From cfbddbd52f8c4d35b06c8b7e7e68b6cf22ce400a Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期二, 04 八月 2026 13:12:02 +0800
Subject: [PATCH] feat(mes): 支持工艺流程工序产出产品多选功能

---
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/task/MesProTaskServiceImpl.java                                    |    4 
 yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeSegmentServiceImpl.java                             |    8 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/route/vo/process/MesProRouteProcessSaveReqVO.java         |    6 
 yudao-module-aftersales/src/main/java/cn/iocoder/yudao/module/aftersales/controller/admin/ticket/AfterSaleTicketController.java           |    3 
 yudao-server/src/main/resources/application-test.yaml                                                                                     |   11 +
 yudao-module-aftersales/src/main/java/cn/iocoder/yudao/module/aftersales/controller/admin/ticket/vo/ticket/AfterSaleTicketRespVO.java     |    4 
 yudao-module-aftersales/src/main/java/cn/iocoder/yudao/module/aftersales/controller/admin/ticket/vo/ticket/AfterSaleTicketSaveReqVO.java  |    3 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/mps/MesProMpsServiceImpl.java                                      |    8 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/route/vo/process/MesProRouteProcessRespVO.java            |   12 +
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/process/MesProWorkOrderProcessSaveReqVO.java |    6 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkOrderProcessDO.java                     |    4 
 yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/YudaoAiProperties.java                                       |   27 +++
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/process/MesProWorkOrderProcessRespVO.java    |   12 +
 yudao-server/src/main/resources/application-local.yaml                                                                                    |   11 +
 docs/route_process_multi_output.md                                                                                                        |  145 ++++++++++++++++++
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/route/MesProRouteProcessServiceImpl.java                           |   12 +
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/route/MesProRouteProcessController.java                   |   55 +++++-
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderProcessServiceImpl.java                   |   19 ++
 yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/enums/storage/StorageRecordTypeEnum.java                                 |    4 
 yudao-server/src/main/resources/application-dev.yaml                                                                                      |    9 +
 yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/AiModelFactoryImpl.java                                  |   23 +-
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/route/MesProRouteProcessDO.java                             |    4 
 yudao-module-aftersales/src/main/java/cn/iocoder/yudao/module/aftersales/service/ticket/AfterSaleTicketServiceImpl.java                   |   14 +
 yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/AiAutoConfiguration.java                                     |    7 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkOrderProcessController.java           |   49 ++++-
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkOrderBomController.java               |    2 
 26 files changed, 396 insertions(+), 66 deletions(-)

