From 7ac5fb62d3ac852ec9505eb5c1999064aafee85f Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期四, 13 八月 2026 16:26:39 +0800
Subject: [PATCH] feat(mes): 添加MES模块配置和功能

---
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pd/project/vo/MesPdProjectRespVO.java           |    3 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/MesPdStatusConstants.java                                  |    4 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pd/project/listener/MesPdProjectStatusListener.java      |   47 ++
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/batch/vo/MesWmBatchProcessTraceRespVO.java   |   46 ++
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/batch/vo/MesWmBatchPurchaseSourceRespVO.java |   52 ++
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/batch/vo/MesWmBatchSalesTargetRespVO.java    |   55 ++
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/batch/MesWmBatchController.java              |   97 ++++
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/batch/MesWmBatchServiceImpl.java                      |   43 +
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/batch/MesWmBatchMapper.java                         |   27 +
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pd/project/MesPdProjectService.java                      |   24 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pd/project/MesPdProjectServiceImpl.java                  |  121 ++++
 docs/pd_project_bpm_approval_frontend.md                                                                                    |   87 +++
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pd/project/MesPdProjectController.java          |   17 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java                                    |    3 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pd/MesPdProjectStatusEnum.java                             |   10 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/batch/MesWmBatchService.java                          |   35 +
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pd/project/MesPdProjectDO.java                    |    8 
 yudao-module-mes/src/main/resources/mapper/wm/batch/MesWmBatchMapper.xml                                                    |   65 ++
 yudao-server/src/main/resources/application-yzfx.yaml                                                                       |  324 ++++++++++++++
 docs/batch_trace_extended_frontend.md                                                                                       |  305 +++++++++++++
 20 files changed, 1,348 insertions(+), 25 deletions(-)

