184 lines
9.3 KiB
Markdown
184 lines
9.3 KiB
Markdown
# 03 RailwaySystem 与 DMS 领域模型映射体系 (Domain Mapping)
|
||
|
||
> **核心原则**:**RailwaySystem 是住宿业务事实的唯一真源 (Source of Truth)**。
|
||
> **DMS 平台**仅作为外部门禁与物联网设备的执行端与监控端。
|
||
> **严禁**:以 DMS 房间状态 (`status`) 直接替代 RailwaySystem 住宿占用与床位台账。
|
||
|
||
---
|
||
|
||
## 1. 核心实体对应关系总览 (Mermaid 架构图)
|
||
|
||
```mermaid
|
||
classDiagram
|
||
direction TB
|
||
|
||
class RailwayTrainingPlan {
|
||
+String planId "内部培训班计划ID"
|
||
+String planName
|
||
+Date trainStart
|
||
+Date trainEnd
|
||
}
|
||
|
||
class RailwayEnrollment {
|
||
+Long enrollmentId "参训学员档案ID"
|
||
+String planId
|
||
+String studentId
|
||
+Integer reportStatus
|
||
}
|
||
|
||
class RailwayAccommodation {
|
||
+Long accommodationId "住宿安排事实ID (Source of Truth)"
|
||
+Long enrollmentId
|
||
+String dormId
|
||
+String bedNo
|
||
+Integer accommodationStatus "0预分配, 1已入住, 2已退宿"
|
||
}
|
||
|
||
class RailwayDormitoryInfo {
|
||
+String dormId "本地宿舍UUID"
|
||
+String dormBuilding "楼栋"
|
||
+String dormFloor "楼层"
|
||
+String dormRoom "房号"
|
||
+Integer capacity "床位容量"
|
||
}
|
||
|
||
class ExternalResourceMapping {
|
||
+Long mappingId
|
||
+String localDormId "关联本地宿舍"
|
||
+Long dmsProjectId "DMS租户/物业站点ID"
|
||
+Long dmsPlaceId "DMS房间ID"
|
||
+String dmsBuilding
|
||
+String dmsFloor
|
||
+String dmsRoom
|
||
+Integer mappingStatus "1已绑定, 0待校验"
|
||
}
|
||
|
||
class DmsPlaceRoom {
|
||
<<DMS Remote>>
|
||
+Long id "DMS placeId"
|
||
+Long projectId "DMS租户ID (≠ planId)"
|
||
+String building
|
||
+String floor
|
||
+String room
|
||
}
|
||
|
||
class DmsDoorLock {
|
||
<<DMS Remote>>
|
||
+Long lockId "DMS锁ID"
|
||
+String hardwareId "锁硬件SN (如 5C9F539A)"
|
||
+Long placeId
|
||
+Integer battery
|
||
+Integer signal
|
||
}
|
||
|
||
class DoorAuthorization {
|
||
+Long authId "本地授权凭证主记录"
|
||
+Long accommodationId
|
||
+Long dmsLockId
|
||
+String dmsHardwareId
|
||
+Long dmsKeyId "DMS返回的钥匙ID"
|
||
+String credentialType "PASSWORD / CARD"
|
||
+Timestamp validStart
|
||
+Timestamp validUntil
|
||
+Integer authStatus "PENDING / ACTIVE / REVOKED"
|
||
}
|
||
|
||
class ExternalOperationRecord {
|
||
+Long operationLocalId
|
||
+Long authId
|
||
+String dmsOperationId "DMS异步操作流水ID"
|
||
+Integer requestType "1下发密码, 3删除密码等"
|
||
+String operationStatus "undone / success / failed / timeout"
|
||
+Integer pollCount
|
||
+Timestamp nextPollTime
|
||
}
|
||
|
||
RailwayTrainingPlan "1" --> "0..*" RailwayEnrollment : 包含
|
||
RailwayEnrollment "1" --> "1" RailwayAccommodation : 产生住宿安排
|
||
RailwayAccommodation "0..*" --> "1" RailwayDormitoryInfo : 分配房间
|
||
RailwayDormitoryInfo "1" --> "0..1" ExternalResourceMapping : 稳定映射
|
||
ExternalResourceMapping "1" ..> "1" DmsPlaceRoom : 对应DMS物理房间
|
||
DmsPlaceRoom "1" ..> "0..*" DmsDoorLock : 挂载智能门锁 (支持一房多锁)
|
||
RailwayAccommodation "1" --> "0..*" DoorAuthorization : 派生门锁授权
|
||
DoorAuthorization "1" --> "0..*" ExternalOperationRecord : 追踪异步执行
|
||
```
|
||
|
||
---
|
||
|
||
## 2. 关键实体边界与重大概念澄清
|
||
|
||
### 2.1 铁律:`DMS projectId ≠ RailwaySystem Training Plan ID`
|
||
- **DMS `projectId`**(示例中为 `319402846`、`3837087560`):代表 DMS 物联网平台的**物业项目/租户/公寓站点 ID**。属于系统级或物理站点级的静态上下文配置,由设备供应商分配。
|
||
- **RailwaySystem `plan_id`**(如 `PLAN20260901`):代表铁路局/段内的**具体教学培训开班批次**。生命周期通常为几天到几周。
|
||
- **红线**:严禁将 DMS `projectId` 错写成或动态传为学员开班 `planId`!在配置文件中应统一作为 `dms.project-id` 进行站点级静态受控配置。
|
||
|
||
### 2.2 铁律:本地住宿事实是唯一真源 (`Local Source of Truth`)
|
||
- DMS 的 `room.status`(0:空置, 1:已入住, 2:脏房等)仅为其平台或第三方酒店系统的简单标记,**绝对不能用于覆盖或推断 RailwaySystem 的床位与入住状态**。
|
||
- 只有 RailwaySystem 自身的 `train_accommodation` 与 `train_enrollment` 能决定学员是否在住、床位是否已满、是否已报到。
|
||
- DMS 门锁授权状态仅是硬件执行层面的技术属性(开门凭据是否已在锁具上成功生效)。
|
||
|
||
---
|
||
|
||
## 3. 房间与门锁映射策略深度比选 (Mapping Proposals)
|
||
|
||
### 3.1 房间映射 (Local Dormitory ↔ DMS Place)
|
||
DMS 提供了两种查询房间的途径:
|
||
- 模糊查询列表:`POST /rest/place/room/list`
|
||
- 精确查询:`POST /rest/place/room/get`(入参:`building`, `floor`, `room`)
|
||
|
||
| 方案 | 实现方式 | 优缺点分析 | 结论 |
|
||
| :--- | :--- | :--- | :--- |
|
||
| **方案 1:直接在 `train_dormitory_info` 加列** | 增加 `dms_place_id`, `dms_project_id`, `dms_sync_time` | **优点**:查询直观,单表读取。<br>**缺点**:污染本地物理宿舍模型;若未来接入其他门禁厂商(如海康、大华),列定义难以复用。 | 可作为一期过渡备选 |
|
||
| **方案 2:独立 `train_external_resource_mapping` 映射表** | 建立独立映射表:`local_resource_type ('DORMITORY')`, `local_id`, `vendor ('DMS')`, `external_id (placeId)`, `metadata_json` | **优点**:模型高度解耦;本地宿舍资源生命周期不受外部影响;天然支持多厂商与资源解绑/重绑。<br>**缺点**:需要多做一次关联查询。 | **推荐采纳** |
|
||
|
||
**映射规则明确**:
|
||
- **严禁**每次下发授权时现场调用 `/rest/place/room/get` 进行文本字符串模糊匹配。网络抖动或楼栋名称微小差异(例如 "1号楼" vs "楼栋1")会导致授权链路阻断。
|
||
- **必须**在管理端提供“房源映射绑定/同步”功能,预先在数据库中持久化 `localDormId ↔ dmsPlaceId` 的权威主键映射。
|
||
|
||
### 3.2 门锁映射:支持“一房多锁”模型 (`One Room to Multi-Locks`)
|
||
DMS 接口 `POST /rest/doorlock/list`(入参 `placeId`)返回的是一个门锁列表:`rows: [...]`。
|
||
这证实了物理现实:**一个公寓房间可能没有门锁(0把)、有一把门锁(1把)、或者有多个门锁(例如外防盗门锁 + 内卧室锁,多把锁)**。
|
||
|
||
- **错误做法**:在 `train_dormitory_info` 中仅保留单一的 `lock_device_sn` 字符串,假设一房仅有一锁。
|
||
- **推荐设计**:
|
||
- 系统必须能够处理一个 `placeId` 对应 `0..N` 把门锁的情况。
|
||
- 当为学员下发该房间的开门权限时,集成适配器应查询该房间绑定的**所有有效门锁**,并为每把锁分别申请/下发开门凭据,生成对应的 `DoorAuthorization` 记录。
|
||
|
||
---
|
||
|
||
## 4. 详细字段级映射字典 (Field-Level Mapping Dictionary)
|
||
|
||
### 4.1 宿舍/房间信息映射
|
||
| RailwaySystem 本地字段 | DMS 对应字段 | 类型转换 / 映射规则 | 说明 |
|
||
| :--- | :--- | :--- | :--- |
|
||
| `train_dormitory_info.dorm_id` | `mapping.local_dorm_id` | `VARCHAR(32)` (UUID) | 本地主键 |
|
||
| - | `dms.place.id` / `placeId` | `BIGINT` | DMS 房间全局唯一主键 |
|
||
| `train_dormitory_info.dorm_building` | `dms.place.building` | 字符串精确比对/绑定 | 宿舍楼栋名 |
|
||
| `train_dormitory_info.dorm_floor` | `dms.place.floor` | 字符串精确比对/绑定 | 所在楼层 |
|
||
| `train_dormitory_info.dorm_room` | `dms.place.room` | 字符串精确比对/绑定 | 房间号 |
|
||
| - | `dms.place.projectId` | `BIGINT` | 系统级受控站点配置 |
|
||
|
||
### 4.2 门锁设备信息映射
|
||
| RailwaySystem 本地概念 | DMS 对应字段 | 类型 / 格式 | 说明 |
|
||
| :--- | :--- | :--- | :--- |
|
||
| `mapping.external_lock_id` | `doorlock.id` | `BIGINT` | DMS 门锁管理 ID |
|
||
| `train_dormitory_info.lock_device_sn` | `doorlock.hardwareId` | `VARCHAR(64)` (如 `5C9F539A`) | 门锁硬件 SN / 通信 ID |
|
||
| `device_battery` | `doorlock.battery` | `INT` (0~100, 255为未知) | 门锁电量 |
|
||
| `device_signal` | `doorlock.signal` | `INT` (-100~0, -128为未知) | 信号强度 (RSSI) |
|
||
|
||
### 4.3 门禁授权与钥匙下发映射 (Online Password 场景)
|
||
| RailwaySystem 本地字段 | DMS 对应入参 / 字段 | 映射规则与约束 |
|
||
| :--- | :--- | :--- |
|
||
| `train_accommodation.accommodation_id` | - | 本地业务事实归属 |
|
||
| `target_lock_id` | `create.lockId` | 目标门锁的 DMS ID |
|
||
| `auth_start` (配合提早 Buffer) | `create.validStart` | 毫秒级时间戳 (`Long`) |
|
||
| `auth_end` (配合延后 Buffer) | `create.validUntil` | 毫秒级时间戳 (`Long`) |
|
||
| `student_name` | `create.holder` | 学员姓名 (可选,建议填写真实姓名) |
|
||
| - | `create.canOpenAntilock` | 固定设为 `false` (不可开反锁,保障私密安全) |
|
||
| `phone_country` | `create.phoneCountry` | 默认 `+86` |
|
||
| `student_phonenumber` | `create.phoneNumber` | 学员手机号 |
|
||
| `door_password` (一次性生成或安全受控) | `create.password` | 系统可生成4~8位纯数字密码,Pilot建议采用6位限时密码 |
|
||
| `credential_sub_type` | `create.subType` | 固定为 `4` (限时密码) |
|
||
| `external_key_id` | 返回的 `data.id` | DMS 钥匙全局 ID (退宿撤权时作为删除入参) |
|
||
| `dms_operation_id` | 返回的 `data.operationId` | DMS 异步下发任务 ID (用于10秒后状态轮询) |
|