feat(ops): 安保工单模块完整实现 #1
@@ -0,0 +1,256 @@
|
||||
package com.viewsh.module.ops.security.integration.listener;
|
||||
|
||||
import com.viewsh.module.ops.core.event.OrderCreatedEvent;
|
||||
import com.viewsh.module.ops.core.event.OrderStateChangedEvent;
|
||||
import com.viewsh.module.ops.core.event.OrderCompletedEvent;
|
||||
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.enums.OperatorTypeEnum;
|
||||
import com.viewsh.module.ops.enums.PriorityEnum;
|
||||
import com.viewsh.module.ops.enums.WorkOrderStatusEnum;
|
||||
import com.viewsh.module.ops.enums.WorkOrderTypeEnum;
|
||||
import com.viewsh.module.ops.infrastructure.log.enumeration.EventDomain;
|
||||
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 com.viewsh.module.ops.security.dal.dataobject.workorder.OpsOrderSecurityExtDO;
|
||||
import com.viewsh.module.ops.security.dal.mysql.workorder.OpsOrderSecurityExtMapper;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.event.TransactionPhase;
|
||||
import org.springframework.transaction.event.TransactionalEventListener;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 安保工单事件监听器
|
||||
* <p>
|
||||
* 监听工单生命周期事件,处理安保业务特有逻辑:
|
||||
* - 工单创建后触发自动派单
|
||||
* - 状态变更时记录扩展表时间点
|
||||
* - 统一记录业务日志(所有状态变更)
|
||||
*
|
||||
* @author lzh
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class SecurityOrderEventListener {
|
||||
|
||||
private static final String ORDER_TYPE_SECURITY = WorkOrderTypeEnum.SECURITY.getType();
|
||||
|
||||
@Resource
|
||||
private OpsOrderSecurityExtMapper securityExtMapper;
|
||||
|
||||
@Resource
|
||||
private DispatchEngine dispatchEngine;
|
||||
|
||||
@Resource
|
||||
private EventLogRecorder eventLogRecorder;
|
||||
|
||||
// ==================== 工单创建事件 ====================
|
||||
|
||||
/**
|
||||
* 工单创建事件 - 异步触发自动派单
|
||||
* <p>
|
||||
* {@code @Async} + {@code @TransactionalEventListener(AFTER_COMMIT)} 组合:
|
||||
* Spring 先等事务提交,再在异步线程池中执行本方法。
|
||||
*/
|
||||
@Async("ops-task-executor")
|
||||
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
|
||||
public void onOrderCreated(OrderCreatedEvent event) {
|
||||
if (!ORDER_TYPE_SECURITY.equals(event.getOrderType())) {
|
||||
return;
|
||||
}
|
||||
log.info("安保工单创建事件: orderId={}, orderCode={}", event.getOrderId(), event.getOrderCode());
|
||||
|
||||
try {
|
||||
OrderDispatchContext context = OrderDispatchContext.builder()
|
||||
.orderId(event.getOrderId())
|
||||
.orderCode(event.getOrderCode())
|
||||
.orderTitle(event.getTitle())
|
||||
.businessType(ORDER_TYPE_SECURITY)
|
||||
.areaId(event.getAreaId())
|
||||
.priority(PriorityEnum.fromPriority(event.getPriority()))
|
||||
.build();
|
||||
|
||||
DispatchResult result = dispatchEngine.dispatch(context);
|
||||
|
||||
if (result.isSuccess()) {
|
||||
log.info("安保工单自动派单完成: orderId={}, assigneeId={}", event.getOrderId(), result.getAssigneeId());
|
||||
// 记录派单成功日志
|
||||
recordLog(EventDomain.DISPATCH, LogType.ORDER_DISPATCHED,
|
||||
"自动派单成功,分配给: " + result.getAssigneeName(),
|
||||
event.getOrderId(), result.getAssigneeId());
|
||||
} else {
|
||||
log.warn("安保工单自动派单失败: orderId={}, reason={}", event.getOrderId(), result.getMessage());
|
||||
// 记录派单失败日志
|
||||
recordLog(EventDomain.DISPATCH, LogType.ORDER_DISPATCHED,
|
||||
"自动派单失败: " + result.getMessage(),
|
||||
event.getOrderId(), null);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("安保工单自动派单失败: orderId={}", event.getOrderId(), e);
|
||||
recordLog(EventDomain.DISPATCH, LogType.ORDER_DISPATCHED,
|
||||
"自动派单异常: " + e.getMessage(),
|
||||
event.getOrderId(), null);
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 状态变更事件 ====================
|
||||
|
||||
/**
|
||||
* 状态变更事件 - 记录扩展表时间点 + 业务日志
|
||||
*/
|
||||
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
|
||||
public void onOrderStateChanged(OrderStateChangedEvent event) {
|
||||
if (!ORDER_TYPE_SECURITY.equals(event.getOrderType())) {
|
||||
return;
|
||||
}
|
||||
|
||||
WorkOrderStatusEnum newStatus = event.getNewStatus();
|
||||
Long orderId = event.getOrderId();
|
||||
|
||||
log.info("安保工单状态变更: orderId={}, {} -> {}", orderId, event.getOldStatus(), newStatus);
|
||||
|
||||
switch (newStatus) {
|
||||
case DISPATCHED -> handleDispatched(orderId, event);
|
||||
case CONFIRMED -> handleConfirmed(orderId, event);
|
||||
case COMPLETED -> handleCompleted(orderId, event);
|
||||
case CANCELLED -> handleCancelled(orderId, event);
|
||||
case PAUSED -> handlePaused(orderId, event);
|
||||
default -> log.debug("安保工单状态变更无需额外处理: orderId={}, status={}", orderId, newStatus);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 工单完成事件 - 自动派送下一个任务
|
||||
*/
|
||||
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
|
||||
public void onOrderCompleted(OrderCompletedEvent event) {
|
||||
if (!ORDER_TYPE_SECURITY.equals(event.getOrderType())) {
|
||||
return;
|
||||
}
|
||||
if (event.getAssigneeId() != null) {
|
||||
try {
|
||||
dispatchEngine.autoDispatchNext(event.getOrderId(), event.getAssigneeId());
|
||||
} catch (Exception e) {
|
||||
log.error("安保工单完成后自动派送下一个失败: orderId={}", event.getOrderId(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 状态处理方法 ====================
|
||||
|
||||
private void handleDispatched(Long orderId, OrderStateChangedEvent event) {
|
||||
// 1. 记录下发时间
|
||||
OpsOrderSecurityExtDO extUpdate = new OpsOrderSecurityExtDO();
|
||||
extUpdate.setOpsOrderId(orderId);
|
||||
extUpdate.setDispatchedTime(LocalDateTime.now());
|
||||
securityExtMapper.insertOrUpdateSelective(extUpdate);
|
||||
|
||||
// 2. 业务日志
|
||||
Long assigneeId = event.getPayloadLong("assigneeId");
|
||||
String assigneeName = (String) event.getPayload().get("assigneeName");
|
||||
String message = assigneeName != null
|
||||
? String.format("工单已派发给 %s", assigneeName)
|
||||
: "工单已派发";
|
||||
|
||||
// 如果是从 PAUSED 恢复,补充说明
|
||||
if (event.getOldStatus() == WorkOrderStatusEnum.PAUSED) {
|
||||
message = "工单从暂停恢复,重新派发";
|
||||
}
|
||||
|
||||
recordLog(EventDomain.DISPATCH, LogType.ORDER_DISPATCHED, message, orderId, assigneeId);
|
||||
}
|
||||
|
||||
private void handleConfirmed(Long orderId, OrderStateChangedEvent event) {
|
||||
// 1. 记录确认时间
|
||||
OpsOrderSecurityExtDO extUpdate = new OpsOrderSecurityExtDO();
|
||||
extUpdate.setOpsOrderId(orderId);
|
||||
extUpdate.setConfirmedTime(LocalDateTime.now());
|
||||
securityExtMapper.insertOrUpdateSelective(extUpdate);
|
||||
|
||||
// 2. 业务日志
|
||||
Long operatorId = event.getOperatorId();
|
||||
recordLog(EventDomain.DISPATCH, LogType.ORDER_CONFIRM, "安保人员确认接单", orderId, operatorId);
|
||||
}
|
||||
|
||||
private void handleCompleted(Long orderId, OrderStateChangedEvent event) {
|
||||
// 1. 记录完成时间
|
||||
OpsOrderSecurityExtDO extUpdate = new OpsOrderSecurityExtDO();
|
||||
extUpdate.setOpsOrderId(orderId);
|
||||
extUpdate.setCompletedTime(LocalDateTime.now());
|
||||
securityExtMapper.insertOrUpdateSelective(extUpdate);
|
||||
|
||||
// 2. 业务日志(区分自动完单 vs 人工完单)
|
||||
Long operatorId = event.getOperatorId();
|
||||
OperatorTypeEnum operatorType = event.getOperatorType();
|
||||
String remark = event.getRemark();
|
||||
|
||||
String message;
|
||||
if (operatorType == OperatorTypeEnum.SYSTEM || operatorId == null) {
|
||||
message = "系统自动完单";
|
||||
if (remark != null && !remark.isEmpty()) {
|
||||
message += "(" + remark + ")";
|
||||
}
|
||||
} else {
|
||||
message = "安保人员提交处理结果";
|
||||
}
|
||||
|
||||
recordLog(EventDomain.DISPATCH, LogType.ORDER_COMPLETED, message, orderId, operatorId);
|
||||
}
|
||||
|
||||
private void handleCancelled(Long orderId, OrderStateChangedEvent event) {
|
||||
Long operatorId = event.getOperatorId();
|
||||
String remark = event.getRemark();
|
||||
String message = "安保工单已取消";
|
||||
if (remark != null && !remark.isEmpty()) {
|
||||
message += "(" + remark + ")";
|
||||
}
|
||||
|
||||
recordLog(EventDomain.DISPATCH, LogType.ORDER_CANCELLED, message, orderId, operatorId);
|
||||
}
|
||||
|
||||
private void handlePaused(Long orderId, OrderStateChangedEvent event) {
|
||||
Long operatorId = event.getOperatorId();
|
||||
String remark = event.getRemark();
|
||||
String message = "安保工单已暂停";
|
||||
if (remark != null && !remark.isEmpty()) {
|
||||
message += "(" + remark + ")";
|
||||
}
|
||||
|
||||
recordLog(EventDomain.DISPATCH, LogType.ORDER_PAUSED, message, orderId, operatorId);
|
||||
}
|
||||
|
||||
// ==================== 日志辅助方法 ====================
|
||||
|
||||
/**
|
||||
* 统一记录安保业务日志
|
||||
*/
|
||||
private void recordLog(EventDomain domain, LogType logType, String message,
|
||||
Long orderId, Long personId) {
|
||||
try {
|
||||
EventLogRecord.EventLogRecordBuilder builder = EventLogRecord.builder()
|
||||
.module(LogModule.SECURITY)
|
||||
.domain(domain)
|
||||
.eventType(logType.getCode())
|
||||
.message(message)
|
||||
.targetId(orderId)
|
||||
.targetType("order");
|
||||
|
||||
if (personId != null) {
|
||||
builder.personId(personId);
|
||||
}
|
||||
|
||||
eventLogRecorder.record(builder.build());
|
||||
} catch (Exception e) {
|
||||
log.warn("[SecurityOrderEventListener] 记录业务日志失败: orderId={}, eventType={}",
|
||||
orderId, logType.getCode(), e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user