# 缺陷单:坐席端缺"已选:xxx ✓"汇总标签——员工最近一次选项选择不可见 > **缺陷编号**: BUG-坐席-002 > **版本**: v1.0 > **状态**: [已修复] > **优先级**: P3-Low > **发现日期**: 2026-07-28 > **发现人**: 宋献 > **指派人**: 宋献 > **修复人**: Duckula (AI助手) > **关闭日期**: - > **处理方式**: 自动处理和部署 > **关联需求**: REQ-坐席-002(AI 辅助消息框) > **关联文档**: > - 故障手册: `docs/04-运维文档/部署运维/00-标准故障排查手册.md`(CASE-20260728-06) > - 技术方案: `docs/02-技术文档/技术架构/技术方案-REQ-坐席-002-AI辅助消息框-v1.0.md` --- ## 1. 基本信息 | 字段 | 内容 | |------|------| | 缺陷标题 | 坐席端缺"已选:xxx ✓"汇总标签——员工最近一次选项选择不可见 | | 影响范围 | 坐席端所有"AI 结构化消息"渲染(涉及 `ai_structured` 类型消息的"推荐选项"区) | | 涉及模块 | 坐席端(frontend-agent) | | 涉及文件 | `src/frontend-agent/src/components/chat/MessageBubble.vue`(ai-structured-options 渲染区) | | 触发条件 | 1. 员工在 H5 端依次点选 AI 结构化消息的"推荐选项"(如"卡纸/缺墨/其他"→"提示错误/无法连接/..."→"错误代码/文字提示/...")
2. 后端通过 WS 广播 `option_selected` 事件到坐席端
3. 坐席端 store `conversationStore.selectedOptionLabels` 累加被选 label | | 预期行为 | 在**最近一次被选的那条 AI 消息**(即选项区里包含最近一次被选 label 的那条)的"推荐选项"区域**顶部**,加一个明显的"已选:错误代码 ✓"绿色徽章,让坐席一眼看到员工最终选了哪个。前几条历史 AI 消息的选项区不显示这个徽章(保持现状的"✓ 在被选条目后"设计) | | 实际行为(修复前) | 坐席端只能看到每个 AI 消息选项区里已选条目后面带 `✓` 标记,但**无法一眼看出员工最终选了哪个**。需要逐个气泡阅读"已选 ✓"标记才能拼出完整决策路径。 | --- ## 2. 复现步骤 1. 员工在 H5 端进入"打印机"会话 2. 员工依次点选 AI 提供的选项: - 第一条 AI 消息"已刷卡但打不出?...":点"卡纸" - 后续交互再点"其他"等 - 第二条 AI 消息"其他问题?...":点"提示错误" - 第三条 AI 消息"提示错误?...":点"错误代码" 3. 坐席端 store 收到 WS 广播 `option_selected` 事件,`selectedOptionLabels` 数组累加 `["卡纸", "其他", "提示错误", "错误代码"]` 4. 坐席端打开该会话,滚动到 3 条 AI 消息 5. **观察**:每条 AI 消息的"推荐选项"区只在自己被选条目后带 ✓ 标记 6. **问题**:坐席需要扫读 3 个气泡的 ✓ 标记才能知道员工最终选了"错误代码"(第 3 条) ### 影响截图 - 页面:坐席端 → "打印机"会话 - 元素:3 条 AI 消息下方的"推荐选项"区 - 期望:在第 3 条 AI 消息选项区顶部显示"已选:错误代码 ✓"绿色徽章 --- ## 3. 根因分析 ### 3.1 现状(修复前) `src/frontend-agent/src/components/chat/MessageBubble.vue` 第 55-65 行(v2.1 版本)只渲染了选项列表: ```vue
推荐选项: {{ option.label || option.value }}
``` ### 3.2 缺失项 - **无"汇总徽章"设计**:只有"✓ 在被选条目后"的局部标记,缺少整体汇总 - **坐席需扫读多气泡**:决策路径分布在多条 AI 消息的多个 ✓ 标记中,无法一眼看清 --- ## 4. 处理办法 | 项目 | 内容 | |------|------| | 处理策略 | 自动处理和部署(v2.2 增量) | | 执行时机 | 立即(影响坐席工作效率) | | 处理流程 | 1. 新增 `latestSelectedLabel` computed(取 `selectedOptionLabels` 数组最后一项)
2. 新增 `messageHasLatestSelected` computed(**关键**:判断当前 AI 消息的 options 是否包含最近一次被选 label)
3. 模板新增"已选:xxx ✓"绿色徽章(`v-if="messageHasLatestSelected"`)
4. CSS 新增 `.ai-structured-options__summary` 系列样式
5. 本地构建 → 上传 → 服务器解压 → docker restart nginx | | 验证方式 | 部署层验证:curl 200 OK + grep 确认新代码生效 + Workspace-B-lO49Vu.js 部署到容器 | | 回滚方案 | 服务器保留 `dist.bak.option-summary.v2.2b/` 备份目录;紧急回滚 `mv dist.bak.option-summary.v2.2b dist && docker restart wecom_it_nginx` | --- ## 5. 修复方案 ### 5.1 代码修复(`MessageBubble.vue`) #### 5.1.1 新增计算属性 `latestSelectedLabel` ```typescript /** * 员工最近一次答案选择(v2.2 新增:坐席端"已选:xxx ✓"汇总标签) * * 做什么:从 conversationStore.selectedOptionLabels 数组中取最后一个值(最近一次被选的) * 为什么:让坐席在每条 AI 消息的选项区顶部一眼看到员工最终选了哪个 * 边界:空数组时返回空字符串(不显示"已选"标签) */ const latestSelectedLabel = computed(() => { const labels = conversationStore.selectedOptionLabels if (!labels || labels.length === 0) return '' return labels[labels.length - 1] }) ``` #### 5.1.2 新增计算属性 `messageHasLatestSelected`(**关键**) ```typescript /** * 当前 AI 消息是否包含最近一次被选的选项(v2.2 配合"已选"标签使用) * * 做什么:判断 props.message.extra_data.options 中是否包含 latestSelectedLabel * 为什么:用户期望"已选:xxx ✓"只显示在"最近一次被选的那条 AI 消息"的选项区 * 前几条历史 AI 消息的选项区不包含最近一次被选的 label,所以不显示 * 边界:latestSelectedLabel 为空时返回 false(不显示"已选"标签) */ const messageHasLatestSelected = computed(() => { if (!latestSelectedLabel.value) return false const options = props.message.extra_data?.options || [] return options.some( (opt: any) => (opt?.label || opt?.value) === latestSelectedLabel.value ) }) ``` #### 5.1.3 模板新增"已选:xxx ✓"绿色徽章 ```vue
已选: {{ latestSelectedLabel }}
推荐选项: ...
``` #### 5.1.4 CSS 样式 ```css /* v2.2 新增:员工最近一次答案选择汇总(绿色徽章,位于选项区顶部) */ .ai-structured-options__summary { display: inline-flex; align-items: center; gap: 4px; margin-right: 4px; padding: 3px 10px; background: #07C160; color: #fff; border-radius: 12px; font-size: 12px; font-weight: 600; line-height: 1.4; /* 占据整行宽度,让"推荐选项:"换到下一行更清晰 */ flex-basis: 100%; margin-bottom: 4px; } .ai-structured-options__summary-label { font-weight: 500; opacity: 0.9; } .ai-structured-options__summary-value { font-weight: 700; } .ai-structured-options__summary-check { font-weight: 700; margin-left: 2px; } ``` ### 5.2 关键设计 - **条件渲染下沉到 message 级**:`messageHasLatestSelected` 把"是否显示徽章"的判断**下沉到每条消息**——只有**包含最近一次被选 label 的那条 AI 消息**才显示"已选"徽章 - **前几条历史 AI 消息的选项区不显示**:避免无差别地所有 AI 消息都显示"已选"造成误导 - **`flex-basis: 100%` 让徽章独占一行**:避免和"推荐选项:"label 挤在同一行造成视觉混乱 ### 5.3 首次实现的 Bug 与修正 首次实现的 v2.2a 版(`Workspace-CdGky81t.js`)**未做"message 级判断"**——`v-if="latestSelectedLabel"` 会让**所有** AI 消息的选项区都显示"已选"徽章(前两条历史 AI 消息也会显示"已选:错误代码 ✓")。 修正后 v2.2b 版(`Workspace-B-lO49Vu.js`)加 `messageHasLatestSelected` 判断,**只在最近一次被选的那条 AI 消息显示**,符合用户期望的"只显示最近一次的答案选择"。 --- ## 6. 验证结果 ### 6.1 部署层验证 | 验证项 | 命令/方式 | 结果 | |--------|----------|------| | 本地构建 | `npm run build` | ✅ 5.21s | | 构建产物 | `dist/assets/Workspace-B-lO49Vu.js`(hash 变化) | ✅ 157.30 kB | | 打包 zip | `dist-agent-option-summary-v2.2b.zip` | ✅ 1,621,981 B | | 上传校验 | `v2_ops.py upload` md5 校验 | ✅ 通过 | | 服务器解压 | `unzip /tmp/dist-agent-option-summary-v2.2b.zip` | ✅ 成功 | | Nginx 重启 | `docker restart wecom_it_nginx` | ✅ Up 3 seconds | | 外部访问 | `curl -I https://itsupport.servyou.com.cn/itagent/assets/Workspace-B-lO49Vu.js` | ✅ HTTP 200 | | 新代码生效 | `grep -c "messageHasLatestSelected" .../Workspace-B-lO49Vu.js` | ✅ 1(命中) | | 容器内文件 | `docker exec wecom_it_nginx ls /usr/share/nginx/html/itagent/assets/ \| grep Workspace` | ✅ 命中 `Workspace-B-lO49Vu.js` | ### 6.2 中文标签验证 ```powershell PS> $content = Get-Content "Workspace-B-lO49Vu.js" -Raw PS> ([regex]::Matches($content, "已选")).Count 4 ``` `已选` 出现 4 次(在 Vue 模板字符串中),字符编码正常,无 GBK 误读。 ### 6.3 真实浏览器验证 ⏳ **待用户在坐席端人工验证**(企微扫码登录后): 1. 打开"打印机"会话 2. 观察 3 条 AI 消息的选项区 3. **预期看到**:第 3 条 AI 消息("提示错误?...")的选项区**顶部**有**绿色徽章** "已选:错误代码 ✓" 4. **预期看到**:前两条 AI 消息的选项区**不**显示"已选"徽章(保持现有 ✓ 在被选条目后的设计) 5. 验证通过后,将本文档状态改为 `[已验证]` ### 6.4 浏览器测试硬性限制 坐席端是**企微扫码登录**,agent-browser 无法脚本模拟扫码。**真实浏览器测试必须由用户人工扫码完成**。 --- ## 7. 关联信息 - **关联需求**: REQ-坐席-002(AI 辅助消息框) - **关联技术方案**: `docs/02-技术文档/技术架构/技术方案-REQ-坐席-002-AI辅助消息框-v1.0.md` - **关联故障手册**: `docs/04-运维文档/部署运维/00-标准故障排查手册.md`(v3.1 新增 CASE-20260728-06) - **修复代码文件**: `src/frontend-agent/src/components/chat/MessageBubble.vue` - **部署包**: `deploy-temp/dist-agent-option-summary-v2.2b.zip`(保留作为部署物证) --- ## 8. 变更记录 | 日期 | 版本 | 变更内容 | 变更人 | 变更原因 | 影响范围 | |------|------|----------|--------|----------|----------| | 2026-07-28 | v1.0 | 创建缺陷单,记录坐席端缺"已选:xxx ✓"汇总标签 | 宋献 / Duckula | 用户反馈坐席无法一眼看清员工最终选项 | 坐席端所有 AI 结构化消息渲染 | | 2026-07-28 | v1.0 | 修复 MessageBubble.vue:新增 `latestSelectedLabel` + `messageHasLatestSelected` 两个 computed | Duckula | 缺少"消息级判断"导致 v2.2a 误显示 | 坐席端 MessageBubble 组件 | | 2026-07-28 | v1.0 | v2.2a 部署后修正为 v2.2b:补 `messageHasLatestSelected` 避免前几条历史 AI 消息也显示徽章 | Duckula | 用户要求"只显示最近一次",避免误导 | 坐席端 MessageBubble 组件 | | 2026-07-28 | v1.0 | 本地构建 + 服务器部署 + nginx 重启 + curl/grep 验证 | Duckula | 部署层确认修复实际生效 | 坐席端 dist 资产 | | 2026-07-28 | v1.0 | 文档规范化:故障手册 v3.0→v3.1 + 缺陷单 README 追加清单 | Duckula | 规范要求 BUG 修复需同步周边文档 | 文档体系 | --- > **缺陷状态**: [已修复] — 部署完成,等用户人工扫码验证。验证通过后请将状态改为 `[已验证]`,并补充关闭日期。