From f13916c4d793db207cec5a4fc75773366f590362 Mon Sep 17 00:00:00 2001
From: liding <756868258@qq.com>
Date: 星期四, 07 五月 2026 16:31:58 +0800
Subject: [PATCH] fix:1.报错中文调整 2.导入导出优化 3.production方法加上注释

---
 src/main/java/com/ruoyi/production/service/impl/ProductionAccountServiceImpl.java                    |    3 
 src/main/java/com/ruoyi/production/service/impl/ProductionProductOutputServiceImpl.java              |    1 
 src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java                |   22 +
 src/main/java/com/ruoyi/production/service/impl/ProductionOrderRoutingServiceImpl.java               |    2 
 src/main/java/com/ruoyi/production/service/impl/ProductionOrderRoutingOperationParamServiceImpl.java |   23 +
 src/main/java/com/ruoyi/production/service/impl/ProductionProductInputServiceImpl.java               |    1 
 src/main/java/com/ruoyi/production/service/impl/ProductionOperationTaskServiceImpl.java              |   20 +
 src/main/java/com/ruoyi/technology/service/impl/TechnologyBomServiceImpl.java                        |   12 
 src/main/java/com/ruoyi/production/service/impl/ProductionOrderPickRecordServiceImpl.java            |    1 
 src/main/java/com/ruoyi/technology/service/impl/TechnologyParamServiceImpl.java                      |   10 
 src/main/java/com/ruoyi/production/service/impl/SalesLedgerProductionAccountingServiceImpl.java      |    1 
 src/main/java/com/ruoyi/production/controller/ProductionPlanController.java                          |    9 
 src/main/java/com/ruoyi/production/service/ProductionPlanService.java                                |    2 
 src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java               |   14 +
 src/main/java/com/ruoyi/production/service/impl/ProductionPlanServiceImpl.java                       |  314 ++++++++++++++++++-----
 src/main/java/com/ruoyi/production/service/impl/ProductionOrderRoutingOperationServiceImpl.java      |    9 
 src/main/java/com/ruoyi/technology/service/impl/TechnologyOperationParamServiceImpl.java             |    8 
 src/main/java/com/ruoyi/production/service/impl/ProductionOrderPickServiceImpl.java                  |  182 ++++++++++---
 src/main/java/com/ruoyi/production/service/impl/ProductionOrderServiceImpl.java                      |   51 +++
 src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java                                              |   69 +++-
 20 files changed, 586 insertions(+), 168 deletions(-)

diff --git a/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java b/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java
index bb2ebb5..d103265 100644
--- a/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java
+++ b/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java
@@ -465,21 +465,37 @@
                     {
                         val = Convert.toBigDecimal(val);
                     }
-                    else if (Date.class == fieldType)
-                    {
-                        if (val instanceof String)
-                        {
-                            val = DateUtils.parseDate(val);
+                    else if (Date.class == fieldType)
+                    {
+                        if (val instanceof String)
+                        {
+                            val = DateUtils.parseDate(val);
                         }
                         else if (val instanceof Double)
-                        {
-                            val = DateUtil.getJavaDate((Double) val);
-                        }
-                    }
-                    else if (Boolean.TYPE == fieldType || Boolean.class == fieldType)
-                    {
-                        val = Convert.toBool(val, false);
-                    }
+                        {
+                            val = DateUtil.getJavaDate((Double) val);
+                        }
+                    }
+                    else if (LocalDate.class == fieldType)
+                    {
+                        if (val instanceof String)
+                        {
+                            Date date = DateUtils.parseDate(val);
+                            val = StringUtils.isNull(date) ? null : DateUtils.toLocalDate(date);
+                        }
+                        else if (val instanceof Date)
+                        {
+                            val = DateUtils.toLocalDate((Date) val);
+                        }
+                        else if (val instanceof Double)
+                        {
+                            val = DateUtils.toLocalDate(DateUtil.getJavaDate((Double) val));
+                        }
+                    }
+                    else if (Boolean.TYPE == fieldType || Boolean.class == fieldType)
+                    {
+                        val = Convert.toBool(val, false);
+                    }
                     if (StringUtils.isNotNull(fieldType))
                     {
                         String propertyName = field.getName();
@@ -651,15 +667,24 @@
                         val = Convert.toFloat(val);
                     } else if (BigDecimal.class == fieldType) {
                         val = Convert.toBigDecimal(val);
-                    } else if (Date.class == fieldType) {
-                        if (val instanceof String) {
-                            val = DateUtils.parseDate(val);
-                        } else if (val instanceof Double) {
-                            val = DateUtil.getJavaDate((Double) val);
-                        }
-                    } else if (Boolean.TYPE == fieldType || Boolean.class == fieldType) {
-                        val = Convert.toBool(val, false);
-                    }
+                    } else if (Date.class == fieldType) {
+                        if (val instanceof String) {
+                            val = DateUtils.parseDate(val);
+                        } else if (val instanceof Double) {
+                            val = DateUtil.getJavaDate((Double) val);
+                        }
+                    } else if (LocalDate.class == fieldType) {
+                        if (val instanceof String) {
+                            Date date = DateUtils.parseDate(val);
+                            val = StringUtils.isNull(date) ? null : DateUtils.toLocalDate(date);
+                        } else if (val instanceof Date) {
+                            val = DateUtils.toLocalDate((Date) val);
+                        } else if (val instanceof Double) {
+                            val = DateUtils.toLocalDate(DateUtil.getJavaDate((Double) val));
+                        }
+                    } else if (Boolean.TYPE == fieldType || Boolean.class == fieldType) {
+                        val = Convert.toBool(val, false);
+                    }
 
                     if (StringUtils.isNotNull(fieldType)) {
                         String propertyName = field.getName();
diff --git a/src/main/java/com/ruoyi/production/controller/ProductionPlanController.java b/src/main/java/com/ruoyi/production/controller/ProductionPlanController.java
index 6190a47..923f95c 100644
--- a/src/main/java/com/ruoyi/production/controller/ProductionPlanController.java
+++ b/src/main/java/com/ruoyi/production/controller/ProductionPlanController.java
@@ -14,6 +14,7 @@
 import io.swagger.v3.oas.annotations.Operation;
 import jakarta.servlet.http.HttpServletResponse;
 import lombok.RequiredArgsConstructor;
+import org.springframework.http.MediaType;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 
@@ -85,10 +86,10 @@
         excelUtil.importTemplateExcel(response, "涓荤敓浜ц鍒掑鍏ユā鏉�");
     }
 
