From 35f74c2abd95e6913180fbccd864915486eecc48 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期二, 28 四月 2026 10:18:59 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/dev_New_pro' into dev_New_pro

---
 src/main/resources/mapper/production/ProductionOrderPickRecordMapper.xml            |   15 
 src/main/java/com/ruoyi/basic/service/IProductService.java                          |    3 
 src/main/resources/mapper/basic/ProductModelMapper.xml                              |   26 +
 src/main/java/com/ruoyi/production/service/ProductionOrderPickService.java          |    9 
 src/main/java/com/ruoyi/basic/service/impl/ProductServiceImpl.java                  |    3 
 src/main/java/com/ruoyi/production/service/impl/ProductionOrderServiceImpl.java     |  103 +++-
 src/main/java/com/ruoyi/production/pojo/ProductionOrderPickRecord.java              |    4 
 src/main/java/com/ruoyi/production/service/ProductionOrderService.java              |    3 
 src/main/java/com/ruoyi/basic/pojo/ProductModel.java                                |    3 
 src/main/java/com/ruoyi/production/bean/dto/ProductionOrderPickDto.java             |   42 ++
 src/main/java/com/ruoyi/production/bean/vo/ProductionOrderPickRecordVo.java         |   25 +
 src/main/java/com/ruoyi/production/bean/vo/ProductionOrderPickVo.java               |   32 +
 src/main/java/com/ruoyi/production/controller/ProductionOrderController.java        |    7 
 src/main/java/com/ruoyi/ai/config/XiaozhiAgentConfig.java                           |   67 +--
 src/main/java/com/ruoyi/basic/controller/ProductController.java                     |    6 
 src/main/java/com/ruoyi/basic/mapper/ProductModelMapper.java                        |    3 
 src/main/java/com/ruoyi/basic/vo/ProductModelVo.java                                |   14 
 src/main/resources/mapper/stock/StockInventoryMapper.xml                            |   14 
 src/main/java/com/ruoyi/production/mapper/ProductionBomStructureMapper.java         |    6 
 src/main/resources/mapper/production/ProductionOrderPickMapper.xml                  |   18 
 src/main/java/com/ruoyi/production/controller/ProductionOrderPickController.java    |   34 +
 src/main/java/com/ruoyi/stock/mapper/StockInventoryMapper.java                      |    2 
 src/main/java/com/ruoyi/production/mapper/ProductionOrderPickRecordMapper.java      |    6 
 src/main/java/com/ruoyi/production/pojo/ProductionOrderPick.java                    |   15 
 src/main/java/com/ruoyi/production/service/impl/ProductionOrderPickServiceImpl.java |  641 +++++++++++++++++++++++++++++++++
 src/main/java/com/ruoyi/production/mapper/ProductionOrderPickMapper.java            |    5 
 src/main/resources/mapper/production/ProductionBomStructureMapper.xml               |   19 +
 27 files changed, 1,038 insertions(+), 87 deletions(-)

diff --git a/src/main/java/com/ruoyi/ai/config/XiaozhiAgentConfig.java b/src/main/java/com/ruoyi/ai/config/XiaozhiAgentConfig.java
index 58be3a6..f266a17 100644
--- a/src/main/java/com/ruoyi/ai/config/XiaozhiAgentConfig.java
+++ b/src/main/java/com/ruoyi/ai/config/XiaozhiAgentConfig.java
@@ -1,24 +1,15 @@
 package com.ruoyi.ai.config;
 
 import com.ruoyi.ai.store.MongoChatMemoryStore;
-import dev.langchain4j.data.document.Document;
-import dev.langchain4j.data.document.loader.FileSystemDocumentLoader;
-import dev.langchain4j.data.segment.TextSegment;
 import dev.langchain4j.memory.chat.ChatMemoryProvider;
 import dev.langchain4j.memory.chat.MessageWindowChatMemory;
 import dev.langchain4j.model.embedding.EmbeddingModel;
 import dev.langchain4j.rag.content.retriever.ContentRetriever;
 import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever;
 import dev.langchain4j.store.embedding.EmbeddingStore;
