ether-docs/02-DESIGN/detail/DETAIL-SPACE.md

50 KiB
Raw Permalink Blame History

空间与项目域 - 详细设计

文档版本: v1.0 生成日期: 2026-05-18 数据来源: module-mdm 实际代码 + REVERSE-MDM.md 对照需求: 02-SPACE_NODE_DESIGN.md


一、功能点清单

功能ID 功能名称 优先级 实现状态 对应需求ID
SPACE-001 项目CRUD P0 已实现 02-SPACE-001
SPACE-002 项目编码自动生成 P0 已实现 02-SPACE-002
SPACE-003 项目状态流转 P0 已实现 02-SPACE-003
SPACE-004 项目成员管理 P0 已实现 02-SPACE-004
SPACE-005 项目统计数据 P1 已实现 02-SPACE-005
SPACE-006 项目配置管理 P1 已实现 02-SPACE-006
SPACE-007 项目删除前检查 P0 已实现 02-SPACE-007
SPACE-008 项目选择器列表 P1 已实现 02-SPACE-008
SPACE-009 空间节点CRUD P0 已实现 02-SPACE-010
SPACE-010 空间节点树形查询 P0 已实现 02-SPACE-011
SPACE-011 空间节点批量创建 P1 已实现 02-SPACE-012
SPACE-012 空间节点删除检查 P0 已实现 02-SPACE-013
SPACE-013 空间节点级联删除 P0 已实现 02-SPACE-014
SPACE-014 设备管理(CRUD) P1 已实现(@Deprecated) 02-SPACE-020
SPACE-015 设备批量创建 P2 已实现(@Deprecated) 02-SPACE-021
SPACE-016 设备Excel导入 P2 已实现(@Deprecated) 02-SPACE-022
SPACE-017 特种设备查询 P2 已实现(@Deprecated) 02-SPACE-023
SPACE-018 即将年检设备查询 P2 已实现(@Deprecated) 02-SPACE-024
SPACE-019 楼栋楼层信息 P1 已实现 02-SPACE-030
SPACE-020 巡检标准项CRUD P0 已实现 02-SPACE-040
SPACE-021 巡检模板管理 P1 已实现 02-SPACE-041
SPACE-022 巡检记录CRUD P0 已实现 02-SPACE-042
SPACE-023 巡检完成确认 P1 已实现 02-SPACE-043
SPACE-024 备件CRUD P1 已实现 02-SPACE-050
SPACE-025 备件出入库 P0 已实现 02-SPACE-051
SPACE-026 备件低库存预警 P1 已实现 02-SPACE-052
SPACE-027 备件分类管理 P1 已实现 02-SPACE-053
SPACE-028 计量点CRUD P1 已实现 02-SPACE-060
SPACE-029 能耗记录录入 P1 已实现 02-SPACE-061
SPACE-030 能耗统计 P2 已实现 02-SPACE-062

二、数据结构设计

2.1 实体定义

2.1.1 Project项目

表名: mdm_project

字段名 类型 约束 说明
id UUID PK, 自动生成 项目唯一标识符
code VARCHAR(50) NOT NULL, UNIQUE, 正则^[a-zA-Z0-9_-]+$, 2-50位 项目编码
name VARCHAR(100) NOT NULL, 2-100位 项目名称
description VARCHAR(500) 项目描述
address VARCHAR(100) 项目地址
projectType VARCHAR(20) @Enumerated(STRING), 默认RESIDENTIAL 项目类型枚举
province VARCHAR(50)
city VARCHAR(50)
district VARCHAR(50)
longitude Double 经度
latitude Double 纬度
status VARCHAR(20) NOT NULL, 默认ACTIVE 项目状态
buildingCount Integer 楼栋数
unitCount Integer 单元数
roomCount Integer 房间数
floorCount Integer 楼层数
logo VARCHAR(200) 项目Logo
contact VARCHAR(200) 联系人
contactPhone VARCHAR(20) 正则^1[3-9]\d{9}$ 联系电话
createdAt LocalDateTime NOT NULL, @PrePersist自动填充 创建时间
updatedAt LocalDateTime NOT NULL, @PreUpdate自动填充 更新时间

枚举: ProjectType

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

项目状态值String类型非枚举:

描述
ACTIVE 正常
DISABLED 禁用
PENDING 待审核
ARCHIVED 已归档

索引:

  • mdm_project_code_key → code (UNIQUE)

2.1.2 SpaceNode空间节点-- 核心实体

表名: mdm_space_node

