ether-docs/02-DESIGN/overview/OVERVIEW-DESIGN.md

52 KiB
Raw Permalink Blame History

Ether 物业管理系统 - 概要设计文档

文档版本: v1.0 编制日期: 2026-05-18 数据来源: REVERSE-AUTH/MDM/ASSET/OPS/FINANCE 反推设计文档 + BEST-PRACTICES-REPORT + CONSISTENCY-REPORT 系统版本: ether-pms v1.x (Spring Boot 3.x)


一、系统架构设计

1.1 总体架构

Ether 物业管理系统采用单体模块化架构,后端为 Spring Boot 3.x 单体应用,通过 Maven 多模块组织业务边界;前端为 Vue3 SPA 应用,按角色拆分为三套独立前端。

技术栈总览

层次 技术选型 说明
后端框架 Spring Boot 3.x + Spring Security 6 Java 17+Servlet 容器
持久层 Spring Data JPA + Hibernate ORM 框架,自动建表
数据库 PostgreSQL 15+ JSONB/UUID/ltree 扩展
缓存 Redis 登录锁定、Session、热数据
认证 JWT (HMAC-SHA256) 无状态 Token 认证
前端框架 Vue3 + TypeScript + Vite Composition API + <script setup>
UI 组件库 Ant Design Vue 4.x 统一视觉风格
状态管理 Pinia Composition API 风格
HTTP 客户端 Axios 请求/响应拦截器封装
构建工具 Maven (后端) / npm (前端) 多模块构建

架构图

┌──────────────────────────────────────────────────────────────────────┐
│                          客户端层                                    │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐              │
│  │ ether-admin  │  │ether-app-    │  │ether-app-    │              │
│  │  (管理后台)   │  │ employee     │  │ owner        │              │
│  │  :5175       │  │ (员工H5)     │  │ (业主H5)     │              │
│  │  Vue3+AntD   │  │ :5174        │  │ :5176        │              │
│  └──────┬───────┘  └──────┬───────┘  └──────┬───────┘              │
│         │                 │                 │                       │
│         └─────────────────┼─────────────────┘                       │
│                           │ RESTful API (JSON)                      │
│                           │ Authorization: Bearer {JWT}            │
│                           │ X-Project-ID: {projectId}              │
└───────────────────────────┼──────────────────────────────────────────┘
                            │
┌───────────────────────────┼──────────────────────────────────────────┐
│                     后端服务层 (ether-pms :8080)                      │
│                           │                                          │
│  ┌────────────────────────┼────────────────────────────────────┐    │
│  │              Spring Security Filter Chain                    │    │
│  │  JwtAuthenticationFilter → LoginAttemptFilter → ...         │    │
│  └────────────────────────┼────────────────────────────────────┘    │
│                           │                                          │
│  ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐          │
│  │module- │ │module- │ │module- │ │module- │ │module- │          │
│  │common  │ │auth    │ │mdm     │ │asset   │ │wo      │          │
│  │        │ │        │ │        │ │        │ │        │          │
│  │公共工具│ │认证授权│ │主数据  │ │设备资产│ │运维工单│          │
│  │异常/响应│ │用户/角色│ │项目/空间│ │设备/健康│ │工单/维保│          │
│  └────────┘ └────────┘ └────────┘ └────────┘ └────────┘          │
│                           │                                          │
│  ┌────────────────────────┼────────────────────────────────────┐    │
│  │              JPA / Hibernate / Repository                    │    │
│  └────────────────────────┼────────────────────────────────────┘    │
│                           │                                          │
└───────────────────────────┼──────────────────────────────────────────┘
                            │
┌───────────────────────────┼──────────────────────────────────────────┐
│                        数据层                                        │
│  ┌──────────────┐  ┌──────────────┐                                │
│  │ PostgreSQL   │  │   Redis      │                                │
│  │ 15+          │  │              │                                │
│  │ JSONB/UUID   │  │ 登录锁定     │                                │
│  │ B-tree/GIN   │  │ Token缓存    │                                │
│  └──────────────┘  └──────────────┘                                │
└──────────────────────────────────────────────────────────────────────┘

1.2 模块划分

