From 4803b22ae0f0f5b4e2ae1627a7d1eea38684f02d Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期四, 23 七月 2026 09:07:06 +0800
Subject: [PATCH] feat(mes): 新增工单工序管理和报工功能
---
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/task/MesProTaskServiceImpl.java | 175 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 171 insertions(+), 4 deletions(-)
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/task/MesProTaskServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/task/MesProTaskServiceImpl.java
index 4052b07..d19426b 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/task/MesProTaskServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/task/MesProTaskServiceImpl.java
@@ -3,6 +3,8 @@
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.mes.controller.admin.pro.task.vo.MesProTaskAutoGeneratePreviewRespVO;
+import cn.iocoder.yudao.module.mes.controller.admin.pro.task.vo.MesProTaskAutoGenerateReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.pro.task.vo.MesProTaskPageReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.pro.task.vo.MesProTaskSaveReqVO;
import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
@@ -10,6 +12,7 @@
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.task.MesProTaskDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO;
import cn.iocoder.yudao.module.mes.dal.mysql.pro.task.MesProTaskMapper;
+import cn.iocoder.yudao.module.mes.dal.mysql.pro.feedback.MesProFeedbackMapper;
import cn.iocoder.yudao.module.mes.enums.md.autocode.MesMdAutoCodeRuleCodeEnum;
import cn.iocoder.yudao.module.mes.enums.pro.MesProTaskStatusEnum;
import cn.iocoder.yudao.module.mes.service.md.autocode.MesMdAutoCodeRecordService;
@@ -17,11 +20,19 @@
import cn.iocoder.yudao.module.mes.service.md.unitmeasure.MesMdUnitMeasureService;
import cn.iocoder.yudao.module.mes.service.md.workstation.MesMdWorkstationService;
import cn.iocoder.yudao.module.mes.service.pro.process.MesProProcessService;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteProcessDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteProductDO;
+import cn.iocoder.yudao.module.mes.service.pro.route.MesProRouteProcessService;
+import cn.iocoder.yudao.module.mes.service.pro.route.MesProRouteProductService;
import cn.iocoder.yudao.module.mes.service.pro.route.MesProRouteService;
import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderService;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderProcessDO;
+import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderProcessService;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import java.math.BigDecimal;
@@ -33,6 +44,7 @@
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.PRO_TASK_ALREADY_FINISHED;
+import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.PRO_TASK_HAS_FEEDBACK;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.PRO_TASK_NOT_EXISTS;
/**
@@ -48,6 +60,9 @@
private MesProTaskMapper taskMapper;
@Resource
+ private MesProFeedbackMapper feedbackMapper;
+
+ @Resource
@Lazy
private MesProWorkOrderService workOrderService;
@Resource
@@ -61,6 +76,15 @@
@Resource
private MesProRouteService routeService;
@Resource
+ @Lazy
+ private MesProRouteProcessService routeProcessService;
+ @Resource
+ @Lazy
+ private MesProRouteProductService routeProductService;
+ @Resource
+ @Lazy
+ private MesProWorkOrderProcessService workOrderProcessService;
+ @Resource
private MesMdAutoCodeRecordService autoCodeRecordService;
@Override
@@ -70,10 +94,23 @@
workstationService.validateWorkstationExists(createReqVO.getWorkstationId());
routeService.validateRouteExists(createReqVO.getRouteId());
processService.validateProcessExistsAndEnable(createReqVO.getProcessId());
- MesMdItemDO item = itemService.validateItemExists(createReqVO.getItemId());
- // 2.1 鏋勫缓浠诲姟 DO锛氳嚜鍔ㄥ~鍏呭鎴蜂俊鎭�
+ // 2. 鑷姩纭畾 itemId锛氫紭鍏堝墠绔紶鍏� 鈫� 宸ヨ壓璺嚎宸ュ簭鐨勪骇鍑轰骇鍝� 鈫� 宸ュ崟鎴愬搧
+ Long itemId = createReqVO.getItemId();
+ if (itemId == null) {
+ MesProRouteProcessDO routeProcess = routeProcessService
+ .getRouteProcessByRouteIdAndProcessId(createReqVO.getRouteId(), createReqVO.getProcessId());
+ if (routeProcess != null && routeProcess.getOutputItemId() != null) {
+ itemId = routeProcess.getOutputItemId();
+ } else {
+ itemId = workOrder.getProductId();
+ }
+ }
+ MesMdItemDO item = itemService.validateItemExists(itemId);
+
+ // 3.1 鏋勫缓浠诲姟 DO锛氳嚜鍔ㄥ~鍏呭鎴蜂俊鎭�
MesProTaskDO task = BeanUtils.toBean(createReqVO, MesProTaskDO.class)
+ .setItemId(itemId) // 纭繚浣跨敤璁$畻鍚庣殑 itemId
.setName(buildTaskName(item, createReqVO.getQuantity()))
.setCode(autoCodeRecordService.generateAutoCode(MesMdAutoCodeRuleCodeEnum.PRO_TASK_CODE.getCode()))
.setStatus(MesProTaskStatusEnum.PREPARE.getStatus());
@@ -130,12 +167,63 @@
return item.getName() + "銆�" + quantity + "銆�" + unitName;
}
+ /**
+ * 纭畾鎺掍骇浣跨敤鐨勫伐鑹鸿矾绾� ID锛氫紭鍏堣姹傛寚瀹� 鈫� 宸ュ崟鍏宠仈 鈫� 浜у搧鍏宠仈
+ */
+ private Long resolveRouteId(Long reqRouteId, MesProWorkOrderDO workOrder) {
+ if (reqRouteId != null) {
+ return reqRouteId;
+ }
+ if (workOrder.getRouteId() != null) {
+ return workOrder.getRouteId();
+ }
+ // 浠庝骇鍝佸叧鑱旂殑宸ヨ壓璺嚎鑾峰彇
+ MesProRouteProductDO routeProduct = routeProductService.getRouteProductByItemId(workOrder.getProductId());
+ if (routeProduct == null) {
+ throw exception(cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.PRO_ROUTE_NOT_EXISTS);
+ }
+ return routeProduct.getRouteId();
+ }
+
+ /**
+ * 鏋勫缓宸ュ簭鍒楄〃锛氫紭鍏堜娇鐢ㄥ伐鍗曞凡淇濆瓨鐨勫伐搴� 鈫� 鍥為��鍒板伐鑹鸿矾绾挎ā鏉垮伐搴�
+ */
+ private List<MesProRouteProcessDO> buildRouteProcessList(Long routeId, Long workOrderId) {
+ // 1. 浼樺厛浣跨敤宸ュ崟宸蹭繚瀛樼殑宸ュ簭
+ List<MesProWorkOrderProcessDO> woProcesses = workOrderProcessService
+ .getWorkOrderProcessListByWorkOrderId(workOrderId);
+ if (CollUtil.isNotEmpty(woProcesses)) {
+ List<MesProRouteProcessDO> result = new java.util.ArrayList<>();
+ for (MesProWorkOrderProcessDO wp : woProcesses) {
+ result.add(new MesProRouteProcessDO()
+ .setRouteId(routeId)
+ .setProcessId(wp.getProcessId())
+ .setSort(wp.getSort())
+ .setKeyFlag(wp.getKeyFlag())
+ .setCheckFlag(wp.getCheckFlag())
+ .setBackflushFlag(wp.getBackflushFlag())
+ .setOutputItemId(wp.getOutputItemId())
+ .setColorCode(wp.getColorCode()));
+ }
+ return result;
+ }
+ // 2. 鍥為��鍒板伐鑹鸿矾绾挎ā鏉垮伐搴�
+ List<MesProRouteProcessDO> routeProcesses = routeProcessService.getRouteProcessListByRouteId(routeId);
+ if (CollUtil.isEmpty(routeProcesses)) {
+ throw exception(cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.PRO_ROUTE_ENABLE_NO_PROCESS);
+ }
+ return routeProcesses;
+ }
+
@Override
public void deleteTask(Long id) {
// 1. 鏍¢獙瀛樺湪涓旈潪缁堟��
validateTaskNotFinished(id);
-
- // 2. 鍒犻櫎
+ // 2. 鏍¢獙浠诲姟涓嬫棤鎶ュ伐璁板綍锛岄伩鍏嶅垹闄ゅ悗鎶ュ伐杩芥函鏂摼
+ if (feedbackMapper.selectCountByTaskId(id) > 0) {
+ throw exception(PRO_TASK_HAS_FEEDBACK);
+ }
+ // 3. 鍒犻櫎
taskMapper.deleteById(id);
}
@@ -147,6 +235,11 @@
@Override
public PageResult<MesProTaskDO> getTaskPage(MesProTaskPageReqVO pageReqVO) {
return taskMapper.selectPage(pageReqVO);
+ }
+
+ @Override
+ public PageResult<MesProTaskDO> getPendingFeedbackPage(MesProTaskPageReqVO pageReqVO) {
+ return taskMapper.selectPendingFeedbackPage(pageReqVO);
}
@Override
@@ -224,4 +317,78 @@
taskMapper.updateProducedQuantity(id, incrProducedQuantity, incrQualifyQuantity, incrUnqualifyQuantity);
}
+ @Override
+ public MesProTaskAutoGeneratePreviewRespVO previewAutoGenerate(MesProTaskAutoGenerateReqVO reqVO) {
+ // 1. 鏍¢獙宸ュ崟宸茬‘璁�
+ MesProWorkOrderDO workOrder = workOrderService.validateWorkOrderConfirmed(reqVO.getWorkOrderId());
+ // 2. 纭畾宸ヨ壓璺嚎锛氫紭鍏堣姹傛寚瀹� 鈫� 宸ュ崟鍏宠仈 鈫� 浜у搧鍏宠仈
+ Long routeId = resolveRouteId(reqVO.getRouteId(), workOrder);
+ MesProRouteDO route = routeService.validateRouteExists(routeId);
+ // 3. 鑾峰彇宸ュ簭鍒楄〃锛氫紭鍏堝伐鍗曞伐搴� 鈫� 宸ヨ壓璺嚎宸ュ簭
+ List<MesProRouteProcessDO> routeProcesses = buildRouteProcessList(routeId, reqVO.getWorkOrderId());
+ // 鎸夊簭鍙锋帓搴�
+ routeProcesses.sort(java.util.Comparator.comparing(MesProRouteProcessDO::getSort, java.util.Comparator.nullsLast(java.util.Comparator.naturalOrder())));
+ // 4. 鏌ヨ宸ュ簭鍚嶇О
+ java.util.Set<Long> processIds = routeProcesses.stream().map(MesProRouteProcessDO::getProcessId).collect(java.util.stream.Collectors.toSet());
+ java.util.Map<Long, cn.iocoder.yudao.module.mes.dal.dataobject.pro.process.MesProProcessDO> procMap = processService.getProcessMap(processIds);
+ // 5. 缁勮棰勮
+ MesProTaskAutoGeneratePreviewRespVO vo = new MesProTaskAutoGeneratePreviewRespVO()
+ .setWorkOrderId(workOrder.getId())
+ .setRouteId(routeId)
+ .setRouteName(route.getName());
+ java.util.List<MesProTaskAutoGeneratePreviewRespVO.TaskPreview> taskList = new java.util.ArrayList<>();
+ for (MesProRouteProcessDO rp : routeProcesses) {
+ cn.iocoder.yudao.module.mes.dal.dataobject.pro.process.MesProProcessDO proc = procMap.get(rp.getProcessId());
+ taskList.add(new MesProTaskAutoGeneratePreviewRespVO.TaskPreview()
+ .setProcessId(rp.getProcessId())
+ .setProcessName(proc != null ? proc.getName() : null)
+ .setSort(rp.getSort())
+ .setQuantity(workOrder.getQuantity())
+ .setKeyFlag(rp.getKeyFlag()));
+ }
+ vo.setTaskList(taskList);
+ return vo;
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public List<Long> autoGenerateTasks(MesProTaskAutoGenerateReqVO reqVO) {
+ // 1. 鏍¢獙宸ュ崟宸茬‘璁�
+ MesProWorkOrderDO workOrder = workOrderService.validateWorkOrderConfirmed(reqVO.getWorkOrderId());
+ // 2. 纭畾宸ヨ壓璺嚎锛氫紭鍏堣姹傛寚瀹� 鈫� 宸ュ崟鍏宠仈 鈫� 浜у搧鍏宠仈
+ Long routeId = resolveRouteId(reqVO.getRouteId(), workOrder);
+ routeService.validateRouteExists(routeId);
+ // 3. 鏍¢獙鎺掍骇鏁伴噺
+ workOrderService.validateScheduleQuantity(reqVO.getWorkOrderId(), workOrder.getQuantity());
+ // 4. 鑾峰彇宸ュ簭鍒楄〃锛氫紭鍏堝伐鍗曞伐搴� 鈫� 宸ヨ壓璺嚎宸ュ簭
+ List<MesProRouteProcessDO> routeProcesses = buildRouteProcessList(routeId, reqVO.getWorkOrderId());
+ routeProcesses.sort(java.util.Comparator.comparing(MesProRouteProcessDO::getSort, java.util.Comparator.nullsLast(java.util.Comparator.naturalOrder())));
+ // 5. 鏌ヨ宸ュ簭淇℃伅
+ java.util.Set<Long> processIds = routeProcesses.stream().map(MesProRouteProcessDO::getProcessId).collect(java.util.stream.Collectors.toSet());
+ java.util.Map<Long, cn.iocoder.yudao.module.mes.dal.dataobject.pro.process.MesProProcessDO> procMap = processService.getProcessMap(processIds);
+ // 6. 涓烘瘡涓伐搴忓垱寤轰换鍔�
+ List<Long> taskIds = new java.util.ArrayList<>();
+ for (MesProRouteProcessDO rp : routeProcesses) {
+ cn.iocoder.yudao.module.mes.dal.dataobject.pro.process.MesProProcessDO proc = procMap.get(rp.getProcessId());
+ Long itemId = rp.getOutputItemId() != null ? rp.getOutputItemId() : workOrder.getProductId();
+ cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO item = itemService.validateItemExists(itemId);
+ MesProTaskDO task = new MesProTaskDO()
+ .setWorkOrderId(workOrder.getId())
+ .setRouteId(routeId)
+ .setProcessId(rp.getProcessId())
+ .setItemId(itemId)
+ .setQuantity(workOrder.getQuantity())
+ .setName(buildTaskName(item, workOrder.getQuantity()))
+ .setCode(autoCodeRecordService.generateAutoCode(MesMdAutoCodeRuleCodeEnum.PRO_TASK_CODE.getCode()))
+ .setStatus(MesProTaskStatusEnum.PREPARE.getStatus())
+ .setClientId(workOrder.getClientId())
+ .setColorCode(rp.getColorCode());
+ taskMapper.insert(task);
+ taskIds.add(task.getId());
+ }
+ // 7. 鏇存柊宸ュ崟宸叉帓浜ф暟閲�
+ workOrderService.updateScheduledQuantity(workOrder.getId(), workOrder.getQuantity());
+ return taskIds;
+ }
+
}
--
Gitblit v1.9.3