From 7d19fa5898e6a511dc58b6b18a98e987b5edfee2 Mon Sep 17 00:00:00 2001 From: Peanut Date: Sun, 26 Jul 2026 16:49:44 +0800 Subject: [PATCH] =?UTF-8?q?fix=EF=BC=9A=E6=BE=84=E6=B8=85=E5=8D=A1?= =?UTF-8?q?=E7=89=87=E6=98=BE=E7=A4=BA=E5=AE=8C=E6=95=B4=E9=80=89=E9=A1=B9?= =?UTF-8?q?=E5=92=8C=E4=B8=AD=E6=96=87=E7=AD=94=E6=A1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 问题:详情页 chat-bubble 卡片视图显示「已回答:family」等英文 value, 而不是中文 label(如「家人」),且不展示所有可选选项。 修复: - 新增 getAnswerLabel(msg) 函数,通过 card.options 查找 value 对应的中文 label - rebuildResultMessages 增加 selectedValue 字段,与 answer 同时存原始 value - 卡片已回答视图新增 card-options-list,渲染所有选项,已选加 .selected 样式并标 ✓ - submitClarification(实时模式)同步存 selectedValue,保持渲染逻辑一致 影响: - ScriptView.vue(chat-bubble 流程视图) - ScriptDetailView.vue(详情页只读视图) 数据基础未动,后端澄清问答 answers 仍存原始 value(语义化)。 全局约束:rpx 单位、代码注释中文、禁止 mock 数据。 --- .../src/pages/main/ScriptDetailView.vue | 94 +++++++++++++++- mini-program/src/pages/main/ScriptView.vue | 103 ++++++++++++++++-- 2 files changed, 186 insertions(+), 11 deletions(-) diff --git a/mini-program/src/pages/main/ScriptDetailView.vue b/mini-program/src/pages/main/ScriptDetailView.vue index 6bc51d0..c4a83cf 100644 --- a/mini-program/src/pages/main/ScriptDetailView.vue +++ b/mini-program/src/pages/main/ScriptDetailView.vue @@ -24,7 +24,24 @@ {{ msg.card.question }} - 已回答:{{ msg.answer || '未回答' }} + + + 已回答: + {{ getAnswerLabel(msg) }} + + + + + {{ opt.label || opt.value }} + {{ opt.description }} + + + @@ -135,7 +152,9 @@ const rebuildResultMessages = (scriptData, messages) => { } else if (m.type === 'clarification_answer') { const lastCard = [...result].reverse().find(x => x.kind === 'card') if (lastCard) { - lastCard.answer = m.content || '未回答' + // answer 存用户提交的 value,渲染时通过 card.options 映射成中文 label + lastCard.answer = m.content || '' + lastCard.selectedValue = m.content || '' } else { // 无对应 question,作为独立 user 消息 result.push({ id: m.id, role: 'user', kind: 'text', content: m.content || '' }) @@ -167,6 +186,20 @@ const rebuildResultMessages = (scriptData, messages) => { return result } +/** + * 把已回答卡片的 value(如 "family")映射为对应的中文 label(如 "家人") + * 若选项中找不到匹配的 value,则原样返回 answer(兜底) + * 若 msg.card 不存在则返回 "未回答" + */ +const getAnswerLabel = (msg) => { + if (!msg || !msg.card) return '未回答' + const raw = msg.selectedValue || msg.answer || '' + if (!raw) return '未回答' + const options = Array.isArray(msg.card.options) ? msg.card.options : [] + const match = options.find(opt => opt && opt.value === raw) + return match?.label || raw +} + const continueCurrent = () => { if (!script.value?.id) return uni.setStorageSync('pending_open_script_chat', { @@ -332,9 +365,62 @@ onUnmounted(() => { color: rgba(255, 255, 255, 0.9); font-weight: 500; } -.card-answer-text { +.card-answer-row { + display: flex; + align-items: baseline; + gap: 8rpx; + margin-bottom: 4rpx; +} +.card-answer-prefix { font-size: 26rpx; - color: rgba(193, 134, 255, 0.88); + color: rgba(255, 255, 255, 0.6); +} +.card-answer-label { + font-size: 28rpx; + color: rgba(193, 134, 255, 0.95); + font-weight: 600; +} +.card-options-list { + display: flex; + flex-direction: column; + gap: 10rpx; + margin-top: 8rpx; +} +.card-option-item { + position: relative; + display: flex; + flex-direction: column; + gap: 4rpx; + padding: 14rpx 18rpx; + border-radius: 14rpx; + background: rgba(255, 255, 255, 0.04); + border: 1rpx solid rgba(255, 255, 255, 0.08); +} +.card-option-item.selected { + background: rgba(168, 85, 247, 0.16); + border-color: rgba(168, 85, 247, 0.45); +} +.card-option-label { + font-size: 26rpx; + color: rgba(255, 255, 255, 0.92); + font-weight: 500; +} +.card-option-item.selected .card-option-label { + color: rgba(220, 195, 255, 1); +} +.card-option-desc { + font-size: 22rpx; + color: rgba(255, 255, 255, 0.55); + line-height: 1.5; +} +.card-option-mark { + position: absolute; + right: 14rpx; + top: 50%; + transform: translateY(-50%); + font-size: 30rpx; + color: rgba(220, 195, 255, 1); + font-weight: 700; } .outline-title { font-size: 32rpx; diff --git a/mini-program/src/pages/main/ScriptView.vue b/mini-program/src/pages/main/ScriptView.vue index 8f58be3..2941906 100644 --- a/mini-program/src/pages/main/ScriptView.vue +++ b/mini-program/src/pages/main/ScriptView.vue @@ -130,7 +130,24 @@ /> {{ msg.card.question }} - 已回答:{{ msg.answer }} + + + 已回答: + {{ getAnswerLabel(msg) }} + + + + + {{ opt.label || opt.value }} + {{ opt.description }} + + + @@ -1189,6 +1206,20 @@ const PENDING_SCRIPT_CHAT_KEY = 'pending_open_script_chat' const createMessageId = () => `msg-${Date.now()}-${Math.random().toString(36).slice(2, 8)}` const createConversationId = () => `conv-${Date.now()}-${Math.random().toString(36).slice(2, 8)}` +/** + * 把已回答卡片的 value(如 "family")映射为对应的中文 label(如 "家人") + * 若选项中找不到匹配的 value,则原样返回 answer(兜底) + * 若 msg.card 不存在则返回 "未回答" + */ +const getAnswerLabel = (msg) => { + if (!msg || !msg.card) return '未回答' + const raw = msg.selectedValue || msg.answer || '' + if (!raw) return '未回答' + const options = Array.isArray(msg.card.options) ? msg.card.options : [] + const match = options.find(opt => opt && opt.value === raw) + return match?.label || raw +} + const getCurrentScriptId = () => String(currentResult.value?.id || '') const getCurrentConversationId = () => String(currentConversationId.value || currentResult.value?.conversationId || '') @@ -1475,10 +1506,12 @@ const openScriptChat = async (payload = {}) => { confirmed: true }) } else if (m.type === 'clarification_answer') { - // 把答案合并到上一条 card 消息的 answer 字段 + // 把答案合并到上一条 card 消息:answer 存用户原始 value,selectedValue 也存 value 用于渲染时映射 label const lastCard = [...resultMessages.value].reverse().find(x => x.kind === 'card') if (lastCard) { - lastCard.answer = m.content || '未回答' + const rawValue = m.content || '' + lastCard.answer = rawValue // 原始 value(用于查找 label) + lastCard.selectedValue = rawValue // 选中的 value(渲染时通过 options 映射成 label) lastCard.submitted = true } else { // 无对应 question,作为独立 user 消息 @@ -1841,12 +1874,11 @@ const submitClarification = (answer) => { if (answeringClarification.value) return // 找最后一张未提交的卡片消息(mp-weixin 模板不支持内联箭头函数传 msg,改为自己查找) const card = [...resultMessages.value].reverse().find(m => m.kind === 'card' && !m.submitted) - // 通过 value 查找选项的 label,用于前端显示;后端 payload 仍用 value(语义化) - const option = card?.card?.options?.find(opt => opt.value === answer) - const label = option?.label || answer if (card) { card.submitted = true - card.answer = label // 显示用 label(中文);答案已在卡片中显示,无需额外用户气泡 + // answer 存用户提交的 value,渲染时通过 card.options 映射成中文 label(与历史回放逻辑一致) + card.answer = answer + card.selectedValue = answer } pendingNextResponse.value = true // 标记等待下一个 assistant 响应 answeringClarification.value = true @@ -3775,6 +3807,63 @@ onUnmounted(() => { font-size: 26rpx; padding: 16rpx 0; } +.card-answer-row { + display: flex; + align-items: baseline; + gap: 8rpx; + margin-bottom: 12rpx; +} +.card-answer-prefix { + font-size: 26rpx; + color: rgba(255, 255, 255, 0.6); +} +.card-answer-label { + font-size: 28rpx; + color: rgba(193, 134, 255, 0.95); + font-weight: 600; +} +.card-options-list { + display: flex; + flex-direction: column; + gap: 10rpx; + margin-top: 8rpx; +} +.card-option-item { + position: relative; + display: flex; + flex-direction: column; + gap: 4rpx; + padding: 14rpx 18rpx; + border-radius: 14rpx; + background: rgba(255, 255, 255, 0.04); + border: 1rpx solid rgba(255, 255, 255, 0.08); +} +.card-option-item.selected { + background: rgba(168, 85, 247, 0.16); + border-color: rgba(168, 85, 247, 0.45); +} +.card-option-label { + font-size: 26rpx; + color: rgba(255, 255, 255, 0.92); + font-weight: 500; +} +.card-option-item.selected .card-option-label { + color: rgba(220, 195, 255, 1); +} +.card-option-desc { + font-size: 22rpx; + color: rgba(255, 255, 255, 0.55); + line-height: 1.5; +} +.card-option-mark { + position: absolute; + right: 14rpx; + top: 50%; + transform: translateY(-50%); + font-size: 30rpx; + color: rgba(220, 195, 255, 1); + font-weight: 700; +} .outline-title { color: #ffffff;