diff --git a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/integration/listener/BadgeDeviceStatusEventHandler.java b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/integration/listener/BadgeDeviceStatusEventHandler.java deleted file mode 100644 index 3de1748..0000000 --- a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/integration/listener/BadgeDeviceStatusEventHandler.java +++ /dev/null @@ -1,206 +0,0 @@ -package com.viewsh.module.ops.environment.integration.listener; - -import com.viewsh.module.ops.environment.service.badge.BadgeDeviceStatusService; -import com.viewsh.module.ops.core.event.OrderStateChangedEvent; -import com.viewsh.module.ops.enums.BadgeDeviceStatusEnum; -import com.viewsh.module.ops.enums.WorkOrderStatusEnum; -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; - -/** - * 工牌设备状态事件处理器 - *
- * 监听工单状态变更事件,同步更新工牌设备状态 - *
- * 设计说明: - * - 使用 Spring EventListener 监听工单状态变更事件 - * - 根据工单状态转换规则更新工牌设备状态 - * - 支持工单分配、开始、暂停、完成等场景 - * - * @author lzh - */ -@Slf4j -@Component -public class BadgeDeviceStatusEventHandler { - - @Resource - private BadgeDeviceStatusService badgeDeviceStatusService; - - /** - * 处理工单状态变更事件 - *
- * 状态映射规则: - * - PENDING → ASSIGNED: 不影响设备状态(设备可能还在处理其他任务) - * - ASSIGNED → ARRIVED: 设备状态 → BUSY(开始执行任务) - * - ARRIVED → PAUSED: 设备状态 → PAUSED(任务暂停) - * - PAUSED → ARRIVED/BUSY: 设备状态 → BUSY(任务恢复) - * - ARRIVED → COMPLETED: 设备状态 → IDLE(任务完成,检查是否还有等待任务) - * - 任意状态 → CANCELLED: 清除设备当前工单,检查是否还有等待任务 - * - * @param event 工单状态变更事件 - */ - @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) - @Async("ops-task-executor") - public void onOrderStateChanged(OrderStateChangedEvent event) { - try { - // 只处理保洁类型的工单 - if (!"CLEAN".equals(event.getOrderType())) { - return; - } - - log.debug("[BadgeDeviceStatusEventHandler] 收到工单状态变更事件: orderId={}, {} → {}, operatorId={}", - event.getOrderId(), event.getOldStatus(), event.getNewStatus(), event.getOperatorId()); - - // 获取设备ID(从 payload 或 operatorId 获取) - Long deviceId = getDeviceIdFromEvent(event); - if (deviceId == null) { - log.debug("[BadgeDeviceStatusEventHandler] 无法获取设备ID,跳过处理: orderId={}", event.getOrderId()); - return; - } - - // 根据状态转换更新设备状态 - handleStatusTransition(deviceId, event); - - } catch (Exception e) { - log.error("[BadgeDeviceStatusEventHandler] 处理工单状态变更事件失败: orderId={}", event.getOrderId(), e); - } - } - - /** - * 根据状态转换更新设备状态 - */ - private void handleStatusTransition(Long deviceId, OrderStateChangedEvent event) { - WorkOrderStatusEnum newStatus = event.getNewStatus(); - - switch (newStatus) { - case PENDING: - // 工单已分配,不影响设备状态(设备可能还在处理其他任务) - // 设置设备当前工单 - badgeDeviceStatusService.setCurrentOrder(deviceId, event.getOrderId()); - break; - - case ARRIVED: - // 保洁员已到岗,开始执行任务 - badgeDeviceStatusService.updateBadgeStatus(deviceId, BadgeDeviceStatusEnum.BUSY, - event.getOperatorId(), "工单开始执行: " + event.getOrderCode()); - badgeDeviceStatusService.setCurrentOrder(deviceId, event.getOrderId()); - break; - - case PAUSED: - // 任务暂停 - badgeDeviceStatusService.updateBadgeStatus(deviceId, BadgeDeviceStatusEnum.PAUSED, - event.getOperatorId(), event.getRemark()); - break; - - case COMPLETED: - // 任务完成 - badgeDeviceStatusService.clearCurrentOrder(deviceId); - - // 检查是否还有等待任务,如果有则保持 BUSY,否则转为 IDLE - checkAndUpdateDeviceStatusAfterCompletion(deviceId, event); - break; - - case CANCELLED: - // 工单取消 - badgeDeviceStatusService.clearCurrentOrder(deviceId); - - // 检查是否还有等待任务,如果有则保持 BUSY,否则转为 IDLE - checkAndUpdateDeviceStatusAfterCompletion(deviceId, event); - break; - - default: - log.debug("[BadgeDeviceStatusEventHandler] 不处理的状态: {}", newStatus); - break; - } - } - - /** - * 任务完成或取消后,检查并更新设备状态 - *
- * 如果有等待任务,保持 BUSY 状态 - * 如果没有等待任务,转为 IDLE 状态 - */ - private void checkAndUpdateDeviceStatusAfterCompletion(Long deviceId, OrderStateChangedEvent event) { - // 检查是否还有等待任务(通过查询队列) - // 这里简化处理,直接转为 IDLE - // 实际业务中可能需要查询队列判断是否还有等待任务 - - // 检查是否是被P0打断的任务恢复 - boolean isResumeFromInterrupt = event.hasPayload("interruptReason") - && "RESUME_FROM_INTERRUPT".equals(event.getPayloadString("interruptReason")); - - if (isResumeFromInterrupt) { - // 恢复被中断的任务,保持 BUSY - badgeDeviceStatusService.updateBadgeStatus(deviceId, BadgeDeviceStatusEnum.BUSY, - event.getOperatorId(), "恢复被中断的任务"); - } else { - // 正常完成,转为 IDLE - badgeDeviceStatusService.updateBadgeStatus(deviceId, BadgeDeviceStatusEnum.IDLE, - event.getOperatorId(), "任务完成,转为空闲"); - } - } - - /** - * 从事件中获取设备ID - *
- * 优先级: - * 1. payload.deviceId - * 2. operatorId(如果 operatorType 是 DEVICE) - * 3. 通过工单查询(需要额外的查询,暂不实现) - */ - private Long getDeviceIdFromEvent(OrderStateChangedEvent event) { - // 优先从 payload 获取 - Long deviceId = event.getPayloadLong("deviceId"); - if (deviceId != null) { - return deviceId; - } - - // TODO: 可以通过工单ID查询获取设备ID - // 这需要注入 OrderService 或 OrderMapper - - return null; - } - - /** - * 处理 P0 紧急任务打断事件 - *
- * 当 P0 任务需要打断当前任务时: - * 1. 将被打断的设备状态转为 PAUSED - * 2. 记录被打断的工单ID - * - * @param deviceId 被打断的设备ID - * @param interruptedOrderId 被打断的工单ID - * @param urgentOrderId P0紧急工单ID - */ - public void handleP0Interrupt(Long deviceId, Long interruptedOrderId, Long urgentOrderId) { - log.info("[BadgeDeviceStatusEventHandler] P0紧急任务打断: deviceId={}, interruptedOrderId={}, urgentOrderId={}", - deviceId, interruptedOrderId, urgentOrderId); - - badgeDeviceStatusService.updateBadgeStatus(deviceId, BadgeDeviceStatusEnum.PAUSED, - null, "被P0紧急任务打断: " + urgentOrderId); - } - - /** - * 处理 P0 任务完成后的恢复事件 - *
- * 当 P0 任务完成后,恢复被打断的任务: - * 1. 将设备状态转为 BUSY - * 2. 设置当前工单为被打断的工单 - * - * @param deviceId 设备ID - * @param interruptedOrderId 被打断的工单ID - */ - public void handleP0Resume(Long deviceId, Long interruptedOrderId) { - log.info("[BadgeDeviceStatusEventHandler] P0任务完成,恢复被中断任务: deviceId={}, interruptedOrderId={}", - deviceId, interruptedOrderId); - - badgeDeviceStatusService.updateBadgeStatus(deviceId, BadgeDeviceStatusEnum.BUSY, - null, "P0任务完成,恢复被中断的任务"); - badgeDeviceStatusService.setCurrentOrder(deviceId, interruptedOrderId); - } -} diff --git a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/integration/listener/BadgeDeviceStatusEventListener.java b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/integration/listener/BadgeDeviceStatusEventListener.java index e6a4b15..ded725e 100644 --- a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/integration/listener/BadgeDeviceStatusEventListener.java +++ b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/integration/listener/BadgeDeviceStatusEventListener.java @@ -1,5 +1,6 @@ package com.viewsh.module.ops.environment.integration.listener; +import com.viewsh.module.ops.api.badge.BadgeDeviceStatusDTO; import com.viewsh.module.ops.api.queue.OrderQueueService; import com.viewsh.module.ops.core.event.OrderStateChangedEvent; import com.viewsh.module.ops.dal.dataobject.workorder.OpsOrderDO; @@ -100,6 +101,7 @@ public class BadgeDeviceStatusEventListener { * 根据工单状态更新设备工牌关联 */ private void handleOrderStatusTransition(Long deviceId, Long orderId, WorkOrderStatusEnum newStatus, OrderStateChangedEvent event) { + var waitingTasks = orderQueueService.getWaitingTasksByUserId(deviceId); switch (newStatus) { case DISPATCHED: // 工单已推送到工牌,设置工单关联,设备状态转为 BUSY @@ -122,9 +124,18 @@ public class BadgeDeviceStatusEventListener { break; case PAUSED: - // 任务暂停,设备状态转为 PAUSED - badgeDeviceStatusService.updateBadgeStatus(deviceId, BadgeDeviceStatusEnum.PAUSED, null, "任务暂停"); - log.info("[BadgeDeviceStatusEventListener] 任务暂停,设备状态转为 PAUSED: deviceId={}", deviceId); + // 检查是否是 P0 打断场景 + Long urgentOrderId = event.getPayloadLong("urgentOrderId"); + if (urgentOrderId != null) { + // P0 打断场景:不修改设备状态,保持当前状态 + // 紧接着会有 P0 工单的 DISPATCHED 事件,将当前工单更新为 P0 工单 + log.info("[BadgeDeviceStatusEventListener] P0打断场景,工单已暂停,等待P0工单派发: pausedOrderId={}, urgentOrderId={}, deviceId={}", + orderId, urgentOrderId, deviceId); + } else { + // 普通暂停场景:设备状态转为 PAUSED + badgeDeviceStatusService.updateBadgeStatus(deviceId, BadgeDeviceStatusEnum.PAUSED, null, "任务暂停"); + log.info("[BadgeDeviceStatusEventListener] 任务暂停,设备状态转为 PAUSED: deviceId={}", deviceId); + } break; case COMPLETED: @@ -132,7 +143,6 @@ public class BadgeDeviceStatusEventListener { badgeDeviceStatusService.clearCurrentOrder(deviceId); // 检查是否有等待任务,决定设备状态 - var waitingTasks = orderQueueService.getWaitingTasksByUserId(deviceId); if (waitingTasks != null && !waitingTasks.isEmpty()) { // 有等待任务,设备状态保持 BUSY(由后续 DISPATCHED 事件更新) log.info("[BadgeDeviceStatusEventListener] 任务完成,有{}个等待任务,设备保持 BUSY: deviceId={}", @@ -145,10 +155,29 @@ public class BadgeDeviceStatusEventListener { break; case CANCELLED: - // 工单取消,清除工单关联,设备状态转为 IDLE - badgeDeviceStatusService.clearCurrentOrder(deviceId); - badgeDeviceStatusService.updateBadgeStatus(deviceId, BadgeDeviceStatusEnum.IDLE, null, "工单已取消"); - log.info("[BadgeDeviceStatusEventListener] 工单已取消,清除设备工单关联: deviceId={}", deviceId); + // 检查被取消的工单是否是设备当前正在执行的工单 + BadgeDeviceStatusDTO deviceStatus = badgeDeviceStatusService.getBadgeStatus(deviceId); + Long currentOrderId = deviceStatus != null ? deviceStatus.getCurrentOpsOrderId() : null; + + if (orderId.equals(currentOrderId)) { + // 取消的是当前正在执行的工单,清除工单关联 + badgeDeviceStatusService.clearCurrentOrder(deviceId); + + // 检查是否有等待任务,决定设备状态 + if (waitingTasks != null && !waitingTasks.isEmpty()) { + // 有等待任务,设备状态保持 BUSY(由后续 DISPATCHED 事件更新) + log.info("[BadgeDeviceStatusEventListener] 当前工单已取消,有{}个等待任务,设备保持 BUSY: deviceId={}", + waitingTasks.size(), deviceId); + } else { + // 无等待任务,设备状态转为 IDLE + badgeDeviceStatusService.updateBadgeStatus(deviceId, BadgeDeviceStatusEnum.IDLE, null, "工单已取消"); + log.info("[BadgeDeviceStatusEventListener] 当前工单已取消,无等待任务,设备转为 IDLE: deviceId={}", deviceId); + } + } else { + // 取消的不是当前工单(可能是队列中的等待任务),不需要修改设备状态 + log.debug("[BadgeDeviceStatusEventListener] 取消的工单非当前执行工单,跳过设备状态更新: cancelledOrderId={}, currentOrderId={}, deviceId={}", + orderId, currentOrderId, deviceId); + } break; default: diff --git a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/badge/BadgeDeviceStatusServiceImpl.java b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/badge/BadgeDeviceStatusServiceImpl.java index 8403523..ea95170 100644 --- a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/badge/BadgeDeviceStatusServiceImpl.java +++ b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/badge/BadgeDeviceStatusServiceImpl.java @@ -19,6 +19,16 @@ import java.util.stream.Collectors; * 工牌设备状态服务实现 *
* 基于 Redis Hash 存储设备状态,Set 维护区域设备索引 + *
+ * 职责: + * 1. 设备状态管理(IDLE/BUSY/PAUSED/OFFLINE) + * 2. 设备与工单关联管理 + * 3. 区域设备索引管理 + * 4. 心跳超时检查 + *
+ * 设计说明: + * - 状态变更事件由 {@link com.viewsh.module.ops.environment.integration.listener.BadgeDeviceStatusEventListener} 处理 + * - 本类只提供基础的服务方法 * * @author lzh */