基础字段
字段名 类型 约束 说明
id UUID PK, 自动生成 节点唯一标识符
projectId UUID NOT NULL, column: project_code 项目ID注意列名为project_code
code VARCHAR(50) @JsonIgnore 空间编码(保留字段,暂未使用)
name VARCHAR(100) NOT NULL, 1-100位 节点名称
fullName VARCHAR(500) 全路径名称
shortName VARCHAR(50) 简称
nodeCategory VARCHAR(20) NOT NULL, @Enumerated(STRING), column: node_category 节点大类枚举
nodeType VARCHAR(30) NOT NULL, @Enumerated(STRING), column: node_type 节点类型枚举
usageType VARCHAR(30) 用途类型
parentId UUID column: parent_id 父节点ID
treePath VARCHAR(1000) column: tree_path 物理路径 id.id.id
treePathName VARCHAR(1000) column: tree_path_name 名称路径 项目/楼栋/单元/房间
level Integer 默认0 层级深度
sortOrder Integer column: sort_order, 默认0 排序号
status VARCHAR(20) 默认ACTIVE 状态
deliveryStatus VARCHAR(20) column: delivery_status 交付状态
decorationStatus VARCHAR(20) column: decoration_status 装修状态
面积信息
字段名 类型 约束 说明
buildingArea BigDecimal(10,2) column: building_area 建筑面积(㎡)
usableArea BigDecimal(10,2) column: usable_area 使用面积(㎡)
sharedArea BigDecimal(10,2) column: shared_area 公摊面积(㎡)
landArea BigDecimal(10,2) column: land_area 占地面积(㎡)
地理信息
字段名 类型 约束 说明
longitude BigDecimal(10) 经度
latitude BigDecimal(10) 纬度
altitude BigDecimal(8,2) 海拔
floorNumber Integer column: floor_number 楼层号(正数地上,负数地下)
地址信息
字段名 类型 约束 说明
province VARCHAR(50)
city VARCHAR(50)
district VARCHAR(50)
street VARCHAR(100) 街道
address VARCHAR(255) 详细地址
扩展属性
字段名 类型 约束 说明
attributes VARCHAR(2000) 类型特定属性(JSON格式)
系统字段
字段名 类型 约束 说明
createdAt LocalDateTime column: created_at 创建时间
updatedAt LocalDateTime column: updated_at 更新时间
createdBy UUID column: created_by 创建人
updatedBy UUID column: updated_by 更新人
isDeleted Boolean column: is_deleted, 默认false 软删除标记
设备扩展字段(@Deprecated -- 请使用 module-asset 的 Equipment 实体)
字段名 类型 约束 说明
isEquipment Boolean @Deprecated, column: is_equipment, 默认false 是否为设备节点
designLifeYears Integer @Deprecated, column: design_life_years 设计寿命(年)
ratedPower BigDecimal(10,2) @Deprecated, column: rated_power 额定功率
ratedVoltage BigDecimal(10,2) @Deprecated, column: rated_voltage 额定电压
ratedCurrent BigDecimal(10,2) @Deprecated, column: rated_current 额定电流
maintenanceVendor VARCHAR(100) @Deprecated, column: maintenance_vendor 维保厂商
maintenanceVendorContact VARCHAR(50) @Deprecated, column: maintenance_vendor_contact 维保联系人
maintenanceVendorPhone VARCHAR(20) @Deprecated, column: maintenance_vendor_phone 维保电话
maintenanceContractNo VARCHAR(50) @Deprecated, column: maintenance_contract_no 维保合同号
maintenanceContractStart LocalDate @Deprecated, column: maintenance_contract_start 合同开始日期
maintenanceContractEnd LocalDate @Deprecated, column: maintenance_contract_end 合同结束日期
specialEquipmentType VARCHAR(50) @Deprecated, column: special_equipment_type 特种设备类型
specialEquipmentCert VARCHAR(100) @Deprecated, column: special_equipment_cert 特种设备证书
inspectionCycle Integer @Deprecated, column: inspection_cycle 巡检周期(天)
nextInspectionDate LocalDate @Deprecated, column: next_inspection_date 下次年检日期
lastInspectionDate LocalDate @Deprecated, column: last_inspection_date 上次年检日期
lastInspectionResult VARCHAR(20) @Deprecated, column: last_inspection_result 上次年检结果
commonSpareParts VARCHAR(2000) @Deprecated, column: common_spare_parts 常用备件(JSON)
energyConsumptionStandard BigDecimal(12,2) @Deprecated, column: energy_consumption_standard 能耗标准
installationEnvironment VARCHAR(50) @Deprecated, column: installation_environment 安装环境
protectionLevel VARCHAR(20) @Deprecated, column: protection_level 防护等级

索引:

索引名 说明
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.1.3 ProjectConfig项目配置

表名: mdm_project_config

字段名 类型 约束 说明
id UUID PK, 自动生成 主键
projectId UUID NOT NULL, UNIQUE, column: project_id 项目ID
enableReservation Boolean column: enable_reservation, 默认false 预约功能
enableVisitor Boolean column: enable_visitor, 默认false 访客功能
enableComplaint Boolean column: enable_complaint, 默认true 投诉功能
enablePayment Boolean column: enable_payment, 默认false 缴费功能
enableAnnouncement Boolean column: enable_announcement, 默认true 公告功能
enableSurvey Boolean column: enable_survey, 默认false 问卷功能
enableVote Boolean column: enable_vote, 默认false 投票功能
enableMaintenance Boolean column: enable_maintenance, 默认true 报修功能
enableAsset Boolean column: enable_asset, 默认false 资产功能
customConfig VARCHAR(5000) column: custom_config 自定义配置JSON
createdAt LocalDateTime column: created_at 创建时间
updatedAt LocalDateTime column: updated_at 更新时间

索引:

  • mdm_project_config_project_id_key → projectId (UNIQUE)

2.1.4 ProjectStatistics项目统计

表名: mdm_project_statistics

字段名 类型 约束 说明
id UUID PK, 自动生成 主键
projectId UUID NOT NULL, UNIQUE, column: project_id 项目ID
memberCount Integer column: member_count, 默认0 成员数
buildingCount Integer column: building_count, 默认0 楼栋数
unitCount Integer column: unit_count, 默认0 单元数
roomCount Integer column: room_count, 默认0 房间数
ownerCount Integer column: owner_count, 默认0 业主数
tenantCount Integer column: tenant_count, 默认0 租户数
lastSyncedAt LocalDateTime column: last_synced_at 最后同步时间
createdAt LocalDateTime column: created_at 创建时间
updatedAt LocalDateTime column: updated_at 更新时间

索引:

  • mdm_project_statistics_project_id_key → projectId (UNIQUE)

2.1.5 ProjectStatusHistory状态变更历史

表名: mdm_project_status_history

字段名 类型 约束 说明
id UUID PK, 自动生成 主键
projectId UUID NOT NULL, column: project_id 项目ID
fromStatus VARCHAR(20) column: from_status 原状态
toStatus VARCHAR(20) NOT NULL, column: to_status 新状态
reason VARCHAR(500) 变更原因
operatorId UUID column: operator_id 操作人ID
operatorName VARCHAR(50) column: operator_name 操作人姓名
createdAt LocalDateTime column: created_at, @PrePersist自动填充 创建时间

