From e5ed471a20179fef875aed7341a5ae6d5b79a8c7 Mon Sep 17 00:00:00 2001
From: yuan <123@>
Date: 星期一, 18 五月 2026 16:44:37 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/dev_NEW_pro' into dev_鹤壁_强信宇_pro

---
 multiple/assets/favicon/JXJHfavicon.ico                                            |    0 
 src/views/productionManagement/productionProcess/index.vue                         |   27 
 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                              |    4 
 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 +
 src/views/productionManagement/workOrderManagement/index.vue                       |    5 
 multiple/assets/logo/ZQSYLogo.png                                                  |    0 
 src/views/reportAnalysis/productionAnalysis/components/right-top.vue               |    9 
 src/views/productionManagement/productionOrder/components/MaterialLedgerDialog.vue |   28 
 src/views/reportAnalysis/productionAnalysis/components/left-bottom.vue             |    9 
 src/views/productionManagement/productionTraceability/index.vue                    |    1 
 multiple/assets/logo/JHYLogo.png                                                   |    0 
 multiple/assets/logo/HYLQLogo.png                                                  |    0 
 src/views/financialManagement/voucher/generalLedger.vue                            |   18 
 src/views/equipmentManagement/upkeep/index.vue                                     |   29 
 src/views/qualityManagement/processInspection/components/formDia.vue               |  120 +
 multiple/multiple-build.js                                                         |  192 +
 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                               |    2 
 src/views/reportAnalysis/productionAnalysis/components/center-top.vue              |    9 
 src/views/procurementManagement/procurementLedger/index.vue                        |    1 
 src/views/qualityManagement/nonconformingManagement/components/formDia.vue         |   22 
 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/qualityManagement/nonconformingManagement/index.vue                      |    2 
 src/views/equipmentManagement/upkeep/Form/MaintenanceModal.vue                     |  357 ++--
 src/views/reportAnalysis/dataDashboard/components/basic/left-top.vue               |    9 
 src/views/safeProduction/safeWorkApproval/components/infoFormDia.vue               |    6 
 multiple/assets/logo/XCDQLogo.png                                                  |    0 
 multiple/assets/logo/XSWHLogo.png                                                  |    0 
 multiple/config.json                                                               |   87 +
 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/components/AIChatSidebar/assistants/index.js                                   |   13 
 src/views/collaborativeApproval/approvalProcess/index.vue                          |   23 
 src/views/financialManagement/voucher/index.vue                                    |  107 +
 src/views/salesManagement/salesLedger/index.vue                                    |    6 
 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/logo/JXJHLogo.png                                                  |    0 
 multiple/assets/favicon/XCDQfavicon.ico                                            |    0 
 src/layout/components/Sidebar/index.vue                                            |   15 
 src/views/financialManagement/assets/intangibleAssets.vue                          |    2 
 src/views/inventoryManagement/stockManagement/Record.vue                           |  354 +++-
 src/views/financialManagement/voucher/detailLedger.vue                             |    2 
 multiple/assets/favicon/XSWHfavicon.ico                                            |    0 
 multiple/assets/logo/YTJZLogo.png                                                  |    0 
 src/components/AIChatSidebar/assistants/salesAssistant.js                          |   28 
 src/views/reportAnalysis/productionAnalysis/components/right-bottom.vue            |    9 
 src/views/basicData/supplierManage/components/HomeTab.vue                          |   21 
 multiple/assets/favicon/YTJZfavicon.ico                                            |    0 
 src/assets/styles/sidebar.scss                                                     |    9 
 src/views/qualityManagement/finalInspection/components/formDia.vue                 |  180 +
 src/views/equipmentManagement/repair/index.vue                                     |   36 
 src/components/AIChatSidebar/index.vue                                             | 1137 ++++++++++++++
 src/views/collaborativeApproval/approvalProcess/components/infoFormDia.vue         |    5 
 src/views/equipmentManagement/inspectionManagement/index.vue                       |   31 
 src/views/productionManagement/productStructure/Detail/index.vue                   |  118 +
 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 
 96 files changed, 3,649 insertions(+), 804 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/XCDQfavicon.ico b/multiple/assets/favicon/XCDQfavicon.ico
new file mode 100644
index 0000000..69a2280
--- /dev/null
+++ b/multiple/assets/favicon/XCDQfavicon.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/XCDQLogo.png b/multiple/assets/logo/XCDQLogo.png
new file mode 100644
index 0000000..d10580a
--- /dev/null
+++ b/multiple/assets/logo/XCDQLogo.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 51f04d6..82f5c86 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"
@@ -59,15 +59,6 @@
     },
     "logo": "logo/ZXZNLogo.png",
     "favicon": "favicon/ZXZNfavicon.ico"
-  },
-  "QXY": {
-    "env": {
-      "VITE_APP_TITLE": "寮轰俊瀹囩數鍣ㄧ鐞嗙郴缁�",
-      "VITE_BASE_API": "http://36.134.154.10:9001",
-      "VITE_JAVA_API": "http://36.134.154.10:9000"
-  },
-    "logo": "logo/QXYLogo.png",
-    "favicon": "favicon/QXYfavicon.ico"
   },
   "HYZC": {
     "env": {
@@ -105,6 +96,78 @@
     "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"
+  },
+  "XCDQ": {
+    "env": {
+      "VITE_APP_TITLE": "鏃櫒鐢靛櫒绠$悊绯荤粺",
+      "VITE_BASE_API": "http://36.133.45.183:9001",
+      "VITE_JAVA_API": "http://36.133.45.183:9002"
+    },
+    "logo": "logo/XCDQLogo.png",
+    "favicon": "favicon/XCDQfavicon.ico"
+  },
   "logo": "/src/assets/logo/logo.png",
   "favicon": "/public/favicon.ico"
 }
diff --git a/multiple/multiple-build.js b/multiple/multiple-build.js
index d87b333..afcd4d5 100644
--- a/multiple/multiple-build.js
+++ b/multiple/multiple-build.js
@@ -1,98 +1,152 @@
-import fs from 'fs/promises';
-import fsSync from 'fs';
-import path from 'path';
-import { fileURLToPath } from 'url';
+import fs from "fs/promises";
+import fsSync from "fs";
+import path from "path";
+import { fileURLToPath } from "url";
 import { execSync } from "child_process";
 
-// 鑾峰彇 __dirname
 const __filename = fileURLToPath(import.meta.url);
 const __dirname = path.dirname(__filename);
 
-// 璇诲彇 JSON 閰嶇疆
-const data = await fs.readFile(path.join(__dirname, 'config.json'), 'utf-8');
+const data = await fs.readFile(path.join(__dirname, "config.json"), "utf-8");
 const config = JSON.parse(data);
 
-// 椤圭洰璺緞
-const rootPath = path.resolve(__dirname, '..');
-const resourcePath = path.join(rootPath, 'multiple', 'assets');
-const replacePath = path.join(rootPath, 'replace');
+const rootPath = path.resolve(__dirname, "..");
+const resourcePath = path.join(rootPath, "multiple", "assets");
+const replacePath = path.join(rootPath, "replace");
+const envFilePath = path.join(rootPath, ".env.production.local");
 
-// 鑾峰彇鍛戒护琛屽弬鏁�
 const params = parseArgs(process.argv);
-const company = params["company"] ?? "default";
+const company = resolveCompany(params);
 const companyMap = config[company];
 
