feat(ops): 补充工单生命周期业务日志记录
- CleanOrderCreateEventHandler: 记录工单创建日志 - CleanOrderArriveEventHandler: 记录到岗日志 - CleanOrderCompleteEventHandler: 记录完成日志 支持客流/信标触发等不同场景的日志分类记录。 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,9 @@ import com.viewsh.module.ops.dal.mysql.workorder.OpsOrderMapper;
|
|||||||
import com.viewsh.module.ops.enums.OperatorTypeEnum;
|
import com.viewsh.module.ops.enums.OperatorTypeEnum;
|
||||||
import com.viewsh.module.ops.enums.WorkOrderStatusEnum;
|
import com.viewsh.module.ops.enums.WorkOrderStatusEnum;
|
||||||
import com.viewsh.module.ops.environment.integration.dto.CleanOrderArriveEventDTO;
|
import com.viewsh.module.ops.environment.integration.dto.CleanOrderArriveEventDTO;
|
||||||
|
import com.viewsh.module.ops.infrastructure.log.enumeration.EventDomain;
|
||||||
|
import com.viewsh.module.ops.infrastructure.log.recorder.EventLogRecord;
|
||||||
|
import com.viewsh.module.ops.infrastructure.log.recorder.EventLogRecorder;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.rocketmq.spring.annotation.ConsumeMode;
|
import org.apache.rocketmq.spring.annotation.ConsumeMode;
|
||||||
@@ -73,6 +76,9 @@ public class CleanOrderArriveEventHandler implements RocketMQListener<String> {
|
|||||||
@Resource
|
@Resource
|
||||||
private OrderLifecycleManager orderLifecycleManager;
|
private OrderLifecycleManager orderLifecycleManager;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private EventLogRecorder eventLogRecorder;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMessage(String message) {
|
public void onMessage(String message) {
|
||||||
try {
|
try {
|
||||||
@@ -146,7 +152,10 @@ public class CleanOrderArriveEventHandler implements RocketMQListener<String> {
|
|||||||
// 5. 通过生命周期管理器执行状态转换(DISPATCHED/CONFIRMED -> ARRIVED)
|
// 5. 通过生命周期管理器执行状态转换(DISPATCHED/CONFIRMED -> ARRIVED)
|
||||||
orderLifecycleManager.transition(request);
|
orderLifecycleManager.transition(request);
|
||||||
|
|
||||||
// 6. 更新 Redis 缓存(设备当前工单)
|
// 6. 记录业务日志
|
||||||
|
recordOrderArrivedLog(event, request);
|
||||||
|
|
||||||
|
// 7. 更新 Redis 缓存(设备当前工单)
|
||||||
cacheDeviceCurrentOrder(event);
|
cacheDeviceCurrentOrder(event);
|
||||||
|
|
||||||
log.info("[CleanOrderArriveEventHandler] 工单到岗成功: eventId={}, orderId={}, deviceId={}",
|
log.info("[CleanOrderArriveEventHandler] 工单到岗成功: eventId={}, orderId={}, deviceId={}",
|
||||||
@@ -190,4 +199,36 @@ public class CleanOrderArriveEventHandler implements RocketMQListener<String> {
|
|||||||
log.error("[CleanOrderArriveEventHandler] 设备工单缓存更新失败: deviceId={}", event.getDeviceId(), e);
|
log.error("[CleanOrderArriveEventHandler] 设备工单缓存更新失败: deviceId={}", event.getDeviceId(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录工单到岗业务日志
|
||||||
|
*/
|
||||||
|
private void recordOrderArrivedLog(CleanOrderArriveEventDTO event, OrderTransitionRequest request) {
|
||||||
|
try {
|
||||||
|
// 构建扩展信息
|
||||||
|
Map<String, Object> extra = new HashMap<>();
|
||||||
|
extra.put("eventId", event.getEventId());
|
||||||
|
extra.put("triggerSource", event.getTriggerSource());
|
||||||
|
extra.put("areaId", event.getAreaId());
|
||||||
|
if (event.getTriggerData() != null) {
|
||||||
|
extra.putAll(event.getTriggerData());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 记录日志
|
||||||
|
eventLogRecorder.record(EventLogRecord.builder()
|
||||||
|
.module("clean")
|
||||||
|
.domain(EventDomain.BEACON)
|
||||||
|
.eventType("ORDER_ARRIVED")
|
||||||
|
.message(String.format("蓝牙信标自动到岗确认 [设备:%s, 区域:%d]",
|
||||||
|
event.getDeviceKey(), event.getAreaId()))
|
||||||
|
.targetId(event.getOrderId())
|
||||||
|
.targetType("order")
|
||||||
|
.deviceId(event.getDeviceId())
|
||||||
|
.payload(extra)
|
||||||
|
.build());
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("[CleanOrderArriveEventHandler] 记录业务日志失败: orderId={}", event.getOrderId(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ import com.viewsh.module.ops.enums.OperatorTypeEnum;
|
|||||||
import com.viewsh.module.ops.enums.WorkOrderStatusEnum;
|
import com.viewsh.module.ops.enums.WorkOrderStatusEnum;
|
||||||
import com.viewsh.module.ops.environment.integration.dto.CleanOrderCompleteEventDTO;
|
import com.viewsh.module.ops.environment.integration.dto.CleanOrderCompleteEventDTO;
|
||||||
import com.viewsh.module.ops.environment.service.cleanorder.CleanOrderService;
|
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.recorder.EventLogRecord;
|
||||||
|
import com.viewsh.module.ops.infrastructure.log.recorder.EventLogRecorder;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.rocketmq.spring.annotation.ConsumeMode;
|
import org.apache.rocketmq.spring.annotation.ConsumeMode;
|
||||||
@@ -72,6 +75,9 @@ public class CleanOrderCompleteEventHandler implements RocketMQListener<String>
|
|||||||
@Resource
|
@Resource
|
||||||
private CleanOrderService cleanOrderService;
|
private CleanOrderService cleanOrderService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private EventLogRecorder eventLogRecorder;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMessage(String message) {
|
public void onMessage(String message) {
|
||||||
try {
|
try {
|
||||||
@@ -143,10 +149,13 @@ public class CleanOrderCompleteEventHandler implements RocketMQListener<String>
|
|||||||
// 5. 通过生命周期管理器执行状态转换(ARRIVED -> COMPLETED)
|
// 5. 通过生命周期管理器执行状态转换(ARRIVED -> COMPLETED)
|
||||||
orderLifecycleManager.completeOrder(event.getOrderId(), null, remark);
|
orderLifecycleManager.completeOrder(event.getOrderId(), null, remark);
|
||||||
|
|
||||||
// 6. 清除 Redis 缓存(设备当前工单)
|
// 6. 记录业务日志
|
||||||
|
recordOrderCompletedLog(event, order, remark);
|
||||||
|
|
||||||
|
// 7. 清除 Redis 缓存(设备当前工单)
|
||||||
clearDeviceCurrentOrder(event.getDeviceId());
|
clearDeviceCurrentOrder(event.getDeviceId());
|
||||||
|
|
||||||
// 7. 自动调度下一个任务(优先恢复被中断的任务)
|
// 8. 自动调度下一个任务(优先恢复被中断的任务)
|
||||||
if (order.getAssigneeId() != null) {
|
if (order.getAssigneeId() != null) {
|
||||||
cleanOrderService.autoDispatchNextOrder(event.getOrderId(), order.getAssigneeId());
|
cleanOrderService.autoDispatchNextOrder(event.getOrderId(), order.getAssigneeId());
|
||||||
}
|
}
|
||||||
@@ -187,4 +196,49 @@ public class CleanOrderCompleteEventHandler implements RocketMQListener<String>
|
|||||||
log.error("[CleanOrderCompleteEventHandler] 设备工单缓存清除失败: deviceId={}", deviceId, e);
|
log.error("[CleanOrderCompleteEventHandler] 设备工单缓存清除失败: deviceId={}", deviceId, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录工单完成业务日志
|
||||||
|
*/
|
||||||
|
private void recordOrderCompletedLog(CleanOrderCompleteEventDTO event, OpsOrderDO order, String remark) {
|
||||||
|
try {
|
||||||
|
// 构建扩展信息
|
||||||
|
Map<String, Object> extra = new HashMap<>();
|
||||||
|
extra.put("eventId", event.getEventId());
|
||||||
|
extra.put("triggerSource", event.getTriggerSource());
|
||||||
|
extra.put("areaId", event.getAreaId());
|
||||||
|
extra.put("completionReason", event.getTriggerData() != null ?
|
||||||
|
event.getTriggerData().get("completionReason") : "SIGNAL_LOSS_TIMEOUT");
|
||||||
|
if (event.getTriggerData() != null) {
|
||||||
|
extra.putAll(event.getTriggerData());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算作业时长(分钟)
|
||||||
|
String durationInfo = "";
|
||||||
|
if (event.getTriggerData() != null && event.getTriggerData().containsKey("durationMs")) {
|
||||||
|
Object durationMs = event.getTriggerData().get("durationMs");
|
||||||
|
if (durationMs != null) {
|
||||||
|
long durationMinutes = ((Number) durationMs).longValue() / 60000;
|
||||||
|
durationInfo = String.format(",作业时长: %d分钟", durationMinutes);
|
||||||
|
extra.put("durationMinutes", durationMinutes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 记录日志
|
||||||
|
eventLogRecorder.record(EventLogRecord.builder()
|
||||||
|
.module("clean")
|
||||||
|
.domain(EventDomain.BEACON)
|
||||||
|
.eventType("ORDER_COMPLETED")
|
||||||
|
.message("信号丢失超时自动完成 [设备:" + event.getDeviceKey() + durationInfo + "]")
|
||||||
|
.targetId(event.getOrderId())
|
||||||
|
.targetType("order")
|
||||||
|
.deviceId(event.getDeviceId())
|
||||||
|
.personId(order.getAssigneeId())
|
||||||
|
.payload(extra)
|
||||||
|
.build());
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("[CleanOrderCompleteEventHandler] 记录业务日志失败: orderId={}", event.getOrderId(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,10 @@ import com.viewsh.module.ops.enums.PriorityEnum;
|
|||||||
import com.viewsh.module.ops.environment.dal.dataobject.CleanOrderAutoCreateReqDTO;
|
import com.viewsh.module.ops.environment.dal.dataobject.CleanOrderAutoCreateReqDTO;
|
||||||
import com.viewsh.module.ops.environment.integration.dto.CleanOrderCreateEventDTO;
|
import com.viewsh.module.ops.environment.integration.dto.CleanOrderCreateEventDTO;
|
||||||
import com.viewsh.module.ops.environment.service.cleanorder.CleanOrderService;
|
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.recorder.EventLogRecord;
|
||||||
|
import com.viewsh.module.ops.infrastructure.log.recorder.EventLogRecorder;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.rocketmq.spring.annotation.ConsumeMode;
|
import org.apache.rocketmq.spring.annotation.ConsumeMode;
|
||||||
@@ -15,6 +19,8 @@ import org.apache.rocketmq.spring.core.RocketMQListener;
|
|||||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -60,6 +66,9 @@ public class CleanOrderCreateEventHandler implements RocketMQListener<String> {
|
|||||||
@Resource
|
@Resource
|
||||||
private IotDeviceControlApi iotDeviceControlApi;
|
private IotDeviceControlApi iotDeviceControlApi;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private EventLogRecorder eventLogRecorder;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMessage(String message) {
|
public void onMessage(String message) {
|
||||||
try {
|
try {
|
||||||
@@ -117,7 +126,10 @@ public class CleanOrderCreateEventHandler implements RocketMQListener<String> {
|
|||||||
// 2. 创建工单(同时创建主表+扩展表)
|
// 2. 创建工单(同时创建主表+扩展表)
|
||||||
Long orderId = cleanOrderService.createAutoCleanOrder(createReq);
|
Long orderId = cleanOrderService.createAutoCleanOrder(createReq);
|
||||||
|
|
||||||
// 3. 如果是客流触发的工单,重置客流计数器基准值
|
// 3. 记录业务日志
|
||||||
|
recordOrderCreatedLog(event, orderId, createReq);
|
||||||
|
|
||||||
|
// 4. 如果是客流触发的工单,重置客流计数器基准值
|
||||||
// TODO: 需要优化这个工单是否创建成功,才重置
|
// TODO: 需要优化这个工单是否创建成功,才重置
|
||||||
if ("IOT_TRAFFIC".equals(event.getTriggerSource()) && event.getTriggerData() != null) {
|
if ("IOT_TRAFFIC".equals(event.getTriggerSource()) && event.getTriggerData() != null) {
|
||||||
resetTrafficCounter(event, orderId);
|
resetTrafficCounter(event, orderId);
|
||||||
@@ -127,6 +139,81 @@ public class CleanOrderCreateEventHandler implements RocketMQListener<String> {
|
|||||||
event.getEventId(), orderId, event.getAreaId());
|
event.getEventId(), orderId, event.getAreaId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录工单创建业务日志
|
||||||
|
*/
|
||||||
|
private void recordOrderCreatedLog(CleanOrderCreateEventDTO event, Long orderId, CleanOrderAutoCreateReqDTO createReq) {
|
||||||
|
try {
|
||||||
|
// 确定事件域和类型
|
||||||
|
EventDomain domain = determineDomain(event.getTriggerSource());
|
||||||
|
String eventType = "ORDER_CREATED";
|
||||||
|
|
||||||
|
// 构建扩展信息
|
||||||
|
Map<String, Object> 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.info("clean", domain, eventType,
|
||||||
|
buildLogMessage(event, createReq),
|
||||||
|
orderId,
|
||||||
|
event.getTriggerDeviceId(),
|
||||||
|
null);
|
||||||
|
|
||||||
|
// 添加扩展信息
|
||||||
|
eventLogRecorder.record(EventLogRecord.builder()
|
||||||
|
.module("clean")
|
||||||
|
.domain(domain)
|
||||||
|
.eventType(eventType + "_DETAIL")
|
||||||
|
.message("工单创建详细数据")
|
||||||
|
.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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 重置客流计数器基准值
|
* 重置客流计数器基准值
|
||||||
* <p>
|
* <p>
|
||||||
|
|||||||
Reference in New Issue
Block a user