From f0c9b593769315001591cb4a759650a76b71cb8f Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期一, 03 八月 2026 17:55:56 +0800
Subject: [PATCH] feat(crm): 合同导出功能优化及状态中文展示

---
 .playwright-mcp/page-2026-08-03T09-20-36-226Z.yml                                                                             |  154 +++++++++
 yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/tender/SrmTenderProjectServiceImpl.java                    |   91 +++++
 .playwright-mcp/page-2026-08-03T09-22-54-018Z.yml                                                                             |  168 ++++++++++
 yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractRespVO.java       |   57 +-
 yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/controller/admin/supplier/vo/SrmSupplierPageReqVO.java             |    3 
 yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/tender/SrmBidEvaluationServiceImpl.java                    |   43 ++
 yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/controller/admin/tender/vo/SrmTenderProjectPartialUpdateReqVO.java |   21 +
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdItemServiceImpl.java                          |   95 -----
 yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/controller/admin/tender/SrmTenderProjectController.java            |    8 
 .playwright-mcp/page-2026-08-03T09-22-30-620Z.yml                                                                             |   17 +
 yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/tender/SrmTenderProjectService.java                        |    2 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/MesMdItemController.java                  |   29 -
 yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/CrmContractController.java               |   14 
 yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/tender/SrmTenderBidServiceImpl.java                        |   48 ++
 yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/dal/mysql/SrmTenderBidMapper.java                                  |    5 
 yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/enums/TenderStatusEnum.java                                        |   37 ++
 yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/tender/SrmBidAwardServiceImpl.java                         |   38 +
 yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/enums/ErrorCodeConstants.java                                      |   11 
 .playwright-mcp/page-2026-08-03T09-20-27-740Z.yml                                                                             |    1 
 yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/dal/mysql/SrmSupplierMapper.java                                   |    3 
 yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/common/CrmAuditStatusEnum.java                               |    8 
 /dev/null                                                                                                                     |   24 -
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java                                      |    1 
 .playwright-mcp/page-2026-08-03T09-22-42-679Z.yml                                                                             |    1 
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdItemService.java                              |   11 
 yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/enums/LogRecordConstants.java                                      |   45 ++
 .playwright-mcp/page-2026-08-03T09-16-38-621Z.yml                                                                             |    1 
 yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/MdmItemController.java                       |   12 
 28 files changed, 731 insertions(+), 217 deletions(-)