diff --git a/docs/route_process_multi_output.md b/docs/route_process_multi_output.md
new file mode 100644
index 0000000..9864423
--- /dev/null
+++ b/docs/route_process_multi_output.md
@@ -0,0 +1,145 @@
+# 宸ヨ壓娴佺▼宸ュ簭"浜у嚭浜у搧"鏀寔澶氶�� - 鍓嶅悗绔敼鍔ㄦ�荤粨
+
+## 鐘舵�侊細宸插畬鎴�
+
+鍓嶇鍜屽悗绔敼鍔ㄥ潎宸插疄鏂斤紝缂栬瘧楠岃瘉閫氳繃銆�
+
+## 娑夊強椤甸潰
+
+- 鐢熶骇绠℃帶 鈫� 浜у搧璁捐 鈫� 宸ヨ壓娴佺▼ 鈫� 宸ュ簭缂栬緫寮圭獥锛堝伐鑹鸿矾绾垮伐搴忥級
+- 鐢熶骇绠℃帶 鈫� 鐢熶骇宸ュ崟 鈫� 宸ュ簭缂栬緫寮圭獥锛堝伐鍗曞伐搴忥級
+- 鐢熶骇绠℃帶 鈫� 鐢熶骇宸ュ崟 鈫� 宸ュ簭鍒楄〃灞曠ず
+
+## API 鍙樻洿
+
+### 璇锋眰鍙傛暟鍙樻洿
+
+**`MesProRouteProcessSaveReqVO`锛堝伐鑹鸿矾绾垮伐搴忎繚瀛橈級锛�**
+
+| 瀛楁 | 鏃х被鍨� | 鏂扮被鍨� | 璇存槑 |
+|------|--------|--------|------|
+| `outputItemId` | `Long` | **宸插垹闄�** | 鏇挎崲涓� `outputItemIds` |
+| `outputItemIds` | - | `List<Long>` | **鏂板**锛屼骇鍑轰骇鍝佺墿鏂欑紪鍙峰垪琛� |
+
+**`MesProWorkOrderProcessSaveReqVO`锛堝伐鍗曞伐搴忎繚瀛橈級锛�**
+
+| 瀛楁 | 鏃х被鍨� | 鏂扮被鍨� | 璇存槑 |
+|------|--------|--------|------|
+| `outputItemId` | `Long` | **宸插垹闄�** | 鏇挎崲涓� `outputItemIds` |
+| `outputItemIds` | - | `List<Long>` | **鏂板**锛屼骇鍑轰骇鍝佺墿鏂欑紪鍙峰垪琛� |
+
+### 鍝嶅簲瀛楁鍙樻洿
+
+**`MesProRouteProcessRespVO`锛堝伐鑹鸿矾绾垮伐搴忓搷搴旓級锛�**
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+|------|------|------|
+| `outputItemId` | `Long` | **淇濈暀**锛堝悜鍚庡吋瀹癸級锛屽彇绗竴涓骇鍑轰骇鍝� |
+| `outputItemCode` | `String` | **淇濈暀**锛岀涓�涓骇鍑轰骇鍝佺紪鐮� |
+| `outputItemName` | `String` | **淇濈暀**锛岀涓�涓骇鍑轰骇鍝佸悕绉� |
+| `outputItemIds` | `List<Long>` | **鏂板**锛屾墍鏈変骇鍑轰骇鍝佺紪鍙峰垪琛� |
+| `outputItemNames` | `String` | **鏂板**锛屾墍鏈変骇鍑轰骇鍝佸悕绉帮紙閫楀彿鎷兼帴锛� |
+
+**`MesProWorkOrderProcessRespVO`锛堝伐鍗曞伐搴忓搷搴旓級锛�**
+
+鍚屼笂锛屽瓧娈典竴鑷淬��
+
+### 鍒楄〃鎺ュ彛
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| GET | `/mes/pro/route-process/list-by-route?routeId={id}` | 宸ヨ壓璺嚎宸ュ簭鍒楄〃 |
+| GET | `/mes/pro/route-process/list-by-product?productId={id}` | 鎸変骇鍝佽幏鍙栧伐搴忓垪琛紙鍚姇鏂橞OM锛� |
+| GET | `/mes/pro/work-order-process/list-by-work-order-id?workOrderId={id}` | 宸ュ崟宸ュ簭鍒楄〃 |
+| GET | `/mes/pro/work-order-process/list-by-product-id?productId={id}` | 鎸変骇鍝佽幏鍙栧伐搴忓垪琛紙宸ュ崟棰勫~鐢級 |
+| POST | `/mes/pro/route-process/create` | 鍒涘缓宸ヨ壓璺嚎宸ュ簭 |
+| PUT | `/mes/pro/route-process/update` | 鏇存柊宸ヨ壓璺嚎宸ュ簭 |
+| POST | `/mes/pro/work-order-process/create` | 鍒涘缓宸ュ崟宸ュ簭 |
+| PUT | `/mes/pro/work-order-process/update` | 鏇存柊宸ュ崟宸ュ簭 |
+| POST | `/mes/pro/work-order-process/batch-save` | 鎵归噺淇濆瓨宸ュ崟宸ュ簭 |
+
+## 鍓嶇淇敼鐐�
+
+### 1. MdItemSelect 缁勪欢锛坄src/views/mes/md/item/components/select.vue`锛�
+
+鏂板 `multiple` prop锛�
+
+| Prop | 绫诲瀷 | 榛樿鍊� | 璇存槑 |
+|------|------|--------|------|
+| `multiple` | `boolean` | `false` | 鏄惁澶氶�夋ā寮� |
+
+澶氶�夋ā寮忚涓猴細
+- `modelValue` 绫诲瀷涓� `number[]`
+- 灞曠ず鍚嶇О閫楀彿鎷兼帴锛堝彇鐗╂枡 `name` 鎷兼帴锛�
+- 寮圭獥浠� `multiple: true` 鎵撳紑
+- 閫変腑鍊间互鏁扮粍褰㈠紡 emit
+
+鍗曢�夋ā寮忚涓轰笉鍙樸��
+
+### 2. API 绫诲瀷瀹氫箟
+
+**`src/api/mes/pro/route/process/index.ts`锛�**
+
+`RouteProcess` 鎺ュ彛鏂板锛�
+```typescript
+outputItemIds?: number[];   // 浜у嚭浜у搧缂栧彿鍒楄〃
+outputItemNames?: string;   // 浜у嚭浜у搧鍚嶇О锛堥�楀彿鎷兼帴锛�
+```
+
+**`src/api/mes/pro/workorder/process/index.ts`锛�**
+
+`WorkOrderProcess` 鎺ュ彛鏂板鍚屼笂涓や釜瀛楁銆�
+
+### 3. 宸ヨ壓璺嚎宸ュ簭琛ㄥ崟
+
+**`src/views/mes/process-design/route/data.ts`锛�**
+
+浜у嚭浜у搧瀛楁 schema 淇敼锛�
+- `fieldName` 浠� `"outputItemId"` 鏀逛负 `"outputItemIds"`
+- `componentProps` 澧炲姞 `multiple: true`
+
+**`src/views/mes/process-design/route/modules/process-list.vue`锛�**
+
+鍒楄〃/琛ㄦ牸涓骇鍑轰骇鍝佸垪灞曠ず鏀逛负 `outputItemNames`锛堥�楀彿鍒嗛殧鐨勫悕绉帮級銆�
+
+### 4. 宸ュ崟宸ュ簭琛ㄥ崟
+
+**`src/views/mes/pro/workorder/modules/process-form.vue`锛�**
+
+浜у嚭浜у搧瀛楁鏀逛负澶氶�夌粍浠讹紝`fieldName` 鏀逛负 `"outputItemIds"`銆�
+
+**`src/views/mes/pro/workorder/data.ts`锛�**
+
+琛ㄦ牸鍒椾腑浜у嚭浜у搧鍒楀睍绀烘敼涓� `outputItemNames`銆�
+
+**`src/views/mes/pro/workorder/modules/process-list.vue`锛�**
+
+宸ヨ壓璺嚎鈫掑伐鍗曞伐搴忔槧灏勬椂锛岄�忎紶澶氬�� `outputItemIds`/`outputItemNames`銆�
+
+## 鏁版嵁甯﹀叆璇存槑
+
+### 宸ヨ壓娴佺▼鏂板宸ュ簭
+
+1. 鐢ㄦ埛鍦ㄨ〃鍗曚腑澶氶�変骇鍑轰骇鍝� 鈫� `outputItemIds: [101, 102]`
+2. 淇濆瓨鏃� POST body 浼� `{ ..., outputItemIds: [101, 102] }`
+3. 鍚庣灏� `[101, 102]` 杞负 `"101,102"` 瀛樺叆 DB
+4. 鍒楄〃鏌ヨ鏃跺悗绔繑鍥� `outputItemIds: [101, 102]`, `outputItemNames: "浜у搧A, 浜у搧B"`
+
+### 宸ュ崟浠庡伐鑹鸿矾绾垮甫鍏�
+
+璋冪敤 `GET /mes/pro/work-order-process/list-by-product-id?productId={id}` 鑾峰彇宸ュ簭鍒楄〃鏃讹細
+- 鍝嶅簲涓� `outputItemIds` 鍜� `outputItemNames` 宸茬敱鍚庣瑙f瀽濂�
+- 鍓嶇鐩存帴鍥炴樉鍒拌〃鍗曞嵆鍙�
+
+### 宸ュ崟宸ュ簭鎵归噺淇濆瓨
+
+璇锋眰 `POST /mes/pro/work-order-process/batch-save`锛�
+- 姣忎釜宸ュ簭椤逛紶 `outputItemIds: [101, 102]`
+- 鍚庣鍚堝苟澶勭悊
+
+## 娉ㄦ剰浜嬮」
+
+- 鏃ф暟鎹吋瀹癸細DB 涓棫鍊� `"101"`锛堝崟鍊煎瓧绗︿覆锛夎В鏋愬悗鑷姩杞负 `["101"]`锛屼笉褰卞搷鍒楄〃灞曠ず
+- 涓嬫父鍙栫涓�涓細鎺掍骇浠诲姟鍒涘缓鏃跺彇 `outputItemIds` 绗竴涓�间綔涓轰换鍔$墿鏂欙紝澶氫骇鍑哄満鏅笅鐢ㄦ埛闇�纭绗竴涓骇鍑轰骇鍝佹槸姝g‘鐨�
+- 鎶曟枡 BOM 灞曞紑锛氫粛鐒舵寜绗竴涓骇鍑轰骇鍝� ID 鍖归厤宸ュ簭閰嶆柟锛屽鏋滃悗缁渶瑕佹敮鎸佸涓骇鍑轰骇鍝佺殑 BOM 灞曞紑锛岄渶鍙﹀鏀归��
+- 鍓嶇 MdItemSelect 鐨� `multiple` prop 榛樿涓� `false`锛岀‘淇濆叾浠栦娇鐢ㄦ缁勪欢鐨勫湴鏂逛笉鍙楀奖鍝�
diff --git a/yudao-module-aftersales/src/main/java/cn/iocoder/yudao/module/aftersales/controller/admin/ticket/AfterSaleTicketController.java b/yudao-module-aftersales/src/main/java/cn/iocoder/yudao/module/aftersales/controller/admin/ticket/AfterSaleTicketController.java
index 3acf172..4f6cddd 100644
--- a/yudao-module-aftersales/src/main/java/cn/iocoder/yudao/module/aftersales/controller/admin/ticket/AfterSaleTicketController.java
+++ b/yudao-module-aftersales/src/main/java/cn/iocoder/yudao/module/aftersales/controller/admin/ticket/AfterSaleTicketController.java
@@ -43,6 +43,8 @@
     private CrmCustomerApi customerApi;
     @Resource
     private AdminUserApi adminUserApi;
