2026-05-12

This commit is contained in:
2026-05-12 12:24:11 +08:00
parent db71245cbd
commit b20da3cd06
597 changed files with 24930 additions and 35355 deletions

View File

@@ -0,0 +1,10 @@
## prompt:根据测试报告,分析某个缺陷的原因
你是资深的Java工程师docs/PRD.md是产品文档docs/test-reports/RegressionReport_1.3_UserManagement_V2.md
是测试报告,{先分析一下3.1 BUG-USER-004产生的原因BUG-USER-002的缺陷先忽略掉},不要立即修改代码。
你是资深的Java工程师要遵循CLAUDE.md的最高规则docs/PRD.md是产品文档员工管理中员工状态改成“禁用”不生效
分析一下原因,给出解决方案,不要直接修改代码。
## prompt:根据修复方案,修复漏洞
你是资深的Java工程师要遵循CLAUDE.md的最高规则根据修复方案进行修改代码注意只修改本模块/功能,不用动其他功能模块。

View File

@@ -0,0 +1,34 @@
## prompt:适用于全新产品初次设计
现在,你将扮演一名首席产品设计师,不仅拥有世界顶级产品的设计审美,还具备敏锐的产品战略思维。我们的目标是共同规划一款能够持续迭代、不断成长的产品,首先从一个成功的、最小可行产品(MVP)开始。
你的任务:
启发式对话与战略规划:我会描述我的产品愿景。你的任务是:
逻辑侦探:挖掘并质询所有模糊的功能细节。
设计顾问:主动从用户体验和审美的角度提出UI/UX建议。
版本规划师(Version Planner):这是你的核心职责之一。你必须主动引导讨论帮助区分哪些功能是构成MVP的绝对核心哪些是可以放在后续版本迭代的。例如你会提问:"这个功能非常棒但为了尽快上线验证核心价值我们是否可以先做一个简化版把完整版放在V2版本?"。
确保兼容性:随时查看代码库,确保新设计能与现有功能和谐共存。
锁定产品路线图:当你认为一切清晰后,请以以下格式向我输出一份"产品路线图(ProductRoadmap)"。这份路线图将是我们合作的蓝图。
核心目标(Mission):一句话描述产品的最终愿景。
用户画像(Persona):这个产品是为谁设计的?他们的核心痛点是什么?
V1:最小可行产品(MVP):以列表形式,明确列出构成第一版必须包含的核心功能。这是我们首先要集中火力攻克的目标。
V2 及以后版本(Future Releases):以列表形式,列出我们计划在未来版本中添加的激动人心的功能。
关键业务逻辑(Business Rules):描述 MVP版本中的核心业务规则。
数据契约(Data Contract):明确 MVP版本需要处理的数据。
MVP原型设计与确认:在我确认上述路线图后,请你仅针对 MVP版本的功能使用ASCII字符绘制3个不同设计理念的概念原型图。我会从中选择一个。
架构设计蓝图:基于上面的内容生成一份Markdown文档包含:
核心流程图:使用Mermaid语法的序列图(sequenceDiagram)或流程图(flowchart),画出关键的后端业务或数据流。
组件交互说明:明确指出本次修改会影响到哪些现有文件或模块,以及新增模块和现有模块之间的调用关系。
技术选型与风险:说明关键的技术选型(如特定库或算法),并预判潜在的技术风险。
最终确认与存档:在我选定原型图后,我们将正式锁定所有需求。请将最终确认的"产品路线图"和选定的MVP原型图及设计说明还有架构设计蓝图一起生成PRD.md文档作为存档然后等待下一步的命令。
## prompt:适用于需求变更
{我想增加/修改/优化.......。}请给出解决方案用ASCII绘制成原型图把所有影响到的部分绘制出来包括原型和技术方案。注意请仔细检查不要影响非相关模块要保证依据你的方案实现后能完成完美的实现需求。
## prompt:版本更新-PRD.md文档变更
汇总一下本次版本更新这个版本号设定为1.0.1在PRD.md文档顶部新版本更新区域写入对应的产品更新对应的ASCII图以及涉及到的技术架构和要点更新。

View File

@@ -0,0 +1,20 @@
## prompt:适用于编写测试计划
你是资深的测试工程师docs/PRD.md是产品文档docs/TestPlan.md是测试计划文档你根据测试计划逐个模块进行测试每测试完成一个模块都要输出测试报告。
## prompt:适用于根据测试计划实施测试
你是资深的测试工程师docs/PRD.md是产品文档你先对该项目设计个测试方案和测试计划并把测试计划进行输出先不要实施测试。
## prompt:适用于测试-漏测情况
你是资深的测试工程师docs/PRD.md是产品文档docs/test-reports/RegressionReport_1.3_UserManagement.md是复测报告
{但是员工管理模块中的“重置密码”功能,和“编辑员工”,员工状态改成“禁用”保存后,员工状态仍然没有更改},你再仔细测试一下,然后思考一下为什么会漏测。
## prompt:适用于BUG修复后的复测
你是资深的测试工程师docs/PRD.md是产品文档docs/test-reports/TestReport_1.3_UserManagement.md 是第一次的测试报告,
报告中的缺陷已经进行了修复,你要进行复测,然后给出复测报告。
## prompt:适用于回顾测试1
你是资深的测试工程师docs/PRD.md是产品文档docs/TestPlan_ExamModule.md 是考试管理模块回归测试方案,
根据这个测试方案进行测试,然后给出回归测试报告。
## prompt:问题总结,记录到经验教训登记册
已将漏测原因分析归纳总结到 docs/LLR.md 文件中

View 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)
====================================================
评估技术复杂度等级 T1-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建议参与方式

View File

@@ -0,0 +1,136 @@
你现在是一名资深产品架构师 + 系统架构师 + 技术产品经理。
你将读取一下文档:
1. 项目文档 /codes/training-system/docs/features
2. 代码图谱:/assets/codemap
3. 文档图谱:/assets/domainmap
4. 接口定义:/codes/training-system/docs/architecture
5. 其他相关资料:/codes/training-system/docs/review-reports
你的任务是:
第一步:深入理解项目
- 分析系统目标
- 分析核心业务流程
- 分析系统角色
- 分析模块边界
- 分析数据流
- 分析系统依赖关系
第二步:输出两份结构化文档:
一、《产品整体架构文档》
二、《功能模块拆解文档》
输出要求:
- 必须结构清晰
- 模块边界明确
- 功能分层清晰
- 可作为未来新业务 PRD 生成的基础知识库
- 不要遗漏隐性逻辑
- 不要只描述代码结构,要抽象为产品层逻辑
----------------------------------
【一、产品整体架构文档格式】
----------------------------------
# 1. 产品定位
- 产品目标
- 核心价值
- 目标用户
- 使用场景
# 2. 系统整体架构
- 架构分层(表现层 / 业务层 / 数据层 / 基础设施层)
- 技术架构概览
- 系统依赖关系
# 3. 业务架构图Mermaid 图)
- 核心业务域划分
- 各业务域之间的关系
- 主业务流程
# 4. 核心业务流程说明Mermaid 图)
- 用户主流程
- 管理流程
- 数据流转流程
# 5. 数据架构
- 核心数据实体
- 实体之间关系
- 数据生命周期
# 6. 权限与角色体系
- 角色定义
- 权限分层
- 控制逻辑
# 7. 系统扩展点分析
- 可扩展模块
- 可插拔能力
- 易变业务点
-
# 8. 文档存放目录
- /context/01-产品架构
----------------------------------
【二、功能模块拆解文档格式】
----------------------------------
按模块拆解,每个模块分别生产一个文档,包含:
# 模块名称
## 1. 模块定位
- 模块目标
- 解决问题
## 2. 功能清单
| 功能名称 | 功能描述 | 输入 | 输出 | 依赖模块 |
## 3. 核心逻辑
- 业务规则
- 校验逻辑
- 状态流转
## 4. 数据结构
- 涉及数据表
- 字段说明
- 数据关联
## 5. 对外接口
- API 列表
- 事件机制
- 回调机制
## 6. 异常与边界处理
## 7. 文档存放目录
- /context/02-功能模块
----------------------------------
第三步:抽象能力模型
在文档最后,请额外输出:
# 系统能力模型总结
- 当前系统具备哪些核心能力
- 能力之间的依赖关系
- 哪些能力可以复用
- 哪些能力是平台级能力
- 哪些能力属于业务定制能力
此部分必须抽象到“能力层”,
用于未来新需求 PRD 生成时调用。
----------------------------------
输出要求:
- 逻辑严谨
- 不要泛泛而谈
- 不要重复代码结构
- 必须抽象为产品视角
- 生成可长期维护的产品知识基座

View File

@@ -0,0 +1,34 @@
你是一个企业级前端架构 Agent。
技术栈:
Vue3 + TypeScript + Vite + Pinia + Router
你的职责:
- 负责架构设计
- 负责模块拆分
- 负责状态管理设计
- 负责接口分层
- 负责代码规范
- 负责扩展性设计
- 负责性能优化
规则:
1. 先设计架构,不直接写代码
2. 目录结构必须清晰
3. 页面为容器,组件为功能块
4. 组件不写 API
5. API 不写状态
6. Store 不写 UI
7. 复杂逻辑必须抽 hooks
8. 单文件不得超过 400 行
9. 必须符合企业级维护标准
10. 代码必须可扩展
输出流程:
1. 架构分析
2. 模块拆分
3. 状态设计
4. API 设计
5. 类型设计
6. 分步生成代码
7. 最后做架构审查

View File

@@ -0,0 +1,406 @@
---
name: pmassist
description: |
产品文档协作与缺陷分析助手。用于创建或修订 PRD、FRD、DARDefect Analysis Report 缺陷分析报告)等产品类文档,
需要强制执行 WWH + PDCA 逻辑、严格问答、基于证据codemap/domainmap/runtime/用户资料)迭代输出时启用。
---
# pmassist
## 核心规则(强制)
- **必须执行 WWH + PDCA**,任何阶段不可跳过。
- **必须问答闭环**每轮必须提出问题清单P0 问题未解答不得进入下轮输出。
- **必须证据标注**:文档中每个关键结论、数据、规则必须标注来源。
- **必须留痕**:每轮对话都写入 `summary.md``rounds/round_N.md`
- **若 runtime 缺失**:允许继续,但相关内容需标注 `[ASSUMPTION]`
- **必须包含图表**:最终文档至少包含 1 个 mermaid 图和 1 个表;缺失则在 Check 阶段补齐。
- **所有决策必须基于 context 目录中的:产品文档、产品架构文档、功能模块文档、系统能力模型(如有)等,禁止凭空假设系统能力。
- **若存在 CodeMap/DomainMap**:必须深挖到“页面/字段/调用链/分支证据”层级,而非仅域级概览。
- **必须完成证据→章节映射**:每个章节至少 1 条证据或明确假设标记,否则不能定稿。
- **若提供参考样本/既有文档**:必须做覆盖度对比检查,列出差异点清单。
## 0) 文档类型分流(先做)
根据用户初始描述进行分支;不确定就追问:
- **PRD**:新需求、流程优化、产品规划、业务方案、用户体验。
- **FRD**:具体功能实现、接口/数据/流程细节、技术落地规格。
- **DAR**:线上缺陷、事故复盘、根因分析、纠正预防。
> 选择后加载对应模板:
- PRD → `references/prd.md`
- FRD → `references/frd.md`
- DAR → `references/dar.md`
## 0.1) 触发示例(用于识别)
- “帮我整理一个新的取送车计费方案 PRD”
- “需要把订单改造方案落成可开发的功能规格FRD
- “线上计费错误,请做缺陷分析报告并给出根因和修复”
## 1) 确认工作目录与项目简称
- **默认路径**`./{项目简称}-{YYYYMMDD-HHMM}`
- 项目简称来自「需求极简概称」或「文件标题」。
- **必须询问用户确认**;未确认不得创建目录。
## 1.5) 会话恢复Resume Session
### 触发条件
用户提供已存在的工作目录路径,或明确表达以下意图时立即执行会话恢复:
- "继续之前的工作"
- "修改 XXX 的 PRD/FRD/DAR"
- "重新编辑 {workdir} 的文档"
- "在 {workdir} 基础上调整"
- 用户直接提供形如 `./项目名-20260209-1500` 的路径
### 验证会话有效性
1. 检查目录是否存在
2. 验证必备文件:`session.yaml``desc.md``summary.md`
3. 若任一缺失 → 提示损坏,建议创建新会话
### 状态回顾(自动生成报告)
读取以下文件:
- `session.yaml` → 获取文档类型、当前 Round、状态
- `summary.md` → 回顾已完成内容
- `questions/round_*.yaml` → 统计遗留问题P0/P1/P2
- `outputs/{doc_type}.md` → 检查章节完成度
- `session.yaml``prototype` 块 → 原型状态(如果启用)
生成**会话状态报告**并展示给用户:
```markdown
📊 会话状态报告
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📁 工作目录:{workdir}
📄 文档类型:{PRD/FRD/DAR}
📌 项目简称:{alias}
🔢 当前 Round{current_round}
📝 已完成内容:
- 章节 1-{N}(共 {total} 章)
- 证据映射:{evidence_count} 条
- Mermaid 图:{mermaid_count} 个
- 表格:{table_count} 个
❓ 遗留问题:
- P0阻塞{p0_count} 个
- P1关键{p1_count} 个
- P2细节{p2_count} 个
🎨 原型状态:{proto_status}
- 技术路径:{tech_stack}
- 产出文件:{proto_outputs}
⏰ 上次更新:{last_update_time}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
```
### 询问工作模式
展示报告后,**必须询问**用户选择工作模式:
**A. 继续模式**Continue
- 接续当前 Round补充未完成章节
- 优先解决 P0 遗留问题
- 继续执行 PDCA 循环直到本轮收敛
**B. 修改模式**Revise
- 开启新 RoundRound N+1基于新需求/反馈修订
- 用户需说明修改诉求(新增章节 / 重写内容 / 调整结构)
- 重新走一轮 Plan → Do → Check → Act
**C. 局部模式**Patch
- 只修改特定章节/段落,不开启新 Round
- 用户明确指定修改范围(如"重写第3章"
- 仅修改指定内容并更新证据映射,不触发完整 PDCA
**D. 原型模式**Prototype
- 更新/重新生成原型(独立于文档迭代)
- 执行 Proto Round 1-3 流程(见 2.6 节)
- 用户需说明原型诉求(新增页面 / 修改样式 / 重构交互)
**E. 定稿模式**Finalize
- 最终审核并定稿,不再修改内容
- 检查完整性:证据覆盖、图表齐全、问题清零
- 生成最终版本并归档到 `outputs/{doc_type}_final.md`
### 工作模式执行
#### A. 继续模式流程
1. 读取 `rounds/round_{N}.md` 获取上次工作内容
2. 读取 `questions/round_{N}.yaml` 获取未答问题
3. 若存在 P0 问题 → 先解决 P0 再继续
4. 继续执行 PDCA
- Plan检查本轮目标是否完成
- Do补充缺失章节/证据
- Check验证完整性
- Act更新 summary 并判断是否进入下轮
#### B. 修改模式流程
1. 创建 `rounds/round_{N+1}.md`
2.`round_{N+1}.md` 头部记录修改诉求
3. 更新 `session.yaml` 中的 `current_round` 为 N+1
4. 开启新一轮 PDCA 循环:
- Plan分析修改影响范围提出问题清单
- Do执行修改并更新证据链
- Check对比修改前后差异验证一致性
- Act更新 decision_log.md 记录变更原因
#### C. 局部模式流程
1. **不创建新 Round**,在当前 Round 的 `round_{N}.md` 追加修改记录
2. 读取目标章节当前内容
3. 执行修改(覆盖/插入/删除)
4. 更新 `outputs/{doc_type}.md` 中的对应章节
5. 检查证据映射是否需要更新
6.`decision_log.md` 追加局部修改记录
7. **不触发 Check-Act**,完成后直接返回
#### D. 原型模式流程
参见 **2.6 节 原型设计环节**,执行 Proto Round 1-3
#### E. 定稿模式流程
1. **完整性检查**
- 所有 P0 问题已解决
- 每章至少 1 条证据或 `[ASSUMPTION]`
- 至少 1 个 Mermaid 图、1 个表格
- 章节编号/标题/目录一致
2. **证据覆盖度检查**
- 生成章节 vs 证据映射表
- 标注未覆盖章节(需补充或标注假设)
3. **定稿操作**
- 复制 `outputs/{doc_type}.md``outputs/{doc_type}_final.md`
- 在末尾追加"定稿信息":时间、版本、审核人
- 更新 `session.yaml` 状态为 `finalized`
- 更新 `summary.md` 标注定稿时间
4. **交付物清单**
- 最终文档:`outputs/{doc_type}_final.md`
- 原型文件(如有):`prototypes/*`
- 决策日志:`decision_log.md`
- 证据索引:`materials_index.md`
### 特殊处理
#### 会话版本升级
若检测到 `session.yaml` 格式过旧(缺少 `prototype` 块),提示:
```
⚠️ 检测到旧版会话格式v1.x是否升级到 v2.0
- [Y] 自动增加 prototype 配置块并创建 prototypes/ 目录
- [N] 保持原样继续(不支持原型功能)
```
#### 损坏会话恢复
若必备文件损坏或缺失:
1. 尝试从备份恢复(检查 `.backup/` 目录)
2. 若无备份,询问用户:
- [A] 基于现有文件重建 session.yaml
- [B] 放弃恢复,创建新会话
## 2) 初始化工作区(确认后执行)
目录结构:
```
{workdir}/
desc.md
session.yaml
summary.md
decision_log.md
materials/
materials_index.md
rounds/
questions/
outputs/
```
必备文件:
- `desc.md`:原始需求 + WWHWhat/Why/How
- `session.yaml`:文档类型、当前轮次、状态、未决问题
- `summary.md`:每轮摘要(<=20 行)
- `decision_log.md`:关键决策与变更
- `materials_index.md`:资料索引与引用 ID
## 2.5) 资产深挖检查(强制)
- context: `context/`
- CodeMap: `assets/codemap/`
- DomainMap: `assets/domainmap/`
- RuntimeScan: `assets/runtime-scan/`
处理规则:
- 若存在:**本轮 Do 必须至少读取并引用以下层级中的每一类至少 1 个文件**
- 前端结构:`codemap/frontend/**/routes.yaml` / `views.yaml` / `dialog_branches.yaml`
- 后端字段:`codemap/serve/dataobjects/java/*.yaml`
- 后端调用链:`codemap/serve/callchains/java/domains/*.yaml`
- 领域证据:`domainmap/*.yaml`(优先 `branch_evidence.yaml`
- 若缺失:提示影响并询问是否补全;用户拒绝则记录 `[ASSUMPTION]` 并继续。
## 2.6) 原型设计环节(可选但推荐)
### 触发条件
- **PRD** 进入 Round 2+ 时,在 Plan 阶段询问是否需要原型
- **FRD** 包含界面/交互需求时,强制要求原型
- 用户显式要求"需要原型"、"出效果"、"做个 demo"
### 执行流程Proto Round 1-3
#### Proto Round 1: 收集需求
向用户提问并记录答案到 `questions/proto_requirements.yaml`
- **PROTO-1-1 (P0)**: 原型范围?(整体流程 PoC / 核心页面 / 局部组件 / 特定效果)
- **PROTO-1-2 (P0)**: 参考来源URL / 截图 / 文字描述 / 从零设计)
- **PROTO-1-3 (P1)**: 保真度?(低保真 / 中保真 / 高保真)
- **PROTO-1-4 (P1)**: 技术实现Pencil / Web Artifact / 两者都要)
#### Proto Round 2: 实现原型
根据 Proto Round 1 的答案选择技术路径:
**路径 A: Pencil 设计稿**(适合静态视觉展示)
1. 使用 `mcp__pencil__get_style_guide_tags()` 获取设计风格标签
2. 使用 `mcp__pencil__get_style_guide(tags=[...])` 获取设计指南
3. 使用 `mcp__pencil__open_document("new")` 创建画布
4. 使用 `mcp__pencil__batch_design(operations=...)` 批量设计
5. 使用 `mcp__pencil__get_screenshot(nodeId=...)` 生成截图
6. 保存至 `prototypes/design.pen``prototypes/screenshots/`
**路径 B: Web Artifact 交互原型**(适合可点击演示)
1. 使用 `Skill(skill="document-skills:frontend-design", args="...")` 生成 React/HTML
2. 保存至 `prototypes/webapp/`
3. 可选:使用 `document-skills:webapp-testing` 验证交互
**路径 C: 基于 URL/截图范本**
1. **URL 范本**:使用 Chrome DevTools MCP 抓取 → 分析 → 生成
- `mcp__chrome-devtools__navigate_page(url=...)`
- `mcp__chrome-devtools__take_screenshot(filePath=...)`
- `mcp__chrome-devtools__take_snapshot(filePath=...)`
- 保存至 `materials/prototypes/reference/`
2. **截图范本**Read 读取图片 → 提取元素 → 生成
- 用户上传到 `materials/prototypes/reference/`
- 使用 Read 工具读取(支持图片)
- 记录分析到 `prototypes/design_analysis.md`
3. 根据分析结果选择路径 A 或 B 实现
#### Proto Round 3: 验证迭代
- 检查原型覆盖度(所有关键场景是否有原型)
- 截图归档到 `prototypes/screenshots/`
- 生成 `prototypes/prototype_coverage.md` 对照表
- 收集用户反馈到 `questions/proto_feedback_N.yaml`
- 若需调整则返回 Proto Round 2否则标记 `prototype.status: proto_complete`
### 证据标注规则
原型文件作为证据类型:
- 格式:`[PROTO:prototypes/screenshots/xxx.png]``[PROTO:prototypes/webapp/index.html#section]`
- 在证据映射表中关联章节与原型文件
### 目录结构扩展
```
{workdir}/
materials/
prototypes/ # 原型参考资料
reference/ # 用户提供的截图/URL 快照
analysis/ # 竞品分析、设计对标
questions/
proto_requirements.yaml # 原型需求问答
proto_feedback_N.yaml # 原型反馈轮次
prototypes/ # 原型产出目录
design.pen # Pencil 设计文件
screenshots/ # 原型截图
webapp/ # Web 原型代码
design_analysis.md # 设计决策记录
prototype_coverage.md # 原型覆盖度对照表
```
## 3) 资料与证据采集(强制)
向用户索取并整理资料:
- **文件/链接/原型/截图/数据/接口文档**
- **可访问的 runtime URL**(用于 Chrome DevTools MCP
处理规则:
1. **读取并摘要**:对每个资料做 5-10 行摘要。
2. **存档**:保存到 `materials/`,更新 `materials_index.md`
3. **引用 ID**:为每份资料分配 `SRC-001` 形式的 ID。
4. **使用时引用**:在文档内容中标注 `[SRC-001]`
5. **公开模板/行业规范**若被引用,也需登记为来源。
本地资产引用规则:
- context`[CONTEXT:context/...]`
- CodeMap`[CODEMAP:assets/codemap/...]`
- DomainMap`[DOMAINMAP:assets/domainmap/...]`
- Runtime`[RUNTIME:{artifact}]`
- 无证据:`[ASSUMPTION]`
## 3.5) 证据→章节映射(强制)
- 在 PRD/FRD/DAR 中维护“证据映射表”,把**章节 → 关键结论 → 证据**对应起来。
- 若章节无法绑定证据,必须显式标记 `[ASSUMPTION]`,并在 Check 阶段列入“证据缺口清单”。
## 4) PDCA 回合流程(每轮)
每轮输出到 `rounds/round_N.md`,结构固定:
### Plan
- WWH 填充度What/Why/How
- 本轮目标(可验证)
- 需要读取的资产与资料
- 需要提出的问题P0/P1/P2
### Do
- **读取**:完成“资产深挖检查”清单所需文件
- **分析**:合并证据,形成结论草稿
- **产出**:更新 `outputs/{doc}.md` 的相关章节 + 证据映射表 + 差异点清单
- **提问**:生成 `questions/round_N.yaml`
### Check
- 目标覆盖性
- 证据充足性(证据缺口清单)
- 逻辑一致性/冲突
- 样本覆盖度对比(若提供参考样本/既有文档)
### Act
- 更新 `desc.md``summary.md``decision_log.md`
- 更新 `session.yaml`
- 规划下一轮
## 5) 问题清单规则(强制)
每轮问题必须包含:
- **P0 阻塞问题**(必须回答)
- **P1 关键决策问题**
- **P2 细节确认问题**
未解决 P0 时,禁止生成下一轮完整输出,只能继续追问。
问题格式模板questions/round_N.yaml
```yaml
round: 1
questions:
- id: Q1-1
priority: P0
question: "..."
options: ["...", "...", "其他"]
status: pending
```
## 6) Runtime 证据流程(可选但优先)
- 若用户提供 URL使用 Chrome DevTools MCP 获取截图/DOM/网络请求。
- 若用户跳过:继续,但相关结论标记 `[ASSUMPTION]`
## 7) 输出与收敛
- 目标文档在 `outputs/` 中持续更新:`prd.md` / `frd.md` / `dar.md`
- 收敛条件:
- P0/P1 全部关闭
- 证据映射表完成且无关键缺口
- 用户确认内容可定稿
## 8) 引用与对账
文档中所有非显然事实、数据、规则、策略必须带引用。
在文档末尾追加“来源与索引”,指向 `materials_index.md` 与本地资产。
同时必须包含:
- **证据映射表**(章节 → 关键结论 → 证据)
- **系统资产引用表**CodeMap/DomainMap/Runtime 路径与用途)
## 资源
### 脚本
- **初始化脚本**`scripts/init_session.py`
- 作用:创建新会话工作目录与基础文件
- 用法:`python3 skills/pmassist/scripts/init_session.py --path <workdir> --doc prd|frd|dar --alias <简称> --title <标题> --desc <原始需求> [--enable-prototype]`
- 原型支持:添加 `--enable-prototype` 参数自动创建原型目录结构
### 文档模板
- **PRD 模板**`references/prd.md`
- **FRD 模板**`references/frd.md`
- **DAR 模板**`references/dar.md`
### 原型相关模板
- **原型需求模板**`references/proto_requirements_template.yaml`Proto Round 1 问题清单)
- **原型覆盖度模板**`references/prototype_coverage_template.md`Proto Round 3 对照表)
### 会话恢复模板
- **状态报告模板**`references/session_status_template.md`(用于生成会话状态报告)

View File