模块 职责 核心实体 API 前缀
module-common 公共工具、异常体系、统一响应、基础配置 ErrorCode、ApiResponse
module-auth 身份认证、用户管理、RBAC 权限、审计日志 User、Role、Permission、Dept、AuditLog /api/auth
module-mdm 项目管理、空间节点、巡检标准、备件库存、能耗计量 Project、SpaceNode、InspectionItem、SparePart、EnergyMeter /api/mdm/api/ops
module-asset 设备台账、健康评分、故障历史、归属主体 Equipment、EquipmentElevator/Hvac/Fire/Energy、EquipmentHealthScore /api/asset
module-wo 工单管理、维保计划、维保任务、巡检模板 WorkOrder、MaintenancePlan、MaintenanceTask、InspectionTemplate /api/wo/api/ops
module-finance 收费项目、账单管理、支付记录(待实现 FeeItem、FeeBill、FeePayment未实现 /api/finance(待定)

模块依赖关系

module-common ← module-auth ← module-mdm ← module-asset
                    ↑              ↑            ↑
                    └──────────────┴────────────┘
                              module-wo
  • module-common 是所有模块的基础依赖
  • module-auth 提供用户/权限基础数据,被其他业务模块引用
  • module-mdm 提供项目/空间基础数据,被 asset/wo 模块引用
  • module-asset 和 module-wo 存在交叉引用(设备-工单关联)

1.3 前后端交互架构

认证流程

1. 客户端 POST /api/auth/login {username, password}
2. 后端验证 → 生成 JWT Token含 userId/username/roles
3. 客户端存储 Token → 后续请求 Header: Authorization: Bearer {token}
4. 后端 JwtAuthenticationFilter 拦截 → 验证签名和过期 → 设置 SecurityContext

项目隔离机制

1. 登录后获取用户项目列表 GET /api/auth/users/{id}/projects
2. 用户选择项目 → 后续请求携带 X-Project-ID Header
3. 后端 ProjectContextInterceptor 拦截 → 设置 ThreadLocal
4. 业务层 DataScopeService 过滤数据 → 按 projectId 限定数据范围

统一响应格式

{
  "code": 0,
  "message": "success",
  "data": { ... }
}

错误响应格式

{
  "code": 1001,
  "message": "用户名或密码错误",
  "data": null
}

错误码分段规则

段号 模块 示例
1xxx 认证 1001 用户名或密码错误
2xxx 用户 2001 用户不存在
3xxx 角色 3001 角色代码已存在
4xxx 权限 4001 权限代码已存在
5xxx 项目 5001 项目编码已存在
6xxx 空间/能耗 6101 仪表不存在
7xxx 文件 7001 文件格式不支持

1.4 部署架构

组件 端口 部署方式 说明
ether-pms 8080 JAR 包部署 后端单体服务
ether-admin 5175 Nginx 静态托管 管理后台前端
ether-app-employee 5174 Nginx 静态托管 员工 H5 前端
ether-app-owner 5176 Nginx 静态托管 业主 H5 前端
ether-app-commercial 5177 Nginx 静态托管 商办 H5 前端
PostgreSQL 5432 独立部署 主数据库
Redis 6379 独立部署 缓存/登录锁定

启动脚本:项目根目录提供 start-services.sh / stop-services.sh 统一管理服务启停。


二、业务域划分与边界

2.1 六大业务域定义

域编号 域名称 核心职责 对应模块 核心实体数
D1 身份与权限域 用户认证、RBAC 权限、项目隔离、审计日志 module-auth 14
D2 空间与项目域 项目管理、空间节点树、项目配置、项目统计 module-mdm 13
D3 设备与资产域 设备台账、专业扩展、健康评分、故障历史、归属管理 module-asset 8
D4 运营与服务域 工单管理、维保计划/任务、巡检模板、备件库存 module-wo + module-mdm(部分) 6
D5 财务与收费域 收费项目、账单管理、支付记录、能耗计费 module-finance(待实现) 0(待实现)
D6 前端交互域 管理后台、员工端、业主端、商办端 ether-admin + ether-app-*

2.2 域间依赖关系图

graph TD
    D1[D1 身份与权限域<br/>module-auth]
    D2[D2 空间与项目域<br/>module-mdm]
    D3[D3 设备与资产域<br/>module-asset]
    D4[D4 运营与服务域<br/>module-wo]
    D5[D5 财务与收费域<br/>module-finance]
    D6[D6 前端交互域<br/>ether-admin/apps]

    D1 -->|用户/角色/权限| D2
    D1 -->|用户/角色/权限| D3
    D1 -->|用户/角色/权限| D4
    D1 -->|用户/角色/权限| D5

    D2 -->|项目/空间节点| D3
    D2 -->|项目/空间节点| D4
    D2 -->|项目/空间节点| D5

    D3 -->|设备信息| D4
    D3 -->|设备健康数据| D5

    D4 -->|工单费用| D5

    D1 -.->|API调用| D6
    D2 -.->|API调用| D6
    D3 -.->|API调用| D6
    D4 -.->|API调用| D6
    D5 -.->|API调用| D6

依赖说明

依赖关系 依赖内容 实现方式
D2 → D1 项目成员管理需要用户数据 UserProject 关联 + ProjectStaff 扩展
D3 → D2 设备关联空间节点 Equipment.spaceNodeId → SpaceNode.id
D4 → D2 工单关联项目和空间 WorkOrder.projectId / spaceId
D4 → D3 工单关联设备 WorkOrder.equipmentId → Equipment.id
D4 → D3 维保任务完成后更新设备 MaintenanceTask → Equipment 联动更新
D5 → D2 账单关联项目和空间 FeeBill.projectId / spaceNodeId
D5 → D3 能耗费用对接设备 EnergyConsumption → Equipment

2.3 域间数据流图

flowchart LR
    subgraph D1[身份与权限域]
        User[User]
        Role[Role]
    end

    subgraph D2[空间与项目域]
        Project[Project]
        SpaceNode[SpaceNode]
        EnergyMeter[EnergyMeter]
    end

    subgraph D3[设备与资产域]
        Equipment[Equipment]
        HealthScore[HealthScore]
        FailureHistory[FailureHistory]
    end

    subgraph D4[运营与服务域]
        WorkOrder[WorkOrder]
        MaintenancePlan[MaintenancePlan]
        MaintenanceTask[MaintenanceTask]
        SparePart[SparePart]
    end

    subgraph D5[财务与收费域]
        FeeItem[FeeItem]
        FeeBill[FeeBill]
        FeePayment[FeePayment]
    end

    User -->|项目成员| Project
    Project -->|1:N| SpaceNode
    SpaceNode -->|spaceNodeId| Equipment
    Equipment -->|equipmentId| WorkOrder
    Equipment -->|equipmentId| MaintenanceTask
    MaintenancePlan -->|planId| MaintenanceTask
    MaintenanceTask -->|完成后联动| Equipment
    WorkOrder -->|relatedOrderId| SparePart
    EnergyMeter -->|费用计算| FeeBill
    Equipment -->|健康数据| HealthScore
    Equipment -->|故障记录| FailureHistory
    FailureHistory -->|关联工单| WorkOrder

2.4 域间接口契约

接口 提供方 消费方 契约内容
用户项目列表 D1 (auth) D2 (mdm) GET /api/auth/users/{id}/projectsList<UserProject>
项目成员管理 D2 (mdm) D1 (auth) GET/POST/DELETE /api/mdm/projects/{id}/members
空间节点查询 D2 (mdm) D3 (asset) Equipment.spaceNodeId → SpaceNode.id通过 JPA 关联
设备查询 D3 (asset) D4 (wo) WorkOrder.equipmentId → Equipment.id通过 JPA 关联
维保完成后设备更新 D4 (wo) D3 (asset) MaintenanceTask 完成时更新 Equipment.maintenanceVendor/nextInspectionDate
备件出库关联工单 D4 (wo) D2 (mdm) SparePartRecord.relatedOrderId → WorkOrder.id
能耗数据对接账单 D2 (mdm) D5 (finance) EnergyConsumption.amount → FeeBill 数据来源(待实现)

三、核心技术实现路径

3.1 多租户数据隔离

隔离策略:共享数据库 + projectId 字段隔离

实现机制

层次 机制 实现细节
数据层 projectId 字段 所有业务表均含 project_id 列,索引覆盖
请求层 X-Project-ID Header 前端每次请求携带当前项目 ID
拦截层 ProjectContextInterceptor 拦截请求,将 projectId 存入 ThreadLocal
服务层 DataScopeService 提供 canAccessAllData()、getPermittedProjectIds() 等判断方法
查询层 Repository 方法 findByProjectIdAndXxx() 系列方法,强制带项目条件

数据范围过滤

// 四级数据范围
ALL          不做数据过滤可查看所有项目数据
PROJECT      过滤 project_id = 当前项目
DEPARTMENT   过滤 project_id + dept_id = 用户部门
SELF         过滤 assigned_to / creator = 当前用户

已知不足与改进方向

  • 当前 DataScopeService 仅提供判断方法,未实现 SQL 自动注入,数据过滤依赖业务层手动调用,存在遗漏风险
  • 改进方案:通过 JPA Specification 或 MyBatis Interceptor 自动拼接数据过滤条件

3.2 RBAC 权限模型

模型结构User ←M2M→ Role ←M2M→ Permission

三级角色体系

角色类型 枚举值 说明 数据范围
系统级 SYSTEM 跨项目全局角色 ALL
项目级 PROJECT 绑定特定项目的角色 PROJECT
部门级 DEPARTMENT 部门范围角色 DEPARTMENT

双层角色分配

用户所有角色 = 用户直接角色(auth_user_role)  项目员工角色(ProjectStaffRole)
  • 用户直接角色:通过 auth_user_role 中间表关联,用户创建时或 UserController.assignRoles 分配
  • 项目员工角色:通过 ProjectStaffRole 关联,项目成员管理时分配

权限类型

类型 说明 示例
MENU 菜单权限 系统管理、设备管理
BUTTON 按钮权限 新增设备、删除工单
API 接口权限 POST /api/asset/equipment

权限代码格式module:resource:action,如 asset:equipment:create

四级数据范围

数据范围 编码 过滤逻辑
全部数据 ALL 不做数据过滤
本项目数据 PROJECT WHERE project_id = ?
本部门数据 DEPARTMENT WHERE project_id = ? AND dept_id = ?
仅本人数据 SELF WHERE assigned_to = ? OR created_by = ?

3.3 树形结构管理

适用实体SpaceNode空间节点、Dept部门、SparePartCategory备件分类

实现方案treePath 字符串路径 + parentId 自引用

核心字段

字段 类型 说明
parentId UUID 父节点 IDNULL=顶级)
treePath String(1000) 物理路径,格式 id1.id2.id3
treePathName String(1000) 名称路径,格式 项目/楼栋/单元/房间
level Integer 层级深度,根节点为 0

