From 1f7c36424e8f48a5917ac6c77e2e47979c469a28 Mon Sep 17 00:00:00 2001
From: liu <2021943741@qq.com>
Date: 星期三, 26 八月 2026 09:00:14 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/dev_business' into dev_business

---
 .agents/rules/compile-check.md                                                                                                             |   32 +
 .agents/rules/database-mcp.md                                                                                                              |   48 +
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/task/MesProTaskServiceImpl.java                                     |   49 +
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/task/MesProTaskController.java                             |   32 +
 docs/sql/README.md                                                                                                                         |    5 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/task/MesProTaskMapper.java                                        |    7 
 yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/LoginUser.java                   |    1 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkOrderController.java                   |    7 
 yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/permission/RoleServiceImpl.java                                   |   13 
 .agents/rules/sql-script.md                                                                                                                |    6 
 yudao-server/src/main/resources/application-wtxc.yaml                                                                                      |  222 +++++++
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/feedback/MesProFeedbackDO.java                               |   10 
 .agents/rules/powershell-commands.md                                                                                                       |   35 +
 docs/sql/mes_pro_task_assignee.sql                                                                                                         |   14 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/feedback/MesProFeedbackController.java                     |    6 
 .agents/rules/sql-docs-sync.md                                                                                                             |   12 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/task/vo/MesProTaskSaveReqVO.java                           |    3 
 yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2TokenServiceImpl.java                                |   20 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/listener/MesProFeedbackStatusListener.java                 |   74 ++
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackServiceImpl.java                             |   77 ++
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java                                                   |    1 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/mps/MesProMpsMapper.java                                          |    6 
 .agents/rules/frontend-doc-generation.md                                                                                                   |   93 +++
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/task/vo/MesProTaskPageReqVO.java                           |    3 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/task/vo/MesProTaskRespVO.java                              |    8 
 .agents/rules/frontend-docs.md                                                                                                             |   64 ++
 yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/util/SecurityFrameworkUtils.java |   23 
 .agents/rules/sql-syntax.md                                                                                                                |   40 +
 .agents/rules/security-guardrails.md                                                                                                       |   37 +
 .gitignore                                                                                                                                 |    5 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/common/bpm/MesBpmProcessServiceImpl.java                                |   71 ++
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/common/bpm/MesBpmProcessService.java                                    |   19 
 yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.java                                 |   34 +
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/task/MesProTaskAssigneeDO.java                               |   40 +
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderServiceImpl.java                           |   13 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pd/project/MesPdProjectServiceImpl.java                                 |   43 -
 sql/mysql/mes_pro_task_assignee.sql                                                                                                        |   14 
 docs/projectSql/ruoyi-vue-pro.sql                                                                                                          |  115 ++-
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/MesProWorkOrderRespVO.java                    |   12 
 .agents/rules/handover-data-query.md                                                                                                       |  103 +++
 yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/permission/RoleService.java                                       |   16 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackService.java                                 |   12 
 .agents/rules/frontend-project.md                                                                                                          |   16 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/feedback/vo/MesProFeedbackSaveReqVO.java                   |    6 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/task/MesProTaskAssigneeMapper.java                                |   38 +
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderService.java                               |    7 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/feedback/vo/MesProFeedbackSubmitReqVO.java                 |   50 +
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkOrderDO.java                             |   18 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/MesProWorkOrderSaveReqVO.java                 |    9 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/feedback/vo/MesProFeedbackRespVO.java                      |    8 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/task/MesProTaskService.java                                         |   19 
 .agents/rules/file-upload.md                                                                                                               |  120 ++++
 yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/permission/RoleMapper.java                                      |    4 
 53 files changed, 1,629 insertions(+), 111 deletions(-)