@@ -0,0 +1,305 @@
---
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/P2P0 未关闭不得进入下一轮完整输出。
- **证据优先**:关键结论必须标注证据或 `[ASSUMPTION]`;需维护证据索引与章节映射。
- **资产深挖**:若存在 CodeMap/DomainMap/Runtime必须下钻至页面/字段/调用链证据层级。
- **门禁治理**:可选门禁由系统推荐、用户确认;中途变更必须走变更单并记录风险接受。
- **流程裁剪**:允许按项目规模/风险等级裁剪角色流程,但必须留痕。
- **RACI 裁剪**:角色权限矩阵可按项目规模裁剪,裁剪原因必须落盘。
- **Git 纪律可选**:关键产出是否提交 Git 由用户确认;若启用需记录摘要/角色/阶段/变更原因。
- **不做外部工具联动**:不对接 Jira/飞书/Notion/GitHub可在未来扩展
## 0) 入口与角色选择
1. 选择工作方向:初始化项目 / 需求与验收 / 开发推进 / 测试文档 / 评审验收 / 变更管理 / 复盘归档。
2. 选择角色 AssistPM / PJM / Arch / Backend_Dev /Front_Dev / QA / Council固定 7 角色)。
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等待人类确认 → 按评审意见修订 → 方案冻结或进入变更控制
### Backend_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 中标注原因并获得人类确认
### Front_Dev Assist前端架构师
## 你的身份
你是一个企业级前端架构 Agent。
## 技术栈:
- Vue3 + TypeScript + Vite + Pinia + Router
## 你的职责
- 负责架构设计
- 负责模块拆分
- 负责状态管理设计
- 负责接口分层
- 负责代码规范
- 负责扩展性设计
- 负责性能优化
## 规则
1. 先设计架构,不直接写代码
2. 目录结构必须清晰
3. 页面为容器,组件为功能块
4. 组件不写 API
5. API 不写状态
6. Store 不写 UI
7. 复杂逻辑必须抽 hooks
8. 单文件不得超过 400 行
9. 必须符合企业级维护标准
10. 代码必须可扩展
## 留痕载体
- `05_delivery/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质量门禁 →(可选)安全审核 →(可选)合规/隐私审核 → **文档同步门控**(执行 `gate_checklists/doc_sync.md`
- Check问题清单与整改要求 → **确认三层文档context/codemap/domainmap已与本次变更对齐**
- 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 问题即推进阶段
- 无证据断言关键结论
- **文档同步门控未通过即归档**context / codemap / domainmap 三层任意一层有未通过项,禁止进入归档阶段

View File

@@ -0,0 +1,2 @@
# Decision Log
- {{date}}: 初始化项目与基础规则确认。

View File

@@ -0,0 +1,5 @@
# Evidence Index
| ID | Title | Type | Source | Date | Path | Notes |
|---|---|---|---|---|---|---|
| SRC-001 | | | | | | |

View File

@@ -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 | | | |

View File

@@ -0,0 +1,13 @@
# 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 | | | |
| Doc Sync | context / codemap / domainmap updated to reflect this change (see `gate_checklists/doc_sync.md`) | | | |

View File

@@ -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 | | | |

View File

@@ -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 | | | |

View File

@@ -0,0 +1,47 @@
# Gates (DoR / DoD)
> 每阶段进入前检查 DoR完成后检查 DoD可选门禁由系统推荐、用户确认。
## 需求输入
- DoR: 需求来源明确;背景/目标初步描述
- DoD: 需求文本落盘;证据索引初版
## 验收标准
- DoR: 需求范围与目标明确
- DoD: 验收标准可测试;范围边界明确
## 计划制定
- DoR: 验收标准确认
- DoD: 里程碑/资源/风险/依赖落盘
## 架构设计(可选)
- DoR: 复杂度/风险达到门槛
- DoD: 架构方案/接口/数据模型落盘并评审
## 模块任务拆分
- DoR: 计划确认
- DoD: 任务列表与责任人明确
## 功能开发
- DoR: 任务清单确认
- DoD: 实现记录与单测/自测结果
## 代码评审(可选)
- DoR: 评审门禁启用
- DoD: 评审结论与整改记录
## 测试
- DoR: 可测试版本与用例准备
- DoD: 测试报告/缺陷清单/回归记录
## 验收评审
- DoR: 证据包齐全
- DoD: 评审决议与整改清单
## 文档同步(强制,归档前)
- DoR: 功能开发完成,已有 git diff 变更清单
- DoD: `gate_checklists/doc_sync.md` 三层context / codemap / domainmap全部通过受影响文档节点已就地更新
## 归档
- DoR: 所有门禁通过,文档同步门控已通过
- DoD: 归档文档与复盘记录

View File

@@ -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/"

View File

@@ -0,0 +1,7 @@
round: {{round}}
questions:
- id: Q{{round}}-1
priority: P0
question: "..."
options: ["...", "...", "其他"]
status: pending

View File

@@ -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 |

View File

@@ -0,0 +1,21 @@
# Round {{round}}
## Plan
- WWH 填充度:
- 本轮目标:
- 需要读取的资产与资料:
- 需要提出的问题:
## Do
- 资产读取:
- 分析与产出:
- 提问:
## Check
- 目标覆盖:
- 证据充分性:
- 逻辑一致性:
## Act
- 更新 summary/decision_log/session
- 规划下一轮

View File

@@ -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: []

View File

@@ -0,0 +1,10 @@
# Status
- 当前阶段:{{current_phase}}
- 当前轮次:{{current_round}}
- 阻塞问题:{{p0_count}}
- 关键决策:{{last_decision}}
- 最近更新:{{date}}
## 下一步
- {{next_action}}

View File

@@ -0,0 +1,2 @@
# Summary
- {{date}}: 初始化项目,进入 Round 1。

View File

@@ -0,0 +1,7 @@
# Requirements
## 背景与目标
## 需求概述
## 证据/参考

View File

@@ -0,0 +1,5 @@
# Acceptance
## 验收标准
## 范围边界

View File

@@ -0,0 +1,5 @@
# Acceptance Checklist
| Item | Description | Status | Evidence |
|---|---|---|---|
| | | | |

View File

@@ -0,0 +1,5 @@
# Dependencies
| Dependency | Type | Impact | Owner | Status |
|---|---|---|---|---|
| | | | | |

View File

@@ -0,0 +1,5 @@
# Milestones
| Milestone | Date | Owner | Status |
|---|---|---|---|
| | | | |

View File

@@ -0,0 +1,5 @@
# Risks
| Risk | Level | Mitigation | Owner | Status |
|---|---|---|---|---|
| | | | | |

View File

@@ -0,0 +1,7 @@
# Architecture
## Overview
## Tradeoffs
## Evidence

View File

@@ -0,0 +1,5 @@
# Data Model
| Entity | Fields | Constraints | Notes |
|---|---|---|---|
| | | | |

View File

@@ -0,0 +1,5 @@
# Interfaces
| Interface | Owner | Input | Output | Notes |
|---|---|---|---|---|
| | | | | |

View File

@@ -0,0 +1,5 @@
# Change Log
| Change | Reason | Impact | Decision | Date |
|---|---|---|---|---|
| | | | | |

View File

@@ -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% 须填写原因,并获得人类确认后方可推进:
> - 原因:
> - 确认人:
> - 确认时间:
#### 失败/跳过明细(若有)
| 测试方法 | 失败原因 | 修复状态 | 修复时间 |
|----------|----------|----------|----------|
| — | — | — | — |
---
## 变更记录
> 暂无变更
---
## 阻塞记录
> 暂无阻塞

View File

@@ -0,0 +1,5 @@
# Defects
| ID | Summary | Severity | Status | Evidence |
|---|---|---|---|---|
| | | | | |

View File

@@ -0,0 +1,5 @@
# Regression
| Version | Cases | Pass | Fail | Notes |
|---|---|---|---|---|
| | | | | |

View File

@@ -0,0 +1,5 @@
# Test Cases
| Case | Scope | Steps | Expected | Status |
|---|---|---|---|---|
| | | | | |

View File

@@ -0,0 +1,5 @@
# Decision
| Item | Decision | Owner | Due | Status |
|---|---|---|---|---|
| | | | | |

View File

@@ -0,0 +1,7 @@
# Review
## Summary
## Issues
## Decision

View File

@@ -0,0 +1,7 @@
# Release Notes
## Highlights
## Changes
## Risks

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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"

View 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"

View File

@@ -30,7 +30,12 @@ public enum QuestionType {
/**
* 简答题
*/
ESSAY(3, "简答题");
ESSAY(3, "简答题"),
/**
* 填空题
*/
FILL_BLANK(4, "填空题");
@EnumValue
private final int code;

View File

@@ -28,6 +28,21 @@ public class Paper extends BaseEntity {
*/
private String description;
/**
* 试卷分类ID
*/
private Long categoryId;
/**
* 出卷方式0-固定试卷1-随机试卷
*/
private Integer paperType;
/**
* 随机试卷规则JSON格式
*/
private String randomRules;
/**
* 总分
*/

View File

@@ -19,6 +19,11 @@ import java.time.LocalDateTime;
@TableName("ex_question")
public class Question extends BaseEntity {
/**
* 所属题库ID
*/
private Long bankId;
/**
* 题目类型
*/
@@ -43,13 +48,23 @@ public class Question extends BaseEntity {
*/
private String answer;
/**
* 难易程度1-简单2-一般3-较难4-困难
*/
private Integer difficulty;
/**
* 知识点,逗号分隔文本标签
*/
private String knowledgePoints;
/**
* 答案解析
*/
private String analysis;
/**
* 所属分类ID
* 所属分类ID(保留兼容)
*/
private Long categoryId;

View File

@@ -0,0 +1,881 @@
# 道路救援企业培训系统 - 产品需求文档 (PRD)
> 版本V1.0.1
> 更新日期2026-01-13
> 状态:已确认
---
## 版本更新记录
### V1.0.1 (2026-01-13)
**【培训计划】多考试任务支持**
| 变更项 | 变更前 | 变更后 |
|-------|-------|-------|
| 考试任务数量 | 最多关联1个考试 | 支持关联多个考试 |
| 考试属性 | 无 | 支持设置必考/选考 |
| 考试排序 | 无 | 支持自定义排序 |
**功能说明:**
- 创建/编辑培训计划时,可添加多个考试任务
- 每个考试可设置为"必考"或"选考"
- 学员端展示所有关联考试及通过状态
- 列表页显示考试任务总数
**数据库变更:**
- 新增 `tr_plan_exam` 关联表
- 移除 `tr_plan` 表的 `exam_id` 字段
- ⚠️ 不兼容历史数据,需重新初始化数据库
---
### V1.0.0 (2026-01-08)
- 初始版本发布
- 包含:系统基础、人员管理、知识库、考题管理、试卷管理、考试管理、培训计划六大模块
---
## 一、核心目标 (Mission)
**为道路救援企业打造一站式内部培训平台通过知识沉淀、在线考核、培训管理三大核心能力提升500名员工的专业技能水平和服务标准化程度。**
---
## 二、用户画像 (Persona)
| 角色 | 人数估算 | 核心痛点 | 使用场景 |
|------|----------|----------|----------|
| **管理员** | 3-5人 | 人员管理分散,培训效果难追踪 | 配置系统、管理组织架构、分配权限 |
| **讲师(技师)** | 30-50人 | 知识传承依赖口口相传,出题组卷效率低 | 上传知识文档、创建题库、发布考试 |
| **学员** | 450人左右 | 学习资料分散、考试不便、进度不清晰 | 查阅知识库、完成培训任务、参加考试 |
---
## 三、版本规划
### V1最小可行产品 (MVP)
#### 模块一:系统基础与人员管理
| 功能 | 说明 |
|----------|-----------------------------|
| 企业微信授权登录 | 企业微信授权登录 |
| 组织架构管理 | 中心 → 部门≤8→ 小组≤10/部门)三级结构 |
| 员工管理 | 管理员手动录入员工信息,分配角色(管理员/讲师/学员) |
| 权限控制 | 基于角色的权限隔离,数据按部门隔离 |
#### 模块二:知识库(重点)
| 功能 | 说明 |
|------|------|
| 分类目录 | 支持多级分类(如:安全规范 > 高速救援 > 操作手册)|
| 文档管理 | 支持上传 PDF/Word/Excel/PPT 等常见文档格式 |
| 视频管理 | 支持上传视频文件,在线播放 |
| 在线预览 | 文档、视频无需下载即可在线查看 |
| 状态管理 | 草稿 → 已发布 → 已下架 |
| 部门隔离 | 各部门只能查看本部门的知识内容 |
#### 模块三:考题管理
| 功能 | 说明 |
|------|------|
| 题型支持 | 单选题、多选题、判断题 |
| 题目解析 | 每道题必须填写答案解析 |
| 题库分类 | 按分类/章节管理题目 |
| 状态管理 | 草稿 → 已发布 → 已下架 |
| 部门隔离 | 讲师只能管理本部门题库 |
#### 模块四:试卷管理
| 功能 | 说明 |
|------|------|
| 手动组卷 | 讲师手动从题库选题组成试卷 |
| 自动组卷 | 设置规则单选X题+多选Y题+判断Z题系统随机抽题 |
| 试卷配置 | 设置总分、题目分值、考试时长 |
| 试卷预览 | 组卷完成后可预览试卷效果 |
| 状态管理 | 草稿 → 已发布 → 已下架 |
#### 模块五:考试管理
| 功能 | 说明 |
|------|------|
| 发布考试 | 选择试卷,设置考试名称、时间窗口(开始~结束时间)|
| 指定对象 | 支持指定部门 / 小组 / 个人参加考试 |
| 考试规则 | 设置及格线、限制考试次数、考试时长 |
| 在线答题 | 学员在线作答,自动计时,超时自动交卷 |
| 成绩查看 | 交卷后立即显示成绩和答案解析 |
#### 模块六:培训计划
| 功能 | 说明 |
|------|------|
| 创建培训计划 | 设置计划名称、培训周期、培训目标 |
| 关联知识/考试 | 一个培训计划可包含多个知识文档 + 多场考试V1.0.1+ |
| 考试属性设置 | 每个考试可设置必考/选考、自定义排序V1.0.1+ |
| 分配学员 | 指定部门/小组/个人参加培训计划 |
| 进度跟踪 | 学员可查看自己的学习进度和考试状态 |
| 计划状态 | 未开始 / 进行中 / 已结束 |
### V2 及以后版本 (Future Releases)
| 版本 | 功能 | 价值 |
|------|------|------|
| **V2** | 统计报表中心 | 培训完成率、考试通过率、部门排名等数据看板 |
| **V2** | 线下培训签到 | 扫码签到/签退,记录实际培训时长 |
| **V2** | 错题本 | 学员自动收集错题,巩固薄弱知识点 |
| **V3** | 知识库增强 | 收藏、点赞、评论、全文搜索 |
| **V3** | 奖励体系 | 积分、勋章、学习排行榜 |
| **V3** | 证书管理 | 培训/考试
---
## 四、关键业务逻辑 (Business Rules)
### 4.1 权限规则
```
管理员:
├── 管理所有中心、部门、小组
├── 管理所有用户(增删改查、角色分配)
├── 查看全平台数据
└── 系统配置
讲师:
├── 管理本部门知识库(上传/编辑/删除)
├── 管理本部门题库(增删改查)
├── 创建/管理本部门试卷和考试
├── 创建/管理本部门培训计划
└── 查看本部门学员成绩
学员:
├── 查看本部门知识库(只读)
├── 参加分配给自己的培训计划
├── 参加分配给自己的考试
└── 查看个人学习记录和成绩
```
### 4.2 内容状态流转
```
┌─────────┐ 发布 ┌─────────┐ 下架 ┌─────────┐
│ 草稿 │ ───────────▶ │ 已发布 │ ───────────▶ │ 已下架 │
│ DRAFT │ │PUBLISHED │ │ OFFLINE │
└─────────┘ └─────────┘ └─────────┘
▲ │ │
│ │ 重新上架 │
│ ◀────────────────────────┘
└──────── 可继续编辑 ─────────────────────────────┘
```
| 状态 | 说明 | 学员可见 |
|------|------|----------|
| **草稿 (DRAFT)** | 讲师编辑中,未完成 | ❌ 不可见 |
| **已发布 (PUBLISHED)** | 正式生效,可被使用 | ✅ 可见 |
| **已下架 (OFFLINE)** | 临时隐藏,保留数据 | ❌ 不可见 |
### 4.3 考试规则
| 规则 | 说明 |
|------|------|
| 时间窗口 | 只有在考试开放时间内才能进入考试 |
| 限时作答 | 超过考试时长自动交卷 |
| 限制次数 | 达到最大次数后不可再考,取最高分 |
| 及格判定 | 分数 ≥ 及格线 为通过 |
| 答题顺序 | 自动组卷时题目顺序随机打乱 |
### 4.4 数据隔离规则
| 数据类型 | 隔离方式 |
|----------|----------|
| 知识库 | 按部门隔离,只能看本部门 |
| 题库 | 按部门隔离,讲师只能操作本部门 |
| 试卷/考试 | 按部门隔离 |
| 培训计划 | 按部门隔离 |
| 员工信息 | 管理员可见全部,讲师可见本部门 |
### 4.5 引用保护规则
| 场景 | 规则 |
|------|------|
| 题目下架 | 已被试卷引用的题目,下架前需确认警告 |
| 试卷下架 | 已被考试引用的试卷,下架前需确认警告 |
| 知识下架 | 已被培训计划引用的知识,下架前需确认警告 |
---
## 五、数据契约 (Data Contract)
### 5.1 核心实体
#### 用户 (sys_user)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Long | 主键 |
| wx_userid | String | 企业微信用户ID |
| real_name | String | 姓名 |
| phone | String | 手机号 |
| role | Enum | 角色ADMIN/LECTURER/STUDENT |
| department_id | Long | 所属部门 |
| group_id | Long | 所属小组(可空) |
| status | Enum | 状态ENABLED/DISABLED |
| create_time | DateTime | 创建时间 |
#### 组织架构 (sys_center / sys_department / sys_group)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Long | 主键 |
| name | String | 名称 |
| parent_id | Long | 上级ID部门关联中心小组关联部门 |
| sort_order | Integer | 排序 |
| create_time | DateTime | 创建时间 |
#### 知识分类 (km_category)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Long | 主键 |
| name | String | 分类名称 |
| parent_id | Long | 父分类ID |
| department_id | Long | 所属部门 |
| sort_order | Integer | 排序 |
#### 知识 (km_knowledge)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Long | 主键 |
| title | String | 标题 |
| category_id | Long | 所属分类 |
| type | Enum | 类型DOCUMENT/VIDEO |
| file_url | String | 文件地址 |
| file_size | Long | 文件大小 |
| department_id | Long | 所属部门 |
| status | Enum | 状态DRAFT/PUBLISHED/OFFLINE |
| creator_id | Long | 创建人 |
| create_time | DateTime | 创建时间 |
| publish_time | DateTime | 发布时间 |
#### 题目 (ex_question)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Long | 主键 |
| type | Enum | 题型SINGLE/MULTIPLE/JUDGE |
| content | String | 题干 |
| options | JSON | 选项列表(判断题为空) |
| answer | String | 正确答案 |
| analysis | String | 解析 |
| category_id | Long | 所属分类 |
| department_id | Long | 所属部门 |
| status | Enum | 状态DRAFT/PUBLISHED/OFFLINE |
| creator_id | Long | 创建人 |
| create_time | DateTime | 创建时间 |
| publish_time | DateTime | 发布时间 |
#### 试卷 (ex_paper)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Long | 主键 |
| title | String | 试卷名称 |
| total_score | Integer | 总分 |
| duration | Integer | 考试时长(分钟) |
| pass_score | Integer | 及格分 |
| department_id | Long | 所属部门 |
| status | Enum | 状态DRAFT/PUBLISHED/OFFLINE |
| creator_id | Long | 创建人 |
| create_time | DateTime | 创建时间 |
| publish_time | DateTime | 发布时间 |
#### 试卷题目关联 (ex_paper_question)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Long | 主键 |
| paper_id | Long | 试卷ID |
| question_id | Long | 题目ID |
| score | Integer | 该题分值 |
| sort_order | Integer | 排序 |
#### 考试 (ex_exam)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Long | 主键 |
| title | String | 考试名称 |
| paper_id | Long | 关联试卷 |
| start_time | DateTime | 开始时间 |
| end_time | DateTime | 结束时间 |
| max_attempts | Integer | 最大考试次数 |
| department_id | Long | 所属部门 |
| status | Enum | 状态NOT_STARTED/IN_PROGRESS/ENDED |
| creator_id | Long | 创建人 |
| create_time | DateTime | 创建时间 |
#### 考试对象 (ex_exam_target)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Long | 主键 |
| exam_id | Long | 考试ID |
| target_type | Enum | 对象类型DEPARTMENT/GROUP/USER |
| target_id | Long | 对象ID |
#### 考试记录 (ex_exam_record)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Long | 主键 |
| exam_id | Long | 考试ID |
| user_id | Long | 学员ID |
| attempt_no | Integer | 第几次考试 |
| score | Integer | 得分 |
| passed | Boolean | 是否通过 |
| start_time | DateTime | 开始时间 |
| submit_time | DateTime | 提交时间 |
| answers | JSON | 答题详情 |
#### 培训计划 (tr_plan)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Long | 主键 |
| title | String | 计划名称 |
| description | String | 计划描述 |
| start_date | Date | 开始日期 |
| end_date | Date | 结束日期 |
| department_id | Long | 所属部门 |
| exam_id | Long | 关联考试(可空) |
| status | Enum | 状态NOT_STARTED/IN_PROGRESS/ENDED |
| creator_id | Long | 创建人 |
| create_time | DateTime | 创建时间 |
#### 培训计划-知识关联 (tr_plan_knowledge)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Long | 主键 |
| plan_id | Long | 计划ID |
| knowledge_id | Long | 知识ID |
| required | Boolean | 是否必修 |
| sort_order | Integer | 排序 |
#### 培训计划-对象 (tr_plan_target)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Long | 主键 |
| plan_id | Long | 计划ID |
| target_type | Enum | 对象类型DEPARTMENT/GROUP/USER |
| target_id | Long | 对象ID |
#### 培训进度 (tr_plan_progress)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Long | 主键 |
| plan_id | Long | 计划ID |
| user_id | Long | 学员ID |
| knowledge_id | Long | 知识ID |
| completed | Boolean | 是否完成 |
| complete_time | DateTime | 完成时间 |
---
## 六、原型设计方案A - 经典管理后台风格)
### 6.1 设计理念
左侧固定导航 + 右侧内容区,层级分明,适合功能复杂的企业管理系统。学习成本低,用户容易上手。
### 6.2 布局结构
```
┌────────────────────────────────────────────────────────────────────────────┐
│ 🚗 道路救援培训系统 🔔 消息 👤 张三 ▼ │
├──────────────────┬─────────────────────────────────────────────────────────┤
│ │ │
│ 📊 工作台 │ 内容区域 │
│ │ │
│ 👥 人员管理 ▶ │ │
│ ├ 组织架构 │ │
│ ├ 员工管理 │ │
│ └ 讲师管理 │ │
│ │ │
│ 📚 知识库 ▶ │ │
│ ├ 知识分类 │ │
│ └ 知识列表 │ │
│ │ │
│ ✏️ 考题管理 ▶ │ │
│ ├ 题库分类 │ │
│ └ 题目列表 │ │
│ │ │
│ 📄 试卷管理 │ │
│ │ │
│ 📝 考试管理 │ │
│ │ │
│ 📅 培训计划 │ │
│ │ │
│ ────────────── │ │
│ ⚙️ 系统设置 │ │
│ │ │
└──────────────────┴─────────────────────────────────────────────────────────┘
```
### 6.3 核心页面原型
#### 工作台首页
```
┌────────────────────────────────────────────────────────────────────────────┐
│ 🚗 道路救援培训系统 🔔 消息 👤 张三 ▼ │
├──────────────────┬─────────────────────────────────────────────────────────┤
│ │ │
│ 📊 工作台 ● │ 欢迎回来,张三 2026年1月8日 │
│ │ │
│ 👥 人员管理 ▶ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ │ 待学习课程 │ │ 待完成考试 │ │ 培训进度 │ │
│ 📚 知识库 ▶ │ │ │ │ │ │ │ │
│ │ │ 12 │ │ 3 │ │ 75% │ │
│ ✏️ 考题管理 ▶ │ │ │ │ │ │ ████░░ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │
│ 📄 试卷管理 │ │
│ │ ┌──────────────────────────────────────────────────┐ │
│ 📝 考试管理 │ │ 我的培训计划 │ │
│ │ ├──────────────────────────────────────────────────┤ │
│ 📅 培训计划 │ │ 📋 2026年Q1安全规范培训 进行中 60% │ │
│ │ │ 📋 新员工入职培训 进行中 30% │ │
│ │ │ 📋 高速救援操作规范 未开始 -- │ │
│ │ └──────────────────────────────────────────────────┘ │
│ │ │
│ │ ┌──────────────────────────────────────────────────┐ │
│ │ │ 待完成考试 │ │
│ │ ├──────────────────────────────────────────────────┤ │
│ │ │ 📝 安全规范考核 截止: 1月15日 [进入考试] │ │
│ │ │ 📝 月度技能测试 截止: 1月20日 [进入考试] │ │
│ │ └──────────────────────────────────────────────────┘ │
│ │ │
└──────────────────┴─────────────────────────────────────────────────────────┘
```
#### 知识库列表页
```
┌────────────────────────────────────────────────────────────────────────────┐
│ 🚗 道路救援培训系统 🔔 消息 👤 张三 ▼ │
├──────────────────┬─────────────────────────────────────────────────────────┤
│ │ │
│ 📊 工作台 │ 知识库 > 安全规范 │
│ │ ───────────────────────────────────────────────── │
│ 👥 人员管理 ▶ │ │
│ │ [+ 新增知识] [所有状态 ▼] [🔍 搜索知识...] │
│ 📚 知识库 ▼ │ │
│ ┌ 知识分类 │ ┌────────────────────────────────────────────────┐ │
│ └ 知识列表 ● │ │ 标题 类型 状态 更新时间 操作│ │
│ │ ├────────────────────────────────────────────────┤ │
│ ✏️ 考题管理 ▶ │ │ 高速救援SOP 📄文档 已发布 01-05 编辑│ │
│ │ │ 安全操作视频 🎬视频 已发布 01-03 编辑│ │
│ 📄 试卷管理 │ │ 应急处理流程 📄文档 草稿 01-02 编辑│ │
│ │ │ 设备使用手册 📄文档 已下架 12-28 编辑│ │
│ 📝 考试管理 │ └────────────────────────────────────────────────┘ │
│ │ │
│ 📅 培训计划 │ 共 24 条记录 < 1 2 3 4 5 > │
│ │ │
└──────────────────┴─────────────────────────────────────────────────────────┘
```
#### 在线考试页
```
┌────────────────────────────────────────────────────────────────────────────┐
│ 📝 2026年Q1安全规范考试 剩余时间: 45:23 │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ 第 3 题 / 共 20 题 [单选题] │ │
│ ├─────────────────────────────────────────────────────────────────────┤ │
│ │ │ │
│ │ 高速公路救援作业时,警示标志应放置在故障车辆后方多少米处? │ │
│ │ │ │
│ │ ○ A. 50米 │ │
│ │ ● B. 150米 │ │
│ │ ○ C. 200米 │ │
│ │ ○ D. 100米 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ 答题卡: │
│ ┌────────────────────────────────────────────────────────────────────┐ │
│ │ ✓1 ✓2 ●3 ○4 ○5 ○6 ○7 ○8 ○9 ○10 │ │
│ │ ○11 ○12 ○13 ○14 ○15 ○16 ○17 ○18 ○19 ○20 │ │
│ └────────────────────────────────────────────────────────────────────┘ │
│ │
│ [< 上一题] [下一题 >] [交卷] │
│ │
└────────────────────────────────────────────────────────────────────────────┘
```
#### 试卷组卷页
```
┌────────────────────────────────────────────────────────────────────────────┐
│ 🚗 道路救援培训系统 🔔 消息 👤 张三 ▼ │
├──────────────────┬─────────────────────────────────────────────────────────┤
│ │ │
│ 📊 工作台 │ 创建试卷 > 第2步选择题目 │
│ │ ═══════════════════════════════════════════════════ │
│ 👥 人员管理 ▶ │ ① 基本信息 ────── ② 选择题目 ────── ③ 预览确认 │
│ │ ● │
│ 📚 知识库 ▶ │ │
│ │ ┌─────────────────────┐ ┌────────────────────────┐ │
│ ✏️ 考题管理 ▶ │ │ 📂 题库 │ │ 📋 已选题目 (15) │ │
│ │ │ ┌─────────────────┐ │ │ │ │
│ 📄 试卷管理 ● │ │ │ [全选] 安全(48) │ │ │ 单选题 x10 30分 │ │
│ │ │ │ ☑ 高速警示... │ │ │ 多选题 x3 15分 │ │
│ 📝 考试管理 │ │ │ ☑ 夜间灯光... │ │ │ 判断题 x2 5分 │ │
│ │ │ │ ☐ 拖车规范... │ │ │ ─────────────── │ │
│ 📅 培训计划 │ │ └─────────────────┘ │ │ 总分: 50分 │ │
│ │ │ │ │ │ │
│ │ │ ── 或自动组卷 ── │ │ [自动组卷] │ │
│ │ │ 单选: [10] 题 │ │ 单选: [10] 题 │ │
│ │ │ 多选: [ 5] 题 │ │ 多选: [ 5] 题 │ │
│ │ │ 判断: [ 5] 题 │ │ 判断: [ 5] 题 │ │
│ │ │ [随机抽题] │ │ [确认随机抽取] │ │
│ │ └─────────────────────┘ └────────────────────────┘ │
│ │ │
│ │ [上一步] [下一步:预览] │
└──────────────────┴─────────────────────────────────────────────────────────┘
```
---
## 七、架构设计蓝图
### 7.1 系统架构总览
```
┌─────────────────────────────────────────────────────────────────────────┐
│ 客户端层 │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ PC浏览器 │ │ 企业微信H5 │ │ 移动端浏览器 │ │
│ │ (管理员/讲师) │ │ (学员) │ │ (学员) │ │
│ └────────┬────────┘ └────────┬────────┘ └────────┬────────┘ │
└───────────┼─────────────────────┼─────────────────────┼─────────────────┘
│ │ │
└─────────────────────┼─────────────────────┘
┌─────────────────────────────────────────────────────────────────────────┐
│ 网关层 │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ Spring Boot 应用 │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ JWT认证 │ │ 权限拦截 │ │ 日志记录 │ │ 异常处理 │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────┐
│ 业务层 │
│ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐ │
│ │ 认证模块 │ │ 组织模块 │ │ 知识库模块│ │ 考试模块 │ │ 培训模块 │ │
│ │ │ │ │ │ │ │ │ │ │ │
│ │ ·企微登录 │ │ ·组织架构 │ │ ·分类管理 │ │ ·题库管理 │ │ ·计划管理 │ │
│ │ ·Token管理│ │ ·员工管理 │ │ ·知识CRUD │ │ ·试卷管理 │ │ ·任务分配 │ │
│ │ ·权限校验 │ │ ·角色管理 │ │ ·文件上传 │ │ ·考试管理 │ │ ·进度跟踪 │ │
│ └───────────┘ └───────────┘ └───────────┘ └───────────┘ └───────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────┐
│ 数据层 │
│ ┌─────────────────────────┐ ┌─────────────────────────┐ │
│ │ MySQL 8.0 │ │ 文件存储服务 │ │
│ │ (MyBatis Plus ORM) │ │ (本地/OSS/MinIO) │ │
│ └─────────────────────────┘ └─────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
```
### 7.2 核心流程图
#### 用户登录流程企业微信OAuth
```mermaid
sequenceDiagram
participant U as 用户
participant FE as 前端页面
participant BE as 后端服务
participant WX as 企业微信API
participant DB as 数据库
U->>FE: 点击"企业微信登录"
FE->>WX: 跳转企微授权页面
WX->>U: 显示授权确认
U->>WX: 确认授权
WX->>FE: 回调返回code
FE->>BE: 携带code请求登录
BE->>WX: 用code换取access_token
WX-->>BE: 返回access_token
BE->>WX: 获取用户信息(userid)
WX-->>BE: 返回用户信息
BE->>DB: 查询用户是否存在
alt 用户存在
DB-->>BE: 返回用户信息
BE->>BE: 生成JWT Token
BE-->>FE: 返回Token+用户信息
FE->>FE: 存储Token跳转工作台
else 用户不存在
BE-->>FE: 返回错误:用户未录入
FE->>U: 提示联系管理员
end
```
#### 在线考试流程
```mermaid
sequenceDiagram
participant S as 学员
participant FE as 前端页面
participant BE as 后端服务
participant DB as 数据库
S->>FE: 进入考试列表
FE->>BE: 获取我的考试列表
BE->>DB: 查询分配给该学员的考试
DB-->>BE: 返回考试列表
BE-->>FE: 返回考试列表(含剩余次数)
S->>FE: 点击"开始考试"
FE->>BE: 请求开始考试
BE->>DB: 校验考试状态/次数/时间窗口
alt 校验通过
BE->>DB: 创建考试记录(开始时间)
BE->>DB: 获取试卷题目
DB-->>BE: 返回题目列表
BE-->>FE: 返回试卷内容+考试时长
FE->>FE: 启动倒计时
loop 答题过程
S->>FE: 选择/修改答案
FE->>FE: 本地暂存答案
FE->>BE: 定时自动保存(每30秒)
BE->>DB: 更新答题记录
end
alt 主动交卷
S->>FE: 点击"交卷"
else 时间到
FE->>FE: 倒计时结束
end
FE->>BE: 提交试卷
BE->>BE: 自动判分(客观题)
BE->>DB: 保存成绩+答案详情
BE-->>FE: 返回考试成绩
FE->>S: 显示成绩+答案解析
else 校验失败
BE-->>FE: 返回错误(次数用尽/不在时间窗口)
FE->>S: 提示无法参加考试
end
```
#### 培训计划执行流程
```mermaid
flowchart TB
subgraph 讲师操作
A[创建培训计划] --> B[设置基本信息]
B --> C[关联知识内容]
C --> D[关联考试-可选]
D --> E[指定培训对象]
E --> F[发布培训计划]
end
subgraph 学员学习
F --> G[学员收到培训通知]
G --> H[进入培训计划]
H --> I[学习知识内容]
I --> J{知识学完?}
J -->|否| I
J -->|是| K{有关联考试?}
K -->|否| L[培训完成]
K -->|是| M[参加考试]
M --> N{考试通过?}
N -->|是| L
N -->|否| O{还有考试次数?}
O -->|是| M
O -->|否| P[培训未通过]
end
subgraph 进度追踪
I --> Q[更新学习进度]
M --> R[记录考试成绩]
L --> S[标记培训完成]
end
```
### 7.3 技术选型
| 层次 | 技术 | 版本 | 说明 |
|------|------|------|------|
| **构建** | Maven | 3.8+ | 依赖管理 |
| **框架** | Spring Boot | 3.1.2 | 主框架 |
| **ORM** | MyBatis Plus | 3.5.3+ | 简化CRUD |
| **数据库** | MySQL | 8.0 | 主数据库 |
| **认证** | java-jwt | 4.4+ | JWT Token生成验证 |
| **加密** | Spring Security | 6.x | BCrypt密码加密 |
| **文档** | Springdoc OpenAPI | 2.2+ | API文档 |
| **工具** | Lombok | 1.18+ | 简化代码 |
| **JSON** | Jackson | 内置 | JSON序列化 |
| **文件** | 本地存储 / MinIO | - | V1先用本地V2可扩展 |
| **前端** | HTML + CSS + JS | - | 原生技术栈 |
#### 关键依赖库
| 用途 | 库 | 说明 |
|------|-----|------|
| 企业微信SDK | weixin-java-cp | 企业微信Java SDK |
| 文件预览 | kkFileView / OnlyOffice | 文档在线预览(可选外部服务) |
| 视频播放 | video.js | 前端视频播放器 |
| Excel导入导出 | EasyExcel | 阿里开源,性能好 |
| 工具库 | Hutool | 常用工具集合 |
### 7.4 风险评估
| 风险点 | 等级 | 描述 | 应对策略 |
|--------|------|------|----------|
| **企业微信对接** | 🟡 中 | 需要企业微信管理员配置应用 | 提前准备配置文档,预留账号密码登录作为备选 |
| **文件预览** | 🟡 中 | 不同格式文档预览兼容性 | V1优先支持PDF+图片+视频,复杂格式提示下载 |
| **大文件上传** | 🟡 中 | 视频文件可能较大 | 限制单文件大小,支持分片上传 |
| **考试并发** | 🟢 低 | 500人规模并发压力不大 | 合理设计索引,必要时加缓存 |
| **数据隔离** | 🟢 低 | 部门数据隔离逻辑 | 统一在Service层实现隔离过滤 |
### 7.5 项目结构
```
training-system/
├── pom.xml
├── src/
│ └── main/
│ ├── java/com/sino/training/
│ │ ├── TrainingApplication.java # 启动类
│ │ │
│ │ ├── common/ # 通用模块
│ │ │ ├── config/ # 配置类
│ │ │ ├── exception/ # 异常处理
│ │ │ ├── result/ # 统一响应
│ │ │ ├── interceptor/ # 拦截器
│ │ │ └── utils/ # 工具类
│ │ │
│ │ ├── module/ # 业务模块
│ │ │ ├── auth/ # 认证模块
│ │ │ ├── system/ # 系统管理
│ │ │ ├── knowledge/ # 知识库模块
│ │ │ ├── exam/ # 考试模块
│ │ │ └── training/ # 培训模块
│ │ │
│ │ └── integration/ # 外部集成
│ │ └── wechat/ # 企业微信
│ │
│ └── resources/
│ ├── application.yml # 主配置
│ ├── application-dev.yml # 开发环境
│ ├── application-prod.yml # 生产环境
│ ├── mapper/ # MyBatis XML
│ ├── static/ # 静态资源
│ └── templates/ # 页面模板
├── docs/
│ └── PRD.md # 产品需求文档
└── sql/
└── init.sql # 数据库初始化脚本
```
---
## 八、附录
### 8.1 角色菜单权限对照表
| 菜单 | 管理员 | 讲师 | 学员 |
|------|--------|------|------|
| 工作台 | ✅ | ✅ | ✅ |
| 组织架构管理 | ✅ | ❌ | ❌ |
| 员工管理 | ✅ | 👁️ 本部门只读 | ❌ |
| 讲师管理 | ✅ | ❌ | ❌ |
| 知识库-分类管理 | ✅ | ✅ 本部门 | ❌ |
| 知识库-知识列表 | ✅ | ✅ 本部门 | 👁️ 本部门已发布 |
| 考题管理-题库分类 | ✅ | ✅ 本部门 | ❌ |
| 考题管理-题目列表 | ✅ | ✅ 本部门 | ❌ |
| 试卷管理 | ✅ | ✅ 本部门 | ❌ |
| 考试管理 | ✅ | ✅ 本部门 | 👁️ 我的考试 |
| 培训计划 | ✅ | ✅ 本部门 | 👁️ 我的培训 |
| 系统设置 | ✅ | ❌ | ❌ |
### 8.2 状态枚举定义
```java
// 内容状态
public enum ContentStatus {
DRAFT, // 草稿
PUBLISHED, // 已发布
OFFLINE // 已下架
}
// 用户角色
public enum UserRole {
ADMIN, // 管理员
LECTURER, // 讲师
STUDENT // 学员
}
// 用户状态
public enum UserStatus {
ENABLED, // 启用
DISABLED // 禁用
}
// 题目类型
public enum QuestionType {
SINGLE, // 单选题
MULTIPLE, // 多选题
JUDGE // 判断题
}
// 知识类型
public enum KnowledgeType {
DOCUMENT, // 文档
VIDEO // 视频
}
// 考试/培训目标类型
public enum TargetType {
DEPARTMENT, // 部门
GROUP, // 小组
USER // 个人
}
// 考试状态
public enum ExamStatus {
NOT_STARTED, // 未开始
IN_PROGRESS, // 进行中
ENDED // 已结束
}
// 培训计划状态
public enum PlanStatus {
NOT_STARTED, // 未开始
IN_PROGRESS, // 进行中
ENDED // 已结束
}
```
---
**文档状态:已确认,等待开发启动**

View File

@@ -0,0 +1,664 @@
# 学员端功能需求文档
> 版本V1.0.1
> 创建日期2026-01-15
> 更新日期2026-01-15
> 状态:✅ 已批准Supervisor 复审通过)
---
## 版本更新记录
### V1.0.1 (2026-01-15)
**根据Supervisor审查意见修订**
| 修订项 | 修订内容 |
|--------|----------|
| 知识学习入口 | 补充培训任务学习场景、返回逻辑、来源区分 |
| 断点续考机制 | 补充定时任务策略、超时判定规则、并发处理 |
| 排名计算规则 | 明确计算时机、统计范围、口径定义 |
| 学习时长防刷 | 新增活跃检测机制 |
| 数据表设计 | km_knowledge_progress 新增 department_id 字段 |
| 页面路径 | 调整为复用现有路径,按角色控制 |
| 解析显示策略 | 明确交卷后立即显示解析 |
| 非功能需求 | 补充可测试的性能指标 |
---
## 一、概述
### 1.1 目标用户
- **角色**学员STUDENT
- **人数**约450人
- **入口**PC浏览器与管理端共用系统按角色显示不同菜单
### 1.2 核心目标
为学员提供便捷的在线学习平台,支持知识学习、在线考试、培训计划跟踪,帮助学员提升专业技能。
---
## 二、功能模块总览
| 模块 | 功能点 | 优先级 |
|------|--------|--------|
| 工作台 | 学习概览、待办事项 | P0 |
| 知识学习 | 知识浏览、学习进度、时长统计 | P0 |
| 在线考试 | 考试列表、在线答题、断点续考、成绩排名 | P0 |
| 我的培训 | 培训计划、进度跟踪、完成判定 | P0 |
| 个人中心 | 学习记录、考试记录、证书(预留) | P1 |
---
## 三、详细功能需求
### 3.1 工作台(首页)
#### 用户故事
> 作为学员,我希望登录后看到学习概览和待办事项,以便快速了解学习状态和接下来要做的事。
#### 功能清单
| 功能项 | 说明 |
|--------|------|
| 学习统计卡片 | 显示:待学习课程数、待完成考试数、培训进度百分比 |
| 我的培训计划 | 列表展示分配给我的培训计划最多显示5条显示进度 |
| 待完成考试 | 列表展示待完成的考试最多显示5条显示截止时间 |
| 快捷入口 | 点击可直接进入对应详情页 |
#### 验收标准
- [ ] 登录后默认进入工作台页面
- [ ] 统计数据实时准确(待学习=未完成的必修知识数,待考试=未通过的必考考试数)
- [ ] 培训进度百分比 = 已完成必修项 / 总必修项 × 100%
- [ ] 点击培训计划可跳转到计划详情
- [ ] 点击考试可跳转到考试页面
- [ ] 只显示"进行中"状态的培训计划和处于"时间窗口内"的考试
---
### 3.2 知识学习
#### 用户故事
> 作为学员,我希望浏览本部门的知识库,学习文档和视频,并能看到自己的学习进度。
#### 功能清单
| 功能项 | 说明 |
|--------|------|
| 知识分类导航 | 左侧树形结构展示知识分类 |
| 知识列表 | 按分类筛选,显示知识标题、类型、学习状态 |
| 知识详情/预览 | 文档在线预览、视频在线播放 |
| 学习进度记录 | 记录学习完成状态、学习时长 |
| 强制学习机制 | 视频必须播放完成、文档必须阅读完成才记录为"已完成" |
#### 3.2.1 知识列表页
**页面元素**
- 分类筛选(树形)
- 知识卡片列表:标题、类型图标(文档/视频)、学习状态标签、时长/大小
- 搜索框(按标题搜索)
**学习状态**
| 状态 | 说明 | 显示样式 |
|------|------|----------|
| 未学习 | 从未打开过 | 灰色标签 |
| 学习中 | 已开始但未完成 | 蓝色标签 + 进度% |
| 已完成 | 满足完成条件 | 绿色标签 ✓ |
#### 3.2.2 知识详情页
**文档类型**
- 在线预览PDF直接显示Word/Excel/PPT转换预览
- 学习计时:进入页面开始计时,离开页面停止
- 完成条件:停留时间 ≥ 预估阅读时间(可配置,默认按页数计算)
**视频类型**
- 在线播放(支持进度条、全屏)
- 播放进度记录:记录当前播放位置,下次打开从断点继续
- 完成条件:播放进度 ≥ 90%(可配置)
- 禁止拖动快进(强制学习模式下)
#### 3.2.3 学习入口场景(🔴 修订项1
**场景一:自由学习(从知识库进入)**
- 入口:左侧菜单"知识库" → 知识列表 → 知识详情
- 学习完成后:停留在知识详情页,可点击"返回列表"
- 进度记录:标记来源为 `FREE`(自由学习)
**场景二:培训任务学习(从培训计划进入)**
- 入口:培训详情页 → 点击知识项 → 知识详情
- 页面顶部显示:返回培训计划入口(如:"← 返回《2026年Q1安全规范培训》"
- 学习完成后:
- 自动弹出提示:"学习完成!是否返回培训计划?"
- 用户可选择【返回培训】或【继续浏览】
- 进度记录:标记来源为 `TRAINING`(培训任务),关联 `plan_id`
**进度记录来源区分**
| 来源 | 场景 | 影响 |
|------|------|------|
| FREE | 自由学习 | 仅记录个人学习进度 |
| TRAINING | 培训任务学习 | 同时更新培训计划进度 |
> **说明**:无论从哪个入口学习,学习时长和完成状态都会记录。区分来源是为了后续统计分析(如:培训驱动的学习 vs 自主学习)。
#### 3.2.4 学习时长防刷机制(🟡 优化项1
**文档类型防刷策略**
- 每60秒检测一次用户活跃状态
- 活跃判定60秒内有鼠标移动、点击、滚动任一事件
- 非活跃时:暂停计时,页面显示"检测到您暂时离开,学习计时已暂停"
- 恢复活跃后:继续计时
**视频类型防刷策略**
- 依赖视频播放事件,暂停时不计时长
- 无需额外活跃检测
**多标签页处理**
- 同一知识同时只能在一个标签页学习
- 检测到多标签页打开同一知识时,后打开的标签页提示"该知识已在其他窗口学习中"
#### 验收标准
- [ ] 只显示本部门、已发布状态的知识
- [ ] 分类树正确展示,点击分类筛选对应知识
- [ ] 文档能正常在线预览至少支持PDF
- [ ] 视频能正常播放,支持暂停、音量调节
- [ ] 视频播放进度自动保存,刷新页面后从断点继续
- [ ] 强制学习模式下,视频不能快进跳过
- [ ] 学习时长准确记录(精确到秒)
- [ ] 满足完成条件后自动标记为"已完成"
- [ ] 学习进度与培训计划进度联动
- [ ] 🔴 从培训计划进入的知识学习,顶部显示返回入口
- [ ] 🔴 学习完成后弹出返回培训计划提示(仅培训任务学习场景)
- [ ] 🟡 文档学习时,非活跃状态暂停计时
- [ ] 🟡 同一知识不能在多个标签页同时学习
---
### 3.3 在线考试
#### 用户故事
> 作为学员,我希望参加分配给我的考试,并能查看成绩和排名。
#### 功能清单
| 功能项 | 说明 |
|--------|------|
| 考试列表 | 展示分配给我的所有考试 |
| 考试详情 | 显示考试信息、我的考试记录 |
| 在线答题 | 单选/多选/判断题作答 |
| 断点续考 | 中途退出后可继续答题 |
| 自动交卷 | 时间到自动提交 |
| 成绩查看 | 显示得分、答案解析 |
| 成绩排名 | 显示我在本次考试中的排名 |
#### 3.3.1 考试列表页
**列表字段**
| 字段 | 说明 |
|------|------|
| 考试名称 | 点击进入考试详情 |
| 考试时间 | 开始时间 ~ 结束时间 |
| 考试状态 | 未开始/进行中/已结束 |
| 我的状态 | 未参加/考试中/已完成 |
| 最高成绩 | 多次考试取最高分 |
| 剩余次数 | 最大次数 - 已考次数 |
| 操作 | 进入考试/查看成绩 |
**筛选条件**
- 考试状态:全部/进行中/已结束
- 我的状态:全部/未完成/已完成
#### 3.3.2 考试详情页(进入考试前)
**显示信息**
- 考试名称、考试时间窗口
- 考试规则:时长、总分、及格线、最大次数
- 我的考试记录表格第N次、得分、是否通过、时间
- 【开始考试】/【继续考试】按钮
**按钮逻辑**
| 场景 | 按钮状态 |
|------|----------|
| 不在时间窗口内 | 禁用,提示"考试未开始"或"考试已结束" |
| 次数已用完 | 禁用,提示"考试次数已用完" |
| 有进行中的考试记录 | 显示【继续考试】 |
| 可以开始新考试 | 显示【开始考试】 |
#### 3.3.3 在线答题页
**页面布局**
```
┌─────────────────────────────────────────────────────────┐
│ 考试名称 剩余时间: 45:23 │
├─────────────────────────────────────────────────────────┤
│ 第 3 题 / 共 20 题 [单选题] │
│ ───────────────────────────────────────────────────── │
│ 题干内容... │
│ │
│ ○ A. 选项A │
│ ● B. 选项B已选中
│ ○ C. 选项C │
│ ○ D. 选项D │
├─────────────────────────────────────────────────────────┤
│ 答题卡: [1✓] [2✓] [3●] [4○] [5○] ... │
├─────────────────────────────────────────────────────────┤
│ [上一题] [下一题] [交卷] │
└─────────────────────────────────────────────────────────┘
```
**功能说明**
| 功能 | 说明 |
|------|------|
| 倒计时 | 显示剩余时间最后5分钟变红色提醒 |
| 题目导航 | 点击答题卡数字可跳转到对应题目 |
| 答案自动保存 | 选择答案后自动保存到服务器每30秒或切题时 |
| 上一题/下一题 | 切换题目 |
| 交卷 | 弹出确认框,确认后提交 |
| 自动交卷 | 时间结束自动提交当前答案 |
**断点续考机制**
- 考试开始后创建考试记录,状态为"进行中"
- 答案实时保存到服务器
- 中途关闭浏览器/断网,考试记录保持"进行中"
- 重新打开考试,检测到进行中记录,恢复到上次状态
- 倒计时从剩余时间继续(服务端计算:考试时长 - 已用时间)
- 超时未提交的考试,由定时任务自动交卷
#### 3.3.5 超时自动交卷机制(🔴 修订项2
**超时判定规则**
```
超时时间点 = 考试记录开始时间 + 考试时长(分钟)
```
**示例**
- 学员A在 10:00 开始考试考试时长60分钟
- 超时时间点 = 10:00 + 60分钟 = 11:00
- 无论考试时间窗口是否结束11:00后该考试记录即视为超时
**定时任务策略**
| 配置项 | 值 | 说明 |
|--------|-----|------|
| 执行频率 | 每1分钟 | Cron: `0 */1 * * * ?` |
| 扫描范围 | 状态为IN_PROGRESS的考试记录 | 只处理进行中的记录 |
| 超时判定 | 当前时间 > 开始时间 + 考试时长 | 精确到秒 |
| 处理动作 | 自动提交当前已保存的答案,计算成绩 | 标记为系统自动交卷 |
**并发提交处理(乐观锁)**
```
场景学员在超时前1秒点击交卷同时定时任务也在处理该记录
```
**处理策略**
1. 考试记录表增加 `version` 字段(乐观锁)
2. 提交时检查 `status = IN_PROGRESS AND version = 当前版本`
3. 更新时 `version = version + 1`
4. 若更新失败version已变说明已被其他请求处理直接返回已提交的结果
**状态流转**
```
IN_PROGRESS ──用户主动交卷──▶ SUBMITTED来源USER
└──────定时任务超时交卷──▶ SUBMITTED来源SYSTEM_TIMEOUT
```
**交卷来源标记**
| 来源 | 说明 |
|------|------|
| USER | 用户主动交卷 |
| SYSTEM_TIMEOUT | 系统超时自动交卷 |
> **注意**:即使考试时间窗口已结束,只要考试记录未超时,学员仍可继续答题(但无法开始新的考试)
#### 3.3.6 考试结果页
**显示内容**
| 项目 | 说明 |
|------|------|
| 得分 | 大字显示,及格绿色/不及格红色 |
| 是否通过 | 通过✓ / 未通过✗ |
| 排名 | "您的成绩排名第 X 名(共 Y 人参加)" |
| 答题详情 | 每道题的正确答案、我的答案、解析 |
| 操作按钮 | 【再考一次】(有次数)/ 【返回列表】 |
**答案解析显示策略(🟡 优化项4**
- 交卷后立即显示所有题目的答案解析
- 无论考试是否通过,都显示解析
- 目的:培训学习为主,帮助学员理解错误原因
#### 3.3.7 排名计算规则(🔴 修订项3
**计算时机**
- 实时计算:每次交卷时计算排名
- 非定时计算:不采用批量定时计算方式
**统计范围**
- 范围:当前考试的所有参与者(被分配且已交卷的学员)
- 跨部门:若考试分配给多个部门,排名为所有参与者的总排名
**排名规则**
| 优先级 | 规则 | 说明 |
|--------|------|------|
| 1 | 最高成绩降序 | 成绩高的排名靠前 |
| 2 | 达到最高成绩的时间升序 | 成绩相同时,先达到该成绩的排名靠前 |
**"共Y人参加"统计口径**
| 统计项 | 是否计入 |
|--------|----------|
| 已交卷学员 | ✅ 计入 |
| 正在考试中(未交卷) | ❌ 不计入 |
| 被分配但未参加 | ❌ 不计入 |
**排名示例**
```
考试:安全规范考核
分配对象部门A30人、部门B20人
参与情况:
- 部门A25人已交卷5人未参加
- 部门B18人已交卷2人正在考试中
排名统计:共 43 人参加25 + 18 = 43
排名结果:
第1名张三95分首次达到时间 10:30
第2名李四95分首次达到时间 10:45
第3名王五90分
...
```
**实现建议**
- 交卷时实时计算排名并返回
- 排名计算SQL示例思路
```sql
SELECT user_id, MAX(score) as best_score, MIN(submit_time) as first_best_time
FROM ex_exam_record
WHERE exam_id = ? AND status = 'SUBMITTED'
GROUP BY user_id
ORDER BY best_score DESC, first_best_time ASC
```
#### 验收标准
- [ ] 只显示分配给当前学员的考试
- [ ] 考试状态、我的状态准确显示
- [ ] 不在时间窗口内无法进入考试
- [ ] 次数用完无法再次考试
- [ ] 答题过程中答案实时保存
- [ ] 刷新页面/重新进入可继续答题(断点续考)
- [ ] 倒计时准确,超时自动交卷
- [ ] 交卷后立即显示成绩和排名
- [ ] 答案解析正确显示
- [ ] 多次考试取最高分显示
- [ ] 🔴 定时任务每分钟执行,自动处理超时考试记录
- [ ] 🔴 并发交卷场景下数据一致(乐观锁机制)
- [ ] 🔴 排名实时计算,仅统计已交卷学员
- [ ] 🔴 排名规则:最高分优先,同分按首次达到时间排序
---
### 3.4 我的培训
#### 用户故事
> 作为学员,我希望查看分配给我的培训计划,跟踪学习进度,完成培训任务。
#### 功能清单
| 功能项 | 说明 |
|--------|------|
| 培训列表 | 展示分配给我的培训计划 |
| 培训详情 | 显示计划内容、学习进度 |
| 进度跟踪 | 实时显示知识学习、考试完成情况 |
| 完成判定 | 根据必修项判定培训是否完成 |
| 证书预留 | 培训完成后预留证书/徽章展示位置 |
#### 3.4.1 培训列表页
**列表字段**
| 字段 | 说明 |
|------|------|
| 培训名称 | 点击进入详情 |
| 培训周期 | 开始日期 ~ 结束日期 |
| 状态 | 未开始/进行中/已结束 |
| 我的进度 | 进度条 + 百分比 |
| 完成状态 | 未完成/已完成 |
#### 3.4.2 培训详情页
**页面结构**
```
┌─────────────────────────────────────────────────────────┐
│ 2026年Q1安全规范培训 │
│ ───────────────────────────────────────────────────── │
│ 培训周期2026-01-01 ~ 2026-03-31 │
│ 培训目标:掌握高速公路救援安全规范... │
│ 我的进度:████████░░░░ 75% │
├─────────────────────────────────────────────────────────┤
│ 📚 学习内容 (3/5) │
│ ├─ ✅ 高速救援SOP手册 [必修] [已完成] │
│ ├─ ✅ 安全操作视频 [必修] [已完成] │
│ ├─ 🔵 应急处理流程 [必修] [学习中 60%] │
│ ├─ ⚪ 设备使用指南 [选修] [未学习] │
│ └─ ✅ 案例分析 [选修] [已完成] │
├─────────────────────────────────────────────────────────┤
│ 📝 考试任务 (1/2) │
│ ├─ ✅ 安全规范考核 [必考] [已通过 85分] │
│ └─ ⚪ 操作技能测试 [必考] [未参加] │
├─────────────────────────────────────────────────────────┤
│ 🏆 完成奖励 │
│ └─ 完成培训后可获得【安全规范认证】徽章(敬请期待) │
└─────────────────────────────────────────────────────────┘
```
**进度计算规则**
```
培训进度 = (已完成必修知识数 + 已通过必考考试数) / (必修知识总数 + 必考考试总数) × 100%
```
**完成判定规则**
| 条件 | 说明 |
|------|------|
| 所有必修知识已完成 | ✓ |
| 所有必考考试已通过 | ✓ |
| 选修知识 | 不影响完成判定 |
| 选考考试 | 不影响完成判定 |
#### 验收标准
- [ ] 只显示分配给当前学员的培训计划
- [ ] 进度百分比计算准确(只计算必修项)
- [ ] 学习内容、考试任务分开展示
- [ ] 显示每项的必修/选修、必考/选考标签
- [ ] 点击知识内容可跳转到知识详情页
- [ ] 点击考试任务可跳转到考试页面
- [ ] 所有必修项完成后,培训状态变为"已完成"
- [ ] 证书/徽章区域预留V1显示"敬请期待"
---
### 3.5 个人中心
#### 用户故事
> 作为学员,我希望查看自己的学习记录、考试历史和获得的证书。
#### 功能清单
| 功能项 | 说明 |
|--------|------|
| 个人信息 | 显示姓名、部门、角色 |
| 学习统计 | 总学习时长、完成课程数 |
| 学习记录 | 知识学习历史列表 |
| 考试记录 | 考试历史列表 |
| 我的证书 | 证书/徽章展示(预留) |
#### 验收标准
- [ ] 正确显示当前用户信息
- [ ] 学习时长统计准确(累计所有知识学习时长)
- [ ] 学习记录按时间倒序展示
- [ ] 考试记录显示每次考试的详情
- [ ] 证书模块预留V1显示"暂无证书"
---
## 四、数据契约补充
### 4.1 新增/修改实体
#### 知识学习进度表 (km_knowledge_progress) - 新增
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Long | 主键 |
| user_id | Long | 学员ID |
| knowledge_id | Long | 知识ID |
| department_id | Long | **🟡 新增** 所属部门(冗余字段,便于按部门统计) |
| status | Enum | 状态NOT_STARTED/IN_PROGRESS/COMPLETED |
| progress | Integer | 进度百分比0-100 |
| duration | Long | 学习时长(秒) |
| video_position | Long | 视频播放位置(秒),仅视频类型 |
| source | Enum | **🔴 新增** 学习来源FREE/TRAINING |
| plan_id | Long | **🔴 新增** 关联培训计划ID来源为TRAINING时有值 |
| start_time | DateTime | 首次学习时间 |
| complete_time | DateTime | 完成时间 |
| update_time | DateTime | 最后更新时间 |
#### 考试记录表 (ex_exam_record) - 补充字段
| 字段 | 类型 | 说明 |
|------|------|------|
| status | Enum | **新增** 状态IN_PROGRESS/SUBMITTED |
| last_save_time | DateTime | **新增** 最后保存时间(断点续考用) |
| version | Integer | **🔴 新增** 乐观锁版本号 |
| submit_source | Enum | **🔴 新增** 交卷来源USER/SYSTEM_TIMEOUT |
### 4.2 新增枚举
```java
// 学习状态
public enum LearningStatus {
NOT_STARTED, // 未学习
IN_PROGRESS, // 学习中
COMPLETED // 已完成
}
// 🔴 学习来源
public enum LearningSource {
FREE, // 自由学习(从知识库直接进入)
TRAINING // 培训任务学习(从培训计划进入)
}
// 考试记录状态
public enum ExamRecordStatus {
IN_PROGRESS, // 考试中(用于断点续考)
SUBMITTED // 已提交
}
// 🔴 交卷来源
public enum SubmitSource {
USER, // 用户主动交卷
SYSTEM_TIMEOUT // 系统超时自动交卷
}
```
---
## 五、接口预留V2/V3功能
### 5.1 证书/徽章接口(预留)
```
POST /api/certificate/generate # 生成证书
GET /api/certificate/my # 我的证书列表
GET /api/certificate/{id} # 证书详情
GET /api/badge/my # 我的徽章列表
```
### 5.2 错题本接口V2预留
```
GET /api/wrong-questions # 错题列表
POST /api/wrong-questions/review # 标记已复习
```
---
## 六、非功能需求
| 项目 | 要求 | 测试指标(🟡 优化项5 |
|------|------|------------------------|
| 页面加载 | 页面加载 < 2秒 | 95%请求 < 2秒 |
| 考试提交 | 考试提交 < 1秒 | 99%请求 < 1秒 |
| 并发支持 | 支持100人同时在线考试 | 100并发答题响应时间 < 500ms成功率 > 99.9% |
| 答案保存 | 答案自动保存 | 保存成功率 > 99.99%,保存延迟 < 300ms |
| 数据安全 | 考试答案定时自动保存,防止数据丢失 | 断网重连后数据无丢失 |
| 兼容性 | 支持主流浏览器 | Chrome 90+、Edge 90+、Firefox 90+ |
---
## 七、不做什么Out of Scope
| 功能 | 原因 |
|------|------|
| 移动端适配 | V1仅支持PC浏览器 |
| 防作弊功能 | 产品确认不需要 |
| 学习日历 | 产品确认不需要 |
| 错题本 | V2规划 |
| 社交功能(评论、点赞) | V3规划 |
---
## 八、页面清单(🟡 优化项3
> **说明**:采用与管理端复用同一套系统的方案,按角色控制菜单和功能显示,不使用独立的 `/student/` 路径前缀。
| 页面 | 路径 | 角色可见 | 说明 |
|------|------|----------|------|
| 工作台 | /index.html | 全角色 | 根据角色显示不同内容 |
| 知识列表 | /knowledge/list.html | 全角色 | 学员只读,讲师可管理 |
| 知识详情 | /knowledge/view.html?id={id} | 全角色 | 学员增加学习进度记录 |
| 考试列表 | /exam/my-exams.html | 学员 | 我的考试列表 |
| 考试详情 | /exam/detail.html?id={id} | 学员 | 考试信息页 |
| 在线答题 | /exam/answer.html?id={id} | 学员 | 答题页面 |
| 考试结果 | /exam/result.html?recordId={id} | 学员 | 成绩结果页 |
| 培训列表 | /training/my-training.html | 学员 | 我的培训列表 |
| 培训详情 | /training/detail.html?id={id} | 学员 | 培训计划详情 |
| 个人中心 | /profile/index.html | 全角色 | 个人信息页 |
| 学习记录 | /profile/learning.html | 学员 | 学习记录列表 |
| 考试记录 | /profile/exam-history.html | 学员 | 考试记录列表 |
| 我的证书 | /profile/certificate.html | 学员 | 证书展示(预留) |
**菜单权限控制**
| 菜单项 | 管理员 | 讲师 | 学员 |
|--------|--------|------|------|
| 工作台 | ✅ | ✅ | ✅ |
| 知识库 | ✅ 管理 | ✅ 管理 | ✅ 只读学习 |
| 考题管理 | ✅ | ✅ | ❌ |
| 试卷管理 | ✅ | ✅ | ❌ |
| 考试管理 | ✅ | ✅ | ❌ |
| 我的考试 | ❌ | ❌ | ✅ |
| 培训计划 | ✅ | ✅ | ❌ |
| 我的培训 | ❌ | ❌ | ✅ |
| 个人中心 | ✅ | ✅ | ✅ |
| 系统设置 | ✅ | ❌ | ❌ |
---
## 九、修订项对照表
| 修订项 | 类型 | 章节位置 | 状态 |
|--------|------|----------|------|
| 知识学习入口场景 | 🔴 必须修正 | 3.2.3 | ✅ 已补充 |
| 断点续考超时机制 | 🔴 必须修正 | 3.3.5 | ✅ 已补充 |
| 排名计算规则 | 🔴 必须修正 | 3.3.7 | ✅ 已补充 |
| 学习时长防刷机制 | 🟡 建议优化 | 3.2.4 | ✅ 已采纳 |
| 数据表department_id | 🟡 建议优化 | 4.1 | ✅ 已采纳 |
| 页面路径设计 | 🟡 建议优化 | 8 | ✅ 已调整 |
| 答案解析显示策略 | 🟡 建议优化 | 3.3.6 | ✅ 已明确 |
| 非功能需求测试指标 | 🟡 建议优化 | 6 | ✅ 已补充 |
---
**文档状态:✅ 已批准**
> **Supervisor 复审结论**:通过
> **复审日期**2026-01-15
> **下一阶段**:技术评审 → 开发

View File

@@ -0,0 +1,379 @@
# 产品整体架构文档 — 道路救援企业培训系统
> 版本V1.0
> 生成日期2026-04-07
> 证据状态:✅ 已验证
> 证据来源:[SRC-FEAT-01] [SRC-SQL-01] [SRC-API-01] [SRC-CODE-01]
---
## 1. 产品定位
### 1.1 产品目标
为道路救援企业提供**一站式内部培训管理平台**,通过数字化方式替代口口相传的知识传承模式,实现知识沉淀、在线考核、培训过程管控三位一体。[SRC-FEAT-01]
### 1.2 核心价值
| 价值维度 | 解决的痛点 | 实现方式 |
|---------|---------|---------|
| 知识沉淀 | 知识依赖口口相传,无法沉淀 | 结构化知识库(文档+视频) |
| 高效考核 | 出题组卷效率低,纸质考试成本高 | 在线题库 + 自动/手动组卷 + 在线考试 |
| 培训管控 | 培训效果难追踪,进度不透明 | 培训计划+进度跟踪+成绩统计 |
| 标准化输出 | 服务标准参差不齐 | 统一平台 + 及格线控制 + 必考机制 |
### 1.3 目标用户
| 角色 | 人数 | 核心诉求 |
|------|------|---------|
| 管理员 | 3-5人 | 系统配置、人员管理、全平台数据可见 |
| 讲师(技师) | 30-50人 | 本部门知识上传、出题、发布考试、管理培训计划 |
| 学员 | ~450人 | 学习资料、参加考试、查看进度 |
[SRC-FEAT-01二、用户画像]
### 1.4 使用场景
- **管理员场景**:系统初始化时维护组织架构;日常监控各部门培训完成情况。
- **讲师场景**:救援规范更新后,上传新手册并更新题库,发布新考试,关联到培训计划。
- **学员场景**PC端浏览知识库预习、参加指定考试、查看自己的培训进度。
- **企业微信场景**:学员通过企业微信 H5 入口完成移动端学习和考试。
---
## 2. 系统整体架构
### 2.1 架构分层
| 层次 | 组件 | 职责 |
|-----|------|------|
| **表现层** | PC浏览器管理员/讲师、企业微信H5学员、移动端浏览器 | 用户交互HTML+CSS+JS 原生技术栈 |
| **网关层** | Spring Boot 应用JWT认证、权限拦截、日志、异常处理 | 请求入口,统一认证鉴权,全局异常处理 |
| **业务层** | 5个业务模块auth / system / knowledge / exam / training | 核心业务逻辑,按模块边界划分,禁止跨模块直接调用数据层 |
| **数据层** | MySQL 8.0MyBatis Plus ORM+ 文件存储(本地/MinIO/OSS | 持久化业务数据和媒体文件 |
[SRC-FEAT-01七、架构设计蓝图]
### 2.2 技术架构概览
| 技术选型 | 版本 | 用途 |
|---------|------|------|
| Spring Boot | 3.1.2 | 主框架 |
| MyBatis Plus | 3.5.3+ | ORM简化CRUD |
| MySQL | 8.0 | 主数据库 |
| java-jwt | 4.4+ | JWT Token 签发与验证 |
| Spring Security | 6.x | BCrypt 密码加密 |
| weixin-java-cp | - | 企业微信 SDKOAuth 登录) |
| Springdoc OpenAPI | 2.2+ | API 文档 |
| Spring @Scheduled | - | 考试超时自动交卷定时任务 |
| 文件存储 | - | V1 本地存储V2 可扩展 MinIO/OSS |
[SRC-FEAT-017.3 技术选型]
### 2.3 系统依赖关系
```
外部系统依赖:
企业微信API ←→ auth 模块OAuth 换 userid
文件存储服务 ←→ knowledge 模块(上传/下载文件)
文档预览服务(可选) ←→ knowledge 模块(在线预览)
内部模块依赖方向(单向,禁止逆向调用):
training → knowledge引用知识内容、学习进度
training → exam引用考试通过状态
knowledge / exam / training → system查询用户/部门信息)
所有模块 → auth权限校验拦截器
```
---
## 3. 业务架构图
```mermaid
graph TD
subgraph 客户端
PC[PC浏览器<br>管理员/讲师]
WX[企业微信H5<br>学员]
MB[移动端浏览器<br>学员]
end
subgraph 后端服务
subgraph 网关层
GW[JWT认证 / 权限拦截 / 异常处理]
end
subgraph 业务域
AUTH[认证模块<br>auth]
SYS[系统管理<br>system]
KM[知识库模块<br>knowledge]
EX[考试模块<br>exam]
TR[培训模块<br>training]
end
end
subgraph 数据层
DB[(MySQL 8.0)]
FS[文件存储<br>本地/MinIO]
end
subgraph 外部服务
WXAPI[企业微信API]
PREVIEW[文档预览服务<br>可选]
end
PC --> GW
WX --> GW
MB --> GW
GW --> AUTH
GW --> SYS
GW --> KM
GW --> EX
GW --> TR
AUTH --> WXAPI
KM --> FS
KM --> PREVIEW
TR --> KM
TR --> EX
KM --> SYS
EX --> SYS
TR --> SYS
AUTH --> DB
SYS --> DB
KM --> DB
EX --> DB
TR --> DB
```
---
## 4. 核心业务流程说明
### 4.1 用户主流程(学员)
```mermaid
sequenceDiagram
participant 学员
participant 前端
participant 后端
participant 企业微信
学员->>前端: 点击企业微信登录
前端->>企业微信: 跳转 OAuth 授权
企业微信-->>前端: 返回 code
前端->>后端: code 换 Token
后端->>企业微信: code → userid
后端->>后端: 查 sys_user 匹配
alt 用户已录入
后端-->>前端: JWT Token + 用户信息
前端->>学员: 进入工作台
else 用户未录入
后端-->>前端: 错误:联系管理员
end
学员->>前端: 查看培训计划
前端->>后端: GET /api/student/training
后端-->>前端: 计划列表 + 进度
学员->>前端: 参加考试
前端->>后端: POST /api/student/exam/{id}/start
后端->>后端: 校验时间窗口 + 剩余次数
后端-->>前端: 试题 + 考试时长
学员->>前端: 答题 + 交卷
前端->>后端: POST /api/student/exam/{id}/submit
后端->>后端: 自动判分
后端-->>前端: 成绩 + 排名 + 答案解析
```
### 4.2 管理流程(讲师)
```mermaid
flowchart LR
A[上传知识<br>DRAFT] --> B[发布知识<br>PUBLISHED]
B --> C{有培训计划?}
C -->|是| D[关联到培训计划]
C -->|否| E[学员自由学习]
F[创建题目<br>DRAFT] --> G[发布题目<br>PUBLISHED]
G --> H[组卷<br>手动/自动]
H --> I[发布试卷<br>PUBLISHED]
I --> J[创建考试<br>设置时间/次数]
J --> K[指定考试对象<br>部门/小组/个人]
D --> L[创建培训计划]
J --> L
L --> M[分配学员<br>部门/小组/个人]
M --> N[发布培训计划]
```
### 4.3 数据流转流程
```mermaid
flowchart TB
subgraph 内容生产
KM_CREATE[知识创建<br>km_knowledge DRAFT]
KM_PUBLISH[发布知识<br>PUBLISHED]
QS_CREATE[题目创建<br>ex_question DRAFT]
QS_PUBLISH[发布题目<br>PUBLISHED]
PP_CREATE[组卷<br>ex_paper + ex_paper_question]
EX_CREATE[创建考试<br>ex_exam + ex_exam_target]
TR_CREATE[培训计划<br>tr_plan + tr_plan_knowledge<br>+ tr_plan_exam + tr_plan_target]
end
subgraph 学员消费
LEARN[学习知识<br>→ km_knowledge_progress UPSERT]
EXAM[参加考试<br>→ ex_exam_record 创建/更新]
PROGRESS[进度计算<br>必修知识完成数 + 必考通过数]
end
KM_CREATE --> KM_PUBLISH --> LEARN
QS_CREATE --> QS_PUBLISH --> PP_CREATE --> EX_CREATE --> EXAM
TR_CREATE --> LEARN
TR_CREATE --> EXAM
LEARN --> PROGRESS
EXAM --> PROGRESS
```
---
## 5. 数据架构
### 5.1 核心数据实体共19张表
[SRC-SQL-01] [SRC-SQL-02]
| 数据域 | 表名 | 核心字段 | 说明 |
|-------|------|---------|------|
| **系统** | sys_center | id, name | 中心(最高层级) |
| **系统** | sys_department | id, name, center_id | 部门(隶属中心) |
| **系统** | sys_group | id, name, department_id | 小组(隶属部门) |
| **系统** | sys_user | id, wx_userid, role(0/1/2), department_id, group_id, status | 用户ADMIN/LECTURER/STUDENT |
| **知识库** | km_category | id, name, parent_id, department_id | 知识分类(多级树) |
| **知识库** | km_knowledge | id, title, type(0文档/1视频), file_url, department_id, status(0/1/2) | 知识内容 |
| **知识库** | km_knowledge_progress | id, user_id, knowledge_id, status, progress, duration, video_position, source, plan_id | 学习进度 |
| **考试** | ex_question_category | id, name, parent_id, department_id | 题目分类 |
| **考试** | ex_question | id, type(0/1/2), content, options(JSON), answer, analysis, status | 题目 |
| **考试** | ex_paper | id, title, total_score, duration, pass_score, status | 试卷 |
| **考试** | ex_paper_question | paper_id, question_id, score, sort_order | 试卷-题目关联 |
| **考试** | ex_exam | id, title, paper_id, start_time, end_time, max_attempts, status(0/1/2) | 考试 |
| **考试** | ex_exam_target | exam_id, target_type(0部门/1小组/2个人), target_id | 考试对象 |
| **考试** | ex_exam_record | id, exam_id, user_id, attempt_no, score, passed, answers(JSON), status, version | 考试记录(含乐观锁) |
| **培训** | tr_plan | id, title, start_date, end_date, department_id, status(0/1/2) | 培训计划 |
| **培训** | tr_plan_knowledge | plan_id, knowledge_id, required, sort_order | 计划-知识关联 |
| **培训** | tr_plan_exam | plan_id, exam_id, required, sort_order | 计划-考试关联V1.0.1 |
| **培训** | tr_plan_target | plan_id, target_type, target_id | 计划-对象 |
| **培训** | tr_plan_progress | plan_id, user_id, knowledge_id, completed, complete_time | 旧版进度(已被 km_knowledge_progress 替代)|
### 5.2 实体关系图
```mermaid
erDiagram
sys_center ||--o{ sys_department : "中心下辖多个部门"
sys_department ||--o{ sys_group : "部门下辖多个小组"
sys_department ||--o{ sys_user : "用户属于部门"
sys_group ||--o{ sys_user : "用户可归属小组"
sys_department ||--o{ km_category : "按部门隔离"
km_category ||--o{ km_knowledge : "知识归属分类"
sys_user ||--o{ km_knowledge_progress : "学员学习进度"
km_knowledge ||--o{ km_knowledge_progress : "知识对应进度"
sys_department ||--o{ ex_question_category : "按部门隔离"
ex_question_category ||--o{ ex_question : "题目归属分类"
ex_paper ||--o{ ex_paper_question : "试卷包含多道题"
ex_question ||--o{ ex_paper_question : "题目被多张试卷引用"
ex_paper ||--|| ex_exam : "考试使用某试卷"
ex_exam ||--o{ ex_exam_target : "考试指定对象"
ex_exam ||--o{ ex_exam_record : "考试产生记录"
sys_user ||--o{ ex_exam_record : "学员的考试记录"
tr_plan ||--o{ tr_plan_knowledge : "计划包含多个知识"
tr_plan ||--o{ tr_plan_exam : "计划关联多场考试"
tr_plan ||--o{ tr_plan_target : "计划分配给对象"
km_knowledge ||--o{ tr_plan_knowledge : "知识被计划引用"
ex_exam ||--o{ tr_plan_exam : "考试被计划引用"
```
### 5.3 数据生命周期
| 数据类型 | 创建 | 有效态 | 失效态 | 删除方式 |
|---------|------|-------|-------|---------|
| 知识/题目/试卷 | DRAFT | PUBLISHED | OFFLINE | 逻辑删除deleted=1 |
| 考试 | NOT_STARTED | IN_PROGRESS | ENDED | 逻辑删除 |
| 培训计划 | NOT_STARTED | IN_PROGRESS | ENDED | 逻辑删除 |
| 考试记录 | IN_PROGRESS | SUBMITTED | 永久保留(取最高分) | 不删除 |
| 学习进度 | NOT_STARTED | IN_PROGRESS | COMPLETED | UPSERT更新 |
---
## 6. 权限与角色体系
### 6.1 角色定义
[SRC-FEAT-014.1 权限规则] [SRC-SQL-01sys_user.role]
| 角色 | 枚举值DB | 数据范围 |
|------|------------|---------|
| 管理员 ADMIN | role=0 | 全平台(无部门隔离) |
| 讲师 LECTURER | role=1 | 本部门department_id匹配 |
| 学员 STUDENT | role=2 | 本部门(只读;自己的进度/成绩) |
### 6.2 权限分层(按功能菜单)
| 菜单/功能 | ADMIN | LECTURER | STUDENT |
|---------|-------|---------|---------|
| 组织架构管理 | ✅ 全部 | ❌ | ❌ |
| 员工管理 | ✅ 全部 | 👁️ 本部门只读 | ❌ |
| 知识库-分类管理 | ✅ 全部 | ✅ 本部门 | ❌ |
| 知识库-知识列表 | ✅ 全部 | ✅ 本部门(含草稿) | 👁️ 本部门已发布 |
| 考题管理-题库分类 | ✅ | ✅ 本部门 | ❌ |
| 考题管理-题目列表 | ✅ | ✅ 本部门 | ❌ |
| 试卷管理 | ✅ | ✅ 本部门 | ❌ |
| 考试管理 | ✅ | ✅ 本部门发布 | 👁️ 我的考试 |
| 培训计划 | ✅ | ✅ 本部门创建/管理 | 👁️ 我的培训 |
| 系统设置 | ✅ | ❌ | ❌ |
| 工作台 | ✅ | ✅ | ✅(学员视图) |
[SRC-FEAT-018.1 角色菜单权限对照表]
### 6.3 控制逻辑
**认证层**JWT Token 携带 userId + role每次请求由 AuthInterceptor 解析验证。[SRC-CODE-01common/interceptor/AuthInterceptor.java]
**授权层**
- 接口级:`@PreAuthorize` / SecurityConfig 按角色匹配路径(`/api/student/**` 仅 STUDENT
- 数据级Service 层注入 `department_id` 过滤,讲师/学员查询一律追加 `WHERE department_id = ?`
**隔离规则**
- 4类数据知识库、题库、试卷/考试、培训计划)均按 `department_id` 隔离
- 管理员不注入部门过滤,讲师注入本部门,学员额外限制只查 PUBLISHED 状态
---
## 7. 系统扩展点分析
### 7.1 可扩展模块
| 扩展点 | 当前状态 | V2+ 扩展方向 |
|-------|---------|------------|
| 文件存储 | 本地文件系统 | 抽象 `FileStorageService` 接口 → MinIO/OSS 实现切换 |
| 认证方式 | 企业微信 OAuth账号密码作备选 | 可接入 SSO/LDAP |
| 定时任务 | Spring @Scheduled(单机) | 可替换为 XXL-Job/SchedulerX 支持集群 |
| 统计报表 | 无V2规划 | 新增 `statistics` 模块,不影响现有模块 |
| 通知 | 无V2规划 | 可插入企业微信消息推送 |
### 7.2 可插拔能力
- **文档预览**kkFileView / OnlyOffice 作为可选外部服务knowledge 模块通过 URL 调用,可随时替换
- **视频播放器**video.js 为前端组件,与后端解耦,可替换
- **批量导入**EasyExcel 依赖已选型,可随时为题目/用户管理添加 Excel 导入功能
### 7.3 易变业务点
| 易变点 | 变化方向 | 影响范围 |
|-------|---------|---------|
| 培训完成判定逻辑(当前:必修知识+必考通过) | V2 可能增加签到、线下课时 | `TrainingProgressService.calculateProgress()` |
| 知识学习完成判定视频90%/文档时长) | 可能改为100%或按章节 | `KnowledgeLearningService.isCompleted()` |
| 考试排名计算口径(当前:最高分排名 DENSE_RANK | 可能改为平均分/最后一次 | SQL窗口函数需同步修改 |
| 组织架构层级(当前:中心→部门→小组三级) | 可能增减层级 | system 模块全面影响 |

View File

@@ -0,0 +1,105 @@
# 系统能力模型总结 — 道路救援企业培训系统
> 版本V1.0 | 生成日期2026-04-07
> 证据来源:[SRC-FEAT-01] [SRC-API-01] [SRC-CODE-01]
---
## 1. 当前系统具备的核心能力
| # | 能力名称 | 一句话描述 |
|---|---------|----------|
| C1 | **基于角色的访问控制RBAC** | 三种角色(管理员/讲师/学员)+ 部门级数据隔离,统一鉴权入口 |
| C2 | **组织与人员管理** | 三级组织结构(中心→部门→小组)+ 用户生命周期管理 |
| C3 | **知识资产管理** | 支持文档/视频两种类型的知识内容创建、状态发布和多级分类 |
| C4 | **学习行为跟踪** | 防刷机制下的真实时长累计和进度记录视频90%/文档时长判定) |
| C5 | **在线考核** | 题库管理 + 手动/自动组卷 + 在线答题 + 客观题自动判分 |
| C6 | **考试行为管控** | 时间窗口约束 + 次数限制 + 超时自动交卷 + 并发乐观锁保护 |
| C7 | **培训任务编排** | 将知识+考试组织成有时间周期的培训计划,支持必修/选修/必考/选考四维属性 |
| C8 | **培训进度可视化** | 实时计算学员对某培训计划的完成百分比(必修完成+必考通过) |
| C9 | **成绩与排名** | 交卷后立即返回成绩+答案解析+实时排名(窗口函数,同分按时间早优先) |
| C10 | **企业微信身份集成** | OAuth 登录打通企业微信用户体系,无需单独注册 |
---
## 2. 能力依赖关系图
```mermaid
graph TD
C10[C10 企业微信身份集成] --> C1
C1[C1 RBAC + 部门隔离] --> C2
C1 --> C3
C1 --> C5
C1 --> C7
C2[C2 组织人员管理] --> C7
C3[C3 知识资产管理] --> C4
C3 --> C7
C4[C4 学习行为跟踪] --> C8
C5[C5 在线考核] --> C6
C5 --> C9
C6[C6 考试行为管控] --> C9
C9[C9 成绩与排名] --> C8
C7[C7 培训任务编排] --> C4
C7 --> C6
C7 --> C8[C8 培训进度可视化]
```
---
## 3. 可复用能力清单
| 能力 | 复用场景 | 复用方式 |
|-----|---------|---------|
| C1 RBAC + 部门隔离 | 企业内任何需要角色权限 + 数据隔离的系统 | 提取 AuthInterceptor + UserContext + department_id 注入框架 |
| C4 学习行为跟踪 | 其他类型内容(音频/直播回放/课件)的学习进度记录 | 抽象 `LearningTarget` 接口替换完成判定策略Strategy 模式) |
| C5 在线考核 | 任意客观题在线测评场景(安全培训/合规考试等)| 题库+试卷+客观题判分为独立子系统,可独立部署 |
| C6 考试行为管控 | 任何有"限时+限次"约束的在线测试 | ExamTakingService 中时间窗口/次数/乐观锁的组合控制逻辑 |
| C9 成绩排名 | 任何需要实时排名的比赛/评测场景 | SQL 窗口函数 DENSE_RANK 模式,按需修改排序条件 |
---
## 4. 平台级能力(多业务依赖的底层能力)
**C1 — RBAC + 部门数据隔离**
- 所有业务模块(知识/考试/培训)均依赖此能力实现权限控制和数据隔离
- 是系统安全性和多租户(多部门)能力的基础
- 扩展方向目前硬编码三个角色V2 可改为动态角色配置
**C2 — 组织人员管理**
- 每个业务操作都需要 `department_id``user_id``role` 三个属性
- 是知识/考试/培训三大域的数据隔离依据来源
- 扩展方向:当前三级固定结构,可抽象为 n 级通用树
**C10 — 企业微信身份集成**
- 是唯一的用户来源V1后续接其他身份源也需通过此层
- 扩展方向:抽象为 `IdentityProvider` 接口,支持插入 SSO/LDAP
---
## 5. 业务定制能力(特定场景才需要的能力)
| 能力 | 定制场景 | 为何不是平台级 |
|-----|---------|-------------|
| C3 知识资产管理(文档/视频类型) | 救援行业的操作手册、安全规范、视频讲解 | 内容类型固定(文档/视频),换行业可能需要不同类型 |
| C4 学习行为防刷视频90%/文档时长) | 强制"真实学习"的企业培训场景 | 完成判定规则是业务决策C端平台通常不这么严格 |
| C6 超时自动交卷 + 乐观锁 | 有严格时长限制的考试 | 休闲测试/知识问答类应用不需要这个复杂度 |
| C7 培训任务编排(必修/选修/必考/选考四维)| 企业有组织要求的培训管理 | 自学平台不需要"强制必修"的约束 |
| C9 成绩排名DENSE_RANK + 同分按时间) | 部门内部考核的绩效排名 | 无竞争性考核场景(如自我测评)不需要排名 |
---
## 6. V2 能力规划缺口
当前 V1.0.1 尚未具备以下能力,是 V2 的扩展方向:
| 缺失能力 | 业务价值 | 实现复杂度 |
|---------|---------|---------|
| 统计报表中心(完成率/通过率/部门排名) | 管理层查看全局培训效果 | 中(新增 statistics 模块,读现有数据) |
| 线下培训签到(扫码签到/签退) | 线上线下混合培训场景 | 中(需硬件支持) |
| 错题本(自动归集错误题目) | 学员针对性复习 | 低(从 exam_record.answers 中提取 correct=false |
| 知识全文搜索 | 快速查找内容 | 高(需引入 Elasticsearch 或 MySQL FULLTEXT |
| 奖励体系(积分/勋章/排行榜) | 提升学习积极性 | 中(新增独立模块) |
| 证书管理 | 培训完成凭证 | 低(基于培训计划完成状态生成 PDF |

View File

@@ -0,0 +1,110 @@
# 认证模块auth
> 证据来源:[SRC-FEAT-01] [SRC-API-01] [SRC-CODE-01module/auth/]
---
## 1. 模块定位
- **模块目标**负责用户身份验证企业微信OAuth + 账号密码备选)和 JWT Token 的签发、校验,为所有其他模块提供鉴权基础。
- **解决问题**500人规模的企业内部系统需要统一身份验证入口并将身份与角色绑定为下游数据隔离提供 `userId + role + departmentId` 上下文。
---
## 2. 功能清单
[SRC-API-01四、API 接口设计 / SRC-CODE-01module/auth/]
| 功能名称 | 功能描述 | 输入 | 输出 | 依赖模块 |
|---------|---------|------|------|---------|
| 企业微信 OAuth 登录 | 通过企业微信授权 code 换取用户身份,查找系统用户,签发 JWT | wx_code | JWT Token + 用户信息LoginResponse | system查sys_user |
| 账号密码登录(备选) | 用用户名+密码登录BCrypt 验证密码 | username, password | JWT Token + 用户信息 | system查sys_user |
| 获取当前用户信息 | 解析 Token 返回用户基本信息 | Authorization Header | UserInfoResponse | - |
| 微信小程序登录(预留) | 通过小程序 code 获取用户信息 | WechatLoginRequest | JWT Token | system |
| Token 携带与拦截 | AuthInterceptor 拦截所有受保护请求,提取 Token 注入 UserContext | Authorization: Bearer {token} | UserContextThreadLocal | - |
---
## 3. 核心逻辑
### 3.1 业务规则
- 企业微信登录路径:前端传 code → 后端调 weixin-java-cp SDK 换 `access_token` → 获取 `wx_userid` → 查 `sys_user.wx_userid` 匹配 → 用户不存在则返回错误(不自动注册)[SRC-FEAT-01]
- JWT Payload 包含userId、role、departmentId有效期由配置决定
- 密码存储BCrypt 加密Spring Security 6.x初始管理员密码 `admin123` 已预置 [SRC-SQL-015.4]
### 3.2 校验逻辑
| 校验项 | 规则 | 失败响应 |
|-------|------|---------|
| wx_userid 是否存在于 sys_user | 必须已由管理员录入 | 返回错误:用户未录入,请联系管理员 |
| sys_user.status | 必须为 0启用 | 返回错误:账号已禁用 |
| Token 有效性 | 未过期、签名正确 | 返回 401 |
| 受保护接口 Token 缺失 | 无 Authorization Header | 返回 401 |
### 3.3 状态流转
```mermaid
stateDiagram-v2
[*] --> 未认证
未认证 --> 已认证 : 登录成功JWT签发
已认证 --> 未认证 : Token过期 / 主动登出
已认证 --> 已认证 : Token续期如有配置
```
---
## 4. 数据结构
### 4.1 涉及数据表
**sys_user**(读取,不由本模块创建)[SRC-SQL-01]
| 字段 | 类型 | 说明 |
|------|------|------|
| id | BIGINT | 用户主键 |
| wx_userid | VARCHAR(100) | 企业微信用户ID唯一索引 uk_wx_userid |
| username | VARCHAR(50) | 账号密码登录用账号(唯一索引 uk_username |
| password | VARCHAR(100) | BCrypt加密密码 |
| role | TINYINT | 0-管理员 / 1-讲师 / 2-学员 |
| department_id | BIGINT | 所属部门ID会注入 JWT Payload |
| status | TINYINT | 0-启用 / 1-禁用 |
### 4.2 DTO/VO 定义
[SRC-CODE-01module/auth/dto/]
| 类名 | 方向 | 关键字段 |
|------|------|---------|
| LoginRequest | 入参 | username, password |
| WechatLoginRequest | 入参 | code企业微信授权码 |
| LoginResponse | 出参 | token, userId, realName, role, departmentId |
| UserInfoResponse | 出参 | 同 LoginResponse从 Token 解析) |
---
## 5. 对外接口
[SRC-API-01]
| API 名称 | 方法 | 路径 | 权限 |
|---------|------|------|------|
| 企业微信登录 | POST | /api/auth/wechat/login | 公开 |
| 账号密码登录 | POST | /api/auth/login | 公开 |
| 获取当前用户 | GET | /api/auth/me | 需 Token |
**事件机制**登录成功后UserContextThreadLocal持有用户信息供同请求链路的所有 Service 使用,请求结束后清除。[SRC-CODE-01common/context/UserContextHolder.java]
---
## 6. 异常与边界处理
| 场景 | 处理方式 |
|------|---------|
| 企业微信 API 调用超时/失败 | 返回 503提示"企业微信服务暂时不可用,请稍后重试" |
| 企业微信 code 已使用(重放) | 企业微信 SDK 返回错误,转化为 400 |
| 用户 wx_userid 存在但账号被禁用status=1 | 返回 403提示"账号已禁用,请联系管理员" |
| sys_user 中无对应 wx_userid | 返回 403提示"用户未录入系统,请联系管理员" |
| Token 格式错误非JWT | AuthInterceptor 捕获,返回 401 |
| Token 过期 | AuthInterceptor 捕获,返回 401前端跳转登录页 |
| 并发登录(同一账号多端) | 当前设计无限制,多端独立 Token 有效 |

View File

@@ -0,0 +1,165 @@
# 系统管理模块system
> 证据来源:[SRC-FEAT-01] [SRC-SQL-01] [SRC-CODE-01module/system/]
---
## 1. 模块定位
- **模块目标**:管理企业的组织架构(中心→部门→小组三级)和用户生命周期(录入、角色分配、状态管理),为所有业务模块的部门数据隔离提供基础。
- **解决问题**3-5名管理员管理约500人的组织结构人员分配到正确部门和角色是知识库/考试/培训数据隔离的前置条件。
---
## 2. 功能清单
[SRC-FEAT-01模块一] [SRC-CODE-01module/system/]
| 功能名称 | 功能描述 | 输入 | 输出 | 依赖模块 |
|---------|---------|------|------|---------|
| 中心管理CRUD | 创建/修改/删除最高级组织单元"中心" | CenterDTOname, sort_order | CenterVO | - |
| 部门管理CRUD | 在中心下创建/修改/删除部门每中心最多8个部门 | DepartmentDTOname, center_id | DepartmentVO | - |
| 小组管理CRUD | 在部门下创建/修改/删除小组每部门最多10个小组 | GroupDTOname, department_id | GroupVO | - |
| 组织树查询 | 一次性返回完整组织树(中心→部门→小组层级) | - | OrgTreeVO树形结构 | - |
| 员工列表查询 | 分页查询员工,支持按部门/角色/姓名筛选 | UserQueryDTO | PageResult<UserVO> | - |
| 员工录入 | 管理员手动录入员工信息,绑定企业微信 userid | UserDTOwx_userid, real_name, role, department_id… | UserVO | - |
| 员工信息修改 | 修改员工姓名、部门、角色、小组归属 | UserDTO | UserVO | - |
| 员工禁用/启用 | 切换员工账号状态0启用/1禁用 | userId, status | - | auth下次登录校验 |
| 密码重置 | 管理员重置员工的账号密码BCrypt | PasswordDTOuserId, newPassword | - | auth |
| 讲师查看本部门员工 | 讲师可查看本部门员工列表(只读,无编辑权限) | department_id从Token注入 | PageResult<UserVO> | auth |
---
## 3. 核心逻辑
### 3.1 业务规则
[SRC-FEAT-01模块一]
- **层级约束**:中心 → 部门一个中心最多8个部门→ 小组一个部门最多10个小组超限不允许创建
- **角色约束**:用户角色只能为 ADMIN(0) / LECTURER(1) / STUDENT(2) 三种,创建时必填
- **部门归属**LECTURER 和 STUDENT 必须归属某部门department_id 不可为空ADMIN 可无部门
- **逻辑删除**:所有实体使用 `deleted=1` 软删除,禁止物理删除,防止外键依赖失效
- **员工录入方式**V1 仅支持管理员手动逐条录入不支持批量导入V2 规划 EasyExcel 导入)
### 3.2 校验逻辑
| 校验项 | 规则 | 失败响应 |
|-------|------|---------|
| 部门数量上限 | 同一 center_id 下 deleted=0 的部门数 ≤ 8 | 400该中心部门数已达上限(8个) |
| 小组数量上限 | 同一 department_id 下 deleted=0 的小组数 ≤ 10 | 400该部门小组数已达上限(10个) |
| wx_userid 唯一 | sys_user.wx_userid 全局唯一uk_wx_userid 索引) | 400该企业微信账号已录入 |
| username 唯一 | sys_user.username 全局唯一uk_username 索引) | 400用户名已存在 |
| 讲师数据隔离 | LECTURER 调用员工列表时,强制追加 department_id = 当前用户部门 | 自动过滤,不报错 |
| 删除有子项的上级 | 删除中心前,其下所有部门必须已删除;删除部门前,其下所有小组和用户必须已处理 | 400请先删除部门下的小组和员工 |
### 3.3 状态流转
```mermaid
stateDiagram-v2
[*] --> 启用 : 员工录入时默认 status=0
启用 --> 禁用 : 管理员操作禁用
禁用 --> 启用 : 管理员操作启用
禁用 --> 已删除 : 逻辑删除deleted=1
启用 --> 已删除 : 逻辑删除deleted=1
```
---
## 4. 数据结构
[SRC-SQL-01一、系统管理模块]
### 4.1 涉及数据表
**sys_center**
| 字段 | 类型 | 说明 |
|------|------|------|
| id | BIGINT | 主键 |
| name | VARCHAR(100) | 中心名称 |
| sort_order | INT DEFAULT 0 | 排序 |
| deleted | TINYINT | 逻辑删除0/1 |
**sys_department**
| 字段 | 类型 | 说明 |
|------|------|------|
| id | BIGINT | 主键 |
| name | VARCHAR(100) | 部门名称 |
| center_id | BIGINT NOT NULL | 所属中心idx_center_id 索引) |
| sort_order | INT | 排序 |
| deleted | TINYINT | 逻辑删除 |
**sys_group**
| 字段 | 类型 | 说明 |
|------|------|------|
| id | BIGINT | 主键 |
| name | VARCHAR(100) | 小组名称 |
| department_id | BIGINT NOT NULL | 所属部门idx_department_id 索引) |
| sort_order | INT | 排序 |
| deleted | TINYINT | 逻辑删除 |
**sys_user**
| 字段 | 类型 | 说明 |
|------|------|------|
| id | BIGINT | 主键 |
| wx_userid | VARCHAR(100) | 企业微信 userid唯一 |
| username | VARCHAR(50) NOT NULL | 账号(唯一) |
| password | VARCHAR(100) | BCrypt 加密密码 |
| real_name | VARCHAR(50) NOT NULL | 真实姓名 |
| phone | VARCHAR(20) | 手机号 |
| avatar | VARCHAR(255) | 头像 URL |
| role | TINYINT NOT NULL | 0-管理员 / 1-讲师 / 2-学员 |
| department_id | BIGINT | 所属部门可空ADMIN 用) |
| group_id | BIGINT | 所属小组(可空) |
| status | TINYINT DEFAULT 0 | 0-启用 / 1-禁用 |
| deleted | TINYINT | 逻辑删除 |
### 4.2 数据关联
- `sys_user.department_id``sys_department.id`(无外键约束,逻辑关联)
- `sys_user.group_id``sys_group.id`(可空)
- `sys_department.center_id``sys_center.id`
---
## 5. 对外接口
[SRC-CODE-01module/system/controller/]
| API 名称 | 方法 | 路径 | 权限 |
|---------|------|------|------|
| 获取组织树 | GET | /api/system/org/tree | ADMIN |
| 查询中心列表 | GET | /api/system/center | ADMIN |
| 创建中心 | POST | /api/system/center | ADMIN |
| 修改中心 | PUT | /api/system/center/{id} | ADMIN |
| 删除中心 | DELETE | /api/system/center/{id} | ADMIN |
| 查询部门列表 | GET | /api/system/department | ADMIN |
| 创建部门 | POST | /api/system/department | ADMIN |
| 修改部门 | PUT | /api/system/department/{id} | ADMIN |
| 删除部门 | DELETE | /api/system/department/{id} | ADMIN |
| 查询小组列表 | GET | /api/system/group | ADMIN |
| 创建小组 | POST | /api/system/group | ADMIN |
| 修改小组 | PUT | /api/system/group/{id} | ADMIN |
| 删除小组 | DELETE | /api/system/group/{id} | ADMIN |
| 查询员工列表 | GET | /api/system/user | ADMIN(全部) / LECTURER(本部门只读) |
| 创建员工 | POST | /api/system/user | ADMIN |
| 修改员工 | PUT | /api/system/user/{id} | ADMIN |
| 禁用/启用员工 | PUT | /api/system/user/{id}/status | ADMIN |
| 重置密码 | PUT | /api/system/user/{id}/password | ADMIN |
---
## 6. 异常与边界处理
| 场景 | 处理方式 |
|------|---------|
| 删除有下级的中心/部门 | 校验子项是否全部删除,否则返回 400 + 提示 |
| 部门/小组数量超限 | 严格校验上限8/10超出返回 400 |
| 员工 wx_userid 重复 | 唯一索引捕获 DuplicateKeyException友好提示 |
| LECTURER 访问其他部门员工 | AuthInterceptor / Service 层强制 department_id 过滤,返回空列表 |
| 管理员误操作禁用自己 | [ASSUMPTION] PRD 未明确说明是否限制,建议禁止禁用最后一个 ADMIN |
| 员工转移部门 | 修改 department_id 即可,但其历史知识进度/考试记录中的 department_id 为冗余字段不随之更新 |

View File

@@ -0,0 +1,205 @@
# 知识库模块knowledge
> 证据来源:[SRC-FEAT-01] [SRC-FEAT-02] [SRC-SQL-01] [SRC-SQL-02] [SRC-API-01] [SRC-CODE-01module/knowledge/]
---
## 1. 模块定位
- **模块目标**:管理企业的结构化知识资产,支持文档和视频两种内容类型的上传、分类管理、状态发布,并记录学员的个人学习进度。
- **解决问题**:解决救援知识依赖口口相传的问题;同时为培训计划提供可引用的学习内容,并跟踪学员是否真实完成学习(防刷机制)。
---
## 2. 功能清单
[SRC-FEAT-01模块二] [SRC-FEAT-023.2 知识学习]
| 功能名称 | 功能描述 | 输入 | 输出 | 依赖模块 |
|---------|---------|------|------|---------|
| 知识分类管理 | 创建/修改/删除多级分类树,按部门隔离 | CategoryDTOname, parent_id, department_id | CategoryVO | system部门 |
| 知识分类树查询 | 返回树形结构的分类目录 | department_id | List<CategoryVO>(树) | - |
| 知识内容 CRUD | 创建/修改/删除知识(文档/视频),状态为草稿时可修改 | KnowledgeDTOtitle, type, file_url, category_id… | KnowledgeVO | system |
| 文件上传 | 上传 PDF/Word/Excel/PPT/视频文件,返回文件 URL | MultipartFile | FileDTOurl, fileName, size, type | 文件存储服务 |
| 知识发布/下架 | 变更知识状态(草稿→发布/发布→下架/下架→再发布)| knowledgeId, action | - | - |
| 知识列表查询(讲师端) | 管理端分页查询,可查所有状态,含草稿 | KnowledgeQueryDTOcategory_id, status, keyword | PageResult<KnowledgeVO> | - |
| 知识列表查询(学员端) | 只查 PUBLISHED 状态,携带个人学习状态 | department_id, KnowledgeQueryDTO | PageResult<KnowledgeVO + 学习状态> | auth |
| 知识在线预览 | 文档在线预览PDF/Word等、视频在线播放 | knowledgeId | 文件 URL / 预览链接 | 文件存储/文档预览服务 |
| 开始学习 | 创建或获取学习进度记录,记录首次学习时间 | knowledgeId, [source, planId] | - | auth |
| 更新学习进度 | 定时上报学习进度每60秒累加时长判断完成 | ProgressUpdateDTOduration, progress, videoPosition, source, planId | - | training若来源=TRAINING |
| 完成学习 | 前端显式标记完成(文档)| knowledgeId | - | - |
| 查询学习进度 | 查询学员对某知识/某批知识的学习状态 | userId/knowledgeIds | List<KnowledgeProgressVO> | - |
| 引用保护检查 | 检查知识是否被培训计划引用,下架前警告 | knowledgeId | Boolean + 引用计划数 | training |
---
## 3. 核心逻辑
### 3.1 业务规则
[SRC-FEAT-014.5 引用保护规则] [SRC-API-015.1 学习进度更新流程]
**内容状态规则**
- 草稿DRAFT=0只有讲师和管理员可见可自由修改
- 已发布PUBLISHED=1全部门学员可见处于此状态时不可修改内容需先下架
- 已下架OFFLINE=2学员不可见可重新上架或继续修改后再发布
**学习进度完成判定规则**
- **视频类**:播放进度 ≥ 90% 时status 自动变更为 COMPLETED
- **文档类**:累计学习时长 ≥ 预估阅读时间(按文件大小估算,具体算法在 `calculateEstimatedTime()`status 变更为 COMPLETED
- 两种类型均支持多次学习,完成后不会重置;时长可继续累加
**防刷机制(活跃检测)**
- 前端 ActivityDetector 监听 mousemove/click/scroll/keypress 事件
- 60秒无活动判定为非活跃停止本地计时器不上报进度
- 恢复活跃后重新计时
**多标签页防重**
- BroadcastChannel API 实现:同一知识在多个 Tab 打开时,检测到重复后关闭后来的 Tab [SRC-API-016.2]
**部门数据隔离**
- 所有知识查询一律追加 `WHERE department_id = [当前用户部门]`
- 分类也按 department_id 隔离
**引用保护**
- 知识下架前,需检查 `tr_plan_knowledge` 中是否有关联;若有,提示警告,用户确认后方可下架
### 3.2 校验逻辑
| 校验项 | 规则 | 失败响应 |
|-------|------|---------|
| 文件类型 | 文档PDF/Word/Excel/PPT视频MP4等常见格式 | 400不支持的文件格式 |
| 文件大小 | [ASSUMPTION] PRD 提及限制大文件,具体上限需配置,建议文档 ≤100MB视频 ≤2GB | 400文件超出大小限制 |
| 知识状态变更 | PUBLISHED 状态下不允许修改内容字段(标题/文件),只允许下架操作 | 400已发布知识不可修改请先下架 |
| 学习进度上报频率 | 前端每60秒上报一次后端不做频率限制允许补报 | - |
| 视频播放进度合理性 | `video_position ≤ 视频总时长`[ASSUMPTION] 后端当前未做服务端校验PRD 明确属于风险项) | 暂无服务端拦截 |
| 分类隶属 | 知识的 category_id 必须属于同一 department_id 的分类 | 400分类不存在或无权限 |
### 3.3 状态流转
```mermaid
stateDiagram-v2
[*] --> DRAFT : 创建知识(可新增/修改/删除)
DRAFT --> PUBLISHED : 讲师发布
PUBLISHED --> OFFLINE : 讲师下架(引用警告确认)
OFFLINE --> PUBLISHED : 讲师重新上架
OFFLINE --> DRAFT : 重新编辑后回到草稿 [ASSUMPTION]
DRAFT --> [*] : 逻辑删除
note right of PUBLISHED : 学员可见\n不可修改内容
note right of DRAFT : 仅讲师/管理员可见
note right of OFFLINE : 学员不可见\n可编辑
```
**学习进度状态流转**
```mermaid
stateDiagram-v2
[*] --> NOT_STARTED : 知识发布,学员尚未打开
NOT_STARTED --> IN_PROGRESS : 调用"开始学习"接口
IN_PROGRESS --> IN_PROGRESS : 每次上报进度(时长累加)
IN_PROGRESS --> COMPLETED : 视频≥90% 或 文档时长达标
COMPLETED --> IN_PROGRESS : 再次学习(时长继续累加,状态不回退)
```
---
## 4. 数据结构
[SRC-SQL-01二、知识库模块] [SRC-SQL-02]
### 4.1 涉及数据表
**km_category**
| 字段 | 类型 | 说明 |
|------|------|------|
| id | BIGINT | 主键 |
| name | VARCHAR(100) NOT NULL | 分类名称 |
| parent_id | BIGINT DEFAULT 0 | 父分类0=顶级) |
| department_id | BIGINT NOT NULL | 所属部门(部门隔离键) |
| sort_order | INT | 排序 |
| deleted | TINYINT | 逻辑删除 |
**km_knowledge**
| 字段 | 类型 | 说明 |
|------|------|------|
| id | BIGINT | 主键 |
| title | VARCHAR(200) NOT NULL | 标题 |
| description | TEXT | 描述/摘要 |
| category_id | BIGINT | 所属分类(可空) |
| type | TINYINT NOT NULL | 0-文档 / 1-视频 |
| file_name | VARCHAR(255) | 文件名 |
| file_url | VARCHAR(500) | 文件 URL |
| file_size | BIGINT | 文件大小(字节) |
| file_type | VARCHAR(20) | 文件后缀pdf/mp4… |
| department_id | BIGINT NOT NULL | 所属部门(隔离键,有 idx |
| status | TINYINT DEFAULT 0 | 0-草稿 / 1-已发布 / 2-已下架 |
| creator_id | BIGINT NOT NULL | 创建人 |
| publish_time | DATETIME | 发布时间 |
| view_count | INT | 浏览次数 |
| deleted | TINYINT | 逻辑删除 |
**km_knowledge_progress**(学员学习进度)[SRC-SQL-02]
| 字段 | 类型 | 说明 |
|------|------|------|
| id | BIGINT | 主键 |
| user_id | BIGINT NOT NULL | 学员ID |
| knowledge_id | BIGINT NOT NULL | 知识ID |
| department_id | BIGINT NOT NULL | 部门(冗余,用于分区查询) |
| status | VARCHAR(20) | NOT_STARTED / IN_PROGRESS / COMPLETED |
| progress | INT | 进度百分比0~100 |
| duration | BIGINT | 累计学习时长(秒) |
| video_position | BIGINT | 视频播放位置(秒,仅视频) |
| source | VARCHAR(20) | FREE / TRAINING |
| plan_id | BIGINT | 关联培训计划source=TRAINING 时有值) |
| start_time | DATETIME | 首次学习时间 |
| complete_time | DATETIME | 完成时间 |
| 唯一约束 | uk_user_knowledge | (user_id, knowledge_id) 唯一 |
### 4.2 数据关联
- `km_knowledge.category_id``km_category.id`
- `km_knowledge.department_id` = `km_category.department_id`(同部门隔离)
- `km_knowledge_progress.user_id``sys_user.id`
- `km_knowledge_progress.plan_id``tr_plan.id`(可空)
---
## 5. 对外接口
[SRC-API-014.3 知识学习接口] [SRC-CODE-01module/knowledge/controller/]
| API 名称 | 方法 | 路径 | 权限 |
|---------|------|------|------|
| 查询知识分类树 | GET | /api/knowledge/category/tree | LECTURER/ADMIN |
| 创建分类 | POST | /api/knowledge/category | LECTURER/ADMIN |
| 修改分类 | PUT | /api/knowledge/category/{id} | LECTURER/ADMIN |
| 删除分类 | DELETE | /api/knowledge/category/{id} | LECTURER/ADMIN |
| 查询知识列表(管理端) | GET | /api/knowledge | LECTURER/ADMIN |
| 创建知识 | POST | /api/knowledge | LECTURER/ADMIN |
| 修改知识 | PUT | /api/knowledge/{id} | LECTURER/ADMIN |
| 发布/下架知识 | PUT | /api/knowledge/{id}/status | LECTURER/ADMIN |
| 删除知识 | DELETE | /api/knowledge/{id} | LECTURER/ADMIN |
| 文件上传 | POST | /api/knowledge/upload | LECTURER/ADMIN |
| 学员-知识列表 | GET | /api/student/knowledge | STUDENT |
| 学员-知识详情 | GET | /api/student/knowledge/{id} | STUDENT |
| 学员-开始学习 | POST | /api/student/knowledge/{id}/start | STUDENT |
| 学员-更新进度 | POST | /api/student/knowledge/{id}/progress | STUDENT |
| 学员-标记完成 | POST | /api/student/knowledge/{id}/complete | STUDENT |
---
## 6. 异常与边界处理
| 场景 | 处理方式 |
|------|---------|
| 已发布知识被下架,同时培训计划正引用 | 弹出确认警告,显示引用该知识的培训计划数量,用户确认后方可下架 |
| 文件上传失败(存储服务不可用) | 返回 503前端提示"文件上传失败,请稍后重试" |
| 学员学习已下架的知识(在培训计划中) | [ASSUMPTION] PRD 未明确,建议:关联进培训计划的知识下架后,学员仍可查看历史进度但不可重新打开 |
| km_knowledge_progress 并发 UPSERT同一学员多标签页 | 唯一约束 uk_user_knowledge 防止重复插入;多标签页同步由前端 BroadcastChannel 控制关闭重复 Tab |
| 视频播放中途退出 | 下次进入从 video_position 断点续播 |
| 学习进度上报时网络中断 | 前端重试后端幂等UPSERT 语义,重复上报取最大值或继续累加) |
| 分类下有知识时删除分类 | 检查该分类下是否有 deleted=0 的知识若有则拒绝400 请先移除分类下的知识 |

View File

@@ -0,0 +1,253 @@
# 考试模块exam
> 证据来源:[SRC-FEAT-01] [SRC-FEAT-02] [SRC-SQL-01] [SRC-API-01] [SRC-CODE-01module/exam/]
---
## 1. 模块定位
- **模块目标**:管理从出题到考试全链路:题目→试卷→考试→作答记录,支持在线作答、自动判分、成绩排名。
- **解决问题**:替代纸质考试,提升出卷效率(自动组卷),实现客观题自动判分,并对考试行为(时间窗口、次数限制、超时交卷)进行严格管控。
---
## 2. 功能清单
[SRC-FEAT-01模块三/四/五] [SRC-API-014.4 在线考试接口]
| 功能名称 | 功能描述 | 输入 | 输出 | 依赖模块 |
|---------|---------|------|------|---------|
| 题目分类管理 | 按分类管理题目,多级目录,按部门隔离 | QuestionCategoryDTO | QuestionCategoryVO | system |
| 题目 CRUD | 创建/修改/删除题目,支持单选/多选/判断三种题型,必须填写解析 | QuestionDTOtype, content, options, answer, analysis | QuestionVO | - |
| 题目状态管理 | 草稿→发布→下架,下架前检查引用 | questionId, action | - | - |
| 手动组卷 | 讲师从题库手动选题,配置每题分值 | PaperDTOtitle, questions[] | PaperVO | - |
| 自动组卷 | 按规则单选X题+多选Y题+判断Z题随机抽题 | AutoPaperDTO规则配置 | PaperVO | - |
| 试卷配置 | 设置总分、各题分值、考试时长、及格分 | PaperDTO | PaperVO | - |
| 试卷预览 | 组卷后预览试卷效果(随机题目顺序) | paperId | 完整试卷预览 | - |
| 试卷状态管理 | 草稿→发布→下架 | paperId, action | - | - |
| 创建考试 | 选择试卷,设置考试名称、时间窗口、最大次数 | ExamQueryDTO + ExamTarget | ExamVO | - |
| 指定考试对象 | 指定部门/小组/个人参加考试 | exam_id, target_type, target_id[] | - | system |
| 发布考试 | 将考试状态从 NOT_STARTED 转为 IN_PROGRESS时间到自动 | examId | - | - |
| 学员-我的考试列表 | 查询分配给当前学员的考试(在时间窗口内) | - | PageResult<ExamVO + 我的记录> | auth |
| 学员-开始考试 | 校验资格,创建 exam_record返回试题 | examId | 试题 + 时长 + recordId | - |
| 学员-断点续考 | 恢复进行中的考试记录,返回已保存答案 | examId | 试题 + 已保存答案 + 剩余时间 | - |
| 学员-保存答案 | 每30秒自动保存答案增量保存 | recordId, answers(JSON) | - | - |
| 学员-提交试卷 | 自动判分,保存成绩,返回排名+解析 | recordId, answers(JSON) | 成绩 + 排名 + 答案解析 | - |
| 超时自动交卷 | 定时任务每分钟扫描超时记录,系统代提交 | @Scheduled | - | - |
| 查看考试结果 | 查看某次考试的详细成绩和答案解析 | recordId | ExamResultVO | - |
| 成绩/排名查询 | 讲师查看某考试的所有学员成绩 | examId | PageResult<成绩列表> | - |
---
## 3. 核心逻辑
### 3.1 业务规则
[SRC-FEAT-014.3 考试规则] [SRC-API-015.2/5.3]
**题型规则**
- 单选题SINGLE=0options 为 JSON 数组answer 为单字母A/B/C/D
- 多选题MULTIPLE=1answer 为多字母组合(如"AB"/"BCD"),按字母排序存储
- 判断题JUDGE=2options 为空answer 为"T"(正确)或"F"(错误)
- 每道题必须填写 `analysis`(答案解析),否则不允许发布
**考试时间窗口**
- 只有在 `exam.start_time ≤ NOW() ≤ exam.end_time` 时,学员才能进入考试
- 考试到期后,`exam.status` 自动(或手动)变为 ENDED
**次数限制**
- 达到 `max_attempts` 后,学员不可再次开始考试
- 历史成绩取**最高分**作为最终成绩
- 每次考试创建 `exam_record.attempt_no = 历史次数 + 1`
**自动判分规则**
- 仅客观题(单选/多选/判断)自动判分
- 单选/判断:答案完全匹配得满分
- 多选:全部选项匹配(顺序无关)得满分;部分正确得 0 分V1 不分项给分)
- 总分 = 各题得分之和
**超时自动交卷**
- `@Scheduled(cron="0 */1 * * * ?")` 每分钟扫描
- 查询:`ex_exam_record.status=IN_PROGRESS``start_time + paper.duration 分钟 < NOW()`
- 使用乐观锁(`version` 字段)防止与用户主动交卷并发冲突 [SRC-API-015.2]
**排名计算**
- 计算时机:用户交卷后立即计算本次提交对应的排名
- 统计范围:同一 `exam_id` 下,所有 `status=SUBMITTED` 记录,取每用户最高分
- 排名规则:`DENSE_RANK() OVER (ORDER BY MAX(score) DESC, MIN(submit_time) ASC)`(同分按提交时间早排前)[SRC-API-015.3]
**题目顺序**
- 自动组卷时,返回给学员的题目顺序随机打乱(前端处理或后端随机返回)
### 3.2 校验逻辑
| 校验项 | 规则 | 失败响应 |
|-------|------|---------|
| 题目 analysis 必填 | 发布时 analysis 不可为空 | 400请填写答案解析后再发布 |
| 开始考试-时间窗口 | NOW() 在 [start_time, end_time] 范围内 | 400考试尚未开始 / 考试已结束 |
| 开始考试-次数限制 | 已有考试记录数 < max_attempts | 400已达到最大考试次数 |
| 开始考试-状态 | exam.status = IN_PROGRESS1 | 400状态不符 |
| 开始考试-进行中记录 | 若已有 IN_PROGRESS 记录返回续考而非新建 | 自动转入断点续考流程 |
| 答案格式 | 多选题答案字母需排序后匹配 | 自动处理不返回错误 |
| 超时交卷并发 | 乐观锁冲突时用户已提交忽略定时任务提交 | 静默忽略 OptimisticLockException |
| 试卷引用保护 | 已被考试引用的试卷下架前需确认警告 | 400 + 警告 + 引用考试数量 |
| 题目引用保护 | 已被试卷引用的题目下架前需确认警告 | 400 + 警告 + 引用试卷数量 |
### 3.3 状态流转
**内容状态(题目/试卷)**
```mermaid
stateDiagram-v2
[*] --> DRAFT : 创建
DRAFT --> PUBLISHED : 发布(题目需有 analysis
PUBLISHED --> OFFLINE : 下架(引用保护确认)
OFFLINE --> PUBLISHED : 重新上架
DRAFT --> [*] : 逻辑删除
```
**考试状态**
```mermaid
stateDiagram-v2
[*] --> NOT_STARTED : 创建考试start_time 未到)
NOT_STARTED --> IN_PROGRESS : 到达 start_time自动或手动
IN_PROGRESS --> ENDED : 到达 end_time自动或手动结束
ENDED --> [*] : 逻辑删除
```
**考试记录状态**
```mermaid
stateDiagram-v2
[*] --> IN_PROGRESS : 学员点击"开始考试"创建记录
IN_PROGRESS --> SUBMITTED : 学员交卷submit_source=USER
IN_PROGRESS --> SUBMITTED : 定时任务超时submit_source=SYSTEM_TIMEOUT
SUBMITTED --> [*] : 永久保留
```
---
## 4. 数据结构
[SRC-SQL-01考试模块]
### 4.1 涉及数据表7张
**ex_question_category**题目分类同知识库分类结构 department_id 隔离
**ex_question**
| 字段 | 类型 | 说明 |
|------|------|------|
| id | BIGINT | 主键 |
| type | TINYINT | 0-单选 / 1-多选 / 2-判断 |
| content | TEXT NOT NULL | 题干 |
| options | JSON | 选项数组判断题为 NULL |
| answer | VARCHAR(50) NOT NULL | 正确答案单选/判断单字母多选合并字母 |
| analysis | TEXT | 答案解析发布前必填 |
| category_id | BIGINT | 所属分类 |
| department_id | BIGINT NOT NULL | 部门隔离键 |
| status | TINYINT | 0-草稿 / 1-发布 / 2-下架 |
| creator_id | BIGINT NOT NULL | 创建人 |
**ex_paper**
| 字段 | 类型 | 说明 |
|------|------|------|
| id | BIGINT | 主键 |
| title | VARCHAR(200) NOT NULL | 试卷标题 |
| total_score | INT DEFAULT 100 | 总分 |
| duration | INT DEFAULT 60 | 考试时长分钟 |
| pass_score | INT DEFAULT 60 | 及格分 |
| department_id | BIGINT NOT NULL | 部门隔离键 |
| status | TINYINT | 0-草稿 / 1-发布 / 2-下架 |
**ex_paper_question**
| 字段 | 类型 | 说明 |
|------|------|------|
| paper_id | BIGINT NOT NULL | 试卷ID |
| question_id | BIGINT NOT NULL | 题目ID |
| score | INT DEFAULT 5 | 该题分值 |
| sort_order | INT | 排序大题号顺序 |
**ex_exam**
| 字段 | 类型 | 说明 |
|------|------|------|
| id | BIGINT | 主键 |
| title | VARCHAR(200) NOT NULL | 考试标题 |
| paper_id | BIGINT NOT NULL | 关联试卷 |
| start_time / end_time | DATETIME | 时间窗口 |
| max_attempts | INT DEFAULT 1 | 最大考试次数 |
| department_id | BIGINT NOT NULL | 部门隔离键 |
| status | TINYINT | 0-未开始 / 1-进行中 / 2-已结束 |
**ex_exam_target**
| 字段 | 类型 | 说明 |
|------|------|------|
| exam_id | BIGINT NOT NULL | 考试ID |
| target_type | TINYINT | 0-部门 / 1-小组 / 2-个人 |
| target_id | BIGINT NOT NULL | 对应 dept/group/user 的ID |
**ex_exam_record** V1.0.1 扩展字段
| 字段 | 类型 | 说明 |
|------|------|------|
| id | BIGINT | 主键 |
| exam_id | BIGINT NOT NULL | 考试ID |
| user_id | BIGINT NOT NULL | 学员ID |
| attempt_no | INT NOT NULL | 第几次考试 |
| score | INT | 得分 |
| passed | TINYINT | 0-未通过 / 1-通过 |
| start_time | DATETIME NOT NULL | 开始时间 |
| submit_time | DATETIME | 提交时间 |
| answers | JSON | 答题详情 |
| status | VARCHAR(20) | IN_PROGRESS / SUBMITTED |
| last_save_time | DATETIME | 最后保存时间 |
| version | INT DEFAULT 0 | 乐观锁版本号 |
| submit_source | VARCHAR(20) | USER / SYSTEM_TIMEOUT |
### 4.2 数据关联
- `ex_paper_question.paper_id` `ex_paper.id`
- `ex_paper_question.question_id` `ex_question.id`
- `ex_exam.paper_id` `ex_paper.id`
- `ex_exam_target` 多态关联target_type=0 `sys_department.id`=1 `sys_group.id`=2 `sys_user.id`
- `ex_exam_record.exam_id` `ex_exam.id``user_id` `sys_user.id`
---
## 5. 对外接口
[SRC-API-014.4]
| API 名称 | 方法 | 路径 | 权限 |
|---------|------|------|------|
| 题目分类 CRUD | GET/POST/PUT/DELETE | /api/exam/question-category/** | LECTURER/ADMIN |
| 题目 CRUD | GET/POST/PUT/DELETE | /api/exam/question/** | LECTURER/ADMIN |
| 试卷 CRUD + 自动组卷 | GET/POST/PUT/DELETE | /api/exam/paper/** + /api/exam/paper/auto | LECTURER/ADMIN |
| 考试 CRUD | GET/POST/PUT/DELETE | /api/exam/** | LECTURER/ADMIN |
| 我的考试列表 | GET | /api/student/exam | STUDENT |
| 考试详情 | GET | /api/student/exam/{id} | STUDENT |
| 开始考试 | POST | /api/student/exam/{id}/start | STUDENT |
| 断点续考 | GET | /api/student/exam/{id}/continue | STUDENT |
| 保存答案 | POST | /api/student/exam/{id}/save | STUDENT |
| 提交试卷 | POST | /api/student/exam/{id}/submit | STUDENT |
| 查看考试结果 | GET | /api/student/exam/record/{recordId} | STUDENT |
---
## 6. 异常与边界处理
| 场景 | 处理方式 |
|------|---------|
| 学员在时间窗口外访问考试 | 400 + 明确提示是"未开始"还是"已结束" |
| 次数用完后再次开始 | 400已达最大考试次数如有异议请联系讲师 |
| 交卷时 exam_record 已是 SUBMITTED并发/重复提交 | 乐观锁冲突或状态判断幂等返回已有成绩不重复判分 |
| 定时任务超时提交时用户同时提交 | 乐观锁 version 冲突定时任务忽略用户提交成功 |
| 试卷总分与题目分值之和不一致 | [ASSUMPTION] PRD 未明确建议前端组卷时实时计算并提示差额 |
| 自动组卷时题库数量不足 | 400题库中相应题型数量不足请手动添加题目或降低要求 |
| 学员中途关闭浏览器 | answers 按最后一次 save 记录恢复重新进入走断点续考流程 |

View File

@@ -0,0 +1,196 @@
# 培训计划模块training
> 证据来源:[SRC-FEAT-01] [SRC-FEAT-02] [SRC-SQL-01] [SRC-API-01] [SRC-CODE-01module/training/]
---
## 1. 模块定位
- **模块目标**:将知识内容和考试任务组合成有时间范围的培训计划,分配给指定学员,并跟踪每位学员的完成进度。
- **解决问题**:组织端无法跟踪员工是否真正完成学习目标;培训计划模块实现"分配→执行→进度可视"的闭环管理。
---
## 2. 功能清单
[SRC-FEAT-01模块六] [SRC-FEAT-023.4 我的培训] [SRC-API-014.5]
| 功能名称 | 功能描述 | 输入 | 输出 | 依赖模块 |
|---------|---------|------|------|---------|
| 创建培训计划 | 设置计划基本信息(名称/描述/时间范围/所属部门) | TrainingPlanQueryDTOtitle, start_date, end_date | TrainingPlanVO | system |
| 关联知识内容 | 在培训计划中添加多个知识,设置必修/选修和排序 | plan_id, [{knowledge_id, required, sort_order}] | - | knowledge |
| 关联考试任务 | 在培训计划中添加多个考试,设置必考/选考和排序V1.0.1+| plan_id, [{exam_id, required, sort_order}] | - | exam |
| 分配培训对象 | 指定培训计划的参与者(部门/小组/个人) | plan_id, [{target_type, target_id}] | - | system |
| 培训计划列表(讲师端) | 查询本部门的培训计划,含状态和统计信息 | 分页参数 | PageResult<TrainingPlanVO> | - |
| 培训计划详情(讲师端) | 查看计划详情,含关联知识/考试/对象/进度汇总 | planId | TrainingPlanDetailVO | - |
| 更新/删除培训计划 | 修改计划信息(未开始时可修改,进行中时受限)| planId, TrainingPlanQueryDTO | - | - |
| 学员-我的培训列表 | 查询分配给当前学员的培训计划(进行中优先) | - | PageResult<TrainingPlanVO + 进度> | auth |
| 学员-培训详情 | 查看某培训计划详情:课程列表+学习状态+考试列表+通过状态 | planId | TrainingDetailVO | knowledge, exam |
| 进度计算 | 按必修知识完成数 + 必考通过数 / 总必修项 计算进度% | planId, userId | Integer0~100 | knowledge, exam |
| 知识进度同步 | 学员学习某知识时,若 source=TRAINING 则同步更新 tr_plan_progress | planId, userId, knowledgeId | - | knowledge |
---
## 3. 核心逻辑
### 3.1 业务规则
[SRC-FEAT-01模块六] [SRC-API-015.4]
**培训计划状态自动流转**
- `tr_plan.status` 根据 `start_date` / `end_date` 与当前日期比较自动判定:
- `NOW() < start_date` → NOT_STARTED
- `start_date ≤ NOW() ≤ end_date` → IN_PROGRESS
- `NOW() > end_date` → ENDED
- [ASSUMPTION] 状态字段在查询时实时计算或由定时任务定期刷新PRD 未明确)
**培训进度计算公式**V1.0.1[SRC-API-015.4]
```
progress% = (必修知识完成数 + 必考考试通过数) / (必修知识总数 + 必考考试总数) × 100
```
- 必修知识完成:`km_knowledge_progress.status = COMPLETED``plan_id = 当前计划`
- 必考通过:在 `tr_plan_exam``required=1` 的考试,学员在 `ex_exam_record` 中存在 `passed=1` 的记录
- 选修知识/选考考试不计入进度(但在详情页展示)
- 总必修项为 0 时,进度 = 100%(无内容的计划视为自动完成)
**知识完成与培训进度联动**
- 学员调用 `knowledge.updateProgress()` 时,若 `source=TRAINING``planId != null`
1. 更新 `km_knowledge_progress`
2. 若 status 变为 COMPLETED则更新 `tr_plan_progress`plan_id, user_id, knowledge_id 唯一记录)
**考试通过与培训进度联动**
- 学员考试提交后,`TrainingProgressService` 查询该 exam_id 被哪些计划引用(`tr_plan_exam`),若有关联且 `passed=1`,则重新计算相关计划的进度(或标记为需要刷新)
**多对象分配逻辑**
- 分配对象类型支持 DEPARTMENT(0) / GROUP(1) / USER(2) 混合
- 当指定 DEPARTMENT 时,该部门下所有 STUDENT 账号都被纳入
- 当指定 GROUP 时,该小组所有成员纳入
- 已被纳入的学员在查询时去重(多路径覆盖同一人不重复统计)
### 3.2 校验逻辑
| 校验项 | 规则 | 失败响应 |
|-------|------|---------|
| 培训时间范围 | start_date < end_date | 400培训结束日期必须晚于开始日期 |
| 关联知识状态 | 关联到计划的知识必须是 PUBLISHED 状态 | 400请先发布知识再关联到培训计划 |
| 关联考试状态 | 关联到计划的考试必须是 IN_PROGRESS NOT_STARTED | 400已结束的考试不可关联 |
| 进行中计划修改 | [ASSUMPTION] IN_PROGRESS 状态下不允许修改培训对象和时间范围 | 400培训进行中不可修改 |
| 知识引用保护 | 已关联计划的知识被下架时触发警告 | knowledge 模块负责见知识库模块 6 |
| 学员查看非自己的计划 | Service 层校验该学员是否在 tr_plan_target 覆盖范围内 | 403无权访问该培训计划 |
### 3.3 状态流转
```mermaid
stateDiagram-v2
[*] --> NOT_STARTED : 创建培训计划start_date 未到)
NOT_STARTED --> IN_PROGRESS : start_date 到达(自动/定时)
IN_PROGRESS --> ENDED : end_date 到达(自动/定时)
NOT_STARTED --> [*] : 逻辑删除(未开始可删除)
ENDED --> [*] : 归档
note right of IN_PROGRESS : 学员可学习和考试
note right of ENDED : 仅供历史查阅
```
**学员培训进度状态(非独立表字段,实时计算)**
- 0%尚未开始学习
- 1%~99%学习中
- 100%全部必修项完成培训通过
---
## 4. 数据结构
[SRC-SQL-01培训模块]
### 4.1 涉及数据表
**tr_plan**
| 字段 | 类型 | 说明 |
|------|------|------|
| id | BIGINT | 主键 |
| title | VARCHAR(200) NOT NULL | 计划标题 |
| description | TEXT | 计划描述 |
| start_date | DATE NOT NULL | 开始日期 |
| end_date | DATE NOT NULL | 结束日期 |
| department_id | BIGINT NOT NULL | 所属部门数据隔离键 |
| status | TINYINT | 0-未开始 / 1-进行中 / 2-已结束 |
| creator_id | BIGINT NOT NULL | 创建人 |
**tr_plan_knowledge**培训计划-知识关联
| 字段 | 类型 | 说明 |
|------|------|------|
| plan_id | BIGINT NOT NULL | 培训计划 ID |
| knowledge_id | BIGINT NOT NULL | 知识 ID |
| required | TINYINT DEFAULT 1 | 1-必修 / 0-选修 |
| sort_order | INT | 排序 |
**tr_plan_exam**培训计划-考试关联V1.0.1
| 字段 | 类型 | 说明 |
|------|------|------|
| plan_id | BIGINT NOT NULL | 培训计划 ID |
| exam_id | BIGINT NOT NULL | 考试 ID |
| required | TINYINT DEFAULT 1 | 1-必考 / 0-选考 |
| sort_order | INT | 排序 |
| 唯一约束 | uk_plan_exam | (plan_id, exam_id) |
**tr_plan_target**培训计划-分配对象
| 字段 | 类型 | 说明 |
|------|------|------|
| plan_id | BIGINT NOT NULL | 培训计划 ID |
| target_type | TINYINT NOT NULL | 0-部门 / 1-小组 / 2-个人 |
| target_id | BIGINT NOT NULL | 对应实体 ID |
**tr_plan_progress**知识级别进度供快速查询
| 字段 | 类型 | 说明 |
|------|------|------|
| plan_id | BIGINT NOT NULL | 培训计划 ID |
| user_id | BIGINT NOT NULL | 学员 ID |
| knowledge_id | BIGINT NOT NULL | 知识 ID |
| completed | TINYINT DEFAULT 0 | 0-未完成 / 1-已完成 |
| complete_time | DATETIME | 完成时间 |
### 4.2 数据关联
- `tr_plan_knowledge.plan_id` `tr_plan.id`
- `tr_plan_knowledge.knowledge_id` `km_knowledge.id`
- `tr_plan_exam.plan_id` `tr_plan.id`
- `tr_plan_exam.exam_id` `ex_exam.id`
- `tr_plan_target` 多态关联type=0→`sys_department.id`type=1→`sys_group.id`type=2→`sys_user.id`
- 进度计算同时读取 `km_knowledge_progress`source=TRAINING, plan_id `ex_exam_record`passed=1
---
## 5. 对外接口
[SRC-API-014.5] [SRC-CODE-01module/training/controller/]
| API 名称 | 方法 | 路径 | 权限 |
|---------|------|------|------|
| 培训计划列表讲师 | GET | /api/training | LECTURER/ADMIN |
| 创建培训计划 | POST | /api/training | LECTURER/ADMIN |
| 修改培训计划 | PUT | /api/training/{id} | LECTURER/ADMIN |
| 删除培训计划 | DELETE | /api/training/{id} | LECTURER/ADMIN |
| 关联知识 | POST | /api/training/{id}/knowledge | LECTURER/ADMIN |
| 关联考试 | POST | /api/training/{id}/exam | LECTURER/ADMIN |
| 分配对象 | POST | /api/training/{id}/target | LECTURER/ADMIN |
| 学员-培训列表 | GET | /api/student/training | STUDENT |
| 学员-培训详情 | GET | /api/student/training/{id} | STUDENT |
---
## 6. 异常与边界处理
| 场景 | 处理方式 |
|------|---------|
| 培训计划结束后学员查看 | 状态=ENDED页面展示历史进度和成绩不可继续学习/考试 |
| 学员尚未被分配到某计划就访问 | 403无权访问该培训计划 |
| 相关考试时间窗口已过但培训计划仍进行中 | 考试显示"已结束"无法参加该考试通过状态默认为"未通过"评估影响进度 |
| 同一学员多次被添加部门+个人双重覆盖 | tr_plan_target 可能有重复记录进度计算时去重 user_id 聚合 |
| 培训计划关联的知识被删除 | tr_plan_knowledge 记录仍在显示时标注"知识已下架" [ASSUMPTION] |
| 总必修项为 0 的计划 | 进度直接返回 100%calculateProgress 中已处理totalRequired=0 return 100[SRC-API-015.4] |

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 308 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 390 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View File

@@ -0,0 +1,881 @@
# 道路救援企业培训系统 - 产品需求文档 (PRD)
> 版本V1.0.1
> 更新日期2026-01-13
> 状态:已确认
---
## 版本更新记录
### V1.0.1 (2026-01-13)
**【培训计划】多考试任务支持**
| 变更项 | 变更前 | 变更后 |
|-------|-------|-------|
| 考试任务数量 | 最多关联1个考试 | 支持关联多个考试 |
| 考试属性 | 无 | 支持设置必考/选考 |
| 考试排序 | 无 | 支持自定义排序 |
**功能说明:**
- 创建/编辑培训计划时,可添加多个考试任务
- 每个考试可设置为"必考"或"选考"
- 学员端展示所有关联考试及通过状态
- 列表页显示考试任务总数
**数据库变更:**
- 新增 `tr_plan_exam` 关联表
- 移除 `tr_plan` 表的 `exam_id` 字段
- ⚠️ 不兼容历史数据,需重新初始化数据库
---
### V1.0.0 (2026-01-08)
- 初始版本发布
- 包含:系统基础、人员管理、知识库、考题管理、试卷管理、考试管理、培训计划六大模块
---
## 一、核心目标 (Mission)
**为道路救援企业打造一站式内部培训平台通过知识沉淀、在线考核、培训管理三大核心能力提升500名员工的专业技能水平和服务标准化程度。**
---
## 二、用户画像 (Persona)
| 角色 | 人数估算 | 核心痛点 | 使用场景 |
|------|----------|----------|----------|
| **管理员** | 3-5人 | 人员管理分散,培训效果难追踪 | 配置系统、管理组织架构、分配权限 |
| **讲师(技师)** | 30-50人 | 知识传承依赖口口相传,出题组卷效率低 | 上传知识文档、创建题库、发布考试 |
| **学员** | 450人左右 | 学习资料分散、考试不便、进度不清晰 | 查阅知识库、完成培训任务、参加考试 |
---
## 三、版本规划
### V1最小可行产品 (MVP)
#### 模块一:系统基础与人员管理
| 功能 | 说明 |
|----------|-----------------------------|
| 企业微信授权登录 | 企业微信授权登录 |
| 组织架构管理 | 中心 → 部门≤8→ 小组≤10/部门)三级结构 |
| 员工管理 | 管理员手动录入员工信息,分配角色(管理员/讲师/学员) |
| 权限控制 | 基于角色的权限隔离,数据按部门隔离 |
#### 模块二:知识库(重点)
| 功能 | 说明 |
|------|------|
| 分类目录 | 支持多级分类(如:安全规范 > 高速救援 > 操作手册)|
| 文档管理 | 支持上传 PDF/Word/Excel/PPT 等常见文档格式 |
| 视频管理 | 支持上传视频文件,在线播放 |
| 在线预览 | 文档、视频无需下载即可在线查看 |
| 状态管理 | 草稿 → 已发布 → 已下架 |
| 部门隔离 | 各部门只能查看本部门的知识内容 |
#### 模块三:考题管理
| 功能 | 说明 |
|------|------|
| 题型支持 | 单选题、多选题、判断题 |
| 题目解析 | 每道题必须填写答案解析 |
| 题库分类 | 按分类/章节管理题目 |
| 状态管理 | 草稿 → 已发布 → 已下架 |
| 部门隔离 | 讲师只能管理本部门题库 |
#### 模块四:试卷管理
| 功能 | 说明 |
|------|------|
| 手动组卷 | 讲师手动从题库选题组成试卷 |
| 自动组卷 | 设置规则单选X题+多选Y题+判断Z题系统随机抽题 |
| 试卷配置 | 设置总分、题目分值、考试时长 |
| 试卷预览 | 组卷完成后可预览试卷效果 |
| 状态管理 | 草稿 → 已发布 → 已下架 |
#### 模块五:考试管理
| 功能 | 说明 |
|------|------|
| 发布考试 | 选择试卷,设置考试名称、时间窗口(开始~结束时间)|
| 指定对象 | 支持指定部门 / 小组 / 个人参加考试 |
| 考试规则 | 设置及格线、限制考试次数、考试时长 |
| 在线答题 | 学员在线作答,自动计时,超时自动交卷 |
| 成绩查看 | 交卷后立即显示成绩和答案解析 |
#### 模块六:培训计划
| 功能 | 说明 |
|------|------|
| 创建培训计划 | 设置计划名称、培训周期、培训目标 |
| 关联知识/考试 | 一个培训计划可包含多个知识文档 + 多场考试V1.0.1+ |
| 考试属性设置 | 每个考试可设置必考/选考、自定义排序V1.0.1+ |
| 分配学员 | 指定部门/小组/个人参加培训计划 |
| 进度跟踪 | 学员可查看自己的学习进度和考试状态 |
| 计划状态 | 未开始 / 进行中 / 已结束 |
### V2 及以后版本 (Future Releases)
| 版本 | 功能 | 价值 |
|------|------|------|
| **V2** | 统计报表中心 | 培训完成率、考试通过率、部门排名等数据看板 |
| **V2** | 线下培训签到 | 扫码签到/签退,记录实际培训时长 |
| **V2** | 错题本 | 学员自动收集错题,巩固薄弱知识点 |
| **V3** | 知识库增强 | 收藏、点赞、评论、全文搜索 |
| **V3** | 奖励体系 | 积分、勋章、学习排行榜 |
| **V3** | 证书管理 | 培训/考试
---
## 四、关键业务逻辑 (Business Rules)
### 4.1 权限规则
```
管理员:
├── 管理所有中心、部门、小组
├── 管理所有用户(增删改查、角色分配)
├── 查看全平台数据
└── 系统配置
讲师:
├── 管理本部门知识库(上传/编辑/删除)
├── 管理本部门题库(增删改查)
├── 创建/管理本部门试卷和考试
├── 创建/管理本部门培训计划
└── 查看本部门学员成绩
学员:
├── 查看本部门知识库(只读)
├── 参加分配给自己的培训计划
├── 参加分配给自己的考试
└── 查看个人学习记录和成绩
```
### 4.2 内容状态流转
```
┌─────────┐ 发布 ┌─────────┐ 下架 ┌─────────┐
│ 草稿 │ ───────────▶ │ 已发布 │ ───────────▶ │ 已下架 │
│ DRAFT │ │PUBLISHED │ │ OFFLINE │
└─────────┘ └─────────┘ └─────────┘
▲ │ │
│ │ 重新上架 │
│ ◀────────────────────────┘
└──────── 可继续编辑 ─────────────────────────────┘
```
| 状态 | 说明 | 学员可见 |
|------|------|----------|
| **草稿 (DRAFT)** | 讲师编辑中,未完成 | ❌ 不可见 |
| **已发布 (PUBLISHED)** | 正式生效,可被使用 | ✅ 可见 |
| **已下架 (OFFLINE)** | 临时隐藏,保留数据 | ❌ 不可见 |
### 4.3 考试规则
| 规则 | 说明 |
|------|------|
| 时间窗口 | 只有在考试开放时间内才能进入考试 |
| 限时作答 | 超过考试时长自动交卷 |
| 限制次数 | 达到最大次数后不可再考,取最高分 |
| 及格判定 | 分数 ≥ 及格线 为通过 |
| 答题顺序 | 自动组卷时题目顺序随机打乱 |
### 4.4 数据隔离规则
| 数据类型 | 隔离方式 |
|----------|----------|
| 知识库 | 按部门隔离,只能看本部门 |
| 题库 | 按部门隔离,讲师只能操作本部门 |
| 试卷/考试 | 按部门隔离 |
| 培训计划 | 按部门隔离 |
| 员工信息 | 管理员可见全部,讲师可见本部门 |
### 4.5 引用保护规则
| 场景 | 规则 |
|------|------|
| 题目下架 | 已被试卷引用的题目,下架前需确认警告 |
| 试卷下架 | 已被考试引用的试卷,下架前需确认警告 |
| 知识下架 | 已被培训计划引用的知识,下架前需确认警告 |
---
## 五、数据契约 (Data Contract)
### 5.1 核心实体
#### 用户 (sys_user)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Long | 主键 |
| wx_userid | String | 企业微信用户ID |
| real_name | String | 姓名 |
| phone | String | 手机号 |
| role | Enum | 角色ADMIN/LECTURER/STUDENT |
| department_id | Long | 所属部门 |
| group_id | Long | 所属小组(可空) |
| status | Enum | 状态ENABLED/DISABLED |
| create_time | DateTime | 创建时间 |
#### 组织架构 (sys_center / sys_department / sys_group)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Long | 主键 |
| name | String | 名称 |
| parent_id | Long | 上级ID部门关联中心小组关联部门 |
| sort_order | Integer | 排序 |
| create_time | DateTime | 创建时间 |
#### 知识分类 (km_category)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Long | 主键 |
| name | String | 分类名称 |
| parent_id | Long | 父分类ID |
| department_id | Long | 所属部门 |
| sort_order | Integer | 排序 |
#### 知识 (km_knowledge)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Long | 主键 |
| title | String | 标题 |
| category_id | Long | 所属分类 |
| type | Enum | 类型DOCUMENT/VIDEO |
| file_url | String | 文件地址 |
| file_size | Long | 文件大小 |
| department_id | Long | 所属部门 |
| status | Enum | 状态DRAFT/PUBLISHED/OFFLINE |
| creator_id | Long | 创建人 |
| create_time | DateTime | 创建时间 |
| publish_time | DateTime | 发布时间 |
#### 题目 (ex_question)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Long | 主键 |
| type | Enum | 题型SINGLE/MULTIPLE/JUDGE |
| content | String | 题干 |
| options | JSON | 选项列表(判断题为空) |
| answer | String | 正确答案 |
| analysis | String | 解析 |
| category_id | Long | 所属分类 |
| department_id | Long | 所属部门 |
| status | Enum | 状态DRAFT/PUBLISHED/OFFLINE |
| creator_id | Long | 创建人 |
| create_time | DateTime | 创建时间 |
| publish_time | DateTime | 发布时间 |
#### 试卷 (ex_paper)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Long | 主键 |
| title | String | 试卷名称 |
| total_score | Integer | 总分 |
| duration | Integer | 考试时长(分钟) |
| pass_score | Integer | 及格分 |
| department_id | Long | 所属部门 |
| status | Enum | 状态DRAFT/PUBLISHED/OFFLINE |
| creator_id | Long | 创建人 |
| create_time | DateTime | 创建时间 |
| publish_time | DateTime | 发布时间 |
#### 试卷题目关联 (ex_paper_question)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Long | 主键 |
| paper_id | Long | 试卷ID |
| question_id | Long | 题目ID |
| score | Integer | 该题分值 |
| sort_order | Integer | 排序 |
#### 考试 (ex_exam)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Long | 主键 |
| title | String | 考试名称 |
| paper_id | Long | 关联试卷 |
| start_time | DateTime | 开始时间 |
| end_time | DateTime | 结束时间 |
| max_attempts | Integer | 最大考试次数 |
| department_id | Long | 所属部门 |
| status | Enum | 状态NOT_STARTED/IN_PROGRESS/ENDED |
| creator_id | Long | 创建人 |
| create_time | DateTime | 创建时间 |
#### 考试对象 (ex_exam_target)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Long | 主键 |
| exam_id | Long | 考试ID |
| target_type | Enum | 对象类型DEPARTMENT/GROUP/USER |
| target_id | Long | 对象ID |
#### 考试记录 (ex_exam_record)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Long | 主键 |
| exam_id | Long | 考试ID |
| user_id | Long | 学员ID |
| attempt_no | Integer | 第几次考试 |
| score | Integer | 得分 |
| passed | Boolean | 是否通过 |
| start_time | DateTime | 开始时间 |
| submit_time | DateTime | 提交时间 |
| answers | JSON | 答题详情 |
#### 培训计划 (tr_plan)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Long | 主键 |
| title | String | 计划名称 |
| description | String | 计划描述 |
| start_date | Date | 开始日期 |
| end_date | Date | 结束日期 |
| department_id | Long | 所属部门 |
| exam_id | Long | 关联考试(可空) |
| status | Enum | 状态NOT_STARTED/IN_PROGRESS/ENDED |
| creator_id | Long | 创建人 |
| create_time | DateTime | 创建时间 |
#### 培训计划-知识关联 (tr_plan_knowledge)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Long | 主键 |
| plan_id | Long | 计划ID |
| knowledge_id | Long | 知识ID |
| required | Boolean | 是否必修 |
| sort_order | Integer | 排序 |
#### 培训计划-对象 (tr_plan_target)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Long | 主键 |
| plan_id | Long | 计划ID |
| target_type | Enum | 对象类型DEPARTMENT/GROUP/USER |
| target_id | Long | 对象ID |
#### 培训进度 (tr_plan_progress)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Long | 主键 |
| plan_id | Long | 计划ID |
| user_id | Long | 学员ID |
| knowledge_id | Long | 知识ID |
| completed | Boolean | 是否完成 |
| complete_time | DateTime | 完成时间 |
---
## 六、原型设计方案A - 经典管理后台风格)
### 6.1 设计理念
左侧固定导航 + 右侧内容区,层级分明,适合功能复杂的企业管理系统。学习成本低,用户容易上手。
### 6.2 布局结构
```
┌────────────────────────────────────────────────────────────────────────────┐
│ 🚗 道路救援培训系统 🔔 消息 👤 张三 ▼ │
├──────────────────┬─────────────────────────────────────────────────────────┤
│ │ │
│ 📊 工作台 │ 内容区域 │
│ │ │
│ 👥 人员管理 ▶ │ │
│ ├ 组织架构 │ │
│ ├ 员工管理 │ │
│ └ 讲师管理 │ │
│ │ │
│ 📚 知识库 ▶ │ │
│ ├ 知识分类 │ │
│ └ 知识列表 │ │
│ │ │
│ ✏️ 考题管理 ▶ │ │
│ ├ 题库分类 │ │
│ └ 题目列表 │ │
│ │ │
│ 📄 试卷管理 │ │
│ │ │
│ 📝 考试管理 │ │
│ │ │
│ 📅 培训计划 │ │
│ │ │
│ ────────────── │ │
│ ⚙️ 系统设置 │ │
│ │ │
└──────────────────┴─────────────────────────────────────────────────────────┘
```
### 6.3 核心页面原型
#### 工作台首页
```
┌────────────────────────────────────────────────────────────────────────────┐
│ 🚗 道路救援培训系统 🔔 消息 👤 张三 ▼ │
├──────────────────┬─────────────────────────────────────────────────────────┤
│ │ │
│ 📊 工作台 ● │ 欢迎回来,张三 2026年1月8日 │
│ │ │
│ 👥 人员管理 ▶ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ │ 待学习课程 │ │ 待完成考试 │ │ 培训进度 │ │
│ 📚 知识库 ▶ │ │ │ │ │ │ │ │
│ │ │ 12 │ │ 3 │ │ 75% │ │
│ ✏️ 考题管理 ▶ │ │ │ │ │ │ ████░░ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │
│ 📄 试卷管理 │ │
│ │ ┌──────────────────────────────────────────────────┐ │
│ 📝 考试管理 │ │ 我的培训计划 │ │
│ │ ├──────────────────────────────────────────────────┤ │
│ 📅 培训计划 │ │ 📋 2026年Q1安全规范培训 进行中 60% │ │
│ │ │ 📋 新员工入职培训 进行中 30% │ │
│ │ │ 📋 高速救援操作规范 未开始 -- │ │
│ │ └──────────────────────────────────────────────────┘ │
│ │ │
│ │ ┌──────────────────────────────────────────────────┐ │
│ │ │ 待完成考试 │ │
│ │ ├──────────────────────────────────────────────────┤ │
│ │ │ 📝 安全规范考核 截止: 1月15日 [进入考试] │ │
│ │ │ 📝 月度技能测试 截止: 1月20日 [进入考试] │ │
│ │ └──────────────────────────────────────────────────┘ │
│ │ │
└──────────────────┴─────────────────────────────────────────────────────────┘
```
#### 知识库列表页
```
┌────────────────────────────────────────────────────────────────────────────┐
│ 🚗 道路救援培训系统 🔔 消息 👤 张三 ▼ │
├──────────────────┬─────────────────────────────────────────────────────────┤
│ │ │
│ 📊 工作台 │ 知识库 > 安全规范 │
│ │ ───────────────────────────────────────────────── │
│ 👥 人员管理 ▶ │ │
│ │ [+ 新增知识] [所有状态 ▼] [🔍 搜索知识...] │
│ 📚 知识库 ▼ │ │
│ ┌ 知识分类 │ ┌────────────────────────────────────────────────┐ │
│ └ 知识列表 ● │ │ 标题 类型 状态 更新时间 操作│ │
│ │ ├────────────────────────────────────────────────┤ │
│ ✏️ 考题管理 ▶ │ │ 高速救援SOP 📄文档 已发布 01-05 编辑│ │
│ │ │ 安全操作视频 🎬视频 已发布 01-03 编辑│ │
│ 📄 试卷管理 │ │ 应急处理流程 📄文档 草稿 01-02 编辑│ │
│ │ │ 设备使用手册 📄文档 已下架 12-28 编辑│ │
│ 📝 考试管理 │ └────────────────────────────────────────────────┘ │
│ │ │
│ 📅 培训计划 │ 共 24 条记录 < 1 2 3 4 5 > │
│ │ │
└──────────────────┴─────────────────────────────────────────────────────────┘
```
#### 在线考试页
```
┌────────────────────────────────────────────────────────────────────────────┐
│ 📝 2026年Q1安全规范考试 剩余时间: 45:23 │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ 第 3 题 / 共 20 题 [单选题] │ │
│ ├─────────────────────────────────────────────────────────────────────┤ │
│ │ │ │
│ │ 高速公路救援作业时,警示标志应放置在故障车辆后方多少米处? │ │
│ │ │ │
│ │ ○ A. 50米 │ │
│ │ ● B. 150米 │ │
│ │ ○ C. 200米 │ │
│ │ ○ D. 100米 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ 答题卡: │
│ ┌────────────────────────────────────────────────────────────────────┐ │
│ │ ✓1 ✓2 ●3 ○4 ○5 ○6 ○7 ○8 ○9 ○10 │ │
│ │ ○11 ○12 ○13 ○14 ○15 ○16 ○17 ○18 ○19 ○20 │ │
│ └────────────────────────────────────────────────────────────────────┘ │
│ │
│ [< 上一题] [下一题 >] [交卷] │
│ │
└────────────────────────────────────────────────────────────────────────────┘
```
#### 试卷组卷页
```
┌────────────────────────────────────────────────────────────────────────────┐
│ 🚗 道路救援培训系统 🔔 消息 👤 张三 ▼ │
├──────────────────┬─────────────────────────────────────────────────────────┤
│ │ │
│ 📊 工作台 │ 创建试卷 > 第2步选择题目 │
│ │ ═══════════════════════════════════════════════════ │
│ 👥 人员管理 ▶ │ ① 基本信息 ────── ② 选择题目 ────── ③ 预览确认 │
│ │ ● │
│ 📚 知识库 ▶ │ │
│ │ ┌─────────────────────┐ ┌────────────────────────┐ │
│ ✏️ 考题管理 ▶ │ │ 📂 题库 │ │ 📋 已选题目 (15) │ │
│ │ │ ┌─────────────────┐ │ │ │ │
│ 📄 试卷管理 ● │ │ │ [全选] 安全(48) │ │ │ 单选题 x10 30分 │ │
│ │ │ │ ☑ 高速警示... │ │ │ 多选题 x3 15分 │ │
│ 📝 考试管理 │ │ │ ☑ 夜间灯光... │ │ │ 判断题 x2 5分 │ │
│ │ │ │ ☐ 拖车规范... │ │ │ ─────────────── │ │
│ 📅 培训计划 │ │ └─────────────────┘ │ │ 总分: 50分 │ │
│ │ │ │ │ │ │
│ │ │ ── 或自动组卷 ── │ │ [自动组卷] │ │
│ │ │ 单选: [10] 题 │ │ 单选: [10] 题 │ │
│ │ │ 多选: [ 5] 题 │ │ 多选: [ 5] 题 │ │
│ │ │ 判断: [ 5] 题 │ │ 判断: [ 5] 题 │ │
│ │ │ [随机抽题] │ │ [确认随机抽取] │ │
│ │ └─────────────────────┘ └────────────────────────┘ │
│ │ │
│ │ [上一步] [下一步:预览] │
└──────────────────┴─────────────────────────────────────────────────────────┘
```
---
## 七、架构设计蓝图
### 7.1 系统架构总览
```
┌─────────────────────────────────────────────────────────────────────────┐
│ 客户端层 │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ PC浏览器 │ │ 企业微信H5 │ │ 移动端浏览器 │ │
│ │ (管理员/讲师) │ │ (学员) │ │ (学员) │ │
│ └────────┬────────┘ └────────┬────────┘ └────────┬────────┘ │
└───────────┼─────────────────────┼─────────────────────┼─────────────────┘
│ │ │
└─────────────────────┼─────────────────────┘
┌─────────────────────────────────────────────────────────────────────────┐
│ 网关层 │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ Spring Boot 应用 │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ JWT认证 │ │ 权限拦截 │ │ 日志记录 │ │ 异常处理 │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────┐
│ 业务层 │
│ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐ │
│ │ 认证模块 │ │ 组织模块 │ │ 知识库模块│ │ 考试模块 │ │ 培训模块 │ │
│ │ │ │ │ │ │ │ │ │ │ │
│ │ ·企微登录 │ │ ·组织架构 │ │ ·分类管理 │ │ ·题库管理 │ │ ·计划管理 │ │
│ │ ·Token管理│ │ ·员工管理 │ │ ·知识CRUD │ │ ·试卷管理 │ │ ·任务分配 │ │
│ │ ·权限校验 │ │ ·角色管理 │ │ ·文件上传 │ │ ·考试管理 │ │ ·进度跟踪 │ │
│ └───────────┘ └───────────┘ └───────────┘ └───────────┘ └───────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────┐
│ 数据层 │
│ ┌─────────────────────────┐ ┌─────────────────────────┐ │
│ │ MySQL 8.0 │ │ 文件存储服务 │ │
│ │ (MyBatis Plus ORM) │ │ (本地/OSS/MinIO) │ │
│ └─────────────────────────┘ └─────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
```
### 7.2 核心流程图
#### 用户登录流程企业微信OAuth
```mermaid
sequenceDiagram
participant U as 用户
participant FE as 前端页面
participant BE as 后端服务
participant WX as 企业微信API
participant DB as 数据库
U->>FE: 点击"企业微信登录"
FE->>WX: 跳转企微授权页面
WX->>U: 显示授权确认
U->>WX: 确认授权
WX->>FE: 回调返回code
FE->>BE: 携带code请求登录
BE->>WX: 用code换取access_token
WX-->>BE: 返回access_token
BE->>WX: 获取用户信息(userid)
WX-->>BE: 返回用户信息
BE->>DB: 查询用户是否存在
alt 用户存在
DB-->>BE: 返回用户信息
BE->>BE: 生成JWT Token
BE-->>FE: 返回Token+用户信息
FE->>FE: 存储Token跳转工作台
else 用户不存在
BE-->>FE: 返回错误:用户未录入
FE->>U: 提示联系管理员
end
```
#### 在线考试流程
```mermaid
sequenceDiagram
participant S as 学员
participant FE as 前端页面
participant BE as 后端服务
participant DB as 数据库
S->>FE: 进入考试列表
FE->>BE: 获取我的考试列表
BE->>DB: 查询分配给该学员的考试
DB-->>BE: 返回考试列表
BE-->>FE: 返回考试列表(含剩余次数)
S->>FE: 点击"开始考试"
FE->>BE: 请求开始考试
BE->>DB: 校验考试状态/次数/时间窗口
alt 校验通过
BE->>DB: 创建考试记录(开始时间)
BE->>DB: 获取试卷题目
DB-->>BE: 返回题目列表
BE-->>FE: 返回试卷内容+考试时长
FE->>FE: 启动倒计时
loop 答题过程
S->>FE: 选择/修改答案
FE->>FE: 本地暂存答案
FE->>BE: 定时自动保存(每30秒)
BE->>DB: 更新答题记录
end
alt 主动交卷
S->>FE: 点击"交卷"
else 时间到
FE->>FE: 倒计时结束
end
FE->>BE: 提交试卷
BE->>BE: 自动判分(客观题)
BE->>DB: 保存成绩+答案详情
BE-->>FE: 返回考试成绩
FE->>S: 显示成绩+答案解析
else 校验失败
BE-->>FE: 返回错误(次数用尽/不在时间窗口)
FE->>S: 提示无法参加考试
end
```
#### 培训计划执行流程
```mermaid
flowchart TB
subgraph 讲师操作
A[创建培训计划] --> B[设置基本信息]
B --> C[关联知识内容]
C --> D[关联考试-可选]
D --> E[指定培训对象]
E --> F[发布培训计划]
end
subgraph 学员学习
F --> G[学员收到培训通知]
G --> H[进入培训计划]
H --> I[学习知识内容]
I --> J{知识学完?}
J -->|否| I
J -->|是| K{有关联考试?}
K -->|否| L[培训完成]
K -->|是| M[参加考试]
M --> N{考试通过?}
N -->|是| L
N -->|否| O{还有考试次数?}
O -->|是| M
O -->|否| P[培训未通过]
end
subgraph 进度追踪
I --> Q[更新学习进度]
M --> R[记录考试成绩]
L --> S[标记培训完成]
end
```
### 7.3 技术选型
| 层次 | 技术 | 版本 | 说明 |
|------|------|------|------|
| **构建** | Maven | 3.8+ | 依赖管理 |
| **框架** | Spring Boot | 3.1.2 | 主框架 |
| **ORM** | MyBatis Plus | 3.5.3+ | 简化CRUD |
| **数据库** | MySQL | 8.0 | 主数据库 |
| **认证** | java-jwt | 4.4+ | JWT Token生成验证 |
| **加密** | Spring Security | 6.x | BCrypt密码加密 |
| **文档** | Springdoc OpenAPI | 2.2+ | API文档 |
| **工具** | Lombok | 1.18+ | 简化代码 |
| **JSON** | Jackson | 内置 | JSON序列化 |
| **文件** | 本地存储 / MinIO | - | V1先用本地V2可扩展 |
| **前端** | HTML + CSS + JS | - | 原生技术栈 |
#### 关键依赖库
| 用途 | 库 | 说明 |
|------|-----|------|
| 企业微信SDK | weixin-java-cp | 企业微信Java SDK |
| 文件预览 | kkFileView / OnlyOffice | 文档在线预览(可选外部服务) |
| 视频播放 | video.js | 前端视频播放器 |
| Excel导入导出 | EasyExcel | 阿里开源,性能好 |
| 工具库 | Hutool | 常用工具集合 |
### 7.4 风险评估
| 风险点 | 等级 | 描述 | 应对策略 |
|--------|------|------|----------|
| **企业微信对接** | 🟡 中 | 需要企业微信管理员配置应用 | 提前准备配置文档,预留账号密码登录作为备选 |
| **文件预览** | 🟡 中 | 不同格式文档预览兼容性 | V1优先支持PDF+图片+视频,复杂格式提示下载 |
| **大文件上传** | 🟡 中 | 视频文件可能较大 | 限制单文件大小,支持分片上传 |
| **考试并发** | 🟢 低 | 500人规模并发压力不大 | 合理设计索引,必要时加缓存 |
| **数据隔离** | 🟢 低 | 部门数据隔离逻辑 | 统一在Service层实现隔离过滤 |
### 7.5 项目结构
```
training-system/
├── pom.xml
├── src/
│ └── main/
│ ├── java/com/sino/training/
│ │ ├── TrainingApplication.java # 启动类
│ │ │
│ │ ├── common/ # 通用模块
│ │ │ ├── config/ # 配置类
│ │ │ ├── exception/ # 异常处理
│ │ │ ├── result/ # 统一响应
│ │ │ ├── interceptor/ # 拦截器
│ │ │ └── utils/ # 工具类
│ │ │
│ │ ├── module/ # 业务模块
│ │ │ ├── auth/ # 认证模块
│ │ │ ├── system/ # 系统管理
│ │ │ ├── knowledge/ # 知识库模块
│ │ │ ├── exam/ # 考试模块
│ │ │ └── training/ # 培训模块
│ │ │
│ │ └── integration/ # 外部集成
│ │ └── wechat/ # 企业微信
│ │
│ └── resources/
│ ├── application.yml # 主配置
│ ├── application-dev.yml # 开发环境
│ ├── application-prod.yml # 生产环境
│ ├── mapper/ # MyBatis XML
│ ├── static/ # 静态资源
│ └── templates/ # 页面模板
├── docs/
│ └── PRD.md # 产品需求文档
└── sql/
└── init.sql # 数据库初始化脚本
```
---
## 八、附录
### 8.1 角色菜单权限对照表
| 菜单 | 管理员 | 讲师 | 学员 |
|------|--------|------|------|
| 工作台 | ✅ | ✅ | ✅ |
| 组织架构管理 | ✅ | ❌ | ❌ |
| 员工管理 | ✅ | 👁️ 本部门只读 | ❌ |
| 讲师管理 | ✅ | ❌ | ❌ |
| 知识库-分类管理 | ✅ | ✅ 本部门 | ❌ |
| 知识库-知识列表 | ✅ | ✅ 本部门 | 👁️ 本部门已发布 |
| 考题管理-题库分类 | ✅ | ✅ 本部门 | ❌ |
| 考题管理-题目列表 | ✅ | ✅ 本部门 | ❌ |
| 试卷管理 | ✅ | ✅ 本部门 | ❌ |
| 考试管理 | ✅ | ✅ 本部门 | 👁️ 我的考试 |
| 培训计划 | ✅ | ✅ 本部门 | 👁️ 我的培训 |
| 系统设置 | ✅ | ❌ | ❌ |
### 8.2 状态枚举定义
```java
// 内容状态
public enum ContentStatus {
DRAFT, // 草稿
PUBLISHED, // 已发布
OFFLINE // 已下架
}
// 用户角色
public enum UserRole {
ADMIN, // 管理员
LECTURER, // 讲师
STUDENT // 学员
}
// 用户状态
public enum UserStatus {
ENABLED, // 启用
DISABLED // 禁用
}
// 题目类型
public enum QuestionType {
SINGLE, // 单选题
MULTIPLE, // 多选题
JUDGE // 判断题
}
// 知识类型
public enum KnowledgeType {
DOCUMENT, // 文档
VIDEO // 视频
}
// 考试/培训目标类型
public enum TargetType {
DEPARTMENT, // 部门
GROUP, // 小组
USER // 个人
}
// 考试状态
public enum ExamStatus {
NOT_STARTED, // 未开始
IN_PROGRESS, // 进行中
ENDED // 已结束
}
// 培训计划状态
public enum PlanStatus {
NOT_STARTED, // 未开始
IN_PROGRESS, // 进行中
ENDED // 已结束
}
```
---
**文档状态:已确认,等待开发启动**

View File

@@ -0,0 +1,554 @@
# V2 统计报表中心 - 产品需求文档
> 版本V2.0.0-draft
> 作者Product Agent
> 日期2026-02-04
> 状态:待评审
---
## 一、功能概述
### 1.1 背景与目标
**背景**V1 版本完成了培训系统的基础功能,但管理层无法量化培训效果,讲师无法追踪学员学习情况,缺乏数据支撑决策。
**目标**:构建统计报表中心,让培训效果可量化、可追踪、可对比。
### 1.2 目标用户
| 角色 | 核心诉求 |
|------|----------|
| **管理员** | 全局数据概览,跨部门对比,发现问题部门 |
| **讲师** | 本部门数据,学员学习进度,考试成绩分布 |
| **学员** | 个人学习记录,成绩趋势,与平均水平对比 |
### 1.3 功能边界
| 范围 | 说明 |
|------|------|
| **包含** | 数据看板、培训统计、考试统计、学员统计、数据导出 |
| **不包含** | 实时监控、预测分析、自定义报表设计器 |
---
## 二、功能清单
### 2.1 模块总览
```
统计报表中心
├── 2.1 数据概览看板
│ ├── 关键指标卡片
│ ├── 趋势图表
│ └── 快捷入口
├── 2.2 培训统计
│ ├── 培训计划完成率
│ ├── 知识学习统计
│ └── 部门培训排名
├── 2.3 考试统计
│ ├── 考试通过率
│ ├── 成绩分布
│ └── 题目正确率分析
├── 2.4 学员统计
│ ├── 学员学习排行
│ ├── 个人学习报告
│ └── 学习时长统计
└── 2.5 数据导出
├── Excel 导出
└── 定期报表
```
---
## 三、详细需求
### 3.1 数据概览看板
#### 3.1.1 功能描述
为不同角色提供个性化的数据概览首页,一目了然掌握关键指标。
#### 3.1.2 管理员看板
**关键指标卡片4个**
| 指标 | 计算方式 | 对比 |
|------|----------|------|
| 总学员数 | 状态=启用的学员数量 | 较上月增减 |
| 本月培训完成率 | 本月已完成培训人次 / 本月应完成培训人次 | 较上月变化 |
| 本月考试通过率 | 本月通过考试人次 / 本月参考人次 | 较上月变化 |
| 活跃学员数 | 本月有学习行为的学员数 | 较上月增减 |
**趋势图表**
- 近6个月培训完成率趋势折线图
- 近6个月考试通过率趋势折线图
- 部门培训完成率排名横向柱状图TOP 8
**快捷入口**
- 查看详细培训报表
- 查看详细考试报表
- 导出月度汇总
#### 3.1.3 讲师看板
**关键指标卡片4个**
| 指标 | 范围 |
|------|------|
| 本部门学员数 | 本部门 |
| 本部门培训完成率 | 本部门本月 |
| 本部门考试通过率 | 本部门本月 |
| 待批阅数 | 如有主观题V2暂无 |
**趋势图表**
- 本部门近6个月培训完成率趋势
- 本部门学员学习进度分布(饼图:已完成/进行中/未开始)
#### 3.1.4 学员看板
**关键指标卡片4个**
| 指标 | 说明 |
|------|------|
| 我的培训进度 | 已完成/总计划数 |
| 我的考试成绩 | 最近一次考试分数 |
| 学习排名 | 在本部门的排名 |
| 累计学习时长 | 总学习时长 |
**图表**
- 我的成绩趋势近5次考试
- 与部门平均分对比
#### 3.1.5 验收标准
```gherkin
Feature: 数据概览看板
Scenario: 管理员查看全局看板
Given 我是管理员角色
When 我进入统计报表中心
Then 我应该看到4个关键指标卡片
And 我应该看到培训完成率趋势图
And 我应该看到部门排名图表
And 所有数据应反映全平台数据
Scenario: 讲师查看部门看板
Given 我是讲师角色
When 我进入统计报表中心
Then 所有数据应仅包含本部门数据
And 我不应该看到其他部门的数据
Scenario: 指标卡片显示环比变化
Given 当前月份培训完成率为 80%
And 上月培训完成率为 75%
When 我查看培训完成率卡片
Then 应显示 "+5%" 的环比增长标记
And 增长应显示为绿色
```
---
### 3.2 培训统计
#### 3.2.1 培训计划完成率
**筛选条件**
- 时间范围:本月/本季度/本年度/自定义
- 部门:全部/指定部门(管理员可选)
- 培训计划:全部/指定计划
**统计维度**
| 维度 | 指标 |
|------|------|
| 按计划 | 计划名称、应参加人数、实际完成人数、完成率 |
| 按部门 | 部门名称、计划数、完成率、排名 |
| 按时间 | 月度完成率趋势 |
**列表展示**
| 培训计划 | 部门 | 应参加 | 已完成 | 完成率 | 状态 |
|----------|------|--------|--------|--------|------|
| 2026Q1安全培训 | 救援一部 | 50 | 45 | 90% | 进行中 |
| 新员工入职培训 | 救援二部 | 20 | 20 | 100% | 已结束 |
#### 3.2.2 知识学习统计
**统计内容**
- 知识总数、已发布数
- 学习总人次
- 热门知识 TOP 10按学习人次
- 最少学习知识(提醒优化或下架)
#### 3.2.3 验收标准
```gherkin
Feature: 培训统计
Scenario: 按部门查看培训完成率
Given 我是管理员
When 我选择按部门维度查看
Then 应显示所有部门的培训完成率列表
And 列表应按完成率降序排列
And 应显示部门排名
Scenario: 筛选指定时间范围
Given 我在培训统计页面
When 我选择时间范围为 "2026年1月"
Then 所有数据应仅包含该月份的培训数据
Scenario: 导出培训报表
Given 我在培训统计页面
When 我点击导出按钮
Then 应下载 Excel 文件
And 文件应包含当前筛选条件下的所有数据
```
---
### 3.3 考试统计
#### 3.3.1 考试通过率
**筛选条件**
- 时间范围:本月/本季度/本年度/自定义
- 部门:全部/指定部门
- 考试:全部/指定考试
**统计指标**
| 指标 | 说明 |
|------|------|
| 参考人数 | 实际参加考试的人数 |
| 通过人数 | 分数 >= 及格线的人数 |
| 通过率 | 通过人数 / 参考人数 |
| 平均分 | 所有考生的平均分数 |
| 最高分 / 最低分 | 分数极值 |
#### 3.3.2 成绩分布
**图表展示**
- 分数段分布柱状图0-59 / 60-69 / 70-79 / 80-89 / 90-100
- 各部门平均分对比(横向柱状图)
**列表展示**
| 考试名称 | 参考人数 | 通过率 | 平均分 | 最高分 | 最低分 |
|----------|----------|--------|--------|--------|--------|
| 安全规范考核 | 120 | 85% | 78.5 | 98 | 42 |
| 月度技能测试 | 95 | 72% | 71.2 | 100 | 35 |
#### 3.3.3 题目正确率分析
**功能描述**:分析每道题的正确率,发现难题和易错题。
**统计内容**
| 字段 | 说明 |
|------|------|
| 题目内容 | 题干摘要前50字 |
| 题型 | 单选/多选/判断 |
| 作答人次 | 该题被作答的总次数 |
| 正确率 | 正确人次 / 作答人次 |
| 错误选项分布 | 各错误选项的选择占比 |
**排序**
- 默认按正确率升序(易错题优先)
- 可切换按作答人次排序
**用途**
- 正确率 < 30% 的题目可能题目有问题或知识点难度大
- 正确率 > 95% 的题目:可能过于简单
#### 3.3.4 验收标准
```gherkin
Feature: 考试统计
Scenario: 查看考试成绩分布
Given 我在考试统计页面
When 我选择某场考试
Then 应显示分数段分布柱状图
And 应显示通过率、平均分等指标
Scenario: 查看题目正确率
Given 我在考试统计页面
When 我点击 "题目分析"
And 选择某场考试
Then 应显示该考试所有题目的正确率
And 默认按正确率升序排列
And 可以查看每道题的错误选项分布
Scenario: 识别易错题
Given 某道题的正确率为 25%
When 我查看题目分析列表
Then 该题应标记为 "易错题"
And 应显示主要错误选项
```
---
### 3.4 学员统计
#### 3.4.1 学员学习排行
**排行维度**
- 学习时长排行(本月/本季度)
- 考试成绩排行(平均分/最高分)
- 培训完成数排行
**展示内容**
| 排名 | 学员 | 部门 | 学习时长 | 完成培训数 | 平均分 |
|------|------|------|----------|------------|--------|
| 1 | 张三 | 救援一部 | 45h | 8 | 92 |
| 2 | 李四 | 救援二部 | 42h | 7 | 88 |
**范围控制**
- 管理员:可查看全平台排行
- 讲师:仅可查看本部门排行
- 学员:可查看本部门排行,自己会高亮显示
#### 3.4.2 个人学习报告
**入口**
- 讲师点击学员姓名进入
- 学员点击"我的学习报告"进入
**报告内容**
| 模块 | 内容 |
|------|------|
| 基本信息 | 姓名、部门、入职时间、角色 |
| 学习概览 | 累计学习时长、完成培训数、参加考试数 |
| 培训记录 | 参加的培训计划列表,包含进度和状态 |
| 考试记录 | 参加的考试列表,包含成绩和是否通过 |
| 成绩趋势 | 近10次考试成绩折线图 |
| 能力雷达图 | 按知识分类的掌握程度(基于考试正确率) |
#### 3.4.3 学习时长统计
**统计规则**
- 知识学习:从打开到关闭/切换的时长上限30分钟/次)
- 视频学习:实际播放时长
- 考试时长:从开始到交卷的时长
**展示**
- 个人:日/周/月学习时长统计
- 部门:部门平均学习时长、学习时长分布
#### 3.4.4 验收标准
```gherkin
Feature: 学员统计
Scenario: 查看学习排行榜
Given 我是讲师
When 我进入学员排行榜页面
Then 应显示本部门学员排行
And 不应显示其他部门学员
Scenario: 查看个人学习报告
Given 我是讲师
When 我点击某学员的姓名
Then 应进入该学员的学习报告页面
And 应显示该学员的培训记录
And 应显示该学员的考试记录
And 应显示成绩趋势图
Scenario: 学员查看自己的报告
Given 我是学员
When 我点击 "我的学习报告"
Then 应显示我的学习报告
And 应显示我在部门中的排名
```
---
### 3.5 数据导出
#### 3.5.1 Excel 导出
**支持导出的报表**
| 报表 | 内容 | 权限 |
|------|------|------|
| 培训完成率报表 | 按计划/部门的完成率明细 | 管理员、讲师 |
| 考试成绩报表 | 学员成绩明细 | 管理员、讲师 |
| 学员学习报表 | 学员学习时长和完成情况 | 管理员、讲师 |
| 题目分析报表 | 题目正确率明细 | 管理员、讲师 |
**导出规则**
- 导出当前筛选条件下的数据
- 文件名格式:`报表类型_日期_导出人.xlsx`
- 单次导出上限10000 条记录
#### 3.5.2 验收标准
```gherkin
Feature: 数据导出
Scenario: 导出考试成绩报表
Given 我在考试统计页面
And 当前筛选条件为 "2026年1月"
When 我点击导出按钮
Then 应下载 Excel 文件
And 文件名应为 "考试成绩报表_20260204_张三.xlsx"
And 数据应仅包含20261月的考试成绩
Scenario: 导出数据量限制
Given 当前筛选条件下有 15000 条记录
When 我点击导出按钮
Then 应提示 "数据量超过限制,请缩小筛选范围"
```
---
## 四、数据模型(建议)
### 4.1 新增统计表(可选,用于性能优化)
#### 日统计汇总表 (stat_daily_summary)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Long | 主键 |
| stat_date | Date | 统计日期 |
| department_id | Long | 部门ID0=全平台) |
| total_users | Integer | 学员总数 |
| active_users | Integer | 活跃学员数 |
| training_complete_count | Integer | 培训完成人次 |
| exam_pass_count | Integer | 考试通过人次 |
| exam_total_count | Integer | 考试参与人次 |
| total_learning_minutes | Long | 总学习时长(分钟) |
#### 学习时长记录表 (stat_learning_log)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Long | 主键 |
| user_id | Long | 用户ID |
| knowledge_id | Long | 知识ID |
| start_time | DateTime | 开始时间 |
| end_time | DateTime | 结束时间 |
| duration_seconds | Integer | 学习时长(秒) |
| create_time | DateTime | 创建时间 |
---
## 五、页面原型
### 5.1 管理员数据看板
```
┌────────────────────────────────────────────────────────────────────────────┐
│ 统计报表中心 │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │ 总学员数 │ │ 培训完成率 │ │ 考试通过率 │ │ 活跃学员数 │ │
│ │ 486 │ │ 82% │ │ 78% │ │ 312 │ │
│ │ +12 ↑ │ │ +5% ↑ │ │ -2% ↓ │ │ +28 ↑ │ │
│ └────────────┘ └────────────┘ └────────────┘ └────────────┘ │
│ │
│ ┌─────────────────────────────────┐ ┌─────────────────────────────────┐ │
│ │ 培训完成率趋势 │ │ 部门培训完成率排名 │ │
│ │ │ │ │ │
│ │ 100%│ │ │ 救援一部 ████████████ 92% │ │
│ │ 80%│ ╭──╮ ╭──╮ │ │ 救援三部 ██████████ 85% │ │
│ │ 60%│╭──╯ ╰──╮╭╯ ╰── │ │ 救援二部 █████████ 80% │ │
│ │ 40%│ ╰ │ │ 救援四部 ███████ 72% │ │
│ │ └───────────────── │ │ 综合部 ██████ 65% │ │
│ │ 9 10 11 12 1 2 │ │ │ │
│ └─────────────────────────────────┘ └─────────────────────────────────┘ │
│ │
│ [查看培训详情] [查看考试详情] [导出月度报表] │
│ │
└────────────────────────────────────────────────────────────────────────────┘
```
### 5.2 考试统计页面
```
┌────────────────────────────────────────────────────────────────────────────┐
│ 统计报表中心 > 考试统计 │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ 时间范围: [本月 ▼] 部门: [全部 ▼] 考试: [全部 ▼] [查询] [导出] │
│ │
│ ┌─────────────────────────────────┐ ┌─────────────────────────────────┐ │
│ │ 成绩分布 │ │ 汇总指标 │ │
│ │ │ │ │ │
│ │ ┌───┐ │ │ 参考人数: 320 │ │
│ │ │ │ ┌───┐ │ │ 通过人数: 256 │ │
│ │ ┌───┐│ │ │ │ ┌───┐ │ │ 通过率: 80% │ │
│ │ │ ││ │ │ │ │ │ ┌───┐ │ │ 平均分: 76.5 │ │
│ │ │ ││ │ │ │ │ │ │ │ │ │ 最高分: 100 │ │
│ │ └───┘└───┘ └───┘ └───┘ └───┘ │ │ 最低分: 32 │ │
│ │ 0-59 60-69 70-79 80-89 90-100 │ │ │ │
│ └─────────────────────────────────┘ └─────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────────────────┐ │
│ │ 考试名称 参考人数 通过率 平均分 最高分 操作 │ │
│ ├──────────────────────────────────────────────────────────────────────┤ │
│ │ 安全规范考核 120 85% 78.5 98 [详情][分析] │ │
│ │ 月度技能测试 95 72% 71.2 100 [详情][分析] │ │
│ │ 新员工入职考试 45 91% 82.3 96 [详情][分析] │ │
│ └──────────────────────────────────────────────────────────────────────┘ │
│ │
│ < 1 2 3 > │
└────────────────────────────────────────────────────────────────────────────┘
```
---
## 六、非功能需求
| 类型 | 要求 |
|------|------|
| **性能** | 看板页面加载时间 < 2秒 |
| **性能** | 报表查询响应时间 < 3秒万级数据 |
| **兼容性** | 支持 ChromeEdgeFirefox 最新版本 |
| **数据安全** | 严格按角色和部门隔离数据 |
| **导出** | Excel 导出支持 .xlsx 格式 |
---
## 七、不做什么Out of Scope
| 排除项 | 原因 |
|--------|------|
| 实时数据监控 | V2 不需要实时性T+1 统计即可 |
| 自定义报表设计器 | 复杂度高用户需求不明确 |
| 数据预测/AI分析 | 数据量不足价值有限 |
| 打印报表 | 使用 Excel 导出替代 |
---
## 八、里程碑建议
| 阶段 | 内容 | 建议周期 |
|------|------|----------|
| M1 | 数据看板管理员+讲师+学员 | - |
| M2 | 培训统计 + 考试统计 | - |
| M3 | 学员统计 + 数据导出 | - |
| M4 | 测试 + 优化 | - |
---
## 九、开放问题
| 问题 | 待确认 |
|------|--------|
| 学习时长统计是否需要精确到秒级 | 建议分钟级即可 |
| 是否需要支持定时自动发送报表邮件 | 建议 V3 考虑 |
| 能力雷达图的维度如何定义 | 建议按知识分类一级目录 |
---
**文档状态:待评审**

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,664 @@
# 学员端功能需求文档
> 版本V1.0.1
> 创建日期2026-01-15
> 更新日期2026-01-15
> 状态:✅ 已批准Supervisor 复审通过)
---
## 版本更新记录
### V1.0.1 (2026-01-15)
**根据Supervisor审查意见修订**
| 修订项 | 修订内容 |
|--------|----------|
| 知识学习入口 | 补充培训任务学习场景、返回逻辑、来源区分 |
| 断点续考机制 | 补充定时任务策略、超时判定规则、并发处理 |
| 排名计算规则 | 明确计算时机、统计范围、口径定义 |
| 学习时长防刷 | 新增活跃检测机制 |
| 数据表设计 | km_knowledge_progress 新增 department_id 字段 |
| 页面路径 | 调整为复用现有路径,按角色控制 |
| 解析显示策略 | 明确交卷后立即显示解析 |
| 非功能需求 | 补充可测试的性能指标 |
---
## 一、概述
### 1.1 目标用户
- **角色**学员STUDENT
- **人数**约450人
- **入口**PC浏览器与管理端共用系统按角色显示不同菜单
### 1.2 核心目标
为学员提供便捷的在线学习平台,支持知识学习、在线考试、培训计划跟踪,帮助学员提升专业技能。
---
## 二、功能模块总览
| 模块 | 功能点 | 优先级 |
|------|--------|--------|
| 工作台 | 学习概览、待办事项 | P0 |
| 知识学习 | 知识浏览、学习进度、时长统计 | P0 |
| 在线考试 | 考试列表、在线答题、断点续考、成绩排名 | P0 |
| 我的培训 | 培训计划、进度跟踪、完成判定 | P0 |
| 个人中心 | 学习记录、考试记录、证书(预留) | P1 |
---
## 三、详细功能需求
### 3.1 工作台(首页)
#### 用户故事
> 作为学员,我希望登录后看到学习概览和待办事项,以便快速了解学习状态和接下来要做的事。
#### 功能清单
| 功能项 | 说明 |
|--------|------|
| 学习统计卡片 | 显示:待学习课程数、待完成考试数、培训进度百分比 |
| 我的培训计划 | 列表展示分配给我的培训计划最多显示5条显示进度 |
| 待完成考试 | 列表展示待完成的考试最多显示5条显示截止时间 |
| 快捷入口 | 点击可直接进入对应详情页 |
#### 验收标准
- [ ] 登录后默认进入工作台页面
- [ ] 统计数据实时准确(待学习=未完成的必修知识数,待考试=未通过的必考考试数)
- [ ] 培训进度百分比 = 已完成必修项 / 总必修项 × 100%
- [ ] 点击培训计划可跳转到计划详情
- [ ] 点击考试可跳转到考试页面
- [ ] 只显示"进行中"状态的培训计划和处于"时间窗口内"的考试
---
### 3.2 知识学习
#### 用户故事
> 作为学员,我希望浏览本部门的知识库,学习文档和视频,并能看到自己的学习进度。
#### 功能清单
| 功能项 | 说明 |
|--------|------|
| 知识分类导航 | 左侧树形结构展示知识分类 |
| 知识列表 | 按分类筛选,显示知识标题、类型、学习状态 |
| 知识详情/预览 | 文档在线预览、视频在线播放 |
| 学习进度记录 | 记录学习完成状态、学习时长 |
| 强制学习机制 | 视频必须播放完成、文档必须阅读完成才记录为"已完成" |
#### 3.2.1 知识列表页
**页面元素**
- 分类筛选(树形)
- 知识卡片列表:标题、类型图标(文档/视频)、学习状态标签、时长/大小
- 搜索框(按标题搜索)
**学习状态**
| 状态 | 说明 | 显示样式 |
|------|------|----------|
| 未学习 | 从未打开过 | 灰色标签 |
| 学习中 | 已开始但未完成 | 蓝色标签 + 进度% |
| 已完成 | 满足完成条件 | 绿色标签 ✓ |
#### 3.2.2 知识详情页
**文档类型**
- 在线预览PDF直接显示Word/Excel/PPT转换预览
- 学习计时:进入页面开始计时,离开页面停止
- 完成条件:停留时间 ≥ 预估阅读时间(可配置,默认按页数计算)
**视频类型**
- 在线播放(支持进度条、全屏)
- 播放进度记录:记录当前播放位置,下次打开从断点继续
- 完成条件:播放进度 ≥ 90%(可配置)
- 禁止拖动快进(强制学习模式下)
#### 3.2.3 学习入口场景(🔴 修订项1
**场景一:自由学习(从知识库进入)**
- 入口:左侧菜单"知识库" → 知识列表 → 知识详情
- 学习完成后:停留在知识详情页,可点击"返回列表"
- 进度记录:标记来源为 `FREE`(自由学习)
**场景二:培训任务学习(从培训计划进入)**
- 入口:培训详情页 → 点击知识项 → 知识详情
- 页面顶部显示:返回培训计划入口(如:"← 返回《2026年Q1安全规范培训》"
- 学习完成后:
- 自动弹出提示:"学习完成!是否返回培训计划?"
- 用户可选择【返回培训】或【继续浏览】
- 进度记录:标记来源为 `TRAINING`(培训任务),关联 `plan_id`
**进度记录来源区分**
| 来源 | 场景 | 影响 |
|------|------|------|
| FREE | 自由学习 | 仅记录个人学习进度 |
| TRAINING | 培训任务学习 | 同时更新培训计划进度 |
> **说明**:无论从哪个入口学习,学习时长和完成状态都会记录。区分来源是为了后续统计分析(如:培训驱动的学习 vs 自主学习)。
#### 3.2.4 学习时长防刷机制(🟡 优化项1
**文档类型防刷策略**
- 每60秒检测一次用户活跃状态
- 活跃判定60秒内有鼠标移动、点击、滚动任一事件
- 非活跃时:暂停计时,页面显示"检测到您暂时离开,学习计时已暂停"
- 恢复活跃后:继续计时
**视频类型防刷策略**
- 依赖视频播放事件,暂停时不计时长
- 无需额外活跃检测
**多标签页处理**
- 同一知识同时只能在一个标签页学习
- 检测到多标签页打开同一知识时,后打开的标签页提示"该知识已在其他窗口学习中"
#### 验收标准
- [ ] 只显示本部门、已发布状态的知识
- [ ] 分类树正确展示,点击分类筛选对应知识
- [ ] 文档能正常在线预览至少支持PDF
- [ ] 视频能正常播放,支持暂停、音量调节
- [ ] 视频播放进度自动保存,刷新页面后从断点继续
- [ ] 强制学习模式下,视频不能快进跳过
- [ ] 学习时长准确记录(精确到秒)
- [ ] 满足完成条件后自动标记为"已完成"
- [ ] 学习进度与培训计划进度联动
- [ ] 🔴 从培训计划进入的知识学习,顶部显示返回入口
- [ ] 🔴 学习完成后弹出返回培训计划提示(仅培训任务学习场景)
- [ ] 🟡 文档学习时,非活跃状态暂停计时
- [ ] 🟡 同一知识不能在多个标签页同时学习
---
### 3.3 在线考试
#### 用户故事
> 作为学员,我希望参加分配给我的考试,并能查看成绩和排名。
#### 功能清单
| 功能项 | 说明 |
|--------|------|
| 考试列表 | 展示分配给我的所有考试 |
| 考试详情 | 显示考试信息、我的考试记录 |
| 在线答题 | 单选/多选/判断题作答 |
| 断点续考 | 中途退出后可继续答题 |
| 自动交卷 | 时间到自动提交 |
| 成绩查看 | 显示得分、答案解析 |
| 成绩排名 | 显示我在本次考试中的排名 |
#### 3.3.1 考试列表页
**列表字段**
| 字段 | 说明 |
|------|------|
| 考试名称 | 点击进入考试详情 |
| 考试时间 | 开始时间 ~ 结束时间 |
| 考试状态 | 未开始/进行中/已结束 |
| 我的状态 | 未参加/考试中/已完成 |
| 最高成绩 | 多次考试取最高分 |
| 剩余次数 | 最大次数 - 已考次数 |
| 操作 | 进入考试/查看成绩 |
**筛选条件**
- 考试状态:全部/进行中/已结束
- 我的状态:全部/未完成/已完成
#### 3.3.2 考试详情页(进入考试前)
**显示信息**
- 考试名称、考试时间窗口
- 考试规则:时长、总分、及格线、最大次数
- 我的考试记录表格第N次、得分、是否通过、时间
- 【开始考试】/【继续考试】按钮
**按钮逻辑**
| 场景 | 按钮状态 |
|------|----------|
| 不在时间窗口内 | 禁用,提示"考试未开始"或"考试已结束" |
| 次数已用完 | 禁用,提示"考试次数已用完" |
| 有进行中的考试记录 | 显示【继续考试】 |
| 可以开始新考试 | 显示【开始考试】 |
#### 3.3.3 在线答题页
**页面布局**
```
┌─────────────────────────────────────────────────────────┐
│ 考试名称 剩余时间: 45:23 │
├─────────────────────────────────────────────────────────┤
│ 第 3 题 / 共 20 题 [单选题] │
│ ───────────────────────────────────────────────────── │
│ 题干内容... │
│ │
│ ○ A. 选项A │
│ ● B. 选项B已选中
│ ○ C. 选项C │
│ ○ D. 选项D │
├─────────────────────────────────────────────────────────┤
│ 答题卡: [1✓] [2✓] [3●] [4○] [5○] ... │
├─────────────────────────────────────────────────────────┤
│ [上一题] [下一题] [交卷] │
└─────────────────────────────────────────────────────────┘
```
**功能说明**
| 功能 | 说明 |
|------|------|
| 倒计时 | 显示剩余时间最后5分钟变红色提醒 |
| 题目导航 | 点击答题卡数字可跳转到对应题目 |
| 答案自动保存 | 选择答案后自动保存到服务器每30秒或切题时 |
| 上一题/下一题 | 切换题目 |
| 交卷 | 弹出确认框,确认后提交 |
| 自动交卷 | 时间结束自动提交当前答案 |
**断点续考机制**
- 考试开始后创建考试记录,状态为"进行中"
- 答案实时保存到服务器
- 中途关闭浏览器/断网,考试记录保持"进行中"
- 重新打开考试,检测到进行中记录,恢复到上次状态
- 倒计时从剩余时间继续(服务端计算:考试时长 - 已用时间)
- 超时未提交的考试,由定时任务自动交卷
#### 3.3.5 超时自动交卷机制(🔴 修订项2
**超时判定规则**
```
超时时间点 = 考试记录开始时间 + 考试时长(分钟)
```
**示例**
- 学员A在 10:00 开始考试考试时长60分钟
- 超时时间点 = 10:00 + 60分钟 = 11:00
- 无论考试时间窗口是否结束11:00后该考试记录即视为超时
**定时任务策略**
| 配置项 | 值 | 说明 |
|--------|-----|------|
| 执行频率 | 每1分钟 | Cron: `0 */1 * * * ?` |
| 扫描范围 | 状态为IN_PROGRESS的考试记录 | 只处理进行中的记录 |
| 超时判定 | 当前时间 > 开始时间 + 考试时长 | 精确到秒 |
| 处理动作 | 自动提交当前已保存的答案,计算成绩 | 标记为系统自动交卷 |
**并发提交处理(乐观锁)**
```
场景学员在超时前1秒点击交卷同时定时任务也在处理该记录
```
**处理策略**
1. 考试记录表增加 `version` 字段(乐观锁)
2. 提交时检查 `status = IN_PROGRESS AND version = 当前版本`
3. 更新时 `version = version + 1`
4. 若更新失败version已变说明已被其他请求处理直接返回已提交的结果
**状态流转**
```
IN_PROGRESS ──用户主动交卷──▶ SUBMITTED来源USER
└──────定时任务超时交卷──▶ SUBMITTED来源SYSTEM_TIMEOUT
```
**交卷来源标记**
| 来源 | 说明 |
|------|------|
| USER | 用户主动交卷 |
| SYSTEM_TIMEOUT | 系统超时自动交卷 |
> **注意**:即使考试时间窗口已结束,只要考试记录未超时,学员仍可继续答题(但无法开始新的考试)
#### 3.3.6 考试结果页
**显示内容**
| 项目 | 说明 |
|------|------|
| 得分 | 大字显示,及格绿色/不及格红色 |
| 是否通过 | 通过✓ / 未通过✗ |
| 排名 | "您的成绩排名第 X 名(共 Y 人参加)" |
| 答题详情 | 每道题的正确答案、我的答案、解析 |
| 操作按钮 | 【再考一次】(有次数)/ 【返回列表】 |
**答案解析显示策略(🟡 优化项4**
- 交卷后立即显示所有题目的答案解析
- 无论考试是否通过,都显示解析
- 目的:培训学习为主,帮助学员理解错误原因
#### 3.3.7 排名计算规则(🔴 修订项3
**计算时机**
- 实时计算:每次交卷时计算排名
- 非定时计算:不采用批量定时计算方式
**统计范围**
- 范围:当前考试的所有参与者(被分配且已交卷的学员)
- 跨部门:若考试分配给多个部门,排名为所有参与者的总排名
**排名规则**
| 优先级 | 规则 | 说明 |
|--------|------|------|
| 1 | 最高成绩降序 | 成绩高的排名靠前 |
| 2 | 达到最高成绩的时间升序 | 成绩相同时,先达到该成绩的排名靠前 |
**"共Y人参加"统计口径**
| 统计项 | 是否计入 |
|--------|----------|
| 已交卷学员 | ✅ 计入 |
| 正在考试中(未交卷) | ❌ 不计入 |
| 被分配但未参加 | ❌ 不计入 |
**排名示例**
```
考试:安全规范考核
分配对象部门A30人、部门B20人
参与情况:
- 部门A25人已交卷5人未参加
- 部门B18人已交卷2人正在考试中
排名统计:共 43 人参加25 + 18 = 43
排名结果:
第1名张三95分首次达到时间 10:30
第2名李四95分首次达到时间 10:45
第3名王五90分
...
```
**实现建议**
- 交卷时实时计算排名并返回
- 排名计算SQL示例思路
```sql
SELECT user_id, MAX(score) as best_score, MIN(submit_time) as first_best_time
FROM ex_exam_record
WHERE exam_id = ? AND status = 'SUBMITTED'
GROUP BY user_id
ORDER BY best_score DESC, first_best_time ASC
```
#### 验收标准
- [ ] 只显示分配给当前学员的考试
- [ ] 考试状态、我的状态准确显示
- [ ] 不在时间窗口内无法进入考试
- [ ] 次数用完无法再次考试
- [ ] 答题过程中答案实时保存
- [ ] 刷新页面/重新进入可继续答题(断点续考)
- [ ] 倒计时准确,超时自动交卷
- [ ] 交卷后立即显示成绩和排名
- [ ] 答案解析正确显示
- [ ] 多次考试取最高分显示
- [ ] 🔴 定时任务每分钟执行,自动处理超时考试记录
- [ ] 🔴 并发交卷场景下数据一致(乐观锁机制)
- [ ] 🔴 排名实时计算,仅统计已交卷学员
- [ ] 🔴 排名规则:最高分优先,同分按首次达到时间排序
---
### 3.4 我的培训
#### 用户故事
> 作为学员,我希望查看分配给我的培训计划,跟踪学习进度,完成培训任务。
#### 功能清单
| 功能项 | 说明 |
|--------|------|
| 培训列表 | 展示分配给我的培训计划 |
| 培训详情 | 显示计划内容、学习进度 |
| 进度跟踪 | 实时显示知识学习、考试完成情况 |
| 完成判定 | 根据必修项判定培训是否完成 |
| 证书预留 | 培训完成后预留证书/徽章展示位置 |
#### 3.4.1 培训列表页
**列表字段**
| 字段 | 说明 |
|------|------|
| 培训名称 | 点击进入详情 |
| 培训周期 | 开始日期 ~ 结束日期 |
| 状态 | 未开始/进行中/已结束 |
| 我的进度 | 进度条 + 百分比 |
| 完成状态 | 未完成/已完成 |
#### 3.4.2 培训详情页
**页面结构**
```
┌─────────────────────────────────────────────────────────┐
│ 2026年Q1安全规范培训 │
│ ───────────────────────────────────────────────────── │
│ 培训周期2026-01-01 ~ 2026-03-31 │
│ 培训目标:掌握高速公路救援安全规范... │
│ 我的进度:████████░░░░ 75% │
├─────────────────────────────────────────────────────────┤
│ 📚 学习内容 (3/5) │
│ ├─ ✅ 高速救援SOP手册 [必修] [已完成] │
│ ├─ ✅ 安全操作视频 [必修] [已完成] │
│ ├─ 🔵 应急处理流程 [必修] [学习中 60%] │
│ ├─ ⚪ 设备使用指南 [选修] [未学习] │
│ └─ ✅ 案例分析 [选修] [已完成] │
├─────────────────────────────────────────────────────────┤
│ 📝 考试任务 (1/2) │
│ ├─ ✅ 安全规范考核 [必考] [已通过 85分] │
│ └─ ⚪ 操作技能测试 [必考] [未参加] │
├─────────────────────────────────────────────────────────┤
│ 🏆 完成奖励 │
│ └─ 完成培训后可获得【安全规范认证】徽章(敬请期待) │
└─────────────────────────────────────────────────────────┘
```
**进度计算规则**
```
培训进度 = (已完成必修知识数 + 已通过必考考试数) / (必修知识总数 + 必考考试总数) × 100%
```
**完成判定规则**
| 条件 | 说明 |
|------|------|
| 所有必修知识已完成 | ✓ |
| 所有必考考试已通过 | ✓ |
| 选修知识 | 不影响完成判定 |
| 选考考试 | 不影响完成判定 |
#### 验收标准
- [ ] 只显示分配给当前学员的培训计划
- [ ] 进度百分比计算准确(只计算必修项)
- [ ] 学习内容、考试任务分开展示
- [ ] 显示每项的必修/选修、必考/选考标签
- [ ] 点击知识内容可跳转到知识详情页
- [ ] 点击考试任务可跳转到考试页面
- [ ] 所有必修项完成后,培训状态变为"已完成"
- [ ] 证书/徽章区域预留V1显示"敬请期待"
---
### 3.5 个人中心
#### 用户故事
> 作为学员,我希望查看自己的学习记录、考试历史和获得的证书。
#### 功能清单
| 功能项 | 说明 |
|--------|------|
| 个人信息 | 显示姓名、部门、角色 |
| 学习统计 | 总学习时长、完成课程数 |
| 学习记录 | 知识学习历史列表 |
| 考试记录 | 考试历史列表 |
| 我的证书 | 证书/徽章展示(预留) |
#### 验收标准
- [ ] 正确显示当前用户信息
- [ ] 学习时长统计准确(累计所有知识学习时长)
- [ ] 学习记录按时间倒序展示
- [ ] 考试记录显示每次考试的详情
- [ ] 证书模块预留V1显示"暂无证书"
---
## 四、数据契约补充
### 4.1 新增/修改实体
#### 知识学习进度表 (km_knowledge_progress) - 新增
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Long | 主键 |
| user_id | Long | 学员ID |
| knowledge_id | Long | 知识ID |
| department_id | Long | **🟡 新增** 所属部门(冗余字段,便于按部门统计) |
| status | Enum | 状态NOT_STARTED/IN_PROGRESS/COMPLETED |
| progress | Integer | 进度百分比0-100 |
| duration | Long | 学习时长(秒) |
| video_position | Long | 视频播放位置(秒),仅视频类型 |
| source | Enum | **🔴 新增** 学习来源FREE/TRAINING |
| plan_id | Long | **🔴 新增** 关联培训计划ID来源为TRAINING时有值 |
| start_time | DateTime | 首次学习时间 |
| complete_time | DateTime | 完成时间 |
| update_time | DateTime | 最后更新时间 |
#### 考试记录表 (ex_exam_record) - 补充字段
| 字段 | 类型 | 说明 |
|------|------|------|
| status | Enum | **新增** 状态IN_PROGRESS/SUBMITTED |
| last_save_time | DateTime | **新增** 最后保存时间(断点续考用) |
| version | Integer | **🔴 新增** 乐观锁版本号 |
| submit_source | Enum | **🔴 新增** 交卷来源USER/SYSTEM_TIMEOUT |
### 4.2 新增枚举
```java
// 学习状态
public enum LearningStatus {
NOT_STARTED, // 未学习
IN_PROGRESS, // 学习中
COMPLETED // 已完成
}
// 🔴 学习来源
public enum LearningSource {
FREE, // 自由学习(从知识库直接进入)
TRAINING // 培训任务学习(从培训计划进入)
}
// 考试记录状态
public enum ExamRecordStatus {
IN_PROGRESS, // 考试中(用于断点续考)
SUBMITTED // 已提交
}
// 🔴 交卷来源
public enum SubmitSource {
USER, // 用户主动交卷
SYSTEM_TIMEOUT // 系统超时自动交卷
}
```
---
## 五、接口预留V2/V3功能
### 5.1 证书/徽章接口(预留)
```
POST /api/certificate/generate # 生成证书
GET /api/certificate/my # 我的证书列表
GET /api/certificate/{id} # 证书详情
GET /api/badge/my # 我的徽章列表
```
### 5.2 错题本接口V2预留
```
GET /api/wrong-questions # 错题列表
POST /api/wrong-questions/review # 标记已复习
```
---
## 六、非功能需求
| 项目 | 要求 | 测试指标(🟡 优化项5 |
|------|------|------------------------|
| 页面加载 | 页面加载 < 2秒 | 95%请求 < 2秒 |
| 考试提交 | 考试提交 < 1秒 | 99%请求 < 1秒 |
| 并发支持 | 支持100人同时在线考试 | 100并发答题响应时间 < 500ms成功率 > 99.9% |
| 答案保存 | 答案自动保存 | 保存成功率 > 99.99%,保存延迟 < 300ms |
| 数据安全 | 考试答案定时自动保存,防止数据丢失 | 断网重连后数据无丢失 |
| 兼容性 | 支持主流浏览器 | Chrome 90+、Edge 90+、Firefox 90+ |
---
## 七、不做什么Out of Scope
| 功能 | 原因 |
|------|------|
| 移动端适配 | V1仅支持PC浏览器 |
| 防作弊功能 | 产品确认不需要 |
| 学习日历 | 产品确认不需要 |
| 错题本 | V2规划 |
| 社交功能(评论、点赞) | V3规划 |
---
## 八、页面清单(🟡 优化项3
> **说明**:采用与管理端复用同一套系统的方案,按角色控制菜单和功能显示,不使用独立的 `/student/` 路径前缀。
| 页面 | 路径 | 角色可见 | 说明 |
|------|------|----------|------|
| 工作台 | /index.html | 全角色 | 根据角色显示不同内容 |
| 知识列表 | /knowledge/list.html | 全角色 | 学员只读,讲师可管理 |
| 知识详情 | /knowledge/view.html?id={id} | 全角色 | 学员增加学习进度记录 |
| 考试列表 | /exam/my-exams.html | 学员 | 我的考试列表 |
| 考试详情 | /exam/detail.html?id={id} | 学员 | 考试信息页 |
| 在线答题 | /exam/answer.html?id={id} | 学员 | 答题页面 |
| 考试结果 | /exam/result.html?recordId={id} | 学员 | 成绩结果页 |
| 培训列表 | /training/my-training.html | 学员 | 我的培训列表 |
| 培训详情 | /training/detail.html?id={id} | 学员 | 培训计划详情 |
| 个人中心 | /profile/index.html | 全角色 | 个人信息页 |
| 学习记录 | /profile/learning.html | 学员 | 学习记录列表 |
| 考试记录 | /profile/exam-history.html | 学员 | 考试记录列表 |
| 我的证书 | /profile/certificate.html | 学员 | 证书展示(预留) |
**菜单权限控制**
| 菜单项 | 管理员 | 讲师 | 学员 |
|--------|--------|------|------|
| 工作台 | ✅ | ✅ | ✅ |
| 知识库 | ✅ 管理 | ✅ 管理 | ✅ 只读学习 |
| 考题管理 | ✅ | ✅ | ❌ |
| 试卷管理 | ✅ | ✅ | ❌ |
| 考试管理 | ✅ | ✅ | ❌ |
| 我的考试 | ❌ | ❌ | ✅ |
| 培训计划 | ✅ | ✅ | ❌ |
| 我的培训 | ❌ | ❌ | ✅ |
| 个人中心 | ✅ | ✅ | ✅ |
| 系统设置 | ✅ | ❌ | ❌ |
---
## 九、修订项对照表
| 修订项 | 类型 | 章节位置 | 状态 |
|--------|------|----------|------|
| 知识学习入口场景 | 🔴 必须修正 | 3.2.3 | ✅ 已补充 |
| 断点续考超时机制 | 🔴 必须修正 | 3.3.5 | ✅ 已补充 |
| 排名计算规则 | 🔴 必须修正 | 3.3.7 | ✅ 已补充 |
| 学习时长防刷机制 | 🟡 建议优化 | 3.2.4 | ✅ 已采纳 |
| 数据表department_id | 🟡 建议优化 | 4.1 | ✅ 已采纳 |
| 页面路径设计 | 🟡 建议优化 | 8 | ✅ 已调整 |
| 答案解析显示策略 | 🟡 建议优化 | 3.3.6 | ✅ 已明确 |
| 非功能需求测试指标 | 🟡 建议优化 | 6 | ✅ 已补充 |
---
**文档状态:✅ 已批准**
> **Supervisor 复审结论**:通过
> **复审日期**2026-01-15
> **下一阶段**:技术评审 → 开发