From 04d6024553ac73e67148ce578cb01b541eebd02a Mon Sep 17 00:00:00 2001
From: yyb <995253665@qq.com>
Date: 星期一, 18 五月 2026 16:37:56 +0800
Subject: [PATCH] Merge branch 'dev_NEW_pro' into dev-new_pro_OA

---
 multiple/assets/favicon/JXJHfavicon.ico                                    |    0 
 src/views/productionManagement/productionProcess/index.vue                 |   20 
 src/views/reportAnalysis/PSIDataAnalysis/components/left-top.vue           |    9 
 multiple/assets/favicon/ZQSYfavicon.ico                                    |    0 
 src/views/basicData/product/index.vue                                      |   53 
 src/views/reportAnalysis/productionAnalysis/index.vue                      |   16 
 src/views/equipmentManagement/measurementEquipment/components/formDia.vue  |   34 
 src/views/financialManagement/generalLedger/index.vue                      |  102 +
 src/views/equipmentManagement/repair/Modal/AcceptanceModal.vue             |  144 +
 src/views/qualityManagement/rawMaterialInspection/index.vue                |   26 
 src/views/reportAnalysis/dataDashboard/components/basic/right-top.vue      |    9 
 src/views/reportAnalysis/productionAnalysis/components/left-top.vue        |    9 
 src/views/qualityManagement/finalInspection/index.vue                      |   21 
 src/views/reportAnalysis/dataDashboard/components/basic/right-bottom.vue   |    9 
 src/views/personnelManagement/contractManagement/index.vue                 |   22 
 multiple/assets/favicon/HYLQfavicon.ico                                    |    0 
 src/api/inventoryManagement/stockInventory.js                              |    8 
 src/views/qualityManagement/processInspection/index.vue                    |   25 
 src/views/collaborativeApproval/sealManagement/index.vue                   |   82 
 multiple/assets/logo/ZQSYLogo.png                                          |    0 
 src/views/reportAnalysis/productionAnalysis/components/right-top.vue       |    9 
 src/views/reportAnalysis/productionAnalysis/components/left-bottom.vue     |    9 
 src/views/procurementManagement/purchaseReturnOrder/ProductList.vue        |   15 
 multiple/assets/logo/JHYLogo.png                                           |    0 
 multiple/assets/logo/HYLQLogo.png                                          |    0 
 src/views/financialManagement/voucher/generalLedger.vue                    |  326 ++-
 src/views/equipmentManagement/upkeep/index.vue                             |    5 
 src/views/qualityManagement/processInspection/components/formDia.vue       |  932 ++++++----
 src/components/AIChatSidebar/assistants/productionAssistant.js             |   27 
 src/views/personnelManagement/employeeRecord/index.vue                     |   59 
 src/views/aiIndustrialBrain/index.vue                                      |    1 
 src/views/equipmentManagement/repair/Modal/RepairModal.vue                 |   38 
 multiple/assets/favicon/JHYfavicon.ico                                     |    0 
 src/views/salesManagement/salesQuotation/index.vue                         |   77 
 src/views/reportAnalysis/dataDashboard/components/basic/center-bottom.vue  |    9 
 src/views/financialManagement/assets/fixedAssets.vue                       |   23 
 multiple/assets/logo/QXYLogo.png                                           |    0 
 src/views/reportAnalysis/productionAnalysis/components/center-top.vue      |    9 
 src/views/procurementManagement/procurementLedger/index.vue                |    1 
 src/views/equipmentManagement/measurementEquipment/index.vue               |   48 
 src/views/reportAnalysis/PSIDataAnalysis/components/center-bottom.vue      |    9 
 src/views/qualityManagement/rawMaterialInspection/components/formDia.vue   |   86 
 src/views/procurementManagement/purchaseReturnOrder/New.vue                |   15 
 src/views/qualityManagement/nonconformingManagement/index.vue              |    2 
 src/views/reportAnalysis/dataDashboard/components/basic/left-top.vue       |    9 
 src/views/safeProduction/safeWorkApproval/components/infoFormDia.vue       |    6 
 multiple/assets/logo/XSWHLogo.png                                          |    0 
 multiple/config.json                                                       |   69 
 src/views/equipmentManagement/upkeep/Form/PlanModal.vue                    |   13 
 src/views/reportAnalysis/dataDashboard/index.vue                           |   16 
 src/views/equipmentManagement/inspectionManagement/components/formDia.vue  |   19 
 src/views/productionManagement/processRoute/processRouteItem/index.vue     |   79 
 src/components/ProcessParamListDialog.vue                                  |   34 
 src/views/salesManagement/returnOrder/components/detailDia.vue             |   15 
 src/components/AIChatSidebar/assistants/index.js                           |   11 
 src/views/collaborativeApproval/approvalProcess/index.vue                  |   23 
 src/views/financialManagement/voucher/index.vue                            |  107 +
 src/views/salesManagement/salesLedger/index.vue                            |    8 
 src/views/reportAnalysis/PSIDataAnalysis/index.vue                         |   16 
 src/views/reportAnalysis/productionAnalysis/components/center-center.vue   |    9 
 src/views/aiIndustrialBrain/MAINTAIN_RULES.md                              |    7 
 multiple/assets/favicon/QXYfavicon.ico                                     |    0 
 src/views/salesManagement/returnOrder/components/formDia.vue               |    5 
 multiple/assets/logo/JXJHLogo.png                                          |    0 
 src/views/procurementManagement/purchaseReturnOrder/index.vue              |   15 
 src/views/financialManagement/assets/intangibleAssets.vue                  |   23 
 src/views/inventoryManagement/stockManagement/Record.vue                   |  354 ++-
 src/views/financialManagement/voucher/detailLedger.vue                     |  383 ++--
 multiple/assets/favicon/XSWHfavicon.ico                                    |    0 
 multiple/assets/logo/YTJZLogo.png                                          |    0 
 src/views/reportAnalysis/productionAnalysis/components/right-bottom.vue    |    9 
 src/views/basicData/supplierManage/components/HomeTab.vue                  |   21 
 multiple/assets/favicon/YTJZfavicon.ico                                    |    0 
 src/views/qualityManagement/finalInspection/components/formDia.vue         |  180 +
 src/views/equipmentManagement/repair/index.vue                             |   36 
 src/components/AIChatSidebar/index.vue                                     |  763 ++++++++
 src/views/collaborativeApproval/approvalProcess/components/infoFormDia.vue |    5 
 src/views/equipmentManagement/inspectionManagement/index.vue               |   17 
 src/views/productionManagement/productStructure/Detail/index.vue           |   49 
 src/views/reportAnalysis/PSIDataAnalysis/components/left-bottom.vue        |    9 
 src/views/reportAnalysis/dataDashboard/components/basic/left-bottom.vue    |    9 
 src/api/equipmentManagement/repair.js                                      |   13 
 src/views/reportAnalysis/PSIDataAnalysis/components/center-top.vue         |    9 
 src/views/inventoryManagement/stockManagement/BatchNoQtyDetail.vue         |  227 ++
 src/views/aiIndustrialBrain/components/AiAssistantWorkspace.vue            |   16 
 src/views/reportAnalysis/productionAnalysis/components/center-bottom.vue   |   27 
 src/views/equipmentManagement/upkeep/Form/formDia.vue                      |   22 
 multiple/assets/logo/HYJCLogo.png                                          |    0 
 src/views/basicData/supplierManage/components/BlacklistTab.vue             |   21 
 src/views/reportAnalysis/PSIDataAnalysis/components/center-center.vue      |    9 
 src/views/reportAnalysis/dataDashboard/components/basic/center-top.vue     |   44 
 multiple/assets/favicon/HYJCfavicon.ico                                    |    0 
 92 files changed, 3,771 insertions(+), 1,225 deletions(-)

diff --git a/multiple/assets/favicon/HYJCfavicon.ico b/multiple/assets/favicon/HYJCfavicon.ico
new file mode 100644
index 0000000..e52f096
--- /dev/null
+++ b/multiple/assets/favicon/HYJCfavicon.ico
Binary files differ
diff --git a/multiple/assets/favicon/HYLQfavicon.ico b/multiple/assets/favicon/HYLQfavicon.ico
new file mode 100644
index 0000000..9a2dbf3
--- /dev/null
+++ b/multiple/assets/favicon/HYLQfavicon.ico
Binary files differ
diff --git a/multiple/assets/favicon/JHYfavicon.ico b/multiple/assets/favicon/JHYfavicon.ico
new file mode 100644
index 0000000..f818f6f
--- /dev/null
+++ b/multiple/assets/favicon/JHYfavicon.ico
Binary files differ
diff --git a/multiple/assets/favicon/JXJHfavicon.ico b/multiple/assets/favicon/JXJHfavicon.ico
new file mode 100644
index 0000000..0c90589
--- /dev/null
+++ b/multiple/assets/favicon/JXJHfavicon.ico
Binary files differ
diff --git a/multiple/assets/favicon/QXYfavicon.ico b/multiple/assets/favicon/QXYfavicon.ico
new file mode 100644
index 0000000..e56847e
--- /dev/null
+++ b/multiple/assets/favicon/QXYfavicon.ico
Binary files differ
diff --git a/multiple/assets/favicon/XSWHfavicon.ico b/multiple/assets/favicon/XSWHfavicon.ico
new file mode 100644
index 0000000..f6cd72d
--- /dev/null
+++ b/multiple/assets/favicon/XSWHfavicon.ico
Binary files differ
diff --git a/multiple/assets/favicon/YTJZfavicon.ico b/multiple/assets/favicon/YTJZfavicon.ico
new file mode 100644
index 0000000..ad7b03b
--- /dev/null
+++ b/multiple/assets/favicon/YTJZfavicon.ico
Binary files differ
diff --git a/multiple/assets/favicon/ZQSYfavicon.ico b/multiple/assets/favicon/ZQSYfavicon.ico
new file mode 100644
index 0000000..9e3422f
--- /dev/null
+++ b/multiple/assets/favicon/ZQSYfavicon.ico
Binary files differ
diff --git a/multiple/assets/logo/HYJCLogo.png b/multiple/assets/logo/HYJCLogo.png
new file mode 100644
index 0000000..367f64d
--- /dev/null
+++ b/multiple/assets/logo/HYJCLogo.png
Binary files differ
diff --git a/multiple/assets/logo/HYLQLogo.png b/multiple/assets/logo/HYLQLogo.png
new file mode 100644
index 0000000..8eda2f7
--- /dev/null
+++ b/multiple/assets/logo/HYLQLogo.png
Binary files differ
diff --git a/multiple/assets/logo/JHYLogo.png b/multiple/assets/logo/JHYLogo.png
new file mode 100644
index 0000000..edf5921
--- /dev/null
+++ b/multiple/assets/logo/JHYLogo.png
Binary files differ
diff --git a/multiple/assets/logo/JXJHLogo.png b/multiple/assets/logo/JXJHLogo.png
new file mode 100644
index 0000000..1d47288
--- /dev/null
+++ b/multiple/assets/logo/JXJHLogo.png
Binary files differ
diff --git a/multiple/assets/logo/QXYLogo.png b/multiple/assets/logo/QXYLogo.png
new file mode 100644
index 0000000..45318ed
--- /dev/null
+++ b/multiple/assets/logo/QXYLogo.png
Binary files differ
diff --git a/multiple/assets/logo/XSWHLogo.png b/multiple/assets/logo/XSWHLogo.png
new file mode 100644
index 0000000..d0c32f5
--- /dev/null
+++ b/multiple/assets/logo/XSWHLogo.png
Binary files differ
diff --git a/multiple/assets/logo/YTJZLogo.png b/multiple/assets/logo/YTJZLogo.png
new file mode 100644
index 0000000..ea0c489
--- /dev/null
+++ b/multiple/assets/logo/YTJZLogo.png
Binary files differ
diff --git a/multiple/assets/logo/ZQSYLogo.png b/multiple/assets/logo/ZQSYLogo.png
new file mode 100644
index 0000000..fe865b6
--- /dev/null
+++ b/multiple/assets/logo/ZQSYLogo.png
Binary files differ
diff --git a/multiple/config.json b/multiple/config.json
index b824456..b1b0131 100644
--- a/multiple/config.json
+++ b/multiple/config.json
@@ -44,9 +44,9 @@
   },
   "BTYX": {
     "env": {
-      "VITE_APP_TITLE": "娌冲崡甯お浼橀�夎繘鍑哄彛鏈夐檺鍏徃",
-      "VITE_BASE_API": "http://127.0.0.1:9001",
-      "VITE_JAVA_API": "http://127.0.0.1:9000"
+      "VITE_APP_TITLE": "娌冲崡甯お浼橀�夐鍝佹湁闄愬叕鍙�",
+      "VITE_BASE_API": "http://1.15.17.182:9056",
+      "VITE_JAVA_API": "http://1.15.17.182:9057"
     },
     "logo": "logo/BTYXLogo.png",
     "favicon": "favicon/BTYXfavicon.ico"
@@ -96,6 +96,69 @@
     "logo": "logo/DYKJLogo.png",
     "favicon": "favicon/DYKJfavicon.ico"
   },
+  "ZQSY": {
+    "env": {
+      "VITE_APP_TITLE": "娉芥穱瀹炰笟",
+      "VITE_BASE_API": "http://36.213.128.159:9000",
+      "VITE_JAVA_API": "http://36.213.128.159:9001"
+    },
+    "logo": "logo/ZQSYLogo.png",
+    "favicon": "favicon/ZQSYfavicon.ico"
+  },
+  "JXJH": {
+    "env": {
+      "VITE_APP_TITLE": "娴氬幙姹熸捣姘存偿鍒跺搧鏈夐檺鍏徃",
+      "VITE_BASE_API": "http://36.139.201.20:9000",
+      "VITE_JAVA_API": "http://36.139.201.20:9001"
+    },
+    "logo": "logo/JXJHLogo.png",
+    "favicon": "favicon/JXJHfavicon.ico"
+  },
+  "YTJZ": {
+    "env": {
+      "VITE_APP_TITLE": "璞嘲寤虹瓚鏉愭枡鏈夐檺鍏徃",
+      "VITE_BASE_API": "http://36.139.201.181:9000",
+      "VITE_JAVA_API": "http://36.139.201.181:9001"
+    },
+    "logo": "logo/YTJZLogo.png",
+    "favicon": "favicon/YTJZfavicon.ico"
+  },
+  "HYLQ": {
+    "env": {
+      "VITE_APP_TITLE": "鑸�歌矾妗ュ伐绋嬫湁闄愬叕鍙�",
+      "VITE_BASE_API": "http://36.139.202.111:9000",
+      "VITE_JAVA_API": "http://36.139.202.111:9001"
+    },
+    "logo": "logo/HYLQLogo.png",
+    "favicon": "favicon/HYLQfavicon.ico"
+  },
+  "QXY": {
+    "env": {
+      "VITE_APP_TITLE": "寮轰俊瀹囩數鍣ㄤ簯涓绘満",
+      "VITE_BASE_API": "http://36.134.154.10:9000",
+      "VITE_JAVA_API": "http://36.134.154.10:9001"
+    },
+    "logo": "logo/QXYLogo.png",
+    "favicon": "favicon/QXYfavicon.ico"
+  },
+  "HYJC": {
+    "env": {
+      "VITE_APP_TITLE": "鎭掓磱寤烘潗",
+      "VITE_BASE_API": "http://36.138.94.178:9000",
+      "VITE_JAVA_API": "http://36.138.94.178:9001"
+    },
+    "logo": "logo/HYJCLogo.png",
+    "favicon": "favicon/HYJCfavicon.ico"
+  },
+  "JHY": {
+    "env": {
+      "VITE_APP_TITLE": "灞辫タ鐪佹绀惧幙鏅嬪拰鍥鍝佹湁闄愬叕鍙�",
+      "VITE_BASE_API": "http://223.15.233.27:9001",
+      "VITE_JAVA_API": "http://223.15.233.27:9002"
+    },
+    "logo": "logo/JHYLogo.png",
+    "favicon": "favicon/JHYfavicon.ico"
+  },
   "logo": "/src/assets/logo/logo.png",
   "favicon": "/public/favicon.ico"
 }
diff --git a/src/api/equipmentManagement/repair.js b/src/api/equipmentManagement/repair.js
index 0233ae6..16bfd28 100644
--- a/src/api/equipmentManagement/repair.js
+++ b/src/api/equipmentManagement/repair.js
@@ -70,3 +70,16 @@
     data,
   });
 };
+
+/**
+ * @desc 楠屾敹瀹℃壒
+ * @param {楠屾敹鍙傛暟} data
+ * @returns
+ */
+export const repairAcceptance = (data) => {
+  return request({
+    url: `/device/repair/acceptance`,
+    method: "post",
+    data,
+  });
+};
diff --git a/src/api/inventoryManagement/stockInventory.js b/src/api/inventoryManagement/stockInventory.js
index 0ba0943..539eedc 100644
--- a/src/api/inventoryManagement/stockInventory.js
+++ b/src/api/inventoryManagement/stockInventory.js
@@ -17,6 +17,14 @@
     });
 };
 
