# 运维工单域功能详细设计文档（代码反推版）

**文档来源**: 基于 module-wo 模块实际代码反推  
**生成日期**: 2026-04-23  
**代码基线**: ether-pms/module-wo, ether-admin  
**对照文档**: 02-OPERATIONS.md（运营调度领域技术方案）

---

## 一、领域概述

### 1.1 领域职责

运维工单域（module-wo）负责管理物业运维全生命周期，涵盖：

- **综合工单管理**：多来源工单的创建、分配、执行、完成、验收全流程
- **维保计划管理**：设备周期性维保计划的制定与调度
- **维保任务管理**：维保工单的触发、执行、验收闭环
- **巡检模板管理**：设备点检模板与检查项的配置
- **工单明细管理**：工单下的备件/巡检项/检查点明细
- **统计看板**：工单与维保任务的多维度统计

### 1.2 核心概念

| 概念 | 说明 | 对应实体 | 数据库表 |
|------|------|----------|----------|
| **工单** | 综合业务单据，支持6种来源6种类型 | WorkOrder | ops_work_order |
| **工单明细** | 工单下的备件/巡检项/检查点 | WorkOrderItem | ops_work_order_item |
| **维保计划** | 设备周期性维保计划 | MaintenancePlan | ops_maintenance_plan |
| **维保任务** | 维保工单（设备维保执行单元） | MaintenanceTask | ops_maintenance_task |
| **巡检模板** | 设备点检模板 | InspectionTemplate | ops_inspection_template |
| **巡检项** | 模板下的检查项 | InspectionItem | ops_inspection_item |

### 1.3 领域边界

实际实现中，运维工单域与原需求文档的边界存在显著差异：

- **原需求**：运营调度域（ether-ops）包含工单 + 消息通知系统
- **实际实现**：module-wo 仅包含工单/维保/巡检，消息通知系统未实现
- **前端分裂**：维保计划存在两套前端 API（`maintenance.ts` vs `maintenance-plan.ts`），巡检标准项归属 MDM 域

---

## 二、数据结构设计

### 2.1 WorkOrder（工单）

**表名**: `ops_work_order`

| 字段 | 类型 | 必填 | 默认值 | 说明 |
|------|------|------|--------|------|
| id | UUID | 是 | 自动生成 | 主键 |
| workNo | VARCHAR(50) | 是 | 自动生成 | 工单编号，格式: WO-YYYYMMDD-XXXX |
| source | ENUM | 是 | - | 工单来源 |
| type | ENUM | 是 | - | 工单类型 |
| priority | ENUM | 否 | MEDIUM | 优先级 |
| status | ENUM | 否 | PENDING | 工单状态 |
| title | VARCHAR(200) | 是 | - | 工单标题 |
| description | VARCHAR(2000) | 否 | - | 工单描述 |
| projectId | UUID | 是 | - | 所属项目 |
| equipmentId | UUID | 否 | - | 关联设备 |
| spaceId | UUID | 否 | - | 关联空间 |
| planId | UUID | 否 | - | 关联维保计划 |
| triggerType | ENUM | 否 | - | 触发类型 |
| assignedTo | VARCHAR(200) | 否 | - | 负责人 |
| assignedVendor | VARCHAR(200) | 否 | - | 服务商 |
| assignedDate | DATE | 否 | - | 派单日期 |
| actualStart | TIMESTAMP | 否 | - | 实际开始时间 |
| actualEnd | TIMESTAMP | 否 | - | 实际结束时间 |
| actualHours | DECIMAL(6,2) | 否 | - | 实际工时（小时） |
| faultCause | VARCHAR(2000) | 否 | - | 故障原因 |
| solution | VARCHAR(5000) | 否 | - | 解决方案 |
| result | VARCHAR(2000) | 否 | - | 处理结果 |
| laborCost | DECIMAL(12,2) | 否 | - | 人工费 |
| partsCost | DECIMAL(12,2) | 否 | - | 备件费 |
| totalCost | DECIMAL(12,2) | 否 | - | 总费用 |
| completedBy | VARCHAR(200) | 否 | - | 完成人 |
| completedDate | DATE | 否 | - | 完成日期 |
| verifiedBy | VARCHAR(200) | 否 | - | 验收人 |
| verifiedDate | DATE | 否 | - | 验收日期 |
| rating | INTEGER | 否 | - | 评分（1-5星） |
| remark | VARCHAR(1000) | 否 | - | 备注 |
| photos | JSONB | 否 | - | 照片URL列表 |
| signature | VARCHAR(2000) | 否 | - | 签名 |
| createdAt | TIMESTAMP | 是 | now() | 创建时间 |
| updatedAt | TIMESTAMP | 是 | now() | 更新时间 |
| createdBy | VARCHAR(200) | 否 | - | 创建人 |

**枚举定义**：

| 枚举 | 值 | 中文 |
|------|-----|------|
| Source | OWNER | 业主报修 |
| | MAINTENANCE | 维保计划 |
| | INSPECTION | 巡检触发 |
| | FAULT | 故障触发 |
| | REGULATORY | 法规巡检 |
| | MANUAL | 手动创建 |
| Type | REPAIR | 维修 |
| | INSPECTION | 巡检 |
| | SECURITY | 安保 |
| | CLEANING | 保洁 |
| | PROPERTY | 物业 |
| | CONSULTATION | 咨询 |
| Priority | LOW / MEDIUM / HIGH / URGENT | 低/中/高/紧急 |
| Status | PENDING / ASSIGNED / IN_PROGRESS / COMPLETED / VERIFIED / CANCELLED | 见状态机 |
| TriggerType | PLAN / INSPECTION / FAULT / MANUAL | 计划/巡检/故障/手动 |