+    @Resource
+    private cn.iocoder.yudao.module.system.api.storage.StorageAttachmentApi storageAttachmentApi;
 
     @PostMapping("/create")
     @Operation(summary = "鍒涘缓鍞悗宸ュ崟")
@@ -79,6 +81,7 @@
         List<AfterSaleTicketRespVO> enrichedList = buildTicketDetailList(List.of(ticket));
         AfterSaleTicketRespVO respVO = enrichedList.get(0);
         respVO.setItems(BeanUtils.toBean(items, AfterSaleTicketRespVO.Item.class));
+        respVO.setAttachmentList(storageAttachmentApi.listAttachments("aftersales_after_sale_ticket", id));
         return success(respVO);
     }
 
diff --git a/yudao-module-aftersales/src/main/java/cn/iocoder/yudao/module/aftersales/controller/admin/ticket/vo/ticket/AfterSaleTicketRespVO.java b/yudao-module-aftersales/src/main/java/cn/iocoder/yudao/module/aftersales/controller/admin/ticket/vo/ticket/AfterSaleTicketRespVO.java
index 9b25b76..f8031a1 100644
--- a/yudao-module-aftersales/src/main/java/cn/iocoder/yudao/module/aftersales/controller/admin/ticket/vo/ticket/AfterSaleTicketRespVO.java
+++ b/yudao-module-aftersales/src/main/java/cn/iocoder/yudao/module/aftersales/controller/admin/ticket/vo/ticket/AfterSaleTicketRespVO.java
@@ -1,5 +1,6 @@
 package cn.iocoder.yudao.module.aftersales.controller.admin.ticket.vo.ticket;
 
+import cn.iocoder.yudao.module.system.api.storage.dto.StorageBlobRespDTO;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 
@@ -101,6 +102,9 @@
     @Schema(description = "鏇存柊鏃堕棿")
     private LocalDateTime updateTime;
 
+    @Schema(description = "闄勪欢鍒楄〃")
+    private List<StorageBlobRespDTO> attachmentList;
+
     @Schema(description = "鏄庣粏琛屽垪琛�")
     private List<Item> items;
 
diff --git a/yudao-module-aftersales/src/main/java/cn/iocoder/yudao/module/aftersales/controller/admin/ticket/vo/ticket/AfterSaleTicketSaveReqVO.java b/yudao-module-aftersales/src/main/java/cn/iocoder/yudao/module/aftersales/controller/admin/ticket/vo/ticket/AfterSaleTicketSaveReqVO.java
index deb2ab0..6e7c96f 100644
--- a/yudao-module-aftersales/src/main/java/cn/iocoder/yudao/module/aftersales/controller/admin/ticket/vo/ticket/AfterSaleTicketSaveReqVO.java
+++ b/yudao-module-aftersales/src/main/java/cn/iocoder/yudao/module/aftersales/controller/admin/ticket/vo/ticket/AfterSaleTicketSaveReqVO.java
@@ -53,6 +53,9 @@
     @Schema(description = "澶囨敞", example = "瀹㈡埛瑕佹眰灏藉揩澶勭悊")
     private String remark;
 
+    @Schema(description = "闄勪欢 blobId 鍒楄〃", example = "[1, 2, 3]")
+    private List<Long> blobIds;
+
     @Schema(description = "鏄庣粏琛屽垪琛�")
     private List<Item> items;
 
diff --git a/yudao-module-aftersales/src/main/java/cn/iocoder/yudao/module/aftersales/service/ticket/AfterSaleTicketServiceImpl.java b/yudao-module-aftersales/src/main/java/cn/iocoder/yudao/module/aftersales/service/ticket/AfterSaleTicketServiceImpl.java
index a076b58..c509cce 100644
--- a/yudao-module-aftersales/src/main/java/cn/iocoder/yudao/module/aftersales/service/ticket/AfterSaleTicketServiceImpl.java
+++ b/yudao-module-aftersales/src/main/java/cn/iocoder/yudao/module/aftersales/service/ticket/AfterSaleTicketServiceImpl.java
@@ -15,6 +15,7 @@
 import cn.iocoder.yudao.module.aftersales.enums.permission.AfterSalePermissionLevelEnum;
 import cn.iocoder.yudao.module.aftersales.service.permission.AfterSalePermissionService;
 import cn.iocoder.yudao.module.aftersales.service.permission.bo.AfterSalePermissionCreateReqBO;
+import cn.iocoder.yudao.module.system.api.storage.StorageAttachmentApi;
 import jakarta.annotation.Resource;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
@@ -47,6 +48,9 @@
     @Resource
     private AfterSalePermissionService permissionService;
 
+    @Resource
+    private StorageAttachmentApi storageAttachmentApi;
+
     @Override
     @Transactional(rollbackFor = Exception.class)
     public Long createTicket(AfterSaleTicketSaveReqVO createReqVO, Long userId) {
@@ -72,7 +76,11 @@
             });
         }
 
-        // 4. 鍒涘缓鏁版嵁鏉冮檺锛堣礋璐d汉锛�
+        // 4. 缁戝畾闄勪欢
+        storageAttachmentApi.bindAttachments("file", "aftersales_after_sale_ticket",
+                ticket.getId(), createReqVO.getBlobIds());
+
+        // 5. 鍒涘缓鏁版嵁鏉冮檺锛堣礋璐d汉锛�
         AfterSalePermissionCreateReqBO permBO = new AfterSalePermissionCreateReqBO();
         permBO.setBizType(AfterSaleBizTypeEnum.AFTER_SALE_TICKET.getType());
         permBO.setBizId(ticket.getId());
@@ -103,6 +111,9 @@
                 ticketItemMapper.insert(itemDO);
             });
         }
+
+        // 4. 鏇存柊闄勪欢
+        storageAttachmentApi.updateAttachments("file", "aftersales_after_sale_ticket", updateReqVO.getId(), updateReqVO.getBlobIds());
     }
 
     @Override
@@ -113,6 +124,7 @@
         // 杞垹闄�
         ticketMapper.deleteById(id);
         ticketItemMapper.deleteByTicketId(id);
+        storageAttachmentApi.deleteAttachmentsByRecord("aftersales_after_sale_ticket", id);
         permissionService.deletePermission(AfterSaleBizTypeEnum.AFTER_SALE_TICKET.getType(), id);
     }
 
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/AiAutoConfiguration.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/AiAutoConfiguration.java
index 27ceff0..ffd28a3 100644
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/AiAutoConfiguration.java
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/AiAutoConfiguration.java
@@ -16,8 +16,6 @@
 import org.springframework.ai.retry.RetryUtils;
 import org.springframework.ai.tokenizer.JTokkitTokenCountEstimator;
 import org.springframework.ai.tokenizer.TokenCountEstimator;