+export const getStockInventoryBatchNoQty = (params) => {
+    return request({
+        url: "/stockInventory/getBatchNoQty",
+        method: "get",
+        params,
+    });
+};
+
 // 鍒涘缓搴撳瓨璁板綍
 export const createStockInventory = (params) => {
     return request({
diff --git a/src/components/AIChatSidebar/assistants/index.js b/src/components/AIChatSidebar/assistants/index.js
index 61d4752..96c54fa 100644
--- a/src/components/AIChatSidebar/assistants/index.js
+++ b/src/components/AIChatSidebar/assistants/index.js
@@ -1,6 +1,13 @@
 import { generalAssistant } from './generalAssistant'
 import { purchaseAssistant } from './purchaseAssistant'
+import { productionAssistant } from './productionAssistant'
 
-export { generalAssistant, purchaseAssistant }
+export { generalAssistant, purchaseAssistant, productionAssistant }
 
-export const builtInAssistants = [generalAssistant, purchaseAssistant]
+export const assistantRegistry = {
+  general: generalAssistant,
+  purchase: purchaseAssistant,
+  production: productionAssistant
+}
+
+export const builtInAssistants = [generalAssistant, purchaseAssistant, productionAssistant]
diff --git a/src/components/AIChatSidebar/assistants/productionAssistant.js b/src/components/AIChatSidebar/assistants/productionAssistant.js
new file mode 100644
index 0000000..fb2d737
--- /dev/null
+++ b/src/components/AIChatSidebar/assistants/productionAssistant.js
@@ -0,0 +1,27 @@
+import { Operation } from '@element-plus/icons-vue'
+
+export const productionAssistant = {
+  key: 'production',
+  label: '鐢熶骇鍔╃悊',
+  title: '鐢熶骇鏅鸿兘鍔╃悊',
+  tooltip: '鐢熶骇鏅鸿兘鍔╂墜',
+  icon: Operation,
+  apiBase: '/manufacturing-ai',
+  storageKey: 'production_ai_chat_uuid',
+  placeholder: '璇疯緭鍏ョ敓浜х浉鍏抽棶棰�... (Enter 鍙戦��, Shift+Enter 鎹㈣)',
+  welcomeMessage: '浣犲ソ',
+  description: '鎴戝彲浠ュ洿缁曠敓浜х幇鍦恒�佽鍒掋�佸伐鍗曘�佽澶囥�佽川閲忋�佺墿鏂欍�佸紓甯稿鐞嗘彁渚涙煡璇€�侀璀︺�佸垎鏋愬拰鍔炵悊寤鸿銆�',
+  allowFileUpload: false,
+  emptySessionText: '鏆傛棤鐢熶骇浼氳瘽',
+  quickPrompts: [
+    '鏌ヨ鏈湀鐢熶骇璁″垝',
+    '鏌ョ湅鏈�杩�10鏉″伐鍗�',
+    '鏌ヨ澶嘇-01鐨勭淮淇儏鍐�',
+    '鏌ヨ川閲忎笉鍚堟牸璁板綍',
+    '鏌ヤ綆搴撳瓨鐗╂枡',
+    '鏌ヨ繎7澶╁紓甯稿鐞�',
+    '鐢熸垚鍒堕�犻璀︾湅鏉�',
+    '鍒嗘瀽鏈湀鐢熶骇瀹屾垚鐜囧拰寮傚父鐜�',
+    '缁欏嚭宸ュ崟閫炬湡鍜岃澶囧緟淇殑鍔炵悊寤鸿'
+  ]
+}
diff --git a/src/components/AIChatSidebar/index.vue b/src/components/AIChatSidebar/index.vue
index a2a365a..e3a9e3c 100644
--- a/src/components/AIChatSidebar/index.vue
+++ b/src/components/AIChatSidebar/index.vue
@@ -242,7 +242,123 @@
                   </el-table>
                 </div>
 
-                <!-- 鎵撳瓧涓姩鐢� -->
+                <div v-if="message.manufacturingData" class="manufacturing-card">
+                  <div class="manufacturing-card__title">{{ getManufacturingTypeLabel(message.type) }}</div>
+
+                  <div
+                      v-if="message.manufacturingData.summaryEntries?.length || message.manufacturingData.coreMetrics?.length"
+                      class="manufacturing-summary-grid"
+                  >
+                    <div
+                        v-for="(entry, entryIndex) in message.manufacturingData.summaryEntries"
+                        :key="`summary-${entry.key}-${entryIndex}`"
+                        class="manufacturing-summary-item"
+                    >
+                      <span class="manufacturing-summary-label">{{ entry.label }}</span>
+                      <strong class="manufacturing-summary-value">{{ entry.value }}</strong>
+                    </div>
+                    <div
+                        v-for="(metric, metricIndex) in message.manufacturingData.coreMetrics"
+                        :key="`core-${metric.key}-${metricIndex}`"
+                        class="manufacturing-summary-item manufacturing-summary-item--core"
+                    >
+                      <span class="manufacturing-summary-label">{{ metric.label }}</span>
+                      <strong class="manufacturing-summary-value">{{ metric.value }}</strong>
+                    </div>
+                  </div>
+
+                  <div v-if="message.manufacturingData.warningItems?.length" class="manufacturing-warning-list">
+                    <div
+                        v-for="(warning, warningIndex) in message.manufacturingData.warningItems"
+                        :key="`warning-${warning.title || warningIndex}`"
+                        class="manufacturing-warning-item"
+                    >
+                      <div class="manufacturing-warning-item__head">
+                        <el-tag size="small" :type="getManufacturingWarningLevelType(warning.level)">
+                          {{ getManufacturingWarningLevelLabel(warning.level) }}
+                        </el-tag>
+                        <strong>{{ warning.title || `棰勮 ${warningIndex + 1}` }}</strong>
+                        <span v-if="warning.count !== '' && warning.count !== null && warning.count !== undefined" class="manufacturing-warning-count">
+                          {{ warning.count }}
+                        </span>
+                      </div>
+                      <p v-if="warning.detail" class="manufacturing-warning-detail">{{ warning.detail }}</p>
+                    </div>
+                  </div>
+
+                  <div
+                      v-if="message.manufacturingData.listItems?.length && message.manufacturingData.columns?.length"
+                      class="table-wrapper manufacturing-table-wrapper"
+                  >
+                    <el-table :data="message.manufacturingData.listItems" border stripe size="small" style="width: 100%">
+                      <el-table-column
+                          v-for="col in message.manufacturingData.columns"
+                          :key="col"
+                          :label="getStructuredFieldLabel(col)"
+                          min-width="140"
+                          show-overflow-tooltip
+                      >
+                        <template #default="{ row }">
+                          {{ formatStructuredValue(row[col]) }}
+                        </template>
+                      </el-table-column>
+                    </el-table>
+                  </div>
+
+                  <div v-if="message.manufacturingData.actionCards?.length" class="manufacturing-action-list">
+                    <div
+                        v-for="(card, cardIndex) in message.manufacturingData.actionCards"
+                        :key="card.runtimeKey || `${card.code}-${card.targetApi}-${cardIndex}`"
+                        class="manufacturing-action-card"
+                    >
+                      <div class="manufacturing-action-card__head">
+                        <strong>{{ card.name || `鍔ㄤ綔 ${cardIndex + 1}` }}</strong>
+                        <el-tag size="small" type="info">{{ getNormalizedRequestMethod(card.method) }}</el-tag>
+                      </div>
+                      <div class="manufacturing-action-card__meta">
+                        <span>{{ card.code || '--' }}</span>
+                        <span>{{ card.targetApi || '--' }}</span>
+                      </div>
+                      <p v-if="card.description" class="manufacturing-action-card__desc">{{ card.description }}</p>
+                      <div v-if="card.requiredFields?.length" class="manufacturing-required-fields">
+                        <span>蹇呭~瀛楁</span>
+                        <el-tag
+                            v-for="field in card.requiredFields"
+                            :key="field"
+                            size="small"
+                            type="warning"
+                        >
+                          {{ getStructuredPathLabel(field) }}
+                        </el-tag>
+                      </div>
+                      <el-input
+                          v-model="card.payloadText"
+                          type="textarea"
+                          :rows="6"
+                          resize="vertical"
+                          :disabled="card.executing"
+                          placeholder="璇疯緭鍏� JSON 璇锋眰鍙傛暟"
+                      />
+                      <div class="manufacturing-action-footer">
+                        <span
+                            v-if="card.executeResult"
+                            :class="['manufacturing-action-result', card.executeError ? 'error' : 'success']"
+                        >
+                          {{ card.executeResult }}
+                        </span>
+                        <el-button
+                            type="primary"
+                            size="small"
+                            :loading="card.executing"
+                            @click="executeManufacturingAction(message, card, cardIndex)"
+                        >
+                          纭骞舵墽琛�
+                        </el-button>
+                      </div>
+                    </div>
+                  </div>
+                </div>
+
                 <div v-if="message.purchaseAnalysisData" class="purchase-confirm-card">
                   <div class="purchase-confirm-header">
                     <span>{{ businessTypeLabelMap[message.purchaseAnalysisData.businessType] || message.purchaseAnalysisData.businessType || '閲囪喘涓氬姟' }}</span>
@@ -523,7 +639,7 @@
 import request from '@/utils/request'
 import * as echarts from 'echarts'
 import { Cpu, User, Plus, Timer, Delete, ChatDotSquare, VideoPause, Upload, Document, Close, Promotion, RefreshRight } from '@element-plus/icons-vue'
-import { ElMessage } from 'element-plus'
+import { ElMessage, ElMessageBox } from 'element-plus'
 import { builtInAssistants, generalAssistant } from './assistants'
 import todoAssistantAvatar from '@/assets/AI/寰呭姙鍔╂墜.png'
 import salesAssistantAvatar from '@/assets/AI/閿�鍞姪鎵�.png'
@@ -633,6 +749,75 @@
   payment_registration: '浠樻鐧昏',
   purchase_return_order: '閲囪喘閫�璐у崟',
   unknown: '鏈煡閲囪喘涓氬姟'
+}
+const manufacturingStructuredTypeSet = new Set([
+  'manufacturing_site_snapshot',
+  'manufacturing_plan_list',
+  'manufacturing_workorder_list',
+  'manufacturing_device_list',
+  'manufacturing_device_repair_list',
+  'manufacturing_quality_list',
+  'manufacturing_material_list',
+  'manufacturing_exception_list',
+  'manufacturing_warning',
+  'manufacturing_analysis',
+  'manufacturing_action_plan'
+])
+const manufacturingListTypeSet = new Set([
+  'manufacturing_plan_list',
+  'manufacturing_workorder_list',
+  'manufacturing_device_list',
+  'manufacturing_device_repair_list',
+  'manufacturing_quality_list',
+  'manufacturing_material_list',
+  'manufacturing_exception_list'
+])
+const manufacturingTypeLabelMap = {
+  manufacturing_site_snapshot: '鐢熶骇鐜板満姒傝',
+  manufacturing_plan_list: '璁″垝鏌ヨ',
+  manufacturing_workorder_list: '宸ュ崟鏌ヨ',
+  manufacturing_device_list: '璁惧鏌ヨ',
+  manufacturing_device_repair_list: '璁惧缁翠慨璁板綍鏌ヨ',
+  manufacturing_quality_list: '璐ㄩ噺鏌ヨ',
+  manufacturing_material_list: '鐗╂枡鏌ヨ',
+  manufacturing_exception_list: '寮傚父鏌ヨ',
+  manufacturing_warning: '棰勮鐪嬫澘',
+  manufacturing_analysis: '缁忚惀鍒嗘瀽',
+  manufacturing_action_plan: '鍔炵悊寤鸿'
+}
+const structuredFieldLabelMap = {
+  workOrderNo: '宸ュ崟鍙�',
+  planEndTime: '璁″垝缁撴潫鏃堕棿',
+  planStartTime: '璁″垝寮�濮嬫椂闂�',
+  timeRange: '鏃堕棿鑼冨洿',
+  startDate: '寮�濮嬫棩鏈�',
+  endDate: '缁撴潫鏃ユ湡',
+  warningCount: '棰勮鏁伴噺',
+  overduePlanCount: '閫炬湡璁″垝鏁�',
+  overdueWorkOrderCount: '閫炬湡宸ュ崟鏁�',
+  actionCount: '寤鸿鍔ㄤ綔鏁�',
+  qualityOpenCount: '璐ㄩ噺寰呭鐞嗘暟',
+  lowStockCount: '浣庡簱瀛樻暟',
+  exceptionCount: '寮傚父鏁�',
+  userId: '鐢ㄦ埛ID',
+  tenantId: '绉熸埛ID',
+  status: '鐘舵��',
+  deviceName: '璁惧鍚嶇О',
+  deviceModel: '璁惧鍨嬪彿',
+  pendingRepairCount: '寰呯淮淇暟',
+  repairTime: '缁翠慨鏃堕棿',
+  repairName: '鎶ヤ慨浜�',
+  maintenanceName: '缁翠慨浜哄憳',
+  level: '棰勮绛夌骇',
+  title: '鏍囬',
+  count: '鏁伴噺',
+  detail: '璇︽儏',
+  remark: '澶囨敞',
+  createTime: '鍒涘缓鏃堕棿',
+  updateTime: '鏇存柊鏃堕棿',
+  exceptionType: '寮傚父绫诲瀷',
+  materialName: '鐗╂枡鍚嶇О',
+  stockQty: '搴撳瓨閲�'
 }
 const purchasePayloadFieldLabelMap = {
   purchaseLedgers: '閲囪喘鍙拌处',
@@ -785,6 +970,366 @@
   inventoryWarningQuantity: 'inventoryWarningQuantity',
   isInspected: 'isInspected',
   isChecked: 'isInspected'
+}
+const isPlainObject = (value) => value !== null && typeof value === 'object' && !Array.isArray(value)
+
+const stringifyStructuredPayload = (value, spaces = 2) => {
+  if (typeof value === 'string') return value
+  try {
+    return JSON.stringify(value ?? {}, null, spaces)
+  } catch (err) {
+    return '{}'
+  }
+}
+
+const structuredFieldTokenLabelMap = {
+  time: '鏃堕棿',
+  range: '鑼冨洿',
+  start: '寮�濮�',
+  end: '缁撴潫',
+  date: '鏃ユ湡',
+  warning: '棰勮',
+  overdue: '閫炬湡',
+  plan: '璁″垝',
+  work: '宸�',
+  order: '鍗�',
+  workorder: '宸ュ崟',
+  count: '鏁伴噺',
+  quality: '璐ㄩ噺',
+  low: '浣�',
+  stock: '搴撳瓨',
+  exception: '寮傚父',
+  action: '鍔ㄤ綔',
+  user: '鐢ㄦ埛',
+  tenant: '绉熸埛',
+  id: 'ID',
+  no: '缂栧彿',
+  number: '缂栧彿',
+  code: '缂栫爜',
+  name: '鍚嶇О',
+  status: '鐘舵��',
+  level: '绛夌骇',
+  title: '鏍囬',
+  detail: '璇︽儏',
+  total: '鎬绘暟',
+  rate: '姣旂巼',
+  type: '绫诲瀷',
+  pending: '寰�',
+  repair: '缁翠慨',
+  device: '璁惧',
+  material: '鐗╂枡'
+}
+
+const convertStructuredFieldKeyToChinese = (fieldKey = '') => {
+  const key = String(fieldKey || '').trim()
+  if (!key) return '-'
+  if (structuredFieldLabelMap[key]) return structuredFieldLabelMap[key]
+  if (/[\u4e00-\u9fa5]/.test(key)) return key
+
+  const rawTokens = key
+    .replace(/([a-z0-9])([A-Z])/g, '$1 $2')
+    .replace(/[_-]+/g, ' ')
+    .trim()
+    .split(/\s+/)
+    .filter(Boolean)
+    .map(token => token.toLowerCase())
+
+  if (!rawTokens.length) return '瀛楁'
+
+  const mappedTokens = rawTokens
+    .map(token => structuredFieldTokenLabelMap[token] || '')
+    .filter(Boolean)
+
+  if (mappedTokens.length) {
+    return mappedTokens.join('')
+  }
+
+  return '瀛楁'
+}
+
+const getStructuredFieldLabel = (fieldKey = '') => {
+  return convertStructuredFieldKeyToChinese(fieldKey)
+}
+
+const getStructuredPathLabel = (fieldPath = '') => {
+  const path = String(fieldPath || '').trim()
+  if (!path) return '-'
+
+  const segments = path
+    .replace(/\[(\d+)]/g, '.$1')
+    .split('.')
+    .filter(Boolean)
+
+  if (!segments.length) return getStructuredFieldLabel(path)
+
+  return segments.map((segment) => {
+    if (/^\d+$/.test(segment)) {
+      return `绗�${Number(segment) + 1}椤筦
+    }
+    return getStructuredFieldLabel(segment)
+  }).join(' / ')
+}
+
+const formatStructuredValue = (value) => {
+  if (value === null || value === undefined || value === '') return '-'
+  if (Array.isArray(value)) {
+    const preview = value.slice(0, 3).map(item => formatStructuredValue(item)).join('銆�')
+    return value.length > 3 ? `${preview} 绛�${value.length}椤筦 : preview
+  }
+  if (isPlainObject(value)) return stringifyStructuredPayload(value, 0)
+  return String(value)
+}
+
+const normalizeManufacturingSummaryEntries = (summary) => {
+  if (!isPlainObject(summary)) return []
+  return Object.entries(summary)
+    .filter(([, value]) => value !== undefined && value !== null && `${value}`.trim() !== '')
+    .map(([key, value]) => ({
+      key,
+      label: getStructuredFieldLabel(key),
+      value: formatStructuredValue(value)
+    }))
+}
+
+const normalizeManufacturingCoreMetrics = (coreMetrics) => {
+  if (Array.isArray(coreMetrics)) {
+    return coreMetrics.map((item, index) => {
+      if (isPlainObject(item)) {
+        const label = item.label || item.name || item.key || `鎸囨爣${index + 1}`
+        const metricValue = item.value ?? item.metricValue ?? item.data ?? '-'
+        const unit = item.unit ? ` ${item.unit}` : ''
+        return {
+          key: String(item.key || item.name || index),
+          label,
+          value: `${formatStructuredValue(metricValue)}${unit}`.trim()
+        }
+      }
+      return {
+        key: String(index),
+        label: `鎸囨爣${index + 1}`,
+        value: formatStructuredValue(item)
+      }
+    })
+  }
+
+  if (isPlainObject(coreMetrics)) {
+    return Object.entries(coreMetrics).map(([key, value]) => ({
+      key,
+      label: getStructuredFieldLabel(key),
+      value: formatStructuredValue(value)
+    }))
+  }
+
+  return []
+}
+
+const normalizeManufacturingWarningItems = (items = []) => {
+  if (!Array.isArray(items)) return []
+  return items
+    .filter(item => isPlainObject(item))
+    .map(item => ({
+      level: String(item.level || '').toLowerCase(),
+      title: item.title || '',
+      count: item.count ?? '',
+      detail: item.detail ?? ''
+    }))
+}
+
+const inferManufacturingColumns = (items = []) => {
+  if (!Array.isArray(items) || !items.length) return []
+  const fieldSet = new Set()
+  items.forEach((item) => {
+    if (!isPlainObject(item)) return
+    Object.keys(item).forEach((key) => fieldSet.add(key))
+  })
+  return Array.from(fieldSet)
+}
+
+const getManufacturingActionCardRuntimeKey = (card = {}, index = 0) => {
+  const code = String(card?.code || '').trim()
+  const api = String(card?.targetApi || '').trim()
+  const name = String(card?.name || '').trim()
+  return `${code}::${api}::${name}::${index}`
+}
+
+const normalizeManufacturingActionCards = (actionCards = [], previousCards = []) => {
+  const previousMap = new Map()
+  if (Array.isArray(previousCards)) {
+    previousCards.forEach((card, index) => {
+      previousMap.set(getManufacturingActionCardRuntimeKey(card, index), card)
+    })
+  }
+
+  return (Array.isArray(actionCards) ? actionCards : [])
+    .filter(card => isPlainObject(card))
+    .map((card, index) => {
+      const runtimeKey = getManufacturingActionCardRuntimeKey(card, index)
+      const previousCard = previousMap.get(runtimeKey)
+      const fallbackPayloadText = stringifyStructuredPayload(card.examplePayload, 2)
+      return {
+        ...card,
+        runtimeKey,
+        payloadText: previousCard?.payloadText ?? fallbackPayloadText,
+        executing: Boolean(previousCard?.executing),
+        executed: Boolean(previousCard?.executed),
+        executeResult: previousCard?.executeResult || '',
+        executeError: Boolean(previousCard?.executeError)
+      }
+    })
+}
+
+const buildManufacturingStructuredData = (parsedData, previousData = null) => {
+  const type = String(parsedData?.type || '')
+  if (!manufacturingStructuredTypeSet.has(type)) return null
+
+  const rawData = isPlainObject(parsedData?.data) ? parsedData.data : {}
+  const items = Array.isArray(rawData.items) ? rawData.items.filter(item => isPlainObject(item)) : []
+  const warningItems = type === 'manufacturing_warning' ? normalizeManufacturingWarningItems(items) : []
+  const listItems = manufacturingListTypeSet.has(type) ? items : []
+  const actionCards = type === 'manufacturing_action_plan'
+    ? normalizeManufacturingActionCards(rawData.actionCards, previousData?.actionCards)
+    : []
+
+  return {
+    type,
+    summaryEntries: normalizeManufacturingSummaryEntries(parsedData?.summary),
+    coreMetrics: normalizeManufacturingCoreMetrics(rawData.coreMetrics),
+    listItems,
+    columns: inferManufacturingColumns(listItems),
+    warningItems,
+    actionCards
+  }
+}
+
+const getManufacturingTypeLabel = (type = '') => manufacturingTypeLabelMap[String(type || '')] || '鍒堕�犵粨鏋�'
+
+const getManufacturingWarningLevelType = (level = '') => {
+  const normalizedLevel = String(level || '').toLowerCase()
+  if (normalizedLevel === 'high') return 'danger'
+  if (normalizedLevel === 'medium') return 'warning'
+  return 'info'
+}
+
+const getManufacturingWarningLevelLabel = (level = '') => {
+  const normalizedLevel = String(level || '').toLowerCase()
+  if (normalizedLevel === 'high') return '楂�'
+  if (normalizedLevel === 'medium') return '涓�'
+  return normalizedLevel ? normalizedLevel.toUpperCase() : '涓�鑸�'
+}
+
+const normalizeRequestMethod = (method = 'POST') => {
+  const normalized = String(method || 'POST').trim().toUpperCase()
+  if (['GET', 'POST', 'PUT', 'DELETE', 'PATCH'].includes(normalized)) return normalized
+  return 'POST'
+}
+
+const getNormalizedRequestMethod = (method) => normalizeRequestMethod(method)
+
+const getPayloadValueByPath = (payload, fieldPath = '') => {
+  const normalizedPath = String(fieldPath || '').trim()
+  if (!normalizedPath || !isPlainObject(payload)) return undefined
+
+  const pathSegments = normalizedPath
+    .replace(/\[(\d+)]/g, '.$1')
+    .split('.')
+    .filter(Boolean)
+
+  return pathSegments.reduce((current, segment) => {
+    if (current === null || current === undefined) return undefined
+    if (!['object', 'function'].includes(typeof current)) return undefined
+    return current[segment]
+  }, payload)
+}
+
+const getMissingRequiredFields = (requiredFields = [], payload = {}) => {
+  if (!Array.isArray(requiredFields) || !requiredFields.length) return []
+  return requiredFields.filter((fieldPath) => {
+    const value = getPayloadValueByPath(payload, fieldPath)
+    return !hasMeaningfulPayloadValue(value)
+  })
+}
+
+const parseManufacturingActionPayload = (payloadText = '') => {
+  const text = String(payloadText ?? '').trim()
+  if (!text) return {}
+  return JSON.parse(text)
+}
+
+const executeManufacturingAction = async (message, actionCard, cardIndex = 0) => {
+  if (!message?.manufacturingData || !actionCard || actionCard.executing) return
+
+  const actionName = actionCard.name || `鍔ㄤ綔 ${cardIndex + 1}`
+  const targetApi = String(actionCard.targetApi || '').trim()
+  if (!targetApi) {
+    actionCard.executeError = true
+    actionCard.executeResult = '缂哄皯 targetApi锛屾棤娉曟墽琛屽姩浣�'
+    return
+  }
+
+  let payload = {}
+  try {
+    payload = parseManufacturingActionPayload(actionCard.payloadText)
+  } catch (err) {
+    actionCard.executeError = true
+    actionCard.executeResult = '璇锋眰鍙傛暟涓嶆槸鍚堟硶 JSON锛岃妫�鏌ュ悗閲嶈瘯'
+    return
+  }
+
+  const requiredFields = Array.isArray(actionCard.requiredFields) ? actionCard.requiredFields : []
+  if (requiredFields.length && !isPlainObject(payload)) {
+    actionCard.executeError = true
+    actionCard.executeResult = '蹇呭~瀛楁鏍¢獙澶辫触锛氳姹傚弬鏁板繀椤绘槸 JSON 瀵硅薄'
+    return
+  }
+
+  const missingFields = getMissingRequiredFields(requiredFields, payload)
+  if (missingFields.length) {
+    actionCard.executeError = true
+    const missingFieldLabels = missingFields.map(field => getStructuredPathLabel(field))
+    actionCard.executeResult = `缂哄皯蹇呭~瀛楁锛�${missingFieldLabels.join('銆�')}`
+    return
+  }
+
+  try {
+    await ElMessageBox.confirm(`纭鎵ц銆�${actionName}銆嶅悧锛焋, '鎵ц纭', {
+      confirmButtonText: '纭鎵ц',
+      cancelButtonText: '鍙栨秷',
+      type: 'warning'
+    })
+  } catch (err) {
+    return
+  }
+
+  actionCard.executing = true
+  actionCard.executeError = false
+  actionCard.executeResult = ''
+
+  const method = normalizeRequestMethod(actionCard.method)
+  const requestConfig = {
+    url: targetApi,
+    method: method.toLowerCase()
+  }
+
+  if (method === 'GET') {
+    requestConfig.params = payload
+  } else {
+    requestConfig.data = payload
+  }
+
+  try {
+    const res = await request(requestConfig)
+    const successMsg = res?.msg || `${actionName}鎵ц鎴愬姛`
+    actionCard.executed = true
+    actionCard.executeError = false
+    actionCard.executeResult = successMsg
+    ElMessage.success(successMsg)
+  } catch (err) {
+    actionCard.executed = false
+    actionCard.executeError = true
+    actionCard.executeResult = err?.message || `${actionName}鎵ц澶辫触锛岃绋嶅悗閲嶈瘯`
+  } finally {
+    actionCard.executing = false
+  }
 }
 
 // 鍘嗗彶浼氳瘽鐩稿叧
@@ -1034,6 +1579,8 @@
           tableData: null,
           payloadTreeData: null,
           payloadHiddenData: null,
+          purchaseAnalysisData: null,
+          manufacturingData: null,
           localUploadFiles: isUser ? mapHistoryFilePathsToSnapshots(msg.filePaths, uuid.value, idx) : []
         }
 
@@ -1273,15 +1820,25 @@
 const applyStructuredMessageData = (messageObj, parsedData, msgIndex, shouldRenderCharts = true) => {
   if (!messageObj || !parsedData?.success) return
 
+  const previousManufacturingData = messageObj.manufacturingData
   messageObj.type = parsedData.type || ''
+  messageObj.tableData = null
+  messageObj.purchaseAnalysisData = null
+  messageObj.manufacturingData = null
 
   if (messageObj.type === 'todo_list' && parsedData.data) {
     messageObj.tableData = parsedData.data
   }
 
+  const manufacturingData = buildManufacturingStructuredData(parsedData, previousManufacturingData)
+  if (manufacturingData) {
+    messageObj.manufacturingData = manufacturingData
+  }
+
   if (parsedData.action === 'confirm_required' && parsedData.businessType) {
     messageObj.type = 'purchase_analysis_confirm'
     messageObj.purchaseAnalysisData = parsedData
+    messageObj.manufacturingData = null
     if (!Array.isArray(messageObj.payloadTreeData) || !messageObj.payloadTreeData.length) {
       initializePurchasePayloadTree(messageObj, parsedData.payload || {})
     }
@@ -1321,6 +1878,19 @@
   }
 
   return null
+}
+
+const getStructuredFallbackText = (parsedData) => {
+  if (!parsedData) return '姝e湪涓烘偍灞曠ず鍒嗘瀽缁撴灉...'
+  if (parsedData.type === 'todo_list') return '宸蹭负鎮ㄦ暣鐞嗗ソ鐩稿叧鏁版嵁銆�'
+  if (manufacturingStructuredTypeSet.has(parsedData.type)) {
+    if (parsedData.type === 'manufacturing_action_plan') return '宸蹭负鎮ㄧ敓鎴愬姙鐞嗗缓璁紝璇风‘璁ゅ姩浣滃悗鎵ц銆�'
+    if (parsedData.type === 'manufacturing_warning') return '宸蹭负鎮ㄧ敓鎴愬埗閫犻璀︾湅鏉裤��'
+    if (parsedData.type === 'manufacturing_analysis') return '宸蹭负鎮ㄧ敓鎴愬埗閫犲垎鏋愮粨鏋溿��'
+    return '宸茶繑鍥炲埗閫犳煡璇㈢粨鏋溿��'
+  }
+  if (parsedData.charts && Object.keys(parsedData.charts).length > 0) return '宸蹭负鎮ㄧ敓鎴愬垎鏋愬浘琛ㄣ��'
+  return '姝e湪涓烘偍灞曠ず鍒嗘瀽缁撴灉...'
 }
 
 const buildPurchaseMaterialRankCharts = (parsedData) => {
@@ -2446,7 +3016,9 @@
     type: '',
     tableData: null,
     payloadTreeData: null,
-    payloadHiddenData: null
+    payloadHiddenData: null,
+    purchaseAnalysisData: null,
+    manufacturingData: null
   })
 
   outputState.value[botMsgIndex] = {
@@ -2569,7 +3141,9 @@
     type: '',
     tableData: null,
     payloadTreeData: null,
-    payloadHiddenData: null
+    payloadHiddenData: null,
+    purchaseAnalysisData: null,
+    manufacturingData: null
   }
   messages.value.push(botMsg)
 
@@ -2735,13 +3309,7 @@
     }
 
     if (!display) {
-      if (parsed.type === 'todo_list') {
-        display = '宸蹭负鎮ㄦ暣鐞嗗ソ鐩稿叧鏁版嵁銆�'
-      } else if (parsed.charts && Object.keys(parsed.charts).length > 0) {
-        display = '宸蹭负鎮ㄧ敓鎴愬垎鏋愬浘琛ㄣ��'
-      } else {
-        display = '姝e湪涓烘偍灞曠ず鍒嗘瀽缁撴灉...'
-      }
+      display = getStructuredFallbackText(parsed)
     }
   } else if (startIdx !== -1) {
     const lastBraceIdx = output.lastIndexOf('}')
@@ -2763,13 +3331,7 @@
         }
 
         if (!display) {
-          if (parsed.type === 'todo_list') {
-            display = '宸蹭负鎮ㄦ暣鐞嗗ソ鐩稿叧鏁版嵁锛�'
-          } else if (parsed.charts && Object.keys(parsed.charts).length > 0) {
-            display = '宸蹭负鎮ㄧ敓鎴愬垎鏋愬浘琛細'
-          } else {
-            display = '姝e湪涓烘偍灞曠ず鍒嗘瀽缁撴灉...'
-          }
+          display = getStructuredFallbackText(parsed)
         }
       } catch (e) {
         // 瑙f瀽澶辫触锛岃鏄� JSON 杩樺湪浼犺緭涓垨鏍煎紡涓嶆纭�
@@ -3792,6 +4354,171 @@
   }
 }
 
+.manufacturing-card {
+  margin-top: 12px;
+  width: 100%;
+  background: #fff;
+  border: 1px solid rgba(0, 85, 212, 0.12);
+  border-radius: 12px;
+  box-shadow: $shadow-card;
+  padding: 14px;
+}
+
+.manufacturing-card__title {
+  font-size: 14px;
+  font-weight: 700;
+  color: $deep-blue;
+  margin-bottom: 10px;
+}
+
+.manufacturing-summary-grid {
+  display: grid;
+  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
+  gap: 8px;
+  margin-bottom: 12px;
+}
+
+.manufacturing-summary-item {
+  border-radius: 10px;
+  padding: 10px 12px;
+  border: 1px solid rgba(0, 85, 212, 0.08);
+  background: linear-gradient(180deg, #f8fbff, #f1f7ff);
+  min-height: 66px;
+  display: flex;
+  flex-direction: column;
+  justify-content: space-between;
+  gap: 6px;
+}
+
+.manufacturing-summary-item--core {
+  border-color: rgba(30, 91, 255, 0.24);
+}
+
+.manufacturing-summary-label {
+  font-size: 12px;
+  color: #4b5563;
+}
+
+.manufacturing-summary-value {
+  font-size: 15px;
+  color: #1f2937;
+  line-height: 1.4;
+  word-break: break-all;
+}
+
+.manufacturing-warning-list {
+  display: flex;
+  flex-direction: column;
+  gap: 8px;
+  margin-bottom: 12px;
+}
+
+.manufacturing-warning-item {
+  border-radius: 10px;
+  border: 1px solid rgba(245, 158, 11, 0.22);
+  background: linear-gradient(135deg, rgba(255, 247, 237, 0.9), rgba(255, 255, 255, 0.98));
+  padding: 10px 12px;
+}
+
+.manufacturing-warning-item__head {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+  color: #92400e;
+  font-size: 13px;
+}
+
+.manufacturing-warning-count {
+  margin-left: auto;
+  font-weight: 700;
+  color: #c2410c;
+}
+
+.manufacturing-warning-detail {
+  margin: 8px 0 0;
+  font-size: 12px;
+  line-height: 1.6;
+  color: #7c2d12;
+  word-break: break-all;
+}
+
+.manufacturing-table-wrapper {
+  margin-top: 10px;
+}
+
+.manufacturing-action-list {
+  display: flex;
+  flex-direction: column;
+  gap: 10px;
+  margin-top: 12px;
+}
+
+.manufacturing-action-card {
+  border: 1px solid rgba(0, 85, 212, 0.1);
+  border-radius: 10px;
+  padding: 10px 12px;
+  background: #f8fbff;
+}
+
+.manufacturing-action-card__head {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  gap: 12px;
+  font-size: 13px;
+  color: #1f2937;
+  margin-bottom: 8px;
+}
+
+.manufacturing-action-card__meta {
+  display: flex;
+  flex-direction: column;
+  gap: 4px;
+  margin-bottom: 8px;
+  font-size: 12px;
+  color: #64748b;
+  word-break: break-all;
+}
+
+.manufacturing-action-card__desc {
+  margin: 0 0 8px;
+  font-size: 12px;
+  line-height: 1.6;
+  color: #475467;
+}
+
+.manufacturing-required-fields {
+  display: flex;
+  flex-wrap: wrap;
+  align-items: center;
+  gap: 6px;
+  margin-bottom: 8px;
+  font-size: 12px;
+  color: #7c2d12;
+}
+
+.manufacturing-action-footer {
+  margin-top: 8px;
+  display: flex;
+  align-items: center;
+  justify-content: flex-end;
+  gap: 12px;
+}
+
+.manufacturing-action-result {
+  flex: 1;
+  font-size: 12px;
+  line-height: 1.5;
+
+  &.success {
+    color: #1f9d55;
+  }
+
+  &.error {
+    color: #d93025;
+  }
+}
+
 .purchase-confirm-card {
   margin-top: 12px;
   width: 100%;
diff --git a/src/components/ProcessParamListDialog.vue b/src/components/ProcessParamListDialog.vue
index 38e892d..deee249 100644
--- a/src/components/ProcessParamListDialog.vue
+++ b/src/components/ProcessParamListDialog.vue
@@ -130,6 +130,7 @@
             </el-form-item>
             <el-form-item label="鏍囧噯鍊�">
               <el-input v-model="selectedParam.standardValue"
+                        @input="val => onStandardValueInput(val, selectedParam)"
                         placeholder="璇疯緭鍏ラ粯璁ゅ��" />
             </el-form-item>
             <el-form-item label="鏄惁蹇呭~">
@@ -144,7 +145,8 @@
         </div>
       </div>
       <template #footer>
-        <el-button type="primary" @click="handleParamSelectSubmit">纭畾</el-button>
+        <el-button type="primary"
+                   @click="handleParamSelectSubmit">纭畾</el-button>
         <el-button @click="selectParamDialogVisible = false">鍙栨秷</el-button>
       </template>
     </el-dialog>
@@ -174,11 +176,13 @@
         <el-form-item label="鏍囧噯鍊�"
                       prop="standardValue">
           <el-input v-model="editParamForm.standardValue"
+                    @input="val => onStandardValueInput(val, editParamForm)"
                     placeholder="璇疯緭鍏ユ爣鍑嗗��" />
         </el-form-item>
       </el-form>
       <template #footer>
-        <el-button type="primary" @click="handleEditParamSubmit">纭畾</el-button>
+        <el-button type="primary"
+                   @click="handleEditParamSubmit">纭畾</el-button>
         <el-button @click="editParamDialogVisible = false">鍙栨秷</el-button>
       </template>
     </el-dialog>
@@ -266,8 +270,32 @@
     paramFormat: "",
     unit: "",
   });
+
+  const onStandardValueInput = (val, target) => {
+    const data = target.value || target;
+    const type = data.paramType || data.parameterType;
+    if (type === 1) {
+      // 鏁板�兼牸寮忥細涓嶈兘杈撳叆涓枃鎴栬嫳鏂囧瓧绗�
+      data.standardValue = val.replace(/[a-zA-Z\u4e00-\u9fa5]/g, "");
+    }
+  };
+
   const editParamRules = ref({
-    // standardValue: [{ required: true, message: "璇疯緭鍏ユ爣鍑嗗��", trigger: "blur" }],
+    standardValue: [
+      {
+        validator: (rule, value, callback) => {
+          const type =
+            editParamForm.value.paramType || editParamForm.value.parameterType;
+          if (type === 1 && value) {
+            if (/[a-zA-Z\u4e00-\u9fa5]/.test(value)) {
+              return callback(new Error("鏁板�兼牸寮忎笉鑳藉寘鍚腑鑻辨枃瀛楃"));
+            }
+          }
+          callback();
+        },
+        trigger: "blur",
+      },
+    ],
   });
   const editParamFormRef = ref(null);
 
diff --git a/src/views/aiIndustrialBrain/MAINTAIN_RULES.md b/src/views/aiIndustrialBrain/MAINTAIN_RULES.md
new file mode 100644
index 0000000..97b9a5c
--- /dev/null
+++ b/src/views/aiIndustrialBrain/MAINTAIN_RULES.md
@@ -0,0 +1,7 @@
+# AI宸ヤ笟澶ц剳缁存姢瑙勫垯
+
+1. 褰� `src/views/aiIndustrialBrain/index.vue` 鏂板鏅鸿兘浣擄紙`agents`锛夐�昏緫鏃讹紝蹇呴』鍚屾纭寮圭獥鍔╂墜鍙敤鎬с��
+2. 寮圭獥鍔╂墜鐢� `src/components/AIChatSidebar/assistants/index.js` 鐨� `assistantRegistry` 缁熶竴娉ㄥ唽銆�
+3. 鏂板鏅鸿兘浣撶殑 `key` 鑻ヨ鍦ㄥ脊绐椾腑鍙敤锛屽繀椤诲湪 `assistantRegistry` 涓彁渚涘悓鍚嶉厤缃��
+4. 鏈湪 `assistantRegistry` 娉ㄥ唽鐨勬櫤鑳戒綋浼氬湪寮圭獥涓樉绀轰负 `pending`锛堝紑鍙戜腑锛夋�併��
+
diff --git a/src/views/aiIndustrialBrain/components/AiAssistantWorkspace.vue b/src/views/aiIndustrialBrain/components/AiAssistantWorkspace.vue
index 2f55511..1eb5e7b 100644
--- a/src/views/aiIndustrialBrain/components/AiAssistantWorkspace.vue
+++ b/src/views/aiIndustrialBrain/components/AiAssistantWorkspace.vue
@@ -17,7 +17,7 @@
             v-if="assistantMode !== 'pending'"
             :key="assistantMode"
             class="workspace-chat"
-            :assistants="assistantMode === 'purchase' ? [purchaseAssistant] : [generalAssistant]"
+            :assistants="resolvedAssistants"
             :default-assistant="assistantMode"
             :hide-trigger="true"
             :auto-open="true"
@@ -43,7 +43,7 @@
 import { computed } from "vue";
 import { ArrowLeftBold } from "@element-plus/icons-vue";
 import AIChatSidebar from "@/components/AIChatSidebar/index.vue";
-import { generalAssistant, purchaseAssistant } from "@/components/AIChatSidebar/assistants";
+import { assistantRegistry } from "@/components/AIChatSidebar/assistants";
 
 const props = defineProps({
   visible: {
@@ -60,11 +60,17 @@
 
 const agentKey = computed(() => String(props.agent?.key || ""));
 const agentTitle = computed(() => String(props.agent?.name || "AI鍔╂墜"));
+
+/**
+ * 缁存姢瑙勫垯锛�
+ * AI宸ヤ笟澶ц剳鏂板鏅鸿兘浣撴椂锛岃嫢甯屾湜鍙充晶寮圭獥鍙敤锛岄渶淇濊瘉鏅鸿兘浣� key 鍦� assistantRegistry 涓湁鍚屽悕閰嶇疆銆�
+ * 鏈厤缃椂浼氳繘鍏� pending锛堝紑鍙戜腑锛夋�侊紝浣滀负鏄惧紡鎻愰啋銆�
+ */
+const resolvedAssistant = computed(() => assistantRegistry[agentKey.value] || null);
 const assistantMode = computed(() => {
-  if (agentKey.value === "purchase") return "purchase";
-  if (agentKey.value === "general") return "general";
-  return "pending";
+  return resolvedAssistant.value ? agentKey.value : "pending";
 });
+const resolvedAssistants = computed(() => (resolvedAssistant.value ? [resolvedAssistant.value] : []));
 </script>
 
 <style scoped>
diff --git a/src/views/aiIndustrialBrain/index.vue b/src/views/aiIndustrialBrain/index.vue
index 33b967d..4afafa5 100644
--- a/src/views/aiIndustrialBrain/index.vue
+++ b/src/views/aiIndustrialBrain/index.vue
@@ -154,6 +154,7 @@
 
 const router = useRouter();
 
+// 缁存姢绾﹀畾瑙侊細src/views/aiIndustrialBrain/MAINTAIN_RULES.md
 const agents = [
   {
     key: "general",
diff --git a/src/views/basicData/product/index.vue b/src/views/basicData/product/index.vue
index 07da49b..b05b215 100644
--- a/src/views/basicData/product/index.vue
+++ b/src/views/basicData/product/index.vue
@@ -5,7 +5,7 @@
         <el-input v-model="search"
                   style="width: 210px"
                   placeholder="杈撳叆鍏抽敭瀛楄繘琛屾悳绱�"
-                  @change="searchFilter"
+                  @input="debouncedSearch"
                   @clear="searchFilter"
                   clearable
                   prefix-icon="Search" />
@@ -565,40 +565,31 @@
         proxy.$modal.msg("宸插彇娑�");
       });
   };
-  // 璋冪敤tree杩囨护鏂规硶 涓枃鑻辫繃婊�
-  const filterNode = (value, data, node) => {
-    if (!value) {
-      //濡傛灉鏁版嵁涓虹┖锛屽垯杩斿洖true,鏄剧ず鎵�鏈夌殑鏁版嵁椤�
-      return true;
-    }
-    // 鏌ヨ鍒楄〃鏄惁鏈夊尮閰嶆暟鎹紝灏嗗�煎皬鍐欙紝鍖归厤鑻辨枃鏁版嵁
-    let val = value.toLowerCase();
-    return chooseNode(val, data, node); // 璋冪敤杩囨护浜屽眰鏂规硶
+  const debounce = (fn, delay = 300) => {
+    let timer;
+    return (...args) => {
+      clearTimeout(timer);
+      timer = setTimeout(() => fn(...args), delay);
+    };
   };
-  // 杩囨护鐖惰妭鐐� / 瀛愯妭鐐� (濡傛灉杈撳叆鐨勫弬鏁版槸鐖惰妭鐐逛笖鑳藉尮閰嶏紝鍒欒繑鍥炶鑺傜偣浠ュ強鍏朵笅鐨勬墍鏈夊瓙鑺傜偣锛涘鏋滃弬鏁版槸瀛愯妭鐐癸紝鍒欒繑鍥炶鑺傜偣鐨勭埗鑺傜偣銆俷ame鏄腑鏂囧瓧绗︼紝enName鏄嫳鏂囧瓧绗�.
-  const chooseNode = (value, data, node) => {
-    if (data.label.indexOf(value) !== -1) {
+
+  const debouncedSearch = debounce(() => {
+    searchFilter();
+  }, 300);
+
+  const filterNode = (value, data) => {
+    if (!value) return true;
+    return chooseNode(value.toLowerCase(), data);
+  };
+
+  const chooseNode = (value, data) => {
+    const label = (data.label || '').toLowerCase();
+    if (label.indexOf(value) !== -1) {
       return true;
     }
-    const level = node.level;
-    // 濡傛灉浼犲叆鐨勮妭鐐规湰韬氨鏄竴绾ц妭鐐瑰氨涓嶇敤鏍¢獙浜�
-    if (level === 1) {
-      return false;
+    if (data.children && data.children.length > 0) {
+      return data.children.some(child => chooseNode(value, child));
     }
-    // 鍏堝彇褰撳墠鑺傜偣鐨勭埗鑺傜偣
-    let parentData = node.parent;
-    // 閬嶅巻褰撳墠鑺傜偣鐨勭埗鑺傜偣
-    let index = 0;
-    while (index < level - 1) {
-      // 濡傛灉鍖归厤鍒扮洿鎺ヨ繑鍥烇紝姝ゅname鍊兼槸涓枃瀛楃锛宔nName鏄嫳鏂囧瓧绗︺�傚垽鏂尮閰嶄腑鑻辨枃杩囨护
-      if (parentData.data.label.indexOf(value) !== -1) {
-        return true;
-      }
-      // 鍚﹀垯鐨勮瘽鍐嶅線涓婁竴灞傚仛鍖归厤
-      parentData = parentData.parent;
-      index++;
-    }
-    // 娌″尮閰嶅埌杩斿洖false
     return false;
   };
   getProductTreeList();
diff --git a/src/views/basicData/supplierManage/components/BlacklistTab.vue b/src/views/basicData/supplierManage/components/BlacklistTab.vue
index 8f6204b..206ba62 100644
--- a/src/views/basicData/supplierManage/components/BlacklistTab.vue
+++ b/src/views/basicData/supplierManage/components/BlacklistTab.vue
@@ -231,7 +231,10 @@
         </div>
       </template>
     </el-dialog>
-    <files-dia ref="filesDia"></files-dia>
+    <FileList v-if="fileListDialogVisible"
+              v-model:visible="fileListDialogVisible"
+              record-type="supplier_manage"
+              :record-id="recordId" />
   </div>
 </template>
 
@@ -249,7 +252,9 @@
 } from "@/api/basicData/supplierManageFile.js";
 import useUserStore from "@/store/modules/user";
 import { getToken } from "@/utils/auth.js";
-import FilesDia from "../filesDia.vue";
+const FileList = defineAsyncComponent(() =>
+    import("@/components/Dialog/FileList.vue")
+);
 const { proxy } = getCurrentInstance();
 const userStore = useUserStore();
 
@@ -327,7 +332,7 @@
         name: "璧勮川鏂囦欢",
         type: "text",
         clickFun: (row) => {
-          openFilesFormDia(row)
+          openFileDialog(row)
         }
       }
     ],
@@ -342,7 +347,8 @@
   size: 100,
   total: 0,
 });
-const filesDia = ref()
+const fileListDialogVisible = ref(false);
+const recordId = ref();
 // 鐢ㄦ埛淇℃伅琛ㄥ崟寮规鏁版嵁
 const operationType = ref("");
 const dialogFormVisible = ref(false);
@@ -567,10 +573,9 @@
   return `${year}-${month}-${day}`;
 }
 // 鎵撳紑闄勪欢寮规
-const openFilesFormDia = (row) => {
-  nextTick(() => {
-    filesDia.value?.openDialog(row)
-  })
+const openFileDialog = async row => {
+  recordId.value = row.id;
+  fileListDialogVisible.value = true;
 };
 
 onMounted(() => {
diff --git a/src/views/basicData/supplierManage/components/HomeTab.vue b/src/views/basicData/supplierManage/components/HomeTab.vue
index 47dce00..da62ca4 100644
--- a/src/views/basicData/supplierManage/components/HomeTab.vue
+++ b/src/views/basicData/supplierManage/components/HomeTab.vue
@@ -237,7 +237,10 @@
         </div>
       </template>
     </el-dialog>
-    <files-dia ref="filesDia"></files-dia>
+    <FileList v-if="fileListDialogVisible"
+              v-model:visible="fileListDialogVisible"
+              record-type="supplier_manage"
+              :record-id="recordId" />
   </div>
 </template>
 
@@ -255,7 +258,9 @@
 } from "@/api/basicData/supplierManageFile.js";
 import useUserStore from "@/store/modules/user";
 import { getToken } from "@/utils/auth.js";
-import FilesDia from "../filesDia.vue";
+const FileList = defineAsyncComponent(() =>
+    import("@/components/Dialog/FileList.vue")
+);
 const { proxy } = getCurrentInstance();
 const userStore = useUserStore();
 
@@ -333,7 +338,7 @@
         name: "璧勮川鏂囦欢",
         type: "text",
         clickFun: (row) => {
-          openFilesFormDia(row)
+          openFileDialog(row)
         }
       }
     ],
@@ -343,12 +348,13 @@
 const selectedRows = ref([]);
 const userList = ref([]);
 const tableLoading = ref(false);
+const fileListDialogVisible = ref(false);
+const recordId = ref();
 const page = reactive({
   current: 1,
   size: 100,
   total: 0,
 });
-const filesDia = ref()
 // 鐢ㄦ埛淇℃伅琛ㄥ崟寮规鏁版嵁
 const operationType = ref("");
 const dialogFormVisible = ref(false);
@@ -573,10 +579,9 @@
   return `${year}-${month}-${day}`;
 }
 // 鎵撳紑闄勪欢寮规
-const openFilesFormDia = (row) => {
-  nextTick(() => {
-    filesDia.value?.openDialog(row)
-  })
+const openFileDialog = async row => {
+  recordId.value = row.id;
+  fileListDialogVisible.value = true;
 };
 
 onMounted(() => {
diff --git a/src/views/collaborativeApproval/approvalProcess/components/infoFormDia.vue b/src/views/collaborativeApproval/approvalProcess/components/infoFormDia.vue
index 6461b2d..5bd7a3e 100644
--- a/src/views/collaborativeApproval/approvalProcess/components/infoFormDia.vue
+++ b/src/views/collaborativeApproval/approvalProcess/components/infoFormDia.vue
@@ -152,7 +152,8 @@
     startDate: "", // 璇峰亣寮�濮嬫椂闂�
     endDate: "", // 璇峰亣缁撴潫鏃堕棿
     price: null, // 鎶ラ攢閲戦
-    location: "" // 鍑哄樊鍦扮偣
+    location: "", // 鍑哄樊鍦扮偣
+    storageBlobDTOS: []
   },
   rules: {
     approveId: [{ required: false, message: "璇疯緭鍏�", trigger: "blur" }],
@@ -270,7 +271,7 @@
       return
     }
   }
-  form.value.storageBlobDTOList = fileList.value
+  form.value.storageBlobDTOS = fileList.value
 
   proxy.$refs.formRef.validate(valid => {
     if (valid) {
diff --git a/src/views/collaborativeApproval/approvalProcess/index.vue b/src/views/collaborativeApproval/approvalProcess/index.vue
index dba6bc1..11a2869 100644
--- a/src/views/collaborativeApproval/approvalProcess/index.vue
+++ b/src/views/collaborativeApproval/approvalProcess/index.vue
@@ -126,20 +126,23 @@
     <!-- 寮圭獥缁勪欢 -->
     <info-form-dia ref="infoFormDia" @close="handleQuery" :approveType="currentApproveType"></info-form-dia>
     <approval-dia ref="approvalDia" @close="handleQuery" :approveType="currentApproveType"></approval-dia>
-    <FileList ref="fileListRef" />
+    <FileList v-if="fileDialogVisible"
+              v-model:visible="fileDialogVisible"
+              record-type="approve_process"
+              :record-id="recordId" />
   </div>
 </template>
 
 <script setup>
-import FileList from "./fileList.vue";
 import { Search, Plus, Delete, Download, RefreshRight, DocumentChecked } from "@element-plus/icons-vue";
-import {onMounted, ref, computed, reactive, toRefs, nextTick, getCurrentInstance} from "vue";
+import {onMounted, ref, computed, reactive, toRefs, nextTick, getCurrentInstance, defineAsyncComponent} from "vue";
 import {ElMessageBox} from "element-plus";
 import { useRoute } from 'vue-router';
 import InfoFormDia from "@/views/collaborativeApproval/approvalProcess/components/infoFormDia.vue";
 import ApprovalDia from "@/views/collaborativeApproval/approvalProcess/components/approvalDia.vue";
 import {approveProcessDelete, approveProcessListPage} from "@/api/collaborativeApproval/approvalProcess.js";
 import useUserStore from "@/store/modules/user";
+const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue"));
 
 const userStore = useUserStore();
 const route = useRoute();
@@ -337,7 +340,7 @@
       name: "闄勪欢",
       type: "text",
       clickFun: (row) => {
-        downLoadFile(row);
+        openFilesFormDia(row);
       },
     });
   }
@@ -371,11 +374,17 @@
   page.current = 1;
   getList();
 };
-const fileListRef = ref(null)
-const downLoadFile = (row) => {
-  fileListRef.value.open(row.commonFileList)
 
+// 鎵撳紑闄勪欢寮圭獥
+const recordId =ref(0)
+const fileDialogVisible = ref(false)
+
+// 鎵撳紑闄勪欢寮规
+const openFilesFormDia = async (row) => {
+  recordId.value = row.id
+  fileDialogVisible.value = true
 }
+
 const pagination = (obj) => {
   page.current = obj.page;
   page.size = obj.limit;
diff --git a/src/views/collaborativeApproval/sealManagement/index.vue b/src/views/collaborativeApproval/sealManagement/index.vue
index a6232c2..9d68848 100644
--- a/src/views/collaborativeApproval/sealManagement/index.vue
+++ b/src/views/collaborativeApproval/sealManagement/index.vue
@@ -87,10 +87,18 @@
         </el-form-item>
         <el-form-item label="绱ф�ョ▼搴�" prop="urgency">
           <el-radio-group v-model="sealForm.urgency">
-            <el-radio label="normal">鏅��</el-radio>
-            <el-radio label="urgent">绱ф��</el-radio>
-            <el-radio label="very-urgent">鐗规��</el-radio>
+            <el-radio value="normal">鏅��</el-radio>
+            <el-radio value="urgent">绱ф��</el-radio>
+            <el-radio value="very-urgent">鐗规��</el-radio>
           </el-radio-group>
+        </el-form-item>
+        <el-form-item label="闄勪欢涓婁紶">
+          <AttachmentUploadFile
+            v-model:fileList="sealForm.storageBlobDTOs"
+            :limit="10"
+            :fileSize="50"
+            buttonText="鐐瑰嚮涓婁紶闄勪欢"
+          />
         </el-form-item>
       </el-form>
     </FormDialog>
@@ -119,8 +127,27 @@
           </el-descriptions-item>
           <el-descriptions-item label="鐢宠鍘熷洜" :span="2">{{ currentSealDetail.reason }}</el-descriptions-item>
         </el-descriptions>
+        <!-- 闄勪欢鍒楄〃 -->
+        <div v-if="currentSealDetail.storageBlobVOList?.length || currentSealDetail.storageBlobDTOs?.length" class="attachment-section">
+          <div class="attachment-title">闄勪欢鍒楄〃锛�</div>
+          <el-table :data="currentSealDetail.storageBlobVOList || currentSealDetail.storageBlobDTOs" border class="attachment-table">
+            <el-table-column label="闄勪欢鍚嶇О" show-overflow-tooltip>
+              <template #default="scope">
+                {{ scope.row.originalFilename || scope.row.name || scope.row.fileName || '鏈懡鍚嶆枃浠�' }}
+              </template>
+            </el-table-column>
+            <el-table-column fixed="right" label="鎿嶄綔" width="150" align="center">
+              <template #default="scope">
+                <el-button link type="primary" size="small" @click="previewFile(scope.row)">棰勮</el-button>
+                <el-button link type="primary" size="small" @click="downloadFile(scope.row)">涓嬭浇</el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </div>
       </div>
     </FormDialog>
+    <!-- 鏂囦欢棰勮缁勪欢 -->
+    <FilePreview ref="filePreviewRef" />
 
   </div>
 </template>
@@ -134,6 +161,9 @@
 import useUserStore from '@/store/modules/user'
 import FormDialog from '@/components/Dialog/FormDialog.vue'
 import PIMTable from '@/components/PIMTable/PIMTable.vue'
+import AttachmentUploadFile from '@/components/AttachmentUpload/file/index.vue'
+import FilePreview from '@/components/filePreview/index.vue'
+import download from '@/plugins/download.js'
 
 // 鍝嶅簲寮忔暟鎹�
 // 鐢ㄥ嵃鐢宠鐩稿叧
@@ -143,6 +173,7 @@
 const tableLoading = ref(false)
 const showSealDetailDialog = ref(false)
 const currentSealDetail = ref(null)
+const filePreviewRef = ref(null)
 const sealFormRef = ref()
 const userList = ref([])
 const sealForm = reactive({
@@ -152,7 +183,8 @@
   reason: '',
   approveUserId: '',
   urgency: 'normal',
-  status: 'pending'
+  status: 'pending',
+  storageBlobDTOs: []
 })
 
 const sealRules = {
@@ -281,7 +313,8 @@
         reason: '',
         approveUserId: '',
         urgency: 'normal',
-        status: 'pending'
+        status: 'pending',
+        storageBlobDTOs: []
       })
       }
     }).catch(err => {
@@ -301,7 +334,8 @@
     reason: '',
     approveUserId: '',
     urgency: 'normal',
-    status: 'pending'
+    status: 'pending',
+    storageBlobDTOs: []
   })
   // 娓呴櫎琛ㄥ崟楠岃瘉鐘舵��
   if (sealFormRef.value) {
@@ -318,6 +352,27 @@
 const viewSealDetail = (row) => {
   currentSealDetail.value = row
   showSealDetailDialog.value = true
+}
+
+// 棰勮鏂囦欢
+const previewFile = (row) => {
+  const url = row.previewURL || row.previewUrl || row.url
+  if (url && filePreviewRef.value) {
+    filePreviewRef.value.open(url)
+  } else {
+    ElMessage.warning('鏂囦欢鍦板潃鏃犳晥锛屾棤娉曢瑙�')
+  }
+}
+
+// 涓嬭浇鏂囦欢
+const downloadFile = (row) => {
+  const url = row.downloadURL || row.downloadUrl || row.url
+  if (url) {
+    const filename = row.originalFilename || row.name || row.fileName || 'download'
+    download.byUrl(url, filename)
+  } else {
+    ElMessage.warning('鏂囦欢鍦板潃鏃犳晥锛屾棤娉曚笅杞�')
+  }
 }
 // 瀹℃壒鐢ㄥ嵃鐢宠
 const approveSeal = (row) => {
@@ -421,4 +476,19 @@
 .ml-10 {
   margin-left: 10px;
 }
+
+.attachment-section {
+  margin-top: 20px;
+}
+
+.attachment-title {
+  font-size: 14px;
+  color: #606266;
+  margin-bottom: 10px;
+  font-weight: 500;
+}
+
+.attachment-table {
+  border-radius: 4px;
+}
 </style>
diff --git a/src/views/equipmentManagement/inspectionManagement/components/formDia.vue b/src/views/equipmentManagement/inspectionManagement/components/formDia.vue
index 9f509b1..3e7f1ca 100644
--- a/src/views/equipmentManagement/inspectionManagement/components/formDia.vue
+++ b/src/views/equipmentManagement/inspectionManagement/components/formDia.vue
@@ -26,6 +26,21 @@
         </el-row>
         <el-row>
           <el-col :span="12">
+            <el-form-item label="宸℃椤圭洰" prop="inspectionProject">
+              <el-input v-model="form.inspectionProject" placeholder="璇疯緭鍏ュ贰妫�椤圭洰" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鏄惁鍚敤" prop="isEnabled">
+              <el-radio-group v-model="form.isEnabled">
+                <el-radio :value="1">鏄�</el-radio>
+                <el-radio :value="0">鍚�</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
             <el-form-item label="澶囨敞" prop="remarks">
               <el-input v-model="form.remarks" placeholder="璇疯緭鍏ュ娉�" type="textarea" />
             </el-form-item>
@@ -118,6 +133,8 @@
     taskName: undefined,
     inspector: '',
     inspectorIds: '',
+    inspectionProject: '',
+    isEnabled: 1,
     remarks: '',
     frequencyType: '',
     frequencyDetail: '',
@@ -245,6 +262,8 @@
     taskName: undefined,
     inspector: '',
     inspectorIds: '',
+    inspectionProject: '',
+    isEnabled: 1,
     remarks: '',
     frequencyType: '',
     frequencyDetail: '',
diff --git a/src/views/equipmentManagement/inspectionManagement/index.vue b/src/views/equipmentManagement/inspectionManagement/index.vue
index 35f82d5..44103ac 100644
--- a/src/views/equipmentManagement/inspectionManagement/index.vue
+++ b/src/views/equipmentManagement/inspectionManagement/index.vue
@@ -70,6 +70,11 @@
                     class="no-data">--</span>
             </div>
           </template>
+          <template #isEnabled="{ row }">
+            <el-tag :type="row.isEnabled === 1 ? 'success' : 'danger'" size="small">
+              {{ row.isEnabled == 1 ? '鏄�' : '鍚�' }}
+            </el-tag>
+          </template>
         </PIMTable>
       </div>
     </el-card>
@@ -126,8 +131,16 @@
   // 鍒楅厤缃�
   const columns = ref([
     { prop: "taskName", label: "宸℃浠诲姟鍚嶇О", minWidth: 160 },
+    { prop: "inspectionProject", label: "宸℃椤圭洰", minWidth: 150 },
     { prop: "remarks", label: "澶囨敞", minWidth: 150 },
     { prop: "inspector", label: "鎵ц宸℃浜�", minWidth: 150, slot: "inspector" },
+    {
+      prop: "isEnabled",
+      label: "鏄惁鍚敤",
+      minWidth: 100,
+      dataType: "slot",
+      slot: "isEnabled"
+    },
     {
       prop: "frequencyType",
       label: "棰戞",
@@ -227,8 +240,10 @@
       operationsArr.value = ["edit"];
     } else if (value === "task") {
       const operationColumn = getOperationColumn(["viewFile"]);
+      // 瀹氭椂浠诲姟璁板綍涓嶅睍绀�"鏄惁鍚敤"鍒�
+      const taskColumns = columns.value.filter(col => col.prop !== "isEnabled");
       tableColumns.value = [
-        ...columns.value,
+        ...taskColumns,
         ...(operationColumn ? [operationColumn] : []),
       ];
       operationsArr.value = ["viewFile"];
diff --git a/src/views/equipmentManagement/measurementEquipment/components/formDia.vue b/src/views/equipmentManagement/measurementEquipment/components/formDia.vue
index 6b7feec..16ac41f 100644
--- a/src/views/equipmentManagement/measurementEquipment/components/formDia.vue
+++ b/src/views/equipmentManagement/measurementEquipment/components/formDia.vue
@@ -36,15 +36,6 @@
 				</el-row>
 				<el-row :gutter="30">
 					<el-col :span="12">
-						<el-form-item label="瀹夎浣嶇疆锛�" prop="instationLocation">
-							<el-input
-								v-model="form.instationLocation"
-								placeholder="璇疯緭鍏�"
-								clearable
-							/>
-						</el-form-item>
-					</el-col>
-					<el-col :span="12">
 						<el-form-item label="妫�瀹氬崟浣嶏細" prop="unit">
               <el-input
                   v-model="form.unit"
@@ -53,17 +44,17 @@
               />
 						</el-form-item>
 					</el-col>
-				</el-row>
-        <el-row :gutter="30">
-          <el-col :span="12">
-            <el-form-item label="璇佷功缂栧彿锛�" prop="model">
+					<el-col :span="12">
+						<el-form-item label="璇佷功缂栧彿锛�" prop="model">
               <el-input
                   v-model="form.model"
                   placeholder="璇疯緭鍏�"
                   clearable
               />
             </el-form-item>
-          </el-col>
+					</el-col>
+				</el-row>
+        <el-row :gutter="30">
           <el-col :span="12">
             <el-form-item label="鏈�鏂伴壌瀹氭棩鏈燂細" prop="mostDate">
               <el-date-picker
@@ -77,8 +68,6 @@
               />
             </el-form-item>
           </el-col>
-        </el-row>
-        <el-row :gutter="30">
           <el-col :span="12">
             <el-form-item label="鏈夋晥鏃ユ湡(澶�)锛�" prop="valid">
               <el-input
@@ -91,15 +80,6 @@
               >
               <template #append>鏃�</template>
               </el-input>
-            </el-form-item>
-          </el-col>
-          <el-col :span="12">
-            <el-form-item label="妫�瀹氬懆鏈燂細" prop="cycle">
-              <el-input
-                  v-model="form.cycle"
-                  placeholder="璇疯緭鍏ユ瀹氬懆鏈�"
-                  clearable
-              />
             </el-form-item>
           </el-col>
         </el-row>
@@ -184,10 +164,8 @@
 	form: {
 		code: "",
     name: "",
-    instationLocation: "",
     mostDate:"",
 		model: "",
-    cycle:"",
 		validDate: "",
 		nextDate: "",
 		userId: "",
@@ -203,9 +181,7 @@
 		nextDate: [{required: true, message: "璇烽�夋嫨", trigger: "change"}],
 		userId: [{required: true, message: "璇烽�夋嫨", trigger: "change"}],
 		recordDate: [{required: true, message: "璇烽�夋嫨", trigger: "change"}],
-    instationLocation: [{required: true, message: "璇疯緭鍏�", trigger: "blur"}],
     mostDate: [{required: true, message: "璇烽�夋嫨", trigger: "change"}],
-    cycle: [{required: true, message: "璇烽�夋嫨", trigger: "blur"}],
     valid: [
       {required: true, message: "璇疯緭鍏�", trigger: "blur"},
       {
diff --git a/src/views/equipmentManagement/measurementEquipment/index.vue b/src/views/equipmentManagement/measurementEquipment/index.vue
index c1d5379..d2ec2d7 100644
--- a/src/views/equipmentManagement/measurementEquipment/index.vue
+++ b/src/views/equipmentManagement/measurementEquipment/index.vue
@@ -42,6 +42,7 @@
 				:tableLoading="tableLoading"
 				@pagination="pagination"
         :dbRowClick="dbRowClick"
+        :rowClassName="rowClassName"
 			></PIMTable>
 		</div>
 		<form-dia ref="formDia" @close="handleQuery"></form-dia>
@@ -89,12 +90,6 @@
     align: "center",
   },
 	{
-		label: "瀹夎浣嶇疆",
-		prop: "instationLocation",
-		width: 150,
-    align:"center"
-	},
-	{
 		label: "妫�瀹氬崟浣�",
 		prop: "unit",
 		width: 200,
@@ -130,12 +125,6 @@
 		width: 130,
     align:"center"
 	},
-  {
-    label: "妫�瀹氬懆鏈�(澶�)",
-    prop: "cycle",
-    width: 130,
-    align:"center"
-  },
   {
     label: "鐘舵��",
     prop: "status",
@@ -193,6 +182,31 @@
 
 const dbRowClick = (row)=>{
   rowClickData.value?.openDialog(row)
+}
+
+// 琛屾牱寮忥細蹇埌鏈燂紙7澶╁唴锛夋垨閫炬湡鏍囩孩
+const rowClassName = ({ row }) => {
+  console.log('rowClassName called:', row);
+  // valid 鏄湁鏁堝ぉ鏁帮紝mostDate 鏄渶鏂版瀹氭棩鏈�
+  if (row.valid && row.mostDate) {
+    const mostDate = new Date(row.mostDate);
+    // 璁$畻鍒版湡鏃ユ湡 = 妫�瀹氭棩鏈� + 鏈夋晥澶╂暟
+    const validDays = parseInt(row.valid) || 0;
+    const expireDate = new Date(mostDate);
+    expireDate.setDate(expireDate.getDate() + validDays);
+    
+    const now = new Date();
+    const diffDays = Math.ceil((expireDate - now) / (1000 * 60 * 60 * 24));
+    console.log('row:', row.code, 'validDays:', validDays, 'expireDate:', expireDate, 'diffDays:', diffDays);
+    // 7澶╁唴鍒版湡鎴栧凡閫炬湡閮芥爣绾�
+    if (diffDays <= 7) {
+      console.log('return warning-row');
+      return 'warning-row';
+    }
+  } else {
+    console.log('row missing valid or mostDate:', row.valid, row.mostDate);
+  }
+  return '';
 }
 
 // 琛ㄦ牸閫夋嫨鏁版嵁
@@ -294,5 +308,13 @@
 </script>
 
 <style scoped>
-
+:deep(.el-table .warning-row) {
+  background-color: #fef0f0 !important;
+}
+:deep(.el-table .warning-row:hover > td) {
+  background-color: #f9d5d5 !important;
+}
+:deep(.el-table .el-table__body tr.warning-row td) {
+  background-color: #fef0f0 !important;
+}
 </style>
\ No newline at end of file
diff --git a/src/views/equipmentManagement/repair/Modal/AcceptanceModal.vue b/src/views/equipmentManagement/repair/Modal/AcceptanceModal.vue
new file mode 100644
index 0000000..6d61a9f
--- /dev/null
+++ b/src/views/equipmentManagement/repair/Modal/AcceptanceModal.vue
@@ -0,0 +1,144 @@
+<template>
+  <FormDialog
+    v-model="visible"
+    title="楠屾敹瀹℃壒"
+    width="500px"
+    @confirm="submitForm"
+    @cancel="handleCancel"
+    @close="handleCancel"
+  >
+    <el-form :model="form" :rules="rules" label-width="100px">
+      <el-form-item label="楠屾敹浜�" prop="acceptanceName">
+        <el-select
+          v-model="form.acceptanceName"
+          placeholder="璇烽�夋嫨楠屾敹浜�"
+          filterable
+          style="width: 100%"
+        >
+          <el-option
+            v-for="item in userList"
+            :key="item.userId"
+            :label="item.nickName"
+            :value="item.nickName"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="楠屾敹鏃堕棿" prop="acceptanceTime">
+        <el-date-picker
+          v-model="form.acceptanceTime"
+          type="datetime"
+          placeholder="璇烽�夋嫨楠屾敹鏃堕棿"
+          format="YYYY-MM-DD HH:mm:ss"
+          value-format="YYYY-MM-DD HH:mm:ss"
+          style="width: 100%"
+        />
+      </el-form-item>
+      <el-form-item label="楠屾敹澶囨敞" prop="acceptanceRemark">
+        <el-input
+          v-model="form.acceptanceRemark"
+          type="textarea"
+          :rows="3"
+          placeholder="璇疯緭鍏ラ獙鏀跺娉�"
+        />
+      </el-form-item>
+    </el-form>
+  </FormDialog>
+</template>
+
+<script setup>
+import FormDialog from "@/components/Dialog/FormDialog.vue";
+import { ref, reactive } from "vue";
+import { ElMessage } from "element-plus";
+import { userListNoPageByTenantId } from "@/api/system/user.js";
+import { repairAcceptance } from "@/api/equipmentManagement/repair";
+import dayjs from "dayjs";
+
+defineOptions({
+  name: "楠屾敹瀹℃壒寮圭獥",
+});
+
+const emits = defineEmits(["ok"]);
+
+const visible = ref(false);
+const loading = ref(false);
+const repairId = ref(null);
+const userList = ref([]);
+
+const form = reactive({
+  acceptanceName: undefined,
+  acceptanceTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
+  acceptanceRemark: undefined,
+});
+
+const rules = {
+  acceptanceName: [
+    { required: true, message: "璇烽�夋嫨楠屾敹浜�", trigger: "change" },
+  ],
+  acceptanceTime: [
+    { required: true, message: "璇烽�夋嫨楠屾敹鏃堕棿", trigger: "change" },
+  ],
+  acceptanceRemark: [
+    { required: true, message: "璇疯緭鍏ラ獙鏀跺娉�", trigger: "blur" },
+  ],
+};
+
+// 鍔犺浇鐢ㄦ埛鍒楄〃
+const loadUserList = async () => {
+  const { data } = await userListNoPageByTenantId();
+  userList.value = data;
+};
+
+// 鎵撳紑寮圭獥
+const open = async (row) => {
+  repairId.value = row.id;
+  visible.value = true;
+  // 閲嶇疆琛ㄥ崟
+  form.acceptanceName = undefined;
+  form.acceptanceTime = dayjs().format("YYYY-MM-DD HH:mm:ss");
+  form.acceptanceRemark = undefined;
+  await loadUserList();
+};
+
+// 鎻愪氦琛ㄥ崟
+const submitForm = async () => {
+  if (!form.acceptanceName) {
+    ElMessage.warning("璇烽�夋嫨楠屾敹浜�");
+    return;
+  }
+  if (!form.acceptanceTime) {
+    ElMessage.warning("璇烽�夋嫨楠屾敹鏃堕棿");
+    return;
+  }
+  if (!form.acceptanceRemark) {
+    ElMessage.warning("璇疯緭鍏ラ獙鏀跺娉�");
+    return;
+  }
+
+  loading.value = true;
+  try {
+    const { code } = await repairAcceptance({
+      id: repairId.value,
+      acceptanceName: form.acceptanceName,
+      acceptanceTime: form.acceptanceTime,
+      acceptanceRemark: form.acceptanceRemark,
+    });
+    if (code === 200) {
+      ElMessage.success("楠屾敹閫氳繃");
+      visible.value = false;
+      emits("ok");
+    }
+  } finally {
+    loading.value = false;
+  }
+};
+
+const handleCancel = () => {
+  visible.value = false;
+};
+
+defineExpose({
+  open,
+});
+</script>
+
+<style lang="scss" scoped></style>
diff --git a/src/views/equipmentManagement/repair/Modal/RepairModal.vue b/src/views/equipmentManagement/repair/Modal/RepairModal.vue
index 5e31943..4e73833 100644
--- a/src/views/equipmentManagement/repair/Modal/RepairModal.vue
+++ b/src/views/equipmentManagement/repair/Modal/RepairModal.vue
@@ -49,19 +49,44 @@
           </el-form-item>
         </el-col>
         <el-col :span="12">
-          <el-form-item label="椤圭洰">
-            <el-input v-model="form.machineryCategory" placeholder="璇疯緭鍏ラ」鐩�" />
+          <el-form-item label="鎶ヤ慨鎶ヤ慨椤圭洰">
+            <el-input v-model="form.machineryCategory" placeholder="璇疯緭鍏ユ姤淇姤淇」鐩�" />
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row>
+        <el-col :span="12">
+          <el-form-item label="缁翠慨浜�">
+            <el-input v-model="form.maintenanceName" placeholder="璇疯緭鍏ョ淮淇汉濮撳悕" />
           </el-form-item>
         </el-col>
       </el-row>
       <el-row v-if="id">
         <el-col :span="12">
           <el-form-item label="鎶ヤ慨鐘舵��">
-            <el-select v-model="form.status">
+            <el-select v-model="form.status" disabled>
               <el-option label="寰呯淮淇�" :value="0"></el-option>
-              <el-option label="瀹岀粨" :value="1"></el-option>
+              <el-option label="宸查獙鏀�" :value="1"></el-option>
               <el-option label="澶辫触" :value="2"></el-option>
             </el-select>
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <!-- 楠屾敹淇℃伅灞曠ず -->
+      <el-row v-if="id && form.status === 1">
+        <el-col :span="12">
+          <el-form-item label="楠屾敹浜�">
+            <el-input v-model="form.acceptanceName" disabled />
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="楠屾敹鏃堕棿">
+            <el-input v-model="form.acceptanceTime" disabled />
+          </el-form-item>
+        </el-col>
+        <el-col :span="24">
+          <el-form-item label="楠屾敹澶囨敞">
+            <el-input v-model="form.acceptanceRemark" type="textarea" :rows="2" disabled />
           </el-form-item>
         </el-col>
       </el-row>
@@ -131,6 +156,7 @@
   status: 0, // 鎶ヤ慨鐘舵��
   machineryCategory: undefined,
   storageBlobDTOs: [],
+  maintenanceName: undefined, // 缁翠慨浜�
 });
 
 const setDeviceModel = (deviceId) => {
@@ -148,6 +174,10 @@
   form.status = data.status;
   form.machineryCategory = data.machineryCategory;
   form.storageBlobDTOs = data.storageBlobVOs || [];
+  form.maintenanceName = data.maintenanceName;
+  form.acceptanceName = data.acceptanceName;
+  form.acceptanceTime = data.acceptanceTime;
+  form.acceptanceRemark = data.acceptanceRemark;
 };
 
 const sendForm = async () => {
diff --git a/src/views/equipmentManagement/repair/index.vue b/src/views/equipmentManagement/repair/index.vue
index f3a4330..2835356 100644
--- a/src/views/equipmentManagement/repair/index.vue
+++ b/src/views/equipmentManagement/repair/index.vue
@@ -100,13 +100,14 @@
         <template #statusRef="{ row }">
           <el-tag v-if="row.status === 2" type="danger">澶辫触</el-tag>
           <el-tag v-if="row.status === 1" type="success">瀹岀粨</el-tag>
+          <el-tag v-if="row.status === 3" type="info">寰呴獙鏀�</el-tag>
           <el-tag v-if="row.status === 0" type="warning">寰呯淮淇�</el-tag>
         </template>
         <template #operation="{ row }">
           <el-button
             type="primary"
             link
-            :disabled="row.status === 1"
+            :disabled="row.status === 1 || row.status === 3"
             @click="editRepair(row.id)"
           >
             缂栬緫
@@ -114,15 +115,23 @@
           <el-button
             type="success"
             link
-            :disabled="row.status === 1"
+            :disabled="row.status !== 0"
             @click="addMaintain(row)"
           >
             缁翠慨
           </el-button>
           <el-button
+            type="warning"
+            link
+            :disabled="row.status !== 3"
+            @click="openAcceptance(row)"
+          >
+            楠屾敹
+          </el-button>
+          <el-button
             type="danger"
             link
-            :disabled="row.status === 1"
+            :disabled="row.status === 1 || row.status === 3"
             @click="delRepairByIds(row.id)"
           >
             鍒犻櫎
@@ -139,6 +148,7 @@
     </div>
     <RepairModal ref="repairModalRef" @ok="getTableData"/>
     <MaintainModal ref="maintainModalRef" @ok="getTableData"/>
+    <AcceptanceModal ref="acceptanceModalRef" @ok="getTableData"/>
     <FileList v-if="fileDialogVisible"  v-model:visible="fileDialogVisible" :record-type="'device_repair'" :record-id="recordId"  />
   </div>
 </template>
@@ -151,6 +161,7 @@
 import {ElMessageBox, ElMessage} from "element-plus";
 import dayjs from "dayjs";
 import MaintainModal from "./Modal/MaintainModal.vue";
+import AcceptanceModal from "./Modal/AcceptanceModal.vue";
 const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue"));
 
 defineOptions({
@@ -162,6 +173,7 @@
 // 妯℃�佹瀹炰緥
 const repairModalRef = ref();
 const maintainModalRef = ref();
+const acceptanceModalRef = ref();
 
 // 琛ㄦ牸澶氶�夋閫変腑椤�
 const multipleList = ref([]);
@@ -197,7 +209,7 @@
         prop: "deviceModel",
       },
       {
-        label: "椤圭洰",
+        label: "鎶ヤ慨椤圭洰",
         align: "center",
         prop: "machineryCategory",
       },
@@ -232,6 +244,17 @@
         align: "center",
         prop: "maintenanceTime",
         formatData: (cell) => (cell ? dayjs(cell).format("YYYY-MM-DD") : ""),
+      },
+      {
+        label: "楠屾敹浜�",
+        align: "center",
+        prop: "acceptanceName",
+      },
+      {
+        label: "楠屾敹鏃堕棿",
+        align: "center",
+        prop: "acceptanceTime",
+        formatData: (cell) => (cell ? dayjs(cell).format("YYYY-MM-DD HH:mm:ss") : ""),
       },
       {
         label: "鐘舵��",
@@ -301,6 +324,11 @@
   maintainModalRef.value.open(row.id, row);
 };
 
+// 鎵撳紑楠屾敹寮圭獥
+const openAcceptance = (row) => {
+  acceptanceModalRef.value.open(row);
+};
+
 const changePage = ({page, limit}) => {
   pagination.currentPage = page;
   pagination.pageSize = limit;
diff --git a/src/views/equipmentManagement/upkeep/Form/PlanModal.vue b/src/views/equipmentManagement/upkeep/Form/PlanModal.vue
index ee59ce2..8a9cd98 100644
--- a/src/views/equipmentManagement/upkeep/Form/PlanModal.vue
+++ b/src/views/equipmentManagement/upkeep/Form/PlanModal.vue
@@ -32,10 +32,10 @@
           disabled
         />
       </el-form-item>
-      <el-form-item label="椤圭洰">
+      <el-form-item label="淇濆吇椤圭洰">
         <el-input
             v-model="form.machineryCategory"
-            placeholder="璇疯緭鍏ラ」鐩�"
+            placeholder="璇疯緭鍏ヤ繚鍏婚」鐩�"
         />
       </el-form-item>
       <el-form-item label="褰曞叆浜�">
@@ -61,6 +61,13 @@
           <el-option label="瀹岀粨" :value="1"></el-option>
           <el-option label="澶辫触" :value="2"></el-option>
         </el-select>
+      </el-form-item>
+      <el-form-item label="淇濆吇浜�">
+        <el-input
+          v-model="form.maintenancePerson"
+          placeholder="璇疯緭鍏ヤ繚鍏讳汉濮撳悕"
+          clearable
+        />
       </el-form-item>
       <el-form-item label="璁″垝淇濆吇鏃ユ湡">
         <el-date-picker
@@ -124,6 +131,7 @@
   status: 0, //淇濅慨鐘舵��
   machineryCategory: undefined,
   storageBlobDTOs: [],
+  maintenancePerson: undefined, // 淇濆吇浜�
 });
 
 const setDeviceModel = (deviceId) => {
@@ -142,6 +150,7 @@
   form.createUser = Number(data.createUser);
   form.status = data.status;
   form.machineryCategory = data.machineryCategory;
+  form.maintenancePerson = data.maintenancePerson;
   if (data.maintenancePlanTime) {
     form.maintenancePlanTime = dayjs(data.maintenancePlanTime).format(
       "YYYY-MM-DD HH:mm:ss"
diff --git a/src/views/equipmentManagement/upkeep/Form/formDia.vue b/src/views/equipmentManagement/upkeep/Form/formDia.vue
index 9550b08..6856ae1 100644
--- a/src/views/equipmentManagement/upkeep/Form/formDia.vue
+++ b/src/views/equipmentManagement/upkeep/Form/formDia.vue
@@ -67,10 +67,20 @@
 			</el-row>
 			<el-row>
 				<el-col :span="12">
-					<el-form-item label="璁惧椤圭洰" prop="machineryCategory">
+					<el-form-item label="淇濆吇椤圭洰" prop="machineryCategory">
 						<el-input
 							v-model.trim="form.machineryCategory"
-							placeholder="璇疯緭鍏ヨ澶囬」鐩�"
+							placeholder="璇疯緭鍏ヤ繚鍏婚」鐩�"
+							maxlength="100"
+							clearable
+						/>
+					</el-form-item>
+				</el-col>
+				<el-col :span="12">
+					<el-form-item label="淇濆吇浜�" prop="maintenancePerson">
+						<el-input
+							v-model.trim="form.maintenancePerson"
+							placeholder="璇疯緭鍏ヤ繚鍏讳汉濮撳悕"
 							maxlength="100"
 							clearable
 						/>
@@ -173,13 +183,14 @@
 		week: '',
 		time: '',
 		deviceModel: undefined, // 瑙勬牸鍨嬪彿
-		registrationDate: ''
+		registrationDate: '',
+		maintenancePerson: '' // 淇濆吇浜�
 	},
 	rules: {
 		taskId: [{ required: true, message: "璇烽�夋嫨璁惧", trigger: "change" },],
 		inspector: [{ required: true, message: "璇烽�夋嫨褰曞叆浜�", trigger: "blur" },],
 		registrationDate: [{ required: true, message: "璇烽�夋嫨鐧昏鏃堕棿", trigger: "change" }],
-		machineryCategory: [{ required: true, message: "璇疯緭鍏ヨ澶囬」鐩�", trigger: "blur" }]
+		machineryCategory: [{ required: true, message: "璇疯緭鍏ヤ繚鍏婚」鐩�", trigger: "blur" }]
 	}
 })
 const { form, rules } = toRefs(data)
@@ -259,7 +270,8 @@
 		week: '',
 		time: '',
 		deviceModel: undefined,
-		registrationDate: ''
+		registrationDate: '',
+		maintenancePerson: ''
 	}
 }
 
diff --git a/src/views/equipmentManagement/upkeep/index.vue b/src/views/equipmentManagement/upkeep/index.vue
index 2fc3eae..6bdbc8f 100644
--- a/src/views/equipmentManagement/upkeep/index.vue
+++ b/src/views/equipmentManagement/upkeep/index.vue
@@ -300,7 +300,7 @@
       prop: "deviceModel",
     },
     {
-      label: "璁惧椤圭洰",
+      label: "淇濆吇椤圭洰",
       prop: "machineryCategory",
       minWidth: 120,
       formatData: cell => cell || "--",
@@ -342,6 +342,7 @@
         );
       },
     },
+    { prop: "maintenancePerson", label: "淇濆吇浜�", minWidth: 100 },
     { prop: "registrant", label: "鐧昏浜�", minWidth: 100 },
     { prop: "registrationDate", label: "鐧昏鏃ユ湡", minWidth: 100 },
     {
@@ -378,7 +379,7 @@
       prop: "createUserName",
     },
     {
-      label: "璁惧椤圭洰",
+      label: "淇濆吇椤圭洰",
       align: "center",
       prop: "machineryCategory",
       formatData: cell => cell || "--",
diff --git a/src/views/financialManagement/assets/fixedAssets.vue b/src/views/financialManagement/assets/fixedAssets.vue
index c713b52..24b4cc3 100644
--- a/src/views/financialManagement/assets/fixedAssets.vue
+++ b/src/views/financialManagement/assets/fixedAssets.vue
@@ -38,11 +38,12 @@
         <div>
           <el-button type="primary" @click="add" icon="Plus">鏂板璧勪骇</el-button>
           <el-button type="warning" @click="handleDepreciation" icon="Money">鎶樻棫璁℃彁</el-button>
-          <el-button @click="handleOut" icon="Download">瀵煎嚭</el-button>
+          <!-- <el-button @click="handleOut" icon="Download">瀵煎嚭</el-button> -->
         </div>
       </div>
       <PIMTable
         rowKey="id"
+        isSelection
         :column="columns"
         :tableData="dataList"
         :page="{
@@ -50,6 +51,7 @@
           size: pagination.pageSize,
           total: pagination.total,
         }"
+        @selection-change="handleSelectionChange"
         @pagination="changePage"
       >
         <template #originalValue="{ row }">
@@ -227,12 +229,18 @@
 ];
 
 const dataList = ref([]);
+const multipleList = ref([]);
 const dialogVisible = ref(false);
 const dialogTitle = ref("");
 const formRef = ref(null);
 const isEdit = ref(false);
 const isView = ref(false);
 const currentId = ref(null);
+const selectedIds = computed(() =>
+  multipleList.value
+    .map(item => item?.id)
+    .filter(id => id !== undefined && id !== null && id !== "")
+);
 
 const createDefaultForm = () => ({
   assetCode: "",
@@ -322,10 +330,15 @@
       status: filters.status,
     });
     dataList.value = data?.records || [];
+    multipleList.value = [];
     pagination.total = Number(data?.total || 0);
   } catch (error) {
     // 鎻愮ず鐢卞叏灞�璇锋眰鎷︽埅鍣ㄥ鐞嗭紝杩欓噷浠呴槻姝㈡湭鎹曡幏寮傚父
   }
+};
+
+const handleSelectionChange = (selectionList) => {
+  multipleList.value = selectionList;
 };
 
 const resetFilters = () => {
@@ -388,12 +401,16 @@
 };
 
 const handleDepreciation = () => {
-  ElMessageBox.confirm("纭杩涜鏈湀鎶樻棫璁℃彁鍚楋紵", "鎻愮ず", {
+  const ids = selectedIds.value;
+  const confirmText = ids.length
+    ? `纭瀵归�変腑鐨� ${ids.length} 鏉¤祫浜ц繘琛屾湰鏈堟姌鏃ц鎻愬悧锛焋
+    : "纭杩涜鏈湀鎶樻棫璁℃彁鍚楋紵";
+  ElMessageBox.confirm(confirmText, "鎻愮ず", {
     confirmButtonText: "纭",
     cancelButtonText: "鍙栨秷",
     type: "info",
   }).then(async () => {
-    await depreciateFixedAsset({});
+    await depreciateFixedAsset({ ids });
     ElMessage.success("鎶樻棫璁℃彁瀹屾垚");
     await getTableData();
   });
diff --git a/src/views/financialManagement/assets/intangibleAssets.vue b/src/views/financialManagement/assets/intangibleAssets.vue
index 06b5583..4642166 100644
--- a/src/views/financialManagement/assets/intangibleAssets.vue
+++ b/src/views/financialManagement/assets/intangibleAssets.vue
@@ -39,11 +39,12 @@
         <div>
           <el-button type="primary" @click="add" icon="Plus">鏂板璧勪骇</el-button>
           <el-button type="warning" @click="handleAmortization" icon="Money">鎽婇攢璁℃彁</el-button>
-          <el-button @click="handleOut" icon="Download">瀵煎嚭</el-button>
+          <!-- <el-button @click="handleOut" icon="Download">瀵煎嚭</el-button> -->
         </div>
       </div>
       <PIMTable
         rowKey="id"
+        isSelection
         :column="columns"
         :tableData="dataList"
         :page="{
@@ -51,6 +52,7 @@
           size: pagination.pageSize,
           total: pagination.total,
         }"
+        @selection-change="handleSelectionChange"
         @pagination="changePage"
       >
         <template #originalValue="{ row }">
@@ -220,12 +222,18 @@
 ];
 
 const dataList = ref([]);
+const multipleList = ref([]);
 const dialogVisible = ref(false);
 const dialogTitle = ref("");
 const formRef = ref(null);
 const isEdit = ref(false);
 const isView = ref(false);
 const currentId = ref(null);
+const selectedIds = computed(() =>
+  multipleList.value
+    .map(item => item?.id)
+    .filter(id => id !== undefined && id !== null && id !== "")
+);
 
 const createDefaultForm = () => ({
   assetCode: "",
@@ -320,10 +328,15 @@
       status: filters.status,
     });
     dataList.value = data?.records || [];
+    multipleList.value = [];
     pagination.total = Number(data?.total || 0);
   } catch (error) {
     // 鎻愮ず鐢卞叏灞�璇锋眰鎷︽埅鍣ㄥ鐞嗭紝杩欓噷浠呴槻姝㈡湭鎹曡幏寮傚父
   }
+};
+
+const handleSelectionChange = (selectionList) => {
+  multipleList.value = selectionList;
 };
 
 const resetFilters = () => {
@@ -386,12 +399,16 @@
 };
 
 const handleAmortization = () => {
-  ElMessageBox.confirm("纭杩涜鏈湀鎽婇攢璁℃彁鍚楋紵", "鎻愮ず", {
+  const ids = selectedIds.value;
+  const confirmText = ids.length
+    ? `纭瀵归�変腑鐨� ${ids.length} 鏉¤祫浜ц繘琛屾湰鏈堟憡閿�璁℃彁鍚楋紵`
+    : "纭杩涜鏈湀鎽婇攢璁℃彁鍚楋紵";
+  ElMessageBox.confirm(confirmText, "鎻愮ず", {
     confirmButtonText: "纭",
     cancelButtonText: "鍙栨秷",
     type: "info",
   }).then(async () => {
-    await amortizeIntangibleAsset({});
+    await amortizeIntangibleAsset({ ids });
     ElMessage.success("鎽婇攢璁℃彁瀹屾垚");
     await getTableData();
   });
diff --git a/src/views/financialManagement/generalLedger/index.vue b/src/views/financialManagement/generalLedger/index.vue
index 2d370f4..a7b1d30 100644
--- a/src/views/financialManagement/generalLedger/index.vue
+++ b/src/views/financialManagement/generalLedger/index.vue
@@ -44,20 +44,62 @@
           <el-button type="primary"
                      @click="add"
                      icon="Plus">鏂板</el-button>
-          <el-button @click="handleOut"
-                     icon="Download">瀵煎嚭</el-button>
+          <!-- <el-button @click="handleOut"
+                     icon="Download">瀵煎嚭</el-button> -->
         </div>
       </div>
-      <PIMTable rowKey="id"
-                :column="columns"
-                :tableData="dataList"
-                :page="{
-          current: pagination.currentPage,
-          size: pagination.pageSize,
-          total: pagination.total,
-        }"
-                @pagination="changePage">
-      </PIMTable>
+      <el-table ref="tableRef"
+                v-loading="loading"
+                :data="dataList"
+                row-key="id"
+                :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
+                height="calc(100vh - 280px)"
+                border
+                stripe
+                highlight-current-row
+                class="subject-table">
+        <el-table-column label="绉戠洰缂栫爜" prop="subjectCode" width="140">
+          <template #default="scope">
+            <span class="subject-code">{{ scope.row.subjectCode }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="绉戠洰鍚嶇О" prop="subjectName" min-width="180">
+          <template #default="scope">
+            <span class="subject-name" :class="{ 'is-parent': scope.row.children?.length > 0 }">
+              {{ scope.row.subjectName }}
+            </span>
+          </template>
+        </el-table-column>
+        <el-table-column label="绉戠洰绫诲瀷" prop="subjectType" width="100" align="center">
+          <template #default="scope">
+            <el-tag size="small" :type="getSubjectTypeType(scope.row.subjectType)">
+              {{ scope.row.subjectType }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="浣欓鏂瑰悜" prop="balanceDirection" width="100" align="center">
+          <template #default="scope">
+            <el-tag size="small" :type="scope.row.balanceDirection === '鍊熸柟' ? 'primary' : 'danger'">
+              {{ scope.row.balanceDirection }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="鐘舵��" prop="status" width="80" align="center">
+          <template #default="scope">
+            <el-tag size="small" :type="scope.row.status === 0 || scope.row.status === '0' ? 'success' : 'info'">
+              {{ scope.row.status === 0 || scope.row.status === '0' ? '鍚敤' : '绂佺敤' }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="澶囨敞" prop="remark" show-overflow-tooltip min-width="150" />
+        <el-table-column label="鎿嶄綔" align="center" fixed="right" width="240">
+          <template #default="scope">
+            <el-button link type="primary" icon="Plus" @click="addChild(scope.row)">鏂板</el-button>
+            <el-button link type="primary" icon="Edit" @click="edit(scope.row)">缂栬緫</el-button>
+            <el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)">鍒犻櫎</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
     </div>
     <FormDialog :title="dialogTitle"
                 v-model="dialogVisible"
@@ -131,7 +173,7 @@
 </template>
 
 <script setup>
-  import { ref, reactive, onMounted, getCurrentInstance } from "vue";
+  import { ref, reactive, onMounted, getCurrentInstance, nextTick } from "vue";
   import { ElMessage, ElMessageBox } from "element-plus";
   import FormDialog from "@/components/Dialog/FormDialog.vue";
   import {
@@ -237,7 +279,9 @@
   const dialogTitle = ref("");
   const parentSubjectLabel = ref("椤剁骇绉戠洰");
   const formRef = ref(null);
+  const tableRef = ref(null);
   const isEdit = ref(false);
+  const loading = ref(false);
 
   const form = reactive({
     id: undefined,
@@ -270,14 +314,17 @@
   };
 
   const getTableData = () => {
+    loading.value = true;
     const query = {
       current: pagination.currentPage,
       size: pagination.pageSize,
       ...filters,
     };
     listAccountSubject(query).then(response => {
-      dataList.value = response.data.records;
-      pagination.total = response.data.total;
+      dataList.value = response.data.records || [];
+      loading.value = false;
+    }).catch(() => {
+      loading.value = false;
     });
   };
 
@@ -423,4 +470,29 @@
     justify-content: space-between;
     margin-bottom: 15px;
   }
+
+  .subject-table {
+    border-radius: 8px;
+    overflow: hidden;
+
+    :deep(.el-table__row) {
+      transition: background-color 0.3s;
+    }
+
+    :deep(.el-table__row:hover) {
+      background-color: #f5f7fa;
+    }
+
+    .subject-code {
+      color: #606266;
+    }
+
+    .subject-name {
+      font-weight: 500;
+
+      &.is-parent {
+        color: #409eff;
+      }
+    }
+  }
 </style>
diff --git a/src/views/financialManagement/voucher/detailLedger.vue b/src/views/financialManagement/voucher/detailLedger.vue
index 8ed7dcb..c07574c 100644
--- a/src/views/financialManagement/voucher/detailLedger.vue
+++ b/src/views/financialManagement/voucher/detailLedger.vue
@@ -1,79 +1,80 @@
 <template>
-  <div class="app-container">
-    <el-form :model="filters" :inline="true">
-      <el-form-item label="浼氳绉戠洰:">
-        <el-cascader v-model="filters.subject" :options="subjectOptions" :props="{ label: 'name', value: 'code', checkStrictly: true }" placeholder="璇烽�夋嫨浼氳绉戠洰" clearable style="width: 250px;" filterable />
-      </el-form-item>
-      <el-form-item label="杈呭姪鏍哥畻:">
-        <el-select v-model="filters.auxiliary" placeholder="璇烽�夋嫨杈呭姪鏍哥畻" clearable style="width: 180px;">
-          <el-option label="瀹㈡埛" value="customer" />
-          <el-option label="渚涘簲鍟�" value="supplier" />
-          <el-option label="閮ㄩ棬" value="department" />
-          <el-option label="鍛樺伐" value="employee" />
-          <el-option label="椤圭洰" value="project" />
-        </el-select>
-      </el-form-item>
-      <el-form-item label="鏍哥畻瀵硅薄:">
-        <el-select v-model="filters.auxiliaryItem" placeholder="璇烽�夋嫨鏍哥畻瀵硅薄" clearable style="width: 200px;" :disabled="!filters.auxiliary">
-          <el-option v-for="item in auxiliaryItems" :key="item.value" :label="item.label" :value="item.value" />
-        </el-select>
-      </el-form-item>
-      <el-form-item label="鏈熼棿:">
-        <el-date-picker v-model="filters.startMonth" type="month" placeholder="寮�濮嬫湀浠�" value-format="YYYY-MM" style="width: 140px;" />
-        <span style="margin: 0 10px;">鑷�</span>
-        <el-date-picker v-model="filters.endMonth" type="month" placeholder="缁撴潫鏈堜唤" value-format="YYYY-MM" style="width: 140px;" />
-      </el-form-item>
-      <el-form-item>
-        <el-button type="primary" @click="getTableData">鏌ヨ</el-button>
-        <el-button @click="resetFilters">閲嶇疆</el-button>
-        <el-button @click="handlePrint" icon="Printer">鎵撳嵃</el-button>
-        <el-button @click="handleOut" icon="Download">瀵煎嚭</el-button>
-      </el-form-item>
-    </el-form>
+  <div class="app-container ledger-page">
+    <div class="ledger-layout">
+      <aside class="subject-panel">
+        <el-input v-model="subjectKeyword" placeholder="璇疯緭鍏ョ鐩悕绉�/缂栧彿" clearable prefix-icon="Search" />
+        <el-scrollbar class="subject-tree-scroll">
+          <el-tree
+            ref="subjectTreeRef"
+            :data="subjectOptions"
+            node-key="code"
+            :props="{ label: 'name', children: 'children' }"
+            highlight-current
+            default-expand-all
+            :expand-on-click-node="false"
+            :filter-node-method="filterSubjectNode"
+            @node-click="handleSubjectClick"
+          >
+            <template #default="{ data }">
+              <span class="subject-node">{{ data.code }} {{ data.name }}</span>
+            </template>
+          </el-tree>
+        </el-scrollbar>
+      </aside>
 
-    <div class="ledger-header" v-if="currentSubject">
-      <h2>绉戠洰鏄庣粏璐�</h2>
-      <p>绉戠洰: {{ currentSubject.code }} {{ currentSubject.name }}</p>
-      <p v-if="filters.auxiliary && filters.auxiliaryItem">杈呭姪鏍哥畻: {{ getAuxiliaryLabel() }}</p>
-      <p>鏈熼棿: {{ filters.startMonth }} 鑷� {{ filters.endMonth }}</p>
+      <section class="ledger-content">
+        <el-form :model="filters" :inline="true" class="filter-form">
+          <el-form-item label="鏈熼棿:">
+            <el-date-picker v-model="filters.startMonth" type="month" placeholder="寮�濮嬫湀浠�" value-format="YYYY-MM" style="width: 140px;" />
+            <span style="margin: 0 10px;">鑷�</span>
+            <el-date-picker v-model="filters.endMonth" type="month" placeholder="缁撴潫鏈堜唤" value-format="YYYY-MM" style="width: 140px;" />
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" @click="getTableData">鏌ヨ</el-button>
+            <el-button @click="resetFilters">閲嶇疆</el-button>
+<!--            <el-button @click="handlePrint" icon="Printer">鎵撳嵃</el-button>-->
+            <el-button @click="handleOut" icon="Download">瀵煎嚭</el-button>
+          </el-form-item>
+        </el-form>
+
+        <div class="table_list">
+          <el-table :data="dataList" border style="width: 100%">
+            <el-table-column prop="date" label="鏃ユ湡" width="120" />
+            <el-table-column prop="voucherNo" label="鍑瘉瀛楀彿" width="120" />
+            <el-table-column prop="summary" label="鎽樿" min-width="200" show-overflow-tooltip />
+            <el-table-column prop="debit" label="鍊熸柟" width="150">
+              <template #default="{ row }">
+                <span v-if="row.debit > 0" class="text-danger">楼{{ formatMoney(row.debit) }}</span>
+                <span v-else>-</span>
+              </template>
+            </el-table-column>
+            <el-table-column prop="credit" label="璐锋柟" width="150">
+              <template #default="{ row }">
+                <span v-if="row.credit > 0" class="text-success">楼{{ formatMoney(row.credit) }}</span>
+                <span v-else>-</span>
+              </template>
+            </el-table-column>
+            <el-table-column label="鏂瑰悜" width="80">
+              <template #default="{ row }">
+                <el-tag :type="row.direction === '鍊�' ? 'success' : 'danger'" size="small">{{ row.direction }}</el-tag>
+              </template>
+            </el-table-column>
+            <el-table-column label="浣欓" width="150">
+              <template #default="{ row }">
+                <span :class="row.balance >= 0 ? 'text-primary' : 'text-warning'">楼{{ formatMoney(Math.abs(row.balance)) }}</span>
+              </template>
+            </el-table-column>
+          </el-table>
+        </div>
+
+        <el-empty v-if="!currentSubject" description="璇烽�夋嫨浼氳绉戠洰鏌ヨ" style="margin-top: 50px;" />
+      </section>
     </div>
-
-    <div class="table_list">
-      <el-table :data="dataList" border style="width: 100%" show-summary :summary-method="getSummaries">
-        <el-table-column prop="date" label="鏃ユ湡" width="120" />
-        <el-table-column prop="voucherNo" label="鍑瘉瀛楀彿" width="120" />
-        <el-table-column prop="summary" label="鎽樿" min-width="200" show-overflow-tooltip />
-        <el-table-column prop="debit" label="鍊熸柟" width="150">
-          <template #default="{ row }">
-            <span v-if="row.debit > 0" class="text-danger">楼{{ formatMoney(row.debit) }}</span>
-            <span v-else>-</span>
-          </template>
-        </el-table-column>
-        <el-table-column prop="credit" label="璐锋柟" width="150">
-          <template #default="{ row }">
-            <span v-if="row.credit > 0" class="text-success">楼{{ formatMoney(row.credit) }}</span>
-            <span v-else>-</span>
-          </template>
-        </el-table-column>
-        <el-table-column label="鏂瑰悜" width="80">
-          <template #default="{ row }">
-            <el-tag :type="row.direction === '鍊�' ? 'success' : 'danger'" size="small">{{ row.direction }}</el-tag>
-          </template>
-        </el-table-column>
-        <el-table-column label="浣欓" width="150">
-          <template #default="{ row }">
-            <span :class="row.balance >= 0 ? 'text-primary' : 'text-warning'">楼{{ formatMoney(Math.abs(row.balance)) }}</span>
-          </template>
-        </el-table-column>
-      </el-table>
-    </div>
-
-    <el-empty v-if="!currentSubject" description="璇烽�夋嫨浼氳绉戠洰鏌ヨ" style="margin-top: 50px;" />
   </div>
 </template>
 
 <script setup>
-import { ref, reactive, onMounted, computed, watch } from "vue";
+import { ref, reactive, onMounted, computed, watch, nextTick } from "vue";
 import { ElMessage } from "element-plus";
 import { listAccountSubject } from "@/api/financialManagement/accountSubject";
 import { getDetailLedger } from "@/api/financialManagement/ledger";
@@ -83,15 +84,28 @@
 });
 
 const filters = reactive({
-  subject: [],
-  auxiliary: "",
-  auxiliaryItem: "",
+  subject: "",
   startMonth: "",
   endMonth: "",
 });
 
 const dataList = ref([]);
 const subjectOptions = ref([]);
+const subjectKeyword = ref("");
+const subjectTreeRef = ref();
+
+const getPreviousMonth = () => {
+  const date = new Date();
+  date.setDate(1);
+  date.setMonth(date.getMonth() - 1);
+  const year = date.getFullYear();
+  const month = String(date.getMonth() + 1).padStart(2, "0");
+  return `${year}-${month}`;
+};
+
+const defaultMonth = getPreviousMonth();
+filters.startMonth = defaultMonth;
+filters.endMonth = defaultMonth;
 
 const fallbackSubjects = [
   { code: "1122", name: "搴旀敹璐︽" },
@@ -99,79 +113,14 @@
   { code: "6602", name: "绠$悊璐圭敤" },
 ];
 
-const toCascaderTree = (nodes = []) =>
+const toTree = (nodes = []) =>
   nodes
     .filter(item => item.subjectCode && item.subjectName)
     .map(item => ({
       code: item.subjectCode,
       name: item.subjectName,
-      children: toCascaderTree(item.children || []),
+      children: toTree(item.children || []),
     }));
-
-const loadSubjectOptions = async () => {
-  try {
-    const { data } = await listAccountSubject({
-      current: 1,
-      size: 1000,
-    });
-    const options = toCascaderTree(data?.records || []);
-    if (options.length > 0) {
-      subjectOptions.value = options;
-      return;
-    }
-  } catch (error) {
-    // 鍏ㄥ眬鎷︽埅鍣ㄥ凡鎻愮ず锛屼笅闈㈣蛋鍏滃簳绉戠洰
-  }
-  subjectOptions.value = fallbackSubjects.map(item => ({ ...item, children: [] }));
-};
-
-const auxiliaryItems = computed(() => {
-  const map = {
-    customer: [
-      { value: "1", label: "鍖椾含绉戞妧鏈夐檺鍏徃" },
-      { value: "2", label: "涓婃捣璐告槗鍏徃" },
-      { value: "3", label: "骞垮窞瀹炰笟鏈夐檺鍏徃" },
-    ],
-    supplier: [
-      { value: "1", label: "鍖椾含鍘熸潗鏂欎緵搴斿晢" },
-      { value: "2", label: "涓婃捣鐢靛瓙鍏冨櫒浠跺叕鍙�" },
-      { value: "3", label: "骞垮窞鍖呰鏉愭枡鍘�" },
-    ],
-    department: [
-      { value: "1", label: "璐㈠姟閮�" },
-      { value: "2", label: "閿�鍞儴" },
-      { value: "3", label: "閲囪喘閮�" },
-    ],
-    employee: [
-      { value: "1", label: "寮犱笁" },
-      { value: "2", label: "鏉庡洓" },
-      { value: "3", label: "鐜嬩簲" },
-    ],
-    project: [
-      { value: "1", label: "椤圭洰A" },
-      { value: "2", label: "椤圭洰B" },
-      { value: "3", label: "椤圭洰C" },
-    ],
-  };
-  return map[filters.auxiliary] || [];
-});
-
-watch(() => filters.auxiliary, () => {
-  filters.auxiliaryItem = "";
-});
-
-const currentSubject = computed(() => {
-  const code = getSelectedSubjectCode(filters.subject);
-  if (!code) return null;
-  return findSubject(subjectOptions.value, code);
-});
-
-const getSelectedSubjectCode = (subjectValue) => {
-  if (Array.isArray(subjectValue)) {
-    return subjectValue.length ? subjectValue[subjectValue.length - 1] : "";
-  }
-  return subjectValue || "";
-};
 
 const findSubject = (options, code) => {
   for (const item of options) {
@@ -184,9 +133,68 @@
   return null;
 };
 
-const getAuxiliaryLabel = () => {
-  const item = auxiliaryItems.value.find(i => i.value === filters.auxiliaryItem);
-  return item ? item.label : "";
+const currentSubject = computed(() => {
+  if (!filters.subject) return null;
+  return findSubject(subjectOptions.value, filters.subject);
+});
+
+const getFirstSubjectCode = (nodes = []) => {
+  for (const item of nodes) {
+    if (item.code) return item.code;
+    if (item.children && item.children.length > 0) {
+      const childCode = getFirstSubjectCode(item.children);
+      if (childCode) return childCode;
+    }
+  }
+  return "";
+};
+
+const setDefaultSubjectSelection = async () => {
+  const firstCode = getFirstSubjectCode(subjectOptions.value);
+  if (!firstCode) {
+    filters.subject = "";
+    subjectTreeRef.value?.setCurrentKey(null);
+    return;
+  }
+  filters.subject = firstCode;
+  await nextTick();
+  subjectTreeRef.value?.setCurrentKey(firstCode);
+};
+
+const filterSubjectNode = (value, data) => {
+  const keyword = value?.trim();
+  if (!keyword) return true;
+  return `${data.code}${data.name}`.includes(keyword);
+};
+
+watch(subjectKeyword, (value) => {
+  subjectTreeRef.value?.filter(value || "");
+});
+
+const handleSubjectClick = async (data) => {
+  filters.subject = data.code;
+  await getTableData();
+};
+
+const loadSubjectOptions = async () => {
+  let options = [];
+  try {
+    const { data } = await listAccountSubject({
+      current: 1,
+      size: 1000,
+    });
+    options = toTree(data?.records || []);
+  } catch (error) {
+    // 鍏ㄥ眬鎷︽埅鍣ㄥ凡鎻愮ず锛屼笅闈㈣蛋鍏滃簳绉戠洰
+  }
+  if (options.length === 0) {
+    options = fallbackSubjects.map(item => ({ ...item, children: [] }));
+  }
+  subjectOptions.value = options;
+  await setDefaultSubjectSelection();
+  if (filters.subject) {
+    await getTableData();
+  }
 };
 
 const formatMoney = (value) => {
@@ -194,7 +202,7 @@
   return Number(value).toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
 };
 
-// 鑱旇皟绾﹀畾锛氭槑缁嗚处鎺ュ彛鍙寜杈呭姪鏍哥畻杩囨护锛坅uxiliaryType/auxiliaryId锛�
+// 鑱旇皟绾﹀畾锛氭槑缁嗚处鎸夌鐩笌鏈熼棿杩囨护
 const getTableData = async () => {
   if (!currentSubject.value) {
     dataList.value = [];
@@ -203,8 +211,6 @@
   try {
     const { data } = await getDetailLedger({
       subjectCode: currentSubject.value.code,
-      auxiliaryType: filters.auxiliary,
-      auxiliaryId: filters.auxiliaryItem,
       startMonth: filters.startMonth,
       endMonth: filters.endMonth,
     });
@@ -214,36 +220,16 @@
   }
 };
 
-const resetFilters = () => {
-  filters.subject = [];
-  filters.auxiliary = "";
-  filters.auxiliaryItem = "";
-  filters.startMonth = "2024-01";
-  filters.endMonth = "2024-03";
+const resetFilters = async () => {
+  filters.startMonth = defaultMonth;
+  filters.endMonth = defaultMonth;
   dataList.value = [];
-};
-
-const getSummaries = (param) => {
-  const { columns, data } = param;
-  const sums = [];
-  columns.forEach((column, index) => {
-    if (index === 0) {
-      sums[index] = "鍚堣";
-      return;
-    }
-    if (column.property === "debit") {
-      const values = data.map(item => Number(item.debit));
-      const sum = values.reduce((prev, curr) => prev + curr, 0);
-      sums[index] = "楼" + formatMoney(sum);
-    } else if (column.property === "credit") {
-      const values = data.map(item => Number(item.credit));
-      const sum = values.reduce((prev, curr) => prev + curr, 0);
-      sums[index] = "楼" + formatMoney(sum);
-    } else {
-      sums[index] = "";
-    }
-  });
-  return sums;
+  subjectKeyword.value = "";
+  subjectTreeRef.value?.filter("");
+  await setDefaultSubjectSelection();
+  if (filters.subject) {
+    await getTableData();
+  }
 };
 
 const handlePrint = () => {
@@ -260,16 +246,37 @@
 </script>
 
 <style lang="scss" scoped>
-.ledger-header {
-  text-align: center;
-  margin-bottom: 20px;
-  h2 {
-    margin: 0 0 10px 0;
-  }
-  p {
-    color: #606266;
-    margin: 5px 0;
-  }
+.ledger-layout {
+  display: flex;
+  gap: 16px;
+}
+
+.subject-panel {
+  width: 260px;
+  flex-shrink: 0;
+  padding: 12px;
+  border: 1px solid #e4e7ed;
+  border-radius: 8px;
+  background-color: #fff;
+}
+
+.subject-tree-scroll {
+  height: 600px;
+  margin-top: 12px;
+}
+
+.subject-node {
+  display: inline-flex;
+  align-items: center;
+}
+
+.ledger-content {
+  flex: 1;
+  min-width: 0;
+}
+
+.filter-form {
+  margin-bottom: 12px;
 }
 
 .text-primary {
@@ -291,4 +298,12 @@
   color: #e6a23c;
   font-weight: bold;
 }
+
+.subject-panel :deep(.el-tree-node__content) {
+  height: 34px;
+}
+
+.subject-panel :deep(.el-tree-node.is-current > .el-tree-node__content) {
+  background-color: #f0f7ff;
+}
 </style>
diff --git a/src/views/financialManagement/voucher/generalLedger.vue b/src/views/financialManagement/voucher/generalLedger.vue
index 9ec3ea1..b362279 100644
--- a/src/views/financialManagement/voucher/generalLedger.vue
+++ b/src/views/financialManagement/voucher/generalLedger.vue
@@ -1,64 +1,80 @@
 <template>
-  <div class="app-container">
-    <el-form :model="filters" :inline="true">
-      <el-form-item label="浼氳绉戠洰:">
-        <el-cascader v-model="filters.subject" :options="subjectOptions" :props="{ label: 'name', value: 'code', checkStrictly: true }" placeholder="璇烽�夋嫨浼氳绉戠洰" clearable style="width: 250px;" filterable />
-      </el-form-item>
-      <el-form-item label="鏈熼棿:">
-        <el-date-picker v-model="filters.startMonth" type="month" placeholder="寮�濮嬫湀浠�" value-format="YYYY-MM" style="width: 140px;" />
-        <span style="margin: 0 10px;">鑷�</span>
-        <el-date-picker v-model="filters.endMonth" type="month" placeholder="缁撴潫鏈堜唤" value-format="YYYY-MM" style="width: 140px;" />
-      </el-form-item>
-      <el-form-item>
-        <el-button type="primary" @click="getTableData">鏌ヨ</el-button>
-        <el-button @click="resetFilters">閲嶇疆</el-button>
-        <el-button @click="handlePrint" icon="Printer">鎵撳嵃</el-button>
-        <el-button @click="handleOut" icon="Download">瀵煎嚭</el-button>
-      </el-form-item>
-    </el-form>
+  <div class="app-container ledger-page">
+    <div class="ledger-layout">
+      <aside class="subject-panel">
+        <el-input v-model="subjectKeyword" placeholder="璇疯緭鍏ョ鐩悕绉�/缂栧彿" clearable prefix-icon="Search" />
+        <el-scrollbar class="subject-tree-scroll">
+          <el-tree
+            ref="subjectTreeRef"
+            :data="subjectOptions"
+            node-key="code"
+            :props="{ label: 'name', children: 'children' }"
+            highlight-current
+            default-expand-all
+            :expand-on-click-node="false"
+            :filter-node-method="filterSubjectNode"
+            @node-click="handleSubjectClick"
+          >
+            <template #default="{ data }">
+              <span class="subject-node">{{ data.code }} {{ data.name }}</span>
+            </template>
+          </el-tree>
+        </el-scrollbar>
+      </aside>
 
-    <div class="ledger-header" v-if="currentSubject">
-      <h2>绉戠洰鎬昏处</h2>
-      <p>绉戠洰: {{ currentSubject.code }} {{ currentSubject.name }}</p>
-      <p>鏈熼棿: {{ filters.startMonth }} 鑷� {{ filters.endMonth }}</p>
+      <section class="ledger-content">
+        <el-form :model="filters" :inline="true" class="filter-form">
+          <el-form-item label="鏈熼棿:">
+            <el-date-picker v-model="filters.startMonth" type="month" placeholder="寮�濮嬫湀浠�" value-format="YYYY-MM" style="width: 140px;" />
+            <span style="margin: 0 10px;">鑷�</span>
+            <el-date-picker v-model="filters.endMonth" type="month" placeholder="缁撴潫鏈堜唤" value-format="YYYY-MM" style="width: 140px;" />
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" @click="getTableData">鏌ヨ</el-button>
+            <el-button @click="resetFilters">閲嶇疆</el-button>
+<!--            <el-button @click="handlePrint" icon="Printer">鎵撳嵃</el-button>-->
+            <!-- <el-button @click="handleOut" icon="Download">瀵煎嚭</el-button> -->
+          </el-form-item>
+        </el-form>
+
+        <div class="table_list">
+          <el-table :data="dataList" border style="width: 100%">
+            <el-table-column prop="date" label="鏃ユ湡"/>
+            <!-- <el-table-column prop="voucherNo" label="鍑瘉瀛楀彿" width="120" /> -->
+            <!-- <el-table-column prop="summary" label="鎽樿" min-width="200" show-overflow-tooltip /> -->
+            <el-table-column prop="debit" label="鍊熸柟">
+              <template #default="{ row }">
+                <span v-if="row.debit > 0" class="text-danger">楼{{ formatMoney(row.debit) }}</span>
+                <span v-else>-</span>
+              </template>
+            </el-table-column>
+            <el-table-column prop="credit" label="璐锋柟">
+              <template #default="{ row }">
+                <span v-if="row.credit > 0" class="text-success">楼{{ formatMoney(row.credit) }}</span>
+                <span v-else>-</span>
+              </template>
+            </el-table-column>
+            <el-table-column label="鏂瑰悜">
+              <template #default="{ row }">
+                <el-tag :type="row.direction === '鍊�' ? 'success' : 'danger'" size="small">{{ row.direction }}</el-tag>
+              </template>
+            </el-table-column>
+            <el-table-column label="浣欓">
+              <template #default="{ row }">
+                <span :class="row.balance >= 0 ? 'text-primary' : 'text-warning'">楼{{ formatMoney(Math.abs(row.balance)) }}</span>
+              </template>
+            </el-table-column>
+          </el-table>
+        </div>
+
+        <el-empty v-if="!currentSubject" description="璇烽�夋嫨浼氳绉戠洰鏌ヨ" style="margin-top: 50px;" />
+      </section>
     </div>
-
-    <div class="table_list">
-      <el-table :data="dataList" border style="width: 100%" show-summary :summary-method="getSummaries">
-        <el-table-column prop="date" label="鏃ユ湡" width="120" />
-        <el-table-column prop="voucherNo" label="鍑瘉瀛楀彿" width="120" />
-        <el-table-column prop="summary" label="鎽樿" min-width="200" show-overflow-tooltip />
-        <el-table-column prop="debit" label="鍊熸柟" width="150">
-          <template #default="{ row }">
-            <span v-if="row.debit > 0" class="text-danger">楼{{ formatMoney(row.debit) }}</span>
-            <span v-else>-</span>
-          </template>
-        </el-table-column>
-        <el-table-column prop="credit" label="璐锋柟" width="150">
-          <template #default="{ row }">
-            <span v-if="row.credit > 0" class="text-success">楼{{ formatMoney(row.credit) }}</span>
-            <span v-else>-</span>
-          </template>
-        </el-table-column>
-        <el-table-column label="鏂瑰悜" width="80">
-          <template #default="{ row }">
-            <el-tag :type="row.direction === '鍊�' ? 'success' : 'danger'" size="small">{{ row.direction }}</el-tag>
-          </template>
-        </el-table-column>
-        <el-table-column label="浣欓" width="150">
-          <template #default="{ row }">
-            <span :class="row.balance >= 0 ? 'text-primary' : 'text-warning'">楼{{ formatMoney(Math.abs(row.balance)) }}</span>
-          </template>
-        </el-table-column>
-      </el-table>
-    </div>
-
-    <el-empty v-if="!currentSubject" description="璇烽�夋嫨浼氳绉戠洰鏌ヨ" style="margin-top: 50px;" />
   </div>
 </template>
 
 <script setup>
-import { ref, reactive, onMounted, computed } from "vue";
+import { ref, reactive, onMounted, computed, watch, nextTick } from "vue";
 import { ElMessage } from "element-plus";
 import { listAccountSubject } from "@/api/financialManagement/accountSubject";
 import { getGeneralLedger } from "@/api/financialManagement/ledger";
@@ -68,13 +84,28 @@
 });
 
 const filters = reactive({
-  subject: [],
+  subject: "",
   startMonth: "",
   endMonth: "",
 });
 
 const dataList = ref([]);
 const subjectOptions = ref([]);
+const subjectKeyword = ref("");
+const subjectTreeRef = ref();
+
+const getPreviousMonth = () => {
+  const date = new Date();
+  date.setDate(1);
+  date.setMonth(date.getMonth() - 1);
+  const year = date.getFullYear();
+  const month = String(date.getMonth() + 1).padStart(2, "0");
+  return `${year}-${month}`;
+};
+
+const defaultMonth = getPreviousMonth();
+filters.startMonth = defaultMonth;
+filters.endMonth = defaultMonth;
 
 const fallbackSubjects = [
   { code: "1001", name: "搴撳瓨鐜伴噾" },
@@ -84,45 +115,14 @@
   { code: "6001", name: "涓昏惀涓氬姟鏀跺叆" },
 ];
 
-const toCascaderTree = (nodes = []) =>
+const toTree = (nodes = []) =>
   nodes
     .filter(item => item.subjectCode && item.subjectName)
     .map(item => ({
       code: item.subjectCode,
       name: item.subjectName,
-      children: toCascaderTree(item.children || []),
+      children: toTree(item.children || []),
     }));
-
-const loadSubjectOptions = async () => {
-  try {
-    const { data } = await listAccountSubject({
-      current: 1,
-      size: 1000,
-      status: 0,
-    });
-    const options = toCascaderTree(data?.records || []);
-    if (options.length > 0) {
-      subjectOptions.value = options;
-      return;
-    }
-  } catch (error) {
-    // 鍏ㄥ眬鎷︽埅鍣ㄥ凡鎻愮ず锛屼笅闈㈣蛋鍏滃簳绉戠洰
-  }
-  subjectOptions.value = fallbackSubjects.map(item => ({ ...item, children: [] }));
-};
-
-const currentSubject = computed(() => {
-  const code = getSelectedSubjectCode(filters.subject);
-  if (!code) return null;
-  return findSubject(subjectOptions.value, code);
-});
-
-const getSelectedSubjectCode = (subjectValue) => {
-  if (Array.isArray(subjectValue)) {
-    return subjectValue.length ? subjectValue[subjectValue.length - 1] : "";
-  }
-  return subjectValue || "";
-};
 
 const findSubject = (options, code) => {
   for (const item of options) {
@@ -133,6 +133,71 @@
     }
   }
   return null;
+};
+
+const currentSubject = computed(() => {
+  if (!filters.subject) return null;
+  return findSubject(subjectOptions.value, filters.subject);
+});
+
+const getFirstSubjectCode = (nodes = []) => {
+  for (const item of nodes) {
+    if (item.code) return item.code;
+    if (item.children && item.children.length > 0) {
+      const childCode = getFirstSubjectCode(item.children);
+      if (childCode) return childCode;
+    }
+  }
+  return "";
+};
+
+const setDefaultSubjectSelection = async () => {
+  const firstCode = getFirstSubjectCode(subjectOptions.value);
+  if (!firstCode) {
+    filters.subject = "";
+    subjectTreeRef.value?.setCurrentKey(null);
+    return;
+  }
+  filters.subject = firstCode;
+  await nextTick();
+  subjectTreeRef.value?.setCurrentKey(firstCode);
+};
+
+const filterSubjectNode = (value, data) => {
+  const keyword = value?.trim();
+  if (!keyword) return true;
+  return `${data.code}${data.name}`.includes(keyword);
+};
+
+watch(subjectKeyword, (value) => {
+  subjectTreeRef.value?.filter(value || "");
+});
+
+const handleSubjectClick = async (data) => {
+  filters.subject = data.code;
+  await getTableData();
+};
+
+const loadSubjectOptions = async () => {
+  let options = [];
+  try {
+    const { data } = await listAccountSubject({
+      current: 1,
+      size: 1000,
+      status: 0,
+    });
+    options = toTree(data?.records || []);
+  } catch (error) {
+    // 鍏ㄥ眬鎷︽埅鍣ㄥ凡鎻愮ず锛屼笅闈㈣蛋鍏滃簳绉戠洰
+  }
+  if (options.length === 0) {
+    options = fallbackSubjects.map(item => ({ ...item, children: [] }));
+  }
+  subjectOptions.value = options;
+  await setDefaultSubjectSelection();
+  if (filters.subject) {
+    await getTableData();
+  }
 };
 
 const formatMoney = (value) => {
@@ -158,34 +223,16 @@
   }
 };
 
-const resetFilters = () => {
-  filters.subject = [];
-  filters.startMonth = "2024-01";
-  filters.endMonth = "2024-03";
+const resetFilters = async () => {
+  filters.startMonth = defaultMonth;
+  filters.endMonth = defaultMonth;
   dataList.value = [];
-};
-
-const getSummaries = (param) => {
-  const { columns, data } = param;
-  const sums = [];
-  columns.forEach((column, index) => {
-    if (index === 0) {
-      sums[index] = "鍚堣";
-      return;
-    }
-    if (column.property === "debit") {
-      const values = data.map(item => Number(item.debit));
-      const sum = values.reduce((prev, curr) => prev + curr, 0);
-      sums[index] = "楼" + formatMoney(sum);
-    } else if (column.property === "credit") {
-      const values = data.map(item => Number(item.credit));
-      const sum = values.reduce((prev, curr) => prev + curr, 0);
-      sums[index] = "楼" + formatMoney(sum);
-    } else {
-      sums[index] = "";
-    }
-  });
-  return sums;
+  subjectKeyword.value = "";
+  subjectTreeRef.value?.filter("");
+  await setDefaultSubjectSelection();
+  if (filters.subject) {
+    await getTableData();
+  }
 };
 
 const handlePrint = () => {
@@ -202,16 +249,37 @@
 </script>
 
 <style lang="scss" scoped>
-.ledger-header {
-  text-align: center;
-  margin-bottom: 20px;
-  h2 {
-    margin: 0 0 10px 0;
-  }
-  p {
-    color: #606266;
-    margin: 5px 0;
-  }
+.ledger-layout {
+  display: flex;
+  gap: 16px;
+}
+
+.subject-panel {
+  width: 260px;
+  flex-shrink: 0;
+  padding: 12px;
+  border: 1px solid #e4e7ed;
+  border-radius: 8px;
+  background-color: #fff;
+}
+
+.subject-tree-scroll {
+  height: 600px;
+  margin-top: 12px;
+}
+
+.subject-node {
+  display: inline-flex;
+  align-items: center;
+}
+
+.ledger-content {
+  flex: 1;
+  min-width: 0;
+}
+
+.filter-form {
+  margin-bottom: 12px;
 }
 
 .text-primary {
@@ -233,4 +301,12 @@
   color: #e6a23c;
   font-weight: bold;
 }
+
+.subject-panel :deep(.el-tree-node__content) {
+  height: 34px;
+}
+
+.subject-panel :deep(.el-tree-node.is-current > .el-tree-node__content) {
+  background-color: #f0f7ff;
+}
 </style>
diff --git a/src/views/financialManagement/voucher/index.vue b/src/views/financialManagement/voucher/index.vue
index 03c0856..1aa6f69 100644
--- a/src/views/financialManagement/voucher/index.vue
+++ b/src/views/financialManagement/voucher/index.vue
@@ -32,13 +32,13 @@
     <div class="table_list">
       <div class="actions">
         <div>
-          <el-statistic title="鍊熸柟鍚堣" :value="totalDebit" precision="2" prefix="楼" />
-          <el-statistic title="璐锋柟鍚堣" :value="totalCredit" precision="2" prefix="楼" style="margin-left: 30px;" />
+          <el-statistic title="鍊熸柟鍚堣" :value="totalDebit" :precision="2" prefix="楼" />
+          <el-statistic title="璐锋柟鍚堣" :value="totalCredit" :precision="2" prefix="楼" style="margin-left: 30px;" />
         </div>
         <div>
           <el-button type="primary" @click="add" icon="Plus">鏂板鍑瘉</el-button>
-          <el-button @click="handleImport" icon="Upload">瀵煎叆</el-button>
-          <el-button @click="handleOut" icon="Download">瀵煎嚭</el-button>
+          <!-- <el-button @click="handleImport" icon="Upload">瀵煎叆</el-button> -->
+          <!-- <el-button @click="handleOut" icon="Download">瀵煎嚭</el-button> -->
         </div>
       </div>
       <PIMTable
@@ -84,6 +84,11 @@
               <span class="label">鍑瘉瀛楋細</span>
               <el-select v-model="form.voucherPrefix" :disabled="isViewMode" style="width: 70px;">
                 <el-option label="璁�" value="璁�" />
+                <el-option label="鐜�" value="鐜�" />
+                <el-option label="閾�" value="閾�" />
+                <el-option label="杞�" value="杞�" />
+                <el-option label="鏀�" value="鏀�" />
+                <el-option label="浠�" value="浠�" />
               </el-select>
               <el-input v-model="form.voucherNum" :disabled="isViewMode" style="width: 60px;" />
               <span class="label" style="margin-left: 5px;">鍙�</span>
@@ -96,7 +101,6 @@
               <span class="label">闄勪欢锛�</span>
               <el-input-number v-model="form.attachmentCount" :disabled="isViewMode" :min="0" :controls="false" style="width: 60px;" />
               <span class="label" style="margin-left: 5px;">寮�</span>
-              <el-button type="primary" link :disabled="isViewMode" style="margin-left: 10px;">涓婁紶鏂囦欢</el-button>
             </div>
           </div>
           <div class="voucher-table">
@@ -153,12 +157,12 @@
                       @change="(val) => handleSubjectChange(val, rowIndex)"
                       @focus="selectRow(rowIndex)"
                     />
-                    <div class="subject-name">{{ entry.subjectName }}</div>
+                    <!-- <div class="subject-name">{{ entry.subjectName }}</div> -->
                   </td>
                   <!-- 鍊熸柟11鍒� -->
                   <template v-if="editingCell.row === rowIndex && editingCell.type === 'debit'">
                     <td colspan="11" class="debit-input-cell">
-                      <el-input-number ref="amountInputRef" v-model="entry.debit" :disabled="isViewMode" :min="0" :precision="2" :controls="false" size="small" @blur="finishEdit" class="full-width-input" />
+                      <el-input-number ref="amountInputRef" v-model="entry.debit" :disabled="isViewMode" :min="0" :precision="2" :controls="false" :value-on-clear="undefined" size="small" @blur="finishEdit" class="full-width-input" />
                     </td>
                   </template>
                   <template v-else>
@@ -169,7 +173,7 @@
                   <!-- 璐锋柟11鍒� -->
                   <template v-if="editingCell.row === rowIndex && editingCell.type === 'credit'">
                     <td colspan="11" class="credit-input-cell">
-                      <el-input-number ref="amountInputRef" v-model="entry.credit" :disabled="isViewMode" :min="0" :precision="2" :controls="false" size="small" @blur="finishEdit" class="full-width-input" />
+                      <el-input-number ref="amountInputRef" v-model="entry.credit" :disabled="isViewMode" :min="0" :precision="2" :controls="false" :value-on-clear="undefined" size="small" @blur="finishEdit" class="full-width-input" />
                     </td>
                   </template>
                   <template v-else>
@@ -217,7 +221,36 @@
               </el-select>
             </div>
           </div>
+          <!-- 缂栬緫妯″紡锛氫娇鐢� AttachmentUploadFile 涓婁紶缁勪欢 -->
+          <div class="voucher-attachment-upload" v-if="!isViewMode">
+            <div class="attachment-label">闄勪欢涓婁紶锛�</div>
+            <AttachmentUploadFile
+              v-model:fileList="form.attachments"
+              :disabled="isViewMode"
+              :limit="10"
+              :fileSize="50"
+              buttonText="鐐瑰嚮涓婁紶闄勪欢"
+              @change="handleAttachmentChange"
+            />
+          </div>
         </el-form>
+        <!-- 鏌ョ湅妯″紡锛氬睍绀洪檮浠跺垪琛紙鏀惧湪 el-form 澶栭潰锛岄伩鍏嶈 disabled锛� -->
+        <div class="voucher-attachment-upload" v-if="isViewMode && form.attachments?.length">
+          <div class="attachment-label">闄勪欢鍒楄〃锛�</div>
+          <el-table :data="form.attachments" border class="attachment-table">
+            <el-table-column label="闄勪欢鍚嶇О" show-overflow-tooltip>
+              <template #default="scope">
+                {{ scope.row.originalFilename || scope.row.name || scope.row.fileName || '鏈懡鍚嶆枃浠�' }}
+              </template>
+            </el-table-column>
+            <el-table-column fixed="right" label="鎿嶄綔" width="150" align="center">
+              <template #default="scope">
+                <el-button link type="primary" size="small" @click="previewFile(scope.row)">棰勮</el-button>
+                <el-button link type="primary" size="small" @click="downloadFile(scope.row)">涓嬭浇</el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </div>
       </div>
       <template #footer>
         <div>
@@ -226,6 +259,8 @@
         </div>
       </template>
     </FormDialog>
+    <!-- 鏂囦欢棰勮缁勪欢 -->
+    <FilePreview ref="filePreviewRef" />
   </div>
 </template>
 
@@ -233,6 +268,10 @@
 import { ref, reactive, onMounted, computed, nextTick } from "vue";
 import { ElMessage, ElMessageBox } from "element-plus";
 import FormDialog from "@/components/Dialog/FormDialog.vue";
+import AttachmentUploadFile from "@/components/AttachmentUpload/file/index.vue";
+import FileList from "@/components/Dialog/FileList.vue";
+import FilePreview from "@/components/filePreview/index.vue";
+import download from "@/plugins/download.js";
 import useUserStore from "@/store/modules/user";
 import { userListNoPageByTenantId } from "@/api/system/user";
 import { listAccountSubject } from "@/api/financialManagement/accountSubject";
@@ -284,6 +323,7 @@
 const isEdit = ref(false);
 const currentId = ref(null);
 const isViewMode = computed(() => dialogMode.value === "view");
+const filePreviewRef = ref(null);
 
 const fallbackSubjectTree = [
   { subjectCode: "1001", subjectName: "搴撳瓨鐜伴噾", balanceDirection: "鍊熸柟", children: [] },
@@ -326,8 +366,8 @@
   subjectName: "",
   balanceDirection: "",
   summary: "",
-  debit: 0,
-  credit: 0,
+  debit: undefined,
+  credit: undefined,
 });
 
 const createDefaultForm = () => ({
@@ -336,6 +376,7 @@
   voucherNum: "",
   voucherDate: "",
   attachmentCount: 0,
+  attachments: [],
   entries: [createEmptyEntry(), createEmptyEntry()],
   creator: getDefaultCreator(),
   remark: "",
@@ -490,6 +531,31 @@
   form.entries.push(createEmptyEntry());
 };
 
+const handleAttachmentChange = (fileList) => {
+  form.attachmentCount = fileList?.length || 0;
+};
+
+// 浣跨敤椤圭洰灏佽鐨� filePreview 缁勪欢棰勮鏂囦欢
+const previewFile = (row) => {
+  const url = row.previewURL || row.previewUrl || row.url;
+  if (url && filePreviewRef.value) {
+    filePreviewRef.value.open(url);
+  } else {
+    ElMessage.warning('鏂囦欢鍦板潃鏃犳晥锛屾棤娉曢瑙�');
+  }
+};
+
+// 浣跨敤椤圭洰灏佽鐨� download 鎻掍欢涓嬭浇鏂囦欢
+const downloadFile = (row) => {
+  const url = row.downloadURL || row.downloadUrl || row.url;
+  if (url) {
+    const filename = row.originalFilename || row.name || row.fileName || 'download';
+    download.byUrl(url, filename);
+  } else {
+    ElMessage.warning('鏂囦欢鍦板潃鏃犳晥锛屾棤娉曚笅杞�');
+  }
+};
+
 const selectRow = (index) => {
   selectedRowIndex.value = index;
 };
@@ -589,10 +655,13 @@
     const { data } = await getVoucherDetail(row.id);
     const detail = data || row;
     const parts = (detail.voucherNo || "").split("-");
-    Object.assign(form, createDefaultForm(), detail, {
+    const attachments = detail.storageBlobVOList || detail.storageBlobDTOs || detail.attachments || [];
+    Object.assign(form, createDefaultForm(), {
+      ...detail,
       voucherPrefix: parts[0] || "璁�",
       voucherNum: parts[1] || "",
       creator: detail.creator || getDefaultCreator(),
+      attachments,
       entries:
         detail.entries?.map(item => ({
           subjectCode: item.subjectCode || "",
@@ -696,6 +765,7 @@
         remark: form.remark,
         debit: totalDebitEntry.value,
         credit: totalCreditEntry.value,
+        storageBlobDTOs: form.attachments || [],
         entries: validEntries.map(entry => ({
           subjectCode: entry.subjectCode,
           subjectName: entry.subjectName,
@@ -801,6 +871,21 @@
   }
 }
 
+.voucher-attachment-upload {
+  margin-top: 15px;
+  padding: 0 10px;
+
+  .attachment-label {
+    font-size: 14px;
+    color: #606266;
+    margin-bottom: 10px;
+  }
+
+  .attachment-table {
+    border-radius: 4px;
+  }
+}
+
 .voucher-table {
   border: 1px solid #dcdfe6;
   border-right: none;
diff --git a/src/views/inventoryManagement/stockManagement/BatchNoQtyDetail.vue b/src/views/inventoryManagement/stockManagement/BatchNoQtyDetail.vue
new file mode 100644
index 0000000..a835ef4
--- /dev/null
+++ b/src/views/inventoryManagement/stockManagement/BatchNoQtyDetail.vue
@@ -0,0 +1,227 @@
+<template>
+  <el-dialog
+    v-model="isShow"
+    title="搴撳瓨璇︽儏"
+    width="90%"
+    top="3vh"
+    class="batch-no-qty-detail-dialog"
+    @close="closeModal"
+  >
+    <div class="detail-content">
+      <div class="detail-table-wrapper">
+        <el-table
+          :data="tableData"
+          border
+          v-loading="tableLoading"
+          style="width: 100%"
+          height="100%"
+        >
+          <el-table-column
+            label="浜у搧鍚嶇О"
+            prop="productName"
+            show-overflow-tooltip
+          />
+          <el-table-column label="瑙勬牸鍨嬪彿" prop="model" show-overflow-tooltip />
+          <el-table-column label="鍗曚綅" prop="unit" show-overflow-tooltip />
+          <el-table-column label="鎵瑰彿" prop="batchNo" show-overflow-tooltip />
+          <el-table-column
+            label="鍚堟牸搴撳瓨鏁伴噺"
+            prop="qualifiedQuantity"
+            show-overflow-tooltip
+          />
+          <el-table-column
+            label="涓嶅悎鏍煎簱瀛樻暟閲�"
+            prop="unQualifiedQuantity"
+            show-overflow-tooltip
+          />
+          <el-table-column
+            label="鍚堟牸鍐荤粨鏁伴噺"
+            prop="qualifiedLockedQuantity"
+            show-overflow-tooltip
+          />
+          <el-table-column
+            label="涓嶅悎鏍煎喕缁撴暟閲�"
+            prop="unQualifiedLockedQuantity"
+            show-overflow-tooltip
+          />
+          <el-table-column
+            label="搴撳瓨棰勮鏁伴噺"
+            prop="warnNum"
+            show-overflow-tooltip
+          />
+          <el-table-column label="澶囨敞" prop="remark" show-overflow-tooltip />
+          <el-table-column
+            label="鏈�杩戞洿鏂版椂闂�"
+            prop="updateTime"
+            show-overflow-tooltip
+          />
+          <el-table-column fixed="right" label="鎿嶄綔" min-width="180" align="center">
+            <template #default="scope">
+              <el-button
+                link
+                type="primary"
+                @click="handleSubtract(scope.row)"
+                :disabled="
+                  (scope.row.qualifiedUnLockedQuantity || 0) +
+                    (scope.row.qualifiedPendingOutQuantity || 0) <=
+                    0 &&
+                  (scope.row.unQualifiedUnLockedQuantity || 0) +
+                    (scope.row.unQualifiedPendingOutQuantity || 0) <=
+                    0
+                "
+                >棰嗙敤</el-button
+              >
+              <el-button
+                link
+                type="primary"
+                v-if="
+                  scope.row.unQualifiedUnLockedQuantity > 0 ||
+                  scope.row.qualifiedUnLockedQuantity > 0
+                "
+                @click="handleFrozen(scope.row)"
+                >鍐荤粨</el-button
+              >
+              <el-button
+                link
+                type="primary"
+                v-if="
+                  scope.row.qualifiedLockedQuantity > 0 ||
+                  scope.row.unQualifiedLockedQuantity > 0
+                "
+                @click="handleThaw(scope.row)"
+                >瑙e喕</el-button
+              >
+            </template>
+          </el-table-column>
+        </el-table>
+      </div>
+      <pagination
+        v-show="total > 0"
+        :total="total"
+        layout="total, sizes, prev, pager, next, jumper"
+        :page="page.current"
+        :limit="page.size"
+        @pagination="paginationChange"
+      />
+    </div>
+  </el-dialog>
+</template>
+
+<script setup>
+import pagination from "@/components/PIMTable/Pagination.vue";
+import { computed, reactive, ref, watch } from "vue";
+import { getStockInventoryBatchNoQty } from "@/api/inventoryManagement/stockInventory.js";
+
+const props = defineProps({
+  visible: {
+    type: Boolean,
+    required: true,
+  },
+  record: {
+    type: Object,
+    default: () => ({}),
+  },
+});
+
+const emit = defineEmits(["update:visible", "subtract", "frozen", "thaw"]);
+
+const isShow = computed({
+  get() {
+    return props.visible;
+  },
+  set(val) {
+    emit("update:visible", val);
+  },
+});
+
+const tableData = ref([]);
+const tableLoading = ref(false);
+const total = ref(0);
+const page = reactive({
+  current: 1,
+  size: 20,
+});
+
+const getList = () => {
+  if (!props.record?.productId || !props.record?.productModelId) {
+    tableData.value = [];
+    total.value = 0;
+    return;
+  }
+
+  tableLoading.value = true;
+  getStockInventoryBatchNoQty({
+    current: page.current,
+    size: page.size,
+    productId: props.record.productId,
+    productModelId: props.record.productModelId,
+  })
+    .then((res) => {
+      tableData.value = res.data?.records || [];
+      total.value = res.data?.total || 0;
+    })
+    .finally(() => {
+      tableLoading.value = false;
+    });
+};
+
+const paginationChange = (obj) => {
+  page.current = obj.page;
+  page.size = obj.limit;
+  getList();
+};
+
+const handleSubtract = (row) => {
+  emit("subtract", row);
+};
+
+const handleFrozen = (row) => {
+  emit("frozen", row);
+};
+
+const handleThaw = (row) => {
+  emit("thaw", row);
+};
+
+const closeModal = () => {
+  isShow.value = false;
+  page.current = 1;
+  page.size = 20;
+  tableData.value = [];
+  total.value = 0;
+};
+
+watch(
+  () => props.visible,
+  (visible) => {
+    if (!visible) {
+      return;
+    }
+    page.current = 1;
+    getList();
+  },
+  { immediate: true }
+);
+</script>
+
+<style scoped lang="scss">
+.detail-content {
+  display: flex;
+  flex-direction: column;
+  height: calc(100vh - 170px);
+  min-height: 520px;
+}
+
+.detail-table-wrapper {
+  flex: 1;
+  min-height: 0;
+}
+
+:deep(.batch-no-qty-detail-dialog .el-dialog) {
+  max-width: calc(100vw - 48px);
+}
+
+:deep(.batch-no-qty-detail-dialog .el-dialog__body) {
+  padding-top: 12px;
+}
+</style>
diff --git a/src/views/inventoryManagement/stockManagement/Record.vue b/src/views/inventoryManagement/stockManagement/Record.vue
index 7c0a461..3b532f8 100644
--- a/src/views/inventoryManagement/stockManagement/Record.vue
+++ b/src/views/inventoryManagement/stockManagement/Record.vue
@@ -3,143 +3,233 @@
     <div class="search_form mb10">
       <div>
         <span class="search_title ml10">浜у搧澶х被锛�</span>
-        <el-input v-model="searchForm.productName"
-                  style="width: 240px"
-                  placeholder="璇疯緭鍏�"
-                  clearable/>
-        <el-button type="primary" @click="handleQuery" style="margin-left: 10px">鎼滅储</el-button>
+        <el-input
+          v-model="searchForm.productName"
+          style="width: 240px"
+          placeholder="璇疯緭鍏�"
+          clearable
+        />
+        <el-button type="primary" @click="handleQuery" style="margin-left: 10px"
+          >鎼滅储</el-button
+        >
       </div>
       <div>
-         <el-button type="primary" @click="isShowNewModal = true">鏂板搴撳瓨</el-button>
-        <el-button type="info" plain icon="Upload" @click="isShowImportModal = true">
+        <el-button type="primary" @click="isShowNewModal = true"
+          >鏂板搴撳瓨</el-button
+        >
+        <el-button
+          type="info"
+          plain
+          icon="Upload"
+          @click="isShowImportModal = true"
+        >
           瀵煎叆搴撳瓨
         </el-button>
         <el-button @click="handleOut">瀵煎嚭</el-button>
       </div>
     </div>
     <div class="table_list">
-      <el-table :data="tableData" border v-loading="tableLoading" @selection-change="handleSelectionChange"
-        :expand-row-keys="expandedRowKeys" :row-key="(row, index) => index" style="width: 100%"
-        :row-class-name="tableRowClassName" height="calc(100vh - 18.5em)">
+      <el-table
+        :data="tableData"
+        border
+        v-loading="tableLoading"
+        @selection-change="handleSelectionChange"
+        :expand-row-keys="expandedRowKeys"
+        :row-key="(row, index) => index"
+        style="width: 100%"
+        :row-class-name="tableRowClassName"
+        height="calc(100vh - 18.5em)"
+      >
         <el-table-column align="center" type="selection" width="55" />
         <el-table-column align="center" label="搴忓彿" type="index" width="60" />
-        <el-table-column label="浜у搧澶х被" prop="productName" show-overflow-tooltip />
+        <el-table-column
+          label="浜у搧鍚嶇О"
+          prop="productName"
+          show-overflow-tooltip
+        />
         <el-table-column label="瑙勬牸鍨嬪彿" prop="model" show-overflow-tooltip />
         <el-table-column label="鍗曚綅" prop="unit" show-overflow-tooltip />
         <el-table-column label="鎵瑰彿" prop="batchNo" show-overflow-tooltip />
-        <el-table-column label="鍚堟牸搴撳瓨鏁伴噺" prop="qualifiedQuantity" show-overflow-tooltip />
-        <el-table-column label="涓嶅悎鏍煎簱瀛樻暟閲�" prop="unQualifiedQuantity" show-overflow-tooltip />
-        <el-table-column label="鍚堟牸鍐荤粨鏁伴噺" prop="qualifiedLockedQuantity" show-overflow-tooltip />
-        <el-table-column label="涓嶅悎鏍煎喕缁撴暟閲�" prop="unQualifiedLockedQuantity" show-overflow-tooltip />
-        <el-table-column label="搴撳瓨棰勮鏁伴噺" prop="warnNum"  show-overflow-tooltip />
-        <el-table-column label="澶囨敞" prop="remark"  show-overflow-tooltip />
-        <el-table-column label="鏈�杩戞洿鏂版椂闂�" prop="updateTime" show-overflow-tooltip />
-        <el-table-column fixed="right" label="鎿嶄綔" min-width="90" align="center">
+        <el-table-column
+          label="鍚堟牸搴撳瓨鏁伴噺"
+          prop="qualifiedQuantity"
+          show-overflow-tooltip
+        />
+        <el-table-column
+          label="涓嶅悎鏍煎簱瀛樻暟閲�"
+          prop="unQualifiedQuantity"
+          show-overflow-tooltip
+        />
+        <el-table-column
+          label="鍚堟牸鍐荤粨鏁伴噺"
+          prop="qualifiedLockedQuantity"
+          show-overflow-tooltip
+        />
+        <el-table-column
+          label="涓嶅悎鏍煎喕缁撴暟閲�"
+          prop="unQualifiedLockedQuantity"
+          show-overflow-tooltip
+        />
+        <el-table-column
+          label="搴撳瓨棰勮鏁伴噺"
+          prop="warnNum"
+          show-overflow-tooltip
+        />
+        <el-table-column label="澶囨敞" prop="remark" show-overflow-tooltip />
+        <el-table-column
+          label="鏈�杩戞洿鏂版椂闂�"
+          prop="updateTime"
+          show-overflow-tooltip
+        />
+        <el-table-column
+          fixed="right"
+          label="鎿嶄綔"
+          min-width="80"
+          align="center"
+        >
           <template #default="scope">
-            <el-button link type="primary" @click="showSubtractModal(scope.row)" :disabled="((scope.row.qualifiedUnLockedQuantity || 0) + (scope.row.qualifiedPendingOutQuantity || 0) <= 0) && ((scope.row.unQualifiedUnLockedQuantity || 0) + (scope.row.unQualifiedPendingOutQuantity || 0) <= 0)">棰嗙敤</el-button>
-            <el-button link type="primary" v-if="scope.row.unQualifiedUnLockedQuantity > 0 || scope.row.qualifiedUnLockedQuantity > 0" @click="showFrozenModal(scope.row)">鍐荤粨</el-button>
-            <el-button link type="primary" v-if="scope.row.qualifiedLockedQuantity > 0 || scope.row.unQualifiedLockedQuantity > 0" @click="showThawModal(scope.row)">瑙e喕</el-button>
+            <el-button
+              link
+              type="primary"
+              @click="showDetailModal(scope.row)"
+              >璇︽儏</el-button
+            >
           </template>
         </el-table-column>
       </el-table>
-      <pagination v-show="total > 0" :total="total" layout="total, sizes, prev, pager, next, jumper"
-        :page="page.current" :limit="page.size" @pagination="paginationChange" />
+      <pagination
+        v-show="total > 0"
+        :total="total"
+        layout="total, sizes, prev, pager, next, jumper"
+        :page="page.current"
+        :limit="page.size"
+        @pagination="paginationChange"
+      />
     </div>
-    <new-stock-inventory v-if="isShowNewModal"
-                 v-model:visible="isShowNewModal"
-                 :top-product-parent-id="props.productId"
-                 @completed="handleQuery" />
+    <batch-no-qty-detail
+      v-if="isShowDetailModal"
+      v-model:visible="isShowDetailModal"
+      :record="record"
+      @subtract="handleDetailSubtract"
+      @frozen="handleDetailFrozen"
+      @thaw="handleDetailThaw"
+    />
+    <new-stock-inventory
+      v-if="isShowNewModal"
+      v-model:visible="isShowNewModal"
+      :top-product-parent-id="props.productId"
+      @completed="handleQuery"
+    />
 
-    <subtract-stock-inventory v-if="isShowSubtractModal"
-                 v-model:visible="isShowSubtractModal"
-                 :record="record"
-                 :type="record.stockType"
-                 @completed="handleQuery" />
+    <subtract-stock-inventory
+      v-if="isShowSubtractModal"
+      v-model:visible="isShowSubtractModal"
+      :record="record"
+      :type="record.stockType"
+      @completed="handleQuery"
+    />
     <!-- 瀵煎叆搴撳瓨-->
-    <import-stock-inventory v-if="isShowImportModal"
-                 v-model:visible="isShowImportModal"
-                 type="qualified"
-                 @uploadSuccess="handleQuery" />
+    <import-stock-inventory
+      v-if="isShowImportModal"
+      v-model:visible="isShowImportModal"
+      type="qualified"
+      @uploadSuccess="handleQuery"
+    />
     <!-- 鍐荤粨/瑙e喕搴撳瓨-->
-    <frozen-and-thaw-stock-inventory v-if="isShowFrozenAndThawModal"
-                 v-model:visible="isShowFrozenAndThawModal"
-                 :record="record"
-                 :operation-type="operationType"
-                 :type="record.stockType"
-                 @completed="handleQuery" />
+    <frozen-and-thaw-stock-inventory
+      v-if="isShowFrozenAndThawModal"
+      v-model:visible="isShowFrozenAndThawModal"
+      :record="record"
+      :operation-type="operationType"
+      :type="record.stockType"
+      @completed="handleQuery"
+    />
   </div>
 </template>
 
 <script setup>
-import pagination from '@/components/PIMTable/Pagination.vue'
-import { ref, reactive, toRefs, onMounted, getCurrentInstance } from 'vue'
-import {ElMessage, ElMessageBox} from "element-plus";
-import {
-  getStockInventoryListPageCombined
-} from "@/api/inventoryManagement/stockInventory.js";
+import pagination from "@/components/PIMTable/Pagination.vue";
+import { ref, reactive, toRefs, onMounted, getCurrentInstance } from "vue";
+import { ElMessage, ElMessageBox } from "element-plus";
+import { getStockInventoryListPageCombined } from "@/api/inventoryManagement/stockInventory.js";
 const props = defineProps({
   productId: {
     type: Number,
     required: true,
-    default: 0
-  }
+    default: 0,
+  },
 });
 
-const NewStockInventory = defineAsyncComponent(() => import("@/views/inventoryManagement/stockManagement/New.vue"));
-const SubtractStockInventory = defineAsyncComponent(() => import("@/views/inventoryManagement/stockManagement/Subtract.vue"));
-const ImportStockInventory = defineAsyncComponent(() => import("@/views/inventoryManagement/stockManagement/Import.vue"));
-const FrozenAndThawStockInventory = defineAsyncComponent(() => import("@/views/inventoryManagement/stockManagement/FrozenAndThaw.vue"));
-const { proxy } = getCurrentInstance()
-const tableData = ref([])
-const selectedRows = ref([])
-const record = ref({})
-const tableLoading = ref(false)
+const NewStockInventory = defineAsyncComponent(() =>
+  import("@/views/inventoryManagement/stockManagement/New.vue")
+);
+const SubtractStockInventory = defineAsyncComponent(() =>
+  import("@/views/inventoryManagement/stockManagement/Subtract.vue")
+);
+const ImportStockInventory = defineAsyncComponent(() =>
+  import("@/views/inventoryManagement/stockManagement/Import.vue")
+);
+const FrozenAndThawStockInventory = defineAsyncComponent(() =>
+  import("@/views/inventoryManagement/stockManagement/FrozenAndThaw.vue")
+);
+const BatchNoQtyDetail = defineAsyncComponent(() =>
+  import("@/views/inventoryManagement/stockManagement/BatchNoQtyDetail.vue")
+);
+const { proxy } = getCurrentInstance();
+const tableData = ref([]);
+const selectedRows = ref([]);
+const record = ref({});
+const tableLoading = ref(false);
 const page = reactive({
   current: 1,
   size: 100,
-})
-const total = ref(0)
+});
+const total = ref(0);
 // 鏄惁鏄剧ず鏂板寮规
-const isShowNewModal = ref(false)
+const isShowNewModal = ref(false);
 // 鏄惁鏄剧ず棰嗙敤寮规
-const isShowSubtractModal = ref(false)
+const isShowSubtractModal = ref(false);
 // 鏄惁鏄剧ず鍐荤粨/瑙e喕寮规
-const isShowFrozenAndThawModal = ref(false)
+const isShowFrozenAndThawModal = ref(false);
+// 鏄惁鏄剧ず璇︽儏寮规
+const isShowDetailModal = ref(false);
 // 鎿嶄綔绫诲瀷
-const operationType = ref('frozen')
+const operationType = ref("frozen");
 // 鏄惁鏄剧ず瀵煎叆寮规
-const isShowImportModal = ref(false)
+const isShowImportModal = ref(false);
 const data = reactive({
   searchForm: {
-    productName: '',
+    productName: "",
     topParentProductId: props.productId,
-  }
-})
-const { searchForm } = toRefs(data)
+  },
+});
+const { searchForm } = toRefs(data);
 
 // 鏌ヨ鍒楄〃
 /** 鎼滅储鎸夐挳鎿嶄綔 */
 const handleQuery = () => {
-  page.current = 1
-  getList()
-}
+  page.current = 1;
+  getList();
+};
 const paginationChange = (obj) => {
   page.current = obj.page;
   page.size = obj.limit;
-  getList()
-}
+  getList();
+};
 const getList = () => {
-  tableLoading.value = true
-  getStockInventoryListPageCombined({ ...searchForm.value, ...page }).then(res => {
-    tableLoading.value = false
-    tableData.value = res.data.records
-    total.value = res.data.total
-    // 鏁版嵁鍔犺浇瀹屾垚鍚庢鏌ュ簱瀛�
-    // checkStockAndCreatePurchase();
-  }).catch(() => {
-    tableLoading.value = false
-  })
-}
+  tableLoading.value = true;
+  getStockInventoryListPageCombined({ ...searchForm.value, ...page })
+    .then((res) => {
+      tableLoading.value = false;
+      tableData.value = res.data.records;
+      total.value = res.data.total;
+      // 鏁版嵁鍔犺浇瀹屾垚鍚庢鏌ュ簱瀛�
+      // checkStockAndCreatePurchase();
+    })
+    .catch(() => {
+      tableLoading.value = false;
+    });
+};
 
 const handleFileSuccess = (response) => {
   const { code, msg } = response;
@@ -154,61 +244,89 @@
 
 // 鐐瑰嚮棰嗙敤
 const showSubtractModal = (row) => {
-  record.value = row
-  isShowSubtractModal.value = true
-}
+  record.value = row;
+  isShowSubtractModal.value = true;
+};
+
+// 鐐瑰嚮璇︽儏
+const showDetailModal = (row) => {
+  if (!row?.productId || !row?.productModelId) {
+    proxy.$modal.msgError("褰撳墠鏁版嵁缂哄皯浜у搧ID鎴栬鏍煎瀷鍙稩D");
+    return;
+  }
+  record.value = row;
+  isShowDetailModal.value = true;
+};
+
+const handleDetailSubtract = (row) => {
+  isShowDetailModal.value = false;
+  showSubtractModal(row);
+};
+
+const handleDetailFrozen = (row) => {
+  isShowDetailModal.value = false;
+  showFrozenModal(row);
+};
+
+const handleDetailThaw = (row) => {
+  isShowDetailModal.value = false;
+  showThawModal(row);
+};
 
 // 鐐瑰嚮鍐荤粨
 const showFrozenModal = (row) => {
-  record.value = row
-  isShowFrozenAndThawModal.value = true
-  operationType.value = 'frozen'
-}
+  record.value = row;
+  isShowFrozenAndThawModal.value = true;
+  operationType.value = "frozen";
+};
 
 // 鐐瑰嚮瑙e喕
 const showThawModal = (row) => {
-  record.value = row
-  isShowFrozenAndThawModal.value = true
-  operationType.value = 'thaw'
-}
+  record.value = row;
+  isShowFrozenAndThawModal.value = true;
+  operationType.value = "thaw";
+};
 
 // 琛ㄦ牸閫夋嫨鏁版嵁
 const handleSelectionChange = (selection) => {
   // 杩囨护鎺夊瓙鏁版嵁
-  selectedRows.value = selection.filter(item => item.id);
-  console.log('selection', selectedRows.value)
-}
-const expandedRowKeys = ref([])
+  selectedRows.value = selection.filter((item) => item.id);
+  console.log("selection", selectedRows.value);
+};
+const expandedRowKeys = ref([]);
 
 // 琛ㄦ牸琛岀被鍚�
 const tableRowClassName = ({ row }) => {
   const stock = Number(row?.qualifiedUnLockedQuantity ?? 0);
   const warn = Number(row?.warnNum ?? 0);
   if (!Number.isFinite(stock) || !Number.isFinite(warn)) {
-    return '';
+    return "";
   }
-  return stock < warn ? 'row-low-stock' : '';
+  return stock < warn ? "row-low-stock" : "";
 };
 
 // 瀵煎嚭
 const handleOut = () => {
-  ElMessageBox.confirm(
-    '鏄惁纭瀵煎嚭锛�',
-    '瀵煎嚭', {
-    confirmButtonText: '纭',
-    cancelButtonText: '鍙栨秷',
-    type: 'warning',
-  }
-  ).then(() => {
-    proxy.download("/stockInventory/exportStockInventory", {topParentProductId: props.productId}, '搴撳瓨淇℃伅.xlsx')
-  }).catch(() => {
-    proxy.$modal.msg("宸插彇娑�")
+  ElMessageBox.confirm("鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
+    confirmButtonText: "纭",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
   })
-}
+    .then(() => {
+      proxy.download(
+        "/stockInventory/exportStockInventory",
+        { topParentProductId: props.productId },
+        "搴撳瓨淇℃伅.xlsx"
+      );
+    })
+    .catch(() => {
+      proxy.$modal.msg("宸插彇娑�");
+    });
+};
 
 onMounted(() => {
-  getList()
-})
+  getList();
+});
 </script>
 
 <style scoped lang="scss">
diff --git a/src/views/personnelManagement/contractManagement/index.vue b/src/views/personnelManagement/contractManagement/index.vue
index a55a502..074b9ac 100644
--- a/src/views/personnelManagement/contractManagement/index.vue
+++ b/src/views/personnelManagement/contractManagement/index.vue
@@ -23,6 +23,12 @@
         :total="page.total"></PIMTable>
     </div>
     <form-dia ref="formDia" @close="handleQuery"></form-dia>
+    <renew-contract
+        v-if="isShowRenewContractModal"
+        v-model:visible="isShowRenewContractModal"
+        :id="id"
+        @completed="handleQuery"
+    />
 
     <!-- 鍚堝悓瀵煎叆瀵硅瘽妗� -->
     <el-dialog
@@ -71,8 +77,9 @@
 
 <script setup>
 import { Search } from "@element-plus/icons-vue";
-import { onMounted, ref } from "vue";
+import { onMounted, ref, defineAsyncComponent } from "vue";
 import FormDia from "@/views/personnelManagement/contractManagement/components/formDia.vue";
+const RenewContract = defineAsyncComponent(() => import("@/views/personnelManagement/employeeRecord/components/RenewContract.vue"));
 import { ElMessageBox } from "element-plus";
 import { staffOnJobListPage } from "@/api/personnelManagement/staffOnJob.js";
 import dayjs from "dayjs";
@@ -183,7 +190,7 @@
     label: "鎿嶄綔",
     align: "center",
     fixed: 'right',
-    width: 120,
+    width: 160,
     operation: [
       {
         name: "璇︽儏",
@@ -191,11 +198,22 @@
         clickFun: (row) => {
           openForm("edit", row);
         },
+      },
+      {
+        name: "缁鍚堝悓",
+        type: "text",
+        showHide: row => row.staffState === 1,
+        clickFun: (row) => {
+          isShowRenewContractModal.value = true;
+          id.value = row.id;
+        },
       }
     ],
   },
 ]);
 const filesDia = ref()
+const isShowRenewContractModal = ref(false);
+const id = ref(0);
 const tableData = ref([]);
 const selectedRows = ref([]);
 const tableLoading = ref(false);
diff --git a/src/views/personnelManagement/employeeRecord/index.vue b/src/views/personnelManagement/employeeRecord/index.vue
index cd4ecf5..5dda8c7 100644
--- a/src/views/personnelManagement/employeeRecord/index.vue
+++ b/src/views/personnelManagement/employeeRecord/index.vue
@@ -52,16 +52,14 @@
           :tableLoading="tableLoading"
           @pagination="pagination"
           :total="page.total"
-      ></PIMTable>
+      >
+        <template #positiveDate="{ row }">
+          <span :class="getPositiveDateClass(row.positiveDate)">{{ row.positiveDate }}</span>
+        </template>
+      </PIMTable>
     </div>
     <show-form-dia ref="formDia" @close="handleQuery"></show-form-dia>
     <new-or-edit-form-dia ref="formDiaNewOrEditFormDia" @close="handleQuery"></new-or-edit-form-dia>
-    <renew-contract
-        v-if="isShowRenewContractModal"
-        v-model:visible="isShowRenewContractModal"
-        :id="id"
-        @completed="handleQuery"
-    />
     
     <!-- 瀵煎叆瀵硅瘽妗� -->
     <el-dialog :title="upload.title" v-model="upload.open" width="400px" append-to-body>
@@ -107,7 +105,6 @@
 
 const NewOrEditFormDia = defineAsyncComponent(() => import("@/views/personnelManagement/employeeRecord/components/NewOrEditFormDia.vue"));
 const ShowFormDia = defineAsyncComponent(() => import( "@/views/personnelManagement/employeeRecord/components/Show.vue"));
-const RenewContract = defineAsyncComponent(() => import( "@/views/personnelManagement/employeeRecord/components/RenewContract.vue"));
 
 const data = reactive({
   searchForm: {
@@ -119,8 +116,6 @@
   deptOptions: [],
 });
 const { searchForm, deptOptions } = toRefs(data);
-const isShowRenewContractModal = ref(false);
-const id = ref(0);
 const tableColumn = ref([
   {
     label: "鐘舵��",
@@ -177,6 +172,13 @@
     width: 120,
   },
   {
+    label: "杞鏃ユ湡",
+    prop: "positiveDate",
+    width: 120,
+    dataType: "slot",
+    slot: "positiveDate",
+  },
+  {
     label: "骞撮緞",
     prop: "age",
   },
@@ -208,22 +210,6 @@
           openFormNewOrEditFormDia("edit", row);
         },
       },
-      {
-        name: "缁鍚堝悓",
-        type: "text",
-        showHide: row => row.staffState === 1,
-        clickFun: (row) => {
-          isShowRenewContractModal.value = true;
-          id.value = row.id;
-        },
-      },
-      // {
-      //   name: "璇︽儏",
-      //   type: "text",
-      //   clickFun: (row) => {
-      //     openForm("edit", row);
-      //   },
-      // },
     ],
   },
 ]);
@@ -253,6 +239,22 @@
   // 涓婁紶鐨勫湴鍧�
   url: import.meta.env.VITE_APP_BASE_API + "/staff/staffOnJob/import"
 })