-const envFilePath = path.join(process.cwd(), '.env.production.local');
+if (!companyMap) {
+  const availableCompanies = Object.entries(config)
+    .filter(([, value]) => value && typeof value === "object" && value.env)
+    .map(([key]) => key)
+    .sort();
+  throw new Error(
+    `鏈煡 company: "${company}"銆傚彲閫夊��: ${availableCompanies.join(", ")}`
+  );
+}
+
+console.log(`褰撳墠 company: ${company}`);
 
 async function copyFileWithOverwrite(src, dest) {
-    await fs.mkdir(path.dirname(dest), { recursive: true });
-    if (fsSync.existsSync(dest)) {
-        try {
-            await fs.chmod(dest, 0o666);
-        } catch {
-            // Ignore chmod failure and try delete directly.
-        }
-        await fs.rm(dest, { force: true });
+  await fs.mkdir(path.dirname(dest), { recursive: true });
+  if (fsSync.existsSync(dest)) {
+    try {
+      await fs.chmod(dest, 0o666);
+    } catch {
+      // Ignore chmod failure and continue.
     }
-    await fs.copyFile(src, dest);
+    await fs.rm(dest, { force: true });
+  }
+  await fs.copyFile(src, dest);
 }
 
 try {
-    // 1锔忊儯 鐢熸垚 .env
-    console.log("=======鐢熸垚.env=======");
-    const envContent = Object.entries(companyMap.env)
-        .map(([key, value]) => `${key}='${value}'`)
-        .join('\n') + '\n';
-    await fs.writeFile(envFilePath, envContent, 'utf-8');
+  console.log("=======鐢熸垚.env=======");
+  const envContent =
+    Object.entries(companyMap.env)
+      .map(([key, value]) => `${key}='${value}'`)
+      .join("\n") + "\n";
+  await fs.writeFile(envFilePath, envContent, "utf-8");
 
-    // 2锔忊儯 澶囦唤鍘熷璧勬簮骞舵浛鎹�
-    console.log("=======淇敼璧勬簮=======");
-    for (const [key, value] of Object.entries(companyMap)) {
-        if (key === 'env') continue;
+  console.log("=======淇敼璧勬簮=======");
+  for (const [key] of Object.entries(companyMap)) {
+    if (key === "env") continue;
 
-        const originFile = path.join(rootPath, config[key]);
-        const backupFile = path.join(replacePath, config[key]);
-        const replaceFile = path.join(resourcePath, companyMap[key]);
+    const originFile = path.join(rootPath, config[key]);
+    const backupFile = path.join(replacePath, config[key]);
+    const replaceFile = path.join(resourcePath, companyMap[key]);
 
-        await copyFileWithOverwrite(originFile, backupFile);
-        await copyFileWithOverwrite(replaceFile, originFile);
-    }
+    await copyFileWithOverwrite(originFile, backupFile);
+    await copyFileWithOverwrite(replaceFile, originFile);
+  }
 
-    console.log("=====寮�濮嬫墦鍖�======");
-    execSync("vite build", { stdio: "inherit" });
-    console.log("=====鎵撳寘瀹屾垚======");
+  console.log("=====寮�濮嬫墦鍖�=====");
+  const buildEnv = createBuildEnv(companyMap.env);
+  execSync("vite build", { stdio: "inherit", cwd: rootPath, env: buildEnv });
+  console.log("=====鎵撳寘瀹屾垚======");
 } finally {
-    console.log("=====鎭㈠璧勬簮======");
+  console.log("=====鎭㈠璧勬簮======");
 
-    // 鍒犻櫎涓存椂 .env 鏂囦欢
-    if (fsSync.existsSync(envFilePath)) {
-        await fs.unlink(envFilePath);
-        console.log(`馃棏锔� 宸插垹闄� ${envFilePath}`);
+  if (fsSync.existsSync(envFilePath)) {
+    await fs.unlink(envFilePath);
+    console.log(`馃棏锔� 宸插垹闄� ${envFilePath}`);
+  }
+
+  if (fsSync.existsSync(replacePath)) {
+    for (const [key] of Object.entries(companyMap)) {
+      if (key === "env") continue;
+
+      const originFile = path.join(rootPath, config[key]);
+      const backupFile = path.join(replacePath, config[key]);
+      await copyFileWithOverwrite(backupFile, originFile);
     }
-
-    // 鎭㈠璧勬簮鏂囦欢
-    if (fsSync.existsSync(replacePath)) {
-        for (const [key, value] of Object.entries(companyMap)) {
-            if (key === 'env') continue;
-
-            const originFile = path.join(rootPath, config[key]);
-            const backupFile = path.join(replacePath, config[key]);
-
-            await copyFileWithOverwrite(backupFile, originFile);
-        }
-        await fs.rm(replacePath, { recursive: true, force: true });
-        console.log(`馃棏锔� 宸插垹闄� ${replacePath}`);
-    }
+    await fs.rm(replacePath, { recursive: true, force: true });
+    console.log(`馃棏锔� 宸插垹闄� ${replacePath}`);
+  }
 }
 
-// 绠�鍗曞懡浠よ鍙傛暟瑙f瀽
 function parseArgs(argv) {
-    const params = {};
-    for (const arg of argv.slice(2)) {
-        if (arg.startsWith('--')) {
-            const [key, value] = arg.slice(2).split('=');
-            params[key] = value ?? true;
-        }
+  const params = {};
+  for (let index = 2; index < argv.length; index++) {
+    const arg = argv[index];
+    if (!arg.startsWith("--")) continue;
+
+    const normalized = arg.slice(2);
+    const equalIndex = normalized.indexOf("=");
+    if (equalIndex >= 0) {
+      const key = normalized.slice(0, equalIndex);
+      const value = normalized.slice(equalIndex + 1);
+      params[key] = value || true;
+      continue;
     }
-    return params;
+
+    const nextArg = argv[index + 1];
+    if (nextArg && !nextArg.startsWith("--")) {
+      params[normalized] = nextArg;
+      index += 1;
+      continue;
+    }
+
+    params[normalized] = true;
+  }
+  return params;
+}
+
+function resolveCompany(parsedParams) {
+  const fromArg = parseValue(parsedParams.company);
+  if (fromArg) return fromArg;
+
+  const fromNpmConfig = parseValue(process.env.npm_config_company);
+  if (fromNpmConfig) return fromNpmConfig;
+
+  const fromEnv = parseValue(process.env.COMPANY ?? process.env.company);
+  if (fromEnv) return fromEnv;
+
+  return "default";
+}
+
+function parseValue(value) {
+  if (value == null || value === true) return undefined;
+  if (typeof value !== "string") return undefined;
+  const trimmed = value.trim();
+  if (!trimmed) return undefined;
+  return trimmed.replace(/^["']|["']$/g, "");
+}
+
+function createBuildEnv(companyEnv) {
+  const env = { ...process.env };
+  for (const key of Object.keys(env)) {
+    if (key.startsWith("VITE_")) {
+      delete env[key];
+    }
+  }
+  return {
+    ...env,
+    ...companyEnv,
+    VITE_APP_ENV: "production",
+  };
 }
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/assets/styles/sidebar.scss b/src/assets/styles/sidebar.scss
index be7b7a7..15d8078 100644
--- a/src/assets/styles/sidebar.scss
+++ b/src/assets/styles/sidebar.scss
@@ -225,14 +225,7 @@
             width: 0;
             overflow: hidden;
             visibility: hidden;
-            display: inline-block;
-          }
-          & > i {
-            height: 0;
-            width: 0;
-            overflow: hidden;
-            visibility: hidden;
-            display: inline-block;
+            display: inline-block;
           }
         }
       }
diff --git a/src/components/AIChatSidebar/assistants/index.js b/src/components/AIChatSidebar/assistants/index.js
index 61d4752..d7081b4 100644
--- a/src/components/AIChatSidebar/assistants/index.js
+++ b/src/components/AIChatSidebar/assistants/index.js
@@ -1,6 +1,15 @@
 import { generalAssistant } from './generalAssistant'
 import { purchaseAssistant } from './purchaseAssistant'
+import { productionAssistant } from './productionAssistant'
+import { salesAssistant } from './salesAssistant'
 
-export { generalAssistant, purchaseAssistant }
+export { generalAssistant, purchaseAssistant, productionAssistant, salesAssistant }
 
-export const builtInAssistants = [generalAssistant, purchaseAssistant]
+export const assistantRegistry = {
+  general: generalAssistant,
+  sales: salesAssistant,
+  purchase: purchaseAssistant,
+  production: productionAssistant
+}
+
+export const builtInAssistants = [generalAssistant, salesAssistant, 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/assistants/salesAssistant.js b/src/components/AIChatSidebar/assistants/salesAssistant.js
new file mode 100644
index 0000000..03cb102
--- /dev/null
+++ b/src/components/AIChatSidebar/assistants/salesAssistant.js
@@ -0,0 +1,28 @@
+import { TrendCharts } from '@element-plus/icons-vue'
+
+export const salesAssistant = {
+  key: 'sales',
+  label: '閿�鍞姪鎵�',
+  title: '閿�鍞櫤鑳藉姪鎵�',
+  tooltip: '閿�鍞櫤鑳藉姪鎵�',
+  icon: TrendCharts,
+  apiBase: '/sales-ai',
+  storageKey: 'sales_ai_chat_uuid',
+  placeholder: '璇疯緭鍏ラ攢鍞浉鍏抽棶棰�... (Enter 鍙戦�� / Shift+Enter 鎹㈣)',
+  welcomeMessage: '浣犲ソ',
+  description: '鎴戝彲浠ュ崗鍔╀綘鏌ヨ瀹㈡埛妗f銆侀攢鍞姤浠枫�侀攢鍞彴璐︺�侀攢鍞��璐с�佸鎴峰線鏉ャ�佸彂璐у彴璐︼紝骞堕噸鐐瑰垎鏋愬鎴锋祦澶遍闄╁強鍥炴/鎶ヤ环绛栫暐銆�',
+  allowFileUpload: false,
+  emptySessionText: '鏆傛棤閿�鍞細璇�',
+  quickPrompts: [
+    '鏌ヨ绉佹捣瀹㈡埛妗f鍓�10鏉�',
+    '鏌ヨ鍏捣瀹㈡埛妗f',
+    '鏌ヨ鏈湀閿�鍞姤浠�',
+    '鏌ヨ鏈湀閿�鍞彴璐�',
+    '鏌ヨ杩�30澶╅攢鍞��璐�',
+    '鏌ヨ杩�30澶╁鎴峰洖娆惧線鏉�',
+    '鏌ヨ鏈湀鍙戣揣鍙拌处',
+    '鏌ョ湅閿�鍞寚鏍囩粺璁�',
+    '甯垜鍋氬鎴锋祦澶遍闄╁垎鏋愶紝杩�30澶╋紝鍓�20鏉�',
+    '鐢熸垚鍥炴涓庢姤浠风瓥鐣ュ缓璁紝浼樺厛楂橀闄╁鎴�'
+  ]
+}
diff --git a/src/components/AIChatSidebar/index.vue b/src/components/AIChatSidebar/index.vue
index a2a365a..3d234d6 100644
--- a/src/components/AIChatSidebar/index.vue
+++ b/src/components/AIChatSidebar/index.vue
@@ -242,7 +242,253 @@
                   </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.salesData" class="sales-structured-card">
+                  <div class="sales-structured-card__title">{{ getSalesTypeLabel(message.type) }}</div>
+
+                  <div v-if="message.salesData.summaryEntries?.length" class="sales-summary-grid">
+                    <div
+                        v-for="(entry, entryIndex) in message.salesData.summaryEntries"
+                        :key="`sales-summary-${entry.key}-${entryIndex}`"
+                        class="sales-summary-item"
+                    >
+                      <span class="sales-summary-label">{{ entry.label }}</span>
+                      <strong class="sales-summary-value">{{ entry.value }}</strong>
+                    </div>
+                  </div>
+
+                  <div v-if="message.type === 'sales_customer_churn_risk' && message.salesData.listItems?.length" class="sales-focus-list">
+                    <div
+                        v-for="(item, itemIndex) in message.salesData.listItems"
+                        :key="`risk-${item.customerName || itemIndex}`"
+                        class="sales-focus-item"
+                    >
+                      <div class="sales-focus-item__head">
+                        <strong>{{ formatStructuredValue(item.customerName) }}</strong>
+                        <div class="sales-focus-tags">
+                          <el-tag size="small" :type="getSalesLevelTagType(item.riskLevel)">
+                            {{ getSalesLevelLabel(item.riskLevel, 'risk') }}
+                          </el-tag>
+                          <el-tag size="small" type="warning">椋庨櫓鍒� {{ formatStructuredValue(item.riskScore) }}</el-tag>
+                        </div>
+                      </div>
+                      <div class="sales-focus-metrics">
+                        <span>寰呭洖娆撅細{{ formatStructuredValue(item.pendingAmount) }}</span>
+                        <span>寰呭洖娆惧崰姣旓細{{ formatStructuredValue(item.pendingRate) }}</span>
+                        <span>璺濅笂娆′笅鍗曪細{{ formatStructuredValue(item.daysSinceLastOrder) }}</span>
+                      </div>
+                      <div v-if="toStructuredStringArray(item.riskReasons).length" class="sales-focus-reasons">
+                        <el-tag
+                            v-for="(reason, reasonIndex) in toStructuredStringArray(item.riskReasons)"
+                            :key="`${item.customerName || itemIndex}-reason-${reasonIndex}`"
+                            size="small"
+                            type="danger"
+                            effect="plain"
+                        >
+                          {{ reason }}
+                        </el-tag>
+                      </div>
+                    </div>
+                  </div>
+
+                  <div v-if="message.type === 'sales_collection_quote_strategy' && message.salesData.listItems?.length" class="sales-focus-list">
+                    <div
+                        v-for="(item, itemIndex) in message.salesData.listItems"
+                        :key="`strategy-${item.customerName || itemIndex}`"
+                        class="sales-focus-item sales-focus-item--strategy"
+                    >
+                      <div class="sales-focus-item__head">
+                        <strong>{{ formatStructuredValue(item.customerName) }}</strong>
+                        <div class="sales-focus-tags">
+                          <el-tag size="small" :type="getSalesLevelTagType(item.priority)">
+                            {{ getSalesLevelLabel(item.priority, 'priority') }}
+                          </el-tag>
+                          <el-tag size="small" type="success">杞寲鐜� {{ formatStructuredValue(item.quoteConversionRate) }}</el-tag>
+                        </div>
+                      </div>
+                      <div class="sales-focus-metrics">
+                        <span>寰呭洖娆撅細{{ formatStructuredValue(item.pendingAmount) }}</span>
+                        <span v-if="item.nextAction">涓嬩竴姝ワ細{{ formatStructuredValue(item.nextAction) }}</span>
+                      </div>
+                      <p v-if="item.collectionStrategy" class="sales-strategy-line">
+                        <strong>鍥炴绛栫暐锛�</strong>{{ formatStructuredValue(item.collectionStrategy) }}
+                      </p>
+                      <p v-if="item.quotationStrategy" class="sales-strategy-line">
+                        <strong>鎶ヤ环绛栫暐锛�</strong>{{ formatStructuredValue(item.quotationStrategy) }}
+                      </p>
+                    </div>
+                  </div>
+
+                  <div
+                      v-if="message.salesData.listItems?.length && message.salesData.columns?.length && !isSalesFocusType(message.type)"
+                      class="table-wrapper manufacturing-table-wrapper"
+                  >
+                    <el-table :data="message.salesData.listItems" border stripe size="small" style="width: 100%">
+                      <el-table-column
+                          v-for="col in message.salesData.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.salesData.topCustomers?.length && message.salesData.topCustomerColumns?.length" class="table-wrapper manufacturing-table-wrapper">
+                    <div class="sales-section-title">閲嶇偣瀹㈡埛</div>
+                    <el-table :data="message.salesData.topCustomers" border stripe size="small" style="width: 100%">
+                      <el-table-column
+                          v-for="col in message.salesData.topCustomerColumns"
+                          :key="`top-customer-${col}`"
+                          :label="getStructuredFieldLabel(col)"
+                          min-width="120"
+                          show-overflow-tooltip
+                      >
+                        <template #default="{ row }">
+                          {{ formatStructuredValue(row[col]) }}
+                        </template>
+                      </el-table-column>
+                    </el-table>
+                  </div>
+
+                  <div v-if="message.salesData.contractTrend?.length && message.salesData.contractTrendColumns?.length" class="table-wrapper manufacturing-table-wrapper">
+                    <div class="sales-section-title">鍚堝悓瓒嬪娍</div>
+                    <el-table :data="message.salesData.contractTrend" border stripe size="small" style="width: 100%">
+                      <el-table-column
+                          v-for="col in message.salesData.contractTrendColumns"
+                          :key="`contract-trend-${col}`"
+                          :label="getStructuredFieldLabel(col)"
+                          min-width="120"
+                          show-overflow-tooltip
+                      >
+                        <template #default="{ row }">
+                          {{ formatStructuredValue(row[col]) }}
+                        </template>
+                      </el-table-column>
+                    </el-table>
+                  </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 +769,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'
@@ -634,6 +880,119 @@
   purchase_return_order: '閲囪喘閫�璐у崟',
   unknown: '鏈煡閲囪喘涓氬姟'
 }
+const salesStructuredTypeSet = new Set([
+  'sales_customer_profile_list',
+  'sales_quotation_list',
+  'sales_ledger_list',
+  'sales_return_list',
+  'sales_customer_interaction_list',
+  'sales_shipping_list',
+  'sales_dashboard',
+  'sales_customer_churn_risk',
+  'sales_collection_quote_strategy'
+])
+const salesFocusTypeSet = new Set([
+  'sales_customer_churn_risk',
+  'sales_collection_quote_strategy'
+])
+const salesTypeLabelMap = {
+  sales_customer_profile_list: '瀹㈡埛妗f',
+  sales_quotation_list: '閿�鍞姤浠�',
+  sales_ledger_list: '閿�鍞彴璐�',
+  sales_return_list: '閿�鍞��璐�',
+  sales_customer_interaction_list: '瀹㈡埛寰�鏉�',
+  sales_shipping_list: '鍙戣揣鍙拌处',
+  sales_dashboard: '閿�鍞寚鏍囩粺璁�',
+  sales_customer_churn_risk: '瀹㈡埛娴佸け椋庨櫓鍒嗘瀽',
+  sales_collection_quote_strategy: '鍥炴涓庢姤浠风瓥鐣ュ缓璁�'
+}
+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: '搴撳瓨閲�'
+}
+Object.assign(structuredFieldLabelMap, {
+  customerName: '瀹㈡埛鍚嶇О',
+  riskLevel: '椋庨櫓绛夌骇',
+  riskScore: '椋庨櫓璇勫垎',
+  riskReasons: '椋庨櫓鍘熷洜',
+  pendingAmount: '寰呭洖娆鹃噾棰�',
+  pendingRate: '寰呭洖娆惧崰姣�',
+  daysSinceLastOrder: '璺濅笂娆′笅鍗曞ぉ鏁�',
+  priority: '浼樺厛绾�',
+  quoteConversionRate: '鎶ヤ环杞寲鐜�',
+  collectionStrategy: '鍥炴绛栫暐',
+  quotationStrategy: '鎶ヤ环绛栫暐',
+  nextAction: '涓嬩竴姝ュ姩浣�',
+  contractAmountTotal: '鍚堝悓鎬婚',
+  receivedAmountTotal: '宸插洖娆鹃噾棰�',
+  pendingAmountTotal: '寰呭洖娆炬�婚',
+  shipRate: '鍙戣揣鐜�'
+})
 const purchasePayloadFieldLabelMap = {
   purchaseLedgers: '閲囪喘鍙拌处',
   productData: '浜у搧鏄庣粏',
@@ -785,6 +1144,437 @@
   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 inferSalesColumns = (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 normalizeSalesListItems = (items) => {
+  if (!Array.isArray(items)) return []
+  return items.filter(item => isPlainObject(item))
+}
+
+const buildSalesStructuredData = (parsedData) => {
+  const type = String(parsedData?.type || '')
+  if (!salesStructuredTypeSet.has(type)) return null
+
+  const rawData = isPlainObject(parsedData?.data) ? parsedData.data : {}
+  const listItems = normalizeSalesListItems(rawData.items)
+  const topCustomers = normalizeSalesListItems(rawData.topCustomers)
+  const contractTrend = normalizeSalesListItems(rawData.contractTrend)
+
+  return {
+    type,
+    summaryEntries: normalizeManufacturingSummaryEntries(parsedData?.summary),
+    listItems,
+    columns: inferSalesColumns(listItems),
+    topCustomers,
+    topCustomerColumns: inferSalesColumns(topCustomers),
+    contractTrend,
+    contractTrendColumns: inferSalesColumns(contractTrend)
+  }
+}
+
+const getSalesTypeLabel = (type = '') => salesTypeLabelMap[String(type || '')] || '閿�鍞煡璇㈢粨鏋�'
+
+const isSalesFocusType = (type = '') => salesFocusTypeSet.has(String(type || ''))
+
+const getSalesLevelTagType = (level = '') => {
+  const normalizedLevel = String(level || '').toLowerCase()
+  if (normalizedLevel === 'high') return 'danger'
+  if (normalizedLevel === 'medium') return 'warning'
+  if (normalizedLevel === 'low') return 'success'
+  return 'info'
+}
+
+const getSalesLevelLabel = (level = '', mode = 'risk') => {
+  const normalizedLevel = String(level || '').toLowerCase()
+  const suffix = mode === 'priority' ? '浼樺厛绾�' : '椋庨櫓'
+  if (normalizedLevel === 'high') return `楂�${suffix}`
+  if (normalizedLevel === 'medium') return `涓�${suffix}`
+  if (normalizedLevel === 'low') return `浣�${suffix}`
+  if (!normalizedLevel) return mode === 'priority' ? '鏈垎绾�' : '鏈瘎浼�'
+  return normalizedLevel.toUpperCase()
+}
+
+const toStructuredStringArray = (value) => {
+  if (Array.isArray(value)) {
+    return value.map(item => String(item || '').trim()).filter(Boolean)
+  }
+  if (typeof value === 'string') {
+    return value
+      .split(/[,\uFF0C\u3001;\uFF1B\n]/)
+      .map(item => item.trim())
+      .filter(Boolean)
+  }
+  return []
+}
+
+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 +1824,9 @@
           tableData: null,
           payloadTreeData: null,
           payloadHiddenData: null,
+          purchaseAnalysisData: null,
+          manufacturingData: null,
+          salesData: null,
           localUploadFiles: isUser ? mapHistoryFilePathsToSnapshots(msg.filePaths, uuid.value, idx) : []
         }
 
@@ -1273,15 +2066,32 @@
 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
+  messageObj.salesData = null
 
   if (messageObj.type === 'todo_list' && parsedData.data) {
     messageObj.tableData = parsedData.data
   }
 
+  const salesData = buildSalesStructuredData(parsedData)
+  if (salesData) {
+    messageObj.salesData = salesData
+  }
+
+  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
+    messageObj.salesData = null
     if (!Array.isArray(messageObj.payloadTreeData) || !messageObj.payloadTreeData.length) {
       initializePurchasePayloadTree(messageObj, parsedData.payload || {})
     }
@@ -1321,6 +2131,25 @@
   }
 
   return null
+}
+
+const getStructuredFallbackText = (parsedData) => {
+  if (!parsedData) return '姝e湪涓烘偍灞曠ず鍒嗘瀽缁撴灉...'
+  if (parsedData.type === 'todo_list') return '宸蹭负鎮ㄦ暣鐞嗗ソ鐩稿叧鏁版嵁銆�'
+  if (salesStructuredTypeSet.has(parsedData.type)) {
+    if (parsedData.type === 'sales_customer_churn_risk') return '宸蹭负鎮ㄧ敓鎴愬鎴锋祦澶遍闄╁垎鏋愩��'
+    if (parsedData.type === 'sales_collection_quote_strategy') return '宸蹭负鎮ㄧ敓鎴愬洖娆句笌鎶ヤ环绛栫暐寤鸿銆�'
+    if (parsedData.type === 'sales_dashboard') return '宸蹭负鎮ㄧ敓鎴愰攢鍞寚鏍囩粺璁°��'
+    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 +3275,10 @@
     type: '',
     tableData: null,
     payloadTreeData: null,
-    payloadHiddenData: null
+    payloadHiddenData: null,
+    purchaseAnalysisData: null,
+    manufacturingData: null,
+    salesData: null
   })
 
   outputState.value[botMsgIndex] = {
@@ -2569,7 +3401,10 @@
     type: '',
     tableData: null,
     payloadTreeData: null,
-    payloadHiddenData: null
+    payloadHiddenData: null,
+    purchaseAnalysisData: null,
+    manufacturingData: null,
+    salesData: null
   }
   messages.value.push(botMsg)
 
