# Ether 主数据域（MDM）功能详细设计文档

**版本**: v1.0（反推自代码）  
**生成日期**: 2026-04-23  
**数据来源**: module-mdm 实际代码反推  
**代码路径**: `ether-pms/module-mdm`

---

## 一、领域概述

### 1.1 领域职责

主数据域（Master Data Management）是 Ether 系统的基础数据层，负责管理物业项目全生命周期的核心主数据，为所有业务域（工单、收费、巡检、维保等）提供统一的数据基座。

核心职责：
- **项目管理**：项目创建、状态流转、成员管理、功能配置
- **空间节点管理**：统一空间体系，树形结构管理楼栋/单元/房间/车位/设备房等
- **巡检标准管理**：巡检标准项库、巡检模板管理
- **巡检记录管理**：设备巡检记录、巡检结果跟踪
- **备件库存管理**：备件台账、分类管理、出入库操作、低库存预警
- **能耗计量管理**：计量点管理、能耗抄表记录、能耗统计分析

### 1.2 核心概念

| 概念 | 说明 | 对应实体 |
|------|------|----------|
| **项目** | 物业管理的基本单元，所有业务数据的归属 | Project |
| **空间节点** | 统一的空间体系，支持树形层级 | SpaceNode |
| **项目配置** | 项目级别的功能开关 | ProjectConfig |
| **项目统计** | 项目维度的汇总统计 | ProjectStatistics |
| **状态历史** | 项目状态变更记录 | ProjectStatusHistory |
| **巡检标准项** | 设备巡检的检查标准库 | InspectionItem |
| **巡检模板** | 按设备类型组织的巡检检查项集合 | InspectionTemplate |
| **巡检记录** | 实际巡检执行记录 | InspectionRecord |
| **备件** | 维修用备品备件 | SparePart |
| **备件分类** | 备件的分类体系 | SparePartCategory |
| **备件记录** | 备件出入库流水 | SparePartRecord |
| **计量点** | 能源计量仪表 | EnergyMeter |
| **能耗记录** | 能源消耗抄表记录 | EnergyConsumption |

### 1.3 领域边界

```
┌─────────────────────────────────────────────────────────────────────────────┐
│                        主数据域（MDM）边界                                    │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐    │
│  │  项目管理  │  │ 空间节点  │  │ 巡检标准  │  │ 备件库存  │  │ 能耗计量  │    │
│  │ Project  │  │SpaceNode │  │InspectItem│  │SparePart │  │  Energy  │    │
│  └──────────┘  └──────────┘  └──────────┘  └──────────┘  └──────────┘    │
│       │              │              │              │              │         │
│       ▼              ▼              ▼              ▼              ▼         │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐    │
│  │ 项目配置  │  │ 设备扩展  │  │ 巡检模板  │  │ 备件分类  │  │ 计量点   │    │
│  │  Config  │  │Equipment │  │ Template │  │ Category │  │  Meter   │    │
│  └──────────┘  └──────────┘  └──────────┘  └──────────┘  └──────────┘    │
│                                                                             │
├─────────────────────────────────────────────────────────────────────────────┤
│  依赖关系：                                                                 │
│  - 所有实体均以 projectId 为核心维度                                         │
│  - SpaceNode 是空间基座，设备/计量点/巡检均关联空间节点                       │
│  - 巡检模板引用巡检标准项                                                    │
│  - 备件记录关联备件和工单                                                    │
└─────────────────────────────────────────────────────────────────────────────┘
```

---

## 二、数据结构设计

### 2.1 实体总览

| # | 实体 | 表名 | 模块 | 说明 |
|---|------|------|------|------|
| 1 | Project | mdm_project | 项目管理 | 项目基础信息 |
| 2 | ProjectConfig | mdm_project_config | 项目管理 | 项目功能配置 |
| 3 | ProjectStatistics | mdm_project_statistics | 项目管理 | 项目统计快照 |
| 4 | ProjectStatusHistory | mdm_project_status_history | 项目管理 | 状态变更历史 |
| 5 | SpaceNode | mdm_space_node | 空间管理 | 统一空间节点（含设备扩展） |
| 6 | InspectionItem | mdm_inspection_item | 巡检标准 | 巡检标准项 |
| 7 | InspectionTemplate | ops_inspection_template | 巡检模板 | 巡检检查模板 |
| 8 | InspectionRecord | mdm_inspection_record | 巡检记录 | 巡检执行记录 |
| 9 | SparePart | ops_spare_part | 备件管理 | 备件台账 |
| 10 | SparePartCategory | ops_spare_part_category | 备件管理 | 备件分类 |
| 11 | SparePartRecord | ops_spare_part_record | 备件管理 | 出入库记录 |
| 12 | EnergyMeter | ops_energy_meter | 能耗管理 | 计量点 |
| 13 | EnergyConsumption | ops_energy_consumption | 能耗管理 | 能耗记录 |

### 2.2 Project（项目）

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| id | UUID | 是 | 主键，自动生成 |
| code | String(50) | 是 | 项目编码，唯一，正则 `^[a-zA-Z0-9_-]+$`，2-50位 |
| name | String(100) | 是 | 项目名称，2-100位 |
| description | String(500) | 否 | 项目描述 |
| address | String(100) | 否 | 项目地址 |
| projectType | Enum(ProjectType) | 否 | 项目类型，默认 RESIDENTIAL |
| province | String(50) | 否 | 省 |
| city | String(50) | 否 | 市 |
| district | String(50) | 否 | 区 |
| longitude | Double | 否 | 经度 |
| latitude | Double | 否 | 纬度 |
| status | String(20) | 是 | 项目状态，默认 ACTIVE |
| buildingCount | Integer | 否 | 楼栋数 |
| unitCount | Integer | 否 | 单元数 |
| roomCount | Integer | 否 | 房间数 |
| floorCount | Integer | 否 | 楼层数 |
| logo | String(200) | 否 | 项目Logo |
| contact | String(200) | 否 | 联系人 |
| contactPhone | String(20) | 否 | 联系电话，正则 `^1[3-9]\d{9}$` |
| createdAt | LocalDateTime | 是 | 创建时间，自动填充 |
| updatedAt | LocalDateTime | 是 | 更新时间，自动填充 |

**枚举：ProjectType**

| 值 | 描述 |
|----|------|
| RESIDENTIAL | 住宅 |
| OFFICE | 办公 |
| INDUSTRIAL_PARK | 产业园区 |

**项目状态值（String类型，非枚举）**

| 值 | 描述 | 前端颜色 |
|----|------|----------|
| ACTIVE | 正常 | success |
| DISABLED | 禁用 | error |
| PENDING | 待审核 | warning |
| ARCHIVED | 已归档 | default |

### 2.3 ProjectConfig（项目配置）