**索引**：

| 索引名 | 字段 | 用途 |
|--------|------|------|
| idx_wo_project_status | project_id, status | 项目+状态查询 |
| idx_wo_priority_status | priority, status | 优先级+状态查询 |
| idx_wo_plan_createdat | plan_id, created_at | 计划关联查询 |
| idx_wo_status_createdat | status, created_at | 状态+时间查询 |
| idx_wo_createdat_desc | created_at DESC | 时间倒序 |

### 2.2 WorkOrderItem（工单明细）

**表名**: `ops_work_order_item`

| 字段 | 类型 | 必填 | 默认值 | 说明 |
|------|------|------|--------|------|
| id | UUID | 是 | 自动生成 | 主键 |
| workOrderId | UUID | 是 | - | 所属工单ID |
| itemType | ENUM | 是 | - | 明细类型 |
| itemName | VARCHAR(200) | 是 | - | 明细名称 |
| quantity | DECIMAL(10,2) | 否 | 1 | 数量 |
| unit | VARCHAR(50) | 否 | - | 单位 |
| unitPrice | DECIMAL(12,2) | 否 | - | 单价 |
| totalPrice | DECIMAL(12,2) | 否 | - | 总价 |
| isNormal | BOOLEAN | 否 | - | 是否正常 |
| observation | VARCHAR(2000) | 否 | - | 观察记录 |
| suggestion | VARCHAR(2000) | 否 | - | 建议 |
| sortOrder | INTEGER | 否 | 0 | 排序序号 |
| createdAt | TIMESTAMP | 否 | now() | 创建时间 |

**枚举定义**：

| 枚举 | 值 | 中文 |
|------|-----|------|
| ItemType | PART | 备件 |
| | INSPECTION_ITEM | 巡检项 |
| | CHECKPOINT | 检查点 |

### 2.3 MaintenanceTask（维保任务）

**表名**: `ops_maintenance_task`

| 字段 | 类型 | 必填 | 默认值 | 说明 |
|------|------|------|--------|------|
| id | UUID | 是 | 自动生成 | 主键 |
| taskNo | VARCHAR(50) | 否 | 自动生成 | 任务编号，格式: EQ-YYYYMMDD-XXXX |
| planId | UUID | 否 | - | 关联维保计划ID |
| equipmentId | UUID | 是 | - | 关联设备ID |
| projectId | UUID | 否 | - | 所属项目 |
| taskType | ENUM | 否 | - | 任务类型 |
| triggerType | ENUM | 否 | - | 触发类型 |
| priority | ENUM | 否 | 自动判定 | 优先级 |
| status | ENUM | 否 | PENDING | 任务状态 |
| title | VARCHAR(200) | 否 | - | 任务标题 |
| description | VARCHAR(2000) | 否 | - | 任务描述 |
| assignedTo | VARCHAR(200) | 否 | - | 负责人 |
| assignedVendor | VARCHAR(200) | 否 | - | 服务商 |
| assignedDate | DATE | 否 | - | 派单日期 |
| actualStart | TIMESTAMP | 否 | - | 实际开始时间 |
| actualEnd | TIMESTAMP | 否 | - | 实际结束时间 |
| actualHours | DECIMAL(6,2) | 否 | - | 实际工时 |
| faultCause | VARCHAR(2000) | 否 | - | 故障原因 |
| solution | VARCHAR(5000) | 否 | - | 解决方案 |
| result | VARCHAR(2000) | 否 | - | 处理结果 |
| partsUsed | JSONB | 否 | - | 使用备件列表 |
| laborCost | DECIMAL(12,2) | 否 | - | 人工费 |
| partsCost | DECIMAL(12,2) | 否 | - | 备件费 |
| totalCost | DECIMAL(12,2) | 否 | - | 总费用 |
| completedBy | VARCHAR(200) | 否 | - | 完成人 |
| completedDate | DATE | 否 | - | 完成日期 |
| verifiedBy | VARCHAR(200) | 否 | - | 验收人 |
| verifiedDate | DATE | 否 | - | 验收日期 |
| rating | INTEGER | 否 | - | 评分（1-5） |
| remark | VARCHAR(1000) | 否 | - | 备注 |
| photos | JSONB | 否 | - | 照片URL列表 |
| signature | VARCHAR(2000) | 否 | - | 签名 |
| createdAt | TIMESTAMP | 否 | now() | 创建时间 |
| updatedAt | TIMESTAMP | 否 | now() | 更新时间 |
| createdBy | VARCHAR(200) | 否 | - | 创建人 |

**枚举定义**：

| 枚举 | 值 | 中文 |
|------|-----|------|
| TaskType | PREVENTIVE | 预防性维护 |
| | CORRECTIVE | 纠正性维护 |
| | EMERGENCY | 紧急维修 |
| TriggerType | PLAN | 计划触发 |
| | INSPECTION | 巡检触发 |
| | FAULT | 故障触发 |
| | MANUAL | 手动创建 |
| Priority | LOW / MEDIUM / HIGH / URGENT | 低/中/高/紧急 |
| Status | PENDING / ASSIGNED / IN_PROGRESS / COMPLETED / VERIFIED / CANCELLED | 见状态机 |

**partsUsed JSONB 结构**：

```json
[
  {
    "partsId": "uuid",
    "partsName": "备件名称",
    "quantity": 2,
    "unitPrice": 100.00,
    "totalPrice": 200.00
  }
]
```