@@ -2735,13 +3570,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 +3592,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 +4615,284 @@
   }
 }
 
+.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;
+  }
+}
+
+.sales-structured-card {
+  margin-top: 12px;
+  width: 100%;
+  background: #fff;
+  border: 1px solid rgba(31, 122, 114, 0.2);
+  border-radius: 12px;
+  box-shadow: $shadow-card;
+  padding: 14px;
+}
+
+.sales-structured-card__title {
+  font-size: 14px;
+  font-weight: 700;
+  color: #1f5ddf;
+  margin-bottom: 10px;
+}
+
+.sales-summary-grid {
+  display: grid;
+  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
+  gap: 8px;
+  margin-bottom: 12px;
+}
+
+.sales-summary-item {
+  border-radius: 10px;
+  padding: 10px 12px;
+  border: 1px solid rgba(30, 91, 255, 0.12);
+  background: linear-gradient(180deg, #f7fbff, #edf6ff);
+  min-height: 66px;
+  display: flex;
+  flex-direction: column;
+  justify-content: space-between;
+  gap: 6px;
+}
+
+.sales-summary-label {
+  font-size: 12px;
+  color: #4b5563;
+}
+
+.sales-summary-value {
+  font-size: 15px;
+  color: #1f2937;
+  line-height: 1.4;
+  word-break: break-all;
+}
+
+.sales-focus-list {
+  display: flex;
+  flex-direction: column;
+  gap: 8px;
+}
+
+.sales-focus-item {
+  border-radius: 10px;
+  border: 1px solid rgba(30, 91, 255, 0.14);
+  background: #f8fbff;
+  padding: 10px 12px;
+}
+
+.sales-focus-item--strategy {
+  border-color: rgba(31, 122, 114, 0.22);
+  background: linear-gradient(180deg, #f7fcfb, #edf9f6);
+}
+
+.sales-focus-item__head {
+  display: flex;
+  align-items: flex-start;
+  justify-content: space-between;
+  gap: 10px;
+  font-size: 13px;
+  color: #1f2937;
+}
+
+.sales-focus-tags {
+  display: inline-flex;
+  align-items: center;
+  gap: 6px;
+  flex-wrap: wrap;
+  justify-content: flex-end;
+}
+
+.sales-focus-metrics {
+  margin-top: 8px;
+  display: flex;
+  flex-wrap: wrap;
+  gap: 10px;
+  font-size: 12px;
+  color: #475467;
+}
+
+.sales-focus-reasons {
+  margin-top: 8px;
+  display: flex;
+  flex-wrap: wrap;
+  gap: 6px;
+}
+
+.sales-strategy-line {
+  margin: 8px 0 0;
+  font-size: 12px;
+  line-height: 1.6;
+  color: #334155;
+}
+
+.sales-section-title {
+  margin: 4px 0 8px;
+  font-size: 13px;
+  font-weight: 700;
+  color: $deep-blue;
+}
+
 .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/layout/components/Sidebar/index.vue b/src/layout/components/Sidebar/index.vue
index 0692dda..d1d60b3 100644
--- a/src/layout/components/Sidebar/index.vue
+++ b/src/layout/components/Sidebar/index.vue
@@ -82,6 +82,7 @@
         margin-bottom: 6px;
         border-radius: 14px;
         color: v-bind(getMenuTextColor);
+        font-size: 13px;
 
         &:hover {
           background-color: var(--menu-hover, rgba(0, 0, 0, 0.06)) !important;
@@ -99,6 +100,19 @@
 
       .el-sub-menu__title {
         color: v-bind(getMenuTextColor);
+      }
+
+      :deep(.el-sub-menu__icon-arrow) {
+        display: inline-flex !important;
+        align-items: center;
+        justify-content: center;
+        width: 14px;
+        height: 14px;
+        margin-top: -7px;
+        right: 12px;
+        font-size: 14px !important;
+        color: currentColor !important;
+        opacity: 0.72;
       }
 
       :deep(.el-sub-menu.is-active > .el-sub-menu__title) {
@@ -128,6 +142,7 @@
 
       :deep(.el-sub-menu.is-active > .el-sub-menu__title .menu-title),
       :deep(.el-sub-menu.is-active > .el-sub-menu__title .svg-icon),
+      :deep(.el-sub-menu.is-active > .el-sub-menu__title .el-sub-menu__icon-arrow),
       :deep(.el-menu-item.is-active .menu-title),
       :deep(.el-menu-item.is-active .svg-icon) {
         color: v-bind(theme) !important;
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..809fd4f 100644
--- a/src/views/equipmentManagement/inspectionManagement/index.vue
+++ b/src/views/equipmentManagement/inspectionManagement/index.vue
@@ -70,6 +70,12 @@
                     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 +132,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: "棰戞",
@@ -176,6 +190,19 @@
     },
     { prop: "registrant", label: "鐧昏浜�", minWidth: 100 },
     { prop: "createTime", label: "鐧昏鏃ユ湡", minWidth: 100 },
+    {
+      prop: "inspectionResult",
+      label: "宸℃缁撴灉",
+      minWidth: 100,
+      dataType: "tag",
+      formatData: val => {
+        return val == 1 ? "姝e父" : "寮傚父";
+      },
+      formatType: val => {
+        return val == 1 ? "success" : "danger";
+      },
+    },
+    { prop: "abnormalDescription", label: "寮傚父鎻忚堪", minWidth: 100 },
   ]);
 
   // 鎿嶄綔鍒楅厤缃�
@@ -227,8 +254,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/MaintenanceModal.vue b/src/views/equipmentManagement/upkeep/Form/MaintenanceModal.vue
index e86b64a..0fcccb2 100644
--- a/src/views/equipmentManagement/upkeep/Form/MaintenanceModal.vue
+++ b/src/views/equipmentManagement/upkeep/Form/MaintenanceModal.vue
@@ -1,199 +1,216 @@
 <template>
-  <FormDialog
-    v-model="visible"
-    :title="'璁惧淇濆吇'"
-    width="500px"
-    @confirm="sendForm"
-    @cancel="handleCancel"
-    @close="handleClose"
-  >
-    <el-form :model="form" label-width="100px">
+  <FormDialog v-model="visible"
+              :title="'璁惧淇濆吇'"
+              width="500px"
+              @confirm="sendForm"
+              @cancel="handleCancel"
+              @close="handleClose">
+    <el-form :model="form"
+             label-width="100px">
       <el-form-item label="瀹為檯淇濆吇浜�">
-        <el-input
-          v-model="form.maintenanceActuallyName"
-          placeholder="璇疯緭鍏ュ疄闄呬繚鍏讳汉"
-        ></el-input>
+        <el-input v-model="form.maintenanceActuallyName"
+                  placeholder="璇疯緭鍏ュ疄闄呬繚鍏讳汉"></el-input>
       </el-form-item>
       <el-form-item label="瀹為檯淇濆吇鏃ユ湡">
-        <el-date-picker
-          v-model="form.maintenanceActuallyTime"
-          placeholder="璇烽�夋嫨瀹為檯淇濆吇鏃ユ湡"
-          format="YYYY-MM-DD HH:mm:ss"
-          value-format="YYYY-MM-DD HH:mm:ss"
-          type="datetime"
-          clearable
-          style="width: 100%"
-        />
+        <el-date-picker v-model="form.maintenanceActuallyTime"
+                        placeholder="璇烽�夋嫨瀹為檯淇濆吇鏃ユ湡"
+                        format="YYYY-MM-DD HH:mm:ss"
+                        value-format="YYYY-MM-DD HH:mm:ss"
+                        type="datetime"
+                        clearable
+                        style="width: 100%" />
       </el-form-item>
       <el-form-item label="淇濆吇鐘舵��">
         <el-select v-model="form.status">
-          <el-option label="寰呬繚鍏�" :value="0"></el-option>
-          <el-option label="瀹岀粨" :value="1"></el-option>
-          <el-option label="澶辫触" :value="2"></el-option>
+          <el-option label="寰呬繚鍏�"
+                     :value="0"></el-option>
+          <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.maintenanceResult"
-          placeholder="璇疯緭鍏ヤ繚鍏荤粨鏋�"
-          type="text" />
+        <el-input v-model="form.maintenanceResult"
+                  placeholder="璇疯緭鍏ヤ繚鍏荤粨鏋�"
+                  type="text" />
       </el-form-item>
       <el-form-item label="璁惧澶囦欢">
-        <el-select v-model="form.sparePartsIds" :loading="loadingSparePartOptions" placeholder="璇烽�夋嫨璁惧澶囦欢" multiple filterable>
-          <el-option
-              v-for="item in sparePartOptions"
-              :key="item.id"
-              :label="item.name"
-              :value="item.id"
-          />
+        <el-select v-model="form.sparePartsIds"
+                   :loading="loadingSparePartOptions"
+                   placeholder="璇烽�夋嫨璁惧澶囦欢"
+                   multiple
+                   filterable>
+          <el-option v-for="item in sparePartOptions"
+                     :key="item.id"
+                     :label="item.name"
+                     :value="item.id" />
         </el-select>
       </el-form-item>
-
-      <el-form-item v-if="selectedSpareParts.length" label="棰嗙敤鏁伴噺">
+      <el-form-item v-if="selectedSpareParts.length"
+                    label="棰嗙敤鏁伴噺">
         <div style="width: 100%">
-          <div
-              v-for="item in selectedSpareParts"
-              :key="item.id"
-              style="display: flex; align-items: center; gap: 10px; margin-bottom: 10px;"
-          >
+          <div v-for="item in selectedSpareParts"
+               :key="item.id"
+               style="display: flex; align-items: center; gap: 10px; margin-bottom: 10px;">
             <div style="flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">
               {{ item.name }}
-              <span v-if="item.quantity !== null && item.quantity !== undefined" style="color: #909399;">
+              <span v-if="item.quantity !== null && item.quantity !== undefined"
+                    style="color: #909399;">
                 锛堝簱瀛橈細{{ item.quantity }}锛�
               </span>
             </div>
-            <el-input-number
-                v-model="sparePartQtyMap[item.id]"
-                :min="1"
-                :max="item.quantity !== null && item.quantity !== undefined ? Number(item.quantity) : undefined"
-                :step="1"
-                controls-position="right"
-                style="width: 180px"
-            />
+            <el-input-number v-model="sparePartQtyMap[item.id]"
+                             :min="1"
+                             :max="item.quantity !== null && item.quantity !== undefined ? Number(item.quantity) : undefined"
+                             :step="1"
+                             controls-position="right"
+                             style="width: 180px" />
           </div>
         </div>
+      </el-form-item>
+      <el-form-item label="闄勪欢">
+        <FileUpload v-model:file-list="form.storageBlobDTOs" />
       </el-form-item>
     </el-form>
   </FormDialog>
 </template>
 
 <script setup>
-import FormDialog from "@/components/Dialog/FormDialog.vue";
-import { addMaintenance } from "@/api/equipmentManagement/upkeep";
-import useFormData from "@/hooks/useFormData";
-import dayjs from "dayjs";
-import useUserStore from "@/store/modules/user";
-import { ElMessage } from "element-plus";
-import {computed, ref} from "vue";
-import {getSparePartsList} from "@/api/equipmentManagement/spareParts.js";
+  import FormDialog from "@/components/Dialog/FormDialog.vue";
+  import FileUpload from "@/components/AttachmentUpload/file/index.vue";
+  import { addMaintenance } from "@/api/equipmentManagement/upkeep";
+  import useFormData from "@/hooks/useFormData";
+  import dayjs from "dayjs";
+  import useUserStore from "@/store/modules/user";
+  import { ElMessage } from "element-plus";
+  import { computed, ref, nextTick, getCurrentInstance } from "vue";
+  import { getSparePartsList } from "@/api/equipmentManagement/spareParts.js";
 
-defineOptions({
-  name: "淇濆吇妯℃�佹",
-});
+  defineOptions({
+    name: "淇濆吇妯℃�佹",
+  });
 
-const emits = defineEmits(["ok"]);
+  const emits = defineEmits(["ok"]);
 
-// 淇濆瓨璁″垝淇濆吇璁板綍鐨刬d
-const planId = ref();
-const visible = ref(false);
-const loading = ref(false);
-const userStore = useUserStore();
+  const { proxy } = getCurrentInstance();
+  // 淇濆瓨璁″垝淇濆吇璁板綍鐨刬d
+  const planId = ref();
+  const visible = ref(false);
+  const loading = ref(false);
+  const userStore = useUserStore();
 
-const { form, resetForm } = useFormData({
-  maintenanceActuallyName: undefined, // 瀹為檯淇濆吇浜�
-  maintenanceActuallyTime: undefined, // 瀹為檯淇濆吇鏃ユ湡
-  maintenanceResult: undefined, // 淇濆吇缁撴灉
-  status: 0, // 淇濆吇鐘舵��
-  sparePartsIds: [],
-});
+  const { form, resetForm } = useFormData({
+    maintenanceActuallyName: undefined, // 瀹為檯淇濆吇浜�
+    maintenanceActuallyTime: undefined, // 瀹為檯淇濆吇鏃ユ湡
+    maintenanceResult: undefined, // 淇濆吇缁撴灉
+    status: 0, // 淇濆吇鐘舵��
+    sparePartsIds: [],
+    storageBlobDTOs: [],
+  });
 
-const sparePartOptions = ref([])
-const loadingSparePartOptions = ref(true)
-const sparePartQtyMap = ref({})
+  const sparePartOptions = ref([]);
+  const loadingSparePartOptions = ref(true);
+  const sparePartQtyMap = ref({});
 
-const selectedSpareParts = computed(() => {
-  const ids = Array.isArray(form.sparePartsIds) ? form.sparePartsIds : [];
-  const set = new Set(ids.map((i) => String(i)));
-  return (sparePartOptions.value || []).filter((p) => set.has(String(p.id)));
-});
+  const selectedSpareParts = computed(() => {
+    const ids = Array.isArray(form.sparePartsIds) ? form.sparePartsIds : [];
+    const set = new Set(ids.map(i => String(i)));
+    return (sparePartOptions.value || []).filter(p => set.has(String(p.id)));
+  });
 
-const setForm = (data) => {
-  form.maintenanceActuallyName =
-    data.maintenanceActuallyName ?? userStore.nickName;
-  form.maintenanceActuallyTime =
-    data.maintenanceActuallyTime 
+  const setForm = data => {
+    form.maintenanceActuallyName =
+      data.maintenanceActuallyName ?? userStore.nickName;
+    form.maintenanceActuallyTime = data.maintenanceActuallyTime
       ? dayjs(data.maintenanceActuallyTime).format("YYYY-MM-DD HH:mm:ss")
       : dayjs().format("YYYY-MM-DD HH:mm:ss");
-  form.maintenanceResult = data.maintenanceResult;
-  form.status = 1; // 榛樿鐘舵�佷负瀹岀粨
-  // multiple 閫夋嫨鍣ㄨ姹傛暟缁勶紱鍚庣甯歌繑鍥� "1,2,3"
-  if (Array.isArray(data?.sparePartsIds)) {
-    form.sparePartsIds = data.sparePartsIds.map((v) => Number(v)).filter((v) => Number.isFinite(v));
-  } else if (typeof data?.sparePartsIds === "string") {
-    form.sparePartsIds = data.sparePartsIds
+    form.maintenanceResult = data.maintenanceResult;
+    form.status = 1; // 榛樿鐘舵�佷负瀹岀粨
+    // multiple 閫夋嫨鍣ㄨ姹傛暟缁勶紱鍚庣甯歌繑鍥� "1,2,3"
+    if (Array.isArray(data?.sparePartsIds)) {
+      form.sparePartsIds = data.sparePartsIds
+        .map(v => Number(v))
+        .filter(v => Number.isFinite(v));
+    } else if (typeof data?.sparePartsIds === "string") {
+      form.sparePartsIds = data.sparePartsIds
         .split(",")
-        .map((s) => Number(String(s).trim()))
-        .filter((v) => Number.isFinite(v));
-  } else if (typeof data?.sparePartsIds === "number") {
-    form.sparePartsIds = [data.sparePartsIds];
-  } else {
-    form.sparePartsIds = [];
-  }
-};
+        .map(s => Number(String(s).trim()))
+        .filter(v => Number.isFinite(v));
+    } else if (typeof data?.sparePartsIds === "number") {
+      form.sparePartsIds = [data.sparePartsIds];
+    } else {
+      form.sparePartsIds = [];
+    }
+    form.storageBlobDTOs = data.storageBlobVOs || [];
+  };
 
-/**
- * @desc 淇濆瓨淇濆吇
- */
-const sendForm = async () => {
-  loading.value = true;
-  try {
-    // 棰嗙敤鏁伴噺鏍¢獙
-    if (Array.isArray(form.sparePartsIds) && form.sparePartsIds.length > 0) {
-      for (const partId of form.sparePartsIds) {
-        const qty = Number(sparePartQtyMap.value?.[partId]);
-        if (!Number.isFinite(qty) || qty <= 0) {
-          proxy?.$modal?.msgError?.("璇峰~鍐欏浠堕鐢ㄦ暟閲�");
-          return;
-        }
-        const part = sparePartOptions.value.find((p) => String(p.id) === String(partId));
-        const stock = part?.quantity;
-        if (stock !== null && stock !== undefined && Number.isFinite(Number(stock))) {
-          if (qty > Number(stock)) {
-            proxy?.$modal?.msgError?.(`澶囦欢銆�${part?.name || ""}銆嶉鐢ㄦ暟閲忎笉鑳借秴杩囧簱瀛橈紙${stock}锛塦);
+  /**
+   * @desc 淇濆瓨淇濆吇
+   */
+  const sendForm = async () => {
+    loading.value = true;
+    try {
+      // 棰嗙敤鏁伴噺鏍¢獙
+      if (Array.isArray(form.sparePartsIds) && form.sparePartsIds.length > 0) {
+        for (const partId of form.sparePartsIds) {
+          const qty = Number(sparePartQtyMap.value?.[partId]);
+          if (!Number.isFinite(qty) || qty <= 0) {
+            proxy?.$modal?.msgError?.("璇峰~鍐欏浠堕鐢ㄦ暟閲�");
             return;
+          }
+          const part = sparePartOptions.value.find(
+            p => String(p.id) === String(partId)
+          );
+          const stock = part?.quantity;
+          if (
+            stock !== null &&
+            stock !== undefined &&
+            Number.isFinite(Number(stock))
+          ) {
+            if (qty > Number(stock)) {
+              proxy?.$modal?.msgError?.(
+                `澶囦欢銆�${part?.name || ""}銆嶉鐢ㄦ暟閲忎笉鑳借秴杩囧簱瀛橈紙${stock}锛塦
+              );
+              return;
+            }
           }
         }
       }
-    }
-    const data = {
-      id: planId.value,
-      ...form,
-      sparePartsIds: form.sparePartsIds ? form.sparePartsIds.join(",") : "",
-      sparePartsQty: form.sparePartsIds
-          ? form.sparePartsIds.map((id) => sparePartQtyMap.value?.[id] ?? 1).join(",")
+      const data = {
+        id: planId.value,
+        ...form,
+        sparePartsIds: form.sparePartsIds ? form.sparePartsIds.join(",") : "",
+        sparePartsQty: form.sparePartsIds
+          ? form.sparePartsIds
+              .map(id => sparePartQtyMap.value?.[id] ?? 1)
+              .join(",")
           : "",
-      sparePartsUseList: form.sparePartsIds
-          ? form.sparePartsIds.map((id) => ({ id, quantity: sparePartQtyMap.value?.[id] ?? 1 }))
+        sparePartsUseList: form.sparePartsIds
+          ? form.sparePartsIds.map(id => ({
+              id,
+              quantity: sparePartQtyMap.value?.[id] ?? 1,
+            }))
           : [],
+      };
+      const { code } = await addMaintenance(data);
+      if (code == 200) {
+        ElMessage.success("淇濆吇鎴愬姛");
+        emits("ok");
+        resetForm();
+        sparePartQtyMap.value = {};
+        visible.value = false;
+      }
+    } finally {
+      loading.value = false;
     }
-    const { code } = await addMaintenance(data);
-    if (code == 200) {
-      ElMessage.success("淇濆吇鎴愬姛");
-      emits("ok");
-      resetForm();
-      sparePartQtyMap.value = {};
-      visible.value = false;
-    }
-  } finally {
-    loading.value = false;
-  }
-};
+  };
 