-import dev.langchain4j.store.embedding.EmbeddingStoreIngestor;
-import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
-
-import java.util.Collections;
-import java.util.List;
 
 /**
  * @author :yys
@@ -35,8 +26,8 @@
     @Autowired
     private EmbeddingModel embeddingModel;
 
-    @Value("${knowledge.one}")
-    private String one;
+//    @Value("${knowledge.one}")
+//    private String one;
 //
 //    @Value("${knowledge.two}")
 //    private String two;
@@ -53,33 +44,33 @@
                 .build();
     }
 
-    @Bean
-    ContentRetriever contentRetrieverXiaozhi() {
-        //浣跨敤FileSystemDocumentLoader璇诲彇鎸囧畾鐩綍涓嬬殑鐭ヨ瘑搴撴枃妗�
-        //骞朵娇鐢ㄩ粯璁ょ殑鏂囨。瑙f瀽鍣ㄥ鏂囨。杩涜瑙f瀽
-        Document document1 = FileSystemDocumentLoader.loadDocument(one);
-//        Document document2 = FileSystemDocumentLoader.loadDocument(two);
-//        Document document3 = FileSystemDocumentLoader.loadDocument(three);
-//        List<Document> documents = Arrays.asList(document1, document2, document3);
-
-        List<Document> documents = Collections.singletonList(document1);
-//         2. 灏嗘暟鎹簱鏁版嵁杞负LangChain4j鐨凞ocument瀵硅薄
-//        List<Document> documents = new ArrayList<>();
-
-        //浣跨敤鍐呭瓨鍚戦噺瀛樺偍
-        InMemoryEmbeddingStore<TextSegment> inMemoryEmbeddingStore = new InMemoryEmbeddingStore<>();
-        //浣跨敤榛樿鐨勬枃妗e垎鍓插櫒
-        EmbeddingStoreIngestor.builder()
-                .embeddingModel(embeddingModel)
-                .embeddingStore(inMemoryEmbeddingStore)
-                .build()
-                .ingest(documents);
-        //浠庡祵鍏ュ瓨鍌紙EmbeddingStore锛夐噷妫�绱㈠拰鏌ヨ鍐呭鐩稿叧鐨勪俊鎭�
-        return EmbeddingStoreContentRetriever.builder()
-                .embeddingModel(embeddingModel)
-                .embeddingStore(inMemoryEmbeddingStore)
-                .build();
-    }
+//    @Bean
+//    ContentRetriever contentRetrieverXiaozhi() {
+//        //浣跨敤FileSystemDocumentLoader璇诲彇鎸囧畾鐩綍涓嬬殑鐭ヨ瘑搴撴枃妗�
+//        //骞朵娇鐢ㄩ粯璁ょ殑鏂囨。瑙f瀽鍣ㄥ鏂囨。杩涜瑙f瀽
+////        Document document1 = FileSystemDocumentLoader.loadDocument(one);
+////        Document document2 = FileSystemDocumentLoader.loadDocument(two);
+////        Document document3 = FileSystemDocumentLoader.loadDocument(three);
+////        List<Document> documents = Arrays.asList(document1, document2, document3);
+//
+////        List<Document> documents = Collections.singletonList(document1);
+////         2. 灏嗘暟鎹簱鏁版嵁杞负LangChain4j鐨凞ocument瀵硅薄
+////        List<Document> documents = new ArrayList<>();
+//
+//        //浣跨敤鍐呭瓨鍚戦噺瀛樺偍
+//        InMemoryEmbeddingStore<TextSegment> inMemoryEmbeddingStore = new InMemoryEmbeddingStore<>();
+//        //浣跨敤榛樿鐨勬枃妗e垎鍓插櫒
+//        EmbeddingStoreIngestor.builder()
+//                .embeddingModel(embeddingModel)
+//                .embeddingStore(inMemoryEmbeddingStore)
+//                .build()
+//                .ingest(documents);
+//        //浠庡祵鍏ュ瓨鍌紙EmbeddingStore锛夐噷妫�绱㈠拰鏌ヨ鍐呭鐩稿叧鐨勪俊鎭�
+//        return EmbeddingStoreContentRetriever.builder()
+//                .embeddingModel(embeddingModel)
+//                .embeddingStore(inMemoryEmbeddingStore)
+//                .build();
+//    }
 
     @Bean
     ContentRetriever contentRetrieverXiaozhiPincone() {
diff --git a/src/main/java/com/ruoyi/basic/controller/ProductController.java b/src/main/java/com/ruoyi/basic/controller/ProductController.java
index 77334e0..1c5224b 100644
--- a/src/main/java/com/ruoyi/basic/controller/ProductController.java
+++ b/src/main/java/com/ruoyi/basic/controller/ProductController.java
@@ -10,6 +10,7 @@
 import com.ruoyi.basic.pojo.ProductModel;
 import com.ruoyi.basic.service.IProductModelService;
 import com.ruoyi.basic.service.IProductService;
+import com.ruoyi.basic.vo.ProductModelVo;
 import com.ruoyi.common.utils.poi.ExcelUtil;
 import com.ruoyi.framework.aspectj.lang.annotation.Log;
 import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
@@ -17,11 +18,8 @@
 import com.ruoyi.framework.web.domain.AjaxResult;
 import com.ruoyi.sales.pojo.SalesLedgerProduct;
 import com.ruoyi.sales.service.ISalesLedgerProductService;
-import com.ruoyi.sales.service.ISalesLedgerService;
-import io.swagger.v3.oas.annotations.tags.Tag;
 import io.swagger.v3.oas.annotations.Operation;
 import lombok.AllArgsConstructor;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 
@@ -118,7 +116,7 @@
 
     @Operation(summary = "鍒嗛〉鏌ヨ鎵�鏈変骇鍝佸瀷鍙�")
     @GetMapping("/pageModel")
-    public IPage<ProductModel> listPageProductModel(Page<ProductModel> page, ProductModel productModel) {
+    public IPage<ProductModelVo> listPageProductModel(Page<ProductModelVo> page, ProductModel productModel) {
         return productService.listPageProductModel(page, productModel);
     }
 
diff --git a/src/main/java/com/ruoyi/basic/mapper/ProductModelMapper.java b/src/main/java/com/ruoyi/basic/mapper/ProductModelMapper.java
index bddcca4..36876d0 100644
--- a/src/main/java/com/ruoyi/basic/mapper/ProductModelMapper.java
+++ b/src/main/java/com/ruoyi/basic/mapper/ProductModelMapper.java
@@ -4,6 +4,7 @@
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.ruoyi.basic.pojo.ProductModel;
+import com.ruoyi.basic.vo.ProductModelVo;
 import com.ruoyi.procurementrecord.dto.ProcurementPageDto;
 import org.apache.ibatis.annotations.Param;
 
@@ -19,7 +20,7 @@
  */
 public interface ProductModelMapper extends BaseMapper<ProductModel> {
 
-    IPage<ProductModel> listPageProductModel(Page<ProductModel> page, @Param("c") ProductModel productModel);
+    IPage<ProductModelVo> listPageProductModel(Page<ProductModelVo> page, @Param("c") ProductModel productModel);
 
     IPage<ProductModel> listPageProductionStock(Page<ProductModel> page, @Param("req") ProcurementPageDto req);
 
diff --git a/src/main/java/com/ruoyi/basic/pojo/ProductModel.java b/src/main/java/com/ruoyi/basic/pojo/ProductModel.java
index 1e21583..0ec51b2 100644
--- a/src/main/java/com/ruoyi/basic/pojo/ProductModel.java
+++ b/src/main/java/com/ruoyi/basic/pojo/ProductModel.java
@@ -5,12 +5,13 @@
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 
+import java.io.Serializable;
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
 
 @Data
 @TableName("product_model")
-public class ProductModel {
+public class ProductModel implements Serializable {
 
     private static final long serialVersionUID = 1L;
 
diff --git a/src/main/java/com/ruoyi/basic/service/IProductService.java b/src/main/java/com/ruoyi/basic/service/IProductService.java
index 7fba662..1abaad4 100644
--- a/src/main/java/com/ruoyi/basic/service/IProductService.java
+++ b/src/main/java/com/ruoyi/basic/service/IProductService.java
@@ -7,6 +7,7 @@
 import com.ruoyi.basic.dto.ProductTreeDto;
 import com.ruoyi.basic.pojo.Product;
 import com.ruoyi.basic.pojo.ProductModel;
+import com.ruoyi.basic.vo.ProductModelVo;
 
 import java.util.List;
 
@@ -18,5 +19,5 @@
 
     List<ProductTreeDto> selectProductList(ProductDto productDto);
 
-    IPage<ProductModel> listPageProductModel(Page<ProductModel> page, ProductModel productModel);
+    IPage<ProductModelVo> listPageProductModel(Page<ProductModelVo> page, ProductModel productModel);
 }
diff --git a/src/main/java/com/ruoyi/basic/service/impl/ProductServiceImpl.java b/src/main/java/com/ruoyi/basic/service/impl/ProductServiceImpl.java
index 437f804..5a7f679 100644
--- a/src/main/java/com/ruoyi/basic/service/impl/ProductServiceImpl.java
+++ b/src/main/java/com/ruoyi/basic/service/impl/ProductServiceImpl.java
@@ -12,6 +12,7 @@
 import com.ruoyi.basic.pojo.Product;
 import com.ruoyi.basic.pojo.ProductModel;
 import com.ruoyi.basic.service.IProductService;
+import com.ruoyi.basic.vo.ProductModelVo;
 import com.ruoyi.common.utils.bean.BeanUtils;
 import com.ruoyi.common.utils.poi.ExcelUtil;
 import com.ruoyi.framework.web.domain.AjaxResult;
@@ -56,7 +57,7 @@
     }
 
     @Override
-    public IPage<ProductModel> listPageProductModel(Page<ProductModel> page, ProductModel productModel) {
+    public IPage<ProductModelVo> listPageProductModel(Page<ProductModelVo> page, ProductModel productModel) {
         return productModelMapper.listPageProductModel(page, productModel);
     }
 
diff --git a/src/main/java/com/ruoyi/basic/vo/ProductModelVo.java b/src/main/java/com/ruoyi/basic/vo/ProductModelVo.java
new file mode 100644
index 0000000..cdcd893
--- /dev/null
+++ b/src/main/java/com/ruoyi/basic/vo/ProductModelVo.java
@@ -0,0 +1,14 @@
+package com.ruoyi.basic.vo;
+
+import com.ruoyi.basic.pojo.ProductModel;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.List;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class ProductModelVo extends ProductModel {
+
+    private List<String> batchNoList;
+}
diff --git a/src/main/java/com/ruoyi/production/bean/dto/ProductionOrderPickDto.java b/src/main/java/com/ruoyi/production/bean/dto/ProductionOrderPickDto.java
new file mode 100644
index 0000000..0c7f5cc
--- /dev/null
+++ b/src/main/java/com/ruoyi/production/bean/dto/ProductionOrderPickDto.java
@@ -0,0 +1,42 @@
+package com.ruoyi.production.bean.dto;
+
+import com.fasterxml.jackson.annotation.JsonAlias;
+import com.ruoyi.production.pojo.ProductionOrderPick;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+@Data
+@Schema(name = "ProductionOrderPickDto", description = "鐢熶骇璁㈠崟棰嗘枡淇濆瓨鍙傛暟")
+public class ProductionOrderPickDto extends ProductionOrderPick {
+
+    @Schema(description = "鐢熶骇璁㈠崟ID")
+    private Long productionOrderId;
+
+    @Schema(description = "鐢熶骇宸ュ崟ID")
+    private Long productionOperationTaskId;
+
+    @Schema(description = "鎵瑰彿")
+    private String batchNo;
+
+    @Schema(description = "鎵瑰彿鍒楄〃")
+    private List<String> batchNoList;
+
+    @Schema(description = "棰嗘枡鏁伴噺")
+    private BigDecimal pickQuantity;
+
+    @Schema(description = "棰嗘枡绫诲瀷锛�1姝e父棰嗘枡锛�2琛ユ枡")
+    private Byte pickType;
+
+    @Schema(description = "澶囨敞")
+    private String remark;
+
+    @Schema(description = "棰嗘枡鏄庣粏鍒楄〃")
+    @JsonAlias({"dto", "productionOrderPickDto"})
+    private List<ProductionOrderPickDto> pickList;
+
+    @Schema(description = "闇�瑕佸垹闄ょ殑棰嗘枡ID鍒楄〃")
+    private List<Long> deletePickIds;
+}
diff --git a/src/main/java/com/ruoyi/production/bean/vo/ProductionOrderPickRecordVo.java b/src/main/java/com/ruoyi/production/bean/vo/ProductionOrderPickRecordVo.java
new file mode 100644
index 0000000..b88aa8a
--- /dev/null
+++ b/src/main/java/com/ruoyi/production/bean/vo/ProductionOrderPickRecordVo.java
@@ -0,0 +1,25 @@
+package com.ruoyi.production.bean.vo;
+
+import com.ruoyi.production.pojo.ProductionOrderPickRecord;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@Schema(name = "ProductionOrderPickRecordVo", description = "宸查鏂欒鎯�")
+public class ProductionOrderPickRecordVo extends ProductionOrderPickRecord {
+
+    @Schema(description = "宸ュ簭鍚嶇О")
+    private String operationName;
+
+    @Schema(description = "浜у搧鍚嶇О")
+    private String productName;
+
+    @Schema(description = "鍨嬪彿")
+    private String model;
+
+    @Schema(description = "鍗曚綅")
+    private String unit;
+}
+
diff --git a/src/main/java/com/ruoyi/production/bean/vo/ProductionOrderPickVo.java b/src/main/java/com/ruoyi/production/bean/vo/ProductionOrderPickVo.java
new file mode 100644
index 0000000..d072634
--- /dev/null
+++ b/src/main/java/com/ruoyi/production/bean/vo/ProductionOrderPickVo.java
@@ -0,0 +1,32 @@
+package com.ruoyi.production.bean.vo;
+
+import com.ruoyi.production.pojo.ProductionOrderPick;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class ProductionOrderPickVo extends ProductionOrderPick {
+
+    @Schema(description = "鍗曚綅")
+    private String unit;
+
+    @Schema(description = "搴撳瓨鏁伴噺")
+    private BigDecimal stockQuantity;
+
+    @Schema(description = "棰嗙敤鏁伴噺")
+    private BigDecimal pickQuantity;
+
+    @Schema(description = "浜у搧鍚嶇О")
+    private String productName;
+
+    @Schema(description = "瑙勬牸鍨嬪彿")
+    private String model;
+
+    @Schema(description = "鎵瑰彿")
+    private List<String> batchNoList;
+}
diff --git a/src/main/java/com/ruoyi/production/controller/ProductionOrderController.java b/src/main/java/com/ruoyi/production/controller/ProductionOrderController.java
index 60ce243..c152736 100644
--- a/src/main/java/com/ruoyi/production/controller/ProductionOrderController.java
+++ b/src/main/java/com/ruoyi/production/controller/ProductionOrderController.java
@@ -4,6 +4,7 @@
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.ruoyi.framework.web.domain.R;
 import com.ruoyi.production.bean.dto.ProductionOrderDto;
+import com.ruoyi.production.bean.vo.ProductionOrderPickVo;
 import com.ruoyi.production.bean.vo.ProductionOrderVo;
 import com.ruoyi.production.bean.vo.ProductionPlanVo;
 import com.ruoyi.production.pojo.ProductionOrder;
@@ -75,4 +76,10 @@
     public R<List<ProductionPlanVo>> getSource(@PathVariable Long id) {
         return R.ok(productionOrderService.getSource(id));
     }
+
+    @GetMapping("/pick/{productionOrderId}")
+    @Operation(summary = "鏍规嵁璁㈠崟id鏌ヨbom棰嗘枡鍗�")
+    public R<List<ProductionOrderPickVo>> pick(@PathVariable Long productionOrderId) {
+        return R.ok(productionOrderService.pick(productionOrderId));
+    }
 }
diff --git a/src/main/java/com/ruoyi/production/controller/ProductionOrderPickController.java b/src/main/java/com/ruoyi/production/controller/ProductionOrderPickController.java
index 7f48ba7..a8e2d2e 100644
--- a/src/main/java/com/ruoyi/production/controller/ProductionOrderPickController.java
+++ b/src/main/java/com/ruoyi/production/controller/ProductionOrderPickController.java
@@ -1,7 +1,15 @@
 package com.ruoyi.production.controller;
 
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.framework.web.domain.R;
+import com.ruoyi.production.bean.dto.ProductionOrderPickDto;
+import com.ruoyi.production.bean.vo.ProductionOrderPickVo;
+import com.ruoyi.production.service.ProductionOrderPickService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
 
 /**
  * <p>
@@ -13,6 +21,28 @@
  */
 @RestController
 @RequestMapping("/productionOrderPick")
+@Tag(name = "鐢熶骇璁㈠崟棰嗘枡")
+@RequiredArgsConstructor
 public class ProductionOrderPickController {
 
+    private final ProductionOrderPickService productionOrderPickService;
+
+    @PostMapping("/savePick")
+    @Operation(summary = "棰嗘枡淇濆瓨鍒扮嚎杈逛粨")
+    public R<Boolean> savePick(@RequestBody ProductionOrderPickDto dto) {
+        return R.ok(productionOrderPickService.savePick(dto));
+    }
+
+    @PostMapping("/updatePick")
+    @Operation(summary = "鍙樻洿棰嗘枡")
+    public R<Boolean> updatePick(@RequestBody ProductionOrderPickDto dto) {
+        return R.ok(productionOrderPickService.updatePick(dto));
+    }
+
+    @GetMapping("/detail/{productionOrderId}")
+    @Operation(summary = "鏌ヨ宸查鏂欒鎯�")
+    public R<List<ProductionOrderPickVo>> listPickedDetail(@PathVariable Long productionOrderId) {
+        return R.ok(productionOrderPickService.listPickedDetail(productionOrderId));
+    }
 }
+
diff --git a/src/main/java/com/ruoyi/production/mapper/ProductionBomStructureMapper.java b/src/main/java/com/ruoyi/production/mapper/ProductionBomStructureMapper.java
index 17c1c99..bb9ad78 100644
--- a/src/main/java/com/ruoyi/production/mapper/ProductionBomStructureMapper.java
+++ b/src/main/java/com/ruoyi/production/mapper/ProductionBomStructureMapper.java
@@ -21,4 +21,10 @@
 
     List<ProductionBomStructureVo> listByBomId(@Param("bomId") Long bomId);
 
+    /**
+     * 棰嗘枡bom
+     * @param bomId
+     * @return
+     */
+    List<ProductionBomStructureVo> pickByBomId(@Param("bomId") Long bomId);
 }
