diff --git a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/dal/dataobject/CleanOrderAutoCreateReqDTO.java b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/dal/dataobject/CleanOrderAutoCreateReqDTO.java index 49788da..9c1a7a2 100644 --- a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/dal/dataobject/CleanOrderAutoCreateReqDTO.java +++ b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/dal/dataobject/CleanOrderAutoCreateReqDTO.java @@ -8,6 +8,8 @@ import lombok.EqualsAndHashCode; import jakarta.validation.constraints.Min; import jakarta.validation.constraints.NotNull; +import java.util.Map; + /** * 保洁自动工单创建请求 DTO * @@ -44,4 +46,7 @@ public class CleanOrderAutoCreateReqDTO extends OpsOrderCreateReqDTO { @Schema(description = "触发设备Key(冗余,便于查询)") private String triggerDeviceKey; + @Schema(description = "触发数据(如客流值、阈值等,用于后续处理)") + private Map triggerData; + } 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 9221ec6..aa49d75 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 @@ -59,24 +59,24 @@ public interface CleanOrderService { // ========== 保洁特有的状态转换 ========== /** - * 保洁员按键确认工单 + * 设备按键确认工单 * 状态转换:DISPATCHED → CONFIRMED - * 同时更新保洁员状态:IDLE → BUSY(关键:确认后才变为忙碌) + * 设备状态保持 BUSY(在 DISPATCHED 时已设置) * - * @param orderId 工单ID - * @param cleanerId 保洁员ID + * @param orderId 工单ID + * @param deviceId 工牌设备ID */ - void confirmOrder(Long orderId, Long cleanerId); + void confirmOrder(Long orderId, Long deviceId); /** * 感知信标,开始作业 * 状态转换:CONFIRMED → ARRIVED * - * @param orderId 工单ID - * @param cleanerId 保洁员ID - * @param beaconId 信标ID + * @param orderId 工单ID + * @param deviceId 工牌设备ID + * @param beaconId 信标ID */ - void startWorkingOnBeacon(Long orderId, Long cleanerId, Long beaconId); + void startWorkingOnBeacon(Long orderId, Long deviceId, Long beaconId); /** * 丢失信号,自动完成 @@ -84,11 +84,11 @@ public interface CleanOrderService { * 完成后自动推送队列中的下一个任务 * * @param orderId 工单ID - * @param cleanerId 保洁员ID - * @param beaconId 信标ID - * @param lostSeconds 丢失信号时长(秒) + * @param deviceId 工牌设备ID + * @param beaconId 信标ID + * @param lostSeconds 丢失信号时长(秒) */ - void autoCompleteOnSignalLost(Long orderId, Long cleanerId, Long beaconId, Integer lostSeconds); + void autoCompleteOnSignalLost(Long orderId, Long deviceId, Long beaconId, Integer lostSeconds); // ========== 任务自动切换 ========== @@ -96,37 +96,38 @@ public interface CleanOrderService { * 任务完成后,自动推送队列中的下一个任务 * * @param completedOrderId 已完成的工单ID - * @param cleanerId 保洁员ID + * @param deviceId 工牌设备ID */ - void autoDispatchNextOrder(Long completedOrderId, Long cleanerId); + void autoDispatchNextOrder(Long completedOrderId, Long deviceId); + // ========== 语音播报(支持去重合并) ========== /** - * 语音播报:空闲保洁员收到新工单 + * 语音播报:空闲设备收到新工单 * - * @param cleanerId 保洁员ID + * @param deviceId 工牌设备ID */ - void playVoiceForNewOrder(Long cleanerId); + void playVoiceForNewOrder(Long deviceId); /** - * 语音播报:忙碌保洁员收到待办(支持去重合并) + * 语音播报:忙碌设备收到待办(支持去重合并) * 例如:"新增3项待办,您共有5个待办工单" * - * @param cleanerId 保洁员ID + * @param deviceId 工牌设备ID * @param queueCount 当前待办数量 */ - void playVoiceForQueuedOrder(Long cleanerId, int queueCount); + void playVoiceForQueuedOrder(Long deviceId, int queueCount); /** * 语音播报:任务完成后自动推送下一个 * 例如:"待办工单总数2个,第一位待办工单xxx" * - * @param cleanerId 保洁员ID + * @param deviceId 工牌设备ID * @param queueCount 待办数量 * @param nextTaskTitle 下一个任务标题 */ - void playVoiceForNextTask(Long cleanerId, int queueCount, String nextTaskTitle); + void playVoiceForNextTask(Long deviceId, int queueCount, String nextTaskTitle); // ========== 优先级管理 ========== 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 947c056..cec7bec 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 @@ -4,7 +4,6 @@ import com.viewsh.module.ops.api.queue.OrderQueueDTO; 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; @@ -120,7 +119,7 @@ public class CleanOrderServiceImpl implements CleanOrderService { log.info("创建自动保洁工单成功: orderId={}, orderCode={}, expectedDuration={}分钟, triggerSource={}", orderId, orderCode, createReq.getExpectedDuration(), createReq.getTriggerSource()); - // 5. 发布工单创建事件,由 CleanOrderEventListener 触发调度 + // 5. 发布工单创建事件 OrderCreatedEvent event = OrderCreatedEvent.builder() .orderId(orderId) .orderType("CLEAN") @@ -132,7 +131,14 @@ public class CleanOrderServiceImpl implements CleanOrderService { .build() .addPayload("isAuto", true) .addPayload("expectedDuration", createReq.getExpectedDuration()) - .addPayload("triggerSource", createReq.getTriggerSource()); + .addPayload("triggerSource", createReq.getTriggerSource()) + .addPayload("triggerDeviceId", createReq.getTriggerDeviceId()) + .addPayload("triggerDeviceKey", createReq.getTriggerDeviceKey()); + + // 添加触发数据(用于客流计数器重置等后续处理) + if (createReq.getTriggerData() != null && !createReq.getTriggerData().isEmpty()) { + event.getPayload().put("triggerData", createReq.getTriggerData()); + } orderEventPublisher.publishOrderCreated(event); @@ -143,28 +149,28 @@ public class CleanOrderServiceImpl implements CleanOrderService { @Override @Transactional(rollbackFor = Exception.class) - public void enqueueOrderOnly(Long orderId, Long cleanerId) { + public void enqueueOrderOnly(Long orderId, Long deviceId) { // 使用生命周期管理器入队 OrderTransitionRequest request = OrderTransitionRequest.builder() .orderId(orderId) - .assigneeId(cleanerId) + .assigneeId(deviceId) .operatorType(OperatorTypeEnum.SYSTEM) - .operatorId(cleanerId) + .operatorId(deviceId) .reason("执行人忙碌,任务入队") .build(); orderLifecycleManager.enqueue(request); - log.info("工单已入队: orderId={}, cleanerId={}", orderId, cleanerId); + log.info("工单已入队: orderId={}, deviceId={}", orderId, deviceId); } @Override @Transactional(rollbackFor = Exception.class) - public void enqueueAndDispatch(Long orderId, Long cleanerId) { - enqueueAndDispatch(orderId, cleanerId, false); + public void enqueueAndDispatch(Long orderId, Long deviceId) { + enqueueAndDispatch(orderId, deviceId, false); } @Transactional(rollbackFor = Exception.class) - public void enqueueAndDispatch(Long orderId, Long cleanerId, boolean isUrgent) { + public void enqueueAndDispatch(Long orderId, Long deviceId, boolean isUrgent) { // 查询工单 OpsOrderDO order = opsOrderMapper.selectById(orderId); if (order == null) { @@ -174,25 +180,25 @@ public class CleanOrderServiceImpl implements CleanOrderService { if (isUrgent) { // P0紧急任务:使用紧急插队 - DispatchResult result = dispatchEngine.urgentInterrupt(orderId, cleanerId); + DispatchResult result = dispatchEngine.urgentInterrupt(orderId, deviceId); log.warn("P0紧急派单结果: orderId={}, success={}", orderId, result.isSuccess()); } else { // 普通任务:正常派单 OrderTransitionRequest request = OrderTransitionRequest.builder() .orderId(orderId) .targetStatus(WorkOrderStatusEnum.DISPATCHED) - .assigneeId(cleanerId) + .assigneeId(deviceId) .operatorType(OperatorTypeEnum.SYSTEM) - .operatorId(cleanerId) + .operatorId(deviceId) .reason("自动派单") .build(); orderLifecycleManager.dispatch(request); - log.info("工单已派发: orderId={}, cleanerId={}", orderId, cleanerId); + log.info("工单已派发: orderId={}, deviceId={}", orderId, deviceId); } // 语音播报 - cleanOrderEventListener.sendNewOrderNotification(cleanerId, orderId); + cleanOrderEventListener.sendNewOrderNotification(deviceId, orderId); } @Override @@ -266,35 +272,35 @@ public class CleanOrderServiceImpl implements CleanOrderService { @Override @Transactional(rollbackFor = Exception.class) - public void confirmOrder(Long orderId, Long cleanerId) { - log.info("保洁员确认工单: orderId={}, cleanerId={}", orderId, cleanerId); + public void confirmOrder(Long orderId, Long deviceId) { + log.info("设备确认工单: orderId={}, deviceId={}", orderId, deviceId); // 使用生命周期管理器转换状态 OrderTransitionRequest request = OrderTransitionRequest.builder() .orderId(orderId) .targetStatus(WorkOrderStatusEnum.CONFIRMED) - .assigneeId(cleanerId) + .assigneeId(deviceId) .operatorType(OperatorTypeEnum.CLEANER) - .operatorId(cleanerId) + .operatorId(deviceId) .reason("确认工单") .build(); orderLifecycleManager.transition(request); - // 注意:保洁员状态更新由 CleanOrderEventListener 处理 + // 注意:设备状态更新由 BadgeDeviceStatusServiceImpl 处理 } @Override @Transactional(rollbackFor = Exception.class) - public void startWorkingOnBeacon(Long orderId, Long cleanerId, Long beaconId) { - log.info("感知信标,开始作业: orderId={}, cleanerId={}, beaconId={}", orderId, cleanerId, beaconId); + public void startWorkingOnBeacon(Long orderId, Long deviceId, Long beaconId) { + log.info("感知信标,开始作业: orderId={}, deviceId={}, beaconId={}", orderId, deviceId, beaconId); // 使用生命周期管理器转换状态 OrderTransitionRequest request = OrderTransitionRequest.builder() .orderId(orderId) .targetStatus(WorkOrderStatusEnum.ARRIVED) - .assigneeId(cleanerId) + .assigneeId(deviceId) .operatorType(OperatorTypeEnum.SYSTEM) - .operatorId(cleanerId) + .operatorId(deviceId) .reason("感知信标,开始作业") .build(); request.putPayload("beaconId", beaconId); @@ -307,17 +313,17 @@ public class CleanOrderServiceImpl implements CleanOrderService { @Override @Transactional(rollbackFor = Exception.class) - public void autoCompleteOnSignalLost(Long orderId, Long cleanerId, Long beaconId, Integer lostSeconds) { - log.info("丢失信号,自动完成工单: orderId={}, cleanerId={}, lostSeconds={}秒", - orderId, cleanerId, lostSeconds); + public void autoCompleteOnSignalLost(Long orderId, Long deviceId, Long beaconId, Integer lostSeconds) { + log.info("丢失信号,自动完成工单: orderId={}, deviceId={}, lostSeconds={}秒", + orderId, deviceId, lostSeconds); // 使用生命周期管理器转换状态 OrderTransitionRequest request = OrderTransitionRequest.builder() .orderId(orderId) .targetStatus(WorkOrderStatusEnum.COMPLETED) - .assigneeId(cleanerId) + .assigneeId(deviceId) .operatorType(OperatorTypeEnum.SYSTEM) - .operatorId(cleanerId) + .operatorId(deviceId) .reason("丢失信号,自动完成") .build(); request.putPayload("lostSeconds", lostSeconds); @@ -329,40 +335,39 @@ public class CleanOrderServiceImpl implements CleanOrderService { recordCompletedTime(orderId); // 自动推送下一个任务 - dispatchEngine.autoDispatchNext(orderId, cleanerId); + dispatchEngine.autoDispatchNext(orderId, deviceId); } @Override @Transactional(rollbackFor = Exception.class) - public void autoDispatchNextOrder(Long completedOrderId, Long cleanerId) { - log.info("任务完成后自动调度下一个: completedOrderId={}, cleanerId={}", completedOrderId, cleanerId); + public void autoDispatchNextOrder(Long completedOrderId, Long deviceId) { + log.info("任务完成后自动调度下一个: completedOrderId={}, deviceId={}", completedOrderId, deviceId); - // 使用新的调度引擎自动推送下一个 - DispatchResult result = dispatchEngine.autoDispatchNext(completedOrderId, cleanerId); + // 使用调度引擎自动推送下一个 + DispatchResult result = dispatchEngine.autoDispatchNext(completedOrderId, deviceId); if (result.isSuccess()) { - log.info("已自动推送下一个任务: cleanerId={}", cleanerId); + log.info("已自动推送下一个任务: deviceId={}", deviceId); } else { - log.info("无等待任务,保洁员变空闲: cleanerId={}", cleanerId); - // 状态更新由 CleanOrderEventListener 处理 + log.info("无等待任务,设备变空闲: deviceId={}", deviceId); } } // ==================== 语音播报(委托给 EventHandler)==================== @Override - public void playVoiceForNewOrder(Long cleanerId) { - cleanOrderEventListener.sendNewOrderNotification(cleanerId, null); + public void playVoiceForNewOrder(Long deviceId) { + cleanOrderEventListener.sendNewOrderNotification(deviceId, null); } @Override - public void playVoiceForQueuedOrder(Long cleanerId, int queueCount) { - cleanOrderEventListener.sendQueuedOrderNotification(cleanerId, queueCount); + public void playVoiceForQueuedOrder(Long deviceId, int queueCount) { + cleanOrderEventListener.sendQueuedOrderNotification(deviceId, queueCount); } @Override - public void playVoiceForNextTask(Long cleanerId, int queueCount, String nextTaskTitle) { - cleanOrderEventListener.sendNextTaskNotification(cleanerId, queueCount, nextTaskTitle); + public void playVoiceForNextTask(Long deviceId, int queueCount, String nextTaskTitle) { + cleanOrderEventListener.sendNextTaskNotification(deviceId, queueCount, nextTaskTitle); } // ==================== 作业时长计算 ==================== diff --git a/viewsh-module-ops/viewsh-module-environment-biz/src/test/java/com/viewsh/module/ops/environment/service/cleanorder/CleanOrderEndToEndTest.java b/viewsh-module-ops/viewsh-module-environment-biz/src/test/java/com/viewsh/module/ops/environment/service/cleanorder/CleanOrderEndToEndTest.java index b0f151b..4eb6a8a 100644 --- a/viewsh-module-ops/viewsh-module-environment-biz/src/test/java/com/viewsh/module/ops/environment/service/cleanorder/CleanOrderEndToEndTest.java +++ b/viewsh-module-ops/viewsh-module-environment-biz/src/test/java/com/viewsh/module/ops/environment/service/cleanorder/CleanOrderEndToEndTest.java @@ -18,6 +18,7 @@ import com.viewsh.framework.common.pojo.CommonResult; import com.viewsh.module.ops.environment.integration.listener.CleanOrderEventListener; import com.viewsh.module.ops.environment.service.cleanorder.CleanOrderServiceImpl; import com.viewsh.module.ops.environment.service.voice.VoiceBroadcastService; +import com.viewsh.module.ops.environment.service.badge.BadgeDeviceStatusService; import com.viewsh.module.ops.infrastructure.code.OrderCodeGenerator; import com.viewsh.module.ops.infrastructure.id.OrderIdGenerator; import com.viewsh.module.ops.infrastructure.log.recorder.EventLogRecorder; @@ -89,6 +90,10 @@ public class CleanOrderEndToEndTest { private ValueOperations valueOperations; @Mock private VoiceBroadcastService voiceBroadcastService; + + @Mock + private BadgeDeviceStatusService badgeDeviceStatusService; + @Mock private EventLogRecorder eventLogRecorder; @@ -245,7 +250,8 @@ public class CleanOrderEndToEndTest { @Test void testAV01_BeaconAutoArrive() throws Exception { injectField(arriveEventHandler, "orderLifecycleManager", orderLifecycleManager); - + injectField(arriveEventHandler, "badgeDeviceStatusService", badgeDeviceStatusService); + // 准备工单:状态 DISPATCHED Long orderId = 1001L; OpsOrderDO order = OpsOrderDO.builder() @@ -283,9 +289,10 @@ public class CleanOrderEndToEndTest { assertEquals(orderId, req.getOrderId()); assertEquals(WorkOrderStatusEnum.ARRIVED, req.getTargetStatus()); assertTrue(req.getReason().contains("自动到岗确认")); - - // 3. 验证 Redis 缓存更新 - verify(valueOperations).set(contains("ops:clean:device:order:5001"), anyString(), anyLong(), any(TimeUnit.class)); + + // 3. 验证设备状态服务更新工单信息 + verify(badgeDeviceStatusService).setCurrentOrderInfo(eq(5001L), eq(1001L), + eq(WorkOrderStatusEnum.ARRIVED.getStatus()), eq(101L), eq("F0:C8:60:1D:10:BB")); } @Test @@ -315,6 +322,7 @@ public class CleanOrderEndToEndTest { void testCP01_SignalLossAutoComplete() throws Exception { injectField(completeEventHandler, "orderLifecycleManager", orderLifecycleManager); injectField(completeEventHandler, "cleanOrderService", cleanOrderService); + injectField(completeEventHandler, "badgeDeviceStatusService", badgeDeviceStatusService); injectField(cleanOrderService, "dispatchEngine", dispatchEngine); // 准备工单:状态 ARRIVED @@ -333,7 +341,7 @@ public class CleanOrderEndToEndTest { "\"triggerSource\":\"IOT_SIGNAL_LOSS\"," + "\"triggerData\":{\"durationMs\":1800000}" + "}"; - + // 模拟 autoDispatchNext 调用成功 when(dispatchEngine.autoDispatchNext(eq(orderId), eq(2001L))) .thenReturn(DispatchResult.success("Success", 2001L)); @@ -345,8 +353,8 @@ public class CleanOrderEndToEndTest { // 1. 验证调用了 completeOrder verify(orderLifecycleManager).completeOrder(eq(orderId), eq(null), contains("信号丢失超时")); - // 2. 验证清理了 Redis 缓存 - verify(stringRedisTemplate).delete(contains("ops:clean:device:order:5001")); + // 2. 验证清理了设备工单缓存 + verify(badgeDeviceStatusService).clearCurrentOrder(5001L); // 3. 验证触发了自动调度下一单 verify(dispatchEngine).autoDispatchNext(eq(orderId), eq(2001L)); diff --git a/viewsh-module-ops/viewsh-module-ops-api/src/main/java/com/viewsh/module/ops/api/queue/OrderQueueService.java b/viewsh-module-ops/viewsh-module-ops-api/src/main/java/com/viewsh/module/ops/api/queue/OrderQueueService.java index e5dfdcf..b4d80e3 100644 --- a/viewsh-module-ops/viewsh-module-ops-api/src/main/java/com/viewsh/module/ops/api/queue/OrderQueueService.java +++ b/viewsh-module-ops/viewsh-module-ops-api/src/main/java/com/viewsh/module/ops/api/queue/OrderQueueService.java @@ -8,7 +8,7 @@ import java.util.List; /** * 工单队列管理服务接口 * 提供工单队列的核心管理功能,包括入队、出队、状态变更、优先级调整等 - * + * @deprecated userId 参数实际存储的是工牌设备ID * @author lzh */ public interface OrderQueueService { @@ -18,7 +18,7 @@ public interface OrderQueueService { * 将工单加入派单队列,等待派单 * * @param opsOrderId 工单ID - * @param userId 执行人员ID(保洁员) + * @param userId 执行人员ID((保洁员/工牌设备ID)) * @param priority 优先级 * @param queueIndex 队列顺序(可选,用于同优先级排序) * @return 队列记录ID diff --git a/viewsh-module-ops/viewsh-module-ops-biz/src/main/java/com/viewsh/module/ops/core/lifecycle/handler/EventPublishHandler.java b/viewsh-module-ops/viewsh-module-ops-biz/src/main/java/com/viewsh/module/ops/core/lifecycle/handler/EventPublishHandler.java index 2336914..912a6d6 100644 --- a/viewsh-module-ops/viewsh-module-ops-biz/src/main/java/com/viewsh/module/ops/core/lifecycle/handler/EventPublishHandler.java +++ b/viewsh-module-ops/viewsh-module-ops-biz/src/main/java/com/viewsh/module/ops/core/lifecycle/handler/EventPublishHandler.java @@ -33,6 +33,18 @@ public class EventPublishHandler extends TransitionHandler { log.debug("事件发布处理器: orderId={}, {} -> {}", context.getOrder().getId(), oldStatus, targetStatus); try { + // 构建事件 payload(包含 assigneeId) + java.util.Map payload = request.getPayload() != null + ? new java.util.HashMap<>(request.getPayload()) + : new java.util.HashMap<>(); + if (request.getAssigneeId() != null) { + payload.put("assigneeId", request.getAssigneeId()); + } + // 添加 urgentOrderId(P0打断场景) + if (request.getUrgentOrderId() != null) { + payload.put("urgentOrderId", request.getUrgentOrderId()); + } + // 发布状态变更事件 OrderStateChangedEvent event = OrderStateChangedEvent.builder() .orderId(context.getOrder().getId()) @@ -44,7 +56,7 @@ public class EventPublishHandler extends TransitionHandler { .operatorType(request.getOperatorType()) .eventTime(java.time.LocalDateTime.now()) .remark(request.getReason()) - .payload(request.getPayload()) + .payload(payload) .build(); orderEventPublisher.publishStateChanged(event); diff --git a/viewsh-module-ops/viewsh-module-ops-biz/src/main/java/com/viewsh/module/ops/infrastructure/log/enumeration/EventDomain.java b/viewsh-module-ops/viewsh-module-ops-biz/src/main/java/com/viewsh/module/ops/infrastructure/log/enumeration/EventDomain.java index 109bc45..3589b4a 100644 --- a/viewsh-module-ops/viewsh-module-ops-biz/src/main/java/com/viewsh/module/ops/infrastructure/log/enumeration/EventDomain.java +++ b/viewsh-module-ops/viewsh-module-ops-biz/src/main/java/com/viewsh/module/ops/infrastructure/log/enumeration/EventDomain.java @@ -25,7 +25,7 @@ public enum EventDomain { TRAFFIC("traffic", "客流"), /** - * 设备域 - 设备控制、TTS��震动等 + * 设备域 - 设备控制、TTS、震动等 */ DEVICE("device", "设备"),