| 字段 | 类型 | 必填 | 默认值 | 说明 |
|------|------|------|--------|------|
| id | UUID | 是 | - | 主键 |
| projectId | UUID | 是 | - | 项目ID，唯一 |
| enableReservation | Boolean | 否 | false | 预约功能 |
| enableVisitor | Boolean | 否 | false | 访客功能 |
| enableComplaint | Boolean | 否 | true | 投诉功能 |
| enablePayment | Boolean | 否 | false | 缴费功能 |
| enableAnnouncement | Boolean | 否 | true | 公告功能 |
| enableSurvey | Boolean | 否 | false | 问卷功能 |
| enableVote | Boolean | 否 | false | 投票功能 |
| enableMaintenance | Boolean | 否 | true | 报修功能 |
| enableAsset | Boolean | 否 | false | 资产功能 |
| customConfig | String(5000) | 否 | - | 自定义配置JSON |
| createdAt | LocalDateTime | - | 自动 | 创建时间 |
| updatedAt | LocalDateTime | - | 自动 | 更新时间 |

### 2.4 ProjectStatistics（项目统计）

| 字段 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| id | UUID | - | 主键 |
| projectId | UUID | - | 项目ID，唯一 |
| memberCount | Integer | 0 | 成员数 |
| buildingCount | Integer | 0 | 楼栋数 |
| unitCount | Integer | 0 | 单元数 |
| roomCount | Integer | 0 | 房间数 |
| ownerCount | Integer | 0 | 业主数 |
| tenantCount | Integer | 0 | 租户数 |
| lastSyncedAt | LocalDateTime | - | 最后同步时间 |
| createdAt | LocalDateTime | 自动 | 创建时间 |
| updatedAt | LocalDateTime | 自动 | 更新时间 |

### 2.5 ProjectStatusHistory（状态变更历史）

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| id | UUID | 是 | 主键 |
| projectId | UUID | 是 | 项目ID |
| fromStatus | String(20) | 否 | 原状态 |
| toStatus | String(20) | 是 | 新状态 |
| reason | String(500) | 否 | 变更原因 |
| operatorId | UUID | 否 | 操作人ID |
| operatorName | String(50) | 否 | 操作人姓名 |
| createdAt | LocalDateTime | 自动 | 创建时间 |

### 2.6 SpaceNode（空间节点）— 核心实体

SpaceNode 是 MDM 域最复杂的实体，采用统一空间模型 + 设备扩展字段的设计。

#### 2.6.1 基础字段

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| id | UUID | 是 | 主键 |
| projectId | UUID | 是 | 项目ID（注意：列名为 project_code） |
| name | String(100) | 是 | 节点名称，1-100位 |
| fullName | String(500) | 否 | 全路径名称 |
| shortName | String(50) | 否 | 简称 |
| nodeCategory | Enum(NodeCategory) | 是 | 节点大类 |
| nodeType | Enum(NodeType) | 是 | 节点类型 |
| usageType | String(30) | 否 | 用途类型 |
| parentId | UUID | 否 | 父节点ID |
| treePath | String(1000) | 否 | 物理路径 id.id.id |
| treePathName | String(1000) | 否 | 名称路径 项目/楼栋/单元/房间 |
| level | Integer | 否 | 层级深度，默认0 |
| sortOrder | Integer | 否 | 排序号，默认0 |
| status | String(20) | 否 | 状态，默认 ACTIVE |
| deliveryStatus | String(20) | 否 | 交付状态 |
| decorationStatus | String(20) | 否 | 装修状态 |

#### 2.6.2 面积信息

| 字段 | 类型 | 说明 |
|------|------|------|
| buildingArea | BigDecimal(10,2) | 建筑面积(㎡) |
| usableArea | BigDecimal(10,2) | 使用面积(㎡) |
| sharedArea | BigDecimal(10,2) | 公摊面积(㎡) |
| landArea | BigDecimal(10,2) | 占地面积(㎡) |

#### 2.6.3 地理信息

| 字段 | 类型 | 说明 |
|------|------|------|
| longitude | BigDecimal(10) | 经度 |
| latitude | BigDecimal(10) | 纬度 |
| altitude | BigDecimal(8,2) | 海拔 |
| floorNumber | Integer | 楼层号(正数地上,负数地下) |

#### 2.6.4 地址信息

| 字段 | 类型 | 说明 |
|------|------|------|
| province | String(50) | 省 |
| city | String(50) | 市 |
| district | String(50) | 区 |
| street | String(100) | 街道 |
| address | String(255) | 详细地址 |

#### 2.6.5 扩展属性

| 字段 | 类型 | 说明 |
|------|------|------|
| attributes | String(2000) | 类型特定属性（JSON格式） |

#### 2.6.6 设备扩展字段（isEquipment=true 时使用）

| 字段 | 类型 | 说明 |
|------|------|------|
| isEquipment | Boolean | 是否为设备节点，默认false |
| designLifeYears | Integer | 设计寿命(年) |
| ratedPower | BigDecimal(10,2) | 额定功率 |
| ratedVoltage | BigDecimal(10,2) | 额定电压 |
| ratedCurrent | BigDecimal(10,2) | 额定电流 |
| maintenanceVendor | String(100) | 维保厂商 |
| maintenanceVendorContact | String(50) | 维保联系人 |
| maintenanceVendorPhone | String(20) | 维保电话 |
| maintenanceContractNo | String(50) | 维保合同号 |
| maintenanceContractStart | LocalDate | 合同开始日期 |
| maintenanceContractEnd | LocalDate | 合同结束日期 |
| specialEquipmentType | String(50) | 特种设备类型 |
| specialEquipmentCert | String(100) | 特种设备证书 |
| inspectionCycle | Integer | 巡检周期(天) |
| nextInspectionDate | LocalDate | 下次年检日期 |
| lastInspectionDate | LocalDate | 上次年检日期 |
| lastInspectionResult | String(20) | 上次年检结果 |
| commonSpareParts | String(2000) | 常用备件(JSON) |
| energyConsumptionStandard | BigDecimal(12,2) | 能耗标准 |
| installationEnvironment | String(50) | 安装环境 |
| protectionLevel | String(20) | 防护等级 |

#### 2.6.7 系统字段

| 字段 | 类型 | 说明 |
|------|------|------|
| createdAt | LocalDateTime | 创建时间 |
| updatedAt | LocalDateTime | 更新时间 |
| createdBy | UUID | 创建人 |
| updatedBy | UUID | 更新人 |
| isDeleted | Boolean | 软删除标记，默认false |

#### 2.6.8 NodeCategory 枚举（节点大类）

| 值 | 描述 |
|----|------|
| BUILDING | 建筑空间 |
| PARKING | 停车空间 |
| FACILITY | 设施空间 |
| AREA | 区域空间 |

#### 2.6.9 NodeType 枚举（节点类型）— 含分类和层级