**索引**：

| 索引名 | 字段 | 用途 |
|--------|------|------|
| idx_mt_equipment_status | equipment_id, status | 设备+状态查询 |
| idx_mt_project_status | project_id, status | 项目+状态查询 |
| idx_mt_plan_createdat | plan_id, created_at | 计划关联查询 |
| idx_mt_status_assigneddate | status, assigned_date | 状态+派单日期查询 |

### 2.4 MaintenancePlan（维保计划）

**表名**: `ops_maintenance_plan`

| 字段 | 类型 | 必填 | 默认值 | 说明 |
|------|------|------|--------|------|
| id | UUID | 是 | 自动生成 | 主键 |
| planCode | VARCHAR(50) | 是 | 自动生成 | 计划编码（唯一） |
| planName | VARCHAR(200) | 是 | - | 计划名称 |
| planContent | VARCHAR(5000) | 否 | - | 计划内容 |
| projectId | UUID | 否 | - | 所属项目 |
| equipmentId | UUID | 是 | - | 关联设备 |
| planType | ENUM | 是 | - | 计划类型 |
| cycleDays | INTEGER | 否 | - | 周期天数 |
| estimatedHours | DECIMAL(6,2) | 否 | - | 预估工时 |
| assignedVendor | VARCHAR(200) | 否 | - | 指定服务商 |
| status | ENUM | 否 | ACTIVE | 计划状态 |
| lastDate | DATE | 否 | - | 上次执行日期 |
| nextDate | DATE | 否 | - | 下次执行日期 |
| createdAt | TIMESTAMP | 否 | now() | 创建时间 |
| updatedAt | TIMESTAMP | 否 | now() | 更新时间 |
| createdBy | VARCHAR(200) | 否 | - | 创建人 |

**枚举定义**：

| 枚举 | 值 | 中文 |
|------|-----|------|
| PlanType | PREVENTIVE | 预防性维护 |
| | CORRECTIVE | 纠正性维护 |
| PlanStatus | ACTIVE | 启用 |
| | INACTIVE | 停用 |
| | SUSPENDED | 暂停 |

### 2.5 InspectionTemplate（巡检模板）

**表名**: `ops_inspection_template`

| 字段 | 类型 | 必填 | 默认值 | 说明 |
|------|------|------|--------|------|
| id | UUID | 是 | 自动生成 | 主键 |
| templateCode | VARCHAR(50) | 是 | 自动生成 | 模板编码（唯一） |
| templateName | VARCHAR(200) | 是 | - | 模板名称 |
| description | VARCHAR(2000) | 否 | - | 描述 |
| projectId | UUID | 否 | - | 所属项目 |
| spaceId | UUID | 否 | - | 关联空间 |
| category | VARCHAR(50) | 否 | - | 分类 |
| status | ENUM | 否 | ACTIVE | 模板状态 |
| createdAt | TIMESTAMP | 否 | now() | 创建时间 |
| updatedAt | TIMESTAMP | 否 | now() | 更新时间 |
| createdBy | VARCHAR(200) | 否 | - | 创建人 |
| items | List\<InspectionItem\> | - | - | 检查项列表（@Transient，非持久化） |

**枚举定义**：

| 枚举 | 值 | 中文 |
|------|-----|------|
| TemplateStatus | ACTIVE | 启用 |
| | INACTIVE | 停用 |

### 2.6 InspectionItem（巡检项）

**表名**: `ops_inspection_item`

| 字段 | 类型 | 必填 | 默认值 | 说明 |
|------|------|------|--------|------|
| id | UUID | 是 | 自动生成 | 主键 |
| templateId | UUID | 是 | - | 所属模板ID |
| itemName | VARCHAR(200) | 是 | - | 检查项名称 |
| description | VARCHAR(2000) | 否 | - | 描述 |
| checkMethod | VARCHAR(2000) | 否 | - | 检查方法 |
| standard | VARCHAR(2000) | 否 | - | 检查标准 |
| isMandatory | BOOLEAN | 否 | true | 是否必检 |
| isNormalRequired | BOOLEAN | 否 | true | 是否需要正常判定 |
| sortOrder | INTEGER | 否 | 0 | 排序序号 |
| createdAt | TIMESTAMP | 否 | now() | 创建时间 |

### 2.7 实体关系图

```
MaintenancePlan ──1:N──> MaintenanceTask
       │                      │
       │ planId               │ equipmentId
       ▼                      ▼
  WorkOrder ──1:N──> WorkOrderItem
       │
       │ (关联)
       ▼
InspectionTemplate ──1:N──> InspectionItem
```

**关系说明**：

- WorkOrder.planId → MaintenancePlan.id（工单可关联维保计划）
- WorkOrderItem.workOrderId → WorkOrder.id（工单明细属于工单）
- MaintenanceTask.planId → MaintenancePlan.id（维保任务由计划触发）
- InspectionItem.templateId → InspectionTemplate.id（检查项属于模板）
- WorkOrder 与 MaintenanceTask 为独立实体，无直接外键关联

---

## 三、API 接口设计

### 3.1 WorkOrderController

**基础路径**: `/api/wo/work-orders`