diff --git a/.agents/rules/compile-check.md b/.agents/rules/compile-check.md
new file mode 100644
index 0000000..46227e5
--- /dev/null
+++ b/.agents/rules/compile-check.md
@@ -0,0 +1,32 @@
+# 缂栬瘧妫�鏌ヨ鍒�
+
+## 瑙勫垯
+
+- 璺ㄦā鍧� API 璋冪敤鍦ㄤ慨鏀瑰畬鎴愭椂锛屽繀椤昏繘琛屼竴娆$紪璇戞鏌ワ紝纭繚娌℃湁寮曞叆缂栬瘧閿欒銆�
+- 浣跨敤鍛戒护锛歚mvn compile -pl <妯″潡鍚�> -am -q` 杩涜蹇�熺紪璇戦獙璇併��
+- 濡傛灉娑夊強澶氫釜妯″潡淇敼锛屽簲鎵ц `mvn compile -q` 杩涜鍏ㄩ」鐩紪璇戦獙璇併��
+
+## 甯歌璺ㄦā鍧� API 璋冪敤鍦烘櫙
+
+| 璋冪敤鏂� | API 鎻愪緵鏂� | 璇存槑 |
+|--------|-----------|------|
+| CRM 妯″潡 | MdmItemApi | MDM 鐗╂枡鎺ュ彛 |
+| CRM 妯″潡 | MdmUnitMeasureApi | MDM 璁¢噺鍗曚綅鎺ュ彛 |
+| CRM 妯″潡 | BpmProcessInstanceApi | BPM 娴佺▼瀹炰緥鎺ュ彛 |
+| CRM 妯″潡 | BpmCategoryService | BPM 鍒嗙被鏈嶅姟 |
+| CRM 妯″潡 | BpmProcessDefinitionService | BPM 娴佺▼瀹氫箟鏈嶅姟 |
+| ERP 妯″潡 | CrmCustomerApi | CRM 瀹㈡埛鎺ュ彛 |
+| ERP 妯″潡 | MdmItemApi | MDM 鐗╂枡鎺ュ彛 |
+
+## 缂栬瘧妫�鏌ョず渚�
+
+```bash
+# 浠呯紪璇� CRM 妯″潡鍙婂叾渚濊禆
+mvn compile -pl yudao-module-crm -am -q
+
+# 浠呯紪璇� ERP 妯″潡鍙婂叾渚濊禆
+mvn compile -pl yudao-module-erp -am -q
+
+# 鍏ㄩ」鐩紪璇�
+mvn compile -q
+```
\ No newline at end of file
diff --git a/.agents/rules/database-mcp.md b/.agents/rules/database-mcp.md
new file mode 100644
index 0000000..dc1f887
--- /dev/null
+++ b/.agents/rules/database-mcp.md
@@ -0,0 +1,48 @@
+# 鏁版嵁搴撴搷浣滆鍒�
+
+## 鏁版嵁搴撶増鏈�
+
+- **MySQL 鐗堟湰**: 8.4.8
+- 娉ㄦ剰 MySQL 8.4 鐨勮娉曞樊寮傦紙濡� `GROUP BY` 鏇翠弗鏍笺�侀儴鍒嗗簾寮冨嚱鏁扮瓑锛�
+
+## Docker 閮ㄧ讲閰嶇疆
+
+```bash
+--sql-mode="STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION" \
+--innodb_strict_mode=OFF \
+--innodb_page_size=32k \
+--max_connections=1020 \
+--lower_case_table_names=1 \
+--innodb_buffer_pool_size=70G \
+--innodb_flush_log_at_trx_commit=2 \
+--innodb_log_file_size=2G \
+--innodb_log_buffer_size=64M
+```
+
+**閰嶇疆璇存槑锛�**
+- `lower_case_table_names=1`: 琛ㄥ悕涓嶅尯鍒嗗ぇ灏忓啓
+- `innodb_page_size=32k`: 杈冨ぇ鐨勯〉澶у皬閫傚悎澶ф暟鎹噺鍦烘櫙
+- `innodb_buffer_pool_size=70G`: 缂撳啿姹犲ぇ灏忥紝寤鸿涓虹墿鐞嗗唴瀛樼殑 60-80%
+- `innodb_flush_log_at_trx_commit=2`: 姣忕鍒峰啓鏃ュ織锛屾�ц兘浼樺厛锛堥潪閲戣瀺鍦烘櫙锛�
+
+## 瑙勫垯
+
+- 浼樺厛浣跨敤 MySQL MCP 宸ュ叿锛坄mcp__designcomputer-mysql_mcp_server__execute_sql`銆乣mcp__designcomputer-mysql_mcp_server__get_schema_info`銆乣mcp__designcomputer-mysql_mcp_server__get_table_sample`锛夌洿鎺ユ搷浣滄暟鎹簱锛岃�岄潪閫氳繃 Bash 鎵ц mysql 鍛戒护銆�
+- 鏌ヨ銆侀獙璇併�佽皟璇曟暟鎹簱鏃讹紝鐩存帴璋冪敤 MCP 宸ュ叿鎵ц SQL锛屾棤闇�鍚戠敤鎴疯緭鍑� SQL 璇彞鎴栬闂槸鍚︽墽琛屻��
+- 浠呭湪浠ヤ笅鍦烘櫙杈撳嚭 SQL锛氱敤鎴锋槑纭姹傛煡鐪� SQL銆侀渶瑕佺敓鎴� SQL 鑴氭湰鏂囦欢锛堝杩佺Щ鑴氭湰锛夈�丮CP 宸ュ叿涓嶅彲鐢ㄦ椂鍥為��鍒� Bash銆�
+
+## MCP 宸ュ叿璇存槑
+
+| 宸ュ叿 | 鐢ㄩ�� |
+|------|------|
+| `execute_sql` | 鎵ц SQL 璇彞锛圫ELECT/INSERT/UPDATE/DELETE/DDL锛� |
+| `get_schema_info` | 鑾峰彇琛ㄧ粨鏋勪俊鎭紙鍒楀悕銆佺被鍨嬨�佹敞閲婄瓑锛� |
+| `get_table_sample` | 鑾峰彇琛ㄦ暟鎹牱鏈紙鐢ㄤ簬浜嗚В鏁版嵁鏍煎紡锛� |
+
+## 鎵ц SQL 鑴氭湰
+
+褰撶敤鎴疯姹傛墽琛� SQL 鏂囦欢鏃讹細
+1. 鍏堣鍙栨枃浠跺唴瀹�
+2. 閫愭潯鎵ц SQL 璇彞
+3. 閬囧埌閿欒鏃舵鏌ヨ〃缁撴瀯锛岃皟鏁磋鍙ュ悗閲嶈瘯
+4. 姹囨�绘墽琛岀粨鏋�
\ No newline at end of file
diff --git a/.agents/rules/file-upload.md b/.agents/rules/file-upload.md
new file mode 100644
index 0000000..c90d46a
--- /dev/null
+++ b/.agents/rules/file-upload.md
@@ -0,0 +1,120 @@
+# 鏂囦欢涓婁紶瑙勫垯
+
+## 鏍稿績鍘熷垯锛圓I 蹇呴』涓ユ牸閬靛畧锛�
+
+**鎵�鏈夋枃浠朵笂浼犲繀椤昏蛋 `yudao-module-system` 妯″潡鐨� Storage API + Attachment 涓棿琛ㄦ満鍒躲��**
+
+**绂佹鍦ㄤ换浣曚笟鍔℃ā鍧楄嚜琛岃璁℃枃浠朵笂浼犳柟妗堬紝鍖呮嫭浣嗕笉闄愪簬锛氭坊鍔� `file_url` 鍒椼�佹柊澧� upload 鎺ュ彛銆佹敞鍏� FileApi銆�**
+
+## 鏂囦欢涓庝笟鍔$殑鍏宠仈鏂瑰紡
+
+鏂囦欢涓庝笟鍔¤褰曠殑鍏宠仈**鍙兘閫氳繃 `system_storage_attachment` 涓棿琛�**锛屼笉鍏佽鍦ㄤ笟鍔¤〃涓坊鍔� `file_url`銆乣file_urls`銆乣attachment_url` 绛夊瓧绗︿覆瀛楁瀛樺偍鏂囦欢鍦板潃銆�
+
+鍏宠仈娴佺▼锛�
+1. 鍓嶇璋冪敤 `POST /system/storage-blob/upload` 涓婁紶鏂囦欢 鈫� 鑾峰緱 `blobId`
+2. 鍓嶇璋冪敤 `POST /system/storage-attachment/bind` 缁戝畾鏂囦欢鍒颁笟鍔¤褰曪紙浼犲叆 `recordType` + `recordId` + `blobItems`锛�
+3. 鍓嶇璋冪敤 `GET /system/storage-attachment/list` 鏌ヨ闄勪欢
+4. 鍓嶇璋冪敤 `DELETE /system/storage-attachment/delete` 鍒犻櫎闄勪欢
+
+## 姝g‘鎺ュ彛锛坰ystem 妯″潡锛�
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| POST | `/system/storage-blob/upload` | 涓婁紶鏂囦欢锛坄files` 鍙傛暟锛宮ultipart锛� |
+| POST | `/system/storage-blob/public-upload` | 鍏叡鏂囦欢涓婁紶锛堟案涔呮湁鏁堬級 |
+| GET | `/system/storage-blob/preview/{fileName}` | 鏂囦欢棰勮 |
+| GET | `/system/storage-blob/download/{fileName}` | 鏂囦欢涓嬭浇 |
+| GET | `/system/storage-attachment/list` | 鏌ヨ闄勪欢鍒楄〃 |
+| POST | `/system/storage-attachment/bind` | 缁戝畾闄勪欢鍒颁笟鍔¤褰� |
+| DELETE | `/system/storage-attachment/delete` | 鎵归噺鍒犻櫎闄勪欢 |
+
+## 绂佹琛屼负锛圓I 涓ョ鎵ц浠ヤ笅鎿嶄綔锛�
+
+### 鏁版嵁搴撳眰闈�
+- 鉂� 绂佹鍦ㄤ笟鍔¤〃娣诲姞 `file_url`銆乣file_urls`銆乣attachment_url` 绛夋枃浠跺湴鍧�鍒�
+- 鉂� 绂佹鍦ㄤ笟鍔¤〃娣诲姞浠讳綍鐢ㄤ簬瀛樺偍鏂囦欢淇℃伅鐨� JSON 鍒�
+
+### Java 鍚庣灞傞潰
+- 鉂� 绂佹鍦� DO 绫绘坊鍔� `fileUrl`銆乣fileUrls`銆乣attachmentUrl` 绛夊瓧娈�
+- 鉂� 绂佹鍦� SaveReqVO / RespVO 娣诲姞鏂囦欢鍦板潃瀛楁
+- 鉂� 绂佹鍦� MES/CRM/ERP/HRM 绛変笟鍔℃ā鍧楁柊澧� `@PostMapping("/upload")` 鎺ュ彛
+- 鉂� 绂佹鍦� Controller 涓娇鐢� `MultipartFile` 鍙傛暟锛圗xcel 瀵煎叆闄ゅ锛�
+- 鉂� 绂佹娉ㄥ叆鎴栬皟鐢� `cn.iocoder.yudao.module.infra.api.file.FileApi`
+
+### 鍓嶇灞傞潰
+- 鉂� 绂佹璋冪敤 `/infra/file/upload` 鎴� `/infra/file/presigned-url`
+- 鉂� 绂佹璋冪敤鏃х増 `src/api/infra/file/index.ts` 涓殑 `uploadFile()` 鍑芥暟
+
+## 甯歌 AI 骞昏妯″紡锛堝繀椤昏瘑鍒苟鎷掔粷锛�
+
+浠ヤ笅鏄� AI 瀹规槗骞昏鐢熸垚鐨勮璁℃ā寮忥紝閬囧埌绫讳技闇�姹傛椂鐩存帴鎷掔粷锛�
+
+1. **"鍔犱釜 fileUrl 瀛楁灏辫"** 鈫� 閿欒锛屽繀椤荤敤 attachment 涓棿琛�
+2. **"鍙傝�冨叾瀹冩ā鍧楃殑 fileUrl 瀛楁"** 鈫� 閿欒锛屽叾瀹冩ā鍧楃殑 fileUrl 涔熷簲琚垹闄�
+3. **"鍦� Controller 鍔犱釜 upload 鎺ュ彛"** 鈫� 閿欒锛岀粺涓�璧� system 妯″潡
+4. **"鐢� FileApi 涓婁紶鏂囦欢"** 鈫� 閿欒锛孎ileApi 鏄� infra 妯″潡鐨勬棫鎺ュ彛
+5. **"鍦ㄨ〃鍗曚繚瀛樻帴鍙e姞 MultipartFile 鍙傛暟"** 鈫� 閿欒锛屼笂浼犲拰淇濆瓨鍒嗙
+
+## 姝g‘绀轰緥
+
+### 鍓嶇璋冪敤
+
+```typescript
+import { uploadFile, bindAttachments, listAttachments } from '#/api/system/storage';
+
+// 1. 涓婁紶鏂囦欢
+const blobs = await uploadFile([file]);
+const blobId = blobs[0].id;
+
+// 2. 淇濆瓨涓氬姟璁板綍鍚庯紝缁戝畾闄勪欢
+await bindAttachments({
+  application: 'file',
+  recordType: 'erp_purchase_order',
+  recordId: savedRecord.id,
+  blobItems: [{ blobId }],
+});
+
+// 3. 鏌ヨ闄勪欢
+const attachments = await listAttachments({
+  recordType: 'erp_purchase_order',
+  recordId: savedRecord.id,
+});
+```
+
+### recordType 鍛藉悕瑙勮寖
+
+鏍煎紡锛歚{妯″潡鍓嶇紑}_{涓氬姟琛ㄥ悕}`
+
+| 妯″潡 | recordType |
+|------|------------|
+| ERP 閲囪喘璁㈠崟 | `erp_purchase_order` |
+| ERP 閲囪喘鐢宠 | `erp_purchase_request` |
+| ERP 閿�鍞鍗� | `erp_sale_order` |
+| ERP 鏀舵鍗� | `erp_finance_receipt` |
+| ERP 浠樻鍗� | `erp_finance_payment` |
+| HRM 璇峰亣 | `hrm_leave_application` |
+| HRM 绂昏亴 | `hrm_resignation_application` |
+| HRM 璋冨姩 | `hrm_transfer_application` |
+| MES 閲囪喘璁㈠崟 | `mes_purchase_order` |
+| MES 宸ュ崟 | `mes_pro_work_order` |
+| CRM 瀹㈡埛 | `crm_customer` |
+
+## AI 鑷煡娓呭崟
+
+鍦ㄥ疄鐜颁换浣曟枃浠朵笂浼犵浉鍏抽渶姹傚墠锛岄�愰」纭锛�
+
+- [ ] 鏄惁浣跨敤浜� `/system/storage-blob/upload` 涓婁紶锛�
+- [ ] 鏄惁浣跨敤浜� `/system/storage-attachment/bind` 鍏宠仈锛�
+- [ ] 鏄惁娌℃湁鍦ㄤ笟鍔¤〃涓坊鍔犳枃浠跺湴鍧�鍒楋紵
+- [ ] 鏄惁娌℃湁鍦� DO/VO 涓坊鍔犳枃浠跺湴鍧�瀛楁锛�
+- [ ] 鏄惁娌℃湁鍒涘缓鏂扮殑 upload Controller 鎺ュ彛锛�
+- [ ] 鏄惁娌℃湁浣跨敤 infra 妯″潡鐨� FileApi锛�
+
+浠ヤ笂 6 椤瑰叏閮ㄤ负"鏄�"鎵嶅彲缁х画銆�
+
+## 涓轰粈涔�
+
+- 瀛樺偍閰嶇疆锛堟湰鍦�/S3锛夊湪 system 妯″潡缁熶竴绠$悊
+- 闄勪欢缁戝畾鏈哄埗锛坰torage-attachment锛夋彁渚� `recordType + recordId` 鐨勬爣鍑嗗叧鑱旀柟寮忥紝鏀寔澶氭枃浠躲�佺敤閫斿垎绫�
+- infra 妯″潡鐨� `/infra/file/*` 鏄棫鐗堟帴鍙o紝瀛樺湪鏂囦欢涓庝笟鍔¤褰曟棤娉曞叧鑱旂殑闂
+- 涓氬姟琛ㄥ瓨鍌� file_url 瀛楃涓叉棤娉曟敮鎸佸鏂囦欢锛屼笖鏂囦欢涓庝笟鍔¤褰曚箣闂寸己涔忔爣鍑嗗寲鐨勫叧鑱旂鐞�
\ No newline at end of file
diff --git a/.agents/rules/frontend-doc-generation.md b/.agents/rules/frontend-doc-generation.md
new file mode 100644
index 0000000..c9e3663
--- /dev/null
+++ b/.agents/rules/frontend-doc-generation.md
@@ -0,0 +1,93 @@
+---
+name: frontend-doc-generation
+description: 鍓嶇鑱旇皟鏂规鐢熸垚瑙勫垯
+metadata:
+  type: feedback
+---
+
+# 鍓嶇鑱旇皟鏂规瑙勫垯
+
+## 瑙勫垯
+
+鍚庣鎺ュ彛鍙樻洿鏃讹紝**涓嶇敓鎴愬墠绔唬鐮�**锛屽彧鐢熸垚鍓嶇鑱旇皟鏂规鏂囨。锛岃緭鍑哄埌 `docs/` 鐩綍銆�
+
+## 绂佹鍐呭
+
+- 鉂� 绂佹鍐� Vue 妯℃澘浠g爜锛坄<el-table-column>`銆乣<el-form-item>` 绛夛級
+- 鉂� 绂佹鍐� JavaScript/TypeScript 浠g爜锛堟柟娉曘�佸嚱鏁般�侀�昏緫鍒ゆ柇绛夛級
+- 鉂� 绂佹鍐� CSS 鏍峰紡浠g爜
+- 鉂� 绂佹鍐欏墠绔粍浠朵娇鐢ㄧず渚�
+
+## 鑱旇皟鏂规鍐呭瑕佹眰
+
+鏂囨。搴斿彧鍖呭惈浠ヤ笅鍐呭锛�
+
+- **API 璇存槑**锛氳矾寰勩�佹柟娉曘�佽姹傚弬鏁般�佸搷搴旀牸寮�
+- **娑夊強鐨勫墠绔〉闈�**锛氬垪鍑洪渶瑕佷慨鏀圭殑椤甸潰鍚嶇О
+- **鏁版嵁甯﹀叆璇存槑**锛氶噸鐐瑰己璋冧俊鎭浣曚粠涓婁竴姝ュ甫鍏ワ紙濡傞噰璐鍗� -> 鍒拌揣閫氱煡 -> 閲囪喘鍏ュ簱锛�
+- **鎺ュ彛璋冪敤鏃跺簭**锛氳鏄庝綍鏃惰皟鐢ㄥ摢涓帴鍙h幏鍙栧叧鑱旀暟鎹�
+- **瀛楁灞曠ず瑙勫垯**锛氱敤琛ㄦ牸璇存槑瀛楁灞曠ず浣嶇疆鍜岃鏄庯紝涓嶅啓浠g爜
+- **涓氬姟瑙勫垯璇存槑**锛氱敤鏂囧瓧鎴栬〃鏍艰鏄庝笟鍔¢�昏緫
+- **娉ㄦ剰浜嬮」**锛氶渶瑕佸墠绔敞鎰忕殑杈圭晫鎯呭喌
+
+## 鏂囨。妯℃澘
+
+```markdown
+# 鍔熻兘鍚嶇О - 鍓嶇鑱旇皟鏂规
+
+## 娑夊強椤甸潰
+
+- 椤甸潰1
+- 椤甸潰2
+
+## 涓氬姟娴佺▼涓庢暟鎹甫鍏�
+
+1. 姝ラ1 -> 姝ラ2锛氬瓧娈礎銆佸瓧娈礏 浠庢楠�1鑷姩甯﹀叆
+2. 姝ラ2 -> 姝ラ3锛氬瓧娈礐 浠庢楠�2鑷姩甯﹀叆
+
+## API
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| POST | /xxx/xxx | 璇存槑 |
+
+**璇锋眰鍙傛暟锛�**
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| xxx | String | 鏄� | xxx |
+
+**鍝嶅簲瀛楁鏂板锛�**
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+|------|------|------|
+| xxx | String | xxx |
+
+**鍝嶅簲绀轰緥锛�**
+
+```json
+{
+  "code": 0,
+  "data": {}
+}
+```
+
+## 瀛楁灞曠ず瑙勫垯
+
+| 瀛楁 | 灞曠ず浣嶇疆 | 璇存槑 |
+|------|----------|------|
+| 瀛楁A | 鍒楄〃銆佽鎯� | 璇存槑 |
+| 瀛楁B | 璇︽儏 | 璇存槑 |
+
+## 涓氬姟瑙勫垯璇存槑
+
+| 鍦烘櫙 | 瑙勫垯 |
+|------|------|
+| 鍦烘櫙1 | 瑙勫垯璇存槑 |
+| 鍦烘櫙2 | 瑙勫垯璇存槑 |
+
+## 娉ㄦ剰浜嬮」
+
+- 娉ㄦ剰浜嬮」1
+- 娉ㄦ剰浜嬮」2
+```
\ No newline at end of file
diff --git a/.agents/rules/frontend-docs.md b/.agents/rules/frontend-docs.md
new file mode 100644
index 0000000..c6e349b
--- /dev/null
+++ b/.agents/rules/frontend-docs.md
@@ -0,0 +1,64 @@
+# 鎺ュ彛鍙樻洿鍓嶇鑱旇皟鏂规瑙勫垯
+
+## 瑙勫垯
+
+- 姣忔娑夊強鎺ュ彛鍙樻洿锛堟柊澧炴帴鍙c�佷慨鏀硅姹傚弬鏁般�佷慨鏀瑰搷搴旂粨鏋勶級鏃讹紝蹇呴』杈撳嚭涓�浠�**鍓嶇鑱旇皟鏂规**鍒� `docs/` 鐩綍銆�
+- **涓嶇敓鎴愬墠绔唬鐮�**锛屽彧鐢熸垚鑱旇皟鏂规鏂囨。锛屾寚瀵煎墠绔紑鍙戜汉鍛樺浣曞鎺ャ��
+- 鏂囨。浠� Markdown 鏍煎紡缂栧啓锛屾枃浠跺悕浣跨敤灏忓啓瀛楁瘝鍜屼笅鍒掔嚎锛屽 `docs/purchase_receipt_integration.md`銆�
+- 鏂囨。鍐呭閲嶇偣寮鸿皟**淇℃伅甯﹀叆**闂锛氬摢浜涙暟鎹粠涓婁竴姝ヨ嚜鍔ㄥ甫鍏ャ�佷綍鏃惰幏鍙栧叧鑱旀暟鎹�佸瓧娈靛浣曟槧灏勩��
+
+## 鏂囨。妯℃澘
+
+```markdown
+# 鍔熻兘鍚嶇О
+
+## 娑夊強椤甸潰
+
+- 椤甸潰1
+- 椤甸潰2
+
+## API
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| POST | /xxx/xxx | 璇存槑 |
+
+**璇锋眰鍙傛暟锛�**
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| xxx | String | 鏄� | xxx |
+
+**鍝嶅簲锛�** `{ "code": 200, "msg": "鎿嶄綔鎴愬姛" }`
+
+## 鍓嶇淇敼鐐�
+
+### 1. 鎸夐挳/寮圭獥/琛ㄦ牸绛�
+
+\`\`\`html
+<el-button>xxx</el-button>
+\`\`\`
+
+### 2. data 鏁版嵁
+
+\`\`\`js
+data() {
+  return {
+    xxx: '',
+  }
+}
+\`\`\`
+
+### 3. 鏂规硶
+
+\`\`\`js
+handleXxx() {
+  // ...
+}
+\`\`\`
+
+## 娉ㄦ剰浜嬮」
+
+- 娉ㄦ剰浜嬮」1
+- 娉ㄦ剰浜嬮」2
+```
\ No newline at end of file
diff --git a/.agents/rules/frontend-project.md b/.agents/rules/frontend-project.md
new file mode 100644
index 0000000..ee5100d
--- /dev/null
+++ b/.agents/rules/frontend-project.md
@@ -0,0 +1,16 @@
+# 鍓嶇椤圭洰瑙勫垯
+
+## 瑙勫垯
+
+- `mom-pro2-before` 鏄墠绔」鐩紝浣嶄簬鍚庣椤圭洰鏍圭洰褰曚笅锛坄D:\鐗涢┈\鍗楅�歕鍚庣\mom-pro2-after\mom-pro2-before`锛夈��
+- 鍙互鏌ョ湅鍓嶇浠g爜浣滀负鍙傝�冿紝甯姪鐞嗚В涓氬姟閫昏緫銆佽璁″悗绔柟妗堛��
+- **鏈粡鐢ㄦ埛鏄庣‘鍏佽锛岀姝慨鏀瑰墠绔」鐩腑鐨勪换浣曟枃浠躲��**
+
+## 浣跨敤鍦烘櫙
+
+| 鍏佽 | 绂佹 |
+|------|------|
+| 璇诲彇鍓嶇鏂囦欢浜嗚В鐜版湁瀹炵幇 | 淇敼鍓嶇浠g爜 |
+| 鍙傝�冨墠绔� API 璋冪敤鏂瑰紡璁捐鍚庣鎺ュ彛 | 鏂板鍓嶇缁勪欢/椤甸潰 |
+| 鍙傝�冨墠绔暟鎹粨鏋勭悊瑙d笟鍔� | 鍒犻櫎鍓嶇鏂囦欢 |
+| 鍦ㄥ墠绔」鐩腑鎼滅储/鏌ユ壘浠g爜 | 閲嶆瀯鍓嶇浠g爜 |
\ No newline at end of file
diff --git a/.agents/rules/handover-data-query.md b/.agents/rules/handover-data-query.md
new file mode 100644
index 0000000..8236ee2
--- /dev/null
+++ b/.agents/rules/handover-data-query.md
@@ -0,0 +1,103 @@
+# 鏁版嵁浜ゆ帴鏌ヨ瑙勫垯
+
+## 瑙勫垯
+
+鎵�鏈夋ā鍧楀湪鏌ヨ"鎴戠殑鏁版嵁"锛堟寜鐢ㄦ埛 ID 杩囨护鐨勪笟鍔℃暟鎹垪琛級鏃讹紝**蹇呴』璋冪敤 `HrmUserHandoverApi.expandUserIds()`** 鎵╁睍鐢ㄦ埛 ID 闆嗗悎锛岀‘淇濅氦鎺ヤ汉鑳芥煡鐪嬪凡绂昏亴浜ゆ帴浜虹殑涓氬姟鏁版嵁銆�
+
+## 鑳屾櫙
+
+褰撳憳宸ョ鑱屾椂锛屽叾涓氬姟鏁版嵁锛堝鎴枫�佸晢鏈恒�佸伐鍗曘�侀噰璐敵璇风瓑锛夐渶瑕佷氦鐢变氦鎺ヤ汉绠$悊銆傜郴缁熼�氳繃 `hrm_user_handover` 鏄犲皠琛ㄨ褰曚簡绂昏亴鐢ㄦ埛涓庝氦鎺ョ洰鏍囩敤鎴风殑鍏宠仈锛岃�岄潪鐩存帴淇敼涓氬姟鏁版嵁鐨勬墍鏈夎�呭瓧娈点��
+
+鏌ヨ鏃堕�氳繃 `expandUserIds` 灏嗕氦鎺ユ簮鐢ㄦ埛 ID 绾冲叆鏌ヨ鑼冨洿锛屼娇浜ゆ帴浜鸿兘鍚屾椂鐪嬪埌鑷繁鍜岀鑱屼汉鐨勬暟鎹��
+
+## 鏍稿績 API
+
+```java
+// 鎺ュ彛锛欻rmUserHandoverApi (yudao-module-hrm-api)
+public interface HrmUserHandoverApi {
+    Set<Long> expandUserIds(Set<Long> userIds);
+}
+```
+
+## 鍚勬ā鍧楅泦鎴愭柟寮�
+
+### 鍩烘湰鐢ㄦ硶
+
+```java
+// 娉ㄥ叆 API
+@Resource
+private HrmUserHandoverApi handoverApi;
+
+// 鍦ㄦ煡璇㈠墠鎵╁睍 userId
+public PageResult<XxxDO> getXxxPage(XxxPageReqVO reqVO) {
+    Long currentUserId = getCurrentUserId();
+    Set<Long> expandedUserIds = handoverApi.expandUserIds(Set.of(currentUserId));
+    // 鐢� expandedUserIds 鍋� IN 鏌ヨ
+    return mapper.selectPage(reqVO, new LambdaQueryWrapperX<XxxDO>()
+            .in(XxxDO::getOwnerUserId, expandedUserIds)
+            ...);
+}
+```
+
+### Mapper 灞傚啓娉�
+
+```java
+// 濡傛灉 userId 鏄姩鎬佷紶鍏ョ殑锛堝绠$悊鍛樺彲鏌ョ湅鎵�鏈変汉鐨勬暟鎹級锛屽厛鍋氬垽鏂細
+default PageResult<XxxDO> selectPage(XxxPageReqVO reqVO, Set<Long> userIds) {
+    return selectPage(reqVO, new LambdaQueryWrapperX<XxxDO>()
+            .inIfPresent(XxxDO::getOwnerUserId, CollUtil.isNotEmpty(userIds) ? userIds : null)
+            ...);
+}
+```
+
+## 鍚勬ā鍧楁秹鍙婄殑鏌ヨ鍦烘櫙
+
+| 妯″潡 | 鏌ヨ鍦烘櫙 | 娑夊強琛� | 鐢ㄦ埛瀛楁 |
+|------|----------|--------|----------|
+| CRM | 鎴戠殑瀹㈡埛 | `crm_customer` | `ownerUserId` |
+| CRM | 鎴戠殑绾跨储 | `crm_clue` | `ownerUserId` |
+| CRM | 鎴戠殑鑱旂郴浜� | `crm_contact` | `ownerUserId` |
+| CRM | 鎴戠殑鍚堝悓 | `crm_contract` | `ownerUserId` |
+| CRM | 鎴戠殑鍟嗘満 | `crm_business` | `ownerUserId` |
+| CRM | 鎴戠殑鍥炴 | `crm_receivable` | `ownerUserId` |
+| CRM | 鎴戠殑鍥炴璁″垝 | `crm_receivable_plan` | `ownerUserId` |
+| CRM | 鎴戠殑鎶ヤ环 | `crm_sale_quotation` | `ownerUserId` |
+| ERP | 鎴戠殑閲囪喘鐢宠 | `erp_purchase_request` | `requestUserId` |
+| ERP | 鎴戠殑閿�鍞鍗� | `erp_sale_order` | `saleUserId` |
+| ERP | 鎴戠殑浠樻鍗� | `erp_finance_payment` | `financeUserId` |
+| ERP | 鎴戠殑鏀舵鍗� | `erp_finance_receipt` | `financeUserId` |
+| MES | 鎴戠殑宸ュ崟/鎶ュ伐/璐ㄦ绛� | 鍚� MES 琛� | `userId` / `inspectorUserId` / `chargeUserId` 绛� |
+
+## expandUserIds 鍘熺悊
+
+```
+hrm_user_handover 琛ㄨ褰�:
+鈹屸攢鈹�鈹�鈹�鈹攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹� id 鈹� from_user_id 鈹� to_user_id 鈹� resignation_id鈹� handover_status 鈹�
+鈹溾攢鈹�鈹�鈹�鈹尖攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹尖攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹尖攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹尖攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹� 1  鈹� 100(绂昏亴浜�)  鈹� 101(浜ゆ帴浜�)鈹� 1             鈹� 20(宸插畬鎴�)       鈹�
+鈹斺攢鈹�鈹�鈹�鈹粹攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹粹攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹粹攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹粹攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+
+expandUserIds({101}) 鈫� {101, 100}
+鈫� 浜ゆ帴浜�101鏌ヨ鏃讹細WHERE owner_user_id IN (101, 100)
+鈫� 鍚屾椂鐪嬪埌鑷繁鐨勫拰绂昏亴浜虹殑鏁版嵁
+```
+
+## 娉ㄦ剰浜嬮」
+
+- `expandUserIds` 鍙墿灞�**宸插畬鎴愮殑浜ゆ帴璁板綍**锛坄handoverStatus = 20`锛�
+- 浼犲叆绌洪泦鍚堣繑鍥炵┖闆嗗悎
+- 鏌ヨ鎬ц兘锛氭槧灏勮〃鏁版嵁閲忔瀬灏忥紙浠呬负宸茬鑱屼汉鍛樻暟锛夛紝鍙斁蹇冨湪姣忔鏌ヨ鍓嶈皟鐢�
+- 濡傛灉鏌ヨ瑕佹眰涓ユ牸鍙湅鏈汉鏁版嵁锛堝涓汉璁剧疆椤碉級锛屽垯涓嶅簲璋冪敤 `expandUserIds`
+
+## Maven 渚濊禆
+
+闇�瑕佸湪妯″潡鐨� `pom.xml` 涓坊鍔犲 HRM API 鐨勪緷璧栵細
+
+```xml
+<dependency>
+    <groupId>cn.iocoder.boot</groupId>
+    <artifactId>yudao-module-hrm-api</artifactId>
+    <version>${revision}</version>
+</dependency>
+```
diff --git a/.agents/rules/powershell-commands.md b/.agents/rules/powershell-commands.md
new file mode 100644
index 0000000..04a9b69
--- /dev/null
+++ b/.agents/rules/powershell-commands.md
@@ -0,0 +1,35 @@
+# PowerShell 鍛戒护瑙勫垯
+
+## 瑙勫垯
+
+鐢变簬椤圭洰杩愯鍦� Windows 鐜涓嬶紝鐢ㄦ埛缁堢榛樿浣跨敤 PowerShell 鑰岄潪 bash銆傚湪鎻愪緵鍛戒护琛屾寚瀵兼椂锛屽繀椤讳娇鐢� PowerShell 璇硶銆�
+
+## 甯哥敤鍛戒护瀵圭収
+
+| 鎿嶄綔 | Bash | PowerShell |
+|------|------|-------------|
+| 鍒犻櫎鐩綍 | `rm -rf <path>` | `Remove-Item -Recurse -Force <path>` 鎴栫畝鍐� `ri -r -fo <path>` |
+| 澶嶅埗鏂囦欢 | `cp <src> <dest>` | `Copy-Item <src> <dest>` 鎴栫畝鍐� `cp <src> <dest>` |
+| 绉诲姩鏂囦欢 | `mv <src> <dest>` | `Move-Item <src> <dest>` 鎴栫畝鍐� `mv <src> <dest>` |
+| 鍒涘缓鐩綍 | `mkdir -p <path>` | `New-Item -ItemType Directory -Path <path>` 鎴栫畝鍐� `md <path>` |
+| 鏌ョ湅鏂囦欢 | `cat <file>` | `Get-Content <file>` 鎴栫畝鍐� `gc <file>` |
+| 鍒楀嚭鏂囦欢 | `ls` | `Get-ChildItem` 鎴栫畝鍐� `ls`/`dir` |
+| 鏌ユ壘鏂囦欢 | `find . -name "*.java"` | `Get-ChildItem -Recurse -Filter "*.java"` 鎴栫畝鍐� `gci -r -fi "*.java"` |
+| 鏌ユ壘鍐呭 | `grep -r "pattern" .` | `Select-String -Path "*.java" -Pattern "pattern"` 鎴栫畝鍐� `sls "pattern" *.java -r` |
+
+## 鍒犻櫎鐩綍绀轰緥
+
+```powershell
+# 鎺ㄨ崘锛氫娇鐢� Remove-Item 瀹屾暣鍛戒护
+Remove-Item -Recurse -Force yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/client
+
+# 绠�鍐欏舰寮�
+ri -r -fo yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/client
+```
+
+## 娉ㄦ剰浜嬮」
+
+- PowerShell 鍙傛暟浣跨敤 `-` 鍓嶇紑锛屽 `-Recurse`銆乣-Force`
+- 鍙傛暟鍙互绠�鍐欓瀛楁瘝锛屽 `-r`銆乣-fo`
+- 璺緞鍒嗛殧绗﹀湪 PowerShell 涓彲浠ヤ娇鐢� `/` 鎴� `\`锛屾帹鑽愪娇鐢� `/` 浠ヤ繚鎸佽法骞冲彴鍏煎
+- 閬垮厤 `-rf` 杩欐牱鐨� bash 椋庢牸鍙傛暟缁勫悎锛孭owerShell 涓嶆敮鎸�
\ No newline at end of file
diff --git a/.agents/rules/security-guardrails.md b/.agents/rules/security-guardrails.md
new file mode 100644
index 0000000..21348c2
--- /dev/null
+++ b/.agents/rules/security-guardrails.md
@@ -0,0 +1,37 @@
+# 瀹夊叏鎶ゆ爮
+
+## SQL 娉ㄥ叆闃叉姢
+
+- 姘歌繙涓嶈灏嗙敤鎴疯緭鍏ョ洿鎺ユ嫾鎺ュ埌 SQL 鏌ヨ涓��
+- 濮嬬粓浣跨敤鍙傛暟鍖栨煡璇㈡垨 ORM 鏂规硶銆�
+- 鍦ㄦ暟鎹簱鎿嶄綔鍓嶉獙璇佸拰娓呯悊鎵�鏈夎緭鍏ャ��
+
+## XSS 闃叉姢
+
+- 鍦� HTML 涓覆鏌撳墠杞箟鎵�鏈夌敤鎴风敓鎴愮殑鍐呭銆�
+- 浣跨敤妯℃澘鑷姩杞箟鍔熻兘銆�
+- 鍦ㄥ鎴风鍜屾湇鍔″櫒绔兘杩涜杈撳叆楠岃瘉鍜屾竻鐞嗐��
+
+## 瀵嗛挜绠$悊
+
+- 姘歌繙涓嶈鍦ㄦ簮浠g爜涓‖缂栫爜瀵嗛挜銆丄PI 瀵嗛挜鎴栧瘑鐮併��
+- 浣跨敤鐜鍙橀噺鎴栧畨鍏ㄤ繚闄╁簱瀛樺偍鏁忔劅鏁版嵁銆�
+- 瀹氭湡杞崲瀵嗛挜锛岄伩鍏嶅湪鏃ュ織涓褰曞畠浠��
+
+## 杈撳叆楠岃瘉
+
+- 鍦ㄧ郴缁熻竟鐣屽楠岃瘉鎵�鏈夎緭鍏ャ��
+- 浣跨敤鐧藉悕鍗曡�岄潪榛戝悕鍗曡繘琛岄獙璇併��
+- 鍦ㄥ鐞嗕笂浼犲墠妫�鏌ユ枃浠剁被鍨嬪拰澶у皬銆�
+
+## 閿欒澶勭悊
+
+- 涓嶈鍦ㄩ敊璇秷鎭腑鏆撮湶鏁忔劅淇℃伅銆�
+- 鍦ㄥ唴閮ㄨ褰曡缁嗛敊璇紝鍚戠敤鎴疯繑鍥為�氱敤娑堟伅銆�
+- 澶勭悊鎵�鏈夊紓甯镐互闃叉淇℃伅娉勯湶銆�
+
+## 渚濊禆绠$悊
+
+- 淇濇寔渚濊禆椤规洿鏂般��
+- 瀹¤渚濊禆椤逛腑鐨勫凡鐭ユ紡娲炪��
+- 鍥哄畾鐗堟湰浠ラ伩鍏嶆剰澶栫殑鐮村潖鎬у彉鏇淬��
diff --git a/.agents/rules/sql-docs-sync.md b/.agents/rules/sql-docs-sync.md
new file mode 100644
index 0000000..d6a73cc
--- /dev/null
+++ b/.agents/rules/sql-docs-sync.md
@@ -0,0 +1,12 @@
+---
+description: Automatically sync new SQL files to docs/sql and update the index
+---
+
+# SQL Files Management Rule
+
+**CRITICAL RULE**: Whenever you create or add a new SQL file (e.g. database migrations, init scripts) in this project (such as in `sql/mysql/` or anywhere else), you MUST:
+
+1. **Copy/Create a duplicate** of that SQL file in the `docs/sql/` directory.
+2. **Update the SQL Index**: Record the newly added SQL file in `docs/sql/README.md` (create the README file if it does not exist) with a brief description of what the SQL file does.
+
+Always remember this when you are generating new SQL scripts to maintain the project's documentation consistency.
diff --git a/.agents/rules/sql-script.md b/.agents/rules/sql-script.md
new file mode 100644
index 0000000..19b1ccb
--- /dev/null
+++ b/.agents/rules/sql-script.md
@@ -0,0 +1,6 @@
+# SQL 鑴氭湰瑙勮寖
+
+## 瑙勫垯
+
+- SQL 鑴氭湰涓笉瑕佸寘鍚� tenant_id 瀛楁锛岄」鐩笉浣跨敤澶氱鎴锋ā寮忋��
+- INSERT 璇彞鍙寘鍚繀瑕佺殑涓氬姟瀛楁锛屼笉闇�瑕� tenant_id銆�
\ No newline at end of file
diff --git a/.agents/rules/sql-syntax.md b/.agents/rules/sql-syntax.md
new file mode 100644
index 0000000..74e1b19
--- /dev/null
+++ b/.agents/rules/sql-syntax.md
@@ -0,0 +1,40 @@
+# SQL 璇硶瑙勮寖
+
+## 瑙勫垯
+
+- MySQL `ALTER TABLE ADD COLUMN` 涓嶆敮鎸� `IF NOT EXISTS` 璇硶锛屽嵆浣� MySQL 8.0+ 涔熶笉鏀寔銆�
+- 娣诲姞瀛楁鍓嶉渶瑕佸厛妫�鏌ュ瓧娈垫槸鍚﹀瓨鍦紝鎴栫洿鎺ユ墽琛屽苟蹇界暐"瀛楁宸插瓨鍦�"閿欒銆�
+
+## 姝g‘绀轰緥
+
+```sql
+-- 姝g‘锛氱洿鎺ユ坊鍔犲瓧娈�
+ALTER TABLE mes_wm_sn ADD COLUMN uuid VARCHAR(64) COMMENT '鎵规UUID' AFTER id;
+
+-- 姝g‘锛氬厛妫�鏌ュ啀娣诲姞锛堝吋瀹硅剼鏈級
+SET @exists = (SELECT COUNT(*) FROM information_schema.columns 
+               WHERE table_schema = DATABASE() AND table_name = 'mes_wm_sn' AND column_name = 'uuid');
+SET @sql = IF(@exists = 0, 
+              'ALTER TABLE mes_wm_sn ADD COLUMN uuid VARCHAR(64) COMMENT ''鎵规UUID'' AFTER id', 
+              'SELECT 1');
+PREPARE stmt FROM @sql;
+EXECUTE stmt;
+DEALLOCATE PREPARE stmt;
+```
+
+## 閿欒绀轰緥
+
+```sql
+-- 閿欒锛欰DD COLUMN 涓嶆敮鎸� IF NOT EXISTS
+ALTER TABLE mes_wm_sn ADD COLUMN IF NOT EXISTS uuid VARCHAR(64) COMMENT '鎵规UUID' AFTER id;
+```
+
+## IF NOT EXISTS 鏀寔鍦烘櫙
+
+| 璇彞 | 鏄惁鏀寔 |
+|------|---------|
+| CREATE TABLE IF NOT EXISTS | 鉁� 鏀寔 |
+| CREATE INDEX IF NOT EXISTS | 鉁� 鏀寔锛圡ySQL 8.0+锛� |
+| ALTER TABLE ADD COLUMN IF NOT EXISTS | 鉂� 涓嶆敮鎸� |
+| ALTER TABLE ADD INDEX IF NOT EXISTS | 鉁� 鏀寔锛圡ySQL 8.0+锛� |
+| ALTER TABLE ADD CONSTRAINT IF NOT EXISTS | 鉂� 涓嶆敮鎸� |
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index a140560..d2323d7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -57,4 +57,7 @@
 ### Claude Code ###
 .claude/settings.local.json
 .claude/worktrees/
-.claude/scheduled_tasks.json
\ No newline at end of file
+.claude/scheduled_tasks.json
+
+graphify-out/
+.agents/
\ No newline at end of file
diff --git a/docs/projectSql/ruoyi-vue-pro.sql b/docs/projectSql/ruoyi-vue-pro.sql
index ccf920f..1a34cf4 100644
--- a/docs/projectSql/ruoyi-vue-pro.sql
+++ b/docs/projectSql/ruoyi-vue-pro.sql
@@ -7933,40 +7933,41 @@
 -- Table structure for mes_pro_feedback
 -- ----------------------------
 DROP TABLE IF EXISTS `mes_pro_feedback`;
-CREATE TABLE `mes_pro_feedback`  (
+CREATE TABLE `mes_pro_feedback` (
   `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