-const fetchSparePartOptions = () => {
-  loadingSparePartOptions.value = true;
-  // 鍜屽浠剁鐞嗛〉涓�鑷达細/spareParts/listPage 鈫� res.data.records
-  getSparePartsList({ current: 1, size: 1000 })
-      .then((res) => {
+  const fetchSparePartOptions = () => {
+    loadingSparePartOptions.value = true;
+    // 鍜屽浠剁鐞嗛〉涓�鑷达細/spareParts/listPage 鈫� res.data.records
+    getSparePartsList({ current: 1, size: 1000 })
+      .then(res => {
         if (res.code === 200) {
           sparePartOptions.value = res?.data?.records || [];
         } else {
@@ -206,31 +223,31 @@
       .finally(() => {
         loadingSparePartOptions.value = false;
       });
-}
+  };
 
-const handleCancel = () => {
-  resetForm();
-  sparePartQtyMap.value = {};
-  visible.value = false;
-};
+  const handleCancel = () => {
+    resetForm();
+    sparePartQtyMap.value = {};
+    visible.value = false;
+  };
 
-const handleClose = () => {
-  resetForm();
-  sparePartQtyMap.value = {};
-  visible.value = false;
-};
+  const handleClose = () => {
+    resetForm();
+    sparePartQtyMap.value = {};
+    visible.value = false;
+  };
 
-const open = async (id, row) => {
-  planId.value = id; // 淇濆瓨璁″垝淇濆吇璁板綍鐨刬d
-  visible.value = true;
-  await nextTick();
-  fetchSparePartOptions()
-  setForm(row);
-};
+  const open = async (id, row) => {
+    planId.value = id; // 淇濆瓨璁″垝淇濆吇璁板綍鐨刬d
+    visible.value = true;
+    await nextTick();
+    fetchSparePartOptions();
+    setForm(row);
+  };
 
-defineExpose({
-  open,
-});
+  defineExpose({
+    open,
+  });
 </script>
 
 <style lang="scss" scoped></style>
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..c22ebcc 100644
--- a/src/views/equipmentManagement/upkeep/index.vue
+++ b/src/views/equipmentManagement/upkeep/index.vue
@@ -2,8 +2,8 @@
   <div class="app-container">
     <el-tabs v-model="activeTab"
              @tab-change="handleTabChange">
-      <!-- 瀹氭椂浠诲姟绠$悊tab -->
-      <el-tab-pane label="瀹氭椂浠诲姟绠$悊"
+      <!-- 淇濆吇浠诲姟tab -->
+      <el-tab-pane label="淇濆吇浠诲姟"
                    name="scheduled">
         <div class="search_form">
           <el-form :model="scheduledFilters"
@@ -37,7 +37,7 @@
         <div class="table_list">
           <div class="actions">
             <el-text class="mx-1"
-                     size="large">瀹氭椂浠诲姟绠$悊</el-text>
+                     size="large">淇濆吇浠诲姟</el-text>
             <div>
               <el-button type="primary"
                          icon="Plus"
@@ -84,8 +84,8 @@
           </PIMTable>
         </div>
       </el-tab-pane>
-      <!-- 浠诲姟璁板綍tab锛堝師璁惧淇濆吇椤甸潰锛� -->
-      <el-tab-pane label="浠诲姟璁板綍"
+      <!-- 淇濆吇璁板綍tab锛堝師璁惧淇濆吇椤甸潰锛� -->
+      <el-tab-pane label="淇濆吇璁板綍"
                    name="record">
         <div class="search_form">
           <el-form :model="filters"
@@ -130,7 +130,7 @@
         <div class="table_list">
           <div class="actions">
             <el-text class="mx-1"
-                     size="large">浠诲姟璁板綍</el-text>
+                     size="large">淇濆吇璁板綍</el-text>
             <div>
               <el-button type="success"
                          icon="Van"
@@ -262,7 +262,7 @@
   const fileDialogVisible = ref(false);
   const currentMaintenanceTaskId = ref(null);
 
-  // 浠诲姟璁板綍tab锛堝師璁惧淇濆吇椤甸潰锛夌浉鍏冲彉閲�
+  // 淇濆吇璁板綍tab锛堝師璁惧淇濆吇椤甸潰锛夌浉鍏冲彉閲�
   const filters = reactive({
     deviceName: "",
     maintenancePlanTime: "",
@@ -278,7 +278,7 @@
   });
   const multipleList = ref([]);
 
-  // 瀹氭椂浠诲姟绠$悊tab鐩稿叧鍙橀噺
+  // 淇濆吇浠诲姟tab鐩稿叧鍙橀噺
   const scheduledFilters = reactive({
     taskName: "",
     status: "",
@@ -292,7 +292,7 @@
   });
   const scheduledMultipleList = ref([]);
 
-  // 瀹氭椂浠诲姟绠$悊琛ㄦ牸鍒楅厤缃�
+  // 淇濆吇浠诲姟琛ㄦ牸鍒楅厤缃�
   const scheduledColumns = ref([
     { prop: "taskName", label: "璁惧鍚嶇О" },
     {
@@ -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 },
     {
@@ -354,7 +355,7 @@
     },
   ]);
 
-  // 浠诲姟璁板綍琛ㄦ牸鍒楅厤缃紙鍘熻澶囦繚鍏昏〃鏍煎垪锛�
+  // 淇濆吇璁板綍琛ㄦ牸鍒楅厤缃紙鍘熻澶囦繚鍏昏〃鏍煎垪锛�
   const columns = ref([
     {
       label: "璁惧鍚嶇О",
@@ -378,7 +379,7 @@
       prop: "createUserName",
     },
     {
-      label: "璁惧椤圭洰",
+      label: "淇濆吇椤圭洰",
       align: "center",
       prop: "machineryCategory",
       formatData: cell => cell || "--",
@@ -435,7 +436,7 @@
     }
   };
 
-  // 瀹氭椂浠诲姟绠$悊鐩稿叧鏂规硶
+  // 淇濆吇浠诲姟鐩稿叧鏂规硶
   const getScheduledTableData = async () => {
     try {
       const params = {
@@ -502,7 +503,7 @@
     ElMessage.info("瀵煎嚭瀹氭椂浠诲姟鍔熻兘寰呭疄鐜�");
   };
 
-  // 浠诲姟璁板綍鐩稿叧鏂规硶锛堝師璁惧淇濆吇椤甸潰鏂规硶锛�
+  // 淇濆吇璁板綍鐩稿叧鏂规硶锛堝師璁惧淇濆吇椤甸潰鏂规硶锛�
   const getTableData = async () => {
     try {
       const params = {
diff --git a/src/views/financialManagement/assets/fixedAssets.vue b/src/views/financialManagement/assets/fixedAssets.vue
index c6241c8..24b4cc3 100644
--- a/src/views/financialManagement/assets/fixedAssets.vue
+++ b/src/views/financialManagement/assets/fixedAssets.vue
@@ -38,7 +38,7 @@
         <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
diff --git a/src/views/financialManagement/assets/intangibleAssets.vue b/src/views/financialManagement/assets/intangibleAssets.vue
index 47820c2..4642166 100644
--- a/src/views/financialManagement/assets/intangibleAssets.vue
+++ b/src/views/financialManagement/assets/intangibleAssets.vue
@@ -39,7 +39,7 @@
         <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
diff --git a/src/views/financialManagement/generalLedger/index.vue b/src/views/financialManagement/generalLedger/index.vue
index 556567b..a7b1d30 100644
--- a/src/views/financialManagement/generalLedger/index.vue
+++ b/src/views/financialManagement/generalLedger/index.vue
@@ -44,8 +44,8 @@
           <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>
       <el-table ref="tableRef"
diff --git a/src/views/financialManagement/voucher/detailLedger.vue b/src/views/financialManagement/voucher/detailLedger.vue
index 1909d0e..c07574c 100644
--- a/src/views/financialManagement/voucher/detailLedger.vue
+++ b/src/views/financialManagement/voucher/detailLedger.vue
@@ -32,7 +32,7 @@
           <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="handlePrint" icon="Printer">鎵撳嵃</el-button>-->
             <el-button @click="handleOut" icon="Download">瀵煎嚭</el-button>
           </el-form-item>
         </el-form>
diff --git a/src/views/financialManagement/voucher/generalLedger.vue b/src/views/financialManagement/voucher/generalLedger.vue
index 9683487..b362279 100644
--- a/src/views/financialManagement/voucher/generalLedger.vue
+++ b/src/views/financialManagement/voucher/generalLedger.vue
@@ -32,34 +32,34 @@
           <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-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">
+            <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="璐锋柟" width="150">
+            <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="鏂瑰悜" width="80">
+            <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="浣欓" width="150">
+            <el-table-column label="浣欓">
               <template #default="{ row }">
                 <span :class="row.balance >= 0 ? 'text-primary' : 'text-warning'">楼{{ formatMoney(Math.abs(row.balance)) }}</span>
               </template>
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/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..0c326cc 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 };
@@ -279,9 +316,45 @@
     });
   };
 
+  const findSiblings = (items: any[], tempId: string): any[] | null => {
+    if (!items || items.length === 0) return null;
+    // 妫�鏌ュ綋鍓嶅眰绾�
+    if (items.some(item => item.tempId === tempId)) {
+      return items;
+    }
+    // 閫掑綊鏌ユ壘瀛愮骇
+    for (const item of items) {
+      if (item.children && item.children.length > 0) {
+        const result = findSiblings(item.children, tempId);
+        if (result) return result;
+      }
+    }
+    return null;
+  };
+
   const handleProcessChange = (row: any, value: any) => {
+    if (value) {
+      const siblings = findSiblings(dataValue.dataList, row.tempId);
+      if (siblings) {
+        const isDuplicate = siblings.some(
+          s => s.tempId !== row.tempId && s.processId === value
+        );
+        if (isDuplicate) {
+          const option = getProcessOptionById(value);
+          const processName = option?.name || "璇ュ伐搴�";
+          ElMessage.warning(`鍚屼竴灞傜骇涓嬩笉鑳介�夋嫨閲嶅鐨勬秷鑰楀伐搴忥細${processName}`);
+          row.processId = "";
+          syncProcessOperationFields(row);
+          return;
+        }
+      }
+    }
     row.processId = value || "";
     syncProcessOperationFields(row);
+  };
+
+  const handleUnitQuantityChange = () => {
+    recalculateDemandedQuantities();
   };
 
   const tableData = reactive([
@@ -304,6 +377,7 @@
       const { data } = await listProcessBom({ orderId: routeOrderId.value });
       dataValue.dataList = (data as any) || [];
       normalizeTreeData(dataValue.dataList);
+      recalculateDemandedQuantities();
     } else {
       // 闈炶鍗曟儏鍐碉細浣跨敤鍘熸潵鐨勬帴鍙�
       const { data } = await queryList(routeId.value);
@@ -389,8 +463,37 @@
   const validateAll = () => {
     let isValid = true;
 
+    // 鏍¢獙涓�缁勫厔寮熻妭鐐圭殑宸ュ簭鏄惁鍞竴
+    const checkProcessUniqueness = (items: any[]) => {
+      if (!items || items.length === 0 || !isValid) return;
+
+      const processIds = new Set();
+      for (const item of items) {
+        if (item.processId) {
+          if (processIds.has(item.processId)) {
+            const option = getProcessOptionById(item.processId);
+            const processName = option?.name || item.processName || "鏈煡宸ュ簭";
+            ElMessage.error(
+              `浜у搧銆�${item.productName}銆嶇殑娑堣�楀伐搴忋��${processName}銆嶅湪褰撳墠灞傜骇宸插瓨鍦紝璇峰嬁閲嶅璁剧疆`
+            );
+            isValid = false;
+            return;
+          }
+          processIds.add(item.processId);
+        }
+      }
+
+      // 閫掑綊鏍¢獙瀛愮骇鐨勫厔寮熻妭鐐�
+      for (const item of items) {
+        if (item.children && item.children.length > 0) {
+          checkProcessUniqueness(item.children);
+        }
+      }
+    };
+
     // 鏍¢獙鍑芥暟
     const validateItem = (item: any, isTopLevel = false) => {
+      if (!isValid) return;
       // 鏍¢獙褰撳墠椤圭殑蹇呭~瀛楁
       if (!item.model) {
         ElMessage.error("璇烽�夋嫨瑙勬牸");
@@ -418,7 +521,7 @@
       //   return;
       // }
 
-      // 閫掑綊鏍¢獙瀛愰」
+      // 閫掑綊鏍¢獙瀛愰」瀛楁
       if (item.children && item.children.length > 0) {
         item.children.forEach(child => {
           validateItem(child, false);
@@ -426,7 +529,11 @@
       }
     };
 
-    // 閬嶅巻鎵�鏈夐《灞傞」
+    // 1. 棣栧厛鏍¢獙鍚屼竴鐖剁骇涓嬬殑鍚屽眰娑堣�楀伐搴忔槸鍚﹀敮涓�
+    checkProcessUniqueness(dataValue.dataList);
+    if (!isValid) return false;
+
+    // 2. 鐒跺悗閬嶅巻鏍¢獙鎵�鏈夐《灞傞」鐨勫瓧娈靛繀濉儏鍐�
     dataValue.dataList.forEach(item => {
       validateItem(item, true);
     });
@@ -437,6 +544,7 @@
   const submit = () => {
     dataValue.loading = true;
     normalizeTreeData(dataValue.dataList);
+    recalculateDemandedQuantities();
 
     // 鍏堣繘琛岃〃鍗曟牎楠�
     const valid = validateAll();
@@ -514,6 +622,7 @@
 
           tempId: new Date().getTime(),
         });
+        recalculateDemandedQuantities();
         return;
       }
       addchildItem(item, tempId);
@@ -542,6 +651,7 @@
         unit: "",
         tempId: new Date().getTime(),
       });
+      recalculateDemandedQuantities();
       return true;
     }
     if (item.children && item.children.length > 0) {
@@ -587,4 +697,4 @@
     await fetchProcessOptions();
     await fetchData();
   });
-</script>
\ No newline at end of file
+</script>
diff --git a/src/views/productionManagement/productionOrder/components/MaterialLedgerDialog.vue b/src/views/productionManagement/productionOrder/components/MaterialLedgerDialog.vue
index d058896..09e7421 100644
--- a/src/views/productionManagement/productionOrder/components/MaterialLedgerDialog.vue
+++ b/src/views/productionManagement/productionOrder/components/MaterialLedgerDialog.vue
@@ -111,6 +111,7 @@
         <span class="dialog-footer">
           <el-button type="primary"
                      :loading="materialSaving"
+                     :disabled="isSaveDisabled"
                      @click="handleMaterialSave">淇濆瓨</el-button>
           <el-button @click="dialogVisible = false">鍙栨秷</el-button>
         </span>
@@ -155,6 +156,33 @@
   const materialTableLoading = ref(false);
   const materialSaving = ref(false);
   const materialTableData = ref([]);
+
+  const isSaveDisabled = computed(() => {
+    if (materialTableData.value.length === 0) return true;
+    return !materialTableData.value.some(row => {
+      // 妫�鏌ユ槸鍚︽湁浠讳綍鐢ㄦ埛杈撳叆鍐呭
+      const hasBatch = Array.isArray(row.batchNo) && row.batchNo.length > 0;
+      const hasPickQty =
+        row.pickQty !== null && row.pickQty !== undefined && row.pickQty !== 0;
+
+      if (row.bom) {
+        // 瀵逛簬鏉ヨ嚜BOM鐨勮锛岃緭鍏ユ鍙湁鈥滄壒鍙封�濆拰鈥滈鐢ㄦ暟閲忊��
+        return hasBatch || hasPickQty;
+      } else {
+        // 瀵逛簬鏂板琛岋紝杈撳叆妗嗗寘鎷�滃伐搴忊�濄�佲�滃師鏂欌�濄�佲�滈渶姹傛暟閲忊�濄�佲�滄壒鍙封�濆拰鈥滈鐢ㄦ暟閲忊��
+        const hasOperation = !!row.operationName;
+        const hasMaterial = !!row.materialName;
+        const hasDemanded =
+          row.demandedQuantity !== null &&
+          row.demandedQuantity !== undefined &&
+          row.demandedQuantity !== 0;
+        return (
+          hasBatch || hasPickQty || hasOperation || hasMaterial || hasDemanded
+        );
+      }
+    });
+  });
+
   const processOptions = ref([]);
   const currentMaterialSelectRowIndex = ref(-1);
   let materialTempId = 0;
diff --git a/src/views/productionManagement/productionProcess/index.vue b/src/views/productionManagement/productionProcess/index.vue
index 6d007a4..ee49657 100644
--- a/src/views/productionManagement/productionProcess/index.vue
+++ b/src/views/productionManagement/productionProcess/index.vue
@@ -44,7 +44,7 @@
             <div class="card-body">
               <!-- <div class="process-name">{{ process.name }}</div> -->
               <div class="process-desc">{{ process.remark || '鏆傛棤鎻忚堪' }}</div>
-              <div class="process-device">鍏宠仈璁惧: {{ deviceOptions.find(item => item.id === Number(process.deviceLedgerId))?.deviceName|| '鏈叧鑱�' }}</div>
+              <div class="process-device">鍏宠仈璁惧: {{ (deviceOptions.find(item => item.id === Number(process.deviceLedgerId))?.deviceName) || '鏈叧鑱�' }}</div>
             </div>
             <div class="card-footer">
               <div class="status-tag">
@@ -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();
           }
         },
@@ -551,7 +570,10 @@
     processForm.isQuality = !!process.isQuality;
     processForm.isProduction = !!process.isProduction;
     processForm.remark = process.remark || "";
-    processForm.deviceLedgerId = Number(process.deviceLedgerId);
+    // 濡傛灉璁惧 ID 涓� 0 鎴栬�呭湪璁惧鍒楄〃涓壘涓嶅埌锛屽垯鍥炴樉涓虹┖锛坣ull锛�
+    const deviceId = Number(process.deviceLedgerId);
+    const hasDevice = deviceOptions.value.some(item => item.id === deviceId);
+    processForm.deviceLedgerId = deviceId && hasDevice ? deviceId : null;
     processForm.type = process.type;
     processDialogVisible.value = true;
   };
@@ -717,6 +739,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/productionManagement/productionTraceability/index.vue b/src/views/productionManagement/productionTraceability/index.vue
index ab1c34a..2b220dc 100644
--- a/src/views/productionManagement/productionTraceability/index.vue
+++ b/src/views/productionManagement/productionTraceability/index.vue
@@ -1,5 +1,6 @@
 <template>
   <div class="app-container">
+    <PageHeader content="鐢熶骇璁㈠崟" />
     <el-card style="height:82vh;overflow:auto;">
       <template #header>
         <div class="card-header">
diff --git a/src/views/productionManagement/workOrderManagement/index.vue b/src/views/productionManagement/workOrderManagement/index.vue
index 119bd9e..60fe511 100644
--- a/src/views/productionManagement/workOrderManagement/index.vue
+++ b/src/views/productionManagement/workOrderManagement/index.vue
@@ -673,7 +673,10 @@
       }
     }
     currentReportRowData.value = row;
-    reportForm.planQuantity = row.planQuantity;
+    const planQuantity = Number(row.planQuantity || 0);
+    const completeQuantity = Number(row.completeQuantity || 0);
+    const remainingQuantity = Math.max(0, planQuantity - completeQuantity);
+    reportForm.planQuantity = remainingQuantity;
     reportForm.quantity =
       row.quantity !== undefined && row.quantity !== null ? row.quantity : null;
     reportForm.productProcessRouteItemId = row.productProcessRouteItemId;
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/components/formDia.vue b/src/views/qualityManagement/nonconformingManagement/components/formDia.vue
index 0c6562c..e747d04 100644
--- a/src/views/qualityManagement/nonconformingManagement/components/formDia.vue
+++ b/src/views/qualityManagement/nonconformingManagement/components/formDia.vue
@@ -35,10 +35,10 @@
           </el-col>
           <el-col :span="12">
             <el-form-item label="瑙勬牸鍨嬪彿锛�" prop="model">
-              <el-select v-model="form.model" 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-select>
+              <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-select>
             </el-form-item>
           </el-col>
         </el-row>
@@ -149,7 +149,7 @@
     productId: "",
     model: "",
     unit: "",
-    quantity: "",
+    quantity: undefined,
     checkCompany: "",
     checkResult: "",
     inspectType: '',
@@ -157,6 +157,7 @@
     dealResult: '',
     dealName: '',
     dealTime: '',
+    productModelId: undefined,
   },
   rules: {
     checkTime: [{ required: false, message: "璇疯緭鍏�", trigger: "blur" },],
@@ -199,8 +200,9 @@
       productId: '',
       model: '',
       unit: '',
-      quantity: '',
+      quantity: undefined,
       productName: '',
+      productModelId: undefined,
     };
   } else {
     form.value = {};
@@ -223,6 +225,12 @@
   modelList({ id: value }).then((res) => {
     modelOptions.value = res;
   })
+};
+const handleChangeModel = (value) => {
+  const selectedModel = modelOptions.value.find(item => item.id === value);
+  if (selectedModel) {
+    form.value.model = selectedModel.model;
+  }
 };
 const findNodeById = (nodes, productId) => {
   for (let i = 0; i < nodes.length; i++) {
@@ -285,4 +293,4 @@
 
 <style scoped>
 
-</style>
\ No newline at end of file
+</style>
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 88c1e20..635360f 100644
--- a/src/views/qualityManagement/processInspection/components/formDia.vue
+++ b/src/views/qualityManagement/processInspection/components/formDia.vue
@@ -1,7 +1,7 @@
 <template>
   <div>
     <el-dialog v-model="dialogFormVisible"
-               :title="operationType === 'add' ? '鏂板杩囩▼妫�楠�' : '缂栬緫杩囩▼妫�楠�'"
+               :title="operationType === 'add' ? '鏂板杩囩▼妫�楠�' : operationType === 'view' ? '鏌ョ湅杩囩▼妫�楠�' : '缂栬緫杩囩▼妫�楠�'"
                width="70%"
                @close="closeDia">
       <el-form :model="form"
@@ -16,7 +16,7 @@
               <el-select v-model="form.process"
                          placeholder="璇烽�夋嫨宸ュ簭"
                          clearable
-                         :disabled="processQuantityDisabled"
+                         :disabled="isViewMode || processQuantityDisabled"
                          style="width: 100%">
                 <el-option v-for="item in processList"
                            :key="item.name"
@@ -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>
           </el-col>
@@ -47,7 +47,7 @@
               <el-select v-model="form.productModelId"
                          placeholder="璇烽�夋嫨"
                          clearable
-                         :disabled="operationType === 'edit'"
+                         :disabled="isViewMode || operationType === 'edit'"
                          filterable
                          readonly
                          @change="handleChangeModel">
@@ -65,7 +65,8 @@
                          placeholder="璇烽�夋嫨鎸囨爣"
                          clearable
                          @change="handleTestStandardChange"
-                         style="width: 100%">
+                         style="width: 100%"
+                         :disabled="isViewMode">
                 <el-option v-for="item in testStandardOptions"
                            :key="item.id"
                            :label="item.standardName || item.standardNo"
@@ -93,7 +94,37 @@
                                placeholder="璇疯緭鍏�"
                                clearable
                                :precision="2"
-                               :disabled="processQuantityDisabled" />
+                               :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>
@@ -103,17 +134,20 @@
                           prop="checkCompany">
               <el-input v-model="form.checkCompany"
                         placeholder="璇疯緭鍏�"
-                        clearable />
+                        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>
@@ -124,7 +158,8 @@
                           prop="checkName">
               <el-select v-model="form.checkName"
                          placeholder="璇烽�夋嫨"
-                         clearable>
+                         clearable
+                         :disabled="isViewMode">
                 <el-option v-for="item in userList"
                            :key="item.nickName"
                            :label="item.nickName"
@@ -141,7 +176,8 @@
                               value-format="YYYY-MM-DD"
                               format="YYYY-MM-DD"
                               clearable
-                              style="width: 100%" />
+                              style="width: 100%"
+                              :disabled="isViewMode" />
             </el-form-item>
           </el-col>
         </el-row>
@@ -153,14 +189,18 @@
                 height="400">
         <template #slot="{ row }">
           <el-input v-model="row.testValue"
-                    clearable />
+                    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>
@@ -189,6 +229,7 @@
   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"]);
 
@@ -206,6 +247,8 @@
       testStandardId: "",
       unit: "",
       quantity: "",
+      qualifiedQuantity: "",
+      unqualifiedQuantity: "",
       checkCompany: "",
       checkResult: "",
     },
@@ -215,17 +258,19 @@
       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 userList = ref([]);
   const { form, rules } = toRefs(data);
+  // 鏄惁涓烘煡鐪嬫ā寮�
+  const isViewMode = computed(() => operationType.value === 'view');
   // 缂栬緫鏃讹細productMainId 鎴� purchaseLedgerId 浠讳竴鏈夊�煎垯宸ュ簭銆佹暟閲忕疆鐏�
   const processQuantityDisabled = computed(() => {
     const v = form.value || {};
@@ -299,7 +344,7 @@
     tableData.value = [];
     // 鍏堢‘淇濅骇鍝佹爲宸插姞杞斤紝鍚﹀垯缂栬緫鏃朵骇鍝�/瑙勬牸鍨嬪彿鏃犳硶鍙嶆樉
     await getProductOptions();
-    if (operationType.value === "edit") {
+    if (operationType.value === "edit" || operationType.value === "view") {
       // 鍏堜繚瀛� testStandardId锛岄伩鍏嶈娓呯┖
       const savedTestStandardId = row.testStandardId;
       // 鍏堣缃〃鍗曟暟鎹紝浣嗘殏鏃舵竻绌� testStandardId锛岀瓑閫夐」鍔犺浇瀹屾垚鍚庡啀璁剧疆
@@ -400,6 +445,28 @@
       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) {
@@ -440,6 +507,17 @@
             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 瀛楁浠ュ吋瀹瑰悗绔�
@@ -491,6 +569,10 @@
     getQualityTestStandardParamByTestStandardId(testStandardId)
       .then(res => {
         tableData.value = res.data || [];
+        tableData.value = tableData.value.map(item => ({
+          ...item,
+          id: null
+        }));
       })
       .catch(error => {
         console.error("鑾峰彇鏍囧噯鍙傛暟澶辫触:", error);
@@ -520,4 +602,4 @@
 </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/salesLedger/index.vue b/src/views/salesManagement/salesLedger/index.vue
index e7a73a5..be8a2d7 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
       };
     });
 
@@ -2652,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