From 161f55007b480479354d537deedd2cc467ef475f Mon Sep 17 00:00:00 2001 From: lzh Date: Wed, 25 Feb 2026 17:12:01 +0800 Subject: [PATCH] =?UTF-8?q?fix(ops):=20=E6=89=8B=E5=8A=A8=E5=AE=8C?= =?UTF-8?q?=E5=8D=95=E8=B5=B0=E5=AE=8C=E6=95=B4=E8=B4=A3=E4=BB=BB=E9=93=BE?= =?UTF-8?q?=EF=BC=8C=E8=A1=A5=E5=85=A8=E9=98=9F=E5=88=97=E5=90=8C=E6=AD=A5?= =?UTF-8?q?=E3=80=81=E8=AE=BE=E5=A4=87=E7=8A=B6=E6=80=81=E3=80=81=E4=BA=8B?= =?UTF-8?q?=E4=BB=B6=E5=8F=91=E5=B8=83=E7=AD=89=E7=BC=BA=E5=A4=B1=E7=8E=AF?= =?UTF-8?q?=E8=8A=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 原手动完单逻辑直接更新 DB 状态,绕过了 OrderLifecycleManager 责任链, 导致队列未清理、工牌设备状态未恢复 IDLE、自动派发下一任务未触发、 事件表缺少操作人信息等问题。 改动: - CleanWorkOrderServiceImpl.manualCompleteOrder 改为委托 OrderLifecycleManager - OrderLifecycleManager 新增 completeOrder(orderId, operatorId, operatorType, remark) 重载 - Controller 注入 SecurityFrameworkUtils.getLoginUserId() 填充操作人 - EventPublishHandler 修复 OrderCompletedEvent.assigneeId 兜底逻辑 - 新增已完成幂等返回和已取消拒绝校验 Co-Authored-By: Claude Opus 4.6 --- .../dataobject/ManualCompleteOrderReqDTO.java | 3 + .../cleanorder/CleanWorkOrderServiceImpl.java | 63 +++++++++---------- .../core/lifecycle/OrderLifecycleManager.java | 12 ++++ .../lifecycle/OrderLifecycleManagerImpl.java | 15 +++-- .../handler/EventPublishHandler.java | 7 ++- .../admin/clean/CleanWorkOrderController.java | 3 + 6 files changed, 64 insertions(+), 39 deletions(-) diff --git a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/dal/dataobject/ManualCompleteOrderReqDTO.java b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/dal/dataobject/ManualCompleteOrderReqDTO.java index fecca9e..3d0bdf5 100644 --- a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/dal/dataobject/ManualCompleteOrderReqDTO.java +++ b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/dal/dataobject/ManualCompleteOrderReqDTO.java @@ -21,4 +21,7 @@ public class ManualCompleteOrderReqDTO { @Schema(description = "备注", example = "管理员手动完成") private String remark; + + @Schema(description = "操作人ID(由后端自动填充)", hidden = true) + private Long operatorId; } diff --git a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/cleanorder/CleanWorkOrderServiceImpl.java b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/cleanorder/CleanWorkOrderServiceImpl.java index d7d5e3e..d127753 100644 --- a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/cleanorder/CleanWorkOrderServiceImpl.java +++ b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/cleanorder/CleanWorkOrderServiceImpl.java @@ -2,10 +2,13 @@ package com.viewsh.module.ops.environment.service.cleanorder; import com.viewsh.framework.mybatis.core.query.LambdaQueryWrapperX; import com.viewsh.module.ops.api.clean.OrderTimelineRespDTO; +import com.viewsh.module.ops.core.lifecycle.OrderLifecycleManager; import com.viewsh.module.ops.dal.dataobject.workorder.OpsOrderDO; import com.viewsh.module.ops.dal.dataobject.workorder.OpsOrderEventDO; import com.viewsh.module.ops.dal.mysql.workorder.OpsOrderEventMapper; 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.environment.dal.dataobject.ManualCompleteOrderReqDTO; import com.viewsh.module.ops.environment.dal.dataobject.UpgradePriorityReqDTO; import com.viewsh.module.ops.service.event.OpsOrderEventService; @@ -40,6 +43,9 @@ public class CleanWorkOrderServiceImpl implements CleanWorkOrderService { @Resource private OpsOrderEventService opsOrderEventService; + @Resource + private OrderLifecycleManager orderLifecycleManager; + /** * 事件类型名称映射 */ @@ -120,42 +126,31 @@ public class CleanWorkOrderServiceImpl implements CleanWorkOrderService { @Override @Transactional(rollbackFor = Exception.class) public void manualCompleteOrder(ManualCompleteOrderReqDTO req) { - try { - Long orderId = req.getOrderId(); + Long orderId = req.getOrderId(); - // 1. 查询工单 - OpsOrderDO order = opsOrderMapper.selectById(orderId); - if (order == null) { - log.warn("[manualCompleteOrder] 工单不存在: orderId={}", orderId); - return; - } - - String fromStatus = order.getStatus(); - - // 2. 更新工单状态为已完成 - OpsOrderDO updateDO = new OpsOrderDO(); - updateDO.setId(orderId); - updateDO.setStatus("COMPLETED"); - updateDO.setEndTime(LocalDateTime.now()); - opsOrderMapper.updateById(updateDO); - - // 3. 记录事件 - opsOrderEventService.recordEvent( - orderId, - fromStatus, - "COMPLETED", - "COMPLETE", - "ADMIN", - null, // 管理员操作,当前未传递具体ID - req.getRemark() != null ? req.getRemark() : "管理员手动完成" - ); - - log.info("[manualCompleteOrder] 手动完成工单成功: orderId={}, remark={}", orderId, req.getRemark()); - - } catch (Exception e) { - log.error("[manualCompleteOrder] 手动完成工单失败: orderId={}", req.getOrderId(), e); - throw e; + // 1. 查询工单 + OpsOrderDO order = opsOrderMapper.selectById(orderId); + if (order == null) { + throw new IllegalArgumentException("工单不存在: orderId=" + orderId); } + + // 2. 校验:已完成的工单幂等返回 + if (WorkOrderStatusEnum.COMPLETED.getStatus().equals(order.getStatus())) { + log.info("[manualCompleteOrder] 工单已处于完成状态,幂等返回: orderId={}", orderId); + return; + } + + // 3. 校验:已取消的工单不能完成 + if (WorkOrderStatusEnum.CANCELLED.getStatus().equals(order.getStatus())) { + throw new IllegalStateException("已取消的工单不能完成: orderId=" + orderId); + } + + // 4. 通过 OrderLifecycleManager 走完整责任链(状态校验→队列同步→事件发布) + String remark = req.getRemark() != null ? req.getRemark() : "管理员手动完成"; + orderLifecycleManager.completeOrder(orderId, req.getOperatorId(), OperatorTypeEnum.ADMIN, remark); + + log.info("[manualCompleteOrder] 手动完成工单成功: orderId={}, operatorId={}, remark={}", + orderId, req.getOperatorId(), remark); } @Override diff --git a/viewsh-module-ops/viewsh-module-ops-biz/src/main/java/com/viewsh/module/ops/core/lifecycle/OrderLifecycleManager.java b/viewsh-module-ops/viewsh-module-ops-biz/src/main/java/com/viewsh/module/ops/core/lifecycle/OrderLifecycleManager.java index 92dfb35..cbce021 100644 --- a/viewsh-module-ops/viewsh-module-ops-biz/src/main/java/com/viewsh/module/ops/core/lifecycle/OrderLifecycleManager.java +++ b/viewsh-module-ops/viewsh-module-ops-biz/src/main/java/com/viewsh/module/ops/core/lifecycle/OrderLifecycleManager.java @@ -140,6 +140,18 @@ public interface OrderLifecycleManager { */ void completeOrder(Long orderId, Long operatorId, String remark); + /** + * 完成工单(指定操作人类型) + *

+ * 用于管理员手动完单等场景,允许指定操作人类型 + * + * @param orderId 工单ID + * @param operatorId 操作人ID + * @param operatorType 操作人类型 + * @param remark 完成备注 + */ + void completeOrder(Long orderId, Long operatorId, OperatorTypeEnum operatorType, String remark); + /** * 取消工单 *

diff --git a/viewsh-module-ops/viewsh-module-ops-biz/src/main/java/com/viewsh/module/ops/core/lifecycle/OrderLifecycleManagerImpl.java b/viewsh-module-ops/viewsh-module-ops-biz/src/main/java/com/viewsh/module/ops/core/lifecycle/OrderLifecycleManagerImpl.java index 29fef7c..10f86af 100644 --- a/viewsh-module-ops/viewsh-module-ops-biz/src/main/java/com/viewsh/module/ops/core/lifecycle/OrderLifecycleManagerImpl.java +++ b/viewsh-module-ops/viewsh-module-ops-biz/src/main/java/com/viewsh/module/ops/core/lifecycle/OrderLifecycleManagerImpl.java @@ -268,13 +268,20 @@ public class OrderLifecycleManagerImpl implements OrderLifecycleManager { @Override @Transactional(rollbackFor = Exception.class) public void completeOrder(Long orderId, Long operatorId, String remark) { - log.info("开始完成工单: orderId={}, operatorId={}, remark={}", orderId, operatorId, remark); + completeOrder(orderId, operatorId, OperatorTypeEnum.CLEANER, remark); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void completeOrder(Long orderId, Long operatorId, OperatorTypeEnum operatorType, String remark) { + log.info("开始完成工单: orderId={}, operatorId={}, operatorType={}, remark={}", + orderId, operatorId, operatorType, remark); // 构建请求 OrderTransitionRequest request = OrderTransitionRequest.builder() .orderId(orderId) .targetStatus(WorkOrderStatusEnum.COMPLETED) - .operatorType(OperatorTypeEnum.CLEANER) + .operatorType(operatorType) .operatorId(operatorId) .reason(remark) .build(); @@ -287,8 +294,8 @@ public class OrderLifecycleManagerImpl implements OrderLifecycleManager { } // 注意:IoT 触发的自动完成在 CleanOrderCompleteEventHandler 中记录日志 - // 这里只记录手动完成的日志(operatorId 不为空的情况) - if (operatorId != null) { + // 管理员手动完成时记录日志 + if (operatorType == OperatorTypeEnum.ADMIN) { recordStatusChangeLog(orderId, result, "ORDER_COMPLETED_MANUAL", "工单手动完成"); } } diff --git a/viewsh-module-ops/viewsh-module-ops-biz/src/main/java/com/viewsh/module/ops/core/lifecycle/handler/EventPublishHandler.java b/viewsh-module-ops/viewsh-module-ops-biz/src/main/java/com/viewsh/module/ops/core/lifecycle/handler/EventPublishHandler.java index 788e38e..ae2810c 100644 --- a/viewsh-module-ops/viewsh-module-ops-biz/src/main/java/com/viewsh/module/ops/core/lifecycle/handler/EventPublishHandler.java +++ b/viewsh-module-ops/viewsh-module-ops-biz/src/main/java/com/viewsh/module/ops/core/lifecycle/handler/EventPublishHandler.java @@ -64,11 +64,16 @@ public class EventPublishHandler extends TransitionHandler { // 如果是完成状态,额外发布完成事件 if (targetStatus == WorkOrderStatusEnum.COMPLETED) { + // assigneeId 优先从 request 获取,兜底从工单对象获取(手动完单等场景 request 中无 assigneeId) + Long assigneeId = request.getAssigneeId() != null + ? request.getAssigneeId() + : context.getOrder().getAssigneeId(); + OrderCompletedEvent completedEvent = OrderCompletedEvent.builder() .orderId(context.getOrder().getId()) .orderCode(context.getOrder().getOrderCode()) .orderType(context.getOrder().getOrderType()) - .assigneeId(request.getAssigneeId()) + .assigneeId(assigneeId) .workDuration(calculateWorkDuration(context)) .build(); diff --git a/viewsh-module-ops/viewsh-module-ops-server/src/main/java/com/viewsh/module/ops/controller/admin/clean/CleanWorkOrderController.java b/viewsh-module-ops/viewsh-module-ops-server/src/main/java/com/viewsh/module/ops/controller/admin/clean/CleanWorkOrderController.java index 438d53e..0948acc 100644 --- a/viewsh-module-ops/viewsh-module-ops-server/src/main/java/com/viewsh/module/ops/controller/admin/clean/CleanWorkOrderController.java +++ b/viewsh-module-ops/viewsh-module-ops-server/src/main/java/com/viewsh/module/ops/controller/admin/clean/CleanWorkOrderController.java @@ -1,6 +1,7 @@ package com.viewsh.module.ops.controller.admin.clean; import com.viewsh.framework.common.pojo.CommonResult; +import com.viewsh.framework.security.core.util.SecurityFrameworkUtils; import com.viewsh.module.ops.api.clean.OrderTimelineRespDTO; import com.viewsh.module.ops.environment.dal.dataobject.ManualCompleteOrderReqDTO; import com.viewsh.module.ops.environment.dal.dataobject.UpgradePriorityReqDTO; @@ -49,6 +50,8 @@ public class CleanWorkOrderController { public CommonResult manualCompleteOrder( @Valid @RequestBody ManualCompleteOrderReqDTO req) { + // 注入当前登录用户ID作为操作人 + req.setOperatorId(SecurityFrameworkUtils.getLoginUserId()); cleanWorkOrderService.manualCompleteOrder(req); return success(true); }