SpaceNode 空间层级

项目 (Project)
├── 楼栋 (BUILDING)       ← NodeCategory.BUILDING, level=1
│   ├── 单元 (UNIT)       ← NodeCategory.BUILDING, level=2
│   │   ├── 楼层 (FLOOR)  ← NodeCategory.BUILDING, level=3
│   │   │   └── 房间 (ROOM) ← NodeCategory.BUILDING, level=4
│   │   └── 房间 (ROOM)   ← 可跳过楼层直接挂房间
│   └── 公共用房 (PUBLIC_ROOM)
├── 商铺 (SHOP)           ← NodeCategory.BUILDING, level=2
├── 车库 (GARAGE)         ← NodeCategory.PARKING, level=1
│   ├── 停车区域 (PARKING_AREA) ← level=2
│   │   └── 车位 (PARKING_SPACE) ← level=3
├── 设备房 (EQUIPMENT_ROOM) ← NodeCategory.FACILITY, level=1
├── 公共区域 (PUBLIC_AREA) ← NodeCategory.AREA, level=1
└── 绿化区域 (GREEN_AREA) ← NodeCategory.AREA, level=1

查询模式

查询需求 实现方式 SQL 示例
查子节点 parentId 查询 WHERE parent_id = ?
查所有子孙 treePath LIKE WHERE tree_path LIKE 'parentPath.%'
查祖先链 treePath 解析 应用层拆分 treePath 获取祖先 ID 列表
构建完整树 扁平列表 + 递归 Controller 层递归构建树形 VO

索引设计

idx_space_node_tree_path (tree_path)        -- 路径前缀查询
idx_sn_project_parent (project_id, parent_id) -- 项目+父节点
idx_sn_project_type (project_id, node_type)   -- 项目+类型

已知不足treePath LIKE 查询在大数据量下性能不佳,未使用 PostgreSQL ltree 扩展或闭包表方案。后续可评估升级。

3.4 设备扩展表模式

设计原则:主表存储公共字段,扩展表存储专业参数,通过 equipmentType 决定扩展表。

模式结构

Equipment (主表, ~40个公共字段)
├── EquipmentElevator (电梯扩展) ← equipment_id UNIQUE
├── EquipmentHvac (暖通扩展)     ← equipment_id UNIQUE
├── EquipmentFire (消防扩展)     ← equipment_id UNIQUE
└── EquipmentEnergy (能源计量扩展) ← equipment_id UNIQUE

设备类型与扩展表映射

设备类型 枚举值 扩展表 无扩展表时
电梯系统 ELEVATOR EquipmentElevator
暖通空调 HVAC EquipmentHvac
消防系统 FIRE_PROTECTION EquipmentFire
能源计量 ENERGY_METER EquipmentEnergy
给排水系统 PLUMBING 使用 attributes JSON
电气系统 ELECTRICAL 使用 attributes JSON
弱电系统 SECURITY 使用 attributes JSON
景观绿化 LANDSCAPE 使用 attributes JSON
厨余设备 KITCHEN 使用 attributes JSON
其他设备 OTHER 使用 attributes JSON

扩展表服务接口模式

public interface EquipmentElevatorService {
    Optional<EquipmentElevator> getByEquipmentId(UUID equipmentId);
    EquipmentElevator saveOrUpdate(EquipmentElevator elevator);
}

扩展表 API 路径

GET  /api/asset/equipment/{id}/elevator   → 获取电梯扩展
PUT  /api/asset/equipment/{id}/elevator   → 更新电梯扩展
GET  /api/asset/equipment/{id}/hvac       → 获取暖通扩展
PUT  /api/asset/equipment/{id}/hvac       → 更新暖通扩展
GET  /api/asset/equipment/{id}/fire       → 获取消防扩展
PUT  /api/asset/equipment/{id}/fire       → 更新消防扩展
GET  /api/asset/equipment/{id}/energy     → 获取能源扩展
PUT  /api/asset/equipment/{id}/energy     → 更新能源扩展

