Files
sbnews/uniapp/src/components/feed-card/feed-card.vue
T
2026-06-11 12:15:29 +08:00

144 lines
3.6 KiB
Vue

<template>
<navigator :url="`/pages/news_detail/news_detail?id=${item.id}`" class="feed-card">
<view class="feed-card__body">
<view class="feed-card__info">
<view class="feed-card__title">{{ item.title }}</view>
<view v-if="descText" class="feed-card__desc">{{ descText }}</view>
<view class="feed-card__footer">
<text class="feed-card__author">{{ authorText }}</text>
<text class="feed-card__meta feed-card__meta--center">{{ item.comment_count || item.click || 0
}}评论</text>
<text class="feed-card__meta feed-card__meta--right">{{ formatTime(item.create_time) }}</text>
</view>
</view>
<UImage v-if="item.image" :src="item.image" width="220" height="140" border-radius="8" mode="aspectFill"
class="feed-card__img" />
</view>
</navigator>
</template>
<script lang="ts" setup>
import { computed } from 'vue'
import UImage from '@/uni_modules/vk-uview-ui/components/u-image/u-image.vue'
const props = withDefaults(
defineProps<{
item: any
}>(),
{
item: () => ({})
}
)
const stripHtml = (html: string) => {
if (!html) return ''
return html.replace(/<[^>]+>/g, '').replace(/&nbsp;/g, ' ').replace(/\s+/g, ' ').trim()
}
const descText = computed(() => {
if (props.item.desc) return props.item.desc
if (props.item.content) return stripHtml(props.item.content).substring(0, 100)
return ''
})
const authorText = computed(() => {
const rawAuthor = String(props.item.author || '')
const cleanedAuthor = rawAuthor.replace(/@懂球帝/g, '').trim()
return cleanedAuthor || '体育小编'
})
const formatTime = (t: string) => {
if (!t) return ''
const d = new Date(t.replace(/-/g, '/'))
if (isNaN(d.getTime())) return t
const m = String(d.getMonth() + 1).padStart(2, '0')
const day = String(d.getDate()).padStart(2, '0')
const h = String(d.getHours()).padStart(2, '0')
const min = String(d.getMinutes()).padStart(2, '0')
return `${m}-${day} ${h}:${min}`
}
</script>
<style lang="scss" scoped>
.feed-card {
display: block;
padding: 20rpx 20rpx;
background: #fff;
border-bottom: 1rpx solid #f0f0f0;
&__body {
display: flex;
gap: 20rpx;
align-items: flex-start;
}
&__info {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
min-width: 0;
}
&__title {
font-size: 28rpx;
font-weight: 600;
color: #111;
line-height: 1.45;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
&__desc {
font-size: 24rpx;
color: #999;
margin-top: 8rpx;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
&__footer {
display: flex;
flex-direction: row;
align-items: center;
margin-top: auto;
padding-top: 12rpx;
gap: 12rpx;
white-space: nowrap;
overflow: hidden;
}
&__author {
flex: 1;
font-size: 24rpx;
color: #999;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
text-align: left;
}
&__meta {
flex: 1;
font-size: 24rpx;
color: #bbb;
white-space: nowrap;
&--center {
text-align: center;
}
&--right {
text-align: right;
}
}
&__img {
flex-shrink: 0;
}
}
</style>