| 值 | 描述 | 所属大类 | 层级序号 |
|----|------|----------|----------|
| BUILDING | 楼栋 | BUILDING | 1 |
| UNIT | 单元 | BUILDING | 2 |
| FLOOR | 楼层 | BUILDING | 3 |
| ROOM | 房间 | BUILDING | 4 |
| SHOP | 商铺 | BUILDING | 2 |
| GARAGE | 车库 | PARKING | 1 |
| PARKING_AREA | 停车区域 | PARKING | 2 |
| PARKING_SPACE | 车位 | PARKING | 3 |
| EQUIPMENT_ROOM | 设备房 | FACILITY | 1 |
| PROPERTY_OFFICE | 物业用房 | FACILITY | 1 |
| SECURITY_ROOM | 门岗 | FACILITY | 1 |
| PUBLIC_ROOM | 公共用房 | FACILITY | 1 |
| PUBLIC_AREA | 公共区域 | AREA | 1 |
| GREEN_AREA | 绿化区域 | AREA | 1 |
| ROAD | 道路 | AREA | 1 |

#### 2.6.10 索引设计

| 索引名 | 列 | 说明 |
|--------|-----|------|
| idx_space_node_project | project_id | 按项目查询 |
| idx_space_node_parent | parent_id | 查子节点 |
| idx_space_node_type | node_type | 按类型查询 |
| idx_space_node_tree_path | tree_path | 路径查询 |
| idx_sn_project_parent | project_id, parent_id | 项目+父节点 |
| idx_sn_project_type | project_id, node_type | 项目+类型 |
| idx_sn_project_isequipment | project_id, is_equipment | 项目+设备 |
| idx_sn_project_nextinspection | project_id, next_inspection_date | 年检预警 |

### 2.7 InspectionItem（巡检标准项）

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| id | UUID | 是 | 主键 |
| equipmentType | String(50) | 否 | 设备类型 |
| systemType | String(50) | 否 | 系统类型 |
| itemName | String(200) | 是 | 检查项名称 |
| checkMethod | String(200) | 否 | 检查方法 |
| standardValue | String(100) | 否 | 标准值 |
| isRequired | Boolean | 否 | 是否必检，默认true |
| remark | String(500) | 否 | 备注 |
| sortOrder | Integer | 否 | 排序号 |
| status | Enum(Status) | 否 | 状态，默认ACTIVE |
| createdAt | LocalDateTime | 自动 | 创建时间 |
| updatedAt | LocalDateTime | 自动 | 更新时间 |

**枚举：Status**

| 值 | 描述 |
|----|------|
| ACTIVE | 启用 |
| INACTIVE | 停用 |

### 2.8 InspectionTemplate（巡检模板）

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| id | UUID | 是 | 主键 |
| projectId | UUID | 是 | 项目ID |
| templateCode | String | 是 | 模板编码，唯一 |
| templateName | String | 是 | 模板名称 |
| equipmentType | String | 是 | 设备类型 |
| inspectionItems | String(5000) | 否 | 检查项(JSON) |
| estimatedDuration | Integer | 否 | 预计耗时(分钟) |
| status | Enum(Status) | 否 | 状态，默认ACTIVE |
| version | Integer | 否 | 版本号，默认1 |
| createdBy | String | 否 | 创建人 |
| createdAt | LocalDateTime | 自动 | 创建时间 |
| updatedAt | LocalDateTime | 自动 | 更新时间 |

### 2.9 InspectionRecord（巡检记录）

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| id | UUID | 是 | 主键 |
| planId | UUID | 否 | 巡检计划ID |
| equipmentId | UUID | 是 | 设备ID |
| inspectionDate | LocalDate | 是 | 巡检日期 |
| inspector | String(200) | 是 | 巡检人 |
| status | Enum(CheckStatus) | 否 | 检查状态，默认NORMAL |
| checkInTime | LocalDateTime | 否 | 签到时间 |
| checkInLocation | String(100) | 否 | 签到位置 |
| checkInPhoto | String(200) | 否 | 签到照片 |
| items | JSONB | 否 | 检查项结果列表 |
| problems | JSONB | 否 | 异常问题列表 |
| completed | Boolean | 否 | 是否完成，默认false |
| completedTime | LocalDateTime | 否 | 完成时间 |
| createdAt | LocalDateTime | 自动 | 创建时间 |

**枚举：CheckStatus**

| 值 | 描述 |
|----|------|
| NORMAL | 正常 |
| WARNING | 预警 |
| ABNORMAL | 异常 |

**items JSONB 结构示例**：
```json
[
  { "itemId": "uuid", "itemName": "检查项", "value": "实测值", "result": "PASS/FAIL", "remark": "备注" }
]
```

**problems JSONB 结构示例**：
```json
[
  { "desc": "问题描述", "photo": "照片URL", "severity": "LOW/MEDIUM/HIGH" }
]
```

**索引设计**：

| 索引名 | 列 |
|--------|-----|
| idx_ir_equipment_date | equipment_id, inspection_date |
| idx_ir_inspectiondate | inspection_date |

### 2.10 SparePart（备件）

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| id | UUID | 是 | 主键 |
| projectId | UUID | 是 | 项目ID |
| sparePartCode | String | 是 | 备件编码，唯一 |
| sparePartName | String | 是 | 备件名称 |
| categoryId | UUID | 否 | 分类ID |
| specification | String(500) | 否 | 规格型号 |
| unit | String(50) | 是 | 计量单位 |
| safeStock | Integer | 否 | 安全库存，默认0 |
| currentStock | Integer | 否 | 当前库存，默认0 |
| unitPrice | BigDecimal(10,2) | 否 | 单价 |
| supplier | String(200) | 否 | 供应商 |
| supplierContact | String | 否 | 供应商联系方式 |
| location | String(200) | 否 | 存放位置 |
| remarks | String(1000) | 否 | 备注 |
| status | Enum(Status) | 否 | 状态，默认ACTIVE |
| createdAt | LocalDateTime | 自动 | 创建时间 |
| updatedAt | LocalDateTime | 自动 | 更新时间 |

**枚举：Status**

| 值 | 描述 |
|----|------|
| ACTIVE | 启用 |
| INACTIVE | 停用 |

**索引**：`idx_sp_project_status(project_id, status)`

### 2.11 SparePartCategory（备件分类）

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| id | UUID | 是 | 主键 |
| parentId | UUID | 否 | 父分类ID（支持树形） |
| categoryCode | String | 是 | 分类编码，唯一 |
| categoryName | String | 是 | 分类名称 |
| description | String(500) | 否 | 描述 |
| sortOrder | Integer | 否 | 排序号 |
| createdAt | LocalDateTime | 自动 | 创建时间 |

