feat(ui): 评论三态显式 — 有内容 / 等待中(灰斜体) / 失败(红)

- 之前: 只有 commentary 内容才显示 v-if 块,否则空白
- 现在: 评论卡永远显示,三态语义明确:
    ok + 有内容 → 评论文本(正常)
    pending / n/a / null → 等待中(灰斜体 + 提示 enrichment_loop 会跑)
    failed → 评论生成失败(红斜体 + 失败原因)
- 列表 Feed + 详情 ArticleDetail 同步改造
- 加 commentaryState() 辅助函数:status+content → 'ok'|'waiting'|'failed'
This commit is contained in:
xiaji
2026-06-12 23:24:30 +08:00
parent 16536fe3a0
commit 66e57c6e07
2 changed files with 154 additions and 29 deletions

View File

@@ -99,6 +99,18 @@ function commentaryStatusType(s?: string | null): 'success' | 'warning' | 'error
return 'default'
}
// === 评论三态语义 ===
// status 'ok' + 有内容 → 显示评论
// status 'ok' + 无内容 → 视为等待(防御性,正常不会触发)
// status 'pending' / 'n/a' / null → 等待中
// status 'failed' → 显示失败提示
type CommentaryState = 'ok' | 'waiting' | 'failed'
function commentaryState(status?: string | null, content?: string | null): CommentaryState {
if (status === 'failed') return 'failed'
if (status === 'ok' && content) return 'ok'
return 'waiting'
}
// 正文摘要(取 body_zh_text 前 N 字;没有就 fallback 到 summary_zh)
function bodyExcerpt(text?: string | null, max = 200): string {
if (!text) return ''
@@ -224,35 +236,71 @@ onMounted(async () => {
{{ bodyExcerpt(a.body_zh_text || a.summary_zh, 220) }}
</div>
<!-- 评论钩子( provider:Angel + 美团,淡木色背景 + 木色左边框, Android 对齐) -->
<!-- 评论钩子( provider:Angel + 美团,三态显式显示:有内容 / 等待中 / 失败) -->
<div
v-if="a.commentary || a.commentary_meituan"
v-if="true"
class="commentary-box"
>
<!-- Angel 评论 -->
<template v-if="a.commentary">
<template>
<NSpace align="center" :size="6" style="margin-bottom: 6px">
<span class="commentary-label">💬 Angel 评论</span>
<NTag size="tiny" :type="commentaryStatusType(a.commentary_status)" round :bordered="false">
{{ a.commentary_status || 'n/a' }}
<NTag
size="tiny"
:type="commentaryStatusType(a.commentary_status)"
round
:bordered="false"
>
{{
commentaryState(a.commentary_status, a.commentary) === 'ok' ? 'ok'
: commentaryState(a.commentary_status, a.commentary) === 'failed' ? 'failed'
: '等待中'
}}
</NTag>
</NSpace>
<div class="commentary-text">
<div
v-if="commentaryState(a.commentary_status, a.commentary) === 'ok'"
class="commentary-text"
>
{{ previewCommentary(a.commentary, 140) }}
</div>
<div v-else-if="commentaryState(a.commentary_status, a.commentary) === 'failed'" class="commentary-text commentary-text-failed">
评论生成失败,后台重试中
</div>
<div v-else class="commentary-text commentary-text-waiting">
🕒 等待评论中
</div>
</template>
<!-- 美团评论 -->
<template v-if="a.commentary_meituan">
<div v-if="a.commentary" class="commentary-divider" />
<template>
<div class="commentary-divider" />
<NSpace align="center" :size="6" style="margin-bottom: 6px">
<span class="commentary-label commentary-label-meituan">🐱 美团评论</span>
<NTag size="tiny" :type="commentaryStatusType(a.commentary_meituan_status)" round :bordered="false">
{{ a.commentary_meituan_status || 'n/a' }}
<NTag
size="tiny"
:type="commentaryStatusType(a.commentary_meituan_status)"
round
:bordered="false"
>
{{
commentaryState(a.commentary_meituan_status, a.commentary_meituan) === 'ok' ? 'ok'
: commentaryState(a.commentary_meituan_status, a.commentary_meituan) === 'failed' ? 'failed'
: '等待中'
}}
</NTag>
</NSpace>
<div class="commentary-text">
<div
v-if="commentaryState(a.commentary_meituan_status, a.commentary_meituan) === 'ok'"
class="commentary-text"
>
{{ previewCommentary(a.commentary_meituan, 140) }}
</div>
<div v-else-if="commentaryState(a.commentary_meituan_status, a.commentary_meituan) === 'failed'" class="commentary-text commentary-text-failed">
评论生成失败,后台重试中
</div>
<div v-else class="commentary-text commentary-text-waiting">
🕒 等待评论中
</div>
</template>
</div>
</NSpace>
@@ -303,6 +351,18 @@ onMounted(async () => {
line-height: 1.7;
}
.commentary-text-waiting {
color: var(--color-text-faint);
font-style: italic;
font-size: 12px;
}
.commentary-text-failed {
color: #d03050;
font-size: 12px;
font-style: italic;
}
.commentary-divider {
height: 1px;
background: var(--color-primary-soft);