已知问题module-mdm 的 SpaceNode 也内嵌了设备扩展字段isEquipment 标记),与 module-asset 的独立 Equipment 实体形成双体系并存,需统一。

3.5 工单状态机

WorkOrder 状态机6 状态)

┌─────────────┐
│   PENDING   │ ← 创建工单(默认状态)
│   (待分配)   │
└──────┬──────┘
       │ assign (派单)
       ▼
┌─────────────┐
│  ASSIGNED   │ ← 分配负责人/服务商
│   (已派单)   │
└──────┬──────┘
       │ start (开始执行)
       ▼
┌─────────────┐
│ IN_PROGRESS │ ← 记录 actualStart
│   (执行中)   │
└──────┬──────┘
       │ complete (完成)
       ▼
┌─────────────┐
│  COMPLETED  │ ← 记录故障原因/解决方案/费用
│   (已完成)   │
└──────┬──────┘
       │ verify (验收)
       ▼
┌─────────────┐
│  VERIFIED   │ ← 记录验收人/评分/备注
│   (已验收)   │
└─────────────┘

特殊: CANCELLED ← PENDING/ASSIGNED/IN_PROGRESS 可取消
      COMPLETED/VERIFIED 不可取消

状态流转约束

当前状态 允许操作 下一状态 自动处理
PENDING assign ASSIGNED 设置 assignedTo/assignedVendor/assignedDate
ASSIGNED start IN_PROGRESS 设置 actualStart = now()
IN_PROGRESS complete COMPLETED 设置 actualEnd = now(),自动计算 actualHours
COMPLETED verify VERIFIED 设置 verifiedBy/verifiedDate/rating
PENDING/ASSIGNED/IN_PROGRESS cancel CANCELLED

MaintenanceTask 状态机6 状态,与工单类似但有差异)

差异点 WorkOrder MaintenanceTask
完成方式 仅一种 complete 两种complete简版+ complete-details详版
评分方式 验收时评分 验收时评分 + 独立 rate 接口
删除策略 物理删除 逻辑删除(设为 CANCELLED
完成后联动 自动更新设备维保记录

工单编号生成规则

类型 格式 示例
工单 WO-YYYYMMDD-XXXX WO-20260518-0001
维保任务 EQ-YYYYMMDD-XXXX EQ-20260518-0001

已知风险:编号生成使用 findMaxWorkNoByPrefix 查询最大编号 +1并发场景可能生成重复编号需改用数据库序列或 Redis INCR。

3.6 健康评分算法 [Beta]

评分公式

健康度 = 基础分(100) - 故障扣分 - 维保扣分 - 年龄扣分
最低分 = 0不会为负数

三维扣分规则

扣分项 计算公式 参数 上限
故障扣分 故障次数(近30天) x 5 FAILURE_DEDUCTION_PER_COUNT = 5 无上限
维保扣分 (1 - 维保完成率) x 20 MAINTENANCE_DEDUCTION_FACTOR = 20 20 分
年龄扣分 设备年龄(年) x 2 AGE_DEDUCTION_PER_YEAR = 2 10 分 (MAX_AGE_DEDUCTION)

5 级健康等级

等级 枚举值 分数范围 前端颜色
优秀 EXCELLENT [90, 100) 绿色
良好 GOOD [75, 90) 青色
一般 FAIR [60, 75) 橙色
较差 POOR [40, 60) 红色
危急 CRITICAL [0, 40) 红色

MTBF 计算(平均故障间隔时间)

MTBF = 运行时间(小时) / 故障次数
  • 计算周期:默认 30 天,可自定义
  • 运行时间:从第一个故障到最后一个故障的时间跨度
  • 仅 1 次故障:使用默认期间天数 x 24 小时
  • 无故障时返回 0

MTTR 计算(平均修复时间)

MTTR = 总修复时间(小时) / 修复次数
  • 仅统计已完成修复的故障记录repairDurationHours 不为空)
  • 无修复记录时返回 0

已知问题

  1. calculateEquipmentAge() 错误使用 SpaceNode.maintenanceContractStart 而非 Equipment.installationDate
  2. projectId 硬编码为全零 UUID 00000000-0000-0000-0000-000000000000
  3. 维保完成率固定返回 1.0TODO 标记)
  4. 扣分系数5、20、2、10硬编码在代码中未提取为配置

Beta → 正式演进路径

阶段 时间 目标
Beta当前 2026 Q2 修复已知 Bug提取配置项
V1 2026 Q3 完善维保完成率计算,积累真实数据校准系数
V2 2026 Q4 引入 IoT 数据,增加运行参数扣分维度
V3 2027 Q1 机器学习模型,基于历史数据预测故障概率

3.7 审计日志

记录方式@OperationLog 注解 + AOP 切面

@OperationLog(operation = "创建用户", module = "USER", action = AuditLog.ActionType.CREATE)
public User createUser(User user) { ... }

异步持久化:通过 auditLogExecutor 线程池异步保存,避免影响业务性能

核心字段

字段 说明
userId / username 操作人
operation 操作描述
module 模块标识USER/ROLE/PERMISSION/PROJECT/AUTH/DEPT
action 操作类型CREATE/UPDATE/DELETE/QUERY/VIEW/LOGIN/LOGOUT/EXPORT/IMPORT/ASSIGN/REVOKE
targetType / targetId 操作目标
content 操作内容
params / result 请求参数 / 操作结果
executionTimeMs 执行耗时
status SUCCESS / FAIL

查询窗口:强制限制 30 天,超过 30 天的查询自动截断起始时间

归档策略90 天以上日志归档当前实现为直接删除TODO: 导出至对象存储保留 3-5 年)

索引设计

idx_audit_log_created_at (created_at)
idx_audit_log_user_id (user_id)
idx_audit_log_module (module)
idx_audit_log_action (action)
idx_al_user_createdat (user_id, created_at DESC)