+
+// 鍒ゆ柇杞鏃ユ湡鏄惁鍦�7澶╁唴
+const getPositiveDateClass = (positiveDate) => {
+  if (!positiveDate) return '';
+  const today = new Date();
+  today.setHours(0, 0, 0, 0);
+  const positive = new Date(positiveDate);
+  positive.setHours(0, 0, 0, 0);
+  const diffTime = positive - today;
+  const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
+  // 7澶╁唴杞锛堝寘鎷粖澶╋級鏄剧ず璀﹀憡鑹�
+  if (diffDays >= 0 && diffDays <= 7) {
+    return 'positive-date-warning';
+  }
+  return '';
+};
 
 const fetchDeptOptions = () => {
     deptTreeSelect().then(response => {
@@ -402,4 +404,9 @@
 .search_title2 {
   margin-left: 10px;
 }
+
+.positive-date-warning {
+  color: #f56c6c;
+  font-weight: bold;
+}
 </style>
diff --git a/src/views/procurementManagement/procurementLedger/index.vue b/src/views/procurementManagement/procurementLedger/index.vue
index cffdcc6..adf7b6e 100644
--- a/src/views/procurementManagement/procurementLedger/index.vue
+++ b/src/views/procurementManagement/procurementLedger/index.vue
@@ -693,6 +693,7 @@
   const salesContractList = ref([]);
   const supplierList = ref([]);
   const tableLoading = ref(false);
+  const recordId = ref();
   const fileListDialogVisible = ref(false);
   const page = reactive({
     current: 1,
diff --git a/src/views/procurementManagement/purchaseReturnOrder/New.vue b/src/views/procurementManagement/purchaseReturnOrder/New.vue
index c412ca7..2c6801d 100644
--- a/src/views/procurementManagement/purchaseReturnOrder/New.vue
+++ b/src/views/procurementManagement/purchaseReturnOrder/New.vue
@@ -261,8 +261,11 @@
                                prop="unQuantity"
                                width="130" />
               <el-table-column label="宸查��璐ф暟閲�"
-                               prop="totalReturnNum"
-                               width="130" />
+                               width="130">
+                <template #default="scope">
+                  {{ calcAlreadyReturned(scope.row) }}
+                </template>
+              </el-table-column>
               <el-table-column label="閫�璐ф暟閲�"
                                prop="returnQuantity"
                                width="180">
@@ -526,6 +529,14 @@
   return Number.isNaN(num) ? 0 : num
 }
 
+/** 宸查��璐ф暟閲� = 鍏ュ簱琛屾�绘暟閲� 鈭� 褰撳墠鍙��璐ф暟閲忥紙鍓╀綑锛� */
+const calcAlreadyReturned = (row) => {
+  const total = Number(row?.stockInNum ?? row?.totalQuantity ?? row?.quantity ?? 0)
+  const un = Number(row?.unQuantity ?? 0)
+  if (!Number.isFinite(total) || !Number.isFinite(un)) return 0
+  return Math.max(total - un, 0)
+}
+
 const getReturnTotal = (row) => {
   const qty = toNumber(row?.returnQuantity)
   const unitPrice = toNumber(row?.taxInclusiveUnitPrice)
diff --git a/src/views/procurementManagement/purchaseReturnOrder/ProductList.vue b/src/views/procurementManagement/purchaseReturnOrder/ProductList.vue
index 24d64c6..27fae4a 100644
--- a/src/views/procurementManagement/purchaseReturnOrder/ProductList.vue
+++ b/src/views/procurementManagement/purchaseReturnOrder/ProductList.vue
@@ -38,8 +38,11 @@
                            prop="unQuantity"
                            width="130" />
           <el-table-column label="宸查��璐ф暟閲�"
-                           prop="totalReturnNum"
-                           width="130" />
+                           width="130">
+            <template #default="scope">
+              {{ calcAlreadyReturned(scope.row) }}
+            </template>
+          </el-table-column>
           <!-- <el-table-column label="搴撳瓨棰勮鏁伴噺"
                            prop="warnNum"
                            width="120"
@@ -116,6 +119,14 @@
   return parseFloat(cellValue).toFixed(2);
 };
 
+/** 宸查��璐ф暟閲� = 鍏ュ簱琛屾�绘暟閲� 鈭� 褰撳墠鍙��璐ф暟閲忥紙鍓╀綑锛� */
+const calcAlreadyReturned = (row) => {
+  const total = Number(row?.stockInNum ?? row?.totalQuantity ?? row?.quantity ?? 0)
+  const un = Number(row?.unQuantity ?? 0)
+  if (!Number.isFinite(total) || !Number.isFinite(un)) return 0
+  return Math.max(total - un, 0)
+}
+
 const handleChangeSelection = (val) => {
   selectedRows.value = val;
 }
diff --git a/src/views/procurementManagement/purchaseReturnOrder/index.vue b/src/views/procurementManagement/purchaseReturnOrder/index.vue
index 3986f03..f8866e1 100644
--- a/src/views/procurementManagement/purchaseReturnOrder/index.vue
+++ b/src/views/procurementManagement/purchaseReturnOrder/index.vue
@@ -146,8 +146,11 @@
                            prop="unQuantity"
                            width="100" />
           <el-table-column label="宸查��璐ф暟閲�"
-                           prop="totalReturnNum"
-                           width="100" />
+                           width="100">
+            <template #default="scope">
+              {{ calcAlreadyReturned(scope.row) }}
+            </template>
+          </el-table-column>
           <!-- <el-table-column label="搴撳瓨棰勮鏁伴噺" prop="warnNum" width="120" /> -->
           <!-- <el-table-column label="绋庣巼(%)" prop="taxRate" width="90" /> -->
           <el-table-column
@@ -458,6 +461,14 @@
   return num.toFixed(2);
 };
 
+/** 宸查��璐ф暟閲� = 鍏ュ簱琛屾�绘暟閲� 鈭� 褰撳墠鍙��璐ф暟閲忥紙鍓╀綑锛� */
+const calcAlreadyReturned = (row) => {
+  const total = Number(row?.stockInNum ?? row?.totalQuantity ?? row?.quantity ?? 0);
+  const un = Number(row?.unQuantity ?? 0);
+  if (!Number.isFinite(total) || !Number.isFinite(un)) return 0;
+  return Math.max(total - un, 0);
+};
+
 onMounted(() => {
   getList();
 });
diff --git a/src/views/productionManagement/processRoute/processRouteItem/index.vue b/src/views/productionManagement/processRoute/processRouteItem/index.vue
index 99d4ab1..83ee60a 100644
--- a/src/views/productionManagement/processRoute/processRouteItem/index.vue
+++ b/src/views/productionManagement/processRoute/processRouteItem/index.vue
@@ -315,7 +315,7 @@
                                      :step="1"
                                      controls-position="right"
                                      style="width: 100%"
-                                     @change="handleUnitQuantityChange(row)"
+                                     @change="handleUnitQuantityChange"
                                      :disabled="!bomDataValue.isEdit || bomDataValue.dataList.some(item => (item).tempId === row.tempId)" />
                   </el-form-item>
                 </template>
@@ -333,7 +333,7 @@
                                      :step="1"
                                      controls-position="right"
                                      style="width: 100%"
-                                     :disabled="!bomDataValue.isEdit || bomDataValue.dataList.some(item => (item).tempId === row.tempId)" />
+                                     :disabled="true" />
                   </el-form-item>
                 </template>
               </el-table-column>
@@ -1089,6 +1089,53 @@
       }
     });
   };