2.1.6 InspectionItem巡检标准项

表名: mdm_inspection_item

字段名 类型 约束 说明
id UUID PK, 自动生成 主键
equipmentType VARCHAR(50) column: equipment_type 设备类型
systemType VARCHAR(50) column: system_type 系统类型
itemName VARCHAR(200) NOT NULL, column: item_name 检查项名称
checkMethod VARCHAR(200) column: check_method 检查方法
standardValue VARCHAR(100) column: standard_value 标准值
isRequired Boolean column: is_required, 默认true 是否必检
remark VARCHAR(500) 备注
sortOrder Integer column: sort_order 排序号
status VARCHAR(20) NOT NULL, @Enumerated(STRING), 默认ACTIVE 状态枚举
createdAt LocalDateTime column: created_at, @PrePersist自动填充 创建时间
updatedAt LocalDateTime column: updated_at, @PreUpdate自动填充 更新时间

枚举: Status

描述
ACTIVE 启用
INACTIVE 停用

2.1.7 InspectionRecord巡检记录

表名: mdm_inspection_record

字段名 类型 约束 说明
id UUID PK, 自动生成 主键
planId UUID column: plan_id 巡检计划ID
equipmentId UUID NOT NULL, column: equipment_id 设备ID
inspectionDate LocalDate NOT NULL, column: inspection_date 巡检日期
inspector VARCHAR(200) NOT NULL 巡检人
status VARCHAR(20) @Enumerated(STRING), 默认NORMAL 检查状态枚举
checkInTime LocalDateTime column: check_in_time 签到时间
checkInLocation VARCHAR(100) column: check_in_location 签到位置
checkInPhoto VARCHAR(200) column: check_in_photo 签到照片
items JSONB @JdbcTypeCode(JSON), columnDefinition: jsonb 检查项结果列表
problems JSONB @JdbcTypeCode(JSON), columnDefinition: jsonb 异常问题列表
completed Boolean 默认false 是否完成
completedTime LocalDateTime column: completed_time 完成时间
createdAt LocalDateTime column: created_at, @PrePersist自动填充 创建时间

枚举: CheckStatus

描述
NORMAL 正常
WARNING 预警
ABNORMAL 异常

items JSONB结构:

[
  {"itemId": "uuid", "itemName": "检查项", "value": "实测值", "result": "PASS/FAIL", "remark": "备注"}
]

problems JSONB结构:

[
  {"desc": "问题描述", "photo": "照片URL", "severity": "LOW/MEDIUM/HIGH"}
]

索引:

索引名
idx_ir_equipment_date equipment_id, inspection_date
idx_ir_inspectiondate inspection_date

2.2 枚举定义

NodeCategory节点大类

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

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

ProjectType项目类型

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

InspectionItem.Status巡检标准项状态

描述
ACTIVE 启用
INACTIVE 停用

CheckStatus巡检检查状态

描述
NORMAL 正常
WARNING 预警
ABNORMAL 异常

2.3 ER关系图Mermaid