| 方法 | 路径 | 说明 | 请求体 | 响应 |
|------|------|------|--------|------|
| POST | / | 创建工单 | WorkOrder | WorkOrder |
| GET | / | 查询工单列表 | QueryParams | List\<WorkOrder\> |
| GET | /{id} | 获取工单详情 | - | WorkOrder |
| PUT | /{id} | 更新工单 | WorkOrder | WorkOrder |
| DELETE | /{id} | 删除工单 | - | Void |
| POST | /{id}/assign | 派单 | AssignRequest | WorkOrder |
| POST | /{id}/start | 开始执行 | - | WorkOrder |
| POST | /{id}/complete | 完成工单 | WorkOrder | WorkOrder |
| POST | /{id}/verify | 验收工单 | VerifyRequest | WorkOrder |
| POST | /{id}/cancel | 取消工单 | - | WorkOrder |
| GET | /stats | 工单统计 | - | WorkOrderStatsDTO |
| GET | /{id}/items | 获取工单明细 | - | List\<WorkOrderItem\> |
| POST | /{id}/items | 批量添加工单明细 | List\<WorkOrderItem\> | WorkOrder |

**查询参数**（GET /）：

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| projectId | UUID | 否 | 按项目筛选 |
| equipmentId | UUID | 否 | 按设备筛选 |
| source | Enum | 否 | 按来源筛选 |
| type | Enum | 否 | 按类型筛选 |
| status | Enum | 否 | 按状态筛选 |
| assignedTo | String | 否 | 按负责人筛选 |

> 注意：查询参数互斥，按优先级 projectId > equipmentId > source > type > status > assignedTo 依次判断

**请求体定义**：

```java
// 派单请求
AssignRequest {
    String assignedTo;       // 负责人
    String assignedVendor;   // 服务商
    LocalDate assignedDate;  // 派单日期
}

// 验收请求
VerifyRequest {
    String verifiedBy;  // 验收人
    String remark;      // 备注
    Integer rating;     // 评分（1-5）
}
```

**WorkOrderStatsDTO**：

| 字段 | 类型 | 说明 |
|------|------|------|
| total | long | 工单总数 |
| pending | long | 待分配数 |
| assigned | long | 已派单数 |
| inProgress | long | 执行中数 |
| completed | long | 已完成数 |
| verified | long | 已验收数 |
| cancelled | long | 已取消数 |
| completedToday | long | 今日完成数 |
| createdToday | long | 今日创建数 |
| overdue | long | 逾期数 |
| avgCompleteHours | BigDecimal | 平均完成工时 |
| avgRating | BigDecimal | 平均评分 |
| bySource | Map\<String, Long\> | 按来源分布 |
| byType | Map\<String, Long\> | 按类型分布 |
| byPriority | Map\<String, Long\> | 按优先级分布 |

### 3.2 MaintenanceTaskController

**基础路径**: `/api/ops/maintenance-tasks`

| 方法 | 路径 | 说明 | 请求体 | 响应 |
|------|------|------|--------|------|
| POST | / | 创建维保任务 | MaintenanceTask | MaintenanceTask |
| GET | / | 查询维保任务列表 | QueryParams | List\<MaintenanceTask\> |
| GET | /{id} | 获取任务详情 | - | MaintenanceTask |
| PUT | /{id} | 更新任务 | MaintenanceTask | MaintenanceTask |
| DELETE | /{id} | 删除任务 | - | Void |
| POST | /{id}/assign | 分配任务 | AssignRequest | MaintenanceTask |
| POST | /{id}/start | 开始执行 | - | MaintenanceTask |
| POST | /{id}/complete | 完成任务（简版） | CompleteRequest | MaintenanceTask |
| POST | /{id}/complete-details | 完成任务（详版） | MaintenanceTask | MaintenanceTask |
| POST | /{id}/verify | 验收任务 | VerifyRequest | MaintenanceTask |
| POST | /{id}/cancel | 取消任务 | - | MaintenanceTask |
| POST | /{id}/rate | 评分 | rating (query) | MaintenanceTask |
| GET | /stats | 任务统计 | - | MaintenanceTaskStatsDTO |

**查询参数**（GET /）：

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| equipmentId | UUID | 否 | 按设备筛选 |
| planId | UUID | 否 | 按计划筛选 |
| status | Enum | 否 | 按状态筛选 |
| priority | Enum | 否 | 按优先级筛选 |
| assignedTo | String | 否 | 按负责人筛选 |
| overdueDate | LocalDate | 否 | 逾期截止日期 |

> 同样互斥优先级：equipmentId > planId > status > priority > assignedTo > overdueDate

**请求体定义**：

```java
// 分配请求
AssignRequest {
    String assignedTo;       // 负责人
    LocalDate assignedDate;  // 派单日期
}

// 完成请求（简版）
CompleteRequest {
    String result;            // 处理结果
    BigDecimal actualHours;   // 实际工时
    BigDecimal cost;          // 总费用
    String completedBy;       // 完成人
}

// 验收请求
VerifyRequest {
    String verifiedBy;  // 验收人
    String remark;      // 备注
    Integer rating;     // 评分
}
```

**MaintenanceTaskStatsDTO**：

| 字段 | 类型 | 说明 |
|------|------|------|
| total | long | 任务总数 |
| pending | long | 待分配数 |
| assigned | long | 已派单数 |
| inProgress | long | 执行中数 |
| completed | long | 已完成数 |
| verified | long | 已验收数 |
| cancelled | long | 已取消数 |
| completedToday | long | 今日完成数 |
| createdToday | long | 今日创建数 |
| overdue | long | 逾期数 |
| avgCompleteHours | BigDecimal | 平均完成工时 |
| avgRating | BigDecimal | 平均评分 |
| byPriority | Map\<String, Long\> | 按优先级分布 |
| byTriggerType | Map\<String, Long\> | 按触发类型分布 |
| totalLaborCost | BigDecimal | 人工费总计 |
| totalPartsCost | BigDecimal | 备件费总计 |
| totalCost | BigDecimal | 费用总计 |

