From 28b9a32cb641dac1b5c35d40dd19722ee59ddd81 Mon Sep 17 00:00:00 2001 From: lzh Date: Fri, 30 Jan 2026 12:03:24 +0800 Subject: [PATCH] =?UTF-8?q?feat(ops):=20=E4=BA=8B=E4=BB=B6=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E5=A2=9E=E5=BC=BA=E4=B8=8E=E7=A9=BA=E9=97=B2=E8=AE=BE?= =?UTF-8?q?=E5=A4=87=E5=BE=85=E5=8A=9E=E6=A3=80=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 实现空闲设备待办工单检查定时任务 - 修复事件日志 orderId 关联 (使用 targetId) - 增强语音播报和工单事件的日志完整性 --- .../consumer/CleanOrderAuditEventHandler.java | 16 +- .../CleanOrderCreateEventHandler.java | 14 +- .../BadgeDeviceStatusEventListener.java | 58 +++++-- .../listener/CleanOrderEventListener.java | 11 +- .../job/IdleDevicePendingOrderCheckJob.java | 144 ++++++++++++++++++ .../service/voice/VoiceBroadcastService.java | 60 +++++++- .../log/recorder/EventLogRecord.java | 11 +- .../log/recorder/EventLogRecorderImpl.java | 21 ++- 8 files changed, 285 insertions(+), 50 deletions(-) create mode 100644 viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/job/IdleDevicePendingOrderCheckJob.java diff --git a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/integration/consumer/CleanOrderAuditEventHandler.java b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/integration/consumer/CleanOrderAuditEventHandler.java index 664afea..cb582f9 100644 --- a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/integration/consumer/CleanOrderAuditEventHandler.java +++ b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/integration/consumer/CleanOrderAuditEventHandler.java @@ -36,12 +36,7 @@ import java.util.concurrent.TimeUnit; */ @Slf4j @Component -@RocketMQMessageListener( - topic = "ops-order-audit", - consumerGroup = "ops-clean-order-audit-group", - consumeMode = ConsumeMode.CONCURRENTLY, - selectorExpression = "*" -) +@RocketMQMessageListener(topic = "ops-order-audit", consumerGroup = "ops-clean-order-audit-group", consumeMode = ConsumeMode.CONCURRENTLY, selectorExpression = "*") public class CleanOrderAuditEventHandler implements RocketMQListener { /** @@ -148,7 +143,7 @@ public class CleanOrderAuditEventHandler implements RocketMQListener { return; } - sendTts(event.getDeviceId(), ttsText); + sendTts(event.getDeviceId(), ttsText, event.getOrderId()); } /** @@ -187,15 +182,16 @@ public class CleanOrderAuditEventHandler implements RocketMQListener { String ttsText = CleanNotificationConstants.VoiceBuilder.buildQuery(currentOrderTitle, pendingCount.intValue()); // 4. 下发 TTS - sendTts(deviceId, ttsText); + Long orderId = currentOrder != null ? currentOrder.getId() : null; + sendTts(deviceId, ttsText, orderId); } /** * 下发 TTS 语音播报 */ - private void sendTts(Long deviceId, String text) { + private void sendTts(Long deviceId, String text, Long orderId) { try { - voiceBroadcastService.broadcast(deviceId, text); + voiceBroadcastService.broadcast(deviceId, text, orderId); log.info("[CleanOrderAuditEventHandler] TTS 下发成功: deviceId={}, text={}", deviceId, text); } catch (Exception e) { log.error("[CleanOrderAuditEventHandler] TTS 下发异常: deviceId={}", deviceId, e); 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 53f51df..6f171cf 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 @@ -34,12 +34,7 @@ import java.util.concurrent.TimeUnit; */ @Slf4j @Component -@RocketMQMessageListener( - topic = "ops-order-create", - consumerGroup = "ops-clean-order-create-group", - consumeMode = ConsumeMode.CONCURRENTLY, - selectorExpression = "*" -) +@RocketMQMessageListener(topic = "ops-order-create", consumerGroup = "ops-clean-order-create-group", consumeMode = ConsumeMode.CONCURRENTLY, selectorExpression = "*") public class CleanOrderCreateEventHandler implements RocketMQListener { /** @@ -102,8 +97,8 @@ public class CleanOrderCreateEventHandler implements RocketMQListener { createReq.setSourceType("TRAFFIC"); // 系统触发 createReq.setTitle(generateOrderTitle(event)); createReq.setDescription(generateOrderDescription(event)); - createReq.setPriority(PriorityEnum.fromPriority(event.getPriority() != null ? - event.getPriority() : 2).getPriority()); + createReq.setPriority( + PriorityEnum.fromPriority(event.getPriority() != null ? event.getPriority() : 2).getPriority()); createReq.setAreaId(event.getAreaId()); // 扩展字段 @@ -133,7 +128,8 @@ public class CleanOrderCreateEventHandler implements RocketMQListener { /** * 记录工单创建业务日志 */ - private void recordOrderCreatedLog(CleanOrderCreateEventDTO event, Long orderId, CleanOrderAutoCreateReqDTO createReq) { + private void recordOrderCreatedLog(CleanOrderCreateEventDTO event, Long orderId, + CleanOrderAutoCreateReqDTO createReq) { try { // 确定事件域 EventDomain domain = determineDomain(event.getTriggerSource()); 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 753bfe8..921bbdb 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 @@ -28,13 +28,41 @@ import org.springframework.stereotype.Component; *

* 状态处理: * - * - * - * - * - * - * - * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * *
状态设备状态工单关联
DISPATCHEDBUSY设置
CONFIRMED保持BUSY设置
ARRIVED保持BUSY设置完整信息
PAUSEDPAUSED保持
COMPLETED检查等待任务清除
CANCELLEDIDLE清除
状态设备状态工单关联
DISPATCHEDBUSY设置
CONFIRMED保持BUSY设置
ARRIVED保持BUSY设置完整信息
PAUSEDPAUSED保持
COMPLETED检查等待任务清除
CANCELLEDIDLE清除
* * @author lzh @@ -99,14 +127,16 @@ public class BadgeDeviceStatusEventListener { /** * 根据工单状态更新设备工牌关联 */ - private void handleOrderStatusTransition(Long deviceId, Long orderId, WorkOrderStatusEnum newStatus, OrderStateChangedEvent event) { + private void handleOrderStatusTransition(Long deviceId, Long orderId, WorkOrderStatusEnum newStatus, + OrderStateChangedEvent event) { var waitingTasks = orderQueueService.getWaitingTasksByUserId(deviceId); switch (newStatus) { case DISPATCHED: // 工单已推送到工牌,设置工单关联,设备状态转为 BUSY badgeDeviceStatusService.setCurrentOrder(deviceId, orderId); badgeDeviceStatusService.updateBadgeStatus(deviceId, BadgeDeviceStatusEnum.BUSY, null, "新工单已推送"); - log.info("[BadgeDeviceStatusEventListener] 工单已推送,设备状态转为 BUSY: deviceId={}, orderId={}", deviceId, orderId); + log.info("[BadgeDeviceStatusEventListener] 工单已推送,设备状态转为 BUSY: deviceId={}, orderId={}", deviceId, + orderId); break; case CONFIRMED: @@ -128,7 +158,8 @@ public class BadgeDeviceStatusEventListener { if (urgentOrderId != null) { // P0 打断场景:不修改设备状态,保持当前状态 // 紧接着会有 P0 工单的 DISPATCHED 事件,将当前工单更新为 P0 工单 - log.info("[BadgeDeviceStatusEventListener] P0打断场景,工单已暂停,等待P0工单派发: pausedOrderId={}, urgentOrderId={}, deviceId={}", + log.info( + "[BadgeDeviceStatusEventListener] P0打断场景,工单已暂停,等待P0工单派发: pausedOrderId={}, urgentOrderId={}, deviceId={}", orderId, urgentOrderId, deviceId); } else { // 普通暂停场景:设备状态转为 PAUSED @@ -174,7 +205,8 @@ public class BadgeDeviceStatusEventListener { } } else { // 取消的不是当前工单(可能是队列中的等待任务),不需要修改设备状态 - log.debug("[BadgeDeviceStatusEventListener] 取消的工单非当前执行工单,跳过设备状态更新: cancelledOrderId={}, currentOrderId={}, deviceId={}", + log.debug( + "[BadgeDeviceStatusEventListener] 取消的工单非当前执行工单,跳过设备状态更新: cancelledOrderId={}, currentOrderId={}, deviceId={}", orderId, currentOrderId, deviceId); } break; @@ -207,8 +239,7 @@ public class BadgeDeviceStatusEventListener { orderId, event.getNewStatus().getStatus(), areaId, - beaconMac - ); + beaconMac); log.debug("[BadgeDeviceStatusEventListener] 设备工单信息已更新: deviceId={}, orderId={}, areaId={}, beaconMac={}", deviceId, orderId, areaId, beaconMac); @@ -242,4 +273,3 @@ public class BadgeDeviceStatusEventListener { } } } - diff --git a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/integration/listener/CleanOrderEventListener.java b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/integration/listener/CleanOrderEventListener.java index 5e6056a..08f1d1f 100644 --- a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/integration/listener/CleanOrderEventListener.java +++ b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/integration/listener/CleanOrderEventListener.java @@ -539,7 +539,7 @@ public class CleanOrderEventListener { // 1. 语音播报 - 通知保洁员工单已完成 if (deviceId != null) { - playVoice(deviceId, CleanNotificationConstants.VoiceTemplate.ORDER_COMPLETED); + playVoice(deviceId, CleanNotificationConstants.VoiceTemplate.ORDER_COMPLETED, orderId); } // 2. 发送站内信(给管理员) @@ -569,8 +569,15 @@ public class CleanOrderEventListener { * 语音播报 */ private void playVoice(Long deviceId, String message) { + playVoice(deviceId, message, null); + } + + /** + * 语音播报(带工单ID) + */ + private void playVoice(Long deviceId, String message, Long orderId) { try { - voiceBroadcastService.broadcast(deviceId, message); + voiceBroadcastService.broadcast(deviceId, message, orderId); log.debug("[语音播报] 调用成功: deviceId={}, message={}", deviceId, message); } catch (Exception e) { diff --git a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/job/IdleDevicePendingOrderCheckJob.java b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/job/IdleDevicePendingOrderCheckJob.java new file mode 100644 index 0000000..7fead7c --- /dev/null +++ b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/job/IdleDevicePendingOrderCheckJob.java @@ -0,0 +1,144 @@ +package com.viewsh.module.ops.environment.job; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import com.viewsh.framework.tenant.core.job.TenantJob; +import com.viewsh.module.ops.api.badge.BadgeDeviceStatusDTO; +import com.viewsh.module.ops.core.dispatch.DispatchEngine; +import com.viewsh.module.ops.core.dispatch.model.DispatchResult; +import com.viewsh.module.ops.dal.dataobject.workorder.OpsOrderDO; +import com.viewsh.module.ops.dal.mysql.workorder.OpsOrderMapper; +import com.viewsh.module.ops.enums.BadgeDeviceStatusEnum; +import com.viewsh.module.ops.enums.WorkOrderStatusEnum; +import com.viewsh.module.ops.environment.service.badge.BadgeDeviceStatusService; +import com.viewsh.framework.mybatis.core.query.LambdaQueryWrapperX; +import com.xxl.job.core.handler.annotation.XxlJob; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * 空闲设备待办工单检查 Job + *

+ * 职责: + * 1. 每15分钟扫描所有IDLE状态的设备 + * 2. 检查设备是否有QUEUED状态的待办工单 + * 3. 如有,自动推送第一条工单 + *

+ * 场景: + * - 工单完成后自动调度失败的补偿 + * - 设备上线后有待办但未自动推送的补偿 + * - 消息丢失导致未推送的兜底检查 + *

+ * XXL-Job 配置: + * - JobHandler: idleDevicePendingOrderCheckJob + * - Cron: 0 0/15 * * * ? (每 15 分钟) + * + * @author AI + */ +@Slf4j +@Component +public class IdleDevicePendingOrderCheckJob { + + @Resource + private BadgeDeviceStatusService badgeDeviceStatusService; + + @Resource + private OpsOrderMapper opsOrderMapper; + + @Resource + private DispatchEngine dispatchEngine; + + /** + * 执行空闲设备待办检查 + *

+ * XXL-Job 调度入口 + * + * @return 执行结果 + */ + @XxlJob("idleDevicePendingOrderCheckJob") + @TenantJob + public String execute() { + try { + CheckResult result = checkAndDispatchPendingOrders(); + return StrUtil.format("空闲设备待办检查完成: 检查 {} 台空闲设备,发现 {} 台有待办,成功推送 {} 个工单,耗时 {} ms", + result.idleDeviceCount, result.deviceWithPendingCount, result.dispatchedCount, result.durationMs); + } catch (Exception e) { + log.error("[IdleDevicePendingOrderCheckJob] 执行失败", e); + return StrUtil.format("空闲设备待办检查失败: {}", e.getMessage()); + } + } + + /** + * 检查并推送待办工单 + * + * @return 检查结果 + */ + public CheckResult checkAndDispatchPendingOrders() { + log.info("[IdleDevicePendingOrderCheckJob] 开始检查空闲设备待办工单"); + long startTime = System.currentTimeMillis(); + int idleDeviceCount = 0; + int deviceWithPendingCount = 0; + int dispatchedCount = 0; + + // 1. 获取所有空闲状态的设备 + List idleDevices = badgeDeviceStatusService.listActiveBadges().stream() + .filter(dto -> dto.getStatus() == BadgeDeviceStatusEnum.IDLE) + .toList(); + + if (CollUtil.isEmpty(idleDevices)) { + log.info("[IdleDevicePendingOrderCheckJob] 无空闲设备,跳过检查"); + return new CheckResult(0, 0, 0, System.currentTimeMillis() - startTime); + } + + idleDeviceCount = idleDevices.size(); + log.info("[IdleDevicePendingOrderCheckJob] 发现 {} 台空闲设备,开始检查待办工单", idleDeviceCount); + + // 2. 逐个检查是否有待办工单 + for (BadgeDeviceStatusDTO deviceStatus : idleDevices) { + Long deviceId = deviceStatus.getDeviceId(); + try { + // 查询该设备的待办工单(QUEUED状态,按优先级和时间排序) + OpsOrderDO pendingOrder = opsOrderMapper.selectOne(new LambdaQueryWrapperX() + .eq(OpsOrderDO::getAssigneeDeviceId, deviceId) + .eq(OpsOrderDO::getStatus, WorkOrderStatusEnum.QUEUED.getStatus()) + .orderByAsc(OpsOrderDO::getPriority) // 优先级高的排前面 + .orderByAsc(OpsOrderDO::getCreateTime) // 时间早的排前面 + .last("LIMIT 1")); + + if (pendingOrder != null) { + deviceWithPendingCount++; + log.info("[IdleDevicePendingOrderCheckJob] 发现空闲设备有待办工单: deviceId={}, orderId={}, orderCode={}", + deviceId, pendingOrder.getId(), pendingOrder.getOrderCode()); + + // 3. 自动推送工单 + DispatchResult result = dispatchEngine.autoDispatchNext(null, deviceId); + if (result.isSuccess()) { + dispatchedCount++; + log.info("[IdleDevicePendingOrderCheckJob] 自动推送成功: deviceId={}, orderId={}", + deviceId, pendingOrder.getId()); + } else { + log.warn("[IdleDevicePendingOrderCheckJob] 自动推送失败: deviceId={}, reason={}", + deviceId, result.getMessage()); + } + } + } catch (Exception e) { + log.error("[IdleDevicePendingOrderCheckJob] 检查设备待办失败: deviceId={}", deviceId, e); + } + } + + long duration = System.currentTimeMillis() - startTime; + log.info("[IdleDevicePendingOrderCheckJob] 检查完成: 空闲设备 {} 台,有待办 {} 台,成功推送 {} 个,耗时 {} ms", + idleDeviceCount, deviceWithPendingCount, dispatchedCount, duration); + + return new CheckResult(idleDeviceCount, deviceWithPendingCount, dispatchedCount, duration); + } + + /** + * 检查结果 + */ + public record CheckResult(int idleDeviceCount, int deviceWithPendingCount, int dispatchedCount, long durationMs) { + } +} diff --git a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/voice/VoiceBroadcastService.java b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/voice/VoiceBroadcastService.java index 03e89f4..d101d6c 100644 --- a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/voice/VoiceBroadcastService.java +++ b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/voice/VoiceBroadcastService.java @@ -4,6 +4,8 @@ import cn.hutool.core.map.MapUtil; import com.viewsh.module.iot.api.device.IotDeviceControlApi; import com.viewsh.module.iot.api.device.dto.IotDeviceServiceInvokeReqDTO; 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.recorder.EventLogRecord; import com.viewsh.module.ops.infrastructure.log.recorder.EventLogRecorder; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; @@ -75,7 +77,14 @@ public class VoiceBroadcastService { * @param text 播报文本 */ public void broadcast(Long deviceId, String text) { - broadcast(deviceId, text, TTS_FLAG_URGENT); + broadcast(deviceId, text, TTS_FLAG_URGENT, null); + } + + /** + * 播报语音(带工单ID) + */ + public void broadcast(Long deviceId, String text, Long orderId) { + broadcast(deviceId, text, TTS_FLAG_URGENT, orderId); } /** @@ -86,6 +95,18 @@ public class VoiceBroadcastService { * @param ttsFlag 播报标志(0x01=静默, 0x08=普通, 0x09=紧急) */ public void broadcast(Long deviceId, String text, int ttsFlag) { + broadcast(deviceId, text, ttsFlag, null); + } + + /** + * 播报语音(指定播报类型和工单ID) + * + * @param deviceId 设备ID + * @param text 播报文本 + * @param ttsFlag 播报标志 + * @param orderId 工单ID(可选) + */ + public void broadcast(Long deviceId, String text, int ttsFlag, Long orderId) { if (deviceId == null || text == null) { return; } @@ -104,15 +125,38 @@ public class VoiceBroadcastService { deviceId, text, Integer.toHexString(ttsFlag)); // 记录日志 - eventLogRecorder.info("clean", EventDomain.DEVICE, "TTS_SENT", - "语音播报: " + text, deviceId); + if (orderId != null) { + eventLogRecorder.info("clean", EventDomain.DEVICE, "TTS_SENT", + "语音播报: " + text, orderId, deviceId, null); + } else { + eventLogRecorder.info("clean", EventDomain.DEVICE, "TTS_SENT", + "语音播报: " + text, deviceId); + } } catch (Exception e) { log.error("[VoiceBroadcast] 播报失败: deviceId={}, text={}", deviceId, text, e); // 记录错误日志 - eventLogRecorder.error("clean", EventDomain.DEVICE, "TTS_FAILED", - "语音播报失败: " + e.getMessage(), deviceId, e); + if (orderId != null) { + eventLogRecorder.error("clean", EventDomain.DEVICE, "TTS_FAILED", + "语音播报失败: " + e.getMessage(), deviceId, e); // error方法目前没有支持orderId的重载,或者需要检查一下 + // 检查 EventLogRecorder 接口,error 方法可能有带 orderId 的重载吗? + // 刚才看 EventLogRecorderImpl 好像没有特别全的重载,或者我需要用 record() 方法手动构建 + // 让我先用简单方式,error 日志暂时不强求 orderId,或者手动构建 + eventLogRecorder.record(EventLogRecord.builder() + .module("clean") + .domain(EventDomain.DEVICE) + .eventType("TTS_FAILED") + .message("语音播报失败: " + e.getMessage()) + .targetId(orderId) + .targetType("order") + .deviceId(deviceId) + .level(EventLevel.ERROR) + .build()); + } else { + eventLogRecorder.error("clean", EventDomain.DEVICE, "TTS_FAILED", + "语音播报失败: " + e.getMessage(), deviceId, e); + } } } @@ -137,7 +181,11 @@ public class VoiceBroadcastService { * @param text 播报文本 */ public void broadcastUrgent(Long deviceId, String text) { - broadcast(deviceId, text, TTS_FLAG_URGENT); + broadcast(deviceId, text, TTS_FLAG_URGENT, null); + } + + public void broadcastUrgent(Long deviceId, String text, Long orderId) { + broadcast(deviceId, text, TTS_FLAG_URGENT, orderId); } /** diff --git a/viewsh-module-ops/viewsh-module-ops-biz/src/main/java/com/viewsh/module/ops/infrastructure/log/recorder/EventLogRecord.java b/viewsh-module-ops/viewsh-module-ops-biz/src/main/java/com/viewsh/module/ops/infrastructure/log/recorder/EventLogRecord.java index dd3ef7d..782af44 100644 --- a/viewsh-module-ops/viewsh-module-ops-biz/src/main/java/com/viewsh/module/ops/infrastructure/log/recorder/EventLogRecord.java +++ b/viewsh-module-ops/viewsh-module-ops-biz/src/main/java/com/viewsh/module/ops/infrastructure/log/recorder/EventLogRecord.java @@ -112,6 +112,11 @@ public class EventLogRecord { */ private String targetType; + /** + * 工单ID(便于直接关联查询) + */ + private Long orderId; + // ==================== 扩展字段 ==================== /** @@ -181,7 +186,7 @@ public class EventLogRecord { * 创建设备事件日志 */ public static EventLogRecord forDevice(String module, EventDomain domain, String eventType, - String message, Long deviceId) { + String message, Long deviceId) { return EventLogRecord.builder() .module(module) .domain(domain) @@ -195,7 +200,7 @@ public class EventLogRecord { * 创建工单事件日志 */ public static EventLogRecord forOrder(String module, EventDomain domain, String eventType, - String message, Long orderId, Long deviceId, Long personId) { + String message, Long orderId, Long deviceId, Long personId) { return EventLogRecord.builder() .module(module) .domain(domain) @@ -212,7 +217,7 @@ public class EventLogRecord { * 创建系统事件日志 */ public static EventLogRecord forSystem(String module, EventDomain domain, String eventType, - String message) { + String message) { return EventLogRecord.builder() .module(module) .domain(domain) diff --git a/viewsh-module-ops/viewsh-module-ops-biz/src/main/java/com/viewsh/module/ops/infrastructure/log/recorder/EventLogRecorderImpl.java b/viewsh-module-ops/viewsh-module-ops-biz/src/main/java/com/viewsh/module/ops/infrastructure/log/recorder/EventLogRecorderImpl.java index a47b631..ea12055 100644 --- a/viewsh-module-ops/viewsh-module-ops-biz/src/main/java/com/viewsh/module/ops/infrastructure/log/recorder/EventLogRecorderImpl.java +++ b/viewsh-module-ops/viewsh-module-ops-biz/src/main/java/com/viewsh/module/ops/infrastructure/log/recorder/EventLogRecorderImpl.java @@ -8,6 +8,8 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; +import java.util.Map; + /** * 事件日志记录器实现 *

@@ -31,7 +33,6 @@ public class EventLogRecorderImpl implements EventLogRecorder { @Resource private EventLogPersister persister; - /** * 异步记录日志(默认方式) *

@@ -110,7 +111,7 @@ public class EventLogRecorderImpl implements EventLogRecorder { @Override public void info(String module, EventDomain domain, String eventType, String message, - Long orderId, Long deviceId, Long personId) { + Long orderId, Long deviceId, Long personId) { record(EventLogRecord.builder() .module(module) .domain(domain) @@ -165,7 +166,7 @@ public class EventLogRecorderImpl implements EventLogRecorder { @Override public void error(String module, EventDomain domain, String eventType, String message, - Long deviceId, Throwable throwable) { + Long deviceId, Throwable throwable) { EventLogRecord record = EventLogRecord.builder() .module(module) .domain(domain) @@ -185,6 +186,12 @@ public class EventLogRecorderImpl implements EventLogRecorder { * 转换为 DO */ private OpsBusinessEventLogDO convertToDO(EventLogRecord record) { + // payload 为空或空 Map 时设为 null,避免存储 {} + Map payload = record.getPayload(); + if (payload != null && payload.isEmpty()) { + payload = null; + } + return OpsBusinessEventLogDO.builder() .eventTime(record.getEventTime()) .eventLevel(record.getLevel() != null ? record.getLevel().getCode() : EventLevel.INFO.getCode()) @@ -202,7 +209,7 @@ public class EventLogRecorderImpl implements EventLogRecorder { .targetType(record.getTargetType()) .eventMessage(record.getMessage()) .eventSummary(record.getSummary()) - .eventPayload(record.getPayload()) + .eventPayload(payload) .build(); } @@ -228,10 +235,12 @@ public class EventLogRecorderImpl implements EventLogRecorder { */ private void logConsole(EventLogRecord record) { String deviceInfo = record.getDeviceId() != null - ? " [设备:" + record.getDeviceId() + (record.getDeviceName() != null ? "(" + record.getDeviceName() + ")" : "") + "]" + ? " [设备:" + record.getDeviceId() + + (record.getDeviceName() != null ? "(" + record.getDeviceName() + ")" : "") + "]" : ""; String personInfo = record.getPersonId() != null - ? " [人员:" + record.getPersonId() + (record.getPersonName() != null ? "(" + record.getPersonName() + ")" : "") + "]" + ? " [人员:" + record.getPersonId() + + (record.getPersonName() != null ? "(" + record.getPersonName() + ")" : "") + "]" : ""; String targetInfo = record.getTargetId() != null ? " [" + record.getTargetType() + ":" + record.getTargetId() + "]"