修正文档:校准教室状态与破坏性操作审计结论
This commit is contained in:
1 parent
c6231099a8
commit
740c59d5dd
2 files changed
+70
-58
No files matched your search
+69
-57
@@ -1,12 +1,12 @@
|
||||
# SYFJGYD学员管理系统 管理员端破坏性操作生命周期审计与补齐报告
|
||||
(ADMIN DESTRUCTIVE ACTION UI ALIGNMENT AUDIT & COMPLIANCE REPORT)
|
||||
|
||||
- **报告生成时间**:2026-09-20
|
||||
- **当前执行基准**:严格聚焦管理员端破坏性生命周期操作(删除、移除、停用、取消、撤销、作废、退训、退宿等)在前端的可见性、可用性、友好提示与权限一致性。
|
||||
- **报告更新时间**:2026-09-20
|
||||
- **当前执行基准**:严格聚焦管理员端破坏性生命周期操作(删除、移除、停用、取消、撤销、作废、退训、退宿等)在前端的可见性、可用性、友好提示、权限一致性以及契约防御。
|
||||
- **环境安全约定**:
|
||||
- 数据库默认密码 `sict123456` 保持不变,未作任何篡改与强制 Hardening。
|
||||
- 严禁盲目向共享试用分支 `feat/cicd-pipeline` 部署触发 CI/CD。
|
||||
- 浏览器操作按用户最新指示保持静默,不做自动化浏览器驱动,所有交互与逻辑均由严格静态契约分析、源码审计及全量后端单元测试(346 测试通过)予以证实。
|
||||
- 禁止 push,禁止部署。
|
||||
|
||||
---
|
||||
|
||||
@@ -15,9 +15,12 @@
|
||||
| 指标项 | 统计值 | 说明 |
|
||||
| :--- | :---: | :--- |
|
||||
| **ENTITY_TOTAL** | **15** | 覆盖 15 个核心管理与业务实体 |
|
||||
| **BACKEND_DELETE_CAPABILITY_COUNT** | **8** | 后端具备直接物理删除/逻辑移除能力的实体数(课程、教室、计划课程、课次、参训记录、住宿、门禁授权、成绩) |
|
||||
| **FRONTEND_DELETE_VISIBLE_COUNT** | **9** | 前端界面可见破坏性移除/物理删除操作的实体数(课程、教室、宿舍映射解绑、培训计划移除未结训草稿、计划课程、课次、参训记录、住宿预分配、成绩) |
|
||||
| **BACKEND_DELETE_CAPABILITY_COUNT** | **8** | 后端具备直接物理删除/逻辑移除能力的实体数(课程、教室、计划课程、课次、参训记录、住宿预分配、门禁授权、成绩) |
|
||||
| **FRONTEND_DELETE_VISIBLE_COUNT** | **8** | 前端界面可见破坏性移除/物理删除操作的实体数(课程、教室、宿舍映射解绑、计划课程移除、课次、参训记录、住宿预分配、成绩) |
|
||||
| **UI_OPERATION_GAP_COUNT** | **0** | **本轮补齐后,已不存在“后端有稳定安全API但前端无入口”的断代缺口** |
|
||||
| **BROWSER_GATE_PREVIOUS_RESULT** | **FAIL** | 上一轮 CLI Browser Gate 执行结果为 FAIL |
|
||||
| **COURSE_DELETE_HTTP_500_OBSERVED** | **YES** | 上一轮浏览器测试中课程删除因访问已 drop 的旧表 `train_score_info` 产生 HTTP 500(本轮代码已根治) |
|
||||
| **READY_FOR_BROWSER_RETEST** | **YES** | 阻塞已完成代码级最小修复与契约测试验证,全量后端测试通过,具备浏览器复测条件 |
|
||||
|
||||
---
|
||||
|
||||
@@ -25,13 +28,13 @@
|
||||
|
||||
| 序号 | 业务对象 (ENTITY) | 当前后端操作 (BACKEND_OPERATION) | 当前前端操作 (FRONTEND_BUTTON) | 本轮补齐操作 (ALIGNED_ACTION) | 仍需甲方确认 (CONFIRMATION_REQUIRED) | 最终状态 (STATUS) |
|
||||
| :---: | :--- | :--- | :--- | :--- | :--- | :---: |
|
||||
| 1 | **教师**<br>`Teacher` | 查询、新增、修改、重置密码、解绑账号 | 修改、关联/解绑账号 | 保持现状,不开放物理删除 | 离职解聘或零引用教师注销规范 | **TEACHER_SAFE_DELETE_GAP** |
|
||||
| 1 | **教师**<br>`Teacher` | 查询、新增、修改、重置密码、解绑账号 | 修改、关联/解绑账号 | 保持现状,不开放物理删除 | 零引用教师安全注销/离职归档标准规程 | **TEACHER_SAFE_DELETE_GAP** |
|
||||
| 2 | **学员**<br>`Student` | 查询、新增、详情、解绑账号 | 详情、关联/解绑账号 | 保持现状,严禁物理删除 | 跨6大子系统历史学籍归档与零引用注销规范 | **STUDENT_SAFE_DELETE_GAP** |
|
||||
| 3 | **课程**<br>`Course` | 查询、新增、修改、**安全删除** (`train:course:remove`) | 修改、**停用/启用**、**删除** | **补齐后端删除端点+计划与成绩引用拦截;补齐前端停用/启用/删除按钮及《课程名称》确认提示** | 无 | **ALIGNED** |
|
||||
| 4 | **教室/场地**<br>`Classroom` | 查询、新增、修改、**安全删除** (`train:classroom:remove`) | 修改、**删除** | **补齐后端删除端点+排课占用拦截;补齐前端删除按钮及【教室名称】确认提示** | 场地维修维护与停用流转状态机 | **ALIGNED** |
|
||||
| 3 | **课程**<br>`Course` | 查询、新增、修改、**安全删除** (`train:course:remove`) | 修改、**停用/启用**、**删除** | **补齐后端删除端点+计划引用与V2有效成绩引用拦截;彻底消除旧表 train_score_info 依赖;补齐前端停用/启用/删除入口及《课程名称》提示** | 无 | **ALIGNED** |
|
||||
| 4 | **教室/场地**<br>`Classroom` | 查询、新增、修改、**安全删除** (`train:classroom:remove`) | 修改、**删除** | **补齐后端删除端点+排课占用拦截;校准提示文案为“可将其状态调整为维护中”;补齐前端删除入口及【教室名称】提示** | 场地维护与维修完整状态机 | **ALIGNED** |
|
||||
| 5 | **宿舍**<br>`Dormitory` | 查询、新增、详情、绑定/解绑映射 | 详情、门禁映射(含解绑) | 保持现状(契约冻结不擅自新增删除) | 宿舍维修、停用完整状态机及房号变更规范 | **CONFIRMATION_REQUIRED** |
|
||||
| 6 | **培训计划**<br>`Training Plan` | 查询、新增、修改、结束计划归档 | 计划详情、课程配置、修改、结束计划 | 保持现状(终态归档保护) | 培训计划取消/废止多级审批流程与历史数据处置规范 | **CONFIRMATION_REQUIRED** |
|
||||
| 7 | **计划课程**<br>`Plan Course` | 课程配置新增、移除课程 (`DELETE`) | 移除(含计划锁定/课次/成绩/学时四重防御) | 已有并具备具体课程名称提示 | 无 | **ALIGNED** |
|
||||
| 6 | **培训计划**<br>`Training Plan` | 查询、新增、修改、结束计划归档 | 计划详情、课程配置、修改、结束计划 | 保持现状(**明确当前无计划级删除能力**,依赖结束计划终态归档保护) | 培训计划取消/废止多级审批流程与历史数据处置规范 | **CONFIRMATION_REQUIRED** |
|
||||
| 7 | **计划课程**<br>`Plan Course` | 课程配置新增、移除课程 (`DELETE`) | **移除**(含计划锁定/课次/成绩/学时四重防御) | 已有并具备具体课程名称提示 | 无 | **ALIGNED** |
|
||||
| 8 | **课次**<br>`Lesson` | 新增排课、修改课次、删除课次 (`DELETE`) | 修改、删除(含考勤记录后端阻断与课次时间提示) | 已有并保持考勤强阻断 | 无 | **ALIGNED** |
|
||||
| 9 | **参训记录**<br>`Enrollment` | 导入/新增、状态变更(请假/退训)、移除 | 详情、请假/退训、移除(仅待报到显示移除) | 已有并保持产生业务流转退训 | 无 | **ALIGNED** |
|
||||
| 10 | **报到**<br>`Report` | 查询列表、导出、到校核验确认 | 查询、导出 | 保持法定履约证据,不开放删除 | 报到核验撤销/异常纠错规程 | **CONFIRMATION_REQUIRED** |
|
||||
@@ -46,86 +49,95 @@
|
||||
## 三、本轮完成的核心补齐与防御加固
|
||||
|
||||
### 1. 课程 (Course)
|
||||
- **业务规则**:未被任何培训计划或成绩记录引用的课程允许管理员删除;已被引用的课程严禁删除,引导管理员使用“停用”。
|
||||
- **后端加固**:
|
||||
- `TrainPlanCourseMapper` 增加 `countPlanCoursesByCId`。
|
||||
- `TrainCourseServiceImpl.deleteTrainCourseByCId` 增加强校验:若存在开班计划关联,抛出 `ServiceException("该课程已被培训计划引用,无法删除,可将其停用。")`;若存在成绩记录关联,抛出 `ServiceException("该课程已有学员成绩记录,无法删除。")`。
|
||||
- Controller 暴露 `@DeleteMapping("/{cIds}")`,鉴权 `@PreAuthorize("@ss.hasPermi('train:course:remove')")`。
|
||||
- **业务规则**:未被任何培训计划或当前有效成绩记录引用的课程允许管理员删除;已被引用的课程严禁删除,引导管理员使用“停用”。
|
||||
- **V2 成绩模型对齐与旧表解耦**:
|
||||
- 彻底移除对已废弃旧表 `train_score_info`、`TrainScoreInfo` 实体及 `TrainScoreInfoMapper` 的运行时依赖;
|
||||
- 在当前有效 V2 成绩模型下,通过 `train_student_score`(学员得分明细)关联 `train_score_item`(成绩配置项)和 `train_plan_course`(开班课程),在 `TrainPlanCourseMapper` 中实现 `countStudentScoresByCId` 强引用检查;
|
||||
- `TrainCourseServiceImpl.deleteTrainCourseByCId` 实现双重拦截:
|
||||
1. 若存在开班计划关联(`countPlanCoursesByCId > 0`),抛出 `ServiceException("该课程已被培训计划引用,无法删除,可将其停用。")`;
|
||||
2. 若存在有效学员成绩明细(`countStudentScoresByCId > 0`),抛出 `ServiceException("该课程已产生学员成绩记录,无法删除,可将其停用。")`;
|
||||
- Controller 暴露安全 `@DeleteMapping("/{cIds}")`,鉴权 `@PreAuthorize("@ss.hasPermi('train:course:remove')")`。
|
||||
- **前端加固**:
|
||||
- `api/train/course.js` 补齐 `delCourse(cId)`。
|
||||
- `views/train/course/index.vue` 表格操作列增加“停用/启用”按钮(根据 `status` 动态展示文案并提示课程名称《xxx》);增加“删除”按钮(带 `v-hasPermi="['train:course:remove']"`,提示 `确定删除课程《${row.cName}》吗?`)。
|
||||
- `api/train/course.js` 补齐 `delCourse(cId)`;
|
||||
- `views/train/course/index.vue` 表格操作列增加“停用/启用”按钮与“删除”按钮,提示具体《课程名称》。
|
||||
|
||||
### 2. 教室 (Classroom)
|
||||
- **业务规则**:未安排排课日程的教室允许物理删除;已在课次日程中使用的教室严禁物理删除,引导管理员通过修改状态设为“维护中”或“停用”。
|
||||
- **后端加固**:
|
||||
- `TrainLessonMapper` 增加 `countLessonsByClassRoomId`。
|
||||
- `TrainClassroomInfoServiceImpl.deleteTrainClassroomInfoByClassRoomId` 增加校验:若存在关联课次日程,抛出 `ServiceException("该教室已在排课课次中使用,无法删除,可通过状态调整为维护中或停用。")`。
|
||||
- Controller 暴露 `@DeleteMapping("/{classRoomIds}")`,鉴权 `@PreAuthorize("@ss.hasPermi('train:classroom:remove')")`。
|
||||
- **业务规则**:未安排排课日程的教室允许物理删除;已在课次日程中使用的教室严禁物理删除,引导管理员通过修改状态设为“维护中”。
|
||||
- **状态与文案校准**:
|
||||
- 当前教室实际运行状态为:`可用空闲`、`正在使用`、`维护中`(不存在“停用”状态);
|
||||
- `TrainClassroomInfoServiceImpl.deleteTrainClassroomInfoByClassRoomId` 拦截提示文案准确校准为:`"该教室已在排课课次中使用,无法删除,可将其状态调整为维护中。"`,不新增不存在的停用状态;
|
||||
- Controller 暴露安全 `@DeleteMapping("/{classRoomIds}")`,鉴权 `@PreAuthorize("@ss.hasPermi('train:classroom:remove')")`。
|
||||
- **前端加固**:
|
||||
- `api/train/classroom.js` 补齐 `delClassroom(classRoomId)`。
|
||||
- `views/train/classroom/index.vue` 表格操作列增加“删除”按钮(带 `v-hasPermi="['train:classroom:remove']"`,提示 `确定删除教室【${row.roomName}】吗?`)。
|
||||
- `api/train/classroom.js` 补齐 `delClassroom(classRoomId)`;
|
||||
- `views/train/classroom/index.vue` 表格操作列增加“删除”按钮,提示具体【教室名称】。
|
||||
|
||||
### 3. 住宿管理 (Accommodation)
|
||||
- **业务规则**:只有处于预分配状态 (`accommodationStatus === 0`) 的错误/待调整记录才允许删除;在住 (1) 和已退宿 (2) 必须保持完整的住宿履历,严禁提供物理删除入口。
|
||||
- **前端加固**:
|
||||
- `api/train/accommodation.js` 补齐导出 `delAccommodation`。
|
||||
- `views/train/accommodation/index.vue` 表格操作列仅在 `scope.row.accommodationStatus === 0` 时渲染“删除”按钮,确认框明确显示 `确定删除学员 ${row.studentId} 在 ${row.roomNumber} 的预分配记录吗?`。
|
||||
- `api/train/accommodation.js` 补齐导出 `delAccommodation`;
|
||||
- `views/train/accommodation/index.vue` 表格操作列仅在 `scope.row.accommodationStatus === 0` 时渲染“删除”按钮,确认框明确显示学员与房号信息。
|
||||
|
||||
### 4. 门禁授权 (Access / Auth)
|
||||
- **业务规则**:门禁授权属于外围设备控制记录,在普通业务界面上绝不暴露物理 DELETE 接口,仅提供业务合规的“注销/撤销授权”操作。
|
||||
- **前端加固**:
|
||||
- `api/train/auth.js` 补齐导出 `revokeAuth`,调用后端已有 `POST /train/auth/{authId}/revoke`。
|
||||
- `views/train/auth/index.vue` 操作列在 `ACTIVE` 或 `GRANTING` 状态渲染“注销授权”按钮,确认框明确提示 `确定注销学员 ${row.studentId} 的门禁授权吗?注销后该凭证将立即失效。`。
|
||||
- `api/train/auth.js` 补齐导出 `revokeAuth`,调用后端已有 `POST /train/auth/{authId}/revoke`;
|
||||
- `views/train/auth/index.vue` 操作列在 `ACTIVE` 或 `GRANTING` 状态渲染“注销授权”按钮。
|
||||
|
||||
### 5. 成绩管理 (Score)
|
||||
- **业务规则**:成绩录入期支持错录删除,操作权限指令保持与后端 `@PreAuthorize("@ss.hasPermi('system:info:remove')")` 一致。
|
||||
- **前端交互优化**:
|
||||
- 优化确认弹窗文案,由模糊的“是否确认删除”改造为明确展示学员学号与成绩记录编号:`确定删除学员 ${student} 的成绩记录(ID: ${recordId})吗?此操作不可逆!`。
|
||||
- 优化确认弹窗文案,明确展示学员学号与具体成绩记录编号。
|
||||
|
||||
---
|
||||
|
||||
## 四、教师与学员安全删除断代评估
|
||||
## 四、教师与学员基础资料生命周期事实澄清
|
||||
|
||||
### 1. 教师资料 (`TEACHER_SAFE_DELETE_GAP`)
|
||||
- **审计事实**:
|
||||
- 教师身份与 `sys_user` 账号系统强绑定;
|
||||
- 教师作为授课讲师,深度关联 `train_course`(主讲教师)、`train_lesson`(排课课次)、`train_plan_course`(开班教师关联);
|
||||
- 当前数据字典与后端 Service 中均无“教师离职/停用”状态字段,且暂无多表联合无引用校验探针。
|
||||
- **裁决**:**坚决不盲目开放物理删除接口**,防止级联破坏课程表排课日程与课次考勤;列为 `TEACHER_SAFE_DELETE_GAP`,待甲方确认教师账号解绑与归档标准规程。
|
||||
- **真实档案状态**:
|
||||
- 数据库表 `train_teacher` **明确存在业务状态字段 `status`(1=正常,0=停用)**;
|
||||
- 教师身份与 `sys_user` 账号系统强绑定,并深度关联主讲课程 (`train_course`)、排课课次 (`train_lesson`)、开班课程 (`train_plan_course`);
|
||||
- 当前系统对教师暂未开放物理删除能力,主要是防止级联破坏课程表排课日程与课次考勤历史;
|
||||
- **定性**:保持现状,不开放物理删除;列为 `TEACHER_SAFE_DELETE_GAP`,待甲方确认零引用教师安全注销/离职归档规程。
|
||||
|
||||
### 2. 学员资料 (`STUDENT_SAFE_DELETE_GAP`)
|
||||
- **审计事实**:
|
||||
- 学员档案是整个培训生命周期的核心锚点,横向关联 6 大子系统:账号 (`sys_user`)、参训名册 (`train_plan_student`)、现场报到 (`train_report_record`)、考勤打卡流水 (`train_attendance`)、自主学习流水 (`train_learner_duration`)、宿舍安排 (`train_accommodation`)、门禁授权凭据 (`train_auth_record`)、考试与平时成绩 (`train_exam_score`)。
|
||||
- 当前系统无学员“休学/退学/注销”软删除状态机,亦无法在不破坏外键与报表统计的前提下直接 DROP/DELETE。
|
||||
- **裁决**:**严禁开放学员物理删除能力**,维持当前“账号解绑与资料查看”边界;列为 `STUDENT_SAFE_DELETE_GAP`,待甲方确认历史学籍生命周期销户规则。
|
||||
- **真实档案状态**:
|
||||
- 学员档案是整个培训生命周期的核心锚点,横向关联 6 大子系统:账号 (`sys_user`)、参训名册 (`train_plan_student`)、现场报到 (`train_report_record`)、考勤打卡流水 (`train_attendance`)、自主学习流水 (`train_learner_duration`)、宿舍安排 (`train_accommodation`)、门禁授权凭据 (`train_auth_record`)、考试与平时成绩 (`train_student_score`);
|
||||
- 物理删除将导致历史审计账目与报表统计瘫痪。
|
||||
- **定性**:严禁开放学员物理删除能力,维持当前“账号解绑与资料查看”边界;列为 `STUDENT_SAFE_DELETE_GAP`,待甲方确认历史学籍生命周期销户规则。
|
||||
|
||||
---
|
||||
|
||||
## 五、甲方规则待确认项总览 (CONFIRMATION REQUIRED)
|
||||
## 五、权限事实与静态资源 404 根因排查
|
||||
|
||||
1. **培训计划取消/废止**:
|
||||
- 现状:当前培训计划仅支持“草稿移除”与“结束计划归档”(终态不可逆)。
|
||||
- 待确认:已发布/进行中的培训计划在发生突发事件时是否允许“废止”或“取消”,其下属已开课次与学员考勤流水如何处理。
|
||||
2. **报到核验撤销**:
|
||||
- 现状:报到记录为法定到校履约凭证,仅允许核验确认,不提供反向撤销。
|
||||
- 待确认:现场核验错误时(如误报)是否支持管理员撤销核验状态。
|
||||
3. **自主学习异常学时纠错**:
|
||||
- 现状:只读呈现外部学习平台打卡学时流水,不支持管理员随意篡改或删除。
|
||||
- 待确认:对于异常上报或作弊学时,是否需要设计核销或扣减审批单。
|
||||
4. **宿舍维护/停用状态机**:
|
||||
- 现状:支持房源维护与门禁设备绑定/解绑映射,无专用维修中状态机。
|
||||
- 待确认:整栋/整间宿舍维修改造期间是否引入不可分配的专用状态标识。
|
||||
### 1. qa_train_admin 课程删除权限事实
|
||||
- **事实检查**:
|
||||
- 在 `005_training_roles_permissions.sql` 中,`train_admin` 角色(`role_id = 3`)被授予的菜单与按钮包括:课程查询 (`2214/train:course:list`)、课程详情 (`2215/train:course:query`)、课程新增 (`2216/train:course:add`)、课程修改 (`2217/train:course:edit`);
|
||||
- **角色权限初始化中并未给 `train_admin` 分配 `train:course:remove`**;
|
||||
- 只有拥有全局通配权限 `*:*:*` 的超级管理员 `admin` 具备课程删除权限;
|
||||
- **结论**:
|
||||
`TRAIN_ADMIN_COURSE_REMOVE_PERMISSION_CURRENT = NO`
|
||||
此现象属于既定权限架构配置事实,保持现状,不擅自越权添加,不作为 Bug 处理。
|
||||
|
||||
### 2. 默认头像与静态资源 404 根因排查 (`STATIC_RESOURCE_404_ROOT_CAUSE`)
|
||||
- **根因定性**:属于 **C. 账号头像数据指向不存在资源** 叠加 **B. 多页面路由挂载**。
|
||||
- **详细机理**:
|
||||
1. 系统预置用户或历史导入数据中,`sys_user.avatar` 保存了相对路径(如 `/profile/avatar/2021/02/18/...`);
|
||||
2. 共享试用环境或新容器磁盘并未持久化历史头像真实图片文件;
|
||||
3. 前端各管理页面加载时,全局顶部导航组件 `Navbar.vue` 会向服务器请求该静态头像,服务端返回 HTTP 404;
|
||||
4. 虽然前端组件通过 `@error="handleAvatarError"` 成功容错降级回退至工程内置 `profile.jpg`,不影响任何业务功能,但浏览器控制台网络层已产生 404 请求记录;
|
||||
5. 在无头浏览器巡检 8 个页面时,每个页面重新挂载 Navbar 均触发一次此网络请求,恰好产生 8 次 404 控制台错误。
|
||||
|
||||
---
|
||||
|
||||
## 六、质量保证与验证记录
|
||||
|
||||
1. **后端单元与契约测试**:
|
||||
- 针对课程引用拦截与教室排课占用拦截,新增专用单元测试:`DestructiveActionSafetyTest.java`;
|
||||
- 更新接口反射契约测试:`PreCustomerStabilizationFinalFixesContractTest.java`;
|
||||
- **全量 Surefire 测试套件汇总**:55 个测试类,**TOTAL TESTS: 346,FAILURES: 0,ERRORS: 0,SKIPPED: 0,100% 通过**。
|
||||
2. **前端打包与构建检查**:
|
||||
- `build_ui` 运行 `npm run build:prod`,产物打包完成无编译报错。
|
||||
- 增加契约测试 `testContract_CourseServiceMustNotDependOnLegacyScoreTable`,通过类反射与 Mapper XML 解析,强断言课程删除业务链路绝不依赖废弃表 `train_score_info`;
|
||||
- 完善课程删除 3 大场景单测:无引用成功删除、开班计划引用拦截拒绝、有效 V2 成绩记录引用拦截拒绝;
|
||||
- 完善教室删除 2 大场景单测:排课占用提示维护中拦截、未排课成功删除;
|
||||
- **全量 Surefire 测试套件汇总**:55 个测试类,**TOTAL TESTS: 347,FAILURES: 0,ERRORS: 0,SKIPPED: 0,100% 绿通过**。
|
||||
2. **前端打包构建验证**:
|
||||
- `build_ui` 运行 `npm run build:prod`,产物打包完成无编译报错 (`FRONTEND_BUILD = PASS`)。
|
||||
3. **环境安全符合性检查**:
|
||||
- 数据库密码 `sict123456` 保持不变,无未授权配置修改。
|
||||
- 未执行任何 push 操作,未触发 CI/CD 流水线,完全遵守“完成后不要立即部署”之铁律。
|
||||
Reference in new issue
Block a user