### 3.3 前端独立 API（无后端 Controller 对应）

以下前端 API 存在但后端无对应 Controller 实现：

| 前端文件 | API 路径 | 说明 |
|----------|----------|------|
| maintenance-plan.ts | /api/mdm/maintenance-plans | 维保计划 CRUD（归属 MDM 域） |
| maintenance.ts | /api/ops/maintenance-plans | 维保计划 CRUD（另一套，含 accept 操作） |
| maintenance.ts | /api/ops/maintenance-tasks | 维保任务（含 accept 操作，状态含 ACCEPTED） |
| inspection-template.ts | /api/ops/inspection-templates | 巡检模板 CRUD |
| inspection-item.ts | /api/mdm/inspection-items | 巡检标准项 CRUD（归属 MDM 域） |
| inspection-record.ts | /api/mdm/inspection-records | 巡检记录 CRUD（归属 MDM 域） |

---

## 四、业务规则

### 4.1 工单状态机

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

特殊状态:
- CANCELLED (已取消): PENDING/ASSIGNED/IN_PROGRESS 可转入
```

**状态流转规则**：

| 当前状态 | 允许操作 | 下一状态 | 前置条件 | 自动处理 |
|---------|---------|---------|---------|---------|
| PENDING | 派单 | ASSIGNED | - | 设置 assignedTo/assignedVendor/assignedDate |
| ASSIGNED | 开始执行 | IN_PROGRESS | - | 设置 actualStart = now() |
| IN_PROGRESS | 完成 | COMPLETED | - | 设置 actualEnd = now()，自动计算 actualHours |
| COMPLETED | 验收 | VERIFIED | - | 设置 verifiedBy/verifiedDate/rating |
| PENDING/ASSIGNED/IN_PROGRESS | 取消 | CANCELLED | - | - |
| COMPLETED/VERIFIED | 取消 | ❌ 不允许 | - | 抛出异常"无法取消已完成的工单" |

**工单编号生成规则**：`WO-YYYYMMDD-XXXX`（4位序号，按日期递增）

**完成工单自动计算工时**：

```java
actualHours = Duration.between(actualStart, actualEnd).toMinutes() / 60.0
```

### 4.2 维保任务状态机

```
┌─────────────┐
│   PENDING   │ ← 创建任务（默认状态）
│   (待分配)   │
└──────┬──────┘
       │ 分配 (assign)
       ▼
┌─────────────┐
│  ASSIGNED   │ ← 指定负责人
│   (已派单)   │
└──────┬──────┘
       │ 开始执行 (start)
       ▼
┌─────────────┐
│ IN_PROGRESS │ ← 记录实际开始时间
│   (执行中)   │
└──────┬──────┘
       │ 完成 (complete / complete-details)
       ▼
┌─────────────┐
│  COMPLETED  │ ← 记录执行详情/费用/备件
│   (已完成)   │
└──────┬──────┘
       │ 验收 (verify)
       ▼
┌─────────────┐
│  VERIFIED   │ ← 记录验收人/评分
│   (已验收)   │
└─────────────┘

特殊状态:
- CANCELLED (已取消): PENDING/ASSIGNED/IN_PROGRESS 可转入
```

**与工单状态机的差异**：

| 差异点 | WorkOrder | MaintenanceTask |
|--------|-----------|-----------------|
| 完成方式 | 仅一种 complete | 两种：complete（简版）+ complete-details（详版） |
| 评分方式 | 验收时评分 | 验收时评分 + 独立 rate 接口 |
| 取消条件 | COMPLETED/VERIFIED 不可取消 | 同 |
| 删除行为 | 物理删除 | 逻辑删除（设为 CANCELLED） |
| 完成后联动 | 无 | 自动更新设备维保记录（maintenanceVendor/nextInspectionDate） |

**任务编号生成规则**：`EQ-YYYYMMDD-XXXX`（4位序号，按日期递增）

### 4.3 维保任务触发机制

| 触发类型 | 枚举值 | 说明 | 优先级自动判定规则 |
|---------|--------|------|-------------------|
| 计划触发 | PLAN | 由维保计划周期性触发 | MEDIUM |
| 巡检触发 | INSPECTION | 巡检发现异常时触发 | HIGH |
| 故障触发 | FAULT | 设备故障时触发 | HIGH（含紧急关键词时 URGENT） |
| 手动创建 | MANUAL | 人工手动创建 | MEDIUM |

**自动优先级判定规则**（MaintenanceTaskServiceImpl.autoDeterminePriority）：

```
1. 紧急维修类型(EMERGENCY) → URGENT
2. 故障触发(FAULT) + 紧急关键词 → URGENT
   紧急关键词: 困人/漏水/停电/火灾/爆炸/漏电/冒烟/故障停机
