From 227eff61120aaca63e068035d745d86452e6499a Mon Sep 17 00:00:00 2001
From: hsy <1029150275@qq.com>
Date: 星期一, 17 八月 2026 09:35:12 +0800
Subject: [PATCH] feat(mes): 优化生产订单与排产任务列表显示,新增启停工及校验逻辑 1. 生产订单列表展示优化 (WorkOrder) - 新增「生产状态」列,全局注册 `ORDER_PRODUCTION_STATUS` 常量并绑定系统动态字典。 - 彻底重构「工序生产进度」单元格显示:弃用臃肿的 Steps 组件,改为极简横向布局(彩色状态圆点 + 进度百分比),解决表格行高被强行撑开及内容截断问题,支持横向滚动。 - 优化「完成进度」列宽及展示样式,将百分比数值外置同行显示,更加直观。 2. 排产任务列表改造 (Task) - 顶部表头重构,由单一标题重构为「全部 / 未完成 / 已完成」的 Tabs 标签页切换结构。 - 重写数据过滤逻辑,剥离写死的 status 查询,改为使用 `scheduleStatus` 字段动态响应 Tabs 切换 (0: 未完成, 1: 已完成)。 3. 工单业务逻辑增强与状态流转 - 落实「工单查询逻辑设计方案」,优化底层的工单条件检索逻辑。 - 实现「添加工单启停功能」与「停工状态」,支持工单在执行过程中的暂停与恢复业务流转。 - 强化容错与防呆设计:操作「完成订单」时增加前置校验 `handleCheckFinish`,若生产状态为未完成,强制弹出二次确认 Modal,避免误操作。 # 相关讨论/参考方案 # - 添加工单启停功能 # - 停工状态功能设计方案 # - 工单查询逻辑设计方案 # - 工单完成进度显示优化
---
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/task/MesProTaskServiceImpl.java | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 100 insertions(+), 3 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 d19426b..d6ebc52 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
@@ -7,17 +7,21 @@
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.dv.machinery.MesDvMachineryDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.md.workstation.MesMdWorkstationMachineDO;
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.dv.machinery.MesDvMachineryService;
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;
+import cn.iocoder.yudao.module.mes.service.md.workstation.MesMdWorkstationMachineService;
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;
@@ -40,17 +44,27 @@
import java.util.Collection;
import java.util.Collections;
import java.util.List;
+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
@@ -61,6 +75,9 @@
@Resource
private MesProFeedbackMapper feedbackMapper;
+
+ @Resource
+ private MesProTaskPauseRecordMapper taskPauseRecordMapper;
@Resource
@Lazy
@@ -86,6 +103,11 @@
private MesProWorkOrderProcessService workOrderProcessService;
@Resource
private MesMdAutoCodeRecordService autoCodeRecordService;
+ @Resource
+ private MesMdWorkstationMachineService workstationMachineService;
+ @Resource
+ @Lazy
+ private MesDvMachineryService machineryService;
@Override
public Long createTask(MesProTaskSaveReqVO createReqVO) {
@@ -101,7 +123,7 @@
MesProRouteProcessDO routeProcess = routeProcessService
.getRouteProcessByRouteIdAndProcessId(createReqVO.getRouteId(), createReqVO.getProcessId());
if (routeProcess != null && routeProcess.getOutputItemId() != null) {
- itemId = routeProcess.getOutputItemId();
+ itemId = Long.valueOf(routeProcess.getOutputItemId().split(",")[0].trim());
} else {
itemId = workOrder.getProductId();
}
@@ -318,6 +340,33 @@
}
@Override
+ public Integer calculateDuration(Long workstationId, BigDecimal quantity) {
+ if (quantity == null || quantity.compareTo(BigDecimal.ZERO) <= 0) {
+ return 0;
+ }
+ // 1. 鏌ヨ宸ヤ綔绔欑粦瀹氱殑璁惧
+ List<MesMdWorkstationMachineDO> machines = workstationMachineService
+ .getWorkstationMachineListByWorkstationId(workstationId);
+ if (CollUtil.isEmpty(machines)) {
+ return 0;
+ }
+ // 2. 鑾峰彇璁惧璇︽儏锛岃绠楁�绘晥鐜�
+ Set<Long> machineryIds = convertSet(machines, MesMdWorkstationMachineDO::getMachineryId);
+ List<MesDvMachineryDO> machineryList = machineryService.getMachineryList(machineryIds);
+ BigDecimal totalEfficiency = BigDecimal.ZERO;
+ for (MesDvMachineryDO m : machineryList) {
+ BigDecimal efficiency = m.getProductionEfficiency() != null ? m.getProductionEfficiency() : BigDecimal.ZERO;
+ Integer belt = m.getConveyorBelt() != null && m.getConveyorBelt() > 0 ? m.getConveyorBelt() : 1;
+ totalEfficiency = totalEfficiency.add(efficiency.multiply(BigDecimal.valueOf(belt)));
+ }
+ if (totalEfficiency.compareTo(BigDecimal.ZERO) <= 0) {
+ return 0;
+ }
+ // 3. 鐢熶骇鏃堕暱锛堝皬鏃讹級 = ceil(鎺掍骇鏁伴噺 / 鎬绘晥鐜�)锛屾晥鐜囧崟浣嶄负姣忓皬鏃朵骇閲�
+ return quantity.divide(totalEfficiency, 0, java.math.RoundingMode.CEILING).intValue();
+ }
+
+ @Override
public MesProTaskAutoGeneratePreviewRespVO previewAutoGenerate(MesProTaskAutoGenerateReqVO reqVO) {
// 1. 鏍¢獙宸ュ崟宸茬‘璁�
MesProWorkOrderDO workOrder = workOrderService.validateWorkOrderConfirmed(reqVO.getWorkOrderId());
@@ -370,7 +419,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 ? rp.getOutputItemId() : workOrder.getProductId();
+ Long itemId = rp.getOutputItemId() != null ? Long.valueOf(rp.getOutputItemId().split(",")[0].trim()) : workOrder.getProductId();
cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO item = itemService.validateItemExists(itemId);
MesProTaskDO task = new MesProTaskDO()
.setWorkOrderId(workOrder.getId())
@@ -391,4 +440,52 @@
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.PREPARE.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 = MesProTaskStatusEnum.PREPARE.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