Files
wecom_it_smart_desk/docs/01-产品文档/04-坐席工作台/PRD-REQ-坐席-011-统一工作队列重构-v0.1.md
T
Simon 9292f41763 feat(agent/backend): 坐席端审批线降级跳转 + 回调最终一致回写
实现 Phase 0 审批线 T01+T02(依据 PRD-REQ-坐席-011 + U-1 技术验证结论)。

前端(T01):
- TaskDetailView.handleAction 移除 mock toast,审批类仅 console.info
- ApprovalDetail 通过/拒绝/转交 + 打开按钮接线为企微审批深链真实跳转(<a target="_blank">)
- useWebSocket 新增 todo_status_changed 实时刷新分支

后端(T02):
- approval.py 新增 writeback_approval_todo_status 主入口 + /approval/callback 接线
- approval_webhook.py 新增 _writeback_agent_todo 复用回调→WS 推送通道
- 以 approval:{sp_no} 为关联键,缓存就地改写 + 7天快照 + WS 推送,最终一致

测试:src/backend/tests/test_approval_todo_writeback.py(51 例全绿)
文档:PRD-REQ-坐席-011 v0.1、技术验证-U-1 v1.0
2026-08-09 00:46:31 +08:00

206 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# PRD — 坐席端统一工作队列重构
> **REQ编号**: REQ-坐席-011
> **版本**: v0.1(方案草案 / 沟通确认阶段)
> **状态**: 🟡 待评审 — 含未决项,不得据此排期开发
> **优先级**: P1(其中 Phase 0 为 P0
> **日期**: 2026-08-08
> **作者**: 宋献
> **关联**: REQ-坐席-004(任务详情视图切换)、REQ-坐席-009(会话状态Tab筛选)、任务说明书 #132
---
## 1. 背景
### 1.1 提案
取消坐席工作台「待办事项」独立面板,将审批单与工单纳入左栏,与咨询会话统一按优先级和分类排列。
### 1.2 提案原始论据与核查结论
| # | 原始论据 | 核查结论 | 依据 |
|---|---|---|---|
| ① | 咨询/审批/工单本质都是待处理的单个事件 | ✅ **成立** | 与 Zendesk / ServiceNow Agent Workspace 的单一工作队列范式一致 |
| ② | 均关联对应员工(左栏) | ❌ **当前不成立** | `TodoItemData``src/frontend-agent/src/api/todo.ts:17`)顶层无 employee 字段 |
| ③ | 均需辅助处理功能(右栏) | ⚠️ **当前未实现,且不应简单共用** | `AiAssistantPanel.vue:100` 仅依赖 `conversationId`,不感知 `workspaceView` |
**对 ② 的补充**:前端待办头像为伪造实现 —— `todoAvatarText()``TodoPanel.vue:224-233`)从 `title``" - "` 切分后取**部门名最后一个字**,颜色取 `title` 的 hash。后端 `applicant` 仅有 userid,埋在 `description` JSON 内未暴露到顶层(`src/backend/app/services/todo_source_service.py:485`)。
**对 ③ 的补充**:会话辅助信息(知识推荐 / 话术 / 排查步骤)服务于「对话」;审批辅助信息(申请人历史 / 同类通过率 / 合规校验)服务于「决策」。二者不同源、不同构。统一三栏布局 ≠ 统一右栏内容,右栏必须按工作项类型分派渲染。
### 1.3 立项主理由(重新论证)
原提案表述为「布局更合理、处理更高效」,论证力度不足。本 PRD 采用以下主理由:
> **待办面板置于右栏属于信息架构语义错位。** 右栏的定义是「当前会话的上下文辅助面板」,而待办是**不隶属于任何会话的全局工作队列**。将全局队列置入上下文面板,破坏了右栏的语义一致性,并导致坐席的工作入口分裂为两处。
### 1.4 与 #132 的关系(须在评审中说明)
| 项 | 内容 |
|---|---|
| #132 做了什么 | 2026-08-0208-03,待办面板由**左栏底部**迁至**右栏底部** |
| #132 的决策依据 | 任务说明书仅记载「与 v1.1 原型保持一致」,验收项含「左栏会话列表不被压缩」。**无信息架构层面论证** |
| 本次是否为返工 | **否**#132 是面板位移;本次是数据模型与列表融合,属架构升级 |
| 需规避 | 若仅将面板移回左栏(见 §5 方案 B),将原地重演 #132 的左栏空间竞争问题,构成第三次搬迁 |
---
## 2. 已确认决策
以下三项经沟通确认,作为本方案的设计约束。
| # | 决策项 | 结论 | 推导出的约束 |
|---|---|---|---|
| **D-1** | 左栏列表主键模型 | **以「事」为主键** | 每个咨询/审批/工单各占一条;员工信息作为条目属性展示,不作聚合维度 |
| **D-2** | 实施顺序 | **先闭环、后合并** | Phase 0(操作闭环)为 Phase 2(布局合并)的硬前置,顺序不可调换 |
| **D-3** | 待办归属范围 | **本人指派 + 组内未分配** | 引入「认领」动作与并发控制 —— **当前系统完全没有此能力,属新增需求** |
### 2.1 D-3 的成本提示
D-3 不是筛选条件的调整,而是新增一条状态机路径。当前 `todo-items` 接口按 `assigned_agent_id` 过滤,不存在无主池概念。落地需新增:
- 后端:未分配待办的查询口径(组边界定义见 §6 未决项 U-3)
- 后端:`claim`(认领)动作 + 幂等与乐观锁(防并发抢单)
- 前端:认领按钮、认领中态、认领失败(已被他人认领)的提示
- 数据:认领操作的审计留痕
---
## 3. 阻塞项(P0
### 3.1 任务详情操作按钮全部为 Mock
```js
// src/frontend-agent/src/components/chat/TaskDetailView.vue:117
function handleAction(action: string): void {
ElMessage.success(`操作成功:${action}`) // 仅 toast,不调用任何接口
}
```
REQ-坐席-004 §2.4 定义的全部操作 —— 工单(接单 / 开始处理 / 结单 / 转派)、审批(通过 / 拒绝 / 转交)—— **均不生效**
**风险定级:P0,阻塞布局合并。**
理由:当前待办面板位于右栏底部 260px 区域,坐席误操作的暴露面有限。一旦将待办提升至左栏主队列首屏,等同于把不可用功能放置于最高可见度位置。坐席点击「审批通过」后收到绿色成功提示,而企业微信侧该单仍处于挂起状态 —— 属于会造成真实业务后果的错误反馈。
---
## 4. 其余工程前置条件
| 编号 | 前置项 | 现状 | 不处理的后果 |
|---|---|---|---|
| **B-1** | 待办缺员工身份字段 | 顶层无 employee_id/name/department`applicant` 仅 userid 且未暴露 | 混排后同列表内会话条目为真人头像+姓名+部门,待办条目为伪头像+部门残字,身份密度断裂,无法按人扫视 |
| **B-2** | 待办无实时推送 | 会话走 WS(`useWebSocket.ts` 12 类事件);待办为 60s 轮询(`TodoPanel.vue:143`),后端**无任何 todo WS 事件** | 紧急审批最长滞后 60s 才浮升;同列表内会话实时跳动而待办静止,坐席对排序失去信任 |
| **B-3** | 优先级不可比 | 会话为 `urgency_score` 1–5 叠加 6 档加权(置顶 10000 / 代办 5000 / 招手 2000 / 需介入 1500 / 情绪 1000 / VIP 800);待办仅 `urgent/high/normal` 三档,且**同档内无二级排序**`todo_aggregator_service.py:134` 无时间兜底) | 混排结果不可解释,坐席无法预期条目位置 |
| **B-4** | SLA 语义冲突 | 会话等待成本为「用户实时干等」(秒级);审批为「当日处理完毕」(小时级) | 纯优先级排序会使 urgent 审批将 `serving` 状态会话挤出首屏。**漏回一条实时会话的代价显著高于晚 30 分钟处理一单审批**,纯优先级模型会系统性放大该错误 |
**B-4 的设计要求**:统一排序权重**不得**仅取优先级,必须引入「实时性/等待可感知度」维度。建议排序键为 `f(优先级, SLA剩余时间, 对端是否在线等待)`,其中「对端在线等待」应具备最高权重档位。具体系数见 §6 未决项 U-2。
---
## 5. 方案选型
| 方案 | 做法 | 优势 | 劣势 | 采纳 |
|---|---|---|---|---|
| **A** 完全融合 | 单列表跨类型混排 | 真正的单一队列 | 四项前置全欠;实时会话被挤压;排序不可解释 | ❌ 不作为首个形态 |
| **B** 移回左栏保持分区 | 左栏上会话、下待办,可折叠 | 改动最小(≈0.5d),立即消除右栏语义错位 | 仍为两个列表;重演 #132 左栏空间竞争,构成第三次搬迁 | ❌ 不单独实施 |
| **C** 统一容器 + Tab 分层 | 左栏 Tab 增加类型层「会话 / 待办 / 全部」,「全部」下混排 | 兼顾专注模式与全局视图;可灰度、可回退 | Tab 层级加深一层 | ✅ **首个落地形态** |
| **D** WorkItem 统一模型 | 后端抽象 WorkItem,会话/工单/审批为其子类型,共享优先级、SLA、关联人、状态机 | 架构最干净;未来接入设备告警、巡检任务零边际成本 | 后端工作量高一个数量级 | ✅ **目标态** |
**采纳路径:以 D 为目标态,C 为首个落地形态,Phase 0 为硬前置。**
---
## 6. 实施路线
> 工时为粗估,用于排序参考,不作为承诺。
### Phase 0 — 操作闭环(P0,阻塞后续全部阶段)
> **U-1 已验证结论(2026-08-08)**:企微审批**不可服务端闭环**(官方文档证实无代审批接口,PC Web 无 JS-SDK 能力),审批动作必须降级为「跳转企微原系统 + 回调状态回写」;ITSM 工单因操作类 OpenAPI 尚未落地,**暂不可判定服务端闭环**,需先降级跳转,待 T05 外部依赖到位后升级。详见 `docs/02-技术文档/技术架构/技术验证-U-1-审批与工单操作闭环可行性-v1.0.md`。
| 任务 | 说明 | 降级层级 |
|---|---|---|
| 审批操作 → 降级跳转 + 回写 | 通过 / 拒绝 / 转交 → 点击「在企微审批中打开」跳转原系统,由 `approval_webhook.py` 接收 `sys_approval_change` 回调 → 补全 `approval.py:902` 状态回写 → WS 推送 | Level 0 立即可做;Level 1 需补回调回写 |
| 工单操作 → 降级跳转(暂) | 接单 / 开始处理 / 结单 / 转派 → 点击「在 ITSM 中打开」跳转原系统;ITSM 写接口到位前不承诺服务端闭环(受 T05 外部阻塞)。**⚠️ 注意:该跳转依赖工单可见,而当前 ITSM 读列表亦未实现(见 U-1.2),故本行在读链路打通前无实际可操作对象** | Level 0(暂,受 U-1.2 前置) |
| 失败态处理 | 移除无条件 `ElMessage.success`,改为「跳转成功提示 + 状态回写后刷新」按三态分派;仍禁止以 toast 作为验收依据 | — |
**验收标准**:操作后外部系统(ITSM / 企微审批)**状态真实变更**,且前端反馈与外部状态**最终一致**(通过回调 / webhook 回写达成)。禁止以 toast 成功作为验收依据。审批 / 工单在降级跳转模式下,以「跳转成功 + 原系统状态通过回调回写并刷新」作为验收闭环,不要求前端内嵌直接操作。
### Phase 1 — 数据层归一(后端)
| 任务 | 对应前置项 |
|---|---|
| `TodoItem` 顶层暴露 `employee_id` / `employee_name` / `department`(由 applicant userid 反查企微通讯录) | B-1 |
| 新增 `sla_due_at` 字段 | B-4 |
| 定义 WorkItem 统一排序权重模型 | B-3 / B-4 |
| 新增 todo WS 事件:`todo_created` / `todo_updated` / `todo_claimed` / `todo_resolved` | B-2 |
| 未分配待办查询口径 + `claim` 动作(幂等 + 乐观锁) | D-3 |
### Phase 2 — 左栏统一容器(前端,方案 C)
| 任务 |
|---|
| 左栏 Tab 分层:类型层(会话 / 待办 / 全部)+ 状态层(沿用 REQ-009 的四态) |
| 定义统一 `ListItem` 类型(含 `kind` 判别式),条目组件支持会话态与任务态两种渲染 |
| 移除 `AiAssistantPanel.vue` 中的 `<TodoPanel />` 挂载 |
| **右栏按 `workspaceView` 分派渲染**(修复现存缺陷:任务详情下右栏仍显示上一会话的排查建议) |
| 修复 `selectConversation` 不重置 `workspaceView` 的问题 |
| 视图切换时保留输入框草稿与滚动位置(当前 `v-if/v-else` 互斥卸载会丢失,`ReplyBox.vue:307``inputText` 为组件局部 ref |
### Phase 3 — 混排与观察
| 任务 |
|---|
| 「全部」Tab 下按归一化权重混排 |
| 灰度发布 + 2 周数据观察(观测指标见下) |
| 依据数据决定是否推进 D(后端 WorkItem 模型) |
**观测指标**:会话首响时长(是否因混排而劣化)、待办平均处理时长、坐席 Tab 切换频次、认领冲突率。
---
## 7. 未决项
| 编号 | 未决项 | 影响 | 需谁决策 |
|---|---|---|---|
| **U-1** | 审批操作能否在坐席 PC Web 端完成 | **已验证(2026-08-08**:企微审批**不可服务端闭环**——官方文档证实无代审批接口,PC Web 亦无 JS-SDK 原生表单能力。结论:审批动作须降级为「跳转企微原系统 + `sys_approval_change` 回调状态回写」。该结论**不阻塞** Phase 0 启动(降级跳转可立即落地)。验证依据见 `技术验证-U-1-审批与工单操作闭环可行性-v1.0.md` | 已闭环(技术) |
| **U-1.1** | ITSM 写接口到位时间 | 工单「接单 / 开始处理 / 结单 / 转派」能否服务端闭环,取决于 ITSM 平台方提供的操作类 OpenAPI 文档、`app_id`/`secret` 写权限、测试账号(对应 T05)。当前项目内 ITSM 仅实现只读查询(`itsm_service.py` 全文件无写操作),无写接口实证。该项是**工单服务端闭环的外部阻塞项**,未到位前工单同样降级跳转 | 平台方 / 外部协调 |
| **U-1.2** 🔴 | **ITSM 工单当前在坐席端完全不可见(读链路即断)** | **代码实证(2026-08-08 主理人复核补录)**`ITSMService.get_todo_list()``src/backend/app/services/itsm_service.py:113-130`**无条件 `return []`**,仅打印告警「ITSM 代办列表 API 尚未实现」。`TodoAggregatorService``todo_aggregator_service.py:110-127`)并发聚合审批与 ITSM 两源,ITSM 分支恒为空 → **待办列表中工单数量恒为 0,现有待办全部是企微审批单**。且因无列表即无 `process_instance_id`,已实现的 `get_todo_detail` / `workitem/detail`(只读)**实际也无从调用**。<br>**影响**:此项**比 U-1.1(写接口缺失)更前置**——写接口的前提是先能读到工单。在读链路打通前,「工单纳入统一队列」在数据层无内容可纳入,Phase 2 的工单部分实为空跑 | 平台方 / 外部协调(与 U-1.1 合并索取) |
| **U-2** | 统一排序权重的具体系数 | 决定混排结果是否可解释、是否会挤压实时会话 | 产品 + 坐席试用反馈 |
| **U-3** | 「组内未分配」的组边界定义 | 全体 IT 支持组?还是按技能/区域路由后的子集?直接影响列表长度 | 产品 |
| **U-4** | 认领并发冲突的交互 | 两名坐席同时认领同一单时的提示与落败方引导 | 产品 |
| **U-5** | 列表长度上限与虚拟滚动 | 合并 + 组内未分配后列表显著变长,260px 宽左栏的承载能力 | 前端 |
| **U-6** | 待办条目的未读/变更标识 | 会话有 `is_todo` 等标志,待办无未读概念,混排后视觉规则需统一 | 产品 |
---
## 8. 风险登记
| 编号 | 风险 | 等级 | 缓解措施 |
|---|---|---|---|
| R-1 | 实时会话被审批挤出首屏,首响时长劣化 | 🔴 高 | 排序模型引入「对端在线等待」最高权重档;Phase 3 灰度观测首响指标 |
| R-2 | 认领并发抢单导致重复处理 | 🟡 中 | 后端乐观锁 + 幂等;前端落败态明确提示 |
| R-3 | 轮询向 WS 迁移期间的双通道数据不一致 | 🟡 中 | 迁移期保留轮询作为兜底,以 WS 事件为主、轮询做对账 |
| R-4 | 第三次布局搬迁引发团队对决策稳定性的质疑 | 🟢 低 | 评审时明确说明本次为架构升级而非位移返工(见 §1.4) |
| R-5 | 工单闭环因 ITSM 写接口缺失受阻,导致 Phase 0 工单部分停滞 | 🟡 中 | U-1 已验证:审批走降级跳转**不阻塞** Phase 0;工单闭环的外部阻塞已独立为 U-1.1 / T05,审批与工单降级跳转可先行落地,不拖累整体路线 |
---
## 9. 明确不在本次范围
- 会话侧数据模型改造(`urgency_score` 与加权标志保持不变)
- H5 员工端任何改动
- 设备异常类型(REQ-004 §2.3 曾定义,现已从 `TodoPanel` 移除,本次不恢复)
- 坐席在线统计数据源(当前取自 `src/mock/data.ts`,属独立技术债)
---
## 10. 变更记录
| 日期 | 版本 | 变更内容 | 变更人 |
|---|---|---|---|
| 2026-08-08 | v0.1 | 创建方案草案;固化 D-1/D-2/D-3 三项决策;完成原始论据核查与现状事实核实 | 宋献 |
| 2026-08-08 | v0.1 | 据 U-1 技术验证结论(架构师高见远)修订 §6 Phase 0 与 §7 U-1:审批明确为降级跳转 + 回写(U-1 已验证);新增 U-1.1 ITSM 写接口外部阻塞项;同步下调 R-5 风险表述 | 宋献 |
| 2026-08-08 | v0.1 | 主理人复核补录 **U-1.2**:代码实证 `ITSMService.get_todo_list()` 无条件返回空列表,ITSM 工单在坐席端读链路即断、当前待办全为企微审批单。该项前置于 U-1.1,一并标注于 §6 Phase 0 工单行 | 齐活林(交付总监) |