From cdf5605fb5caa0da0f134893bac350785250ea8a Mon Sep 17 00:00:00 2001
From: liu <2021943741@qq.com>
Date: 星期四, 27 八月 2026 11:21:19 +0800
Subject: [PATCH] feat(mes): 基础参数与工序绑定,报工填写绑定的参数字段

---
 docs/process_param_bind_feedback_integration.md                                                                                   |  194 +++++++++++
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/task/MesProTaskServiceImpl.java                            |   32 +
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/feedback/MesProFeedbackController.java            |   47 ++
 docs/sql/mes_process_param_bind_full.sql                                                                                          |  145 ++++++++
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/process/MesProProcessParamController.java         |  111 ++++++
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/process/MesProProcessParamService.java                     |   55 +++
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderParamRecordService.java           |   10 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/feedback/vo/MesProFeedbackRespVO.java             |   31 +
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/process/vo/param/MesProProcessParamRespVO.java    |   57 +++
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderParamRecordServiceImpl.java       |   85 ++++
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pd/processparam/MesPdProcessParamServiceImpl.java              |    6 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/process/MesProProcessParamServiceImpl.java                 |   86 +++++
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackServiceImpl.java                    |    6 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/process/vo/param/MesProProcessParamSaveReqVO.java |   37 ++
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/workorder/MesProWorkOrderParamRecordMapper.java          |    7 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/process/MesProProcessParamDO.java                   |   56 +++
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/process/MesProProcessParamMapper.java                    |   49 ++
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkOrderParamRecordDetailDO.java   |    4 
 18 files changed, 1,004 insertions(+), 14 deletions(-)