diff --git a/src/main/java/com/ruoyi/production/mapper/ProductionOrderPickMapper.java b/src/main/java/com/ruoyi/production/mapper/ProductionOrderPickMapper.java
index 95c4324..3f2b9cc 100644
--- a/src/main/java/com/ruoyi/production/mapper/ProductionOrderPickMapper.java
+++ b/src/main/java/com/ruoyi/production/mapper/ProductionOrderPickMapper.java
@@ -1,8 +1,12 @@
 package com.ruoyi.production.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.production.bean.vo.ProductionOrderPickVo;
 import com.ruoyi.production.pojo.ProductionOrderPick;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
 
 /**
  * <p>
@@ -15,4 +19,5 @@
 @Mapper
 public interface ProductionOrderPickMapper extends BaseMapper<ProductionOrderPick> {
 
+    List<ProductionOrderPickVo> listPickedDetailByOrderId(@Param("productionOrderId") Long productionOrderId);
 }
diff --git a/src/main/java/com/ruoyi/production/mapper/ProductionOrderPickRecordMapper.java b/src/main/java/com/ruoyi/production/mapper/ProductionOrderPickRecordMapper.java
index 711f244..dc909cd 100644
--- a/src/main/java/com/ruoyi/production/mapper/ProductionOrderPickRecordMapper.java
+++ b/src/main/java/com/ruoyi/production/mapper/ProductionOrderPickRecordMapper.java
@@ -1,8 +1,12 @@
 package com.ruoyi.production.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.production.bean.vo.ProductionOrderPickVo;
 import com.ruoyi.production.pojo.ProductionOrderPickRecord;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
 
 /**
  * <p>
@@ -15,4 +19,6 @@
 @Mapper
 public interface ProductionOrderPickRecordMapper extends BaseMapper<ProductionOrderPickRecord> {
 
+    List<ProductionOrderPickVo> listPickedDetailByOrderId(@Param("productionOrderId") Long productionOrderId);
 }
+
diff --git a/src/main/java/com/ruoyi/production/pojo/ProductionOrderPick.java b/src/main/java/com/ruoyi/production/pojo/ProductionOrderPick.java
index e0180e1..a15270c 100644
--- a/src/main/java/com/ruoyi/production/pojo/ProductionOrderPick.java
+++ b/src/main/java/com/ruoyi/production/pojo/ProductionOrderPick.java
@@ -28,7 +28,7 @@
     private Long id;
 
     @Schema(description = "浜у搧瑙勬牸id")
-    private Integer productModelId;
+    private Long productModelId;
 
     @Schema(description = "鏁伴噺")
     private BigDecimal quantity;
@@ -56,4 +56,17 @@
     @Schema(description = "閮ㄩ棬ID")
     @TableField(fill = FieldFill.INSERT)
     private Long deptId;
+
+    @Schema(description = "宸ュ簭鍚嶇О")
+    private String operationName;
+
+    @Schema(description = "宸ュ簭id")
+    private Long technologyOperationId;
+
+    @Schema(description = "闇�姹傛暟閲�")
+    private BigDecimal demandedQuantity;
+
+    @Schema(description = "鏄惁bom棰嗘枡")
+    @TableField("is_bom")
+    private Boolean bom;
 }
diff --git a/src/main/java/com/ruoyi/production/pojo/ProductionOrderPickRecord.java b/src/main/java/com/ruoyi/production/pojo/ProductionOrderPickRecord.java
index dc610c2..75bf484 100644
--- a/src/main/java/com/ruoyi/production/pojo/ProductionOrderPickRecord.java
+++ b/src/main/java/com/ruoyi/production/pojo/ProductionOrderPickRecord.java
@@ -3,8 +3,6 @@
 import com.baomidou.mybatisplus.annotation.*;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
-import lombok.Getter;
-import lombok.Setter;
 
 import java.io.Serializable;
 import java.math.BigDecimal;
@@ -39,7 +37,7 @@
     private Long productionOperationTaskId;
 
     @Schema(description = "浜у搧瑙勬牸id")
-    private Integer productModelId;
+    private Long productModelId;
 
     @Schema(description = "鎵瑰彿")
     private String batchNo;
diff --git a/src/main/java/com/ruoyi/production/service/ProductionOrderPickService.java b/src/main/java/com/ruoyi/production/service/ProductionOrderPickService.java
index acffc16..82ee298 100644
--- a/src/main/java/com/ruoyi/production/service/ProductionOrderPickService.java
+++ b/src/main/java/com/ruoyi/production/service/ProductionOrderPickService.java
@@ -1,7 +1,11 @@
 package com.ruoyi.production.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.production.bean.dto.ProductionOrderPickDto;
+import com.ruoyi.production.bean.vo.ProductionOrderPickVo;
 import com.ruoyi.production.pojo.ProductionOrderPick;
+
+import java.util.List;
 
 /**
  * <p>
@@ -13,4 +17,9 @@
  */
 public interface ProductionOrderPickService extends IService<ProductionOrderPick> {
 
+    Boolean savePick(ProductionOrderPickDto dto);
+
+    Boolean updatePick(ProductionOrderPickDto dto);
+
+    List<ProductionOrderPickVo> listPickedDetail(Long productionOrderId);
 }
