diff --git a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/cleanorder/CleanWorkOrderService.java b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/cleanorder/CleanWorkOrderService.java index 68c9b00..c0a5a10 100644 --- a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/cleanorder/CleanWorkOrderService.java +++ b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/cleanorder/CleanWorkOrderService.java @@ -1,6 +1,9 @@ package com.viewsh.module.ops.environment.service.cleanorder; import com.viewsh.module.ops.api.clean.OrderTimelineRespDTO; +import com.viewsh.module.ops.environment.service.cleanorder.dto.CleanManualCancelReqDTO; +import com.viewsh.module.ops.environment.service.cleanorder.dto.CleanManualCreateReqDTO; +import com.viewsh.module.ops.environment.service.cleanorder.dto.CleanManualDispatchReqDTO; import com.viewsh.module.ops.environment.service.cleanorder.dto.ManualCompleteOrderReqDTO; import com.viewsh.module.ops.environment.service.cleanorder.dto.UpgradePriorityReqDTO; @@ -47,4 +50,32 @@ public interface CleanWorkOrderService { * @param req 升级优先级请求 */ void upgradePriority(UpgradePriorityReqDTO req); + + /** + * 手动创建保洁工单 + *
+ * 管理员手动创建保洁工单,补齐主表 + 扩展表 + 创建事件 + 审计日志 + * + * @param req 手动创建请求 + * @return 工单ID + */ + Long manualCreateOrder(CleanManualCreateReqDTO req); + + /** + * 手动派单 + *
+ * 管理员指定设备/人员,绕过自动调度直接派单 + * + * @param req 手动派单请求 + */ + void manualDispatch(CleanManualDispatchReqDTO req); + + /** + * 手动取消工单 + *
+ * 管理员手动取消工单,走完整生命周期链(停止播报、恢复状态、自动派发下一单)
+ *
+ * @param req 手动取消请求
+ */
+ void manualCancelOrder(CleanManualCancelReqDTO req);
}
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 af3cf68..fd8e3d7 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,16 +2,30 @@ 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.api.queue.OrderQueueService;
+import com.viewsh.module.ops.core.event.OrderCreatedEvent;
+import com.viewsh.module.ops.core.event.OrderEventPublisher;
import com.viewsh.module.ops.core.lifecycle.OrderLifecycleManager;
+import com.viewsh.module.ops.core.manual.ManualOrderActionFacade;
+import com.viewsh.module.ops.core.manual.audit.OrderAuditService;
+import com.viewsh.module.ops.core.manual.model.*;
+import com.viewsh.module.ops.dal.dataobject.area.OpsBusAreaDO;
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.area.OpsBusAreaMapper;
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.service.cleanorder.dto.ManualCompleteOrderReqDTO;
-import com.viewsh.module.ops.environment.service.cleanorder.dto.UpgradePriorityReqDTO;
+import com.viewsh.module.ops.enums.*;
+import com.viewsh.module.ops.environment.dal.dataobject.workorder.OpsOrderCleanExtDO;
+import com.viewsh.module.ops.environment.dal.mysql.workorder.OpsOrderCleanExtMapper;
+import com.viewsh.module.ops.environment.service.cleanorder.dto.*;
+import com.viewsh.module.ops.infrastructure.area.AreaPathBuilder;
+import com.viewsh.module.ops.infrastructure.code.OrderCodeGenerator;
+import com.viewsh.module.ops.infrastructure.id.OrderIdGenerator;
+import com.viewsh.module.ops.infrastructure.log.recorder.EventLogRecorder;
import com.viewsh.module.ops.service.event.OpsOrderEventService;
+import com.viewsh.module.system.api.user.AdminUserApi;
+import com.viewsh.module.system.api.user.dto.AdminUserRespDTO;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@@ -41,10 +55,33 @@ public class CleanWorkOrderServiceImpl implements CleanWorkOrderService {
private OpsOrderEventMapper opsOrderEventMapper;
@Resource
- private OpsOrderEventService opsOrderEventService;
+ private AdminUserApi adminUserApi;
@Resource
- private OrderLifecycleManager orderLifecycleManager;
+ private OrderIdGenerator orderIdGenerator;
+
+ @Resource
+ private OrderCodeGenerator orderCodeGenerator;
+
+ @Resource
+ private OrderEventPublisher orderEventPublisher;
+
+ @Resource
+ private OpsBusAreaMapper opsBusAreaMapper;
+
+ @Resource
+ private AreaPathBuilder areaPathBuilder;
+
+ @Resource
+ private OpsOrderCleanExtMapper cleanExtMapper;
+
+ @Resource
+ private ManualOrderActionFacade manualOrderActionFacade;
+
+ @Resource
+ private OrderAuditService orderAuditService;
+
+ private static final String BUSINESS_TYPE = WorkOrderTypeEnum.CLEAN.getType();
/**
* 事件类型名称映射
@@ -124,75 +161,24 @@ public class CleanWorkOrderServiceImpl implements CleanWorkOrderService {
}
@Override
- @Transactional(rollbackFor = Exception.class)
public void manualCompleteOrder(ManualCompleteOrderReqDTO req) {
- Long orderId = req.getOrderId();
-
- // 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);
+ manualOrderActionFacade.complete(CompleteOrderCommand.builder()
+ .businessType(BUSINESS_TYPE)
+ .orderId(req.getOrderId())
+ .operator(OperatorContext.ofAdmin(req.getOperatorId(), resolveUserName(req.getOperatorId())))
+ .reason(req.getRemark())
+ .build());
}
@Override
- @Transactional(rollbackFor = Exception.class)
public void upgradePriority(UpgradePriorityReqDTO req) {
- try {
- Long orderId = req.getOrderId();
-
- // 1. 查询工单
- OpsOrderDO order = opsOrderMapper.selectById(orderId);
- if (order == null) {
- log.warn("[upgradePriority] 工单不存在: orderId={}", orderId);
- return;
- }
-
- Integer oldPriority = order.getPriority();
-
- // 2. 更新工单优先级为 P0
- OpsOrderDO updateDO = new OpsOrderDO();
- updateDO.setId(orderId);
- updateDO.setPriority(0); // P0
- opsOrderMapper.updateById(updateDO);
-
- // 3. 记录事件
- opsOrderEventService.recordEvent(
- orderId,
- order.getStatus(),
- order.getStatus(),
- "UPGRADE_PRIORITY",
- "ADMIN",
- null, // 管理员操作
- String.format("优先级从 P%d 升级为 P0: %s",
- oldPriority != null ? oldPriority : 1, req.getReason())
- );
-
- log.info("[upgradePriority] 升级工单优先级成功: orderId={}, oldPriority={}, reason={}",
- orderId, oldPriority, req.getReason());
-
- } catch (Exception e) {
- log.error("[upgradePriority] 升级工单优先级失败: orderId={}", req.getOrderId(), e);
- throw e;
- }
+ manualOrderActionFacade.upgradePriority(UpgradePriorityCommand.builder()
+ .businessType(BUSINESS_TYPE)
+ .orderId(req.getOrderId())
+ .operator(OperatorContext.ofAdmin(req.getOperatorId(), resolveUserName(req.getOperatorId())))
+ .newPriority(req.getEffectiveNewPriority())
+ .reason(req.getReason())
+ .build());
}
// ==================== 私有方法 ====================
@@ -208,7 +194,7 @@ public class CleanWorkOrderServiceImpl implements CleanWorkOrderService {
String operator = event.getOperatorName();
if (operator == null || operator.isEmpty()) {
- if ("SYSTEM".equals(event.getOperatorType())) {
+ if (OperatorTypeEnum.SYSTEM.getType().equals(event.getOperatorType())) {
operator = "系统";
} else {
operator = "操作员";
@@ -259,8 +245,8 @@ public class CleanWorkOrderServiceImpl implements CleanWorkOrderService {
*/
private Map
- * 用于将普通工单升级为 P0 紧急工单
*
* @author lzh
*/
@@ -20,7 +18,20 @@ public class UpgradePriorityReqDTO {
@NotNull(message = "工单ID不能为空")
private Long orderId;
+ @Schema(description = "目标优先级(0=P0紧急, 1=P1重要, 2=P2普通),默认 0(P0)", example = "0")
+ private Integer newPriority;
+
@Schema(description = "升级原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "客户投诉急需处理")
@NotBlank(message = "升级原因不能为空")
private String reason;
+
+ @Schema(description = "操作人ID(由 Controller 注入)", hidden = true)
+ private Long operatorId;
+
+ /**
+ * 获取目标优先级,默认 P0
+ */
+ public Integer getEffectiveNewPriority() {
+ return newPriority != null ? newPriority : 0;
+ }
}
diff --git a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/manual/CleanOrderBusinessStrategy.java b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/manual/CleanOrderBusinessStrategy.java
index 35f441f..f90e2ee 100644
--- a/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/manual/CleanOrderBusinessStrategy.java
+++ b/viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/manual/CleanOrderBusinessStrategy.java
@@ -1,21 +1,22 @@
package com.viewsh.module.ops.environment.service.manual;
+import com.viewsh.module.ops.api.badge.BadgeDeviceStatusDTO;
+import com.viewsh.module.ops.api.queue.OrderQueueDTO;
import com.viewsh.module.ops.api.queue.OrderQueueService;
-import com.viewsh.module.ops.core.manual.model.*;
+import com.viewsh.module.ops.core.manual.model.DispatchOrderCommand;
+import com.viewsh.module.ops.core.manual.model.UpgradePriorityCommand;
import com.viewsh.module.ops.core.manual.strategy.OrderBusinessStrategy;
import com.viewsh.module.ops.dal.dataobject.workorder.OpsOrderDO;
-import com.viewsh.module.ops.enums.WorkOrderStatusEnum;
+import com.viewsh.module.ops.enums.PriorityEnum;
import com.viewsh.module.ops.enums.WorkOrderTypeEnum;
+import com.viewsh.module.ops.environment.service.badge.BadgeDeviceStatusService;
+import com.viewsh.module.ops.environment.service.notification.CleanOrderNotificationService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
- * 保洁条线策略
- *
- * 处理保洁特有的前置校验和后置副作用。
- *
- * @author lzh
+ * 保洁条线策略。
*/
@Slf4j
@Component
@@ -24,18 +25,60 @@ public class CleanOrderBusinessStrategy implements OrderBusinessStrategy {
@Resource
private OrderQueueService orderQueueService;
+ @Resource
+ private CleanOrderNotificationService cleanOrderNotificationService;
+
+ @Resource
+ private BadgeDeviceStatusService badgeDeviceStatusService;
+
@Override
public boolean supports(String businessType) {
return WorkOrderTypeEnum.CLEAN.getType().equals(businessType);
}
@Override
- public void afterUpgradePriority(UpgradePriorityCommand cmd, OpsOrderDO order) {
- // 如果工单在队列中,触发队列分数重算
- if (WorkOrderStatusEnum.QUEUED.getStatus().equals(order.getStatus()) && order.getAssigneeId() != null) {
- orderQueueService.rebuildWaitingTasksByUserId(order.getAssigneeId(), order.getAreaId());
- log.info("[CleanStrategy] 升级优先级后重算队列: orderId={}, assigneeId={}",
- cmd.getOrderId(), order.getAssigneeId());
+ public void validateDispatch(DispatchOrderCommand cmd, OpsOrderDO order) {
+ if (cmd.getAssigneeId() == null) {
+ throw new IllegalArgumentException("手动派单目标设备不能为空");
+ }
+
+ BadgeDeviceStatusDTO badge = badgeDeviceStatusService.getBadgeStatus(cmd.getAssigneeId());
+ if (badge == null) {
+ throw new IllegalStateException("目标保洁设备不存在");
+ }
+ if (!badge.isOnline()) {
+ throw new IllegalStateException("目标保洁设备当前离线,不能手动派单");
+ }
+ if (!badge.canAcceptNewOrder()) {
+ throw new IllegalStateException("目标保洁设备当前不可接单");
+ }
+ if (order.getAreaId() != null && badge.getCurrentAreaId() == null) {
+ throw new IllegalStateException("目标保洁设备当前未绑定区域,不能手动派单");
+ }
+ if (order.getAreaId() != null && !order.getAreaId().equals(badge.getCurrentAreaId())) {
+ throw new IllegalStateException("目标保洁设备不在当前工单所属区域");
}
}
+
+ @Override
+ public void afterUpgradePriority(UpgradePriorityCommand cmd, OpsOrderDO order) {
+ OrderQueueDTO queueDTO = orderQueueService.getByOpsOrderId(cmd.getOrderId());
+ if (queueDTO == null) {
+ return;
+ }
+
+ PriorityEnum newPriority = PriorityEnum.fromPriority(cmd.getNewPriority());
+ String reason = cmd.getReason() != null ? cmd.getReason() : "手动升级优先级";
+
+ orderQueueService.adjustPriority(queueDTO.getId(), newPriority, reason);
+ orderQueueService.rebuildWaitingTasksByUserId(queueDTO.getUserId(), order.getAreaId());
+
+ if (newPriority == PriorityEnum.P0) {
+ cleanOrderNotificationService.sendPriorityUpgradeNotification(
+ queueDTO.getUserId(), order.getOrderCode(), cmd.getOrderId());
+ }
+
+ log.info("[CleanStrategy] 升级优先级后置完成: orderId={}, newPriority={}, queueId={}",
+ cmd.getOrderId(), newPriority, queueDTO.getId());
+ }
}