+
+  const toQuantityNumber = value => {
+    const numberValue = Number(value);
+    if (!Number.isFinite(numberValue)) {
+      return 0;
+    }
+    return Number(numberValue.toFixed(2));
+  };
+
+  const syncDemandedQuantityTree = (items, parentDemandedQuantity = null) => {
+    items.forEach(item => {
+      if (parentDemandedQuantity !== null) {
+        item.demandedQuantity = toQuantityNumber(
+          parentDemandedQuantity * toQuantityNumber(item.unitQuantity)
+        );
+      }
+
+      if (Array.isArray(item.children) && item.children.length > 0) {
+        syncDemandedQuantityTree(
+          item.children,
+          toQuantityNumber(item.demandedQuantity)
+        );
+      }
+    });
+  };
+
+  const recalculateDemandedQuantities = () => {
+    if (pageType.value !== "order") {
+      return;
+    }
+
+    const rootDemandedQuantity = routeInfo.value.quantity;
+    if (
+      rootDemandedQuantity === undefined ||
+      rootDemandedQuantity === null ||
+      rootDemandedQuantity === ""
+    ) {
+      syncDemandedQuantityTree(bomDataValue.value.dataList);
+      return;
+    }
+
+    syncDemandedQuantityTree(
+      bomDataValue.value.dataList,
+      toQuantityNumber(rootDemandedQuantity)
+    );
+  };
+
   const processChange = value => {
     processOptions.value.forEach(item => {
       if (item.id == value) {
@@ -1117,6 +1164,7 @@
       );
       bomDataValue.value.dataList = data || [];
       normalizeTreeData(bomDataValue.value.dataList);
+      recalculateDemandedQuantities();
     } catch (err) {
       console.error("鑾峰彇BOM鏁版嵁澶辫触锛�", err);
     }
@@ -1212,10 +1260,8 @@
     });
   };
 