diff --git a/docs/batch_trace_extended_frontend.md b/docs/batch_trace_extended_frontend.md
new file mode 100644
index 0000000..8a04534
--- /dev/null
+++ b/docs/batch_trace_extended_frontend.md
@@ -0,0 +1,305 @@
+# 鎵规杩芥函鎵╁睍 - 鍓嶇鑱旇皟鏂规
+
+## 姒傝堪
+
+鍦ㄧ幇鏈夋壒娆¤拷婧紙鍚戝墠/鍚戝悗锛夊熀纭�涓婏紝鎵╁睍 4 涓兘鍔涳紝琛ラ綈鎵规鍏ㄩ摼璺拷婧細
+
+1. **閲囪喘鏉ユ簮**锛氫粠鎵规鍙嶆煡閲囪喘鍏ュ簱鍗� + IQC 璐ㄦ缁撹锛堝師鏂欎晶鏂摼鎵撻�氾級
+2. **閿�鍞幓鍚�**锛氫粠鎵规鍙嶆煡閿�鍞嚭搴撳崟 + OQC 璐ㄦ缁撹锛堟垚鍝佷晶鏂摼鎵撻�氾級
+3. **宸ュ簭娴佽浆**锛氫粠鎵规鏌ョ湅浜у嚭/鎶曞叆鐨勫伐搴忕骇浜嬩欢锛堟棤闇�寤鸿〃锛屽姩鎬佽仛鍚堬級
+4. **SN 鍙嶆煡**锛氳緭鍏� SN 搴忓垪鍙风洿鎺ュ畾浣嶆壒娆″苟璺宠浆璇︽儏
+
+鍚庣 4 涓柊鎺ュ彛鍧囧凡瀹屾垚骞剁紪璇戦�氳繃锛屾湰鏂囨。鎸囧鍓嶇瀵规帴銆�
+
+---
+
+## 涓�銆佹秹鍙婇〉闈�
+
+| 椤甸潰 | 璺緞 | 鏀瑰姩璇存槑 |
+|------|------|----------|
+| 鎵规杩芥函椤� | `src/views/mes/qc/batchtrace/index.vue` | 椤堕儴鏂板 SN 鍙嶆煡杈撳叆妗� |
+| 杩芥函璇︽儏寮圭獥 | `src/views/mes/qc/batchtrace/modules/trace-detail.vue` | 瀛愰〉绛炬墿灞曚负 5 涓紙鐢熶骇/閲囪喘鏉ユ簮/閿�鍞幓鍚�/宸ュ簭娴佽浆/璐ㄦ锛� |
+| 閲囪喘鏉ユ簮瀛愬垪琛� | `src/views/mes/qc/batchtrace/modules/purchase-source-list.vue` | 鏂板瀛愮粍浠� |
+| 閿�鍞幓鍚戝瓙鍒楄〃 | `src/views/mes/qc/batchtrace/modules/sales-target-list.vue` | 鏂板瀛愮粍浠� |
+| 宸ュ簭娴佽浆瀛愬垪琛� | `src/views/mes/qc/batchtrace/modules/process-trace-list.vue` | 鏂板瀛愮粍浠� |
+| 鎵规 API | `src/api/mes/wm/batch/index.ts` | 鏂板 4 涓帴鍙e嚱鏁� |
+| 鍒楀畾涔� | `src/views/mes/qc/batchtrace/data.ts` | 鏂板 3 缁勫垪閰嶇疆 |
+
+---
+
+## 浜屻�丄PI 鎺ュ彛
+
+### 2.1 鎵规閲囪喘鏉ユ簮
+
+**璇锋眰鏂瑰紡**锛欸ET
+
+**璇锋眰璺緞**锛歚/mes/wm/batch/purchase-sources`
+
+**璇锋眰鍙傛暟**锛�
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| code | String | 鏄� | 鎵规缂栫爜 |
+
+**鍝嶅簲**锛�
+
+```json
+{
+  "code": 0,
+  "data": [
+    {
+      "receiptCode": "IR20250713001",
+      "receiptDate": "2026-08-01 10:00:00",
+      "purchaseOrderCode": "PO20250701001",
+      "vendorId": 20,
+      "vendorCode": "VENDOR001",
+      "vendorName": "渚涘簲鍟咥",
+      "iqcCode": "IQC20250713001",
+      "checkResult": 1,
+      "itemId": 100,
+      "itemCode": "ITEM001",
+      "itemName": "鍘熸枡A",
+      "batchCode": "BT20260731001",
+      "receivedQuantity": 100
+    }
+  ]
+}
+```
+
+**瀛楁璇存槑**锛�
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+|------|------|------|
+| receiptCode | String | 閲囪喘鍏ュ簱鍗曞彿 |
+| receiptDate | Date | 鍏ュ簱鏃ユ湡 |
+| purchaseOrderCode | String | 閲囪喘璁㈠崟鍙� |
+| vendorCode / vendorName | String | 渚涘簲鍟嗙紪鐮�/鍚嶇О锛堝悗绔瘜鍖栵級 |
+| iqcCode | String | IQC 璐ㄦ鍗曞彿锛堝彲鑳戒负绌猴級 |
+| checkResult | Integer | IQC 璐ㄦ缁撹锛屽瓧鍏� `mes_qc_check_result` |
+| itemCode / itemName | String | 鐗╂枡缂栫爜/鍚嶇О锛堝悗绔瘜鍖栵級 |
+| batchCode | String | 鎵规缂栫爜 |
+| receivedQuantity | BigDecimal | 鍏ュ簱鏁伴噺 |
+
+### 2.2 鎵规閿�鍞幓鍚�
+
+**璇锋眰鏂瑰紡**锛欸ET
+
+**璇锋眰璺緞**锛歚/mes/wm/batch/sales-targets`
+
+**璇锋眰鍙傛暟**锛�
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| code | String | 鏄� | 鎵规缂栫爜 |
+
+**鍝嶅簲**锛�
+
+```json
+{
+  "code": 0,
+  "data": [
+    {
+      "salesCode": "SS20250713001",
+      "salesDate": "2026-08-05 14:00:00",
+      "salesOrderCode": "SO20250701001",
+      "clientId": 30,
+      "clientName": "瀹㈡埛A",
+      "oqcCode": "OQC20250713001",
+      "checkResult": 1,
+      "itemId": 100,
+      "itemCode": "ITEM001",
+      "itemName": "鎴愬搧A",
+      "batchCode": "BT20260804001",
+      "quantity": 50,
+      "qualityStatus": 1
+    }
+  ]
+}
+```
+
+**瀛楁璇存槑**锛�
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+|------|------|------|
+| salesCode | String | 閿�鍞嚭搴撳崟鍙� |
+| salesDate | Date | 鍑哄簱鏃ユ湡 |
+| salesOrderCode | String | 閿�鍞鍗曞彿 |
+| clientName | String | 瀹㈡埛鍚嶇О锛堝悗绔瘜鍖栵紝娉ㄦ剰锛氬鎴锋棤缂栫爜瀛楁锛� |
+| oqcCode | String | OQC 璐ㄦ鍗曞彿锛堝彲鑳戒负绌猴級 |
+| checkResult | Integer | OQC 璐ㄦ缁撹锛屽瓧鍏� `mes_qc_check_result` |
+| itemCode / itemName | String | 鐗╂枡缂栫爜/鍚嶇О锛堝悗绔瘜鍖栵級 |
+| batchCode | String | 鎵规缂栫爜 |
+| quantity | BigDecimal | 鍑哄簱鏁伴噺 |
+| qualityStatus | Integer | 璐ㄩ噺鐘舵�侊紝瀛楀吀 `mes_wm_quality_status` |
+
+### 2.3 鎵规宸ュ簭娴佽浆
+
+**璇锋眰鏂瑰紡**锛欸ET
+
+**璇锋眰璺緞**锛歚/mes/wm/batch/process-trace`
+
+**璇锋眰鍙傛暟**锛�
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| code | String | 鏄� | 鎵规缂栫爜 |
+
+**鍝嶅簲**锛�
+
+```json
+{
+  "code": 0,
+  "data": [
+    {
+      "eventType": "IN",
+      "workOrderId": 50,
+      "workOrderCode": "WO20260730001",
+      "processId": 10,
+      "processCode": "P001",
+      "processName": "涓嬫枡",
+      "batchCode": "BT20260804001",
+      "quantity": 100,
+      "qualityStatus": null,
+      "eventTime": "2026-08-04 09:00:00",
+      "processSort": 1
+    },
+    {
+      "eventType": "OUT",
+      "workOrderId": 50,
+      "workOrderCode": "WO20260730001",
+      "processId": 10,
+      "processCode": "P001",
+      "processName": "涓嬫枡",
+      "batchCode": "BT20260804001",
+      "quantity": 90,
+      "qualityStatus": 1,
+      "eventTime": "2026-08-04 10:00:00",
+      "processSort": 1
+    }
+  ]
+}
+```
+
+**瀛楁璇存槑**锛�
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+|------|------|------|
+| eventType | String | 浜嬩欢绫诲瀷锛歚OUT` = 浜у嚭銆乣IN` = 鎶曞叆 |
+| workOrderCode | String | 宸ュ崟鍙凤紙鍚庣瀵屽寲锛� |
+| processCode / processName | String | 宸ュ簭缂栫爜/鍚嶇О锛堝悗绔瘜鍖栵級 |
+| batchCode | String | 鎵规缂栫爜 |
+| quantity | BigDecimal | 鏁伴噺锛圤UT=浜у嚭鏁伴噺锛孖N=鎶曞叆鏁伴噺锛� |
+| qualityStatus | Integer | 璐ㄩ噺鐘舵�侊紙浠� OUT 渚ф湁鍊硷紝IN 渚т负 null锛� |
+| eventTime | Date | 浜嬩欢鏃堕棿锛圤UT=浜у嚭鏃ユ湡锛孖N=娑堣�楁棩鏈燂級 |
+| processSort | Integer | 宸ュ簭搴忓彿锛堢敤浜庡睍绀哄伐搴忓厛鍚庯級 |
+
+**鎺掑簭瑙勫垯**锛氬悗绔凡鎸� `workOrderId asc 鈫� processSort asc锛堢┖鍊肩疆鍚庯級鈫� eventTime asc` 鎺掑簭锛屽墠绔洿鎺ユ寜杩斿洖椤哄簭灞曠ず鍗冲彲銆�
+
+### 2.4 SN 鍙嶆煡鎵规
+
+**璇锋眰鏂瑰紡**锛欸ET
+
+**璇锋眰璺緞**锛歚/mes/wm/batch/get-by-sn`
+
+**璇锋眰鍙傛暟**锛�
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| sn | String | 鏄� | SN 搴忓垪鍙� |
+
+**鍝嶅簲**锛氫笌 `GET /mes/wm/batch/get` 瀹屽叏涓�鑷达紙`MesWmBatchRespVO`锛夛紝鏈懡涓繑鍥� `data: null`锛�
+
+```json
+{
+  "code": 0,
+  "data": {
+    "id": 1,
+    "code": "BT20260804001",
+    "itemId": 100,
+    "itemCode": "ITEM001",
+    "itemName": "鎴愬搧A",
+    "vendorCode": "VENDOR001",
+    "vendorName": "渚涘簲鍟咥",
+    "clientName": "瀹㈡埛A",
+    "workOrderCode": "WO20260730001",
+    "taskCode": "TASK001",
+    "workstationCode": "WS001",
+    "toolCode": "TOOL001",
+    "lotNumber": "LOT20260801"
+  }
+}
+```
+
+**璇存槑**锛歋N 鍦� `mes_wm_sn` 琛ㄩ�氳繃 `code` 鍞竴鍖归厤锛屽懡涓悗鍙栧叾 `batch_code` 鍙嶆煡鎵规銆傚墠绔牴鎹� `data` 鏄惁涓虹┖鍒ゆ柇鏄惁鎻愮ず"鏈壘鍒板搴旀壒娆�"銆�
+
+---
+
+## 涓夈�佸瓧娈靛睍绀鸿鍒�
+
+| 鍔熻兘 | 灞曠ず浣嶇疆 | 瀛楁璇存槑 |
+|------|----------|----------|
+| 閲囪喘鏉ユ簮 | 璇︽儏寮圭獥瀛愰〉绛�"閲囪喘鏉ユ簮" | 鍏ュ簱鍗曞彿銆佸叆搴撴棩鏈熴�侀噰璐鍗曘�佷緵搴斿晢銆両QC鍗曞彿銆両QC缁撹銆佺墿鏂欍�佹暟閲� |
+| 閿�鍞幓鍚� | 璇︽儏寮圭獥瀛愰〉绛�"閿�鍞幓鍚�" | 鍑哄簱鍗曞彿銆佸嚭搴撴棩鏈熴�侀攢鍞鍗曘�佸鎴枫�丱QC鍗曞彿銆丱QC缁撹銆佺墿鏂欍�佹暟閲忋�佽川閲忕姸鎬� |
+| 宸ュ簭娴佽浆 | 璇︽儏寮圭獥瀛愰〉绛�"宸ュ簭娴佽浆" | 浜嬩欢绫诲瀷銆佸伐鍗曞彿銆佸伐搴忕紪鐮�/鍚嶇О銆佹暟閲忋�佹椂闂淬�佽川閲忕姸鎬� |
+| SN 鍙嶆煡 | 杩芥函椤甸《閮ㄨ緭鍏ユ | 杈撳叆 SN 鈫� 鍛戒腑鐩存帴鎵撳紑鎵规璇︽儏寮圭獥 |
+
+**瀛楀吀璇存槑**锛�
+
+| 瀛楀吀 | 鍙栧�� |
+|------|------|
+| `mes_qc_check_result` | 1=鍚堟牸銆�2=鐗归噰銆�3=閫�璐с��4=鎶ュ簾 |
+| `mes_wm_quality_status` | 0=寰呮銆�1=鍚堟牸銆�2=涓嶅悎鏍� |
+
+---
+
+## 鍥涖�佹暟鎹甫鍏ヨ鏄�
+
+| 鍦烘櫙 | 甯﹀叆璇存槑 |
+|------|----------|
+| 杩芥函椤� 鈫� 閲囪喘鏉ユ簮 | 鐐瑰嚮鎵规琛岋紝鎼哄甫璇ヨ鐨� `code` 璋冪敤 `getPurchaseSourceList(code)` |
+| 杩芥函椤� 鈫� 閿�鍞幓鍚� | 鐐瑰嚮鎵规琛岋紝鎼哄甫璇ヨ鐨� `code` 璋冪敤 `getSalesTargetList(code)` |
+| 杩芥函椤� 鈫� 宸ュ簭娴佽浆 | 鐐瑰嚮鎵规琛岋紝鎼哄甫璇ヨ鐨� `code` 璋冪敤 `getProcessTraceList(code)` |
+| SN 杈撳叆妗� 鈫� 璇︽儏 | 杈撳叆 SN 璋冪敤 `getBatchBySn(sn)`锛岃繑鍥炵殑 `code` 浣滀负璇︽儏寮圭獥鏌ヨ渚濇嵁锛堟垨鐩存帴浣跨敤杩斿洖鏁版嵁锛� |
+
+---
+
+## 浜斻�佹帴鍙h皟鐢ㄦ椂搴�
+
+1. 杩芥函椤靛姞杞芥壒娆″垪琛紙`/mes/wm/batch/page`锛�
+2. 鐐瑰嚮鏌愭壒娆¤ 鈫� 鎵撳紑璇︽儏寮圭獥锛屽脊绐楀唴榛樿灞曠ず"鐢熶骇"椤电锛堝悜鍓�/鍚戝悗杩芥函锛�
+3. 鍒囨崲"閲囪喘鏉ユ簮/閿�鍞幓鍚�/宸ュ簭娴佽浆"椤电鏃讹紝鎸夐渶璋冪敤瀵瑰簲鎺ュ彛锛堝缓璁噿鍔犺浇锛氶娆″垏鎹㈡墠璇锋眰锛�
+4. 椤堕儴 SN 杈撳叆妗� 鈫� 鎸夊洖杞︽垨鐐瑰嚮鎼滅储 鈫� `getBatchBySn` 鈫� 鍛戒腑鎵撳紑璇︽儏寮圭獥锛屾湭鍛戒腑鎻愮ず鏃犺褰�
+
+---
+
+## 鍏�佷笟鍔¤鍒欒鏄�
+
+| 鍦烘櫙 | 瑙勫垯 |
+|------|------|
+| 鍘熸枡鎵规 | 鏈夐噰璐潵婧愶紙鍏ュ簱+IQC锛夛紝鏃犻攢鍞幓鍚戯紱宸ュ簭娴佽浆浠� IN 鎶曞叆涓轰富 |
+| 鎴愬搧鎵规 | 鏈夐攢鍞幓鍚戯紙鍑哄簱+OQC锛夛紝鏃犻噰璐潵婧愶紱宸ュ簭娴佽浆浠� OUT 浜у嚭涓轰富 |
+| 涓棿鎵规 | 鍚屾椂瀛樺湪 IN 涓� OUT 浜嬩欢锛屼綋鐜板伐搴忕骇娴佽浆 |
+| 璐ㄦ鍗曠己澶� | `iqcCode`/`oqcCode` 鍙兘涓虹┖锛堝崟鎹湭鍏宠仈锛夛紝缁撹鍒楀睍绀�"-" |
+| SN 鏈懡涓� | `get-by-sn` 杩斿洖 `data: null`锛屽墠绔彁绀�"鏈壘鍒拌 SN 瀵瑰簲鐨勬壒娆�" |
+| 鏁版嵁涓虹┖ | 涓変釜瀛愬垪琛ㄦ帴鍙e潎鍙兘杩斿洖绌烘暟缁勶紝椤甸潰灞曠ず绌烘�佹彁绀� |
+
+---
+
+## 涓冦�佹敞鎰忎簨椤�
+
+- 涓変釜鍒楄〃鎺ュ彛涓庢棦鏈� forward/backward 鐩稿悓锛屽潎闇�瑕� `mes:wm-batch:query` 鏉冮檺
+- 瀛愰〉绛惧缓璁噿鍔犺浇 + 缂撳瓨锛岄伩鍏嶆瘡娆″垏鎹㈤噸澶嶈姹�
+- 宸ュ簭娴佽浆鐨� `processSort` 鐢卞悗绔帓濂藉簭锛屽墠绔嬁鍐嶆帓搴�
+- 閿�鍞晶 `qualityStatus` 涓哄瓧鍏稿�硷紝灞曠ず鐢� `mes_wm_quality_status` 瀛楀吀缈昏瘧
+- 娴嬭瘯鐜鍙兘瀛樺湪鏃� `batchCode` 鐨勯攢鍞嚭搴撹鏁版嵁锛屽睘鍘嗗彶鑴忔暟鎹紝鍓嶇瀵圭┖瀛楁鍋氬厹搴曞睍绀哄嵆鍙�
+
+---
+
+## 鍏�佺浉鍏虫帴鍙f眹鎬�
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| GET | /mes/wm/batch/purchase-sources | 鎵规閲囪喘鏉ユ簮锛堝叆搴� + IQC锛� |
+| GET | /mes/wm/batch/sales-targets | 鎵规閿�鍞幓鍚戯紙鍑哄簱 + OQC锛� |
+| GET | /mes/wm/batch/process-trace | 鎵规宸ュ簭娴佽浆锛堜骇鍑�/鎶曞叆锛� |
+| GET | /mes/wm/batch/get-by-sn | SN 鍙嶆煡鎵规 |
diff --git a/docs/pd_project_bpm_approval_frontend.md b/docs/pd_project_bpm_approval_frontend.md
new file mode 100644
index 0000000..f9ef944
--- /dev/null
+++ b/docs/pd_project_bpm_approval_frontend.md
@@ -0,0 +1,87 @@
+# MES 浜у搧椤圭洰鎺ュ叆 BPM 瀹℃壒 - 鍓嶇鑱旇皟鏂规
+
+## 娑夊強椤甸潰
+
+- 鐢熶骇绠℃帶-浜у搧璁捐-浜у搧椤圭洰 鍒楄〃椤碉紙`src/views/mes/pd/project/index.vue`锛�
+- 浜у搧椤圭洰 璇︽儏椤碉紙`src/views/mes/pd/project/detail/index.vue`锛�
+- 浜у搧椤圭洰 娴佺▼杩涘害缁勪欢锛坄src/views/mes/pd/project/modules/workflow-timeline.vue`锛�
+
+## 涓氬姟娴佺▼涓庢暟鎹甫鍏�
+
+1. 寰呭鏍�(2) 鈫� 鍒楄〃/璇︽儏鐐广�屾彁浜ゅ鎵广�嶏細鍏堣皟 `GET /mes/pd/project/approve-process-list` 鑾峰彇鍙敤 BPM 娴佺▼ 鈫� 鎵撳紑娴佺▼閫夋嫨寮圭獥 鈫� 閫変腑娴佺▼鍚庤皟 `PUT /mes/pd/project/submit-approval?id={id}&processDefinitionKey={key}` 鈫� 椤圭洰鐘舵�佸彉涓� **瀹℃壒涓�(5)**
+2. BPM 鍚庡彴瀹℃壒閫氳繃 鈫� 鍚庣鐩戝惉鍣ㄥ洖璋� 鈫� 椤圭洰鐘舵�佸彉涓� **寰呭綊妗�(3)**锛涘鎵归┏鍥�/鍙栨秷 鈫� 鐘舵�佸洖鍒� **寰呭鏍�(2)**锛屽彲閲嶆柊鎻愪氦
+3. 瀹℃壒涓�(5) 鈫� 鍒楄〃/璇︽儏鏄剧ず銆屾煡鐪嬪鎵广�嶆寜閽� 鈫� 璺宠浆 BPM 娴佺▼璇︽儏椤垫煡鐪嬪鎵硅繘搴�
+4. 寰呭綊妗�(3) 鈫� 鐐广�屽綊妗c�嶁啋 `PUT /mes/pd/project/archive?id={id}` 鈫� 鐘舵�佸彉涓� **宸插綊妗�(4)**
+
+## API
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| GET | /mes/pd/project/approve-process-list | 鑾峰緱鍙敤 BPM 瀹℃壒娴佺▼鍒楄〃 |
+| PUT | /mes/pd/project/submit-approval | 鎻愪氦瀹℃壒锛堝緟瀹℃牳鈫掑鎵逛腑锛� |
+| PUT | /mes/pd/project/archive | 褰掓。锛堝緟褰掓。鈫掑凡褰掓。锛� |
+
+**璇锋眰鍙傛暟锛坰ubmit-approval锛夛細**
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| id | Long | 鏄� | 椤圭洰缂栧彿 |
+| processDefinitionKey | String | 鏄� | 閫変腑鐨� BPM 娴佺▼瀹氫箟 Key |
+
+**鍝嶅簲瀛楁鍙樻洿锛�/get銆�/page锛夛細**
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+|------|------|------|
+| processInstanceId | String | BPM 娴佺▼瀹炰緥缂栧彿锛屽鎵逛腑鍙婁互鍚庢湁鍊� |
+
+**鍝嶅簲绀轰緥锛坅pprove-process-list锛夛細**
+
+```json
+{
+  "code": 0,
+  "data": [
+    { "id": "xxx", "name": "浜у搧椤圭洰瀹℃壒娴佺▼", "key": "mes-pd-project-audit" }
+  ]
+}
+```
+
+## 瀛楁灞曠ず瑙勫垯
+
+| 瀛楁 | 灞曠ず浣嶇疆 | 璇存槑 |
+|------|----------|------|
+| 鐘舵�� | 鍒楄〃銆佽鎯� | 鏂板瀛楀吀鍊笺�屽鎵逛腑銆�(value=5)锛屽垪琛� `CellDict` 鑷姩娓叉煋 |
+| processInstanceId | 鍒楄〃/璇︽儏銆屾煡鐪嬪鎵广�� | 鏈夊�兼墠鏄剧ず銆屾煡鐪嬪鎵广�嶆寜閽� |
+
+## 椤甸潰鏀瑰姩
+
+### 1. 鍒楄〃椤� index.vue
+
+- 銆屽鏍搞�嶆寜閽敼涓恒�屾彁浜ゅ鎵广�嶏細`ifShow` 浠嶄负 `status === PENDING_AUDIT`锛岀偣鍑诲厛鏌ユ祦绋嬪垪琛紙绌哄垯鎻愮ず銆屾殏鏃犲彲鐢ㄥ鎵规祦绋嬶紝璇峰厛閰嶇疆 BPM 娴佺▼銆嶏級锛屾湁鍒欐墦寮�娴佺▼閫夋嫨寮圭獥
+- 鏂板銆屾煡鐪嬪鎵广�嶆寜閽細`ifShow` 涓� `status === APPROVING` 涓� `processInstanceId` 鏈夊�硷紝鐐瑰嚮璺� BPM 娴佺▼璇︽儏
+- 鏂板娴佺▼閫夋嫨寮圭獥缁勪欢 `process-select-modal.vue`锛圫elect 涓嬫媺閫夋祦绋嬶紝榛樿閫夌涓�涓紝纭鍚庤皟 submit-approval锛�
+
+### 2. 璇︽儏椤� detail/index.vue
+
+- 銆屽鏍搁�氳繃銆嶆寜閽敼涓恒�屾彁浜ゅ鎵广�嶏紝閫昏緫鍚屼笂锛屾垚鍔熷悗鍒锋柊璇︽儏
+- 鏂板銆屾煡鐪嬪鎵广�嶆寜閽細`ifShow` 涓哄鎵逛腑鐘舵�侊紝鐐瑰嚮璺� BPM 娴佺▼璇︽儏
+- 椤堕儴鎸夐挳鍖烘柊澧炲鎵逛腑鍒ゆ柇
+
+### 3. 娴佺▼杩涘害缁勪欢 workflow-timeline.vue
+
+- 姝ラ鐢� 5 姝ユ墿涓� 6 姝ワ細寰呭彂甯� 鈫� 寰呬笂浼� 鈫� 寰呭鏍� 鈫� **瀹℃壒涓�** 鈫� 寰呭綊妗� 鈫� 宸插綊妗�
+- 鐘舵�佸�煎埌姝ラ绱㈠紩鐨勬槧灏勯渶鏄惧紡澶勭悊锛堝鎵逛腑 value=5 鎻掑湪寰呭鏍镐箣鍚庯級
+
+## 涓氬姟瑙勫垯璇存槑
+
+| 鍦烘櫙 | 瑙勫垯 |
+|------|------|
+| 鎻愪氦瀹℃壒 | 浠呭緟瀹℃牳(2)鐘舵�佸彲鎻愪氦锛涜嫢椤圭洰涓嬪瓨鍦ㄦ湭瀹℃牳鐨勮璁¤祫鏂欙紝鍚庣杩斿洖閿欒銆岃椤圭洰涓嬪瓨鍦ㄦ湭瀹℃牳鐨勮祫鏂欍�� |
+| 瀹℃壒閫氳繃 | 鐘舵�� 鈫� 寰呭綊妗�(3)锛屽彲鎵ц褰掓。 |
+| 瀹℃壒椹冲洖/鍙栨秷 | 鐘舵�� 鈫� 寰呭鏍�(2)锛屽彲淇敼鍚庨噸鏂版彁浜� |
+| 褰掓。 | 浠呭緟褰掓。(3)鐘舵�佸彲褰掓。锛屽綊妗e悗鐢熸垚鍙拌处璁板綍銆侀」鐩笉鍙啀淇敼 |
+
+## 娉ㄦ剰浜嬮」
+
+- 闇�鍏堝湪 BPM 鍚庡彴鎵嬪伐閮ㄧ讲瀹℃壒娴佺▼锛堟祦绋� key=`mes-pd-project-audit`锛屽垎绫�=`mes_pd_project_approve`锛夛紝鍚﹀垯銆屾彁浜ゅ鎵广�嶆彁绀烘殏鏃犲彲鐢ㄦ祦绋�
+- 鏈彁浜ゅ鎵癸紙processInstanceId 涓虹┖锛夋椂鐐广�屾煡鐪嬪鎵广�嶅簲鎻愮ず銆岃椤圭洰灏氭湭鎻愪氦瀹℃壒銆�
+- 鍘嗗彶鏁版嵁 status 0-4 涓嶅彈褰卞搷锛涙椂闂寸嚎缁勪欢闇�鍏煎鐘舵�佸�煎埌姝ラ鐨勯潪杩炵画鏄犲皠
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pd/project/MesPdProjectController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pd/project/MesPdProjectController.java
index 88b79d1..45c7cb9 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pd/project/MesPdProjectController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pd/project/MesPdProjectController.java
@@ -124,15 +124,24 @@
         return success(true);
     }
 
-    @PutMapping("/audit")
-    @Operation(summary = "瀹℃牳璁捐椤圭洰锛堝緟瀹℃牳鈫掑緟褰掓。锛�")
+    @PutMapping("/submit-approval")
+    @Operation(summary = "鎻愪氦璁捐椤圭洰瀹℃壒锛堝緟瀹℃牳鈫掑鎵逛腑锛�")
     @Parameter(name = "id", description = "缂栧彿", required = true)
+    @Parameter(name = "processDefinitionKey", description = "娴佺▼瀹氫箟 Key", required = true)
     @PreAuthorize("@ss.hasPermission('mes:pd-project:update')")
-    public CommonResult<Boolean> auditProject(@RequestParam("id") Long id) {
-        projectService.auditProject(id);
+    public CommonResult<Boolean> submitProjectApproval(@RequestParam("id") Long id,
+                                                       @RequestParam("processDefinitionKey") String processDefinitionKey) {
+        projectService.submitProjectApproval(id, processDefinitionKey);
         return success(true);
     }
 
+    @GetMapping("/approve-process-list")
+    @Operation(summary = "鑾峰緱璁捐椤圭洰瀹℃壒娴佺▼鍒楄〃")
+    @PreAuthorize("@ss.hasPermission('mes:pd-project:update')")
+    public CommonResult<List<Map<String, Object>>> getProjectApproveProcessDefinitionList() {
+        return success(projectService.getProjectApproveProcessDefinitionList());
+    }
+
     @PutMapping("/archive")
     @Operation(summary = "褰掓。璁捐椤圭洰锛堝緟褰掓。鈫掑凡褰掓。锛夛紝鍚屾椂鑷姩鍒涘缓褰掓。鍙拌处")
     @Parameter(name = "id", description = "缂栧彿", required = true)
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pd/project/vo/MesPdProjectRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pd/project/vo/MesPdProjectRespVO.java
index d0ea908..28a581f 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pd/project/vo/MesPdProjectRespVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pd/project/vo/MesPdProjectRespVO.java
@@ -66,6 +66,9 @@
     @ExcelProperty("澶囨敞")
     private String remark;
 
+    @Schema(description = "BPM 娴佺▼瀹炰緥缂栧彿")
+    private String processInstanceId;
+
     @Schema(description = "鍒涘缓鏃堕棿", requiredMode = Schema.RequiredMode.REQUIRED)
     @ExcelProperty("鍒涘缓鏃堕棿")
     private LocalDateTime createTime;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/batch/MesWmBatchController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/batch/MesWmBatchController.java
index 5a9257e..6fff993 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/batch/MesWmBatchController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/batch/MesWmBatchController.java
@@ -6,7 +6,10 @@
 import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchPageReqVO;
+import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchProcessTraceRespVO;
+import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchPurchaseSourceRespVO;
 import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchRespVO;
+import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchSalesTargetRespVO;
 import cn.iocoder.yudao.module.crm.api.customer.CrmCustomerApi;
 import cn.iocoder.yudao.module.crm.api.customer.dto.CrmCustomerRespDTO;
 import cn.iocoder.yudao.module.srm.api.supplier.SrmSupplierApi;
@@ -15,6 +18,7 @@
 import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemRespDTO;
 
 import cn.iocoder.yudao.module.mes.dal.dataobject.md.workstation.MesMdWorkstationDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.process.MesProProcessDO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.task.MesProTaskDO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.tm.tool.MesTmToolDO;
@@ -23,6 +27,7 @@
 import cn.iocoder.yudao.module.mdm.api.unit.dto.MdmUnitMeasureRespDTO;
 
 import cn.iocoder.yudao.module.mes.service.md.workstation.MesMdWorkstationService;
+import cn.iocoder.yudao.module.mes.service.pro.process.MesProProcessService;
 import cn.iocoder.yudao.module.mes.service.pro.task.MesProTaskService;
 import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderService;
 import cn.iocoder.yudao.module.mes.service.tm.tool.MesTmToolService;
@@ -71,6 +76,8 @@
     private MesMdWorkstationService workstationService;
     @Resource
     private MesTmToolService toolService;
+    @Resource
+    private MesProProcessService processService;
 
     @GetMapping("/get")
     @Operation(summary = "鑾峰緱鎵规璇︽儏")
@@ -105,6 +112,42 @@
     public CommonResult<List<MesWmBatchRespVO>> getBackwardList(@RequestParam("code") @Valid String code) {
         List<MesWmBatchDO> list = batchService.getBackwardBatchList(code);
         return success(buildBatchRespVOList(list));
+    }
+
+    @GetMapping("/purchase-sources")
+    @Operation(summary = "鎵规閲囪喘鏉ユ簮锛堥噰璐叆搴撳崟 + IQC锛�")
+    @Parameter(name = "code", description = "鎵规缂栫爜", required = true, example = "BATCH20250314001")
+    @PreAuthorize("@ss.hasPermission('mes:wm-batch:query')")
+    public CommonResult<List<MesWmBatchPurchaseSourceRespVO>> getPurchaseSourceList(@RequestParam("code") @Valid String code) {
+        List<MesWmBatchPurchaseSourceRespVO> list = batchService.getPurchaseSourceList(code);
+        return success(buildPurchaseSourceRespVOList(list));
+    }
+
+    @GetMapping("/sales-targets")
+    @Operation(summary = "鎵规閿�鍞幓鍚戯紙閿�鍞嚭搴撳崟 + OQC锛�")
+    @Parameter(name = "code", description = "鎵规缂栫爜", required = true, example = "BATCH20250314001")
+    @PreAuthorize("@ss.hasPermission('mes:wm-batch:query')")
+    public CommonResult<List<MesWmBatchSalesTargetRespVO>> getSalesTargetList(@RequestParam("code") @Valid String code) {
+        List<MesWmBatchSalesTargetRespVO> list = batchService.getSalesTargetList(code);
+        return success(buildSalesTargetRespVOList(list));
+    }
+
+    @GetMapping("/process-trace")
+    @Operation(summary = "鎵规宸ュ簭娴佽浆锛堜骇鍑�/鎶曞叆浜嬩欢锛�")
+    @Parameter(name = "code", description = "鎵规缂栫爜", required = true, example = "BATCH20250314001")
+    @PreAuthorize("@ss.hasPermission('mes:wm-batch:query')")
+    public CommonResult<List<MesWmBatchProcessTraceRespVO>> getProcessTraceList(@RequestParam("code") @Valid String code) {
+        List<MesWmBatchProcessTraceRespVO> list = batchService.getProcessTraceList(code);
+        return success(buildProcessTraceRespVOList(list));
+    }
+
+    @GetMapping("/get-by-sn")
+    @Operation(summary = "鏍规嵁 SN 鐮佸弽鏌ユ壒娆�")
+    @Parameter(name = "sn", description = "SN 搴忓垪鍙�", required = true, example = "SN20250314001")
+    @PreAuthorize("@ss.hasPermission('mes:wm-batch:query')")
+    public CommonResult<MesWmBatchRespVO> getBatchBySn(@RequestParam("sn") @Valid String sn) {
+        MesWmBatchDO batch = batchService.getBatchBySn(sn);
+        return success(buildBatchRespVO(batch));
     }
 
     // ==================== 鎷兼帴 VO ====================
@@ -162,4 +205,58 @@
         return buildBatchRespVOList(Collections.singletonList(batch)).get(0);
     }
 
+    private List<MesWmBatchPurchaseSourceRespVO> buildPurchaseSourceRespVOList(List<MesWmBatchPurchaseSourceRespVO> list) {
+        if (CollUtil.isEmpty(list)) {
+            return Collections.emptyList();
+        }
+        Map<Long, MdmItemRespDTO> itemMap = mdmItemApi.getItemMap(
+                convertSet(list, MesWmBatchPurchaseSourceRespVO::getItemId));
+        Map<Long, SrmSupplierRespDTO> vendorMap = srmSupplierApi.getSupplierList(
+                convertSet(list, MesWmBatchPurchaseSourceRespVO::getVendorId)).getCheckedData().stream()
+                .collect(Collectors.toMap(SrmSupplierRespDTO::getId, s -> s));
+        list.forEach(vo -> {
+            MapUtils.findAndThen(itemMap, vo.getItemId(), item -> {
+                vo.setItemCode(item.getCode()).setItemName(item.getName());
+            });
+            MapUtils.findAndThen(vendorMap, vo.getVendorId(),
+                    vendor -> vo.setVendorCode(vendor.getCode()).setVendorName(vendor.getName()));
+        });
+        return list;
+    }
+
+    private List<MesWmBatchSalesTargetRespVO> buildSalesTargetRespVOList(List<MesWmBatchSalesTargetRespVO> list) {
+        if (CollUtil.isEmpty(list)) {
+            return Collections.emptyList();
+        }
+        Map<Long, MdmItemRespDTO> itemMap = mdmItemApi.getItemMap(
+                convertSet(list, MesWmBatchSalesTargetRespVO::getItemId));
+        Map<Long, CrmCustomerRespDTO> clientMap = customerApi.getCustomerMap(
+                convertSet(list, MesWmBatchSalesTargetRespVO::getClientId));
+        list.forEach(vo -> {
+            MapUtils.findAndThen(itemMap, vo.getItemId(), item -> {
+                vo.setItemCode(item.getCode()).setItemName(item.getName());
+            });
+            MapUtils.findAndThen(clientMap, vo.getClientId(),
+                    client -> vo.setClientName(client.getName()));
+        });
+        return list;
+    }
+
+    private List<MesWmBatchProcessTraceRespVO> buildProcessTraceRespVOList(List<MesWmBatchProcessTraceRespVO> list) {
+        if (CollUtil.isEmpty(list)) {
+            return Collections.emptyList();
+        }
+        Map<Long, MesProWorkOrderDO> workOrderMap = workOrderService.getWorkOrderMap(
+                convertSet(list, MesWmBatchProcessTraceRespVO::getWorkOrderId));
+        Map<Long, MesProProcessDO> processMap = processService.getProcessMap(
+                convertSet(list, MesWmBatchProcessTraceRespVO::getProcessId));
+        list.forEach(vo -> {
+            MapUtils.findAndThen(workOrderMap, vo.getWorkOrderId(),
+                    workOrder -> vo.setWorkOrderCode(workOrder.getCode()));
+            MapUtils.findAndThen(processMap, vo.getProcessId(),
+                    process -> vo.setProcessCode(process.getCode()).setProcessName(process.getName()));
+        });
+        return list;
+    }
+
 }
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/batch/vo/MesWmBatchProcessTraceRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/batch/vo/MesWmBatchProcessTraceRespVO.java
new file mode 100644
index 0000000..ce165eb
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/batch/vo/MesWmBatchProcessTraceRespVO.java
@@ -0,0 +1,46 @@
+package cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+@Schema(description = "绠$悊鍚庡彴 - MES 鎵规宸ュ簭娴佽浆 Response VO")
+@Data
+public class MesWmBatchProcessTraceRespVO {
+
+    @Schema(description = "浜嬩欢绫诲瀷锛欼N-宸ュ簭鎶曞叆 / OUT-宸ュ簭浜у嚭", example = "OUT")
+    private String eventType;
+
+    @Schema(description = "鐢熶骇宸ュ崟 ID", example = "1")
+    private Long workOrderId;
+
+    @Schema(description = "鐢熶骇宸ュ崟缂栧彿", example = "WO20250801001")
+    private String workOrderCode;
+
+    @Schema(description = "宸ュ簭 ID", example = "1")
+    private Long processId;
+
+    @Schema(description = "宸ュ簭缂栫爜", example = "PROC001")
+    private String processCode;
+
+    @Schema(description = "宸ュ簭鍚嶇О", example = "CNC 鍔犲伐")
+    private String processName;
+
+    @Schema(description = "鎵规鍙�", example = "BATCH20250801001")
+    private String batchCode;
+
+    @Schema(description = "鏁伴噺", example = "100")
+    private BigDecimal quantity;
+
+    @Schema(description = "璐ㄩ噺鐘舵�侊紙瀛楀吀 mes_wm_quality_status锛夛紝浠呬骇鍑轰晶鏈夊��", example = "1")
+    private Integer qualityStatus;
+
+    @Schema(description = "浜嬩欢鏃堕棿")
+    private LocalDateTime eventTime;
+
+    @Schema(description = "宸ュ簭搴忓彿锛堟帓搴忕敤锛�", example = "1")
+    private Integer processSort;
+
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/batch/vo/MesWmBatchPurchaseSourceRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/batch/vo/MesWmBatchPurchaseSourceRespVO.java
new file mode 100644
index 0000000..ddbd9e9
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/batch/vo/MesWmBatchPurchaseSourceRespVO.java
@@ -0,0 +1,52 @@
+package cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+@Schema(description = "绠$悊鍚庡彴 - MES 鎵规閲囪喘鏉ユ簮 Response VO")
+@Data
+public class MesWmBatchPurchaseSourceRespVO {
+
+    @Schema(description = "閲囪喘鍏ュ簱鍗曞彿", example = "IR20250731001")
+    private String receiptCode;
+
+    @Schema(description = "鍏ュ簱鏃ユ湡")
+    private LocalDateTime receiptDate;
+
+    @Schema(description = "閲囪喘璁㈠崟缂栧彿", example = "PO20250731001")
+    private String purchaseOrderCode;
+
+    @Schema(description = "渚涘簲鍟� ID", example = "1")
+    private Long vendorId;
+
+    @Schema(description = "渚涘簲鍟嗙紪鐮�", example = "V001")
+    private String vendorCode;
+
+    @Schema(description = "渚涘簲鍟嗗悕绉�", example = "渚涘簲鍟咥")
+    private String vendorName;
+
+    @Schema(description = "鏉ユ枡妫�楠屽崟鍙凤紙IQC锛�", example = "IQC20250731001")
+    private String iqcCode;
+
+    @Schema(description = "IQC 妫�楠岀粨璁猴紙瀛楀吀 mes_qc_check_result锛�", example = "1")
+    private Integer checkResult;
+
+    @Schema(description = "鐗╂枡 ID", example = "1")
+    private Long itemId;
+
+    @Schema(description = "鐗╂枡缂栫爜", example = "ITEM001")
+    private String itemCode;
+
+    @Schema(description = "鐗╂枡鍚嶇О", example = "浜у搧A")
+    private String itemName;
+
+    @Schema(description = "鎵规鍙�", example = "BATCH20250731001")
+    private String batchCode;
+
+    @Schema(description = "鍏ュ簱鏁伴噺", example = "100")
+    private BigDecimal receivedQuantity;
+
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/batch/vo/MesWmBatchSalesTargetRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/batch/vo/MesWmBatchSalesTargetRespVO.java
new file mode 100644
index 0000000..5da84ae
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/batch/vo/MesWmBatchSalesTargetRespVO.java
@@ -0,0 +1,55 @@
+package cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+@Schema(description = "绠$悊鍚庡彴 - MES 鎵规閿�鍞幓鍚� Response VO")
+@Data
+public class MesWmBatchSalesTargetRespVO {
+
+    @Schema(description = "閿�鍞嚭搴撳崟鍙�", example = "SO20250801001")
+    private String salesCode;
+
+    @Schema(description = "鍑哄簱鏃ユ湡")
+    private LocalDateTime salesDate;
+
+    @Schema(description = "閿�鍞鍗曠紪鍙�", example = "SO20250801001")
+    private String salesOrderCode;
+
+    @Schema(description = "瀹㈡埛 ID", example = "1")
+    private Long clientId;
+
+    @Schema(description = "瀹㈡埛缂栫爜", example = "C001")
+    private String clientCode;
+
+    @Schema(description = "瀹㈡埛鍚嶇О", example = "瀹㈡埛A")
+    private String clientName;
+
+    @Schema(description = "鍑哄巶妫�楠屽崟鍙凤紙OQC锛�", example = "OQC20250801001")
+    private String oqcCode;
+
+    @Schema(description = "OQC 妫�楠岀粨璁猴紙瀛楀吀 mes_qc_check_result锛�", example = "1")
+    private Integer checkResult;
+
+    @Schema(description = "鐗╂枡 ID", example = "1")
+    private Long itemId;
+
+    @Schema(description = "鐗╂枡缂栫爜", example = "ITEM001")
+    private String itemCode;
+
+    @Schema(description = "鐗╂枡鍚嶇О", example = "浜у搧A")
+    private String itemName;
+
+    @Schema(description = "鎵规鍙�", example = "BATCH20250801001")
+    private String batchCode;
+
+    @Schema(description = "鍑哄簱鏁伴噺", example = "100")
+    private BigDecimal quantity;
+
+    @Schema(description = "璐ㄩ噺鐘舵�侊紙瀛楀吀 mes_wm_quality_status锛�", example = "1")
+    private Integer qualityStatus;
+
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pd/project/MesPdProjectDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pd/project/MesPdProjectDO.java
index c6f449e..bbfd926 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pd/project/MesPdProjectDO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pd/project/MesPdProjectDO.java
@@ -58,6 +58,14 @@
      */
     private Integer status;
     /**
+     * BPM 娴佺▼瀹炰緥缂栧彿
+     */
+    private String processInstanceId;
+    /**
+     * BPM 娴佺▼瀹氫箟 Key
+     */
+    private String processDefinitionKey;
+    /**
      * 涓昏璁″笀
      *
      * 鍏宠仈 AdminUserDO#getId()
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/batch/MesWmBatchMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/batch/MesWmBatchMapper.java
index 8294d56..084e2ad 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/batch/MesWmBatchMapper.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/batch/MesWmBatchMapper.java
@@ -7,6 +7,9 @@
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
 import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchPageReqVO;
+import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchProcessTraceRespVO;
+import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchPurchaseSourceRespVO;
+import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchSalesTargetRespVO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch.MesWmBatchDO;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import org.apache.ibatis.annotations.Mapper;
@@ -185,4 +188,28 @@
      */
     List<MesWmBatchDO> selectListByBackward(String batchCode);
 
+    /**
+     * 鏌ヨ鎵规閲囪喘鏉ユ簮锛堥噰璐叆搴撳崟 + IQC锛�
+     *
+     * @param batchCode 鎵规鍙�
+     * @return 閲囪喘鏉ユ簮鍒楄〃
+     */
+    List<MesWmBatchPurchaseSourceRespVO> selectPurchaseSourceList(String batchCode);
+
+    /**
+     * 鏌ヨ鎵规閿�鍞幓鍚戯紙閿�鍞嚭搴撳崟 + OQC锛�
+     *
+     * @param batchCode 鎵规鍙�
+     * @return 閿�鍞幓鍚戝垪琛�
+     */
+    List<MesWmBatchSalesTargetRespVO> selectSalesTargetList(String batchCode);
+
+    /**
+     * 鏌ヨ鎵规宸ュ簭娴佽浆锛堜骇鍑�/鎶曞叆浜嬩欢锛�
+     *
+     * @param batchCode 鎵规鍙�
+     * @return 宸ュ簭娴佽浆鍒楄〃
+     */
+    List<MesWmBatchProcessTraceRespVO> selectProcessTraceList(String batchCode);
+
 }
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
index ca229f4..a5459f0 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
@@ -773,6 +773,9 @@
     ErrorCode PD_PROJECT_NOT_UPLOAD_FOR_AUDIT = new ErrorCode(1_040_800_005, "鍙湁寰呭鏍哥姸鎬佺殑璁捐椤圭洰鎵嶈兘瀹℃牳");
     ErrorCode PD_PROJECT_NOT_AUDIT_FOR_ARCHIVE = new ErrorCode(1_040_800_006, "鍙湁寰呭綊妗g姸鎬佺殑璁捐椤圭洰鎵嶈兘褰掓。");
     ErrorCode PD_PROJECT_AUDIT_NOT_FINISHED = new ErrorCode(1_040_800_007, "璇ラ」鐩笅瀛樺湪鏈鏍哥殑璧勬枡锛岃鍏堝畬鎴愭墍鏈夎祫鏂欏鏍�");
+    ErrorCode PD_PROJECT_NOT_UPLOAD_FOR_APPROVAL = new ErrorCode(1_040_800_008, "鍙湁寰呭鏍哥姸鎬佺殑璁捐椤圭洰鎵嶈兘鎻愪氦瀹℃壒");
+    ErrorCode PD_PROJECT_NOT_APPROVING = new ErrorCode(1_040_800_009, "璁捐椤圭洰涓嶅浜庡鎵逛腑鐘舵��");
+    ErrorCode PD_PROJECT_BPM_CATEGORY_NOT_EXISTS = new ErrorCode(1_040_800_010, "璁捐椤圭洰瀹℃壒鍒嗙被涓嶅瓨鍦紝璇峰厛閰嶇疆 BPM 瀹℃壒娴佺▼");
 
     // ========== MES 浜у搧璁捐-璧勬枡瀛愯〃锛�1-040-801-000锛� ==========
     ErrorCode PD_DOCUMENT_NOT_EXISTS = new ErrorCode(1_040_801_000, "璁捐璧勬枡涓嶅瓨鍦�");
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/MesPdStatusConstants.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/MesPdStatusConstants.java
index 1771e05..5b763af 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/MesPdStatusConstants.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/MesPdStatusConstants.java
@@ -32,5 +32,9 @@
      * 宸插綊妗�
      */
     public static final int ARCHIVE = 4;
+    /**
+     * 瀹℃壒涓紙BPM 瀹℃壒杩涜涓級
+     */
+    public static final int APPROVING = 5;
 
 }
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pd/MesPdProjectStatusEnum.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pd/MesPdProjectStatusEnum.java
index 94fd5e8..8aa13ec 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pd/MesPdProjectStatusEnum.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pd/MesPdProjectStatusEnum.java
@@ -39,7 +39,7 @@
     /**
      * 寰呭綊妗�
      *
-     * 瀵瑰簲 MesPdProjectService#auditProject 鏂规硶
+     * 瀵瑰簲 MesPdProjectService#updateProjectAuditStatus 鏂规硶锛圔PM 瀹℃壒閫氳繃鍚庯級
      */
     AUDIT(MesPdStatusConstants.AUDIT, "寰呭綊妗�"),
     /**
@@ -47,7 +47,13 @@
      *
      * 瀵瑰簲 MesPdProjectService#archiveProject 鏂规硶
      */
-    ARCHIVE(MesPdStatusConstants.ARCHIVE, "宸插綊妗�");
+    ARCHIVE(MesPdStatusConstants.ARCHIVE, "宸插綊妗�"),
+    /**
+     * 瀹℃壒涓�
+     *
+     * 瀵瑰簲 MesPdProjectService#submitProjectApproval 鏂规硶
+     */
+    APPROVING(MesPdStatusConstants.APPROVING, "瀹℃壒涓�");
 
     public static final Integer[] ARRAYS = Arrays.stream(values()).map(MesPdProjectStatusEnum::getStatus).toArray(Integer[]::new);
 
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pd/project/MesPdProjectService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pd/project/MesPdProjectService.java
index 2e1bb45..54deaeb 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pd/project/MesPdProjectService.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pd/project/MesPdProjectService.java
@@ -81,11 +81,29 @@
     void uploadProject(Long id, Long userId);
 
     /**
-     * 瀹℃牳璁捐椤圭洰锛堝緟瀹℃牳鈫掑緟褰掓。锛�
+     * 鎻愪氦璁捐椤圭洰瀹℃壒锛堝緟瀹℃牳鈫掑鎵逛腑锛�
+     * <p>
+     * 鍒涘缓 BPM 娴佺▼瀹炰緥锛屽鎵归�氳繃鍚庣敱鐩戝惉鍣ㄥ洖璋冩洿鏂颁负寰呭綊妗�
      *
-     * @param id 缂栧彿
+     * @param id                  缂栧彿
+     * @param processDefinitionKey 娴佺▼瀹氫箟 Key
      */
-    void auditProject(Long id);
+    void submitProjectApproval(Long id, String processDefinitionKey);
+
+    /**
+     * 鑾峰緱璁捐椤圭洰瀹℃壒娴佺▼鍒楄〃
+     *
+     * @return 娴佺▼鍒楄〃锛坕d/name/version/key锛�
+     */
+    List<Map<String, Object>> getProjectApproveProcessDefinitionList();
+
+    /**
+     * 鏇存柊璁捐椤圭洰瀹℃壒鐘舵�侊紙BPM 鐩戝惉鍣ㄥ洖璋冿級
+     *
+     * @param id       缂栧彿
+     * @param bpmResult BPM 瀹℃壒缁撴灉
+     */
+    void updateProjectAuditStatus(Long id, Integer bpmResult);
 
     /**
      * 褰掓。璁捐椤圭洰锛堝緟褰掓。鈫掑凡褰掓。锛�
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pd/project/MesPdProjectServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pd/project/MesPdProjectServiceImpl.java
index 12a637d..6648c60 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pd/project/MesPdProjectServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pd/project/MesPdProjectServiceImpl.java
@@ -1,6 +1,14 @@
 package cn.iocoder.yudao.module.mes.service.pd.project;
 
+import cn.hutool.core.collection.CollUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi;
+import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
+import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO;
+import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO;
+import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum;
+import cn.iocoder.yudao.module.bpm.service.definition.BpmCategoryService;
+import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService;
 import cn.iocoder.yudao.module.mes.controller.admin.pd.project.vo.MesPdProjectPageReqVO;
 import cn.iocoder.yudao.module.mes.controller.admin.pd.project.vo.MesPdProjectSaveReqVO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.pd.document.MesPdDocumentDO;
@@ -16,18 +24,24 @@
 import cn.iocoder.yudao.module.mes.service.pd.document.MesPdDocumentService;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.flowable.engine.repository.ProcessDefinition;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
 
 import java.time.LocalDateTime;
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
+import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
 
 /**
@@ -37,7 +51,13 @@
  */
 @Service
 @Validated
+@Slf4j
 public class MesPdProjectServiceImpl implements MesPdProjectService {
+
+    /**
+     * BPM 浜у搧椤圭洰瀹℃壒鍒嗙被缂栫爜
+     */
+    private static final String BPM_PROCESS_DEFINITION_CATEGORY_CODE = "mes_pd_project_approve";
 
     @Resource
     private MesPdProjectMapper projectMapper;
@@ -55,6 +75,15 @@
     @Resource
     @Lazy
     private MesMdAutoCodeRecordService autoCodeRecordService;
+
+    @Resource
+    private BpmProcessInstanceApi processInstanceApi;
+
+    @Resource
+    private BpmCategoryService bpmCategoryService;
+
+    @Resource
+    private BpmProcessDefinitionService bpmProcessDefinitionService;
 
     @Override
     @Transactional(rollbackFor = Exception.class)
@@ -180,27 +209,105 @@
     }
 
     @Override
-    public void auditProject(Long id) {
-        // 鏍¢獙瀛樺湪
+    @Transactional(rollbackFor = Exception.class)
+    public void submitProjectApproval(Long id, String processDefinitionKey) {
+        // 1. 鏍¢獙瀛樺湪 + 寰呭鏍哥姸鎬�
         MesPdProjectDO project = validateProjectExists(id);
-        // 鏍¢獙鐘舵�佷负寰呭鏍�
         if (!MesPdProjectStatusEnum.UPLOAD.getStatus().equals(project.getStatus())) {
-            throw exception(PD_PROJECT_NOT_UPLOAD_FOR_AUDIT);
+            throw exception(PD_PROJECT_NOT_UPLOAD_FOR_APPROVAL);
         }
-        // 鏍¢獙璇ラ」鐩笅鎵�鏈夎祫鏂欏鏍歌褰曞潎宸插鏍革紙涓嶅瓨鍦ㄥ緟瀹℃牳鐨勮褰曪級
+        // 2. 鏍¢獙璇ラ」鐩笅鎵�鏈夎祫鏂欏鏍歌褰曞潎宸插鏍革紙涓嶅瓨鍦ㄥ緟瀹℃牳鐨勮褰曪級
         List<MesPdDocumentDO> documents = documentService.getDocumentListByProjectId(id);
         List<Long> documentIds = documents.stream().map(MesPdDocumentDO::getId).toList();
         if (documentAuditMapper.existsPendingAuditByDocumentIds(documentIds)) {
             throw exception(PD_PROJECT_AUDIT_NOT_FINISHED);
         }
-        // 鏇存柊鐘舵��
+        // 3. 鍒涘缓 BPM 娴佺▼瀹炰緥
+        String processInstanceId = processInstanceApi.createProcessInstance(getLoginUserId(),
+                new BpmProcessInstanceCreateReqDTO()
+                        .setProcessDefinitionKey(processDefinitionKey)
+                        .setBusinessKey(String.valueOf(id)));
+        // 4. 鏇存柊椤圭洰鐘舵�佷负瀹℃壒涓�
         projectMapper.updateById(MesPdProjectDO.builder()
                 .id(id)
-                .status(MesPdProjectStatusEnum.AUDIT.getStatus())
+                .status(MesPdProjectStatusEnum.APPROVING.getStatus())
+                .processInstanceId(processInstanceId)
+                .processDefinitionKey(processDefinitionKey)
                 .build());
     }
 
     @Override
+    public List<Map<String, Object>> getProjectApproveProcessDefinitionList() {
+        // 1. 鏍¢獙鍒嗙被鏄惁瀛樺湪
+        List<BpmCategoryDO> categories = bpmCategoryService.getCategoryListByCode(
+                Collections.singletonList(BPM_PROCESS_DEFINITION_CATEGORY_CODE));
+        if (CollUtil.isEmpty(categories)) {
+            throw exception(PD_PROJECT_BPM_CATEGORY_NOT_EXISTS);
+        }
+        // 2. 鑾峰彇鍒嗙被涓嬬殑娴佺▼瀹氫箟淇℃伅
+        List<BpmProcessDefinitionInfoDO> definitionInfoList = bpmProcessDefinitionService
+                .getProcessDefinitionInfoListByCategory(BPM_PROCESS_DEFINITION_CATEGORY_CODE);
+        if (CollUtil.isEmpty(definitionInfoList)) {
+            return Collections.emptyList();
+        }
+        // 3. 杩囨护婵�娲荤姸鎬侊紝淇濈暀鏈�鏂扮増鏈�
+        Map<String, ProcessDefinition> latestVersionMap = new HashMap<>();
+        for (BpmProcessDefinitionInfoDO info : definitionInfoList) {
+            ProcessDefinition pd = bpmProcessDefinitionService.getProcessDefinition(info.getProcessDefinitionId());
+            if (pd == null || pd.isSuspended()) {
+                continue;
+            }
+            ProcessDefinition existing = latestVersionMap.get(pd.getKey());
+            if (existing == null || pd.getVersion() > existing.getVersion()) {
+                latestVersionMap.put(pd.getKey(), pd);
+            }
+        }
+        // 4. 杩斿洖娴佺▼瀹氫箟鍒楄〃
+        List<Map<String, Object>> result = new ArrayList<>();
+        for (ProcessDefinition pd : latestVersionMap.values()) {
+            Map<String, Object> item = new HashMap<>();
+            item.put("id", pd.getId());
+            item.put("key", pd.getKey());
+            item.put("name", pd.getName());
+            result.add(item);
+        }
+        return result;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void updateProjectAuditStatus(Long id, Integer bpmResult) {
+        // 1. 鏍¢獙瀛樺湪
+        MesPdProjectDO project = validateProjectExists(id);
+        if (!MesPdProjectStatusEnum.APPROVING.getStatus().equals(project.getStatus())) {
+            log.warn("[updateProjectAuditStatus] 璁捐椤圭洰({}) 涓嶅浜庡鎵逛腑鐘舵�侊紝褰撳墠鐘舵�侊細{}", id, project.getStatus());
+            return;
+        }
+        // 2. 鏍规嵁瀹℃壒缁撴灉鏇存柊鐘舵��
+        Integer newStatus = convertBpmResultToProjectStatus(bpmResult);
+        if (newStatus != null) {
+            projectMapper.updateById(MesPdProjectDO.builder()
+                    .id(id)
+                    .status(newStatus)
+                    .build());
+        }
+    }
+
+    /**
+     * 杞崲 BPM 瀹℃壒缁撴灉涓鸿璁¢」鐩姸鎬�
+     */
+    private Integer convertBpmResultToProjectStatus(Integer bpmResult) {
+        if (BpmTaskStatusEnum.APPROVE.getStatus().equals(bpmResult)) {
+            return MesPdProjectStatusEnum.AUDIT.getStatus();
+        } else if (BpmTaskStatusEnum.REJECT.getStatus().equals(bpmResult)) {
+            return MesPdProjectStatusEnum.UPLOAD.getStatus();
+        } else if (BpmTaskStatusEnum.CANCEL.getStatus().equals(bpmResult)) {
+            return MesPdProjectStatusEnum.UPLOAD.getStatus();
+        }
+        return null;
+    }
+
+    @Override
     @Transactional(rollbackFor = Exception.class)
     public void archiveProject(Long id, Long userId) {
         // 鏍¢獙瀛樺湪
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pd/project/listener/MesPdProjectStatusListener.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pd/project/listener/MesPdProjectStatusListener.java
new file mode 100644
index 0000000..31402d1
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pd/project/listener/MesPdProjectStatusListener.java
@@ -0,0 +1,47 @@
+package cn.iocoder.yudao.module.mes.service.pd.project.listener;
+
+import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEvent;
+import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEventListener;
+import cn.iocoder.yudao.module.mes.service.pd.project.MesPdProjectService;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+/**
+ * 璁捐椤圭洰瀹℃壒鐘舵�佺洃鍚櫒
+ *
+ * 鐩戝惉 BPM 娴佺▼瀹炰緥鐘舵�佸彉鏇翠簨浠讹紝鏇存柊璁捐椤圭洰鐨勫鎵圭姸鎬�
+ *
+ * @author 瓒呯骇绠$悊鍛�
+ */
+@Component
+@Slf4j
+public class MesPdProjectStatusListener extends BpmProcessInstanceStatusEventListener {
+
+    /**
+     * BPM 璁捐椤圭洰瀹℃壒娴佺▼瀹氫箟 key
+     */
+    private static final String BPM_PROCESS_DEFINITION_KEY = "mes-pd-project-audit";
+
+    @Resource
+    private MesPdProjectService projectService;
+
+    @Override
+    protected String getProcessDefinitionKey() {
+        return BPM_PROCESS_DEFINITION_KEY;
+    }
+
+    @Override
+    protected void onEvent(BpmProcessInstanceStatusEvent event) {
+        Long projectId;
+        try {
+            projectId = Long.parseLong(event.getBusinessKey());
+        } catch (NumberFormatException e) {
+            log.warn("[onEvent] businessKey({}) 涓嶆槸鏈夋晥鐨勮璁¢」鐩紪鍙�", event.getBusinessKey());
+            return;
+        }
+        log.info("[onEvent] 鏀跺埌BPM瀹℃壒浜嬩欢锛宲rojectId={}, status={}", projectId, event.getStatus());
+        projectService.updateProjectAuditStatus(projectId, event.getStatus());
+    }
+
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/batch/MesWmBatchService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/batch/MesWmBatchService.java
index 66048dd..cf58d84 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/batch/MesWmBatchService.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/batch/MesWmBatchService.java
@@ -3,6 +3,9 @@
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchGenerateReqVO;
 import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchPageReqVO;
+import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchProcessTraceRespVO;
+import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchPurchaseSourceRespVO;
+import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchSalesTargetRespVO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch.MesWmBatchDO;
 
 import java.util.List;
@@ -96,4 +99,36 @@
      */
     Long getBatchCountByToolId(Long toolId);
 
+    /**
+     * 鑾峰緱鎵规閲囪喘鏉ユ簮锛堥噰璐叆搴撳崟 + IQC锛�
+     *
+     * @param code 鎵规鍙�
+     * @return 閲囪喘鏉ユ簮鍒楄〃
+     */
+    List<MesWmBatchPurchaseSourceRespVO> getPurchaseSourceList(String code);
+
+    /**
+     * 鑾峰緱鎵规閿�鍞幓鍚戯紙閿�鍞嚭搴撳崟 + OQC锛�
+     *
+     * @param code 鎵规鍙�
+     * @return 閿�鍞幓鍚戝垪琛�
+     */
+    List<MesWmBatchSalesTargetRespVO> getSalesTargetList(String code);
+
+    /**
+     * 鑾峰緱鎵规宸ュ簭娴佽浆锛堜骇鍑�/鎶曞叆浜嬩欢锛�
+     *
+     * @param code 鎵规鍙�
+     * @return 宸ュ簭娴佽浆鍒楄〃
+     */
+    List<MesWmBatchProcessTraceRespVO> getProcessTraceList(String code);
+
+    /**
+     * 鏍规嵁 SN 鐮佽幏寰楁壒娆�
+     *
+     * @param sn SN 鐮�
+     * @return 鎵规璁板綍锛堟湭鍛戒腑杩斿洖 null锛�
+     */
+    MesWmBatchDO getBatchBySn(String sn);
+
 }
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/batch/MesWmBatchServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/batch/MesWmBatchServiceImpl.java
index d218f8c..ea88533 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/batch/MesWmBatchServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/batch/MesWmBatchServiceImpl.java
@@ -6,9 +6,14 @@
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchGenerateReqVO;
 import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchPageReqVO;
+import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchProcessTraceRespVO;
+import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchPurchaseSourceRespVO;
+import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchSalesTargetRespVO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.mdm.MesMdmItemDO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch.MesWmBatchDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.sn.MesWmSnDO;
 import cn.iocoder.yudao.module.mes.dal.mysql.wm.batch.MesWmBatchMapper;
+import cn.iocoder.yudao.module.mes.dal.mysql.wm.sn.MesWmSnMapper;
 import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants;
 import cn.iocoder.yudao.module.mes.enums.md.autocode.MesMdAutoCodeRuleCodeEnum;
 import cn.iocoder.yudao.module.mes.service.md.autocode.MesMdAutoCodeRecordService;
@@ -24,6 +29,7 @@
 import org.springframework.validation.annotation.Validated;
 
 import java.util.ArrayList;
+import java.util.Comparator;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -51,6 +57,8 @@
 
     @Resource
     private MesMdmItemService mdmItemService;
+    @Resource
+    private MesWmSnMapper snMapper;
     @Resource
     private MdmItemBatchConfigApi itemBatchConfigApi;
     @Resource
@@ -372,4 +380,39 @@
         return batchMapper.selectCountByToolId(toolId);
     }
 
+    @Override
+    public List<MesWmBatchPurchaseSourceRespVO> getPurchaseSourceList(String code) {
+        return batchMapper.selectPurchaseSourceList(code);
+    }
+
+    @Override
+    public List<MesWmBatchSalesTargetRespVO> getSalesTargetList(String code) {
+        return batchMapper.selectSalesTargetList(code);
+    }
+
+    @Override
+    public List<MesWmBatchProcessTraceRespVO> getProcessTraceList(String code) {
+        List<MesWmBatchProcessTraceRespVO> list = batchMapper.selectProcessTraceList(code);
+        if (CollUtil.isEmpty(list)) {
+            return list;
+        }
+        // 鎸夊伐鍗曘�佸伐搴忓簭鍙枫�佷簨浠舵椂闂存帓搴忥紙sort 鍙兘涓虹┖锛岀┖鍊煎厹搴曪級
+        list.sort(Comparator.comparing(MesWmBatchProcessTraceRespVO::getWorkOrderId,
+                        Comparator.nullsLast(Comparator.naturalOrder()))
+                .thenComparing(MesWmBatchProcessTraceRespVO::getProcessSort,
+                        Comparator.nullsLast(Comparator.naturalOrder()))
+                .thenComparing(MesWmBatchProcessTraceRespVO::getEventTime,
+                        Comparator.nullsLast(Comparator.naturalOrder())));
+        return list;
+    }
+
+    @Override
+    public MesWmBatchDO getBatchBySn(String sn) {
+        MesWmSnDO snDO = snMapper.selectOne(MesWmSnDO::getCode, sn);
+        if (snDO == null || StrUtil.isBlank(snDO.getBatchCode())) {
+            return null;
+        }
+        return batchMapper.selectByCode(snDO.getBatchCode());
+    }
+
 }
diff --git a/yudao-module-mes/src/main/resources/mapper/wm/batch/MesWmBatchMapper.xml b/yudao-module-mes/src/main/resources/mapper/wm/batch/MesWmBatchMapper.xml
index 22fba71..0eda416 100644
--- a/yudao-module-mes/src/main/resources/mapper/wm/batch/MesWmBatchMapper.xml
+++ b/yudao-module-mes/src/main/resources/mapper/wm/batch/MesWmBatchMapper.xml
@@ -11,14 +11,15 @@
 
     <!--
         鍚戝墠杩芥函锛氫粠鏌愪釜鍘熸潗鏂欐壒娆″嚭鍙戯紝鏌ユ壘瀹冭鍝簺宸ュ崟娑堣�楀悗锛屼骇鍑轰簡鍝簺鎴愬搧鎵规
-        SQL 璺緞锛氬簱瀛樹簨鍔�(娑堣�� OUT) 鈫� 娑堣�楀崟 鈫� 鎶ュ伐璁板綍 鈫� 搴撳瓨浜嬪姟(浜у嚭 IN) 鈫� 鎵规
+        閾捐矾锛氬簱瀛樹簨鍔�(娑堣�� OUT, biz=123, biz_id=娑堣�楀崟id) 鈫� 娑堣�楀崟 鈫� 鎶ュ伐 鈫� 浜у嚭鍗�(feedback_id) 鈫� 搴撳瓨浜嬪姟(浜у嚭 IN, biz=124, biz_id=浜у嚭鍗昳d) 鈫� 鎵规
     -->
     <select id="selectListByForward" parameterType="String" resultMap="BatchTraceResult">
         SELECT DISTINCT pf.work_order_id, pf.item_id, tx_produce.batch_id, tx_produce.batch_code
         FROM mes_wm_transaction tx_consume
-        LEFT JOIN mes_wm_item_consume ic ON tx_consume.biz_id = ic.id AND tx_consume.biz_type = 123 AND ic.deleted = 0
-        LEFT JOIN mes_pro_feedback pf ON pf.id = ic.feedback_id AND pf.deleted = 0
-        LEFT JOIN mes_wm_transaction tx_produce ON tx_produce.biz_id = pf.id AND tx_produce.biz_type = 124 AND tx_produce.deleted = 0
+        JOIN mes_wm_item_consume ic ON tx_consume.biz_id = ic.id AND tx_consume.biz_type = 123 AND ic.deleted = 0
+        JOIN mes_pro_feedback pf ON pf.id = ic.feedback_id AND pf.deleted = 0
+        JOIN mes_wm_product_produce pp ON pp.feedback_id = pf.id AND pp.deleted = 0
+        JOIN mes_wm_transaction tx_produce ON tx_produce.biz_id = pp.id AND tx_produce.biz_type = 124 AND tx_produce.deleted = 0
         WHERE tx_consume.batch_code = #{batchCode}
         AND tx_consume.biz_type = 123
         AND tx_consume.deleted = 0
@@ -27,19 +28,65 @@
 
     <!--
         鍚戝悗杩芥函锛氫粠鏌愪釜鎴愬搧鎵规鍑哄彂锛屾煡鎵剧敓浜у畠鏃舵秷鑰椾簡鍝簺鍘熸潗鏂欐壒娆�
-        SQL 璺緞锛氬簱瀛樹簨鍔�(浜у嚭 IN) 鈫� 浜у嚭鍗� 鈫� 鎶ュ伐璁板綍 鈫� 搴撳瓨浜嬪姟(娑堣�� OUT) 鈫� 鎵规
+        閾捐矾锛氬簱瀛樹簨鍔�(浜у嚭 IN, biz=124, biz_id=浜у嚭鍗昳d) 鈫� 浜у嚭鍗� 鈫� 鎶ュ伐 鈫� 娑堣�楀崟(feedback_id) 鈫� 搴撳瓨浜嬪姟(娑堣�� OUT, biz=123, biz_id=娑堣�楀崟id) 鈫� 鎵规
     -->
     <select id="selectListByBackward" parameterType="String" resultMap="BatchTraceResult">
         SELECT DISTINCT ic.work_order_id, tx_consume.item_id, tx_consume.batch_id, tx_consume.batch_code
         FROM mes_wm_transaction tx_produce
-        LEFT JOIN mes_wm_product_produce pp ON tx_produce.biz_id = pp.id AND tx_produce.biz_type = 124 AND pp.deleted = 0
-        LEFT JOIN mes_pro_feedback pf ON pf.id = pp.feedback_id AND pf.deleted = 0
-        LEFT JOIN mes_wm_transaction tx_consume ON tx_consume.biz_id = pf.id AND tx_consume.biz_type = 123 AND tx_consume.deleted = 0
-        LEFT JOIN mes_wm_item_consume ic ON ic.id = tx_consume.biz_id AND ic.deleted = 0
+        JOIN mes_wm_product_produce pp ON tx_produce.biz_id = pp.id AND tx_produce.biz_type = 124 AND pp.deleted = 0
+        JOIN mes_pro_feedback pf ON pf.id = pp.feedback_id AND pf.deleted = 0
+        JOIN mes_wm_item_consume ic ON ic.feedback_id = pf.id AND ic.deleted = 0
+        JOIN mes_wm_transaction tx_consume ON tx_consume.biz_id = ic.id AND tx_consume.biz_type = 123 AND tx_consume.deleted = 0
         WHERE tx_produce.batch_code = #{batchCode}
         AND tx_produce.biz_type = 124
         AND tx_produce.deleted = 0
         AND tx_consume.batch_id IS NOT NULL
     </select>
 
+    <!-- 鎵规閲囪喘鏉ユ簮锛氭壒娆� 鈫� 閲囪喘鍏ュ簱琛� 鈫� 閲囪喘鍏ュ簱鍗� 鈫� IQC -->
+    <select id="selectPurchaseSourceList" parameterType="String"
+            resultType="cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchPurchaseSourceRespVO">
+        SELECT r.code AS receipt_code, r.receipt_date, r.purchase_order_code, r.vendor_id,
+               iqc.code AS iqc_code, iqc.check_result AS check_result,
+               rl.batch_code, rl.item_id, rl.received_quantity
+        FROM mes_wm_item_receipt_line rl
+        JOIN mes_wm_item_receipt r ON r.id = rl.receipt_id AND r.deleted = 0
+        LEFT JOIN mes_qc_iqc iqc ON iqc.id = r.iqc_id AND iqc.deleted = 0
+        WHERE rl.batch_code = #{batchCode} AND rl.deleted = 0
+    </select>
+
+    <!-- 鎵规閿�鍞幓鍚戯細鎵规 鈫� 閿�鍞嚭搴撹 鈫� 閿�鍞嚭搴撳崟 鈫� OQC -->
+    <select id="selectSalesTargetList" parameterType="String"
+            resultType="cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchSalesTargetRespVO">
+        SELECT s.code AS sales_code, s.sales_date, s.sales_order_code, s.client_id,
+               oqc.code AS oqc_code, oqc.check_result AS check_result,
+               sl.batch_code, sl.item_id, sl.quantity, sl.quality_status
+        FROM mes_wm_product_sales_line sl
+        JOIN mes_wm_product_sales s ON s.id = sl.sales_id AND s.deleted = 0
+        LEFT JOIN mes_qc_oqc oqc ON oqc.id = sl.oqc_id AND oqc.deleted = 0
+        WHERE sl.batch_code = #{batchCode} AND sl.deleted = 0
+    </select>
+
+    <!-- 鎵规宸ュ簭娴佽浆锛氫骇鍑�(OUT)/鎶曞叆(IN) 浜嬩欢鑱氬悎锛屾棤闇�寤鸿〃 -->
+    <select id="selectProcessTraceList" parameterType="String"
+            resultType="cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchProcessTraceRespVO">
+        SELECT 'OUT' AS event_type, pp.work_order_id, pp.process_id,
+               ppl.batch_code, ppl.quantity, ppl.quality_status, pp.produce_date AS event_time,
+               wop.sort AS process_sort
+        FROM mes_wm_product_produce_line ppl
+        JOIN mes_wm_product_produce pp ON pp.id = ppl.produce_id AND pp.deleted = 0
+        LEFT JOIN mes_pro_work_order_process wop
+               ON wop.work_order_id = pp.work_order_id AND wop.process_id = pp.process_id AND wop.deleted = 0
+        WHERE ppl.batch_code = #{batchCode} AND ppl.deleted = 0
+        UNION ALL
+        SELECT 'IN' AS event_type, ic.work_order_id, ic.process_id,
+               icd.batch_code, icd.quantity, NULL AS quality_status, ic.consume_date AS event_time,
+               wop.sort AS process_sort
+        FROM mes_wm_item_consume_detail icd
+        JOIN mes_wm_item_consume ic ON ic.id = icd.consume_id AND ic.deleted = 0
+        LEFT JOIN mes_pro_work_order_process wop
+               ON wop.work_order_id = ic.work_order_id AND wop.process_id = ic.process_id AND wop.deleted = 0
+        WHERE icd.batch_code = #{batchCode} AND icd.deleted = 0
+    </select>
+
 </mapper>
diff --git a/yudao-server/src/main/resources/application-yzfx.yaml b/yudao-server/src/main/resources/application-yzfx.yaml
new file mode 100644
index 0000000..080012b
--- /dev/null
+++ b/yudao-server/src/main/resources/application-yzfx.yaml
@@ -0,0 +1,324 @@
+server:
+  port: 48080
+
+--- #################### 鏁版嵁搴撶浉鍏抽厤缃� ####################
+spring:
+  autoconfigure:
+    # noinspection SpringBootApplicationYaml
+    exclude:
+      - org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration # 榛樿 local 鐜锛屼笉寮�鍚� Quartz 鐨勮嚜鍔ㄩ厤缃�
+      - org.springframework.ai.vectorstore.qdrant.autoconfigure.QdrantVectorStoreAutoConfiguration # 绂佺敤 AI 妯″潡鐨� Qdrant锛屾墜鍔ㄥ垱寤�
+      - org.springframework.ai.vectorstore.redis.autoconfigure.RedisVectorStoreAutoConfiguration # 绂佺敤 AI 妯″潡鐨� Redis锛屾墜鍔ㄥ垱寤�
+      - org.springframework.ai.vectorstore.milvus.autoconfigure.MilvusVectorStoreAutoConfiguration # 绂佺敤 AI 妯″潡鐨� Milvus锛屾墜鍔ㄥ垱寤�
+      - org.dromara.trans.config.TransServiceConfig # TODO 鑺嬭壙锛歟asy-trans 鍏煎 Spring Boot 4 鍚庣Щ闄わ紙TransServiceConfig 寮曠敤浜嗗凡绉婚櫎鐨� RestTemplateBuilder锛�
+      # 绂佺敤鏈厤缃� API Key 鐨勬ā鍨嬭嚜鍔ㄩ厤缃紙鍙繚鐣欓�氫箟鍗冮棶 Embedding 鐨勬墜鍔ㄩ厤缃級
+      - org.springframework.ai.model.openai.autoconfigure.OpenAiChatAutoConfiguration
+      - org.springframework.ai.model.openai.autoconfigure.OpenAiEmbeddingAutoConfiguration
+      - org.springframework.ai.model.openai.autoconfigure.OpenAiImageAutoConfiguration
+      - org.springframework.ai.model.openai.autoconfigure.OpenAiAudioSpeechAutoConfiguration
+      - org.springframework.ai.model.openai.autoconfigure.OpenAiAudioTranscriptionAutoConfiguration
+      - org.springframework.ai.model.openai.autoconfigure.OpenAiModerationAutoConfiguration
+      - org.springframework.ai.model.deepseek.autoconfigure.DeepSeekChatAutoConfiguration
+      - org.springframework.ai.model.anthropic.autoconfigure.AnthropicChatAutoConfiguration
+      - org.springframework.ai.model.google.genai.autoconfigure.chat.GoogleGenAiChatAutoConfiguration
+      - org.springframework.ai.model.google.genai.autoconfigure.embedding.GoogleGenAiEmbeddingConnectionAutoConfiguration
+      - org.springframework.ai.model.google.genai.autoconfigure.embedding.GoogleGenAiTextEmbeddingAutoConfiguration
+      - org.springframework.ai.model.ollama.autoconfigure.OllamaApiAutoConfiguration
+      - org.springframework.ai.model.ollama.autoconfigure.OllamaChatAutoConfiguration
+      - org.springframework.ai.model.ollama.autoconfigure.OllamaEmbeddingAutoConfiguration
+      - org.springframework.ai.model.stabilityai.autoconfigure.StabilityAiImageAutoConfiguration
+  # 鏁版嵁婧愰厤缃」
+  datasource:
+    druid: # Druid 銆愮洃鎺с�戠浉鍏崇殑鍏ㄥ眬閰嶇疆
+      web-stat-filter:
+        enabled: true
+      stat-view-servlet:
+        enabled: true
+        allow: # 璁剧疆鐧藉悕鍗曪紝涓嶅~鍒欏厑璁告墍鏈夎闂�
+        url-pattern: /druid/*
+        login-username: # 鎺у埗鍙扮鐞嗙敤鎴峰悕鍜屽瘑鐮�
+        login-password:
+      filter:
+        stat:
+          enabled: true
+          log-slow-sql: true # 鎱� SQL 璁板綍
+          slow-sql-millis: 100
+          merge-sql: true
+        wall:
+          config:
+            multi-statement-allow: true
+    dynamic: # 澶氭暟鎹簮閰嶇疆
+      druid: # Druid 銆愯繛鎺ユ睜銆戠浉鍏崇殑鍏ㄥ眬閰嶇疆
+        initial-size: 1 # 鍒濆杩炴帴鏁�
+        min-idle: 1 # 鏈�灏忚繛鎺ユ睜鏁伴噺
+        max-active: 20 # 鏈�澶ц繛鎺ユ睜鏁伴噺
+        max-wait: 60000 # 閰嶇疆鑾峰彇杩炴帴绛夊緟瓒呮椂鐨勬椂闂达紝鍗曚綅锛氭绉掞紙1 鍒嗛挓锛�
+        time-between-eviction-runs-millis: 60000 # 閰嶇疆闂撮殧澶氫箙鎵嶈繘琛屼竴娆℃娴嬶紝妫�娴嬮渶瑕佸叧闂殑绌洪棽杩炴帴锛屽崟浣嶏細姣锛�1 鍒嗛挓锛�
+        min-evictable-idle-time-millis: 600000 # 閰嶇疆涓�涓繛鎺ュ湪姹犱腑鏈�灏忕敓瀛樼殑鏃堕棿锛屽崟浣嶏細姣锛�10 鍒嗛挓锛�
+        max-evictable-idle-time-millis: 1800000 # 閰嶇疆涓�涓繛鎺ュ湪姹犱腑鏈�澶х敓瀛樼殑鏃堕棿锛屽崟浣嶏細姣锛�30 鍒嗛挓锛�
+        validation-query: SELECT 1 FROM DUAL # 閰嶇疆妫�娴嬭繛鎺ユ槸鍚︽湁鏁�
+        test-while-idle: true
+        test-on-borrow: false
+        test-on-return: false
+        pool-prepared-statements: true # 鏄惁寮�鍚� PreparedStatement 缂撳瓨
+        max-pool-prepared-statement-per-connection-size: 20 # 姣忎釜杩炴帴缂撳瓨鐨� PreparedStatement 鏁伴噺
+      primary: master
+      datasource:
+        master:
+          url: jdbc:mysql://172.17.0.1:9002/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 杩炴帴鐨勭ず渚�
+          #          url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=true&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true # MySQL Connector/J 5.X 杩炴帴鐨勭ず渚�
+          #          url: jdbc:postgresql://127.0.0.1:5432/ruoyi-vue-pro # PostgreSQL 杩炴帴鐨勭ず渚�
+          #          url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 杩炴帴鐨勭ず渚�
+          #          url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=ruoyi-vue-pro;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true;useUnicode=true;characterEncoding=utf-8 # SQLServer 杩炴帴鐨勭ず渚�
+          #          url: jdbc:dm://127.0.0.1:5236?schema=RUOYI_VUE_PRO # DM 杩炴帴鐨勭ず渚�
+          #          url: jdbc:kingbase8://127.0.0.1:54321/test  # 浜哄ぇ閲戜粨 KingbaseES 杩炴帴鐨勭ず渚�
+          #          url: jdbc:postgresql://127.0.0.1:5432/postgres # OpenGauss 杩炴帴鐨勭ず渚�
+          #          url: jdbc:postgresql://127.0.0.1:5866/ruoyi-vue-pro # 鐎氶珮 HighGo 杩炴帴鐨勭ず渚�
+          username: root
+          password: yzfx@123456..
+          #          username: sa # SQL Server 杩炴帴鐨勭ず渚�
+          #          password: Yudao@2024 # SQL Server 杩炴帴鐨勭ず渚�
+          #          username: SYSDBA # DM 杩炴帴鐨勭ず渚�
+          #          password: SYSDBA001 # DM 杩炴帴鐨勭ず渚�
+          #          username: root # OpenGauss 杩炴帴鐨勭ず渚�
+          #          password: Yudao@2024 # OpenGauss 杩炴帴鐨勭ず渚�
+          #          username: root # 鐎氶珮 HighGo 杩炴帴鐨勭ず渚�
+          #          password: 123456 # 鐎氶珮 HighGo 杩炴帴鐨勭ず渚�
+        slave: # 妯℃嫙浠庡簱锛屽彲鏍规嵁鑷繁闇�瑕佷慨鏀�
+          lazy: true # 寮�鍚噿鍔犺浇锛屼繚璇佸惎鍔ㄩ�熷害
+          url: jdbc:mysql://172.17.0.1:9002/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true&nullCatalogMeansCurrent=true
+          username: root
+          password: yzfx@123456
+#        tdengine: # IoT 鏁版嵁搴擄紙闇�瑕� IoT 鐗╄仈缃戝啀寮�鍚櫌锛侊級
+#          lazy: true # 寮�鍚噿鍔犺浇锛屼繚璇佸惎鍔ㄩ�熷害
+#          url: jdbc:TAOS-WS://127.0.0.1:6041/ruoyi_vue_pro?varcharAsString=true&enableAutoReconnect=true # 鍙傝锛歨ttps://t.zsxq.com/qaX9c锛屽紑鍚� TDengine WebSocket 鑷姩閲嶈繛
+#          driver-class-name: com.taosdata.jdbc.ws.WebSocketDriver
+#          username: root
+#          password: taosdata
+#          druid:
+#            validation-query: SELECT SERVER_STATUS() # TDengine 鏁版嵁婧愮殑鏈夋晥鎬ф鏌� SQL
+
+  # Redis 閰嶇疆銆俁edisson 榛樿鐨勯厤缃冻澶熶娇鐢紝涓�鑸笉闇�瑕佽繘琛岃皟浼�
+  data:
+    redis:
+      host: 172.17.0.1 # 鍦板潃
+      port: 6379 # 绔彛
+      database: 1 # 鏁版嵁搴撶储寮�
+#      password: dev # 瀵嗙爜锛屽缓璁敓浜х幆澧冨紑鍚�
+
+--- #################### 瀹氭椂浠诲姟鐩稿叧閰嶇疆 ####################
+
+# Quartz 閰嶇疆椤癸紝瀵瑰簲 QuartzProperties 閰嶇疆绫�
+spring:
+  quartz:
+    auto-startup: true # 鏈湴寮�鍙戠幆澧冿紝灏介噺涓嶈寮�鍚� Job
+    scheduler-name: schedulerName # Scheduler 鍚嶅瓧銆傞粯璁や负 schedulerName
+    job-store-type: jdbc # Job 瀛樺偍鍣ㄧ被鍨嬨�傞粯璁や负 memory 琛ㄧず鍐呭瓨锛屽彲閫� jdbc 浣跨敤鏁版嵁搴撱��
+    wait-for-jobs-to-complete-on-shutdown: true # 搴旂敤鍏抽棴鏃讹紝鏄惁绛夊緟瀹氭椂浠诲姟鎵ц瀹屾垚銆傞粯璁や负 false 锛屽缓璁缃负 true
+    properties: # 娣诲姞 Quartz Scheduler 闄勫姞灞炴�э紝鏇村鍙互鐪� http://www.quartz-scheduler.org/documentation/2.4.0-SNAPSHOT/configuration.html 鏂囨。
+      org:
+        quartz:
+          # Scheduler 鐩稿叧閰嶇疆
+          scheduler:
+            instanceName: schedulerName
+            instanceId: AUTO # 鑷姩鐢熸垚 instance ID
+          # JobStore 鐩稿叧閰嶇疆
+          jobStore:
+            # JobStore 瀹炵幇绫汇�傚彲瑙佸崥瀹細https://blog.csdn.net/weixin_42458219/article/details/122247162
+            class: org.springframework.scheduling.quartz.LocalDataSourceJobStore
+            isClustered: true # 鏄泦缇ゆā寮�
+            clusterCheckinInterval: 15000 # 闆嗙兢妫�鏌ラ鐜囷紝鍗曚綅锛氭绉掋�傞粯璁や负 15000锛屽嵆 15 绉�
+            misfireThreshold: 60000 # misfire 闃�鍊硷紝鍗曚綅锛氭绉掋��
+          # 绾跨▼姹犵浉鍏抽厤缃�
+          threadPool:
+            threadCount: 25 # 绾跨▼姹犲ぇ灏忋�傞粯璁や负 10 銆�
+            threadPriority: 5 # 绾跨▼浼樺厛绾�
+            class: org.quartz.simpl.SimpleThreadPool # 绾跨▼姹犵被鍨�
+    jdbc: # 浣跨敤 JDBC 鐨� JobStore 鐨勬椂鍊欙紝JDBC 鐨勯厤缃�
+      initialize-schema: NEVER # 鏄惁鑷姩浣跨敤 SQL 鍒濆鍖� Quartz 琛ㄧ粨鏋勩�傝繖閲岃缃垚 never 锛屾垜浠墜鍔ㄥ垱寤鸿〃缁撴瀯銆�
+
+--- #################### 娑堟伅闃熷垪鐩稿叧 ####################
+
+# rocketmq 閰嶇疆椤癸紝瀵瑰簲 RocketMQProperties 閰嶇疆绫�
+rocketmq:
+  name-server: 127.0.0.1:9876 # RocketMQ Namesrv
+
+spring:
+  # RabbitMQ 閰嶇疆椤癸紝瀵瑰簲 RabbitProperties 閰嶇疆绫�
+  rabbitmq:
+    host: 127.0.0.1 # RabbitMQ 鏈嶅姟鐨勫湴鍧�
+    port: 5672 # RabbitMQ 鏈嶅姟鐨勭鍙�
+    username: rabbit # RabbitMQ 鏈嶅姟鐨勮处鍙�
+    password: rabbit # RabbitMQ 鏈嶅姟鐨勫瘑鐮�
+  # Kafka 閰嶇疆椤癸紝瀵瑰簲 KafkaProperties 閰嶇疆绫�
+  kafka:
+    bootstrap-servers: 127.0.0.1:9092 # 鎸囧畾 Kafka Broker 鍦板潃锛屽彲浠ヨ缃涓紝浠ラ�楀彿鍒嗛殧
+
+--- #################### 鏈嶅姟淇濋殰鐩稿叧閰嶇疆 ####################
+
+# Lock4j 閰嶇疆椤�
+lock4j:
+  acquire-timeout: 3000 # 鑾峰彇鍒嗗竷寮忛攣瓒呮椂鏃堕棿锛岄粯璁や负 3000 姣
+  expire: 30000 # 鍒嗗竷寮忛攣鐨勮秴鏃舵椂闂达紝榛樿涓� 30000 姣
+
+--- #################### 鐩戞帶鐩稿叧閰嶇疆 ####################
+
+# Actuator 鐩戞帶绔偣鐨勯厤缃」
+management:
+  endpoints:
+    web:
+      base-path: /actuator # Actuator 鎻愪緵鐨� API 鎺ュ彛鐨勬牴鐩綍銆傞粯璁や负 /actuator
+      exposure:
+        include: '*' # 闇�瑕佸紑鏀剧殑绔偣銆傞粯璁ゅ�煎彧鎵撳紑 health 鍜� info 涓や釜绔偣銆傞�氳繃璁剧疆 * 锛屽彲浠ュ紑鏀炬墍鏈夌鐐广��
+
+# Spring Boot Admin 閰嶇疆椤�
+spring:
+  boot:
+    admin:
+      # Spring Boot Admin Client 瀹㈡埛绔殑鐩稿叧閰嶇疆
+      client:
+        url: http://127.0.0.1:${server.port}/${spring.boot.admin.context-path} # 璁剧疆 Spring Boot Admin Server 鍦板潃
+        instance:
+          service-host-type: IP # 娉ㄥ唽瀹炰緥鏃讹紝浼樺厛浣跨敤 IP [IP, HOST_NAME, CANONICAL_HOST_NAME]
+        username: admin
+        password: admin
+      # Spring Boot Admin Server 鏈嶅姟绔殑鐩稿叧閰嶇疆
+      context-path: /admin # 閰嶇疆 Spring
+      # 鍏佽宓屽叆 iframe 鐨勫煙鍚嶏紙鏀寔閫氶厤绗︼級锛屽疄闄呴儴缃叉椂锛屽彲浠ユ敼涓� "'self' [浣犵殑鍏綉鍩熷悕]"
+      frame-ancestors: "'self' localhost localhost:48080 127.0.0.1 127.0.0.1:48080"
+
+# 鏃ュ織鏂囦欢閰嶇疆
+logging:
+  file:
+    name: logs/${spring.application.name}.log # 鏃ュ織鏂囦欢鍚嶏紝鐩稿浜庨」鐩牴鐩綍
+  level:
+    # 閰嶇疆鑷繁鍐欑殑 MyBatis Mapper 鎵撳嵃鏃ュ織
+    cn.iocoder.yudao.module.bpm.dal.mysql: debug
+    cn.iocoder.yudao.module.infra.dal.mysql: debug
+    cn.iocoder.yudao.module.infra.dal.mysql.logger.ApiErrorLogMapper: INFO # 閰嶇疆 ApiErrorLogMapper 鐨勬棩蹇楃骇鍒负 info锛岄伩鍏嶅拰 GlobalExceptionHandler 閲嶅鎵撳嵃
+    cn.iocoder.yudao.module.infra.dal.mysql.job.JobLogMapper: INFO # 閰嶇疆 JobLogMapper 鐨勬棩蹇楃骇鍒负 info
+    cn.iocoder.yudao.module.infra.dal.mysql.file.FileConfigMapper: INFO # 閰嶇疆 FileConfigMapper 鐨勬棩蹇楃骇鍒负 info
+    cn.iocoder.yudao.module.pay.dal.mysql: debug
+    cn.iocoder.yudao.module.pay.dal.mysql.notify.PayNotifyTaskMapper: INFO # 閰嶇疆 PayNotifyTaskMapper 鐨勬棩蹇楃骇鍒负 info
+    cn.iocoder.yudao.module.system.dal.mysql: debug
+    cn.iocoder.yudao.module.system.dal.mysql.sms.SmsChannelMapper: INFO # 閰嶇疆 SmsChannelMapper 鐨勬棩蹇楃骇鍒负 info
+    cn.iocoder.yudao.module.tool.dal.mysql: debug
+    cn.iocoder.yudao.module.member.dal.mysql: debug
+    cn.iocoder.yudao.module.trade.dal.mysql: debug
+    cn.iocoder.yudao.module.promotion.dal.mysql: debug
+    cn.iocoder.yudao.module.statistics.dal.mysql: debug
+    cn.iocoder.yudao.module.crm.dal.mysql: debug
+    cn.iocoder.yudao.module.erp.dal.mysql: debug
+    cn.iocoder.yudao.module.mes.dal.mysql: debug
+    cn.iocoder.yudao.module.wms.dal.mysql: debug
+    cn.iocoder.yudao.module.iot.dal.mysql: debug
+    cn.iocoder.yudao.module.iot.dal.tdengine: DEBUG
+    cn.iocoder.yudao.module.iot.service.rule: debug
+    cn.iocoder.yudao.module.ai.dal.mysql: debug
+    cn.iocoder.yudao.module.im.dal.mysql: debug
+    org.springframework.context.support.PostProcessorRegistrationDelegate: ERROR # TODO 鑺嬭壙锛氬厛绂佺敤锛孲pring Boot 3.X 瀛樺湪閮ㄥ垎閿欒鐨� WARN 鎻愮ず
+
+debug: false
+
+yudao:
+  ai:
+    vector-store:
+      type: milvus # 鍚戦噺搴撶被鍨嬶細milvus
+      milvus:
+        initialize-schema: true
+        database-name: test
+        collection-name: knowledge_segment_yzfx
+        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 鏂囨。
+#    app-id: wx041349c6f39b268b # 娴嬭瘯鍙凤紙鐗涘笇灏ф彁渚涚殑锛�
+#    secret: 5abee519483bc9f8cb37ce280e814bd0
+#    app-id: wx5b23ba7a5589ecbb # 娴嬭瘯鍙凤紙鑷繁鐨勶級
+#    secret: 2a7b3b20c537e52e74afd395eb85f61f
+    app-id: wxf56b1542b9e85f8a # 娴嬭瘯鍙凤紙Kongdy 鎻愪緵鐨勶級
+    secret: 496379dcef1ba869e9234de8d598cfd3
+    # 瀛樺偍閰嶇疆锛岃В鍐� AccessToken 鐨勮法鑺傜偣鐨勫叡浜�
+    config-storage:
+      type: RedisTemplate # 閲囩敤 RedisTemplate 鎿嶄綔 Redis锛屼細鑷姩浠� Spring 涓幏鍙�
+      key-prefix: wx # Redis Key 鐨勫墠缂�
+      http-client-type: HttpComponents # 閲囩敤 HttpComponents锛圚ttpClient 5锛夎姹傚井淇″叕浼楀彿骞冲彴
+  miniapp: # 灏忕▼搴忛厤缃紙蹇呭~锛夛紝鍙傝 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-miniapp-spring-boot-starter/README.md 鏂囨。
+    #    appid: wx62056c0d5e8db250 # 娴嬭瘯鍙凤紙鐗涘笇灏ф彁渚涚殑锛�
+    #    secret: 333ae72f41552af1e998fe1f54e1584a
+#    appid: wx63c280fe3248a3e7 # wenhualian鐨勬帴鍙f祴璇曞彿
+#    secret: 6f270509224a7ae1296bbf1c8cb97aed
+    appid: wxc4598c446f8a9cb3 # 娴嬭瘯鍙凤紙Kongdy 鎻愪緵鐨勶級
+    secret: 4a1a04e07f6a4a0751b39c3064a92c8b
+#    appid: wx66186af0759f47c9 # 娴嬭瘯鍙凤紙puhui 鎻愪緵鐨勶級
+#    secret: 3218bcbd112cbc614c7264ceb20144ac
+    config-storage:
+      type: RedisTemplate # 閲囩敤 RedisTemplate 鎿嶄綔 Redis锛屼細鑷姩浠� Spring 涓幏鍙�
+      key-prefix: wa # Redis Key 鐨勫墠缂�
+      http-client-type: HttpComponents # 閲囩敤 HttpComponents锛圚ttpClient 5锛夎姹傚井淇″皬绋嬪簭骞冲彴
+
+--- #################### 瓒呯骇绠$悊鍛樼浉鍏抽厤缃� ####################
+
+# 瓒呯骇绠$悊鍛橀厤缃」锛岃缃綋鍓嶉」鐩墍鏈夎嚜瀹氫箟鐨勯厤缃�
+yudao:
+  captcha:
+    enable: false # 鏈湴鐜锛屾殏鏃跺叧闂浘鐗囬獙璇佺爜锛屾柟渚跨櫥褰曠瓑鎺ュ彛鐨勬祴璇曪紱
+  security:
+    mock-enable: true
+  pay:
+    order-notify-url: https://yutou.mynatapp.cc/admin-api/pay/notify/order # 鏀粯娓犻亾鐨勩�愭敮浠樸�戝洖璋冨湴鍧�
+    refund-notify-url: https://yutou.mynatapp.cc/admin-api/pay/notify/refund # 鏀粯娓犻亾鐨勩�愰��娆俱�戝洖璋冨湴鍧�
+    transfer-notify-url: https://yutou.mynatapp.cc/admin-api/pay/notify/transfer # 鏀粯娓犻亾鐨勩�愯浆璐︺�戝洖璋冨湴鍧�
+  access-log: # 璁块棶鏃ュ織鐨勯厤缃」
+    enable: false
+  demo: false # 鍏抽棴婕旂ず妯″紡
+  wxa-code:
+    env-version: develop # 灏忕▼搴忕増鏈�: 姝e紡鐗堜负 "release"锛涗綋楠岀増涓� "trial"锛涘紑鍙戠増涓� "develop"
+  wxa-subscribe-message:
+    miniprogram-state: developer # 璺宠浆灏忕▼搴忕被鍨嬶細寮�鍙戠増涓� 鈥渄eveloper鈥濓紱浣撻獙鐗堜负 鈥渢rial鈥濅负锛涙寮忕増涓� 鈥渇ormal鈥�
+  tencent-lbs-key: TVDBZ-TDILD-4ON4B-PFDZA-RNLKH-VVF6E # QQ 鍦板浘鐨勫瘑閽� https://lbs.qq.com/service/staticV2/staticGuide/staticDoc
+  storage: # 鏂囦欢涓婁紶閰嶇疆
+    path: /data/javaWork/mom/file # 鏂囦欢瀛樺偍鏍圭洰褰�
+    url-prefix: /admin-api/system/storage-blob # URL璺緞鍓嶇紑
+    domain: http://42.63.70.231:9001 # 鍩熷悕鍓嶇紑锛堟寜瀹為檯鍩熷悕閰嶇疆锛夛紝鍓嶇閰嶇疆濂藉儚涓嶅お瀵圭幇鍦ㄦ槸鐩磋繛鍚庣锛屾墍鏈夎鍚庣绔彛
+    expired: 120 # token杩囨湡鏃堕棿锛堝垎閽燂級
+    use-limit: 10 # token浣跨敤娆℃暟涓婇檺
+    jwt-secret: abcdefghijklmnopqrstuvwxyz0123456789ABCDEFG # JWT瀵嗛挜
+    compress: true # 鏄惁鍘嬬缉鍥剧墖
+    need-compress-size: 10MB # 瑙﹀彂鍘嬬缉鐨勬枃浠跺ぇ灏忛槇鍊�
+    compress-quality: 0.5 # 鍘嬬缉璐ㄩ噺(0.0-1.0)
+
+justauth:
+  enabled: true
+  type:
+    DINGTALK: # 閽夐拤
+      client-id: dingvrnreaje3yqvzhxg
+      client-secret: i8E6iZyDvZj51JIb0tYsYfVQYOks9Cq1lgryEjFRqC79P3iJcrxEwT6Qk2QvLrLI
+      ignore-check-redirect-uri: true
+    WECHAT_ENTERPRISE: # 浼佷笟寰俊
+      client-id: wwd411c69a39ad2e54
+      client-secret: 1wTb7hYxnpT2TUbIeHGXGo7T0odav1ic10mLdyyATOw
+      agent-id: 1000004
+      ignore-check-redirect-uri: true
+    # noinspection SpringBootApplicationYaml
+    WECHAT_MINI_PROGRAM: # 寰俊灏忕▼搴�
+      client-id: ${wx.miniapp.appid}
+      client-secret: ${wx.miniapp.secret}
+      ignore-check-redirect-uri: true
+      ignore-check-state: true # 寰俊灏忕▼搴忥紝涓嶄細浣跨敤鍒� state锛屾墍浠ヤ笉杩涜鏍¢獙
+    WECHAT_MP: # 寰俊鍏紬鍙�
+      client-id: ${wx.mp.app-id}
+      client-secret: ${wx.mp.secret}
+      ignore-check-redirect-uri: true
+    ALIPAY: # 鏀粯瀹濆皬绋嬪簭
+      client-id: xx
+      client-secret: xx
+      alipay-public-key: xx
+      ignore-check-redirect-uri: true
+      ignore-check-state: true
+  cache:
+    type: REDIS
+    prefix: 'social_auth_state:' # 缂撳瓨鍓嶇紑锛岀洰鍓嶅彧瀵� Redis 缂撳瓨鐢熸晥锛岄粯璁� JUSTAUTH::STATE::
+    timeout: 24h # 瓒呮椂鏃堕暱锛岀洰鍓嶅彧瀵� Redis 缂撳瓨鐢熸晥锛岄粯璁� 3 鍒嗛挓

--
Gitblit v1.9.3