3. 故障触发(FAULT) 无紧急关键词 → HIGH
4. 巡检触发(INSPECTION) → HIGH
5. 计划触发(PLAN) → MEDIUM
6. 其他 → MEDIUM
```

### 4.4 维保计划管理规则

| 规则 | 说明 |
|------|------|
| 计划状态 | ACTIVE（启用）/ INACTIVE（停用）/ SUSPENDED（暂停） |
| 删除行为 | 逻辑删除，将状态设为 INACTIVE |
| 周期调度 | 通过 cycleDays 计算下次执行日期（nextDate） |
| 计划类型 | PREVENTIVE（预防性）/ CORRECTIVE（纠正性） |

### 4.5 巡检模板管理规则

| 规则 | 说明 |
|------|------|
| 模板状态 | ACTIVE（启用）/ INACTIVE（停用） |
| 检查项关联 | InspectionItem 通过 templateId 关联模板 |
| 必检项 | isMandatory = true 的检查项不可跳过 |
| 正常判定 | isNormalRequired = true 的检查项需要判定正常/异常 |
| 排序 | 通过 sortOrder 控制检查项顺序 |

### 4.6 工单明细管理规则

| 规则 | 说明 |
|------|------|
| 明细类型 | PART（备件）/ INSPECTION_ITEM（巡检项）/ CHECKPOINT（检查点） |
| 批量添加 | 支持批量添加，受 BatchOperationValidator 限制 |
| 费用计算 | 前端计算：totalPrice = quantity × unitPrice，partsCost = Σ totalPrice |
| 总费用 | totalCost = laborCost + partsCost |

### 4.7 维保任务完成后联动

维保任务完成（completeTaskWithDetails）时自动更新设备信息：

```
1. 更新设备维保商: equipment.maintenanceVendor = task.assignedVendor
2. 更新下次巡检日期（仅预防性维护）:
   equipment.nextInspectionDate = now() + equipment.inspectionCycle
   默认周期: 30天
3. 异常容错: 更新设备失败不影响工单完成
```

---

## 五、前端操作流程

### 5.1 工单管理（WorkOrder.vue）

**页面路径**: /ops/work-order

**操作流程**：

```
1. 选择项目 → 加载工单列表
2. 筛选: 项目/来源/类型/状态/优先级/关键词
3. 查看统计卡片: 总工单/待分配/执行中/今日完成/逾期/平均评分
4. 工单操作:
   ├─ 新建工单 → 填写来源/类型/优先级/标题/描述/负责人/服务商
   ├─ 查看详情 → 抽屉展示: 基本信息/问题描述/派单信息/执行信息/工单项/费用/验收
   ├─ 编辑工单 → 修改基本信息
   ├─ 派单 → 指定负责人/服务商/派单日期（PENDING → ASSIGNED）
   ├─ 开始执行 → 确认弹窗（ASSIGNED → IN_PROGRESS）
   ├─ 完成工单 → 填写工时/故障原因/解决方案/结果/工单项/费用（IN_PROGRESS → COMPLETED）
   ├─ 验收工单 → 填写验收人/评分/备注（COMPLETED → VERIFIED）
   ├─ 取消工单 → 确认弹窗（PENDING/ASSIGNED/IN_PROGRESS → CANCELLED）
   └─ 删除工单 → 确认弹窗
```

**完成工单时的工单项录入**：

```
添加工单项:
  ├─ 选择类型: 备件/巡检项/检查点
  ├─ 输入名称
  ├─ 输入数量 + 单价 → 自动计算 totalPrice
  └─ 自动汇总: partsCost = Σ(各工单项totalPrice)
                 totalCost = laborCost + partsCost
```

**前端状态颜色映射**：

| 状态 | 颜色 | 优先级 | 颜色 |
|------|------|--------|------|
| PENDING | default (灰) | LOW | green |
| ASSIGNED | blue | MEDIUM | blue |
| IN_PROGRESS | orange | HIGH | orange |
| COMPLETED | green | URGENT | red |
| VERIFIED | cyan | | |
| CANCELLED | red | | |

### 5.2 维保计划（PlanList.vue）

**页面路径**: /maintenance/plans

> 注意：此页面使用 `maintenance.ts` API（/api/ops/maintenance-plans），与后端 MaintenancePlan 实体对应的是 `maintenance-plan.ts` API（/api/mdm/maintenance-plans），存在两套前端实现

**操作流程**：

```
1. 选择项目 → 加载维保计划列表
2. 筛选: 项目/触发类型
3. 计划操作:
   ├─ 新建计划 → 填写名称/项目/触发类型/Cron表达式/描述/启用状态
   ├─ 编辑计划 → 修改计划信息
   └─ 停用计划 → 确认弹窗（逻辑删除）
```

**前端触发类型**（与后端不一致）：

| 前端枚举 | 中文 | 后端枚举 | 差异 |
|---------|------|---------|------|
| MANUAL | 手动 | - | 前端独有 |
| SCHEDULED | 定时 | - | 前端独有 |
| AUTOMATIC | 自动 | - | 前端独有 |
| - | - | PLAN | 后端独有 |
| - | - | INSPECTION | 后端独有 |
| - | - | FAULT | 后端独有 |
| - | - | MANUAL | 后端有但含义不同 |

### 5.3 维保任务（TaskList.vue）

**页面路径**: /maintenance/tasks

> 注意：此页面使用 `maintenance.ts` API，状态包含 ACCEPTED，与后端 MaintenanceTaskController 的6状态不一致

**操作流程**：

```
1. 选择项目 → 加载维保任务列表
2. 筛选: 项目/状态/负责人
3. 任务操作:
   ├─ 接受任务 → PENDING → ACCEPTED（前端独有状态）
   ├─ 开始任务 → ACCEPTED → IN_PROGRESS
   ├─ 完成任务 → 弹窗输入完成备注 → IN_PROGRESS → COMPLETED
   └─ 取消任务 → 确认弹窗
