diff --git a/viewsh-module-ops/viewsh-module-ops-biz/src/main/java/com/viewsh/module/ops/service/fsm/OrderStateMachine.java b/viewsh-module-ops/viewsh-module-ops-biz/src/main/java/com/viewsh/module/ops/service/fsm/OrderStateMachine.java index 50d098f..1d1acef 100644 --- a/viewsh-module-ops/viewsh-module-ops-biz/src/main/java/com/viewsh/module/ops/service/fsm/OrderStateMachine.java +++ b/viewsh-module-ops/viewsh-module-ops-biz/src/main/java/com/viewsh/module/ops/service/fsm/OrderStateMachine.java @@ -93,22 +93,21 @@ public class OrderStateMachine { WorkOrderStatusEnum.CANCELLED, Collections.emptySet() ); + /** 终态集合,不允许再转换 */ + private static final Set TERMINAL_STATES = Set.of( + WorkOrderStatusEnum.COMPLETED, WorkOrderStatusEnum.CANCELLED + ); + /** - * 执行状态转换(核心方法) - *

- * 此方法负责: - * 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 状态转换不合法 + * @throws IllegalStateException 状态转换不合法 */ @Transactional(rollbackFor = Exception.class) public void transition(OpsOrderDO order, @@ -116,7 +115,66 @@ public class OrderStateMachine { OperatorTypeEnum operatorType, Long operatorId, String remark) { + doTransition(order, newStatus, operatorType, operatorId, remark, true); + } + /** + * 强制状态跳转(不受转换规则限制) + *

+ * 适用于系统自动结单等场景:告警自动解除时工单可能处于任何非终态, + * 需要直接跳转到 COMPLETED / CANCELLED,不经过中间状态。 + *

+ * 与 {@link #transition} 的区别:跳过转换规则校验, + * 其余逻辑(字段更新、事件记录)完全一致。 + * + * @param order 工单对象 + * @param newStatus 目标状态(通常为终态 COMPLETED / CANCELLED) + * @param operatorType 操作人类型 + * @param operatorId 操作人ID + * @param remark 说明 + * @throws IllegalArgumentException 参数不合法 + * @throws IllegalStateException 当前已是终态 + */ + @Transactional(rollbackFor = Exception.class) + public void forceTransition(OpsOrderDO order, + WorkOrderStatusEnum newStatus, + OperatorTypeEnum operatorType, + Long operatorId, + String remark) { + doTransition(order, newStatus, operatorType, operatorId, remark, false); + } + + /** + * 检查状态转换是否合法(不执行转换) + */ + public boolean canTransition(WorkOrderStatusEnum fromStatus, WorkOrderStatusEnum toStatus) { + if (fromStatus == null || toStatus == null) { + return false; + } + Set allowedTargets = TRANSITIONS.get(fromStatus); + return allowedTargets != null && allowedTargets.contains(toStatus); + } + + /** + * 获取当前状态允许转换到的目标状态集合 + */ + public Set getAllowedTransitions(WorkOrderStatusEnum currentStatus) { + return TRANSITIONS.getOrDefault(currentStatus, Collections.emptySet()); + } + + // ==================== 私有方法 ==================== + + /** + * 状态转换核心逻辑(transition / forceTransition 的统一实现) + * + * @param validate true=校验转换规则(transition),false=仅校验终态(forceTransition) + */ + private void doTransition(OpsOrderDO order, + WorkOrderStatusEnum newStatus, + OperatorTypeEnum operatorType, + Long operatorId, + String remark, + boolean validate) { // 1. 参数校验 if (order == null) { throw new IllegalArgumentException("工单对象不能为空"); @@ -128,15 +186,19 @@ public class OrderStateMachine { // 2. 获取当前状态 WorkOrderStatusEnum currentStatus = WorkOrderStatusEnum.valueOf(order.getStatus()); - // 3. 如果目标状态与当前状态相同,直接返回(避免不必要的操作) + // 3. 相同状态,跳过 if (currentStatus == newStatus) { - log.debug("工单状态未变化,跳过状态转换: orderId={}, status={}", - order.getId(), currentStatus); + log.debug("工单状态未变化,跳过: orderId={}, status={}", order.getId(), currentStatus); return; } - // 4. 校验状态转换合法性 - validateTransition(currentStatus, newStatus); + // 4. 校验 + if (validate) { + validateTransition(currentStatus, newStatus); + } else if (TERMINAL_STATES.contains(currentStatus)) { + throw new IllegalStateException(String.format( + "工单已处于终态 %s,无法转换到 %s", currentStatus.name(), newStatus.name())); + } // 5. 更新工单状态和相关字段 WorkOrderStatusEnum oldStatus = currentStatus; @@ -155,37 +217,10 @@ public class OrderStateMachine { remark ); - log.info("工单状态转换成功: orderId={}, {} -> {}, operatorType={}, operatorId={}", - order.getId(), oldStatus, newStatus, operatorType, operatorId); + log.info("工单状态转换: orderId={}, {} -> {}, forced={}, operatorType={}, operatorId={}", + order.getId(), oldStatus, newStatus, !validate, operatorType, operatorId); } - /** - * 检查状态转换是否合法(不执行转换) - * - * @param fromStatus 当前状态 - * @param toStatus 目标状态 - * @return 是否可以转换 - */ - public boolean canTransition(WorkOrderStatusEnum fromStatus, WorkOrderStatusEnum toStatus) { - if (fromStatus == null || toStatus == null) { - return false; - } - Set allowedTargets = TRANSITIONS.get(fromStatus); - return allowedTargets != null && allowedTargets.contains(toStatus); - } - - /** - * 获取当前状态允许转换到的目标状态集合 - * - * @param currentStatus 当前状态 - * @return 允许的目标状态集合 - */ - public Set getAllowedTransitions(WorkOrderStatusEnum currentStatus) { - return TRANSITIONS.getOrDefault(currentStatus, Collections.emptySet()); - } - - // ==================== 私有方法 ==================== - /** * 校验状态转换是否合法 */