From bf5f52656e128f578ed42c7979c31cf4b476ce46 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期六, 31 十月 2026 19:04:40 +0800
Subject: [PATCH] feat: 优化业务导入及工艺流程管理
---
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/task/MesProTaskServiceImpl.java | 185 ++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 176 insertions(+), 9 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 b210c28..b723f98 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
@@ -2,6 +2,10 @@
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
+import cn.iocoder.yudao.module.mes.service.pd.processparamtemplate.MesPdProcessParamTemplateService;
+import cn.iocoder.yudao.module.mes.service.pro.feedback.dto.MesTaskParamSnapshot;
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;
@@ -18,6 +22,8 @@
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.dv.machinery.MesDvMachineryService;
+import cn.iocoder.yudao.module.mes.service.cal.team.MesCalTeamService;
+import cn.iocoder.yudao.module.mes.dal.dataobject.cal.team.MesCalTeamDO;
import cn.iocoder.yudao.module.mes.service.md.autocode.MesMdAutoCodeRecordService;
import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
import cn.iocoder.yudao.module.mes.service.md.unitmeasure.MesMdUnitMeasureService;
@@ -43,20 +49,30 @@
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Set;
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.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.PRO_TASK_ALREADY_FINISHED;
+import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.PRO_TASK_CANNOT_PAUSE;
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;
+import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.PRO_TASK_NOT_PAUSED;
+import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
+import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.task.MesProTaskPauseRecordDO;
+import cn.iocoder.yudao.module.mes.dal.mysql.pro.task.MesProTaskPauseRecordMapper;
+import cn.iocoder.yudao.module.mes.controller.admin.pro.task.vo.MesProTaskPauseReqVO;
+import cn.iocoder.yudao.module.mes.controller.admin.pro.task.vo.MesProTaskResumeReqVO;
/**
* MES 鐢熶骇浠诲姟 Service 瀹炵幇绫�
*
- * @author 鑺嬮亾婧愮爜
+ * @author 瓒呯骇绠$悊鍛�
*/
@Service
@Validated
@@ -64,9 +80,14 @@
@Resource
private MesProTaskMapper taskMapper;
+ @Resource
+ private MesPdProcessParamTemplateService paramTemplateService;
@Resource
private MesProFeedbackMapper feedbackMapper;
+
+ @Resource
+ private MesProTaskPauseRecordMapper taskPauseRecordMapper;
@Resource
@Lazy
@@ -97,25 +118,25 @@
@Resource
@Lazy
private MesDvMachineryService machineryService;
+ @Resource
+ private MesCalTeamService teamService;
@Override
+ @Transactional(rollbackFor = Exception.class)
public Long createTask(MesProTaskSaveReqVO createReqVO) {
// 1. 鏍¢獙鍏宠仈鏁版嵁瀛樺湪
MesProWorkOrderDO workOrder = workOrderService.validateWorkOrderExists(createReqVO.getWorkOrderId());
workstationService.validateWorkstationExists(createReqVO.getWorkstationId());
routeService.validateRouteExists(createReqVO.getRouteId());
processService.validateProcessExistsAndEnable(createReqVO.getProcessId());
+ fillTeamInfo(createReqVO);
// 2. 鑷姩纭畾 itemId锛氫紭鍏堝墠绔紶鍏� 鈫� 宸ヨ壓璺嚎宸ュ簭鐨勪骇鍑轰骇鍝� 鈫� 宸ュ崟鎴愬搧
Long itemId = createReqVO.getItemId();
if (itemId == null) {
MesProRouteProcessDO routeProcess = routeProcessService
.getRouteProcessByRouteIdAndProcessId(createReqVO.getRouteId(), createReqVO.getProcessId());
- if (routeProcess != null && routeProcess.getOutputItemId() != null) {
- itemId = Long.valueOf(routeProcess.getOutputItemId().split(",")[0].trim());
- } else {
- itemId = workOrder.getProductId();
- }
+ itemId = resolveTaskItemId(routeProcess, workOrder.getProductId());
}
MesMdItemDO item = itemService.validateItemExists(itemId);
@@ -129,14 +150,17 @@
task.setClientId(workOrder.getClientId());
}
// 2.2 鎻掑叆
+ freezeTaskParamConfig(task);
taskMapper.insert(task);
return task.getId();
}
@Override
+ @Transactional(rollbackFor = Exception.class)
public void updateTask(MesProTaskSaveReqVO updateReqVO) {
- // 1.1 鏍¢獙瀛樺湪
- MesProTaskDO task = validateTaskExists(updateReqVO.getId());
+ MesProTaskDO task = taskMapper.selectOne(new LambdaQueryWrapperX<MesProTaskDO>()
+ .eq(MesProTaskDO::getId, updateReqVO.getId()).last("FOR UPDATE"));
+ if (task == null) throw exception(PRO_TASK_NOT_EXISTS);
// 1.2 鏍¢獙鍏宠仈鏁版嵁瀛樺湪
if (updateReqVO.getWorkOrderId() != null) {
workOrderService.validateWorkOrderExists(updateReqVO.getWorkOrderId());
@@ -150,6 +174,7 @@
if (updateReqVO.getProcessId() != null) {
processService.validateProcessExistsAndEnable(updateReqVO.getProcessId());
}
+ fillTeamInfo(updateReqVO);
MesMdItemDO item;
if (updateReqVO.getItemId() != null) {
item = itemService.validateItemExists(updateReqVO.getItemId());
@@ -161,7 +186,53 @@
// 2. 鏇存柊
MesProTaskDO updateObj = BeanUtils.toBean(updateReqVO, MesProTaskDO.class)
.setName(buildTaskName(item, quantity));
+ if (updateReqVO.getProcessId() != null && !updateReqVO.getProcessId().equals(task.getProcessId())) {
+ if (feedbackMapper.selectCountByTaskId(task.getId()) > 0) throw exception(PRO_TASK_HAS_FEEDBACK);
+ freezeTaskParamConfig(updateObj);
+ }
taskMapper.updateById(updateObj);
+ }
+
+ /** 浠庡伐搴忓拰妯℃澘澶嶅埗瀹氫箟锛屽悗缁ā鏉跨淮鎶や笉鏀瑰彉宸叉帓浜т换鍔°�� */
+ private void freezeTaskParamConfig(MesProTaskDO task) {
+ var process = processService.getProcess(task.getProcessId());
+ if (process == null) throw exception(cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.PRO_PROCESS_NOT_EXISTS);
+ int mode = process.getParamCollectMode() == null ? 0 : process.getParamCollectMode();
+ task.setParamCollectMode(mode);
+ task.setParamTemplateSnapshot("");
+ task.setParamSharedSnapshot("");
+ if (mode == 0) return;
+ if ((mode != 1 && mode != 2) || process.getParamTemplateId() == null)
+ throw exception(cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.PRO_PROCESS_PARAM_CONFIG_INVALID);
+ var template = paramTemplateService.validateProcessParamTemplateExists(process.getParamTemplateId());
+ var details = paramTemplateService.getProcessParamTemplateDetailListByTemplateId(template.getId());
+ if (CollUtil.isEmpty(details)) throw exception(cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.PRO_WORK_ORDER_PARAM_RECORD_TEMPLATE_NO_DETAIL);
+ MesTaskParamSnapshot snapshot = new MesTaskParamSnapshot();
+ snapshot.setTemplateId(template.getId());
+ snapshot.setTemplateCode(template.getTemplateCode());
+ snapshot.setTemplateName(template.getTemplateName());
+ List<MesTaskParamSnapshot.Detail> frozenDetails = BeanUtils.toBean(details, MesTaskParamSnapshot.Detail.class);
+ for (MesTaskParamSnapshot.Detail detail : frozenDetails) {
+ if (detail.getUnitMeasureId() != null) {
+ var unit = unitMeasureService.getUnitMeasure(detail.getUnitMeasureId());
+ if (unit != null) detail.setUnitMeasureName(unit.getName());
+ }
+ }
+ snapshot.setDetails(frozenDetails);
+ task.setParamTemplateSnapshot(JsonUtils.toJsonString(snapshot));
+ }
+
+ /**
+ * 鏍¢獙鐝粍瀛樺湪骞跺洖濉彮缁勫悕绉�
+ */
+ private void fillTeamInfo(MesProTaskSaveReqVO reqVO) {
+ if (reqVO.getTeamId() == null) {
+ return;
+ }
+ MesCalTeamDO team = teamService.validateTeamExists(reqVO.getTeamId());
+ if (team != null) {
+ reqVO.setTeamName(team.getName());
+ }
}
/**
@@ -226,6 +297,30 @@
return routeProcesses;
}
+ /**
+ * 浠诲姟浜у嚭鐗╂枡锛氫紭鍏堝彇宸ュ簭鍦ㄥ綋鍓嶄骇鍝佷笅鐨勪骇鍑猴紙鎸夊綊灞炶繃婊わ級锛屾病鏈変骇鍑烘椂鍙栧伐鍗曟垚鍝�
+ */
+ private Long resolveTaskItemId(MesProRouteProcessDO routeProcess, Long productId) {
+ if (routeProcess == null) {
+ return productId;
+ }
+ if (routeProcess.getId() != null) {
+ // 宸ヨ壓璺嚎妯℃澘锛氭寜浜у嚭褰掑睘杩囨护鍑哄綋鍓嶄骇鍝佺殑浜у嚭
+ List<Long> outputIds = routeProcessService
+ .getOutputItemIdsByRouteProcessId(routeProcess.getId(), productId);
+ if (outputIds != null) {
+ // 鏈夊綊灞為厤缃細璇ヤ骇鍝佹棤浜у嚭鏃跺彇宸ュ崟鎴愬搧锛沶ull 琛ㄧず瀛橀噺鏃犲綊灞炴暟鎹紝缁х画璧拌仛鍚堝厹搴�
+ return CollUtil.isNotEmpty(outputIds) ? outputIds.get(0) : productId;
+ }
+ }
+ // 宸ュ崟宸ュ簭蹇収 / 瀛橀噺鏃犲綊灞炴暟鎹細浜у嚭宸叉寜浜у搧杩囨护锛屽彇绗竴涓�
+ String outputItemId = routeProcess.getOutputItemId();
+ if (outputItemId != null && !outputItemId.isBlank()) {
+ return Long.valueOf(outputItemId.split(",")[0].trim());
+ }
+ return productId;
+ }
+
@Override
public void deleteTask(Long id) {
// 1. 鏍¢獙瀛樺湪涓旈潪缁堟��
@@ -244,6 +339,11 @@
}
@Override
+ public MesProTaskDO getTaskByCode(String code) {
+ return taskMapper.selectByCode(code);
+ }
+
+ @Override
public PageResult<MesProTaskDO> getTaskPage(MesProTaskPageReqVO pageReqVO) {
return taskMapper.selectPage(pageReqVO);
}
@@ -251,6 +351,20 @@
@Override
public PageResult<MesProTaskDO> getPendingFeedbackPage(MesProTaskPageReqVO pageReqVO) {
return taskMapper.selectPendingFeedbackPage(pageReqVO);
+ }
+
+ @Override
+ public Map<Long, Long> getPendingFeedbackCountByWorkstation() {
+ List<Map<String, Object>> rows = taskMapper.selectPendingFeedbackCountByWorkstation();
+ Map<Long, Long> result = new HashMap<>(rows.size());
+ for (Map<String, Object> row : rows) {
+ Object workstationId = row.get("workstation_id");
+ Object count = row.get("pending_count");
+ if (workstationId instanceof Number && count instanceof Number) {
+ result.put(((Number) workstationId).longValue(), ((Number) count).longValue());
+ }
+ }
+ return result;
}
@Override
@@ -408,7 +522,7 @@
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 ? Long.valueOf(rp.getOutputItemId().split(",")[0].trim()) : workOrder.getProductId();
+ Long itemId = resolveTaskItemId(rp, workOrder.getProductId());
cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO item = itemService.validateItemExists(itemId);
MesProTaskDO task = new MesProTaskDO()
.setWorkOrderId(workOrder.getId())
@@ -421,6 +535,7 @@
.setStatus(MesProTaskStatusEnum.PREPARE.getStatus())
.setClientId(workOrder.getClientId())
.setColorCode(rp.getColorCode());
+ freezeTaskParamConfig(task);
taskMapper.insert(task);
taskIds.add(task.getId());
}
@@ -429,4 +544,56 @@
return taskIds;
}
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void pauseTask(MesProTaskPauseReqVO pauseReqVO) {
+ // 1. 鏍¢獙浠诲姟瀛樺湪
+ MesProTaskDO task = validateTaskExists(pauseReqVO.getId());
+ // 2. 鏍¢獙鐘舵�佹槸鍚﹀厑璁稿仠宸ワ紙濡傚繀椤绘槸 鐢熶骇涓� 鎴� 閮ㄥ垎瀹屾垚锛�
+ if (!ObjectUtils.equalsAny(task.getStatus(), MesProTaskStatusEnum.PRODUCING.getStatus(),
+ MesProTaskStatusEnum.PARTIAL_FINISHED.getStatus())) {
+ throw exception(PRO_TASK_CANNOT_PAUSE);
+ }
+
+ // 3. 淇敼浠诲姟鐘舵�佷负宸插仠宸�
+ taskMapper.updateById(new MesProTaskDO().setId(task.getId()).setStatus(MesProTaskStatusEnum.PAUSED.getStatus()));
+
+ // 4. 鍒涘缓鍋滃伐璁板綍
+ MesProTaskPauseRecordDO pauseRecord = new MesProTaskPauseRecordDO()
+ .setTaskId(task.getId())
+ .setWorkOrderId(task.getWorkOrderId())
+ .setWorkstationId(task.getWorkstationId())
+ .setReason(pauseReqVO.getReason())
+ .setRemark(pauseReqVO.getRemark())
+ .setPauseTime(LocalDateTime.now())
+ .setPauseUserId(SecurityFrameworkUtils.getLoginUserId());
+ taskPauseRecordMapper.insert(pauseRecord);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void resumeTask(MesProTaskResumeReqVO resumeReqVO) {
+ // 1. 鏍¢獙浠诲姟瀛樺湪
+ MesProTaskDO task = validateTaskExists(resumeReqVO.getId());
+ // 2. 鏍¢獙鐘舵�佸繀椤绘槸宸插仠宸�
+ if (!ObjectUtils.equalsAny(task.getStatus(), MesProTaskStatusEnum.PAUSED.getStatus())) {
+ throw exception(PRO_TASK_NOT_PAUSED);
+ }
+
+ // 3. 鎭㈠浠诲姟鐘舵��
+ Integer resumeStatus = task.getProducedQuantity() != null
+ && task.getProducedQuantity().signum() > 0
+ ? MesProTaskStatusEnum.PARTIAL_FINISHED.getStatus()
+ : MesProTaskStatusEnum.PRODUCING.getStatus();
+ taskMapper.updateById(new MesProTaskDO().setId(task.getId()).setStatus(resumeStatus));
+
+ // 4. 鏇存柊鏈�鏂扮殑涓�鏉″仠宸ヨ褰�
+ MesProTaskPauseRecordDO pauseRecord = taskPauseRecordMapper.selectLastUnresumedByTaskId(task.getId());
+ if (pauseRecord != null) {
+ pauseRecord.setResumeTime(LocalDateTime.now());
+ pauseRecord.setResumeUserId(SecurityFrameworkUtils.getLoginUserId());
+ taskPauseRecordMapper.updateById(pauseRecord);
+ }
+ }
+
}
--
Gitblit v1.9.3