-import org.springframework.ai.vectorstore.milvus.autoconfigure.MilvusServiceClientProperties;
-import org.springframework.ai.vectorstore.milvus.autoconfigure.MilvusVectorStoreProperties;
 import org.springframework.ai.vectorstore.qdrant.autoconfigure.QdrantVectorStoreProperties;
 import org.springframework.ai.vectorstore.redis.autoconfigure.RedisVectorStoreProperties;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@@ -29,14 +27,13 @@
  * 鑺嬮亾 AI 鑷姩閰嶇疆
  *
  * 浣跨敤 OpenAI 鍏煎鎺ュ彛瀵规帴閫氫箟鍗冮棶 DashScope
+ * 鍚戦噺搴撻厤缃 yudao.ai.vector-store 鑺傜偣锛屼笉鍐嶄緷璧� Spring AI 鐨� Milvus 鑷姩閰嶇疆灞炴��
  */
 @Configuration
 @EnableConfigurationProperties({
         YudaoAiProperties.class,
         QdrantVectorStoreProperties.class,
-        RedisVectorStoreProperties.class,
-        MilvusVectorStoreProperties.class,
-        MilvusServiceClientProperties.class
+        RedisVectorStoreProperties.class
 })
 @Slf4j
 public class AiAutoConfiguration {
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/YudaoAiProperties.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/YudaoAiProperties.java
index c225b1e..2a26300 100644
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/YudaoAiProperties.java
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/YudaoAiProperties.java
@@ -12,10 +12,37 @@
 
     private WebSearch webSearch;
 
+    /** 鍚戦噺搴撻厤缃� */
+    private VectorStore vectorStore = new VectorStore();
+
     @Data
     public static class WebSearch {
         private boolean enable;
         private String apiKey;
     }
 
+    @Data
+    public static class VectorStore {
+
+        /** 鍚戦噺搴撶被鍨嬶細milvus */
+        private String type = "milvus";
+
+        /** Milvus 閰嶇疆 */
+        private Milvus milvus = new Milvus();
+
+        @Data
+        public static class Milvus {
+            /** 鏄惁鍒濆鍖� Schema */
+            private boolean initializeSchema = true;
+            /** 鏁版嵁搴撳悕绉� */
+            private String databaseName = "default";
+            /** 闆嗗悎鍚嶇О */
+            private String collectionName = "knowledge_segment";
+            /** 涓绘満鍦板潃 */
+            private String host = "127.0.0.1";
+            /** 绔彛 */
+            private int port = 19530;
+        }
+    }
+
 }
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/AiModelFactoryImpl.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/AiModelFactoryImpl.java
index 86b307a..fd2c3d9 100644
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/AiModelFactoryImpl.java
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/AiModelFactoryImpl.java
@@ -7,22 +7,20 @@
 import cn.hutool.extra.spring.SpringUtil;
 import cn.iocoder.yudao.module.ai.enums.model.AiPlatformEnum;
 import cn.iocoder.yudao.module.ai.framework.ai.config.AiAutoConfiguration;
+import cn.iocoder.yudao.module.ai.framework.ai.config.YudaoAiProperties;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.ai.chat.model.ChatModel;
-import org.springframework.ai.embedding.BatchingStrategy;
 import org.springframework.ai.embedding.EmbeddingModel;
 import org.springframework.ai.embedding.TokenCountBatchingStrategy;
 import org.springframework.ai.openai.OpenAiChatModel;
 import org.springframework.ai.vectorstore.VectorStore;
 import org.springframework.ai.vectorstore.milvus.MilvusVectorStore;