### 2.12 SparePartRecord（备件出入库记录）

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| id | UUID | 是 | 主键 |
| recordCode | String | 是 | 记录编码，唯一 |
| recordType | Enum(RecordType) | 是 | 记录类型 |
| sparePartId | UUID | 是 | 备件ID |
| quantity | Integer | 是 | 数量 |
| balance | Integer | 是 | 余额（操作后库存） |
| relatedOrderId | UUID | 否 | 关联工单ID |
| recordedBy | UUID | 否 | 操作人ID |
| recordDate | LocalDateTime | 否 | 操作时间，默认当前 |
| remarks | String(1000) | 否 | 备注 |

**枚举：RecordType**

| 值 | 描述 |
|----|------|
| IN | 入库 |
| OUT | 出库 |
| CHECK | 盘点 |
| ADJUST | 调整 |

### 2.13 EnergyMeter（计量点）

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| id | UUID | 是 | 主键 |
| projectId | UUID | 是 | 项目ID |
| meterCode | String | 是 | 计量点编码，唯一 |
| meterName | String | 是 | 计量点名称 |
| energyType | Enum(EnergyType) | 是 | 能源类型 |
| spaceNodeId | UUID | 否 | 关联空间节点 |
| installationLocation | String | 否 | 安装位置 |
| ratedCapacity | BigDecimal(10,2) | 否 | 额定容量 |
| unitPrice | BigDecimal(10,4) | 否 | 单价 |
| status | Enum(Status) | 否 | 状态，默认ACTIVE |
| createdAt | LocalDateTime | 自动 | 创建时间 |
| updatedAt | LocalDateTime | 自动 | 更新时间 |

**枚举：EnergyType**

| 值 | 描述 |
|----|------|
| LIGHTING | 照明插座用电 |
| HVAC | 空调用电 |
| POWER | 动力用电 |
| SPECIAL | 特殊用电 |
| WATER | 给排水 |
| GAS | 燃气 |

### 2.14 EnergyConsumption（能耗记录）

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| id | UUID | 是 | 主键 |
| projectId | UUID | 是 | 项目ID |
| meterId | UUID | 是 | 计量点ID |
| consumptionDate | LocalDate | 是 | 消耗日期 |
| previousReading | BigDecimal(12,2) | 否 | 上次读数 |
| currentReading | BigDecimal(12,2) | 否 | 本次读数 |
| consumption | BigDecimal(12,2) | 是 | 消耗量 |
| amount | BigDecimal(10,2) | 否 | 金额 |
| recordedBy | UUID | 否 | 记录人 |
| recordMethod | Enum(RecordMethod) | 否 | 记录方式，默认MANUAL |
| remarks | String(1000) | 否 | 备注 |
| createdAt | LocalDateTime | 自动 | 创建时间 |

**枚举：RecordMethod**

| 值 | 描述 |
|----|------|
| MANUAL | 手动录入 |
| IOT | IoT自动采集 |

**索引**：

| 索引名 | 列 |
|--------|-----|
| idx_ec_meter_date | meter_id, consumption_date |
| idx_ec_project_date | project_id, consumption_date |

### 2.15 实体关系图

```
Project (1) ──→ (N) SpaceNode          通过 projectId 关联
Project (1) ──→ (1) ProjectConfig      通过 projectId 唯一关联
Project (1) ──→ (1) ProjectStatistics   通过 projectId 唯一关联
Project (1) ──→ (N) ProjectStatusHistory 通过 projectId 关联

SpaceNode (1) ──→ (N) SpaceNode        通过 parentId 自关联（树形）
SpaceNode (1) ──→ (0..1) Equipment     通过 isEquipment 标记（设备扩展字段）

EnergyMeter (1) ──→ (N) EnergyConsumption  通过 meterId 关联
EnergyMeter ──→ SpaceNode               通过 spaceNodeId 关联

SparePartCategory (1) ──→ (N) SparePartCategory  通过 parentId 自关联（树形）
SparePartCategory (1) ──→ (N) SparePart          通过 categoryId 关联
SparePart (1) ──→ (N) SparePartRecord            通过 sparePartId 关联

InspectionItem ──→ InspectionTemplate   通过 equipmentType 逻辑关联
InspectionTemplate ──→ InspectionRecord 通过 planId 逻辑关联
InspectionRecord ──→ SpaceNode(Equipment) 通过 equipmentId 关联
```

---

## 三、API接口设计

### 3.1 ProjectController — `/api/mdm/projects`

| 编号 | 方法 | 路径 | 说明 | 请求参数 |
|------|------|------|------|----------|
| PM-001 | GET | / | 分页查询项目列表 | keyword, status, page, size, sortBy, sortDirection |
| PM-010 | GET | /selector | 获取项目选择器列表 | - |
| PM-005 | GET | /generate-code | 生成项目编码 | - |
| - | GET | /{id} | 按ID查询项目 | id(Path) |
| - | GET | /code/{code} | 按编码查询项目 | code(Path) |
| - | POST | / | 创建项目 | Project(Body) |
| - | PUT | /{id} | 更新项目 | id(Path), Project(Body) |
| - | DELETE | /{id} | 删除项目 | id(Path) |
| PM-003 | GET | /{id}/members | 获取项目成员列表 | id(Path), page, size |
| PM-003 | POST | /{id}/members | 添加项目成员 | id(Path), AddMemberRequest(Body) |
| PM-003 | DELETE | /{id}/members/{memberId} | 移除项目成员 | id(Path), memberId(Path) |
| PM-002 | GET | /{id}/statistics | 获取项目统计数据 | id(Path) |
| PM-006 | PUT | /{id}/status | 变更项目状态 | id(Path), ChangeStatusRequest(Body) |
| PM-008 | GET | /{id}/config | 获取项目配置 | id(Path) |
| PM-008 | PUT | /{id}/config | 更新项目配置 | id(Path), ProjectConfigDTO(Body) |
| PM-009 | GET | /{projectId}/delete-check | 项目删除前检查 | projectId(Path) |

**关键DTO**：

```typescript
// ProjectQueryRequest
{ keyword?: string; status?: string; page?: number; size?: number; sortBy?: string; sortDirection?: string }

// ChangeStatusRequest
{ status: string; reason?: string }

// AddMemberRequest
{ userIds: string[]; roleInProject: string }

// ProjectDeleteCheckVO
{ canDelete: boolean; reason?: string; statistics: ProjectDeleteStatistics }
```

### 3.2 SpaceNodeController — `/api/mdm/space-nodes`