-  `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '鎶ュ伐鍗曠紪鍙�',
-  `type` int NULL DEFAULT NULL COMMENT '鎶ュ伐绫诲瀷',
-  `channel` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '鎶ュ伐閫斿緞',
-  `feedback_time` datetime NULL DEFAULT NULL COMMENT '鎶ュ伐鏃堕棿',
-  `workstation_id` bigint NULL DEFAULT NULL COMMENT '宸ヤ綔绔欑紪鍙�',
-  `route_id` bigint NULL DEFAULT NULL COMMENT '宸ヨ壓璺嚎缂栧彿',
-  `process_id` bigint NULL DEFAULT NULL COMMENT '宸ュ簭缂栧彿',
-  `work_order_id` bigint NULL DEFAULT NULL COMMENT '鐢熶骇宸ュ崟缂栧彿',
-  `task_id` bigint NULL DEFAULT NULL COMMENT '鐢熶骇浠诲姟缂栧彿',
-  `item_id` bigint NULL DEFAULT NULL COMMENT '浜у搧鐗╂枡缂栧彿',
-  `expire_date` datetime NULL DEFAULT NULL COMMENT '杩囨湡鏃ユ湡',
-  `lot_number` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '鐢熶骇鎵瑰彿',
-  `scheduled_quantity` decimal(24, 6) NULL DEFAULT NULL COMMENT '鎺掍骇鏁伴噺',
-  `feedback_quantity` decimal(24, 6) NULL DEFAULT NULL COMMENT '鏈鎶ュ伐鏁伴噺',
-  `qualified_quantity` decimal(24, 6) NULL DEFAULT NULL COMMENT '鍚堟牸鍝佹暟閲�',
-  `unqualified_quantity` decimal(24, 6) NULL DEFAULT NULL COMMENT '涓嶈壇鍝佹暟閲�',
-  `uncheck_quantity` decimal(24, 6) NULL DEFAULT NULL COMMENT '寰呮娴嬫暟閲�',
-  `labor_scrap_quantity` decimal(24, 6) NULL DEFAULT NULL COMMENT '宸ュ簾鏁伴噺',
-  `material_scrap_quantity` decimal(24, 6) NULL DEFAULT NULL COMMENT '鏂欏簾鏁伴噺',
-  `other_scrap_quantity` decimal(24, 6) NULL DEFAULT NULL COMMENT '鍏朵粬搴熷搧鏁伴噺',
-  `feedback_user_id` bigint NULL DEFAULT NULL COMMENT '鎶ュ伐鐢ㄦ埛缂栧彿',
-  `approve_user_id` bigint NULL DEFAULT NULL COMMENT '瀹℃牳鐢ㄦ埛缂栧彿',
-  `status` 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 '鍒涘缓鑰�',
+  `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎶ュ伐鍗曠紪鍙�',
+  `type` int DEFAULT NULL COMMENT '鎶ュ伐绫诲瀷',
+  `channel` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎶ュ伐閫斿緞',
+  `feedback_time` datetime DEFAULT NULL COMMENT '鎶ュ伐鏃堕棿',
+  `workstation_id` bigint DEFAULT NULL COMMENT '宸ヤ綔绔欑紪鍙�',
+  `route_id` bigint DEFAULT NULL COMMENT '宸ヨ壓璺嚎缂栧彿',
+  `process_id` bigint DEFAULT NULL COMMENT '宸ュ簭缂栧彿',
+  `work_order_id` bigint DEFAULT NULL COMMENT '鐢熶骇宸ュ崟缂栧彿',
+  `task_id` bigint DEFAULT NULL COMMENT '鐢熶骇浠诲姟缂栧彿',
+  `item_id` bigint DEFAULT NULL COMMENT '浜у搧鐗╂枡缂栧彿',
+  `expire_date` datetime DEFAULT NULL COMMENT '杩囨湡鏃ユ湡',
+  `lot_number` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐢熶骇鎵瑰彿',
+  `scheduled_quantity` decimal(24,6) DEFAULT NULL COMMENT '鎺掍骇鏁伴噺',
+  `feedback_quantity` decimal(24,6) DEFAULT NULL COMMENT '鏈鎶ュ伐鏁伴噺',
+  `qualified_quantity` decimal(24,6) DEFAULT NULL COMMENT '鍚堟牸鍝佹暟閲�',
+  `unqualified_quantity` decimal(24,6) DEFAULT NULL COMMENT '涓嶈壇鍝佹暟閲�',
+  `uncheck_quantity` decimal(24,6) DEFAULT NULL COMMENT '寰呮娴嬫暟閲�',
+  `labor_scrap_quantity` decimal(24,6) DEFAULT NULL COMMENT '宸ュ簾鏁伴噺',
+  `material_scrap_quantity` decimal(24,6) DEFAULT NULL COMMENT '鏂欏簾鏁伴噺',
+  `other_scrap_quantity` decimal(24,6) DEFAULT NULL COMMENT '鍏朵粬搴熷搧鏁伴噺',
+  `feedback_user_id` bigint DEFAULT NULL COMMENT '鎶ュ伐鐢ㄦ埛缂栧彿',
+  `approve_user_id` bigint DEFAULT NULL COMMENT '瀹℃牳鐢ㄦ埛缂栧彿',
+  `status` int DEFAULT NULL COMMENT '鐘舵��',
+  `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci 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 NULL DEFAULT '' 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
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'MES 鐢熶骇鎶ュ伐' ROW_FORMAT = Dynamic;
-
+  `process_instance_id` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'BPM 娴佺▼瀹炰緥缂栧彿',
+  `process_definition_key` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'BPM 娴佺▼瀹氫箟 Key',
+  PRIMARY KEY (`id`) USING BTREE,
+) ENGINE=InnoDB AUTO_INCREMENT=79 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐢熶骇鎶ュ伐';
 -- ----------------------------
 -- Records of mes_pro_feedback
 -- ----------------------------
@@ -8220,36 +8221,40 @@
 -- Table structure for mes_pro_work_order
 -- ----------------------------
 DROP TABLE IF EXISTS `mes_pro_work_order`;
-CREATE TABLE `mes_pro_work_order`  (
+CREATE TABLE `mes_pro_work_order` (
   `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
