ether-docs/_archive/domains-old/02-OPERATIONS.md

1080 lines
33 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 运营调度领域技术方案
**领域编号**: 4.2
**微服务**: ether-ops
**最后更新**: 2026-04-26
> **更新记录**:
> - 2026-04-26: 反向同步实际代码实现到文档。主要变更工单状态机更新为PENDING→ASSIGNED→IN_PROGRESS→COMPLETED→VERIFIED/CANCELLED标注TODO: 增加SUSPENDED/RETURNED工单类型枚举更新REPAIR/INSPECTION/SECURITY/CLEANING/PROPERTY/CONSULTATION工单来源枚举更新OWNER/MAINTENANCE/INSPECTION/FAULT/REGULATORY/MANUAL新增实体WorkOrderItem/MaintenancePlan/MaintenanceTask/InspectionTemplate/InspectionItem新增字段planId/triggerType/assignedVendor/laborCost/partsCost/totalCost/signature字段拆分resultDescription→result+faultCause+solution新增业务规则优先级自动判定/设备联动更新/维保任务双完成接口API路径从/api/v1/ops改为/api/wo标注TODO: 工单列表需改为分页查询。
---
## 一、领域概述
### 1.1 领域职责
运营调度领域是 Ether 平台的核心业务领域,负责管理:
- 综合工单管理(创建、分配、处理、关闭)
- 工单流转记录与状态机
- 消息通知系统(模板、规则、渠道)
- 工单统计与分析
### 1.2 核心概念
| 概念 | 说明 | 对应实体 |
|------|------|----------|
| **工单** | 综合业务单据,支持多种类型 | WorkOrder |
| **工单明细** | 工单下的处理项目清单 | WorkOrderItem |
| **工单流转** | 工单状态变更记录 | WorkOrderFlow |
| **维保计划** | 定期保养计划 | MaintenancePlan |
| **维保任务** | 维保执行工单 | MaintenanceTask |
| **巡检模板** | 巡检检查项模板 | InspectionTemplate |
| **巡检项目** | 巡检模板中的检查项 | InspectionItem |
| **通知渠道** | 消息发送通道 | NotificationChannel |
| **通知模板** | 消息内容模板 | NotificationTemplate |
| **通知规则** | 触发条件和发送策略 | NotificationRule |
| **通知历史** | 已发送消息记录 | NotificationHistory |
---
## 二、领域模型
### 2.1 聚合根设计
#### WorkOrder综合工单
```java
@Entity
@Table(name = "ops_work_order")
@Data
public class WorkOrder {
@Id
private UUID id;
private UUID projectId;
private String orderNo; // 工单编号: WO2024021000001
// 工单类型
private WorkOrderType orderType; // REPAIR/INSPECTION/SECURITY/CLEANING/PROPERTY/CONSULTATION
private WorkOrderStatus status; // 状态机
private WorkOrderPriority priority; // URGENT/HIGH/MEDIUM/LOW
private WorkOrderSource source; // OWNER/MAINTENANCE/INSPECTION/FAULT/REGULATORY/MANUAL
// 基本信息
private String title;
private String description;
// 报修人信息
private UUID reporterId;
private String reporterName;
private String reporterPhone;
private String reporterAddress;
// 关联信息
private UUID spaceNodeId; // 关联空间
private UUID equipmentId; // 关联设备
// 维保关联(新增)
private UUID planId; // 关联维保计划ID
private String triggerType; // 触发类型: MANUAL/AUTO/SCHEDULED
// 处理人信息
private UUID assigneeId;
private String assigneeName;
private UUID assignedVendor; // 指派供应商ID新增
private LocalDateTime assignedAt;
private LocalDateTime acceptedAt;
private LocalDateTime startedAt;
private LocalDateTime completedAt;
private LocalDateTime closedAt;
// 费用(拆分细化)
private BigDecimal laborCost; // 人工费(新增)
private BigDecimal partsCost; // 材料费(新增)
private BigDecimal totalCost; // 总费用新增替代原actualCost
// 结果拆分原resultDescription → result + faultCause + solution
private String result; // 处理结果
private String faultCause; // 故障原因
private String solution; // 解决方案
private Integer satisfactionScore;
private String satisfactionComment;
// 签名确认(新增)
private String signature; // 签名图片URL
// 附件
private String images;
private String attachments;
// 扩展属性
private String attributes;
// 审计字段
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
private UUID createdBy;
}
```
**工单类型枚举(更新)**:
```java
public enum WorkOrderType {
REPAIR("报修"),
INSPECTION("巡检"),
SECURITY("安全"),
CLEANING("保洁"),
PROPERTY("物业"),
CONSULTATION("咨询");
}
```
**工单来源枚举(更新)**:
```java
public enum WorkOrderSource {
OWNER("业主报修"),
MAINTENANCE("维保触发"),
INSPECTION("巡检发现"),
FAULT("设备故障"),
REGULATORY("监管要求"),
MANUAL("手动创建");
}
```
**业务规则**:
- orderNo 自动生成,格式: WO + yyyyMMdd + 5位序号
- 状态流转必须通过合法的业务操作
- 关闭工单时必须填写处理结果
- **优先级自动判定**新增根据工单类型和来源自动设置优先级如安全类默认HIGH设备故障默认HIGH
- **设备联动更新**(新增):工单完成时自动更新关联设备状态
#### WorkOrderFlow工单流转记录
```java
@Entity
@Table(name = "ops_work_order_flow")
@Data
public class WorkOrderFlow {
@Id
private UUID id;
private UUID workOrderId;
// 流转信息
private WorkOrderStatus fromStatus;
private WorkOrderStatus toStatus;
private String action; // 操作: ASSIGN/START/COMPLETE/VERIFY/CANCEL
// 操作人
private UUID operatorId;
private String operatorName;
private LocalDateTime operateTime;
// 备注
private String remark;
// 附件
private String images;
}
```
#### WorkOrderItem工单明细新增
```java
@Entity
@Table(name = "ops_work_order_item")
@Data
public class WorkOrderItem {
@Id
private UUID id;
private UUID workOrderId;
private UUID projectId;
private String itemName; // 明细名称
private String itemType; // 明细类型
private String description; // 明细描述
private Integer quantity; // 数量
private BigDecimal unitPrice; // 单价
private BigDecimal amount; // 金额
private String remark; // 备注
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
```
#### MaintenancePlan维保计划新增
```java
@Entity
@Table(name = "ops_maintenance_plan")
@Data
public class MaintenancePlan {
@Id
private UUID id;
private UUID projectId;
private UUID equipmentId;
private String name;
private MaintenanceType type; // DAILY/WEEKLY/MONTHLY/QUARTERLY/YEARLY
private Integer cycleDays;
private String cronExpression;
private String content;
private String checkItems; // JSON
private UUID maintainerId;
private String maintainerName;
private Integer remindDays;
private Boolean enabled;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
```
#### MaintenanceTask维保任务新增
```java
@Entity
@Table(name = "ops_maintenance_task")
@Data
public class MaintenanceTask {
@Id
private UUID id;
private UUID projectId;
private UUID equipmentId;
private UUID planId;
private String taskCode;
private MaintenanceTaskStatus status; // PENDING/IN_PROGRESS/COMPLETED/CANCELLED
private LocalDate maintenanceDate;
private MaintenanceType type;
private String content;
private UUID maintainerId;
private String maintainerName;
private MaintenanceResult result;
private String remark;
private String images;
private String checkResults; // JSON
private BigDecimal laborCost;
private BigDecimal partsCost;
private BigDecimal totalCost;
private String signature;
private LocalDate nextMaintenanceDate;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
public enum MaintenanceTaskStatus {
PENDING, IN_PROGRESS, COMPLETED, CANCELLED;
}
```
> **维保任务双完成接口**(新增业务规则): 维保任务提供两个完成接口:
> 1. `POST /api/wo/maintenance-tasks/{id}/complete` - 维保人员完成
> 2. `POST /api/wo/maintenance-tasks/{id}/verify` - 主管验证确认
#### InspectionTemplate巡检模板新增
```java
@Entity
@Table(name = "ops_inspection_template")
@Data
public class InspectionTemplate {
@Id
private UUID id;
private UUID projectId;
private String name;
private String description;
private String category; // 模板分类
private Boolean enabled;
@OneToMany(mappedBy = "templateId", fetch = FetchType.LAZY)
private List<InspectionItem> items;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
```
#### InspectionItem巡检项目新增
```java
@Entity
@Table(name = "ops_inspection_item")
@Data
public class InspectionItem {
@Id
private UUID id;
private UUID templateId;
private String itemName; // 检查项名称
private String checkStandard; // 检查标准
private String checkMethod; // 检查方法
private Integer sortOrder; // 排序
private Boolean required; // 是否必检
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
```
### 2.2 状态机设计
```
┌─────────────┐
│ PENDING │ ← 创建工单
│ (待处理) │
└──────┬──────┘
│ 分配
┌─────────────┐
│ ASSIGNED │ ← 分配给处理人
│ (已分配) │
└──────┬──────┘
│ 开始处理
┌─────────────┐
│ IN_PROGRESS │ ← 开始处理
│ (处理中) │
└──────┬──────┘
│ 完成
┌─────────────┐
│ COMPLETED │ ← 处理完成
│ (已完成) │
└──────┬──────┘
│ 验证
┌─────────────┐
│ VERIFIED │ ← 验证通过
│ (已验证) │
└─────────────┘
特殊状态:
- CANCELLED (已取消): PENDING/ASSIGNED状态可转入
```
> **TODO**: 当前状态机缺少 SUSPENDED(已挂起) 和 RETURNED(已退回) 状态,需后续补充:
> - SUSPENDED: 任意状态可转入,可恢复到原状态
> - RETURNED: ASSIGNED状态可转入需重新分配
**状态流转规则**:
| 当前状态 | 允许操作 | 下一状态 | 权限 |
|---------|---------|---------|------|
| PENDING | 分配 | ASSIGNED | 管理员/调度员 |
| ASSIGNED | 开始 | IN_PROGRESS | 被指派人 |
| IN_PROGRESS | 完成 | COMPLETED | 被指派人 |
| COMPLETED | 验证 | VERIFIED | 管理员/创建人 |
| PENDING/ASSIGNED | 取消 | CANCELLED | 管理员 |
---
## 三、消息通知系统
### 3.1 聚合根设计
#### NotificationChannel通知渠道
```java
@Entity
@Table(name = "ops_notification_channel")
@Data
public class NotificationChannel {
@Id
private UUID id;
private UUID projectId;
private String name;
private ChannelType type; // SITE_MESSAGE/SMS/EMAIL/PUSH/WECHAT_WORK
// 配置(JSONB)
private String config; // 渠道配置参数
// SITE_MESSAGE: {}
// SMS: {provider, apiKey, apiSecret, templateCode}
// EMAIL: {host, port, username, password}
// PUSH: {appKey, appSecret}
// WECHAT_WORK: {corpId, agentId, secret}
private Boolean enabled;
private Integer priority; // 优先级,数字越小优先级越高
private Integer dailyLimit; // 日发送限制
private Integer sentToday; // 今日已发送
// 审计字段
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
```
#### NotificationTemplate消息模板
```java
@Entity
@Table(name = "ops_notification_template")
@Data
public class NotificationTemplate {
@Id
private UUID id;
private UUID projectId;
private String name;
private String code; // 模板编码,唯一
// 模板内容
private String titleTemplate;
private String contentTemplate;
// 变量定义
private String variables; // ["orderNo", "title", "assigneeName"]
// 适用渠道
private String channels; // ["SITE_MESSAGE", "SMS"]
// 示例
private String example; // 渲染后的示例
// 审计字段
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
// 模板示例:
// titleTemplate: "新工单通知: {{title}}"
// contentTemplate: "您有一个新的{{orderType}}工单待处理,工单号: {{orderNo}},请尽快处理。"
```
#### NotificationRule通知规则
```java
@Entity
@Table(name = "ops_notification_rule")
@Data
public class NotificationRule {
@Id
private UUID id;
private UUID projectId;
private String name;
private String eventType; // 事件类型: WORK_ORDER_CREATED/ASSIGNED/COMPLETED
// 触发条件(JSONB)
private String conditions; // {"orderType": "REPAIR", "priority": "HIGH"}
// 延迟发送
private Integer delayMinutes; // 延迟分钟数0为立即发送
// 通知配置
private String templateCode; // 关联模板
private String receivers; // 接收人: ["CREATOR", "ASSIGNEE", "MANAGER"]
private String channels; // 通知渠道优先级: ["SITE_MESSAGE", "SMS"]
// 免打扰
private String quietHours; // 免打扰时段: "22:00-08:00"
private Boolean enabled;
// 审计字段
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
```
#### NotificationHistory通知历史
```java
@Entity
@Table(name = "ops_notification_history")
@Data
public class NotificationHistory {
@Id
private UUID id;
private UUID projectId;
// 通知内容
private String title;
private String content;
private String eventType;
// 接收人
private UUID receiverId;
private String receiverName;
private String receiverPhone;
private String receiverEmail;
// 渠道信息
private ChannelType channel;
private String channelMsgId; // 渠道消息ID
// 状态
private NotificationStatus status; // PENDING/SENT/FAILED/READ
private String failReason; // 失败原因
private LocalDateTime sendTime;
private LocalDateTime readTime;
// 关联业务
private String businessType; // WORK_ORDER/INSPECTION/FEE
private String businessId;
// 审计字段
private LocalDateTime createdAt;
}
```
### 3.2 通知事件类型
| 事件类型 | 触发时机 | 默认接收人 | 默认渠道 |
|---------|---------|-----------|---------|
| WORK_ORDER_CREATED | 工单创建 | 创建人 | 站内信 |
| WORK_ORDER_ASSIGNED | 工单分配 | 处理人 | 站内信+推送 |
| WORK_ORDER_ACCEPTED | 工单接单 | 创建人 | 站内信 |
| WORK_ORDER_COMPLETED | 工单完成 | 创建人 | 站内信+推送 |
| WORK_ORDER_CLOSED | 工单关闭 | - | - |
| INSPECTION_TODAY | 当天巡检提醒 | 巡检人 | 站内信+推送 |
| INSPECTION_OVERDUE | 巡检逾期 | 巡检人+管理员 | 站内信+短信 |
| FEE_UPCOMING_DUE | 费用即将到期 | 业主 | 站内信+推送 |
| FEE_OVERDUE | 费用逾期 | 业主 | 站内信+短信 |
### 3.3 通知流程
```
1. 业务事件触发
2. 查询匹配的通知规则
3. 渲染消息模板
4. 确定接收人列表
5. 选择通知渠道
6. 检查免打扰设置
7. 发送消息
8. 记录发送历史
9. 更新站内信未读数
```
---
## 四、工单统计
### 4.1 统计维度
```java
// 工单统计服务
@Service
public class WorkOrderStatisticsService {
// 概览统计
public WorkOrderOverviewVO getOverview(UUID projectId, LocalDate startDate, LocalDate endDate) {
// 工单总数
// 待处理数
// 今日新增
// 今日完成
// 平均处理时长
// 满意度评分
}
// 趋势统计
public List<TrendVO> getTrend(UUID projectId, StatisticsType type, LocalDate startDate, LocalDate endDate) {
// 按日/周/月统计工单量
// 创建趋势
// 完成趋势
}
// 类型分布
public List<DistributionVO> getTypeDistribution(UUID projectId, LocalDate startDate, LocalDate endDate) {
// 按工单类型统计
}
// 处理人排行
public List<RankingVO> getAssigneeRanking(UUID projectId, LocalDate startDate, LocalDate endDate) {
// 处理人工作量排行
// 处理人满意度排行
}
// 超时分析
public List<OvertimeVO> getOvertimeAnalysis(UUID projectId, LocalDate startDate, LocalDate endDate) {
// 超时工单列表
// 超时原因分析
}
}
```
### 4.2 统计指标
| 指标 | 说明 | 计算方式 |
|------|------|---------|
| 工单总数 | 指定时间范围内的工单总数 | COUNT(*) |
| 待处理数 | 状态为CREATED/ASSIGNED/ACCEPTED/IN_PROGRESS的工单数 | COUNT(*) WHERE status IN (...) |
| 今日新增 | 今日创建的工单数 | COUNT(*) WHERE created_at >= today |
| 今日完成 | 今日完成的工单数 | COUNT(*) WHERE completed_at >= today |
| 平均处理时长 | 从创建到完成的平均时间 | AVG(completed_at - created_at) |
| 按时完成率 | 在SLA时间内完成的工单比例 | COUNT(on_time) / COUNT(completed) |
| 满意度评分 | 业主评价的平均分 | AVG(satisfaction_score) |
---
## 五、API 接口
### 5.1 WorkOrder API
> **注意**: API路径已从 `/api/v1/ops` 改为 `/api/wo`。
```java
@RestController
@RequestMapping("/api/wo/work-orders")
@Tag(name = "工单管理")
public class WorkOrderController {
@PostMapping
@Operation(summary = "创建工单")
public Result<WorkOrderVO> create(@RequestBody @Valid WorkOrderCreateRequest request);
@GetMapping("/{id}")
@Operation(summary = "获取工单详情")
public Result<WorkOrderVO> getById(@PathVariable UUID id);
@GetMapping
@Operation(summary = "查询工单列表")
public Result<List<WorkOrderVO>> list(WorkOrderQueryRequest request);
@PutMapping("/{id}")
@Operation(summary = "更新工单")
public Result<WorkOrderVO> update(@PathVariable UUID id,
@RequestBody @Valid WorkOrderUpdateRequest request);
@DeleteMapping("/{id}")
@Operation(summary = "删除工单")
public Result<Void> delete(@PathVariable UUID id);
// 业务操作
@PostMapping("/{id}/assign")
@Operation(summary = "分配工单")
public Result<WorkOrderVO> assign(@PathVariable UUID id,
@RequestBody @Valid WorkOrderAssignRequest request);
@PostMapping("/{id}/start")
@Operation(summary = "开始处理")
public Result<WorkOrderVO> start(@PathVariable UUID id);
@PostMapping("/{id}/complete")
@Operation(summary = "完成工单")
public Result<WorkOrderVO> complete(@PathVariable UUID id,
@RequestBody @Valid WorkOrderCompleteRequest request);
@PostMapping("/{id}/verify")
@Operation(summary = "验证工单")
public Result<WorkOrderVO> verify(@PathVariable UUID id,
@RequestBody @Valid WorkOrderVerifyRequest request);
@PostMapping("/{id}/cancel")
@Operation(summary = "取消工单")
public Result<WorkOrderVO> cancel(@PathVariable UUID id,
@RequestBody WorkOrderCancelRequest request);
// 流转记录
@GetMapping("/{id}/flows")
@Operation(summary = "获取流转记录")
public Result<List<WorkOrderFlowVO>> getFlows(@PathVariable UUID id);
}
```
> **TODO**: 工单列表接口GET /api/wo/work-orders当前返回 List需改为分页查询返回 Page<WorkOrderVO>)。
### 5.2 Notification API
```java
@RestController
@RequestMapping("/api/wo/notifications")
@Tag(name = "消息通知")
public class NotificationController {
// 渠道管理
@PostMapping("/channels")
@Operation(summary = "创建通知渠道")
public Result<NotificationChannelVO> createChannel(@RequestBody @Valid ChannelCreateRequest request);
@GetMapping("/channels")
@Operation(summary = "查询渠道列表")
public Result<List<NotificationChannelVO>> listChannels();
// 模板管理
@PostMapping("/templates")
@Operation(summary = "创建消息模板")
public Result<NotificationTemplateVO> createTemplate(@RequestBody @Valid TemplateCreateRequest request);
@GetMapping("/templates")
@Operation(summary = "查询模板列表")
public Result<List<NotificationTemplateVO>> listTemplates();
// 规则管理
@PostMapping("/rules")
@Operation(summary = "创建通知规则")
public Result<NotificationRuleVO> createRule(@RequestBody @Valid RuleCreateRequest request);
@GetMapping("/rules")
@Operation(summary = "查询规则列表")
public Result<List<NotificationRuleVO>> listRules();
// 消息历史
@GetMapping("/history")
@Operation(summary = "分页查询消息历史")
public Result<Page<NotificationHistoryVO>> pageHistory(NotificationHistoryQueryRequest request);
// 个人消息
@GetMapping("/my")
@Operation(summary = "获取我的消息列表")
public Result<Page<NotificationVO>> getMyNotifications(@RequestParam(required = false) Boolean unread);
@GetMapping("/my/unread-count")
@Operation(summary = "获取未读消息数量")
public Result<Long> getUnreadCount();
@PostMapping("/{id}/read")
@Operation(summary = "标记已读")
public Result<Void> markAsRead(@PathVariable UUID id);
@PostMapping("/read-all")
@Operation(summary = "全部已读")
public Result<Void> markAllAsRead();
}
```
### 5.3 Statistics API
```java
@RestController
@RequestMapping("/api/wo/statistics")
@Tag(name = "工单统计")
public class WorkOrderStatisticsController {
@GetMapping("/overview")
@Operation(summary = "概览统计")
public Result<WorkOrderOverviewVO> getOverview(
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate startDate,
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate);
@GetMapping("/trend")
@Operation(summary = "趋势统计")
public Result<List<TrendVO>> getTrend(
@RequestParam StatisticsType type,
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate startDate,
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate);
@GetMapping("/type-distribution")
@Operation(summary = "类型分布")
public Result<List<DistributionVO>> getTypeDistribution(
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate startDate,
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate);
@GetMapping("/assignee-ranking")
@Operation(summary = "处理人排行")
public Result<List<RankingVO>> getAssigneeRanking(
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate startDate,
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate);
}
```
---
## 六、实现状态与差异
### 6.1 实现状态
| 功能模块 | 实现状态 | 备注 |
|---------|---------|------|
| WorkOrder | 🟢 已实现 | 完整状态机(PENDING→ASSIGNED→IN_PROGRESS→COMPLETED→VERIFIED/CANCELLED) |
| WorkOrderItem | 🟢 已实现 | 工单明细 |
| WorkOrderFlow | 🟢 已实现 | 自动记录流转 |
| MaintenancePlan | 🟢 已实现 | 维保计划 |
| MaintenanceTask | 🟢 已实现 | 维保任务,双完成接口 |
| InspectionTemplate | 🟢 已实现 | 巡检模板 |
| InspectionItem | 🟢 已实现 | 巡检项目 |
| NotificationChannel | 🟢 已实现 | 基础CRUD |
| NotificationTemplate | 🟢 已实现 | 基础CRUD |
| NotificationRule | 🟢 已实现 | 基础CRUD |
| NotificationHistory | 🟢 已实现 | 基础CRUD |
| 工单与通知集成 | 🟢 已实现 | 事件驱动 |
| 工单统计 | 🟢 已实现 | 多维度统计 |
| 优先级自动判定 | 🟢 已实现 | 根据类型/来源自动设置 |
| 设备联动更新 | 🟢 已实现 | 工单完成时更新设备状态 |
| SLA监控 | 🔴 未实现 | 超时预警 |
| 智能派单 | 🔴 未实现 | 自动分配 |
| SUSPENDED/RETURNED状态 | 🔴 未实现 | TODO: 需增加挂起和退回状态 |
| 工单分页查询 | 🔴 未实现 | TODO: 列表接口需改为分页查询 |
### 6.2 与设计方案的差异
| 设计项 | 设计方案 | 现有实现 | 差异分析 |
|--------|----------|----------|----------|
| **工单状态机** | CREATED→ASSIGNED→ACCEPTED→IN_PROGRESS→COMPLETED→CLOSED | PENDING→ASSIGNED→IN_PROGRESS→COMPLETED→VERIFIED/CANCELLED | 已更新:简化流程,增加验证环节 |
| **工单类型** | REPAIR/COMPLAINT/CLEANING/SECURITY/OTHER | REPAIR/INSPECTION/SECURITY/CLEANING/PROPERTY/CONSULTATION | 已更新:更贴合物业场景 |
| **工单来源** | APP/PHONE/INSPECTION/IOT/SYSTEM | OWNER/MAINTENANCE/INSPECTION/FAULT/REGULATORY/MANUAL | 已更新:按业务角色区分 |
| **结果字段** | resultDescription单字段 | result+faultCause+solution三字段 | 已拆分:更细粒度的结果记录 |
| **费用字段** | actualCost/materialCost/laborCost | laborCost/partsCost/totalCost | 已更新:更清晰的费用分类 |
| **通知渠道** | 多渠道支持 | 仅站内信实现 | 其他渠道待扩展 |
| **API路径** | /api/v1/ops | /api/wo | 已更新:路径简化 |
| **巡检归属** | ether-ops | ether-mdm | 领域边界模糊 |
### 6.3 待改进项
| 优先级 | 改进项 | 说明 |
|--------|--------|------|
| P0 | 工单分页查询 | 列表接口需改为分页查询 |
| P0 | 增加SUSPENDED/RETURNED状态 | 挂起和退回是常见业务需求 |
| P1 | 实现SLA监控 | 工单超时预警和自动升级 |
| P2 | 扩展通知渠道 | 短信、邮件、推送渠道 |
| P3 | 智能派单算法 | 基于负载、技能、位置的自动分配 |
---
## 七、数据库表结构
```sql
-- 工单表
CREATE TABLE ops_work_order (
id UUID PRIMARY KEY,
project_id UUID NOT NULL,
order_no VARCHAR(32) NOT NULL,
order_type VARCHAR(20) NOT NULL,
status VARCHAR(20) NOT NULL DEFAULT 'PENDING',
priority VARCHAR(20) NOT NULL DEFAULT 'MEDIUM',
source VARCHAR(20) NOT NULL,
title VARCHAR(200) NOT NULL,
description TEXT,
reporter_id UUID,
reporter_name VARCHAR(100),
reporter_phone VARCHAR(20),
reporter_address VARCHAR(255),
space_node_id UUID,
equipment_id UUID,
plan_id UUID,
trigger_type VARCHAR(20),
assignee_id UUID,
assignee_name VARCHAR(100),
assigned_vendor UUID,
assigned_at TIMESTAMP,
accepted_at TIMESTAMP,
started_at TIMESTAMP,
completed_at TIMESTAMP,
closed_at TIMESTAMP,
labor_cost NUMERIC(12,2),
parts_cost NUMERIC(12,2),
total_cost NUMERIC(12,2),
result TEXT,
fault_cause TEXT,
solution TEXT,
satisfaction_score INTEGER,
satisfaction_comment VARCHAR(500),
signature VARCHAR(255),
images TEXT,
attachments TEXT,
attributes JSONB,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
created_by UUID,
updated_by UUID,
UNIQUE(project_id, order_no)
);
-- 工单明细表(新增)
CREATE TABLE ops_work_order_item (
id UUID PRIMARY KEY,
work_order_id UUID NOT NULL REFERENCES ops_work_order(id),
project_id UUID NOT NULL,
item_name VARCHAR(200) NOT NULL,
item_type VARCHAR(50),
description TEXT,
quantity INTEGER,
unit_price NUMERIC(12,2),
amount NUMERIC(12,2),
remark VARCHAR(500),
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
-- 工单流转表
CREATE TABLE ops_work_order_flow (
id UUID PRIMARY KEY,
work_order_id UUID NOT NULL,
from_status VARCHAR(20),
to_status VARCHAR(20) NOT NULL,
action VARCHAR(50) NOT NULL,
operator_id UUID,
operator_name VARCHAR(100),
operate_time TIMESTAMP NOT NULL DEFAULT NOW(),
remark VARCHAR(500),
images TEXT
);
-- 维保计划表(新增)
CREATE TABLE ops_maintenance_plan (
id UUID PRIMARY KEY,
project_id UUID NOT NULL,
equipment_id UUID NOT NULL,
name VARCHAR(100) NOT NULL,
type VARCHAR(20) NOT NULL,
cycle_days INTEGER,
cron_expression VARCHAR(50),
content TEXT,
check_items JSONB,
maintainer_id UUID,
maintainer_name VARCHAR(100),
remind_days INTEGER DEFAULT 3,
enabled BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
-- 维保任务表(新增)
CREATE TABLE ops_maintenance_task (
id UUID PRIMARY KEY,
project_id UUID NOT NULL,
equipment_id UUID NOT NULL,
plan_id UUID,
task_code VARCHAR(50),
status VARCHAR(20) NOT NULL DEFAULT 'PENDING',
maintenance_date DATE NOT NULL,
type VARCHAR(20) NOT NULL,
content TEXT,
maintainer_id UUID,
maintainer_name VARCHAR(100),
result VARCHAR(20),
remark VARCHAR(500),
images TEXT,
check_results JSONB,
labor_cost NUMERIC(12,2),
parts_cost NUMERIC(12,2),
total_cost NUMERIC(12,2),
signature VARCHAR(255),
next_maintenance_date DATE,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
-- 巡检模板表(新增)
CREATE TABLE ops_inspection_template (
id UUID PRIMARY KEY,
project_id UUID NOT NULL,
name VARCHAR(100) NOT NULL,
description TEXT,
category VARCHAR(50),
enabled BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
-- 巡检项目表(新增)
CREATE TABLE ops_inspection_item (
id UUID PRIMARY KEY,
template_id UUID NOT NULL REFERENCES ops_inspection_template(id),
item_name VARCHAR(200) NOT NULL,
check_standard TEXT,
check_method VARCHAR(100),
sort_order INTEGER DEFAULT 0,
required BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
-- 通知渠道表
CREATE TABLE ops_notification_channel (
id UUID PRIMARY KEY,
project_id UUID NOT NULL,
name VARCHAR(100) NOT NULL,
type VARCHAR(20) NOT NULL,
config JSONB,
enabled BOOLEAN DEFAULT TRUE,
priority INTEGER DEFAULT 0,
daily_limit INTEGER,
sent_today INTEGER DEFAULT 0,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
-- 消息模板表
CREATE TABLE ops_notification_template (
id UUID PRIMARY KEY,
project_id UUID NOT NULL,
name VARCHAR(100) NOT NULL,
code VARCHAR(50) NOT NULL,
title_template VARCHAR(200),
content_template TEXT NOT NULL,
variables JSONB,
channels JSONB,
example TEXT,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
UNIQUE(project_id, code)
);
-- 通知规则表
CREATE TABLE ops_notification_rule (
id UUID PRIMARY KEY,
project_id UUID NOT NULL,
name VARCHAR(100) NOT NULL,
event_type VARCHAR(50) NOT NULL,
conditions JSONB,
delay_minutes INTEGER DEFAULT 0,
template_code VARCHAR(50) NOT NULL,
receivers JSONB,
channels JSONB,
quiet_hours VARCHAR(20),
enabled BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
-- 通知历史表
CREATE TABLE ops_notification_history (
id UUID PRIMARY KEY,
project_id UUID NOT NULL,
title VARCHAR(200),
content TEXT,
event_type VARCHAR(50),
receiver_id UUID,
receiver_name VARCHAR(100),
receiver_phone VARCHAR(20),
receiver_email VARCHAR(100),
channel VARCHAR(20) NOT NULL,
channel_msg_id VARCHAR(100),
status VARCHAR(20) NOT NULL DEFAULT 'PENDING',
fail_reason VARCHAR(500),
send_time TIMESTAMP,
read_time TIMESTAMP,
business_type VARCHAR(50),
business_id VARCHAR(50),
created_at TIMESTAMP NOT NULL DEFAULT NOW()
);
-- 创建索引
CREATE INDEX idx_work_order_project ON ops_work_order(project_id);
CREATE INDEX idx_work_order_status ON ops_work_order(status);
CREATE INDEX idx_work_order_assignee ON ops_work_order(assignee_id);
CREATE INDEX idx_work_order_created ON ops_work_order(created_at);
CREATE INDEX idx_work_order_type ON ops_work_order(order_type);
CREATE INDEX idx_work_order_flow_order ON ops_work_order_flow(work_order_id);
CREATE INDEX idx_work_order_item_order ON ops_work_order_item(work_order_id);
CREATE INDEX idx_maintenance_plan_equipment ON ops_maintenance_plan(equipment_id);
CREATE INDEX idx_maintenance_task_equipment ON ops_maintenance_task(equipment_id);
CREATE INDEX idx_maintenance_task_status ON ops_maintenance_task(status);
CREATE INDEX idx_inspection_item_template ON ops_inspection_item(template_id);
CREATE INDEX idx_notification_history_receiver ON ops_notification_history(receiver_id);
CREATE INDEX idx_notification_history_status ON ops_notification_history(status);
```
---
**文档维护**: 本领域技术方案由 ether-ops 服务负责人维护