chore: 【ops】工单基础Service

This commit is contained in:
lzh
2026-01-06 10:52:33 +08:00
parent bb94103548
commit 77b7bfb89d
2 changed files with 414 additions and 0 deletions

View File

@@ -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<OpsOrderDO> 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);
}

View File

@@ -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<OpsOrderDO> 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);
}
}