# Implementation Tasks ## 1. 数据存储与状态管理 - [x] 1.1 创建 localStorage 键 `outbound_call_jobs` 用于存储 jobId 数组和状态 - [x] 1.2 实现 jobId 数据结构设计:`{ jobId, callStatus, startTime, personId, mediationId }` - [x] 1.3 实现状态过滤逻辑:活跃状态保留,终态清除 - [x] 1.4 新增失败任务存储:创建 `outbound_call_jobs_failed` 键存储失败记录 - [x] 1.5 实现失败任务去重:按 personId 去重,避免重复显示 - [x] 1.6 实现自动清理:失败任务超过24小时自动清除 ## 2. CaseDataContext 外呼触发逻辑 - [x] 2.1 在 `loadCaseData` 方法的第 141 行 `saveToStorage(timelineData)` 之后添加外呼触发调用 - [x] 2.2 检查 localStorage 中是否有活跃的 jobId,如有则跳过发起新外呼 - [x] 2.3 提取 `mediationId`(timelineData.id)和 `caseId`(timelineData.case_id)构建请求参数 - [x] 2.4 调用 `OutboundBotAPIService.makeCallV2({ mediationId, caseId, callAuto: 0, callPersonId: null })` - [x] 2.5 处理 `makeCallV2` 响应: - [x] 2.5.1 解析 `response.data` 数组,提取所有 `errorCode === 0` 的记录 - [x] 2.5.2 存储 jobId、callStatus、personId 等信息到 localStorage - [x] 2.5.3 失败时(errorCode !== 0)展示 `message.error()` 并记录控制台日志 - [x] 2.6 错误捕获:`makeCallV2` 调用失败时展示友好提示,不阻塞页面加载 - [x] 2.7 失败任务处理:存储失败任务到独立的 localStorage 键,支持后续显示 ## 3. OutboundCallWidget 轮询改造 - [x] 3.1 移除现有 `getCallStatus` 基于 `caseRef` 的轮询逻辑 - [x] 3.2 从 localStorage 读取 `outbound_call_jobs`,过滤活跃状态的 jobId - [x] 3.3 实现新的轮询逻辑: - [x] 3.3.1 遍历所有活跃 jobId,调用 `OutboundBotAPIService.getCallStatus({ jobId })` - [x] 3.3.2 更新 `calls` 状态数组,展示通话人和状态信息 - [x] 3.3.3 检测终态状态(Succeeded/Failed/Cancelled),从 localStorage 移除对应 jobId - [x] 3.4 设置轮询间隔为 10 秒(`setInterval(fetchCallStatus, 10000)`) - [x] 3.5 实现最大轮询时长限制(2小时): - [x] 3.5.1 记录轮询开始时间 - [x] 3.5.2 每次轮询检查是否超时,超时则停止轮询并清理 jobId - [x] 3.6 实现失败重试机制: - [x] 3.6.1 为每个 jobId 维护重试计数器 - [x] 3.6.2 单次查询失败时累加计数,最多重试 10 次 - [x] 3.6.3 超过 10 次失败后展示 `message.error()` 并移除该 jobId - [x] 3.7 失败任务显示:读取失败任务并展示在气泡中 - [x] 3.8 重复任务去重:读取时按 personId 去重,避免重复显示 ## 4. 气泡组件显示优化 - [x] 4.1 支持多任务显示:当 `calls.length > 1` 时,纵向堆叠展示多个气泡 - [x] 4.2 显示字段映射: - [x] 4.2.1 通话人姓名:从 API 响应的 `personId` 或 Mock 数据获取 - [x] 4.2.2 通话状态:中文映射(Scheduling→拨号中,Executing→通话中等) - [x] 4.2.3 通话时长:根据 `startTime` 和当前时间计算(格式:MM:SS) - [x] 4.3 终态处理:当所有 jobId 均为终态时,自动隐藏气泡(设置 `isVisible=false`) - [x] 4.4 失败任务视觉优化:蓝色气泡 + 红色呼吸灯状态指示 - [x] 4.5 成功任务视觉优化:蓝色气泡 + 绿色呼吸灯状态指示 ## 5. 组件卸载与清理 - [x] 5.1 在 `OutboundCallWidget` 的 `useEffect` 清理函数中停止轮询定时器 - [x] 5.2 用户离开页面时(如路由切换),确保定时器被清除 - [x] 5.3 避免内存泄漏:组件卸载时取消所有待处理的 API 请求(如使用 AbortController) ## 6. 错误提示与日志 - [x] 6.1 `makeCallV2` 失败时:`message.error('发起外呼失败,请稍后重试')` + `console.error(err)` - [x] 6.2 `getCallStatus` 重试超限时:`message.error('获取通话状态失败,请检查网络连接')` + `console.error()` - [x] 6.3 所有关键步骤记录 `console.log`,便于前端调试 - [x] 6.4 失败任务提示:`message.warning('部分联系人外呼失败')` + 控制台日志 ## 7. 测试与验证 - [x] 7.1 测试场景1:首次进入首页,自动发起外呼,气泡正常弹出 - [x] 7.2 测试场景2:刷新页面,检测到活跃 jobId,继续监听不发起新外呼 - [x] 7.3 测试场景3:多人外呼(2个jobId),气泡同时展示两条记录 - [x] 7.4 测试场景4:通话成功(Succeeded),气泡消失,jobId 清除 - [x] 7.5 测试场景5:通话失败(Failed),展示错误提示,jobId 清除 - [x] 7.6 测试场景6:API 连续失败 10 次,展示重试超限提示 - [x] 7.7 测试场景7:轮询超过 2 小时,自动停止并清理 - [x] 7.8 测试场景8:组件卸载时定时器正常清除,无报错 - [x] 7.9 测试场景9:失败任务正确显示在气泡中,带红色状态指示灯 - [x] 7.10 测试场景10:重复失败任务自动去重,不重复显示 - [x] 7.11 测试场景11:失败任务超过24小时自动清理 ## 8. 性能优化 - [x] 8.1 localStorage 读写优化:减少不必要的序列化/反序列化操作 - [x] 8.2 轮询性能优化:只对活跃任务进行轮询查询 - [x] 8.3 内存泄漏防护:组件卸载时正确清理所有定时器和事件监听器 ## 9. 文档与注释 - [x] 9.1 为新增代码添加 JSDoc 注释 - [x] 9.2 更新 `OutboundCallWidget.jsx` 头部组件说明 - [x] 9.3 在关键逻辑处添加行内注释(jobId 状态判断、轮询逻辑等) - [x] 9.4 更新 tasks.md 文档,标记完成状态并添加新任务项 - [x] 9.5 创建开发规范记忆:外呼失败状态指示圆点颜色规范