| 编号 | 方法 | 路径 | 说明 | 请求参数 |
|------|------|------|------|----------|
| - | GET | / | 分页查询空间节点 | page, size |
| - | GET | /{id} | 查询节点详情 | id(Path) |
| - | GET | /project/{projectId} | 按项目查询节点列表 | projectId(Path) |
| - | GET | /project/{projectId}/tree | 获取项目空间树 | projectId(Path) |
| - | GET | /project/{projectId}/roots | 获取项目根节点 | projectId(Path) |
| - | GET | /project/{projectId}/type/{nodeType} | 按项目+类型查询 | projectId(Path), nodeType(Path) |
| - | GET | /parent/{parentId}/children | 获取子节点列表 | parentId(Path) |
| - | POST | / | 创建空间节点 | SpaceNodeCreateDTO(Body) |
| - | POST | /batch | 批量创建节点 | List\<SpaceNodeCreateDTO\>(Body) |
| - | PUT | /{id} | 更新节点 | id(Path), SpaceNodeUpdateDTO(Body) |
| - | DELETE | /{id} | 删除节点 | id(Path) |
| - | GET | /{id}/delete-check | 删除前检查 | id(Path) |
| - | DELETE | /{id}/cascade | 级联删除（含子节点） | id(Path) |
| - | GET | /{id}/equipment | 获取设备详情 | id(Path) |
| - | GET | /equipment | 获取设备列表 | projectId(Param) |
| - | GET | /special-equipment | 获取特种设备列表 | projectId(Param) |
| - | GET | /expiring-inspection | 获取即将年检设备 | projectId(Param), daysAhead(默认90) |
| - | POST | /equipment | 创建设备 | EquipmentCreateDTO(Body) |
| - | POST | /equipment/batch | 批量创建设备 | List\<EquipmentCreateDTO\>(Body) |
| - | POST | /equipment/import | Excel导入设备 | file(Multipart), projectId(Param) |
| - | GET | /{buildingId}/floor-info | 获取楼栋楼层信息 | buildingId(Path) |
| - | GET | /debug/floor-numbers | 调试：检查房间楼层号 | projectId(Param) |

**关键DTO**：

```typescript
// SpaceNodeCreateDTO / SpaceNodeUpdateForm
{ projectId, name, nodeCategory, nodeType, parentId?, buildingArea?, ... }

// SpaceNodeTreeDTO extends SpaceNode
{ ...SpaceNode, children: SpaceNodeTreeDTO[] }

// SpaceNodeDeleteCheckDTO
{ nodeId, nodeName, childCount, childTypeCount, totalDescendantCount }

// EquipmentCreateDTO
{ projectId, name, nodeType, parentId?, ...设备扩展字段 }

// FloorInfoVO
{ buildingId, buildingName, totalFloors, undergroundFloors, floors: FloorDetailVO[] }
```

### 3.3 InspectionItemController — `/api/mdm/inspection-items`

| 方法 | 路径 | 说明 | 请求参数 |
|------|------|------|----------|
| POST | / | 创建巡检标准项 | InspectionItem(Body) |
| GET | / | 查询巡检标准项列表 | equipmentType?, systemType?, activeOnly? |
| GET | /{id} | 获取标准项详情 | id(Path) |
| PUT | /{id} | 更新标准项 | id(Path), InspectionItem(Body) |
| DELETE | /{id} | 删除标准项 | id(Path) |

**查询逻辑**：activeOnly=true → 仅启用项；equipmentType+systemType → 双条件过滤；equipmentType → 单条件过滤；systemType → 系统类型过滤；无参数 → 全部。

### 3.4 InspectionTemplateController — `/api/ops/inspection-templates`

| 方法 | 路径 | 说明 | 请求参数 |
|------|------|------|----------|
| GET | / | 获取项目模板列表 | projectId(Param) |
| POST | / | 创建模板 | InspectionTemplate(Body) |
| GET | /{id} | 获取模板详情 | id(Path) |
| PUT | /{id} | 更新模板 | id(Path), InspectionTemplate(Body) |
| POST | /{id}/copy | 复制模板 | id(Path), newName(Param) |
| GET | /by-type/{equipmentType} | 按设备类型查模板 | equipmentType(Path) |

### 3.5 InspectionRecordController — `/api/mdm/inspection-records`

| 方法 | 路径 | 说明 | 请求参数 |
|------|------|------|----------|
| POST | / | 创建巡检记录 | InspectionRecord(Body) |
| GET | / | 查询巡检记录列表 | equipmentId?, planId?, inspector?, status?, startDate?, endDate? |
| GET | /{id} | 获取记录详情 | id(Path) |
| PUT | /{id} | 更新记录 | id(Path), InspectionRecord(Body) |
| DELETE | /{id} | 删除记录 | id(Path) |
| POST | /{id}/complete | 完成巡检记录 | id(Path) |

**查询逻辑**：equipmentId+日期范围 → 设备+日期；equipmentId → 设备；planId → 计划；inspector → 巡检人；status → 状态；日期范围 → 时间段；无参数 → 全部。

### 3.6 SparePartController — `/api/ops/spare-parts`

| 方法 | 路径 | 说明 | 请求参数 |
|------|------|------|----------|
| GET | /categories | 获取分类列表 | - |
| POST | /categories | 创建分类 | SparePartCategory(Body) |
| GET | / | 获取备件列表 | projectId(Param), categoryId? |
| GET | /{id} | 获取备件详情 | id(Path) |
| POST | / | 创建备件 | SparePart(Body) |
| PUT | /{id} | 更新备件 | id(Path), SparePart(Body) |
| DELETE | /{id} | 删除备件 | id(Path) |
| GET | /low-stock | 获取低库存备件 | projectId(Param) |
| POST | /in-stock | 入库操作 | StockRequest(Body) |
| POST | /out-stock | 出库操作 | OutStockRequest(Body) |
| GET | /{id}/records | 获取备件出入库记录 | id(Path) |

**关键请求体**：

```typescript
// StockRequest
{ sparePartId: UUID; quantity: Integer; recordedBy?: UUID; remarks?: String }

// OutStockRequest
{ sparePartId: UUID; quantity: Integer; relatedOrderId?: UUID; recordedBy?: UUID; remarks?: String }
```

### 3.7 EnergyController — `/api/ops/energy`

| 方法 | 路径 | 说明 | 请求参数 |
|------|------|------|----------|
| POST | /meters | 创建计量点 | EnergyMeter(Body) |
| GET | /meters | 获取计量点列表 | projectId(Param), energyType? |
| GET | /meters/{id} | 获取计量点详情 | id(Path) |
| PUT | /meters/{id} | 更新计量点 | id(Path), EnergyMeter(Body) |
| DELETE | /meters/{id} | 删除计量点 | id(Path) |
| POST | /consumption | 录入能耗记录 | RecordConsumptionRequest(Body) |
| GET | /consumption/{meterId} | 获取能耗记录 | meterId(Path), startDate?, endDate? |
| GET | /statistics/by-type | 按类型统计能耗 | projectId(Param), month(Param) |
| GET | /statistics/unit-consumption | 单位面积能耗 | projectId(Param), month(Param) |

**关键请求体**：

```typescript
// RecordConsumptionRequest
{ meterId: UUID; currentReading: BigDecimal; recordedBy?: UUID }
```

---

## 四、业务规则

### 4.1 空间节点树形管理