diff --git a/docs/process_param_bind_feedback_integration.md b/docs/process_param_bind_feedback_integration.md
new file mode 100644
index 0000000..c797576
--- /dev/null
+++ b/docs/process_param_bind_feedback_integration.md
@@ -0,0 +1,194 @@
+# 鍩虹鍙傛暟涓庡伐搴忕粦瀹� + 鎶ュ伐濉啓鍙傛暟瀛楁 - 鍓嶇鑱旇皟鏂规
+
+## 闇�姹傝儗鏅�
+
+- 鍩虹鍙傛暟锛堝伐鑹哄弬鏁帮紝鑿滃崟銆屽伐鑹鸿璁� 鈫� 鍩虹鍙傛暟銆嶏級鍘熸湰鏃犳硶涓庛�屽伐搴忋�嶇洿鎺ョ粦瀹氥��
+- 鏈瀹炵幇锛�**宸ュ簭涓绘暟鎹彲缁戝畾鍩虹鍙傛暟**锛涗换鍔℃棤鍙傛暟妯℃澘鏃讹紝鐢熸垚浠诲姟浼氭寜宸ュ簭缁戝畾鐨勫弬鏁拌嚜鍔ㄥ浐鍖栧弬鏁板揩鐓э紱**鎶ュ伐鏃跺繀椤诲~鍐欑粦瀹氱殑鍙傛暟瀛楁**锛堝繀濉弬鏁板己鏍¢獙锛夛紝鎶ュ伐璇︽儏/鍒楄〃鍥炴樉鍙傛暟鍊笺��
+
+## 娑夊強椤甸潰
+
+1. 宸ュ簭璁剧疆椤碉紙`mes/process-design/process/index`锛夆�斺�旀柊澧炪�屽伐鑹哄弬鏁般�峊ab锛岀淮鎶ゅ伐搴忕粦瀹氱殑鍙傛暟
+2. 鍩虹鍙傛暟椤碉紙`mes/process-design/parameter/index`锛夆�斺�旀柊澧炪�屽叧鑱斿伐搴忋�嶅叆鍙o紝鏌ョ湅璇ュ弬鏁拌鍝簺宸ュ簭浣跨敤
+3. 鐢熶骇浠诲姟鍒涘缓/鑷姩鎺掍骇鈥斺�斾换鍔℃寜宸ュ簭缁戝畾鍙傛暟鐢熸垚鍙傛暟蹇収锛堟棤妯℃澘鏃讹級
+4. 鐢熶骇鎶ュ伐鏂板/缂栬緫鈥斺�旀寜浠诲姟鍙傛暟璁板綍娓叉煋鍙傛暟瀛楁锛屽繀濉弬鏁版牎楠�
+5. 鎶ュ伐璇︽儏/鍒楄〃鈥斺�斿洖鏄惧凡濉啓鐨勫弬鏁板��
+
+## 涓氬姟娴佺▼涓庢暟鎹甫鍏�
+
+```
+1. 宸ュ簭璁剧疆椤� 鈫� 銆屽伐鑹哄弬鏁般�峊ab 鈫� 鍕鹃�夊熀纭�鍙傛暟锛岃缃槸鍚﹀繀濉�/鎺掑簭 鈫� 淇濆瓨鍒� mes_pro_process_param
+2. 鎺掍骇/鎵嬪伐寤轰换鍔� 鈫� 浠诲姟鐨勫伐搴忚嫢鏈粦瀹氬弬鏁版ā鏉匡紝鍒欎粠銆屽伐搴忕粦瀹氱殑鍙傛暟銆嶇敓鎴愪换鍔″弬鏁拌褰曞揩鐓�
+   锛堝弬鏁版潵婧愪紭鍏堢骇锛氬伐鍗曞伐搴忕粦瀹氭ā鏉� 鈫� 璺嚎宸ュ簭缁戝畾妯℃澘 鈫� 宸ュ簭涓绘暟鎹粦瀹氬弬鏁� 鈫� 鏃犲弬鏁拌褰曪級
+3. 鐢熶骇鎶ュ伐 鈫� 鎸変换鍔″弬鏁拌褰曟覆鏌撳弬鏁板瓧娈碉紙鍙傛暟鍚� + 鍗曚綅 + 蹇呭~鏄熷彿锛�
+4. 鎻愪氦鎶ュ伐 鈫� 蹇呭~鍙傛暟涓虹┖鍒欏悗绔嫆缁濓紙鎶ラ敊銆屽繀濉弬鏁般�恱xx銆戞湭濉啓銆嶏級
+5. 鎶ュ伐璇︽儏/鍒楄〃 鈫� 鍥炴樉鏈浠诲姟鍙傛暟蹇収鍙婂凡濉啓鐨勫弬鏁板��
+```
+
+## API
+
+### 涓�銆佸伐搴�-宸ヨ壓鍙傛暟缁戝畾锛堟柊澧烇級
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| GET | `/admin-api/mes/pro/process-param/list-by-process` | 鏌ヨ宸ュ簭缁戝畾鐨勫弬鏁板垪琛紙甯﹀弬鏁拌鎯�/鍗曚綅锛� |
+| POST | `/admin-api/mes/pro/process-param/update-bindings` | 鍏ㄩ噺瑕嗙洊淇濆瓨宸ュ簭缁戝畾鐨勫弬鏁� |
+| GET | `/admin-api/mes/pro/process-param/list-by-param` | 鍙嶆煡鏌愬熀纭�鍙傛暟琚摢浜涘伐搴忕粦瀹� |
+
+鏉冮檺锛氳 `mes:pro-process:query`锛涘啓 `mes:pro-process:update`锛堝鐢ㄥ伐搴忔潈闄愶紝鏃犻渶鏂拌彍鍗曪級銆�
+
+**GET /list-by-process 璇锋眰鍙傛暟锛�**
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| processId | Long | 鏄� | 宸ュ簭缂栧彿 |
+
+**鍝嶅簲锛�**
+
+```json
+{
+  "code": 0,
+  "data": [
+    {
+      "id": 9,
+      "processId": 10,
+      "processParamId": 7,
+      "paramCode": "CS202607150004",
+      "paramName": "娴嬭瘯鍙傛暟_鏁板��",
+      "paramType": 1,
+      "unitMeasureId": 1,
+      "unitMeasureName": "鍚�",
+      "required": true,
+      "sort": 1,
+      "remark": null
+    }
+  ]
+}
+```
+
+**POST /update-bindings 璇锋眰鍙傛暟锛堝叏閲忚鐩栵級锛�**
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| processId | Long | 鏄� | 宸ュ簭缂栧彿 |
+| items | Array | 鍚� | 缁戝畾鐨勫弬鏁板垪琛紙浼犵┖鏁扮粍=娓呯┖缁戝畾锛� |
+| items[].processParamId | Long | 鏄� | 鍩虹鍙傛暟缂栧彿 |
+| items[].required | Boolean | 鍚� | 鏄惁蹇呭~锛堝彲瑕嗙洊鍙傛暟榛樿鍊硷級 |
+| items[].sort | Integer | 鍚� | 鎺掑簭 |
+| items[].remark | String | 鍚� | 澶囨敞 |
+
+**GET /list-by-param 璇锋眰鍙傛暟锛�**
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| paramId | Long | 鏄� | 鍩虹鍙傛暟缂栧彿 |
+
+**鍝嶅簲锛�** `data` 涓哄伐搴忓垪琛紙`id`銆乣code`銆乣name`锛夈��
+
+### 浜屻�佷换鍔″弬鏁拌褰曪紙宸叉湁鎺ュ彛锛岃涓哄寮猴級
+
+浠诲姟鍒涘缓/鑷姩鎺掍骇鏃讹紝鑻ヤ换鍔℃棤鍙傛暟妯℃澘浣嗗伐搴忕粦瀹氫簡鍙傛暟锛屼細鐢熸垚涓�鏉� `templateName=宸ュ簭缁戝畾鍙傛暟`銆乣templateId=null` 鐨勫弬鏁拌褰曘��
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| GET | `/admin-api/mes/pro/work-order-param-record/page-by-work-order?taskId=` | 鎸変换鍔℃煡璇㈠弬鏁拌褰曪紙鍚槑缁嗗揩鐓э級 |
+
+鏄庣粏蹇収鏂板瀛楁锛歚required`锛堟槸鍚﹀繀濉級銆�
+
+### 涓夈�佺敓浜ф姤宸ワ紙宸叉湁鎺ュ彛锛屽寮猴級
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| POST | `/admin-api/mes/pro/feedback/create` | 鍒涘缓鎶ュ伐锛堟彁浜� `paramValues`锛� |
+| PUT | `/admin-api/mes/pro/feedback/update` | 淇敼鎶ュ伐 |
+| GET | `/admin-api/mes/pro/feedback/get` | 鎶ュ伐璇︽儏锛堝搷搴旀柊澧� `paramValues`锛� |
+| GET | `/admin-api/mes/pro/feedback/page` | 鎶ュ伐鍒嗛〉锛堝搷搴旀柊澧� `paramValues`锛� |
+
+**璇锋眰鍙傛暟鏂板锛堝凡瀛樺湪锛夛細**
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| paramValues | Array | 鍚� | 鏈鎶ュ伐濉啓鐨勫弬鏁板�硷紱浠诲姟鏃犲弬鏁拌褰曟椂涓嶄紶 |
+| paramValues[].detailId | Long | 鏄紙浼犲叆鏃讹級 | **浠诲姟鍙傛暟璁板綍鏄庣粏缂栧彿**锛堜笉鏄ā鏉挎槑缁嗙紪鍙凤級 |
+| paramValues[].value | String | 鏉′欢蹇呭~ | 鍙傛暟鍊硷紙蹇呭~鍙傛暟涓嶈兘涓虹┖锛� |
+
+**鍝嶅簲瀛楁鏂板锛堟姤宸ヨ鎯�/鍒楄〃锛夛細**
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+|------|------|------|
+| paramValues | Array | 浠诲姟鍙傛暟蹇収鍙婂凡濉啓鐨勫�� |
+| paramValues[].detailId | Long | 浠诲姟鍙傛暟璁板綍鏄庣粏缂栧彿 |
+| paramValues[].paramCode | String | 鍙傛暟缂栫爜 |
+| paramValues[].paramName | String | 鍙傛暟鍚嶇О |
+| paramValues[].paramType | Integer | 鍙傛暟绫诲瀷 |
+| paramValues[].unitMeasureName | String | 鍗曚綅鍚嶇О |
+| paramValues[].paramValue | String | 鍙傛暟鍊� |
+| paramValues[].required | Boolean | 鏄惁蹇呭~ |
+
+**鍝嶅簲绀轰緥锛堟姤宸ヨ鎯咃級锛�**
+
+```json
+{
+  "code": 0,
+  "data": {
+    "id": 48,
+    "code": "FB_TEST_39",
+    "processId": 10,
+    "paramValues": [
+      { "detailId": 55, "paramCode": "CS202607150004", "paramName": "娴嬭瘯鍙傛暟_鏁板��", "paramType": 1, "unitMeasureName": "鍚�", "paramValue": "200", "required": true },
+      { "detailId": 56, "paramCode": "CS202607100003", "paramName": "娴嬭瘯鍙傛暟11", "paramType": 2, "unitMeasureName": "鍗冨厠", "paramValue": "200", "required": false }
+    ]
+  }
+}
+```
+
+## 瀛楁灞曠ず瑙勫垯
+
+### 宸ュ簭璁剧疆椤点�屽伐鑹哄弬鏁般�峊ab
+
+| 瀛楁 | 灞曠ず浣嶇疆 | 璇存槑 |
+|------|----------|------|
+| 鍙傛暟缂栫爜/鍚嶇О | Tab 琛ㄦ牸 | 灞曠ず宸茬粦瀹氬弬鏁� |
+| 鍙傛暟绫诲瀷 | Tab 琛ㄦ牸 | 瀛楀吀锛�1=鏂囨湰 2=鏁板�� 3=甯冨皵 4=鏃ユ湡 |
+| 鍗曚綅 | Tab 琛ㄦ牸 | 璁¢噺鍗曚綅鍚嶇О |
+| 鏄惁蹇呭~ | Tab 琛ㄦ牸锛堝紑鍏筹級 | 鍙鐩栧弬鏁伴粯璁ゅ�� |
+| 鎺掑簭 | Tab 琛ㄦ牸 | 鏁板瓧鎺掑簭 |
+| 澶囨敞 | Tab 琛ㄦ牸 | 澶囨敞 |
+| 鎿嶄綔 | Tab 琛ㄦ牸 | 鏂板琛岋紙閫夋嫨鍩虹鍙傛暟锛夈�佸垹闄よ |
+| 淇濆瓨 | Tab 搴曢儴 | 鍏ㄩ噺瑕嗙洊淇濆瓨锛堣皟鐢� update-bindings锛� |
+
+### 鍩虹鍙傛暟椤点�屽叧鑱斿伐搴忋��
+
+| 瀛楁 | 灞曠ず浣嶇疆 | 璇存槑 |
+|------|----------|------|
+| 宸ュ簭缂栫爜/鍚嶇О | 寮圭獥/鎶藉眽 | 璇ュ弬鏁拌缁戝畾鐨勫伐搴忓垪琛紙鍙锛� |
+
+### 鐢熶骇鎶ュ伐琛ㄥ崟
+
+| 瀛楁 | 灞曠ず浣嶇疆 | 璇存槑 |
+|------|----------|------|
+| 鍙傛暟鍚嶇О | 琛ㄥ崟琛屾爣绛� | 浠庝换鍔″弬鏁拌褰曞揩鐓ц鍙� |
+| 鍗曚綅 | 杈撳叆妗嗗悗缂� | 濡� 鈩� |
+| 蹇呭~ | 绾㈣壊鏄熷彿 | required=true 鏃舵爣璁� |
+| 鍙傛暟鍊� | 杈撳叆妗� | 鎸夊弬鏁扮被鍨嬫覆鏌撹緭鍏ユ帶浠� |
+| 蹇呭~鏍¢獙 | 鎻愪氦鏃� | 蹇呭~鍙傛暟涓虹┖锛屽悗绔繑鍥炪�屽繀濉弬鏁般�恱xx銆戞湭濉啓銆� |
+
+## 涓氬姟瑙勫垯璇存槑
+
+| 鍦烘櫙 | 瑙勫垯 |
+|------|------|
+| 鍙傛暟鏉ユ簮浼樺厛绾� | 宸ュ崟宸ュ簭缁戝畾妯℃澘 鈫� 璺嚎宸ュ簭缁戝畾妯℃澘 鈫� 宸ュ簭涓绘暟鎹粦瀹氬弬鏁� 鈫� 鏃犲弬鏁拌褰� |
+| 鏃犲弬鏁拌褰� | 浠诲姟姝e父鐢熸垚銆佹姤宸ヤ笉瑕佹眰鍙傛暟鍊� |
+| 鏈夊弬鏁拌褰� | 鎶ュ伐鎸変换鍔″弬鏁版槑缁嗗~鍐欙紱蹇呭~鍙傛暟锛坮equired=true锛夊繀椤诲~鍐� |
+| 蹇収鏈哄埗 | 浠诲姟鐢熸垚鏃跺浐鍖栧弬鏁板揩鐓э紙鍚嶇О/绫诲瀷/鍗曚綅/蹇呭~锛夛紝鍚庣画鏀瑰伐搴忕粦瀹氫笉褰卞搷鍘嗗彶浠诲姟 |
+| 鍏ㄩ噺瑕嗙洊 | 宸ュ簭缁戝畾淇濆瓨涓哄叏閲忚鐩栵紱浼犵┖鏁扮粍=娓呯┖缁戝畾 |
+| 鍒犻櫎鍩虹鍙傛暟 | 鑷姩娓呯悊鍏跺伐搴忕粦瀹氬叧绯� |
+| 鎶ュ伐鍥炴樉 | 鎶ュ伐璇︽儏/鍒楄〃鍥炴樉浠诲姟鍙傛暟蹇収鍙婂凡濉�硷紝鍘嗗彶鍊间笉鍥犲悗缁彉鏇存敼鍙� |
+
+## 娉ㄦ剰浜嬮」
+
+- `paramValues[].detailId` 鏄�**浠诲姟鍙傛暟璁板綍鏄庣粏缂栧彿**锛屼笉鏄ā鏉挎槑缁嗙紪鍙凤紱鍓嶇搴斿厛鎸変换鍔″弬鏁拌褰曟帴鍙e彇鏄庣粏锛屽啀浠ュ叾 id 鎻愪氦銆�
+- 浠诲姟鏃犳ā鏉夸絾宸ュ簭缁戝畾浜嗗弬鏁版椂锛屽弬鏁拌褰曠殑 `templateId=null`銆乣templateName=宸ュ簭缁戝畾鍙傛暟`锛屽伐鍗曞弬鏁拌褰曢〉鎸夋灞曠ず銆�
+- 鍙傛暟绫诲瀷锛�1=鏂囨湰 2=鏁板�� 3=甯冨皵 4=鏃ユ湡锛屾姤宸ヨ〃鍗曟寜绫诲瀷娓叉煋杈撳叆鎺т欢銆�
+- 鎶ュ伐鎻愪氦鏃跺嵆浣夸笉濉弬鏁帮紙paramValues 涓虹┖锛夛紝鍚庣涔熶細鏍¢獙蹇呭~鍙傛暟锛屼换鍔$粦瀹氫簡鍙傛暟鏃跺繀椤诲~鍐欍��
+- 宸ュ簭缁戝畾鍙傛暟鎺ュ彛鐨勮鍐欐潈闄愬鐢ㄥ伐搴忚缃〉鏉冮檺锛坄mes:pro-process:query/update`锛夈��
+- 鍓嶇椤甸潰璺緞涓庤彍鍗曪細宸ュ簭璁剧疆 `mes/process-design/process/index`銆佸熀纭�鍙傛暟 `mes/process-design/parameter/index`銆�
diff --git a/docs/sql/mes_process_param_bind_full.sql b/docs/sql/mes_process_param_bind_full.sql
new file mode 100644
index 0000000..576234c
--- /dev/null
+++ b/docs/sql/mes_process_param_bind_full.sql
@@ -0,0 +1,145 @@
+-- ============================================================================
+-- 闇�姹傦細鍩虹鍙傛暟(宸ヨ壓鍙傛暟)鍙笌宸ュ簭缁戝畾锛岀粦瀹氬悗鎶ュ伐闇�濉啓鍙傛暟瀛楁
+-- 涓�閿暣鍚堣剼鏈細鍙洿鎺ユ墜鍔ㄦ墽琛岋紙鍚箓绛変繚鎶わ紝閲嶅鎵ц涓嶆姤閿欙級
+--
+-- 绗竴閮ㄥ垎锛氬姛鑳借縼绉伙紙宸ュ簭-鍙傛暟缁戝畾锛�
+-- 绗簩閮ㄥ垎锛氭椿搴撴紓绉讳慨澶嶏紙浠g爜宸插紩鐢ㄤ絾搴撶己澶辩殑鍒�/琛紝闇�琛ラ綈鎵嶈兘寤轰换鍔�/鎶ュ伐锛�
+-- ============================================================================
+
+-- ============================================================================
+-- 绗竴閮ㄥ垎锛氬姛鑳借縼绉�
+-- ============================================================================
+
+-- ---------- 1.1 宸ュ簭/浠诲姟/宸ュ崟宸ュ簭 澧炲姞 param_template_id锛堝弬鏁版ā鏉垮叧鑱旓紝鍔熻兘閾捐矾鍓嶇疆锛� ----------
+SET @exists = (SELECT COUNT(*) FROM information_schema.columns
+               WHERE table_schema = DATABASE() AND table_name = 'mes_pro_task' AND column_name = 'param_template_id');
+SET @sql = IF(@exists = 0,
+              'ALTER TABLE mes_pro_task ADD COLUMN param_template_id bigint DEFAULT NULL COMMENT ''宸ヨ壓鍙傛暟妯℃澘缂栧彿'' AFTER process_id',
+              'SELECT 1');
+PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
+
+SET @exists = (SELECT COUNT(*) FROM information_schema.columns
+               WHERE table_schema = DATABASE() AND table_name = 'mes_pro_route_process' AND column_name = 'param_template_id');
+SET @sql = IF(@exists = 0,
+              'ALTER TABLE mes_pro_route_process ADD COLUMN param_template_id bigint DEFAULT NULL COMMENT ''宸ヨ壓鍙傛暟妯℃澘缂栧彿'' AFTER process_id',
+              'SELECT 1');
+PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
+
+SET @exists = (SELECT COUNT(*) FROM information_schema.columns
+               WHERE table_schema = DATABASE() AND table_name = 'mes_pro_work_order_process' AND column_name = 'param_template_id');
+SET @sql = IF(@exists = 0,
+              'ALTER TABLE mes_pro_work_order_process ADD COLUMN param_template_id bigint DEFAULT NULL COMMENT ''宸ヨ壓鍙傛暟妯℃澘缂栧彿'' AFTER process_id',
+              'SELECT 1');
+PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
+
+-- ---------- 1.2 鏂板缓 宸ュ簭-宸ヨ壓鍙傛暟缁戝畾琛� ----------
+CREATE TABLE IF NOT EXISTS `mes_pro_process_param` (
+  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+  `process_id` bigint NOT NULL COMMENT '宸ュ簭缂栧彿锛堝叧鑱� mes_pro_process锛�',
+  `process_param_id` bigint NOT NULL COMMENT '宸ヨ壓鍙傛暟缂栧彿锛堝叧鑱� mes_pd_process_param锛�',
+  `required` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁蹇呭~',
+  `sort` int NULL DEFAULT NULL COMMENT '鎺掑簭',
+  `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '澶囨敞',
+  `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '鍒涘缓鑰�',
+  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+  `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '鏇存柊鑰�',
+  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+  `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+  PRIMARY KEY (`id`) USING BTREE,
+  INDEX `idx_process_id`(`process_id` ASC) USING BTREE,
+  INDEX `idx_process_param_id`(`process_param_id` ASC) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'MES 宸ュ簭-宸ヨ壓鍙傛暟缁戝畾' ROW_FORMAT = DYNAMIC;
+
+-- ---------- 1.3 鍙傛暟璁板綍涓昏〃妯℃澘瀛楁鍏佽涓虹┖锛堝伐搴忕粦瀹氬弬鏁扮敓鎴愭椂鏃犳ā鏉匡級 ----------
+ALTER TABLE mes_pro_work_order_param_record MODIFY COLUMN template_id bigint NULL DEFAULT NULL COMMENT '鍙傛暟妯℃澘缂栧彿锛堝伐搴忕粦瀹氬弬鏁扮敓鎴愭椂涓虹┖锛�';
+ALTER TABLE mes_pro_work_order_param_record MODIFY COLUMN template_name varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '妯℃澘鍚嶇О锛堝揩鐓э級';
+
+-- ---------- 1.4 鍙傛暟璁板綍鏄庣粏澧炲姞 required 蹇収锛堟姤宸ュ繀濉牎楠岀敤锛� ----------
+SET @exists = (SELECT COUNT(*) FROM information_schema.columns
+               WHERE table_schema = DATABASE() AND table_name = 'mes_pro_work_order_param_record_detail' AND column_name = 'required');
+SET @sql = IF(@exists = 0,
+              'ALTER TABLE mes_pro_work_order_param_record_detail ADD COLUMN required bit(1) NOT NULL DEFAULT b''0'' COMMENT ''鏄惁蹇呭~锛堝揩鐓э級'' AFTER param_type',
+              'SELECT 1');
+PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
+
+-- ============================================================================
+-- 绗簩閮ㄥ垎锛氭椿搴撴紓绉讳慨澶嶏紙浠g爜宸插紩鐢ㄤ絾搴撶己澶憋紱鑻ヤ綘鐨勫簱宸叉湁杩欎簺鍒�/琛ㄥ彲蹇界暐锛�
+-- ============================================================================
+
+-- ---------- 2.1 mes_pro_work_order 缂哄け鍒楋紙鎶ュ伐瀹℃壒 BPM 鐩稿叧锛� ----------
+SET @exists = (SELECT COUNT(*) FROM information_schema.columns
+               WHERE table_schema = DATABASE() AND table_name = 'mes_pro_work_order' AND column_name = 'is_feedback_approve');
+SET @sql = IF(@exists = 0,
+              'ALTER TABLE mes_pro_work_order ADD COLUMN is_feedback_approve tinyint(1) DEFAULT NULL COMMENT ''鏄惁寮�鍚姤宸ュ鎵� (1: 寮�鍚�, 0/NULL: 鍏抽棴)'' AFTER deleted',
+              'SELECT 1');
+PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
+
+SET @exists = (SELECT COUNT(*) FROM information_schema.columns
+               WHERE table_schema = DATABASE() AND table_name = 'mes_pro_work_order' AND column_name = 'process_definition_key');
+SET @sql = IF(@exists = 0,
+              'ALTER TABLE mes_pro_work_order ADD COLUMN process_definition_key varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT ''BPM 娴佺▼瀹氫箟 Key'' AFTER is_feedback_approve',
+              'SELECT 1');
+PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
+
+SET @exists = (SELECT COUNT(*) FROM information_schema.columns
+               WHERE table_schema = DATABASE() AND table_name = 'mes_pro_work_order' AND column_name = 'feedback_role');
+SET @sql = IF(@exists = 0,
+              'ALTER TABLE mes_pro_work_order ADD COLUMN feedback_role varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT ''鎶ュ伐瑙掕壊 (澶氫釜瑙掕壊浠ラ�楀彿鍒嗛殧)'' AFTER process_definition_key',
+              'SELECT 1');
+PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
+
+-- ---------- 2.2 mes_pro_feedback 缂哄け鍒楋紙鎶ュ伐 BPM 鐩稿叧锛� ----------
+SET @exists = (SELECT COUNT(*) FROM information_schema.columns
+               WHERE table_schema = DATABASE() AND table_name = 'mes_pro_feedback' AND column_name = 'process_instance_id');
+SET @sql = IF(@exists = 0,
+              'ALTER TABLE mes_pro_feedback ADD COLUMN process_instance_id varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT ''BPM 娴佺▼瀹炰緥缂栧彿'' AFTER remark',
+              'SELECT 1');
+PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
+
+SET @exists = (SELECT COUNT(*) FROM information_schema.columns
+               WHERE table_schema = DATABASE() AND table_name = 'mes_pro_feedback' AND column_name = 'process_definition_key');
+SET @sql = IF(@exists = 0,
+              'ALTER TABLE mes_pro_feedback ADD COLUMN process_definition_key varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT ''BPM 娴佺▼瀹氫箟 Key'' AFTER process_instance_id',
+              'SELECT 1');
+PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
+
+-- ---------- 2.3 缂哄け琛細浠诲姟鎸囧畾鎶ュ伐浜哄憳銆佷换鍔″仠宸ヨ褰曪紙姝ゅ墠杩佺Щ鏈簲鐢級 ----------
+CREATE TABLE IF NOT EXISTS `mes_pro_task_assignee` (
+  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+  `task_id` bigint(20) NOT NULL COMMENT '鐢熶骇浠诲姟 ID',
+  `user_id` bigint(20) NOT NULL COMMENT '绯荤粺鐢ㄦ埛 ID (鎸囧畾鎶ュ伐浜哄憳)',
+  `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
+  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+  `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
+  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+  `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+  PRIMARY KEY (`id`),
+  KEY `idx_task_id` (`task_id`),
+  KEY `idx_user_id` (`user_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='鐢熶骇浠诲姟鎸囧畾鎶ュ伐浜哄憳琛�';
+
+CREATE TABLE IF NOT EXISTS `mes_pro_task_pause_record` (
+  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+  `task_id` bigint(20) NOT NULL COMMENT '浠诲姟缂栧彿',
+  `work_order_id` bigint(20) DEFAULT NULL COMMENT '宸ュ崟缂栧彿',
+  `workstation_id` bigint(20) DEFAULT NULL COMMENT '宸ヤ綔绔欑紪鍙�',
+  `reason` varchar(255) NOT NULL COMMENT '鍋滃伐鍘熷洜',
+  `pause_time` datetime NOT NULL COMMENT '鍋滃伐鏃堕棿',
+  `pause_user_id` bigint(20) NOT NULL COMMENT '鍋滃伐鎿嶄綔浜篒D',
+  `resume_time` datetime DEFAULT NULL COMMENT '澶嶅伐鏃堕棿',
+  `resume_user_id` bigint(20) DEFAULT NULL COMMENT '澶嶅伐鎿嶄綔浜篒D',
+  `remark` varchar(500) DEFAULT NULL COMMENT '澶囨敞',
+  `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+  `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+  `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+  PRIMARY KEY (`id`) USING BTREE,
+  KEY `idx_task_id` (`task_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='鐢熶骇浠诲姟鍋滃伐璁板綍琛�';
+
+-- ============================================================================
+-- 鎵ц瀹屾垚銆傚彲鎵ц浠ヤ笅璇彞鏍稿锛�
+--   SHOW TABLES LIKE 'mes_pro_process_param';
+--   SHOW COLUMNS FROM mes_pro_work_order_param_record_detail LIKE 'required';
+-- ============================================================================
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/feedback/MesProFeedbackController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/feedback/MesProFeedbackController.java
index 8a78405..ef72ab0 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/feedback/MesProFeedbackController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/feedback/MesProFeedbackController.java
@@ -59,10 +59,15 @@
 import cn.iocoder.yudao.module.mes.dal.mysql.wm.itemconsume.MesWmItemConsumeMapper;
 import cn.iocoder.yudao.module.mes.dal.mysql.wm.productproduce.MesWmProductProduceLineMapper;
 import cn.iocoder.yudao.module.mes.dal.mysql.wm.productproduce.MesWmProductProduceMapper;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderParamRecordDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderParamRecordDetailDO;
+import cn.iocoder.yudao.module.mes.dal.mysql.pro.workorder.MesProWorkOrderParamRecordMapper;
+import cn.iocoder.yudao.module.mes.dal.mysql.pro.workorder.MesProWorkOrderParamRecordDetailMapper;
 import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants;
 
 import java.io.IOException;
 import java.util.*;
+import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
@@ -109,6 +114,10 @@
     private MesWmItemConsumeLineMapper itemConsumeLineMapper;
     @Resource
     private MesQcIpqcMapper ipqcMapper;
+    @Resource
+    private MesProWorkOrderParamRecordMapper paramRecordMapper;
+    @Resource
+    private MesProWorkOrderParamRecordDetailMapper paramRecordDetailMapper;
 
     @PostMapping("/create")
     @Operation(summary = "鍒涘缓鐢熶骇鎶ュ伐")
@@ -287,6 +296,28 @@
         Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
                 convertSetByFlatMap(list, feedback ->
                         Stream.of(feedback.getFeedbackUserId(), feedback.getApproveUserId())));
+        // 1.9 浠诲姟鍙傛暟璁板綍锛氭姤宸ュ洖鏄惧弬鏁板��
+        Set<Long> taskIds = convertSet(list, MesProFeedbackDO::getTaskId);
+        Map<Long, List<MesProWorkOrderParamRecordDetailDO>> taskParamDetailMap = new HashMap<>();
+        if (CollUtil.isNotEmpty(taskIds)) {
+            List<MesProWorkOrderParamRecordDO> paramRecords = paramRecordMapper.selectListByTaskIds(taskIds);
+            if (CollUtil.isNotEmpty(paramRecords)) {
+                Map<Long, List<MesProWorkOrderParamRecordDetailDO>> recordDetailMap = paramRecordDetailMapper
+                        .selectListByRecordIds(convertSet(paramRecords, MesProWorkOrderParamRecordDO::getId)).stream()
+                        .collect(Collectors.groupingBy(MesProWorkOrderParamRecordDetailDO::getRecordId));
+                for (MesProWorkOrderParamRecordDO record : paramRecords) {
+                    taskParamDetailMap.putIfAbsent(record.getTaskId(),
+                            recordDetailMap.getOrDefault(record.getId(), Collections.emptyList()));
+                }
+            }
+        }
+        Set<Long> paramUnitIds = new HashSet<>();
+        taskParamDetailMap.values().forEach(details -> details.forEach(d -> {
+            if (d.getUnitMeasureId() != null) {
+                paramUnitIds.add(d.getUnitMeasureId());
+            }
+        }));
+        Map<Long, MesMdUnitMeasureDO> paramUnitMeasureMap = unitMeasureService.getUnitMeasureMap(paramUnitIds);
 
         // 2. 鎷兼帴 VO
         return BeanUtils.toBean(list, MesProFeedbackRespVO.class, vo -> {
@@ -320,6 +351,22 @@
                     vo.setFeedbackUserNickname(user.getNickname()));
             findAndThen(userMap, vo.getApproveUserId(), user ->
                     vo.setApproveUserNickname(user.getNickname()));
+            // 鍙傛暟鍊煎洖鏄撅紙浠诲姟鍙傛暟璁板綍蹇収锛屽惈蹇呭~鏍囪锛�
+            List<MesProWorkOrderParamRecordDetailDO> taskDetails = taskParamDetailMap.get(vo.getTaskId());
+            if (CollUtil.isNotEmpty(taskDetails)) {
+                vo.setParamValues(taskDetails.stream().map(detail -> {
+                    MesProFeedbackRespVO.ParamValueResp pv = new MesProFeedbackRespVO.ParamValueResp();
+                    pv.setDetailId(detail.getId());
+                    pv.setParamCode(detail.getParamCode());
+                    pv.setParamName(detail.getParamName());
+                    pv.setParamType(detail.getParamType());
+                    pv.setUnitMeasureName(paramUnitMeasureMap.containsKey(detail.getUnitMeasureId())
+                            ? paramUnitMeasureMap.get(detail.getUnitMeasureId()).getName() : null);
+                    pv.setParamValue(detail.getParamValue());
+                    pv.setRequired(detail.getRequired());
+                    return pv;
+                }).toList());
+            }
         });
     }
 
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/feedback/vo/MesProFeedbackRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/feedback/vo/MesProFeedbackRespVO.java
index 4df6e71..5695b34 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/feedback/vo/MesProFeedbackRespVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/feedback/vo/MesProFeedbackRespVO.java
@@ -10,6 +10,7 @@
 
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
+import java.util.List;
 
 @Schema(description = "绠$悊鍚庡彴 - MES 鐢熶骇鎶ュ伐 Response VO")
 @Data
