chore: 【ops】状态机实现/状态切换事件发布/保洁监听处理事件
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
package com.viewsh.module.ops.core.event;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 工单完成领域事件
|
||||
* <p>
|
||||
* 当工单完成时发布此事件
|
||||
*
|
||||
* @author lzh
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class OrderCompletedEvent {
|
||||
|
||||
/**
|
||||
* 工单ID
|
||||
*/
|
||||
private Long orderId;
|
||||
|
||||
/**
|
||||
* 工单类型
|
||||
*/
|
||||
private String orderType;
|
||||
|
||||
/**
|
||||
* 工单编号
|
||||
*/
|
||||
private String orderCode;
|
||||
|
||||
/**
|
||||
* 执行人ID
|
||||
*/
|
||||
private Long assigneeId;
|
||||
|
||||
/**
|
||||
* 完成时间
|
||||
*/
|
||||
private LocalDateTime completedTime;
|
||||
|
||||
/**
|
||||
* 作业时长(秒)
|
||||
*/
|
||||
private Integer workDuration;
|
||||
|
||||
/**
|
||||
* 完成备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 扩展参数
|
||||
*/
|
||||
@Builder.Default
|
||||
private java.util.Map<String, Object> payload = new java.util.HashMap<>();
|
||||
|
||||
public OrderCompletedEvent addPayload(String key, Object value) {
|
||||
if (this.payload == null) {
|
||||
this.payload = new java.util.HashMap<>();
|
||||
}
|
||||
this.payload.put(key, value);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.viewsh.module.ops.core.event;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 工单创建领域事件
|
||||
* <p>
|
||||
* 当新工单创建时发布此事件
|
||||
*
|
||||
* @author lzh
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class OrderCreatedEvent {
|
||||
|
||||
/**
|
||||
* 工单ID
|
||||
*/
|
||||
private Long orderId;
|
||||
|
||||
/**
|
||||
* 工单类型
|
||||
*/
|
||||
private String orderType;
|
||||
|
||||
/**
|
||||
* 工单编号
|
||||
*/
|
||||
private String orderCode;
|
||||
|
||||
/**
|
||||
* 工单标题
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 区域ID
|
||||
*/
|
||||
private Long areaId;
|
||||
|
||||
/**
|
||||
* 优先级
|
||||
*/
|
||||
private Integer priority;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 创建人ID
|
||||
*/
|
||||
private Long creatorId;
|
||||
|
||||
/**
|
||||
* 扩展参数
|
||||
*/
|
||||
@Builder.Default
|
||||
private Map<String, Object> payload = new java.util.HashMap<>();
|
||||
|
||||
public OrderCreatedEvent addPayload(String key, Object value) {
|
||||
if (this.payload == null) {
|
||||
this.payload = new java.util.HashMap<>();
|
||||
}
|
||||
this.payload.put(key, value);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.viewsh.module.ops.core.event;
|
||||
|
||||
/**
|
||||
* 工单事件发布器接口
|
||||
* <p>
|
||||
* 职责:
|
||||
* 1. 发布工单状态变更事件
|
||||
* 2. 发布工单创建事件
|
||||
* 3. 发布工单完成事件
|
||||
* <p>
|
||||
* 设计说明:
|
||||
* - 使用领域事件模式解耦状态机与业务逻辑
|
||||
* - 业务方通过 @EventListener 订阅事件
|
||||
* - 事件异步发布,不阻塞主流程
|
||||
*
|
||||
* @author lzh
|
||||
*/
|
||||
public interface OrderEventPublisher {
|
||||
|
||||
/**
|
||||
* 发布状态变更事件
|
||||
*
|
||||
* @param event 状态变更事件
|
||||
*/
|
||||
void publishStateChanged(OrderStateChangedEvent event);
|
||||
|
||||
/**
|
||||
* 发布工单创建事件
|
||||
*
|
||||
* @param event 工单创建事件
|
||||
*/
|
||||
void publishOrderCreated(OrderCreatedEvent event);
|
||||
|
||||
/**
|
||||
* 发布工单完成事件
|
||||
*
|
||||
* @param event 工单完成事件
|
||||
*/
|
||||
void publishOrderCompleted(OrderCompletedEvent event);
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package com.viewsh.module.ops.core.event;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 工单事件发布器实现
|
||||
* <p>
|
||||
* 使用 Spring 的 ApplicationEventPublisher 发布事件
|
||||
* 业务方通过 @EventListener 订阅事件
|
||||
* <p>
|
||||
* 使用示例:
|
||||
* <pre>
|
||||
* @Component
|
||||
* public class CleanOrderEventHandler {
|
||||
* @EventListener
|
||||
* public void onStateChanged(OrderStateChangedEvent event) {
|
||||
* // 处理保洁工单状态变更
|
||||
* if ("CLEAN".equals(event.getOrderType())) {
|
||||
* // ...
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @author lzh
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class OrderEventPublisherImpl implements OrderEventPublisher {
|
||||
|
||||
@Resource
|
||||
private ApplicationEventPublisher applicationEventPublisher;
|
||||
|
||||
@Override
|
||||
public void publishStateChanged(OrderStateChangedEvent event) {
|
||||
try {
|
||||
applicationEventPublisher.publishEvent(event);
|
||||
log.debug("状态变更事件已发布: orderId={}, {} -> {}",
|
||||
event.getOrderId(), event.getOldStatus(), event.getNewStatus());
|
||||
} catch (Exception e) {
|
||||
// 事件发布失败不应影响主流程
|
||||
log.error("发布状态变更事件失败: orderId={}", event.getOrderId(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publishOrderCreated(OrderCreatedEvent event) {
|
||||
try {
|
||||
applicationEventPublisher.publishEvent(event);
|
||||
log.debug("工单创建事件已发布: orderId={}, orderCode={}",
|
||||
event.getOrderId(), event.getOrderCode());
|
||||
} catch (Exception e) {
|
||||
log.error("发布工单创建事件失败: orderId={}", event.getOrderId(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publishOrderCompleted(OrderCompletedEvent event) {
|
||||
try {
|
||||
applicationEventPublisher.publishEvent(event);
|
||||
log.debug("工单完成事件已发布: orderId={}, assigneeId={}",
|
||||
event.getOrderId(), event.getAssigneeId());
|
||||
} catch (Exception e) {
|
||||
log.error("发布工单完成事件失败: orderId={}", event.getOrderId(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
package com.viewsh.module.ops.core.event;
|
||||
|
||||
import com.viewsh.module.ops.enums.OperatorTypeEnum;
|
||||
import com.viewsh.module.ops.enums.WorkOrderStatusEnum;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 工单状态变更领域事件
|
||||
* <p>
|
||||
* 当工单状态发生变更时发布此事件,业务方订阅此事件处理自己的逻辑
|
||||
* <p>
|
||||
* 设计说明:
|
||||
* - 使用领域事件模式解耦状态机与业务逻辑
|
||||
* - 业务方通过 @EventListener 订阅事件
|
||||
* - 支持扩展参数传递额外信息
|
||||
*
|
||||
* @author lzh
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class OrderStateChangedEvent {
|
||||
|
||||
/**
|
||||
* 工单ID
|
||||
*/
|
||||
private Long orderId;
|
||||
|
||||
/**
|
||||
* 工单类型(CLEAN、REPAIR、SECURITY等)
|
||||
*/
|
||||
private String orderType;
|
||||
|
||||
/**
|
||||
* 工单编号
|
||||
*/
|
||||
private String orderCode;
|
||||
|
||||
/**
|
||||
* 旧状态
|
||||
*/
|
||||
private WorkOrderStatusEnum oldStatus;
|
||||
|
||||
/**
|
||||
* 新状态
|
||||
*/
|
||||
private WorkOrderStatusEnum newStatus;
|
||||
|
||||
/**
|
||||
* 操作人类型
|
||||
*/
|
||||
private OperatorTypeEnum operatorType;
|
||||
|
||||
/**
|
||||
* 操作人ID
|
||||
*/
|
||||
private Long operatorId;
|
||||
|
||||
/**
|
||||
* 操作时间
|
||||
*/
|
||||
private LocalDateTime eventTime;
|
||||
|
||||
/**
|
||||
* 备注/说明
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 扩展参数(可选)
|
||||
* 用于传递额外的业务信息
|
||||
* 例如:interruptReason, urgentOrderId
|
||||
*/
|
||||
@Builder.Default
|
||||
private Map<String, Object> payload = new java.util.HashMap<>();
|
||||
|
||||
/**
|
||||
* 添加扩展参数
|
||||
*/
|
||||
public OrderStateChangedEvent addPayload(String key, Object value) {
|
||||
if (this.payload == null) {
|
||||
this.payload = new java.util.HashMap<>();
|
||||
}
|
||||
this.payload.put(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取扩展参数
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getPayload(String key, Class<T> type) {
|
||||
if (this.payload == null) {
|
||||
return null;
|
||||
}
|
||||
Object value = this.payload.get(key);
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (type.isInstance(value)) {
|
||||
return (T) value;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取扩展参数(字符串)
|
||||
*/
|
||||
public String getPayloadString(String key) {
|
||||
Object value = getPayload(key, Object.class);
|
||||
return value != null ? value.toString() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取扩展参数(Long)
|
||||
*/
|
||||
public Long getPayloadLong(String key) {
|
||||
Object value = getPayload(key, Object.class);
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Long) {
|
||||
return (Long) value;
|
||||
}
|
||||
if (value instanceof Integer) {
|
||||
return ((Integer) value).longValue();
|
||||
}
|
||||
if (value instanceof String) {
|
||||
try {
|
||||
return Long.parseLong((String) value);
|
||||
} catch (NumberFormatException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否包含指定的扩展参数
|
||||
*/
|
||||
public boolean hasPayload(String key) {
|
||||
return this.payload != null && this.payload.containsKey(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 静态工厂方法:创建事件
|
||||
*/
|
||||
public static OrderStateChangedEvent of(Long orderId, String orderType,
|
||||
WorkOrderStatusEnum oldStatus,
|
||||
WorkOrderStatusEnum newStatus,
|
||||
OperatorTypeEnum operatorType,
|
||||
Long operatorId,
|
||||
String remark) {
|
||||
return OrderStateChangedEvent.builder()
|
||||
.orderId(orderId)
|
||||
.orderType(orderType)
|
||||
.oldStatus(oldStatus)
|
||||
.newStatus(newStatus)
|
||||
.operatorType(operatorType)
|
||||
.operatorId(operatorId)
|
||||
.eventTime(LocalDateTime.now())
|
||||
.remark(remark)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,37 @@
|
||||
package com.viewsh.module.ops.service.fsm;
|
||||
|
||||
import com.viewsh.module.ops.core.event.OrderEventPublisher;
|
||||
import com.viewsh.module.ops.core.event.OrderStateChangedEvent;
|
||||
import com.viewsh.module.ops.dal.dataobject.workorder.OpsOrderDO;
|
||||
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.service.event.OpsOrderEventService;
|
||||
import com.viewsh.module.ops.service.fsm.event.OrderStateChangedEvent;
|
||||
import com.viewsh.module.ops.service.fsm.listener.OrderStateChangeListener;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 工单状态机核心
|
||||
* <p>
|
||||
* 职责:
|
||||
* 1. 管理工单状态转换规则
|
||||
* 2. 执行状态转换并记录事件
|
||||
* 3. 触发状态变更监听器
|
||||
* 3. 发布状态变更事件(通过事件发布器)
|
||||
* <p>
|
||||
* 设计原则:
|
||||
* - 单一职责:只负责状态转换规则验证和状态管理
|
||||
* - 不触发业务逻辑:业务逻辑通过事件订阅处理
|
||||
* - 事件驱动:状态变更后发布事件,业务方订阅处理
|
||||
* <p>
|
||||
* 变更说明:
|
||||
* - 移除了监听器机制(改为事件发布)
|
||||
* - 状态机只负责状态转换验证和状态更新
|
||||
* - 业务逻辑通过 @EventListener 订阅事件处理
|
||||
*
|
||||
* @author lzh
|
||||
*/
|
||||
@@ -34,6 +45,12 @@ public class OrderStateMachine {
|
||||
@Resource
|
||||
private OpsOrderEventService eventService;
|
||||
|
||||
/**
|
||||
* 事件发布器(用于发布状态变更事件)
|
||||
*/
|
||||
@Resource
|
||||
private OrderEventPublisher eventPublisher;
|
||||
|
||||
/**
|
||||
* 状态转换规则(清晰可见)
|
||||
* Key: 当前状态
|
||||
@@ -43,72 +60,63 @@ public class OrderStateMachine {
|
||||
* 保洁流程:PENDING → QUEUED → DISPATCHED → CONFIRMED → ARRIVED → COMPLETED
|
||||
*/
|
||||
private static final Map<WorkOrderStatusEnum, Set<WorkOrderStatusEnum>> TRANSITIONS = Map.of(
|
||||
// 初始状态
|
||||
WorkOrderStatusEnum.PENDING, Set.of(
|
||||
WorkOrderStatusEnum.QUEUED, // 保洁业务:入队
|
||||
WorkOrderStatusEnum.DISPATCHED, // 通用业务:直接派单
|
||||
WorkOrderStatusEnum.CANCELLED
|
||||
),
|
||||
// 初始状态
|
||||
WorkOrderStatusEnum.PENDING, Set.of(
|
||||
WorkOrderStatusEnum.QUEUED, // 保洁业务:入队
|
||||
WorkOrderStatusEnum.DISPATCHED, // 通用业务:直接派单
|
||||
WorkOrderStatusEnum.CANCELLED
|
||||
),
|
||||
|
||||
// 保洁业务特有状态
|
||||
WorkOrderStatusEnum.QUEUED, Set.of(
|
||||
WorkOrderStatusEnum.DISPATCHED, // 推送到工牌
|
||||
WorkOrderStatusEnum.CANCELLED
|
||||
),
|
||||
// 保洁业务特有状态
|
||||
WorkOrderStatusEnum.QUEUED, Set.of(
|
||||
WorkOrderStatusEnum.DISPATCHED, // 推送到工牌
|
||||
WorkOrderStatusEnum.CANCELLED
|
||||
),
|
||||
|
||||
WorkOrderStatusEnum.DISPATCHED, Set.of(
|
||||
WorkOrderStatusEnum.CONFIRMED, // 保洁员确认
|
||||
WorkOrderStatusEnum.ARRIVED, // 通用业务:直接到岗
|
||||
WorkOrderStatusEnum.CANCELLED
|
||||
),
|
||||
WorkOrderStatusEnum.DISPATCHED, Set.of(
|
||||
WorkOrderStatusEnum.CONFIRMED, // 保洁员确认
|
||||
WorkOrderStatusEnum.ARRIVED, // 通用业务:直接到岗
|
||||
WorkOrderStatusEnum.CANCELLED
|
||||
),
|
||||
|
||||
WorkOrderStatusEnum.CONFIRMED, Set.of(
|
||||
WorkOrderStatusEnum.ARRIVED, // 感知信标开始作业
|
||||
WorkOrderStatusEnum.CANCELLED
|
||||
),
|
||||
WorkOrderStatusEnum.CONFIRMED, Set.of(
|
||||
WorkOrderStatusEnum.ARRIVED, // 感知信标开始作业
|
||||
WorkOrderStatusEnum.CANCELLED
|
||||
),
|
||||
|
||||
// 作业中
|
||||
WorkOrderStatusEnum.ARRIVED, Set.of(
|
||||
WorkOrderStatusEnum.PAUSED, // 暂停作业
|
||||
WorkOrderStatusEnum.COMPLETED // 完成作业
|
||||
),
|
||||
// 作业中
|
||||
WorkOrderStatusEnum.ARRIVED, Set.of(
|
||||
WorkOrderStatusEnum.PAUSED, // 暂停作业
|
||||
WorkOrderStatusEnum.COMPLETED // 完成作业
|
||||
),
|
||||
|
||||
// 暂停状态
|
||||
WorkOrderStatusEnum.PAUSED, Set.of(
|
||||
WorkOrderStatusEnum.ARRIVED, // 恢复作业
|
||||
WorkOrderStatusEnum.CANCELLED
|
||||
),
|
||||
// 暂停状态
|
||||
WorkOrderStatusEnum.PAUSED, Set.of(
|
||||
WorkOrderStatusEnum.ARRIVED, // 恢复作业
|
||||
WorkOrderStatusEnum.CANCELLED
|
||||
),
|
||||
|
||||
// 终态
|
||||
WorkOrderStatusEnum.COMPLETED, Collections.emptySet(),
|
||||
WorkOrderStatusEnum.CANCELLED, Collections.emptySet()
|
||||
// 终态
|
||||
WorkOrderStatusEnum.COMPLETED, Collections.emptySet(),
|
||||
WorkOrderStatusEnum.CANCELLED, Collections.emptySet()
|
||||
);
|
||||
|
||||
/**
|
||||
* 状态变更监听器列表(支持扩展)
|
||||
*/
|
||||
private final List<OrderStateChangeListener> listeners = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 注册监听器
|
||||
*
|
||||
* @param listener 监听器实例
|
||||
*/
|
||||
public void registerListener(OrderStateChangeListener listener) {
|
||||
if (listener != null) {
|
||||
listeners.add(listener);
|
||||
log.info("注册状态监听器: {}", listener.getClass().getSimpleName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行状态转换(核心方法)
|
||||
* <p>
|
||||
* 此方法负责:
|
||||
* 1. 验证状态转换合法性
|
||||
* 2. 更新工单状态和相关字段
|
||||
* 3. 记录事件流
|
||||
* 4. 发布状态变更事件
|
||||
*
|
||||
* @param order 工单对象
|
||||
* @param newStatus 目标状态
|
||||
* @param order 工单对象
|
||||
* @param newStatus 目标状态
|
||||
* @param operatorType 操作人类型
|
||||
* @param operatorId 操作人ID
|
||||
* @param remark 说明
|
||||
* @param operatorId 操作人ID
|
||||
* @param remark 说明
|
||||
* @throws IllegalArgumentException 参数不合法
|
||||
* @throws IllegalStateException 状态转换不合法
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void transition(OpsOrderDO order,
|
||||
@@ -137,32 +145,57 @@ public class OrderStateMachine {
|
||||
|
||||
// 4. 记录事件流
|
||||
eventService.recordEvent(
|
||||
order.getId(),
|
||||
oldStatus.name(),
|
||||
newStatus.name(),
|
||||
determineEventType(newStatus),
|
||||
operatorType.getType(),
|
||||
operatorId,
|
||||
remark
|
||||
order.getId(),
|
||||
oldStatus.name(),
|
||||
newStatus.name(),
|
||||
determineEventType(newStatus),
|
||||
operatorType.getType(),
|
||||
operatorId,
|
||||
remark
|
||||
);
|
||||
|
||||
// 5. 触发监听器(扩展点)
|
||||
notifyListeners(order, oldStatus, newStatus, operatorType, operatorId, remark);
|
||||
// 5. 发布状态变更事件(替代监听器机制)
|
||||
publishStateChangedEvent(order, oldStatus, newStatus, operatorType, operatorId, remark);
|
||||
|
||||
log.info("工单状态转换成功: orderId={}, {} -> {}, operatorType={}, operatorId={}",
|
||||
order.getId(), oldStatus, newStatus, operatorType, operatorId);
|
||||
order.getId(), oldStatus, newStatus, operatorType, operatorId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查状态转换是否合法(不执行转换)
|
||||
*
|
||||
* @param fromStatus 当前状态
|
||||
* @param toStatus 目标状态
|
||||
* @return 是否可以转换
|
||||
*/
|
||||
public boolean canTransition(WorkOrderStatusEnum fromStatus, WorkOrderStatusEnum toStatus) {
|
||||
if (fromStatus == null || toStatus == null) {
|
||||
return false;
|
||||
}
|
||||
Set<WorkOrderStatusEnum> allowedTargets = TRANSITIONS.get(fromStatus);
|
||||
return allowedTargets != null && allowedTargets.contains(toStatus);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前状态允许转换到的目标状态集合
|
||||
*
|
||||
* @param currentStatus 当前状态
|
||||
* @return 允许的目标状态集合
|
||||
*/
|
||||
public Set<WorkOrderStatusEnum> getAllowedTransitions(WorkOrderStatusEnum currentStatus) {
|
||||
return TRANSITIONS.getOrDefault(currentStatus, Collections.emptySet());
|
||||
}
|
||||
|
||||
// ==================== 私有方法 ====================
|
||||
|
||||
/**
|
||||
* 校验状态转换是否合法
|
||||
*/
|
||||
private void validateTransition(WorkOrderStatusEnum currentStatus, WorkOrderStatusEnum newStatus) {
|
||||
Set<WorkOrderStatusEnum> allowedTargets = TRANSITIONS.get(currentStatus);
|
||||
|
||||
if (allowedTargets == null || !allowedTargets.contains(newStatus)) {
|
||||
if (!canTransition(currentStatus, newStatus)) {
|
||||
throw new IllegalStateException(String.format(
|
||||
"非法状态转换: %s -> %s,该转换不被允许",
|
||||
currentStatus.name(), newStatus.name()
|
||||
"非法状态转换: %s -> %s,该转换不被允许",
|
||||
currentStatus.name(), newStatus.name()
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -172,39 +205,33 @@ public class OrderStateMachine {
|
||||
*/
|
||||
private void updateStatusFields(OpsOrderDO order, WorkOrderStatusEnum newStatus) {
|
||||
switch (newStatus) {
|
||||
case QUEUED:
|
||||
case QUEUED -> {
|
||||
// 入队时无需特殊处理
|
||||
break;
|
||||
|
||||
case DISPATCHED:
|
||||
}
|
||||
case DISPATCHED -> {
|
||||
// 派单时记录派单时间(如有需要)
|
||||
break;
|
||||
|
||||
case CONFIRMED:
|
||||
// 确认时,保洁员状态由 CleanOrderService 处理
|
||||
break;
|
||||
|
||||
case ARRIVED:
|
||||
}
|
||||
case CONFIRMED -> {
|
||||
// 确认时,保洁员状态由业务层处理
|
||||
}
|
||||
case ARRIVED -> {
|
||||
// 到岗时记录开始时间
|
||||
order.setStartTime(LocalDateTime.now());
|
||||
break;
|
||||
|
||||
case PAUSED:
|
||||
// 暂停时,记录暂停时间由保洁业务线处理
|
||||
break;
|
||||
|
||||
case COMPLETED:
|
||||
}
|
||||
case PAUSED -> {
|
||||
// 暂停时,记录暂停时间由业务层处理
|
||||
}
|
||||
case COMPLETED -> {
|
||||
// 完成时记录结束时间
|
||||
order.setEndTime(LocalDateTime.now());
|
||||
break;
|
||||
|
||||
case CANCELLED:
|
||||
}
|
||||
case CANCELLED -> {
|
||||
// 取消时记录结束时间
|
||||
order.setEndTime(LocalDateTime.now());
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
default -> {
|
||||
// 其他状态无需处理
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,47 +252,35 @@ public class OrderStateMachine {
|
||||
}
|
||||
|
||||
/**
|
||||
* 触发所有监听器
|
||||
* 发布状态变更事件
|
||||
* <p>
|
||||
* 替代原有的监听器机制:
|
||||
* - 业务方通过 @EventListener 订阅事件
|
||||
* - 事件异步发布,不阻塞主流程
|
||||
*/
|
||||
private void notifyListeners(OpsOrderDO order,
|
||||
WorkOrderStatusEnum oldStatus,
|
||||
WorkOrderStatusEnum newStatus,
|
||||
OperatorTypeEnum operatorType,
|
||||
Long operatorId,
|
||||
String remark) {
|
||||
if (listeners.isEmpty()) {
|
||||
return;
|
||||
private void publishStateChangedEvent(OpsOrderDO order,
|
||||
WorkOrderStatusEnum oldStatus,
|
||||
WorkOrderStatusEnum newStatus,
|
||||
OperatorTypeEnum operatorType,
|
||||
Long operatorId,
|
||||
String remark) {
|
||||
try {
|
||||
OrderStateChangedEvent event = OrderStateChangedEvent.builder()
|
||||
.orderId(order.getId())
|
||||
.orderType(order.getOrderType())
|
||||
.orderCode(order.getOrderCode())
|
||||
.oldStatus(oldStatus)
|
||||
.newStatus(newStatus)
|
||||
.operatorType(operatorType)
|
||||
.operatorId(operatorId)
|
||||
.eventTime(LocalDateTime.now())
|
||||
.remark(remark)
|
||||
.build();
|
||||
|
||||
eventPublisher.publishStateChanged(event);
|
||||
} catch (Exception e) {
|
||||
// 事件发布失败不应影响主流程
|
||||
log.error("发布状态变更事件失败: orderId={}", order.getId(), e);
|
||||
}
|
||||
|
||||
OrderStateChangedEvent event = OrderStateChangedEvent.builder()
|
||||
.order(order)
|
||||
.oldStatus(oldStatus)
|
||||
.newStatus(newStatus)
|
||||
.operatorType(operatorType)
|
||||
.operatorId(operatorId)
|
||||
.eventTime(LocalDateTime.now())
|
||||
.remark(remark)
|
||||
.build();
|
||||
|
||||
listeners.forEach(listener -> {
|
||||
try {
|
||||
listener.onStateChanged(event);
|
||||
} catch (Exception e) {
|
||||
// 监听器异常不影响主流程
|
||||
log.error("[状态监听器] 执行失败: listener={}, orderId={}, error={}",
|
||||
listener.getClass().getSimpleName(), order.getId(), e.getMessage(), e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前状态允许转换到的目标状态集合
|
||||
*
|
||||
* @param currentStatus 当前状态
|
||||
* @return 允许的目标状态集合
|
||||
*/
|
||||
public Set<WorkOrderStatusEnum> getAllowedTransitions(WorkOrderStatusEnum currentStatus) {
|
||||
return TRANSITIONS.getOrDefault(currentStatus, Collections.emptySet());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user