From 59609b1d8d96fd5c836223a1d3eaca983b1ee0a5 Mon Sep 17 00:00:00 2001 From: Simon Date: Sat, 18 Jul 2026 02:03:13 +0800 Subject: [PATCH] =?UTF-8?q?P1-6:=20WS=E6=AD=BB=E8=B7=AF=E7=94=B1=E6=B8=85?= =?UTF-8?q?=E7=90=86+=E7=BB=93=E5=8D=95=E7=A1=AE=E8=AE=A4=E6=96=AD?= =?UTF-8?q?=E9=93=BE=E4=BF=AE=E5=A4=8D=20-=20=E5=88=A0ai=5Freply=5Fchunk/q?= =?UTF-8?q?uiz=5Fdiagnostic=5Fanswer=E6=AD=BB=E8=B7=AF=E7=94=B1=20+=20pend?= =?UTF-8?q?ing=5Fclose=5Frequest=E6=94=B9=E4=B8=BAresolve=5Fconfirm?= =?UTF-8?q?=E5=AF=B9=E9=BD=90=E5=90=8E=E7=AB=AF=20+=20=E6=8C=82=E8=BD=BDRe?= =?UTF-8?q?solveConfirmCard=EF=BC=88=E4=BF=AE=E5=A4=8D=E5=9D=90=E5=B8=AD?= =?UTF-8?q?=E7=BB=93=E5=8D=95=E5=91=98=E5=B7=A5=E7=AB=AF=E4=B8=8D=E5=8F=AF?= =?UTF-8?q?=E8=A7=81=E7=9A=84=E5=8A=9F=E8=83=BD=E6=96=AD=E9=93=BE=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend-h5/src/components/chat/ChatPanel.vue | 11 +++ frontend-h5/src/composables/useH5WebSocket.ts | 24 ++----- frontend-h5/src/stores/conversation.ts | 67 ++----------------- 3 files changed, 24 insertions(+), 78 deletions(-) diff --git a/frontend-h5/src/components/chat/ChatPanel.vue b/frontend-h5/src/components/chat/ChatPanel.vue index 1695980..4ef67cb 100644 --- a/frontend-h5/src/components/chat/ChatPanel.vue +++ b/frontend-h5/src/components/chat/ChatPanel.vue @@ -86,6 +86,16 @@ :key="msg.message_id" :msg="msg" /> + + + @@ -139,6 +149,7 @@ import InputBar from './InputBar.vue' // 2026-07-12 改造:不再 import CallAgentModal(弹窗动画已移除) // import CallAgentModal from './CallAgentModal.vue' import TroubleshootFlow from './TroubleshootFlow.vue' +import ResolveConfirmCard from './ResolveConfirmCard.vue' import ParticipantStrip from './ParticipantStrip.vue' import ParticipantList from './ParticipantList.vue' import EvaluationDialog from './EvaluationDialog.vue' diff --git a/frontend-h5/src/composables/useH5WebSocket.ts b/frontend-h5/src/composables/useH5WebSocket.ts index c766899..001d6b9 100644 --- a/frontend-h5/src/composables/useH5WebSocket.ts +++ b/frontend-h5/src/composables/useH5WebSocket.ts @@ -387,14 +387,10 @@ export function useH5WebSocket() { break // ================================================================== - // AI 回复流式推送(改造方案 A:发送瞬时返回,AI 经 WS 推回) + // AI 回复(blocking 模式:发送瞬时返回,AI 经 WS 推回) // ================================================================== - case 'ai_reply_chunk': - // 打字机:逐 chunk 累积到临时 AI 气泡 - if (msg.data) { - store.handleAiReplyChunk(msg.data) - } - break + // v4.0 P1-6:case 'ai_reply_chunk' 已删除(后端从未推送流式 chunk, + // blocking 模式下 AI 回复只走 ai_reply 完整消息) case 'ai_reply': // AI 终态:用真实消息替换打字机气泡 @@ -474,10 +470,10 @@ export function useH5WebSocket() { // ================================================================== // 坐席发起结单 — 员工端弹出确认卡片 // ================================================================== - case 'pending_close_request': + case 'resolve_confirm': // 坐席发起了结单,会话进入 pending_close 状态 - // 做什么:在消息流中插入 ResolveConfirmCard 组件 - // 员工需在 5 分钟内确认或拒绝,否则系统自动关闭 + // v4.0 P1-6 修复:后端实际推送类型是 resolve_confirm(closing_service._push_resolve_confirm), + // 原 case 'pending_close_request' 从未命中导致结单确认卡片不显示(功能断链) if (msg.data) { store.handlePendingCloseRequest(msg.data) } @@ -486,13 +482,7 @@ export function useH5WebSocket() { // ================================================================== // 诊断答题答案附加到会话上下文 // ================================================================== - case 'quiz_diagnostic_answer': - // 诊断题答案已附加到会话上下文 - // 做什么:在消息流中显示一条系统消息,告知用户诊断信息已传递给坐席 - if (msg.data) { - store.handleQuizDiagnosticAnswer(msg.data) - } - break + // v4.0 P1-6:case 'quiz_diagnostic_answer' 已删除(后端从未推送此类型) default: console.warn(`[H5 WS] 未知消息类型: ${msg.type}`) diff --git a/frontend-h5/src/stores/conversation.ts b/frontend-h5/src/stores/conversation.ts index 765b0b3..cb4d5e3 100644 --- a/frontend-h5/src/stores/conversation.ts +++ b/frontend-h5/src/stores/conversation.ts @@ -1067,39 +1067,6 @@ export const useConversationStore = defineStore('conversation', () => { /** * 处理 WS 流式 AI 回复 chunk(打字机效果) - * 做什么:首个 chunk 时创建临时 AI 气泡,后续 chunk 累积到该气泡 content - * 为什么:后端 AI 推理(Dify)流式返回,逐字推送以获得打字机体验, - * 避免整段等待(原同步方案卡"发送中"3~15s) - * - * @param data - { conversation_id, chunk } - */ - function handleAiReplyChunk(data: { conversation_id: string; chunk: string }): void { - // 仅处理当前会话,避免串台 - if (currentConversation.value?.conversation_id !== data.conversation_id) return - if (!data.chunk) return - - // 首个 chunk:创建占位气泡(不设置 status,避免误显示"发送中") - if (!streamingAiMessageId.value) { - const tempId = `ai_stream_${data.conversation_id}_${Date.now()}` - streamingAiMessageId.value = tempId - messages.value.push({ - message_id: tempId, - conversation_id: data.conversation_id, - message_type: 'ai', - msg_type: 'text', - content: '', - sender_name: 'Duckula(达寇拉)', - created_at: new Date().toISOString(), - }) - } - - // 累积 chunk(Vue3 ref 深层响应式,直接改属性即可触发重渲染 → 打字机) - const idx = messages.value.findIndex(m => m.message_id === streamingAiMessageId.value) - if (idx !== -1) { - messages.value[idx].content += data.chunk - } - } - /** * 处理 WS AI 回复终态 * 做什么:用真实 AI 消息(含 DB message_id)替换打字机占位气泡, @@ -1457,12 +1424,15 @@ export const useConversationStore = defineStore('conversation', () => { /** * 处理坐席结单请求 - * WS event: pending_close_request + * WS event: resolve_confirm(v4.0 P1-6 修复:对齐后端 closing_service 实际推送类型) + * 后端 payload: { conversation_id, agent_id, resolve_summary, auto_close_minutes, timestamp } */ function handlePendingCloseRequest(data: { conversation_id: string resolve_summary: string - agent_name: string + agent_id?: string + agent_name?: string + auto_close_minutes?: number }): void { if (currentConversation.value?.conversation_id !== data.conversation_id) return @@ -1491,29 +1461,6 @@ export const useConversationStore = defineStore('conversation', () => { messages.value.push(systemMsg) } - /** - * 处理诊断答题答案附加到上下文 - * WS event: quiz_diagnostic_answer - */ - function handleQuizDiagnosticAnswer(data: { - question: string - selected_answer: string - conversation_id: string - }): void { - // 添加系统消息,告知用户诊断信息已传递 - const systemMsg: Message = { - message_id: `quiz_diag_${data.conversation_id}_${Date.now()}`, - conversation_id: data.conversation_id, - message_type: 'system', - msg_type: 'text', - content: `📝 诊断信息已传递给坐席:${data.question} → ${data.selected_answer}`, - sender_name: '系统', - created_at: new Date().toISOString(), - status: 'sent', - } - messages.value.push(systemMsg) - } - /** 清除结单请求(确认或拒绝后调用) */ function clearPendingCloseRequest(): void { pendingCloseRequest.value = null @@ -1710,8 +1657,7 @@ export const useConversationStore = defineStore('conversation', () => { // WS-06 消息去重(与 agent 端对齐,WebSocket 接入时使用) handleNewMessage, - // 流式 AI 回复(改造方案 A:打字机) - handleAiReplyChunk, + // 流式 AI 回复(改造方案 A:blocking 模式,v4.0 P1-6 删除 handleAiReplyChunk) handleAiReply, handleAiReplyFailed, cancelStreamingBubble, @@ -1737,7 +1683,6 @@ export const useConversationStore = defineStore('conversation', () => { handleQueuePositionUpdate, handleConversationResolved, handlePendingCloseRequest, - handleQuizDiagnosticAnswer, clearPendingCloseRequest, clearResolvedInfo, }