@@ -177,4 +178,34 @@
     @ExcelProperty("BPM 娴佺▼瀹氫箟 Key")
     private String processDefinitionKey;
 
+    @Schema(description = "鏈鎶ュ伐瀵瑰簲鐨勪换鍔″弬鏁板�硷紙鎸変换鍔″弬鏁拌褰曞揩鐓у睍绀猴級")
+    private List<ParamValueResp> paramValues;
+
+    @Data
+    @Schema(description = "鎶ュ伐鍙傛暟鍊�")
+    public static class ParamValueResp {
+
+        @Schema(description = "浠诲姟鍙傛暟璁板綍鏄庣粏缂栧彿", example = "1")
+        private Long detailId;
+
+        @Schema(description = "鍙傛暟缂栫爜", example = "PP2024001")
+        private String paramCode;
+
+        @Schema(description = "鍙傛暟鍚嶇О", example = "娓╁害")
+        private String paramName;
+
+        @Schema(description = "鍙傛暟绫诲瀷", example = "2")
+        private Integer paramType;
+
+        @Schema(description = "璁¢噺鍗曚綅鍚嶇О", example = "鈩�")
+        private String unitMeasureName;
+
+        @Schema(description = "鍙傛暟鍊�", example = "200")
+        private String paramValue;
+
+        @Schema(description = "鏄惁蹇呭~", example = "true")
+        private Boolean required;
+
+    }
+
 }
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/process/MesProProcessParamController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/process/MesProProcessParamController.java
new file mode 100644
index 0000000..d058a81
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/process/MesProProcessParamController.java
@@ -0,0 +1,111 @@
+package cn.iocoder.yudao.module.mes.controller.admin.pro.process;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.mes.controller.admin.pro.process.vo.MesProProcessRespVO;
+import cn.iocoder.yudao.module.mes.controller.admin.pro.process.vo.param.MesProProcessParamRespVO;
+import cn.iocoder.yudao.module.mes.controller.admin.pro.process.vo.param.MesProProcessParamSaveReqVO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pd.processparam.MesPdProcessParamDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.process.MesProProcessDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.process.MesProProcessParamDO;
+import cn.iocoder.yudao.module.mes.service.md.unitmeasure.MesMdUnitMeasureService;
+import cn.iocoder.yudao.module.mes.service.pd.processparam.MesPdProcessParamService;
+import cn.iocoder.yudao.module.mes.service.pro.process.MesProProcessParamService;
+import cn.iocoder.yudao.module.mes.service.pro.process.MesProProcessService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import org.springframework.security.access.prepost.PreAuthorize;
+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 static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
+
+@Tag(name = "绠$悊鍚庡彴 - MES 宸ュ簭宸ヨ壓鍙傛暟缁戝畾")
+@RestController
+@RequestMapping("/mes/pro/process-param")
+@Validated
+public class MesProProcessParamController {
+
+    @Resource
+    private MesProProcessParamService processParamService;
+    @Resource
+    private MesPdProcessParamService pdProcessParamService;
+    @Resource
+    private MesMdUnitMeasureService unitMeasureService;
+    @Resource
+    private MesProProcessService processService;
+
+    @GetMapping("/list-by-process")
+    @Operation(summary = "鑾峰緱宸ュ簭缁戝畾鐨勫伐鑹哄弬鏁板垪琛紙鎸夊伐搴忕紪鍙凤級")
+    @Parameter(name = "processId", description = "宸ュ簭缂栧彿", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('mes:pro-process:query')")
+    public CommonResult<List<MesProProcessParamRespVO>> getProcessParamListByProcessId(@RequestParam("processId") Long processId) {
+        List<MesProProcessParamDO> list = processParamService.getProcessParamListByProcessId(processId);
+        return success(buildRespVOList(list));
+    }
+
+    @PostMapping("/update-bindings")
+    @Operation(summary = "鍏ㄩ噺瑕嗙洊淇濆瓨宸ュ簭缁戝畾鐨勫伐鑹哄弬鏁�")
+    @PreAuthorize("@ss.hasPermission('mes:pro-process:update')")
+    public CommonResult<Boolean> updateProcessParams(@Valid @RequestBody MesProProcessParamSaveReqVO reqVO) {
+        processParamService.updateProcessParams(reqVO.getProcessId(), reqVO.getItems());
+        return success(true);
+    }
+
+    @GetMapping("/list-by-param")
+    @Operation(summary = "鑾峰緱宸ヨ壓鍙傛暟琚粦瀹氱殑宸ュ簭鍒楄〃锛堟寜宸ヨ壓鍙傛暟缂栧彿锛�")
+    @Parameter(name = "paramId", description = "宸ヨ壓鍙傛暟缂栧彿", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('mes:pro-process:query')")
+    public CommonResult<List<MesProProcessRespVO>> getProcessListByParamId(@RequestParam("paramId") Long paramId) {
+        List<MesProProcessParamDO> list = processParamService.getProcessParamListByParamId(paramId);
+        if (CollUtil.isEmpty(list)) {
+            return success(Collections.emptyList());
+        }
+        Map<Long, MesProProcessDO> processMap = processService.getProcessMap(
+                convertSet(list, MesProProcessParamDO::getProcessId));
+        List<MesProProcessRespVO> result = new ArrayList<>(list.size());
+        for (MesProProcessParamDO binding : list) {
+            MesProProcessDO process = processMap.get(binding.getProcessId());
+            if (process != null) {
+                result.add(new MesProProcessRespVO()
+                        .setId(process.getId()).setCode(process.getCode()).setName(process.getName()));
+            }
+        }
+        return success(result);
+    }
+
+    // ==================== 鎷兼帴 VO ====================
+
+    private List<MesProProcessParamRespVO> buildRespVOList(List<MesProProcessParamDO> list) {
+        if (CollUtil.isEmpty(list)) {
+            return Collections.emptyList();
+        }
+        // 1. 鎵归噺鑾峰彇宸ヨ壓鍙傛暟涓庤閲忓崟浣�
+        Map<Long, MesPdProcessParamDO> paramMap = pdProcessParamService.getProcessParamMap(
+                convertSet(list, MesProProcessParamDO::getProcessParamId));
+        Map<Long, MesMdUnitMeasureDO> unitMeasureMap = unitMeasureService.getUnitMeasureMap(
+                convertSet(paramMap.values(), MesPdProcessParamDO::getUnitMeasureId));
+        // 2. 鎷兼帴 VO
+        return BeanUtils.toBean(list, MesProProcessParamRespVO.class, vo ->
+                findAndThen(paramMap, vo.getProcessParamId(), param -> {
+                    vo.setParamCode(param.getParamCode()).setParamName(param.getParamName())
+                            .setParamType(param.getParamType()).setUnitMeasureId(param.getUnitMeasureId());
+                    findAndThen(unitMeasureMap, param.getUnitMeasureId(), unit ->
+                            vo.setUnitMeasureName(unit.getName()));
+                })
+        );
+    }
+
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/process/vo/param/MesProProcessParamRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/process/vo/param/MesProProcessParamRespVO.java
new file mode 100644
index 0000000..a858665
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/process/vo/param/MesProProcessParamRespVO.java
@@ -0,0 +1,57 @@
+package cn.iocoder.yudao.module.mes.controller.admin.pro.process.vo.param;
+
+import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
+import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
+import cn.iocoder.yudao.module.mes.enums.DictTypeConstants;
+import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
+import cn.idev.excel.annotation.ExcelProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "绠$悊鍚庡彴 - MES 宸ュ簭宸ヨ壓鍙傛暟缁戝畾 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class MesProProcessParamRespVO {
+
+    @Schema(description = "缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+    @ExcelProperty("缂栧彿")
+    private Long id;
+
+    @Schema(description = "宸ュ簭缂栧彿", example = "1")
+    private Long processId;
+
+    @Schema(description = "宸ヨ壓鍙傛暟缂栧彿", example = "1")
+    private Long processParamId;
+
+    @Schema(description = "鍙傛暟缂栫爜", example = "PP2024001")
+    @ExcelProperty("鍙傛暟缂栫爜")
+    private String paramCode;
+
+    @Schema(description = "鍙傛暟鍚嶇О", example = "娓╁害")
+    @ExcelProperty("鍙傛暟鍚嶇О")
+    private String paramName;
+
+    @Schema(description = "鍙傛暟绫诲瀷", example = "2")
+    @ExcelProperty(value = "鍙傛暟绫诲瀷", converter = DictConvert.class)
+    @DictFormat(DictTypeConstants.MES_PD_PROCESS_PARAM_TYPE)
+    private Integer paramType;
+
+    @Schema(description = "璁¢噺鍗曚綅缂栧彿", example = "1")
+    private Long unitMeasureId;
+
+    @Schema(description = "璁¢噺鍗曚綅鍚嶇О", example = "鈩�")
+    @ExcelProperty("鍗曚綅")
+    private String unitMeasureName;
+
+    @Schema(description = "鏄惁蹇呭~", example = "true")
+    @ExcelProperty("鏄惁蹇呭~")
+    private Boolean required;
+
+    @Schema(description = "鎺掑簭", example = "1")
+    private Integer sort;
+
+    @Schema(description = "澶囨敞", example = "澶囨敞")
+    @ExcelProperty("澶囨敞")
+    private String remark;
+
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/process/vo/param/MesProProcessParamSaveReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/process/vo/param/MesProProcessParamSaveReqVO.java
new file mode 100644
index 0000000..a2e7445
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/process/vo/param/MesProProcessParamSaveReqVO.java
@@ -0,0 +1,37 @@
+package cn.iocoder.yudao.module.mes.controller.admin.pro.process.vo.param;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.util.List;
+
+@Schema(description = "绠$悊鍚庡彴 - MES 宸ュ簭宸ヨ壓鍙傛暟缁戝畾鏂板/淇敼 Request VO")
+@Data
+public class MesProProcessParamSaveReqVO {
+
+    @Schema(description = "宸ュ簭缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+    @NotNull(message = "宸ュ簭缂栧彿涓嶈兘涓虹┖")
+    private Long processId;
+
+    @Schema(description = "缁戝畾鐨勫伐鑹哄弬鏁板垪琛紙鍏ㄩ噺瑕嗙洊淇濆瓨锛�")
+    private List<Item> items;
+
+    @Data
+    public static class Item {
+
+        @Schema(description = "宸ヨ壓鍙傛暟缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+        @NotNull(message = "宸ヨ壓鍙傛暟涓嶈兘涓虹┖")
+        private Long processParamId;
+
+        @Schema(description = "鏄惁蹇呭~锛堝彲瑕嗙洊鍙傛暟榛樿鍊硷級", example = "true")
+        private Boolean required;
+
+        @Schema(description = "鎺掑簭", example = "1")
+        private Integer sort;
+
+        @Schema(description = "澶囨敞", example = "澶囨敞")
+        private String remark;
+    }
+
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/process/MesProProcessParamDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/process/MesProProcessParamDO.java
new file mode 100644
index 0000000..07c0a46
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/process/MesProProcessParamDO.java
@@ -0,0 +1,56 @@
+package cn.iocoder.yudao.module.mes.dal.dataobject.pro.process;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+/**
+ * MES 宸ュ簭-宸ヨ壓鍙傛暟缁戝畾 DO
+ *
+ * <p>宸ュ簭涓绘暟鎹笌鍩虹鍙傛暟锛堝伐鑹哄弬鏁帮級鐨勫叧鑱斿叧绯伙紝鐢ㄤ簬鎶ュ伐鏃舵寜宸ュ簭灞曠ず鍙傛暟瀛楁銆�
+ *
+ * @author 瓒呯骇绠$悊鍛�
+ */
+@TableName("mes_pro_process_param")
+@KeySequence("mes_pro_process_param_seq") // 鐢ㄤ簬 Oracle銆丳ostgreSQL銆並ingbase銆丏B2銆丠2 鏁版嵁搴撶殑涓婚敭鑷銆傚鏋滄槸 MySQL 绛夋暟鎹簱锛屽彲涓嶅啓銆�
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class MesProProcessParamDO extends BaseDO {
+
+    /**
+     * 缂栧彿
+     */
+    @TableId
+    private Long id;
+    /**
+     * 宸ュ簭缂栧彿
+     *
+     * 鍏宠仈 {@link MesProProcessDO#getId()}
+     */
+    private Long processId;
+    /**
+     * 宸ヨ壓鍙傛暟缂栧彿
+     *
+     * 鍏宠仈 {@link cn.iocoder.yudao.module.mes.dal.dataobject.pd.processparam.MesPdProcessParamDO#getId()}
+     */
+    private Long processParamId;
+    /**
+     * 鏄惁蹇呭~锛堝彲瑕嗙洊鍙傛暟榛樿鍊硷級
+     */
+    private Boolean required;
+    /**
+     * 鎺掑簭
+     */
+    private Integer sort;
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkOrderParamRecordDetailDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkOrderParamRecordDetailDO.java
index 2ec0fe7..45fefc2 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkOrderParamRecordDetailDO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkOrderParamRecordDetailDO.java
@@ -55,6 +55,10 @@
      */
     private Integer paramType;
     /**
+     * 鏄惁蹇呭~锛堝揩鐓э級
+     */
+    private Boolean required;
+    /**
      * 璁¢噺鍗曚綅缂栧彿锛堝揩鐓э級
      */
     private Long unitMeasureId;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/process/MesProProcessParamMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/process/MesProProcessParamMapper.java
new file mode 100644
index 0000000..88502af
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/process/MesProProcessParamMapper.java
@@ -0,0 +1,49 @@
+package cn.iocoder.yudao.module.mes.dal.mysql.pro.process;
+
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.process.MesProProcessParamDO;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * MES 宸ュ簭-宸ヨ壓鍙傛暟缁戝畾 Mapper
+ *
+ * @author 瓒呯骇绠$悊鍛�
+ */
+@Mapper
+public interface MesProProcessParamMapper extends BaseMapperX<MesProProcessParamDO> {
+
+    default List<MesProProcessParamDO> selectListByProcessId(Long processId) {
+        return selectList(new LambdaQueryWrapperX<MesProProcessParamDO>()
+                .eq(MesProProcessParamDO::getProcessId, processId)
+                .orderByAsc(MesProProcessParamDO::getSort)
+                .orderByAsc(MesProProcessParamDO::getId));
+    }
+
+    default List<MesProProcessParamDO> selectListByProcessIds(Collection<Long> processIds) {
+        return selectList(new LambdaQueryWrapperX<MesProProcessParamDO>()
+                .inIfPresent(MesProProcessParamDO::getProcessId, processIds)
+                .orderByAsc(MesProProcessParamDO::getSort)
+                .orderByAsc(MesProProcessParamDO::getId));
+    }
+
+    default List<MesProProcessParamDO> selectListByProcessParamId(Long processParamId) {
+        return selectList(new LambdaQueryWrapperX<MesProProcessParamDO>()
+                .eq(MesProProcessParamDO::getProcessParamId, processParamId)
+                .orderByAsc(MesProProcessParamDO::getId));
+    }
+
+    default void deleteByProcessId(Long processId) {
+        delete(new LambdaQueryWrapperX<MesProProcessParamDO>()
+                .eq(MesProProcessParamDO::getProcessId, processId));
+    }
+
+    default void deleteByProcessParamId(Long processParamId) {
+        delete(new LambdaQueryWrapperX<MesProProcessParamDO>()
+                .eq(MesProProcessParamDO::getProcessParamId, processParamId));
+    }
+
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/workorder/MesProWorkOrderParamRecordMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/workorder/MesProWorkOrderParamRecordMapper.java
index 69dfec2..6322627 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/workorder/MesProWorkOrderParamRecordMapper.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/workorder/MesProWorkOrderParamRecordMapper.java
@@ -7,6 +7,7 @@
 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderParamRecordDO;
 import org.apache.ibatis.annotations.Mapper;
 
+import java.util.Collection;
 import java.util.List;
 
 /**
@@ -40,4 +41,10 @@
                 .orderByDesc(MesProWorkOrderParamRecordDO::getId));
     }
 
+    default List<MesProWorkOrderParamRecordDO> selectListByTaskIds(Collection<Long> taskIds) {
+        return selectList(new LambdaQueryWrapperX<MesProWorkOrderParamRecordDO>()
+                .in(MesProWorkOrderParamRecordDO::getTaskId, taskIds)
+                .orderByAsc(MesProWorkOrderParamRecordDO::getId));
+    }
+
 }
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pd/processparam/MesPdProcessParamServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pd/processparam/MesPdProcessParamServiceImpl.java
index 8f2fc10..dfe42b2 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pd/processparam/MesPdProcessParamServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pd/processparam/MesPdProcessParamServiceImpl.java
@@ -35,6 +35,10 @@
     @Lazy
     private MesMdAutoCodeRecordService autoCodeRecordService;
 
+    @Resource
+    @Lazy
+    private cn.iocoder.yudao.module.mes.service.pro.process.MesProProcessParamService processParamService;
+
     @Override
     public Long createProcessParam(MesPdProcessParamSaveReqVO createReqVO) {
         // 鐢熸垚鍙傛暟缂栫爜
@@ -60,6 +64,8 @@
     public void deleteProcessParam(Long id) {
         // 鏍¢獙瀛樺湪
         validateProcessParamExists(id);
+        // 鍒犻櫎宸ュ簭缁戝畾鍏崇郴锛岄伩鍏嶆畫鐣欒剰鏁版嵁
+        processParamService.deleteByParamId(id);
         // 鍒犻櫎
         processParamMapper.deleteById(id);
     }
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackServiceImpl.java
index e8fdc37..a7617dc 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackServiceImpl.java
@@ -104,6 +104,7 @@
     private cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi processInstanceApi;
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public Long createFeedback(MesProFeedbackSaveReqVO createReqVO) {
         // 1. 鏍¢獙
         MesProTaskDO task = validateFeedbackData(createReqVO);
@@ -113,11 +114,13 @@
                 .setStatus(MesProFeedbackStatusEnum.PREPARE.getStatus())
                 .setItemId(task.getItemId());
         feedbackMapper.insert(feedback);
+        // 3. 淇濆瓨鍙傛暟鍊硷紱蹇呭~鍙傛暟鏍¢獙澶辫触鏃舵暣浣撳洖婊氾紝閬垮厤娈嬬暀鑽夌
         saveParamValues(task.getId(), createReqVO.getParamValues());
         return feedback.getId();
     }
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public void updateFeedback(MesProFeedbackSaveReqVO updateReqVO) {
         // 1.1 鏍¢獙瀛樺湪 + 鑽夌鐘舵��
         validateFeedbackStatusPrepare(updateReqVO.getId());
@@ -128,11 +131,14 @@
         MesProFeedbackDO updateObj = BeanUtils.toBean(updateReqVO, MesProFeedbackDO.class)
                 .setItemId(task.getItemId());
         feedbackMapper.updateById(updateObj);
+        // 3. 淇濆瓨鍙傛暟鍊硷紱蹇呭~鍙傛暟鏍¢獙澶辫触鏃舵暣浣撳洖婊�
         saveParamValues(task.getId(), updateReqVO.getParamValues());
     }
 
     private void saveParamValues(Long taskId, List<MesProFeedbackSaveReqVO.ParamValue> paramValues) {
+        // 鍗充娇鍙傛暟涓虹┖涔熻皟鐢ㄦ洿鏂帮紝浠ヤ究瑙﹀彂蹇呭~鍙傛暟鏍¢獙锛堜换鍔$粦瀹氫簡鍙傛暟鏃跺繀椤诲~鍐欙級
         if (CollUtil.isEmpty(paramValues)) {
+            paramRecordService.updateTaskParamValues(taskId, null, null);
             return;
         }
         paramRecordService.updateTaskParamValues(taskId,
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/process/MesProProcessParamService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/process/MesProProcessParamService.java
new file mode 100644
index 0000000..ee1820d
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/process/MesProProcessParamService.java
@@ -0,0 +1,55 @@
+package cn.iocoder.yudao.module.mes.service.pro.process;
+
+import cn.iocoder.yudao.module.mes.controller.admin.pro.process.vo.param.MesProProcessParamSaveReqVO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.process.MesProProcessParamDO;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * MES 宸ュ簭-宸ヨ壓鍙傛暟缁戝畾 Service 鎺ュ彛
+ *
+ * @author 瓒呯骇绠$悊鍛�
+ */
+public interface MesProProcessParamService {
+
+    /**
+     * 鑾峰緱鏌愬伐搴忕粦瀹氱殑宸ヨ壓鍙傛暟鍒楄〃锛堟寜鎺掑簭锛�
+     *
+     * @param processId 宸ュ簭缂栧彿
+     * @return 缁戝畾鍒楄〃
+     */
+    List<MesProProcessParamDO> getProcessParamListByProcessId(Long processId);
+
+    /**
+     * 鎵归噺鑾峰緱澶氫釜宸ュ簭缁戝畾鐨勫伐鑹哄弬鏁�
+     *
+     * @param processIds 宸ュ簭缂栧彿闆嗗悎
+     * @return 缁戝畾鍒楄〃
+     */
+    List<MesProProcessParamDO> getProcessParamListByProcessIds(Collection<Long> processIds);
+
+    /**
+     * 鑾峰緱鏌愬伐鑹哄弬鏁拌鍝簺宸ュ簭缁戝畾锛堝熀纭�鍙傛暟椤靛弽鏌ュ伐搴忥級
+     *
+     * @param processParamId 宸ヨ壓鍙傛暟缂栧彿
+     * @return 缁戝畾鍒楄〃
+     */
+    List<MesProProcessParamDO> getProcessParamListByParamId(Long processParamId);
+
+    /**
+     * 鍏ㄩ噺瑕嗙洊淇濆瓨鏌愬伐搴忕粦瀹氱殑宸ヨ壓鍙傛暟
+     *
+     * @param processId 宸ュ簭缂栧彿
+     * @param items     缁戝畾椤瑰垪琛�
+     */
+    void updateProcessParams(Long processId, List<MesProProcessParamSaveReqVO.Item> items);
+
+    /**
+     * 鍒犻櫎鏌愬伐鑹哄弬鏁扮殑鎵�鏈夊伐搴忕粦瀹氾紙鍒犻櫎宸ヨ壓鍙傛暟鏃舵竻鐞嗭級
+     *
+     * @param processParamId 宸ヨ壓鍙傛暟缂栧彿
+     */
+    void deleteByParamId(Long processParamId);
+
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/process/MesProProcessParamServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/process/MesProProcessParamServiceImpl.java
new file mode 100644
index 0000000..2bece6f
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/process/MesProProcessParamServiceImpl.java
@@ -0,0 +1,86 @@
+package cn.iocoder.yudao.module.mes.service.pro.process;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.module.mes.controller.admin.pro.process.vo.param.MesProProcessParamSaveReqVO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.process.MesProProcessParamDO;
+import cn.iocoder.yudao.module.mes.dal.mysql.pro.process.MesProProcessParamMapper;
+import cn.iocoder.yudao.module.mes.service.pd.processparam.MesPdProcessParamService;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.validation.annotation.Validated;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * MES 宸ュ簭-宸ヨ壓鍙傛暟缁戝畾 Service 瀹炵幇绫�
+ *
+ * @author 瓒呯骇绠$悊鍛�
+ */
+@Service
+@Validated
+public class MesProProcessParamServiceImpl implements MesProProcessParamService {
+
+    @Resource
+    private MesProProcessParamMapper processParamMapper;
+    @Resource
+    private MesProProcessService processService;
+    @Resource
+    private MesPdProcessParamService pdProcessParamService;
+
+    @Override
+    public List<MesProProcessParamDO> getProcessParamListByProcessId(Long processId) {
+        return processParamMapper.selectListByProcessId(processId);
+    }
+
+    @Override
+    public List<MesProProcessParamDO> getProcessParamListByProcessIds(Collection<Long> processIds) {
+        if (CollUtil.isEmpty(processIds)) {
+            return new ArrayList<>();
+        }
+        return processParamMapper.selectListByProcessIds(processIds);
+    }
+
+    @Override
+    public List<MesProProcessParamDO> getProcessParamListByParamId(Long processParamId) {
+        return processParamMapper.selectListByProcessParamId(processParamId);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void updateProcessParams(Long processId, List<MesProProcessParamSaveReqVO.Item> items) {
+        // 1. 鏍¢獙宸ュ簭瀛樺湪
+        processService.validateProcessExists(processId);
+        // 2. 鏍¢獙宸ヨ壓鍙傛暟瀛樺湪
+        if (CollUtil.isNotEmpty(items)) {
+            for (MesProProcessParamSaveReqVO.Item item : items) {
+                pdProcessParamService.validateProcessParamExists(item.getProcessParamId());
+            }
+        }
+        // 3. 鍏ㄩ噺瑕嗙洊锛氬厛鍒犳棫缁戝畾锛屽啀鎻掑叆鏂扮粦瀹�
+        processParamMapper.deleteByProcessId(processId);
+        if (CollUtil.isEmpty(items)) {
+            return;
+        }
+        List<MesProProcessParamDO> list = new ArrayList<>(items.size());
+        for (int i = 0; i < items.size(); i++) {
+            MesProProcessParamSaveReqVO.Item item = items.get(i);
+            list.add(MesProProcessParamDO.builder()
+                    .processId(processId)
+                    .processParamId(item.getProcessParamId())
+                    .required(Boolean.TRUE.equals(item.getRequired()))
+                    .sort(item.getSort() != null ? item.getSort() : i + 1)
+                    .remark(item.getRemark())
+                    .build());
+        }
+        processParamMapper.insertBatch(list);
+    }
+
+    @Override
+    public void deleteByParamId(Long processParamId) {
+        processParamMapper.deleteByProcessParamId(processParamId);
+    }
+
+}
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 5f82736..71194e3 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
@@ -12,6 +12,7 @@
 import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.md.workstation.MesMdWorkstationMachineDO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.task.MesProTaskDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.process.MesProProcessParamDO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO;
 import cn.iocoder.yudao.module.mes.dal.mysql.pro.task.MesProTaskMapper;
 import cn.iocoder.yudao.module.mes.dal.mysql.pro.feedback.MesProFeedbackMapper;
@@ -24,6 +25,7 @@
 import cn.iocoder.yudao.module.mes.service.md.workstation.MesMdWorkstationMachineService;
 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.process.MesProProcessParamService;
 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteProcessDO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteDO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteProductDO;
@@ -111,6 +113,9 @@
     @Lazy
     private MesProWorkOrderParamRecordService workOrderParamRecordService;
     @Resource
+    @Lazy
+    private MesProProcessParamService processParamService;
+    @Resource
     private MesMdAutoCodeRecordService autoCodeRecordService;
     @Resource
     private MesMdWorkstationMachineService workstationMachineService;
@@ -150,14 +155,28 @@
         }
         // 2.2 鎻掑叆
         taskMapper.insert(task);
-        if (task.getParamTemplateId() != null) {
-            workOrderParamRecordService.createTaskParamRecord(task.getId(), task.getParamTemplateId());
-        }
+        // 2.2.1 鍙傛暟蹇収锛氫紭鍏堜娇鐢ㄦā鏉匡紱鏃犳ā鏉挎椂鍥為��鍒板伐搴忎富鏁版嵁缁戝畾鐨勫伐鑹哄弬鏁�
+        createTaskParamRecordWithFallback(task);
 
         // 2.3 淇濆瓨鎸囧畾鎶ュ伐浜哄憳
         updateTaskAssignees(task.getId(), createReqVO.getAssigneeUserIds());
-        
+
         return task.getId();
+    }
+
+    /**
+     * 涓轰换鍔″浐鍖栧弬鏁板揩鐓э細浼樺厛浣跨敤璺嚎/宸ュ崟宸ュ簭缁戝畾鐨勫弬鏁版ā鏉匡紱鏃犳ā鏉挎椂鍥為��鍒板伐搴忎富鏁版嵁缁戝畾鐨勫伐鑹哄弬鏁�
+     */
+    private void createTaskParamRecordWithFallback(MesProTaskDO task) {
+        if (task.getParamTemplateId() != null) {
+            workOrderParamRecordService.createTaskParamRecord(task.getId(), task.getParamTemplateId());
+            return;
+        }
+        // 鏃犳ā鏉匡細浠庡伐搴忎富鏁版嵁瑙f瀽缁戝畾鐨勫伐鑹哄弬鏁�
+        List<MesProProcessParamDO> processParams = processParamService.getProcessParamListByProcessId(task.getProcessId());
+        if (CollUtil.isNotEmpty(processParams)) {
+            workOrderParamRecordService.createTaskParamRecordFromProcessParams(task.getId(), processParams);
+        }
     }
 
     @Override
@@ -498,9 +517,8 @@
                     .setClientId(workOrder.getClientId())
                     .setColorCode(rp.getColorCode());
             taskMapper.insert(task);
-            if (task.getParamTemplateId() != null) {
-                workOrderParamRecordService.createTaskParamRecord(task.getId(), task.getParamTemplateId());
-            }
+            // 鍙傛暟蹇収锛氫紭鍏堜娇鐢ㄦā鏉匡紱鏃犳ā鏉挎椂鍥為��鍒板伐搴忎富鏁版嵁缁戝畾鐨勫伐鑹哄弬鏁�
+            createTaskParamRecordWithFallback(task);
             taskIds.add(task.getId());
         }
         // 7. 鏇存柊宸ュ崟宸叉帓浜ф暟閲�
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderParamRecordService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderParamRecordService.java
index 344dc04..85465c3 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderParamRecordService.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderParamRecordService.java
@@ -3,6 +3,7 @@
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.paramrecord.MesProWorkOrderParamRecordPageReqVO;
 import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.paramrecord.MesProWorkOrderParamRecordSaveReqVO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.process.MesProProcessParamDO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderParamRecordDO;
 import jakarta.validation.Valid;
 
@@ -30,6 +31,15 @@
     Long createTaskParamRecord(Long taskId, Long templateId);
 
     /**
+     * 鏍规嵁宸ュ簭缁戝畾鐨勫伐鑹哄弬鏁颁负鐢熶骇浠诲姟鍥哄寲鍙傛暟蹇収锛堟棤妯℃澘鏃剁殑鍥為��璺緞锛�
+     *
+     * @param taskId        浠诲姟缂栧彿
+     * @param processParams 宸ュ簭缁戝畾鐨勫伐鑹哄弬鏁板垪琛�
+     * @return 璁板綍缂栧彿
+     */
+    Long createTaskParamRecordFromProcessParams(Long taskId, List<MesProProcessParamDO> processParams);
+
+    /**
      * 鏇存柊宸ュ崟鍙傛暟璁板綍锛堜粎鏇存柊濉啓鍊硷紝涓嶆崲妯℃澘锛�
      *
      * @param updateReqVO 鏇存柊淇℃伅
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderParamRecordServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderParamRecordServiceImpl.java
index baea293..56bacbf 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderParamRecordServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderParamRecordServiceImpl.java
@@ -5,14 +5,17 @@
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.paramrecord.MesProWorkOrderParamRecordPageReqVO;
 import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.paramrecord.MesProWorkOrderParamRecordSaveReqVO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pd.processparam.MesPdProcessParamDO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.pd.processparamtemplate.MesPdProcessParamTemplateDetailDO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.pd.processparamtemplate.MesPdProcessParamTemplateDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.process.MesProProcessParamDO;
 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.pro.workorder.MesProWorkOrderParamRecordDO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderParamRecordDetailDO;
 import cn.iocoder.yudao.module.mes.dal.mysql.pro.workorder.MesProWorkOrderParamRecordDetailMapper;
 import cn.iocoder.yudao.module.mes.dal.mysql.pro.workorder.MesProWorkOrderParamRecordMapper;
+import cn.iocoder.yudao.module.mes.service.pd.processparam.MesPdProcessParamService;
 import cn.iocoder.yudao.module.mes.service.pd.processparamtemplate.MesPdProcessParamTemplateService;
 import cn.iocoder.yudao.module.mes.service.pro.task.MesProTaskService;
 import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderService;
@@ -22,6 +25,7 @@
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
 
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
@@ -46,6 +50,8 @@
     private MesProWorkOrderService workOrderService;
     @Resource
     private MesPdProcessParamTemplateService templateService;
+    @Resource
+    private MesPdProcessParamService pdProcessParamService;
     @Autowired
     private MesProTaskService mesProTaskService;
     @Autowired
@@ -80,10 +86,57 @@
                 .paramCode(detail.getParamCode())
                 .paramName(detail.getParamName())
                 .paramType(detail.getParamType())
+                .required(detail.getRequired())
                 .unitMeasureId(detail.getUnitMeasureId())
                 .paramValue(null)
                 .remark(detail.getRemark())
                 .build()).toList());
+        return record.getId();
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Long createTaskParamRecordFromProcessParams(Long taskId, List<MesProProcessParamDO> processParams) {
+        MesProTaskDO task = mesProTaskService.getTask(taskId);
+        if (task == null || CollUtil.isEmpty(processParams)) {
+            return null;
+        }
+        // 1. 鎵归噺鑾峰彇宸ヨ壓鍙傛暟瀹氫箟锛岃繃婊ゅ凡鍒犻櫎鐨勫弬鏁�
+        Map<Long, MesPdProcessParamDO> paramMap = pdProcessParamService.getProcessParamMap(
+                processParams.stream().map(MesProProcessParamDO::getProcessParamId).collect(Collectors.toSet()));
+        List<MesProProcessParamDO> valid = processParams.stream()
+                .filter(pp -> paramMap.containsKey(pp.getProcessParamId()))
+                .toList();
+        if (CollUtil.isEmpty(valid)) {
+            return null;
+        }
+        // 2. 鎻掑叆涓昏〃锛堟棤妯℃澘锛宼emplate 鐩稿叧瀛楁涓虹┖锛�
+        MesProWorkOrderDO workOrder = mesProWorkOrderService.getWorkOrder(task.getWorkOrderId());
+        MesProWorkOrderParamRecordDO record = MesProWorkOrderParamRecordDO.builder()
+                .workOrderId(workOrder != null ? workOrder.getId() : task.getWorkOrderId())
+                .taskId(taskId)
+                .templateId(null)
+                .templateCode(null)
+                .templateName("宸ュ簭缁戝畾鍙傛暟")
+                .recordNo("TASK-" + taskId)
+                .remark("鐢熶骇浠诲姟鎸夊伐搴忕粦瀹氬弬鏁扮敓鎴愮殑鍙傛暟蹇収")
+                .build();
+        paramRecordMapper.insert(record);
+        // 3. 鎻掑叆鏄庣粏锛堝揩鐓у弬鏁板畾涔夛紝required 浼樺厛鍙栫粦瀹氬�硷紝鍏舵鍙栧弬鏁伴粯璁ゅ�硷級
+        paramRecordDetailMapper.insertBatch(valid.stream().map(pp -> {
+            MesPdProcessParamDO param = paramMap.get(pp.getProcessParamId());
+            return MesProWorkOrderParamRecordDetailDO.builder()
+                    .recordId(record.getId())
+                    .templateDetailId(null)
+                    .paramCode(param.getParamCode())
+                    .paramName(param.getParamName())
+                    .paramType(param.getParamType())
+                    .required(pp.getRequired() != null ? pp.getRequired() : param.getRequired())
+                    .unitMeasureId(param.getUnitMeasureId())
+                    .paramValue(null)
+                    .remark(pp.getRemark())
+                    .build();
+        }).toList());
         return record.getId();
     }
 
@@ -139,6 +192,7 @@
                             .paramCode(templateDetail.getParamCode())
                             .paramName(templateDetail.getParamName())
                             .paramType(templateDetail.getParamType())
+                            .required(templateDetail.getRequired())
                             .unitMeasureId(templateDetail.getUnitMeasureId())
                             .paramValue(item.getParamValue())
                             .build();
@@ -194,6 +248,7 @@
                             .paramCode(templateDetail.getParamCode())
                             .paramName(templateDetail.getParamName())
                             .paramType(templateDetail.getParamType())
+                            .required(templateDetail.getRequired())
                             .unitMeasureId(templateDetail.getUnitMeasureId())
                             .paramValue(item.getParamValue())
                             .build();
@@ -230,22 +285,38 @@
     @Override
     @Transactional(rollbackFor = Exception.class)
     public void updateTaskParamValues(Long taskId, List<Long> detailIds, List<String> values) {
-        if (CollUtil.isEmpty(detailIds)) {
-            return;
-        }
         MesProWorkOrderParamRecordDO record = paramRecordMapper.selectFirstByTaskId(taskId);
         if (record == null) {
-            return;
+            return; // 浠诲姟鏃犲弬鏁拌褰曪紙鏈粦瀹氬弬鏁帮級锛屾棤闇�鏍¢獙
         }
         List<MesProWorkOrderParamRecordDetailDO> details = paramRecordDetailMapper.selectListByRecordId(record.getId());
+        if (CollUtil.isEmpty(details)) {
+            return;
+        }
+        // 1. 鏋勫缓鎻愪氦鏄庣粏鏄犲皠锛坉etailId -> 鍙傛暟鍊硷級
+        Map<Long, String> valueMap = new HashMap<>();
+        if (CollUtil.isNotEmpty(detailIds)) {
+            for (int i = 0; i < detailIds.size(); i++) {
+                valueMap.put(detailIds.get(i), values != null && values.size() > i ? values.get(i) : null);
+            }
+        }
+        // 2. 鏍¢獙蹇呭~鍙傛暟閮芥湁鍊硷紙缁戝畾鍙傛暟鎴栨ā鏉垮揩鐓т腑鐨� required锛�
         Map<Long, MesProWorkOrderParamRecordDetailDO> detailMap = details.stream()
                 .collect(Collectors.toMap(MesProWorkOrderParamRecordDetailDO::getId, d -> d));
-        for (int i = 0; i < detailIds.size(); i++) {
-            MesProWorkOrderParamRecordDetailDO detail = detailMap.get(detailIds.get(i));
+        for (MesProWorkOrderParamRecordDetailDO detail : details) {
+            String value = valueMap.get(detail.getId());
+            if (Boolean.TRUE.equals(detail.getRequired())
+                    && (value == null || value.isBlank())) {
+                throw exception(PRO_WORK_ORDER_PARAM_RECORD_REQUIRED_PARAM_MISSING, detail.getParamName());
+            }
+        }
+        // 3. 鏇存柊鎻愪氦鐨勫弬鏁板��
+        for (Map.Entry<Long, String> entry : valueMap.entrySet()) {
+            MesProWorkOrderParamRecordDetailDO detail = detailMap.get(entry.getKey());
             if (detail == null) {
                 throw exception(PRO_WORK_ORDER_PARAM_RECORD_DETAIL_NOT_IN_TEMPLATE);
             }
-            detail.setParamValue(values != null && values.size() > i ? values.get(i) : null);
+            detail.setParamValue(entry.getValue());
             paramRecordDetailMapper.updateById(detail);
         }
     }

--
Gitblit v1.9.3