-    @PostMapping("/import")
+    @PostMapping(value = "/import", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
     @Operation(summary = "涓荤敓浜ц鍒掓暟鎹鍏�")
     @Log(title = "涓荤敓浜ц鍒掓暟鎹鍏�", businessType = BusinessType.IMPORT)
-    public R importProdData(@RequestParam("file") MultipartFile file) {
+    public R importProdData(@RequestPart("file") MultipartFile file) {
         productionPlanService.importProdData(file);
         return R.ok("瀵煎叆鎴愬姛");
     }
@@ -96,8 +97,8 @@
     @PostMapping("/export")
     @Operation(summary = "涓荤敓浜ц鍒掓暟鎹鍑�")
     @Log(title = "涓荤敓浜ц鍒掓暟鎹鍑�", businessType = BusinessType.EXPORT)
-    public void exportProdData(HttpServletResponse response, @RequestBody(required = false) List<Long> ids) {
-        productionPlanService.exportProdData(response, ids);
+    public void exportProdData(HttpServletResponse response, @RequestBody(required = false) ProductionPlanDto requestDto) {
+        productionPlanService.exportProdData(response, requestDto);
     }
 
 }
diff --git a/src/main/java/com/ruoyi/production/service/ProductionPlanService.java b/src/main/java/com/ruoyi/production/service/ProductionPlanService.java
index 052676b..715e221 100644
--- a/src/main/java/com/ruoyi/production/service/ProductionPlanService.java
+++ b/src/main/java/com/ruoyi/production/service/ProductionPlanService.java
@@ -51,6 +51,6 @@
     /**
      * 瀵煎嚭鏁版嵁
      */
-    void exportProdData(HttpServletResponse response, List<Long> ids);
+    void exportProdData(HttpServletResponse response, ProductionPlanDto requestDto);
 
 }
diff --git a/src/main/java/com/ruoyi/production/service/impl/ProductionAccountServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/ProductionAccountServiceImpl.java
index 9c1843c..c35c757 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductionAccountServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionAccountServiceImpl.java
@@ -24,16 +24,19 @@
 
     @Override
     public IPage<ProductionAccountVo> listPage(Page<ProductionAccountDto> page, ProductionAccountDto dto) {
+        // 鍒嗛〉鏌ヨ鐢熶骇鏍哥畻鏁版嵁
         ProductionAccountDto queryDto = normalizeDateQuery(dto);
         return baseMapper.listPage(page, queryDto);
     }
 
     @Override
     public IPage<ProductionProductMainDto> listProductionDetails(ProductionAccountDto dto, Page page) {
+        // 鏌ヨ鐢熶骇鏍哥畻鏄庣粏
         return productionProductMainMapper.listProductionDetails(normalizeDateQuery(dto), page);
     }
 
     private ProductionAccountDto normalizeDateQuery(ProductionAccountDto dto) {
+        // 瑙勮寖鏃ユ湡鏌ヨ鑼冨洿锛岃ˉ榻愮己澶辩殑寮�濮嬫垨缁撴潫鏃堕棿
         if (dto == null) {
             return new ProductionAccountDto();
         }
diff --git a/src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java
index cbae0dc..35cdb27 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java
@@ -33,6 +33,7 @@
      */
     @Override
     public List<ProductionBomStructureVo> listByBomId(Long bomId) {
+        // 鎸塀OMID鏌ヨ鐢熶骇缁撴瀯鏁版嵁
         List<ProductionBomStructureVo> list = productionBomStructureMapper.listByBomId(bomId);
         Map<Long, ProductionBomStructureVo> map = new HashMap<>();
         for (ProductionBomStructureVo node : list) {
@@ -58,13 +59,17 @@
     @Override
     @Transactional(rollbackFor = Exception.class)
     public Boolean addProductionBomStructure(ProductionBomStructureDto dto) {
+        // 鏂板鐢熶骇BOM缁撴瀯
+        // 璇诲彇褰撳墠璁㈠崟BOM涓婚敭锛屽苟鎶婂墠绔爲缁撴瀯鎷嶅钩鎴愬垪琛�
         Long orderBomId = dto.getProductionOrderBomId();
         List<ProductionBomStructureDto> flatDtoList = new ArrayList<>();
         flattenTree(dto.getChildren(), flatDtoList);
 
+        // 鏌ヨ鏁版嵁搴撳凡鏈夌粨鏋勶紝鐢ㄤ簬鍚庣画鍋氬鍒犳敼瀵规瘮
         List<ProductionBomStructure> dbList = this.list(new LambdaQueryWrapper<ProductionBomStructure>()
                 .eq(ProductionBomStructure::getProductionOrderBomId, orderBomId));
 
+        // 鏀堕泦鍓嶇浠嶇劧瀛樺湪鐨勮妭鐐笽D
         Set<Long> frontendIds = new HashSet<>();
         for (ProductionBomStructureDto item : flatDtoList) {
             if (item.getId() != null) {
@@ -72,16 +77,19 @@
             }
         }
 
+        // 璁$畻闇�瑕佸垹闄ょ殑鑺傜偣锛堟暟鎹簱鏈夈�佸墠绔凡鍒犻櫎锛�
         Set<Long> deleteIds = new HashSet<>();
         for (ProductionBomStructure dbItem : dbList) {
             if (!frontendIds.contains(dbItem.getId())) {
                 deleteIds.add(dbItem.getId());
             }
         }
+        // 鍏堝垹鎺夊墠绔凡缁忕Щ闄ょ殑鑺傜偣
         if (!deleteIds.isEmpty()) {
             this.removeByIds(deleteIds);
         }
 
+        // 鎸夋槸鍚︽湁ID鎷嗗垎涓烘柊澧炲拰鏇存柊锛屽悓鏃剁紦瀛樻柊澧炶妭鐐圭殑涓存椂ID鏄犲皠
         List<ProductionBomStructure> insertList = new ArrayList<>();
         List<ProductionBomStructure> updateList = new ArrayList<>();
         Map<String, ProductionBomStructure> tempEntityMap = new HashMap<>();
@@ -99,10 +107,12 @@
             }
         }
 
+        // 鎵归噺鏂板锛屾嬁鍒版暟鎹簱鐢熸垚鐨勭湡瀹濱D
         if (!insertList.isEmpty()) {
             this.saveBatch(insertList);
         }
 
+        // 鏂板鑺傜偣浜屾鍥炲啓鐖禝D锛堝墠绔紶鐨勬槸涓存椂鐖禝D锛�
         List<ProductionBomStructure> parentFixList = new ArrayList<>();
         for (ProductionBomStructureDto item : flatDtoList) {
             if (item.getId() == null && item.getParentTempId() != null) {
@@ -111,15 +121,18 @@
                     continue;
                 }
                 ProductionBomStructure parent = tempEntityMap.get(item.getParentTempId());
+                // 鐖惰妭鐐规槸鏈鏂板鏃讹紝鐩存帴鐢ㄦ柊澧炲悗鐨勭湡瀹濱D锛涘惁鍒欏洖閫�涓哄墠绔紶鍏ョ埗ID
                 Long realParentId = parent != null ? parent.getId() : Long.valueOf(item.getParentTempId());
                 child.setParentId(realParentId);
                 parentFixList.add(child);
             }
         }
 
+        // 鍥炲啓鏂板鑺傜偣鐨勭埗瀛愬叧绯�
         if (!parentFixList.isEmpty()) {
             this.updateBatchById(parentFixList);
         }
+        // 鎵归噺鏇存柊宸叉湁鑺傜偣
         if (!updateList.isEmpty()) {
             this.updateBatchById(updateList);
         }
@@ -130,6 +143,7 @@
      * 灏嗘爲褰㈢粨鏋勬媿骞虫垚鍒楄〃锛屼究浜庣粺涓�淇濆瓨銆�
      */
     private void flattenTree(List<ProductionBomStructureDto> source, List<ProductionBomStructureDto> result) {
+        // 鎵佸钩鍖栧鐞嗘爲
         if (source == null) {
             return;
         }
diff --git a/src/main/java/com/ruoyi/production/service/impl/ProductionOperationTaskServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/ProductionOperationTaskServiceImpl.java
index 383193b..6e9457d 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductionOperationTaskServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionOperationTaskServiceImpl.java
@@ -58,6 +58,7 @@
 
     @Override
     public IPage<ProductionOperationTaskVo> pageProductionOperationTask(Page<ProductionOperationTaskDto> page, ProductionOperationTaskDto dto) {
+        // 鍒嗛〉鏌ヨ鐢熶骇宸ュ簭浠诲姟
         Page<ProductionOperationTaskVo> voPage = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
         IPage<ProductionOperationTaskVo> result = baseMapper.pageProductionOperationTask(voPage, dto);
         fillUserNames(result.getRecords());
@@ -66,6 +67,7 @@
 
     @Override
     public List<ProductionOperationTaskVo> listProductionOperationTask(ProductionOperationTaskDto dto) {
+        // 鏌ヨ宸ュ簭浠诲姟鍒楄〃
         List<ProductionOperationTaskVo> result = BeanUtil.copyToList(this.list(buildQueryWrapper(dto)), ProductionOperationTaskVo.class);
         fillUserNames(result);
         return result;
@@ -73,6 +75,7 @@
 
     @Override
     public ProductionOperationTaskVo getProductionOperationTaskInfo(Long id) {
+        // 鑾峰彇鐢熶骇宸ュ簭浠诲姟璇︽儏
         ProductionOperationTask item = this.getById(id);
         if (item == null) {
             return null;
@@ -90,21 +93,25 @@
 
     @Override
     public boolean saveProductionOperationTask(ProductionOperationTask productionOperationTask) {
+        // 淇濆瓨鐢熶骇宸ュ簭浠诲姟
         return this.saveOrUpdate(productionOperationTask);
     }
 
     @Override
     public boolean removeProductionOperationTask(List<Long> ids) {
+        // 鍒犻櫎鐢熶骇宸ュ簭浠诲姟
         return ids != null && !ids.isEmpty() && this.removeByIds(ids);
     }
 
     @Override
     public int updateProductWorkOrder(ProductionOperationTaskDto dto) {
+        // 鏇存柊宸ュ簭浠诲姟瀵瑰簲鐨勫伐鍗曚俊鎭�
         return baseMapper.updateById(dto);
     }
 
     @Override
     public boolean assign(ProductionOperationTaskDto dto) {
+        // 鍒嗛厤宸ュ簭浠诲姟鎵ц浜�
         if (dto == null || dto.getId() == null) {
             throw new ServiceException("宸ュ崟ID涓嶈兘涓虹┖");
         }
@@ -120,6 +127,7 @@
     }
 
     private LambdaQueryWrapper<ProductionOperationTask> buildQueryWrapper(ProductionOperationTaskDto dto) {
+        // 鎸夋潯浠跺姩鎬佹瀯寤烘暟鎹簱鏌ヨ鏉′欢
         ProductionOperationTask query = dto == null ? new ProductionOperationTask() : dto;
         return Wrappers.<ProductionOperationTask>lambdaQuery()
                 .eq(query.getId() != null, ProductionOperationTask::getId, query.getId())
@@ -133,10 +141,12 @@
     }
 
     private void fillUserNames(List<ProductionOperationTaskVo> voList) {
+        // 濉厖鐢ㄦ埛鍚嶇О
         if (voList == null || voList.isEmpty()) {
             return;
         }
         Set<Long> userIdSet = new LinkedHashSet<>();
+        // 閬嶅巻澶勭悊鏁版嵁骞剁粍瑁呯粨鏋�
         for (ProductionOperationTaskVo vo : voList) {
             if (vo == null) {
                 continue;
@@ -172,6 +182,7 @@
     }
 
     private List<Long> parseUserIdList(String userIds, boolean strict) {
+        // 瑙f瀽骞舵牎楠岀敤鎴稩D鏁扮粍瀛楃涓�
         if (StringUtils.isBlank(userIds)) {
             if (strict) {
                 throw new ServiceException("userIds鏍煎紡涓嶆纭紝蹇呴』涓篔SON鏁板瓧鏁扮粍");
@@ -199,6 +210,7 @@
 
     @Override
     public void down(HttpServletResponse response, ProductionOperationTaskDto dto) {
+        // 瀵煎嚭宸ュ簭浠诲姟鏁版嵁
         if (dto == null || dto.getId() == null) {
             throw new ServiceException("宸ュ崟ID涓嶈兘涓虹┖");
         }
@@ -250,15 +262,18 @@
     }
 
     private List<Map<String, Object>> buildTaskAttachmentImages(Long taskId) {
+        // 缁勮浠诲姟闄勪欢鍥剧墖鏁版嵁鐢ㄤ簬瀵煎嚭
         List<Map<String, Object>> images = new ArrayList<>();
         StorageAttachmentDTO storageAttachmentDTO = new StorageAttachmentDTO();
         storageAttachmentDTO.setRecordType(RecordTypeEnum.PRODUCTION_OPERATION_TASK.getType());
         storageAttachmentDTO.setRecordId(taskId);
         List<StorageBlobVO> taskWorkOrderFiles =
                 fileUtil.getStorageBlobVOsByApplicationAndRecordTypeAndRecordId(storageAttachmentDTO);
+        // 鍙傛暟涓庡墠缃潯浠舵牎楠�
         if (CollectionUtils.isEmpty(taskWorkOrderFiles)) {
             return images;
         }
+        // 閬嶅巻澶勭悊鏁版嵁骞剁粍瑁呯粨鏋�
         for (StorageBlobVO blobVO : taskWorkOrderFiles) {
             if (blobVO == null) {
                 continue;
@@ -286,6 +301,7 @@
     }
 
     private File resolveImageFile(StorageBlobVO blobVO) {
+        // 灏嗛檮浠朵俊鎭В鏋愪负鏈湴鍥剧墖鏂囦欢瀵硅薄
         if (blobVO == null || StringUtils.isBlank(blobVO.getUidFilename())) {
             return null;
         }
@@ -296,6 +312,7 @@
     }
 
     private PictureType resolvePictureType(StorageBlobVO blobVO) {
+        // 鎸夋枃浠跺悕鎴栧唴瀹圭被鍨嬭瘑鍒浘鐗囨牸寮�
         if (blobVO == null) {
             return null;
         }
@@ -311,6 +328,7 @@
     }
 
     private PictureType parsePictureTypeByFileName(String fileName) {
+        // 鏍规嵁鏂囦欢鍚庣紑瑙f瀽鍥剧墖鏍煎紡
         if (StringUtils.isBlank(fileName) || !fileName.contains(".")) {
             return null;
         }
@@ -322,6 +340,7 @@
     }
 
     private PictureType parsePictureTypeByContentType(String contentType) {
+        // 鏍规嵁Content-Type瑙f瀽鍥剧墖鏍煎紡
         if (StringUtils.isBlank(contentType)) {
             return null;
         }
@@ -350,6 +369,7 @@
 
     @Override
     public List<ProductionOperationTaskVo> getOperation(ProductionOperationTaskDto dto) {
+        // 鏌ヨ宸ュ簭浠诲姟鍒楄〃
         return baseMapper.getOperation(dto);
     }
 }
diff --git a/src/main/java/com/ruoyi/production/service/impl/ProductionOrderPickRecordServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/ProductionOrderPickRecordServiceImpl.java
index 1cf7c1e..4b71eb3 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductionOrderPickRecordServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionOrderPickRecordServiceImpl.java
@@ -24,6 +24,7 @@
 
     @Override
     public List<ProductionOrderPickRecordVo> listFeedingRecord(ProductionOrderPickRecordDto dto) {
+        // 鏌ヨ鎶曟枡璁板綍
         if (dto == null || dto.getProductionOrderId() == null || dto.getPickId() == null) {
             return Collections.emptyList();
         }
diff --git a/src/main/java/com/ruoyi/production/service/impl/ProductionOrderPickServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/ProductionOrderPickServiceImpl.java
index f45c117..478ecd5 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductionOrderPickServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionOrderPickServiceImpl.java
@@ -30,12 +30,8 @@
 import java.util.stream.Collectors;
 
 /**
- * <p>
- * 鐠併垹宕熸0鍡樻灐缁捐儻绔熸禒?閺堝秴濮熺�圭偟骞囩猾?
- * </p>
- *
- * @author 閼侯垰顕辨潪顖欐閿涘牊鐫欓懟蹇ョ礆閺堝妾洪崗顒�寰�
- * @since 2026-04-21 03:55:52
+ * 鐢熶骇璁㈠崟棰嗘枡鏈嶅姟瀹炵幇銆�
+ * 璐熻矗棰嗘枡鏂板銆佹洿鏂般�佽ˉ鏂欍�侀��鏂欏強搴撳瓨鑱斿姩銆�
  */
 @Service
 @RequiredArgsConstructor
@@ -53,17 +49,26 @@
     @Override
     @Transactional(rollbackFor = Exception.class)
     public Boolean savePick(ProductionOrderPickDto dto) {
+        // 棰嗘枡鏂板鎬绘祦绋嬶細
+        // 1) 瑙f瀽鍓嶇琛屾暟鎹苟閫愯鍚堝苟鍙傛暟锛�
+        // 2) 鏍¢獙鍙傛暟涓庢壒娆★紱
+        // 3) 鍏堟墸鍑忓簱瀛橈紝鍐嶈惤搴撻鏂欎富璁板綍锛�
+        // 4) 鍐欏叆棰嗘枡娴佹按锛岃褰曟暟閲忓彉鍖栬建杩广��
         List<ProductionOrderPickDto> pickItems = resolvePickItems(dto);
+        // 閫愯澶勭悊棰嗘枡鏁版嵁锛岃鍙风敤浜庢嫾瑁呯簿纭殑鎶ラ敊淇℃伅銆�
         for (int i = 0; i < pickItems.size(); i++) {
             int rowNo = i + 1;
             ProductionOrderPickDto resolvedDto = mergeDto(dto, pickItems.get(i));
+            // 姣忚閮藉仛瀹屾暣鏍¢獙锛屽紓甯镐俊鎭甫琛屽彿銆�
             validatePickParam(resolvedDto, rowNo);
 
+            // 缁熶竴澶勭悊鎵规锛堟敮鎸佸崟鎵规/澶氭壒娆★級銆�
             List<String> batchNoList = resolveBatchNoList(resolvedDto);
             String inventoryBatchNo = pickInventoryBatchNo(batchNoList);
             String storedBatchNo = formatBatchNoStorage(batchNoList);
             subtractInventory(resolvedDto.getProductModelId(), storedBatchNo, resolvedDto.getPickQuantity(), rowNo);
 
+            // 淇濆瓨棰嗘枡涓昏褰曞揩鐓с��
             ProductionOrderPick orderPick = new ProductionOrderPick();
             orderPick.setProductionOrderId(resolvedDto.getProductionOrderId());
             orderPick.setProductModelId(resolvedDto.getProductModelId());
@@ -75,8 +80,10 @@
             orderPick.setDemandedQuantity(resolvedDto.getDemandedQuantity());
             orderPick.setBom(resolvedDto.getBom());
             orderPick.setReturned(false);
+            // 鏂板涓昏褰曘��
             baseMapper.insert(orderPick);
 
+            // 璁板綍鏈棰嗘枡娴佹按锛坆efore=0锛宎fter=鏈棰嗘枡閲忥級銆�
             insertPickRecord(orderPick.getId(),
                     resolvedDto.getProductionOrderId(),
                     resolvedDto.getProductionOperationTaskId(),
@@ -95,8 +102,12 @@
     @Override
     @Transactional(rollbackFor = Exception.class)
     public Boolean updatePick(ProductionOrderPickDto dto) {
+        // 棰嗘枡鏇存柊鍏ュ彛锛堝悓鎺ュ彛鍏煎涓夌被涓氬姟锛夛細
+        // 1) 鏅�氶鏂欐敼閲�/澧炲垹锛�
+        // 2) 琛ユ枡锛坧ickType=2锛夛紱
+        // 3) 閫�鏂欙紙returned=true锛夈��
         if (dto == null) {
-            throw new ServiceException("鍙樻洿鍙傛暟涓嶈兘涓虹┖");
+            throw new ServiceException("鍙傛暟涓嶈兘涓虹┖");
         }
         Long productionOrderId = resolveProductionOrderId(dto);
         if (productionOrderId == null) {
@@ -107,26 +118,32 @@
             throw new ServiceException("鐢熶骇璁㈠崟涓嶅瓨鍦�");
         }
 
+        // 鏌ヨ璁㈠崟涓嬬幇鏈夐鏂欒褰曞苟鏋勫缓ID绱㈠紩銆�
         List<ProductionOrderPick> existingPickList = baseMapper.selectList(
                 Wrappers.<ProductionOrderPick>lambdaQuery()
                         .eq(ProductionOrderPick::getProductionOrderId, productionOrderId));
+        // 杞垚Map渚夸簬鍚庣画鎸塈D蹇�熸牎楠屼笌鏇存柊銆�
         Map<Long, ProductionOrderPick> existingPickMap = existingPickList.stream()
                 .filter(item -> item.getId() != null)
                 .collect(Collectors.toMap(ProductionOrderPick::getId, Function.identity(), (a, b) -> a));
 
+        // 琛ユ枡璇锋眰鍗曠嫭璧拌ˉ鏂欏垎鏀��
         if (isFeedingRequest(dto)) {
             processFeedingPickItems(dto, existingPickMap, productionOrderId);
             return true;
         }
+        // 閫�鏂欒姹傚崟鐙蛋閫�鏂欏垎鏀��
         if (isReturnRequest(dto)) {
             processReturnPickItems(dto, existingPickMap, productionOrderId);
             return true;
         }
 
+        // 鏅�氭洿鏂板満鏅厛澶勭悊鏄惧紡鍒犻櫎銆�
         processDeletePickIds(dto, existingPickMap, productionOrderId);
 
         List<ProductionOrderPickDto> pickItems = resolveUpdateItems(dto);
         Set<Long> keepPickIdSet = new HashSet<>();
+        // keepPickIdSet 鐢ㄤ簬鏍囪鏈鍓嶇浠嶇劧淇濈暀鐨勬棫璁板綍锛屽悗缁敤浜庤瘑鍒�滄湭鍥炰紶鍗冲垹闄も�濈殑琛屻��
         for (int i = 0; i < pickItems.size(); i++) {
             int rowNo = i + 1;
             ProductionOrderPickDto resolvedDto = mergeDto(dto, pickItems.get(i));
@@ -145,12 +162,14 @@
             keepPickIdSet.add(resolvedDto.getId());
             updateExistingPick(resolvedDto, rowNo, existingPickMap);
         }
+        // 娓呯悊鍓嶇鏈洖浼犳棫琛屽苟鍥炶ˉ搴撳瓨銆�
         processMissingPickItems(dto, existingPickMap, productionOrderId, keepPickIdSet);
         return true;
     }
 
     @Override
     public List<ProductionOrderPickVo> listPickedDetail(Long productionOrderId) {
+        // 鏌ヨ璁㈠崟棰嗘枡鏄庣粏锛屽苟琛ラ綈鎵规灞曠ず瀛楁銆�
         if (productionOrderId == null) {
             return Collections.emptyList();
         }
@@ -163,6 +182,11 @@
     private void processDeletePickIds(ProductionOrderPickDto rootDto,
                                       Map<Long, ProductionOrderPick> existingPickMap,
                                       Long productionOrderId) {
+        // 澶勭悊鍓嶇鏄惧紡鍒犻櫎ID锛�
+        // 1) 鏍¢獙鍒犻櫎鐩爣鏄惁灞炰簬褰撳墠璁㈠崟锛�
+        // 2) 鍥炶ˉ搴撳瓨锛�
+        // 3) 鍒犻櫎涓昏褰曪紱
+        // 4) 璁板綍鍒犻櫎娴佹按銆�
         if (rootDto.getDeletePickIds() == null || rootDto.getDeletePickIds().isEmpty()) {
             return;
         }
@@ -173,14 +197,14 @@
             }
             ProductionOrderPick existingPick = existingPickMap.get(deleteId);
             if (existingPick == null || !Objects.equals(existingPick.getProductionOrderId(), productionOrderId)) {
-                throw new ServiceException("瑕佸垹闄ょ殑棰嗘枡璁板綍涓嶅瓨鍦ㄦ垨涓嶅睘浜庡綋鍓嶈鍗曪紝ID=" + deleteId);
+                throw new ServiceException("鍒犻櫎澶辫触锛氶鏂欒褰曚笉瀛樺湪鎴栦笉灞炰簬褰撳墠璁㈠崟锛孖D=" + deleteId);
             }
             String oldBatchNo = resolveInventoryBatchNoFromStored(existingPick.getBatchNo());
             BigDecimal oldQuantity = defaultDecimal(existingPick.getQuantity());
             addInventory(existingPick.getProductModelId(), oldBatchNo, oldQuantity);
             int affected = baseMapper.deleteById(deleteId);
             if (affected <= 0) {
-                throw new ServiceException("鍒犻櫎棰嗘枡澶辫触锛孖D=" + deleteId);
+                throw new ServiceException("鍒犻櫎棰嗘枡璁板綍澶辫触锛孖D=" + deleteId);
             }
             insertPickRecord(existingPick.getId(),
                     existingPick.getProductionOrderId(),
@@ -201,6 +225,9 @@
                                          Map<Long, ProductionOrderPick> existingPickMap,
                                          Long productionOrderId,
                                          Set<Long> keepPickIdSet) {
+        // 澶勭悊鈥滃墠绔湭鍥炰紶鈥濈殑鏃ц锛�
+        // 瀵瑰簲鍦烘櫙鏄敤鎴峰湪鍓嶇鍒犻櫎琛屼絾鏈斁鍏� deletePickIds銆�
+        // 杩欓噷鍏滃簳璇嗗埆骞舵墽琛屽洖琛ュ簱瀛� + 鍒犻櫎涓昏褰� + 鍐欐祦姘淬��
         if (rootDto.getPickList() == null) {
             return;
         }
@@ -216,7 +243,7 @@
             addInventory(missingPick.getProductModelId(), oldBatchNo, oldQuantity);
             int affected = baseMapper.deleteById(missingPick.getId());
             if (affected <= 0) {
-                throw new ServiceException("鍒犻櫎棰嗘枡澶辫触锛孖D=" + missingPick.getId());
+                throw new ServiceException("鍒犻櫎鏈洖浼犻鏂欒褰曞け璐ワ紝ID=" + missingPick.getId());
             }
             insertPickRecord(missingPick.getId(),
                     missingPick.getProductionOrderId(),
@@ -234,6 +261,7 @@
     }
 
     private void addNewPickInUpdate(ProductionOrderPickDto dto, int rowNo) {
+        // 鏇存柊鍦烘櫙涓嬫柊澧炰竴鏉¢鏂欙細鎵e簱瀛� -> 鏂板涓昏褰� -> 鍐欐祦姘淬��
         List<String> batchNoList = resolveBatchNoList(dto);
         String inventoryBatchNo = pickInventoryBatchNo(batchNoList);
         String storedBatchNo = formatBatchNoStorage(batchNoList);
@@ -268,6 +296,8 @@
     private void processFeedingPickItems(ProductionOrderPickDto rootDto,
                                          Map<Long, ProductionOrderPick> existingPickMap,
                                          Long productionOrderId) {
+        // 琛ユ枡娴佺▼鍏ュ彛锛�
+        // 閫愯鏍¢獙琛ユ枡鍙傛暟锛屾牎楠屽師棰嗘枡褰掑睘锛屽啀鎵ц琛ユ枡搴撳瓨鎵e噺鍜屼富璁板綍鍥炲啓銆�
         List<ProductionOrderPickDto> pickItems = resolveUpdateItems(rootDto);
         for (int i = 0; i < pickItems.size(); i++) {
             int rowNo = i + 1;
@@ -276,7 +306,7 @@
                 continue;
             }
             if (!isFeedingPick(resolvedDto)) {
-                throw new ServiceException("琛ユ枡璇锋眰涓殑棰嗘枡绫诲瀷蹇呴』鍏ㄩ儴涓�2");
+                throw new ServiceException("琛ユ枡璇锋眰涓瓨鍦ㄩ潪琛ユ枡绫诲瀷鏁版嵁");
             }
             if (resolvedDto.getProductionOrderId() == null) {
                 resolvedDto.setProductionOrderId(productionOrderId);
@@ -285,15 +315,20 @@
 
             ProductionOrderPick oldPick = existingPickMap.get(resolvedDto.getId());
             if (oldPick == null || !Objects.equals(oldPick.getProductionOrderId(), productionOrderId)) {
-                throw new ServiceException("绗�" + rowNo + "鏉¢鏂欒褰曚笉瀛樺湪鎴栦笉灞炰簬褰撳墠璁㈠崟");
+                throw new ServiceException("绗�" + rowNo + "琛岃ˉ鏂欏け璐ワ細鏈壘鍒板搴旂殑棰嗘枡璁板綍");
             }
             addFeedingPick(resolvedDto, oldPick, rowNo);
         }
     }
 
     private void addFeedingPick(ProductionOrderPickDto dto, ProductionOrderPick oldPick, int rowNo) {
+        // 琛ユ枡鏍稿績锛�
+        // 1) 鏍¢獙瑙勬牸涓�鑷达紱
+        // 2) 鎵e噺琛ユ枡搴撳瓨锛�
+        // 3) 鍐欒ˉ鏂欐祦姘达紱
+        // 4) 鍥炲啓涓诲崟绱琛ユ枡閲忓拰瀹為檯閲忋��
         if (dto.getProductModelId() != null && !Objects.equals(dto.getProductModelId(), oldPick.getProductModelId())) {
-            throw new ServiceException("绗�" + rowNo + "鏉¤ˉ鏂欎骇鍝佽鏍间笌棰嗘枡璁板綍涓嶄竴鑷�");
+            throw new ServiceException("绗�" + rowNo + "琛岃ˉ鏂欏け璐ワ細浜у搧瑙勬牸涓庡師棰嗘枡璁板綍涓嶄竴鑷�");
         }
         Long productModelId = oldPick.getProductModelId();
         List<String> batchNoList = resolveBatchNoList(dto);
@@ -304,6 +339,7 @@
 
         subtractInventory(productModelId, inventoryBatchNo, feedingQuantity, rowNo);
 
+        // 璁$畻琛ユ枡鍓嶅悗鏁伴噺骞跺啓琛ユ枡娴佹按銆�
         BigDecimal beforeFeedingQty = sumFeedingQuantity(dto.getProductionOrderId(), oldPick.getId());
         BigDecimal afterFeedingQty = beforeFeedingQty.add(feedingQuantity);
         insertPickRecord(oldPick.getId(),
@@ -322,9 +358,10 @@
         updatePick.setId(oldPick.getId());
         updatePick.setFeedingQty(afterFeedingQty);
         updatePick.setActualQty(calculateActualQty(oldPick, afterFeedingQty));
+        // 鍥炲啓涓昏褰曠殑琛ユ枡绱鍊间笌瀹為檯鐢ㄩ噺銆�
         int affected = baseMapper.updateById(updatePick);
         if (affected <= 0) {
-            throw new ServiceException("绗�" + rowNo + "鏉¤ˉ鏂欐�婚噺鏇存柊澶辫触");
+            throw new ServiceException("绗�" + rowNo + "琛岃ˉ鏂欏け璐ワ細鏇存柊棰嗘枡涓昏褰曞け璐�");
         }
         oldPick.setFeedingQty(afterFeedingQty);
         oldPick.setActualQty(updatePick.getActualQty());
@@ -333,6 +370,8 @@
     private void processReturnPickItems(ProductionOrderPickDto rootDto,
                                         Map<Long, ProductionOrderPick> existingPickMap,
                                         Long productionOrderId) {
+        // 閫�鏂欐祦绋嬪叆鍙o細
+        // 閫愯鏍¢獙閫�鏂欏弬鏁颁笌棰嗘枡褰掑睘锛屽啀鏇存柊閫�鏂欓噺涓庡疄闄呴噺瀛楁銆�
         List<ProductionOrderPickDto> pickItems = resolveUpdateItems(rootDto);
         for (int i = 0; i < pickItems.size(); i++) {
             int rowNo = i + 1;
@@ -347,13 +386,14 @@
 
             ProductionOrderPick oldPick = existingPickMap.get(resolvedDto.getId());
             if (oldPick == null || !Objects.equals(oldPick.getProductionOrderId(), productionOrderId)) {
-                throw new ServiceException("绗�" + rowNo + "鏉¢鏂欒褰曚笉瀛樺湪鎴栦笉灞炰簬褰撳墠璁㈠崟");
+                throw new ServiceException("绗�" + rowNo + "琛岄��鏂欏け璐ワ細鏈壘鍒板搴旂殑棰嗘枡璁板綍");
             }
             updateReturnPick(resolvedDto, oldPick, rowNo);
         }
     }
 
     private void updateReturnPick(ProductionOrderPickDto dto, ProductionOrderPick oldPick, int rowNo) {
+        // 閫�鏂欐洿鏂板彧鏀逛富棰嗘枡璁板綍涓殑閫�鏂欏瓧娈典笌瀹為檯閲忋��
         ProductionOrderPick updatePick = new ProductionOrderPick();
         updatePick.setId(oldPick.getId());
         updatePick.setReturnQty(dto.getReturnQty());
@@ -361,7 +401,7 @@
         updatePick.setReturned(true);
         int affected = baseMapper.updateById(updatePick);
         if (affected <= 0) {
-            throw new ServiceException("绗�" + rowNo + "鏉¢��鏂欎俊鎭洿鏂板け璐�");
+            throw new ServiceException("绗�" + rowNo + "琛岄��鏂欏け璐ワ細鏇存柊棰嗘枡涓昏褰曞け璐�");
         }
         oldPick.setReturnQty(updatePick.getReturnQty());
         oldPick.setActualQty(updatePick.getActualQty());
@@ -371,9 +411,14 @@
     private void updateExistingPick(ProductionOrderPickDto dto,
                                     int rowNo,
                                     Map<Long, ProductionOrderPick> existingPickMap) {
+        // 鏅�氭洿鏂板崟琛屾牳蹇冩祦绋嬶細
+        // 1) 鏍¢獙鏃ц褰曞瓨鍦ㄤ笖灞炰簬褰撳墠璁㈠崟锛�
+        // 2) 姣旇緝鏂版棫鈥滆鏍�+鎵规鈥濓紝鍐冲畾搴撳瓨澶勭悊绛栫暐锛�
+        // 3) 鏇存柊涓昏褰曪紱
+        // 4) 鍐欏彉鏇存祦姘达紙璁板綍鍓嶅悗鏁伴噺鍙樺寲锛夈��
         ProductionOrderPick oldPick = existingPickMap.get(dto.getId());
         if (oldPick == null || !Objects.equals(oldPick.getProductionOrderId(), dto.getProductionOrderId())) {
-            throw new ServiceException("绗�" + rowNo + "鏉¢鏂欒褰曚笉瀛樺湪鎴栦笉灞炰簬褰撳墠璁㈠崟");
+            throw new ServiceException("绗�" + rowNo + "琛屾洿鏂板け璐ワ細鏈壘鍒板搴旂殑棰嗘枡璁板綍");
         }
 
         Long oldProductModelId = oldPick.getProductModelId();
@@ -386,9 +431,11 @@
         String newStoredBatchNo = formatBatchNoStorage(newBatchNoList);
         BigDecimal newQuantity = dto.getPickQuantity();
 
+        // 鍒ゆ柇瑙勬牸+鎵规鏄惁鍙樺寲锛屽喅瀹氬簱瀛樺鐞嗙瓥鐣ャ��
         boolean sameStockKey = Objects.equals(oldProductModelId, newProductModelId)
                 && Objects.equals(oldBatchNo, newBatchNo);
         if (sameStockKey) {
+            // 瑙勬牸涓庢壒娆′笉鍙橈細鍙寜宸�煎鍑忓簱瀛樸��
             BigDecimal delta = newQuantity.subtract(oldQuantity);
             if (delta.compareTo(BigDecimal.ZERO) > 0) {
                 subtractInventory(newProductModelId, newStoredBatchNo, delta, rowNo);
@@ -396,6 +443,7 @@
                 addInventory(oldProductModelId, oldBatchNo, delta.abs());
             }
         } else {
+            // 瑙勬牸鎴栨壒娆″彉鍖栵細鍏堝洖琛ユ棫搴撳瓨锛屽啀鎵e噺鏂板簱瀛樸��
             addInventory(oldProductModelId, oldBatchNo, oldQuantity);
             subtractInventory(newProductModelId, newStoredBatchNo, newQuantity, rowNo);
         }
@@ -414,9 +462,10 @@
         }
         int affected = baseMapper.updateById(oldPick);
         if (affected <= 0) {
-            throw new ServiceException("绗�" + rowNo + "鏉¢鏂欐洿鏂板け璐�");
+            throw new ServiceException("绗�" + rowNo + "琛屾洿鏂板け璐ワ細鏇存柊棰嗘枡璁板綍澶辫触");
         }
 
+        // 鍐欏叆鏇存柊娴佹按锛屼繚鐣欐湰娆℃暟閲忓彉鍖栬建杩广��
         BigDecimal recordQuantity = sameStockKey ? oldQuantity.subtract(newQuantity).abs() : newQuantity;
         if (recordQuantity.compareTo(BigDecimal.ZERO) > 0 || oldQuantity.compareTo(newQuantity) != 0 || !sameStockKey) {
             insertPickRecord(oldPick.getId(),
@@ -444,6 +493,7 @@
                                   Byte pickType,
                                   String remark,
                                   String feedingReason) {
+        // 鍐欓鏂欐祦姘磋褰曪細缁熶竴璁板綍棰嗘枡/琛ユ枡/閫�鏂欐暟閲忓彉鍖栬建杩广��
         ProductionOrderPickRecord pickRecord = new ProductionOrderPickRecord();
         pickRecord.setPickId(pickId);
         pickRecord.setProductionOrderId(productionOrderId);
@@ -460,7 +510,13 @@
     }
 
     private void subtractInventory(Long productModelId, String batchNo, BigDecimal quantity, int rowNo) {
+        // 鎵e噺搴撳瓨鎬绘祦绋嬶細
+        // 1) 瑙f瀽鎵规鍒楄〃锛�
+        // 2) 璁$畻姣忎釜鎵规鍙敤閲忎笌鎬诲彲鐢ㄩ噺锛�
+        // 3) 鎸夋壒娆¢『搴忛�愮瑪鎵e噺锛岀洿鍒版墸瀹岀洰鏍囨暟閲忥紱
+        // 4) 浠讳竴姝ュけ璐ュ嵆鎶涢敊骞跺洖婊氫簨鍔°��
         BigDecimal deductQuantity = defaultDecimal(quantity);
+        // 棰嗘枡鏁伴噺灏忎簬绛変簬0鏃讹紝涓嶉渶瑕佹墽琛屽簱瀛樻墸鍑忋��
         if (deductQuantity.compareTo(BigDecimal.ZERO) <= 0) {
             return;
         }
@@ -470,9 +526,12 @@
             batchNoList = Collections.singletonList(null);
         }
 
+        // 鍏堣绠楀悇鎵规鍙敤閲忥紝閬垮厤杈规墸杈圭畻瀵艰嚧鍒ゆ柇涓嶄竴鑷淬��
         Map<String, BigDecimal> availableQuantityMap = new LinkedHashMap<>();
         BigDecimal totalAvailableQuantity = BigDecimal.ZERO;
+        // 閬嶅巻鎵规锛岃绠楁瘡涓壒娆″彲鐢ㄥ簱瀛樸��
         for (String currentBatchNo : batchNoList) {
+            // 鏌ヨ褰撳墠瑙勬牸+鎵规鐨勫簱瀛樿褰曘��
             StockInventory stockInventory = stockInventoryMapper.selectOne(buildStockWrapper(productModelId, currentBatchNo));
             BigDecimal availableQuantity = BigDecimal.ZERO;
             if (stockInventory != null) {
@@ -488,10 +547,11 @@
 
         if (deductQuantity.compareTo(totalAvailableQuantity) > 0) {
             BigDecimal shortQuantity = deductQuantity.subtract(totalAvailableQuantity);
-            throw new ServiceException("棰嗘枡鍙敤搴撳瓨涓嶈冻锛屽彲鐢ㄥ簱瀛樹负" + formatQuantity(totalAvailableQuantity)
-                    + "锛岃繕宸�" + formatQuantity(shortQuantity));
+            throw new ServiceException("绗�" + rowNo + "琛屾墸鍑忓簱瀛樺け璐ワ細鍙敤搴撳瓨涓嶈冻锛屽綋鍓嶅彲鐢�"
+                    + formatQuantity(totalAvailableQuantity) + "锛屼粛缂哄皯" + formatQuantity(shortQuantity));
         }
 
+        // 鎸夋壒娆¢『搴忛�愮瑪鎵e噺搴撳瓨銆�
         BigDecimal remainingQuantity = deductQuantity;
         for (Map.Entry<String, BigDecimal> entry : availableQuantityMap.entrySet()) {
             if (remainingQuantity.compareTo(BigDecimal.ZERO) <= 0) {
@@ -508,17 +568,18 @@
             stockInventoryDto.setQualitity(currentDeductQuantity);
             int affected = stockInventoryMapper.updateSubtractStockInventory(stockInventoryDto);
             if (affected <= 0) {
-                throw new ServiceException("绗�" + rowNo + "鏉¢鏂欐墸鍑忓簱瀛樺け璐�");
+                throw new ServiceException("绗�" + rowNo + "琛屾墸鍑忓簱瀛樺け璐ワ細搴撳瓨鏇存柊澶辫触");
             }
             remainingQuantity = remainingQuantity.subtract(currentDeductQuantity);
         }
 
         if (remainingQuantity.compareTo(BigDecimal.ZERO) > 0) {
-            throw new ServiceException("绗�" + rowNo + "鏉¢鏂欐墸鍑忓簱瀛樺け璐ワ紝鍓╀綑寰呮墸鍑忔暟閲忎负" + formatQuantity(remainingQuantity));
+            throw new ServiceException("绗�" + rowNo + "琛屾墸鍑忓簱瀛樺け璐ワ細浠嶆湁鏈墸鍑忔暟閲�" + formatQuantity(remainingQuantity));
         }
     }
 
     private void addInventory(Long productModelId, String batchNo, BigDecimal quantity) {
+        // 鍥炶ˉ搴撳瓨锛堢敤浜庡垹闄ら鏂欍�佹敼灏忛鏂欍�佸垏鎹㈡壒娆$瓑鍦烘櫙锛夈��
         BigDecimal addQuantity = defaultDecimal(quantity);
         if (addQuantity.compareTo(BigDecimal.ZERO) <= 0) {
             return;
@@ -533,8 +594,9 @@
     }
 
     private List<ProductionOrderPickDto> resolvePickItems(ProductionOrderPickDto dto) {
+        // 瑙f瀽鏂板鍦烘櫙鐨勯鏂欐槑缁嗛泦鍚堛��
         if (dto == null) {
-            throw new ServiceException("棰嗘枡鍙傛暟涓嶈兘涓虹┖");
+            throw new ServiceException("鍙傛暟涓嶈兘涓虹┖");
         }
         if (dto.getPickList() != null && !dto.getPickList().isEmpty()) {
             return dto.getPickList();
@@ -543,6 +605,7 @@
     }
 
     private List<ProductionOrderPickDto> resolveUpdateItems(ProductionOrderPickDto dto) {
+        // 瑙f瀽鏇存柊鍦烘櫙鐨勯鏂欐槑缁嗛泦鍚堛��
         if (dto.getPickList() != null) {
             return dto.getPickList();
         }
@@ -553,6 +616,7 @@
     }
 
     private boolean isEmptyUpdateItem(ProductionOrderPickDto dto) {
+        // 鍒ゆ柇鏇存柊琛屾槸鍚︿负绌虹櫧鍗犱綅琛屻��
         return dto.getId() == null
                 && dto.getProductModelId() == null
                 && dto.getPickQuantity() == null
@@ -573,6 +637,7 @@
     }
 
     private Long resolveProductionOrderId(ProductionOrderPickDto dto) {
+        // 浼樺厛浠庝富DTO瑙f瀽璁㈠崟ID锛屼笉瀛樺湪鏃跺啀浠庡瓙椤逛腑鍥為��鏌ユ壘銆�
         if (dto.getProductionOrderId() != null) {
             return dto.getProductionOrderId();
         }
@@ -588,7 +653,12 @@
     }
 
     private ProductionOrderPickDto mergeDto(ProductionOrderPickDto rootDto, ProductionOrderPickDto itemDto) {
+        // 鍚堝苟瑙勫垯锛�
+        // - itemDto 浼樺厛鎵胯浇琛岀骇杈撳叆锛�
+        // - itemDto 缂哄け瀛楁浠� rootDto 鍏滃簳缁ф壙锛�
+        // - 杈撳嚭 merged 浣滀负缁熶竴涓氬姟鍏ュ弬銆�
         ProductionOrderPickDto merged = new ProductionOrderPickDto();
+        // 鍏堟嫹璐濊绾у瓧娈点��
         if (itemDto != null) {
             merged.setId(itemDto.getId());
             merged.setProductionOrderId(itemDto.getProductionOrderId());
@@ -667,51 +737,55 @@
     }
 
     private void validatePickParam(ProductionOrderPickDto dto, int rowNo) {
+        // 鏍¢獙鏅�氶鏂欏弬鏁帮紙璁㈠崟銆佽鏍笺�佹暟閲忋�佺被鍨嬶級銆�
         if (dto.getProductionOrderId() == null) {
-            throw new ServiceException("绗�" + rowNo + "鏉$敓浜ц鍗旾D涓嶈兘涓虹┖");
+            throw new ServiceException("绗�" + rowNo + "琛屽弬鏁伴敊璇細鐢熶骇璁㈠崟ID涓嶈兘涓虹┖");
         }
         if (dto.getProductModelId() == null) {
-            throw new ServiceException("绗�" + rowNo + "鏉′骇鍝佽鏍糏D涓嶈兘涓虹┖");
+            throw new ServiceException("绗�" + rowNo + "琛屽弬鏁伴敊璇細浜у搧瑙勬牸涓嶈兘涓虹┖");
         }
         if (dto.getPickQuantity() == null || dto.getPickQuantity().compareTo(BigDecimal.ZERO) < 0) {
-            throw new ServiceException("绗�" + rowNo + "鏉¢鏂欐暟閲忎笉鑳藉皬浜�0");
+            throw new ServiceException("绗�" + rowNo + "琛屽弬鏁伴敊璇細棰嗘枡鏁伴噺涓嶈兘灏忎簬0");
         }
         if (dto.getPickType() != null && dto.getPickType() != PICK_TYPE_NORMAL && dto.getPickType() != PICK_TYPE_FEEDING) {
-            throw new ServiceException("绗�" + rowNo + "鏉¢鏂欑被鍨嬪彧鑳芥槸1鎴�2");
+            throw new ServiceException("绗�" + rowNo + "琛屽弬鏁伴敊璇細棰嗘枡绫诲瀷浠呮敮鎸�1(棰嗘枡)鎴�2(琛ユ枡)");
         }
     }
 
     private void validateFeedingParam(ProductionOrderPickDto dto, int rowNo) {
+        // 鏍¢獙琛ユ枡鍙傛暟锛堣鍗曘�侀鏂橧D銆佽ˉ鏂欐暟閲忋�佺被鍨嬶級銆�
         if (dto.getProductionOrderId() == null) {
-            throw new ServiceException("绗�" + rowNo + "鏉$敓浜ц鍗旾D涓嶈兘涓虹┖");
+            throw new ServiceException("绗�" + rowNo + "琛屽弬鏁伴敊璇細鐢熶骇璁㈠崟ID涓嶈兘涓虹┖");
         }
         if (dto.getId() == null) {
-            throw new ServiceException("绗�" + rowNo + "鏉¢鏂橧D涓嶈兘涓虹┖");
+            throw new ServiceException("绗�" + rowNo + "琛屽弬鏁伴敊璇細棰嗘枡璁板綍ID涓嶈兘涓虹┖");
         }
         if (dto.getFeedingQuantity() == null || dto.getFeedingQuantity().compareTo(BigDecimal.ZERO) < 0) {
-            throw new ServiceException("绗�" + rowNo + "鏉℃湰娆¤ˉ鏂欐暟閲忎笉鑳藉皬浜�0");
+            throw new ServiceException("绗�" + rowNo + "琛屽弬鏁伴敊璇細琛ユ枡鏁伴噺涓嶈兘灏忎簬0");
         }
         if (!isFeedingPick(dto)) {
-            throw new ServiceException("绗�" + rowNo + "鏉¤ˉ鏂欑被鍨嬪繀椤讳负2");
+            throw new ServiceException("绗�" + rowNo + "琛屽弬鏁伴敊璇細琛ユ枡鍦烘櫙涓嬮鏂欑被鍨嬪繀椤讳负2");
         }
     }
 
     private void validateReturnParam(ProductionOrderPickDto dto, int rowNo) {
+        // 鏍¢獙閫�鏂欏弬鏁帮紙璁㈠崟銆侀鏂橧D銆侀��鏂欓噺銆佸疄闄呴噺锛夈��
         if (dto.getProductionOrderId() == null) {
-            throw new ServiceException("绗�" + rowNo + "鏉$敓浜ц鍗旾D涓嶈兘涓虹┖");
+            throw new ServiceException("绗�" + rowNo + "琛屽弬鏁伴敊璇細鐢熶骇璁㈠崟ID涓嶈兘涓虹┖");
         }
         if (dto.getId() == null) {
-            throw new ServiceException("绗�" + rowNo + "鏉¢鏂橧D涓嶈兘涓虹┖");
+            throw new ServiceException("绗�" + rowNo + "琛屽弬鏁伴敊璇細棰嗘枡璁板綍ID涓嶈兘涓虹┖");
         }
         if (dto.getReturnQty() == null || dto.getReturnQty().compareTo(BigDecimal.ZERO) < 0) {
-            throw new ServiceException("绗�" + rowNo + "鏉¢��鏂欐暟閲忎笉鑳戒负绌轰笖涓嶈兘灏忎簬0");
+            throw new ServiceException("绗�" + rowNo + "琛屽弬鏁伴敊璇細閫�鏂欐暟閲忎笉鑳藉皬浜�0");
         }
         if (dto.getActualQty() == null || dto.getActualQty().compareTo(BigDecimal.ZERO) < 0) {
-            throw new ServiceException("绗�" + rowNo + "鏉″疄闄呮暟閲忎笉鑳戒负绌轰笖涓嶈兘灏忎簬0");
+            throw new ServiceException("绗�" + rowNo + "琛屽弬鏁伴敊璇細瀹為檯鏁伴噺涓嶈兘灏忎簬0");
         }
     }
 
     private boolean isFeedingRequest(ProductionOrderPickDto dto) {
+        // 鍒ゆ柇褰撳墠璇锋眰鏄惁灞炰簬琛ユ枡娴佺▼銆�
         if (isFeedingPick(dto)) {
             return true;
         }
@@ -724,10 +798,12 @@
     }
 
     private boolean isFeedingPick(ProductionOrderPickDto dto) {
+        // 鍒ゆ柇褰撳墠琛屾槸鍚︿负琛ユ枡绫诲瀷銆�
         return dto != null && Objects.equals(dto.getPickType(), PICK_TYPE_FEEDING);
     }
 
     private boolean isReturnRequest(ProductionOrderPickDto dto) {
+        // 鍒ゆ柇褰撳墠璇锋眰鏄惁灞炰簬閫�鏂欐祦绋嬨��
         if (isReturnPick(dto)) {
             return true;
         }
@@ -740,10 +816,12 @@
     }
 
     private boolean isReturnPick(ProductionOrderPickDto dto) {
+        // 鍒ゆ柇褰撳墠琛屾槸鍚︿负閫�鏂欑被鍨嬨��
         return dto != null && Boolean.TRUE.equals(dto.getReturned());
     }
 
     private BigDecimal sumFeedingQuantity(Long productionOrderId, Long pickId) {
+        // 姹囨�绘寚瀹氶鏂欏崟鐨勫巻鍙茶ˉ鏂欐�婚噺銆�
         List<ProductionOrderPickRecord> feedingRecords = productionOrderPickRecordMapper.selectList(
                 Wrappers.<ProductionOrderPickRecord>lambdaQuery()
                         .eq(ProductionOrderPickRecord::getProductionOrderId, productionOrderId)
@@ -756,12 +834,14 @@
     }
 
     private BigDecimal calculateActualQty(ProductionOrderPick pick, BigDecimal feedingQty) {
+        // 鎸夆�滈鏂�+琛ユ枡-閫�鏂欌�濊绠楀疄闄呯敤閲忋��
         return defaultDecimal(pick.getQuantity())
                 .add(defaultDecimal(feedingQty))
                 .subtract(defaultDecimal(pick.getReturnQty()));
     }
 
     private String normalizeBatchNo(String batchNo) {
+        // 鏍囧噯鍖栨壒娆″彿锛堝幓绌虹櫧銆佺┖涓茶浆null锛夈��
         if (StringUtils.isEmpty(batchNo)) {
             return null;
         }
@@ -769,6 +849,7 @@
         return trimBatchNo.isEmpty() ? null : trimBatchNo;
     }
     private List<String> resolveBatchNoList(ProductionOrderPickDto dto) {
+        // 浼樺厛瑙f瀽 batchNoList锛岀┖鍒欏洖閫�瑙f瀽 batchNo 瀛楃涓层��
         List<String> normalizedBatchNoList = normalizeBatchNoList(dto.getBatchNoList());
         if (!normalizedBatchNoList.isEmpty()) {
             return normalizedBatchNoList;
@@ -777,6 +858,7 @@
     }
 
     private String pickInventoryBatchNo(List<String> batchNoList) {
+        // 浠庢壒娆¢泦鍚堜腑鍙栧簱瀛樻墸鍑忎娇鐢ㄧ殑鎵规銆�
         if (batchNoList == null || batchNoList.isEmpty()) {
             return null;
         }
@@ -784,10 +866,12 @@
     }
 
     private String resolveInventoryBatchNoFromStored(String storedBatchNo) {
+        // 浠庢暟鎹簱瀛樺偍鎵规瀛楁涓弽瑙e彲鐢ㄦ壒娆°��
         return pickInventoryBatchNo(parseBatchNoValue(storedBatchNo));
     }
 
     private String formatBatchNoStorage(List<String> batchNoList) {
+        // 灏嗘壒娆¢泦鍚堟牸寮忓寲涓烘暟鎹簱瀛樺偍鍊笺��
         if (batchNoList == null || batchNoList.isEmpty()) {
             return null;
         }
@@ -798,6 +882,7 @@
     }
 
     private List<String> normalizeBatchNoList(List<String> batchNoList) {
+        // 鎵归噺鏍囧噯鍖栨壒娆″彿骞跺幓閲嶃��
         if (batchNoList == null || batchNoList.isEmpty()) {
             return Collections.emptyList();
         }
@@ -812,6 +897,7 @@
     }
 
     private void fillBatchNoList(List<ProductionOrderPickVo> detailList) {
+        // 灏嗗悓璁㈠崟+鍚岃鏍�+鍚屽伐搴忕殑鏁版嵁鎸夌粍鑱氬悎鎵规锛屼究浜庡墠绔粺涓�灞曠ず銆�
         if (detailList == null || detailList.isEmpty()) {
             return;
         }
@@ -832,9 +918,11 @@
     }
 
     private void fillSelectableBatchNoList(List<ProductionOrderPickVo> detailList) {
+        // 鍚堝苟鈥滃凡閫夋壒娆♀�濆拰鈥滃簱瀛樺彲閫夋壒娆♀�濓紝鐢ㄤ簬鍓嶇涓嬫媺銆�
         if (detailList == null || detailList.isEmpty()) {
             return;
         }
+        // 鍏堟敹闆嗘槑缁嗕腑娑夊強鐨勮鏍糏D锛屾壒閲忔煡璇㈠簱瀛樻壒娆°��
         Set<Long> productModelIdSet = detailList.stream()
                 .map(ProductionOrderPickVo::getProductModelId)
                 .filter(Objects::nonNull)
@@ -868,30 +956,35 @@
     }
 
     private String buildBatchNoGroupKey(ProductionOrderPickVo detail) {
-        return String.valueOf(detail.getProductionOrderId()) + "|"
-                + String.valueOf(detail.getProductModelId()) + "|"
-                + String.valueOf(detail.getTechnologyOperationId()) + "|"
-                + String.valueOf(detail.getOperationName());
+        // 鏋勫缓鎵规鑱氬悎鍒嗙粍閿��
+        return detail.getProductionOrderId() + "|"
+                + detail.getProductModelId() + "|"
+                + detail.getTechnologyOperationId() + "|"
+                + detail.getOperationName();
     }
 
     private List<String> parseBatchNoValue(String rawBatchNoValue) {
+        // 鎵规瑙f瀽鍏煎涓夌鏍煎紡锛�
+        // 1) 鍗曞�硷細A001
+        // 2) 閫楀彿鍒嗛殧锛欰001,A002
+        // 3) 绫籎SON鏁扮粍瀛楃涓诧細["A001","A002"]
         String normalizedValue = normalizeBatchNo(rawBatchNoValue);
         if (StringUtils.isEmpty(normalizedValue)) {
             return Collections.emptyList();
         }
-        if (normalizedValue.startsWith("[") && normalizedValue.endsWith("]")) {
+        if (normalizedValue != null && normalizedValue.startsWith("[") && normalizedValue.endsWith("]")) {
             String value = normalizedValue.substring(1, normalizedValue.length() - 1);
             if (StringUtils.isEmpty(value)) {
                 return Collections.emptyList();
             }
             List<String> parsed = Arrays.stream(value.split(","))
-                    .map(item -> item == null ? null : item.trim().replace("\"", "").replace("'", ""))
+                    .map(item -> item.trim().replace("\"", "").replace("'", ""))
                     .collect(Collectors.toList());
             return normalizeBatchNoList(parsed);
         }
-        if (normalizedValue.contains(",")) {
+        if (normalizedValue != null && normalizedValue.contains(",")) {
             List<String> parsed = Arrays.stream(normalizedValue.split(","))
-                    .map(item -> item == null ? null : item.trim())
+                    .map(item -> item.trim())
                     .collect(Collectors.toList());
             return normalizeBatchNoList(parsed);
         }
@@ -899,6 +992,7 @@
     }
 
     private LambdaQueryWrapper<StockInventory> buildStockWrapper(Long productModelId, String batchNo) {
+        // 鏋勫缓搴撳瓨鏌ヨ鏉′欢锛堣鏍� + 鎵规锛夈��
         LambdaQueryWrapper<StockInventory> wrapper = Wrappers.<StockInventory>lambdaQuery()
                 .eq(StockInventory::getProductModelId, productModelId);
         if (StringUtils.isEmpty(batchNo)) {
@@ -910,10 +1004,12 @@
     }
 
     private BigDecimal defaultDecimal(BigDecimal value) {
+        // BigDecimal 绌哄�煎厹搴曪紝缁熶竴鎸�0澶勭悊銆�
         return value == null ? BigDecimal.ZERO : value;
     }
 
     private String formatQuantity(BigDecimal value) {
+        // 鏁伴噺鏍煎紡鍖栬緭鍑猴紙鍘婚櫎鏈熬鏃犳晥0锛夈��
         return defaultDecimal(value).stripTrailingZeros().toPlainString();
     }
 }
diff --git a/src/main/java/com/ruoyi/production/service/impl/ProductionOrderRoutingOperationParamServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/ProductionOrderRoutingOperationParamServiceImpl.java
index a99b194..d66ebc7 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductionOrderRoutingOperationParamServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionOrderRoutingOperationParamServiceImpl.java
@@ -48,17 +48,20 @@
 
     @Override
     public List<ProductionOrderRoutingOperationParamVo> listProductionOrderRoutingOperationParam(ProductionOrderRoutingOperationParamDto dto) {
+        // 鏌ヨ鐢熶骇璁㈠崟宸ヨ壓璺嚎宸ュ簭鍙傛暟
         return BeanUtil.copyToList(this.list(buildQueryWrapper(dto)), ProductionOrderRoutingOperationParamVo.class);
     }
 
     @Override
     public ProductionOrderRoutingOperationParamVo getProductionOrderRoutingOperationParamInfo(Long id) {
+        // 鑾峰彇鐢熶骇璁㈠崟宸ヨ壓璺嚎宸ュ簭鍙傛暟璇︽儏
         ProductionOrderRoutingOperationParam item = this.getById(id);
         return item == null ? null : BeanUtil.copyProperties(item, ProductionOrderRoutingOperationParamVo.class);
     }
 
     @Override
     public boolean saveProductionOrderRoutingOperationParam(ProductionOrderRoutingOperationParam item) {
+        // 淇濆瓨鐢熶骇璁㈠崟宸ヨ壓璺嚎宸ュ簭鍙傛暟
         ProductionOrderRoutingOperation routingOperation = getRoutingOperation(item.getProductionOrderRoutingOperationId());
         fillFromSourceParam(item, routingOperation);
         validateManualFields(item);
@@ -68,10 +71,12 @@
 
     @Override
     public boolean removeProductionOrderRoutingOperationParam(Long id) {
+        // 鍒犻櫎鐢熶骇璁㈠崟宸ヨ壓璺嚎宸ュ簭鍙傛暟
         return this.removeById(id);
     }
 
     private LambdaQueryWrapper<ProductionOrderRoutingOperationParam> buildQueryWrapper(ProductionOrderRoutingOperationParamDto dto) {
+        // 鎸夋潯浠跺姩鎬佹瀯寤烘暟鎹簱鏌ヨ鏉′欢
         ProductionOrderRoutingOperationParam query = dto == null ? new ProductionOrderRoutingOperationParam() : dto;
         return Wrappers.<ProductionOrderRoutingOperationParam>lambdaQuery()
                 .eq(query.getId() != null, ProductionOrderRoutingOperationParam::getId, query.getId())
@@ -96,29 +101,31 @@
     }
 
     private ProductionOrderRoutingOperation getRoutingOperation(Long productionOrderRoutingOperationId) {
+        // 鑾峰彇宸ヨ壓璺嚎宸ュ簭
         if (productionOrderRoutingOperationId == null) {
-            throw new ServiceException("productionOrderRoutingOperationId is required");
+            throw new ServiceException("鐢熶骇璁㈠崟宸ヨ壓璺嚎宸ュ簭ID涓嶈兘涓虹┖");
         }
         ProductionOrderRoutingOperation routingOperation = productionOrderRoutingOperationMapper.selectById(productionOrderRoutingOperationId);
         if (routingOperation == null) {
-            throw new ServiceException("Production order routing operation not found");
+            throw new ServiceException("鐢熶骇璁㈠崟宸ヨ壓璺嚎宸ュ簭涓嶅瓨鍦�");
         }
         return routingOperation;
     }
 
     private void fillFromSourceParam(ProductionOrderRoutingOperationParam item, ProductionOrderRoutingOperation routingOperation) {
+        // 浠庢潵婧愬弬鏁板洖濉綋鍓嶅弬鏁伴粯璁ゅ��
         item.setProductionOrderId(routingOperation.getProductionOrderId());
         item.setProductionOrderRoutingOperationId(routingOperation.getId());
         ProductionOrder productionOrder = productionOrderMapper.selectById(routingOperation.getProductionOrderId());
         if (productionOrder == null) {
-            throw new ServiceException("Production order not found");
+            throw new ServiceException("鐢熶骇璁㈠崟涓嶅瓨鍦�");
         }
         if (item.getParamId() == null) {
             return;
         }
         TechnologyParam sourceParam = technologyParamMapper.selectById(item.getParamId());
         if (sourceParam == null) {
-            throw new ServiceException("Technology  param not found");
+            throw new ServiceException("宸ヨ壓鍙傛暟涓嶅瓨鍦�");
         }
         if (item.getTechnologyOperationParamId() != null) {
             TechnologyRoutingOperationParam sourceRoutingOperationParam = technologyRoutingOperationParamMapper.selectById(item.getTechnologyOperationParamId());
@@ -141,15 +148,17 @@
     }
 
     private void validateManualFields(ProductionOrderRoutingOperationParam item) {
+        // 鏍¢獙鎵嬪伐褰曞叆瀛楁鐨勫繀濉笌鏍煎紡
         if (item.getParamCode() == null || item.getParamCode().trim().isEmpty()) {
-            throw new ServiceException("paramCode is required");
+            throw new ServiceException("鍙傛暟缂栫爜涓嶈兘涓虹┖");
         }
         if (item.getParamName() == null || item.getParamName().trim().isEmpty()) {
-            throw new ServiceException("paramName is required");
+            throw new ServiceException("鍙傛暟鍚嶇О涓嶈兘涓虹┖");
         }
     }
 
     private void checkDuplicate(ProductionOrderRoutingOperationParam item) {
+        // 妫�鏌ユ暟鎹槸鍚﹂噸澶嶏紝閬垮厤閲嶅淇濆瓨
         boolean duplicate = productionOrderRoutingOperationParamMapper.selectCount(
                 Wrappers.<ProductionOrderRoutingOperationParam>lambdaQuery()
                         .isNull(ProductionOrderRoutingOperationParam::getProductionProductMainId)
@@ -161,7 +170,7 @@
                         .ne(item.getId() != null, ProductionOrderRoutingOperationParam::getId, item.getId())
         ) > 0;
         if (duplicate) {
-            throw new ServiceException("Duplicate production order routing operation param");
+            throw new ServiceException("鐢熶骇璁㈠崟宸ヨ壓璺嚎宸ュ簭鍙傛暟閲嶅");
         }
     }
 }
diff --git a/src/main/java/com/ruoyi/production/service/impl/ProductionOrderRoutingOperationServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/ProductionOrderRoutingOperationServiceImpl.java
index 886da11..3d16a07 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductionOrderRoutingOperationServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionOrderRoutingOperationServiceImpl.java
@@ -45,12 +45,15 @@
 
     @Override
     public R addRouteItem(ProductionOrderRoutingOperation productionOrderRoutingOperation) {
+        // 鏂板宸ヨ壓璺嚎
         int insert = productionOrderRoutingOperationMapper.insert(productionOrderRoutingOperation);
         //宸ュ簭鍏宠仈鐨勫弬鏁伴渶瑕佸悓姝ユ柊澧�
         List<TechnologyOperationParam> technologyOperationParams = technologyOperationParamMapper.selectList(Wrappers.<TechnologyOperationParam>lambdaQuery()
                 .eq(TechnologyOperationParam::getTechnologyOperationId, productionOrderRoutingOperation.getTechnologyOperationId()));
+        // 鍙傛暟涓庡墠缃潯浠舵牎楠�
         if (CollectionUtils.isNotEmpty(technologyOperationParams)){
             ArrayList<ProductionOrderRoutingOperationParam> productionOrderRoutingOperationParams = new ArrayList<>();
+        // 閬嶅巻澶勭悊鏁版嵁骞剁粍瑁呯粨鏋�
             for (TechnologyOperationParam technologyOperationParam : technologyOperationParams) {
                 TechnologyParam technologyParam = technologyParamMapper.selectById(technologyOperationParam.getTechnologyParamId());
                 ProductionOrderRoutingOperationParam productionOrderRoutingOperationParam = new ProductionOrderRoutingOperationParam();
@@ -103,11 +106,14 @@
 
     @Override
     public R deleteRouteItem(Long id) {
+        // 鍒犻櫎宸ヨ壓璺嚎
         try {
+        // 鏌ヨ骞跺噯澶囦笟鍔℃暟鎹�
             ProductionOperationTask productionOperationTask = productionOperationTaskMapper.selectOne(
                     new LambdaQueryWrapper<ProductionOperationTask>()
                             .eq(ProductionOperationTask::getProductionOrderRoutingOperationId, id)
                             .last("limit 1"));
+        // 鍙傛暟涓庡墠缃潯浠舵牎楠�
             if (productionOperationTask == null) {
                 throw new RuntimeException("鍒犻櫎澶辫触锛氭湭鎵惧埌鍏宠仈鐨勭敓浜у伐鍗�");
             }
@@ -118,6 +124,7 @@
             List<ProductionProductMain> productionProductMains = productionProductMainMapper.selectList(
                     new LambdaQueryWrapper<ProductionProductMain>()
                             .eq(ProductionProductMain::getProductionOperationTaskId, productionOperationTask.getId()));
+        // 閬嶅巻澶勭悊鏁版嵁骞剁粍瑁呯粨鏋�
             for (ProductionProductMain main : productionProductMains) {
                 productionProductMainService.removeProductMain(main.getId());
             }
@@ -140,6 +147,7 @@
                     ProductionOrderRoutingOperation item = operationList.get(i);
                     if (!Integer.valueOf(i + 1).equals(item.getDragSort())) {
                         item.setDragSort(i + 1);
+        // 鎸佷箙鍖栨垨杈撳嚭澶勭悊缁撴灉
                         productionOrderRoutingOperationMapper.updateById(item);
                     }
                 }
@@ -152,6 +160,7 @@
 
     @Override
     public int sortRouteItem(ProductionOrderRoutingOperation productionOrderRoutingOperation) {
+        // 鎺掑簭宸ヨ壓璺嚎
         ProductionOrderRoutingOperation oldItem = productionOrderRoutingOperationMapper.selectById(productionOrderRoutingOperation.getId());
         List<ProductionOrderRoutingOperation> operationList = productionOrderRoutingOperationMapper.selectList(
                 Wrappers.<ProductionOrderRoutingOperation>lambdaQuery()
diff --git a/src/main/java/com/ruoyi/production/service/impl/ProductionOrderRoutingServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/ProductionOrderRoutingServiceImpl.java
index 10443c1..0ffb34f 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductionOrderRoutingServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionOrderRoutingServiceImpl.java
@@ -21,6 +21,7 @@
 
     @Override
     public ProductionOrderRouting listMain(Long orderId) {
+        // 鏌ヨ涓昏〃ID闆嗗悎
         return productionOrderRoutingMapper.selectOne(
                 Wrappers.<ProductionOrderRouting>lambdaQuery()
                         .eq(ProductionOrderRouting::getProductionOrderId, orderId)
@@ -30,6 +31,7 @@
 
     @Override
     public List<ProductionOrderRoutingOperationVo> listItem(Long orderId) {
+        // 鏌ヨ宸ヨ壓璺嚎宸ュ簭鏄庣粏
         return productionOrderRoutingOperationMapper.selectVoListByOrderId(orderId);
     }
 }
diff --git a/src/main/java/com/ruoyi/production/service/impl/ProductionOrderServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/ProductionOrderServiceImpl.java
index 9973d98..6ef6a44 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductionOrderServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionOrderServiceImpl.java
@@ -82,6 +82,7 @@
 
     @Override
     public IPage<ProductionOrderVo> pageProductionOrder(Page<ProductionOrderDto> page, ProductionOrderDto dto) {
+        // 鍒嗛〉鏌ヨ鐢熶骇璁㈠崟
         Page<ProductionOrderVo> result = (Page<ProductionOrderVo>) baseMapper.pageProductionOrder(page, dto);
         fillProductImages(result.getRecords());
         return result;
@@ -89,6 +90,7 @@
 
     @Override
     public List<ProductionOrderVo> listProductionOrder(ProductionOrderDto dto) {
+        // 鏌ヨ鐢熶骇璁㈠崟鍒楄〃
         List<ProductionOrderVo> records = baseMapper.listProductionOrder(dto);
         fillProductImages(records);
         return records;
@@ -96,6 +98,7 @@
 
     @Override
     public ProductionOrderVo getProductionOrderInfo(Long id) {
+        // 鑾峰彇鐢熶骇璁㈠崟璇︽儏
         ProductionOrderVo item = baseMapper.getProductionOrderInfo(id);
         if (item == null) {
             return null;
@@ -106,6 +109,7 @@
 
     @Override
     public boolean saveProductionOrder(ProductionOrder productionOrder) {
+        // 淇濆瓨鐢熶骇璁㈠崟
         ProductionOrder oldOrder = productionOrder.getId() == null ? null : this.getById(productionOrder.getId());
         // 涓嬪崟鍏ュ彛缁熶竴琛ラ綈鏉ユ簮鍗曟嵁銆佽鍒掑拰宸ヨ壓淇℃伅锛岄伩鍏嶅墠绔垎鍒紶澶氬瀛楁銆�
         validateAndFillOrder(productionOrder, oldOrder);
@@ -137,6 +141,7 @@
 
     @Override
     public boolean removeProductionOrder(List<Long> ids) {
+        // 鍒犻櫎鐢熶骇璁㈠崟
         if (ids == null || ids.isEmpty()) {
             return false;
         }
@@ -150,6 +155,7 @@
 
     @Override
     public Integer bindingRoute(ProductionOrderDto productionOrderDto) {
+        // 涓鸿鍗曠粦瀹氬伐鑹鸿矾绾�
         if (productionOrderDto == null || productionOrderDto.getId() == null) {
             throw new ServiceException("鐢熶骇璁㈠崟ID涓嶈兘涓虹┖");
         }
@@ -182,6 +188,7 @@
             ProductionOrder update = new ProductionOrder();
             update.setId(productionOrder.getId());
             update.setTechnologyRoutingId(targetRoutingId);
+        // 鎸佷箙鍖栨垨杈撳嚭澶勭悊缁撴灉
             if (!this.updateById(update)) {
                 throw new ServiceException("缁戝畾宸ヨ壓璺嚎澶辫触");
             }
@@ -193,6 +200,7 @@
 
     @Override
     public List<ProductionPlanVo> getSource(Long id) {
+        // 鏌ヨ璁㈠崟鍏宠仈鏉ユ簮璁″垝
         ProductionOrder productionOrder = baseMapper.selectById(id);
         if (productionOrder != null && productionOrder.getProductionPlanIds() != null) {
             List<Long> planIds = parsePlanIds(productionOrder.getProductionPlanIds());
@@ -203,7 +211,9 @@
 
     @Override
     public int syncProductionOrderSnapshot(Long productionOrderId) {
+        // 鍚屾璁㈠崟宸ヨ壓銆佸伐搴忋�佸弬鏁板拰BOM蹇収
         ProductionOrder productionOrder = this.getById(productionOrderId);
+        // 鍙傛暟涓庡墠缃潯浠舵牎楠�
         if (productionOrder == null) {
             throw new ServiceException("鐢熶骇璁㈠崟涓嶅瓨鍦�");
         }
@@ -226,15 +236,18 @@
         orderRouting.setDescription(technologyRouting.getDescription());
         orderRouting.setBomId(technologyRouting.getBomId());
         orderRouting.setOrderBomId(orderBom == null ? null : orderBom.getId());
+        // 鎸佷箙鍖栨垨杈撳嚭澶勭悊缁撴灉
         productionOrderRoutingMapper.insert(orderRouting);
 
         int syncedParamCount = 0;
+        // 鏌ヨ骞跺噯澶囦笟鍔℃暟鎹�
         List<TechnologyRoutingOperation> routingOperations = technologyRoutingOperationMapper.selectList(
                 Wrappers.<TechnologyRoutingOperation>lambdaQuery()
                         .eq(TechnologyRoutingOperation::getTechnologyRoutingId, technologyRouting.getId())
                         .orderByDesc(TechnologyRoutingOperation::getDragSort)
                         .orderByDesc(TechnologyRoutingOperation::getId));
         Map<Long, String> operationNameMap = technologyOperationMapper.selectBatchIds(
+        // 閬嶅巻澶勭悊鏁版嵁骞剁粍瑁呯粨鏋�
                         routingOperations.stream()
                                 .map(TechnologyRoutingOperation::getTechnologyOperationId)
                                 .filter(Objects::nonNull)
@@ -301,6 +314,7 @@
     }
 
     private ProductionOrderBom syncProductionOrderBomSnapshot(ProductionOrder productionOrder, TechnologyRouting technologyRouting) {
+        // 鍚屾璁㈠崟BOM蹇収缁撴瀯
         if (technologyRouting.getBomId() == null) {
             return null;
         }
@@ -308,10 +322,12 @@
         if (technologyBom == null) {
             throw new ServiceException("宸ヨ壓BOM涓嶅瓨鍦�");
         }
+        // 鏌ヨ骞跺噯澶囦笟鍔℃暟鎹�
         List<TechnologyBomStructure> structureList = technologyBomStructureMapper.selectList(
                 Wrappers.<TechnologyBomStructure>lambdaQuery()
                         .eq(TechnologyBomStructure::getBomId, technologyBom.getId())
                         .orderByAsc(TechnologyBomStructure::getId));
+        // 閬嶅巻澶勭悊鏁版嵁骞剁粍瑁呯粨鏋�
         TechnologyBomStructure root = structureList.stream().filter(item -> item.getParentId() == null).findFirst().orElse(null);
         BigDecimal orderQuantity = defaultDecimal(productionOrder.getQuantity());
 
@@ -322,6 +338,7 @@
         orderBom.setRemark(technologyBom.getRemark());
         orderBom.setBomNo(technologyBom.getBomNo());
         orderBom.setVersion(technologyBom.getVersion());
+        // 鎸佷箙鍖栨垨杈撳嚭澶勭悊缁撴灉
         productionOrderBomMapper.insert(orderBom);
 
         Map<Long, Long> idMap = new HashMap<>();
@@ -343,16 +360,19 @@
     }
 
     private void clearProductionSnapshot(Long productionOrderId) {
-        // 宸蹭骇鐢熼鏂欒褰曞悗绂佹閲嶅缓锛岄伩鍏嶅鏂�/鎶曟枡渚濇嵁涓庤鍗曞揩鐓ц劚鑺傘��
+        // 娓呯悊璁㈠崟宸茬敓鎴愮殑宸ヨ壓涓嶣OM蹇収鏁版嵁
         boolean hasPickRecord = productionOrderPickRecordMapper.selectCount(
+        // 鏌ヨ骞跺噯澶囦笟鍔℃暟鎹�
                 Wrappers.<ProductionOrderPickRecord>lambdaQuery()
                         .eq(ProductionOrderPickRecord::getProductionOrderId, productionOrderId)) > 0;
+        // 鍙傛暟涓庡墠缃潯浠舵牎楠�
         if (hasPickRecord) {
             throw new ServiceException("鐢熶骇璁㈠崟宸插瓨鍦ㄩ鏂欒褰曪紝涓嶈兘閲嶆柊鐢熸垚蹇収");
         }
         List<Long> taskIds = productionOperationTaskMapper.selectList(
                         Wrappers.<ProductionOperationTask>lambdaQuery()
                                 .eq(ProductionOperationTask::getProductionOrderId, productionOrderId))
+        // 閬嶅巻澶勭悊鏁版嵁骞剁粍瑁呯粨鏋�
                 .stream().map(ProductionOperationTask::getId).collect(Collectors.toList());
         if (!taskIds.isEmpty()) {
             // 宸叉湁鎶ュ伐璁板綍璇存槑璁㈠崟宸插紑宸ワ紝姝ゆ椂涓嶅厑璁稿啀閲嶅缓蹇収銆�
@@ -380,6 +400,7 @@
     }
 
     private LambdaQueryWrapper<ProductionOrder> buildQueryWrapper(ProductionOrderDto dto) {
+        // 鎸夋潯浠跺姩鎬佹瀯寤烘暟鎹簱鏌ヨ鏉′欢
         ProductionOrder query = dto == null ? new ProductionOrder() : dto;
         return Wrappers.<ProductionOrder>lambdaQuery()
                 .eq(query.getId() != null, ProductionOrder::getId, query.getId())
@@ -390,6 +411,7 @@
     }
 
     private String generateNextOrderNo() {
+        // 鐢熸垚涓嬩竴涓敓浜ц鍗曞彿
         String datePrefix = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
         String prefix = "SC" + datePrefix;
         ProductionOrder latestOrder = this.getOne(Wrappers.<ProductionOrder>lambdaQuery()
@@ -408,6 +430,7 @@
     }
 
     private String generateNextTaskNo() {
+        // 鐢熸垚涓嬩竴涓敓浜у伐鍗曞彿
         String datePrefix = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
         String prefix = "GD" + datePrefix;
         ProductionOperationTask lastTask = productionOperationTaskMapper.selectOne(
@@ -427,10 +450,12 @@
     }
 
     private BigDecimal defaultDecimal(BigDecimal value) {
+        // 灏嗙┖鏁伴噺鍏滃簳涓�0锛岄伩鍏嶇┖鎸囬拡寮傚父
         return value == null ? BigDecimal.ZERO : value;
     }
 
     private void validateAndFillOrder(ProductionOrder productionOrder, ProductionOrder oldOrder) {
+        // 鏍¢獙璁㈠崟鍙傛暟骞惰ˉ榻愰粯璁ゅ��
         if (productionOrder == null) {
             throw new ServiceException("鐢熶骇璁㈠崟涓嶈兘涓虹┖");
         }
@@ -463,7 +488,9 @@
     }
 
     private void fillFromProductionPlans(ProductionOrder productionOrder) {
+        // 浠庡叧鑱旂敓浜ц鍒掑洖濉鍗曞叧閿瓧娈�
         List<Long> planIds = parsePlanIds(productionOrder.getProductionPlanIds());
+        // 鍙傛暟涓庡墠缃潯浠舵牎楠�
         if (planIds.isEmpty()) {
             return;
         }
@@ -472,6 +499,7 @@
         if (productionPlans.size() != planIds.size()) {
             throw new ServiceException("閮ㄥ垎鐢熶骇璁″垝涓嶅瓨鍦�");
         }
+        // 閬嶅巻澶勭悊鏁版嵁骞剁粍瑁呯粨鏋�
         Map<Long, ProductionPlan> planMap = productionPlans.stream()
                 .collect(Collectors.toMap(ProductionPlan::getId, item -> item, (left, right) -> left));
         ProductionPlan mainPlan = planMap.get(planIds.get(0));
@@ -510,6 +538,7 @@
     }
 
     private void releaseProductionPlanIssueStatus(ProductionOrder productionOrder) {
+        // 鍥為��鐢熶骇璁″垝涓嬪彂鐘舵��
         if (productionOrder == null) {
             return;
         }
@@ -522,6 +551,7 @@
 
     //鐢熶骇璁㈠崟鍒犻櫎锛岀敓浜ц鍒掔殑宸蹭笅鍙戞暟閲忓搴斿彉鏇�
     private void updatePlanIssuedFlag(List<Long> planIds, BigDecimal remainingAssignedQuantity) {
+        // 鏇存柊璁″垝涓嬪彂鏍囪鍜屼笅鍙戞暟閲�
         if (planIds == null || planIds.isEmpty()) {
             return;
         }
@@ -551,6 +581,7 @@
     }
 
     private BigDecimal resolveRemainingQuantity(ProductionPlan plan) {
+        // 璁$畻褰撳墠璁″垝鎴栬褰曠殑鍓╀綑鏁伴噺
         if (plan == null) {
             return BigDecimal.ZERO;
         }
@@ -569,6 +600,7 @@
     }
 
     private int resolvePlanStatus(BigDecimal requiredQuantity, BigDecimal issuedQuantity) {
+        // 鏍规嵁闇�姹傞噺鍜屼笅鍙戦噺鎺ㄥ璁″垝鐘舵��
         if (requiredQuantity == null || requiredQuantity.compareTo(BigDecimal.ZERO) <= 0) {
             return 0;
         }
@@ -579,6 +611,7 @@
     }
 
     private List<Long> parsePlanIds(String productionPlanIds) {
+        // 灏嗚鍒扞D瀛楃涓茶В鏋愪负Long鍒楄〃
         if (productionPlanIds == null || productionPlanIds.trim().isEmpty()) {
             return new ArrayList<>();
         }
@@ -595,6 +628,7 @@
     }
 
     private String formatPlanIds(List<Long> planIds) {
+        // 灏嗚鍒扞D闆嗗悎鏍煎紡鍖栦负[1,2,3]瀛楃涓�
         if (planIds == null || planIds.isEmpty()) {
             return null;
         }
@@ -605,6 +639,7 @@
     }
 
     private LocalDate resolvePlanCompleteDate(ProductionPlan productionPlan) {
+        // 瑙f瀽璁″垝瀹屾垚鏃ユ湡
         if (productionPlan == null) {
             return null;
         }
@@ -618,13 +653,16 @@
     }
 
     private int compareDecimal(BigDecimal left, BigDecimal right) {
+        // 瀹夊叏姣旇緝涓や釜鏁伴噺鍊煎ぇ灏�
         return defaultDecimal(left).compareTo(defaultDecimal(right));
     }
 
     private void fillProductImages(List<ProductionOrderVo> records) {
+        // 濉厖浜у搧鍥剧墖
         if (records == null || records.isEmpty()) {
             return;
         }
+        // 閬嶅巻澶勭悊鏁版嵁骞剁粍瑁呯粨鏋�
         List<Long> productModelIds = records.stream()
                 .map(ProductionOrderVo::getProductModelId)
                 .filter(Objects::nonNull)
@@ -634,6 +672,7 @@
             return;
         }
 
+        // 鏌ヨ骞跺噯澶囦笟鍔℃暟鎹�
         List<StorageAttachment> attachments = storageAttachmentMapper.selectList(
                 Wrappers.<StorageAttachment>lambdaQuery()
                         .in(StorageAttachment::getRecordId, productModelIds)
@@ -676,6 +715,7 @@
     }
 
     private StorageBlobVO toStorageBlobVO(StorageBlob blob) {
+        // 灏嗗瓨鍌ㄦ枃浠跺璞¤浆鎹负VO
         StorageBlobVO vo = BeanUtil.copyProperties(blob, StorageBlobVO.class);
         vo.setPreviewURL(fileUtil.buildSignedPreviewUrl(vo));
         vo.setDownloadURL(fileUtil.buildSignedDownloadUrl(vo));
@@ -684,8 +724,10 @@
 
     @Override
     public ProductionOrderWorkOrderDetailVo getWorkOrderReportInspectDetail(ProductionOrderDto dto) {
+        // 鑾峰彇宸ュ崟璁㈠崟鎶ュ伐璐ㄦ鏄庣粏
         Long productionOrderId = resolveProductionOrderId(dto);
         ProductionOrderVo orderInfo = getProductionOrderInfo(productionOrderId);
+        // 鍙傛暟涓庡墠缃潯浠舵牎楠�
         if (orderInfo == null) {
             throw new ServiceException("鐢熶骇璁㈠崟涓嶅瓨鍦�");
         }
@@ -699,6 +741,7 @@
                 new Page<ProductionOperationTaskVo>(1, -1), taskQuery);
         List<ProductionOperationTaskVo> workOrderList = workOrderPage == null || workOrderPage.getRecords() == null
                 ? Collections.emptyList()
+        // 閬嶅巻澶勭悊鏁版嵁骞剁粍瑁呯粨鏋�
                 : workOrderPage.getRecords().stream()
                 .filter(Objects::nonNull)
                 .sorted(Comparator.comparing(ProductionOperationTaskVo::getId, Comparator.nullsLast(Comparator.naturalOrder())))
@@ -714,6 +757,7 @@
                 .collect(Collectors.toList());
         List<ProductionProductMain> reportMainList = workOrderIdList.isEmpty()
                 ? Collections.emptyList()
+        // 鏌ヨ骞跺噯澶囦笟鍔℃暟鎹�
                 : productionProductMainMapper.selectList(
                 Wrappers.<ProductionProductMain>lambdaQuery()
                         .in(ProductionProductMain::getProductionOperationTaskId, workOrderIdList)
@@ -851,6 +895,7 @@
     }
 
     private Long resolveProductionOrderId(ProductionOrderDto dto) {
+        // 浠庡叆鍙備腑瑙f瀽鐢熶骇璁㈠崟ID骞舵牎楠�
         if (dto == null) {
             throw new ServiceException("璇蜂紶鍏ョ敓浜ц鍗旾D鎴栫敓浜ц鍗曞彿");
         }
@@ -872,10 +917,12 @@
 
     @Override
     public List<ProductionOrderPickVo> pick(Long productionOrderId) {
+        // 鏌ヨ璁㈠崟棰嗘枡銆佹姇鏂欎笌閫�鏂欐槑缁�
         if (productionOrderId == null) {
             return Collections.emptyList();
         }
 
+        // 鏌ヨ骞跺噯澶囦笟鍔℃暟鎹�
         ProductionOrderBom orderBom = productionOrderBomMapper.selectOne(
                 Wrappers.<ProductionOrderBom>lambdaQuery()
                         .eq(ProductionOrderBom::getProductionOrderId, productionOrderId)
@@ -890,6 +937,7 @@
             return Collections.emptyList();
         }
 
+        // 閬嶅巻澶勭悊鏁版嵁骞剁粍瑁呯粨鏋�
         List<Long> productModelIds = bomStructureList.stream()
                 .map(ProductionBomStructureVo::getProductModelId)
                 .filter(Objects::nonNull)
@@ -946,6 +994,7 @@
 
     @Override
     public int updateOrder(ProductionOrderDto productionOrderDto) {
+        // 鏇存柊鐢熶骇璁㈠崟涓绘暟鎹�
         productionOrderDto.setStatus(5);
         return baseMapper.updateById(productionOrderDto);
     }
diff --git a/src/main/java/com/ruoyi/production/service/impl/ProductionPlanServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/ProductionPlanServiceImpl.java
index b3ad742..8c885cd 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductionPlanServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionPlanServiceImpl.java
@@ -6,6 +6,10 @@
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.basic.mapper.ProductMapper;
+import com.ruoyi.basic.mapper.ProductModelMapper;
+import com.ruoyi.basic.pojo.Product;
+import com.ruoyi.basic.pojo.ProductModel;
 import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.exception.base.BaseException;
 import com.ruoyi.common.utils.StringUtils;
@@ -44,27 +48,32 @@
     private final ProductionPlanMapper productionPlanMapper;
     private final ProductionOrderMapper productionOrderMapper;
     private final ProductionOrderService productionOrderService;
+    private final ProductModelMapper productModelMapper;
+    private final ProductMapper productMapper;
 
     @Override
     public IPage<ProductionPlanVo> listPage(Page<ProductionPlanDto> page, ProductionPlanDto productionPlanDto) {
+        // 鍒嗛〉鏌ヨ涓荤敓浜ц鍒掑垪琛�
         return productionPlanMapper.listPage(page, productionPlanDto);
     }
 
     /**
      * 鍚堝苟鐢熶骇璁″垝骞朵笅鍙戠敓浜ц鍗曘��
-     * 涓氬姟绾︽潫锛�
+     * 绾︽潫锛�
      * 1. 浠呭厑璁稿悓涓�浜у搧鍨嬪彿鐨勮鍒掑悎骞讹紱
-     * 2. 宸蹭笅鍙戞垨閮ㄥ垎涓嬪彂鐨勮鍒掔姝㈠啀娆″悎骞讹紱
-     * 3. 涓嬪彂鏁伴噺涓嶈兘澶т簬鎵�閫夎鍒掗渶姹傛�婚噺锛�
-     * 4. 璁㈠崟鍒涘缓缁熶竴澶嶇敤 ProductionOrderService.saveProductionOrder锛岀‘淇濆伐鑹�/BOM/棰嗘枡涓诲崟绛夊悗缁�昏緫涓�鑷淬��
+     * 2. 宸蹭笅鍙戞垨閮ㄥ垎涓嬪彂鐨勮鍒掍笉鍏佽鍐嶆鍚堝苟锛�
+     * 3. 涓嬪彂鏁伴噺涓嶈兘澶т簬鎵�閫夎鍒掑墿浣欓渶姹傛�婚噺锛�
+     * 4. 涓嬪彂鏃剁粺涓�璋冪敤 ProductionOrderService.saveProductionOrder锛岀‘淇濆悗缁伐鑹�/BOM/棰嗘枡閫昏緫涓�鑷淬��
      */
     @Override
     @Transactional(rollbackFor = Exception.class)
     public boolean combine(ProductionPlanDto productionPlanDto) {
+        // 鍩虹鍏ュ弬鏍¢獙锛氭病鏈夊彲涓嬪彂璁″垝鍒欑洿鎺ヨ繑鍥� false
         if (productionPlanDto == null || productionPlanDto.getIds() == null || productionPlanDto.getIds().isEmpty()) {
             return false;
         }
 
+        // 鍘荤┖銆佸幓閲嶏紝寰楀埌鏈鍙備笌鍚堝苟鐨勮鍒� ID
         List<Long> planIds = productionPlanDto.getIds().stream()
                 .filter(Objects::nonNull)
                 .distinct()
@@ -73,43 +82,51 @@
             throw new ServiceException("涓嬪彂澶辫触锛屾湭閫夋嫨鐢熶骇璁″垝");
         }
 
+        // 鏌ヨ骞舵牎楠岃鍒掓槸鍚﹂兘瀛樺湪
         List<ProductionPlanDto> planLists = productionPlanMapper.selectWithMaterialByIds(planIds);
         if (planLists == null || planLists.isEmpty() || planLists.size() != planIds.size()) {
             throw new ServiceException("涓嬪彂澶辫触锛岀敓浜ц鍒掍笉瀛樺湪鎴栧凡琚垹闄�");
         }
 
+        // 浠ョ涓�鏉¤鍒掍綔涓哄瀷鍙峰熀鍑�
         ProductionPlanDto firstPlan = planLists.getFirst();
         if (firstPlan.getProductModelId() == null) {
             throw new ServiceException("涓嬪彂澶辫触锛岀敓浜ц鍒掔己灏戜骇鍝佸瀷鍙�");
         }
 
+        // 浠呭厑璁稿悓鍨嬪彿璁″垝鍚堝苟涓嬪彂
         boolean hasDifferentModel = planLists.stream()
                 .anyMatch(item -> !Objects.equals(item.getProductModelId(), firstPlan.getProductModelId()));
         if (hasDifferentModel) {
             throw new BaseException("鍚堝苟澶辫触锛屾墍閫夌敓浜ц鍒掔殑浜у搧鍨嬪彿涓嶄竴鑷�");
         }
 
+        // 宸蹭笅鍙戞垨閮ㄥ垎涓嬪彂鐨勮鍒掍笉鍏佽鍐嶆鍚堝苟
         boolean hasIssuedPlan = planLists.stream()
-                .anyMatch(item -> item.getStatus() != null && item.getStatus() == PLAN_STATUS_ISSUED);
+                .anyMatch(item -> item.getStatus() != null
+                        && (item.getStatus() == PLAN_STATUS_PARTIAL || item.getStatus() == PLAN_STATUS_ISSUED));
         if (hasIssuedPlan) {
-            throw new BaseException("鍚堝苟澶辫触锛屾墍閫夌敓浜ц鍒掑瓨鍦ㄥ凡涓嬪彂鎴栭儴鍒嗕笅鍙戞暟鎹�");
+            throw new BaseException("鍚堝苟澶辫触锛屾墍閫夌敓浜ц鍒掑瓨鍦ㄥ凡涓嬪彂鎴栭儴鍒嗕笅鍙戠殑鏁版嵁");
         }
 
+        // 璁$畻鏈鍙笅鍙戠殑鍓╀綑闇�姹傛�婚噺
         BigDecimal totalRequiredQuantity = planLists.stream()
                 .map(this::resolveRemainingQuantity)
                 .reduce(BigDecimal.ZERO, BigDecimal::add);
         if (totalRequiredQuantity.compareTo(BigDecimal.ZERO) <= 0) {
-            throw new ServiceException("涓嬪彂澶辫触锛屾墍閫夌敓浜ц鍒掗渶姹傛�婚噺蹇呴』澶т簬0");
+            throw new ServiceException("涓嬪彂澶辫触锛屾墍閫夌敓浜ц鍒掑墿浣欓渶姹傛�婚噺蹇呴』澶т簬0");
         }
 
+        // 鏍¢獙涓嬪彂鏁伴噺
         BigDecimal assignedQuantity = productionPlanDto.getTotalAssignedQuantity();
         if (assignedQuantity == null || assignedQuantity.compareTo(BigDecimal.ZERO) <= 0) {
             throw new ServiceException("涓嬪彂澶辫触锛屼笅鍙戞暟閲忓繀椤诲ぇ浜�0");
         }
         if (assignedQuantity.compareTo(totalRequiredQuantity) > 0) {
-            throw new ServiceException("涓嬪彂澶辫触锛屼笅鍙戞暟閲忎笉鑳藉ぇ浜庤鍒掗渶姹傛�婚噺");
+            throw new ServiceException("涓嬪彂澶辫触锛屼笅鍙戞暟閲忎笉鑳藉ぇ浜庤鍒掑墿浣欓渶姹傛�婚噺");
         }
 
+        // 鎸夎鍒掗『搴忓垎鎽婁笅鍙戞暟閲忥紝鏀堕泦瀹為檯鍙備笌涓嬪彂鐨勮鍒� ID
         BigDecimal remainingForOrderBind = assignedQuantity;
         List<Long> issuedPlanIds = new ArrayList<>();
         for (ProductionPlanDto plan : planLists) {
@@ -124,21 +141,20 @@
             }
         }
         if (issuedPlanIds.isEmpty()) {
-            throw new ServiceException("Issue failed, no quantity available for dispatch");
+            throw new ServiceException("涓嬪彂澶辫触锛屾棤鍙笅鍙戞暟閲�");
         }
 
+        // 鐢熸垚鐢熶骇璁㈠崟涓诲崟锛屽苟缁戝畾鏈涓嬪彂鍏宠仈鐨勮鍒�
         ProductionOrder productionOrder = new ProductionOrder();
         productionOrder.setProductionPlanIds(formatPlanIds(issuedPlanIds));
         productionOrder.setProductModelId(firstPlan.getProductModelId());
         productionOrder.setQuantity(assignedQuantity);
         productionOrder.setPlanCompleteTime(productionPlanDto.getPlanCompleteTime());
-
-        boolean saved = productionOrderService.saveProductionOrder(productionOrder);
-        if (!saved) {
+        if (!productionOrderService.saveProductionOrder(productionOrder)) {
             throw new ServiceException("涓嬪彂澶辫触锛岀敓浜ц鍗曚繚瀛樺け璐�");
         }
 
-        //宸蹭笅鍙戞暟閲�
+        // 鍥炲啓姣忔潯璁″垝鐨勭疮璁′笅鍙戦噺鍜岀姸鎬�
         BigDecimal remainingAssignedQuantity = assignedQuantity;
         List<ProductionPlan> updates = new ArrayList<>();
         for (ProductionPlanDto plan : planLists) {
@@ -163,6 +179,7 @@
             updates.add(update);
         }
         if (!updates.isEmpty()) {
+            // 鎵归噺鏇存柊璁″垝鐘舵�佷笌鏁伴噺
             this.updateBatchById(updates);
         }
         return true;
@@ -171,17 +188,24 @@
     @Override
     @Transactional(rollbackFor = Exception.class)
     public boolean add(ProductionPlanDto dto) {
+        // 鏂板涓荤敓浜ц鍒�
         if (StringUtils.isBlank(dto.getMpsNo())) {
-            dto.setMpsNo(generateNextPlanNo(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"))));
-        }else checkMpsNoUnique(dto.getMpsNo(), null);
+            String datePrefix = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
+            dto.setMpsNo(buildPlanNo(datePrefix, resolveNextPlanSequence(datePrefix)));
+        } else {
+            checkMpsNoUnique(dto.getMpsNo(), null);
+        }
         dto.setStatus(PLAN_STATUS_WAIT);
-        dto.setSource("鍐呴儴");
+        if (StringUtils.isBlank(dto.getSource())) {
+            dto.setSource("鍐呴儴");
+        }
         return productionPlanMapper.insert(dto) > 0;
     }
 
     @Override
     @Transactional(rollbackFor = Exception.class)
     public boolean update(ProductionPlanDto dto) {
+        // 鏇存柊涓荤敓浜ц鍒�
         if (dto == null || dto.getId() == null) {
             throw new ServiceException("缂栬緫澶辫触锛屾暟鎹笉鑳戒负绌�");
         }
@@ -202,20 +226,10 @@
         return productionPlanMapper.updateById(dto) > 0;
     }
 
-    private void checkMpsNoUnique(String mpsNo, Long excludeId) {
-        LambdaQueryWrapper<ProductionPlan> wrapper = Wrappers.lambdaQuery();
-        wrapper.eq(ProductionPlan::getMpsNo, mpsNo);
-        if (excludeId != null) {
-            wrapper.ne(ProductionPlan::getId, excludeId);
-        }
-        if (productionPlanMapper.selectCount(wrapper) > 0) {
-            throw new ServiceException("鐢熶骇璁″垝鍙� " + mpsNo + " 宸插瓨鍦�");
-        }
-    }
-
     @Override
     @Transactional(rollbackFor = Exception.class)
     public boolean delete(List<Long> ids) {
+        // 鍒犻櫎涓荤敓浜ц鍒�
         if (productionPlanMapper.selectList(Wrappers.<ProductionPlan>lambdaQuery().in(ProductionPlan::getId, ids))
                 .stream()
                 .anyMatch(p -> p.getStatus() == PLAN_STATUS_PARTIAL || p.getStatus() == PLAN_STATUS_ISSUED)) {
@@ -234,6 +248,7 @@
     @Override
     @Transactional(rollbackFor = Exception.class)
     public void importProdData(MultipartFile file) {
+        // 鍙傛暟涓庡墠缃潯浠舵牎楠�
         if (file == null || file.isEmpty()) {
             throw new ServiceException("瀵煎叆鏁版嵁涓嶈兘涓虹┖");
         }
@@ -247,104 +262,251 @@
         if (list == null || list.isEmpty()) {
             throw new ServiceException("Excel娌℃湁鏁版嵁");
         }
+
+        String datePrefix = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
+        int nextSequence = resolveNextPlanSequence(datePrefix);
         Set<String> mpsNos = new HashSet<>();
+        // 閬嶅巻澶勭悊鏁版嵁骞剁粍瑁呯粨鏋�
         for (int i = 0; i < list.size(); i++) {
             ProductionPlanImportDto dto = list.get(i);
-            String mpsNo = dto.getMpsNo();
+            String mpsNo = StringUtils.trim(dto.getMpsNo());
             if (StringUtils.isEmpty(mpsNo)) {
-                generateNextPlanNo(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")));
+                mpsNo = buildPlanNo(datePrefix, nextSequence++);
             }
+            dto.setMpsNo(mpsNo);
             if (!mpsNos.add(mpsNo)) {
-                throw new ServiceException("瀵煎叆澶辫触锛欵xcel 涓瓨鍦ㄩ噸澶嶇殑鐢宠鍗曠紪鍙� " + mpsNo);
+                throw new ServiceException("瀵煎叆澶辫触锛孍xcel涓瓨鍦ㄩ噸澶嶇殑涓荤敓浜ц鍒掑彿 " + mpsNo);
+            }
+            if (dto.getQtyRequired() == null || dto.getQtyRequired().compareTo(BigDecimal.ZERO) <= 0) {
+                throw new ServiceException("瀵煎叆澶辫触锛氱" + (i + 2) + "琛岄渶姹傛暟閲忓繀椤诲ぇ浜�0");
             }
         }
-        Long existApplyNoCount = baseMapper.selectCount(Wrappers.<ProductionPlan>lambdaQuery()
-                .in(ProductionPlan::getMpsNo, mpsNos));
+
+        // 鏌ヨ骞跺噯澶囦笟鍔℃暟鎹�
+        Long existApplyNoCount = baseMapper.selectCount(Wrappers.<ProductionPlan>lambdaQuery().in(ProductionPlan::getMpsNo, mpsNos));
         if (existApplyNoCount > 0) {
-            List<String> existMpsNos = baseMapper.selectList(Wrappers.<ProductionPlan>lambdaQuery()
-                            .in(ProductionPlan::getMpsNo, mpsNos))
+            List<String> existMpsNos = baseMapper.selectList(Wrappers.<ProductionPlan>lambdaQuery().in(ProductionPlan::getMpsNo, mpsNos))
                     .stream()
                     .map(ProductionPlan::getMpsNo)
                     .collect(Collectors.toList());
-            throw new ServiceException("瀵煎叆澶辫触锛岀敓浜ц鍒掑彿宸插瓨鍦�: " + String.join(", ", existMpsNos));
+            throw new ServiceException("瀵煎叆澶辫触锛屼富鐢熶骇璁″垝鍙峰凡瀛樺湪: " + String.join(", ", existMpsNos));
         }
+
+        List<ProductModel> allModels = productModelMapper.selectList(Wrappers.<ProductModel>lambdaQuery());
+        Set<Long> productIds = allModels.stream()
+                .map(ProductModel::getProductId)
+                .filter(Objects::nonNull)
+                .collect(Collectors.toSet());
+        Map<Long, String> productNameById = productIds.isEmpty()
+                ? Collections.emptyMap()
+                : productMapper.selectBatchIds(productIds).stream()
+                .collect(Collectors.toMap(Product::getId, Product::getProductName, (a, b) -> a));
+
         LocalDateTime now = LocalDateTime.now();
-        List<ProductionPlan> entityList = list.stream().map(dto -> {
+        List<ProductionPlan> entityList = new ArrayList<>();
+        for (int i = 0; i < list.size(); i++) {
+            ProductionPlanImportDto dto = list.get(i);
             ProductionPlan entity = new ProductionPlan();
             BeanUtils.copyProperties(dto, entity);
+            entity.setProductModelId(resolveProductModelId(dto, i + 2, allModels, productNameById));
             entity.setStatus(PLAN_STATUS_WAIT);
-            entity.setSource("鍐呴儴");
+            entity.setSource(StringUtils.isNotEmpty(dto.getSource()) ? StringUtils.trim(dto.getSource()) : "鍐呴儴");
+            entity.setQuantityIssued(BigDecimal.ZERO);
             entity.setCreateTime(now);
             entity.setUpdateTime(now);
-            return entity;
-        }).collect(Collectors.toList());
-        this.saveBatch(entityList);
+            entityList.add(entity);
+        }
+        // 鎸佷箙鍖栨垨杈撳嚭澶勭悊缁撴灉
+        if (!this.saveBatch(entityList)) {
+            throw new ServiceException("瀵煎叆澶辫触锛屼繚瀛樼敓浜ц鍒掓暟鎹け璐�");
+        }
     }
 
     @Override
-    public void exportProdData(HttpServletResponse response, List<Long> ids) {
-        List<ProductionPlanDto> list = productionPlanMapper.selectWithMaterialByIds(ids);
+    public void exportProdData(HttpServletResponse response, ProductionPlanDto requestDto) {
+        // 瀵煎嚭涓荤敓浜ц鍒掓暟鎹�
+        List<Long> ids = requestDto == null || requestDto.getIds() == null
+                ? Collections.emptyList()
+                : requestDto.getIds().stream().filter(Objects::nonNull).distinct().collect(Collectors.toList());
+
         List<ProductionPlanImportDto> exportList = new ArrayList<>();
-        for (ProductionPlanDto entity : list) {
-            ProductionPlanImportDto dto = new ProductionPlanImportDto();
-            BeanUtils.copyProperties(entity, dto);
-            exportList.add(dto);
+        if (!ids.isEmpty()) {
+            List<ProductionPlanDto> list = productionPlanMapper.selectWithMaterialByIds(ids);
+            for (ProductionPlanDto item : list) {
+                ProductionPlanImportDto dto = new ProductionPlanImportDto();
+                BeanUtils.copyProperties(item, dto);
+                dto.setAssignedQuantity(item.getQuantityIssued());
+                exportList.add(dto);
+            }
+        } else {
+            ProductionPlanDto query = new ProductionPlanDto();
+            if (requestDto != null) {
+                BeanUtils.copyProperties(requestDto, query);
+            }
+            IPage<ProductionPlanVo> page = productionPlanMapper.listPage(new Page<>(1, -1), query);
+            if (page != null && page.getRecords() != null) {
+                for (ProductionPlanVo item : page.getRecords()) {
+                    ProductionPlanImportDto dto = new ProductionPlanImportDto();
+                    BeanUtils.copyProperties(item, dto);
+                    dto.setAssignedQuantity(item.getQuantityIssued());
+                    exportList.add(dto);
+                }
+            }
         }
+
         ExcelUtil<ProductionPlanImportDto> util = new ExcelUtil<>(ProductionPlanImportDto.class);
         util.exportExcel(response, exportList, "涓荤敓浜ц鍒�");
     }
 
-    private BigDecimal resolveRemainingQuantity(ProductionPlan plan) {
-        if (plan == null) {
-            return BigDecimal.ZERO;
+    /**
+     * 鏍¢獙涓荤敓浜ц鍒掑彿鍞竴鎬э紝鍙�氳繃 excludeId 鎺掗櫎褰撳墠璁板綍銆�
+     */
+    private void checkMpsNoUnique(String mpsNo, Long excludeId) {
+        // 鎸変富鐢熶骇璁″垝鍙锋煡璇㈤噸澶嶈褰�
+        LambdaQueryWrapper<ProductionPlan> wrapper = Wrappers.lambdaQuery();
+        wrapper.eq(ProductionPlan::getMpsNo, mpsNo);
+        if (excludeId != null) {
+            // 鏇存柊鏃舵帓闄ゅ綋鍓嶈褰曟湰韬�
+            wrapper.ne(ProductionPlan::getId, excludeId);
         }
-        BigDecimal requiredQuantity = Optional.ofNullable(plan.getQtyRequired()).orElse(BigDecimal.ZERO);
-        if (requiredQuantity.compareTo(BigDecimal.ZERO) <= 0) {
-            return BigDecimal.ZERO;
+        if (productionPlanMapper.selectCount(wrapper) > 0) {
+            // 瀛樺湪閲嶅璁″垝鍙凤紝鐩存帴鎷︽埅
+            throw new ServiceException("鐢熶骇璁″垝鍙� " + mpsNo + " 宸插瓨鍦�");
         }
-        BigDecimal issuedQuantity = Optional.ofNullable(plan.getQuantityIssued()).orElse(BigDecimal.ZERO);
-        if (issuedQuantity.compareTo(BigDecimal.ZERO) <= 0) {
-            return requiredQuantity;
-        }
-        if (issuedQuantity.compareTo(requiredQuantity) >= 0) {
-            return BigDecimal.ZERO;
-        }
-        return requiredQuantity.subtract(issuedQuantity);
     }
 
-    private int resolvePlanStatus(BigDecimal requiredQuantity, BigDecimal issuedQuantity) {
-        if (requiredQuantity == null || requiredQuantity.compareTo(BigDecimal.ZERO) <= 0) {
-            return PLAN_STATUS_WAIT;
+    /**
+     * 鏍规嵁瀵煎叆琛岀殑鍨嬪彿銆佷骇鍝佸悕绉般�佸崟浣嶅畾浣嶅敮涓�鐨勪骇鍝佸瀷鍙� ID銆�
+     */
+    private Long resolveProductModelId(ProductionPlanImportDto dto, int rowNo, List<ProductModel> allModels,
+                                       Map<Long, String> productNameById) {
+        // 鍏堟寜瑙勬牸鍨嬪彿鍋氱涓�杞繃婊�
+        String model = StringUtils.trim(dto.getModel());
+        if (StringUtils.isEmpty(model)) {
+            throw new ServiceException("瀵煎叆澶辫触锛氱" + rowNo + "琛岃鏍煎瀷鍙蜂笉鑳戒负绌�");
         }
-        if (issuedQuantity == null || issuedQuantity.compareTo(BigDecimal.ZERO) <= 0) {
-            return PLAN_STATUS_WAIT;
+
+        List<ProductModel> candidates = allModels.stream()
+                .filter(item -> model.equals(StringUtils.trim(item.getModel())))
+                .collect(Collectors.toList());
+        if (candidates.isEmpty()) {
+            throw new ServiceException("瀵煎叆澶辫触锛氱" + rowNo + "琛岃鏍煎瀷鍙蜂笉瀛樺湪锛屽瀷鍙凤細" + model);
         }
-        return issuedQuantity.compareTo(requiredQuantity) < 0 ? PLAN_STATUS_PARTIAL : PLAN_STATUS_ISSUED;
+
+        // 鑻ヤ紶浜嗕骇鍝佸悕绉帮紝鍐嶅仛绗簩杞繃婊�
+        String productName = StringUtils.trim(dto.getProductName());
+        if (StringUtils.isNotEmpty(productName)) {
+            candidates = candidates.stream()
+                    .filter(item -> productName.equals(StringUtils.trim(productNameById.get(item.getProductId()))))
+                    .collect(Collectors.toList());
+            if (candidates.isEmpty()) {
+                throw new ServiceException("瀵煎叆澶辫触锛氱" + rowNo + "琛屼骇鍝佸悕绉颁笌瑙勬牸鍨嬪彿涓嶅尮閰�");
+            }
+        }
+
+        // 鑻ヤ紶浜嗗崟浣嶏紝鍐嶅仛绗笁杞繃婊�
+        String unit = StringUtils.trim(dto.getUnit());
+        if (StringUtils.isNotEmpty(unit)) {
+            candidates = candidates.stream()
+                    .filter(item -> unit.equals(StringUtils.trim(item.getUnit())))
+                    .collect(Collectors.toList());
+            if (candidates.isEmpty()) {
+                throw new ServiceException("瀵煎叆澶辫触锛氱" + rowNo + "琛屽崟浣嶄笌瑙勬牸鍨嬪彿涓嶅尮閰�");
+            }
+        }
+
+        // 浠嶇劧澶氭潯璇存槑淇℃伅涓嶈冻浠ュ敮涓�瀹氫綅
+        if (candidates.size() > 1) {
+            throw new ServiceException("瀵煎叆澶辫触锛氱" + rowNo + "琛岃鏍煎瀷鍙峰尮閰嶅埌澶氫釜浜у搧锛岃琛ュ厖浜у搧鍚嶇О鎴栧崟浣�");
+        }
+        return candidates.get(0).getId();
     }
 
-    private String formatPlanIds(List<Long> planIds) {
-        return planIds.stream()
-                .filter(Objects::nonNull)
-                .distinct()
-                .map(String::valueOf)
-                .collect(Collectors.joining(",", "[", "]"));
+    /**
+     * 鐢熸垚涓荤敓浜ц鍒掑彿锛屾牸寮忥細JH + yyyyMMdd + 4浣嶆祦姘村彿銆�
+     */
+    private String buildPlanNo(String datePrefix, int sequence) {
+        // 缁熶竴璁″垝鍙锋牸寮忥細JH + 鏃ユ湡 + 4浣嶆祦姘村彿
+        return "JH" + datePrefix + String.format("%04d", sequence);
     }
 
-    private String generateNextPlanNo(String datePrefix) {
+    /**
+     * 鏌ヨ褰撴棩宸插瓨鍦ㄧ殑鏈�澶ф祦姘村彿锛屽苟杩斿洖涓嬩竴涓彲鐢ㄦ祦姘村彿銆�
+     */
+    private int resolveNextPlanSequence(String datePrefix) {
+        // 鏌ヨ褰撴棩鏈�鏂颁竴鏉¤鍒掑彿
         QueryWrapper<ProductionPlan> queryWrapper = new QueryWrapper<>();
         queryWrapper.likeRight("mps_no", "JH" + datePrefix);
         queryWrapper.orderByDesc("mps_no");
         queryWrapper.last("LIMIT 1");
         ProductionPlan latestPlan = productionPlanMapper.selectOne(queryWrapper);
+
+        // 榛樿浠� 0001 寮�濮�
         int sequence = 1;
-        if (latestPlan != null && latestPlan.getMpsNo() != null && !latestPlan.getMpsNo().isEmpty()) {
+        if (latestPlan != null && StringUtils.isNotEmpty(latestPlan.getMpsNo())) {
+            // 鎴彇鏈熬娴佹按鍙峰苟閫掑
             String sequenceStr = latestPlan.getMpsNo().substring(("JH" + datePrefix).length());
             try {
                 sequence = Integer.parseInt(sequenceStr) + 1;
-            } catch (NumberFormatException e) {
+            } catch (NumberFormatException ignored) {
+                // 鍘嗗彶鏁版嵁鏍煎紡寮傚父鏃跺洖閫�鍒� 0001
                 sequence = 1;
             }
         }
-        return "JH" + datePrefix + String.format("%04d", sequence);
+        return sequence;
+    }
+
+    /**
+     * 璁$畻鐢熶骇璁″垝鐨勫墿浣欐湭涓嬪彂鏁伴噺锛堥渶姹傞噺 - 宸蹭笅鍙戦噺锛屾渶灏忎负 0锛夈��
+     */
+    private BigDecimal resolveRemainingQuantity(ProductionPlan plan) {
+        // 绌哄璞℃寜 0 澶勭悊
+        if (plan == null) {
+            return BigDecimal.ZERO;
+        }
+        // 闇�姹傞噺涓虹┖鎴栧皬浜庣瓑浜� 0锛岃涓烘棤鍓╀綑
+        BigDecimal requiredQuantity = Optional.ofNullable(plan.getQtyRequired()).orElse(BigDecimal.ZERO);
+        if (requiredQuantity.compareTo(BigDecimal.ZERO) <= 0) {
+            return BigDecimal.ZERO;
+        }
+        // 宸蹭笅鍙戦噺涓虹┖鎴栧皬浜庣瓑浜� 0锛屽墿浣欏嵆闇�姹傞噺
+        BigDecimal issuedQuantity = Optional.ofNullable(plan.getQuantityIssued()).orElse(BigDecimal.ZERO);
+        if (issuedQuantity.compareTo(BigDecimal.ZERO) <= 0) {
+            return requiredQuantity;
+        }
+        // 宸蹭笅鍙戦噺澶т簬绛変簬闇�姹傞噺锛屽墿浣欏綊闆�
+        if (issuedQuantity.compareTo(requiredQuantity) >= 0) {
+            return BigDecimal.ZERO;
+        }
+        // 姝e父鍦烘櫙杩斿洖宸��
+        return requiredQuantity.subtract(issuedQuantity);
+    }
+
+    /**
+     * 鎸夐渶姹傞噺涓庣疮璁′笅鍙戦噺鎺ㄥ璁″垝鐘舵�併��
+     */
+    private int resolvePlanStatus(BigDecimal requiredQuantity, BigDecimal issuedQuantity) {
+        // 鏃犳湁鏁堥渶姹傞噺鏃讹紝鐘舵�佷繚鎸佸緟涓嬪彂
+        if (requiredQuantity == null || requiredQuantity.compareTo(BigDecimal.ZERO) <= 0) {
+            return PLAN_STATUS_WAIT;
+        }
+        // 鏈夐渶姹備絾鏈笅鍙戯紝鐘舵�佷粛涓哄緟涓嬪彂
+        if (issuedQuantity == null || issuedQuantity.compareTo(BigDecimal.ZERO) <= 0) {
+            return PLAN_STATUS_WAIT;
+        }
+        // 宸蹭笅鍙戦噺灏忎簬闇�姹傞噺涓洪儴鍒嗕笅鍙戯紝鍚﹀垯涓哄凡涓嬪彂
+        return issuedQuantity.compareTo(requiredQuantity) < 0 ? PLAN_STATUS_PARTIAL : PLAN_STATUS_ISSUED;
+    }
+
+    /**
+     * 灏嗚鍒� ID 闆嗗悎杞垚 [1,2,3] 褰㈠紡锛屽啓鍏ョ敓浜ц鍗曞叧鑱斿瓧娈点��
+     */
+    private String formatPlanIds(List<Long> planIds) {
+        // 鍘婚噸骞舵嫾鎺ヤ负 [1,2,3] 褰㈠紡鐨勫瓧绗︿覆
+        return planIds.stream()
+                .filter(Objects::nonNull)
+                .distinct()
+                .map(String::valueOf)
+                .collect(Collectors.joining(",", "[", "]"));
     }
 }
diff --git a/src/main/java/com/ruoyi/production/service/impl/ProductionProductInputServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/ProductionProductInputServiceImpl.java
index 38e0baf..64d78fb 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductionProductInputServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionProductInputServiceImpl.java
@@ -17,6 +17,7 @@
 
     @Override
     public IPage<ProductionProductInputDto> listPageProductionProductInputDto(Page page, ProductionProductInputDto productionProductInputDto) {
+        // 鍒嗛〉鏌ヨ鐢熶骇浜у搧鍏ュ簱
         return productionProductInputMapper.listPageProductionProductInputDto(page, productionProductInputDto);
     }
 }
diff --git a/src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java
index 150fc89..175dd30 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java
@@ -82,6 +82,7 @@
 
     @Override
     public IPage<ProductionProductMainDto> listPageProductionProductMainDto(Page page, ProductionProductMainDto productionProductMainDto) {
+        // 鍒嗛〉鏌ヨ鐢熶骇鎶ュ伐涓昏〃
         IPage<ProductionProductMainDto> result = productionProductMainMapper.listPageProductionProductMainDto(page, productionProductMainDto);
         fillOperationParamList(result.getRecords());
         return result;
@@ -89,20 +90,24 @@
 
     @Override
     public IPage<ProductionProductMainDto> pageProductionProductMain(Page page, ProductionProductMainDto productionProductMainDto) {
+        // 鍒嗛〉鏌ヨ鐢熶骇鎶ュ伐涓昏〃
         return listPageProductionProductMainDto(page, productionProductMainDto);
     }
 
     @Override
     public ProductionProductMainDto getProductionProductMainInfo(Long id) {
+        // 鑾峰彇鐢熶骇浜у搧涓昏〃璇︽儏
         return listPageProductionProductMainDto(new Page<>(1, 1), new ProductionProductMainDto() {{
             setId(id);
         }}).getRecords().stream().findFirst().orElse(null);
     }
 
     private void fillOperationParamList(List<ProductionProductMainDto> recordList) {
+        // 濉厖宸ュ簭鍙傛暟鍒楄〃
         if (recordList == null || recordList.isEmpty()) {
             return;
         }
+        // 閬嶅巻澶勭悊鏁版嵁骞剁粍瑁呯粨鏋�
         Set<Long> mainIdSet = recordList.stream()
                 .map(ProductionProductMainDto::getId)
                 .filter(Objects::nonNull)
@@ -112,6 +117,7 @@
             return;
         }
 
+        // 鏌ヨ骞跺噯澶囦笟鍔℃暟鎹�
         List<ProductionOrderRoutingOperationParam> paramList = productionOrderRoutingOperationParamMapper.selectList(
                 Wrappers.<ProductionOrderRoutingOperationParam>lambdaQuery()
                         .in(ProductionOrderRoutingOperationParam::getProductionProductMainId, mainIdSet)
@@ -211,6 +217,7 @@
 
     @Override
     public Boolean addProductMain(ProductionProductMainDto dto) {
+        // 鏂板鐢熶骇鎶ュ伐涓昏褰�
         Long taskId = resolveTaskId(dto);
         if (taskId == null) {
             throw new ServiceException("璇蜂紶鍏ョ敓浜у伐鍗旾D");
@@ -220,11 +227,13 @@
 
     @Override
     public Boolean saveProductionProductMain(ProductionProductMainDto productionProductMainDto) {
+        // 淇濆瓨鐢熶骇鎶ュ伐涓昏褰�
         return addProductMain(productionProductMainDto);
     }
 
     @Override
     public Boolean removeProductMain(Long id) {
+        // 鍒犻櫎鐢熶骇鎶ュ伐涓昏褰�
         ProductionProductMain currentMain = productionProductMainMapper.selectById(id);
         if (currentMain == null) {
             return true;
@@ -233,10 +242,10 @@
     }
 
     private Boolean addProductMainByProductionTask(ProductionProductMainDto dto) {
-        // 鎶ュ伐浠ヨ鍗曞伐搴忓揩鐓т负鍑嗭紝閬垮厤宸ヨ壓涓绘暟鎹彉鏇村悗褰卞搷鍘嗗彶宸ュ崟鎵ц銆�
+        // 鎸夌敓浜т换鍔℃柊澧炴姤宸ヤ富璁板綍
         Long taskId = resolveTaskId(dto);
         if (taskId == null) {
-            throw new ServiceException("productionOperationTaskId can not be null");
+            throw new ServiceException("鐢熶骇宸ュ崟ID涓嶈兘涓虹┖");
         }
         SysUser user = userMapper.selectUserById(dto.getUserId());
         ProductionOperationTask productionOperationTask = productionOperationTaskMapper.selectById(taskId);
@@ -522,12 +531,14 @@
     }
 
     private Boolean removeProductMainByProductionTask(ProductionProductMain productionProductMain) {
-        // 鍒犻櫎鎶ュ伐闇�瑕佸悓姝ュ洖婊氳川妫�銆佸簱瀛樸�佸伐鏃舵牳绠楀拰璁㈠崟/宸ュ崟杩涘害銆�
+        // 鎸夌敓浜т换鍔″洖婊氬苟鍒犻櫎鎶ュ伐涓昏褰�
         List<QualityInspect> qualityInspects = qualityInspectMapper.selectList(
                 Wrappers.<QualityInspect>lambdaQuery().eq(QualityInspect::getProductMainId, productionProductMain.getId()));
+        // 鍙傛暟涓庡墠缃潯浠舵牎楠�
         if (qualityInspects.size() > 0) {
             List<QualityUnqualified> qualityUnqualifieds = qualityUnqualifiedMapper.selectList(
                     Wrappers.<QualityUnqualified>lambdaQuery()
+        // 閬嶅巻澶勭悊鏁版嵁骞剁粍瑁呯粨鏋�
                             .in(QualityUnqualified::getInspectId, qualityInspects.stream().map(QualityInspect::getId).collect(Collectors.toList())));
             if (qualityUnqualifieds.size() > 0 && qualityUnqualifieds.get(0).getInspectState() == 1) {
                 throw new ServiceException("璇ユ潯鎶ュ伐宸茬粡涓嶅悎鏍煎鐞嗕簡锛屼笉鍏佽鍒犻櫎");
@@ -552,6 +563,7 @@
             } else {
                 productionOperationTask.setStatus(3);
             }
+        // 鎸佷箙鍖栨垨杈撳嚭澶勭悊缁撴灉
             productionOperationTaskMapper.updateById(productionOperationTask);
 
             ProductionOrder productionOrder = productionOrderMapper.selectById(productionOperationTask.getProductionOrderId());
@@ -600,6 +612,7 @@
     }
 
     private String generateProductNo() {
+        // 鐢熸垚涓嬩竴涓敓浜т骇鍝佺紪鍙�
         String datePrefix = "BG" + LocalDate.now().format(DateTimeFormatter.ofPattern("yyMMdd"));
         QueryWrapper<ProductionProductMain> queryWrapper = new QueryWrapper<>();
         queryWrapper.select("MAX(product_no) as maxNo").likeRight("product_no", datePrefix);
@@ -622,10 +635,12 @@
     }
 
     private BigDecimal defaultDecimal(BigDecimal value) {
+        // 灏嗙┖鏁伴噺鍏滃簳涓�0锛岄伩鍏嶇┖鎸囬拡寮傚父
         return value == null ? BigDecimal.ZERO : value;
     }
 
     private Long resolveTaskId(ProductionProductMainDto dto) {
+        // 浠庡叆鍙備腑瑙f瀽鐢熶骇宸ュ崟ID骞舵牎楠�
         if (dto == null) {
             return null;
         }
@@ -634,6 +649,7 @@
 
     @Override
     public ArrayList<Long> listMain(List<Long> idList) {
+        // 鏌ヨ涓昏〃ID闆嗗悎
         return productionProductMainMapper.listMain(idList);
     }
 }
diff --git a/src/main/java/com/ruoyi/production/service/impl/ProductionProductOutputServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/ProductionProductOutputServiceImpl.java
index fb2aa26..904c8cc 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductionProductOutputServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionProductOutputServiceImpl.java
@@ -17,6 +17,7 @@
 
     @Override
     public IPage<ProductionProductOutputDto> listPageProductionProductOutputDto(Page page, ProductionProductOutputDto productionProductOutputDto) {
+        // 鍒嗛〉鏌ヨ鐢熶骇浜у搧鍑哄簱
         return productionProductOutputMapper.listPageProductionProductOutputDto(page, productionProductOutputDto);
     }
 }
diff --git a/src/main/java/com/ruoyi/production/service/impl/SalesLedgerProductionAccountingServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/SalesLedgerProductionAccountingServiceImpl.java
index f06284d..e937ba4 100644
--- a/src/main/java/com/ruoyi/production/service/impl/SalesLedgerProductionAccountingServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/SalesLedgerProductionAccountingServiceImpl.java
@@ -15,6 +15,7 @@
 
     @Override
     public UserAccountDto getByUserId(UserProductionAccountingDto dto) {
+        // 鎸夌敤鎴锋煡璇㈢敓浜ф牳绠椾俊鎭�
         if (dto == null || dto.getUserId() == null || dto.getDate() == null || dto.getDate().trim().isEmpty()) {
             return new UserAccountDto();
         }
diff --git a/src/main/java/com/ruoyi/technology/service/impl/TechnologyBomServiceImpl.java b/src/main/java/com/ruoyi/technology/service/impl/TechnologyBomServiceImpl.java
index 2a4cd1d..bac4f37 100644
--- a/src/main/java/com/ruoyi/technology/service/impl/TechnologyBomServiceImpl.java
+++ b/src/main/java/com/ruoyi/technology/service/impl/TechnologyBomServiceImpl.java
@@ -108,12 +108,12 @@
     @Transactional(rollbackFor = Exception.class)
     public R update(TechnologyBom technologyBom) {
         if (technologyBom.getId() == null) {
-            throw new ServiceException("BOM id is required");
+            throw new ServiceException("BOM ID涓嶈兘涓虹┖");
         }
         validateProductModel(technologyBom.getProductModelId());
         TechnologyBom oldBom = technologyBomMapper.selectById(technologyBom.getId());
         if (oldBom == null) {
-            throw new ServiceException("BOM not found");
+            throw new ServiceException("BOM涓嶅瓨鍦�");
         }
         if (oldBom.getProductModelId() != null && !oldBom.getProductModelId().equals(technologyBom.getProductModelId())) {
             technologyRoutingMapper.updateProductModelByBomId(technologyBom.getProductModelId(), technologyBom.getId().longValue());
@@ -135,12 +135,12 @@
     @Transactional(rollbackFor = Exception.class)
     public boolean batchDelete(List<Long> ids) {
         if (ids == null || ids.isEmpty()) {
-            throw new ServiceException("Select at least one BOM");
+            throw new ServiceException("璇疯嚦灏戦�夋嫨涓�涓狟OM");
         }
         List<TechnologyRouting> list = technologyRoutingMapper.selectList(Wrappers.<TechnologyRouting>lambdaQuery()
                 .in(TechnologyRouting::getBomId, ids));
         if (!list.isEmpty()) {
-            throw new ServiceException("BOM is referenced by routing");
+            throw new ServiceException("BOM宸茶宸ヨ壓璺嚎寮曠敤锛屼笉鑳藉垹闄�");
         }
         technologyBomStructureService.remove(Wrappers.<TechnologyBomStructure>lambdaQuery()
                 .in(TechnologyBomStructure::getBomId, ids));
@@ -152,11 +152,11 @@
      */
     private void validateProductModel(Long productModelId) {
         if (productModelId == null) {
-            throw new ServiceException("Product model is required");
+            throw new ServiceException("浜у搧瑙勬牸ID涓嶈兘涓虹┖");
         }
         ProductModel productModel = productModelService.getById(productModelId);
         if (productModel == null) {
-            throw new ServiceException("Product model not found");
+            throw new ServiceException("浜у搧瑙勬牸涓嶅瓨鍦�");
         }
     }
 
diff --git a/src/main/java/com/ruoyi/technology/service/impl/TechnologyOperationParamServiceImpl.java b/src/main/java/com/ruoyi/technology/service/impl/TechnologyOperationParamServiceImpl.java
index 107fa22..e8cd6c1 100644
--- a/src/main/java/com/ruoyi/technology/service/impl/TechnologyOperationParamServiceImpl.java
+++ b/src/main/java/com/ruoyi/technology/service/impl/TechnologyOperationParamServiceImpl.java
@@ -41,21 +41,21 @@
     public boolean saveTechnologyOperationParam(TechnologyOperationParam technologyOperationParam) {
         if (technologyOperationParam.getTechnologyOperationId() == null
                 || technologyOperationMapper.selectById(technologyOperationParam.getTechnologyOperationId()) == null) {
-            throw new ServiceException("Operation not found");
+            throw new ServiceException("宸ュ簭涓嶅瓨鍦�");
         }
         if (technologyOperationParam.getTechnologyParamId() == null) {
-            throw new ServiceException("Param is required");
+            throw new ServiceException("鍙傛暟ID涓嶈兘涓虹┖");
         }
         TechnologyParam technologyParam = technologyParamMapper.selectById(technologyOperationParam.getTechnologyParamId());
         if (technologyParam == null) {
-            throw new ServiceException("Param not found");
+            throw new ServiceException("鍙傛暟涓嶅瓨鍦�");
         }
         boolean duplicate = technologyOperationParamMapper.selectCount(Wrappers.<TechnologyOperationParam>lambdaQuery()
                 .eq(TechnologyOperationParam::getTechnologyOperationId, technologyOperationParam.getTechnologyOperationId())
                 .eq(TechnologyOperationParam::getTechnologyParamId, technologyOperationParam.getTechnologyParamId())
                 .ne(technologyOperationParam.getId() != null, TechnologyOperationParam::getId, technologyOperationParam.getId())) > 0;
         if (duplicate) {
-            throw new ServiceException("Duplicate param in operation");
+            throw new ServiceException("宸ュ簭鍙傛暟閲嶅");
         }
         return this.saveOrUpdate(technologyOperationParam);
     }
diff --git a/src/main/java/com/ruoyi/technology/service/impl/TechnologyParamServiceImpl.java b/src/main/java/com/ruoyi/technology/service/impl/TechnologyParamServiceImpl.java
index a3e8f5e..c30cb06 100644
--- a/src/main/java/com/ruoyi/technology/service/impl/TechnologyParamServiceImpl.java
+++ b/src/main/java/com/ruoyi/technology/service/impl/TechnologyParamServiceImpl.java
@@ -2,18 +2,22 @@
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.ruoyi.common.utils.SecurityUtils;
 import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.technology.bean.dto.TechnologyParamDto;
 import com.ruoyi.technology.bean.vo.TechnologyParamVo;
+import com.ruoyi.technology.mapper.TechnologyOperationParamMapper;
 import com.ruoyi.technology.mapper.TechnologyParamMapper;
+import com.ruoyi.technology.pojo.TechnologyOperationParam;
 import com.ruoyi.technology.pojo.TechnologyParam;
 import com.ruoyi.technology.service.TechnologyParamService;
 import lombok.RequiredArgsConstructor;
 import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
@@ -28,6 +32,7 @@
     private static final List<Integer> VALID_PARAM_TYPES = Arrays.asList(1, 2, 3, 4);
     private static final String PARAM_CODE_PREFIX = "PARAM_";
     private static final Byte DATE_PARAM_TYPE = (byte) 4;
+    private final TechnologyOperationParamMapper technologyOperationParamMapper;
 
     /**
      * 鍒嗛〉鏌ヨ鍩虹鍙傛暟骞舵牸寮忓寲鏃ユ湡绫诲瀷灞曠ず銆�
@@ -161,10 +166,13 @@
      * 鎵归噺鍒犻櫎鍩虹鍙傛暟銆�
      */
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public int deleteBaseParamByIds(Long[] ids) {
         if (ids == null || ids.length == 0) {
             throw new RuntimeException("鍒犻櫎ID涓嶈兘涓虹┖");
         }
-        return baseMapper.deleteBatchIds(Arrays.asList(ids));
+        technologyOperationParamMapper.delete(Wrappers.<TechnologyOperationParam>lambdaQuery()
+                .in(TechnologyOperationParam::getTechnologyParamId, Arrays.asList(ids)));
+        return baseMapper.deleteByIds(Arrays.asList(ids));
     }
 }

--
Gitblit v1.9.3