#### 4.1.1 树形结构规则

```
项目 (Project)
├── 楼栋 (BUILDING)          ← NodeCategory.BUILDING, order=1
│   ├── 单元 (UNIT)          ← NodeCategory.BUILDING, order=2
│   │   ├── 楼层 (FLOOR)     ← NodeCategory.BUILDING, order=3
│   │   │   └── 房间 (ROOM)  ← NodeCategory.BUILDING, order=4
│   │   └── 房间 (ROOM)      ← 可跳过楼层直接挂房间
│   └── 公共用房 (PUBLIC_ROOM)
├── 商铺 (SHOP)              ← NodeCategory.BUILDING, order=2（直接挂在项目下）
├── 车库 (GARAGE)            ← NodeCategory.PARKING, order=1
│   ├── 停车区域 (PARKING_AREA) ← NodeCategory.PARKING, order=2
│   │   └── 车位 (PARKING_SPACE) ← NodeCategory.PARKING, order=3
├── 设备房 (EQUIPMENT_ROOM)  ← NodeCategory.FACILITY, order=1
├── 物业用房 (PROPERTY_OFFICE)
├── 门岗 (SECURITY_ROOM)
├── 公共区域 (PUBLIC_AREA)   ← NodeCategory.AREA, order=1
├── 绿化区域 (GREEN_AREA)
└── 道路 (ROAD)
```

#### 4.1.2 树形路径维护

- **treePath**：物理路径，格式 `id1.id2.id3`，用于快速查询所有子孙节点
- **treePathName**：名称路径，格式 `项目/楼栋/单元/房间`，用于展示
- **level**：层级深度，根节点为0，每层+1
- 创建/移动节点时自动维护 treePath 和 treePathName

#### 4.1.3 设备扩展模式

SpaceNode 通过 `isEquipment` 字段标记是否为设备节点。设备节点在基础空间字段之外，额外使用设备扩展字段（维保信息、巡检周期、特种设备证书等）。这种设计将设备信息嵌入空间节点，而非独立设备实体。

#### 4.1.4 删除规则

- 删除前必须调用 `delete-check` 接口检查子节点数量
- 普通删除：仅删除当前节点（有子节点时拒绝）
- 级联删除：删除当前节点及所有子孙节点
- 软删除：通过 `isDeleted` 标记，非物理删除

#### 4.1.5 批量操作

- 批量创建：通过 `batch` 接口，受 `BatchOperationValidator` 限制数量
- Excel导入设备：支持 .xlsx/.xls 格式，最大1000行，文件类型校验

### 4.2 项目状态流转

#### 4.2.1 状态值

| 状态 | 描述 | 可流转到 |
|------|------|----------|
| PENDING | 待审核 | ACTIVE, DISABLED |
| ACTIVE | 正常 | DISABLED, ARCHIVED |
| DISABLED | 禁用 | ACTIVE, ARCHIVED |
| ARCHIVED | 已归档 | -（终态） |

#### 4.2.2 状态变更规则

- 每次状态变更必须记录 `ProjectStatusHistory`（fromStatus, toStatus, reason, operatorId, operatorName）
- 删除项目前必须调用 `delete-check` 检查关联数据
- 存在应收未收费用时无法删除项目

#### 4.2.3 项目成员管理

- 成员角色：PROJECT_MANAGER(项目经理)、PROJECT_ADMIN(项目管理员)、OPERATION_STAFF(运营人员)、FINANCE_STAFF(财务人员)、VIEWER(查看者)
- 员工类型：SECURITY(保安)、CLEANING(保洁)、GARDEN(绿化)、MAINTENANCE(维修)、CUSTOMER_SERVICE(客服)、PROJECT_STAFF(项目人员)
- 支持批量添加成员

### 4.3 巡检标准项管理

#### 4.3.1 标准项库

- 巡检标准项按 `equipmentType`（设备类型）和 `systemType`（系统类型）分类
- 每个标准项包含：检查项名称、检查方法、标准值、是否必检
- 标准项状态：ACTIVE(启用)/INACTIVE(停用)
- 支持按 activeOnly=true 仅查询启用项

#### 4.3.2 巡检模板

- 模板按项目+设备类型组织
- 模板包含检查项列表（JSON格式存储）
- 支持模板版本管理（version字段）
- 支持模板复制（copy接口）
- 模板与标准项通过 equipmentType 逻辑关联

#### 4.3.3 巡检记录

- 记录关联设备（equipmentId）和计划（planId）
- 检查结果状态：NORMAL(正常)/WARNING(预警)/ABNORMAL(异常)
- 支持签到信息（时间、位置、照片）
- 检查项结果和异常问题以JSONB存储
- 完成操作：调用 `complete` 接口标记完成

### 4.4 备件库存管理

#### 4.4.1 库存管理规则

- 每个备件有 `currentStock`（当前库存）和 `safeStock`（安全库存）
- 当 `currentStock < safeStock` 时触发低库存预警
- 低库存查询：`low-stock` 接口返回低于安全库存的备件列表

#### 4.4.2 出入库操作

| 操作 | 说明 | 关键字段 |
|------|------|----------|
| 入库(IN) | 增加库存 | sparePartId, quantity, recordedBy, remarks |
| 出库(OUT) | 减少库存 | sparePartId, quantity, relatedOrderId, recordedBy, remarks |
| 盘点(CHECK) | 库存盘点 | sparePartId, quantity, recordedBy |
| 调整(ADJUST) | 库存调整 | sparePartId, quantity, recordedBy |

- 每次操作记录 `SparePartRecord`，包含操作后余额（balance）
- 出库可关联工单（relatedOrderId）
- 出库时校验库存不能为负

#### 4.4.3 备件分类

- 支持树形分类（parentId 自关联）
- 分类编码唯一
- 备件通过 categoryId 关联分类

### 4.5 能耗计量管理

#### 4.5.1 计量点管理

- 计量点按能源类型分类：照明插座用电、空调用电、动力用电、特殊用电、给排水、燃气
- 计量点关联空间节点（spaceNodeId）
- 计量点状态：ACTIVE(启用)/INACTIVE(停用)

#### 4.5.2 能耗记录

- 抄表记录包含：上次读数、本次读数、消耗量、金额
- 消耗量 = 本次读数 - 上次读数
- 金额 = 消耗量 × 单价（计量点的 unitPrice）
- 记录方式：MANUAL(手动录入)/IOT(IoT自动采集)

#### 4.5.3 能耗统计

- **按类型统计**：`getConsumptionByType(projectId, month)` → `Map<EnergyType, BigDecimal>`
- **单位面积能耗**：`getUnitConsumption(projectId, month)` → 总能耗/总建筑面积
- 支持按日期范围查询能耗趋势

---

## 五、前端操作流程

### 5.1 项目管理流程

