2026-05-12
This commit is contained in:
203
ai_project/.claude/agents/demand-assessor.md
Normal file
203
ai_project/.claude/agents/demand-assessor.md
Normal file
@@ -0,0 +1,203 @@
|
||||
你是一个精通 Java 微服务架构的资深技术负责人。
|
||||
|
||||
请基于以下统一模型评估需求的工作量。
|
||||
|
||||
==============================
|
||||
整体工作量模型
|
||||
==============================
|
||||
|
||||
工作量指数 W =
|
||||
(单元业务复杂度 B × 单元数量 S)
|
||||
× 技术复杂度系数 F(T)
|
||||
× AI效率系数 G(A)
|
||||
|
||||
其中:
|
||||
|
||||
B = 单个功能单元复杂度
|
||||
S = 单元数量
|
||||
F(T) = 技术放大系数
|
||||
G(A) = AI效率系数
|
||||
|
||||
请严格按照步骤执行。
|
||||
|
||||
|
||||
====================================================
|
||||
第一部分:识别功能单元(规模 S)
|
||||
====================================================
|
||||
|
||||
1. 识别最小可重复功能单元
|
||||
(例如:接口、页面、报表、定时任务等)
|
||||
|
||||
2. 统计每类单元数量
|
||||
|
||||
要求:
|
||||
- 不要在此阶段评估复杂度
|
||||
- 仅统计数量
|
||||
|
||||
输出:
|
||||
- 单元类型
|
||||
- 每类数量
|
||||
- 总数量 S
|
||||
|
||||
|
||||
====================================================
|
||||
第二部分:单元业务复杂度评估 B(仅评单个单元)
|
||||
====================================================
|
||||
|
||||
假设只实现一个单元,评分(1-5):
|
||||
|
||||
1. 业务规则数量
|
||||
2. 状态流转复杂度
|
||||
3. 异常处理复杂度
|
||||
4. 边界场景复杂度
|
||||
5. 需求不确定性
|
||||
|
||||
计算:
|
||||
|
||||
B = 五项平均值(保留1位小数)
|
||||
|
||||
注意:
|
||||
禁止在此阶段考虑单元数量。
|
||||
|
||||
输出:
|
||||
- 各项评分
|
||||
- 单元复杂度 B
|
||||
|
||||
|
||||
====================================================
|
||||
第三部分:技术复杂度评估 F(T)
|
||||
====================================================
|
||||
|
||||
评估技术复杂度等级 T(1-5):
|
||||
|
||||
1 = 单服务简单CRUD
|
||||
2 = 单服务中等逻辑
|
||||
3 = 多服务调用
|
||||
4 = 涉及DB变更/MQ
|
||||
5 = 分布式事务/核心链路/高并发
|
||||
|
||||
计算:
|
||||
|
||||
F(T) = 1 + 0.2 × (T - 1)
|
||||
|
||||
输出:
|
||||
- T值
|
||||
- 技术复杂度系数 F(T)
|
||||
- 技术风险说明
|
||||
|
||||
|
||||
====================================================
|
||||
第四部分:AI效率系数 G(A) 计算
|
||||
====================================================
|
||||
|
||||
步骤A:正向评分(1-5分)
|
||||
|
||||
1.需求清晰
|
||||
2.规则明确度
|
||||
3.可验证性
|
||||
4.代码结构清晰度
|
||||
|
||||
P = 三项得分之和
|
||||
|
||||
|
||||
步骤B:架构抽象复杂度(计数制)
|
||||
|
||||
每触发一项 +1:
|
||||
|
||||
- 策略/模板动态组合
|
||||
- 插件或SPI机制
|
||||
- 规则引擎/表达式驱动
|
||||
- AOP深度影响核心逻辑
|
||||
- Saga/TCC/补偿机制
|
||||
- 多租户/动态数据源
|
||||
|
||||
记为 N1
|
||||
|
||||
|
||||
步骤C:变更影响范围(计数制)
|
||||
|
||||
每触发一项 +1:
|
||||
|
||||
- 老服务接口变更
|
||||
- 数据库老表变更
|
||||
- 核心业务链路变更
|
||||
- 公共组件修改
|
||||
- 权限安全机制修改
|
||||
- 分布式事务/MQ变更
|
||||
- 低测试覆盖区域
|
||||
|
||||
记为 N2
|
||||
|
||||
|
||||
步骤D:历史耦合程度(计数制)
|
||||
|
||||
每触发一项 +1:
|
||||
|
||||
- 巨型类
|
||||
- 高复杂度方法
|
||||
- 隐式调用链
|
||||
- 模块边界不清晰
|
||||
- 测试覆盖<30%
|
||||
- 多服务共享数据库
|
||||
- 无维护人/无文档
|
||||
|
||||
记为 N3
|
||||
|
||||
|
||||
步骤E:计算
|
||||
|
||||
N = N1 + N2 + N3
|
||||
|
||||
A = P - N
|
||||
|
||||
|
||||
====================================================
|
||||
第五部分:安全门检查
|
||||
====================================================
|
||||
|
||||
若满足任一:
|
||||
|
||||
- 修改核心结算逻辑
|
||||
- 修改分布式事务核心
|
||||
- 修改权限核心鉴权
|
||||
- 单测覆盖率<20%
|
||||
- 无法清晰定位影响范围
|
||||
|
||||
标记为【高风险变更】
|
||||
|
||||
|
||||
|
||||
====================================================
|
||||
第六部分:AI效率系数映射
|
||||
====================================================
|
||||
|
||||
若非高风险变更:
|
||||
|
||||
A ≥ 10 → G(A) = 0.55
|
||||
8 ≤ A < 10 → G(A) = 0.65
|
||||
6 ≤ A < 8 → G(A) = 0.75
|
||||
3 ≤ A < 6 → G(A) = 0.85
|
||||
1 ≤ A < 3 → G(A) = 0.95
|
||||
A ≤ 0 → G(A) = 1.0
|
||||
|
||||
|
||||
====================================================
|
||||
第七部分:最终工作量计算
|
||||
====================================================
|
||||
|
||||
计算:
|
||||
|
||||
基础工作量 = B × S
|
||||
技术放大后 = 基础工作量 × F(T)
|
||||
最终工作量指数 W = 技术放大后 × G(A)
|
||||
|
||||
请输出:
|
||||
|
||||
1. 单元数量 S
|
||||
2. 单元复杂度 B
|
||||
3. 技术系数 F(T)
|
||||
4. AI效率系数 G(A)
|
||||
5. 最终工作量指数 W
|
||||
6. 综合风险等级(低/中/高)
|
||||
7. 是否建议拆分需求
|
||||
8. AI建议参与方式
|
||||
3598
cc-center/FreeSWITCH技术架构与ESL开发指南.txt
Normal file
3598
cc-center/FreeSWITCH技术架构与ESL开发指南.txt
Normal file
File diff suppressed because it is too large
Load Diff
6953
cc-center/chat-📞 呼叫中心系统需求规划.txt
Normal file
6953
cc-center/chat-📞 呼叫中心系统需求规划.txt
Normal file
File diff suppressed because it is too large
Load Diff
871
cc-center/企业呼叫中心系统需求规格说明书.txt
Normal file
871
cc-center/企业呼叫中心系统需求规格说明书.txt
Normal file
@@ -0,0 +1,871 @@
|
||||
**文档版本**:V1.0
|
||||
**编制日期**:2024年1月
|
||||
**文档状态**:初稿
|
||||
|
||||
---
|
||||
|
||||
## 第一章 项目概述
|
||||
|
||||
### 1.1 项目背景
|
||||
|
||||
本企业主营道路救援、家政服务、代驾服务三大业务板块,面向个人消费者(ToC)提供服务。随着业务规模扩大,现需建设一套专业的呼叫中心系统,
|
||||
以提升客户服务体验、提高服务响应效率、降低人工成本。
|
||||
|
||||
### 1.2 项目目标
|
||||
|
||||
| 目标维度 | 具体目标 |
|
||||
|---------|---------|
|
||||
| **服务能力** | 支持150坐席同时在线,日处理呼叫量50,000通 |
|
||||
| **响应效率** | 道路救援等紧急服务实现快速响应,7×24小时不间断服务 |
|
||||
| **人工效率** | 通过预测式外呼提升坐席利用率,减少空闲等待时间 |
|
||||
| **自动化水平** | 通过智能IVR和机器人实现常见问题自助解答、批量通知自动化 |
|
||||
| **系统稳定性** | 主备高可用架构,确保核心业务(道路救援)不中断 |
|
||||
|
||||
### 1.3 项目范围
|
||||
|
||||
**纳入范围:**
|
||||
- 基础呼叫能力(呼入/呼出)
|
||||
- 智能IVR与语音导航
|
||||
- 呼入/呼出机器人
|
||||
- 预测式外呼
|
||||
- 无人化批量通知
|
||||
- CRM系统集成(API对接)
|
||||
- 软电话条组件
|
||||
- 实时监控大屏
|
||||
- 班长监控功能
|
||||
- 全程录音
|
||||
- 主备高可用部署
|
||||
|
||||
**不纳入本期范围:**
|
||||
- 统计报表系统(二期规划)
|
||||
- 智能质检系统(二期规划)
|
||||
- 短信功能(由第三方平台提供)
|
||||
|
||||
### 1.4 术语定义
|
||||
|
||||
| 术语 | 定义 |
|
||||
|------|------|
|
||||
| **ACD** | 自动呼叫分配(Automatic Call Distribution) |
|
||||
| **IVR** | 交互式语音应答(Interactive Voice Response) |
|
||||
| **ASR** | 自动语音识别(Automatic Speech Recognition) |
|
||||
| **TTS** | 语音合成(Text To Speech) |
|
||||
| **NLU** | 自然语言理解(Natural Language Understanding) |
|
||||
| **CTI** | 计算机电话集成(Computer Telephony Integration) |
|
||||
| **SIP** | 会话发起协议(Session Initiation Protocol) |
|
||||
|
||||
---
|
||||
|
||||
## 第二章 业务需求
|
||||
|
||||
### 2.1 业务架构
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ 客户触点 │
|
||||
│ 道路救援热线 家政服务热线 代驾服务热线 │
|
||||
│ (400-XXX-XXXX) (400-XXX-XXXX) (固话/400) │
|
||||
└───────────────┬─────────────────┬─────────────────┬─────────────┘
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ 呼叫中心系统 │
|
||||
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
||||
│ │ 智能IVR │ │ 呼入机器人│ │ ACD分配 │ │ 外呼系统 │ │
|
||||
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
|
||||
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
||||
│ │ 坐席管理 │ │ 录音系统 │ │ 实时监控 │ │ API网关 │ │
|
||||
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
|
||||
└───────────────────────────┬─────────────────────────────────────┘
|
||||
│ API
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ CRM/业务系统 │
|
||||
│ 客户管理 │ 工单管理 │ 派单系统 │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 2.2 呼入业务场景
|
||||
|
||||
#### 2.2.1 道路救援来电场景
|
||||
|
||||
**业务流程:**
|
||||
|
||||
```
|
||||
客户来电
|
||||
→ 智能IVR(语音识别:"道路救援")
|
||||
→ 机器人收集初步信息(可选)
|
||||
→ 转救援技能组
|
||||
→ ACD分配(历史服务优先 > 最长空闲 > 轮询)
|
||||
→ 技能组全忙时溢出到备用组
|
||||
→ 坐席接听 + CRM弹屏
|
||||
→ 坐席在CRM创建工单/派单
|
||||
→ 通话结束 → 录音保存
|
||||
```
|
||||
|
||||
**业务要求:**
|
||||
- 响应时效要求高,需优先保障接通率
|
||||
- 支持7×24小时服务
|
||||
- 来电需快速识别客户身份,展示历史服务记录
|
||||
|
||||
#### 2.2.2 家政服务来电场景
|
||||
|
||||
**业务流程:**
|
||||
|
||||
```
|
||||
客户来电
|
||||
→ 智能IVR(按键或语音选择"家政服务")
|
||||
→ 常见问题解答(服务项目、价格咨询等)
|
||||
→ 客户需要人工服务 → 转家政技能组
|
||||
→ 坐席接听 + CRM弹屏
|
||||
→ 预约服务/创建工单
|
||||
→ 通话结束 → 录音保存
|
||||
```
|
||||
|
||||
#### 2.2.3 代驾服务来电场景
|
||||
|
||||
**业务流程:**
|
||||
|
||||
```
|
||||
客户来电
|
||||
→ 智能IVR(语音识别:"叫代驾")
|
||||
→ 转代驾技能组
|
||||
→ 坐席接听 + CRM弹屏
|
||||
→ 创建代驾订单/派单
|
||||
→ 通话结束 → 录音保存
|
||||
```
|
||||
|
||||
#### 2.2.4 投诉来电场景
|
||||
|
||||
**业务流程:**
|
||||
|
||||
```
|
||||
客户来电
|
||||
→ 智能IVR(识别"投诉"意图)
|
||||
→ 直接转人工(投诉不经机器人处理)
|
||||
→ 分配至对应业务技能组或投诉专席
|
||||
→ CRM弹屏 + 标记投诉标签
|
||||
→ 坐席记录投诉内容
|
||||
```
|
||||
|
||||
### 2.3 呼出业务场景
|
||||
|
||||
#### 2.3.1 预测式外呼(营销/回访)
|
||||
|
||||
**业务流程:**
|
||||
|
||||
```
|
||||
业务系统推送外呼任务(客户名单)
|
||||
→ 呼叫中心批量拨打
|
||||
→ 客户接听 → 自动转接空闲坐席
|
||||
→ CRM弹屏展示客户信息
|
||||
→ 坐席进行营销/回访
|
||||
→ 通话结束 → 录音保存 → 话单回传业务系统
|
||||
```
|
||||
|
||||
**业务要求:**
|
||||
- 系统自动拨打,接通后才转坐席,减少坐席等待时间
|
||||
- 支持接通率、坐席利用率统计
|
||||
- 外呼任务支持暂停、恢复、停止
|
||||
|
||||
#### 2.3.2 机器人自动外呼(通知类)
|
||||
|
||||
**场景一:服务人员派出/即将到达通知**
|
||||
|
||||
```
|
||||
业务系统触发通知(API调用)
|
||||
→ 呼叫中心自动拨打客户电话
|
||||
→ 播放TTS语音:"您好,您预约的道路救援服务,师傅已出发,预计10分钟到达..."
|
||||
→ 通话结束 → 结果回传业务系统
|
||||
```
|
||||
|
||||
**场景二:账单催缴提醒**
|
||||
|
||||
```
|
||||
业务系统推送催缴名单
|
||||
→ 批量自动拨打
|
||||
→ 播放TTS语音:"您好,您有一笔待支付账单..."
|
||||
→ 纯语音播报,无需交互
|
||||
→ 拨打结果回传(接通/未接通/关机等)
|
||||
```
|
||||
|
||||
#### 2.3.3 机器人自动外呼(回访/满意度调查)
|
||||
|
||||
**业务流程:**
|
||||
|
||||
```
|
||||
业务系统推送回访任务
|
||||
→ 呼叫中心自动拨打
|
||||
→ 播放TTS语音:"您好,请问您对本次服务满意吗?满意请按1,不满意请按2"
|
||||
→ 采集客户按键
|
||||
→ 按键结果回传业务系统
|
||||
→ 不满意客户可选择转人工跟进
|
||||
```
|
||||
|
||||
### 2.4 机器人客服场景
|
||||
|
||||
#### 2.4.1 呼入机器人功能定位
|
||||
|
||||
| 功能 | 说明 |
|
||||
|------|------|
|
||||
| **语音导航** | 支持客户语音说出需求,自动识别并转接对应技能组 |
|
||||
| **常见问题解答** | 支持50个以上FAQ,自动语音解答 |
|
||||
| **转人工预处理** | 收集客户初步信息后转人工,提高坐席效率 |
|
||||
|
||||
#### 2.4.2 转人工触发条件
|
||||
|
||||
| 触发条件 | 说明 |
|
||||
|---------|------|
|
||||
| 客户主动要求 | 客户说"转人工"或按键选择转人工 |
|
||||
| 识别失败 | 机器人连续2-3次无法识别客户意图 |
|
||||
| 特定问题类型 | 投诉类问题直接转人工,不经机器人处理 |
|
||||
|
||||
---
|
||||
|
||||
## 第三章 功能需求
|
||||
|
||||
### 3.1 智能IVR模块
|
||||
|
||||
#### 3.1.1 功能清单
|
||||
|
||||
| 功能编号 | 功能名称 | 功能描述 | 优先级 |
|
||||
|---------|---------|---------|--------|
|
||||
| IVR-001 | 多级语音菜单 | 支持配置多级IVR语音菜单,按键导航 | P0 |
|
||||
| IVR-002 | 语音识别导航 | 集成阿里云ASR,支持客户语音说出需求自动识别 | P0 |
|
||||
| IVR-003 | 多业务线路由 | 根据来电号码(400/固话)自动进入对应业务IVR流程 | P0 |
|
||||
| IVR-004 | 时间条件路由 | 支持按工作时间/节假日配置不同IVR流程 | P1 |
|
||||
| IVR-005 | 黑名单拦截 | 来电号码在黑名单中自动播放提示后挂断 | P1 |
|
||||
| IVR-006 | VIP客户识别 | VIP客户来电自动优先排队或转专属坐席 | P2 |
|
||||
| IVR-007 | IVR流程可视化配置 | 提供可视化拖拽界面配置IVR流程 | P1 |
|
||||
|
||||
#### 3.1.2 语音识别要求
|
||||
|
||||
- **ASR供应商**:阿里云语音识别
|
||||
- **识别准确率**:≥90%
|
||||
- **响应时间**:≤500ms
|
||||
- **支持方言**:普通话为主,可选支持粤语、四川话等
|
||||
|
||||
### 3.2 ACD自动分配模块
|
||||
|
||||
#### 3.2.1 功能清单
|
||||
|
||||
| 功能编号 | 功能名称 | 功能描述 | 优先级 |
|
||||
|---------|---------|---------|--------|
|
||||
| ACD-001 | 技能组管理 | 支持创建多个技能组(救援组、家政组、代驾组) | P0 |
|
||||
| ACD-002 | 坐席技能配置 | 坐席可属于一个或多个技能组,配置技能等级 | P0 |
|
||||
| ACD-003 | 历史服务优先 | 来电客户优先分配给上次服务的坐席 | P0 |
|
||||
| ACD-004 | 最长空闲优先 | 同技能组内优先分配给空闲时间最长的坐席 | P0 |
|
||||
| ACD-005 | 轮询分配 | 同技能组内按顺序轮流分配 | P0 |
|
||||
| ACD-006 | 分配策略优先级 | 支持配置分配策略优先级:历史服务 > 最长空闲 > 轮询 | P0 |
|
||||
| ACD-007 | 技能组溢出 | 技能组全忙时,来电溢出到配置的备用技能组 | P0 |
|
||||
| ACD-008 | 排队等待 | 所有坐席忙时,来电进入排队,播放等待音乐 | P0 |
|
||||
| ACD-009 | 排队超时处理 | 排队超时可配置:继续等待/溢出/留言/回拨 | P1 |
|
||||
| ACD-010 | 排队位置播报 | 向等待客户播报当前排队位置 | P2 |
|
||||
|
||||
### 3.3 坐席管理模块
|
||||
|
||||
#### 3.3.1 功能清单
|
||||
|
||||
| 功能编号 | 功能名称 | 功能描述 | 优先级 |
|
||||
|---------|---------|---------|--------|
|
||||
| AGT-001 | 坐席签入/签出 | 坐席上下班签入签出系统 | P0 |
|
||||
| AGT-002 | 坐席状态管理 | 支持状态:空闲、通话中、振铃中、后处理、小休、忙碌 | P0 |
|
||||
| AGT-003 | 小休原因 | 小休时需选择原因(用餐、洗手间、培训等) | P1 |
|
||||
| AGT-004 | 状态自动切换 | 通话结束自动进入后处理状态,超时自动转空闲 | P0 |
|
||||
| AGT-005 | 后处理时长配置 | 可配置后处理时长(如30秒) | P1 |
|
||||
| AGT-006 | 强制签出 | 班长可强制签出坐席 | P1 |
|
||||
|
||||
#### 3.3.2 坐席工作台要求
|
||||
|
||||
- 坐席不使用呼叫中心独立工作台
|
||||
- 坐席在CRM系统中操作业务
|
||||
- 呼叫中心提供**软电话条组件**嵌入CRM页面
|
||||
- 软电话条通过WebSocket与呼叫中心通信
|
||||
- 同时支持IP话机(SIP协议注册)
|
||||
|
||||
### 3.4 软电话条组件
|
||||
|
||||
#### 3.4.1 功能清单
|
||||
|
||||
| 功能编号 | 功能名称 | 功能描述 | 优先级 |
|
||||
|---------|---------|---------|--------|
|
||||
| SFT-001 | 签入/签出 | 坐席登录CRM后通过软电话条签入呼叫中心 | P0 |
|
||||
| SFT-002 | 状态切换 | 置忙/置闲/小休状态切换按钮 | P0 |
|
||||
| SFT-003 | 来电弹屏触发 | 来电时向CRM发送弹屏事件,携带来电号码、客户ID等 | P0 |
|
||||
| SFT-004 | 接听/挂断 | 点击接听/挂断按钮控制通话 | P0 |
|
||||
| SFT-005 | 保持/取回 | 通话保持(播放等待音乐)和取回 | P0 |
|
||||
| SFT-006 | 静音 | 坐席侧静音 | P1 |
|
||||
| SFT-007 | 转接 | 转接至其他坐席/技能组/外线号码 | P0 |
|
||||
| SFT-008 | 咨询转 | 先与第三方通话咨询,再决定是否转接 | P1 |
|
||||
| SFT-009 | 三方通话 | 坐席、客户、第三方三方通话 | P1 |
|
||||
| SFT-010 | 点击拨号 | 在CRM中点击号码呼出 | P0 |
|
||||
| SFT-011 | 手动拨号 | 手动输入号码拨打 | P0 |
|
||||
| SFT-012 | 通话计时 | 显示当前通话时长 | P0 |
|
||||
| SFT-013 | 来电信息展示 | 显示来电号码、归属地、技能组等 | P0 |
|
||||
|
||||
#### 3.4.2 软电话条技术要求
|
||||
|
||||
| 要求项 | 说明 |
|
||||
|-------|------|
|
||||
| **前端技术** | Web组件,支持iframe嵌入或JS SDK集成 |
|
||||
| **通信协议** | WebSocket长连接,实时接收呼叫事件 |
|
||||
| **语音方案** | WebRTC(浏览器软电话)或SIP话机(硬件话机) |
|
||||
| **浏览器支持** | Chrome 70+、Firefox 65+、Edge 79+ |
|
||||
|
||||
### 3.5 呼入通话控制
|
||||
|
||||
#### 3.5.1 功能清单
|
||||
|
||||
| 功能编号 | 功能名称 | 功能描述 | 优先级 |
|
||||
|---------|---------|---------|--------|
|
||||
| IBC-001 | 来电接入 | 支持SIP中继接入来电 | P0 |
|
||||
| IBC-002 | 来电排队 | 坐席全忙时来电进入队列等待 | P0 |
|
||||
| IBC-003 | 等待音乐 | 排队等待时播放等待音乐 | P0 |
|
||||
| IBC-004 | 来电转接 | 支持盲转、咨询转、转技能组、转外线 | P0 |
|
||||
| IBC-005 | 三方通话 | 支持三方会议通话 | P1 |
|
||||
| IBC-006 | 通话保持 | 通话保持并播放等待音乐 | P0 |
|
||||
| IBC-007 | 通话录音 | 全程录音,支持双声道(坐席/客户分轨)| P0 |
|
||||
|
||||
### 3.6 呼出通话控制
|
||||
|
||||
#### 3.6.1 功能清单
|
||||
|
||||
| 功能编号 | 功能名称 | 功能描述 | 优先级 |
|
||||
|---------|---------|---------|--------|
|
||||
| OBC-001 | 点击外呼 | 坐席点击号码发起外呼 | P0 |
|
||||
| OBC-002 | 外显号码设置 | 支持配置外呼显示的主叫号码 | P0 |
|
||||
| OBC-003 | 外呼转接 | 外呼通话中支持转接 | P0 |
|
||||
| OBC-004 | 通话录音 | 外呼通话全程录音 | P0 |
|
||||
|
||||
### 3.7 预测式外呼模块
|
||||
|
||||
#### 3.7.1 功能清单
|
||||
|
||||
| 功能编号 | 功能名称 | 功能描述 | 优先级 |
|
||||
|---------|---------|---------|--------|
|
||||
| PDL-001 | 外呼任务创建 | 通过API创建外呼任务,导入号码名单 | P0 |
|
||||
| PDL-002 | 任务状态控制 | 支持任务启动、暂停、恢复、停止 | P0 |
|
||||
| PDL-003 | 预测式拨号算法 | 根据坐席空闲情况自动计算拨打频率 | P0 |
|
||||
| PDL-004 | 接通转坐席 | 客户接听后自动转接空闲坐席 | P0 |
|
||||
| PDL-005 | 无人接听处理 | 无人接听/忙音/关机等自动标记状态 | P0 |
|
||||
| PDL-006 | 外呼时段限制 | 可配置允许外呼的时间段(如9:00-21:00) | P1 |
|
||||
| PDL-007 | 号码去重 | 同一任务内号码自动去重 | P1 |
|
||||
| PDL-008 | 重试策略 | 未接通号码可配置自动重试次数和间隔 | P1 |
|
||||
| PDL-009 | 坐席利用率统计 | 统计坐席有效通话时长占比 | P0 |
|
||||
| PDL-010 | 接通率统计 | 统计任务接通率 | P0 |
|
||||
|
||||
### 3.8 机器人外呼模块
|
||||
|
||||
#### 3.8.1 功能清单
|
||||
|
||||
| 功能编号 | 功能名称 | 功能描述 | 优先级 |
|
||||
|---------|---------|---------|--------|
|
||||
| RBT-001 | 批量通知任务 | 通过API创建批量语音通知任务 | P0 |
|
||||
| RBT-002 | TTS语音播放 | 集成阿里云TTS,文本转语音播放 | P0 |
|
||||
| RBT-003 | 变量替换 | 支持语音内容中插入变量(姓名、时间、金额等) | P0 |
|
||||
| RBT-004 | 纯播报模式 | 播放语音后直接挂断 | P0 |
|
||||
| RBT-005 | 按键采集模式 | 播放语音后等待客户按键,采集结果 | P0 |
|
||||
| RBT-006 | 按键结果回传 | 按键结果通过回调接口推送至业务系统 | P0 |
|
||||
| RBT-007 | 无应答处理 | 客户无应答/超时可配置重试或标记 | P1 |
|
||||
| RBT-008 | 并发控制 | 可配置任务最大并发拨打数 | P1 |
|
||||
| RBT-009 | 任务进度查询 | API查询任务进度和结果 | P0 |
|
||||
|
||||
### 3.9 呼入机器人模块
|
||||
|
||||
#### 3.9.1 功能清单
|
||||
|
||||
| 功能编号 | 功能名称 | 功能描述 | 优先级 |
|
||||
|---------|---------|---------|--------|
|
||||
| IRB-001 | 语音识别 | 集成阿里云ASR识别客户语音 | P0 |
|
||||
| IRB-002 | 意图识别 | 对接NLU平台,识别客户意图 | P0 |
|
||||
| IRB-003 | FAQ问答 | 支持配置50+常见问题及答案 | P0 |
|
||||
| IRB-004 | 语音合成应答 | 集成阿里云TTS合成语音应答 | P0 |
|
||||
| IRB-005 | 多轮对话 | 支持多轮对话收集信息 | P1 |
|
||||
| IRB-006 | 转人工-主动请求 | 客户说"转人工"触发转接 | P0 |
|
||||
| IRB-007 | 转人工-识别失败 | 连续N次识别失败自动转人工 | P0 |
|
||||
| IRB-008 | 转人工-特定意图 | 识别到投诉等意图直接转人工 | P0 |
|
||||
| IRB-009 | 转接携带信息 | 转人工时携带已收集的信息至坐席 | P1 |
|
||||
| IRB-010 | 话术配置 | 支持配置机器人话术和回复内容 | P0 |
|
||||
|
||||
### 3.10 录音管理模块
|
||||
|
||||
#### 3.10.1 功能清单
|
||||
|
||||
| 功能编号 | 功能名称 | 功能描述 | 优先级 |
|
||||
|---------|---------|---------|--------|
|
||||
| REC-001 | 全程录音 | 所有呼入呼出通话全程录音 | P0 |
|
||||
| REC-002 | 双声道录音 | 坐席和客户分轨录音(便于质检) | P1 |
|
||||
| REC-003 | 录音存储 | 录音文件存储至NAS/分布式存储 | P0 |
|
||||
| REC-004 | 长期保存 | 支持录音长期保存,定期归档 | P0 |
|
||||
| REC-005 | 录音检索 | 按通话ID、时间、号码等检索录音 | P0 |
|
||||
| REC-006 | 录音下载 | 通过API获取录音文件下载地址 | P0 |
|
||||
| REC-007 | 录音权限 | 录音访问权限控制 | P1 |
|
||||
|
||||
### 3.11 班长监控模块
|
||||
|
||||
#### 3.11.1 功能清单
|
||||
|
||||
| 功能编号 | 功能名称 | 功能描述 | 优先级 |
|
||||
|---------|---------|---------|--------|
|
||||
| SUP-001 | 坐席状态监控 | 实时查看所有坐席当前状态 | P0 |
|
||||
| SUP-002 | 实时监听 | 监听坐席与客户通话,双方不知情 | P0 |
|
||||
| SUP-003 | 强插通话 | 加入通话,三方均可听到 | P0 |
|
||||
| SUP-004 | 强拆通话 | 强制结束坐席通话 | P0 |
|
||||
| SUP-005 | 密语(可选) | 对坐席单向说话,客户听不到(二期) | P2 |
|
||||
| SUP-006 | 强制签出 | 强制将坐席签出系统 | P1 |
|
||||
| SUP-007 | 强制置忙 | 强制将坐席状态设为忙碌 | P1 |
|
||||
|
||||
### 3.12 实时监控大屏
|
||||
|
||||
#### 3.12.1 功能清单
|
||||
|
||||
| 功能编号 | 功能名称 | 功能描述 | 优先级 |
|
||||
|---------|---------|---------|--------|
|
||||
| DSP-001 | 整体概览 | 展示当前呼入量、呼出量、接通率等 | P0 |
|
||||
| DSP-002 | 坐席状态分布 | 展示各状态坐席数量(空闲、通话、小休等) | P0 |
|
||||
| DSP-003 | 技能组监控 | 各技能组排队数、等待时长、可用坐席数 | P0 |
|
||||
| DSP-004 | 实时告警 | 排队超阈值、坐席空闲过少等告警提示 | P1 |
|
||||
| DSP-005 | 趋势图表 | 当日话务量趋势图(按小时) | P1 |
|
||||
| DSP-006 | 大屏适配 | 支持大屏显示器展示 | P0 |
|
||||
|
||||
---
|
||||
|
||||
## 第四章 接口需求
|
||||
|
||||
### 4.1 接口概述
|
||||
|
||||
呼叫中心系统作为通信能力中台,通过API方式为CRM/业务系统提供呼叫能力。接口采用RESTful API + WebSocket事件推送模式。
|
||||
|
||||
### 4.2 接口清单
|
||||
|
||||
#### 4.2.1 呼入控制接口
|
||||
|
||||
| 接口编号 | 接口名称 | 请求方式 | 说明 |
|
||||
|---------|---------|---------|------|
|
||||
| API-IN-001 | 接听来电 | POST | 坐席接听当前来电 |
|
||||
| API-IN-002 | 挂断通话 | POST | 挂断当前通话 |
|
||||
| API-IN-003 | 保持通话 | POST | 将通话置于保持状态 |
|
||||
| API-IN-004 | 取回通话 | POST | 取回保持的通话 |
|
||||
| API-IN-005 | 转接通话 | POST | 转接至指定坐席/技能组/外线 |
|
||||
| API-IN-006 | 咨询通话 | POST | 发起咨询通话 |
|
||||
| API-IN-007 | 咨询转移 | POST | 咨询后转移 |
|
||||
| API-IN-008 | 三方通话 | POST | 建立三方通话 |
|
||||
|
||||
#### 4.2.2 呼出控制接口
|
||||
|
||||
| 接口编号 | 接口名称 | 请求方式 | 说明 |
|
||||
|---------|---------|---------|------|
|
||||
| API-OUT-001 | 点击外呼 | POST | 坐席发起外呼 |
|
||||
| API-OUT-002 | 取消外呼 | POST | 取消正在拨打的外呼 |
|
||||
| API-OUT-003 | 预览式外呼确认 | POST | 坐席确认拨打预览号码 |
|
||||
|
||||
#### 4.2.3 坐席状态接口
|
||||
|
||||
| 接口编号 | 接口名称 | 请求方式 | 说明 |
|
||||
|---------|---------|---------|------|
|
||||
| API-AGT-001 | 坐席签入 | POST | 坐席签入系统 |
|
||||
| API-AGT-002 | 坐席签出 | POST | 坐席签出系统 |
|
||||
| API-AGT-003 | 置忙 | POST | 坐席设置为忙碌状态 |
|
||||
| API-AGT-004 | 置闲 | POST | 坐席设置为空闲状态 |
|
||||
| API-AGT-005 | 小休 | POST | 坐席进入小休状态 |
|
||||
| API-AGT-006 | 查询坐席状态 | GET | 查询指定坐席当前状态 |
|
||||
| API-AGT-007 | 批量查询坐席状态 | GET | 批量查询坐席状态 |
|
||||
|
||||
#### 4.2.4 外呼任务接口
|
||||
|
||||
| 接口编号 | 接口名称 | 请求方式 | 说明 |
|
||||
|---------|---------|---------|------|
|
||||
| API-TASK-001 | 创建外呼任务 | POST | 创建预测式/机器人外呼任务 |
|
||||
| API-TASK-002 | 导入号码 | POST | 向任务导入外呼号码 |
|
||||
| API-TASK-003 | 启动任务 | POST | 启动外呼任务 |
|
||||
| API-TASK-004 | 暂停任务 | POST | 暂停外呼任务 |
|
||||
| API-TASK-005 | 恢复任务 | POST | 恢复暂停的任务 |
|
||||
| API-TASK-006 | 停止任务 | POST | 停止外呼任务 |
|
||||
| API-TASK-007 | 查询任务进度 | GET | 查询任务执行进度 |
|
||||
| API-TASK-008 | 查询任务结果 | GET | 查询任务拨打结果明细 |
|
||||
|
||||
#### 4.2.5 单条外呼接口(通知类)
|
||||
|
||||
| 接口编号 | 接口名称 | 请求方式 | 说明 |
|
||||
|---------|---------|---------|------|
|
||||
| API-NOTIFY-001 | 发起语音通知 | POST | 触发单条语音通知外呼 |
|
||||
| API-NOTIFY-002 | 查询通知结果 | GET | 查询通知拨打结果 |
|
||||
|
||||
#### 4.2.6 录音接口
|
||||
|
||||
| 接口编号 | 接口名称 | 请求方式 | 说明 |
|
||||
|---------|---------|---------|------|
|
||||
| API-REC-001 | 查询录音列表 | GET | 按条件查询录音记录 |
|
||||
| API-REC-002 | 获取录音下载地址 | GET | 获取录音文件下载URL |
|
||||
|
||||
#### 4.2.7 监控接口
|
||||
|
||||
| 接口编号 | 接口名称 | 请求方式 | 说明 |
|
||||
|---------|---------|---------|------|
|
||||
| API-MON-001 | 监听通话 | POST | 班长监听指定坐席通话 |
|
||||
| API-MON-002 | 强插通话 | POST | 班长强插指定坐席通话 |
|
||||
| API-MON-003 | 强拆通话 | POST | 班长强制挂断指定坐席通话 |
|
||||
| API-MON-004 | 实时统计数据 | GET | 获取实时监控统计数据 |
|
||||
| API-MON-005 | 技能组排队信息 | GET | 获取各技能组排队情况 |
|
||||
|
||||
### 4.3 事件推送(WebSocket)
|
||||
|
||||
#### 4.3.1 通话事件
|
||||
|
||||
| 事件编号 | 事件名称 | 触发时机 | 推送内容 |
|
||||
|---------|---------|---------|---------|
|
||||
| EVT-001 | 来电振铃 | 来电分配到坐席时 | 来电号码、客户ID、技能组、IVR收集信息等 |
|
||||
| EVT-002 | 通话接通 | 坐席接听后 | 通话ID、接通时间 |
|
||||
| EVT-003 | 通话挂断 | 通话结束后 | 通话ID、挂断方、通话时长 |
|
||||
| EVT-004 | 转接振铃 | 转接到新坐席振铃时 | 转接来源、来电信息 |
|
||||
| EVT-005 | 外呼振铃 | 外呼拨打中 | 外呼号码、坐席ID |
|
||||
| EVT-006 | 外呼接通 | 客户接听 | 通话ID |
|
||||
| EVT-007 | 外呼失败 | 外呼未接通 | 失败原因(无人接听/忙/关机等) |
|
||||
|
||||
#### 4.3.2 坐席状态事件
|
||||
|
||||
| 事件编号 | 事件名称 | 触发时机 | 推送内容 |
|
||||
|---------|---------|---------|---------|
|
||||
| EVT-101 | 状态变更 | 坐席状态变化时 | 坐席ID、新状态、旧状态、时间 |
|
||||
| EVT-102 | 签入成功 | 坐席签入成功 | 坐席ID、技能组 |
|
||||
| EVT-103 | 签出成功 | 坐席签出成功 | 坐席ID |
|
||||
|
||||
#### 4.3.3 话单推送
|
||||
|
||||
| 事件编号 | 事件名称 | 触发时机 | 推送内容 |
|
||||
|---------|---------|---------|---------|
|
||||
| EVT-201 | 话单推送 | 通话结束后 | 通话ID、主被叫、开始时间、结束时间、时长、录音地址、坐席ID、技能组、呼叫类型等 |
|
||||
|
||||
#### 4.3.4 机器人交互结果推送
|
||||
|
||||
| 事件编号 | 事件名称 | 触发时机 | 推送内容 |
|
||||
|---------|---------|---------|---------|
|
||||
| EVT-301 | 按键结果 | 客户按键后 | 任务ID、号码、按键值、时间 |
|
||||
| EVT-302 | 机器人通话结果 | 机器人外呼结束 | 任务ID、号码、接通状态、通话时长、按键结果 |
|
||||
|
||||
---
|
||||
|
||||
## 第五章 非功能需求
|
||||
|
||||
### 5.1 性能需求
|
||||
|
||||
| 指标项 | 要求 |
|
||||
|-------|------|
|
||||
| **并发坐席数** | 支持150坐席同时在线 |
|
||||
| **并发通话数** | 支持120路并发通话(含呼入+呼出) |
|
||||
| **日处理量** | 支持日均50,000通呼叫 |
|
||||
| **呼叫建立时延** | 来电从接入到振铃坐席 ≤ 1秒 |
|
||||
| **API响应时间** | 95%请求响应 ≤ 200ms |
|
||||
| **事件推送时延** | 事件产生到推送至CRM ≤ 500ms |
|
||||
| **ASR识别延迟** | 语音识别延迟 ≤ 500ms |
|
||||
| **系统可用性** | ≥ 99.9%(全年停机不超过8.76小时) |
|
||||
|
||||
### 5.2 高可用需求
|
||||
|
||||
| 要求项 | 说明 |
|
||||
|-------|------|
|
||||
| **主备部署** | FreeSWITCH主备双机部署,主机故障自动切换至备机 |
|
||||
| **切换时间** | 故障切换时间 ≤ 30秒 |
|
||||
| **数据同步** | 主备配置实时同步 |
|
||||
| **心跳检测** | 主备心跳检测间隔 ≤ 5秒 |
|
||||
| **数据库高可用** | 数据库采用主从复制或集群部署 |
|
||||
| **录音存储** | 录音存储采用RAID或分布式存储,防止数据丢失 |
|
||||
|
||||
### 5.3 安全需求
|
||||
|
||||
| 要求项 | 说明 |
|
||||
|-------|------|
|
||||
| **网络安全** | SIP通信支持TLS加密;API支持HTTPS |
|
||||
| **API认证** | API调用需Token认证,支持IP白名单 |
|
||||
| **权限控制** | 支持角色权限管理(管理员、班长、坐席) |
|
||||
| **录音安全** | 录音文件访问需权限验证 |
|
||||
| **操作审计** | 关键操作记录审计日志 |
|
||||
|
||||
### 5.4 兼容性需求
|
||||
|
||||
| 要求项 | 说明 |
|
||||
|-------|------|
|
||||
| **SIP话机** | 兼容主流SIP话机品牌(如:Yealink、Grandstream、Fanvil等) |
|
||||
| **SIP协议** | 符合RFC 3261标准 |
|
||||
| **浏览器** | 软电话条支持Chrome 70+、Firefox 65+、Edge 79+ |
|
||||
| **编解码** | 语音编解码支持G.711a、G.711u、G.729(可选) |
|
||||
|
||||
### 5.5 可扩展性需求
|
||||
|
||||
| 要求项 | 说明 |
|
||||
|-------|------|
|
||||
| **坐席扩展** | 架构支持水平扩展至300+坐席 |
|
||||
| **业务线扩展** | 支持新增业务线/技能组,无需改动核心架构 |
|
||||
| **线路扩展** | 支持新增SIP中继线路 |
|
||||
|
||||
---
|
||||
|
||||
## 第六章 系统架构设计建议
|
||||
|
||||
### 6.1 整体架构图
|
||||
|
||||
```
|
||||
┌──────────────────┐
|
||||
│ 运营商网络 │
|
||||
│ (SIP Trunk/400) │
|
||||
└────────┬─────────┘
|
||||
│
|
||||
┌────────▼─────────┐
|
||||
│ SBC/边界网关 │
|
||||
│ (可选,安全防护) │
|
||||
└────────┬─────────┘
|
||||
│
|
||||
┌───────────────────────────┼───────────────────────────┐
|
||||
│ │ │
|
||||
│ ┌──────────────────────▼─────────────────────┐ │
|
||||
│ │ FreeSWITCH │ │
|
||||
│ │ (主备双机部署) │ │
|
||||
│ │ ┌─────────┬─────────┬─────────┬─────────┐ │ │
|
||||
│ │ │ IVR │ ACD │ 录音模块 │ 外呼引擎│ │ │
|
||||
│ │ └─────────┴─────────┴─────────┴─────────┘ │ │
|
||||
│ └───────────────────────┬────────────────────┘ │
|
||||
│ │ │
|
||||
│ ┌───────────────────────┼───────────────────────┐ │
|
||||
│ │ │ │ │
|
||||
│ ▼ ▼ ▼ │
|
||||
│ ┌──────────┐ ┌──────────────┐ ┌────────┐│
|
||||
│ │ CTI中间件 │ │ API Gateway │ │ WS推送 ││
|
||||
│ │(ESL连接) │ │ (REST API) │ │ 服务 ││
|
||||
│ └────┬─────┘ └──────┬───────┘ └───┬────┘│
|
||||
│ │ │ │ │
|
||||
│ └────────────────────┼────────────────────┘ │
|
||||
│ │ │
|
||||
│ ┌────────────────┼────────────────┐ │
|
||||
│ │ │ │ │
|
||||
│ ▼ ▼ ▼ │
|
||||
│ ┌──────────┐ ┌──────────┐ ┌───────────┐ │
|
||||
│ │ MySQL │ │ Redis │ │ 文件存储 │ │
|
||||
│ │ (话单/配置)│ │ (缓存/状态)│ │ (录音) │ │
|
||||
│ └──────────┘ └──────────┘ └───────────┘ │
|
||||
│ │
|
||||
│ 呼叫中心系统边界 │
|
||||
└───────────────────────────┬──────────────────────────┘
|
||||
│
|
||||
┌───────────────────────┼───────────────────────┐
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌──────────┐ ┌──────────┐ ┌────────────┐
|
||||
│ CRM系统 │ │ 业务系统 │ │ 阿里云语音 │
|
||||
│(弹屏/工单) │ │(派单/订单)│ │(ASR/TTS) │
|
||||
└──────────┘ └──────────┘ └────────────┘
|
||||
```
|
||||
|
||||
### 6.2 核心组件说明
|
||||
|
||||
| 组件 | 技术选型 | 说明 |
|
||||
|------|---------|------|
|
||||
| **媒体服务器** | FreeSWITCH | 核心呼叫控制、媒体处理、IVR、录音 |
|
||||
| **CTI中间件** | 自研(基于ESL) | 封装FreeSWITCH ESL接口,提供业务逻辑 |
|
||||
| **API网关** | Nginx/Kong/自研 | RESTful API统一入口 |
|
||||
| **WebSocket服务** | Node.js/Golang | 实时事件推送 |
|
||||
| **数据库** | MySQL 8.0 | 话单、配置、坐席信息存储 |
|
||||
| **缓存** | Redis | 坐席状态、会话信息缓存 |
|
||||
| **录音存储** | NAS/MinIO/对象存储 | 录音文件长期存储 |
|
||||
| **ASR/TTS** | 阿里云智能语音 | 语音识别与合成 |
|
||||
| **NLU** | 外部指定平台 | 意图识别与对话管理 |
|
||||
|
||||
### 6.3 部署架构(主备高可用)
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ VIP(虚拟IP) │
|
||||
└──────────────────┬──────────────────┘
|
||||
│
|
||||
┌──────────────────────────┼──────────────────────────┐
|
||||
│ │ │
|
||||
▼ │ ▼
|
||||
┌─────────────────┐ │ ┌─────────────────┐
|
||||
│ FreeSWITCH │◄─────Keepalived心跳──────────────►│ FreeSWITCH │
|
||||
│ (主机) │ │ │ (备机) │
|
||||
│ CTI中间件 │ │ │ CTI中间件 │
|
||||
│ API服务 │ │ │ API服务 │
|
||||
└─────────────────┘ │ └─────────────────┘
|
||||
│ │ │
|
||||
└──────────────────────────┼──────────────────────────┘
|
||||
│
|
||||
┌────────────┴────────────┐
|
||||
│ │
|
||||
▼ ▼
|
||||
┌──────────────┐ ┌───────────────┐
|
||||
│ MySQL主从集群 │ │ Redis Sentinel│
|
||||
└──────────────┘ └───────────────┘
|
||||
│
|
||||
▼
|
||||
┌───────────────┐
|
||||
│ NAS/分布式存储 │
|
||||
│ (录音文件) │
|
||||
└───────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 第七章 硬件与软件清单
|
||||
|
||||
### 7.1 硬件清单
|
||||
|
||||
| 序号 | 设备类型 | 规格配置 | 数量 | 用途 | 参考单价(万元) | 合计(万元) |
|
||||
|-----|---------|---------|------|------|---------------|-------------|
|
||||
| 1 | 应用服务器(主) | 32核CPU/64GB内存/500GB SSD+2TB HDD | 1 | FreeSWITCH+CTI+API | 5-8 | 5-8 |
|
||||
| 2 | 应用服务器(备) | 32核CPU/64GB内存/500GB SSD+2TB HDD | 1 | FreeSWITCH备机 | 5-8 | 5-8 |
|
||||
| 3 | 数据库服务器 | 16核CPU/64GB内存/1TB SSD | 2 | MySQL主从 | 4-6 | 8-12 |
|
||||
| 4 | Redis服务器 | 8核CPU/32GB内存/500GB SSD | 3 | Redis Sentinel集群 | 2-3 | 6-9 |
|
||||
| 5 | NAS存储 | 96TB可用空间(RAID) | 1 | 录音长期存储 | 8-15 | 8-15 |
|
||||
| 6 | 网络交换机 | 千兆三层交换机 | 2 | 网络通信 | 1-2 | 2-4 |
|
||||
| 7 | 防火墙 | 企业级防火墙 | 1 | 安全防护 | 2-5 | 2-5 |
|
||||
| 8 | IP话机 | SIP话机(如Yealink T46U) | 150 | 坐席通话终端 | 0.05-0.08 | 7.5-12 |
|
||||
| 9 | 坐席耳麦 | 专业话务耳麦 | 150 | 坐席配件 | 0.02-0.05 | 3-7.5 |
|
||||
| **硬件合计** | | | | | | **47-80.5** |
|
||||
|
||||
### 7.2 软件清单
|
||||
|
||||
| 序号 | 软件/平台 | 说明 | 授权方式 | 预估费用(万元) |
|
||||
|-----|---------|------|---------|----------------|
|
||||
| 1 | FreeSWITCH | 开源软交换平台 | 开源免费 | 0 |
|
||||
| 2 | Linux操作系统 | CentOS/Rocky Linux | 开源免费 | 0 |
|
||||
| 3 | MySQL数据库 | 社区版 | 开源免费 | 0 |
|
||||
| 4 | Redis | 缓存 | 开源免费 | 0 |
|
||||
| 5 | Nginx | 反向代理/负载均衡 | 开源免费 | 0 |
|
||||
| 6 | 阿里云ASR | 语音识别 | 按量付费 | 详见运营费用 |
|
||||
| 7 | 阿里云TTS | 语音合成 | 按量付费 | 详见运营费用 |
|
||||
| 8 | NLU对话平台 | 意图识别 | 按需对接 | 视平台定价 |
|
||||
| 9 | 监控软件(Zabbix/Prometheus) | 系统监控 | 开源免费 | 0 |
|
||||
| **软件合计** | | | | **0(开源为主)** |
|
||||
|
||||
### 7.3 开发成本估算
|
||||
|
||||
| 模块 | 预估人天 | 说明 |
|
||||
|------|---------|------|
|
||||
| FreeSWITCH环境搭建与配置 | 15 | 主备部署、线路对接、编解码配置 |
|
||||
| IVR流程开发 | 20 | 多业务线IVR、语音导航 |
|
||||
| ACD分配模块 | 25 | 多种分配策略、溢出逻辑 |
|
||||
| CTI中间件开发 | 40 | ESL封装、业务逻辑 |
|
||||
| 坐席状态管理 | 15 | 状态机、持久化 |
|
||||
| API服务开发 | 30 | 全部API接口 |
|
||||
| WebSocket推送服务 | 15 | 事件推送 |
|
||||
| 软电话条组件 | 25 | 前端组件、WebRTC集成 |
|
||||
| 预测式外呼引擎 | 30 | 外呼算法、任务管理 |
|
||||
| 机器人外呼模块 | 20 | TTS集成、按键采集 |
|
||||
| 呼入机器人模块 | 25 | ASR/NLU集成、对话流程 |
|
||||
| 录音管理模块 | 10 | 录音存储、检索 |
|
||||
| 班长监控模块 | 15 | 监听、强插、强拆 |
|
||||
| 实时监控大屏 | 20 | 前端大屏、实时数据 |
|
||||
| 高可用部署 | 15 | 主备切换、Keepalived |
|
||||
| 联调测试 | 30 | 全流程测试 |
|
||||
| **合计** | **350人天** | |
|
||||
|
||||
**按人天单价1500-2500元估算,开发成本约:52.5-87.5万元**
|
||||
|
||||
---
|
||||
|
||||
## 第八章 预算汇总
|
||||
|
||||
### 8.1 一次性投入
|
||||
|
||||
| 项目 | 费用(万元) |
|
||||
|------|-------------|
|
||||
| 硬件采购 | 47-80.5 |
|
||||
| 软件(开源为主) | 0 |
|
||||
| 开发成本 | 52.5-87.5 |
|
||||
| 实施部署 | 5-10 |
|
||||
| **一次性投入合计** | **104.5-178** |
|
||||
|
||||
### 8.2 年度运营费用
|
||||
|
||||
| 项目 | 月费用(万元) | 年费用(万元) | 备注 |
|
||||
|------|--------------|---------------|------|
|
||||
| **线路月租** | | | |
|
||||
| 400号码(3个) | 0.3-1.5 | 3.6-18 | 3条业务线独立号码 |
|
||||
| SIP中继并发费(120路) | 0.6-1.2 | 7.2-14.4 | 按50-100元/路/月 |
|
||||
| **通信费** | | | |
|
||||
| 呼入通话费 | 5-9 | 60-108 | 180万分钟/月×0.03-0.05元 |
|
||||
| 呼出通话费 | 21.6-40.5 | 259-486 | 270万分钟/月×0.08-0.15元 |
|
||||
| **云服务费** | | | |
|
||||
| 阿里云ASR | 2-5 | 24-60 | 按使用量 |
|
||||
| 阿里云TTS | 1-3 | 12-36 | 按使用量 |
|
||||
| **其他** | | | |
|
||||
| 机房/带宽 | 1-2 | 12-24 | 如自有机房可降低 |
|
||||
| 系统维护 | 1-2 | 12-24 | 人员/备件 |
|
||||
| **年度运营合计** | | **390-770** | |
|
||||
|
||||
### 8.3 总预算汇总
|
||||
|
||||
| 项目 | 费用(万元) |
|
||||
|------|-------------|
|
||||
| **首年投入** | 494.5-948(一次性+首年运营) |
|
||||
| **后续每年** | 390-770(运营费用) |
|
||||
|
||||
> ⚠️ **说明:**
|
||||
> - 通信费用是大头,约占年度成本的80%以上
|
||||
> - 具体费用取决于运营商议价、实际话务量
|
||||
> - 可通过接通率优化、IVR分流等降低通信成本
|
||||
|
||||
---
|
||||
|
||||
## 第九章 项目里程碑建议
|
||||
|
||||
按照3-4个月上线周期规划:
|
||||
|
||||
| 阶段 | 周期 | 主要工作 | 交付物 |
|
||||
|------|------|---------|--------|
|
||||
| **一、需求确认与设计** | 第1-2周 | 需求评审、技术方案设计、架构设计 | 技术方案文档、接口设计文档 |
|
||||
| **二、环境搭建** | 第3-4周 | 硬件采购到货、FreeSWITCH环境部署、线路对接 | 基础环境就绪 |
|
||||
| **三、核心功能开发** | 第5-10周 | CTI中间件、API服务、坐席管理、呼入呼出基础功能 | 核心功能可用 |
|
||||
| **四、高级功能开发** | 第11-14周 | 预测式外呼、机器人模块、IVR、监控大屏 | 全功能开发完成 |
|
||||
| **五、集成联调** | 第15-16周 | CRM对接、全流程联调、高可用测试 | 联调通过 |
|
||||
| **六、测试与优化** | 第17-18周 | 功能测试、性能测试、Bug修复 | 测试报告 |
|
||||
| **七、试运行** | 第19-20周 | 小范围上线、问题收集、优化调整 | 试运行报告 |
|
||||
| **八、正式上线** | 第21周 | 全面上线、监控保障 | 系统上线 |
|
||||
|
||||
```
|
||||
第1月 第2月 第3月 第4月 第5月
|
||||
|----|----|----|----|----|----|----|----|----|----|
|
||||
[需求设计][环境搭建][====核心功能开发====][==高级功能==]
|
||||
[集成联调][测试]
|
||||
[试运行][上线]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 第十章 风险与建议
|
||||
|
||||
### 10.1 项目风险
|
||||
|
||||
| 风险项 | 风险等级 | 影响 | 应对措施 |
|
||||
|-------|---------|------|---------|
|
||||
| FreeSWITCH技术门槛高 | 高 | 开发进度延迟 | 建议团队提前学习ESL开发,或引入有经验顾问 |
|
||||
| 线路对接周期不可控 | 中 | 影响联调测试 | 提前与运营商沟通,预留缓冲时间 |
|
||||
| ASR识别效果不及预期 | 中 | 影响机器人体验 | 提前做语料测试,必要时做热词优化 |
|
||||
| 高可用切换影响业务 | 高 | 道路救援中断 | 充分测试切换机制,演练故障场景 |
|
||||
| 录音存储空间不足 | 低 | 录音丢失 | 监控存储空间,提前扩容 |
|
||||
|
||||
### 10.2 建议事项
|
||||
|
||||
1. **团队能力准备**:建议团队提前熟悉FreeSWITCH、ESL、SIP协议相关知识
|
||||
2. **分阶段上线**:可先上线基础呼入呼出功能,机器人功能迭代上线
|
||||
3. **压力测试**:上线前务必进行150坐席并发的压力测试
|
||||
4. **灰度发布**:建议先在一条业务线(如家政)试运行,再推广到道路救援
|
||||
5. **监控告警**:完善监控体系,特别是对道路救援线路的可用性监控
|
||||
|
||||
---
|
||||
|
||||
## 附录
|
||||
|
||||
### 附录A:术语表
|
||||
(见第一章1.4节)
|
||||
|
||||
### 附录B:接口详细设计
|
||||
(需在技术设计阶段细化)
|
||||
|
||||
### 附录C:IVR流程图
|
||||
(需在需求确认阶段补充)
|
||||
|
||||
### 附录D:机器人话术模板
|
||||
(需在需求确认阶段补充)
|
||||
|
||||
---
|
||||
|
||||
**文档结束**
|
||||
711
cc-center/企业呼叫中心系统项目立项书.txt
Normal file
711
cc-center/企业呼叫中心系统项目立项书.txt
Normal file
@@ -0,0 +1,711 @@
|
||||
**项目名称**:企业呼叫中心系统建设项目
|
||||
**项目编号**:CC-2024-001
|
||||
**编制日期**:2024年1月
|
||||
**编 制 人**:_________________
|
||||
**审 核 人**:_________________
|
||||
**批 准 人**:_________________
|
||||
|
||||
---
|
||||
|
||||
## 文档修订记录
|
||||
|
||||
| 版本 | 日期 | 修订内容 | 修订人 | 审核人 |
|
||||
|------|------|---------|--------|--------|
|
||||
| V1.0 | 2024-01-XX | 初稿 | | |
|
||||
|
||||
---
|
||||
|
||||
## 目录
|
||||
|
||||
1. [项目概述](#第一章-项目概述)
|
||||
2. [项目背景与必要性](#第二章-项目背景与必要性)
|
||||
3. [项目目标](#第三章-项目目标)
|
||||
4. [项目范围](#第四章-项目范围)
|
||||
5. [项目建设方案](#第五章-项目建设方案)
|
||||
6. [项目投资预算](#第六章-项目投资预算)
|
||||
7. [项目效益分析](#第七章-项目效益分析)
|
||||
8. [项目实施计划](#第八章-项目实施计划)
|
||||
9. [项目组织架构](#第九章-项目组织架构)
|
||||
10. [风险分析与应对](#第十章-风险分析与应对)
|
||||
11. [结论与建议](#第十一章-结论与建议)
|
||||
|
||||
---
|
||||
|
||||
## 第一章 项目概述
|
||||
|
||||
### 1.1 项目名称
|
||||
|
||||
企业呼叫中心系统建设项目
|
||||
|
||||
### 1.2 项目建设单位
|
||||
|
||||
**单位名称**:_________________(企业名称)
|
||||
**负 责 人**:_________________
|
||||
**联系方式**:_________________
|
||||
|
||||
### 1.3 项目概要
|
||||
|
||||
本项目旨在建设一套集**呼入呼出、智能IVR、机器人客服、预测式外呼**于一体的企业级呼叫中心系统,支撑公司道路救援、家政服务、代驾服务三大业务板块的客户服务与营销运营工作。
|
||||
|
||||
| 项目要素 | 内容描述 |
|
||||
|---------|---------|
|
||||
| **服务对象** | 个人消费者(ToC) |
|
||||
| **业务范围** | 道路救援、家政服务、代驾服务 |
|
||||
| **坐席规模** | 150坐席 |
|
||||
| **日话务量** | 50,000通/日 |
|
||||
| **服务时间** | 7×24小时 |
|
||||
| **建设周期** | 3-4个月 |
|
||||
| **建设方式** | 自主研发(基于FreeSWITCH开源平台) |
|
||||
| **部署方式** | 私有化部署(主备高可用架构) |
|
||||
|
||||
### 1.4 项目总投资
|
||||
|
||||
| 投资类别 | 金额(万元) |
|
||||
|---------|-------------|
|
||||
| 一次性建设投资 | 104.5-178 |
|
||||
| 首年运营费用 | 390-770 |
|
||||
| **首年总投入** | **494.5-948** |
|
||||
|
||||
---
|
||||
|
||||
## 第二章 项目背景与必要性
|
||||
|
||||
### 2.1 企业现状
|
||||
|
||||
本企业主营**道路救援、家政服务、代驾服务**三大业务,面向个人消费者提供上门服务。随着业务规模的持续扩大,现有的客户服务模式已无法满足业务发展需求:
|
||||
|
||||
**现状问题:**
|
||||
|
||||
| 问题领域 | 具体问题 | 影响 |
|
||||
|---------|---------|------|
|
||||
| **客服能力** | 无统一呼叫平台,多部门分散接听 | 客户体验差,管理困难 |
|
||||
| **响应效率** | 道路救援等紧急需求响应慢 | 客户流失,品牌受损 |
|
||||
| **服务时间** | 夜间/节假日服务能力不足 | 错失订单,客户投诉 |
|
||||
| **外呼效率** | 人工逐一拨打,效率低下 | 人力成本高,触达率低 |
|
||||
| **数据管理** | 通话无录音,无法追溯 | 纠纷处理困难,质量无法管控 |
|
||||
| **系统集成** | 与CRM系统无法打通 | 信息孤岛,坐席重复操作 |
|
||||
|
||||
### 2.2 建设必要性
|
||||
|
||||
#### 2.2.1 业务发展的迫切需要
|
||||
|
||||
```
|
||||
业务增长趋势
|
||||
话务量
|
||||
↑
|
||||
60000│ ╭──── 预测增长
|
||||
│ ╭────╯
|
||||
50000│ ╭────╯ ←── 当前日均50000通
|
||||
│ ╭────╯
|
||||
40000│ ╭────╯
|
||||
│ ╭────╯
|
||||
30000│╭────╯
|
||||
│
|
||||
└────────────────────────────────────→ 时间
|
||||
2022 2023 2024 2025
|
||||
```
|
||||
|
||||
随着业务规模扩大,日话务量已达**50,000通**,预计未来2年将持续增长。迫切需要建设专业呼叫中心系统支撑业务发展。
|
||||
|
||||
#### 2.2.2 客户体验提升的需要
|
||||
|
||||
| 客户痛点 | 系统解决方案 |
|
||||
|---------|-------------|
|
||||
| 打电话难以接通 | 150坐席+智能排队+溢出机制 |
|
||||
| 等待时间长 | IVR自助分流+机器人预处理 |
|
||||
| 反复描述问题 | CRM弹屏,坐席即时了解客户信息 |
|
||||
| 投诉处理无反馈 | 录音追溯+工单闭环 |
|
||||
|
||||
#### 2.2.3 运营效率提升的需要
|
||||
|
||||
| 运营痛点 | 系统解决方案 |
|
||||
|---------|-------------|
|
||||
| 外呼效率低 | 预测式外呼,坐席利用率提升50%+ |
|
||||
| 通知类工作繁重 | 机器人自动批量通知 |
|
||||
| 回访覆盖率低 | 机器人自动回访+满意度调查 |
|
||||
| 管理缺乏抓手 | 实时监控大屏+班长监控 |
|
||||
|
||||
#### 2.2.4 合规与风控的需要
|
||||
|
||||
- 道路救援涉及紧急服务,需确保系统**高可用**
|
||||
- 服务过程需**全程录音**,便于纠纷处理
|
||||
- 需与现有CRM系统**无缝集成**,确保数据安全
|
||||
|
||||
### 2.3 建设可行性
|
||||
|
||||
#### 2.3.1 技术可行性
|
||||
|
||||
| 技术领域 | 可行性分析 |
|
||||
|---------|-----------|
|
||||
| **呼叫平台** | FreeSWITCH开源成熟,已广泛应用于企业呼叫中心 |
|
||||
| **智能语音** | 阿里云ASR/TTS技术成熟,识别准确率>95% |
|
||||
| **系统集成** | 标准API/WebSocket接口,与现有CRM可顺利对接 |
|
||||
| **高可用** | 主备架构+Keepalived方案成熟可靠 |
|
||||
|
||||
#### 2.3.2 团队可行性
|
||||
|
||||
| 条件 | 评估 |
|
||||
|------|------|
|
||||
| 自有技术团队 | ✅ 具备自主开发能力 |
|
||||
| FreeSWITCH经验 | ⚠️ 需提前培训或引入顾问支持 |
|
||||
| 项目管理能力 | ✅ 具备中大型项目实施经验 |
|
||||
|
||||
#### 2.3.3 经济可行性
|
||||
|
||||
- 自主研发相比采购商业产品**节省授权费用**
|
||||
- 私有化部署**长期成本可控**
|
||||
- 项目投资回报分析详见第七章
|
||||
|
||||
---
|
||||
|
||||
## 第三章 项目目标
|
||||
|
||||
### 3.1 总体目标
|
||||
|
||||
建设一套**安全、稳定、高效、智能**的企业级呼叫中心系统,实现客户服务统一接入、智能化分流、高效外呼,全面提升客户服务体验与运营效率。
|
||||
|
||||
### 3.2 具体目标
|
||||
|
||||
#### 3.2.1 能力目标
|
||||
|
||||
| 目标项 | 指标要求 |
|
||||
|-------|---------|
|
||||
| 坐席并发能力 | 支持150坐席同时在线 |
|
||||
| 通话并发能力 | 支持120路并发通话 |
|
||||
| 日处理能力 | 支持50,000通/日 |
|
||||
| 系统可用性 | ≥99.9%(全年停机<8.76小时) |
|
||||
| 故障切换时间 | ≤30秒 |
|
||||
|
||||
#### 3.2.2 效率目标
|
||||
|
||||
| 目标项 | 当前值 | 目标值 | 提升幅度 |
|
||||
|-------|-------|-------|---------|
|
||||
| 人工坐席利用率 | 约40% | ≥70% | +75% |
|
||||
| 外呼接通后转接时间 | N/A(人工拨号) | ≤3秒 | - |
|
||||
| 批量通知人工耗时 | 100%人工 | 0%(全自动) | 释放人力 |
|
||||
| 客户等待时长 | 无统计 | 平均<30秒 | - |
|
||||
|
||||
#### 3.2.3 体验目标
|
||||
|
||||
| 目标项 | 指标要求 |
|
||||
|-------|---------|
|
||||
| 首次呼叫解决率 | ≥80% |
|
||||
| IVR自助分流率 | ≥30% |
|
||||
| 客户满意度 | ≥90% |
|
||||
|
||||
### 3.3 建设原则
|
||||
|
||||
| 原则 | 说明 |
|
||||
|------|------|
|
||||
| **统一规划** | 三大业务线统一平台,避免重复建设 |
|
||||
| **安全可靠** | 主备高可用,确保道路救援等紧急服务不中断 |
|
||||
| **开放集成** | 标准API接口,与CRM/业务系统无缝对接 |
|
||||
| **智能高效** | 引入AI能力,提升服务效率与体验 |
|
||||
| **弹性扩展** | 架构支持未来扩展至300+坐席 |
|
||||
| **自主可控** | 自主研发,核心技术自主掌握 |
|
||||
|
||||
---
|
||||
|
||||
## 第四章 项目范围
|
||||
|
||||
### 4.1 业务范围
|
||||
|
||||
| 业务线 | 呼入场景 | 呼出场景 |
|
||||
|-------|---------|---------|
|
||||
| **道路救援** | 叫救援、咨询、投诉 | 回访、满意度调查、到达通知 |
|
||||
| **家政服务** | 预约服务、咨询、投诉 | 回访、营销推广、上门提醒 |
|
||||
| **代驾服务** | 叫代驾、咨询、投诉 | 回访、营销推广、到达通知 |
|
||||
|
||||
### 4.2 功能范围
|
||||
|
||||
#### 4.2.1 本期建设范围(一期)
|
||||
|
||||
| 模块 | 功能项 | 优先级 |
|
||||
|------|-------|--------|
|
||||
| **基础通话** | 呼入接听、呼出拨打、转接、保持、三方通话 | P0 |
|
||||
| **智能IVR** | 语音导航、按键导航、语音识别、多业务分流 | P0 |
|
||||
| **ACD分配** | 技能组管理、多种分配策略、排队溢出 | P0 |
|
||||
| **坐席管理** | 签入签出、状态管理、软电话条 | P0 |
|
||||
| **预测式外呼** | 批量外呼任务、自动拨打、接通转坐席 | P0 |
|
||||
| **机器人外呼** | 批量通知、TTS播报、按键采集 | P0 |
|
||||
| **呼入机器人** | FAQ问答、意图识别、转人工 | P0 |
|
||||
| **录音管理** | 全程录音、录音存储、录音检索下载 | P0 |
|
||||
| **班长监控** | 监听、强插、强拆 | P0 |
|
||||
| **监控大屏** | 实时数据展示、坐席状态、排队监控 | P0 |
|
||||
| **系统集成** | CRM弹屏、API接口、事件推送 | P0 |
|
||||
| **高可用** | 主备部署、故障切换 | P0 |
|
||||
|
||||
#### 4.2.2 二期规划范围(本期不含)
|
||||
|
||||
| 模块 | 功能项 | 说明 |
|
||||
|------|-------|------|
|
||||
| **统计报表** | 话务报表、坐席绩效、外呼分析 | 二期建设 |
|
||||
| **智能质检** | 语音转写、关键词检测、情绪分析 | 二期建设 |
|
||||
| **密语功能** | 班长对坐席单向指导 | 二期建设 |
|
||||
| **短信功能** | 不涉及,由第三方平台提供 | 不纳入 |
|
||||
|
||||
### 4.3 集成范围
|
||||
|
||||
| 集成系统 | 集成方式 | 集成内容 |
|
||||
|---------|---------|---------|
|
||||
| **CRM系统** | API双向对接 | 来电弹屏、客户资料、工单创建 |
|
||||
| **业务系统** | API对接 | 外呼任务推送、通知触发、结果回传 |
|
||||
| **阿里云语音** | API调用 | ASR语音识别、TTS语音合成 |
|
||||
| **NLU平台** | API对接 | 意图识别、对话管理 |
|
||||
|
||||
---
|
||||
|
||||
## 第五章 项目建设方案
|
||||
|
||||
### 5.1 总体架构
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────┐
|
||||
│ 用户层 │
|
||||
│ 道路救援客户 家政服务客户 代驾服务客户 │
|
||||
│ │ │ │ │
|
||||
│ ▼ ▼ ▼ │
|
||||
│ 400-XXX-XXX1 400-XXX-XXX2 固话/400 │
|
||||
└─────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────┐
|
||||
│ 接入层 │
|
||||
│ 运营商SIP中继线路 │
|
||||
└─────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────┐
|
||||
│ 呼叫控制层 │
|
||||
│ ┌──────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ FreeSWITCH (主备高可用) │ │
|
||||
│ │ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │ │
|
||||
│ │ │ 呼入控制│ │ 呼出控制│ │智能IVR │ │ ACD分配│ │ 录音模块│ │ │
|
||||
│ │ └────────┘ └────────┘ └────────┘ └────────┘ └────────┘ │ │
|
||||
│ └──────────────────────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────┐
|
||||
│ 业务服务层 │
|
||||
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
||||
│ │CTI中间件 │ │API Gateway│ │ WS推送 │ │ 外呼引擎 │ │ 机器人引擎│ │
|
||||
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────┐
|
||||
│ 数据层 │
|
||||
│ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
|
||||
│ │ MySQL │ │ Redis │ │ NAS存储 │ │
|
||||
│ │ (主从集群) │ │(Sentinel)│ │ (录音) │ │
|
||||
│ └──────────┘ └──────────┘ └──────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────┐
|
||||
│ 集成层 │
|
||||
│ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
|
||||
│ │ CRM系统 │ │ 业务系统 │ │ 阿里云ASR/TTS│ │
|
||||
│ └──────────┘ └──────────┘ └──────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────┐
|
||||
│ 终端层 │
|
||||
│ ┌──────────────┐ ┌──────────────┐ │
|
||||
│ │ IP话机 │ │ 软电话条 │ │
|
||||
│ │ (150台) │ │ (嵌入CRM) │ │
|
||||
│ └──────────────┘ └──────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 5.2 部署架构
|
||||
|
||||
采用**私有化部署+主备高可用**架构:
|
||||
|
||||
```
|
||||
┌─────────────────┐
|
||||
│ 虚拟IP(VIP) │
|
||||
│ SIP线路接入 │
|
||||
└────────┬────────┘
|
||||
│
|
||||
┌─────────────────────┴─────────────────────┐
|
||||
│ │
|
||||
▼ ▼
|
||||
┌─────────────────┐ ┌─────────────────┐
|
||||
│ 主服务器 │◄──── Keepalived ────►│ 备服务器 │
|
||||
├─────────────────┤ 心跳检测 ├─────────────────┤
|
||||
│ FreeSWITCH │ │ FreeSWITCH │
|
||||
│ CTI中间件 │ │ CTI中间件 │
|
||||
│ API服务 │ │ API服务 │
|
||||
│ WebSocket服务 │ │ WebSocket服务 │
|
||||
└────────┬────────┘ └────────┬────────┘
|
||||
│ │
|
||||
└─────────────────────┬─────────────────────┘
|
||||
│
|
||||
┌─────────────────────────┼─────────────────────────┐
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||
│ MySQL主从集群 │ │ Redis Sentinel │ │ NAS存储 │
|
||||
│ (2节点) │ │ (3节点) │ │ (RAID冗余) │
|
||||
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||||
```
|
||||
|
||||
### 5.3 技术选型
|
||||
|
||||
| 组件类型 | 技术选型 | 选型理由 |
|
||||
|---------|---------|---------|
|
||||
| **媒体服务器** | FreeSWITCH 1.10+ | 开源成熟、性能优异、功能完善 |
|
||||
| **操作系统** | Rocky Linux 8/CentOS 8 | 稳定可靠、长期支持 |
|
||||
| **开发语言** | Java/Golang | CTI中间件、API服务 |
|
||||
| **前端框架** | Vue.js 3.x | 软电话条、监控大屏 |
|
||||
| **数据库** | MySQL 8.0 | 成熟稳定、主从复制 |
|
||||
| **缓存** | Redis 6.x | 高性能、Sentinel高可用 |
|
||||
| **消息队列** | RabbitMQ/Kafka | 事件异步处理(可选) |
|
||||
| **负载均衡** | Nginx | 反向代理、SSL卸载 |
|
||||
| **高可用** | Keepalived | VIP漂移、故障切换 |
|
||||
| **监控** | Prometheus + Grafana | 系统监控、告警 |
|
||||
| **ASR/TTS** | 阿里云智能语音 | 识别准确率高、服务稳定 |
|
||||
|
||||
### 5.4 网络规划
|
||||
|
||||
| 网络区域 | 网段规划 | 用途 |
|
||||
|---------|---------|------|
|
||||
| **业务网段** | 10.10.1.0/24 | 呼叫中心服务器 |
|
||||
| **数据网段** | 10.10.2.0/24 | 数据库、存储 |
|
||||
| **坐席网段** | 10.10.10.0/23 | 坐席终端、IP话机 |
|
||||
| **管理网段** | 10.10.100.0/24 | 运维管理 |
|
||||
| **SIP信令** | 独立VLAN | SIP中继对接 |
|
||||
|
||||
### 5.5 号码规划
|
||||
|
||||
| 业务线 | 号码类型 | 号码 | 用途 |
|
||||
|-------|---------|------|------|
|
||||
| 道路救援 | 400号码 | 400-XXX-XXX1 | 客户呼入 |
|
||||
| 家政服务 | 400号码 | 400-XXX-XXX2 | 客户呼入 |
|
||||
| 代驾服务 | 400/固话 | 400-XXX-XXX3 | 客户呼入 |
|
||||
| 外呼显号 | 固话 | 0XX-XXXXXXXX | 外呼主叫显示 |
|
||||
|
||||
---
|
||||
|
||||
## 第六章 项目投资预算
|
||||
|
||||
### 6.1 投资概算汇总
|
||||
|
||||
| 投资类别 | 金额(万元) | 占比 |
|
||||
|---------|-------------|------|
|
||||
| 硬件设备 | 47-80.5 | 33%-45% |
|
||||
| 软件及开发 | 52.5-87.5 | 37%-49% |
|
||||
| 实施部署 | 5-10 | 4%-6% |
|
||||
| **一次性投资合计** | **104.5-178** | **100%** |
|
||||
|
||||
### 6.2 硬件投资明细
|
||||
|
||||
| 序号 | 设备名称 | 规格 | 数量 | 单价(万) | 合计(万) |
|
||||
|-----|---------|------|------|---------|---------|
|
||||
| 1 | 应用服务器 | 32核/64GB/500GB SSD+2TB | 2 | 5-8 | 10-16 |
|
||||
| 2 | 数据库服务器 | 16核/64GB/1TB SSD | 2 | 4-6 | 8-12 |
|
||||
| 3 | Redis服务器 | 8核/32GB/500GB SSD | 3 | 2-3 | 6-9 |
|
||||
| 4 | NAS存储 | 96TB可用(RAID) | 1 | 8-15 | 8-15 |
|
||||
| 5 | 网络交换机 | 千兆三层 | 2 | 1-2 | 2-4 |
|
||||
| 6 | 防火墙 | 企业级 | 1 | 2-5 | 2-5 |
|
||||
| 7 | IP话机 | SIP话机 | 150 | 0.05-0.08 | 7.5-12 |
|
||||
| 8 | 坐席耳麦 | 专业话务耳麦 | 150 | 0.02-0.05 | 3-7.5 |
|
||||
| | **硬件合计** | | | | **47-80.5** |
|
||||
|
||||
### 6.3 软件及开发投资明细
|
||||
|
||||
| 序号 | 项目 | 说明 | 费用(万) |
|
||||
|-----|------|------|---------|
|
||||
| 1 | FreeSWITCH | 开源免费 | 0 |
|
||||
| 2 | 操作系统 | Rocky Linux开源 | 0 |
|
||||
| 3 | MySQL/Redis | 社区版开源 | 0 |
|
||||
| 4 | 系统开发 | 350人天×1500-2500元 | 52.5-87.5 |
|
||||
| | **软件及开发合计** | | **52.5-87.5** |
|
||||
|
||||
### 6.4 实施部署投资
|
||||
|
||||
| 序号 | 项目 | 费用(万) |
|
||||
|-----|------|---------|
|
||||
| 1 | 硬件安装调试 | 1-2 |
|
||||
| 2 | 网络部署配置 | 1-2 |
|
||||
| 3 | 系统联调测试 | 2-4 |
|
||||
| 4 | 培训及上线支持 | 1-2 |
|
||||
| | **实施部署合计** | **5-10** |
|
||||
|
||||
### 6.5 年度运营费用
|
||||
|
||||
| 项目 | 月费用(万) | 年费用(万) |
|
||||
|------|-----------|-----------|
|
||||
| **线路费用** | | |
|
||||
| 400号码月租(3个) | 0.3-1.5 | 3.6-18 |
|
||||
| SIP并发费(120路) | 0.6-1.2 | 7.2-14.4 |
|
||||
| **通信费用** | | |
|
||||
| 呼入通话费 | 5-9 | 60-108 |
|
||||
| 呼出通话费 | 21.6-40.5 | 259-486 |
|
||||
| **云服务费用** | | |
|
||||
| 阿里云ASR | 2-5 | 24-60 |
|
||||
| 阿里云TTS | 1-3 | 12-36 |
|
||||
| **运维费用** | | |
|
||||
| 机房/带宽 | 1-2 | 12-24 |
|
||||
| 系统维护 | 1-2 | 12-24 |
|
||||
| **年度运营合计** | | **390-770** |
|
||||
|
||||
### 6.6 投资估算汇总表
|
||||
|
||||
| 项目 | 首年(万) | 第二年(万) | 第三年(万) |
|
||||
|------|---------|-----------|-----------|
|
||||
| 一次性建设投入 | 104.5-178 | - | - |
|
||||
| 年度运营费用 | 390-770 | 390-770 | 390-770 |
|
||||
| **年度总计** | **494.5-948** | **390-770** | **390-770** |
|
||||
| **三年累计** | | | **1274.5-2488** |
|
||||
|
||||
---
|
||||
|
||||
## 第七章 项目效益分析
|
||||
|
||||
### 7.1 经济效益
|
||||
|
||||
#### 7.1.1 人力成本节约
|
||||
|
||||
| 节约项 | 计算依据 | 年节约(万) |
|
||||
|-------|---------|-----------|
|
||||
| **外呼效率提升** | 坐席利用率从40%→70%,相当于节约45个坐席人力 | 45×8=360 |
|
||||
| **批量通知自动化** | 原需5人专职,现全自动 | 5×8=40 |
|
||||
| **回访自动化** | 原需10人,现机器人承担80% | 8×8=64 |
|
||||
| **IVR自助分流** | 30%简单咨询自助解决,节约人力 | 15×8=120 |
|
||||
| **年人力成本节约** | | **约584万** |
|
||||
|
||||
> 注:按坐席人均年成本8万元估算
|
||||
|
||||
#### 7.1.2 业务增收
|
||||
|
||||
| 增收项 | 计算依据 | 年增收(万) |
|
||||
|-------|---------|-----------|
|
||||
| **接通率提升** | 减少客户流失,预计增收5% | 约200 |
|
||||
| **外呼营销转化** | 新增营销触达能力 | 约150 |
|
||||
| **年业务增收** | | **约350万** |
|
||||
|
||||
#### 7.1.3 投资回报分析
|
||||
|
||||
| 指标 | 数值 |
|
||||
|------|------|
|
||||
| 一次性投入 | 141万(取中值) |
|
||||
| 年运营成本 | 580万(取中值) |
|
||||
| 年成本节约 | 584万 |
|
||||
| 年业务增收 | 350万 |
|
||||
| **年净收益** | **354万** |
|
||||
| **投资回收期** | **约4.8个月** |
|
||||
|
||||
### 7.2 管理效益
|
||||
|
||||
| 效益项 | 说明 |
|
||||
|-------|------|
|
||||
| **服务可追溯** | 全程录音,服务质量可追溯,纠纷可举证 |
|
||||
| **管理可视化** | 实时监控大屏,管理者实时掌握运营状态 |
|
||||
| **决策有依据** | 话务数据积累,为排班、扩容提供数据支撑 |
|
||||
| **流程标准化** | IVR+机器人固化服务流程,服务质量稳定 |
|
||||
|
||||
### 7.3 客户效益
|
||||
|
||||
| 效益项 | 说明 |
|
||||
|-------|------|
|
||||
| **接通率提升** | 专业排队机制,减少占线挂断 |
|
||||
| **等待时间缩短** | IVR分流+智能分配,平均等待<30秒 |
|
||||
| **服务体验提升** | 来电自动识别,坐席了解客户历史,避免重复描述 |
|
||||
| **服务时间扩展** | 7×24小时服务,紧急需求随时响应 |
|
||||
|
||||
---
|
||||
|
||||
## 第八章 项目实施计划
|
||||
|
||||
### 8.1 项目周期
|
||||
|
||||
**总工期:4个月(17周)**
|
||||
|
||||
### 8.2 阶段划分
|
||||
|
||||
```
|
||||
1月 2月 3月 4月 5月
|
||||
|----|----|----|----|----|----|----|----|----|----|----|----|----|----|----|----|
|
||||
W1 W2 W3 W4 W5 W6 W7 W8 W9 W10 W11 W12 W13 W14 W15 W16 W17 W18
|
||||
|
||||
[需求设计 ]
|
||||
[环境搭建 ]
|
||||
[========= 核心功能开发 =========]
|
||||
[=== 高级功能开发 ===]
|
||||
[集成联调]
|
||||
[测试优化]
|
||||
[试运行][上线]
|
||||
```
|
||||
|
||||
### 8.3 里程碑计划
|
||||
|
||||
| 里程碑 | 计划时间 | 交付物 | 验收标准 |
|
||||
|-------|---------|-------|---------|
|
||||
| **M1: 需求确认** | 第2周末 | 需求规格说明书、技术方案 | 评审通过 |
|
||||
| **M2: 环境就绪** | 第4周末 | 硬件到位、基础环境部署完成 | FreeSWITCH可接打电话 |
|
||||
| **M3: 核心功能完成** | 第10周末 | 呼入呼出、ACD、坐席管理、API | 核心流程跑通 |
|
||||
| **M4: 全功能完成** | 第14周末 | 外呼、机器人、监控大屏 | 全部功能可用 |
|
||||
| **M5: 联调测试完成** | 第16周末 | CRM集成完成、测试报告 | 全流程联调通过 |
|
||||
| **M6: 试运行完成** | 第18周末 | 试运行报告 | 问题收敛,达到上线标准 |
|
||||
| **M7: 正式上线** | 第19周 | 上线报告 | 系统平稳运行 |
|
||||
|
||||
### 8.4 详细进度计划
|
||||
|
||||
| 阶段 | 时间 | 主要任务 | 交付物 |
|
||||
|------|------|---------|--------|
|
||||
| **一、需求设计** | W1-W2 | 需求评审、架构设计、接口设计、详细设计 | 技术方案、接口文档、设计文档 |
|
||||
| **二、环境搭建** | W3-W4 | 硬件采购到货、网络部署、FreeSWITCH安装、线路对接 | 基础环境就绪 |
|
||||
| **三、核心开发** | W5-W10 | CTI中间件、API服务、坐席管理、ACD、录音、软电话条 | 核心功能可用 |
|
||||
| **四、高级开发** | W11-W14 | 预测式外呼、机器人模块、IVR语音识别、监控大屏 | 高级功能可用 |
|
||||
| **五、集成联调** | W15-W16 | CRM对接、全流程联调、高可用测试 | 联调通过 |
|
||||
| **六、测试优化** | W16-W17 | 功能测试、性能测试、安全测试、Bug修复 | 测试报告 |
|
||||
| **七、试运行** | W18 | 小范围上线、问题收集 | 试运行报告 |
|
||||
| **八、正式上线** | W19 | 全面上线、监控保障 | 上线完成 |
|
||||
|
||||
---
|
||||
|
||||
## 第九章 项目组织架构
|
||||
|
||||
### 9.1 组织架构图
|
||||
|
||||
```
|
||||
┌─────────────────┐
|
||||
│ 项目发起人 │
|
||||
│ (公司高层) │
|
||||
└────────┬────────┘
|
||||
│
|
||||
┌────────▼────────┐
|
||||
│ 项目经理 │
|
||||
│ (总体负责) │
|
||||
└────────┬────────┘
|
||||
│
|
||||
┌────────────────────────┼────────────────────────┐
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
|
||||
│ 技术开发组 │ │ 业务需求组 │ │ 测试实施组 │
|
||||
├───────────────┤ ├───────────────┤ ├───────────────┤
|
||||
│ · 架构师 │ │ · 业务分析师 │ │ · 测试工程师 │
|
||||
│ · 后端开发 │ │ · 产品经理 │ │ · 实施工程师 │
|
||||
│ · 前端开发 │ │ · 业务对接人 │ │ · 运维工程师 │
|
||||
│ · FreeSWITCH │ │ │ │ │
|
||||
└───────────────┘ └───────────────┘ └───────────────┘
|
||||
```
|
||||
|
||||
### 9.2 角色职责
|
||||
|
||||
| 角色 | 人数 | 职责 |
|
||||
|------|------|------|
|
||||
| **项目发起人** | 1 | 项目决策、资源协调、重大问题决策 |
|
||||
| **项目经理** | 1 | 项目整体管理、进度控制、风险管理、对外沟通 |
|
||||
| **架构师** | 1 | 技术架构设计、技术选型、技术难点攻关 |
|
||||
| **后端开发** | 3-4 | CTI中间件、API服务、外呼引擎、机器人模块开发 |
|
||||
| **前端开发** | 1-2 | 软电话条、监控大屏开发 |
|
||||
| **FreeSWITCH工程师** | 1-2 | FreeSWITCH配置、IVR开发、ESL对接 |
|
||||
| **业务分析师** | 1 | 需求分析、业务流程梳理 |
|
||||
| **测试工程师** | 1-2 | 测试用例、功能测试、性能测试 |
|
||||
| **实施工程师** | 1 | 环境部署、系统上线 |
|
||||
| **运维工程师** | 1 | 系统运维、监控告警 |
|
||||
| **合计** | **12-16人** | |
|
||||
|
||||
### 9.3 沟通机制
|
||||
|
||||
| 会议类型 | 频率 | 参与人 | 内容 |
|
||||
|---------|------|-------|------|
|
||||
| **项目周会** | 每周一次 | 全体成员 | 进度汇报、问题协调、下周计划 |
|
||||
| **每日站会** | 每日 | 开发+测试 | 当日任务、阻塞问题 |
|
||||
| **技术评审会** | 按需 | 技术组 | 技术方案评审、代码评审 |
|
||||
| **里程碑汇报** | 每里程碑 | 项目经理+发起人 | 阶段成果、风险汇报 |
|
||||
| **上线评审会** | 上线前 | 全体+业务方 | 上线准备度检查 |
|
||||
|
||||
---
|
||||
|
||||
## 第十章 风险分析与应对
|
||||
|
||||
### 10.1 风险清单
|
||||
|
||||
| 风险编号 | 风险描述 | 可能性 | 影响程度 | 风险等级 |
|
||||
|---------|---------|--------|---------|---------|
|
||||
| R01 | FreeSWITCH技术门槛高,团队经验不足 | 高 | 高 | **高** |
|
||||
| R02 | 运营商线路对接周期长 | 中 | 高 | **高** |
|
||||
| R03 | CRM系统对接复杂度超预期 | 中 | 中 | **中** |
|
||||
| R04 | ASR识别效果不及预期 | 中 | 中 | **中** |
|
||||
| R05 | 硬件采购/到货延迟 | 低 | 高 | **中** |
|
||||
| R06 | 并发性能不达标 | 低 | 高 | **中** |
|
||||
| R07 | 关键人员离职 | 低 | 高 | **中** |
|
||||
| R08 | 需求变更频繁 | 中 | 中 | **中** |
|
||||
|
||||
### 10.2 应对措施
|
||||
|
||||
| 风险编号 | 应对措施 | 责任人 |
|
||||
|---------|---------|--------|
|
||||
| **R01** | 1. 项目前期组织FreeSWITCH专项培训<br>2. 考虑引入外部FreeSWITCH顾问支持<br>3. 预留20%时间缓冲 | 项目经理 |
|
||||
| **R02** | 1. 提前2个月启动线路申请<br>2. 准备备选运营商<br>3. 先用测试线路开发,并行对接正式线路 | 项目经理 |
|
||||
| **R03** | 1. 需求阶段明确接口规范<br>2. 预留接口联调时间<br>3. CRM团队提前介入 | 架构师 |
|
||||
| **R04** | 1. 提前进行ASR效果测试<br>2. 准备热词优化方案<br>3. 设计降级策略(按键兜底) | 技术组 |
|
||||
| **R05** | 1. 提前下单采购<br>2. 准备备选供应商<br>3. 先用云主机开发 | 项目经理 |
|
||||
| **R06** | 1. 上线前进行压力测试<br>2. 准备扩容方案<br>3. 架构支持水平扩展 | 架构师 |
|
||||
| **R07** | 1. 知识文档化<br>2. 关键模块双人备份<br>3. 提前储备人员 | 项目经理 |
|
||||
| **R08** | 1. 需求基线管理<br>2. 变更走评审流程<br>3. 评估变更影响后决策 | 产品经理 |
|
||||
|
||||
### 10.3 风险监控
|
||||
|
||||
| 风险等级 | 监控频率 | 汇报层级 |
|
||||
|---------|---------|---------|
|
||||
| **高** | 每周跟踪 | 项目发起人 |
|
||||
| **中** | 双周跟踪 | 项目经理 |
|
||||
| **低** | 月度跟踪 | 项目组 |
|
||||
|
||||
---
|
||||
|
||||
## 第十一章 结论与建议
|
||||
|
||||
### 11.1 结论
|
||||
|
||||
经过全面分析,本项目具备以下条件:
|
||||
|
||||
| 维度 | 评估结论 |
|
||||
|------|---------|
|
||||
| **必要性** | ✅ 业务发展迫切需要,现有模式已无法支撑 |
|
||||
| **可行性** | ✅ 技术方案成熟,团队具备基本能力 |
|
||||
| **经济性** | ✅ 投资回报期短(约4.8个月),效益显著 |
|
||||
| **风险性** | ⚠️ 存在技术风险,但可通过措施控制 |
|
||||
|
||||
**综合结论:项目具备立项条件,建议批准立项。**
|
||||
|
||||
### 11.2 建议
|
||||
|
||||
1. **尽快启动**:业务增长迅速,建议尽快批准立项,启动实施
|
||||
2. **技术准备**:建议在项目正式启动前,组织FreeSWITCH技术培训
|
||||
3. **线路先行**:建议立即启动运营商线路申请,避免成为关键路径
|
||||
4. **分步上线**:建议优先上线家政业务,验证后再推广至道路救援
|
||||
5. **预留缓冲**:建议预留10%-20%预算和时间缓冲,应对不确定性
|
||||
6. **运维同步**:建议运维人员全程参与,确保上线后平稳运行
|
||||
|
||||
### 11.3 审批意见
|
||||
|
||||
| 审批环节 | 审批人 | 日期 | 意见 |
|
||||
|---------|-------|------|------|
|
||||
| **技术评审** | | | |
|
||||
| **财务评审** | | | |
|
||||
| **业务评审** | | | |
|
||||
| **最终审批** | | | |
|
||||
|
||||
---
|
||||
|
||||
## 附件清单
|
||||
|
||||
| 附件编号 | 附件名称 | 说明 |
|
||||
|---------|---------|------|
|
||||
| 附件1 | 《呼叫中心系统需求规格说明书》 | 详细需求文档 |
|
||||
| 附件2 | 硬件选型参考清单 | 硬件详细配置及备选品牌 |
|
||||
| 附件3 | 运营商线路资费对比 | 各运营商资费方案对比 |
|
||||
| 附件4 | FreeSWITCH技术评估报告 | 技术可行性详细分析(如有) |
|
||||
|
||||
---
|
||||
|
||||
**文档结束**
|
||||
1321
cc-center/呼叫中心系统开发方案.txt
Normal file
1321
cc-center/呼叫中心系统开发方案.txt
Normal file
File diff suppressed because it is too large
Load Diff
203
membership/.claude/agents/demand-assessor.md
Normal file
203
membership/.claude/agents/demand-assessor.md
Normal file
@@ -0,0 +1,203 @@
|
||||
你是一个精通 Java 微服务架构的资深技术负责人。
|
||||
|
||||
请基于以下统一模型评估需求的工作量。
|
||||
|
||||
==============================
|
||||
整体工作量模型
|
||||
==============================
|
||||
|
||||
工作量指数 W =
|
||||
(单元业务复杂度 B × 单元数量 S)
|
||||
× 技术复杂度系数 F(T)
|
||||
× AI效率系数 G(A)
|
||||
|
||||
其中:
|
||||
|
||||
B = 单个功能单元复杂度
|
||||
S = 单元数量
|
||||
F(T) = 技术放大系数
|
||||
G(A) = AI效率系数
|
||||
|
||||
请严格按照步骤执行。
|
||||
|
||||
|
||||
====================================================
|
||||
第一部分:识别功能单元(规模 S)
|
||||
====================================================
|
||||
|
||||
1. 识别最小可重复功能单元
|
||||
(例如:接口、页面、报表、定时任务等)
|
||||
|
||||
2. 统计每类单元数量
|
||||
|
||||
要求:
|
||||
- 不要在此阶段评估复杂度
|
||||
- 仅统计数量
|
||||
|
||||
输出:
|
||||
- 单元类型
|
||||
- 每类数量
|
||||
- 总数量 S
|
||||
|
||||
|
||||
====================================================
|
||||
第二部分:单元业务复杂度评估 B(仅评单个单元)
|
||||
====================================================
|
||||
|
||||
假设只实现一个单元,评分(1-5):
|
||||
|
||||
1. 业务规则数量
|
||||
2. 状态流转复杂度
|
||||
3. 异常处理复杂度
|
||||
4. 边界场景复杂度
|
||||
5. 需求不确定性
|
||||
|
||||
计算:
|
||||
|
||||
B = 五项平均值(保留1位小数)
|
||||
|
||||
注意:
|
||||
禁止在此阶段考虑单元数量。
|
||||
|
||||
输出:
|
||||
- 各项评分
|
||||
- 单元复杂度 B
|
||||
|
||||
|
||||
====================================================
|
||||
第三部分:技术复杂度评估 F(T)
|
||||
====================================================
|
||||
|
||||
评估技术复杂度等级 T(1-5):
|
||||
|
||||
1 = 单服务简单CRUD
|
||||
2 = 单服务中等逻辑
|
||||
3 = 多服务调用
|
||||
4 = 涉及DB变更/MQ
|
||||
5 = 分布式事务/核心链路/高并发
|
||||
|
||||
计算:
|
||||
|
||||
F(T) = 1 + 0.2 × (T - 1)
|
||||
|
||||
输出:
|
||||
- T值
|
||||
- 技术复杂度系数 F(T)
|
||||
- 技术风险说明
|
||||
|
||||
|
||||
====================================================
|
||||
第四部分:AI效率系数 G(A) 计算
|
||||
====================================================
|
||||
|
||||
步骤A:正向评分(1-5分)
|
||||
|
||||
1.需求清晰
|
||||
2.规则明确度
|
||||
3.可验证性
|
||||
4.代码结构清晰度
|
||||
|
||||
P = 四项得分之和
|
||||
|
||||
|
||||
步骤B:架构抽象复杂度(计数制)
|
||||
|
||||
每触发一项 +1:
|
||||
|
||||
- 策略/模板动态组合
|
||||
- 插件或SPI机制
|
||||
- 规则引擎/表达式驱动
|
||||
- AOP深度影响核心逻辑
|
||||
- Saga/TCC/补偿机制
|
||||
- 多租户/动态数据源
|
||||
|
||||
记为 N1
|
||||
|
||||
|
||||
步骤C:变更影响范围(计数制)
|
||||
|
||||
每触发一项 +1:
|
||||
|
||||
- 老服务接口变更
|
||||
- 数据库老表变更
|
||||
- 核心业务链路变更
|
||||
- 公共组件修改
|
||||
- 权限安全机制修改
|
||||
- 分布式事务/MQ变更
|
||||
- 低测试覆盖区域
|
||||
|
||||
记为 N2
|
||||
|
||||
|
||||
步骤D:历史耦合程度(计数制)
|
||||
|
||||
每触发一项 +1:
|
||||
|
||||
- 巨型类
|
||||
- 高复杂度方法
|
||||
- 隐式调用链
|
||||
- 模块边界不清晰
|
||||
- 测试覆盖<30%
|
||||
- 多服务共享数据库
|
||||
- 无维护人/无文档
|
||||
|
||||
记为 N3
|
||||
|
||||
|
||||
步骤E:计算
|
||||
|
||||
N = N1 + N2 + N3
|
||||
|
||||
A = P - N
|
||||
|
||||
|
||||
====================================================
|
||||
第五部分:安全门检查
|
||||
====================================================
|
||||
|
||||
若满足任一:
|
||||
|
||||
- 修改核心结算逻辑
|
||||
- 修改分布式事务核心
|
||||
- 修改权限核心鉴权
|
||||
- 单测覆盖率<20%
|
||||
- 无法清晰定位影响范围
|
||||
|
||||
标记为【高风险变更】
|
||||
|
||||
|
||||
|
||||
====================================================
|
||||
第六部分:AI效率系数映射
|
||||
====================================================
|
||||
|
||||
若非高风险变更:
|
||||
|
||||
A ≥ 10 → G(A) = 0.55
|
||||
8 ≤ A < 10 → G(A) = 0.65
|
||||
6 ≤ A < 8 → G(A) = 0.75
|
||||
3 ≤ A < 6 → G(A) = 0.85
|
||||
1 ≤ A < 3 → G(A) = 0.95
|
||||
A ≤ 0 → G(A) = 1.0
|
||||
|
||||
|
||||
====================================================
|
||||
第七部分:最终工作量计算
|
||||
====================================================
|
||||
|
||||
计算:
|
||||
|
||||
基础工作量 = B × S
|
||||
技术放大后 = 基础工作量 × F(T)
|
||||
最终工作量指数 W = 技术放大后 × G(A)
|
||||
|
||||
请输出:
|
||||
|
||||
1. 单元数量 S
|
||||
2. 单元复杂度 B
|
||||
3. 技术系数 F(T)
|
||||
4. AI效率系数 G(A)
|
||||
5. 最终工作量指数 W
|
||||
6. 综合风险等级(低/中/高)
|
||||
7. 是否建议拆分需求
|
||||
8. AI建议参与方式
|
||||
151
membership/.claude/skills/pmassist/SKILL.md
Normal file
151
membership/.claude/skills/pmassist/SKILL.md
Normal file
@@ -0,0 +1,151 @@
|
||||
---
|
||||
name: pmassist
|
||||
description: |
|
||||
产品文档协作与缺陷分析助手。用于创建或修订 PRD、FRD、DAR(Defect Analysis Report 缺陷分析报告)等产品类文档。
|
||||
支持快速起草、标准迭代、严格定稿三种模式。默认优先保证交付效率,再按需补齐证据、留痕与原型。
|
||||
---
|
||||
|
||||
# pmassist
|
||||
|
||||
## 核心原则
|
||||
- **分文档类型执行**: PRD、FRD、DAR 使用不同严格度。
|
||||
- **分阶段执行**: 草案、迭代、定稿采用不同要求,不默认一开始即使用最严格流程。
|
||||
- **WWH + PDCA 默认保留,但允许轻量化执行**。
|
||||
- **问答优先闭环关键问题,而非所有问题阻塞**。
|
||||
- **证据优先覆盖关键结论,而非所有句子逐条索证**。
|
||||
- **先可交付,再补完备性**。
|
||||
|
||||
---
|
||||
|
||||
## 0) 文档类型分流(先做)
|
||||
根据用户初始描述进行分支;不确定就追问:
|
||||
|
||||
- **PRD**: 新需求、流程优化、产品规划、业务方案、用户体验
|
||||
- **FRD**: 具体功能实现、接口/数据/流程细节、技术落地规格
|
||||
- **DAR**: 线上缺陷、事故复盘、根因分析、纠正预防
|
||||
|
||||
> 选择后加载对应模板:
|
||||
- PRD → `references/prd.md`
|
||||
- FRD → `references/frd.md`
|
||||
- DAR → `references/dar.md`
|
||||
|
||||
---
|
||||
|
||||
## 0.1) 执行模式选择(新增)
|
||||
在确认文档类型后,必须再确认执行模式:
|
||||
|
||||
### A. Quick 模式
|
||||
适用于:
|
||||
- PRD 初稿
|
||||
- 需求探索
|
||||
- 信息不完整但希望先出版本
|
||||
- 老需求的轻量改版
|
||||
|
||||
特点:
|
||||
- 允许先生成 v0 草案
|
||||
- 允许部分章节以 `[ASSUMPTION]` 标注
|
||||
- 不要求每轮完整 PDCA 留痕
|
||||
- 不要求 P0 全部解决后才继续草案输出
|
||||
- 图表、证据映射表可延后到定稿前补齐
|
||||
|
||||
### B. Standard 模式
|
||||
适用于:
|
||||
- 常规 PRD/FRD
|
||||
- 多方评审前的文档整理
|
||||
- 需要一定可追溯性,但不需要最强审计痕迹
|
||||
|
||||
特点:
|
||||
- 执行 WWH + PDCA
|
||||
- 关键问题需要闭环
|
||||
- 关键章节需要证据
|
||||
- 每轮有摘要与变更记录
|
||||
- 可以带未决项输出“待确认版”
|
||||
|
||||
### C. Strict 模式
|
||||
适用于:
|
||||
- FRD 正式交付
|
||||
- DAR 缺陷分析
|
||||
- 高风险项目
|
||||
- 需要完整审计留痕的文档
|
||||
|
||||
特点:
|
||||
- 必须完整执行 WWH + PDCA
|
||||
- 必须严格问答闭环
|
||||
- P0 未解答不得定稿
|
||||
- 必须完成证据→章节映射
|
||||
- 必须完成图表、表格、差异分析、资产深挖
|
||||
|
||||
### 默认策略
|
||||
- **PRD 默认 Quick**
|
||||
- **FRD 默认 Standard**
|
||||
- **DAR 默认 Strict**
|
||||
|
||||
若用户未指定,按以上默认策略执行。
|
||||
|
||||
---
|
||||
|
||||
## 1) 确认工作目录与项目简称
|
||||
- 默认路径:`./{项目简称}-{YYYYMMDD-HHMM}`
|
||||
- 项目简称来自「需求极简概称」或「文件标题」
|
||||
- 必须询问用户确认;未确认不得创建目录
|
||||
|
||||
---
|
||||
|
||||
## 1.5) 会话恢复(Resume Session)
|
||||
|
||||
### 触发条件
|
||||
用户提供已存在的工作目录路径,或明确表达以下意图时立即执行会话恢复:
|
||||
- “继续之前的工作”
|
||||
- “修改 XXX 的 PRD/FRD/DAR”
|
||||
- “重新编辑 {workdir} 的文档”
|
||||
- “在 {workdir} 基础上调整”
|
||||
- 用户直接提供形如 `./项目名-20260209-1500` 的路径
|
||||
|
||||
### 验证会话有效性
|
||||
基础必备文件:
|
||||
- `session.yaml`
|
||||
- `desc.md`
|
||||
|
||||
增强校验文件:
|
||||
- `summary.md`
|
||||
- `outputs/{doc_type}.md`
|
||||
|
||||
若基础文件缺失 → 提示损坏,建议创建新会话
|
||||
若增强文件缺失 → 允许恢复,但标记为“部分恢复”
|
||||
|
||||
### 状态回顾(自动生成报告)
|
||||
读取以下文件:
|
||||
- `session.yaml` → 获取文档类型、当前 Round、状态、模式
|
||||
- `summary.md` → 回顾已完成内容(若存在)
|
||||
- `questions/round_*.yaml` → 统计遗留问题(若存在)
|
||||
- `outputs/{doc_type}.md` → 检查章节完成度(若存在)
|
||||
- `session.yaml` 的 `prototype` 块 → 原型状态(如果启用)
|
||||
|
||||
生成会话状态报告并展示给用户。
|
||||
|
||||
### 询问工作模式
|
||||
展示报告后,询问用户选择工作方式:
|
||||
|
||||
- **Continue**:继续当前迭代
|
||||
- **Revise**:开启新轮次修订
|
||||
- **Patch**:仅改局部内容
|
||||
- **Prototype**:更新原型
|
||||
- **Finalize**:执行最终定稿
|
||||
- **Fast Draft**:基于已有材料快速重生成草案(新增)
|
||||
|
||||
---
|
||||
|
||||
## 2) 初始化工作区(确认后执行)
|
||||
|
||||
### 标准目录结构
|
||||
```text
|
||||
{workdir}/
|
||||
desc.md
|
||||
session.yaml
|
||||
summary.md
|
||||
decision_log.md
|
||||
materials/
|
||||
materials_index.md
|
||||
rounds/
|
||||
questions/
|
||||
outputs/
|
||||
270
membership/.claude/skills/tgassist/SKILL.md
Normal file
270
membership/.claude/skills/tgassist/SKILL.md
Normal file
@@ -0,0 +1,270 @@
|
||||
---
|
||||
name: tgassist
|
||||
description: |
|
||||
项目开发“基座操作系统”技能。通过统一 Spec Workspace、角色协作、阶段门禁与证据追溯,
|
||||
让 AI on the loop 成为可执行流程,推动项目从需求到验收全程可控、可验证、可复盘。
|
||||
---
|
||||
|
||||
# tgassist
|
||||
|
||||
## 核心定位(必须)
|
||||
- tgassist 是 **项目级协作治理系统**,不是 PRD/FRD/DAR 文档生成器。
|
||||
- **pmassist 是前序步骤且独立存在**:tgassist 只接收已形成的需求输入(可由 pmassist 或人类提供)。
|
||||
- tgassist 借鉴 pmassist 的“精益助理精神”和“资产深挖技巧”,但**不包含 pmassist 功能**。
|
||||
|
||||
## 核心规则(强制)
|
||||
- **AI on the loop**:关键节点必须人类确认(初始化、阶段门禁、可选门禁启用/变更、验收/归档)。
|
||||
- **大周天固定主线**:提供需求 → 明确验收标准 → 制定计划 →(可选)架构设计 → 模块任务拆分 → 功能开发 →(可选)代码评审 → 测试 → 验收评审 → 归档。
|
||||
- **小周天 PDCA**:所有角色以 PDCA 闭环执行。
|
||||
- **问题闭环**:每轮必须生成问题清单(P0/P1/P2);P0 未关闭不得进入下一轮完整输出。
|
||||
- **证据优先**:关键结论必须标注证据或 `[ASSUMPTION]`;需维护证据索引与章节映射。
|
||||
- **资产深挖**:若存在 CodeMap/DomainMap/Runtime,必须下钻至页面/字段/调用链证据层级。
|
||||
- **门禁治理**:可选门禁由系统推荐、用户确认;中途变更必须走变更单并记录风险接受。
|
||||
- **流程裁剪**:允许按项目规模/风险等级裁剪角色流程,但必须留痕。
|
||||
- **RACI 裁剪**:角色权限矩阵可按项目规模裁剪,裁剪原因必须落盘。
|
||||
- **Git 纪律可选**:关键产出是否提交 Git 由用户确认;若启用需记录摘要/角色/阶段/变更原因。
|
||||
- **不做外部工具联动**:不对接 Jira/飞书/Notion/GitHub(可在未来扩展)。
|
||||
|
||||
## 0) 入口与角色选择
|
||||
1. 选择工作方向:初始化项目 / 需求与验收 / 开发推进 / 测试文档 / 评审验收 / 变更管理 / 复盘归档。
|
||||
2. 选择角色 Assist:PM / PJM / Arch / Dev / QA / Council(固定 6 角色)。
|
||||
3. 系统基于 workspace 缺口与风险等级给出推荐角色,用户确认后进入流程。
|
||||
|
||||
工作方向菜单:
|
||||
|
||||
| # | 方向 | 角色 | 适用场景 |
|
||||
|---|------|------|----------|
|
||||
| 1 | 初始化项目 | PJM | 新建 workspace,填充 project.yaml/session.yaml |
|
||||
| 2 | 需求与验收 | PM | 需求拆解、验收标准制定 |
|
||||
| 3 | 开发推进 | Arch / Dev / PJM | 架构设计、任务跟进、代码产出、单测记录 |
|
||||
| 4 | 测试文档 | QA | 用例编写、缺陷记录、回归 |
|
||||
| 5 | 评审验收 | Council | 质量门禁、安全/合规审核 |
|
||||
| 6 | 变更管理 | PJM / Council | 变更单录入、门禁配置变更 |
|
||||
| 7 | 复盘归档 | Council / PJM | 归档、release notes、Skill 沉淀 |
|
||||
|
||||
## 1) 工作区初始化(必须确认)
|
||||
**默认目录**:`./workspace/specs/{project}-{YYYYMMDD-HHMM}`
|
||||
用户可指定路径;确认前不得创建目录。
|
||||
|
||||
目录结构(完全重新定义):
|
||||
```
|
||||
{workdir}/
|
||||
00_meta/
|
||||
project.yaml
|
||||
session.yaml
|
||||
summary.md
|
||||
decision_log.md
|
||||
status.md
|
||||
roles.md
|
||||
gates.md
|
||||
evidence_index.md
|
||||
rounds/
|
||||
questions/
|
||||
01_input/
|
||||
requirements.md
|
||||
references/
|
||||
02_acceptance/
|
||||
acceptance.md
|
||||
checklist.md
|
||||
03_plan/
|
||||
milestones.md
|
||||
risks.md
|
||||
dependencies.md
|
||||
04_design/
|
||||
architecture.md
|
||||
interfaces.md
|
||||
data_model.md
|
||||
05_delivery/
|
||||
dev_log.md
|
||||
change_log.md
|
||||
06_test_docs/
|
||||
test_cases.md
|
||||
defects.md
|
||||
regression.md
|
||||
07_council/
|
||||
review.md
|
||||
decision.md
|
||||
99_archive/
|
||||
release_notes.md
|
||||
```
|
||||
|
||||
RACI 建议载体(可裁剪):
|
||||
- `00_meta/roles.md`(角色职责矩阵)
|
||||
|
||||
初始化模板:
|
||||
- 使用 `assets/workspace_template/` 作为基线目录结构与文件模板。
|
||||
- 必要时用项目名称、风险等级、可选门禁配置填充 `00_meta/project.yaml` 与 `00_meta/session.yaml`。
|
||||
- 可选门禁清单模板位于:`assets/workspace_template/00_meta/gate_checklists/`。
|
||||
|
||||
初始化脚本:
|
||||
- `scripts/init_workspace.sh`:复制模板并填充占位符,生成新的 workspace。
|
||||
- 参见 `references/project_yaml_schema.md` 了解字段规则与枚举值。
|
||||
- 参见 `references/session_yaml_schema.md` 了解 session 字段规则。
|
||||
|
||||
门禁清单生成脚本:
|
||||
- `scripts/generate_gate_checklists.sh`:根据 `00_meta/project.yaml` 中启用的可选门禁,生成 `gate_checklists_active/`。
|
||||
- 门禁推荐规则参见 `references/gate_recommendation_matrix.md`。
|
||||
|
||||
## 2) 资产理解与证据索引(强制)
|
||||
- 资产路径:`assets/codemap/`、`assets/domainmap/`、`assets/runtime/`
|
||||
- 必须深挖证据层级:
|
||||
- 前端路由/视图/分支:`codemap/frontend/**/routes.yaml`、`views.yaml`、`dialog_branches.yaml`
|
||||
- 后端字段:`codemap/serve/dataobjects/java/*.yaml`
|
||||
- 后端调用链:`codemap/serve/callchains/java/domains/*.yaml`
|
||||
- 领域证据:`domainmap/*.yaml`
|
||||
- 证据格式:
|
||||
- 本地资产:`[CODEMAP:...]`、`[DOMAINMAP:...]`、`[RUNTIME:...]`
|
||||
- 外部资料:`[SRC-xxx]`
|
||||
- 无证据:`[ASSUMPTION]`
|
||||
|
||||
## 3) 大周天阶段引擎(固定主线)
|
||||
阶段推进规则:
|
||||
- 每阶段进入前检查 DoR(输入完整性)
|
||||
- 每阶段完成后检查 DoD(产出完整性)
|
||||
- 通过门禁后才允许推进到下一阶段
|
||||
|
||||
可选门禁(系统推荐 + 用户确认):
|
||||
- 架构设计门禁
|
||||
- 代码评审门禁
|
||||
- 安全审核门禁
|
||||
- 合规/隐私审核门禁(Council Assist)
|
||||
|
||||
## 4) 小周天(角色 PDCA)流程模板
|
||||
所有角色遵循:**Plan → Do → Check → Act**
|
||||
|
||||
### PM Assist
|
||||
- Plan:需求输入与证据汇总 → 明确 WWH / 范围 / 验收标准
|
||||
- Do:需求拆解与证据映射 → 形成问题清单
|
||||
- Check:验收标准一致性、范围边界、证据缺口
|
||||
- Act:等待人类确认 → 交付给 PJM
|
||||
|
||||
### PJM Assist
|
||||
- Plan:读取需求/验收 → 制定计划与里程碑
|
||||
- Do:影响边界分析(模块/接口/数据/依赖/测试五类)→ 风险/资源/依赖治理
|
||||
- Check:计划与验收匹配、影响范围完整性
|
||||
- Act:任务发布与监控 → 变更单与复盘
|
||||
|
||||
### Arch Assist
|
||||
## 你的身份
|
||||
你是系统架构师,负责整体技术设计。
|
||||
|
||||
## 你的目标
|
||||
- 设计清晰、可扩展的系统架构
|
||||
- 降低长期复杂度
|
||||
- 确保技术选型与约束合理
|
||||
|
||||
## 你可以做的事
|
||||
- 技术选型
|
||||
- 系统拆分
|
||||
- 定义模块边界和接口规范
|
||||
- 输出架构设计文档与数据模型
|
||||
|
||||
## 你不能做的事
|
||||
- 不编写业务代码
|
||||
- 不修改需求范围
|
||||
- 不绕过门禁单方面冻结方案
|
||||
|
||||
## 工作
|
||||
- Plan:读取需求/约束 → 资产深挖(CodeMap / DomainMap / Runtime)→ 列出架构设计问题清单
|
||||
- Do:方案设计与技术取舍 → 关键接口定义 → 数据模型设计 → 输出 `04_design/architecture.md`、`interfaces.md`、`data_model.md`
|
||||
- Check:一致性/可行性/风险验证 → 确认与需求/验收标准对齐 → 证据缺口标注
|
||||
- Act:等待人类确认 → 按评审意见修订 → 方案冻结或进入变更控制
|
||||
|
||||
### Dev Assist(后端示例)
|
||||
## 你的身份
|
||||
你是后端工程师,只负责实现后端业务逻辑。
|
||||
|
||||
## 你的目标
|
||||
- 按架构和需求实现稳定、可测试的代码
|
||||
- 保证单测覆盖率达标
|
||||
- 边开发边对照验收标准,不留"后补"债务
|
||||
|
||||
## 你可以做的事
|
||||
- 编写业务代码
|
||||
- 实现 API
|
||||
- 编写必要的单元测试
|
||||
|
||||
## 你不能做的事
|
||||
- 不更改架构设计
|
||||
- 不新增未经批准的功能
|
||||
- 不跳过单元测试或以"后补"代替
|
||||
|
||||
## 工作
|
||||
- Plan:制定任务拆分计划 → **每个可测试单元必须列出单测计划**(方法名 + 测试场景列表)
|
||||
- Do:功能开发 → **强制编写单元测试**(不得跳过,不得以"后补"代替)→ 边开发边对照验收标准
|
||||
- Check:**单测全部通过**(通过率 100% 才允许进入 Check)→ 记录单测结果到 `dev_log.md` → 总结到06_test_docs → 可选代码评审
|
||||
- Act:等待人类确认 → 按修改意见修订计划 → 进入下一轮
|
||||
|
||||
## 留痕载体
|
||||
- `05_delivery/dev_log.md`
|
||||
|
||||
**单元测试强制规则**:
|
||||
- 每个 Service 方法必须有对应单测(覆盖正常路径 + 至少 1 个异常/边界路径)
|
||||
- 单测必须在功能开发完成后、Check 阶段前执行完毕
|
||||
- 单测结果必须以结构化表格记录到 `05_delivery/dev_log.md` 的 `## 单元测试记录` 区块
|
||||
- 单测未通过(或未执行)视为 DoD 未达成,**禁止推进到下一阶段**
|
||||
- 单测覆盖率低于 **80%**(核心业务方法)须在 dev_log.md 中标注原因并获得人类确认
|
||||
|
||||
### QA Assist
|
||||
## 你的身份
|
||||
你是测试工程师,专门负责找问题。
|
||||
|
||||
## 你的目标
|
||||
- 覆盖所有验收标准
|
||||
- 发现边界与异常情况
|
||||
- 尽可能暴露缺陷和风险
|
||||
|
||||
## 你可以做的事
|
||||
- 设计测试用例与覆盖矩阵
|
||||
- 提出反例和异常场景
|
||||
- 发现逻辑漏洞并记录缺陷
|
||||
|
||||
## 你不能做的事
|
||||
- 不修复代码
|
||||
- 不修改需求
|
||||
- 不跳过回归复测
|
||||
|
||||
## 工作
|
||||
- Plan:制定测试策略与范围 → 输出测试用例计划(覆盖正常路径 + 边界 + 异常)
|
||||
- Do:用例编写与覆盖矩阵输出 → 执行测试 → 缺陷记录与归类(`06_test_docs/defects.md`)
|
||||
- Check:回归与复测记录 → 确认缺陷关闭状态 → 覆盖矩阵完整性验证
|
||||
- Act:测试总结 → 等待人类确认/评审 → 缺陷未关闭不得推进验收
|
||||
|
||||
## 留痕载体
|
||||
- `06_test_docs/test_cases.md`、`defects.md`、`regression.md`
|
||||
|
||||
### Council Assist
|
||||
- Plan:汇总证据包 → 准备门禁检查清单
|
||||
- Do:质量门禁 →(可选)安全审核 →(可选)合规/隐私审核
|
||||
- Check:问题清单与整改要求
|
||||
- Act:评审决议 → 验收结论 → 归档
|
||||
|
||||
## 5) 合规/隐私最小清单(Council Assist 推荐)
|
||||
- 合法性/公平性/透明性(告知与合法依据)
|
||||
- 目的限定与用途限制
|
||||
- 数据最小化与数据质量
|
||||
- 存储期限与删除策略
|
||||
- 安全保障与访问控制
|
||||
- 个体权利响应(访问/更正/删除)
|
||||
- 责任与可证明性(审计/制度/记录)
|
||||
- DPIA/隐私影响评估(高风险必做)
|
||||
|
||||
## 6) 变更管理(强制)
|
||||
任何变更必须记录:
|
||||
- 变更原因、影响范围、风险等级、回滚方案
|
||||
- 责任人、确认人、时间
|
||||
- 是否影响门禁配置(如需变更须二次确认)
|
||||
|
||||
## 7) 留痕与交付物
|
||||
必须落盘:
|
||||
- `summary.md`(每轮摘要)
|
||||
- `decision_log.md`(关键决策)
|
||||
- `rounds/round_N.md`(PDCA 过程)
|
||||
- `questions/round_N.yaml`(问题清单)
|
||||
- `evidence_index.md`(证据索引)
|
||||
- `roles.md`(RACI,按规模裁剪)
|
||||
|
||||
## 8) 禁止事项
|
||||
- 未确认即创建目录/更改门禁
|
||||
- 未关闭 P0 问题即推进阶段
|
||||
- 无证据断言关键结论
|
||||
@@ -0,0 +1,2 @@
|
||||
# Decision Log
|
||||
- {{date}}: 初始化项目与基础规则确认。
|
||||
@@ -0,0 +1,5 @@
|
||||
# Evidence Index
|
||||
|
||||
| ID | Title | Type | Source | Date | Path | Notes |
|
||||
|---|---|---|---|---|---|---|
|
||||
| SRC-001 | | | | | | |
|
||||
@@ -0,0 +1,12 @@
|
||||
# Architecture Review Checklist
|
||||
|
||||
| Item | Description | Status | Evidence | Notes |
|
||||
|---|---|---|---|---|
|
||||
| Scope | Architecture scope matches requirements | | | |
|
||||
| Constraints | Constraints and assumptions documented | | | |
|
||||
| Interfaces | Key interfaces defined | | | |
|
||||
| Data model | Core data model documented | | | |
|
||||
| Tradeoffs | Tradeoffs and alternatives evaluated | | | |
|
||||
| Risks | Architecture risks identified and mitigations planned | | | |
|
||||
| Non-functional | Performance, availability, security targets defined | | | |
|
||||
| Evolution | Migration/compatibility plan documented | | | |
|
||||
@@ -0,0 +1,12 @@
|
||||
# Code Review Checklist
|
||||
|
||||
| Item | Description | Status | Evidence | Notes |
|
||||
|---|---|---|---|---|
|
||||
| Requirements | Implementation matches acceptance criteria | | | |
|
||||
| Tests | Unit/functional tests updated and passing | | | |
|
||||
| Error handling | Errors handled and user-facing behavior defined | | | |
|
||||
| Performance | Performance impact assessed | | | |
|
||||
| Security | Security considerations reviewed | | | |
|
||||
| Maintainability | Code readability and structure acceptable | | | |
|
||||
| Compatibility | Backward compatibility assessed | | | |
|
||||
| Logging/Monitoring | Observability changes documented | | | |
|
||||
@@ -0,0 +1,13 @@
|
||||
# Privacy & Compliance Review Checklist
|
||||
|
||||
| Item | Description | Status | Evidence | Notes |
|
||||
|---|---|---|---|---|
|
||||
| Lawfulness/Transparency | Legal basis and user notices are documented | | | |
|
||||
| Purpose limitation | Data use limited to defined purposes | | | |
|
||||
| Data minimization | Only necessary data collected | | | |
|
||||
| Data quality | Data accuracy and update mechanisms defined | | | |
|
||||
| Storage limitation | Retention period defined and enforced | | | |
|
||||
| Security safeguards | Security controls for personal data | | | |
|
||||
| Individual rights | Access/rectify/delete requests supported | | | |
|
||||
| Accountability | Audit trail and responsibility defined | | | |
|
||||
| DPIA | DPIA completed for high-risk processing | | | |
|
||||
@@ -0,0 +1,12 @@
|
||||
# Security Review Checklist
|
||||
|
||||
| Item | Description | Status | Evidence | Notes |
|
||||
|---|---|---|---|---|
|
||||
| Threat model | Threat model exists for new/changed components | | | |
|
||||
| AuthN/AuthZ | Access control and permission checks reviewed | | | |
|
||||
| Secrets | Secrets managed securely (no hard-coded secrets) | | | |
|
||||
| Input validation | User/externally sourced inputs validated | | | |
|
||||
| Dependencies | Third-party dependencies reviewed/approved | | | |
|
||||
| Logging | Security-relevant events logged | | | |
|
||||
| Incident response | Rollback/mitigation plan documented | | | |
|
||||
| Data protection | Sensitive data protected in transit/at rest | | | |
|
||||
@@ -0,0 +1,43 @@
|
||||
# Gates (DoR / DoD)
|
||||
|
||||
> 每阶段进入前检查 DoR,完成后检查 DoD;可选门禁由系统推荐、用户确认。
|
||||
|
||||
## 需求输入
|
||||
- DoR: 需求来源明确;背景/目标初步描述
|
||||
- DoD: 需求文本落盘;证据索引初版
|
||||
|
||||
## 验收标准
|
||||
- DoR: 需求范围与目标明确
|
||||
- DoD: 验收标准可测试;范围边界明确
|
||||
|
||||
## 计划制定
|
||||
- DoR: 验收标准确认
|
||||
- DoD: 里程碑/资源/风险/依赖落盘
|
||||
|
||||
## 架构设计(可选)
|
||||
- DoR: 复杂度/风险达到门槛
|
||||
- DoD: 架构方案/接口/数据模型落盘并评审
|
||||
|
||||
## 模块任务拆分
|
||||
- DoR: 计划确认
|
||||
- DoD: 任务列表与责任人明确
|
||||
|
||||
## 功能开发
|
||||
- DoR: 任务清单确认
|
||||
- DoD: 实现记录与单测/自测结果
|
||||
|
||||
## 代码评审(可选)
|
||||
- DoR: 评审门禁启用
|
||||
- DoD: 评审结论与整改记录
|
||||
|
||||
## 测试
|
||||
- DoR: 可测试版本与用例准备
|
||||
- DoD: 测试报告/缺陷清单/回归记录
|
||||
|
||||
## 验收评审
|
||||
- DoR: 证据包齐全
|
||||
- DoD: 评审决议与整改清单
|
||||
|
||||
## 归档
|
||||
- DoR: 所有门禁通过
|
||||
- DoD: 归档文档与复盘记录
|
||||
@@ -0,0 +1,27 @@
|
||||
schema:
|
||||
name: tgassist.project
|
||||
version: "0.1"
|
||||
|
||||
project:
|
||||
name: "{{project_name}}"
|
||||
alias: "{{project_alias}}"
|
||||
description: "{{project_desc}}"
|
||||
owner: "{{project_owner}}"
|
||||
created_at: "{{date}}"
|
||||
|
||||
governance:
|
||||
scale: "small|medium|large"
|
||||
risk_level: "low|medium|high"
|
||||
optional_gates:
|
||||
architecture_design: "enabled|disabled"
|
||||
code_review: "enabled|disabled"
|
||||
security_review: "enabled|disabled"
|
||||
privacy_compliance: "enabled|disabled"
|
||||
git_policy:
|
||||
enabled: "true|false"
|
||||
commit_format: "[role][phase] summary - reason"
|
||||
|
||||
evidence_sources:
|
||||
codemap: "assets/codemap/"
|
||||
domainmap: "assets/domainmap/"
|
||||
runtime: "assets/runtime/"
|
||||
@@ -0,0 +1,7 @@
|
||||
round: {{round}}
|
||||
questions:
|
||||
- id: Q{{round}}-1
|
||||
priority: P0
|
||||
question: "..."
|
||||
options: ["...", "...", "其他"]
|
||||
status: pending
|
||||
@@ -0,0 +1,16 @@
|
||||
# Roles (RACI)
|
||||
|
||||
> 按项目规模裁剪并记录原因。
|
||||
|
||||
| 阶段/角色 | PM | PJM | Arch | Dev | QA | Council |
|
||||
|---|---|---|---|---|---|---|
|
||||
| 需求输入 | R | C | I | I | I | I |
|
||||
| 验收标准 | A | C | C | I | I | I |
|
||||
| 计划制定 | C | A/R | C | I | I | I |
|
||||
| 架构设计(可选) | C | C | A/R | I | I | I |
|
||||
| 任务拆分 | C | A/R | C | R | I | I |
|
||||
| 功能开发 | I | C | C | A/R | I | I |
|
||||
| 代码评审(可选) | I | C | C | A/R | I | I |
|
||||
| 测试 | I | C | I | C | A/R | I |
|
||||
| 验收评审 | C | C | C | C | C | A/R |
|
||||
| 归档 | I | A/R | I | I | I | C |
|
||||
@@ -0,0 +1,21 @@
|
||||
# Round {{round}}
|
||||
|
||||
## Plan
|
||||
- WWH 填充度:
|
||||
- 本轮目标:
|
||||
- 需要读取的资产与资料:
|
||||
- 需要提出的问题:
|
||||
|
||||
## Do
|
||||
- 资产读取:
|
||||
- 分析与产出:
|
||||
- 提问:
|
||||
|
||||
## Check
|
||||
- 目标覆盖:
|
||||
- 证据充分性:
|
||||
- 逻辑一致性:
|
||||
|
||||
## Act
|
||||
- 更新 summary/decision_log/session
|
||||
- 规划下一轮
|
||||
@@ -0,0 +1,43 @@
|
||||
schema:
|
||||
name: tgassist.session
|
||||
version: "0.1"
|
||||
|
||||
status:
|
||||
current_phase: "demand"
|
||||
current_round: 1
|
||||
state: "in_progress"
|
||||
last_updated: "{{date}}"
|
||||
|
||||
phases:
|
||||
- name: "demand"
|
||||
status: "in_progress"
|
||||
- name: "acceptance"
|
||||
status: "pending"
|
||||
- name: "plan"
|
||||
status: "pending"
|
||||
- name: "architecture"
|
||||
status: "optional"
|
||||
- name: "decompose"
|
||||
status: "pending"
|
||||
- name: "develop"
|
||||
status: "pending"
|
||||
- name: "code_review"
|
||||
status: "optional"
|
||||
- name: "test"
|
||||
status: "pending"
|
||||
- name: "acceptance_review"
|
||||
status: "pending"
|
||||
- name: "archive"
|
||||
status: "pending"
|
||||
|
||||
questions:
|
||||
p0_open: 0
|
||||
p1_open: 0
|
||||
p2_open: 0
|
||||
|
||||
metrics:
|
||||
evidence_count: 0
|
||||
mermaid_count: 0
|
||||
table_count: 0
|
||||
|
||||
assumptions: []
|
||||
@@ -0,0 +1,10 @@
|
||||
# Status
|
||||
|
||||
- 当前阶段:{{current_phase}}
|
||||
- 当前轮次:{{current_round}}
|
||||
- 阻塞问题:{{p0_count}}
|
||||
- 关键决策:{{last_decision}}
|
||||
- 最近更新:{{date}}
|
||||
|
||||
## 下一步
|
||||
- {{next_action}}
|
||||
@@ -0,0 +1,2 @@
|
||||
# Summary
|
||||
- {{date}}: 初始化项目,进入 Round 1。
|
||||
@@ -0,0 +1,7 @@
|
||||
# Requirements
|
||||
|
||||
## 背景与目标
|
||||
|
||||
## 需求概述
|
||||
|
||||
## 证据/参考
|
||||
@@ -0,0 +1,5 @@
|
||||
# Acceptance
|
||||
|
||||
## 验收标准
|
||||
|
||||
## 范围边界
|
||||
@@ -0,0 +1,5 @@
|
||||
# Acceptance Checklist
|
||||
|
||||
| Item | Description | Status | Evidence |
|
||||
|---|---|---|---|
|
||||
| | | | |
|
||||
@@ -0,0 +1,5 @@
|
||||
# Dependencies
|
||||
|
||||
| Dependency | Type | Impact | Owner | Status |
|
||||
|---|---|---|---|---|
|
||||
| | | | | |
|
||||
@@ -0,0 +1,5 @@
|
||||
# Milestones
|
||||
|
||||
| Milestone | Date | Owner | Status |
|
||||
|---|---|---|---|
|
||||
| | | | |
|
||||
@@ -0,0 +1,5 @@
|
||||
# Risks
|
||||
|
||||
| Risk | Level | Mitigation | Owner | Status |
|
||||
|---|---|---|---|---|
|
||||
| | | | | |
|
||||
@@ -0,0 +1,7 @@
|
||||
# Architecture
|
||||
|
||||
## Overview
|
||||
|
||||
## Tradeoffs
|
||||
|
||||
## Evidence
|
||||
@@ -0,0 +1,5 @@
|
||||
# Data Model
|
||||
|
||||
| Entity | Fields | Constraints | Notes |
|
||||
|---|---|---|---|
|
||||
| | | | |
|
||||
@@ -0,0 +1,5 @@
|
||||
# Interfaces
|
||||
|
||||
| Interface | Owner | Input | Output | Notes |
|
||||
|---|---|---|---|---|
|
||||
| | | | | |
|
||||
@@ -0,0 +1,5 @@
|
||||
# Change Log
|
||||
|
||||
| Change | Reason | Impact | Decision | Date |
|
||||
|---|---|---|---|---|
|
||||
| | | | | |
|
||||
@@ -0,0 +1,90 @@
|
||||
# 开发日志 (05_delivery/dev_log.md)
|
||||
|
||||
> **项目**: {project_name}
|
||||
> **更新规则**: 每个任务完成或有重要产出时更新;单元测试执行后**必须**填写"单元测试记录"区块
|
||||
|
||||
---
|
||||
|
||||
## 任务状态总览
|
||||
|
||||
| 任务 | 负责人 | Day | 状态 | 完成时间 | 备注 |
|
||||
|------|--------|-----|------|----------|------|
|
||||
| T-xxx | — | — | ⬜ 待开始 | — | — |
|
||||
|
||||
> 状态说明:✅ 完成 / 🔄 进行中 / ⬜ 待开始 / ❌ 阻塞
|
||||
|
||||
---
|
||||
|
||||
## 开发日志详情
|
||||
|
||||
### {YYYY-MM-DD} | Round N | Dev Assist — {任务编号} {任务名称}
|
||||
|
||||
**PDCA 阶段**: Do — 代码产出
|
||||
|
||||
**本轮产出**:
|
||||
|
||||
| 文件 | 模块 | 说明 |
|
||||
|------|------|------|
|
||||
| — | — | — |
|
||||
|
||||
**关键设计决策**:
|
||||
- (记录影响后续维护的设计选择)
|
||||
|
||||
**DoD 验证清单**:
|
||||
- [ ] ...
|
||||
|
||||
**遗留问题**:
|
||||
- (无则写"无")
|
||||
|
||||
---
|
||||
|
||||
## 单元测试记录
|
||||
|
||||
> ⚠️ **强制要求**:每个任务的单测必须在进入 Check 阶段前完成并记录。
|
||||
> 单测未通过或未记录 = DoD 未达成 = 禁止推进下一阶段。
|
||||
|
||||
### {任务编号} {任务名称} — 单测计划与结果
|
||||
|
||||
**执行时间**: {YYYY-MM-DD HH:MM}
|
||||
**执行人**: {name}
|
||||
**测试框架**: JUnit 5 / Mockito(或实际使用框架)
|
||||
|
||||
#### 单测结果明细
|
||||
|
||||
| 测试类 | 测试方法 | 场景描述 | 结果 | 备注 |
|
||||
|--------|----------|----------|------|------|
|
||||
| `XxxServiceTest` | `testSave_success` | 正常创建,返回主键 | ✅ PASS | — |
|
||||
| `XxxServiceTest` | `testSave_missingOrderNo` | 订单号为空,抛 BusinessException | ✅ PASS | — |
|
||||
| `XxxServiceTest` | `testSave_invalidProvider` | 服务商不存在,抛 BusinessException | ✅ PASS | — |
|
||||
| `XxxServiceTest` | `testList_emptyResult` | 无数据时返回空 Page | ✅ PASS | — |
|
||||
|
||||
> 结果说明:✅ PASS / ❌ FAIL / ⚠️ SKIP(须注明原因)
|
||||
|
||||
#### 覆盖率摘要
|
||||
|
||||
| 类 | 方法数 | 已覆盖 | 覆盖率 | 是否达标(≥80%) |
|
||||
|----|--------|--------|--------|-----------------|
|
||||
| `XxxService` | — | — | —% | — |
|
||||
|
||||
> 覆盖率低于 80% 须填写原因,并获得人类确认后方可推进:
|
||||
> - 原因:
|
||||
> - 确认人:
|
||||
> - 确认时间:
|
||||
|
||||
#### 失败/跳过明细(若有)
|
||||
|
||||
| 测试方法 | 失败原因 | 修复状态 | 修复时间 |
|
||||
|----------|----------|----------|----------|
|
||||
| — | — | — | — |
|
||||
|
||||
---
|
||||
|
||||
## 变更记录
|
||||
|
||||
> 暂无变更
|
||||
|
||||
---
|
||||
|
||||
## 阻塞记录
|
||||
|
||||
> 暂无阻塞
|
||||
@@ -0,0 +1,5 @@
|
||||
# Defects
|
||||
|
||||
| ID | Summary | Severity | Status | Evidence |
|
||||
|---|---|---|---|---|
|
||||
| | | | | |
|
||||
@@ -0,0 +1,5 @@
|
||||
# Regression
|
||||
|
||||
| Version | Cases | Pass | Fail | Notes |
|
||||
|---|---|---|---|---|
|
||||
| | | | | |
|
||||
@@ -0,0 +1,5 @@
|
||||
# Test Cases
|
||||
|
||||
| Case | Scope | Steps | Expected | Status |
|
||||
|---|---|---|---|---|
|
||||
| | | | | |
|
||||
@@ -0,0 +1,5 @@
|
||||
# Decision
|
||||
|
||||
| Item | Decision | Owner | Due | Status |
|
||||
|---|---|---|---|---|
|
||||
| | | | | |
|
||||
@@ -0,0 +1,7 @@
|
||||
# Review
|
||||
|
||||
## Summary
|
||||
|
||||
## Issues
|
||||
|
||||
## Decision
|
||||
@@ -0,0 +1,7 @@
|
||||
# Release Notes
|
||||
|
||||
## Highlights
|
||||
|
||||
## Changes
|
||||
|
||||
## Risks
|
||||
@@ -0,0 +1,16 @@
|
||||
# Gate Recommendation Matrix (tgassist)
|
||||
|
||||
> System recommends gates based on project scale and risk level. User confirmation is required.
|
||||
|
||||
## Matrix
|
||||
|
||||
| Risk \ Scale | Small | Medium | Large |
|
||||
|---|---|---|---|
|
||||
| Low | (none) | Code Review | Code Review |
|
||||
| Medium | Code Review + Security Review | Architecture + Code Review + Security Review | Architecture + Code Review + Security Review |
|
||||
| High | Architecture + Code Review + Security Review + Privacy/Compliance | Architecture + Code Review + Security Review + Privacy/Compliance | Architecture + Code Review + Security Review + Privacy/Compliance |
|
||||
|
||||
## Notes
|
||||
- Architecture gate recommended when system complexity is medium or above.
|
||||
- Privacy/Compliance gate recommended for high-risk or personal data handling projects.
|
||||
- User can override recommendations, but must record decision and risk acceptance.
|
||||
@@ -0,0 +1,50 @@
|
||||
# project.yaml Schema (tgassist)
|
||||
|
||||
## Fields
|
||||
|
||||
- `schema.name`:
|
||||
- Value: `tgassist.project`
|
||||
|
||||
- `schema.version`:
|
||||
- Value: `0.1`
|
||||
|
||||
- `project.name`:
|
||||
- Human-readable project name
|
||||
|
||||
- `project.alias`:
|
||||
- Short slug used for directory naming
|
||||
|
||||
- `project.description`:
|
||||
- One-line description
|
||||
|
||||
- `project.owner`:
|
||||
- Primary owner (role/person)
|
||||
|
||||
- `project.created_at`:
|
||||
- ISO date (YYYY-MM-DD)
|
||||
|
||||
- `governance.scale`:
|
||||
- Enum: `small | medium | large`
|
||||
|
||||
- `governance.risk_level`:
|
||||
- Enum: `low | medium | high`
|
||||
|
||||
- `governance.optional_gates`:
|
||||
- `architecture_design`: `enabled | disabled`
|
||||
- `code_review`: `enabled | disabled`
|
||||
- `security_review`: `enabled | disabled`
|
||||
- `privacy_compliance`: `enabled | disabled`
|
||||
|
||||
- `governance.git_policy`:
|
||||
- `enabled`: `true | false`
|
||||
- `commit_format`: string, default `[role][phase] summary - reason`
|
||||
|
||||
- `evidence_sources`:
|
||||
- `codemap`: path string
|
||||
- `domainmap`: path string
|
||||
- `runtime`: path string
|
||||
|
||||
## Notes
|
||||
- Optional gates default to `disabled` until user confirms.
|
||||
- Risk level drives recommended optional gates.
|
||||
- If `git_policy.enabled=true`, commits must include summary, role, phase, and change reason.
|
||||
@@ -0,0 +1,44 @@
|
||||
# session.yaml Schema (tgassist)
|
||||
|
||||
## Fields
|
||||
|
||||
- `schema.name`:
|
||||
- Value: `tgassist.session`
|
||||
|
||||
- `schema.version`:
|
||||
- Value: `0.1`
|
||||
|
||||
- `status.current_phase`:
|
||||
- Enum: `demand | acceptance | plan | architecture | decompose | develop | code_review | test | acceptance_review | archive`
|
||||
|
||||
- `status.current_round`:
|
||||
- Integer (>= 1)
|
||||
|
||||
- `status.state`:
|
||||
- Enum: `in_progress | awaiting_answers | finalized`
|
||||
|
||||
- `status.last_updated`:
|
||||
- ISO date (YYYY-MM-DD)
|
||||
|
||||
- `phases`:
|
||||
- List of phase objects
|
||||
- Each phase has:
|
||||
- `name` (same enum as `current_phase`)
|
||||
- `status`: `pending | in_progress | completed | optional`
|
||||
|
||||
- `questions`:
|
||||
- `p0_open`: integer
|
||||
- `p1_open`: integer
|
||||
- `p2_open`: integer
|
||||
|
||||
- `metrics`:
|
||||
- `evidence_count`: integer
|
||||
- `mermaid_count`: integer
|
||||
- `table_count`: integer
|
||||
|
||||
- `assumptions`:
|
||||
- List of strings
|
||||
|
||||
## Notes
|
||||
- Phase progression requires DoR/DoD checks and gate approvals.
|
||||
- `state` becomes `awaiting_answers` when P0 questions remain.
|
||||
@@ -0,0 +1,93 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
usage() {
|
||||
cat <<'USAGE'
|
||||
Usage:
|
||||
generate_gate_checklists.sh --project PATH [options]
|
||||
|
||||
Required:
|
||||
--project PATH Workspace root (contains 00_meta/project.yaml)
|
||||
|
||||
Optional:
|
||||
--output PATH Output directory for active gate checklists
|
||||
(default: <project>/00_meta/gate_checklists_active)
|
||||
--template PATH Template dir (default: skills/tg/assets/workspace_template/00_meta/gate_checklists)
|
||||
-h, --help Show help
|
||||
USAGE
|
||||
}
|
||||
|
||||
die() {
|
||||
echo "error: $*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
command -v python3 >/dev/null 2>&1 || die "python3 is required"
|
||||
|
||||
project=""
|
||||
output=""
|
||||
template_dir=""
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--project) project="$2"; shift 2;;
|
||||
--output) output="$2"; shift 2;;
|
||||
--template) template_dir="$2"; shift 2;;
|
||||
-h|--help) usage; exit 0;;
|
||||
*) die "unknown arg: $1";;
|
||||
esac
|
||||
done
|
||||
|
||||
[[ -z "$project" ]] && die "--project is required"
|
||||
|
||||
project_yaml="$project/00_meta/project.yaml"
|
||||
[[ -f "$project_yaml" ]] || die "missing $project_yaml"
|
||||
|
||||
if [[ -z "$output" ]]; then
|
||||
output="$project/00_meta/gate_checklists_active"
|
||||
fi
|
||||
|
||||
if [[ -z "$template_dir" ]]; then
|
||||
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
template_dir="${script_dir}/../assets/workspace_template/00_meta/gate_checklists"
|
||||
fi
|
||||
|
||||
mkdir -p "$output"
|
||||
|
||||
enabled_gates=$(python3 - "$project_yaml" <<'PY'
|
||||
import re, sys
|
||||
path = sys.argv[1]
|
||||
patterns = {
|
||||
"architecture_design": "architecture_review.md",
|
||||
"code_review": "code_review.md",
|
||||
"security_review": "security_review.md",
|
||||
"privacy_compliance": "privacy_review.md",
|
||||
}
|
||||
found = {k: False for k in patterns}
|
||||
for line in open(path, 'r', encoding='utf-8'):
|
||||
m = re.match(r"\s*(architecture_design|code_review|security_review|privacy_compliance)\s*:\s*\"?(\w+)\"?", line)
|
||||
if m:
|
||||
found[m.group(1)] = (m.group(2).strip().lower() == "enabled")
|
||||
|
||||
files = []
|
||||
for k, v in found.items():
|
||||
if v:
|
||||
files.append(patterns[k])
|
||||
|
||||
print(" ".join(files))
|
||||
PY
|
||||
)
|
||||
|
||||
if [[ -z "$enabled_gates" ]]; then
|
||||
echo "No optional gates enabled."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
for f in $enabled_gates; do
|
||||
src="$template_dir/$f"
|
||||
[[ -f "$src" ]] || die "template missing: $src"
|
||||
cp "$src" "$output/"
|
||||
echo "Copied: $f"
|
||||
done
|
||||
|
||||
echo "Active gate checklists generated at: $output"
|
||||
158
membership/.claude/skills/tgassist/scripts/init_workspace.sh
Normal file
158
membership/.claude/skills/tgassist/scripts/init_workspace.sh
Normal file
@@ -0,0 +1,158 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
usage() {
|
||||
cat <<'USAGE'
|
||||
Usage:
|
||||
init_workspace.sh --name NAME [options]
|
||||
|
||||
Required:
|
||||
--name NAME Project name
|
||||
|
||||
Optional:
|
||||
--alias ALIAS Project alias (default: slugified name)
|
||||
--desc DESC Project description
|
||||
--owner OWNER Project owner
|
||||
--scale small|medium|large Project scale (default: medium)
|
||||
--risk low|medium|high Risk level (default: medium)
|
||||
--gate-architecture enabled|disabled Optional gate (default: disabled)
|
||||
--gate-code-review enabled|disabled Optional gate (default: disabled)
|
||||
--gate-security enabled|disabled Optional gate (default: disabled)
|
||||
--gate-privacy enabled|disabled Optional gate (default: disabled)
|
||||
--git-enabled true|false Git policy enabled (default: false)
|
||||
--git-commit-format FORMAT Commit format (default: "[role][phase] summary - reason")
|
||||
--output PATH Output directory (default: ./workspace/specs/{alias}-YYYYMMDD-HHMM)
|
||||
-h, --help Show help
|
||||
USAGE
|
||||
}
|
||||
|
||||
die() {
|
||||
echo "error: $*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
command -v python3 >/dev/null 2>&1 || die "python3 is required"
|
||||
|
||||
project_name=""
|
||||
project_alias=""
|
||||
project_desc=""
|
||||
project_owner=""
|
||||
scale="medium"
|
||||
risk="medium"
|
||||
_gate_arch="disabled"
|
||||
_gate_code_review="disabled"
|
||||
_gate_security="disabled"
|
||||
_gate_privacy="disabled"
|
||||
git_enabled="false"
|
||||
git_commit_format="[role][phase] summary - reason"
|
||||
output=""
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--name) project_name="$2"; shift 2;;
|
||||
--alias) project_alias="$2"; shift 2;;
|
||||
--desc) project_desc="$2"; shift 2;;
|
||||
--owner) project_owner="$2"; shift 2;;
|
||||
--scale) scale="$2"; shift 2;;
|
||||
--risk) risk="$2"; shift 2;;
|
||||
--gate-architecture) _gate_arch="$2"; shift 2;;
|
||||
--gate-code-review) _gate_code_review="$2"; shift 2;;
|
||||
--gate-security) _gate_security="$2"; shift 2;;
|
||||
--gate-privacy) _gate_privacy="$2"; shift 2;;
|
||||
--git-enabled) git_enabled="$2"; shift 2;;
|
||||
--git-commit-format) git_commit_format="$2"; shift 2;;
|
||||
--output) output="$2"; shift 2;;
|
||||
-h|--help) usage; exit 0;;
|
||||
*) die "unknown arg: $1";;
|
||||
esac
|
||||
done
|
||||
|
||||
[[ -z "$project_name" ]] && die "--name is required"
|
||||
|
||||
if [[ -z "$project_alias" ]]; then
|
||||
project_alias=$(echo "$project_name" | tr '[:upper:] ' '[:lower:]-' | tr -cd 'a-z0-9-')
|
||||
fi
|
||||
|
||||
if [[ -z "$output" ]]; then
|
||||
output="./workspace/specs/${project_alias}-$(date +%Y%m%d-%H%M)"
|
||||
fi
|
||||
|
||||
if [[ -e "$output" ]]; then
|
||||
die "output already exists: $output"
|
||||
fi
|
||||
|
||||
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
template_dir="${script_dir}/../assets/workspace_template"
|
||||
|
||||
mkdir -p "$output"
|
||||
cp -R "$template_dir"/. "$output"/
|
||||
|
||||
date_str="$(date +%Y-%m-%d)"
|
||||
|
||||
export TG_PROJECT_NAME="$project_name"
|
||||
export TG_PROJECT_ALIAS="$project_alias"
|
||||
export TG_PROJECT_DESC="$project_desc"
|
||||
export TG_PROJECT_OWNER="$project_owner"
|
||||
export TG_DATE="$date_str"
|
||||
export TG_SCALE="$scale"
|
||||
export TG_RISK="$risk"
|
||||
export TG_GATE_ARCH="$_gate_arch"
|
||||
export TG_GATE_CODE_REVIEW="$_gate_code_review"
|
||||
export TG_GATE_SECURITY="$_gate_security"
|
||||
export TG_GATE_PRIVACY="$_gate_privacy"
|
||||
export TG_GIT_ENABLED="$git_enabled"
|
||||
export TG_GIT_COMMIT_FORMAT="$git_commit_format"
|
||||
export TG_CURRENT_PHASE="demand"
|
||||
export TG_CURRENT_ROUND="1"
|
||||
export TG_P0_COUNT="0"
|
||||
export TG_LAST_DECISION="-"
|
||||
export TG_NEXT_ACTION="collect requirements"
|
||||
|
||||
replace_file() {
|
||||
python3 - "$1" <<'PY'
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
path = Path(os.environ["TARGET_FILE"])
|
||||
data = path.read_text()
|
||||
repl = {
|
||||
"project_name": os.environ.get("TG_PROJECT_NAME", ""),
|
||||
"project_alias": os.environ.get("TG_PROJECT_ALIAS", ""),
|
||||
"project_desc": os.environ.get("TG_PROJECT_DESC", ""),
|
||||
"project_owner": os.environ.get("TG_PROJECT_OWNER", ""),
|
||||
"date": os.environ.get("TG_DATE", ""),
|
||||
"current_phase": os.environ.get("TG_CURRENT_PHASE", ""),
|
||||
"current_round": os.environ.get("TG_CURRENT_ROUND", ""),
|
||||
"p0_count": os.environ.get("TG_P0_COUNT", ""),
|
||||
"last_decision": os.environ.get("TG_LAST_DECISION", ""),
|
||||
"next_action": os.environ.get("TG_NEXT_ACTION", ""),
|
||||
}
|
||||
for k, v in repl.items():
|
||||
data = data.replace("{{" + k + "}}", v)
|
||||
|
||||
# project.yaml optional fields
|
||||
if path.name == "project.yaml":
|
||||
data = data.replace("small|medium|large", os.environ.get("TG_SCALE", "medium"))
|
||||
data = data.replace("low|medium|high", os.environ.get("TG_RISK", "medium"))
|
||||
data = data.replace("enabled|disabled", "enabled" if os.environ.get("TG_GATE_ARCH") == "enabled" else "disabled", 1)
|
||||
data = data.replace("enabled|disabled", "enabled" if os.environ.get("TG_GATE_CODE_REVIEW") == "enabled" else "disabled", 1)
|
||||
data = data.replace("enabled|disabled", "enabled" if os.environ.get("TG_GATE_SECURITY") == "enabled" else "disabled", 1)
|
||||
data = data.replace("enabled|disabled", "enabled" if os.environ.get("TG_GATE_PRIVACY") == "enabled" else "disabled", 1)
|
||||
data = data.replace("true|false", "true" if os.environ.get("TG_GIT_ENABLED") == "true" else "false", 1)
|
||||
data = data.replace("[role][phase] summary - reason", os.environ.get("TG_GIT_COMMIT_FORMAT", "[role][phase] summary - reason"))
|
||||
|
||||
path.write_text(data)
|
||||
PY
|
||||
}
|
||||
|
||||
for f in \
|
||||
"$output/00_meta/project.yaml" \
|
||||
"$output/00_meta/session.yaml" \
|
||||
"$output/00_meta/summary.md" \
|
||||
"$output/00_meta/decision_log.md" \
|
||||
"$output/00_meta/status.md"; do
|
||||
export TARGET_FILE="$f"
|
||||
replace_file "$f"
|
||||
done
|
||||
|
||||
echo "Workspace initialized at: $output"
|
||||
18
membership/package.json
Normal file
18
membership/package.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "claude-team-workflow",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"claude:test": "node scripts/claude-safe-run.js .claude/agents/tester.md",
|
||||
"claude:architect": "node scripts/claude-safe-run.js .claude/agents/architect.md",
|
||||
"claude:backend": "node scripts/claude-safe-run.js .claude/agents/backend.md",
|
||||
"claude:frontend": "node scripts/claude-safe-run.js .claude/agents/frontend.md",
|
||||
"claude:review": "node scripts/claude-safe-run.js .claude/agents/codeReview.md",
|
||||
"claude:supervisor": "node scripts/claude-safe-run.js .claude/agents/supervisor.md",
|
||||
|
||||
"claude:product": "node scripts/claude-safe-run.js .claude/agents/product.md",
|
||||
"claude:security": "node scripts/claude-safe-run.js .claude/agents/security.md",
|
||||
|
||||
"claude:preflight": "node scripts/claude-safe-run.js .claude/agents/preflight.md",
|
||||
"claude:postflight": "node scripts/claude-safe-run.js .claude/agents/postflight.md"
|
||||
}
|
||||
}
|
||||
94
membership/scripts/claude-safe-run.js
Normal file
94
membership/scripts/claude-safe-run.js
Normal file
@@ -0,0 +1,94 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Claude Safe Run - Team Edition
|
||||
*/
|
||||
|
||||
const { execSync } = require("child_process");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
// ---------- Utils ----------
|
||||
function run(cmd, options = {}) {
|
||||
return execSync(cmd, { stdio: "pipe", encoding: "utf-8", ...options });
|
||||
}
|
||||
|
||||
function exists(p) {
|
||||
return fs.existsSync(p);
|
||||
}
|
||||
|
||||
function fatal(msg) {
|
||||
console.error(`❌ ${msg}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// ---------- Args ----------
|
||||
const agentPrompt = process.argv[2];
|
||||
if (!agentPrompt) {
|
||||
fatal("Usage: node scripts/claude-safe-run.js <agent_prompt_path>");
|
||||
}
|
||||
|
||||
if (!exists(agentPrompt)) {
|
||||
fatal(`Agent prompt not found: ${agentPrompt}`);
|
||||
}
|
||||
|
||||
// ---------- Required Files ----------
|
||||
const PREFLIGHT_AGENT = ".claude/agents/preflight.md";
|
||||
const POSTFLIGHT_AGENT = ".claude/agents/postflight.md";
|
||||
const RUNS_DIR = ".claude/runs";
|
||||
|
||||
[PREFLIGHT_AGENT, POSTFLIGHT_AGENT, RUNS_DIR].forEach((p) => {
|
||||
if (!exists(p)) fatal(`Required file or directory missing: ${p}`);
|
||||
});
|
||||
|
||||
// ---------- Git Context ----------
|
||||
let git = {};
|
||||
try {
|
||||
git.user = run("git config user.name").trim();
|
||||
git.branch = run("git rev-parse --abbrev-ref HEAD").trim();
|
||||
git.commit = run("git rev-parse HEAD").trim();
|
||||
} catch {
|
||||
fatal("Git context unavailable. Are you in a git repository?");
|
||||
}
|
||||
|
||||
// ---------- Metadata ----------
|
||||
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
||||
const agentName = path.basename(agentPrompt, ".md");
|
||||
const runId = `${timestamp}-${agentName}-${git.user.replace(/\s+/g, "_")}`;
|
||||
|
||||
console.log(`🧠 Claude Safe Run`);
|
||||
console.log(`- Agent: ${agentName}`);
|
||||
console.log(`- Author: ${git.user}`);
|
||||
console.log(`- Branch: ${git.branch}`);
|
||||
console.log(`- Commit: ${git.commit}`);
|
||||
console.log(`- Run ID: ${runId}`);
|
||||
|
||||
// ---------- Preflight ----------
|
||||
console.log("\n🔍 Running Preflight Agent...");
|
||||
const preflightOutput = run(
|
||||
`claude run --prompt ${PREFLIGHT_AGENT} --input ${agentPrompt}`
|
||||
);
|
||||
|
||||
console.log(preflightOutput);
|
||||
|
||||
if (!preflightOutput.includes("PRECHECK: PASS")) {
|
||||
fatal("Preflight check failed or unclear. Execution aborted.");
|
||||
}
|
||||
|
||||
// ---------- Run Main Agent ----------
|
||||
console.log("\n🚀 Running Main Agent...");
|
||||
execSync(`claude run --prompt ${agentPrompt}`, { stdio: "inherit" });
|
||||
|
||||
// ---------- Postflight ----------
|
||||
console.log("\n🧪 Running Postflight Agent...");
|
||||
const postflightOutput = run(
|
||||
`claude run --prompt ${POSTFLIGHT_AGENT} --input ${runId}`
|
||||
);
|
||||
|
||||
console.log(postflightOutput);
|
||||
|
||||
if (!postflightOutput.includes("POSTCHECK: PASS")) {
|
||||
fatal("Postflight validation failed. Run logs invalid or missing.");
|
||||
}
|
||||
|
||||
console.log("\n✅ Claude run completed successfully.");
|
||||
console.log(`📄 Run ID: ${runId}`);
|
||||
BIN
membership/specs/materials/企业微信截图_17706340271335.png
Normal file
BIN
membership/specs/materials/企业微信截图_17706340271335.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 410 KiB |
BIN
membership/specs/materials/服务商配置.png
Normal file
BIN
membership/specs/materials/服务商配置.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 401 KiB |
BIN
membership/specs/materials/调度日志比价.png
Normal file
BIN
membership/specs/materials/调度日志比价.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 157 KiB |
2493
membership/产品需求文档.txt
Normal file
2493
membership/产品需求文档.txt
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(netstat:*)",
|
||||
"Bash(findstr:*)",
|
||||
"Bash(ping:*)",
|
||||
"Bash(curl:*)",
|
||||
"Bash(mvn compile test-compile:*)",
|
||||
"mcp__chrome-devtools__click",
|
||||
"mcp__chrome-devtools__take_snapshot",
|
||||
"mcp__chrome-devtools__navigate_page",
|
||||
"mcp__chrome-devtools__list_network_requests",
|
||||
"mcp__chrome-devtools__get_network_request",
|
||||
"mcp__chrome-devtools__fill",
|
||||
"mcp__chrome-devtools__evaluate_script",
|
||||
"mcp__chrome-devtools__fill_form",
|
||||
"mcp__chrome-devtools__wait_for",
|
||||
"Bash(copy:*)"
|
||||
]
|
||||
}
|
||||
}
|
||||
6
training-system/.gitignore
vendored
6
training-system/.gitignore
vendored
@@ -1,6 +0,0 @@
|
||||
node_modules/
|
||||
target/
|
||||
.idea/
|
||||
.summaries/
|
||||
.claude/
|
||||
.env
|
||||
8
training-system/.idea/.gitignore
generated
vendored
8
training-system/.idea/.gitignore
generated
vendored
@@ -1,8 +0,0 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
6
training-system/.idea/misc.xml
generated
6
training-system/.idea/misc.xml
generated
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="24" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
8
training-system/.idea/modules.xml
generated
8
training-system/.idea/modules.xml
generated
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/training-system.iml" filepath="$PROJECT_DIR$/.idea/training-system.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
9
training-system/.idea/training-system.iml
generated
9
training-system/.idea/training-system.iml
generated
@@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
6
training-system/.idea/vcs.xml
generated
6
training-system/.idea/vcs.xml
generated
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -1,28 +0,0 @@
|
||||
# 会话摘要
|
||||
|
||||
| 项目 | 时间 | 任务 | 需求ID |
|
||||
|------|------|------|--------|
|
||||
| training-system | 2026-01-08 16:34 | 会话摘要 | - |
|
||||
|
||||
## 交互记录
|
||||
|
||||
| 序号 | 用户操作 | AI响应 | 结果 |
|
||||
|------|----------|--------|------|
|
||||
| 1 | 执行 /summary 命令 | 获取系统时间并询问需求ID | 成功 |
|
||||
|
||||
## 错误记录
|
||||
|
||||
无错误记录。
|
||||
|
||||
## 成果产出
|
||||
|
||||
- 生成本会话摘要文件
|
||||
|
||||
## 总结
|
||||
|
||||
本次会话为新开始的会话,用户直接执行了 /summary 命令生成会话摘要。
|
||||
|
||||
## 效率评估
|
||||
|
||||
**实际用时**: 1分钟
|
||||
**应耗人工**: 3分钟
|
||||
@@ -1,50 +0,0 @@
|
||||
# 会话摘要
|
||||
|
||||
| 项目 | 时间 | 任务 | 需求ID |
|
||||
|------|------|------|--------|
|
||||
| training-system | 2026-01-08 17:21 | 后端服务及前端页面开发 | - |
|
||||
|
||||
## 交互记录
|
||||
|
||||
| 序号 | 用户操作 | AI响应 | 结果 |
|
||||
|------|----------|--------|------|
|
||||
| 1 | 继续上一会话开发任务 | 读取已完成的DTO/VO文件,继续开发阶段四培训计划模块 | 成功 |
|
||||
| 2 | - | 创建TrainingPlanService接口和PlanProgressService接口 | 成功 |
|
||||
| 3 | - | 创建PlanProgressServiceImpl实现类 | 成功 |
|
||||
| 4 | - | 创建TrainingPlanServiceImpl实现类 | 成功 |
|
||||
| 5 | - | 创建TrainingPlanController控制器 | 成功 |
|
||||
| 6 | - | 开始阶段五前端页面开发,检查现有页面文件 | 成功 |
|
||||
| 7 | - | 创建system/org.html组织架构页面 | 成功 |
|
||||
| 8 | - | 创建system/user.html员工管理页面 | 成功 |
|
||||
| 9 | - | 创建knowledge/category.html知识分类页面 | 成功 |
|
||||
| 10 | - | 创建knowledge/list.html知识列表页面 | 成功 |
|
||||
| 11 | - | 创建exam/question-category.html题库分类页面 | 成功 |
|
||||
|
||||
## 错误记录
|
||||
|
||||
无错误发生
|
||||
|
||||
## 成果产出
|
||||
|
||||
### 后端服务层(阶段四)
|
||||
- `TrainingPlanService.java` - 培训计划服务接口
|
||||
- `PlanProgressService.java` - 学习进度服务接口
|
||||
- `TrainingPlanServiceImpl.java` - 培训计划服务实现(含CRUD、发布、结束、学员计划查询)
|
||||
- `PlanProgressServiceImpl.java` - 学习进度服务实现(含知识完成标记、进度计算)
|
||||
- `TrainingPlanController.java` - 培训计划控制器(含管理端和学员端接口)
|
||||
|
||||
### 前端页面(阶段五进行中)
|
||||
- `templates/system/org.html` - 组织架构管理页面(树形结构+详情展示+CRUD弹窗)
|
||||
- `templates/system/user.html` - 员工管理页面(列表+筛选+新增编辑+密码重置)
|
||||
- `templates/knowledge/category.html` - 知识分类页面(树形结构+表单编辑)
|
||||
- `templates/knowledge/list.html` - 知识列表页面(列表+上传+状态管理)
|
||||
- `templates/exam/question-category.html` - 题库分类页面(树形结构+题目数量统计)
|
||||
|
||||
## 总结
|
||||
|
||||
本次会话完成了阶段四培训计划模块的全部后端开发,包括培训计划的创建、编辑、删除、发布、结束,以及学员的培训计划查看和学习进度跟踪功能。同时开始了阶段五前端页面开发,已完成组织架构、员工管理、知识分类、知识列表、题库分类共5个核心管理页面。前端页面采用纯HTML+CSS+JS方案,通过AJAX与后端API交互,实现了完整的CRUD操作界面。
|
||||
|
||||
## 效率评估
|
||||
|
||||
**实际用时**: 25分钟
|
||||
**应耗人工**: 480分钟
|
||||
@@ -1,55 +0,0 @@
|
||||
# 会话摘要
|
||||
|
||||
| 项目 | 时间 | 任务 | 需求ID |
|
||||
|------|------|------|--------|
|
||||
| training-system | 2026-01-08 19:47 | 登录功能测试 | - |
|
||||
|
||||
## 交互记录
|
||||
|
||||
| 序号 | 用户操作 | AI响应 | 结果 |
|
||||
|------|---------|--------|------|
|
||||
| 1 | 请求测试登录功能 | 创建JwtUtilsTest、AuthServiceTest、AuthControllerTest | 41个测试用例全部通过 |
|
||||
| 2 | 询问如何运行项目 | 提供项目运行步骤和配置说明 | 用户成功启动项目 |
|
||||
| 3 | 登录页面404错误 | 分析原因:HTML在templates目录而非static目录 | 将HTML文件移至static目录,问题解决 |
|
||||
| 4 | admin/admin登录失败 | 检查SQL初始化脚本,发现密码应为admin123 | 告知用户正确密码 |
|
||||
| 5 | 请求做登录功能单元测试 | 创建PasswordEncoderTest和LoginIntegrationTest | 发现数据库密码哈希错误并修复 |
|
||||
|
||||
## 错误记录
|
||||
|
||||
| 错误类型 | 错误描述 | 解决方案 |
|
||||
|---------|---------|---------|
|
||||
| 404错误 | 登录页面无法访问 | HTML文件从templates移至static目录 |
|
||||
| 密码错误 | admin用户登录失败 | SQL脚本中BCrypt哈希错误,生成新的有效哈希并更新 |
|
||||
| JWT测试失败 | 同用户同秒生成Token相同 | 测试延迟从10ms改为1100ms |
|
||||
|
||||
## 成果产出
|
||||
|
||||
### 测试文件
|
||||
1. `src/test/java/com/sino/training/common/utils/JwtUtilsTest.java` - 19个测试用例
|
||||
2. `src/test/java/com/sino/training/module/auth/service/AuthServiceTest.java` - 11个测试用例
|
||||
3. `src/test/java/com/sino/training/module/auth/controller/AuthControllerTest.java` - 11个测试用例
|
||||
4. `src/test/java/com/sino/training/module/auth/PasswordEncoderTest.java` - 4个测试用例
|
||||
5. `src/test/java/com/sino/training/module/auth/LoginIntegrationTest.java` - 11个测试用例
|
||||
|
||||
### 文档
|
||||
- `docs/测试报告-登录模块.md` - 完整测试报告
|
||||
|
||||
### 修复
|
||||
- 修复SQL初始化脚本中admin用户的密码哈希
|
||||
- 将前端HTML文件移至static目录
|
||||
|
||||
## 总结
|
||||
|
||||
完成了登录模块的全面测试工作,包括:
|
||||
1. 后端单元测试(JwtUtils、AuthService、AuthController)共41个用例全部通过
|
||||
2. 发现并修复登录页面404问题(HTML文件位置错误)
|
||||
3. 发现并修复数据库密码哈希错误问题
|
||||
4. 创建密码编码验证测试和登录集成测试
|
||||
5. 生成完整测试报告
|
||||
|
||||
用户需执行SQL更新数据库密码后,使用admin/admin123登录。
|
||||
|
||||
## 效率评估
|
||||
|
||||
**实际用时**: 45分钟
|
||||
**应耗人工**: 240分钟
|
||||
@@ -1,48 +0,0 @@
|
||||
# 会话摘要
|
||||
|
||||
| 项目 | 时间 | 任务 | 需求ID |
|
||||
|------|------|------|--------|
|
||||
| training-system | 2026-01-09 18:06 | 员工管理复测及漏测分析 | - |
|
||||
|
||||
## 交互记录
|
||||
|
||||
| 序号 | 用户操作 | AI响应 | 结果 |
|
||||
|------|---------|--------|------|
|
||||
| 1 | 要求对员工管理模块进行复测 | 获取Token并验证3个缺陷修复情况 | BUG-USER-001通过、BUG-USER-002失败、BUG-USER-003通过 |
|
||||
| 2 | 反馈重置密码和编辑状态功能问题 | 测试重置密码功能 | 功能正常,新密码可登录 |
|
||||
| 3 | 继续测试编辑状态功能 | 测试专用disable接口和编辑接口 | 发现编辑接口无法修改状态 |
|
||||
| 4 | 要求确认是否前端问题 | 分析前端代码user.html | 确认前端正确传递status字段 |
|
||||
| 5 | 继续验证后端问题 | 检查UserDTO和UserServiceImpl | 确认后端DTO缺少status字段 |
|
||||
| 6 | 要求分析漏测原因 | 分析前两次测试记录 | 归纳出6大漏测原因 |
|
||||
| 7 | 要求将分析归纳到LLR.md | 更新docs/LLR.md文件 | 添加漏测分析记录 |
|
||||
|
||||
## 错误记录
|
||||
|
||||
| 错误类型 | 描述 | 解决方案 |
|
||||
|---------|------|---------|
|
||||
| 后端Bug | UserDTO缺少status字段,updateUser()未处理状态 | 需在DTO添加status字段并在Service中处理 |
|
||||
| 后端Bug | JWT Token未包含departmentId导致部门隔离失效 | 需修改JwtUtils.generateToken()添加departmentId |
|
||||
|
||||
## 成果产出
|
||||
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
| docs/test-reports/RegressionReport_1.3_UserManagement.md | 第一版复测报告 |
|
||||
| docs/test-reports/RegressionReport_1.3_UserManagement_V2.md | 深度测试后的V2复测报告 |
|
||||
| docs/LLR.md | 更新漏测原因分析记录 |
|
||||
|
||||
## 总结
|
||||
|
||||
本次会话对员工管理模块进行了三轮测试:
|
||||
1. **第一轮复测**:验证原有3个缺陷,2个通过1个失败
|
||||
2. **第二轮深度测试**:根据用户反馈发现新Bug(编辑接口无法修改状态)
|
||||
3. **第三轮分析**:确认问题为后端Bug(非前端问题),并归纳漏测原因
|
||||
|
||||
核心发现:
|
||||
- BUG-USER-004:编辑接口无法修改状态(后端UserDTO缺少status字段)
|
||||
- 漏测根因:"只测了能用的接口,没测用户实际用的接口"
|
||||
|
||||
## 效率评估
|
||||
|
||||
**实际用时**: 45分钟
|
||||
**应耗人工**: 180分钟
|
||||
@@ -1,57 +0,0 @@
|
||||
# 会话摘要
|
||||
|
||||
| 项目 | 时间 | 任务 | 需求ID |
|
||||
|------|------|------|--------|
|
||||
| training-system | 2026-01-09 18:08 | 员工管理模块缺陷修复 | - |
|
||||
|
||||
## 交互记录
|
||||
|
||||
| 序号 | 用户操作 | AI响应 | 结果 |
|
||||
|------|---------|--------|------|
|
||||
| 1 | 要求根据测试报告给出修复建议 | 分析测试报告,识别3个缺陷并给出修复方案 | 完成缺陷分析 |
|
||||
| 2 | 确认查看相关文件 | 查看UserController、UserServiceImpl、AuthInterceptor等文件 | 给出详细修复方案 |
|
||||
| 3 | 要求按方案修改代码 | 创建RequireRole注解、RoleInterceptor拦截器,修改WebMvcConfig、UserController、UserServiceImpl、ResultCode | P0/P1/P2缺陷修复完成 |
|
||||
| 4 | 分析员工禁用状态不生效问题 | 分析AuthInterceptor未校验用户状态,给出修复方案 | 完成分析(未修改代码) |
|
||||
| 5 | 分析BUG-USER-004问题 | 分析UserDTO缺少status字段、updateUser未处理状态更新 | 完成根因分析 |
|
||||
| 6 | 要求修复BUG-USER-004 | 修改UserDTO添加status字段,修改updateUser添加状态更新逻辑 | 修复完成 |
|
||||
|
||||
## 错误记录
|
||||
|
||||
| 错误类型 | 描述 | 解决方案 |
|
||||
|---------|------|---------|
|
||||
| 无 | - | - |
|
||||
|
||||
## 成果产出
|
||||
|
||||
### 新建文件
|
||||
1. `src/main/java/com/sino/training/common/annotation/RequireRole.java` - 角色权限注解
|
||||
2. `src/main/java/com/sino/training/common/interceptor/RoleInterceptor.java` - 角色权限拦截器
|
||||
|
||||
### 修改文件
|
||||
1. `WebMvcConfig.java` - 注册RoleInterceptor
|
||||
2. `UserController.java` - 添加@RequireRole注解
|
||||
3. `UserServiceImpl.java` - 添加部门数据隔离逻辑、手机号唯一性校验、状态更新逻辑
|
||||
4. `ResultCode.java` - 新增PHONE_EXISTS错误码
|
||||
5. `UserDTO.java` - 新增status字段
|
||||
|
||||
### 缺陷修复情况
|
||||
| 缺陷编号 | 描述 | 状态 |
|
||||
|---------|------|------|
|
||||
| BUG-USER-001 | 手机号未做唯一性校验 | ✅ 已修复 |
|
||||
| BUG-USER-002 | 讲师未实现部门数据隔离 | ⚠️ Service层已添加,需修复JWT |
|
||||
| BUG-USER-003 | 学员可访问员工管理接口 | ✅ 已修复 |
|
||||
| BUG-USER-004 | 编辑接口无法修改状态 | ✅ 已修复 |
|
||||
|
||||
## 总结
|
||||
|
||||
本次会话完成了员工管理模块的缺陷分析和修复工作:
|
||||
1. 实现了基于注解的角色权限控制机制(@RequireRole + RoleInterceptor)
|
||||
2. 在Service层添加了部门数据隔离逻辑
|
||||
3. 添加了手机号唯一性校验
|
||||
4. 修复了编辑接口无法修改状态的问题
|
||||
5. 分析了禁用状态不生效的根因(AuthInterceptor未校验用户状态),待后续修复
|
||||
|
||||
## 效率评估
|
||||
|
||||
**实际用时**: 45分钟
|
||||
**应耗人工**: 180分钟
|
||||
@@ -1,55 +0,0 @@
|
||||
# 会话摘要
|
||||
|
||||
| 项目 | 时间 | 任务 | 需求ID |
|
||||
|------|------|------|--------|
|
||||
| training-system | 2026-01-12 19:53 | 前端BUG修复 | - |
|
||||
|
||||
## 交互记录
|
||||
|
||||
| 序号 | 用户操作 | AI响应 | 结果 |
|
||||
|------|----------|--------|------|
|
||||
| 1 | 题目编辑时选项和答案不显示 | 分析发现前端JSON.parse多余且setOptions未正确读取opt.value | 修复question-edit.html两处代码 |
|
||||
| 2 | 组卷方式题目不显示 | 分析发现result.data.list应为result.data.records | 修复paper-edit.html两处代码 |
|
||||
| 3 | 新增考卷totalScore未传后端 | 分析发现savePaper函数缺少totalScore字段 | 添加totalScore计算并传递 |
|
||||
| 4 | 创建试卷报"所属部门"不存在 | 分析发现PaperServiceImpl.createPaper未实现部门ID逻辑 | 添加与QuestionServiceImpl相同的部门ID处理逻辑 |
|
||||
| 5 | 试卷管理列表不显示 | 分析发现pageData.list应为pageData.records | 修复paper.html一处代码 |
|
||||
| 6 | 编辑试卷不显示信息 | 分析发现q.content应为q.question.content | 修复paper-edit.html两处字段路径 |
|
||||
| 7 | 试卷发布功能不可用 | 分析发现前端用POST但后端用PUT | 修复paper.html请求方法 |
|
||||
| 8 | 试卷复制功能不可用 | 分析发现后端未实现copy接口 | 删除前端复制按钮和函数 |
|
||||
| 9 | 试卷预览不显示内容 | 分析发现多处字段路径错误 | 修复paper-preview.html六处代码 |
|
||||
|
||||
## 错误记录
|
||||
|
||||
| 错误类型 | 文件 | 问题描述 | 解决方案 |
|
||||
|----------|------|----------|----------|
|
||||
| 数据格式不匹配 | question-edit.html | 后端返回options是对象数组,前端多余JSON.parse | 移除JSON.parse,读取opt.value |
|
||||
| 字段名错误 | paper-edit.html, paper.html | 使用data.list但后端返回data.records | 改为records |
|
||||
| 缺少字段 | paper-edit.html | savePaper未传totalScore | 添加totalScore计算 |
|
||||
| 业务逻辑缺失 | PaperServiceImpl.java | createPaper未按角色处理departmentId | 添加UserContext判断逻辑 |
|
||||
| 嵌套对象访问错误 | paper-edit.html, paper-preview.html | 直接访问q.content但实际是q.question.content | 修正字段路径 |
|
||||
| HTTP方法不匹配 | paper.html | 前端POST但后端PUT | 改为put方法 |
|
||||
| 接口未实现 | paper.html | 复制功能后端未实现 | 删除前端复制功能 |
|
||||
|
||||
## 成果产出
|
||||
|
||||
| 文件 | 修改类型 | 说明 |
|
||||
|------|----------|------|
|
||||
| question-edit.html | 修复 | 移除多余JSON.parse,正确读取选项值 |
|
||||
| paper-edit.html | 修复 | records字段、totalScore、嵌套对象访问 |
|
||||
| paper.html | 修复 | records字段、PUT方法、删除复制功能 |
|
||||
| paper-preview.html | 修复 | 6处嵌套对象字段路径修正 |
|
||||
| PaperServiceImpl.java | 修复 | createPaper添加部门ID逻辑 |
|
||||
|
||||
## 总结
|
||||
|
||||
本次会话修复了9个前端BUG,主要问题集中在:
|
||||
1. **数据格式不匹配**:后端返回的分页数据用records字段,前端错误使用list
|
||||
2. **嵌套对象访问**:试卷题目数据嵌套在question对象中,前端直接访问导致undefined
|
||||
3. **JSON解析问题**:后端已将JSON字符串解析为对象,前端多余的JSON.parse导致错误
|
||||
4. **HTTP方法不一致**:发布接口后端用PUT,前端用POST
|
||||
5. **后端逻辑缺失**:PaperServiceImpl未按CLAUDE.md要求处理departmentId
|
||||
|
||||
## 效率评估
|
||||
|
||||
**实际用时**: 25分钟
|
||||
**应耗人工**: 120分钟
|
||||
@@ -1,44 +0,0 @@
|
||||
# 会话摘要
|
||||
|
||||
| 项目 | 时间 | 任务 | 需求ID |
|
||||
|------|------|------|--------|
|
||||
| training-system | 2026-01-13 11:38 | 参与人员保存BUG修复 | - |
|
||||
|
||||
## 交互记录
|
||||
|
||||
| 序号 | 操作类型 | 描述 | 结果 |
|
||||
|------|----------|------|------|
|
||||
| 1 | 问题复现 | 用户反馈"发布考试选择了参与人员,保存后参与人员丢失" | 确认问题存在 |
|
||||
| 2 | API验证 | 调用 `/api/exam/3` 检查数据库数据 | 数据已正确保存(targets数组包含2人) |
|
||||
| 3 | 前端检查 | 编辑页面显示"已选择0人" | 确认是前端显示问题 |
|
||||
| 4 | 代码分析 | 阅读 edit.html 中 loadExam 函数 | 发现字段名不匹配和异步顺序问题 |
|
||||
| 5 | 修复1 | 修正字段名 participants → targets, userId → targetId | 完成 |
|
||||
| 6 | 修复2 | 添加 await 确保异步执行顺序正确 | 完成 |
|
||||
| 7 | 文件同步 | 复制修改后的文件到 target 目录 | 完成 |
|
||||
| 8 | 验证修复 | 刷新页面检查参与人员显示 | 正确显示"已选择2人" |
|
||||
|
||||
## 错误记录
|
||||
|
||||
| 错误类型 | 位置 | 原因 | 解决方案 |
|
||||
|----------|------|------|----------|
|
||||
| 字段名不匹配 | edit.html:294-299 | 代码使用 `exam.participants`,API返回 `exam.targets` | 修改为 `exam.targets` 和 `targetId` |
|
||||
| 异步执行顺序 | edit.html:149-160 | loadUsers()和loadExam()同时执行无await | 添加 await 保证执行顺序 |
|
||||
|
||||
## 成果产出
|
||||
|
||||
| 文件 | 修改内容 |
|
||||
|------|----------|
|
||||
| src/main/resources/static/exam/edit.html | 1. 修复 loadExam 中参与人员字段名(participants→targets, userId→targetId)<br>2. 修复 DOMContentLoaded 中异步执行顺序(添加await) |
|
||||
|
||||
## 总结
|
||||
|
||||
用户反馈考试参与人员保存后丢失的问题。经测试定位,数据已正确保存到数据库,问题在于前端编辑页面加载时:
|
||||
1. 使用了错误的字段名(participants 而非 targets)
|
||||
2. 异步函数执行顺序不正确导致渲染时机问题
|
||||
|
||||
通过修正字段名和异步执行顺序,问题已修复并验证通过。
|
||||
|
||||
## 效率评估
|
||||
|
||||
**实际用时**: 15分钟
|
||||
**应耗人工**: 60分钟
|
||||
@@ -1,43 +0,0 @@
|
||||
# Java Maven 项目 AI 开发最高准则(必须遵守)
|
||||
|
||||
## 一、技术栈(不可更改)
|
||||
- 后端语言:Java
|
||||
- JDK:17
|
||||
- 构建工具:Maven
|
||||
- 后端框架:Spring Boot 3.1.2
|
||||
- 前端框架: HTML + CSS + Bootstrap
|
||||
- ORM:MyBatis Plus
|
||||
- 数据库:MySQL 8
|
||||
- API 文档:Springdoc OpenAPI
|
||||
- 序列化:Jackson
|
||||
- 安全框架:Spring Security(用于BCrypt密码加密)
|
||||
- 认证方式:JWT Token(使用 java-jwt)
|
||||
|
||||
## 二、强制约束(最高优先级)
|
||||
- ❌ 不允许引入未声明的新技术栈
|
||||
- ❌ 不允许更换框架或大版本
|
||||
- ❌ 不允许使用过时 API
|
||||
- ❌ 不允许在本项目任何位置使用 Python(包括代码、脚本、Notebook 等)
|
||||
|
||||
## 三、编码规范
|
||||
- 遵循《阿里 Java 开发规范》
|
||||
- 必须使用 Lombok
|
||||
- Controller(RESTful) 层不写业务逻辑
|
||||
- Service + Impl 负责业务
|
||||
- Mapper 只做数据访问
|
||||
|
||||
## 四、通用要求
|
||||
- 所有代码必须:
|
||||
- 可读
|
||||
- 可维护
|
||||
- 有必要注释
|
||||
- 不生成 Demo / 示例 / 伪代码
|
||||
- 生成代码必须可直接运行
|
||||
|
||||
## 五、当需求与以上规则冲突时
|
||||
👉 **以本文件为最高准则,拒绝执行冲突需求**
|
||||
|
||||
## 六、业务逻辑要求
|
||||
- 实现部门ID逻辑:
|
||||
- ADMIN:使用前端传入的 departmentId,若为空则报错
|
||||
- 非ADMIN:强制使用当前登录用户的 departmentId,忽略前端传值
|
||||
@@ -1,159 +0,0 @@
|
||||
# 道路救援企业培训系统
|
||||
|
||||
> 版本:V1.0.1 | 基于 Spring Boot 3.1.2
|
||||
|
||||
为道路救援企业打造的一站式内部培训平台,通过知识沉淀、在线考核、培训管理三大核心能力,提升员工专业技能水平和服务标准化程度。
|
||||
|
||||
---
|
||||
|
||||
## 技术栈
|
||||
|
||||
| 类别 | 技术 | 版本 |
|
||||
|-----|------|------|
|
||||
| 语言 | Java | 17 |
|
||||
| 构建 | Maven | 3.6+ |
|
||||
| 框架 | Spring Boot | 3.1.2 |
|
||||
| ORM | MyBatis Plus | 3.5.3.1 |
|
||||
| 数据库 | MySQL | 8.0+ |
|
||||
| 认证 | JWT (java-jwt) | 4.4.0 |
|
||||
| API文档 | Springdoc OpenAPI | 2.2.0 |
|
||||
| 工具库 | Lombok、Hutool | - |
|
||||
|
||||
---
|
||||
|
||||
## 功能模块
|
||||
|
||||
| 模块 | 功能说明 |
|
||||
|-----|---------|
|
||||
| **人员管理** | 组织架构(中心→部门→小组)、员工管理、角色权限 |
|
||||
| **知识库** | 文档/视频上传、在线预览、分类管理、状态流转 |
|
||||
| **考题管理** | 单选/多选/判断题、题目解析、题库分类 |
|
||||
| **试卷管理** | 手动组卷、自动组卷、试卷预览 |
|
||||
| **考试管理** | 发布考试、指定对象、在线答题、自动阅卷 |
|
||||
| **培训计划** | 关联多个知识+多个考试、分配学员、进度跟踪 |
|
||||
|
||||
---
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 环境要求
|
||||
|
||||
- JDK 17+
|
||||
- Maven 3.6+
|
||||
- MySQL 8.0+
|
||||
|
||||
### 1. 克隆项目
|
||||
|
||||
```bash
|
||||
git clone <repository-url>
|
||||
cd training-system
|
||||
```
|
||||
|
||||
### 2. 初始化数据库
|
||||
|
||||
```sql
|
||||
CREATE DATABASE training_system DEFAULT CHARACTER SET utf8mb4;
|
||||
USE training_system;
|
||||
SOURCE sql/init.sql;
|
||||
```
|
||||
|
||||
### 3. 修改配置
|
||||
|
||||
编辑 `src/main/resources/application.yml`,配置数据库连接:
|
||||
|
||||
```yaml
|
||||
spring:
|
||||
datasource:
|
||||
url: jdbc:mysql://localhost:3306/training_system
|
||||
username: root
|
||||
password: 你的密码
|
||||
```
|
||||
|
||||
### 4. 启动应用
|
||||
|
||||
```bash
|
||||
mvn spring-boot:run
|
||||
```
|
||||
|
||||
### 5. 访问系统
|
||||
|
||||
- 系统地址:http://localhost:8080
|
||||
- API文档:http://localhost:8080/swagger-ui.html
|
||||
- 默认账号:`admin` / `123456`
|
||||
|
||||
---
|
||||
|
||||
## 生产部署
|
||||
|
||||
### 打包
|
||||
|
||||
```bash
|
||||
mvn clean package -DskipTests
|
||||
```
|
||||
|
||||
生成文件:`target/training-system-1.0.0.jar`
|
||||
|
||||
### Linux部署
|
||||
|
||||
```bash
|
||||
# 上传JAR包和SQL脚本到服务器
|
||||
scp target/training-system-1.0.0.jar user@server:/opt/training/
|
||||
scp sql/init.sql user@server:/opt/training/
|
||||
|
||||
# 创建生产配置 /opt/training/application-prod.yml
|
||||
# 启动应用
|
||||
java -jar training-system-1.0.0.jar --spring.profiles.active=prod
|
||||
```
|
||||
|
||||
详细部署指南见 [部署文档](docs/Deploy.md)
|
||||
|
||||
---
|
||||
|
||||
## 项目结构
|
||||
|
||||
```
|
||||
training-system/
|
||||
├── src/main/java/com/sino/training/
|
||||
│ ├── common/ # 公共模块(配置、异常、工具类)
|
||||
│ ├── module/
|
||||
│ │ ├── system/ # 系统模块(用户、部门、小组)
|
||||
│ │ ├── knowledge/ # 知识库模块
|
||||
│ │ ├── exam/ # 考试模块(题目、试卷、考试)
|
||||
│ │ └── training/ # 培训计划模块
|
||||
│ └── TrainingApplication.java
|
||||
├── src/main/resources/
|
||||
│ ├── static/ # 前端静态资源
|
||||
│ ├── application.yml # 配置文件
|
||||
│ └── mapper/ # MyBatis XML
|
||||
├── sql/
|
||||
│ └── init.sql # 数据库初始化脚本
|
||||
├── docs/ # 项目文档
|
||||
└── pom.xml
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 编码规范
|
||||
|
||||
- 遵循《阿里 Java 开发规范》
|
||||
- Controller 层不写业务逻辑
|
||||
- Service + Impl 负责业务处理
|
||||
- Mapper 只做数据访问
|
||||
- 必须使用 Lombok 简化代码
|
||||
|
||||
---
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [产品需求文档 (PRD)](docs/PRD.md)
|
||||
- [低层级需求文档 (LLR)](docs/LLR.md)
|
||||
- [测试计划](docs/TestPlan.md)
|
||||
|
||||
---
|
||||
|
||||
## 版本记录
|
||||
|
||||
| 版本 | 日期 | 更新内容 |
|
||||
|-----|------|---------|
|
||||
| V1.0.1 | 2026-01-13 | 培训计划支持多考试任务 |
|
||||
| V1.0.0 | 2026-01-08 | 初始版本发布 |
|
||||
@@ -1,31 +0,0 @@
|
||||
# Role: Architect Agent(系统架构师)
|
||||
|
||||
## 你的身份
|
||||
你是系统架构师,负责整体技术设计。
|
||||
|
||||
## 你的目标
|
||||
- 设计清晰、可扩展的系统架构
|
||||
- 降低长期复杂度
|
||||
|
||||
## 你可以做的事
|
||||
- 技术选型
|
||||
- 系统拆分
|
||||
- 定义模块边界和接口规范
|
||||
|
||||
## 你不能做的事
|
||||
- 不实现具体业务逻辑
|
||||
- 不写完整功能代码
|
||||
|
||||
## 输入
|
||||
- requirements.md
|
||||
- Supervisor 指令
|
||||
|
||||
## 输出
|
||||
- architecture.md
|
||||
- 目录结构建议
|
||||
- API 设计说明
|
||||
|
||||
## 工作规则
|
||||
- 设计必须支持未来扩展
|
||||
- 避免过度设计
|
||||
- 明确模块职责
|
||||
@@ -1,30 +0,0 @@
|
||||
# Role: Backend Agent(后端工程师)
|
||||
|
||||
## 你的身份
|
||||
你是后端工程师,只负责实现后端业务逻辑。
|
||||
|
||||
## 你的目标
|
||||
- 按架构和需求实现稳定、可测试的代码
|
||||
|
||||
## 你可以做的事
|
||||
- 编写业务代码
|
||||
- 实现 API
|
||||
- 编写必要的单元测试
|
||||
|
||||
## 你不能做的事
|
||||
- 不更改架构设计
|
||||
- 不新增未经批准的功能
|
||||
|
||||
## 输入
|
||||
- architecture.md
|
||||
- requirements.md
|
||||
- Supervisor 指令
|
||||
|
||||
## 输出
|
||||
- 后端源码
|
||||
- 测试代码
|
||||
|
||||
## 工作规则
|
||||
- 代码必须可读
|
||||
- 必须遵循项目规范
|
||||
- 所有假设必须说明
|
||||
@@ -1,20 +0,0 @@
|
||||
# Role: DevOps Agent(部署与运维)
|
||||
|
||||
## 你的身份
|
||||
你负责系统交付与运行环境。
|
||||
|
||||
## 你的目标
|
||||
- 系统可部署、可回滚、可监控
|
||||
|
||||
## 输入
|
||||
- 架构设计
|
||||
- 运行要求
|
||||
|
||||
## 输出
|
||||
- 部署方案
|
||||
- CI/CD 建议
|
||||
- 环境说明
|
||||
|
||||
## 工作规则
|
||||
- 优先稳定性
|
||||
- 避免复杂配置
|
||||
@@ -1,28 +0,0 @@
|
||||
# Role: Doc Agent(文档工程师)
|
||||
|
||||
## 你的身份
|
||||
你是项目文档负责人。
|
||||
|
||||
## 你的目标
|
||||
- 让人和 AI 都能快速理解项目
|
||||
|
||||
## 你可以做的事
|
||||
- 编写 README
|
||||
- 编写使用说明和开发规范
|
||||
|
||||
## 你不能做的事
|
||||
- 不修改代码
|
||||
- 不解释未实现的功能
|
||||
|
||||
## 输入
|
||||
- 最终代码
|
||||
- 架构与需求文档
|
||||
|
||||
## 输出
|
||||
- README.md
|
||||
- 使用与维护说明
|
||||
|
||||
## 工作规则
|
||||
- 文档必须准确
|
||||
- 避免废话
|
||||
- 假设读者是新加入的开发者或 AI
|
||||
@@ -1,28 +0,0 @@
|
||||
# Role: Frontend Agent(前端工程师)
|
||||
|
||||
## 你的身份
|
||||
你是前端工程师,负责 UI 与交互实现。
|
||||
|
||||
## 你的目标
|
||||
- 提供清晰、一致的用户体验
|
||||
|
||||
## 你可以做的事
|
||||
- 编写前端代码
|
||||
- 实现页面和交互逻辑
|
||||
|
||||
## 你不能做的事
|
||||
- 不改后端接口定义
|
||||
- 不引入未确认的 UI 框架
|
||||
|
||||
## 输入
|
||||
- architecture.md
|
||||
- requirements.md
|
||||
- API 文档
|
||||
|
||||
## 输出
|
||||
- 前端源码
|
||||
- 简要交互说明
|
||||
|
||||
## 工作规则
|
||||
- 优先可维护性
|
||||
- 不做“看起来更酷”的无关改动
|
||||
@@ -1,32 +0,0 @@
|
||||
# Role: Product Manager Agent(产品经理)
|
||||
|
||||
## 你的身份
|
||||
你是负责需求分析和功能拆解的产品经理。
|
||||
|
||||
## 你的目标
|
||||
- 将模糊需求转化为清晰、可执行的需求
|
||||
- 定义验收标准
|
||||
|
||||
## 你可以做的事
|
||||
- 追问需求细节
|
||||
- 编写用户故事(User Story)
|
||||
- 定义功能边界和非功能需求
|
||||
|
||||
## 你不能做的事
|
||||
- 不做技术选型
|
||||
- 不设计系统架构
|
||||
- 不写代码
|
||||
|
||||
## 输入
|
||||
- 用户原始需求
|
||||
- Supervisor 的指令
|
||||
|
||||
## 输出
|
||||
- requirements.md
|
||||
- 功能清单
|
||||
- 验收标准(Acceptance Criteria)
|
||||
|
||||
## 工作规则
|
||||
- 所有需求必须可测试
|
||||
- 明确“不做什么”
|
||||
- 避免模糊词(如:尽量、可能)
|
||||
@@ -1,29 +0,0 @@
|
||||
# Role: QA / Tester Agent(测试工程师)
|
||||
|
||||
## 你的身份
|
||||
你是专门负责找问题的人。
|
||||
|
||||
## 你的目标
|
||||
- 尽可能暴露缺陷和风险
|
||||
|
||||
## 你可以做的事
|
||||
- 设计测试用例
|
||||
- 提出反例和异常场景
|
||||
- 发现逻辑漏洞
|
||||
|
||||
## 你不能做的事
|
||||
- 不修复代码
|
||||
- 不修改需求
|
||||
|
||||
## 输入
|
||||
- 功能说明
|
||||
- 源码或接口定义
|
||||
|
||||
## 输出
|
||||
- 测试用例
|
||||
- Bug 列表
|
||||
- 风险说明
|
||||
|
||||
## 工作规则
|
||||
- 假设开发会犯错
|
||||
- 重点关注边界条件
|
||||
@@ -1,29 +0,0 @@
|
||||
# Role: Security Agent(安全审计)
|
||||
|
||||
## 你的身份
|
||||
你是安全专家。
|
||||
|
||||
## 你的目标
|
||||
- 发现安全漏洞和设计风险
|
||||
|
||||
## 你可以做的事
|
||||
- 审查代码和接口
|
||||
- 指出潜在攻击面
|
||||
- 提供修复建议
|
||||
|
||||
## 你不能做的事
|
||||
- 不实现功能
|
||||
- 不更改业务逻辑
|
||||
|
||||
## 输入
|
||||
- 架构设计
|
||||
- 代码或接口文档
|
||||
|
||||
## 输出
|
||||
- 安全问题清单
|
||||
- 风险等级
|
||||
- 修复建议
|
||||
|
||||
## 工作规则
|
||||
- 默认系统处于敌对环境
|
||||
- 不忽略“看起来不太可能”的问题
|
||||
@@ -1,34 +0,0 @@
|
||||
# Role: Supervisor Agent(项目总负责人)
|
||||
|
||||
## 你的身份
|
||||
你是整个项目的总负责人,负责项目最终质量与方向。
|
||||
你不写具体业务代码。
|
||||
|
||||
## 你的目标
|
||||
- 确保项目符合需求、可维护、可扩展
|
||||
- 确保每个 Agent 各司其职
|
||||
- 防止范围蔓延和架构混乱
|
||||
|
||||
## 你可以做的事
|
||||
- 拆分项目阶段
|
||||
- 指派 Agent 执行任务
|
||||
- 审核、拒绝或要求返工任何 Agent 的输出
|
||||
- 汇总各 Agent 结果
|
||||
|
||||
## 你不能做的事
|
||||
- 不直接编写业务代码
|
||||
- 不绕过其他 Agent 直接下结论
|
||||
|
||||
## 输入
|
||||
- 用户需求
|
||||
- 各 Agent 的输出文档
|
||||
|
||||
## 输出
|
||||
- 决策说明
|
||||
- 是否通过 / 是否返工
|
||||
- 下一步执行指令
|
||||
|
||||
## 工作规则
|
||||
- 若信息不足,必须要求澄清
|
||||
- 优先考虑长期维护而非短期实现
|
||||
- 所有结论必须有理由
|
||||
@@ -1,89 +0,0 @@
|
||||
# LLR (Lessons Learned Record)
|
||||
|
||||
## 2026-01-09: 组织架构列表加载失败
|
||||
|
||||
### 问题现象
|
||||
组织架构页面列表一直显示 loading,无法加载数据。
|
||||
|
||||
### 根本原因
|
||||
`common.js` 中 `getCurrentUser()` 函数对 localStorage 数据处理不够健壮,当存储值为字符串 `"undefined"` 时,`JSON.parse("undefined")` 抛出异常,导致页面脚本中断。
|
||||
|
||||
### 经验教训
|
||||
|
||||
1. **防御性编程**:从 localStorage 读取数据时,应考虑数据可能被污染或格式异常的情况,需增加有效性校验
|
||||
2. **错误定位**:前端加载问题应先查看浏览器控制台错误信息,而非只检查网络请求
|
||||
3. **文件去重**:项目中 `static` 和 `templates` 目录下存在相同文件(如 `org.html`),应统一管理避免修改遗漏
|
||||
|
||||
---
|
||||
|
||||
## 2026-01-09: 编辑员工状态功能漏测分析
|
||||
|
||||
### 问题现象
|
||||
|
||||
员工管理模块中,用户通过前端编辑页面修改员工状态为"禁用",点击保存后提示成功,但刷新页面后状态仍为"启用"。
|
||||
|
||||
### 根本原因
|
||||
|
||||
**后端Bug**:`UserDTO` 没有定义 `status` 字段,`UserServiceImpl.updateUser()` 方法也未处理状态更新,导致前端传递的 status 字段被静默忽略。
|
||||
|
||||
### 漏测原因分析
|
||||
|
||||
#### 1. 测试路径覆盖不完整
|
||||
|
||||
系统提供了两种修改状态的方式,但只测试了一种:
|
||||
|
||||
| 路径 | 接口 | 是否测试 |
|
||||
|------|------|---------|
|
||||
| 路径1:专用接口 | `PUT /api/system/user/{id}/disable` | ✅ 已测试 |
|
||||
| 路径2:编辑接口 | `PUT /api/system/user` + status字段 | ❌ 未测试 |
|
||||
|
||||
#### 2. 接口覆盖遗漏
|
||||
|
||||
编辑接口 `PUT /api/system/user` 完全没有出现在测试用例中:
|
||||
|
||||
```
|
||||
第一轮测试覆盖:
|
||||
✅ POST /api/system/user (创建)
|
||||
❌ PUT /api/system/user (编辑 - 漏测!)
|
||||
✅ GET /api/system/user/{id} (查询)
|
||||
✅ PUT /api/system/user/{id}/enable (启用)
|
||||
✅ PUT /api/system/user/{id}/disable (禁用)
|
||||
```
|
||||
|
||||
#### 3. 未进行端到端测试
|
||||
|
||||
只做了接口级测试,没有模拟前端真实操作流程。如果从前端页面操作验证,可以直接发现问题。
|
||||
|
||||
#### 4. 字段级测试缺失
|
||||
|
||||
对编辑接口没有验证每个字段是否都能正确更新(realName、phone、role、departmentId、**status**)。
|
||||
|
||||
#### 5. 前后端契约未验证
|
||||
|
||||
没有验证前端传递的字段后端是否都能正确接收和处理。
|
||||
|
||||
#### 6. 测试思维局限
|
||||
|
||||
看到系统提供了专用的 `/enable` 和 `/disable` 接口,就主观认为"状态修改功能已覆盖",忽略了编辑接口也应该支持状态修改。
|
||||
|
||||
### 经验教训
|
||||
|
||||
1. **测试要覆盖所有接口**:不能遗漏任何CRUD接口
|
||||
2. **测试要覆盖所有路径**:同一功能的不同实现路径,每条都要测试
|
||||
3. **测试要覆盖所有字段**:对编辑接口,需建立字段覆盖矩阵
|
||||
4. **测试要端到端验证**:重要功能必须从前端页面操作验证
|
||||
5. **测试要二次确认**:不信任接口返回值,必须查询确认数据确实变化
|
||||
6. **验证前后端契约**:确保前端发送的字段后端都能正确处理
|
||||
|
||||
### 改进检查清单
|
||||
|
||||
设计和执行测试时,问自己:
|
||||
|
||||
- [ ] 这个功能有几种实现路径?都测了吗?
|
||||
- [ ] 这个接口的所有字段都验证了吗?
|
||||
- [ ] 前端实际是怎么调用的?和我测试的方式一样吗?
|
||||
- [ ] 我验证了数据确实变化了吗?还是只看了返回值?
|
||||
|
||||
### 一句话总结
|
||||
|
||||
**"只测了能用的接口,没测用户实际用的接口"**
|
||||
@@ -1,412 +0,0 @@
|
||||
# 道路救援企业培训系统 - 测试计划
|
||||
|
||||
> 版本:V1.0
|
||||
> 创建日期:2026-01-09
|
||||
> 基于:PRD V1.0 MVP版本
|
||||
|
||||
---
|
||||
|
||||
## 一、测试范围
|
||||
|
||||
根据PRD V1.0 MVP版本,测试覆盖以下6大模块:
|
||||
|
||||
| 模块 | 测试优先级 |
|
||||
|------|-----------|
|
||||
| 模块一:系统基础与人员管理 | P0 |
|
||||
| 模块二:知识库 | P0 |
|
||||
| 模块三:考题管理 | P0 |
|
||||
| 模块四:试卷管理 | P0 |
|
||||
| 模块五:考试管理 | P0 |
|
||||
| 模块六:培训计划 | P1 |
|
||||
|
||||
---
|
||||
|
||||
## 二、测试类型
|
||||
|
||||
- 2.1 功能测试
|
||||
- 2.2 接口测试(API)
|
||||
- 2.3 权限测试
|
||||
- 2.4 边界测试
|
||||
- 2.5 数据隔离测试
|
||||
- 2.6 UI/交互测试
|
||||
|
||||
---
|
||||
|
||||
## 三、详细测试用例
|
||||
|
||||
### 模块一:系统基础与人员管理
|
||||
|
||||
#### 1.1 认证登录
|
||||
|
||||
| 用例编号 | 测试项 | 预期结果 | 状态 |
|
||||
|---------|--------|---------|------|
|
||||
| AUTH-001 | 企业微信授权登录(正常流程) | 跳转企微授权,返回后获取Token,成功进入系统 | 待测 |
|
||||
| AUTH-002 | 未录入员工登录 | 提示"用户未录入,请联系管理员" | 待测 |
|
||||
| AUTH-003 | 被禁用用户登录 | 提示"账号已禁用" | 待测 |
|
||||
| AUTH-004 | Token过期访问 | 返回401,跳转登录页 | 待测 |
|
||||
| AUTH-005 | 无效Token访问 | 返回401,拒绝访问 | 待测 |
|
||||
|
||||
#### 1.2 组织架构管理
|
||||
|
||||
| 用例编号 | 测试项 | 预期结果 | 状态 |
|
||||
|---------|--------|---------|------|
|
||||
| ORG-001 | 创建中心 | 成功创建,返回中心信息 | 待测 |
|
||||
| ORG-002 | 创建部门(关联中心) | 成功创建,部门数 ≤ 8 | 待测 |
|
||||
| ORG-003 | 创建小组(关联部门) | 成功创建,小组数 ≤ 10/部门 | 待测 |
|
||||
| ORG-004 | 部门数量超过8个 | 提示"部门数量已达上限" | 待测 |
|
||||
| ORG-005 | 小组数量超过10个 | 提示"小组数量已达上限" | 待测 |
|
||||
| ORG-006 | 删除有员工的部门 | 提示"存在关联员工,无法删除" | 待测 |
|
||||
| ORG-007 | 编辑组织名称 | 成功修改 | 待测 |
|
||||
|
||||
#### 1.3 员工管理
|
||||
|
||||
| 用例编号 | 测试项 | 预期结果 | 状态 |
|
||||
|---------|--------|---------|------|
|
||||
| USER-001 | 管理员创建员工 | 成功创建,指定角色和部门 | 待测 |
|
||||
| USER-002 | 创建重复手机号员工 | 提示"手机号已存在" | 待测 |
|
||||
| USER-003 | 分配角色(ADMIN/LECTURER/STUDENT) | 角色分配成功 | 待测 |
|
||||
| USER-004 | 禁用员工 | 状态变更为DISABLED | 待测 |
|
||||
| USER-005 | 启用员工 | 状态变更为ENABLED | 待测 |
|
||||
| USER-006 | 讲师查看本部门员工 | 只能看到本部门 | 待测 |
|
||||
| USER-007 | 学员无法访问员工管理 | 返回403 | 待测 |
|
||||
|
||||
---
|
||||
|
||||
### 模块二:知识库
|
||||
|
||||
#### 2.1 知识分类
|
||||
|
||||
| 用例编号 | 测试项 | 预期结果 | 状态 |
|
||||
|---------|--------|---------|------|
|
||||
| KC-001 | 创建一级分类 | 成功创建 | 待测 |
|
||||
| KC-002 | 创建多级分类(如:安全规范 > 高速救援) | 层级关系正确 | 待测 |
|
||||
| KC-003 | 删除有知识的分类 | 提示"存在关联知识,无法删除" | 待测 |
|
||||
| KC-004 | 讲师只能管理本部门分类 | 其他部门分类不可见/不可操作 | 待测 |
|
||||
|
||||
#### 2.2 知识文档管理
|
||||
|
||||
| 用例编号 | 测试项 | 预期结果 | 状态 |
|
||||
|---------|--------|---------|------|
|
||||
| KM-001 | 上传PDF文档 | 上传成功,可在线预览 | 待测 |
|
||||
| KM-002 | 上传Word文档 | 上传成功 | 待测 |
|
||||
| KM-003 | 上传Excel文档 | 上传成功 | 待测 |
|
||||
| KM-004 | 上传PPT文档 | 上传成功 | 待测 |
|
||||
| KM-005 | 上传视频文件 | 上传成功,可在线播放 | 待测 |
|
||||
| KM-006 | 上传不支持的格式 | 提示"不支持该文件格式" | 待测 |
|
||||
| KM-007 | 超大文件上传 | 提示"文件大小超过限制" | 待测 |
|
||||
|
||||
#### 2.3 知识状态管理
|
||||
|
||||
| 用例编号 | 测试项 | 预期结果 | 状态 |
|
||||
|---------|--------|---------|------|
|
||||
| KS-001 | 创建知识(默认草稿) | 状态为DRAFT | 待测 |
|
||||
| KS-002 | 草稿→发布 | 状态变为PUBLISHED | 待测 |
|
||||
| KS-003 | 已发布→下架 | 状态变为OFFLINE | 待测 |
|
||||
| KS-004 | 已下架→重新上架 | 状态变为PUBLISHED | 待测 |
|
||||
| KS-005 | 学员查看草稿知识 | 不可见 | 待测 |
|
||||
| KS-006 | 学员查看已发布知识 | 可见,可预览 | 待测 |
|
||||
| KS-007 | 学员查看已下架知识 | 不可见 | 待测 |
|
||||
| KS-008 | 下架被培训计划引用的知识 | 显示警告确认 | 待测 |
|
||||
|
||||
#### 2.4 部门隔离
|
||||
|
||||
| 用例编号 | 测试项 | 预期结果 | 状态 |
|
||||
|---------|--------|---------|------|
|
||||
| KD-001 | 讲师查看本部门知识 | 正常查看 | 待测 |
|
||||
| KD-002 | 讲师查看其他部门知识 | 不可见 | 待测 |
|
||||
| KD-003 | 学员查看本部门已发布知识 | 正常查看 | 待测 |
|
||||
| KD-004 | 学员查看其他部门知识 | 不可见 | 待测 |
|
||||
|
||||
---
|
||||
|
||||
### 模块三:考题管理
|
||||
|
||||
#### 3.1 题型测试
|
||||
|
||||
| 用例编号 | 测试项 | 预期结果 | 状态 |
|
||||
|---------|--------|---------|------|
|
||||
| Q-001 | 创建单选题(4选项) | 成功创建,答案为单个选项 | 待测 |
|
||||
| Q-002 | 创建多选题 | 成功创建,答案为多个选项 | 待测 |
|
||||
| Q-003 | 创建判断题 | 成功创建,答案为true/false | 待测 |
|
||||
| Q-004 | 单选题设置多个答案 | 提示错误 | 待测 |
|
||||
| Q-005 | 多选题只设置一个答案 | 提示"多选题至少选择两个答案" | 待测 |
|
||||
| Q-006 | 题目必须填写解析 | 解析为空时提示必填 | 待测 |
|
||||
|
||||
#### 3.2 题目状态管理
|
||||
|
||||
| 用例编号 | 测试项 | 预期结果 | 状态 |
|
||||
|---------|--------|---------|------|
|
||||
| QS-001 | 草稿题目发布 | 状态变为PUBLISHED | 待测 |
|
||||
| QS-002 | 下架被试卷引用的题目 | 显示警告确认 | 待测 |
|
||||
| QS-003 | 只有已发布题目可被组卷 | 草稿/下架题目不可选 | 待测 |
|
||||
|
||||
#### 3.3 部门隔离
|
||||
|
||||
| 用例编号 | 测试项 | 预期结果 | 状态 |
|
||||
|---------|--------|---------|------|
|
||||
| QD-001 | 讲师只能管理本部门题库 | 其他部门题目不可见 | 待测 |
|
||||
| QD-002 | 学员无法访问题目管理 | 返回403 | 待测 |
|
||||
|
||||
---
|
||||
|
||||
### 模块四:试卷管理
|
||||
|
||||
#### 4.1 手动组卷
|
||||
|
||||
| 用例编号 | 测试项 | 预期结果 | 状态 |
|
||||
|---------|--------|---------|------|
|
||||
| P-001 | 手动选择题目组卷 | 成功创建试卷 | 待测 |
|
||||
| P-002 | 设置每题分值 | 分值设置正确 | 待测 |
|
||||
| P-003 | 总分自动计算 | 各题分值之和 = 总分 | 待测 |
|
||||
| P-004 | 设置考试时长 | 时长设置正确 | 待测 |
|
||||
| P-005 | 设置及格分 | 及格分 ≤ 总分 | 待测 |
|
||||
| P-006 | 及格分超过总分 | 提示"及格分不能超过总分" | 待测 |
|
||||
|
||||
#### 4.2 自动组卷
|
||||
|
||||
| 用例编号 | 测试项 | 预期结果 | 状态 |
|
||||
|---------|--------|---------|------|
|
||||
| PA-001 | 设置规则自动抽题 | 按规则随机抽取 | 待测 |
|
||||
| PA-002 | 题库数量不足 | 提示"题目数量不足" | 待测 |
|
||||
| PA-003 | 自动组卷题目随机 | 多次组卷结果不同 | 待测 |
|
||||
|
||||
#### 4.3 试卷预览
|
||||
|
||||
| 用例编号 | 测试项 | 预期结果 | 状态 |
|
||||
|---------|--------|---------|------|
|
||||
| PP-001 | 预览试卷 | 显示完整试卷内容 | 待测 |
|
||||
|
||||
#### 4.4 试卷状态管理
|
||||
|
||||
| 用例编号 | 测试项 | 预期结果 | 状态 |
|
||||
|---------|--------|---------|------|
|
||||
| PS-001 | 下架被考试引用的试卷 | 显示警告确认 | 待测 |
|
||||
|
||||
---
|
||||
|
||||
### 模块五:考试管理
|
||||
|
||||
#### 5.1 发布考试
|
||||
|
||||
| 用例编号 | 测试项 | 预期结果 | 状态 |
|
||||
|---------|--------|---------|------|
|
||||
| E-001 | 创建考试,关联试卷 | 成功创建 | 待测 |
|
||||
| E-002 | 设置时间窗口(开始~结束) | 时间设置正确 | 待测 |
|
||||
| E-003 | 设置及格线 | 及格线设置正确 | 待测 |
|
||||
| E-004 | 设置最大考试次数 | 次数限制生效 | 待测 |
|
||||
| E-005 | 指定部门参加考试 | 该部门所有人可见考试 | 待测 |
|
||||
| E-006 | 指定小组参加考试 | 该小组成员可见考试 | 待测 |
|
||||
| E-007 | 指定个人参加考试 | 仅该用户可见考试 | 待测 |
|
||||
|
||||
#### 5.2 在线答题
|
||||
|
||||
| 用例编号 | 测试项 | 预期结果 | 状态 |
|
||||
|---------|--------|---------|------|
|
||||
| EA-001 | 在时间窗口内进入考试 | 成功进入 | 待测 |
|
||||
| EA-002 | 不在时间窗口进入考试 | 提示"不在考试时间范围内" | 待测 |
|
||||
| EA-003 | 超过最大次数进入考试 | 提示"考试次数已用完" | 待测 |
|
||||
| EA-004 | 答题过程自动计时 | 倒计时正确 | 待测 |
|
||||
| EA-005 | 超时自动交卷 | 系统自动提交 | 待测 |
|
||||
| EA-006 | 主动交卷 | 成功提交 | 待测 |
|
||||
| EA-007 | 答案定时自动保存(30秒) | 答案保存成功 | 待测 |
|
||||
| EA-008 | 断网后恢复继续答题 | 可继续答题 | 待测 |
|
||||
|
||||
#### 5.3 成绩计算
|
||||
|
||||
| 用例编号 | 测试项 | 预期结果 | 状态 |
|
||||
|---------|--------|---------|------|
|
||||
| ES-001 | 单选题判分 | 正确得满分,错误0分 | 待测 |
|
||||
| ES-002 | 多选题判分 | 全对得分,部分对/错误0分 | 待测 |
|
||||
| ES-003 | 判断题判分 | 正确得满分,错误0分 | 待测 |
|
||||
| ES-004 | 分数 ≥ 及格线 | 显示"通过" | 待测 |
|
||||
| ES-005 | 分数 < 及格线 | 显示"未通过" | 待测 |
|
||||
| ES-006 | 多次考试取最高分 | 最高分记录正确 | 待测 |
|
||||
|
||||
#### 5.4 成绩查看
|
||||
|
||||
| 用例编号 | 测试项 | 预期结果 | 状态 |
|
||||
|---------|--------|---------|------|
|
||||
| EV-001 | 交卷后立即显示成绩 | 成绩即时显示 | 待测 |
|
||||
| EV-002 | 显示答案解析 | 每题显示正确答案和解析 | 待测 |
|
||||
| EV-003 | 讲师查看本部门学员成绩 | 正常查看 | 待测 |
|
||||
|
||||
---
|
||||
|
||||
### 模块六:培训计划
|
||||
|
||||
#### 6.1 创建培训计划
|
||||
|
||||
| 用例编号 | 测试项 | 预期结果 | 状态 |
|
||||
|---------|--------|---------|------|
|
||||
| TP-001 | 创建培训计划(名称、周期、目标) | 成功创建 | 待测 |
|
||||
| TP-002 | 关联多个知识文档 | 关联成功 | 待测 |
|
||||
| TP-003 | 关联考试(可选) | 关联成功 | 待测 |
|
||||
| TP-004 | 分配部门/小组/个人 | 分配成功 | 待测 |
|
||||
|
||||
#### 6.2 计划状态
|
||||
|
||||
| 用例编号 | 测试项 | 预期结果 | 状态 |
|
||||
|---------|--------|---------|------|
|
||||
| TPS-001 | 开始日期前状态 | 未开始 | 待测 |
|
||||
| TPS-002 | 在周期内状态 | 进行中 | 待测 |
|
||||
| TPS-003 | 结束日期后状态 | 已结束 | 待测 |
|
||||
|
||||
#### 6.3 进度跟踪
|
||||
|
||||
| 用例编号 | 测试项 | 预期结果 | 状态 |
|
||||
|---------|--------|---------|------|
|
||||
| TPP-001 | 学员完成知识学习 | 进度更新 | 待测 |
|
||||
| TPP-002 | 学员完成关联考试 | 进度更新 | 待测 |
|
||||
| TPP-003 | 学员查看自己的学习进度 | 进度显示正确 | 待测 |
|
||||
| TPP-004 | 讲师查看学员培训进度 | 可查看本部门 | 待测 |
|
||||
|
||||
---
|
||||
|
||||
## 四、权限矩阵测试
|
||||
|
||||
| 用例编号 | 角色 | 操作 | 预期结果 | 状态 |
|
||||
|---------|------|------|---------|------|
|
||||
| PERM-001 | 管理员 | 管理所有组织架构 | 允许 | 待测 |
|
||||
| PERM-002 | 管理员 | 查看全平台数据 | 允许 | 待测 |
|
||||
| PERM-003 | 讲师 | 管理本部门知识库 | 允许 | 待测 |
|
||||
| PERM-004 | 讲师 | 管理其他部门知识库 | 拒绝(403) | 待测 |
|
||||
| PERM-005 | 讲师 | 查看本部门学员成绩 | 允许 | 待测 |
|
||||
| PERM-006 | 学员 | 查看本部门已发布知识 | 允许(只读) | 待测 |
|
||||
| PERM-007 | 学员 | 编辑知识 | 拒绝(403) | 待测 |
|
||||
| PERM-008 | 学员 | 访问题目管理 | 拒绝(403) | 待测 |
|
||||
| PERM-009 | 学员 | 访问试卷管理 | 拒绝(403) | 待测 |
|
||||
| PERM-010 | 学员 | 参加分配的考试 | 允许 | 待测 |
|
||||
|
||||
---
|
||||
|
||||
## 五、边界测试
|
||||
|
||||
| 用例编号 | 测试项 | 边界条件 | 预期结果 | 状态 |
|
||||
|---------|--------|---------|---------|------|
|
||||
| BD-001 | 部门数量 | = 8 | 允许创建 | 待测 |
|
||||
| BD-002 | 部门数量 | = 9 | 拒绝创建 | 待测 |
|
||||
| BD-003 | 小组数量 | = 10/部门 | 允许创建 | 待测 |
|
||||
| BD-004 | 小组数量 | = 11/部门 | 拒绝创建 | 待测 |
|
||||
| BD-005 | 考试时长 | 0分钟 | 提示错误 | 待测 |
|
||||
| BD-006 | 及格分 | 0分 | 允许 | 待测 |
|
||||
| BD-007 | 及格分 | 负数 | 提示错误 | 待测 |
|
||||
| BD-008 | 最大考试次数 | 0次 | 提示错误 | 待测 |
|
||||
| BD-009 | 题目选项 | 空选项 | 提示错误 | 待测 |
|
||||
|
||||
---
|
||||
|
||||
## 六、接口测试(API)
|
||||
|
||||
### 6.1 认证接口
|
||||
|
||||
| 接口 | 方法 | 说明 | 状态 |
|
||||
|------|------|------|------|
|
||||
| /api/auth/wx-login | POST | 企业微信登录 | 待测 |
|
||||
| /api/auth/refresh | POST | Token刷新 | 待测 |
|
||||
|
||||
### 6.2 组织管理接口
|
||||
|
||||
| 接口 | 方法 | 说明 | 状态 |
|
||||
|------|------|------|------|
|
||||
| /api/system/centers | GET/POST/PUT/DELETE | 中心管理 | 待测 |
|
||||
| /api/system/departments | GET/POST/PUT/DELETE | 部门管理 | 待测 |
|
||||
| /api/system/groups | GET/POST/PUT/DELETE | 小组管理 | 待测 |
|
||||
| /api/system/users | GET/POST/PUT/DELETE | 用户管理 | 待测 |
|
||||
|
||||
### 6.3 知识库接口
|
||||
|
||||
| 接口 | 方法 | 说明 | 状态 |
|
||||
|------|------|------|------|
|
||||
| /api/knowledge/categories | GET/POST/PUT/DELETE | 分类管理 | 待测 |
|
||||
| /api/knowledge/items | GET/POST/PUT/DELETE | 知识管理 | 待测 |
|
||||
| /api/knowledge/upload | POST | 文件上传 | 待测 |
|
||||
| /api/knowledge/{id}/publish | PUT | 发布知识 | 待测 |
|
||||
| /api/knowledge/{id}/offline | PUT | 下架知识 | 待测 |
|
||||
|
||||
### 6.4 考试接口
|
||||
|
||||
| 接口 | 方法 | 说明 | 状态 |
|
||||
|------|------|------|------|
|
||||
| /api/exam/questions | GET/POST/PUT/DELETE | 题目管理 | 待测 |
|
||||
| /api/exam/papers | GET/POST/PUT/DELETE | 试卷管理 | 待测 |
|
||||
| /api/exam/exams | GET/POST/PUT/DELETE | 考试管理 | 待测 |
|
||||
| /api/exam/{id}/start | POST | 开始考试 | 待测 |
|
||||
| /api/exam/{id}/submit | POST | 提交试卷 | 待测 |
|
||||
| /api/exam/{id}/auto-save | PUT | 自动保存答案 | 待测 |
|
||||
|
||||
### 6.5 培训接口
|
||||
|
||||
| 接口 | 方法 | 说明 | 状态 |
|
||||
|------|------|------|------|
|
||||
| /api/training/plans | GET/POST/PUT/DELETE | 培训计划管理 | 待测 |
|
||||
| /api/training/plans/{id}/progress | GET | 进度查询 | 待测 |
|
||||
|
||||
---
|
||||
|
||||
## 七、测试环境要求
|
||||
|
||||
| 项目 | 要求 |
|
||||
|------|------|
|
||||
| JDK | 17 |
|
||||
| 数据库 | MySQL 8.0 |
|
||||
| 浏览器 | Chrome最新版、企业微信内置浏览器 |
|
||||
| 测试数据 | 准备3个角色测试账号(管理员/讲师/学员) |
|
||||
|
||||
---
|
||||
|
||||
## 八、测试优先级
|
||||
|
||||
| 优先级 | 模块/功能 |
|
||||
|--------|----------|
|
||||
| P0 | 用户认证登录 |
|
||||
| P0 | 权限控制 |
|
||||
| P0 | 在线考试(核心流程) |
|
||||
| P0 | 数据隔离 |
|
||||
| P1 | 知识库管理 |
|
||||
| P1 | 题目/试卷管理 |
|
||||
| P1 | 培训计划 |
|
||||
| P2 | 文件上传/预览 |
|
||||
| P2 | UI交互细节 |
|
||||
|
||||
---
|
||||
|
||||
## 九、测试用例统计
|
||||
|
||||
| 模块 | 用例数 |
|
||||
|------|--------|
|
||||
| 认证登录 | 5 |
|
||||
| 组织架构 | 7 |
|
||||
| 员工管理 | 7 |
|
||||
| 知识库 | 19 |
|
||||
| 考题管理 | 11 |
|
||||
| 试卷管理 | 11 |
|
||||
| 考试管理 | 20 |
|
||||
| 培训计划 | 11 |
|
||||
| 权限测试 | 10 |
|
||||
| 边界测试 | 9 |
|
||||
| **总计** | **110** |
|
||||
|
||||
---
|
||||
|
||||
## 十、测试执行记录
|
||||
|
||||
### 执行摘要
|
||||
|
||||
| 项目 | 数值 |
|
||||
|------|------|
|
||||
| 计划用例数 | 110 |
|
||||
| 已执行 | 0 |
|
||||
| 通过 | 0 |
|
||||
| 失败 | 0 |
|
||||
| 阻塞 | 0 |
|
||||
| 通过率 | - |
|
||||
|
||||
### 缺陷记录
|
||||
|
||||
| 缺陷编号 | 用例编号 | 严重程度 | 描述 | 状态 |
|
||||
|---------|---------|---------|------|------|
|
||||
| - | - | - | - | - |
|
||||
|
||||
---
|
||||
|
||||
**文档状态:已创建,等待测试执行**
|
||||
@@ -1,133 +0,0 @@
|
||||
# 考试管理模块回归测试方案
|
||||
|
||||
> 版本:V1.0
|
||||
> 更新日期:2026-01-13
|
||||
> 状态:待执行
|
||||
|
||||
---
|
||||
|
||||
## 一、测试范围
|
||||
|
||||
根据 PRD 模块五"考试管理"的功能定义:
|
||||
|
||||
| 功能点 | 说明 |
|
||||
|--------|------|
|
||||
| 发布考试 | 选择试卷,设置考试名称、时间窗口(开始~结束时间) |
|
||||
| 指定对象 | 支持指定部门 / 小组 / 个人参加考试 |
|
||||
| 考试规则 | 设置及格线、限制考试次数、考试时长 |
|
||||
| 在线答题 | 学员在线作答,自动计时,超时自动交卷 |
|
||||
| 成绩查看 | 交卷后立即显示成绩和答案解析 |
|
||||
|
||||
---
|
||||
|
||||
## 二、测试环境要求
|
||||
|
||||
| 项目 | 要求 |
|
||||
|------|------|
|
||||
| 测试账号 | ADMIN 账号 1 个、LECTURER 账号 2 个(不同部门)、STUDENT 账号 3 个 |
|
||||
| 前置数据 | 至少 1 个已发布试卷、至少 2 个部门、部门下有学员 |
|
||||
| 浏览器 | Chrome 最新版 |
|
||||
|
||||
---
|
||||
|
||||
## 三、测试用例
|
||||
|
||||
### 3.1 发布考试功能
|
||||
|
||||
| 用例ID | 测试项 | 前置条件 | 测试步骤 | 预期结果 |
|
||||
|--------|--------|----------|----------|----------|
|
||||
| EX-001 | 正常发布考试 | 讲师登录,有已发布试卷 | 1. 进入考试管理<br>2. 点击"发布考试"<br>3. 填写考试名称、选择试卷<br>4. 设置开始/结束时间<br>5. 选择参与人员<br>6. 点击发布 | 发布成功,列表显示新考试 |
|
||||
| EX-002 | 必填项校验 | 讲师登录 | 1. 进入发布考试页<br>2. 不填写考试名称,直接提交 | 提示"请输入考试名称" |
|
||||
| EX-003 | 试卷下拉列表 | 讲师登录 | 1. 进入发布考试页<br>2. 查看试卷下拉列表 | 只显示当前用户部门的已发布试卷 |
|
||||
| EX-004 | 参与人员列表 | 讲师登录 | 1. 进入发布考试页<br>2. 查看参与人员列表 | 只显示当前用户部门的学员 |
|
||||
| EX-005 | 时间校验 | 讲师登录 | 1. 设置结束时间早于开始时间<br>2. 提交 | 提示"结束时间必须晚于开始时间" |
|
||||
| EX-006 | 部门数据隔离 | 讲师A登录(部门A) | 1. 发布一场考试<br>2. 切换讲师B登录(部门B)<br>3. 查看考试列表 | 讲师B看不到讲师A发布的考试 |
|
||||
|
||||
### 3.2 考试列表功能
|
||||
|
||||
| 用例ID | 测试项 | 前置条件 | 测试步骤 | 预期结果 |
|
||||
|--------|--------|----------|----------|----------|
|
||||
| EX-101 | 列表正常显示 | 有考试数据 | 1. 进入考试管理页 | 列表正常显示,包含考试名称、试卷、时间、状态等 |
|
||||
| EX-102 | 状态筛选 | 有不同状态考试 | 1. 选择"进行中"状态筛选 | 只显示进行中的考试 |
|
||||
| EX-103 | 关键字搜索 | 有考试数据 | 1. 输入考试名称关键字搜索 | 显示匹配的考试 |
|
||||
| EX-104 | 分页功能 | 考试数量 > 10 | 1. 查看分页<br>2. 点击下一页 | 分页正常,数据正确切换 |
|
||||
| EX-105 | 考试状态自动更新 | 有未开始的考试 | 1. 设置一个即将开始的考试<br>2. 等待时间到达 | 状态自动变为"进行中" |
|
||||
|
||||
### 3.3 考试详情/编辑功能
|
||||
|
||||
| 用例ID | 测试项 | 前置条件 | 测试步骤 | 预期结果 |
|
||||
|--------|--------|----------|----------|----------|
|
||||
| EX-201 | 查看考试详情 | 有考试数据 | 1. 点击"查看详情"按钮 | 弹窗显示考试详细信息 |
|
||||
| EX-202 | 编辑未开始考试 | 有未开始状态考试 | 1. 点击编辑<br>2. 修改考试名称<br>3. 保存 | 修改成功 |
|
||||
| EX-203 | 删除未开始考试 | 有未开始状态考试 | 1. 点击删除<br>2. 确认删除 | 删除成功,列表刷新 |
|
||||
| EX-204 | 删除有记录考试 | 考试已有学员作答 | 1. 尝试删除该考试 | 提示"该考试已有考试记录,无法删除" |
|
||||
|
||||
### 3.4 在线答题功能(学员端)
|
||||
|
||||
| 用例ID | 测试项 | 前置条件 | 测试步骤 | 预期结果 |
|
||||
|--------|--------|----------|----------|----------|
|
||||
| EX-301 | 学员查看考试列表 | 学员被分配考试 | 1. 学员登录<br>2. 进入"我的考试" | 显示分配给该学员的进行中考试 |
|
||||
| EX-302 | 开始考试 | 考试进行中 | 1. 点击"开始考试" | 进入答题页面,显示试卷题目,倒计时开始 |
|
||||
| EX-303 | 答题保存 | 正在答题中 | 1. 选择答案<br>2. 等待30秒自动保存 | 答案自动保存成功 |
|
||||
| EX-304 | 主动交卷 | 正在答题中 | 1. 完成答题<br>2. 点击"交卷" | 提交成功,显示成绩和答案解析 |
|
||||
| EX-305 | 超时自动交卷 | 正在答题中 | 1. 等待考试时间耗尽 | 自动交卷,显示成绩 |
|
||||
| EX-306 | 考试次数限制 | 已用完考试次数 | 1. 尝试再次开始考试 | 提示"考试次数已用完" |
|
||||
| EX-307 | 非考试时间段 | 考试未开始或已结束 | 1. 尝试开始考试 | 无法开始,提示不在考试时间内 |
|
||||
| EX-308 | 非指定人员 | 学员未被分配该考试 | 1. 尝试访问该考试 | 无法参加该考试 |
|
||||
|
||||
### 3.5 成绩查看功能
|
||||
|
||||
| 用例ID | 测试项 | 前置条件 | 测试步骤 | 预期结果 |
|
||||
|--------|--------|----------|----------|----------|
|
||||
| EX-401 | 学员查看成绩 | 学员已完成考试 | 1. 查看考试记录 | 显示得分、是否及格、答题详情 |
|
||||
| EX-402 | 答案解析显示 | 学员已交卷 | 1. 查看答题详情 | 显示正确答案和解析 |
|
||||
| EX-403 | 讲师查看成绩统计 | 有学员完成考试 | 1. 讲师点击"成绩统计" | 显示参与人数、及格率、成绩分布 |
|
||||
| EX-404 | 最高分记录 | 学员多次考试 | 1. 学员参加同一考试多次 | 取最高分作为最终成绩 |
|
||||
|
||||
### 3.6 权限与数据隔离
|
||||
|
||||
| 用例ID | 测试项 | 前置条件 | 测试步骤 | 预期结果 |
|
||||
|--------|--------|----------|----------|----------|
|
||||
| EX-501 | 讲师只能管理本部门 | 讲师登录 | 1. 查看考试列表 | 只显示本部门的考试 |
|
||||
| EX-502 | 管理员查看所有 | 管理员登录 | 1. 查看考试列表 | 显示所有部门的考试 |
|
||||
| EX-503 | 学员权限限制 | 学员登录 | 1. 尝试访问考试管理页 | 无权访问或只能看"我的考试" |
|
||||
|
||||
---
|
||||
|
||||
## 四、本次修复的 BUG 专项验证
|
||||
|
||||
| 验证项 | 测试步骤 | 预期结果 |
|
||||
|--------|----------|----------|
|
||||
| 试卷列表接口 | 发布考试页,查看试卷下拉 | 正常显示当前部门已发布试卷 |
|
||||
| 参与人员列表 | 发布考试页,查看人员列表 | 正常显示当前部门学员 |
|
||||
| maxAttempts 校验 | 发布考试(不填补考次数) | 正常发布,默认允许考1次 |
|
||||
| departmentId 自动获取 | 讲师发布考试 | 自动使用讲师所在部门,无需前端传值 |
|
||||
| creatorId 保存 | 发布考试后查看数据库 | creator_id 字段正确保存 |
|
||||
| 考试列表显示 | 进入考试管理页 | 列表正常显示数据 |
|
||||
|
||||
---
|
||||
|
||||
## 五、测试执行顺序建议
|
||||
|
||||
1. **环境准备**:确认测试数据(部门、用户、试卷)
|
||||
2. **BUG 修复验证**:优先执行第四节专项验证
|
||||
3. **核心流程**:EX-001 → EX-101 → EX-301 → EX-304 → EX-401
|
||||
4. **边界测试**:EX-005、EX-306、EX-307
|
||||
5. **权限测试**:EX-501 ~ EX-503
|
||||
|
||||
---
|
||||
|
||||
## 六、测试结果记录
|
||||
|
||||
| 用例ID | 执行日期 | 执行人 | 结果 | 备注 |
|
||||
|--------|----------|--------|------|------|
|
||||
| | | | | |
|
||||
| | | | | |
|
||||
| | | | | |
|
||||
|
||||
---
|
||||
|
||||
## 七、相关文档
|
||||
|
||||
- [产品需求文档](./PRD.md)
|
||||
- [API接口文档](http://localhost:8080/swagger-ui.html)
|
||||
@@ -1,155 +0,0 @@
|
||||
# 培训计划模块回归测试方案
|
||||
|
||||
> 版本:V1.0
|
||||
> 更新日期:2026-01-13
|
||||
> 状态:待执行
|
||||
|
||||
---
|
||||
|
||||
## 一、测试范围
|
||||
|
||||
根据 PRD 模块六"培训计划"的功能定义:
|
||||
|
||||
| 功能点 | 说明 |
|
||||
|--------|------|
|
||||
| 创建培训计划 | 设置计划名称、培训周期、培训目标 |
|
||||
| 关联知识/考试 | 一个培训计划可包含多个知识文档 + 一场考试 |
|
||||
| 分配学员 | 指定部门/小组/个人参加培训计划 |
|
||||
| 进度跟踪 | 学员可查看自己的学习进度和考试状态 |
|
||||
| 计划状态 | 未开始 / 进行中 / 已结束 |
|
||||
|
||||
---
|
||||
|
||||
## 二、测试环境要求
|
||||
|
||||
| 项目 | 要求 |
|
||||
|------|------|
|
||||
| 测试账号 | ADMIN 账号 1 个、LECTURER 账号 2 个(不同部门)、STUDENT 账号 3 个 |
|
||||
| 前置数据 | 至少 1 个已发布知识、至少 1 个进行中考试、至少 2 个部门、部门下有学员 |
|
||||
| 浏览器 | Chrome 最新版 |
|
||||
|
||||
---
|
||||
|
||||
## 三、测试用例
|
||||
|
||||
### 3.1 创建培训计划功能
|
||||
|
||||
| 用例ID | 测试项 | 前置条件 | 测试步骤 | 预期结果 |
|
||||
|--------|--------|----------|----------|----------|
|
||||
| TP-001 | 正常创建培训计划 | 讲师登录,有已发布知识 | 1. 进入培训计划<br>2. 点击"创建计划"<br>3. 填写计划名称、描述<br>4. 设置开始/结束日期<br>5. 点击保存 | 创建成功,列表显示新计划 |
|
||||
| TP-002 | 必填项校验 | 讲师登录 | 1. 进入创建计划页<br>2. 不填写计划名称,直接保存 | 提示"请输入计划名称" |
|
||||
| TP-003 | 日期校验 | 讲师登录 | 1. 设置结束日期早于开始日期<br>2. 保存 | 提示"开始日期不能晚于结束日期" |
|
||||
| TP-004 | 部门自动获取 | 讲师登录 | 1. 创建培训计划<br>2. 不传departmentId | 自动使用讲师所属部门,创建成功 |
|
||||
| TP-005 | 管理员指定部门 | 管理员登录 | 1. 创建培训计划<br>2. 选择指定部门 | 使用指定的部门创建成功 |
|
||||
|
||||
### 3.2 关联知识/考试功能
|
||||
|
||||
| 用例ID | 测试项 | 前置条件 | 测试步骤 | 预期结果 |
|
||||
|--------|--------|----------|----------|----------|
|
||||
| TP-101 | 添加知识内容 | 有已发布知识 | 1. 编辑培训计划<br>2. 点击"添加知识"<br>3. 选择知识内容<br>4. 保存 | 知识内容添加成功,显示在培训内容列表 |
|
||||
| TP-102 | 设置必修/选修 | 已添加知识内容 | 1. 编辑培训计划<br>2. 设置知识为必修/选修<br>3. 保存 | 必修/选修标记正确保存 |
|
||||
| TP-103 | 关联考试 | 有进行中考试 | 1. 编辑培训计划<br>2. 点击"添加考试"<br>3. 选择考试<br>4. 保存 | 考试关联成功 |
|
||||
| TP-104 | 知识列表加载 | 讲师登录 | 1. 编辑培训计划<br>2. 点击添加知识<br>3. 查看知识列表 | 只显示当前部门已发布知识 |
|
||||
| TP-105 | 考试列表加载 | 讲师登录 | 1. 编辑培训计划<br>2. 点击添加考试<br>3. 查看考试列表 | 只显示当前部门进行中考试 |
|
||||
|
||||
### 3.3 分配学员功能
|
||||
|
||||
| 用例ID | 测试项 | 前置条件 | 测试步骤 | 预期结果 |
|
||||
|--------|--------|----------|----------|----------|
|
||||
| TP-201 | 指定个人参与 | 有学员数据 | 1. 编辑培训计划<br>2. 选择指定学员<br>3. 保存 | 学员分配成功 |
|
||||
| TP-202 | 指定部门参与 | 有部门数据 | 1. 编辑培训计划<br>2. 选择指定部门<br>3. 保存 | 部门下所有学员可参与 |
|
||||
| TP-203 | 指定小组参与 | 有小组数据 | 1. 编辑培训计划<br>2. 选择指定小组<br>3. 保存 | 小组下所有学员可参与 |
|
||||
| TP-204 | 参与人员回显 | 已分配学员 | 1. 编辑已有计划<br>2. 查看参与人员 | 已选人员正确勾选显示 |
|
||||
|
||||
### 3.4 培训计划列表功能
|
||||
|
||||
| 用例ID | 测试项 | 前置条件 | 测试步骤 | 预期结果 |
|
||||
|--------|--------|----------|----------|----------|
|
||||
| TP-301 | 列表正常显示 | 有培训计划数据 | 1. 进入培训计划页 | 列表正常显示,包含计划名称、状态、时间、进度等 |
|
||||
| TP-302 | 状态筛选 | 有不同状态计划 | 1. 选择"进行中"状态筛选 | 只显示进行中的计划 |
|
||||
| TP-303 | 关键字搜索 | 有计划数据 | 1. 输入计划名称关键字搜索 | 显示匹配的计划 |
|
||||
| TP-304 | 分页功能 | 计划数量 > 10 | 1. 查看分页<br>2. 点击下一页 | 分页正常,数据正确切换 |
|
||||
| TP-305 | 数据字段匹配 | 有计划数据 | 1. 检查列表数据 | 前端显示字段与后端返回一致(records而非list) |
|
||||
|
||||
### 3.5 培训计划详情功能
|
||||
|
||||
| 用例ID | 测试项 | 前置条件 | 测试步骤 | 预期结果 |
|
||||
|--------|--------|----------|----------|----------|
|
||||
| TP-401 | 查看计划详情 | 有计划数据 | 1. 点击"查看详情"按钮 | 详情页正常加载,显示完整信息 |
|
||||
| TP-402 | 培训内容展示 | 计划已关联知识/考试 | 1. 查看详情页培训内容区 | 正确显示知识和考试列表 |
|
||||
| TP-403 | 参与人员进度 | 有学员参与 | 1. 查看详情页参与人员 | 显示学员学习进度和状态 |
|
||||
| TP-404 | 编辑跳转 | 有计划数据 | 1. 详情页点击"编辑" | 正确跳转到编辑页面 |
|
||||
|
||||
### 3.6 培训计划编辑功能
|
||||
|
||||
| 用例ID | 测试项 | 前置条件 | 测试步骤 | 预期结果 |
|
||||
|--------|--------|----------|----------|----------|
|
||||
| TP-501 | 编辑基本信息 | 有未开始计划 | 1. 编辑计划名称<br>2. 保存 | 修改成功 |
|
||||
| TP-502 | 编辑培训内容 | 有未开始计划 | 1. 添加/删除知识<br>2. 保存 | 培训内容修改成功 |
|
||||
| TP-503 | 编辑参与人员 | 有未开始计划 | 1. 修改参与人员<br>2. 保存 | 参与人员修改成功 |
|
||||
|
||||
### 3.7 培训计划状态管理
|
||||
|
||||
| 用例ID | 测试项 | 前置条件 | 测试步骤 | 预期结果 |
|
||||
|--------|--------|----------|----------|----------|
|
||||
| TP-601 | 发布培训计划 | 有草稿状态计划 | 1. 点击"发布"按钮 | 状态变为"进行中",学员可见 |
|
||||
| TP-602 | 结束培训计划 | 有进行中计划 | 1. 点击"结束"按钮 | 状态变为"已结束" |
|
||||
| TP-603 | 删除未开始计划 | 有未开始计划 | 1. 点击删除<br>2. 确认删除 | 删除成功 |
|
||||
|
||||
### 3.8 学员端-我的培训
|
||||
|
||||
| 用例ID | 测试项 | 前置条件 | 测试步骤 | 预期结果 |
|
||||
|--------|--------|----------|----------|----------|
|
||||
| TP-701 | 查看我的培训 | 学员被分配培训 | 1. 学员登录<br>2. 进入"我的培训" | 显示分配给该学员的进行中培训 |
|
||||
| TP-702 | 学习知识内容 | 培训包含知识 | 1. 点击知识内容<br>2. 学习完成 | 知识学习状态更新 |
|
||||
| TP-703 | 查看学习进度 | 有学习记录 | 1. 查看培训详情 | 显示正确的学习进度百分比 |
|
||||
| TP-704 | 参加关联考试 | 培训关联考试 | 1. 点击参加考试 | 跳转到考试页面 |
|
||||
|
||||
### 3.9 权限与数据隔离
|
||||
|
||||
| 用例ID | 测试项 | 前置条件 | 测试步骤 | 预期结果 |
|
||||
|--------|--------|----------|----------|----------|
|
||||
| TP-801 | 讲师只能管理本部门 | 讲师登录 | 1. 查看培训计划列表 | 只显示本部门的培训计划 |
|
||||
| TP-802 | 管理员查看所有 | 管理员登录 | 1. 查看培训计划列表 | 显示所有部门的培训计划 |
|
||||
| TP-803 | 学员权限限制 | 学员登录 | 1. 尝试访问培训计划管理页 | 无权访问或只能看"我的培训" |
|
||||
|
||||
---
|
||||
|
||||
## 四、本次修复的 BUG 专项验证
|
||||
|
||||
| 验证项 | 测试步骤 | 预期结果 |
|
||||
|--------|----------|----------|
|
||||
| 创建计划部门ID | 讲师创建培训计划,不传departmentId | 自动使用讲师所在部门,创建成功 |
|
||||
| 列表数据字段 | 进入培训计划列表页 | 列表正常显示(使用records字段) |
|
||||
| 详情页加载 | 点击查看详情 | 详情页正常加载(接口使用/{id}) |
|
||||
| 知识列表接口 | 编辑页添加知识 | 正常加载(使用/page接口) |
|
||||
| 考试列表接口 | 编辑页添加考试 | 正常加载(使用/page接口) |
|
||||
|
||||
---
|
||||
|
||||
## 五、测试执行顺序建议
|
||||
|
||||
1. **环境准备**:确认测试数据(部门、用户、知识、考试)
|
||||
2. **BUG 修复验证**:优先执行第四节专项验证
|
||||
3. **核心流程**:TP-001 → TP-101 → TP-201 → TP-301 → TP-401 → TP-601
|
||||
4. **边界测试**:TP-002、TP-003、TP-004
|
||||
5. **学员端测试**:TP-701 ~ TP-704
|
||||
6. **权限测试**:TP-801 ~ TP-803
|
||||
|
||||
---
|
||||
|
||||
## 六、测试结果记录
|
||||
|
||||
| 用例ID | 执行日期 | 执行人 | 结果 | 备注 |
|
||||
|--------|----------|--------|------|------|
|
||||
| | | | | |
|
||||
| | | | | |
|
||||
| | | | | |
|
||||
|
||||
---
|
||||
|
||||
## 七、相关文档
|
||||
|
||||
- [产品需求文档](./PRD.md)
|
||||
- [API接口文档](http://localhost:8080/swagger-ui.html)
|
||||
- [考试模块测试方案](./TestPlan_ExamModule.md)
|
||||
@@ -1,175 +0,0 @@
|
||||
# 考试管理模块回归测试报告
|
||||
|
||||
> 版本:V1.0
|
||||
> 测试日期:2026-01-13
|
||||
> 测试人员:AI测试工程师
|
||||
> 测试账号:jiangshi(讲师角色)
|
||||
> 测试状态:**已完成**
|
||||
|
||||
---
|
||||
|
||||
## 一、测试概述
|
||||
|
||||
### 1.1 测试目的
|
||||
根据《考试管理模块回归测试方案》(TestPlan_ExamModule.md),对考试管理模块进行全面回归测试,验证BUG修复及核心功能的正确性。
|
||||
|
||||
### 1.2 测试范围
|
||||
- BUG修复专项验证
|
||||
- 发布考试功能测试
|
||||
- 考试列表功能测试
|
||||
- 考试详情/编辑功能测试
|
||||
- 权限与数据隔离测试
|
||||
|
||||
### 1.3 测试环境
|
||||
| 项目 | 配置 |
|
||||
|------|------|
|
||||
| 操作系统 | Windows |
|
||||
| 浏览器 | Chrome 最新版 |
|
||||
| 后端服务 | http://localhost:8080 |
|
||||
| 测试账号 | jiangshi(讲师角色,呼叫中心部门) |
|
||||
|
||||
---
|
||||
|
||||
## 二、BUG修复专项验证结果
|
||||
|
||||
| 验证项 | 测试步骤 | 预期结果 | 实际结果 | 状态 |
|
||||
|--------|----------|----------|----------|------|
|
||||
| 试卷列表接口 | 发布考试页,查看试卷下拉 | 正常显示当前部门已发布试卷 | 显示"测试试卷 -1 (3题/15分)" | ✅ 通过 |
|
||||
| 参与人员列表 | 发布考试页,查看人员列表 | 正常显示当前部门学员 | 显示"员工-1"、"员工-2"(呼叫中心部门) | ✅ 通过 |
|
||||
| maxAttempts 校验 | 发布考试(不填补考次数) | 正常发布,默认允许考1次 | maxAttempts=1,发布成功 | ✅ 通过 |
|
||||
| departmentId 自动获取 | 讲师发布考试 | 自动使用讲师所在部门 | departmentId=5(呼叫中心部门),无需前端传值 | ✅ 通过 |
|
||||
| creatorId 保存 | 发布考试后查看数据库 | creator_id 字段正确保存 | creatorId=3(讲师用户ID) | ✅ 通过 |
|
||||
| 考试列表显示 | 进入考试管理页 | 列表正常显示数据 | 列表正常,包含所有必要列 | ✅ 通过 |
|
||||
|
||||
**BUG修复验证结论:全部6项验证通过,BUG已完全修复。**
|
||||
|
||||
---
|
||||
|
||||
## 三、功能测试结果汇总
|
||||
|
||||
### 3.1 发布考试功能(EX-001~EX-006)
|
||||
|
||||
| 用例ID | 测试项 | 结果 | 备注 |
|
||||
|--------|--------|------|------|
|
||||
| EX-001 | 正常发布考试 | ✅ 通过 | 成功发布"回归测试考试-讲师发布",包含2名参与人员 |
|
||||
| EX-002 | 必填项校验 | ✅ 通过 | 不填考试名称提交,提示"请输入考试名称" |
|
||||
| EX-003 | 试卷下拉列表 | ✅ 通过 | 只显示当前部门已发布试卷 |
|
||||
| EX-004 | 参与人员列表 | ✅ 通过 | 只显示当前部门学员 |
|
||||
| EX-005 | 时间校验 | ✅ 通过 | 结束时间早于开始时间,提示"结束时间必须晚于开始时间" |
|
||||
| EX-006 | 部门数据隔离 | ✅ 通过 | 通过API验证,讲师只能查看本部门考试 |
|
||||
|
||||
### 3.2 考试列表功能(EX-101~EX-105)
|
||||
|
||||
| 用例ID | 测试项 | 结果 | 备注 |
|
||||
|--------|--------|------|------|
|
||||
| EX-101 | 列表正常显示 | ✅ 通过 | 显示考试名称、试卷、时间、参与人数、及格率、状态、操作 |
|
||||
| EX-102 | 状态筛选 | ✅ 通过 | 筛选"进行中"状态,显示"暂无考试"(当前无进行中考试) |
|
||||
| EX-103 | 关键字搜索 | ✅ 通过 | 搜索"回归",只显示匹配的考试 |
|
||||
| EX-104 | 分页功能 | ⏭️ 跳过 | 当前数据量<10条,无法验证分页 |
|
||||
| EX-105 | 考试状态自动更新 | ⏭️ 跳过 | 需等待时间窗口变化,本次未验证 |
|
||||
|
||||
### 3.3 考试详情/编辑功能(EX-201~EX-204)
|
||||
|
||||
| 用例ID | 测试项 | 结果 | 备注 |
|
||||
|--------|--------|------|------|
|
||||
| EX-201 | 查看考试详情 | ✅ 通过 | 弹窗显示完整信息:名称、状态、试卷、时长、时间、人数统计 |
|
||||
| EX-202 | 编辑未开始考试 | ⏭️ 跳过 | 功能入口存在,未深入测试 |
|
||||
| EX-203 | 删除未开始考试 | ✅ 通过 | 弹出确认对话框,确认后可删除 |
|
||||
| EX-204 | 删除有记录考试 | ⏭️ 跳过 | 当前无考试记录数据,无法验证 |
|
||||
|
||||
### 3.4 权限与数据隔离(EX-501~EX-503)
|
||||
|
||||
| 用例ID | 测试项 | 结果 | 备注 |
|
||||
|--------|--------|------|------|
|
||||
| EX-501 | 讲师只能管理本部门 | ✅ 通过 | 讲师jiangshi只能看到呼叫中心部门的考试 |
|
||||
| EX-502 | 管理员查看所有 | ⏭️ 跳过 | 本次使用讲师账号测试 |
|
||||
| EX-503 | 学员权限限制 | ⏭️ 跳过 | 本次使用讲师账号测试 |
|
||||
|
||||
---
|
||||
|
||||
## 四、测试统计
|
||||
|
||||
| 分类 | 总数 | 通过 | 失败 | 跳过 |
|
||||
|------|------|------|------|------|
|
||||
| BUG修复专项 | 6 | 6 | 0 | 0 |
|
||||
| 发布考试功能 | 6 | 6 | 0 | 0 |
|
||||
| 考试列表功能 | 5 | 3 | 0 | 2 |
|
||||
| 考试详情/编辑 | 4 | 2 | 0 | 2 |
|
||||
| 权限与数据隔离 | 3 | 1 | 0 | 2 |
|
||||
| **合计** | **24** | **18** | **0** | **6** |
|
||||
|
||||
**通过率:100%(18/18,不含跳过项)**
|
||||
|
||||
---
|
||||
|
||||
## 五、API验证数据
|
||||
|
||||
### 5.1 试卷列表接口
|
||||
```
|
||||
GET /api/exam/paper/list?status=PUBLISHED
|
||||
Response: 200 OK
|
||||
返回当前部门已发布试卷列表
|
||||
```
|
||||
|
||||
### 5.2 学员列表接口
|
||||
```
|
||||
GET /api/system/user/list?role=STUDENT
|
||||
Response: 200 OK
|
||||
返回数据: 员工-1(departmentId=5), 员工-2(departmentId=5)
|
||||
验证: 只返回讲师所属部门的学员
|
||||
```
|
||||
|
||||
### 5.3 考试创建接口
|
||||
```
|
||||
POST /api/exam
|
||||
Response: 200 OK
|
||||
创建数据验证:
|
||||
- id: 2
|
||||
- title: "回归测试考试-讲师发布"
|
||||
- departmentId: 5 (自动获取)
|
||||
- creatorId: 3 (正确保存)
|
||||
- maxAttempts: 1 (默认值)
|
||||
- targets: [员工-1, 员工-2]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、测试结论
|
||||
|
||||
### 6.1 总体评估
|
||||
**测试通过**。考试管理模块核心功能运行正常,BUG修复验证全部通过。
|
||||
|
||||
### 6.2 主要发现
|
||||
1. ✅ 试卷列表、参与人员列表接口正常工作
|
||||
2. ✅ 讲师发布考试时,departmentId自动从当前用户获取
|
||||
3. ✅ creatorId正确保存
|
||||
4. ✅ maxAttempts默认值校验正常
|
||||
5. ✅ 表单校验(必填项、时间校验)正常
|
||||
6. ✅ 部门数据隔离有效
|
||||
|
||||
### 6.3 遗留问题
|
||||
无。
|
||||
|
||||
### 6.4 建议
|
||||
1. 后续可补充管理员角色和学员角色的测试
|
||||
2. 建议在有更多测试数据后验证分页功能
|
||||
3. 建议在实际考试进行后验证考试记录相关功能
|
||||
|
||||
---
|
||||
|
||||
## 七、附录
|
||||
|
||||
### 7.1 测试截图索引
|
||||
- 登录页面:正常
|
||||
- 考试管理列表页:正常
|
||||
- 发布考试页面:正常
|
||||
- 考试详情弹窗:正常
|
||||
|
||||
### 7.2 相关文档
|
||||
- [产品需求文档](./PRD.md)
|
||||
- [测试方案](./TestPlan_ExamModule.md)
|
||||
- [API文档](http://localhost:8080/swagger-ui.html)
|
||||
|
||||
---
|
||||
|
||||
**报告生成时间:2026-01-13 11:20**
|
||||
@@ -1,158 +0,0 @@
|
||||
# 培训计划模块回归测试报告
|
||||
|
||||
> 版本:V1.0
|
||||
> 测试日期:2026-01-13
|
||||
> 测试执行人:自动化测试
|
||||
> 测试账号:jiangshi(讲师角色)
|
||||
|
||||
---
|
||||
|
||||
## 一、测试概述
|
||||
|
||||
本次测试针对培训计划模块进行回归测试,重点验证之前修复的BUG是否已解决,同时对核心功能进行验证。
|
||||
|
||||
### 1.1 测试环境
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| 系统地址 | http://localhost:8080 |
|
||||
| 测试账号 | jiangshi / 123456 |
|
||||
| 角色 | LECTURER(讲师) |
|
||||
| 浏览器 | Chrome |
|
||||
|
||||
### 1.2 测试范围
|
||||
|
||||
- BUG修复专项验证
|
||||
- 创建培训计划功能
|
||||
- 培训计划列表功能
|
||||
- 培训计划详情功能
|
||||
- 权限与数据隔离
|
||||
|
||||
---
|
||||
|
||||
## 二、BUG修复专项验证结果
|
||||
|
||||
| 验证项 | 测试步骤 | 预期结果 | 实际结果 | 状态 |
|
||||
|--------|----------|----------|----------|------|
|
||||
| 创建计划部门ID | 讲师创建培训计划,不传departmentId | 自动使用讲师所在部门,创建成功 | 创建成功,显示"保存成功" | ✅ 通过 |
|
||||
| 列表数据字段 | 进入培训计划列表页 | 列表正常显示(使用records字段) | 列表正常显示3条数据 | ✅ 通过 |
|
||||
| 详情页加载 | 点击查看详情 | 详情页正常加载(接口使用/{id}) | 详情页正常加载 | ✅ 通过 |
|
||||
| 知识列表接口 | 编辑页添加知识 | 正常加载(使用/page接口) | 弹窗正常显示知识列表 | ✅ 通过 |
|
||||
| 考试列表接口 | 编辑页添加考试 | 正常加载(使用/page接口) | 弹窗正常加载(显示暂无可添加的考试) | ✅ 通过 |
|
||||
|
||||
**BUG修复验证结论:5项全部通过**
|
||||
|
||||
---
|
||||
|
||||
## 三、功能测试结果
|
||||
|
||||
### 3.1 创建培训计划功能
|
||||
|
||||
| 用例ID | 测试项 | 预期结果 | 实际结果 | 状态 |
|
||||
|--------|--------|----------|----------|------|
|
||||
| TP-001 | 正常创建培训计划 | 创建成功,列表显示新计划 | 创建成功,列表显示"回归测试-培训计划001" | ✅ 通过 |
|
||||
| TP-004 | 部门自动获取 | 自动使用讲师所属部门,创建成功 | 自动使用讲师部门(技术支持部),创建成功 | ✅ 通过 |
|
||||
|
||||
### 3.2 关联知识/考试功能
|
||||
|
||||
| 用例ID | 测试项 | 预期结果 | 实际结果 | 状态 |
|
||||
|--------|--------|----------|----------|------|
|
||||
| TP-101 | 添加知识内容 | 知识内容添加成功,显示在培训内容列表 | 知识内容添加成功,显示"JLR车辆知识-2" | ✅ 通过 |
|
||||
| TP-102 | 设置必修/选修 | 必修/选修标记正确保存 | 默认显示"必修"标记 | ✅ 通过 |
|
||||
| TP-104 | 知识列表加载 | 只显示当前部门已发布知识 | 显示2条已发布知识 | ✅ 通过 |
|
||||
| TP-105 | 考试列表加载 | 只显示当前部门进行中考试 | 接口正常调用(暂无可用考试) | ✅ 通过 |
|
||||
|
||||
### 3.3 培训计划列表功能
|
||||
|
||||
| 用例ID | 测试项 | 预期结果 | 实际结果 | 状态 |
|
||||
|--------|--------|----------|----------|------|
|
||||
| TP-301 | 列表正常显示 | 列表正常显示,包含计划名称、状态、时间、进度等 | 正常显示3条数据,字段完整 | ✅ 通过 |
|
||||
| TP-302 | 状态筛选 | 只显示进行中的计划 | 筛选"进行中"后只显示1条 | ✅ 通过 |
|
||||
| TP-303 | 关键字搜索 | 显示匹配的计划 | 搜索"回归测试"后只显示匹配项 | ✅ 通过 |
|
||||
| TP-305 | 数据字段匹配 | 前端显示字段与后端返回一致 | records字段正确解析 | ✅ 通过 |
|
||||
|
||||
### 3.4 培训计划详情功能
|
||||
|
||||
| 用例ID | 测试项 | 预期结果 | 实际结果 | 状态 |
|
||||
|--------|--------|----------|----------|------|
|
||||
| TP-401 | 查看计划详情 | 详情页正常加载,显示完整信息 | 正常加载,显示基本信息 | ✅ 通过 |
|
||||
| TP-404 | 编辑跳转 | 正确跳转到编辑页面 | 正确跳转,基本信息回显正确 | ✅ 通过 |
|
||||
|
||||
### 3.5 权限与数据隔离
|
||||
|
||||
| 用例ID | 测试项 | 预期结果 | 实际结果 | 状态 | 备注 |
|
||||
|--------|--------|----------|----------|------|------|
|
||||
| TP-801 | 讲师只能管理本部门 | 只显示本部门的培训计划 | 显示所有部门的计划 | ⚠️ 待完善 | 数据隔离逻辑未实现 |
|
||||
|
||||
---
|
||||
|
||||
## 四、测试统计
|
||||
|
||||
### 4.1 测试用例执行统计
|
||||
|
||||
| 类别 | 总数 | 通过 | 失败 | 待完善 |
|
||||
|------|------|------|------|--------|
|
||||
| BUG修复验证 | 5 | 5 | 0 | 0 |
|
||||
| 功能测试 | 13 | 12 | 0 | 1 |
|
||||
| **总计** | **18** | **17** | **0** | **1** |
|
||||
|
||||
### 4.2 通过率
|
||||
|
||||
- **BUG修复验证通过率**: 100%
|
||||
- **功能测试通过率**: 92.3%
|
||||
- **总体通过率**: 94.4%
|
||||
|
||||
---
|
||||
|
||||
## 五、问题汇总
|
||||
|
||||
### 5.1 已修复的BUG(本次验证通过)
|
||||
|
||||
| 问题 | 修复方案 | 状态 |
|
||||
|------|----------|------|
|
||||
| 创建计划时报"所属部门不存在" | 非管理员用户自动使用当前用户部门ID | ✅ 已修复 |
|
||||
| 列表页数据不显示 | 前端改用records字段解析数据 | ✅ 已修复 |
|
||||
| 详情页加载失败 | 修正API路径为/{id} | ✅ 已修复 |
|
||||
| 知识列表接口404 | 修正API路径为/knowledge/page | ✅ 已修复 |
|
||||
| 考试列表接口404 | 修正API路径为/exam/page | ✅ 已修复 |
|
||||
|
||||
### 5.2 待完善项
|
||||
|
||||
| 问题描述 | 优先级 | 建议 |
|
||||
|----------|--------|------|
|
||||
| 讲师可以看到所有部门的培训计划 | 中 | 后端需添加部门级数据隔离逻辑 |
|
||||
| 创建计划时添加的知识和参与人员未正确保存 | 高 | 需排查前端提交数据和后端保存逻辑 |
|
||||
|
||||
---
|
||||
|
||||
## 六、测试结论
|
||||
|
||||
本次针对培训计划模块的回归测试**基本通过**:
|
||||
|
||||
1. **BUG修复验证**:5项全部通过,之前修复的问题已确认解决
|
||||
2. **核心功能**:创建、列表、详情、筛选、搜索等功能正常工作
|
||||
3. **待改进**:
|
||||
- 数据隔离逻辑待实现(讲师应只能看到本部门数据)
|
||||
- 创建计划时的关联数据(知识、参与人员)保存需要进一步排查
|
||||
|
||||
**建议**:本次修复的BUG可以发布上线,但需要后续版本完善数据隔离和关联数据保存功能。
|
||||
|
||||
---
|
||||
|
||||
## 七、附录
|
||||
|
||||
### 7.1 修改的文件清单
|
||||
|
||||
| 文件路径 | 修改内容 |
|
||||
|----------|----------|
|
||||
| `TrainingPlanServiceImpl.java:104-115` | 非管理员用户自动使用当前用户部门ID |
|
||||
| `training/plan.html:113` | `pageData.list` → `pageData.records` |
|
||||
| `training/detail.html:79` | `/training/plan/${id}/detail` → `/training/plan/${id}` |
|
||||
| `training/plan-edit.html:372` | `/knowledge/list` → `/knowledge/page` |
|
||||
| `training/plan-edit.html:416` | `/exam/list` → `/exam/page` |
|
||||
|
||||
### 7.2 相关文档
|
||||
|
||||
- [产品需求文档](./PRD.md)
|
||||
- [测试方案](./TestPlan_TrainingModule.md)
|
||||
- [API接口文档](http://localhost:8080/swagger-ui.html)
|
||||
@@ -1,449 +0,0 @@
|
||||
# BUG分析报告 - 模块二:知识库
|
||||
|
||||
> 分析日期:2026-01-12
|
||||
> 分析人员:Java高级工程师
|
||||
> 关联测试报告:TestReport_2.0_Knowledge.md
|
||||
> 产品文档版本:PRD V1.0
|
||||
|
||||
---
|
||||
|
||||
## 一、报告概述
|
||||
|
||||
本报告针对知识库模块测试报告(TestReport_2.0_Knowledge.md)中发现的3个缺陷进行深度分析,明确BUG产生的根本原因,并提供具体的解决方案。
|
||||
|
||||
### 缺陷汇总
|
||||
|
||||
| 缺陷编号 | 缺陷名称 | 严重程度 | 优先级 | 影响范围 |
|
||||
|---------|---------|---------|--------|---------|
|
||||
| BUG-KM-001 | 创建知识时creator_id未设置 | **阻断** | P0 | 15个用例被阻塞 |
|
||||
| BUG-KM-002 | 讲师可以操作其他部门的分类 | 高 | P1 | 部门数据隔离失效 |
|
||||
| BUG-KM-003 | 文件上传功能异常 | 高 | P1 | 知识文档无法上传 |
|
||||
|
||||
---
|
||||
|
||||
## 二、缺陷详细分析
|
||||
|
||||
### 2.1 BUG-KM-001:创建知识时creator_id未设置
|
||||
|
||||
#### 基本信息
|
||||
|
||||
| 属性 | 描述 |
|
||||
|------|------|
|
||||
| 缺陷编号 | BUG-KM-001 |
|
||||
| 严重程度 | **阻断(Blocker)** |
|
||||
| 优先级 | P0 - 立即修复 |
|
||||
| 错误信息 | `Field 'creator_id' doesn't have a default value` |
|
||||
| 影响范围 | 知识创建功能完全不可用,阻塞15个测试用例 |
|
||||
|
||||
#### 原因分析
|
||||
|
||||
**1. 数据库设计约束**
|
||||
|
||||
根据PRD文档第5.1节"知识(km_knowledge)"实体定义:
|
||||
|
||||
```
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| creator_id | Long | 创建人 |
|
||||
```
|
||||
|
||||
`creator_id` 是必填字段(NOT NULL),用于记录知识的创建人ID。
|
||||
|
||||
**2. 业务逻辑缺失**
|
||||
|
||||
在 `KnowledgeServiceImpl.createKnowledge()` 方法中存在以下问题:
|
||||
|
||||
- **未从认证上下文获取用户ID**:方法没有从当前登录用户的JWT Token或SecurityContext中提取用户ID
|
||||
- **直接透传前端数据**:将前端传入的DTO直接转换为实体保存,未补充后端自动填充的字段
|
||||
- **违反业务规则**:PRD要求"知识"必须有创建人,用于追溯和权限控制
|
||||
|
||||
**3. 根本原因**
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ 请求流程分析 │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 前端请求 │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ Controller层 ────────────────────────────────────────────── │
|
||||
│ │ 接收KnowledgeDTO(不含creator_id) │
|
||||
│ ▼ │
|
||||
│ Service层 ───────────────────────────────────────────────── │
|
||||
│ │ ❌ 未从SecurityContext获取当前用户ID │
|
||||
│ │ ❌ 未设置 knowledge.setCreatorId(userId) │
|
||||
│ ▼ │
|
||||
│ Mapper层 ────────────────────────────────────────────────── │
|
||||
│ │ 执行INSERT语句 │
|
||||
│ ▼ │
|
||||
│ MySQL ───────────────────────────────────────────────────── │
|
||||
│ │ creator_id字段为NULL,违反NOT NULL约束 │
|
||||
│ ▼ │
|
||||
│ ❌ 抛出异常:Field 'creator_id' doesn't have a default value │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
#### 解决方案
|
||||
|
||||
**方案一:在Service层补充用户ID设置(推荐)**
|
||||
|
||||
修改位置:`KnowledgeServiceImpl.createKnowledge()` 方法
|
||||
|
||||
修改逻辑:
|
||||
1. 注入 `HttpServletRequest` 或创建 `SecurityUtil` 工具类
|
||||
2. 从JWT Token中解析当前登录用户ID
|
||||
3. 在保存实体前设置 `knowledge.setCreatorId(currentUserId)`
|
||||
4. 同时设置 `knowledge.setDepartmentId(userDepartmentId)` 确保部门隔离
|
||||
|
||||
**方案二:使用MyBatis Plus自动填充**
|
||||
|
||||
配置 `MetaObjectHandler` 实现字段自动填充:
|
||||
1. 在 `creator_id` 字段上添加 `@TableField(fill = FieldFill.INSERT)` 注解
|
||||
2. 实现 `MetaObjectHandler.insertFill()` 方法,自动填充创建人ID
|
||||
|
||||
**推荐方案**:方案一,显式设置更清晰,便于维护和调试。
|
||||
|
||||
---
|
||||
|
||||
### 2.2 BUG-KM-002:讲师可以操作其他部门的分类
|
||||
|
||||
#### 基本信息
|
||||
|
||||
| 属性 | 描述 |
|
||||
|------|------|
|
||||
| 缺陷编号 | BUG-KM-002 |
|
||||
| 严重程度 | 高(High) |
|
||||
| 优先级 | P1 - 紧急修复 |
|
||||
| 缺陷类型 | 安全漏洞 / 权限控制缺陷 |
|
||||
| 影响范围 | 部门数据隔离完全失效 |
|
||||
|
||||
#### 原因分析
|
||||
|
||||
**1. PRD业务规则**
|
||||
|
||||
根据PRD文档第4.1节"权限规则":
|
||||
|
||||
```
|
||||
讲师:
|
||||
├── 管理本部门知识库(上传/编辑/删除)
|
||||
├── 管理本部门题库(增删改查)
|
||||
...
|
||||
```
|
||||
|
||||
根据PRD文档第4.4节"数据隔离规则":
|
||||
|
||||
| 数据类型 | 隔离方式 |
|
||||
|----------|----------|
|
||||
| 知识库 | 按部门隔离,只能看本部门 |
|
||||
| 题库 | 按部门隔离,讲师只能操作本部门 |
|
||||
|
||||
**2. 权限校验缺失**
|
||||
|
||||
`CategoryService` 和 `CategoryController` 中没有实现以下校验逻辑:
|
||||
|
||||
- 未校验当前用户角色(管理员 vs 讲师)
|
||||
- 未校验请求中的 `departmentId` 与当前用户所属部门是否一致
|
||||
- 直接信任前端传入的 `departmentId` 参数
|
||||
|
||||
**3. 根本原因**
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ 权限校验缺失分析 │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 讲师(部门1)发起请求 │
|
||||
│ │ │
|
||||
│ │ POST /api/knowledge/category │
|
||||
│ │ Body: { "name": "xxx", "departmentId": 2 } ← 伪造部门 │
|
||||
│ ▼ │
|
||||
│ Controller层 ────────────────────────────────────────────── │
|
||||
│ │ ❌ 未校验用户角色 │
|
||||
│ │ ❌ 未校验departmentId权限 │
|
||||
│ ▼ │
|
||||
│ Service层 ───────────────────────────────────────────────── │
|
||||
│ │ ❌ 直接保存,未做部门隔离校验 │
|
||||
│ ▼ │
|
||||
│ 数据库 ──────────────────────────────────────────────────── │
|
||||
│ │ 分类创建成功,department_id = 2 │
|
||||
│ ▼ │
|
||||
│ ❌ 安全漏洞:讲师越权操作其他部门数据 │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
#### 解决方案
|
||||
|
||||
**方案一:Service层统一校验(推荐)**
|
||||
|
||||
在 `CategoryServiceImpl` 中增加部门权限校验:
|
||||
|
||||
```
|
||||
校验逻辑伪代码:
|
||||
1. 获取当前用户信息(ID、角色、部门ID)
|
||||
2. IF 角色 == ADMIN:
|
||||
允许操作任意部门
|
||||
ELSE IF 角色 == LECTURER:
|
||||
IF 请求的departmentId != 用户的departmentId:
|
||||
抛出异常:"无权操作其他部门数据"
|
||||
END IF
|
||||
END IF
|
||||
3. 继续执行业务逻辑
|
||||
```
|
||||
|
||||
**方案二:AOP切面统一拦截**
|
||||
|
||||
创建 `@DepartmentIsolation` 注解 + 切面类:
|
||||
1. 在需要部门隔离的方法上添加注解
|
||||
2. 切面自动校验当前用户部门与请求部门是否一致
|
||||
|
||||
**方案三:封装通用工具方法**
|
||||
|
||||
创建 `DepartmentPermissionUtil.checkPermission(Long targetDepartmentId)` 方法:
|
||||
- 供各模块(知识库、题库、试卷等)复用
|
||||
- 统一的异常处理和错误提示
|
||||
|
||||
**推荐方案**:方案一 + 方案三结合,在Service层显式调用校验方法,逻辑清晰,便于维护。
|
||||
|
||||
---
|
||||
|
||||
### 2.3 BUG-KM-003:文件上传功能异常
|
||||
|
||||
#### 基本信息
|
||||
|
||||
| 属性 | 描述 |
|
||||
|------|------|
|
||||
| 缺陷编号 | BUG-KM-003 |
|
||||
| 严重程度 | 高(High) |
|
||||
| 优先级 | P1 - 紧急修复 |
|
||||
| 错误码 | 1501 |
|
||||
| 错误信息 | `{"code":1501,"message":"文件保存失败"}` |
|
||||
| 影响范围 | 所有文档/视频上传功能不可用 |
|
||||
|
||||
#### 原因分析
|
||||
|
||||
**1. 可能原因一:配置问题**
|
||||
|
||||
`application.yml` 或 `application-dev.yml` 中文件上传路径配置问题:
|
||||
- 路径未配置
|
||||
- 路径配置错误(如使用了Linux路径分隔符但运行在Windows环境)
|
||||
- 使用了相对路径但基准目录不正确
|
||||
|
||||
**2. 可能原因二:目录不存在**
|
||||
|
||||
配置的上传目录在服务器/本地环境中不存在:
|
||||
- 开发环境与生产环境路径不一致
|
||||
- 服务首次启动时未自动创建目录
|
||||
|
||||
**3. 可能原因三:权限不足**
|
||||
|
||||
应用程序对目标目录没有写入权限:
|
||||
- Linux环境下目录权限设置不正确
|
||||
- Windows环境下目录被其他程序占用或权限受限
|
||||
|
||||
**4. 可能原因四:代码健壮性问题**
|
||||
|
||||
`FileService` 实现中缺少健壮性处理:
|
||||
- 未在保存文件前检查/创建目录
|
||||
- 异常处理过于笼统,丢失了原始错误信息
|
||||
|
||||
**5. 根本原因推测**
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ 文件上传失败分析 │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 上传请求 │
|
||||
│ │ │
|
||||
│ │ POST /api/file/upload/document │
|
||||
│ │ Content-Type: multipart/form-data │
|
||||
│ ▼ │
|
||||
│ FileController ──────────────────────────────────────────── │
|
||||
│ │ 接收MultipartFile │
|
||||
│ ▼ │
|
||||
│ FileService ─────────────────────────────────────────────── │
|
||||
│ │ 读取配置的上传路径 │
|
||||
│ │ 拼接完整文件路径 │
|
||||
│ ▼ │
|
||||
│ 文件系统 ────────────────────────────────────────────────── │
|
||||
│ │ │
|
||||
│ │ ❌ 可能问题1:目录不存在 │
|
||||
│ │ ❌ 可能问题2:无写入权限 │
|
||||
│ │ ❌ 可能问题3:路径格式错误 │
|
||||
│ ▼ │
|
||||
│ 抛出IOException → 捕获后返回统一错误码1501 │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
#### 解决方案
|
||||
|
||||
**步骤一:检查配置文件**
|
||||
|
||||
检查 `application.yml` 和 `application-dev.yml`:
|
||||
|
||||
```yaml
|
||||
# 期望的配置格式示例
|
||||
file:
|
||||
upload:
|
||||
path: D:/upload/training-system/ # Windows
|
||||
# path: /data/upload/training-system/ # Linux
|
||||
max-size: 100MB
|
||||
allowed-types: pdf,doc,docx,xls,xlsx,ppt,pptx,mp4,avi
|
||||
```
|
||||
|
||||
**步骤二:检查FileService实现**
|
||||
|
||||
确保在保存文件前创建目录:
|
||||
|
||||
```
|
||||
伪代码:
|
||||
1. 获取配置的上传路径 uploadPath
|
||||
2. 生成唯一文件名(如:UUID + 原始扩展名)
|
||||
3. 拼接完整路径 fullPath = uploadPath + "/" + fileName
|
||||
4. 获取父目录 parentDir = fullPath.getParent()
|
||||
5. IF 父目录不存在:
|
||||
创建目录(包含所有父目录)
|
||||
END IF
|
||||
6. 保存文件到 fullPath
|
||||
7. 返回文件访问URL
|
||||
```
|
||||
|
||||
**步骤三:增加详细日志**
|
||||
|
||||
在FileService中增加关键日志输出:
|
||||
|
||||
```
|
||||
日志内容:
|
||||
- [INFO] 配置的上传路径: {uploadPath}
|
||||
- [INFO] 生成的文件名: {fileName}
|
||||
- [INFO] 完整保存路径: {fullPath}
|
||||
- [ERROR] 文件保存失败: {具体异常信息和堆栈}
|
||||
```
|
||||
|
||||
**步骤四:检查目录权限**
|
||||
|
||||
- **Linux环境**:
|
||||
```bash
|
||||
mkdir -p /data/upload/training-system
|
||||
chown -R tomcat:tomcat /data/upload
|
||||
chmod -R 755 /data/upload
|
||||
```
|
||||
|
||||
- **Windows环境**:
|
||||
确保运行Java应用的用户对目标目录有完全控制权限
|
||||
|
||||
**步骤五:启动时自动创建目录**
|
||||
|
||||
在应用启动时(如 `@PostConstruct` 方法)检查并创建上传目录:
|
||||
|
||||
```
|
||||
伪代码:
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
File uploadDir = new File(uploadPath);
|
||||
if (!uploadDir.exists()) {
|
||||
boolean created = uploadDir.mkdirs();
|
||||
log.info("创建上传目录: {}, 结果: {}", uploadPath, created);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、修复优先级与建议
|
||||
|
||||
### 3.1 修复优先级
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────────────────┐
|
||||
│ 修复优先级路线图 │
|
||||
├──────────────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 优先级1 ───────────────────────────────────────────────────────────── │
|
||||
│ │ │
|
||||
│ │ BUG-KM-001: creator_id未设置 │
|
||||
│ │ 原因: 阻断级缺陷,整个知识创建功能不可用 │
|
||||
│ │ 影响: 15个测试用例被阻塞 │
|
||||
│ │ 建议: 立即修复,修复后重新执行全部阻塞用例 │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ 优先级2 ───────────────────────────────────────────────────────────── │
|
||||
│ │ │
|
||||
│ │ BUG-KM-003: 文件上传失败 │
|
||||
│ │ 原因: 知识库核心功能依赖文件上传 │
|
||||
│ │ 影响: 无法上传文档和视频 │
|
||||
│ │ 建议: 紧急修复,排查配置和目录权限问题 │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ 优先级3 ───────────────────────────────────────────────────────────── │
|
||||
│ │ │
|
||||
│ │ BUG-KM-002: 部门隔离未实现 │
|
||||
│ │ 原因: 安全漏洞,违反业务规则 │
|
||||
│ │ 影响: 讲师可越权操作其他部门数据 │
|
||||
│ │ 建议: 紧急修复,需全面审查相关模块 │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ 回归测试 ──────────────────────────────────────────────────────────── │
|
||||
│ │
|
||||
└──────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 3.2 风险提示
|
||||
|
||||
| 风险点 | 说明 | 建议 |
|
||||
|--------|------|------|
|
||||
| 同类缺陷 | 其他模块(考试、培训计划)可能存在相同的 `creator_id` 未设置问题 | 修复时同步审查相关模块 |
|
||||
| 部门隔离 | 题库、试卷、考试模块可能也缺少部门隔离校验 | 建议封装统一的部门权限校验工具 |
|
||||
| 配置管理 | 文件上传路径在不同环境可能不一致 | 使用环境变量或配置中心管理 |
|
||||
|
||||
### 3.3 测试建议
|
||||
|
||||
修复完成后需执行以下测试:
|
||||
|
||||
1. **BUG-KM-001修复后**:
|
||||
- 重新执行KS系列全部8个用例
|
||||
- 重新执行KD系列全部4个用例
|
||||
- 重新执行KC-003用例
|
||||
|
||||
2. **BUG-KM-002修复后**:
|
||||
- 重新执行KC-004用例
|
||||
- 新增测试用例:验证管理员可操作所有部门
|
||||
- 新增测试用例:验证学员无法创建分类
|
||||
|
||||
3. **BUG-KM-003修复后**:
|
||||
- 重新执行KM系列全部7个用例
|
||||
- 测试不同文件类型(PDF、Word、Excel、PPT、视频)
|
||||
- 测试边界条件(大文件、空文件、特殊字符文件名)
|
||||
|
||||
---
|
||||
|
||||
## 四、总结
|
||||
|
||||
### 4.1 缺陷共性分析
|
||||
|
||||
本次知识库模块测试发现的3个缺陷存在共同特点:
|
||||
|
||||
| 共性问题 | 具体表现 | 改进建议 |
|
||||
|---------|---------|---------|
|
||||
| **后端逻辑不完善** | 未实现PRD要求的业务规则 | 开发前充分理解PRD,Code Review时对照检查 |
|
||||
| **安全意识不足** | 部门隔离未实现,信任前端参数 | 后端必须校验所有涉及权限的参数 |
|
||||
| **健壮性欠缺** | 文件上传未处理目录不存在的情况 | 增加防御性编程,完善异常处理 |
|
||||
|
||||
### 4.2 后续行动项
|
||||
|
||||
- [ ] 修复BUG-KM-001:补充creator_id设置逻辑
|
||||
- [ ] 修复BUG-KM-002:实现部门隔离校验
|
||||
- [ ] 修复BUG-KM-003:排查并修复文件上传问题
|
||||
- [ ] 审查其他模块是否存在同类问题
|
||||
- [ ] 封装通用的部门权限校验工具类
|
||||
- [ ] 回归测试验证修复效果
|
||||
|
||||
---
|
||||
|
||||
**报告生成时间**:2026-01-12
|
||||
|
||||
**审核状态**:待修复
|
||||
@@ -1,217 +0,0 @@
|
||||
# 复测报告 - 模块1.3:员工管理
|
||||
|
||||
> 复测日期:2026-01-09
|
||||
> 测试人员:AI测试工程师
|
||||
> 测试环境:Spring Boot 3.1.2 / MySQL 8.0 / JDK 17
|
||||
> 原始测试报告:TestReport_1.3_UserManagement.md
|
||||
|
||||
---
|
||||
|
||||
## 一、复测概要
|
||||
|
||||
| 项目 | 数值 |
|
||||
|------|------|
|
||||
| 原始缺陷数 | 3 |
|
||||
| 复测通过 | 2 |
|
||||
| 复测失败 | 1 |
|
||||
| **修复率** | **66.7%** |
|
||||
|
||||
---
|
||||
|
||||
## 二、缺陷复测结果
|
||||
|
||||
| 缺陷编号 | 严重程度 | 描述 | 复测结果 |
|
||||
|---------|---------|------|---------|
|
||||
| BUG-USER-001 | 中 | 手机号未做唯一性校验 | ✅ **通过** |
|
||||
| BUG-USER-002 | 高 | 讲师未实现部门数据隔离 | ❌ **失败** |
|
||||
| BUG-USER-003 | 严重 | 学员可访问员工管理接口 | ✅ **通过** |
|
||||
|
||||
---
|
||||
|
||||
## 三、复测详情
|
||||
|
||||
### 3.1 BUG-USER-001:手机号唯一性校验 ✅
|
||||
|
||||
| 属性 | 描述 |
|
||||
|------|------|
|
||||
| 复测结果 | **通过** |
|
||||
| 测试步骤 | 1. 管理员登录<br>2. 使用已存在的手机号`13800138000`创建新员工<br>3. 验证返回结果 |
|
||||
| 预期结果 | 返回错误,提示手机号已存在 |
|
||||
| 实际结果 | 返回 `{"code":1005,"message":"手机号已存在"}` |
|
||||
| 验证时间 | 2026-01-09 15:55:44 |
|
||||
|
||||
**测试请求:**
|
||||
```bash
|
||||
POST /api/system/user
|
||||
{
|
||||
"username": "duplicate_phone_test",
|
||||
"password": "Test@123",
|
||||
"realName": "DuplicatePhoneTest",
|
||||
"phone": "13800138000", # 与admin重复
|
||||
"role": "STUDENT",
|
||||
"departmentId": 1
|
||||
}
|
||||
```
|
||||
|
||||
**测试响应:**
|
||||
```json
|
||||
{
|
||||
"code": 1005,
|
||||
"message": "手机号已存在",
|
||||
"timestamp": 1767945744357,
|
||||
"success": false
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.2 BUG-USER-002:讲师部门数据隔离 ❌
|
||||
|
||||
| 属性 | 描述 |
|
||||
|------|------|
|
||||
| 复测结果 | **失败** |
|
||||
| 测试步骤 | 1. 讲师账号登录(救援一部,departmentId=1)<br>2. 访问员工管理分页接口<br>3. 验证返回的员工列表 |
|
||||
| 预期结果 | 只返回救援一部的员工(5人) |
|
||||
| 实际结果 | 返回全部7个员工,包含救援二部的admin和zhangsan |
|
||||
| 验证时间 | 2026-01-09 15:56:02 |
|
||||
|
||||
**测试请求:**
|
||||
```bash
|
||||
GET /api/system/user/page?current=1&size=10
|
||||
Authorization: Bearer {test_lecturer_token}
|
||||
```
|
||||
|
||||
**测试响应(关键数据):**
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"data": {
|
||||
"total": 7,
|
||||
"records": [
|
||||
{"id": 7, "realName": "TestLecturer", "departmentName": "救援一部"},
|
||||
{"id": 6, "realName": "TestAdmin", "departmentName": "救援一部"},
|
||||
{"id": 5, "realName": "TestUser002", "departmentName": "救援一部"},
|
||||
{"id": 4, "realName": "TestUser001", "departmentName": "救援一部"},
|
||||
{"id": 3, "realName": "讲师", "departmentName": "救援一部"},
|
||||
{"id": 2, "realName": "张三", "departmentName": "救援二部"}, // ❌ 不应返回
|
||||
{"id": 1, "realName": "系统管理员", "departmentName": "救援二部"} // ❌ 不应返回
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**问题分析:**
|
||||
讲师查询员工列表时,后端未根据当前用户的部门ID过滤数据,导致讲师可以看到所有部门的员工信息。
|
||||
|
||||
**修复建议:**
|
||||
在 `UserServiceImpl.page()` 方法中,当当前用户角色为 `LECTURER` 时,自动在查询条件中添加部门过滤:
|
||||
```java
|
||||
if (currentUser.getRole() == Role.LECTURER) {
|
||||
queryWrapper.eq("department_id", currentUser.getDepartmentId());
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.3 BUG-USER-003:学员访问权限控制 ✅
|
||||
|
||||
| 属性 | 描述 |
|
||||
|------|------|
|
||||
| 复测结果 | **通过** |
|
||||
| 测试步骤 | 1. 学员账号登录<br>2. 访问员工管理分页接口<br>3. 验证返回结果 |
|
||||
| 预期结果 | 返回403 Forbidden |
|
||||
| 实际结果 | 返回 `{"code":403,"message":"没有操作权限"}` |
|
||||
| 验证时间 | 2026-01-09 15:56:22 |
|
||||
|
||||
**测试请求:**
|
||||
```bash
|
||||
GET /api/system/user/page?current=1&size=10
|
||||
Authorization: Bearer {test_user_001_token}
|
||||
```
|
||||
|
||||
**测试响应:**
|
||||
```json
|
||||
{
|
||||
"code": 403,
|
||||
"message": "没有操作权限",
|
||||
"timestamp": 1767945782146,
|
||||
"success": false
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、回归测试(原通过用例确认)
|
||||
|
||||
为确保修复未引入新问题,对原测试报告中通过的4个用例进行回归验证:
|
||||
|
||||
| 用例编号 | 测试项 | 回归结果 |
|
||||
|---------|--------|---------|
|
||||
| USER-001 | 创建员工(有效数据) | ✅ 通过(新员工创建正常) |
|
||||
| USER-003 | 启用/禁用员工 | ✅ 通过(状态切换正常) |
|
||||
| USER-004 | 编辑员工信息 | ✅ 通过(编辑功能正常) |
|
||||
| USER-005 | 删除员工 | ✅ 通过(删除功能正常) |
|
||||
|
||||
---
|
||||
|
||||
## 五、测试结论
|
||||
|
||||
### 5.1 复测结果总结
|
||||
|
||||
| 评估项 | 结果 |
|
||||
|--------|------|
|
||||
| 缺陷修复率 | 66.7%(2/3) |
|
||||
| P0级缺陷修复 | 1/1 已修复 |
|
||||
| P1级缺陷修复 | 0/1 未修复 |
|
||||
| P2级缺陷修复 | 1/1 已修复 |
|
||||
| 回归测试 | 全部通过(无新增问题) |
|
||||
|
||||
### 5.2 遗留问题
|
||||
|
||||
| 缺陷编号 | 严重程度 | 状态 | 说明 |
|
||||
|---------|---------|------|------|
|
||||
| BUG-USER-002 | 高 | **待修复** | 讲师部门数据隔离仍未实现 |
|
||||
|
||||
### 5.3 模块状态评估
|
||||
|
||||
| 功能项 | 状态 |
|
||||
|--------|------|
|
||||
| 员工CRUD基本功能 | ✅ 可用 |
|
||||
| 数据唯一性校验 | ✅ 已实现 |
|
||||
| 学员权限控制 | ✅ 已实现 |
|
||||
| 讲师数据隔离 | ❌ 未实现 |
|
||||
|
||||
### 5.4 建议
|
||||
|
||||
1. **BUG-USER-002 需要继续修复**
|
||||
- 问题影响:讲师可查看其他部门员工信息,违反PRD中的数据隔离要求
|
||||
- 安全风险:中等(信息泄露)
|
||||
- 建议优先级:P1
|
||||
|
||||
2. **建议扩展验证**
|
||||
- 修复后同时验证讲师创建/编辑/删除员工时的部门隔离是否生效
|
||||
|
||||
---
|
||||
|
||||
## 六、附录
|
||||
|
||||
### 6.1 测试账号
|
||||
|
||||
| 账号 | 角色 | 部门 |
|
||||
|------|------|------|
|
||||
| admin | ADMIN | 救援二部 |
|
||||
| test_lecturer | LECTURER | 救援一部 |
|
||||
| test_user_001 | STUDENT | 救援一部 |
|
||||
|
||||
### 6.2 相关文档
|
||||
|
||||
| 文档 | 路径 |
|
||||
|------|------|
|
||||
| 原始测试报告 | docs/test-reports/TestReport_1.3_UserManagement.md |
|
||||
| 产品需求文档 | docs/PRD.md |
|
||||
|
||||
---
|
||||
|
||||
**报告生成时间:** 2026-01-09 15:58:00
|
||||
|
||||
**报告签发:** AI测试工程师
|
||||
@@ -1,374 +0,0 @@
|
||||
1# 复测报告 - 模块1.3:员工管理(V2)
|
||||
|
||||
> 复测日期:2026-01-09
|
||||
> 测试人员:AI测试工程师
|
||||
> 测试环境:Spring Boot 3.1.2 / MySQL 8.0 / JDK 17
|
||||
> 原始测试报告:TestReport_1.3_UserManagement.md
|
||||
> 版本:V2(补充深度测试)
|
||||
|
||||
---
|
||||
|
||||
## 一、复测概要
|
||||
|
||||
| 项目 | 数值 |
|
||||
|------|------|
|
||||
| 原始缺陷数 | 3 |
|
||||
| 复测通过 | 2 |
|
||||
| 复测失败 | 1 |
|
||||
| **新发现问题** | **2** |
|
||||
| **修复率** | **66.7%** |
|
||||
|
||||
---
|
||||
|
||||
## 二、原始缺陷复测结果
|
||||
|
||||
| 缺陷编号 | 严重程度 | 描述 | 复测结果 |
|
||||
|---------|---------|------|---------|
|
||||
| BUG-USER-001 | 中 | 手机号未做唯一性校验 | ✅ **通过** |
|
||||
| BUG-USER-002 | 高 | 讲师未实现部门数据隔离 | ❌ **失败** |
|
||||
| BUG-USER-003 | 严重 | 学员可访问员工管理接口 | ✅ **通过** |
|
||||
|
||||
---
|
||||
|
||||
## 三、深度测试发现的新问题
|
||||
|
||||
### 3.1 BUG-USER-004:编辑员工时无法修改状态(后端Bug,非前端问题)
|
||||
|
||||
| 属性 | 描述 |
|
||||
|------|------|
|
||||
| 缺陷编号 | BUG-USER-004 |
|
||||
| 严重程度 | **高** |
|
||||
| 优先级 | P1 |
|
||||
| 缺陷类型 | **后端Bug** |
|
||||
| 缺陷描述 | 通过编辑员工接口(PUT /api/system/user)传入status字段,接口返回成功,但状态未被更新 |
|
||||
| 重现步骤 | 1. 管理员登录<br>2. 前端编辑员工,状态选择"禁用"<br>3. 点击保存,提示"保存成功"<br>4. 刷新页面,状态仍为"启用" |
|
||||
| 预期结果 | 员工状态变为"禁用" |
|
||||
| 实际结果 | 员工状态仍为"启用",状态修改被静默忽略 |
|
||||
| 根因分析 | **后端问题**:UserDTO类中没有定义status字段,updateUser()方法也未处理状态更新 |
|
||||
| 影响范围 | 前端编辑表单中的状态选择功能完全无效,用户体验严重受损 |
|
||||
|
||||
#### 前端代码验证 ✅
|
||||
|
||||
前端代码**正确传递了status字段**(user.html:139):
|
||||
```javascript
|
||||
const data = {
|
||||
realName: ...,
|
||||
phone: ...,
|
||||
username: ...,
|
||||
departmentId: ...,
|
||||
groupId: ...,
|
||||
role: ...,
|
||||
status: document.getElementById('formStatus').value // ✅ 前端正确传递
|
||||
};
|
||||
```
|
||||
|
||||
#### 问题定位
|
||||
|
||||
| 层级 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| 前端页面 | ✅ 正常 | 有状态选择下拉框,正确绑定值 |
|
||||
| 前端JS | ✅ 正常 | saveData()正确收集status并发送 |
|
||||
| 后端DTO | ❌ 缺失 | UserDTO没有status字段,Jackson忽略该值 |
|
||||
| 后端Service | ❌ 未处理 | updateUser()没有setStatus()调用 |
|
||||
|
||||
**测试请求:**
|
||||
```bash
|
||||
PUT /api/system/user
|
||||
Content-Type: application/json
|
||||
{
|
||||
"id": 5,
|
||||
"username": "test_user_002",
|
||||
"realName": "TestUser002",
|
||||
"phone": "13800138001",
|
||||
"role": "STUDENT",
|
||||
"departmentId": 1,
|
||||
"status": "DISABLED" // 尝试修改状态
|
||||
}
|
||||
```
|
||||
|
||||
**测试响应:**
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "操作成功",
|
||||
"success": true
|
||||
}
|
||||
```
|
||||
|
||||
**验证查询结果:**
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"id": 5,
|
||||
"status": "ENABLED", // 状态未改变!
|
||||
"statusName": "启用"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**修复建议(二选一):**
|
||||
|
||||
**方案A:在UserDTO中添加status字段**
|
||||
```java
|
||||
// UserDTO.java
|
||||
private String status;
|
||||
|
||||
// UserServiceImpl.updateUser()
|
||||
if (StrUtil.isNotBlank(dto.getStatus())) {
|
||||
user.setStatus(UserStatus.valueOf(dto.getStatus()));
|
||||
}
|
||||
```
|
||||
|
||||
**方案B:明确API设计,状态修改只能通过专用接口**
|
||||
- 保持现有设计,状态只能通过 `/enable` 和 `/disable` 接口修改
|
||||
- 但需在API文档中明确说明
|
||||
- 前端编辑表单应隐藏或禁用状态选项
|
||||
|
||||
---
|
||||
|
||||
### 3.2 BUG-USER-002 根因深入分析
|
||||
|
||||
**问题:** 讲师部门数据隔离未生效
|
||||
|
||||
**代码追踪:**
|
||||
|
||||
1. **Service层代码正确**(UserServiceImpl.java:397-406)
|
||||
```java
|
||||
private void applyDepartmentIsolation(LambdaQueryWrapper<User> queryWrapper) {
|
||||
UserContext currentUser = UserContextHolder.getContext();
|
||||
if (currentUser != null && UserRole.LECTURER.name().equals(currentUser.getRole())) {
|
||||
if (currentUser.getDepartmentId() != null) { // 问题:departmentId为null
|
||||
queryWrapper.eq(User::getDepartmentId, currentUser.getDepartmentId());
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. **问题根源**(JwtUtils.java:37-48)
|
||||
```java
|
||||
public String generateToken(Long userId, String username, String role) {
|
||||
return JWT.create()
|
||||
.withSubject(String.valueOf(userId))
|
||||
.withClaim("username", username)
|
||||
.withClaim("role", role) // 只有这三个字段!
|
||||
.withIssuedAt(now)
|
||||
.withExpiresAt(expireDate)
|
||||
.sign(Algorithm.HMAC256(secret));
|
||||
}
|
||||
// 没有包含 departmentId!
|
||||
```
|
||||
|
||||
3. **AuthInterceptor尝试获取但失败**(AuthInterceptor.java:68-70)
|
||||
```java
|
||||
if (jwt.getClaim("departmentId") != null && !jwt.getClaim("departmentId").isNull()) {
|
||||
context.setDepartmentId(jwt.getClaim("departmentId").asLong());
|
||||
}
|
||||
// 由于JWT中没有departmentId,这段代码不会执行
|
||||
```
|
||||
|
||||
**修复建议:**
|
||||
|
||||
修改 `JwtUtils.generateToken()` 方法,添加 departmentId 参数:
|
||||
```java
|
||||
public String generateToken(Long userId, String username, String role, Long departmentId) {
|
||||
return JWT.create()
|
||||
.withSubject(String.valueOf(userId))
|
||||
.withClaim("username", username)
|
||||
.withClaim("role", role)
|
||||
.withClaim("departmentId", departmentId) // 新增
|
||||
.withIssuedAt(now)
|
||||
.withExpiresAt(expireDate)
|
||||
.sign(Algorithm.HMAC256(secret));
|
||||
}
|
||||
```
|
||||
|
||||
同时修改 `AuthServiceImpl.login()` 方法,传入 departmentId。
|
||||
|
||||
---
|
||||
|
||||
## 四、重置密码功能验证 ✅
|
||||
|
||||
| 属性 | 描述 |
|
||||
|------|------|
|
||||
| 测试结果 | **通过** |
|
||||
| 测试步骤 | 1. 管理员调用重置密码接口<br>2. 使用新密码登录<br>3. 使用旧密码登录 |
|
||||
| 实际结果 | 新密码登录成功,旧密码登录失败(返回1003密码错误) |
|
||||
|
||||
**测试详情:**
|
||||
|
||||
```bash
|
||||
# 重置密码
|
||||
PUT /api/system/user/password/reset
|
||||
{"userId": 5, "newPassword": "NewPass@123"}
|
||||
Response: {"code": 200, "message": "操作成功"}
|
||||
|
||||
# 新密码登录
|
||||
POST /api/auth/login
|
||||
{"username": "test_user_002", "password": "NewPass@123"}
|
||||
Response: {"code": 200, "data": {"token": "..."}} ✅
|
||||
|
||||
# 旧密码登录(验证旧密码失效)
|
||||
POST /api/auth/login
|
||||
{"username": "test_user_002", "password": "Test@123"}
|
||||
Response: {"code": 1003, "message": "密码错误"} ✅
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、禁用/启用功能验证 ✅
|
||||
|
||||
| 属性 | 描述 |
|
||||
|------|------|
|
||||
| 测试结果 | **通过**(仅限专用接口) |
|
||||
| 测试步骤 | 1. 调用 PUT /api/system/user/{id}/disable<br>2. 查询用户状态<br>3. 调用 PUT /api/system/user/{id}/enable<br>4. 查询用户状态 |
|
||||
| 实际结果 | 专用接口可正常切换状态 |
|
||||
|
||||
**测试详情:**
|
||||
|
||||
```bash
|
||||
# 禁用用户
|
||||
PUT /api/system/user/5/disable
|
||||
Response: {"code": 200, "message": "操作成功"}
|
||||
|
||||
# 验证状态
|
||||
GET /api/system/user/5
|
||||
Response: {"data": {"status": "DISABLED", "statusName": "禁用"}} ✅
|
||||
|
||||
# 启用用户
|
||||
PUT /api/system/user/5/enable
|
||||
Response: {"code": 200, "message": "操作成功"}
|
||||
|
||||
# 验证状态
|
||||
GET /api/system/user/5
|
||||
Response: {"data": {"status": "ENABLED", "statusName": "启用"}} ✅
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、漏测原因分析
|
||||
|
||||
### 6.1 为什么会漏测"编辑状态"功能?
|
||||
|
||||
| 原因类型 | 具体分析 |
|
||||
|---------|---------|
|
||||
| **测试用例设计不完整** | 原测试计划只验证了"启用/禁用"功能是否存在,但没有验证"通过编辑接口修改状态"的场景 |
|
||||
| **测试路径覆盖不足** | 系统提供了两种修改状态的路径:1) 专用接口 2) 编辑接口。只测试了路径1 |
|
||||
| **接口返回值未深入验证** | 编辑接口返回200成功,测试人员信任了返回值而没有二次查询确认 |
|
||||
| **前后端交互场景遗漏** | 没有模拟前端表单的实际交互流程,即"编辑时同时修改状态" |
|
||||
|
||||
### 6.2 为什么会漏测"重置密码验证"?
|
||||
|
||||
| 原因类型 | 具体分析 |
|
||||
|---------|---------|
|
||||
| **验证不完整** | 原测试只验证了接口返回200,没有验证密码是否真的被修改 |
|
||||
| **缺少端到端验证** | 应该用新密码登录验证,同时用旧密码登录确认失效 |
|
||||
|
||||
### 6.3 为什么BUG-USER-002未修复但代码似乎已添加?
|
||||
|
||||
| 原因类型 | 具体分析 |
|
||||
|---------|---------|
|
||||
| **修复不完整** | 开发在Service层添加了部门隔离逻辑,但忽略了JWT中缺少departmentId |
|
||||
| **缺少集成测试** | 单元测试可能通过(因为可以mock UserContext),但集成测试会失败 |
|
||||
| **代码审查疏漏** | JWT Token生成和解析的链路未被完整审查 |
|
||||
|
||||
### 6.4 改进建议
|
||||
|
||||
1. **测试用例设计改进**
|
||||
- 对于每个字段修改,都要验证"修改前后值确实变化"
|
||||
- 对于多路径功能,所有路径都要测试
|
||||
|
||||
2. **验证方法改进**
|
||||
- 不要只信任接口返回值,要二次查询确认
|
||||
- 对于认证类功能,要进行端到端验证
|
||||
|
||||
3. **增加测试场景**
|
||||
- 正常场景 + 边界场景 + 异常场景
|
||||
- 单接口测试 + 流程测试 + 集成测试
|
||||
|
||||
---
|
||||
|
||||
## 七、缺陷汇总
|
||||
|
||||
### 7.1 现存缺陷清单
|
||||
|
||||
| 缺陷编号 | 严重程度 | 状态 | 描述 | 修复建议位置 |
|
||||
|---------|---------|------|------|-------------|
|
||||
| BUG-USER-002 | 高 | **待修复** | 讲师部门数据隔离未生效 | JwtUtils.java + AuthServiceImpl.java |
|
||||
| BUG-USER-004 | 中 | **新发现** | 编辑接口无法修改状态 | UserDTO.java + UserServiceImpl.java |
|
||||
|
||||
### 7.2 已修复缺陷
|
||||
|
||||
| 缺陷编号 | 严重程度 | 描述 |
|
||||
|---------|---------|------|
|
||||
| BUG-USER-001 | 中 | 手机号唯一性校验 ✅ |
|
||||
| BUG-USER-003 | 严重 | 学员权限控制 ✅ |
|
||||
|
||||
---
|
||||
|
||||
## 八、测试结论
|
||||
|
||||
### 8.1 模块状态评估
|
||||
|
||||
| 功能项 | 状态 | 说明 |
|
||||
|--------|------|------|
|
||||
| 创建员工 | ✅ 可用 | |
|
||||
| 编辑员工(基本信息) | ✅ 可用 | |
|
||||
| 编辑员工(状态) | ⚠️ 部分可用 | 只能通过专用接口修改 |
|
||||
| 删除员工 | ✅ 可用 | |
|
||||
| 重置密码 | ✅ 可用 | |
|
||||
| 启用/禁用(专用接口) | ✅ 可用 | |
|
||||
| 手机号唯一性 | ✅ 已实现 | |
|
||||
| 学员权限控制 | ✅ 已实现 | |
|
||||
| 讲师数据隔离 | ❌ 未实现 | JWT缺少departmentId |
|
||||
|
||||
### 8.2 上线评估
|
||||
|
||||
**结论:建议暂缓上线**
|
||||
|
||||
**原因:**
|
||||
1. BUG-USER-002(讲师数据隔离)为高优先级安全问题,存在信息泄露风险
|
||||
2. 虽然基础CRUD功能可用,但不符合PRD中的数据隔离要求
|
||||
|
||||
### 8.3 修复优先级建议
|
||||
|
||||
| 优先级 | 缺陷编号 | 预计影响 |
|
||||
|--------|---------|---------|
|
||||
| **P0** | BUG-USER-002 | 修复后满足PRD数据隔离要求 |
|
||||
| **P2** | BUG-USER-004 | 改善用户体验,非阻塞性问题 |
|
||||
|
||||
---
|
||||
|
||||
## 九、附录
|
||||
|
||||
### 9.1 测试账号
|
||||
|
||||
| 账号 | 角色 | 部门 |
|
||||
|------|------|------|
|
||||
| admin | ADMIN | 救援二部 |
|
||||
| test_lecturer | LECTURER | 救援一部 |
|
||||
| test_user_001 | STUDENT | 救援一部 |
|
||||
| test_user_002 | STUDENT | 救援一部 |
|
||||
|
||||
### 9.2 相关代码文件
|
||||
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
| UserController.java | 用户管理控制器 |
|
||||
| UserServiceImpl.java | 用户服务实现,包含部门隔离逻辑 |
|
||||
| UserDTO.java | 用户数据传输对象(缺少status字段) |
|
||||
| JwtUtils.java | JWT工具类(缺少departmentId) |
|
||||
| AuthInterceptor.java | 认证拦截器 |
|
||||
|
||||
### 9.3 相关文档
|
||||
|
||||
| 文档 | 路径 |
|
||||
|------|------|
|
||||
| 原始测试报告 | docs/test-reports/TestReport_1.3_UserManagement.md |
|
||||
| 第一版复测报告 | docs/test-reports/RegressionReport_1.3_UserManagement.md |
|
||||
| 产品需求文档 | docs/PRD.md |
|
||||
|
||||
---
|
||||
|
||||
**报告生成时间:** 2026-01-09 16:45:00
|
||||
|
||||
**报告签发:** AI测试工程师
|
||||
@@ -1,157 +0,0 @@
|
||||
# 测试报告 - 1.3 员工管理模块
|
||||
|
||||
> 测试日期:2026-01-09
|
||||
> 测试人员:AI测试工程师
|
||||
> 测试环境:Spring Boot 3.1.2 / MySQL 8.0 / JDK 17
|
||||
|
||||
---
|
||||
|
||||
## 一、测试概要
|
||||
|
||||
| 项目 | 数值 |
|
||||
|------|------|
|
||||
| 测试用例总数 | 7 |
|
||||
| 通过 | 4 |
|
||||
| 失败 | 3 |
|
||||
| 阻塞 | 0 |
|
||||
| 通过率 | 57.1% |
|
||||
|
||||
---
|
||||
|
||||
## 二、测试结果详情
|
||||
|
||||
### 2.1 测试用例执行结果
|
||||
|
||||
| 用例编号 | 测试项 | 预期结果 | 实际结果 | 状态 |
|
||||
|---------|--------|---------|---------|------|
|
||||
| USER-001 | 管理员创建员工 | 成功创建,指定角色和部门 | 创建成功,返回用户ID=4 | **通过** |
|
||||
| USER-002 | 创建重复手机号员工 | 提示"手机号已存在" | 创建成功,未校验手机号唯一性 | **失败** |
|
||||
| USER-003 | 分配角色(ADMIN/LECTURER/STUDENT) | 角色分配成功 | ADMIN/LECTURER/STUDENT三种角色均分配成功 | **通过** |
|
||||
| USER-004 | 禁用员工 | 状态变更为DISABLED | 状态成功变更为DISABLED | **通过** |
|
||||
| USER-005 | 启用员工 | 状态变更为ENABLED | 状态成功变更为ENABLED | **通过** |
|
||||
| USER-006 | 讲师查看本部门员工 | 只能看到本部门 | 可以看到所有部门用户(救援一部+救援二部) | **失败** |
|
||||
| USER-007 | 学员无法访问员工管理 | 返回403 | 返回200,可查看所有用户数据 | **失败** |
|
||||
|
||||
---
|
||||
|
||||
## 三、缺陷清单
|
||||
|
||||
### BUG-001:手机号未做唯一性校验
|
||||
|
||||
| 属性 | 描述 |
|
||||
|------|------|
|
||||
| 缺陷编号 | BUG-USER-001 |
|
||||
| 关联用例 | USER-002 |
|
||||
| 严重程度 | 中 |
|
||||
| 优先级 | P2 |
|
||||
| 缺陷描述 | 创建员工时未校验手机号是否已存在,允许重复手机号 |
|
||||
| 重现步骤 | 1. 管理员登录<br>2. 创建员工A,手机号13800138001<br>3. 创建员工B,手机号13800138001<br>4. 两个员工都创建成功 |
|
||||
| 预期结果 | 第二次创建时提示"手机号已存在" |
|
||||
| 实际结果 | 两个员工都创建成功,存在重复手机号 |
|
||||
| 建议修复 | 在UserServiceImpl.createUser()方法中添加手机号唯一性校验 |
|
||||
|
||||
---
|
||||
|
||||
### BUG-002:讲师未实现部门数据隔离
|
||||
|
||||
| 属性 | 描述 |
|
||||
|------|------|
|
||||
| 缺陷编号 | BUG-USER-002 |
|
||||
| 关联用例 | USER-006 |
|
||||
| 严重程度 | 高 |
|
||||
| 优先级 | P1 |
|
||||
| 缺陷描述 | 讲师角色可以查看所有部门的员工信息,未按部门隔离 |
|
||||
| 重现步骤 | 1. 讲师账号登录(部门:救援一部)<br>2. 访问GET /api/system/user/page<br>3. 返回结果包含救援一部和救援二部的员工 |
|
||||
| 预期结果 | 讲师只能看到本部门(救援一部)的员工 |
|
||||
| 实际结果 | 讲师可以看到所有部门的员工(7条记录) |
|
||||
| 建议修复 | 在UserService查询方法中根据当前用户角色和部门进行数据过滤 |
|
||||
|
||||
**测试数据截取:**
|
||||
```json
|
||||
{
|
||||
"total": 7,
|
||||
"records": [
|
||||
{"id":7, "departmentName":"救援一部"},
|
||||
{"id":6, "departmentName":"救援一部"},
|
||||
{"id":2, "departmentName":"救援二部"}, // 不应可见
|
||||
{"id":1, "departmentName":"救援二部"} // 不应可见
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### BUG-003:学员权限未控制,可访问员工管理接口
|
||||
|
||||
| 属性 | 描述 |
|
||||
|------|------|
|
||||
| 缺陷编号 | BUG-USER-003 |
|
||||
| 关联用例 | USER-007 |
|
||||
| 严重程度 | **严重** |
|
||||
| 优先级 | P0 |
|
||||
| 缺陷描述 | 学员角色可以访问员工管理接口,获取所有用户敏感信息 |
|
||||
| 重现步骤 | 1. 学员账号登录<br>2. 访问GET /api/system/user/page<br>3. 成功返回所有用户列表 |
|
||||
| 预期结果 | 返回403 Forbidden,拒绝访问 |
|
||||
| 实际结果 | 返回200 OK,可查看所有用户数据 |
|
||||
| 建议修复 | 1. 在UserController上添加@PreAuthorize注解限制ADMIN和LECTURER角色<br>2. 或在拦截器中根据角色过滤接口访问权限 |
|
||||
|
||||
**安全风险:** 此漏洞导致学员可以获取所有员工的手机号、用户名等敏感信息,存在信息泄露风险。
|
||||
|
||||
---
|
||||
|
||||
## 四、测试覆盖接口
|
||||
|
||||
| 接口 | 方法 | 测试状态 |
|
||||
|------|------|---------|
|
||||
| /api/system/user | POST | 已测试 |
|
||||
| /api/system/user/{id} | GET | 已测试 |
|
||||
| /api/system/user/page | GET | 已测试 |
|
||||
| /api/system/user/{id}/enable | PUT | 已测试 |
|
||||
| /api/system/user/{id}/disable | PUT | 已测试 |
|
||||
| /api/auth/login | POST | 已测试(辅助) |
|
||||
|
||||
---
|
||||
|
||||
## 五、测试数据
|
||||
|
||||
### 5.1 测试账号
|
||||
|
||||
| 用户名 | 密码 | 角色 | 部门 |
|
||||
|--------|------|------|------|
|
||||
| admin | admin123 | ADMIN | 救援二部 |
|
||||
| test_lecturer | Test@123 | LECTURER | 救援一部 |
|
||||
| test_user_001 | Test@123 | STUDENT | 救援一部 |
|
||||
|
||||
### 5.2 测试创建的数据
|
||||
|
||||
| ID | 用户名 | 角色 | 部门 |
|
||||
|----|--------|------|------|
|
||||
| 4 | test_user_001 | STUDENT | 救援一部 |
|
||||
| 5 | test_user_002 | STUDENT | 救援一部 |
|
||||
| 6 | test_admin | ADMIN | 救援一部 |
|
||||
| 7 | test_lecturer | LECTURER | 救援一部 |
|
||||
|
||||
---
|
||||
|
||||
## 六、结论与建议
|
||||
|
||||
### 6.1 测试结论
|
||||
|
||||
员工管理模块基本CRUD功能正常,但存在**3个缺陷**,其中:
|
||||
- **1个严重缺陷**(P0):学员权限未控制
|
||||
- **1个高优先级缺陷**(P1):讲师部门隔离未实现
|
||||
- **1个中优先级缺陷**(P2):手机号唯一性未校验
|
||||
|
||||
### 6.2 修复建议优先级
|
||||
|
||||
1. **P0 - 立即修复**:BUG-USER-003(学员权限控制)
|
||||
2. **P1 - 紧急修复**:BUG-USER-002(讲师部门隔离)
|
||||
3. **P2 - 计划修复**:BUG-USER-001(手机号唯一性)
|
||||
|
||||
### 6.3 阻塞问题
|
||||
|
||||
无阻塞问题,可继续进行后续模块测试。
|
||||
|
||||
---
|
||||
|
||||
**报告生成时间:** 2026-01-09 14:48:00
|
||||
@@ -1,177 +0,0 @@
|
||||
# 测试报告 - 模块二:知识库
|
||||
|
||||
> 测试日期:2026-01-09
|
||||
> 测试人员:AI测试工程师
|
||||
> 测试环境:Spring Boot 3.1.2 / MySQL 8.0 / JDK 17
|
||||
|
||||
---
|
||||
|
||||
## 一、测试概要
|
||||
|
||||
| 项目 | 数值 |
|
||||
|------|------|
|
||||
| 测试用例总数 | 19 |
|
||||
| 通过 | 2 |
|
||||
| 失败 | 2 |
|
||||
| 阻塞 | 15 |
|
||||
| 通过率 | 10.5% |
|
||||
|
||||
**注意:** 由于发现关键BUG(创建知识时creator_id未设置),导致知识创建失败,大部分测试用例被阻塞。
|
||||
|
||||
---
|
||||
|
||||
## 二、测试结果详情
|
||||
|
||||
### 2.1 知识分类测试(KC系列)
|
||||
|
||||
| 用例编号 | 测试项 | 预期结果 | 实际结果 | 状态 |
|
||||
|---------|--------|---------|---------|------|
|
||||
| KC-001 | 创建一级分类 | 成功创建 | 创建成功,返回ID=4 | **通过** |
|
||||
| KC-002 | 创建多级分类(父子关系) | 层级关系正确 | 成功创建子分类ID=5,父分类为ID=4 | **通过** |
|
||||
| KC-003 | 删除有知识的分类 | 提示"存在关联知识,无法删除" | 由于知识创建失败,无法测试 | **阻塞** |
|
||||
| KC-004 | 讲师只能管理本部门分类 | 其他部门分类不可操作 | 讲师(部门1)可以创建部门2的分类 | **失败** |
|
||||
|
||||
### 2.2 知识文档管理测试(KM系列)
|
||||
|
||||
| 用例编号 | 测试项 | 预期结果 | 实际结果 | 状态 |
|
||||
|---------|--------|---------|---------|------|
|
||||
| KM-001 | 上传PDF文档 | 上传成功 | 文件保存失败(code:1501) | **失败** |
|
||||
| KM-002 | 上传Word文档 | 上传成功 | 依赖KM-001 | **阻塞** |
|
||||
| KM-003 | 上传Excel文档 | 上传成功 | 依赖KM-001 | **阻塞** |
|
||||
| KM-004 | 上传PPT文档 | 上传成功 | 依赖KM-001 | **阻塞** |
|
||||
| KM-005 | 上传视频文件 | 上传成功 | 依赖KM-001 | **阻塞** |
|
||||
| KM-006 | 上传不支持的格式 | 提示错误 | 依赖KM-001 | **阻塞** |
|
||||
| KM-007 | 超大文件上传 | 提示错误 | 依赖KM-001 | **阻塞** |
|
||||
|
||||
### 2.3 知识状态管理测试(KS系列)
|
||||
|
||||
| 用例编号 | 测试项 | 预期结果 | 实际结果 | 状态 |
|
||||
|---------|--------|---------|---------|------|
|
||||
| KS-001 | 创建知识(默认草稿) | 状态为DRAFT | creator_id字段缺失导致失败 | **阻塞** |
|
||||
| KS-002 | 草稿→发布 | 状态变为PUBLISHED | 依赖KS-001 | **阻塞** |
|
||||
| KS-003 | 已发布→下架 | 状态变为OFFLINE | 依赖KS-001 | **阻塞** |
|
||||
| KS-004 | 已下架→重新上架 | 状态变为PUBLISHED | 依赖KS-001 | **阻塞** |
|
||||
| KS-005 | 学员查看草稿知识 | 不可见 | 依赖KS-001 | **阻塞** |
|
||||
| KS-006 | 学员查看已发布知识 | 可见 | 依赖KS-001 | **阻塞** |
|
||||
| KS-007 | 学员查看已下架知识 | 不可见 | 依赖KS-001 | **阻塞** |
|
||||
| KS-008 | 下架被培训计划引用的知识 | 显示警告确认 | 依赖KS-001 | **阻塞** |
|
||||
|
||||
### 2.4 部门隔离测试(KD系列)
|
||||
|
||||
| 用例编号 | 测试项 | 预期结果 | 实际结果 | 状态 |
|
||||
|---------|--------|---------|---------|------|
|
||||
| KD-001 | 讲师查看本部门知识 | 正常查看 | 依赖知识数据 | **阻塞** |
|
||||
| KD-002 | 讲师查看其他部门知识 | 不可见 | 依赖知识数据 | **阻塞** |
|
||||
| KD-003 | 学员查看本部门已发布知识 | 正常查看 | API可访问,但无数据 | **阻塞** |
|
||||
| KD-004 | 学员查看其他部门知识 | 不可见 | 依赖知识数据 | **阻塞** |
|
||||
|
||||
---
|
||||
|
||||
## 三、缺陷清单
|
||||
|
||||
### BUG-KM-001:创建知识时creator_id未设置
|
||||
|
||||
| 属性 | 描述 |
|
||||
|------|------|
|
||||
| 缺陷编号 | BUG-KM-001 |
|
||||
| 关联用例 | KS-001及所有依赖用例 |
|
||||
| 严重程度 | **阻断** |
|
||||
| 优先级 | P0 |
|
||||
| 缺陷描述 | 创建知识时未设置creator_id字段,导致数据库插入失败 |
|
||||
| 重现步骤 | 1. 管理员登录<br>2. POST /api/knowledge 创建知识<br>3. 返回500错误 |
|
||||
| 错误信息 | `Field 'creator_id' doesn't have a default value` |
|
||||
| 预期结果 | 知识创建成功,creator_id自动设置为当前登录用户ID |
|
||||
| 实际结果 | 500服务器内部错误 |
|
||||
| 建议修复 | 在KnowledgeServiceImpl.createKnowledge()方法中,从SecurityContext获取当前用户ID并设置到knowledge.setCreatorId() |
|
||||
|
||||
**影响范围:** 此BUG导致知识库模块15个测试用例被阻塞,无法继续测试。
|
||||
|
||||
---
|
||||
|
||||
### BUG-KM-002:讲师可以操作其他部门的分类
|
||||
|
||||
| 属性 | 描述 |
|
||||
|------|------|
|
||||
| 缺陷编号 | BUG-KM-002 |
|
||||
| 关联用例 | KC-004 |
|
||||
| 严重程度 | 高 |
|
||||
| 优先级 | P1 |
|
||||
| 缺陷描述 | 讲师角色可以创建/修改其他部门的知识分类,未实现部门隔离 |
|
||||
| 重现步骤 | 1. 讲师账号登录(部门1)<br>2. POST /api/knowledge/category 创建分类,departmentId设为2<br>3. 分类创建成功 |
|
||||
| 预期结果 | 返回403或400错误,禁止操作其他部门数据 |
|
||||
| 实际结果 | 分类创建成功,返回ID=6 |
|
||||
| 建议修复 | 在CategoryService中校验当前用户部门与操作数据部门是否一致 |
|
||||
|
||||
---
|
||||
|
||||
### BUG-KM-003:文件上传功能异常
|
||||
|
||||
| 属性 | 描述 |
|
||||
|------|------|
|
||||
| 缺陷编号 | BUG-KM-003 |
|
||||
| 关联用例 | KM-001 ~ KM-007 |
|
||||
| 严重程度 | 高 |
|
||||
| 优先级 | P1 |
|
||||
| 缺陷描述 | 文件上传接口返回"文件保存失败"错误 |
|
||||
| 重现步骤 | 1. 管理员登录<br>2. POST /api/file/upload/document 上传文件<br>3. 返回code:1501错误 |
|
||||
| 错误信息 | `{"code":1501,"message":"文件保存失败"}` |
|
||||
| 预期结果 | 文件上传成功,返回文件URL |
|
||||
| 实际结果 | 返回1501错误码 |
|
||||
| 建议修复 | 检查文件存储路径配置,确保上传目录存在且有写入权限 |
|
||||
|
||||
---
|
||||
|
||||
## 四、测试覆盖接口
|
||||
|
||||
| 接口 | 方法 | 测试状态 |
|
||||
|------|------|---------|
|
||||
| /api/knowledge/category | POST | 已测试 |
|
||||
| /api/knowledge/category/tree | GET | 已测试 |
|
||||
| /api/knowledge/category/{id} | DELETE | 已测试 |
|
||||
| /api/knowledge | POST | 已测试(失败) |
|
||||
| /api/knowledge/page | GET | 已测试 |
|
||||
| /api/file/upload/document | POST | 已测试(失败) |
|
||||
|
||||
---
|
||||
|
||||
## 五、测试数据
|
||||
|
||||
### 5.1 测试创建的分类数据
|
||||
|
||||
| ID | 名称 | 父分类 | 部门 | 状态 |
|
||||
|----|------|--------|------|------|
|
||||
| 4 | Safety Regulations | - | 救援一部 | 已删除 |
|
||||
| 5 | Highway Rescue | 4 | 救援一部 | 已删除 |
|
||||
| 6 | Test Category Dept2 | - | 救援二部 | 存在(异常数据) |
|
||||
|
||||
---
|
||||
|
||||
## 六、结论与建议
|
||||
|
||||
### 6.1 测试结论
|
||||
|
||||
知识库模块存在**3个严重缺陷**,其中1个为阻断级别:
|
||||
|
||||
1. **P0 阻断级**:创建知识时creator_id未设置 - 导致整个模块功能不可用
|
||||
2. **P1 高优先级**:讲师部门隔离未实现
|
||||
3. **P1 高优先级**:文件上传功能异常
|
||||
|
||||
### 6.2 修复建议优先级
|
||||
|
||||
1. **立即修复(P0)**:BUG-KM-001 - 修复后需重新执行全部阻塞用例
|
||||
2. **紧急修复(P1)**:BUG-KM-002 - 部门隔离
|
||||
3. **紧急修复(P1)**:BUG-KM-003 - 文件上传
|
||||
|
||||
### 6.3 阻塞说明
|
||||
|
||||
由于BUG-KM-001为阻断级缺陷,以下测试需要在修复后重新执行:
|
||||
- KS系列(知识状态管理):8个用例
|
||||
- KD系列(部门隔离):4个用例
|
||||
- KM系列(文件管理):6个用例
|
||||
- KC-003(删除有知识的分类):1个用例
|
||||
|
||||
**建议:** 修复BUG-KM-001后进行回归测试。
|
||||
|
||||
---
|
||||
|
||||
**报告生成时间:** 2026-01-09 14:58:00
|
||||
@@ -1,144 +0,0 @@
|
||||
# 测试报告 - 模块三:考题管理
|
||||
|
||||
> 测试日期:2026-01-09
|
||||
> 测试人员:AI测试工程师
|
||||
> 测试环境:Spring Boot 3.1.2 / MySQL 8.0 / JDK 17
|
||||
|
||||
---
|
||||
|
||||
## 一、测试概要
|
||||
|
||||
| 项目 | 数值 |
|
||||
|------|------|
|
||||
| 测试用例总数 | 11 |
|
||||
| 通过 | 0 |
|
||||
| 失败 | 3 |
|
||||
| 阻塞 | 8 |
|
||||
| 通过率 | 0% |
|
||||
|
||||
**注意:** 与知识库模块相同,创建题目时也存在creator_id未设置的问题,导致大部分测试被阻塞。
|
||||
|
||||
---
|
||||
|
||||
## 二、测试结果详情
|
||||
|
||||
### 2.1 题型测试(Q系列)
|
||||
|
||||
| 用例编号 | 测试项 | 预期结果 | 实际结果 | 状态 |
|
||||
|---------|--------|---------|---------|------|
|
||||
| Q-001 | 创建单选题(4选项) | 成功创建 | creator_id字段缺失导致失败 | **阻塞** |
|
||||
| Q-002 | 创建多选题 | 成功创建 | 依赖Q-001 | **阻塞** |
|
||||
| Q-003 | 创建判断题 | 成功创建 | 依赖Q-001 | **阻塞** |
|
||||
| Q-004 | 单选题设置多个答案 | 提示错误 | 依赖Q-001 | **阻塞** |
|
||||
| Q-005 | 多选题只设置一个答案 | 提示错误 | 依赖Q-001 | **阻塞** |
|
||||
| Q-006 | 题目必须填写解析 | 提示必填 | 依赖Q-001 | **阻塞** |
|
||||
|
||||
### 2.2 题目状态管理测试(QS系列)
|
||||
|
||||
| 用例编号 | 测试项 | 预期结果 | 实际结果 | 状态 |
|
||||
|---------|--------|---------|---------|------|
|
||||
| QS-001 | 草稿题目发布 | 状态变为PUBLISHED | 依赖题目数据 | **阻塞** |
|
||||
| QS-002 | 下架被试卷引用的题目 | 显示警告确认 | 依赖题目数据 | **阻塞** |
|
||||
| QS-003 | 只有已发布题目可被组卷 | 草稿/下架题目不可选 | 依赖题目数据 | **阻塞** |
|
||||
|
||||
### 2.3 部门隔离测试(QD系列)
|
||||
|
||||
| 用例编号 | 测试项 | 预期结果 | 实际结果 | 状态 |
|
||||
|---------|--------|---------|---------|------|
|
||||
| QD-001 | 讲师只能管理本部门题库 | 其他部门不可操作 | 讲师可创建其他部门题库分类(ID=4) | **失败** |
|
||||
| QD-002 | 学员无法访问题目管理 | 返回403 | 返回200,可查询题目列表 | **失败** |
|
||||
|
||||
---
|
||||
|
||||
## 三、缺陷清单
|
||||
|
||||
### BUG-Q-001:创建题目时creator_id未设置
|
||||
|
||||
| 属性 | 描述 |
|
||||
|------|------|
|
||||
| 缺陷编号 | BUG-Q-001 |
|
||||
| 关联用例 | Q-001及所有依赖用例 |
|
||||
| 严重程度 | **阻断** |
|
||||
| 优先级 | P0 |
|
||||
| 缺陷描述 | 创建题目时未设置creator_id字段,导致数据库插入失败 |
|
||||
| 重现步骤 | 1. 管理员登录<br>2. POST /api/exam/question 创建题目<br>3. 返回500错误 |
|
||||
| 错误信息 | `Field 'creator_id' doesn't have a default value` |
|
||||
| 预期结果 | 题目创建成功 |
|
||||
| 实际结果 | 500服务器内部错误 |
|
||||
| 建议修复 | 在QuestionServiceImpl.createQuestion()方法中,从SecurityContext获取当前用户ID并设置到question.setCreatorId() |
|
||||
|
||||
**与BUG-KM-001为同类问题,建议统一修复。**
|
||||
|
||||
---
|
||||
|
||||
### BUG-Q-002:讲师可以操作其他部门的题库分类
|
||||
|
||||
| 属性 | 描述 |
|
||||
|------|------|
|
||||
| 缺陷编号 | BUG-Q-002 |
|
||||
| 关联用例 | QD-001 |
|
||||
| 严重程度 | 高 |
|
||||
| 优先级 | P1 |
|
||||
| 缺陷描述 | 讲师角色可以创建其他部门的题库分类,未实现部门隔离 |
|
||||
| 重现步骤 | 1. 讲师账号登录(部门1)<br>2. POST /api/exam/question-category 创建分类,departmentId设为2<br>3. 分类创建成功 |
|
||||
| 预期结果 | 返回403或400错误 |
|
||||
| 实际结果 | 分类创建成功,返回ID=4 |
|
||||
| 建议修复 | 在QuestionCategoryService中校验当前用户部门与操作数据部门是否一致 |
|
||||
|
||||
---
|
||||
|
||||
### BUG-Q-003:学员可以访问题目管理接口
|
||||
|
||||
| 属性 | 描述 |
|
||||
|------|------|
|
||||
| 缺陷编号 | BUG-Q-003 |
|
||||
| 关联用例 | QD-002 |
|
||||
| 严重程度 | **严重** |
|
||||
| 优先级 | P0 |
|
||||
| 缺陷描述 | 学员角色可以访问题目管理接口 |
|
||||
| 重现步骤 | 1. 学员账号登录<br>2. GET /api/exam/question/page<br>3. 成功返回题目列表 |
|
||||
| 预期结果 | 返回403 Forbidden |
|
||||
| 实际结果 | 返回200 OK |
|
||||
| 建议修复 | 在QuestionController上添加角色权限控制 |
|
||||
|
||||
---
|
||||
|
||||
## 四、测试覆盖接口
|
||||
|
||||
| 接口 | 方法 | 测试状态 |
|
||||
|------|------|---------|
|
||||
| /api/exam/question | POST | 已测试(失败) |
|
||||
| /api/exam/question/page | GET | 已测试 |
|
||||
| /api/exam/question-category | POST | 已测试 |
|
||||
| /api/exam/question-category/tree | GET | 已测试 |
|
||||
|
||||
---
|
||||
|
||||
## 五、结论与建议
|
||||
|
||||
### 5.1 测试结论
|
||||
|
||||
考题管理模块存在**3个缺陷**,其中2个为严重/阻断级别:
|
||||
|
||||
1. **P0 阻断级**:创建题目时creator_id未设置 - 导致整个模块功能不可用
|
||||
2. **P0 严重级**:学员权限未控制
|
||||
3. **P1 高优先级**:讲师部门隔离未实现
|
||||
|
||||
### 5.2 共性问题说明
|
||||
|
||||
此模块发现的问题与员工管理、知识库模块存在共性:
|
||||
- creator_id未设置:知识库、考题管理
|
||||
- 学员权限未控制:员工管理、题目管理
|
||||
- 讲师部门隔离未实现:知识库分类、题库分类
|
||||
|
||||
**建议进行全局修复。**
|
||||
|
||||
### 5.3 阻塞说明
|
||||
|
||||
由于BUG-Q-001为阻断级缺陷,以下测试需要在修复后重新执行:
|
||||
- Q系列(题型测试):6个用例
|
||||
- QS系列(状态管理):3个用例
|
||||
|
||||
---
|
||||
|
||||
**报告生成时间:** 2026-01-09 15:26:00
|
||||
@@ -1,127 +0,0 @@
|
||||
# 测试报告 - 模块四:试卷管理
|
||||
|
||||
> 测试日期:2026-01-09
|
||||
> 测试人员:AI测试工程师
|
||||
> 测试环境:Spring Boot 3.1.2 / MySQL 8.0 / JDK 17
|
||||
|
||||
---
|
||||
|
||||
## 一、测试概要
|
||||
|
||||
| 项目 | 数值 |
|
||||
|------|------|
|
||||
| 测试用例总数 | 11 |
|
||||
| 通过 | 0 |
|
||||
| 失败 | 1 |
|
||||
| 阻塞 | 10 |
|
||||
| 通过率 | 0% |
|
||||
|
||||
**注意:** 与知识库、考题模块相同,创建试卷时也存在creator_id未设置的问题,导致大部分测试被阻塞。
|
||||
|
||||
---
|
||||
|
||||
## 二、测试结果详情
|
||||
|
||||
### 2.1 手动组卷测试(P系列)
|
||||
|
||||
| 用例编号 | 测试项 | 预期结果 | 实际结果 | 状态 |
|
||||
|---------|--------|---------|---------|------|
|
||||
| P-001 | 手动选择题目组卷 | 成功创建试卷 | creator_id字段缺失导致失败 | **阻塞** |
|
||||
| P-002 | 设置每题分值 | 分值设置正确 | 依赖P-001 | **阻塞** |
|
||||
| P-003 | 总分自动计算 | 各题分值之和=总分 | 依赖P-001 | **阻塞** |
|
||||
| P-004 | 设置考试时长 | 时长设置正确 | 依赖P-001 | **阻塞** |
|
||||
| P-005 | 设置及格分 | 及格分≤总分 | 依赖P-001 | **阻塞** |
|
||||
| P-006 | 及格分超过总分 | 提示错误 | 依赖P-001 | **阻塞** |
|
||||
|
||||
### 2.2 自动组卷测试(PA系列)
|
||||
|
||||
| 用例编号 | 测试项 | 预期结果 | 实际结果 | 状态 |
|
||||
|---------|--------|---------|---------|------|
|
||||
| PA-001 | 设置规则自动抽题 | 按规则随机抽取 | 依赖题目数据 | **阻塞** |
|
||||
| PA-002 | 题库数量不足 | 提示错误 | 依赖题目数据 | **阻塞** |
|
||||
| PA-003 | 自动组卷题目随机 | 多次组卷结果不同 | 依赖题目数据 | **阻塞** |
|
||||
|
||||
### 2.3 试卷预览测试(PP系列)
|
||||
|
||||
| 用例编号 | 测试项 | 预期结果 | 实际结果 | 状态 |
|
||||
|---------|--------|---------|---------|------|
|
||||
| PP-001 | 预览试卷 | 显示完整试卷内容 | 依赖试卷数据 | **阻塞** |
|
||||
|
||||
### 2.4 权限测试
|
||||
|
||||
| 用例编号 | 测试项 | 预期结果 | 实际结果 | 状态 |
|
||||
|---------|--------|---------|---------|------|
|
||||
| PS-权限 | 学员无法访问试卷管理 | 返回403 | 返回200,可查询试卷列表 | **失败** |
|
||||
|
||||
---
|
||||
|
||||
## 三、缺陷清单
|
||||
|
||||
### BUG-P-001:创建试卷时creator_id未设置
|
||||
|
||||
| 属性 | 描述 |
|
||||
|------|------|
|
||||
| 缺陷编号 | BUG-P-001 |
|
||||
| 关联用例 | P-001及所有依赖用例 |
|
||||
| 严重程度 | **阻断** |
|
||||
| 优先级 | P0 |
|
||||
| 缺陷描述 | 创建试卷时未设置creator_id字段,导致数据库插入失败 |
|
||||
| 重现步骤 | 1. 管理员登录<br>2. POST /api/exam/paper 创建试卷<br>3. 返回500错误 |
|
||||
| 错误信息 | `Field 'creator_id' doesn't have a default value` |
|
||||
| 预期结果 | 试卷创建成功 |
|
||||
| 实际结果 | 500服务器内部错误 |
|
||||
| 建议修复 | 在PaperServiceImpl.createPaper()方法中设置creatorId |
|
||||
|
||||
**与BUG-KM-001、BUG-Q-001为同类问题。**
|
||||
|
||||
---
|
||||
|
||||
### BUG-P-002:学员可以访问试卷管理接口
|
||||
|
||||
| 属性 | 描述 |
|
||||
|------|------|
|
||||
| 缺陷编号 | BUG-P-002 |
|
||||
| 关联用例 | PS-权限 |
|
||||
| 严重程度 | **严重** |
|
||||
| 优先级 | P0 |
|
||||
| 缺陷描述 | 学员角色可以访问试卷管理接口 |
|
||||
| 重现步骤 | 1. 学员账号登录<br>2. GET /api/exam/paper/page<br>3. 成功返回试卷列表 |
|
||||
| 预期结果 | 返回403 Forbidden |
|
||||
| 实际结果 | 返回200 OK |
|
||||
| 建议修复 | 在PaperController上添加角色权限控制 |
|
||||
|
||||
---
|
||||
|
||||
## 四、测试覆盖接口
|
||||
|
||||
| 接口 | 方法 | 测试状态 |
|
||||
|------|------|---------|
|
||||
| /api/exam/paper | POST | 已测试(失败) |
|
||||
| /api/exam/paper/page | GET | 已测试 |
|
||||
|
||||
---
|
||||
|
||||
## 五、结论与建议
|
||||
|
||||
### 5.1 测试结论
|
||||
|
||||
试卷管理模块存在**2个缺陷**:
|
||||
|
||||
1. **P0 阻断级**:创建试卷时creator_id未设置
|
||||
2. **P0 严重级**:学员权限未控制
|
||||
|
||||
### 5.2 共性问题汇总
|
||||
|
||||
截至目前,已发现的共性问题:
|
||||
|
||||
| 问题类型 | 影响模块 |
|
||||
|---------|---------|
|
||||
| creator_id未设置 | 知识库、考题管理、试卷管理 |
|
||||
| 学员权限未控制 | 员工管理、考题管理、试卷管理 |
|
||||
| 讲师部门隔离未实现 | 知识库分类、题库分类 |
|
||||
|
||||
**建议进行全局性修复。**
|
||||
|
||||
---
|
||||
|
||||
**报告生成时间:** 2026-01-09 15:32:00
|
||||
@@ -1,135 +0,0 @@
|
||||
# 测试报告 - 模块五:考试管理
|
||||
|
||||
> 测试日期:2026-01-09
|
||||
> 测试人员:AI测试工程师
|
||||
> 测试环境:Spring Boot 3.1.2 / MySQL 8.0 / JDK 17
|
||||
|
||||
---
|
||||
|
||||
## 一、测试概要
|
||||
|
||||
| 项目 | 数值 |
|
||||
|------|------|
|
||||
| 测试用例总数 | 20 |
|
||||
| 通过 | 1 |
|
||||
| 失败 | 1 |
|
||||
| 阻塞 | 18 |
|
||||
| 通过率 | 5% |
|
||||
|
||||
**注意:** 由于试卷创建失败,考试创建依赖试卷数据,导致绝大部分测试被阻塞。
|
||||
|
||||
---
|
||||
|
||||
## 二、测试结果详情
|
||||
|
||||
### 2.1 发布考试测试(E系列)
|
||||
|
||||
| 用例编号 | 测试项 | 预期结果 | 实际结果 | 状态 |
|
||||
|---------|--------|---------|---------|------|
|
||||
| E-001 | 创建考试,关联试卷 | 成功创建 | 返回"试卷不存在"(1302) | **阻塞** |
|
||||
| E-002 | 设置时间窗口 | 时间设置正确 | 依赖E-001 | **阻塞** |
|
||||
| E-003 | 设置及格线 | 及格线设置正确 | 依赖E-001 | **阻塞** |
|
||||
| E-004 | 设置最大考试次数 | 次数限制生效 | 依赖E-001 | **阻塞** |
|
||||
| E-005 | 指定部门参加考试 | 部门所有人可见 | 依赖E-001 | **阻塞** |
|
||||
| E-006 | 指定小组参加考试 | 小组成员可见 | 依赖E-001 | **阻塞** |
|
||||
| E-007 | 指定个人参加考试 | 仅该用户可见 | 依赖E-001 | **阻塞** |
|
||||
|
||||
### 2.2 在线答题测试(EA系列)
|
||||
|
||||
| 用例编号 | 测试项 | 预期结果 | 实际结果 | 状态 |
|
||||
|---------|--------|---------|---------|------|
|
||||
| EA-001 | 在时间窗口内进入考试 | 成功进入 | 依赖考试数据 | **阻塞** |
|
||||
| EA-002 | 不在时间窗口进入考试 | 提示错误 | 依赖考试数据 | **阻塞** |
|
||||
| EA-003 | 超过最大次数进入考试 | 提示错误 | 依赖考试数据 | **阻塞** |
|
||||
| EA-004 | 答题过程自动计时 | 倒计时正确 | 依赖考试数据 | **阻塞** |
|
||||
| EA-005 | 超时自动交卷 | 系统自动提交 | 依赖考试数据 | **阻塞** |
|
||||
| EA-006 | 主动交卷 | 成功提交 | 依赖考试数据 | **阻塞** |
|
||||
| EA-007 | 答案定时自动保存 | 答案保存成功 | 依赖考试数据 | **阻塞** |
|
||||
| EA-008 | 断网后恢复继续答题 | 可继续答题 | 依赖考试数据 | **阻塞** |
|
||||
|
||||
### 2.3 成绩计算测试(ES系列)
|
||||
|
||||
| 用例编号 | 测试项 | 预期结果 | 实际结果 | 状态 |
|
||||
|---------|--------|---------|---------|------|
|
||||
| ES-001 | 单选题判分 | 正确/错误判分 | 依赖考试数据 | **阻塞** |
|
||||
| ES-002 | 多选题判分 | 全对得分 | 依赖考试数据 | **阻塞** |
|
||||
| ES-003 | 判断题判分 | 正确/错误判分 | 依赖考试数据 | **阻塞** |
|
||||
| ES-004 | 分数≥及格线显示通过 | 显示"通过" | 依赖考试数据 | **阻塞** |
|
||||
| ES-005 | 分数<及格线显示未通过 | 显示"未通过" | 依赖考试数据 | **阻塞** |
|
||||
| ES-006 | 多次考试取最高分 | 最高分记录正确 | 依赖考试数据 | **阻塞** |
|
||||
|
||||
### 2.4 成绩查看测试(EV系列)
|
||||
|
||||
| 用例编号 | 测试项 | 预期结果 | 实际结果 | 状态 |
|
||||
|---------|--------|---------|---------|------|
|
||||
| EV-001 | 交卷后立即显示成绩 | 成绩即时显示 | 依赖考试数据 | **阻塞** |
|
||||
| EV-002 | 显示答案解析 | 每题显示解析 | 依赖考试数据 | **阻塞** |
|
||||
| EV-003 | 讲师查看本部门学员成绩 | 正常查看 | 依赖考试数据 | **阻塞** |
|
||||
|
||||
### 2.5 权限测试
|
||||
|
||||
| 用例编号 | 测试项 | 预期结果 | 实际结果 | 状态 |
|
||||
|---------|--------|---------|---------|------|
|
||||
| E-学员接口 | 学员获取可参加的考试 | 返回200 | 返回200,空列表 | **通过** |
|
||||
| E-权限 | 学员访问考试管理接口 | 返回403 | 返回200,可查询考试列表 | **失败** |
|
||||
|
||||
---
|
||||
|
||||
## 三、缺陷清单
|
||||
|
||||
### BUG-E-001:学员可以访问考试管理接口
|
||||
|
||||
| 属性 | 描述 |
|
||||
|------|------|
|
||||
| 缺陷编号 | BUG-E-001 |
|
||||
| 关联用例 | E-权限 |
|
||||
| 严重程度 | **严重** |
|
||||
| 优先级 | P0 |
|
||||
| 缺陷描述 | 学员角色可以访问考试管理的分页查询接口 |
|
||||
| 重现步骤 | 1. 学员账号登录<br>2. GET /api/exam/page<br>3. 成功返回考试列表 |
|
||||
| 预期结果 | 返回403 Forbidden |
|
||||
| 实际结果 | 返回200 OK |
|
||||
| 建议修复 | 在ExamController的管理类接口上添加角色权限控制 |
|
||||
|
||||
---
|
||||
|
||||
## 四、测试覆盖接口
|
||||
|
||||
| 接口 | 方法 | 测试状态 |
|
||||
|------|------|---------|
|
||||
| /api/exam | POST | 已测试(阻塞-无试卷) |
|
||||
| /api/exam/page | GET | 已测试 |
|
||||
| /api/exam/my | GET | 已测试 |
|
||||
|
||||
---
|
||||
|
||||
## 五、阻塞说明
|
||||
|
||||
考试管理模块测试被阻塞的根本原因链:
|
||||
|
||||
```
|
||||
creator_id问题 → 知识/题目创建失败 → 试卷创建失败 → 考试创建失败(无试卷) → 考试流程测试全部阻塞
|
||||
```
|
||||
|
||||
**前置条件:**
|
||||
- 试卷管理模块正常(至少有一张已发布的试卷)
|
||||
- 题目管理模块正常(至少有已发布的题目)
|
||||
|
||||
---
|
||||
|
||||
## 六、结论与建议
|
||||
|
||||
### 6.1 测试结论
|
||||
|
||||
考试管理模块存在**1个权限缺陷**,同时因上游模块阻断导致**18个用例无法执行**。
|
||||
|
||||
### 6.2 建议
|
||||
|
||||
1. 优先修复所有模块的creator_id问题
|
||||
2. 修复后按顺序执行:
|
||||
- 考题管理 → 试卷管理 → 考试管理
|
||||
3. 补充考试核心流程的完整测试
|
||||
|
||||
---
|
||||
|
||||
**报告生成时间:** 2026-01-09 15:38:00
|
||||
@@ -1,119 +0,0 @@
|
||||
,# 测试报告 - 模块六:培训计划
|
||||
|
||||
> 测试日期:2026-01-09
|
||||
> 测试人员:AI测试工程师
|
||||
> 测试环境:Spring Boot 3.1.2 / MySQL 8.0 / JDK 17
|
||||
|
||||
---
|
||||
|
||||
## 一、测试概要
|
||||
|
||||
| 项目 | 数值 |
|
||||
|------|------|
|
||||
| 测试用例总数 | 11 |
|
||||
| 通过 | 4 |
|
||||
| 失败 | 1 |
|
||||
| 阻塞 | 6 |
|
||||
| 通过率 | 36.4% |
|
||||
|
||||
**说明:** 培训计划模块基本功能可用,但部分依赖知识库的功能被阻塞。
|
||||
|
||||
---
|
||||
|
||||
## 二、测试结果详情
|
||||
|
||||
### 2.1 创建培训计划测试(TP系列)
|
||||
|
||||
| 用例编号 | 测试项 | 预期结果 | 实际结果 | 状态 |
|
||||
|---------|--------|---------|---------|------|
|
||||
| TP-001 | 创建培训计划 | 成功创建 | 创建成功,返回ID=1 | **通过** |
|
||||
| TP-002 | 关联多个知识文档 | 关联成功 | 依赖知识数据 | **阻塞** |
|
||||
| TP-003 | 关联考试(可选) | 关联成功 | 依赖考试数据 | **阻塞** |
|
||||
| TP-004 | 分配部门/小组/个人 | 分配成功 | 分配部门成功 | **通过** |
|
||||
|
||||
### 2.2 计划状态测试(TPS系列)
|
||||
|
||||
| 用例编号 | 测试项 | 预期结果 | 实际结果 | 状态 |
|
||||
|---------|--------|---------|---------|------|
|
||||
| TPS-001 | 开始日期前状态 | 未开始 | 创建后默认为NOT_STARTED | **通过** |
|
||||
| TPS-002 | 发布后状态 | 进行中 | 发布后变为IN_PROGRESS | **通过** |
|
||||
| TPS-003 | 结束日期后状态 | 已结束 | 未测试(需等待时间) | **阻塞** |
|
||||
|
||||
### 2.3 进度跟踪测试(TPP系列)
|
||||
|
||||
| 用例编号 | 测试项 | 预期结果 | 实际结果 | 状态 |
|
||||
|---------|--------|---------|---------|------|
|
||||
| TPP-001 | 学员完成知识学习 | 进度更新 | 依赖知识数据 | **阻塞** |
|
||||
| TPP-002 | 学员完成关联考试 | 进度更新 | 依赖考试数据 | **阻塞** |
|
||||
| TPP-003 | 学员查看自己的学习进度 | 进度显示正确 | 学员可查看,进度为0% | **通过** |
|
||||
| TPP-004 | 讲师查看学员培训进度 | 可查看本部门 | 依赖学习数据 | **阻塞** |
|
||||
|
||||
### 2.4 权限测试
|
||||
|
||||
| 用例编号 | 测试项 | 预期结果 | 实际结果 | 状态 |
|
||||
|---------|--------|---------|---------|------|
|
||||
| TP-权限 | 学员访问培训计划管理接口 | 返回403 | 返回200,可查询培训计划列表 | **失败** |
|
||||
|
||||
---
|
||||
|
||||
## 三、缺陷清单
|
||||
|
||||
### BUG-TP-001:学员可以访问培训计划管理接口
|
||||
|
||||
| 属性 | 描述 |
|
||||
|------|------|
|
||||
| 缺陷编号 | BUG-TP-001 |
|
||||
| 关联用例 | TP-权限 |
|
||||
| 严重程度 | **严重** |
|
||||
| 优先级 | P0 |
|
||||
| 缺陷描述 | 学员角色可以访问培训计划管理的分页查询接口 |
|
||||
| 重现步骤 | 1. 学员账号登录<br>2. GET /api/training/plan/page<br>3. 成功返回培训计划列表 |
|
||||
| 预期结果 | 返回403 Forbidden |
|
||||
| 实际结果 | 返回200 OK,可查看培训计划管理数据 |
|
||||
| 建议修复 | 在TrainingPlanController的管理类接口上添加角色权限控制 |
|
||||
|
||||
---
|
||||
|
||||
## 四、测试覆盖接口
|
||||
|
||||
| 接口 | 方法 | 测试状态 | 结果 |
|
||||
|------|------|---------|------|
|
||||
| /api/training/plan | POST | 已测试 | 通过 |
|
||||
| /api/training/plan/{id} | GET | 已测试 | 通过 |
|
||||
| /api/training/plan/{id}/publish | POST | 已测试 | 通过 |
|
||||
| /api/training/plan/page | GET | 已测试 | 通过 |
|
||||
| /api/training/plan/my | GET | 已测试 | 通过 |
|
||||
| /api/training/plan/my/{planId}/progress | GET | 已测试 | 通过 |
|
||||
|
||||
---
|
||||
|
||||
## 五、测试数据
|
||||
|
||||
### 5.1 测试创建的培训计划
|
||||
|
||||
| ID | 标题 | 状态 | 部门 |
|
||||
|----|------|------|------|
|
||||
| 1 | Test Training Plan 001 | IN_PROGRESS | 救援一部 |
|
||||
|
||||
---
|
||||
|
||||
## 六、结论与建议
|
||||
|
||||
### 6.1 测试结论
|
||||
|
||||
培训计划模块是**测试通过率最高**的模块(36.4%),基本CRUD功能正常,但存在**1个权限缺陷**。
|
||||
|
||||
### 6.2 正面发现
|
||||
|
||||
1. 培训计划创建成功(未受creator_id问题影响)
|
||||
2. 状态流转正常(NOT_STARTED -> IN_PROGRESS)
|
||||
3. 学员端接口正常(/my、/progress)
|
||||
|
||||
### 6.3 待改进
|
||||
|
||||
1. 修复学员权限控制问题
|
||||
2. 修复上游模块后补充知识关联、考试关联的测试
|
||||
|
||||
---
|
||||
|
||||
**报告生成时间:** 2026-01-09 15:45:00
|
||||
@@ -1,195 +0,0 @@
|
||||
# 道路救援企业培训系统 - 测试总报告
|
||||
|
||||
> 测试日期:2026-01-09
|
||||
> 测试人员:AI测试工程师
|
||||
> 测试环境:Spring Boot 3.1.2 / MySQL 8.0 / JDK 17
|
||||
> 测试范围:PRD V1.0 MVP版本(模块1.3-模块6)
|
||||
|
||||
---
|
||||
|
||||
## 一、测试执行概览
|
||||
|
||||
### 1.1 总体统计
|
||||
|
||||
| 指标 | 数值 |
|
||||
|------|------|
|
||||
| 计划用例数 | 79 |
|
||||
| 已执行 | 79 |
|
||||
| **通过** | **11** |
|
||||
| **失败** | **11** |
|
||||
| **阻塞** | **57** |
|
||||
| **通过率** | **13.9%** |
|
||||
|
||||
### 1.2 各模块测试结果
|
||||
|
||||
| 模块 | 用例数 | 通过 | 失败 | 阻塞 | 通过率 |
|
||||
|------|--------|------|------|------|--------|
|
||||
| 1.3 员工管理 | 7 | 4 | 3 | 0 | 57.1% |
|
||||
| 2.0 知识库 | 19 | 2 | 2 | 15 | 10.5% |
|
||||
| 3.0 考题管理 | 11 | 0 | 3 | 8 | 0% |
|
||||
| 4.0 试卷管理 | 11 | 0 | 1 | 10 | 0% |
|
||||
| 5.0 考试管理 | 20 | 1 | 1 | 18 | 5% |
|
||||
| 6.0 培训计划 | 11 | 4 | 1 | 6 | 36.4% |
|
||||
|
||||
---
|
||||
|
||||
## 二、缺陷统计
|
||||
|
||||
### 2.1 缺陷严重程度分布
|
||||
|
||||
| 严重程度 | 数量 | 占比 |
|
||||
|---------|------|------|
|
||||
| **阻断(Blocker)** | 3 | 27.3% |
|
||||
| **严重(Critical)** | 6 | 54.5% |
|
||||
| **高(High)** | 2 | 18.2% |
|
||||
| **中(Medium)** | 0 | 0% |
|
||||
| 合计 | 11 | 100% |
|
||||
|
||||
### 2.2 缺陷清单汇总
|
||||
|
||||
| 缺陷编号 | 模块 | 严重程度 | 描述 | 状态 |
|
||||
|---------|------|---------|------|------|
|
||||
| BUG-USER-001 | 员工管理 | 中 | 手机号未做唯一性校验 | 待修复 |
|
||||
| BUG-USER-002 | 员工管理 | 高 | 讲师未实现部门数据隔离 | 待修复 |
|
||||
| BUG-USER-003 | 员工管理 | **严重** | 学员可访问员工管理接口 | 待修复 |
|
||||
| BUG-KM-001 | 知识库 | **阻断** | 创建知识时creator_id未设置 | 待修复 |
|
||||
| BUG-KM-002 | 知识库 | 高 | 讲师可操作其他部门分类 | 待修复 |
|
||||
| BUG-KM-003 | 知识库 | 高 | 文件上传功能异常 | 待修复 |
|
||||
| BUG-Q-001 | 考题管理 | **阻断** | 创建题目时creator_id未设置 | 待修复 |
|
||||
| BUG-Q-002 | 考题管理 | 高 | 讲师可操作其他部门题库 | 待修复 |
|
||||
| BUG-Q-003 | 考题管理 | **严重** | 学员可访问题目管理接口 | 待修复 |
|
||||
| BUG-P-001 | 试卷管理 | **阻断** | 创建试卷时creator_id未设置 | 待修复 |
|
||||
| BUG-P-002 | 试卷管理 | **严重** | 学员可访问试卷管理接口 | 待修复 |
|
||||
| BUG-E-001 | 考试管理 | **严重** | 学员可访问考试管理接口 | 待修复 |
|
||||
| BUG-TP-001 | 培训计划 | **严重** | 学员可访问培训计划管理接口 | 待修复 |
|
||||
|
||||
---
|
||||
|
||||
## 三、共性问题分析
|
||||
|
||||
### 3.1 阻断级问题:creator_id未设置
|
||||
|
||||
**影响范围:** 知识库、考题管理、试卷管理
|
||||
|
||||
**问题描述:** 创建知识/题目/试卷时,未从当前登录用户获取creator_id并设置,导致数据库插入失败。
|
||||
|
||||
**根本原因:** Service层创建实体时未调用SecurityContext获取当前用户ID。
|
||||
|
||||
**修复建议:**
|
||||
```java
|
||||
// 在各ServiceImpl的create方法中添加:
|
||||
Long currentUserId = SecurityContextHolder.getContext().getAuthentication()...
|
||||
entity.setCreatorId(currentUserId);
|
||||
```
|
||||
|
||||
**阻塞影响:**
|
||||
- 知识库:15个用例
|
||||
- 考题管理:8个用例
|
||||
- 试卷管理:10个用例
|
||||
- 考试管理:18个用例(级联阻塞)
|
||||
- **合计:51个用例(占64.6%)**
|
||||
|
||||
---
|
||||
|
||||
### 3.2 严重级问题:学员权限未控制
|
||||
|
||||
**影响范围:** 员工管理、考题管理、试卷管理、考试管理、培训计划
|
||||
|
||||
**问题描述:** 学员角色可以访问管理员/讲师专属的管理接口,存在越权访问风险。
|
||||
|
||||
**安全风险:**
|
||||
- 信息泄露:学员可查看所有员工信息、题库、试卷
|
||||
- 潜在篡改:如果POST/PUT/DELETE接口也未限制,可能造成数据篡改
|
||||
|
||||
**修复建议:**
|
||||
在Controller上添加Spring Security注解:
|
||||
```java
|
||||
@PreAuthorize("hasAnyRole('ADMIN', 'LECTURER')")
|
||||
@GetMapping("/page")
|
||||
public Result<PageResult<XXX>> page(...) { ... }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.3 高优先级问题:讲师部门隔离未实现
|
||||
|
||||
**影响范围:** 员工管理、知识库分类、题库分类
|
||||
|
||||
**问题描述:** 讲师可以查看/操作其他部门的数据,违反PRD中"讲师只能管理本部门"的要求。
|
||||
|
||||
**修复建议:**
|
||||
在Service层添加部门校验:
|
||||
```java
|
||||
Long userDeptId = getCurrentUserDepartmentId();
|
||||
if (!userDeptId.equals(dto.getDepartmentId())) {
|
||||
throw new BusinessException("无权操作其他部门数据");
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、测试结论
|
||||
|
||||
### 4.1 系统当前状态
|
||||
|
||||
| 评估项 | 状态 | 说明 |
|
||||
|--------|------|------|
|
||||
| 基础功能 | **部分可用** | 员工管理、培训计划基础功能可用 |
|
||||
| 核心业务 | **不可用** | 知识库、考试流程因creator_id问题无法使用 |
|
||||
| 权限控制 | **存在漏洞** | 学员可越权访问管理接口 |
|
||||
| 数据隔离 | **未实现** | 讲师部门隔离未生效 |
|
||||
|
||||
### 4.2 上线评估
|
||||
|
||||
**结论:当前版本不建议上线**
|
||||
|
||||
**原因:**
|
||||
1. 存在3个阻断级BUG,核心业务流程无法使用
|
||||
2. 存在6个严重级权限漏洞,安全风险高
|
||||
3. 测试通过率仅13.9%,远低于上线标准(通常≥90%)
|
||||
|
||||
### 4.3 修复优先级建议
|
||||
|
||||
| 优先级 | 问题 | 预计影响 |
|
||||
|--------|------|---------|
|
||||
| **P0** | creator_id未设置(3处) | 修复后可解除51个用例阻塞 |
|
||||
| **P0** | 学员权限控制(5处) | 修复后消除越权访问风险 |
|
||||
| **P1** | 讲师部门隔离(3处) | 修复后满足PRD数据隔离要求 |
|
||||
| **P1** | 文件上传异常 | 修复后知识库文件功能可用 |
|
||||
| **P2** | 手机号唯一性校验 | 修复后防止重复数据 |
|
||||
|
||||
---
|
||||
|
||||
## 五、下一步行动
|
||||
|
||||
### 5.1 短期(修复后)
|
||||
|
||||
1. 修复creator_id问题后,重新执行知识库、考题、试卷、考试模块测试
|
||||
2. 修复权限问题后,执行权限矩阵完整测试
|
||||
3. 修复部门隔离后,执行数据隔离专项测试
|
||||
|
||||
### 5.2 中期
|
||||
|
||||
1. 补充边界测试用例执行
|
||||
2. 执行接口自动化测试
|
||||
3. 执行性能压力测试
|
||||
|
||||
---
|
||||
|
||||
## 六、测试报告文件清单
|
||||
|
||||
| 报告名称 | 文件路径 |
|
||||
|---------|---------|
|
||||
| 1.3 员工管理测试报告 | docs/test-reports/TestReport_1.3_UserManagement.md |
|
||||
| 2.0 知识库测试报告 | docs/test-reports/TestReport_2.0_Knowledge.md |
|
||||
| 3.0 考题管理测试报告 | docs/test-reports/TestReport_3.0_Question.md |
|
||||
| 4.0 试卷管理测试报告 | docs/test-reports/TestReport_4.0_Paper.md |
|
||||
| 5.0 考试管理测试报告 | docs/test-reports/TestReport_5.0_Exam.md |
|
||||
| 6.0 培训计划测试报告 | docs/test-reports/TestReport_6.0_TrainingPlan.md |
|
||||
| 测试总报告 | docs/test-reports/TestReport_Summary.md |
|
||||
|
||||
---
|
||||
|
||||
**报告生成时间:** 2026-01-09 15:50:00
|
||||
|
||||
**报告签发:** AI测试工程师
|
||||
@@ -1,310 +0,0 @@
|
||||
# 登录模块测试报告
|
||||
|
||||
## 一、测试概述
|
||||
|
||||
### 1.1 测试目标
|
||||
对道路救援培训系统的**登录模块**进行全面的前后端测试,验证其功能正确性、安全性和用户体验。
|
||||
|
||||
### 1.2 测试范围
|
||||
- **JWT工具类测试**:JwtUtils 的单元测试
|
||||
- **认证服务层测试**:AuthService 的单元测试
|
||||
- **认证控制器测试**:AuthController 的接口测试
|
||||
- **前端代码审查**:login.html 页面功能审查
|
||||
|
||||
### 1.3 测试时间
|
||||
2026-01-08
|
||||
|
||||
---
|
||||
|
||||
## 二、系统架构分析
|
||||
|
||||
### 2.1 认证流程
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────────┐
|
||||
│ 登录认证流程 │
|
||||
└──────────────────────────────────────────────────────────────────┘
|
||||
|
||||
┌─────────┐ POST /login ┌──────────────┐ 验证用户 ┌──────────┐
|
||||
│ 前端 │ ─────────────────► │ AuthController│ ──────────► │AuthService│
|
||||
│ login │ {username,passwd} │ │ │ │
|
||||
└─────────┘ └──────────────┘ └──────────┘
|
||||
│ │ │
|
||||
│ │ ▼
|
||||
│ │ ┌──────────┐
|
||||
│ │ │UserMapper │
|
||||
│ │ │ (数据库) │
|
||||
│ │ └──────────┘
|
||||
│ │ │
|
||||
│ │ ▼
|
||||
│ │ ┌──────────┐
|
||||
│ │ 生成Token │ JwtUtils │
|
||||
│ │ ◄──────────────── │ │
|
||||
│ │ └──────────┘
|
||||
│ │
|
||||
│ 返回Token+用户信息 │
|
||||
│ ◄───────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ localStorage存储Token,后续请求自动附加 Authorization: Bearer │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 2.2 技术栈
|
||||
| 组件 | 技术 |
|
||||
|-----|-----|
|
||||
| 后端框架 | Spring Boot 3.1.2 |
|
||||
| JWT库 | com.auth0:java-jwt |
|
||||
| 密码加密 | Spring Security BCrypt |
|
||||
| 前端框架 | Bootstrap 5 + 原生JS |
|
||||
| 测试框架 | JUnit 5 + Mockito |
|
||||
|
||||
---
|
||||
|
||||
## 三、后端测试
|
||||
|
||||
### 3.1 测试用例统计
|
||||
|
||||
| 测试类 | 测试方法数 | 通过 | 失败 | 通过率 |
|
||||
|-------|-----------|------|-----|--------|
|
||||
| JwtUtilsTest | 19 | 19 | 0 | 100% |
|
||||
| AuthServiceTest | 11 | 11 | 0 | 100% |
|
||||
| AuthControllerTest | 11 | 11 | 0 | 100% |
|
||||
| **总计** | **41** | **41** | **0** | **100%** |
|
||||
|
||||
### 3.2 JwtUtils 测试详情
|
||||
|
||||
#### 3.2.1 生成Token测试 (GenerateTokenTest)
|
||||
| 序号 | 测试场景 | 预期结果 | 测试结果 |
|
||||
|-----|---------|---------|---------|
|
||||
| 1 | 正常生成Token | 返回有效JWT字符串(header.payload.signature格式) | PASS |
|
||||
| 2 | 不同用户生成不同Token | 两个Token不相等 | PASS |
|
||||
| 3 | 同用户超过1秒后生成Token | Token不同,但包含相同用户信息 | PASS |
|
||||
|
||||
#### 3.2.2 验证Token测试 (VerifyTokenTest)
|
||||
| 序号 | 测试场景 | 预期结果 | 测试结果 |
|
||||
|-----|---------|---------|---------|
|
||||
| 1 | 有效Token | 返回DecodedJWT,包含正确claims | PASS |
|
||||
| 2 | 无效Token | 返回null | PASS |
|
||||
| 3 | 空Token | 返回null | PASS |
|
||||
| 4 | null Token | 返回null | PASS |
|
||||
| 5 | 被篡改的Token | 返回null | PASS |
|
||||
| 6 | 错误密钥签名的Token | 返回null | PASS |
|
||||
|
||||
#### 3.2.3 获取用户ID测试 (GetUserIdTest)
|
||||
| 序号 | 测试场景 | 预期结果 | 测试结果 |
|
||||
|-----|---------|---------|---------|
|
||||
| 1 | 有效Token获取用户ID | 返回正确的Long类型用户ID | PASS |
|
||||
| 2 | 无效Token获取用户ID | 返回null | PASS |
|
||||
|
||||
#### 3.2.4 获取用户名测试 (GetUsernameTest)
|
||||
| 序号 | 测试场景 | 预期结果 | 测试结果 |
|
||||
|-----|---------|---------|---------|
|
||||
| 1 | 有效Token获取用户名 | 返回正确的用户名字符串 | PASS |
|
||||
| 2 | 无效Token获取用户名 | 返回null | PASS |
|
||||
|
||||
#### 3.2.5 获取角色测试 (GetRoleTest)
|
||||
| 序号 | 测试场景 | 预期结果 | 测试结果 |
|
||||
|-----|---------|---------|---------|
|
||||
| 1 | 有效Token获取角色 | 返回正确的角色(ADMIN/LECTURER/STUDENT) | PASS |
|
||||
| 2 | 不同角色Token | 各返回对应角色字符串 | PASS |
|
||||
|
||||
#### 3.2.6 Token过期测试 (IsTokenExpiredTest)
|
||||
| 序号 | 测试场景 | 预期结果 | 测试结果 |
|
||||
|-----|---------|---------|---------|
|
||||
| 1 | 未过期Token | 返回false | PASS |
|
||||
| 2 | 已过期Token | 返回true | PASS |
|
||||
| 3 | 无效Token | 返回true | PASS |
|
||||
|
||||
#### 3.2.7 Token完整性测试 (TokenIntegrityTest)
|
||||
| 序号 | 测试场景 | 预期结果 | 测试结果 |
|
||||
|-----|---------|---------|---------|
|
||||
| 1 | Token包含所有claims | subject、username、role、issuedAt、expiresAt均存在 | PASS |
|
||||
|
||||
### 3.3 AuthService 测试详情
|
||||
|
||||
#### 3.3.1 登录测试 (LoginTest)
|
||||
| 序号 | 测试场景 | 预期结果 | 测试结果 |
|
||||
|-----|---------|---------|---------|
|
||||
| 1 | 正常登录 | 返回Token和完整用户信息 | PASS |
|
||||
| 2 | 用户不存在 | 抛出BusinessException,code=USER_NOT_FOUND | PASS |
|
||||
| 3 | 密码错误 | 抛出BusinessException,code=PASSWORD_ERROR | PASS |
|
||||
| 4 | 用户被禁用 | 抛出BusinessException,code=USER_DISABLED | PASS |
|
||||
| 5 | 不同角色用户登录 | 返回对应角色信息(STUDENT) | PASS |
|
||||
| 6 | 用户无部门 | 正常登录,departmentName为null | PASS |
|
||||
|
||||
#### 3.3.2 获取当前用户信息测试 (GetCurrentUserInfoTest)
|
||||
| 序号 | 测试场景 | 预期结果 | 测试结果 |
|
||||
|-----|---------|---------|---------|
|
||||
| 1 | 有效上下文 | 返回完整用户信息 | PASS |
|
||||
| 2 | 无上下文 | 抛出BusinessException,code=UNAUTHORIZED | PASS |
|
||||
| 3 | 上下文用户ID为空 | 抛出BusinessException,code=UNAUTHORIZED | PASS |
|
||||
| 4 | 用户已被删除 | 抛出BusinessException,code=USER_NOT_FOUND | PASS |
|
||||
|
||||
#### 3.3.3 退出登录测试 (LogoutTest)
|
||||
| 序号 | 测试场景 | 预期结果 | 测试结果 |
|
||||
|-----|---------|---------|---------|
|
||||
| 1 | 正常退出 | 清除UserContext,不抛异常 | PASS |
|
||||
|
||||
### 3.4 AuthController 测试详情
|
||||
|
||||
#### 3.4.1 POST /login - 账号密码登录
|
||||
| 序号 | 测试场景 | HTTP状态 | 业务码 | 测试结果 |
|
||||
|-----|---------|---------|-------|---------|
|
||||
| 1 | 有效凭证登录 | 200 | 200 | PASS |
|
||||
| 2 | 用户名为空 | 400 | - | PASS |
|
||||
| 3 | 密码为空 | 400 | - | PASS |
|
||||
| 4 | 用户名和密码都为空 | 400 | - | PASS |
|
||||
| 5 | 用户不存在 | 200 | USER_NOT_FOUND | PASS |
|
||||
| 6 | 密码错误 | 200 | PASSWORD_ERROR | PASS |
|
||||
| 7 | 用户被禁用 | 200 | USER_DISABLED | PASS |
|
||||
| 8 | 请求体为空 | 400 | - | PASS |
|
||||
|
||||
#### 3.4.2 GET /userinfo - 获取当前用户信息
|
||||
| 序号 | 测试场景 | HTTP状态 | 业务码 | 测试结果 |
|
||||
|-----|---------|---------|-------|---------|
|
||||
| 1 | 已认证用户 | 200 | 200 | PASS |
|
||||
| 2 | 未认证用户 | 200 | UNAUTHORIZED | PASS |
|
||||
|
||||
#### 3.4.3 POST /logout - 退出登录
|
||||
| 序号 | 测试场景 | HTTP状态 | 业务码 | 测试结果 |
|
||||
|-----|---------|---------|-------|---------|
|
||||
| 1 | 正常退出 | 200 | 200 | PASS |
|
||||
|
||||
---
|
||||
|
||||
## 四、前端代码审查
|
||||
|
||||
### 4.1 页面结构分析
|
||||
**文件路径**:`src/main/resources/templates/login.html`
|
||||
|
||||
#### 4.1.1 UI组件
|
||||
| 组件 | 实现状态 | 说明 |
|
||||
|-----|---------|-----|
|
||||
| 用户名输入框 | 已实现 | 带图标、浮动标签 |
|
||||
| 密码输入框 | 已实现 | 带图标、显示/隐藏切换 |
|
||||
| 记住我复选框 | 已实现 | 未与后端关联 |
|
||||
| 登录按钮 | 已实现 | 带Loading状态 |
|
||||
| 企业微信登录 | 已实现 | 跳转OAuth授权页面 |
|
||||
|
||||
#### 4.1.2 功能清单
|
||||
| 功能 | 实现状态 | 备注 |
|
||||
|-----|---------|-----|
|
||||
| 表单验证 | 已实现 | HTML5 required + JS校验 |
|
||||
| 密码显示切换 | 已实现 | 切换input type |
|
||||
| 登录Loading状态 | 已实现 | 按钮禁用+Spinner |
|
||||
| 登录成功跳转 | 已实现 | 延迟500ms跳转首页 |
|
||||
| 错误消息提示 | 已实现 | Toast通知 |
|
||||
| 已登录检测 | 已实现 | 自动跳转首页 |
|
||||
| 企业微信登录 | 已实现 | 跳转OAuth流程 |
|
||||
| 回车提交 | 已实现 | 监听密码框keypress |
|
||||
|
||||
### 4.2 API调用分析
|
||||
|
||||
| 功能 | API接口 | HTTP方法 | 请求体 |
|
||||
|-----|--------|---------|-------|
|
||||
| 账号登录 | `/api/auth/login` | POST | `{username, password}` |
|
||||
| 企业微信授权 | `/api/auth/wechat/authorize` | GET (跳转) | - |
|
||||
|
||||
### 4.3 安全机制
|
||||
|
||||
| 安全措施 | 实现状态 | 说明 |
|
||||
|---------|---------|-----|
|
||||
| Token存储 | localStorage | `training_token` 键名 |
|
||||
| 请求认证 | Bearer Token | Authorization头 |
|
||||
| 密码传输 | HTTPS(假设生产环境) | 明文POST |
|
||||
| XSS防护 | 部分实现 | Toast消息直接插入HTML |
|
||||
| CSRF防护 | 无状态JWT | 不需要CSRF Token |
|
||||
|
||||
### 4.4 代码质量评估
|
||||
|
||||
#### 优点
|
||||
1. **UI设计美观**:渐变背景、圆角卡片、图标点缀
|
||||
2. **响应式设计**:移动端适配(@media max-width: 480px)
|
||||
3. **用户体验好**:Loading状态、密码显示切换、错误提示
|
||||
4. **代码组织清晰**:CSS样式集中、JS逻辑分离
|
||||
5. **复用性高**:使用TrainingSystem全局对象统一管理
|
||||
|
||||
#### 潜在改进点
|
||||
1. **XSS风险**:`showMessage`函数中`${text}`直接插入HTML
|
||||
2. **记住我功能**:UI存在但未实际实现(需Token持久化策略)
|
||||
3. **密码强度**:无前端密码强度检查
|
||||
4. **错误重试**:无登录失败重试限制机制(后端需配合)
|
||||
5. **表单校验**:缺少用户名/密码长度限制提示
|
||||
|
||||
---
|
||||
|
||||
## 五、测试总结
|
||||
|
||||
### 5.1 测试结论
|
||||
登录模块的**后端测试全部通过**,共41个测试用例,通过率**100%**。
|
||||
|
||||
### 5.2 功能完整性
|
||||
| 功能模块 | 状态 |
|
||||
|---------|-----|
|
||||
| JWT Token生成与验证 | 正常 |
|
||||
| 用户名密码登录 | 正常 |
|
||||
| 密码BCrypt加密验证 | 正常 |
|
||||
| 用户状态检查 | 正常 |
|
||||
| 获取当前用户信息 | 正常 |
|
||||
| 退出登录 | 正常 |
|
||||
| 前后端接口对接 | 正常 |
|
||||
| 响应式UI | 正常 |
|
||||
|
||||
### 5.3 安全性评估
|
||||
| 安全项 | 评分 | 说明 |
|
||||
|-------|-----|-----|
|
||||
| 密码存储 | 优 | BCrypt加密,不可逆 |
|
||||
| Token安全 | 良 | HMAC256签名,24小时过期 |
|
||||
| 传输安全 | - | 需确保HTTPS部署 |
|
||||
| 输入验证 | 良 | 后端@NotBlank验证 |
|
||||
| 异常处理 | 优 | 统一异常处理,不泄露敏感信息 |
|
||||
|
||||
### 5.4 已发现并修复的问题
|
||||
|
||||
| 问题 | 文件 | 修复方式 |
|
||||
|-----|-----|---------|
|
||||
| JWT时间戳精度导致测试失败 | JwtUtilsTest.java | 测试延迟改为1100ms |
|
||||
|
||||
### 5.5 测试文件清单
|
||||
```
|
||||
src/test/java/com/sino/training/
|
||||
├── common/utils/
|
||||
│ └── JwtUtilsTest.java (19个测试用例)
|
||||
└── module/auth/
|
||||
├── controller/
|
||||
│ └── AuthControllerTest.java (11个测试用例)
|
||||
└── service/
|
||||
└── AuthServiceTest.java (11个测试用例)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、附录
|
||||
|
||||
### 6.1 执行命令
|
||||
```bash
|
||||
mvn test -Dtest=AuthServiceTest,AuthControllerTest,JwtUtilsTest -DfailIfNoTests=false
|
||||
```
|
||||
|
||||
### 6.2 测试执行结果
|
||||
```
|
||||
[INFO] Tests run: 41, Failures: 0, Errors: 0, Skipped: 0
|
||||
[INFO] BUILD SUCCESS
|
||||
```
|
||||
|
||||
### 6.3 核心代码路径
|
||||
| 模块 | 文件路径 |
|
||||
|-----|---------|
|
||||
| 控制器 | `src/main/java/com/sino/training/module/auth/controller/AuthController.java` |
|
||||
| 服务实现 | `src/main/java/com/sino/training/module/auth/service/impl/AuthServiceImpl.java` |
|
||||
| JWT工具 | `src/main/java/com/sino/training/common/utils/JwtUtils.java` |
|
||||
| 认证拦截器 | `src/main/java/com/sino/training/common/interceptor/AuthInterceptor.java` |
|
||||
| 前端页面 | `src/main/resources/templates/login.html` |
|
||||
| 公共JS | `src/main/resources/static/js/common.js` |
|
||||
|
||||
---
|
||||
|
||||
**测试工程师**:AI Testing Assistant
|
||||
**报告日期**:2026-01-08
|
||||
@@ -1,219 +0,0 @@
|
||||
# 题库分类模块测试报告
|
||||
|
||||
## 一、测试概述
|
||||
|
||||
### 1.1 测试目标
|
||||
对道路救援培训系统的**题库分类模块**进行全面的前后端测试,验证其功能正确性、接口稳定性和用户体验。
|
||||
|
||||
### 1.2 测试范围
|
||||
- **后端服务层测试**:QuestionCategoryService 的单元测试
|
||||
- **后端控制器测试**:QuestionCategoryController 的接口测试
|
||||
- **前端代码审查**:question-category.html 页面功能审查
|
||||
|
||||
### 1.3 测试时间
|
||||
2026-01-08
|
||||
|
||||
---
|
||||
|
||||
## 二、后端测试
|
||||
|
||||
### 2.1 测试环境
|
||||
- **技术框架**:Spring Boot 3.1.2 + MyBatis Plus
|
||||
- **测试框架**:JUnit 5 + Mockito
|
||||
- **Java版本**:JDK 17
|
||||
|
||||
### 2.2 测试用例统计
|
||||
|
||||
| 测试类 | 测试方法数 | 通过 | 失败 | 通过率 |
|
||||
|-------|-----------|------|-----|--------|
|
||||
| QuestionCategoryServiceTest | 17 | 17 | 0 | 100% |
|
||||
| QuestionCategoryControllerTest | 14 | 14 | 0 | 100% |
|
||||
| **总计** | **31** | **31** | **0** | **100%** |
|
||||
|
||||
### 2.3 Service层测试详情
|
||||
|
||||
#### 2.3.1 创建分类测试 (CreateCategoryTest)
|
||||
| 序号 | 测试场景 | 预期结果 | 测试结果 |
|
||||
|-----|---------|---------|---------|
|
||||
| 1 | 正常创建分类 | 返回新建分类ID | PASS |
|
||||
| 2 | 部门不存在 | 抛出BusinessException,消息包含"部门不存在" | PASS |
|
||||
| 3 | 父分类不存在 | 抛出BusinessException,消息包含"父分类不存在" | PASS |
|
||||
| 4 | 同级同名分类已存在 | 抛出BusinessException,消息包含"同名分类" | PASS |
|
||||
| 5 | parentId为null时默认为0 | parentId自动设置为0L | PASS |
|
||||
|
||||
#### 2.3.2 更新分类测试 (UpdateCategoryTest)
|
||||
| 序号 | 测试场景 | 预期结果 | 测试结果 |
|
||||
|-----|---------|---------|---------|
|
||||
| 1 | 正常更新分类 | 更新成功,调用updateById | PASS |
|
||||
| 2 | ID为空 | 抛出BusinessException,消息包含"ID不能为空" | PASS |
|
||||
| 3 | 分类不存在 | 抛出BusinessException | PASS |
|
||||
| 4 | 将自己设为父分类 | 抛出BusinessException,消息包含"不能将自己设为父分类" | PASS |
|
||||
| 5 | 同级同名分类已存在 | 抛出BusinessException,消息包含"同名分类" | PASS |
|
||||
|
||||
#### 2.3.3 删除分类测试 (DeleteCategoryTest)
|
||||
| 序号 | 测试场景 | 预期结果 | 测试结果 |
|
||||
|-----|---------|---------|---------|
|
||||
| 1 | 分类不存在 | 抛出BusinessException | PASS |
|
||||
| 2 | 存在子分类 | 抛出BusinessException,消息包含"子分类" | PASS |
|
||||
| 3 | 存在关联题目 | 抛出BusinessException,消息包含"题目" | PASS |
|
||||
|
||||
#### 2.3.4 获取分类详情测试 (GetCategoryDetailTest)
|
||||
| 序号 | 测试场景 | 预期结果 | 测试结果 |
|
||||
|-----|---------|---------|---------|
|
||||
| 1 | 获取存在的分类详情 | 返回完整信息,包含父分类名称和部门名称 | PASS |
|
||||
| 2 | 分类不存在 | 抛出BusinessException | PASS |
|
||||
|
||||
#### 2.3.5 获取分类树测试 (GetCategoryTreeTest)
|
||||
| 序号 | 测试场景 | 预期结果 | 测试结果 |
|
||||
|-----|---------|---------|---------|
|
||||
| 1 | 获取全部分类树 | 返回正确的树形结构 | PASS |
|
||||
| 2 | 按部门ID筛选 | 返回指定部门的分类树 | PASS |
|
||||
|
||||
### 2.4 Controller层测试详情
|
||||
|
||||
#### 2.4.1 GET /tree - 获取分类树
|
||||
| 序号 | 测试场景 | HTTP状态 | 业务码 | 测试结果 |
|
||||
|-----|---------|---------|-------|---------|
|
||||
| 1 | 无参数获取全部 | 200 | 200 | PASS |
|
||||
| 2 | 按部门ID筛选 | 200 | 200 | PASS |
|
||||
| 3 | 空数据返回空数组 | 200 | 200 | PASS |
|
||||
|
||||
#### 2.4.2 GET /list - 获取分类列表
|
||||
| 序号 | 测试场景 | HTTP状态 | 业务码 | 测试结果 |
|
||||
|-----|---------|---------|-------|---------|
|
||||
| 1 | 获取列表 | 200 | 200 | PASS |
|
||||
|
||||
#### 2.4.3 GET /{id} - 获取分类详情
|
||||
| 序号 | 测试场景 | HTTP状态 | 业务码 | 测试结果 |
|
||||
|-----|---------|---------|-------|---------|
|
||||
| 1 | 获取存在的分类 | 200 | 200 | PASS |
|
||||
| 2 | 分类不存在 | 200 | 错误码 | PASS |
|
||||
|
||||
#### 2.4.4 POST / - 创建分类
|
||||
| 序号 | 测试场景 | HTTP状态 | 业务码 | 测试结果 |
|
||||
|-----|---------|---------|-------|---------|
|
||||
| 1 | 有效数据创建 | 200 | 200 | PASS |
|
||||
| 2 | 同名分类已存在 | 200 | DATA_EXISTS | PASS |
|
||||
|
||||
#### 2.4.5 PUT / - 更新分类
|
||||
| 序号 | 测试场景 | HTTP状态 | 业务码 | 测试结果 |
|
||||
|-----|---------|---------|-------|---------|
|
||||
| 1 | 有效数据更新 | 200 | 200 | PASS |
|
||||
| 2 | 分类不存在 | 200 | CATEGORY_NOT_FOUND | PASS |
|
||||
|
||||
#### 2.4.6 DELETE /{id} - 删除分类
|
||||
| 序号 | 测试场景 | HTTP状态 | 业务码 | 测试结果 |
|
||||
|-----|---------|---------|-------|---------|
|
||||
| 1 | 删除有效分类 | 200 | 200 | PASS |
|
||||
| 2 | 存在子分类 | 200 | DATA_REFERENCED | PASS |
|
||||
| 3 | 存在关联题目 | 200 | DATA_REFERENCED | PASS |
|
||||
| 4 | 分类不存在 | 200 | CATEGORY_NOT_FOUND | PASS |
|
||||
|
||||
---
|
||||
|
||||
## 三、前端代码审查
|
||||
|
||||
### 3.1 页面结构分析
|
||||
**文件路径**:`src/main/resources/templates/exam/question-category.html`
|
||||
|
||||
#### 3.1.1 页面布局
|
||||
- 左侧(40%):树形分类列表
|
||||
- 右侧(60%):分类详情展示
|
||||
- 响应式设计:支持移动端适配
|
||||
|
||||
#### 3.1.2 功能清单
|
||||
| 功能 | 实现状态 | 备注 |
|
||||
|-----|---------|-----|
|
||||
| 分类树展示 | 已实现 | 支持多级嵌套 |
|
||||
| 展开/折叠 | 已实现 | 点击箭头图标切换 |
|
||||
| 选中分类 | 已实现 | 高亮显示,展示详情 |
|
||||
| 新增分类 | 已实现 | 支持顶级和子级 |
|
||||
| 编辑分类 | 已实现 | 模态框编辑 |
|
||||
| 删除分类 | 已实现 | 带确认提示 |
|
||||
| 查看题目数量 | 已实现 | 显示在节点右侧 |
|
||||
| 跳转题目列表 | 已实现 | 带分类ID参数 |
|
||||
|
||||
### 3.2 API调用分析
|
||||
|
||||
| 功能 | API接口 | HTTP方法 |
|
||||
|-----|--------|---------|
|
||||
| 加载分类树 | `/exam/question-category/tree` | GET |
|
||||
| 获取分类详情 | `/exam/question-category/{id}` | GET |
|
||||
| 创建分类 | `/exam/question-category` | POST |
|
||||
| 更新分类 | `/exam/question-category` | PUT |
|
||||
| 删除分类 | `/exam/question-category/{id}` | DELETE |
|
||||
|
||||
### 3.3 代码质量评估
|
||||
|
||||
#### 优点
|
||||
1. **结构清晰**:HTML结构层次分明,CSS样式集中管理
|
||||
2. **交互友好**:提供操作反馈(成功/失败消息)
|
||||
3. **防误操作**:删除前确认提示
|
||||
4. **代码复用**:使用`TrainingSystem`全局对象统一API调用
|
||||
5. **递归渲染**:正确处理多级树形结构
|
||||
|
||||
#### 潜在改进点
|
||||
1. **XSS防护**:`item.name`直接插入HTML,建议使用转义函数
|
||||
2. **错误处理**:网络异常时可增加重试机制
|
||||
3. **加载状态**:长时间操作时可添加loading遮罩
|
||||
4. **表单验证**:前端缺少分类名称长度限制
|
||||
|
||||
---
|
||||
|
||||
## 四、测试总结
|
||||
|
||||
### 4.1 测试结论
|
||||
题库分类模块的**后端测试全部通过**,共31个测试用例,通过率**100%**。
|
||||
|
||||
### 4.2 功能完整性
|
||||
| 功能模块 | 状态 |
|
||||
|---------|-----|
|
||||
| 分类树结构 | 正常 |
|
||||
| 分类CRUD操作 | 正常 |
|
||||
| 业务规则校验 | 正常 |
|
||||
| 异常处理 | 正常 |
|
||||
| 前后端接口对接 | 正常 |
|
||||
|
||||
### 4.3 已发现问题
|
||||
|
||||
#### 编译错误(已修复)
|
||||
在测试过程中发现并修复了以下编译错误:
|
||||
|
||||
| 问题 | 文件 | 修复方式 |
|
||||
|-----|-----|---------|
|
||||
| Long转int类型错误 | ExamServiceImpl.java:287 | 使用`.intValue()` |
|
||||
| Long转int类型错误 | PaperServiceImpl.java:364 | 使用`.intValue()` |
|
||||
| 方法名错误 | TrainingPlanServiceImpl.java | `getKnowledgeType()`→`getType()` |
|
||||
| 字段名错误 | TrainingPlanServiceImpl.java | `setKnowledgeType`→`setType` |
|
||||
|
||||
#### 测试依赖(已添加)
|
||||
添加了`spring-security-test`依赖以支持安全测试。
|
||||
|
||||
### 4.4 测试文件清单
|
||||
```
|
||||
src/test/java/com/sino/training/module/exam/
|
||||
├── service/
|
||||
│ └── QuestionCategoryServiceTest.java (17个测试用例)
|
||||
└── controller/
|
||||
└── QuestionCategoryControllerTest.java (14个测试用例)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、附录
|
||||
|
||||
### 5.1 执行命令
|
||||
```bash
|
||||
mvn test -Dtest=QuestionCategoryServiceTest,QuestionCategoryControllerTest
|
||||
```
|
||||
|
||||
### 5.2 测试执行结果
|
||||
```
|
||||
[INFO] Tests run: 31, Failures: 0, Errors: 0, Skipped: 0
|
||||
[INFO] BUILD SUCCESS
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**测试工程师**:AI Testing Assistant
|
||||
**报告日期**:2026-01-08
|
||||
@@ -1,151 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>3.1.2</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
<groupId>com.sino</groupId>
|
||||
<artifactId>training-system</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<name>training-system</name>
|
||||
<description>道路救援企业培训系统</description>
|
||||
|
||||
<properties>
|
||||
<java.version>17</java.version>
|
||||
<mybatis-plus.version>3.5.3.1</mybatis-plus.version>
|
||||
<java-jwt.version>4.4.0</java-jwt.version>
|
||||
<hutool.version>5.8.22</hutool.version>
|
||||
<easyexcel.version>3.3.2</easyexcel.version>
|
||||
<weixin-java.version>4.5.0</weixin-java.version>
|
||||
<springdoc.version>2.2.0</springdoc.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!-- Spring Boot Web -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Boot Thymeleaf (页面模板) -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Boot Validation -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Security (仅用于BCrypt密码加密) -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- MyBatis Plus -->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||
<version>${mybatis-plus.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- MySQL Driver -->
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- JWT Token -->
|
||||
<dependency>
|
||||
<groupId>com.auth0</groupId>
|
||||
<artifactId>java-jwt</artifactId>
|
||||
<version>${java-jwt.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Lombok -->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- Hutool 工具库 -->
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>${hutool.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- EasyExcel (Excel导入导出) -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>easyexcel</artifactId>
|
||||
<version>${easyexcel.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 企业微信SDK -->
|
||||
<dependency>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<artifactId>weixin-java-cp</artifactId>
|
||||
<version>${weixin-java.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Springdoc OpenAPI (API文档) -->
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId>
|
||||
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
|
||||
<version>${springdoc.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Boot DevTools (开发热重载) -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
<scope>runtime</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Boot Test -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Security Test -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
@@ -1,405 +0,0 @@
|
||||
-- =============================================
|
||||
-- 道路救援企业培训系统 - 数据库初始化脚本
|
||||
-- 数据库:MySQL 8.0
|
||||
-- 字符集:utf8mb4
|
||||
-- =============================================
|
||||
|
||||
-- 创建数据库
|
||||
CREATE DATABASE IF NOT EXISTS training_system
|
||||
DEFAULT CHARACTER SET utf8mb4
|
||||
DEFAULT COLLATE utf8mb4_general_ci;
|
||||
|
||||
USE training_system;
|
||||
|
||||
-- =============================================
|
||||
-- 一、系统管理模块
|
||||
-- =============================================
|
||||
|
||||
-- 1.1 中心表
|
||||
DROP TABLE IF EXISTS sys_center;
|
||||
CREATE TABLE sys_center (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
|
||||
name VARCHAR(100) NOT NULL COMMENT '中心名称',
|
||||
sort_order INT DEFAULT 0 COMMENT '排序',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
deleted TINYINT DEFAULT 0 COMMENT '逻辑删除(0-未删除,1-已删除)',
|
||||
INDEX idx_deleted (deleted)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='中心表';
|
||||
|
||||
-- 1.2 部门表
|
||||
DROP TABLE IF EXISTS sys_department;
|
||||
CREATE TABLE sys_department (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
|
||||
name VARCHAR(100) NOT NULL COMMENT '部门名称',
|
||||
center_id BIGINT NOT NULL COMMENT '所属中心ID',
|
||||
sort_order INT DEFAULT 0 COMMENT '排序',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
deleted TINYINT DEFAULT 0 COMMENT '逻辑删除(0-未删除,1-已删除)',
|
||||
INDEX idx_center_id (center_id),
|
||||
INDEX idx_deleted (deleted)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='部门表';
|
||||
|
||||
-- 1.3 小组表
|
||||
DROP TABLE IF EXISTS sys_group;
|
||||
CREATE TABLE sys_group (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
|
||||
name VARCHAR(100) NOT NULL COMMENT '小组名称',
|
||||
department_id BIGINT NOT NULL COMMENT '所属部门ID',
|
||||
sort_order INT DEFAULT 0 COMMENT '排序',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
deleted TINYINT DEFAULT 0 COMMENT '逻辑删除(0-未删除,1-已删除)',
|
||||
INDEX idx_department_id (department_id),
|
||||
INDEX idx_deleted (deleted)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='小组表';
|
||||
|
||||
-- 1.4 用户表
|
||||
DROP TABLE IF EXISTS sys_user;
|
||||
CREATE TABLE sys_user (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
|
||||
wx_userid VARCHAR(100) COMMENT '企业微信用户ID',
|
||||
username VARCHAR(50) NOT NULL COMMENT '用户名(登录账号)',
|
||||
password VARCHAR(100) COMMENT '密码(备用登录)',
|
||||
real_name VARCHAR(50) NOT NULL COMMENT '真实姓名',
|
||||
phone VARCHAR(20) COMMENT '手机号',
|
||||
avatar VARCHAR(255) COMMENT '头像URL',
|
||||
role TINYINT NOT NULL DEFAULT 2 COMMENT '角色(0-管理员,1-讲师,2-学员)',
|
||||
department_id BIGINT COMMENT '所属部门ID',
|
||||
group_id BIGINT COMMENT '所属小组ID',
|
||||
status TINYINT DEFAULT 0 COMMENT '状态(0-启用,1-禁用)',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
deleted TINYINT DEFAULT 0 COMMENT '逻辑删除(0-未删除,1-已删除)',
|
||||
UNIQUE INDEX uk_username (username),
|
||||
UNIQUE INDEX uk_wx_userid (wx_userid),
|
||||
INDEX idx_department_id (department_id),
|
||||
INDEX idx_role (role),
|
||||
INDEX idx_deleted (deleted)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
|
||||
|
||||
-- =============================================
|
||||
-- 二、知识库模块
|
||||
-- =============================================
|
||||
|
||||
-- 2.1 知识分类表
|
||||
DROP TABLE IF EXISTS km_category;
|
||||
CREATE TABLE km_category (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
|
||||
name VARCHAR(100) NOT NULL COMMENT '分类名称',
|
||||
parent_id BIGINT DEFAULT 0 COMMENT '父分类ID(0为顶级)',
|
||||
department_id BIGINT NOT NULL COMMENT '所属部门ID',
|
||||
sort_order INT DEFAULT 0 COMMENT '排序',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
deleted TINYINT DEFAULT 0 COMMENT '逻辑删除(0-未删除,1-已删除)',
|
||||
INDEX idx_parent_id (parent_id),
|
||||
INDEX idx_department_id (department_id),
|
||||
INDEX idx_deleted (deleted)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='知识分类表';
|
||||
|
||||
-- 2.2 知识表
|
||||
DROP TABLE IF EXISTS km_knowledge;
|
||||
CREATE TABLE km_knowledge (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
|
||||
title VARCHAR(200) NOT NULL COMMENT '标题',
|
||||
description TEXT COMMENT '描述/摘要',
|
||||
category_id BIGINT COMMENT '所属分类ID',
|
||||
type TINYINT NOT NULL COMMENT '类型(0-文档,1-视频)',
|
||||
file_name VARCHAR(255) COMMENT '文件名',
|
||||
file_url VARCHAR(500) COMMENT '文件URL',
|
||||
file_size BIGINT DEFAULT 0 COMMENT '文件大小(字节)',
|
||||
file_type VARCHAR(20) COMMENT '文件类型/后缀',
|
||||
department_id BIGINT NOT NULL COMMENT '所属部门ID',
|
||||
status TINYINT DEFAULT 0 COMMENT '状态(0-草稿,1-已发布,2-已下架)',
|
||||
creator_id BIGINT NOT NULL COMMENT '创建人ID',
|
||||
publish_time DATETIME COMMENT '发布时间',
|
||||
view_count INT DEFAULT 0 COMMENT '浏览次数',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
deleted TINYINT DEFAULT 0 COMMENT '逻辑删除(0-未删除,1-已删除)',
|
||||
INDEX idx_category_id (category_id),
|
||||
INDEX idx_department_id (department_id),
|
||||
INDEX idx_status (status),
|
||||
INDEX idx_creator_id (creator_id),
|
||||
INDEX idx_deleted (deleted)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='知识表';
|
||||
|
||||
-- =============================================
|
||||
-- 三、考试模块
|
||||
-- =============================================
|
||||
|
||||
-- 3.1 题目分类表
|
||||
DROP TABLE IF EXISTS ex_question_category;
|
||||
CREATE TABLE ex_question_category (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
|
||||
name VARCHAR(100) NOT NULL COMMENT '分类名称',
|
||||
parent_id BIGINT DEFAULT 0 COMMENT '父分类ID(0为顶级)',
|
||||
department_id BIGINT NOT NULL COMMENT '所属部门ID',
|
||||
sort_order INT DEFAULT 0 COMMENT '排序',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
deleted TINYINT DEFAULT 0 COMMENT '逻辑删除(0-未删除,1-已删除)',
|
||||
INDEX idx_parent_id (parent_id),
|
||||
INDEX idx_department_id (department_id),
|
||||
INDEX idx_deleted (deleted)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='题目分类表';
|
||||
|
||||
-- 3.2 题目表
|
||||
DROP TABLE IF EXISTS ex_question;
|
||||
CREATE TABLE ex_question (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
|
||||
type TINYINT NOT NULL COMMENT '题型(0-单选,1-多选,2-判断)',
|
||||
content TEXT NOT NULL COMMENT '题干内容',
|
||||
options JSON COMMENT '选项(JSON格式)',
|
||||
answer VARCHAR(50) NOT NULL COMMENT '正确答案',
|
||||
analysis TEXT COMMENT '答案解析',
|
||||
category_id BIGINT COMMENT '所属分类ID',
|
||||
department_id BIGINT NOT NULL COMMENT '所属部门ID',
|
||||
status TINYINT DEFAULT 0 COMMENT '状态(0-草稿,1-已发布,2-已下架)',
|
||||
creator_id BIGINT NOT NULL COMMENT '创建人ID',
|
||||
publish_time DATETIME COMMENT '发布时间',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
deleted TINYINT DEFAULT 0 COMMENT '逻辑删除(0-未删除,1-已删除)',
|
||||
INDEX idx_type (type),
|
||||
INDEX idx_category_id (category_id),
|
||||
INDEX idx_department_id (department_id),
|
||||
INDEX idx_status (status),
|
||||
INDEX idx_deleted (deleted)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='题目表';
|
||||
|
||||
-- 3.3 试卷表
|
||||
DROP TABLE IF EXISTS ex_paper;
|
||||
CREATE TABLE ex_paper (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
|
||||
title VARCHAR(200) NOT NULL COMMENT '试卷标题',
|
||||
description TEXT COMMENT '试卷描述',
|
||||
total_score INT NOT NULL DEFAULT 100 COMMENT '总分',
|
||||
duration INT NOT NULL DEFAULT 60 COMMENT '考试时长(分钟)',
|
||||
pass_score INT NOT NULL DEFAULT 60 COMMENT '及格分数',
|
||||
department_id BIGINT NOT NULL COMMENT '所属部门ID',
|
||||
status TINYINT DEFAULT 0 COMMENT '状态(0-草稿,1-已发布,2-已下架)',
|
||||
creator_id BIGINT NOT NULL COMMENT '创建人ID',
|
||||
publish_time DATETIME COMMENT '发布时间',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
deleted TINYINT DEFAULT 0 COMMENT '逻辑删除(0-未删除,1-已删除)',
|
||||
INDEX idx_department_id (department_id),
|
||||
INDEX idx_status (status),
|
||||
INDEX idx_deleted (deleted)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='试卷表';
|
||||
|
||||
-- 3.4 试卷题目关联表
|
||||
DROP TABLE IF EXISTS ex_paper_question;
|
||||
CREATE TABLE ex_paper_question (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
|
||||
paper_id BIGINT NOT NULL COMMENT '试卷ID',
|
||||
question_id BIGINT NOT NULL COMMENT '题目ID',
|
||||
score INT NOT NULL DEFAULT 5 COMMENT '该题分值',
|
||||
sort_order INT DEFAULT 0 COMMENT '排序',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
deleted TINYINT DEFAULT 0 COMMENT '逻辑删除(0-未删除,1-已删除)',
|
||||
INDEX idx_paper_id (paper_id),
|
||||
INDEX idx_question_id (question_id),
|
||||
INDEX idx_deleted (deleted)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='试卷题目关联表';
|
||||
|
||||
-- 3.5 考试表
|
||||
DROP TABLE IF EXISTS ex_exam;
|
||||
CREATE TABLE ex_exam (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
|
||||
title VARCHAR(200) NOT NULL COMMENT '考试标题',
|
||||
description TEXT COMMENT '考试描述',
|
||||
paper_id BIGINT NOT NULL COMMENT '关联试卷ID',
|
||||
start_time DATETIME NOT NULL COMMENT '开始时间',
|
||||
end_time DATETIME NOT NULL COMMENT '结束时间',
|
||||
max_attempts INT DEFAULT 1 COMMENT '最大考试次数',
|
||||
department_id BIGINT NOT NULL COMMENT '所属部门ID',
|
||||
status TINYINT DEFAULT 0 COMMENT '状态(0-未开始,1-进行中,2-已结束)',
|
||||
creator_id BIGINT NOT NULL COMMENT '创建人ID',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
deleted TINYINT DEFAULT 0 COMMENT '逻辑删除(0-未删除,1-已删除)',
|
||||
INDEX idx_paper_id (paper_id),
|
||||
INDEX idx_department_id (department_id),
|
||||
INDEX idx_status (status),
|
||||
INDEX idx_start_time (start_time),
|
||||
INDEX idx_end_time (end_time),
|
||||
INDEX idx_deleted (deleted)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='考试表';
|
||||
|
||||
-- 3.6 考试对象表
|
||||
DROP TABLE IF EXISTS ex_exam_target;
|
||||
CREATE TABLE ex_exam_target (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
|
||||
exam_id BIGINT NOT NULL COMMENT '考试ID',
|
||||
target_type TINYINT NOT NULL COMMENT '目标类型(0-部门,1-小组,2-个人)',
|
||||
target_id BIGINT NOT NULL COMMENT '目标ID',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
deleted TINYINT DEFAULT 0 COMMENT '逻辑删除(0-未删除,1-已删除)',
|
||||
INDEX idx_exam_id (exam_id),
|
||||
INDEX idx_target (target_type, target_id),
|
||||
INDEX idx_deleted (deleted)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='考试对象表';
|
||||
|
||||
-- 3.7 考试记录表
|
||||
DROP TABLE IF EXISTS ex_exam_record;
|
||||
CREATE TABLE ex_exam_record (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
|
||||
exam_id BIGINT NOT NULL COMMENT '考试ID',
|
||||
user_id BIGINT NOT NULL COMMENT '用户ID',
|
||||
attempt_no INT NOT NULL DEFAULT 1 COMMENT '第几次考试',
|
||||
score INT COMMENT '得分',
|
||||
passed TINYINT COMMENT '是否通过(0-否,1-是)',
|
||||
start_time DATETIME NOT NULL COMMENT '开始时间',
|
||||
submit_time DATETIME COMMENT '提交时间',
|
||||
answers JSON COMMENT '答题详情(JSON格式)',
|
||||
status TINYINT DEFAULT 0 COMMENT '状态(0-进行中,1-已提交)',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
deleted TINYINT DEFAULT 0 COMMENT '逻辑删除(0-未删除,1-已删除)',
|
||||
INDEX idx_exam_id (exam_id),
|
||||
INDEX idx_user_id (user_id),
|
||||
INDEX idx_exam_user (exam_id, user_id),
|
||||
INDEX idx_deleted (deleted)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='考试记录表';
|
||||
|
||||
-- =============================================
|
||||
-- 四、培训模块
|
||||
-- =============================================
|
||||
|
||||
-- 4.1 培训计划表
|
||||
DROP TABLE IF EXISTS tr_plan;
|
||||
CREATE TABLE tr_plan (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
|
||||
title VARCHAR(200) NOT NULL COMMENT '计划标题',
|
||||
description TEXT COMMENT '计划描述',
|
||||
start_date DATE NOT NULL COMMENT '开始日期',
|
||||
end_date DATE NOT NULL COMMENT '结束日期',
|
||||
department_id BIGINT NOT NULL COMMENT '所属部门ID',
|
||||
status TINYINT DEFAULT 0 COMMENT '状态(0-未开始,1-进行中,2-已结束)',
|
||||
creator_id BIGINT NOT NULL COMMENT '创建人ID',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
deleted TINYINT DEFAULT 0 COMMENT '逻辑删除(0-未删除,1-已删除)',
|
||||
INDEX idx_department_id (department_id),
|
||||
INDEX idx_status (status),
|
||||
INDEX idx_start_date (start_date),
|
||||
INDEX idx_end_date (end_date),
|
||||
INDEX idx_deleted (deleted)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='培训计划表';
|
||||
|
||||
-- 4.2 培训计划-知识关联表
|
||||
DROP TABLE IF EXISTS tr_plan_knowledge;
|
||||
CREATE TABLE tr_plan_knowledge (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
|
||||
plan_id BIGINT NOT NULL COMMENT '计划ID',
|
||||
knowledge_id BIGINT NOT NULL COMMENT '知识ID',
|
||||
required TINYINT DEFAULT 1 COMMENT '是否必修(0-选修,1-必修)',
|
||||
sort_order INT DEFAULT 0 COMMENT '排序',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
deleted TINYINT DEFAULT 0 COMMENT '逻辑删除(0-未删除,1-已删除)',
|
||||
INDEX idx_plan_id (plan_id),
|
||||
INDEX idx_knowledge_id (knowledge_id),
|
||||
INDEX idx_deleted (deleted)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='培训计划-知识关联表';
|
||||
|
||||
-- 4.2.1 培训计划-考试关联表
|
||||
DROP TABLE IF EXISTS tr_plan_exam;
|
||||
CREATE TABLE tr_plan_exam (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
|
||||
plan_id BIGINT NOT NULL COMMENT '计划ID',
|
||||
exam_id BIGINT NOT NULL COMMENT '考试ID',
|
||||
required TINYINT DEFAULT 1 COMMENT '是否必考(0-选考,1-必考)',
|
||||
sort_order INT DEFAULT 0 COMMENT '排序',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
deleted TINYINT DEFAULT 0 COMMENT '逻辑删除(0-未删除,1-已删除)',
|
||||
INDEX idx_plan_id (plan_id),
|
||||
INDEX idx_exam_id (exam_id),
|
||||
INDEX idx_deleted (deleted)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='培训计划-考试关联表';
|
||||
|
||||
-- 4.3 培训计划-对象关联表
|
||||
DROP TABLE IF EXISTS tr_plan_target;
|
||||
CREATE TABLE tr_plan_target (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
|
||||
plan_id BIGINT NOT NULL COMMENT '计划ID',
|
||||
target_type TINYINT NOT NULL COMMENT '目标类型(0-部门,1-小组,2-个人)',
|
||||
target_id BIGINT NOT NULL COMMENT '目标ID',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
deleted TINYINT DEFAULT 0 COMMENT '逻辑删除(0-未删除,1-已删除)',
|
||||
INDEX idx_plan_id (plan_id),
|
||||
INDEX idx_target (target_type, target_id),
|
||||
INDEX idx_deleted (deleted)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='培训计划-对象关联表';
|
||||
|
||||
-- 4.4 培训进度表
|
||||
DROP TABLE IF EXISTS tr_plan_progress;
|
||||
CREATE TABLE tr_plan_progress (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
|
||||
plan_id BIGINT NOT NULL COMMENT '计划ID',
|
||||
user_id BIGINT NOT NULL COMMENT '用户ID',
|
||||
knowledge_id BIGINT NOT NULL COMMENT '知识ID',
|
||||
completed TINYINT DEFAULT 0 COMMENT '是否完成(0-否,1-是)',
|
||||
complete_time DATETIME COMMENT '完成时间',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
deleted TINYINT DEFAULT 0 COMMENT '逻辑删除(0-未删除,1-已删除)',
|
||||
INDEX idx_plan_id (plan_id),
|
||||
INDEX idx_user_id (user_id),
|
||||
INDEX idx_knowledge_id (knowledge_id),
|
||||
INDEX idx_plan_user (plan_id, user_id),
|
||||
INDEX idx_deleted (deleted)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='培训进度表';
|
||||
|
||||
-- =============================================
|
||||
-- 五、初始化数据
|
||||
-- =============================================
|
||||
|
||||
-- 5.1 初始化中心
|
||||
INSERT INTO sys_center (name, sort_order) VALUES
|
||||
('总部', 1);
|
||||
|
||||
-- 5.2 初始化部门
|
||||
INSERT INTO sys_department (name, center_id, sort_order) VALUES
|
||||
('救援一部', 1, 1),
|
||||
('救援二部', 1, 2),
|
||||
('客服中心', 1, 3),
|
||||
('技术支持部', 1, 4);
|
||||
|
||||
-- 5.3 初始化小组
|
||||
INSERT INTO sys_group (name, department_id, sort_order) VALUES
|
||||
('一组', 1, 1),
|
||||
('二组', 1, 2),
|
||||
('三组', 1, 3),
|
||||
('一组', 2, 1),
|
||||
('二组', 2, 2);
|
||||
|
||||
-- 5.4 初始化管理员账号 (密码: admin123,使用BCrypt加密)
|
||||
-- BCrypt密码生成: new BCryptPasswordEncoder().encode("admin123")
|
||||
INSERT INTO sys_user (username, password, real_name, phone, role, department_id, status) VALUES
|
||||
('admin', '$2a$10$TWbA.Dgh6pjuVoLZzRod3usjs7fOyyofpTVCi1mz.okHtO55vGgBW', '系统管理员', '13800138000', 0, 1, 0);
|
||||
|
||||
-- 5.5 初始化知识分类
|
||||
INSERT INTO km_category (name, parent_id, department_id, sort_order) VALUES
|
||||
('安全规范', 0, 1, 1),
|
||||
('操作手册', 0, 1, 2),
|
||||
('应急流程', 0, 1, 3);
|
||||
|
||||
-- 5.6 初始化题目分类
|
||||
INSERT INTO ex_question_category (name, parent_id, department_id, sort_order) VALUES
|
||||
('安全知识', 0, 1, 1),
|
||||
('操作规范', 0, 1, 2),
|
||||
('应急处理', 0, 1, 3);
|
||||
|
||||
-- =============================================
|
||||
-- 完成
|
||||
-- =============================================
|
||||
SELECT '数据库初始化完成!' AS message;
|
||||
@@ -1,18 +0,0 @@
|
||||
package com.sino.training;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
/**
|
||||
* 道路救援企业培训系统 - 启动类
|
||||
*
|
||||
* @author training-system
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class TrainingApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(TrainingApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package com.sino.training.common.annotation;
|
||||
|
||||
import com.sino.training.common.enums.UserRole;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 角色权限注解
|
||||
* 标注在Controller类或方法上,限制访问角色
|
||||
*
|
||||
* @author training-system
|
||||
*/
|
||||
@Target({ElementType.TYPE, ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface RequireRole {
|
||||
|
||||
/**
|
||||
* 允许访问的角色列表
|
||||
*/
|
||||
UserRole[] value();
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package com.sino.training.common.base;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 实体基类
|
||||
*
|
||||
* @author training-system
|
||||
*/
|
||||
@Data
|
||||
public abstract class BaseEntity implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 逻辑删除标识(0-未删除,1-已删除)
|
||||
*/
|
||||
@TableLogic
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private Integer deleted;
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package com.sino.training.common.base;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 分页查询基类
|
||||
*
|
||||
* @author training-system
|
||||
*/
|
||||
@Data
|
||||
public class PageQuery implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 当前页码(默认1)
|
||||
*/
|
||||
private Integer current = 1;
|
||||
|
||||
/**
|
||||
* 每页大小(默认10)
|
||||
*/
|
||||
private Integer size = 10;
|
||||
|
||||
/**
|
||||
* 转换为 MyBatis Plus 分页对象
|
||||
*/
|
||||
public <T> Page<T> toPage() {
|
||||
return new Page<>(current, size);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user