-  const handleUnitQuantityChange = row => {
-    if (routeInfo.value.quantity && routeInfo.value.quantity !== 0) {
-      row.demandedQuantity = (row.unitQuantity || 0) * routeInfo.value.quantity;
-    }
+  const handleUnitQuantityChange = () => {
+    recalculateDemandedQuantities();
   };
 
   const addchildItem = (item, tempId) => {
@@ -1236,14 +1282,12 @@
           "",
         operationName: "",
         unitQuantity: 1,
-        demandedQuantity:
-          routeInfo.value.quantity && routeInfo.value.quantity !== 0
-            ? 1 * routeInfo.value.quantity
-            : 0,
+        demandedQuantity: 0,
         children: [],
         unit: "",
         tempId: new Date().getTime(),
       });
+      recalculateDemandedQuantities();
       return true;
     }
     if (item.children && item.children.length > 0) {
@@ -1275,14 +1319,12 @@
             "",
           operationName: "",
           unitQuantity: 1,
-          demandedQuantity:
-            routeInfo.value.quantity && routeInfo.value.quantity !== 0
-              ? 1 * routeInfo.value.quantity
-              : 0,
+          demandedQuantity: 0,
           unit: "",
           children: [],
           tempId: new Date().getTime(),
         });
+        recalculateDemandedQuantities();
         return;
       }
       addchildItem(item, tempId);
@@ -1350,6 +1392,7 @@
     console.log(bomDataValue.value.dataList, "bomDataValue.value.dataList");
 
     normalizeTreeData(bomDataValue.value.dataList);