```

**前端状态映射**（与后端不一致）：

| 前端状态 | 中文 | 后端状态 | 差异 |
|---------|------|---------|------|
| PENDING | 待接受 | PENDING (待分配) | 含义不同 |
| ACCEPTED | 已接受 | - | 前端独有 |
| IN_PROGRESS | 进行中 | IN_PROGRESS | 一致 |
| COMPLETED | 已完成 | COMPLETED | 一致 |
| CANCELLED | 已取消 | CANCELLED | 一致 |
| - | - | ASSIGNED | 后端独有 |
| - | - | VERIFIED | 后端独有 |

### 5.4 点检模板管理（TemplateList.vue）

**页面路径**: /inspection/templates

**操作流程**：

```
1. 选择项目 → 加载模板列表
2. 模板操作:
   ├─ 新建模板 → 填写名称/设备类型/项目/启用状态 + 添加点检项目
   ├─ 编辑模板 → 修改模板信息 + 编辑点检项目
   ├─ 复制模板 → 创建副本（名称加"_副本"后缀）
   └─ 删除模板 → 确认弹窗

添加点检项目:
  ├─ 输入项目名称
  ├─ 输入检查方法
  ├─ 输入检查标准
  ├─ 设置是否必检
  └─ 添加到列表
```

**前端设备类型选项**（中文，与后端 category 字段不一致）：

电梯/消防设备/空调/给排水/配电/安防/其他

### 5.5 前端页面与 API 对照表

| 页面 | 前端文件 | API 文件 | 后端 Controller | API 基础路径 |
|------|---------|----------|----------------|-------------|
| 工单管理 | WorkOrder.vue | work-order.ts | WorkOrderController | /api/wo/work-orders |
| 维保计划 | PlanList.vue | maintenance.ts | ❌ 无对应 | /api/ops/maintenance-plans |
| 维保任务 | TaskList.vue | maintenance.ts | MaintenanceTaskController | /api/ops/maintenance-tasks |
| 点检模板 | TemplateList.vue | inspection-template.ts | ❌ 无对应 | /api/ops/inspection-templates |

---

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

### 6.1 状态机差异（核心差异）

| 对比项 | 需求文档 | 实际实现 | 差异分析 |
|--------|----------|----------|----------|
| **工单初始状态** | CREATED（已创建） | PENDING（待分配） | 实现简化，合并创建与待分配 |
| **接单状态** | ACCEPTED（已接单） | ❌ 不存在 | 实现中 ASSIGNED 直接进入 IN_PROGRESS，省略接单环节 |
| **关闭状态** | CLOSED（已关闭） | ❌ 不存在 | 实现用 VERIFIED（已验收）替代关闭 |
| **验收状态** | ❌ 不存在 | VERIFIED（已验收） | 实现新增，强调验收确认环节 |
| **挂起状态** | SUSPENDED（已挂起） | ❌ 不存在 | 实现未支持挂起/恢复 |
| **退回状态** | RETURNED（已退回） | ❌ 不存在 | 实现未支持退回重分配 |
| **取消状态** | ❌ 未提及 | CANCELLED（已取消） | 实现新增，支持工单取消 |

**状态机对比图**：

```
需求文档:  CREATED → ASSIGNED → ACCEPTED → IN_PROGRESS → COMPLETED → CLOSED
           + SUSPENDED（任意状态可挂起）
           + RETURNED（ASSIGNED 可退回）

实际实现:  PENDING → ASSIGNED → IN_PROGRESS → COMPLETED → VERIFIED
           + CANCELLED（PENDING/ASSIGNED/IN_PROGRESS 可取消）