-  `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '宸ュ崟缂栫爜',
-  `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '宸ュ崟鍚嶇О',
-  `type` int NULL DEFAULT NULL COMMENT '宸ュ崟绫诲瀷',
-  `order_source_type` int NULL DEFAULT NULL COMMENT '鏉ユ簮绫诲瀷',
-  `order_source_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁缂栧彿',
-  `product_id` bigint NULL DEFAULT NULL COMMENT '浜у搧缂栧彿',
-  `quantity` decimal(24, 6) NULL DEFAULT NULL COMMENT '鐢熶骇鏁伴噺',
-  `quantity_produced` decimal(24, 6) NULL DEFAULT NULL COMMENT '宸茬敓浜ф暟閲�',
-  `quantity_changed` decimal(24, 6) NULL DEFAULT NULL COMMENT '璋冩暣鏁伴噺',
-  `quantity_scheduled` decimal(24, 6) NULL DEFAULT NULL COMMENT '宸叉帓浜ф暟閲�',
-  `client_id` bigint NULL DEFAULT NULL COMMENT '瀹㈡埛缂栧彿',
-  `vendor_id` bigint NULL DEFAULT NULL COMMENT '渚涘簲鍟嗙紪鍙�',
-  `batch_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '鎵规鍙�',
-  `request_date` datetime NULL DEFAULT NULL COMMENT '闇�姹傛棩鏈�',
-  `parent_id` bigint NULL DEFAULT NULL COMMENT '鐖跺伐鍗曠紪鍙�',
-  `finish_date` datetime NULL DEFAULT NULL COMMENT '瀹屾垚鏃堕棿',
-  `cancel_date` datetime NULL DEFAULT NULL COMMENT '鍙栨秷鏃堕棿',
-  `status` int NULL DEFAULT NULL COMMENT '宸ュ崟鐘舵��',
-  `process_instance_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'BPM 娴佺▼瀹炰緥缂栧彿',
-  `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 '鍒涘缓鑰�',
+  `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '宸ュ崟缂栫爜',
+  `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '宸ュ崟鍚嶇О',
+  `type` int DEFAULT NULL COMMENT '宸ュ崟绫诲瀷',
+  `order_source_type` int DEFAULT NULL COMMENT '鏉ユ簮绫诲瀷',
+  `order_source_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁缂栧彿',
+  `product_id` bigint DEFAULT NULL COMMENT '浜у搧缂栧彿',
+  `quantity` decimal(24,6) DEFAULT NULL COMMENT '鐢熶骇鏁伴噺',
+  `quantity_produced` decimal(24,6) DEFAULT NULL COMMENT '宸茬敓浜ф暟閲�',
+  `quantity_changed` decimal(24,6) DEFAULT NULL COMMENT '璋冩暣鏁伴噺',
+  `quantity_scheduled` decimal(24,6) DEFAULT NULL COMMENT '宸叉帓浜ф暟閲�',
+  `client_id` bigint DEFAULT NULL COMMENT '瀹㈡埛缂栧彿',
+  `vendor_id` bigint DEFAULT NULL COMMENT '渚涘簲鍟嗙紪鍙�',
+  `batch_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎵规鍙�',
+  `route_id` bigint DEFAULT NULL COMMENT '宸ヨ壓璺嚎缂栧彿',
+  `auto_finish_flag` tinyint(1) DEFAULT '1' COMMENT '鏄惁鑷姩瀹屾垚',
+  `request_date` datetime DEFAULT NULL COMMENT '闇�姹傛棩鏈�',
+  `parent_id` bigint DEFAULT NULL COMMENT '鐖跺伐鍗曠紪鍙�',
+  `finish_date` datetime DEFAULT NULL COMMENT '瀹屾垚鏃堕棿',
+  `cancel_date` datetime DEFAULT NULL COMMENT '鍙栨秷鏃堕棿',
+  `status` int DEFAULT NULL COMMENT '宸ュ崟鐘舵��',
+  `process_instance_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'BPM 娴佺▼瀹炰緥缂栧彿',
+  `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci 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 NULL DEFAULT '' 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 '鏄惁鍒犻櫎',
+  `is_feedback_approve` tinyint(1) DEFAULT NULL COMMENT '鏄惁寮�鍚姤宸ュ鎵� (1: 寮�鍚�, 0/NULL: 鍏抽棴)',
+  `process_definition_key` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'BPM 娴佺▼瀹氫箟 Key',
+  `feedback_role` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎶ュ伐瑙掕壊 (澶氫釜瑙掕壊浠ラ�楀彿鍒嗛殧)',
   PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'MES 鐢熶骇宸ュ崟' ROW_FORMAT = Dynamic;
