diff --git a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/integration/consumer/CleanOrderCreateEventHandler.java b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/integration/consumer/CleanOrderCreateEventHandler.java
index 2e8640e..723860c 100644
--- a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/integration/consumer/CleanOrderCreateEventHandler.java
+++ b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/integration/consumer/CleanOrderCreateEventHandler.java
@@ -1,508 +1,508 @@
-package com.viewsh.module.ops.environment.integration.consumer;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.viewsh.module.iot.api.device.IotDeviceControlApi;
-import com.viewsh.module.iot.api.device.dto.ResetTrafficCounterReqDTO;
-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 com.viewsh.module.ops.enums.WorkOrderStatusEnum;
-import com.viewsh.module.ops.environment.dal.dataobject.CleanOrderAutoCreateReqDTO;
-import com.viewsh.module.ops.environment.dal.redis.ActiveOrderInfo;
-import com.viewsh.module.ops.environment.dal.redis.TrafficActiveOrderRedisDAO;
-import com.viewsh.module.ops.environment.integration.dto.CleanOrderCreateEventDTO;
-import com.viewsh.module.ops.environment.service.cleanorder.CleanOrderService;
-import com.viewsh.module.ops.infrastructure.log.enumeration.EventDomain;
-import com.viewsh.module.ops.infrastructure.log.enumeration.EventLevel;
-import com.viewsh.module.ops.infrastructure.log.enumeration.LogModule;
-import com.viewsh.module.ops.infrastructure.log.enumeration.LogType;
-import com.viewsh.module.ops.infrastructure.log.recorder.EventLogRecord;
-import com.viewsh.module.ops.infrastructure.log.recorder.EventLogRecorder;
-import jakarta.annotation.Resource;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.rocketmq.spring.annotation.ConsumeMode;
-import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
-import org.apache.rocketmq.spring.core.RocketMQListener;
-import org.springframework.data.redis.core.StringRedisTemplate;
-import org.springframework.stereotype.Component;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-/**
- * 保洁工单创建事件消费者
- *
- * 订阅 IoT 模块发布的保洁工单创建事件。
- *
- * 客流触发逻辑(周期化):
- * 1. 无活跃工单 → 创建新工单 → 标记活跃 → 重置阈值
- * 2. 有排队中工单(PENDING/QUEUED) → 升级优先级一级 → 重置阈值
- * 3. 有已派发/已到达工单(DISPATCHED/CONFIRMED/ARRIVED) → 静默处理,不升级不创建 → 重置阈值
- * 4. 已是 P0 → 不升级,记录审计日志 → 重置阈值
- *
- * RocketMQ 配置:
- * - Topic: ops-order-create
- * - ConsumerGroup: ops-clean-order-create-group
- *
- * @author AI
- */
-@Slf4j
-@Component
-@RocketMQMessageListener(
- topic = "ops-order-create",
- consumerGroup = "ops-clean-order-create-group",
- consumeMode = ConsumeMode.CONCURRENTLY,
- selectorExpression = "*",
- accessKey = "${rocketmq.consumer.access-key:}",
- secretKey = "${rocketmq.consumer.secret-key:}"
-)
-public class CleanOrderCreateEventHandler implements RocketMQListener {
-
- /**
- * 幂等性控制 Key 模式
- */
- private static final String DEDUP_KEY_PATTERN = "ops:clean:dedup:create:%s";
-
- /**
- * 幂等性控制 TTL(秒)
- */
- private static final int DEDUP_TTL_SECONDS = 300;
-
- /**
- * 可升级优先级的状态集合(仅排队中,尚未派发)
- */
- private static final Set UPGRADABLE_STATUSES = Set.of(
- WorkOrderStatusEnum.PENDING.getStatus(),
- WorkOrderStatusEnum.QUEUED.getStatus()
- );
-
- @Resource
- private ObjectMapper objectMapper;
-
- @Resource
- private StringRedisTemplate stringRedisTemplate;
-
- @Resource
- private CleanOrderService cleanOrderService;
-
- @Resource
- private EventLogRecorder eventLogRecorder;
-
- @Resource
- private TrafficActiveOrderRedisDAO trafficActiveOrderRedisDAO;
-
- @Resource
- private IotDeviceControlApi iotDeviceControlApi;
-
- @Resource
- private OpsOrderMapper opsOrderMapper;
-
- @Override
- public void onMessage(String message) {
- try {
- // 1. JSON 反序列化
- CleanOrderCreateEventDTO event = objectMapper.readValue(message, CleanOrderCreateEventDTO.class);
-
- // 2. 幂等性检查
- String dedupKey = String.format(DEDUP_KEY_PATTERN, event.getEventId());
- Boolean firstTime = stringRedisTemplate.opsForValue()
- .setIfAbsent(dedupKey, "1", DEDUP_TTL_SECONDS, TimeUnit.SECONDS);
-
- if (!Boolean.TRUE.equals(firstTime)) {
- log.debug("[CleanOrderCreateEventHandler] 重复消息,跳过处理: eventId={}", event.getEventId());
- return;
- }
-
- // 3. 业务处理
- handleOrderCreate(event);
-
- } catch (Exception e) {
- log.error("[CleanOrderCreateEventHandler] 消息处理失败: message={}", message, e);
- throw new RuntimeException("保洁工单创建事件处理失败", e);
- }
- }
-
- /**
- * 处理工单创建
- */
- private void handleOrderCreate(CleanOrderCreateEventDTO event) {
- log.info("[CleanOrderCreateEventHandler] 收到工单创建事件: eventId={}, areaId={}, triggerSource={}",
- event.getEventId(), event.getAreaId(), event.getTriggerSource());
-
- // 客流触发 → 周期化逻辑
- if ("IOT_TRAFFIC".equals(event.getTriggerSource())) {
- handleTrafficTrigger(event);
- return;
- }
-
- // 非客流触发 → 原逻辑
- handleNonTrafficTrigger(event);
- }
-
- /**
- * 处理客流触发的工单创建(周期化逻辑)
- */
- private void handleTrafficTrigger(CleanOrderCreateEventDTO event) {
- Long areaId = event.getAreaId();
-
- // 1. 查询活跃工单(Redis 优先,DB 兜底)
- ActiveOrderInfo activeOrder = trafficActiveOrderRedisDAO.getActive(areaId);
- if (activeOrder == null) {
- activeOrder = queryActiveTrafficOrderFromDb(areaId);
- if (activeOrder != null) {
- // 恢复 Redis 标记
- trafficActiveOrderRedisDAO.markActive(areaId, activeOrder.getOrderId(),
- activeOrder.getStatus(), activeOrder.getPriority());
- log.info("[CleanOrderCreateEventHandler] Redis标记丢失已恢复: areaId={}, orderId={}",
- areaId, activeOrder.getOrderId());
- }
- }
-
- // 2. 有活跃工单 → 升级或忽略
- if (activeOrder != null) {
- String status = activeOrder.getStatus();
-
- if (UPGRADABLE_STATUSES.contains(status)) {
- // 排队中 → 升级优先级一级
- PriorityEnum result = cleanOrderService.upgradeOneLevelPriority(
- activeOrder.getOrderId(), "客流持续达标自动升级");
-
- if (result != null) {
- trafficActiveOrderRedisDAO.updatePriority(areaId, result.getPriority());
- recordUpgradeLog(event, activeOrder.getOrderId(), result);
- log.info("[CleanOrderCreateEventHandler] 工单优先级已升级: areaId={}, orderId={}, newPriority={}",
- areaId, activeOrder.getOrderId(), result);
- } else {
- // 已是 P0,记录审计日志
- recordP0CeilingLog(event, activeOrder.getOrderId());
- log.info("[CleanOrderCreateEventHandler] 工单已是P0封顶,不再升级: areaId={}, orderId={}",
- areaId, activeOrder.getOrderId());
- }
- } else {
- // 已派发/已确认/已到达 → 保洁员已在处理中,静默忽略
- log.info("[CleanOrderCreateEventHandler] 区域{}保洁员已在处理中(状态:{}),客流触发静默忽略: orderId={}",
- areaId, status, activeOrder.getOrderId());
- recordArrivedSilentLog(event, activeOrder.getOrderId());
- }
-
- // ★ 所有分支都重置阈值
- resetTrafficCounter(event);
- return;
- }
-
- // 3. 无活跃工单 → 创建新工单
- CleanOrderAutoCreateReqDTO createReq = buildCreateRequest(event);
- Long orderId = cleanOrderService.createAutoCleanOrder(createReq);
-
- // 标记 Redis 活跃工单
- trafficActiveOrderRedisDAO.markActive(areaId, orderId,
- WorkOrderStatusEnum.PENDING.getStatus(), createReq.getPriority());
-
- // 重置阈值
- resetTrafficCounter(event);
-
- // 记录业务日志
- recordOrderCreatedLog(event, orderId, createReq);
-
- log.info("[CleanOrderCreateEventHandler] 客流工单创建成功: eventId={}, orderId={}, areaId={}",
- event.getEventId(), orderId, areaId);
- }
-
- /**
- * 处理非客流触发的工单创建(原逻辑不变)
- */
- private void handleNonTrafficTrigger(CleanOrderCreateEventDTO event) {
- CleanOrderAutoCreateReqDTO createReq = buildCreateRequest(event);
- Long orderId = cleanOrderService.createAutoCleanOrder(createReq);
-
- recordOrderCreatedLog(event, orderId, createReq);
-
- log.info("[CleanOrderCreateEventHandler] 工单创建成功: eventId={}, orderId={}, areaId={}",
- event.getEventId(), orderId, event.getAreaId());
- }
-
- // ==================== 阈值重置 ====================
-
- /**
- * 重置客流阈值计数器
- */
- private void resetTrafficCounter(CleanOrderCreateEventDTO event) {
- Long deviceId = event.getTriggerDeviceId();
- if (deviceId == null) {
- log.warn("[CleanOrderCreateEventHandler] 缺少设备ID,跳过重置阈值: eventId={}", event.getEventId());
- return;
- }
-
- try {
- ResetTrafficCounterReqDTO reqDTO = ResetTrafficCounterReqDTO.builder()
- .deviceId(deviceId)
- .remark("客流达标后重置阈值计数器")
- .build();
- var result = iotDeviceControlApi.resetTrafficCounter(reqDTO);
-
- if (result.getData() != null && result.getData()) {
- log.info("[CleanOrderCreateEventHandler] 阈值计数器重置成功: deviceId={}", deviceId);
- } else {
- log.error("[CleanOrderCreateEventHandler] 阈值计数器重置失败: deviceId={}", deviceId);
- }
- } catch (Exception e) {
- log.error("[CleanOrderCreateEventHandler] 阈值计数器重置异常: deviceId={}", deviceId, e);
- }
- }
-
- // ==================== DB 兜底查询 ====================
-
- /**
- * 从 DB 查询区域内客流触发的活跃工单(Redis 标记丢失时兜底)
- */
- private ActiveOrderInfo queryActiveTrafficOrderFromDb(Long areaId) {
- OpsOrderDO order = opsOrderMapper.selectActiveTrafficOrder(areaId);
- if (order == null) {
- return null;
- }
- return ActiveOrderInfo.builder()
- .orderId(order.getId())
- .status(order.getStatus())
- .priority(order.getPriority())
- .build();
- }
-
- // ==================== 构建请求 ====================
-
- /**
- * 构建工单创建请求
- */
- private CleanOrderAutoCreateReqDTO buildCreateRequest(CleanOrderCreateEventDTO event) {
- CleanOrderAutoCreateReqDTO createReq = new CleanOrderAutoCreateReqDTO();
- createReq.setOrderType("CLEAN");
- createReq.setSourceType("TRAFFIC");
- createReq.setTitle(generateOrderTitle(event));
- createReq.setDescription(generateOrderDescription(event));
- createReq.setPriority(
- PriorityEnum.fromPriority(event.getPriority() != null ? event.getPriority() : 2).getPriority());
- createReq.setAreaId(event.getAreaId());
-
- // 扩展字段
- createReq.setExpectedDuration(calculateExpectedDuration(event));
- createReq.setCleaningType("ROUTINE");
- createReq.setDifficultyLevel(3);
-
- // IoT集成字段
- createReq.setTriggerSource(event.getTriggerSource());
- createReq.setTriggerRuleId(extractRuleId(event));
- createReq.setTriggerDeviceId(event.getTriggerDeviceId());
- createReq.setTriggerDeviceKey(event.getTriggerDeviceKey());
- createReq.setTriggerData(event.getTriggerData());
-
- return createReq;
- }
-
- // ==================== 业务日志 ====================
-
- /**
- * 记录工单创建业务日志
- */
- private void recordOrderCreatedLog(CleanOrderCreateEventDTO event, Long orderId,
- CleanOrderAutoCreateReqDTO createReq) {
- try {
- EventDomain domain = determineDomain(event.getTriggerSource());
-
- Map extra = new HashMap<>();
- extra.put("eventId", event.getEventId());
- extra.put("triggerSource", event.getTriggerSource());
- extra.put("areaId", event.getAreaId());
- extra.put("priority", createReq.getPriority());
- extra.put("expectedDuration", createReq.getExpectedDuration());
- if (event.getTriggerData() != null) {
- extra.putAll(event.getTriggerData());
- }
-
- eventLogRecorder.record(EventLogRecord.builder()
- .module(LogModule.CLEAN)
- .domain(domain)
- .eventType(LogType.ORDER_CREATED.getCode())
- .message(buildLogMessage(event, createReq))
- .targetId(orderId)
- .targetType("order")
- .deviceId(event.getTriggerDeviceId())
- .level(EventLevel.INFO)
- .payload(extra)
- .build());
-
- } catch (Exception e) {
- log.warn("[CleanOrderCreateEventHandler] 记录业务日志失败: orderId={}", orderId, e);
- }
- }
-
- /**
- * 记录优先级升级日志
- */
- private void recordUpgradeLog(CleanOrderCreateEventDTO event, Long orderId, PriorityEnum newPriority) {
- try {
- Map extra = new HashMap<>();
- extra.put("eventId", event.getEventId());
- extra.put("areaId", event.getAreaId());
- extra.put("newPriority", newPriority.getPriority());
- extra.put("reason", "客流持续达标自动升级");
-
- eventLogRecorder.record(EventLogRecord.builder()
- .module(LogModule.CLEAN)
- .domain(EventDomain.TRAFFIC)
- .eventType(LogType.PRIORITY_UPGRADE.getCode())
- .message(String.format("客流持续达标,工单优先级升级至%s [区域:%d]",
- newPriority.getDescription(), event.getAreaId()))
- .targetId(orderId)
- .targetType("order")
- .deviceId(event.getTriggerDeviceId())
- .level(EventLevel.WARN)
- .payload(extra)
- .build());
-
- } catch (Exception e) {
- log.warn("[CleanOrderCreateEventHandler] 记录升级日志失败: orderId={}", orderId, e);
- }
- }
-
- /**
- * 记录 P0 封顶审计日志
- */
- private void recordP0CeilingLog(CleanOrderCreateEventDTO event, Long orderId) {
- try {
- Map extra = new HashMap<>();
- extra.put("eventId", event.getEventId());
- extra.put("areaId", event.getAreaId());
- extra.put("reason", "已是P0最高优先级,无法继续升级");
-
- eventLogRecorder.record(EventLogRecord.builder()
- .module(LogModule.CLEAN)
- .domain(EventDomain.TRAFFIC)
- .eventType(LogType.PRIORITY_CEILING.getCode())
- .message(String.format("客流持续达标但工单已是P0封顶 [区域:%d]", event.getAreaId()))
- .targetId(orderId)
- .targetType("order")
- .deviceId(event.getTriggerDeviceId())
- .level(EventLevel.WARN)
- .payload(extra)
- .build());
-
- } catch (Exception e) {
- log.warn("[CleanOrderCreateEventHandler] 记录P0封顶日志失败: orderId={}", orderId, e);
- }
- }
-
- /**
- * 记录已派发/已到达静默处理审计日志
- */
- private void recordArrivedSilentLog(CleanOrderCreateEventDTO event, Long orderId) {
- try {
- Map extra = new HashMap<>();
- extra.put("eventId", event.getEventId());
- extra.put("areaId", event.getAreaId());
- extra.put("reason", "保洁员已在处理中,客流触发静默忽略");
-
- eventLogRecorder.record(EventLogRecord.builder()
- .module(LogModule.CLEAN)
- .domain(EventDomain.TRAFFIC)
- .eventType(LogType.ARRIVED_SILENT_IGNORE.getCode())
- .message(String.format("保洁员已在处理中,客流触发静默忽略 [区域:%d]", event.getAreaId()))
- .targetId(orderId)
- .targetType("order")
- .deviceId(event.getTriggerDeviceId())
- .level(EventLevel.INFO)
- .payload(extra)
- .build());
-
- } catch (Exception e) {
- log.warn("[CleanOrderCreateEventHandler] 记录静默处理日志失败: orderId={}", orderId, e);
- }
- }
-
- /**
- * 确定事件域
- */
- private EventDomain determineDomain(String triggerSource) {
- if ("IOT_TRAFFIC".equals(triggerSource)) {
- return EventDomain.TRAFFIC;
- } else if ("IOT_BEACON".equals(triggerSource)) {
- return EventDomain.BEACON;
- } else if ("IOT_SIGNAL_LOSS".equals(triggerSource)) {
- return EventDomain.BEACON;
- }
- return EventDomain.SYSTEM;
- }
-
- /**
- * 构建日志消息
- */
- private String buildLogMessage(CleanOrderCreateEventDTO event, CleanOrderAutoCreateReqDTO createReq) {
- if ("IOT_TRAFFIC".equals(event.getTriggerSource())) {
- return String.format("客流阈值触发工单创建 [设备:%s, 区域:%d]",
- event.getTriggerDeviceKey(), event.getAreaId());
- } else if ("IOT_BEACON".equals(event.getTriggerSource())) {
- return String.format("信标检测触发工单创建 [设备:%s, 区域:%d]",
- event.getTriggerDeviceKey(), event.getAreaId());
- }
- return String.format("IoT设备触发工单创建 [设备:%s, 来源:%s]",
- event.getTriggerDeviceKey(), event.getTriggerSource());
- }
-
- // ==================== 工具方法 ====================
-
- private String generateOrderTitle(CleanOrderCreateEventDTO event) {
- if ("IOT_TRAFFIC".equals(event.getTriggerSource())) {
- return "客流阈值触发保洁";
- } else if ("IOT_BEACON".equals(event.getTriggerSource())) {
- return "信标检测触发保洁";
- } else if ("IOT_SIGNAL_LOSS".equals(event.getTriggerSource())) {
- return "离线超时触发保洁";
- } else {
- return "IoT设备触发保洁";
- }
- }
-
- private String generateOrderDescription(CleanOrderCreateEventDTO event) {
- StringBuilder desc = new StringBuilder();
- desc.append("触发来源: ").append(event.getTriggerSource()).append("\n");
- desc.append("触发设备: ").append(event.getTriggerDeviceKey()).append("\n");
-
- if (event.getTriggerData() != null) {
- if (event.getTriggerData().containsKey("actualCount")) {
- desc.append("当前客流: ").append(event.getTriggerData().get("actualCount")).append("\n");
- }
- if (event.getTriggerData().containsKey("threshold")) {
- desc.append("触发阈值: ").append(event.getTriggerData().get("threshold")).append("\n");
- }
- }
-
- return desc.toString();
- }
-
- private Integer calculateExpectedDuration(CleanOrderCreateEventDTO event) {
- if ("IOT_TRAFFIC".equals(event.getTriggerSource()) && event.getTriggerData() != null) {
- Object actualCountObj = event.getTriggerData().get("actualCount");
- if (actualCountObj != null) {
- Long actualCount = ((Number) actualCountObj).longValue();
- if (actualCount > 50) {
- return 45;
- } else if (actualCount > 20) {
- return 30;
- } else {
- return 20;
- }
- }
- }
- return 30;
- }
-
- private Long extractRuleId(CleanOrderCreateEventDTO event) {
- if (event.getTriggerData() != null && event.getTriggerData().containsKey("ruleId")) {
- Object ruleIdObj = event.getTriggerData().get("ruleId");
- if (ruleIdObj instanceof Number) {
- return ((Number) ruleIdObj).longValue();
- }
- }
- return null;
- }
-}
+package com.viewsh.module.ops.environment.integration.consumer;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.viewsh.module.iot.api.device.IotDeviceControlApi;
+import com.viewsh.module.iot.api.device.dto.ResetTrafficCounterReqDTO;
+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 com.viewsh.module.ops.enums.WorkOrderStatusEnum;
+import com.viewsh.module.ops.environment.service.cleanorder.dto.CleanOrderAutoCreateReqDTO;
+import com.viewsh.module.ops.environment.dal.redis.ActiveOrderInfo;
+import com.viewsh.module.ops.environment.dal.redis.TrafficActiveOrderRedisDAO;
+import com.viewsh.module.ops.environment.integration.dto.CleanOrderCreateEventDTO;
+import com.viewsh.module.ops.environment.service.cleanorder.CleanOrderService;
+import com.viewsh.module.ops.infrastructure.log.enumeration.EventDomain;
+import com.viewsh.module.ops.infrastructure.log.enumeration.EventLevel;
+import com.viewsh.module.ops.infrastructure.log.enumeration.LogModule;
+import com.viewsh.module.ops.infrastructure.log.enumeration.LogType;
+import com.viewsh.module.ops.infrastructure.log.recorder.EventLogRecord;
+import com.viewsh.module.ops.infrastructure.log.recorder.EventLogRecorder;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.rocketmq.spring.annotation.ConsumeMode;
+import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
+import org.apache.rocketmq.spring.core.RocketMQListener;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 保洁工单创建事件消费者
+ *
+ * 订阅 IoT 模块发布的保洁工单创建事件。
+ *
+ * 客流触发逻辑(周期化):
+ * 1. 无活跃工单 → 创建新工单 → 标记活跃 → 重置阈值
+ * 2. 有排队中工单(PENDING/QUEUED) → 升级优先级一级 → 重置阈值
+ * 3. 有已派发/已到达工单(DISPATCHED/CONFIRMED/ARRIVED) → 静默处理,不升级不创建 → 重置阈值
+ * 4. 已是 P0 → 不升级,记录审计日志 → 重置阈值
+ *
+ * RocketMQ 配置:
+ * - Topic: ops-order-create
+ * - ConsumerGroup: ops-clean-order-create-group
+ *
+ * @author AI
+ */
+@Slf4j
+@Component
+@RocketMQMessageListener(
+ topic = "ops-order-create",
+ consumerGroup = "ops-clean-order-create-group",
+ consumeMode = ConsumeMode.CONCURRENTLY,
+ selectorExpression = "*",
+ accessKey = "${rocketmq.consumer.access-key:}",
+ secretKey = "${rocketmq.consumer.secret-key:}"
+)
+public class CleanOrderCreateEventHandler implements RocketMQListener {
+
+ /**
+ * 幂等性控制 Key 模式
+ */
+ private static final String DEDUP_KEY_PATTERN = "ops:clean:dedup:create:%s";
+
+ /**
+ * 幂等性控制 TTL(秒)
+ */
+ private static final int DEDUP_TTL_SECONDS = 300;
+
+ /**
+ * 可升级优先级的状态集合(仅排队中,尚未派发)
+ */
+ private static final Set UPGRADABLE_STATUSES = Set.of(
+ WorkOrderStatusEnum.PENDING.getStatus(),
+ WorkOrderStatusEnum.QUEUED.getStatus()
+ );
+
+ @Resource
+ private ObjectMapper objectMapper;
+
+ @Resource
+ private StringRedisTemplate stringRedisTemplate;
+
+ @Resource
+ private CleanOrderService cleanOrderService;
+
+ @Resource
+ private EventLogRecorder eventLogRecorder;
+
+ @Resource
+ private TrafficActiveOrderRedisDAO trafficActiveOrderRedisDAO;
+
+ @Resource
+ private IotDeviceControlApi iotDeviceControlApi;
+
+ @Resource
+ private OpsOrderMapper opsOrderMapper;
+
+ @Override
+ public void onMessage(String message) {
+ try {
+ // 1. JSON 反序列化
+ CleanOrderCreateEventDTO event = objectMapper.readValue(message, CleanOrderCreateEventDTO.class);
+
+ // 2. 幂等性检查
+ String dedupKey = String.format(DEDUP_KEY_PATTERN, event.getEventId());
+ Boolean firstTime = stringRedisTemplate.opsForValue()
+ .setIfAbsent(dedupKey, "1", DEDUP_TTL_SECONDS, TimeUnit.SECONDS);
+
+ if (!Boolean.TRUE.equals(firstTime)) {
+ log.debug("[CleanOrderCreateEventHandler] 重复消息,跳过处理: eventId={}", event.getEventId());
+ return;
+ }
+
+ // 3. 业务处理
+ handleOrderCreate(event);
+
+ } catch (Exception e) {
+ log.error("[CleanOrderCreateEventHandler] 消息处理失败: message={}", message, e);
+ throw new RuntimeException("保洁工单创建事件处理失败", e);
+ }
+ }
+
+ /**
+ * 处理工单创建
+ */
+ private void handleOrderCreate(CleanOrderCreateEventDTO event) {
+ log.info("[CleanOrderCreateEventHandler] 收到工单创建事件: eventId={}, areaId={}, triggerSource={}",
+ event.getEventId(), event.getAreaId(), event.getTriggerSource());
+
+ // 客流触发 → 周期化逻辑
+ if ("IOT_TRAFFIC".equals(event.getTriggerSource())) {
+ handleTrafficTrigger(event);
+ return;
+ }
+
+ // 非客流触发 → 原逻辑
+ handleNonTrafficTrigger(event);
+ }
+
+ /**
+ * 处理客流触发的工单创建(周期化逻辑)
+ */
+ private void handleTrafficTrigger(CleanOrderCreateEventDTO event) {
+ Long areaId = event.getAreaId();
+
+ // 1. 查询活跃工单(Redis 优先,DB 兜底)
+ ActiveOrderInfo activeOrder = trafficActiveOrderRedisDAO.getActive(areaId);
+ if (activeOrder == null) {
+ activeOrder = queryActiveTrafficOrderFromDb(areaId);
+ if (activeOrder != null) {
+ // 恢复 Redis 标记
+ trafficActiveOrderRedisDAO.markActive(areaId, activeOrder.getOrderId(),
+ activeOrder.getStatus(), activeOrder.getPriority());
+ log.info("[CleanOrderCreateEventHandler] Redis标记丢失已恢复: areaId={}, orderId={}",
+ areaId, activeOrder.getOrderId());
+ }
+ }
+
+ // 2. 有活跃工单 → 升级或忽略
+ if (activeOrder != null) {
+ String status = activeOrder.getStatus();
+
+ if (UPGRADABLE_STATUSES.contains(status)) {
+ // 排队中 → 升级优先级一级
+ PriorityEnum result = cleanOrderService.upgradeOneLevelPriority(
+ activeOrder.getOrderId(), "客流持续达标自动升级");
+
+ if (result != null) {
+ trafficActiveOrderRedisDAO.updatePriority(areaId, result.getPriority());
+ recordUpgradeLog(event, activeOrder.getOrderId(), result);
+ log.info("[CleanOrderCreateEventHandler] 工单优先级已升级: areaId={}, orderId={}, newPriority={}",
+ areaId, activeOrder.getOrderId(), result);
+ } else {
+ // 已是 P0,记录审计日志
+ recordP0CeilingLog(event, activeOrder.getOrderId());
+ log.info("[CleanOrderCreateEventHandler] 工单已是P0封顶,不再升级: areaId={}, orderId={}",
+ areaId, activeOrder.getOrderId());
+ }
+ } else {
+ // 已派发/已确认/已到达 → 保洁员已在处理中,静默忽略
+ log.info("[CleanOrderCreateEventHandler] 区域{}保洁员已在处理中(状态:{}),客流触发静默忽略: orderId={}",
+ areaId, status, activeOrder.getOrderId());
+ recordArrivedSilentLog(event, activeOrder.getOrderId());
+ }
+
+ // ★ 所有分支都重置阈值
+ resetTrafficCounter(event);
+ return;
+ }
+
+ // 3. 无活跃工单 → 创建新工单
+ CleanOrderAutoCreateReqDTO createReq = buildCreateRequest(event);
+ Long orderId = cleanOrderService.createAutoCleanOrder(createReq);
+
+ // 标记 Redis 活跃工单
+ trafficActiveOrderRedisDAO.markActive(areaId, orderId,
+ WorkOrderStatusEnum.PENDING.getStatus(), createReq.getPriority());
+
+ // 重置阈值
+ resetTrafficCounter(event);
+
+ // 记录业务日志
+ recordOrderCreatedLog(event, orderId, createReq);
+
+ log.info("[CleanOrderCreateEventHandler] 客流工单创建成功: eventId={}, orderId={}, areaId={}",
+ event.getEventId(), orderId, areaId);
+ }
+
+ /**
+ * 处理非客流触发的工单创建(原逻辑不变)
+ */
+ private void handleNonTrafficTrigger(CleanOrderCreateEventDTO event) {
+ CleanOrderAutoCreateReqDTO createReq = buildCreateRequest(event);
+ Long orderId = cleanOrderService.createAutoCleanOrder(createReq);
+
+ recordOrderCreatedLog(event, orderId, createReq);
+
+ log.info("[CleanOrderCreateEventHandler] 工单创建成功: eventId={}, orderId={}, areaId={}",
+ event.getEventId(), orderId, event.getAreaId());
+ }
+
+ // ==================== 阈值重置 ====================
+
+ /**
+ * 重置客流阈值计数器
+ */
+ private void resetTrafficCounter(CleanOrderCreateEventDTO event) {
+ Long deviceId = event.getTriggerDeviceId();
+ if (deviceId == null) {
+ log.warn("[CleanOrderCreateEventHandler] 缺少设备ID,跳过重置阈值: eventId={}", event.getEventId());
+ return;
+ }
+
+ try {
+ ResetTrafficCounterReqDTO reqDTO = ResetTrafficCounterReqDTO.builder()
+ .deviceId(deviceId)
+ .remark("客流达标后重置阈值计数器")
+ .build();
+ var result = iotDeviceControlApi.resetTrafficCounter(reqDTO);
+
+ if (result.getData() != null && result.getData()) {
+ log.info("[CleanOrderCreateEventHandler] 阈值计数器重置成功: deviceId={}", deviceId);
+ } else {
+ log.error("[CleanOrderCreateEventHandler] 阈值计数器重置失败: deviceId={}", deviceId);
+ }
+ } catch (Exception e) {
+ log.error("[CleanOrderCreateEventHandler] 阈值计数器重置异常: deviceId={}", deviceId, e);
+ }
+ }
+
+ // ==================== DB 兜底查询 ====================
+
+ /**
+ * 从 DB 查询区域内客流触发的活跃工单(Redis 标记丢失时兜底)
+ */
+ private ActiveOrderInfo queryActiveTrafficOrderFromDb(Long areaId) {
+ OpsOrderDO order = opsOrderMapper.selectActiveTrafficOrder(areaId);
+ if (order == null) {
+ return null;
+ }
+ return ActiveOrderInfo.builder()
+ .orderId(order.getId())
+ .status(order.getStatus())
+ .priority(order.getPriority())
+ .build();
+ }
+
+ // ==================== 构建请求 ====================
+
+ /**
+ * 构建工单创建请求
+ */
+ private CleanOrderAutoCreateReqDTO buildCreateRequest(CleanOrderCreateEventDTO event) {
+ CleanOrderAutoCreateReqDTO createReq = new CleanOrderAutoCreateReqDTO();
+ createReq.setOrderType("CLEAN");
+ createReq.setSourceType("TRAFFIC");
+ createReq.setTitle(generateOrderTitle(event));
+ createReq.setDescription(generateOrderDescription(event));
+ createReq.setPriority(
+ PriorityEnum.fromPriority(event.getPriority() != null ? event.getPriority() : 2).getPriority());
+ createReq.setAreaId(event.getAreaId());
+
+ // 扩展字段
+ createReq.setExpectedDuration(calculateExpectedDuration(event));
+ createReq.setCleaningType("ROUTINE");
+ createReq.setDifficultyLevel(3);
+
+ // IoT集成字段
+ createReq.setTriggerSource(event.getTriggerSource());
+ createReq.setTriggerRuleId(extractRuleId(event));
+ createReq.setTriggerDeviceId(event.getTriggerDeviceId());
+ createReq.setTriggerDeviceKey(event.getTriggerDeviceKey());
+ createReq.setTriggerData(event.getTriggerData());
+
+ return createReq;
+ }
+
+ // ==================== 业务日志 ====================
+
+ /**
+ * 记录工单创建业务日志
+ */
+ private void recordOrderCreatedLog(CleanOrderCreateEventDTO event, Long orderId,
+ CleanOrderAutoCreateReqDTO createReq) {
+ try {
+ EventDomain domain = determineDomain(event.getTriggerSource());
+
+ Map extra = new HashMap<>();
+ extra.put("eventId", event.getEventId());
+ extra.put("triggerSource", event.getTriggerSource());
+ extra.put("areaId", event.getAreaId());
+ extra.put("priority", createReq.getPriority());
+ extra.put("expectedDuration", createReq.getExpectedDuration());
+ if (event.getTriggerData() != null) {
+ extra.putAll(event.getTriggerData());
+ }
+
+ eventLogRecorder.record(EventLogRecord.builder()
+ .module(LogModule.CLEAN)
+ .domain(domain)
+ .eventType(LogType.ORDER_CREATED.getCode())
+ .message(buildLogMessage(event, createReq))
+ .targetId(orderId)
+ .targetType("order")
+ .deviceId(event.getTriggerDeviceId())
+ .level(EventLevel.INFO)
+ .payload(extra)
+ .build());
+
+ } catch (Exception e) {
+ log.warn("[CleanOrderCreateEventHandler] 记录业务日志失败: orderId={}", orderId, e);
+ }
+ }
+
+ /**
+ * 记录优先级升级日志
+ */
+ private void recordUpgradeLog(CleanOrderCreateEventDTO event, Long orderId, PriorityEnum newPriority) {
+ try {
+ Map extra = new HashMap<>();
+ extra.put("eventId", event.getEventId());
+ extra.put("areaId", event.getAreaId());
+ extra.put("newPriority", newPriority.getPriority());
+ extra.put("reason", "客流持续达标自动升级");
+
+ eventLogRecorder.record(EventLogRecord.builder()
+ .module(LogModule.CLEAN)
+ .domain(EventDomain.TRAFFIC)
+ .eventType(LogType.PRIORITY_UPGRADE.getCode())
+ .message(String.format("客流持续达标,工单优先级升级至%s [区域:%d]",
+ newPriority.getDescription(), event.getAreaId()))
+ .targetId(orderId)
+ .targetType("order")
+ .deviceId(event.getTriggerDeviceId())
+ .level(EventLevel.WARN)
+ .payload(extra)
+ .build());
+
+ } catch (Exception e) {
+ log.warn("[CleanOrderCreateEventHandler] 记录升级日志失败: orderId={}", orderId, e);
+ }
+ }
+
+ /**
+ * 记录 P0 封顶审计日志
+ */
+ private void recordP0CeilingLog(CleanOrderCreateEventDTO event, Long orderId) {
+ try {
+ Map extra = new HashMap<>();
+ extra.put("eventId", event.getEventId());
+ extra.put("areaId", event.getAreaId());
+ extra.put("reason", "已是P0最高优先级,无法继续升级");
+
+ eventLogRecorder.record(EventLogRecord.builder()
+ .module(LogModule.CLEAN)
+ .domain(EventDomain.TRAFFIC)
+ .eventType(LogType.PRIORITY_CEILING.getCode())
+ .message(String.format("客流持续达标但工单已是P0封顶 [区域:%d]", event.getAreaId()))
+ .targetId(orderId)
+ .targetType("order")
+ .deviceId(event.getTriggerDeviceId())
+ .level(EventLevel.WARN)
+ .payload(extra)
+ .build());
+
+ } catch (Exception e) {
+ log.warn("[CleanOrderCreateEventHandler] 记录P0封顶日志失败: orderId={}", orderId, e);
+ }
+ }
+
+ /**
+ * 记录已派发/已到达静默处理审计日志
+ */
+ private void recordArrivedSilentLog(CleanOrderCreateEventDTO event, Long orderId) {
+ try {
+ Map extra = new HashMap<>();
+ extra.put("eventId", event.getEventId());
+ extra.put("areaId", event.getAreaId());
+ extra.put("reason", "保洁员已在处理中,客流触发静默忽略");
+
+ eventLogRecorder.record(EventLogRecord.builder()
+ .module(LogModule.CLEAN)
+ .domain(EventDomain.TRAFFIC)
+ .eventType(LogType.ARRIVED_SILENT_IGNORE.getCode())
+ .message(String.format("保洁员已在处理中,客流触发静默忽略 [区域:%d]", event.getAreaId()))
+ .targetId(orderId)
+ .targetType("order")
+ .deviceId(event.getTriggerDeviceId())
+ .level(EventLevel.INFO)
+ .payload(extra)
+ .build());
+
+ } catch (Exception e) {
+ log.warn("[CleanOrderCreateEventHandler] 记录静默处理日志失败: orderId={}", orderId, e);
+ }
+ }
+
+ /**
+ * 确定事件域
+ */
+ private EventDomain determineDomain(String triggerSource) {
+ if ("IOT_TRAFFIC".equals(triggerSource)) {
+ return EventDomain.TRAFFIC;
+ } else if ("IOT_BEACON".equals(triggerSource)) {
+ return EventDomain.BEACON;
+ } else if ("IOT_SIGNAL_LOSS".equals(triggerSource)) {
+ return EventDomain.BEACON;
+ }
+ return EventDomain.SYSTEM;
+ }
+
+ /**
+ * 构建日志消息
+ */
+ private String buildLogMessage(CleanOrderCreateEventDTO event, CleanOrderAutoCreateReqDTO createReq) {
+ if ("IOT_TRAFFIC".equals(event.getTriggerSource())) {
+ return String.format("客流阈值触发工单创建 [设备:%s, 区域:%d]",
+ event.getTriggerDeviceKey(), event.getAreaId());
+ } else if ("IOT_BEACON".equals(event.getTriggerSource())) {
+ return String.format("信标检测触发工单创建 [设备:%s, 区域:%d]",
+ event.getTriggerDeviceKey(), event.getAreaId());
+ }
+ return String.format("IoT设备触发工单创建 [设备:%s, 来源:%s]",
+ event.getTriggerDeviceKey(), event.getTriggerSource());
+ }
+
+ // ==================== 工具方法 ====================
+
+ private String generateOrderTitle(CleanOrderCreateEventDTO event) {
+ if ("IOT_TRAFFIC".equals(event.getTriggerSource())) {
+ return "客流阈值触发保洁";
+ } else if ("IOT_BEACON".equals(event.getTriggerSource())) {
+ return "信标检测触发保洁";
+ } else if ("IOT_SIGNAL_LOSS".equals(event.getTriggerSource())) {
+ return "离线超时触发保洁";
+ } else {
+ return "IoT设备触发保洁";
+ }
+ }
+
+ private String generateOrderDescription(CleanOrderCreateEventDTO event) {
+ StringBuilder desc = new StringBuilder();
+ desc.append("触发来源: ").append(event.getTriggerSource()).append("\n");
+ desc.append("触发设备: ").append(event.getTriggerDeviceKey()).append("\n");
+
+ if (event.getTriggerData() != null) {
+ if (event.getTriggerData().containsKey("actualCount")) {
+ desc.append("当前客流: ").append(event.getTriggerData().get("actualCount")).append("\n");
+ }
+ if (event.getTriggerData().containsKey("threshold")) {
+ desc.append("触发阈值: ").append(event.getTriggerData().get("threshold")).append("\n");
+ }
+ }
+
+ return desc.toString();
+ }
+
+ private Integer calculateExpectedDuration(CleanOrderCreateEventDTO event) {
+ if ("IOT_TRAFFIC".equals(event.getTriggerSource()) && event.getTriggerData() != null) {
+ Object actualCountObj = event.getTriggerData().get("actualCount");
+ if (actualCountObj != null) {
+ Long actualCount = ((Number) actualCountObj).longValue();
+ if (actualCount > 50) {
+ return 45;
+ } else if (actualCount > 20) {
+ return 30;
+ } else {
+ return 20;
+ }
+ }
+ }
+ return 30;
+ }
+
+ private Long extractRuleId(CleanOrderCreateEventDTO event) {
+ if (event.getTriggerData() != null && event.getTriggerData().containsKey("ruleId")) {
+ Object ruleIdObj = event.getTriggerData().get("ruleId");
+ if (ruleIdObj instanceof Number) {
+ return ((Number) ruleIdObj).longValue();
+ }
+ }
+ return null;
+ }
+}
diff --git a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/badge/CleanBadgeService.java b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/badge/CleanBadgeService.java
index aa241eb..ca5e1b4 100644
--- a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/badge/CleanBadgeService.java
+++ b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/badge/CleanBadgeService.java
@@ -3,7 +3,7 @@ package com.viewsh.module.ops.environment.service.badge;
import com.viewsh.module.ops.api.badge.BadgeDeviceStatusDTO;
import com.viewsh.module.ops.api.clean.BadgeRealtimeStatusRespDTO;
import com.viewsh.module.ops.api.clean.BadgeStatusRespDTO;
-import com.viewsh.module.ops.environment.dal.dataobject.BadgeNotifyReqDTO;
+import com.viewsh.module.ops.environment.service.badge.dto.BadgeNotifyReqDTO;
import java.util.List;
diff --git a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/badge/CleanBadgeServiceImpl.java b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/badge/CleanBadgeServiceImpl.java
index a2a6a48..3ad62fb 100644
--- a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/badge/CleanBadgeServiceImpl.java
+++ b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/badge/CleanBadgeServiceImpl.java
@@ -5,7 +5,7 @@ import com.viewsh.module.iot.api.device.dto.IotDeviceServiceInvokeReqDTO;
import com.viewsh.module.ops.api.badge.BadgeDeviceStatusDTO;
import com.viewsh.module.ops.api.clean.BadgeRealtimeStatusRespDTO;
import com.viewsh.module.ops.api.clean.BadgeStatusRespDTO;
-import com.viewsh.module.ops.environment.dal.dataobject.BadgeNotifyReqDTO;
+import com.viewsh.module.ops.environment.service.badge.dto.BadgeNotifyReqDTO;
import com.viewsh.module.ops.service.area.AreaDeviceService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
diff --git a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/dal/dataobject/BadgeNotifyReqDTO.java b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/badge/dto/BadgeNotifyReqDTO.java
similarity index 93%
rename from viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/dal/dataobject/BadgeNotifyReqDTO.java
rename to viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/badge/dto/BadgeNotifyReqDTO.java
index eb45094..0720c02 100644
--- a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/dal/dataobject/BadgeNotifyReqDTO.java
+++ b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/badge/dto/BadgeNotifyReqDTO.java
@@ -1,4 +1,4 @@
-package com.viewsh.module.ops.environment.dal.dataobject;
+package com.viewsh.module.ops.environment.service.badge.dto;
import com.viewsh.module.ops.enums.NotifyTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
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 f839391..f9784c3 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,7 +1,7 @@
package com.viewsh.module.ops.environment.service.cleanorder;
import com.viewsh.module.ops.enums.PriorityEnum;
-import com.viewsh.module.ops.environment.dal.dataobject.CleanOrderAutoCreateReqDTO;
+import com.viewsh.module.ops.environment.service.cleanorder.dto.CleanOrderAutoCreateReqDTO;
/**
* 保洁工单服务
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 38cf86c..a2287bf 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
@@ -15,7 +15,7 @@ import com.viewsh.module.ops.dal.mysql.workorder.OpsOrderMapper;
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.service.cleanorder.dto.CleanOrderAutoCreateReqDTO;
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.integration.listener.CleanOrderEventListener;
diff --git a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/cleanorder/CleanWorkOrderService.java b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/cleanorder/CleanWorkOrderService.java
index 8d32271..68c9b00 100644
--- a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/cleanorder/CleanWorkOrderService.java
+++ b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/cleanorder/CleanWorkOrderService.java
@@ -1,8 +1,8 @@
package com.viewsh.module.ops.environment.service.cleanorder;
import com.viewsh.module.ops.api.clean.OrderTimelineRespDTO;
-import com.viewsh.module.ops.environment.dal.dataobject.ManualCompleteOrderReqDTO;
-import com.viewsh.module.ops.environment.dal.dataobject.UpgradePriorityReqDTO;
+import com.viewsh.module.ops.environment.service.cleanorder.dto.ManualCompleteOrderReqDTO;
+import com.viewsh.module.ops.environment.service.cleanorder.dto.UpgradePriorityReqDTO;
/**
* 保洁工单服务接口
diff --git a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/cleanorder/CleanWorkOrderServiceImpl.java b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/cleanorder/CleanWorkOrderServiceImpl.java
index d127753..af3cf68 100644
--- a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/cleanorder/CleanWorkOrderServiceImpl.java
+++ b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/cleanorder/CleanWorkOrderServiceImpl.java
@@ -9,8 +9,8 @@ import com.viewsh.module.ops.dal.mysql.workorder.OpsOrderEventMapper;
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.dal.dataobject.ManualCompleteOrderReqDTO;
-import com.viewsh.module.ops.environment.dal.dataobject.UpgradePriorityReqDTO;
+import com.viewsh.module.ops.environment.service.cleanorder.dto.ManualCompleteOrderReqDTO;
+import com.viewsh.module.ops.environment.service.cleanorder.dto.UpgradePriorityReqDTO;
import com.viewsh.module.ops.service.event.OpsOrderEventService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
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/service/cleanorder/dto/CleanOrderAutoCreateReqDTO.java
similarity index 93%
rename from viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/dal/dataobject/CleanOrderAutoCreateReqDTO.java
rename to viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/cleanorder/dto/CleanOrderAutoCreateReqDTO.java
index 9c1a7a2..8c67fa1 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/service/cleanorder/dto/CleanOrderAutoCreateReqDTO.java
@@ -1,6 +1,6 @@
-package com.viewsh.module.ops.environment.dal.dataobject;
+package com.viewsh.module.ops.environment.service.cleanorder.dto;
-import com.viewsh.module.ops.dal.dataobject.dto.OpsOrderCreateReqDTO;
+import com.viewsh.module.ops.service.order.dto.OpsOrderCreateReqDTO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
diff --git a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/dal/dataobject/CleanOrderPauseReqDTO.java b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/cleanorder/dto/CleanOrderPauseReqDTO.java
similarity index 93%
rename from viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/dal/dataobject/CleanOrderPauseReqDTO.java
rename to viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/cleanorder/dto/CleanOrderPauseReqDTO.java
index bde816c..c5364d8 100644
--- a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/dal/dataobject/CleanOrderPauseReqDTO.java
+++ b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/cleanorder/dto/CleanOrderPauseReqDTO.java
@@ -1,4 +1,4 @@
-package com.viewsh.module.ops.environment.dal.dataobject;
+package com.viewsh.module.ops.environment.service.cleanorder.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
diff --git a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/dal/dataobject/CleanOrderResumeReqDTO.java b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/cleanorder/dto/CleanOrderResumeReqDTO.java
similarity index 90%
rename from viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/dal/dataobject/CleanOrderResumeReqDTO.java
rename to viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/cleanorder/dto/CleanOrderResumeReqDTO.java
index bc3b2e4..fc9dd8b 100644
--- a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/dal/dataobject/CleanOrderResumeReqDTO.java
+++ b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/cleanorder/dto/CleanOrderResumeReqDTO.java
@@ -1,4 +1,4 @@
-package com.viewsh.module.ops.environment.dal.dataobject;
+package com.viewsh.module.ops.environment.service.cleanorder.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
diff --git a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/dal/dataobject/ManualCompleteOrderReqDTO.java b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/cleanorder/dto/ManualCompleteOrderReqDTO.java
similarity index 91%
rename from viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/dal/dataobject/ManualCompleteOrderReqDTO.java
rename to viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/cleanorder/dto/ManualCompleteOrderReqDTO.java
index 3d0bdf5..43e03df 100644
--- a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/dal/dataobject/ManualCompleteOrderReqDTO.java
+++ b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/cleanorder/dto/ManualCompleteOrderReqDTO.java
@@ -1,4 +1,4 @@
-package com.viewsh.module.ops.environment.dal.dataobject;
+package com.viewsh.module.ops.environment.service.cleanorder.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
diff --git a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/dal/dataobject/UpgradePriorityReqDTO.java b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/cleanorder/dto/UpgradePriorityReqDTO.java
similarity index 92%
rename from viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/dal/dataobject/UpgradePriorityReqDTO.java
rename to viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/cleanorder/dto/UpgradePriorityReqDTO.java
index 7a5e628..e311e31 100644
--- a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/dal/dataobject/UpgradePriorityReqDTO.java
+++ b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/cleanorder/dto/UpgradePriorityReqDTO.java
@@ -1,4 +1,4 @@
-package com.viewsh.module.ops.environment.dal.dataobject;
+package com.viewsh.module.ops.environment.service.cleanorder.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
diff --git a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/inspection/InspectionRectificationServiceImpl.java b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/inspection/InspectionRectificationServiceImpl.java
index 7cb8557..26312c8 100644
--- a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/inspection/InspectionRectificationServiceImpl.java
+++ b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/inspection/InspectionRectificationServiceImpl.java
@@ -2,7 +2,7 @@ package com.viewsh.module.ops.environment.service.inspection;
import com.viewsh.module.ops.dal.dataobject.area.OpsBusAreaDO;
import com.viewsh.module.ops.dal.mysql.area.OpsBusAreaMapper;
-import com.viewsh.module.ops.environment.dal.dataobject.CleanOrderAutoCreateReqDTO;
+import com.viewsh.module.ops.environment.service.cleanorder.dto.CleanOrderAutoCreateReqDTO;
import com.viewsh.module.ops.environment.dal.dataobject.inspection.OpsInspectionRecordDO;
import com.viewsh.module.ops.environment.dal.mysql.inspection.OpsInspectionRecordMapper;
import com.viewsh.module.ops.environment.service.cleanorder.CleanOrderService;
diff --git a/viewsh-module-ops/viewsh-module-ops-server/src/main/java/com/viewsh/module/ops/controller/admin/clean/CleanBadgeController.java b/viewsh-module-ops/viewsh-module-ops-server/src/main/java/com/viewsh/module/ops/controller/admin/clean/CleanBadgeController.java
index f6d5a3e..ebefd67 100644
--- a/viewsh-module-ops/viewsh-module-ops-server/src/main/java/com/viewsh/module/ops/controller/admin/clean/CleanBadgeController.java
+++ b/viewsh-module-ops/viewsh-module-ops-server/src/main/java/com/viewsh/module/ops/controller/admin/clean/CleanBadgeController.java
@@ -3,7 +3,7 @@ package com.viewsh.module.ops.controller.admin.clean;
import com.viewsh.framework.common.pojo.CommonResult;
import com.viewsh.module.ops.api.clean.BadgeRealtimeStatusRespDTO;
import com.viewsh.module.ops.api.clean.BadgeStatusRespDTO;
-import com.viewsh.module.ops.environment.dal.dataobject.BadgeNotifyReqDTO;
+import com.viewsh.module.ops.environment.service.badge.dto.BadgeNotifyReqDTO;
import com.viewsh.module.ops.environment.service.badge.CleanBadgeService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
diff --git a/viewsh-module-ops/viewsh-module-ops-server/src/main/java/com/viewsh/module/ops/controller/admin/clean/CleanDeviceController.java b/viewsh-module-ops/viewsh-module-ops-server/src/main/java/com/viewsh/module/ops/controller/admin/clean/CleanDeviceController.java
index a92ee4d..d52b7a8 100644
--- a/viewsh-module-ops/viewsh-module-ops-server/src/main/java/com/viewsh/module/ops/controller/admin/clean/CleanDeviceController.java
+++ b/viewsh-module-ops/viewsh-module-ops-server/src/main/java/com/viewsh/module/ops/controller/admin/clean/CleanDeviceController.java
@@ -1,7 +1,7 @@
package com.viewsh.module.ops.controller.admin.clean;
import com.viewsh.framework.common.pojo.CommonResult;
-import com.viewsh.module.ops.environment.dal.dataobject.BadgeNotifyReqDTO;
+import com.viewsh.module.ops.environment.service.badge.dto.BadgeNotifyReqDTO;
import com.viewsh.module.ops.environment.service.badge.CleanBadgeService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
diff --git a/viewsh-module-ops/viewsh-module-ops-server/src/main/java/com/viewsh/module/ops/controller/admin/clean/CleanWorkOrderController.java b/viewsh-module-ops/viewsh-module-ops-server/src/main/java/com/viewsh/module/ops/controller/admin/clean/CleanWorkOrderController.java
index 2842d81..1b878d9 100644
--- a/viewsh-module-ops/viewsh-module-ops-server/src/main/java/com/viewsh/module/ops/controller/admin/clean/CleanWorkOrderController.java
+++ b/viewsh-module-ops/viewsh-module-ops-server/src/main/java/com/viewsh/module/ops/controller/admin/clean/CleanWorkOrderController.java
@@ -3,8 +3,8 @@ package com.viewsh.module.ops.controller.admin.clean;
import com.viewsh.framework.common.pojo.CommonResult;
import com.viewsh.framework.security.core.util.SecurityFrameworkUtils;
import com.viewsh.module.ops.api.clean.OrderTimelineRespDTO;
-import com.viewsh.module.ops.environment.dal.dataobject.ManualCompleteOrderReqDTO;
-import com.viewsh.module.ops.environment.dal.dataobject.UpgradePriorityReqDTO;
+import com.viewsh.module.ops.environment.service.cleanorder.dto.ManualCompleteOrderReqDTO;
+import com.viewsh.module.ops.environment.service.cleanorder.dto.UpgradePriorityReqDTO;
import com.viewsh.module.ops.environment.service.badge.BadgeDeviceStatusService;
import com.viewsh.module.ops.environment.service.cleanorder.CleanWorkOrderService;
import io.swagger.v3.oas.annotations.Operation;
@@ -21,6 +21,10 @@ import static com.viewsh.framework.common.pojo.CommonResult.success;
/**
* 管理后台 - 保洁工单 Controller
+ *
+ * 职责边界:提供保洁条线特有的业务操作,包括手动完单、优先级升级、工单时间线查询等。
+ * 通用的工单 CRUD 和状态转换接口请使用
+ * {@link com.viewsh.module.ops.controller.admin.OpsOrderController}。
*
* @author lzh
*/