已知不足

  1. 审计日志可篡改(无防篡改机制),需改为只追加
  2. 90 天归档实为删除,不符合合规要求(物业行业需保留 3-5 年)
  3. 改进方案:数据库触发器禁止 UPDATE/DELETE + 90 天后导出至 OSS/S3

3.8 编码生成规则

实体 编码格式 生成方式 唯一性保障
项目编码 正则 ^[a-zA-Z0-9_-]+$ 后端 generateCode() 数据库 UNIQUE
空间编码 未实现
设备编码 equipmentCode 创建时指定 数据库 UNIQUE
工单编号 WO-YYYYMMDD-XXXX findMaxWorkNoByPrefix + 1 应用层(有并发风险)
维保任务编号 EQ-YYYYMMDD-XXXX 同上 应用层(有并发风险)
计划编码 planCode 创建时指定 数据库 UNIQUE
备件编码 sparePartCode 创建时指定 数据库 UNIQUE
计量点编码 EM + yyyyMMddHHmmss generateMeterCode() 冲突时追加后缀
记录编码 recordCode 创建时指定 数据库 UNIQUE

改进方向

  1. 空间编码需实现自动生成规则(如 项目编码-楼栋号-单元号-房号)
  2. 工单/任务编号改用数据库序列或 Redis INCR 保障并发安全
  3. 统一编码生成服务,避免各模块各自实现

四、难点识别与应对

4.1 跨域业务流程的一致性保障

难点描述:维保任务完成后需联动更新设备信息(维保商、下次巡检日期),工单完成后需关联备件出库,能耗数据需对接账单生成。这些跨域操作需要保证数据一致性。

应对方案

方案 适用场景 实现方式 一致性级别
同步调用 + 事务 强一致性要求 @Transactional 跨模块 Service 调用 强一致
事件驱动 + 最终一致性 弱一致性可接受 Spring ApplicationEvent + 异步监听 最终一致
补偿事务 需要回滚能力 Saga 模式,失败时执行补偿操作 最终一致

当前实现:维保任务完成后同步调用 EquipmentService 更新设备,异常容错(更新设备失败不影响工单完成)。

改进计划

  1. 短期Q2 2026保持同步调用增加重试机制@Retryable
  2. 中期Q3 2026引入 Spring ApplicationEvent关键操作发布领域事件
  3. 远期Q4 2026评估引入消息队列RabbitMQ/Kafka解耦跨域通信

4.2 工单状态机的并发控制

难点描述:多个用户可能同时对同一工单执行状态变更操作(如同时派单、同时完成),需要保证状态流转的正确性和幂等性。

应对方案

机制 实现方式 说明
乐观锁 version 字段 + @Version JPA 自动版本控制,更新时检查版本号
状态校验 业务层前置检查 状态变更前校验当前状态是否允许该操作
幂等性 幂等键 + 去重 重复请求返回当前状态而非报错
分布式锁 Redis SETNX 防止同一工单被并发操作

当前实现:仅业务层前置状态校验,无乐观锁和分布式锁。

