From 8ea92030610fd1e62136f7b26e10d5396359d8f8 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期三, 30 九月 2026 19:04:28 +0800
Subject: [PATCH] feat(mes): 更新追溯功能支持未绑定批次和品种单位信息

---
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/trace/MesProTracePublicServiceImpl.java |   83 +++++++++++++++++++++++++++++++++--------
 1 files changed, 67 insertions(+), 16 deletions(-)

diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/trace/MesProTracePublicServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/trace/MesProTracePublicServiceImpl.java
index 04ff12f..b19e03a 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/trace/MesProTracePublicServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/trace/MesProTracePublicServiceImpl.java
@@ -2,6 +2,7 @@
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchFlowRespVO;
 import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchProcessTraceRespVO;
 import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchPurchaseSourceRespVO;
 import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchSalesTargetRespVO;
@@ -29,6 +30,9 @@
 import cn.iocoder.yudao.module.mes.service.trace.crossregion.MesTraceCrossRegionService;
 import cn.iocoder.yudao.module.mes.service.trace.integrity.MesTraceIntegrityService;
 import cn.iocoder.yudao.module.mes.service.wm.batch.MesWmBatchService;
+import cn.iocoder.yudao.module.mdm.api.unit.MdmUnitMeasureApi;
+import cn.iocoder.yudao.module.mdm.api.unit.dto.MdmUnitMeasureRespDTO;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
 import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
 import jakarta.annotation.Resource;
@@ -43,6 +47,7 @@
 import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@@ -78,6 +83,8 @@
     @Resource
     private MesMdmItemService mdmItemService;
     @Resource
+    private MdmUnitMeasureApi unitMeasureApi;
+    @Resource
     private AdminUserApi adminUserApi;
     @Resource
     private MesWmBatchService mesWmBatchService;