-import org.springframework.ai.vectorstore.milvus.autoconfigure.MilvusServiceClientProperties;
-import org.springframework.ai.vectorstore.milvus.autoconfigure.MilvusVectorStoreProperties;
 import java.util.Map;
 
 /**
  * AI Model 妯″瀷宸ュ巶瀹炵幇绫�
  *
- * 浣跨敤 OpenAI 鍏煎鎺ュ彛瀵规帴閫氫箟鍗冮棶 + Milvus 鍚戦噺瀛樺偍
+ * 浣跨敤 OpenAI 鍏煎鎺ュ彛瀵规帴閫氫箟鍗冮棶 + 鍙厤缃悜閲忓瓨鍌紙Milvus锛�
  */
 @Slf4j
 public class AiModelFactoryImpl implements AiModelFactory {
@@ -61,7 +59,6 @@
     public VectorStore getOrCreateVectorStore(Class<? extends VectorStore> type,
                                               EmbeddingModel embeddingModel,
                                               Map<String, Class<?>> metadataFields) {
-        // metadataFields 鍙備笌缂撳瓨 key锛岀‘淇濅笉鍚岀煡璇嗗簱浣跨敤涓嶅悓閰嶇疆鏃朵笉浼氬鐢�
         String cacheKey = buildCacheKey(VectorStore.class, embeddingModel, type, metadataFields.hashCode());
         return Singleton.get(cacheKey, (Func0<VectorStore>) () -> {
             if (type == MilvusVectorStore.class) {
@@ -72,20 +69,20 @@
     }
 
     private MilvusVectorStore buildMilvusVectorStore(EmbeddingModel embeddingModel) {
-        MilvusVectorStoreProperties serverProperties = SpringUtil.getBean(MilvusVectorStoreProperties.class);
-        MilvusServiceClientProperties clientProperties = SpringUtil.getBean(MilvusServiceClientProperties.class);
+        YudaoAiProperties aiProperties = SpringUtil.getBean(YudaoAiProperties.class);
+        YudaoAiProperties.VectorStore.Milvus milvusConfig = aiProperties.getVectorStore().getMilvus();
 
         var connectParam = io.milvus.param.ConnectParam.newBuilder()
-                .withHost(clientProperties.getHost())
-                .withPort(clientProperties.getPort())
-                .withDatabaseName(serverProperties.getDatabaseName())
+                .withHost(milvusConfig.getHost())
+                .withPort(milvusConfig.getPort())
+                .withDatabaseName(milvusConfig.getDatabaseName())
                 .build();
         var milvusClient = new io.milvus.client.MilvusServiceClient(connectParam);
 
         MilvusVectorStore vectorStore = MilvusVectorStore.builder(milvusClient, embeddingModel)
-                .databaseName(serverProperties.getDatabaseName())
-                .collectionName(serverProperties.getCollectionName())
-                .initializeSchema(serverProperties.isInitializeSchema())
+                .databaseName(milvusConfig.getDatabaseName())
+                .collectionName(milvusConfig.getCollectionName())
+                .initializeSchema(milvusConfig.isInitializeSchema())
                 .batchingStrategy(new TokenCountBatchingStrategy())
                 .build();
         try {
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeSegmentServiceImpl.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeSegmentServiceImpl.java
index 544bca4..8763b30 100644
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeSegmentServiceImpl.java
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeSegmentServiceImpl.java
@@ -212,9 +212,13 @@
             documents.add(doc);
         }
 
+        // 鍚戦噺搴撻檺鍒跺崟鎵规鏈�澶� 10 鏉★紝鍒嗘壒鍐欏叆
+        int batchSize = 10;
         try {
-            vectorStore.add(documents);
-            // 鏇存柊 vectorId锛圡ilvus 杩斿洖鐨� ID 灏辨槸浼犲叆鐨� docId锛�
+            for (int i = 0; i < documents.size(); i += batchSize) {
+                int end = Math.min(i + batchSize, documents.size());
+                vectorStore.add(documents.subList(i, end));
+            }
             for (AiKnowledgeSegmentDO segment : segments) {
                 segment.setVectorId(segment.getId().toString());
                 segmentMapper.updateById(segment);
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/route/MesProRouteProcessController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/route/MesProRouteProcessController.java
index e02cb8a..1bc0813 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/route/MesProRouteProcessController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/route/MesProRouteProcessController.java
@@ -24,11 +24,7 @@
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 import java.util.stream.Collectors;
 
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@@ -150,21 +146,50 @@
         list.forEach(item -> { if (item.getNextProcessId() != null) processIds.add(item.getNextProcessId()); });
         Map<Long, MesProProcessDO> processMap = convertMap(
                 processService.getProcessList(new ArrayList<>(processIds)), MesProProcessDO::getId);
-        // 2. 鎵归噺鑾峰彇浜у嚭浜у搧鐗╂枡淇℃伅
-        Set<Long> outputItemIds = convertSet(list, MesProRouteProcessDO::getOutputItemId);
-        outputItemIds.remove(null);
-        Map<Long, MesMdItemDO> outputItemMap = outputItemIds.isEmpty()
-                ? Collections.emptyMap()
-                : mdItemService.getItemMap(outputItemIds);
+        // 2. 鎵归噺鑾峰彇浜у嚭浜у搧鐗╂枡淇℃伅锛堣В鏋愰�楀彿鍒嗛殧鐨勫瓧绗︿覆锛�
+        Set<Long> allOutputItemIds = new HashSet<>();
+        Map<Long, List<Long>> voOutputItemIdsMap = new HashMap<>();
+        for (int i = 0; i < list.size(); i++) {
+            String outputItemIdStr = list.get(i).getOutputItemId();
+            if (outputItemIdStr != null && !outputItemIdStr.isBlank()) {
+                List<Long> ids = Arrays.stream(outputItemIdStr.split(","))
+                        .map(String::trim).filter(s -> !s.isEmpty())
+                        .map(Long::valueOf).collect(Collectors.toList());
+                voOutputItemIdsMap.put((long) i, ids);
+                allOutputItemIds.addAll(ids);
+            }
+        }
+        Map<Long, MesMdItemDO> outputItemMap = allOutputItemIds.isEmpty()
+                ? Collections.emptyMap() : mdItemService.getItemMap(allOutputItemIds);
         // 3. 鎷兼帴 VO
-        return BeanUtils.toBean(list, MesProRouteProcessRespVO.class, vo -> {
+        List<MesProRouteProcessRespVO> result = BeanUtils.toBean(list, MesProRouteProcessRespVO.class);
+        for (int i = 0; i < result.size(); i++) {
+            MesProRouteProcessRespVO vo = result.get(i);
             MapUtils.findAndThen(processMap, vo.getProcessId(),
                     process -> vo.setProcessCode(process.getCode()).setProcessName(process.getName()));
             MapUtils.findAndThen(processMap, vo.getNextProcessId(),
                     nextProcess -> vo.setNextProcessName(nextProcess.getName()));
-            MapUtils.findAndThen(outputItemMap, vo.getOutputItemId(),
-                    item -> vo.setOutputItemCode(item.getCode()).setOutputItemName(item.getName()));
-        });
+            // 浜у嚭浜у搧锛堟敮鎸佸閫夛級
+            List<Long> ids = voOutputItemIdsMap.getOrDefault((long) i, Collections.emptyList());
+            if (!ids.isEmpty()) {
+                vo.setOutputItemIds(ids);
+                List<String> names = ids.stream()
+                        .map(id -> {
+                            MesMdItemDO item = outputItemMap.get(id);
+                            return item != null ? item.getName() : String.valueOf(id);
+                        }).collect(Collectors.toList());
+                vo.setOutputItemNames(String.join(", ", names));
+                // 鍚戝悗鍏煎锛氱涓�涓骇鍑轰骇鍝�
+                Long firstId = ids.get(0);
+                vo.setOutputItemId(firstId);
+                MesMdItemDO firstItem = outputItemMap.get(firstId);
+                if (firstItem != null) {
+                    vo.setOutputItemCode(firstItem.getCode());
+                    vo.setOutputItemName(firstItem.getName());
+                }
+            }
+        }
+        return result;
     }
 
     private MesProRouteProcessRespVO buildRouteProcessRespVO(MesProRouteProcessDO routeProcess) {
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/route/vo/process/MesProRouteProcessRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/route/vo/process/MesProRouteProcessRespVO.java
index 76ef7f3..935d463 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/route/vo/process/MesProRouteProcessRespVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/route/vo/process/MesProRouteProcessRespVO.java
@@ -55,15 +55,21 @@
     @Schema(description = "鏄惁鍊掑啿锛坱rue=鎶ュ伐鏃舵寜BOM鑷姩鎵f枡锛沠alse=涓嶈嚜鍔ㄦ墸鏂欙級", example = "true")
     private Boolean backflushFlag;
 
-    @Schema(description = "浜у嚭浜у搧鐗╂枡缂栧彿", example = "100")
+    @Schema(description = "浜у嚭浜у搧鐗╂枡缂栧彿锛堢涓�涓紝鍚戝悗鍏煎锛�", example = "100")
     private Long outputItemId;
 
-    @Schema(description = "浜у嚭浜у搧鐗╂枡缂栫爜")
+    @Schema(description = "浜у嚭浜у搧鐗╂枡缂栫爜锛堢涓�涓級")
     private String outputItemCode;
 
-    @Schema(description = "浜у嚭浜у搧鐗╂枡鍚嶇О")
+    @Schema(description = "浜у嚭浜у搧鐗╂枡鍚嶇О锛堢涓�涓級")
     private String outputItemName;
 
+    @Schema(description = "浜у嚭浜у搧鐗╂枡缂栧彿鍒楄〃", example = "[100, 101]")
+    private List<Long> outputItemIds;
+
+    @Schema(description = "浜у嚭浜у搧鐗╂枡鍚嶇О锛堥�楀彿鎷兼帴锛�", example = "浜у搧A, 浜у搧B")
+    private String outputItemNames;
+
     @Schema(description = "澶囨敞")
     private String remark;
 
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/route/vo/process/MesProRouteProcessSaveReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/route/vo/process/MesProRouteProcessSaveReqVO.java
index 8a4fa09..17f71e2 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/route/vo/process/MesProRouteProcessSaveReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/route/vo/process/MesProRouteProcessSaveReqVO.java
@@ -4,6 +4,8 @@
 import jakarta.validation.constraints.NotNull;
 import lombok.Data;
 
+import java.util.List;
+
 @Schema(description = "绠$悊鍚庡彴 - MES 宸ヨ壓璺嚎宸ュ簭鏂板/淇敼 Request VO")
 @Data
 public class MesProRouteProcessSaveReqVO {
@@ -44,8 +46,8 @@
     @Schema(description = "鏄惁鍊掑啿锛坱rue=鎶ュ伐鏃舵寜BOM鑷姩鎵f枡锛沠alse=涓嶈嚜鍔ㄦ墸鏂欙級", example = "true")
     private Boolean backflushFlag;
 
-    @Schema(description = "浜у嚭浜у搧鐗╂枡缂栧彿锛堜负绌烘椂榛樿鐢ㄥ伐鍗曟垚鍝侊級", example = "100")
-    private Long outputItemId;
+    @Schema(description = "浜у嚭浜у搧鐗╂枡缂栧彿鍒楄〃锛堝閫夛紝涓虹┖鏃堕粯璁ょ敤宸ュ崟鎴愬搧锛�", example = "[100, 101]")
+    private List<Long> outputItemIds;
 
     @Schema(description = "澶囨敞")
     private String remark;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkOrderBomController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkOrderBomController.java
index a44b286..2f2795d 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkOrderBomController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkOrderBomController.java
@@ -249,7 +249,7 @@
                     items.add(bom);
                 }
             }
-            processBomMap.put(process.getOutputItemId(), items);
+            processBomMap.put(Long.valueOf(process.getOutputItemId().split(",")[0].trim()), items);
         }
 
         // 2. 鍙栨渶鍚庝竴閬撳伐搴忥紙sort 鏈�澶э級浣滀负灞曞紑璧风偣锛岄�愬眰鍚戝墠閫掓帹
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkOrderProcessController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkOrderProcessController.java
index 398cda6..1cb8944 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkOrderProcessController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkOrderProcessController.java
@@ -28,6 +28,7 @@
 import org.springframework.web.bind.annotation.*;
 
 import java.util.*;
+import java.util.stream.Collectors;
 
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
@@ -134,11 +135,21 @@
         processIds.addAll(nextProcessIds);
         Map<Long, MesProProcessDO> processMap = CollUtil.isNotEmpty(processIds)
                 ? processService.getProcessMap(processIds) : Collections.emptyMap();
-        // 鑾峰彇浜у嚭鐗╂枡
-        Set<Long> outputItemIds = convertSet(list, MesProWorkOrderProcessDO::getOutputItemId);
-        outputItemIds.removeAll(Collections.singleton(null));
-        Map<Long, MesMdItemDO> itemMap = CollUtil.isNotEmpty(outputItemIds)
-                ? itemService.getItemMap(outputItemIds) : Collections.emptyMap();
+        // 鑾峰彇浜у嚭鐗╂枡锛堣В鏋愰�楀彿鍒嗛殧鐨勫瓧绗︿覆锛�
+        Set<Long> allOutputItemIds = new HashSet<>();
+        Map<Long, List<Long>> voOutputItemIdsMap = new HashMap<>();
+        for (int i = 0; i < list.size(); i++) {
+            String outputItemIdStr = list.get(i).getOutputItemId();
+            if (outputItemIdStr != null && !outputItemIdStr.isBlank()) {
+                List<Long> ids = Arrays.stream(outputItemIdStr.split(","))
+                        .map(String::trim).filter(s -> !s.isEmpty())
+                        .map(Long::valueOf).collect(Collectors.toList());
+                voOutputItemIdsMap.put((long) i, ids);
+                allOutputItemIds.addAll(ids);
+            }
+        }
+        Map<Long, MesMdItemDO> itemMap = CollUtil.isNotEmpty(allOutputItemIds)
+                ? itemService.getItemMap(allOutputItemIds) : Collections.emptyMap();
 
         // 2. 鏌ヨ鎶曟枡BOM锛堟寜宸ュ簭鍒嗙粍锛�
         Set<Long> workOrderIds = convertSet(list, MesProWorkOrderProcessDO::getWorkOrderId);
@@ -165,17 +176,35 @@
         }));
 
         // 3. 鎷兼帴 VO
-        List<MesProWorkOrderProcessRespVO> result = BeanUtils.toBean(list, MesProWorkOrderProcessRespVO.class, vo -> {
+        List<MesProWorkOrderProcessRespVO> result = BeanUtils.toBean(list, MesProWorkOrderProcessRespVO.class);
+        for (int i = 0; i < result.size(); i++) {
+            MesProWorkOrderProcessRespVO vo = result.get(i);
             MapUtils.findAndThen(processMap, vo.getProcessId(), process -> {
                 vo.setProcessCode(process.getCode()).setProcessName(process.getName());
             });
             MapUtils.findAndThen(processMap, vo.getNextProcessId(), process -> {
                 vo.setNextProcessName(process.getName());
             });
-            MapUtils.findAndThen(itemMap, vo.getOutputItemId(), item -> {
-                vo.setOutputItemCode(item.getCode()).setOutputItemName(item.getName());
-            });
-        });
+            // 浜у嚭鐗╂枡锛堟敮鎸佸閫夛級
+            List<Long> ids = voOutputItemIdsMap.getOrDefault((long) i, Collections.emptyList());
+            if (!ids.isEmpty()) {
+                vo.setOutputItemIds(ids);
+                List<String> names = ids.stream()
+                        .map(id -> {
+                            MesMdItemDO item = itemMap.get(id);
+                            return item != null ? item.getName() : String.valueOf(id);
+                        }).collect(Collectors.toList());
+                vo.setOutputItemNames(String.join(", ", names));
+                // 鍚戝悗鍏煎锛氱涓�涓骇鍑虹墿鏂�
+                Long firstId = ids.get(0);
+                vo.setOutputItemId(firstId);
+                MesMdItemDO firstItem = itemMap.get(firstId);
+                if (firstItem != null) {
+                    vo.setOutputItemCode(firstItem.getCode());
+                    vo.setOutputItemName(firstItem.getName());
+                }
+            }
+        }
         // 璁剧疆姣忎釜宸ュ簭鍚勮嚜鐨勬姇鏂橞OM
         result.forEach(vo -> vo.setBomItems(bomItemsByProcessId.getOrDefault(vo.getProcessId(), Collections.emptyList())));
         return result;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/process/MesProWorkOrderProcessRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/process/MesProWorkOrderProcessRespVO.java
index e2806fd..1fdaabc 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/process/MesProWorkOrderProcessRespVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/process/MesProWorkOrderProcessRespVO.java
@@ -68,15 +68,21 @@
     @ExcelProperty("鏄惁鍊掑啿")
     private Boolean backflushFlag;
 
-    @Schema(description = "浜у嚭浜у搧鐗╂枡缂栧彿", example = "100")
+    @Schema(description = "浜у嚭浜у搧鐗╂枡缂栧彿锛堢涓�涓紝鍚戝悗鍏煎锛�", example = "100")
     private Long outputItemId;
 
-    @Schema(description = "浜у嚭浜у搧鐗╂枡缂栫爜", example = "M001")
+    @Schema(description = "浜у嚭浜у搧鐗╂枡缂栫爜锛堢涓�涓級", example = "M001")
     private String outputItemCode;
 
-    @Schema(description = "浜у嚭浜у搧鐗╂枡鍚嶇О", example = "浜у搧A")
+    @Schema(description = "浜у嚭浜у搧鐗╂枡鍚嶇О锛堢涓�涓級", example = "浜у搧A")
     private String outputItemName;
 
+    @Schema(description = "浜у嚭浜у搧鐗╂枡缂栧彿鍒楄〃", example = "[100, 101]")
+    private List<Long> outputItemIds;
+
+    @Schema(description = "浜у嚭浜у搧鐗╂枡鍚嶇О锛堥�楀彿鎷兼帴锛�", example = "浜у搧A, 浜у搧B")
+    private String outputItemNames;
+
     @Schema(description = "澶囨敞", example = "澶囨敞")
     @ExcelProperty("澶囨敞")
     private String remark;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/process/MesProWorkOrderProcessSaveReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/process/MesProWorkOrderProcessSaveReqVO.java
index 5b9b2a8..3a09e6b 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/process/MesProWorkOrderProcessSaveReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/process/MesProWorkOrderProcessSaveReqVO.java
@@ -7,6 +7,8 @@
 import java.math.BigDecimal;
 import java.util.List;
 
+import java.util.List;
+
 @Schema(description = "绠$悊鍚庡彴 - MES 鐢熶骇宸ュ崟宸ュ簭鏂板/淇敼 Request VO")
 @Data
 public class MesProWorkOrderProcessSaveReqVO {
@@ -47,8 +49,8 @@
     @Schema(description = "鏄惁鍊掑啿", example = "true")
     private Boolean backflushFlag;
 
-    @Schema(description = "浜у嚭浜у搧鐗╂枡缂栧彿", example = "100")
-    private Long outputItemId;
+    @Schema(description = "浜у嚭浜у搧鐗╂枡缂栧彿鍒楄〃锛堝閫夛紝涓虹┖鏃堕粯璁ょ敤宸ュ崟鎴愬搧锛�", example = "[100, 101]")
+    private List<Long> outputItemIds;
 
     @Schema(description = "澶囨敞")
     private String remark;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/route/MesProRouteProcessDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/route/MesProRouteProcessDO.java
index 82ca417..9c19235 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/route/MesProRouteProcessDO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/route/MesProRouteProcessDO.java
@@ -84,12 +84,12 @@
      */
     private Boolean backflushFlag;
     /**
-     * 浜у嚭浜у搧鐗╂枡缂栧彿
+     * 浜у嚭浜у搧鐗╂枡缂栧彿锛堝涓敤閫楀彿鍒嗛殧锛�
      *
      * 鍏宠仈 {@link cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO#getId()}
      * 涓虹┖鏃堕粯璁ょ敤宸ュ崟鐨勬垚鍝�
      */
-    private Long outputItemId;
+    private String outputItemId;
     /**
      * 澶囨敞
      */
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkOrderProcessDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkOrderProcessDO.java
index 0d378d1..565f202 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkOrderProcessDO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkOrderProcessDO.java
@@ -83,12 +83,12 @@
      */
     private Boolean backflushFlag;
     /**
-     * 浜у嚭浜у搧鐗╂枡缂栧彿
+     * 浜у嚭浜у搧鐗╂枡缂栧彿锛堝涓敤閫楀彿鍒嗛殧锛�
      *
      * 鍏宠仈 {@link cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO#getId()}
      * 涓虹┖鏃堕粯璁ょ敤宸ュ崟鐨勬垚鍝�
      */
-    private Long outputItemId;
+    private String outputItemId;
     /**
      * 澶囨敞
      */
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/mps/MesProMpsServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/mps/MesProMpsServiceImpl.java
index eff04b4..e380ac7 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/mps/MesProMpsServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/mps/MesProMpsServiceImpl.java
@@ -40,10 +40,12 @@
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
@@ -552,7 +554,11 @@
             process.setKeyFlag(rp.getKeyFlag());
             process.setCheckFlag(rp.getCheckFlag());
             process.setBackflushFlag(rp.getBackflushFlag());
-            process.setOutputItemId(rp.getOutputItemId());
+            if (rp.getOutputItemId() != null && !rp.getOutputItemId().isBlank()) {
+                process.setOutputItemIds(Arrays.stream(rp.getOutputItemId().split(","))
+                        .map(String::trim).filter(s -> !s.isEmpty())
+                        .map(Long::valueOf).collect(Collectors.toList()));
+            }
             process.setColorCode(rp.getColorCode());
             // 甯﹀叆宸ュ簭鎶曟枡BOM
             List<MesProRouteProductBomDO> routeBomItems = bomMap != null ? bomMap.get(rp.getProcessId()) : null;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/route/MesProRouteProcessServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/route/MesProRouteProcessServiceImpl.java
index 42417d2..816d104 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/route/MesProRouteProcessServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/route/MesProRouteProcessServiceImpl.java
@@ -63,6 +63,12 @@
 
         // 2. 鎻掑叆
         MesProRouteProcessDO routeProcess = BeanUtils.toBean(createReqVO, MesProRouteProcessDO.class);
+        if (CollUtil.isNotEmpty(createReqVO.getOutputItemIds())) {
+            routeProcess.setOutputItemId(
+                createReqVO.getOutputItemIds().stream()
+                    .map(String::valueOf)
+                    .collect(Collectors.joining(",")));
+        }
         routeProcessMapper.insert(routeProcess);
 
         // 3. 鏇存柊宸ュ簭閾�
@@ -86,6 +92,12 @@
 
         // 2. 鏇存柊
         MesProRouteProcessDO updateObj = BeanUtils.toBean(updateReqVO, MesProRouteProcessDO.class);
+        if (CollUtil.isNotEmpty(updateReqVO.getOutputItemIds())) {
+            updateObj.setOutputItemId(
+                updateReqVO.getOutputItemIds().stream()
+                    .map(String::valueOf)
+                    .collect(Collectors.joining(",")));
+        }
         routeProcessMapper.updateById(updateObj);
 
         // 3. 閲嶅缓宸ュ簭閾�
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/task/MesProTaskServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/task/MesProTaskServiceImpl.java
index bf04d45..b210c28 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/task/MesProTaskServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/task/MesProTaskServiceImpl.java
@@ -112,7 +112,7 @@
             MesProRouteProcessDO routeProcess = routeProcessService
                     .getRouteProcessByRouteIdAndProcessId(createReqVO.getRouteId(), createReqVO.getProcessId());
             if (routeProcess != null && routeProcess.getOutputItemId() != null) {
-                itemId = routeProcess.getOutputItemId();
+                itemId = Long.valueOf(routeProcess.getOutputItemId().split(",")[0].trim());
             } else {
                 itemId = workOrder.getProductId();
             }
@@ -408,7 +408,7 @@
         List<Long> taskIds = new java.util.ArrayList<>();
         for (MesProRouteProcessDO rp : routeProcesses) {
             cn.iocoder.yudao.module.mes.dal.dataobject.pro.process.MesProProcessDO proc = procMap.get(rp.getProcessId());
-            Long itemId = rp.getOutputItemId() != null ? rp.getOutputItemId() : workOrder.getProductId();
+            Long itemId = rp.getOutputItemId() != null ? Long.valueOf(rp.getOutputItemId().split(",")[0].trim()) : workOrder.getProductId();
             cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO item = itemService.validateItemExists(itemId);
             MesProTaskDO task = new MesProTaskDO()
                     .setWorkOrderId(workOrder.getId())
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderProcessServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderProcessServiceImpl.java
index 9ee4e74..2351151 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderProcessServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderProcessServiceImpl.java
@@ -24,6 +24,7 @@
 import java.util.Comparator;
 import java.util.List;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
@@ -60,6 +61,12 @@
 
         // 2. 鎻掑叆鏁版嵁
         MesProWorkOrderProcessDO workOrderProcess = BeanUtils.toBean(createReqVO, MesProWorkOrderProcessDO.class);
+        if (CollUtil.isNotEmpty(createReqVO.getOutputItemIds())) {
+            workOrderProcess.setOutputItemId(
+                createReqVO.getOutputItemIds().stream()
+                    .map(String::valueOf)
+                    .collect(Collectors.joining(",")));
+        }
         workOrderProcessMapper.insert(workOrderProcess);
 
         // 3. 閲嶅缓宸ュ簭閾�
@@ -75,6 +82,12 @@
 
         // 2. 鏇存柊鏁版嵁
         MesProWorkOrderProcessDO updateObj = BeanUtils.toBean(updateReqVO, MesProWorkOrderProcessDO.class);
+        if (CollUtil.isNotEmpty(updateReqVO.getOutputItemIds())) {
+            updateObj.setOutputItemId(
+                updateReqVO.getOutputItemIds().stream()
+                    .map(String::valueOf)
+                    .collect(Collectors.joining(",")));
+        }
         workOrderProcessMapper.updateById(updateObj);
 
         // 3. 閲嶅缓宸ュ簭閾�
@@ -175,10 +188,16 @@
             if (item.getId() == null) {
                 // 鏂板
                 MesProWorkOrderProcessDO process = BeanUtils.toBean(item, MesProWorkOrderProcessDO.class);
+                if (CollUtil.isNotEmpty(item.getOutputItemIds())) {
+                    process.setOutputItemId(item.getOutputItemIds().stream().map(String::valueOf).collect(Collectors.joining(",")));
+                }
                 workOrderProcessMapper.insert(process);
             } else {
                 // 鏇存柊
                 MesProWorkOrderProcessDO updateObj = BeanUtils.toBean(item, MesProWorkOrderProcessDO.class);
+                if (CollUtil.isNotEmpty(item.getOutputItemIds())) {
+                    updateObj.setOutputItemId(item.getOutputItemIds().stream().map(String::valueOf).collect(Collectors.joining(",")));
+                }
                 workOrderProcessMapper.updateById(updateObj);
             }
         }
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/enums/storage/StorageRecordTypeEnum.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/enums/storage/StorageRecordTypeEnum.java
index 63a5981..bb0087d 100644
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/enums/storage/StorageRecordTypeEnum.java
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/enums/storage/StorageRecordTypeEnum.java
@@ -54,8 +54,8 @@
     HRM_ATTENDANCE_EXCEPTION("hrm_attendance_exception", "HRM 鑰冨嫟寮傚父"),
 
     // ===== 鍞悗 =====
-    AFTER_SALE_TICKET("aftersales_ticket", "鍞悗宸ュ崟"),
-    AFTER_SALE_RETURN("aftersales_return", "鍞悗閫�璐х敵璇�"),
+    AFTER_SALE_TICKET("aftersales_after_sale_ticket", "鍞悗宸ュ崟"),
+    AFTER_SALE_RETURN("aftersales_after_sale_return", "鍞悗閫�璐х敵璇�"),
 
     // ===== MES =====
     MES_PD_DOCUMENT("mes_pd_document", "MES 璁捐璧勬枡");
diff --git a/yudao-server/src/main/resources/application-dev.yaml b/yudao-server/src/main/resources/application-dev.yaml
index 1901934..537dcd8 100644
--- a/yudao-server/src/main/resources/application-dev.yaml
+++ b/yudao-server/src/main/resources/application-dev.yaml
@@ -175,6 +175,15 @@
 
 # 鑺嬮亾閰嶇疆椤癸紝璁剧疆褰撳墠椤圭洰鎵�鏈夎嚜瀹氫箟鐨勯厤缃�
 yudao:
+  ai:
+    vector-store:
+      type: milvus # 鍚戦噺搴撶被鍨嬶細milvus
+      milvus:
+        initialize-schema: true
+        database-name: default
+        collection-name: knowledge_segment
+        host: 127.0.0.1
+        port: 19530
   pay:
     order-notify-url: http://yunai.natapp1.cc/admin-api/pay/notify/order # 鏀粯娓犻亾鐨勩�愭敮浠樸�戝洖璋冨湴鍧�
     refund-notify-url: http://yunai.natapp1.cc/admin-api/pay/notify/refund # 鏀粯娓犻亾鐨勩�愰��娆俱�戝洖璋冨湴鍧�
diff --git a/yudao-server/src/main/resources/application-local.yaml b/yudao-server/src/main/resources/application-local.yaml
index 66b7e46..20f1cdb 100644
--- a/yudao-server/src/main/resources/application-local.yaml
+++ b/yudao-server/src/main/resources/application-local.yaml
@@ -222,6 +222,17 @@
 
 debug: false
 
+yudao:
+  ai:
+    vector-store:
+      type: milvus # 鍚戦噺搴撶被鍨嬶細milvus
+      milvus:
+        initialize-schema: true
+        database-name: default
+        collection-name: knowledge_segment
+        host: 36.213.180.217
+        port: 19530
+
 --- #################### 寰俊鍏紬鍙枫�佸皬绋嬪簭鐩稿叧閰嶇疆 ####################
 wx:
   mp: # 鍏紬鍙烽厤缃紙蹇呭~锛夛紝鍙傝 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-mp-spring-boot-starter/README.md 鏂囨。
diff --git a/yudao-server/src/main/resources/application-test.yaml b/yudao-server/src/main/resources/application-test.yaml
index f3dcef3..ac895f6 100644
--- a/yudao-server/src/main/resources/application-test.yaml
+++ b/yudao-server/src/main/resources/application-test.yaml
@@ -220,6 +220,17 @@
 
 debug: false
 
+yudao:
+  ai:
+    vector-store:
+      type: milvus # 鍚戦噺搴撶被鍨嬶細milvus
+      milvus:
+        initialize-schema: true
+        database-name: test
+        collection-name: knowledge_segment
+        host: 36.213.180.217
+        port: 19530
+
 --- #################### 寰俊鍏紬鍙枫�佸皬绋嬪簭鐩稿叧閰嶇疆 ####################
 wx:
   mp: # 鍏紬鍙烽厤缃紙蹇呭~锛夛紝鍙傝 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-mp-spring-boot-starter/README.md 鏂囨。

--
Gitblit v1.9.3