+    recalculateDemandedQuantities();
 
     const valid = validateAllBom();
     if (valid) {
@@ -1361,7 +1404,7 @@
         .then(() => {
           ElMessage.success("BOM淇濆瓨鎴愬姛");
           bomDataValue.value.isEdit = false;
-          fetchBomData();
+          refreshCurrentPage();
         })
         .catch(() => {
           ElMessage.error("BOM淇濆瓨澶辫触");
@@ -1374,11 +1417,15 @@
     }
   };
 
-  onMounted(() => {
+  const refreshCurrentPage = () => {
     getRouteInfo();
     getList();
     getProcessList();
     fetchBomData();
+  };
+
+  onMounted(() => {
+    refreshCurrentPage();
   });
 
   onUnmounted(() => {
diff --git a/src/views/productionManagement/productStructure/Detail/index.vue b/src/views/productionManagement/productStructure/Detail/index.vue
index 750d584..a7f6b6b 100644
--- a/src/views/productionManagement/productStructure/Detail/index.vue
+++ b/src/views/productionManagement/productStructure/Detail/index.vue
@@ -86,6 +86,7 @@
                                      :step="1"
                                      controls-position="right"
                                      style="width: 100%"
+                                     @change="handleUnitQuantityChange"
                                      :disabled="!dataValue.isEdit || dataValue.dataList.some(item => (item as any).tempId === row.tempId)" />
                   </el-form-item>
                 </template>
@@ -103,7 +104,7 @@
                                      :step="1"
                                      controls-position="right"
                                      style="width: 100%"
-                                     :disabled="!dataValue.isEdit || dataValue.dataList.some(item => (item as any).tempId === row.tempId)" />
+                                     :disabled="true" />
                   </el-form-item>
                 </template>
               </el-table-column>
@@ -268,6 +269,42 @@
     });
   };
 
+  const toQuantityNumber = (value: any) => {
+    const numberValue = Number(value);
+    if (!Number.isFinite(numberValue)) {
+      return 0;
+    }
+    return Number(numberValue.toFixed(2));
+  };
+
+  const syncDemandedQuantityTree = (
+    items: any[],
+    parentDemandedQuantity: number | null = null
+  ) => {
+    items.forEach((item: any) => {
+      if (parentDemandedQuantity !== null) {
+        item.demandedQuantity = toQuantityNumber(
+          parentDemandedQuantity * toQuantityNumber(item.unitQuantity)
+        );
+      }
+
+      if (Array.isArray(item.children) && item.children.length > 0) {
+        syncDemandedQuantityTree(
+          item.children,
+          toQuantityNumber(item.demandedQuantity)
+        );
+      }
+    });
+  };
+
+  const recalculateDemandedQuantities = () => {
+    if (!isOrderPage.value) {
+      return;
+    }
+
+    syncDemandedQuantityTree(dataValue.dataList);
+  };
+
   const buildSubmitTree = (items: any[]) => {
     return items.map((item: any) => {
       const current = { ...item };
@@ -282,6 +319,10 @@
   const handleProcessChange = (row: any, value: any) => {
     row.processId = value || "";
     syncProcessOperationFields(row);
+  };
+
+  const handleUnitQuantityChange = () => {
+    recalculateDemandedQuantities();
   };
 
   const tableData = reactive([
@@ -304,6 +345,7 @@
       const { data } = await listProcessBom({ orderId: routeOrderId.value });
       dataValue.dataList = (data as any) || [];
       normalizeTreeData(dataValue.dataList);
+      recalculateDemandedQuantities();
     } else {
       // 闈炶鍗曟儏鍐碉細浣跨敤鍘熸潵鐨勬帴鍙�
       const { data } = await queryList(routeId.value);
@@ -437,6 +479,7 @@
   const submit = () => {
     dataValue.loading = true;
     normalizeTreeData(dataValue.dataList);
+    recalculateDemandedQuantities();
 
     // 鍏堣繘琛岃〃鍗曟牎楠�
     const valid = validateAll();
@@ -514,6 +557,7 @@
 
           tempId: new Date().getTime(),
         });
+        recalculateDemandedQuantities();
         return;
       }
       addchildItem(item, tempId);
@@ -542,6 +586,7 @@
         unit: "",
         tempId: new Date().getTime(),
       });
+      recalculateDemandedQuantities();
       return true;
     }
     if (item.children && item.children.length > 0) {
@@ -587,4 +632,4 @@
     await fetchProcessOptions();
     await fetchData();
   });
-</script>
\ No newline at end of file
+</script>
diff --git a/src/views/productionManagement/productionProcess/index.vue b/src/views/productionManagement/productionProcess/index.vue
index 6d007a4..747b8de 100644
--- a/src/views/productionManagement/productionProcess/index.vue
+++ b/src/views/productionManagement/productionProcess/index.vue
@@ -243,6 +243,7 @@
             </el-form-item>
             <el-form-item label="鏍囧噯鍊�">
               <el-input v-model="selectedParam.standardValue"
+                        @input="val => onStandardValueInput(val, selectedParam)"
                         placeholder="璇疯緭鍏ラ粯璁ゅ��" />
             </el-form-item>
           </el-form>
@@ -273,6 +274,7 @@
         <el-form-item label="鏍囧噯鍊�"
                       prop="standardValue">
           <el-input v-model="editParamForm.standardValue"
+                    @input="val => onStandardValueInput(val, editParamForm)"
                     placeholder="璇疯緭鍏ユ爣鍑嗗��" />
         </el-form-item>
       </el-form>
@@ -392,7 +394,18 @@
     technologyParamId: null,
     paramName: "",
     standardValue: null,
+    paramType: null,
   });
+
+  const onStandardValueInput = (val, target) => {
+    const data = target.value || target;
+    const type = data.paramType;
+    if (type === 1) {
+      // 鏁板�兼牸寮忥細涓嶈兘杈撳叆涓枃鎴栬嫳鏂囧瓧绗�
+      data.standardValue = val.replace(/[a-zA-Z\u4e00-\u9fa5]/g, "");
+    }
+  };
+
   const editParamRules = {
     standardValue: [
       {
@@ -403,6 +416,12 @@
           if (value === null || value === undefined || value === "") {
             callback(new Error("璇疯緭鍏ユ爣鍑嗗��"));
           } else {
+            const type = editParamForm.paramType;
+            if (type === 1 && value) {
+              if (/[a-zA-Z\u4e00-\u9fa5]/.test(value)) {
+                return callback(new Error("鏁板�兼牸寮忎笉鑳藉寘鍚腑鑻辨枃瀛楃"));
+              }
+            }
             callback();
           }
         },
@@ -717,6 +736,7 @@
     editParamForm.technologyParamId = row.technologyParamId;
     editParamForm.paramName = row.paramName;
     editParamForm.standardValue = row.standardValue;
+    editParamForm.paramType = row.paramType;
     editParamDialogVisible.value = true;
   };
 
diff --git a/src/views/qualityManagement/finalInspection/components/formDia.vue b/src/views/qualityManagement/finalInspection/components/formDia.vue
index 5f4c975..10bfad9 100644
--- a/src/views/qualityManagement/finalInspection/components/formDia.vue
+++ b/src/views/qualityManagement/finalInspection/components/formDia.vue
@@ -2,7 +2,7 @@
   <div>
     <el-dialog
         v-model="dialogFormVisible"
-        :title="operationType === 'add' ? '鏂板鍑哄巶妫�楠�' : '缂栬緫鍑哄巶妫�楠�'"
+        :title="operationType === 'add' ? '鏂板鍑哄巶妫�楠�' : operationType === 'view' ? '鏌ョ湅鍑哄巶妫�楠�' : '缂栬緫鍑哄巶妫�楠�'"
         width="70%"
         @close="closeDia"
     >
@@ -18,19 +18,21 @@
                   @change="getModels"
                   :data="productOptions"
                   :render-after-expand="false"
-                  :disabled="operationType === 'edit'"
+                  :disabled="isViewMode || operationType === 'edit'"
                   style="width: 100%"
               />
             </el-form-item>
           </el-col>
           <el-col :span="12">
             <el-form-item label="瑙勬牸鍨嬪彿锛�" prop="productModelId">
-              <el-select v-model="form.productModelId" placeholder="璇烽�夋嫨" clearable :disabled="operationType === 'edit'"
+              <el-select v-model="form.productModelId" placeholder="璇烽�夋嫨" clearable :disabled="isViewMode || operationType === 'edit'"
                          filterable readonly @change="handleChangeModel">
                 <el-option v-for="item in modelOptions" :key="item.id" :label="item.model" :value="item.id" />
               </el-select>
             </el-form-item>
           </el-col>
+        </el-row>
+        <el-row :gutter="30">
           <el-col :span="12">
             <el-form-item label="鎸囨爣閫夋嫨锛�" prop="testStandardId">
               <el-select
@@ -39,6 +41,7 @@
                 clearable
                 @change="handleTestStandardChange"
                 style="width: 100%"
+                :disabled="isViewMode"
               >
                 <el-option
                   v-for="item in testStandardOptions"
@@ -58,21 +61,52 @@
           </el-col>
           <el-col :span="12">
             <el-form-item label="鏁伴噺锛�" prop="quantity">
-              <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.quantity" placeholder="璇疯緭鍏�" clearable :precision="2" :disabled="quantityDisabled"/>
+              <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.quantity" placeholder="璇疯緭鍏�" clearable :precision="2" :disabled="isViewMode || processQuantityDisabled"/>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="鍚堟牸鏁伴噺锛�"
+                          prop="qualifiedQuantity">
+              <el-input-number :step="0.01"
+                               :min="0"
+                               style="width: 100%"
+                               v-model="form.qualifiedQuantity"
+                               placeholder="璇疯緭鍏�"
+                               clearable
+                               :precision="2"
+                               @change="handleQualifiedQuantityChange"
+                               :disabled="isViewMode" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="涓嶅悎鏍兼暟閲忥細"
+                          prop="unqualifiedQuantity">
+              <el-input-number :step="0.01"
+                               :min="0"
+                               style="width: 100%"
+                               v-model="form.unqualifiedQuantity"
+                               placeholder="璇疯緭鍏�"
+                               clearable
+                               :precision="2"
+                               @change="handleUnqualifiedQuantityChange"
+                               :disabled="isViewMode" />
             </el-form-item>
           </el-col>
         </el-row>
         <el-row :gutter="30">
           <el-col :span="12">
             <el-form-item label="妫�娴嬪崟浣嶏細" prop="checkCompany">
-              <el-input v-model="form.checkCompany" placeholder="璇疯緭鍏�" clearable/>
+              <el-input v-model="form.checkCompany" placeholder="璇疯緭鍏�" clearable :disabled="isViewMode"/>
             </el-form-item>
           </el-col>
           <el-col :span="12">
             <el-form-item label="妫�娴嬬粨鏋滐細" prop="checkResult">
-              <el-select v-model="form.checkResult">
+              <el-select v-model="form.checkResult" :disabled="isViewMode">
                 <el-option label="鍚堟牸" value="鍚堟牸" />
                 <el-option label="涓嶅悎鏍�" value="涓嶅悎鏍�" />
+                <el-option label="閮ㄥ垎鍚堟牸" value="閮ㄥ垎鍚堟牸" />
               </el-select>
             </el-form-item>
           </el-col>
@@ -80,10 +114,10 @@
         <el-row :gutter="30">
           <el-col :span="12">
             <el-form-item label="妫�楠屽憳锛�" prop="checkName">
-							<el-select v-model="form.checkName" placeholder="璇烽�夋嫨" clearable>
-								<el-option v-for="item in userList" :key="item.nickName" :label="item.nickName"
-													 :value="item.nickName"/>
-							</el-select>
+              <el-select v-model="form.checkName" placeholder="璇烽�夋嫨" clearable :disabled="isViewMode">
+                <el-option v-for="item in userList" :key="item.nickName" :label="item.nickName"
+                           :value="item.nickName"/>
+              </el-select>
             </el-form-item>
           </el-col>
           <el-col :span="12">
@@ -96,6 +130,7 @@
                   format="YYYY-MM-DD"
                   clearable
                   style="width: 100%"
+                  :disabled="isViewMode"
               />
             </el-form-item>
           </el-col>
@@ -109,13 +144,16 @@
 				height="400"
 			>
 				<template #slot="{ row }">
-					<el-input v-model="row.testValue" clearable/>
+					<el-input v-model="row.testValue" clearable :disabled="isViewMode"/>
 				</template>
 			</PIMTable>
       <template #footer>
         <div class="dialog-footer">
-          <el-button type="primary" @click="submitForm">纭</el-button>
-          <el-button @click="closeDia">鍙栨秷</el-button>
+          <template v-if="!isViewMode">
+            <el-button type="primary" @click="submitForm">纭</el-button>
+            <el-button @click="closeDia">鍙栨秷</el-button>
+          </template>
+          <el-button v-else @click="closeDia">鍏抽棴</el-button>
         </div>
       </template>
     </el-dialog>
@@ -134,7 +172,7 @@
 const emit = defineEmits(['close'])
 
 const dialogFormVisible = ref(false);
-const operationType = ref('')
+const operationType = ref("");
 const data = reactive({
   form: {
     checkTime: "",
@@ -147,25 +185,31 @@
     testStandardId: "",
     unit: "",
     quantity: "",
+    qualifiedQuantity: "",
+    unqualifiedQuantity: "",
     checkCompany: "",
     checkResult: "",
   },
   rules: {
-    checkTime: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" },],
+    checkTime: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
     process: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
     checkName: [{ required: false, message: "璇疯緭鍏�", trigger: "blur" }],
     productId: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
     productModelId: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
-    testStandardId: [{required: false, message: "璇烽�夋嫨鎸囨爣", trigger: "change"}],
+    testStandardId: [{ required: false, message: "璇烽�夋嫨鎸囨爣", trigger: "change" }],
     unit: [{ required: false, message: "璇疯緭鍏�", trigger: "blur" }],
     quantity: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+    qualifiedQuantity: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+    unqualifiedQuantity: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
     checkCompany: [{ required: false, message: "璇疯緭鍏�", trigger: "blur" }],
     checkResult: [{ required: true, message: "璇疯緭鍏�", trigger: "change" }],
   },
 });
 const { form, rules } = toRefs(data);
-// 缂栬緫鏃讹細productMainId 鎴� purchaseLedgerId 浠讳竴鏈夊�煎垯鏁伴噺缃伆
-const quantityDisabled = computed(() => {
+// 鏄惁涓烘煡鐪嬫ā寮�
+const isViewMode = computed(() => operationType.value === 'view');
+// 缂栬緫鏃讹細productMainId 鎴� purchaseLedgerId 浠讳竴鏈夊�煎垯宸ュ簭銆佹暟閲忕疆鐏�
+const processQuantityDisabled = computed(() => {
   const v = form.value || {};
   return !!(v.productMainId != null || v.purchaseLedgerId != null);
 });
@@ -209,7 +253,7 @@
   // 鍏堟竻绌鸿〃鍗曢獙璇佺姸鎬侊紝閬垮厤闂儊
   await nextTick();
   proxy.$refs.formRef?.clearValidate();
-  
+
   // 骞惰鍔犺浇鍩虹鏁版嵁
   const [userListsRes] = await Promise.all([
     userListNoPage(),
@@ -219,12 +263,12 @@
     })
   ]);
   userList.value = userListsRes.data;
-  
+
   form.value = {}
   testStandardOptions.value = [];
   tableData.value = [];
-  
-  if (operationType.value === 'edit') {
+
+  if (operationType.value === 'edit' || operationType.value === 'view') {
     // 鍏堜繚瀛� testStandardId锛岄伩鍏嶈娓呯┖
     const savedTestStandardId = row.testStandardId;
     // 鍏堣缃〃鍗曟暟鎹紝浣嗘殏鏃舵竻绌� testStandardId锛岀瓑閫夐」鍔犺浇瀹屾垚鍚庡啀璁剧疆
@@ -234,18 +278,18 @@
     nextTick(() => {
       proxy.$refs.formRef?.clearValidate();
     });
-    
+
     // 缂栬緫妯″紡涓嬶紝骞惰鍔犺浇瑙勬牸鍨嬪彿鍜屾寚鏍囬�夐」
     if (currentProductId.value) {
       // 璁剧疆浜у搧鍚嶇О
       form.value.productName = findNodeById(productOptions.value, currentProductId.value);
-      
+
       // 骞惰鍔犺浇瑙勬牸鍨嬪彿鍜屾寚鏍囬�夐」
       const params = {
         productId: currentProductId.value,
         inspectType: 2
       };
-      
+
       Promise.all([
         modelList({ id: currentProductId.value }),
         qualityInspectDetailByProductId(params)
@@ -260,15 +304,15 @@
             form.value.unit = selectedModel.unit || '';
           }
         }
-        
+
         // 璁剧疆鎸囨爣閫夐」
         testStandardOptions.value = testStandardRes.data || [];
-        
+
         // 璁剧疆 testStandardId 骞跺姞杞藉弬鏁板垪琛�
         nextTick(() => {
           if (savedTestStandardId) {
             // 纭繚绫诲瀷鍖归厤锛坕tem.id 鍙兘鏄暟瀛楁垨瀛楃涓诧級
-            const matchedOption = testStandardOptions.value.find(item => 
+            const matchedOption = testStandardOptions.value.find(item =>
               item.id == savedTestStandardId || String(item.id) === String(savedTestStandardId)
             );
             if (matchedOption) {
@@ -313,6 +357,28 @@
   form.value.unit = modelOptions.value.find(item => item.id == value)?.unit || '';
 }
 
+const handleQualifiedQuantityChange = (value) => {
+  if (value === null || value === undefined) {
+    form.value.qualifiedQuantity = 0;
+    return;
+  }
+  const quantity = parseFloat(form.value.quantity) || 0;
+  const qualified = parseFloat(value) || 0;
+  form.value.qualifiedQuantity = qualified > quantity?quantity:qualified;
+  form.value.unqualifiedQuantity = Math.max(0, quantity - qualified);
+};
+
+const handleUnqualifiedQuantityChange = (value) => {
+  if (value === null || value === undefined) {
+    form.value.unqualifiedQuantity = 0;
+    return;
+  }
+  const quantity = parseFloat(form.value.quantity) || 0;
+  const unqualified = parseFloat(value) || 0;
+  form.value.unqualifiedQuantity = unqualified > quantity?quantity:unqualified;
+  form.value.qualifiedQuantity = Math.max(0, quantity - unqualified);
+};
+
 const findNodeById = (nodes, productId) => {
   for (let i = 0; i < nodes.length; i++) {
     if (nodes[i].value === productId) {
@@ -337,7 +403,7 @@
     if (children && children.length > 0) {
       newItem.children = convertIdToValue(children);
     }
-    
+
     return newItem;
   });
 }
@@ -345,26 +411,26 @@
 const submitForm = () => {
   proxy.$refs.formRef.validate(valid => {
     if (valid) {
-      form.value.inspectType = 2
-			if (operationType.value === "add") {
-				tableData.value.forEach((item) => {
-					delete item.id
-				})
-			}
-			const data = {...form.value, qualityInspectParams: tableData.value}
+      form.value.inspectType = 2;
+      if (operationType.value === "add") {
+        tableData.value.forEach((item) => {
+          delete item.id;
+        });
+      }
+      const data = { ...form.value, qualityInspectParams: tableData.value };
       if (operationType.value === "add") {
         qualityInspectAdd(data).then(res => {
           proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
           closeDia();
-        })
+        });
       } else {
         qualityInspectUpdate(data).then(res => {
           proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
           closeDia();
-        })
+        });
       }
     }
-  })
+  });
 }
 const getList = () => {
   if (!currentProductId.value) {
@@ -375,15 +441,15 @@
   let params = {
     productId: currentProductId.value,
     inspectType: 2
-  }
-	qualityInspectDetailByProductId(params).then(res => {
-		// 淇濆瓨涓嬫媺妗嗛�夐」鏁版嵁
-		testStandardOptions.value = res.data || [];
-		// 娓呯┖琛ㄦ牸鏁版嵁锛岀瓑寰呯敤鎴烽�夋嫨鎸囨爣
-		tableData.value = [];
-		// 娓呯┖鎸囨爣閫夋嫨
-		form.value.testStandardId = '';
-	})
+  };
+  qualityInspectDetailByProductId(params).then(res => {
+    // 淇濆瓨涓嬫媺妗嗛�夐」鏁版嵁
+    testStandardOptions.value = res.data || [];
+    // 娓呯┖琛ㄦ牸鏁版嵁锛岀瓑寰呯敤鎴烽�夋嫨鎸囨爣
+    tableData.value = [];
+    // 娓呯┖鎸囨爣閫夋嫨
+    form.value.testStandardId = '';
+  });
 }
 
 // 鎸囨爣閫夋嫨鍙樺寲澶勭悊
@@ -395,17 +461,21 @@
   tableLoading.value = true;
   getQualityTestStandardParamByTestStandardId(testStandardId).then(res => {
     tableData.value = res.data || [];
+    tableData.value = tableData.value.map(item => ({
+      ...item,
+      id: null
+    }));
   }).catch(error => {
     console.error('鑾峰彇鏍囧噯鍙傛暟澶辫触:', error);
     tableData.value = [];
   }).finally(() => {
     tableLoading.value = false;
-  })
+  });
 }
 const getQualityInspectParamList = (id) => {
-	qualityInspectParamInfo(id).then(res => {
-		tableData.value = res.data;
-	})
+  qualityInspectParamInfo(id).then(res => {
+    tableData.value = res.data;
+  });
 }
 // 鍏抽棴寮规
 const closeDia = () => {
@@ -414,8 +484,8 @@
   testStandardOptions.value = [];
   form.value.testStandardId = '';
   dialogFormVisible.value = false;
-  emit('close')
-};
+  emit('close');
+}
 defineExpose({
   openDialog,
 });
@@ -423,4 +493,4 @@
 
 <style scoped>
 
-</style>
\ No newline at end of file
+</style>
diff --git a/src/views/qualityManagement/finalInspection/index.vue b/src/views/qualityManagement/finalInspection/index.vue
index a2d1acc..bdb71c4 100644
--- a/src/views/qualityManagement/finalInspection/index.vue
+++ b/src/views/qualityManagement/finalInspection/index.vue
@@ -123,8 +123,18 @@
     prop: "unit",
   },
   {
-    label: "鏁伴噺",
+    label: "鎬绘暟閲�",
     prop: "quantity",
+    width: 100
+  },
+  {
+    label: "鍚堟牸鏁伴噺",
+    prop: "qualifiedQuantity",
+    width: 100
+  },
+  {
+    label: "涓嶅悎鏍兼暟閲�",
+    prop: "unqualifiedQuantity",
     width: 100
   },
   {
@@ -142,7 +152,7 @@
       } else if (params == '鍚堟牸') {
         return "success";
       } else {
-        return null;
+        return 'danger';
       }
     },
   },
@@ -181,6 +191,13 @@
         }
       },
       {
+        name: "鏌ョ湅",
+        type: "text",
+        clickFun: (row) => {
+          openForm("view", row);
+        },
+      },
+      {
         name: "闄勪欢",
         type: "text",
         clickFun: (row) => {
diff --git a/src/views/qualityManagement/nonconformingManagement/index.vue b/src/views/qualityManagement/nonconformingManagement/index.vue
index 6306397..fc9d5d2 100644
--- a/src/views/qualityManagement/nonconformingManagement/index.vue
+++ b/src/views/qualityManagement/nonconformingManagement/index.vue
@@ -98,7 +98,7 @@
       } else if (params == '鍚堟牸') {
         return "success";
       } else {
-        return null;
+        return 'danger';
       }
     },
   },
diff --git a/src/views/qualityManagement/processInspection/components/formDia.vue b/src/views/qualityManagement/processInspection/components/formDia.vue
index c1185d2..635360f 100644
--- a/src/views/qualityManagement/processInspection/components/formDia.vue
+++ b/src/views/qualityManagement/processInspection/components/formDia.vue
@@ -1,130 +1,206 @@
 <template>
   <div>
-    <el-dialog
-        v-model="dialogFormVisible"
-        :title="operationType === 'add' ? '鏂板杩囩▼妫�楠�' : '缂栬緫杩囩▼妫�楠�'"
-        width="70%"
-        @close="closeDia"
-    >
-      <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef">
+    <el-dialog v-model="dialogFormVisible"
+               :title="operationType === 'add' ? '鏂板杩囩▼妫�楠�' : operationType === 'view' ? '鏌ョ湅杩囩▼妫�楠�' : '缂栬緫杩囩▼妫�楠�'"
+               width="70%"
+               @close="closeDia">
+      <el-form :model="form"
+               label-width="140px"
+               label-position="top"
+               :rules="rules"
+               ref="formRef">
         <el-row :gutter="30">
           <el-col :span="12">
-            <el-form-item label="宸ュ簭锛�" prop="process">
-              <el-select v-model="form.process" placeholder="璇烽�夋嫨宸ュ簭" clearable :disabled="processQuantityDisabled" style="width: 100%">
-                <el-option v-for="item in processList" :key="item.name" :label="item.name" :value="item.name"/>
+            <el-form-item label="宸ュ簭锛�"
+                          prop="process">
+              <el-select v-model="form.process"
+                         placeholder="璇烽�夋嫨宸ュ簭"
+                         clearable
+                         :disabled="isViewMode || processQuantityDisabled"
+                         style="width: 100%">
+                <el-option v-for="item in processList"
+                           :key="item.name"
+                           :label="item.name"
+                           :value="item.name" />
               </el-select>
             </el-form-item>
           </el-col>
           <el-col :span="12">
-            <el-form-item label="浜у搧鍚嶇О锛�" prop="productId">
-              <el-tree-select
-                  v-model="form.productId"
-                  placeholder="璇烽�夋嫨"
-                  clearable
-                  check-strictly
-                  @change="getModels"
-                  :data="productOptions"
-                  :render-after-expand="false"
-                  :disabled="operationType === 'edit'"
-                  style="width: 100%"
-              />
+            <el-form-item label="浜у搧鍚嶇О锛�"
+                          prop="productId">
+              <el-tree-select v-model="form.productId"
+                              placeholder="璇烽�夋嫨"
+                              clearable
+                              check-strictly
+                              @change="getModels"
+                              :data="productOptions"
+                              :render-after-expand="false"
+                              :disabled="isViewMode || operationType === 'edit'"
+                              style="width: 100%" />
             </el-form-item>
           </el-col>
         </el-row>
         <el-row :gutter="30">
           <el-col :span="12">
-            <el-form-item label="瑙勬牸鍨嬪彿锛�" prop="productModelId">
-              <el-select v-model="form.productModelId" placeholder="璇烽�夋嫨" clearable :disabled="operationType === 'edit'"
-                         filterable readonly @change="handleChangeModel">
-                <el-option v-for="item in modelOptions" :key="item.id" :label="item.model" :value="item.id" />
+            <el-form-item label="瑙勬牸鍨嬪彿锛�"
+                          prop="productModelId">
+              <el-select v-model="form.productModelId"
+                         placeholder="璇烽�夋嫨"
+                         clearable
+                         :disabled="isViewMode || operationType === 'edit'"
+                         filterable
+                         readonly
+                         @change="handleChangeModel">
+                <el-option v-for="item in modelOptions"
+                           :key="item.id"
+                           :label="item.model"
+                           :value="item.id" />
               </el-select>
             </el-form-item>
           </el-col>
           <el-col :span="12">
-            <el-form-item label="鎸囨爣閫夋嫨锛�" prop="testStandardId">
-              <el-select
-                v-model="form.testStandardId"
-                placeholder="璇烽�夋嫨鎸囨爣"
-                clearable
-                @change="handleTestStandardChange"
-                style="width: 100%"
-              >
-                <el-option
-                  v-for="item in testStandardOptions"
-                  :key="item.id"
-                  :label="item.standardName || item.standardNo"
-                  :value="item.id"
-                />
+            <el-form-item label="鎸囨爣閫夋嫨锛�"
+                          prop="testStandardId">
+              <el-select v-model="form.testStandardId"
+                         placeholder="璇烽�夋嫨鎸囨爣"
+                         clearable
+                         @change="handleTestStandardChange"
+                         style="width: 100%"
+                         :disabled="isViewMode">
+                <el-option v-for="item in testStandardOptions"
+                           :key="item.id"
+                           :label="item.standardName || item.standardNo"
+                           :value="item.id" />
               </el-select>
             </el-form-item>
           </el-col>
         </el-row>
         <el-row :gutter="30">
           <el-col :span="12">
-            <el-form-item label="鍗曚綅锛�" prop="unit">
-              <el-input v-model="form.unit" placeholder="璇疯緭鍏�" disabled/>
+            <el-form-item label="鍗曚綅锛�"
+                          prop="unit">
+              <el-input v-model="form.unit"
+                        placeholder="璇疯緭鍏�"
+                        disabled />
             </el-form-item>
           </el-col>
           <el-col :span="12">
-            <el-form-item label="鏁伴噺锛�" prop="quantity">
-              <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.quantity" placeholder="璇疯緭鍏�" clearable :precision="2" :disabled="processQuantityDisabled"/>
+            <el-form-item label="鏁伴噺锛�"
+                          prop="quantity">
+              <el-input-number :step="0.01"
+                               :min="0"
+                               style="width: 100%"
+                               v-model="form.quantity"
+                               placeholder="璇疯緭鍏�"
+                               clearable
+                               :precision="2"
+                               :disabled="isViewMode || processQuantityDisabled" />
             </el-form-item>
           </el-col>
         </el-row>
         <el-row :gutter="30">
           <el-col :span="12">
-            <el-form-item label="妫�娴嬪崟浣嶏細" prop="checkCompany">
-              <el-input v-model="form.checkCompany" placeholder="璇疯緭鍏�" clearable/>
+            <el-form-item label="鍚堟牸鏁伴噺锛�"
+                          prop="qualifiedQuantity">
+              <el-input-number :step="0.01"
+                               :min="0"
+                               style="width: 100%"
+                               v-model="form.qualifiedQuantity"
+                               placeholder="璇疯緭鍏�"
+                               clearable
+                               :precision="2"
+                               @change="handleQualifiedQuantityChange"
+                               :disabled="isViewMode" />
             </el-form-item>
           </el-col>
           <el-col :span="12">
-            <el-form-item label="妫�娴嬬粨鏋滐細" prop="checkResult">
-              <el-select v-model="form.checkResult">
-                <el-option label="鍚堟牸" value="鍚堟牸" />
-                <el-option label="涓嶅悎鏍�" value="涓嶅悎鏍�" />
+            <el-form-item label="涓嶅悎鏍兼暟閲忥細"
+                          prop="unqualifiedQuantity">
+              <el-input-number :step="0.01"
+                               :min="0"
+                               style="width: 100%"
+                               v-model="form.unqualifiedQuantity"
+                               placeholder="璇疯緭鍏�"
+                               clearable
+                               :precision="2"
+                               @change="handleUnqualifiedQuantityChange"
+                               :disabled="isViewMode" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="妫�娴嬪崟浣嶏細"
+                          prop="checkCompany">
+              <el-input v-model="form.checkCompany"
+                        placeholder="璇疯緭鍏�"
+                        clearable
+                        :disabled="isViewMode" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="妫�娴嬬粨鏋滐細"
+                          prop="checkResult">
+              <el-select v-model="form.checkResult" :disabled="isViewMode">
+                <el-option label="鍚堟牸"
+                           value="鍚堟牸" />
+                <el-option label="涓嶅悎鏍�"
+                           value="涓嶅悎鏍�" />
+                <el-option label="閮ㄥ垎鍚堟牸"
+                           value="閮ㄥ垎鍚堟牸" />
               </el-select>
             </el-form-item>
           </el-col>
         </el-row>
         <el-row :gutter="30">
           <el-col :span="12">
-            <el-form-item label="妫�楠屽憳锛�" prop="checkName">
-							<el-select v-model="form.checkName" placeholder="璇烽�夋嫨" clearable>
-								<el-option v-for="item in userList" :key="item.nickName" :label="item.nickName"
-													 :value="item.nickName"/>
-							</el-select>
+            <el-form-item label="妫�楠屽憳锛�"
+                          prop="checkName">
+              <el-select v-model="form.checkName"
+                         placeholder="璇烽�夋嫨"
+                         clearable
+                         :disabled="isViewMode">
+                <el-option v-for="item in userList"
+                           :key="item.nickName"
+                           :label="item.nickName"
+                           :value="item.nickName" />
+              </el-select>
             </el-form-item>
           </el-col>
           <el-col :span="12">
-            <el-form-item label="妫�娴嬫棩鏈燂細" prop="checkTime">
-              <el-date-picker
-                  v-model="form.checkTime"
-                  type="date"
-                  placeholder="璇烽�夋嫨鏃ユ湡"
-                  value-format="YYYY-MM-DD"
-                  format="YYYY-MM-DD"
-                  clearable
-                  style="width: 100%"
-              />
+            <el-form-item label="妫�娴嬫棩鏈燂細"
+                          prop="checkTime">
+              <el-date-picker v-model="form.checkTime"
+                              type="date"
+                              placeholder="璇烽�夋嫨鏃ユ湡"
+                              value-format="YYYY-MM-DD"
+                              format="YYYY-MM-DD"
+                              clearable
+                              style="width: 100%"
+                              :disabled="isViewMode" />
             </el-form-item>
           </el-col>
         </el-row>
       </el-form>
-			<PIMTable
-				rowKey="id"
-				:column="tableColumn"
-				:tableData="tableData"
-				:tableLoading="tableLoading"
-				height="400"
-			>
-				<template #slot="{ row }">
-					<el-input v-model="row.testValue" clearable/>
-				</template>
-			</PIMTable>
+      <PIMTable rowKey="id"
+                :column="tableColumn"
+                :tableData="tableData"
+                :tableLoading="tableLoading"
+                height="400">
+        <template #slot="{ row }">
+          <el-input v-model="row.testValue"
+                    clearable
+                    :disabled="isViewMode" />
+        </template>
+      </PIMTable>
       <template #footer>
         <div class="dialog-footer">
-          <el-button type="primary" @click="submitForm">纭</el-button>
-          <el-button @click="closeDia">鍙栨秷</el-button>
+          <template v-if="!isViewMode">
+            <el-button type="primary"
+                       @click="submitForm">纭</el-button>
+            <el-button @click="closeDia">鍙栨秷</el-button>
+          </template>
+          <el-button v-else @click="closeDia">鍏抽棴</el-button>
         </div>
       </template>
     </el-dialog>
@@ -132,332 +208,398 @@
 </template>
 
 <script setup>
-import {ref, reactive, toRefs, computed, getCurrentInstance, nextTick} from "vue";
-import {getOptions} from "@/api/procurementManagement/procurementLedger.js";
-import {modelList, productTreeList} from "@/api/basicData/product.js";
-import {qualityInspectAdd, qualityInspectUpdate} from "@/api/qualityManagement/rawMaterialInspection.js";
-import {qualityInspectDetailByProductId, getQualityTestStandardParamByTestStandardId} from "@/api/qualityManagement/metricMaintenance.js";
-import {userListNoPage} from "@/api/system/user.js";
-import {qualityInspectParamInfo} from "@/api/qualityManagement/qualityInspectParam.js";
-import { list } from "@/api/productionManagement/productionProcess";
-const { proxy } = getCurrentInstance()
-const emit = defineEmits(['close'])
+  import {
+    ref,
+    reactive,
+    toRefs,
+    computed,
+    getCurrentInstance,
+    nextTick,
+  } from "vue";
+  import { getOptions } from "@/api/procurementManagement/procurementLedger.js";
+  import { modelList, productTreeList } from "@/api/basicData/product.js";
+  import {
+    qualityInspectAdd,
+    qualityInspectUpdate,
+  } from "@/api/qualityManagement/rawMaterialInspection.js";
+  import {
+    qualityInspectDetailByProductId,
+    getQualityTestStandardParamByTestStandardId,
+  } from "@/api/qualityManagement/metricMaintenance.js";
+  import { userListNoPage } from "@/api/system/user.js";
+  import { qualityInspectParamInfo } from "@/api/qualityManagement/qualityInspectParam.js";
+  import { list } from "@/api/productionManagement/productionProcess";
+  import qualified from "@/views/inventoryManagement/stockManagement/Qualified.vue";
+  const { proxy } = getCurrentInstance();
+  const emit = defineEmits(["close"]);
 
