# 运营调度领域技术方案 **领域编号**: 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 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 getTrend(UUID projectId, StatisticsType type, LocalDate startDate, LocalDate endDate) { // 按日/周/月统计工单量 // 创建趋势 // 完成趋势 } // 类型分布 public List getTypeDistribution(UUID projectId, LocalDate startDate, LocalDate endDate) { // 按工单类型统计 } // 处理人排行 public List getAssigneeRanking(UUID projectId, LocalDate startDate, LocalDate endDate) { // 处理人工作量排行 // 处理人满意度排行 } // 超时分析 public List 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 create(@RequestBody @Valid WorkOrderCreateRequest request); @GetMapping("/{id}") @Operation(summary = "获取工单详情") public Result getById(@PathVariable UUID id); @GetMapping @Operation(summary = "查询工单列表") public Result> list(WorkOrderQueryRequest request); @PutMapping("/{id}") @Operation(summary = "更新工单") public Result update(@PathVariable UUID id, @RequestBody @Valid WorkOrderUpdateRequest request); @DeleteMapping("/{id}") @Operation(summary = "删除工单") public Result delete(@PathVariable UUID id); // 业务操作 @PostMapping("/{id}/assign") @Operation(summary = "分配工单") public Result assign(@PathVariable UUID id, @RequestBody @Valid WorkOrderAssignRequest request); @PostMapping("/{id}/start") @Operation(summary = "开始处理") public Result start(@PathVariable UUID id); @PostMapping("/{id}/complete") @Operation(summary = "完成工单") public Result complete(@PathVariable UUID id, @RequestBody @Valid WorkOrderCompleteRequest request); @PostMapping("/{id}/verify") @Operation(summary = "验证工单") public Result verify(@PathVariable UUID id, @RequestBody @Valid WorkOrderVerifyRequest request); @PostMapping("/{id}/cancel") @Operation(summary = "取消工单") public Result cancel(@PathVariable UUID id, @RequestBody WorkOrderCancelRequest request); // 流转记录 @GetMapping("/{id}/flows") @Operation(summary = "获取流转记录") public Result> getFlows(@PathVariable UUID id); } ``` > **TODO**: 工单列表接口(GET /api/wo/work-orders)当前返回 List,需改为分页查询(返回 Page)。 ### 5.2 Notification API ```java @RestController @RequestMapping("/api/wo/notifications") @Tag(name = "消息通知") public class NotificationController { // 渠道管理 @PostMapping("/channels") @Operation(summary = "创建通知渠道") public Result createChannel(@RequestBody @Valid ChannelCreateRequest request); @GetMapping("/channels") @Operation(summary = "查询渠道列表") public Result> listChannels(); // 模板管理 @PostMapping("/templates") @Operation(summary = "创建消息模板") public Result createTemplate(@RequestBody @Valid TemplateCreateRequest request); @GetMapping("/templates") @Operation(summary = "查询模板列表") public Result> listTemplates(); // 规则管理 @PostMapping("/rules") @Operation(summary = "创建通知规则") public Result createRule(@RequestBody @Valid RuleCreateRequest request); @GetMapping("/rules") @Operation(summary = "查询规则列表") public Result> listRules(); // 消息历史 @GetMapping("/history") @Operation(summary = "分页查询消息历史") public Result> pageHistory(NotificationHistoryQueryRequest request); // 个人消息 @GetMapping("/my") @Operation(summary = "获取我的消息列表") public Result> getMyNotifications(@RequestParam(required = false) Boolean unread); @GetMapping("/my/unread-count") @Operation(summary = "获取未读消息数量") public Result getUnreadCount(); @PostMapping("/{id}/read") @Operation(summary = "标记已读") public Result markAsRead(@PathVariable UUID id); @PostMapping("/read-all") @Operation(summary = "全部已读") public Result markAllAsRead(); } ``` ### 5.3 Statistics API ```java @RestController @RequestMapping("/api/wo/statistics") @Tag(name = "工单统计") public class WorkOrderStatisticsController { @GetMapping("/overview") @Operation(summary = "概览统计") public Result getOverview( @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate startDate, @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate); @GetMapping("/trend") @Operation(summary = "趋势统计") public Result> 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> getTypeDistribution( @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate startDate, @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate); @GetMapping("/assignee-ranking") @Operation(summary = "处理人排行") public Result> 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 服务负责人维护