erDiagram
    Project ||--o{ SpaceNode : "1:N projectId"
    Project ||--|| ProjectConfig : "1:1 projectId UNIQUE"
    Project ||--|| ProjectStatistics : "1:1 projectId UNIQUE"
    Project ||--o{ ProjectStatusHistory : "1:N projectId"

    SpaceNode ||--o{ SpaceNode : "自引用树形 parentId"
    SpaceNode ||--o| SpaceNode : "设备扩展 isEquipment=true"

    InspectionItem {
        UUID id PK
        String equipmentType
        String systemType
        String itemName
        String status
    }

    InspectionTemplate {
        UUID id PK
        UUID projectId
        String templateCode
        String equipmentType
        String inspectionItems
    }

    InspectionRecord {
        UUID id PK
        UUID planId
        UUID equipmentId
        LocalDate inspectionDate
        String inspector
        String status
    }

    InspectionRecord }o--|| SpaceNode : "equipmentId"

    SparePartCategory ||--o{ SparePartCategory : "自引用树形 parentId"
    SparePartCategory ||--o{ SparePart : "1:N categoryId"
    SparePart ||--o{ SparePartRecord : "1:N sparePartId"

    EnergyMeter ||--o{ EnergyConsumption : "1:N meterId"
    EnergyMeter }o--o| SpaceNode : "spaceNodeId"

三、API设计

3.1 ProjectController -- /api/mdm/projects

编号 方法 路径 说明 请求参数 响应格式 权限要求 例外情况
PROJ-API-001 GET / 分页查询项目列表 keyword(String, 可选), status(String, 可选), page(int, 默认0), size(int, 默认10), sortBy(String, 可选), sortDirection(String, 可选) {code, data: PageResponse<Project>} 已登录 分页参数越界
PROJ-API-002 GET /selector 获取项目选择器列表 {code, data: [ProjectSelectorItem]} 已登录
PROJ-API-003 GET /generate-code 生成项目编码 {code, data: "PRJ-xxx"} 管理员
PROJ-API-004 GET /{id} 按ID查询项目 id(UUID, Path) {code, data: Project} 已登录 项目不存在
PROJ-API-005 GET /code/{code} 按编码查询项目 code(String, Path) {code, data: Project} 已登录 编码不存在
PROJ-API-006 POST / 创建项目 Body: Project实体 {code, data: Project} 管理员 项目编码已存在; 字段校验失败
PROJ-API-007 PUT /{id} 更新项目 id(UUID, Path), Body: Project实体 {code, data: Project} 管理员 项目不存在; 编码冲突
PROJ-API-008 DELETE /{id} 删除项目 id(UUID, Path) {code, data: null} 管理员 项目不存在; 有关联数据
PROJ-API-009 GET /{id}/members 获取项目成员列表 id(UUID, Path), page(int, 默认0), size(int, 默认20) {code, data: PageResponse<ProjectMemberDTO>} 项目成员 项目不存在
PROJ-API-010 POST /{id}/members 添加项目成员 id(UUID, Path), Body: AddMemberRequest {userIds: [UUID], roleInProject: String} {code, data: null} 项目管理员 项目不存在; 用户不存在; 已是成员
PROJ-API-011 DELETE /{id}/members/{memberId} 移除项目成员 id(UUID, Path), memberId(UUID, Path) {code, data: null} 项目管理员 成员不存在
PROJ-API-012 GET /{id}/statistics 获取项目统计数据 id(UUID, Path) {code, data: ProjectStatistics} 项目成员 项目不存在
PROJ-API-013 PUT /{id}/status 变更项目状态 id(UUID, Path), Body: ChangeStatusRequest {status: String, reason?: String} {code, data: null} 管理员 项目不存在; 状态流转非法
PROJ-API-014 GET /{id}/config 获取项目配置 id(UUID, Path) {code, data: ProjectConfigDTO} 项目成员 项目不存在
PROJ-API-015 PUT /{id}/config 更新项目配置 id(UUID, Path), Body: ProjectConfigDTO {code, data: ProjectConfigDTO} 项目管理员 项目不存在
PROJ-API-016 GET /{projectId}/delete-check 项目删除前检查 projectId(UUID, Path) {code, data: ProjectDeleteCheckVO} 管理员 项目不存在

关键DTO:

// 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 }

// ProjectSelectorItem
{ id: UUID; code: string; name: string; status: string }

3.2 SpaceNodeController -- /api/mdm/space-nodes

编号 方法 路径 说明 请求参数 响应格式 权限要求 例外情况
SN-API-001 GET / 分页查询空间节点 page(int, 默认0), size(int, 默认10) {code, data: Page<SpaceNode>} 已登录 分页参数越界
SN-API-002 GET /{id} 查询节点详情 id(UUID, Path) {code, data: SpaceNode} 已登录 节点不存在
SN-API-003 GET /project/{projectId} 按项目查询节点列表 projectId(UUID, Path) {code, data: [SpaceNode]} 项目成员 项目不存在
SN-API-004 GET /project/{projectId}/tree 获取项目空间树 projectId(UUID, Path) {code, data: [SpaceNodeTreeDTO]} 项目成员 项目不存在
SN-API-005 GET /project/{projectId}/roots 获取项目根节点 projectId(UUID, Path) {code, data: [SpaceNode]} 项目成员 项目不存在
SN-API-006 GET /project/{projectId}/type/{nodeType} 按项目+类型查询 projectId(UUID, Path), nodeType(NodeType, Path) {code, data: [SpaceNode]} 项目成员 无效NodeType
SN-API-007 GET /parent/{parentId}/children 获取子节点列表 parentId(UUID, Path) {code, data: [SpaceNode]} 已登录 父节点不存在
SN-API-008 POST / 创建空间节点 Body: SpaceNodeCreateDTO {code, data: SpaceNode} 项目管理员 项目不存在; 父节点不存在; 字段校验失败
SN-API-009 POST /batch 批量创建节点 Body: [SpaceNodeCreateDTO] {code, data: [SpaceNode]} 项目管理员 批量数量超限; 父节点不存在
SN-API-010 PUT /{id} 更新节点 id(UUID, Path), Body: SpaceNodeUpdateDTO {code, data: SpaceNode} 项目管理员 节点不存在
SN-API-011 DELETE /{id} 删除节点 id(UUID, Path) {code, data: null} 项目管理员 节点不存在; 有子节点
SN-API-012 GET /{id}/delete-check 删除前检查 id(UUID, Path) {code, data: SpaceNodeDeleteCheckDTO} 项目管理员 节点不存在
SN-API-013 DELETE /{id}/cascade 级联删除(含子节点) id(UUID, Path) {code, data: null} 项目管理员 节点不存在
SN-API-014 GET /{id}/equipment 获取设备详情 id(UUID, Path) {code, data: SpaceNodeEquipmentDTO} 项目成员(@Deprecated) 节点不存在
SN-API-015 GET /equipment 获取设备列表 projectId(UUID, Param) {code, data: [SpaceNodeEquipmentDTO]} 项目成员(@Deprecated) 项目不存在
SN-API-016 GET /special-equipment 获取特种设备列表 projectId(UUID, Param) {code, data: [SpaceNodeEquipmentDTO]} 项目成员(@Deprecated) 项目不存在
SN-API-017 GET /expiring-inspection 获取即将年检设备 projectId(UUID, Param), daysAhead(Integer, 默认90) {code, data: [SpaceNodeEquipmentDTO]} 项目成员(@Deprecated) 项目不存在
SN-API-018 POST /equipment 创建设备 Body: EquipmentCreateDTO {code, data: SpaceNode} 项目管理员(@Deprecated) 项目不存在; 字段校验失败
SN-API-019 POST /equipment/batch 批量创建设备 Body: [EquipmentCreateDTO] {code, data: [SpaceNode]} 项目管理员(@Deprecated) 批量数量超限
SN-API-020 POST /equipment/import Excel导入设备 file(Multipart), projectId(UUID, Param) {code, data: Object} 项目管理员(@Deprecated) 文件为空; 文件类型不支持; 文件超10MB; 行数超1000
SN-API-021 GET /{buildingId}/floor-info 获取楼栋楼层信息 buildingId(String, Path) {code, data: FloorInfoVO} 项目成员 楼栋不存在
SN-API-022 GET /debug/floor-numbers 调试:检查房间楼层号 projectId(UUID, Param) {code, data: Map} 管理员 项目不存在

关键DTO:

// SpaceNodeCreateDTO
{ projectId: UUID; name: String; nodeCategory: NodeCategory; nodeType: NodeType; parentId?: UUID; buildingArea?: BigDecimal; ... }

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

// SpaceNodeDeleteCheckDTO
{ nodeId: UUID; nodeName: String; childCount: Integer; childTypeCount: Map; totalDescendantCount: Integer }

// EquipmentCreateDTO
{ projectId: UUID; name: String; nodeType: NodeType; parentId?: UUID; ...设备扩展字段 }

// FloorInfoVO
{ buildingId: UUID; buildingName: String; totalFloors: Integer; undergroundFloors: Integer; floors: FloorDetailVO[] }

3.3 InspectionItemController -- /api/mdm/inspection-items

编号 方法 路径 说明 请求参数 响应格式 权限要求 例外情况
II-API-001 POST / 创建巡检标准项 Body: InspectionItem {code, data: InspectionItem} 管理员 字段校验失败
II-API-002 GET / 查询巡检标准项列表 equipmentType?(String), systemType?(String), activeOnly?(Boolean) {code, data: [InspectionItem]} 已登录
II-API-003 GET /{id} 获取标准项详情 id(UUID, Path) {code, data: InspectionItem} 已登录 标准项不存在
II-API-004 PUT /{id} 更新标准项 id(UUID, Path), Body: InspectionItem {code, data: InspectionItem} 管理员 标准项不存在
II-API-005 DELETE /{id} 删除标准项 id(UUID, Path) {code, data: null} 管理员 标准项不存在; 已被模板引用

查询逻辑优先级:

  1. activeOnly=true → 仅返回ACTIVE状态项
  2. equipmentType + systemType → 双条件过滤
  3. equipmentType → 单条件过滤
  4. systemType → 系统类型过滤
  5. 无参数 → 返回全部

3.4 InspectionTemplateController -- /api/ops/inspection-templates

编号 方法 路径 说明 请求参数 响应格式 权限要求 例外情况
IT-API-001 GET / 获取项目模板列表 projectId(UUID, Param) {code, data: [InspectionTemplate]} 项目成员 项目不存在
IT-API-002 POST / 创建模板 Body: InspectionTemplate {code, data: InspectionTemplate} 管理员 模板编码已存在
IT-API-003 GET /{id} 获取模板详情 id(UUID, Path) {code, data: InspectionTemplate} 已登录 模板不存在
IT-API-004 PUT /{id} 更新模板 id(UUID, Path), Body: InspectionTemplate {code, data: InspectionTemplate} 管理员 模板不存在
IT-API-005 POST /{id}/copy 复制模板 id(UUID, Path), newName(String, Param) {code, data: InspectionTemplate} 管理员 模板不存在
IT-API-006 GET /by-type/{equipmentType} 按设备类型查模板 equipmentType(String, Path) {code, data: [InspectionTemplate]} 已登录

3.5 InspectionRecordController -- /api/mdm/inspection-records

编号 方法 路径 说明 请求参数 响应格式 权限要求 例外情况
IR-API-001 POST / 创建巡检记录 Body: InspectionRecord {code, data: InspectionRecord} 项目成员 设备不存在; 字段校验失败
IR-API-002 GET / 查询巡检记录列表 equipmentId?(UUID), planId?(UUID), inspector?(String), status?(CheckStatus), startDate?(LocalDate), endDate?(LocalDate) {code, data: [InspectionRecord]} 项目成员
IR-API-003 GET /{id} 获取记录详情 id(UUID, Path) {code, data: InspectionRecord} 已登录 记录不存在
IR-API-004 PUT /{id} 更新记录 id(UUID, Path), Body: InspectionRecord {code, data: InspectionRecord} 项目成员 记录不存在
IR-API-005 DELETE /{id} 删除记录 id(UUID, Path) {code, data: null} 管理员 记录不存在
IR-API-006 POST /{id}/complete 完成巡检记录 id(UUID, Path) {code, data: null} 项目成员 记录不存在; 已完成

查询逻辑优先级:

  1. equipmentId + 日期范围 → 设备+日期
  2. equipmentId → 设备
  3. planId → 计划
  4. inspector → 巡检人
  5. status → 状态
  6. 日期范围 → 时间段
  7. 无参数 → 全部

3.6 SparePartController -- /api/ops/spare-parts

编号 方法 路径 说明 请求参数 响应格式 权限要求 例外情况
SP-API-001 GET /categories 获取分类列表 {code, data: [SparePartCategory]} 已登录
SP-API-002 POST /categories 创建分类 Body: SparePartCategory {code, data: SparePartCategory} 管理员 分类编码已存在
SP-API-003 GET / 获取备件列表 projectId(UUID, Param), categoryId?(UUID) {code, data: [SparePart]} 项目成员 项目不存在
SP-API-004 GET /{id} 获取备件详情 id(UUID, Path) {code, data: SparePart} 已登录 备件不存在
SP-API-005 POST / 创建备件 Body: SparePart {code, data: SparePart} 管理员 备件编码已存在
SP-API-006 PUT /{id} 更新备件 id(UUID, Path), Body: SparePart {code, data: SparePart} 管理员 备件不存在
SP-API-007 DELETE /{id} 删除备件 id(UUID, Path) {code, data: null} 管理员 备件不存在; 有出入库记录
SP-API-008 GET /low-stock 获取低库存备件 projectId(UUID, Param) {code, data: [SparePart]} 项目成员 项目不存在
SP-API-009 POST /in-stock 入库操作 Body: StockRequest {sparePartId, quantity, recordedBy?, remarks?} {code, data: null} 项目成员 备件不存在; 数量<=0
SP-API-010 POST /out-stock 出库操作 Body: OutStockRequest {sparePartId, quantity, relatedOrderId?, recordedBy?, remarks?} {code, data: null} 项目成员 备件不存在; 库存不足; 数量<=0
SP-API-011 GET /{id}/records 获取备件出入库记录 id(UUID, Path) {code, data: [SparePartRecord]} 已登录 备件不存在

3.7 EnergyController -- /api/ops/energy

编号 方法 路径 说明 请求参数 响应格式 权限要求 例外情况
EN-API-001 POST /meters 创建计量点 Body: EnergyMeter {code, data: EnergyMeter} 管理员 计量点编码已存在
EN-API-002 GET /meters 获取计量点列表 projectId(UUID, Param), energyType?(String) {code, data: [EnergyMeter]} 项目成员 项目不存在
EN-API-003 GET /meters/{id} 获取计量点详情 id(UUID, Path) {code, data: EnergyMeter} 已登录 计量点不存在
EN-API-004 PUT /meters/{id} 更新计量点 id(UUID, Path), Body: EnergyMeter {code, data: EnergyMeter} 管理员 计量点不存在
EN-API-005 DELETE /meters/{id} 删除计量点 id(UUID, Path) {code, data: null} 管理员 计量点不存在; 有能耗记录
EN-API-006 POST /consumption 录入能耗记录 Body: RecordConsumptionRequest {meterId, currentReading, recordedBy?} {code, data: null} 项目成员 计量点不存在; 读数小于上次
EN-API-007 GET /consumption/{meterId} 获取能耗记录 meterId(UUID, Path), startDate?(LocalDate), endDate?(LocalDate) {code, data: [EnergyConsumption]} 项目成员 计量点不存在
EN-API-008 GET /statistics/by-type 按类型统计能耗 projectId(UUID, Param), month(String, Param) {code, data: Map<EnergyType, BigDecimal>} 项目成员 项目不存在
EN-API-009 GET /statistics/unit-consumption 单位面积能耗 projectId(UUID, Param), month(String, Param) {code, data: BigDecimal} 项目成员 项目不存在

四、业务规则

4.1 空间节点树形管理创建时自动生成treePath/删除前检查/级联删除)

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,用于快速查询所有子孙节点

    • 创建节点时: 父节点.treePath + "." + 当前节点.id根节点为自身id
    • 支持通过 LIKE 'parentId.%' 快速查询所有子孙
  • treePathName: 名称路径,格式 项目/楼栋/单元/房间,用于展示

    • 创建节点时: 父节点.treePathName + "/" + 当前节点.name
  • level: 层级深度根节点为0每层+1

    • 创建节点时: 父节点.level + 1
  • sortOrder: 同级排序默认0

4.1.3 删除规则

  1. 删除前检查: 调用 GET /{id}/delete-check 获取子节点信息

    • 返回: {nodeId, nodeName, childCount, childTypeCount, totalDescendantCount}
  2. 普通删除: DELETE /{id}

    • 有子节点时拒绝删除
    • 软删除: 设置 isDeleted=true
  3. 级联删除: DELETE /{id}/cascade

    • 删除当前节点及所有子孙节点
    • 软删除: 所有节点设置 isDeleted=true

4.1.4 批量操作

  • 批量创建: POST /batch,受 BatchOperationValidator.validateUpdateSize() 限制数量
  • Excel导入设备: POST /equipment/import
    • 支持格式: .xlsx, .xls
    • 文件大小限制: 10MB
    • 行数限制: 1000行
    • 文件类型校验: contentType + 扩展名双重校验

4.2 项目状态流转ACTIVE/DISABLED/PENDING/ARCHIVED的转换规则

4.2.1 状态值与转换规则

当前状态 可流转到 说明
PENDING ACTIVE 审核通过
PENDING DISABLED 审核拒绝
ACTIVE DISABLED 禁用项目
ACTIVE ARCHIVED 归档项目
DISABLED ACTIVE 重新启用
DISABLED ARCHIVED 归档禁用项目
ARCHIVED - 终态,不可再变更

4.2.2 状态变更规则

  • 每次状态变更必须记录 ProjectStatusHistoryfromStatus, toStatus, reason, operatorId, operatorName
  • 变更接口: PUT /{id}/status,请求体: {status, reason}
  • 非法状态转换抛出 BusinessException

4.2.3 项目成员角色

角色 说明
PROJECT_MANAGER 项目经理
PROJECT_ADMIN 项目管理员
OPERATION_STAFF 运营人员
FINANCE_STAFF 财务人员
VIEWER 查看者

4.3 空间编码自动生成BLD-{projSuffix}-{seq}格式)

当前状态: SpaceNode实体有 code 字段VARCHAR(50), @JsonIgnore但自动编码规则尚未完整实现。

设计规则(参考原需求 02-SPACE_NODE_DESIGN.md:

NodeType 编码格式 示例
BUILDING BLD-{projSuffix}-{seq} BLD-XY-001
UNIT BLD-{projSuffix}-{bldSeq}-{seq} BLD-XY-001-01
FLOOR BLD-{projSuffix}-{bldSeq}-F{floorNo} BLD-XY-001-F3
ROOM BLD-{projSuffix}-{bldSeq}-{unitSeq}-{seq} BLD-XY-001-01-0301
GARAGE GRG-{projSuffix}-{seq} GRG-XY-001
PARKING_SPACE GRG-{projSuffix}-{grgSeq}-{seq} GRG-XY-001-A001
EQUIPMENT_ROOM EQP-{projSuffix}-{seq} EQP-XY-001

唯一性约束: 同项目同类型下编码唯一(原设计 UNIQUE(project_id, code),当前代码未实现此约束)


4.4 巡检标准项管理(按设备类型/系统类型分类)

4.4.1 标准项库

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

4.4.2 巡检模板

  • 模板按项目+设备类型组织
  • 模板包含检查项列表JSON格式存储字段 inspectionItems
  • 支持模板版本管理(version 字段)
  • 支持模板复制(POST /{id}/copy
  • 模板与标准项通过 equipmentType 逻辑关联

4.4.3 巡检记录

  • 记录关联设备(equipmentId)和计划(planId
  • 检查结果状态: NORMAL(正常) / WARNING(预警) / ABNORMAL(异常)
  • 支持签到信息: 时间(checkInTime)、位置(checkInLocation)、照片(checkInPhoto
  • 检查项结果和异常问题以JSONB存储
  • 完成操作: 调用 POST /{id}/complete 标记完成

4.5 巡检记录管理(签到/问题上报/完成确认)

4.5.1 创建巡检记录流程

  1. 选择设备(equipmentId
  2. 填写巡检日期(inspectionDate)和巡检人(inspector
  3. 逐项填写检查结果(items JSONB
  4. 上报异常问题(problems JSONB
  5. 签到: 记录时间、位置、照片

4.5.2 完成确认

  • 调用 POST /{id}/complete
  • 设置 completed=true, completedTime=当前时间
  • 已完成的记录不可再修改

4.5.3 状态判定

  • NORMAL: 所有检查项通过,无异常问题
  • WARNING: 存在轻微异常
  • ABNORMAL: 存在严重异常

五、执行约束

5.1 项目编码唯一性

  • 数据库约束: mdm_project.code 列 UNIQUE
  • 校验规则: 正则 ^[a-zA-Z0-9_-]+$长度2-50位
  • 违反后果: 创建/更新项目时抛出 DataIntegrityViolationException
  • 自动生成: GET /generate-code 接口生成唯一编码

5.2 空间节点树完整性(不能形成环/父节点必须存在)

  • 约束说明: 空间节点通过 parentId 自引用形成树形结构
  • 父节点校验: 创建/更新节点时parentId 指向的节点必须存在且属于同一项目
  • 环路检测: 更新 parentId 时,沿 parentId 链向上遍历,检查是否会回到当前节点
  • 违反后果: 抛出 BusinessException提示"不能将节点设置为其子节点的下级"
  • 项目一致性: 子节点的 projectId 必须与父节点一致

5.3 项目删除前检查(有空间节点/设备/工单时不能删除)

  • 检查接口: GET /{projectId}/delete-check
  • 返回结果: ProjectDeleteCheckVO { canDelete, reason, statistics }
  • 阻止删除条件:
    • 存在空间节点SpaceNode
    • 存在设备isEquipment=true的SpaceNode
    • 存在应收未收费用
    • 存在关联工单
  • 违反后果: canDelete=false返回具体原因

5.4 空间编码唯一性(同项目同类型下唯一)

  • 约束说明: 同一项目下,相同 NodeType 的节点 code 应唯一
  • 当前状态: 数据库层面未建立 UNIQUE(project_id, code) 约束
  • 业务层校验: 创建/更新节点时检查同项目同类型下编码是否重复
  • 违反后果: 抛出 BusinessException

5.5 备件出库库存约束

  • 约束说明: 出库数量不能超过当前库存
  • 校验方式: currentStock - quantity >= 0
  • 违反后果: 抛出 BusinessException提示"库存不足"

5.6 能耗读数递增约束

  • 约束说明: 本次读数必须大于上次读数
  • 校验方式: currentReading > previousReading
  • 违反后果: 抛出 BusinessException提示"本次读数不能小于上次读数"

六、权限控制

6.1 API端点权限矩阵

控制器 端点 所需角色 数据范围过滤
ProjectController GET / 已登录用户 ALL/PROJECT(按用户项目过滤)
ProjectController GET /selector 已登录用户 PROJECT(仅用户参与的项目)
ProjectController GET /generate-code 管理员
ProjectController GET /{id} 项目成员 PROJECT
ProjectController GET /code/{code} 项目成员 PROJECT
ProjectController POST / 管理员(SYSTEM级)
ProjectController PUT /{id} 项目管理员 PROJECT
ProjectController DELETE /{id} 管理员(SYSTEM级)
ProjectController GET /{id}/members 项目成员 PROJECT
ProjectController POST /{id}/members 项目管理员 PROJECT
ProjectController DELETE /{id}/members/{memberId} 项目管理员 PROJECT
ProjectController GET /{id}/statistics 项目成员 PROJECT
ProjectController PUT /{id}/status 管理员(SYSTEM级)
ProjectController GET /{id}/config 项目成员 PROJECT
ProjectController PUT /{id}/config 项目管理员 PROJECT
ProjectController GET /{projectId}/delete-check 管理员(SYSTEM级)
SpaceNodeController GET / 已登录用户 ALL/PROJECT
SpaceNodeController GET /{id} 已登录用户 PROJECT
SpaceNodeController GET /project/{projectId}/* 项目成员 PROJECT
SpaceNodeController POST / 项目管理员 PROJECT
SpaceNodeController POST /batch 项目管理员 PROJECT
SpaceNodeController PUT /{id} 项目管理员 PROJECT
SpaceNodeController DELETE /{id} 项目管理员 PROJECT
SpaceNodeController DELETE /{id}/cascade 项目管理员 PROJECT
SpaceNodeController POST /equipment* 项目管理员(@Deprecated) PROJECT
SpaceNodeController GET /{buildingId}/floor-info 项目成员 PROJECT
InspectionItemController GET / 已登录用户 ALL
InspectionItemController GET /{id} 已登录用户 ALL
InspectionItemController POST / 管理员
InspectionItemController PUT /{id} 管理员
InspectionItemController DELETE /{id} 管理员
InspectionTemplateController GET / 项目成员 PROJECT
InspectionTemplateController POST / 管理员
InspectionTemplateController GET /{id} 已登录用户 PROJECT
InspectionTemplateController PUT /{id} 管理员
InspectionTemplateController POST /{id}/copy 管理员
InspectionRecordController POST / 项目成员 PROJECT
InspectionRecordController GET / 项目成员 PROJECT
InspectionRecordController GET /{id} 已登录用户 PROJECT
InspectionRecordController PUT /{id} 项目成员 PROJECT
InspectionRecordController DELETE /{id} 管理员
InspectionRecordController POST /{id}/complete 项目成员 PROJECT
SparePartController GET /categories 已登录用户 ALL
SparePartController POST /categories 管理员
SparePartController GET / 项目成员 PROJECT
SparePartController GET /{id} 已登录用户 ALL
SparePartController POST / 管理员 PROJECT
SparePartController PUT /{id} 管理员 PROJECT
SparePartController DELETE /{id} 管理员 PROJECT
SparePartController GET /low-stock 项目成员 PROJECT
SparePartController POST /in-stock 项目成员 PROJECT
SparePartController POST /out-stock 项目成员 PROJECT
SparePartController GET /{id}/records 已登录用户 ALL
EnergyController POST /meters 管理员 PROJECT
EnergyController GET /meters 项目成员 PROJECT
EnergyController GET /meters/{id} 已登录用户 ALL
EnergyController PUT /meters/{id} 管理员 PROJECT
EnergyController DELETE /meters/{id} 管理员 PROJECT
EnergyController POST /consumption 项目成员 PROJECT
EnergyController GET /consumption/{meterId} 项目成员 PROJECT
EnergyController GET /statistics/* 项目成员 PROJECT

七、例外情况处理

7.1 项目相关例外

例外场景 错误码 错误信息 处理方式
项目不存在 404 "项目不存在" findById返回空时抛出
项目编码已存在 409 "项目编码{code}已存在" 创建/更新前查询
项目编码格式错误 400 "项目代码只能包含字母、数字、连字符和下划线" 正则校验
项目名称为空 400 "项目名称不能为空" @NotNull校验
联系电话格式错误 400 "联系电话格式不正确" 正则校验
非法状态转换 400 "不允许从{from}变更为{to}" 状态机校验
删除项目有空间节点 400 "项目下存在空间节点,无法删除" delete-check检查
删除项目有应收费用 400 "项目存在应收未收费用,无法删除" delete-check检查
项目已归档不可变更 400 "已归档项目不可操作" ARCHIVED终态检查

7.2 空间节点相关例外

例外场景 错误码 错误信息 处理方式
节点不存在 404 "空间节点不存在" findById返回空时抛出
父节点不存在 400 "父节点不存在" 创建/更新时校验parentId
父节点不属于同一项目 400 "父节点不属于当前项目" projectId一致性校验
有子节点不能普通删除 400 "该节点存在{count}个子节点,请使用级联删除" delete-check检查
树形结构形成环 400 "不能将节点设置为其子节点的下级" parentId链遍历检查
节点名称为空 400 "空间节点名称不能为空" @NotNull校验
nodeType与nodeCategory不匹配 400 "节点类型与节点大类不匹配" 枚举关联校验
批量创建数量超限 400 "批量操作数量超过限制" BatchOperationValidator校验

7.3 设备相关例外(@Deprecated

例外场景 错误码 错误信息 处理方式
设备不存在 404 "设备不存在" findById返回空时抛出
Excel文件为空 400 "文件不能为空" file.isEmpty()检查
Excel文件类型不支持 400 "不支持的文件类型,仅支持 Excel 文件(.xlsx, .xls" contentType+扩展名校验
Excel文件过大 400 "文件大小不能超过 10MB" file.getSize()检查
Excel行数超限 400 "Excel 行数不能超过 1000 行,当前 {n} 行" POI解析行数检查
Excel解析失败 400 "文件解析失败: {message}" IOException捕获

7.4 巡检相关例外

例外场景 错误码 错误信息 处理方式
巡检标准项不存在 404 "巡检标准项不存在" findById返回空时抛出
标准项已被模板引用 400 "该标准项已被巡检模板引用,无法删除" 检查模板引用
巡检记录不存在 404 "巡检记录不存在" findById返回空时抛出
巡检记录已完成 400 "巡检记录已完成,不可修改" completed=true检查
设备ID不存在 400 "设备不存在" equipmentId校验
巡检模板编码已存在 409 "模板编码{code}已存在" 创建前查询
巡检模板不存在 404 "巡检模板不存在" findById返回空时抛出

7.5 备件相关例外

例外场景 错误码 错误信息 处理方式
备件不存在 404 "备件不存在" findById返回空时抛出
备件编码已存在 409 "备件编码{code}已存在" 创建前查询
出库数量超过库存 400 "库存不足,当前库存{stock},出库数量{qty}" currentStock校验
出入库数量为0或负数 400 "数量必须大于0" quantity > 0校验
分类编码已存在 409 "分类编码{code}已存在" 创建前查询
备件有出入库记录不能删除 400 "该备件存在出入库记录,无法删除" 检查SparePartRecord

7.6 能耗相关例外

例外场景 错误码 错误信息 处理方式
计量点不存在 404 "计量点不存在" findById返回空时抛出
计量点编码已存在 409 "计量点编码{code}已存在" 创建前查询
本次读数小于上次读数 400 "本次读数不能小于上次读数" currentReading > previousReading
计量点有能耗记录不能删除 400 "该计量点存在能耗记录,无法删除" 检查EnergyConsumption
项目无建筑面积 400 "项目无建筑面积数据,无法计算单位面积能耗" 统计时校验

7.7 通用例外

例外场景 错误码 错误信息 处理方式
分页参数越界 200(自动修正) 无(使用getSafeSize修正) PaginationValidator校验
项目ID为空 400 "项目ID不能为空" @NotNull校验
无权限访问项目数据 403 "无权访问该项目数据" DataScopeService校验