-
+) ENGINE=InnoDB AUTO_INCREMENT=62 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐢熶骇宸ュ崟';
 -- ----------------------------
 -- Records of mes_pro_work_order
 -- ----------------------------
diff --git a/docs/sql/README.md b/docs/sql/README.md
new file mode 100644
index 0000000..51895b5
--- /dev/null
+++ b/docs/sql/README.md
@@ -0,0 +1,5 @@
+# SQL 鑴氭湰绱㈠紩
+
+鏈」鐩寘鍚殑 SQL 鑴氭湰姹囨�诲涓嬶細
+
+- [mes_pro_task_assignee.sql](mes_pro_task_assignee.sql): 澧炲姞鐢熶骇浠诲姟鎶ュ伐浜哄憳鍏宠仈琛紝鐢ㄤ簬澶氫汉鍛樻姤宸ュ垎閰嶃��
diff --git a/docs/sql/mes_pro_task_assignee.sql b/docs/sql/mes_pro_task_assignee.sql
new file mode 100644
index 0000000..389cb16
--- /dev/null
+++ b/docs/sql/mes_pro_task_assignee.sql
@@ -0,0 +1,14 @@
+CREATE TABLE `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 '鏄惁鍒犻櫎',
+  `tenant_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '绉熸埛缂栧彿',
+  PRIMARY KEY (`id`),
+  KEY `idx_task_id` (`task_id`),
+  KEY `idx_user_id` (`user_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='鐢熶骇浠诲姟鎸囧畾鎶ュ伐浜哄憳琛�';
diff --git a/sql/mysql/mes_pro_task_assignee.sql b/sql/mysql/mes_pro_task_assignee.sql
new file mode 100644
index 0000000..389cb16
--- /dev/null
+++ b/sql/mysql/mes_pro_task_assignee.sql
@@ -0,0 +1,14 @@
+CREATE TABLE `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 '鏄惁鍒犻櫎',
+  `tenant_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '绉熸埛缂栧彿',
+  PRIMARY KEY (`id`),
+  KEY `idx_task_id` (`task_id`),
+  KEY `idx_user_id` (`user_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='鐢熶骇浠诲姟鎸囧畾鎶ュ伐浜哄憳琛�';
diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/LoginUser.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/LoginUser.java
index a07bd78..71d656f 100644
--- a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/LoginUser.java
+++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/LoginUser.java
@@ -20,6 +20,7 @@
 
     public static final String INFO_KEY_NICKNAME = "nickname";
     public static final String INFO_KEY_DEPT_ID = "deptId";
+    public static final String INFO_KEY_ROLE_CODES = "roleCodes";
 
     /**
      * 鐢ㄦ埛缂栧彿
diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/util/SecurityFrameworkUtils.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/util/SecurityFrameworkUtils.java
index ede1ad7..a8f9fc0 100644
--- a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/util/SecurityFrameworkUtils.java
+++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/util/SecurityFrameworkUtils.java
@@ -114,6 +114,29 @@
     }
 
     /**
+     * 鑾峰緱褰撳墠鐢ㄦ埛鐨勮鑹茬紪鐮佸垪琛紝浠庝笂涓嬫枃涓�
+     *
+     * @return 瑙掕壊缂栫爜鍒楄〃
+     */
+    public static java.util.List<String> getLoginUserRoleCodeList() {
+        LoginUser loginUser = getLoginUser();
+        if (loginUser == null || loginUser.getInfo() == null) {
+            return Collections.emptyList();
+        }
+        String roleCodes = loginUser.getInfo().get(LoginUser.INFO_KEY_ROLE_CODES);
+        return StrUtil.isNotEmpty(roleCodes) ? StrUtil.split(roleCodes, ",") : Collections.emptyList();
+    }
+
+    /**
+     * 鍒ゆ柇褰撳墠鐢ㄦ埛鏄惁涓鸿秴绾х鐞嗗憳
+     *
+     * @return 鏄惁涓鸿秴绾х鐞嗗憳
+     */
+    public static boolean isSuperAdmin() {
+        return getLoginUserRoleCodeList().contains("super_admin");
+    }
+
+    /**
      * 璁剧疆褰撳墠鐢ㄦ埛
      *
      * @param loginUser 鐧诲綍鐢ㄦ埛
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 db782f7..8a78405 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
@@ -17,6 +17,7 @@
 import cn.iocoder.yudao.module.mes.controller.admin.pro.feedback.vo.MesProFeedbackQuickCreateRespVO;
 import cn.iocoder.yudao.module.mes.controller.admin.pro.feedback.vo.MesProFeedbackRespVO;
 import cn.iocoder.yudao.module.mes.controller.admin.pro.feedback.vo.MesProFeedbackSaveReqVO;
+import cn.iocoder.yudao.module.mes.controller.admin.pro.feedback.vo.MesProFeedbackSubmitReqVO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.md.workstation.MesMdWorkstationDO;
@@ -176,10 +177,9 @@
 
     @PutMapping("/submit")
     @Operation(summary = "鎻愪氦鎶ュ伐")
-    @Parameter(name = "id", description = "缂栧彿", required = true)
     @PreAuthorize("@ss.hasPermission('mes:pro-feedback:update')")
-    public CommonResult<Boolean> submitFeedback(@RequestParam("id") Long id) {
-        feedbackService.submitFeedback(id);
+    public CommonResult<Boolean> submitFeedback(@Valid @RequestBody MesProFeedbackSubmitReqVO reqVO) {
+        feedbackService.submitFeedback(reqVO);
         return success(true);
     }
 
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 b86dc24..4df6e71 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
@@ -169,4 +169,12 @@
     @ExcelProperty("鍒涘缓鏃堕棿")
     private LocalDateTime createTime;
 
+    @Schema(description = "BPM 娴佺▼瀹炰緥缂栧彿")
+    @ExcelProperty("BPM 娴佺▼瀹炰緥缂栧彿")
+    private String processInstanceId;
+
+    @Schema(description = "BPM 娴佺▼瀹氫箟 Key")
+    @ExcelProperty("BPM 娴佺▼瀹氫箟 Key")
+    private String processDefinitionKey;
+
 }
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/feedback/vo/MesProFeedbackSaveReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/feedback/vo/MesProFeedbackSaveReqVO.java
index 35a5f3c..2deb3fd 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/feedback/vo/MesProFeedbackSaveReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/feedback/vo/MesProFeedbackSaveReqVO.java
@@ -87,4 +87,10 @@
     @Schema(description = "澶囨敞", example = "澶囨敞")
     private String remark;
 
+    @Schema(description = "BPM 娴佺▼瀹炰緥缂栧彿")
+    private String processInstanceId;
+
+    @Schema(description = "BPM 娴佺▼瀹氫箟 Key")
+    private String processDefinitionKey;
+
     }
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/feedback/vo/MesProFeedbackSubmitReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/feedback/vo/MesProFeedbackSubmitReqVO.java
new file mode 100644
index 0000000..88b6f76
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/feedback/vo/MesProFeedbackSubmitReqVO.java
@@ -0,0 +1,50 @@
+package cn.iocoder.yudao.module.mes.controller.admin.pro.feedback.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "绠$悊鍚庡彴 - MES 鐢熶骇鎶ュ伐鎻愪氦 Request VO")
+@Data
+public class MesProFeedbackSubmitReqVO {
+
+    @Schema(description = "鎶ュ伐鍗曠紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+    @NotNull(message = "鎶ュ伐鍗旾D涓嶈兘涓虹┖")
+    private Long id;
+
+    @Schema(description = "鐢熶骇鏃ユ湡")
+    private LocalDateTime produceDate;
+
+    @Schema(description = "杩囨湡鏃ユ湡")
+    private LocalDateTime expireDate;
+
+    @Schema(description = "鍏ュ簱鏃ユ湡")
+    private LocalDateTime receiptDate;
+
+    @Schema(description = "渚涘簲鍟咺D")
+    private Long vendorId;
+
+    @Schema(description = "瀹㈡埛ID")
+    private Long clientId;
+
+    @Schema(description = "閲囪喘璁㈠崟缂栧彿")
+    private String purchaseOrderCode;
+
+    @Schema(description = "閿�鍞鍗曠紪鍙�")
+    private String salesOrderCode;
+
+    @Schema(description = "宸ュ叿ID")
+    private Long toolId;
+
+    @Schema(description = "妯″叿ID")
+    private Long moldId;
+
+    @Schema(description = "鐢熶骇鎵瑰彿")
+    private String lotNumber;
+
+    @Schema(description = "璐ㄩ噺鐘舵��")
+    private Integer qualityStatus;
+
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/task/MesProTaskController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/task/MesProTaskController.java
index ff141d7..7557506 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/task/MesProTaskController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/task/MesProTaskController.java
@@ -94,6 +94,8 @@
     private MesProTaskPauseRecordMapper pauseRecordMapper;
     @Resource
     private AdminUserApi adminUserApi;
+    @Resource
+    private cn.iocoder.yudao.module.system.api.permission.PermissionApi permissionApi;
 
     @PostMapping("/create")
     @Operation(summary = "鍒涘缓鐢熶骇浠诲姟")
@@ -190,6 +192,11 @@
     @Operation(summary = "鑾峰緱寰呮姤宸ュ彴璐﹀垎椤�", description = "宸叉帓浜т笖浠嶆湁寰呮姤宸ユ暟閲忕殑浠诲姟锛堢姸鎬�=杩涜涓級")
     @PreAuthorize("@ss.hasPermission('mes:pro-task:query')")
     public CommonResult<PageResult<MesProTaskRespVO>> getPendingFeedbackPage(@Valid MesProTaskPageReqVO pageReqVO) {
+        Long loginUserId = cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId();
+        // 濡傛灉褰撳墠鐧诲綍浜轰笉鏄秴绾х鐞嗗憳锛屽垯浠呮煡璇㈠垎閰嶇粰鑷繁鐨勭敓浜у伐鍗�
+        if (loginUserId != null && !permissionApi.hasAnyRoles(loginUserId, cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum.SUPER_ADMIN.getCode())) {
+            pageReqVO.setAssigneeUserId(loginUserId);
+        }
         PageResult<MesProTaskDO> pageResult = taskService.getPendingFeedbackPage(pageReqVO);
         List<MesProTaskRespVO> respVOList = buildTaskRespVOList(pageResult.getList());
         
@@ -349,6 +356,15 @@
                 inTransitMap.merge(fb.getTaskId(), fbQty, BigDecimal::add);
             }
         }
+
+        // 鏌ヨ鎸囨淳鎶ュ伐浜哄憳
+        Set<Long> taskIds = convertSet(list, MesProTaskDO::getId);
+        Map<Long, List<cn.iocoder.yudao.module.mes.dal.dataobject.pro.task.MesProTaskAssigneeDO>> assigneeMap = taskService.getTaskAssigneeMap(taskIds);
+        Set<Long> allAssigneeUserIds = new HashSet<>();
+        assigneeMap.values().forEach(assignees -> 
+            assignees.forEach(assignee -> allAssigneeUserIds.add(assignee.getUserId())));
+        Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(allAssigneeUserIds);
+
         // 鎷兼帴 VO
         return convertList(list, task -> {
             MesProTaskRespVO vo = BeanUtils.toBean(task, MesProTaskRespVO.class);
@@ -379,6 +395,22 @@
                     findAndThen(processCheckMap, task.getProcessId(), vo::setCheckFlag));
             findAndThen(routeProcessBackflushFlagMap, task.getRouteId(), processBackflushMap ->
                     findAndThen(processBackflushMap, task.getProcessId(), vo::setBackflushFlag));
+
+            // 璁剧疆鎸囨淳鎶ュ伐浜哄憳
+            List<cn.iocoder.yudao.module.mes.dal.dataobject.pro.task.MesProTaskAssigneeDO> assignees = assigneeMap.get(task.getId());
+            if (CollUtil.isNotEmpty(assignees)) {
+                List<Long> assigneeUserIds = convertList(assignees, cn.iocoder.yudao.module.mes.dal.dataobject.pro.task.MesProTaskAssigneeDO::getUserId);
+                vo.setAssigneeUserIds(assigneeUserIds);
+                List<String> assigneeUserNames = new ArrayList<>();
+                for (Long userId : assigneeUserIds) {
+                    AdminUserRespDTO user = userMap.get(userId);
+                    if (user != null && user.getNickname() != null) {
+                        assigneeUserNames.add(user.getNickname());
+                    }
+                }
+                vo.setAssigneeUserNames(assigneeUserNames);
+            }
+
             return vo;
         });
     }
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/task/vo/MesProTaskPageReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/task/vo/MesProTaskPageReqVO.java
index 28b4c06..7720d4f 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/task/vo/MesProTaskPageReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/task/vo/MesProTaskPageReqVO.java
@@ -49,4 +49,7 @@
     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
     private LocalDateTime[] createTime;
 
+    @Schema(description = "澶勭悊浜虹敤鎴风紪鍙�", example = "1024")
+    private Long assigneeUserId;
+
 }
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/task/vo/MesProTaskRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/task/vo/MesProTaskRespVO.java
index f4c0dd1..17f18e6 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/task/vo/MesProTaskRespVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/task/vo/MesProTaskRespVO.java
@@ -134,4 +134,12 @@
     @Schema(description = "鍋滃伐鍘嗗彶璁板綍")
     private List<MesProTaskPauseRecordRespVO> pauseRecords;
 
+    @Schema(description = "鎸囧畾鎶ュ伐浜哄憳 ID 闆嗗悎")
+    private List<Long> assigneeUserIds;
+
+    @Schema(description = "鎸囧畾鎶ュ伐浜哄憳濮撳悕闆嗗悎")
+    private List<String> assigneeUserNames;
+
+    @Schema(description = "鏄惁鎶ュ伐瀹℃壒")
+    private Boolean feedbackApprove;
 }
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/task/vo/MesProTaskSaveReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/task/vo/MesProTaskSaveReqVO.java
index db9f5e2..82cdb6b 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/task/vo/MesProTaskSaveReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/task/vo/MesProTaskSaveReqVO.java
@@ -51,4 +51,7 @@
     @Schema(description = "澶囨敞", example = "澶囨敞")
     private String remark;
 
+    @Schema(description = "鎸囧畾鎶ュ伐浜哄憳 ID 闆嗗悎")
+    private java.util.List<Long> assigneeUserIds;
+
 }
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkOrderController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkOrderController.java
index b6233cd..37ab219 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkOrderController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkOrderController.java
@@ -113,6 +113,13 @@
         return success(new PageResult<>(buildWorkOrderRespVOList(pageResult.getList()), pageResult.getTotal()));
     }
 
+    @GetMapping("/approve-process-list")
+    @Operation(summary = "鑾峰彇瀹℃壒鎶ュ伐鐨勬祦绋嬪畾涔夊垪琛�")
+    @PreAuthorize("@ss.hasPermission('mes:pro-work-order:query')")
+    public CommonResult<List<Map<String, Object>>> getWorkOrderApproveProcessDefinitionList() {
+        return success(workOrderService.getWorkOrderApproveProcessDefinitionList());
+    }
+
     @GetMapping("/schedule-page")
     @Operation(summary = "鑾峰緱鐢熶骇宸ュ崟璋冨害鐘舵�佸垎椤�")
     @PreAuthorize("@ss.hasPermission('mes:pro-work-order:query')")
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/MesProWorkOrderRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/MesProWorkOrderRespVO.java
index beb178f..714bf36 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/MesProWorkOrderRespVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/MesProWorkOrderRespVO.java
@@ -145,4 +145,16 @@
     @ExcelProperty("鐢熶骇鐘舵��")
     private Integer productionStatus;
 
+    @Schema(description = "鏄惁鎶ュ伐瀹℃壒")
+    @ExcelProperty("鏄惁鎶ュ伐瀹℃壒")
+    private Boolean feedbackApprove;
+
+    @Schema(description = "BPM 娴佺▼瀹氫箟 Key")
+    @ExcelProperty("BPM 娴佺▼瀹氫箟 Key")
+    private String processDefinitionKey;
+
+    @Schema(description = "鎶ュ伐瑙掕壊 (澶氫釜瑙掕壊閫楀彿鍒嗛殧)")
+    @ExcelProperty("鎶ュ伐瑙掕壊")
+    private String feedbackRole;
+
 }
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/MesProWorkOrderSaveReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/MesProWorkOrderSaveReqVO.java
index b8527bc..a41d1f1 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/MesProWorkOrderSaveReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/MesProWorkOrderSaveReqVO.java
@@ -70,4 +70,13 @@
     @Schema(description = "澶囨敞", example = "澶囨敞")
     private String remark;
 
+    @Schema(description = "鏄惁鎶ュ伐瀹℃壒")
+    private Boolean feedbackApprove;
+
+    @Schema(description = "BPM 娴佺▼瀹氫箟 Key")
+    private String processDefinitionKey;
+
+    @Schema(description = "鎶ュ伐瑙掕壊 (澶氫釜瑙掕壊閫楀彿鍒嗛殧)")
+    private String feedbackRole;
+
 }
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/feedback/MesProFeedbackDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/feedback/MesProFeedbackDO.java
index bb3cc23..bd27c07 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/feedback/MesProFeedbackDO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/feedback/MesProFeedbackDO.java
@@ -160,4 +160,14 @@
      */
     private String remark;
 
+    /**
+     * BPM 娴佺▼瀹炰緥缂栧彿
+     */
+    private String processInstanceId;
+
+    /**
+     * BPM 娴佺▼瀹氫箟 Key
+     */
+    private String processDefinitionKey;
+
 }
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/task/MesProTaskAssigneeDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/task/MesProTaskAssigneeDO.java
new file mode 100644
index 0000000..47d357e
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/task/MesProTaskAssigneeDO.java
@@ -0,0 +1,40 @@
+package cn.iocoder.yudao.module.mes.dal.dataobject.pro.task;
+
+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.*;
+
+/**
+ * 鐢熶骇浠诲姟鎸囧畾鎶ュ伐浜哄憳琛� DO
+ *
+ * @author 鑷姩鐢熸垚
+ */
+@TableName("mes_pro_task_assignee")
+@KeySequence("mes_pro_task_assignee_seq")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class MesProTaskAssigneeDO extends BaseDO {
+
+    /**
+     * 缂栧彿
+     */
+    @TableId
+    private Long id;
+    /**
+     * 鐢熶骇浠诲姟 ID
+     *
+     * 鍏宠仈 {@link MesProTaskDO#getId()}
+     */
+    private Long taskId;
+    /**
+     * 绯荤粺鐢ㄦ埛 ID (鎸囧畾鎶ュ伐浜哄憳)
+     */
+    private Long userId;
+
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkOrderDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkOrderDO.java
index 82cd251..85dd127 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkOrderDO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkOrderDO.java
@@ -8,6 +8,7 @@
 import com.baomidou.mybatisplus.annotation.KeySequence;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.*;
 
 import java.math.BigDecimal;
@@ -148,4 +149,21 @@
      */
     private String remark;
 
+    /**
+     * 鏄惁鎶ュ伐瀹℃壒
+     */
+    @com.baomidou.mybatisplus.annotation.TableField("is_feedback_approve")
+    private Boolean feedbackApprove;
+
+    /**
+     * BPM 娴佺▼瀹氫箟 Key
+     */
+    private String processDefinitionKey;
+
+    /**
+     * 鎶ュ伐瑙掕壊 (澶氫釜瑙掕壊閫楀彿鍒嗛殧)
+     */
+    private String feedbackRole;
+
+
 }
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/mps/MesProMpsMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/mps/MesProMpsMapper.java
index 6225ad7..824754a 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/mps/MesProMpsMapper.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/mps/MesProMpsMapper.java
@@ -52,9 +52,11 @@
                 .orderByDesc(MesProMpsDO::getId);
         if (permittedClientIds != null) {
             if (CollUtil.isEmpty(permittedClientIds)) {
-                return PageResult.empty();
+                wrapper.isNull(MesProMpsDO::getClientId);
+            } else {
+                wrapper.and(w -> w.in(MesProMpsDO::getClientId, permittedClientIds)
+                        .or().isNull(MesProMpsDO::getClientId));
             }
-            wrapper.in(MesProMpsDO::getClientId, permittedClientIds);
         }
         return selectPage(reqVO, wrapper);
     }
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/task/MesProTaskAssigneeMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/task/MesProTaskAssigneeMapper.java
new file mode 100644
index 0000000..2631cef
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/task/MesProTaskAssigneeMapper.java
@@ -0,0 +1,38 @@
+package cn.iocoder.yudao.module.mes.dal.mysql.pro.task;
+
+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.task.MesProTaskAssigneeDO;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 鐢熶骇浠诲姟鎸囧畾鎶ュ伐浜哄憳 Mapper
+ *
+ * @author 鑷姩鐢熸垚
+ */
+@Mapper
+public interface MesProTaskAssigneeMapper extends BaseMapperX<MesProTaskAssigneeDO> {
+
+    default List<MesProTaskAssigneeDO> selectListByTaskId(Long taskId) {
+        return selectList(MesProTaskAssigneeDO::getTaskId, taskId);
+    }
+
+    default List<MesProTaskAssigneeDO> selectListByTaskIds(Collection<Long> taskIds) {
+        return selectList(new LambdaQueryWrapperX<MesProTaskAssigneeDO>()
+                .inIfPresent(MesProTaskAssigneeDO::getTaskId, taskIds));
+    }
+
+    default void deleteByTaskId(Long taskId) {
+        delete(MesProTaskAssigneeDO::getTaskId, taskId);
+    }
+    
+    default void deleteByTaskIdAndUserIds(Long taskId, Collection<Long> userIds) {
+        delete(new LambdaQueryWrapperX<MesProTaskAssigneeDO>()
+                .eq(MesProTaskAssigneeDO::getTaskId, taskId)
+                .in(MesProTaskAssigneeDO::getUserId, userIds));
+    }
+
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/task/MesProTaskMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/task/MesProTaskMapper.java
index 503445b..a90270a 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/task/MesProTaskMapper.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/task/MesProTaskMapper.java
@@ -6,6 +6,7 @@
 import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX;
 import cn.iocoder.yudao.module.mes.controller.admin.pro.task.vo.MesProTaskPageReqVO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteProcessDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.task.MesProTaskAssigneeDO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.task.MesProTaskDO;
 import cn.iocoder.yudao.module.mes.enums.pro.MesProTaskStatusEnum;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
@@ -48,6 +49,12 @@
     default PageResult<MesProTaskDO> selectPendingFeedbackPage(MesProTaskPageReqVO reqVO) {
         MPJLambdaWrapperX<MesProTaskDO> query = new MPJLambdaWrapperX<>();
         query.selectAll(MesProTaskDO.class);
+        // 褰撻渶瑕佹寜 assigneeUserId 杩囨护鏃讹紝INNER JOIN mes_pro_task_assignee
+        if (reqVO.getAssigneeUserId() != null) {
+            query.innerJoin(MesProTaskAssigneeDO.class, on -> on
+                    .eq(MesProTaskAssigneeDO::getTaskId, MesProTaskDO::getId));
+            query.eq(MesProTaskAssigneeDO::getUserId, reqVO.getAssigneeUserId());
+        }
         // 寰呮姤宸ュ彴璐︼細杩涜涓殑浠诲姟锛堟帓闄ゅ凡瀹屾垚/宸插彇娑堬級锛屼笖浠嶆湁寰呮姤宸ラ噺
         query.in(MesProTaskDO::getStatus, MesProTaskStatusEnum.PREPARE.getStatus(),MesProTaskStatusEnum.PAUSED.getStatus());
         query.apply("(quantity - IFNULL(produced_quantity, 0)) > 0");
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 efc8ff9..cadf846 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
@@ -40,6 +40,7 @@
     ErrorCode MD_ITEM_BATCH_CONFIG_NOT_EXISTS = new ErrorCode(1_040_102_100, "鐗╂枡鎵规灞炴�ч厤缃笉瀛樺湪");
     ErrorCode MD_ITEM_BATCH_CONFIG_AT_LEAST_ONE_FLAG = new ErrorCode(1_040_102_101, "鎵规绠$悊宸插惎鐢紝鑷冲皯闇�瑕侀厤缃竴涓壒娆″睘鎬�");
     ErrorCode MD_ITEM_PRODUCT_BOM_REQUIRED = new ErrorCode(1_040_102_102, "浜у搧绫荤墿鏂欏惎鐢ㄥ墠锛屽繀椤婚厤缃嚦灏戜竴涓� BOM 缁勬垚");
+    ErrorCode MD_ITEM_BATCH_CONFIG_AT_LEAST_ONE_APPROVE_FLAG = new ErrorCode(1_040_102_103, "闇�瑕侀厤缃竴涓壒娆″睘鎬�,璇峰湪瀹℃壒鎰忚涓~鍐�");
 
     // ========== MES 浠撳簱绠$悊-鎵规绠$悊锛�1-040-717-000锛� ==========
     ErrorCode WM_BATCH_PRODUCE_DATE_REQUIRED = new ErrorCode(1_040_717_000, "鎵规閰嶇疆瑕佹眰鐢熶骇鏃ユ湡涓嶈兘涓虹┖");
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/common/bpm/MesBpmProcessService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/common/bpm/MesBpmProcessService.java
new file mode 100644
index 0000000..8771e8d
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/common/bpm/MesBpmProcessService.java
@@ -0,0 +1,19 @@
+package cn.iocoder.yudao.module.mes.service.common.bpm;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * MES 妯″潡鐨勯�氱敤 BPM 娴佺▼澶勭悊 Service 鎺ュ彛
+ */
+public interface MesBpmProcessService {
+
+    /**
+     * 鑾峰彇鎸囧畾鍒嗙被涓嬬殑婵�娲荤姸鎬併�佹渶鏂扮増鏈殑娴佺▼瀹氫箟鍒楄〃
+     *
+     * @param categoryCode 娴佺▼鍒嗙被缂栫爜
+     * @return 娴佺▼瀹氫箟鍒楄〃锛屽寘鍚� id, key, name
+     */
+    List<Map<String, Object>> getApproveProcessDefinitionList(String categoryCode);
+
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/common/bpm/MesBpmProcessServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/common/bpm/MesBpmProcessServiceImpl.java
new file mode 100644
index 0000000..13055df
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/common/bpm/MesBpmProcessServiceImpl.java
@@ -0,0 +1,71 @@
+package cn.iocoder.yudao.module.mes.service.common.bpm;
+
+import cn.hutool.core.collection.CollUtil;
+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.service.definition.BpmCategoryService;
+import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.flowable.engine.repository.ProcessDefinition;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import java.util.*;
+
+/**
+ * MES 妯″潡鐨勯�氱敤 BPM 娴佺▼澶勭悊 Service 瀹炵幇绫�
+ */
+@Service
+@Validated
+@Slf4j
+public class MesBpmProcessServiceImpl implements MesBpmProcessService {
+
+    @Resource
+    private BpmCategoryService bpmCategoryService;
+    @Resource
+    private BpmProcessDefinitionService bpmProcessDefinitionService;
+
+    @Override
+    public List<Map<String, Object>> getApproveProcessDefinitionList(String categoryCode) {
+        // 1. 鏍¢獙鍒嗙被鏄惁瀛樺湪
+        List<BpmCategoryDO> categories = bpmCategoryService.getCategoryListByCode(
+                Collections.singletonList(categoryCode));
+        if (CollUtil.isEmpty(categories)) {
+            log.warn("[getApproveProcessDefinitionList] BPM 娴佺▼鍒嗙被 {} 涓嶅瓨鍦�", categoryCode);
+            return Collections.emptyList();
+        }
+
+        // 2. 鑾峰彇鍒嗙被涓嬬殑娴佺▼瀹氫箟淇℃伅
+        List<BpmProcessDefinitionInfoDO> definitionInfoList = bpmProcessDefinitionService
+                .getProcessDefinitionInfoListByCategory(categoryCode);
+        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;
+    }
+
+}
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 aa655a4..bb57d2b 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
@@ -7,8 +7,7 @@
 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.service.common.bpm.MesBpmProcessService;
 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;
@@ -80,10 +79,7 @@
     private BpmProcessInstanceApi processInstanceApi;
 
     @Resource
-    private BpmCategoryService bpmCategoryService;
-
-    @Resource
-    private BpmProcessDefinitionService bpmProcessDefinitionService;
+    private MesBpmProcessService mesBpmProcessService;
 
     @Override
     @Transactional(rollbackFor = Exception.class)
@@ -238,40 +234,7 @@
 
     @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;
+        return mesBpmProcessService.getApproveProcessDefinitionList(BPM_PROCESS_DEFINITION_CATEGORY_CODE);
     }
 
     @Override
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackService.java
index 05d2a48..c744afe 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackService.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackService.java
@@ -81,9 +81,9 @@
     /**
      * 鎻愪氦鎶ュ伐锛堣崏绋� 鈫� 瀹℃壒涓級
      *
-     * @param id 缂栧彿
+     * @param reqVO 鎻愪氦璇锋眰
      */
-    void submitFeedback(Long id);
+    void submitFeedback(@Valid MesProFeedbackSubmitReqVO reqVO);
 
     /**
      * 椹冲洖鎶ュ伐锛堝鎵逛腑 鈫� 鑽夌锛�
@@ -122,6 +122,14 @@
     MesProFeedbackBatchCheckRespVO checkBatchRequirements(Long feedbackId);
 
     /**
+     * 澶勭悊 BPM 瀹℃壒缁撴灉
+     *
+     * @param id 鎶ュ伐鍗旾D
+     * @param bpmResult 瀹℃壒缁撴灉鐘舵��
+     */
+    void handleBpmProcessResult(Long id, Integer bpmResult,String reason);
+
+    /**
      * IPQC 瀹屾垚鍚庡洖璋冿細瀹屾垚鎶ュ伐鍗曞苟鏇存柊浠诲姟/宸ュ崟杩涘害
      *
      * <p>鐢� IPQC 妫�楠屽畬鎴愭椂璋冪敤锛屽皢鎶ュ伐鍗曠姸鎬佷粠寰呮楠屾敼涓哄凡瀹屾垚锛�
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 d5401e9..3d3022f 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
@@ -4,6 +4,7 @@
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ObjUtil;
 import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 import cn.iocoder.yudao.module.mes.controller.admin.pro.feedback.vo.*;
@@ -62,6 +63,7 @@
  */
 @Service
 @Validated
+@lombok.extern.slf4j.Slf4j
 public class MesProFeedbackServiceImpl implements MesProFeedbackService {
 
     @Resource
@@ -94,6 +96,8 @@
     private MesMdmItemService mdmItemService;
     @Resource
     private MdmItemBatchConfigApi itemBatchConfigApi;
+    @Resource
+    private cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi processInstanceApi;
 
     @Override
     public Long createFeedback(MesProFeedbackSaveReqVO createReqVO) {
@@ -154,13 +158,76 @@
     }
 
     @Override
-    public void submitFeedback(Long id) {
+    @Transactional(rollbackFor = Exception.class)
+    public void submitFeedback(MesProFeedbackSubmitReqVO reqVO) {
+        Long id = reqVO.getId();
         // 1. 鏍¢獙瀛樺湪 + 鑽夌鐘舵��
-        validateFeedbackStatusPrepare(id);
+        MesProFeedbackDO feedback = validateFeedbackStatusPrepare(id);
 
-        // 2. 鏇存柊鐘舵�佷负瀹℃壒涓紙鎶ュ伐浜哄拰鎶ュ伐鏃堕棿鐢辫〃鍗曚繚瀛樻椂纭畾锛屾彁浜や笉瑕嗙洊锛�
-        feedbackMapper.updateById(new MesProFeedbackDO().setId(id)
-                .setStatus(MesProFeedbackStatusEnum.APPROVING.getStatus()));
+        MesProWorkOrderDO workOrder = workOrderService.getWorkOrder(feedback.getWorkOrderId());
+
+        if (workOrder != null && Boolean.TRUE.equals(workOrder.getFeedbackApprove()) && cn.hutool.core.util.StrUtil.isNotBlank(workOrder.getProcessDefinitionKey())) {
+            // 2. 鏇存柊鐘舵�佷负瀹℃壒涓紝骞跺惎鍔ㄦ祦绋�
+            String processInstanceId = processInstanceApi.createProcessInstance(cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId(),
+                    new cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO()
+                            .setProcessDefinitionKey(workOrder.getProcessDefinitionKey())
+                            .setBusinessKey(String.valueOf(id)));
+
+            feedbackMapper.updateById(new MesProFeedbackDO().setId(id)
+                    .setStatus(MesProFeedbackStatusEnum.APPROVING.getStatus())
+                    .setProcessDefinitionKey(workOrder.getProcessDefinitionKey())
+                    .setProcessInstanceId(processInstanceId));
+        } else {
+            // 2. 鍒ゆ柇杩欎釜鎶ュ伐闇�涓嶉渶瑕佹壒娆″彿
+            MesProFeedbackBatchCheckRespVO mesProFeedbackBatchCheckRespVO = checkBatchRequirements(id);
+            if (mesProFeedbackBatchCheckRespVO.getNeedBatchInput()) {
+                if (StrUtil.isBlank(reqVO.getLotNumber())) {
+                    throw exception(MD_ITEM_BATCH_CONFIG_AT_LEAST_ONE_APPROVE_FLAG);
+                }
+            }
+
+            // 3. 鏇存柊鐘舵�佷负瀹℃壒涓紝鐒跺悗鐩存帴閫氳繃瀹℃壒
+            feedbackMapper.updateById(new MesProFeedbackDO().setId(id)
+                    .setStatus(MesProFeedbackStatusEnum.APPROVING.getStatus()));
+            MesProFeedbackApproveReqVO approveReqVO = cn.iocoder.yudao.framework.common.util.object.BeanUtils.toBean(reqVO, MesProFeedbackApproveReqVO.class);
+            approveFeedback(approveReqVO);
+        }
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void handleBpmProcessResult(Long id, Integer bpmResult,String reason) {
+        // 1. 鏌旀�ф牎楠岋細鑾峰彇鎶ュ伐鍗曞苟鍒ゆ柇鐘舵��
+        MesProFeedbackDO feedback = feedbackMapper.selectById(id);
+        if (feedback == null) {
+            log.warn("[handleBpmProcessResult] 鐢熶骇鎶ュ伐({}) 涓嶅瓨鍦�", id);
+            return;
+        }
+        if (!MesProFeedbackStatusEnum.APPROVING.getStatus().equals(feedback.getStatus())) {
+            log.warn("[handleBpmProcessResult] 鐢熶骇鎶ュ伐({}) 涓嶅浜庡鎵逛腑鐘舵�侊紝褰撳墠鐘舵�侊細{}", id, feedback.getStatus());
+            return;
+        }
+
+        // 2. 鏍规嵁瀹℃壒缁撴灉杩涜澶勭悊
+        if (cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum.APPROVE.getStatus().equals(bpmResult)) {
+            MesProFeedbackApproveReqVO  reqVO = new MesProFeedbackApproveReqVO();
+            reqVO.setId(id);
+            //  鍒ゆ柇杩欎釜鎶ュ伐闇�涓嶉渶瑕佹壒娆″彿
+            MesProFeedbackBatchCheckRespVO mesProFeedbackBatchCheckRespVO = checkBatchRequirements(id);
+            if (mesProFeedbackBatchCheckRespVO.getNeedBatchInput()){
+               if (StrUtil.isBlank(reason)){
+                   //  鎶ラ敊 璇峰湪瀹℃壒鎰忚閲屽~鍐欐壒娆″彿
+                   throw  exception(MD_ITEM_BATCH_CONFIG_AT_LEAST_ONE_APPROVE_FLAG);
+               }else {
+                 BeanUtils.copyProperties(mesProFeedbackBatchCheckRespVO,reqVO);
+                 reqVO.setLotNumber(reason);
+               }
+            }
+            approveFeedback(reqVO);
+        } else if (cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum.REJECT.getStatus().equals(bpmResult) ||
+                   cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum.CANCEL.getStatus().equals(bpmResult)) {
+            rejectFeedback(id);
+        }
     }
 
     @Override
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/listener/MesProFeedbackStatusListener.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/listener/MesProFeedbackStatusListener.java
new file mode 100644
index 0000000..9156eeb
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/listener/MesProFeedbackStatusListener.java
@@ -0,0 +1,74 @@
+package cn.iocoder.yudao.module.mes.service.pro.feedback.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.pro.feedback.MesProFeedbackService;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants;
+import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService;
+import org.flowable.task.api.history.HistoricTaskInstance;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * 鐢熶骇鎶ュ伐瀹℃壒鐘舵�佺洃鍚櫒
+ *
+ * 鐩戝惉 BPM 娴佺▼瀹炰緥鐘舵�佸彉鏇翠簨浠讹紝鏇存柊鐢熶骇鎶ュ伐鐨勫鎵圭姸鎬�
+ *
+ * @author 瓒呯骇绠$悊鍛�
+ */
+@Component
+@Slf4j
+public class MesProFeedbackStatusListener extends BpmProcessInstanceStatusEventListener {
+
+    /**
+     * BPM 鐢熶骇鎶ュ伐瀹℃壒娴佺▼瀹氫箟 key
+     */
+    private static final String BPM_PROCESS_DEFINITION_KEY = "mes-pro-feedback-audit";
+
+    @Resource
+    private MesProFeedbackService feedbackService;
+
+    @Resource
+    private BpmTaskService bpmTaskService;
+
+    @Override
+    protected String getProcessDefinitionKey() {
+        return BPM_PROCESS_DEFINITION_KEY;
+    }
+
+    @Override
+    protected void onEvent(BpmProcessInstanceStatusEvent event) {
+        Long feedbackId;
+        try {
+            feedbackId = Long.parseLong(event.getBusinessKey());
+        } catch (NumberFormatException e) {
+            log.warn("[onEvent] businessKey({}) 涓嶆槸鏈夋晥鐨勭敓浜ф姤宸ョ紪鍙�", event.getBusinessKey());
+            return;
+        }
+        String reason = event.getReason();
+        if (StrUtil.isEmpty(reason) && event.getId() != null) {
+            // 褰� event.getReason() 涓虹┖鏃讹紝灏濊瘯浠庢渶鍚庝竴涓畬鎴愮殑浠诲姟涓幏鍙栧鎵规剰瑙�
+            List<HistoricTaskInstance> tasks = bpmTaskService.getTaskListByProcessInstanceId(event.getId(), false);
+            if (CollUtil.isNotEmpty(tasks)) {
+                HistoricTaskInstance lastTask = tasks.stream()
+                        .filter(task -> task.getEndTime() != null)
+                        .max(Comparator.comparing(HistoricTaskInstance::getEndTime))
+                        .orElse(null);
+                if (lastTask != null && lastTask.getTaskLocalVariables() != null) {
+                    reason = (String) lastTask.getTaskLocalVariables().get(BpmnVariableConstants.TASK_VARIABLE_REASON);
+                }
+            }
+        }
+
+        log.info("[onEvent] 鏀跺埌BPM瀹℃壒浜嬩欢锛宖eedbackId={}, status={},Reason={}", feedbackId, event.getStatus(), reason);
+
+        feedbackService.handleBpmProcessResult(feedbackId, event.getStatus(), reason);
+    }
+
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/task/MesProTaskService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/task/MesProTaskService.java
index d98de42..c2e0d11 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/task/MesProTaskService.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/task/MesProTaskService.java
@@ -176,4 +176,23 @@
      */
     void resumeTask(cn.iocoder.yudao.module.mes.controller.admin.pro.task.vo.MesProTaskResumeReqVO resumeReqVO);
 
+    /**
+     * 鑾峰彇鐢熶骇浠诲姟鐨勬寚瀹氭姤宸ヤ汉鍛樺垪琛紝鎸変换鍔$紪鍙峰垎缁�
+     *
+     * @param taskIds 浠诲姟缂栧彿闆嗗悎
+     * @return 浠诲姟鍏宠仈鐨勪汉鍛樺垪琛� Map
+     */
+    default Map<Long, List<cn.iocoder.yudao.module.mes.dal.dataobject.pro.task.MesProTaskAssigneeDO>> getTaskAssigneeMap(Collection<Long> taskIds) {
+        if (cn.hutool.core.collection.CollUtil.isEmpty(taskIds)) {
+            return java.util.Collections.emptyMap();
+        }
+        return cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap(
+                getTaskAssigneeListByTaskIds(taskIds), cn.iocoder.yudao.module.mes.dal.dataobject.pro.task.MesProTaskAssigneeDO::getTaskId);
+    }
+
+    /**
+     * 鏍规嵁浠诲姟缂栧彿闆嗗悎鑾峰彇鍏宠仈浜哄憳鍒楄〃
+     */
+    List<cn.iocoder.yudao.module.mes.dal.dataobject.pro.task.MesProTaskAssigneeDO> getTaskAssigneeListByTaskIds(Collection<Long> taskIds);
+
 }
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 d6ebc52..d13aa2c 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
@@ -58,6 +58,8 @@
 import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.task.MesProTaskPauseRecordDO;
 import cn.iocoder.yudao.module.mes.dal.mysql.pro.task.MesProTaskPauseRecordMapper;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.task.MesProTaskAssigneeDO;
+import cn.iocoder.yudao.module.mes.dal.mysql.pro.task.MesProTaskAssigneeMapper;
 import cn.iocoder.yudao.module.mes.controller.admin.pro.task.vo.MesProTaskPauseReqVO;
 import cn.iocoder.yudao.module.mes.controller.admin.pro.task.vo.MesProTaskResumeReqVO;
 
@@ -78,6 +80,9 @@
 
     @Resource
     private MesProTaskPauseRecordMapper taskPauseRecordMapper;
+
+    @Resource
+    private MesProTaskAssigneeMapper taskAssigneeMapper;
 
     @Resource
     @Lazy
@@ -141,6 +146,10 @@
         }
         // 2.2 鎻掑叆
         taskMapper.insert(task);
+        
+        // 2.3 淇濆瓨鎸囧畾鎶ュ伐浜哄憳
+        updateTaskAssignees(task.getId(), createReqVO.getAssigneeUserIds());
+        
         return task.getId();
     }
 
@@ -173,6 +182,34 @@
         MesProTaskDO updateObj = BeanUtils.toBean(updateReqVO, MesProTaskDO.class)
                 .setName(buildTaskName(item, quantity));
         taskMapper.updateById(updateObj);
+        
+        // 3. 鏇存柊鎸囧畾鎶ュ伐浜哄憳锛堟瘮瀵规洿鏂帮級
+        updateTaskAssignees(task.getId(), updateReqVO.getAssigneeUserIds());
+    }
+
+    private void updateTaskAssignees(Long taskId, List<Long> assigneeUserIds) {
+        if (assigneeUserIds == null) {
+            assigneeUserIds = Collections.emptyList();
+        }
+        // 1. 鏌ヨ鏁版嵁搴撲腑鍘熸湁鐨�
+        List<MesProTaskAssigneeDO> oldAssignees = taskAssigneeMapper.selectListByTaskId(taskId);
+        Set<Long> oldUserIds = convertSet(oldAssignees, MesProTaskAssigneeDO::getUserId);
+        Set<Long> newUserIds = new java.util.HashSet<>(assigneeUserIds);
+
+        // 2. 璁$畻闇�瑕佹柊澧炵殑鍜岄渶瑕佸垹闄ょ殑
+        Set<Long> toAddUserIds = newUserIds.stream().filter(id -> !oldUserIds.contains(id)).collect(java.util.stream.Collectors.toSet());
+        Set<Long> toRemoveUserIds = oldUserIds.stream().filter(id -> !newUserIds.contains(id)).collect(java.util.stream.Collectors.toSet());
+
+        // 3. 鏂板
+        if (CollUtil.isNotEmpty(toAddUserIds)) {
+            List<MesProTaskAssigneeDO> addList = convertList(toAddUserIds, userId -> new MesProTaskAssigneeDO().setTaskId(taskId).setUserId(userId));
+            taskAssigneeMapper.insertBatch(addList);
+        }
+
+        // 4. 鍒犻櫎
+        if (CollUtil.isNotEmpty(toRemoveUserIds)) {
+            taskAssigneeMapper.deleteByTaskIdAndUserIds(taskId, toRemoveUserIds);
+        }
     }
 
     /**
@@ -245,8 +282,10 @@
         if (feedbackMapper.selectCountByTaskId(id) > 0) {
             throw exception(PRO_TASK_HAS_FEEDBACK);
         }
-        // 3. 鍒犻櫎
+        // 3. 鍒犻櫎浠诲姟涓昏〃
         taskMapper.deleteById(id);
+        // 4. 鍒犻櫎鍏宠仈鐨勪汉鍛�
+        taskAssigneeMapper.deleteByTaskId(id);
     }
 
     @Override
@@ -273,6 +312,14 @@
     }
 
     @Override
+    public List<MesProTaskAssigneeDO> getTaskAssigneeListByTaskIds(Collection<Long> taskIds) {
+        if (CollUtil.isEmpty(taskIds)) {
+            return Collections.emptyList();
+        }
+        return taskAssigneeMapper.selectListByTaskIds(taskIds);
+    }
+
+    @Override
     public MesProTaskDO validateTaskExists(Long id) {
         MesProTaskDO task = taskMapper.selectById(id);
         if (task == null) {
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderService.java
index 08c4657..04d890d 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderService.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderService.java
@@ -67,6 +67,13 @@
     MesProWorkOrderDO getWorkOrder(String code);
 
     /**
+     * 鑾峰彇瀹℃壒鎶ュ伐鐨勬祦绋嬪畾涔夊垪琛�
+     *
+     * @return 娴佺▼瀹氫箟鍒楄〃锛屽寘鍚� id, key, name
+     */
+    List<Map<String, Object>> getWorkOrderApproveProcessDefinitionList();
+
+    /**
      * 鑾峰緱鐢熶骇宸ュ崟鍒嗛〉
      *
      * @param pageReqVO 鍒嗛〉鏌ヨ
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderServiceImpl.java
index c4cb972..eee7b86 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderServiceImpl.java
@@ -13,6 +13,7 @@
 import cn.iocoder.yudao.module.mes.enums.wm.BarcodeBizTypeEnum;
 import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemBatchConfigService;
 import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
+import cn.iocoder.yudao.module.mes.service.common.bpm.MesBpmProcessService;
 import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderProgressRespVO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.md.workstation.MesMdWorkstationDO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.process.MesProProcessDO;
@@ -46,6 +47,11 @@
 @Service
 @Validated
 public class MesProWorkOrderServiceImpl implements MesProWorkOrderService {
+
+    @Resource
+    private MesBpmProcessService mesBpmProcessService;
+
+    private static final String BPM_PROCESS_DEFINITION_CATEGORY_CODE = "mes_pro_feedback_audit";
 
     @Resource
     private MesProWorkOrderMapper workOrderMapper;
@@ -150,6 +156,13 @@
     }
 
     @Override
+    public List<Map<String, Object>> getWorkOrderApproveProcessDefinitionList() {
+        return mesBpmProcessService.getApproveProcessDefinitionList(BPM_PROCESS_DEFINITION_CATEGORY_CODE);
+    }
+
+
+
+    @Override
     public MesProWorkOrderDO getWorkOrder(Long id) {
         return workOrderMapper.selectById(id);
     }
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.java
index 81e6c02..9212aaf 100644
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.java
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.java
@@ -14,7 +14,10 @@
 import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
 import cn.iocoder.yudao.module.system.enums.common.SexEnum;
 import cn.iocoder.yudao.module.system.service.dept.DeptService;
+import cn.iocoder.yudao.module.system.service.permission.PermissionService;
+import cn.iocoder.yudao.module.system.service.permission.RoleService;
 import cn.iocoder.yudao.module.system.service.user.AdminUserService;
+import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
 import io.swagger.v3.oas.annotations.Parameters;
@@ -33,6 +36,7 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@@ -49,6 +53,10 @@
     private AdminUserService userService;
     @Resource
     private DeptService deptService;
+    @Resource
+    private RoleService roleService;
+    @Resource
+    private PermissionService permissionService;
 
     @PostMapping("/create")
     @Operation(summary = "鏂板鐢ㄦ埛")
@@ -148,6 +156,32 @@
         return success(UserConvert.INSTANCE.convertSimpleList(list, deptMap));
     }
 
+    @GetMapping("/list-by-role-code")
+    @Operation(summary = "閫氳繃瑙掕壊鏍囪瘑鑾峰彇鐢ㄦ埛绮剧畝淇℃伅鍒楄〃", description = "鍙寘鍚嫢鏈夎繖浜涜鑹茬殑鐢ㄦ埛锛屼富瑕佺敤浜庡墠绔殑涓嬫媺閫夐」銆傛敮鎸侀�楀彿鍒嗛殧鐨勫涓鑹叉爣璇�")
+    @Parameter(name = "code", description = "瑙掕壊鏍囪瘑锛屾敮鎸佸涓紝閫楀彿鍒嗛殧", required = true, example = "admin,user")
+    public CommonResult<List<UserSimpleRespVO>> getSimpleUserListByRoleCode(
+            @RequestParam("code") String code) {
+        if (StrUtil.isBlank(code)) {
+            return success(Collections.emptyList());
+        }
+        List<String> codes = StrUtil.split(code, ",");
+        List<RoleDO> roles = roleService.getRoleListByCodes(codes);
+        if (CollUtil.isEmpty(roles)) {
+            return success(Collections.emptyList());
+        }
+        Set<Long> userIds = permissionService.getUserRoleIdListByRoleId(convertList(roles, RoleDO::getId));
+        if (CollUtil.isEmpty(userIds)) {
+            return success(Collections.emptyList());
+        }
+        List<AdminUserDO> list = userService.getUserList(userIds);
+        
+        // 鎷兼帴鏁版嵁
+        Map<Long, DeptDO> deptMap = deptService.getDeptMap(
+                convertList(list, AdminUserDO::getDeptId));
+        return success(UserConvert.INSTANCE.convertSimpleList(list, deptMap));
+    }
+
+
     @GetMapping("/get")
     @Operation(summary = "鑾峰緱鐢ㄦ埛璇︽儏")
     @Parameter(name = "id", description = "缂栧彿", required = true, example = "1024")
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/permission/RoleMapper.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/permission/RoleMapper.java
index 902ff90..a9fd004 100644
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/permission/RoleMapper.java
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/permission/RoleMapper.java
@@ -32,6 +32,10 @@
         return selectOne(RoleDO::getCode, code);
     }
 
+    default List<RoleDO> selectListByCodes(Collection<String> codes) {
+        return selectList(RoleDO::getCode, codes);
+    }
+
     default List<RoleDO> selectListByStatus(@Nullable Collection<Integer> statuses) {
         return selectList(RoleDO::getStatus, statuses);
     }
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2TokenServiceImpl.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2TokenServiceImpl.java
index 5a8d019..da7b82f 100644
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2TokenServiceImpl.java
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2TokenServiceImpl.java
@@ -57,6 +57,12 @@
     @Resource
     @Lazy // 鎳掑姞杞斤紝閬垮厤寰幆渚濊禆
     private AdminUserService adminUserService;
+    @Resource
+    @Lazy
+    private cn.iocoder.yudao.module.system.service.permission.PermissionService permissionService;
+    @Resource
+    @Lazy
+    private cn.iocoder.yudao.module.system.service.permission.RoleService roleService;
 
     @Override
     @Transactional(rollbackFor = Exception.class)
@@ -226,8 +232,18 @@
         }
         if (userType.equals(UserTypeEnum.ADMIN.getValue())) {
             AdminUserDO user = adminUserService.getUser(userId);
-            return MapUtil.builder(LoginUser.INFO_KEY_NICKNAME, user.getNickname())
-                    .put(LoginUser.INFO_KEY_DEPT_ID, StrUtil.toStringOrNull(user.getDeptId())).build();
+            java.util.Map<String, String> info = new java.util.HashMap<>();
+            info.put(LoginUser.INFO_KEY_NICKNAME, user.getNickname());
+            info.put(LoginUser.INFO_KEY_DEPT_ID, cn.hutool.core.util.StrUtil.toStringOrNull(user.getDeptId()));
+            // Fetch roles and put into info
+            java.util.Set<Long> roleIds = permissionService.getUserRoleIdListByUserId(userId);
+            if (cn.hutool.core.collection.CollUtil.isNotEmpty(roleIds)) {
+                java.util.List<cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO> roles = roleService.getRoleList(roleIds);
+                if (cn.hutool.core.collection.CollUtil.isNotEmpty(roles)) {
+                    info.put(LoginUser.INFO_KEY_ROLE_CODES, cn.hutool.core.collection.CollUtil.join(roles, ",", cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO::getCode));
+                }
+            }
+            return info;
         } else if (userType.equals(UserTypeEnum.MEMBER.getValue())) {
             // 娉ㄦ剰锛氱洰鍓� Member 鏆傛椂涓嶈鍙栵紝鍙互鎸夐渶瀹炵幇
             return Collections.emptyMap();
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/permission/RoleService.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/permission/RoleService.java
index 7d4b133..fddb9dc 100644
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/permission/RoleService.java
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/permission/RoleService.java
@@ -65,6 +65,22 @@
     RoleDO getRole(Long id);
 
     /**
+     * 鑾峰緱瑙掕壊
+     *
+     * @param code 瑙掕壊缂栫爜
+     * @return 瑙掕壊
+     */
+    RoleDO getRoleByCode(String code);
+
+    /**
+     * 鑾峰緱瑙掕壊鍒楄〃
+     *
+     * @param codes 瑙掕壊缂栫爜鏁扮粍
+     * @return 瑙掕壊鍒楄〃
+     */
+    List<RoleDO> getRoleListByCodes(Collection<String> codes);
+
+    /**
      * 鑾峰緱瑙掕壊锛屼粠缂撳瓨涓�
      *
      * @param id 瑙掕壊缂栧彿
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/permission/RoleServiceImpl.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/permission/RoleServiceImpl.java
index c1559e2..32ccf51 100644
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/permission/RoleServiceImpl.java
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/permission/RoleServiceImpl.java
@@ -190,6 +190,19 @@
     }
 
     @Override
+    public RoleDO getRoleByCode(String code) {
+        return roleMapper.selectByCode(code);
+    }
+
+    @Override
+    public List<RoleDO> getRoleListByCodes(Collection<String> codes) {
+        if (CollUtil.isEmpty(codes)) {
+            return Collections.emptyList();
+        }
+        return roleMapper.selectListByCodes(codes);
+    }
+
+    @Override
     @Cacheable(value = RedisKeyConstants.ROLE, key = "#id",
             unless = "#result == null")
     public RoleDO getRoleFromCache(Long id) {
diff --git a/yudao-server/src/main/resources/application-wtxc.yaml b/yudao-server/src/main/resources/application-wtxc.yaml
new file mode 100644
index 0000000..674f67a
--- /dev/null
+++ b/yudao-server/src/main/resources/application-wtxc.yaml
@@ -0,0 +1,222 @@
+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/mom-wtxc?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: wtxc@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 杩炴帴鐨勭ず渚�
+#        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 锛屾垜浠墜鍔ㄥ垱寤鸿〃缁撴瀯銆�
+
+--- #################### 鏈嶅姟淇濋殰鐩稿叧閰嶇疆 ####################
+
+# 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.system.dal.mysql: debug
+    cn.iocoder.yudao.module.system.dal.mysql.sms.SmsChannelMapper: INFO # 閰嶇疆 SmsChannelMapper 鐨勬棩蹇楃骇鍒负 info
+    cn.iocoder.yudao.module.member.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.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_wtxc
+        host: 36.213.90.123
+        port: 19530
+
+--- #################### 瓒呯骇绠$悊鍛樼浉鍏抽厤缃� ####################
+
+# 瓒呯骇绠$悊鍛橀厤缃」锛岃缃綋鍓嶉」鐩墍鏈夎嚜瀹氫箟鐨勯厤缃�
+yudao:
+  captcha:
+    enable: false # 鏈湴鐜锛屾殏鏃跺叧闂浘鐗囬獙璇佺爜锛屾柟渚跨櫥褰曠瓑鎺ュ彛鐨勬祴璇曪紱
+  security:
+    mock-enable: true
+  access-log: # 璁块棶鏃ュ織鐨勯厤缃」
+    enable: false
+  demo: false # 鍏抽棴婕旂ず妯″紡
+  storage: # 鏂囦欢涓婁紶閰嶇疆
+    path: /data/javaWork/mom/file # 鏂囦欢瀛樺偍鏍圭洰褰�
+    url-prefix: /admin-api/system/storage-blob # URL璺緞鍓嶇紑
+    domain: http://42.63.71.140: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)

--
Gitblit v1.9.3