9.3 KiB
9.3 KiB
培训计划模块(training)
证据来源:[SRC-FEAT-01] [SRC-FEAT-02] [SRC-SQL-01] [SRC-API-01] [SRC-CODE-01:module/training/]
1. 模块定位
- 模块目标:将知识内容和考试任务组合成有时间范围的培训计划,分配给指定学员,并跟踪每位学员的完成进度。
- 解决问题:组织端无法跟踪员工是否真正完成学习目标;培训计划模块实现"分配→执行→进度可视"的闭环管理。
2. 功能清单
[SRC-FEAT-01:模块六] [SRC-FEAT-02:3.4 我的培训] [SRC-API-01:4.5]
| 功能名称 | 功能描述 | 输入 | 输出 | 依赖模块 |
|---|---|---|---|---|
| 创建培训计划 | 设置计划基本信息(名称/描述/时间范围/所属部门) | TrainingPlanQueryDTO(title, 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 | - |
| 培训计划详情(讲师端) | 查看计划详情,含关联知识/考试/对象/进度汇总 | planId | TrainingPlanDetailVO | - |
| 更新/删除培训计划 | 修改计划信息(未开始时可修改,进行中时受限) | planId, TrainingPlanQueryDTO | - | - |
| 学员-我的培训列表 | 查询分配给当前学员的培训计划(进行中优先) | - | PageResult<TrainingPlanVO + 进度> | auth |
| 学员-培训详情 | 查看某培训计划详情:课程列表+学习状态+考试列表+通过状态 | planId | TrainingDetailVO | knowledge, exam |
| 进度计算 | 按必修知识完成数 + 必考通过数 / 总必修项 计算进度% | planId, userId | Integer(0~100) | knowledge, exam |
| 知识进度同步 | 学员学习某知识时,若 source=TRAINING 则同步更新 tr_plan_progress | planId, userId, knowledgeId | - | knowledge |
3. 核心逻辑
3.1 业务规则
[SRC-FEAT-01:模块六] [SRC-API-01:5.4]
培训计划状态自动流转:
tr_plan.status根据start_date/end_date与当前日期比较自动判定:NOW() < start_date→ NOT_STARTEDstart_date ≤ NOW() ≤ end_date→ IN_PROGRESSNOW() > end_date→ ENDED
- [ASSUMPTION] 状态字段在查询时实时计算,或由定时任务定期刷新(PRD 未明确)
培训进度计算公式(V1.0.1)[SRC-API-01:5.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:- 更新
km_knowledge_progress - 若 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 状态流转
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.idtr_plan_knowledge.knowledge_id→km_knowledge.idtr_plan_exam.plan_id→tr_plan.idtr_plan_exam.exam_id→ex_exam.idtr_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-01:4.5] [SRC-CODE-01:module/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-01:5.4] |