diff --git a/src/main/java/com/ruoyi/production/service/ProductionOrderService.java b/src/main/java/com/ruoyi/production/service/ProductionOrderService.java
index 95d3fc4..fa1186c 100644
--- a/src/main/java/com/ruoyi/production/service/ProductionOrderService.java
+++ b/src/main/java/com/ruoyi/production/service/ProductionOrderService.java
@@ -4,6 +4,7 @@
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.ruoyi.production.bean.dto.ProductionOrderDto;
+import com.ruoyi.production.bean.vo.ProductionOrderPickVo;
 import com.ruoyi.production.bean.vo.ProductionOrderVo;
 import com.ruoyi.production.bean.vo.ProductionPlanVo;
 import com.ruoyi.production.pojo.ProductionOrder;
@@ -27,4 +28,6 @@
     Object bindingRoute(ProductionOrderDto productionOrderDto);
 
     List<ProductionPlanVo> getSource(Long id);
+
+    List<ProductionOrderPickVo> pick(Long productionOrderId);
 }
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 b4e3826..8f2f728 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductionOrderPickServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionOrderPickServiceImpl.java
@@ -1,20 +1,657 @@
 package com.ruoyi.production.service.impl;
 
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.production.bean.dto.ProductionOrderPickDto;
+import com.ruoyi.production.bean.vo.ProductionOrderPickVo;
+import com.ruoyi.production.mapper.ProductionOperationTaskMapper;
+import com.ruoyi.production.mapper.ProductionOrderMapper;
 import com.ruoyi.production.mapper.ProductionOrderPickMapper;
+import com.ruoyi.production.mapper.ProductionOrderPickRecordMapper;
+import com.ruoyi.production.pojo.ProductionOrder;
 import com.ruoyi.production.pojo.ProductionOrderPick;
+import com.ruoyi.production.pojo.ProductionOrderPickRecord;
 import com.ruoyi.production.service.ProductionOrderPickService;
+import com.ruoyi.stock.dto.StockInventoryDto;
+import com.ruoyi.stock.mapper.StockInventoryMapper;
+import com.ruoyi.stock.pojo.StockInventory;
+import lombok.RequiredArgsConstructor;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.math.BigDecimal;
+import java.util.*;
+import java.util.function.Function;
+import java.util.stream.Collectors;
 
 /**
  * <p>
- * 璁㈠崟棰嗘枡绾胯竟浠� 鏈嶅姟瀹炵幇绫�
+ * 鐠併垹宕熸0鍡樻灐缁捐儻绔熸禒?閺堝秴濮熺�圭偟骞囩猾?
  * </p>
  *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @author 閼侯垰顕辨潪顖欐閿涘牊鐫欓懟蹇ョ礆閺堝妾洪崗顒�寰�
  * @since 2026-04-21 03:55:52
  */
 @Service
