Files
railwaysystem/docs/development/issue-01-05-dormitory.md
T

153 lines
8.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ISSUE-01-05 宿舍房间与楼宇基础数据维护开发验收文档
## 1. 任务概述与环境基线
- **任务 ID:** `ISSUE-01-05`
- **任务名称:** 宿舍房间与楼宇基础数据维护
- **所属 Epic:** `EPIC-01 基础主数据必要集合`
- **优先级:** P0
- **工作区目录:** `/Users/wzb/Desktop/项目/RailwaySystem-worktrees/issue-01-05-dormitory`
- **当前分支:** `feat/issue-01-05-dormitory`
- **正确基线 Commit:** `4682df03c566776562b693ed5cb48fd98cda2472` (`integration/wave1a-foundation`)
- 基线祖先校验状态:`PASS`(当前分支直接派生自该正式基线)
- **API 契约基准:** `docs/api-v2/02_module_a_base_resource_api.md` 4.4 节、`docs/api-v2/06_dto_vo_catalog.md`、`docs/api-v2/10_permission_and_error_codes.md`
- **数据库基线:** Database V2 (`train_dormitory_info`)
- **Generator 冻结策略:** `YES (单表结构)`(依据 `docs/issues-v1/02_p0_issue_backlog.md` 与 `docs/issues-v1/05_agent_assignment.md`)
- **本轮 Generator 实际执行:** `Generator actually executed = NO`(骨架已在此前生成,本次按 V2 契约与手写逻辑完成重构与对齐,未重新执行 Generator)
- **核心业务目标:** 建立宿舍物理房间主数据台账(楼栋、楼层、房间号、核定容量、适用性别、门锁SN),提供同楼栋房号查重与防重、实时在住人数与剩余床位只读动态聚合、当前入住学员列表回显以及楼栋-楼层-房间三级结构化级联下拉选项。
---
## 2. HTTP Endpoint 最终收口与物理映射
严格依照冻结契约收口 Controller 公开接口,**非冻结接口全部从 Controller 移除,不再对外公开**:
- 彻底移除历史 `/train/dorminfo` 路由及 Alias;
- 彻底移除 `PUT /train/dormitory`、`DELETE /train/dormitory/{dormIds}`、`POST /train/dormitory/export` 等非 P0 接口。
### 2.1 最终公开物理 Endpoint 完整列表(共且仅有 4 个正式 P0)
| 优先级 | HTTP Method | URI 路径 | Controller 方法 | 权限字符 | 适用角色 | 功能说明与契约对齐 |
|:---|:---|:---|:---|:---|:---|:---|
| **P0** | `GET` | `/train/dormitory/list` | `list(TrainDormitoryInfo)` | `train:dormitory:list` | 管理员, 宿管 | 分页查询宿舍列表,附带 capacity、usedCount、remainingBeds |
| **P0** | `GET` | `/train/dormitory/{dormId}` | `getInfo(@PathVariable)` | `train:dormitory:list` | 管理员, 宿管 | 获取指定房间详情及当前入住人员列表 (occupants) |
| **P0** | `POST` | `/train/dormitory` | `add(@Validated @RequestBody)` | `train:dormitory:edit` | 管理员, 宿管 | 新增房间(前置查重与底层唯一约束冲突均转换为 40006) |
| **P0** | `GET` | `/train/dormitory/options` | `options()` | `train:dormitory:list` | 管理员, 宿管 | 获取结构化的楼栋 -> 楼层 -> 房间层级树(分房弹窗必需) |
- **Contract-extra Endpoint 数量:** 0 个。
---
## 3. DTO 与 VO 设计规范
### 3.1 `DormitoryCreateDTO`
- `dormBuilding` (String, `@NotBlank`, `@Size(max = 50)`): 宿舍楼栋
- `dormFloor` (String, `@NotBlank`, `@Size(max = 20)`): 所在楼层
- `dormRoom` (String, `@NotBlank`, `@Size(max = 30)`): 房间号
- `capacity` (Integer, `@NotNull`, `@Min(1)`, `@Max(8)`): 核定床位容量 (1~8)
- `genderType` (Integer, `@NotNull`): 适用性别 (0:不限, 1:男, 2:女)
- `lockDeviceSn` (String, `@Size(max = 64)`): 智能门锁设备序列号 (可选)
- `remark` (String, `@Size(max = 500)`): 备注 (可选)
### 3.2 `DormitoryItemVO`
- `dormId` (String): 宿舍ID主键
- `dormBuilding` (String): 宿舍楼栋
- `dormFloor` (String): 所在楼层
- `dormRoom` (String): 房间号
- `capacity` (Integer): 核定床位容量
- `usedCount` (Integer): 已住人数 (动态聚合自 `train_accommodation`)
- `remainingBeds` (Integer): 剩余床位 (`capacity - usedCount`)
- `genderType` (Integer): 适用性别 (0:不限, 1:男, 2:女)
- `lockDeviceSn` (String): 智能门锁SN
- `dormStatus` (Integer): 状态 (0:禁用, 1:可用)
- `remark` (String): 备注
- `createTime` (Date): 创建时间
### 3.3 `DormitoryOccupantVO`
- `enrollmentId` (Long): 参训档案ID
- `studentId` (String): 学员主档ID
- `studentName` (String): 学员姓名
- `gender` (String): 性别
- `orgName` (String): 所属单位
- `bedNo` (String): 分配床位号 (可选)
- `assignedTime` (Date): 分配入住时间
- `accommodationStatus` (Integer): 住宿状态 (0:预分配, 1:已入住)
### 3.4 `DormitoryDetailVO`
- 包含房间基础信息与动态统计 (`dormId`, `dormBuilding`, `dormFloor`, `dormRoom`, `capacity`, `usedCount`, `remainingBeds`, `genderType`, `lockDeviceSn`, `dormStatus`, `remark`, `createTime`);
- `occupants` (`List<DormitoryOccupantVO>`): 当前入住学员列表(空房时返回 `[]`,严禁返回 `null`)。
### 3.5 `DormOptionsVO`
- 楼栋 -> 楼层 -> 房间三级树节点,包含 `value`, `label`, `type` ("building"/"floor"/"room"), `children`;
- 叶子节点(房间)挂载 `capacity`, `usedCount`, `remainingBeds`, `genderType`, `lockDeviceSn` 元数据,方便前端分房弹窗直接消费。
---
## 4. 业务规则与边界约束
### 4.1 容量与性别规则
- **容量范围:** 严格限定在 $1 \le \text{capacity} \le 8$ 之间,非正数或大于 8 抛出业务校验异常。
- **适用性别:** 必须为合法枚举值(0: 不限, 1: 男, 2: 女)。
### 4.2 动态房态聚合口径
- **依据:** `RuoYi-Vue/sql/train/v2/007_dicts.sql` 中 `train_accommodation_status` 字典定义:
- `0`: 预分配 (报到前系统预先分配)
- `1`: 已入住 (报到确认并已入住)
- `2`: 已退宿 (培训结束已离宿)
- **实际占用定义:** 仅处于“预分配”与“已入住”状态的记录占用床位,退宿后释放。
- **实际 SQL 过滤条件:**
```sql
SELECT dorm_id, COUNT(1) AS used_count
FROM train_accommodation
WHERE accommodation_status IN (0, 1)
GROUP BY dorm_id
```
`remaining_beds = (capacity - COALESCE(acc.used_count, 0))`。
### 4.3 UNIQUE 并发语义保证
- **数据库约束:** `uq_dorm_building_room UNIQUE (dorm_building, dorm_room)`。
- **并发保护机制:**
1. 应用层前置查重:查询 `train_dormitory_info` 是否存在同楼栋同房号未删除记录,存在即抛出 `ServiceException("同一楼栋下该宿舍房号已存在", 40006)`;
2. 底层并发冲突兜底:高并发场景下两请求同时绕过前置查重时,底层 INSERT 触发唯一约束冲突抛出 `DuplicateKeyException`,Service 层显式捕获并转换为 40006 业务异常,杜绝 500 裸异常泄漏。
### 4.4 业务边界铁律
- **Dormitory 仅代表物理房间基础资源:** 负责房间基础资产的维护与只读聚合。
- **无独立 DormBed 实体:** Phase 1 阶段严禁引入 `train_dorm_bed` 表;`bed_no` 仅为 `train_accommodation` 的可空业务字段。
- **禁止 Accommodation 写操作:** 本 Issue 严禁分房、调房、退宿、门禁下发与同步、报到入住办理以及级联物理删除。
---
## 5. 验证结果与质量达标记录
1. **单元测试:**
- 执行测试:`DormitoryServiceTest` 包含 6 个测试用例:
- `testAddAndDuplicateInterception`: 前置防重与 40006 拦截
- `testConcurrentInsertDuplicateKeyConversion`: 高并发 `DuplicateKeyException` 转换为 40006
- `testCapacityAndGenderValidation`: 容量 (1~8) 与性别枚举合法性
- `testList`: 动态聚合 `usedCount` 与 `remainingBeds`
- `testGet`: 房间详情与 `occupants` 列表回显
- `testOptions`: 楼栋-楼层-房间三级树结构组装
- 运行结果:`Tests run: 6, Failures: 0, Errors: 0, Skipped: 0` 全部通过。
2. **模块依赖测试:**
- 命令:`mvn test -pl ruoyi-train -am -f RuoYi-Vue/pom.xml`
- 运行结果:`Tests run: 20, Failures: 0, Errors: 0, Skipped: 0` 全部通过。
3. **后端 Reactor 编译:**
- 命令:`mvn compile -DskipTests -f RuoYi-Vue/pom.xml`
- 运行结果:8 个子模块全部 `SUCCESS`。
4. **前端 ESLint 检查:**
- 命令:`./node_modules/.bin/eslint --no-ignore src/api/train/dormitory.js src/views/train/dormitory/index.vue`
- 运行结果:0 errors, 0 warnings。
5. **前端生产打包 (build:prod):**
- 命令:`npm run build:prod`
- 运行结果:`Build complete. The dist directory is ready to be deployed.` 构建成功。构建完成后已彻底清理临时产物与软链接。
6. **格式检查 (git diff --check):**
- 命令:`git diff --check`
- 运行结果:无任何 trailing whitespace,洁净通过。
7. **Commit 状态:**
- 本地暂存区与工作区保留全部修改,**未执行 git commit**,等待评审。