@@ -100,13 +107,13 @@
         }
         TraceEntry entry = null;
         try {
-            // 1. 瑙f瀽杩芥函鍏ュ彛锛屽畾浣嶆壒娆�
+            // 1. 瑙f瀽杩芥函鍏ュ彛锛屽畾浣嶆壒娆★紙琚嬬爜/鎵樼洏宸茬敓鎴愪絾鏈綍鍏ユ壒娆℃椂锛岄檷绾т负浠呰繑鍥炲搧绉嶄俊鎭級
             entry = resolveEntry(traceCode);
-            if (entry.batchId == null) {
+            if (entry.batchId == null && entry.bagItemId == null) {
                 throw exception(MES_TRACE_CODE_NOT_FOUND);
             }
             // 2. 鑱氬悎鍏ㄧ▼淇℃伅
-            MesProTracePublicRespVO result = buildRespVO(rawCode, traceCode, entry.sourceType, entry.batchId);
+            MesProTracePublicRespVO result = buildRespVO(rawCode, traceCode, entry.sourceType, entry.batchId, entry.bagItemId);
             recordConsumerScan(rawCode, traceCode, entry.sourceType, entry.batchId, true);
             return result;
         } catch (RuntimeException ex) {
@@ -166,33 +173,44 @@
         // 鈶� 琚嬬爜
         MesProBagCodeDO bag = bagCodeService.getBagCodeByCode(traceCode);
         if (bag != null) {
-            return new TraceEntry("BAG", bag.getBatchId());
+            return new TraceEntry("BAG", bag.getBatchId(), bag.getItemId());
         }
         // 鈶� 鎵樼洏鐮�
         MesProPalletDO pallet = palletService.getPalletByCode(traceCode);
         if (pallet != null) {
-            return new TraceEntry("PALLET", pallet.getBatchId());
+            // 鏈綍鍏ユ壒娆$殑鎵樼洏鍙栨墭鐩樺唴浠讳竴琚嬬爜鍝佺锛屼繚璇佷粛鑳藉睍绀哄搧绉嶄俊鎭�
+            Long itemId = pallet.getBatchId() == null
+                    ? firstItemId(bagCodeService.getBagCodeListByPalletId(pallet.getId())) : null;
+            return new TraceEntry("PALLET", pallet.getBatchId(), itemId);
         }
         // 鈶� 鎵规鐮侊紙鍚复鏃舵壒娆$爜锛実etBatchByCode 鍐呴儴鍏煎锛�
         MesProBatchDO batch = batchService.getBatchByCode(traceCode);
         if (batch != null) {
-            return new TraceEntry("BATCH", batch.getId());
+            return new TraceEntry("BATCH", batch.getId(), null);
         }
-        return new TraceEntry("", null);
+        return new TraceEntry("", null, null);
     }
 
     // ==================== 鑱氬悎鏋勫缓 ====================
 
-    private MesProTracePublicRespVO buildRespVO(String requestCode, String traceCode, String sourceType, Long batchId) {
-        MesProBatchDO batch = batchService.getBatch(batchId);
-        if (batch == null) {
+    private MesProTracePublicRespVO buildRespVO(String requestCode, String traceCode, String sourceType, Long batchId, Long bagItemId) {
+        MesProBatchDO batch = batchId == null ? null : batchService.getBatch(batchId);
+        if (batchId != null && batch == null) {
             throw exception(MES_TRACE_CODE_NOT_FOUND);
         }
         MesProTracePublicRespVO resp = new MesProTracePublicRespVO();
         resp.setSourceType(sourceType);
         resp.setRequestCode(requestCode);
         // 鍝佺鍖哄潡
-        fillItem(resp, batch);
+        fillItem(resp, batch, bagItemId);
+        if (batch == null) {
+            // 琚嬬爜/鎵樼洏宸茬敓鎴愪絾灏氭湭褰曞叆鐢熶骇鎵规锛氬彧杩斿洖鍝佺淇℃伅锛岀敱鍓嶇鎻愮ず鏈粦瀹氭壒娆�
+            resp.setBatchBound(false);
+            fillAntiFake(resp, traceCode);
+            fillTimelineAndDecision(resp);
+            return resp;
+        }
+        resp.setBatchBound(true);
         // 鎵规鍖哄潡
         resp.setBatchCode(batch.getCode()).setTempCode(batch.getTempCode())
                 .setBatchStatus(batch.getStatus()).setBatchStatusName(batchStatusName(batch.getStatus()))
@@ -219,15 +237,45 @@
         return resp;
     }
 
-    private void fillItem(MesProTracePublicRespVO resp, MesProBatchDO batch) {
-        if (batch.getItemId() == null) {
+    /**
+     * 鍝佺宸蹭笅娌夊埌琚嬬爜鏁版嵁鍖咃細浼樺厛鍙栨壂鐮佽鐮佸搧绉嶏紝鍘嗗彶鎵规鍥為��鎵规鍝佺锛屾壒娆�/鎵樼洏鍏ュ彛鍙栨壒鍐呬换涓�琚嬬爜鍝佺
+     */
+    private void fillItem(MesProTracePublicRespVO resp, MesProBatchDO batch, Long bagItemId) {
+        Long itemId = bagItemId != null ? bagItemId : (batch == null ? null : batch.getItemId());
+        if (itemId == null && batch != null) {
+            itemId = firstItemId(bagCodeService.getBagCodeListByBatchId(batch.getId()));
+        }
+        if (itemId == null) {
             return;
         }
-        MesMdmItemDO item = mdmItemService.getItem(batch.getItemId());
+        MesMdmItemDO item = mdmItemService.getItem(itemId);
         if (item == null) {
             return;
         }
-        resp.setItemCode(item.getCode()).setItemName(item.getName()).setItemSpecification(item.getSpecification());
+        resp.setItemCode(item.getCode()).setItemName(item.getName()).setItemSpecification(item.getSpecification())
+                .setItemUnitMeasureName(unitMeasureName(item.getUnitMeasureId()));
+    }
+
+    /**
+     * 璇诲彇琚嬬爜鍒楄〃涓涓�涓潪绌哄搧绉嶇紪鍙�
+     */
+    private Long firstItemId(List<MesProBagCodeDO> bags) {
+        return CollUtil.isEmpty(bags) ? null : bags.stream().map(MesProBagCodeDO::getItemId)
+                .filter(Objects::nonNull).findFirst().orElse(null);
+    }
+
+    /**
+     * 璇诲彇鍝佺涓昏閲忓崟浣嶅悕绉帮紝鏈厤缃崟浣嶆垨鍗曚綅涓嶅瓨鍦ㄦ椂杩斿洖 null
+     */
+    private String unitMeasureName(Long unitMeasureId) {
+        if (unitMeasureId == null) {
+            return null;
+        }
+        CommonResult<MdmUnitMeasureRespDTO> result = unitMeasureApi.getUnitMeasure(unitMeasureId);
+        if (result == null || !result.isSuccess() || result.getData() == null) {
+            return null;
+        }
+        return StrUtil.trimToNull(result.getData().getName());
     }
 
     private List<MesProTracePublicRespVO.WorkerVO> buildWorkers(Long batchId) {
@@ -333,12 +381,15 @@
             resp.setPurchaseSources(CollUtil.isNotEmpty(purchaseSources) ? purchaseSources : List.of());
             resp.setSalesTargets(CollUtil.isNotEmpty(salesTargets) ? salesTargets : List.of());
             resp.setProcessTraces(CollUtil.isNotEmpty(processTraces) ? processTraces : List.of());
+            List<MesWmBatchFlowRespVO> seedFlows = mesWmBatchService.getBatchFlowList(batch.getCode());
+            resp.setSeedFlows(CollUtil.isNotEmpty(seedFlows) ? seedFlows : List.of());
         } catch (Exception ex) {
             // 浠撳簱鎵规浣撶郴锛堥噰璐�/閿�鍞�/娴佽浆锛夋湭鍚敤鏃跺閿欙紝涓嶅奖鍝嶆牳蹇冭拷婧�
             log.warn("[fillOptionalModules][鎵规 {} 鎵╁睍妯″潡鏌ヨ澶辫触: {}]", batch.getCode(), ex.getMessage());
             resp.setPurchaseSources(List.of());
             resp.setSalesTargets(List.of());
             resp.setProcessTraces(List.of());
+            resp.setSeedFlows(List.of());
         }
     }
 
@@ -454,7 +505,7 @@
         };
     }
 
-    private record TraceEntry(String sourceType, Long batchId) {
+    private record TraceEntry(String sourceType, Long batchId, Long bagItemId) {
     }
 
 }

--
Gitblit v1.9.3