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