From db2e215ffe92af3a6558344b2150cadbab7cfe2c Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期六, 09 五月 2026 17:54:46 +0800
Subject: [PATCH] Merge branch 'dev_NEW_pro' into dev_浪潮

---
 src/views/productionManagement/productionProcess/index.vue                         |    9 
 src/assets/AI/老板助手.png                                                             |    0 
 src/assets/AI/待办助手.png                                                             |    0 
 src/layout/index.vue                                                               |    8 
 src/views/financialManagement/generalLedger/index.vue                              |  527 +-
 multiple/assets/logo/KSLogo.png                                                    |    0 
 src/api/salesManagement/deliveryLedger.js                                          |    9 
 src/views/customerService/expiryAfterSales/components/formDia.vue                  |   92 
 src/views/productionManagement/workOrderManagement/index.vue                       |   35 
 src/views/productionManagement/productionOrder/components/MaterialLedgerDialog.vue |    8 
 src/views/productionManagement/productionTraceability/index.vue                    |   16 
 src/assets/AI/采购助手.png                                                             |    0 
 src/views/inventoryManagement/receiptManagement/Record.vue                         |   13 
 src/api/financialManagement/accountSubject.js                                      |   46 
 src/views/salesManagement/deliveryLedger/index.vue                                 |    6 
 src/views/equipmentManagement/operationManagement/index.vue                        |  132 
 src/assets/AI/生产助手.png                                                             |    0 
 src/assets/aiIndustrialBrain/reference-chat.png                                    |    0 
 src/views/aiIndustrialBrain/index.vue                                              | 1499 ++++++++
 src/assets/AI/财务助手.png                                                             |    0 
 src/router/index.js                                                                |  239 
 src/views/productionManagement/workOrderEdit/index.vue                             |    2 
 multiple/assets/favicon/DZZBfavicon.ico                                            |    0 
 src/views/productionManagement/productionReporting/index.vue                       |    5 
 src/components/AIChatSidebar/assistants/generalAssistant.js                        |   33 
 multiple/assets/favicon/KSfavicon.ico                                              |    0 
 src/views/productionManagement/productionOrder/index.vue                           |    2 
 src/components/PurchaseAIChatSidebar/index.vue                                     |   20 
 src/views/inventoryManagement/stockReport/index.vue                                | 1251 +++---
 src/views/customerService/feedbackRegistration/components/formDia.vue              |  895 ++--
 multiple/config.json                                                               |   20 
 src/components/AIChatSidebar/assistants/purchaseAssistant.js                       |   25 
 src/views/productionManagement/processRoute/processRouteItem/index.vue             |   28 
 src/components/AIChatSidebar/assistants/index.js                                   |    6 
 src/views/salesManagement/salesLedger/index.vue                                    | 3632 +++++++++---------
 src/views/collaborativeApproval/approvalProcess/components/approvalDia.vue         |  852 ++-
 src/views/inventoryManagement/dispatchLog/Record.vue                               |   13 
 multiple/assets/logo/DZZBLogo.png                                                  |    0 
 src/views/procurementManagement/purchaseReturnOrder/index.vue                      |   12 
 src/assets/AI/销售助手.png                                                             |    0 
 src/assets/aiIndustrialBrain/reference-cards.png                                   |    0 
 src/views/productionManagement/productionCosting/index.vue                         |    5 
 src/store/modules/permission.js                                                    |   35 
 src/components/AIChatSidebar/index.vue                                             | 1362 +++++--
 src/views/personnelManagement/dimission/components/formDia.vue                     |   17 
 src/views/customerService/expiryAfterSales/index.vue                               |    6 
 src/views/aiIndustrialBrain/components/AiAssistantWorkspace.vue                    |  192 +
 package.json                                                                       |    3 
 src/views/productionPlan/productionPlan/index.vue                                  |   22 
 49 files changed, 7,007 insertions(+), 4,070 deletions(-)

diff --git a/multiple/assets/favicon/DZZBfavicon.ico b/multiple/assets/favicon/DZZBfavicon.ico
new file mode 100644
index 0000000..63bf216
--- /dev/null
+++ b/multiple/assets/favicon/DZZBfavicon.ico
Binary files differ
diff --git a/multiple/assets/favicon/KSfavicon.ico b/multiple/assets/favicon/KSfavicon.ico
new file mode 100644
index 0000000..57ebd54
--- /dev/null
+++ b/multiple/assets/favicon/KSfavicon.ico
Binary files differ
diff --git a/multiple/assets/logo/DZZBLogo.png b/multiple/assets/logo/DZZBLogo.png
new file mode 100644
index 0000000..5b3f56b
--- /dev/null
+++ b/multiple/assets/logo/DZZBLogo.png
Binary files differ
diff --git a/multiple/assets/logo/KSLogo.png b/multiple/assets/logo/KSLogo.png
new file mode 100644
index 0000000..39d52a0
--- /dev/null
+++ b/multiple/assets/logo/KSLogo.png
Binary files differ
diff --git a/multiple/config.json b/multiple/config.json
index 565ad80..a2586e5 100644
--- a/multiple/config.json
+++ b/multiple/config.json
@@ -24,6 +24,24 @@
     "logo": "logo/SDJCLogo.png",
     "favicon": "favicon/SDJCfavicon.ico"
   },
+  "KS": {
+    "env": {
+      "VITE_APP_TITLE": "榛庡煄搴锋.鍟嗙牸鏈夐檺鍏徃",
+      "VITE_BASE_API": "http://36.138.236.176:9000",
+      "VITE_JAVA_API": "http://36.138.236.176:9001"
+    },
+    "logo": "logo/KSLogo.png",
+    "favicon": "favicon/KSfavicon.ico"
+  },
+  "DZZB": {
+    "env": {
+      "VITE_APP_TITLE": "灞辫タ涓规湵瑁呭鍒堕�犺偂浠芥湁闄愬叕鍙�",
+      "VITE_BASE_API": "http://36.138.236.176:9000",
+      "VITE_JAVA_API": "http://36.138.236.176:9001"
+    },
+    "logo": "logo/DZZBLogo.png",
+    "favicon": "favicon/DZZBfavicon.ico"
+  },
   "logo": "/src/assets/logo/logo.png",
   "favicon": "/public/favicon.ico"
-}
\ No newline at end of file
+}
diff --git a/package.json b/package.json
index e80e1e7..11fa01d 100644
--- a/package.json
+++ b/package.json
@@ -56,5 +56,6 @@
   },
   "overrides": {
     "quill": "2.0.2"
-  }
+  },
+  "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
 }
diff --git a/src/api/financialManagement/accountSubject.js b/src/api/financialManagement/accountSubject.js
new file mode 100644
index 0000000..e54de63
--- /dev/null
+++ b/src/api/financialManagement/accountSubject.js
@@ -0,0 +1,46 @@
+import request from "@/utils/request";
+
+// 鏌ヨ鎬诲笎绉戠洰鍒楄〃
+export function listAccountSubject(query) {
+  return request({
+    url: "/accountSubject/list",
+    method: "get",
+    params: query,
+  });
+}
+
+// 鏂板鎬诲笎绉戠洰
+export function addAccountSubject(data) {
+  return request({
+    url: "/accountSubject/add",
+    method: "post",
+    data: data,
+  });
+}
+
+// 淇敼鎬诲笎绉戠洰
+export function updateAccountSubject(data) {
+  return request({
+    url: "/accountSubject/edit",
+    method: "put",
+    data: data,
+  });
+}
+
+// 鍒犻櫎鎬诲笎绉戠洰
+export function delAccountSubject(ids) {
+  return request({
+    url: "/accountSubject/remove/" + ids,
+    method: "delete",
+  });
+}
+
+// 瀵煎嚭鎬诲笎绉戠洰
+export function exportAccountSubject(data) {
+  return request({
+    url: "/accountSubject/export",
+    method: "post",
+    data: data,
+    responseType: "blob",
+  });
+}
diff --git a/src/api/salesManagement/deliveryLedger.js b/src/api/salesManagement/deliveryLedger.js
index b85582c..bcc47a3 100644
--- a/src/api/salesManagement/deliveryLedger.js
+++ b/src/api/salesManagement/deliveryLedger.js
@@ -17,6 +17,14 @@
     method: "get",
   });
 }
+// 淇敼鍙戣揣鍙拌处
+export function getDeliveryDetailByShippingNo(query) {
+  return request({
+    url: "/shippingInfo/getDateilByShippingNo",
+    method: "get",
+    params: query,
+  });
+}
 
 export function addOrUpdateDeliveryLedger(query) {
   return request({
@@ -51,4 +59,3 @@
     data,
   });
 }
-
diff --git "a/src/assets/AI/\345\276\205\345\212\236\345\212\251\346\211\213.png" "b/src/assets/AI/\345\276\205\345\212\236\345\212\251\346\211\213.png"
new file mode 100644
index 0000000..d8e5e80
--- /dev/null
+++ "b/src/assets/AI/\345\276\205\345\212\236\345\212\251\346\211\213.png"
Binary files differ
diff --git "a/src/assets/AI/\347\224\237\344\272\247\345\212\251\346\211\213.png" "b/src/assets/AI/\347\224\237\344\272\247\345\212\251\346\211\213.png"
new file mode 100644
index 0000000..2d5d3b5
--- /dev/null
+++ "b/src/assets/AI/\347\224\237\344\272\247\345\212\251\346\211\213.png"
Binary files differ
diff --git "a/src/assets/AI/\350\200\201\346\235\277\345\212\251\346\211\213.png" "b/src/assets/AI/\350\200\201\346\235\277\345\212\251\346\211\213.png"
new file mode 100644
index 0000000..1b5030d
--- /dev/null
+++ "b/src/assets/AI/\350\200\201\346\235\277\345\212\251\346\211\213.png"
Binary files differ
diff --git "a/src/assets/AI/\350\264\242\345\212\241\345\212\251\346\211\213.png" "b/src/assets/AI/\350\264\242\345\212\241\345\212\251\346\211\213.png"
new file mode 100644
index 0000000..fd6c90c
--- /dev/null
+++ "b/src/assets/AI/\350\264\242\345\212\241\345\212\251\346\211\213.png"
Binary files differ
diff --git "a/src/assets/AI/\351\207\207\350\264\255\345\212\251\346\211\213.png" "b/src/assets/AI/\351\207\207\350\264\255\345\212\251\346\211\213.png"
new file mode 100644
index 0000000..3eba34a
--- /dev/null
+++ "b/src/assets/AI/\351\207\207\350\264\255\345\212\251\346\211\213.png"
Binary files differ
diff --git "a/src/assets/AI/\351\224\200\345\224\256\345\212\251\346\211\213.png" "b/src/assets/AI/\351\224\200\345\224\256\345\212\251\346\211\213.png"
new file mode 100644
index 0000000..8382efa
--- /dev/null
+++ "b/src/assets/AI/\351\224\200\345\224\256\345\212\251\346\211\213.png"
Binary files differ
diff --git a/src/assets/aiIndustrialBrain/reference-cards.png b/src/assets/aiIndustrialBrain/reference-cards.png
new file mode 100644
index 0000000..72fdb93
--- /dev/null
+++ b/src/assets/aiIndustrialBrain/reference-cards.png
Binary files differ
diff --git a/src/assets/aiIndustrialBrain/reference-chat.png b/src/assets/aiIndustrialBrain/reference-chat.png
new file mode 100644
index 0000000..d026388
--- /dev/null
+++ b/src/assets/aiIndustrialBrain/reference-chat.png
Binary files differ
diff --git a/src/components/AIChatSidebar/assistants/generalAssistant.js b/src/components/AIChatSidebar/assistants/generalAssistant.js
new file mode 100644
index 0000000..b5610e3
--- /dev/null
+++ b/src/components/AIChatSidebar/assistants/generalAssistant.js
@@ -0,0 +1,33 @@
+import { Cpu } from '@element-plus/icons-vue'
+
+export const generalAssistant = {
+  key: 'general',
+  label: '寰呭姙鍔╃悊',
+  title: '寰呭姙鏅鸿兘鍔╃悊',
+  tooltip: '寰呭姙鍔╂墜',
+  icon: Cpu,
+  apiBase: '/xiaozhi',
+  storageKey: 'ai_chat_uuid',
+  placeholder: '璇疯緭鍏ユ偍鐨勯棶棰�... (Enter 鍙戦��, Shift+Enter 鎹㈣)',
+  welcomeMessage: '浣犲ソ',
+  description: '鎴戝彲浠ュ洖绛斾綘鐨勯棶棰橈紝涓轰綘鎻愪緵涓氬姟鏁版嵁瑙h淇℃伅銆佸鐞嗗缓璁拰杈呭姪鍐崇瓥鏀寔銆�',
+  allowFileUpload: true,
+  emptySessionText: '鏆傛棤鍘嗗彶浼氳瘽',
+  quickPrompts: [
+    '鎴戝綋鍓嶆湁鍝簺瀹℃壒寰呭姙闇�瑕佸鐞嗭紵',
+    '甯垜鍒楀嚭浠婂ぉ鏂板鐨勫鎵瑰緟鍔炪��',
+    '褰撳墠寰呮垜瀹℃壒鐨勫崟鎹紝鎸夋椂闂村�掑簭鍒楀嚭鏉ャ��',
+    '鎴戝彂璧风殑瀹℃壒閲岋紝鍝簺杩樺湪澶勭悊涓紵',
+    '鏌ヨ娴佺▼缂栧彿 XXX 鐨勫鎵硅鎯呫��',
+    '娴佺▼缂栧彿 XXX 鐜板湪鍗″湪鍝釜瀹℃壒鑺傜偣锛熷綋鍓嶅鎵逛汉鏄皝锛�',
+    '甯垜鏌ョ湅娴佺▼缂栧彿 XXX 鐨勫鎵规祦杞褰曘��',
+    '杩�7澶╂垜鐨勫鎵瑰緟鍔炵粺璁℃儏鍐垫�庝箞鏍凤紵',
+    '鏈湀鎴戠殑瀹℃壒涓紝閫氳繃銆侀┏鍥炪�佸鐞嗕腑鍚勬湁澶氬皯锛�',
+    '杩�30澶╁悇绫诲瀷瀹℃壒鏁伴噺鍒嗗竷鏄粈涔堬紵',
+    '甯垜瀹℃壒閫氳繃娴佺▼缂栧彿 XXX锛屽娉ㄢ�滃悓鎰忊�濄��',
+    '甯垜椹冲洖娴佺▼缂栧彿 XXX锛屽娉ㄢ�滆琛ュ厖璇存槑鈥濄��',
+    '鎾ら攢鎴戝垰鍒氬娴佺▼缂栧彿 XXX 鐨勫鎵规搷浣溿��',
+    '甯垜淇敼娴佺▼缂栧彿 XXX 鐨勫娉ㄤ负鈥滃凡琛ュ厖闄勪欢鈥濄��',
+    '鍒犻櫎鎴戝彂璧风殑娴佺▼缂栧彿 XXX銆�'
+  ]
+}
diff --git a/src/components/AIChatSidebar/assistants/index.js b/src/components/AIChatSidebar/assistants/index.js
new file mode 100644
index 0000000..61d4752
--- /dev/null
+++ b/src/components/AIChatSidebar/assistants/index.js
@@ -0,0 +1,6 @@
+import { generalAssistant } from './generalAssistant'
+import { purchaseAssistant } from './purchaseAssistant'
+
+export { generalAssistant, purchaseAssistant }
+
+export const builtInAssistants = [generalAssistant, purchaseAssistant]
diff --git a/src/components/AIChatSidebar/assistants/purchaseAssistant.js b/src/components/AIChatSidebar/assistants/purchaseAssistant.js
new file mode 100644
index 0000000..8f0ae0a
--- /dev/null
+++ b/src/components/AIChatSidebar/assistants/purchaseAssistant.js
@@ -0,0 +1,25 @@
+import { ShoppingCart } from '@element-plus/icons-vue'
+
+export const purchaseAssistant = {
+  key: 'purchase',
+  label: '閲囪喘鍔╃悊',
+  title: '閲囪喘鏅鸿兘鍔╃悊',
+  tooltip: '閲囪喘鏅鸿兘鍔╃悊',
+  icon: ShoppingCart,
+  apiBase: '/purchase-ai',
+  storageKey: 'purchase_ai_chat_uuid',
+  placeholder: '璇疯緭鍏ラ噰璐棶棰�... (Enter 鍙戦��, Shift+Enter 鎹㈣)',
+  welcomeMessage: '浣犲ソ',
+  description: '鎴戝彲浠ュ崗鍔╀綘鍒嗘瀽閲囪喘璁㈠崟銆佸埌璐ц繘搴︺�佷緵搴斿晢琛ㄧ幇鍜屼粯娆炬儏鍐碉紝甯姪浣犲揩閫熷畾浣嶉噰璐紓甯搞��',
+  allowFileUpload: true,
+  allowMultipleFileUpload: true,
+  fileAnalyzeUrl: '/purchase-ai/analyze-files',
+  emptySessionText: '鏆傛棤閲囪喘浼氳瘽',
+  quickPrompts: [
+    '鏈湀閲囪喘閲戦鎺掑悕鍓嶅崄鐨勭墿鏂欐湁鍝簺锛�',
+    '鍝簺閲囪喘璁㈠崟杩樻湭鍏ュ簱锛�',
+    '鏈�杩�7澶╀緵搴斿晢鍒拌揣寮傚父鏈夊摢浜涳紵',
+    '甯垜缁熻寰呬粯娆鹃噰璐崟',
+    '鍒楀嚭鏈湀閲囪喘閫�璐ф儏鍐�'
+  ]
+}
diff --git a/src/components/AIChatSidebar/index.vue b/src/components/AIChatSidebar/index.vue
index 369d75d..5d81355 100644
--- a/src/components/AIChatSidebar/index.vue
+++ b/src/components/AIChatSidebar/index.vue
@@ -1,7 +1,7 @@
 <template>
   <div class="ai-chat-sidebar-wrapper">
     <!-- 鎮诞鍥炬爣 -->
-    <div class="ai-chat-trigger" @click="toggleSidebar" v-show="!visible">
+    <div v-if="!hideTrigger" class="ai-chat-trigger" @click="toggleSidebar" v-show="!visible">
       <el-tooltip :content="currentAssistant.tooltip" placement="left">
         <div class="trigger-icon">
           <el-icon :size="30" color="#fff"><component :is="currentAssistant.icon" /></el-icon>
@@ -12,14 +12,16 @@
     <!-- 渚ц竟鏍忓璇濇 -->
     <el-drawer
         v-model="visible"
-        :size="drawerSize"
-        direction="rtl"
+        :size="computedDrawerSize"
+        :direction="drawerDirection"
         :with-header="true"
         class="ai-chat-drawer"
         :modal="false"
         modal-class="ai-chat-overlay"
         :show-close="false"
         :append-to-body="false"
+        :close-on-press-escape="!hideTrigger"
+        :close-on-click-modal="!hideTrigger"
         @close="handleClose"
     >
       <template #header>
@@ -50,8 +52,16 @@
                 <el-icon :size="18"><Plus /></el-icon>
               </el-button>
             </el-tooltip>
-            <div class="action-divider"></div>
-            <el-tooltip content="鍏抽棴" placement="bottom">
+            <el-button
+                v-if="headerExtraActionText"
+                link
+                class="header-action-btn header-action-btn--text"
+                @click="handleHeaderExtraAction"
+            >
+              {{ headerExtraActionText }}
+            </el-button>
+            <div v-if="!hideTrigger" class="action-divider"></div>
+            <el-tooltip v-if="!hideTrigger" content="鍏抽棴" placement="bottom">
               <el-button link class="header-action-btn close-btn" @click="handleManualClose">
                 <el-icon :size="18"><Close /></el-icon>
               </el-button>
@@ -105,23 +115,17 @@
               <div class="assistant-scan-ring"></div>
               <div class="assistant-orbit assistant-orbit-a"></div>
               <div class="assistant-orbit assistant-orbit-b"></div>
-              <div class="assistant-bot">
-                <div class="assistant-bot-antenna assistant-bot-antenna-left"></div>
-                <div class="assistant-bot-antenna assistant-bot-antenna-right"></div>
-                <div class="assistant-bot-head">
-                  <div class="assistant-bot-head-glow"></div>
-                  <div class="assistant-bot-eye assistant-bot-eye-left"></div>
-                  <div class="assistant-bot-eye assistant-bot-eye-right"></div>
-                  <div class="assistant-bot-mouth"></div>
-                </div>
-                <div class="assistant-bot-neck"></div>
-                <div class="assistant-bot-body">
-                  <div class="assistant-bot-core">
-                    <div class="assistant-bot-core-ring"></div>
-                    <el-icon :size="22"><component :is="currentAssistant.icon" /></el-icon>
+              <div class="assistant-model-shell">
+                <div class="assistant-model-cut">
+                  <img
+                      v-if="currentAssistantAvatar"
+                      class="assistant-model-img"
+                      :src="currentAssistantAvatar"
+                      :alt="currentAssistant.label"
+                  />
+                  <div v-else class="assistant-model-fallback">
+                    <el-icon :size="30"><component :is="currentAssistant.icon" /></el-icon>
                   </div>
-                  <div class="assistant-bot-arm assistant-bot-arm-left"></div>
-                  <div class="assistant-bot-arm assistant-bot-arm-right"></div>
                 </div>
               </div>
               <div class="assistant-status">
@@ -169,10 +173,6 @@
             </div>
           </div>
 
-          <div v-show="!hasMessages" class="hero-dot-grid" aria-hidden="true">
-            <span v-for="dot in 28" :key="dot"></span>
-          </div>
-
           <div class="message-list" ref="messageListRef">
             <div
                 v-for="(message, index) in messages"
@@ -186,6 +186,37 @@
               <div class="message-content">
                 <!-- 鏂囨湰鍐呭 -->
                 <div class="text-box" v-html="message.htmlContent"></div>
+
+                <div v-if="message.localUploadFiles?.length" class="message-local-file-list">
+                  <div
+                      v-for="(file, fileIndex) in message.localUploadFiles"
+                      :key="`${file.previewId || file.name}-${fileIndex}`"
+                      :class="['message-local-file-item', { clickable: !!file.accessUrl && !file.isImage }]"
+                      @click="handleMessageFileClick(file)"
+                  >
+                    <el-image
+                        v-if="file.isImage && file.previewUrl"
+                        :src="file.previewUrl"
+                        :preview-src-list="getImagePreviewList(message.localUploadFiles)"
+                        :initial-index="getImagePreviewInitialIndex(message.localUploadFiles, file.previewUrl)"
+                        :z-index="4000"
+                        preview-teleported
+                        fit="cover"
+                        class="message-local-file-thumb"
+                    />
+                    <el-icon v-else class="message-local-file-icon"><Document /></el-icon>
+                    <div class="message-local-file-meta">
+                      <span
+                          :class="['message-local-file-name', { clickable: !!file.accessUrl }]"
+                          :title="file.name"
+                          @click.stop="openMessageAttachment(file)"
+                      >
+                        {{ file.name }}
+                      </span>
+                      <small v-if="Number(file.size) > 0" class="message-local-file-size">{{ formatFileSize(file.size) }}</small>
+                    </div>
+                  </div>
+                </div>
 
                 <!-- 鍥捐〃鍐呭 -->
                 <div v-if="message.chartOptions && message.chartRenderReady" class="charts-wrapper">
@@ -443,9 +474,22 @@
             </div>
             <div class="input-box">
               <div v-if="selectedFiles.length" class="selected-file-list">
-                <div v-for="(file, fileIndex) in selectedFiles" :key="`${file.name}-${fileIndex}`" class="selected-file-tag">
-                  <el-icon><Document /></el-icon>
-                  <span class="file-name">{{ file.name }}</span>
+                <div v-for="(file, fileIndex) in selectedFileSnapshots" :key="`${file.previewId || file.name}-${fileIndex}`" class="selected-file-tag">
+                  <el-image
+                      v-if="file.isImage && file.previewUrl"
+                      :src="file.previewUrl"
+                      :preview-src-list="getImagePreviewList(selectedFileSnapshots)"
+                      :initial-index="getImagePreviewInitialIndex(selectedFileSnapshots, file.previewUrl)"
+                      :z-index="4000"
+                      preview-teleported
+                      fit="cover"
+                      class="selected-file-thumb"
+                  />
+                  <el-icon v-else><Document /></el-icon>
+                  <div class="selected-file-meta">
+                    <span class="file-name">{{ file.name }}</span>
+                    <small class="file-size">{{ formatFileSize(file.size) }}</small>
+                  </div>
                   <el-icon class="remove-file" @click="removeSelectedFile(fileIndex)"><Close /></el-icon>
                 </div>
               </div>
@@ -478,8 +522,17 @@
 import { ref, onMounted, onUnmounted, nextTick, watch, computed } from 'vue'
 import request from '@/utils/request'
 import * as echarts from 'echarts'
-import { Cpu, User, Plus, Timer, Delete, ChatDotSquare, VideoPause, Upload, Document, Close, ShoppingCart, Promotion, RefreshRight } from '@element-plus/icons-vue'
+import { Cpu, User, Plus, Timer, Delete, ChatDotSquare, VideoPause, Upload, Document, Close, Promotion, RefreshRight } from '@element-plus/icons-vue'
 import { ElMessage } from 'element-plus'
+import { builtInAssistants, generalAssistant } from './assistants'
+import todoAssistantAvatar from '@/assets/AI/寰呭姙鍔╂墜.png'
+import salesAssistantAvatar from '@/assets/AI/閿�鍞姪鎵�.png'
+import purchaseAssistantAvatar from '@/assets/AI/閲囪喘鍔╂墜.png'
+import productionAssistantAvatar from '@/assets/AI/鐢熶骇鍔╂墜.png'
+import financeAssistantAvatar from '@/assets/AI/璐㈠姟鍔╂墜.png'
+import bossAssistantAvatar from '@/assets/AI/鑰佹澘鍔╂墜.png'
+
+const emit = defineEmits(['header-extra-action'])
 
 const props = defineProps({
   assistants: {
@@ -489,72 +542,51 @@
   defaultAssistant: {
     type: String,
     default: ''
+  },
+  hideTrigger: {
+    type: Boolean,
+    default: false
+  },
+  autoOpen: {
+    type: Boolean,
+    default: false
+  },
+  drawerSize: {
+    type: [String, Number],
+    default: ''
+  },
+  drawerDirection: {
+    type: String,
+    default: 'rtl'
+  },
+  headerExtraActionText: {
+    type: String,
+    default: ''
   }
 })
 
-const builtInAssistants = [
-  {
-    key: 'general',
-    label: '寰呭姙鍔╃悊',
-    title: '寰呭姙鏅鸿兘鍔╃悊',
-    tooltip: '寰呭姙鍔╂墜',
-    icon: Cpu,
-    apiBase: '/xiaozhi',
-    storageKey: 'ai_chat_uuid',
-    placeholder: '璇疯緭鍏ユ偍鐨勯棶棰�... (Enter 鍙戦��, Shift+Enter 鎹㈣)',
-    welcomeMessage: '浣犲ソ',
-    description: '鎴戝彲浠ュ洖绛斾綘鐨勯棶棰橈紝涓轰綘鎻愪緵涓氬姟鏁版嵁瑙h淇℃伅銆佸鐞嗗缓璁拰杈呭姪鍐崇瓥鏀寔銆�',
-    allowFileUpload: true,
-    emptySessionText: '鏆傛棤鍘嗗彶浼氳瘽'
-  },
-  {
-    key: 'purchase',
-    label: '閲囪喘鍔╃悊',
-    title: '閲囪喘鏅鸿兘鍔╃悊',
-    tooltip: '閲囪喘鏅鸿兘鍔╃悊',
-    icon: ShoppingCart,
-    apiBase: '/purchase-ai',
-    storageKey: 'purchase_ai_chat_uuid',
-    placeholder: '璇疯緭鍏ラ噰璐棶棰�... (Enter 鍙戦��, Shift+Enter 鎹㈣)',
-    welcomeMessage: '浣犲ソ',
-    description: '鎴戝彲浠ュ崗鍔╀綘鍒嗘瀽閲囪喘璁㈠崟銆佸埌璐ц繘搴︺�佷緵搴斿晢琛ㄧ幇鍜屼粯娆炬儏鍐碉紝甯姪浣犲揩閫熷畾浣嶉噰璐紓甯搞��',
-    allowFileUpload: true,
-    allowMultipleFileUpload: true,
-    fileAnalyzeUrl: '/purchase-ai/analyze-files',
-    emptySessionText: '鏆傛棤閲囪喘浼氳瘽'
-  }
-]
-
+const hideTrigger = computed(() => props.hideTrigger)
+const headerExtraActionText = computed(() => String(props.headerExtraActionText || '').trim())
+const drawerDirection = computed(() => (props.drawerDirection === 'ttb' || props.drawerDirection === 'btt' || props.drawerDirection === 'ltr' || props.drawerDirection === 'rtl')
+  ? props.drawerDirection
+  : 'rtl')
 const assistants = computed(() => props.assistants?.length ? props.assistants : builtInAssistants)
 const selectedAssistantKey = ref(props.defaultAssistant || assistants.value[0]?.key || 'general')
 const currentAssistant = computed(() => assistants.value.find(item => item.key === selectedAssistantKey.value) || assistants.value[0] || builtInAssistants[0])
-const showAssistantSwitch = computed(() => assistants.value.length > 1)
-const assistantQuickPromptMap = {
-  general: [
-    '鎴戝綋鍓嶆湁鍝簺瀹℃壒寰呭姙闇�瑕佸鐞嗭紵',
-    '甯垜鍒楀嚭浠婂ぉ鏂板鐨勫鎵瑰緟鍔炪��',
-    '褰撳墠寰呮垜瀹℃壒鐨勫崟鎹紝鎸夋椂闂村�掑簭鍒楀嚭鏉ャ��',
-    '鎴戝彂璧风殑瀹℃壒閲岋紝鍝簺杩樺湪澶勭悊涓紵',
-    '鏌ヨ娴佺▼缂栧彿 XXX 鐨勫鎵硅鎯呫��',
-    '娴佺▼缂栧彿 XXX 鐜板湪鍗″湪鍝釜瀹℃壒鑺傜偣锛熷綋鍓嶅鎵逛汉鏄皝锛�',
-    '甯垜鏌ョ湅娴佺▼缂栧彿 XXX 鐨勫鎵规祦杞褰曘��',
-    '杩�7澶╂垜鐨勫鎵瑰緟鍔炵粺璁℃儏鍐垫�庝箞鏍凤紵',
-    '鏈湀鎴戠殑瀹℃壒涓紝閫氳繃銆侀┏鍥炪�佸鐞嗕腑鍚勬湁澶氬皯锛�',
-    '杩�30澶╁悇绫诲瀷瀹℃壒鏁伴噺鍒嗗竷鏄粈涔堬紵',
-    '甯垜瀹℃壒閫氳繃娴佺▼缂栧彿 XXX锛屽娉ㄢ�滃悓鎰忊�濄��',
-    '甯垜椹冲洖娴佺▼缂栧彿 XXX锛屽娉ㄢ�滆琛ュ厖璇存槑鈥濄��',
-    '鎾ら攢鎴戝垰鍒氬娴佺▼缂栧彿 XXX 鐨勫鎵规搷浣溿��',
-    '甯垜淇敼娴佺▼缂栧彿 XXX 鐨勫娉ㄤ负鈥滃凡琛ュ厖闄勪欢鈥濄��',
-    '鍒犻櫎鎴戝彂璧风殑娴佺▼缂栧彿 XXX銆�'
-  ],
-  purchase: [
-    '鏈湀閲囪喘閲戦鎺掑悕鍓嶅崄鐨勭墿鏂欐湁鍝簺锛�',
-    '鍝簺閲囪喘璁㈠崟杩樻湭鍏ュ簱锛�',
-    '鏈�杩�7澶╀緵搴斿晢鍒拌揣寮傚父鏈夊摢浜涳紵',
-    '甯垜缁熻寰呬粯娆鹃噰璐崟',
-    '鍒楀嚭鏈湀閲囪喘閫�璐ф儏鍐�'
-  ]
+const assistantAvatarByKey = {
+  general: todoAssistantAvatar,
+  todo: todoAssistantAvatar,
+  purchase: purchaseAssistantAvatar,
+  sales: salesAssistantAvatar,
+  production: productionAssistantAvatar,
+  finance: financeAssistantAvatar,
+  boss: bossAssistantAvatar
 }
+const currentAssistantAvatar = computed(() => {
+  const assistant = currentAssistant.value || {}
+  return assistant.avatar || assistantAvatarByKey[assistant.key] || ''
+})
+const showAssistantSwitch = computed(() => assistants.value.length > 1)
 const quickPromptLimit = 3
 const quickPromptStart = ref(0)
 const quickPrompts = computed(() => {
@@ -562,7 +594,7 @@
   if (Array.isArray(assistant.quickPrompts) && assistant.quickPrompts.length) {
     return assistant.quickPrompts
   }
-  return assistantQuickPromptMap[assistant.key] || assistantQuickPromptMap.general
+  return generalAssistant.quickPrompts || []
 })
 const displayedQuickPrompts = computed(() => {
   const prompts = quickPrompts.value || []
@@ -578,17 +610,19 @@
 
 const visible = ref(false)
 const windowWidth = ref(window.innerWidth)
-const drawerSize = computed(() => {
+const responsiveDrawerSize = computed(() => {
   if (windowWidth.value < 768) return '100%'
   if (windowWidth.value < 1200) return '50%'
   return '50%'
 })
+const computedDrawerSize = computed(() => props.drawerSize || responsiveDrawerSize.value)
 const messageListRef = ref(null)
 const isSending = ref(false)
 const currentAbortController = ref(null)
 const inputMessage = ref('')
 const selectedFiles = ref([])
 const uploadFileList = ref([])
+const selectedFileSnapshots = ref([])
 const messages = ref([])
 const uuid = ref('')
 const chartInstances = ref({})
@@ -792,6 +826,142 @@
 const sessions = ref([])
 const loadingSessions = ref(false)
 
+const isImageFileType = (fileType = '') => String(fileType || '').toLowerCase().startsWith('image/')
+const imageFilePathPattern = /\.(png|jpe?g|gif|webp|bmp|svg)$/i
+
+const getPathnameFromFilePath = (filePath = '') => {
+  const rawPath = String(filePath || '').trim()
+  if (!rawPath) return ''
+  try {
+    const baseOrigin = typeof window !== 'undefined' ? window.location.origin : 'http://localhost'
+    return new URL(rawPath, baseOrigin).pathname || ''
+  } catch (err) {
+    return rawPath.split('?')[0]
+  }
+}
+
+const isImageFilePath = (filePath = '') => {
+  const pathname = getPathnameFromFilePath(filePath).toLowerCase()
+  return imageFilePathPattern.test(pathname)
+}
+
+const getHistoryFileName = (filePath = '', index = 0) => {
+  const pathname = getPathnameFromFilePath(filePath)
+  const fileName = pathname.split('/').filter(Boolean).pop()
+  if (!fileName) return `file-${index + 1}`
+  try {
+    return decodeURIComponent(fileName)
+  } catch (err) {
+    return fileName
+  }
+}
+
+const getImagePreviewList = (files = []) => {
+  if (!Array.isArray(files)) return []
+  return files
+    .filter(item => item?.isImage && item?.previewUrl)
+    .map(item => item.previewUrl)
+}
+
+const getImagePreviewInitialIndex = (files = [], previewUrl = '') => {
+  const list = getImagePreviewList(files)
+  const index = list.indexOf(previewUrl)
+  return index >= 0 ? index : 0
+}
+
+const formatFileSize = (size) => {
+  const bytes = Number(size)
+  if (!Number.isFinite(bytes) || bytes <= 0) return '0 B'
+  if (bytes < 1024) return `${bytes} B`
+  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1).replace(/\.0$/, '')} KB`
+  return `${(bytes / (1024 * 1024)).toFixed(1).replace(/\.0$/, '')} MB`
+}
+
+const createLocalFileSnapshot = (file, index = 0) => {
+  const rawFile = typeof File !== 'undefined' && file instanceof File ? file : null
+  const fileType = rawFile?.type || ''
+  const isImage = isImageFileType(fileType)
+  const canCreateObjectURL = typeof URL !== 'undefined' && typeof URL.createObjectURL === 'function'
+  const previewUrl = isImage && rawFile && canCreateObjectURL ? URL.createObjectURL(rawFile) : ''
+  return {
+    previewId: `${rawFile?.name || 'file'}-${rawFile?.size || 0}-${rawFile?.lastModified || Date.now()}-${index}`,
+    name: rawFile?.name || `file-${index + 1}`,
+    size: rawFile?.size || 0,
+    type: fileType,
+    isImage,
+    previewUrl,
+    accessUrl: '',
+    rawFile,
+    isObjectUrl: !!previewUrl
+  }
+}
+
+const createHistoryFileSnapshot = (filePath, memoryId = '', messageIndex = 0, fileIndex = 0) => {
+  const normalizedPath = String(filePath || '').trim()
+  if (!normalizedPath) return null
+  const isImage = isImageFilePath(normalizedPath)
+  return {
+    previewId: `${memoryId || 'history'}-${messageIndex}-${fileIndex}`,
+    name: getHistoryFileName(normalizedPath, fileIndex),
+    size: 0,
+    type: '',
+    isImage,
+    previewUrl: isImage ? normalizedPath : '',
+    accessUrl: normalizedPath,
+    rawFile: null,
+    isObjectUrl: false
+  }
+}
+
+const revokeLocalFileSnapshots = (snapshots = []) => {
+  const canRevokeObjectURL = typeof URL !== 'undefined' && typeof URL.revokeObjectURL === 'function'
+  if (!canRevokeObjectURL) return
+  if (!Array.isArray(snapshots)) return
+  snapshots.forEach((snapshot) => {
+    if (snapshot?.isObjectUrl && snapshot?.previewUrl) {
+      URL.revokeObjectURL(snapshot.previewUrl)
+    }
+  })
+}
+
+const mapHistoryFilePathsToSnapshots = (filePaths = [], memoryId = '', messageIndex = 0) => {
+  if (!Array.isArray(filePaths)) return []
+  return filePaths
+    .map((filePath, fileIndex) => createHistoryFileSnapshot(filePath, memoryId, messageIndex, fileIndex))
+    .filter(Boolean)
+}
+
+const openMessageAttachment = (file) => {
+  const accessUrl = String(file?.accessUrl || '').trim()
+  if (!accessUrl) return
+  if (typeof window === 'undefined' || typeof window.open !== 'function') return
+  window.open(accessUrl, '_blank', 'noopener,noreferrer')
+}
+
+const handleMessageFileClick = (file) => {
+  if (!file?.accessUrl || file?.isImage) return
+  openMessageAttachment(file)
+}
+
+const revokeMessageLocalFileSnapshots = (messageList = []) => {
+  if (!Array.isArray(messageList)) return
+  messageList.forEach((msg) => {
+    if (Array.isArray(msg?.localUploadFiles)) {
+      revokeLocalFileSnapshots(msg.localUploadFiles)
+      msg.localUploadFiles = []
+    }
+  })
+}
+
+const clearSelectedFiles = ({ releaseSnapshots = true } = {}) => {
+  if (releaseSnapshots) {
+    revokeLocalFileSnapshots(selectedFileSnapshots.value)
+  }
+  selectedFiles.value = []
+  uploadFileList.value = []
+  selectedFileSnapshots.value = []
+}
+
 const abortCurrentRequest = () => {
   if (!currentAbortController.value) return
 
@@ -835,6 +1005,7 @@
 
 const selectSession = async (session) => {
   showHistory.value = false
+  clearSelectedFiles()
   uuid.value = session.memoryId
   localStorage.setItem(currentAssistant.value.storageKey, uuid.value)
 
@@ -842,6 +1013,7 @@
   try {
     const res = await request.get(`${currentAssistant.value.apiBase}/history/messages/${uuid.value}`)
     if (res.code === 200) {
+      revokeMessageLocalFileSnapshots(messages.value)
       disposeCharts()
       messages.value = []
       const historyMsgs = res.data || []
@@ -853,7 +1025,7 @@
 
         const messageObj = {
           isUser,
-          content: msg.content,
+          content: msg.content || '',
           htmlContent: '',
           isTyping: false,
           chartOptions: null,
@@ -861,7 +1033,8 @@
           type: '',
           tableData: null,
           payloadTreeData: null,
-          payloadHiddenData: null
+          payloadHiddenData: null,
+          localUploadFiles: isUser ? mapHistoryFilePathsToSnapshots(msg.filePaths, uuid.value, idx) : []
         }
 
         messages.value.push(messageObj)
@@ -876,15 +1049,15 @@
           }
 
           // 瑙f瀽鍘嗗彶娑堟伅涓殑 JSON
-          const extracted = extractEmbeddedSuccessJson(msg.content)
+          const extracted = extractEmbeddedSuccessJson(msg.content || '')
           if (extracted) {
             applyStructuredMessageData(messageObj, extracted.data, botMsgIndex)
           }
 
-          updateOutputState(msg.content, botMsgIndex)
-          messageObj.htmlContent = convertStreamOutput(msg.content, botMsgIndex)
+          updateOutputState(msg.content || '', botMsgIndex)
+          messageObj.htmlContent = convertStreamOutput(msg.content || '', botMsgIndex)
         } else {
-          messageObj.htmlContent = convertTextToHtml(msg.content)
+          messageObj.htmlContent = convertTextToHtml(msg.content || '')
         }
       })
       scrollToBottom()
@@ -919,15 +1092,16 @@
 }
 
 onMounted(() => {
-  initUUID()
-  // 鍒濆娆㈣繋
-  if (messages.value.length === 0) {
-    hello()
+  if (props.autoOpen) {
+    visible.value = true
   }
+  initUUID()
   window.addEventListener('resize', handleWindowResize)
 })
 
 onUnmounted(() => {
+  revokeMessageLocalFileSnapshots(messages.value)
+  clearSelectedFiles()
   disposeCharts()
   window.removeEventListener('resize', handleWindowResize)
 })
@@ -936,21 +1110,36 @@
   if (!prevKey || nextKey === prevKey) return
 
   abortCurrentRequest()
+  revokeMessageLocalFileSnapshots(messages.value)
   disposeCharts()
   messages.value = []
   outputState.value = {}
   sessions.value = []
   showHistory.value = false
-  selectedFiles.value = []
-  uploadFileList.value = []
+  clearSelectedFiles()
   inputMessage.value = ''
   quickPromptStart.value = 0
   initUUID()
-  hello()
+})
+
+watch(() => props.defaultAssistant, (nextKey) => {
+  if (!nextKey || nextKey === selectedAssistantKey.value) return
+  if (!assistants.value.some(item => item.key === nextKey)) return
+  selectedAssistantKey.value = nextKey
+})
+
+watch(() => props.autoOpen, (nextValue) => {
+  if (nextValue) {
+    visible.value = true
+  }
 })
 
 const handleWindowResize = () => {
   windowWidth.value = window.innerWidth
+}
+
+const handleHeaderExtraAction = () => {
+  emit('header-extra-action')
 }
 
 const toggleSidebar = () => {
@@ -961,10 +1150,12 @@
 }
 
 const handleClose = () => {
+  if (hideTrigger.value) return
   visible.value = false
 }
 
 const handleManualClose = () => {
+  if (hideTrigger.value) return
   if (isSending.value) {
     abortCurrentRequest()
   }
@@ -980,22 +1171,17 @@
   uuid.value = storedUUID
 }
 
-const hello = () => {
-  sendRequest(currentAssistant.value.welcomeMessage || '浣犲ソ')
-}
-
 const newChat = () => {
+  revokeMessageLocalFileSnapshots(messages.value)
   disposeCharts()
   messages.value = []
   outputState.value = {}
   sessions.value = []
   showHistory.value = false
-  selectedFiles.value = []
-  uploadFileList.value = []
+  clearSelectedFiles()
   quickPromptStart.value = 0
   localStorage.removeItem(currentAssistant.value.storageKey)
   initUUID()
-  hello()
 }
 
 const handleNewChat = () => {
@@ -1667,6 +1853,76 @@
   '瀹℃壒鐢ㄦ埛ID鍒楄〃'
 ])
 
+const purchaseIntegerFieldKeys = new Set([
+  'id',
+  'supplierId',
+  'recorderId',
+  'salesContractNoId',
+  'salesLedgerId',
+  'Type',
+  'businessPersonId',
+  'productId',
+  'productModelId',
+  'ticketRegistrationId',
+  'type',
+  'approvalStatus',
+  'inventoryWarningQuantity'
+])
+
+const purchaseDecimalFieldKeys = new Set([
+  'invoiceAmount',
+  'contractAmount',
+  'receiptPaymentAmount',
+  'unReceiptPaymentAmount',
+  'quantity',
+  'taxRate',
+  'taxInclusiveUnitPrice',
+  'taxInclusiveTotalPrice',
+  'taxExclusiveTotalPrice',
+  'priceWithTax',
+  'totalPriceWithTax'
+])
+
+const purchaseBooleanFieldKeys = new Set([
+  'hasChildren',
+  'isWhite',
+  'isInspected',
+  'isChecked'
+])
+
+const purchaseStringFieldKeys = new Set([
+  'entryDateStart',
+  'entryDateEnd',
+  'purchaseContractNumber',
+  'supplierName',
+  'recorderName',
+  'salesContractNo',
+  'projectName',
+  'entryDate',
+  'executionDate',
+  'remarks',
+  'attachmentMaterials',
+  'createdAt',
+  'updatedAt',
+  'phoneNumber',
+  'invoiceNumber',
+  'paymentMethod',
+  'templateName',
+  'productCategory',
+  'specificationModel',
+  'unit',
+  'invoiceType'
+])
+
+const purchaseGenericArrayFieldKeys = new Set([
+  'purchaseLedgers',
+  'productData'
+])
+
+const purchaseStringArrayFieldKeys = new Set(['tempFileIds'])
+
+const purchaseObjectArrayFieldKeys = new Set(['SalesLedgerFiles'])
+
 const normalizePurchaseProductRecord = (record) => {
   if (!record || typeof record !== 'object' || Array.isArray(record)) return record
   return mapPayloadKeys(record, purchasePayloadFieldKeyMap)
@@ -1746,10 +2002,191 @@
   }, {})
 }
 
+const normalizeAttachmentMaterialsValue = (value) => {
+  if (value === null || value === undefined) return value
+  if (typeof value === 'string') return value
+  if (typeof value === 'number' || typeof value === 'boolean') return String(value)
+  try {
+    return JSON.stringify(value)
+  } catch (err) {
+    return String(value)
+  }
+}
+
+const normalizePurchaseAttachmentMaterialsField = (value) => {
+  if (Array.isArray(value)) {
+    return value.map(item => normalizePurchaseAttachmentMaterialsField(item))
+  }
+  if (value && typeof value === 'object') {
+    return Object.entries(value).reduce((result, [key, item]) => {
+      if (key === 'attachmentMaterials') {
+        result[key] = normalizeAttachmentMaterialsValue(item)
+      } else {
+        result[key] = normalizePurchaseAttachmentMaterialsField(item)
+      }
+      return result
+    }, {})
+  }
+  return value
+}
+
+const normalizePurchaseNumericText = (text = '') => {
+  return String(text)
+    .replace(/[,\s锛宂/g, '')
+    .replace(/[楼锟ュ厓%]/g, '')
+}
+
+const parsePurchaseNumberValue = (value) => {
+  if (typeof value === 'number') {
+    return Number.isFinite(value) ? value : null
+  }
+  if (typeof value === 'boolean') {
+    return value ? 1 : 0
+  }
+  if (typeof value !== 'string') {
+    return null
+  }
+  const text = normalizePurchaseNumericText(value.trim())
+  if (!text) return null
+  if (!/^[-+]?\d+(\.\d+)?$/.test(text)) return null
+  const numberValue = Number(text)
+  return Number.isFinite(numberValue) ? numberValue : null
+}
+
+const normalizePurchaseIntegerFieldValue = (value) => {
+  if (value === null || value === undefined) return value
+  if (value === '') return null
+  const numberValue = parsePurchaseNumberValue(value)
+  if (numberValue === null) return null
+  return Math.trunc(numberValue)
+}
+
+const normalizePurchaseDecimalFieldValue = (value) => {
+  if (value === null || value === undefined) return value
+  if (value === '') return null
+  const numberValue = parsePurchaseNumberValue(value)
+  return numberValue === null ? null : numberValue
+}
+
+const normalizePurchaseBooleanFieldValue = (value) => {
+  if (value === null || value === undefined) return value
+  if (value === '') return null
+  if (typeof value === 'boolean') return value
+  if (typeof value === 'number') return value !== 0
+  if (typeof value !== 'string') return null
+
+  const text = value.trim().toLowerCase()
+  if (!text) return null
+  if (['true', '1', 'yes', 'y', '鏄�', '宸�', 'checked'].includes(text)) return true
+  if (['false', '0', 'no', 'n', '鍚�', '鏈�', 'unchecked'].includes(text)) return false
+  return null
+}
+
+const normalizePurchaseStringFieldValue = (value) => {
+  if (value === null || value === undefined) return value
+  if (typeof value === 'string') return value
+  if (typeof value === 'number' || typeof value === 'boolean') return String(value)
+  try {
+    return JSON.stringify(value)
+  } catch (err) {
+    return String(value)
+  }
+}
+
+const normalizePurchaseStringArrayFieldValue = (value) => {
+  if (Array.isArray(value)) {
+    return value
+      .map(item => normalizePurchaseStringFieldValue(item))
+      .filter(item => item !== null && item !== undefined && item !== '')
+  }
+  if (value === null || value === undefined || value === '') return []
+  if (typeof value === 'string') {
+    const text = value.trim()
+    if (!text) return []
+    if (/^\[.*\]$/.test(text)) {
+      try {
+        const parsedValue = JSON.parse(text)
+        if (Array.isArray(parsedValue)) {
+          return parsedValue
+            .map(item => normalizePurchaseStringFieldValue(item))
+            .filter(item => item !== null && item !== undefined && item !== '')
+        }
+      } catch (err) {
+        // Keep as plain text when not valid JSON array.
+      }
+    }
+    const splitValues = text
+      .split(/[,\n锛宂/)
+      .map(item => item.trim())
+      .filter(Boolean)
+    return splitValues.length > 1 ? splitValues : [text]
+  }
+  const normalizedValue = normalizePurchaseStringFieldValue(value)
+  return normalizedValue === null || normalizedValue === undefined || normalizedValue === ''
+    ? []
+    : [normalizedValue]
+}
+
+const normalizePurchaseObjectArrayFieldValue = (value) => {
+  if (Array.isArray(value)) {
+    return value.filter(item => item && typeof item === 'object')
+  }
+  if (value && typeof value === 'object') {
+    return [value]
+  }
+  return []
+}
+
+const normalizePurchaseValueByFieldKey = (fieldKey, value) => {
+  if (fieldKey === 'attachmentMaterials') return normalizeAttachmentMaterialsValue(value)
+  if (purchaseIntegerFieldKeys.has(fieldKey)) return normalizePurchaseIntegerFieldValue(value)
+  if (purchaseDecimalFieldKeys.has(fieldKey)) return normalizePurchaseDecimalFieldValue(value)
+  if (purchaseBooleanFieldKeys.has(fieldKey)) return normalizePurchaseBooleanFieldValue(value)
+  if (purchaseStringArrayFieldKeys.has(fieldKey)) return normalizePurchaseStringArrayFieldValue(value)
+  if (purchaseObjectArrayFieldKeys.has(fieldKey)) return normalizePurchaseObjectArrayFieldValue(value)
+  if (purchaseStringFieldKeys.has(fieldKey)) return normalizePurchaseStringFieldValue(value)
+  return value
+}
+
+const normalizePurchasePayloadFieldTypes = (value, fieldKey = '') => {
+  if (purchaseGenericArrayFieldKeys.has(fieldKey)) {
+    if (Array.isArray(value)) {
+      return value.map(item => normalizePurchasePayloadFieldTypes(item))
+    }
+    if (value && typeof value === 'object') {
+      return [normalizePurchasePayloadFieldTypes(value)]
+    }
+    return []
+  }
+
+  if (purchaseStringArrayFieldKeys.has(fieldKey)) {
+    return normalizePurchaseStringArrayFieldValue(value)
+  }
+
+  if (purchaseObjectArrayFieldKeys.has(fieldKey)) {
+    return normalizePurchaseObjectArrayFieldValue(value)
+  }
+
+  if (Array.isArray(value)) {
+    return value.map(item => normalizePurchasePayloadFieldTypes(item))
+  }
+
+  if (value && typeof value === 'object') {
+    return Object.entries(value).reduce((result, [key, item]) => {
+      result[key] = normalizePurchasePayloadFieldTypes(item, key)
+      return result
+    }, {})
+  }
+
+  return normalizePurchaseValueByFieldKey(fieldKey, value)
+}
+
 const sanitizePurchasePayloadForSubmit = (payload, businessType) => {
   if (businessType !== 'purchase_ledger' || !payload || typeof payload !== 'object') return payload
 
-  const sanitized = mergeLegacyProductDataIntoLedgers(Array.isArray(payload) ? [...payload] : { ...payload })
+  let sanitized = mergeLegacyProductDataIntoLedgers(Array.isArray(payload) ? [...payload] : { ...payload })
+  sanitized = normalizePurchaseAttachmentMaterialsField(sanitized)
+  sanitized = normalizePurchasePayloadFieldTypes(sanitized)
   if (Array.isArray(sanitized.purchaseLedgers)) {
     sanitized.purchaseLedgers = sanitized.purchaseLedgers.map(filterPurchaseLedgerRecord)
   }
@@ -1954,16 +2391,20 @@
     return isLt10M
   })
 
+  clearSelectedFiles()
   selectedFiles.value = validFiles
   uploadFileList.value = fileList.filter(item => item.raw && validFiles.includes(item.raw))
+  selectedFileSnapshots.value = validFiles.map((rawFile, index) => createLocalFileSnapshot(rawFile, index))
 }
 
 const removeSelectedFile = (index) => {
+  const [removedSnapshot] = selectedFileSnapshots.value.splice(index, 1)
+  revokeLocalFileSnapshots(removedSnapshot ? [removedSnapshot] : [])
   selectedFiles.value.splice(index, 1)
   uploadFileList.value.splice(index, 1)
 }
 
-const analyzeFiles = async (files, message = '') => {
+const analyzeFiles = async (files, message = '', localFileSnapshots = []) => {
   const uploadFiles = Array.isArray(files) ? files : [files].filter(Boolean)
   if (!uploadFiles.length) return
   if (isSending.value) return
@@ -1976,7 +2417,8 @@
     isUser: true,
     content: userMsg,
     htmlContent: convertTextToHtml(userMsg),
-    isTyping: false
+    isTyping: false,
+    localUploadFiles: Array.isArray(localFileSnapshots) ? localFileSnapshots : []
   })
 
   const botMsgIndex = messages.value.length
@@ -2075,9 +2517,9 @@
   const msg = inputMessage.value?.trim() || ''
   if ((msg || selectedFiles.value.length) && !isSending.value) {
     if (selectedFiles.value.length) {
-      analyzeFiles([...selectedFiles.value], msg)
-      selectedFiles.value = []
-      uploadFileList.value = []
+      const localFileSnapshots = selectedFileSnapshots.value
+      analyzeFiles([...selectedFiles.value], msg, localFileSnapshots)
+      clearSelectedFiles({ releaseSnapshots: false })
     } else {
       sendRequest(msg)
     }
@@ -2659,8 +3101,9 @@
     height: 100%;
   }
   :deep(.el-drawer__header) {
-    margin-bottom: 0;
-    padding: 0;
+    margin-bottom: 0 !important;
+    padding: 0 !important;
+    border-bottom: 1px solid rgba(255, 255, 255, 0.12);
     background: $gradient-dark;
     color: #fff;
   }
@@ -2671,7 +3114,7 @@
   justify-content: space-between;
   align-items: center;
   width: 100%;
-  padding: 18px 20px;
+  padding: 12px 18px;
   background: $gradient-dark;
   position: relative;
   overflow: hidden;
@@ -2803,6 +3246,15 @@
         opacity: 1;
       }
     }
+
+    :deep(.header-action-btn--text) {
+      width: auto !important;
+      min-width: 104px;
+      padding: 8px 14px !important;
+      font-size: 14px;
+      font-weight: 600;
+      white-space: nowrap;
+    }
   }
 
   .assistant-switcher {
@@ -2885,7 +3337,7 @@
     top: 0;
     left: 0;
     right: 0;
-    height: 240px;
+    height: 128px;
     background: linear-gradient(180deg, rgba(0, 85, 212, 0.06) 0%, transparent 100%);
     pointer-events: none;
   }
@@ -3124,6 +3576,87 @@
         background: rgba(0, 85, 212, 0.25);
         border-radius: 2px;
       }
+    }
+
+    .message-local-file-list {
+      margin-top: 8px;
+      display: grid;
+      gap: 8px;
+      max-width: 100%;
+    }
+
+    .message-local-file-item {
+      display: flex;
+      align-items: center;
+      gap: 10px;
+      padding: 8px 10px;
+      border-radius: 10px;
+      border: 1px solid rgba(88, 117, 255, 0.2);
+      background: rgba(255, 255, 255, 0.9);
+      max-width: 100%;
+
+      &.clickable {
+        cursor: pointer;
+        transition: all 0.2s ease;
+
+        &:hover {
+          border-color: rgba(44, 109, 255, 0.38);
+          background: rgba(243, 247, 255, 0.96);
+        }
+      }
+    }
+
+    .message-local-file-thumb {
+      width: 40px;
+      height: 40px;
+      border-radius: 6px;
+      overflow: hidden;
+      flex-shrink: 0;
+      border: 1px solid rgba(124, 148, 255, 0.26);
+      background: #f4f7ff;
+      cursor: zoom-in;
+
+      :deep(.el-image__inner) {
+        width: 100%;
+        height: 100%;
+      }
+    }
+
+    .message-local-file-icon {
+      font-size: 20px;
+      color: $primary-blue;
+      flex-shrink: 0;
+    }
+
+    .message-local-file-meta {
+      min-width: 0;
+      display: flex;
+      flex-direction: column;
+      gap: 2px;
+    }
+
+    .message-local-file-name {
+      font-size: 12px;
+      color: #1f2a44;
+      font-weight: 600;
+      white-space: nowrap;
+      overflow: hidden;
+      text-overflow: ellipsis;
+
+      &.clickable {
+        color: $primary-blue;
+        cursor: pointer;
+
+        &:hover {
+          text-decoration: underline;
+        }
+      }
+    }
+
+    .message-local-file-size {
+      font-size: 11px;
+      color: #7f8ba1;
+      line-height: 1.2;
     }
   }
 
@@ -3537,6 +4070,28 @@
         font-size: 18px;
       }
 
+      .selected-file-thumb {
+        width: 30px;
+        height: 30px;
+        border-radius: 6px;
+        overflow: hidden;
+        border: 1px solid rgba(0, 85, 212, 0.2);
+        flex-shrink: 0;
+        cursor: zoom-in;
+
+        :deep(.el-image__inner) {
+          width: 100%;
+          height: 100%;
+        }
+      }
+
+      .selected-file-meta {
+        min-width: 0;
+        display: flex;
+        flex-direction: column;
+        gap: 2px;
+      }
+
       .file-name {
         font-size: 13px;
         color: $deep-blue;
@@ -3544,6 +4099,12 @@
         overflow: hidden;
         text-overflow: ellipsis;
         font-weight: 600;
+      }
+
+      .file-size {
+        font-size: 11px;
+        color: #5f86b4;
+        line-height: 1.1;
       }
 
       .remove-file {
@@ -3703,75 +4264,59 @@
 
 .chat-hero {
   display: grid;
-  grid-template-columns: 164px minmax(0, 1fr);
-  gap: 18px;
-  align-items: start;
-  padding: 14px 18px 6px;
+  grid-template-columns: 176px minmax(0, 1fr);
+  gap: 14px;
+  align-items: stretch;
+  padding: 8px 18px 4px;
 
   &.compact {
-    grid-template-columns: 122px minmax(0, 1fr);
-    gap: 12px;
-    padding: 8px 18px 2px;
+    grid-template-columns: 132px minmax(0, 1fr);
+    gap: 10px;
+    padding: 4px 18px 2px;
   }
 }
 
 .assistant-stand {
   position: relative;
-  min-height: 252px;
+  min-height: 206px;
   display: flex;
   align-items: center;
   justify-content: center;
   flex-direction: column;
-  padding-top: 18px;
+  padding-top: 8px;
   overflow: hidden;
 
   &.compact {
-    min-height: 176px;
-    padding-top: 8px;
+    min-height: 160px;
+    padding-top: 4px;
   }
 
   &.thinking {
     .assistant-halo {
       opacity: 1;
-      transform: scale(1.08);
-      filter: blur(8px);
+      transform: scale(1.12);
+      filter: blur(9px);
     }
 
     .assistant-scan-ring {
-      opacity: 1;
-      animation-duration: 1.6s;
+      opacity: 0.95;
+      animation-duration: 1.5s;
     }
 
     .assistant-orbit {
-      opacity: 1;
+      opacity: 0.76;
     }
 
-    .assistant-bot {
-      transform: translateY(-4px) scale(1.02);
+    .assistant-model-shell {
+      transform: translateY(-5px) scale(1.02);
     }
 
-    .assistant-bot-head {
-      box-shadow: 0 0 30px rgba(80, 157, 255, 0.36);
+    .assistant-model-cut {
+      animation-duration: 2.2s;
     }
 
-    .assistant-bot-eye {
-      animation: robotBlinkFast 1.1s infinite;
-      box-shadow: 0 0 16px rgba(72, 186, 255, 0.95);
-    }
-
-    .assistant-bot-mouth {
-      width: 28px;
-      opacity: 1;
-      animation: robotTalk 1.2s ease-in-out infinite;
-    }
-
-    .assistant-bot-core {
-      animation: corePulse 1.4s ease-in-out infinite;
-      box-shadow: 0 0 24px rgba(78, 120, 255, 0.26);
-    }
-
-    .assistant-bot-core-ring {
-      animation: coreRotate 3s linear infinite;
+    .assistant-model-img {
+      filter: saturate(1.06) drop-shadow(0 18px 20px rgba(22, 48, 80, 0.22));
     }
 
     .assistant-status {
@@ -3785,219 +4330,174 @@
       animation: thinkingDot 1s ease-in-out infinite;
     }
 
+    .assistant-base-lg {
+      animation-duration: 1.8s;
+    }
+
+    .assistant-base-md {
+      animation-duration: 1.5s;
+    }
+
     .assistant-base-sm {
-      box-shadow: 0 0 24px rgba(255, 93, 122, 0.48);
+      box-shadow: 0 0 24px rgba(30, 91, 255, 0.36);
+      animation-duration: 1.25s;
     }
   }
 }
 
 .assistant-halo {
   position: absolute;
-  top: 22px;
-  width: 130px;
-  height: 130px;
+  top: 24px;
+  width: 146px;
+  height: 146px;
   border-radius: 50%;
-  background: radial-gradient(circle, rgba(46, 140, 224, 0.3) 0%, rgba(0, 85, 212, 0.18) 42%, rgba(113, 54, 244, 0.12) 60%, transparent 78%);
+  background: radial-gradient(circle, rgba(31, 122, 114, 0.26) 0%, rgba(30, 91, 255, 0.2) 42%, rgba(109, 65, 237, 0.12) 66%, transparent 80%);
   filter: blur(6px);
-  opacity: 0.82;
+  opacity: 0.78;
   transition: all 0.35s ease;
 }
 
 .assistant-scan-ring {
   position: absolute;
-  top: 40px;
-  width: 132px;
-  height: 132px;
+  top: 44px;
+  width: 136px;
+  height: 136px;
   border-radius: 50%;
-  border: 1px solid rgba(90, 159, 224, 0.22);
+  border: 1px solid rgba(67, 145, 223, 0.24);
   box-shadow: inset 0 0 16px rgba(255, 255, 255, 0.25);
-  opacity: 0.55;
+  opacity: 0.52;
   animation: scanRing 4s linear infinite;
 }
 
 .assistant-orbit {
   position: absolute;
   top: 52px;
-  width: 150px;
-  height: 150px;
+  width: 156px;
+  height: 156px;
   border-radius: 50%;
-  border: 1px dashed rgba(92, 135, 255, 0.22);
-  opacity: 0.45;
+  border: 1px dashed rgba(92, 135, 255, 0.24);
+  opacity: 0.42;
 }
 
 .assistant-orbit-a {
-  animation: orbitRotate 8s linear infinite;
+  animation: orbitRotate 8.6s linear infinite;
 }
 
 .assistant-orbit-b {
-  width: 118px;
-  height: 118px;
+  width: 124px;
+  height: 124px;
   top: 68px;
-  border-color: rgba(255, 108, 150, 0.22);
-  animation: orbitRotateReverse 5.6s linear infinite;
+  border-color: rgba(31, 122, 114, 0.24);
+  animation: orbitRotateReverse 6.2s linear infinite;
 }
 
-.assistant-bot {
+.assistant-model-shell {
   position: relative;
   z-index: 1;
+  width: 148px;
+  height: 178px;
   display: flex;
-  flex-direction: column;
-  align-items: center;
+  align-items: flex-end;
   justify-content: center;
-  margin-top: 12px;
+  margin-top: 4px;
   transition: transform 0.35s ease;
-}
-
-.assistant-bot-antenna {
-  position: absolute;
-  top: -4px;
-  width: 4px;
-  height: 20px;
-  border-radius: 999px;
-  background: linear-gradient(180deg, #fefefe, #aac9ff);
 
   &::before {
     content: '';
     position: absolute;
-    top: -6px;
     left: 50%;
-    width: 10px;
-    height: 10px;
-    border-radius: 50%;
+    bottom: 2px;
+    width: 164px;
+    height: 42px;
     transform: translateX(-50%);
-    background: linear-gradient(135deg, #54bfff, #7a41ff);
-    box-shadow: 0 0 14px rgba(84, 191, 255, 0.65);
+    border-radius: 50%;
+    background: radial-gradient(
+      ellipse at center,
+      rgba(43, 126, 211, 0.32) 0%,
+      rgba(43, 126, 211, 0.14) 46%,
+      rgba(43, 126, 211, 0) 74%
+    );
+    filter: blur(2.6px);
+    animation: baseGlow 4.6s ease-in-out infinite;
+    z-index: 1;
+  }
+
+  &::after {
+    content: '';
+    position: absolute;
+    left: 50%;
+    bottom: 10px;
+    width: 138px;
+    height: 28px;
+    transform: translateX(-50%);
+    border-radius: 50%;
+    border: 1px solid rgba(36, 116, 198, 0.6);
+    box-shadow:
+      inset 0 0 0 1px rgba(255, 255, 255, 0.58),
+      0 0 22px rgba(42, 116, 196, 0.24);
+    animation: basePulse 3.2s ease-in-out infinite;
+    z-index: 4;
   }
 }
 
-.assistant-bot-antenna-left {
-  left: 36px;
-  transform: rotate(-14deg);
-}
-
-.assistant-bot-antenna-right {
-  right: 36px;
-  transform: rotate(14deg);
-}
-
-.assistant-bot-head {
+.assistant-model-cut {
   position: relative;
+  width: 132px;
+  height: 178px;
+  z-index: 6;
+  display: flex;
+  align-items: flex-end;
+  justify-content: center;
+  transform-origin: center 84%;
+  animation: avatarFloat 3.2s ease-in-out infinite;
+}
+
+.assistant-model-img {
+  width: 100%;
+  height: 100%;
+  object-fit: contain;
+  object-position: center bottom;
+  display: block;
+  filter: saturate(1.03) drop-shadow(0 14px 18px rgba(22, 49, 79, 0.2));
+  transition: filter 0.35s ease;
+}
+
+.assistant-model-fallback {
   width: 92px;
-  height: 78px;
-  border-radius: 28px;
-  background: linear-gradient(180deg, rgba(255, 255, 255, 0.98) 0%, #e8f1ff 100%);
-  border: 1px solid rgba(0, 85, 212, 0.14);
-  box-shadow: 0 16px 32px rgba(0, 85, 212, 0.14);
+  height: 92px;
+  border-radius: 24px;
+  color: #fff;
+  background: linear-gradient(145deg, rgba(31, 122, 114, 0.9), rgba(30, 91, 255, 0.9));
+  border: 1px solid rgba(255, 255, 255, 0.3);
+  box-shadow: 0 12px 24px rgba(31, 85, 173, 0.22);
+  display: flex;
+  align-items: center;
+  justify-content: center;
 }
 
-.assistant-bot-head-glow {
-  position: absolute;
-  inset: 10px 16px auto;
-  height: 20px;
-  border-radius: 999px;
-  background: linear-gradient(180deg, rgba(0, 85, 212, 0.16), transparent);
-}
-
-.assistant-bot-eye {
-  position: absolute;
-  top: 30px;
-  width: 16px;
-  height: 16px;
-  border-radius: 50%;
-  background: radial-gradient(circle, #8ef0ff 0%, #56c0ff 42%, #2869ff 100%);
-  box-shadow: 0 0 12px rgba(72, 186, 255, 0.72);
-  animation: robotBlink 3.2s infinite;
-}
-
-.assistant-bot-eye-left {
-  left: 22px;
-}
-
-.assistant-bot-eye-right {
-  right: 22px;
-}
-
-.assistant-bot-mouth {
+.assistant-base {
   position: absolute;
   left: 50%;
-  bottom: 16px;
-  width: 22px;
-  height: 4px;
+  bottom: 8px;
   transform: translateX(-50%);
-  border-radius: 999px;
-  background: linear-gradient(90deg, rgba(72, 186, 255, 0.2), rgba(72, 186, 255, 0.9), rgba(72, 186, 255, 0.2));
-}
-
-.assistant-bot-neck {
-  width: 16px;
-  height: 10px;
-  border-radius: 0 0 10px 10px;
-  background: linear-gradient(180deg, #dceaff, #bdd5ff);
-  margin-top: -2px;
-}
-
-.assistant-bot-body {
-  position: relative;
-  width: 104px;
-  height: 92px;
-  margin-top: 2px;
-  border-radius: 28px 28px 34px 34px;
-  background: linear-gradient(180deg, rgba(255, 255, 255, 0.98) 0%, #e3eeff 100%);
-  border: 1px solid rgba(0, 85, 212, 0.14);
-  box-shadow: 0 18px 36px rgba(0, 85, 212, 0.16);
-  display: flex;
-  align-items: center;
-  justify-content: center;
-}
-
-.assistant-bot-arm {
-  position: absolute;
-  top: 18px;
-  width: 16px;
-  height: 44px;
-  border-radius: 999px;
-  background: linear-gradient(180deg, #eff5ff, #c7dbff);
-  border: 1px solid rgba(0, 85, 212, 0.12);
-}
-
-.assistant-bot-arm-left {
-  left: -10px;
-  transform: rotate(16deg);
-}
-
-.assistant-bot-arm-right {
-  right: -10px;
-  transform: rotate(-16deg);
-}
-
-.assistant-bot-core {
-  position: relative;
-  width: 46px;
-  height: 46px;
   border-radius: 50%;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  color: $primary-blue;
-  background: radial-gradient(circle, rgba(255, 255, 255, 1) 0%, #dae8ff 55%, #adc7ff 100%);
-}
-
-.assistant-bot-core-ring {
-  position: absolute;
-  inset: -6px;
-  border-radius: 50%;
-  border: 1px solid rgba(88, 135, 255, 0.3);
-  border-top-color: rgba(255, 96, 139, 0.85);
-  border-right-color: rgba(79, 145, 255, 0.9);
+  border: 1px solid rgba(36, 116, 198, 0.28);
+  background: radial-gradient(
+    ellipse at center,
+    rgba(255, 255, 255, 0.94) 0%,
+    rgba(81, 164, 233, 0.16) 58%,
+    rgba(30, 91, 255, 0.06) 100%
+  );
+  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.2);
 }
 
 .assistant-status {
   position: relative;
   z-index: 1;
-  margin-top: 14px;
-  padding: 6px 12px;
+  margin-top: 7px;
+  padding: 5px 10px;
   border-radius: 999px;
-  font-size: 12px;
+  font-size: 11px;
   font-weight: 600;
   color: $deep-blue;
   background: rgba(255, 255, 255, 0.95);
@@ -4017,81 +4517,25 @@
 }
 
 .assistant-base {
-  position: absolute;
-  bottom: 0;
-  left: 50%;
-  transform: translateX(-50%);
-  border-radius: 50%;
-  border: 2px solid rgba(255, 93, 122, 0.22);
-  background: radial-gradient(circle, rgba(255, 255, 255, 0.9) 0%, rgba(255, 111, 145, 0.1) 70%, transparent 100%);
-}
-
-.assistant-base-lg {
-  width: 118px;
-  height: 30px;
+  pointer-events: none;
 }
 
 .assistant-base-md {
-  bottom: 6px;
-  width: 88px;
-  height: 20px;
-  border-color: rgba(255, 93, 122, 0.34);
+  bottom: 15px;
+  width: 104px;
+  height: 22px;
+  border-color: rgba(36, 116, 198, 0.48);
+  animation: basePulse 2.8s ease-in-out infinite;
 }
 
 .assistant-base-sm {
-  bottom: 11px;
-  width: 54px;
-  height: 10px;
-  background: linear-gradient(90deg, rgba(255, 93, 122, 0.95), rgba(255, 173, 188, 0.9));
+  bottom: 20px;
+  width: 68px;
+  height: 14px;
+  background: linear-gradient(90deg, rgba(31, 122, 114, 0.82), rgba(45, 124, 255, 0.9));
   border: none;
-  box-shadow: 0 0 18px rgba(255, 93, 122, 0.38);
-}
-
-@keyframes robotBlink {
-  0%, 44%, 48%, 100% {
-    transform: scaleY(1);
-  }
-  46% {
-    transform: scaleY(0.14);
-  }
-}
-
-@keyframes robotBlinkFast {
-  0%, 100% {
-    transform: scaleY(1);
-  }
-  50% {
-    transform: scaleY(0.3);
-  }
-}
-
-@keyframes robotTalk {
-  0%, 100% {
-    transform: translateX(-50%) scaleX(1);
-  }
-  50% {
-    transform: translateX(-50%) scaleX(1.35);
-  }
-}
-
-@keyframes corePulse {
-  0%, 100% {
-    transform: scale(1);
-    filter: brightness(1);
-  }
-  50% {
-    transform: scale(1.08);
-    filter: brightness(1.08);
-  }
-}
-
-@keyframes coreRotate {
-  from {
-    transform: rotate(0deg);
-  }
-  to {
-    transform: rotate(360deg);
-  }
+  box-shadow: 0 0 18px rgba(45, 124, 255, 0.34);
+  animation: basePulse 2.2s ease-in-out infinite;
 }
 
 @keyframes orbitRotate {
@@ -4132,9 +4576,85 @@
   }
 }
 
+.assistant-base-lg {
+  width: 142px;
+  height: 32px;
+  animation: basePulse 3.4s ease-in-out infinite;
+
+  &::before {
+    content: '';
+    position: absolute;
+    left: 50%;
+    top: 50%;
+    width: 130px;
+    height: 130px;
+    transform: translate(-50%, -50%);
+    border-radius: 50%;
+    background: conic-gradient(
+      from 180deg,
+      transparent 0deg,
+      rgba(36, 116, 198, 0.65) 48deg,
+      transparent 114deg,
+      rgba(36, 116, 198, 0.55) 212deg,
+      transparent 286deg,
+      rgba(31, 122, 114, 0.45) 334deg,
+      transparent 360deg
+    );
+    -webkit-mask: radial-gradient(circle, transparent 61%, #000 62%, #000 68%, transparent 70%);
+    mask: radial-gradient(circle, transparent 61%, #000 62%, #000 68%, transparent 70%);
+    opacity: 0.62;
+    animation: baseSpin 9s linear infinite;
+  }
+}
+
+@keyframes avatarFloat {
+  0%,
+  100% {
+    transform: translateY(0);
+  }
+  50% {
+    transform: translateY(-7px);
+  }
+}
+
+@keyframes basePulse {
+  0%,
+  100% {
+    transform: translateX(-50%) scale(1);
+    opacity: 0.88;
+  }
+  50% {
+    transform: translateX(-50%) scale(1.05);
+    opacity: 0.98;
+  }
+}
+
+@keyframes baseSpin {
+  from {
+    transform: translate(-50%, -50%) rotate(0deg);
+  }
+  to {
+    transform: translate(-50%, -50%) rotate(360deg);
+  }
+}
+
+@keyframes baseGlow {
+  0%,
+  100% {
+    transform: translateX(-50%) scaleX(1);
+    opacity: 0.82;
+  }
+  50% {
+    transform: translateX(-50%) scaleX(1.06);
+    opacity: 0.96;
+  }
+}
+
 .welcome-card {
   position: relative;
-  padding: 14px 14px 12px;
+  align-self: stretch;
+  min-height: 206px;
+  padding: 9px 10px 8px;
   border-radius: 16px;
   background:
     linear-gradient(#fff, #fff) padding-box,
@@ -4143,7 +4663,8 @@
   box-shadow: 0 16px 36px rgba(0, 85, 212, 0.12);
 
   &.compact {
-    padding: 10px 12px;
+    min-height: 160px;
+    padding: 8px 9px 7px;
     border-radius: 12px;
     box-shadow: 0 8px 16px rgba(0, 85, 212, 0.07);
 
@@ -4152,8 +4673,8 @@
     }
 
     .welcome-title {
-      font-size: 17px;
-      line-height: 1.3;
+      font-size: 16px;
+      line-height: 1.25;
 
       br {
         display: none;
@@ -4161,65 +4682,69 @@
     }
 
     .welcome-desc {
-      margin-top: 6px;
-      font-size: 12px;
-      line-height: 1.55;
+      margin-top: 4px;
+      font-size: 11px;
+      line-height: 1.5;
     }
 
     .quick-prompt-list {
-      margin-top: 10px;
-      gap: 6px;
+      margin-top: 8px;
+      gap: 5px;
     }
 
     .quick-prompt-btn {
-      padding: 8px 10px;
-      font-size: 12px;
+      padding: 7px 9px;
+      font-size: 11px;
       border-radius: 7px;
     }
 
     .more-prompts-btn {
-      margin-top: 8px;
-      font-size: 12px;
+      margin-top: 6px;
+      font-size: 11px;
     }
   }
 }
 
 .welcome-eyebrow {
-  font-size: 11px;
+  font-size: 10px;
   font-weight: 700;
   letter-spacing: 2px;
   color: rgba(0, 85, 212, 0.58);
-  margin-bottom: 8px;
+  margin-bottom: 5px;
 }
 
 .welcome-title {
   margin: 0;
-  font-size: 26px;
-  line-height: 1.2;
+  font-size: 20px;
+  line-height: 1.15;
   font-weight: 800;
   color: #172033;
+
+  br {
+    display: none;
+  }
 }
 
 .welcome-desc {
-  margin: 10px 0 0;
-  font-size: 13px;
-  line-height: 1.7;
+  margin: 5px 0 0;
+  font-size: 12px;
+  line-height: 1.5;
   color: #5f6980;
 }
 
 .quick-prompt-list {
   display: grid;
-  gap: 8px;
-  margin-top: 14px;
+  gap: 6px;
+  margin-top: 8px;
 }
 
 .quick-prompt-btn {
   width: 100%;
   border: none;
-  border-radius: 10px;
-  padding: 11px 14px;
+  border-radius: 9px;
+  padding: 7px 10px;
   text-align: left;
-  font-size: 13px;
+  font-size: 12px;
   font-weight: 600;
   color: #fff;
   cursor: pointer;
@@ -4267,14 +4792,14 @@
 }
 
 .more-prompts-btn {
-  margin-top: 10px;
-  padding: 0 12px;
-  height: 32px;
+  margin-top: 6px;
+  padding: 0 10px;
+  height: 26px;
   border: 1px solid rgba(208, 65, 81, 0.12);
   border-radius: 999px;
   background: linear-gradient(180deg, rgba(255, 255, 255, 0.96), rgba(255, 241, 245, 0.96));
   color: #d04151;
-  font-size: 13px;
+  font-size: 12px;
   font-weight: 600;
   cursor: pointer;
   display: inline-flex;
@@ -4289,21 +4814,6 @@
     border-color: transparent;
     color: #fff;
     box-shadow: 0 14px 24px rgba(138, 61, 246, 0.18);
-  }
-}
-
-.hero-dot-grid {
-  display: grid;
-  grid-template-columns: repeat(14, 1fr);
-  gap: 7px;
-  padding: 0 18px 14px;
-
-  span {
-    display: block;
-    width: 100%;
-    aspect-ratio: 1;
-    border-radius: 2px;
-    background: linear-gradient(135deg, rgba(255, 110, 138, 0.95), rgba(255, 190, 201, 0.55));
   }
 }
 
@@ -4399,12 +4909,6 @@
 
   .welcome-title {
     font-size: 21px;
-  }
-
-  .hero-dot-grid {
-    grid-template-columns: repeat(12, 1fr);
-    gap: 6px;
-    padding: 0 14px 12px;
   }
 
   .message-list {
diff --git a/src/components/PurchaseAIChatSidebar/index.vue b/src/components/PurchaseAIChatSidebar/index.vue
index ecc46be..428f84f 100644
--- a/src/components/PurchaseAIChatSidebar/index.vue
+++ b/src/components/PurchaseAIChatSidebar/index.vue
@@ -3,24 +3,8 @@
 </template>
 
 <script setup>
-import { ShoppingCart } from '@element-plus/icons-vue'
 import AIChatSidebar from '@/components/AIChatSidebar/index.vue'
+import { purchaseAssistant } from '@/components/AIChatSidebar/assistants'
 
-const assistants = [
-  {
-    key: 'purchase',
-    label: '閲囪喘鍔╃悊',
-    title: '閲囪喘鏅鸿兘鍔╃悊',
-    tooltip: '閲囪喘鏅鸿兘鍔╃悊',
-    icon: ShoppingCart,
-    apiBase: '/purchase-ai',
-    storageKey: 'purchase_ai_chat_uuid',
-    placeholder: '璇疯緭鍏ラ噰璐棶棰�... (Enter 鍙戦��, Shift+Enter 鎹㈣)',
-    welcomeMessage: '浣犲ソ',
-    allowFileUpload: true,
-    allowMultipleFileUpload: true,
-    fileAnalyzeUrl: '/purchase-ai/analyze-files',
-    emptySessionText: '鏆傛棤閲囪喘浼氳瘽'
-  }
-]
+const assistants = [purchaseAssistant]
 </script>
diff --git a/src/layout/index.vue b/src/layout/index.vue
index 03c13ba..fc47afa 100644
--- a/src/layout/index.vue
+++ b/src/layout/index.vue
@@ -16,12 +16,13 @@
       <app-main />
       <settings ref="settingRef" />
     </div>
-    <AIChatSidebar v-if="aiEnabled" />
+    <AIChatSidebar v-if="showGlobalAiChat" />
   </div>
 </template>
 
 <script setup>
   import { useWindowSize } from "@vueuse/core";
+  import { useRoute } from "vue-router";
   import Sidebar from "./components/Sidebar/index.vue";
   import { AppMain, Navbar, Settings, TagsView } from "./components";
   import AIChatSidebar from "@/components/AIChatSidebar/index.vue";
@@ -33,6 +34,7 @@
 
   const settingsStore = useSettingsStore();
   const userStore = useUserStore();
+  const route = useRoute();
   const theme = computed(() => settingsStore.theme);
   const sideTheme = computed(() => settingsStore.sideTheme);
   const sidebar = computed(() => useAppStore().sidebar);
@@ -40,6 +42,10 @@
   const needTagsView = computed(() => settingsStore.tagsView);
   const fixedHeader = computed(() => settingsStore.fixedHeader);
   const aiEnabled = computed(() => Number(userStore.aiEnabled) === 1);
+  const showGlobalAiChat = computed(() => {
+    const isIndustrialBrainRoute = String(route.path || "").startsWith("/ai-industrial-brain");
+    return !isIndustrialBrainRoute && aiEnabled.value;
+  });
 
   const classObj = computed(() => ({
     hideSidebar: !sidebar.value.opened,
diff --git a/src/router/index.js b/src/router/index.js
index 2bb5586..2c98627 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -86,6 +86,18 @@
     ],
   },
   {
+    path: "/ai-industrial-brain",
+    component: Layout,
+    children: [
+      {
+        path: "index",
+        component: () => import("@/views/aiIndustrialBrain/index.vue"),
+        name: "AiIndustrialBrain",
+        meta: { title: "AI宸ヤ笟澶ц剳", icon: "skill" },
+      },
+    ],
+  },
+  {
     path: "/user",
     component: Layout,
     hidden: true,
@@ -134,118 +146,121 @@
     ],
   },
   // 璐㈠姟绠$悊妯″潡璺敱
-  // {
-  //   path: "/financial",
-  //   component: Layout,
-  //   hidden: false,
-  //   redirect: "/financial/general-ledger",
-  //   alwaysShow: true,
-  //   meta: { title: "璐㈠姟绠$悊", icon: "money" },
-  //   children: [
-  //     {
-  //       path: "general-ledger",
-  //       component: () => import("@/views/financialManagement/generalLedger/index.vue"),
-  //       name: "GeneralLedger",
-  //       meta: { title: "鎬诲笎绉戠洰" },
-  //     },
-  //     {
-  //       path: "sales-out",
-  //       component: () => import("@/views/financialManagement/receivable/salesOut.vue"),
-  //       name: "SalesOut",
-  //       meta: { title: "閿�鍞嚭搴�" },
-  //     },
-  //     {
-  //       path: "sales-return",
-  //       component: () => import("@/views/financialManagement/receivable/salesReturn.vue"),
-  //       name: "SalesReturn",
-  //       meta: { title: "閿�鍞��璐�" },
-  //     },
-  //     {
-  //       path: "receivable-reconciliation",
-  //       component: () => import("@/views/financialManagement/receivable/reconciliation.vue"),
-  //       name: "ReceivableReconciliation",
-  //       meta: { title: "搴旀敹瀵硅处" },
-  //     },
-  //     {
-  //       path: "invoice-apply",
-  //       component: () => import("@/views/financialManagement/receivable/invoiceApply.vue"),
-  //       name: "InvoiceApply",
-  //       meta: { title: "寮�绁ㄧ敵璇�" },
-  //     },
-  //     {
-  //       path: "output-invoice",
-  //       component: () => import("@/views/financialManagement/receivable/outputInvoice.vue"),
-  //       name: "OutputInvoice",
-  //       meta: { title: "閿�椤瑰彂绁�" },
-  //     },
-  //     {
-  //       path: "receipt",
-  //       component: () => import("@/views/financialManagement/receivable/receipt.vue"),
-  //       name: "Receipt",
-  //       meta: { title: "鏀舵鍗�" },
-  //     },
-  //     {
-  //       path: "purchase-in",
-  //       component: () => import("@/views/financialManagement/payable/purchaseIn.vue"),
-  //       name: "PurchaseIn",
-  //       meta: { title: "閲囪喘鍏ュ簱" },
-  //     },
-  //     {
-  //       path: "payable-reconciliation",
-  //       component: () => import("@/views/financialManagement/payable/reconciliation.vue"),
-  //       name: "PayableReconciliation",
-  //       meta: { title: "搴斾粯瀵硅处" },
-  //     },
-  //     {
-  //       path: "input-invoice",
-  //       component: () => import("@/views/financialManagement/payable/input-invoice.vue"),
-  //       name: "InputInvoice",
-  //       meta: { title: "杩涢」鍙戠エ" },
-  //     },
-  //     {
-  //       path: "payment-apply",
-  //       component: () => import("@/views/financialManagement/payable/paymentApply.vue"),
-  //       name: "PaymentApply",
-  //       meta: { title: "浠樻鐢宠" },
-  //     },
-  //     {
-  //       path: "payment",
-  //       component: () => import("@/views/financialManagement/payable/payment.vue"),
-  //       name: "Payment",
-  //       meta: { title: "浠樻鍗�" },
-  //     },
-  //     {
-  //       path: "fixed-assets",
-  //       component: () => import("@/views/financialManagement/assets/fixedAssets.vue"),
-  //       name: "FixedAssets",
-  //       meta: { title: "鍥哄畾璧勪骇" },
-  //     },
-  //     {
-  //       path: "intangible-assets",
-  //       component: () => import("@/views/financialManagement/assets/intangibleAssets.vue"),
-  //       name: "IntangibleAssets",
-  //       meta: { title: "鏃犲舰璧勪骇" },
-  //     },
-  //     {
-  //       path: "voucher",
-  //       component: () => import("@/views/financialManagement/voucher/index.vue"),
-  //       name: "Voucher",
-  //       meta: { title: "鍑瘉" },
-  //     },
-  //     {
-  //       path: "voucher-general-ledger",
-  //       component: () => import("@/views/financialManagement/voucher/generalLedger.vue"),
-  //       name: "VoucherGeneralLedger",
-  //       meta: { title: "绉戠洰鎬诲笎" },
-  //     },
-  //     {
-  //       path: "voucher-detail-ledger",
-  //       component: () => import("@/views/financialManagement/voucher/detailLedger.vue"),
-  //       name: "VoucherDetailLedger",
-  //       meta: { title: "绉戠洰鏄庣粏甯�" },
-  //     },
-  //   ],
-  // },
+  {
+    path: "/financial",
+    component: Layout,
+    hidden: false,
+    redirect: "/financial/general-ledger",
+    alwaysShow: true,
+    meta: { title: "璐㈠姟绠$悊", icon: "money" },
+    children: [
+      {
+        path: "sales-out",
+        component: () => import("@/views/financialManagement/receivable/salesOut.vue"),
+        name: "SalesOut",
+        meta: { title: "閿�鍞嚭搴�" },
+      },
+      {
+        path: "sales-return",
+        component: () => import("@/views/financialManagement/receivable/salesReturn.vue"),
+        name: "SalesReturn",
+        meta: { title: "閿�鍞��璐�" },
+      },
+      
+      {
+        path: "invoice-apply",
+        component: () => import("@/views/financialManagement/receivable/invoiceApply.vue"),
+        name: "InvoiceApply",
+        meta: { title: "寮�绁ㄧ敵璇�" },
+      },
+      {
+        path: "output-invoice",
+        component: () => import("@/views/financialManagement/receivable/outputInvoice.vue"),
+        name: "OutputInvoice",
+        meta: { title: "閿�椤瑰彂绁�" },
+      },
+      {
+        path: "receipt",
+        component: () => import("@/views/financialManagement/receivable/receipt.vue"),
+        name: "Receipt",
+        meta: { title: "鏀舵鍗�" },
+      },
+      {
+        path: "receivable-reconciliation",
+        component: () => import("@/views/financialManagement/receivable/reconciliation.vue"),
+        name: "ReceivableReconciliation",
+        meta: { title: "搴旀敹瀵硅处" },
+      },
+      {
+        path: "purchase-in",
+        component: () => import("@/views/financialManagement/payable/purchaseIn.vue"),
+        name: "PurchaseIn",
+        meta: { title: "閲囪喘鍏ュ簱" },
+      },
+      
+      {
+        path: "input-invoice",
+        component: () => import("@/views/financialManagement/payable/input-invoice.vue"),
+        name: "InputInvoice",
+        meta: { title: "杩涢」鍙戠エ" },
+      },
+      {
+        path: "payment-apply",
+        component: () => import("@/views/financialManagement/payable/paymentApply.vue"),
+        name: "PaymentApply",
+        meta: { title: "浠樻鐢宠" },
+      },
+      
+      {
+        path: "payment",
+        component: () => import("@/views/financialManagement/payable/payment.vue"),
+        name: "Payment",
+        meta: { title: "浠樻鍗�" },
+      },
+      {
+        path: "payable-reconciliation",
+        component: () => import("@/views/financialManagement/payable/reconciliation.vue"),
+        name: "PayableReconciliation",
+        meta: { title: "搴斾粯瀵硅处" },
+      },
+      {
+        path: "fixed-assets",
+        component: () => import("@/views/financialManagement/assets/fixedAssets.vue"),
+        name: "FixedAssets",
+        meta: { title: "鍥哄畾璧勪骇" },
+      },
+      {
+        path: "intangible-assets",
+        component: () => import("@/views/financialManagement/assets/intangibleAssets.vue"),
+        name: "IntangibleAssets",
+        meta: { title: "鏃犲舰璧勪骇" },
+      },
+      {
+        path: "general-ledger",
+        component: () => import("@/views/financialManagement/generalLedger/index.vue"),
+        name: "GeneralLedger",
+        meta: { title: "鎬诲笎绉戠洰" },
+      },
+      {
+        path: "voucher",
+        component: () => import("@/views/financialManagement/voucher/index.vue"),
+        name: "Voucher",
+        meta: { title: "鍑瘉" },
+      },
+      {
+        path: "voucher-general-ledger",
+        component: () => import("@/views/financialManagement/voucher/generalLedger.vue"),
+        name: "VoucherGeneralLedger",
+        meta: { title: "绉戠洰鎬诲笎" },
+      },
+      {
+        path: "voucher-detail-ledger",
+        component: () => import("@/views/financialManagement/voucher/detailLedger.vue"),
+        name: "VoucherDetailLedger",
+        meta: { title: "绉戠洰鏄庣粏甯�" },
+      },
+    ],
+  },
 ];
 
 // 鍔ㄦ�佽矾鐢憋紝鍩轰簬鐢ㄦ埛鏉冮檺鍔ㄦ�佸幓鍔犺浇
diff --git a/src/store/modules/permission.js b/src/store/modules/permission.js
index d3f0594..0b11d2e 100644
--- a/src/store/modules/permission.js
+++ b/src/store/modules/permission.js
@@ -44,17 +44,18 @@
             const defaultData = JSON.parse(JSON.stringify(rawRoutes))
             const sidebarRoutes = filterAsyncRouter(sdata)
             const rewriteRoutes = filterAsyncRouter(rdata, false, true)
-            const defaultRoutes = filterAsyncRouter(defaultData)
-            const asyncRoutes = filterDynamicRoutes(dynamicRoutes)
-            asyncRoutes.forEach(route => { router.addRoute(route) })
-            this.setRoutes(rewriteRoutes)
-            // 灏嗚储鍔$鐞嗚矾鐢卞悎骞跺埌渚ц竟鏍�
-            this.setSidebarRouters(constantRoutes.concat(sidebarRoutes))
-            this.setDefaultRoutes(sidebarRoutes)
-            this.setTopbarRoutes(defaultRoutes)
-            resolve(rewriteRoutes)
-          })
-        })
+            const defaultRoutes = filterAsyncRouter(defaultData)
+            const asyncRoutes = filterDynamicRoutes(dynamicRoutes)
+            asyncRoutes.forEach(route => { router.addRoute(route) })
+            this.setRoutes(rewriteRoutes)
+            const constantSidebarRoutes = filterAiFeatureRoutes(constantRoutes, aiEnabled)
+            // 灏嗚储鍔$鐞嗚矾鐢卞悎骞跺埌渚ц竟鏍�
+            this.setSidebarRouters(constantSidebarRoutes.concat(sidebarRoutes))
+            this.setDefaultRoutes(sidebarRoutes)
+            this.setTopbarRoutes(defaultRoutes)
+            resolve(rewriteRoutes)
+          })
+        })
       }
     }
   })
@@ -118,7 +119,7 @@
   })
 }
 
-function filterChildren(childrenMap, lastRouter = false) {
+function filterChildren(childrenMap, lastRouter = false) {
   var children = []
   childrenMap.forEach(el => {
     el.path = lastRouter ? lastRouter.path + '/' + el.path : el.path
@@ -128,11 +129,11 @@
       children.push(el)
     }
   })
-  return children
-}
-
-// 鍔ㄦ�佽矾鐢遍亶鍘嗭紝楠岃瘉鏄惁鍏峰鏉冮檺
-export function filterDynamicRoutes(routes) {
+  return children
+}
+
+// 鍔ㄦ�佽矾鐢遍亶鍘嗭紝楠岃瘉鏄惁鍏峰鏉冮檺
+export function filterDynamicRoutes(routes) {
   const res = []
   routes.forEach(route => {
     if (route.permissions) {
diff --git a/src/views/aiIndustrialBrain/components/AiAssistantWorkspace.vue b/src/views/aiIndustrialBrain/components/AiAssistantWorkspace.vue
new file mode 100644
index 0000000..2f55511
--- /dev/null
+++ b/src/views/aiIndustrialBrain/components/AiAssistantWorkspace.vue
@@ -0,0 +1,192 @@
+<template>
+  <transition name="fade">
+    <section v-if="visible" class="assistant-workspace">
+      <div class="assistant-workspace__panel">
+        <button
+          v-if="assistantMode === 'pending'"
+          type="button"
+          class="workspace-back-btn"
+          @click="$emit('close')"
+        >
+          <el-icon><ArrowLeftBold /></el-icon>
+          <span>杩斿洖宸ヤ笟澶у睆</span>
+        </button>
+
+        <div class="assistant-workspace__body">
+          <AIChatSidebar
+            v-if="assistantMode !== 'pending'"
+            :key="assistantMode"
+            class="workspace-chat"
+            :assistants="assistantMode === 'purchase' ? [purchaseAssistant] : [generalAssistant]"
+            :default-assistant="assistantMode"
+            :hide-trigger="true"
+            :auto-open="true"
+            drawer-size="100%"
+            drawer-direction="ttb"
+            header-extra-action-text="杩斿洖宸ヤ笟澶у睆"
+            @header-extra-action="$emit('close')"
+          />
+
+          <div v-else class="workspace-pending">
+            <div class="workspace-pending__content">
+              <h3>{{ agentTitle }}</h3>
+              <p>姝e湪寮�鍙戯紝鏁鏈熷緟......</p>
+            </div>
+          </div>
+        </div>
+      </div>
+    </section>
+  </transition>
+</template>
+
+<script setup>
+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";
+
+const props = defineProps({
+  visible: {
+    type: Boolean,
+    default: false,
+  },
+  agent: {
+    type: Object,
+    default: () => ({}),
+  },
+});
+
+defineEmits(["close"]);
+
+const agentKey = computed(() => String(props.agent?.key || ""));
+const agentTitle = computed(() => String(props.agent?.name || "AI鍔╂墜"));
+const assistantMode = computed(() => {
+  if (agentKey.value === "purchase") return "purchase";
+  if (agentKey.value === "general") return "general";
+  return "pending";
+});
+</script>
+
+<style scoped>
+.assistant-workspace {
+  position: fixed;
+  inset: 0;
+  z-index: 2100;
+  padding: 12px;
+  background: rgba(33, 49, 63, 0.24);
+  backdrop-filter: blur(2px);
+}
+
+.assistant-workspace__panel {
+  position: relative;
+  height: 100%;
+  border-radius: 22px;
+  border: 1px solid var(--surface-border);
+  background: linear-gradient(180deg, #f9fcfb 0%, #f0f5f2 100%);
+  box-shadow: var(--shadow-md);
+  overflow: hidden;
+}
+
+.assistant-workspace__body {
+  height: 100%;
+  min-height: 100%;
+}
+
+.workspace-back-btn {
+  position: absolute;
+  top: 16px;
+  right: 20px;
+  z-index: 5;
+  height: 36px;
+  padding: 0 14px;
+  border: 1px solid rgba(38, 112, 183, 0.3);
+  border-radius: 10px;
+  background: rgba(255, 255, 255, 0.92);
+  color: #25528f;
+  display: inline-flex;
+  align-items: center;
+  gap: 6px;
+  font-size: 14px;
+  font-weight: 600;
+  cursor: pointer;
+  transition: all 0.2s ease;
+}
+
+.workspace-back-btn:hover {
+  border-color: rgba(31, 122, 114, 0.45);
+  color: #1f5ddf;
+  box-shadow: 0 8px 16px rgba(31, 122, 114, 0.14);
+  transform: translateY(-1px);
+}
+
+.workspace-chat {
+  width: 100%;
+  height: 100%;
+}
+
+.workspace-chat :deep(.ai-chat-sidebar-wrapper) {
+  height: 100%;
+}
+
+.workspace-chat :deep(.ai-chat-drawer) {
+  height: 100%;
+}
+
+.workspace-chat :deep(.el-drawer) {
+  height: 100% !important;
+  width: 100% !important;
+}
+
+.workspace-pending {
+  height: 100%;
+  display: grid;
+  place-items: center;
+  padding: 20px;
+  color: var(--text-secondary);
+}
+
+.workspace-pending__content {
+  display: grid;
+  gap: 12px;
+  text-align: center;
+}
+
+.workspace-pending__content h3 {
+  margin: 0;
+  font-size: 36px;
+  color: var(--text-primary);
+}
+
+.workspace-pending__content p {
+  margin: 0;
+  font-size: 24px;
+}
+
+.fade-enter-active,
+.fade-leave-active {
+  transition: opacity 0.2s ease;
+}
+
+.fade-enter-from,
+.fade-leave-to {
+  opacity: 0;
+}
+
+@media (max-width: 1600px) {
+  .workspace-back-btn {
+    top: 12px;
+    right: 14px;
+    height: 32px;
+    padding: 0 12px;
+    font-size: 13px;
+  }
+
+  .workspace-pending__content h3 {
+    font-size: 30px;
+  }
+
+  .workspace-pending__content p {
+    font-size: 20px;
+  }
+}
+</style>
diff --git a/src/views/aiIndustrialBrain/index.vue b/src/views/aiIndustrialBrain/index.vue
new file mode 100644
index 0000000..33b967d
--- /dev/null
+++ b/src/views/aiIndustrialBrain/index.vue
@@ -0,0 +1,1499 @@
+<template>
+  <div ref="screenRef" class="ai-brain-screen">
+    <section class="brain-stage">
+      <header class="brain-head">
+        <div class="head-date">
+          <p>{{ weekLabel }}</p>
+          <p>{{ dateLabel }}</p>
+        </div>
+
+        <div class="head-title">
+          <span>AI宸ヤ笟澶ц剳</span>
+        </div>
+
+        <div class="head-actions">
+          <button type="button" class="head-back-btn" @click="goBack">
+            <el-icon><ArrowLeftBold /></el-icon>
+            <span>杩斿洖</span>
+          </button>
+        </div>
+      </header>
+
+      <section class="brain-intro">
+        <h2>宸ヤ笟AI鏁板瓧鍛樺伐锛岃祴鑳芥櫤閫犳柊绾厓</h2>
+        <p>鍏ぇAI鍔╂墜鍗忓悓浼佷笟绠$悊銆侀攢鍞�侀噰璐�佺敓浜с�佽储鍔″強鏁版嵁鍏ㄩ摼璺�</p>
+        <div class="intro-sign">闃块噷浜� 脳 鍗冮棶澶фā鍨� 脳 鏅鸿兘浣揂I</div>
+      </section>
+
+      <section class="carousel-area">
+        <button type="button" class="nav-btn nav-btn--left" @click="prevCard">
+          <el-icon><ArrowLeftBold /></el-icon>
+        </button>
+
+        <div class="carousel-track">
+          <article
+            v-for="card in visibleCards"
+            :key="card.agent.key"
+            class="agent-card"
+            :class="{ 'agent-card--active': card.offset === 0 }"
+            :style="getCardStyle(card.offset)"
+            @click="openAssistant(card.realIndex)"
+          >
+            <div class="agent-card__head" :class="{ 'agent-card__head--active': card.offset === 0 }">
+              {{ card.agent.name }}
+            </div>
+
+            <div class="agent-card__body" :class="{ 'agent-card__body--active': card.offset === 0 }">
+              <div class="avatar-shell" :class="{ 'avatar-shell--active': card.offset === 0 }">
+                <div class="avatar-base"></div>
+                <div class="avatar-cut">
+                  <img v-if="card.agent.avatar" class="avatar-cut__img" :src="card.agent.avatar" :alt="card.agent.name" />
+                </div>
+              </div>
+              <div v-if="card.offset === 0" class="highlight-list">
+                <div
+                  v-for="highlight in card.agent.highlights"
+                  :key="highlight"
+                  class="highlight-item"
+                >
+                  {{ highlight }}
+                </div>
+              </div>
+            </div>
+          </article>
+        </div>
+
+        <button type="button" class="nav-btn nav-btn--right" @click="nextCard">
+          <el-icon><ArrowRightBold /></el-icon>
+        </button>
+      </section>
+
+      <section class="brain-footer">
+        <div class="footer-grid-overlay"></div>
+
+        <div class="footer-metrics">
+          <article class="footer-metric">
+            <span class="footer-metric__label">鍦ㄧ嚎鏅鸿兘浣�</span>
+            <strong class="footer-metric__value">{{ agents.length }}涓�</strong>
+            <small class="footer-metric__hint">鍏ㄩ摼璺崗鍚岃繍琛�</small>
+          </article>
+
+          <article class="footer-metric footer-metric--focus">
+            <span class="footer-metric__label">褰撳墠鐒︾偣</span>
+            <strong class="footer-metric__value">{{ getFooterAgentName(focusAgent.name) }}</strong>
+            <small class="footer-metric__hint">{{ focusAgent.highlights?.[0] || "鏅鸿兘鍒嗘瀽鑱斿姩" }}</small>
+          </article>
+
+          <article class="footer-metric footer-metric--period">
+            <span class="footer-metric__label">杞挱鍛ㄦ湡</span>
+            <strong class="footer-metric__value">{{ carouselSecondsText }}</strong>
+            <div class="footer-period-control">
+              <button type="button" class="period-btn" @click="adjustCarouselSeconds(-0.5)">-</button>
+              <input
+                v-model.number="carouselSeconds"
+                class="period-input"
+                type="number"
+                min="2"
+                max="12"
+                step="0.5"
+              />
+              <span class="period-unit">s</span>
+              <button type="button" class="period-btn" @click="adjustCarouselSeconds(0.5)">+</button>
+            </div>
+            <input
+              v-model.number="carouselSeconds"
+              class="footer-period-slider"
+              type="range"
+              min="2"
+              max="12"
+              step="0.5"
+            />
+            <small class="footer-metric__hint">鍙墜鍔ㄨ缃� 2.0s - 12.0s</small>
+          </article>
+        </div>
+
+        <div class="footer-rail">
+          <div class="footer-rail__line">
+            <span class="footer-rail__flow"></span>
+          </div>
+          <div class="footer-rail__nodes">
+            <button
+              v-for="node in footerNodes"
+              :key="node.key"
+              type="button"
+              class="footer-node"
+              :class="{ 'footer-node--active': node.index === carouselIndex }"
+              @click="openAssistant(node.index)"
+            >
+              <span class="footer-node__dot"></span>
+              <span class="footer-node__name">{{ getFooterAgentName(node.name) }}</span>
+            </button>
+          </div>
+        </div>
+      </section>
+    </section>
+
+    <AiAssistantWorkspace
+      :visible="fullscreenVisible"
+      :agent="currentAgent"
+      @close="closeFullscreen"
+    />
+  </div>
+</template>
+
+<script setup>
+import { computed, onBeforeUnmount, onMounted, ref, watch } from "vue";
+import { useRouter } from "vue-router";
+import { ArrowLeftBold, ArrowRightBold } from "@element-plus/icons-vue";
+import AiAssistantWorkspace from "./components/AiAssistantWorkspace.vue";
+import todoAvatar from "@/assets/AI/寰呭姙鍔╂墜.png";
+import salesAvatar from "@/assets/AI/閿�鍞姪鎵�.png";
+import purchaseAvatar from "@/assets/AI/閲囪喘鍔╂墜.png";
+import productionAvatar from "@/assets/AI/鐢熶骇鍔╂墜.png";
+import financeAvatar from "@/assets/AI/璐㈠姟鍔╂墜.png";
+
+const router = useRouter();
+
+const agents = [
+  {
+    key: "general",
+    name: "AI寰呭姙鍔╂墜",
+    highlights: ["璺ㄦā鍧楁祦绋嬭瘖鏂�", "缁忚惀椋庨櫓鏅鸿兘鎻愰啋"],
+  },
+  {
+    key: "sales",
+    name: "AI閿�鍞姪鎵�",
+    highlights: ["瀹㈡埛娴佸け椋庨櫓鍒嗘瀽", "鍥炴涓庢姤浠风瓥鐣ュ缓璁�"],
+  },
+  {
+    key: "purchase",
+    name: "AI閲囪喘鍔╂墜",
+    highlights: ["渚涘簲閾炬寚鏍囧垎鏋�", "閲囪喘璁㈠崟鏅鸿兘鐢熸垚"],
+  },
+  {
+    key: "production",
+    name: "AI鐢熶骇鍔╂墜",
+    highlights: ["宸ュ簭鐡堕瀹氫綅", "浜ц兘涓庢姤搴熸櫤鑳介璀�"],
+  },
+  {
+    key: "finance",
+    name: "AI璐㈠姟鍔╂墜",
+    highlights: ["鐜伴噾娴佸帇鍔涢鍒�", "璐圭敤缁撴瀯鏅鸿兘鍒嗘瀽"],
+  },
+];
+
+const avatarByAgentKey = {
+  general: todoAvatar,
+  sales: salesAvatar,
+  purchase: purchaseAvatar,
+  production: productionAvatar,
+  finance: financeAvatar,
+};
+
+for (let i = agents.length - 1; i >= 0; i -= 1) {
+  const agent = agents[i];
+  const avatar = avatarByAgentKey[agent.key];
+  if (!avatar) {
+    agents.splice(i, 1);
+    continue;
+  }
+  agent.avatar = avatar;
+}
+
+const carouselIndex = ref(Math.min(2, Math.max(agents.length - 1, 0)));
+const fullscreenVisible = ref(false);
+const screenRef = ref(null);
+const carouselIntervalMs = ref(4500);
+
+let carouselTimer = null;
+
+const fallbackAgent = {
+  key: "fallback",
+  name: "AI鍔╂墜",
+  avatar: "",
+  highlights: [],
+};
+
+const currentAgent = computed(() => agents[carouselIndex.value] || agents[0] || fallbackAgent);
+const focusAgent = computed(() => currentAgent.value || fallbackAgent);
+const footerNodes = computed(() =>
+  agents.map((agent, index) => ({
+    key: agent.key,
+    name: agent.name,
+    index,
+  }))
+);
+const carouselSeconds = computed({
+  get: () => Number((carouselIntervalMs.value / 1000).toFixed(1)),
+  set: (value) => {
+    const next = Number(value);
+    if (!Number.isFinite(next)) return;
+    const clamped = Math.max(2, Math.min(12, Math.round(next * 2) / 2));
+    carouselIntervalMs.value = Math.round(clamped * 1000);
+  },
+});
+const carouselSecondsText = computed(() => `${carouselSeconds.value.toFixed(1)}s`);
+
+const weekLabel = computed(() => {
+  const weekMap = ["鏄熸湡鏃�", "鏄熸湡涓�", "鏄熸湡浜�", "鏄熸湡涓�", "鏄熸湡鍥�", "鏄熸湡浜�", "鏄熸湡鍏�"];
+  return weekMap[new Date().getDay()];
+});
+
+const dateLabel = computed(() => {
+  const now = new Date();
+  const year = now.getFullYear();
+  const month = String(now.getMonth() + 1).padStart(2, "0");
+  const day = String(now.getDate()).padStart(2, "0");
+  return `${year}骞�${month}鏈�${day}鏃;
+});
+
+const visibleCards = computed(() => {
+  const total = agents.length;
+  return agents
+    .map((agent, index) => {
+      let offset = index - carouselIndex.value;
+      if (offset > total / 2) offset -= total;
+      if (offset < -total / 2) offset += total;
+      return { agent, offset, realIndex: index };
+    })
+    .filter((item) => Math.abs(item.offset) <= 2)
+    .sort((a, b) => a.offset - b.offset);
+});
+
+function getCardStyle(offset) {
+  const distance = Math.abs(offset);
+  const scale = distance === 0 ? 1 : distance === 1 ? 0.88 : 0.78;
+  const opacity = distance === 0 ? 1 : distance === 1 ? 0.92 : 0.76;
+  return {
+    transform: `translateX(${offset * 340}px) scale(${scale})`,
+    zIndex: String(50 - distance),
+    opacity,
+  };
+}
+
+function getFooterAgentName(name) {
+  return String(name || "AI鍔╂墜").replace(/^AI/, "");
+}
+
+function adjustCarouselSeconds(delta) {
+  carouselSeconds.value = carouselSeconds.value + delta;
+}
+
+function prevCard() {
+  const total = agents.length;
+  if (!total) return;
+  carouselIndex.value = (carouselIndex.value - 1 + total) % total;
+}
+
+function nextCard() {
+  const total = agents.length;
+  if (!total) return;
+  carouselIndex.value = (carouselIndex.value + 1) % total;
+}
+
+async function enterBrowserFullscreen() {
+  if (document.fullscreenElement) return;
+  const target = screenRef.value || document.documentElement;
+  if (!target || typeof target.requestFullscreen !== "function") return;
+  try {
+    await target.requestFullscreen();
+  } catch (error) {
+    // Ignore: browser may block fullscreen when there is no direct user activation.
+  }
+}
+
+async function exitBrowserFullscreen() {
+  if (!document.fullscreenElement || typeof document.exitFullscreen !== "function") return;
+  try {
+    await document.exitFullscreen();
+  } catch (error) {
+    // Ignore fullscreen exit failures.
+  }
+}
+
+function goBack() {
+  closeFullscreen();
+  exitBrowserFullscreen();
+  if (window.history.length > 1) {
+    router.back();
+    return;
+  }
+  router.push("/index");
+}
+
+function openAssistant(index) {
+  if (!agents.length) return;
+  carouselIndex.value = index;
+  fullscreenVisible.value = true;
+}
+
+function closeFullscreen() {
+  fullscreenVisible.value = false;
+}
+
+function startCarousel() {
+  stopCarousel();
+  if (fullscreenVisible.value) return;
+  carouselTimer = window.setInterval(() => {
+    nextCard();
+  }, carouselIntervalMs.value);
+}
+
+function stopCarousel() {
+  if (carouselTimer) {
+    window.clearInterval(carouselTimer);
+    carouselTimer = null;
+  }
+}
+
+function handleEscClose(event) {
+  if (event.key === "Escape" && fullscreenVisible.value) {
+    closeFullscreen();
+  }
+}
+
+watch(
+  () => fullscreenVisible.value,
+  (opened) => {
+    if (opened) {
+      stopCarousel();
+    } else {
+      startCarousel();
+    }
+  }
+);
+
+watch(
+  () => carouselIntervalMs.value,
+  () => {
+    if (!fullscreenVisible.value) {
+      startCarousel();
+    }
+  }
+);
+
+onMounted(() => {
+  startCarousel();
+  window.addEventListener("keydown", handleEscClose);
+  window.requestAnimationFrame(() => {
+    enterBrowserFullscreen();
+  });
+});
+
+onBeforeUnmount(() => {
+  stopCarousel();
+  window.removeEventListener("keydown", handleEscClose);
+  exitBrowserFullscreen();
+});
+</script>
+
+<style scoped>
+.ai-brain-screen {
+  position: fixed;
+  inset: 0;
+  z-index: 1900;
+  padding: 10px;
+  overflow: hidden;
+  background: var(--app-bg);
+}
+
+.brain-stage {
+  position: relative;
+  height: 100%;
+  min-height: 100%;
+  border-radius: 22px;
+  border: 1px solid var(--surface-border);
+  background:
+    radial-gradient(circle at 14% 8%, rgba(31, 122, 114, 0.14), transparent 40%),
+    radial-gradient(circle at 86% 12%, rgba(30, 91, 255, 0.1), transparent 42%),
+    linear-gradient(180deg, rgba(255, 255, 255, 0.95), rgba(245, 249, 247, 0.94)),
+    repeating-linear-gradient(
+      135deg,
+      rgba(255, 255, 255, 0.05) 0,
+      rgba(255, 255, 255, 0.05) 14px,
+      rgba(31, 122, 114, 0.03) 14px,
+      rgba(31, 122, 114, 0.03) 28px
+    );
+  box-shadow: var(--shadow-sm);
+}
+
+.brain-head {
+  display: grid;
+  grid-template-columns: 220px minmax(0, 1fr) 180px;
+  align-items: center;
+  padding: 12px 18px 0;
+}
+
+.head-date {
+  color: var(--text-secondary);
+  font-size: 24px;
+  font-weight: 600;
+}
+
+.head-date p {
+  margin: 0;
+  line-height: 1.2;
+}
+
+.head-title {
+  justify-self: center;
+  width: min(760px, 95%);
+  height: 68px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  border-radius: 0 0 46px 46px;
+  color: #fff;
+  font-size: 42px;
+  font-style: italic;
+  font-weight: 700;
+  letter-spacing: 1px;
+  background: linear-gradient(135deg, #1f7a72 0%, #1e5bff 100%);
+  box-shadow: 0 16px 30px rgba(31, 122, 114, 0.24);
+}
+
+.head-actions {
+  justify-self: end;
+}
+
+.head-back-btn {
+  height: 40px;
+  padding: 0 14px;
+  display: inline-flex;
+  align-items: center;
+  gap: 4px;
+  border: none;
+  border-radius: 999px;
+  font-size: 16px;
+  font-weight: 600;
+  color: var(--colorPrimary);
+  background: var(--surface-base);
+  box-shadow: 0 8px 18px rgba(31, 49, 38, 0.12);
+  cursor: pointer;
+}
+
+.brain-intro {
+  text-align: center;
+  margin-top: 34px;
+}
+
+.brain-intro h2 {
+  margin: 0;
+  font-size: 44px;
+  font-style: italic;
+  font-weight: 700;
+  color: var(--text-primary);
+}
+
+.brain-intro p {
+  margin: 12px 0 10px;
+  font-size: 28px;
+  color: var(--text-secondary);
+}
+
+.intro-sign {
+  display: inline-block;
+  padding: 6px 18px;
+  border-radius: 999px;
+  font-size: 24px;
+  font-weight: 700;
+  color: #1e5bff;
+  background: rgba(255, 255, 255, 0.82);
+  border: 1px solid rgba(30, 91, 255, 0.18);
+}
+
+.carousel-area {
+  position: relative;
+  margin-top: 34px;
+  padding: 0 72px 12px;
+}
+
+.carousel-track {
+  position: relative;
+  height: 500px;
+  overflow: hidden;
+}
+
+.brain-footer {
+  position: relative;
+  margin: 0 72px;
+  height: clamp(226px, 25vh,0);
+  border-radius: 18px;
+  border: 1px solid rgba(31, 122, 114, 0.28);
+  background:
+    linear-gradient(120deg, rgba(31, 122, 114, 0.14), rgba(30, 91, 255, 0.14)),
+    linear-gradient(180deg, rgba(255, 255, 255, 0.92), rgba(236, 244, 249, 0.9));
+  box-shadow:
+    0 16px 34px rgba(31, 81, 131, 0.12),
+    inset 0 1px 0 rgba(255, 255, 255, 0.72);
+  overflow: hidden;
+}
+
+.brain-footer::before {
+  content: "";
+  position: absolute;
+  left: -22%;
+  bottom: -120%;
+  width: 52%;
+  height: 260%;
+  background: radial-gradient(ellipse at center, rgba(30, 91, 255, 0.2) 0%, rgba(30, 91, 255, 0) 72%);
+  pointer-events: none;
+}
+
+.brain-footer::after {
+  content: "";
+  position: absolute;
+  inset: 0;
+  background: linear-gradient(110deg, transparent 12%, rgba(255, 255, 255, 0.24) 38%, transparent 64%);
+  transform: translateX(-120%);
+  animation: footerSweep 5.8s linear infinite;
+  pointer-events: none;
+}
+
+.footer-grid-overlay {
+  position: absolute;
+  inset: 0;
+  background:
+    repeating-linear-gradient(
+      90deg,
+      rgba(31, 122, 114, 0.07) 0,
+      rgba(31, 122, 114, 0.07) 1px,
+      transparent 1px,
+      transparent 36px
+    ),
+    repeating-linear-gradient(
+      0deg,
+      rgba(30, 91, 255, 0.06) 0,
+      rgba(30, 91, 255, 0.06) 1px,
+      transparent 1px,
+      transparent 28px
+    );
+  opacity: 0.72;
+  pointer-events: none;
+}
+
+.footer-metrics {
+  position: relative;
+  z-index: 2;
+  padding: 14px 20px 72px;
+  display: grid;
+  grid-template-columns: repeat(3, minmax(0, 1fr));
+  gap: 12px;
+}
+
+.footer-metric {
+  min-height: 76px;
+  border-radius: 12px;
+  padding: 10px 14px;
+  border: 1px solid rgba(37, 124, 188, 0.2);
+  background: linear-gradient(180deg, rgba(255, 255, 255, 0.88), rgba(245, 250, 255, 0.82));
+  box-shadow: 0 10px 18px rgba(29, 83, 134, 0.08);
+  display: grid;
+  grid-template-rows: auto auto 1fr;
+  gap: 4px;
+}
+
+.footer-metric--focus {
+  border-color: rgba(38, 122, 194, 0.34);
+  box-shadow:
+    0 12px 22px rgba(30, 91, 255, 0.12),
+    inset 0 0 0 1px rgba(85, 148, 232, 0.2);
+}
+
+.footer-metric__label {
+  font-size: 14px;
+  color: rgba(38, 72, 108, 0.88);
+  font-weight: 600;
+}
+
+.footer-metric__value {
+  font-size: 30px;
+  line-height: 1;
+  font-style: italic;
+  font-weight: 700;
+  color: #1f5ddf;
+  text-shadow: 0 3px 10px rgba(30, 91, 255, 0.18);
+}
+
+.footer-metric__hint {
+  margin-top: auto;
+  font-size: 13px;
+  color: rgba(52, 89, 128, 0.82);
+}
+
+.footer-metric--period .footer-metric__hint {
+  margin-top: 0;
+  line-height: 1.25;
+}
+
+.footer-metric--period {
+  min-height: 122px;
+  grid-template-rows: auto auto auto auto auto;
+  gap: 6px;
+}
+
+.footer-period-control {
+  display: inline-flex;
+  align-items: center;
+  gap: 8px;
+}
+
+.period-btn {
+  width: 22px;
+  height: 22px;
+  border-radius: 50%;
+  border: 1px solid rgba(38, 112, 183, 0.28);
+  background: rgba(255, 255, 255, 0.9);
+  color: #2054c9;
+  font-size: 14px;
+  font-weight: 700;
+  line-height: 1;
+  cursor: pointer;
+}
+
+.period-input {
+  width: 56px;
+  height: 24px;
+  border-radius: 8px;
+  border: 1px solid rgba(38, 112, 183, 0.24);
+  background: rgba(255, 255, 255, 0.94);
+  color: #1f5ddf;
+  font-size: 13px;
+  font-weight: 600;
+  text-align: center;
+  padding: 0 4px;
+}
+
+.period-unit {
+  font-size: 12px;
+  font-weight: 600;
+  color: rgba(40, 80, 117, 0.86);
+}
+
+.footer-period-slider {
+  width: min(250px, 100%);
+  height: 3px;
+  accent-color: #2a6ded;
+  cursor: pointer;
+}
+
+.footer-rail {
+  position: absolute;
+  left: 20px;
+  right: 20px;
+  bottom: 18px;
+  z-index: 2;
+}
+
+.footer-rail__line {
+  position: relative;
+  height: 2px;
+  border-radius: 999px;
+  background: linear-gradient(90deg, rgba(31, 122, 114, 0.12), rgba(30, 91, 255, 0.6), rgba(31, 122, 114, 0.12));
+  overflow: hidden;
+}
+
+.footer-rail__flow {
+  position: absolute;
+  top: -1px;
+  left: -18%;
+  width: 22%;
+  height: 4px;
+  border-radius: 999px;
+  background: linear-gradient(90deg, rgba(31, 122, 114, 0), rgba(59, 146, 244, 0.92), rgba(30, 91, 255, 0));
+  filter: blur(0.2px);
+  animation: railFlow 3.1s ease-in-out infinite;
+}
+
+.footer-rail__nodes {
+  margin-top: 12px;
+  display: grid;
+  grid-template-columns: repeat(5, minmax(0, 1fr));
+  gap: 8px;
+}
+
+.footer-node {
+  height: 34px;
+  border: 1px solid rgba(38, 112, 183, 0.18);
+  border-radius: 999px;
+  background: rgba(255, 255, 255, 0.76);
+  display: inline-flex;
+  align-items: center;
+  justify-content: center;
+  gap: 8px;
+  color: rgba(40, 80, 117, 0.92);
+  font-size: 14px;
+  font-weight: 600;
+  cursor: pointer;
+  transition: all 0.26s ease;
+}
+
+.footer-node:hover {
+  transform: translateY(-1px);
+  border-color: rgba(31, 122, 114, 0.34);
+  box-shadow: 0 8px 14px rgba(31, 122, 114, 0.14);
+}
+
+.footer-node--active {
+  color: #fff;
+  border-color: transparent;
+  background: linear-gradient(135deg, rgba(31, 122, 114, 0.94), rgba(30, 91, 255, 0.94));
+  box-shadow: 0 10px 18px rgba(30, 91, 255, 0.28);
+}
+
+.footer-node__dot {
+  width: 8px;
+  height: 8px;
+  border-radius: 50%;
+  background: rgba(30, 91, 255, 0.72);
+  box-shadow: 0 0 10px rgba(30, 91, 255, 0.52);
+}
+
+.footer-node--active .footer-node__dot {
+  background: #fff;
+  box-shadow: 0 0 12px rgba(255, 255, 255, 0.72);
+  animation: nodePulse 1.4s ease-in-out infinite;
+}
+
+.agent-card {
+  position: absolute;
+  left: 50%;
+  top: 0;
+  width: 460px;
+  margin-left: -230px;
+  cursor: pointer;
+  transform-origin: center bottom;
+  transition: transform 0.35s ease, opacity 0.35s ease;
+}
+
+.agent-card__head {
+  height: 56px;
+  border-radius: 12px 12px 0 0;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 28px;
+  color: #fff;
+  font-weight: 700;
+  background: linear-gradient(135deg, #1f7a72 0%, #1e5bff 100%);
+}
+
+.agent-card__head--active {
+  box-shadow:
+    0 12px 22px rgba(30, 91, 255, 0.26),
+    inset 0 0 0 1px rgba(255, 255, 255, 0.28);
+  position: relative;
+}
+
+.agent-card__head--active::after {
+  content: "";
+  position: absolute;
+  left: 12px;
+  right: 12px;
+  bottom: 6px;
+  height: 3px;
+  border-radius: 999px;
+  background: linear-gradient(90deg, rgba(255, 255, 255, 0.22), rgba(255, 255, 255, 0.96), rgba(255, 255, 255, 0.22));
+}
+
+.agent-card__body {
+  position: relative;
+  height: 430px;
+  border: 1px solid var(--surface-border-strong);
+  border-top: none;
+  border-radius: 0 0 20px 20px;
+  background: rgba(255, 255, 255, 0.96);
+  overflow: hidden;
+  display: flex;
+  justify-content: center;
+  align-items: flex-end;
+  isolation: isolate;
+  box-shadow: 0 12px 24px rgba(31, 49, 38, 0.1);
+}
+
+.agent-card__body--active {
+  background: linear-gradient(180deg, rgba(248, 252, 251, 0.96), rgba(225, 241, 250, 0.9));
+  border-color: rgba(31, 122, 114, 0.35);
+}
+
+.agent-card__body--active::after {
+  content: "";
+  position: absolute;
+  inset: 0;
+  background: linear-gradient(108deg, transparent 28%, rgba(255, 255, 255, 0.34) 50%, transparent 72%);
+  transform: translateX(-125%);
+  animation: bodySweep 3.6s linear infinite;
+  pointer-events: none;
+  z-index: 1;
+}
+
+.avatar-shell {
+  position: relative;
+  width: 248px;
+  height: 430px;
+  display: flex;
+  align-items: flex-end;
+  justify-content: center;
+  --base-core: rgba(53, 143, 222, 0.4);
+  --base-ring: rgba(39, 122, 201, 0.62);
+  --base-glow: rgba(46, 133, 214, 0.28);
+}
+
+.avatar-shell::before {
+  content: "";
+  position: absolute;
+  left: 50%;
+  bottom: -10px;
+  width: 268px;
+  height: 58px;
+  transform: translateX(-50%);
+  border-radius: 50%;
+  background: radial-gradient(
+    ellipse at center,
+    rgba(55, 140, 219, 0.22) 0%,
+    rgba(55, 140, 219, 0.11) 46%,
+    rgba(55, 140, 219, 0) 74%
+  );
+  filter: blur(2.4px);
+  animation: baseGlow 4.6s ease-in-out infinite;
+  z-index: 1;
+  pointer-events: none;
+}
+
+.avatar-shell::after {
+  content: "";
+  position: absolute;
+  left: 50%;
+  bottom: 0;
+  width: 248px;
+  height: 46px;
+  transform: translateX(-50%);
+  border-radius: 50%;
+  border: 2px solid var(--base-ring);
+  box-shadow:
+    inset 0 0 0 1px rgba(255, 255, 255, 0.64),
+    0 0 24px var(--base-glow);
+  animation: basePulse 3.1s ease-in-out infinite;
+  z-index: 4;
+}
+
+.avatar-base {
+  position: absolute;
+  left: 50%;
+  bottom: 2px;
+  width: 224px;
+  height: 38px;
+  transform: translateX(-50%);
+  z-index: 2;
+  pointer-events: none;
+}
+
+.avatar-base::before {
+  content: "";
+  position: absolute;
+  inset: 0;
+  border-radius: 50%;
+  background:
+    radial-gradient(
+      ellipse at center,
+      rgba(255, 255, 255, 0.96) 0%,
+      rgba(255, 255, 255, 0.92) 36%,
+      var(--base-core) 68%,
+      rgba(38, 118, 195, 0.08) 100%
+    );
+  box-shadow:
+    0 0 30px var(--base-core),
+    0 0 10px rgba(255, 255, 255, 0.34) inset;
+  z-index: 3;
+}
+
+.avatar-base::after {
+  content: "";
+  position: absolute;
+  left: 50%;
+  top: 50%;
+  width: 194px;
+  height: 194px;
+  transform: translate(-50%, -50%);
+  border-radius: 50%;
+  background:
+    conic-gradient(
+      from 180deg,
+      transparent 0deg,
+      var(--base-ring) 48deg,
+      transparent 112deg,
+      var(--base-ring) 208deg,
+      transparent 284deg,
+      rgba(33, 114, 191, 0.48) 332deg,
+      transparent 360deg
+    );
+  -webkit-mask: radial-gradient(circle, transparent 61%, #000 62%, #000 68%, transparent 70%);
+  mask: radial-gradient(circle, transparent 61%, #000 62%, #000 68%, transparent 70%);
+  opacity: 0.62;
+  animation: baseRotate 10.5s linear infinite;
+  z-index: 2;
+}
+
+.avatar-shell--active {
+  --base-core: rgba(50, 141, 217, 0.52);
+  --base-ring: rgba(42, 127, 205, 0.76);
+  --base-glow: rgba(38, 130, 211, 0.38);
+}
+
+.avatar-cut {
+  position: relative;
+  width: 220px;
+  height: 430px;
+  z-index: 6;
+  display: flex;
+  align-items: flex-end;
+  justify-content: center;
+  filter: saturate(1.04) drop-shadow(0 14px 18px rgba(24, 44, 66, 0.14));
+  transform-origin: center 82%;
+  animation: avatarFloat 3.2s ease-in-out infinite;
+}
+
+.avatar-cut__img {
+  width: 100%;
+  height: 100%;
+  object-fit: contain;
+  object-position: center bottom;
+  display: block;
+}
+
+.agent-card--active .avatar-cut {
+  animation-duration: 2.6s;
+}
+
+.highlight-list {
+  position: absolute;
+  right: 10px;
+  top: 14px;
+  display: grid;
+  gap: 8px;
+  width: 220px;
+  z-index: 16;
+}
+
+.highlight-item {
+  border-radius: 10px;
+  padding: 8px 10px;
+  font-size: 18px;
+  line-height: 1.4;
+  color: #fff;
+  background: rgba(33, 49, 63, 0.92);
+  box-shadow: 0 8px 16px rgba(21, 30, 40, 0.22);
+}
+
+.agent-card--active .highlight-item {
+  background: rgba(31, 122, 114, 0.9);
+}
+
+.nav-btn {
+  position: absolute;
+  top: 212px;
+  z-index: 80;
+  width: 50px;
+  height: 50px;
+  border-radius: 50%;
+  border: none;
+  font-size: 30px;
+  color: var(--colorPrimary);
+  background: var(--surface-base);
+  box-shadow: 0 10px 20px rgba(31, 49, 38, 0.16);
+  cursor: pointer;
+}
+
+.nav-btn--left {
+  left: 14px;
+}
+
+.nav-btn--right {
+  right: 14px;
+}
+
+.ai-fullscreen {
+  position: fixed;
+  inset: 0;
+  z-index: 2100;
+  padding: 12px;
+  background: rgba(33, 49, 63, 0.24);
+  backdrop-filter: blur(2px);
+}
+
+.ai-panel {
+  height: 100%;
+  border-radius: 22px;
+  border: 1px solid var(--surface-border);
+  background: linear-gradient(180deg, #f9fcfb 0%, #f0f5f2 100%);
+  display: grid;
+  grid-template-rows: 62px minmax(0, 1fr) 110px;
+  box-shadow: var(--shadow-md);
+}
+
+.ai-panel__top {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 0 24px;
+}
+
+.ai-brand {
+  font-size: 34px;
+  color: var(--text-primary);
+  font-weight: 700;
+}
+
+.ai-close {
+  width: 40px;
+  height: 40px;
+  border: none;
+  border-radius: 50%;
+  background: transparent;
+  font-size: 30px;
+  color: var(--text-secondary);
+  cursor: pointer;
+}
+
+.ai-panel__center {
+  padding: 8px 20px 10px;
+  display: grid;
+  grid-template-rows: 120px 290px minmax(0, 1fr);
+  gap: 10px;
+  min-height: 0;
+}
+
+.welcome-card {
+  border-radius: 14px;
+  background: linear-gradient(135deg, rgba(232, 244, 242, 0.95), rgba(230, 237, 250, 0.9));
+  padding: 16px 18px;
+  display: flex;
+  justify-content: space-between;
+  gap: 12px;
+  border: 1px solid var(--surface-border);
+}
+
+.welcome-card__text h3 {
+  margin: 0;
+  font-size: 28px;
+  color: var(--text-primary);
+}
+
+.welcome-card__text p {
+  margin: 8px 0 0;
+  font-size: 20px;
+  color: var(--text-secondary);
+}
+
+.mini-avatar {
+  width: 120px;
+  height: 120px;
+  border-radius: 14px;
+  border: 1px solid var(--surface-border);
+  background-color: #fff;
+  background-clip: border-box;
+  overflow: hidden;
+}
+
+.mini-avatar__img {
+  width: 100%;
+  height: 100%;
+  object-fit: contain;
+  object-position: center bottom;
+  display: block;
+}
+
+.recommend-card {
+  border-radius: 14px;
+  border: 1px solid var(--surface-border);
+  background: rgba(255, 255, 255, 0.86);
+  padding: 12px 14px;
+}
+
+.recommend-card__head {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  margin-bottom: 10px;
+  color: var(--text-primary);
+  font-size: 24px;
+  font-weight: 700;
+}
+
+.refresh-btn {
+  border: none;
+  background: transparent;
+  color: var(--text-secondary);
+  font-size: 18px;
+  display: inline-flex;
+  align-items: center;
+  gap: 4px;
+  cursor: pointer;
+}
+
+.recommend-grid {
+  display: grid;
+  grid-template-columns: 1fr 1fr;
+  gap: 8px 18px;
+}
+
+.recommend-item {
+  border: 1px solid var(--surface-border);
+  border-radius: 8px;
+  text-align: left;
+  padding: 8px 10px;
+  font-size: 18px;
+  color: var(--text-secondary);
+  background: #fff;
+  cursor: pointer;
+}
+
+.recommend-item:hover {
+  background: rgba(31, 122, 114, 0.08);
+  color: var(--colorPrimary);
+}
+
+.chat-card {
+  border-radius: 14px;
+  border: 1px solid var(--surface-border);
+  background: #fff;
+  min-height: 0;
+  overflow: hidden;
+}
+
+.chat-empty {
+  height: 100%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  color: var(--text-tertiary);
+  font-size: 18px;
+}
+
+.chat-messages {
+  height: 100%;
+  overflow-y: auto;
+  padding: 14px;
+  display: grid;
+  gap: 10px;
+}
+
+.chat-row {
+  display: flex;
+}
+
+.chat-row--assistant {
+  justify-content: flex-start;
+}
+
+.chat-row--user {
+  justify-content: flex-end;
+}
+
+.chat-bubble {
+  max-width: 72%;
+  border-radius: 12px;
+  padding: 10px 12px;
+  font-size: 18px;
+  line-height: 1.5;
+  white-space: pre-wrap;
+  color: var(--text-primary);
+  background: var(--surface-soft);
+  border: 1px solid var(--surface-border);
+}
+
+.chat-row--user .chat-bubble {
+  color: #fff;
+  background: linear-gradient(135deg, #1f7a72 0%, #1e5bff 100%);
+  border: none;
+}
+
+.ai-panel__input {
+  display: grid;
+  grid-template-columns: minmax(0, 1fr) 130px;
+  gap: 12px;
+  padding: 14px 20px 18px;
+}
+
+.ask-input :deep(.el-input__wrapper) {
+  height: 74px;
+  border-radius: 18px;
+  box-shadow: 0 0 0 1px var(--surface-border) inset;
+  background: #fff;
+}
+
+.ask-input :deep(.el-input__inner) {
+  font-size: 20px;
+}
+
+.send-btn {
+  align-self: center;
+  height: 56px;
+  font-size: 20px;
+  min-width: 98px;
+}
+
+.fade-enter-active,
+.fade-leave-active {
+  transition: opacity 0.2s ease;
+}
+
+.fade-enter-from,
+.fade-leave-to {
+  opacity: 0;
+}
+
+@keyframes avatarFloat {
+  0%,
+  100% {
+    transform: translateY(0);
+  }
+  50% {
+    transform: translateY(-8px);
+  }
+}
+
+@keyframes basePulse {
+  0%,
+  100% {
+    transform: translateX(-50%) scale(1);
+    opacity: 0.88;
+  }
+  50% {
+    transform: translateX(-50%) scale(1.045);
+    opacity: 0.95;
+  }
+}
+
+@keyframes baseRotate {
+  from {
+    transform: translate(-50%, -50%) rotate(0deg);
+  }
+  to {
+    transform: translate(-50%, -50%) rotate(360deg);
+  }
+}
+
+@keyframes baseGlow {
+  0%,
+  100% {
+    transform: translateX(-50%) scaleX(1);
+    opacity: 0.84;
+  }
+  50% {
+    transform: translateX(-50%) scaleX(1.06);
+    opacity: 0.96;
+  }
+}
+
+@keyframes bodySweep {
+  0% {
+    transform: translateX(-125%);
+  }
+  100% {
+    transform: translateX(135%);
+  }
+}
+
+@keyframes footerSweep {
+  0% {
+    transform: translateX(-120%);
+  }
+  100% {
+    transform: translateX(140%);
+  }
+}
+
+@keyframes railFlow {
+  0% {
+    transform: translateX(0);
+    opacity: 0;
+  }
+  20% {
+    opacity: 1;
+  }
+  80% {
+    opacity: 1;
+  }
+  100% {
+    transform: translateX(520%);
+    opacity: 0;
+  }
+}
+
+@keyframes nodePulse {
+  0%,
+  100% {
+    transform: scale(1);
+  }
+  50% {
+    transform: scale(1.25);
+  }
+}
+
+@media (max-width: 1600px) {
+  .head-title {
+    font-size: 34px;
+    height: 60px;
+  }
+
+  .brain-intro h2 {
+    font-size: 36px;
+  }
+
+  .brain-intro p {
+    font-size: 22px;
+  }
+
+  .intro-sign {
+    font-size: 20px;
+  }
+
+  .agent-card {
+    width: 380px;
+    margin-left: -190px;
+  }
+
+  .agent-card__head {
+    font-size: 24px;
+    height: 54px;
+  }
+
+  .agent-card__body {
+    height: 390px;
+  }
+
+  .highlight-list {
+    width: 184px;
+  }
+
+  .highlight-item {
+    font-size: 15px;
+  }
+
+  .avatar-shell {
+    width: 220px;
+    height: 390px;
+  }
+
+  .avatar-cut {
+    width: 202px;
+    height: 390px;
+  }
+
+  .avatar-base {
+    width: 194px;
+    height: 34px;
+  }
+
+  .avatar-base::after {
+    width: 164px;
+    height: 164px;
+  }
+
+  .avatar-shell::before {
+    width: 236px;
+    height: 48px;
+    bottom: -9px;
+  }
+
+  .avatar-shell::after {
+    width: 220px;
+    height: 40px;
+    bottom: 0;
+  }
+
+  .brain-footer {
+    margin: 0 52px;
+    height: clamp(210px, 23vh, 264px);
+  }
+
+  .footer-metrics {
+    padding: 12px 14px 66px;
+    gap: 8px;
+  }
+
+  .footer-metric {
+    min-height: 66px;
+    padding: 8px 10px;
+  }
+
+  .footer-metric--period {
+    min-height: 108px;
+    gap: 4px;
+  }
+
+  .footer-metric__label {
+    font-size: 12px;
+  }
+
+  .footer-metric__value {
+    font-size: 24px;
+  }
+
+  .footer-metric__hint {
+    font-size: 11px;
+  }
+
+  .footer-period-control {
+    gap: 6px;
+  }
+
+  .period-btn {
+    width: 20px;
+    height: 20px;
+    font-size: 12px;
+  }
+
+  .period-input {
+    width: 50px;
+    height: 22px;
+    font-size: 12px;
+  }
+
+  .footer-period-slider {
+    width: 100%;
+  }
+
+  .footer-rail {
+    left: 14px;
+    right: 14px;
+    bottom: 14px;
+  }
+
+  .footer-rail__nodes {
+    margin-top: 10px;
+    gap: 6px;
+  }
+
+  .footer-node {
+    height: 30px;
+    font-size: 12px;
+    gap: 6px;
+  }
+
+  .footer-node__dot {
+    width: 7px;
+    height: 7px;
+  }
+
+  .ai-brand {
+    font-size: 28px;
+  }
+
+  .welcome-card__text h3,
+  .recommend-card__head {
+    font-size: 22px;
+  }
+
+  .welcome-card__text p,
+  .recommend-item,
+  .chat-bubble,
+  .refresh-btn,
+  .chat-empty,
+  .ask-input :deep(.el-input__inner),
+  .send-btn {
+    font-size: 16px;
+  }
+}
+</style>
diff --git a/src/views/collaborativeApproval/approvalProcess/components/approvalDia.vue b/src/views/collaborativeApproval/approvalProcess/components/approvalDia.vue
index 1269621..0605fe5 100644
--- a/src/views/collaborativeApproval/approvalProcess/components/approvalDia.vue
+++ b/src/views/collaborativeApproval/approvalProcess/components/approvalDia.vue
@@ -1,85 +1,103 @@
 <template>
   <div>
-    <el-dialog
-      v-model="dialogFormVisible"
-      :title="operationType === 'approval' ? '瀹℃壒' : '璇︽儏'"
-      width="700px"
-      @close="closeDia"
-    >
-			<el-form :model="form" label-width="140px" label-position="top" ref="formRef">
-				<el-row>
-					<el-col :span="24">
-						<el-form-item label="娴佺▼缂栧彿锛�" prop="approveId">
-							<el-input v-model="form.approveId" placeholder="鑷姩缂栧彿" clearable disabled/>
-						</el-form-item>
-					</el-col>
-				</el-row>
-				<el-row>
-					<el-col :span="24">
-						<el-form-item label="鐢宠閮ㄩ棬锛�">
-							<el-select
-								disabled
-								v-model="form.approveDeptId"
-								placeholder="閫夋嫨閮ㄩ棬"
-							>
-								<el-option
-									v-for="user in productOptions"
-									:key="user.deptId"
-									:label="user.deptName"
-									:value="user.deptId"
-								/>
-							</el-select>
-						</el-form-item>
-					</el-col>
-				</el-row>
-				<el-row v-if="!isQuotationApproval && !isPurchaseApproval">
-					<el-col :span="24">
-						<el-form-item :label="props.approveType == 5 ? '閲囪喘鍚堝悓鍙凤細' : '瀹℃壒浜嬬敱锛�'" prop="approveReason">
-							<el-input v-model="form.approveReason" placeholder="璇疯緭鍏�" clearable type="textarea" disabled/>
-						</el-form-item>
-					</el-col>
-				</el-row>
-			</el-form>
-
+    <el-dialog v-model="dialogFormVisible"
+               :title="operationType === 'approval' ? '瀹℃壒' : '璇︽儏'"
+               width="700px"
+               @close="closeDia">
+      <el-form :model="form"
+               label-width="140px"
+               label-position="top"
+               ref="formRef">
+        <el-row>
+          <el-col :span="24">
+            <el-form-item label="娴佺▼缂栧彿锛�"
+                          prop="approveId">
+              <el-input v-model="form.approveId"
+                        placeholder="鑷姩缂栧彿"
+                        clearable
+                        disabled />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="24">
+            <el-form-item label="鐢宠閮ㄩ棬锛�">
+              <el-select disabled
+                         v-model="form.approveDeptId"
+                         placeholder="閫夋嫨閮ㄩ棬">
+                <el-option v-for="user in productOptions"
+                           :key="user.deptId"
+                           :label="user.deptName"
+                           :value="user.deptId" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row v-if="!isQuotationApproval && !isPurchaseApproval">
+          <el-col :span="24">
+            <el-form-item :label="props.approveType == 5 ? '閲囪喘鍚堝悓鍙凤細' : '瀹℃壒浜嬬敱锛�'"
+                          prop="approveReason">
+              <el-input v-model="form.approveReason"
+                        placeholder="璇疯緭鍏�"
+                        clearable
+                        type="textarea"
+                        disabled />
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
       <!-- 鎶ヤ环瀹℃壒锛氬睍绀烘姤浠疯鎯咃紙澶嶇敤閿�鍞姤浠�"鏌ョ湅璇︽儏瀵硅瘽妗�"鍐呭缁撴瀯锛� -->
-      <div v-if="isQuotationApproval" style="margin: 10px 0 18px;">
+      <div v-if="isQuotationApproval"
+           style="margin: 10px 0 18px;">
         <el-divider content-position="left">鎶ヤ环璇︽儏</el-divider>
-        <el-skeleton :loading="quotationLoading" animated>
+        <el-skeleton :loading="quotationLoading"
+                     animated>
           <template #template>
-            <el-skeleton-item variant="h3" style="width: 30%" />
-            <el-skeleton-item variant="text" style="width: 100%" />
-            <el-skeleton-item variant="text" style="width: 100%" />
+            <el-skeleton-item variant="h3"
+                              style="width: 30%" />
+            <el-skeleton-item variant="text"
+                              style="width: 100%" />
+            <el-skeleton-item variant="text"
+                              style="width: 100%" />
           </template>
           <template #default>
-            <el-empty v-if="!currentQuotation || !currentQuotation.quotationNo" description="鏈煡璇㈠埌瀵瑰簲鎶ヤ环璇︽儏" />
+            <el-empty v-if="!currentQuotation || !currentQuotation.quotationNo"
+                      description="鏈煡璇㈠埌瀵瑰簲鎶ヤ环璇︽儏" />
             <template v-else>
-              <el-descriptions :column="2" border>
+              <el-descriptions :column="2"
+                               border>
                 <el-descriptions-item label="鎶ヤ环鍗曞彿">{{ currentQuotation.quotationNo }}</el-descriptions-item>
                 <el-descriptions-item label="瀹㈡埛鍚嶇О">{{ currentQuotation.customer }}</el-descriptions-item>
                 <el-descriptions-item label="涓氬姟鍛�">{{ currentQuotation.salesperson }}</el-descriptions-item>
                 <el-descriptions-item label="鎶ヤ环鏃ユ湡">{{ currentQuotation.quotationDate }}</el-descriptions-item>
                 <el-descriptions-item label="鏈夋晥鏈熻嚦">{{ currentQuotation.validDate }}</el-descriptions-item>
                 <el-descriptions-item label="浠樻鏂瑰紡">{{ currentQuotation.paymentMethod }}</el-descriptions-item>
-                <el-descriptions-item label="鎶ヤ环鎬婚" :span="2">
+                <el-descriptions-item label="鎶ヤ环鎬婚"
+                                      :span="2">
                   <span style="font-size: 18px; color: #e6a23c; font-weight: bold;">
                     楼{{ Number(currentQuotation.totalAmount ?? 0).toFixed(2) }}
                   </span>
                 </el-descriptions-item>
               </el-descriptions>
-
               <div style="margin-top: 20px;">
                 <h4>浜у搧鏄庣粏</h4>
-                <el-table :data="currentQuotation.products || []" border style="width: 100%">
-                  <el-table-column prop="product" label="浜у搧鍚嶇О" />
-                  <el-table-column prop="specification" label="瑙勬牸鍨嬪彿" />
-                  <el-table-column prop="unit" label="鍗曚綅" />
-                  <el-table-column prop="unitPrice" label="鍗曚环">
+                <el-table :data="currentQuotation.products || []"
+                          border
+                          style="width: 100%">
+                  <el-table-column prop="product"
+                                   label="浜у搧鍚嶇О" />
+                  <el-table-column prop="specification"
+                                   label="瑙勬牸鍨嬪彿" />
+                  <el-table-column prop="unit"
+                                   label="鍗曚綅" />
+                  <el-table-column prop="unitPrice"
+                                   label="鍗曚环">
                     <template #default="scope">楼{{ Number(scope.row.unitPrice ?? 0).toFixed(2) }}</template>
                   </el-table-column>
                 </el-table>
               </div>
-
-              <div v-if="currentQuotation.remark" style="margin-top: 20px;">
+              <div v-if="currentQuotation.remark"
+                   style="margin-top: 20px;">
                 <h4>澶囨敞</h4>
                 <p>{{ currentQuotation.remark }}</p>
               </div>
@@ -87,20 +105,26 @@
           </template>
         </el-skeleton>
       </div>
-
       <!-- 閲囪喘瀹℃壒锛氬睍绀洪噰璐鎯� -->
-      <div v-if="isPurchaseApproval" style="margin: 10px 0 18px;">
+      <div v-if="isPurchaseApproval"
+           style="margin: 10px 0 18px;">
         <el-divider content-position="left">閲囪喘璇︽儏</el-divider>
-        <el-skeleton :loading="purchaseLoading" animated>
+        <el-skeleton :loading="purchaseLoading"
+                     animated>
           <template #template>
-            <el-skeleton-item variant="h3" style="width: 30%" />
-            <el-skeleton-item variant="text" style="width: 100%" />
-            <el-skeleton-item variant="text" style="width: 100%" />
+            <el-skeleton-item variant="h3"
+                              style="width: 30%" />
+            <el-skeleton-item variant="text"
+                              style="width: 100%" />
+            <el-skeleton-item variant="text"
+                              style="width: 100%" />
           </template>
           <template #default>
-            <el-empty v-if="!currentPurchase || !currentPurchase.purchaseContractNumber" description="鏈煡璇㈠埌瀵瑰簲閲囪喘璇︽儏" />
+            <el-empty v-if="!currentPurchase || !currentPurchase.purchaseContractNumber"
+                      description="鏈煡璇㈠埌瀵瑰簲閲囪喘璇︽儏" />
             <template v-else>
-              <el-descriptions :column="2" border>
+              <el-descriptions :column="2"
+                               border>
                 <el-descriptions-item label="閲囪喘鍚堝悓鍙�">{{ currentPurchase.purchaseContractNumber }}</el-descriptions-item>
                 <el-descriptions-item label="渚涘簲鍟嗗悕绉�">{{ currentPurchase.supplierName }}</el-descriptions-item>
                 <el-descriptions-item label="椤圭洰鍚嶇О">{{ currentPurchase.projectName }}</el-descriptions-item>
@@ -108,24 +132,32 @@
                 <el-descriptions-item label="绛捐鏃ユ湡">{{ currentPurchase.executionDate }}</el-descriptions-item>
                 <el-descriptions-item label="褰曞叆鏃ユ湡">{{ currentPurchase.entryDate }}</el-descriptions-item>
                 <el-descriptions-item label="浠樻鏂瑰紡">{{ currentPurchase.paymentMethod }}</el-descriptions-item>
-                <el-descriptions-item label="鍚堝悓閲戦" :span="2">
+                <el-descriptions-item label="鍚堝悓閲戦"
+                                      :span="2">
                   <span style="font-size: 18px; color: #e6a23c; font-weight: bold;">
                     楼{{ Number(currentPurchase.contractAmount ?? 0).toFixed(2) }}
                   </span>
                 </el-descriptions-item>
               </el-descriptions>
-
               <div style="margin-top: 20px;">
                 <h4>浜у搧鏄庣粏</h4>
-                <el-table :data="currentPurchase.productData || []" border style="width: 100%">
-                  <el-table-column prop="productCategory" label="浜у搧鍚嶇О" />
-                  <el-table-column prop="specificationModel" label="瑙勬牸鍨嬪彿" />
-                  <el-table-column prop="unit" label="鍗曚綅" />
-                  <el-table-column prop="quantity" label="鏁伴噺" />
-                  <el-table-column prop="taxInclusiveUnitPrice" label="鍚◣鍗曚环">
+                <el-table :data="currentPurchase.productData || []"
+                          border
+                          style="width: 100%">
+                  <el-table-column prop="productCategory"
+                                   label="浜у搧鍚嶇О" />
+                  <el-table-column prop="specificationModel"
+                                   label="瑙勬牸鍨嬪彿" />
+                  <el-table-column prop="unit"
+                                   label="鍗曚綅" />
+                  <el-table-column prop="quantity"
+                                   label="鏁伴噺" />
+                  <el-table-column prop="taxInclusiveUnitPrice"
+                                   label="鍚◣鍗曚环">
                     <template #default="scope">楼{{ Number(scope.row.taxInclusiveUnitPrice ?? 0).toFixed(2) }}</template>
                   </el-table-column>
-                  <el-table-column prop="taxInclusiveTotalPrice" label="鍚◣鎬讳环">
+                  <el-table-column prop="taxInclusiveTotalPrice"
+                                   label="鍚◣鎬讳环">
                     <template #default="scope">楼{{ Number(scope.row.taxInclusiveTotalPrice ?? 0).toFixed(2) }}</template>
                   </el-table-column>
                 </el-table>
@@ -134,52 +166,138 @@
           </template>
         </el-skeleton>
       </div>
-
-      <el-form :model="{ activities }" ref="formRef" label-position="top">
-        <el-steps :active="getActiveStep()" finish-status="success" process-status="process" align-center direction="vertical">
-          <el-step
-            v-for="(activity, index) in activities"
-            :key="index"
-						finish-status="success"
-            :title="getNodeTitle(index, activities.length)"
-            :description="activity.approveNodeUser"
-            :icon="getNodeIcon(activity, index)"
-          >
-						<template #icon>
-							<el-icon v-if="activity.approveNodeStatus === 2" color="red" :size="22"><WarningFilled /></el-icon>
-							<el-icon v-else-if="activity.isShen" color="#1890ff" :size="22"><Edit /></el-icon>
-							<el-icon v-else-if="activity.approveNodeStatus === 1" color="#67C23A" :size="26"><Check /></el-icon>
-							<el-icon v-else color="#C0C4CC" :size="22"><MoreFilled /></el-icon>
-						</template>
+      <!-- 鍙戣揣瀹℃壒锛氬睍绀哄彂璐ц鎯� -->
+      <div v-if="isDeliveryApproval"
+           style="margin: 10px 0 18px;">
+        <el-divider content-position="left">鍙戣揣璇︽儏</el-divider>
+        <el-skeleton :loading="deliveryLoading"
+                     animated>
+          <template #template>
+            <el-skeleton-item variant="h3"
+                              style="width: 30%" />
+            <el-skeleton-item variant="text"
+                              style="width: 100%" />
+            <el-skeleton-item variant="text"
+                              style="width: 100%" />
+          </template>
+          <template #default>
+            <el-empty v-if="!currentDelivery || !currentDelivery.shippingInfo"
+                      description="鏈煡璇㈠埌瀵瑰簲鍙戣揣璇︽儏" />
+            <template v-else>
+              <el-descriptions :column="2"
+                               border>
+                <el-descriptions-item label="閿�鍞鍗�">{{ currentDelivery.shippingInfo.salesContractNo || '--' }}</el-descriptions-item>
+                <el-descriptions-item label="鍙戣揣璁㈠崟鍙�">{{ currentDelivery.shippingInfo.shippingNo || '--' }}</el-descriptions-item>
+                <el-descriptions-item label="瀹㈡埛鍚嶇О">{{ currentDelivery.shippingInfo.customerName || '--' }}</el-descriptions-item>
+                <el-descriptions-item label="鍙戣揣绫诲瀷">{{ currentDelivery.shippingInfo.type || '--' }}</el-descriptions-item>
+                <el-descriptions-item label="鍙戣揣鏃ユ湡">{{ currentDelivery.shippingInfo.shippingDate || '--' }}</el-descriptions-item>
+                <el-descriptions-item label="瀹℃牳鐘舵��">{{ currentDelivery.shippingInfo.status || '--' }}</el-descriptions-item>
+                <el-descriptions-item label="鍙戣揣杞︾墝鍙�">{{ currentDelivery.shippingInfo.shippingCarNumber || '--' }}</el-descriptions-item>
+                <el-descriptions-item label="蹇�掑叕鍙�">{{ currentDelivery.shippingInfo.expressCompany || '--' }}</el-descriptions-item>
+                <el-descriptions-item label="蹇�掑崟鍙�"
+                                      :span="2">{{ currentDelivery.shippingInfo.expressNumber || '--' }}</el-descriptions-item>
+              </el-descriptions>
+              <div style="margin-top: 20px;">
+                <h4>浜у搧鏄庣粏</h4>
+                <el-table :data="deliveryProductList"
+                          border
+                          size="small"
+                          style="width: 100%">
+                  <el-table-column prop="batchNo"
+                                   label="鎵瑰彿"
+                                   show-overflow-tooltip />
+                  <el-table-column prop="productName"
+                                   label="浜у搧鍚嶇О"
+                                   show-overflow-tooltip />
+                  <el-table-column prop="specificationModel"
+                                   label="瑙勬牸鍨嬪彿"
+                                   show-overflow-tooltip />
+                  <el-table-column prop="deliveryQuantity"
+                                   label="鍙戣揣鏁伴噺"
+                                   align="center" />
+                </el-table>
+              </div>
+              <div v-if="currentDelivery.shippingInfo.storageBlobVOs && currentDelivery.shippingInfo.storageBlobVOs.length"
+                   style="margin-top: 20px;">
+                <h4>鍙戣揣鍥剧墖</h4>
+                <ImagePreview :file-list="currentDelivery.shippingInfo.storageBlobVOs" />
+              </div>
+            </template>
+          </template>
+        </el-skeleton>
+      </div>
+      <el-form :model="{ activities }"
+               ref="formRef"
+               label-position="top">
+        <el-steps :active="getActiveStep()"
+                  finish-status="success"
+                  process-status="process"
+                  align-center
+                  direction="vertical">
+          <el-step v-for="(activity, index) in activities"
+                   :key="index"
+                   finish-status="success"
+                   :title="getNodeTitle(index, activities.length)"
+                   :description="activity.approveNodeUser"
+                   :icon="getNodeIcon(activity, index)">
+            <template #icon>
+              <el-icon v-if="activity.approveNodeStatus === 2"
+                       color="red"
+                       :size="22">
+                <WarningFilled />
+              </el-icon>
+              <el-icon v-else-if="activity.isShen"
+                       color="#1890ff"
+                       :size="22">
+                <Edit />
+              </el-icon>
+              <el-icon v-else-if="activity.approveNodeStatus === 1"
+                       color="#67C23A"
+                       :size="26">
+                <Check />
+              </el-icon>
+              <el-icon v-else
+                       color="#C0C4CC"
+                       :size="22">
+                <MoreFilled />
+              </el-icon>
+            </template>
             <template #title>
               <span style="color: #000000">{{ getNodeTitle(index, activities.length) }}</span>
             </template>
             <template #description>
               <div class="node-user">
                 <div class="avatar-wrapper">
-                  <img :src="userStore.avatar" class="user-avatar" alt=""/>
+                  <img :src="userStore.avatar"
+                       class="user-avatar"
+                       alt="" />
                 </div>
                 <span style="color: #000000">{{ activity.approveNodeUser }}-{{activity.isApproval}}</span>
               </div>
-              <div v-if="!activity.isShen" class="node-reason">
+              <div v-if="!activity.isShen"
+                   class="node-reason">
                 <span>瀹℃壒鎰忚锛�</span>{{ activity.approveNodeReason }}
               </div>
               <div v-else-if="activity.isShen">
-                <el-form-item
-                  :prop="'activities.' + index + '.approveNodeReason'"
-                  :rules="[{ required: true, message: '瀹℃壒鎰忚涓嶈兘涓虹┖', trigger: 'blur' }]"
-                >
-                  <el-input v-model="activity.approveNodeReason" clearable type="textarea" :disabled="operationType === 'view'"></el-input>
+                <el-form-item :prop="'activities.' + index + '.approveNodeReason'"
+                              :rules="[{ required: true, message: '瀹℃壒鎰忚涓嶈兘涓虹┖', trigger: 'blur' }]">
+                  <el-input v-model="activity.approveNodeReason"
+                            clearable
+                            type="textarea"
+                            :disabled="operationType === 'view'"></el-input>
                 </el-form-item>
               </div>
             </template>
           </el-step>
         </el-steps>
       </el-form>
-      <template #footer v-if="operationType === 'approval'">
+      <template #footer
+                v-if="operationType === 'approval'">
         <div class="dialog-footer">
-          <el-button type="primary" @click="submitForm(2)">涓嶉�氳繃</el-button>
-          <el-button type="primary" @click="submitForm(1)">閫氳繃</el-button>
+          <el-button type="primary"
+                     @click="submitForm(2)">涓嶉�氳繃</el-button>
+          <el-button type="primary"
+                     @click="submitForm(1)">閫氳繃</el-button>
           <el-button @click="closeDia">鍙栨秷</el-button>
         </div>
       </template>
@@ -188,221 +306,329 @@
 </template>
 
 <script setup>
-import { computed, getCurrentInstance, nextTick, reactive, ref, toRefs } from "vue";
-import {
-	approveProcessDetails,
-	getDept,
-	updateApproveNode
-} from "@/api/collaborativeApproval/approvalProcess.js";
-import useUserStore from "@/store/modules/user.js";
-import { WarningFilled, Edit, Check, MoreFilled } from '@element-plus/icons-vue'
-import { getQuotationList } from "@/api/salesManagement/salesQuotation.js";
-import { getPurchaseByCode } from "@/api/procurementManagement/procurementLedger.js";
-const emit = defineEmits(['close'])
-const { proxy } = getCurrentInstance()
+  import {
+    computed,
+    getCurrentInstance,
+    nextTick,
+    reactive,
+    ref,
+    toRefs,
+  } from "vue";
+  import {
+    approveProcessDetails,
+    getDept,
+    updateApproveNode,
+  } from "@/api/collaborativeApproval/approvalProcess.js";
+  import useUserStore from "@/store/modules/user.js";
+  import {
+    WarningFilled,
+    Edit,
+    Check,
+    MoreFilled,
+  } from "@element-plus/icons-vue";
+  import { getQuotationList } from "@/api/salesManagement/salesQuotation.js";
+  import { getPurchaseByCode } from "@/api/procurementManagement/procurementLedger.js";
+  import { getDeliveryDetailByShippingNo } from "@/api/salesManagement/deliveryLedger.js";
+  import ImagePreview from "@/components/AttachmentPreview/image/index.vue";
+  const emit = defineEmits(["close"]);
+  const { proxy } = getCurrentInstance();
 
-const props = defineProps({
-  approveType: {
-    type: [Number, String],
-    default: 0
-  }
-})
-
-const dialogFormVisible = ref(false);
-const operationType = ref('')
-const activities = ref([])
-const formRef = ref(null);
-const userStore = useUserStore()
-const productOptions = ref([]);
-const quotationLoading = ref(false)
-const currentQuotation = ref({})
-const purchaseLoading = ref(false)
-const currentPurchase = ref({})
-const isQuotationApproval = computed(() => Number(props.approveType) === 6)
-const isPurchaseApproval = computed(() => Number(props.approveType) === 5)
-
-const data = reactive({
-	form: {
-		approveId: "",
-		approveDeptId: "",
-		approveReason: "",
-		checkResult: "",
-	},
-});
-const { form } = toRefs(data);
-
-// 鑺傜偣鏍囬
-const getNodeTitle = (index, len) => {
-  if (index === len - 1) return '缁撴潫';
-  return '瀹℃壒';
-};
-
-// 鑾峰彇褰撳墠婵�娲绘楠�
-const getActiveStep = () => {
-  // 濡傛灉鎵�鏈� isShen 閮戒负 false锛岃繑鍥炴渶鍚庝竴涓楠わ紙鍏ㄩ儴瀹屾垚锛�
-  const hasActive = activities.value.some(a => a.isShen === true);
-  if (!hasActive) return activities.value.length;
-  // 褰撳墠鑺傜偣绱㈠紩
-  return activities.value.findIndex(a => a.isShen  == true);
-};
-// 姝ラicon
-const getNodeIcon = (activity, index) => {
-  if (activity.approveNodeStatus === 2) return 'el-icon-warning'; // 涓嶉�氳繃
-  if (activity.isShen) return 'Edit';
-  return '';
-};
-
-// 鎵撳紑寮规
-const openDialog = (type, row) => {
-  operationType.value = type;
-  dialogFormVisible.value = true;
-  currentQuotation.value = {}
-  currentPurchase.value = {}
-	form.value = {...row}
-	// 绔嬪嵆娓呴櫎琛ㄥ崟楠岃瘉鐘舵�侊紙鍥犱负瀛楁鏄痙isabled鐨勶紝涓嶉渶瑕侀獙璇侊級
-	nextTick(() => {
-		if (formRef.value) {
-			formRef.value.clearValidate();
-		}
-	});
-	// 纭繚閫夐」鍔犺浇瀹屾垚鍚庡啀鍖归厤鍊肩被鍨�
-	getProductOptions().then(() => {
-		// 纭繚鍊肩被鍨嬪尮閰嶏紙濡傛灉閫夐」宸插姞杞斤級
-		if (productOptions.value.length > 0 && form.value.approveDeptId) {
-			const matchedOption = productOptions.value.find(opt => 
-				opt.deptId == form.value.approveDeptId || 
-				String(opt.deptId) === String(form.value.approveDeptId)
-			);
-			if (matchedOption) {
-				form.value.approveDeptId = matchedOption.deptId;
-			}
-		}
-		// 鍐嶆娓呴櫎楠岃瘉锛岀‘淇濋�夐」鍔犺浇鍚庡�煎尮閰嶆纭�
-		nextTick(() => {
-			if (formRef.value) {
-				formRef.value.clearValidate();
-			}
-		});
-	});
-
-  // 鎶ヤ环瀹℃壒锛氱敤瀹℃壒浜嬬敱瀛楁鎵胯浇鐨�"鎶ヤ环鍗曞彿"鍘绘煡鎶ヤ环鍒楄〃
-  if (isQuotationApproval.value) {
-    const quotationNo = row?.approveReason;
-    if (quotationNo) {
-      quotationLoading.value = true
-      getQuotationList({ quotationNo }).then((res) => {
-        const records = res?.data?.records || []
-        currentQuotation.value = records[0] || {}
-      }).finally(() => {
-        quotationLoading.value = false
-      })
-    }
-  }
-
-  // 閲囪喘瀹℃壒锛氱敤瀹℃壒浜嬬敱瀛楁鎵胯浇鐨�"閲囪喘鍚堝悓鍙�"鍘绘煡閲囪喘璇︽儏
-  if (isPurchaseApproval.value) {
-    const purchaseContractNumber = row?.approveReason;
-    if (purchaseContractNumber) {
-      purchaseLoading.value = true
-      getPurchaseByCode({ purchaseContractNumber }).then((res) => {
-        currentPurchase.value = res
-      }).catch((err) => {
-        console.error('鏌ヨ閲囪喘璇︽儏澶辫触:', err)
-        proxy.$modal.msgError('鏌ヨ閲囪喘璇︽儏澶辫触')
-      }).finally(() => {
-        purchaseLoading.value = false
-      })
-    }
-  }
-
-  approveProcessDetails(row.approveId).then((res) => {
-    activities.value = res.data
-    // 澧炲姞isApproval瀛楁
-    activities.value.forEach(item => {
-			if (item.url && item.url.includes('word')) {
-				item.urlTem = item.url.replaceAll('word', 'img')
-			} else {
-				item.urlTem = item.url
-			}
-      if (item.approveNodeStatus === 2) {
-        item.isApproval = '宸查┏鍥�';
-      } else if (item.approveNodeStatus === 1) {
-        item.isApproval = '宸插悓鎰�';
-      } else {
-        item.isApproval = '鏈鎵�';
-      }
-    })
-  })
-}
-const getProductOptions = () => {
-	return getDept().then((res) => {
-		productOptions.value = res.data;
-	});
-};
-// 鎻愪氦瀹℃壒
-const submitForm = (status) => {
-  const filteredActivities = activities.value.filter(activity => activity.isShen);
-  if (!filteredActivities || filteredActivities.length === 0) {
-    proxy.$modal.msgError("鏈壘鍒板緟瀹℃壒鐨勮妭鐐�");
-    return;
-  }
-  const currentActivity = filteredActivities[0];
-  if (!currentActivity) {
-    proxy.$modal.msgError("鏈壘鍒板緟瀹℃壒鐨勮妭鐐�");
-    return;
-  }
-  currentActivity.approveNodeStatus = status;
-  // 鍒ゆ柇鏄惁涓烘渶鍚庝竴姝�
-  const isLast = activities.value.findIndex(a => a.isShen) === activities.value.length-1;
-  updateApproveNode({ ...currentActivity, isLast }).then(() => {
-    proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
-    closeDia();
+  const props = defineProps({
+    approveType: {
+      type: [Number, String],
+      default: 0,
+    },
   });
-};
-// 鍏抽棴寮规
-const closeDia = () => {
-  proxy.resetForm("formRef");
-  dialogFormVisible.value = false;
-  quotationLoading.value = false
-  currentQuotation.value = {}
-  purchaseLoading.value = false
-  currentPurchase.value = {}
-  emit('close')
-};
-defineExpose({
-  openDialog,
-});
+
+  const dialogFormVisible = ref(false);
+  const operationType = ref("");
+  const activities = ref([]);
+  const formRef = ref(null);
+  const userStore = useUserStore();
+  const productOptions = ref([]);
+  const quotationLoading = ref(false);
+  const currentQuotation = ref({});
+  const purchaseLoading = ref(false);
+  const currentPurchase = ref({});
+  const deliveryLoading = ref(false);
+  const currentDelivery = ref({});
+  const deliveryProductList = ref([]);
+  const isQuotationApproval = computed(() => Number(props.approveType) === 6);
+  const isPurchaseApproval = computed(() => Number(props.approveType) === 5);
+  const isDeliveryApproval = computed(() => Number(props.approveType) === 7);
+
+  const data = reactive({
+    form: {
+      approveId: "",
+      approveDeptId: "",
+      approveReason: "",
+      checkResult: "",
+    },
+  });
+  const { form } = toRefs(data);
+
+  // 鑺傜偣鏍囬
+  const getNodeTitle = (index, len) => {
+    if (index === len - 1) return "缁撴潫";
+    return "瀹℃壒";
+  };
+
+  // 鑾峰彇褰撳墠婵�娲绘楠�
+  const getActiveStep = () => {
+    // 濡傛灉鎵�鏈� isShen 閮戒负 false锛岃繑鍥炴渶鍚庝竴涓楠わ紙鍏ㄩ儴瀹屾垚锛�
+    const hasActive = activities.value.some(a => a.isShen === true);
+    if (!hasActive) return activities.value.length;
+    // 褰撳墠鑺傜偣绱㈠紩
+    return activities.value.findIndex(a => a.isShen == true);
+  };
+  // 姝ラicon
+  const getNodeIcon = (activity, index) => {
+    if (activity.approveNodeStatus === 2) return "el-icon-warning"; // 涓嶉�氳繃
+    if (activity.isShen) return "Edit";
+    return "";
+  };
+
+  // 鎵撳紑寮规
+  const openDialog = (type, row) => {
+    operationType.value = type;
+    dialogFormVisible.value = true;
+    currentQuotation.value = {};
+    currentPurchase.value = {};
+    form.value = { ...row };
+    // 绔嬪嵆娓呴櫎琛ㄥ崟楠岃瘉鐘舵�侊紙鍥犱负瀛楁鏄痙isabled鐨勶紝涓嶉渶瑕侀獙璇侊級
+    nextTick(() => {
+      if (formRef.value) {
+        formRef.value.clearValidate();
+      }
+    });
+    // 纭繚閫夐」鍔犺浇瀹屾垚鍚庡啀鍖归厤鍊肩被鍨�
+    getProductOptions().then(() => {
+      // 纭繚鍊肩被鍨嬪尮閰嶏紙濡傛灉閫夐」宸插姞杞斤級
+      if (productOptions.value.length > 0 && form.value.approveDeptId) {
+        const matchedOption = productOptions.value.find(
+          opt =>
+            opt.deptId == form.value.approveDeptId ||
+            String(opt.deptId) === String(form.value.approveDeptId)
+        );
+        if (matchedOption) {
+          form.value.approveDeptId = matchedOption.deptId;
+        }
+      }
+      // 鍐嶆娓呴櫎楠岃瘉锛岀‘淇濋�夐」鍔犺浇鍚庡�煎尮閰嶆纭�
+      nextTick(() => {
+        if (formRef.value) {
+          formRef.value.clearValidate();
+        }
+      });
+    });
+
+    // 鎶ヤ环瀹℃壒锛氱敤瀹℃壒浜嬬敱瀛楁鎵胯浇鐨�"鎶ヤ环鍗曞彿"鍘绘煡鎶ヤ环鍒楄〃
+    if (isQuotationApproval.value) {
+      const quotationNo = row?.approveReason;
+      if (quotationNo) {
+        quotationLoading.value = true;
+        getQuotationList({ quotationNo })
+          .then(res => {
+            const records = res?.data?.records || [];
+            currentQuotation.value = records[0] || {};
+          })
+          .finally(() => {
+            quotationLoading.value = false;
+          });
+      }
+    }
+
+    // 閲囪喘瀹℃壒锛氱敤瀹℃壒浜嬬敱瀛楁鎵胯浇鐨�"閲囪喘鍚堝悓鍙�"鍘绘煡閲囪喘璇︽儏
+    if (isPurchaseApproval.value) {
+      const purchaseContractNumber = row?.approveReason;
+      if (purchaseContractNumber) {
+        purchaseLoading.value = true;
+        getPurchaseByCode({ purchaseContractNumber })
+          .then(res => {
+            currentPurchase.value = res;
+          })
+          .catch(err => {
+            console.error("鏌ヨ閲囪喘璇︽儏澶辫触:", err);
+            proxy.$modal.msgError("鏌ヨ閲囪喘璇︽儏澶辫触");
+          })
+          .finally(() => {
+            purchaseLoading.value = false;
+          });
+      }
+    }
+    // 鍙戣揣瀹℃壒锛氱敤瀹℃壒浜嬬敱瀛楁鎵胯浇鐨�"鍙戣揣鍗曞彿"鍘绘煡鍙戣揣璇︽儏
+    if (isDeliveryApproval.value) {
+      const deliveryNo = row?.approveReason;
+      if (deliveryNo) {
+        deliveryLoading.value = true;
+        currentDelivery.value = {};
+        deliveryProductList.value = [];
+        getDeliveryDetailByShippingNo({ shippingNo: deliveryNo })
+          .then(res => {
+            const detailData = res?.data || res || {};
+            currentDelivery.value = detailData;
+            deliveryProductList.value =
+              detailData.shippingProductDetailDtoList || [];
+          })
+          .catch(err => {
+            console.error("鏌ヨ鍙戣揣璇︽儏澶辫触:", err);
+            proxy.$modal.msgError("鏌ヨ鍙戣揣璇︽儏澶辫触");
+          })
+          .finally(() => {
+            deliveryLoading.value = false;
+          });
+      }
+    }
+
+    approveProcessDetails(row.approveId).then(res => {
+      activities.value = res.data;
+      // 澧炲姞isApproval瀛楁
+      activities.value.forEach(item => {
+        if (item.url && item.url.includes("word")) {
+          item.urlTem = item.url.replaceAll("word", "img");
+        } else {
+          item.urlTem = item.url;
+        }
+        if (item.approveNodeStatus === 2) {
+          item.isApproval = "宸查┏鍥�";
+        } else if (item.approveNodeStatus === 1) {
+          item.isApproval = "宸插悓鎰�";
+        } else {
+          item.isApproval = "鏈鎵�";
+        }
+      });
+    });
+  };
+
+  const getDeliveryProductInfoList = () => {
+    const row = currentDelivery.value;
+    if (!row) return [];
+    const normalizeBatchNoList = value => {
+      if (Array.isArray(value)) return value;
+      if (typeof value === "string" && value.includes(",")) {
+        return value
+          .split(",")
+          .map(item => item.trim())
+          .filter(Boolean);
+      }
+      return value ? [value] : [];
+    };
+    const detailList = deliveryProductList.value.length
+      ? deliveryProductList.value
+      : [
+          row.batchNoDetailList,
+          row.batchNoList,
+          row.shippingBatchList,
+          row.shippingInfoDetailList,
+          row.detailList,
+          row.batchDetailList,
+        ].find(value => Array.isArray(value) && value.length);
+    const batchNoList = normalizeBatchNoList(row.batchNo);
+    const toTableRow = (item = {}) => ({
+      batchNo:
+        typeof item === "string" || typeof item === "number"
+          ? item
+          : item.batchNo ?? item.batchNumber ?? row.batchNo ?? "--",
+      productName: item.productName ?? row.productName ?? "--",
+      specificationModel:
+        item.specificationModel ?? item.model ?? row.specificationModel ?? "--",
+      deliveryQuantity:
+        item.deliveryQuantity ??
+        item.quantity ??
+        item.shippingQuantity ??
+        row.deliveryQuantity ??
+        row.quantity ??
+        "--",
+    });
+    if (detailList?.length) {
+      return detailList.map(toTableRow);
+    }
+    if (batchNoList.length) {
+      return batchNoList.map(batchNo => toTableRow({ batchNo }));
+    }
+    return [toTableRow()];
+  };
+  const getApprovalStatusText = status => {
+    const statusMap = {
+      0: "寰呭鏍�",
+      1: "瀹℃牳閫氳繃",
+      2: "瀹℃牳鎷掔粷",
+      3: "瀹℃牳涓�",
+    };
+    return statusMap[status] || "寰呭鏍�";
+  };
+
+  const getProductOptions = () => {
+    return getDept().then(res => {
+      productOptions.value = res.data;
+    });
+  };
+  // 鎻愪氦瀹℃壒
+  const submitForm = status => {
+    const filteredActivities = activities.value.filter(
+      activity => activity.isShen
+    );
+    if (!filteredActivities || filteredActivities.length === 0) {
+      proxy.$modal.msgError("鏈壘鍒板緟瀹℃壒鐨勮妭鐐�");
+      return;
+    }
+    const currentActivity = filteredActivities[0];
+    if (!currentActivity) {
+      proxy.$modal.msgError("鏈壘鍒板緟瀹℃壒鐨勮妭鐐�");
+      return;
+    }
+    currentActivity.approveNodeStatus = status;
+    // 鍒ゆ柇鏄惁涓烘渶鍚庝竴姝�
+    const isLast =
+      activities.value.findIndex(a => a.isShen) === activities.value.length - 1;
+    updateApproveNode({ ...currentActivity, isLast }).then(() => {
+      proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+      closeDia();
+    });
+  };
+  // 鍏抽棴寮规
+  const closeDia = () => {
+    proxy.resetForm("formRef");
+    dialogFormVisible.value = false;
+    quotationLoading.value = false;
+    currentQuotation.value = {};
+    purchaseLoading.value = false;
+    currentPurchase.value = {};
+    emit("close");
+  };
+  defineExpose({
+    openDialog,
+  });
 </script>
 
 <style scoped>
-
-.node-user {
-  margin: 10px 0;
-  font-size: 16px;
-  font-weight: 600;
-  display: flex;
-  align-items: center;
-  gap: 8px;
-}
-.node-status {
-  color: #1890ff;
-  margin-left: 8px;
-  font-size: 14px;
-}
-.node-reason {
-  font-size: 15px;
-  color: #333;
-  margin: 10px 0;
-}
-.user-avatar {
-	cursor: pointer;
-	width: 30px;
-	height: 30px;
-	border-radius: 50px;
-}
-.signImg {
-	cursor: pointer;
-	width: 200px;
-	height: 60px;
-}
+  .node-user {
+    margin: 10px 0;
+    font-size: 16px;
+    font-weight: 600;
+    display: flex;
+    align-items: center;
+    gap: 8px;
+  }
+  .node-status {
+    color: #1890ff;
+    margin-left: 8px;
+    font-size: 14px;
+  }
+  .node-reason {
+    font-size: 15px;
+    color: #333;
+    margin: 10px 0;
+  }
+  .user-avatar {
+    cursor: pointer;
+    width: 30px;
+    height: 30px;
+    border-radius: 50px;
+  }
+  .signImg {
+    cursor: pointer;
+    width: 200px;
+    height: 60px;
+  }
 </style>
\ No newline at end of file
diff --git a/src/views/customerService/expiryAfterSales/components/formDia.vue b/src/views/customerService/expiryAfterSales/components/formDia.vue
index 2fe603b..d899b8d 100644
--- a/src/views/customerService/expiryAfterSales/components/formDia.vue
+++ b/src/views/customerService/expiryAfterSales/components/formDia.vue
@@ -20,7 +20,7 @@
 								v-model="form.productName"
 								placeholder="璇疯緭鍏ヤ骇鍝佸悕绉�"
 								clearable
-								:disabled="operationType === 'view'"
+								:disabled="isFieldDisabled('productName')"
 							/>
 						</el-form-item>
 					</el-col>
@@ -30,7 +30,7 @@
 								v-model="form.batchNumber"
 								placeholder="璇疯緭鍏ヤ骇鍝佹壒鍙�"
 								clearable
-								:disabled="operationType === 'view'"
+								:disabled="isFieldDisabled('batchNumber')"
 							/>
 						</el-form-item>
 					</el-col>
@@ -46,7 +46,7 @@
 								type="date"
 								placeholder="璇烽�夋嫨涓存湡鏃ユ湡"
 								clearable
-								:disabled="operationType === 'view'"
+								:disabled="isFieldDisabled('expiryDate')"
 							/>
 						</el-form-item>
 					</el-col>
@@ -57,7 +57,7 @@
 								:min="0"
 								placeholder="璇疯緭鍏ュ簱瀛樻暟閲�"
 								style="width: 100%"
-								:disabled="operationType === 'view'"
+								:disabled="isFieldDisabled('stockQuantity')"
 							/>
 						</el-form-item>
 					</el-col>
@@ -69,7 +69,7 @@
 								v-model="form.customerName"
 								placeholder="璇疯緭鍏ュ鎴峰悕绉�"
 								clearable
-								:disabled="operationType === 'view'"
+								:disabled="isFieldDisabled('customerName')"
 							/>
 						</el-form-item>
 					</el-col>
@@ -79,7 +79,7 @@
 								v-model="form.contactPhone"
 								placeholder="璇疯緭鍏ヨ仈绯荤數璇�"
 								clearable
-								:disabled="operationType === 'view'"
+								:disabled="isFieldDisabled('contactPhone')"
 							/>
 						</el-form-item>
 					</el-col>
@@ -91,7 +91,7 @@
 								v-model="form.problemDesc"
 								placeholder="璇疯緭鍏ラ棶棰樻弿杩�"
 								clearable
-								:disabled="operationType === 'view'"
+								:disabled="isFieldDisabled('problemDesc')"
 								type="textarea"
 								:rows="3"
 							/>
@@ -105,7 +105,7 @@
 								v-model="form.handlerId"
 								placeholder="璇烽�夋嫨澶勭悊浜�"
 								clearable
-								:disabled="operationType === 'view'"
+								:disabled="isFieldDisabled('handlerId')"
 								style="width: 100%"
 							>
 								<el-option
@@ -127,7 +127,7 @@
 								type="date"
 								placeholder="璇烽�夋嫨澶勭悊鏃ユ湡"
 								clearable
-								:disabled="operationType === 'view'"
+								:disabled="isFieldDisabled('handleDate')"
 							/>
 						</el-form-item>
 					</el-col>
@@ -139,7 +139,7 @@
 								v-model="form.handleResult"
 								placeholder="璇疯緭鍏ュ鐞嗙粨鏋�"
 								clearable
-								:disabled="operationType === 'view'"
+								:disabled="isFieldDisabled('handleResult')"
 								type="textarea"
 								:rows="3"
 							/>
@@ -175,6 +175,8 @@
 			return '鏂板涓存湡鍞悗';
 		case 'edit':
 			return '缂栬緫涓存湡鍞悗';
+		case 'handle':
+			return '澶勭悊涓存湡鍞悗';
 		case 'view':
 			return '鏌ョ湅涓存湡鍞悗';
 		default:
@@ -212,6 +214,13 @@
 })
 const { form, rules } = toRefs(data);
 const userList = ref([])
+const handleEditableFields = ["handlerId", "handleDate", "handleResult"];
+
+const isFieldDisabled = (field) => {
+	if (operationType.value === "view") return true;
+	if (operationType.value === "handle") return !handleEditableFields.includes(field);
+	return false;
+};
 
 // 鎵撳紑寮规
 const openDialog = (type, row) => {
@@ -242,7 +251,7 @@
 	} else {
 		// 缂栬緫鎴栨煡鐪嬫椂濉厖鏁版嵁
 		form.value = { ...row };
-		if (type === 'edit' && !form.value.handlerId) {
+		if (type === 'handle' && !form.value.handlerId) {
 			form.value.handlerId = userStore.id;
 			form.value.handleDate = getCurrentDate();
 		}
@@ -250,36 +259,49 @@
 }
 
 const submitForm = () => {
+	if (operationType.value === "handle") {
+		if (!form.value.handlerId || !form.value.handleDate || !form.value.handleResult) {
+			proxy.$modal.msgWarning("璇峰~鍐欏鐞嗕汉銆佸鐞嗘棩鏈熷拰澶勭悊缁撴灉");
+			return;
+		}
+		handleSubmit();
+		return;
+	}
 	proxy.$refs["formRef"].validate(valid => {
 		if (valid) {
-			const submitData = {
-				id: form.value.id,
-				productName: form.value.productName,
-				batchNumber: form.value.batchNumber,
-				expireDate: form.value.expiryDate,
-				stockQuantity: form.value.stockQuantity,
-				customerName: form.value.customerName,
-				contactPhone: form.value.contactPhone,
-				disRes: form.value.problemDesc,
-				status: form.value.status,
-				disposeUserId: form.value.handlerId,
-				disposeNickName: userList.value.find(item => item.userId === form.value.handlerId)?.nickName,
-				disposeResult: form.value.handleResult,
-				disDate: form.value.handleDate
-			};
-			
-			const apiCall = operationType.value === 'add' ? expiryAfterSalesAdd : expiryAfterSalesUpdate;
-			apiCall(submitData).then(() => {
-				proxy.$modal.msgSuccess(operationType.value === 'add' ? "鏂板鎴愬姛" : "鏇存柊鎴愬姛");
-				closeDia();
-			}).catch(error => {
-				console.error('鎻愪氦鏁版嵁澶辫触:', error);
-				proxy.$modal.msgError('鎻愪氦鏁版嵁澶辫触锛岃绋嶅悗閲嶈瘯');
-			});
+			handleSubmit();
 		}
 	});
 }
 
+const handleSubmit = () => {
+	const submitData = {
+		id: form.value.id,
+		productName: form.value.productName,
+		batchNumber: form.value.batchNumber,
+		expireDate: form.value.expiryDate,
+		stockQuantity: form.value.stockQuantity,
+		customerName: form.value.customerName,
+		contactPhone: form.value.contactPhone,
+		disRes: form.value.problemDesc,
+		status: operationType.value === "handle" ? 2 : form.value.status,
+		disposeUserId: form.value.handlerId,
+		disposeNickName: userList.value.find(item => item.userId === form.value.handlerId)?.nickName,
+		disposeResult: form.value.handleResult,
+		disDate: form.value.handleDate
+	};
+
+	const apiCall = operationType.value === 'add' ? expiryAfterSalesAdd : expiryAfterSalesUpdate;
+	apiCall(submitData).then(() => {
+		const successText = operationType.value === "add" ? "鏂板鎴愬姛" : operationType.value === "handle" ? "澶勭悊鎴愬姛" : "鏇存柊鎴愬姛";
+		proxy.$modal.msgSuccess(successText);
+		closeDia();
+	}).catch(error => {
+		console.error('鎻愪氦鏁版嵁澶辫触:', error);
+		proxy.$modal.msgError('鎻愪氦鏁版嵁澶辫触锛岃绋嶅悗閲嶈瘯');
+	});
+}
+
 // 鍏抽棴寮规
 const closeDia = () => {
 	proxy.resetForm("formRef");
diff --git a/src/views/customerService/expiryAfterSales/index.vue b/src/views/customerService/expiryAfterSales/index.vue
index c94e3dd..9966785 100644
--- a/src/views/customerService/expiryAfterSales/index.vue
+++ b/src/views/customerService/expiryAfterSales/index.vue
@@ -39,7 +39,7 @@
 				<el-button type="danger" @click="handleDelete">鍒犻櫎</el-button>
 			</div>
 		</div>
-		
+
 		<div class="table_list">
 			<PIMTable
 				rowKey="id"
@@ -60,7 +60,7 @@
 
 				<template #operation="{ row }">
 					<el-button type="primary" link @click="openForm('view', row)">鏌ョ湅</el-button>
-					<el-button type="primary" link @click="openForm('edit', row)" v-if="row.status === 1">缂栬緫</el-button>
+					<el-button type="primary" link @click="openForm('handle', row)" v-if="row.status === 1">澶勭悊</el-button>
 				</template>
 			</PIMTable>
 		</div>
@@ -201,7 +201,7 @@
 		current: page.value.current,
 		size: page.value.size
 	};
-	
+
 	expiryAfterSalesListPage(queryParams).then(res => {
 		// 鏄犲皠鍚庣杩斿洖鏁版嵁鍒板墠绔〃鏍�
 		tableData.value = res.data.records.map(item => ({
diff --git a/src/views/customerService/feedbackRegistration/components/formDia.vue b/src/views/customerService/feedbackRegistration/components/formDia.vue
index e5905ee..790ddbe 100644
--- a/src/views/customerService/feedbackRegistration/components/formDia.vue
+++ b/src/views/customerService/feedbackRegistration/components/formDia.vue
@@ -1,490 +1,507 @@
 <template>
   <div>
-    <el-dialog
-        v-model="dialogFormVisible"
-        title="鏂板鍞悗鍗�"
-        width="90%"
-        @close="closeDia"
-    >
+    <el-dialog v-model="dialogFormVisible"
+               title="鏂板鍞悗鍗�"
+               width="90%"
+               @close="closeDia">
       <div>
         <span class="descriptions">鍩虹璧勬枡</span>
-        <el-form
-            :model="form"
-            label-width="140px"
-            label-position="top"
-            :rules="rules"
-            ref="formRef"
-        >
+        <el-form :model="form"
+                 label-width="140px"
+                 label-position="top"
+                 :rules="rules"
+                 ref="formRef">
           <el-row :gutter="30">
             <el-col :span="4">
-              <el-form-item label="瀹㈡埛鍚嶇О锛�" prop="customerName">
-                <el-select
-                    v-model="form.customerName"
-                    filterable
-                    @change="customerNameChange"
-                >
-                  <el-option
-                      v-for="item in customerNameOptions"
-                      :key="item.value"
-                      :label="item.label"
-                      :value="item.value"
-                  />
+              <el-form-item label="瀹㈡埛鍚嶇О锛�"
+                            prop="customerName">
+                <el-select v-model="form.customerName"
+                           filterable
+                           @change="customerNameChange">
+                  <el-option v-for="item in customerNameOptions"
+                             :key="item.value"
+                             :label="item.label"
+                             :value="item.value" />
                 </el-select>
               </el-form-item>
             </el-col>
             <el-col :span="4">
-              <el-form-item label="鍞悗绫诲瀷锛�" prop="serviceType">
-                <el-select
-                    v-model="form.serviceType"
-                    filterable
-                >
-                  <el-option
-                      v-for="dict in serviceTypeOptions"
-                      :key="dict.value"
-                      :label="dict.label"
-                      :value="dict.value"
-                  />
+              <el-form-item label="鍞悗绫诲瀷锛�"
+                            prop="serviceType">
+                <el-select v-model="form.serviceType"
+                           filterable>
+                  <el-option v-for="dict in serviceTypeOptions"
+                             :key="dict.value"
+                             :label="dict.label"
+                             :value="dict.value" />
                 </el-select>
               </el-form-item>
             </el-col>
             <el-col :span="4">
-              <el-form-item label="鍏宠仈閿�鍞崟鍙凤細" prop="salesContractNo">
-                <el-select
-                    v-model="form.salesContractNo"
-                    @change="associatedSalesOrderNumberChange"
-                    filterable
-                >
-                  <el-option
-                      v-for="item in associatedSalesOrderNumberOptions"
-                      :key="item.value"
-                      :label="item.label"
-                      :value="item.value"
-                  />
+              <el-form-item label="鍏宠仈閿�鍞崟鍙凤細"
+                            prop="salesContractNo">
+                <el-select v-model="form.salesContractNo"
+                           @change="associatedSalesOrderNumberChange"
+                           filterable>
+                  <el-option v-for="item in associatedSalesOrderNumberOptions"
+                             :key="item.value"
+                             :label="item.label"
+                             :value="item.value" />
                 </el-select>
               </el-form-item>
             </el-col>
             <el-col :span="4">
-              <el-form-item label="绱ф�ョ▼搴︼細" prop="urgency">
-                <el-select
-                    v-model="form.urgency"
-                    filterable
-                >
-                  <el-option
-                      v-for="dict in urgencyOptions"
-                      :key="dict.value"
-                      :label="dict.label"
-                      :value="dict.value"
-                  />
+              <el-form-item label="绱ф�ョ▼搴︼細"
+                            prop="urgency">
+                <el-select v-model="form.urgency"
+                           filterable>
+                  <el-option v-for="dict in urgencyOptions"
+                             :key="dict.value"
+                             :label="dict.label"
+                             :value="dict.value" />
                 </el-select>
               </el-form-item>
             </el-col>
             <el-col :span="4">
-              <el-form-item label="闂鎻忚堪锛�" prop="proDesc">
-                <el-input
-                    v-model="form.proDesc"
-                    placeholder="璇疯緭鍏ラ棶棰樻弿杩�"
-                />
+              <el-form-item label="闂鎻忚堪锛�"
+                            prop="proDesc">
+                <el-input v-model="form.proDesc"
+                          placeholder="璇疯緭鍏ラ棶棰樻弿杩�" />
               </el-form-item>
             </el-col>
           </el-row>
         </el-form>
         <hr>
-          <div style="padding-top: 20px">
-            <div style="display: flex; justify-content: space-between">
-              <span class="descriptions">鍏宠仈浜у搧</span>
-            <el-button
-              type="primary"
-              style="margin-right: 12px; margin-bottom: 10px"
-              @click="isShowProductSelectDialog = true"
-            >
+        <div style="padding-top: 20px">
+          <div style="display: flex; justify-content: space-between">
+            <span class="descriptions">鍏宠仈浜у搧</span>
+            <el-button type="primary"
+                       style="margin-right: 12px; margin-bottom: 10px"
+                       @click="isShowProductSelectDialog = true">
               閫夋嫨浜у搧
             </el-button>
-            </div>
-            <PIMTable
-                :isShowPagination="false"
-                rowKey="id"
-                :column="tableColumn"
-                :tableData="tableData"
-            >
-              <template #approveStatus="{ row }">
-                <el-tag :type="getApproveStatusType(row)" size="small">
-                  {{ getApproveStatusText(row) }}
-                </el-tag>
-              </template>
-              <template #shippingStatus="{ row }">
-                <el-tag :type="getShippingStatusType(row)" size="small">
-                  {{ getShippingStatusText(row) }}
-                </el-tag>
-              </template>
-            </PIMTable>
           </div>
+          <PIMTable :isShowPagination="false"
+                    rowKey="id"
+                    :column="tableColumn"
+                    :tableData="tableData">
+            <template #approveStatus="{ row }">
+              <el-tag :type="getApproveStatusType(row)"
+                      size="small">
+                {{ getApproveStatusText(row) }}
+              </el-tag>
+            </template>
+            <template #shippingStatus="{ row }">
+              <el-tag :type="getShippingStatusType(row)"
+                      size="small">
+                {{ getShippingStatusText(row) }}
+              </el-tag>
+            </template>
+          </PIMTable>
+        </div>
       </div>
-			<template #footer>
-				<div class="dialog-footer">
-					<el-button type="primary" @click="submitForm">纭</el-button>
-					<el-button @click="closeDia">鍙栨秷</el-button>
-				</div>
-			</template>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary"
+                     @click="submitForm">纭</el-button>
+          <el-button @click="closeDia">鍙栨秷</el-button>
+        </div>
+      </template>
     </el-dialog>
     <!-- 閫夋嫨浜у搧寮圭獥 -->
-    <ProductSelectDialog
-      v-model="isShowProductSelectDialog"
-      :products="currentSalesOrderProducts"
-      :selected-ids="currentSelectedProductIds"
-      @confirm="handleSelectProducts"
-    />
+    <ProductSelectDialog v-model="isShowProductSelectDialog"
+                         :products="currentSalesOrderProducts"
+                         :selected-ids="currentSelectedProductIds"
+                         @confirm="handleSelectProducts" />
   </div>
 </template>
 
 <script setup>
-import { ref, reactive, toRefs, getCurrentInstance, computed } from "vue";
-import ProductSelectDialog from "./ProductSelectDialog.vue";
-import useUserStore from "@/store/modules/user.js";
-import {userListNoPageByTenantId} from "@/api/system/user.js";
-import {afterSalesServiceAdd, afterSalesServiceUpdate, getAllCustomerList, getSalesLedger } from "@/api/customerService/index.js";
-import { getCurrentDate } from "@/utils/index.js";
-const { proxy } = getCurrentInstance()
-const emit = defineEmits(['close'])
-const dialogFormVisible = ref(false);
-const operationType = ref('')
-const formRef = ref(null)
-const customerNameOptions = ref([])
-const userStore = useUserStore();
+  import { ref, reactive, toRefs, getCurrentInstance, computed } from "vue";
+  import ProductSelectDialog from "./ProductSelectDialog.vue";
+  import useUserStore from "@/store/modules/user.js";
+  import { userListNoPageByTenantId } from "@/api/system/user.js";
+  import {
+    afterSalesServiceAdd,
+    afterSalesServiceUpdate,
+    getAllCustomerList,
+    getSalesLedger,
+  } from "@/api/customerService/index.js";
+  import { getCurrentDate } from "@/utils/index.js";
+  const { proxy } = getCurrentInstance();
+  const emit = defineEmits(["close"]);
+  const dialogFormVisible = ref(false);
+  const operationType = ref("");
+  const formRef = ref(null);
+  const customerNameOptions = ref([]);
+  const userStore = useUserStore();
 
-const data = reactive({
-	form: {
-    topic: "",
-    serviceType: "",
-    urgency: "",
-    salesLedgerId: null,
-    productModelIds: "",
-    customerId: null,
-    salesContractNo: "",
-    proDesc: "",
-    customerName: ""
-	},
-	rules: {
-    customerName: [{required: true, message: "璇烽�夋嫨瀹㈡埛鍚嶇О", trigger: "change"}],
-    serviceType: [{required: true, message: "璇烽�夋嫨鍞悗绫诲瀷", trigger: "change"}],
-    urgency: [{required: true, message: "璇烽�夋嫨绱ф�ョ▼搴�", trigger: "change"}],
-		feedbackDate: [{required: true, message: "璇烽�夋嫨", trigger: "change"}],
-	}
-})
-
-// 鑷畾涔夋牎楠屽嚱鏁帮細鍒ゆ柇鏄惁闇�瑕佹牎楠屽敭鍚庣紪鍙�
-
-const { form, rules } = toRefs(data);
-const userList = ref([])
-
-const formatCurrency = (val) => {
-  if (val === null || val === undefined || val === '') return '-'
-  const num = Number(val)
-  return Number.isFinite(num) ? num.toFixed(2) : '-'
-}
-
-const { post_sale_waiting_list, degree_of_urgency } = proxy.useDict(
-  "post_sale_waiting_list",
-  "degree_of_urgency"
-);
-
-const serviceTypeOptions = computed(() => post_sale_waiting_list?.value || []);
-const urgencyOptions = computed(() => degree_of_urgency?.value || []);
-
-const getProductRowId = (row) => {
-  return row?.id ?? row?.productModelId ?? row?.modelId ?? `${row?.productCategory || row?.productName || ""}-${row?.specificationModel || row?.model || ""}-${row?.unit || ""}`
-}
-
-const normalizeProductRow = (row) => {
-  return {
-    ...row,
-    id: getProductRowId(row),
-    productCategory: row?.productCategory ?? row?.productName ?? '',
-    specificationModel: row?.specificationModel ?? row?.model ?? '',
-    unit: row?.unit ?? '',
-    approveStatus: row?.approveStatus ?? null,
-    shippingStatus: row?.shippingStatus ?? '',
-    expressCompany: row?.expressCompany ?? '',
-    expressNumber: row?.expressNumber ?? '',
-    shippingCarNumber: row?.shippingCarNumber ?? '',
-    shippingDate: row?.shippingDate ?? '',
-    quantity: row?.quantity ?? 0,
-    taxRate: row?.taxRate ?? 0,
-    taxInclusiveUnitPrice: row?.taxInclusiveUnitPrice ?? 0,
-    taxInclusiveTotalPrice: row?.taxInclusiveTotalPrice ?? 0,
-    taxExclusiveTotalPrice: row?.taxExclusiveTotalPrice ?? 0,
-    noQuantity: row?.noQuantity ?? 0,
-  }
-}
-
-const tableColumn = ref([
-  { label: "浜у搧澶х被", prop: "productCategory" },
-  { label: "瑙勬牸鍨嬪彿", prop: "specificationModel" },
-  { label: "鍗曚綅", prop: "unit" },
-  {
-    label: "浜у搧鐘舵��",
-    prop: "approveStatus",
-    width: 100,
-    align: "center",
-    dataType: "slot",
-    slot: "approveStatus",
-  },
-  {
-    label: "鍙戣揣鐘舵��",
-    align: "center",
-    width: 140,
-    dataType: "slot",
-    slot: "shippingStatus",
-  },
-  { label: "蹇�掑叕鍙�", prop: "expressCompany", width: 140 },
-  { label: "蹇�掑崟鍙�", prop: "expressNumber", width: 160 },
-  { label: "鍙戣揣杞︾墝", prop: "shippingCarNumber", minWidth: 100, align: "center" },
-  { label: "鍙戣揣鏃ユ湡", prop: "shippingDate", minWidth: 100, align: "center" },
-  { label: "鏁伴噺", prop: "quantity", width: 100 },
-  { label: "绋庣巼(%)", prop: "taxRate", width: 100 },
-  {
-    label: "鍚◣鍗曚环(鍏�)",
-    prop: "taxInclusiveUnitPrice",
-    width: 160,
-    formatData: formatCurrency,
-  },
-  {
-    label: "鍚◣鎬讳环(鍏�)",
-    prop: "taxInclusiveTotalPrice",
-    width: 160,
-    formatData: formatCurrency,
-  },
-  {
-    label: "涓嶅惈绋庢�讳环(鍏�)",
-    prop: "taxExclusiveTotalPrice",
-    width: 160,
-    formatData: formatCurrency,
-  },
-  {
-    dataType: "action",
-    label: "鎿嶄綔",
-    align: "center",
-    fixed: 'right',
-    operation: [
-      {
-        name: "鍒犻櫎",
-        type: "text",
-        clickFun: (row) => {
-          tableData.value = tableData.value.filter(i => getProductRowId(i) !== getProductRowId(row))
-        },
-
-      },
-    ],
-  },
-])
-const tableData = ref([])
-// 閫夋嫨浜у搧寮圭獥
-const isShowProductSelectDialog = ref(false)
-const handleSelectProducts = (rows) => {
-  if (!Array.isArray(rows)) return
-  const existingIds = new Set(tableData.value.map(i => String(getProductRowId(i))))
-  const mapped = rows
-    .map(normalizeProductRow)
-    .filter(r => !existingIds.has(String(getProductRowId(r))))
-  tableData.value = tableData.value.concat(mapped)
-}
-const currentSelectedProductIds = computed(() => {
-  return tableData.value.map(item => getProductRowId(item)).filter(item => item !== undefined && item !== null && item !== '')
-})
-
-const associatedSalesOrderNumberChange = () => {
-  const opt = associatedSalesOrderNumberOptions.value.find(
-    (item) => item.value === form.value.salesContractNo
-  )
-  tableData.value = (opt?.productData || []).map(normalizeProductRow)
-  form.value.salesLedgerId = opt?.id || null
-}
-
-const associatedSalesOrderNumberOptions = ref([])
-
-const currentSalesOrderProducts = computed(() => {
-  const opt = associatedSalesOrderNumberOptions.value.find(
-    (item) => item.value === form.value.salesContractNo
-  )
-  return (opt?.productData || []).map(normalizeProductRow)
-})
-
-const customerNameChange = (val) => {
-  form.value.salesContractNo = "";
-  form.value.salesLedgerId = null;
-  tableData.value = [];
-  associatedSalesOrderNumberOptions.value = [];
-  const opt = customerNameOptions.value.find(item => item.value === val);
-  if (opt) {
-    form.value.customerId = opt.id;
-  } else {
-    form.value.customerId = null;
-  }
-  getSalesLedger({
-    customerName: form.value.customerName
-  }).then(res => {
-    if(res.code === 200){
-      associatedSalesOrderNumberOptions.value = res.data.records.map(item => ({
-        label: item.salesContractNo,
-        value: item.salesContractNo,
-        productData:item.productData,
-        id: item.id
-      }))
-    }
-  })
-}
-
-const getApproveStatusText = (row) => {
-  if (!row) return '涓嶈冻'
-  if (row.approveStatus === 1 && (!row.shippingDate || !row.shippingCarNumber)) {
-    return '鍏呰冻'
-  }
-  if (row.approveStatus === 0 && (row.shippingDate || row.shippingCarNumber)) {
-    return '宸插嚭搴�'
-  }
-  return '涓嶈冻'
-}
-
-const getApproveStatusType = (row) => {
-  const statusText = getApproveStatusText(row)
-  return statusText === '涓嶈冻' ? 'danger' : 'success'
-}
-
-const getShippingStatusText = (row) => {
-  if (!row) return '寰呭彂璐�'
-  if (row.shippingDate || row.shippingCarNumber) {
-    return '宸插彂璐�'
-  }
-  const status = row.shippingStatus
-  if (status === null || status === undefined || status === '') {
-    return '寰呭彂璐�'
-  }
-  const map = {
-    '寰呭彂璐�': '寰呭彂璐�',
-    '寰呭鏍�': '寰呭鏍�',
-    '瀹℃牳涓�': '瀹℃牳涓�',
-    '瀹℃牳鎷掔粷': '瀹℃牳鎷掔粷',
-    '瀹℃牳閫氳繃': '瀹℃牳閫氳繃',
-    '宸插彂璐�': '宸插彂璐�'
-  }
-  return map[String(status).trim()] || '寰呭彂璐�'
-}
-
-const getShippingStatusType = (row) => {
-  if (!row) return 'info'
-  if (row.shippingDate || row.shippingCarNumber) {
-    return 'success'
-  }
-  const status = row.shippingStatus
-  if (status === null || status === undefined || status === '') {
-    return 'info'
-  }
-  const map = {
-    '寰呭彂璐�': 'info',
-    '寰呭鏍�': 'warning',
-    '瀹℃牳涓�': 'warning',
-    '瀹℃牳鎷掔粷': 'danger',
-    '瀹℃牳閫氳繃': 'success',
-    '宸插彂璐�': 'success'
-  }
-  return map[String(status).trim()] || 'info'
-}
-
-// 鎵撳紑寮规
-const openDialog =async (type, row) => {
-  // 璇锋眰澶氫釜鎺ュ彛锛岃幏鍙栨暟鎹�
-  let res = await getAllCustomerList({
-    current: 1,
-  size: 1000,
-  total: 0,
+  const data = reactive({
+    form: {
+      topic: "",
+      serviceType: "",
+      urgency: "",
+      salesLedgerId: null,
+      productModelIds: "",
+      customerId: null,
+      salesContractNo: "",
+      proDesc: "",
+      customerName: "",
+    },
+    rules: {
+      customerName: [
+        { required: true, message: "璇烽�夋嫨瀹㈡埛鍚嶇О", trigger: "change" },
+      ],
+      serviceType: [
+        { required: true, message: "璇烽�夋嫨鍞悗绫诲瀷", trigger: "change" },
+      ],
+      urgency: [{ required: true, message: "璇烽�夋嫨绱ф�ョ▼搴�", trigger: "change" }],
+      feedbackDate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+    },
   });
-  if(res.data.records){
-    customerNameOptions.value = res.data.records.map(item => ({
-      label: item.customerName,
-      value: item.customerName,
-      id: item.id
-    }));
-  }
 
+  // 鑷畾涔夋牎楠屽嚱鏁帮細鍒ゆ柇鏄惁闇�瑕佹牎楠屽敭鍚庣紪鍙�
 
-  operationType.value = type;
-  dialogFormVisible.value = true;
-	form.value = {}
-	proxy.resetForm("formRef");
-	form.value.checkUserId = userStore.id;
-	form.value.feedbackDate = getCurrentDate();
-  // 鏂板鏃舵竻绌哄凡閫夊叧鑱斾骇鍝�
-  if (type === "add") {
-    tableData.value = []
-  }
-	userListNoPageByTenantId().then((res) => {
-		userList.value = res.data;
-	});
-	if (type === "edit") {
-		form.value = {...row}
-    if (form.value.customerName) {
-      const res = await getSalesLedger({ customerName: form.value.customerName })
-      if (res?.code === 200) {
-        console.log(res)
-        associatedSalesOrderNumberOptions.value = (res.data?.records || []).map(item => ({
+  const { form, rules } = toRefs(data);
+  const userList = ref([]);
+
+  const formatCurrency = val => {
+    if (val === null || val === undefined || val === "") return "-";
+    const num = Number(val);
+    return Number.isFinite(num) ? num.toFixed(2) : "-";
+  };
+
+  const { post_sale_waiting_list, degree_of_urgency } = proxy.useDict(
+    "post_sale_waiting_list",
+    "degree_of_urgency"
+  );
+
+  const serviceTypeOptions = computed(() => post_sale_waiting_list?.value || []);
+  const urgencyOptions = computed(() => degree_of_urgency?.value || []);
+
+  const getProductRowId = row => {
+    return (
+      row?.id ??
+      row?.productModelId ??
+      row?.modelId ??
+      `${row?.productCategory || row?.productName || ""}-${
+        row?.specificationModel || row?.model || ""
+      }-${row?.unit || ""}`
+    );
+  };
+
+  const normalizeProductRow = row => {
+    return {
+      ...row,
+      id: getProductRowId(row),
+      productCategory: row?.productCategory ?? row?.productName ?? "",
+      specificationModel: row?.specificationModel ?? row?.model ?? "",
+      unit: row?.unit ?? "",
+      approveStatus: row?.approveStatus ?? null,
+      shippingStatus: row?.shippingStatus ?? "",
+      expressCompany: row?.expressCompany ?? "",
+      expressNumber: row?.expressNumber ?? "",
+      shippingCarNumber: row?.shippingCarNumber ?? "",
+      shippingDate: row?.shippingDate ?? "",
+      quantity: row?.quantity ?? 0,
+      taxRate: row?.taxRate ?? 0,
+      taxInclusiveUnitPrice: row?.taxInclusiveUnitPrice ?? 0,
+      taxInclusiveTotalPrice: row?.taxInclusiveTotalPrice ?? 0,
+      taxExclusiveTotalPrice: row?.taxExclusiveTotalPrice ?? 0,
+      noQuantity: row?.noQuantity ?? 0,
+    };
+  };
+
+  const tableColumn = ref([
+    { label: "浜у搧澶х被", prop: "productCategory" },
+    { label: "瑙勬牸鍨嬪彿", prop: "specificationModel" },
+    { label: "鍗曚綅", prop: "unit" },
+    {
+      label: "浜у搧鐘舵��",
+      prop: "approveStatus",
+      width: 100,
+      align: "center",
+      dataType: "slot",
+      slot: "approveStatus",
+    },
+    {
+      label: "鍙戣揣鐘舵��",
+      align: "center",
+      width: 140,
+      dataType: "slot",
+      slot: "shippingStatus",
+    },
+    { label: "蹇�掑叕鍙�", prop: "expressCompany", width: 140 },
+    { label: "蹇�掑崟鍙�", prop: "expressNumber", width: 160 },
+    {
+      label: "鍙戣揣杞︾墝",
+      prop: "shippingCarNumber",
+      minWidth: 100,
+      align: "center",
+    },
+    { label: "鍙戣揣鏃ユ湡", prop: "shippingDate", minWidth: 100, align: "center" },
+    { label: "鏁伴噺", prop: "quantity", width: 100 },
+    { label: "绋庣巼(%)", prop: "taxRate", width: 100 },
+    {
+      label: "鍚◣鍗曚环(鍏�)",
+      prop: "taxInclusiveUnitPrice",
+      width: 160,
+      formatData: formatCurrency,
+    },
+    {
+      label: "鍚◣鎬讳环(鍏�)",
+      prop: "taxInclusiveTotalPrice",
+      width: 160,
+      formatData: formatCurrency,
+    },
+    {
+      label: "涓嶅惈绋庢�讳环(鍏�)",
+      prop: "taxExclusiveTotalPrice",
+      width: 160,
+      formatData: formatCurrency,
+    },
+    {
+      dataType: "action",
+      label: "鎿嶄綔",
+      align: "center",
+      fixed: "right",
+      operation: [
+        {
+          name: "鍒犻櫎",
+          type: "text",
+          clickFun: row => {
+            tableData.value = tableData.value.filter(
+              i => getProductRowId(i) !== getProductRowId(row)
+            );
+          },
+        },
+      ],
+    },
+  ]);
+  const tableData = ref([]);
+  // 閫夋嫨浜у搧寮圭獥
+  const isShowProductSelectDialog = ref(false);
+  const handleSelectProducts = rows => {
+    if (!Array.isArray(rows)) return;
+    const existingIds = new Set(
+      tableData.value.map(i => String(getProductRowId(i)))
+    );
+    const mapped = rows
+      .map(normalizeProductRow)
+      .filter(r => !existingIds.has(String(getProductRowId(r))));
+    tableData.value = tableData.value.concat(mapped);
+  };
+  const currentSelectedProductIds = computed(() => {
+    return tableData.value
+      .map(item => getProductRowId(item))
+      .filter(item => item !== undefined && item !== null && item !== "");
+  });
+
+  const associatedSalesOrderNumberChange = () => {
+    const opt = associatedSalesOrderNumberOptions.value.find(
+      item => item.value === form.value.salesContractNo
+    );
+    tableData.value = (opt?.productData || []).map(normalizeProductRow);
+    form.value.salesLedgerId = opt?.id || null;
+  };
+
+  const associatedSalesOrderNumberOptions = ref([]);
+
+  const currentSalesOrderProducts = computed(() => {
+    const opt = associatedSalesOrderNumberOptions.value.find(
+      item => item.value === form.value.salesContractNo
+    );
+    return (opt?.productData || []).map(normalizeProductRow);
+  });
+
+  const customerNameChange = val => {
+    form.value.salesContractNo = "";
+    form.value.salesLedgerId = null;
+    tableData.value = [];
+    associatedSalesOrderNumberOptions.value = [];
+    const opt = customerNameOptions.value.find(item => item.value === val);
+    if (opt) {
+      form.value.customerId = opt.id;
+    } else {
+      form.value.customerId = null;
+    }
+    getSalesLedger({
+      customerName: form.value.customerName,
+    }).then(res => {
+      if (res.code === 200) {
+        associatedSalesOrderNumberOptions.value = res.data.records.map(item => ({
           label: item.salesContractNo,
           value: item.salesContractNo,
           productData: item.productData,
-          id: item.id
-        }))
+          id: item.id,
+        }));
       }
+    });
+  };
+
+  const getApproveStatusText = row => {
+    if (!row) return "涓嶈冻";
+    if (
+      row.approveStatus === 1 &&
+      (!row.shippingDate || !row.shippingCarNumber)
+    ) {
+      return "鍏呰冻";
     }
-    console.log(form.value)
-	}
-}
-const submitForm = () => {
-	proxy.$refs["formRef"].validate(valid => {
-		if (valid) {
-      // 鍖归厤浜у搧鍨嬪彿IDs
-      form.value.productModelIds = tableData.value.map(item => item.id).join(",")
-			if (operationType.value === "add") {
-				afterSalesServiceAdd(form.value).then(response => {
-					proxy.$modal.msgSuccess("鏂板鎴愬姛")
-					closeDia()
-				})
-			} else {
-				afterSalesServiceUpdate(form.value).then(response => {
-					proxy.$modal.msgSuccess("淇敼鎴愬姛")
-					closeDia()
-				})
-			}
-		}
-	})
-}
-// 鍏抽棴寮规
-const closeDia = () => {
-	proxy.resetForm("formRef");
-  dialogFormVisible.value = false;
-  emit('close')
-};
-defineExpose({
-  openDialog,
-});
+    if (row.approveStatus === 0 && (row.shippingDate || row.shippingCarNumber)) {
+      return "宸插嚭搴�";
+    }
+    return "涓嶈冻";
+  };
+
+  const getApproveStatusType = row => {
+    const statusText = getApproveStatusText(row);
+    return statusText === "涓嶈冻" ? "danger" : "success";
+  };
+
+  const getShippingStatusText = row => {
+    if (!row) return "寰呭彂璐�";
+    if (row.shippingDate || row.shippingCarNumber) {
+      return "宸插彂璐�";
+    }
+    const status = row.shippingStatus;
+    if (status === null || status === undefined || status === "") {
+      return "寰呭彂璐�";
+    }
+    const map = {
+      寰呭彂璐�: "寰呭彂璐�",
+      寰呭鏍�: "寰呭鏍�",
+      瀹℃牳涓�: "瀹℃牳涓�",
+      瀹℃牳鎷掔粷: "瀹℃牳鎷掔粷",
+      瀹℃牳閫氳繃: "瀹℃牳閫氳繃",
+      宸插彂璐�: "宸插彂璐�",
+    };
+    return map[String(status).trim()] || "寰呭彂璐�";
+  };
+
+  const getShippingStatusType = row => {
+    if (!row) return "info";
+    if (row.shippingDate || row.shippingCarNumber) {
+      return "success";
+    }
+    const status = row.shippingStatus;
+    if (status === null || status === undefined || status === "") {
+      return "info";
+    }
+    const map = {
+      寰呭彂璐�: "info",
+      寰呭鏍�: "warning",
+      瀹℃牳涓�: "warning",
+      瀹℃牳鎷掔粷: "danger",
+      瀹℃牳閫氳繃: "success",
+      宸插彂璐�: "success",
+    };
+    return map[String(status).trim()] || "info";
+  };
+
+  // 鎵撳紑寮规
+  const openDialog = async (type, row) => {
+    // 璇锋眰澶氫釜鎺ュ彛锛岃幏鍙栨暟鎹�
+    let res = await getAllCustomerList({
+      current: 1,
+      size: 1000,
+      total: 0,
+    });
+    console.log(res, "res");
+
+    if (res.data.records) {
+      customerNameOptions.value = res.data.records.map(item => ({
+        label: item.customerName,
+        value: item.customerName,
+        id: item.id,
+      }));
+    } else {
+    }
+
+    operationType.value = type;
+    dialogFormVisible.value = true;
+    form.value = {};
+    proxy.resetForm("formRef");
+    form.value.checkUserId = userStore.id;
+    form.value.feedbackDate = getCurrentDate();
+    // 鏂板鏃舵竻绌哄凡閫夊叧鑱斾骇鍝�
+    if (type === "add") {
+      tableData.value = [];
+    }
+    userListNoPageByTenantId().then(res => {
+      userList.value = res.data;
+    });
+    if (type === "edit") {
+      form.value = { ...row };
+      if (form.value.customerName) {
+        const res = await getSalesLedger({
+          customerName: form.value.customerName,
+        });
+        if (res?.code === 200) {
+          console.log(res);
+          associatedSalesOrderNumberOptions.value = (res.data?.records || []).map(
+            item => ({
+              label: item.salesContractNo,
+              value: item.salesContractNo,
+              productData: item.productData,
+              id: item.id,
+            })
+          );
+        }
+      }
+      console.log(form.value);
+    }
+  };
+  const submitForm = () => {
+    proxy.$refs["formRef"].validate(valid => {
+      if (valid) {
+        // 鍖归厤浜у搧鍨嬪彿IDs
+        form.value.productModelIds = tableData.value
+          .map(item => item.id)
+          .join(",");
+        if (operationType.value === "add") {
+          afterSalesServiceAdd(form.value).then(response => {
+            proxy.$modal.msgSuccess("鏂板鎴愬姛");
+            closeDia();
+          });
+        } else {
+          afterSalesServiceUpdate(form.value).then(response => {
+            proxy.$modal.msgSuccess("淇敼鎴愬姛");
+            closeDia();
+          });
+        }
+      }
+    });
+  };
+  // 鍏抽棴寮规
+  const closeDia = () => {
+    proxy.resetForm("formRef");
+    dialogFormVisible.value = false;
+    emit("close");
+  };
+  defineExpose({
+    openDialog,
+  });
 </script>
 
 <style scoped lang="scss">
-.descriptions {
-  margin-bottom: 20px;
-  display: inline-block;
-  font-size: 1rem;
-  font-weight: 600;
-  padding-left: 12px;
-  position: relative;
-}
+  .descriptions {
+    margin-bottom: 20px;
+    display: inline-block;
+    font-size: 1rem;
+    font-weight: 600;
+    padding-left: 12px;
+    position: relative;
+  }
 
-.descriptions::before {
-  content: "";
-  position: absolute;
-  left: 0;
-  top: 50%;
-  transform: translateY(-50%);
-  width: 4px;
-  height: 1rem;
-  background-color: #002FA7; /* Element 榛樿绾㈣壊 */
-  border-radius: 2px;
-}
+  .descriptions::before {
+    content: "";
+    position: absolute;
+    left: 0;
+    top: 50%;
+    transform: translateY(-50%);
+    width: 4px;
+    height: 1rem;
+    background-color: #002fa7; /* Element 榛樿绾㈣壊 */
+    border-radius: 2px;
+  }
 </style>
diff --git a/src/views/equipmentManagement/operationManagement/index.vue b/src/views/equipmentManagement/operationManagement/index.vue
index 008cc2c..99c3bd1 100644
--- a/src/views/equipmentManagement/operationManagement/index.vue
+++ b/src/views/equipmentManagement/operationManagement/index.vue
@@ -104,7 +104,7 @@
           align="center"
         >
           <template #default="scope">
-            {{ scope.row.runtimeDuration || '-' }}
+            {{ getRuntimeDurationDisplay(scope.row) }}
           </template>
         </el-table-column>
         <el-table-column
@@ -154,7 +154,8 @@
 </template>
 
 <script setup>
-import { ref, onMounted, computed } from 'vue'
+import { ref, onMounted, onUnmounted, computed } from 'vue'
+import dayjs from 'dayjs'
 import { ElMessage } from 'element-plus'
 import {
   VideoPlay,
@@ -193,6 +194,98 @@
 
   return filtered
 })
+
+// 杩愯涓棤缁撴潫鏃堕棿鏃讹紝杩愯鏃堕暱闇�闅忓綋鍓嶆椂闂村彉鍖栵紝鐢� tick 瑙﹀彂妯℃澘閲嶇畻
+const runtimeDisplayTick = ref(0)
+
+/** 鍙栧悗绔彲鑳戒娇鐢ㄧ殑寮�濮�/缁撴潫鏃堕棿瀛楁 */
+const pickStartTime = (row) => row?.startRuntimeTime ?? row?.startTime ?? row?.start_time
+const pickEndTime = (row) => row?.endRuntimeTime ?? row?.endTime ?? row?.end_time
+
+/**
+ * 瑙f瀽鎺ュ彛/鍓嶇鍐欏叆鐨勫悇绫绘椂闂达細鏃堕棿鎴炽�両SO 瀛楃涓层�亂yyy-MM-dd HH:mm:ss銆丣ackson 鏁扮粍 [y,M,d,h,m,s]銆佸惈涓枃鐨� toLocaleString 绛�
+ */
+const parseDeviceTime = (input) => {
+  if (input === null || input === undefined || input === '') return null
+  if (typeof input === 'number' && !Number.isNaN(input)) {
+    const d = dayjs(input)
+    return d.isValid() ? d.toDate() : null
+  }
+  if (Array.isArray(input)) {
+    const [y, mo, day, h = 0, mi = 0, se = 0] = input
+    if (y == null || y === '') return null
+    const d = dayjs()
+        .year(Number(y))
+        .month(Number(mo || 1) - 1)
+        .date(Number(day || 1))
+        .hour(Number(h) || 0)
+        .minute(Number(mi) || 0)
+        .second(Number(se) || 0)
+    return d.isValid() ? d.toDate() : null
+  }
+  const s = String(input).trim()
+  if (!s || s === '-') return null
+  let d = dayjs(s)
+  if (d.isValid()) return d.toDate()
+  d = dayjs(s.replace(/-/g, '/'))
+  if (d.isValid()) return d.toDate()
+  d = dayjs(s.replace(/\//g, '-'))
+  if (d.isValid()) return d.toDate()
+  return null
+}
+
+const formatDurationMs = (durationMs) => {
+  if (durationMs == null || Number.isNaN(durationMs) || durationMs < 0) return '-'
+  const hours = Math.floor(durationMs / (1000 * 60 * 60))
+  const minutes = Math.floor((durationMs % (1000 * 60 * 60)) / (1000 * 60))
+  if (hours === 0 && minutes === 0) return '涓嶈冻1鍒嗛挓'
+  return `${hours}灏忔椂${minutes}鍒嗛挓`
+}
+
+const hasMeaningfulEnd = (endRaw) =>
+    endRaw !== null &&
+    endRaw !== undefined &&
+    String(endRaw).trim() !== '' &&
+    String(endRaw).trim() !== '-'
+
+const formatStoredDuration = (row) => {
+  const rd = row?.runtimeDuration
+  if (rd === null || rd === undefined) return ''
+  const t = String(rd).trim()
+  return t === '' || t === '-' ? '' : String(rd)
+}
+
+/** 杩愯涓細濮嬬粓鐢ㄣ�屽綋鍓嶆椂闂� - 寮�濮嬫椂闂淬�嶏紱宸插仠姝細浼樺厛鎺ュ彛 runtimeDuration锛屽惁鍒欑敤缁撴潫-寮�濮嬶紱鏃犵粨鏉熷彲鐪嬪凡瀛樻椂闀挎垨鍔ㄦ�佹帹绠� */
+const getRuntimeDurationDisplay = (row) => {
+  void runtimeDisplayTick.value
+  const start = parseDeviceTime(pickStartTime(row))
+  if (!start) {
+    return formatStoredDuration(row) || '-'
+  }
+
+  const statusStr = String(row?.status ?? '').trim()
+  const isRunning = statusStr === '杩愯涓�' || statusStr === '1'
+  const endRaw = pickEndTime(row)
+  const hasEnd = hasMeaningfulEnd(endRaw)
+
+  // 鏃犵粨鏉熸椂闂达細杩愯涓竴瀹氬姩鎬佺畻锛涘凡鍋滄鍒欎紭鍏堝睍绀哄悗绔凡瀛樻椂闀匡紝娌℃湁鍐嶆寜褰撳墠鏃堕棿鎺ㄧ畻
+  if (!hasEnd) {
+    if (isRunning) return formatDurationMs(Date.now() - start.getTime())
+    const stored = formatStoredDuration(row)
+    if (stored) return stored
+    return formatDurationMs(Date.now() - start.getTime())
+  }
+
+  if (isRunning) {
+    return formatDurationMs(Date.now() - start.getTime())
+  }
+
+  const end = parseDeviceTime(endRaw)
+  const stored = formatStoredDuration(row)
+  if (stored) return stored
+  if (end) return formatDurationMs(end.getTime() - start.getTime())
+  return '-'
+}
 
 // 妫�鏌ヨ澶囨槸鍚﹁秴鏃舵湭鍚姩
 const isOverdue = (device) => {
@@ -246,12 +339,11 @@
       device.endRuntimeTime = currentTime
       // 璁$畻杩愯鏃堕暱
       if (device.startRuntimeTime) {
-        const startTime = new Date(device.startRuntimeTime)
-        const endTime = new Date(currentTime)
-        const duration = endTime - startTime
-        const hours = Math.floor(duration / (1000 * 60 * 60))
-        const minutes = Math.floor((duration % (1000 * 60 * 60)) / (1000 * 60))
-        device.runtimeDuration = `${hours}灏忔椂${minutes}鍒嗛挓`
+        const startTime = parseDeviceTime(device.startRuntimeTime)
+        const endTime = parseDeviceTime(currentTime)
+        if (startTime && endTime) {
+          device.runtimeDuration = formatDurationMs(endTime.getTime() - startTime.getTime())
+        }
       }
     }
     const params = {
@@ -297,9 +389,31 @@
 
 
 
-// 缁勪欢鎸傝浇鏃跺垵濮嬪寲鏁版嵁
+const POLL_MS = 60 * 1000
+const RUNTIME_TICK_MS = 30 * 1000
+let listPollTimer = null
+let runtimeTickTimer = null
+
+// 缁勪欢鎸傝浇鏃舵媺鍙栨暟鎹紝骞舵瘡鍒嗛挓鍒锋柊涓�娆″垪琛紱杩愯涓椂闀挎瘡 30 绉掑埛鏂版樉绀�
 onMounted(() => {
   getList()
+  listPollTimer = setInterval(() => {
+    getList()
+  }, POLL_MS)
+  runtimeTickTimer = setInterval(() => {
+    runtimeDisplayTick.value++
+  }, RUNTIME_TICK_MS)
+})
+
+onUnmounted(() => {
+  if (listPollTimer != null) {
+    clearInterval(listPollTimer)
+    listPollTimer = null
+  }
+  if (runtimeTickTimer != null) {
+    clearInterval(runtimeTickTimer)
+    runtimeTickTimer = null
+  }
 })
 </script>
 
diff --git a/src/views/financialManagement/generalLedger/index.vue b/src/views/financialManagement/generalLedger/index.vue
index 0570627..fbe2210 100644
--- a/src/views/financialManagement/generalLedger/index.vue
+++ b/src/views/financialManagement/generalLedger/index.vue
@@ -1,23 +1,39 @@
 <template>
   <div class="app-container">
-    <el-form :model="filters" :inline="true">
+    <el-form :model="filters"
+             :inline="true">
       <el-form-item label="绉戠洰缂栫爜:">
-        <el-input v-model="filters.subjectCode" placeholder="璇疯緭鍏ョ鐩紪鐮�" clearable style="width: 200px;" />
+        <el-input v-model="filters.subjectCode"
+                  placeholder="璇疯緭鍏ョ鐩紪鐮�"
+                  clearable
+                  style="width: 200px;" />
       </el-form-item>
       <el-form-item label="绉戠洰鍚嶇О:">
-        <el-input v-model="filters.subjectName" placeholder="璇疯緭鍏ョ鐩悕绉�" clearable style="width: 200px;" />
+        <el-input v-model="filters.subjectName"
+                  placeholder="璇疯緭鍏ョ鐩悕绉�"
+                  clearable
+                  style="width: 200px;" />
       </el-form-item>
       <el-form-item label="绉戠洰绫诲瀷:">
-        <el-select v-model="filters.subjectType" placeholder="璇烽�夋嫨" clearable style="width: 200px;">
-          <el-option label="璧勪骇绫�" value="asset" />
-          <el-option label="璐熷�虹被" value="liability" />
-          <el-option label="鏉冪泭绫�" value="equity" />
-          <el-option label="鎴愭湰绫�" value="cost" />
-          <el-option label="鎹熺泭绫�" value="profit_loss" />
+        <el-select v-model="filters.subjectType"
+                   placeholder="璇烽�夋嫨"
+                   clearable
+                   style="width: 200px;">
+          <el-option label="璧勪骇绫�"
+                     value="璧勪骇绫�" />
+          <el-option label="璐熷�虹被"
+                     value="璐熷�虹被" />
+          <el-option label="鏉冪泭绫�"
+                     value="鏉冪泭绫�" />
+          <el-option label="鎴愭湰绫�"
+                     value="鎴愭湰绫�" />
+          <el-option label="鎹熺泭绫�"
+                     value="鎹熺泭绫�" />
         </el-select>
       </el-form-item>
       <el-form-item>
-        <el-button type="primary" @click="getTableData">鎼滅储</el-button>
+        <el-button type="primary"
+                   @click="getTableData">鎼滅储</el-button>
         <el-button @click="resetFilters">閲嶇疆</el-button>
       </el-form-item>
     </el-form>
@@ -25,76 +41,85 @@
       <div class="actions">
         <div></div>
         <div>
-          <el-button type="primary" @click="add" icon="Plus">鏂板</el-button>
-          <el-button @click="handleOut" icon="Download">瀵煎嚭</el-button>
+          <el-button type="primary"
+                     @click="add"
+                     icon="Plus">鏂板</el-button>
+          <el-button @click="handleOut"
+                     icon="Download">瀵煎嚭</el-button>
         </div>
       </div>
-      <PIMTable
-        rowKey="id"
-        :column="columns"
-        :tableData="dataList"
-        :page="{
+      <PIMTable rowKey="id"
+                :column="columns"
+                :tableData="dataList"
+                :page="{
           current: pagination.currentPage,
           size: pagination.pageSize,
           total: pagination.total,
         }"
-        @pagination="changePage"
-      >
-        <template #subjectType="{ row }">
-          <el-tag :type="getSubjectTypeType(row.subjectType)">{{ getSubjectTypeLabel(row.subjectType) }}</el-tag>
-        </template>
-        <template #balanceDirection="{ row }">
-          <el-tag :type="row.balanceDirection === 'debit' ? 'success' : 'danger'">
-            {{ row.balanceDirection === 'debit' ? '鍊熸柟' : '璐锋柟' }}
-          </el-tag>
-        </template>
-        <template #status="{ row }">
-          <el-tag :type="row.status === 'active' ? 'success' : 'info'">
-            {{ row.status === 'active' ? '鍚敤' : '绂佺敤' }}
-          </el-tag>
-        </template>
-        <template #operation="{ row }">
-          <el-button type="primary" link @click="edit(row)">缂栬緫</el-button>
-          <el-button type="danger" link @click="handleDelete(row)">鍒犻櫎</el-button>
-        </template>
+                @pagination="changePage">
       </PIMTable>
     </div>
-
-    <FormDialog :title="dialogTitle" v-model="dialogVisible" width="600px" @confirm="submitForm" @cancel="dialogVisible = false">
-      <el-form :model="form" :rules="rules" ref="formRef" label-width="100px">
-        <el-form-item label="绉戠洰缂栫爜" prop="subjectCode">
-          <el-input v-model="form.subjectCode" placeholder="璇疯緭鍏ョ鐩紪鐮�" />
+    <FormDialog :title="dialogTitle"
+                v-model="dialogVisible"
+                width="600px"
+                @confirm="submitForm"
+                @cancel="dialogVisible = false">
+      <el-form :model="form"
+               :rules="rules"
+               ref="formRef"
+               label-width="100px">
+        <el-form-item label="绉戠洰缂栫爜"
+                      prop="subjectCode">
+          <el-input v-model="form.subjectCode"
+                    placeholder="璇疯緭鍏ョ鐩紪鐮�" />
         </el-form-item>
-        <el-form-item label="绉戠洰鍚嶇О" prop="subjectName">
-          <el-input v-model="form.subjectName" placeholder="璇疯緭鍏ョ鐩悕绉�" />
+        <el-form-item label="绉戠洰鍚嶇О"
+                      prop="subjectName">
+          <el-input v-model="form.subjectName"
+                    placeholder="璇疯緭鍏ョ鐩悕绉�" />
         </el-form-item>
-        <el-form-item label="绉戠洰绫诲瀷" prop="subjectType">
-          <el-select v-model="form.subjectType" placeholder="璇烽�夋嫨绉戠洰绫诲瀷" style="width: 100%;">
-            <el-option label="璧勪骇绫�" value="asset" />
-            <el-option label="璐熷�虹被" value="liability" />
-            <el-option label="鏉冪泭绫�" value="equity" />
-            <el-option label="鎴愭湰绫�" value="cost" />
-            <el-option label="鎹熺泭绫�" value="profit_loss" />
+        <el-form-item label="绉戠洰绫诲瀷"
+                      prop="subjectType">
+          <el-select v-model="form.subjectType"
+                     placeholder="璇烽�夋嫨绉戠洰绫诲瀷"
+                     style="width: 100%;">
+            <el-option label="璧勪骇绫�"
+                       value="璧勪骇绫�" />
+            <el-option label="璐熷�虹被"
+                       value="璐熷�虹被" />
+            <el-option label="鏉冪泭绫�"
+                       value="鏉冪泭绫�" />
+            <el-option label="鎴愭湰绫�"
+                       value="鎴愭湰绫�" />
+            <el-option label="鎹熺泭绫�"
+                       value="鎹熺泭绫�" />
           </el-select>
         </el-form-item>
-        <el-form-item label="浣欓鏂瑰悜" prop="balanceDirection">
+        <el-form-item label="浣欓鏂瑰悜"
+                      prop="balanceDirection">
           <el-radio-group v-model="form.balanceDirection">
-            <el-radio label="debit">鍊熸柟</el-radio>
-            <el-radio label="credit">璐锋柟</el-radio>
+            <el-radio label="鍊熸柟">鍊熸柟</el-radio>
+            <el-radio label="璐锋柟">璐锋柟</el-radio>
           </el-radio-group>
         </el-form-item>
-        <el-form-item label="鐘舵��" prop="status">
+        <el-form-item label="鐘舵��"
+                      prop="status">
           <el-radio-group v-model="form.status">
-            <el-radio label="active">鍚敤</el-radio>
-            <el-radio label="inactive">绂佺敤</el-radio>
+            <el-radio :label="0">鍚敤</el-radio>
+            <el-radio :label="1">绂佺敤</el-radio>
           </el-radio-group>
         </el-form-item>
-        <el-form-item label="澶囨敞" prop="remark">
-          <el-input v-model="form.remark" type="textarea" :rows="3" placeholder="璇疯緭鍏ュ娉�" />
+        <el-form-item label="澶囨敞"
+                      prop="remark">
+          <el-input v-model="form.remark"
+                    type="textarea"
+                    :rows="3"
+                    placeholder="璇疯緭鍏ュ娉�" />
         </el-form-item>
       </el-form>
       <template #footer>
-        <el-button type="primary" @click="submitForm">纭畾</el-button>
+        <el-button type="primary"
+                   @click="submitForm">纭畾</el-button>
         <el-button @click="dialogVisible = false">鍙栨秷</el-button>
       </template>
     </FormDialog>
@@ -102,190 +127,238 @@
 </template>
 
 <script setup>
-import { ref, reactive, onMounted } from "vue";
-import { ElMessage, ElMessageBox } from "element-plus";
-import FormDialog from "@/components/Dialog/FormDialog.vue";
+  import { ref, reactive, onMounted, getCurrentInstance } from "vue";
+  import { ElMessage, ElMessageBox } from "element-plus";
+  import FormDialog from "@/components/Dialog/FormDialog.vue";
+  import {
+    listAccountSubject,
+    addAccountSubject,
+    updateAccountSubject,
+    delAccountSubject,
+    exportAccountSubject,
+  } from "@/api/financialManagement/accountSubject";
 
-defineOptions({
-  name: "鎬诲笎绉戠洰",
-});
+  defineOptions({
+    name: "鎬诲笎绉戠洰",
+  });
 
-const filters = reactive({
-  subjectCode: "",
-  subjectName: "",
-  subjectType: "",
-});
+  const { proxy } = getCurrentInstance();
 
-const pagination = reactive({
-  currentPage: 1,
-  pageSize: 10,
-  total: 0,
-});
-
-const columns = [
-  { label: "绉戠洰缂栫爜", prop: "subjectCode", width: "120" },
-  { label: "绉戠洰鍚嶇О", prop: "subjectName", width: "150" },
-  { label: "绉戠洰绫诲瀷", prop: "subjectType", slot: "subjectType" },
-  { label: "浣欓鏂瑰悜", prop: "balanceDirection", slot: "balanceDirection" },
-  { label: "鐘舵��", prop: "status", slot: "status" },
-  { label: "澶囨敞", prop: "remark", showOverflowTooltip: true },
-  { label: "鎿嶄綔", prop: "operation", slot: "operation", width: "150", fixed: "right" },
-];
-
-const dataList = ref([]);
-const dialogVisible = ref(false);
-const dialogTitle = ref("");
-const formRef = ref(null);
-const isEdit = ref(false);
-const currentId = ref(null);
-
-const form = reactive({
-  subjectCode: "",
-  subjectName: "",
-  subjectType: "",
-  balanceDirection: "debit",
-  status: "active",
-  remark: "",
-});
-
-const rules = {
-  subjectCode: [{ required: true, message: "璇疯緭鍏ョ鐩紪鐮�", trigger: "blur" }],
-  subjectName: [{ required: true, message: "璇疯緭鍏ョ鐩悕绉�", trigger: "blur" }],
-  subjectType: [{ required: true, message: "璇烽�夋嫨绉戠洰绫诲瀷", trigger: "change" }],
-};
-
-const mockData = [
-  { id: 1, subjectCode: "1001", subjectName: "搴撳瓨鐜伴噾", subjectType: "asset", balanceDirection: "debit", status: "active", remark: "" },
-  { id: 2, subjectCode: "1002", subjectName: "閾惰瀛樻", subjectType: "asset", balanceDirection: "debit", status: "active", remark: "" },
-  { id: 3, subjectCode: "1122", subjectName: "搴旀敹璐︽", subjectType: "asset", balanceDirection: "debit", status: "active", remark: "" },
-  { id: 4, subjectCode: "2202", subjectName: "搴斾粯璐︽", subjectType: "liability", balanceDirection: "credit", status: "active", remark: "" },
-  { id: 5, subjectCode: "4001", subjectName: "瀹炴敹璧勬湰", subjectType: "equity", balanceDirection: "credit", status: "active", remark: "" },
-  { id: 6, subjectCode: "5001", subjectName: "鐢熶骇鎴愭湰", subjectType: "cost", balanceDirection: "debit", status: "active", remark: "" },
-  { id: 7, subjectCode: "6001", subjectName: "涓昏惀涓氬姟鏀跺叆", subjectType: "profit_loss", balanceDirection: "credit", status: "active", remark: "" },
-  { id: 8, subjectCode: "6401", subjectName: "涓昏惀涓氬姟鎴愭湰", subjectType: "profit_loss", balanceDirection: "debit", status: "active", remark: "" },
-];
-
-const getSubjectTypeLabel = (type) => {
-  const map = {
-    asset: "璧勪骇绫�",
-    liability: "璐熷�虹被",
-    equity: "鏉冪泭绫�",
-    cost: "鎴愭湰绫�",
-    profit_loss: "鎹熺泭绫�",
-  };
-  return map[type] || type;
-};
-
-const getSubjectTypeType = (type) => {
-  const map = {
-    asset: "success",
-    liability: "danger",
-    equity: "warning",
-    cost: "info",
-    profit_loss: "primary",
-  };
-  return map[type] || "";
-};
-
-const getTableData = () => {
-  let result = [...mockData];
-  if (filters.subjectCode) {
-    result = result.filter(item => item.subjectCode.includes(filters.subjectCode));
-  }
-  if (filters.subjectName) {
-    result = result.filter(item => item.subjectName.includes(filters.subjectName));
-  }
-  if (filters.subjectType) {
-    result = result.filter(item => item.subjectType === filters.subjectType);
-  }
-  pagination.total = result.length;
-  dataList.value = result.slice((pagination.currentPage - 1) * pagination.pageSize, pagination.currentPage * pagination.pageSize);
-};
-
-const resetFilters = () => {
-  filters.subjectCode = "";
-  filters.subjectName = "";
-  filters.subjectType = "";
-  pagination.currentPage = 1;
-  getTableData();
-};
-
-const changePage = ({ current, size }) => {
-  pagination.currentPage = current;
-  pagination.pageSize = size;
-  getTableData();
-};
-
-const add = () => {
-  isEdit.value = false;
-  dialogTitle.value = "鏂板绉戠洰";
-  Object.assign(form, {
+  const filters = reactive({
     subjectCode: "",
     subjectName: "",
     subjectType: "",
-    balanceDirection: "debit",
-    status: "active",
+  });
+
+  const pagination = reactive({
+    currentPage: 1,
+    pageSize: 10,
+    total: 0,
+  });
+
+  const columns = [
+    { label: "绉戠洰缂栫爜", prop: "subjectCode", width: "120" },
+    { label: "绉戠洰鍚嶇О", prop: "subjectName", width: "150" },
+    { label: "绉戠洰绫诲瀷", prop: "subjectType" },
+    {
+      label: "浣欓鏂瑰悜",
+      prop: "balanceDirection",
+      dataType: "tag",
+      formatData: value => {
+        if (value === "鍊熸柟") {
+          return "鍊熸柟";
+        }
+        return "璐锋柟";
+      },
+      formatType: value => {
+        if (value === "鍊熸柟") {
+          return "primary";
+        }
+        return "danger";
+      },
+    },
+    {
+      label: "鐘舵��",
+      prop: "status",
+      dataType: "tag",
+      formatData: value => {
+        if (value === 0 || value === "0") {
+          return "鍚敤";
+        }
+        return "绂佺敤";
+      },
+      formatType: value => {
+        if (value === 0 || value === "0") {
+          return "success";
+        }
+        return "info";
+      },
+    },
+
+    { label: "澶囨敞", prop: "remark", showOverflowTooltip: true },
+    {
+      dataType: "action",
+      label: "鎿嶄綔",
+      align: "center",
+      fixed: "right",
+      width: "150",
+      operation: [
+        {
+          name: "缂栬緫",
+          type: "primary",
+          clickFun: row => {
+            edit(row);
+          },
+        },
+        {
+          name: "鍒犻櫎",
+          type: "danger",
+          clickFun: row => {
+            handleDelete(row);
+          },
+        },
+      ],
+    },
+  ];
+
+  const dataList = ref([]);
+  const dialogVisible = ref(false);
+  const dialogTitle = ref("");
+  const formRef = ref(null);
+  const isEdit = ref(false);
+
+  const form = reactive({
+    id: undefined,
+    subjectCode: "",
+    subjectName: "",
+    subjectType: "",
+    balanceDirection: "鍊熸柟",
+    status: 0,
     remark: "",
   });
-  dialogVisible.value = true;
-};
 
-const edit = (row) => {
-  isEdit.value = true;
-  currentId.value = row.id;
-  dialogTitle.value = "缂栬緫绉戠洰";
-  Object.assign(form, row);
-  dialogVisible.value = true;
-};
+  const rules = {
+    subjectCode: [{ required: true, message: "璇疯緭鍏ョ鐩紪鐮�", trigger: "blur" }],
+    subjectName: [{ required: true, message: "璇疯緭鍏ョ鐩悕绉�", trigger: "blur" }],
+    subjectType: [
+      { required: true, message: "璇烽�夋嫨绉戠洰绫诲瀷", trigger: "change" },
+    ],
+  };
 
-const submitForm = () => {
-  formRef.value.validate((valid) => {
-    if (valid) {
-      if (isEdit.value) {
-        const index = mockData.findIndex(item => item.id === currentId.value);
-        if (index !== -1) {
-          mockData[index] = { ...mockData[index], ...form };
+  const getSubjectTypeType = type => {
+    const map = {
+      璧勪骇绫�: "success",
+      璐熷�虹被: "danger",
+      鏉冪泭绫�: "warning",
+      鎴愭湰绫�: "info",
+      鎹熺泭绫�: "primary",
+    };
+    return map[type] || "";
+  };
+
+  const getTableData = () => {
+    const query = {
+      pageNum: pagination.currentPage,
+      pageSize: pagination.pageSize,
+      ...filters,
+    };
+    listAccountSubject(query).then(response => {
+      dataList.value = response.data.records;
+      pagination.total = response.data.total;
+    });
+  };
+
+  const resetFilters = () => {
+    filters.subjectCode = "";
+    filters.subjectName = "";
+    filters.subjectType = "";
+    pagination.currentPage = 1;
+    getTableData();
+  };
+
+  const changePage = obj => {
+    pagination.currentPage = obj.page;
+    pagination.pageSize = obj.limit;
+    getTableData();
+  };
+
+  const add = () => {
+    isEdit.value = false;
+    dialogTitle.value = "鏂板绉戠洰";
+    Object.assign(form, {
+      id: undefined,
+      subjectCode: "",
+      subjectName: "",
+      subjectType: "",
+      balanceDirection: "鍊熸柟",
+      status: 0,
+      remark: "",
+    });
+    dialogVisible.value = true;
+  };
+
+  const edit = row => {
+    isEdit.value = true;
+    dialogTitle.value = "缂栬緫绉戠洰";
+    Object.assign(form, row);
+    dialogVisible.value = true;
+  };
+
+  const submitForm = () => {
+    formRef.value.validate(valid => {
+      if (valid) {
+        if (isEdit.value) {
+          updateAccountSubject(form).then(() => {
+            ElMessage.success("缂栬緫鎴愬姛");
+            dialogVisible.value = false;
+            getTableData();
+          });
+        } else {
+          addAccountSubject(form).then(() => {
+            ElMessage.success("鏂板鎴愬姛");
+            dialogVisible.value = false;
+            getTableData();
+          });
         }
-        ElMessage.success("缂栬緫鎴愬姛");
-      } else {
-        const newId = mockData.length > 0 ? Math.max(...mockData.map(item => item.id)) + 1 : 1;
-        mockData.push({ id: newId, ...form });
-        ElMessage.success("鏂板鎴愬姛");
       }
-      dialogVisible.value = false;
-      getTableData();
-    }
-  });
-};
+    });
+  };
 
-const handleDelete = (row) => {
-  ElMessageBox.confirm("纭鍒犻櫎璇ョ鐩悧锛�", "鎻愮ず", {
-    confirmButtonText: "纭畾",
-    cancelButtonText: "鍙栨秷",
-    type: "warning",
-  }).then(() => {
-    const index = mockData.findIndex(item => item.id === row.id);
-    if (index !== -1) {
-      mockData.splice(index, 1);
-    }
-    ElMessage.success("鍒犻櫎鎴愬姛");
+  const handleDelete = row => {
+    const ids = row.id;
+    ElMessageBox.confirm("纭鍒犻櫎璇ョ鐩悧锛�", "鎻愮ず", {
+      confirmButtonText: "纭畾",
+      cancelButtonText: "鍙栨秷",
+      type: "warning",
+    })
+      .then(() => {
+        return delAccountSubject(ids);
+      })
+      .then(() => {
+        ElMessage.success("鍒犻櫎鎴愬姛");
+        getTableData();
+      });
+  };
+
+  const handleOut = () => {
+    proxy.download(
+      "accountSubject/export",
+      {
+        ...filters,
+      },
+      `account_subject_${new Date().getTime()}.xlsx`
+    );
+  };
+
+  onMounted(() => {
     getTableData();
   });
-};
-
-const handleOut = () => {
-  ElMessage.success("瀵煎嚭鎴愬姛");
-};
-
-onMounted(() => {
-  getTableData();
-});
 </script>
 
 <style lang="scss" scoped>
-.actions {
-  display: flex;
-  justify-content: space-between;
-  margin-bottom: 15px;
-}
+  .actions {
+    display: flex;
+    justify-content: space-between;
+    margin-bottom: 15px;
+  }
 </style>
diff --git a/src/views/inventoryManagement/dispatchLog/Record.vue b/src/views/inventoryManagement/dispatchLog/Record.vue
index 6060cf5..f41eaaa 100644
--- a/src/views/inventoryManagement/dispatchLog/Record.vue
+++ b/src/views/inventoryManagement/dispatchLog/Record.vue
@@ -96,7 +96,9 @@
         </el-table-column>
 				<el-table-column label="瀹℃壒鐘舵��" prop="approvalStatus" show-overflow-tooltip>
 					<template #default="scope">
-						{{ getApprovalStatusLabel(scope.row.approvalStatus) }}
+						<el-tag :type="getApprovalStatusTagType(scope.row.approvalStatus)" size="small">
+							{{ getApprovalStatusLabel(scope.row.approvalStatus) }}
+						</el-tag>
 					</template>
 				</el-table-column>
 			</el-table>
@@ -179,7 +181,7 @@
 };
 const getList = () => {
 	tableLoading.value = true;
-	getStockOutPage({ ...searchForm.value, ...page, type: props.type, topParentProductId: props.topParentProductId })
+	getStockOutPage({ ...searchForm.value, ...page,  topParentProductId: props.topParentProductId })
 		.then((res) => {
 			tableLoading.value = false;
 			tableData.value = res.data.records;
@@ -216,6 +218,13 @@
 	return approvalStatusLabelMap[status] || "寰呭鎵�";
 };
 
+// 閫氳繃/椹冲洖鍥哄畾鑹诧紱鍏朵綑锛堝惈寰呭鎵广�佺┖鍊笺�佹湭鏄犲皠浣嗘枃妗堜负寰呭鎵癸級缁熶竴鐢� warning 棰勮鑹�
+const getApprovalStatusTagType = (status) => {
+	if (status === 1 || status === "1" || status === "approved" || status === "APPROVED") return "success";
+	if (status === 2 || status === "2" || status === "rejected" || status === "REJECTED") return "danger";
+	return "warning";
+};
+
 // 鑾峰彇鏉ユ簮绫诲瀷閫夐」
 const fetchStockRecordTypeOptions = () => {
   if (props.type === '0') {
diff --git a/src/views/inventoryManagement/receiptManagement/Record.vue b/src/views/inventoryManagement/receiptManagement/Record.vue
index 7ca8fea..c9cb6ee 100644
--- a/src/views/inventoryManagement/receiptManagement/Record.vue
+++ b/src/views/inventoryManagement/receiptManagement/Record.vue
@@ -91,7 +91,9 @@
                          prop="approvalStatus"
                          show-overflow-tooltip>
           <template #default="scope">
-            {{ getApprovalStatusLabel(scope.row.approvalStatus) }}
+            <el-tag :type="getApprovalStatusTagType(scope.row.approvalStatus)" size="small">
+              {{ getApprovalStatusLabel(scope.row.approvalStatus) }}
+            </el-tag>
           </template>
         </el-table-column>
       </el-table>
@@ -187,6 +189,13 @@
   return approvalStatusLabelMap[status] || "寰呭鎵�";
 };
 
+// 閫氳繃/椹冲洖鍥哄畾鑹诧紱鍏朵綑锛堝惈寰呭鎵广�佺┖鍊笺�佹湭鏄犲皠浣嗘枃妗堜负寰呭鎵癸級缁熶竴鐢� warning 棰勮鑹�
+const getApprovalStatusTagType = (status) => {
+  if (status === 1 || status === "1" || status === "approved" || status === "APPROVED") return "success";
+  if (status === 2 || status === "2" || status === "rejected" || status === "REJECTED") return "danger";
+  return "warning";
+};
+
 const pageProductChange = obj => {
   page.current = obj.page;
   page.size = obj.limit;
@@ -195,7 +204,7 @@
 
 const getList = () => {
   tableLoading.value = true;
-  const params = {...page, type: props.type, topParentProductId: props.topParentProductId};
+  const params = {...page,  topParentProductId: props.topParentProductId};
   params.timeStr = searchForm.value.timeStr;
   params.productName = searchForm.value.productName;
   params.recordType = searchForm.value.recordType;
diff --git a/src/views/inventoryManagement/stockReport/index.vue b/src/views/inventoryManagement/stockReport/index.vue
index 89773cf..8139508 100644
--- a/src/views/inventoryManagement/stockReport/index.vue
+++ b/src/views/inventoryManagement/stockReport/index.vue
@@ -4,708 +4,683 @@
     <div class="search_form">
       <div class="search_left">
         <span class="search_title">鎶ヨ〃绫诲瀷锛�</span>
-        <el-select
-          v-model="searchForm.reportType"
-          style="width: 150px;"
-          placeholder="璇烽�夋嫨"
-          @change="handleReportTypeChange"
-        >
-          <el-option label="鏃ユ姤" value="daily" />
-          <el-option label="鏈堟姤" value="monthly" />
-          <el-option label="杩涘嚭瀛樻姤琛�" value="inout" />
+        <el-select v-model="searchForm.reportType"
+                   style="width: 150px;"
+                   placeholder="璇烽�夋嫨"
+                   @change="handleReportTypeChange">
+          <el-option label="鏃ユ姤"
+                     value="daily" />
+          <el-option label="鏈堟姤"
+                     value="monthly" />
+          <el-option label="杩涘嚭瀛樻姤琛�"
+                     value="inout" />
         </el-select>
-        
         <span class="search_title ml10">鏃堕棿鑼冨洿锛�</span>
-         <el-date-picker
-           v-if="searchForm.reportType === 'daily'"
-           v-model="searchForm.singleDate"
-           type="date"
-           placeholder="璇烽�夋嫨鏃ユ湡"
-           format="YYYY-MM-DD"
-           value-format="YYYY-MM-DD"
-           style="width: 200px;"
-         />
-        <el-date-picker
-          v-else-if="searchForm.reportType === 'monthly'"
-          v-model="searchForm.monthRange"
-          type="monthrange"
-          range-separator="鑷�"
-          start-placeholder="寮�濮嬫湀浠�"
-          end-placeholder="缁撴潫鏈堜唤"
-          format="YYYY-MM-DD"
-          value-format="YYYY-MM-DD"
-          style="width: 240px;"
-        />
-        <el-date-picker
-          v-else
-          v-model="searchForm.dateRange"
-          type="daterange"
-          range-separator="鑷�"
-          start-placeholder="寮�濮嬫棩鏈�"
-          end-placeholder="缁撴潫鏃ユ湡"
-          format="YYYY-MM-DD"
-          value-format="YYYY-MM-DD"
-          style="width: 240px;"
-        />
-        
-        <el-button type="primary" @click="onSearch" style="margin-left: 10px">
+        <el-date-picker v-if="searchForm.reportType === 'daily'"
+                        v-model="searchForm.singleDate"
+                        type="date"
+                        placeholder="璇烽�夋嫨鏃ユ湡"
+                        format="YYYY-MM-DD"
+                        value-format="YYYY-MM-DD"
+                        style="width: 200px;" />
+        <el-date-picker v-else-if="searchForm.reportType === 'monthly'"
+                        v-model="searchForm.monthRange"
+                        type="monthrange"
+                        range-separator="鑷�"
+                        start-placeholder="寮�濮嬫湀浠�"
+                        end-placeholder="缁撴潫鏈堜唤"
+                        format="YYYY-MM-DD"
+                        value-format="YYYY-MM-DD"
+                        style="width: 240px;" />
+        <el-date-picker v-else
+                        v-model="searchForm.dateRange"
+                        type="daterange"
+                        range-separator="鑷�"
+                        start-placeholder="寮�濮嬫棩鏈�"
+                        end-placeholder="缁撴潫鏃ユ湡"
+                        format="YYYY-MM-DD"
+                        value-format="YYYY-MM-DD"
+                        style="width: 240px;" />
+        <el-button type="primary"
+                   @click="onSearch"
+                   style="margin-left: 10px">
           鏌ヨ
         </el-button>
         <el-button @click="handleReset">閲嶇疆</el-button>
       </div>
-
       <div class="search_right">
-<!--        <el-button type="success" @click="handleExport" icon="Download">-->
-<!--          瀵煎嚭鎶ヨ〃-->
-<!--        </el-button>-->
+        <!--        <el-button type="success" @click="handleExport" icon="Download">-->
+        <!--          瀵煎嚭鎶ヨ〃-->
+        <!--        </el-button>-->
       </div>
     </div>
-
-<!--    &lt;!&ndash; 缁熻鍗$墖 &ndash;&gt;-->
-<!--    <div class="stats_cards" v-if="reportData.summary">-->
-<!--      <el-row :gutter="20">-->
-<!--        <el-col :span="6">-->
-<!--          <el-card class="stats_card">-->
-<!--            <div class="stats_content">-->
-<!--              <div class="stats_icon in">-->
-<!--                <el-icon><TrendCharts /></el-icon>-->
-<!--              </div>-->
-<!--              <div class="stats_info">-->
-<!--                <div class="stats_value">{{ reportData.summary.totalIn || 0 }}</div>-->
-<!--                <div class="stats_label">鎬诲叆搴撻噺</div>-->
-<!--              </div>-->
-<!--            </div>-->
-<!--          </el-card>-->
-<!--        </el-col>-->
-<!--        <el-col :span="6">-->
-<!--          <el-card class="stats_card">-->
-<!--            <div class="stats_content">-->
-<!--              <div class="stats_icon out">-->
-<!--                <el-icon><TrendCharts /></el-icon>-->
-<!--              </div>-->
-<!--              <div class="stats_info">-->
-<!--                <div class="stats_value">{{ reportData.summary.totalOut || 0 }}</div>-->
-<!--                <div class="stats_label">鎬诲嚭搴撻噺</div>-->
-<!--              </div>-->
-<!--            </div>-->
-<!--          </el-card>-->
-<!--        </el-col>-->
-<!--        <el-col :span="6">-->
-<!--          <el-card class="stats_card">-->
-<!--            <div class="stats_content">-->
-<!--              <div class="stats_icon stock">-->
-<!--                <el-icon><Box /></el-icon>-->
-<!--              </div>-->
-<!--              <div class="stats_info">-->
-<!--                <div class="stats_value">{{ reportData.summary.currentStock || 0 }}</div>-->
-<!--                <div class="stats_label">褰撳墠搴撳瓨</div>-->
-<!--              </div>-->
-<!--            </div>-->
-<!--          </el-card>-->
-<!--        </el-col>-->
-<!--        <el-col :span="6">-->
-<!--          <el-card class="stats_card">-->
-<!--            <div class="stats_content">-->
-<!--              <div class="stats_icon turnover">-->
-<!--                <el-icon><Refresh /></el-icon>-->
-<!--              </div>-->
-<!--              <div class="stats_info">-->
-<!--                <div class="stats_value">{{ reportData.summary.turnoverRate || 0 }}%</div>-->
-<!--                <div class="stats_label">鍛ㄨ浆鐜�</div>-->
-<!--              </div>-->
-<!--            </div>-->
-<!--          </el-card>-->
-<!--        </el-col>-->
-<!--      </el-row>-->
-<!--    </div>-->
-
-<!--    &lt;!&ndash; 鍥捐〃鍖哄煙 &ndash;&gt;-->
-<!--    <div class="chart_section" v-if="reportData.chartData">-->
-<!--      <el-row :gutter="20">-->
-<!--        <el-col :span="12">-->
-<!--          <el-card>-->
-<!--            <template #header>-->
-<!--              <span>搴撳瓨瓒嬪娍鍥�</span>-->
-<!--            </template>-->
-<!--            <div ref="trendChart" style="height: 300px;"></div>-->
-<!--          </el-card>-->
-<!--        </el-col>-->
-<!--        <el-col :span="12">-->
-<!--          <el-card>-->
-<!--            <template #header>-->
-<!--              <span>杩涘嚭搴撳姣�</span>-->
-<!--            </template>-->
-<!--            <div ref="comparisonChart" style="height: 300px;"></div>-->
-<!--          </el-card>-->
-<!--        </el-col>-->
-<!--      </el-row>-->
-<!--    </div>-->
-
+    <!--    &lt;!&ndash; 缁熻鍗$墖 &ndash;&gt;-->
+    <!--    <div class="stats_cards" v-if="reportData.summary">-->
+    <!--      <el-row :gutter="20">-->
+    <!--        <el-col :span="6">-->
+    <!--          <el-card class="stats_card">-->
+    <!--            <div class="stats_content">-->
+    <!--              <div class="stats_icon in">-->
+    <!--                <el-icon><TrendCharts /></el-icon>-->
+    <!--              </div>-->
+    <!--              <div class="stats_info">-->
+    <!--                <div class="stats_value">{{ reportData.summary.totalIn || 0 }}</div>-->
+    <!--                <div class="stats_label">鎬诲叆搴撻噺</div>-->
+    <!--              </div>-->
+    <!--            </div>-->
+    <!--          </el-card>-->
+    <!--        </el-col>-->
+    <!--        <el-col :span="6">-->
+    <!--          <el-card class="stats_card">-->
+    <!--            <div class="stats_content">-->
+    <!--              <div class="stats_icon out">-->
+    <!--                <el-icon><TrendCharts /></el-icon>-->
+    <!--              </div>-->
+    <!--              <div class="stats_info">-->
+    <!--                <div class="stats_value">{{ reportData.summary.totalOut || 0 }}</div>-->
+    <!--                <div class="stats_label">鎬诲嚭搴撻噺</div>-->
+    <!--              </div>-->
+    <!--            </div>-->
+    <!--          </el-card>-->
+    <!--        </el-col>-->
+    <!--        <el-col :span="6">-->
+    <!--          <el-card class="stats_card">-->
+    <!--            <div class="stats_content">-->
+    <!--              <div class="stats_icon stock">-->
+    <!--                <el-icon><Box /></el-icon>-->
+    <!--              </div>-->
+    <!--              <div class="stats_info">-->
+    <!--                <div class="stats_value">{{ reportData.summary.currentStock || 0 }}</div>-->
+    <!--                <div class="stats_label">褰撳墠搴撳瓨</div>-->
+    <!--              </div>-->
+    <!--            </div>-->
+    <!--          </el-card>-->
+    <!--        </el-col>-->
+    <!--        <el-col :span="6">-->
+    <!--          <el-card class="stats_card">-->
+    <!--            <div class="stats_content">-->
+    <!--              <div class="stats_icon turnover">-->
+    <!--                <el-icon><Refresh /></el-icon>-->
+    <!--              </div>-->
+    <!--              <div class="stats_info">-->
+    <!--                <div class="stats_value">{{ reportData.summary.turnoverRate || 0 }}%</div>-->
+    <!--                <div class="stats_label">鍛ㄨ浆鐜�</div>-->
+    <!--              </div>-->
+    <!--            </div>-->
+    <!--          </el-card>-->
+    <!--        </el-col>-->
+    <!--      </el-row>-->
+    <!--    </div>-->
+    <!--    &lt;!&ndash; 鍥捐〃鍖哄煙 &ndash;&gt;-->
+    <!--    <div class="chart_section" v-if="reportData.chartData">-->
+    <!--      <el-row :gutter="20">-->
+    <!--        <el-col :span="12">-->
+    <!--          <el-card>-->
+    <!--            <template #header>-->
+    <!--              <span>搴撳瓨瓒嬪娍鍥�</span>-->
+    <!--            </template>-->
+    <!--            <div ref="trendChart" style="height: 300px;"></div>-->
+    <!--          </el-card>-->
+    <!--        </el-col>-->
+    <!--        <el-col :span="12">-->
+    <!--          <el-card>-->
+    <!--            <template #header>-->
+    <!--              <span>杩涘嚭搴撳姣�</span>-->
+    <!--            </template>-->
+    <!--            <div ref="comparisonChart" style="height: 300px;"></div>-->
+    <!--          </el-card>-->
+    <!--        </el-col>-->
+    <!--      </el-row>-->
+    <!--    </div>-->
     <!-- 璇︾粏鏁版嵁琛ㄦ牸 -->
     <div class="table_section">
       <el-card>
         <template #header>
           <span>{{ getTableTitle() }}</span>
         </template>
-         <el-table
-           v-loading="tableLoading"
-           :data="reportData.tableData"
-           border
-           height="400"
-           style="width: 100%"
-           :header-cell-style="{ background: '#F0F1F5', color: '#333333' }"
-         >
-          <el-table-column
-            align="center"
-            label="搴忓彿"
-            type="index"
-            width="60"
-          />
-           <el-table-column
-             label="鍏ュ簱鏃堕棿"
-             prop="createTime"
-             width="200"
-             show-overflow-tooltip
-             v-if="searchForm.reportType !== 'inout'"
-           />
-           <el-table-column
-             label="鍏ュ簱鎵规"
-             prop="inboundBatches"
-             width="240"
-             show-overflow-tooltip
-             v-if="searchForm.reportType !== 'inout'"
-           />
-           <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="totalStockIn"
-             align="center"
-             v-if="searchForm.reportType === 'inout'"
-           />
-           <el-table-column
-               label="鍏ュ簱鏁伴噺"
-               prop="stockInNum"
-               align="center"
-               v-else
-           />
-           <el-table-column
-             label="鍑哄簱鏁伴噺"
-             prop="totalStockOut"
-             width="100"
-             align="center"
-             v-if="searchForm.reportType === 'inout'"
-           />
-           <el-table-column
-             label="鐜板湪搴撳瓨"
-             prop="currentStock"
-             align="center"
-           />
-           <el-table-column label="鏉ユ簮"
-                            prop="recordType"
-                            v-if="searchForm.reportType !== 'inout'"
-                            show-overflow-tooltip>
-             <template #default="scope">
-               {{ getRecordType(scope.row.recordType) }}
-             </template>
-           </el-table-column>
-           <el-table-column
-             label="鍏ュ簱浜�"
-             prop="createBy"
-             width="80"
-             v-if="searchForm.reportType !== 'inout'"
-             show-overflow-tooltip
-           />
+        <el-table v-loading="tableLoading"
+                  :data="reportData.tableData"
+                  border
+                  height="400"
+                  style="width: 100%"
+                  :header-cell-style="{ background: '#F0F1F5', color: '#333333' }">
+          <el-table-column align="center"
+                           label="搴忓彿"
+                           type="index"
+                           width="60" />
+          <el-table-column label="鍏ュ簱鏃堕棿"
+                           prop="createTime"
+                           width="200"
+                           show-overflow-tooltip
+                           v-if="searchForm.reportType !== 'inout'" />
+          <el-table-column label="鍏ュ簱鎵规"
+                           prop="inboundBatches"
+                           width="180"
+                           show-overflow-tooltip
+                           v-if="searchForm.reportType !== 'inout'" />
+          <el-table-column label="鎵瑰彿"
+                           prop="batchNo"
+                           width="180"
+                           show-overflow-tooltip
+                           v-if="searchForm.reportType !== 'inout'" />
+          <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="totalStockIn"
+                           align="center"
+                           v-if="searchForm.reportType === 'inout'" />
+          <el-table-column label="鍏ュ簱鏁伴噺"
+                           prop="stockInNum"
+                           align="center"
+                           v-else />
+          <el-table-column label="鍑哄簱鏁伴噺"
+                           prop="totalStockOut"
+                           width="100"
+                           align="center"
+                           v-if="searchForm.reportType === 'inout'" />
+          <el-table-column label="鐜板湪搴撳瓨"
+                           prop="currentStock"
+                           align="center" />
+          <el-table-column label="鏉ユ簮"
+                           prop="recordType"
+                           v-if="searchForm.reportType !== 'inout'"
+                           show-overflow-tooltip>
+            <template #default="scope">
+              {{ getRecordType(scope.row.recordType) }}
+            </template>
+          </el-table-column>
+          <el-table-column label="鍏ュ簱浜�"
+                           prop="createBy"
+                           width="80"
+                           v-if="searchForm.reportType !== 'inout'"
+                           show-overflow-tooltip />
         </el-table>
-        <pagination
-          :total="total"
-          layout="total, sizes, prev, pager, next, jumper"
-          :page="page.current"
-          :limit="page.size"
-          @pagination="paginationChange"
-        />
+        <pagination :total="total"
+                    layout="total, sizes, prev, pager, next, jumper"
+                    :page="page.current"
+                    :limit="page.size"
+                    @pagination="paginationChange" />
       </el-card>
     </div>
   </div>
 </template>
 
 <script setup>
-import { ref, reactive, onMounted, nextTick, getCurrentInstance } from 'vue'
-import { ElMessage } from 'element-plus'
-import * as echarts from 'echarts'
-import pagination from '@/components/PIMTable/Pagination.vue'
-import {
-  getStockInventoryInAndOutReportList,
-  getStockInventoryReportList
-} from "@/api/inventoryManagement/stockInventory.js";
-import {
-  findAllQualifiedStockInRecordTypeOptions,findAllUnQualifiedStockInRecordTypeOptions,
-} from "@/api/basicData/enum.js";
+  import { ref, reactive, onMounted, nextTick, getCurrentInstance } from "vue";
+  import { ElMessage } from "element-plus";
+  import * as echarts from "echarts";
+  import pagination from "@/components/PIMTable/Pagination.vue";
+  import {
+    getStockInventoryInAndOutReportList,
+    getStockInventoryReportList,
+  } from "@/api/inventoryManagement/stockInventory.js";
+  import {
+    findAllQualifiedStockInRecordTypeOptions,
+    findAllUnQualifiedStockInRecordTypeOptions,
+  } from "@/api/basicData/enum.js";
 
+  const { proxy } = getCurrentInstance();
+  // 鍝嶅簲寮忔暟鎹�
+  const tableLoading = ref(false);
+  const trendChart = ref(null);
+  const comparisonChart = ref(null);
 
-const { proxy } = getCurrentInstance()
-// 鍝嶅簲寮忔暟鎹�
-const tableLoading = ref(false)
-const trendChart = ref(null)
-const comparisonChart = ref(null)
+  const searchForm = reactive({
+    reportType: "daily",
+    singleDate: "",
+    dateRange: [],
+    monthRange: [],
+  });
 
-const searchForm = reactive({
-  reportType: 'daily',
-  singleDate: '',
-  dateRange: [],
-  monthRange: []
-})
-
-const reportData = ref({
-  summary: null,
-  chartData: null,
-  tableData: []
-})
-
-const page = reactive({
-  current: 1,
-  size: 10,
-})
-
-const total = ref(0)
-
-const stockRecordTypeOptions = ref([])
-
-const getRecordType = (recordType) => {
-  return stockRecordTypeOptions.value.find(item => item.value === recordType)?.label || ''
-}
-
-// 鑾峰彇鏉ユ簮绫诲瀷閫夐」
-const fetchStockRecordTypeOptions = () => {
-  findAllQualifiedStockInRecordTypeOptions()
-      .then(res => {
-        stockRecordTypeOptions.value = res.data;
-        findAllUnQualifiedStockInRecordTypeOptions()
-          .then(res => {
-          stockRecordTypeOptions.value = [...stockRecordTypeOptions.value,...res.data];
-      })
-      })
-}
-
-// 鑾峰彇琛ㄦ牸鏍囬
-const getTableTitle = () => {
-  const typeMap = {
-    daily: '鏃ユ姤璇︾粏鏁版嵁',
-    monthly: '鏈堟姤璇︾粏鏁版嵁',
-    inout: '杩涘嚭瀛樻姤琛ㄨ缁嗘暟鎹�'
-  }
-  return typeMap[searchForm.reportType] || '鎶ヨ〃璇︾粏鏁版嵁'
-}
-
-// 鎶ヨ〃绫诲瀷鏀瑰彉
-const handleReportTypeChange = () => {
-  page.current = 1
-  reportData.value = {
+  const reportData = ref({
     summary: null,
     chartData: null,
-    tableData: []
-  }
-}
+    tableData: [],
+  });
 
-// 鏌ヨ鏁版嵁
-const handleQuery = async () => {
-  if (!validateSearchForm()) {
-    return
-  }
-  
-  tableLoading.value = true
-  try {
-    const baseParams = getQueryParams()
+  const page = reactive({
+    current: 1,
+    size: 10,
+  });
+
+  const total = ref(0);
+
+  const stockRecordTypeOptions = ref([]);
+
+  const getRecordType = recordType => {
+    return (
+      stockRecordTypeOptions.value.find(item => item.value === recordType)
+        ?.label || ""
+    );
+  };
+
+  // 鑾峰彇鏉ユ簮绫诲瀷閫夐」
+  const fetchStockRecordTypeOptions = () => {
+    findAllQualifiedStockInRecordTypeOptions().then(res => {
+      stockRecordTypeOptions.value = res.data;
+      findAllUnQualifiedStockInRecordTypeOptions().then(res => {
+        stockRecordTypeOptions.value = [
+          ...stockRecordTypeOptions.value,
+          ...res.data,
+        ];
+      });
+    });
+  };
+
+  // 鑾峰彇琛ㄦ牸鏍囬
+  const getTableTitle = () => {
+    const typeMap = {
+      daily: "鏃ユ姤璇︾粏鏁版嵁",
+      monthly: "鏈堟姤璇︾粏鏁版嵁",
+      inout: "杩涘嚭瀛樻姤琛ㄨ缁嗘暟鎹�",
+    };
+    return typeMap[searchForm.reportType] || "鎶ヨ〃璇︾粏鏁版嵁";
+  };
+
+  // 鎶ヨ〃绫诲瀷鏀瑰彉
+  const handleReportTypeChange = () => {
+    page.current = 1;
+    reportData.value = {
+      summary: null,
+      chartData: null,
+      tableData: [],
+    };
+  };
+
+  // 鏌ヨ鏁版嵁
+  const handleQuery = async () => {
+    if (!validateSearchForm()) {
+      return;
+    }
+
+    tableLoading.value = true;
+    try {
+      const baseParams = getQueryParams();
+      const params = {
+        ...baseParams,
+        current: page.current,
+        size: page.size,
+      };
+      let response;
+
+      if (searchForm.reportType === "inout") {
+        response = await getStockInventoryInAndOutReportList(params);
+      } else {
+        response = await getStockInventoryReportList(params);
+      }
+      if (response.code === 200) {
+        reportData.value.tableData = response.data.records || [];
+        total.value = response.data.total || 0;
+        // reportData.value.summary = response.data.summary
+        // reportData.value.chartData = response.data.chartData
+        // nextTick(() => {
+        //   initCharts()
+        // })
+      }
+    } catch (error) {
+      ElMessage.error("鏌ヨ澶辫触锛�" + error.message);
+    } finally {
+      tableLoading.value = false;
+    }
+  };
+
+  // 鏌ヨ鎸夐挳锛氶噸缃埌绗竴椤靛苟鏌ヨ
+  const onSearch = () => {
+    page.current = 1;
+    handleQuery();
+  };
+
+  // 鍒嗛〉鍙樺寲
+  const paginationChange = obj => {
+    page.current = obj.page;
+    page.size = obj.limit;
+    handleQuery();
+  };
+  // // 鐢熸垚鍋囨暟鎹�
+  // const generateMockData = () => {
+  //   // 鐢熸垚缁熻鍗$墖鍋囨暟鎹�
+  //   const summary = {
+  //     totalIn: 1000,
+  //     totalOut: 600,
+  //     currentStock: 400,
+  //     turnoverRate: 30
+  //   }
+
+  //   // 鐢熸垚鍥捐〃鍋囨暟鎹�
+  //   const trendDates = ['2025-09-15', '2025-09-16', '2025-09-17', '2025-09-18', '2025-09-19']
+  //   const trendValues = [300, 350, 400, 380, 420]
+  //   const comparisonDates = ['2025-09-15', '2025-09-16', '2025-09-17']
+  //   const inValues = [100, 150, 200]
+  //   const outValues = [80, 120, 100]
+
+  //   const chartData = {
+  //     trendDates,
+  //     trendValues,
+  //     comparisonDates,
+  //     inValues,
+  //     outValues
+  //   }
+
+  //   reportData.value = {
+  //     summary,
+  //     chartData,
+  //     tableData: []
+  //   }
+  // }
+  // 楠岃瘉鎼滅储琛ㄥ崟
+  const validateSearchForm = () => {
+    if (searchForm.reportType === "daily") {
+      if (!searchForm.singleDate) {
+        ElMessage.warning("璇烽�夋嫨鏃ユ湡");
+        return false;
+      }
+    } else if (searchForm.reportType === "inout") {
+      if (!searchForm.dateRange || searchForm.dateRange.length !== 2) {
+        ElMessage.warning("璇烽�夋嫨鏃ユ湡鑼冨洿");
+        return false;
+      }
+    } else if (searchForm.reportType === "monthly") {
+      if (!searchForm.monthRange || searchForm.monthRange.length !== 2) {
+        ElMessage.warning("璇烽�夋嫨鏈堜唤鑼冨洿");
+        return false;
+      }
+    }
+    return true;
+  };
+
+  // 鑾峰彇鏌ヨ鍙傛暟
+  const getQueryParams = () => {
     const params = {
-      ...baseParams,
-      current: page.current,
-      size: page.size,
-    }
-    let response
+      reportType: searchForm.reportType,
+      reportDate: "",
+      startMonth: "",
+      endMonth: "",
+      startDate: "",
+      endDate: "",
+    };
 
-    if (searchForm.reportType === 'inout') {
-      response = await getStockInventoryInAndOutReportList(params)
+    if (searchForm.reportType === "daily") {
+      params.reportDate = searchForm.singleDate;
+    } else if (searchForm.reportType === "monthly") {
+      params.startMonth = searchForm.monthRange[0];
+      params.endMonth = searchForm.monthRange[1];
     } else {
-      response = await getStockInventoryReportList(params)
+      params.startDate = searchForm.dateRange[0];
+      params.endDate = searchForm.dateRange[1];
     }
-    if (response.code === 200) {
-      reportData.value.tableData = response.data.records || []
-      total.value = response.data.total || 0
-      // reportData.value.summary = response.data.summary
-      // reportData.value.chartData = response.data.chartData
-      // nextTick(() => {
-      //   initCharts()
-      // })
-      
+
+    return params;
+  };
+
+  // 閲嶇疆鎼滅储
+  const handleReset = () => {
+    searchForm.reportType = "daily";
+    searchForm.singleDate = "";
+    searchForm.dateRange = [];
+    searchForm.monthRange = [];
+    reportData.value = {
+      summary: null,
+      chartData: null,
+      tableData: [],
+    };
+  };
+
+  // 瀵煎嚭鎶ヨ〃
+  const handleExport = async () => {
+    if (!validateSearchForm()) {
+      return;
     }
-  } catch (error) {
-    ElMessage.error('鏌ヨ澶辫触锛�' + error.message)
-  } finally {
-    tableLoading.value = false
-  }
-}
 
-// 鏌ヨ鎸夐挳锛氶噸缃埌绗竴椤靛苟鏌ヨ
-const onSearch = () => {
-  page.current = 1
-  handleQuery()
-}
+    try {
+      const params = getQueryParams();
+      // const response = await exportStockReport(params)
+      proxy.download("/stockin/exportCopy", params, "搴撳瓨鎶ヨ〃.xlsx");
+      // 鍒涘缓涓嬭浇閾炬帴
+      // const blob = new Blob([response], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' })
+      // const url = window.URL.createObjectURL(blob)
+      // const link = document.createElement('a')
+      // link.href = url
+      // link.download = `${getTableTitle()}_${new Date().getTime()}.xlsx`
+      // document.body.appendChild(link)
+      // link.click()
+      // document.body.removeChild(link)
+      // window.URL.revokeObjectURL(url)
 
-// 鍒嗛〉鍙樺寲
-const paginationChange = (obj) => {
-  page.current = obj.page
-  page.size = obj.limit
-  handleQuery()
-}
-// // 鐢熸垚鍋囨暟鎹�
-// const generateMockData = () => {
-//   // 鐢熸垚缁熻鍗$墖鍋囨暟鎹�
-//   const summary = {
-//     totalIn: 1000,
-//     totalOut: 600,
-//     currentStock: 400,
-//     turnoverRate: 30
-//   }
-
-//   // 鐢熸垚鍥捐〃鍋囨暟鎹�
-//   const trendDates = ['2025-09-15', '2025-09-16', '2025-09-17', '2025-09-18', '2025-09-19']
-//   const trendValues = [300, 350, 400, 380, 420]
-//   const comparisonDates = ['2025-09-15', '2025-09-16', '2025-09-17']
-//   const inValues = [100, 150, 200]
-//   const outValues = [80, 120, 100]
-
-//   const chartData = {
-//     trendDates,
-//     trendValues,
-//     comparisonDates,
-//     inValues,
-//     outValues
-//   }
-
-//   reportData.value = {
-//     summary,
-//     chartData,
-//     tableData: []
-//   }
-// }
-// 楠岃瘉鎼滅储琛ㄥ崟
-const validateSearchForm = () => {
-  if (searchForm.reportType === 'daily') {
-    if (!searchForm.singleDate) {
-      ElMessage.warning('璇烽�夋嫨鏃ユ湡')
-      return false
+      // ElMessage.success('瀵煎嚭鎴愬姛')
+    } catch (error) {
+      ElMessage.error("瀵煎嚭澶辫触锛�" + error.message);
     }
-  } else if (searchForm.reportType === 'inout') {
-    if (!searchForm.dateRange || searchForm.dateRange.length !== 2) {
-      ElMessage.warning('璇烽�夋嫨鏃ユ湡鑼冨洿')
-      return false
-    }
-  } else if (searchForm.reportType === 'monthly') {
-    if (!searchForm.monthRange || searchForm.monthRange.length !== 2) {
-      ElMessage.warning('璇烽�夋嫨鏈堜唤鑼冨洿')
-      return false
-    }
-  }
-  return true
-}
+  };
 
-// 鑾峰彇鏌ヨ鍙傛暟
-const getQueryParams = () => {
-  const params = {
-    reportType: searchForm.reportType,
-    reportDate: "",
-    startMonth: "",
-    endMonth: "",
-    startDate: "",
-    endDate: ""
-  }
-  
-  if (searchForm.reportType === 'daily') {
-    params.reportDate = searchForm.singleDate
-  } else if (searchForm.reportType === 'monthly') {
-    params.startMonth = searchForm.monthRange[0]
-    params.endMonth = searchForm.monthRange[1]
-  } else {
-    params.startDate = searchForm.dateRange[0]
-    params.endDate = searchForm.dateRange[1]
-  }
-  
-  return params
-}
+  // 鍒濆鍖栧浘琛�
+  const initCharts = () => {
+    if (!reportData.value.chartData) return;
 
-// 閲嶇疆鎼滅储
-const handleReset = () => {
-  searchForm.reportType = 'daily'
-  searchForm.singleDate = ''
-  searchForm.dateRange = []
-  searchForm.monthRange = []
-  reportData.value = {
-    summary: null,
-    chartData: null,
-    tableData: []
-  }
-}
+    initTrendChart();
+    initComparisonChart();
+  };
 
-// 瀵煎嚭鎶ヨ〃
-const handleExport = async () => {
-  if (!validateSearchForm()) {
-    return
-  }
-  
-  try {
-    const params = getQueryParams()
-    // const response = await exportStockReport(params)
-    proxy.download("/stockin/exportCopy", params, '搴撳瓨鎶ヨ〃.xlsx')
-    // 鍒涘缓涓嬭浇閾炬帴
-    // const blob = new Blob([response], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' })
-    // const url = window.URL.createObjectURL(blob)
-    // const link = document.createElement('a')
-    // link.href = url
-    // link.download = `${getTableTitle()}_${new Date().getTime()}.xlsx`
-    // document.body.appendChild(link)
-    // link.click()
-    // document.body.removeChild(link)
-    // window.URL.revokeObjectURL(url)
-    
-    // ElMessage.success('瀵煎嚭鎴愬姛')
-  } catch (error) {
-    ElMessage.error('瀵煎嚭澶辫触锛�' + error.message)
-  }
-}
+  // 鍒濆鍖栬秼鍔垮浘
+  const initTrendChart = () => {
+    if (!trendChart.value) return;
 
-// 鍒濆鍖栧浘琛�
-const initCharts = () => {
-  if (!reportData.value.chartData) return
-  
-  initTrendChart()
-  initComparisonChart()
-}
-
-// 鍒濆鍖栬秼鍔垮浘
-const initTrendChart = () => {
-  if (!trendChart.value) return
-  
-  const chart = echarts.init(trendChart.value)
-  const option = {
-    title: {
-      text: '搴撳瓨鍙樺寲瓒嬪娍',
-      left: 'center'
-    },
-    tooltip: {
-      trigger: 'axis'
-    },
-    legend: {
-      data: ['搴撳瓨閲�'],
-      top: 30
-    },
-    xAxis: {
-      type: 'category',
-      data: reportData.value.chartData.trendDates || []
-    },
-    yAxis: {
-      type: 'value'
-    },
-    series: [{
-      name: '搴撳瓨閲�',
-      type: 'line',
-      data: reportData.value.chartData.trendValues || [],
-      smooth: true,
-      itemStyle: {
-        color: '#409EFF'
-      }
-    }]
-  }
-  chart.setOption(option)
-}
-
-// 鍒濆鍖栧姣斿浘
-const initComparisonChart = () => {
-  if (!comparisonChart.value) return
-  
-  const chart = echarts.init(comparisonChart.value)
-  const option = {
-    title: {
-      text: '杩涘嚭搴撳姣�',
-      left: 'center'
-    },
-    tooltip: {
-      trigger: 'axis'
-    },
-    legend: {
-      data: ['鍏ュ簱', '鍑哄簱'],
-      top: 30
-    },
-    xAxis: {
-      type: 'category',
-      data: reportData.value.chartData.comparisonDates || []
-    },
-    yAxis: {
-      type: 'value'
-    },
-    series: [
-      {
-        name: '鍏ュ簱',
-        type: 'bar',
-        data: reportData.value.chartData.inValues || [],
-        itemStyle: {
-          color: '#67C23A'
-        }
+    const chart = echarts.init(trendChart.value);
+    const option = {
+      title: {
+        text: "搴撳瓨鍙樺寲瓒嬪娍",
+        left: "center",
       },
-      {
-        name: '鍑哄簱',
-        type: 'bar',
-        data: reportData.value.chartData.outValues || [],
-        itemStyle: {
-          color: '#F56C6C'
-        }
-      }
-    ]
-  }
-  chart.setOption(option)
-}
+      tooltip: {
+        trigger: "axis",
+      },
+      legend: {
+        data: ["搴撳瓨閲�"],
+        top: 30,
+      },
+      xAxis: {
+        type: "category",
+        data: reportData.value.chartData.trendDates || [],
+      },
+      yAxis: {
+        type: "value",
+      },
+      series: [
+        {
+          name: "搴撳瓨閲�",
+          type: "line",
+          data: reportData.value.chartData.trendValues || [],
+          smooth: true,
+          itemStyle: {
+            color: "#409EFF",
+          },
+        },
+      ],
+    };
+    chart.setOption(option);
+  };
 
-// 缁勪欢鎸傝浇鏃惰缃粯璁ゆ椂闂�
-onMounted(() => {
-  const today = new Date()
-  searchForm.singleDate = today.toISOString().split('T')[0]
-  
-  const yesterday = new Date(today.getTime() - 24 * 60 * 60 * 1000)
-  searchForm.dateRange = [
-    yesterday.toISOString().split('T')[0],
-    today.toISOString().split('T')[0]
-  ]
+  // 鍒濆鍖栧姣斿浘
+  const initComparisonChart = () => {
+    if (!comparisonChart.value) return;
 
-  fetchStockRecordTypeOptions()
-  // 鍒濆鍖栧姞杞戒竴娆℃暟鎹�
-  handleQuery()
-})
+    const chart = echarts.init(comparisonChart.value);
+    const option = {
+      title: {
+        text: "杩涘嚭搴撳姣�",
+        left: "center",
+      },
+      tooltip: {
+        trigger: "axis",
+      },
+      legend: {
+        data: ["鍏ュ簱", "鍑哄簱"],
+        top: 30,
+      },
+      xAxis: {
+        type: "category",
+        data: reportData.value.chartData.comparisonDates || [],
+      },
+      yAxis: {
+        type: "value",
+      },
+      series: [
+        {
+          name: "鍏ュ簱",
+          type: "bar",
+          data: reportData.value.chartData.inValues || [],
+          itemStyle: {
+            color: "#67C23A",
+          },
+        },
+        {
+          name: "鍑哄簱",
+          type: "bar",
+          data: reportData.value.chartData.outValues || [],
+          itemStyle: {
+            color: "#F56C6C",
+          },
+        },
+      ],
+    };
+    chart.setOption(option);
+  };
+
+  // 缁勪欢鎸傝浇鏃惰缃粯璁ゆ椂闂�
+  onMounted(() => {
+    const today = new Date();
+    searchForm.singleDate = today.toISOString().split("T")[0];
+
+    const yesterday = new Date(today.getTime() - 24 * 60 * 60 * 1000);
+    searchForm.dateRange = [
+      yesterday.toISOString().split("T")[0],
+      today.toISOString().split("T")[0],
+    ];
+
+    fetchStockRecordTypeOptions();
+    // 鍒濆鍖栧姞杞戒竴娆℃暟鎹�
+    handleQuery();
+  });
 </script>
 
 <style scoped>
-.app-container {
-  padding: 20px;
-}
+  .app-container {
+    padding: 20px;
+  }
 
-.search_form {
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  margin-bottom: 20px;
-  padding: 20px;
-  background: #fff;
-  border-radius: 4px;
-  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
-}
+  .search_form {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 20px;
+    padding: 20px;
+    background: #fff;
+    border-radius: 4px;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+  }
 
-.search_left {
-  display: flex;
-  align-items: center;
-}
+  .search_left {
+    display: flex;
+    align-items: center;
+  }
 
-.search_title {
-  font-weight: 500;
-  color: #333;
-  margin-right: 8px;
-}
+  .search_title {
+    font-weight: 500;
+    color: #333;
+    margin-right: 8px;
+  }
 
-.ml10 {
-  margin-left: 10px;
-}
+  .ml10 {
+    margin-left: 10px;
+  }
 
-.stats_cards {
-  margin-bottom: 20px;
-}
+  .stats_cards {
+    margin-bottom: 20px;
+  }
 
-.stats_card {
-  border-radius: 8px;
-  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
-}
+  .stats_card {
+    border-radius: 8px;
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+  }
 
-.stats_content {
-  display: flex;
-  align-items: center;
-  padding: 10px 0;
-}
+  .stats_content {
+    display: flex;
+    align-items: center;
+    padding: 10px 0;
+  }
 
-.stats_icon {
-  width: 50px;
-  height: 50px;
-  border-radius: 50%;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  margin-right: 15px;
-  font-size: 24px;
-  color: #fff;
-}
+  .stats_icon {
+    width: 50px;
+    height: 50px;
+    border-radius: 50%;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    margin-right: 15px;
+    font-size: 24px;
+    color: #fff;
+  }
 
-.stats_icon.in {
-  background: linear-gradient(135deg, #67C23A, #85CE61);
-}
+  .stats_icon.in {
+    background: linear-gradient(135deg, #67c23a, #85ce61);
+  }
 
-.stats_icon.out {
-  background: linear-gradient(135deg, #F56C6C, #F78989);
-}
+  .stats_icon.out {
+    background: linear-gradient(135deg, #f56c6c, #f78989);
+  }
 
-.stats_icon.stock {
-  background: linear-gradient(135deg, #409EFF, #66B1FF);
-}
+  .stats_icon.stock {
+    background: linear-gradient(135deg, #409eff, #66b1ff);
+  }
 
-.stats_icon.turnover {
-  background: linear-gradient(135deg, #E6A23C, #EEBE77);
-}
+  .stats_icon.turnover {
+    background: linear-gradient(135deg, #e6a23c, #eebe77);
+  }
 
-.stats_info {
-  flex: 1;
-}
+  .stats_info {
+    flex: 1;
+  }
 
-.stats_value {
-  font-size: 24px;
-  font-weight: bold;
-  color: #333;
-  line-height: 1;
-  margin-bottom: 5px;
-}
+  .stats_value {
+    font-size: 24px;
+    font-weight: bold;
+    color: #333;
+    line-height: 1;
+    margin-bottom: 5px;
+  }
 
-.stats_label {
-  font-size: 14px;
-  color: #666;
-}
+  .stats_label {
+    font-size: 14px;
+    color: #666;
+  }
 
-.chart_section {
-  margin-bottom: 20px;
-}
+  .chart_section {
+    margin-bottom: 20px;
+  }
 
-.table_section {
-  margin-bottom: 20px;
-}
+  .table_section {
+    margin-bottom: 20px;
+  }
 
-:deep(.el-card__header) {
-  background: #f8f9fa;
-  border-bottom: 1px solid #e9ecef;
-  font-weight: 500;
-}
+  :deep(.el-card__header) {
+    background: #f8f9fa;
+    border-bottom: 1px solid #e9ecef;
+    font-weight: 500;
+  }
 
-:deep(.el-table .el-table__header-wrapper th) {
-  background-color: #F0F1F5 !important;
-  color: #333333;
-  font-weight: 600;
-}
+  :deep(.el-table .el-table__header-wrapper th) {
+    background-color: #f0f1f5 !important;
+    color: #333333;
+    font-weight: 600;
+  }
 
-:deep(.el-table .el-table__body-wrapper td) {
-  padding: 8px 0;
-}
+  :deep(.el-table .el-table__body-wrapper td) {
+    padding: 8px 0;
+  }
 </style>
diff --git a/src/views/personnelManagement/dimission/components/formDia.vue b/src/views/personnelManagement/dimission/components/formDia.vue
index 84922ec..86c59ce 100644
--- a/src/views/personnelManagement/dimission/components/formDia.vue
+++ b/src/views/personnelManagement/dimission/components/formDia.vue
@@ -102,6 +102,7 @@
                     v-model="form.leaveDate"
                     type="date"
                     :disabled="operationType === 'edit'"
+                    :disabled-date="disabledFutureDate"
                     placeholder="璇烽�夋嫨绂昏亴鏃ユ湡"
                     value-format="YYYY-MM-DD"
                     format="YYYY-MM-DD"
@@ -180,6 +181,19 @@
 
 const dialogFormVisible = ref(false);
 const operationType = ref('')
+const getTodayDate = () => {
+  const now = new Date();
+  const year = now.getFullYear();
+  const month = `${now.getMonth() + 1}`.padStart(2, '0');
+  const day = `${now.getDate()}`.padStart(2, '0');
+  return `${year}-${month}-${day}`;
+};
+
+const disabledFutureDate = (time) => {
+  const todayEnd = new Date();
+  todayEnd.setHours(23, 59, 59, 999);
+  return time.getTime() > todayEnd.getTime();
+};
 const data = reactive({
   form: {
     staffOnJobId: undefined,
@@ -220,6 +234,7 @@
       }
     ]
   } else {
+    form.value.leaveDate = getTodayDate()
     getList()
   }
 }
@@ -329,4 +344,4 @@
   color: #303133;
   font-size: 14px;
 }
-</style>
\ No newline at end of file
+</style>
diff --git a/src/views/procurementManagement/purchaseReturnOrder/index.vue b/src/views/procurementManagement/purchaseReturnOrder/index.vue
index cd2c7f4..942b4dc 100644
--- a/src/views/procurementManagement/purchaseReturnOrder/index.vue
+++ b/src/views/procurementManagement/purchaseReturnOrder/index.vue
@@ -88,10 +88,10 @@
           <el-table-column label="鍚◣鍗曚环(鍏�)" prop="taxInclusiveUnitPrice" width="130">
             <template #default="scope">{{ formatAmount(scope.row.taxInclusiveUnitPrice) }}</template>
           </el-table-column>
-          <el-table-column label="鍚◣鎬讳环(鍏�)" prop="taxInclusiveTotalPrice" width="130">
+          <el-table-column label="閫�璐ф�讳环(鍏�)" prop="taxInclusiveTotalPrice" width="130">
             <template #default="scope">{{ formatAmount(scope.row.taxInclusiveTotalPrice) }}</template>
           </el-table-column>
-          <el-table-column label="涓嶅惈绋庢�讳环(鍏�)" prop="taxExclusiveTotalPrice" width="140">
+          <el-table-column label="涓嶉��璐ф�讳环(鍏�)" prop="taxExclusiveTotalPrice" width="140">
             <template #default="scope">{{ formatAmount(scope.row.taxExclusiveTotalPrice) }}</template>
           </el-table-column>
           <el-table-column label="鏄惁璐ㄦ" prop="isChecked" width="100" align="center">
@@ -182,7 +182,7 @@
     prop: 'returnUserName',
     width: 110,
   },
-  
+
   {
     label: '鏁村崟鎶樻墸棰�',
     prop: 'totalDiscountAmount',
@@ -236,7 +236,7 @@
       },
   ],
   },
-  
+
 ])
 const data = reactive({
   searchForm: {
@@ -281,8 +281,8 @@
     const payload = res?.data || {}
     detailData.value = payload
     // 鎷兼帴杩炰釜瀵硅薄鎴愪竴涓璞★紝鏂逛究灞曠ず item 鍜� item.salesLedgerProduct 閲岀殑瀛楁
-    
-    
+
+
     detailProducts.value =
       payload.purchaseReturnOrderProductsDetailVoList.map(item => ({ ...item, ...item.salesLedgerProduct })) ||
       []
diff --git a/src/views/productionManagement/processRoute/processRouteItem/index.vue b/src/views/productionManagement/processRoute/processRouteItem/index.vue
index 6d64c30..99d4ab1 100644
--- a/src/views/productionManagement/processRoute/processRouteItem/index.vue
+++ b/src/views/productionManagement/processRoute/processRouteItem/index.vue
@@ -111,6 +111,13 @@
       <el-table-column label="鍗曚綅"
                        prop="unit"
                        width="100" />
+      <el-table-column label="璁¤垂绫诲瀷"
+                       prop="type"
+                       width="100">
+        <template #default="scope">
+          {{scope.row.type==0 ? "璁℃椂" : "璁′欢"}}
+        </template>
+      </el-table-column>
       <el-table-column label="鏄惁璐ㄦ"
                        prop="isQuality"
                        width="100">
@@ -181,12 +188,16 @@
                   {{ item.model }}
                   <!-- <span v-if="item.unit" class="product-unit">{{ item.unit }}</span> -->
                 </div>
+                <el-tag class="product-tag"
+                        :type="item.type == 1 ? 'primary' : 'success'"
+                        style="margin-left: 8px;">{{ item.type==0?'璁℃椂':'璁′欢' }}</el-tag>
                 <el-tag type="primary"
                         class="product-tag"
+                        style="margin-left: 8px;"
                         v-if="item.isQuality">璐ㄦ</el-tag>
                 <el-tag type="primary"
                         class="product-tag"
-                        :style="item.isQuality?'margin-left:8px':''"
+                        style="margin-left: 8px;"
                         v-if="item.isProduction">鐢熶骇</el-tag>
               </div>
               <div v-else
@@ -424,6 +435,13 @@
                       v-else>
           <span>{{ form.unit }}</span>
         </el-form-item>
+        <el-form-item label="璁¤垂绫诲瀷"
+                      prop="type">
+          <el-radio-group v-model="form.type">
+            <el-radio :label="0">璁℃椂</el-radio>
+            <el-radio :label="1">璁′欢</el-radio>
+          </el-radio-group>
+        </el-form-item>
         <el-form-item label="鏄惁璐ㄦ"
                       prop="isQuality">
           <el-switch v-model="form.isQuality"
@@ -558,6 +576,7 @@
     model: "",
     unit: "",
     isQuality: false,
+    type: 0,
     isProduction: false,
   });
 
@@ -687,6 +706,7 @@
       model: row.model || "",
       unit: row.unit || "",
       isQuality: row.isQuality,
+      type: row.type || 0,
       isProduction: row.isProduction,
     };
     dialogVisible.value = true;
@@ -758,6 +778,7 @@
                 operationName: getProcessName(form.value.technologyOperationId),
                 productModelId: form.value.productModelId,
                 isQuality: form.value.isQuality,
+                type: form.value.type,
                 isProduction: form.value.isProduction,
                 dragSort,
               })
@@ -766,6 +787,7 @@
                 technologyOperationId: form.value.technologyOperationId,
                 productModelId: form.value.productModelId,
                 isQuality: form.value.isQuality,
+                type: form.value.type,
                 isProduction: form.value.isProduction,
                 dragSort,
               });
@@ -793,6 +815,7 @@
                 operationName: getProcessName(form.value.technologyOperationId),
                 productModelId: form.value.productModelId,
                 isQuality: form.value.isQuality,
+                type: form.value.type,
                 isProduction: form.value.isProduction,
               })
             : addOrUpdateProcessRouteItem1({
@@ -801,6 +824,7 @@
                 productModelId: form.value.productModelId,
                 id: form.value.id,
                 isQuality: form.value.isQuality,
+                type: form.value.type,
                 isProduction: form.value.isProduction,
               });
 
@@ -832,6 +856,7 @@
       model: "",
       unit: "",
       isQuality: false,
+      type: 0,
       isProduction: false,
     };
     formRef.value?.resetFields();
@@ -1068,6 +1093,7 @@
     processOptions.value.forEach(item => {
       if (item.id == value) {
         form.value.isQuality = item.isQuality;
+        form.value.type = item.type || 0;
         form.value.isProduction = item.isProduction;
       }
     });
diff --git a/src/views/productionManagement/productionCosting/index.vue b/src/views/productionManagement/productionCosting/index.vue
index 2dc63bd..5d42a7d 100644
--- a/src/views/productionManagement/productionCosting/index.vue
+++ b/src/views/productionManagement/productionCosting/index.vue
@@ -130,6 +130,11 @@
       minWidth: 100,
     },
     {
+      label: "宸ユ椂锛坔锛�",
+      prop: "workHour",
+      minWidth: 100,
+    },
+    {
       label: "鐢熶骇鏁伴噺",
       prop: "quantity",
       minWidth: 100,
diff --git a/src/views/productionManagement/productionOrder/components/MaterialLedgerDialog.vue b/src/views/productionManagement/productionOrder/components/MaterialLedgerDialog.vue
index 210dbba..d058896 100644
--- a/src/views/productionManagement/productionOrder/components/MaterialLedgerDialog.vue
+++ b/src/views/productionManagement/productionOrder/components/MaterialLedgerDialog.vue
@@ -312,12 +312,20 @@
         !item.materialName ||
         (Number(item.pickQty) > 0 &&
           (!item.batchNo || item.batchNo.length === 0)) ||
+        (item.batchNo && item.batchNo.length > 0 && Number(item.pickQty) <= 0) ||
         item.demandedQuantity === null ||
         item.demandedQuantity === undefined ||
         item.pickQty === null ||
         item.pickQty === undefined
     );
     if (invalidRow) {
+      if (
+        invalidRow.batchNo &&
+        invalidRow.batchNo.length > 0 &&
+        Number(invalidRow.pickQty) <= 0
+      ) {
+        return { valid: false, message: "閫夋嫨浜嗘壒鍙锋椂锛岄鐢ㄦ暟閲忓繀椤诲ぇ浜庨浂" };
+      }
       return { valid: false, message: "璇峰畬鍠勫伐搴忋�佸師鏂欍�佹壒鍙峰拰鏁伴噺鍚庡啀淇濆瓨" };
     }
     return { valid: true, message: "" };
diff --git a/src/views/productionManagement/productionOrder/index.vue b/src/views/productionManagement/productionOrder/index.vue
index e761523..96185b2 100644
--- a/src/views/productionManagement/productionOrder/index.vue
+++ b/src/views/productionManagement/productionOrder/index.vue
@@ -617,7 +617,7 @@
 
   const openBindRouteDialog = async (row, type) => {
     bindForm.orderId = row.id;
-    bindForm.routeId = type === "add" ? null : row.processRouteCode;
+    bindForm.routeId = type === "add" ? null : row.technologyRoutingId;
     bindRouteDialogVisible.value = true;
     routeOptions.value = [];
     if (!row.productModelId) {
diff --git a/src/views/productionManagement/productionProcess/index.vue b/src/views/productionManagement/productionProcess/index.vue
index 216e73b..6d007a4 100644
--- a/src/views/productionManagement/productionProcess/index.vue
+++ b/src/views/productionManagement/productionProcess/index.vue
@@ -162,7 +162,8 @@
       </el-form>
       <template #footer>
         <span class="dialog-footer">
-          <el-button type="primary" @click="handleProcessSubmit">纭畾</el-button>
+          <el-button type="primary"
+                     @click="handleProcessSubmit">纭畾</el-button>
           <el-button @click="processDialogVisible = false">鍙栨秷</el-button>
         </span>
       </template>
@@ -251,7 +252,9 @@
       </div>
       <template #footer>
         <span class="dialog-footer">
-          <el-button type="primary" :disabled="!selectedParam" @click="handleParamSubmit">纭畾</el-button>
+          <el-button type="primary"
+                     :disabled="!selectedParam"
+                     @click="handleParamSubmit">纭畾</el-button>
           <el-button @click="paramDialogVisible = false">鍙栨秷</el-button>
         </span>
       </template>
@@ -275,9 +278,9 @@
       </el-form>
       <template #footer>
         <span class="dialog-footer">
-          <el-button @click="editParamDialogVisible = false">鍙栨秷</el-button>
           <el-button type="primary"
                      @click="handleEditParamSubmit">纭畾</el-button>
+          <el-button @click="editParamDialogVisible = false">鍙栨秷</el-button>
         </span>
       </template>
     </el-dialog>
diff --git a/src/views/productionManagement/productionReporting/index.vue b/src/views/productionManagement/productionReporting/index.vue
index cf42a0a..ee1f0df 100644
--- a/src/views/productionManagement/productionReporting/index.vue
+++ b/src/views/productionManagement/productionReporting/index.vue
@@ -187,6 +187,11 @@
       width: 120,
     },
     {
+      label: "宸ユ椂锛坔锛�",
+      width: 100,
+      prop: "workHour",
+    },
+    {
       label: "宸ュ簭",
       prop: "process",
       width: 120,
diff --git a/src/views/productionManagement/productionTraceability/index.vue b/src/views/productionManagement/productionTraceability/index.vue
index a494cf5..671a204 100644
--- a/src/views/productionManagement/productionTraceability/index.vue
+++ b/src/views/productionManagement/productionTraceability/index.vue
@@ -80,11 +80,17 @@
                   {{ row.workOrder.model || '-' }}
                 </template>
               </el-table-column>
+              <el-table-column label="宸ュ簭"
+                               prop="workOrder.operationName"
+                               align="center" />
               <el-table-column prop="workOrder.planQuantity"
                                label="闇�姹傛暟閲�"
                                align="center" />
               <el-table-column prop="workOrder.completeQuantity"
                                label="瀹屾垚鏁伴噺"
+                               align="center" />
+              <el-table-column prop="workOrder.scrapQty"
+                               label="鎶ュ簾鏁伴噺"
                                align="center" />
               <el-table-column prop="workOrder.completionStatus"
                                label="瀹屾垚杩涘害"
@@ -154,6 +160,15 @@
                 {{ parseTime(row.createTime) }}
               </template>
             </el-table-column>
+            <el-table-column label="宸ユ椂锛坔锛�"
+                             prop="workHour"
+                             align="center" />
+            <el-table-column label="浜у嚭鏁伴噺"
+                             prop="quantity"
+                             align="center" />
+            <el-table-column label="鎶ュ簾鏁伴噺"
+                             prop="scrapQty"
+                             align="center" />
             <el-table-column label="鎿嶄綔"
                              align="center"
                              width="200">
@@ -387,6 +402,7 @@
       workOrder: row.workOrder || {},
       reports: (row.reportList || []).map(r => ({
         ...r.reportMain,
+        ...(r.reportOutputList[0] || {}),
         productionOperationParamList: r.reportParamList || [],
       })),
     };
diff --git a/src/views/productionManagement/workOrderEdit/index.vue b/src/views/productionManagement/workOrderEdit/index.vue
index d0b77bd..60d6f9c 100644
--- a/src/views/productionManagement/workOrderEdit/index.vue
+++ b/src/views/productionManagement/workOrderEdit/index.vue
@@ -111,9 +111,9 @@
       </div>
       <template #footer>
         <span class="dialog-footer">
-          <el-button @click="assignReporterDialogVisible = false">鍙栨秷</el-button>
           <el-button type="primary"
                      @click="handleSaveReporters">纭畾</el-button>
+          <el-button @click="assignReporterDialogVisible = false">鍙栨秷</el-button>
         </span>
       </template>
     </el-dialog>
diff --git a/src/views/productionManagement/workOrderManagement/index.vue b/src/views/productionManagement/workOrderManagement/index.vue
index 6a1b24f..3c99447 100644
--- a/src/views/productionManagement/workOrderManagement/index.vue
+++ b/src/views/productionManagement/workOrderManagement/index.vue
@@ -161,6 +161,17 @@
                        :value="user.userId" />
           </el-select>
         </el-form-item>
+        <!-- 宸ユ椂 -->
+        <el-form-item label="宸ユ椂"
+                      v-if="currentReportRowData?.type == 0"
+                      prop="workHour">
+          <el-input v-model.number="reportForm.workHour"
+                    type="number"
+                    min="0"
+                    style="width: 280px"
+                    placeholder="璇疯緭鍏ュ伐鏃�" /><span style="margin-left:10px"
+                class="param-unit">h</span>
+        </el-form-item>
         <div v-if="params.length > 0"
              class="param-grid"
              v-loading="paramLoading">
@@ -259,6 +270,7 @@
     addProductMain,
     downProductWorkOrder,
   } from "@/api/productionManagement/workOrder.js";
+  import { listMaterialPickingDetail } from "@/api/productionManagement/productionOrder.js";
   import { findProcessParamListOrder } from "@/api/productionManagement/productProcessRoute.js";
   import { getUserProfile, userListNoPageByTenantId } from "@/api/system/user.js";
   import { getDicts } from "@/api/system/dict/data";
@@ -423,6 +435,7 @@
     productMainId: null,
     productionOrderRoutingOperationId: "",
     productionOrderId: "",
+    workHour: 0,
     paramGroups: {},
   });
 
@@ -649,7 +662,21 @@
     fileDialogVisible.value = true;
   };
 
-  const showReportDialog = row => {
+  const showReportDialog = async row => {
+    if (row.productionOrderId) {
+      try {
+        const res = await listMaterialPickingDetail(row.productionOrderId);
+        const records = Array.isArray(res.data)
+          ? res.data
+          : res.data?.records || [];
+        if (res.code === 200 && records.length === 0) {
+          proxy.$modal.msgError("鏈鏂欐棤娉曟姤宸�");
+          return;
+        }
+      } catch (error) {
+        console.error("鏌ヨ棰嗘枡璇︽儏澶辫触:", error);
+      }
+    }
     currentReportRowData.value = row;
     reportForm.planQuantity = row.planQuantity;
     reportForm.quantity =
@@ -663,6 +690,11 @@
     reportForm.productionOrderRoutingOperationId =
       row.productionOrderRoutingOperationId;
     reportForm.productionOrderId = row.productionOrderId;
+    if (row.type == 0) {
+      reportForm.workHour = row.workHour || 0;
+    } else {
+      reportForm.workHour = 0;
+    }
     nextTick(() => {
       reportFormRef.value?.clearValidate();
       if (row.productionOrderRoutingOperationId && row.productionOrderId) {
@@ -762,6 +794,7 @@
         productionOrderRoutingOperationId:
           reportForm.productionOrderRoutingOperationId,
         productionOrderId: reportForm.productionOrderId,
+        workHour: reportForm.workHour,
         productionOperationParamList: productionOperationParamList,
       };
 
diff --git a/src/views/productionPlan/productionPlan/index.vue b/src/views/productionPlan/productionPlan/index.vue
index 78dca1f..6bcc7b2 100644
--- a/src/views/productionPlan/productionPlan/index.vue
+++ b/src/views/productionPlan/productionPlan/index.vue
@@ -13,6 +13,14 @@
                     style="width: 160px;"
                     @keyup.enter="handleQuery" />
         </el-form-item>
+        <el-form-item label="閿�鍞悎鍚屽彿:"
+                      prop="salesContractNo">
+          <el-input v-model="searchForm.salesContractNo"
+                    placeholder="璇疯緭鍏�"
+                    clearable
+                    style="width: 160px;"
+                    @keyup.enter="handleQuery" />
+        </el-form-item>
         <el-form-item label="闇�姹傛棩鏈熻寖鍥�:"
                       prop="dateRange">
           <el-date-picker v-model="searchForm.dateRange"
@@ -146,7 +154,8 @@
       </el-form>
       <template #footer>
         <span class="dialog-footer">
-          <el-button type="primary" @click="handleMergeSubmit">纭畾涓嬪彂</el-button>
+          <el-button type="primary"
+                     @click="handleMergeSubmit">纭畾涓嬪彂</el-button>
           <el-button @click="isShowNewModal = false">鍙栨秷</el-button>
         </span>
       </template>
@@ -239,7 +248,8 @@
       </el-form>
       <template #footer>
         <span class="dialog-footer">
-          <el-button type="primary" @click="handleSubmit">纭畾</el-button>
+          <el-button type="primary"
+                     @click="handleSubmit">纭畾</el-button>
           <el-button @click="dialogVisible = false">鍙栨秷</el-button>
         </span>
       </template>
@@ -269,6 +279,7 @@
     productionPlanUpdate,
     productionPlanDelete,
     productionPlanCombine,
+    exportProductionPlan,
   } from "@/api/productionPlan/productionPlan.js";
   import { productTreeList, modelListPage } from "@/api/basicData/product.js";
   import { workshopPage } from "@/api/basicData/workshop.js";
@@ -281,11 +292,6 @@
   const loadProdData = () => {
     console.log("Mock loadProdData called");
     return Promise.resolve({ code: 200, msg: "鍚屾鎴愬姛" });
-  };
-
-  const exportProductionPlan = () => {
-    console.log("Mock exportProductionPlan called");
-    return Promise.resolve();
   };
 
   // const productionPlanCombine = payload => {
@@ -650,6 +656,7 @@
   const data = reactive({
     searchForm: {
       mpsNo: "",
+      salesContractNo: "",
       productName: "",
       model: "",
       status: "",
@@ -678,6 +685,7 @@
     }
     Object.assign(searchForm.value, {
       mpsNo: "",
+      salesContractNo: "",
       productName: "",
       model: "",
       status: "",
diff --git a/src/views/salesManagement/deliveryLedger/index.vue b/src/views/salesManagement/deliveryLedger/index.vue
index d7f47dd..f93731b 100644
--- a/src/views/salesManagement/deliveryLedger/index.vue
+++ b/src/views/salesManagement/deliveryLedger/index.vue
@@ -56,7 +56,7 @@
                 link
                 type="primary"
                 :disabled="!isApproved(scope.row.status)"
-                @click="openForm('edit', scope.row)">琛ュ厖鍙戣揣淇℃伅
+                @click="openForm('edit', scope.row)">鍙戣揣
             </el-button>
             <el-button
                 link
@@ -319,9 +319,9 @@
 
 // 鎵撳紑寮规
 const openForm = async (type, row) => {
-  // 琛ュ厖鍙戣揣淇℃伅锛氫粎鈥滃鏍搁�氳繃鈥濆厑璁哥紪杈�
+  // 鍙戣揣锛氫粎鈥滃鏍搁�氳繃鈥濆厑璁哥紪杈�
   if (type === 'edit' && row && !isApproved(row.status)) {
-    proxy.$modal.msgWarning("鍙湁瀹℃牳閫氳繃鐨勬暟鎹墠鍙互琛ュ厖鍙戣揣淇℃伅");
+    proxy.$modal.msgWarning("鍙湁瀹℃牳閫氳繃鐨勬暟鎹墠鍙互鍙戣揣");
     return;
   }
 
diff --git a/src/views/salesManagement/salesLedger/index.vue b/src/views/salesManagement/salesLedger/index.vue
index 5340d99..8d25f53 100644
--- a/src/views/salesManagement/salesLedger/index.vue
+++ b/src/views/salesManagement/salesLedger/index.vue
@@ -8,21 +8,21 @@
                     placeholder="璇疯緭鍏�"
                     clearable
                     prefix-icon="Search"
-                    @change="handleQuery"/>
+                    @change="handleQuery" />
         </el-form-item>
         <el-form-item label="閿�鍞悎鍚屽彿锛�">
           <el-input v-model="searchForm.salesContractNo"
                     placeholder="璇疯緭鍏�"
                     clearable
                     prefix-icon="Search"
-                    @change="handleQuery"/>
+                    @change="handleQuery" />
         </el-form-item>
         <el-form-item label="椤圭洰鍚嶇О锛�">
           <el-input v-model="searchForm.projectName"
                     placeholder="璇疯緭鍏�"
                     clearable
                     prefix-icon="Search"
-                    @change="handleQuery"/>
+                    @change="handleQuery" />
         </el-form-item>
         <el-form-item label="褰曞叆鏃ユ湡锛�">
           <el-date-picker v-model="searchForm.entryDate"
@@ -31,7 +31,7 @@
                           type="daterange"
                           placeholder="璇烽�夋嫨"
                           clearable
-                          @change="changeDaterange"/>
+                          @change="changeDaterange" />
         </el-form-item>
         <el-form-item>
           <el-button type="primary"
@@ -78,7 +78,7 @@
         <el-table-column align="center"
                          type="selection"
                          width="55"
-                         fixed="left"/>
+                         fixed="left" />
         <el-table-column type="expand"
                          width="60"
                          fixed="left">
@@ -89,24 +89,22 @@
                       :summary-method="(param) => summarizeChildrenTable(param, props.row)">
               <el-table-column align="center"
                                label="搴忓彿"
-                               type="index"/>
+                               type="index" />
               <el-table-column label="浜у搧澶х被"
-                               prop="productCategory"/>
+                               prop="productCategory" />
               <el-table-column label="瑙勬牸鍨嬪彿"
-                               prop="specificationModel"/>
+                               prop="specificationModel" />
               <el-table-column label="鍗曚綅"
-                               prop="unit"/>
+                               prop="unit" />
               <el-table-column label="浜у搧鐘舵��"
                                width="100px"
                                align="center">
                 <template #default="scope">
-                  <el-tag
-                      v-if="scope.row.approveStatus === 1 && scope.row.noQuantity !== 0"
-                      type="success">鍏呰冻
+                  <el-tag v-if="scope.row.approveStatus === 1 "
+                          type="success">鍏呰冻
                   </el-tag>
-                  <el-tag
-                      v-else-if="scope.row.approveStatus === 0 && scope.row.noQuantity === 0"
-                      type="success">宸插嚭搴�
+                  <el-tag v-else-if="scope.row.approveStatus === 0 && scope.row.noQuantity === 0"
+                          type="success">宸插嚭搴�
                   </el-tag>
                   <el-tag v-else
                           type="danger">涓嶈冻
@@ -125,10 +123,10 @@
               </el-table-column>
               <el-table-column label="蹇�掑叕鍙�"
                                prop="expressCompany"
-                               show-overflow-tooltip/>
+                               show-overflow-tooltip />
               <el-table-column label="蹇�掑崟鍙�"
                                prop="expressNumber"
-                               show-overflow-tooltip/>
+                               show-overflow-tooltip />
               <el-table-column label="鍙戣揣杞︾墝"
                                minWidth="100px"
                                align="center">
@@ -156,20 +154,20 @@
                 </template>
               </el-table-column>
               <el-table-column label="鏁伴噺"
-                               prop="quantity"/>
+                               prop="quantity" />
               <el-table-column label="寰呭彂璐ф暟閲�"
-                               prop="noQuantity"/>
+                               prop="noQuantity" />
               <el-table-column label="绋庣巼(%)"
-                               prop="taxRate"/>
+                               prop="taxRate" />
               <el-table-column label="鍚◣鍗曚环(鍏�)"
                                prop="taxInclusiveUnitPrice"
-                               :formatter="sensitiveAmountFormatter"/>
+                               :formatter="sensitiveAmountFormatter" />
               <el-table-column label="鍚◣鎬讳环(鍏�)"
                                prop="taxInclusiveTotalPrice"
-                               :formatter="sensitiveAmountFormatter"/>
+                               :formatter="sensitiveAmountFormatter" />
               <el-table-column label="涓嶅惈绋庢�讳环(鍏�)"
                                prop="taxExclusiveTotalPrice"
-                               :formatter="sensitiveAmountFormatter"/>
+                               :formatter="sensitiveAmountFormatter" />
               <!--鎿嶄綔-->
               <el-table-column Width="60px"
                                label="鎿嶄綔"
@@ -189,51 +187,51 @@
         <el-table-column align="center"
                          label="搴忓彿"
                          type="index"
-                         width="60"/>
+                         width="60" />
         <el-table-column label="閿�鍞悎鍚屽彿"
                          prop="salesContractNo"
                          width="180"
-                         show-overflow-tooltip/>
+                         show-overflow-tooltip />
         <el-table-column label="瀹㈡埛鍚嶇О"
                          prop="customerName"
                          width="300"
-                         show-overflow-tooltip/>
+                         show-overflow-tooltip />
         <el-table-column label="涓氬姟鍛�"
                          prop="salesman"
                          width="100"
-                         show-overflow-tooltip/>
+                         show-overflow-tooltip />
         <el-table-column label="椤圭洰鍚嶇О"
                          prop="projectName"
                          width="180"
-                         show-overflow-tooltip/>
+                         show-overflow-tooltip />
         <el-table-column label="浠樻鏂瑰紡"
                          prop="paymentMethod"
-                         show-overflow-tooltip/>
+                         show-overflow-tooltip />
         <el-table-column label="鍚堝悓閲戦(鍏�)"
                          prop="contractAmount"
                          width="220"
                          show-overflow-tooltip
-                         :formatter="formattedNumber"/>
+                         :formatter="formattedNumber" />
         <el-table-column label="褰曞叆浜�"
                          prop="entryPersonName"
                          width="100"
-                         show-overflow-tooltip/>
+                         show-overflow-tooltip />
         <el-table-column label="褰曞叆鏃ユ湡"
                          prop="entryDate"
                          width="120"
-                         show-overflow-tooltip/>
+                         show-overflow-tooltip />
         <el-table-column label="绛捐鏃ユ湡"
                          prop="executionDate"
                          width="120"
-                         show-overflow-tooltip/>
+                         show-overflow-tooltip />
         <el-table-column label="浜や粯鏃ユ湡"
                          prop="deliveryDate"
                          width="120"
-                         show-overflow-tooltip/>
+                         show-overflow-tooltip />
         <el-table-column label="澶囨敞"
                          prop="remarks"
                          width="200"
-                         show-overflow-tooltip/>
+                         show-overflow-tooltip />
         <el-table-column fixed="right"
                          label="鎿嶄綔"
                          width="130"
@@ -256,7 +254,7 @@
                   layout="total, sizes, prev, pager, next, jumper"
                   :page="page.current"
                   :limit="page.size"
-                  @pagination="paginationChange"/>
+                  @pagination="paginationChange" />
     </div>
     <FormDialog v-model="dialogFormVisible"
                 :title="operationType === 'add' ? '鏂板閿�鍞彴璐﹂〉闈�' : '缂栬緫閿�鍞彴璐﹂〉闈�'"
@@ -289,7 +287,7 @@
               <el-input v-model="form.salesContractNo"
                         placeholder="鑷姩鐢熸垚"
                         clearable
-                        disabled/>
+                        disabled />
             </el-form-item>
           </el-col>
           <el-col :span="12">
@@ -303,7 +301,7 @@
                 <el-option v-for="item in userList"
                            :key="item.nickName"
                            :label="item.nickName"
-                           :value="item.nickName"/>
+                           :value="item.nickName" />
               </el-select>
             </el-form-item>
           </el-col>
@@ -334,7 +332,7 @@
               <el-input v-model="form.projectName"
                         placeholder="璇疯緭鍏�"
                         clearable
-                        :disabled="operationType === 'view'"/>
+                        :disabled="operationType === 'view'" />
             </el-form-item>
           </el-col>
         </el-row>
@@ -349,7 +347,7 @@
                               type="date"
                               placeholder="璇烽�夋嫨"
                               clearable
-                              :disabled="operationType === 'view'"/>
+                              :disabled="operationType === 'view'" />
             </el-form-item>
           </el-col>
           <el-col :span="12">
@@ -357,7 +355,7 @@
               <el-input v-model="form.paymentMethod"
                         placeholder="璇疯緭鍏�"
                         clearable
-                        :disabled="operationType === 'view'"/>
+                        :disabled="operationType === 'view'" />
             </el-form-item>
           </el-col>
         </el-row>
@@ -375,7 +373,7 @@
                 <el-option v-for="item in userList"
                            :key="item.userId"
                            :label="item.nickName"
-                           :value="item.userId"/>
+                           :value="item.userId" />
               </el-select>
             </el-form-item>
           </el-col>
@@ -388,7 +386,7 @@
                               format="YYYY-MM-DD"
                               type="date"
                               placeholder="璇烽�夋嫨"
-                              clearable/>
+                              clearable />
             </el-form-item>
           </el-col>
         </el-row>
@@ -402,7 +400,7 @@
                               format="YYYY-MM-DD"
                               type="date"
                               placeholder="璇烽�夋嫨"
-                              clearable/>
+                              clearable />
             </el-form-item>
           </el-col>
         </el-row>
@@ -429,30 +427,30 @@
                            type="selection"
                            width="55"
                            v-if="operationType !== 'view'"
-                           :selectable="(row) => !isProductShipped(row)"/>
+                           :selectable="(row) => !isProductShipped(row)" />
           <el-table-column align="center"
                            label="搴忓彿"
                            type="index"
-                           width="60"/>
+                           width="60" />
           <el-table-column label="浜у搧澶х被"
-                           prop="productCategory"/>
+                           prop="productCategory" />
           <el-table-column label="瑙勬牸鍨嬪彿"
-                           prop="specificationModel"/>
+                           prop="specificationModel" />
           <el-table-column label="鍗曚綅"
-                           prop="unit"/>
+                           prop="unit" />
           <el-table-column label="鏁伴噺"
-                           prop="quantity"/>
+                           prop="quantity" />
           <el-table-column label="绋庣巼(%)"
-                           prop="taxRate"/>
+                           prop="taxRate" />
           <el-table-column label="鍚◣鍗曚环(鍏�)"
                            prop="taxInclusiveUnitPrice"
-                           :formatter="formattedNumber"/>
+                           :formatter="formattedNumber" />
           <el-table-column label="鍚◣鎬讳环(鍏�)"
                            prop="taxInclusiveTotalPrice"
-                           :formatter="formattedNumber"/>
+                           :formatter="formattedNumber" />
           <el-table-column label="涓嶅惈绋庢�讳环(鍏�)"
                            prop="taxExclusiveTotalPrice"
-                           :formatter="formattedNumber"/>
+                           :formatter="formattedNumber" />
           <el-table-column label="鏄惁鐢熶骇"
                            prop="isProduction"
                            width="150">
@@ -486,7 +484,7 @@
                         clearable
                         type="textarea"
                         :rows="2"
-                        :disabled="operationType === 'view'"/>
+                        :disabled="operationType === 'view'" />
             </el-form-item>
           </el-col>
         </el-row>
@@ -494,7 +492,7 @@
           <el-col :span="24">
             <el-form-item label="闄勪欢鏉愭枡锛�"
                           prop="salesLedgerFiles">
-              <FileUpload v-model:file-list="fileList"/>
+              <FileUpload v-model:file-list="fileList" />
             </el-form-item>
           </el-col>
         </el-row>
@@ -510,12 +508,12 @@
                   placeholder="璇疯緭鍏ユ姤浠峰崟鍙�"
                   clearable
                   style="max-width: 260px;"
-                  @change="fetchQuotationList"/>
+                  @change="fetchQuotationList" />
         <el-input v-model="quotationSearchForm.customer"
                   placeholder="璇疯緭鍏ュ鎴峰悕绉�"
                   clearable
                   style="max-width: 260px;"
-                  @change="fetchQuotationList"/>
+                  @change="fetchQuotationList" />
         <el-button type="primary"
                    @click="fetchQuotationList">鎼滅储
         </el-button>
@@ -529,26 +527,26 @@
         <el-table-column align="center"
                          label="搴忓彿"
                          type="index"
-                         width="60"/>
+                         width="60" />
         <el-table-column prop="quotationNo"
                          label="鎶ヤ环鍗曞彿"
                          width="180"
-                         show-overflow-tooltip/>
+                         show-overflow-tooltip />
         <el-table-column prop="customer"
                          label="瀹㈡埛鍚嶇О"
                          min-width="220"
-                         show-overflow-tooltip/>
+                         show-overflow-tooltip />
         <el-table-column prop="salesperson"
                          label="涓氬姟鍛�"
                          width="120"
-                         show-overflow-tooltip/>
+                         show-overflow-tooltip />
         <el-table-column prop="quotationDate"
                          label="鎶ヤ环鏃ユ湡"
-                         width="140"/>
+                         width="140" />
         <el-table-column prop="status"
                          label="瀹℃壒鐘舵��"
                          width="120"
-                         align="center"/>
+                         align="center" />
         <el-table-column prop="totalAmount"
                          label="鎶ヤ环閲戦(鍏�)"
                          width="160"
@@ -574,7 +572,7 @@
                   layout="total, sizes, prev, pager, next, jumper"
                   :page="quotationPage.current"
                   :limit="quotationPage.size"
-                  @pagination="quotationPaginationChange"/>
+                  @pagination="quotationPaginationChange" />
       <template #footer>
         <el-button @click="quotationDialogVisible = false">鍏抽棴</el-button>
       </template>
@@ -603,7 +601,7 @@
                               @change="getModels"
                               :data="productOptions"
                               :render-after-expand="false"
-                              style="width: 100%"/>
+                              style="width: 100%" />
             </el-form-item>
           </el-col>
         </el-row>
@@ -619,7 +617,7 @@
                 <el-option v-for="item in modelOptions"
                            :key="item.id"
                            :label="item.model"
-                           :value="item.id"/>
+                           :value="item.id" />
               </el-select>
             </el-form-item>
           </el-col>
@@ -630,7 +628,7 @@
                           prop="unit">
               <el-input v-model="productForm.unit"
                         placeholder="璇疯緭鍏�"
-                        clearable/>
+                        clearable />
             </el-form-item>
           </el-col>
           <el-col :span="12">
@@ -640,12 +638,10 @@
                          placeholder="璇烽�夋嫨"
                          clearable
                          @change="calculateFromTaxRate">
-                <el-option
-                  v-for="dict in tax_rate"
-                  :key="dict.value"
-                  :label="dict.label"
-                  :value="dict.value"
-                />
+                <el-option v-for="dict in tax_rate"
+                           :key="dict.value"
+                           :label="dict.label"
+                           :value="dict.value" />
               </el-select>
             </el-form-item>
           </el-col>
@@ -661,7 +657,7 @@
                                :precision="2"
                                placeholder="璇疯緭鍏�"
                                clearable
-                               @change="calculateFromUnitPrice"/>
+                               @change="calculateFromUnitPrice" />
             </el-form-item>
           </el-col>
           <el-col :span="12">
@@ -674,7 +670,7 @@
                                clearable
                                :precision="2"
                                @change="calculateFromQuantity"
-                               style="width: 100%"/>
+                               style="width: 100%" />
             </el-form-item>
           </el-col>
         </el-row>
@@ -685,7 +681,7 @@
               <el-input v-model="productForm.taxInclusiveTotalPrice"
                         placeholder="璇疯緭鍏�"
                         clearable
-                        @change="calculateFromTotalPrice"/>
+                        @change="calculateFromTotalPrice" />
             </el-form-item>
           </el-col>
           <el-col :span="12">
@@ -694,7 +690,7 @@
               <el-input v-model="productForm.taxExclusiveTotalPrice"
                         placeholder="璇疯緭鍏�"
                         clearable
-                        @change="calculateFromExclusiveTotalPrice"/>
+                        @change="calculateFromExclusiveTotalPrice" />
             </el-form-item>
           </el-col>
         </el-row>
@@ -706,9 +702,9 @@
                          placeholder="璇烽�夋嫨"
                          clearable>
                 <el-option label="澧炴櫘绁�"
-                           value="澧炴櫘绁�"/>
+                           value="澧炴櫘绁�" />
                 <el-option label="澧炰笓绁�"
-                           value="澧炰笓绁�"/>
+                           value="澧炰笓绁�" />
               </el-select>
             </el-form-item>
           </el-col>
@@ -717,9 +713,9 @@
                           prop="isProduction">
               <el-radio-group v-model="productForm.isProduction">
                 <el-radio label="鏄�"
-                          :value="true"/>
+                          :value="true" />
                 <el-radio label="鍚�"
-                          :value="false"/>
+                          :value="false" />
               </el-radio-group>
             </el-form-item>
           </el-col>
@@ -762,8 +758,10 @@
     </FormDialog>
     <!-- // todo 闄勪欢棰勮鐩稿叧 -->
     <!-- 闄勪欢鍒楄〃寮圭獥 -->
-    <FileList v-if="fileDialogVisible" v-model:visible="fileDialogVisible" record-type="sales_ledger"
-              :record-id="recordId"/>
+    <FileList v-if="fileDialogVisible"
+              v-model:visible="fileDialogVisible"
+              record-type="sales_ledger"
+              :record-id="recordId" />
     <!-- 鎵撳嵃棰勮寮圭獥 -->
     <el-dialog v-model="printPreviewVisible"
                title="鎵撳嵃棰勮"
@@ -816,40 +814,40 @@
               <div class="table-section">
                 <table class="product-table">
                   <thead>
-                  <tr>
-                    <th>浜у搧鍚嶇О</th>
-                    <th>瑙勬牸鍨嬪彿</th>
-                    <th>鍗曚綅</th>
-                    <th>鍗曚环</th>
-                    <th>闆跺敭鏁伴噺</th>
-                    <th>闆跺敭閲戦</th>
-                  </tr>
+                    <tr>
+                      <th>浜у搧鍚嶇О</th>
+                      <th>瑙勬牸鍨嬪彿</th>
+                      <th>鍗曚綅</th>
+                      <th>鍗曚环</th>
+                      <th>闆跺敭鏁伴噺</th>
+                      <th>闆跺敭閲戦</th>
+                    </tr>
                   </thead>
                   <tbody>
-                  <tr v-for="product in item.products"
-                      :key="product.id">
-                    <td>{{ product.productCategory || '' }}</td>
-                    <td>{{ product.specificationModel || '' }}</td>
-                    <td>{{ product.unit || '' }}</td>
-                    <td>{{ product.taxInclusiveUnitPrice || '0' }}</td>
-                    <td>{{ product.quantity || '0' }}</td>
-                    <td>{{ product.taxInclusiveTotalPrice || '0' }}</td>
-                  </tr>
-                  <tr v-if="!item.products || item.products.length === 0">
-                    <td colspan="6"
-                        style="text-align: center; color: #999;">鏆傛棤浜у搧鏁版嵁
-                    </td>
-                  </tr>
+                    <tr v-for="product in item.products"
+                        :key="product.id">
+                      <td>{{ product.productCategory || '' }}</td>
+                      <td>{{ product.specificationModel || '' }}</td>
+                      <td>{{ product.unit || '' }}</td>
+                      <td>{{ product.taxInclusiveUnitPrice || '0' }}</td>
+                      <td>{{ product.quantity || '0' }}</td>
+                      <td>{{ product.taxInclusiveTotalPrice || '0' }}</td>
+                    </tr>
+                    <tr v-if="!item.products || item.products.length === 0">
+                      <td colspan="6"
+                          style="text-align: center; color: #999;">鏆傛棤浜у搧鏁版嵁
+                      </td>
+                    </tr>
                   </tbody>
                   <tfoot>
-                  <tr>
-                    <td class="label">鍚堣</td>
-                    <td class="total-value"></td>
-                    <td class="total-value"></td>
-                    <td class="total-value"></td>
-                    <td class="total-value">{{ getTotalQuantity(item.products) }}</td>
-                    <td class="total-value">{{ getTotalAmount(item.products) }}</td>
-                  </tr>
+                    <tr>
+                      <td class="label">鍚堣</td>
+                      <td class="total-value"></td>
+                      <td class="total-value"></td>
+                      <td class="total-value"></td>
+                      <td class="total-value">{{ getTotalQuantity(item.products) }}</td>
+                      <td class="total-value">{{ getTotalAmount(item.products) }}</td>
+                    </tr>
                   </tfoot>
                 </table>
               </div>
@@ -902,10 +900,16 @@
                          placeholder="璇烽�夋嫨鍙戣揣绫诲瀷"
                          style="width: 100%">
                 <el-option label="璐ц溅"
-                           value="璐ц溅"/>
+                           value="璐ц溅" />
                 <el-option label="蹇��"
-                           value="蹇��"/>
+                           value="蹇��" />
               </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="寰呭彂璐ф暟閲忥細">
+              <el-input :model-value="currentDeliveryRow?.noQuantity"
+                        disabled />
             </el-form-item>
           </el-col>
         </el-row>
@@ -920,8 +924,8 @@
                         style="width: 100%;">
                 <el-table-column label="鎵瑰彿"
                                  prop="batchNo"
-                                 min-width="180"/>
-                <el-table-column label="鏁伴噺"
+                                 min-width="180" />
+                <el-table-column label="搴撳瓨鏁伴噺"
                                  min-width="120"
                                  align="center">
                   <template #default="scope">
@@ -939,7 +943,7 @@
                                      :step="0.01"
                                      controls-position="right"
                                      @change="handleDeliveryBatchQuantityChange(scope.row)"
-                                     style="width: 100%;"/>
+                                     style="width: 100%;" />
                   </template>
                 </el-table-column>
               </el-table>
@@ -960,309 +964,330 @@
 </template>
 
 <script setup>
-import {getToken} from "@/utils/auth";
-import pagination from "@/components/PIMTable/Pagination.vue";
-import {onMounted, ref, getCurrentInstance} from "vue";
-import {addShippingInfo} from "@/api/salesManagement/deliveryLedger.js";
-import {ElMessageBox, ElMessage} from "element-plus";
-import useUserStore from "@/store/modules/user";
-import {userListNoPage} from "@/api/system/user.js";
-import FormDialog from "@/components/Dialog/FormDialog.vue";
-import {getQuotationList} from "@/api/salesManagement/salesQuotation.js";
-import {
-  ledgerListPage,
-  productList,
-  customerList,
-  addOrUpdateSalesLedger,
-  getSalesLedgerWithProducts,
-  delLedger,
-  addOrUpdateSalesLedgerProduct,
-  delProduct,
-  delLedgerFile,
-  getProductInventory,
-} from "@/api/salesManagement/salesLedger.js";
-import {getStockInventoryByModelId} from "@/api/inventoryManagement/stockInventory.js";
-import {modelList, productTreeList} from "@/api/basicData/product.js";
-import useFormData from "@/hooks/useFormData.js";
-import dayjs from "dayjs";
-import FileUpload from "@/components/AttachmentUpload/file/index.vue";
-import { getCurrentDate } from "@/utils/index.js";
-import {listCustomer} from "@/api/basicData/customer.js";
+  import { getToken } from "@/utils/auth";
+  import pagination from "@/components/PIMTable/Pagination.vue";
+  import { onMounted, ref, getCurrentInstance } from "vue";
+  import { addShippingInfo } from "@/api/salesManagement/deliveryLedger.js";
+  import { ElMessageBox, ElMessage } from "element-plus";
+  import useUserStore from "@/store/modules/user";
+  import { userListNoPage } from "@/api/system/user.js";
+  import FormDialog from "@/components/Dialog/FormDialog.vue";
+  import { getQuotationList } from "@/api/salesManagement/salesQuotation.js";
+  import {
+    ledgerListPage,
+    productList,
+    customerList,
+    addOrUpdateSalesLedger,
+    getSalesLedgerWithProducts,
+    delLedger,
+    addOrUpdateSalesLedgerProduct,
+    delProduct,
+    delLedgerFile,
+    getProductInventory,
+  } from "@/api/salesManagement/salesLedger.js";
+  import { getStockInventoryByModelId } from "@/api/inventoryManagement/stockInventory.js";
+  import { modelList, productTreeList } from "@/api/basicData/product.js";
+  import useFormData from "@/hooks/useFormData.js";
+  import dayjs from "dayjs";
+  import FileUpload from "@/components/AttachmentUpload/file/index.vue";
+  import { getCurrentDate } from "@/utils/index.js";
+  import { listCustomer } from "@/api/basicData/customer.js";
 
-const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue"));
+  const FileList = defineAsyncComponent(() =>
+    import("@/components/Dialog/FileList.vue")
+  );
 
-const router = useRouter();
-const route = useRoute();
-const userStore = useUserStore();
-const {proxy} = getCurrentInstance();
-const { tax_rate } = proxy.useDict("tax_rate");
-const tableData = ref([]);
-const productData = ref([]);
-const selectedRows = ref([]);
-const productSelectedRows = ref([]);
-const userList = ref([]);
-const customerOption = ref([]);
-const productOptions = ref([]);
-const modelOptions = ref([]);
-const tableLoading = ref(false);
-const page = reactive({
-  current: 1,
-  size: 100,
-});
-const total = ref(0);
-const fileList = ref([]);
+  const router = useRouter();
+  const route = useRoute();
+  const userStore = useUserStore();
+  const { proxy } = getCurrentInstance();
+  const { tax_rate } = proxy.useDict("tax_rate");
+  const tableData = ref([]);
+  const productData = ref([]);
+  const selectedRows = ref([]);
+  const productSelectedRows = ref([]);
+  const userList = ref([]);
+  const customerOption = ref([]);
+  const productOptions = ref([]);
+  const modelOptions = ref([]);
+  const tableLoading = ref(false);
+  const page = reactive({
+    current: 1,
+    size: 100,
+  });
+  const total = ref(0);
+  const fileList = ref([]);
 
-// 鐢ㄦ埛淇℃伅琛ㄥ崟寮规鏁版嵁
-const operationType = ref("");
-const dialogFormVisible = ref(false);
-const data = reactive({
-  searchForm: {
-    customerName: "", // 瀹㈡埛鍚嶇О
-    salesContractNo: "", // 閿�鍞悎鍚岀紪鍙�
-    entryDate: null, // 褰曞叆鏃ユ湡
-    entryDateStart: undefined,
-    entryDateEnd: undefined,
-  },
-  form: {
-    salesContractNo: "",
-    salesman: "",
-    customerId: "",
-    entryPerson: "",
-    entryDate: "",
-    deliveryDate: "",
-    maintenanceTime: "",
-    productData: [],
-    executionDate: "",
-    hasProductionRecord: false,
-  },
-  rules: {
-    salesman: [{required: true, message: "璇烽�夋嫨", trigger: "change"}],
-    customerId: [{required: true, message: "璇烽�夋嫨", trigger: "change"}],
-    entryPerson: [{required: true, message: "璇烽�夋嫨", trigger: "change"}],
-    entryDate: [{required: true, message: "璇烽�夋嫨", trigger: "change"}],
-    deliveryDate: [{required: true, message: "璇烽�夋嫨", trigger: "change"}],
-    executionDate: [{required: true, message: "璇烽�夋嫨", trigger: "change"}],
-  },
-});
-const {form, rules} = toRefs(data);
-const {form: searchForm} = useFormData(data.searchForm);
-// 浜у搧琛ㄥ崟寮规鏁版嵁
-const productFormVisible = ref(false);
-const productOperationType = ref("");
-const currentId = ref("");
-const productFormData = reactive({
-  productForm: {
-    productCategory: "",
-    specificationModel: "",
-    unit: "",
-    quantity: "",
-    taxInclusiveUnitPrice: "",
-    taxRate: "",
-    taxInclusiveTotalPrice: "",
-    taxExclusiveTotalPrice: "",
-    invoiceType: "",
-    isProduction: false,
-  },
-  productRules: {
-    productCategory: [{required: true, message: "璇烽�夋嫨", trigger: "change"}],
-    productModelId: [{required: true, message: "璇烽�夋嫨", trigger: "change"}],
-    specificationModel: [
-      {required: true, message: "璇烽�夋嫨", trigger: "change"},
-    ],
-    unit: [{required: true, message: "璇疯緭鍏�", trigger: "blur"}],
-    quantity: [{required: true, message: "璇疯緭鍏�", trigger: "blur"}],
-    taxInclusiveUnitPrice: [
-      {required: true, message: "璇疯緭鍏�", trigger: "blur"},
-    ],
-    taxRate: [{required: true, message: "璇烽�夋嫨", trigger: "change"}],
-    taxInclusiveTotalPrice: [
-      {required: true, message: "璇疯緭鍏�", trigger: "blur"},
-    ],
-    taxExclusiveTotalPrice: [
-      {required: true, message: "璇疯緭鍏�", trigger: "blur"},
-    ],
-    invoiceType: [{required: true, message: "璇烽�夋嫨", trigger: "change"}],
-    isProduction: [{required: true, message: "璇烽�夋嫨", trigger: "change"}],
-  },
-});
-const {productForm, productRules} = toRefs(productFormData);
-// 闃叉寰幆璁$畻鐨勬爣蹇�
-const isCalculating = ref(false);
-// 鎵撳嵃鐩稿叧
-const printPreviewVisible = ref(false);
-const printData = ref([]);
+  // 鐢ㄦ埛淇℃伅琛ㄥ崟寮规鏁版嵁
+  const operationType = ref("");
+  const dialogFormVisible = ref(false);
+  const data = reactive({
+    searchForm: {
+      customerName: "", // 瀹㈡埛鍚嶇О
+      salesContractNo: "", // 閿�鍞悎鍚岀紪鍙�
+      entryDate: null, // 褰曞叆鏃ユ湡
+      entryDateStart: undefined,
+      entryDateEnd: undefined,
+    },
+    form: {
+      salesContractNo: "",
+      salesman: "",
+      customerId: "",
+      entryPerson: "",
+      entryDate: "",
+      deliveryDate: "",
+      maintenanceTime: "",
+      productData: [],
+      executionDate: "",
+      hasProductionRecord: false,
+    },
+    rules: {
+      salesman: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+      customerId: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+      entryPerson: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+      entryDate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+      deliveryDate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+      executionDate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+    },
+  });
+  const { form, rules } = toRefs(data);
+  const { form: searchForm } = useFormData(data.searchForm);
+  // 浜у搧琛ㄥ崟寮规鏁版嵁
+  const productFormVisible = ref(false);
+  const productOperationType = ref("");
+  const currentId = ref("");
+  const productFormData = reactive({
+    productForm: {
+      productCategory: "",
+      specificationModel: "",
+      unit: "",
+      quantity: "",
+      taxInclusiveUnitPrice: "",
+      taxRate: "",
+      taxInclusiveTotalPrice: "",
+      taxExclusiveTotalPrice: "",
+      invoiceType: "",
+      isProduction: false,
+    },
+    productRules: {
+      productCategory: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+      productModelId: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+      specificationModel: [
+        { required: true, message: "璇烽�夋嫨", trigger: "change" },
+      ],
+      unit: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+      quantity: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+      taxInclusiveUnitPrice: [
+        { required: true, message: "璇疯緭鍏�", trigger: "blur" },
+      ],
+      taxRate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+      taxInclusiveTotalPrice: [
+        { required: true, message: "璇疯緭鍏�", trigger: "blur" },
+      ],
+      taxExclusiveTotalPrice: [
+        { required: true, message: "璇疯緭鍏�", trigger: "blur" },
+      ],
+      invoiceType: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+      isProduction: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+    },
+  });
+  const { productForm, productRules } = toRefs(productFormData);
+  // 闃叉寰幆璁$畻鐨勬爣蹇�
+  const isCalculating = ref(false);
+  // 鎵撳嵃鐩稿叧
+  const printPreviewVisible = ref(false);
+  const printData = ref([]);
 
-// 鎶ヤ环鍗曞鍏ョ浉鍏�
-const quotationDialogVisible = ref(false);
-const quotationLoading = ref(false);
-const quotationList = ref([]);
-const quotationSearchForm = reactive({
-  quotationNo: "",
-  customer: "",
-});
-// 鎶ヤ环鍗曞脊妗嗗垎椤�
-const quotationPage = reactive({
-  current: 1,
-  size: 10,
-  total: 0,
-});
-const selectedQuotation = ref(null);
+  // 鎶ヤ环鍗曞鍏ョ浉鍏�
+  const quotationDialogVisible = ref(false);
+  const quotationLoading = ref(false);
+  const quotationList = ref([]);
+  const quotationSearchForm = reactive({
+    quotationNo: "",
+    customer: "",
+  });
+  // 鎶ヤ环鍗曞脊妗嗗垎椤�
+  const quotationPage = reactive({
+    current: 1,
+    size: 10,
+    total: 0,
+  });
+  const selectedQuotation = ref(null);
 
-// 鍙戣揣鐩稿叧
-const deliveryFormVisible = ref(false);
-const currentDeliveryRow = ref(null);
-const getDeliveryBatchQuantity = item => {
-  const quantity = item?.qualitity
-      ?? item?.quantity
-      ?? item?.unLockedQuantity
-      ?? item?.qualifiedUnLockedQuantity
-      ?? item?.qualifiedQuantity
-      ?? item?.stockQuantity;
-  return quantity ?? 0;
-};
-const getCurrentDeliveryRowQuantity = () => {
-  return Number(currentDeliveryRow.value?.noQuantity || 0);
-};
-const getDeliveryBatchDeliveryMax = row => {
-  const productQuantity = getCurrentDeliveryRowQuantity();
-  const batchQuantity = Number(getDeliveryBatchQuantity(row) || 0);
-  const otherBatchTotal = (deliveryForm.value.batchNoList || []).reduce(
+  // 鍙戣揣鐩稿叧
+  const deliveryFormVisible = ref(false);
+  const currentDeliveryRow = ref(null);
+  const getDeliveryBatchQuantity = item => {
+    const quantity =
+      item?.qualitity ??
+      item?.quantity ??
+      item?.unLockedQuantity ??
+      item?.qualifiedUnLockedQuantity ??
+      item?.qualifiedQuantity ??
+      item?.stockQuantity;
+    return quantity ?? 0;
+  };
+  const getCurrentDeliveryRowQuantity = () => {
+    return Number(currentDeliveryRow.value?.noQuantity || 0);
+  };
+  const getDeliveryBatchDeliveryMax = row => {
+    const productQuantity = getCurrentDeliveryRowQuantity();
+    const batchQuantity = Number(getDeliveryBatchQuantity(row) || 0);
+    const otherBatchTotal = (deliveryForm.value.batchNoList || []).reduce(
       (sum, item) => {
         if (item?.id === row?.id) return sum;
         return sum + Number(item?.deliveryQuantity || 0);
       },
       0
-  );
-  const remainingProductQuantity = Math.max(
+    );
+    const remainingProductQuantity = Math.max(
       0,
       productQuantity - otherBatchTotal
-  );
-  return Math.max(0, Math.min(batchQuantity, remainingProductQuantity));
-};
-const handleDeliveryBatchQuantityChange = row => {
-  const max = getDeliveryBatchDeliveryMax(row);
-  const currentValue = Number(row?.deliveryQuantity || 0);
-  if (currentValue > max) {
-    row.deliveryQuantity = max;
-    proxy.$modal.msgWarning("鍙戣揣鏁伴噺涓嶈兘瓒呰繃杩欎釜浜у搧鐨勬暟閲�");
-  }
-};
-const getSelectedDeliveryBatchRows = () => {
-  return (deliveryForm.value.batchNoList || []).filter(
+    );
+    return Math.max(0, Math.min(batchQuantity, remainingProductQuantity));
+  };
+  const handleDeliveryBatchQuantityChange = row => {
+    const productQuantity = getCurrentDeliveryRowQuantity();
+    const batchQuantity = Number(getDeliveryBatchQuantity(row) || 0);
+    const otherBatchTotal = (deliveryForm.value.batchNoList || []).reduce(
+      (sum, item) => {
+        if (item?.id === row?.id) return sum;
+        return sum + Number(item?.deliveryQuantity || 0);
+      },
+      0
+    );
+    const remainingProductQuantity = Math.max(
+      0,
+      productQuantity - otherBatchTotal
+    );
+    const currentValue = Number(row?.deliveryQuantity || 0);
+
+    if (currentValue > batchQuantity) {
+      row.deliveryQuantity = batchQuantity;
+      proxy.$modal.msgWarning("鍙戣揣鏁伴噺涓嶈兘澶т簬搴撳瓨鏁伴噺");
+    } else if (currentValue > remainingProductQuantity) {
+      row.deliveryQuantity = remainingProductQuantity;
+      proxy.$modal.msgWarning("鎵�鏈夋壒娆″彂璐ф暟閲忎箣鍜屼笉鑳藉ぇ浜庡緟鍙戣揣鏁伴噺");
+    }
+  };
+  const getSelectedDeliveryBatchRows = () => {
+    return (deliveryForm.value.batchNoList || []).filter(
       item => Number(item?.deliveryQuantity || 0) > 0
-  );
-};
-const getDeliveryBatchNoList = async productModelId => {
-  if (!productModelId) return [];
-  const res = await getStockInventoryByModelId(productModelId);
-  const rawList = Array.isArray(res?.data)
+    );
+  };
+  const getDeliveryBatchNoList = async productModelId => {
+    if (!productModelId) return [];
+    const res = await getStockInventoryByModelId(productModelId);
+    const rawList = Array.isArray(res?.data)
       ? res.data
       : res?.data?.records || res?.data?.rows || [];
-  const seenIds = new Set();
-  return rawList.filter(item => {
-    if (!item?.id || !item?.batchNo || seenIds.has(item.id)) {
-      return false;
-    }
-    seenIds.add(item.id);
-    return true;
-  }).map(item => ({
-    ...item,
-    deliveryQuantity: 0,
-  }));
-};
-const deliveryFormData = reactive({
-  deliveryForm: {
-    type: "璐ц溅", // 璐ц溅, 蹇��
-  },
-  deliveryRules: {
-    type: [{required: true, message: "璇烽�夋嫨鍙戣揣绫诲瀷", trigger: "change"}],
-  },
-});
-const {deliveryForm, deliveryRules} = toRefs(deliveryFormData);
+    const seenIds = new Set();
+    return rawList
+      .filter(item => {
+        if (!item?.id || !item?.batchNo || seenIds.has(item.id)) {
+          return false;
+        }
+        seenIds.add(item.id);
+        return true;
+      })
+      .map(item => ({
+        ...item,
+        deliveryQuantity: 0,
+      }));
+  };
+  const deliveryFormData = reactive({
+    deliveryForm: {
+      type: "璐ц溅", // 璐ц溅, 蹇��
+    },
+    deliveryRules: {
+      type: [{ required: true, message: "璇烽�夋嫨鍙戣揣绫诲瀷", trigger: "change" }],
+    },
+  });
+  const { deliveryForm, deliveryRules } = toRefs(deliveryFormData);
 
-// 瀵煎叆鐩稿叧
-const importUploadRef = ref(null);
-const importUpload = reactive({
-  title: "瀵煎叆閿�鍞彴璐�",
-  open: false,
-  url: import.meta.env.VITE_APP_BASE_API + "/sales/ledger/import",
-  headers: {Authorization: "Bearer " + getToken()},
-  isUploading: false,
-  beforeUpload: file => {
-    const isExcel = file.name.endsWith(".xlsx") || file.name.endsWith(".xls");
-    const isLt10M = file.size / 1024 / 1024 < 10;
-    if (!isExcel) {
-      proxy.$modal.msgError("涓婁紶鏂囦欢鍙兘鏄� xlsx/xls 鏍煎紡!");
-      return false;
-    }
-    if (!isLt10M) {
-      proxy.$modal.msgError("涓婁紶鏂囦欢澶у皬涓嶈兘瓒呰繃 10MB!");
-      return false;
-    }
-    return true;
-  },
-  onChange: (file, fileList) => {
-    console.log("鏂囦欢鐘舵�佹敼鍙�", file, fileList);
-  },
-  onProgress: (event, file, fileList) => {
-    console.log("涓婁紶涓�...", event.percent);
-  },
-  onSuccess: (response, file, fileList) => {
-    console.log("涓婁紶鎴愬姛", response, file, fileList);
-    importUpload.isUploading = false;
-    if (response.code === 200) {
-      proxy.$modal.msgSuccess("瀵煎叆鎴愬姛");
-      importUpload.open = false;
-      if (importUploadRef.value) {
-        importUploadRef.value.clearFiles();
+  // 瀵煎叆鐩稿叧
+  const importUploadRef = ref(null);
+  const importUpload = reactive({
+    title: "瀵煎叆閿�鍞彴璐�",
+    open: false,
+    url: import.meta.env.VITE_APP_BASE_API + "/sales/ledger/import",
+    headers: { Authorization: "Bearer " + getToken() },
+    isUploading: false,
+    beforeUpload: file => {
+      const isExcel = file.name.endsWith(".xlsx") || file.name.endsWith(".xls");
+      const isLt10M = file.size / 1024 / 1024 < 10;
+      if (!isExcel) {
+        proxy.$modal.msgError("涓婁紶鏂囦欢鍙兘鏄� xlsx/xls 鏍煎紡!");
+        return false;
       }
-      getList();
+      if (!isLt10M) {
+        proxy.$modal.msgError("涓婁紶鏂囦欢澶у皬涓嶈兘瓒呰繃 10MB!");
+        return false;
+      }
+      return true;
+    },
+    onChange: (file, fileList) => {
+      console.log("鏂囦欢鐘舵�佹敼鍙�", file, fileList);
+    },
+    onProgress: (event, file, fileList) => {
+      console.log("涓婁紶涓�...", event.percent);
+    },
+    onSuccess: (response, file, fileList) => {
+      console.log("涓婁紶鎴愬姛", response, file, fileList);
+      importUpload.isUploading = false;
+      if (response.code === 200) {
+        proxy.$modal.msgSuccess("瀵煎叆鎴愬姛");
+        importUpload.open = false;
+        if (importUploadRef.value) {
+          importUploadRef.value.clearFiles();
+        }
+        getList();
+      } else {
+        proxy.$modal.msgError(response.msg || "瀵煎叆澶辫触");
+      }
+    },
+    onError: (error, file, fileList) => {
+      console.error("涓婁紶澶辫触", error, file, fileList);
+      importUpload.isUploading = false;
+      proxy.$modal.msgError("瀵煎叆澶辫触锛岃閲嶈瘯");
+    },
+  });
+
+  const changeDaterange = value => {
+    if (value) {
+      searchForm.entryDateStart = dayjs(value[0]).format("YYYY-MM-DD");
+      searchForm.entryDateEnd = dayjs(value[1]).format("YYYY-MM-DD");
     } else {
-      proxy.$modal.msgError(response.msg || "瀵煎叆澶辫触");
+      searchForm.entryDateStart = undefined;
+      searchForm.entryDateEnd = undefined;
     }
-  },
-  onError: (error, file, fileList) => {
-    console.error("涓婁紶澶辫触", error, file, fileList);
-    importUpload.isUploading = false;
-    proxy.$modal.msgError("瀵煎叆澶辫触锛岃閲嶈瘯");
-  },
-});
+    handleQuery();
+  };
 
-const changeDaterange = value => {
-  if (value) {
-    searchForm.entryDateStart = dayjs(value[0]).format("YYYY-MM-DD");
-    searchForm.entryDateEnd = dayjs(value[1]).format("YYYY-MM-DD");
-  } else {
-    searchForm.entryDateStart = undefined;
-    searchForm.entryDateEnd = undefined;
-  }
-  handleQuery();
-};
-
-// 鏌ヨ鍒楄〃
-/** 鎼滅储鎸夐挳鎿嶄綔 */
-const handleQuery = () => {
-  // 鍙湁鍦ㄧ偣鍑绘悳绱㈡寜閽椂鎵嶉噸缃〉鐮佸埌绗竴椤�
-  // 閬垮厤琛ㄥ崟瀛楁change浜嬩欢骞叉壈鍒嗛〉
-  if (arguments.length === 0) {
-    page.current = 1;
-  }
-  expandedRowKeys.value = [];
-  getList();
-};
-const paginationChange = obj => {
-  page.current = obj.page;
-  page.size = obj.limit;
-  getList();
-};
-const getList = () => {
-  tableLoading.value = true;
-  const {entryDate, ...rest} = searchForm;
-  // 灏嗚寖鍥存棩鏈熷瓧娈典紶閫掔粰鍚庣
-  const params = {...rest, ...page};
-  // 绉婚櫎褰曞叆鏃ユ湡鐨勯粯璁ゅ�艰缃紝鍙繚鐣欒寖鍥存棩鏈熷瓧娈�
-  delete params.entryDate;
-  return ledgerListPage(params)
+  // 鏌ヨ鍒楄〃
+  /** 鎼滅储鎸夐挳鎿嶄綔 */
+  const handleQuery = () => {
+    // 鍙湁鍦ㄧ偣鍑绘悳绱㈡寜閽椂鎵嶉噸缃〉鐮佸埌绗竴椤�
+    // 閬垮厤琛ㄥ崟瀛楁change浜嬩欢骞叉壈鍒嗛〉
+    if (arguments.length === 0) {
+      page.current = 1;
+    }
+    expandedRowKeys.value = [];
+    getList();
+  };
+  const paginationChange = obj => {
+    page.current = obj.page;
+    page.size = obj.limit;
+    getList();
+  };
+  const getList = () => {
+    tableLoading.value = true;
+    const { entryDate, ...rest } = searchForm;
+    // 灏嗚寖鍥存棩鏈熷瓧娈典紶閫掔粰鍚庣
+    const params = { ...rest, ...page };
+    // 绉婚櫎褰曞叆鏃ユ湡鐨勯粯璁ゅ�艰缃紝鍙繚鐣欒寖鍥存棩鏈熷瓧娈�
+    delete params.entryDate;
+    return ledgerListPage(params)
       .then(res => {
         tableLoading.value = false;
         tableData.value = res.records;
@@ -1275,624 +1300,624 @@
       .catch(() => {
         tableLoading.value = false;
       });
-};
-// 鑾峰彇浜у搧澶х被tree鏁版嵁
-const getProductOptions = () => {
-  // 杩斿洖 Promise锛屼究浜庡湪缂栬緫浜у搧鏃剁瓑寰呭姞杞藉畬鎴�
-  return productTreeList().then(res => {
-    productOptions.value = convertIdToValue(res);
-    return productOptions.value;
-  });
-};
-const formattedNumber = (row, column, cellValue) => {
-  if (cellValue === undefined || cellValue === null || cellValue === "") {
-    return "0.00";
-  }
-  return parseFloat(cellValue).toFixed(2);
-};
-const findLedgerRecordByRow = row => {
-  if (!row) return null;
-  if (
+  };
+  // 鑾峰彇浜у搧澶х被tree鏁版嵁
+  const getProductOptions = () => {
+    // 杩斿洖 Promise锛屼究浜庡湪缂栬緫浜у搧鏃剁瓑寰呭姞杞藉畬鎴�
+    return productTreeList().then(res => {
+      productOptions.value = convertIdToValue(res);
+      return productOptions.value;
+    });
+  };
+  const formattedNumber = (row, column, cellValue) => {
+    if (cellValue === undefined || cellValue === null || cellValue === "") {
+      return "0.00";
+    }
+    return parseFloat(cellValue).toFixed(2);
+  };
+  const findLedgerRecordByRow = row => {
+    if (!row) return null;
+    if (
       row.maintainer !== undefined ||
       row.maintainerName !== undefined ||
       row.entryPerson !== undefined ||
       row.entryPersonName !== undefined
-  ) {
-    return row;
-  }
-  if (row.salesLedgerId !== undefined && row.salesLedgerId !== null) {
-    return (
+    ) {
+      return row;
+    }
+    if (row.salesLedgerId !== undefined && row.salesLedgerId !== null) {
+      return (
         tableData.value.find(
-            item => String(item.id) === String(row.salesLedgerId)
+          item => String(item.id) === String(row.salesLedgerId)
         ) || null
-    );
-  }
-  return null;
-};
-const isCurrentUserMaintainer = row => {
-  const ledgerRecord = findLedgerRecordByRow(row);
-  if (!ledgerRecord) return true;
-  const currentUserId = String(userStore.id ?? "");
-  const currentNickName = String(userStore.nickName ?? "").trim();
-  const maintainerId = ledgerRecord.maintainerId ?? ledgerRecord.entryPerson;
-  const maintainerName =
+      );
+    }
+    return null;
+  };
+  const isCurrentUserMaintainer = row => {
+    const ledgerRecord = findLedgerRecordByRow(row);
+    if (!ledgerRecord) return true;
+    const currentUserId = String(userStore.id ?? "");
+    const currentNickName = String(userStore.nickName ?? "").trim();
+    const maintainerId = ledgerRecord.maintainerId ?? ledgerRecord.entryPerson;
+    const maintainerName =
       ledgerRecord.maintainerName ??
       ledgerRecord.maintainer ??
       ledgerRecord.entryPersonName;
-  if (
+    if (
       maintainerId !== undefined &&
       maintainerId !== null &&
       String(maintainerId) !== ""
-  ) {
-    return String(maintainerId) === currentUserId;
-  }
-  if (
+    ) {
+      return String(maintainerId) === currentUserId;
+    }
+    if (
       maintainerName !== undefined &&
       maintainerName !== null &&
       String(maintainerName).trim() !== ""
-  ) {
-    return String(maintainerName).trim() === currentNickName;
-  }
-  return true;
-};
-const canEditLedger = row => isCurrentUserMaintainer(row);
-const canDeleteLedger = row => isCurrentUserMaintainer(row);
-const sensitiveAmountFormatter = (row, column, cellValue) => {
-  if (!isCurrentUserMaintainer(row)) {
-    return "*****";
-  }
-  return formattedNumber(row, column, cellValue);
-};
-// 鑾峰彇tree瀛愭暟鎹�
-const getModels = value => {
-  productForm.value.productCategory = findNodeById(productOptions.value, value);
-  modelList({id: value}).then(res => {
-    modelOptions.value = res;
-  });
-};
-const getProductModel = value => {
-  const index = modelOptions.value.findIndex(item => item.id === value);
-  if (index !== -1) {
-    productForm.value.specificationModel = modelOptions.value[index].model;
-    productForm.value.unit = modelOptions.value[index].unit;
-  } else {
-    productForm.value.specificationModel = null;
-    productForm.value.unit = null;
-  }
-};
-const findNodeById = (nodes, productId) => {
-  for (let i = 0; i < nodes.length; i++) {
-    if (nodes[i].value === productId) {
-      return nodes[i].label; // 鎵惧埌鑺傜偣锛岃繑鍥炶鑺傜偣
+    ) {
+      return String(maintainerName).trim() === currentNickName;
     }
-    if (nodes[i].children && nodes[i].children.length > 0) {
-      const foundNode = findNodeById(nodes[i].children, productId);
-      if (foundNode) {
-        return foundNode; // 鍦ㄥ瓙鑺傜偣涓壘鍒帮紝杩斿洖璇ヨ妭鐐�
+    return true;
+  };
+  const canEditLedger = row => isCurrentUserMaintainer(row);
+  const canDeleteLedger = row => isCurrentUserMaintainer(row);
+  const sensitiveAmountFormatter = (row, column, cellValue) => {
+    if (!isCurrentUserMaintainer(row)) {
+      return "*****";
+    }
+    return formattedNumber(row, column, cellValue);
+  };
+  // 鑾峰彇tree瀛愭暟鎹�
+  const getModels = value => {
+    productForm.value.productCategory = findNodeById(productOptions.value, value);
+    modelList({ id: value }).then(res => {
+      modelOptions.value = res;
+    });
+  };
+  const getProductModel = value => {
+    const index = modelOptions.value.findIndex(item => item.id === value);
+    if (index !== -1) {
+      productForm.value.specificationModel = modelOptions.value[index].model;
+      productForm.value.unit = modelOptions.value[index].unit;
+    } else {
+      productForm.value.specificationModel = null;
+      productForm.value.unit = null;
+    }
+  };
+  const findNodeById = (nodes, productId) => {
+    for (let i = 0; i < nodes.length; i++) {
+      if (nodes[i].value === productId) {
+        return nodes[i].label; // 鎵惧埌鑺傜偣锛岃繑鍥炶鑺傜偣
       }
-    }
-  }
-  return null; // 娌℃湁鎵惧埌鑺傜偣锛岃繑鍥瀗ull
-};
-
-function convertIdToValue(data) {
-  return data.map(item => {
-    const {id, children, ...rest} = item;
-    const newItem = {
-      ...rest,
-      value: id, // 灏� id 鏀逛负 value
-    };
-    if (children && children.length > 0) {
-      newItem.children = convertIdToValue(children);
-    }
-
-    return newItem;
-  });
-}
-
-// 鏍规嵁鍚嶇О鍙嶆煡浜у搧澶х被 id锛屼究浜庝粎瀛樺悕绉版椂鐨勫弽鏄�
-function findNodeIdByLabel(nodes, label) {
-  if (!label) return null;
-  for (let i = 0; i < nodes.length; i++) {
-    const node = nodes[i];
-    if (node.label === label) return node.value;
-    if (node.children && node.children.length > 0) {
-      const found = findNodeIdByLabel(node.children, label);
-      if (found !== null && found !== undefined) return found;
-    }
-  }
-  return null;
-}
-
-// 琛ㄦ牸閫夋嫨鏁版嵁
-const handleSelectionChange = selection => {
-  // 杩囨护鎺夊瓙鏁版嵁
-  selectedRows.value = selection.filter(item => item.children !== undefined);
-  console.log("selection", selectedRows.value);
-};
-const productSelected = selectedRows => {
-  productSelectedRows.value = selectedRows;
-};
-const expandedRowKeys = ref([]);
-// 灞曞紑琛�
-const expandChange = (row, expandedRows) => {
-  if (expandedRows.length > 0) {
-    expandedRowKeys.value = [];
-    try {
-      productList({salesLedgerId: row.id, type: 1}).then(res => {
-        const index = tableData.value.findIndex(item => item.id === row.id);
-        if (index > -1) {
-          tableData.value[index].children = res.data;
+      if (nodes[i].children && nodes[i].children.length > 0) {
+        const foundNode = findNodeById(nodes[i].children, productId);
+        if (foundNode) {
+          return foundNode; // 鍦ㄥ瓙鑺傜偣涓壘鍒帮紝杩斿洖璇ヨ妭鐐�
         }
-        expandedRowKeys.value.push(row.id);
-      });
-    } catch (error) {
-      console.log(error);
-    }
-  } else {
-    expandedRowKeys.value = [];
-  }
-};
-
-// 娣诲姞琛ㄨ绫诲悕鏂规硶
-const tableRowClassName = ({row}) => {
-  if (!row.deliveryDate) return "";
-  if (row.isFh) return "";
-
-  const diff = row.deliveryDaysDiff;
-  if (diff === 15) {
-    return "yellow";
-  } else if (diff === 10) {
-    return "pink";
-  } else if (diff === 2) {
-    return "purple";
-  } else if (diff < 2) {
-    return "red";
-  }
-};
-// 涓昏〃鍚堣鏂规硶
-const summarizeMainTable = param => {
-  return proxy.summarizeTable(param, [
-    "contractAmount",
-    "taxInclusiveTotalPrice",
-    "taxExclusiveTotalPrice",
-  ]);
-};
-// 瀛愯〃鍚堣鏂规硶
-const summarizeChildrenTable = (param, parentRow) => {
-  if (!isCurrentUserMaintainer(parentRow)) {
-    const {columns} = param;
-    return columns.map((column, index) => {
-      if (index === 0) {
-        return "鍚堣";
       }
-      if (
+    }
+    return null; // 娌℃湁鎵惧埌鑺傜偣锛岃繑鍥瀗ull
+  };
+
+  function convertIdToValue(data) {
+    return data.map(item => {
+      const { id, children, ...rest } = item;
+      const newItem = {
+        ...rest,
+        value: id, // 灏� id 鏀逛负 value
+      };
+      if (children && children.length > 0) {
+        newItem.children = convertIdToValue(children);
+      }
+
+      return newItem;
+    });
+  }
+
+  // 鏍规嵁鍚嶇О鍙嶆煡浜у搧澶х被 id锛屼究浜庝粎瀛樺悕绉版椂鐨勫弽鏄�
+  function findNodeIdByLabel(nodes, label) {
+    if (!label) return null;
+    for (let i = 0; i < nodes.length; i++) {
+      const node = nodes[i];
+      if (node.label === label) return node.value;
+      if (node.children && node.children.length > 0) {
+        const found = findNodeIdByLabel(node.children, label);
+        if (found !== null && found !== undefined) return found;
+      }
+    }
+    return null;
+  }
+
+  // 琛ㄦ牸閫夋嫨鏁版嵁
+  const handleSelectionChange = selection => {
+    // 杩囨护鎺夊瓙鏁版嵁
+    selectedRows.value = selection.filter(item => item.children !== undefined);
+    console.log("selection", selectedRows.value);
+  };
+  const productSelected = selectedRows => {
+    productSelectedRows.value = selectedRows;
+  };
+  const expandedRowKeys = ref([]);
+  // 灞曞紑琛�
+  const expandChange = (row, expandedRows) => {
+    if (expandedRows.length > 0) {
+      expandedRowKeys.value = [];
+      try {
+        productList({ salesLedgerId: row.id, type: 1 }).then(res => {
+          const index = tableData.value.findIndex(item => item.id === row.id);
+          if (index > -1) {
+            tableData.value[index].children = res.data;
+          }
+          expandedRowKeys.value.push(row.id);
+        });
+      } catch (error) {
+        console.log(error);
+      }
+    } else {
+      expandedRowKeys.value = [];
+    }
+  };
+
+  // 娣诲姞琛ㄨ绫诲悕鏂规硶
+  const tableRowClassName = ({ row }) => {
+    if (!row.deliveryDate) return "";
+    if (row.isFh) return "";
+
+    const diff = row.deliveryDaysDiff;
+    if (diff === 15) {
+      return "yellow";
+    } else if (diff === 10) {
+      return "pink";
+    } else if (diff === 2) {
+      return "purple";
+    } else if (diff < 2) {
+      return "red";
+    }
+  };
+  // 涓昏〃鍚堣鏂规硶
+  const summarizeMainTable = param => {
+    return proxy.summarizeTable(param, [
+      "contractAmount",
+      "taxInclusiveTotalPrice",
+      "taxExclusiveTotalPrice",
+    ]);
+  };
+  // 瀛愯〃鍚堣鏂规硶
+  const summarizeChildrenTable = (param, parentRow) => {
+    if (!isCurrentUserMaintainer(parentRow)) {
+      const { columns } = param;
+      return columns.map((column, index) => {
+        if (index === 0) {
+          return "鍚堣";
+        }
+        if (
           [
             "taxInclusiveUnitPrice",
             "taxInclusiveTotalPrice",
             "taxExclusiveTotalPrice",
           ].includes(column.property)
-      ) {
-        return "*****";
-      }
-      return "";
-    });
-  }
-  return proxy.summarizeTable(param, [
-    "taxInclusiveUnitPrice",
-    "taxInclusiveTotalPrice",
-    "taxExclusiveTotalPrice",
-  ]);
-};
-// 鎵撳紑寮规
-const openForm = async (type, row) => {
-  if (type === "edit" && row && !canEditLedger(row)) {
-    proxy.$modal.msgWarning("褰撳墠绯荤粺鐧诲綍浜轰笉鏄淮鎶や汉锛屼笉鑳界紪杈戞暟鎹�");
-    return;
-  }
-  operationType.value = type;
-  form.value = {};
-  productData.value = [];
-  selectedQuotation.value = null;
-  let userLists = await userListNoPage();
-  userList.value = userLists.data;
-  listCustomer({current: -1, size: -1}).then(res => {
-    customerOption.value = res.data.records;
-  });
-  form.value.entryPerson = userStore.id;
-  if (type === "add") {
-    // 鏂板鏃惰缃綍鍏ユ棩鏈熶负褰撳ぉ
-    form.value.entryDate = getCurrentDate();
-    // 绛捐鏃ユ湡榛樿涓哄綋澶�
-    form.value.executionDate = getCurrentDate();
-  } else {
-    currentId.value = row.id;
-    getSalesLedgerWithProducts({id: row.id, type: 1}).then(res => {
-      form.value = {...res};
-      form.value.entryPerson = Number(res.entryPerson);
-      productData.value = form.value.productData;
-      fileList.value = form.value.storageBlobVOs;
-    });
-  }
-  // let userAll = await userStore.getInfo()
-  // userList.value.forEach(element => {
-  //   if(userAll.user.nickName === element.nickName && userAll.user.userName === element.userName) {
-  //     form.value.entryPerson = userAll.user.userId // 璁剧疆榛樿涓氬姟鍛樹负褰撳墠鐢ㄦ埛
-  //   }
-  // });
-  form.value.entryDate = getCurrentDate(); // 璁剧疆榛樿褰曞叆鏃ユ湡涓哄綋鍓嶆棩鏈�
-  dialogFormVisible.value = true;
-};
-
-// 鎵撳紑鎶ヤ环鍗曢�夋嫨寮圭獥锛堜粎瀹℃壒閫氳繃锛�
-const openQuotationDialog = async () => {
-  if (operationType.value === "view") return;
-  quotationDialogVisible.value = true;
-  // 鎵撳紑寮圭獥鏃堕噸缃垎椤靛埌绗竴椤�
-  quotationPage.current = 1;
-  // 鍏堢‘淇濆鎴峰垪琛ㄥ凡鍔犺浇锛屼究浜庡悗缁洖濉� customerId
-  if (!customerOption.value || customerOption.value.length === 0) {
-    try {
-      listCustomer({current: -1, size: -1}).then(res => {
-        customerOption.value = res.data.records;
+        ) {
+          return "*****";
+        }
+        return "";
       });
-    } catch (e) {
-      // ignore锛屽厑璁哥敤鎴峰悗缁墜鍔ㄩ�夋嫨瀹㈡埛
     }
-  }
-  await fetchQuotationList();
-};
+    return proxy.summarizeTable(param, [
+      "taxInclusiveUnitPrice",
+      "taxInclusiveTotalPrice",
+      "taxExclusiveTotalPrice",
+    ]);
+  };
+  // 鎵撳紑寮规
+  const openForm = async (type, row) => {
+    if (type === "edit" && row && !canEditLedger(row)) {
+      proxy.$modal.msgWarning("褰撳墠绯荤粺鐧诲綍浜轰笉鏄淮鎶や汉锛屼笉鑳界紪杈戞暟鎹�");
+      return;
+    }
+    operationType.value = type;
+    form.value = {};
+    productData.value = [];
+    selectedQuotation.value = null;
+    let userLists = await userListNoPage();
+    userList.value = userLists.data;
+    listCustomer({ current: -1, size: -1 }).then(res => {
+      customerOption.value = res.data.records;
+    });
+    form.value.entryPerson = userStore.id;
+    if (type === "add") {
+      // 鏂板鏃惰缃綍鍏ユ棩鏈熶负褰撳ぉ
+      form.value.entryDate = getCurrentDate();
+      // 绛捐鏃ユ湡榛樿涓哄綋澶�
+      form.value.executionDate = getCurrentDate();
+    } else {
+      currentId.value = row.id;
+      getSalesLedgerWithProducts({ id: row.id, type: 1 }).then(res => {
+        form.value = { ...res };
+        form.value.entryPerson = Number(res.entryPerson);
+        productData.value = form.value.productData;
+        fileList.value = form.value.storageBlobVOs;
+      });
+    }
+    // let userAll = await userStore.getInfo()
+    // userList.value.forEach(element => {
+    //   if(userAll.user.nickName === element.nickName && userAll.user.userName === element.userName) {
+    //     form.value.entryPerson = userAll.user.userId // 璁剧疆榛樿涓氬姟鍛樹负褰撳墠鐢ㄦ埛
+    //   }
+    // });
+    form.value.entryDate = getCurrentDate(); // 璁剧疆榛樿褰曞叆鏃ユ湡涓哄綋鍓嶆棩鏈�
+    dialogFormVisible.value = true;
+  };
 
-const fetchQuotationList = async () => {
-  quotationLoading.value = true;
-  try {
-    const params = {
-      // 鍚庣鍒嗛〉瀛楁锛歝urrent / size
-      current: quotationPage.current,
-      size: quotationPage.size,
-      ...quotationSearchForm,
-      status: "閫氳繃",
-    };
-    const res = await getQuotationList(params);
-    quotationList.value = res?.data?.records || [];
-    quotationPage.total = res?.data?.total || 0;
-  } finally {
-    quotationLoading.value = false;
-  }
-};
+  // 鎵撳紑鎶ヤ环鍗曢�夋嫨寮圭獥锛堜粎瀹℃壒閫氳繃锛�
+  const openQuotationDialog = async () => {
+    if (operationType.value === "view") return;
+    quotationDialogVisible.value = true;
+    // 鎵撳紑寮圭獥鏃堕噸缃垎椤靛埌绗竴椤�
+    quotationPage.current = 1;
+    // 鍏堢‘淇濆鎴峰垪琛ㄥ凡鍔犺浇锛屼究浜庡悗缁洖濉� customerId
+    if (!customerOption.value || customerOption.value.length === 0) {
+      try {
+        listCustomer({ current: -1, size: -1 }).then(res => {
+          customerOption.value = res.data.records;
+        });
+      } catch (e) {
+        // ignore锛屽厑璁哥敤鎴峰悗缁墜鍔ㄩ�夋嫨瀹㈡埛
+      }
+    }
+    await fetchQuotationList();
+  };
 
-const resetQuotationSearch = async () => {
-  quotationSearchForm.quotationNo = "";
-  quotationSearchForm.customer = "";
-  quotationPage.current = 1;
-  await fetchQuotationList();
-};
+  const fetchQuotationList = async () => {
+    quotationLoading.value = true;
+    try {
+      const params = {
+        // 鍚庣鍒嗛〉瀛楁锛歝urrent / size
+        current: quotationPage.current,
+        size: quotationPage.size,
+        ...quotationSearchForm,
+        status: "閫氳繃",
+      };
+      const res = await getQuotationList(params);
+      quotationList.value = res?.data?.records || [];
+      quotationPage.total = res?.data?.total || 0;
+    } finally {
+      quotationLoading.value = false;
+    }
+  };
 
-// 鎶ヤ环鍗曞脊妗嗗垎椤靛垏鎹�
-const quotationPaginationChange = obj => {
-  quotationPage.current = obj.page;
-  quotationPage.size = obj.limit;
-  fetchQuotationList();
-};
+  const resetQuotationSearch = async () => {
+    quotationSearchForm.quotationNo = "";
+    quotationSearchForm.customer = "";
+    quotationPage.current = 1;
+    await fetchQuotationList();
+  };
 
-// 閫変腑鎶ヤ环鍗曞悗鍥炲~鍒板彴璐﹁〃鍗�
-const applyQuotation = row => {
-  if (!row) return;
-  selectedQuotation.value = row;
+  // 鎶ヤ环鍗曞脊妗嗗垎椤靛垏鎹�
+  const quotationPaginationChange = obj => {
+    quotationPage.current = obj.page;
+    quotationPage.size = obj.limit;
+    fetchQuotationList();
+  };
 
-  // 涓氬姟鍛�
-  form.value.salesman = (row.salesperson || "").trim();
+  // 閫変腑鎶ヤ环鍗曞悗鍥炲~鍒板彴璐﹁〃鍗�
+  const applyQuotation = row => {
+    if (!row) return;
+    selectedQuotation.value = row;
 
-  // 瀹㈡埛鍚嶇О -> customerId
-  const qCustomerName = String(row.customer || "").trim();
-  const customer = (customerOption.value || []).find(c => {
-    const name = String(c.customerName || "").trim();
-    return (
+    // 涓氬姟鍛�
+    form.value.salesman = (row.salesperson || "").trim();
+
+    // 瀹㈡埛鍚嶇О -> customerId
+    const qCustomerName = String(row.customer || "").trim();
+    const customer = (customerOption.value || []).find(c => {
+      const name = String(c.customerName || "").trim();
+      return (
         name === qCustomerName ||
         name.includes(qCustomerName) ||
         qCustomerName.includes(name)
-    );
-  });
-  if (customer?.id) {
-    form.value.customerId = customer.id;
-  } else {
-    // 濡傛灉鎵句笉鍒帮紝淇濈暀鍘熷�硷紙鍏佽鐢ㄦ埛鎵嬪姩閫夋嫨/涓嶆墦鏂凡鏈夎緭鍏ワ級
-    form.value.customerId = form.value.customerId || "";
-  }
+      );
+    });
+    if (customer?.id) {
+      form.value.customerId = customer.id;
+    } else {
+      // 濡傛灉鎵句笉鍒帮紝淇濈暀鍘熷�硷紙鍏佽鐢ㄦ埛鎵嬪姩閫夋嫨/涓嶆墦鏂凡鏈夎緭鍏ワ級
+      form.value.customerId = form.value.customerId || "";
+    }
 
-  // 浜у搧淇℃伅鏄犲皠锛氭姤浠� products -> 鍙拌处 productData
-  const products = Array.isArray(row.products) ? row.products : [];
-  productData.value = products.map(p => {
-    const quantity = Number(p.quantity ?? 0) || 0;
-    const unitPrice = Number(p.unitPrice ?? 0) || 0;
-    const taxRate = "13"; // 榛樿 13%锛屼究浜庣洿鎺ユ彁浜わ紙濡傞渶鍙湪浜у搧涓嚜琛屼慨鏀癸級
-    const taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(2);
-    const taxExclusiveTotalPrice = proxy.calculateTaxExclusiveTotalPrice(
+    // 浜у搧淇℃伅鏄犲皠锛氭姤浠� products -> 鍙拌处 productData
+    const products = Array.isArray(row.products) ? row.products : [];
+    productData.value = products.map(p => {
+      const quantity = Number(p.quantity ?? 0) || 0;
+      const unitPrice = Number(p.unitPrice ?? 0) || 0;
+      const taxRate = "13"; // 榛樿 13%锛屼究浜庣洿鎺ユ彁浜わ紙濡傞渶鍙湪浜у搧涓嚜琛屼慨鏀癸級
+      const taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(2);
+      const taxExclusiveTotalPrice = proxy.calculateTaxExclusiveTotalPrice(
         taxInclusiveTotalPrice,
         taxRate
-    );
-    return {
-      // 鍙拌处瀛楁
-      productCategory: p.product || p.productName || "",
-      specificationModel: p.specification || "",
-      unit: p.unit || "",
-      quantity: quantity,
-      taxRate: taxRate,
-      taxInclusiveUnitPrice: unitPrice.toFixed(2),
-      taxInclusiveTotalPrice: taxInclusiveTotalPrice,
-      taxExclusiveTotalPrice: taxExclusiveTotalPrice,
-      invoiceType: "澧炴櫘绁�",
-      isProduction: true,
-    };
-  });
+      );
+      return {
+        // 鍙拌处瀛楁
+        productCategory: p.product || p.productName || "",
+        specificationModel: p.specification || "",
+        unit: p.unit || "",
+        quantity: quantity,
+        taxRate: taxRate,
+        taxInclusiveUnitPrice: unitPrice.toFixed(2),
+        taxInclusiveTotalPrice: taxInclusiveTotalPrice,
+        taxExclusiveTotalPrice: taxExclusiveTotalPrice,
+        invoiceType: "澧炴櫘绁�",
+        isProduction: true,
+      };
+    });
 
-  quotationDialogVisible.value = false;
-};
+    quotationDialogVisible.value = false;
+  };
 
-function changs(val) {
-  console.log(val);
-}
+  function changs(val) {
+    console.log(val);
+  }
 
-// 鎻愪氦琛ㄥ崟
-const submitForm = () => {
-  proxy.$refs["formRef"].validate(valid => {
-    if (valid) {
-      console.log("productData.value--", productData.value);
-      if (productData.value !== null && productData.value.length > 0) {
-        form.value.productData = proxy.HaveJson(productData.value);
-      } else {
-        proxy.$modal.msgWarning("璇锋坊鍔犱骇鍝佷俊鎭�");
-        return;
+  // 鎻愪氦琛ㄥ崟
+  const submitForm = () => {
+    proxy.$refs["formRef"].validate(valid => {
+      if (valid) {
+        console.log("productData.value--", productData.value);
+        if (productData.value !== null && productData.value.length > 0) {
+          form.value.productData = proxy.HaveJson(productData.value);
+        } else {
+          proxy.$modal.msgWarning("璇锋坊鍔犱骇鍝佷俊鎭�");
+          return;
+        }
+        form.value.storageBlobDTOs = fileList;
+        form.value.type = 1;
+        addOrUpdateSalesLedger(form.value).then(res => {
+          proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+          closeDia();
+          expandedRowKeys.value = [];
+          getList();
+        });
       }
-      form.value.storageBlobDTOs = fileList;
-      form.value.type = 1;
-      addOrUpdateSalesLedger(form.value).then(res => {
-        proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
-        closeDia();
-        expandedRowKeys.value = [];
-        getList();
-      });
+    });
+  };
+  // 鍏抽棴寮规
+  const closeDia = () => {
+    proxy.resetForm("formRef");
+    dialogFormVisible.value = false;
+  };
+
+  const productIndex = ref(0);
+  // 鎵撳紑浜у搧寮规
+  const openProductForm = async (type, row, index) => {
+    // 缂栬緫鏃舵鏌ヤ骇鍝佹槸鍚﹀凡鍙戣揣鎴栧鏍搁�氳繃
+    if (type === "edit" && isProductShipped(row)) {
+      proxy.$modal.msgWarning("宸插彂璐ф垨瀹℃牳閫氳繃鐨勪骇鍝佷笉鑳界紪杈�");
+      return;
     }
-  });
-};
-// 鍏抽棴寮规
-const closeDia = () => {
-  proxy.resetForm("formRef");
-  dialogFormVisible.value = false;
-};
 
-const productIndex = ref(0);
-// 鎵撳紑浜у搧寮规
-const openProductForm = async (type, row, index) => {
-  // 缂栬緫鏃舵鏌ヤ骇鍝佹槸鍚﹀凡鍙戣揣鎴栧鏍搁�氳繃
-  if (type === "edit" && isProductShipped(row)) {
-    proxy.$modal.msgWarning("宸插彂璐ф垨瀹℃牳閫氳繃鐨勪骇鍝佷笉鑳界紪杈�");
-    return;
-  }
-
-  productOperationType.value = type;
-  productForm.value = {};
-  if (type === "add") {
-    productForm.value.isProduction = true;
-  }
-  proxy.resetForm("productFormRef");
-  if (type === "edit") {
-    productForm.value = {...row};
-    productIndex.value = index;
-    // 缂栬緫鏃舵牴鎹骇鍝佸ぇ绫诲悕绉板弽鏌� tree 鑺傜偣 id锛屽苟鍔犺浇瑙勬牸鍨嬪彿鍒楄〃
-    try {
-      const options =
+    productOperationType.value = type;
+    productForm.value = {};
+    if (type === "add") {
+      productForm.value.isProduction = true;
+    }
+    proxy.resetForm("productFormRef");
+    if (type === "edit") {
+      productForm.value = { ...row };
+      productIndex.value = index;
+      // 缂栬緫鏃舵牴鎹骇鍝佸ぇ绫诲悕绉板弽鏌� tree 鑺傜偣 id锛屽苟鍔犺浇瑙勬牸鍨嬪彿鍒楄〃
+      try {
+        const options =
           productOptions.value && productOptions.value.length > 0
-              ? productOptions.value
-              : await getProductOptions();
-      const categoryId = findNodeIdByLabel(
+            ? productOptions.value
+            : await getProductOptions();
+        const categoryId = findNodeIdByLabel(
           options,
           productForm.value.productCategory
-      );
-      if (categoryId) {
-        const models = await modelList({id: categoryId});
-        modelOptions.value = models || [];
-        // 鏍规嵁褰撳墠瑙勬牸鍨嬪彿鍚嶇О鍙嶆煡骞惰缃� productModelId锛屼究浜庝笅鎷夋鏄剧ず宸查�夊��
-        const currentModel = (modelOptions.value || []).find(
-            m => m.model === productForm.value.specificationModel
         );
-        if (currentModel) {
-          productForm.value.productModelId = currentModel.id;
+        if (categoryId) {
+          const models = await modelList({ id: categoryId });
+          modelOptions.value = models || [];
+          // 鏍规嵁褰撳墠瑙勬牸鍨嬪彿鍚嶇О鍙嶆煡骞惰缃� productModelId锛屼究浜庝笅鎷夋鏄剧ず宸查�夊��
+          const currentModel = (modelOptions.value || []).find(
+            m => m.model === productForm.value.specificationModel
+          );
+          if (currentModel) {
+            productForm.value.productModelId = currentModel.id;
+          }
         }
+      } catch (e) {
+        // 鍔犺浇澶辫触鏃朵繚鎸佸彲缂栬緫锛屼笉涓柇寮圭獥
+        console.error("鍔犺浇浜у搧瑙勬牸鍨嬪彿澶辫触", e);
       }
-    } catch (e) {
-      // 鍔犺浇澶辫触鏃朵繚鎸佸彲缂栬緫锛屼笉涓柇寮圭獥
-      console.error("鍔犺浇浜у搧瑙勬牸鍨嬪彿澶辫触", e);
+    } else {
+      getProductOptions();
     }
-  } else {
-    getProductOptions();
-  }
-  productFormVisible.value = true;
-};
-// 鎻愪氦浜у搧琛ㄥ崟
-const submitProduct = () => {
-  proxy.$refs["productFormRef"].validate(valid => {
-    if (valid) {
-      if (operationType.value === "edit") {
-        submitProductEdit();
-      } else {
-        if (productOperationType.value === "add") {
-          productData.value.push({...productForm.value});
+    productFormVisible.value = true;
+  };
+  // 鎻愪氦浜у搧琛ㄥ崟
+  const submitProduct = () => {
+    proxy.$refs["productFormRef"].validate(valid => {
+      if (valid) {
+        if (operationType.value === "edit") {
+          submitProductEdit();
         } else {
-          productData.value[productIndex.value] = {...productForm.value};
+          if (productOperationType.value === "add") {
+            productData.value.push({ ...productForm.value });
+          } else {
+            productData.value[productIndex.value] = { ...productForm.value };
+          }
+          closeProductDia();
         }
-        closeProductDia();
       }
-    }
-  });
-};
-const submitProductEdit = () => {
-  productForm.value.salesLedgerId = currentId.value;
-  productForm.value.type = 1;
-  addOrUpdateSalesLedgerProduct(productForm.value).then(res => {
-    proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
-    closeProductDia();
-    getSalesLedgerWithProducts({id: currentId.value, type: 1}).then(res => {
-      productData.value = res.productData;
     });
-  });
-};
-// 鍒犻櫎浜у搧
-const deleteProduct = () => {
-  if (productSelectedRows.value.length === 0) {
-    proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
-    return;
-  }
+  };
+  const submitProductEdit = () => {
+    productForm.value.salesLedgerId = currentId.value;
+    productForm.value.type = 1;
+    addOrUpdateSalesLedgerProduct(productForm.value).then(res => {
+      proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+      closeProductDia();
+      getSalesLedgerWithProducts({ id: currentId.value, type: 1 }).then(res => {
+        productData.value = res.productData;
+      });
+    });
+  };
+  // 鍒犻櫎浜у搧
+  const deleteProduct = () => {
+    if (productSelectedRows.value.length === 0) {
+      proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
+      return;
+    }
 
-  // 妫�鏌ユ槸鍚︽湁宸插彂璐ф垨瀹℃牳閫氳繃鐨勪骇鍝�
-  const shippedProducts = productSelectedRows.value.filter(row =>
+    // 妫�鏌ユ槸鍚︽湁宸插彂璐ф垨瀹℃牳閫氳繃鐨勪骇鍝�
+    const shippedProducts = productSelectedRows.value.filter(row =>
       isProductShipped(row)
-  );
-  if (shippedProducts.length > 0) {
-    proxy.$modal.msgWarning("宸插彂璐ф垨瀹℃牳閫氳繃鐨勪骇鍝佷笉鑳藉垹闄�");
-    return;
-  }
-
-  if (operationType.value === "add") {
-    productSelectedRows.value.forEach(selectedRow => {
-      const index = productData.value.findIndex(
-          product => product.id === selectedRow.id
-      );
-      if (index !== -1) {
-        productData.value.splice(index, 1);
-      }
-    });
-  } else {
-    let ids = [];
-    if (productSelectedRows.value.length > 0) {
-      ids = productSelectedRows.value.map(item => item.id);
+    );
+    if (shippedProducts.length > 0) {
+      proxy.$modal.msgWarning("宸插彂璐ф垨瀹℃牳閫氳繃鐨勪骇鍝佷笉鑳藉垹闄�");
+      return;
     }
-    ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "瀵煎嚭", {
-      confirmButtonText: "纭",
-      cancelButtonText: "鍙栨秷",
-      type: "warning",
-    })
+
+    if (operationType.value === "add") {
+      productSelectedRows.value.forEach(selectedRow => {
+        const index = productData.value.findIndex(
+          product => product.id === selectedRow.id
+        );
+        if (index !== -1) {
+          productData.value.splice(index, 1);
+        }
+      });
+    } else {
+      let ids = [];
+      if (productSelectedRows.value.length > 0) {
+        ids = productSelectedRows.value.map(item => item.id);
+      }
+      ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "瀵煎嚭", {
+        confirmButtonText: "纭",
+        cancelButtonText: "鍙栨秷",
+        type: "warning",
+      })
         .then(() => {
           delProduct(ids).then(res => {
             proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
             closeProductDia();
-            getSalesLedgerWithProducts({id: currentId.value, type: 1}).then(
-                res => {
-                  productData.value = res.productData;
-                }
+            getSalesLedgerWithProducts({ id: currentId.value, type: 1 }).then(
+              res => {
+                productData.value = res.productData;
+              }
             );
           });
         })
         .catch(() => {
           proxy.$modal.msg("宸插彇娑�");
         });
-  }
-};
-// 鍏抽棴浜у搧寮规
-const closeProductDia = () => {
-  proxy.resetForm("productFormRef");
-  productFormVisible.value = false;
-};
-// 瀵煎叆
-const handleImport = () => {
-  importUpload.title = "瀵煎叆閿�鍞彴璐�";
-  importUpload.open = true;
-  if (importUploadRef.value) {
-    importUploadRef.value.clearFiles();
-  }
-};
+    }
+  };
+  // 鍏抽棴浜у搧寮规
+  const closeProductDia = () => {
+    proxy.resetForm("productFormRef");
+    productFormVisible.value = false;
+  };
+  // 瀵煎叆
+  const handleImport = () => {
+    importUpload.title = "瀵煎叆閿�鍞彴璐�";
+    importUpload.open = true;
+    if (importUploadRef.value) {
+      importUploadRef.value.clearFiles();
+    }
+  };
 
-// 涓嬭浇瀵煎叆妯℃澘
-const downloadTemplate = () => {
-  proxy.download("/sales/ledger/exportTemplate", {}, "閿�鍞彴璐﹀鍏ユā鏉�.xlsx");
-};
+  // 涓嬭浇瀵煎叆妯℃澘
+  const downloadTemplate = () => {
+    proxy.download("/sales/ledger/exportTemplate", {}, "閿�鍞彴璐﹀鍏ユā鏉�.xlsx");
+  };
 
-// 鎻愪氦瀵煎叆鏂囦欢
-const submitImportFile = () => {
-  importUpload.isUploading = true;
-  proxy.$refs["importUploadRef"].submit();
-};
+  // 鎻愪氦瀵煎叆鏂囦欢
+  const submitImportFile = () => {
+    importUpload.isUploading = true;
+    proxy.$refs["importUploadRef"].submit();
+  };
 
-// 瀵煎嚭
-const handleOut = () => {
-  ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
-    confirmButtonText: "纭",
-    cancelButtonText: "鍙栨秷",
-    type: "warning",
-  })
+  // 瀵煎嚭
+  const handleOut = () => {
+    ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
+      confirmButtonText: "纭",
+      cancelButtonText: "鍙栨秷",
+      type: "warning",
+    })
       .then(() => {
         proxy.download("/sales/ledger/export", {}, "閿�鍞彴璐�.xlsx");
       })
       .catch(() => {
         proxy.$modal.msg("宸插彇娑�");
       });
-};
-/** 鍒ゆ柇鍗曚釜浜у搧鏄惁宸插彂璐э紙鏍规嵁shippingStatus鍒ゆ柇锛屽凡鍙戣揣鎴栧鏍搁�氳繃涓嶅彲缂栬緫鍜屽垹闄わ級 */
-const isProductShipped = product => {
-  if (!product) return false;
-  const status = String(product.shippingStatus || "").trim();
-  // 濡傛灉鍙戣揣鐘舵�佹槸"宸插彂璐�"鎴�"瀹℃牳閫氳繃"锛屽垯涓嶅彲缂栬緫鍜屽垹闄�
-  return status === "宸插彂璐�" || status === "瀹℃牳閫氳繃";
-};
+  };
+  /** 鍒ゆ柇鍗曚釜浜у搧鏄惁宸插彂璐э紙鏍规嵁shippingStatus鍒ゆ柇锛屽凡鍙戣揣鎴栧鏍搁�氳繃涓嶅彲缂栬緫鍜屽垹闄わ級 */
+  const isProductShipped = product => {
+    if (!product) return false;
+    const status = String(product.shippingStatus || "").trim();
+    // 濡傛灉鍙戣揣鐘舵�佹槸"宸插彂璐�"鎴�"瀹℃牳閫氳繃"锛屽垯涓嶅彲缂栬緫鍜屽垹闄�
+    return status === "宸插彂璐�" || status === "瀹℃牳閫氳繃";
+  };
 
-/** 鍒ゆ柇閿�鍞鍗曚笅鏄惁瀛樺湪宸插彂璐�/鍙戣揣瀹屾垚鐨勪骇鍝侊紙涓嶅彲鍒犻櫎锛� */
-const hasShippedProducts = products => {
-  if (!products || !products.length) return false;
-  return products.some(p => {
-    const status = String(p.shippingStatus || "").trim();
-    // 鏈夊彂璐ф棩鏈熸垨杞︾墝鍙疯涓哄凡鍙戣揣
-    if (p.shippingDate || p.shippingCarNumber) return true;
-    // 宸茶繘琛屽彂璐с�佸彂璐у畬鎴愩�佸凡鍙戣揣 鍧囦笉鍙垹闄�
-    return (
+  /** 鍒ゆ柇閿�鍞鍗曚笅鏄惁瀛樺湪宸插彂璐�/鍙戣揣瀹屾垚鐨勪骇鍝侊紙涓嶅彲鍒犻櫎锛� */
+  const hasShippedProducts = products => {
+    if (!products || !products.length) return false;
+    return products.some(p => {
+      const status = String(p.shippingStatus || "").trim();
+      // 鏈夊彂璐ф棩鏈熸垨杞︾墝鍙疯涓哄凡鍙戣揣
+      if (p.shippingDate || p.shippingCarNumber) return true;
+      // 宸茶繘琛屽彂璐с�佸彂璐у畬鎴愩�佸凡鍙戣揣 鍧囦笉鍙垹闄�
+      return (
         status === "宸茶繘琛屽彂璐�" || status === "鍙戣揣瀹屾垚" || status === "宸插彂璐�"
-    );
-  });
-};
+      );
+    });
+  };
 
-// 鍒犻櫎
-const handleDelete = async () => {
-  if (selectedRows.value.length === 0) {
-    proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
-    return;
-  }
-  const unauthorizedRows = selectedRows.value.filter(
+  // 鍒犻櫎
+  const handleDelete = async () => {
+    if (selectedRows.value.length === 0) {
+      proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
+      return;
+    }
+    const unauthorizedRows = selectedRows.value.filter(
       row => !canDeleteLedger(row)
-  );
-  if (unauthorizedRows.length > 0) {
-    proxy.$modal.msgWarning("褰撳墠鐧诲綍鐢ㄦ埛涓嶆槸褰曞叆浜猴紝涓嶈兘鍒犻櫎璇ユ暟鎹�");
-    return;
-  }
-  const ids = selectedRows.value.map(item => item.id);
+    );
+    if (unauthorizedRows.length > 0) {
+      proxy.$modal.msgWarning("褰撳墠鐧诲綍鐢ㄦ埛涓嶆槸褰曞叆浜猴紝涓嶈兘鍒犻櫎璇ユ暟鎹�");
+      return;
+    }
+    const ids = selectedRows.value.map(item => item.id);
 
-  // 妫�鏌ユ槸鍚︽湁宸茶繘琛屽彂璐ф垨鍙戣揣瀹屾垚鐨勯攢鍞鍗曪紝鑻ユ湁鍒欎笉鍏佽鍒犻櫎
-  const cannotDeleteNames = [];
-  for (const row of selectedRows.value) {
-    let products =
+    // 妫�鏌ユ槸鍚︽湁宸茶繘琛屽彂璐ф垨鍙戣揣瀹屾垚鐨勯攢鍞鍗曪紝鑻ユ湁鍒欎笉鍏佽鍒犻櫎
+    const cannotDeleteNames = [];
+    for (const row of selectedRows.value) {
+      let products =
         row.children && row.children.length > 0 ? row.children : null;
-    if (!products) {
-      try {
-        const res = await productList({salesLedgerId: row.id, type: 1});
-        products = res.data || [];
-      } catch {
-        products = [];
+      if (!products) {
+        try {
+          const res = await productList({ salesLedgerId: row.id, type: 1 });
+          products = res.data || [];
+        } catch {
+          products = [];
+        }
+      }
+      if (hasShippedProducts(products)) {
+        cannotDeleteNames.push(row.salesContractNo || `ID:${row.id}`);
       }
     }
-    if (hasShippedProducts(products)) {
-      cannotDeleteNames.push(row.salesContractNo || `ID:${row.id}`);
-    }
-  }
-  if (cannotDeleteNames.length > 0) {
-    proxy.$modal.msgWarning(
+    if (cannotDeleteNames.length > 0) {
+      proxy.$modal.msgWarning(
         "宸茶繘琛屽彂璐ф垨鍙戣揣瀹屾垚鐨勯攢鍞鍗曚笉鑳藉垹闄わ細" + cannotDeleteNames.join("銆�")
-    );
-    return;
-  }
+      );
+      return;
+    }
 
-  ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "瀵煎嚭", {
-    confirmButtonText: "纭",
-    cancelButtonText: "鍙栨秷",
-    type: "warning",
-  })
+    ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "瀵煎嚭", {
+      confirmButtonText: "纭",
+      cancelButtonText: "鍙栨秷",
+      type: "warning",
+    })
       .then(() => {
         delLedger(ids).then(res => {
           proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
@@ -1902,985 +1927,996 @@
       .catch(() => {
         proxy.$modal.msg("宸插彇娑�");
       });
-};
-
-// 鎵撳嵃鍔熻兘
-const handlePrint = async () => {
-  if (selectedRows.value.length === 0) {
-    proxy.$modal.msgWarning("璇烽�夋嫨瑕佹墦鍗扮殑鏁版嵁");
-    return;
-  }
-
-  // 鏄剧ず鍔犺浇鐘舵��
-  proxy.$modal.loading("姝e湪鑾峰彇浜у搧鏁版嵁锛岃绋嶅��...");
-
-  try {
-    // 涓烘瘡涓�変腑鐨勯攢鍞彴璐﹁褰曟煡璇㈠搴旂殑浜у搧鏁版嵁
-    const printDataWithProducts = [];
-
-    for (const row of selectedRows.value) {
-      try {
-        // 璋冪敤productList鎺ュ彛鏌ヨ浜у搧鏁版嵁
-        const productRes = await productList({
-          salesLedgerId: row.id,
-          type: 1,
-        });
-
-        // 灏嗕骇鍝佹暟鎹暣鍚堝埌閿�鍞彴璐﹁褰曚腑
-        const rowWithProducts = {
-          ...row,
-          products: productRes.data || [],
-        };
-
-        printDataWithProducts.push(rowWithProducts);
-      } catch (error) {
-        console.error(`鑾峰彇閿�鍞彴璐� ${row.id} 鐨勪骇鍝佹暟鎹け璐�:`, error);
-        // 鍗充娇鏌愪釜璁板綍鐨勪骇鍝佹暟鎹幏鍙栧け璐ワ紝涔熻鍖呭惈璇ヨ褰�
-        printDataWithProducts.push({
-          ...row,
-          products: [],
-        });
-      }
-    }
-
-    printData.value = printDataWithProducts;
-    console.log("鎵撳嵃鏁版嵁锛堝寘鍚骇鍝侊級:", printData.value);
-    printPreviewVisible.value = true;
-  } catch (error) {
-    console.error("鑾峰彇浜у搧鏁版嵁澶辫触:", error);
-    proxy.$modal.msgError("鑾峰彇浜у搧鏁版嵁澶辫触锛岃閲嶈瘯");
-  } finally {
-    proxy.$modal.closeLoading();
-  }
-};
-// 鎵ц鎵撳嵃
-const executePrint = () => {
-  console.log("寮�濮嬫墽琛屾墦鍗帮紝鏁版嵁鏉℃暟:", printData.value.length);
-  console.log("鎵撳嵃鏁版嵁:", printData.value);
-
-  // 鍒涘缓涓�涓柊鐨勬墦鍗扮獥鍙�
-  const printWindow = window.open("", "_blank", "width=800,height=600");
-
-  // 鏋勫缓鎵撳嵃鍐呭
-  let printContent = `
-                                                    <!DOCTYPE html>
-                                                    <html>
-                                                    <head>
-                                                      <meta charset="UTF-8">
-                                                      <title>鎵撳嵃棰勮</title>
-                                                      <style>
-                                                        body {
-                                                          margin: 0;
-                                                          padding: 0;
-                                                          font-family: "SimSun", serif;
-                                                          background: white;
-                                                        }
-                                                                                                     .print-page {
-                                                            width: 200mm;
-                                                            height: 75mm;
-                                                            padding: 10mm;
-                                                            padding-left: 20mm;
-                                                            background: white;
-                                                            box-sizing: border-box;
-                                                            page-break-after: always;
-                                                            page-break-inside: avoid;
-                                                          }
-                                                         .print-page:last-child {
-                                                           page-break-after: avoid;
-                                                         }
-                                                        .delivery-note {
-                                                          width: 100%;
-                                                          height: 100%;
-                                                          font-size: 12px;
-                                                          line-height: 1.2;
-                                                          display: flex;
-                                                          flex-direction: column;
-                                                          color: #000;
-                                                        }
-                                                        .header {
-                                                          text-align: center;
-                                                          margin-bottom: 8px;
-                                                        }
-                                                        .company-name {
-                                                          font-size: 18px;
-                                                          font-weight: bold;
-                                                          margin-bottom: 4px;
-                                                        }
-                                                        .document-title {
-                                                          font-size: 16px;
-                                                          font-weight: bold;
-                                                        }
-                                                        .info-section {
-                                                          margin-bottom: 8px;
-                                                          display: flex;
-                                                          justify-content: space-between;
-                                                          align-items: center;
-                                                        }
-                                                        .info-row {
-                                                          line-height: 20px;
-                                                        }
-                                                        .label {
-                                                          font-weight: bold;
-                                                          width: 60px;
-                                                          font-size: 12px;
-                                                        }
-                                                        .value {
-                                                          margin-right: 20px;
-                                                          min-width: 80px;
-                                                          font-size: 12px;
-                                                        }
-                                                                 .table-section {
-                                                                 margin-bottom: 40px;
-                                                          //  flex: 0.6;
-                                                         }
-                                                        .product-table {
-                                                          width: 100%;
-                                                          border-collapse: collapse;
-                                                          border: 1px solid #000;
-                                                        }
-                                                                 .product-table th, .product-table td {
-                                                           border: 1px solid #000;
-                                                           padding: 6px;
-                                                           text-align: center;
-                                                           font-size: 12px;
-                                                           line-height: 1.4;
-                                                         }
-                                                        .product-table th {
-                                                          font-weight: bold;
-                                                        }
-                                                        .total-value {
-                                                          font-weight: bold;
-                                                        }
-                                                        .footer-section {
-                                                          margin-top: auto;
-                                                        }
-                                                        .footer-row {
-                                                          display: flex;
-                                                          margin-bottom: 3px;
-                                                          line-height: 22px;
-                                                          justify-content: space-between;
-                                                        }
-                                                        .footer-item {
-                                                          display: flex;
-                                                          margin-right: 20px;
-                                                        }
-                                                        .footer-item .label {
-                                                          font-weight: bold;
-                                                          width: 80px;
-                                                          font-size: 12px;
-                                                        }
-                                                        .footer-item .value {
-                                                          min-width: 80px;
-                                                          font-size: 12px;
-                                                        }
-                                                        .address-item .address-value {
-                                                          min-width: 200px;
-                                                        }
-                                                        @media print {
-                                                          body {
-                                                            margin: 0;
-                                                            padding: 0;
-                                                          }
-                                                                     .print-page {
-                                                             margin: 0;
-                                                             padding: 10mm;
-                                                             /* padding-left: 20mm; */
-                                                             page-break-inside: avoid;
-                                                             page-break-after: always;
-                                                           }
-                                                           .print-page:last-child {
-                                                             page-break-after: avoid;
-                                                           }
-                                                        }
-                                                      </style>
-                                                    </head>
-                                                    <body>
-                                                  `;
-
-  // 涓烘瘡鏉℃暟鎹敓鎴愭墦鍗伴〉闈�
-  printData.value.forEach((item, index) => {
-    printContent += `
-                                                      <div class="print-page">
-                                                        <div class="delivery-note">
-                                                          <div class="header">
-                                                            <div class="document-title">闆跺敭鍙戣揣鍗�</div>
-                                                          </div>
-                                                          
-                                                          <div class="info-section">
-                                                            <div class="info-row">
-                                                              <div>
-                                                                <span class="label">鍙戣揣鏃ユ湡锛�</span>
-                                                                <span class="value">${formatDate(
-        item.createTime
-    )}</span>
-                                                              </div>
-                                                              <div>
-                                                                <span class="label">瀹㈡埛鍚嶇О锛�</span>
-                                                                <span class="value">${
-        item.customerName
-    }</span>
-                                                              </div>
-                                                            </div>
-                                                            <div class="info-row">
-                                                              <span class="label">鍗曞彿锛�</span>
-                                                              <span class="value">${
-        item.salesContractNo ||
-        ""
-    }</span>
-                                                            </div>
-                                                          </div>
-
-                                                          <div class="table-section">
-                                                            <table class="product-table">
-                                                              <thead>
-                                                                <tr>
-                                                                  <th>浜у搧鍚嶇О</th>
-                                                                  <th>瑙勬牸鍨嬪彿</th>
-                                                                  <th>鍗曚綅</th>
-                                                                  <th>鍗曚环</th>
-                                                                  <th>闆跺敭鏁伴噺</th>
-                                                                  <th>闆跺敭閲戦</th>
-                                                                </tr>
-                                                              </thead>
-                                                              <tbody>
-                                                                ${
-        item.products &&
-        item.products
-            .length > 0
-            ? item.products
-                .map(
-                    product => `
-                                                                    <tr>
-                                                                      <td>${
-                        product.productCategory ||
-                        ""
-                    }</td>
-                                                                      <td>${
-                        product.specificationModel ||
-                        ""
-                    }</td>
-                                                                      <td>${
-                        product.unit ||
-                        ""
-                    }</td>
-                                                                      <td>${
-                        product.taxInclusiveUnitPrice ||
-                        "0"
-                    }</td>
-                                                                      <td>${
-                        product.quantity ||
-                        "0"
-                    }</td>
-                                                                      <td>${
-                        product.taxInclusiveTotalPrice ||
-                        "0"
-                    }</td>
-                                                                    </tr>
-                                                                  `
-                )
-                .join("")
-            : '<tr><td colspan="6" style="text-align: center; color: #999;">鏆傛棤浜у搧鏁版嵁</td></tr>'
-    }
-                                                              </tbody>
-                                                              <tfoot>
-                                                                <tr>
-                                                                  <td class="label">鍚堣</td>
-                                                                  <td class="total-value"></td>
-                                                                  <td class="total-value"></td>
-                                                                  <td class="total-value"></td>
-                                                                  <td class="total-value">${getTotalQuantityForPrint(
-        item.products
-    )}</td>
-                                                                  <td class="total-value">${getTotalAmountForPrint(
-        item.products
-    )}</td>
-                                                                </tr>
-                                                              </tfoot>
-                                                            </table>
-                                                          </div>
-
-                                                          <div class="footer-section">
-                                                            <div class="footer-row">
-                                                              <div class="footer-item">
-                                                                <span class="label">鏀惰揣鐢佃瘽锛�</span>
-                                                                <span class="value"></span>
-                                                              </div>
-                                                              <div class="footer-item">
-                                                                <span class="label">鏀惰揣浜猴細</span>
-                                                                <span class="value"></span>
-                                                              </div>
-                                                              <div class="footer-item address-item">
-                                                                <span class="label">鏀惰揣鍦板潃锛�</span>
-                                                                <span class="value address-value"></span>
-                                                              </div>
-                                                            </div>
-                                                            <div class="footer-row">
-                                                              <div class="footer-item">
-                                                                <span class="label">鎿嶄綔鍛橈細</span>
-                                                                <span class="value">${
-        userStore.nickName ||
-        "鎾曞紑鍓�"
-    }</span>
-                                                              </div>
-                                                              <div class="footer-item">
-                                                                <span class="label">鎵撳嵃鏃ユ湡锛�</span>
-                                                                <span class="value">${formatDateTime(
-        new Date()
-    )}</span>
-                                                              </div>
-                                                            </div>
-                                                          </div>
-                                                        </div>
-                                                      </div>
-                                                    `;
-  });
-
-  printContent += `
-                                                    </body>
-                                                    </html>
-                                                  `;
-
-  // 鍐欏叆鍐呭鍒版柊绐楀彛
-  printWindow.document.write(printContent);
-  printWindow.document.close();
-
-  // 绛夊緟鍐呭鍔犺浇瀹屾垚鍚庢墦鍗�
-  printWindow.onload = () => {
-    setTimeout(() => {
-      printWindow.print();
-      printWindow.close();
-      printPreviewVisible.value = false;
-    }, 500);
   };
-};
-// 鏍煎紡鍖栨棩鏈�
-const formatDate = dateString => {
-  if (!dateString) return getCurrentDate();
-  const date = new Date(dateString);
-  const year = date.getFullYear();
-  const month = String(date.getMonth() + 1).padStart(2, "0");
-  const day = String(date.getDate()).padStart(2, "0");
-  return `${year}/${month}/${day}`;
-};
-// 鏍煎紡鍖栨棩鏈熸椂闂�
-const formatDateTime = date => {
-  const year = date.getFullYear();
-  const month = String(date.getMonth() + 1).padStart(2, "0");
-  const day = String(date.getDate()).padStart(2, "0");
-  const hours = String(date.getHours()).padStart(2, "0");
-  const minutes = String(date.getMinutes()).padStart(2, "0");
-  const seconds = String(date.getSeconds()).padStart(2, "0");
-  return `${year}/${month}/${day} ${hours}:${minutes}:${seconds}`;
-};
-// 璁$畻浜у搧鎬绘暟閲�
-const getTotalQuantity = products => {
-  if (!products || products.length === 0) return "0";
-  const total = products.reduce((sum, product) => {
-    return sum + (parseFloat(product.quantity) || 0);
-  }, 0);
-  return total.toFixed(2);
-};
 
-// 璁$畻浜у搧鎬婚噾棰�
-const getTotalAmount = products => {
-  if (!products || products.length === 0) return "0";
-  const total = products.reduce((sum, product) => {
-    return sum + (parseFloat(product.taxInclusiveTotalPrice) || 0);
-  }, 0);
-  return total.toFixed(2);
-};
+  // 鎵撳嵃鍔熻兘
+  const handlePrint = async () => {
+    if (selectedRows.value.length === 0) {
+      proxy.$modal.msgWarning("璇烽�夋嫨瑕佹墦鍗扮殑鏁版嵁");
+      return;
+    }
 
-// 鐢ㄤ簬鎵撳嵃鐨勮绠楀嚱鏁�
-const getTotalQuantityForPrint = products => {
-  if (!products || products.length === 0) return "0";
-  const total = products.reduce((sum, product) => {
-    return sum + (parseFloat(product.quantity) || 0);
-  }, 0);
-  return total.toFixed(2);
-};
+    // 鏄剧ず鍔犺浇鐘舵��
+    proxy.$modal.loading("姝e湪鑾峰彇浜у搧鏁版嵁锛岃绋嶅��...");
 
-const getTotalAmountForPrint = products => {
-  if (!products || products.length === 0) return "0";
-  const total = products.reduce((sum, product) => {
-    return sum + (parseFloat(product.taxInclusiveTotalPrice) || 0);
-  }, 0);
-  return total.toFixed(2);
-};
+    try {
+      // 涓烘瘡涓�変腑鐨勯攢鍞彴璐﹁褰曟煡璇㈠搴旂殑浜у搧鏁版嵁
+      const printDataWithProducts = [];
 
-const mathNum = () => {
-  console.log("productForm.value", productForm.value);
-  if (!productForm.value.taxInclusiveUnitPrice) {
-    return;
-  }
-  if (!productForm.value.quantity) {
-    return;
-  }
-  // 鍚◣鎬讳环璁$畻
-  productForm.value.taxInclusiveTotalPrice =
+      for (const row of selectedRows.value) {
+        try {
+          // 璋冪敤productList鎺ュ彛鏌ヨ浜у搧鏁版嵁
+          const productRes = await productList({
+            salesLedgerId: row.id,
+            type: 1,
+          });
+
+          // 灏嗕骇鍝佹暟鎹暣鍚堝埌閿�鍞彴璐﹁褰曚腑
+          const rowWithProducts = {
+            ...row,
+            products: productRes.data || [],
+          };
+
+          printDataWithProducts.push(rowWithProducts);
+        } catch (error) {
+          console.error(`鑾峰彇閿�鍞彴璐� ${row.id} 鐨勪骇鍝佹暟鎹け璐�:`, error);
+          // 鍗充娇鏌愪釜璁板綍鐨勪骇鍝佹暟鎹幏鍙栧け璐ワ紝涔熻鍖呭惈璇ヨ褰�
+          printDataWithProducts.push({
+            ...row,
+            products: [],
+          });
+        }
+      }
+
+      printData.value = printDataWithProducts;
+      console.log("鎵撳嵃鏁版嵁锛堝寘鍚骇鍝侊級:", printData.value);
+      printPreviewVisible.value = true;
+    } catch (error) {
+      console.error("鑾峰彇浜у搧鏁版嵁澶辫触:", error);
+      proxy.$modal.msgError("鑾峰彇浜у搧鏁版嵁澶辫触锛岃閲嶈瘯");
+    } finally {
+      proxy.$modal.closeLoading();
+    }
+  };
+  // 鎵ц鎵撳嵃
+  const executePrint = () => {
+    console.log("寮�濮嬫墽琛屾墦鍗帮紝鏁版嵁鏉℃暟:", printData.value.length);
+    console.log("鎵撳嵃鏁版嵁:", printData.value);
+
+    // 鍒涘缓涓�涓柊鐨勬墦鍗扮獥鍙�
+    const printWindow = window.open("", "_blank", "width=800,height=600");
+
+    // 鏋勫缓鎵撳嵃鍐呭
+    let printContent = `
+                                                                <!DOCTYPE html>
+                                                                <html>
+                                                                <head>
+                                                                  <meta charset="UTF-8">
+                                                                  <title>鎵撳嵃棰勮</title>
+                                                                  <style>
+                                                                    body {
+                                                                      margin: 0;
+                                                                      padding: 0;
+                                                                      font-family: "SimSun", serif;
+                                                                      background: white;
+                                                                    }
+                                                                                                                 .print-page {
+                                                                        width: 200mm;
+                                                                        height: 75mm;
+                                                                        padding: 10mm;
+                                                                        padding-left: 20mm;
+                                                                        background: white;
+                                                                        box-sizing: border-box;
+                                                                        page-break-after: always;
+                                                                        page-break-inside: avoid;
+                                                                      }
+                                                                     .print-page:last-child {
+                                                                       page-break-after: avoid;
+                                                                     }
+                                                                    .delivery-note {
+                                                                      width: 100%;
+                                                                      height: 100%;
+                                                                      font-size: 12px;
+                                                                      line-height: 1.2;
+                                                                      display: flex;
+                                                                      flex-direction: column;
+                                                                      color: #000;
+                                                                    }
+                                                                    .header {
+                                                                      text-align: center;
+                                                                      margin-bottom: 8px;
+                                                                    }
+                                                                    .company-name {
+                                                                      font-size: 18px;
+                                                                      font-weight: bold;
+                                                                      margin-bottom: 4px;
+                                                                    }
+                                                                    .document-title {
+                                                                      font-size: 16px;
+                                                                      font-weight: bold;
+                                                                    }
+                                                                    .info-section {
+                                                                      margin-bottom: 8px;
+                                                                      display: flex;
+                                                                      justify-content: space-between;
+                                                                      align-items: center;
+                                                                    }
+                                                                    .info-row {
+                                                                      line-height: 20px;
+                                                                    }
+                                                                    .label {
+                                                                      font-weight: bold;
+                                                                      width: 60px;
+                                                                      font-size: 12px;
+                                                                    }
+                                                                    .value {
+                                                                      margin-right: 20px;
+                                                                      min-width: 80px;
+                                                                      font-size: 12px;
+                                                                    }
+                                                                             .table-section {
+                                                                             margin-bottom: 40px;
+                                                                      //  flex: 0.6;
+                                                                     }
+                                                                    .product-table {
+                                                                      width: 100%;
+                                                                      border-collapse: collapse;
+                                                                      border: 1px solid #000;
+                                                                    }
+                                                                             .product-table th, .product-table td {
+                                                                       border: 1px solid #000;
+                                                                       padding: 6px;
+                                                                       text-align: center;
+                                                                       font-size: 12px;
+                                                                       line-height: 1.4;
+                                                                     }
+                                                                    .product-table th {
+                                                                      font-weight: bold;
+                                                                    }
+                                                                    .total-value {
+                                                                      font-weight: bold;
+                                                                    }
+                                                                    .footer-section {
+                                                                      margin-top: auto;
+                                                                    }
+                                                                    .footer-row {
+                                                                      display: flex;
+                                                                      margin-bottom: 3px;
+                                                                      line-height: 22px;
+                                                                      justify-content: space-between;
+                                                                    }
+                                                                    .footer-item {
+                                                                      display: flex;
+                                                                      margin-right: 20px;
+                                                                    }
+                                                                    .footer-item .label {
+                                                                      font-weight: bold;
+                                                                      width: 80px;
+                                                                      font-size: 12px;
+                                                                    }
+                                                                    .footer-item .value {
+                                                                      min-width: 80px;
+                                                                      font-size: 12px;
+                                                                    }
+                                                                    .address-item .address-value {
+                                                                      min-width: 200px;
+                                                                    }
+                                                                    @media print {
+                                                                      body {
+                                                                        margin: 0;
+                                                                        padding: 0;
+                                                                      }
+                                                                                 .print-page {
+                                                                         margin: 0;
+                                                                         padding: 10mm;
+                                                                         /* padding-left: 20mm; */
+                                                                         page-break-inside: avoid;
+                                                                         page-break-after: always;
+                                                                       }
+                                                                       .print-page:last-child {
+                                                                         page-break-after: avoid;
+                                                                       }
+                                                                    }
+                                                                  </style>
+                                                                </head>
+                                                                <body>
+                                                              `;
+
+    // 涓烘瘡鏉℃暟鎹敓鎴愭墦鍗伴〉闈�
+    printData.value.forEach((item, index) => {
+      printContent += `
+                                                                  <div class="print-page">
+                                                                    <div class="delivery-note">
+                                                                      <div class="header">
+                                                                        <div class="document-title">闆跺敭鍙戣揣鍗�</div>
+                                                                      </div>
+                                                                      
+                                                                      <div class="info-section">
+                                                                        <div class="info-row">
+                                                                          <div>
+                                                                            <span class="label">鍙戣揣鏃ユ湡锛�</span>
+                                                                            <span class="value">${formatDate(
+                                                                              item.createTime
+                                                                            )}</span>
+                                                                          </div>
+                                                                          <div>
+                                                                            <span class="label">瀹㈡埛鍚嶇О锛�</span>
+                                                                            <span class="value">${
+                                                                              item.customerName
+                                                                            }</span>
+                                                                          </div>
+                                                                        </div>
+                                                                        <div class="info-row">
+                                                                          <span class="label">鍗曞彿锛�</span>
+                                                                          <span class="value">${
+                                                                            item.salesContractNo ||
+                                                                            ""
+                                                                          }</span>
+                                                                        </div>
+                                                                      </div>
+
+                                                                      <div class="table-section">
+                                                                        <table class="product-table">
+                                                                          <thead>
+                                                                            <tr>
+                                                                              <th>浜у搧鍚嶇О</th>
+                                                                              <th>瑙勬牸鍨嬪彿</th>
+                                                                              <th>鍗曚綅</th>
+                                                                              <th>鍗曚环</th>
+                                                                              <th>闆跺敭鏁伴噺</th>
+                                                                              <th>闆跺敭閲戦</th>
+                                                                            </tr>
+                                                                          </thead>
+                                                                          <tbody>
+                                                                            ${
+                                                                              item.products &&
+                                                                              item
+                                                                                .products
+                                                                                .length >
+                                                                                0
+                                                                                ? item.products
+                                                                                    .map(
+                                                                                      product => `
+                                                                                <tr>
+                                                                                  <td>${
+                                                                                    product.productCategory ||
+                                                                                    ""
+                                                                                  }</td>
+                                                                                  <td>${
+                                                                                    product.specificationModel ||
+                                                                                    ""
+                                                                                  }</td>
+                                                                                  <td>${
+                                                                                    product.unit ||
+                                                                                    ""
+                                                                                  }</td>
+                                                                                  <td>${
+                                                                                    product.taxInclusiveUnitPrice ||
+                                                                                    "0"
+                                                                                  }</td>
+                                                                                  <td>${
+                                                                                    product.quantity ||
+                                                                                    "0"
+                                                                                  }</td>
+                                                                                  <td>${
+                                                                                    product.taxInclusiveTotalPrice ||
+                                                                                    "0"
+                                                                                  }</td>
+                                                                                </tr>
+                                                                              `
+                                                                                    )
+                                                                                    .join(
+                                                                                      ""
+                                                                                    )
+                                                                                : '<tr><td colspan="6" style="text-align: center; color: #999;">鏆傛棤浜у搧鏁版嵁</td></tr>'
+                                                                            }
+                                                                          </tbody>
+                                                                          <tfoot>
+                                                                            <tr>
+                                                                              <td class="label">鍚堣</td>
+                                                                              <td class="total-value"></td>
+                                                                              <td class="total-value"></td>
+                                                                              <td class="total-value"></td>
+                                                                              <td class="total-value">${getTotalQuantityForPrint(
+                                                                                item.products
+                                                                              )}</td>
+                                                                              <td class="total-value">${getTotalAmountForPrint(
+                                                                                item.products
+                                                                              )}</td>
+                                                                            </tr>
+                                                                          </tfoot>
+                                                                        </table>
+                                                                      </div>
+
+                                                                      <div class="footer-section">
+                                                                        <div class="footer-row">
+                                                                          <div class="footer-item">
+                                                                            <span class="label">鏀惰揣鐢佃瘽锛�</span>
+                                                                            <span class="value"></span>
+                                                                          </div>
+                                                                          <div class="footer-item">
+                                                                            <span class="label">鏀惰揣浜猴細</span>
+                                                                            <span class="value"></span>
+                                                                          </div>
+                                                                          <div class="footer-item address-item">
+                                                                            <span class="label">鏀惰揣鍦板潃锛�</span>
+                                                                            <span class="value address-value"></span>
+                                                                          </div>
+                                                                        </div>
+                                                                        <div class="footer-row">
+                                                                          <div class="footer-item">
+                                                                            <span class="label">鎿嶄綔鍛橈細</span>
+                                                                            <span class="value">${
+                                                                              userStore.nickName ||
+                                                                              "鎾曞紑鍓�"
+                                                                            }</span>
+                                                                          </div>
+                                                                          <div class="footer-item">
+                                                                            <span class="label">鎵撳嵃鏃ユ湡锛�</span>
+                                                                            <span class="value">${formatDateTime(
+                                                                              new Date()
+                                                                            )}</span>
+                                                                          </div>
+                                                                        </div>
+                                                                      </div>
+                                                                    </div>
+                                                                  </div>
+                                                                `;
+    });
+
+    printContent += `
+                                                                </body>
+                                                                </html>
+                                                              `;
+
+    // 鍐欏叆鍐呭鍒版柊绐楀彛
+    printWindow.document.write(printContent);
+    printWindow.document.close();
+
+    // 绛夊緟鍐呭鍔犺浇瀹屾垚鍚庢墦鍗�
+    printWindow.onload = () => {
+      setTimeout(() => {
+        printWindow.print();
+        printWindow.close();
+        printPreviewVisible.value = false;
+      }, 500);
+    };
+  };
+  // 鏍煎紡鍖栨棩鏈�
+  const formatDate = dateString => {
+    if (!dateString) return getCurrentDate();
+    const date = new Date(dateString);
+    const year = date.getFullYear();
+    const month = String(date.getMonth() + 1).padStart(2, "0");
+    const day = String(date.getDate()).padStart(2, "0");
+    return `${year}/${month}/${day}`;
+  };
+  // 鏍煎紡鍖栨棩鏈熸椂闂�
+  const formatDateTime = date => {
+    const year = date.getFullYear();
+    const month = String(date.getMonth() + 1).padStart(2, "0");
+    const day = String(date.getDate()).padStart(2, "0");
+    const hours = String(date.getHours()).padStart(2, "0");
+    const minutes = String(date.getMinutes()).padStart(2, "0");
+    const seconds = String(date.getSeconds()).padStart(2, "0");
+    return `${year}/${month}/${day} ${hours}:${minutes}:${seconds}`;
+  };
+  // 璁$畻浜у搧鎬绘暟閲�
+  const getTotalQuantity = products => {
+    if (!products || products.length === 0) return "0";
+    const total = products.reduce((sum, product) => {
+      return sum + (parseFloat(product.quantity) || 0);
+    }, 0);
+    return total.toFixed(2);
+  };
+
+  // 璁$畻浜у搧鎬婚噾棰�
+  const getTotalAmount = products => {
+    if (!products || products.length === 0) return "0";
+    const total = products.reduce((sum, product) => {
+      return sum + (parseFloat(product.taxInclusiveTotalPrice) || 0);
+    }, 0);
+    return total.toFixed(2);
+  };
+
+  // 鐢ㄤ簬鎵撳嵃鐨勮绠楀嚱鏁�
+  const getTotalQuantityForPrint = products => {
+    if (!products || products.length === 0) return "0";
+    const total = products.reduce((sum, product) => {
+      return sum + (parseFloat(product.quantity) || 0);
+    }, 0);
+    return total.toFixed(2);
+  };
+
+  const getTotalAmountForPrint = products => {
+    if (!products || products.length === 0) return "0";
+    const total = products.reduce((sum, product) => {
+      return sum + (parseFloat(product.taxInclusiveTotalPrice) || 0);
+    }, 0);
+    return total.toFixed(2);
+  };
+
+  const mathNum = () => {
+    console.log("productForm.value", productForm.value);
+    if (!productForm.value.taxInclusiveUnitPrice) {
+      return;
+    }
+    if (!productForm.value.quantity) {
+      return;
+    }
+    // 鍚◣鎬讳环璁$畻
+    productForm.value.taxInclusiveTotalPrice =
       proxy.calculateTaxIncludeTotalPrice(
-          productForm.value.taxInclusiveUnitPrice,
-          productForm.value.quantity
+        productForm.value.taxInclusiveUnitPrice,
+        productForm.value.quantity
       );
-  if (productForm.value.taxRate) {
-    // 涓嶅惈绋庢�讳环璁$畻
-    productForm.value.taxExclusiveTotalPrice =
+    if (productForm.value.taxRate) {
+      // 涓嶅惈绋庢�讳环璁$畻
+      productForm.value.taxExclusiveTotalPrice =
         proxy.calculateTaxExclusiveTotalPrice(
-            productForm.value.taxInclusiveTotalPrice,
-            productForm.value.taxRate
+          productForm.value.taxInclusiveTotalPrice,
+          productForm.value.taxRate
         );
-  }
-};
+    }
+  };
 
-// 鏍规嵁鍚◣鎬讳环璁$畻鍚◣鍗曚环鍜屾暟閲�
-const calculateFromTotalPrice = () => {
-  if (isCalculating.value) return;
+  // 鏍规嵁鍚◣鎬讳环璁$畻鍚◣鍗曚环鍜屾暟閲�
+  const calculateFromTotalPrice = () => {
+    if (isCalculating.value) return;
 
-  const totalPrice = parseFloat(productForm.value.taxInclusiveTotalPrice);
-  const quantity = parseFloat(productForm.value.quantity);
+    const totalPrice = parseFloat(productForm.value.taxInclusiveTotalPrice);
+    const quantity = parseFloat(productForm.value.quantity);
 
-  if (!totalPrice || !quantity || quantity <= 0) {
-    return;
-  }
+    if (!totalPrice || !quantity || quantity <= 0) {
+      return;
+    }
 
-  isCalculating.value = true;
+    isCalculating.value = true;
 
-  // 璁$畻鍚◣鍗曚环 = 鍚◣鎬讳环 / 鏁伴噺
-  productForm.value.taxInclusiveUnitPrice = (totalPrice / quantity).toFixed(2);
+    // 璁$畻鍚◣鍗曚环 = 鍚◣鎬讳环 / 鏁伴噺
+    productForm.value.taxInclusiveUnitPrice = (totalPrice / quantity).toFixed(2);
 
-  // 濡傛灉鏈夌◣鐜囷紝璁$畻涓嶅惈绋庢�讳环
-  if (productForm.value.taxRate) {
-    productForm.value.taxExclusiveTotalPrice =
+    // 濡傛灉鏈夌◣鐜囷紝璁$畻涓嶅惈绋庢�讳环
+    if (productForm.value.taxRate) {
+      productForm.value.taxExclusiveTotalPrice =
         proxy.calculateTaxExclusiveTotalPrice(
-            totalPrice,
-            productForm.value.taxRate
+          totalPrice,
+          productForm.value.taxRate
         );
-  }
+    }
 
-  isCalculating.value = false;
-};
+    isCalculating.value = false;
+  };
 
-// 鏍规嵁涓嶅惈绋庢�讳环璁$畻鍚◣鍗曚环鍜屾暟閲�
-const calculateFromExclusiveTotalPrice = () => {
-  if (!productForm.value.taxRate) {
-    proxy.$modal.msgWarning("璇峰厛閫夋嫨绋庣巼");
-    return;
-  }
-  if (isCalculating.value) return;
+  // 鏍规嵁涓嶅惈绋庢�讳环璁$畻鍚◣鍗曚环鍜屾暟閲�
+  const calculateFromExclusiveTotalPrice = () => {
+    if (!productForm.value.taxRate) {
+      proxy.$modal.msgWarning("璇峰厛閫夋嫨绋庣巼");
+      return;
+    }
+    if (isCalculating.value) return;
 
-  const exclusiveTotalPrice = parseFloat(
+    const exclusiveTotalPrice = parseFloat(
       productForm.value.taxExclusiveTotalPrice
-  );
-  const quantity = parseFloat(productForm.value.quantity);
-  const taxRate = parseFloat(productForm.value.taxRate);
+    );
+    const quantity = parseFloat(productForm.value.quantity);
+    const taxRate = parseFloat(productForm.value.taxRate);
 
-  if (!exclusiveTotalPrice || !quantity || quantity <= 0 || !taxRate) {
-    return;
-  }
+    if (!exclusiveTotalPrice || !quantity || quantity <= 0 || !taxRate) {
+      return;
+    }
 
-  isCalculating.value = true;
+    isCalculating.value = true;
 
-  // 鍏堣绠楀惈绋庢�讳环 = 涓嶅惈绋庢�讳环 / (1 - 绋庣巼/100)
-  const taxRateDecimal = taxRate / 100;
-  const inclusiveTotalPrice = exclusiveTotalPrice / (1 - taxRateDecimal);
-  productForm.value.taxInclusiveTotalPrice = inclusiveTotalPrice.toFixed(2);
+    // 鍏堣绠楀惈绋庢�讳环 = 涓嶅惈绋庢�讳环 / (1 - 绋庣巼/100)
+    const taxRateDecimal = taxRate / 100;
+    const inclusiveTotalPrice = exclusiveTotalPrice / (1 - taxRateDecimal);
+    productForm.value.taxInclusiveTotalPrice = inclusiveTotalPrice.toFixed(2);
 
-  // 璁$畻鍚◣鍗曚环 = 鍚◣鎬讳环 / 鏁伴噺
-  productForm.value.taxInclusiveUnitPrice = (
+    // 璁$畻鍚◣鍗曚环 = 鍚◣鎬讳环 / 鏁伴噺
+    productForm.value.taxInclusiveUnitPrice = (
       inclusiveTotalPrice / quantity
-  ).toFixed(2);
+    ).toFixed(2);
 
-  isCalculating.value = false;
-};
+    isCalculating.value = false;
+  };
 
-// 鏍规嵁鏁伴噺鍙樺寲璁$畻鎬讳环
-const calculateFromQuantity = () => {
-  if (!productForm.value.taxRate) {
-    proxy.$modal.msgWarning("璇峰厛閫夋嫨绋庣巼");
-    return;
-  }
-  if (isCalculating.value) return;
+  // 鏍规嵁鏁伴噺鍙樺寲璁$畻鎬讳环
+  const calculateFromQuantity = () => {
+    if (!productForm.value.taxRate) {
+      proxy.$modal.msgWarning("璇峰厛閫夋嫨绋庣巼");
+      return;
+    }
+    if (isCalculating.value) return;
 
-  const quantity = parseFloat(productForm.value.quantity);
-  const unitPrice = parseFloat(productForm.value.taxInclusiveUnitPrice);
+    const quantity = parseFloat(productForm.value.quantity);
+    const unitPrice = parseFloat(productForm.value.taxInclusiveUnitPrice);
 
-  if (!quantity || quantity <= 0 || !unitPrice) {
-    return;
-  }
+    if (!quantity || quantity <= 0 || !unitPrice) {
+      return;
+    }
 
-  isCalculating.value = true;
+    isCalculating.value = true;
 
-  // 璁$畻鍚◣鎬讳环
-  productForm.value.taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(2);
+    // 璁$畻鍚◣鎬讳环
+    productForm.value.taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(2);
 
-  // 濡傛灉鏈夌◣鐜囷紝璁$畻涓嶅惈绋庢�讳环
-  if (productForm.value.taxRate) {
-    productForm.value.taxExclusiveTotalPrice =
+    // 濡傛灉鏈夌◣鐜囷紝璁$畻涓嶅惈绋庢�讳环
+    if (productForm.value.taxRate) {
+      productForm.value.taxExclusiveTotalPrice =
         proxy.calculateTaxExclusiveTotalPrice(
-            productForm.value.taxInclusiveTotalPrice,
-            productForm.value.taxRate
+          productForm.value.taxInclusiveTotalPrice,
+          productForm.value.taxRate
         );
-  }
+    }
 
-  isCalculating.value = false;
-};
+    isCalculating.value = false;
+  };
 
-// 鏍规嵁鍚◣鍗曚环鍙樺寲璁$畻鎬讳环
-const calculateFromUnitPrice = () => {
-  if (!productForm.value.taxRate) {
-    proxy.$modal.msgWarning("璇峰厛閫夋嫨绋庣巼");
-    return;
-  }
-  if (isCalculating.value) return;
+  // 鏍规嵁鍚◣鍗曚环鍙樺寲璁$畻鎬讳环
+  const calculateFromUnitPrice = () => {
+    if (!productForm.value.taxRate) {
+      proxy.$modal.msgWarning("璇峰厛閫夋嫨绋庣巼");
+      return;
+    }
+    if (isCalculating.value) return;
 
-  const quantity = parseFloat(productForm.value.quantity);
-  const unitPrice = parseFloat(productForm.value.taxInclusiveUnitPrice);
+    const quantity = parseFloat(productForm.value.quantity);
+    const unitPrice = parseFloat(productForm.value.taxInclusiveUnitPrice);
 
-  if (!quantity || quantity <= 0 || !unitPrice) {
-    return;
-  }
+    if (!quantity || quantity <= 0 || !unitPrice) {
+      return;
+    }
 
-  isCalculating.value = true;
+    isCalculating.value = true;
 
-  // 璁$畻鍚◣鎬讳环
-  productForm.value.taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(2);
+    // 璁$畻鍚◣鎬讳环
+    productForm.value.taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(2);
 
-  // 濡傛灉鏈夌◣鐜囷紝璁$畻涓嶅惈绋庢�讳环
-  if (productForm.value.taxRate) {
-    productForm.value.taxExclusiveTotalPrice =
+    // 濡傛灉鏈夌◣鐜囷紝璁$畻涓嶅惈绋庢�讳环
+    if (productForm.value.taxRate) {
+      productForm.value.taxExclusiveTotalPrice =
         proxy.calculateTaxExclusiveTotalPrice(
-            productForm.value.taxInclusiveTotalPrice,
-            productForm.value.taxRate
+          productForm.value.taxInclusiveTotalPrice,
+          productForm.value.taxRate
         );
-  }
+    }
 
-  isCalculating.value = false;
-};
+    isCalculating.value = false;
+  };
 
-// 鏍规嵁绋庣巼鍙樺寲璁$畻涓嶅惈绋庢�讳环
-const calculateFromTaxRate = () => {
-  if (!productForm.value.taxRate) {
-    proxy.$modal.msgWarning("璇峰厛閫夋嫨绋庣巼");
-    return;
-  }
-  if (isCalculating.value) return;
+  // 鏍规嵁绋庣巼鍙樺寲璁$畻涓嶅惈绋庢�讳环
+  const calculateFromTaxRate = () => {
+    if (!productForm.value.taxRate) {
+      proxy.$modal.msgWarning("璇峰厛閫夋嫨绋庣巼");
+      return;
+    }
+    if (isCalculating.value) return;
 
-  const inclusiveTotalPrice = parseFloat(
+    const inclusiveTotalPrice = parseFloat(
       productForm.value.taxInclusiveTotalPrice
-  );
-  const taxRate = parseFloat(productForm.value.taxRate);
+    );
+    const taxRate = parseFloat(productForm.value.taxRate);
 
-  if (!inclusiveTotalPrice || !taxRate) {
-    return;
-  }
+    if (!inclusiveTotalPrice || !taxRate) {
+      return;
+    }
 
-  isCalculating.value = true;
+    isCalculating.value = true;
 
-  // 璁$畻涓嶅惈绋庢�讳环
-  productForm.value.taxExclusiveTotalPrice =
+    // 璁$畻涓嶅惈绋庢�讳环
+    productForm.value.taxExclusiveTotalPrice =
       proxy.calculateTaxExclusiveTotalPrice(inclusiveTotalPrice, taxRate);
 
-  isCalculating.value = false;
-};
-/**
- * 鑾峰彇鍙戣揣鐘舵�佹枃鏈�
- * @param row 琛屾暟鎹�
- */
-const getShippingStatusText = row => {
-  // 濡傛灉宸插彂璐э紙鏈夊彂璐ф棩鏈熸垨杞︾墝鍙凤級锛屾樉绀�"宸插彂璐�"
-  // if (row.shippingDate || row.shippingCarNumber) {
-  //   return "宸插彂璐�";
-  // }
-
-  // 鑾峰彇鍙戣揣鐘舵�佸瓧娈�
-  const status = row.shippingStatus;
-
-  // 濡傛灉鐘舵�佷负绌烘垨鏈畾涔夛紝榛樿涓�"寰呭彂璐�"
-  if (status === null || status === undefined || status === "") {
-    return "寰呭彂璐�";
-  }
-
-  // 鐘舵�佹槸瀛楃涓�
-  const statusStr = String(status).trim();
-  const statusTextMap = {
-    寰呭彂璐�: "寰呭彂璐�",
-    寰呭鏍�: "寰呭鏍�",
-    瀹℃牳涓�: "瀹℃牳涓�",
-    瀹℃牳鎷掔粷: "瀹℃牳鎷掔粷",
-    瀹℃牳閫氳繃: "瀹℃牳閫氳繃",
-    宸插彂璐�: "宸插彂璐�",
+    isCalculating.value = false;
   };
-  return statusTextMap[statusStr] || "寰呭彂璐�";
-};
+  /**
+   * 鑾峰彇鍙戣揣鐘舵�佹枃鏈�
+   * @param row 琛屾暟鎹�
+   */
+  const getShippingStatusText = row => {
+    // 濡傛灉宸插彂璐э紙鏈夊彂璐ф棩鏈熸垨杞︾墝鍙凤級锛屾樉绀�"宸插彂璐�"
+    // if (row.shippingDate || row.shippingCarNumber) {
+    //   return "宸插彂璐�";
+    // }
 
-/**
- * 鑾峰彇鍙戣揣鐘舵�佹爣绛剧被鍨嬶紙棰滆壊锛�
- * @param row 琛屾暟鎹�
- */
-const getShippingStatusType = row => {
-  // 濡傛灉宸插彂璐э紙鏈夊彂璐ф棩鏈熸垨杞︾墝鍙凤級锛屾樉绀虹豢鑹�
-  if (row.shippingStatus === "宸插彂璐�") {
-    return "success";
-  }
+    // 鑾峰彇鍙戣揣鐘舵�佸瓧娈�
+    const status = row.shippingStatus;
 
-  // 鑾峰彇鍙戣揣鐘舵�佸瓧娈�
-  const status = row.shippingStatus;
+    // 濡傛灉鐘舵�佷负绌烘垨鏈畾涔夛紝榛樿涓�"寰呭彂璐�"
+    if (status === null || status === undefined || status === "") {
+      return "寰呭彂璐�";
+    }
 
-  // 濡傛灉鐘舵�佷负绌烘垨鏈畾涔夛紝榛樿涓虹伆鑹诧紙寰呭彂璐э級
-  if (status === null || status === undefined || status === "") {
-    return "info";
-  }
-
-  // 鐘舵�佹槸瀛楃涓�
-  const statusStr = String(status).trim();
-  const typeTextMap = {
-    寰呭彂璐�: "info",
-    寰呭鏍�: "info",
-    瀹℃牳涓�: "warning",
-    瀹℃牳鎷掔粷: "danger",
-    瀹℃牳閫氳繃: "success",
-    宸插彂璐�: "success",
+    // 鐘舵�佹槸瀛楃涓�
+    const statusStr = String(status).trim();
+    const statusTextMap = {
+      寰呭彂璐�: "寰呭彂璐�",
+      寰呭鏍�: "寰呭鏍�",
+      瀹℃牳涓�: "瀹℃牳涓�",
+      瀹℃牳鎷掔粷: "瀹℃牳鎷掔粷",
+      瀹℃牳閫氳繃: "瀹℃牳閫氳繃",
+      宸插彂璐�: "宸插彂璐�",
+    };
+    return statusTextMap[statusStr] || "寰呭彂璐�";
   };
-  return typeTextMap[statusStr] || "info";
-};
 
-/**
- * 鍒ゆ柇鏄惁鍙互鍙戣揣
- * 鍙湁鍦ㄤ骇鍝佺姸鎬佹槸鍏呰冻锛屽彂璐х姸鎬佹槸寰呭彂璐у拰瀹℃牳鎷掔粷鐨勬椂鍊欐墠鍙互鍙戣揣
- * @param row 琛屾暟鎹�
- */
-const canShip = row => {
-  // 浜у搧鐘舵�佸繀椤绘槸鍏呰冻锛坅pproveStatus === 1锛�
-  if (row.approveStatus !== 1) {
-    return false;
-  }
+  /**
+   * 鑾峰彇鍙戣揣鐘舵�佹爣绛剧被鍨嬶紙棰滆壊锛�
+   * @param row 琛屾暟鎹�
+   */
+  const getShippingStatusType = row => {
+    // 濡傛灉宸插彂璐э紙鏈夊彂璐ф棩鏈熸垨杞︾墝鍙凤級锛屾樉绀虹豢鑹�
+    if (row.shippingStatus === "宸插彂璐�") {
+      return "success";
+    }
 
-  // 鑾峰彇鍙戣揣鐘舵��
-  const shippingStatus = row.shippingStatus;
+    // 鑾峰彇鍙戣揣鐘舵�佸瓧娈�
+    const status = row.shippingStatus;
 
-  // 濡傛灉宸插彂璐э紙鏈夊彂璐ф棩鏈熸垨杞︾墝鍙凤級锛屼笉鑳藉啀娆″彂璐�
-  if (shippingStatus === "宸插彂璐�") {
-    return false;
-  }
+    // 濡傛灉鐘舵�佷负绌烘垨鏈畾涔夛紝榛樿涓虹伆鑹诧紙寰呭彂璐э級
+    if (status === null || status === undefined || status === "") {
+      return "info";
+    }
 
-  // 鍙戣揣鐘舵�佸繀椤绘槸"寰呭彂璐�"鎴�"瀹℃牳鎷掔粷"
-  const statusStr = shippingStatus ? String(shippingStatus).trim() : "";
-  return statusStr === "寰呭彂璐�" || statusStr === "瀹℃牳鎷掔粷";
-};
+    // 鐘舵�佹槸瀛楃涓�
+    const statusStr = String(status).trim();
+    const typeTextMap = {
+      寰呭彂璐�: "info",
+      寰呭鏍�: "info",
+      瀹℃牳涓�: "warning",
+      瀹℃牳鎷掔粷: "danger",
+      瀹℃牳閫氳繃: "success",
+      宸插彂璐�: "success",
+    };
+    return typeTextMap[statusStr] || "info";
+  };
 
-// 鎵撳紑闄勪欢寮圭獥
-const recordId = ref(0)
-const fileDialogVisible = ref(false)
+  /**
+   * 鍒ゆ柇鏄惁鍙互鍙戣揣
+   * 鍙湁鍦ㄤ骇鍝佺姸鎬佹槸鍏呰冻锛屽彂璐х姸鎬佹槸寰呭彂璐у拰瀹℃牳鎷掔粷鐨勬椂鍊欐墠鍙互鍙戣揣
+   * @param row 琛屾暟鎹�
+   */
+  const canShip = row => {
+    // 浜у搧鐘舵�佸繀椤绘槸鍏呰冻锛坅pproveStatus === 1锛�
+    if (row.approveStatus !== 1) {
+      return false;
+    }
 
-// 鎵撳紑闄勪欢寮规
-const openFileDialog = async (row) => {
-  recordId.value = row.id
-  fileDialogVisible.value = true
-}
+    // 鑾峰彇鍙戣揣鐘舵��
+    const shippingStatus = row.shippingStatus;
 
-// 鎵撳紑鍙戣揣寮规
-const openDeliveryForm = async row => {
-  // 妫�鏌ユ槸鍚﹀彲浠ュ彂璐�
-  if (!canShip(row)) {
-    proxy.$modal.msgWarning(
+    // 濡傛灉宸插彂璐э紙鏈夊彂璐ф棩鏈熸垨杞︾墝鍙凤級锛屼笉鑳藉啀娆″彂璐�
+    if (shippingStatus === "宸插彂璐�") {
+      return false;
+    }
+
+    // 鍙戣揣鐘舵�佸繀椤绘槸"寰呭彂璐�"鎴�"瀹℃牳鎷掔粷"
+    const statusStr = shippingStatus ? String(shippingStatus).trim() : "";
+    return statusStr === "寰呭彂璐�" || statusStr === "瀹℃牳鎷掔粷";
+  };
+
+  // 鎵撳紑闄勪欢寮圭獥
+  const recordId = ref(0);
+  const fileDialogVisible = ref(false);
+
+  // 鎵撳紑闄勪欢寮规
+  const openFileDialog = async row => {
+    recordId.value = row.id;
+    fileDialogVisible.value = true;
+  };
+
+  // 鎵撳紑鍙戣揣寮规
+  const openDeliveryForm = async row => {
+    // 妫�鏌ユ槸鍚﹀彲浠ュ彂璐�
+    if (!canShip(row)) {
+      proxy.$modal.msgWarning(
         "鍙湁鍦ㄤ骇鍝佺姸鎬佹槸鍏呰冻锛屽彂璐х姸鎬佹槸寰呭彂璐ф垨瀹℃牳鎷掔粷鐨勬椂鍊欐墠鍙互鍙戣揣"
-    );
-    return;
-  }
+      );
+      return;
+    }
 
-  currentDeliveryRow.value = row;
-  const batchNoList = await getDeliveryBatchNoList(
+    currentDeliveryRow.value = row;
+    const batchNoList = await getDeliveryBatchNoList(
       row.productModelId || row.modelId
-  );
-  deliveryForm.value = {
-    type: "璐ц溅",
-    batchNo: [],
-    batchNoList,
+    );
+    deliveryForm.value = {
+      type: "璐ц溅",
+      batchNo: [],
+      batchNoList,
+    };
+    deliveryFormVisible.value = true;
   };
-  deliveryFormVisible.value = true;
-};
 
-// 鎻愪氦鍙戣揣琛ㄥ崟
-const submitDelivery = () => {
-  proxy.$refs["deliveryFormRef"].validate(valid => {
-    if (valid) {
-      const selectedBatchRows = getSelectedDeliveryBatchRows();
-      if (selectedBatchRows.length === 0) {
-        proxy.$modal.msgWarning("璇疯嚦灏戝~鍐欎竴涓壒鍙风殑鍙戣揣鏁伴噺");
-        return;
-      }
-      const totalDeliveryQuantity = selectedBatchRows.reduce(
+  // 鎻愪氦鍙戣揣琛ㄥ崟
+  const submitDelivery = () => {
+    proxy.$refs["deliveryFormRef"].validate(valid => {
+      if (valid) {
+        const selectedBatchRows = getSelectedDeliveryBatchRows();
+        if (selectedBatchRows.length === 0) {
+          proxy.$modal.msgWarning("璇疯嚦灏戝~鍐欎竴涓壒鍙风殑鍙戣揣鏁伴噺");
+          return;
+        }
+        const totalDeliveryQuantity = selectedBatchRows.reduce(
           (sum, item) => sum + Number(item.deliveryQuantity || 0),
           0
-      );
-      const currentRowQuantity = Number(currentDeliveryRow.value?.quantity || 0);
-      if (currentRowQuantity > 0 && totalDeliveryQuantity > currentRowQuantity) {
-        proxy.$modal.msgWarning("鎵瑰彿鍙戣揣鎬绘暟涓嶈兘瓒呰繃褰撳墠浜у搧鏁伴噺");
-        return;
-      }
-      // 淇濆瓨褰撳墠灞曞紑鐨勮ID锛屼互渚垮彂璐у悗閲嶆柊鍔犺浇瀛愯〃鏍兼暟鎹�
-      const currentExpandedKeys = [...expandedRowKeys.value];
-      const salesLedgerId = currentDeliveryRow.value.salesLedgerId;
-      deliveryForm.value.batchNo = selectedBatchRows.map(item => item.id);
-      const productModelId = currentDeliveryRow.value.productModelId || currentDeliveryRow.value.modelId;
-      addShippingInfo({
-        salesLedgerId: salesLedgerId,
-        salesLedgerProductId: currentDeliveryRow.value.id,
-        type: deliveryForm.value.type,
-        batchNo: deliveryForm.value.batchNo,
-        batchNoDetailList: selectedBatchRows.map(item => ({
-          stockInventoryId: item.id,
-          batchNo: item.batchNo,
-          quantity: Number(item.deliveryQuantity || 0),
-          productModelId: productModelId,
-        })),
-      }).then(() => {
-        proxy.$modal.msgSuccess("鍙戣揣鎴愬姛");
-        closeDeliveryDia();
-        // 鍒锋柊涓昏〃鏁版嵁
-        getList().then(() => {
-          // 濡傛灉涔嬪墠鏈夊睍寮�鐨勮锛岄噸鏂板姞杞借繖浜涜鐨勫瓙琛ㄦ牸鏁版嵁
-          if (currentExpandedKeys.length > 0) {
-            // 浣跨敤 Promise.all 骞惰鍔犺浇鎵�鏈夊睍寮�琛岀殑瀛愯〃鏍兼暟鎹�
-            const loadPromises = currentExpandedKeys.map(ledgerId => {
-              return productList({salesLedgerId: ledgerId, type: 1}).then(
+        );
+        const currentRowNoQuantity = Number(
+          currentDeliveryRow.value?.noQuantity || 0
+        );
+        if (
+          currentRowNoQuantity > 0 &&
+          totalDeliveryQuantity > currentRowNoQuantity
+        ) {
+          proxy.$modal.msgWarning("鎵瑰彿鍙戣揣鎬绘暟涓嶈兘瓒呰繃寰呭彂璐ф暟閲�");
+          return;
+        }
+        // 淇濆瓨褰撳墠灞曞紑鐨勮ID锛屼互渚垮彂璐у悗閲嶆柊鍔犺浇瀛愯〃鏍兼暟鎹�
+        const currentExpandedKeys = [...expandedRowKeys.value];
+        const salesLedgerId = currentDeliveryRow.value.salesLedgerId;
+        deliveryForm.value.batchNo = selectedBatchRows.map(item => item.id);
+        const productModelId =
+          currentDeliveryRow.value.productModelId ||
+          currentDeliveryRow.value.modelId;
+        addShippingInfo({
+          salesLedgerId: salesLedgerId,
+          salesLedgerProductId: currentDeliveryRow.value.id,
+          type: deliveryForm.value.type,
+          batchNo: deliveryForm.value.batchNo,
+          batchNoDetailList: selectedBatchRows.map(item => ({
+            stockInventoryId: item.id,
+            batchNo: item.batchNo,
+            quantity: Number(item.deliveryQuantity || 0),
+            productModelId: productModelId,
+          })),
+        }).then(() => {
+          proxy.$modal.msgSuccess("鍙戣揣鎴愬姛");
+          closeDeliveryDia();
+          // 鍒锋柊涓昏〃鏁版嵁
+          getList().then(() => {
+            // 濡傛灉涔嬪墠鏈夊睍寮�鐨勮锛岄噸鏂板姞杞借繖浜涜鐨勫瓙琛ㄦ牸鏁版嵁
+            if (currentExpandedKeys.length > 0) {
+              // 浣跨敤 Promise.all 骞惰鍔犺浇鎵�鏈夊睍寮�琛岀殑瀛愯〃鏍兼暟鎹�
+              const loadPromises = currentExpandedKeys.map(ledgerId => {
+                return productList({ salesLedgerId: ledgerId, type: 1 }).then(
                   res => {
                     const index = tableData.value.findIndex(
-                        item => item.id === ledgerId
+                      item => item.id === ledgerId
                     );
                     if (index > -1) {
                       tableData.value[index].children = res.data;
                     }
                   }
-              );
-            });
-            Promise.all(loadPromises).then(() => {
-              // 鎭㈠灞曞紑鐘舵��
-              expandedRowKeys.value = currentExpandedKeys;
-            });
-          }
+                );
+              });
+              Promise.all(loadPromises).then(() => {
+                // 鎭㈠灞曞紑鐘舵��
+                expandedRowKeys.value = currentExpandedKeys;
+              });
+            }
+          });
         });
-      });
-    }
-  });
-};
+      }
+    });
+  };
 
-// 鍏抽棴鍙戣揣寮规
-const closeDeliveryDia = () => {
-  proxy.resetForm("deliveryFormRef");
-  deliveryFormVisible.value = false;
-  currentDeliveryRow.value = null;
-};
-const currentFactoryName = ref("");
-const getCurrentFactoryName = async () => {
-  let res = await userStore.getInfo();
-  currentFactoryName.value = res.user.currentFactoryName;
-};
-onMounted(() => {
-  searchForm.salesContractNo = route.query.salesContractNo;
-  getList();
-  userListNoPage().then(res => {
-    userList.value = res.data;
+  // 鍏抽棴鍙戣揣寮规
+  const closeDeliveryDia = () => {
+    proxy.resetForm("deliveryFormRef");
+    deliveryFormVisible.value = false;
+    currentDeliveryRow.value = null;
+  };
+  const currentFactoryName = ref("");
+  const getCurrentFactoryName = async () => {
+    let res = await userStore.getInfo();
+    currentFactoryName.value = res.user.currentFactoryName;
+  };
+  onMounted(() => {
+    searchForm.salesContractNo = route.query.salesContractNo;
+    getList();
+    userListNoPage().then(res => {
+      userList.value = res.data;
+    });
+    getCurrentFactoryName();
   });
-  getCurrentFactoryName();
-});
 </script>
 
 <style scoped lang="scss">
-.ml-10 {
-  margin-left: 10px;
-}
-
-:deep(.yellow) {
-  background-color: #faf0de;
-}
-
-:deep(.pink) {
-  background-color: #fae1de;
-}
-
-:deep(.red) {
-  background-color: #fae1de;
-}
-
-:deep(.purple) {
-  background-color: #f4defa;
-}
-
-.table_list {
-  margin-top: unset;
-}
-
-.actions {
-  display: flex;
-  justify-content: space-between;
-  margin-bottom: 10px;
-}
-
-.print-preview-dialog {
-  .el-dialog__body {
-    padding: 0;
-    max-height: 80vh;
-    overflow-y: auto;
-  }
-}
-
-.print-preview-container {
-  .print-preview-header {
-    padding: 15px;
-    border-bottom: 1px solid #e4e7ed;
-    text-align: center;
-
-    .el-button {
-      margin: 0 10px;
-    }
+  .ml-10 {
+    margin-left: 10px;
   }
 
-  .print-preview-content {
-    padding: 20px;
-    background-color: #f5f5f5;
-    min-height: 400px;
-  }
-}
-
-.print-page {
-  width: 220mm;
-  height: 90mm;
-  padding: 10mm;
-  margin: 0 auto;
-  background: white;
-  box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
-  margin-bottom: 10px;
-  box-sizing: border-box;
-}
-
-.delivery-note {
-  width: 100%;
-  height: 100%;
-  font-family: "SimSun", serif;
-  font-size: 10px;
-  line-height: 1.2;
-  display: flex;
-  flex-direction: column;
-}
-
-.header {
-  text-align: center;
-  margin-bottom: 8px;
-
-  .company-name {
-    font-size: 18px;
-    font-weight: bold;
-    margin-bottom: 4px;
+  :deep(.yellow) {
+    background-color: #faf0de;
   }
 
-  .document-title {
-    font-size: 16px;
-    font-weight: bold;
+  :deep(.pink) {
+    background-color: #fae1de;
   }
-}
 
-.info-section {
-  margin-bottom: 8px;
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-
-  .info-row {
-    line-height: 20px;
-
-    .label {
-      font-weight: bold;
-      width: 60px;
-      font-size: 14px;
-    }
-
-    .value {
-      margin-right: 20px;
-      min-width: 80px;
-      font-size: 14px;
-    }
+  :deep(.red) {
+    background-color: #fae1de;
   }
-}
 
-.table-section {
-  margin-bottom: 4px;
-  flex: 1;
-
-  .product-table {
-    width: 100%;
-    border-collapse: collapse;
-    border: 1px solid #000;
-
-    th,
-    td {
-      border: 1px solid #000;
-      padding: 6px;
-      text-align: center;
-      font-size: 14px;
-      line-height: 1.4;
-    }
-
-    th {
-      font-weight: bold;
-    }
-
-    .total-label {
-      text-align: right;
-      font-weight: bold;
-    }
-
-    .total-value {
-      font-weight: bold;
-    }
+  :deep(.purple) {
+    background-color: #f4defa;
   }
-}
 
-.footer-section {
-  .footer-row {
+  .table_list {
+    margin-top: unset;
+  }
+
+  .actions {
     display: flex;
-    margin-bottom: 3px;
-    line-height: 20px;
     justify-content: space-between;
+    margin-bottom: 10px;
+  }
 
-    .footer-item {
-      display: flex;
-      margin-right: 20px;
+  .print-preview-dialog {
+    .el-dialog__body {
+      padding: 0;
+      max-height: 80vh;
+      overflow-y: auto;
+    }
+  }
+
+  .print-preview-container {
+    .print-preview-header {
+      padding: 15px;
+      border-bottom: 1px solid #e4e7ed;
+      text-align: center;
+
+      .el-button {
+        margin: 0 10px;
+      }
+    }
+
+    .print-preview-content {
+      padding: 20px;
+      background-color: #f5f5f5;
+      min-height: 400px;
+    }
+  }
+
+  .print-page {
+    width: 220mm;
+    height: 90mm;
+    padding: 10mm;
+    margin: 0 auto;
+    background: white;
+    box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
+    margin-bottom: 10px;
+    box-sizing: border-box;
+  }
+
+  .delivery-note {
+    width: 100%;
+    height: 100%;
+    font-family: "SimSun", serif;
+    font-size: 10px;
+    line-height: 1.2;
+    display: flex;
+    flex-direction: column;
+  }
+
+  .header {
+    text-align: center;
+    margin-bottom: 8px;
+
+    .company-name {
+      font-size: 18px;
+      font-weight: bold;
+      margin-bottom: 4px;
+    }
+
+    .document-title {
+      font-size: 16px;
+      font-weight: bold;
+    }
+  }
+
+  .info-section {
+    margin-bottom: 8px;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+
+    .info-row {
+      line-height: 20px;
 
       .label {
         font-weight: bold;
-        width: 80px;
+        width: 60px;
         font-size: 14px;
       }
 
       .value {
+        margin-right: 20px;
         min-width: 80px;
         font-size: 14px;
       }
+    }
+  }
 
-      &.address-item {
-        .address-value {
-          min-width: 200px;
+  .table-section {
+    margin-bottom: 4px;
+    flex: 1;
+
+    .product-table {
+      width: 100%;
+      border-collapse: collapse;
+      border: 1px solid #000;
+
+      th,
+      td {
+        border: 1px solid #000;
+        padding: 6px;
+        text-align: center;
+        font-size: 14px;
+        line-height: 1.4;
+      }
+
+      th {
+        font-weight: bold;
+      }
+
+      .total-label {
+        text-align: right;
+        font-weight: bold;
+      }
+
+      .total-value {
+        font-weight: bold;
+      }
+    }
+  }
+
+  .footer-section {
+    .footer-row {
+      display: flex;
+      margin-bottom: 3px;
+      line-height: 20px;
+      justify-content: space-between;
+
+      .footer-item {
+        display: flex;
+        margin-right: 20px;
+
+        .label {
+          font-weight: bold;
+          width: 80px;
+          font-size: 14px;
+        }
+
+        .value {
+          min-width: 80px;
+          font-size: 14px;
+        }
+
+        &.address-item {
+          .address-value {
+            min-width: 200px;
+          }
         }
       }
     }
   }
-}
 
-@media print {
-  .app-container {
-    display: none;
-  }
+  @media print {
+    .app-container {
+      display: none;
+    }
 
-  .print-page {
-    box-shadow: none;
-    margin: 0;
-    padding: 10mm;
-    padding-left: 20mm;
-    page-break-inside: avoid;
-    page-break-after: always;
+    .print-page {
+      box-shadow: none;
+      margin: 0;
+      padding: 10mm;
+      padding-left: 20mm;
+      page-break-inside: avoid;
+      page-break-after: always;
+    }
+    .print-page:last-child {
+      page-break-after: avoid;
+    }
   }
-  .print-page:last-child {
-    page-break-after: avoid;
-  }
-}
 </style>

--
Gitblit v1.9.3