feat(feed): 首页列表展示分类标签 + LLM 评论预览
- 后端 ArticleListItem schema 加 commentary / commentary_status / image_ai_url - 后端 articles.list 接口把以上字段写入响应 - 前端 API 类型同步 - 前端 Feed.vue 卡片: * 分类 tag(逗号分隔,多 tag) * 评论预览(蓝色引线块,140 字截断,带状态点) * 用户点进详情页前就能看到 LLM 点评钩子
This commit is contained in:
@@ -68,6 +68,26 @@ function fmtTime(s?: string | null) {
|
||||
return dayjs(s).fromNow()
|
||||
}
|
||||
|
||||
// category 是逗号分隔字符串(LLM 输出),拆成多个 tag
|
||||
function splitCategory(c?: string | null): string[] {
|
||||
if (!c) return []
|
||||
return c.split(',').map((s) => s.trim()).filter(Boolean)
|
||||
}
|
||||
|
||||
// 评论预览:长文截断,带状态点
|
||||
function previewCommentary(c?: string | null, max = 120): string {
|
||||
if (!c) return ''
|
||||
const trimmed = c.replace(/\s+/g, ' ').trim()
|
||||
return trimmed.length > max ? trimmed.slice(0, max) + '…' : trimmed
|
||||
}
|
||||
|
||||
function commentaryStatusType(s?: string | null): 'success' | 'warning' | 'error' | 'default' {
|
||||
if (s === 'ok') return 'success'
|
||||
if (s === 'failed') return 'error'
|
||||
if (s === 'pending') return 'warning'
|
||||
return 'default'
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await loadSources()
|
||||
await load()
|
||||
@@ -112,6 +132,15 @@ onMounted(async () => {
|
||||
<NTag v-if="a.translation_status !== 'ok'" size="small" type="warning">
|
||||
{{ a.translation_status }}
|
||||
</NTag>
|
||||
<!-- 分类标签(LLM classify 输出,多分类逗号分隔) -->
|
||||
<NTag
|
||||
v-for="c in splitCategory(a.category)"
|
||||
:key="c"
|
||||
size="small"
|
||||
type="success"
|
||||
>
|
||||
{{ c }}
|
||||
</NTag>
|
||||
<NText depth="3" style="font-size: 12px">{{ fmtTime(a.published_at || a.fetched_at) }}</NText>
|
||||
</NSpace>
|
||||
<div style="font-size: 16px; font-weight: 600; color: #333">{{ a.title }}</div>
|
||||
@@ -121,6 +150,28 @@ onMounted(async () => {
|
||||
<div v-if="a.summary_zh" style="color: #666; font-size: 13px; margin-top: 4px">
|
||||
{{ a.summary_zh.slice(0, 200) }}{{ a.summary_zh.length > 200 ? '…' : '' }}
|
||||
</div>
|
||||
<!-- 评论预览(列表钩子,详情页有完整版) -->
|
||||
<div
|
||||
v-if="a.commentary"
|
||||
style="
|
||||
margin-top: 8px;
|
||||
padding: 8px 10px;
|
||||
background: #f6f8ff;
|
||||
border-left: 3px solid #2080f0;
|
||||
border-radius: 4px;
|
||||
color: #444;
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
"
|
||||
>
|
||||
<NSpace align="center" :size="6" style="margin-bottom: 4px">
|
||||
<NText depth="2" style="font-size: 12px; font-weight: 600">💬 评论</NText>
|
||||
<NTag size="tiny" :type="commentaryStatusType(a.commentary_status)">
|
||||
{{ a.commentary_status || 'n/a' }}
|
||||
</NTag>
|
||||
</NSpace>
|
||||
<span>{{ previewCommentary(a.commentary, 140) }}</span>
|
||||
</div>
|
||||
</NSpace>
|
||||
</NCard>
|
||||
<NSpace v-if="!exhausted" justify="center" style="margin: 16px 0">
|
||||
|
||||
Reference in New Issue
Block a user