```

### 6.2 实体差异

| 对比项 | 需求文档 | 实际实现 | 差异分析 |
|--------|----------|----------|----------|
| **WorkOrderFlow** | 有（工单流转记录） | ❌ 不存在 | 实现未记录流转历史 |
| **NotificationChannel** | 有（通知渠道） | ❌ 不存在 | 消息通知系统未实现 |
| **NotificationTemplate** | 有（消息模板） | ❌ 不存在 | 消息通知系统未实现 |
| **NotificationRule** | 有（通知规则） | ❌ 不存在 | 消息通知系统未实现 |
| **NotificationHistory** | 有（通知历史） | ❌ 不存在 | 消息通知系统未实现 |
| **WorkOrderItem** | ❌ 不存在 | 有（工单明细） | 实现新增，支持备件/巡检项/检查点 |
| **MaintenancePlan** | ❌ 不存在 | 有（维保计划） | 实现新增，支持周期性维保调度 |
| **MaintenanceTask** | ❌ 不存在 | 有（维保任务） | 实现新增，独立于 WorkOrder 的维保工单 |
| **InspectionTemplate** | ❌ 不存在 | 有（巡检模板） | 实现新增，支持点检模板管理 |
| **InspectionItem** | ❌ 不存在 | 有（巡检项） | 实现新增，模板下的检查项 |

### 6.3 字段差异（WorkOrder）

| 字段 | 需求文档 | 实际实现 | 差异分析 |
|------|----------|----------|----------|
| orderNo | WO2024021000001 | workNo: WO-YYYYMMDD-XXXX | 编号格式不同，实现用连字符分隔 |
| orderType | REPAIR/COMPLAINT/CLEANING/SECURITY/OTHER | type: REPAIR/INSPECTION/SECURITY/CLEANING/PROPERTY/CONSULTATION | 枚举值完全不同 |
| source | APP/PHONE/INSPECTION/IOT/SYSTEM | OWNER/MAINTENANCE/INSPECTION/FAULT/REGULATORY/MANUAL | 枚举值完全不同 |
| reporterId/reporterName/reporterPhone/reporterAddress | 有 | ❌ 不存在 | 实现无报修人信息 |
| assigneeId/assigneeName | UUID引用 | assignedTo: String | 实现用字符串而非用户ID引用 |
| acceptedAt/startedAt/completedAt/closedAt | 有 | actualStart/actualEnd/completedDate/verifiedDate | 字段名和粒度不同 |
| materialCost | 有 | partsCost | 字段名不同 |
| resultDescription | 有 | result + faultCause + solution | 实现拆分为3个字段 |
| satisfactionScore/satisfactionComment | 有 | rating + remark | 实现简化，无评论字段 |
| images/attachments | String | photos: JSONB (List\<String\>) | 实现用JSONB数组 |
| attributes | JSONB | ❌ 不存在 | 实现无扩展属性 |
| spaceNodeId | 有 | spaceId | 字段名不同 |
| planId/triggerType | ❌ 不存在 | 有 | 实现新增，关联维保计划 |
| assignedVendor | ❌ 不存在 | 有 | 实现新增，支持服务商 |
| laborCost/partsCost/totalCost | ❌ 不存在 | 有 | 实现新增，费用明细 |
| signature | ❌ 不存在 | 有 | 实现新增，签名确认 |

### 6.4 API 差异

| 对比项 | 需求文档 | 实际实现 | 差异分析 |
|--------|----------|----------|----------|
| API 版本 | /api/v1/ops/work-orders | /api/wo/work-orders | 路径不同，实现无版本号 |
| 分页查询 | Page\<WorkOrderVO\> | List\<WorkOrder\> | 实现无分页，全量返回 |
| 接单接口 | POST /{id}/accept | ❌ 不存在 | 无 ACCEPTED 状态 |
| 关闭接口 | POST /{id}/close | ❌ 不存在 | 用 verify 替代 |
| 挂起/恢复 | POST /{id}/suspend, /{id}/resume | ❌ 不存在 | 未实现 |
| 退回 | ❌ 不存在 | ❌ 不存在 | 需求有但实现无 |
| 流转记录 | GET /{id}/flows | ❌ 不存在 | 未实现 WorkOrderFlow |
| 通知 API | 完整的渠道/模板/规则/历史 | ❌ 不存在 | 消息通知系统未实现 |
| 统计 API | 独立 Controller，多维度 | GET /stats（嵌入工单 Controller） | 实现简化 |
| 工单明细 | ❌ 不存在 | GET/POST /{id}/items | 实现新增 |
| 维保任务 API | ❌ 不存在 | 完整的 CRUD + 状态流转 | 实现新增 |

### 6.5 业务规则差异

| 对比项 | 需求文档 | 实际实现 | 差异分析 |
|--------|----------|----------|----------|
| 工单编号格式 | WO + yyyyMMdd + 5位序号 | WO-YYYYMMDD-XXXX（4位） | 格式不同 |
| 通知触发 | 工单状态变更自动触发通知 | ❌ 无通知 | 消息通知未实现 |
| SLA 监控 | 提及但未实现 | ❌ 未实现 | 均未实现 |
| 智能派单 | 提及但未实现 | ❌ 未实现 | 均未实现 |
| 维保优先级自动判定 | ❌ 未提及 | 有（基于触发类型+关键词） | 实现新增 |
| 设备联动更新 | ❌ 未提及 | 有（完成维保后更新设备记录） | 实现新增 |
| 维保任务双完成接口 | ❌ 未提及 | complete + complete-details | 实现新增，简版/详版 |
| 删除策略 | 未明确 | WorkOrder 物理删除，MaintenanceTask 逻辑删除 | 不一致 |

### 6.6 前端实现差异

| 对比项 | 需求文档 | 实际实现 | 差异分析 |
|--------|----------|----------|----------|
| 维保计划 API | 单一 | 两套（maintenance.ts + maintenance-plan.ts） | 前端分裂 |
| 维保计划触发类型 | - | MANUAL/SCHEDULED/AUTOMATIC vs PLAN/INSPECTION/FAULT/MANUAL | 前后端不一致 |
| 维保任务状态 | - | 前端含 ACCEPTED，后端含 ASSIGNED/VERIFIED | 前后端不一致 |
| 巡检模板 | ❌ 未提及 | 有（inspection-template.ts + TemplateList.vue） | 实现新增 |
| 巡检标准项 | ❌ 未提及 | 有（inspection-item.ts，归属 MDM 域） | 实现新增 |
| 巡检记录 | ❌ 未提及 | 有（inspection-record.ts，归属 MDM 域） | 实现新增 |

### 6.7 差异总结

| 类别 | 需求文档有/实现无 | 实现有/需求文档无 | 说明 |
|------|-----------------|-----------------|------|
| 状态 | CREATED, ACCEPTED, CLOSED, SUSPENDED, RETURNED | VERIFIED, CANCELLED | 状态机完全重构 |
| 实体 | WorkOrderFlow, NotificationChannel/Template/Rule/History | WorkOrderItem, MaintenancePlan/Task, InspectionTemplate/Item | 实体体系完全不同 |
| 功能 | 消息通知系统, 工单流转记录 | 维保计划/任务, 巡检模板, 工单明细 | 功能重心偏移 |
| 字段 | 报修人信息, 扩展属性 | 服务商, 费用明细, 签名, 触发类型 | 字段侧重不同 |

> **核心结论**: 实际实现与需求文档是两套不同的设计方案。需求文档侧重"运营调度+消息通知"，实际实现侧重"运维工单+维保管理+巡检模板"。状态机从7状态简化为6状态，去掉了接单/挂起/退回环节，新增了验收/取消环节。消息通知系统完全未实现，但新增了维保计划/任务/巡检模板等需求文档未涵盖的功能。