```
项目列表页 → 新建项目
    │
    ├── 填写项目基本信息（编码、名称、类型、地址）
    ├── 系统自动生成项目编码（generate-code）
    ├── 创建后自动初始化 ProjectConfig（默认配置）
    └── 跳转到项目详情

项目详情页
    ├── 基本信息Tab：编辑项目信息
    ├── 成员管理Tab：
    │   ├── 查看成员列表（分页）
    │   ├── 添加成员（从企业员工中选择）
    │   └── 移除成员
    ├── 空间管理Tab：跳转到空间节点管理
    ├── 统计数据Tab：查看项目统计
    ├── 配置管理Tab：功能开关配置
    └── 状态管理：变更项目状态（需填写原因）

项目删除
    ├── 先调用 delete-check 检查关联数据
    ├── 有应收未收费用 → 无法删除
    └── 无关联数据 → 确认删除
```

### 5.2 空间节点管理流程

```
空间管理页（左侧树 + 右侧详情）
    │
    ├── 左侧树形导航
    │   ├── 加载项目空间树（getSpaceTree）
    │   ├── 点击节点 → 右侧显示详情
    │   └── 展开/折叠节点
    │
    ├── 右侧详情区
    │   ├── 节点基本信息
    │   ├── 面积信息
    │   ├── 地址信息
    │   └── 子节点列表（表格）
    │
    ├── 新增节点
    │   ├── 选择父节点
    │   ├── 选择节点类型（NodeType）
    │   ├── 自动填充 NodeCategory
    │   └── 填写名称、面积等信息
    │
    ├── 批量创建
    │   ├── 批量创建楼栋/单元/房间
    │   └── 受 BatchOperationValidator 限制
    │
    ├── 设备管理
    │   ├── 创建设备（isEquipment=true）
    │   ├── 批量创建设备
    │   ├── Excel导入设备
    │   ├── 查看设备列表
    │   ├── 查看特种设备列表
    │   └── 查看即将年检设备（90天内）
    │
    └── 删除节点
        ├── 删除前检查（delete-check）
        └── 确认删除或级联删除
```

### 5.3 巡检管理流程

```
巡检标准项管理
    │
    ├── 标准项列表页
    │   ├── 按设备类型/系统类型筛选
    │   ├── 仅查看启用项（activeOnly）
    │   ├── 新增标准项
    │   ├── 编辑标准项
    │   └── 停用/启用标准项
    │
    └── 巡检模板管理
        ├── 模板列表页（按项目筛选）
        ├── 新增模板
        │   ├── 选择设备类型
        │   ├── 配置检查项（从标准项库选择）
        │   └── 设置预计耗时
        ├── 编辑模板
        ├── 复制模板
        └── 按设备类型查模板

巡检记录管理
    │
    ├── 记录列表页
    │   ├── 按设备/计划/巡检人/状态/日期筛选
    │   └── 查看记录详情
    │
    ├── 创建巡检记录
    │   ├── 选择设备
    │   ├── 填写巡检日期和巡检人
    │   ├── 逐项填写检查结果
    │   ├── 上报异常问题
    │   └── 签到（时间、位置、照片）
    │
    └── 完成巡检
        └── 调用 complete 接口标记完成
```

### 5.4 备件管理流程

```
备件分类管理
    │
    ├── 分类列表
    ├── 新增分类（支持树形层级）
    └── 编辑分类

备件台账管理
    │
    ├── 备件列表页
    │   ├── 按项目筛选
    │   ├── 按分类筛选
    │   ├── 低库存预警标识
    │   └── 新增/编辑/删除备件
    │
    ├── 入库操作
    │   ├── 选择备件
    │   ├── 输入入库数量
    │   └── 确认入库 → 更新 currentStock
    │
    ├── 出库操作
    │   ├── 选择备件
    │   ├── 输入出库数量
    │   ├── 可关联工单
    │   └── 确认出库 → 更新 currentStock
    │
    └── 出入库记录
        └── 查看备件的所有操作流水

低库存预警
    │
    └── 低库存备件列表（currentStock < safeStock）
```

### 5.5 能耗管理流程

```
计量点管理
    │
    ├── 计量点列表页
    │   ├── 按项目筛选
    │   ├── 按能源类型筛选
    │   └── 新增/编辑/删除计量点
    │
    └── 计量点详情
        ├── 关联空间节点
        ├── 额定容量、单价
        └── 状态管理

能耗抄表
    │
    ├── 录入能耗
    │   ├── 选择计量点
    │   ├── 输入本次读数
    │   ├── 系统自动计算消耗量和金额
    │   └── 选择记录方式（手动/IoT）
    │
    └── 能耗记录查询
        ├── 按计量点查询
        └── 按日期范围查询

能耗统计
    │
    ├── 按类型统计
    │   └── 指定月份各能源类型消耗量
    │
    └── 单位面积能耗
        └── 总能耗/总建筑面积
```

---

## 六、与原需求文档 02-SPACE_NODE_DESIGN.md 的差异对比

### 6.1 数据模型差异

| 对比项 | 原需求文档设计 | 实际代码实现 | 差异分析 |
|--------|---------------|-------------|----------|
| **API路径前缀** | `/api/v1/mdm/space-nodes` | `/api/mdm/space-nodes` | 去掉了v1版本号 |
| **code字段** | 有 `code` 列，`UNIQUE(project_id, code)` | 无 `code` 列，列名 `project_code` 实际存 projectId | 原设计的空间编码未实现，project_code 列名与实际存储不匹配 |
| **PostGIS字段** | `location GEOMETRY(Point)`, `boundary GEOMETRY(Polygon)` | 无PostGIS字段 | 地图服务未实现，仅保留经纬度数值字段 |
| **attributes字段** | JSONB类型 | String(2000) | 降级为字符串存储JSON，未使用PostgreSQL JSONB |
| **设备扩展字段** | 未设计（设备独立为 asset_equipment 表） | SpaceNode 内嵌设备扩展字段 | 实际采用"空间+设备"混合模型，isEquipment标记 |
| **NodeType枚举** | 无 PUBLIC_ROOM | 增加 PUBLIC_ROOM(公共用房) | 实际增加了公共用房类型 |
| **删除方式** | 未明确 | 软删除（isDeleted字段） | 实际采用软删除 |
| **唯一约束** | `UNIQUE(project_id, code)` | 无唯一约束 | 空间编码唯一性未在数据库层面约束 |
| **索引** | GIST空间索引、GIN属性索引 | 普通B-tree索引 | 无空间索引和JSON索引 |

### 6.2 API接口差异

