2026-05-12
This commit is contained in:
196
training/context/03-功能模块/05-培训计划模块.md
Normal file
196
training/context/03-功能模块/05-培训计划模块.md
Normal file
@@ -0,0 +1,196 @@
|
||||
# 培训计划模块(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<TrainingPlanVO> | - |
|
||||
| 培训计划详情(讲师端) | 查看计划详情,含关联知识/考试/对象/进度汇总 | 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_STARTED
|
||||
- `start_date ≤ NOW() ≤ end_date` → IN_PROGRESS
|
||||
- `NOW() > 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`:
|
||||
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-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] |
|
||||
Reference in New Issue
Block a user