feat(ops): 工单创建发布事件(事件驱动调度) & 工单完成自动下一个任务

This commit is contained in:
lzh
2026-01-19 10:56:30 +08:00
parent 1d056a5e7a
commit 5419a949d4
3 changed files with 123 additions and 9 deletions

View File

@@ -8,6 +8,7 @@ import com.viewsh.module.ops.dal.mysql.workorder.OpsOrderMapper;
import com.viewsh.module.ops.enums.OperatorTypeEnum;
import com.viewsh.module.ops.enums.WorkOrderStatusEnum;
import com.viewsh.module.ops.environment.integration.dto.CleanOrderCompleteEventDTO;
import com.viewsh.module.ops.environment.service.cleanorder.CleanOrderService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.annotation.ConsumeMode;
@@ -68,6 +69,9 @@ public class CleanOrderCompleteEventHandler implements RocketMQListener<String>
@Resource
private OrderLifecycleManager orderLifecycleManager;
@Resource
private CleanOrderService cleanOrderService;
@Override
public void onMessage(String message) {
try {
@@ -142,8 +146,13 @@ public class CleanOrderCompleteEventHandler implements RocketMQListener<String>
// 6. 清除 Redis 缓存(设备当前工单)
clearDeviceCurrentOrder(event.getDeviceId());
log.info("[CleanOrderCompleteEventHandler] 工单完成成功: eventId={}, orderId={}, duration={}ms",
event.getEventId(), event.getOrderId(),
// 7. 自动调度下一个任务(优先恢复被中断的任务)
if (order.getAssigneeId() != null) {
cleanOrderService.autoDispatchNextOrder(event.getOrderId(), order.getAssigneeId());
}
log.info("[CleanOrderCompleteEventHandler] 工单完成成功: eventId={}, orderId={}, assigneeId={}, duration={}ms",
event.getEventId(), event.getOrderId(), order.getAssigneeId(),
event.getTriggerData() != null ? event.getTriggerData().get("durationMs") : "N/A");
}

View File

@@ -0,0 +1,91 @@
package com.viewsh.module.ops.environment.integration.listener;
import com.viewsh.module.ops.core.dispatch.DispatchEngine;
import com.viewsh.module.ops.core.dispatch.model.OrderDispatchContext;
import com.viewsh.module.ops.core.event.OrderCreatedEvent;
import com.viewsh.module.ops.dal.dataobject.workorder.OpsOrderDO;
import com.viewsh.module.ops.dal.mysql.workorder.OpsOrderMapper;
import com.viewsh.module.ops.enums.PriorityEnum;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;
/**
* 工单创建事件监听器
* <p>
* 监听工单创建事件,自动触发调度流程
* <p>
* 职责:
* - 工单创建后自动调用调度引擎进行派单
* - 支持 P0 紧急任务的打断逻辑(通过 CleanerPriorityScheduleStrategy
*
* @author AI
*/
@Slf4j
@Component
public class OrderCreatedEventListener {
@Resource
private DispatchEngine dispatchEngine;
@Resource
private OpsOrderMapper opsOrderMapper;
/**
* 监听工单创建事件,触发自动调度
* <p>
* 使用 @TransactionalEventListener 确保在事务提交后才执行调度
* 这样可以避免调度失败导致工单创建回滚
*/
@org.springframework.transaction.event.TransactionalEventListener(
phase = TransactionPhase.AFTER_COMMIT
)
public void onOrderCreated(OrderCreatedEvent event) {
try {
log.info("[OrderCreatedEventListener] 收到工单创建事件: orderId={}, orderType={}, priority={}",
event.getOrderId(), event.getOrderType(), event.getPriority());
// 只处理保洁工单
if (!"CLEAN".equals(event.getOrderType())) {
log.debug("[OrderCreatedEventListener] 跳过非保洁工单: orderType={}", event.getOrderType());
return;
}
// 查询工单信息
OpsOrderDO order = opsOrderMapper.selectById(event.getOrderId());
if (order == null) {
log.warn("[OrderCreatedEventListener] 工单不存在,无法调度: orderId={}", event.getOrderId());
return;
}
// 构建调度上下文
OrderDispatchContext context = OrderDispatchContext.builder()
.orderId(order.getId())
.orderCode(order.getOrderCode())
.orderTitle(order.getTitle())
.businessType(order.getOrderType())
.areaId(event.getAreaId() != null ? event.getAreaId() : order.getAreaId())
.priority(PriorityEnum.fromPriority(event.getPriority()))
.build();
// 使用调度引擎执行调度(包含 P0 打断逻辑)
var result = dispatchEngine.dispatch(context);
if (result.isSuccess()) {
log.info("[OrderCreatedEventListener] 自动调度成功: orderId={}, assigneeId={}, path={}",
event.getOrderId(), result.getAssigneeId(), result.getPath());
} else {
log.warn("[OrderCreatedEventListener] 自动调度失败: orderId={}, reason={}",
event.getOrderId(), result.getMessage());
}
} catch (Exception e) {
// 调度失败不应影响工单创建
log.error("[OrderCreatedEventListener] 自动调度异常: orderId={}", event.getOrderId(), e);
}
}
}

View File

@@ -5,6 +5,8 @@ import com.viewsh.module.ops.api.queue.OrderQueueService;
import com.viewsh.module.ops.core.dispatch.DispatchEngine;
import com.viewsh.module.ops.core.dispatch.model.DispatchResult;
import com.viewsh.module.ops.core.dispatch.model.OrderDispatchContext;
import com.viewsh.module.ops.core.event.OrderCreatedEvent;
import com.viewsh.module.ops.core.event.OrderEventPublisher;
import com.viewsh.module.ops.core.lifecycle.OrderLifecycleManager;
import com.viewsh.module.ops.core.lifecycle.model.OrderTransitionRequest;
import com.viewsh.module.ops.dal.dataobject.workorder.OpsOrderDO;
@@ -64,11 +66,11 @@ public class CleanOrderServiceImpl implements CleanOrderService {
@Resource
private OrderQueueService orderQueueService;
@Resource
private CleanerAreaAssignStrategy cleanerAreaAssignStrategy;
@Resource
private CleanerStatusService cleanerStatusService;
// @Resource
// private CleanerAreaAssignStrategy cleanerAreaAssignStrategy;
//
// @Resource
// private CleanerStatusService cleanerStatusService;
@Resource
private DispatchEngine dispatchEngine;
@@ -79,6 +81,9 @@ public class CleanOrderServiceImpl implements CleanOrderService {
@Resource
private CleanOrderEventHandler cleanOrderEventHandler;
@Resource
private OrderEventPublisher orderEventPublisher;
// ==================== 工单创建 ====================
@Override
@@ -100,8 +105,17 @@ public class CleanOrderServiceImpl implements CleanOrderService {
log.info("创建自动保洁工单成功: orderId={}, expectedDuration={}分钟",
orderId, createReq.getExpectedDuration());
// 3. 调度引擎分配
autoAssignOrder(orderId, createReq.getAreaId(), PriorityEnum.fromPriority(createReq.getPriority()));
// 3. 发布工单创建事件,由 OrderCreatedEventListener 触发调度
OrderCreatedEvent event = OrderCreatedEvent.builder()
.orderId(orderId)
.orderType("CLEAN")
.areaId(createReq.getAreaId())
.priority(PriorityEnum.fromPriority(createReq.getPriority()).getPriority())
.createTime(java.time.LocalDateTime.now())
.build()
.addPayload("isAuto", true)
.addPayload("expectedDuration", createReq.getExpectedDuration());
orderEventPublisher.publishOrderCreated(event);
return orderId;
}