# RailwaySystem Electronic Board Demo-Safe Cleanup (V2 闭环版) 实施报告 ## 1. 任务背景与集成基线 本任务目标为 **RailwaySystem Electronic Board Demo-Safe Cleanup**: 1. **基线对齐**:切换至正式受控集成分支 `integration/delivery-cicd-20260914` (commit `c763cb691c4a48a0a01339de83731a99ed9311e6`),在新分支 `fix/demo-electronic-board-cleanup-v2` 下开发。 2. **结构对齐**:与已在数据库执行的 Database V2 (`public.train_electronic_board`) 真实物理结构完全对齐; 3. **界面清洁**:前端管理页面彻底消除裸露的数据库表名、列名、主键 ID 及枚举裸数值; 4. **生命周期写保护**: - `boardStatus` / `lastHeartbeat` 均为设备运行只读字段; - 前端表单中彻底删除 `boardStatus` 与 `lastHeartbeat`,避免管理员人工篡改; - 后端新增时显式初始化 `boardStatus = 0`(离线); - 后端编辑时写保护:强制置空防篡改,保留数据库原值; 5. **boardId 闭环**:前端不传 `boardId`,后端 Service 自动生成唯一 UUID,实现 INSERT 与 GET 闭环; 6. **逻辑删除**:DELETE 操作统一使用 `UPDATE ... SET del_flag = '2'` 软删除,所有查询(包含教室聚合)强制排除 `del_flag = '2'`; 7. **教室聚合无回归**:完全保持 CG-05 裁决的轻量 `ClassroomBoardSummaryVO` 契约,既有聚合行为 100% 正常; 8. **不伪造能力**:不伪造不存在的设备心跳上报、不伪造协议/MQTT、不添加假“在线心跳模拟”按钮。 --- ## 2. 真实数据库 V2 结构验证 (Kingbase 元数据) 通过直连 Kingbase 只读查询 `information_schema.columns`、`information_schema.table_constraints`、`information_schema.key_column_usage`,确认当前 `public.train_electronic_board` 的实际元数据如下: ### 2.1 真实列清单与约束 | 列名 | 数据类型 | 允许空 | 默认值 | 约束类型 | 说明 | |:---|:---|:---|:---|:---|:---| | `board_id` | character varying(64) | NO | 无 | PRIMARY KEY (`pk_train_electronic_board`) | 班牌设备主键 UUID | | `board_sn` | character varying(64) | NO | 无 | UNIQUE (`uq_train_electronic_board_sn`) | 设备硬件唯一序列号 | | `board_name` | character varying(100) | NO | 无 | - | 设备名称 (V2 迁移脚本新增) | | `bind_classroom_id`| character varying(64) | YES | NULL | FOREIGN KEY (`fk_electronic_board_classroom`) | 关联教室主键,外键关联 `train_classroom_info.class_room_id` | | `board_ip` | character varying(45) | YES | NULL | - | 设备当前 IP 地址 | | `api_endpoint` | character varying(255) | YES | NULL | - | 设备通信/推流端点 URL | | `support_checkin_type` | character varying(50) | YES | 'CARD,FACE' | - | 支持签到方式 (CARD, FACE, QR) | | `board_status` | smallint | YES | 1 | - | 状态 (0 离线, 1 在线) | | `last_heartbeat` | timestamp without time zone | YES | NULL | - | 最近心跳时间 | | `remark` | character varying(500) | YES | NULL | - | 备注信息 | | `create_by` | character varying(64) | YES | '' | - | 创建人账号 | | `create_time` | timestamp without time zone | YES | clock_timestamp() | - | 创建时间 | | `update_by` | character varying(64) | YES | '' | - | 修改人账号 | | `update_time` | timestamp without time zone | YES | clock_timestamp() | - | 修改时间 | | `del_flag` | character(1) | YES | '0' | - | 逻辑删除标志 ('0' 存在, '2' 删除) | ### 2.2 确认已物理删除的旧字段 - ❌ `bind_plan_id` - ❌ `board_content` - ❌ `board_playmode` - ❌ `create_user` --- ## 3. 后端最小兼容整改明细 ### 3.1 实体模型对齐 (`TrainElectronicBoard.java`) - 剔除 `bindPlanId`、`boardContent`、`boardPlaymode`、`createUser`。 - 补充 `boardName`、`apiEndpoint`、`delFlag`。 - 标注 `@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")`。 ### 3.2 映射器对齐与逻辑删除 (`TrainElectronicBoardMapper.xml`) - 彻底剔除不存在的旧列,加入 `board_name` 与 `api_endpoint`。 - 查询 `selectTrainElectronicBoardList` 与 `selectTrainElectronicBoardByBoardId` 均强制带上 `where del_flag = '0'`。 - 逻辑删除: ```sql update train_electronic_board set del_flag = '2', update_time = clock_timestamp() where board_id = #{boardId} ``` ### 3.3 业务服务层写保护与主键闭环 (`TrainElectronicBoardServiceImpl.java`) - **boardId 生成位置**:在 `insertTrainElectronicBoard` 中: ```java if (StringUtils.isEmpty(trainElectronicBoard.getBoardId())) { trainElectronicBoard.setBoardId(IdUtils.fastSimpleUUID()); } trainElectronicBoard.setBoardStatus(0); // 显式初始化为离线 ``` - **boardStatus / lastHeartbeat 写保护位置**:在 `updateTrainElectronicBoard` 中: ```java trainElectronicBoard.setBoardStatus(null); trainElectronicBoard.setLastHeartbeat(null); ``` ### 3.4 控制器与接口兼容 (`TrainElectronicBoardController.java`) - 路由基路径:`@RequestMapping("/train/board")`。 - 权限保持系统正式权限:`@ss.hasPermi('system:board:...')`。 --- ## 4. 前端表单与列表重构 (`build_ui/src/views/train/board/index.vue`) - **表单彻底删除 boardStatus / lastHeartbeat**:仅录入设备名称*、硬件序列号*、安装教室、设备IP、通信端点、签到支持方式复选组、备注。 - **列表优雅展示**:安装教室根据 ID 映射显示 `roomName`;状态 Tag 化(绿标签“在线”/灰标签“离线”);心跳空显示“—”。 --- ## 5. KingbaseES 9 步最小 Smoke Test 实测结果 在直连真实 KingbaseES 测试(`BoardSmokeTest.java`)中执行全部 9 项测试,结果全绿: 1. **新增 Board(不传 boardId)**:Service 生成 UUID 并成功执行 INSERT。 2. **查询 Board**:验证存在,初始 `board_status` 为 0(离线),`last_heartbeat` 为 NULL。 3. **修改业务字段**:名称与 IP 成功更新。 4. **确认写保护**:修改无法人为篡改 `boardStatus` 与 `lastHeartbeat`,DB 原值完好。 5. **删除 Board**:执行软删除 UPDATE。 6. **DB 物理验证**:底层行记录仍存在,`del_flag` 成功标记为 `'2'`。 7. **业务 list 验证**:业务 list 查询自动排除,已不再返回该设备。 8. **新增绑定教室 Board**:成功插入绑定测试教室的班牌。 9. **Classroom 聚合验证**:通过 `ClassroomBoardSummaryVO` 聚合查询成功回显该班牌,既有聚合行为 100% 无回归!