改进计划

  1. 为 WorkOrder 和 MaintenanceTask 添加 version 字段(@Version
  2. 状态变更操作使用 Redis 分布式锁key: work_order:lock:{id}
  3. 状态变更接口设计为幂等:重复操作返回当前状态

4.3 树形结构的高效查询

难点描述SpaceNode 使用 treePath 字符串路径(如 uuid1.uuid2.uuid3),查询子孙节点需 LIKE 匹配,大数据量下性能堪忧。

应对方案

方案 查询性能 维护成本 适用场景
treePath LIKE当前 O(n) 全表扫描 数据量 < 1万
PostgreSQL ltree 扩展 O(log n) 索引扫描 数据量 1-10万
闭包表 (Closure Table) O(1) 直接查询 高(需额外表) 数据量 > 10万
递归 CTE O(depth) 深度有限(< 10层

当前实现treePath LIKE + B-tree 索引

改进计划

  1. 短期Q2 2026确保 treePath 索引存在,添加 GIN 索引支持前缀查询
  2. 中期Q3 2026评估迁移至 PostgreSQL ltree 扩展,利用专用的 ltree 索引
  3. 远期Q4 2026若数据量超过 10 万节点,考虑闭包表方案

递归 CTE 查询示例(当前可用的优化方案):

WITH RECURSIVE space_tree AS (
    SELECT * FROM mdm_space_node WHERE id = :rootId
    UNION ALL
    SELECT n.* FROM mdm_space_node n
    JOIN space_tree st ON n.parent_id = st.id
)
SELECT * FROM space_tree;

4.4 健康评分的数据积累与算法迭代

难点描述:健康评分算法当前为 Beta 版,扣分系数基于经验设定,缺乏真实数据校准。维保完成率固定为 1.0,影响评分准确性。

应对方案

阶段 目标 具体措施
Beta → V1 修复 Bug + 提取配置 修正设备年龄计算、projectId 硬编码;提取扣分系数为 @ConfigurationProperties
V1 → V2 数据校准 + 完善计算 实现维保完成率真实计算;积累 3 个月数据后用线性回归校准系数
V2 → V3 引入 IoT + 预测模型 增加运行参数扣分维度;基于历史数据训练故障预测模型

配置化改进

# application.yml
equipment:
  health:
    failure-deduction-per-count: 5
    maintenance-deduction-factor: 20
    age-deduction-per-year: 2
    max-age-deduction: 10
    calculation-period-days: 30
    default-inspection-cycle-days: 30

4.5 备件库存的并发出入库

难点描述:多个工单可能同时使用同一备件,导致库存超卖或数据不一致。

应对方案

机制 实现方式 说明
乐观锁 currentStock + @Version 出库时检查版本号,冲突时重试
库存校验 出库前检查 currentStock >= quantity 防止库存为负
事务隔离 @Transactional(isolation = SERIALIZABLE) 最高隔离级别,性能影响大
Redis 原子操作 DECRBY 命令 原子性扣减,性能最优

当前实现:出库时校验库存不能为负,但无乐观锁。

改进计划

  1. 为 SparePart 添加 version 字段(@Version
  2. 出库操作使用 Redis DECRBY 原子扣减,成功后异步同步到数据库
  3. 引入库存预占机制:工单创建时预占库存,完成时确认扣减,取消时释放

4.6 能耗数据的 IoT 接入

难点描述当前能耗数据仅支持手动录入MANUALIoT 自动采集IOT枚举已定义但未实现对接。

当前状态

public enum RecordMethod {
    MANUAL,  // 手动录入 — 已实现
    IOT      // IoT自动采集 — 枚举已定义,对接未实现
}

扩展路径

阶段 目标 技术方案
Phase 1当前 手动录入 前端表单 + 后端 API
Phase 2 IoT 数据接入 MQTT Broker + Spring Integration 消费消息
Phase 3 实时监控 WebSocket 推送 + 时序数据库TimescaleDB
Phase 4 智能告警 规则引擎 + 异常检测算法

Phase 2 架构设计

IoT 设备 → MQTT Broker → Spring Integration → EnergyConsumptionService.recordConsumption()
                                    ↓
                            recordMethod = IOT
                            自动获取 previousReading
                            自动计算 consumption 和 amount

五、跨模块跨功能实现规范

5.1 API 设计规范

路径前缀

/api/{module}/{resource}
模块 路径前缀 示例
auth /api/auth /api/auth/users, /api/auth/roles
mdm /api/mdm /api/mdm/projects, /api/mdm/space-nodes
asset /api/asset /api/asset/equipment
wo /api/wo /api/wo/work-orders
ops /api/ops /api/ops/maintenance-tasks, /api/ops/energy

版本管理(待实现):

当前: /api/{module}/{resource}
目标: /api/v1/{module}/{resource}

分页规范

// 请求参数
GET /api/mdm/projects?page=0&size=20&sortBy=createdAt&sortDirection=DESC

// 响应格式
{
  "code": 0,
  "message": "success",
  "data": {
    "content": [...],
    "totalElements": 100,
    "totalPages": 5,
    "number": 0,
    "size": 20
  }
}

约束所有列表接口必须支持分页禁止全量返回。WorkOrder 当前返回 List<WorkOrder> 全量数据需改造。

错误码规范

段号 模块 范围
1xxx 认证 1000-1999
2xxx 用户 2000-2999
3xxx 角色 3000-3999
4xxx 权限 4000-4999
5xxx 项目 5000-5999
6xxx 空间/能耗 6000-6999
7xxx 文件 7000-7999
8xxx 工单 8000-8999待分配
9xxx 财务 9000-9999待分配

统一响应封装

public class ApiResponse<T> {
    private int code;
    private String message;
    private T data;
}

5.2 数据模型规范

主键策略

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private UUID id;  // 所有实体使用 UUID 主键

软删除

private Boolean isDeleted = false;  // 核心业务实体必须有此字段

// Repository 查询方法
findByIdAndIsDeletedFalse(UUID id);
findByProjectIdAndIsDeletedFalse(UUID projectId);

约束WorkOrder 当前使用物理删除,需统一改为逻辑删除。

审计字段

@CreatedDate
@Column(nullable = false, updatable = false)
private LocalDateTime createdAt;

@LastModifiedDate
@Column(nullable = false)
private LocalDateTime updatedAt;

@Column(updatable = false)
private UUID createdBy;

private UUID updatedBy;

约束:所有实体必须有 createdAt 和 updatedAt 字段,使用 JPA Auditing 自动填充。

JSONB 使用规范

场景 字段类型 说明
照片列表 JSONB List<String>List<EquipmentPhoto>
文档列表 JSONB List<EquipmentDocument>
扩展属性 JSONB Map<String, Object> 或 String 存储 JSON
检查项结果 JSONB 结构化 JSON 数组

约束SpaceNode.attributes 当前为 String(2000),需改为 JSONB 类型以支持 GIN 索引和原生 JSON 查询。

枚举策略

// 数据库存储为字符串JPA 实体使用枚举类型
@Enumerated(EnumType.STRING)
private UserStatus status;

// 枚举定义
public enum UserStatus {
    ACTIVE, LOCKED, DISABLED
}

约束:禁止使用 EnumType.ORDINAL统一使用 EnumType.STRING。

5.3 异常处理规范

三层异常体系

BusinessException (业务异常)
    ├── ErrorCode (错误码枚举)
    └── GlobalExceptionHandler (全局异常处理器)

BusinessException 使用规范

// 正确用法
throw new BusinessException(ErrorCode.USER_NOT_FOUND);

// 错误用法(禁止)
throw new RuntimeException("用户不存在");

约束WorkOrderServiceImpl 中存在 throw new RuntimeException("工单不存在"),需替换为 BusinessException + ErrorCode。

GlobalExceptionHandler 处理规则

异常类型 HTTP 状态码 处理方式
BusinessException 200 (body 含错误码) 返回 ApiResponse(code, message, null)
MethodArgumentNotValidException 200 返回参数校验错误信息
DataAccessException 200 脱敏后返回数据库错误
Exception 200 通用异常兜底

改进方向:业务错误码 4xx/5xx 应映射为对应 HTTP 状态码,非标准码保持 200 但在 body 中体现。

5.4 权限控制规范

注解式权限

@PreAuthorize("hasAuthority('asset:equipment:create')")
public Equipment createEquipment(Equipment equipment) { ... }

数据范围过滤

// Service 层手动调用
if (!dataScopeService.canAccessAllData(currentUser)) {
    List<UUID> permittedProjectIds = dataScopeService.getPermittedProjectIds(currentUser);
    // 过滤查询结果
}

改进方向:通过 JPA Specification 自动拼接数据过滤条件,避免业务层遗漏。

菜单动态渲染(待实现):

1. 前端登录后请求 GET /api/auth/users/{id}/menus
2. 后端根据用户角色返回有权限的菜单列表
3. 前端动态生成路由和菜单

5.5 前后端协作规范

TypeScript 类型同步

// 前端类型定义必须与后端枚举一致
// equipment.ts
export enum EquipmentType {
  ELEVATOR = 'ELEVATOR',
  HVAC = 'HVAC',
  FIRE_PROTECTION = 'FIRE_PROTECTION',
  // ... 与后端 EquipmentType 枚举完全一致
}

约束当前前端能源类型ELECTRICITY/WATER/GAS/CENTRAL_HEATING/CENTRAL_COOLING与后端LIGHTING/HVAC/POWER/SPECIAL/WATER/GAS不一致需统一。

枚举一致性检查清单

枚举 前端文件 后端位置 是否一致
EquipmentType equipment.ts Equipment.java 需校验
EnergyType energy.ts EnergyMeter.java 不一致(需修复)
WorkOrderStatus work-order.ts WorkOrder.java 需校验
MaintenanceTaskStatus maintenance.ts MaintenanceTask.java 不一致(需修复)
TriggerType maintenance.ts MaintenanceTask.java 不一致(需修复)

API 调用封装

// src/api/xxx.ts
import request from '@/utils/request'

export function getEquipment(id: string) {
  return request.get<ApiResponse<Equipment>>(`/api/asset/equipment/${id}`)
}

约束:维保计划存在两套前端 APImaintenance.ts + maintenance-plan.ts需合并为统一 API 文件。

5.6 测试规范

TDD 开发流程

1. 编写失败测试Red
2. 编写最小实现代码Green
3. 重构优化Refactor

测试分层

层次 框架 覆盖范围 当前状态
单元测试 JUnit 5 + Mockito Service 层业务逻辑 仅 EnergyMeterServiceTest
API 测试 Spring MockMvc Controller 层接口 缺失
集成测试 @SpringBootTest 跨模块交互 缺失
E2E 测试 Playwright/Cypress 前端用户流程 缺失

优先补充的单元测试

  1. WorkOrderService — 工单状态机流转
  2. LoginService — 登录认证流程
  3. EquipmentHealthService — 健康评分算法
  4. SparePartService — 出入库库存校验

六、数据库设计概要

6.1 ER 图(核心实体关系)

erDiagram
    User ||--o{ Role : "auth_user_role"
    Role ||--o{ Permission : "auth_role_permission"
    User ||--|| EnterpriseUser : "共享主键1:1"
    User ||--|| ProjectStaff : "1:1"
    User ||--|| Resident : "共享主键1:1"
    ProjectStaff ||--o{ ProjectStaffRole : "1:N"
    ProjectStaffRole }o--|| Role : "N:1"
    Resident ||--o{ ResidentSpace : "1:N"
    ResidentSpace }o--|| Space : "N:1"
    User ||--o{ UserProject : "1:N"
    UserProject }o--|| Project : "N:1"
    Dept ||--o{ Dept : "parentId自引用"

    Project ||--|| ProjectConfig : "1:1"
    Project ||--|| ProjectStatistics : "1:1"
    Project ||--o{ ProjectStatusHistory : "1:N"
    Project ||--o{ SpaceNode : "1:N"
    SpaceNode ||--o{ SpaceNode : "parentId自引用"

    Equipment ||--o| EquipmentElevator : "1:1"
    Equipment ||--o| EquipmentHvac : "1:1"
    Equipment ||--o| EquipmentFire : "1:1"
    Equipment ||--o| EquipmentEnergy : "1:1"
    Equipment ||--o{ EquipmentHealthScore : "1:N"
    Equipment ||--o{ EquipmentFailureHistory : "1:N"
    Equipment }o--|| OwnershipEntity : "N:1"
    Equipment }o--o| SpaceNode : "spaceNodeId"

    MaintenancePlan ||--o{ MaintenanceTask : "1:N"
    WorkOrder ||--o{ WorkOrderItem : "1:N"
    WorkOrder }o--o| MaintenancePlan : "planId"
    WorkOrder }o--o| Equipment : "equipmentId"
    MaintenanceTask }o--o| Equipment : "equipmentId"

    SparePartCategory ||--o{ SparePartCategory : "parentId自引用"
    SparePartCategory ||--o{ SparePart : "1:N"
    SparePart ||--o{ SparePartRecord : "1:N"

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

6.2 表命名规范

格式{模块前缀}_{实体名}

模块前缀 示例 说明
auth_ auth_user, auth_role, auth_permission 认证授权模块
mdm_ mdm_project, mdm_space_node 主数据模块
asset_ asset_equipment, asset_equipment_elevator 设备资产模块
ops_ ops_work_order, ops_maintenance_plan 运维工单模块
fin_ fin_fee_item, fin_fee_bill 财务模块(待实现)
sys_ sys_audit_log, sys_config 系统级表

列命名规范

  • 使用 snake_caseproject_idcreated_atis_deleted
  • 外键列:{关联实体}_idequipment_idspace_node_id
  • 布尔列:is_ 前缀:is_deletedis_equipment
  • 时间列:_at 后缀:created_atupdated_at
  • 日期列:_date 后缀:installation_datenext_inspection_date

6.3 索引策略

B-tree 索引(等值查询、范围查询、排序):

索引列 用途
ops_work_order (project_id, status) 按项目+状态查询工单
ops_work_order (status, created_at) 按状态+时间查询
ops_work_order (created_at DESC) 时间倒序
asset_equipment (project_id, status) 按项目+状态查询设备
asset_equipment (project_id, equipment_type) 按项目+类型查询设备
asset_equipment (equipment_code) UNIQUE 编码唯一
mdm_space_node (project_id, parent_id) 项目+父节点
mdm_space_node (project_id, node_type) 项目+类型
mdm_space_node (tree_path) 路径前缀查询
ops_equipment_failure_history (equipment_id, failure_time DESC) 设备故障时间线
sys_audit_log (user_id, created_at DESC) 用户操作时间线

GIN 索引JSONB 查询,待添加):

CREATE INDEX idx_equipment_attributes ON asset_equipment USING GIN (attributes);
CREATE INDEX idx_equipment_photos ON asset_equipment USING GIN (photos);
CREATE INDEX idx_space_node_attributes ON mdm_space_node USING GIN (attributes);

JSONB 索引使用场景

字段 查询场景
asset_equipment attributes 按扩展属性筛选设备
asset_equipment photos 按照片类型查询
ops_maintenance_task parts_used 按备件 ID 查询使用该备件的工单
mdm_inspection_record items 按检查项结果查询

6.4 数据迁移策略

工具选型Flyway

迁移脚本命名规范

V{版本号}__{描述}.sql
示例:
V1__init_auth_tables.sql
V2__init_mdm_tables.sql
V3__init_asset_tables.sql
V4__init_ops_tables.sql
V5__add_equipment_health_score.sql
V6__add_space_node_indexes.sql

当前状态:未使用 Flyway依赖 JPA 自动建表ddl-auto: update

改进计划

  1. 短期:在开发环境继续使用 JPA 自动建表
  2. 中期:引入 Flyway将现有 schema 导出为初始迁移脚本
  3. 长期:生产环境禁止 ddl-auto: update所有变更通过 Flyway 迁移脚本执行

七、技术选型与依赖

7.1 后端技术栈

技术 版本 用途 说明
Spring Boot 3.x 应用框架 Java 17+Servlet 容器
Spring Security 6.x 安全框架 JWT 认证 + RBAC 授权
Spring Data JPA 3.x ORM 框架 Hibernate 实现,自动建表
Hibernate 6.x JPA 实现 实体映射、懒加载、审计
MapStruct 对象映射 Entity ↔ DTO 转换
Lombok 代码简化 @Data、@Builder、@RequiredArgsConstructor
BCrypt 密码加密 Spring Security PasswordEncoder
JJWT JWT 工具 Token 生成与验证
Spring AOP 切面编程 审计日志 @OperationLog
Spring Validation 参数校验 @NotNull、@Size、@Pattern
Spring Web REST API @RestController、@RequestMapping

7.2 前端技术栈

技术 版本 用途 说明
Vue 3.x 前端框架 Composition API + <script setup>
TypeScript 5.x 类型系统 类型安全
Ant Design Vue 4.x UI 组件库 统一视觉风格
Pinia 2.x 状态管理 Composition API 风格,支持持久化
Vite 5.x 构建工具 快速 HMR
Axios 1.x HTTP 客户端 请求/响应拦截器封装
Vue Router 4.x 路由管理 路由守卫 + 权限控制
ECharts 5.x 图表库 健康评分趋势图

7.3 数据库

技术 版本 用途 说明
PostgreSQL 15+ 主数据库 JSONB、UUID、ltree 扩展
JSONB 半结构化数据 照片列表、文档列表、扩展属性、检查项结果
UUID 主键类型 所有实体主键使用 UUID
Redis 7+ 缓存 登录失败锁定、Token 缓存

PostgreSQL 特性使用

特性 使用场景 当前状态
JSONB Equipment.photos/documents/attributes、InspectionRecord.items/problems 部分使用SpaceNode.attributes 降级为 String
UUID 所有实体主键 已使用
ltree 空间树形结构 未使用(使用 treePath 字符串替代)
GIN 索引 JSONB 字段查询 未使用(待添加)
PostGIS 地图空间查询 未使用

7.4 开发工具

工具 用途 说明
Maven 后端构建 多模块项目管理
npm 前端构建 依赖管理
Git 版本控制 分支管理
Flyway 数据库迁移 待引入
SpringDoc/OpenAPI API 文档 待引入

附录 A实现状态总览

功能模块 实现状态 核心实体 说明
用户管理 已实现 User/EnterpriseUser/ProjectStaff/Resident 4 种用户类型扩展
角色权限 已实现 Role/Permission/ProjectStaffRole 三级角色 + 四级数据范围
部门管理 已实现 Dept 树形结构5 种部门类型
项目管理 已实现 Project/ProjectConfig/ProjectStatistics 状态流转 + 配置 + 统计
空间节点 已实现 SpaceNode 统一空间模型 + 设备扩展字段
设备台账 已实现 Equipment + 4 张扩展表 主表 + 扩展表模式
健康评分 已实现(Beta) EquipmentHealthScore MTBF/MTTR + 三维扣分
故障历史 已实现 EquipmentFailureHistory 4 级故障 + 4 种修复结果
归属管理 已实现 OwnershipEntity 4 种归属 + 3 种主体
工单管理 已实现 WorkOrder/WorkOrderItem 6 状态状态机
维保计划 已实现 MaintenancePlan 周期性维保调度
维保任务 已实现 MaintenanceTask 6 状态 + 自动优先级判定
巡检标准 已实现 InspectionItem/InspectionTemplate 标准项库 + 模板管理
巡检记录 已实现 InspectionRecord 签到 + JSONB 结果
备件库存 已实现 SparePart/SparePartCategory/SparePartRecord 出入库 + 低库存预警
能耗计量 已实现 EnergyMeter/EnergyConsumption 手动录入 + 简单费用计算
审计日志 已实现 AuditLog AOP + 异步 + 30 天窗口
系统配置 已实现 SysConfig 键值对配置
消息通知 未实现 NotificationChannel/Template/Rule/History
收费项目 未实现 FeeItem
账单管理 未实现 FeeBill
支付记录 未实现 FeePayment
设备二维码 未实现 原需求有但未实现
IoT 集成 未实现 枚举已定义,对接未实现
地图服务 未实现 PostGIS + 高德地图
SLA 管理 未实现 响应时间/处理时间/超时升级

附录 B关键风险与优先行动

优先级 风险 行动项 预估工作量
P0 财务域核心功能完全缺失 创建 module-finance实现 FeeItem/FeeBill/FeePayment 5 天
P0 消息通知系统完全缺失 实现 NotificationChannel/Template/Rule/History 8 天
P0 工单全量查询 OOM 风险 改为分页查询 1 天
P0 健康评分算法 Bug 修正设备年龄计算和 projectId 硬编码 1 天
P1 工单状态机缺少挂起/退回 增加 SUSPENDED/RETURNED 状态 3 天
P1 工单流转记录缺失 实现 WorkOrderFlow 2 天
P1 前后端枚举不一致 统一能源类型/维保状态/触发类型 1 天
P1 权限相关端点缺失 实现权限树/权限校验/用户菜单 3 天
P2 API 无版本管理 引入 /api/v1/ 前缀 3 天
P2 SpaceNode.attributes 非 JSONB 改为 JSONB + GIN 索引 2 天
P2 审计日志可篡改 改为只追加 + 归档而非删除 2 天
P2 设备模型双体系并存 统一 MDM SpaceNode 内嵌设备与 ASSET Equipment 3 天

文档说明:本概要设计文档基于 REVERSE-AUTH/MDM/ASSET/OPS/FINANCE 五份反推设计文档、BEST-PRACTICES-REPORT 行业最佳实践评估报告、CONSISTENCY-REPORT 需求一致性评估报告综合编制,反映 2026-05-18 代码库状态。财务域D5核心功能标注为"待实现",需优先启动开发。