chore: 【ops】工单生命周期操作(暂停、回复、完成、取消)
This commit is contained in:
@@ -0,0 +1,137 @@
|
||||
package com.viewsh.module.ops.core.lifecycle;
|
||||
|
||||
import com.viewsh.module.ops.enums.OperatorTypeEnum;
|
||||
import com.viewsh.module.ops.enums.PriorityEnum;
|
||||
|
||||
/**
|
||||
* 工单生命周期管理器接口
|
||||
* <p>
|
||||
* 职责:
|
||||
* 1. 统一管理工单状态和队列状态的同步
|
||||
* 2. 处理工单的暂停/恢复/打断等复杂状态变更
|
||||
* 3. 提供事务保证,确保状态一致性
|
||||
* <p>
|
||||
* 设计原则:
|
||||
* - 单一职责:只负责生命周期状态管理
|
||||
* - 事务保证:所有状态变更在同一事务中完成
|
||||
* - 扩展性:通过事件发布机制解耦业务逻辑
|
||||
*
|
||||
* @author lzh
|
||||
*/
|
||||
public interface OrderLifecycleManager {
|
||||
|
||||
// ==================== 暂停/恢复 ====================
|
||||
|
||||
/**
|
||||
* 暂停工单(同步更新队列状态和工单状态)
|
||||
* <p>
|
||||
* 状态转换:
|
||||
* - 工单状态:ARRIVED → PAUSED
|
||||
* - 队列状态:PROCESSING → PAUSED
|
||||
*
|
||||
* @param orderId 工单ID
|
||||
* @param operatorId 操作人ID
|
||||
* @param reason 暂停原因
|
||||
* @throws IllegalStateException 如果工单状态不允许暂停
|
||||
*/
|
||||
void pauseOrder(Long orderId, Long operatorId, String reason);
|
||||
|
||||
/**
|
||||
* 恢复工单(同步更新队列状态和工单状态)
|
||||
* <p>
|
||||
* 状态转换:
|
||||
* - 工单状态:PAUSED → DISPATCHED
|
||||
* - 队列状态:PAUSED → PROCESSING
|
||||
*
|
||||
* @param orderId 工单ID
|
||||
* @param operatorId 操作人ID
|
||||
* @throws IllegalStateException 如果工单状态不允许恢复
|
||||
*/
|
||||
void resumeOrder(Long orderId, Long operatorId);
|
||||
|
||||
// ==================== 打断/恢复 ====================
|
||||
|
||||
/**
|
||||
* 打断工单(P0紧急任务场景)
|
||||
* <p>
|
||||
* 状态转换:
|
||||
* - 工单状态:DISPATCHED/CONFIRMED/ARRIVED → PAUSED
|
||||
* - 队列状态:PROCESSING → PAUSED
|
||||
* <p>
|
||||
* 使用场景:当P0紧急任务需要插队时,打断当前正在执行的任务
|
||||
*
|
||||
* @param orderId 被打断的工单ID
|
||||
* @param urgentOrderId 紧急工单ID(P0任务)
|
||||
* @param operatorId 操作人ID
|
||||
* @throws IllegalStateException 如果工单状态不允许被打断
|
||||
*/
|
||||
void interruptOrder(Long orderId, Long urgentOrderId, Long operatorId);
|
||||
|
||||
/**
|
||||
* 恢复被打断的工单(P0任务完成后自动恢复)
|
||||
* <p>
|
||||
* 状态转换:
|
||||
* - 工单状态:PAUSED → DISPATCHED
|
||||
* - 队列状态:PAUSED → PROCESSING
|
||||
*
|
||||
* @param orderId 被打断的工单ID
|
||||
* @param operatorId 操作人ID
|
||||
*/
|
||||
void resumeInterruptedOrder(Long orderId, Long operatorId);
|
||||
|
||||
// ==================== 完工/取消 ====================
|
||||
|
||||
/**
|
||||
* 完成工单(清理队列记录)
|
||||
* <p>
|
||||
* 状态转换:
|
||||
* - 工单状态:ARRIVED → COMPLETED
|
||||
* - 队列状态:PROCESSING → REMOVED
|
||||
*
|
||||
* @param orderId 工单ID
|
||||
* @param operatorId 操作人ID
|
||||
* @param remark 完成备注
|
||||
*/
|
||||
void completeOrder(Long orderId, Long operatorId, String remark);
|
||||
|
||||
/**
|
||||
* 取消工单
|
||||
* <p>
|
||||
* 状态转换:
|
||||
* - 工单状态:任何非终态 → CANCELLED
|
||||
* - 队列状态:任何状态 → REMOVED
|
||||
*
|
||||
* @param orderId 工单ID
|
||||
* @param operatorId 操作人ID
|
||||
* @param operatorType 操作人类型
|
||||
* @param reason 取消原因
|
||||
*/
|
||||
void cancelOrder(Long orderId, Long operatorId, OperatorTypeEnum operatorType, String reason);
|
||||
|
||||
// ==================== 查询方法 ====================
|
||||
|
||||
/**
|
||||
* 检查工单是否可以暂停
|
||||
*
|
||||
* @param orderId 工单ID
|
||||
* @return 是否可以暂停
|
||||
*/
|
||||
boolean canPause(Long orderId);
|
||||
|
||||
/**
|
||||
* 检查工单是否可以恢复
|
||||
*
|
||||
* @param orderId 工单ID
|
||||
* @return 是否可以恢复
|
||||
*/
|
||||
boolean canResume(Long orderId);
|
||||
|
||||
/**
|
||||
* 检查工单是否可以打断
|
||||
*
|
||||
* @param orderId 工单ID
|
||||
* @param urgentPriority 紧急任务优先级
|
||||
* @return 是否可以打断
|
||||
*/
|
||||
boolean canInterrupt(Long orderId, PriorityEnum urgentPriority);
|
||||
}
|
||||
@@ -0,0 +1,373 @@
|
||||
package com.viewsh.module.ops.core.lifecycle;
|
||||
|
||||
import com.viewsh.module.ops.api.queue.OrderQueueDTO;
|
||||
import com.viewsh.module.ops.api.queue.OrderQueueService;
|
||||
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.PriorityEnum;
|
||||
import com.viewsh.module.ops.enums.WorkOrderStatusEnum;
|
||||
import com.viewsh.module.ops.service.fsm.OrderStateMachine;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 工单生命周期管理器实现
|
||||
* <p>
|
||||
* 职责:
|
||||
* 1. 统一管理工单状态和队列状态的同步
|
||||
* 2. 处理工单的暂停/恢复/打断等复杂状态变更
|
||||
* 3. 提供事务保证,确保状态一致性
|
||||
* <p>
|
||||
* 实现说明:
|
||||
* - 所有状态变更方法都在事务中执行
|
||||
* - 状态变更后发布领域事件,由业务方订阅处理
|
||||
* - 确保工单状态与队列状态的一致性
|
||||
*
|
||||
* @author lzh
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class OrderLifecycleManagerImpl implements OrderLifecycleManager {
|
||||
|
||||
@Resource
|
||||
private OrderStateMachine orderStateMachine;
|
||||
|
||||
@Resource
|
||||
private OrderQueueService orderQueueService;
|
||||
|
||||
@Resource
|
||||
private OpsOrderMapper opsOrderMapper;
|
||||
|
||||
@Resource
|
||||
private OrderEventPublisher eventPublisher;
|
||||
|
||||
// ==================== 暂停/恢复 ====================
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void pauseOrder(Long orderId, Long operatorId, String reason) {
|
||||
log.info("开始暂停工单: orderId={}, operatorId={}, reason={}", orderId, operatorId, reason);
|
||||
|
||||
// 1. 查询工单和队列
|
||||
OpsOrderDO order = getOrderByOrderId(orderId);
|
||||
OrderQueueDTO queueDTO = orderQueueService.getByOpsOrderId(orderId);
|
||||
|
||||
// 2. 验证状态
|
||||
validateCanPause(order, queueDTO);
|
||||
|
||||
WorkOrderStatusEnum oldStatus = WorkOrderStatusEnum.valueOf(order.getStatus());
|
||||
|
||||
// 3. 同步转换状态
|
||||
// 工单状态:ARRIVED → PAUSED
|
||||
orderStateMachine.transition(order, WorkOrderStatusEnum.PAUSED,
|
||||
OperatorTypeEnum.CLEANER, operatorId, reason);
|
||||
|
||||
// 队列状态:PROCESSING → PAUSED
|
||||
if (queueDTO != null) {
|
||||
orderQueueService.pauseTask(queueDTO.getId());
|
||||
log.info("队列状态已更新为PAUSED: queueId={}, orderId={}", queueDTO.getId(), orderId);
|
||||
}
|
||||
|
||||
// 4. 发布事件
|
||||
publishStateChangedEvent(order, oldStatus, WorkOrderStatusEnum.PAUSED,
|
||||
OperatorTypeEnum.CLEANER, operatorId, reason);
|
||||
|
||||
log.info("工单暂停完成: orderId={}, oldStatus={}, newStatus=PAUSED", orderId, oldStatus);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void resumeOrder(Long orderId, Long operatorId) {
|
||||
log.info("开始恢复工单: orderId={}, operatorId={}", orderId, operatorId);
|
||||
|
||||
// 1. 查询工单和队列
|
||||
OpsOrderDO order = getOrderByOrderId(orderId);
|
||||
OrderQueueDTO queueDTO = orderQueueService.getByOpsOrderId(orderId);
|
||||
|
||||
// 2. 验证状态
|
||||
validateCanResume(order, queueDTO);
|
||||
|
||||
WorkOrderStatusEnum oldStatus = WorkOrderStatusEnum.valueOf(order.getStatus());
|
||||
|
||||
// 3. 同步转换状态
|
||||
// 工单状态:PAUSED → DISPATCHED
|
||||
orderStateMachine.transition(order, WorkOrderStatusEnum.DISPATCHED,
|
||||
OperatorTypeEnum.CLEANER, operatorId, "恢复工单");
|
||||
|
||||
// 队列状态:PAUSED → PROCESSING
|
||||
if (queueDTO != null) {
|
||||
orderQueueService.resumeTask(queueDTO.getId());
|
||||
log.info("队列状态已更新为PROCESSING: queueId={}, orderId={}", queueDTO.getId(), orderId);
|
||||
}
|
||||
|
||||
// 4. 发布事件
|
||||
publishStateChangedEvent(order, oldStatus, WorkOrderStatusEnum.DISPATCHED,
|
||||
OperatorTypeEnum.CLEANER, operatorId, "恢复工单");
|
||||
|
||||
log.info("工单恢复完成: orderId={}, oldStatus={}, newStatus=DISPATCHED", orderId, oldStatus);
|
||||
}
|
||||
|
||||
// ==================== 打断/恢复 ====================
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void interruptOrder(Long orderId, Long urgentOrderId, Long operatorId) {
|
||||
log.warn("开始打断工单: orderId={}, urgentOrderId={}, operatorId={}",
|
||||
orderId, urgentOrderId, operatorId);
|
||||
|
||||
// 1. 查询工单和队列
|
||||
OpsOrderDO order = getOrderByOrderId(orderId);
|
||||
OrderQueueDTO queueDTO = orderQueueService.getByOpsOrderId(orderId);
|
||||
|
||||
// 2. 验证状态(只有 DISPATCHED/CONFIRMED/ARRIVED 可以被打断)
|
||||
WorkOrderStatusEnum currentStatus = WorkOrderStatusEnum.valueOf(order.getStatus());
|
||||
if (!canInterruptStatus(currentStatus)) {
|
||||
throw new IllegalStateException("工单状态不允许被打断: orderId=" + orderId + ", status=" + currentStatus);
|
||||
}
|
||||
|
||||
// 3. 同步转换状态
|
||||
// 工单状态:DISPATCHED/CONFIRMED/ARRIVED → PAUSED
|
||||
orderStateMachine.transition(order, WorkOrderStatusEnum.PAUSED,
|
||||
OperatorTypeEnum.SYSTEM, operatorId, "被P0任务打断: " + urgentOrderId);
|
||||
|
||||
if (queueDTO != null) {
|
||||
orderQueueService.pauseTask(queueDTO.getId());
|
||||
orderQueueService.updateEventMessage(queueDTO.getId(),
|
||||
"被P0任务打断,紧急工单ID: " + urgentOrderId);
|
||||
log.info("队列状态已更新为PAUSED: queueId={}, orderId={}", queueDTO.getId(), orderId);
|
||||
}
|
||||
|
||||
// 4. 发布事件(带打断信息)
|
||||
OrderStateChangedEvent event = OrderStateChangedEvent.builder()
|
||||
.orderId(orderId)
|
||||
.orderType(order.getOrderType())
|
||||
.oldStatus(currentStatus)
|
||||
.newStatus(WorkOrderStatusEnum.PAUSED)
|
||||
.operatorType(OperatorTypeEnum.SYSTEM)
|
||||
.operatorId(operatorId)
|
||||
.remark("被P0任务打断: " + urgentOrderId)
|
||||
.build();
|
||||
event.addPayload("urgentOrderId", urgentOrderId);
|
||||
event.addPayload("interruptReason", "P0_TASK_INTERRUPT");
|
||||
eventPublisher.publishStateChanged(event);
|
||||
|
||||
log.warn("工单打断完成: orderId={}, urgentOrderId={}, oldStatus={}, newStatus=PAUSED",
|
||||
orderId, urgentOrderId, currentStatus);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void resumeInterruptedOrder(Long orderId, Long operatorId) {
|
||||
log.info("开始恢复被打断的工单: orderId={}, operatorId={}", orderId, operatorId);
|
||||
|
||||
// 复用恢复方法
|
||||
resumeOrder(orderId, operatorId);
|
||||
|
||||
log.info("被打断的工单已恢复: orderId={}", orderId);
|
||||
}
|
||||
|
||||
// ==================== 完工/取消 ====================
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void completeOrder(Long orderId, Long operatorId, String remark) {
|
||||
log.info("开始完成工单: orderId={}, operatorId={}, remark={}", orderId, operatorId, remark);
|
||||
|
||||
// 1. 查询工单和队列
|
||||
OpsOrderDO order = getOrderByOrderId(orderId);
|
||||
OrderQueueDTO queueDTO = orderQueueService.getByOpsOrderId(orderId);
|
||||
|
||||
WorkOrderStatusEnum oldStatus = WorkOrderStatusEnum.valueOf(order.getStatus());
|
||||
|
||||
// 2. 验证状态
|
||||
if (!canCompleteStatus(oldStatus)) {
|
||||
throw new IllegalStateException("工单状态不允许完成: orderId=" + orderId + ", status=" + oldStatus);
|
||||
}
|
||||
|
||||
// 3. 转换工单状态
|
||||
orderStateMachine.transition(order, WorkOrderStatusEnum.COMPLETED,
|
||||
OperatorTypeEnum.CLEANER, operatorId, remark);
|
||||
|
||||
// 4. 清理队列记录
|
||||
if (queueDTO != null) {
|
||||
orderQueueService.updateStatus(queueDTO.getId(),
|
||||
com.viewsh.module.ops.enums.OrderQueueStatusEnum.REMOVED);
|
||||
log.info("队列记录已移除: queueId={}, orderId={}", queueDTO.getId(), orderId);
|
||||
}
|
||||
|
||||
// 5. 发布事件
|
||||
publishStateChangedEvent(order, oldStatus, WorkOrderStatusEnum.COMPLETED,
|
||||
OperatorTypeEnum.CLEANER, operatorId, remark);
|
||||
|
||||
log.info("工单完成: orderId={}, oldStatus={}, newStatus=COMPLETED", orderId, oldStatus);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void cancelOrder(Long orderId, Long operatorId, OperatorTypeEnum operatorType, String reason) {
|
||||
log.info("开始取消工单: orderId={}, operatorId={}, operatorType={}, reason={}",
|
||||
orderId, operatorId, operatorType, reason);
|
||||
|
||||
// 1. 查询工单和队列
|
||||
OpsOrderDO order = getOrderByOrderId(orderId);
|
||||
OrderQueueDTO queueDTO = orderQueueService.getByOpsOrderId(orderId);
|
||||
|
||||
WorkOrderStatusEnum oldStatus = WorkOrderStatusEnum.valueOf(order.getStatus());
|
||||
|
||||
// 2. 验证状态(已完成的工单不能取消)
|
||||
if (WorkOrderStatusEnum.COMPLETED == oldStatus) {
|
||||
throw new IllegalStateException("已完成的工单不能取消: orderId=" + orderId);
|
||||
}
|
||||
|
||||
// 3. 转换工单状态
|
||||
orderStateMachine.transition(order, WorkOrderStatusEnum.CANCELLED,
|
||||
operatorType, operatorId, reason);
|
||||
|
||||
// 4. 清理队列记录
|
||||
if (queueDTO != null) {
|
||||
orderQueueService.updateStatus(queueDTO.getId(),
|
||||
com.viewsh.module.ops.enums.OrderQueueStatusEnum.REMOVED);
|
||||
log.info("队列记录已移除: queueId={}, orderId={}", queueDTO.getId(), orderId);
|
||||
}
|
||||
|
||||
// 5. 发布事件
|
||||
publishStateChangedEvent(order, oldStatus, WorkOrderStatusEnum.CANCELLED,
|
||||
operatorType, operatorId, reason);
|
||||
|
||||
log.info("工单已取消: orderId={}, oldStatus={}, newStatus=CANCELLED", orderId, oldStatus);
|
||||
}
|
||||
|
||||
// ==================== 查询方法 ====================
|
||||
|
||||
@Override
|
||||
public boolean canPause(Long orderId) {
|
||||
OpsOrderDO order = opsOrderMapper.selectById(orderId);
|
||||
if (order == null) {
|
||||
return false;
|
||||
}
|
||||
WorkOrderStatusEnum status = WorkOrderStatusEnum.valueOf(order.getStatus());
|
||||
return canPauseStatus(status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canResume(Long orderId) {
|
||||
OpsOrderDO order = opsOrderMapper.selectById(orderId);
|
||||
if (order == null) {
|
||||
return false;
|
||||
}
|
||||
WorkOrderStatusEnum status = WorkOrderStatusEnum.valueOf(order.getStatus());
|
||||
return WorkOrderStatusEnum.PAUSED == status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canInterrupt(Long orderId, PriorityEnum urgentPriority) {
|
||||
OpsOrderDO order = opsOrderMapper.selectById(orderId);
|
||||
if (order == null) {
|
||||
return false;
|
||||
}
|
||||
WorkOrderStatusEnum status = WorkOrderStatusEnum.valueOf(order.getStatus());
|
||||
return canInterruptStatus(status);
|
||||
}
|
||||
|
||||
// ==================== 私有方法 ====================
|
||||
|
||||
/**
|
||||
* 获取工单对象
|
||||
*/
|
||||
private OpsOrderDO getOrderByOrderId(Long orderId) {
|
||||
OpsOrderDO order = opsOrderMapper.selectById(orderId);
|
||||
if (order == null) {
|
||||
throw new IllegalArgumentException("工单不存在: orderId=" + orderId);
|
||||
}
|
||||
return order;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证是否可以暂停
|
||||
*/
|
||||
private void validateCanPause(OpsOrderDO order, OrderQueueDTO queueDTO) {
|
||||
WorkOrderStatusEnum status = WorkOrderStatusEnum.valueOf(order.getStatus());
|
||||
|
||||
if (!canPauseStatus(status)) {
|
||||
throw new IllegalStateException("工单状态不允许暂停: orderId=" + order.getId() + ", status=" + status);
|
||||
}
|
||||
|
||||
if (queueDTO != null) {
|
||||
String queueStatus = queueDTO.getQueueStatus();
|
||||
if (!com.viewsh.module.ops.enums.OrderQueueStatusEnum.PROCESSING.getStatus().equals(queueStatus)) {
|
||||
log.warn("队列状态不是PROCESSING,可能已暂停: queueId={}, status={}",
|
||||
queueDTO.getId(), queueStatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证是否可以恢复
|
||||
*/
|
||||
private void validateCanResume(OpsOrderDO order, OrderQueueDTO queueDTO) {
|
||||
WorkOrderStatusEnum status = WorkOrderStatusEnum.valueOf(order.getStatus());
|
||||
|
||||
if (WorkOrderStatusEnum.PAUSED != status) {
|
||||
throw new IllegalStateException("工单状态不允许恢复: orderId=" + order.getId() + ", status=" + status);
|
||||
}
|
||||
|
||||
if (queueDTO != null) {
|
||||
String queueStatus = queueDTO.getQueueStatus();
|
||||
if (!com.viewsh.module.ops.enums.OrderQueueStatusEnum.PAUSED.getStatus().equals(queueStatus)) {
|
||||
log.warn("队列状态不是PAUSED: queueId={}, status={}", queueDTO.getId(), queueStatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断状态是否可以暂停
|
||||
*/
|
||||
private boolean canPauseStatus(WorkOrderStatusEnum status) {
|
||||
return WorkOrderStatusEnum.ARRIVED == status;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断状态是否可以打断
|
||||
*/
|
||||
private boolean canInterruptStatus(WorkOrderStatusEnum status) {
|
||||
return WorkOrderStatusEnum.DISPATCHED == status
|
||||
|| WorkOrderStatusEnum.CONFIRMED == status
|
||||
|| WorkOrderStatusEnum.ARRIVED == status;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断状态是否可以完成
|
||||
*/
|
||||
private boolean canCompleteStatus(WorkOrderStatusEnum status) {
|
||||
return WorkOrderStatusEnum.ARRIVED == status
|
||||
|| WorkOrderStatusEnum.PAUSED == status;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发布状态变更事件
|
||||
*/
|
||||
private void publishStateChangedEvent(OpsOrderDO order,
|
||||
WorkOrderStatusEnum oldStatus,
|
||||
WorkOrderStatusEnum newStatus,
|
||||
OperatorTypeEnum operatorType,
|
||||
Long operatorId,
|
||||
String remark) {
|
||||
OrderStateChangedEvent event = OrderStateChangedEvent.builder()
|
||||
.orderId(order.getId())
|
||||
.orderType(order.getOrderType())
|
||||
.oldStatus(oldStatus)
|
||||
.newStatus(newStatus)
|
||||
.operatorType(operatorType)
|
||||
.operatorId(operatorId)
|
||||
.remark(remark)
|
||||
.build();
|
||||
eventPublisher.publishStateChanged(event);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user