+@RequiredArgsConstructor
 public class ProductionOrderPickServiceImpl extends ServiceImpl<ProductionOrderPickMapper, ProductionOrderPick> implements ProductionOrderPickService {
 
+    private final ProductionOrderMapper productionOrderMapper;
+    private final ProductionOperationTaskMapper productionOperationTaskMapper;
+    private final ProductionOrderPickRecordMapper productionOrderPickRecordMapper;
+    private final StockInventoryMapper stockInventoryMapper;
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean savePick(ProductionOrderPickDto dto) {
+        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(), inventoryBatchNo, resolvedDto.getPickQuantity(), rowNo);
+
+            ProductionOrderPick orderPick = new ProductionOrderPick();
+            orderPick.setProductionOrderId(resolvedDto.getProductionOrderId());
+            orderPick.setProductModelId(resolvedDto.getProductModelId());
+            orderPick.setBatchNo(storedBatchNo);
+            orderPick.setQuantity(resolvedDto.getPickQuantity());
+            orderPick.setRemark(resolvedDto.getRemark());
+            orderPick.setOperationName(resolvedDto.getOperationName());
+            orderPick.setTechnologyOperationId(resolvedDto.getTechnologyOperationId());
+            orderPick.setDemandedQuantity(resolvedDto.getDemandedQuantity());
+            orderPick.setBom(resolvedDto.getBom());
+            baseMapper.insert(orderPick);
+
+            insertPickRecord(orderPick.getId(),
+                    resolvedDto.getProductionOrderId(),
+                    resolvedDto.getProductionOperationTaskId(),
+                    resolvedDto.getProductModelId(),
+                    inventoryBatchNo,
+                    resolvedDto.getPickQuantity(),
+                    BigDecimal.ZERO,
+                    resolvedDto.getPickQuantity(),
+                    resolvedDto.getPickType(),
+                    resolvedDto.getRemark());
+        }
+        return true;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean updatePick(ProductionOrderPickDto dto) {
+        if (dto == null) {
+            throw new ServiceException("鍙樻洿鍙傛暟涓嶈兘涓虹┖");
+        }
+        Long productionOrderId = resolveProductionOrderId(dto);
+        if (productionOrderId == null) {
+            throw new ServiceException("鐢熶骇璁㈠崟ID涓嶈兘涓虹┖");
+        }
+        ProductionOrder productionOrder = productionOrderMapper.selectById(productionOrderId);
+        if (productionOrder == null) {
+            throw new ServiceException("鐢熶骇璁㈠崟涓嶅瓨鍦�");
+        }
+
+        List<ProductionOrderPick> existingPickList = baseMapper.selectList(
+                Wrappers.<ProductionOrderPick>lambdaQuery()
+                        .eq(ProductionOrderPick::getProductionOrderId, productionOrderId));
+        Map<Long, ProductionOrderPick> existingPickMap = existingPickList.stream()
+                .filter(item -> item.getId() != null)
+                .collect(Collectors.toMap(ProductionOrderPick::getId, Function.identity(), (a, b) -> a));
+
+        processDeletePickIds(dto, existingPickMap, productionOrderId);
+
+        List<ProductionOrderPickDto> pickItems = resolveUpdateItems(dto);
+        Set<Long> keepPickIdSet = new HashSet<>();
+        for (int i = 0; i < pickItems.size(); i++) {
+            int rowNo = i + 1;
+            ProductionOrderPickDto resolvedDto = mergeDto(dto, pickItems.get(i));
+            if (isEmptyUpdateItem(resolvedDto)) {
+                continue;
+            }
+            if (resolvedDto.getProductionOrderId() == null) {
+                resolvedDto.setProductionOrderId(productionOrderId);
+            }
+            validatePickParam(resolvedDto, rowNo);
+
+            if (resolvedDto.getId() == null) {
+                addNewPickInUpdate(resolvedDto, rowNo);
+                continue;
+            }
+            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();
+        }
+        List<ProductionOrderPickVo> detailList = baseMapper.listPickedDetailByOrderId(productionOrderId);
+        fillBatchNoList(detailList);
+        fillSelectableBatchNoList(detailList);
+        return detailList;
+    }
+
+    private void processDeletePickIds(ProductionOrderPickDto rootDto,
+                                      Map<Long, ProductionOrderPick> existingPickMap,
+                                      Long productionOrderId) {
+        if (rootDto.getDeletePickIds() == null || rootDto.getDeletePickIds().isEmpty()) {
+            return;
+        }
+        Set<Long> deleteIdSet = new LinkedHashSet<>(rootDto.getDeletePickIds());
+        for (Long deleteId : deleteIdSet) {
+            if (deleteId == null) {
+                continue;
+            }
+            ProductionOrderPick existingPick = existingPickMap.get(deleteId);
+            if (existingPick == null || !Objects.equals(existingPick.getProductionOrderId(), productionOrderId)) {
+                throw new ServiceException("瑕佸垹闄ょ殑棰嗘枡璁板綍涓嶅瓨鍦ㄦ垨涓嶅睘浜庡綋鍓嶈鍗曪紝ID=" + 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);
+            }
+            insertPickRecord(existingPick.getId(),
+                    existingPick.getProductionOrderId(),
+                    rootDto.getProductionOperationTaskId(),
+                    existingPick.getProductModelId(),
+                    oldBatchNo,
+                    oldQuantity,
+                    oldQuantity,
+                    BigDecimal.ZERO,
+                    rootDto.getPickType(),
+                    rootDto.getRemark());
+            existingPickMap.remove(deleteId);
+        }
+    }
+
+    private void processMissingPickItems(ProductionOrderPickDto rootDto,
+                                         Map<Long, ProductionOrderPick> existingPickMap,
+                                         Long productionOrderId,
+                                         Set<Long> keepPickIdSet) {
+        if (rootDto.getPickList() == null) {
+            return;
+        }
+        List<ProductionOrderPick> missingPickList = existingPickMap.values().stream()
+                .filter(Objects::nonNull)
+                .filter(item -> item.getId() != null)
+                .filter(item -> Objects.equals(item.getProductionOrderId(), productionOrderId))
+                .filter(item -> !keepPickIdSet.contains(item.getId()))
+                .collect(Collectors.toList());
+        for (ProductionOrderPick missingPick : missingPickList) {
+            String oldBatchNo = resolveInventoryBatchNoFromStored(missingPick.getBatchNo());
+            BigDecimal oldQuantity = defaultDecimal(missingPick.getQuantity());
+            addInventory(missingPick.getProductModelId(), oldBatchNo, oldQuantity);
+            int affected = baseMapper.deleteById(missingPick.getId());
+            if (affected <= 0) {
+                throw new ServiceException("鍒犻櫎棰嗘枡澶辫触锛孖D=" + missingPick.getId());
+            }
+            insertPickRecord(missingPick.getId(),
+                    missingPick.getProductionOrderId(),
+                    rootDto.getProductionOperationTaskId(),
+                    missingPick.getProductModelId(),
+                    oldBatchNo,
+                    oldQuantity,
+                    oldQuantity,
+                    BigDecimal.ZERO,
+                    rootDto.getPickType(),
+                    rootDto.getRemark());
+            existingPickMap.remove(missingPick.getId());
+        }
+    }
+
+    private void addNewPickInUpdate(ProductionOrderPickDto dto, int rowNo) {
+        List<String> batchNoList = resolveBatchNoList(dto);
+        String inventoryBatchNo = pickInventoryBatchNo(batchNoList);
+        String storedBatchNo = formatBatchNoStorage(batchNoList);
+        subtractInventory(dto.getProductModelId(), inventoryBatchNo, dto.getPickQuantity(), rowNo);
+
+        ProductionOrderPick orderPick = new ProductionOrderPick();
+        orderPick.setProductionOrderId(dto.getProductionOrderId());
+        orderPick.setProductModelId(dto.getProductModelId());
+        orderPick.setBatchNo(storedBatchNo);
+        orderPick.setQuantity(dto.getPickQuantity());
+        orderPick.setRemark(dto.getRemark());
+        orderPick.setOperationName(dto.getOperationName());
+        orderPick.setTechnologyOperationId(dto.getTechnologyOperationId());
+        orderPick.setDemandedQuantity(dto.getDemandedQuantity());
+        orderPick.setBom(dto.getBom());
+        baseMapper.insert(orderPick);
+
+        insertPickRecord(orderPick.getId(),
+                dto.getProductionOrderId(),
+                dto.getProductionOperationTaskId(),
+                dto.getProductModelId(),
+                inventoryBatchNo,
+                dto.getPickQuantity(),
+                BigDecimal.ZERO,
+                dto.getPickQuantity(),
+                dto.getPickType(),
+                dto.getRemark());
+    }
+
+    private void updateExistingPick(ProductionOrderPickDto dto,
+                                    int rowNo,
+                                    Map<Long, ProductionOrderPick> existingPickMap) {
+        ProductionOrderPick oldPick = existingPickMap.get(dto.getId());
+        if (oldPick == null || !Objects.equals(oldPick.getProductionOrderId(), dto.getProductionOrderId())) {
+            throw new ServiceException("绗�" + rowNo + "鏉¢鏂欒褰曚笉瀛樺湪鎴栦笉灞炰簬褰撳墠璁㈠崟");
+        }
+
+        Long oldProductModelId = oldPick.getProductModelId();
+        String oldBatchNo = resolveInventoryBatchNoFromStored(oldPick.getBatchNo());
+        BigDecimal oldQuantity = defaultDecimal(oldPick.getQuantity());
+
+        Long newProductModelId = dto.getProductModelId();
+        List<String> newBatchNoList = resolveBatchNoList(dto);
+        String newBatchNo = pickInventoryBatchNo(newBatchNoList);
+        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, newBatchNo, delta, rowNo);
+            } else if (delta.compareTo(BigDecimal.ZERO) < 0) {
+                addInventory(oldProductModelId, oldBatchNo, delta.abs());
+            }
+        } else {
+            addInventory(oldProductModelId, oldBatchNo, oldQuantity);
+            subtractInventory(newProductModelId, newBatchNo, newQuantity, rowNo);
+        }
+
+        oldPick.setProductModelId(newProductModelId);
+        oldPick.setBatchNo(newStoredBatchNo);
+        oldPick.setQuantity(newQuantity);
+        oldPick.setRemark(dto.getRemark());
+        oldPick.setOperationName(dto.getOperationName());
+        oldPick.setTechnologyOperationId(dto.getTechnologyOperationId());
+        if (dto.getDemandedQuantity() != null) {
+            oldPick.setDemandedQuantity(dto.getDemandedQuantity());
+        }
+        if (dto.getBom() != null) {
+            oldPick.setBom(dto.getBom());
+        }
+        int affected = baseMapper.updateById(oldPick);
+        if (affected <= 0) {
+            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(),
+                    dto.getProductionOrderId(),
+                    dto.getProductionOperationTaskId(),
+                    newProductModelId,
+                    newBatchNo,
+                    recordQuantity,
+                    oldQuantity,
+                    newQuantity,
+                    dto.getPickType(),
+                    dto.getRemark());
+        }
+    }
+
+    private void insertPickRecord(Long pickId,
+                                  Long productionOrderId,
+                                  Long productionOperationTaskId,
+                                  Long productModelId,
+                                  String batchNo,
+                                  BigDecimal pickQuantity,
+                                  BigDecimal beforeQuantity,
+                                  BigDecimal afterQuantity,
+                                  Byte pickType,
+                                  String remark) {
+        ProductionOrderPickRecord pickRecord = new ProductionOrderPickRecord();
+        pickRecord.setPickId(pickId);
+        pickRecord.setProductionOrderId(productionOrderId);
+        pickRecord.setProductionOperationTaskId(productionOperationTaskId);
+        pickRecord.setProductModelId(productModelId);
+        pickRecord.setBatchNo(batchNo);
+        pickRecord.setPickQuantity(defaultDecimal(pickQuantity));
+        pickRecord.setBeforeQuantity(defaultDecimal(beforeQuantity));
+        pickRecord.setAfterQuantity(defaultDecimal(afterQuantity));
+        pickRecord.setPickType(pickType == null ? (byte) 1 : pickType);
+        pickRecord.setRemark(remark);
+        productionOrderPickRecordMapper.insert(pickRecord);
+    }
+
+    private void subtractInventory(Long productModelId, String batchNo, BigDecimal quantity, int rowNo) {
+        StockInventory stockInventory = stockInventoryMapper.selectOne(buildStockWrapper(productModelId, batchNo));
+        if (stockInventory == null) {
+            throw new ServiceException("绗�" + rowNo + "鏉¢鏂欏搴斿簱瀛樹笉瀛樺湪");
+        }
+        BigDecimal availableQuantity = defaultDecimal(stockInventory.getQualitity())
+                .subtract(defaultDecimal(stockInventory.getLockedQuantity()));
+        if (quantity.compareTo(availableQuantity) > 0) {
+            throw new ServiceException("绗�" + rowNo + "鏉¢鏂欏彲鐢ㄥ簱瀛樹笉瓒�");
+        }
+        StockInventoryDto stockInventoryDto = new StockInventoryDto();
+        stockInventoryDto.setProductModelId(productModelId);
+        stockInventoryDto.setBatchNo(batchNo);
+        stockInventoryDto.setQualitity(quantity);
+        int affected = stockInventoryMapper.updateSubtractStockInventory(stockInventoryDto);
+        if (affected <= 0) {
+            throw new ServiceException("绗�" + rowNo + "鏉¢鏂欐墸鍑忓簱瀛樺け璐�");
+        }
+    }
+
+    private void addInventory(Long productModelId, String batchNo, BigDecimal quantity) {
+        BigDecimal addQuantity = defaultDecimal(quantity);
+        if (addQuantity.compareTo(BigDecimal.ZERO) <= 0) {
+            return;
+        }
+        StockInventory stockInventory = stockInventoryMapper.selectOne(buildStockWrapper(productModelId, batchNo));
+        if (stockInventory == null) {
+            StockInventory newStockInventory = new StockInventory();
+            newStockInventory.setProductModelId(productModelId);
+            newStockInventory.setBatchNo(batchNo);
+            newStockInventory.setQualitity(addQuantity);
+            newStockInventory.setLockedQuantity(BigDecimal.ZERO);
+            newStockInventory.setVersion(1);
+            stockInventoryMapper.insert(newStockInventory);
+            return;
+        }
+        StockInventoryDto stockInventoryDto = new StockInventoryDto();
+        stockInventoryDto.setProductModelId(productModelId);
+        stockInventoryDto.setBatchNo(batchNo);
+        stockInventoryDto.setQualitity(addQuantity);
+        int affected = stockInventoryMapper.updateAddStockInventory(stockInventoryDto);
+        if (affected <= 0) {
+            throw new ServiceException("搴撳瓨鍥為��澶辫触锛屼骇鍝佽鏍糏D=" + productModelId);
+        }
+    }
+
+    private List<ProductionOrderPickDto> resolvePickItems(ProductionOrderPickDto dto) {
+        if (dto == null) {
+            throw new ServiceException("棰嗘枡鍙傛暟涓嶈兘涓虹┖");
+        }
+        if (dto.getPickList() != null && !dto.getPickList().isEmpty()) {
+            return dto.getPickList();
+        }
+        return Collections.singletonList(dto);
+    }
+
+    private List<ProductionOrderPickDto> resolveUpdateItems(ProductionOrderPickDto dto) {
+        if (dto.getPickList() != null) {
+            return dto.getPickList();
+        }
+        if (isEmptyUpdateItem(dto)) {
+            return Collections.emptyList();
+        }
+        return Collections.singletonList(dto);
+    }
+
+    private boolean isEmptyUpdateItem(ProductionOrderPickDto dto) {
+        return dto.getId() == null
+                && dto.getProductModelId() == null
+                && dto.getPickQuantity() == null
+                && StringUtils.isEmpty(dto.getBatchNo())
+                && (dto.getBatchNoList() == null || dto.getBatchNoList().isEmpty())
+                && dto.getPickType() == null
+                && dto.getProductionOperationTaskId() == null
+                && dto.getTechnologyOperationId() == null
+                && StringUtils.isEmpty(dto.getOperationName())
+                && dto.getDemandedQuantity() == null
+                && dto.getBom() == null
+                && StringUtils.isEmpty(dto.getRemark());
+    }
+
+    private Long resolveProductionOrderId(ProductionOrderPickDto dto) {
+        if (dto.getProductionOrderId() != null) {
+            return dto.getProductionOrderId();
+        }
+        if (dto.getPickList() == null || dto.getPickList().isEmpty()) {
+            return null;
+        }
+        return dto.getPickList().stream()
+                .filter(Objects::nonNull)
+                .map(ProductionOrderPickDto::getProductionOrderId)
+                .filter(Objects::nonNull)
+                .findFirst()
+                .orElse(null);
+    }
+
+    private ProductionOrderPickDto mergeDto(ProductionOrderPickDto rootDto, ProductionOrderPickDto itemDto) {
+        ProductionOrderPickDto merged = new ProductionOrderPickDto();
+        if (itemDto != null) {
+            merged.setId(itemDto.getId());
+            merged.setProductionOrderId(itemDto.getProductionOrderId());
+            merged.setProductionOperationTaskId(itemDto.getProductionOperationTaskId());
+            merged.setProductModelId(itemDto.getProductModelId());
+            merged.setBatchNo(itemDto.getBatchNo());
+            merged.setBatchNoList(itemDto.getBatchNoList());
+            merged.setPickQuantity(itemDto.getPickQuantity());
+            merged.setPickType(itemDto.getPickType());
+            merged.setRemark(itemDto.getRemark());
+            merged.setTechnologyOperationId(itemDto.getTechnologyOperationId());
+            merged.setOperationName(itemDto.getOperationName());
+            merged.setDemandedQuantity(itemDto.getDemandedQuantity());
+            merged.setBom(itemDto.getBom());
+        }
+        if (merged.getId() == null) {
+            merged.setId(rootDto.getId());
+        }
+        if (merged.getProductionOrderId() == null) {
+            merged.setProductionOrderId(rootDto.getProductionOrderId());
+        }
+        if (merged.getProductionOperationTaskId() == null) {
+            merged.setProductionOperationTaskId(rootDto.getProductionOperationTaskId());
+        }
+        if (merged.getProductModelId() == null) {
+            merged.setProductModelId(rootDto.getProductModelId());
+        }
+        if (merged.getBatchNo() == null) {
+            merged.setBatchNo(rootDto.getBatchNo());
+        }
+        if (merged.getBatchNoList() == null || merged.getBatchNoList().isEmpty()) {
+            merged.setBatchNoList(rootDto.getBatchNoList());
+        }
+        if (merged.getPickQuantity() == null) {
+            merged.setPickQuantity(rootDto.getPickQuantity());
+        }
+        if (merged.getPickType() == null) {
+            merged.setPickType(rootDto.getPickType());
+        }
+        if (merged.getRemark() == null) {
+            merged.setRemark(rootDto.getRemark());
+        }
+        if (merged.getTechnologyOperationId() == null) {
+            merged.setTechnologyOperationId(rootDto.getTechnologyOperationId());
+        }
+        if (merged.getOperationName() == null) {
+            merged.setOperationName(rootDto.getOperationName());
+        }
+        if (merged.getDemandedQuantity() == null) {
+            merged.setDemandedQuantity(rootDto.getDemandedQuantity());
+        }
+        if (merged.getBom() == null) {
+            merged.setBom(rootDto.getBom());
+        }
+        return merged;
+    }
+
+    private void validatePickParam(ProductionOrderPickDto dto, int rowNo) {
+        if (dto.getProductionOrderId() == null) {
+            throw new ServiceException("绗�" + rowNo + "鏉$敓浜ц鍗旾D涓嶈兘涓虹┖");
+        }
+        if (dto.getProductModelId() == null) {
+            throw new ServiceException("绗�" + rowNo + "鏉′骇鍝佽鏍糏D涓嶈兘涓虹┖");
+        }
+        if (dto.getPickQuantity() == null || dto.getPickQuantity().compareTo(BigDecimal.ZERO) <= 0) {
+            throw new ServiceException("绗�" + rowNo + "鏉¢鏂欐暟閲忓繀椤诲ぇ浜�0");
+        }
+        if (dto.getPickType() != null && dto.getPickType() != 1 && dto.getPickType() != 2) {
+            throw new ServiceException("绗�" + rowNo + "鏉¢鏂欑被鍨嬪彧鑳芥槸1鎴�2");
+        }
+    }
+
+    private String normalizeBatchNo(String batchNo) {
+        if (StringUtils.isEmpty(batchNo)) {
+            return null;
+        }
+        String trimBatchNo = batchNo.trim();
+        return trimBatchNo.isEmpty() ? null : trimBatchNo;
+    }
+    private List<String> resolveBatchNoList(ProductionOrderPickDto dto) {
+        List<String> normalizedBatchNoList = normalizeBatchNoList(dto.getBatchNoList());
+        if (!normalizedBatchNoList.isEmpty()) {
+            return normalizedBatchNoList;
+        }
+        return parseBatchNoValue(dto.getBatchNo());
+    }
+
+    private String pickInventoryBatchNo(List<String> batchNoList) {
+        if (batchNoList == null || batchNoList.isEmpty()) {
+            return null;
+        }
+        return batchNoList.get(0);
+    }
+
+    private String resolveInventoryBatchNoFromStored(String storedBatchNo) {
+        return pickInventoryBatchNo(parseBatchNoValue(storedBatchNo));
+    }
+
+    private String formatBatchNoStorage(List<String> batchNoList) {
+        if (batchNoList == null || batchNoList.isEmpty()) {
+            return null;
+        }
+        if (batchNoList.size() == 1) {
+            return batchNoList.get(0);
+        }
+        return String.join(",", batchNoList);
+    }
+
+    private List<String> normalizeBatchNoList(List<String> batchNoList) {
+        if (batchNoList == null || batchNoList.isEmpty()) {
+            return Collections.emptyList();
+        }
+        LinkedHashSet<String> normalizedSet = new LinkedHashSet<>();
+        for (String batchNo : batchNoList) {
+            String normalizedBatchNo = normalizeBatchNo(batchNo);
+            if (!StringUtils.isEmpty(normalizedBatchNo)) {
+                normalizedSet.add(normalizedBatchNo);
+            }
+        }
+        return new ArrayList<>(normalizedSet);
+    }
+
+    private void fillBatchNoList(List<ProductionOrderPickVo> detailList) {
+        if (detailList == null || detailList.isEmpty()) {
+            return;
+        }
+        Map<String, LinkedHashSet<String>> batchNoGroupMap = new HashMap<>();
+        for (ProductionOrderPickVo detail : detailList) {
+            String key = buildBatchNoGroupKey(detail);
+            LinkedHashSet<String> batchSet = batchNoGroupMap.computeIfAbsent(key, k -> new LinkedHashSet<>());
+            batchSet.addAll(parseBatchNoValue(detail.getBatchNo()));
+            if (detail.getBatchNoList() != null && !detail.getBatchNoList().isEmpty()) {
+                batchSet.addAll(normalizeBatchNoList(detail.getBatchNoList()));
+            }
+        }
+        for (ProductionOrderPickVo detail : detailList) {
+            String key = buildBatchNoGroupKey(detail);
+            LinkedHashSet<String> batchSet = batchNoGroupMap.get(key);
+            detail.setBatchNoList(batchSet == null ? Collections.emptyList() : new ArrayList<>(batchSet));
+        }
+    }
+
+    private void fillSelectableBatchNoList(List<ProductionOrderPickVo> detailList) {
+        if (detailList == null || detailList.isEmpty()) {
+            return;
+        }
+        Set<Long> productModelIdSet = detailList.stream()
+                .map(ProductionOrderPickVo::getProductModelId)
+                .filter(Objects::nonNull)
+                .collect(Collectors.toSet());
+        if (productModelIdSet.isEmpty()) {
+            return;
+        }
+        List<StockInventory> stockBatchList = stockInventoryMapper.listSelectableBatchNoByProductModelIds(
+                new ArrayList<>(productModelIdSet));
+        Map<Long, LinkedHashSet<String>> stockBatchMap = new HashMap<>();
+        for (StockInventory stockInventory : stockBatchList) {
+            if (stockInventory == null || stockInventory.getProductModelId() == null) {
+                continue;
+            }
+            String normalizedBatchNo = normalizeBatchNo(stockInventory.getBatchNo());
+            if (StringUtils.isEmpty(normalizedBatchNo)) {
+                continue;
+            }
+            stockBatchMap.computeIfAbsent(stockInventory.getProductModelId(), k -> new LinkedHashSet<>())
+                    .add(normalizedBatchNo);
+        }
+        for (ProductionOrderPickVo detail : detailList) {
+            LinkedHashSet<String> mergedBatchSet = new LinkedHashSet<>();
+            mergedBatchSet.addAll(normalizeBatchNoList(detail.getBatchNoList()));
+            LinkedHashSet<String> selectableBatchSet = stockBatchMap.get(detail.getProductModelId());
+            if (selectableBatchSet != null) {
+                mergedBatchSet.addAll(selectableBatchSet);
+            }
+            detail.setBatchNoList(new ArrayList<>(mergedBatchSet));
+        }
+    }
+
+    private String buildBatchNoGroupKey(ProductionOrderPickVo detail) {
+        return String.valueOf(detail.getProductionOrderId()) + "|"
+                + String.valueOf(detail.getProductModelId()) + "|"
+                + String.valueOf(detail.getTechnologyOperationId()) + "|"
+                + String.valueOf(detail.getOperationName());
+    }
+
+    private List<String> parseBatchNoValue(String rawBatchNoValue) {
+        String normalizedValue = normalizeBatchNo(rawBatchNoValue);
+        if (StringUtils.isEmpty(normalizedValue)) {
+            return Collections.emptyList();
+        }
+        if (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("'", ""))
+                    .collect(Collectors.toList());
+            return normalizeBatchNoList(parsed);
+        }
+        if (normalizedValue.contains(",")) {
+            List<String> parsed = Arrays.stream(normalizedValue.split(","))
+                    .map(item -> item == null ? null : item.trim())
+                    .collect(Collectors.toList());
+            return normalizeBatchNoList(parsed);
+        }
+        return Collections.singletonList(normalizedValue);
+    }
+
+    private LambdaQueryWrapper<StockInventory> buildStockWrapper(Long productModelId, String batchNo) {
+        LambdaQueryWrapper<StockInventory> wrapper = Wrappers.<StockInventory>lambdaQuery()
+                .eq(StockInventory::getProductModelId, productModelId);
+        if (StringUtils.isEmpty(batchNo)) {
+            wrapper.isNull(StockInventory::getBatchNo);
+        } else {
+            wrapper.eq(StockInventory::getBatchNo, batchNo);
+        }
+        return wrapper;
+    }
+
+    private BigDecimal defaultDecimal(BigDecimal value) {
+        return value == null ? BigDecimal.ZERO : value;
+    }
 }