-
-
-const dialogFormVisible = ref(false);
-const operationType = ref('')
-const data = reactive({
-  form: {
-    checkTime: "",
-    process: "",
-    checkName: "",
-    productName: "",
-    productId: "",
-    productModelId: "",
-    model: "",
-    testStandardId: "",
-    unit: "",
-    quantity: "",
-    checkCompany: "",
-    checkResult: "",
-  },
-  rules: {
-    checkTime: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" },],
-    process: [{ required: true, message: "璇烽�夋嫨宸ュ簭", trigger: "change" }],
-    checkName: [{ required: false, message: "璇疯緭鍏�", trigger: "blur" }],
-    productId: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
-    productModelId: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
-    testStandardId: [{required: false, message: "璇烽�夋嫨鎸囨爣", trigger: "change"}],
-    unit: [{ required: false, message: "璇疯緭鍏�", trigger: "blur" }],
-    quantity: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
-    checkCompany: [{ required: false, message: "璇疯緭鍏�", trigger: "blur" }],
-    checkResult: [{ required: true, message: "璇疯緭鍏�", trigger: "change" }],
-  },
-});
-const userList = ref([]);
-const { form, rules } = toRefs(data);
-// 缂栬緫鏃讹細productMainId 鎴� purchaseLedgerId 浠讳竴鏈夊�煎垯宸ュ簭銆佹暟閲忕疆鐏�
-const processQuantityDisabled = computed(() => {
-  const v = form.value || {};
-  return !!(v.productMainId != null || v.purchaseLedgerId != null);
-});
-const processList = ref([]); // 宸ュ簭涓嬫媺鍒楄〃锛堝伐搴忓悕绉� name锛�
-const supplierList = ref([]);
-const productOptions = ref([]);
-const tableColumn = ref([
-	{
-		label: "鎸囨爣",
-		prop: "parameterItem",
-	},
-	{
-		label: "鍗曚綅",
-		prop: "unit",
-	},
-	{
-		label: "鏍囧噯鍊�",
-		prop: "standardValue",
-	},
-	{
-		label: "鍐呮帶鍊�",
-		prop: "controlValue",
-	},
-	{
-		label: "妫�楠屽��",
-		prop: "testValue",
-		dataType: 'slot',
-		slot: 'slot',
-	},
-]);
-const tableData = ref([]);
-const tableLoading = ref(false);
-const currentProductId = ref(0);
-const testStandardOptions = ref([]); // 鎸囨爣閫夋嫨涓嬫媺妗嗘暟鎹�
-const modelOptions = ref([]);
-
-// 鎵撳紑寮规
-const openDialog = async (type, row) => {
-	operationType.value = type;
-	getOptions().then((res) => {
-		supplierList.value = res.data;
-	});
-	// 鍔犺浇宸ュ簭涓嬫媺鍒楄〃
-	try {
-		const res = await list();
-		processList.value = res.data || [];
-	} catch (e) {
-		console.error("鍔犺浇宸ュ簭鍒楄〃澶辫触", e);
-		processList.value = [];
-	}
-	let userLists = await userListNoPage();
-	userList.value = userLists.data;
-	// 鍏堥噸缃〃鍗曟暟鎹紙淇濇寔瀛楁瀹屾暣锛岄伩鍏嶅脊绐楅娆℃覆鏌撴椂瑙﹀彂蹇呭~绾㈡鈥滈棯涓�涓嬧�濓級
-	form.value = {
-		checkTime: "",
-		process: "",
-		checkName: "",
-		productName: "",
-		productId: "",
-		productModelId: "",
-		model: "",
-		testStandardId: "",
-		unit: "",
-		quantity: "",
-		checkCompany: "",
-		checkResult: "",
-	}
-	testStandardOptions.value = [];
-	tableData.value = [];
-	// 鍏堢‘淇濅骇鍝佹爲宸插姞杞斤紝鍚﹀垯缂栬緫鏃朵骇鍝�/瑙勬牸鍨嬪彿鏃犳硶鍙嶆樉
-	await getProductOptions();
-	if (operationType.value === 'edit') {
-		// 鍏堜繚瀛� testStandardId锛岄伩鍏嶈娓呯┖
-		const savedTestStandardId = row.testStandardId;
-		// 鍏堣缃〃鍗曟暟鎹紝浣嗘殏鏃舵竻绌� testStandardId锛岀瓑閫夐」鍔犺浇瀹屾垚鍚庡啀璁剧疆
-		form.value = {...row, testStandardId: ''}
-		currentProductId.value = row.productId || 0
-		// 鍏抽敭锛氱紪杈戞椂鍔犺浇瑙勬牸鍨嬪彿涓嬫媺閫夐」锛屾墠鑳藉弽鏄� productModelId
-		if (currentProductId.value) {
-			try {
-				const res = await modelList({ id: currentProductId.value });
-				modelOptions.value = res || [];
-				// 鍚屾鍥炲~ model / unit锛堟湁浜涙帴鍙h繑鍥炵殑 row 閲屽彲鑳芥病甯﹀叏锛�
-				if (form.value.productModelId) {
-					handleChangeModel(form.value.productModelId);
-				}
-			} catch (e) {
-				console.error("鍔犺浇瑙勬牸鍨嬪彿澶辫触", e);
-				modelOptions.value = [];
-			}
-		}
-		// 缂栬緫妯″紡涓嬶紝鍏堝姞杞芥寚鏍囬�夐」锛岀劧鍚庡姞杞藉弬鏁板垪琛�
-		if (currentProductId.value) {
-			// 鍏堝姞杞芥寚鏍囬�夐」
-			let params = {
-				productId: currentProductId.value,
-				inspectType: 1,
-				process: form.value.process || ''
-			}
-			qualityInspectDetailByProductId(params).then(res => {
-				testStandardOptions.value = res.data || [];
-				// 浣跨敤 nextTick 鍜� setTimeout 纭繚閫夐」宸茬粡娓叉煋鍒� DOM
-				nextTick(() => {
-					setTimeout(() => {
-						// 濡傛灉缂栬緫鏁版嵁涓湁 testStandardId锛屽垯璁剧疆骞跺姞杞藉搴旂殑鍙傛暟
-						if (savedTestStandardId) {
-							// 纭繚绫诲瀷鍖归厤锛坕tem.id 鍙兘鏄暟瀛楁垨瀛楃涓诧級
-							const matchedOption = testStandardOptions.value.find(item => 
-								item.id == savedTestStandardId || String(item.id) === String(savedTestStandardId)
-							);
-							if (matchedOption) {
-								// 纭繚浣跨敤鍖归厤椤圭殑 id锛堜繚鎸佺被鍨嬩竴鑷达級
-								form.value.testStandardId = matchedOption.id;
-								// 缂栬緫淇濈暀鍘熸楠屽�硷紝鐩存帴鎷夊彇鍘熷弬鏁版暟鎹�
-								getQualityInspectParamList(row.id);
-							} else {
-								// 濡傛灉鎵句笉鍒板尮閰嶉」锛屽皾璇曠洿鎺ヤ娇鐢ㄥ師鍊�
-								console.warn('鏈壘鍒板尮閰嶇殑鎸囨爣閫夐」锛宼estStandardId:', savedTestStandardId, '鍙敤閫夐」:', testStandardOptions.value);
-								form.value.testStandardId = savedTestStandardId;
-								getQualityInspectParamList(row.id);
-							}
-						} else {
-							// 鍚﹀垯浣跨敤鏃х殑閫昏緫
-							getQualityInspectParamList(row.id);
-						}
-					}, 100);
-				});
-			});
-		} else {
-			getQualityInspectParamList(row.id);
-		}
-	}
-	// 鏈�鍚庡啀鎵撳紑寮圭獥锛屽苟娓呯悊鏍¢獙鎬侊紝閬垮厤蹇呭~鎻愮ず闂儊
-	dialogFormVisible.value = true;
-	nextTick(() => {
-		proxy.$refs?.formRef?.clearValidate?.();
-	});
-}
-const getProductOptions = () => {
-  return productTreeList().then((res) => {
-    productOptions.value = convertIdToValue(res);
-		return productOptions.value;
+  const dialogFormVisible = ref(false);
+  const operationType = ref("");
+  const data = reactive({
+    form: {
+      checkTime: "",
+      process: "",
+      checkName: "",
+      productName: "",
+      productId: "",
+      productModelId: "",
+      model: "",
+      testStandardId: "",
+      unit: "",
+      quantity: "",
+      qualifiedQuantity: "",
+      unqualifiedQuantity: "",
+      checkCompany: "",
+      checkResult: "",
+    },
+    rules: {
+      checkTime: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+      process: [{ required: true, message: "璇烽�夋嫨宸ュ簭", trigger: "change" }],
+      checkName: [{ required: false, message: "璇疯緭鍏�", trigger: "blur" }],
+      productId: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+      productModelId: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+      testStandardId: [{ required: false, message: "璇烽�夋嫨鎸囨爣", trigger: "change" }],
+      unit: [{ required: false, message: "璇疯緭鍏�", trigger: "blur" }],
+      quantity: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+      qualifiedQuantity: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+      unqualifiedQuantity: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+      checkCompany: [{ required: false, message: "璇疯緭鍏�", trigger: "blur" }],
+      checkResult: [{ required: true, message: "璇疯緭鍏�", trigger: "change" }],
+    },
   });
-};
-const getModels = (value) => {
-  form.value.productModelId = undefined;
-  form.value.unit = undefined;
-  modelOptions.value = [];
-  currentProductId.value = value
-  form.value.productName = findNodeById(productOptions.value, value);
-  modelList({ id: value }).then((res) => {
-    modelOptions.value = res;
-  })
-  if (currentProductId.value) {
-    getList();
-  }
-};
+  const userList = ref([]);
+  const { form, rules } = toRefs(data);
+  // 鏄惁涓烘煡鐪嬫ā寮�
+  const isViewMode = computed(() => operationType.value === 'view');
+  // 缂栬緫鏃讹細productMainId 鎴� purchaseLedgerId 浠讳竴鏈夊�煎垯宸ュ簭銆佹暟閲忕疆鐏�
+  const processQuantityDisabled = computed(() => {
+    const v = form.value || {};
+    return !!(v.productMainId != null || v.purchaseLedgerId != null);
+  });
+  const processList = ref([]); // 宸ュ簭涓嬫媺鍒楄〃锛堝伐搴忓悕绉� name锛�
+  const supplierList = ref([]);
+  const productOptions = ref([]);
+  const tableColumn = ref([
+    {
+      label: "鎸囨爣",
+      prop: "parameterItem",
+    },
+    {
+      label: "鍗曚綅",
+      prop: "unit",
+    },
+    {
+      label: "鏍囧噯鍊�",
+      prop: "standardValue",
+    },
+    {
+      label: "鍐呮帶鍊�",
+      prop: "controlValue",
+    },
+    {
+      label: "妫�楠屽��",
+      prop: "testValue",
+      dataType: "slot",
+      slot: "slot",
+    },
+  ]);
+  const tableData = ref([]);
+  const tableLoading = ref(false);
+  const currentProductId = ref(0);
+  const testStandardOptions = ref([]); // 鎸囨爣閫夋嫨涓嬫媺妗嗘暟鎹�
+  const modelOptions = ref([]);
 
-const handleChangeModel = (value) => {
-  form.value.model = modelOptions.value.find(item => item.id == value)?.model || '';
-  form.value.unit = modelOptions.value.find(item => item.id == value)?.unit || '';
-}
-
-const findNodeById = (nodes, productId) => {
-  for (let i = 0; i < nodes.length; i++) {
-    if (nodes[i].value === productId) {
-      return nodes[i].label; // 鎵惧埌鑺傜偣锛岃繑鍥炶鑺傜偣
+  // 鎵撳紑寮规
+  const openDialog = async (type, row) => {
+    operationType.value = type;
+    getOptions().then(res => {
+      supplierList.value = res.data;
+    });
+    // 鍔犺浇宸ュ簭涓嬫媺鍒楄〃
+    try {
+      const res = await list({ size: -1, current: -1 });
+      processList.value = res.data.records || [];
+    } catch (e) {
+      console.error("鍔犺浇宸ュ簭鍒楄〃澶辫触", e);
+      processList.value = [];
     }
-    if (nodes[i].children && nodes[i].children.length > 0) {
-      const foundNode = findNodeById(nodes[i].children, productId);
-      if (foundNode) {
-        return foundNode; // 鍦ㄥ瓙鑺傜偣涓壘鍒帮紝杩斿洖璇ヨ妭鐐�
-      }
-    }
-  }
-  return null; // 娌℃湁鎵惧埌鑺傜偣锛岃繑鍥瀗ull
-};
-function convertIdToValue(data) {
-  return data.map((item) => {
-    const { id, children, ...rest } = item;
-    const newItem = {
-      ...rest,
-      value: id, // 灏� id 鏀逛负 value
+    let userLists = await userListNoPage();
+    userList.value = userLists.data;
+    // 鍏堥噸缃〃鍗曟暟鎹紙淇濇寔瀛楁瀹屾暣锛岄伩鍏嶅脊绐楅娆℃覆鏌撴椂瑙﹀彂蹇呭~绾㈡鈥滈棯涓�涓嬧�濓級
+    form.value = {
+      checkTime: "",
+      process: "",
+      checkName: "",
+      productName: "",
+      productId: "",
+      productModelId: "",
+      model: "",
+      testStandardId: "",
+      unit: "",
+      quantity: "",
+      checkCompany: "",
+      checkResult: "",
     };
-    if (children && children.length > 0) {
-      newItem.children = convertIdToValue(children);
-    }
-    
-    return newItem;
-  });
-}
-// 宸ュ簭鍙樺寲澶勭悊
-// 鎻愪氦浜у搧琛ㄥ崟
-const submitForm = () => {
-  proxy.$refs.formRef.validate(valid => {
-    if (valid) {
-      form.value.inspectType = 1
-			const processName = form.value.process || '';
-			if (operationType.value === "add") {
-				tableData.value.forEach((item) => {
-					delete item.id
-				})
-			}
-			const data = {
-				...form.value, 
-				process: processName, // 淇濈暀 process 瀛楁浠ュ吋瀹瑰悗绔�
-				qualityInspectParams: tableData.value
-			}
-      if (operationType.value === "add") {
-        qualityInspectAdd(data).then(res => {
-          proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
-          closeDia();
-        })
+    testStandardOptions.value = [];
+    tableData.value = [];
+    // 鍏堢‘淇濅骇鍝佹爲宸插姞杞斤紝鍚﹀垯缂栬緫鏃朵骇鍝�/瑙勬牸鍨嬪彿鏃犳硶鍙嶆樉
+    await getProductOptions();
+    if (operationType.value === "edit" || operationType.value === "view") {
+      // 鍏堜繚瀛� testStandardId锛岄伩鍏嶈娓呯┖
+      const savedTestStandardId = row.testStandardId;
+      // 鍏堣缃〃鍗曟暟鎹紝浣嗘殏鏃舵竻绌� testStandardId锛岀瓑閫夐」鍔犺浇瀹屾垚鍚庡啀璁剧疆
+      form.value = { ...row, testStandardId: "" };
+      currentProductId.value = row.productId || 0;
+      // 鍏抽敭锛氱紪杈戞椂鍔犺浇瑙勬牸鍨嬪彿涓嬫媺閫夐」锛屾墠鑳藉弽鏄� productModelId
+      if (currentProductId.value) {
+        try {
+          const res = await modelList({ id: currentProductId.value });
+          modelOptions.value = res || [];
+          // 鍚屾鍥炲~ model / unit锛堟湁浜涙帴鍙h繑鍥炵殑 row 閲屽彲鑳芥病甯﹀叏锛�
+          if (form.value.productModelId) {
+            handleChangeModel(form.value.productModelId);
+          }
+        } catch (e) {
+          console.error("鍔犺浇瑙勬牸鍨嬪彿澶辫触", e);
+          modelOptions.value = [];
+        }
+      }
+      // 缂栬緫妯″紡涓嬶紝鍏堝姞杞芥寚鏍囬�夐」锛岀劧鍚庡姞杞藉弬鏁板垪琛�
+      if (currentProductId.value) {
+        // 鍏堝姞杞芥寚鏍囬�夐」
+        let params = {
+          productId: currentProductId.value,
+          inspectType: 1,
+          process: form.value.process || "",
+        };
+        qualityInspectDetailByProductId(params).then(res => {
+          testStandardOptions.value = res.data || [];
+          // 浣跨敤 nextTick 鍜� setTimeout 纭繚閫夐」宸茬粡娓叉煋鍒� DOM
+          nextTick(() => {
+            setTimeout(() => {
+              // 濡傛灉缂栬緫鏁版嵁涓湁 testStandardId锛屽垯璁剧疆骞跺姞杞藉搴旂殑鍙傛暟
+              if (savedTestStandardId) {
+                // 纭繚绫诲瀷鍖归厤锛坕tem.id 鍙兘鏄暟瀛楁垨瀛楃涓诧級
+                const matchedOption = testStandardOptions.value.find(
+                  item =>
+                    item.id == savedTestStandardId ||
+                    String(item.id) === String(savedTestStandardId)
+                );
+                if (matchedOption) {
+                  // 纭繚浣跨敤鍖归厤椤圭殑 id锛堜繚鎸佺被鍨嬩竴鑷达級
+                  form.value.testStandardId = matchedOption.id;
+                  // 缂栬緫淇濈暀鍘熸楠屽�硷紝鐩存帴鎷夊彇鍘熷弬鏁版暟鎹�
+                  getQualityInspectParamList(row.id);
+                } else {
+                  // 濡傛灉鎵句笉鍒板尮閰嶉」锛屽皾璇曠洿鎺ヤ娇鐢ㄥ師鍊�
+                  console.warn(
+                    "鏈壘鍒板尮閰嶇殑鎸囨爣閫夐」锛宼estStandardId:",
+                    savedTestStandardId,
+                    "鍙敤閫夐」:",
+                    testStandardOptions.value
+                  );
+                  form.value.testStandardId = savedTestStandardId;
+                  getQualityInspectParamList(row.id);
+                }
+              } else {
+                // 鍚﹀垯浣跨敤鏃х殑閫昏緫
+                getQualityInspectParamList(row.id);
+              }
+            }, 100);
+          });
+        });
       } else {
-        qualityInspectUpdate(data).then(res => {
-          proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
-          closeDia();
-        })
+        getQualityInspectParamList(row.id);
       }
     }
-  })
-}
-const getList = () => {
-	if (!currentProductId.value) {
-		testStandardOptions.value = [];
-		tableData.value = [];
-		return;
-	}
-	const processName = form.value.process || '';
-	let params = {
-		productId: currentProductId.value,
-		inspectType: 1,
-		process: processName
-	}
-	qualityInspectDetailByProductId(params).then(res => {
-		// 淇濆瓨涓嬫媺妗嗛�夐」鏁版嵁
-		testStandardOptions.value = res.data || [];
-		// 娓呯┖琛ㄦ牸鏁版嵁锛岀瓑寰呯敤鎴烽�夋嫨鎸囨爣
-		tableData.value = [];
-		// 娓呯┖鎸囨爣閫夋嫨
-		form.value.testStandardId = '';
-	})
-}
+    // 鏈�鍚庡啀鎵撳紑寮圭獥锛屽苟娓呯悊鏍¢獙鎬侊紝閬垮厤蹇呭~鎻愮ず闂儊
+    dialogFormVisible.value = true;
+    nextTick(() => {
+      proxy.$refs?.formRef?.clearValidate?.();
+    });
+  };
+  const getProductOptions = () => {
+    return productTreeList().then(res => {
+      productOptions.value = convertIdToValue(res);
+      return productOptions.value;
+    });
+  };
+  const getModels = value => {
+    form.value.productModelId = undefined;
+    form.value.unit = undefined;
+    modelOptions.value = [];
+    currentProductId.value = value;
+    form.value.productName = findNodeById(productOptions.value, value);
+    modelList({ id: value }).then(res => {
+      modelOptions.value = res;
+    });
+    if (currentProductId.value) {
+      getList();
+    }
+  };
 
-// 鎸囨爣閫夋嫨鍙樺寲澶勭悊
-const handleTestStandardChange = (testStandardId) => {
-	if (!testStandardId) {
-		tableData.value = [];
-		return;
-	}
-	tableLoading.value = true;
-	getQualityTestStandardParamByTestStandardId(testStandardId).then(res => {
-		tableData.value = res.data || [];
-	}).catch(error => {
-		console.error('鑾峰彇鏍囧噯鍙傛暟澶辫触:', error);
-		tableData.value = [];
-	}).finally(() => {
-		tableLoading.value = false;
-	})
-}
-const getQualityInspectParamList = (id) => {
-	qualityInspectParamInfo(id).then(res => {
-		tableData.value = res.data;
-	})
-}
-// 鍏抽棴寮规
-const closeDia = () => {
-  proxy.resetForm("formRef");
-  tableData.value = [];
-  testStandardOptions.value = [];
-  form.value.testStandardId = '';
-  dialogFormVisible.value = false;
-  emit('close')
-};
-defineExpose({
-  openDialog,
-});
+  const handleChangeModel = value => {
+    form.value.model =
+      modelOptions.value.find(item => item.id == value)?.model || "";
+    form.value.unit =
+      modelOptions.value.find(item => item.id == value)?.unit || "";
+  };
+
+  const handleQualifiedQuantityChange = (value) => {
+    if (value === null || value === undefined) {
+      form.value.qualifiedQuantity = 0;
+      return;
+    }
+    const quantity = parseFloat(form.value.quantity) || 0;
+    const qualified = parseFloat(value) || 0;
+    form.value.qualifiedQuantity = qualified > quantity?quantity:qualified;
+    form.value.unqualifiedQuantity = Math.max(0, quantity - qualified);
+  };
+
+  const handleUnqualifiedQuantityChange = (value) => {
+    if (value === null || value === undefined) {
+      form.value.unqualifiedQuantity = 0;
+      return;
+    }
+    const quantity = parseFloat(form.value.quantity) || 0;
+    const unqualified = parseFloat(value) || 0;
+    form.value.unqualifiedQuantity = unqualified > quantity?quantity:unqualified;
+    form.value.qualifiedQuantity = Math.max(0, quantity - unqualified);
+  };
+
+  const findNodeById = (nodes, productId) => {
+    for (let i = 0; i < nodes.length; i++) {
+      if (nodes[i].value === productId) {
+        return nodes[i].label; // 鎵惧埌鑺傜偣锛岃繑鍥炶鑺傜偣
+      }
+      if (nodes[i].children && nodes[i].children.length > 0) {
+        const foundNode = findNodeById(nodes[i].children, productId);
+        if (foundNode) {
+          return foundNode; // 鍦ㄥ瓙鑺傜偣涓壘鍒帮紝杩斿洖璇ヨ妭鐐�
+        }
+      }
+    }
+    return null; // 娌℃湁鎵惧埌鑺傜偣锛岃繑鍥瀗ull
+  };
+  function convertIdToValue(data) {
+    return data.map(item => {
+      const { id, children, ...rest } = item;
+      const newItem = {
+        ...rest,
+        value: id, // 灏� id 鏀逛负 value
+      };
+      if (children && children.length > 0) {
+        newItem.children = convertIdToValue(children);
+      }
+
+      return newItem;
+    });
+  }
+  // 宸ュ簭鍙樺寲澶勭悊
+  // 鎻愪氦浜у搧琛ㄥ崟
+  const submitForm = () => {
+    proxy.$refs.formRef.validate(valid => {
+      if (valid) {
+        form.value.inspectType = 1;
+        const processName = form.value.process || "";
+        if (operationType.value === "add") {
+          tableData.value.forEach(item => {
+            delete item.id;
+          });
+        }
+        // 纭繚鏁伴噺涓嶄负null
+        const quantity = parseFloat(form.value.quantity) || 0;
+        const qualified = parseFloat(form.value.qualifiedQuantity) || 0;
+        const unqualified = parseFloat(form.value.unqualifiedQuantity) || 0;
+
+        // 楠岃瘉鏁伴噺鍏崇郴
+        if (qualified + unqualified !== quantity) {
+          proxy.$modal.msgError("鍚堟牸鏁伴噺涓庝笉鍚堟牸鏁伴噺涔嬪拰蹇呴』绛変簬鎬绘暟閲�");
+          return;
+        }
+
+        const data = {
+          ...form.value,
+          process: processName, // 淇濈暀 process 瀛楁浠ュ吋瀹瑰悗绔�
+          qualityInspectParams: tableData.value,
+        };
+        if (operationType.value === "add") {
+          qualityInspectAdd(data).then(res => {
+            proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+            closeDia();
+          });
+        } else {
+          qualityInspectUpdate(data).then(res => {
+            proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+            closeDia();
+          });
+        }
+      }
+    });
+  };
+  const getList = () => {
+    if (!currentProductId.value) {
+      testStandardOptions.value = [];
+      tableData.value = [];
+      return;
+    }
+    const processName = form.value.process || "";
+    let params = {
+      productId: currentProductId.value,
+      inspectType: 1,
+      process: processName,
+    };
+    qualityInspectDetailByProductId(params).then(res => {
+      // 淇濆瓨涓嬫媺妗嗛�夐」鏁版嵁
+      testStandardOptions.value = res.data || [];
+      // 娓呯┖琛ㄦ牸鏁版嵁锛岀瓑寰呯敤鎴烽�夋嫨鎸囨爣
+      tableData.value = [];
+      // 娓呯┖鎸囨爣閫夋嫨
+      form.value.testStandardId = "";
+    });
+  };
+
+  // 鎸囨爣閫夋嫨鍙樺寲澶勭悊
+  const handleTestStandardChange = testStandardId => {
+    if (!testStandardId) {
+      tableData.value = [];
+      return;
+    }
+    tableLoading.value = true;
+    getQualityTestStandardParamByTestStandardId(testStandardId)
+      .then(res => {
+        tableData.value = res.data || [];
+        tableData.value = tableData.value.map(item => ({
+          ...item,
+          id: null
+        }));
+      })
+      .catch(error => {
+        console.error("鑾峰彇鏍囧噯鍙傛暟澶辫触:", error);
+        tableData.value = [];
+      })
+      .finally(() => {
+        tableLoading.value = false;
+      });
+  };
+  const getQualityInspectParamList = id => {
+    qualityInspectParamInfo(id).then(res => {
+      tableData.value = res.data;
+    });
+  };
+  // 鍏抽棴寮规
+  const closeDia = () => {
+    proxy.resetForm("formRef");
+    tableData.value = [];
+    testStandardOptions.value = [];
+    form.value.testStandardId = "";
+    dialogFormVisible.value = false;
+    emit("close");
+  };
+  defineExpose({
+    openDialog,
+  });
 </script>
 
 <style scoped>
-
-</style>
\ No newline at end of file
+</style>
diff --git a/src/views/qualityManagement/processInspection/index.vue b/src/views/qualityManagement/processInspection/index.vue
index e5504b6..178e81a 100644
--- a/src/views/qualityManagement/processInspection/index.vue
+++ b/src/views/qualityManagement/processInspection/index.vue
@@ -122,8 +122,18 @@
     prop: "unit",
   },
   {
-    label: "鏁伴噺",
+    label: "鎬绘暟閲�",
     prop: "quantity",
+    width: 100
+  },
+  {
+    label: "鍚堟牸鏁伴噺",
+    prop: "qualifiedQuantity",
+    width: 100
+  },
+  {
+    label: "涓嶅悎鏍兼暟閲�",
+    prop: "unqualifiedQuantity",
     width: 100
   },
   {
@@ -141,7 +151,7 @@
       } else if (params == '鍚堟牸') {
         return "success";
       } else {
-        return null;
+        return 'danger';
       }
     },
   },
@@ -178,6 +188,13 @@
 					}
 					return false;
 				}
+      },
+      {
+        name: "鏌ョ湅",
+        type: "text",
+        clickFun: (row) => {
+          openForm("view", row);
+        },
       },
       {
         name: "闄勪欢",
@@ -363,13 +380,13 @@
 			type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
 		})
 		const downloadUrl = window.URL.createObjectURL(blob)
-		
+
 		const link = document.createElement('a')
 		link.href = downloadUrl
 		link.download = '杩囩▼妫�楠屾姤鍛�.docx'
 		document.body.appendChild(link)
 		link.click()
-		
+
 		document.body.removeChild(link)
 		window.URL.revokeObjectURL(downloadUrl)
 	})
diff --git a/src/views/qualityManagement/rawMaterialInspection/components/formDia.vue b/src/views/qualityManagement/rawMaterialInspection/components/formDia.vue
index 7e373bf..8bcc72b 100644
--- a/src/views/qualityManagement/rawMaterialInspection/components/formDia.vue
+++ b/src/views/qualityManagement/rawMaterialInspection/components/formDia.vue
@@ -2,7 +2,7 @@
   <div>
     <el-dialog
         v-model="dialogFormVisible"
-        :title="operationType === 'add' ? '鏂板鍘熸潗鏂欐楠�' : '缂栬緫鍘熸潗鏂欐楠�'"
+        :title="operationType === 'add' ? '鏂板鍘熸潗鏂欐楠�' : operationType === 'view' ? '鏌ョ湅鍘熸潗鏂欐楠�' : '缂栬緫鍘熸潗鏂欐楠�'"
         width="70%"
         @close="closeDia"
     >
@@ -14,7 +14,7 @@
                   v-model="form.supplier"
                   placeholder="璇烽�夋嫨"
                   clearable
-                  :disabled="supplierQuantityDisabled"
+                  :disabled="isViewMode || supplierQuantityDisabled"
               >
                 <el-option
                     v-for="item in supplierList"
@@ -35,7 +35,7 @@
                   @change="getModels"
                   :data="productOptions"
                   :render-after-expand="false"
-                  :disabled="operationType === 'edit'"
+                  :disabled="isViewMode || operationType === 'edit'"
                   style="width: 100%"
               />
             </el-form-item>
@@ -44,7 +44,7 @@
         <el-row :gutter="30">
           <el-col :span="12">
             <el-form-item label="瑙勬牸鍨嬪彿锛�" prop="productModelId">
-              <el-select v-model="form.productModelId" placeholder="璇烽�夋嫨" clearable :disabled="operationType === 'edit'"
+              <el-select v-model="form.productModelId" placeholder="璇烽�夋嫨" clearable :disabled="isViewMode || operationType === 'edit'"
                          filterable readonly @change="handleChangeModel">
                 <el-option v-for="item in modelOptions" :key="item.id" :label="item.model" :value="item.id" />
               </el-select>
@@ -58,6 +58,7 @@
                 clearable
                 @change="handleTestStandardChange"
                 style="width: 100%"
+                :disabled="isViewMode"
               >
                 <el-option
                   v-for="item in testStandardOptions"
@@ -78,21 +79,39 @@
           <el-col :span="12">
             <el-form-item label="鏁伴噺锛�" prop="quantity">
               <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.quantity" placeholder="璇疯緭鍏�"
-                               clearable :precision="2" :disabled="supplierQuantityDisabled"/>
+                               clearable :precision="2" :disabled="isViewMode || supplierQuantityDisabled"/>
             </el-form-item>
           </el-col>
         </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="鍚堟牸鏁伴噺锛�" prop="qualifiedQuantity">
+              <el-input-number :step="0.01" :min="0" :max="form.quantity || 0" style="width: 100%"
+                               v-model="form.qualifiedQuantity" placeholder="璇疯緭鍏�" :precision="2"
+                               @change="onQualifiedChange" :disabled="isViewMode"/>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="涓嶅悎鏍兼暟閲忥細" prop="unqualifiedQuantity">
+              <el-input-number :step="0.01" :min="0" :max="form.quantity || 0" style="width: 100%"
+                               v-model="form.unqualifiedQuantity" placeholder="璇疯緭鍏�" :precision="2"
+                               @change="onUnqualifiedChange" :disabled="isViewMode"/>
+            </el-form-item>
+          </el-col>
+        </el-row>
+
         <el-row :gutter="30">
           <el-col :span="12">
             <el-form-item label="妫�娴嬪崟浣嶏細" prop="checkCompany">
-              <el-input v-model="form.checkCompany" placeholder="璇疯緭鍏�" clearable/>
+              <el-input v-model="form.checkCompany" placeholder="璇疯緭鍏�" clearable :disabled="isViewMode"/>
             </el-form-item>
           </el-col>
           <el-col :span="12">
             <el-form-item label="妫�娴嬬粨鏋滐細" prop="checkResult">
-              <el-select v-model="form.checkResult">
+              <el-select v-model="form.checkResult" :disabled="isViewMode">
                 <el-option label="鍚堟牸" value="鍚堟牸"/>
                 <el-option label="涓嶅悎鏍�" value="涓嶅悎鏍�"/>
+                <el-option label="閮ㄥ垎鍚堟牸" value="閮ㄥ垎鍚堟牸"/>
               </el-select>
             </el-form-item>
           </el-col>
@@ -100,7 +119,7 @@
         <el-row :gutter="30">
           <el-col :span="12">
             <el-form-item label="妫�楠屽憳锛�" prop="checkName">
-              <el-select v-model="form.checkName" placeholder="璇烽�夋嫨" clearable style="width: 100%">
+              <el-select v-model="form.checkName" placeholder="璇烽�夋嫨" clearable style="width: 100%" :disabled="isViewMode">
                 <el-option v-for="item in userList" :key="item.nickName" :label="item.nickName" :value="item.nickName"/>
               </el-select>
             </el-form-item>
@@ -115,6 +134,7 @@
                   format="YYYY-MM-DD"
                   clearable
                   style="width: 100%"
+                  :disabled="isViewMode"
               />
             </el-form-item>
           </el-col>
@@ -131,13 +151,16 @@
           height="400"
       >
         <template #slot="{ row }">
-          <el-input v-model="row.testValue" clearable/>
+          <el-input v-model="row.testValue" clearable :disabled="isViewMode"/>
         </template>
       </PIMTable>
       <template #footer>
         <div class="dialog-footer">
-          <el-button type="primary" @click="submitForm">纭</el-button>
-          <el-button @click="closeDia">鍙栨秷</el-button>
+          <template v-if="!isViewMode">
+            <el-button type="primary" @click="submitForm">纭</el-button>
+            <el-button @click="closeDia">鍙栨秷</el-button>
+          </template>
+          <el-button v-else @click="closeDia">鍏抽棴</el-button>
         </div>
       </template>
     </el-dialog>
@@ -182,6 +205,8 @@
     testStandardId: [{required: false, message: "璇烽�夋嫨鎸囨爣", trigger: "change"}],
     unit: [{required: false, message: "璇疯緭鍏�", trigger: "blur"}],
     quantity: [{required: true, message: "璇疯緭鍏�", trigger: "blur"}],
+    qualifiedQuantity: [{required: true, message: "璇疯緭鍏�", trigger: "blur"}],
+    unqualifiedQuantity: [{required: true, message: "璇疯緭鍏�", trigger: "blur"}],
     checkCompany: [{required: false, message: "璇疯緭鍏�", trigger: "blur"}],
     checkResult: [{required: true, message: "璇烽�夋嫨妫�娴嬬粨鏋�", trigger: "change"}],
   },
@@ -220,6 +245,9 @@
 const testStandardOptions = ref([]); // 鎸囨爣閫夋嫨涓嬫媺妗嗘暟鎹�
 const modelOptions = ref([]);
 const userList = ref([]); // 妫�楠屽憳涓嬫媺鍒楄〃
+
+// 鏄惁涓烘煡鐪嬫ā寮�
+const isViewMode = computed(() => operationType.value === 'view');
 
 // 缂栬緫鏃讹細productMainId 鎴� purchaseLedgerId 浠讳竴鏈夊�煎垯渚涘簲鍟嗐�佹暟閲忕疆鐏�
 const supplierQuantityDisabled = computed(() => {
@@ -260,7 +288,7 @@
   tableData.value = [];
   // 鍏堢‘淇濅骇鍝佹爲宸插姞杞斤紝鍚﹀垯缂栬緫鏃朵骇鍝�/瑙勬牸鍨嬪彿鏃犳硶鍙嶆樉
   await getProductOptions();
-  if (operationType.value === 'edit') {
+  if (operationType.value === 'edit' || operationType.value === 'view') {
     // 鍏堜繚瀛� testStandardId锛岄伩鍏嶈娓呯┖
     const savedTestStandardId = row.testStandardId;
     form.value = {...row}
@@ -294,7 +322,7 @@
             // 濡傛灉缂栬緫鏁版嵁涓湁 testStandardId锛屽垯璁剧疆骞跺姞杞藉搴旂殑鍙傛暟
             if (savedTestStandardId) {
               // 纭繚绫诲瀷鍖归厤锛坕tem.id 鍙兘鏄暟瀛楁垨瀛楃涓诧級
-              const matchedOption = testStandardOptions.value.find(item => 
+              const matchedOption = testStandardOptions.value.find(item =>
                 item.id == savedTestStandardId || String(item.id) === String(savedTestStandardId)
               );
               if (matchedOption) {
@@ -435,6 +463,10 @@
   tableLoading.value = true;
   getQualityTestStandardParamByTestStandardId(testStandardId).then(res => {
     tableData.value = res.data || [];
+    tableData.value = tableData.value.map(item => ({
+      ...item,
+      id: null
+    }));
   }).catch(error => {
     console.error('鑾峰彇鏍囧噯鍙傛暟澶辫触:', error);
     tableData.value = [];
@@ -448,6 +480,32 @@
     tableData.value = res.data;
   })
 }
+// 鑷姩璁$畻鍚堟牸鏁伴噺鍙樺寲鏃剁殑涓嶅悎鏍兼暟閲�
+const onQualifiedChange = (value) => {
+  if (form.value.quantity !== undefined && form.value.quantity !== null) {
+    const maxUnqualified = form.value.quantity - value;
+    if (maxUnqualified >= 0) {
+      form.value.unqualifiedQuantity = maxUnqualified;
+    } else {
+      form.value.qualifiedQuantity = form.value.quantity;
+      form.value.unqualifiedQuantity = 0;
+    }
+  }
+};
+
+// 鑷姩璁$畻涓嶅悎鏍兼暟閲忓彉鍖栨椂鐨勫悎鏍兼暟閲�
+const onUnqualifiedChange = (value) => {
+  if (form.value.quantity !== undefined && form.value.quantity !== null) {
+    const maxQualified = form.value.quantity - value;
+    if (maxQualified >= 0) {
+      form.value.qualifiedQuantity = maxQualified;
+    } else {
+      form.value.unqualifiedQuantity = form.value.quantity;
+      form.value.qualifiedQuantity = 0;
+    }
+  }
+};
+
 // 鍏抽棴寮规
 const closeDia = () => {
   proxy.resetForm("formRef");
@@ -464,4 +522,4 @@
 
 <style scoped>
 
-</style>
\ No newline at end of file
+</style>
diff --git a/src/views/qualityManagement/rawMaterialInspection/index.vue b/src/views/qualityManagement/rawMaterialInspection/index.vue
index cc2c151..b6adb40 100644
--- a/src/views/qualityManagement/rawMaterialInspection/index.vue
+++ b/src/views/qualityManagement/rawMaterialInspection/index.vue
@@ -124,8 +124,23 @@
     prop: "unit",
   },
   {
-    label: "鏁伴噺",
+    label: "鎬绘暟閲�",
     prop: "quantity",
+    width: 100
+  },
+  {
+    label: "鍚堟牸鏁伴噺",
+    prop: "qualifiedQuantity",
+    width: 100
+  },
+  {
+    label: "涓嶅悎鏍兼暟閲�",
+    prop: "unqualifiedQuantity",
+    width: 100
+  },
+  {
+    label: "妫�娴嬪崟浣�",
+    prop: "checkCompany",
     width: 120
   },
   {
@@ -143,7 +158,7 @@
       } else if (params === '鍚堟牸') {
         return "success";
       } else {
-        return null;
+        return 'danger';
       }
     },
   },
@@ -182,6 +197,13 @@
 				}
       },
       {
+        name: "鏌ョ湅",
+        type: "text",
+        clickFun: (row) => {
+          openForm("view", row);
+        },
+      },
+      {
         name: "闄勪欢",
         type: "text",
         clickFun: (row) => {
diff --git a/src/views/reportAnalysis/PSIDataAnalysis/components/center-bottom.vue b/src/views/reportAnalysis/PSIDataAnalysis/components/center-bottom.vue
index ccd7504..f4e49b6 100644
--- a/src/views/reportAnalysis/PSIDataAnalysis/components/center-bottom.vue
+++ b/src/views/reportAnalysis/PSIDataAnalysis/components/center-bottom.vue
@@ -23,7 +23,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted } from 'vue'
+import { ref, onMounted, inject, watch } from 'vue'
 import * as echarts from 'echarts'
 import Echarts from '@/components/Echarts/echarts.vue'
 import PanelHeader from './PanelHeader.vue'
@@ -151,6 +151,13 @@
   fetchData()
 }
 
+const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
+if (dataDashboardRefreshTick) {
+  watch(dataDashboardRefreshTick, () => {
+    fetchData()
+  })
+}
+
 onMounted(() => {
   fetchData()
 })
diff --git a/src/views/reportAnalysis/PSIDataAnalysis/components/center-center.vue b/src/views/reportAnalysis/PSIDataAnalysis/components/center-center.vue
index 0f3ec84..6e39eb1 100644
--- a/src/views/reportAnalysis/PSIDataAnalysis/components/center-center.vue
+++ b/src/views/reportAnalysis/PSIDataAnalysis/components/center-center.vue
@@ -27,7 +27,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted } from 'vue'
+import { ref, onMounted, inject, watch } from 'vue'
 import Echarts from '@/components/Echarts/echarts.vue'
 import { productTurnoverDays } from '@/api/viewIndex.js'
 
@@ -82,6 +82,13 @@
     })
 }
 
+const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
+if (dataDashboardRefreshTick) {
+  watch(dataDashboardRefreshTick, () => {
+    fetchData()
+  })
+}
+
 onMounted(() => {
   fetchData()
 })
diff --git a/src/views/reportAnalysis/PSIDataAnalysis/components/center-top.vue b/src/views/reportAnalysis/PSIDataAnalysis/components/center-top.vue
index 0937b32..055fb66 100644
--- a/src/views/reportAnalysis/PSIDataAnalysis/components/center-top.vue
+++ b/src/views/reportAnalysis/PSIDataAnalysis/components/center-top.vue
@@ -24,7 +24,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted } from 'vue'
+import { ref, onMounted, inject, watch } from 'vue'
 import { salesPurchaseStorageProductCount } from '@/api/viewIndex.js'
 
 const statItems = ref([])
@@ -52,6 +52,13 @@
     })
 }
 
+const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
+if (dataDashboardRefreshTick) {
+  watch(dataDashboardRefreshTick, () => {
+    fetchData()
+  })
+}
+
 onMounted(() => {
   fetchData()
 })
diff --git a/src/views/reportAnalysis/PSIDataAnalysis/components/left-bottom.vue b/src/views/reportAnalysis/PSIDataAnalysis/components/left-bottom.vue
index 669c826..65a72fe 100644
--- a/src/views/reportAnalysis/PSIDataAnalysis/components/left-bottom.vue
+++ b/src/views/reportAnalysis/PSIDataAnalysis/components/left-bottom.vue
@@ -22,7 +22,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted, onBeforeUnmount, computed } from 'vue'
+import { ref, onMounted, onBeforeUnmount, computed, inject, watch } from 'vue'
 import Echarts from '@/components/Echarts/echarts.vue'
 import PanelHeader from './PanelHeader.vue'
 import CarouselCards from './CarouselCards.vue'
@@ -205,6 +205,13 @@
     })
 }
 
