diff --git a/viewsh-module-ops/viewsh-module-ops-biz/src/main/java/com/viewsh/module/ops/service/order/OpsOrderService.java b/viewsh-module-ops/viewsh-module-ops-biz/src/main/java/com/viewsh/module/ops/service/order/OpsOrderService.java new file mode 100644 index 0000000..ebe0866 --- /dev/null +++ b/viewsh-module-ops/viewsh-module-ops-biz/src/main/java/com/viewsh/module/ops/service/order/OpsOrderService.java @@ -0,0 +1,109 @@ +package com.viewsh.module.ops.service.order; + +import com.viewsh.framework.common.pojo.PageResult; +import com.viewsh.module.ops.dal.dataobject.dto.*; +import com.viewsh.module.ops.dal.dataobject.workorder.OpsOrderDO; +import com.viewsh.module.ops.enums.OperatorTypeEnum; + +/** + * 通用工单服务 + * 职责: + * 1. 工单CRUD基础操作 + * 2. 工单状态转换(调用状态机) + * 3. 工单分页查询 + * + * @author lzh + */ +public interface OpsOrderService { + + /** + * 创建工单(通用方法) + * + * @param createReq 创建请求 + * @return 工单ID + */ + Long createOrder(OpsOrderCreateReqDTO createReq); + + /** + * 更新工单 + * + * @param updateReq 更新请求 + */ + void updateOrder(OpsOrderUpdateReqDTO updateReq); + + /** + * 删除工单 + * + * @param orderId 工单ID + */ + void deleteOrder(Long orderId); + + /** + * 查询工单详情 + * + * @param orderId 工单ID + * @return 工单对象 + */ + OpsOrderDO getOrder(Long orderId); + + /** + * 分页查询工单 + * + * @param pageReq 分页请求 + * @return 分页结果 + */ + PageResult getOrderPage(OpsOrderPageReqDTO pageReq); + + /** + * 分配工单(状态转换:PENDING -> ASSIGNED) + * + * @param assignReq 分配请求 + * @param operatorType 操作人类型 + * @param operatorId 操作人ID + */ + void assignOrder(OpsOrderAssignReqDTO assignReq, OperatorTypeEnum operatorType, Long operatorId); + + /** + * 接单(状态转换:ASSIGNED -> ARRIVED) + * + * @param orderId 工单ID + * @param userId 保洁员ID + */ + void acceptOrder(Long orderId, Long userId); + + /** + * 完成工单(状态转换:ARRIVED -> COMPLETED) + * + * @param completeReq 完成请求 + * @param userId 执行人ID + */ + void completeOrder(OpsOrderCompleteReqDTO completeReq, Long userId); + + /** + * 暂停工单(状态转换:ARRIVED -> PAUSED) + * + * @param orderId 工单ID + * @param userId 保洁员ID + * @param reason 暂停原因 + */ + void pauseOrder(Long orderId, Long userId, String reason); + + /** + * 恢复工单(状态转换:PAUSED -> ARRIVED) + * + * @param orderId 工单ID + * @param userId 保洁员ID + */ + void resumeOrder(Long orderId, Long userId); + + /** + * 取消工单 + * + * @param orderId 工单ID + * @param reason 取消原因 + * @param operatorType 操作人类型 + * @param operatorId 操作人ID + */ + void cancelOrder(Long orderId, String reason, OperatorTypeEnum operatorType, Long operatorId); + +} diff --git a/viewsh-module-ops/viewsh-module-ops-biz/src/main/java/com/viewsh/module/ops/service/order/OpsOrderServiceImpl.java b/viewsh-module-ops/viewsh-module-ops-biz/src/main/java/com/viewsh/module/ops/service/order/OpsOrderServiceImpl.java new file mode 100644 index 0000000..b160761 --- /dev/null +++ b/viewsh-module-ops/viewsh-module-ops-biz/src/main/java/com/viewsh/module/ops/service/order/OpsOrderServiceImpl.java @@ -0,0 +1,305 @@ +package com.viewsh.module.ops.service.order; + +import com.viewsh.framework.common.pojo.PageResult; +import com.viewsh.framework.common.util.object.BeanUtils; +import com.viewsh.module.ops.dal.dataobject.dto.*; +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 lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import jakarta.annotation.Resource; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; + +/** + * 通用工单服务实现 + * + * @author lzh + */ +@Slf4j +@Service +public class OpsOrderServiceImpl implements OpsOrderService { + + @Resource + private OpsOrderMapper opsOrderMapper; + + @Resource + private OrderStateMachine orderStateMachine; + + private static final DateTimeFormatter ORDER_CODE_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmmss"); + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createOrder(OpsOrderCreateReqDTO createReq) { + // 1. 构建工单对象 + OpsOrderDO order = BeanUtils.toBean(createReq, OpsOrderDO.class); + + // 2. 设置默认值 + if (order.getPriority() == null) { + order.setPriority(PriorityEnum.P2.getPriority()); + } + if (order.getStatus() == null) { + order.setStatus(WorkOrderStatusEnum.PENDING.getStatus()); + } + if (order.getSourceType() == null) { + order.setSourceType("MANUAL"); + } + + // 3. 生成工单编号 + order.setOrderCode(generateOrderCode()); + + // 4. 插入数据库 + opsOrderMapper.insert(order); + + // 5. 记录创建事件 + orderStateMachine.transition( + order, + WorkOrderStatusEnum.PENDING, + OperatorTypeEnum.SYSTEM, + null, + "创建工单" + ); + + log.info("创建工单成功: orderId={}, orderCode={}, title={}", + order.getId(), order.getOrderCode(), order.getTitle()); + + return order.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateOrder(OpsOrderUpdateReqDTO updateReq) { + // 1. 查询工单 + OpsOrderDO existingOrder = opsOrderMapper.selectById(updateReq.getId()); + if (existingOrder == null) { + throw new RuntimeException("工单不存在: " + updateReq.getId()); + } + + // 2. 更新允许修改的字段 + OpsOrderDO updateObj = new OpsOrderDO(); + updateObj.setId(updateReq.getId()); + if (updateReq.getTitle() != null) { + updateObj.setTitle(updateReq.getTitle()); + } + if (updateReq.getDescription() != null) { + updateObj.setDescription(updateReq.getDescription()); + } + if (updateReq.getPriority() != null) { + updateObj.setPriority(updateReq.getPriority()); + } + if (updateReq.getUrgentReason() != null) { + updateObj.setUrgentReason(updateReq.getUrgentReason()); + } + + // 3. 执行更新 + opsOrderMapper.updateById(updateObj); + + log.info("更新工单成功: orderId={}", updateReq.getId()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteOrder(Long orderId) { + // 1. 校验工单状态 + OpsOrderDO order = opsOrderMapper.selectById(orderId); + if (order == null) { + throw new RuntimeException("工单不存在: " + orderId); + } + + // 2. 只能删除待分配或已取消的工单 + if (!WorkOrderStatusEnum.PENDING.getStatus().equals(order.getStatus()) && + !WorkOrderStatusEnum.CANCELLED.getStatus().equals(order.getStatus())) { + throw new RuntimeException("只能删除待分配或已取消的工单"); + } + + // 3. 执行删除 + opsOrderMapper.deleteById(orderId); + + log.info("删除工单成功: orderId={}", orderId); + } + + @Override + public OpsOrderDO getOrder(Long orderId) { + OpsOrderDO order = opsOrderMapper.selectById(orderId); + if (order == null) { + throw new RuntimeException("工单不存在: " + orderId); + } + return order; + } + + @Override + public PageResult getOrderPage(OpsOrderPageReqDTO pageReq) { + // TODO: 实现分页查询 + // 需要在OpsOrderMapper中添加分页查询方法 + // 或者使用MyBatis Plus的原生分页 + throw new UnsupportedOperationException("分页查询功能待实现"); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void assignOrder(OpsOrderAssignReqDTO assignReq, OperatorTypeEnum operatorType, Long operatorId) { + // 1. 查询工单 + OpsOrderDO order = opsOrderMapper.selectById(assignReq.getOrderId()); + if (order == null) { + throw new RuntimeException("工单不存在: " + assignReq.getOrderId()); + } + + // 2. 设置执行人 + order.setAssigneeId(assignReq.getAssigneeId()); + + // 3. 通过状态机执行状态转换 + orderStateMachine.transition( + order, + WorkOrderStatusEnum.DISPATCHED, + operatorType, + operatorId, + assignReq.getRemark() + ); + + log.info("分配工单成功: orderId={}, assigneeId={}", assignReq.getOrderId(), assignReq.getAssigneeId()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void acceptOrder(Long orderId, Long userId) { + // 1. 查询工单 + OpsOrderDO order = opsOrderMapper.selectById(orderId); + if (order == null) { + throw new RuntimeException("工单不存在: " + orderId); + } + + // 2. 校验:只有分配给的执行人才能接单 + if (!userId.equals(order.getAssigneeId())) { + throw new RuntimeException("无权接单,该工单未分配给您"); + } + + // 3. 通过状态机执行状态转换 + orderStateMachine.transition( + order, + WorkOrderStatusEnum.ARRIVED, + OperatorTypeEnum.CLEANER, + userId, + "保洁员接单" + ); + + log.info("接单成功: orderId={}, userId={}", orderId, userId); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void completeOrder(OpsOrderCompleteReqDTO completeReq, Long userId) { + // 1. 查询工单 + OpsOrderDO order = opsOrderMapper.selectById(completeReq.getOrderId()); + if (order == null) { + throw new RuntimeException("工单不存在: " + completeReq.getOrderId()); + } + + // 2. 校验:只有执行人才能完成工单 + if (!userId.equals(order.getAssigneeId())) { + throw new RuntimeException("无权完成工单,您不是该工单的执行人"); + } + + // 3. 通过状态机执行状态转换 + orderStateMachine.transition( + order, + WorkOrderStatusEnum.COMPLETED, + OperatorTypeEnum.CLEANER, + userId, + completeReq.getRemark() + ); + + log.info("完成工单成功: orderId={}, userId={}", completeReq.getOrderId(), userId); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void pauseOrder(Long orderId, Long userId, String reason) { + // 1. 查询工单 + OpsOrderDO order = opsOrderMapper.selectById(orderId); + if (order == null) { + throw new RuntimeException("工单不存在: " + orderId); + } + + // 2. 校验:只有执行人才能暂停工单 + if (!userId.equals(order.getAssigneeId())) { + throw new RuntimeException("无权暂停工单,您不是该工单的执行人"); + } + + // 3. 通过状态机执行状态转换 + orderStateMachine.transition( + order, + WorkOrderStatusEnum.PAUSED, + OperatorTypeEnum.CLEANER, + userId, + reason + ); + + log.info("暂停工单成功: orderId={}, userId={}, reason={}", orderId, userId, reason); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void resumeOrder(Long orderId, Long userId) { + // 1. 查询工单 + OpsOrderDO order = opsOrderMapper.selectById(orderId); + if (order == null) { + throw new RuntimeException("工单不存在: " + orderId); + } + + // 2. 通过状态机执行状态转换 + orderStateMachine.transition( + order, + WorkOrderStatusEnum.ARRIVED, + OperatorTypeEnum.CLEANER, + userId, + "恢复工单" + ); + + log.info("恢复工单成功: orderId={}, userId={}", orderId, userId); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void cancelOrder(Long orderId, String reason, OperatorTypeEnum operatorType, Long operatorId) { + // 1. 查询工单 + OpsOrderDO order = opsOrderMapper.selectById(orderId); + if (order == null) { + throw new RuntimeException("工单不存在: " + orderId); + } + + // 2. 校验:已完成的工单不能取消 + if (WorkOrderStatusEnum.COMPLETED.getStatus().equals(order.getStatus())) { + throw new RuntimeException("已完成的工单不能取消"); + } + + // 3. 通过状态机执行状态转换 + orderStateMachine.transition( + order, + WorkOrderStatusEnum.CANCELLED, + operatorType, + operatorId, + reason + ); + + log.info("取消工单成功: orderId={}, reason={}", orderId, reason); + } + + /** + * 生成工单编号 + * 格式:WO + yyyyMMddHHmmss + 3位随机数 + * 示例:WO20250104143025123 + */ + private String generateOrderCode() { + String timestamp = LocalDateTime.now().format(ORDER_CODE_FORMATTER); + int random = (int) (Math.random() * 1000); + return String.format("WO%s%03d", timestamp, random); + } + +}