+
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 bb56608..31affd2 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductionOrderServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionOrderServiceImpl.java
@@ -15,6 +15,8 @@
 import com.ruoyi.common.constant.StorageAttachmentConstants;
 import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.production.bean.dto.ProductionOrderDto;
+import com.ruoyi.production.bean.vo.ProductionBomStructureVo;
+import com.ruoyi.production.bean.vo.ProductionOrderPickVo;
 import com.ruoyi.production.bean.vo.ProductionOrderVo;
 import com.ruoyi.production.bean.vo.ProductionPlanVo;
 import com.ruoyi.production.enums.ProductOrderStatusEnum;
@@ -23,6 +25,8 @@
 import com.ruoyi.production.service.ProductionOrderService;
 import com.ruoyi.sales.mapper.SalesLedgerMapper;
 import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
+import com.ruoyi.stock.mapper.StockInventoryMapper;
+import com.ruoyi.stock.pojo.StockInventory;
 import com.ruoyi.technology.mapper.*;
 import com.ruoyi.technology.pojo.*;
 import lombok.RequiredArgsConstructor;
@@ -50,6 +54,7 @@
     private final ProductionOrderPickMapper productionOrderPickMapper;
     private final ProductionOrderPickRecordMapper productionOrderPickRecordMapper;
     private final ProductionPlanMapper productionPlanMapper;