+const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
+if (dataDashboardRefreshTick) {
+  watch(dataDashboardRefreshTick, () => {
+    fetchData()
+  })
+}
+
 onMounted(() => {
   fetchData()
   initBackground()
diff --git a/src/views/reportAnalysis/PSIDataAnalysis/components/left-top.vue b/src/views/reportAnalysis/PSIDataAnalysis/components/left-top.vue
index 8fcaa42..f5dac31 100644
--- a/src/views/reportAnalysis/PSIDataAnalysis/components/left-top.vue
+++ b/src/views/reportAnalysis/PSIDataAnalysis/components/left-top.vue
@@ -21,7 +21,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted, onBeforeUnmount, computed } from 'vue'
+import { ref, onMounted, onBeforeUnmount, computed, inject, watch } from 'vue'
 import { productSalesAnalysis } from '@/api/viewIndex.js'
 import PanelHeader from './PanelHeader.vue'
 import CarouselCards from './CarouselCards.vue'
@@ -175,6 +175,13 @@
     })
 }
 
+const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
+if (dataDashboardRefreshTick) {
+  watch(dataDashboardRefreshTick, () => {
+    fetchData()
+  })
+}
+
 onMounted(() => {
   fetchData()
   initBackground()
diff --git a/src/views/reportAnalysis/PSIDataAnalysis/index.vue b/src/views/reportAnalysis/PSIDataAnalysis/index.vue
index 065b59d..f81e482 100644
--- a/src/views/reportAnalysis/PSIDataAnalysis/index.vue
+++ b/src/views/reportAnalysis/PSIDataAnalysis/index.vue
@@ -43,7 +43,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue'
+import { ref, onMounted, onBeforeUnmount, nextTick, provide } from 'vue'
 import autofit from 'autofit.js'
 import LeftBottom from './components/left-bottom.vue'
 import CenterCenter from './components/center-center.vue'
@@ -65,6 +65,12 @@
 
 // 鐢ㄦ埛store
 const userStore = useUserStore()
+
+/** 涓� dataDashboard 鍏辩敤娉ㄥ叆鍚嶏紝瀛愮粍浠讹紙鍚鐢ㄧ殑 right-top/right-bottom锛夋瘡鍒嗛挓鍒锋柊 */
+const DASHBOARD_REFRESH_MS = 60 * 1000
+const dataDashboardRefreshTick = ref(0)
+provide('dataDashboardRefreshTick', dataDashboardRefreshTick)
+let dashboardPollTimer = null
 
 // 璁$畻缂╂斁姣斾緥
 const calculateScale = () => {
@@ -140,9 +146,17 @@
   window.addEventListener('fullscreenchange', handleFullscreenChange)
   window.addEventListener('webkitfullscreenchange', handleFullscreenChange)
   window.addEventListener('MSFullscreenChange', handleFullscreenChange)
+
+  dashboardPollTimer = setInterval(() => {
+    dataDashboardRefreshTick.value++
+  }, DASHBOARD_REFRESH_MS)
 })
 
 onBeforeUnmount(() => {
+  if (dashboardPollTimer) {
+    clearInterval(dashboardPollTimer)
+    dashboardPollTimer = null
+  }
   window.removeEventListener('resize', handleResize)
   window.removeEventListener('fullscreenchange', handleFullscreenChange)
   window.removeEventListener('webkitfullscreenchange', handleFullscreenChange)
diff --git a/src/views/reportAnalysis/dataDashboard/components/basic/center-bottom.vue b/src/views/reportAnalysis/dataDashboard/components/basic/center-bottom.vue
index a4824a2..c28c2fa 100644
--- a/src/views/reportAnalysis/dataDashboard/components/basic/center-bottom.vue
+++ b/src/views/reportAnalysis/dataDashboard/components/basic/center-bottom.vue
@@ -20,7 +20,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted, computed } from 'vue'
+import { ref, onMounted, computed, inject, watch } from 'vue'
 import { deptStaffDistribution } from '@/api/viewIndex.js'
 import PanelHeader from '../PanelHeader.vue'
 import Echarts from '@/components/Echarts/echarts.vue'
@@ -148,6 +148,13 @@
   })
 }
 
+const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
+if (dataDashboardRefreshTick) {
+  watch(dataDashboardRefreshTick, () => {
+    getDeptStaffDistribution()
+  })
+}
+
 onMounted(() => {
   getDeptStaffDistribution()
 })
diff --git a/src/views/reportAnalysis/dataDashboard/components/basic/center-top.vue b/src/views/reportAnalysis/dataDashboard/components/basic/center-top.vue
index 950038e..a7d0174 100644
--- a/src/views/reportAnalysis/dataDashboard/components/basic/center-top.vue
+++ b/src/views/reportAnalysis/dataDashboard/components/basic/center-top.vue
@@ -110,7 +110,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue'
+import { ref, onMounted, onBeforeUnmount, nextTick, inject, watch } from 'vue'
 import { homeTodos, summaryStatistics } from '@/api/viewIndex.js'
 import { getLedgerPage } from '@/api/equipmentManagement/ledger.js'
 import { getRepairPage } from '@/api/equipmentManagement/repair.js'
@@ -175,8 +175,23 @@
   })
 }
 
+const destroyTodoListScroll = () => {
+  const todoListEl = refTodoList.value
+  if (todoListEl) {
+    if (todoListEl._animationFrame) {
+      cancelAnimationFrame(todoListEl._animationFrame)
+      todoListEl._animationFrame = null
+    }
+    if (todoListEl._pauseTimer) {
+      clearInterval(todoListEl._pauseTimer)
+      todoListEl._pauseTimer = null
+    }
+  }
+}
+
 // 鍒濆鍖栧緟鍔炰簨椤瑰垪琛ㄦ粴鍔ㄥ姛鑳�
 const initTodoListScroll = () => {
+  destroyTodoListScroll()
   const todoListEl = refTodoList.value
   // 寮哄埗鍚敤婊氬姩锛屼笉妫�鏌ヤ换浣曟潯浠�
   if (todoListEl) {
@@ -259,6 +274,7 @@
 
 // 寰呭姙浜嬮」
 const todoInfoS = () => {
+  destroyTodoListScroll()
   homeTodos().then((res) => {
     todoList.value = res.data
     // 鍦ㄨ幏鍙栧埌寰呭姙浜嬮」鏁版嵁鍚庯紝鍒濆鍖栨粴鍔ㄥ姛鑳�
@@ -268,25 +284,25 @@
   })
 }
 
-onMounted(() => {
+const refreshCenterTopData = () => {
   getNum()
   getLedgerNum()
   todoInfoS()
+}
+
+const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
+if (dataDashboardRefreshTick) {
+  watch(dataDashboardRefreshTick, () => {
+    refreshCenterTopData()
+  })
+}
+
+onMounted(() => {
+  refreshCenterTopData()
 })
 
 onBeforeUnmount(() => {
-  // 娓呯悊寰呭姙浜嬮」鍒楄〃鐨勫姩鐢诲拰瀹氭椂鍣�
-  const todoListEl = refTodoList.value
-  if (todoListEl) {
-    if (todoListEl._animationFrame) {
-      cancelAnimationFrame(todoListEl._animationFrame)
-      todoListEl._animationFrame = null
-    }
-    if (todoListEl._pauseTimer) {
-      clearInterval(todoListEl._pauseTimer)
-      todoListEl._pauseTimer = null
-    }
-  }
+  destroyTodoListScroll()
 })
 </script>
 
diff --git a/src/views/reportAnalysis/dataDashboard/components/basic/left-bottom.vue b/src/views/reportAnalysis/dataDashboard/components/basic/left-bottom.vue
index 58c83d8..bab6024 100644
--- a/src/views/reportAnalysis/dataDashboard/components/basic/left-bottom.vue
+++ b/src/views/reportAnalysis/dataDashboard/components/basic/left-bottom.vue
@@ -40,7 +40,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted } from 'vue'
+import { ref, onMounted, inject, watch } from 'vue'
 import Echarts from '@/components/Echarts/echarts.vue'
 import PanelHeader from '../PanelHeader.vue'
 import DateTypeSwitch from '../DateTypeSwitch.vue'
@@ -192,6 +192,13 @@
   getCustomerRevenueAnalysis()
 }
 
+const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
+if (dataDashboardRefreshTick) {
+  watch(dataDashboardRefreshTick, () => {
+    getCustomerRevenueAnalysis()
+  })
+}
+
 onMounted(() => {
   fetchCustomerOptions()
 })
diff --git a/src/views/reportAnalysis/dataDashboard/components/basic/left-top.vue b/src/views/reportAnalysis/dataDashboard/components/basic/left-top.vue
index 5b7e29e..16791de 100644
--- a/src/views/reportAnalysis/dataDashboard/components/basic/left-top.vue
+++ b/src/views/reportAnalysis/dataDashboard/components/basic/left-top.vue
@@ -21,7 +21,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted, onBeforeUnmount } from 'vue'
+import { ref, onMounted, onBeforeUnmount, inject, watch } from 'vue'
 import Echarts from '@/components/Echarts/echarts.vue'
 import PanelHeader from '../PanelHeader.vue'
 import { productCategoryDistribution } from '@/api/viewIndex.js'
@@ -207,6 +207,13 @@
 }
 
 
+const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
+if (dataDashboardRefreshTick) {
+  watch(dataDashboardRefreshTick, () => {
+    loadData()
+  })
+}
+
 onMounted(() => {
   loadData()
   initBackground()
diff --git a/src/views/reportAnalysis/dataDashboard/components/basic/right-bottom.vue b/src/views/reportAnalysis/dataDashboard/components/basic/right-bottom.vue
index bbcd5f0..6fcd80f 100644
--- a/src/views/reportAnalysis/dataDashboard/components/basic/right-bottom.vue
+++ b/src/views/reportAnalysis/dataDashboard/components/basic/right-bottom.vue
@@ -22,7 +22,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted, computed } from 'vue'
+import { ref, onMounted, computed, inject, watch } from 'vue'
 import Echarts from '@/components/Echarts/echarts.vue'
 import PanelHeader from '../PanelHeader.vue'
 import DateTypeSwitch from '../DateTypeSwitch.vue'
@@ -308,6 +308,13 @@
   fetchCustomerRanking()
 }
 
+const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
+if (dataDashboardRefreshTick) {
+  watch(dataDashboardRefreshTick, () => {
+    fetchCustomerRanking()
+  })
+}
+
 onMounted(() => {
   fetchCustomerRanking()
 })
diff --git a/src/views/reportAnalysis/dataDashboard/components/basic/right-top.vue b/src/views/reportAnalysis/dataDashboard/components/basic/right-top.vue
index 21696fa..96e4548 100644
--- a/src/views/reportAnalysis/dataDashboard/components/basic/right-top.vue
+++ b/src/views/reportAnalysis/dataDashboard/components/basic/right-top.vue
@@ -21,7 +21,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted, computed } from 'vue'
+import { ref, onMounted, computed, inject, watch } from 'vue'
 import Echarts from '@/components/Echarts/echarts.vue'
 import PanelHeader from '../PanelHeader.vue'
 import DateTypeSwitch from '../DateTypeSwitch.vue'
@@ -331,6 +331,13 @@
   fetchSupplierRanking()
 }
 
+const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
+if (dataDashboardRefreshTick) {
+  watch(dataDashboardRefreshTick, () => {
+    fetchSupplierRanking()
+  })
+}
+
 onMounted(() => {
   fetchSupplierRanking()
 })
diff --git a/src/views/reportAnalysis/dataDashboard/index.vue b/src/views/reportAnalysis/dataDashboard/index.vue
index 67a700f..ff53a7b 100644
--- a/src/views/reportAnalysis/dataDashboard/index.vue
+++ b/src/views/reportAnalysis/dataDashboard/index.vue
@@ -44,7 +44,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue'
+import { ref, onMounted, onBeforeUnmount, nextTick, provide } from 'vue'
 import autofit from 'autofit.js'
 import LeftTop from './components/basic/left-top.vue'
 import LeftBottom from './components/basic/left-bottom.vue'
@@ -65,6 +65,12 @@
 
 // 鐢ㄦ埛store
 const userStore = useUserStore()
+
+// 澶у睆鎺ュ彛杞闂撮殧
+const DASHBOARD_REFRESH_MS = 60 * 1000
+const dataDashboardRefreshTick = ref(0)
+provide('dataDashboardRefreshTick', dataDashboardRefreshTick)
+let dashboardPollTimer = null
 
 // 璁$畻缂╂斁姣斾緥
 const calculateScale = () => {
@@ -140,9 +146,17 @@
   window.addEventListener('fullscreenchange', handleFullscreenChange)
   window.addEventListener('webkitfullscreenchange', handleFullscreenChange)
   window.addEventListener('MSFullscreenChange', handleFullscreenChange)
+
+  dashboardPollTimer = setInterval(() => {
+    dataDashboardRefreshTick.value++
+  }, DASHBOARD_REFRESH_MS)
 })
 
 onBeforeUnmount(() => {
+  if (dashboardPollTimer) {
+    clearInterval(dashboardPollTimer)
+    dashboardPollTimer = null
+  }
   window.removeEventListener('resize', handleResize)
   window.removeEventListener('fullscreenchange', handleFullscreenChange)
   window.removeEventListener('webkitfullscreenchange', handleFullscreenChange)
diff --git a/src/views/reportAnalysis/productionAnalysis/components/center-bottom.vue b/src/views/reportAnalysis/productionAnalysis/components/center-bottom.vue
index 46a870a..f4f4024 100644
--- a/src/views/reportAnalysis/productionAnalysis/components/center-bottom.vue
+++ b/src/views/reportAnalysis/productionAnalysis/components/center-bottom.vue
@@ -51,7 +51,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue'
+import { ref, onMounted, onBeforeUnmount, nextTick, inject, watch } from 'vue'
 import { getProgressStatistics } from '@/api/viewIndex.js'
 import PanelHeader from './PanelHeader.vue'
 import CarouselCards from './CarouselCards.vue'
@@ -132,17 +132,22 @@
   }, 150)
 }
 
-const initProgressTableScroll = () => {
-  const tableContainer = progressTableRef.value
-  if (!tableContainer) return
+const stopProgressTableScroll = () => {
   if (progressTableScrollTimer.value) {
     cancelAnimationFrame(progressTableScrollTimer.value)
     progressTableScrollTimer.value = null
   }
-  if (tableContainer._pauseTimer) {
+  const tableContainer = progressTableRef.value
+  if (tableContainer?._pauseTimer) {
     clearInterval(tableContainer._pauseTimer)
     tableContainer._pauseTimer = null
   }
+}
+
+const initProgressTableScroll = () => {
+  const tableContainer = progressTableRef.value
+  if (!tableContainer) return
+  stopProgressTableScroll()
   const tbody = tableContainer.querySelector('tbody')
   if (!tbody) return
   const originalCount = progressTableData.value.length
@@ -198,6 +203,7 @@
 const progressStatisticsInfo = () => {
   getProgressStatistics()
     .then((res) => {
+      stopProgressTableScroll()
       if (!res || !res.data) return
       const obj = {
         totalOrderCount: res.data.totalOrderCount || 0,
@@ -224,14 +230,19 @@
     })
 }
 
+const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
+if (dataDashboardRefreshTick) {
+  watch(dataDashboardRefreshTick, () => {
+    progressStatisticsInfo()
+  })
+}
+
 onMounted(() => {
   progressStatisticsInfo()
 })
 
 onBeforeUnmount(() => {
-  if (progressTableScrollTimer.value) {
-    cancelAnimationFrame(progressTableScrollTimer.value)
-  }
+  stopProgressTableScroll()
   if (tableScrollTimeout.value) clearTimeout(tableScrollTimeout.value)
   const tableContainer = progressTableRef.value
   if (tableContainer?._pauseTimer) {
diff --git a/src/views/reportAnalysis/productionAnalysis/components/center-center.vue b/src/views/reportAnalysis/productionAnalysis/components/center-center.vue
index 96bcada..a65f4f8 100644
--- a/src/views/reportAnalysis/productionAnalysis/components/center-center.vue
+++ b/src/views/reportAnalysis/productionAnalysis/components/center-center.vue
@@ -27,7 +27,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted } from 'vue'
+import { ref, onMounted, inject, watch } from 'vue'
 import * as echarts from 'echarts'
 import Echarts from '@/components/Echarts/echarts.vue'
 import { inputOutputAnalysis } from '@/api/viewIndex.js'
@@ -146,6 +146,13 @@
     })
 }
 
+const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
+if (dataDashboardRefreshTick) {
+  watch(dataDashboardRefreshTick, () => {
+    fetchData()
+  })
+}
+
 onMounted(() => {
   fetchData()
 })
diff --git a/src/views/reportAnalysis/productionAnalysis/components/center-top.vue b/src/views/reportAnalysis/productionAnalysis/components/center-top.vue
index 7201828..a806150 100644
--- a/src/views/reportAnalysis/productionAnalysis/components/center-top.vue
+++ b/src/views/reportAnalysis/productionAnalysis/components/center-top.vue
@@ -24,7 +24,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted } from 'vue'
+import { ref, onMounted, inject, watch } from 'vue'
 import { orderCount } from '@/api/viewIndex.js'
 
 const statItems = ref([])
@@ -52,6 +52,13 @@
     })
 }
 
+const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
+if (dataDashboardRefreshTick) {
+  watch(dataDashboardRefreshTick, () => {
+    fetchData()
+  })
+}
+
 onMounted(() => {
   fetchData()
 })
diff --git a/src/views/reportAnalysis/productionAnalysis/components/left-bottom.vue b/src/views/reportAnalysis/productionAnalysis/components/left-bottom.vue
index 9f6a8c1..b7c7358 100644
--- a/src/views/reportAnalysis/productionAnalysis/components/left-bottom.vue
+++ b/src/views/reportAnalysis/productionAnalysis/components/left-bottom.vue
@@ -22,7 +22,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted } from 'vue'
+import { ref, onMounted, inject, watch } from 'vue'
 import Echarts from '@/components/Echarts/echarts.vue'
 import PanelHeader from './PanelHeader.vue'
 import CarouselCards from './CarouselCards.vue'
@@ -143,6 +143,13 @@
     })
 }
 
+const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
+if (dataDashboardRefreshTick) {
+  watch(dataDashboardRefreshTick, () => {
+    workInProcessTurnoverInfo()
+  })
+}
+
 onMounted(() => {
   workInProcessTurnoverInfo()
 })
diff --git a/src/views/reportAnalysis/productionAnalysis/components/left-top.vue b/src/views/reportAnalysis/productionAnalysis/components/left-top.vue
index fd52b1b..37c82f0 100644
--- a/src/views/reportAnalysis/productionAnalysis/components/left-top.vue
+++ b/src/views/reportAnalysis/productionAnalysis/components/left-top.vue
@@ -23,7 +23,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted, onBeforeUnmount, computed } from 'vue'
+import { ref, onMounted, onBeforeUnmount, computed, inject, watch } from 'vue'
 import { processOutputAnalysis } from '@/api/viewIndex.js'
 import PanelHeader from './PanelHeader.vue'
 import Echarts from '@/components/Echarts/echarts.vue'
@@ -170,6 +170,13 @@
   fetchData()
 }
 
+const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
+if (dataDashboardRefreshTick) {
+  watch(dataDashboardRefreshTick, () => {
+    fetchData()
+  })
+}
+
 onMounted(() => {
   fetchData()
   initBackground()
diff --git a/src/views/reportAnalysis/productionAnalysis/components/right-bottom.vue b/src/views/reportAnalysis/productionAnalysis/components/right-bottom.vue
index 28de03b..62356e7 100644
--- a/src/views/reportAnalysis/productionAnalysis/components/right-bottom.vue
+++ b/src/views/reportAnalysis/productionAnalysis/components/right-bottom.vue
@@ -22,7 +22,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted } from 'vue'
+import { ref, onMounted, inject, watch } from 'vue'
 import { productionAccountingAnalysis } from '@/api/viewIndex.js'
 import PanelHeader from './PanelHeader.vue'
 import DateTypeSwitch from './DateTypeSwitch.vue'
@@ -157,6 +157,13 @@
     })
 }
 
+const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
+if (dataDashboardRefreshTick) {
+  watch(dataDashboardRefreshTick, () => {
+    fetchData()
+  })
+}
+
 onMounted(() => {
   fetchData()
 })
diff --git a/src/views/reportAnalysis/productionAnalysis/components/right-top.vue b/src/views/reportAnalysis/productionAnalysis/components/right-top.vue
index d3a9eb9..5ec836f 100644
--- a/src/views/reportAnalysis/productionAnalysis/components/right-top.vue
+++ b/src/views/reportAnalysis/productionAnalysis/components/right-top.vue
@@ -22,7 +22,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted } from 'vue'
+import { ref, onMounted, inject, watch } from 'vue'
 import { workOrderEfficiencyAnalysis } from '@/api/viewIndex.js'
 import PanelHeader from './PanelHeader.vue'
 import Echarts from '@/components/Echarts/echarts.vue'
@@ -152,6 +152,13 @@
     })
 }
 
+const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
+if (dataDashboardRefreshTick) {
+  watch(dataDashboardRefreshTick, () => {
+    fetchData()
+  })
+}
+
 onMounted(() => {
   fetchData()
 })
diff --git a/src/views/reportAnalysis/productionAnalysis/index.vue b/src/views/reportAnalysis/productionAnalysis/index.vue
index e179150..7e03bbd 100644
--- a/src/views/reportAnalysis/productionAnalysis/index.vue
+++ b/src/views/reportAnalysis/productionAnalysis/index.vue
@@ -44,7 +44,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue'
+import { ref, onMounted, onBeforeUnmount, nextTick, provide } from 'vue'
 import autofit from 'autofit.js'
 import LeftBottom from './components/left-bottom.vue'
 import CenterCenter from './components/center-center.vue'
@@ -66,6 +66,12 @@
 
 // 鐢ㄦ埛store
 const userStore = useUserStore()
+
+/** 涓庡叾瀹冮┚椹惰埍鍏辩敤娉ㄥ叆鍚嶏紝瀛愮粍浠舵瘡鍒嗛挓鍒锋柊鎺ュ彛鏁版嵁 */
+const DASHBOARD_REFRESH_MS = 60 * 1000
+const dataDashboardRefreshTick = ref(0)
+provide('dataDashboardRefreshTick', dataDashboardRefreshTick)
+let dashboardPollTimer = null
 
 // 璁$畻缂╂斁姣斾緥
 const calculateScale = () => {
@@ -141,9 +147,17 @@
   window.addEventListener('fullscreenchange', handleFullscreenChange)
   window.addEventListener('webkitfullscreenchange', handleFullscreenChange)
   window.addEventListener('MSFullscreenChange', handleFullscreenChange)
+
+  dashboardPollTimer = setInterval(() => {
+    dataDashboardRefreshTick.value++
+  }, DASHBOARD_REFRESH_MS)
 })
 
 onBeforeUnmount(() => {
+  if (dashboardPollTimer) {
+    clearInterval(dashboardPollTimer)
+    dashboardPollTimer = null
+  }
   window.removeEventListener('resize', handleResize)
   window.removeEventListener('fullscreenchange', handleFullscreenChange)
   window.removeEventListener('webkitfullscreenchange', handleFullscreenChange)
diff --git a/src/views/safeProduction/safeWorkApproval/components/infoFormDia.vue b/src/views/safeProduction/safeWorkApproval/components/infoFormDia.vue
index a0146ba..86acdf8 100644
--- a/src/views/safeProduction/safeWorkApproval/components/infoFormDia.vue
+++ b/src/views/safeProduction/safeWorkApproval/components/infoFormDia.vue
@@ -218,7 +218,7 @@
       approveDeptName: "",
       approveReason: "",
       checkResult: "",
-      storageBlobDTOs: [],
+      storageBlobDTOS: [],
       approverList: [], // 鏂板瀛楁锛屽瓨鍌ㄦ墍鏈夎妭鐐圭殑瀹℃壒浜篿d
       startDate: "", // 璇峰亣寮�濮嬫椂闂�
       endDate: "", // 璇峰亣缁撴潫鏃堕棿
@@ -298,7 +298,7 @@
       approveProcessGetInfo({ id: row.approveId, approveReason: "1" }).then(
         res => {
           form.value = { ...res.data };
-          form.value.storageBlobDTOs = res.data.storageBlobVOS;
+          form.value.storageBlobDTOS = res.data.storageBlobVOS;
           // 鍙嶆樉瀹℃壒浜�
           if (res.data && res.data.approveUserIds) {
             const userIds = res.data.approveUserIds.split(",");
@@ -388,7 +388,7 @@
         return;
       }
     }
-    form.value.storageBlobDTOs = fileList.value;
+    form.value.storageBlobDTOS = fileList.value;
     proxy.$refs.formRef.validate(valid => {
       if (valid) {
         if (operationType.value === "add" || currentApproveStatus.value == 3) {
diff --git a/src/views/salesManagement/returnOrder/components/detailDia.vue b/src/views/salesManagement/returnOrder/components/detailDia.vue
index e4a69f3..ecc663f 100644
--- a/src/views/salesManagement/returnOrder/components/detailDia.vue
+++ b/src/views/salesManagement/returnOrder/components/detailDia.vue
@@ -20,7 +20,11 @@
 
       <div style="padding-top: 20px">
         <span class="descriptions">浜у搧鍒楄〃</span>
-        <PIMTable :isShowPagination="false" rowKey="id" :column="tableColumn" :tableData="tableData" />
+        <PIMTable :isShowPagination="false" rowKey="id" :column="tableColumn" :tableData="tableData">
+          <template #totalReturnNum="{ row }">
+            {{ calcAlreadyReturned(row) }}
+          </template>
+        </PIMTable>
       </div>
     </div>
     <template #footer>
@@ -101,6 +105,13 @@
 const firstNonEmptyText = (...vals) => {
   const hit = vals.find((v) => !isEmptyText(v));
   return hit === undefined ? "" : hit;
+};
+
+const calcAlreadyReturned = (row) => {
+  const total = Number(row?.stockOutNum ?? row?.totalQuantity ?? row?.totalReturnNum ?? 0);
+  const un = Number(row?.unQuantity ?? 0);
+  if (!Number.isFinite(total) || !Number.isFinite(un)) return 0;
+  return Math.max(total - un, 0);
 };
 
 /** 璇︽儏琛ㄧ敤 productName / model锛涘悎骞舵椂鍕胯绌轰覆鐩栨帀鍑哄簱琛屽瓧娈� */
@@ -241,7 +252,7 @@
   {align: "center", label: "瑙勬牸鍨嬪彿", prop: "model"},
   {align: "center", label: "鍗曚綅", prop: "unit", width: 80},
   {align: "center", label: "鎬绘暟閲�", prop: "stockOutNum", width: 120},
-  {align: "center", label: "宸查��璐ф暟閲�", prop: "totalReturnNum", width: 120},
+  {align: "center", label: "宸查��璐ф暟閲�", prop: "totalReturnNum", width: 120, dataType: "slot", slot: "totalReturnNum"},
   {align: "center", label: "鏈��璐ф暟閲�", prop: "unQuantity", width: 120},
   {align: "center", label: "閫�璐ф暟閲�", prop: "returnQuantity", width: 120},
   {align: "center", label: "閫�璐т骇鍝佸崟浠�", prop: "price", width: 120},
diff --git a/src/views/salesManagement/returnOrder/components/formDia.vue b/src/views/salesManagement/returnOrder/components/formDia.vue
index fe0a75c..6a6d756 100644
--- a/src/views/salesManagement/returnOrder/components/formDia.vue
+++ b/src/views/salesManagement/returnOrder/components/formDia.vue
@@ -82,6 +82,9 @@
             <el-button type="primary" @click="openProductSelection" :disabled="!form.shippingId">娣诲姞浜у搧</el-button>
           </div>
           <PIMTable :isShowPagination="false" rowKey="id" :column="tableColumn" :tableData="tableData">
+            <template #totalReturnNum="{ row }">
+              {{ calcAlreadyReturned(row) }}
+            </template>
             <template #returnQuantity="{ row }">
               <el-input 
                 v-model="row.returnQuantity" 
@@ -223,7 +226,7 @@
   {align: "center", label: "瑙勬牸鍨嬪彿", prop: "specificationModel" },
   {align: "center", label: "鍗曚綅", prop: "unit", width: 80 },
   {align: "center", label: "鎬绘暟閲�", prop: "stockOutNum", width: 120 },
-  {align: "center", label: "宸查��璐ф暟閲�", prop: "totalReturnNum", width: 120 },
+  {align: "center", label: "宸查��璐ф暟閲�", prop: "totalReturnNum", width: 120, dataType: "slot", slot: "totalReturnNum" },
   {align: "center", label: "鏈��璐ф暟閲�", prop: "unQuantity", width: 120 },
   {align: "center", label: "閫�璐ф暟閲�", prop: "returnQuantity", dataType: "slot", slot: "returnQuantity", width: 120 },
   {align: "center", label: "閫�璐т骇鍝佸崟浠�", prop: "price", dataType: "slot", slot: "price", width: 120 },
diff --git a/src/views/salesManagement/salesLedger/index.vue b/src/views/salesManagement/salesLedger/index.vue
index 4e2d84e..a4ebbdf 100644
--- a/src/views/salesManagement/salesLedger/index.vue
+++ b/src/views/salesManagement/salesLedger/index.vue
@@ -1578,7 +1578,7 @@
     selectedQuotation.value = null;
     let userLists = await userListNoPage();
     userList.value = userLists.data;
-    listCustomer({ current: -1, size: -1 }).then(res => {
+    listCustomer({ current: -1, size: -1, type: 0 }).then(res => {
       customerOption.value = res.data.records;
     });
     form.value.entryPerson = userStore.id;
@@ -1705,6 +1705,8 @@
         taxExclusiveTotalPrice: taxExclusiveTotalPrice,
         invoiceType: "澧炴櫘绁�",
         isProduction: true,
+        productId: p.productId,
+        productModelId: p.productModelId
       };
     });
 
@@ -2594,6 +2596,7 @@
       瀹℃牳鎷掔粷: "瀹℃牳鎷掔粷",
       瀹℃牳閫氳繃: "瀹℃牳閫氳繃",
       宸插彂璐�: "宸插彂璐�",
+      閮ㄥ垎鍙戣揣: "閮ㄥ垎鍙戣揣",
     };
     return statusTextMap[statusStr] || "寰呭彂璐�";
   };
@@ -2625,6 +2628,7 @@
       瀹℃牳鎷掔粷: "danger",
       瀹℃牳閫氳繃: "success",
       宸插彂璐�: "success",
+      閮ㄥ垎鍙戣揣: "warning",
     };
     return typeTextMap[statusStr] || "info";
   };
@@ -2650,7 +2654,7 @@
 
     // 鍙戣揣鐘舵�佸繀椤绘槸"寰呭彂璐�"鎴�"瀹℃牳鎷掔粷"
     const statusStr = shippingStatus ? String(shippingStatus).trim() : "";
-    return statusStr === "寰呭彂璐�" || statusStr === "瀹℃牳鎷掔粷";
+    return statusStr === "寰呭彂璐�" || statusStr === "瀹℃牳鎷掔粷" || statusStr === "閮ㄥ垎鍙戣揣";
   };
 
   // 鎵撳紑闄勪欢寮圭獥
diff --git a/src/views/salesManagement/salesQuotation/index.vue b/src/views/salesManagement/salesQuotation/index.vue
index 2237b72..fce764f 100644
--- a/src/views/salesManagement/salesQuotation/index.vue
+++ b/src/views/salesManagement/salesQuotation/index.vue
@@ -187,9 +187,9 @@
             </el-table-column>
             <el-table-column prop="specification" label="瑙勬牸鍨嬪彿" width="200">
               <template #default="scope">
-                <el-form-item :prop="`products.${scope.$index}.specificationId`" class="product-table-form-item">
+                <el-form-item :prop="`products.${scope.$index}.productModelId`" class="product-table-form-item">
                   <el-select
-                    v-model="scope.row.specificationId"
+                    v-model="scope.row.productModelId"
                     placeholder="璇烽�夋嫨"
                     clearable
                     @change="getProductModel($event, scope.row)"
@@ -239,10 +239,10 @@
           </template>
           <div class="form-content">
             <el-form-item label="澶囨敞" prop="remark">
-              <el-input 
-                type="textarea" 
-                v-model="form.remark" 
-                placeholder="璇疯緭鍏ュ娉ㄤ俊鎭紙閫夊~锛�" 
+              <el-input
+                type="textarea"
+                v-model="form.remark"
+                placeholder="璇疯緭鍏ュ娉ㄤ俊鎭紙閫夊~锛�"
                 :rows="4"
                 maxlength="500"
                 show-word-limit
@@ -270,7 +270,7 @@
           <span style="font-size: 18px; color: #e6a23c; font-weight: bold;">楼{{ currentQuotation.totalAmount?.toFixed(2) }}</span>
         </el-descriptions-item>
       </el-descriptions>
-      
+
       <div style="margin: 20px 0;">
         <h4>浜у搧鏄庣粏</h4>
         <el-table :data="currentQuotation.products" border style="width: 100%">
@@ -354,7 +354,7 @@
 
 const productRowRules = {
   productId: [{ required: true, message: '璇烽�夋嫨浜у搧鍚嶇О', trigger: 'change' }],
-  specificationId: [{ required: true, message: '璇烽�夋嫨瑙勬牸鍨嬪彿', trigger: 'change' }],
+  productModelId: [{ required: true, message: '璇烽�夋嫨瑙勬牸鍨嬪彿', trigger: 'change' }],
   unit: [{ required: true, message: '璇峰~鍐欏崟浣�', trigger: 'blur' }],
   unitPrice: [{ required: true, message: '璇峰~鍐欏崟浠�', trigger: 'change' }]
 }
@@ -362,7 +362,7 @@
   const r = { ...baseRules }
   ;(form.products || []).forEach((_, i) => {
     r[`products.${i}.productId`] = productRowRules.productId
-    r[`products.${i}.specificationId`] = productRowRules.specificationId
+    r[`products.${i}.productModelId`] = productRowRules.productModelId
     r[`products.${i}.unit`] = productRowRules.unit
     r[`products.${i}.unitPrice`] = productRowRules.unitPrice
   })
@@ -433,7 +433,7 @@
 		if (children && children.length > 0) {
 			newItem.children = convertIdToValue(children);
 		}
-		
+
 		return newItem;
 	});
 }
@@ -457,7 +457,7 @@
 		row.productId = '';
 		row.product = '';
 		row.modelOptions = [];
-		row.specificationId = '';
+		row.productModelId = '';
 		row.specification = '';
 		row.unit = '';
 		return;
@@ -478,13 +478,13 @@
 	if (!row) return;
 	// 濡傛灉娓呯┖閫夋嫨锛屽垯娓呯┖鐩稿叧瀛楁
 	if (!value) {
-		row.specificationId = '';
+		row.productModelId = '';
 		row.specification = '';
 		row.unit = '';
 		return;
 	}
-	// 鏇存柊 specificationId锛坴-model 宸茬粡鑷姩鏇存柊锛岃繖閲岀‘淇濅竴鑷存�э級
-	row.specificationId = value;
+	// 鏇存柊 productModelId锛坴-model 宸茬粡鑷姩鏇存柊锛岃繖閲岀‘淇濅竴鑷存�э級
+	row.productModelId = value;
 	const modelOptions = row.modelOptions || [];
 	const index = modelOptions.findIndex((item) => item.id === value);
 	if (index !== -1) {
@@ -523,7 +523,7 @@
     products: row.products ? row.products.map(product => ({
       productId: product.productId || '',
       product: product.product || product.productName || '',
-      specificationId: product.specificationId || '',
+      productModelId: product.productModelId || '',
       specification: product.specification || '',
       quantity: product.quantity || 0,
       unit: product.unit || '',
@@ -560,32 +560,32 @@
     const resolvedProductId = product.productId
       ? Number(product.productId)
       : findNodeIdByLabel(productOptions.value, productName) || ''
-    
+
     // 濡傛灉鏈変骇鍝両D锛屽姞杞藉搴旂殑瑙勬牸鍨嬪彿鍒楄〃
     let modelOptions = [];
-    let resolvedSpecificationId = product.specificationId || '';
-    
+    let resolvedProductModelId = product.productModelId || '';
+
     if (resolvedProductId) {
       try {
         const res = await modelList({ id: resolvedProductId });
         modelOptions = res || [];
-        
-        // 濡傛灉杩斿洖鐨勬暟鎹病鏈� specificationId锛屼絾鏈� specification 鍚嶇О锛屾牴鎹悕绉版煡鎵� ID
-        if (!resolvedSpecificationId && product.specification) {
+
+        // 濡傛灉杩斿洖鐨勬暟鎹病鏈� productModelId锛屼絾鏈� specification 鍚嶇О锛屾牴鎹悕绉版煡鎵� ID
+        if (!resolvedProductModelId && product.specification) {
           const foundModel = modelOptions.find(item => item.model === product.specification);
           if (foundModel) {
-            resolvedSpecificationId = foundModel.id;
+            resolvedProductModelId = foundModel.id;
           }
         }
       } catch (error) {
         console.error('鍔犺浇瑙勬牸鍨嬪彿澶辫触:', error);
       }
     }
-    
+
     return {
       productId: resolvedProductId,
       product: productName,
-      specificationId: resolvedSpecificationId,
+      productModelId: resolvedProductModelId,
       specification: product.specification || '',
       quantity: product.quantity || 0,
       unit: product.unit || '',
@@ -649,8 +649,7 @@
     productId: '',
     product: '',
     productName: '',
-    specificationId: '',
-    specification: '',
+    productModelId: '',
     quantity: 1,
     unit: '',
     unitPrice: 0,
@@ -755,7 +754,7 @@
         products: item.products ? item.products.map(product => ({
           productId: product.productId || '',
           product: product.product || product.productName || '',
-          specificationId: product.specificationId || '',
+          productModelId: product.productModelId || '',
           specification: product.specification || '',
           quantity: product.quantity || 0,
           unit: product.unit || '',
@@ -803,16 +802,16 @@
   padding: 10px 0;
   max-height: calc(100vh - 200px);
   overflow-y: auto;
-  
+
   &::-webkit-scrollbar {
     width: 6px;
     height: 6px;
   }
-  
+
   &::-webkit-scrollbar-thumb {
     background: #c1c1c1;
     border-radius: 3px;
-    
+
     &:hover {
       background: #a8a8a8;
     }
@@ -829,17 +828,17 @@
   margin-bottom: 24px;
   border-radius: 8px;
   transition: all 0.3s ease;
-  
+
   &:hover {
     box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08) !important;
   }
-  
+
   :deep(.el-card__header) {
     padding: 16px 20px;
     background: linear-gradient(135deg, #f5f7fa 0%, #ffffff 100%);
     border-bottom: 1px solid #ebeef5;
   }
-  
+
   :deep(.el-card__body) {
     padding: 20px;
   }
@@ -849,19 +848,19 @@
   display: flex;
   align-items: center;
   gap: 8px;
-  
+
   .card-icon {
     font-size: 18px;
     color: #409eff;
   }
-  
+
   .card-title {
     font-weight: 600;
     font-size: 16px;
     color: #303133;
     flex: 1;
   }
-  
+
   .header-btn {
     margin-left: auto;
   }
@@ -885,20 +884,20 @@
 .product-table {
   :deep(.el-table__header) {
     background-color: #f5f7fa;
-    
+
     th {
       background-color: #f5f7fa !important;
       color: #606266;
       font-weight: 600;
     }
   }
-  
+
   :deep(.el-table__row) {
     &:hover {
       background-color: #f5f7fa;
     }
   }
-  
+
   :deep(.el-table__cell) {
     padding: 12px 0;
   }

--
Gitblit v1.9.3