%% ==================================================================== %% v1.1 正式技术方案 — 4 个时序图 %% ==================================================================== %% ========== 时序 ①:点选-广播-落库 ========== sequenceDiagram autonumber actor Emp as 员工 participant MB as MessageBubble participant Store as ConversationStore participant WS as ws._handle_option_select participant DB as PostgreSQL participant WSM as ws_manager participant Obs as BackendObserver participant Task as process_h5_ai_reply Emp->>MB: 点击 option MB->>Store: sendOptionSelect(value, label, sourceId, qId, oId) Note over Store: lastSentOptionContent=label
optionSubmitting=true
5 重 UUID 守卫判定 Store->>WS: option_select(6 字段 + client_msg_id) WS->>WS: UUID 校验 WS->>DB: BEGIN + pg_advisory_xact_lock WS->>DB: SELECT 5s 内同 UUID alt 5s 内重复命中 DB-->>WS: dup row returned WS-->>Store: 无副作用,结束 else 首次受理 WS->>DB: INSERT Message(msg_type=option_select) DB-->>WS: commit_ts = T1 Note over WS,WSM: ★ v1.1 T03: 同步推员工端 WS->>WSM: broadcast_to_employees([employee_id], new_message) WSM-->>Store: new_message (employee 端) Store->>Store: trackProcessedMessageId + push message Note over Store: 员工立即看到 ✓ 气泡 WS->>WSM: broadcast(new_message) - 坐席 WSM-->>Obs: 记录 broadcast_ts = T2 Obs-->>Obs: option_select_broadcast_latency_ms = T2 - T1 WS->>Task: create_task(process_h5_ai_reply) end %% ========== 时序 ②:AI 回复回流 ========== sequenceDiagram autonumber participant Dify as Dify Workflow participant Task as process_h5_ai_reply participant DB as PostgreSQL participant WSM as ws_manager participant WS as H5 useH5WebSocket participant Store as ConversationStore participant MB as MessageBubble Dify-->>Task: 返回结构化 reply (ai_text 或 still_thinking) alt Dify 正常返回 Task->>DB: INSERT Message(ai_text) DB-->>Task: commit else Dify 超时 ≥ 15s Note over Task: ★ v1.1 T03: still_thinking 兜底
主动补发 option_select_confirm Task->>WSM: broadcast_to_employees(option_select_confirm) end Task->>WSM: broadcast_to_employees(ai_reply) WSM->>WS: ai_reply { type: "ai_reply", data: {...} } WS->>Store: handleAiReply(data) Note over Store: ★ v1.1 Bug 4 软校验:
conversation_id 不匹配 → console.warn
但不再 return
仅 message_id 已去重才 return Store->>Store: trackProcessedMessageId(message_id) Store->>Store: messages.value.push(finalMessage) Store-->>MB: reactive 触发重渲 MB->>MB: 显示 AI 答案气泡(打字机逐字) Note over MB: ★ v1.1 T02 派生:
isOptionSelected 从 messages 过滤
不再依赖内存 ref %% ========== 时序 ③:视觉分组 ========== sequenceDiagram autonumber actor Emp as 员工 participant Store as ConversationStore participant Panel as ChatPanel participant MB as MessageBubble Note over Store: messages 序列示例:
[ai_structured Q1]
[option_select Q1.optA] 第 1 次
[ai_text 回复1]
[option_select Q1.optB] 第 2 次(重选)
[ai_text 回复2] Emp->>Store: 选 Q1.optB Store->>Store: sendOptionSelect → WS send Note over Store: groupedMessagesByQuestion (v1.1 ★)
按 question_id 相邻聚合
折叠 Q1.optA,激活 Q1.optB Panel->>MB: v-for msg in groupedMessages MB->>MB: option_select 模板加 data-question-id alt collapsed (历史同题选项) MB->>MB: class=message-bubble--option-select collapsed
背景灰底 + 折叠图标 ▾ else active (本次选项) MB->>MB: class=message-bubble--option-select active
蓝底 + ✓ end MB->>MB: ai_text 紧随其后,按时间顺序独立出现 Note over MB: 3 个 UI 元素顺序独立:
① ✓当前 ② AI 思考占位 ③ AI 答案 %% ========== 时序 ④:时延监控 ========== sequenceDiagram autonumber actor Emp as 员工 (Chromium A) actor Agent as 坐席 (Chromium B) participant H5Emp as H5 useH5WebSocket participant H5Agt as H5 useH5WebSocket participant WS as ws._handle_option_select participant WSM as ws_manager participant Obs as BackendObserver participant Script as measure-option-latency.mjs Script->>Script: 启动双 context + login 双方 Script->>Script: t0_start = performance.now() Emp->>H5Emp: click option H5Emp->>WS: option_select payload (含 client_msg_id UUID) H5Emp->>H5Emp: 记录 client_send_ts = T0 WS->>WSM: broadcast_to_employees + broadcast WSM->>H5Agt: new_message(option_select) H5Agt->>H5Agt: 渲染 ✓ 气泡 H5Agt->>Script: postMessage { event: 'rendered', ts: T_agent } H5Emp->>H5Emp: 收到自己的 new_message (员工端) H5Emp->>Obs: POST /api/backend-observer/record
{metric: 'option_select_e2e_latency_ms',
value: T_agent - T0} WSM->>Obs: 记录 option_select_persist_latency_ms (commit_ts)
记录 option_select_broadcast_latency_ms (broadcast_ts) Script->>Script: t1_end = performance.now() (员工点击 → 坐席渲染) Script->>Obs: GET /api/backend-observer/metrics?name=option_select_* Obs-->>Script: 4 个指标样本 Script->>Script: p50/p95 计算 + 告警 (>100ms warning) Script->>Script: 输出 report.json