| 对比项 | 原需求文档设计 | 实际代码实现 | 差异分析 |
|--------|---------------|-------------|----------|
| **树形查询** | `GET /tree` 全局树 | `GET /project/{projectId}/tree` 按项目 | 实际按项目维度查询，更合理 |
| **祖先节点** | `GET /{id}/ancestors` | 未实现 | 祖先链查询缺失 |
| **子孙节点** | `GET /{id}/descendants` | 未实现 | 可通过 treePath LIKE 查询替代 |
| **移动节点** | `PUT /{id}/move` | 未实现 | 节点移动功能缺失 |
| **类型快捷查询** | `/buildings`, `/rooms`, `/parking-spaces`, `/shops` | `GET /project/{projectId}/type/{nodeType}` | 统一为按类型查询，更通用 |
| **批量更新** | `PUT /batch` | 未实现 | 仅支持批量创建 |
| **批量删除** | `DELETE /batch` | 未实现 | 仅支持单个/级联删除 |
| **导入模板下载** | `GET /export/template` | 未实现 | 无模板下载接口 |
| **数据导出** | `GET /export` | 未实现 | 无导出功能 |
| **地图相关** | `/map/markers`, `/map/boundaries`, `/{id}/location`, `/{id}/boundary` | 未实现 | 地图服务完全未实现 |
| **统计分析** | `/statistics`, `/statistics/by-type`, `/statistics/by-status` | 未实现 | 空间统计接口缺失 |
| **删除前检查** | 未设计 | `GET /{id}/delete-check` | 实际增加了安全检查 |
| **级联删除** | 未设计 | `DELETE /{id}/cascade` | 实际增加了级联删除 |
| **设备管理** | 未设计（设备独立模块） | 设备CRUD集成在SpaceNodeController | 空间与设备管理合并 |
| **Excel导入** | 空间节点导入 | 仅设备导入 | 空间节点批量导入未实现 |
| **楼层信息** | 未设计 | `GET /{buildingId}/floor-info` | 实际增加了楼栋楼层信息接口 |

### 6.3 前端差异

| 对比项 | 原需求文档设计 | 实际代码实现 | 差异分析 |
|--------|---------------|-------------|----------|
| **地图模式** | 高德地图集成，支持标注/绘制/路径 | 未实现 | 地图功能完全未开发 |
| **MapEditor组件** | AMap SDK集成 | 未实现 | - |
| **空间编码** | 自动生成空间编码规则 | 未实现 | SpaceNode无code字段 |
| **批量创建房间** | 支持 startFloor/endFloor/roomsPerFloor 模板 | 仅支持 DTO 列表批量创建 | 智能批量创建未实现 |

### 6.4 业务规则差异

| 对比项 | 原需求文档设计 | 实际代码实现 | 差异分析 |
|--------|---------------|-------------|----------|
| **设备模型** | 独立 Equipment 实体（asset_equipment表） | SpaceNode 内嵌设备扩展字段 | 两种模型并存：module-mdm 用 SpaceNode 扩展，module-asset 用独立 Equipment |
| **项目统计** | 数据库视图实时计算 | ProjectStatistics 实体快照 | 实际采用快照模式，需手动同步 |
| **空间编码** | 自动生成编码规则 | 未实现 | 无自动编码机制 |
| **PostGIS** | 空间查询（范围搜索、距离计算） | 未使用 | 无空间数据库能力 |

### 6.5 差异总结

| 类别 | 已实现 | 部分实现 | 未实现 |
|------|--------|----------|--------|
| **数据模型** | 基础字段、树形结构、NodeType枚举 | 设备扩展字段（混合模型） | PostGIS、JSONB、空间编码 |
| **API接口** | 基础CRUD、树形查询、设备管理 | 批量操作 | 地图服务、统计分析、导入导出 |
| **前端** | 树形导航、表单编辑 | - | 地图模式、智能批量创建 |
| **业务规则** | 删除检查、级联删除 | - | 空间编码、空间查询 |

---

## 附录A：服务层接口清单

| 服务 | 关键方法 |
|------|----------|
| ProjectService | create, update, delete, findById, findByCode, queryProjects, getSelectorList, generateCode, changeStatus, checkProjectDelete |
| ProjectMemberService | getMembers, addMembers, removeMember |
| ProjectConfigService | getConfig, updateConfig |
| ProjectStatisticsService | getStatistics |
| SpaceNodeService | create, batchCreate, update, delete, deleteWithChildren, findById, findByProjectId, getTreeByProjectId, findRootsByProjectId, findChildren, findByProjectIdAndNodeType, checkDeleteInfo, getEquipmentById, getEquipmentList, getSpecialEquipmentList, getExpiringInspectionEquipment, createEquipment, batchCreateEquipment, importEquipmentFromExcel, getBuildingFloorInfo |
| InspectionItemService | createItem, getItemById, updateItem, deleteItem, getAllItems, getActiveItems, getItemsByEquipmentType, getItemsBySystemType, getItemsByEquipmentTypeAndSystemType |
| InspectionTemplateService | createTemplate, getTemplateById, updateTemplate, getTemplatesByProject, getTemplatesByType, copyTemplate |
| InspectionRecordService | createRecord, getRecordById, updateRecord, deleteRecord, completeRecord, getAllRecords, getRecordsByEquipment, getRecordsByEquipmentAndDateRange, getRecordsByPlan, getRecordsByInspector, getRecordsByStatus, getRecordsByDateRange |
| SparePartService | createSparePart, getSparePartById, updateSparePart, deleteSparePart, getSparePartsByProject, getSparePartsByCategory, getLowStockParts, inStock, outStock, getSparePartRecords, getCategories, createCategory |
| EnergyMeterService | createMeter, getMeterById, updateMeter, deleteMeter, getMetersByProject, getMetersByType |
| EnergyConsumptionService | recordConsumption, getConsumptionByMeter, getConsumptionByMeterAndDateRange, getConsumptionByType, getUnitConsumption |

---

## 附录B：前端API文件对照

| 前端文件 | 对应后端Controller | 说明 |
|----------|-------------------|------|
| `src/api/project.ts` | ProjectController | 项目CRUD、成员、配置、统计 |
| `src/api/space.ts` | SpaceNodeController | 空间节点CRUD、树形查询 |
| `src/api/inspection-item.ts` | InspectionItemController | 巡检标准项CRUD |
| `src/api/inspection-template.ts` | InspectionTemplateController | 巡检模板CRUD |
| `src/api/inspection-record.ts` | InspectionRecordController | 巡检记录CRUD |
| `src/api/sparepart.ts` | SparePartController | 备件CRUD、出入库 |
| `src/api/energy.ts` | EnergyController | 计量点CRUD、能耗记录 |
| `src/api/maintenance-plan.ts` | - | 维保计划（独立模块） |
| `src/types/project.ts` | - | 项目相关类型定义 |
| `src/types/space.ts` | - | 空间节点类型定义 |

---

**文档生成说明**：本文档基于 `ether-pms/module-mdm` 模块的实际代码反推生成，涵盖13个实体、7个控制器、11个服务接口的完整分析。所有字段、枚举、API端点均来源于实际代码，与原需求文档的差异已在第六章详细对比。
