From db46314b9c56256a31c9114bd45d9bd63368cbd8 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期三, 29 七月 2026 18:06:22 +0800
Subject: [PATCH] feat(crm): 实现CRM客户管理查看全部权限功能
---
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/common/CrmSceneTypeEnum.java | 7
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/task/MesProTaskServiceImpl.java | 38 +
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/task/MesProTaskController.java | 15
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dv/machinery/vo/MesDvMachineryImportExcelVO.java | 9
yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/tender/SrmBidEvaluationServiceImpl.java | 24
docs/machinery_new_fields_frontend.md | 140 ++++
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dv/machinery/vo/MesDvMachineryPageReqVO.java | 3
.playwright-mcp/page-2026-07-29T06-47-38-983Z.yml | 113 +++
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dv/machinery/vo/MesDvMachineryRespVO.java | 15
.playwright-mcp/page-2026-07-29T06-40-35-404Z.yml | 1
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dv/machinery/MesDvMachineryController.java | 8
yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/controller/admin/tender/vo/SrmSupplierQuoteRespVO.java | 3
yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/dal/mysql/SrmTenderBidMapper.java | 5
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pd/documentaudit/vo/MesPdDocumentAuditPageReqVO.java | 3
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dv/machinery/vo/MesDvMachinerySaveReqVO.java | 9
yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/tender/SrmBidAwardServiceImpl.java | 28
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/util/CrmPermissionUtils.java | 18
yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/enums/ErrorCodeConstants.java | 1
.playwright-mcp/page-2026-07-29T06-56-04-077Z.yml | 1
yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/controller/admin/tender/SrmBidAwardController.java | 16
.playwright-mcp/page-2026-07-29T07-14-58-476Z.yml | 1
.playwright-mcp/page-2026-07-29T06-42-36-804Z.yml | 112 +++
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pd/documentaudit/MesPdDocumentAuditMapper.java | 10
.playwright-mcp/page-2026-07-29T07-10-45-745Z.yml | 1
docs/document_audit_project_filter_fix.md | 59 +
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pd/documentaudit/MesPdDocumentAuditServiceImpl.java | 15
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java | 1
sql/mysql/mes_pd_menu_init.sql | 37 +
.playwright-mcp/page-2026-07-29T07-14-24-445Z.yml | 1
.playwright-mcp/page-2026-07-29T06-56-14-335Z.yml | 122 +++
yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/tender/SrmTenderProjectServiceImpl.java | 15
yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/controller/admin/tender/SrmBidEvaluationController.java | 8
.playwright-mcp/page-2026-07-29T06-42-11-724Z.yml | 1
docs/pro_archive_integration.md | 154 ++++
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/dv/machinery/MesDvMachineryMapper.java | 1
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerMapper.java | 6
yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/tender/SrmBidEvaluationService.java | 5
.playwright-mcp/page-2026-07-29T06-43-35-225Z.yml | 112 +++
.playwright-mcp/page-2026-07-29T06-47-24-223Z.yml | 1
.mcp.json.tmp | 8
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/dv/machinery/MesDvMachineryServiceImpl.java | 32
yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/supplier/SrmSupplierServiceImpl.java | 5
yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/tender/SrmTenderBidServiceImpl.java | 4
docs/crm_customer_view_all.md | 88 ++
yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/controller/admin/tender/SrmTenderBidController.java | 1
.playwright-mcp/page-2026-07-29T07-14-44-587Z.yml | 121 +++
docs/pro_task_calculate_duration.md | 81 ++
.mcp.json | 2
yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/tender/SrmBidAwardService.java | 5
.playwright-mcp/page-2026-07-29T07-12-31-548Z.yml | 121 +++
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/task/MesProTaskService.java | 9
.playwright-mcp/page-2026-07-29T06-51-00-932Z.yml | 152 ++++
.playwright-mcp/page-2026-07-29T06-47-57-125Z.yml | 152 ++++
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/dv/machinery/MesDvMachineryDO.java | 14
54 files changed, 1,904 insertions(+), 10 deletions(-)
diff --git a/.mcp.json b/.mcp.json
index b2068ac..19d9d48 100644
--- a/.mcp.json
+++ b/.mcp.json
@@ -1,7 +1,7 @@
{
"mcpServers": {
"idea": {
- "url": "http://127.0.0.1:64342/stream",
+ "url": "http://127.0.0.1:64417/stream",
"type": "http"
}
}
diff --git a/.mcp.json.tmp b/.mcp.json.tmp
new file mode 100644
index 0000000..19d9d48
--- /dev/null
+++ b/.mcp.json.tmp
@@ -0,0 +1,8 @@
+{
+ "mcpServers": {
+ "idea": {
+ "url": "http://127.0.0.1:64417/stream",
+ "type": "http"
+ }
+ }
+}
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-07-29T06-40-35-404Z.yml b/.playwright-mcp/page-2026-07-29T06-40-35-404Z.yml
new file mode 100644
index 0000000..987bb5e
--- /dev/null
+++ b/.playwright-mcp/page-2026-07-29T06-40-35-404Z.yml
@@ -0,0 +1 @@
+- generic [active]: 宸ュ巶鏁板瓧鍖朚OM绯荤粺
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-07-29T06-42-11-724Z.yml b/.playwright-mcp/page-2026-07-29T06-42-11-724Z.yml
new file mode 100644
index 0000000..987bb5e
--- /dev/null
+++ b/.playwright-mcp/page-2026-07-29T06-42-11-724Z.yml
@@ -0,0 +1 @@
+- generic [active]: 宸ュ巶鏁板瓧鍖朚OM绯荤粺
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-07-29T06-42-36-804Z.yml b/.playwright-mcp/page-2026-07-29T06-42-36-804Z.yml
new file mode 100644
index 0000000..b4e4c37
--- /dev/null
+++ b/.playwright-mcp/page-2026-07-29T06-42-36-804Z.yml
@@ -0,0 +1,112 @@
+- generic [ref=e7]:
+ - complementary [ref=e8]:
+ - generic [ref=e9]:
+ - link "宸ュ巶鏁板瓧鍖朚OM绯荤粺 宸ュ巶鏁板瓧鍖朚OM绯荤粺" [ref=e15] [cursor=pointer]:
+ - /url: javascript:void 0
+ - img "宸ュ巶鏁板瓧鍖朚OM绯荤粺" [ref=e18]
+ - generic [ref=e19]: 宸ュ巶鏁板瓧鍖朚OM绯荤粺
+ - menu [ref=e22]:
+ - listitem [ref=e23]:
+ - generic [ref=e24] [cursor=pointer]: 姒傝
+ - listitem [ref=e34]:
+ - generic [ref=e35] [cursor=pointer]: 鍩虹鏁版嵁
+ - listitem [ref=e43]:
+ - generic [ref=e44] [cursor=pointer]: 閲囪喘绠$悊
+ - listitem [ref=e50]:
+ - generic [ref=e51] [cursor=pointer]: 钀ラ攢绠$悊
+ - listitem [ref=e57]:
+ - generic [ref=e58] [cursor=pointer]: 璁惧绠$悊
+ - listitem [ref=e65]:
+ - generic [ref=e66] [cursor=pointer]: 浠撳偍鐗╂祦
+ - listitem [ref=e74]:
+ - generic [ref=e75] [cursor=pointer]: 鐢熶骇绠℃帶
+ - listitem [ref=e82]:
+ - generic [ref=e83] [cursor=pointer]: 璐ㄩ噺绠$悊
+ - listitem [ref=e89]:
+ - generic [ref=e90] [cursor=pointer]: 鍗忓悓鍔炲叕
+ - listitem [ref=e96]:
+ - generic [ref=e97] [cursor=pointer]: 浜哄姏璧勬簮
+ - listitem [ref=e103]:
+ - generic [ref=e104] [cursor=pointer]: 鍩虹璁炬柦
+ - listitem [ref=e110]:
+ - generic [ref=e111] [cursor=pointer]: 绯荤粺绠$悊
+ - listitem [ref=e117]:
+ - generic [ref=e118] [cursor=pointer]: IM 鍗虫椂閫氳
+ - generic [ref=e131]:
+ - generic [ref=e132]:
+ - banner [ref=e133]:
+ - button [ref=e134] [cursor=pointer]
+ - button [ref=e137] [cursor=pointer]
+ - navigation "breadcrumb" [ref=e142]:
+ - list [ref=e143]:
+ - listitem [ref=e144]:
+ - link [ref=e145] [cursor=pointer]:
+ - /url: javascript:void 0
+ - listitem [ref=e152]
+ - listitem [ref=e155]:
+ - link "鎷涙爣璇︽儏" [disabled] [ref=e156]
+ - generic [ref=e159]:
+ - generic [ref=e161] [cursor=pointer]:
+ - generic [ref=e165]: 鎼滅储
+ - generic [ref=e166]: Ctrl K
+ - button [ref=e168] [cursor=pointer]
+ - button "dark" [ref=e173] [cursor=pointer]
+ - button [ref=e182] [cursor=pointer]
+ - button [ref=e188] [cursor=pointer]
+ - button [ref=e191] [cursor=pointer]
+ - button [ref=e197] [cursor=pointer]:
+ - button [ref=e199]
+ - button "宸ヤ綔鍙�" [ref=e203] [cursor=pointer]
+ - button "婧愮爜" [ref=e207] [cursor=pointer]
+ - generic [ref=e214]:
+ - generic [ref=e219]:
+ - generic [ref=e220] [cursor=pointer]: 鍒嗘瀽椤�
+ - generic [ref=e238] [cursor=pointer]: 鎷涙爣璇︽儏
+ - button [ref=e254] [cursor=pointer]
+ - main [ref=e272]:
+ - generic [ref=e275]:
+ - generic [ref=e276]:
+ - button [ref=e277] [cursor=pointer]
+ - generic [ref=e280]: 娴嬭瘯椤圭洰
+ - generic [ref=e281]: 娴嬭瘯缂栧彿
+ - generic [ref=e282]: 璇勬爣涓�
+ - generic [ref=e283]: 鍏紑鎷涙爣
+ - button "鍒锋柊" [ref=e284] [cursor=pointer]
+ - generic [ref=e290]:
+ - generic:
+ - generic "鑽夌"
+ - generic "鍙戝竷"
+ - generic "鎶曟爣涓�"
+ - generic "璇勬爣涓�"
+ - generic "宸插畾鏍�"
+ - generic [ref=e291]:
+ - generic [ref=e292]:
+ - generic [ref=e293]: 棰勭畻閲戦
+ - generic [ref=e294]: 15,000 鍏�
+ - generic [ref=e295]:
+ - generic [ref=e296]: 璐熻矗浜�
+ - generic [ref=e297]: "-"
+ - generic [ref=e298]:
+ - generic [ref=e299]: 閲囪喘缁勭粐
+ - generic [ref=e300]: "-"
+ - generic [ref=e301]:
+ - generic [ref=e302]: 寮�鏍囨椂闂�
+ - generic [ref=e303]: 2026-07-29 11:20:11
+ - generic [ref=e304]:
+ - generic [ref=e305]: 寮�濮嬫椂闂�
+ - generic [ref=e306]: 2026-07-29 11:13:02
+ - generic [ref=e307]:
+ - generic [ref=e308]: 鎴鏃堕棿
+ - generic [ref=e309]: 2026-07-29 19:13:06
+ - generic [ref=e313]:
+ - tablist [ref=e314]:
+ - generic [ref=e316]:
+ - tab [ref=e318] [cursor=pointer]
+ - tab [ref=e323] [cursor=pointer]
+ - tab [ref=e328] [cursor=pointer]
+ - tab [ref=e333] [cursor=pointer]
+ - tab [ref=e338] [cursor=pointer]
+ - tab [active] [selected] [ref=e343] [cursor=pointer]
+ - tabpanel "瀹氭爣" [ref=e404]:
+ - generic [ref=e405]:
+ - generic "灏氭湭瀹氭爣"
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-07-29T06-43-35-225Z.yml b/.playwright-mcp/page-2026-07-29T06-43-35-225Z.yml
new file mode 100644
index 0000000..0dd6375
--- /dev/null
+++ b/.playwright-mcp/page-2026-07-29T06-43-35-225Z.yml
@@ -0,0 +1,112 @@
+- generic [ref=e7]:
+ - complementary [ref=e8]:
+ - generic [ref=e9]:
+ - link "宸ュ巶鏁板瓧鍖朚OM绯荤粺 宸ュ巶鏁板瓧鍖朚OM绯荤粺" [ref=e15] [cursor=pointer]:
+ - /url: javascript:void 0
+ - img "宸ュ巶鏁板瓧鍖朚OM绯荤粺" [ref=e18]
+ - generic [ref=e19]: 宸ュ巶鏁板瓧鍖朚OM绯荤粺
+ - menu [ref=e22]:
+ - listitem [ref=e23]:
+ - generic [ref=e24] [cursor=pointer]: 姒傝
+ - listitem [ref=e34]:
+ - generic [ref=e35] [cursor=pointer]: 鍩虹鏁版嵁
+ - listitem [ref=e43]:
+ - generic [ref=e44] [cursor=pointer]: 閲囪喘绠$悊
+ - listitem [ref=e50]:
+ - generic [ref=e51] [cursor=pointer]: 钀ラ攢绠$悊
+ - listitem [ref=e57]:
+ - generic [ref=e58] [cursor=pointer]: 璁惧绠$悊
+ - listitem [ref=e65]:
+ - generic [ref=e66] [cursor=pointer]: 浠撳偍鐗╂祦
+ - listitem [ref=e74]:
+ - generic [ref=e75] [cursor=pointer]: 鐢熶骇绠℃帶
+ - listitem [ref=e82]:
+ - generic [ref=e83] [cursor=pointer]: 璐ㄩ噺绠$悊
+ - listitem [ref=e89]:
+ - generic [ref=e90] [cursor=pointer]: 鍗忓悓鍔炲叕
+ - listitem [ref=e96]:
+ - generic [ref=e97] [cursor=pointer]: 浜哄姏璧勬簮
+ - listitem [ref=e103]:
+ - generic [ref=e104] [cursor=pointer]: 鍩虹璁炬柦
+ - listitem [ref=e110]:
+ - generic [ref=e111] [cursor=pointer]: 绯荤粺绠$悊
+ - listitem [ref=e117]:
+ - generic [ref=e118] [cursor=pointer]: IM 鍗虫椂閫氳
+ - generic [ref=e131]:
+ - generic [ref=e132]:
+ - banner [ref=e133]:
+ - button [ref=e134] [cursor=pointer]
+ - button [ref=e137] [cursor=pointer]
+ - navigation "breadcrumb" [ref=e142]:
+ - list [ref=e143]:
+ - listitem [ref=e144]:
+ - link [ref=e145] [cursor=pointer]:
+ - /url: javascript:void 0
+ - listitem [ref=e152]
+ - listitem [ref=e155]:
+ - link "鎷涙爣璇︽儏" [disabled] [ref=e156]
+ - generic [ref=e159]:
+ - generic [ref=e161] [cursor=pointer]:
+ - generic [ref=e165]: 鎼滅储
+ - generic [ref=e166]: Ctrl K
+ - button [ref=e168] [cursor=pointer]
+ - button "dark" [ref=e173] [cursor=pointer]
+ - button [ref=e182] [cursor=pointer]
+ - button [ref=e188] [cursor=pointer]
+ - button [ref=e191] [cursor=pointer]
+ - button [ref=e197] [cursor=pointer]:
+ - button [ref=e199]
+ - button "宸ヤ綔鍙�" [ref=e203] [cursor=pointer]
+ - button "婧愮爜" [ref=e207] [cursor=pointer]
+ - generic [ref=e214]:
+ - generic [ref=e219]:
+ - generic [ref=e220] [cursor=pointer]: 鍒嗘瀽椤�
+ - generic [ref=e238] [cursor=pointer]: 鎷涙爣璇︽儏
+ - button [ref=e254] [cursor=pointer]
+ - main [ref=e272]:
+ - generic [ref=e275]:
+ - generic [ref=e276]:
+ - button [ref=e277] [cursor=pointer]
+ - generic [ref=e280]: 娴嬭瘯椤圭洰
+ - generic [ref=e281]: 娴嬭瘯缂栧彿
+ - generic [ref=e282]: 璇勬爣涓�
+ - generic [ref=e283]: 鍏紑鎷涙爣
+ - button "鍒锋柊" [ref=e284] [cursor=pointer]
+ - generic [ref=e290]:
+ - generic:
+ - generic "鑽夌"
+ - generic "鍙戝竷"
+ - generic "鎶曟爣涓�"
+ - generic "璇勬爣涓�"
+ - generic "宸插畾鏍�"
+ - generic [ref=e291]:
+ - generic [ref=e292]:
+ - generic [ref=e293]: 棰勭畻閲戦
+ - generic [ref=e294]: 15,000 鍏�
+ - generic [ref=e295]:
+ - generic [ref=e296]: 璐熻矗浜�
+ - generic [ref=e297]: "-"
+ - generic [ref=e298]:
+ - generic [ref=e299]: 閲囪喘缁勭粐
+ - generic [ref=e300]: "-"
+ - generic [ref=e301]:
+ - generic [ref=e302]: 寮�鏍囨椂闂�
+ - generic [ref=e303]: 2026-07-29 11:20:11
+ - generic [ref=e304]:
+ - generic [ref=e305]: 寮�濮嬫椂闂�
+ - generic [ref=e306]: 2026-07-29 11:13:02
+ - generic [ref=e307]:
+ - generic [ref=e308]: 鎴鏃堕棿
+ - generic [ref=e309]: 2026-07-29 19:13:06
+ - generic [ref=e313]:
+ - tablist [ref=e314]:
+ - generic [ref=e316]:
+ - tab [ref=e318] [cursor=pointer]
+ - tab [ref=e323] [cursor=pointer]
+ - tab [ref=e328] [cursor=pointer]
+ - tab [active] [selected] [ref=e333] [cursor=pointer]
+ - tab [ref=e338] [cursor=pointer]
+ - tab [ref=e343] [cursor=pointer]
+ - tabpanel "寮�鏍�" [ref=e406]:
+ - generic [ref=e407]:
+ - generic "灏氭湭寮�鏍�"
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-07-29T06-47-24-223Z.yml b/.playwright-mcp/page-2026-07-29T06-47-24-223Z.yml
new file mode 100644
index 0000000..987bb5e
--- /dev/null
+++ b/.playwright-mcp/page-2026-07-29T06-47-24-223Z.yml
@@ -0,0 +1 @@
+- generic [active]: 宸ュ巶鏁板瓧鍖朚OM绯荤粺
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-07-29T06-47-38-983Z.yml b/.playwright-mcp/page-2026-07-29T06-47-38-983Z.yml
new file mode 100644
index 0000000..75b64e4
--- /dev/null
+++ b/.playwright-mcp/page-2026-07-29T06-47-38-983Z.yml
@@ -0,0 +1,113 @@
+- generic [ref=f1e7]:
+ - complementary [ref=f1e8]:
+ - generic [ref=f1e9]:
+ - link "宸ュ巶鏁板瓧鍖朚OM绯荤粺 宸ュ巶鏁板瓧鍖朚OM绯荤粺" [ref=f1e15] [cursor=pointer]:
+ - /url: javascript:void 0
+ - img "宸ュ巶鏁板瓧鍖朚OM绯荤粺" [ref=f1e18]
+ - generic [ref=f1e19]: 宸ュ巶鏁板瓧鍖朚OM绯荤粺
+ - menu [ref=f1e22]:
+ - listitem [ref=f1e23]:
+ - generic [ref=f1e24] [cursor=pointer]: 姒傝
+ - listitem [ref=f1e34]:
+ - generic [ref=f1e35] [cursor=pointer]: 鍩虹鏁版嵁
+ - listitem [ref=f1e43]:
+ - generic [ref=f1e44] [cursor=pointer]: 閲囪喘绠$悊
+ - listitem [ref=f1e50]:
+ - generic [ref=f1e51] [cursor=pointer]: 钀ラ攢绠$悊
+ - listitem [ref=f1e57]:
+ - generic [ref=f1e58] [cursor=pointer]: 璁惧绠$悊
+ - listitem [ref=f1e65]:
+ - generic [ref=f1e66] [cursor=pointer]: 浠撳偍鐗╂祦
+ - listitem [ref=f1e74]:
+ - generic [ref=f1e75] [cursor=pointer]: 鐢熶骇绠℃帶
+ - listitem [ref=f1e82]:
+ - generic [ref=f1e83] [cursor=pointer]: 璐ㄩ噺绠$悊
+ - listitem [ref=f1e89]:
+ - generic [ref=f1e90] [cursor=pointer]: 鍗忓悓鍔炲叕
+ - listitem [ref=f1e96]:
+ - generic [ref=f1e97] [cursor=pointer]: 浜哄姏璧勬簮
+ - listitem [ref=f1e103]:
+ - generic [ref=f1e104] [cursor=pointer]: 鍩虹璁炬柦
+ - listitem [ref=f1e110]:
+ - generic [ref=f1e111] [cursor=pointer]: 绯荤粺绠$悊
+ - listitem [ref=f1e117]:
+ - generic [ref=f1e118] [cursor=pointer]: IM 鍗虫椂閫氳
+ - generic [ref=f1e131]:
+ - generic [ref=f1e132]:
+ - banner [ref=f1e133]:
+ - button [ref=f1e134] [cursor=pointer]
+ - button [ref=f1e137] [cursor=pointer]
+ - navigation "breadcrumb" [ref=f1e142]:
+ - list [ref=f1e143]:
+ - listitem [ref=f1e144]:
+ - link [ref=f1e145] [cursor=pointer]:
+ - /url: javascript:void 0
+ - listitem [ref=f1e152]
+ - listitem [ref=f1e155]:
+ - link "鎷涙爣璇︽儏" [disabled] [ref=f1e156]
+ - generic [ref=f1e159]:
+ - generic [ref=f1e161] [cursor=pointer]:
+ - generic [ref=f1e165]: 鎼滅储
+ - generic [ref=f1e166]: Ctrl K
+ - button [ref=f1e168] [cursor=pointer]
+ - button "dark" [ref=f1e173] [cursor=pointer]
+ - button [ref=f1e182] [cursor=pointer]
+ - button [ref=f1e188] [cursor=pointer]
+ - button [ref=f1e191] [cursor=pointer]
+ - button [ref=f1e197] [cursor=pointer]:
+ - button [ref=f1e199]
+ - button "宸ヤ綔鍙�" [ref=f1e203] [cursor=pointer]
+ - button "婧愮爜" [ref=f1e207] [cursor=pointer]
+ - generic [ref=f1e214]:
+ - generic [ref=f1e219]:
+ - generic [ref=f1e220] [cursor=pointer]: 鍒嗘瀽椤�
+ - generic [ref=f1e238] [cursor=pointer]: 鎷涙爣璇︽儏
+ - button [ref=f1e254] [cursor=pointer]
+ - main [ref=f1e272]:
+ - generic [ref=f1e275]:
+ - generic [ref=f1e276]:
+ - button [ref=f1e277] [cursor=pointer]
+ - generic [ref=f1e280]: 娴嬭瘯椤圭洰
+ - generic [ref=f1e281]: 娴嬭瘯缂栧彿
+ - generic [ref=f1e282]: 璇勬爣涓�
+ - generic [ref=f1e283]: 鍏紑鎷涙爣
+ - button "鍒锋柊" [ref=f1e284] [cursor=pointer]
+ - generic [ref=f1e290]:
+ - generic:
+ - generic "鑽夌"
+ - generic "鍙戝竷"
+ - generic "鎶曟爣涓�"
+ - generic "璇勬爣涓�"
+ - generic "宸插畾鏍�"
+ - generic [ref=f1e291]:
+ - generic [ref=f1e292]:
+ - generic [ref=f1e293]: 棰勭畻閲戦
+ - generic [ref=f1e294]: 15,000 鍏�
+ - generic [ref=f1e295]:
+ - generic [ref=f1e296]: 璐熻矗浜�
+ - generic [ref=f1e297]: "-"
+ - generic [ref=f1e298]:
+ - generic [ref=f1e299]: 閲囪喘缁勭粐
+ - generic [ref=f1e300]: "-"
+ - generic [ref=f1e301]:
+ - generic [ref=f1e302]: 寮�鏍囨椂闂�
+ - generic [ref=f1e303]: 2026-07-29 11:20:11
+ - generic [ref=f1e304]:
+ - generic [ref=f1e305]: 寮�濮嬫椂闂�
+ - generic [ref=f1e306]: 2026-07-29 11:13:02
+ - generic [ref=f1e307]:
+ - generic [ref=f1e308]: 鎴鏃堕棿
+ - generic [ref=f1e309]: 2026-07-29 19:13:06
+ - generic [ref=f1e313]:
+ - tablist [ref=f1e314]:
+ - generic [ref=f1e316]:
+ - tab [ref=f1e318] [cursor=pointer]
+ - tab [ref=f1e323] [cursor=pointer]
+ - tab [ref=f1e328] [cursor=pointer]
+ - tab [ref=f1e333] [cursor=pointer]
+ - tab [ref=f1e338] [cursor=pointer]
+ - tab [active] [selected] [ref=f1e343] [cursor=pointer]
+ - tabpanel "瀹氭爣" [ref=f1e404]:
+ - generic [ref=f1e405]:
+ - generic "灏氭湭瀹氭爣"
+ - button "鍒涘缓瀹氭爣" [ref=f1e406] [cursor=pointer]
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-07-29T06-47-57-125Z.yml b/.playwright-mcp/page-2026-07-29T06-47-57-125Z.yml
new file mode 100644
index 0000000..3bbcfe5
--- /dev/null
+++ b/.playwright-mcp/page-2026-07-29T06-47-57-125Z.yml
@@ -0,0 +1,152 @@
+- generic [ref=f1e4]:
+ - generic [ref=f1e7]:
+ - complementary [ref=f1e8]:
+ - generic [ref=f1e9]:
+ - link "宸ュ巶鏁板瓧鍖朚OM绯荤粺 宸ュ巶鏁板瓧鍖朚OM绯荤粺" [ref=f1e15] [cursor=pointer]:
+ - /url: javascript:void 0
+ - img "宸ュ巶鏁板瓧鍖朚OM绯荤粺" [ref=f1e18]
+ - generic [ref=f1e19]: 宸ュ巶鏁板瓧鍖朚OM绯荤粺
+ - menu [ref=f1e22]:
+ - listitem [ref=f1e23]:
+ - generic [ref=f1e24] [cursor=pointer]: 姒傝
+ - listitem [ref=f1e34]:
+ - generic [ref=f1e35] [cursor=pointer]: 鍩虹鏁版嵁
+ - listitem [ref=f1e43]:
+ - generic [ref=f1e44] [cursor=pointer]: 閲囪喘绠$悊
+ - listitem [ref=f1e50]:
+ - generic [ref=f1e51] [cursor=pointer]: 钀ラ攢绠$悊
+ - listitem [ref=f1e57]:
+ - generic [ref=f1e58] [cursor=pointer]: 璁惧绠$悊
+ - listitem [ref=f1e65]:
+ - generic [ref=f1e66] [cursor=pointer]: 浠撳偍鐗╂祦
+ - listitem [ref=f1e74]:
+ - generic [ref=f1e75] [cursor=pointer]: 鐢熶骇绠℃帶
+ - listitem [ref=f1e82]:
+ - generic [ref=f1e83] [cursor=pointer]: 璐ㄩ噺绠$悊
+ - listitem [ref=f1e89]:
+ - generic [ref=f1e90] [cursor=pointer]: 鍗忓悓鍔炲叕
+ - listitem [ref=f1e96]:
+ - generic [ref=f1e97] [cursor=pointer]: 浜哄姏璧勬簮
+ - listitem [ref=f1e103]:
+ - generic [ref=f1e104] [cursor=pointer]: 鍩虹璁炬柦
+ - listitem [ref=f1e110]:
+ - generic [ref=f1e111] [cursor=pointer]: 绯荤粺绠$悊
+ - listitem [ref=f1e117]:
+ - generic [ref=f1e118] [cursor=pointer]: IM 鍗虫椂閫氳
+ - generic [ref=f1e131]:
+ - generic [ref=f1e132]:
+ - banner [ref=f1e133]:
+ - button [ref=f1e134] [cursor=pointer]
+ - button [ref=f1e137] [cursor=pointer]
+ - navigation "breadcrumb" [ref=f1e142]:
+ - list [ref=f1e143]:
+ - listitem [ref=f1e144]:
+ - link [ref=f1e145] [cursor=pointer]:
+ - /url: javascript:void 0
+ - listitem [ref=f1e152]
+ - listitem [ref=f1e155]:
+ - link "鎷涙爣璇︽儏" [disabled] [ref=f1e156]
+ - generic [ref=f1e159]:
+ - generic [ref=f1e161] [cursor=pointer]:
+ - generic [ref=f1e165]: 鎼滅储
+ - generic [ref=f1e166]: Ctrl K
+ - button [ref=f1e168] [cursor=pointer]
+ - button "dark" [ref=f1e173] [cursor=pointer]
+ - button [ref=f1e182] [cursor=pointer]
+ - button [ref=f1e188] [cursor=pointer]
+ - button [ref=f1e191] [cursor=pointer]
+ - button [ref=f1e197] [cursor=pointer]:
+ - button [ref=f1e199]
+ - button "宸ヤ綔鍙�" [ref=f1e203] [cursor=pointer]
+ - button "婧愮爜" [ref=f1e207] [cursor=pointer]
+ - generic [ref=f1e214]:
+ - generic [ref=f1e219]:
+ - generic [ref=f1e220] [cursor=pointer]: 鍒嗘瀽椤�
+ - generic [ref=f1e238] [cursor=pointer]: 鎷涙爣璇︽儏
+ - button [ref=f1e254] [cursor=pointer]
+ - main [ref=f1e272]:
+ - generic [ref=f1e275]:
+ - generic [ref=f1e276]:
+ - button [ref=f1e277] [cursor=pointer]
+ - generic [ref=f1e280]: 娴嬭瘯椤圭洰
+ - generic [ref=f1e281]: 娴嬭瘯缂栧彿
+ - generic [ref=f1e282]: 璇勬爣涓�
+ - generic [ref=f1e283]: 鍏紑鎷涙爣
+ - button "鍒锋柊" [ref=f1e284] [cursor=pointer]
+ - generic [ref=f1e290]:
+ - generic:
+ - generic "鑽夌"
+ - generic "鍙戝竷"
+ - generic "鎶曟爣涓�"
+ - generic "璇勬爣涓�"
+ - generic "宸插畾鏍�"
+ - generic [ref=f1e291]:
+ - generic [ref=f1e292]:
+ - generic [ref=f1e293]: 棰勭畻閲戦
+ - generic [ref=f1e294]: 15,000 鍏�
+ - generic [ref=f1e295]:
+ - generic [ref=f1e296]: 璐熻矗浜�
+ - generic [ref=f1e297]: "-"
+ - generic [ref=f1e298]:
+ - generic [ref=f1e299]: 閲囪喘缁勭粐
+ - generic [ref=f1e300]: "-"
+ - generic [ref=f1e301]:
+ - generic [ref=f1e302]: 寮�鏍囨椂闂�
+ - generic [ref=f1e303]: 2026-07-29 11:20:11
+ - generic [ref=f1e304]:
+ - generic [ref=f1e305]: 寮�濮嬫椂闂�
+ - generic [ref=f1e306]: 2026-07-29 11:13:02
+ - generic [ref=f1e307]:
+ - generic [ref=f1e308]: 鎴鏃堕棿
+ - generic [ref=f1e309]: 2026-07-29 19:13:06
+ - generic [ref=f1e313]:
+ - tablist [ref=f1e314]:
+ - generic [ref=f1e316]:
+ - tab [ref=f1e318] [cursor=pointer]
+ - tab [ref=f1e323] [cursor=pointer]
+ - tab [ref=f1e328] [cursor=pointer]
+ - tab [ref=f1e333] [cursor=pointer]
+ - tab [ref=f1e338] [cursor=pointer]
+ - tab [selected] [ref=f1e343] [cursor=pointer]
+ - tabpanel "瀹氭爣" [ref=f1e404]:
+ - generic [ref=f1e405]:
+ - generic "灏氭湭瀹氭爣"
+ - button "鍒涘缓瀹氭爣" [active] [ref=f1e406] [cursor=pointer]
+ - dialog "鍒涘缓瀹氭爣" [ref=f1e412]:
+ - document:
+ - generic [ref=f1e413]:
+ - button "Close" [ref=f1e414] [cursor=pointer]:
+ - img "close" [ref=f1e416]
+ - generic [ref=f1e419]: 鍒涘缓瀹氭爣
+ - generic [ref=f1e422]:
+ - generic [ref=f1e424]:
+ - generic "瀹氭爣缂栧彿" [ref=f1e426]: "* 瀹氭爣缂栧彿"
+ - textbox "濡� AWARD2024010001" [ref=f1e430]
+ - generic [ref=f1e431]:
+ - generic [ref=f1e434]:
+ - generic "渚涘簲鍟�" [ref=f1e436]: "* 渚涘簲鍟�"
+ - generic [ref=f1e441]:
+ - combobox [ref=f1e443]
+ - generic "0" [ref=f1e444]
+ - generic [ref=f1e447]:
+ - generic "鎶曟爣" [ref=f1e449]: "* 鎶曟爣"
+ - generic [ref=f1e454]:
+ - combobox [ref=f1e456]
+ - generic "0" [ref=f1e457]
+ - generic [ref=f1e459]:
+ - generic "瀹氭爣閲戦" [ref=f1e461]: "* 瀹氭爣閲戦"
+ - generic [ref=f1e466]:
+ - generic [ref=f1e467]:
+ - generic [ref=f1e468]:
+ - button "Increase Value" [ref=f1e469] [cursor=pointer]:
+ - img "up" [ref=f1e470]
+ - button "Decrease Value" [ref=f1e473] [cursor=pointer]:
+ - img "down" [ref=f1e474]
+ - spinbutton "瀹氭爣閲戦" [ref=f1e478]
+ - generic [ref=f1e479]: 鍏�
+ - generic [ref=f1e481]:
+ - generic "澶囨敞" [ref=f1e483]
+ - textbox "濡傦細缁煎悎璇勬爣绗竴鍚�" [ref=f1e487]
+ - generic [ref=f1e488]:
+ - button "鍙� 娑�" [ref=f1e489] [cursor=pointer]
+ - button "纭� 瀹�" [ref=f1e491] [cursor=pointer]
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-07-29T06-51-00-932Z.yml b/.playwright-mcp/page-2026-07-29T06-51-00-932Z.yml
new file mode 100644
index 0000000..f4d9f7c
--- /dev/null
+++ b/.playwright-mcp/page-2026-07-29T06-51-00-932Z.yml
@@ -0,0 +1,152 @@
+- generic [ref=f1e4]:
+ - generic [ref=f1e7]:
+ - complementary [ref=f1e8]:
+ - generic [ref=f1e9]:
+ - link "宸ュ巶鏁板瓧鍖朚OM绯荤粺 宸ュ巶鏁板瓧鍖朚OM绯荤粺" [ref=f1e15] [cursor=pointer]:
+ - /url: javascript:void 0
+ - img "宸ュ巶鏁板瓧鍖朚OM绯荤粺" [ref=f1e18]
+ - generic [ref=f1e19]: 宸ュ巶鏁板瓧鍖朚OM绯荤粺
+ - menu [ref=f1e22]:
+ - listitem [ref=f1e23]:
+ - generic [ref=f1e24] [cursor=pointer]: 姒傝
+ - listitem [ref=f1e34]:
+ - generic [ref=f1e35] [cursor=pointer]: 鍩虹鏁版嵁
+ - listitem [ref=f1e43]:
+ - generic [ref=f1e44] [cursor=pointer]: 閲囪喘绠$悊
+ - listitem [ref=f1e50]:
+ - generic [ref=f1e51] [cursor=pointer]: 钀ラ攢绠$悊
+ - listitem [ref=f1e57]:
+ - generic [ref=f1e58] [cursor=pointer]: 璁惧绠$悊
+ - listitem [ref=f1e65]:
+ - generic [ref=f1e66] [cursor=pointer]: 浠撳偍鐗╂祦
+ - listitem [ref=f1e74]:
+ - generic [ref=f1e75] [cursor=pointer]: 鐢熶骇绠℃帶
+ - listitem [ref=f1e82]:
+ - generic [ref=f1e83] [cursor=pointer]: 璐ㄩ噺绠$悊
+ - listitem [ref=f1e89]:
+ - generic [ref=f1e90] [cursor=pointer]: 鍗忓悓鍔炲叕
+ - listitem [ref=f1e96]:
+ - generic [ref=f1e97] [cursor=pointer]: 浜哄姏璧勬簮
+ - listitem [ref=f1e103]:
+ - generic [ref=f1e104] [cursor=pointer]: 鍩虹璁炬柦
+ - listitem [ref=f1e110]:
+ - generic [ref=f1e111] [cursor=pointer]: 绯荤粺绠$悊
+ - listitem [ref=f1e117]:
+ - generic [ref=f1e118] [cursor=pointer]: IM 鍗虫椂閫氳
+ - generic [ref=f1e131]:
+ - generic [ref=f1e132]:
+ - banner [ref=f1e133]:
+ - button [ref=f1e134] [cursor=pointer]
+ - button [ref=f1e137] [cursor=pointer]
+ - navigation "breadcrumb" [ref=f1e142]:
+ - list [ref=f1e143]:
+ - listitem [ref=f1e144]:
+ - link [ref=f1e145] [cursor=pointer]:
+ - /url: javascript:void 0
+ - listitem [ref=f1e152]
+ - listitem [ref=f1e155]:
+ - link "鎷涙爣璇︽儏" [disabled] [ref=f1e156]
+ - generic [ref=f1e159]:
+ - generic [ref=f1e161] [cursor=pointer]:
+ - generic [ref=f1e165]: 鎼滅储
+ - generic [ref=f1e166]: Ctrl K
+ - button [ref=f1e168] [cursor=pointer]
+ - button "dark" [ref=f1e173] [cursor=pointer]
+ - button [ref=f1e182] [cursor=pointer]
+ - button [ref=f1e188] [cursor=pointer]
+ - button [ref=f1e191] [cursor=pointer]
+ - button [ref=f1e197] [cursor=pointer]:
+ - button [ref=f1e199]
+ - button "宸ヤ綔鍙�" [ref=f1e203] [cursor=pointer]
+ - button "婧愮爜" [ref=f1e207] [cursor=pointer]
+ - generic [ref=f1e214]:
+ - generic [ref=f1e219]:
+ - generic [ref=f1e220] [cursor=pointer]: 鍒嗘瀽椤�
+ - generic [ref=f1e238] [cursor=pointer]: 鎷涙爣璇︽儏
+ - button [ref=f1e254] [cursor=pointer]
+ - main [ref=f1e272]:
+ - generic [ref=f1e275]:
+ - generic [ref=f1e276]:
+ - button [ref=f1e277] [cursor=pointer]
+ - generic [ref=f1e280]: 娴嬭瘯椤圭洰
+ - generic [ref=f1e281]: 娴嬭瘯缂栧彿
+ - generic [ref=f1e282]: 璇勬爣涓�
+ - generic [ref=f1e283]: 鍏紑鎷涙爣
+ - button "鍒锋柊" [ref=f1e284] [cursor=pointer]
+ - generic [ref=f1e290]:
+ - generic:
+ - generic "鑽夌"
+ - generic "鍙戝竷"
+ - generic "鎶曟爣涓�"
+ - generic "璇勬爣涓�"
+ - generic "宸插畾鏍�"
+ - generic [ref=f1e291]:
+ - generic [ref=f1e292]:
+ - generic [ref=f1e293]: 棰勭畻閲戦
+ - generic [ref=f1e294]: 15,000 鍏�
+ - generic [ref=f1e295]:
+ - generic [ref=f1e296]: 璐熻矗浜�
+ - generic [ref=f1e297]: "-"
+ - generic [ref=f1e298]:
+ - generic [ref=f1e299]: 閲囪喘缁勭粐
+ - generic [ref=f1e300]: "-"
+ - generic [ref=f1e301]:
+ - generic [ref=f1e302]: 寮�鏍囨椂闂�
+ - generic [ref=f1e303]: 2026-07-29 11:20:11
+ - generic [ref=f1e304]:
+ - generic [ref=f1e305]: 寮�濮嬫椂闂�
+ - generic [ref=f1e306]: 2026-07-29 11:13:02
+ - generic [ref=f1e307]:
+ - generic [ref=f1e308]: 鎴鏃堕棿
+ - generic [ref=f1e309]: 2026-07-29 19:13:06
+ - generic [ref=f1e313]:
+ - tablist [ref=f1e314]:
+ - generic [ref=f1e316]:
+ - tab [ref=f1e318] [cursor=pointer]
+ - tab [ref=f1e323] [cursor=pointer]
+ - tab [ref=f1e328] [cursor=pointer]
+ - tab [ref=f1e333] [cursor=pointer]
+ - tab [ref=f1e338] [cursor=pointer]
+ - tab [selected] [ref=f1e343] [cursor=pointer]
+ - tabpanel "瀹氭爣" [ref=f1e404]:
+ - generic [ref=f1e405]:
+ - generic "灏氭湭瀹氭爣"
+ - button "鍒涘缓瀹氭爣" [ref=f1e406] [cursor=pointer]
+ - dialog "鍒涘缓瀹氭爣" [ref=f1e412]:
+ - document:
+ - generic [ref=f1e413]:
+ - button "Close" [ref=f1e414] [cursor=pointer]:
+ - img "close" [ref=f1e416]
+ - generic [ref=f1e419]: 鍒涘缓瀹氭爣
+ - generic [ref=f1e422]:
+ - generic [ref=f1e424]:
+ - generic "瀹氭爣缂栧彿" [ref=f1e426]: "* 瀹氭爣缂栧彿"
+ - textbox "濡� AWARD2024010001" [ref=f1e430]
+ - generic [ref=f1e431]:
+ - generic [ref=f1e434]:
+ - generic "渚涘簲鍟�" [ref=f1e436]: "* 渚涘簲鍟�"
+ - generic [ref=f1e441]:
+ - combobox [ref=f1e443]
+ - generic "0" [ref=f1e444]
+ - generic [ref=f1e447]:
+ - generic "鎶曟爣" [ref=f1e449]: "* 鎶曟爣"
+ - generic [ref=f1e454]:
+ - combobox [ref=f1e456]
+ - generic "0" [ref=f1e457]
+ - generic [ref=f1e459]:
+ - generic "瀹氭爣閲戦" [ref=f1e461]: "* 瀹氭爣閲戦"
+ - generic [ref=f1e466]:
+ - generic [ref=f1e467]:
+ - generic [ref=f1e468]:
+ - button "Increase Value" [ref=f1e469] [cursor=pointer]:
+ - img "up" [ref=f1e470]
+ - button "Decrease Value" [ref=f1e473] [cursor=pointer]:
+ - img "down" [ref=f1e474]
+ - spinbutton "瀹氭爣閲戦" [ref=f1e478]
+ - generic [ref=f1e479]: 鍏�
+ - generic [ref=f1e481]:
+ - generic "澶囨敞" [ref=f1e483]
+ - textbox "濡傦細缁煎悎璇勬爣绗竴鍚�" [ref=f1e487]
+ - generic [ref=f1e488]:
+ - button "鍙� 娑�" [ref=f1e489] [cursor=pointer]
+ - button "纭� 瀹�" [ref=f1e491] [cursor=pointer]
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-07-29T06-56-04-077Z.yml b/.playwright-mcp/page-2026-07-29T06-56-04-077Z.yml
new file mode 100644
index 0000000..987bb5e
--- /dev/null
+++ b/.playwright-mcp/page-2026-07-29T06-56-04-077Z.yml
@@ -0,0 +1 @@
+- generic [active]: 宸ュ巶鏁板瓧鍖朚OM绯荤粺
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-07-29T06-56-14-335Z.yml b/.playwright-mcp/page-2026-07-29T06-56-14-335Z.yml
new file mode 100644
index 0000000..090f728
--- /dev/null
+++ b/.playwright-mcp/page-2026-07-29T06-56-14-335Z.yml
@@ -0,0 +1,122 @@
+- generic [ref=f2e7]:
+ - complementary [ref=f2e8]:
+ - generic [ref=f2e9]:
+ - link "宸ュ巶鏁板瓧鍖朚OM绯荤粺 宸ュ巶鏁板瓧鍖朚OM绯荤粺" [ref=f2e15] [cursor=pointer]:
+ - /url: javascript:void 0
+ - img "宸ュ巶鏁板瓧鍖朚OM绯荤粺" [ref=f2e18]
+ - generic [ref=f2e19]: 宸ュ巶鏁板瓧鍖朚OM绯荤粺
+ - menu [ref=f2e22]:
+ - listitem [ref=f2e23]:
+ - generic [ref=f2e24] [cursor=pointer]: 姒傝
+ - listitem [ref=f2e34]:
+ - generic [ref=f2e35] [cursor=pointer]: 鍩虹鏁版嵁
+ - listitem [ref=f2e43]:
+ - generic [ref=f2e44] [cursor=pointer]: 閲囪喘绠$悊
+ - listitem [ref=f2e50]:
+ - generic [ref=f2e51] [cursor=pointer]: 钀ラ攢绠$悊
+ - listitem [ref=f2e57]:
+ - generic [ref=f2e58] [cursor=pointer]: 璁惧绠$悊
+ - listitem [ref=f2e65]:
+ - generic [ref=f2e66] [cursor=pointer]: 浠撳偍鐗╂祦
+ - listitem [ref=f2e74]:
+ - generic [ref=f2e75] [cursor=pointer]: 鐢熶骇绠℃帶
+ - listitem [ref=f2e82]:
+ - generic [ref=f2e83] [cursor=pointer]: 璐ㄩ噺绠$悊
+ - listitem [ref=f2e89]:
+ - generic [ref=f2e90] [cursor=pointer]: 鍗忓悓鍔炲叕
+ - listitem [ref=f2e96]:
+ - generic [ref=f2e97] [cursor=pointer]: 浜哄姏璧勬簮
+ - listitem [ref=f2e103]:
+ - generic [ref=f2e104] [cursor=pointer]: 鍩虹璁炬柦
+ - listitem [ref=f2e110]:
+ - generic [ref=f2e111] [cursor=pointer]: 绯荤粺绠$悊
+ - listitem [ref=f2e117]:
+ - generic [ref=f2e118] [cursor=pointer]: IM 鍗虫椂閫氳
+ - generic [ref=f2e131]:
+ - generic [ref=f2e132]:
+ - banner [ref=f2e133]:
+ - button [ref=f2e134] [cursor=pointer]
+ - button [ref=f2e137] [cursor=pointer]
+ - navigation "breadcrumb" [ref=f2e142]:
+ - list [ref=f2e143]:
+ - listitem [ref=f2e144]:
+ - link [ref=f2e145] [cursor=pointer]:
+ - /url: javascript:void 0
+ - listitem [ref=f2e152]
+ - listitem [ref=f2e155]:
+ - link "鎷涙爣璇︽儏" [disabled] [ref=f2e156]
+ - generic [ref=f2e159]:
+ - generic [ref=f2e161] [cursor=pointer]:
+ - generic [ref=f2e165]: 鎼滅储
+ - generic [ref=f2e166]: Ctrl K
+ - button [ref=f2e168] [cursor=pointer]
+ - button "dark" [ref=f2e173] [cursor=pointer]
+ - button [ref=f2e182] [cursor=pointer]
+ - button [ref=f2e188] [cursor=pointer]
+ - button [ref=f2e191] [cursor=pointer]
+ - button [ref=f2e197] [cursor=pointer]:
+ - button [ref=f2e199]
+ - button "宸ヤ綔鍙�" [ref=f2e203] [cursor=pointer]
+ - button "婧愮爜" [ref=f2e207] [cursor=pointer]
+ - generic [ref=f2e214]:
+ - generic [ref=f2e219]:
+ - generic [ref=f2e220] [cursor=pointer]: 鍒嗘瀽椤�
+ - generic [ref=f2e238] [cursor=pointer]: 鎷涙爣璇︽儏
+ - button [ref=f2e254] [cursor=pointer]
+ - main [ref=f2e272]:
+ - generic [ref=f2e275]:
+ - generic [ref=f2e276]:
+ - button [ref=f2e277] [cursor=pointer]
+ - generic [ref=f2e280]: 娴嬭瘯椤圭洰
+ - generic [ref=f2e281]: 娴嬭瘯缂栧彿
+ - generic [ref=f2e282]: 宸插畾鏍�
+ - generic [ref=f2e283]: 鍏紑鎷涙爣
+ - button "鍒锋柊" [ref=f2e284] [cursor=pointer]
+ - generic [ref=f2e290]:
+ - generic:
+ - generic "鑽夌"
+ - generic "鍙戝竷"
+ - generic "鎶曟爣涓�"
+ - generic "璇勬爣涓�"
+ - generic "宸插畾鏍�"
+ - generic [ref=f2e291]:
+ - generic [ref=f2e292]:
+ - generic [ref=f2e293]: 棰勭畻閲戦
+ - generic [ref=f2e294]: 15,000 鍏�
+ - generic [ref=f2e295]:
+ - generic [ref=f2e296]: 璐熻矗浜�
+ - generic [ref=f2e297]: "-"
+ - generic [ref=f2e298]:
+ - generic [ref=f2e299]: 閲囪喘缁勭粐
+ - generic [ref=f2e300]: "-"
+ - generic [ref=f2e301]:
+ - generic [ref=f2e302]: 寮�鏍囨椂闂�
+ - generic [ref=f2e303]: 2026-07-29 11:20:11
+ - generic [ref=f2e304]:
+ - generic [ref=f2e305]: 寮�濮嬫椂闂�
+ - generic [ref=f2e306]: 2026-07-29 11:13:02
+ - generic [ref=f2e307]:
+ - generic [ref=f2e308]: 鎴鏃堕棿
+ - generic [ref=f2e309]: 2026-07-29 19:13:06
+ - generic [ref=f2e313]:
+ - tablist [ref=f2e314]:
+ - generic [ref=f2e316]:
+ - tab [ref=f2e318] [cursor=pointer]
+ - tab [ref=f2e323] [cursor=pointer]
+ - tab [ref=f2e328] [cursor=pointer]
+ - tab [ref=f2e333] [cursor=pointer]
+ - tab [ref=f2e338] [cursor=pointer]
+ - tab [active] [selected] [ref=f2e343] [cursor=pointer]
+ - tabpanel "瀹氭爣" [ref=f2e350]:
+ - generic [ref=f2e351]:
+ - generic [ref=f2e353]:
+ - generic [ref=f2e354]: 宸插畾琛�
+ - generic [ref=f2e355]: "12"
+ - generic [ref=f2e357]: 10,000 鍏�
+ - text: 2026-07-29 14:52:43
+ - generic [ref=f2e358]: 宸插畾鏍�
+ - text: 寰呯敓鎴愮患鍚堣瘎瀹�
+ - generic [ref=f2e361]:
+ - generic "瀹氭爣瀹屾垚"
+ - button "鐢熸垚閲囪喘璁㈠崟" [ref=f2e362] [cursor=pointer]
+ - button "鍒犻櫎瀹氭爣" [ref=f2e366] [cursor=pointer]
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-07-29T07-10-45-745Z.yml b/.playwright-mcp/page-2026-07-29T07-10-45-745Z.yml
new file mode 100644
index 0000000..987bb5e
--- /dev/null
+++ b/.playwright-mcp/page-2026-07-29T07-10-45-745Z.yml
@@ -0,0 +1 @@
+- generic [active]: 宸ュ巶鏁板瓧鍖朚OM绯荤粺
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-07-29T07-12-31-548Z.yml b/.playwright-mcp/page-2026-07-29T07-12-31-548Z.yml
new file mode 100644
index 0000000..5dde7b1
--- /dev/null
+++ b/.playwright-mcp/page-2026-07-29T07-12-31-548Z.yml
@@ -0,0 +1,121 @@
+- generic [ref=f3e7]:
+ - complementary [ref=f3e8]:
+ - generic [ref=f3e9]:
+ - link "宸ュ巶鏁板瓧鍖朚OM绯荤粺 宸ュ巶鏁板瓧鍖朚OM绯荤粺" [ref=f3e15] [cursor=pointer]:
+ - /url: javascript:void 0
+ - img "宸ュ巶鏁板瓧鍖朚OM绯荤粺" [ref=f3e18]
+ - generic [ref=f3e19]: 宸ュ巶鏁板瓧鍖朚OM绯荤粺
+ - menu [ref=f3e22]:
+ - listitem [ref=f3e23]:
+ - generic [ref=f3e24] [cursor=pointer]: 姒傝
+ - listitem [ref=f3e34]:
+ - generic [ref=f3e35] [cursor=pointer]: 鍩虹鏁版嵁
+ - listitem [ref=f3e43]:
+ - generic [ref=f3e44] [cursor=pointer]: 閲囪喘绠$悊
+ - listitem [ref=f3e50]:
+ - generic [ref=f3e51] [cursor=pointer]: 钀ラ攢绠$悊
+ - listitem [ref=f3e57]:
+ - generic [ref=f3e58] [cursor=pointer]: 璁惧绠$悊
+ - listitem [ref=f3e65]:
+ - generic [ref=f3e66] [cursor=pointer]: 浠撳偍鐗╂祦
+ - listitem [ref=f3e74]:
+ - generic [ref=f3e75] [cursor=pointer]: 鐢熶骇绠℃帶
+ - listitem [ref=f3e82]:
+ - generic [ref=f3e83] [cursor=pointer]: 璐ㄩ噺绠$悊
+ - listitem [ref=f3e89]:
+ - generic [ref=f3e90] [cursor=pointer]: 鍗忓悓鍔炲叕
+ - listitem [ref=f3e96]:
+ - generic [ref=f3e97] [cursor=pointer]: 浜哄姏璧勬簮
+ - listitem [ref=f3e103]:
+ - generic [ref=f3e104] [cursor=pointer]: 鍩虹璁炬柦
+ - listitem [ref=f3e110]:
+ - generic [ref=f3e111] [cursor=pointer]: 绯荤粺绠$悊
+ - listitem [ref=f3e117]:
+ - generic [ref=f3e118] [cursor=pointer]: IM 鍗虫椂閫氳
+ - generic [ref=f3e131]:
+ - generic [ref=f3e132]:
+ - banner [ref=f3e133]:
+ - button [ref=f3e134] [cursor=pointer]
+ - button [ref=f3e137] [cursor=pointer]
+ - navigation "breadcrumb" [ref=f3e142]:
+ - list [ref=f3e143]:
+ - listitem [ref=f3e144]:
+ - link [ref=f3e145] [cursor=pointer]:
+ - /url: javascript:void 0
+ - listitem [ref=f3e152]
+ - listitem [ref=f3e155]:
+ - link "鎷涙爣璇︽儏" [disabled] [ref=f3e156]
+ - generic [ref=f3e159]:
+ - generic [ref=f3e161] [cursor=pointer]:
+ - generic [ref=f3e165]: 鎼滅储
+ - generic [ref=f3e166]: Ctrl K
+ - button [ref=f3e168] [cursor=pointer]
+ - button "dark" [ref=f3e173] [cursor=pointer]
+ - button [ref=f3e182] [cursor=pointer]
+ - button [ref=f3e188] [cursor=pointer]
+ - button [ref=f3e191] [cursor=pointer]
+ - button [ref=f3e197] [cursor=pointer]:
+ - button [ref=f3e199]
+ - button "宸ヤ綔鍙�" [ref=f3e203] [cursor=pointer]
+ - button "婧愮爜" [ref=f3e207] [cursor=pointer]
+ - generic [ref=f3e214]:
+ - generic [ref=f3e219]:
+ - generic [ref=f3e220] [cursor=pointer]: 鍒嗘瀽椤�
+ - generic [ref=f3e238] [cursor=pointer]: 鎷涙爣璇︽儏
+ - button [ref=f3e254] [cursor=pointer]
+ - main [ref=f3e272]:
+ - generic [ref=f3e275]:
+ - generic [ref=f3e276]:
+ - button [ref=f3e277] [cursor=pointer]
+ - generic [ref=f3e280]: 娴嬭瘯椤圭洰
+ - generic [ref=f3e281]: 娴嬭瘯缂栧彿
+ - generic [ref=f3e282]: 宸插畾鏍�
+ - generic [ref=f3e283]: 鍏紑鎷涙爣
+ - button "鍒锋柊" [ref=f3e284] [cursor=pointer]
+ - generic [ref=f3e290]:
+ - generic:
+ - generic "鑽夌"
+ - generic "鍙戝竷"
+ - generic "鎶曟爣涓�"
+ - generic "璇勬爣涓�"
+ - generic "宸插畾鏍�"
+ - generic [ref=f3e291]:
+ - generic [ref=f3e292]:
+ - generic [ref=f3e293]: 棰勭畻閲戦
+ - generic [ref=f3e294]: 15,000 鍏�
+ - generic [ref=f3e295]:
+ - generic [ref=f3e296]: 璐熻矗浜�
+ - generic [ref=f3e297]: "-"
+ - generic [ref=f3e298]:
+ - generic [ref=f3e299]: 閲囪喘缁勭粐
+ - generic [ref=f3e300]: "-"
+ - generic [ref=f3e301]:
+ - generic [ref=f3e302]: 寮�鏍囨椂闂�
+ - generic [ref=f3e303]: 2026-07-29 11:20:11
+ - generic [ref=f3e304]:
+ - generic [ref=f3e305]: 寮�濮嬫椂闂�
+ - generic [ref=f3e306]: 2026-07-29 11:13:02
+ - generic [ref=f3e307]:
+ - generic [ref=f3e308]: 鎴鏃堕棿
+ - generic [ref=f3e309]: 2026-07-29 19:13:06
+ - generic [ref=f3e313]:
+ - tablist [ref=f3e314]:
+ - generic [ref=f3e316]:
+ - tab [ref=f3e318] [cursor=pointer]
+ - tab [ref=f3e323] [cursor=pointer]
+ - tab [ref=f3e328] [cursor=pointer]
+ - tab [ref=f3e333] [cursor=pointer]
+ - tab [ref=f3e338] [cursor=pointer]
+ - tab [active] [selected] [ref=f3e343] [cursor=pointer]
+ - tabpanel "瀹氭爣" [ref=f3e404]:
+ - generic [ref=f3e405]:
+ - generic [ref=f3e407]:
+ - generic [ref=f3e408]: 宸插畾琛�
+ - generic [ref=f3e409]: "12"
+ - generic [ref=f3e411]: 10,000 鍏�
+ - text: 2026-07-29 14:52:43
+ - generic [ref=f3e412]: 宸茬敓鎴愯鍗�
+ - text: 18缁煎悎璇勫畾
+ - generic [ref=f3e415]:
+ - generic "璁㈠崟宸茬敓鎴�"
+ - button "鍒犻櫎瀹氭爣" [ref=f3e416] [cursor=pointer]
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-07-29T07-14-24-445Z.yml b/.playwright-mcp/page-2026-07-29T07-14-24-445Z.yml
new file mode 100644
index 0000000..987bb5e
--- /dev/null
+++ b/.playwright-mcp/page-2026-07-29T07-14-24-445Z.yml
@@ -0,0 +1 @@
+- generic [active]: 宸ュ巶鏁板瓧鍖朚OM绯荤粺
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-07-29T07-14-44-587Z.yml b/.playwright-mcp/page-2026-07-29T07-14-44-587Z.yml
new file mode 100644
index 0000000..cff9162
--- /dev/null
+++ b/.playwright-mcp/page-2026-07-29T07-14-44-587Z.yml
@@ -0,0 +1,121 @@
+- generic [ref=f4e7]:
+ - complementary [ref=f4e8]:
+ - generic [ref=f4e9]:
+ - link "宸ュ巶鏁板瓧鍖朚OM绯荤粺 宸ュ巶鏁板瓧鍖朚OM绯荤粺" [ref=f4e15] [cursor=pointer]:
+ - /url: javascript:void 0
+ - img "宸ュ巶鏁板瓧鍖朚OM绯荤粺" [ref=f4e18]
+ - generic [ref=f4e19]: 宸ュ巶鏁板瓧鍖朚OM绯荤粺
+ - menu [ref=f4e22]:
+ - listitem [ref=f4e23]:
+ - generic [ref=f4e24] [cursor=pointer]: 姒傝
+ - listitem [ref=f4e34]:
+ - generic [ref=f4e35] [cursor=pointer]: 鍩虹鏁版嵁
+ - listitem [ref=f4e43]:
+ - generic [ref=f4e44] [cursor=pointer]: 閲囪喘绠$悊
+ - listitem [ref=f4e50]:
+ - generic [ref=f4e51] [cursor=pointer]: 钀ラ攢绠$悊
+ - listitem [ref=f4e57]:
+ - generic [ref=f4e58] [cursor=pointer]: 璁惧绠$悊
+ - listitem [ref=f4e65]:
+ - generic [ref=f4e66] [cursor=pointer]: 浠撳偍鐗╂祦
+ - listitem [ref=f4e74]:
+ - generic [ref=f4e75] [cursor=pointer]: 鐢熶骇绠℃帶
+ - listitem [ref=f4e82]:
+ - generic [ref=f4e83] [cursor=pointer]: 璐ㄩ噺绠$悊
+ - listitem [ref=f4e89]:
+ - generic [ref=f4e90] [cursor=pointer]: 鍗忓悓鍔炲叕
+ - listitem [ref=f4e96]:
+ - generic [ref=f4e97] [cursor=pointer]: 浜哄姏璧勬簮
+ - listitem [ref=f4e103]:
+ - generic [ref=f4e104] [cursor=pointer]: 鍩虹璁炬柦
+ - listitem [ref=f4e110]:
+ - generic [ref=f4e111] [cursor=pointer]: 绯荤粺绠$悊
+ - listitem [ref=f4e117]:
+ - generic [ref=f4e118] [cursor=pointer]: IM 鍗虫椂閫氳
+ - generic [ref=f4e131]:
+ - generic [ref=f4e132]:
+ - banner [ref=f4e133]:
+ - button [ref=f4e134] [cursor=pointer]
+ - button [ref=f4e137] [cursor=pointer]
+ - navigation "breadcrumb" [ref=f4e142]:
+ - list [ref=f4e143]:
+ - listitem [ref=f4e144]:
+ - link [ref=f4e145] [cursor=pointer]:
+ - /url: javascript:void 0
+ - listitem [ref=f4e152]
+ - listitem [ref=f4e155]:
+ - link "鎷涙爣璇︽儏" [disabled] [ref=f4e156]
+ - generic [ref=f4e159]:
+ - generic [ref=f4e161] [cursor=pointer]:
+ - generic [ref=f4e165]: 鎼滅储
+ - generic [ref=f4e166]: Ctrl K
+ - button [ref=f4e168] [cursor=pointer]
+ - button "dark" [ref=f4e173] [cursor=pointer]
+ - button [ref=f4e182] [cursor=pointer]
+ - button [ref=f4e188] [cursor=pointer]
+ - button [ref=f4e191] [cursor=pointer]
+ - button [ref=f4e197] [cursor=pointer]:
+ - button [ref=f4e199]
+ - button "宸ヤ綔鍙�" [ref=f4e203] [cursor=pointer]
+ - button "婧愮爜" [ref=f4e207] [cursor=pointer]
+ - generic [ref=f4e214]:
+ - generic [ref=f4e219]:
+ - generic [ref=f4e220] [cursor=pointer]: 鍒嗘瀽椤�
+ - generic [ref=f4e238] [cursor=pointer]: 鎷涙爣璇︽儏
+ - button [ref=f4e254] [cursor=pointer]
+ - main [ref=f4e272]:
+ - generic [ref=f4e275]:
+ - generic [ref=f4e276]:
+ - button [ref=f4e277] [cursor=pointer]
+ - generic [ref=f4e280]: 娴嬭瘯椤圭洰
+ - generic [ref=f4e281]: 娴嬭瘯缂栧彿
+ - generic [ref=f4e282]: 宸插畾鏍�
+ - generic [ref=f4e283]: 鍏紑鎷涙爣
+ - button "鍒锋柊" [ref=f4e284] [cursor=pointer]
+ - generic [ref=f4e290]:
+ - generic:
+ - generic "鑽夌"
+ - generic "鍙戝竷"
+ - generic "鎶曟爣涓�"
+ - generic "璇勬爣涓�"
+ - generic "宸插畾鏍�"
+ - generic [ref=f4e291]:
+ - generic [ref=f4e292]:
+ - generic [ref=f4e293]: 棰勭畻閲戦
+ - generic [ref=f4e294]: 15,000 鍏�
+ - generic [ref=f4e295]:
+ - generic [ref=f4e296]: 璐熻矗浜�
+ - generic [ref=f4e297]: "-"
+ - generic [ref=f4e298]:
+ - generic [ref=f4e299]: 閲囪喘缁勭粐
+ - generic [ref=f4e300]: "-"
+ - generic [ref=f4e301]:
+ - generic [ref=f4e302]: 寮�鏍囨椂闂�
+ - generic [ref=f4e303]: 2026-07-29 11:20:11
+ - generic [ref=f4e304]:
+ - generic [ref=f4e305]: 寮�濮嬫椂闂�
+ - generic [ref=f4e306]: 2026-07-29 11:13:02
+ - generic [ref=f4e307]:
+ - generic [ref=f4e308]: 鎴鏃堕棿
+ - generic [ref=f4e309]: 2026-07-29 19:13:06
+ - generic [ref=f4e313]:
+ - tablist [ref=f4e314]:
+ - generic [ref=f4e316]:
+ - tab [ref=f4e318] [cursor=pointer]
+ - tab [ref=f4e323] [cursor=pointer]
+ - tab [ref=f4e328] [cursor=pointer]
+ - tab [ref=f4e333] [cursor=pointer]
+ - tab [ref=f4e338] [cursor=pointer]
+ - tab [selected] [ref=f4e343] [cursor=pointer]
+ - tabpanel "瀹氭爣" [active] [ref=f4e404]:
+ - generic [ref=f4e405]:
+ - generic [ref=f4e407]:
+ - generic [ref=f4e408]: AWARD2024070001
+ - generic [ref=f4e409]: "12"
+ - generic [ref=f4e411]: 10,000 鍏�
+ - text: 2026-07-29 14:52:43
+ - generic [ref=f4e412]: 宸茬敓鎴愯鍗�
+ - text: 18缁煎悎璇勫畾
+ - generic [ref=f4e415]:
+ - generic "璁㈠崟宸茬敓鎴�"
+ - button "鍒犻櫎瀹氭爣" [ref=f4e416] [cursor=pointer]
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-07-29T07-14-58-476Z.yml b/.playwright-mcp/page-2026-07-29T07-14-58-476Z.yml
new file mode 100644
index 0000000..987bb5e
--- /dev/null
+++ b/.playwright-mcp/page-2026-07-29T07-14-58-476Z.yml
@@ -0,0 +1 @@
+- generic [active]: 宸ュ巶鏁板瓧鍖朚OM绯荤粺
\ No newline at end of file
diff --git a/docs/crm_customer_view_all.md b/docs/crm_customer_view_all.md
new file mode 100644
index 0000000..adb890c
--- /dev/null
+++ b/docs/crm_customer_view_all.md
@@ -0,0 +1,88 @@
+# 鏌ョ湅鍏ㄩ儴瀹㈡埛鏉冮檺 - 鍓嶇鑱旇皟鏂规
+
+## 娑夊強椤甸潰
+
+| 椤甸潰 | 璺敱璺緞 | 璇存槑 |
+|------|----------|------|
+| 瀹㈡埛绠$悊鍒楄〃 | `/crm/customer` | 瀹㈡埛鍒楄〃椤碉紝鏂板"鍏ㄩ儴"Tab |
+
+---
+
+## API
+
+### 宸叉湁鎺ュ彛锛氬鎴峰垎椤垫煡璇紙鏃犻渶鏂板鎺ュ彛锛�
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| GET | `/crm/customer/page` | 瀹㈡埛鍒嗛〉鏌ヨ |
+
+**宸叉湁璇锋眰鍙傛暟锛坄CrmCustomerPageReqVO`锛夛細**
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| sceneType | Integer | 鍚� | 鍦烘櫙绫诲瀷锛�1-鎴戣礋璐g殑 / 2-鎴戝弬涓庣殑 / 3-涓嬪睘璐熻矗鐨� / **4-鍏ㄩ儴锛堟柊澧烇級** |
+| name | String | 鍚� | 瀹㈡埛鍚嶇О锛堟ā绯婏級 |
+| mobile | String | 鍚� | 鎵嬫満 |
+| industryId | Integer | 鍚� | 鎵�灞炶涓� |
+| level | Integer | 鍚� | 瀹㈡埛绛夌骇 |
+| source | Integer | 鍚� | 瀹㈡埛鏉ユ簮 |
+| pool | Boolean | 鍚� | 鏄惁涓哄叕娴锋暟鎹� |
+| followUpStatus | Boolean | 鍚� | 璺熻繘鐘舵�� |
+
+**鍝嶅簲鏃犲彉鍖�**锛宍CrmCustomerRespVO` 宸插寘鍚細
+- `ownerUserName` 鈥� 閿�鍞汉鍛樺悕绉�
+- `ownerUserDeptName` 鈥� 閿�鍞汉鍛橀儴闂ㄥ悕绉�
+
+---
+
+## 涓氬姟瑙勫垯璇存槑
+
+### 鍦烘櫙绫诲瀷鎵╁睍
+
+| sceneType 鍊� | 鍦烘櫙鍚嶇О | 鏁版嵁鑼冨洿 | 鏉冮檺瑕佹眰 |
+|--------------|----------|----------|----------|
+| 1 | 鎴戣礋璐g殑 | `owner_user_id = 褰撳墠鐢ㄦ埛` | `crm:customer:query` |
+| 2 | 鎴戝弬涓庣殑 | 鍥㈤槦鎴愬憳锛堥潪璐熻矗浜猴級 | `crm:customer:query` |
+| 3 | 涓嬪睘璐熻矗鐨� | 涓嬪睘涓鸿礋璐d汉 | `crm:customer:query` |
+| **4锛堟柊澧烇級** | **鍏ㄩ儴** | **鎵�鏈夊鎴凤紙鏃犺繃婊わ級** | **`crm:customer:view-all` 鎴� `crm_admin` 瑙掕壊** |
+
+### 鏉冮檺闄嶇骇瑙勫垯
+
+褰撶敤鎴蜂互 `sceneType=4` 璇锋眰鏁版嵁鏃讹細
+- 鐢ㄦ埛鎷ユ湁 `crm:customer:view-all` 鏉冮檺 **鎴�** `crm_admin` 瑙掕壊 鈫� 杩斿洖鍏ㄩ儴瀹㈡埛
+- 鐢ㄦ埛**娌℃湁**璇ユ潈闄� 鈫� 鑷姩闄嶇骇涓�"鎴戣礋璐g殑"锛坄sceneType=1`锛夛紝浠呰繑鍥炶嚜宸辩殑瀹㈡埛
+
+### 鏉冮檺鏍囪瘑
+
+| 鏉冮檺鏍囪瘑 | 璇存槑 | 鎵�灞炶彍鍗� |
+|----------|------|----------|
+| `crm:customer:view-all` | 鏌ョ湅鍏ㄩ儴瀹㈡埛 | CRM 瀹㈡埛鍏捣 |
+
+璇ユ潈闄愬凡娣诲姞鍒版暟鎹簱 `system_menu` 琛紝浣嶄簬銆屽鎴峰叕娴枫�嶈彍鍗曚笅锛坕d=602583锛夛紝瑙掕壊鍒嗛厤鍚庡嵆鍙敓鏁堛��
+
+---
+
+## 鍓嶇淇敼鐐�
+
+### 1. 瀹㈡埛鍒楄〃椤� Tab 鍒囨崲
+
+鍦ㄧ幇鏈夌殑鍦烘櫙绫诲瀷 Tab锛堟垜璐熻矗鐨�/鎴戝弬涓庣殑/涓嬪睘璐熻矗鐨勶級鍚庨潰锛屾柊澧�"鍏ㄩ儴"Tab锛坄sceneType=4`锛夈��
+
+**灞曠ず瑙勫垯**锛�
+- 浠呭綋鐢ㄦ埛鎷ユ湁 `crm:customer:view-all` 鏉冮檺鎴� `crm_admin` 瑙掕壊鏃讹紝鎵嶆樉绀�"鍏ㄩ儴"Tab
+- 鍒ゆ柇鏂瑰紡锛氳皟鐢ㄦ潈闄愬垽鏂帴鍙f垨浠庣敤鎴锋潈闄愬垪琛ㄤ腑妫�鏌�
+
+### 2. 鏉冮檺鍒ゆ柇
+
+鍓嶇闇�瑕佸垽鏂綋鍓嶇敤鎴锋槸鍚︽湁 `crm:customer:view-all` 鏉冮檺锛�
+- 鏂瑰紡涓�锛氶�氳繃 Vue 鎸囦护 `v-hasPermi="['crm:customer:view-all']"` 鎺у埗 Tab 鏄鹃殣
+- 鏂瑰紡浜岋細閫氳繃鑾峰彇鐢ㄦ埛鏉冮檺鍒楄〃鍒ゆ柇
+
+---
+
+## 娉ㄦ剰浜嬮」
+
+- "鍏ㄩ儴"Tab 浠呮帶鍒舵暟鎹彲瑙佽寖鍥达紝涓嶆敼鍙樺叾浠栧姛鑳芥潈闄愶紙濡傜紪杈戙�佸垹闄や粛闇�瀵瑰簲鏉冮檺锛�
+- 瀵煎嚭 Excel 鏃跺悓鏍锋敮鎸� `sceneType=4`锛屾嫢鏈夋潈闄愮殑鐢ㄦ埛鍙鍑哄叏閮ㄥ鎴锋暟鎹�
+- 鏉冮檺鏁版嵁宸叉彃鍏ユ暟鎹簱锛坄system_menu` id=602583锛夛紝鏃犻渶鍓嶇棰濆澶勭悊鏉冮檺娉ㄥ唽
+- 璇ユ潈闄愪笌 `crm_admin` 瑙掕壊鐨勫尯鍒細`crm_admin` 鎷ユ湁鎵�鏈� CRM 绠$悊鏉冮檺锛岃�� `view-all` 浠呮帶鍒跺鎴峰垪琛ㄧ殑鏌ョ湅鑼冨洿
diff --git a/docs/document_audit_project_filter_fix.md b/docs/document_audit_project_filter_fix.md
new file mode 100644
index 0000000..c3a69ca
--- /dev/null
+++ b/docs/document_audit_project_filter_fix.md
@@ -0,0 +1,59 @@
+# 椤圭洰璇︽儏 - 璧勬枡瀹℃牳鏌ヨ淇锛堝墠绔仈璋冩柟妗堬級
+
+## 闂
+
+椤圭洰璇︽儏椤�"璧勬枡瀹℃牳" Tab 鏌ヨ `/mes/pd/document-audit/page` 鏃舵湭浼犲叆 `projectId`锛屽鑷磋繑鍥炰簡鎵�鏈夐」鐩殑瀹℃牳璁板綍锛岃�岄潪褰撳墠椤圭洰鐨勩��
+
+## 娑夊強椤甸潰
+
+| 椤甸潰 | 璺敱 | 璇存槑 |
+|------|------|------|
+| 椤圭洰璇︽儏 - 璧勬枡瀹℃牳 Tab | `/mes/pd/project/detail/{id}` | 寰呬慨澶� |
+
+---
+
+## API 鍙樻洿
+
+`GET /mes/pd/document-audit/page` 鈥� 鏂板璇锋眰鍙傛暟锛�
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| projectId | Long | 鍚� | 椤圭洰 ID锛屼紶鍏ュ悗浠呰繑鍥炶椤圭洰涓嬭祫鏂欑殑瀹℃牳璁板綍 |
+
+**鍝嶅簲缁撴瀯涓嶅彉銆�**
+
+---
+
+## 鍓嶇淇敼鐐�
+
+**鏂囦欢**: `src/views/mes/pd/project/modules/document-audit-list.vue`
+
+璇ョ粍浠跺凡閫氳繃 `props.projectId` 鎺ユ敹浜嗛」鐩� ID锛屼絾鏈紶缁欐帴鍙c�傚湪 `proxyConfig.ajax.query` 涓姞涓婂嵆鍙細
+
+```typescript
+// 绗� 62-67 琛岋紝鍘熸潵鐨勶細
+query: async ({ page }, formValues) => {
+ return await getPdDocumentAuditPage({
+ pageNo: page.currentPage,
+ pageSize: page.pageSize,
+ ...formValues,
+ });
+},
+
+// 鏀逛负锛�
+query: async ({ page }, formValues) => {
+ return await getPdDocumentAuditPage({
+ pageNo: page.currentPage,
+ pageSize: page.pageSize,
+ projectId: props.projectId,
+ ...formValues,
+ });
+},
+```
+
+---
+
+## 娉ㄦ剰浜嬮」
+
+- 璇ョ粍浠跺湪椤圭洰鐘舵�佷负 `PENDING_AUDIT`锛堝緟瀹℃牳锛夋椂灞曠ず锛岄�氳繃 props 鎺ユ敹 `projectId`
+- 鏀瑰姩浠呴渶涓�琛岋紝鏃犻渶淇敼 API 灏佽鍑芥暟鎴栫被鍨嬪畾涔�
diff --git a/docs/machinery_new_fields_frontend.md b/docs/machinery_new_fields_frontend.md
new file mode 100644
index 0000000..32a1b30
--- /dev/null
+++ b/docs/machinery_new_fields_frontend.md
@@ -0,0 +1,140 @@
+# 璁惧鍙拌处鏂板瀛楁 - 鍓嶇鑱旇皟鏂规
+
+## 娑夊強椤甸潰
+
+| 椤甸潰 | 璺敱璺緞 | 璇存槑 |
+|------|----------|------|
+| 璁惧鍙拌处鍒楄〃 | `/mes/dv-machinery` | 鍒楄〃鏂板绛涢�夋潯浠躲�佽〃鏍煎垪 |
+| 璁惧鍙拌处琛ㄥ崟 | `/mes/dv-machinery` (寮圭獥) | 鏂板/缂栬緫琛ㄥ崟涓鍔� 3 涓瓧娈� |
+| 璁惧鍙拌处瀵煎叆 | 鍚屼笂锛堝鍏ュ脊绐楋級 | Excel 妯℃澘鏂板 3 鍒� |
+
+---
+
+## 鏂板瀛楁璇存槑
+
+| 瀛楁 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| `productionEfficiency` | BigDecimal | 鍚� | 鐢熶骇鏁堢巼锛屽崟浣嶏細姣忓皬鏃剁敓浜ф暟閲忥紝鐢ㄤ簬涓嬫帓浜ц嚜鍔ㄨ绠楃敓浜ф椂闂� |
+| `conveyorBelt` | Integer | 鍚� | 浼犻�佸饱甯︽暟閲忥紝渚嬶細2 浠h〃鍙屽�嶆晥鐜� |
+| `workstationId` | Long | 鍚� | 宸ヤ綔绔欑紪鍙凤紝鐢ㄤ簬灏嗚澶囩粦瀹氬埌鎸囧畾宸ヤ綔绔� |
+
+---
+
+## API
+
+### 宸叉湁鎺ュ彛锛堟棤闇�鏂板锛�
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| POST | `/mes/dv/machinery/create` | 鍒涘缓璁惧 |
+| PUT | `/mes/dv/machinery/update` | 鏇存柊璁惧 |
+| GET | `/mes/dv/machinery/get?id={id}` | 鑾峰彇璇︽儏 |
+| GET | `/mes/dv/machinery/page` | 鍒嗛〉鏌ヨ |
+| GET | `/mes/dv/machinery/simple-list` | 绮剧畝鍒楄〃锛堜笅鎷夐�夐」锛� |
+| POST | `/mes/dv/machinery/import` | 瀵煎叆璁惧 |
+| GET | `/mes/dv/machinery/get-import-template` | 涓嬭浇瀵煎叆妯℃澘 |
+
+### 璇锋眰鍙傛暟 - 鍒涘缓/鏇存柊锛坄MesDvMachinerySaveReqVO`锛�
+
+**鏂板瀛楁锛�**
+
+| 瀛楁 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| productionEfficiency | BigDecimal | 鍚� | 鐢熶骇鏁堢巼锛堟瘡鍒嗛挓锛� |
+| conveyorBelt | Integer | 鍚� | 浼犻�佸饱甯︽暟閲� |
+| workstationId | Long | 鍚� | 宸ヤ綔绔欑紪鍙� |
+
+### 鍒嗛〉鏌ヨ鍙傛暟锛坄MesDvMachineryPageReqVO`锛�
+
+**鏂板绛涢�夊瓧娈碉細**
+
+| 瀛楁 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| workstationId | Long | 鍚� | 鎸夊伐浣滅珯绛涢�� |
+
+### 鍝嶅簲锛坄MesDvMachineryRespVO`锛�
+
+**鏂板瀛楁锛�**
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+|------|------|------|
+| productionEfficiency | BigDecimal | 鐢熶骇鏁堢巼 |
+| conveyorBelt | Integer | 浼犻�佸饱甯� |
+| workstationId | Long | 宸ヤ綔绔欑紪鍙� |
+| workstationName | String | 宸ヤ綔绔欏悕绉� |
+
+**鍝嶅簲绀轰緥锛�**
+
+```json
+{
+ "code": 0,
+ "data": {
+ "id": 1,
+ "name": "CNC 鍔犲伐涓績",
+ "code": "EQ-001",
+ "productionEfficiency": 10.5,
+ "conveyorBelt": 2,
+ "workstationId": 300,
+ "workstationName": "涓�鍙峰伐浣滅珯",
+ ...
+ }
+}
+```
+
+---
+
+## 鍓嶇淇敼鐐�
+
+### 1. 鍒楄〃椤� - 绛涢�夐」
+
+鍦ㄥ垪琛ㄦ悳绱㈡爮鏂板"宸ヤ綔绔�"涓嬫媺绛涢�夋锛岃皟鐢� `/mes/md-workstation/simple-list` 鑾峰彇閫夐」銆�
+
+### 2. 鍒楄〃椤� - 琛ㄦ牸鍒�
+
+| 鏂板鍒� | 缁戝畾瀛楁 | 璇存槑 |
+|--------|----------|------|
+| 鐢熶骇鏁堢巼 | `productionEfficiency` | 鏄剧ず鏁板�� |
+| 浼犻�佸饱甯� | `conveyorBelt` | 鏄剧ず鏁板�� |
+| 宸ヤ綔绔� | `workstationName` | 鏄剧ず宸ヤ綔绔欏悕绉� |
+
+### 3. 琛ㄥ崟椤� - 鏂板/缂栬緫
+
+鍦ㄨ〃鍗曚腑鏂板 3 涓瓧娈碉細
+
+| 瀛楁 | 缁勪欢 | 璇存槑 |
+|------|------|------|
+| 鐢熶骇鏁堢巼 | `<el-input-number>` | 鏀寔灏忔暟锛屽崟浣嶆彁绀�"姣忓皬鏃�" |
+| 浼犻�佸饱甯� | `<el-input-number>` | 姝f暣鏁帮紝鎻愮ず"2=鍙屽�嶆晥鐜�" |
+| 宸ヤ綔绔� | `<el-select>` | 涓嬫媺閫夋嫨锛岃皟鐢ㄥ伐浣滅珯绮剧畝鍒楄〃鎺ュ彛 |
+
+### 4. 瀵煎叆妯℃澘
+
+瀵煎叆 Excel 妯℃澘鏂板 3 鍒楋紙鍙�夊垪锛夛細
+
+| 鍒楀悕 | 璇存槑 |
+|------|------|
+| 鐢熶骇鏁堢巼(姣忓皬鏃�) | 鏁板瓧锛屽彲閫� |
+| 浼犻�佸饱甯� | 鏁存暟锛屽彲閫� |
+| 宸ヤ綔绔欑紪鐮� | 宸ヤ綔绔欑紪鐮侊紝鍙�夛紝濉簡鍒欐牎楠屾槸鍚﹀瓨鍦� |
+
+---
+
+## 涓氬姟瑙勫垯璇存槑
+
+| 瑙勫垯 | 璇存槑 |
+|------|------|
+| 鐢熶骇鏁堢巼鍗曚綅 | 鍥哄畾涓�"姣忓皬鏃剁敓浜ф暟閲�"锛屽墠绔洿鎺ュ睍绀�"姣忓皬鏃�" |
+| 浼犻�佸饱甯﹀惈涔� | 鏁板�� 2 浠h〃鍙屽�嶆晥鐜囷紝鎺掍骇鏃� `conveyorBelt 脳 productionEfficiency` 寰楀埌鏈�缁堜骇鑳� |
+| 宸ヤ綔绔欑粦瀹� | 涓�鍙拌澶囧彲缁戝畾涓�涓伐浣滅珯锛堥潪寮哄埗锛夛紝涓嬫媺鏁版嵁婧愪负 `/mes/md-workstation/simple-list` |
+| 瀵煎叆鏃跺伐浣滅珯 | 濉叆宸ヤ綔绔欑紪鐮侊紙闈� ID锛夛紝绯荤粺鑷姩杞崲锛岀紪鐮佷笉瀛樺湪鍒欏鍏ュけ璐� |
+
+---
+
+## 娉ㄦ剰浜嬮」
+
+- 3 涓柊瀛楁鍧囦负鍙�夛紝涓嶅奖鍝嶇幇鏈夋暟鎹�
+- 鐢熶骇鏁堢巼杈撳叆寤鸿闄愬埗鏈�灏忓�� 0锛屼繚鐣� 2 浣嶅皬鏁�
+- 浼犻�佸饱甯︿粎鍏佽姝f暣鏁�
+- 宸ヤ綔绔欎笅鎷変娇鐢ㄥ凡鏈夋帴鍙� `/mes/md-workstation/simple-list`锛屾棤闇�鏂板
+- Excel 瀵煎叆鏃跺伐浣滅珯鍒楀~缂栫爜鑰岄潪 ID
+- 瀵煎叆妯℃澘鍚庣鎺ュ彛 `/mes/dv/machinery/get-import-template` 涔熶細杩斿洖鏂板垪
diff --git a/docs/pro_archive_integration.md b/docs/pro_archive_integration.md
new file mode 100644
index 0000000..4667d21
--- /dev/null
+++ b/docs/pro_archive_integration.md
@@ -0,0 +1,154 @@
+# 鐢熶骇娴佺▼ - 鏌ョ湅浜у搧璁捐褰掓。鍙婇檮浠讹紙鍓嶇鑱旇皟鏂规锛�
+
+## 娑夊強椤甸潰
+
+| 椤甸潰 | 璺敱璺緞 | 璇存槑 |
+|------|----------|------|
+| 鐢熶骇宸ュ崟鍒楄〃/璇︽儏 | `/mes/pro-workorder` | 鏂板"鏌ョ湅褰掓。"鎸夐挳 |
+| 鐢熶骇宸ュ崟涓績 | `/mes/workorder-center` | 鏂板"鏌ョ湅褰掓。"鎸夐挳 |
+| 鐢熶骇浠诲姟鍒楄〃/璇︽儏 | `/mes/pro-task` | 鏂板"鏌ョ湅褰掓。"鎸夐挳 |
+| 寰呮姤宸ュ彴璐� | `/mes/pro-task` (pending-feedback) | 鏂板"鏌ョ湅褰掓。"鎸夐挳 |
+| 鐢熶骇鎶ュ伐鍒楄〃/璇︽儏 | `/mes/pro-feedback` | 鏂板"鏌ョ湅褰掓。"鎸夐挳 |
+
+---
+
+## API锛堝凡鏈夋帴鍙o紝鏃犻渶鏂板锛�
+
+### 褰掓。鍒嗛〉鍒楄〃
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| GET | `/mes/pd/archive/page` | 鎸変骇鍝佺紪鐮佺瓫閫夊綊妗e垪琛� |
+
+**璇锋眰鍙傛暟锛堝叧閿級锛�**
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| productCode | String | 鏄� | 浜у搧缂栫爜锛屼粠褰撳墠璁板綍鐨� `itemCode` 鎴� `productCode` 浼犲叆 |
+| pageNo | Integer | 鍚� | 椤电爜 |
+| pageSize | Integer | 鍚� | 姣忛〉鏉℃暟 |
+
+### 褰掓。璇︽儏锛堝惈闄勪欢锛�
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| GET | `/mes/pd/archive/detail-by-product` | 鎸変骇鍝佺紪鐮佽幏鍙栧綊妗h鎯呭拰闄勪欢 |
+
+**璇锋眰鍙傛暟锛�**
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| productCode | String | 鏄� | 浜у搧缂栫爜 |
+
+**鍝嶅簲缁撴瀯锛�**
+
+```json
+{
+ "code": 0,
+ "data": [
+ {
+ "project": {
+ "id": 1,
+ "taskCode": "PD2024001",
+ "taskName": "鏂颁骇鍝佽璁′换鍔�",
+ "productCode": "P001",
+ "productName": "娉ㄥ浜у搧A",
+ "version": "V1.0",
+ "status": 4,
+ "chiefDesigner": 1,
+ "chiefDesignerNickname": "寮犱笁"
+ },
+ "archives": [
+ {
+ "id": 1,
+ "archiveCode": "ARC2024001",
+ "archiver": 1,
+ "archiverNickname": "鐜嬩簲",
+ "archiveStatus": 1,
+ "archiveTime": "2024-01-15T10:30:00"
+ }
+ ],
+ "documents": [
+ {
+ "id": 1,
+ "documentType": "1",
+ "documentName": "浜у搧璁捐鍥�",
+ "documentVersion": "V1.0",
+ "fileName": "design.pdf",
+ "attachmentList": [
+ {
+ "id": "blob-id-xxx",
+ "name": "璁捐鍥剧焊.pdf",
+ "url": "/system/storage-blob/preview/xxx"
+ }
+ ],
+ "uploadUserId": 1,
+ "uploadUserNickname": "璧靛叚",
+ "uploadTime": "2024-01-10T09:00:00"
+ }
+ ]
+ }
+ ]
+}
+```
+
+---
+
+## 鏁版嵁浼犻��
+
+鐢熶骇娴佺▼鍚勭幆鑺傜殑璁板綍涓凡鍖呭惈浜у搧缂栫爜锛岀洿鎺ヤ紶缁欏綊妗f帴鍙o細
+
+| 鏉ユ簮椤甸潰 | 瀛楁鍚� | 浼犵粰褰掓。鎺ュ彛 |
+|----------|--------|-------------|
+| 鐢熶骇宸ュ崟 | `productCode` | `?productCode={productCode}` |
+| 鐢熶骇浠诲姟 | `itemCode` | `?productCode={itemCode}` |
+| 鐢熶骇鎶ュ伐 | `itemCode` | `?productCode={itemCode}` |
+| 寰呮姤宸ュ彴璐� | `itemCode` | `?productCode={itemCode}` |
+
+---
+
+## 鍓嶇淇敼鐐�
+
+### 1. 鏌ョ湅褰掓。鎸夐挳
+
+鍦ㄧ敓浜у伐鍗曘�佷换鍔°�佹姤宸ュ垪琛ㄧ殑鎿嶄綔鍒楋紝浠ュ強璇︽儏椤碉紝鏂板"璁捐褰掓。"鎸夐挳銆�
+
+鐐瑰嚮鍚庡脊鍑烘娊灞夋垨寮圭獥锛岃皟鐢� `/mes/pd/archive/detail-by-product?productCode={code}` 鑾峰彇褰掓。璇︽儏銆�
+
+### 2. 寮圭獥鍐呭灞曠ず
+
+浠� Tab 鎴栧垎鍖哄睍绀轰笁閮ㄥ垎鍐呭锛�
+
+| 鍖哄煙 | 鍐呭 | 鏁版嵁鏉ユ簮 |
+|------|------|----------|
+| 椤圭洰淇℃伅 | 浠诲姟缂栫爜銆佷换鍔″悕绉般�佷骇鍝佺紪鐮�/鍚嶇О銆佺増鏈�佷富璁捐甯堛�佺姸鎬� | `response[].project` |
+| 褰掓。璁板綍 | 琛ㄦ牸锛氬綊妗g紪鍙枫�佸綊妗d汉銆佸綊妗g姸鎬併�佸綊妗f椂闂� | `response[].archives` |
+| 璁捐璧勬枡 | 琛ㄦ牸锛氳祫鏂欑被鍨嬨�佸悕绉般�佺増鏈�佹枃浠跺悕锛岄檮浠跺彲鐐瑰嚮涓嬭浇/棰勮 | `response[].documents` |
+
+### 3. 闄勪欢澶勭悊
+
+璁捐璧勬枡涓殑 `attachmentList` 涓洪檮浠跺垪琛紝鍏朵腑 `url` 鍙洿鎺ョ敤浜庢枃浠堕瑙�/涓嬭浇銆�
+
+鏂囦欢棰勮 URL 鏍煎紡锛�
+- 棰勮锛歚/system/storage-blob/preview/{fileName}`
+- 涓嬭浇锛歚/system/storage-blob/download/{fileName}`
+
+---
+
+## 涓氬姟瑙勫垯璇存槑
+
+| 瑙勫垯 | 璇存槑 |
+|------|------|
+| 浜у搧鏈綊妗� | 鎺ュ彛杩斿洖绌烘暟缁勶紝寮圭獥鎻愮ず"璇ヤ骇鍝佹殏鏃犺璁″綊妗�" |
+| 澶氫釜椤圭洰 | 鍚屼竴浜у搧鍙兘鏈夊涓璁¢」鐩紝鎸夐」鐩垎缁勫睍绀� |
+| 闄勪欢鏉冮檺 | 闄勪欢棰勮/涓嬭浇璧� system 妯″潡 Storage API锛屾棤闇�棰濆閴存潈 |
+| 绌洪檮浠� | `attachmentList` 鍙兘涓虹┖鏁扮粍锛屽墠绔垽鏂悗涓嶆樉绀轰笅杞介摼鎺� |
+
+---
+
+## 娉ㄦ剰浜嬮」
+
+- 鍒楄〃椤垫搷浣滃垪瀹藉害鏈夐檺锛屽缓璁寜閽枃瀛楃畝鍐欎负"褰掓。"
+- `detail-by-product` 鎺ュ彛杩斿洖鏁扮粍锛屼竴涓骇鍝佸彲鑳藉搴斿涓璁¢」鐩�
+- 闄勪欢棰勮浣跨敤 `window.open()` 鎵撳紑棰勮 URL
+- 鎺ュ彛宸插瓨鍦紝鍓嶇鐩存帴璋冪敤 `src/api/mes/pd/archive/index.ts` 涓殑灏佽鏂规硶
diff --git a/docs/pro_task_calculate_duration.md b/docs/pro_task_calculate_duration.md
new file mode 100644
index 0000000..b679ee1
--- /dev/null
+++ b/docs/pro_task_calculate_duration.md
@@ -0,0 +1,81 @@
+# 鐢熶骇浠诲姟 - 閫夊伐浣滅珯鑷姩璁$畻鐢熶骇鏃堕暱锛堝墠绔仈璋冩柟妗堬級
+
+## 娑夊強椤甸潰
+
+| 椤甸潰 | 璺敱璺緞 | 璇存槑 |
+|------|----------|------|
+| 鐢熶骇浠诲姟琛ㄥ崟 | `/mes/pro-task` (鏂板/缂栬緫寮圭獥) | 閫夋嫨宸ヤ綔绔欏悗鑷姩璋冪敤鎺ュ彛璁$畻鐢熶骇鏃堕暱 |
+
+---
+
+## API
+
+### 鏂板鎺ュ彛锛氳绠楃敓浜ф椂闀�
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| GET | `/mes/pro/task/calculate-duration` | 鏍规嵁宸ヤ綔绔欏拰鏁伴噺璁$畻鐢熶骇鏃堕暱 |
+
+**璇锋眰鍙傛暟锛�**
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| workstationId | Long | 鏄� | 宸ヤ綔绔欑紪鍙� |
+| quantity | BigDecimal | 鏄� | 鎺掍骇鏁伴噺 |
+
+**鍝嶅簲绀轰緥锛�**
+
+```json
+{
+ "code": 0,
+ "data": {
+ "duration": 3
+ },
+ "msg": ""
+}
+```
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+|------|------|------|
+| duration | Integer | 鐢熶骇鏃堕暱锛堝皬鏃讹級锛屾棤缁戝畾璁惧鏃惰繑鍥� 0 |
+
+---
+
+## 鍓嶇淇敼鐐�
+
+### 1. 瑙﹀彂鏃舵満
+
+鍦ㄦ柊澧�/缂栬緫鐢熶骇浠诲姟鐨勮〃鍗曚腑锛屽綋鐢ㄦ埛**閫夋嫨宸ヤ綔绔�**鎴�**淇敼鎺掍骇鏁伴噺**鍚庯紝鑷姩璋冪敤璁$畻鎺ュ彛銆�
+
+### 2. 瀛楁鍥炲~
+
+鎺ュ彛杩斿洖鐨� `duration` 鍊艰嚜鍔ㄥ~鍏ヨ〃鍗曠殑"鐢熶骇鏃堕暱"瀛楁锛屾棤闇�鐢ㄦ埛鎵嬪姩璁$畻銆�
+
+### 3. 杈圭晫鎯呭喌
+
+| 鍦烘櫙 | 琛ㄧ幇 |
+|------|------|
+| 鏈�夊伐浣滅珯 | 涓嶈皟鐢ㄦ帴鍙� |
+| 鏈~鏁伴噺 | 涓嶈皟鐢ㄦ帴鍙� |
+| 宸ヤ綔绔欐湭缁戝畾璁惧 | 杩斿洖 `duration=0`锛屽墠绔彲鎻愮ず"璇ュ伐浣滅珯鏈粦瀹氳澶�" |
+| 璁惧鏈厤缃敓浜ф晥鐜� | 杩斿洖 `duration=0`锛屽墠绔彲鎻愮ず"缁戝畾璁惧鏈厤缃敓浜ф晥鐜�" |
+
+---
+
+## 璁$畻閫昏緫璇存槑
+
+| 姝ラ | 璇存槑 |
+|------|------|
+| 1 | 鏌ヨ宸ヤ綔绔欑粦瀹氱殑鎵�鏈夎澶� |
+| 2 | 鎬绘晥鐜� = 危(姣忓彴璁惧鐨� `productionEfficiency` 脳 `conveyorBelt`) |
+| 3 | 浼犻�佸饱甯︿负 0 鎴栫┖鏃堕粯璁ゅ彇 1 |
+| 4 | 鐢熶骇鏃堕暱锛堝皬鏃讹級= 鍚戜笂鍙栨暣(鎺掍骇鏁伴噺 / 鎬绘晥鐜�) |
+
+---
+
+## 娉ㄦ剰浜嬮」
+
+- 璋冪敤鎺ュ彛鍓嶉渶纭繚 `workstationId` 鍜� `quantity` 鍧囨湁鍊硷紝閬垮厤鏃犳晥璇锋眰
+- 鎺ュ彛杩斿洖 0 鏃讹紝寤鸿缁欏嚭鍙嬪ソ鎻愮ず锛岃�岄潪闈欓粯
+- 鐢ㄦ埛浠嶅彲鎵嬪姩淇敼璁$畻鍚庣殑鐢熶骇鏃堕暱
+- 璇ユ帴鍙d粎鐢ㄤ簬鍓嶇杈呭姪璁$畻锛屼笉褰卞搷鍚庣鍒涘缓/鏇存柊浠诲姟鐨勪笟鍔¢�昏緫
diff --git a/sql/mysql/mes_pd_menu_init.sql b/sql/mysql/mes_pd_menu_init.sql
new file mode 100644
index 0000000..426e3d6
--- /dev/null
+++ b/sql/mysql/mes_pd_menu_init.sql
@@ -0,0 +1,37 @@
+-- =============================================
+-- MES PD 浜у搧璁捐妯″潡鑿滃崟鍒濆鍖�
+-- 鍦� MES 绯荤粺(5100) 涓嬫柊澧�"浜у搧璁捐"浜岀骇鐩綍
+-- 璁捐椤圭洰銆佽璁″綊妗d袱涓〉闈�
+-- =============================================
+
+-- 淇鍘熸湁"浜у搧璁捐"(6809) 鍛藉悕涓�"宸ヨ壓璁捐"锛岄伩鍏嶅啿绐侊紙鍏跺唴瀹逛负宸ヨ壓璁捐锛氬伐搴忚缃�佸伐鑹烘祦绋嬬瓑锛�
+UPDATE `system_menu` SET `name` = '宸ヨ壓璁捐', `updater` = '1', `update_time` = NOW() WHERE `id` = 6809 AND `name` = '浜у搧璁捐';
+
+-- 浜у搧璁捐锛堜簩绾х洰褰曪紝鏀惧湪 MES 绯荤粺涓嬶紝sort=25 浣嶄簬宸ヨ壓璁捐涔嬪悗锛�
+INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
+VALUES (602571, '浜у搧璁捐', '', 1, 25, 5100, 'pd', 'ep:design', '', '', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0');
+
+-- 璁捐椤圭洰锛堜笁绾ц彍鍗曪級
+INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
+VALUES (602572, '璁捐椤圭洰', '', 2, 1, 602571, 'project', 'ep:document', 'mes/pd/project/index', 'MesPdProject', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0');
+
+-- 璁捐椤圭洰 - 鎸夐挳鏉冮檺
+INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
+VALUES
+(602573, '璁捐椤圭洰鏌ヨ', 'mes:pd-project:query', 3, 1, 602572, '', '', '', '', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'),
+(602574, '璁捐椤圭洰鍒涘缓', 'mes:pd-project:create', 3, 2, 602572, '', '', '', '', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'),
+(602575, '璁捐椤圭洰鏇存柊', 'mes:pd-project:update', 3, 3, 602572, '', '', '', '', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'),
+(602576, '璁捐椤圭洰鍒犻櫎', 'mes:pd-project:delete', 3, 4, 602572, '', '', '', '', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'),
+(602577, '璁捐椤圭洰瀵煎嚭', 'mes:pd-project:export', 3, 5, 602572, '', '', '', '', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0');
+
+-- 璁捐褰掓。锛堜笁绾ц彍鍗曪級
+INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
+VALUES (602578, '璁捐褰掓。', '', 2, 2, 602571, 'archive', 'ep:folder', 'mes/pd/archive/index', 'MesPdArchive', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0');
+
+-- 璁捐褰掓。 - 鎸夐挳鏉冮檺
+INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
+VALUES
+(602579, '璁捐褰掓。鏌ヨ', 'mes:pd-archive:query', 3, 1, 602578, '', '', '', '', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'),
+(602580, '璁捐褰掓。鏇存柊', 'mes:pd-archive:update', 3, 2, 602578, '', '', '', '', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'),
+(602581, '璁捐褰掓。鍒犻櫎', 'mes:pd-archive:delete', 3, 3, 602578, '', '', '', '', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'),
+(602582, '璁捐褰掓。瀵煎嚭', 'mes:pd-archive:export', 3, 4, 602578, '', '', '', '', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0');
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerMapper.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerMapper.java
index e6a1991..25de6e6 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerMapper.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerMapper.java
@@ -51,7 +51,11 @@
default PageResult<CrmCustomerDO> selectPage(CrmCustomerPageReqVO pageReqVO, Long ownerUserId) {
MPJLambdaWrapperX<CrmCustomerDO> query = new MPJLambdaWrapperX<>();
// 鎷兼帴鏁版嵁鏉冮檺鐨勬煡璇㈡潯浠�
- if (Boolean.TRUE.equals(pageReqVO.getPool())) {
+ if (CrmSceneTypeEnum.isAll(pageReqVO.getSceneType())) {
+ // 鍦烘櫙鍥涳細鍏ㄩ儴鏁版嵁锛屼笉鍖哄垎鍏捣/闈炲叕娴凤紝鐢� appendPermissionCondition 缁熶竴澶勭悊
+ CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CUSTOMER.getType(),
+ CrmCustomerDO::getId, ownerUserId, pageReqVO.getSceneType());
+ } else if (Boolean.TRUE.equals(pageReqVO.getPool())) {
query.isNull(CrmCustomerDO::getOwnerUserId);
} else {
CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CUSTOMER.getType(),
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/common/CrmSceneTypeEnum.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/common/CrmSceneTypeEnum.java
index 9a1a420..d129d02 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/common/CrmSceneTypeEnum.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/common/CrmSceneTypeEnum.java
@@ -18,7 +18,8 @@
OWNER(1, "鎴戣礋璐g殑"),
INVOLVED(2, "鎴戝弬涓庣殑"),
- SUBORDINATE(3, "涓嬪睘璐熻矗鐨�");
+ SUBORDINATE(3, "涓嬪睘璐熻矗鐨�"),
+ ALL(4, "鍏ㄩ儴");
public static final Integer[] ARRAYS = Arrays.stream(values()).map(CrmSceneTypeEnum::getType).toArray(Integer[]::new);
@@ -43,6 +44,10 @@
return ObjUtil.equal(SUBORDINATE.getType(), type);
}
+ public static boolean isAll(Integer type) {
+ return ObjUtil.equal(ALL.getType(), type);
+ }
+
@Override
public Integer[] array() {
return ARRAYS;
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/util/CrmPermissionUtils.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/util/CrmPermissionUtils.java
index c97266b..24740c9 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/util/CrmPermissionUtils.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/util/CrmPermissionUtils.java
@@ -37,6 +37,16 @@
}
/**
+ * 鏍¢獙鐢ㄦ埛鏄惁鏈夋煡鐪嬪叏閮ㄥ鎴风殑鏉冮檺
+ *
+ * @return 鏄�/鍚�
+ */
+ private static boolean hasCustomerViewAllPermission() {
+ PermissionCommonApi permissionApi = SpringUtil.getBean(PermissionCommonApi.class);
+ return permissionApi.hasAnyPermissions(getLoginUserId(), "crm:customer:view-all");
+ }
+
+ /**
* 鏋勯�� CRM 鏁版嵁绫诲瀷鏁版嵁銆愬垎椤点�戞煡璇㈡潯浠�
*
* @param query 杩炶〃鏌ヨ瀵硅薄
@@ -79,6 +89,14 @@
query.in(ownerUserIdField, convertSet(subordinateUsers, AdminUserRespDTO::getId));
}
}
+ // 鍦烘櫙鍥涳細鍏ㄩ儴鏁版嵁锛堥渶瑕佹湁 view-all 鏉冮檺鎴� CRM 绠$悊鍛橈級
+ if (CrmSceneTypeEnum.isAll(sceneType)) {
+ if (isCrmAdmin() || hasCustomerViewAllPermission()) {
+ return; // 璺宠繃杩囨护锛屾煡鐪嬪叏閮�
+ }
+ // 鏃犳潈闄愬垯闄嶇骇涓�"鎴戣礋璐g殑"
+ query.eq(ownerUserIdField, userId);
+ }
}
/**
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dv/machinery/MesDvMachineryController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dv/machinery/MesDvMachineryController.java
index 932db26..864bf15 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dv/machinery/MesDvMachineryController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dv/machinery/MesDvMachineryController.java
@@ -52,6 +52,8 @@
private MesDvMachineryTypeService machineryTypeService;
@Resource
private MesMdWorkshopService workshopService;
+ @Resource
+ private cn.iocoder.yudao.module.mes.service.md.workstation.MesMdWorkstationService workstationService;
@PostMapping("/create")
@Operation(summary = "鍒涘缓璁惧")
@@ -151,17 +153,21 @@
if (CollUtil.isEmpty(list)) {
return Collections.emptyList();
}
- // 1. 鎵归噺鑾峰彇璁惧绫诲瀷鍜岃溅闂翠俊鎭�
+ // 1. 鎵归噺鑾峰彇璁惧绫诲瀷銆佽溅闂村拰宸ヤ綔绔欎俊鎭�
Map<Long, MesDvMachineryTypeDO> machineryTypeMap = machineryTypeService.getMachineryTypeMap(
convertSet(list, MesDvMachineryDO::getMachineryTypeId));
Map<Long, MesMdWorkshopDO> workshopMap = workshopService.getWorkshopMap(
convertSet(list, MesDvMachineryDO::getWorkshopId));
+ Map<Long, cn.iocoder.yudao.module.mes.dal.dataobject.md.workstation.MesMdWorkstationDO> workstationMap =
+ workstationService.getWorkstationMap(convertSet(list, MesDvMachineryDO::getWorkstationId));
// 2. 鎷兼帴 VO
return BeanUtils.toBean(list, MesDvMachineryRespVO.class, vo -> {
MapUtils.findAndThen(machineryTypeMap, vo.getMachineryTypeId(),
machineryType -> vo.setMachineryTypeName(machineryType.getName()));
MapUtils.findAndThen(workshopMap, vo.getWorkshopId(),
workshop -> vo.setWorkshopName(workshop.getName()));
+ MapUtils.findAndThen(workstationMap, vo.getWorkstationId(),
+ workstation -> vo.setWorkstationName(workstation.getName()));
});
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dv/machinery/vo/MesDvMachineryImportExcelVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dv/machinery/vo/MesDvMachineryImportExcelVO.java
index 82b2364..fe5729d 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dv/machinery/vo/MesDvMachineryImportExcelVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dv/machinery/vo/MesDvMachineryImportExcelVO.java
@@ -43,4 +43,13 @@
@ExcelProperty("澶囨敞")
private String remark;
+ @ExcelProperty("鐢熶骇鏁堢巼(姣忓皬鏃�)")
+ private java.math.BigDecimal productionEfficiency;
+
+ @ExcelProperty("浼犻�佸饱甯�")
+ private Integer conveyorBelt;
+
+ @ExcelProperty("宸ヤ綔绔欑紪鐮�")
+ private String workstationCode;
+
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dv/machinery/vo/MesDvMachineryPageReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dv/machinery/vo/MesDvMachineryPageReqVO.java
index aefad44..2eea5ba 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dv/machinery/vo/MesDvMachineryPageReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dv/machinery/vo/MesDvMachineryPageReqVO.java
@@ -35,4 +35,7 @@
@Schema(description = "璁惧鐘舵��", example = "1")
private Integer status;
+ @Schema(description = "宸ヤ綔绔欑紪鍙�", example = "300")
+ private Long workstationId;
+
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dv/machinery/vo/MesDvMachineryRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dv/machinery/vo/MesDvMachineryRespVO.java
index 5d46e43..9834bbe 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dv/machinery/vo/MesDvMachineryRespVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dv/machinery/vo/MesDvMachineryRespVO.java
@@ -66,6 +66,21 @@
@ExcelProperty("澶囨敞")
private String remark;
+ @Schema(description = "鐢熶骇鏁堢巼锛堟瘡灏忔椂锛�", example = "10.5")
+ @ExcelProperty("鐢熶骇鏁堢巼(姣忓皬鏃�)")
+ private java.math.BigDecimal productionEfficiency;
+
+ @Schema(description = "浼犻�佸饱甯︼紙2=鍙屽�嶆晥鐜囷級", example = "2")
+ @ExcelProperty("浼犻�佸饱甯�")
+ private Integer conveyorBelt;
+
+ @Schema(description = "宸ヤ綔绔欑紪鍙�", example = "300")
+ private Long workstationId;
+
+ @Schema(description = "宸ヤ綔绔欏悕绉�", example = "涓�鍙峰伐浣滅珯")
+ @ExcelProperty("宸ヤ綔绔�")
+ private String workstationName;
+
@Schema(description = "鍒涘缓鏃堕棿", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("鍒涘缓鏃堕棿")
private LocalDateTime createTime;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dv/machinery/vo/MesDvMachinerySaveReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dv/machinery/vo/MesDvMachinerySaveReqVO.java
index e2aaad1..c9fecbc 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dv/machinery/vo/MesDvMachinerySaveReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dv/machinery/vo/MesDvMachinerySaveReqVO.java
@@ -49,4 +49,13 @@
@Schema(description = "澶囨敞", example = "澶囨敞")
private String remark;
+ @Schema(description = "鐢熶骇鏁堢巼锛堟瘡灏忔椂锛�", example = "10.5")
+ private java.math.BigDecimal productionEfficiency;
+
+ @Schema(description = "浼犻�佸饱甯︼紙2=鍙屽�嶆晥鐜囷級", example = "2")
+ private Integer conveyorBelt;
+
+ @Schema(description = "宸ヤ綔绔欑紪鍙�", example = "300")
+ private Long workstationId;
+
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pd/documentaudit/vo/MesPdDocumentAuditPageReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pd/documentaudit/vo/MesPdDocumentAuditPageReqVO.java
index d41bf8f..fd1b1f3 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pd/documentaudit/vo/MesPdDocumentAuditPageReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pd/documentaudit/vo/MesPdDocumentAuditPageReqVO.java
@@ -21,4 +21,7 @@
@Schema(description = "瀹℃牳鐘舵��", example = "0")
private Integer auditStatus;
+ @Schema(description = "椤圭洰ID", example = "1")
+ private Long projectId;
+
}
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 19dd295..a0cca8c 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
@@ -34,6 +34,7 @@
import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
@@ -98,6 +99,20 @@
return success(true);
}
+ @GetMapping("/calculate-duration")
+ @Operation(summary = "璁$畻鐢熶骇鏃堕暱", description = "鏍规嵁宸ヤ綔绔欑粦瀹氳澶囩殑鐢熶骇鏁堢巼鍜屼紶閫佸饱甯︼紝鑷姩璁$畻鐢熶骇鏃堕暱锛堝皬鏃讹級")
+ @Parameters({
+ @Parameter(name = "workstationId", description = "宸ヤ綔绔欑紪鍙�", required = true),
+ @Parameter(name = "quantity", description = "鎺掍骇鏁伴噺", required = true)
+ })
+ @PreAuthorize("@ss.hasPermission('mes:pro-task:query')")
+ public CommonResult<java.util.Map<String, Object>> calculateDuration(
+ @RequestParam("workstationId") Long workstationId,
+ @RequestParam("quantity") BigDecimal quantity) {
+ Integer duration = taskService.calculateDuration(workstationId, quantity);
+ return success(java.util.Map.of("duration", duration));
+ }
+
@DeleteMapping("/delete")
@Operation(summary = "鍒犻櫎鐢熶骇浠诲姟")
@Parameter(name = "id", description = "缂栧彿", required = true)
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/dv/machinery/MesDvMachineryDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/dv/machinery/MesDvMachineryDO.java
index bb65941..5caf847 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/dv/machinery/MesDvMachineryDO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/dv/machinery/MesDvMachineryDO.java
@@ -76,5 +76,19 @@
* 澶囨敞
*/
private String remark;
+ /**
+ * 鐢熶骇鏁堢巼锛堟瘡灏忔椂锛�
+ */
+ private java.math.BigDecimal productionEfficiency;
+ /**
+ * 浼犻�佸饱甯︼紙2=鍙屽�嶆晥鐜囷級
+ */
+ private Integer conveyorBelt;
+ /**
+ * 宸ヤ綔绔欑紪鍙�
+ *
+ * 鍏宠仈 {@link cn.iocoder.yudao.module.mes.dal.dataobject.md.workstation.MesMdWorkstationDO#getId()}
+ */
+ private Long workstationId;
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/dv/machinery/MesDvMachineryMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/dv/machinery/MesDvMachineryMapper.java
index 5e39c3d..a6b2112 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/dv/machinery/MesDvMachineryMapper.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/dv/machinery/MesDvMachineryMapper.java
@@ -24,6 +24,7 @@
.eqIfPresent(MesDvMachineryDO::getMachineryTypeId, reqVO.getMachineryTypeId())
.inIfPresent(MesDvMachineryDO::getMachineryTypeId, reqVO.getMachineryTypeIds())
.eqIfPresent(MesDvMachineryDO::getWorkshopId, reqVO.getWorkshopId())
+ .eqIfPresent(MesDvMachineryDO::getWorkstationId, reqVO.getWorkstationId())
.eqIfPresent(MesDvMachineryDO::getStatus, reqVO.getStatus())
.orderByDesc(MesDvMachineryDO::getId));
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pd/documentaudit/MesPdDocumentAuditMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pd/documentaudit/MesPdDocumentAuditMapper.java
index f876368..bb34e18 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pd/documentaudit/MesPdDocumentAuditMapper.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pd/documentaudit/MesPdDocumentAuditMapper.java
@@ -21,6 +21,16 @@
.orderByDesc(MesPdDocumentAuditDO::getId));
}
+ default PageResult<MesPdDocumentAuditDO> selectPage(MesPdDocumentAuditPageReqVO reqVO,
+ Collection<Long> documentIds) {
+ return selectPage(reqVO, new LambdaQueryWrapperX<MesPdDocumentAuditDO>()
+ .eqIfPresent(MesPdDocumentAuditDO::getDocumentId, reqVO.getDocumentId())
+ .likeIfPresent(MesPdDocumentAuditDO::getAuditNo, reqVO.getAuditNo())
+ .eqIfPresent(MesPdDocumentAuditDO::getAuditStatus, reqVO.getAuditStatus())
+ .inIfPresent(MesPdDocumentAuditDO::getDocumentId, documentIds)
+ .orderByDesc(MesPdDocumentAuditDO::getId));
+ }
+
default List<MesPdDocumentAuditDO> selectListByDocumentId(Long documentId) {
return selectList(MesPdDocumentAuditDO::getDocumentId, documentId);
}
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 6b6e280..eb2ae1a 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
@@ -169,6 +169,7 @@
ErrorCode DV_MACHINERY_HAS_CHECK_RECORD = new ErrorCode(1_040_301_004, "璁惧宸插叧鑱旂偣妫�璁板綍锛屾棤娉曞垹闄�");
ErrorCode DV_MACHINERY_HAS_MAINTEN_RECORD = new ErrorCode(1_040_301_005, "璁惧宸插叧鑱斾繚鍏昏褰曪紝鏃犳硶鍒犻櫎");
ErrorCode DV_MACHINERY_HAS_REPAIR = new ErrorCode(1_040_301_006, "璁惧宸插叧鑱旂淮淇伐鍗曪紝鏃犳硶鍒犻櫎");
+ ErrorCode DV_MACHINERY_WORKSTATION_NOT_EXISTS = new ErrorCode(1_040_301_008, "宸ヤ綔绔欑紪鐮佷笉瀛樺湪");
// ========== MES 璁惧绠$悊-鐐规淇濆吇椤圭洰锛�1-040-304-000锛� ==========
ErrorCode DV_SUBJECT_NOT_EXISTS = new ErrorCode(1_040_304_000, "鐐规淇濆吇椤圭洰涓嶅瓨鍦�");
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/dv/machinery/MesDvMachineryServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/dv/machinery/MesDvMachineryServiceImpl.java
index 9e74cf6..2325b04 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/dv/machinery/MesDvMachineryServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/dv/machinery/MesDvMachineryServiceImpl.java
@@ -54,6 +54,9 @@
@Lazy
private MesMdWorkshopService workshopService;
@Resource
+ @Lazy
+ private cn.iocoder.yudao.module.mes.service.md.workstation.MesMdWorkstationService workstationService;
+ @Resource
private MesWmBarcodeService barcodeService;
@Resource
@Lazy
@@ -201,7 +204,7 @@
throw exception(DV_MACHINERY_IMPORT_LIST_IS_EMPTY);
}
- // 2. 鎵归噺鍔犺浇璁惧绫诲瀷鍜岃溅闂达紝鏋勫缓缂栫爜鍒板疄浣撶殑鏄犲皠
+ // 2. 鎵归噺鍔犺浇璁惧绫诲瀷銆佽溅闂村拰宸ヤ綔绔欙紝鏋勫缓缂栫爜鍒板疄浣撶殑鏄犲皠
List<MesDvMachineryTypeDO> allTypes = machineryTypeService.getMachineryTypeList(
new cn.iocoder.yudao.module.mes.controller.admin.dv.machinery.vo.type.MesDvMachineryTypeListReqVO());
Map<String, MesDvMachineryTypeDO> typeCodeMap = allTypes.stream()
@@ -210,6 +213,13 @@
cn.iocoder.yudao.framework.common.enums.CommonStatusEnum.ENABLE.getStatus());
Map<String, MesMdWorkshopDO> workshopCodeMap = allWorkshops.stream()
.collect(Collectors.toMap(MesMdWorkshopDO::getCode, w -> w, (a, b) -> a));
+ List<cn.iocoder.yudao.module.mes.dal.dataobject.md.workstation.MesMdWorkstationDO> allWorkstations =
+ workstationService.getWorkstationListByStatus(
+ cn.iocoder.yudao.framework.common.enums.CommonStatusEnum.ENABLE.getStatus());
+ Map<String, cn.iocoder.yudao.module.mes.dal.dataobject.md.workstation.MesMdWorkstationDO> workstationCodeMap =
+ allWorkstations.stream().collect(Collectors.toMap(
+ cn.iocoder.yudao.module.mes.dal.dataobject.md.workstation.MesMdWorkstationDO::getCode,
+ w -> w, (a, b) -> a));
// 3. 閬嶅巻锛岄�愪釜鍒涘缓 or 鏇存柊
MesDvMachineryImportRespVO respVO = MesDvMachineryImportRespVO.builder()
@@ -249,24 +259,38 @@
return;
}
- // 3.4 鍒ゆ柇锛氬垱寤� or 鏇存柊
+ // 3.4 鏍¢獙宸ヤ綔绔欑紪鐮侊紙鍙�夛級
+ Long workstationId = null;
+ if (StrUtil.isNotBlank(importItem.getWorkstationCode())) {
+ cn.iocoder.yudao.module.mes.dal.dataobject.md.workstation.MesMdWorkstationDO workstation =
+ workstationCodeMap.get(importItem.getWorkstationCode());
+ if (workstation == null) {
+ respVO.getFailureCodes().put(key, "宸ヤ綔绔欑紪鐮乕" + importItem.getWorkstationCode() + "]涓嶅瓨鍦�");
+ return;
+ }
+ workstationId = workstation.getId();
+ }
+
+ // 3.5 鍒ゆ柇锛氬垱寤� or 鏇存柊
MesDvMachineryDO existMachinery = machineryMapper.selectByCode(importItem.getCode());
if (existMachinery == null) {
- // 3.4.1 鍒涘缓
+ // 3.5.1 鍒涘缓
MesDvMachineryDO machinery = BeanUtils.toBean(importItem, MesDvMachineryDO.class);
machinery.setMachineryTypeId(machineryType.getId());
machinery.setWorkshopId(workshop.getId());
+ machinery.setWorkstationId(workstationId);
machineryMapper.insert(machinery);
// 鑷姩鐢熸垚鏉$爜
barcodeService.autoGenerateBarcode(BarcodeBizTypeEnum.MACHINERY.getValue(),
machinery.getId(), machinery.getCode(), machinery.getName());
respVO.getCreateCodes().add(importItem.getCode());
} else if (updateSupport) {
- // 3.4.2 鏇存柊
+ // 3.5.2 鏇存柊
MesDvMachineryDO updateObj = BeanUtils.toBean(importItem, MesDvMachineryDO.class);
updateObj.setId(existMachinery.getId());
updateObj.setMachineryTypeId(machineryType.getId());
updateObj.setWorkshopId(workshop.getId());
+ updateObj.setWorkstationId(workstationId);
machineryMapper.updateById(updateObj);
respVO.getUpdateCodes().add(importItem.getCode());
} else {
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pd/documentaudit/MesPdDocumentAuditServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pd/documentaudit/MesPdDocumentAuditServiceImpl.java
index 1119fc3..d9c1f43 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pd/documentaudit/MesPdDocumentAuditServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pd/documentaudit/MesPdDocumentAuditServiceImpl.java
@@ -4,7 +4,9 @@
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.mes.controller.admin.pd.documentaudit.vo.MesPdDocumentAuditPageReqVO;
+import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.module.mes.controller.admin.pd.documentaudit.vo.MesPdDocumentAuditSaveReqVO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pd.document.MesPdDocumentDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pd.documentaudit.MesPdDocumentAuditDO;
import cn.iocoder.yudao.module.mes.dal.mysql.pd.documentaudit.MesPdDocumentAuditMapper;
import cn.iocoder.yudao.module.mes.service.pd.document.MesPdDocumentService;
@@ -14,7 +16,9 @@
import org.springframework.validation.annotation.Validated;
import java.time.LocalDateTime;
+import java.util.Collections;
import java.util.List;
+import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.PD_DOCUMENT_AUDIT_NOT_EXISTS;
@@ -72,6 +76,17 @@
@Override
public PageResult<MesPdDocumentAuditDO> getDocumentAuditPage(MesPdDocumentAuditPageReqVO pageReqVO) {
+ // 鎸夐」鐩瓫閫夛細鍏堟煡鍑洪」鐩笅鎵�鏈夎祫鏂欙紝鍐嶆寜璧勬枡 ID 杩囨护瀹℃牳璁板綍
+ if (pageReqVO.getProjectId() != null) {
+ List<MesPdDocumentDO> documents = documentService.getDocumentListByProjectId(
+ pageReqVO.getProjectId());
+ if (CollUtil.isEmpty(documents)) {
+ return PageResult.empty();
+ }
+ List<Long> documentIds = documents.stream()
+ .map(MesPdDocumentDO::getId).collect(Collectors.toList());
+ return documentAuditMapper.selectPage(pageReqVO, documentIds);
+ }
return documentAuditMapper.selectPage(pageReqVO);
}
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 f3180d5..e47abc7 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
@@ -123,6 +123,15 @@
void cancelTaskByOrderId(Long workOrderId);
/**
+ * 鏍规嵁宸ヤ綔绔欑粦瀹氳澶囩殑鐢熶骇鏁堢巼鍜屼紶閫佸饱甯︼紝璁$畻鐢熶骇鏃堕暱锛堝崟浣嶏細灏忔椂锛�
+ *
+ * @param workstationId 宸ヤ綔绔欑紪鍙�
+ * @param quantity 鎺掍骇鏁伴噺
+ * @return 鐢熶骇鏃堕暱锛堝皬鏃讹級锛屾棤璁惧鍒欒繑鍥� 0
+ */
+ Integer calculateDuration(Long workstationId, BigDecimal quantity);
+
+ /**
* 绱姞浠诲姟鐨勫凡鐢熶骇銆佸悎鏍笺�佷笉鍚堟牸鏁伴噺
*
* @param id 浠诲姟缂栧彿
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 d19426b..bf04d45 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
@@ -7,17 +7,21 @@
import cn.iocoder.yudao.module.mes.controller.admin.pro.task.vo.MesProTaskAutoGenerateReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.pro.task.vo.MesProTaskPageReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.pro.task.vo.MesProTaskSaveReqVO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.dv.machinery.MesDvMachineryDO;
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.MesMdWorkstationMachineDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.task.MesProTaskDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO;
import cn.iocoder.yudao.module.mes.dal.mysql.pro.task.MesProTaskMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.pro.feedback.MesProFeedbackMapper;
import cn.iocoder.yudao.module.mes.enums.md.autocode.MesMdAutoCodeRuleCodeEnum;
import cn.iocoder.yudao.module.mes.enums.pro.MesProTaskStatusEnum;
+import cn.iocoder.yudao.module.mes.service.dv.machinery.MesDvMachineryService;
import cn.iocoder.yudao.module.mes.service.md.autocode.MesMdAutoCodeRecordService;
import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
import cn.iocoder.yudao.module.mes.service.md.unitmeasure.MesMdUnitMeasureService;
+import cn.iocoder.yudao.module.mes.service.md.workstation.MesMdWorkstationMachineService;
import cn.iocoder.yudao.module.mes.service.md.workstation.MesMdWorkstationService;
import cn.iocoder.yudao.module.mes.service.pro.process.MesProProcessService;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteProcessDO;
@@ -40,9 +44,11 @@
import java.util.Collection;
import java.util.Collections;
import java.util.List;
+import java.util.Set;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.PRO_TASK_ALREADY_FINISHED;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.PRO_TASK_HAS_FEEDBACK;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.PRO_TASK_NOT_EXISTS;
@@ -86,6 +92,11 @@
private MesProWorkOrderProcessService workOrderProcessService;
@Resource
private MesMdAutoCodeRecordService autoCodeRecordService;
+ @Resource
+ private MesMdWorkstationMachineService workstationMachineService;
+ @Resource
+ @Lazy
+ private MesDvMachineryService machineryService;
@Override
public Long createTask(MesProTaskSaveReqVO createReqVO) {
@@ -318,6 +329,33 @@
}
@Override
+ public Integer calculateDuration(Long workstationId, BigDecimal quantity) {
+ if (quantity == null || quantity.compareTo(BigDecimal.ZERO) <= 0) {
+ return 0;
+ }
+ // 1. 鏌ヨ宸ヤ綔绔欑粦瀹氱殑璁惧
+ List<MesMdWorkstationMachineDO> machines = workstationMachineService
+ .getWorkstationMachineListByWorkstationId(workstationId);
+ if (CollUtil.isEmpty(machines)) {
+ return 0;
+ }
+ // 2. 鑾峰彇璁惧璇︽儏锛岃绠楁�绘晥鐜�
+ Set<Long> machineryIds = convertSet(machines, MesMdWorkstationMachineDO::getMachineryId);
+ List<MesDvMachineryDO> machineryList = machineryService.getMachineryList(machineryIds);
+ BigDecimal totalEfficiency = BigDecimal.ZERO;
+ for (MesDvMachineryDO m : machineryList) {
+ BigDecimal efficiency = m.getProductionEfficiency() != null ? m.getProductionEfficiency() : BigDecimal.ZERO;
+ Integer belt = m.getConveyorBelt() != null && m.getConveyorBelt() > 0 ? m.getConveyorBelt() : 1;
+ totalEfficiency = totalEfficiency.add(efficiency.multiply(BigDecimal.valueOf(belt)));
+ }
+ if (totalEfficiency.compareTo(BigDecimal.ZERO) <= 0) {
+ return 0;
+ }
+ // 3. 鐢熶骇鏃堕暱锛堝皬鏃讹級 = ceil(鎺掍骇鏁伴噺 / 鎬绘晥鐜�)锛屾晥鐜囧崟浣嶄负姣忓皬鏃朵骇閲�
+ return quantity.divide(totalEfficiency, 0, java.math.RoundingMode.CEILING).intValue();
+ }
+
+ @Override
public MesProTaskAutoGeneratePreviewRespVO previewAutoGenerate(MesProTaskAutoGenerateReqVO reqVO) {
// 1. 鏍¢獙宸ュ崟宸茬‘璁�
MesProWorkOrderDO workOrder = workOrderService.validateWorkOrderConfirmed(reqVO.getWorkOrderId());
diff --git a/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/controller/admin/tender/SrmBidAwardController.java b/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/controller/admin/tender/SrmBidAwardController.java
index 9457f46..6b7fb1d 100644
--- a/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/controller/admin/tender/SrmBidAwardController.java
+++ b/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/controller/admin/tender/SrmBidAwardController.java
@@ -3,6 +3,7 @@
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.srm.controller.admin.tender.vo.*;
+import cn.iocoder.yudao.module.srm.dal.dataobject.SrmBidAwardDO;
import cn.iocoder.yudao.module.srm.service.tender.SrmBidAwardService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
@@ -42,7 +43,20 @@
@Operation(summary = "鏍规嵁鎷涙爣椤圭洰ID鑾峰彇瀹氭爣璇︽儏")
@PreAuthorize("@ss.hasPermission('srm:bid-award:query')")
public CommonResult<SrmBidAwardRespVO> getAwardByProject(@RequestParam("tenderProjectId") Long tenderProjectId) {
- return success(BeanUtils.toBean(bidAwardService.getAwardByProjectId(tenderProjectId), SrmBidAwardRespVO.class));
+ SrmBidAwardDO award = bidAwardService.getAwardByProjectId(tenderProjectId);
+ if (award == null) {
+ return success((SrmBidAwardRespVO) null);
+ }
+ return success(BeanUtils.toBean(award, SrmBidAwardRespVO.class));
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "鍒犻櫎瀹氭爣")
+ @Parameter(name = "id", description = "瀹氭爣ID", required = true)
+ @PreAuthorize("@ss.hasPermission('srm:bid-award:update')")
+ public CommonResult<Boolean> deleteAward(@RequestParam("id") Long id) {
+ bidAwardService.deleteAward(id);
+ return success(true);
}
@PutMapping("/approve")
diff --git a/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/controller/admin/tender/SrmBidEvaluationController.java b/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/controller/admin/tender/SrmBidEvaluationController.java
index 68e69a5..793f1bb 100644
--- a/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/controller/admin/tender/SrmBidEvaluationController.java
+++ b/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/controller/admin/tender/SrmBidEvaluationController.java
@@ -40,6 +40,14 @@
return success(bidEvaluationService.createEvaluation(createReqVO));
}
+ @PutMapping("/update")
+ @Operation(summary = "鏇存柊璇勬爣璁板綍")
+ @PreAuthorize("@ss.hasPermission('srm:bid-evaluation:update')")
+ public CommonResult<Boolean> updateEvaluation(@Valid @RequestBody SrmBidEvaluationSaveReqVO updateReqVO) {
+ bidEvaluationService.updateEvaluation(updateReqVO);
+ return success(true);
+ }
+
@GetMapping("/list-by-project")
@Operation(summary = "鎸夋嫑鏍囬」鐩幏鍙栬瘎鏍囧垪琛�")
@PreAuthorize("@ss.hasPermission('srm:bid-evaluation:query')")
diff --git a/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/controller/admin/tender/SrmTenderBidController.java b/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/controller/admin/tender/SrmTenderBidController.java
index cab0f50..54e23a7 100644
--- a/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/controller/admin/tender/SrmTenderBidController.java
+++ b/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/controller/admin/tender/SrmTenderBidController.java
@@ -111,6 +111,7 @@
if (material != null) {
vo.setTenderMaterialCode(material.getProductCode());
vo.setTenderMaterialName(material.getProductName());
+ vo.setMaterialName(material.getProductName());
vo.setTenderMaterialSpec(material.getProductSpec());
vo.setTenderMaterialUnit(material.getUnit());
}
diff --git a/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/controller/admin/tender/vo/SrmSupplierQuoteRespVO.java b/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/controller/admin/tender/vo/SrmSupplierQuoteRespVO.java
index b4b81ed..2e5d968 100644
--- a/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/controller/admin/tender/vo/SrmSupplierQuoteRespVO.java
+++ b/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/controller/admin/tender/vo/SrmSupplierQuoteRespVO.java
@@ -31,6 +31,9 @@
@Schema(description = "鐗╂枡鍚嶇О")
private String tenderMaterialName;
+ @Schema(description = "鐗╂枡鍚嶇О锛堜笌鍓嶇 materialName 瀵瑰簲锛�")
+ private String materialName;
+
@Schema(description = "鐗╂枡瑙勬牸")
private String tenderMaterialSpec;
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 fd1cc12..766e20c 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
@@ -21,4 +21,9 @@
.eq(SrmTenderBidDO::getSupplierId, supplierId));
}
+ default boolean existsByBidNo(String bidNo) {
+ return exists(new LambdaQueryWrapperX<SrmTenderBidDO>()
+ .eq(SrmTenderBidDO::getBidNo, bidNo));
+ }
+
}
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 72cef94..e685314 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
@@ -37,6 +37,7 @@
ErrorCode TENDER_STATUS_ALREADY_CLOSED = new ErrorCode(1_040_500_010, "宸插叧闂殑椤圭洰涓嶅厑璁告搷浣�");
ErrorCode BID_NOT_EXISTS = new ErrorCode(1_040_500_003, "鎶曟爣璁板綍涓嶅瓨鍦�");
ErrorCode BID_SUPPLIER_EXISTS = new ErrorCode(1_040_500_004, "渚涘簲鍟嗗凡鍙備笌鎶曟爣");
+ ErrorCode BID_NO_EXISTS = new ErrorCode(1_040_500_016, "鎶曟爣缂栧彿宸插瓨鍦�");
ErrorCode BID_PAST_END_TIME = new ErrorCode(1_040_500_005, "鎶曟爣宸叉埅姝�");
ErrorCode BID_SUPPLIER_NOT_APPROVED = new ErrorCode(1_040_500_011, "渚涘簲鍟嗘湭閫氳繃鍑嗗叆瀹℃壒锛屾棤娉曞弬涓庢姇鏍�");
ErrorCode BID_WITHDRAWN_CANNOT_QUOTE = new ErrorCode(1_040_500_012, "鎶曟爣宸叉挙鏍囷紝涓嶅厑璁告姤浠�");
diff --git a/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/supplier/SrmSupplierServiceImpl.java b/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/supplier/SrmSupplierServiceImpl.java
index de712dc..dd02774 100644
--- a/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/supplier/SrmSupplierServiceImpl.java
+++ b/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/supplier/SrmSupplierServiceImpl.java
@@ -14,7 +14,9 @@
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
+import cn.hutool.core.collection.CollUtil;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
@Service
@@ -79,6 +81,9 @@
@Override
public List<SrmSupplierDO> getSupplierList(Collection<Long> ids) {
+ if (CollUtil.isEmpty(ids)) {
+ return Collections.emptyList();
+ }
return supplierMapper.selectBatchIds(ids);
}
diff --git a/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/tender/SrmBidAwardService.java b/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/tender/SrmBidAwardService.java
index e11e855..d27fd62 100644
--- a/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/tender/SrmBidAwardService.java
+++ b/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/tender/SrmBidAwardService.java
@@ -25,6 +25,11 @@
SrmBidAwardDO getAwardByProjectId(Long tenderProjectId);
/**
+ * 鍒犻櫎瀹氭爣
+ */
+ void deleteAward(Long id);
+
+ /**
* 瀹℃壒瀹氭爣
*/
void approveAward(Long id);
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 c27da39..962feb8 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
@@ -15,10 +15,12 @@
import cn.iocoder.yudao.module.srm.enums.ErrorCodeConstants;
import cn.iocoder.yudao.module.srm.enums.TenderStatusEnum;
import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
+import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
@@ -29,6 +31,7 @@
*/
@Service
@Validated
+@Slf4j
public class SrmBidAwardServiceImpl implements SrmBidAwardService {
@Resource
@@ -86,6 +89,13 @@
@Override
public SrmBidAwardDO getAwardByProjectId(Long tenderProjectId) {
return bidAwardMapper.selectByTenderProjectId(tenderProjectId);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void deleteAward(Long id) {
+ SrmBidAwardDO award = validateAwardExists(id);
+ bidAwardMapper.deleteById(id);
}
@Override
@@ -169,15 +179,33 @@
ErpPurchaseOrderCreateReqDTO createReq = new ErpPurchaseOrderCreateReqDTO();
createReq.setSupplierId(srmSupplier.getId());
createReq.setOrderTime(LocalDateTime.now());
+ createReq.setDepositPrice(BigDecimal.ZERO);
createReq.setItems(orderItems);
createReq.setRemark("SRM 瀹氭爣鑷姩鐢熸垚, 瀹氭爣缂栧彿: " + award.getAwardNo());
Long purchaseOrderId = erpPurchaseOrderApi.createPurchaseOrder(createReq).getCheckedData();
+ // 鑾峰彇閲囪喘璁㈠崟鍙�
+ String purchaseOrderNo = null;
+ try {
+ purchaseOrderNo = erpPurchaseOrderApi.getPurchaseOrder(purchaseOrderId)
+ .getCheckedData().getNo();
+ } catch (Exception e) {
+ log.warn("[generatePurchaseOrder] 鑾峰彇閲囪喘璁㈠崟鍙峰け璐ワ紝purchaseOrderId={}", purchaseOrderId, e);
+ }
+
// 8. 鏇存柊瀹氭爣璁板綍
award.setPurchaseOrderId(purchaseOrderId);
+ award.setPurchaseOrderNo(purchaseOrderNo);
award.setAwardStatus(AwardStatusEnum.ORDER_GENERATED.getCode());
bidAwardMapper.updateById(award);
+
+ // 9. 鏇存柊鎷涙爣椤圭洰鐘舵��
+ SrmTenderProjectDO project = tenderProjectMapper.selectById(award.getTenderProjectId());
+ if (project != null) {
+ 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/SrmBidEvaluationService.java b/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/tender/SrmBidEvaluationService.java
index 1614b1b..3ffd6a8 100644
--- a/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/tender/SrmBidEvaluationService.java
+++ b/yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/tender/SrmBidEvaluationService.java
@@ -20,6 +20,11 @@
Long createEvaluation(@Valid SrmBidEvaluationSaveReqVO createReqVO);
/**
+ * 鏇存柊璇勬爣璁板綍
+ */
+ void updateEvaluation(@Valid SrmBidEvaluationSaveReqVO updateReqVO);
+
+ /**
* 鑾峰彇璇勬爣鍒楄〃锛堟寜鎷涙爣椤圭洰锛�
*/
List<SrmBidEvaluationDO> getEvaluationList(Long tenderProjectId);
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 fa1f95e..c0f3b72 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
@@ -44,6 +44,8 @@
@Transactional(rollbackFor = Exception.class)
public Long createEvaluation(SrmBidEvaluationSaveReqVO createReqVO) {
SrmBidEvaluationDO evaluation = BeanUtils.toBean(createReqVO, SrmBidEvaluationDO.class);
+ // 寮哄埗缃┖ id锛岄伩鍏嶅墠绔紶鍏ュ凡鏈� id 瀵艰嚧涓婚敭鍐茬獊锛岀敱鏁版嵁搴撳簭鍒楄嚜鍔ㄧ敓鎴�
+ evaluation.setId(null);
// 璁$畻缁煎悎璇勫垎: 浠锋牸*0.4 + 鎶�鏈�*0.3 + 浜や粯*0.2 + 鏈嶅姟*0.1
BigDecimal price = nvl(evaluation.getPriceScore());
BigDecimal tech = nvl(evaluation.getTechScore());
@@ -67,6 +69,28 @@
}
@Override
+ @Transactional(rollbackFor = Exception.class)
+ public void updateEvaluation(SrmBidEvaluationSaveReqVO updateReqVO) {
+ SrmBidEvaluationDO existing = bidEvaluationMapper.selectById(updateReqVO.getId());
+ if (existing == null) {
+ throw ServiceExceptionUtil.exception(ErrorCodeConstants.EVALUATION_NOT_EXISTS_TENDER);
+ }
+ SrmBidEvaluationDO evaluation = BeanUtils.toBean(updateReqVO, SrmBidEvaluationDO.class);
+ BigDecimal price = nvl(evaluation.getPriceScore());
+ BigDecimal tech = nvl(evaluation.getTechScore());
+ BigDecimal delivery = nvl(evaluation.getDeliveryScore());
+ BigDecimal service = nvl(evaluation.getServiceScore());
+ BigDecimal composite = price.multiply(new BigDecimal("0.4"))
+ .add(tech.multiply(new BigDecimal("0.3")))
+ .add(delivery.multiply(new BigDecimal("0.2")))
+ .add(service.multiply(new BigDecimal("0.1")))
+ .setScale(2, RoundingMode.HALF_UP);
+ evaluation.setCompositeScore(composite);
+ evaluation.setEvaluationTime(LocalDateTime.now());
+ bidEvaluationMapper.updateById(evaluation);
+ }
+
+ @Override
public List<SrmBidEvaluationDO> getEvaluationList(Long tenderProjectId) {
return bidEvaluationMapper.selectListByTenderProjectId(tenderProjectId);
}
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 6931e61..91e6e74 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
@@ -51,6 +51,10 @@
if (!supplierApplyMapper.existsApprovedBySupplierId(createReqVO.getSupplierId())) {
throw ServiceExceptionUtil.exception(ErrorCodeConstants.BID_SUPPLIER_NOT_APPROVED);
}
+ // 鏍¢獙鎶曟爣缂栧彿鏄惁閲嶅
+ if (tenderBidMapper.existsByBidNo(createReqVO.getBidNo())) {
+ throw ServiceExceptionUtil.exception(ErrorCodeConstants.BID_NO_EXISTS);
+ }
// 鏍¢獙渚涘簲鍟嗘槸鍚﹀凡鍙備笌鎶曟爣
SrmTenderBidDO existing = tenderBidMapper.selectByTenderAndSupplier(createReqVO.getTenderProjectId(), createReqVO.getSupplierId());
if (existing != null) {
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 0048d8f..7de0819 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
@@ -11,6 +11,7 @@
import cn.iocoder.yudao.module.srm.dal.mysql.SrmBidAwardMapper;
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;
@@ -64,7 +65,15 @@
@Override
public SrmTenderProjectDO getTenderProject(Long id) {
- return tenderProjectMapper.selectById(id);
+ SrmTenderProjectDO project = tenderProjectMapper.selectById(id);
+ if (project != null) {
+ SrmBidAwardDO award = bidAwardMapper.selectByTenderProjectId(id);
+ if (award != null) {
+ project.setAwardId(award.getId());
+ project.setPurchaseOrderNo(award.getPurchaseOrderNo());
+ }
+ }
+ return project;
}
@Override
@@ -82,6 +91,10 @@
if (award != null) {
project.setAwardId(award.getId());
project.setPurchaseOrderNo(award.getPurchaseOrderNo());
+ // 闃插尽锛氬鏋滃畾鏍囧凡鐢熸垚璁㈠崟浣嗛」鐩姸鎬佹湭鏇存柊锛屽悓姝ョ姸鎬�
+ if (AwardStatusEnum.ORDER_GENERATED.getCode().equals(award.getAwardStatus())) {
+ project.setTenderStatus(TenderStatusEnum.CLOSED.getCode());
+ }
}
});
}
--
Gitblit v1.9.3