P1-6: WS死路由清理+结单确认断链修复 - 删ai_reply_chunk/quiz_diagnostic_answer死路由 + pending_close_request改为resolve_confirm对齐后端 + 挂载ResolveConfirmCard(修复坐席结单员工端不可见的功能断链)
This commit is contained in:
@@ -86,6 +86,16 @@
|
||||
:key="msg.message_id"
|
||||
:msg="msg"
|
||||
/>
|
||||
|
||||
<!-- 坐席结单确认卡片(v4.0 P1-6 修复:WS resolve_confirm → pendingCloseRequest → 挂载此卡片) -->
|
||||
<ResolveConfirmCard
|
||||
v-if="store.pendingCloseRequest"
|
||||
:resolve-summary="store.pendingCloseRequest.resolve_summary"
|
||||
:conversation-id="store.pendingCloseRequest.conversation_id"
|
||||
@confirmed="store.clearPendingCloseRequest()"
|
||||
@rejected="store.clearPendingCloseRequest()"
|
||||
@timeout="store.clearPendingCloseRequest()"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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}`)
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user