+    private final StockInventoryMapper stockInventoryMapper;
     private final StorageAttachmentMapper storageAttachmentMapper;
     private final StorageBlobMapper storageBlobMapper;
     private final SalesLedgerMapper salesLedgerMapper;
@@ -112,11 +117,7 @@
                 || productionOrderRoutingMapper.selectCount(Wrappers.<ProductionOrderRouting>lambdaQuery()
                         .eq(ProductionOrderRouting::getProductionOrderId, productionOrder.getId())) == 0);
         if (needSync) {
-            // 宸ヨ壓銆佷骇鍝佹垨鏁伴噺鍙樺寲鍚庯紝璁㈠崟蹇収蹇呴』鍜屽綋鍓嶄笅鍗曟暟鎹噸鏂板榻愩��
             syncProductionOrderSnapshot(productionOrder.getId());
-        } else {
-            // 鏈噸寤哄揩鐓ф椂锛屼篃瑕佺‘淇濆鏂欎富鍗曞拰璁㈠崟鏁伴噺淇濇寔鍚屾銆�
-            upsertOrderPick(productionOrder);
         }
         return true;
     }
@@ -274,8 +275,6 @@
                 syncedParamCount++;
             }
         }
-
-        upsertOrderPick(productionOrder);
         return syncedParamCount;
     }
 
@@ -551,29 +550,6 @@
         return issuedQuantity.compareTo(requiredQuantity) < 0 ? 1 : 2;
     }
 
-    private void upsertOrderPick(ProductionOrder productionOrder) {
-        if (productionOrder == null || productionOrder.getId() == null) {
-            return;
-        }
-        // 璁㈠崟涓嬭揪鍚庤嚜鍔ㄧ敓鎴愪竴寮犲鏂欎富鍗曪紝鍚庣画棰嗘枡璁板綍閮芥寕鍦ㄨ繖寮犲崟涓娿��
-        ProductionOrderPick orderPick = productionOrderPickMapper.selectOne(
-                Wrappers.<ProductionOrderPick>lambdaQuery()
-                        .eq(ProductionOrderPick::getProductionOrderId, productionOrder.getId())
-                        .last("limit 1"));
-        if (orderPick == null) {
-            orderPick = new ProductionOrderPick();
-            orderPick.setProductionOrderId(productionOrder.getId());
-        }
-        orderPick.setProductModelId(productionOrder.getProductModelId() == null ? null : Math.toIntExact(productionOrder.getProductModelId()));
-        orderPick.setQuantity(defaultDecimal(productionOrder.getQuantity()));
-        orderPick.setRemark("涓嬪崟鑷姩鐢熸垚");
-        if (orderPick.getId() == null) {
-            productionOrderPickMapper.insert(orderPick);
-        } else {
-            productionOrderPickMapper.updateById(orderPick);
-        }
-    }
-
     private List<Long> parsePlanIds(String productionPlanIds) {
         if (productionPlanIds == null || productionPlanIds.trim().isEmpty()) {
             return new ArrayList<>();
@@ -677,4 +653,73 @@
         vo.setDownloadURL(fileUtil.buildSignedDownloadUrl(vo));
         return vo;
     }
+
+    @Override
+    public List<ProductionOrderPickVo> pick(Long productionOrderId) {
+        if (productionOrderId == null) {
+            return Collections.emptyList();
+        }
+
+        ProductionOrderBom orderBom = productionOrderBomMapper.selectOne(
+                Wrappers.<ProductionOrderBom>lambdaQuery()
+                        .eq(ProductionOrderBom::getProductionOrderId, productionOrderId)
+                        .orderByDesc(ProductionOrderBom::getId)
+                        .last("limit 1"));
+        if (orderBom == null || orderBom.getId() == null) {
+            return Collections.emptyList();
+        }
+
+        List<ProductionBomStructureVo> bomStructureList = productionBomStructureMapper.pickByBomId(orderBom.getId());
+        if (bomStructureList == null || bomStructureList.isEmpty()) {
+            return Collections.emptyList();
+        }
+
+        List<Long> productModelIds = bomStructureList.stream()
+                .map(ProductionBomStructureVo::getProductModelId)
+                .filter(Objects::nonNull)
+                .distinct()
+                .collect(Collectors.toList());
+        Map<Long, BigDecimal> stockQuantityMap = new HashMap<>();
+        Map<Long, LinkedHashSet<String>> stockBatchNoMap = new HashMap<>();
+        if (!productModelIds.isEmpty()) {
+            List<StockInventory> stockList = stockInventoryMapper.selectList(
+                    Wrappers.<StockInventory>lambdaQuery()
+                            .in(StockInventory::getProductModelId, productModelIds));
+            for (StockInventory stockItem : stockList) {
+                if (stockItem == null || stockItem.getProductModelId() == null) {
+                    continue;
+                }
+                Long productModelId = stockItem.getProductModelId();
+                stockQuantityMap.merge(productModelId, defaultDecimal(stockItem.getQualitity()), BigDecimal::add);
+                String batchNo = stockItem.getBatchNo();
+                if (batchNo != null && !batchNo.trim().isEmpty()) {
+                    stockBatchNoMap.computeIfAbsent(productModelId, key -> new LinkedHashSet<>()).add(batchNo);
+                }
+            }
+        }
+
+        List<ProductionOrderPickVo> result = new ArrayList<>(bomStructureList.size());
+        for (ProductionBomStructureVo structure : bomStructureList) {
+            if (structure == null || structure.getProductModelId() == null) {
+                continue;
+            }
+            Long productModelId = structure.getProductModelId();
+            ProductionOrderPickVo vo = new ProductionOrderPickVo();
+            vo.setProductModelId(productModelId);
+            vo.setOperationName(structure.getOperationName());
+            vo.setTechnologyOperationId(structure.getTechnologyOperationId());
+            vo.setProductName(structure.getProductName());
+            vo.setModel(structure.getModel());
+            vo.setDemandedQuantity(defaultDecimal(structure.getDemandedQuantity()));
+            vo.setUnit(structure.getUnit());
+            List<String> batchNoList = stockBatchNoMap.get(productModelId) == null
+                    ? Collections.emptyList()
+                    : new ArrayList<>(stockBatchNoMap.get(productModelId));
+            vo.setBatchNoList(batchNoList);
+            vo.setStockQuantity(stockQuantityMap.getOrDefault(productModelId, BigDecimal.ZERO));
+            vo.setBom(true);
+            result.add(vo);
+        }
+        return result;
+    }
 }
