17 KiB
17 KiB
ISSUE-01-04 教学空间资源维护开发验收文档 (Contract V1.0.2 CG-05 闭环版)
1. 任务概述与环境基线
- 任务 ID:
ISSUE-01-04 - 任务名称: 教学空间资源维护(普通教室与实训场地)
- 所属 Epic:
EPIC-01 基础主数据必要集合 - 工作区目录:
/Users/wzb/Desktop/项目/RailwaySystem-worktrees/issue-01-04-space - 当前分支:
feat/issue-01-04-space - 基线 Commit:
7fcaea29b8810546fd972ba0c9d366c71a357d63(issues-v1.0) - API 契约基准:
api-v2-contract-v1.0.2(a979c02841b7b0f8b00c45a67c07a915fc668413)(Contract Gate 已正式解除) - 数据库基线: Database V2 (
train_classroom_info,train_training_site) - Generator 状态:
GENERATOR SLOT = SPACE (受控 Pilot 已完成,PASS)(完成train_classroom_info与train_training_site双阶段元数据导入与沙箱预览,严禁覆盖源码,零迁移 generated artifact) - 核心业务目标: 建立普通教室 (
Classroom) 与专业实训场地 (TrainingSite) 的主数据档案,保证物理主键标识(classRoomId,siteId)的稳定性与唯一性,为后续排课冲突检测与课表编排提供可靠实体空间校验支撑。
2. HTTP Endpoint 最终收口与物理映射
严格依照冻结契约 docs/api-v2/02_module_a_base_resource_api.md 4.1 与 4.2 节收口 Controller 公开接口,非冻结接口全部从 Controller 移除,不再对外公开:
2.1 Classroom 最终物理 Endpoint 完整列表(共 4 个)
| 优先级 | HTTP Method | URI 路径 | Controller 方法 | 权限字符 | 适用角色 | 契约对齐说明 |
|---|---|---|---|---|---|---|
| P0 | GET |
/train/classroom/list |
list(TrainClassroomInfo) |
train:classroom:list |
管理员, 教师 | 分页查询教室列表 |
| P0 | GET |
/train/classroom/{classRoomId} |
getInfo(@PathVariable) |
train:classroom:list |
管理员, 教师 | 获取教室详情(返回 ClassroomDetailVO) |
| P0 | POST |
/train/classroom |
add(@Validated @RequestBody) |
train:classroom:edit |
管理员 | 新增教室(校验 capacity > 0,名称预查重) |
| P1 | PUT |
/train/classroom/{classRoomId} |
edit(@PathVariable, @Validated @RequestBody) |
train:classroom:edit |
管理员 | 修改教室信息 |
已彻底从 Controller 移除的非公开方法:
PUT /train/classroom(无 Path ID 的修改映射已删除)DELETE /train/classroom/{classRoomIds}(已从 Controller 移除,底层逻辑删除能力保留于 Service/Mapper)POST /train/classroom/export(已从 Controller 移除)
2.2 TrainingSite 最终物理 Endpoint 完整列表(共 4 个)
| 优先级 | HTTP Method | URI 路径 | Controller 方法 | 权限字符 | 适用角色 | 契约对齐说明 |
|---|---|---|---|---|---|---|
| P0 | GET |
/train/training-site/list |
list(TrainTrainingSite) |
train:site:list |
管理员, 教师 | 分页查询实训场地列表 |
| P0 | GET |
/train/training-site/{siteId} |
getInfo(@PathVariable) |
train:site:list |
管理员, 教师 | 获取实训场地详情 |
| P0 | POST |
/train/training-site |
add(@Validated @RequestBody) |
train:site:edit |
管理员 | 新增实训场地(校验 capacity > 0,名称预查重) |
| P1 | PUT |
/train/training-site/{siteId} |
edit(@PathVariable, @Validated @RequestBody) |
train:site:edit |
管理员 | 修改实训场地信息 |
已彻底从 Controller 移除的非公开方法:
PUT /train/training-site(无 Path ID 的修改映射已删除)DELETE /train/training-site/{siteIds}(已从 Controller 移除,底层逻辑删除能力保留于 Service/Mapper)POST /train/training-site/export(已从 Controller 移除)
3. CG-05 落地实现与响应模型收口 (API Contract V1.0.2)
3.1 新增轻量班牌摘要视图:ClassroomBoardSummaryVO
依据 API Contract V1.0.2 (06_dto_vo_catalog.md 1.11 节):
- 仅且只包含 3 个字段:
boardId(String, 系统内部稳定班牌ID)boardSn(String, 设备硬件序列号)boardStatus(Integer, 班牌状态:0离线 1在线)
- 彻底避免向前端泄漏
TrainElectronicBoard持久化 Domain 实体字段。
3.2 ClassroomDetailVO 完整字段列表
classRoomId(String, 教室ID)roomName(String, 教室名称)roomLocation(String, 教室物理位置)capacity(Long, 核定容纳人数)roomStatus(Integer, 教室状态:0正在使用 1可用空闲 2维护中)remark(String, 备注)createTime(Date, 创建时间)boards(List<ClassroomBoardSummaryVO>, 绑定的班牌摘要列表)- 严格遵循 0..N 语义;
- 无绑定班牌时返回
boards = [],绝不返回null; - 绝不引入
electronicBoard、primaryBoard、preferredBoard,绝不假定“第一条就是默认班牌”。
3.3 详情查询装配逻辑
在 TrainClassroomInfoServiceImpl.selectClassroomDetailByClassRoomId 中:
- 根据
classRoomId查询单表持久化实体TrainClassroomInfo; - 依据
bind_classroom_id = classRoomId检索train_electronic_board列表; - 将班牌记录转换为轻量
ClassroomBoardSummaryVO列表;若无记录则初始化为空列表[]; - 组装至
ClassroomDetailVO.boards返回。
4. Contract Gap 处理结果
4.1 CG-04 (错误码 40008 / 40009 遗漏):已闭环
- 在 API Contract V1.0.2 中,
docs/api-v2/10_permission_and_error_codes.md已正式补录:40008:CLASSROOM_NAME_DUPLICATED(教室名称已存在)40009:SITE_NAME_DUPLICATED(实训场地名称已存在)
- 代码层
TrainClassroomInfoServiceImpl与TrainTrainingSiteServiceImpl保持现有查重与抛错实现,Contract Gap 正式闭环消除。
4.2 CG-05 (教室详情班牌数据结构与基数未决):已闭环
- 在 API Contract V1.0.2 中,
docs/api-v2/06_dto_vo_catalog.md明确定义了ClassroomBoardSummaryVO与List<ClassroomBoardSummaryVO> boards(0..N 语义,空返回[])。 - 代码层已严格按该定义实现,Contract Gap 正式闭环消除。
4.3 数据库名称唯一性并发边界记录
- 在 Database V2 物理结构中,
train_classroom_info.room_name与train_training_site.site_name均无 UNIQUE 唯一约束。 - 当前查重为 Service 层的应用级预检查(
checkRoomNameUnique/checkSiteNameUnique)。 - 边界说明: 在高并发写操作下,应用层预检查无法绝对保证无并发幻读重复写入,并发强唯一性当前不保证。本 Issue 遵守红线,未修改 Database V2。
5. 前端同步收口
build_ui/src/api/train/classroom.js:- 删除了
delClassroom与exportClassroom导出函数; updateClassroom请求路径收口为带有 Path ID 的PUT /train/classroom/{classRoomId}。
- 删除了
build_ui/src/views/train/classroom/index.vue:- 删除了顶部批量删除与导出按钮;
- 删除了表格操作列的删除按钮;
- 删除了
handleDelete与handleExport对应方法与未使用的 API 引用; - 表单编辑保存精准调用
/train/classroom/{classRoomId}。
build_ui/src/api/train/site.js:- 删除了
delSite导出函数; updateSite请求路径收口为带有 Path ID 的PUT /train/training-site/{siteId}。
- 删除了
build_ui/src/views/train/site/index.vue:- 删除了顶部批量删除与导出按钮;
- 删除了表格操作列的删除按钮;
- 删除了
handleDelete与handleExport对应方法与未使用的 API 引用; - 表单编辑保存精准调用
/train/training-site/{siteId}。
6. 构建与工程验证结果
6.1 后端 Maven 编译验证
- 命令:
mvn compile -DskipTests -f RuoYi-Vue/pom.xml - 构建结果:
BUILD SUCCESS(8 个模块全部成功,退出码 0)。
6.2 前端 ESLint 严格校验
- 命令:
cd build_ui /Users/wzb/Desktop/项目/RailwaySystem/build_ui/node_modules/.bin/eslint \ --resolve-plugins-relative-to /Users/wzb/Desktop/项目/RailwaySystem/build_ui \ --no-ignore \ src/api/train/classroom.js \ src/api/train/site.js \ src/views/train/classroom/index.vue \ src/views/train/site/index.vue - 执行结果: PASS(0 errors, 0 warnings,退出码 0)。
6.3 代码差异与规范检查
git diff --check:输出为空,退出码 0,无任何空白字符、CRLF 或冲突标记问题。git status --short:严格收敛于本 Issue 范围内。
7. 受控 Generator Pilot 执行与元数据核验记录
在技术负责人正式释放 GENERATOR SLOT = SPACE 后,严格按照分阶段受控流程执行了双阶段 Pilot:
7.1 第一阶段:train_classroom_info Pilot
- 备份表隔离前置检查:
- 调用
genTableService.selectDbTableList,匹配bak_v1_*的表数量为 0,确认历史快照备份表完全隔离不可见,无误选风险。
- 调用
- 单表严格导入:
- 仅且唯独选择
train_classroom_info单表导入,成功写入gen_table(分配table_id = 4)及gen_table_column(共 11 列元数据)。
- 仅且唯独选择
- 主键列与状态列元数据核验:
- 主键
class_room_id:isPk = "1",isIncrement = "0",javaType = "String",columnType = character varying(32)-> PASS(准确识别为非自增 VARCHAR(32) 字符串主键)。 - 状态
room_status:isPk = "0",isIncrement = "0",javaType = "Long",columnType = smallint。
- 主键
- 沙箱目录隔离输出:
- 调用
previewCode(4L),文件全部写入临时沙箱目录:/tmp/railwaysystem-generator/issue-01-04-space/classroom/。 - 输出清单包括:
TrainClassroomInfo.java、TrainClassroomInfoMapper.java、ITrainClassroomInfoService.java、TrainClassroomInfoServiceImpl.java、TrainClassroomInfoController.java、TrainClassroomInfoMapper.xml、classroomMenu.sql、classroom.js、index.vue。 - 禁止覆盖原则: 未向工程源码目录覆盖任何文件,零迁移 generated artifact。
- 调用
7.2 第二阶段:train_training_site Pilot
- 备份表隔离前置检查:
- 匹配
bak_v1_*的表数量为 0,无误选风险。
- 匹配
- 单表严格导入:
- 仅选择
train_training_site单表导入,成功写入gen_table(分配table_id = 5)及gen_table_column(共 12 列元数据)。
- 仅选择
- 主键列与状态列元数据核验:
- 主键
site_id:isPk = "1",isIncrement = "0",javaType = "String",columnType = character varying(32)-> PASS(准确识别为非自增 VARCHAR(32) 字符串主键)。 - 状态
site_status:isPk = "0",isIncrement = "0",javaType = "Long",columnType = smallint。
- 主键
- 沙箱目录隔离输出:
- 调用
previewCode(5L),文件全部写入临时沙箱目录:/tmp/railwaysystem-generator/issue-01-04-space/site/。 - 输出清单包括:
TrainTrainingSite.java、TrainTrainingSiteMapper.java、ITrainTrainingSiteService.java、TrainTrainingSiteServiceImpl.java、TrainTrainingSiteController.java、TrainTrainingSiteMapper.xml、siteMenu.sql、site.js、index.vue。 - 禁止覆盖原则: 未向工程源码目录覆盖任何文件,零迁移 generated artifact。
- 调用
8. 三方比较矩阵 (Generated vs Existing vs API Contract V1.0.2) 与不迁移裁决
8.1 Classroom 三方比对与处理策略
| 检查维度 | Generated (代码生成器输出) | Existing (现有实现) | API Contract V1.0.2 (正式契约) | 最终裁定与处理策略 |
|---|---|---|---|---|
| 主键与类型 | classRoomId (String), roomStatus (Long), capacity (Long) |
classRoomId (String), roomStatus (Integer), capacity (Long) |
classRoomId (String, 32位), roomStatus (Integer), capacity (Long) |
KEEP Existing Existing 的 roomStatus 为 Integer,与 Contract 定义的 Integer/Number 契约完全吻合。 |
| Controller 路径与前缀 | @RequestMapping("/system/info")(默认系统模块名) |
@RequestMapping("/train/classroom") |
/train/classroom/... |
KEEP Existing Generated 路径前缀完全偏离业务契约,严禁覆盖。 |
| 权限字符定义 | @ss.hasPermi('system:info:list') 等默认字符 |
@ss.hasPermi('train:classroom:list'),train:classroom:edit |
train:classroom:list,train:classroom:edit |
KEEP Existing Generated 权限字符错误,Existing 符合冻结权限表。 |
| DTO / VO 分层 | 完全无分层(直接裸露持久化实体 TrainClassroomInfo) |
入参 ClassroomCreateDTO,出参 ClassroomDetailVO |
明确要求响应类型为 ClassroomDetailVO |
KEEP Existing 架构级契约合规必需品,严禁退化回单实体架构。 |
| 班牌摘要聚合 (CG-05) | 完全缺失(纯单表生成,无任何关联能力) | ClassroomDetailVO.boards: List<ClassroomBoardSummaryVO>(0..N 聚合,无绑定时返回 []) |
详情响应必须包含 boards: List<ClassroomBoardSummaryVO> |
KEEP Existing 核心业务与架构契约指标,Generated 无法提供。 |
| 额外端点 (DELETE/export) | 生成了未冻结的 POST /export 与 DELETE /{classRoomIds} 以及无 ID 的 PUT |
严格收敛为 4 个公开端点(P0: list, getInfo, add; P1: edit with ID),无 DELETE/export | 明确仅冻结 4 个端点,无 DELETE 与 export | KEEP Existing 坚决拒绝引入契约外暴露的破坏性物理删除与导出端点。 |
| Service 业务防御 | 纯调用 Mapper,无容量非正数拦截,无名称预查重 | 容量 <= 0 强校验拦截;checkRoomNameUnique 查重(40008);自动分配 32 位 UUID |
容量大于 0;同名校验(CG-04 40008) | KEEP Existing Existing 承载了业务防御规则,保持现有实现。 |
8.2 TrainingSite 三方比对与处理策略
| 检查维度 | Generated (代码生成器输出) | Existing (现有实现) | API Contract V1.0.2 (正式契约) | 最终裁定与处理策略 |
|---|---|---|---|---|
| 主键与类型 | siteId (String), siteStatus (Long), capacity (Long) |
siteId (String), siteStatus (Integer), capacity (Long) |
siteId (String, 32位), siteStatus (Integer), capacity (Long) |
KEEP ExistingsiteStatus 保持 Integer 对齐契约。 |
| Controller 路径与前缀 | @RequestMapping("/system/site") |
@RequestMapping("/train/training-site") |
/train/training-site/... |
KEEP Existing Generated 路径错误,坚决不覆盖。 |
| 权限字符定义 | @ss.hasPermi('system:site:list') 等默认字符 |
@ss.hasPermi('train:site:list'),train:site:edit |
train:site:list,train:site:edit |
KEEP Existing Existing 完全符合冻结契约。 |
| DTO / VO 分层 | 完全无分层(直接裸露持久化实体 TrainTrainingSite) |
入参 SiteCreateDTO,出参 SiteDetailVO |
详情出参要求 SiteDetailVO |
KEEP Existing 保留专用分层对象。 |
| 额外端点 (DELETE/export) | 生成了未冻结的 POST /export 与 DELETE /{siteIds} 以及无 ID 的 PUT |
严格收敛为 4 个公开端点(P0: list, getInfo, add; P1: edit with ID),无 DELETE/export | 明确仅冻结 4 个端点,无 DELETE 与 export | KEEP Existing 拒绝暴露契约外端点。 |
| Service 业务防御 | 纯调用 Mapper,无容量校验,无名称查重 | 容量 <= 0 强校验拦截;checkSiteNameUnique 查重(40009);自动分配 32 位 UUID |
容量大于 0;场地名称唯一性校验(CG-04 40009) | KEEP Existing 保留核心业务防御逻辑。 |
- 综合裁决结论:
本次受控 Pilot 充分证明 Kingbase 代码生成器底层对
train_classroom_info与train_training_site的元数据读取、主键识别(class_room_id与site_id均准确识别为非自增 String 主键)及 Velocity 模板渲染能力 100% 正常。 鉴于现有实现已经严格按照 API Contract V1.0.2(包含 CG-04 与 CG-05)完成了精细化对齐,而 Generator 默认输出包含错误的路径前缀、错误的权限字符、未授权的 DELETE/export 端点且缺失 DTO/VO 分层与班牌聚合,因此坚决不迁移任何 generated artifact,不覆盖现有任何工程源码。生成文件仅作为临时沙箱比对凭证保留于/tmp/目录备查。
9. 数据库影响与写入核查声明
- Generator 元数据记录:
- 成功向
gen_table写入 2 条元数据记录:train_classroom_info(table_id = 4)、train_training_site(table_id = 5)。 - 成功向
gen_table_column写入 23 条列元数据(教室 11 列,场地 12 列)。
- 成功向
- 业务数据库零写入:
- 未执行任何
ALTER TABLE/CREATE TABLE/DROP TABLE等 DDL 语句。 - 未执行任何
IDENTITY变更或自增序列修正(未调用nextval/setval)。 - 未对
train_classroom_info执行任何业务数据写入(行数保持精确为 0)。 - 未对
train_training_site执行任何业务数据写入(行数保持精确为 0)。 - 未修改 Database V2 既有物理表结构,未修改 API Contract 冻结契约。
- 未执行任何