v3.1 + 批次0: 智能回复重构基线 - ApprovalMatcher + 关键词降级 + 文档速修 + v4.0任务书面化

This commit is contained in:
Simon
2026-07-17 23:08:59 +08:00
parent 5a77a89ab1
commit 3ed86d5fb3
181 changed files with 19738 additions and 2655 deletions
@@ -0,0 +1,89 @@
# 呼叫坐席功能验证指南
> 后端 `http://localhost:8000` | 前端 `http://localhost:5173`
---
## 前置条件
1. 后端 8000 端口已启动 ✅
2. 前端 H5 5173 端口已启动 ✅
3. 数据库已包含 `ai_substantive_reply_count` 列(项目用 `create_all(checkfirst=True)`,重启后端即自动添加)
## 测试流程(按顺序验证)
### 测试1:打招呼被拦截,按钮不出现
| 步骤 | 操作 | 预期结果 |
|------|------|---------|
| 1 | 浏览器打开 `http://localhost:5173` | 进入会话窗口 |
| 2 | 输入 "你好" 发送 | AI回复引导话术(如"你好!请描述你遇到的IT问题..."),**按钮不出现** |
| 3 | 输入 "hi" 发送 | 同上,引导话术,按钮不出现 |
### 测试2:直接呼叫人工被拦截
| 步骤 | 操作 | 预期结果 |
|------|------|---------|
| 4 | 输入 "人工坐席" 发送 | AI回复引导话术(如"请先描述你的问题,AI会先帮你分析..."),**按钮不出现** |
| 5 | 输入 "转人工" 发送 | 同上 |
### 测试3:正常问题 → AI回复1~2次,按钮不出现
| 步骤 | 操作 | 预期结果 |
|------|------|---------|
| 6 | 输入 "我的打印机连不上了" | AI给出第1次实质性回复,按钮仍不出现 |
| 7 | 输入 "我试了重启还是不行" | AI给出第2次实质性回复,按钮仍不出现 |
### 测试4:AI回复满3次,按钮出现
| 步骤 | 操作 | 预期结果 |
|------|------|---------|
| 8 | 输入 "驱动也重装了还是不行" | AI给出第3次实质性回复,**「👊 呼叫坐席」按钮出现** |
| 9 | 检查底部引导文案 | 变为 "👊👊 呼叫坐席通道已开启..." 橙色闪烁 |
### 测试5:点击按钮 → 弹窗动画
| 步骤 | 操作 | 预期结果 |
|------|------|---------|
| 10 | 点击「👊 呼叫坐席」按钮 | 全屏弹窗,直接进入摇人动画(7个场景SVG依次切换) |
| 11 | 等待动画播放 | 自动发送 shake 请求,成功后有"已通知坐席"提示 |
| 12 | 弹窗自动关闭 | 约4秒后自动关闭,会话进入排队状态 |
### 测试6:API 直接验证(可选)
用 curl 验证后端逻辑:
```bash
# 1. 获取/创建当前会话
curl -s http://localhost:8000/api/h5/conversations/current -H "X-Employee-Id: test001" | python -m json.tool
# 检查返回的 can_call_agent 应为 falseai_substantive_reply_count 应为 0
# 2. 发送问候语 → 应该收到引导回复
curl -s -X POST http://localhost:8000/api/h5/conversations/current/messages \
-H "Content-Type: application/json" \
-d '{"employee_id":"test001","content":"你好"}' | python -m json.tool
# 检查 is_guidance 应为 truecan_call_agent 应为 false
# 3. 发送实际问题 x3
curl -s -X POST http://localhost:8000/api/h5/conversations/current/messages \
-H "Content-Type: application/json" \
-d '{"employee_id":"test001","content":"打印机连不上"}' | python -m json.tool
# 重复3次,第3次后 can_call_agent 应为 true
# 4. 在未满3次时尝试 shake → 应返回 1003 错误
curl -s -X POST http://localhost:8000/api/h5/conversations/current/shake \
-H "Content-Type: application/json" \
-H "X-Employee-Id: test002" \
-d '{}' | python -m json.tool
```
---
## 注意事项
1. **每个会话独立计数**`ai_substantive_reply_count` 是 Conversation 级别的字段,不同用户/会话不共享
2. **切换会话会重置**:新会话从 0 开始
3. **后续可扩展**:如果用户说"谢谢"等结束语,可以重置计数;当前版本未实现此逻辑
@@ -0,0 +1,140 @@
# 会话存档功能 - 测试用例
> **版本**: v1.0 | **日期**: 2026-07-15 | **状态**: 已完成
---
## 1. 测试范围
| 模块 | 测试类型 | 优先级 |
|------|----------|--------|
| 数据模型 | 单元测试 | P0 |
| 归档脚本 | 单元测试 | P0 |
| 管理后台 API | 接口测试 | P0 |
| 坐席端显示 | 集成测试 | P1 |
| 管理后台 UI | UI 测试 | P1 |
---
## 2. 数据模型测试
### 2.1 Conversation 字段测试
| 用例ID | 测试场景 | 预期结果 | 优先级 |
|--------|----------|----------|--------|
| MODEL-01 | 创建会话时 is_archived 默认值为 false | 默认为 false | P0 |
| MODEL-02 | 创建会话时 archived_at 默认值为 null | 默认为 null | P0 |
| MODEL-03 | 归档会话后 is_archived 更新为 true | 值为 true | P0 |
| MODEL-04 | 归档会话后 archived_at 记录归档时间 | 值为归档时间 | P0 |
---
## 3. 归档脚本测试
### 3.1 自动归档测试
| 用例ID | 测试场景 | 预期结果 | 优先级 |
|--------|----------|----------|--------|
| SCRIPT-01 | 已结单超过90天的会话 | 自动标记为已归档 | P0 |
| SCRIPT-02 | 已结单不足90天的会话 | 不标记为已归档 | P0 |
| SCRIPT-03 | 未结单的会话 | 不标记为已归档 | P0 |
| SCRIPT-04 | 已归档的会话再次执行 | 跳过已归档会话 | P0 |
| SCRIPT-05 | 无需归档的会话执行 | 输出"没有需要归档的会话" | P0 |
### 3.2 归档数据准确性测试
| 用例ID | 测试场景 | 预期结果 | 优先级 |
|--------|----------|----------|--------|
| SCRIPT-06 | 归档时记录正确的归档时间 | archived_at 与当前时间误差 < 1秒 | P0 |
| SCRIPT-07 | 批量归档多条会话 | 所有会话正确标记 | P0 |
### 3.3 日志测试
| 用例ID | 测试场景 | 预期结果 | 优先级 |
|--------|----------|----------|--------|
| SCRIPT-08 | 归档执行成功 | 输出归档数量统计 | P1 |
| SCRIPT-09 | 归档执行失败 | 输出错误信息 | P1 |
---
## 4. 管理后台 API 测试
### 4.1 会话列表接口
| 用例ID | 测试场景 | 预期结果 | 优先级 |
|--------|----------|----------|--------|
| API-01 | 不传 is_archived 参数 | 返回全部会话 | P0 |
| API-02 | 传 is_archived=true | 仅返回已归档会话 | P0 |
| API-03 | 传 is_archived=false | 仅返回未归档会话 | P0 |
| API-04 | 组合筛选 status + is_archived | 正确筛选 | P0 |
| API-05 | 分页参数测试 | 分页数据正确 | P1 |
### 4.2 响应数据结构
| 用例ID | 测试场景 | 预期结果 | 优先级 |
|--------|----------|----------|--------|
| API-06 | 获取会话列表 | 包含 is_archived 和 archived_at 字段 | P0 |
| API-07 | 会话详情 | 归档信息正确 | P0 |
---
## 5. 坐席端测试
### 5.1 历史会话显示测试
| 用例ID | 测试场景 | 预期结果 | 优先级 |
|--------|----------|----------|--------|
| AGENT-01 | 90天内的已结单会话 | 显示在历史会话中 | P0 |
| AGENT-02 | 超过90天的已结单会话 | 不显示在历史会话中 | P0 |
| AGENT-03 | 活跃会话 | 显示在当前会话列表 | P0 |
### 5.2 筛选功能测试
| 用例ID | 测试场景 | 预期结果 | 优先级 |
|--------|----------|----------|--------|
| AGENT-04 | 搜索历史会话 | 按关键词过滤 | P1 |
| AGENT-05 | 切换筛选标签 | 正确切换显示内容 | P1 |
---
## 6. 管理后台 UI 测试
### 6.1 归档状态筛选
| 用例ID | 测试场景 | 预期结果 | 优先级 |
|--------|----------|----------|--------|
| UI-01 | 选择"全部" | 显示所有会话 | P0 |
| UI-02 | 选择"未归档" | 仅显示未归档会话 | P0 |
| UI-03 | 选择"已归档" | 仅显示已归档会话 | P0 |
### 6.2 归档状态显示
| 用例ID | 测试场景 | 预期结果 | 优先级 |
|--------|----------|----------|--------|
| UI-04 | 查看未归档会话 | 显示"-"或空 | P0 |
| UI-05 | 查看已归档会话 | 显示"已归档"标签 | P0 |
---
## 7. 性能测试
| 用例ID | 测试场景 | 预期结果 | 优先级 |
|--------|----------|----------|--------|
| PERF-01 | 1000条会话归档 | 执行时间 < 5秒 | P1 |
| PERF-02 | 归档期间查询会话 | 不影响在线查询 | P1 |
---
## 8. 测试用例执行记录
| 执行日期 | 测试人员 | 通过数 | 失败数 | 备注 |
|----------|----------|--------|--------|------|
| 2026-07-15 | Duckula | — | — | 待执行 |
---
## 9. 版本历史
| 版本 | 日期 | 变更 |
|------|------|------|
| v1.0 | 2026-07-15 | 初始版本 |
@@ -0,0 +1,91 @@
# 登录功能测试用例
> **版本**: v1.0 | **日期**: 2026-07-06 | **状态**: 待执行
> **依据文档**: PRD v1.2 §4.5 身份认证与统一入口
> **测试环境**: 本地开发环境
---
## 1. 测试范围
| 模块 | 接口 | 说明 |
|------|------|------|
| 企微免密登录 | `/api/auth_wecom/jsdk-login` | 企微JS-SDK免认证登录 |
| 账号密码登录 | `/api/agents/login` | 坐席/管理员账号密码+OTP登录 |
| MFA验证 | `/api/mfa/verify` | OTP验证码验证 |
---
## 2. 前置条件
### 2.1 测试账号
| 角色 | user_id | 密码 | MFA状态 | 说明 |
|------|---------|------|---------|------|
| 坐席 | `sxn` | `admin123` | 已绑定 | IT支持组组长 |
| 管理员 | `sxn` | `admin123` | 已绑定 | 同上,具有admin权限 |
| 普通员工 | `test_user` | - | 未绑定 | 仅user角色 |
### 2.2 环境要求
- 后端服务运行在 `http://127.0.0.1:8000`
- 前端服务:坐席端 `http://127.0.0.1:5177`,管理后台 `http://127.0.0.1:5178`
- Redis 服务正常运行
- PostgreSQL/SQLite 数据库正常运行
---
## 3. 测试用例
### 3.1 企微免密登录 (/jsdk-login)
| TC_ID | 测试场景 | 前置条件 | 测试步骤 | 预期结果 | 实际结果 | 状态 |
|-------|----------|----------|----------|----------|----------|------|
| JSDK-01 | 企微用户具有坐席角色,免密登录 | user_id 具有 agent 角色 | 1. 前端调用 jsdk-login 传入 userid<br>2. 后端查询角色列表 | 返回 token 和 roles=["agent"] | | 待测试 |
| JSDK-02 | 企微用户具有管理员角色,免密登录 | user_id 具有 admin 角色 | 同上 | 返回 token 和 roles=["admin"] | | 待测试 |
| JSDK-03 | 企微用户具有坐席+管理员角色 | user_id 同时具有 agent 和 admin | 同上 | 返回 token 和 roles=["admin","agent"] | | 待测试 |
| JSDK-04 | 企微用户仅具有user角色 | user_id 只有 user 角色 | 同上 | 返回 403 错误:"您没有坐席或管理员权限" | | 待测试 |
| JSDK-05 | 企微用户无任何角色 | user_id 不在 user_roles 表 | 同上 | 返回 403 错误 | | 待测试 |
### 3.2 账号密码登录 (/agents/login)
| TC_ID | 测试场景 | 前置条件 | 测试步骤 | 预期结果 | 实际结果 | 状态 |
|-------|----------|----------|----------|----------|----------|------|
| PWD-01 | 正确账号密码+OTP登录 | 坐席账号、已绑定MFA | 1. 输入正确账号密码<br>2. 点击登录<br>3. 输入正确OTP | 返回 token,进入工作台 | | 待测试 |
| PWD-02 | 正确账号密码+错误OTP | 坐席账号、已绑定MFA | 1. 输入正确账号密码<br>2. 点击登录<br>3. 输入错误OTP | 返回错误:"OTP验证码错误" | | 待测试 |
| PWD-03 | 正确账号密码+无OTP | 坐席账号、已绑定MFA | 1. 输入正确账号密码<br>2. 点击登录(不输入OTP | 返回 require_otp: true,提示输入OTP | | 待测试 |
| PWD-04 | 错误账号 | 不存在的账号 | 输入错误的user_id | 返回错误:"用户不存在" | | 待测试 |
| PWD-05 | 错误密码 | 正确的user_id,错误密码 | 输入错误的password | 返回错误:"本地密码错误" | | 待测试 |
| PWD-06 | 账号密码登录(未绑定MFA) | 坐席账号、未绑定MFA | 输入正确的账号密码 | 直接返回 token,无需OTP | | 待测试 |
### 3.3 MFA 验证
| TC_ID | 测试场景 | 前置条件 | 测试步骤 | 预期结果 | 实际结果 | 状态 |
|-------|----------|----------|----------|----------|----------|------|
| MFA-01 | 正确OTP验证码 | 已绑定MFA的坐席 | 调用 /api/mfa/verify | 返回验证成功 | | 待测试 |
| MFA-02 | 错误OTP验证码 | 已绑定MFA的坐席 | 输入错误的OTP | 返回验证失败 | | 待测试 |
| MFA-03 | 已验证状态(30分钟内) | 之前已通过OTP验证 | 再次调用需要MFA的接口 | 无需再次OTP | | 待测试 |
---
## 4. 执行记录
| 执行日期 | 测试人员 | 环境 | 备注 |
|----------|----------|------|------|
| 2026-07-06 | | 本地开发环境 | 首轮测试 |
---
## 5. 缺陷记录
| 缺陷ID | 对应TC | 描述 | 严重程度 | 状态 |
|--------|--------|------|----------|------|
| | | | | |
---
## 6. 修订历史
| 版本 | 日期 | 变更内容 | 修改人 |
|------|------|----------|--------|
| v1.0 | 2026-07-06 | 初始版本 | Claude |