diff --git a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/cleanorder/CleanOrderService.java b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/cleanorder/CleanOrderService.java index e30de72..9031e26 100644 --- a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/cleanorder/CleanOrderService.java +++ b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/cleanorder/CleanOrderService.java @@ -1,20 +1,20 @@ package com.viewsh.module.ops.environment.service.cleanorder; - import com.viewsh.module.ops.environment.dal.dataobject.CleanOrderAutoCreateReqDTO; -import com.viewsh.module.ops.environment.dal.dataobject.CleanOrderPauseReqDTO; -import com.viewsh.module.ops.environment.dal.dataobject.CleanOrderResumeReqDTO; /** * 保洁工单服务 - * + *
* 职责: * 1. 自动创建保洁工单 * 2. 队列推送管理(空闲推送,忙碌入队) * 3. 保洁特有的状态转换(confirmOrder、信标触发) - * 4. 作业时长计算 - * 5. 保洁扩展信息管理 - * 6. 并发控制和去重合并播报 + * 4. 任务自动切换 + * 5. 语音播报管理 + *
+ * 变更说明: + * - 移除了暂停/恢复/打断方法(由 {@link com.viewsh.module.ops.core.lifecycle.OrderLifecycleManager} 处理) + * - 移除了作业时长计算方法(由 {@link com.viewsh.module.ops.environment.handler.CleanOrderEventHandler} 通过事件处理) * * @author lzh */ @@ -72,8 +72,6 @@ public interface CleanOrderService { * 感知信标,开始作业 * 状态转换:CONFIRMED → ARRIVED * - * 注意:此方法由IoT信标事件触发,暂不实现,留接口 - * * @param orderId 工单ID * @param cleanerId 保洁员ID * @param beaconId 信标ID @@ -85,8 +83,6 @@ public interface CleanOrderService { * 状态转换:ARRIVED → COMPLETED * 完成后自动推送队列中的下一个任务 * - * 注意:此方法由IoT信标事件触发,暂不实现,留接口 - * * @param orderId 工单ID * @param cleanerId 保洁员ID * @param beaconId 信标ID @@ -132,17 +128,8 @@ public interface CleanOrderService { */ void playVoiceForNextTask(Long cleanerId, int queueCount, String nextTaskTitle); - // ========== 暂停/恢复(调用通用服务)========== - - /** - * 暂停保洁工单(状态转换:ARRIVED -> PAUSED) - * 场景:P0紧急工单插队、临时离开 - * - * @param pauseReq 暂停请求 - */ - void pauseCleanOrder(CleanOrderPauseReqDTO pauseReq); - // ========== 优先级管理 ========== + /** * 升级工单优先级为P0并处理紧急插队 * 场景:巡检员手动将普通工单升级为P0紧急任务 @@ -153,13 +140,6 @@ public interface CleanOrderService { */ boolean upgradePriorityToP0(Long orderId, String reason); - /** - * 恢复保洁工单(状态转换:PAUSED -> ARRIVED) - * - * @param resumeReq 恢复请求 - */ - void resumeCleanOrder(CleanOrderResumeReqDTO resumeReq); - // ========== 作业时长计算 ========== /** @@ -169,21 +149,4 @@ public interface CleanOrderService { * @return 作业时长(秒) */ Integer calculateActualDuration(Long orderId); - - /** - * 记录到岗时间 - * 场景:状态机监听器调用 - * - * @param orderId 工单ID - */ - void recordArrivedTime(Long orderId); - - /** - * 计算并更新作业时长 - * 场景:工单完成时,状态机监听器调用 - * - * @param orderId 工单ID - */ - void calculateDuration(Long orderId); - } diff --git a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/cleanorder/CleanOrderServiceImpl.java b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/cleanorder/CleanOrderServiceImpl.java index 2f01ab9..7a2d9c8 100644 --- a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/cleanorder/CleanOrderServiceImpl.java +++ b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/cleanorder/CleanOrderServiceImpl.java @@ -1,24 +1,23 @@ package com.viewsh.module.ops.environment.service.cleanorder; -import com.viewsh.module.ops.api.dispatch.DispatchEngineService; import com.viewsh.module.ops.api.queue.OrderQueueDTO; import com.viewsh.module.ops.api.queue.OrderQueueService; -import com.viewsh.module.ops.dal.dataobject.cleaner.OpsCleanerStatusDO; -import com.viewsh.module.ops.dal.dataobject.workorder.OpsOrderCleanExtDO; +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.lifecycle.OrderLifecycleManager; +import com.viewsh.module.ops.core.lifecycle.model.OrderTransitionRequest; import com.viewsh.module.ops.dal.dataobject.workorder.OpsOrderDO; -import com.viewsh.module.ops.dal.mysql.workorder.OpsOrderCleanExtMapper; import com.viewsh.module.ops.dal.mysql.workorder.OpsOrderMapper; -import com.viewsh.module.ops.enums.CleanerStatusEnum; import com.viewsh.module.ops.enums.OperatorTypeEnum; import com.viewsh.module.ops.enums.PriorityEnum; import com.viewsh.module.ops.enums.WorkOrderStatusEnum; import com.viewsh.module.ops.environment.dal.dataobject.CleanOrderAutoCreateReqDTO; -import com.viewsh.module.ops.environment.dal.dataobject.CleanOrderPauseReqDTO; -import com.viewsh.module.ops.environment.dal.dataobject.CleanOrderResumeReqDTO; +import com.viewsh.module.ops.environment.dal.dataobject.workorder.OpsOrderCleanExtDO; +import com.viewsh.module.ops.environment.dal.mysql.workorder.OpsOrderCleanExtMapper; +import com.viewsh.module.ops.environment.handler.CleanOrderEventHandler; import com.viewsh.module.ops.environment.service.cleaner.CleanerStatusService; -import com.viewsh.module.ops.environment.service.dispatch.CleanerAreaPriorityStrategy; -import com.viewsh.module.ops.environment.service.voice.VoiceBroadcastDeduplicationService; -import com.viewsh.module.ops.service.fsm.OrderStateMachine; +import com.viewsh.module.ops.environment.service.dispatch.CleanerAreaAssignStrategy; import com.viewsh.module.ops.service.order.OpsOrderService; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; @@ -27,10 +26,25 @@ import org.springframework.transaction.annotation.Transactional; import java.time.Duration; import java.time.LocalDateTime; -import java.util.List; /** - * 保洁工单扩展服务实现 + * 保洁工单服务实现(简化版) + *
+ * 职责: + * 1. 工单创建与自动分配 + * 2. 保洁特有的状态转换编排(confirm, arrive, complete) + * 3. 作业时长计算 + *
+ * 架构说明: + * - 状态同步:委托给 {@link OrderLifecycleManager} + * - 派单决策:使用新的 {@link DispatchEngine} + * - 保洁员状态:由 {@link com.viewsh.module.ops.environment.integration.listener.CleanerStateChangeListener} 处理 + * - 通知逻辑:由 {@link CleanOrderEventHandler} 处理 + *
+ * 变更历史:
+ * - Phase 3: 使用新的调度引擎和生命周期管理器
+ * - Phase 3: 移除直接的状态管理代码(改为事件驱动)
+ * - Phase 3: 瘦身代码,专注保洁业务编排
*
* @author lzh
*/
@@ -51,19 +65,21 @@ public class CleanOrderServiceImpl implements CleanOrderService {
private OrderQueueService orderQueueService;
@Resource
- private CleanerAreaPriorityStrategy cleanerAreaPriorityStrategy;
+ private CleanerAreaAssignStrategy cleanerAreaAssignStrategy;
@Resource
private CleanerStatusService cleanerStatusService;
@Resource
- private VoiceBroadcastDeduplicationService voiceBroadcastDeduplicationService;
+ private DispatchEngine dispatchEngine;
@Resource
- private OrderStateMachine orderStateMachine;
+ private OrderLifecycleManager orderLifecycleManager;
@Resource
- private DispatchEngineService dispatchEngineService;
+ private CleanOrderEventHandler cleanOrderEventHandler;
+
+ // ==================== 工单创建 ====================
@Override
@Transactional(rollbackFor = Exception.class)
@@ -74,122 +90,75 @@ public class CleanOrderServiceImpl implements CleanOrderService {
// 2. 创建保洁扩展信息
OpsOrderCleanExtDO cleanExt = OpsOrderCleanExtDO.builder()
.opsOrderId(orderId)
- .isAuto(1) // 自动工单
+ .isAuto(1)
.expectedDuration(createReq.getExpectedDuration())
.cleaningType(createReq.getCleaningType())
.difficultyLevel(createReq.getDifficultyLevel())
.build();
-
cleanExtMapper.insert(cleanExt);
log.info("创建自动保洁工单成功: orderId={}, expectedDuration={}分钟",
orderId, createReq.getExpectedDuration());
- // 3. 自动分配保洁员并入队
- enqueueOrder(orderId, createReq.getAreaId(), PriorityEnum.fromPriority(createReq.getPriority()));
+ // 3. 调度引擎分配
+ autoAssignOrder(orderId, createReq.getAreaId(), PriorityEnum.fromPriority(createReq.getPriority()));
return orderId;
}
/**
- * 工单入队(根据保洁员状态选择不同策略)
- * 推荐保洁员、入队、派单、同步状态
- *
- * @param orderId 工单ID
- * @param areaId 区域ID
- * @param priority 优先级
+ * 自动分配工单(使用新的调度引擎)
*/
- private void enqueueOrder(Long orderId, Long areaId, PriorityEnum priority) {
+ private void autoAssignOrder(Long orderId, Long areaId, PriorityEnum priority) {
try {
- // 1. 推荐保洁员
- Long recommendedCleanerId = cleanerAreaPriorityStrategy.recommendCleanerForNewOrder(areaId, priority);
-
- if (recommendedCleanerId == null) {
- log.warn("未找到可用的保洁员,工单将无法自动派单: orderId={}, areaId={}", orderId, areaId);
- // 工单保持在PENDING状态,等待后续处理
+ // 查询工单信息
+ OpsOrderDO order = opsOrderMapper.selectById(orderId);
+ if (order == null) {
+ log.warn("工单不存在,无法自动分配: orderId={}", orderId);
return;
}
- // 2. 查询保洁员状态
- OpsCleanerStatusDO cleanerStatusDO =
- cleanerStatusService.getStatus(recommendedCleanerId);
+ // 构建调度上下文
+ OrderDispatchContext context = OrderDispatchContext.builder()
+ .orderId(order.getId())
+ .orderCode(order.getOrderCode())
+ .orderTitle(order.getTitle())
+ .businessType(order.getOrderType())
+ .areaId(areaId)
+ .priority(priority)
+ .build();
- if (cleanerStatusDO == null) {
- log.warn("保洁员状态不存在,无法派单: cleanerId={}", recommendedCleanerId);
- return;
- }
+ // 使用调度引擎执行调度
+ DispatchResult result = dispatchEngine.dispatch(context);
- CleanerStatusEnum cleanerStatus = cleanerStatusDO.getStatusEnum();
-
- // 3. P0 紧急任务特殊处理
- boolean isUrgent = priority == PriorityEnum.P0;
-
- if (cleanerStatus == CleanerStatusEnum.IDLE) {
- // 空闲状态:立即推送
- log.info("保洁员空闲,立即推送工单: cleanerId={}, isUrgent={}", recommendedCleanerId, isUrgent);
- enqueueAndDispatch(orderId, recommendedCleanerId, isUrgent);
- } else if (cleanerStatus == CleanerStatusEnum.BUSY) {
- if (isUrgent) {
- // P0 紧急任务:使用派单引擎处理(可能打断当前任务)
- log.warn("保洁员忙碌但为P0紧急任务,使用紧急派单: cleanerId={}", recommendedCleanerId);
- enqueueAndDispatch(orderId, recommendedCleanerId, true);
- } else {
- // 忙碌状态:只入队
- log.info("保洁员忙碌,工单入队等待: cleanerId={}", recommendedCleanerId);
- enqueueOrderOnly(orderId, recommendedCleanerId);
-
- // 语音提示待办数量
- int queueCount = getQueueCount(recommendedCleanerId);
- playVoiceForQueuedOrder(recommendedCleanerId, queueCount);
- }
+ if (result.isSuccess()) {
+ log.info("自动分配成功: orderId={}, assigneeId={}, path={}",
+ orderId, result.getAssigneeId(), result.getPath());
} else {
- log.warn("保洁员状态不可接单: cleanerId={}, status={}",
- recommendedCleanerId, cleanerStatus);
+ log.warn("自动分配失败: orderId={}, reason={}", orderId, result.getMessage());
}
} catch (Exception e) {
- log.error("工单入队或派单失败: orderId={}, areaId={}", orderId, areaId, e);
- // TODO: 可以考虑回滚工单创建,或者标记为"入队失败"状态
+ log.error("自动分配工单失败: orderId={}", orderId, e);
}
}
- // ========== 队列推送机制实现 ==========
+ // ==================== 队列推送(兼容旧接口)====================
@Override
@Transactional(rollbackFor = Exception.class)
public void enqueueOrderOnly(Long orderId, Long cleanerId) {
- log.info("工单入队(不推送): orderId={}, cleanerId={}", orderId, cleanerId);
+ // 使用生命周期管理器入队
+ OrderTransitionRequest request = OrderTransitionRequest.builder()
+ .orderId(orderId)
+ .assigneeId(cleanerId)
+ .operatorType(OperatorTypeEnum.SYSTEM)
+ .operatorId(cleanerId)
+ .reason("执行人忙碌,任务入队")
+ .build();
- // 1. 查询工单
- OpsOrderDO order = opsOrderMapper.selectById(orderId);
- if (order == null) {
- log.error("工单不存在: orderId={}", orderId);
- throw new IllegalArgumentException("工单不存在: " + orderId);
- }
-
- // 2. 设置执行人
- order.setAssigneeId(cleanerId);
- opsOrderMapper.updateById(order);
-
- // 3. 使用状态机转换状态:PENDING → QUEUED
- orderStateMachine.transition(
- order,
- WorkOrderStatusEnum.QUEUED,
- OperatorTypeEnum.SYSTEM,
- cleanerId,
- "工单入队,等待推送"
- );
-
- // 4. 创建队列记录(使用 OrderQueueService,等待后续推送)
- Long queueId = orderQueueService.enqueue(
- orderId,
- cleanerId,
- PriorityEnum.fromPriority(order.getPriority()),
- null // queueIndex 自动计算
- );
-
- log.info("工单已入队等待: orderId={}, cleanerId={}, queueId={}, status=QUEUED",
- orderId, cleanerId, queueId);
+ orderLifecycleManager.enqueue(request);
+ log.info("工单已入队: orderId={}, cleanerId={}", orderId, cleanerId);
}
@Override
@@ -198,183 +167,64 @@ public class CleanOrderServiceImpl implements CleanOrderService {
enqueueAndDispatch(orderId, cleanerId, false);
}
- /**
- * 工单入队并立即推送(内部方法,支持紧急派单)
- *
- * @param orderId 工单ID
- * @param cleanerId 保洁员ID
- * @param isUrgent 是否为紧急任务(P0)
- */
@Transactional(rollbackFor = Exception.class)
public void enqueueAndDispatch(Long orderId, Long cleanerId, boolean isUrgent) {
- log.info("工单入队并立即推送: orderId={}, cleanerId={}, isUrgent={}", orderId, cleanerId, isUrgent);
-
- // 1. 查询工单
+ // 查询工单
OpsOrderDO order = opsOrderMapper.selectById(orderId);
if (order == null) {
log.error("工单不存在: orderId={}", orderId);
- throw new IllegalArgumentException("工单不存在: " + orderId);
+ return;
}
- // 2. 更新工单状态:PENDING → QUEUED
- order.setStatus(WorkOrderStatusEnum.QUEUED.getStatus());
- order.setAssigneeId(cleanerId);
- opsOrderMapper.updateById(order);
-
- // 3. 创建队列记录
- Long queueId = orderQueueService.enqueue(
- orderId,
- cleanerId,
- PriorityEnum.fromPriority(order.getPriority()),
- null
- );
-
- // 4. 立即推送到工牌(根据是否紧急使用不同的派单策略)
if (isUrgent) {
- // P0 紧急任务:使用派单引擎的紧急派单(可能打断当前任务)
- boolean success = dispatchEngineService.urgentDispatch(queueId);
- if (!success) {
- log.warn("紧急派单失败,回退到普通派单: queueId={}", queueId);
- dispatchToCleaner(queueId);
- }
+ // P0紧急任务:使用紧急插队
+ DispatchResult result = dispatchEngine.urgentInterrupt(orderId, cleanerId);
+ log.warn("P0紧急派单结果: orderId={}, success={}", orderId, result.isSuccess());
} else {
// 普通任务:正常派单
- dispatchToCleaner(queueId);
+ OrderTransitionRequest request = OrderTransitionRequest.builder()
+ .orderId(orderId)
+ .targetStatus(WorkOrderStatusEnum.DISPATCHED)
+ .assigneeId(cleanerId)
+ .operatorType(OperatorTypeEnum.SYSTEM)
+ .operatorId(cleanerId)
+ .reason("自动派单")
+ .build();
+
+ orderLifecycleManager.dispatch(request);
+ log.info("工单已派发: orderId={}, cleanerId={}", orderId, cleanerId);
}
- // 5. 语音播报
- playVoiceForNewOrder(cleanerId);
+ // 语音播报
+ cleanOrderEventHandler.sendNewOrderNotification(cleanerId, orderId);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void dispatchToCleaner(Long queueId) {
- log.info("推送工单到工牌: queueId={}", queueId);
-
- // 1. 查询队列记录
+ // 查询队列记录
OrderQueueDTO queueDTO = orderQueueService.getById(queueId);
if (queueDTO == null) {
log.error("队列记录不存在: queueId={}", queueId);
return;
}
- // 2. 并发控制:检查是否已有任务在推送中(状态为DISPATCHED)
- boolean hasDispatchingTask = checkIfHasDispatchingTask(queueDTO.getUserId());
- if (hasDispatchingTask) {
- log.warn("保洁员已有任务在推送中,跳过本次推送: queueId={}, cleanerId={}",
- queueId, queueDTO.getUserId());
- return;
- }
+ // 使用生命周期管理器派单
+ OrderTransitionRequest request = OrderTransitionRequest.builder()
+ .orderId(queueDTO.getOpsOrderId())
+ .targetStatus(WorkOrderStatusEnum.DISPATCHED)
+ .assigneeId(queueDTO.getUserId())
+ .queueId(queueId)
+ .operatorType(OperatorTypeEnum.SYSTEM)
+ .operatorId(queueDTO.getUserId())
+ .reason("推送工单")
+ .build();
- // 3. 查询工单
- OpsOrderDO order = opsOrderMapper.selectById(queueDTO.getOpsOrderId());
- if (order == null) {
- log.error("工单不存在: orderId={}", queueDTO.getOpsOrderId());
- return;
- }
-
- // 4. 使用派单引擎进行自动派单(管理队列状态转换)
- boolean dispatchSuccess = dispatchEngineService.autoDispatch(queueId);
-
- if (!dispatchSuccess) {
- log.error("派单失败: queueId={}", queueId);
- return;
- }
-
- // 5. 使用状态机转换状态:QUEUED → DISPATCHED
- orderStateMachine.transition(
- order,
- WorkOrderStatusEnum.DISPATCHED,
- OperatorTypeEnum.SYSTEM,
- queueDTO.getUserId(),
- "推送工单"
- );
-
- log.info("工单已推送到工牌: queueId={}, orderId={}, cleanerId={}, status=DISPATCHED",
- queueId, queueDTO.getOpsOrderId(), queueDTO.getUserId());
-
- // TODO: 调用 IoT 服务推送工牌通知
- // iotDeviceService.pushNotification(queueDTO.getUserId(),
- // "您有新的工单:" + order.getTitle());
- // iotDeviceService.vibrate(queueDTO.getUserId(), 1000);
+ orderLifecycleManager.dispatch(request);
+ log.info("工单已推送: queueId={}, orderId={}", queueId, queueDTO.getOpsOrderId());
}
- /**
- * 检查保洁员是否已有任务在推送中(状态为DISPATCHED)
- * 用于并发控制,防止重复推送
- */
- private boolean checkIfHasDispatchingTask(Long cleanerId) {
- // 查询该保洁员是否有状态为 DISPATCHED 的队列记录
- List