diff --git a/.playwright-mcp/page-2026-08-03T09-16-38-621Z.yml b/.playwright-mcp/page-2026-08-03T09-16-38-621Z.yml
new file mode 100644
index 0000000..6adf37e
--- /dev/null
+++ b/.playwright-mcp/page-2026-08-03T09-16-38-621Z.yml
@@ -0,0 +1 @@
+- generic [active]: 宸ヤ笟AI鏅洪�犲钩鍙�
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-08-03T09-20-27-740Z.yml b/.playwright-mcp/page-2026-08-03T09-20-27-740Z.yml
new file mode 100644
index 0000000..6adf37e
--- /dev/null
+++ b/.playwright-mcp/page-2026-08-03T09-20-27-740Z.yml
@@ -0,0 +1 @@
+- generic [active]: 宸ヤ笟AI鏅洪�犲钩鍙�
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-08-03T09-20-36-226Z.yml b/.playwright-mcp/page-2026-08-03T09-20-36-226Z.yml
new file mode 100644
index 0000000..1e8a48e
--- /dev/null
+++ b/.playwright-mcp/page-2026-08-03T09-20-36-226Z.yml
@@ -0,0 +1,154 @@
+- generic [ref=f1e7]:
+  - complementary [ref=f1e8]:
+    - generic [ref=f1e9]:
+      - link "宸ヤ笟AI鏅洪�犲钩鍙� 宸ヤ笟AI鏅洪�犲钩鍙�" [ref=f1e15] [cursor=pointer]:
+        - /url: javascript:void 0
+        - img "宸ヤ笟AI鏅洪�犲钩鍙�" [ref=f1e18]
+        - generic [ref=f1e19]: 宸ヤ笟AI鏅洪�犲钩鍙�
+      - menu [ref=f1e22]:
+        - menuitem "棣栭〉" [ref=f1e23] [cursor=pointer]
+        - listitem [ref=f1e30]:
+          - generic [ref=f1e31] [cursor=pointer]: 鍩虹鏁版嵁
+        - listitem [ref=f1e39]:
+          - generic [ref=f1e40] [cursor=pointer]: 閲囪喘绠$悊
+        - listitem [ref=f1e46]:
+          - generic [ref=f1e47] [cursor=pointer]: 钀ラ攢绠$悊
+        - listitem [ref=f1e53]:
+          - generic [ref=f1e54] [cursor=pointer]: 璁惧绠$悊
+        - listitem [ref=f1e61]:
+          - generic [ref=f1e62] [cursor=pointer]: 浠撳偍鐗╂祦
+        - listitem [ref=f1e70]:
+          - generic [ref=f1e71] [cursor=pointer]: 鐢熶骇绠℃帶
+        - listitem [ref=f1e78]:
+          - generic [ref=f1e79] [cursor=pointer]: 璐ㄩ噺绠$悊
+        - listitem [ref=f1e85]:
+          - generic [ref=f1e86] [cursor=pointer]: 鍗忓悓鍔炲叕
+        - listitem [ref=f1e92]:
+          - generic [ref=f1e93] [cursor=pointer]: 浜哄姏璧勬簮
+        - listitem [ref=f1e99]:
+          - generic [ref=f1e100] [cursor=pointer]: 鍞悗绠$悊
+        - listitem [ref=f1e106]:
+          - generic [ref=f1e107] [cursor=pointer]: 鍩虹璁炬柦
+        - listitem [ref=f1e113]:
+          - generic [ref=f1e114] [cursor=pointer]: 绯荤粺绠$悊
+        - listitem [ref=f1e120]:
+          - generic [ref=f1e121] [cursor=pointer]: IM 鍗虫椂閫氳
+  - generic [ref=f1e134]:
+    - generic [ref=f1e135]:
+      - banner [ref=f1e136]:
+        - button [ref=f1e137] [cursor=pointer]
+        - button [ref=f1e140] [cursor=pointer]
+        - navigation "breadcrumb" [ref=f1e145]:
+          - list [ref=f1e146]:
+            - listitem [ref=f1e147]:
+              - link [disabled] [ref=f1e148]
+        - generic [ref=f1e155]:
+          - generic [ref=f1e157] [cursor=pointer]:
+            - generic [ref=f1e161]: 鎼滅储
+            - generic [ref=f1e162]: Ctrl K
+          - button [ref=f1e164] [cursor=pointer]
+          - button "dark" [ref=f1e169] [cursor=pointer]
+          - button [ref=f1e178] [cursor=pointer]
+          - button [ref=f1e184] [cursor=pointer]
+          - button [ref=f1e187] [cursor=pointer]
+          - button [ref=f1e193] [cursor=pointer]:
+            - button [ref=f1e195]
+          - button "宸ヤ綔鍙�" [ref=f1e199] [cursor=pointer]
+          - button [ref=f1e203] [cursor=pointer]:
+            - img "鑺嬮亾婧愮爜" [ref=f1e208]
+      - generic [ref=f1e210]:
+        - generic [ref=f1e211]: 棣栭〉
+        - button [ref=f1e233] [cursor=pointer]
+    - main [ref=f1e251]:
+      - generic [ref=f1e254]:
+        - generic [ref=f1e255]:
+          - generic [ref=f1e256]:
+            - heading "涓嬪崍濂斤紝娆㈣繋鍥炴潵" [level=1] [ref=f1e257]
+            - paragraph [ref=f1e258]: 2026骞�8鏈�3鏃� 鏄熸湡涓�
+          - generic [ref=f1e259]: 绯荤粺杩愯涓�
+        - generic [ref=f1e264]:
+          - generic [ref=f1e273] [cursor=pointer]:
+            - generic [ref=f1e274]: 鐢熶骇璁㈠崟
+            - generic [ref=f1e275]:
+              - generic [ref=f1e276]: "25"
+              - generic [ref=f1e278]: 杩涜涓�
+            - generic [ref=f1e279]:
+              - text: 寰呮帓浜� 15
+              - generic [ref=f1e281]: "|"
+              - text: 宸插畬鎴� 5
+          - generic [ref=f1e293] [cursor=pointer]:
+            - generic [ref=f1e294]: 浠婃棩浜ч噺
+            - generic [ref=f1e295]:
+              - generic [ref=f1e296]: "0"
+              - generic [ref=f1e298]: 浠�
+            - generic [ref=f1e299]: 鏄ㄦ棩 0 浠�
+          - generic [ref=f1e310] [cursor=pointer]:
+            - generic [ref=f1e311]: 璐ㄩ噺鍚堟牸鐜�
+            - generic [ref=f1e312]:
+              - generic [ref=f1e313]: "0.0"
+              - generic [ref=f1e315]: "%"
+            - generic [ref=f1e316]: 鍚堟牸 0 | 涓嶈壇 0
+          - generic [ref=f1e328] [cursor=pointer]:
+            - generic [ref=f1e329]: 璁惧杩愯鐜�
+            - generic [ref=f1e330]:
+              - generic [ref=f1e331]: "100.0"
+              - generic [ref=f1e333]: "%"
+            - generic [ref=f1e334]:
+              - generic [ref=f1e335]: 鍋滄満 0
+              - generic [ref=f1e336]: "|"
+              - generic [ref=f1e337]: 缁存姢 0
+        - generic [ref=f1e340]:
+          - generic [ref=f1e350] [cursor=pointer]:
+            - generic [ref=f1e351]: 閲囪喘璁㈠崟
+            - generic [ref=f1e352]:
+              - generic [ref=f1e353]: "14"
+              - generic [ref=f1e355]: 绗�
+            - generic [ref=f1e356]: ERP 閲囪喘绠$悊
+          - generic [ref=f1e367] [cursor=pointer]:
+            - generic [ref=f1e368]: 閿�鍞鍗�
+            - generic [ref=f1e369]:
+              - generic [ref=f1e370]: "22"
+              - generic [ref=f1e372]: 绗�
+            - generic [ref=f1e373]: ERP 閿�鍞鐞�
+          - generic [ref=f1e385] [cursor=pointer]:
+            - generic [ref=f1e386]: 鐗╂枡搴撳瓨
+            - generic [ref=f1e387]:
+              - generic [ref=f1e388]: "13"
+              - generic [ref=f1e390]: 鏉�
+            - generic [ref=f1e391]: MES 搴撳瓨鍙拌处
+          - generic [ref=f1e403] [cursor=pointer]:
+            - generic [ref=f1e404]: 鎴戠殑寰呭姙
+            - generic [ref=f1e405]:
+              - generic [ref=f1e406]: "1"
+              - generic [ref=f1e408]: 椤�
+            - generic [ref=f1e409]: BPM 寰呭鎵�
+        - generic [ref=f1e413]:
+          - heading "AI 鏅鸿兘鍒嗘瀽" [level=3] [ref=f1e414]
+          - generic [ref=f1e415]: 25 涓伐鍗曞彲鍒嗘瀽
+        - generic [ref=f1e416]:
+          - heading "鐢熶骇瓒嬪娍锛堣繎7澶╋級" [level=3] [ref=f1e419]
+          - generic [ref=f1e424]:
+            - generic [ref=f1e425]:
+              - generic [ref=f1e431] [cursor=pointer]:
+                - generic [ref=f1e432]: 瀹夌伅鍛煎彨
+                - generic [ref=f1e433]:
+                  - generic [ref=f1e434]: "0"
+                  - generic [ref=f1e436]: 鏈缃�
+              - generic [ref=f1e442] [cursor=pointer]:
+                - generic [ref=f1e443]: 缁翠慨宸ュ崟
+                - generic [ref=f1e444]:
+                  - generic [ref=f1e445]: "0"
+                  - generic [ref=f1e447]: 寰呭鐞�
+            - heading "宸ュ崟鐘舵�佸垎甯�" [level=4] [ref=f1e449]
+        - generic [ref=f1e457]:
+          - heading "蹇嵎鎿嶄綔" [level=3] [ref=f1e458]
+          - generic [ref=f1e459]:
+            - generic [ref=f1e460] [cursor=pointer]: 鐢熶骇宸ュ崟
+            - generic [ref=f1e463] [cursor=pointer]: 鐢熶骇鎶ュ伐
+            - generic [ref=f1e466] [cursor=pointer]: 璐ㄦ绠$悊
+            - generic [ref=f1e469] [cursor=pointer]: 璁惧鐐规
+            - generic [ref=f1e472] [cursor=pointer]: 鐢熶骇鎺掔▼
+            - generic [ref=f1e475] [cursor=pointer]: 瀹夌伅鍛煎彨
+            - generic [ref=f1e478] [cursor=pointer]: 鐗╂枡搴撳瓨
+            - generic [ref=f1e481] [cursor=pointer]: 宸ヨ壓璺嚎
+            - generic [ref=f1e484] [cursor=pointer]: 鏁版嵁鎶ヨ〃
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-08-03T09-22-30-620Z.yml b/.playwright-mcp/page-2026-08-03T09-22-30-620Z.yml
new file mode 100644
index 0000000..a7a7ba4
--- /dev/null
+++ b/.playwright-mcp/page-2026-08-03T09-22-30-620Z.yml
@@ -0,0 +1,17 @@
+- generic [ref=f2e3]:
+  - generic [ref=f2e6]:
+    - heading "鏃犳硶璁块棶姝ょ綉绔�" [level=1] [ref=f2e7]
+    - paragraph [ref=f2e8]:
+      - strong [ref=f2e9]: localhost
+      - text: 鎷掔粷浜嗘垜浠殑杩炴帴璇锋眰銆�
+    - generic [ref=f2e10]:
+      - paragraph [ref=f2e11]: 璇疯瘯璇曚互涓嬪姙娉曪細
+      - list [ref=f2e12]:
+        - listitem [ref=f2e13]: 妫�鏌ョ綉缁滆繛鎺�
+        - listitem [ref=f2e14]:
+          - link "妫�鏌ヤ唬鐞嗘湇鍔″櫒鍜岄槻鐏" [ref=f2e15] [cursor=pointer]:
+            - /url: "#buttons"
+    - generic [ref=f2e16]: ERR_CONNECTION_REFUSED
+  - generic [ref=f2e17]:
+    - button "閲嶆柊鍔犺浇" [ref=f2e19] [cursor=pointer]
+    - button "璇︽儏" [ref=f2e20] [cursor=pointer]
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-08-03T09-22-42-679Z.yml b/.playwright-mcp/page-2026-08-03T09-22-42-679Z.yml
new file mode 100644
index 0000000..6adf37e
--- /dev/null
+++ b/.playwright-mcp/page-2026-08-03T09-22-42-679Z.yml
@@ -0,0 +1 @@
+- generic [active]: 宸ヤ笟AI鏅洪�犲钩鍙�
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-08-03T09-22-54-018Z.yml b/.playwright-mcp/page-2026-08-03T09-22-54-018Z.yml
new file mode 100644
index 0000000..0107202
--- /dev/null
+++ b/.playwright-mcp/page-2026-08-03T09-22-54-018Z.yml
@@ -0,0 +1,168 @@
+- generic [ref=f3e7]:
+  - complementary [ref=f3e8]:
+    - generic [ref=f3e9]:
+      - link "宸ヤ笟AI鏅洪�犲钩鍙� 宸ヤ笟AI鏅洪�犲钩鍙�" [ref=f3e15] [cursor=pointer]:
+        - /url: javascript:void 0
+        - img "宸ヤ笟AI鏅洪�犲钩鍙�" [ref=f3e18]
+        - generic [ref=f3e19]: 宸ヤ笟AI鏅洪�犲钩鍙�
+      - menu [ref=f3e22]:
+        - menuitem "棣栭〉" [ref=f3e23] [cursor=pointer]
+        - listitem [ref=f3e30]:
+          - generic [ref=f3e31] [cursor=pointer]: 鍩虹鏁版嵁
+        - listitem [ref=f3e39]:
+          - generic [ref=f3e40] [cursor=pointer]: 閲囪喘绠$悊
+        - listitem [ref=f3e46]:
+          - generic [ref=f3e47] [cursor=pointer]: 钀ラ攢绠$悊
+        - listitem [ref=f3e53]:
+          - generic [ref=f3e54] [cursor=pointer]: 璁惧绠$悊
+        - listitem [ref=f3e61]:
+          - generic [ref=f3e62] [cursor=pointer]: 浠撳偍鐗╂祦
+        - listitem [ref=f3e70]:
+          - generic [ref=f3e71] [cursor=pointer]: 鐢熶骇绠℃帶
+        - listitem [ref=f3e78]:
+          - generic [ref=f3e79] [cursor=pointer]: 璐ㄩ噺绠$悊
+        - listitem [ref=f3e85]:
+          - generic [ref=f3e86] [cursor=pointer]: 鍗忓悓鍔炲叕
+        - listitem [ref=f3e92]:
+          - generic [ref=f3e93] [cursor=pointer]: 浜哄姏璧勬簮
+        - listitem [ref=f3e99]:
+          - generic [ref=f3e100] [cursor=pointer]: 鍞悗绠$悊
+        - listitem [ref=f3e106]:
+          - generic [ref=f3e107] [cursor=pointer]: 鍩虹璁炬柦
+        - listitem [ref=f3e113]:
+          - generic [ref=f3e114] [cursor=pointer]: 绯荤粺绠$悊
+        - listitem [ref=f3e120]:
+          - generic [ref=f3e121] [cursor=pointer]: IM 鍗虫椂閫氳
+  - generic [ref=f3e134]:
+    - generic [ref=f3e135]:
+      - banner [ref=f3e136]:
+        - button [ref=f3e137] [cursor=pointer]
+        - button [ref=f3e140] [cursor=pointer]
+        - navigation "breadcrumb" [ref=f3e145]:
+          - list [ref=f3e146]:
+            - listitem [ref=f3e147]:
+              - link [disabled] [ref=f3e148]
+        - generic [ref=f3e155]:
+          - generic [ref=f3e157] [cursor=pointer]:
+            - generic [ref=f3e161]: 鎼滅储
+            - generic [ref=f3e162]: Ctrl K
+          - button [ref=f3e164] [cursor=pointer]
+          - button "dark" [ref=f3e169] [cursor=pointer]
+          - button [ref=f3e178] [cursor=pointer]
+          - button [ref=f3e184] [cursor=pointer]
+          - button [ref=f3e187] [cursor=pointer]
+          - button [ref=f3e193] [cursor=pointer]:
+            - button [ref=f3e195]
+          - button "宸ヤ綔鍙�" [ref=f3e199] [cursor=pointer]
+          - button [ref=f3e203] [cursor=pointer]:
+            - img "鑺嬮亾婧愮爜" [ref=f3e208]
+      - generic [ref=f3e210]:
+        - generic [ref=f3e211]: 棣栭〉
+        - button [ref=f3e233] [cursor=pointer]
+    - main [ref=f3e251]:
+      - generic [ref=f3e254]:
+        - generic [ref=f3e255]:
+          - generic [ref=f3e256]:
+            - heading "涓嬪崍濂斤紝娆㈣繋鍥炴潵" [level=1] [ref=f3e257]
+            - paragraph [ref=f3e258]: 2026骞�8鏈�3鏃� 鏄熸湡涓�
+          - generic [ref=f3e259]: 绯荤粺杩愯涓�
+        - generic [ref=f3e264]:
+          - generic [ref=f3e273] [cursor=pointer]:
+            - generic [ref=f3e274]: 鐢熶骇璁㈠崟
+            - generic [ref=f3e275]:
+              - generic [ref=f3e276]: "25"
+              - generic [ref=f3e278]: 杩涜涓�
+            - generic [ref=f3e279]:
+              - text: 寰呮帓浜� 15
+              - generic [ref=f3e281]: "|"
+              - text: 宸插畬鎴� 5
+          - generic [ref=f3e293] [cursor=pointer]:
+            - generic [ref=f3e294]: 浠婃棩浜ч噺
+            - generic [ref=f3e295]:
+              - generic [ref=f3e296]: "0"
+              - generic [ref=f3e298]: 浠�
+            - generic [ref=f3e299]: 鏄ㄦ棩 0 浠�
+          - generic [ref=f3e310] [cursor=pointer]:
+            - generic [ref=f3e311]: 璐ㄩ噺鍚堟牸鐜�
+            - generic [ref=f3e312]:
+              - generic [ref=f3e313]: "0.0"
+              - generic [ref=f3e315]: "%"
+            - generic [ref=f3e316]: 鍚堟牸 0 | 涓嶈壇 0
+          - generic [ref=f3e328] [cursor=pointer]:
+            - generic [ref=f3e329]: 璁惧杩愯鐜�
+            - generic [ref=f3e330]:
+              - generic [ref=f3e331]: "100.0"
+              - generic [ref=f3e333]: "%"
+            - generic [ref=f3e334]:
+              - generic [ref=f3e335]: 鍋滄満 0
+              - generic [ref=f3e336]: "|"
+              - generic [ref=f3e337]: 缁存姢 0
+        - generic [ref=f3e340]:
+          - generic [ref=f3e350] [cursor=pointer]:
+            - generic [ref=f3e351]: 閲囪喘璁㈠崟
+            - generic [ref=f3e352]:
+              - generic [ref=f3e353]: "14"
+              - generic [ref=f3e355]: 绗�
+            - generic [ref=f3e356]: ERP 閲囪喘绠$悊
+          - generic [ref=f3e367] [cursor=pointer]:
+            - generic [ref=f3e368]: 閿�鍞鍗�
+            - generic [ref=f3e369]:
+              - generic [ref=f3e370]: "22"
+              - generic [ref=f3e372]: 绗�
+            - generic [ref=f3e373]: ERP 閿�鍞鐞�
+          - generic [ref=f3e385] [cursor=pointer]:
+            - generic [ref=f3e386]: 鐗╂枡搴撳瓨
+            - generic [ref=f3e387]:
+              - generic [ref=f3e388]: "13"
+              - generic [ref=f3e390]: 鏉�
+            - generic [ref=f3e391]: MES 搴撳瓨鍙拌处
+          - generic [ref=f3e403] [cursor=pointer]:
+            - generic [ref=f3e404]: 鎴戠殑寰呭姙
+            - generic [ref=f3e405]:
+              - generic [ref=f3e406]: "1"
+              - generic [ref=f3e408]: 椤�
+            - generic [ref=f3e409]: BPM 寰呭鎵�
+        - generic [ref=f3e412]:
+          - generic [ref=f3e413]:
+            - heading "AI 鏅鸿兘鍒嗘瀽" [level=3] [ref=f3e414]
+            - generic [ref=f3e415]: 25 涓伐鍗曞彲鍒嗘瀽
+          - generic [ref=f3e416]:
+            - generic [ref=f3e424] [cursor=pointer]:
+              - generic [ref=f3e425]: AI 鐗╂枡棰勬祴
+              - generic [ref=f3e426]: 棰勬祴鐗╂枡闇�姹備笌鐭己椋庨櫓
+            - generic [ref=f3e435] [cursor=pointer]:
+              - generic [ref=f3e436]: AI 鏃堕暱棰勬祴
+              - generic [ref=f3e437]: 棰勬祴鍚勫伐搴忕敓浜ц�楁椂
+            - generic [ref=f3e444] [cursor=pointer]:
+              - generic [ref=f3e445]: AI 椋庨櫓棰勬祴
+              - generic [ref=f3e446]: 璇嗗埆娼滃湪鐢熶骇椋庨櫓骞剁粰鍑哄缓璁�
+            - generic [ref=f3e456] [cursor=pointer]:
+              - generic [ref=f3e457]: AI 浜や粯璇勪及
+              - generic [ref=f3e458]: 璇勪及璁㈠崟浜や粯鍑嗘椂鐜囦笌寤舵湡鍥犵礌
+        - generic [ref=f3e461]:
+          - heading "鐢熶骇瓒嬪娍锛堣繎7澶╋級" [level=3] [ref=f3e464]
+          - generic [ref=f3e469]:
+            - generic [ref=f3e470]:
+              - generic [ref=f3e476] [cursor=pointer]:
+                - generic [ref=f3e477]: 瀹夌伅鍛煎彨
+                - generic [ref=f3e478]:
+                  - generic [ref=f3e479]: "0"
+                  - generic [ref=f3e481]: 鏈缃�
+              - generic [ref=f3e487] [cursor=pointer]:
+                - generic [ref=f3e488]: 缁翠慨宸ュ崟
+                - generic [ref=f3e489]:
+                  - generic [ref=f3e490]: "0"
+                  - generic [ref=f3e492]: 寰呭鐞�
+            - heading "宸ュ崟鐘舵�佸垎甯�" [level=4] [ref=f3e494]
+        - generic [ref=f3e502]:
+          - heading "蹇嵎鎿嶄綔" [level=3] [ref=f3e503]
+          - generic [ref=f3e504]:
+            - generic [ref=f3e505] [cursor=pointer]: 鐢熶骇宸ュ崟
+            - generic [ref=f3e512] [cursor=pointer]: 鐢熶骇鎶ュ伐
+            - generic [ref=f3e519] [cursor=pointer]: 璐ㄦ绠$悊
+            - generic [ref=f3e527] [cursor=pointer]: 璁惧鐐规
+            - generic [ref=f3e534] [cursor=pointer]: 鐢熶骇鎺掔▼
+            - generic [ref=f3e541] [cursor=pointer]: 瀹夌伅鍛煎彨
+            - generic [ref=f3e546] [cursor=pointer]: 鐗╂枡搴撳瓨
+            - generic [ref=f3e554] [cursor=pointer]: 宸ヨ壓璺嚎
+            - generic [ref=f3e562] [cursor=pointer]: 鏁版嵁鎶ヨ〃
\ No newline at end of file
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/CrmContractController.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/CrmContractController.java
index 555ccd3..4de695d 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/CrmContractController.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/CrmContractController.java
@@ -19,6 +19,7 @@
 import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO;
 import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractProductDO;
 import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