diff --git a/src/main/java/com/ruoyi/stock/mapper/StockInventoryMapper.java b/src/main/java/com/ruoyi/stock/mapper/StockInventoryMapper.java
index f17065a..21fa421 100644
--- a/src/main/java/com/ruoyi/stock/mapper/StockInventoryMapper.java
+++ b/src/main/java/com/ruoyi/stock/mapper/StockInventoryMapper.java
@@ -52,4 +52,6 @@
     BigDecimal selectTotalByDate(@Param("now") LocalDate now);
 
     BigDecimal selectPendingOutQuantity(@Param("productModelId") Long productModelId, @Param("batchNo") String batchNo, @Param("type") String type);
+
+    List<StockInventory> listSelectableBatchNoByProductModelIds(@Param("productModelIds") List<Long> productModelIds);
 }
diff --git a/src/main/resources/mapper/basic/ProductModelMapper.xml b/src/main/resources/mapper/basic/ProductModelMapper.xml
index 4ae5508..0a540bf 100644
--- a/src/main/resources/mapper/basic/ProductModelMapper.xml
+++ b/src/main/resources/mapper/basic/ProductModelMapper.xml
@@ -14,7 +14,16 @@
         <result column="product_name" property="productName" />
         <result column="product_id" property="productId" />
     </resultMap>
-    <select id="listPageProductModel" resultType="com.ruoyi.basic.pojo.ProductModel">
+
+    <resultMap id="ProductModelVoResultMap" type="com.ruoyi.basic.vo.ProductModelVo" extends="BaseResultMap">
+        <result column="create_time" property="createTime" />
+        <collection property="batchNoList"
+                    ofType="java.lang.String"
+                    column="{productModelId=id}"
+                    select="selectBatchNoListByProductModelId"/>
+    </resultMap>
+
+    <select id="listPageProductModel" resultMap="ProductModelVoResultMap">
         select pm.*,p.product_name
         from product_model pm
         left join product p on pm.product_id = p.id
@@ -31,9 +40,9 @@
                         SELECT id
                         FROM product
                         WHERE id = #{c.topProductParentId}
-                        
+
                         UNION ALL
-                        
+
                         SELECT p.id
                         FROM product p
                         INNER JOIN product_tree pt ON p.parent_id = pt.id
@@ -43,6 +52,15 @@
             </if>
         </where>
         order by  pm.id
+    </select>
+
+    <select id="selectBatchNoListByProductModelId" resultType="java.lang.String">
+        select distinct si.batch_no
+        from stock_inventory si
+        where si.product_model_id = #{productModelId}
+          and si.batch_no is not null
+          and si.batch_no != ''
+        order by si.batch_no
     </select>
     <select id="selectLatestRecord" resultType="com.ruoyi.basic.pojo.ProductModel">
             SELECT * FROM product_model
@@ -123,4 +141,4 @@
         order by p.id,pm.id desc
     </select>
 
-</mapper>
\ No newline at end of file
+</mapper>
diff --git a/src/main/resources/mapper/production/ProductionBomStructureMapper.xml b/src/main/resources/mapper/production/ProductionBomStructureMapper.xml
index 13b534f..c116f6f 100644
--- a/src/main/resources/mapper/production/ProductionBomStructureMapper.xml
+++ b/src/main/resources/mapper/production/ProductionBomStructureMapper.xml
@@ -31,4 +31,23 @@
         order by pbs.id
     </select>
 
+    <select id="pickByBomId" resultType="com.ruoyi.production.bean.vo.ProductionBomStructureVo">
+        SELECT
+            pbs.*,
+            p.product_name AS productName,
+            pm.product_id AS productId,
+            pm.model,
+            top1.NAME AS operationName
+        FROM
+            production_bom_structure pbs
+                LEFT JOIN product_model pm ON pbs.product_model_id = pm.id
+                LEFT JOIN product p ON pm.product_id = p.id
+                LEFT JOIN technology_operation top1 ON pbs.technology_operation_id = top1.id
+        WHERE
+            pbs.parent_id IS NOT NULL
+          AND pbs.production_order_bom_id = #{bomId}
+        ORDER BY
+            pbs.id
+    </select>
+
 </mapper>
diff --git a/src/main/resources/mapper/production/ProductionOrderPickMapper.xml b/src/main/resources/mapper/production/ProductionOrderPickMapper.xml
index c4b11f8..7dd8a1f 100644
--- a/src/main/resources/mapper/production/ProductionOrderPickMapper.xml
+++ b/src/main/resources/mapper/production/ProductionOrderPickMapper.xml
@@ -14,6 +14,24 @@
         <result column="remark" property="remark" />
         <result column="create_user" property="createUser" />
         <result column="dept_id" property="deptId" />
+        <result column="operation_name" property="operationName" />
+        <result column="technology_operation_id" property="technologyOperationId" />
+        <result column="demanded_quantity" property="demandedQuantity" />
+        <result column="is_bom" property="bom" />
     </resultMap>
 
+    <select id="listPickedDetailByOrderId" resultType="com.ruoyi.production.bean.vo.ProductionOrderPickVo">
+        select pop.*,
+               pop.is_bom as bom,
+               pop.quantity as pickQuantity,
+               p.product_name as productName,
+               pm.model as model,
+               pm.unit as unit
+        from production_order_pick pop
+                 left join product_model pm on pop.product_model_id = pm.id
+                 left join product p on pm.product_id = p.id
+        where pop.production_order_id = #{productionOrderId}
+        order by pop.create_time desc, pop.id desc
+    </select>
+
 </mapper>
diff --git a/src/main/resources/mapper/production/ProductionOrderPickRecordMapper.xml b/src/main/resources/mapper/production/ProductionOrderPickRecordMapper.xml
index 37c1285..818f4d9 100644
--- a/src/main/resources/mapper/production/ProductionOrderPickRecordMapper.xml
+++ b/src/main/resources/mapper/production/ProductionOrderPickRecordMapper.xml
@@ -21,4 +21,19 @@
         <result column="dept_id" property="deptId" />
     </resultMap>
 
+    <select id="listPickedDetailByOrderId" resultType="com.ruoyi.production.bean.vo.ProductionOrderPickVo">
+        select popr.*,
+               poro.operation_name as operationName,
+               p.product_name as productName,
+               pm.model as model,
+               pm.unit as unit
+        from production_order_pick_record popr
+                 left join production_operation_task pot on popr.production_operation_task_id = pot.id
+                 left join production_order_routing_operation poro on pot.technology_routing_operation_id = poro.id
+                 left join product_model pm on popr.product_model_id = pm.id
+                 left join product p on pm.product_id = p.id
+        where popr.production_order_id = #{productionOrderId}
+        order by popr.create_time desc, popr.id desc
+    </select>
+
 </mapper>
diff --git a/src/main/resources/mapper/stock/StockInventoryMapper.xml b/src/main/resources/mapper/stock/StockInventoryMapper.xml
index 6e8a3bc..d1eecb5 100644
--- a/src/main/resources/mapper/stock/StockInventoryMapper.xml
+++ b/src/main/resources/mapper/stock/StockInventoryMapper.xml
@@ -439,4 +439,18 @@
           AND sor.approval_status = 0
     </select>
 
+    <select id="listSelectableBatchNoByProductModelIds" resultType="com.ruoyi.stock.pojo.StockInventory">
+        select distinct si.product_model_id,
+                        si.batch_no
+        from stock_inventory si
+        where si.product_model_id in
+        <foreach collection="productModelIds" item="productModelId" open="(" separator="," close=")">
+            #{productModelId}
+        </foreach>
+          and si.batch_no is not null
+          and si.batch_no != ''
+          and (si.qualitity - ifnull(si.locked_quantity, 0)) > 0
+        order by si.product_model_id, si.batch_no
+    </select>
+
 </mapper>

--
Gitblit v1.9.3