+import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum;
 import cn.iocoder.yudao.module.mdm.api.item.MdmItemApi;
 import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemRespDTO;
 import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService;
@@ -159,9 +160,18 @@
     public void exportContractExcel(@Valid CrmContractPageReqVO exportReqVO,
                                     HttpServletResponse response) throws IOException {
         PageResult<CrmContractDO> pageResult = contractService.getContractPage(exportReqVO, getLoginUserId());
+        List<CrmContractRespVO> list = BeanUtils.toBean(pageResult.getList(), CrmContractRespVO.class);
+        // 璁$畻鏈洖娆鹃噾棰濄�佽浆鎹㈠鎵圭姸鎬佷负涓枃
+        list.forEach(vo -> {
+            if (vo.getTotalPrice() != null && vo.getTotalReceivablePrice() != null) {
+                vo.setUnReceivablePrice(vo.getTotalPrice().subtract(vo.getTotalReceivablePrice()));
+            }
+            if (vo.getAuditStatus() != null) {
+                vo.setAuditStatusName(CrmAuditStatusEnum.getNameByStatus(vo.getAuditStatus()));
+            }
+        });
         // 瀵煎嚭 Excel
-        ExcelUtils.write(response, "鍚堝悓.xls", "鏁版嵁", CrmContractRespVO.class,
-                BeanUtils.toBean(pageResult.getList(), CrmContractRespVO.class));
+        ExcelUtils.write(response, "鍚堝悓.xls", "鏁版嵁", CrmContractRespVO.class, list);
     }
 
     @PutMapping("/transfer")
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractRespVO.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractRespVO.java
index d33143d..4410428 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractRespVO.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractRespVO.java
@@ -17,121 +17,120 @@
 public class CrmContractRespVO {
 
     @Schema(description = "鍚堝悓缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430")
-    @ExcelProperty("鍚堝悓缂栧彿")
     private Long id;
 
     @Schema(description = "鍚堝悓鍚嶇О", requiredMode = Schema.RequiredMode.REQUIRED, example = "鐜嬩簲")
-    @ExcelProperty("鍚堝悓鍚嶇О")
+    @ExcelProperty(value = "鍚堝悓鍚嶇О", index = 1)
     private String name;
 
     @Schema(description = "鍚堝悓缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "20230101")
-    @ExcelProperty("鍚堝悓缂栧彿")
+    @ExcelProperty(value = "鍚堝悓缂栧彿", index = 0)
     private String no;
 
     @Schema(description = "瀹㈡埛缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "18336")
-    @ExcelProperty("瀹㈡埛缂栧彿")
     private Long customerId;
     @Schema(description = "瀹㈡埛鍚嶇О", requiredMode = Schema.RequiredMode.REQUIRED, example = "18336")
-    @ExcelProperty("瀹㈡埛鍚嶇О")
+    @ExcelProperty(value = "瀹㈡埛鍚嶇О", index = 2)
     private String customerName;
 
     @Schema(description = "鍟嗘満缂栧彿", example = "10864")
-    @ExcelProperty("鍟嗘満缂栧彿")
     private Long businessId;
     @Schema(description = "鍟嗘満鍚嶇О", example = "10864")
-    @ExcelProperty("鍟嗘満鍚嶇О")
+    @ExcelProperty(value = "鍟嗘満鍚嶇О", index = 3)
     private String businessName;
 
     @Schema(description = "鏈�鍚庤窡杩涙椂闂�")
-    @ExcelProperty("鏈�鍚庤窡杩涙椂闂�")
+    @ExcelProperty(value = "鏈�鍚庤窡杩涙椂闂�", index = 14)
     private LocalDateTime contactLastTime;
 
     @Schema(description = "璐熻矗浜虹殑鐢ㄦ埛缂栧彿", example = "25682")
-    @ExcelProperty("璐熻矗浜虹殑鐢ㄦ埛缂栧彿")
     private Long ownerUserId;
     @Schema(description = "璐熻矗浜哄悕瀛�", example = "25682")
-    @ExcelProperty("璐熻矗浜哄悕瀛�")
+    @ExcelProperty(value = "璐熻矗浜�", index = 15)
     private String ownerUserName;
     @Schema(description = "璐熻矗浜洪儴闂�")
-    @ExcelProperty("璐熻矗浜洪儴闂�")
+    @ExcelProperty(value = "鎵�灞為儴闂�", index = 16)
     private String ownerUserDeptName;
 
     @Schema(description = "宸ヤ綔娴佺紪鍙�", example = "1043")
-    @ExcelProperty("宸ヤ綔娴佺紪鍙�")
     private String processInstanceId;
 
     @Schema(description = "瀹℃壒鐘舵��", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
-    @ExcelProperty("瀹℃壒鐘舵��")
     private Integer auditStatus;
 
+    @Schema(description = "鍚堝悓鐘舵�佸悕绉�", example = "瀹℃壒涓�")
+    @ExcelProperty(value = "鍚堝悓鐘舵��", index = 20)
+    private String auditStatusName;
+
     @Schema(description = "涓嬪崟鏃ユ湡", requiredMode = Schema.RequiredMode.REQUIRED)
-    @ExcelProperty("涓嬪崟鏃ユ湡")
+    @ExcelProperty(value = "涓嬪崟鏃堕棿", index = 6)
     private LocalDateTime orderDate;
 
     @Schema(description = "寮�濮嬫椂闂�")
-    @ExcelProperty("寮�濮嬫椂闂�")
+    @ExcelProperty(value = "鍚堝悓寮�濮嬫椂闂�", index = 7)
     private LocalDateTime startTime;
 
     @Schema(description = "缁撴潫鏃堕棿")
-    @ExcelProperty("缁撴潫鏃堕棿")
+    @ExcelProperty(value = "鍚堝悓缁撴潫鏃堕棿", index = 8)
     private LocalDateTime endTime;
 
     @Schema(description = "浜у搧鎬婚噾棰�", example = "19510")
-    @ExcelProperty("浜у搧鎬婚噾棰�")
     private BigDecimal totalProductPrice;
 
     @Schema(description = "鏁村崟鎶樻墸")
-    @ExcelProperty("鏁村崟鎶樻墸")
     private BigDecimal discountPercent;
 
     @Schema(description = "鍚堝悓閲戦", example = "5617")
-    @ExcelProperty("鍚堝悓閲戦")
+    @ExcelProperty(value = "鍚堝悓閲戦锛堝厓锛�", index = 4)
     private BigDecimal totalPrice;
 
     @Schema(description = "瀹氶噾閲戦锛屽崟浣嶏細鍏�", example = "1000.00")
-    @ExcelProperty("瀹氶噾閲戦")
+    @ExcelProperty(value = "瀹氶噾閲戦锛堝厓锛�", index = 5)
     private BigDecimal depositPrice;
 
     @Schema(description = "宸插洖娆鹃噾棰�", example = "5617")
-    @ExcelProperty("宸插洖娆鹃噾棰�")
+    @ExcelProperty(value = "宸插洖娆鹃噾棰濓紙鍏冿級", index = 12)
     private BigDecimal totalReceivablePrice;
+
+    @Schema(description = "鏈洖娆鹃噾棰濓紝绛変簬 鍚堝悓閲戦 - 宸插洖娆鹃噾棰�", example = "1000.00")
+    @ExcelProperty(value = "鏈洖娆鹃噾棰濓紙鍏冿級", index = 13)
+    private BigDecimal unReceivablePrice;
 
     @Schema(description = "鍏宠仈 ERP 閿�鍞鍗曠紪鍙�", example = "12345")
     private Long orderId;
     @Schema(description = "ERP 閿�鍞鍗曞崟鍙�", example = "SO001")
-    @ExcelProperty("閿�鍞鍗曞崟鍙�")
+    @ExcelProperty(value = "鍏宠仈璁㈠崟", index = 21)
     private String orderNo;
 
     @Schema(description = "瀹㈡埛绛剧害浜虹紪鍙�", example = "18546")
     private Long signContactId;
     @Schema(description = "瀹㈡埛绛剧害浜�", example = "灏忚眴")
-    @ExcelProperty("瀹㈡埛绛剧害浜�")
+    @ExcelProperty(value = "瀹㈡埛绛剧害浜�", index = 9)
     private String signContactName;
 
     @Schema(description = "鍏徃绛剧害浜�", example = "14036")
     private Long signUserId;
     @Schema(description = "鍏徃绛剧害浜�", example = "灏忔槑")
-    @ExcelProperty("鍏徃绛剧害浜�")
+    @ExcelProperty(value = "鍏徃绛剧害浜�", index = 10)
     private String signUserName;
 
     @Schema(description = "澶囨敞", example = "浣犵寽")
-    @ExcelProperty("澶囨敞")
+    @ExcelProperty(value = "澶囨敞", index = 11)
     private String remark;
 
     @Schema(description = "鍒涘缓鏃堕棿", requiredMode = Schema.RequiredMode.REQUIRED)
-    @ExcelProperty("鍒涘缓鏃堕棿")
+    @ExcelProperty(value = "鍒涘缓鏃堕棿", index = 18)
     private LocalDateTime createTime;
 
     @Schema(description = "鍒涘缓浜�", example = "25682")
-    @ExcelProperty("鍒涘缓浜�")
     private String creator;
 
     @Schema(description = "鍒涘缓浜哄悕瀛�", example = "test")
-    @ExcelProperty("鍒涘缓浜哄悕瀛�")
+    @ExcelProperty(value = "鍒涘缓浜�", index = 19)
     private String creatorName;
 
     @Schema(description = "鏇存柊鏃堕棿", requiredMode = Schema.RequiredMode.REQUIRED)
-    @ExcelProperty("鏇存柊鏃堕棿")
+    @ExcelProperty(value = "鏇存柊鏃堕棿", index = 17)
     private LocalDateTime updateTime;
 
     @Schema(description = "浜у搧鍒楄〃")
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/common/CrmAuditStatusEnum.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/common/CrmAuditStatusEnum.java
index b23de46..394652d 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/common/CrmAuditStatusEnum.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/common/CrmAuditStatusEnum.java
@@ -27,6 +27,14 @@
 
     public static final Integer[] ARRAYS = Arrays.stream(values()).map(CrmAuditStatusEnum::getStatus).toArray(Integer[]::new);
 
+    public static String getNameByStatus(Integer status) {
+        if (status == null) return null;
+        for (CrmAuditStatusEnum e : values()) {
+            if (e.getStatus().equals(status)) return e.getName();
+        }
+        return null;
+    }
+
     @Override
     public Integer[] array() {
         return ARRAYS;
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/MdmItemController.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/MdmItemController.java
index 1e51193..461e65e 100644
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/MdmItemController.java
+++ b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/MdmItemController.java
@@ -189,7 +189,17 @@
     @Operation(summary = "鑾峰彇鐗╂枡绮剧畝鍒楄〃锛堝惎鐢ㄧ姸鎬侊紝鐢ㄤ簬涓嬫媺閫夋嫨锛�")
     public CommonResult<List<MdmItemRespVO>> getItemSimpleList() {
         List<MdmItemDO> list = itemService.getItemSimpleList();
-        return success(BeanUtils.toBean(list, MdmItemRespVO.class));
+        List<MdmItemRespVO> respList = BeanUtils.toBean(list, MdmItemRespVO.class);
+        // 濉厖鍗曚綅鍚嶇О绛夊叧鑱斿瓧娈碉紝纭繚涓嬫媺閫夋嫨鍚庡彲甯﹀嚭鍗曚綅绛変俊鎭�
+        Map<Long, MdmUnitMeasureDO> unitMap = unitMeasureService.getUnitMeasureMap(
+                convertSet(respList, MdmItemRespVO::getUnitMeasureId));
+        respList.forEach(resp -> {
+            MdmUnitMeasureDO unit = unitMap.get(resp.getUnitMeasureId());
+            if (unit != null) {
+                resp.setUnitMeasureName(unit.getName());
+            }
+        });
+        return success(respList);
     }
 
     /**
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/MesMdItemController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/MesMdItemController.java
index b9d9492..1e58218 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/MesMdItemController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/MesMdItemController.java
@@ -8,8 +8,6 @@
 import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
-import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.MesMdItemImportExcelVO;
-import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.MesMdItemImportRespVO;
 import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.MesMdItemPageReqVO;
 import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.MesMdItemRespVO;
 import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.MesMdItemSaveReqVO;
@@ -29,7 +27,6 @@
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
-import org.springframework.web.multipart.MultipartFile;
 
 import java.io.IOException;
 import java.util.Collections;
@@ -118,32 +115,6 @@
         // 瀵煎嚭 Excel
         ExcelUtils.write(response, "鐗╂枡浜у搧.xls", "鏁版嵁", MesMdItemRespVO.class,
                 buildItemVOList(pageResult.getList()));
-    }
-
-    @GetMapping("/get-import-template")
-    @Operation(summary = "鑾峰緱鐗╂枡瀵煎叆妯℃澘")
-    public void importTemplate(HttpServletResponse response) throws IOException {
-        // 鎵嬪姩鍒涘缓瀵煎嚭 demo
-        List<MesMdItemImportExcelVO> list = Collections.singletonList(
-                MesMdItemImportExcelVO.builder().code("ITEM001").name("铻轰笣").specification("M6*20")
-                        .unitMeasureCode("PCS").itemTypeId(1L).status(0).build()
-        );
-        // 杈撳嚭
-        ExcelUtils.write(response, "鐗╂枡瀵煎叆妯℃澘.xls", "鐗╂枡鍒楄〃", MesMdItemImportExcelVO.class, list);
-    }
-
-    @PostMapping("/import")
-    @Operation(summary = "瀵煎叆鐗╂枡")
-    @Parameters({
-            @Parameter(name = "file", description = "Excel 鏂囦欢", required = true),
-            @Parameter(name = "updateSupport", description = "鏄惁鏀寔鏇存柊锛岄粯璁や负 false", example = "true")
-    })
-    @PreAuthorize("@ss.hasPermission('mes:md-item:import')")
-    public CommonResult<MesMdItemImportRespVO> importExcel(@RequestParam("file") MultipartFile file,
-                                                           @RequestParam(value = "updateSupport", required = false,
-                                                                   defaultValue = "false") Boolean updateSupport) throws Exception {
-        List<MesMdItemImportExcelVO> list = ExcelUtils.read(file, MesMdItemImportExcelVO.class);
-        return success(itemService.importItemList(list, updateSupport));
     }
 
     // ==================== 鎷兼帴 VO ====================
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/MesMdItemImportExcelVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/MesMdItemImportExcelVO.java
deleted file mode 100644
index dee51f7..0000000
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/MesMdItemImportExcelVO.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package cn.iocoder.yudao.module.mes.controller.admin.md.item.vo;
-
-import cn.idev.excel.annotation.ExcelProperty;
-import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
-import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
-import cn.iocoder.yudao.module.system.enums.DictTypeConstants;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-import java.math.BigDecimal;
-
-/**
- * 鐗╂枡浜у搧 Excel 瀵煎叆 VO
- */
-@Data
-@Builder
-@AllArgsConstructor
-@NoArgsConstructor
-public class MesMdItemImportExcelVO {
-
-    @ExcelProperty("鐗╂枡缂栫爜")
-    private String code;
-
-    @ExcelProperty("鐗╂枡鍚嶇О")
-    private String name;
-
-    @ExcelProperty("瑙勬牸鍨嬪彿")
-    private String specification;
-
-    @ExcelProperty("鍗曚綅缂栫爜")
-    private String unitMeasureCode;
-
-    @ExcelProperty("鐗╂枡鍒嗙被缂栧彿")
-    private Long itemTypeId;
-
-    @ExcelProperty(value = "鐘舵��", converter = DictConvert.class)
-    @DictFormat(DictTypeConstants.COMMON_STATUS)
-    private Integer status;
-
-    @ExcelProperty("鏄惁鍚敤瀹夊叏搴撳瓨")
-    private Boolean safeStockFlag;
-
-    @ExcelProperty("鏈�浣庡簱瀛橀噺")
-    private BigDecimal minStock;
-
-    @ExcelProperty("鏈�楂樺簱瀛橀噺")
-    private BigDecimal maxStock;
-
-    @ExcelProperty("鏄惁楂樺�肩墿鏂�")
-    private Boolean highValue;
-
-    @ExcelProperty("鏄惁鍚敤鎵规绠$悊")
-    private Boolean batchFlag;
-
-    @ExcelProperty("澶囨敞")
-    private String remark;
-
-}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/MesMdItemImportRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/MesMdItemImportRespVO.java
deleted file mode 100644
index de3f51b..0000000
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/MesMdItemImportRespVO.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package cn.iocoder.yudao.module.mes.controller.admin.md.item.vo;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Builder;
-import lombok.Data;
-
-import java.util.List;
-import java.util.Map;
-
-@Schema(description = "绠$悊鍚庡彴 - MES 鐗╂枡浜у搧瀵煎叆 Response VO")
-@Data
-@Builder
-public class MesMdItemImportRespVO {
-
-    @Schema(description = "鍒涘缓鎴愬姛鐨勭墿鏂欑紪鐮佹暟缁�", requiredMode = Schema.RequiredMode.REQUIRED)
-    private List<String> createCodes;
-
-    @Schema(description = "鏇存柊鎴愬姛鐨勭墿鏂欑紪鐮佹暟缁�", requiredMode = Schema.RequiredMode.REQUIRED)
-    private List<String> updateCodes;
-
-    @Schema(description = "瀵煎叆澶辫触鐨勭墿鏂欓泦鍚堬紝key 涓虹墿鏂欑紪鐮侊紝value 涓哄け璐ュ師鍥�", requiredMode = Schema.RequiredMode.REQUIRED)
-    private Map<String, String> failureCodes;
-
-}
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 eb2ae1a..5c661bc 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
@@ -33,7 +33,6 @@
     ErrorCode MD_ITEM_NOT_EXISTS = new ErrorCode(1_040_102_000, "鐗╂枡涓嶅瓨鍦�");
     ErrorCode MD_ITEM_CODE_DUPLICATE = new ErrorCode(1_040_102_001, "鐗╂枡缂栫爜宸插瓨鍦�");
     ErrorCode MD_ITEM_NAME_DUPLICATE = new ErrorCode(1_040_102_002, "鐗╂枡鍚嶇О宸插瓨鍦�");
-    ErrorCode MD_ITEM_IMPORT_LIST_IS_EMPTY = new ErrorCode(1_040_102_003, "瀵煎叆鐗╂枡鏁版嵁涓嶈兘涓虹┖");
     ErrorCode MD_ITEM_BATCH_REQUIRED = new ErrorCode(1_040_102_004, "褰撳墠鐗╂枡鍚敤浜嗘壒娆$鐞嗭紝璇烽�夋嫨鎵规");
     ErrorCode MD_ITEM_IS_DISABLE = new ErrorCode(1_040_102_005, "鐗╂枡宸茬鐢�");
 
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdItemService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdItemService.java
index a8b407a..5159a16 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdItemService.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdItemService.java
@@ -1,8 +1,6 @@
 package cn.iocoder.yudao.module.mes.service.md.item;
 
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.MesMdItemImportExcelVO;
-import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.MesMdItemImportRespVO;
 import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.MesMdItemPageReqVO;
 import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.MesMdItemSaveReqVO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
@@ -116,15 +114,6 @@
      * @return 鐗╂枡鏁伴噺
      */
     Long getItemCountByItemTypeId(Long itemTypeId);
-
-    /**
-     * 鎵归噺瀵煎叆鐗╂枡
-     *
-     * @param importItems 瀵煎叆鐗╂枡鍒楄〃
-     * @param updateSupport 鏄惁鏀寔鏇存柊
-     * @return 瀵煎叆缁撴灉
-     */
-    MesMdItemImportRespVO importItemList(List<MesMdItemImportExcelVO> importItems, boolean updateSupport);
 
     /**
      * 鍩轰簬璁¢噺鍗曚綅缂栧彿锛岃幏寰楃墿鏂欐暟閲�
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdItemServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdItemServiceImpl.java
index c8f85a6..fcefee0 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdItemServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdItemServiceImpl.java
@@ -2,12 +2,8 @@
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ObjUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.iocoder.yudao.framework.common.exception.ServiceException;
 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.md.item.vo.MesMdItemImportExcelVO;
-import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.MesMdItemImportRespVO;
 import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.MesMdItemPageReqVO;
 import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.MesMdItemSaveReqVO;
 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
@@ -17,7 +13,7 @@
 import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO;
 import cn.iocoder.yudao.module.mes.dal.mysql.md.item.MesMdItemMapper;
 import cn.iocoder.yudao.module.mes.enums.md.MesMdItemTypeEnum;
-import cn.iocoder.yudao.module.mes.enums.md.autocode.MesMdAutoCodeRuleCodeEnum;
+
 import cn.iocoder.yudao.module.mes.enums.wm.BarcodeBizTypeEnum;
 import cn.iocoder.yudao.module.mes.service.md.unitmeasure.MesMdUnitMeasureService;
 import cn.iocoder.yudao.module.mes.service.md.autocode.MesMdAutoCodeRecordService;
@@ -31,7 +27,6 @@
 
 import java.math.BigDecimal;
 import java.util.*;
-import java.util.concurrent.atomic.AtomicInteger;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
@@ -308,94 +303,6 @@
     @Override
     public Long getItemCountByUnitMeasureId(Long unitMeasureId) {
         return itemMapper.selectCountByUnitMeasureId(unitMeasureId);
-    }
-
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public MesMdItemImportRespVO importItemList(List<MesMdItemImportExcelVO> importItems, boolean updateSupport) {
-        // 1. 鍙傛暟鏍¢獙
-        if (CollUtil.isEmpty(importItems)) {
-            throw exception(MD_ITEM_IMPORT_LIST_IS_EMPTY);
-        }
-
-        // 2. 閬嶅巻锛岄�愪釜鍒涘缓 or 鏇存柊
-        MesMdItemImportRespVO respVO = MesMdItemImportRespVO.builder()
-                .createCodes(new ArrayList<>()).updateCodes(new ArrayList<>())
-                .failureCodes(new LinkedHashMap<>()).build();
-        AtomicInteger index = new AtomicInteger(1);
-        importItems.forEach(importItem -> {
-            int currentIndex = index.getAndIncrement();
-            // 2.1 鏍¢獙瀛楁
-            if (StrUtil.isBlank(importItem.getCode())) {
-                // 绌虹紪鐮佹椂鑷姩鐢熸垚
-                importItem.setCode(autoCodeRecordService.generateAutoCode(MesMdAutoCodeRuleCodeEnum.MD_ITEM_CODE.getCode()));
-            }
-            String key = importItem.getCode();
-            if (StrUtil.isBlank(importItem.getName())) {
-                respVO.getFailureCodes().put(key, "鐗╂枡鍚嶇О涓嶈兘涓虹┖");
-                return;
-            }
-            if (StrUtil.isBlank(importItem.getUnitMeasureCode())) {
-                respVO.getFailureCodes().put(key, "鍗曚綅缂栫爜涓嶈兘涓虹┖");
-                return;
-            }
-            // 灏嗗崟浣嶇紪鐮佽浆鎹负鍗曚綅 ID
-            MesMdUnitMeasureDO unitMeasure = unitMeasureService.getUnitMeasureByCode(importItem.getUnitMeasureCode());
-            if (unitMeasure == null) {
-                respVO.getFailureCodes().put(key, "鍗曚綅缂栫爜[" + importItem.getUnitMeasureCode() + "]涓嶅瓨鍦�");
-                return;
-            }
-            if (importItem.getItemTypeId() == null) {
-                respVO.getFailureCodes().put(key, "鐗╂枡鍒嗙被缂栧彿涓嶈兘涓虹┖");
-                return;
-            }
-            // 2.2 鏍¢獙鍒嗙被鏄惁瀛樺湪
-            try {
-                validateItemTypeExists(importItem.getItemTypeId());
-            } catch (ServiceException ex) {
-                respVO.getFailureCodes().put(key, ex.getMessage());
-                return;
-            }
-
-            // 2.3 鍒ゆ柇锛氬垱寤� or 鏇存柊
-            MesMdItemDO existItem = itemMapper.selectByCode(importItem.getCode());
-            if (existItem == null) {
-                // 2.3.1 鍒涘缓
-                try {
-                    validateItemNameUnique(null, importItem.getName());
-                } catch (ServiceException ex) {
-                    respVO.getFailureCodes().put(key, ex.getMessage());
-                    return;
-                }
-                MesMdItemDO item = BeanUtils.toBean(importItem, MesMdItemDO.class);
-                item.setUnitMeasureId(unitMeasure.getId());
-                item.setStatus(CommonStatusEnum.DISABLE.getStatus()); // 榛樿绂佺敤銆備俊鎭畬鎴愬悗锛屽啀鍚敤
-                clearStockIfNotSafe(item);
-                itemMapper.insert(item);
-                // 鑷姩鐢熸垚鏉$爜
-                barcodeService.autoGenerateBarcode(BarcodeBizTypeEnum.ITEM.getValue(),
-                        item.getId(), item.getCode(), item.getName());
-                respVO.getCreateCodes().add(importItem.getCode());
-            } else if (updateSupport) {
-                // 2.3.2 鏇存柊
-                try {
-                    validateItemNameUnique(existItem.getId(), importItem.getName());
-                } catch (ServiceException ex) {
-                    respVO.getFailureCodes().put(key, ex.getMessage());
-                    return;
-                }
-                MesMdItemDO updateObj = BeanUtils.toBean(importItem, MesMdItemDO.class);
-                updateObj.setId(existItem.getId());
-                updateObj.setUnitMeasureId(unitMeasure.getId());
-                clearStockIfNotSafe(updateObj);
-                itemMapper.updateById(updateObj);
-                respVO.getUpdateCodes().add(importItem.getCode());
-            } else {
-                // 涓嶆敮鎸佹洿鏂�
-                respVO.getFailureCodes().put(key, "鐗╂枡缂栫爜宸插瓨鍦�");
-            }
-        });
-        return respVO;
     }
 
     /**
diff --git a/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/controller/admin/supplier/vo/SrmSupplierPageReqVO.java b/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/controller/admin/supplier/vo/SrmSupplierPageReqVO.java
index 8302ac8..833469d 100644
--- a/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/controller/admin/supplier/vo/SrmSupplierPageReqVO.java
+++ b/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/controller/admin/supplier/vo/SrmSupplierPageReqVO.java
@@ -33,4 +33,7 @@
     @Schema(description = "浠呮樉绀哄凡閫氳繃鍑嗗叆瀹℃壒鐨勪緵搴斿晢")
     private Boolean approved;
 
+    @Schema(description = "鎺掗櫎宸查�氳繃鍑嗗叆瀹℃壒鐨勪緵搴斿晢锛堢敤浜庢柊澧炲噯鍏ユ椂閬垮厤閲嶅閫夋嫨锛�")
+    private Boolean excludeApproved;
+
 }
diff --git a/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/controller/admin/tender/SrmTenderProjectController.java b/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/controller/admin/tender/SrmTenderProjectController.java
index feb776a..6ad8a2b 100644
--- a/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/controller/admin/tender/SrmTenderProjectController.java
+++ b/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/controller/admin/tender/SrmTenderProjectController.java
@@ -96,6 +96,14 @@
         return success(true);
     }
 
+    @PutMapping("/update-info")
+    @Operation(summary = "閮ㄥ垎鏇存柊鎷涙爣淇℃伅锛堜粎鍙戝竷涓�/鎶曟爣涓彲缂栬緫锛氭嫑鏍囪鏄庡拰璧勮川瑕佹眰锛�")
+    @PreAuthorize("@ss.hasPermission('srm:tender-project:update')")
+    public CommonResult<Boolean> updateTenderProjectInfo(@Valid @RequestBody SrmTenderProjectPartialUpdateReqVO updateReqVO) {
+        tenderProjectService.updateTenderProjectPartial(updateReqVO);
+        return success(true);
+    }
+
     // ========== 鐗╂枡瀛愯〃 ==========
 
     @PostMapping("/material/create")
diff --git a/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/controller/admin/tender/vo/SrmTenderProjectPartialUpdateReqVO.java b/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/controller/admin/tender/vo/SrmTenderProjectPartialUpdateReqVO.java
new file mode 100644
index 0000000..0b8aa99
--- /dev/null
+++ b/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/controller/admin/tender/vo/SrmTenderProjectPartialUpdateReqVO.java
@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.module.srm.controller.admin.tender.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+@Schema(description = "绠$悊鍚庡彴 - SRM 鎷涙爣椤圭洰閮ㄥ垎鏇存柊 Request VO锛堝彂甯冧腑/鎶曟爣涓樁娈碉級")
+@Data
+public class SrmTenderProjectPartialUpdateReqVO {
+
+    @Schema(description = "椤圭洰ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    @NotNull(message = "椤圭洰ID涓嶈兘涓虹┖")
+    private Long id;
+
+    @Schema(description = "鎷涙爣鎻忚堪", example = "鏈鎷涙爣閲囪喘閽㈡潗涓�鎵�")
+    private String tenderDesc;
+
+    @Schema(description = "璧勮川瑕佹眰", example = "闇�鍏峰ISO9001璁よ瘉")
+    private String qualificationRequirements;
+
+}
diff --git a/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/dal/mysql/SrmSupplierMapper.java b/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/dal/mysql/SrmSupplierMapper.java
index a5ae79c..398696d 100644
--- a/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/dal/mysql/SrmSupplierMapper.java
+++ b/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/dal/mysql/SrmSupplierMapper.java
@@ -26,6 +26,9 @@
         if (Boolean.TRUE.equals(reqVO.getApproved())) {
             wrapper.apply("id IN (SELECT supplier_id FROM srm_supplier_apply WHERE apply_status = 40 AND supplier_id IS NOT NULL AND deleted = 0)");
         }
+        if (Boolean.TRUE.equals(reqVO.getExcludeApproved())) {
+            wrapper.apply("id NOT IN (SELECT supplier_id FROM srm_supplier_apply WHERE apply_status = 40 AND supplier_id IS NOT NULL AND deleted = 0)");
+        }
         return selectPage(reqVO, wrapper);
     }
 
diff --git a/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/dal/mysql/SrmTenderBidMapper.java b/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/dal/mysql/SrmTenderBidMapper.java
index 766e20c..d98ca53 100644
--- a/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/dal/mysql/SrmTenderBidMapper.java
+++ b/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/dal/mysql/SrmTenderBidMapper.java
@@ -26,4 +26,9 @@
                 .eq(SrmTenderBidDO::getBidNo, bidNo));
     }
 
+    default long countByTenderProjectId(Long tenderProjectId) {
+        return selectCount(new LambdaQueryWrapperX<SrmTenderBidDO>()
+                .eq(SrmTenderBidDO::getTenderProjectId, tenderProjectId));
+    }
+
 }
diff --git a/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/enums/ErrorCodeConstants.java b/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/enums/ErrorCodeConstants.java
index e685314..106b948 100644
--- a/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/enums/ErrorCodeConstants.java
+++ b/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/enums/ErrorCodeConstants.java
@@ -48,6 +48,17 @@
     ErrorCode AWARD_SUPPLIER_NOT_SYNCED = new ErrorCode(1_040_500_014, "渚涘簲鍟嗘湭鍚屾鑷矱RP锛屾棤娉曠敓鎴愰噰璐鍗�");
     ErrorCode AWARD_QUOTE_NOT_EXISTS = new ErrorCode(1_040_500_015, "涓爣渚涘簲鍟嗘姤浠蜂笉瀛樺湪");
 
+    // 鐘舵�佹牎楠岀簿缁嗗寲閿欒鐮�
+    ErrorCode TENDER_MATERIAL_LOCKED = new ErrorCode(1_040_500_022, "鐗╂枡娓呭崟宸查攣瀹氾紝涓嶅厑璁稿鍒犳敼");
+    ErrorCode TENDER_BID_FORBIDDEN = new ErrorCode(1_040_500_023, "褰撳墠鐘舵�佷笉鍏佽鏂板鎶曟爣");
+    ErrorCode TENDER_QUOTE_FORBIDDEN = new ErrorCode(1_040_500_024, "褰撳墠鐘舵�佷笉鍏佽鎶ヤ环鎿嶄綔");
+    ErrorCode TENDER_END_TIME_PASSED = new ErrorCode(1_040_500_025, "鎶曟爣鎴鏃堕棿宸茶繃锛屼笉鍏佽鏂板鎶曟爣");
+    ErrorCode TENDER_PROJECT_LOCKED = new ErrorCode(1_040_500_026, "椤圭洰宸查攣瀹氾紝褰撳墠鐘舵�佷笉鍏佽鎿嶄綔");
+    ErrorCode TENDER_HAS_BIDS_CANNOT_DELETE = new ErrorCode(1_040_500_027, "宸插瓨鍦ㄦ姇鏍囨暟鎹紝涓嶅厑璁稿垹闄�");
+    ErrorCode TENDER_BID_FORBIDDEN_WITHDRAW = new ErrorCode(1_040_500_028, "褰撳墠鐘舵�佷笉鍏佽鎾ゆ爣");
+    ErrorCode TENDER_EVALUATION_FORBIDDEN = new ErrorCode(1_040_500_029, "褰撳墠鐘舵�佷笉鍏佽璇勬爣鎿嶄綔");
+    ErrorCode TENDER_AWARD_FORBIDDEN = new ErrorCode(1_040_500_030, "褰撳墠鐘舵�佷笉鍏佽瀹氭爣鎿嶄綔");
+
     // ========== 閫氱敤 ==========
     ErrorCode QUOTE_MATERIAL_DUPLICATE = new ErrorCode(1_040_900_001, "璇ユ姇鏍囧凡瀛樺湪鐩稿悓鐗╂枡鐨勬姤浠�");
 
diff --git a/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/enums/LogRecordConstants.java b/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/enums/LogRecordConstants.java
new file mode 100644
index 0000000..6d6cb50
--- /dev/null
+++ b/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/enums/LogRecordConstants.java
@@ -0,0 +1,45 @@
+package cn.iocoder.yudao.module.srm.enums;
+
+/**
+ * SRM 鎿嶄綔鏃ュ織甯搁噺
+ */
+public interface LogRecordConstants {
+
+    // ======================= SRM_TENDER 鎷涙爣椤圭洰 =======================
+    String LOG_TENDER_TYPE = "SRM 鎷涙爣椤圭洰";
+    String LOG_TENDER_UPDATE_SUB_TYPE = "鏇存柊鎷涙爣椤圭洰";
+    String LOG_TENDER_UPDATE_SUCCESS = "鏇存柊浜嗘嫑鏍囬」鐩�恵{#tenderName}}銆戯紝"
+            + "鎷涙爣璇存槑锛歿{#oldTenderDesc}} 鈫� {{#newTenderDesc}}锛�"
+            + "璧勮川瑕佹眰锛歿{#oldQualification}} 鈫� {{#newQualification}}";
+
+    // ======================= SRM_BID 鎶曟爣 =======================
+    String LOG_BID_TYPE = "SRM 鎶曟爣";
+    String LOG_BID_CREATE_SUB_TYPE = "鍒涘缓鎶曟爣";
+    String LOG_BID_CREATE_SUCCESS = "渚涘簲鍟嗗鎷涙爣椤圭洰銆恵{#tenderName}}銆戞彁浜や簡鎶曟爣銆恵{#bidNo}}銆�";
+    String LOG_BID_WITHDRAW_SUB_TYPE = "鎾ゆ爣";
+    String LOG_BID_WITHDRAW_SUCCESS = "鎾ゅ洖浜嗘姇鏍囥�恵{#bidNo}}銆�";
+
+    // ======================= SRM_QUOTE 鎶ヤ环 =======================
+    String LOG_QUOTE_TYPE = "SRM 鎶ヤ环";
+    String LOG_QUOTE_CREATE_SUB_TYPE = "鍒涘缓鎶ヤ环";
+    String LOG_QUOTE_CREATE_SUCCESS = "鎻愪氦浜嗘姇鏍囩殑渚涘簲鍟嗘姤浠�";
+    String LOG_QUOTE_UPDATE_SUB_TYPE = "鏇存柊鎶ヤ环";
+    String LOG_QUOTE_UPDATE_SUCCESS = "鏇存柊浜嗘姇鏍囩殑渚涘簲鍟嗘姤浠�";
+
+    // ======================= SRM_EVALUATION 璇勬爣 =======================
+    String LOG_EVALUATION_TYPE = "SRM 璇勬爣";
+    String LOG_EVALUATION_CREATE_SUB_TYPE = "鍒涘缓璇勬爣";
+    String LOG_EVALUATION_CREATE_SUCCESS = "瀵规嫑鏍囬」鐩繘琛屼簡璇勬爣璇勫垎";
+    String LOG_EVALUATION_UPDATE_SUB_TYPE = "鏇存柊璇勬爣";
+    String LOG_EVALUATION_UPDATE_SUCCESS = "鏇存柊浜嗚瘎鏍囪褰�";
+
+    // ======================= SRM_AWARD 瀹氭爣 =======================
+    String LOG_AWARD_TYPE = "SRM 瀹氭爣";
+    String LOG_AWARD_CREATE_SUB_TYPE = "鍒涘缓瀹氭爣";
+    String LOG_AWARD_CREATE_SUCCESS = "鍒涘缓浜嗗畾鏍囥�恵{#createReqVO.awardNo}}銆�";
+    String LOG_AWARD_APPROVE_SUB_TYPE = "瀹℃壒瀹氭爣";
+    String LOG_AWARD_APPROVE_SUCCESS = "瀹℃壒閫氳繃浜嗗畾鏍囪褰�";
+    String LOG_AWARD_ORDER_SUB_TYPE = "鐢熸垚閲囪喘璁㈠崟";
+    String LOG_AWARD_ORDER_SUCCESS = "瀹氭爣璁板綍鐢熸垚浜嗛噰璐鍗�";
+
+}
diff --git a/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/enums/TenderStatusEnum.java b/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/enums/TenderStatusEnum.java
index f567c33..ca84fba 100644
--- a/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/enums/TenderStatusEnum.java
+++ b/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/enums/TenderStatusEnum.java
@@ -23,4 +23,41 @@
     private final Integer code;
     private final String name;
 
+    // ========== 鐘舵�佸伐鍏锋柟娉� ==========
+
+    /** DRAFT 鍏佽鍏ㄥ瓧娈电紪杈� */
+    public static boolean canEditFullProject(Integer status) {
+        return DRAFT.getCode().equals(status);
+    }
+
+    /** PUBLISHED 鎴� BIDDING 鍏佽閮ㄥ垎缂栬緫锛堟嫑鏍囪鏄庛�佽祫璐ㄨ姹傦級 */
+    public static boolean canEditPartialProject(Integer status) {
+        return PUBLISHED.getCode().equals(status) || BIDDING.getCode().equals(status);
+    }
+
+    /** DRAFT 鍏佽缂栬緫鐗╂枡娓呭崟 */
+    public static boolean canEditMaterial(Integer status) {
+        return DRAFT.getCode().equals(status);
+    }
+
+    /** PUBLISHED 鎴� BIDDING 鍏佽渚涘簲鍟嗘姇鏍� */
+    public static boolean canCreateBid(Integer status) {
+        return PUBLISHED.getCode().equals(status) || BIDDING.getCode().equals(status);
+    }
+
+    /** PUBLISHED 鎴� BIDDING 鍏佽渚涘簲鍟嗘姤浠� */
+    public static boolean canCreateOrUpdateQuote(Integer status) {
+        return PUBLISHED.getCode().equals(status) || BIDDING.getCode().equals(status);
+    }
+
+    /** EVALUATING 鍏佽璇勬爣鎿嶄綔 */
+    public static boolean canEvaluate(Integer status) {
+        return EVALUATING.getCode().equals(status);
+    }
+
+    /** EVALUATING 鍏佽瀹氭爣鎿嶄綔 */
+    public static boolean canAward(Integer status) {
+        return EVALUATING.getCode().equals(status);
+    }
+
 }
diff --git a/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/tender/SrmBidAwardServiceImpl.java b/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/tender/SrmBidAwardServiceImpl.java
index 962feb8..6104b97 100644
--- a/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/tender/SrmBidAwardServiceImpl.java
+++ b/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/tender/SrmBidAwardServiceImpl.java
@@ -14,6 +14,7 @@
 import cn.iocoder.yudao.module.srm.enums.BidStatusEnum;
 import cn.iocoder.yudao.module.srm.enums.ErrorCodeConstants;
 import cn.iocoder.yudao.module.srm.enums.TenderStatusEnum;
+import com.mzt.logapi.starter.annotation.LogRecord;
 import jakarta.annotation.Resource;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
@@ -25,6 +26,8 @@
 import java.util.*;
 import java.util.function.Function;
 import java.util.stream.Collectors;
+
+import static cn.iocoder.yudao.module.srm.enums.LogRecordConstants.*;
 
 /**
  * SRM 瀹氭爣绠$悊 Service 瀹炵幇绫�
@@ -60,7 +63,14 @@
 
     @Override
     @Transactional(rollbackFor = Exception.class)
+    @LogRecord(type = LOG_AWARD_TYPE, subType = LOG_AWARD_CREATE_SUB_TYPE,
+            bizNo = "{{#createReqVO.awardNo}}", success = LOG_AWARD_CREATE_SUCCESS)
     public Long createAward(SrmBidAwardSaveReqVO createReqVO) {
+        // 妫�鏌ユ嫑鏍囬」鐩姸鎬侊細浠� EVALUATING 鍏佽鍒涘缓瀹氭爣
+        SrmTenderProjectDO project = tenderProjectMapper.selectById(createReqVO.getTenderProjectId());
+        if (project == null || !TenderStatusEnum.canAward(project.getTenderStatus())) {
+            throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_AWARD_FORBIDDEN);
+        }
         // 鏍¢獙鏄惁宸插瓨鍦ㄥ畾鏍�
         SrmBidAwardDO existing = bidAwardMapper.selectByTenderProjectId(createReqVO.getTenderProjectId());
         if (existing != null) {
@@ -95,6 +105,10 @@
     @Transactional(rollbackFor = Exception.class)
     public void deleteAward(Long id) {
         SrmBidAwardDO award = validateAwardExists(id);
+        // 浠呭緟瀹℃壒鐘舵�佸彲鍒犻櫎
+        if (!AwardStatusEnum.PENDING_APPROVAL.getCode().equals(award.getAwardStatus())) {
+            throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_AWARD_FORBIDDEN);
+        }
         bidAwardMapper.deleteById(id);
     }
 
@@ -102,16 +116,18 @@
     @Transactional(rollbackFor = Exception.class)
     public void approveAward(Long id) {
         SrmBidAwardDO award = validateAwardExists(id);
+        // 鏍¢獙鎷涙爣椤圭洰鐘舵�佷负璇勬爣涓�
+        SrmTenderProjectDO project = tenderProjectMapper.selectById(award.getTenderProjectId());
+        if (project == null || !TenderStatusEnum.canAward(project.getTenderStatus())) {
+            throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_AWARD_FORBIDDEN);
+        }
         award.setAwardStatus(AwardStatusEnum.AWARDED.getCode());
         award.setApprovalTime(LocalDateTime.now());
         bidAwardMapper.updateById(award);
 
         // 鏇存柊鎷涙爣椤圭洰鐘舵�佷负宸插畾鏍�
-        SrmTenderProjectDO project = tenderProjectMapper.selectById(award.getTenderProjectId());
-        if (project != null) {
-            project.setTenderStatus(TenderStatusEnum.AWARDED.getCode());
-            tenderProjectMapper.updateById(project);
-        }
+        project.setTenderStatus(TenderStatusEnum.AWARDED.getCode());
+        tenderProjectMapper.updateById(project);
     }
 
     @Override
@@ -121,6 +137,11 @@
         SrmBidAwardDO award = validateAwardExists(id);
         if (!AwardStatusEnum.AWARDED.getCode().equals(award.getAwardStatus())) {
             throw ServiceExceptionUtil.exception(ErrorCodeConstants.AWARD_STATUS_NOT_AWARDED);
+        }
+        // 鏍¢獙鎷涙爣椤圭洰鐘舵�佷负宸插畾鏍�
+        SrmTenderProjectDO project = tenderProjectMapper.selectById(award.getTenderProjectId());
+        if (project == null || !TenderStatusEnum.AWARDED.getCode().equals(project.getTenderStatus())) {
+            throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_AWARD_FORBIDDEN);
         }
 
         // 2. 鏌� SRM 渚涘簲鍟�
@@ -201,11 +222,8 @@
         bidAwardMapper.updateById(award);
 
         // 9. 鏇存柊鎷涙爣椤圭洰鐘舵��
-        SrmTenderProjectDO project = tenderProjectMapper.selectById(award.getTenderProjectId());
-        if (project != null) {
-            project.setTenderStatus(TenderStatusEnum.CLOSED.getCode());
-            tenderProjectMapper.updateById(project);
-        }
+        project.setTenderStatus(TenderStatusEnum.CLOSED.getCode());
+        tenderProjectMapper.updateById(project);
     }
 
     private SrmBidAwardDO validateAwardExists(Long id) {
diff --git a/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/tender/SrmBidEvaluationServiceImpl.java b/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/tender/SrmBidEvaluationServiceImpl.java
index c0f3b72..f211793 100644
--- a/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/tender/SrmBidEvaluationServiceImpl.java
+++ b/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/tender/SrmBidEvaluationServiceImpl.java
@@ -11,6 +11,7 @@
 import cn.iocoder.yudao.module.srm.enums.ErrorCodeConstants;
 import cn.iocoder.yudao.module.srm.enums.TenderStatusEnum;
 import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
+import com.mzt.logapi.starter.annotation.LogRecord;
 import jakarta.annotation.Resource;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -21,6 +22,8 @@
 import java.time.LocalDateTime;
 import java.util.Comparator;
 import java.util.List;
+
+import static cn.iocoder.yudao.module.srm.enums.LogRecordConstants.*;
 
 /**
  * SRM 璇勬爣绠$悊 Service 瀹炵幇绫�
@@ -42,7 +45,20 @@
 
     @Override
     @Transactional(rollbackFor = Exception.class)
+    @LogRecord(type = LOG_EVALUATION_TYPE, subType = LOG_EVALUATION_CREATE_SUB_TYPE,
+            bizNo = "{{#createReqVO.tenderProjectId}}", success = LOG_EVALUATION_CREATE_SUCCESS)
     public Long createEvaluation(SrmBidEvaluationSaveReqVO createReqVO) {
+        // 妫�鏌ユ嫑鏍囬」鐩姸鎬侊細BIDDING 鎴� EVALUATING 鎵嶅厑璁歌瘎鏍�
+        SrmTenderProjectDO project = tenderProjectMapper.selectById(createReqVO.getTenderProjectId());
+        if (project == null) {
+            throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_NOT_EXISTS);
+        }
+        Integer status = project.getTenderStatus();
+        if (!TenderStatusEnum.BIDDING.getCode().equals(status)
+                && !TenderStatusEnum.EVALUATING.getCode().equals(status)) {
+            throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_EVALUATION_FORBIDDEN);
+        }
+
         SrmBidEvaluationDO evaluation = BeanUtils.toBean(createReqVO, SrmBidEvaluationDO.class);
         // 寮哄埗缃┖ id锛岄伩鍏嶅墠绔紶鍏ュ凡鏈� id 瀵艰嚧涓婚敭鍐茬獊锛岀敱鏁版嵁搴撳簭鍒楄嚜鍔ㄧ敓鎴�
         evaluation.setId(null);
@@ -60,8 +76,7 @@
         evaluation.setEvaluationTime(LocalDateTime.now());
         bidEvaluationMapper.insert(evaluation);
         // 棣栨璇勬爣鏃舵洿鏂版嫑鏍囬」鐩姸鎬佷负璇勬爣涓�
-        SrmTenderProjectDO project = tenderProjectMapper.selectById(createReqVO.getTenderProjectId());
-        if (project != null && TenderStatusEnum.BIDDING.getCode().equals(project.getTenderStatus())) {
+        if (TenderStatusEnum.BIDDING.getCode().equals(project.getTenderStatus())) {
             project.setTenderStatus(TenderStatusEnum.EVALUATING.getCode());
             tenderProjectMapper.updateById(project);
         }
@@ -74,6 +89,11 @@
         SrmBidEvaluationDO existing = bidEvaluationMapper.selectById(updateReqVO.getId());
         if (existing == null) {
             throw ServiceExceptionUtil.exception(ErrorCodeConstants.EVALUATION_NOT_EXISTS_TENDER);
+        }
+        // 妫�鏌ユ嫑鏍囬」鐩姸鎬侊細浠� EVALUATING 鍏佽鏇存柊璇勬爣
+        SrmTenderProjectDO project = tenderProjectMapper.selectById(existing.getTenderProjectId());
+        if (project == null || !TenderStatusEnum.canEvaluate(project.getTenderStatus())) {
+            throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_EVALUATION_FORBIDDEN);
         }
         SrmBidEvaluationDO evaluation = BeanUtils.toBean(updateReqVO, SrmBidEvaluationDO.class);
         BigDecimal price = nvl(evaluation.getPriceScore());
@@ -98,6 +118,10 @@
     @Override
     @Transactional(rollbackFor = Exception.class)
     public void calculateRanking(Long tenderProjectId) {
+        SrmTenderProjectDO project = tenderProjectMapper.selectById(tenderProjectId);
+        if (project == null || !TenderStatusEnum.canEvaluate(project.getTenderStatus())) {
+            throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_EVALUATION_FORBIDDEN);
+        }
         List<SrmBidEvaluationDO> list = bidEvaluationMapper.selectListByTenderProjectId(tenderProjectId);
         // 鎸夌患鍚堣瘎鍒嗛檷搴忔帓鍚�
         list.sort(Comparator.comparing(e -> e.getCompositeScore() != null ? e.getCompositeScore() : BigDecimal.ZERO, Comparator.reverseOrder()));
@@ -113,15 +137,20 @@
     @Override
     @Transactional(rollbackFor = Exception.class)
     public Long createBidOpen(Long tenderProjectId) {
+        // 鏍¢獙鎷涙爣椤圭洰瀛樺湪涓旂姸鎬佷负鍙戝竷涓�
+        SrmTenderProjectDO project = tenderProjectMapper.selectById(tenderProjectId);
+        if (project == null) {
+            throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_NOT_EXISTS);
+        }
+        if (!TenderStatusEnum.PUBLISHED.getCode().equals(project.getTenderStatus())) {
+            throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_STATUS_NOT_PUBLISHED);
+        }
         if (bidOpenMapper.selectByTenderProjectId(tenderProjectId) != null) {
             throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_STATUS_NOT_PUBLISHED);
         }
         // 寮�鏍囧悗鑷姩鏇存柊鎷涙爣椤圭洰鐘舵�佷负鎶曟爣涓�
-        SrmTenderProjectDO project = tenderProjectMapper.selectById(tenderProjectId);
-        if (project != null && TenderStatusEnum.PUBLISHED.getCode().equals(project.getTenderStatus())) {
-            project.setTenderStatus(TenderStatusEnum.BIDDING.getCode());
-            tenderProjectMapper.updateById(project);
-        }
+        project.setTenderStatus(TenderStatusEnum.BIDDING.getCode());
+        tenderProjectMapper.updateById(project);
         SrmBidOpenDO open = new SrmBidOpenDO();
         open.setTenderProjectId(tenderProjectId);
         open.setOpenTime(LocalDateTime.now());
diff --git a/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/tender/SrmTenderBidServiceImpl.java b/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/tender/SrmTenderBidServiceImpl.java
index 91e6e74..6410946 100644
--- a/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/tender/SrmTenderBidServiceImpl.java
+++ b/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/tender/SrmTenderBidServiceImpl.java
@@ -5,6 +5,7 @@
 import cn.iocoder.yudao.module.srm.controller.admin.tender.vo.SrmTenderBidSaveReqVO;
 import cn.iocoder.yudao.module.srm.dal.dataobject.SrmSupplierQuoteDO;
 import cn.iocoder.yudao.module.srm.dal.dataobject.SrmTenderBidDO;
+import cn.iocoder.yudao.module.srm.dal.dataobject.SrmTenderProjectDO;
 import cn.iocoder.yudao.module.srm.dal.mysql.SrmSupplierApplyMapper;
 import cn.iocoder.yudao.module.srm.dal.mysql.SrmSupplierQuoteMapper;
 import cn.iocoder.yudao.module.srm.dal.mysql.SrmTenderBidMapper;
@@ -13,6 +14,8 @@
 import cn.iocoder.yudao.module.srm.enums.ErrorCodeConstants;
 import cn.iocoder.yudao.module.srm.enums.TenderStatusEnum;
 import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
+import com.mzt.logapi.context.LogRecordContext;
+import com.mzt.logapi.starter.annotation.LogRecord;
 import jakarta.annotation.Resource;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -20,6 +23,8 @@
 
 import java.time.LocalDateTime;
 import java.util.List;
+
+import static cn.iocoder.yudao.module.srm.enums.LogRecordConstants.*;
 
 /**
  * SRM 鎶曟爣绠$悊 Service 瀹炵幇绫�
@@ -44,9 +49,15 @@
 
     @Override
     @Transactional(rollbackFor = Exception.class)
+    @LogRecord(type = LOG_BID_TYPE, subType = LOG_BID_CREATE_SUB_TYPE,
+            bizNo = "{{#createReqVO.bidNo}}", success = LOG_BID_CREATE_SUCCESS)
     public Long createBid(SrmTenderBidSaveReqVO createReqVO) {
-        // 鏍¢獙鎷涙爣椤圭洰鏄惁瀛樺湪涓旂姸鎬佹纭�
-        validateTenderStatus(createReqVO.getTenderProjectId());
+        // 鏍¢獙鎷涙爣椤圭洰鐘舵�侊紙PUBLISHED/BIDDING 鎵嶅厑璁告姇鏍囷級
+        SrmTenderProjectDO project = validateTenderStatus(createReqVO.getTenderProjectId());
+        // 妫�鏌ユ姇鏍囨埅姝㈡椂闂�
+        if (project.getEndTime() != null && LocalDateTime.now().isAfter(project.getEndTime())) {
+            throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_END_TIME_PASSED);
+        }
         // 鏍¢獙渚涘簲鍟嗘槸鍚﹀凡閫氳繃鍑嗗叆瀹℃壒
         if (!supplierApplyMapper.existsApprovedBySupplierId(createReqVO.getSupplierId())) {
             throw ServiceExceptionUtil.exception(ErrorCodeConstants.BID_SUPPLIER_NOT_APPROVED);
@@ -64,6 +75,8 @@
         bid.setBidStatus(BidStatusEnum.REGISTERED.getCode());
         bid.setBidTime(LocalDateTime.now());
         tenderBidMapper.insert(bid);
+        LogRecordContext.putVariable("bidNo", bid.getBidNo());
+        LogRecordContext.putVariable("tenderName", project.getTenderName());
         return bid.getId();
     }
 
@@ -79,20 +92,35 @@
 
     @Override
     @Transactional(rollbackFor = Exception.class)
+    @LogRecord(type = LOG_BID_TYPE, subType = LOG_BID_WITHDRAW_SUB_TYPE,
+            bizNo = "{{#id}}", success = LOG_BID_WITHDRAW_SUCCESS)
     public void withdrawBid(Long id) {
         SrmTenderBidDO bid = validateBidExists(id);
+        // 妫�鏌ユ嫑鏍囬」鐩姸鎬侊細浠� PUBLISHED/BIDDING 鍏佽鎾ゆ爣
+        SrmTenderProjectDO project = tenderProjectMapper.selectById(bid.getTenderProjectId());
+        if (project == null || !TenderStatusEnum.canCreateOrUpdateQuote(project.getTenderStatus())) {
+            throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_BID_FORBIDDEN_WITHDRAW);
+        }
         bid.setBidStatus(BidStatusEnum.WITHDRAWN.getCode());
         tenderBidMapper.updateById(bid);
         // 鍒犻櫎鎶ヤ环
         supplierQuoteMapper.deleteByBidId(id);
+        LogRecordContext.putVariable("bidNo", bid.getBidNo());
     }
 
     // ========== 鎶ヤ环绠$悊 ==========
 
     @Override
+    @LogRecord(type = LOG_QUOTE_TYPE, subType = LOG_QUOTE_CREATE_SUB_TYPE,
+            bizNo = "{{#createReqVO.bidId}}", success = LOG_QUOTE_CREATE_SUCCESS)
     public Long createQuote(SrmSupplierQuoteSaveReqVO createReqVO) {
         // 鏍¢獙鎶曟爣鐘舵�侊紙鎾ゆ爣鍚庝笉鍏佽鎶ヤ环锛�
         SrmTenderBidDO bid = validateBidNotWithdrawn(createReqVO.getBidId());
+        // 鏍¢獙鎷涙爣椤圭洰鐘舵�侊細浠� PUBLISHED/BIDDING 鍏佽鎶ヤ环
+        SrmTenderProjectDO project = tenderProjectMapper.selectById(bid.getTenderProjectId());
+        if (project == null || !TenderStatusEnum.canCreateOrUpdateQuote(project.getTenderStatus())) {
+            throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_QUOTE_FORBIDDEN);
+        }
         // 鏍¢獙鍚屼竴鎶曟爣涓嬬墿鏂欎笉鍙噸澶嶆姤浠�
         if (supplierQuoteMapper.existsByBidAndMaterial(createReqVO.getBidId(), createReqVO.getTenderMaterialId())) {
             throw ServiceExceptionUtil.exception(ErrorCodeConstants.QUOTE_MATERIAL_DUPLICATE);
@@ -108,7 +136,12 @@
     @Override
     public void updateQuote(SrmSupplierQuoteSaveReqVO updateReqVO) {
         // 鏍¢獙鎶曟爣鐘舵�侊紙鎾ゆ爣鍚庝笉鍏佽鎶ヤ环锛�
-        validateBidNotWithdrawn(updateReqVO.getBidId());
+        SrmTenderBidDO bid = validateBidNotWithdrawn(updateReqVO.getBidId());
+        // 鏍¢獙鎷涙爣椤圭洰鐘舵�侊細浠� PUBLISHED/BIDDING 鍏佽鎶ヤ环
+        SrmTenderProjectDO project = tenderProjectMapper.selectById(bid.getTenderProjectId());
+        if (project == null || !TenderStatusEnum.canCreateOrUpdateQuote(project.getTenderStatus())) {
+            throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_QUOTE_FORBIDDEN);
+        }
         // 鏍¢獙鍚屼竴鎶曟爣涓嬬墿鏂欎笉鍙噸澶嶆姤浠凤紙鎺掗櫎鑷韩锛�
         SrmSupplierQuoteDO existing = supplierQuoteMapper.selectById(updateReqVO.getId());
         if (existing != null && !existing.getTenderMaterialId().equals(updateReqVO.getTenderMaterialId())) {
@@ -143,9 +176,14 @@
         return bid;
     }
 
-    private void validateTenderStatus(Long tenderProjectId) {
-        if (tenderProjectMapper.selectById(tenderProjectId) == null) {
+    private SrmTenderProjectDO validateTenderStatus(Long tenderProjectId) {
+        SrmTenderProjectDO project = tenderProjectMapper.selectById(tenderProjectId);
+        if (project == null) {
             throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_NOT_EXISTS);
         }
+        if (!TenderStatusEnum.canCreateBid(project.getTenderStatus())) {
+            throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_BID_FORBIDDEN);
+        }
+        return project;
     }
 }
diff --git a/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/tender/SrmTenderProjectService.java b/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/tender/SrmTenderProjectService.java
index 1ca5508..1edc7ac 100644
--- a/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/tender/SrmTenderProjectService.java
+++ b/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/tender/SrmTenderProjectService.java
@@ -2,6 +2,7 @@
 
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.srm.controller.admin.tender.vo.SrmTenderProjectPageReqVO;
+import cn.iocoder.yudao.module.srm.controller.admin.tender.vo.SrmTenderProjectPartialUpdateReqVO;
 import cn.iocoder.yudao.module.srm.controller.admin.tender.vo.SrmTenderProjectSaveReqVO;
 import cn.iocoder.yudao.module.srm.controller.admin.tender.vo.SrmTenderMaterialSaveReqVO;
 import cn.iocoder.yudao.module.srm.dal.dataobject.SrmTenderMaterialDO;
@@ -14,6 +15,7 @@
 
     Long createTenderProject(@Valid SrmTenderProjectSaveReqVO createReqVO);
     void updateTenderProject(@Valid SrmTenderProjectSaveReqVO updateReqVO);
+    void updateTenderProjectPartial(@Valid SrmTenderProjectPartialUpdateReqVO updateReqVO);
     void deleteTenderProject(Long id);
     SrmTenderProjectDO getTenderProject(Long id);
     PageResult<SrmTenderProjectDO> getTenderProjectPage(SrmTenderProjectPageReqVO pageReqVO);
diff --git a/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/tender/SrmTenderProjectServiceImpl.java b/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/tender/SrmTenderProjectServiceImpl.java
index 7de0819..5d1b679 100644
--- a/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/tender/SrmTenderProjectServiceImpl.java
+++ b/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/tender/SrmTenderProjectServiceImpl.java
@@ -4,17 +4,21 @@
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 import cn.iocoder.yudao.module.srm.controller.admin.tender.vo.SrmTenderMaterialSaveReqVO;
 import cn.iocoder.yudao.module.srm.controller.admin.tender.vo.SrmTenderProjectPageReqVO;
+import cn.iocoder.yudao.module.srm.controller.admin.tender.vo.SrmTenderProjectPartialUpdateReqVO;
 import cn.iocoder.yudao.module.srm.controller.admin.tender.vo.SrmTenderProjectSaveReqVO;
 import cn.iocoder.yudao.module.srm.dal.dataobject.SrmBidAwardDO;
 import cn.iocoder.yudao.module.srm.dal.dataobject.SrmTenderMaterialDO;
 import cn.iocoder.yudao.module.srm.dal.dataobject.SrmTenderProjectDO;
 import cn.iocoder.yudao.module.srm.dal.mysql.SrmBidAwardMapper;
+import cn.iocoder.yudao.module.srm.dal.mysql.SrmTenderBidMapper;
 import cn.iocoder.yudao.module.srm.dal.mysql.SrmTenderMaterialMapper;
 import cn.iocoder.yudao.module.srm.dal.mysql.SrmTenderProjectMapper;
 import cn.iocoder.yudao.module.srm.enums.AwardStatusEnum;
 import cn.iocoder.yudao.module.srm.enums.ErrorCodeConstants;
 import cn.iocoder.yudao.module.srm.enums.TenderStatusEnum;
 import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
+import com.mzt.logapi.context.LogRecordContext;
+import com.mzt.logapi.starter.annotation.LogRecord;
 import jakarta.annotation.Resource;
 import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
@@ -23,6 +27,8 @@
 import java.util.Map;
 import java.util.function.Function;
 import java.util.stream.Collectors;
+
+import static cn.iocoder.yudao.module.srm.enums.LogRecordConstants.*;
 
 @Service
 @Validated
@@ -34,6 +40,8 @@
     private SrmTenderMaterialMapper tenderMaterialMapper;
     @Resource
     private SrmBidAwardMapper bidAwardMapper;
+    @Resource
+    private SrmTenderBidMapper tenderBidMapper;
 
     @Override
     public Long createTenderProject(SrmTenderProjectSaveReqVO createReqVO) {
@@ -44,13 +52,42 @@
     }
 
     @Override
+    @LogRecord(type = LOG_TENDER_TYPE, subType = LOG_TENDER_UPDATE_SUB_TYPE,
+            bizNo = "{{#updateReqVO.id}}", success = LOG_TENDER_UPDATE_SUCCESS)
     public void updateTenderProject(SrmTenderProjectSaveReqVO updateReqVO) {
         SrmTenderProjectDO project = validateTenderExists(updateReqVO.getId());
-        if (!TenderStatusEnum.DRAFT.getCode().equals(project.getTenderStatus())) {
-            throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_STATUS_NOT_DRAFT);
+        Integer status = project.getTenderStatus();
+
+        // 鑽夌鐘舵�侊細鍏ㄥ瓧娈靛彲缂栬緫
+        if (TenderStatusEnum.canEditFullProject(status)) {
+            SrmTenderProjectDO updateObj = BeanUtils.toBean(updateReqVO, SrmTenderProjectDO.class);
+            updateObj.setTenderStatus(status); // 鐘舵�佷笉鍏佽鍓嶇浼犲叆瑕嗙洊
+            tenderProjectMapper.updateById(updateObj);
+            LogRecordContext.putVariable("tenderName", project.getTenderName());
+            LogRecordContext.putVariable("oldTenderDesc", project.getTenderDesc());
+            LogRecordContext.putVariable("newTenderDesc", updateReqVO.getTenderDesc());
+            LogRecordContext.putVariable("oldQualification", project.getQualificationRequirements());
+            LogRecordContext.putVariable("newQualification", updateReqVO.getQualificationRequirements());
+            return;
         }
-        SrmTenderProjectDO updateObj = BeanUtils.toBean(updateReqVO, SrmTenderProjectDO.class);
-        tenderProjectMapper.updateById(updateObj);
+
+        // 鍙戝竷涓�/鎶曟爣涓細浠呭厑璁镐慨鏀规嫑鏍囪鏄庡拰璧勮川瑕佹眰
+        if (TenderStatusEnum.canEditPartialProject(status)) {
+            SrmTenderProjectDO updateObj = new SrmTenderProjectDO();
+            updateObj.setId(updateReqVO.getId());
+            updateObj.setTenderDesc(updateReqVO.getTenderDesc());
+            updateObj.setQualificationRequirements(updateReqVO.getQualificationRequirements());
+            tenderProjectMapper.updateById(updateObj);
+            LogRecordContext.putVariable("tenderName", project.getTenderName());
+            LogRecordContext.putVariable("oldTenderDesc", project.getTenderDesc());
+            LogRecordContext.putVariable("newTenderDesc", updateReqVO.getTenderDesc());
+            LogRecordContext.putVariable("oldQualification", project.getQualificationRequirements());
+            LogRecordContext.putVariable("newQualification", updateReqVO.getQualificationRequirements());
+            return;
+        }
+
+        // 鍏朵粬鐘舵�侊細涓嶅厑璁哥紪杈�
+        throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_PROJECT_LOCKED);
     }
 
     @Override
@@ -58,6 +95,10 @@
         SrmTenderProjectDO project = validateTenderExists(id);
         if (!TenderStatusEnum.DRAFT.getCode().equals(project.getTenderStatus())) {
             throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_STATUS_NOT_DRAFT);
+        }
+        // 妫�鏌ユ槸鍚﹀凡鏈夋姇鏍囨暟鎹�
+        if (tenderBidMapper.countByTenderProjectId(id) > 0) {
+            throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_HAS_BIDS_CANNOT_DELETE);
         }
         tenderMaterialMapper.deleteByTenderProjectId(id);
         tenderProjectMapper.deleteById(id);
@@ -117,6 +158,10 @@
         if (TenderStatusEnum.CLOSED.getCode().equals(project.getTenderStatus())) {
             throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_STATUS_ALREADY_CLOSED);
         }
+        // 鑽夌鐘舵�佷笉鍏佽鐩存帴鍏抽棴
+        if (TenderStatusEnum.DRAFT.getCode().equals(project.getTenderStatus())) {
+            throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_PROJECT_LOCKED);
+        }
         project.setTenderStatus(TenderStatusEnum.CLOSED.getCode());
         tenderProjectMapper.updateById(project);
     }
@@ -141,22 +186,60 @@
         tenderProjectMapper.updateById(project);
     }
 
+    @Override
+    @LogRecord(type = LOG_TENDER_TYPE, subType = LOG_TENDER_UPDATE_SUB_TYPE,
+            bizNo = "{{#updateReqVO.id}}", success = LOG_TENDER_UPDATE_SUCCESS)
+    public void updateTenderProjectPartial(SrmTenderProjectPartialUpdateReqVO updateReqVO) {
+        SrmTenderProjectDO project = validateTenderExists(updateReqVO.getId());
+        if (!TenderStatusEnum.canEditPartialProject(project.getTenderStatus())) {
+            throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_PROJECT_LOCKED);
+        }
+        SrmTenderProjectDO updateObj = new SrmTenderProjectDO();
+        updateObj.setId(updateReqVO.getId());
+        updateObj.setTenderDesc(updateReqVO.getTenderDesc());
+        updateObj.setQualificationRequirements(updateReqVO.getQualificationRequirements());
+        tenderProjectMapper.updateById(updateObj);
+        LogRecordContext.putVariable("tenderName", project.getTenderName());
+        LogRecordContext.putVariable("oldTenderDesc", project.getTenderDesc());
+        LogRecordContext.putVariable("newTenderDesc", updateReqVO.getTenderDesc());
+        LogRecordContext.putVariable("oldQualification", project.getQualificationRequirements());
+        LogRecordContext.putVariable("newQualification", updateReqVO.getQualificationRequirements());
+    }
+
     // ========== 鐗╂枡瀛愯〃 ==========
 
     @Override
     public void createMaterial(SrmTenderMaterialSaveReqVO createReqVO) {
+        SrmTenderProjectDO project = validateTenderExists(createReqVO.getTenderProjectId());
+        if (!TenderStatusEnum.canEditMaterial(project.getTenderStatus())) {
+            throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_MATERIAL_LOCKED);
+        }
         SrmTenderMaterialDO material = BeanUtils.toBean(createReqVO, SrmTenderMaterialDO.class);
         tenderMaterialMapper.insert(material);
     }
 
     @Override
     public void updateMaterial(SrmTenderMaterialSaveReqVO updateReqVO) {
+        SrmTenderMaterialDO existing = tenderMaterialMapper.selectById(updateReqVO.getId());
+        if (existing != null) {
+            SrmTenderProjectDO project = tenderProjectMapper.selectById(existing.getTenderProjectId());
+            if (project != null && !TenderStatusEnum.canEditMaterial(project.getTenderStatus())) {
+                throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_MATERIAL_LOCKED);
+            }
+        }
         SrmTenderMaterialDO updateObj = BeanUtils.toBean(updateReqVO, SrmTenderMaterialDO.class);
         tenderMaterialMapper.updateById(updateObj);
     }
 
     @Override
     public void deleteMaterial(Long id) {
+        SrmTenderMaterialDO material = tenderMaterialMapper.selectById(id);
+        if (material != null) {
+            SrmTenderProjectDO project = tenderProjectMapper.selectById(material.getTenderProjectId());
+            if (project != null && !TenderStatusEnum.canEditMaterial(project.getTenderStatus())) {
+                throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_MATERIAL_LOCKED);
+            }
+        }
         tenderMaterialMapper.deleteById(id);
     }
 

--
Gitblit v1.9.3