From 6faf65a6a7e72b7ecff52355f798fd00a516ba77 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期四, 30 四月 2026 17:37:13 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/dev_NEW_pro' into dev_NEW_pro

---
 src/views/procurementManagement/procurementInvoiceLedger/index.vue                 |  159 -
 src/views/productionManagement/processRoute/index.vue                              |    3 
 src/views/collaborativeApproval/rulesRegulationsManagement/index.vue               |   80 
 src/views/basicData/product/index.vue                                              | 1132 +++++----
 src/views/productionManagement/processRoute/processRouteItem/index.vue             |   20 
 jsconfig.json                                                                      |   10 
 src/api/productionManagement/productionOrder.js                                    |    9 
 src/views/salesManagement/salesLedger/index.vue                                    |   34 
 src/views/productionManagement/workOrderManagement/index.vue                       |   27 
 src/views/salesManagement/invoiceLedger/index.vue                                  |   25 
 src/views/productionManagement/productionTraceability/index.vue                    |  831 +++++++
 src/components/Dialog/FileList.vue                                                 |   29 
 src/layout/components/Sidebar/index.vue                                            |  234 +-
 src/views/safeProduction/safetyTrainingAssessment/index.vue                        |   49 
 src/views/customerService/afterSalesHandling/index.vue                             |  165 -
 src/views/safeProduction/safeQualifications/index.vue                              |   40 
 src/views/inventoryManagement/stockManagement/New.vue                              |    9 
 src/api/productionManagement/productionProcess.js                                  |    6 
 src/components/PIMTable/PIMTable.vue                                               |    5 
 src/views/financialManagement/revenueManagement/index.vue                          |  423 +--
 src/views/equipmentManagement/measurementEquipment/components/calibrationDia.vue   |   33 
 src/router/index.js                                                                |   40 
 src/views/productionManagement/workOrderEdit/index.vue                             |    5 
 src/views/financialManagement/expenseManagement/index.vue                          |  176 -
 src/views/productionManagement/productionOrder/components/MaterialDetailDialog.vue |    5 
 src/views/procurementManagement/procurementLedger/index.vue                        | 2436 ++++++++++----------
 src/main.js                                                                        |    3 
 src/views/productionManagement/productionOrder/index.vue                           |   68 
 FILE_UPLOAD_README.md                                                              |  480 ++++
 src/api/basicData/productProcess.js                                                |   10 
 src/views/safeProduction/dangerInvestigation/index.vue                             |  178 -
 31 files changed, 3,638 insertions(+), 3,086 deletions(-)

diff --git a/FILE_UPLOAD_README.md b/FILE_UPLOAD_README.md
new file mode 100644
index 0000000..ad5b42a
--- /dev/null
+++ b/FILE_UPLOAD_README.md
@@ -0,0 +1,480 @@
+# 鏈湴鏂囦欢涓婁紶 README
+
+鏈枃妗e熀浜庝互涓嬪疄鐜版暣鐞嗭細
+
+- `src/components/AttachmentUpload/file/index.vue`
+- `src/components/AttachmentUpload/image/index.vue`
+- `src/components/AttachmentPreview/image/index.vue`
+- `src/components/Dialog/FileList.vue`
+- `src/api/basicData/common.js`
+- `src/api/publicApi/commonFile.js`
+
+鐩稿叧缁勪欢宸插湪 `src/main.js` 涓敞鍐屼负鍏ㄥ眬缁勪欢锛屽彲鐩存帴鍦ㄩ〉闈腑浣跨敤锛�
+
+- `FileUpload`
+- `ImageUpload`
+- `ImagePreview`
+- `FileListDialog`
+
+## 1. 鍔熻兘姒傝
+
+褰撳墠杩欏涓婁紶鑳藉姏涓昏鍒嗕负 4 閮ㄥ垎锛�
+
+1. `FileUpload`锛氭櫘閫氭枃浠朵笂浼狅紝鏀寔鎷栨嫿銆佹壒閲忎笂浼犮�侀瑙堛�佸垹闄�
+2. `ImageUpload`锛氬浘鐗囦笂浼狅紝鏀寔鍥剧墖澧欏睍绀恒�侀瑙堛�佸垹闄�
+3. `ImagePreview`锛氬浘鐗囧垪琛ㄩ瑙堝睍绀�
+4. `FileListDialog`锛氫笟鍔¢檮浠跺脊绐楋紝鏀寔鏌ヨ銆佷笂浼犮�佸垹闄ゃ�佷笅杞�
+
+涓婁紶搴曞眰缁熶竴璧版帴鍙o細
+
+- `POST /common/upload`
+
+瀵瑰簲鏂规硶鍦� `src/api/basicData/common.js`锛�
+
+```js
+uploadFile(data)
+```
+
+## 2. 涓婁紶鎺ュ彛璇存槑
+
+### 2.1 閫氱敤涓婁紶鎺ュ彛
+
+鏂囦欢涓婁紶缁勪欢鍜屽浘鐗囦笂浼犵粍浠堕兘璋冪敤浜嗭細
+
+```js
+import { uploadFile } from '@/api/basicData/common'
+```
+
+鎺ュ彛鐗瑰緛锛�
+
+- 璇锋眰鏂瑰紡锛歚POST`
+- 鍦板潃锛歚/common/upload`
+- 璇锋眰绫诲瀷锛歚multipart/form-data`
+- 鏀寔 `FormData` 鎵归噺涓婁紶
+- 榛樿瀛楁鍚嶏細`files`
+
+缁勪欢鍐呴儴浼氳繖鏍风粍瑁呭弬鏁帮細
+
+```js
+const formData = new FormData()
+validFiles.forEach((file) => {
+  formData.append(props.uploadFieldName, file.raw)
+})
+```
+
+### 2.2 涓婁紶杩斿洖鍊艰姹�
+
+涓婁紶鎴愬姛鍚庯紝缁勪欢浼氬皾璇曚粠浠ヤ笅缁撴瀯涓彁鍙栨暟缁勶細
+
+- `response`
+- `response.data`
+- `response.data.data`
+- `response.payload`
+- `response.payload.data`
+- `response.rows`
+- `response.result`
+
+鍥犳鍚庣杩斿洖鏁扮粍鏃讹紝涓婇潰浠绘剰涓�绉嶇粨鏋勯兘鍙互琚瘑鍒��
+
+缁勪欢灞曠ず鏃跺父鐢ㄥ埌鐨勫瓧娈垫湁锛�
+
+- 鏂囦欢鍚嶏細`name` / `originalFilename` / `fileName` / `uidFilename`
+- 鏂囦欢鍦板潃锛歚url` / `downloadURL`
+- 鍥剧墖鍦板潃锛歚url` / `previewURL` / `previewUrl`
+- 涓婚敭锛歚id`
+
+寤鸿涓婁紶鎺ュ彛杩斿洖鐨勫崟椤瑰璞″敖閲忓寘鍚細
+
+```js
+{
+  id: 1,
+  originalFilename: 'demo.pdf',
+  downloadURL: 'https://xxx/demo.pdf',
+  previewURL: 'https://xxx/demo.png'
+}
+```
+
+## 3. FileUpload 鏂囦欢涓婁紶缁勪欢
+
+缁勪欢璺緞锛�
+
+`src/components/AttachmentUpload/file/index.vue`
+
+### 3.1 鍩虹鐢ㄦ硶
+
+```vue
+<template>
+  <FileUpload v-model:file-list="fileList" />
+</template>
+
+<script setup>
+import { ref } from 'vue'
+
+const fileList = ref([])
+</script>
+```
+
+### 3.2 甯哥敤灞炴��
+
+| 灞炴�� | 璇存槑 | 绫诲瀷 | 榛樿鍊� |
+| --- | --- | --- | --- |
+| `fileList` | 缁戝畾鏂囦欢鍒楄〃 | `Array` | `[]` |
+| `limit` | 鏈�澶т笂浼犳暟閲� | `Number` | `10` |
+| `fileSize` | 鍗曚釜鏂囦欢澶у皬闄愬埗锛屽崟浣� MB | `Number` | `50` |
+| `fileType` | 鍏佽涓婁紶鐨勬枃浠剁被鍨嬶紝濡� `['pdf', 'docx']` | `Array` | `[]` |
+| `buttonText` | 涓婁紶鎻愮ず鏂囨 | `String` | `鍗曞嚮閫夋嫨鏂囦欢` |
+| `disabled` | 鏄惁绂佺敤 | `Boolean` | `false` |
+| `uploadFieldName` | `FormData` 瀛楁鍚� | `String` | `files` |
+| `index` | 琛ㄦ牸/鍒楄〃琛屾ā寮忎笅鐨勫綋鍓嶈绱㈠紩 | `Number` | `-1` |
+| `childrenKey` | 琛屽唴鎸傝浇瀛楁鍚� | `String` | `files` |
+
+### 3.3 浜嬩欢
+
+| 浜嬩欢 | 璇存槑 |
+| --- | --- |
+| `update:fileList` | 鏂囦欢鍒楄〃鍙樺寲鏃惰Е鍙� |
+| `change` | 鏂囦欢鍒楄〃鍙樺寲鏃惰Е鍙戯紝杩斿洖鏈�鏂板垪琛� |
+
+### 3.4 闄愬埗瑙勫垯
+
+缁勪欢鍐呭凡瀹炵幇锛�
+
+- 鏂囦欢鏁伴噺闄愬埗
+- 鏂囦欢澶у皬闄愬埗
+- 鏂囦欢绫诲瀷鏍¢獙
+- 涓婁紶涓姸鎬侀攣瀹�
+- 澶辫触鍚庤嚜鍔ㄦ竻绌哄綋鍓嶉�夋嫨闃熷垪
+
+渚嬪闄愬埗 PDF/Word锛�
+
+```vue
+<FileUpload
+  v-model:file-list="fileList"
+  :limit="5"
+  :file-size="20"
+  :file-type="['pdf', 'doc', 'docx']"
+/>
+```
+
+### 3.5 杩斿洖鏁版嵁鏍煎紡寤鸿
+
+`FileUpload` 鏇撮�傚悎鎺ユ敹杩欐牱鐨勫垪琛細
+
+```js
+[
+  {
+    id: 1,
+    originalFilename: '鍚堝悓.pdf',
+    downloadURL: 'https://xxx/contract.pdf'
+  }
+]
+```
+
+鍥犱负缁勪欢鎵撳紑鏂囦欢鏃朵細浼樺厛璇诲彇锛�
+
+```js
+url || downloadURL || previewURL || previewUrl
+```
+
+### 3.6 琛屽唴宓屽妯″紡
+
+濡傛灉涓婁紶缁勪欢鏀惧湪琛ㄦ牸鏌愪竴琛屼腑锛屽彲閰嶅悎 `index` 鍜� `childrenKey` 浣跨敤锛�
+
+```vue
+<FileUpload
+  v-model:file-list="tableData"
+  :index="scope.$index"
+  children-key="files"
+/>
+```
+
+姝ゆ椂缁勪欢浼氳嚜鍔ㄨ鍐欙細
+
+```js
+tableData[scope.$index].files
+```
+
+## 4. ImageUpload 鍥剧墖涓婁紶缁勪欢
+
+缁勪欢璺緞锛�
+
+`src/components/AttachmentUpload/image/index.vue`
+
+### 4.1 鍩虹鐢ㄦ硶
+
+```vue
+<template>
+  <ImageUpload v-model:file-list="imageList" />
+</template>
+
+<script setup>
+import { ref } from 'vue'
+
+const imageList = ref([])
+</script>
+```
+
+### 4.2 榛樿琛屼负
+
+鍥剧墖涓婁紶缁勪欢榛樿锛�
+
+- 鏈�澶氫笂浼� `10` 寮�
+- 鍗曞紶涓嶈秴杩� `10MB`
+- 榛樿鏀寔鏍煎紡锛歚png / jpg / jpeg / webp`
+- 浣跨敤 `picture-card` 椋庢牸灞曠ず
+- 鐐瑰嚮缂╃暐鍥惧彲棰勮澶у浘
+
+### 4.3 甯哥敤绀轰緥
+
+```vue
+<ImageUpload
+  v-model:file-list="imageList"
+  :limit="9"
+  :file-size="5"
+  :file-type="['png', 'jpg', 'jpeg']"
+  button-text="涓婁紶鍥剧墖"
+/>
+```
+
+### 4.4 杩斿洖鏁版嵁鏍煎紡寤鸿
+
+`ImageUpload` 灞曠ず鍥剧墖鏃朵紭鍏堣鍙栵細
+
+```js
+url || previewURL || previewUrl
+```
+
+寤鸿鍚庣杩斿洖锛�
+
+```js
+[
+  {
+    id: 1,
+    originalFilename: '鐜板満鍥剧墖.jpg',
+    previewURL: 'https://xxx/image.jpg'
+  }
+]
+```
+
+### 4.5 琛屽唴宓屽妯″紡
+
+鍥剧墖缁勪欢鍚屾牱鏀寔琛屽唴瀛楁鍐欏洖锛�
+
+```vue
+<ImageUpload
+  v-model:file-list="tableData"
+  :index="scope.$index"
+  children-key="images"
+/>
+```
+
+榛樿鍐欏洖瀛楁涓� `images`銆�
+
+## 5. ImagePreview 鍥剧墖棰勮缁勪欢
+
+缁勪欢璺緞锛�
+
+`src/components/AttachmentPreview/image/index.vue`
+
+### 5.1 鍩虹鐢ㄦ硶
+
+```vue
+<ImagePreview :file-list="imageList" />
+```
+
+### 5.2 鍙厤缃」
+
+| 灞炴�� | 璇存槑 | 绫诲瀷 | 榛樿鍊� |
+| --- | --- | --- | --- |
+| `fileList` | 鍥剧墖鍒楄〃 | `Array` | `[]` |
+| `thumbSize` | 缂╃暐鍥惧ぇ灏� | `Number` | `72` |
+| `gap` | 缂╃暐鍥鹃棿璺� | `Number` | `10` |
+
+### 5.3 鏁版嵁瑕佹眰
+
+缁勪欢浼氳繃婊ゆ病鏈� `previewURL` 鐨勯」锛屽洜姝ゅ鏋滆姝e父鏄剧ず锛屽缓璁嚦灏戝寘鍚細
+
+```js
+[
+  {
+    previewURL: 'https://xxx/image.jpg',
+    originalFilename: '鍥剧墖1.jpg'
+  }
+]
+```
+
+濡傛灉鍒楄〃涓虹┖锛岀粍浠舵樉绀衡�滄殏鏃犲浘鐗団�濄��
+
+## 6. FileListDialog 闄勪欢寮圭獥缁勪欢
+
+缁勪欢璺緞锛�
+
+`src/components/Dialog/FileList.vue`
+
+杩欎釜缁勪欢閫傚悎涓氬姟琛ㄥ崟鎴栬鎯呴〉閲岀殑鈥滈檮浠剁鐞嗏�濆満鏅紝鑳藉姏鍖呮嫭锛�
+
+- 鏍规嵁涓氬姟涓婚敭鏌ヨ闄勪欢鍒楄〃
+- 鎵撳紑寮圭獥鏌ョ湅闄勪欢
+- 鍦ㄥ脊绐椾腑缁х画涓婁紶闄勪欢
+- 鍒犻櫎闄勪欢
+- 涓嬭浇闄勪欢
+
+### 6.1 缁勪欢灞炴��
+
+| 灞炴�� | 璇存槑 | 绫诲瀷 | 榛樿鍊� |
+| --- | --- | --- | --- |
+| `visible` | 鏄惁鏄剧ず寮圭獥 | `Boolean` | 蹇呬紶 |
+| `recordType` | 涓氬姟绫诲瀷 | `String` | `''` |
+| `recordId` | 涓氬姟涓婚敭 | `Number` | `0` |
+| `title` | 寮圭獥鏍囬 | `String` | `闄勪欢` |
+| `width` | 寮圭獥瀹藉害 | `String` | `50%` |
+| `showActions` | 鏄惁鏄剧ず涓嬭浇/鍒犻櫎鎿嶄綔鍒� | `Boolean` | `true` |
+
+### 6.2 鍩虹鐢ㄦ硶
+
+```vue
+<template>
+  <el-button @click="visible = true">鏌ョ湅闄勪欢</el-button>
+
+  <FileListDialog
+    v-model:visible="visible"
+    record-type="salesLedger"
+    :record-id="rowId"
+    title="闄勪欢鍒楄〃"
+  />
+</template>
+
+<script setup>
+import { ref } from 'vue'
+
+const visible = ref(false)
+const rowId = ref(1001)
+</script>
+```
+
+### 6.3 缁勪欢鍐呴儴渚濊禆鐨勬帴鍙�
+
+`FileListDialog` 鏈韩涓嶇洿鎺ヨ皟鐢� `commonFile.js`锛岃�屾槸渚濊禆锛�
+
+- `attachmentList`
+- `createAttachment`
+- `deleteAttachment`
+
+澶勭悊閫昏緫涓猴細
+
+1. 鎵撳紑寮圭獥鍚庢牴鎹� `recordType + recordId` 鏌ヨ闄勪欢
+2. 鐐瑰嚮鈥滀笂浼犻檮浠垛�濆悗锛屽唴閮ㄤ娇鐢� `AttachmentUpload/file` 鍏堜笂浼犲埌 `/common/upload`
+3. 涓婁紶鎴愬姛鍚庯紝灏嗚繑鍥炵殑鏂囦欢瀵硅薄鍜屽凡鏈夊垪琛ㄤ竴璧锋彁浜ょ粰 `createAttachment`
+4. 鍒犻櫎鏃惰皟鐢� `deleteAttachment`
+5. 涓嬭浇鏃剁洿鎺� `window.open(downloadURL, '_blank')`
+
+鍥犳杩欓噷瑕佺壒鍒敞鎰忥細
+
+- `recordType` 鍜� `recordId` 蹇呴』鏄湁鏁堜笟鍔℃爣璇�
+- 涓婁紶鎴愬姛杩斿洖鐨勬暟鎹紝闇�瑕佽兘琚� `createAttachment` 鐩存帴鎺ユ敹
+- 鍒楄〃涓殑涓嬭浇鍦板潃瀛楁搴斾负 `downloadURL`
+
+## 7. commonFile.js 璇存槑
+
+鏂囦欢璺緞锛�
+
+`src/api/publicApi/commonFile.js`
+
+褰撳墠鏂囦欢鎻愪緵鐨勬槸鍏叡鏂囦欢鍒犻櫎鎺ュ彛锛�
+
+```js
+delCommonFile(ids)
+delCommonFileInvoiceLedger(ids)
+```
+
+瀵瑰簲鎺ュ彛锛�
+
+- `/commonFile/delCommonFile`
+- `/invoiceLedger/delFile`
+
+杩欎袱涓柟娉曟洿閫傚悎宸茬粡鍜屽叿浣撲笟鍔$粦瀹氬悗鐨勨�滃垹闄ゅ凡淇濆瓨闄勪欢鈥濆満鏅紝涓嶈礋璐d笂浼犳枃浠舵湰韬��
+
+绀轰緥锛�
+
+```js
+import { delCommonFile } from '@/api/publicApi/commonFile'
+
+await delCommonFile([1, 2, 3])
+```
+
+## 8. 鎺ㄨ崘浣跨敤鏂瑰紡
+
+### 8.1 鏅�氫笟鍔¤〃鍗曚笂浼犻檮浠�
+
+```vue
+<FileUpload v-model:file-list="form.storageBlobDTOs" />
+```
+
+鎻愪氦琛ㄥ崟鏃剁洿鎺ュ甫涓婏細
+
+```js
+{
+  ...form,
+  storageBlobDTOs: form.storageBlobDTOs
+}
+```
+
+### 8.2 鍥剧墖绫讳笟鍔�
+
+```vue
+<ImageUpload v-model:file-list="form.images" />
+<ImagePreview :file-list="form.images" />
+```
+
+### 8.3 宸茶惤搴撻檮浠剁鐞�
+
+```vue
+<FileListDialog
+  v-model:visible="dialogVisible"
+  :record-type="recordType"
+  :record-id="recordId"
+/>
+```
+
+閫傚悎璇︽儏椤点�佸鎵归〉銆佸彴璐﹂〉杩欑被鈥滄煡鐪嬪苟缁存姢褰撳墠涓氬姟闄勪欢鈥濈殑鍦烘櫙銆�
+
+## 9. 娉ㄦ剰浜嬮」
+
+1. `FileUpload` 鍜� `ImageUpload` 鍙槸璐熻矗鎶婃枃浠跺厛浼犲埌 `/common/upload`锛屼笉绛変簬宸茬粡鍜屼笟鍔℃暟鎹粦瀹氥��
+2. 濡傛灉涓氬姟闇�瑕佹寔涔呭寲闄勪欢鍏崇郴锛屼粛闇�瑕佸湪淇濆瓨琛ㄥ崟鏃舵妸杩斿洖鐨勬枃浠跺璞℃彁浜ょ粰涓氬姟鎺ュ彛銆�
+3. `ImagePreview` 褰撳墠鍙瘑鍒� `previewURL`锛屽鏋滃悗绔彧杩斿洖 `url`锛岄瑙堢粍浠跺皢涓嶄細灞曠ず锛屾渶濂界粺涓�琛ラ綈 `previewURL`銆�
+4. `FileListDialog` 渚濊禆 `recordType`銆乣recordId` 鏌ヨ鍜屼繚瀛橀檮浠跺叧绯伙紝鏂板涓氬姟鏃惰鍏堢‘璁ゅ悗绔叧鑱旀帴鍙e彲鐢ㄣ��
+5. 鍒犻櫎鏈湴鍒楄〃椤瑰拰鍒犻櫎宸蹭繚瀛橀檮浠舵槸涓や欢浜嬶細
+   - 涓婁紶缁勪欢閲岀殑鍒犻櫎锛氬彧浼氫粠褰撳墠鍓嶇缁戝畾鏁扮粍涓Щ闄�
+   - `commonFile.js` / `deleteAttachment`锛氭墠鏄湡姝h皟鐢ㄥ悗绔垹闄�
+
+## 10. 涓�濂楁渶甯歌鐨勯〉闈㈠啓娉�
+
+```vue
+<template>
+  <el-form :model="form">
+    <el-form-item label="闄勪欢">
+      <FileUpload v-model:file-list="form.storageBlobDTOs" :limit="5" />
+    </el-form-item>
+
+    <el-form-item label="鐜板満鍥剧墖">
+      <ImageUpload v-model:file-list="form.images" :limit="9" />
+    </el-form-item>
+
+    <el-form-item label="鍥剧墖棰勮">
+      <ImagePreview :file-list="form.images" />
+    </el-form-item>
+  </el-form>
+</template>
+
+<script setup>
+import { ref } from 'vue'
+
+const form = ref({
+  storageBlobDTOs: [],
+  images: [],
+})
+</script>
+```
+
+濡傛灉浣犵殑鐩爣鏄�滃厛涓婁紶锛屽啀璺熶笟鍔′竴璧蜂繚瀛樷�濓紝杩欏鍐欐硶鍙互鐩存帴浣滀负鍩虹妯℃澘浣跨敤銆�
diff --git a/jsconfig.json b/jsconfig.json
new file mode 100644
index 0000000..365552f
--- /dev/null
+++ b/jsconfig.json
@@ -0,0 +1,10 @@
+{
+  "compilerOptions": {
+    "baseUrl": ".",
+    "paths": {
+      "@/*": ["src/*"],
+      "~/*": ["./*"]
+    }
+  },
+  "include": ["src/**/*.js", "src/**/*.vue", "vite.config.js"]
+}
diff --git a/src/api/basicData/productProcess.js b/src/api/basicData/productProcess.js
index e0208fa..46356fd 100644
--- a/src/api/basicData/productProcess.js
+++ b/src/api/basicData/productProcess.js
@@ -1,10 +1,10 @@
-import request from '@/utils/request'
+import request from "@/utils/request";
 
 // 宸ュ簭鍒楄〃鍒嗛〉鏌ヨ
 export function productProcessListPage(query) {
   return request({
-    url: '/productProcess/listPage',
-    method: 'get',
-    params: query
-  })
+    url: "/technologyOperation/listPage",
+    method: "get",
+    params: query,
+  });
 }
diff --git a/src/api/productionManagement/productionOrder.js b/src/api/productionManagement/productionOrder.js
index 688abfc..9b5751d 100644
--- a/src/api/productionManagement/productionOrder.js
+++ b/src/api/productionManagement/productionOrder.js
@@ -45,6 +45,15 @@
   });
 }
 
+// 鐢熶骇璁㈠崟-淇敼
+export function updateProductOrder(data) {
+  return request({
+    url: "/productionOrder/updateOrder",
+    method: "post",
+    data: data,
+  });
+}
+
 export function delProductOrder(ids) {
   return request({
     url: `/productionOrder/delete`,
diff --git a/src/api/productionManagement/productionProcess.js b/src/api/productionManagement/productionProcess.js
index 7001997..783f584 100644
--- a/src/api/productionManagement/productionProcess.js
+++ b/src/api/productionManagement/productionProcess.js
@@ -4,7 +4,7 @@
 // 鍒嗛〉鏌ヨ
 export function listPage(query) {
   return request({
-    url: "/productProcess/listPage",
+    url: "/technologyOperation/listPage",
     method: "get",
     params: query,
   });
@@ -53,7 +53,7 @@
 // 瀵煎叆鏁版嵁
 export function importData(data) {
   return request({
-    url: "/productProcess/importData",
+    url: "/technologyOperation/importData",
     method: "post",
     data: data,
   });
@@ -62,7 +62,7 @@
 // 涓嬭浇妯℃澘
 export function downloadTemplate() {
   return request({
-    url: "/productProcess/downloadTemplate",
+    url: "/technologyOperation/downloadTemplate",
     method: "post",
     responseType: "blob",
   });
diff --git a/src/components/Dialog/FileList.vue b/src/components/Dialog/FileList.vue
index 136ff8b..6e0ca23 100644
--- a/src/components/Dialog/FileList.vue
+++ b/src/components/Dialog/FileList.vue
@@ -5,7 +5,8 @@
              @close="handleClose"
              class="attachment-dialog">
     <!-- 宸ュ叿鏍� -->
-    <div class="toolbar">
+    <div v-if="editable"
+         class="toolbar">
       <el-button type="primary"
                  size="small"
                  @click="handleUpload">
@@ -16,10 +17,11 @@
     <el-dialog v-model="uploadDialogVisible"
                title="涓婁紶闄勪欢"
                width="50%"
-               @close="handleUploadClose">
+               @close="closeUpload">
       <AttachmentUpload v-model:file-list="newFileList" />
       <template #footer>
-        <el-button @click="handleUploadClose">鍏抽棴</el-button>
+        <el-button @click="saveUpload">淇濆瓨</el-button>
+        <el-button @click="closeUpload">鍏抽棴</el-button>
       </template>
     </el-dialog>
     <!-- 鏂囦欢鍒楄〃琛ㄦ牸 -->
@@ -40,11 +42,12 @@
             <el-button link
                        type="primary"
                        size="small"
-                       :href="scope.row.downloadURL"
-                       class="download-link">
+                       class="download-link"
+                       @click="downloadFile(scope.row.downloadURL)">
               涓嬭浇
             </el-button>
-            <el-button link
+            <el-button v-if="editable"
+                       link
                        type="danger"
                        size="small"
                        @click="handleDelete(scope.row)">
@@ -93,6 +96,10 @@
       type: Boolean,
       default: true,
     },
+    editable: {
+      type: Boolean,
+      default: true,
+    },
   });
 
   const emit = defineEmits(["close", "download", "upload", "delete"]);
@@ -119,7 +126,7 @@
     uploadDialogVisible.value = true;
   };
 
-  const handleUploadClose = async () => {
+  const saveUpload = async () => {
     // 妫�鏌ユ槸鍚︽湁鏂颁笂浼犵殑鏂囦欢
     if (newFileList.value.length > 0) {
       try {
@@ -136,6 +143,11 @@
         proxy?.$modal?.msgError("涓婁紶澶辫触");
       }
     }
+    uploadDialogVisible.value = false;
+  };
+
+  const closeUpload = () => {
+    newFileList.value = [];
     uploadDialogVisible.value = false;
   };
 
@@ -160,6 +172,9 @@
     });
   };
 
+  const downloadFile = url => {
+    window.open(url, "_blank");
+  };
   onMounted(() => {
     setList();
   });
diff --git a/src/components/PIMTable/PIMTable.vue b/src/components/PIMTable/PIMTable.vue
index 61df179..f99b1eb 100644
--- a/src/components/PIMTable/PIMTable.vue
+++ b/src/components/PIMTable/PIMTable.vue
@@ -21,6 +21,7 @@
             class="lims-table">
     <el-table-column align="center"
                      type="selection"
+                     :selectable="selectable"
                      width="55"
                      v-if="isSelection" />
     <el-table-column align="center"
@@ -258,6 +259,10 @@
       type: Boolean,
       default: false,
     },
+    selectable: {
+      type: Function,
+      default: () => true,
+    },
     isShowPagination: {
       type: Boolean,
       default: true,
diff --git a/src/layout/components/Sidebar/index.vue b/src/layout/components/Sidebar/index.vue
index 83d3026..0692dda 100644
--- a/src/layout/components/Sidebar/index.vue
+++ b/src/layout/components/Sidebar/index.vue
@@ -1,142 +1,142 @@
 <template>
-  <div :class="{ 'has-logo': showLogo }" class="sidebar-container">
-    <logo v-if="showLogo" :collapse="isCollapse" />
+  <div :class="{ 'has-logo': showLogo }"
+       class="sidebar-container">
+    <logo v-if="showLogo"
+          :collapse="isCollapse" />
     <el-scrollbar wrap-class="scrollbar-wrapper">
-      <el-menu
-        :default-active="activeMenu"
-        :collapse="isCollapse"
-        :background-color="getMenuBackground"
-        :text-color="getMenuTextColor"
-        :unique-opened="true"
-        :active-text-color="theme"
-        :collapse-transition="false"
-        mode="vertical"
-        :class="sideTheme"
-      >
-        <sidebar-item
-          v-for="(route, index) in sidebarRouters"
-          :key="route.path + index"
-          :item="route"
-          :base-path="route.path"
-        />
+      <el-menu :default-active="activeMenu"
+               :collapse="isCollapse"
+               :background-color="getMenuBackground"
+               :text-color="getMenuTextColor"
+               :unique-opened="true"
+               :active-text-color="theme"
+               :collapse-transition="false"
+               mode="vertical"
+               :class="sideTheme">
+        <sidebar-item v-for="(route, index) in sidebarRouters"
+                      :key="route.path + index"
+                      :item="route"
+                      :base-path="route.path" />
       </el-menu>
     </el-scrollbar>
   </div>
 </template>
 
 <script setup>
-import Logo from './Logo'
-import SidebarItem from './SidebarItem'
-import variables from '@/assets/styles/variables.module.scss'
-import useAppStore from '@/store/modules/app'
-import useSettingsStore from '@/store/modules/settings'
-import usePermissionStore from '@/store/modules/permission'
+  import Logo from "./Logo";
+  import SidebarItem from "./SidebarItem";
+  import variables from "@/assets/styles/variables.module.scss";
+  import useAppStore from "@/store/modules/app";
+  import useSettingsStore from "@/store/modules/settings";
+  import usePermissionStore from "@/store/modules/permission";
 
-const route = useRoute()
-const appStore = useAppStore()
-const settingsStore = useSettingsStore()
-const permissionStore = usePermissionStore()
+  const route = useRoute();
+  const appStore = useAppStore();
+  const settingsStore = useSettingsStore();
+  const permissionStore = usePermissionStore();
 
-const sidebarRouters = computed(() => permissionStore.sidebarRouters)
-const showLogo = computed(() => settingsStore.sidebarLogo)
-const sideTheme = computed(() => settingsStore.sideTheme)
-const theme = computed(() => settingsStore.theme)
-const isCollapse = computed(() => !appStore.sidebar.opened)
+  const sidebarRouters = computed(() => permissionStore.sidebarRouters);
+  const showLogo = computed(() => settingsStore.sidebarLogo);
+  const sideTheme = computed(() => settingsStore.sideTheme);
+  const theme = computed(() => settingsStore.theme);
+  const isCollapse = computed(() => !appStore.sidebar.opened);
 
-const getMenuBackground = computed(() => 'var(--sidebar-bg)')
+  const getMenuBackground = computed(() => "var(--sidebar-bg)");
 
-const getMenuTextColor = computed(() => {
-  if (settingsStore.isDark) {
-    return 'var(--sidebar-text)'
-  }
-  return sideTheme.value === 'theme-dark' ? variables.menuText : variables.menuLightText
-})
+  const getMenuTextColor = computed(() => {
+    if (settingsStore.isDark) {
+      return "var(--sidebar-text)";
+    }
+    return sideTheme.value === "theme-dark"
+      ? variables.menuText
+      : variables.menuLightText;
+  });
 
-const activeMenu = computed(() => {
-  const { meta, path } = route
-  if (meta.activeMenu) {
-    return meta.activeMenu
-  }
-  return path
-})
+  const activeMenu = computed(() => {
+    const { meta, path } = route;
+    if (meta.activeMenu) {
+      return meta.activeMenu;
+    }
+    return path;
+  });
 </script>
 
 <style lang="scss" scoped>
-.sidebar-container {
-  background-color: v-bind(getMenuBackground);
-  border-radius: 22px;
-  overflow: hidden;
-
-  .scrollbar-wrapper {
+  .sidebar-container {
     background-color: v-bind(getMenuBackground);
-  }
-
-  .el-menu {
-    border: none;
-    height: 100%;
-    width: 100% !important;
     border-radius: 22px;
+    overflow: hidden;
 
-    .el-menu-item,
-    .el-sub-menu__title {
-      margin-bottom: 6px;
-      border-radius: 14px;
-      color: v-bind(getMenuTextColor);
+    .scrollbar-wrapper {
+      background-color: v-bind(getMenuBackground);
+    }
 
-      &:hover {
-        background-color: var(--menu-hover, rgba(0, 0, 0, 0.06)) !important;
+    .el-menu {
+      border: none;
+      height: 100%;
+      width: 100% !important;
+      border-radius: 22px;
+
+      .el-menu-item,
+      .el-sub-menu__title {
+        margin-bottom: 6px;
+        border-radius: 14px;
+        color: v-bind(getMenuTextColor);
+
+        &:hover {
+          background-color: var(--menu-hover, rgba(0, 0, 0, 0.06)) !important;
+          border-radius: 14px;
+        }
+      }
+
+      .el-menu-item {
+        &.is-active {
+          color: v-bind(theme);
+          background-color: var(--menu-active-bg, rgba(0, 0, 0, 0.06)) !important;
+          font-weight: 600;
+        }
+      }
+
+      .el-sub-menu__title {
+        color: v-bind(getMenuTextColor);
+      }
+
+      :deep(.el-sub-menu.is-active > .el-sub-menu__title) {
+        color: v-bind(theme) !important;
+        font-weight: 600;
+        background-color: var(--menu-active-bg, rgba(0, 0, 0, 0.06)) !important;
+        border-radius: 14px;
+        margin: 0 10px 6px !important;
+        // width: calc(100% - 20px) !important;
+        padding-left: 10px !important;
+        padding-right: 10px !important;
+        box-sizing: border-box;
+        overflow: hidden;
+        background-clip: padding-box;
+      }
+
+      :deep(.el-menu-item.is-active) {
+        margin: 0 10px 6px !important;
+        width: calc(100% - 20px) !important;
+        padding-left: 10px !important;
+        padding-right: 10px !important;
+        box-sizing: border-box;
+        overflow: hidden;
+        background-clip: padding-box;
+        border-radius: 14px;
+      }
+
+      :deep(.el-sub-menu.is-active > .el-sub-menu__title .menu-title),
+      :deep(.el-sub-menu.is-active > .el-sub-menu__title .svg-icon),
+      :deep(.el-menu-item.is-active .menu-title),
+      :deep(.el-menu-item.is-active .svg-icon) {
+        color: v-bind(theme) !important;
+      }
+
+      :deep(.el-sub-menu__title:hover),
+      :deep(.el-menu-item:hover) {
         border-radius: 14px;
       }
     }
-
-    .el-menu-item {
-      &.is-active {
-        color: v-bind(theme);
-        background-color: var(--menu-active-bg, rgba(0, 0, 0, 0.06)) !important;
-        font-weight: 600;
-      }
-    }
-
-    .el-sub-menu__title {
-      color: v-bind(getMenuTextColor);
-    }
-
-    :deep(.el-sub-menu.is-active > .el-sub-menu__title) {
-      color: v-bind(theme) !important;
-      font-weight: 600;
-      background-color: var(--menu-active-bg, rgba(0, 0, 0, 0.06)) !important;
-      border-radius: 14px;
-      margin: 0 10px 6px !important;
-      width: calc(100% - 20px) !important;
-      padding-left: 10px !important;
-      padding-right: 10px !important;
-      box-sizing: border-box;
-      overflow: hidden;
-      background-clip: padding-box;
-    }
-
-    :deep(.el-menu-item.is-active) {
-      margin: 0 10px 6px !important;
-      width: calc(100% - 20px) !important;
-      padding-left: 10px !important;
-      padding-right: 10px !important;
-      box-sizing: border-box;
-      overflow: hidden;
-      background-clip: padding-box;
-      border-radius: 14px;
-    }
-
-    :deep(.el-sub-menu.is-active > .el-sub-menu__title .menu-title),
-    :deep(.el-sub-menu.is-active > .el-sub-menu__title .svg-icon),
-    :deep(.el-menu-item.is-active .menu-title),
-    :deep(.el-menu-item.is-active .svg-icon) {
-      color: v-bind(theme) !important;
-    }
-
-    :deep(.el-sub-menu__title:hover),
-    :deep(.el-menu-item:hover) {
-      border-radius: 14px;
-    }
   }
-}
 </style>
diff --git a/src/main.js b/src/main.js
index b80c9b6..025ff14 100644
--- a/src/main.js
+++ b/src/main.js
@@ -48,6 +48,8 @@
 import ImageUpload from "@/components/AttachmentUpload/image";
 // 鍥剧墖棰勮缁勪欢
 import ImagePreview from "@/components/AttachmentPreview/image";
+// 闄勪欢寮圭獥缁勪欢
+import FileListDialog from "@/components/Dialog/FileList.vue";
 // 瀛楀吀鏍囩缁勪欢
 import DictTag from "@/components/DictTag";
 // 琛ㄦ牸缁勪欢
@@ -92,6 +94,7 @@
 app.component("FileUpload", FileUpload);
 app.component("ImageUpload", ImageUpload);
 app.component("ImagePreview", ImagePreview);
+app.component("FileListDialog", FileListDialog);
 app.component("RightToolbar", RightToolbar);
 app.component("Editor", Editor);
 app.component("PIMTable", PIMTable);
diff --git a/src/router/index.js b/src/router/index.js
index cc2b88c..c9b163c 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -146,106 +146,106 @@
         path: "general-ledger",
         component: () => import("@/views/financialManagement/generalLedger/index.vue"),
         name: "GeneralLedger",
-        meta: { title: "鎬诲笎绉戠洰" }
+        meta: { title: "鎬诲笎绉戠洰" },
       },
       {
         path: "sales-out",
         component: () => import("@/views/financialManagement/receivable/salesOut.vue"),
         name: "SalesOut",
-        meta: { title: "閿�鍞嚭搴�" }
+        meta: { title: "閿�鍞嚭搴�" },
       },
       {
         path: "sales-return",
         component: () => import("@/views/financialManagement/receivable/salesReturn.vue"),
         name: "SalesReturn",
-        meta: { title: "閿�鍞��璐�" }
+        meta: { title: "閿�鍞��璐�" },
       },
       {
         path: "receivable-reconciliation",
         component: () => import("@/views/financialManagement/receivable/reconciliation.vue"),
         name: "ReceivableReconciliation",
-        meta: { title: "搴旀敹瀵硅处" }
+        meta: { title: "搴旀敹瀵硅处" },
       },
       {
         path: "invoice-apply",
         component: () => import("@/views/financialManagement/receivable/invoiceApply.vue"),
         name: "InvoiceApply",
-        meta: { title: "寮�绁ㄧ敵璇�" }
+        meta: { title: "寮�绁ㄧ敵璇�" },
       },
       {
         path: "output-invoice",
         component: () => import("@/views/financialManagement/receivable/outputInvoice.vue"),
         name: "OutputInvoice",
-        meta: { title: "閿�椤瑰彂绁�" }
+        meta: { title: "閿�椤瑰彂绁�" },
       },
       {
         path: "receipt",
         component: () => import("@/views/financialManagement/receivable/receipt.vue"),
         name: "Receipt",
-        meta: { title: "鏀舵鍗�" }
+        meta: { title: "鏀舵鍗�" },
       },
       {
         path: "purchase-in",
         component: () => import("@/views/financialManagement/payable/purchaseIn.vue"),
         name: "PurchaseIn",
-        meta: { title: "閲囪喘鍏ュ簱" }
+        meta: { title: "閲囪喘鍏ュ簱" },
       },
       {
         path: "payable-reconciliation",
         component: () => import("@/views/financialManagement/payable/reconciliation.vue"),
         name: "PayableReconciliation",
-        meta: { title: "搴斾粯瀵硅处" }
+        meta: { title: "搴斾粯瀵硅处" },
       },
       {
         path: "input-invoice",
         component: () => import("@/views/financialManagement/payable/input-invoice.vue"),
         name: "InputInvoice",
-        meta: { title: "杩涢」鍙戠エ" }
+        meta: { title: "杩涢」鍙戠エ" },
       },
       {
         path: "payment-apply",
         component: () => import("@/views/financialManagement/payable/paymentApply.vue"),
         name: "PaymentApply",
-        meta: { title: "浠樻鐢宠" }
+        meta: { title: "浠樻鐢宠" },
       },
       {
         path: "payment",
         component: () => import("@/views/financialManagement/payable/payment.vue"),
         name: "Payment",
-        meta: { title: "浠樻鍗�" }
+        meta: { title: "浠樻鍗�" },
       },
       {
         path: "fixed-assets",
         component: () => import("@/views/financialManagement/assets/fixedAssets.vue"),
         name: "FixedAssets",
-        meta: { title: "鍥哄畾璧勪骇" }
+        meta: { title: "鍥哄畾璧勪骇" },
       },
       {
         path: "intangible-assets",
         component: () => import("@/views/financialManagement/assets/intangibleAssets.vue"),
         name: "IntangibleAssets",
-        meta: { title: "鏃犲舰璧勪骇" }
+        meta: { title: "鏃犲舰璧勪骇" },
       },
       {
         path: "voucher",
         component: () => import("@/views/financialManagement/voucher/index.vue"),
         name: "Voucher",
-        meta: { title: "鍑瘉" }
+        meta: { title: "鍑瘉" },
       },
       {
         path: "voucher-general-ledger",
         component: () => import("@/views/financialManagement/voucher/generalLedger.vue"),
         name: "VoucherGeneralLedger",
-        meta: { title: "绉戠洰鎬诲笎" }
+        meta: { title: "绉戠洰鎬诲笎" },
       },
       {
         path: "voucher-detail-ledger",
         component: () => import("@/views/financialManagement/voucher/detailLedger.vue"),
         name: "VoucherDetailLedger",
-        meta: { title: "绉戠洰鏄庣粏甯�" }
-      }
-    ]
-  }
+        meta: { title: "绉戠洰鏄庣粏甯�" },
+      },
+    ],
+  },
 ];
 
 // 鍔ㄦ�佽矾鐢憋紝鍩轰簬鐢ㄦ埛鏉冮檺鍔ㄦ�佸幓鍔犺浇
diff --git a/src/views/basicData/product/index.vue b/src/views/basicData/product/index.vue
index 10b51bf..99ab028 100644
--- a/src/views/basicData/product/index.vue
+++ b/src/views/basicData/product/index.vue
@@ -2,41 +2,34 @@
   <div class="app-container product-view">
     <div class="left">
       <div>
-        <el-input
-          v-model="search"
-          style="width: 210px"
-          placeholder="杈撳叆鍏抽敭瀛楄繘琛屾悳绱�"
-          @change="searchFilter"
-          @clear="searchFilter"
-          clearable
-          prefix-icon="Search"
-        />
-        <el-button
-          v-if="false"
-          type="primary"
-          @click="openProDia('addOne')"
-          style="margin-left: 10px"
-          >鏂板浜у搧澶х被</el-button
-        >
+        <el-input v-model="search"
+                  style="width: 210px"
+                  placeholder="杈撳叆鍏抽敭瀛楄繘琛屾悳绱�"
+                  @change="searchFilter"
+                  @clear="searchFilter"
+                  clearable
+                  prefix-icon="Search" />
+        <el-button v-if="false"
+                   type="primary"
+                   @click="openProDia('addOne')"
+                   style="margin-left: 10px">鏂板浜у搧澶х被</el-button>
       </div>
       <div ref="containerRef">
-        <el-tree
-          ref="tree"
-          v-loading="treeLoad"
-          :data="list"
-          @node-click="handleNodeClick"
-          :expand-on-click-node="false"
-          @node-expand="handleNodeExpand"
-          @node-collapse="handleNodeCollapse"
-          :key="treeKey"
-          :default-expanded-keys="expandedKeys"
-          :filter-node-method="filterNode"
-          :props="{ children: 'children', label: 'label' }"
-          highlight-current
-          node-key="id"
-          class="product-tree-scroll"
-          style="height: calc(100vh - 190px); overflow-y: auto"
-        >
+        <el-tree ref="tree"
+                 v-loading="treeLoad"
+                 :data="list"
+                 @node-click="handleNodeClick"
+                 :expand-on-click-node="false"
+                 @node-expand="handleNodeExpand"
+                 @node-collapse="handleNodeCollapse"
+                 :key="treeKey"
+                 :default-expanded-keys="expandedKeys"
+                 :filter-node-method="filterNode"
+                 :props="{ children: 'children', label: 'label' }"
+                 highlight-current
+                 node-key="id"
+                 class="product-tree-scroll"
+                 style="height: calc(100vh - 190px); overflow-y: auto">
           <template #default="{ node, data }">
             <div class="custom-tree-node">
               <span class="tree-node-content">
@@ -47,25 +40,23 @@
                 <span class="tree-node-label">{{ data.label }}</span>
               </span>
               <div>
-                <el-button
-                  type="primary"
-                  link
-                  :disabled="isTopLevelNode(data, node)"
-                  @click="openProDia('edit', data)"
-                >
+                <el-button type="primary"
+                           link
+                           :disabled="isTopLevelNode(data, node)"
+                           @click="openProDia('edit', data)">
                   缂栬緫
                 </el-button>
-                <el-button type="primary" link @click="openProDia('add', data)">
+                <el-button type="primary"
+                           link
+                           @click="openProDia('add', data)">
                   娣诲姞浜у搧
                 </el-button>
-                <el-button
-                  v-if="!node.childNodes.length"
-                  style="margin-left: 4px"
-                  type="danger"
-                  link
-                  :disabled="isTopLevelNode(data, node)"
-                  @click="remove(node, data)"
-                >
+                <el-button v-if="!node.childNodes.length"
+                           style="margin-left: 4px"
+                           type="danger"
+                           link
+                           :disabled="isTopLevelNode(data, node)"
+                           @click="remove(node, data)">
                   鍒犻櫎
                 </el-button>
               </div>
@@ -75,103 +66,109 @@
       </div>
     </div>
     <div class="right">
-      <div style="margin-bottom: 10px" v-if="isShowButton">
-        <el-button type="primary" @click="openModelDia('add')">
+      <div style="margin-bottom: 10px"
+           v-if="isShowButton">
+        <el-button type="primary"
+                   @click="openModelDia('add')">
           鏂板瑙勬牸鍨嬪彿
         </el-button>
-        <ImportExcel :product-id="currentId" @uploadSuccess="getModelList" />
-        <el-button
-          type="danger"
-          @click="handleDelete"
-          style="margin-left: 10px"
-          plain
-        >
+        <ImportExcel :product-id="currentId"
+                     @uploadSuccess="getModelList" />
+        <el-button type="danger"
+                   @click="handleDelete"
+                   style="margin-left: 10px"
+                   plain>
           鍒犻櫎
         </el-button>
       </div>
-      <PIMTable
-        rowKey="id"
-        :column="tableColumn"
-        :tableData="tableData"
-        :page="page"
-        :isSelection="true"
-        @selection-change="handleSelectionChange"
-        :tableLoading="tableLoading"
-        @pagination="pagination"
-      ></PIMTable>
+      <PIMTable rowKey="id"
+                :column="tableColumn"
+                :tableData="tableData"
+                :page="page"
+                :isSelection="true"
+                @selection-change="handleSelectionChange"
+                :tableLoading="tableLoading"
+                @pagination="pagination"></PIMTable>
     </div>
-    <el-dialog v-model="productDia" title="浜у搧" width="400px" @keydown.enter.prevent>
-      <el-form
-        :model="form"
-        label-width="140px"
-        label-position="top"
-        :rules="rules"
-        ref="formRef"
-      >
+    <el-dialog v-model="productDia"
+               title="浜у搧"
+               width="400px"
+               @keydown.enter.prevent>
+      <el-form :model="form"
+               label-width="140px"
+               label-position="top"
+               :rules="rules"
+               ref="formRef">
         <el-row :gutter="30">
           <el-col :span="24">
-            <el-form-item label="浜у搧鍚嶇О锛�" prop="productName">
-              <el-input
-                v-model="form.productName"
-                placeholder="璇疯緭鍏ヤ骇鍝佸悕绉�"
-                maxlength="20"
-                show-word-limit
-                clearable
-                @keydown.enter.prevent
-              />
+            <el-form-item label="浜у搧鍚嶇О锛�"
+                          prop="productName">
+              <el-input v-model="form.productName"
+                        placeholder="璇疯緭鍏ヤ骇鍝佸悕绉�"
+                        maxlength="20"
+                        show-word-limit
+                        clearable
+                        @keydown.enter.prevent />
             </el-form-item>
           </el-col>
         </el-row>
       </el-form>
       <template #footer>
         <div class="dialog-footer">
-          <el-button type="primary" @click="submitForm">纭</el-button>
+          <el-button type="primary"
+                     @click="submitForm">纭</el-button>
           <el-button @click="closeProDia">鍙栨秷</el-button>
         </div>
       </template>
     </el-dialog>
-    <el-dialog
-      v-model="modelDia"
-      title="瑙勬牸鍨嬪彿"
-      width="400px"
-      @close="closeModelDia"
-      @keydown.enter.prevent
-    >
-      <el-form
-        :model="modelForm"
-        label-width="140px"
-        label-position="top"
-        :rules="modelRules"
-        ref="modelFormRef"
-      >
+    <el-dialog v-model="modelDia"
+               title="瑙勬牸鍨嬪彿"
+               width="400px"
+               @close="closeModelDia"
+               @keydown.enter.prevent>
+      <el-form :model="modelForm"
+               label-width="140px"
+               label-position="top"
+               :rules="modelRules"
+               ref="modelFormRef">
         <el-row>
+          <el-row>
+            <el-col :span="24">
+              <el-form-item label="浜у搧缂栧彿锛�"
+                            prop="productCode">
+                <el-input v-model="modelForm.productCode"
+                          placeholder="璇疯緭鍏ヤ骇鍝佺紪鍙�"
+                          clearable
+                          @keydown.enter.prevent />
+              </el-form-item>
+            </el-col>
+          </el-row>
           <el-col :span="24">
-            <el-form-item label="瑙勬牸鍨嬪彿锛�" prop="model">
-              <el-input
-                v-model="modelForm.model"
-                placeholder="璇疯緭鍏ヨ鏍煎瀷鍙�"
-                clearable
-                @keydown.enter.prevent
-              />
+            <el-form-item label="瑙勬牸鍨嬪彿锛�"
+                          prop="model">
+              <el-input v-model="modelForm.model"
+                        placeholder="璇疯緭鍏ヨ鏍煎瀷鍙�"
+                        clearable
+                        @keydown.enter.prevent />
             </el-form-item>
           </el-col>
         </el-row>
         <el-row>
           <el-col :span="24">
-            <el-form-item label="鍗曚綅锛�" prop="unit">
-              <el-input
-                v-model="modelForm.unit"
-                placeholder="璇疯緭鍏ュ崟浣�"
-                clearable
-                @keydown.enter.prevent
-              />
+            <el-form-item label="鍗曚綅锛�"
+                          prop="unit">
+              <el-input v-model="modelForm.unit"
+                        placeholder="璇疯緭鍏ュ崟浣�"
+                        clearable
+                        @keydown.enter.prevent />
             </el-form-item>
           </el-col>
         </el-row>
       </el-form>
       <template #footer>
         <div class="dialog-footer">
-          <el-button type="primary" @click="submitModelForm">纭</el-button>
+          <el-button type="primary"
+                     @click="submitModelForm">纭</el-button>
           <el-button @click="closeModelDia">鍙栨秷</el-button>
         </div>
       </template>
@@ -180,473 +177,480 @@
 </template>
 
 <script setup>
-import { nextTick, ref } from "vue";
-import { ElMessageBox } from "element-plus";
-import {
-  addOrEditProduct,
-  addOrEditProductModel,
-  delProduct,
-  delProductModel,
-  modelListPage,
-  productTreeList,
-} from "@/api/basicData/product.js";
-import ImportExcel from "./ImportExcel/index.vue";
+  import { nextTick, ref } from "vue";
+  import { ElMessageBox } from "element-plus";
+  import {
+    addOrEditProduct,
+    addOrEditProductModel,
+    delProduct,
+    delProductModel,
+    modelListPage,
+    productTreeList,
+  } from "@/api/basicData/product.js";
+  import ImportExcel from "./ImportExcel/index.vue";
 
-const { proxy } = getCurrentInstance();
-const tree = ref(null);
-const containerRef = ref(null);
-const treeKey = ref(0);
-const expandedKeySet = new Set();
-const EXPANDED_STORAGE_KEY = "basicData_product_tree_expanded_keys_v2";
+  const { proxy } = getCurrentInstance();
+  const tree = ref(null);
+  const containerRef = ref(null);
+  const treeKey = ref(0);
+  const expandedKeySet = new Set();
+  const EXPANDED_STORAGE_KEY = "basicData_product_tree_expanded_keys_v2";
 
-const loadExpandedKeys = () => {
-  if (typeof window === "undefined") {
-    return [];
-  }
-  try {
-    const saved = localStorage.getItem(EXPANDED_STORAGE_KEY);
-    return saved ? JSON.parse(saved) : [];
-  } catch (error) {
-    console.error(error);
-    return [];
-  }
-};
-
-const saveExpandedKeys = () => {
-  if (typeof window === "undefined") {
-    return;
-  }
-  localStorage.setItem(
-    EXPANDED_STORAGE_KEY,
-    JSON.stringify(Array.from(expandedKeySet))
-  );
-};
-
-loadExpandedKeys().forEach((key) => expandedKeySet.add(key));
-
-const syncExpandedKeysFromTree = () => {
-  const keys = [];
-  const walk = (nodes) => {
-    (nodes || []).forEach((item) => {
-      if (item.expanded && item.data?.id !== undefined) {
-        keys.push(item.data.id);
-      }
-      if (item.childNodes && item.childNodes.length) {
-        walk(item.childNodes);
-      }
-    });
-  };
-
-  walk(tree.value?.root?.childNodes);
-  expandedKeySet.clear();
-  keys.forEach((key) => expandedKeySet.add(key));
-  expandedKeys.value = keys;
-  saveExpandedKeys();
-};
-
-const normalizeExpandedKeys = (treeData) => {
-  const parentMap = new Map();
-  const walk = (nodes, parentId = null) => {
-    (nodes || []).forEach((item) => {
-      parentMap.set(item.id, parentId);
-      if (item.children && item.children.length) {
-        walk(item.children, item.id);
-      }
-    });
-  };
-
-  walk(treeData);
-
-  const normalizedKeys = Array.from(expandedKeySet).filter((key) => {
-    if (!parentMap.has(key)) {
-      return false;
+  const loadExpandedKeys = () => {
+    if (typeof window === "undefined") {
+      return [];
     }
-    let currentId = key;
-    while (parentMap.has(currentId)) {
-      const parentId = parentMap.get(currentId);
-      if (!parentId) {
-        return true;
-      }
-      if (!expandedKeySet.has(parentId)) {
+    try {
+      const saved = localStorage.getItem(EXPANDED_STORAGE_KEY);
+      return saved ? JSON.parse(saved) : [];
+    } catch (error) {
+      console.error(error);
+      return [];
+    }
+  };
+
+  const saveExpandedKeys = () => {
+    if (typeof window === "undefined") {
+      return;
+    }
+    localStorage.setItem(
+      EXPANDED_STORAGE_KEY,
+      JSON.stringify(Array.from(expandedKeySet))
+    );
+  };
+
+  loadExpandedKeys().forEach(key => expandedKeySet.add(key));
+
+  const syncExpandedKeysFromTree = () => {
+    const keys = [];
+    const walk = nodes => {
+      (nodes || []).forEach(item => {
+        if (item.expanded && item.data?.id !== undefined) {
+          keys.push(item.data.id);
+        }
+        if (item.childNodes && item.childNodes.length) {
+          walk(item.childNodes);
+        }
+      });
+    };
+
+    walk(tree.value?.root?.childNodes);
+    expandedKeySet.clear();
+    keys.forEach(key => expandedKeySet.add(key));
+    expandedKeys.value = keys;
+    saveExpandedKeys();
+  };
+
+  const normalizeExpandedKeys = treeData => {
+    const parentMap = new Map();
+    const walk = (nodes, parentId = null) => {
+      (nodes || []).forEach(item => {
+        parentMap.set(item.id, parentId);
+        if (item.children && item.children.length) {
+          walk(item.children, item.id);
+        }
+      });
+    };
+
+    walk(treeData);
+
+    const normalizedKeys = Array.from(expandedKeySet).filter(key => {
+      if (!parentMap.has(key)) {
         return false;
       }
-      currentId = parentId;
-    }
-    return true;
-  });
-
-  if (normalizedKeys.length !== expandedKeySet.size) {
-    expandedKeySet.clear();
-    normalizedKeys.forEach((key) => expandedKeySet.add(key));
-    saveExpandedKeys();
-  }
-};
-
-const productDia = ref(false);
-const modelDia = ref(false);
-const modelOperationType = ref("");
-const search = ref("");
-const currentId = ref("");
-const currentParentId = ref("");
-const operationType = ref("");
-const treeLoad = ref(false);
-const list = ref([]);
-const expandedKeys = ref([]);
-const tableColumn = ref([
-  {
-    label: "瑙勬牸鍨嬪彿",
-    prop: "model",
-  },
-  {
-    label: "鍗曚綅",
-    prop: "unit",
-  },
-  {
-    dataType: "action",
-    label: "鎿嶄綔",
-    align: "center",
-    operation: [
-      {
-        name: "缂栬緫",
-        type: "text",
-        clickFun: (row) => {
-          openModelDia("edit", row);
-        },
-      },
-    ],
-  },
-]);
-const tableData = ref([]);
-const tableLoading = ref(false);
-const isShowButton = ref(false);
-const selectedRows = ref([]);
-const page = reactive({
-  current: 1,
-  size: 10,
-  total: 0,
-});
-const data = reactive({
-  form: {
-    productName: "",
-  },
-  rules: {
-    productName: [
-      { required: true, message: "璇疯緭鍏�", trigger: "blur" },
-      { max: 20, message: "浜у搧鍚嶇О涓嶈兘瓒呰繃20涓瓧绗�", trigger: "blur" },
-    ],
-  },
-  modelForm: {
-    model: "",
-    unit: "",
-  },
-  modelRules: {
-    model: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
-    unit: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
-  },
-});
-const { form, rules, modelForm, modelRules } = toRefs(data);
-// 鏌ヨ浜у搧鏍�
-const getProductTreeList = () => {
-  treeLoad.value = true;
-  productTreeList()
-    .then((res) => {
-      list.value = res || [];
-      normalizeExpandedKeys(list.value);
-      expandedKeys.value = Array.from(expandedKeySet);
-      treeKey.value += 1;
-      nextTick(() => {
-        tree.value?.setDefaultExpandedKeys?.(expandedKeys.value);
-      });
-    })
-    .catch((err) => {
-      console.error(err);
-    })
-    .finally(() => {
-      treeLoad.value = false;
-    });
-};
-const handleNodeExpand = (data) => {
-  nextTick(syncExpandedKeysFromTree);
-};
-const handleNodeCollapse = (data, node) => {
-  node?.eachNode?.((item) => {
-    item.collapse();
-  });
-  nextTick(syncExpandedKeysFromTree);
-};
-// 杩囨护浜у搧鏍�
-const searchFilter = () => {
-  proxy.$refs.tree.filter(search.value);
-};
-const isTopLevelNode = (data, node) => {
-  if (node?.level !== undefined) {
-    return node.level === 1;
-  }
-  return [null, undefined, "", 0, "0"].includes(data?.parentId);
-};
-// 鎵撳紑浜у搧寮规
-const openProDia = (type, data) => {
-  if (data && type === "edit" && isTopLevelNode(data)) {
-    proxy.$modal.msgWarning("涓�绾ц妭鐐逛笉鑳界紪杈戞垨鍒犻櫎");
-    return;
-  }
-  operationType.value = type;
-  productDia.value = true;
-  form.value.productName = "";
-  if (type === "edit") {
-    form.value.productName = data.productName;
-  }
-};
-// 鎵撳紑瑙勬牸鍨嬪彿寮规
-const openModelDia = (type, data) => {
-  modelOperationType.value = type;
-  modelDia.value = true;
-  modelForm.value.model = "";
-  modelForm.value.model = "";
-  modelForm.value.id = "";
-  if (type === "edit") {
-    modelForm.value = { ...data };
-  }
-};
-// 鎻愪氦浜у搧鍚嶇О淇敼
-const submitForm = () => {
-  proxy.$refs.formRef.validate((valid) => {
-    if (valid) {
-      if (operationType.value === "add") {
-        form.value.parentId = currentId.value;
-        form.value.id = "";
-      } else if (operationType.value === "addOne") {
-        form.value.id = "";
-        form.value.parentId = "";
-      } else {
-        form.value.id = currentId.value;
-        form.value.parentId = "";
+      let currentId = key;
+      while (parentMap.has(currentId)) {
+        const parentId = parentMap.get(currentId);
+        if (!parentId) {
+          return true;
+        }
+        if (!expandedKeySet.has(parentId)) {
+          return false;
+        }
+        currentId = parentId;
       }
-      addOrEditProduct(form.value).then((res) => {
-        proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
-        closeProDia();
-        getProductTreeList();
-      });
-    }
-  });
-};
-// 鍏抽棴浜у搧寮规
-const closeProDia = () => {
-  proxy.$refs.formRef.resetFields();
-  productDia.value = false;
-};
+      return true;
+    });
 
-// 鍒犻櫎浜у搧
-const remove = (node, data) => {
-  if (isTopLevelNode(data, node)) {
-    proxy.$modal.msgWarning("涓�绾ц妭鐐逛笉鑳界紪杈戞垨鍒犻櫎");
-    return;
-  }
-  let ids = [];
-  ids.push(data.id);
-  ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "鍒犻櫎鎻愮ず", {
-    confirmButtonText: "纭",
-    cancelButtonText: "鍙栨秷",
-    type: "warning",
-  })
-    .then(() => {
-      tableLoading.value = true;
-      delProduct(ids)
-        .then((res) => {
-          proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+    if (normalizedKeys.length !== expandedKeySet.size) {
+      expandedKeySet.clear();
+      normalizedKeys.forEach(key => expandedKeySet.add(key));
+      saveExpandedKeys();
+    }
+  };
+
+  const productDia = ref(false);
+  const modelDia = ref(false);
+  const modelOperationType = ref("");
+  const search = ref("");
+  const currentId = ref("");
+  const currentParentId = ref("");
+  const operationType = ref("");
+  const treeLoad = ref(false);
+  const list = ref([]);
+  const expandedKeys = ref([]);
+  const tableColumn = ref([
+    {
+      label: "浜у搧缂栧彿",
+      prop: "productCode",
+    },
+    {
+      label: "瑙勬牸鍨嬪彿",
+      prop: "model",
+    },
+    {
+      label: "鍗曚綅",
+      prop: "unit",
+    },
+    {
+      dataType: "action",
+      label: "鎿嶄綔",
+      align: "center",
+      operation: [
+        {
+          name: "缂栬緫",
+          type: "text",
+          clickFun: row => {
+            openModelDia("edit", row);
+          },
+        },
+      ],
+    },
+  ]);
+  const tableData = ref([]);
+  const tableLoading = ref(false);
+  const isShowButton = ref(false);
+  const selectedRows = ref([]);
+  const page = reactive({
+    current: 1,
+    size: 10,
+    total: 0,
+  });
+  const data = reactive({
+    form: {
+      productName: "",
+    },
+    rules: {
+      productName: [
+        { required: true, message: "璇疯緭鍏�", trigger: "blur" },
+        { max: 20, message: "浜у搧鍚嶇О涓嶈兘瓒呰繃20涓瓧绗�", trigger: "blur" },
+      ],
+    },
+    modelForm: {
+      model: "",
+      unit: "",
+      productCode: "",
+    },
+    modelRules: {
+      model: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+      unit: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+      productCode: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+    },
+  });
+  const { form, rules, modelForm, modelRules } = toRefs(data);
+  // 鏌ヨ浜у搧鏍�
+  const getProductTreeList = () => {
+    treeLoad.value = true;
+    productTreeList()
+      .then(res => {
+        list.value = res || [];
+        normalizeExpandedKeys(list.value);
+        expandedKeys.value = Array.from(expandedKeySet);
+        treeKey.value += 1;
+        nextTick(() => {
+          tree.value?.setDefaultExpandedKeys?.(expandedKeys.value);
+        });
+      })
+      .catch(err => {
+        console.error(err);
+      })
+      .finally(() => {
+        treeLoad.value = false;
+      });
+  };
+  const handleNodeExpand = data => {
+    nextTick(syncExpandedKeysFromTree);
+  };
+  const handleNodeCollapse = (data, node) => {
+    node?.eachNode?.(item => {
+      item.collapse();
+    });
+    nextTick(syncExpandedKeysFromTree);
+  };
+  // 杩囨护浜у搧鏍�
+  const searchFilter = () => {
+    proxy.$refs.tree.filter(search.value);
+  };
+  const isTopLevelNode = (data, node) => {
+    if (node?.level !== undefined) {
+      return node.level === 1;
+    }
+    return [null, undefined, "", 0, "0"].includes(data?.parentId);
+  };
+  // 鎵撳紑浜у搧寮规
+  const openProDia = (type, data) => {
+    if (data && type === "edit" && isTopLevelNode(data)) {
+      proxy.$modal.msgWarning("涓�绾ц妭鐐逛笉鑳界紪杈戞垨鍒犻櫎");
+      return;
+    }
+    operationType.value = type;
+    productDia.value = true;
+    form.value.productName = "";
+    if (type === "edit") {
+      form.value.productName = data.productName;
+    }
+  };
+  // 鎵撳紑瑙勬牸鍨嬪彿寮规
+  const openModelDia = (type, data) => {
+    modelOperationType.value = type;
+    modelDia.value = true;
+    modelForm.value.model = "";
+    modelForm.value.unit = "";
+    modelForm.value.productCode = "";
+    modelForm.value.id = "";
+    if (type === "edit") {
+      modelForm.value = { ...data };
+    }
+  };
+  // 鎻愪氦浜у搧鍚嶇О淇敼
+  const submitForm = () => {
+    proxy.$refs.formRef.validate(valid => {
+      if (valid) {
+        if (operationType.value === "add") {
+          form.value.parentId = currentId.value;
+          form.value.id = "";
+        } else if (operationType.value === "addOne") {
+          form.value.id = "";
+          form.value.parentId = "";
+        } else {
+          form.value.id = currentId.value;
+          form.value.parentId = "";
+        }
+        addOrEditProduct(form.value).then(res => {
+          proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+          closeProDia();
           getProductTreeList();
-        })
-        .finally(() => {
-          tableLoading.value = false;
         });
-    })
-    .catch(() => {
-      proxy.$modal.msg("宸插彇娑�");
+      }
     });
-};
-// 閫夋嫨浜у搧
-const handleNodeClick = (val, node, el) => {
-  // 鍒ゆ柇鏄惁涓哄彾瀛愯妭鐐�
-  isShowButton.value = !(val.children && val.children.length > 0);
-  // 鍙湁鍙跺瓙鑺傜偣鎵嶆墽琛屼互涓嬮�昏緫
-  currentId.value = val.id;
-  currentParentId.value = val.parentId;
-  getModelList();
-};
+  };
+  // 鍏抽棴浜у搧寮规
+  const closeProDia = () => {
+    proxy.$refs.formRef.resetFields();
+    productDia.value = false;
+  };
 
-// 鎻愪氦瑙勬牸鍨嬪彿淇敼
-const submitModelForm = () => {
-  proxy.$refs.modelFormRef.validate((valid) => {
-    if (valid) {
-      modelForm.value.productId = currentId.value;
-      addOrEditProductModel(modelForm.value).then((res) => {
-        proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
-        closeModelDia();
-        getModelList();
-      });
+  // 鍒犻櫎浜у搧
+  const remove = (node, data) => {
+    if (isTopLevelNode(data, node)) {
+      proxy.$modal.msgWarning("涓�绾ц妭鐐逛笉鑳界紪杈戞垨鍒犻櫎");
+      return;
     }
-  });
-};
-// 鍏抽棴鍨嬪彿寮规
-const closeModelDia = () => {
-  proxy.$refs.modelFormRef.resetFields();
-  modelDia.value = false;
-};
-// 琛ㄦ牸閫夋嫨鏁版嵁
-const handleSelectionChange = (selection) => {
-  selectedRows.value = selection;
-};
-
-// 鏌ヨ瑙勬牸鍨嬪彿
-const pagination = (obj) => {
-  page.current = obj.page;
-  page.size = obj.limit;
-  getModelList();
-};
-const getModelList = () => {
-  tableLoading.value = true;
-  modelListPage({
-    id: currentId.value,
-    current: page.current,
-    size: page.size,
-  }).then((res) => {
-    console.log("res", res);
-    tableData.value = res.records;
-    page.total = res.total;
-    tableLoading.value = false;
-  });
-};
-// 鍒犻櫎瑙勬牸鍨嬪彿
-const handleDelete = () => {
-  let ids = [];
-  if (selectedRows.value.length > 0) {
-    ids = selectedRows.value.map((item) => item.id);
-  } else {
-    proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
-    return;
-  }
-  ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "鍒犻櫎鎻愮ず", {
-    confirmButtonText: "纭",
-    cancelButtonText: "鍙栨秷",
-    type: "warning",
-  })
-    .then(() => {
-      tableLoading.value = true;
-      delProductModel(ids)
-        .then((res) => {
-          proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
-          getModelList();
-        })
-        .finally(() => {
-          tableLoading.value = false;
-        });
+    let ids = [];
+    ids.push(data.id);
+    ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "鍒犻櫎鎻愮ず", {
+      confirmButtonText: "纭",
+      cancelButtonText: "鍙栨秷",
+      type: "warning",
     })
-    .catch(() => {
-      proxy.$modal.msg("宸插彇娑�");
+      .then(() => {
+        tableLoading.value = true;
+        delProduct(ids)
+          .then(res => {
+            proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+            getProductTreeList();
+          })
+          .finally(() => {
+            tableLoading.value = false;
+          });
+      })
+      .catch(() => {
+        proxy.$modal.msg("宸插彇娑�");
+      });
+  };
+  // 閫夋嫨浜у搧
+  const handleNodeClick = (val, node, el) => {
+    // 鍒ゆ柇鏄惁涓哄彾瀛愯妭鐐�
+    isShowButton.value = !(val.children && val.children.length > 0);
+    // 鍙湁鍙跺瓙鑺傜偣鎵嶆墽琛屼互涓嬮�昏緫
+    currentId.value = val.id;
+    currentParentId.value = val.parentId;
+    getModelList();
+  };
+
+  // 鎻愪氦瑙勬牸鍨嬪彿淇敼
+  const submitModelForm = () => {
+    proxy.$refs.modelFormRef.validate(valid => {
+      if (valid) {
+        modelForm.value.productId = currentId.value;
+        addOrEditProductModel(modelForm.value).then(res => {
+          proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+          closeModelDia();
+          getModelList();
+        });
+      }
     });
-};
-// 璋冪敤tree杩囨护鏂规硶 涓枃鑻辫繃婊�
-const filterNode = (value, data, node) => {
-  if (!value) {
-    //濡傛灉鏁版嵁涓虹┖锛屽垯杩斿洖true,鏄剧ず鎵�鏈夌殑鏁版嵁椤�
-    return true;
-  }
-  // 鏌ヨ鍒楄〃鏄惁鏈夊尮閰嶆暟鎹紝灏嗗�煎皬鍐欙紝鍖归厤鑻辨枃鏁版嵁
-  let val = value.toLowerCase();
-  return chooseNode(val, data, node); // 璋冪敤杩囨护浜屽眰鏂规硶
-};
-// 杩囨护鐖惰妭鐐� / 瀛愯妭鐐� (濡傛灉杈撳叆鐨勫弬鏁版槸鐖惰妭鐐逛笖鑳藉尮閰嶏紝鍒欒繑鍥炶鑺傜偣浠ュ強鍏朵笅鐨勬墍鏈夊瓙鑺傜偣锛涘鏋滃弬鏁版槸瀛愯妭鐐癸紝鍒欒繑鍥炶鑺傜偣鐨勭埗鑺傜偣銆俷ame鏄腑鏂囧瓧绗︼紝enName鏄嫳鏂囧瓧绗�.
-const chooseNode = (value, data, node) => {
-  if (data.label.indexOf(value) !== -1) {
-    return true;
-  }
-  const level = node.level;
-  // 濡傛灉浼犲叆鐨勮妭鐐规湰韬氨鏄竴绾ц妭鐐瑰氨涓嶇敤鏍¢獙浜�
-  if (level === 1) {
-    return false;
-  }
-  // 鍏堝彇褰撳墠鑺傜偣鐨勭埗鑺傜偣
-  let parentData = node.parent;
-  // 閬嶅巻褰撳墠鑺傜偣鐨勭埗鑺傜偣
-  let index = 0;
-  while (index < level - 1) {
-    // 濡傛灉鍖归厤鍒扮洿鎺ヨ繑鍥烇紝姝ゅname鍊兼槸涓枃瀛楃锛宔nName鏄嫳鏂囧瓧绗︺�傚垽鏂尮閰嶄腑鑻辨枃杩囨护
-    if (parentData.data.label.indexOf(value) !== -1) {
+  };
+  // 鍏抽棴鍨嬪彿寮规
+  const closeModelDia = () => {
+    proxy.$refs.modelFormRef.resetFields();
+    modelDia.value = false;
+  };
+  // 琛ㄦ牸閫夋嫨鏁版嵁
+  const handleSelectionChange = selection => {
+    selectedRows.value = selection;
+  };
+
+  // 鏌ヨ瑙勬牸鍨嬪彿
+  const pagination = obj => {
+    page.current = obj.page;
+    page.size = obj.limit;
+    getModelList();
+  };
+  const getModelList = () => {
+    tableLoading.value = true;
+    modelListPage({
+      id: currentId.value,
+      current: page.current,
+      size: page.size,
+    }).then(res => {
+      console.log("res", res);
+      tableData.value = res.records;
+      page.total = res.total;
+      tableLoading.value = false;
+    });
+  };
+  // 鍒犻櫎瑙勬牸鍨嬪彿
+  const handleDelete = () => {
+    let ids = [];
+    if (selectedRows.value.length > 0) {
+      ids = selectedRows.value.map(item => item.id);
+    } else {
+      proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
+      return;
+    }
+    ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "鍒犻櫎鎻愮ず", {
+      confirmButtonText: "纭",
+      cancelButtonText: "鍙栨秷",
+      type: "warning",
+    })
+      .then(() => {
+        tableLoading.value = true;
+        delProductModel(ids)
+          .then(res => {
+            proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+            getModelList();
+          })
+          .finally(() => {
+            tableLoading.value = false;
+          });
+      })
+      .catch(() => {
+        proxy.$modal.msg("宸插彇娑�");
+      });
+  };
+  // 璋冪敤tree杩囨护鏂规硶 涓枃鑻辫繃婊�
+  const filterNode = (value, data, node) => {
+    if (!value) {
+      //濡傛灉鏁版嵁涓虹┖锛屽垯杩斿洖true,鏄剧ず鎵�鏈夌殑鏁版嵁椤�
       return true;
     }
-    // 鍚﹀垯鐨勮瘽鍐嶅線涓婁竴灞傚仛鍖归厤
-    parentData = parentData.parent;
-    index++;
-  }
-  // 娌″尮閰嶅埌杩斿洖false
-  return false;
-};
-getProductTreeList();
+    // 鏌ヨ鍒楄〃鏄惁鏈夊尮閰嶆暟鎹紝灏嗗�煎皬鍐欙紝鍖归厤鑻辨枃鏁版嵁
+    let val = value.toLowerCase();
+    return chooseNode(val, data, node); // 璋冪敤杩囨护浜屽眰鏂规硶
+  };
+  // 杩囨护鐖惰妭鐐� / 瀛愯妭鐐� (濡傛灉杈撳叆鐨勫弬鏁版槸鐖惰妭鐐逛笖鑳藉尮閰嶏紝鍒欒繑鍥炶鑺傜偣浠ュ強鍏朵笅鐨勬墍鏈夊瓙鑺傜偣锛涘鏋滃弬鏁版槸瀛愯妭鐐癸紝鍒欒繑鍥炶鑺傜偣鐨勭埗鑺傜偣銆俷ame鏄腑鏂囧瓧绗︼紝enName鏄嫳鏂囧瓧绗�.
+  const chooseNode = (value, data, node) => {
+    if (data.label.indexOf(value) !== -1) {
+      return true;
+    }
+    const level = node.level;
+    // 濡傛灉浼犲叆鐨勮妭鐐规湰韬氨鏄竴绾ц妭鐐瑰氨涓嶇敤鏍¢獙浜�
+    if (level === 1) {
+      return false;
+    }
+    // 鍏堝彇褰撳墠鑺傜偣鐨勭埗鑺傜偣
+    let parentData = node.parent;
+    // 閬嶅巻褰撳墠鑺傜偣鐨勭埗鑺傜偣
+    let index = 0;
+    while (index < level - 1) {
+      // 濡傛灉鍖归厤鍒扮洿鎺ヨ繑鍥烇紝姝ゅname鍊兼槸涓枃瀛楃锛宔nName鏄嫳鏂囧瓧绗︺�傚垽鏂尮閰嶄腑鑻辨枃杩囨护
+      if (parentData.data.label.indexOf(value) !== -1) {
+        return true;
+      }
+      // 鍚﹀垯鐨勮瘽鍐嶅線涓婁竴灞傚仛鍖归厤
+      parentData = parentData.parent;
+      index++;
+    }
+    // 娌″尮閰嶅埌杩斿洖false
+    return false;
+  };
+  getProductTreeList();
 </script>
 
 <style scoped>
-.product-view {
-  display: flex;
-}
-.left {
-  width: 450px;
-  min-width: 450px;
-  padding: 16px;
-  background: #ffffff;
-}
-.right {
-  flex: 1;
-  min-width: 0;
-  padding: 16px;
-  margin-left: 20px;
-  background: #ffffff;
-}
-.custom-tree-node {
-  flex: 1;
-  min-width: 0;
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-  font-size: 14px;
-  padding-right: 8px;
-}
-.tree-node-content {
-  flex: 1;
-  min-width: 0;
-  display: flex;
-  align-items: center;
-  height: 100%;
-  overflow: hidden;
-}
-.tree-node-content .orange-icon {
-  flex-shrink: 0;
-}
-.tree-node-label {
-  overflow: hidden;
-  text-overflow: ellipsis;
-  white-space: nowrap;
-}
-.orange-icon {
-  color: orange;
-  font-size: 18px;
-  margin-right: 8px; /* 鍥炬爣涓庢枃瀛椾箣闂村姞鐐归棿璺� */
-}
-.product-tree-scroll {
-  scrollbar-width: thin;
-  scrollbar-color: #c0c4cc #f5f7fa;
-}
-.product-tree-scroll::-webkit-scrollbar {
-  width: 8px;
-}
-.product-tree-scroll::-webkit-scrollbar-track {
-  background: #f5f7fa;
-  border-radius: 4px;
-}
-.product-tree-scroll::-webkit-scrollbar-thumb {
-  background: #c0c4cc;
-  border-radius: 4px;
-}
-.product-tree-scroll::-webkit-scrollbar-thumb:hover {
-  background: #909399;
-}
+  .product-view {
+    display: flex;
+  }
+  .left {
+    width: 450px;
+    min-width: 450px;
+    padding: 16px;
+    background: #ffffff;
+  }
+  .right {
+    flex: 1;
+    min-width: 0;
+    padding: 16px;
+    margin-left: 20px;
+    background: #ffffff;
+  }
+  .custom-tree-node {
+    flex: 1;
+    min-width: 0;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    font-size: 14px;
+    padding-right: 8px;
+  }
+  .tree-node-content {
+    flex: 1;
+    min-width: 0;
+    display: flex;
+    align-items: center;
+    height: 100%;
+    overflow: hidden;
+  }
+  .tree-node-content .orange-icon {
+    flex-shrink: 0;
+  }
+  .tree-node-label {
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+  }
+  .orange-icon {
+    color: orange;
+    font-size: 18px;
+    margin-right: 8px; /* 鍥炬爣涓庢枃瀛椾箣闂村姞鐐归棿璺� */
+  }
+  .product-tree-scroll {
+    scrollbar-width: thin;
+    scrollbar-color: #c0c4cc #f5f7fa;
+  }
+  .product-tree-scroll::-webkit-scrollbar {
+    width: 8px;
+  }
+  .product-tree-scroll::-webkit-scrollbar-track {
+    background: #f5f7fa;
+    border-radius: 4px;
+  }
+  .product-tree-scroll::-webkit-scrollbar-thumb {
+    background: #c0c4cc;
+    border-radius: 4px;
+  }
+  .product-tree-scroll::-webkit-scrollbar-thumb:hover {
+    background: #909399;
+  }
 </style>
diff --git a/src/views/collaborativeApproval/rulesRegulationsManagement/index.vue b/src/views/collaborativeApproval/rulesRegulationsManagement/index.vue
index eb0802e..f7ba9d9 100644
--- a/src/views/collaborativeApproval/rulesRegulationsManagement/index.vue
+++ b/src/views/collaborativeApproval/rulesRegulationsManagement/index.vue
@@ -212,14 +212,7 @@
         </el-table-column>
       </el-table>
     </el-dialog>
-    <FileListDialog ref="fileListDialogRef"
-                    v-model="fileDialogVisible"
-                    :show-upload-button="true"
-                    :show-delete-button="true"
-                    :delete-method="handleAttachmentDelete"
-                    :rules-regulations-management-id="currentFileRuleId"
-                    :name-column-label="'闄勪欢鍚嶇О'"
-                    @upload="handleAttachmentUpload"/>
+    <FileList v-if="fileDialogVisible"  v-model:visible="fileDialogVisible" record-type="rules_regulations_management" :record-id="recordId"  />
   </div>
 </template>
 
@@ -235,7 +228,7 @@
     addReadingStatus,
     updateReadingStatus,
   } from "@/api/collaborativeApproval/sealManagement.js";
-  import FileListDialog from "@/components/Dialog/FileListDialog.vue";
+  const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue"));
   import {
     listRuleFiles,
     delRuleFile,
@@ -254,14 +247,7 @@
     total: 0,
   });
   // 闄勪欢寮圭獥
-  const fileDialogVisible = ref(false);
-  const fileListDialogRef = ref(null);
   const currentFileRuleId = ref(null);
-  const filePage = reactive({
-    current: 1,
-    size: 1000,
-    total: 0,
-  });
   // 瑙勭珷鍒跺害鐩稿叧
   const showRegulationDialog = ref(false);
   const showRegulationDetailDialog = ref(false);
@@ -564,63 +550,15 @@
     );
   };
 
-  // 闄勪欢锛氭煡璇�
-  const fetchRuleFiles = async rulesRegulationsManagementId => {
-    const params = {
-      current: filePage.current,
-      size: filePage.size,
-      rulesRegulationsManagementId,
-    };
-    const res = await listRuleFiles(params);
-    const records = res?.data?.records || [];
-    filePage.total = res?.data?.total || records.length;
-    const mapped = records.map(item => ({
-      id: item.id,
-      name: item.fileName || item.name,
-      url: item.fileUrl || item.url,
-      raw: item,
-    }));
-    fileListDialogRef.value?.setList(mapped);
-  };
-
   // 鎵撳紑闄勪欢寮圭獥
-  const openFileDialog = async row => {
-    currentFileRuleId.value = row.id;
-    fileDialogVisible.value = true;
-    await fetchRuleFiles(row.id);
-  };
+  const recordId =ref(0)
+  const fileDialogVisible = ref(false)
 
-  // 鍒锋柊闄勪欢鍒楄〃
-  const refreshFileList = async () => {
-    if (!currentFileRuleId.value) return;
-    await fetchRuleFiles(currentFileRuleId.value);
-  };
-
-  // 涓婁紶闄勪欢锛堢敱瀛愮粍浠惰Е鍙戯級
-  const handleAttachmentUpload = async filePayload => {
-    if (!currentFileRuleId.value) return;
-    const payload = {
-      name: filePayload?.fileName || filePayload?.name,
-      url: filePayload?.fileUrl || filePayload?.url,
-      rulesRegulationsManagementId: currentFileRuleId.value,
-    };
-    await addRuleFile(payload);
-    ElMessage.success("鏂囦欢涓婁紶鎴愬姛");
-    await refreshFileList();
-  };
-
-  // 鍒犻櫎闄勪欢
-  const handleAttachmentDelete = async row => {
-    if (!row?.id) return false;
-    try {
-      await ElMessageBox.confirm("纭鍒犻櫎璇ラ檮浠讹紵", "鎻愮ず", { type: "warning" });
-    } catch {
-      return false;
-    }
-    await delRuleFile([row.id]);
-    ElMessage.success("鍒犻櫎鎴愬姛");
-    await refreshFileList();
-  };
+  // 鎵撳紑闄勪欢寮规
+  const openFileDialog = async (row) => {
+    recordId.value = row.id
+    fileDialogVisible.value = true
+  }
 
   // 鑾峰彇瑙勭珷鍒跺害鍒楄〃鏁版嵁
   const getRegulationList = async () => {
diff --git a/src/views/customerService/afterSalesHandling/index.vue b/src/views/customerService/afterSalesHandling/index.vue
index 57cc2eb..d023f51 100644
--- a/src/views/customerService/afterSalesHandling/index.vue
+++ b/src/views/customerService/afterSalesHandling/index.vue
@@ -102,33 +102,19 @@
 			></PIMTable>
 		</div>
 		<form-dia ref="formDia" @close="handleQuery"></form-dia>
-		<FileListDialog
-			ref="fileListRef"
-			v-model="fileListDialogVisible"
-			title="鍞悗闄勪欢"
-			:show-upload-button="true"
-			:show-delete-button="true"
-			:upload-method="handleFileUpload"
-			:delete-method="handleFileDelete"
-		/>
-	</div>
+    <FileList v-if="fileDialogVisible"  v-model:visible="fileDialogVisible" record-type="after_sales_service" :record-id="recordId"  />
+  </div>
 </template>
 
 <script setup>
-import { onMounted, ref, reactive, toRefs, getCurrentInstance, nextTick } from "vue";
+import {onMounted, ref, reactive, toRefs, getCurrentInstance, nextTick, defineAsyncComponent} from "vue";
 import FormDia from "@/views/customerService/afterSalesHandling/components/formDia.vue";
-import FileListDialog from "@/components/Dialog/FileListDialog.vue";
 import { ElMessageBox } from "element-plus";
-import request from "@/utils/request";
-import { getToken } from "@/utils/auth";
 import {
 	afterSalesServiceListPage,
-	afterSalesServiceFileListPage,
-	afterSalesServiceFileDel,
 } from "@/api/customerService/index.js";
-import useUserStore from "@/store/modules/user.js";
 const { proxy } = getCurrentInstance();
-const userStore = useUserStore()
+const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue"));
 
 const data = reactive({
 	searchForm: {
@@ -303,144 +289,15 @@
   })
 }
 
+
+// 鎵撳紑闄勪欢寮圭獥
+const recordId =ref(0)
+const fileDialogVisible = ref(false)
+
 // 鎵撳紑闄勪欢寮规
 const openFilesFormDia = async (row) => {
-	currentFileRow.value = row
-	try {
-		const res = await afterSalesServiceFileListPage({
-			afterSalesServiceId: row.id,
-			current: 1,
-			size: 100,
-		})
-		if (res.code === 200 && fileListRef.value) {
-			const fileList = (res.data?.records || []).map((item) => ({
-				name: item.name || item.fileName,
-				url: item.url || item.fileUrl,
-				id: item.id,
-				...item,
-			}))
-			fileListRef.value.open(fileList)
-			fileListDialogVisible.value = true
-		} else {
-			fileListRef.value?.open([])
-			fileListDialogVisible.value = true
-		}
-	} catch (error) {
-		proxy.$modal.msgError("鑾峰彇闄勪欢鍒楄〃澶辫触")
-		fileListRef.value?.open([])
-		fileListDialogVisible.value = true
-	}
-}
-
-// 涓婁紶闄勪欢
-const handleFileUpload = async () => {
-	if (!currentFileRow.value) {
-		proxy.$modal.msgWarning("璇峰厛閫夋嫨鏁版嵁")
-		return
-	}
-	return new Promise((resolve) => {
-		const input = document.createElement("input")
-		input.type = "file"
-		input.style.display = "none"
-		input.onchange = async (e) => {
-			const file = e.target.files[0]
-			if (!file) {
-				resolve(null)
-				return
-			}
-			try {
-				const formData = new FormData()
-				formData.append("file", file)
-				formData.append("id", currentFileRow.value.id)
-				const uploadRes = await request({
-					url: "/afterSalesService/file/upload",
-					method: "post",
-					data: formData,
-					headers: {
-						"Content-Type": "multipart/form-data",
-						Authorization: `Bearer ${getToken()}`,
-					},
-				})
-				if (uploadRes.code === 200) {
-					proxy.$modal.msgSuccess("鏂囦欢涓婁紶鎴愬姛")
-					// 閲嶆柊鑾峰彇鏂囦欢鍒楄〃
-					const listRes = await afterSalesServiceFileListPage({
-						afterSalesServiceId: currentFileRow.value.id,
-						current: 1,
-						size: 100,
-					})
-					if (listRes.code === 200 && fileListRef.value) {
-						const fileList = (listRes.data?.records || []).map((item) => ({
-							name: item.fileName,
-							url: item.fileUrl,
-							id: item.id,
-							...item,
-						}))
-						fileListRef.value.setList(fileList)
-					}
-					resolve({ name: file.name, url: "", id: null })
-				} else {
-					proxy.$modal.msgError(uploadRes.msg || "鏂囦欢涓婁紶澶辫触")
-					resolve(null)
-				}
-			} catch (err) {
-				proxy.$modal.msgError("鏂囦欢涓婁紶澶辫触")
-				resolve(null)
-			} finally {
-				document.body.removeChild(input)
-			}
-		}
-		document.body.appendChild(input)
-		input.click()
-	})
-}
-
-// 鍒犻櫎闄勪欢
-const handleFileDelete = async (row) => {
-	try {
-		// 娣诲姞纭瀵硅瘽妗�
-		const confirmResult = await ElMessageBox.confirm(
-			'纭畾瑕佸垹闄よ繖涓檮浠跺悧锛�',
-			'鍒犻櫎纭',
-			{
-				confirmButtonText: '纭畾',
-				cancelButtonText: '鍙栨秷',
-				type: 'warning'
-			}
-		)
-
-		if (confirmResult === 'confirm') {
-			const res = await afterSalesServiceFileDel(row.id)
-			if (res.code === 200) {
-				proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛")
-				if (currentFileRow.value && fileListRef.value) {
-					const listRes = await afterSalesServiceFileListPage({
-						afterSalesServiceId: currentFileRow.value.id,
-						current: 1,
-						size: 100,
-					})
-					if (listRes.code === 200) {
-						const fileList = (listRes.data?.records || []).map((item) => ({
-							name: item.fileName,
-							url: item.fileUrl,
-							id: item.id,
-							...item,
-						}))
-						fileListRef.value.setList(fileList)
-					}
-				}
-			} else {
-				proxy.$modal.msgError(res.msg || "鍒犻櫎澶辫触")
-				return false
-			}
-		}
-	} catch (error) {
-		// 濡傛灉鐢ㄦ埛鍙栨秷鍒犻櫎锛屼笉鏄剧ず閿欒淇℃伅
-		if (error !== 'cancel') {
-			proxy.$modal.msgError("鍒犻櫎澶辫触")
-		}
-		return false
-	}
+  recordId.value = row.id
+  fileDialogVisible.value = true
 }
 
 // 鏌ヨ鍒楄〃
diff --git a/src/views/equipmentManagement/measurementEquipment/components/calibrationDia.vue b/src/views/equipmentManagement/measurementEquipment/components/calibrationDia.vue
index b7fa07e..923dd2c 100644
--- a/src/views/equipmentManagement/measurementEquipment/components/calibrationDia.vue
+++ b/src/views/equipmentManagement/measurementEquipment/components/calibrationDia.vue
@@ -228,39 +228,6 @@
 	form.value.entryDate = getCurrentDate();
 }
 
-// 涓婁紶鍓嶆牎妫�
-function handleBeforeUpload(file) {
-	proxy.$modal.loading("姝e湪涓婁紶鏂囦欢锛岃绋嶅��...");
-	return true;
-}
-// 涓婁紶澶辫触
-function handleUploadError(err) {
-	proxy.$modal.msgError("涓婁紶鏂囦欢澶辫触");
-	proxy.$modal.closeLoading();
-}
-// 涓婁紶鎴愬姛鍥炶皟
-function handleUploadSuccess(res, file, uploadFiles) {
-	proxy.$modal.closeLoading();
-	if (res.code === 200) {
-		file.tempId = res.data.tempId;
-		form.value.tempFileIds.push(file.tempId);
-		proxy.$modal.msgSuccess("涓婁紶鎴愬姛");
-	} else {
-		proxy.$modal.msgError(res.msg);
-		proxy.$refs.fileUpload.handleRemove(file);
-	}
-}
-// 绉婚櫎鏂囦欢
-function handleRemove(file) {
-	if (operationType.value === "edit") {
-		let ids = [];
-		ids.push(file.id);
-		delLedgerFile(ids).then((res) => {
-			proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
-		});
-	}
-}
-
 // 澶勭悊鏈夋晥鏃ユ湡杈撳叆锛屽彧鍏佽姝f暣鏁�
 const handleValidInput = (value) => {
 	if (value === '' || value === null || value === undefined) {
diff --git a/src/views/financialManagement/expenseManagement/index.vue b/src/views/financialManagement/expenseManagement/index.vue
index ac55d01..173f8e1 100644
--- a/src/views/financialManagement/expenseManagement/index.vue
+++ b/src/views/financialManagement/expenseManagement/index.vue
@@ -76,27 +76,18 @@
       </PIMTable>
     </div>
     <Modal ref="modalRef" @success="getTableData"></Modal>
-    <FileListDialog 
-      ref="fileListRef" 
-      v-model="fileListDialogVisible"
-      :show-upload-button="true"
-      :show-delete-button="true"
-      :upload-method="handleUpload"
-      :delete-method="handleFileDelete"
-    />
+    <FileList v-if="fileDialogVisible"  v-model:visible="fileDialogVisible" record-type="account_expense" :record-id="recordId"  />
   </div>
 </template>
 
 <script setup>
 import { usePaginationApi } from "@/hooks/usePaginationApi";
-import { listPage, delAccountExpense, fileListPage, fileAdd, fileDel } from "@/api/financialManagement/expenseManagement";
-import { onMounted, getCurrentInstance, ref, computed } from "vue";
+import { listPage, delAccountExpense } from "@/api/financialManagement/expenseManagement";
+import {onMounted, getCurrentInstance, ref, computed, defineAsyncComponent} from "vue";
 import Modal from "./Modal.vue";
 import { ElMessageBox, ElMessage } from "element-plus";
 import dayjs from "dayjs";
-import FileListDialog from "@/components/Dialog/FileListDialog.vue";
-import request from "@/utils/request";
-import { getToken } from "@/utils/auth";
+const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue"));
 
 defineOptions({
   name: "鏀嚭绠$悊",
@@ -108,9 +99,6 @@
 const modalRef = ref();
 const { checkout_payment } = proxy.useDict("checkout_payment");
 const { expense_types } = proxy.useDict("expense_types");
-const fileListRef = ref(null);
-const fileListDialogVisible = ref(false);
-const currentFileRow = ref(null);
 const accountType = ref('鏀嚭');
 
 const {
@@ -315,156 +303,16 @@
       proxy.$modal.msg("宸插彇娑�");
     });
 };
+
+// 鎵撳紑闄勪欢寮圭獥
+const recordId =ref(0)
+const fileDialogVisible = ref(false)
+
 // 鎵撳紑闄勪欢寮规
 const openFilesFormDia = async (row) => {
-  currentFileRow.value = row;
-  accountType.value = '鏀嚭';
-  try {
-    const res = await fileListPage({
-      accountId: row.id,
-      accountType: accountType.value,
-      current: 1,
-      size: 100
-    });
-    if (res.code === 200 && fileListRef.value) {
-      // 灏嗘暟鎹浆鎹负 FileListDialog 闇�瑕佺殑鏍煎紡
-      const fileList = (res.data?.records || []).map(item => ({
-        name: item.name,
-        url: item.url,
-        id: item.id,
-        ...item
-      }));
-      fileListRef.value.open(fileList);
-      fileListDialogVisible.value = true;
-    }
-  } catch (error) {
-    proxy.$modal.msgError("鑾峰彇闄勪欢鍒楄〃澶辫触");
-  }
-};
-
-// 涓婁紶闄勪欢
-const handleUpload = async () => {
-  if (!currentFileRow.value) {
-    proxy.$modal.msgWarning("璇峰厛閫夋嫨鏁版嵁");
-    return null;
-  }
-  
-  return new Promise((resolve) => {
-    // 鍒涘缓涓�涓殣钘忕殑鏂囦欢杈撳叆鍏冪礌
-    const input = document.createElement('input');
-    input.type = 'file';
-    input.style.display = 'none';
-    input.onchange = async (e) => {
-      const file = e.target.files[0];
-      if (!file) {
-        resolve(null);
-        return;
-      }
-      
-      try {
-        // 浣跨敤 FormData 涓婁紶鏂囦欢
-        const formData = new FormData();
-        formData.append('file', file);
-        
-        const uploadRes = await request({
-          url: '/file/upload',
-          method: 'post',
-          data: formData,
-          headers: {
-            'Content-Type': 'multipart/form-data',
-            Authorization: `Bearer ${getToken()}`
-          }
-        });
-        
-        if (uploadRes.code === 200) {
-          // 淇濆瓨闄勪欢淇℃伅
-          const fileData = {
-            accountId: currentFileRow.value.id,
-            accountType: accountType.value,
-            name: uploadRes.data.originalName || file.name,
-            url: uploadRes.data.tempPath || uploadRes.data.url
-          };
-          
-          const saveRes = await fileAdd(fileData);
-          if (saveRes.code === 200) {
-            proxy.$modal.msgSuccess("鏂囦欢涓婁紶鎴愬姛");
-            // 閲嶆柊鍔犺浇鏂囦欢鍒楄〃
-            const listRes = await fileListPage({
-              accountId: currentFileRow.value.id,
-              accountType: accountType.value,
-              current: 1,
-              size: 100
-            });
-            if (listRes.code === 200 && fileListRef.value) {
-              const fileList = (listRes.data?.records || []).map(item => ({
-                name: item.name,
-                url: item.url,
-                id: item.id,
-                ...item
-              }));
-              fileListRef.value.setList(fileList);
-            }
-            // 杩斿洖鏂版枃浠朵俊鎭�
-            resolve({
-              name: fileData.name,
-              url: fileData.url,
-              id: saveRes.data?.id
-            });
-          } else {
-            proxy.$modal.msgError(saveRes.msg || "鏂囦欢淇濆瓨澶辫触");
-            resolve(null);
-          }
-        } else {
-          proxy.$modal.msgError(uploadRes.msg || "鏂囦欢涓婁紶澶辫触");
-          resolve(null);
-        }
-      } catch (error) {
-        proxy.$modal.msgError("鏂囦欢涓婁紶澶辫触");
-        resolve(null);
-      } finally {
-        document.body.removeChild(input);
-      }
-    };
-    
-    document.body.appendChild(input);
-    input.click();
-  });
-};
-
-// 鍒犻櫎闄勪欢
-const handleFileDelete = async (row) => {
-  try {
-    const res = await fileDel([row.id]);
-    if (res.code === 200) {
-      proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
-      // 閲嶆柊鍔犺浇鏂囦欢鍒楄〃
-      if (currentFileRow.value && fileListRef.value) {
-        const listRes = await fileListPage({
-          accountId: currentFileRow.value.id,
-          accountType: accountType.value,
-          current: 1,
-          size: 100
-        });
-        if (listRes.code === 200) {
-          const fileList = (listRes.data?.records || []).map(item => ({
-            name: item.name,
-            url: item.url,
-            id: item.id,
-            ...item
-          }));
-          fileListRef.value.setList(fileList);
-        }
-      }
-      return true; // 杩斿洖 true 琛ㄧず鍒犻櫎鎴愬姛锛岀粍浠朵細鏇存柊鍒楄〃
-    } else {
-      proxy.$modal.msgError(res.msg || "鍒犻櫎澶辫触");
-      return false;
-    }
-  } catch (error) {
-    proxy.$modal.msgError("鍒犻櫎澶辫触");
-    return false;
-  }
-};
+  recordId.value = row.id
+  fileDialogVisible.value = true
+}
 
 onMounted(() => {
   getTableData();
diff --git a/src/views/financialManagement/revenueManagement/index.vue b/src/views/financialManagement/revenueManagement/index.vue
index e2eb28e..bcef5b6 100644
--- a/src/views/financialManagement/revenueManagement/index.vue
+++ b/src/views/financialManagement/revenueManagement/index.vue
@@ -3,22 +3,22 @@
     <el-form :model="filters" :inline="true">
       <el-form-item label="鏀跺叆鏃ユ湡:">
         <el-date-picker v-model="filters.entryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="daterange"
-                        placeholder="璇烽�夋嫨" clearable @change="changeDaterange" />
+                        placeholder="璇烽�夋嫨" clearable @change="changeDaterange"/>
       </el-form-item>
       <el-form-item label="鏀舵鏂瑰紡:">
         <el-select
-                v-model="filters.incomeMethodLabel"
-                placeholder="璇烽�夋嫨"
-                clearable
-                style="width: 200px;"
-              >
-                <el-option
-                  v-for="item in incomeMethodOptions"
-                  :key="item.value"
-                  :label="item.label"
-                  :value="item.value"
-                />
-              </el-select>
+            v-model="filters.incomeMethodLabel"
+            placeholder="璇烽�夋嫨"
+            clearable
+            style="width: 200px;"
+        >
+          <el-option
+              v-for="item in incomeMethodOptions"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+          />
+        </el-select>
       </el-form-item>
       <el-form-item>
         <el-button type="primary" @click="getTableData">鎼滅储</el-button>
@@ -29,32 +29,32 @@
       <div class="actions">
         <div></div>
         <div>
-          <el-button type="primary" @click="add" icon="Plus"> 鏂板 </el-button>
+          <el-button type="primary" @click="add" icon="Plus"> 鏂板</el-button>
           <el-button @click="handleOut" icon="download">瀵煎嚭</el-button>
           <el-button
-            type="danger"
-            icon="Delete"
-            :disabled="multipleList.length <= 0 || hasBusinessIdInSelection"
-            @click="handleBatchDelete"
+              type="danger"
+              icon="Delete"
+              :disabled="multipleList.length <= 0 || hasBusinessIdInSelection"
+              @click="handleBatchDelete"
           >
             鎵归噺鍒犻櫎
           </el-button>
         </div>
       </div>
       <PIMTable
-        rowKey="id"
-        isSelection
-        :column="columns"
-        :tableData="dataList"
-        :page="{
+          rowKey="id"
+          isSelection
+          :column="columns"
+          :tableData="dataList"
+          :page="{
           current: pagination.currentPage,
           size: pagination.pageSize,
           total: pagination.total,
         }"
-        :isShowSummary="true"
-        :summaryMethod="summarizeMainTable"
-        @selection-change="handleSelectionChange"
-        @pagination="changePage"
+          :isShowSummary="true"
+          :summaryMethod="summarizeMainTable"
+          @selection-change="handleSelectionChange"
+          @pagination="changePage"
       >
         <template #incomeMethodSlot="{ row }">
           <el-tag>
@@ -62,18 +62,18 @@
           </el-tag>
         </template>
         <template #operation="{ row }">
-          <el-button 
-            type="primary" 
-            link 
-            :disabled="!!row.businessId"
-            @click="edit(row.id)"
+          <el-button
+              type="primary"
+              link
+              :disabled="!!row.businessId"
+              @click="edit(row.id)"
           >
             缂栬緫
           </el-button>
           <el-button
-            type="primary"
-						link
-            @click="openFilesFormDia(row)"
+              type="primary"
+              link
+              @click="openFilesFormDia(row)"
           >
             闄勪欢
           </el-button>
@@ -81,28 +81,16 @@
       </PIMTable>
     </div>
     <Modal ref="modalRef" @success="getTableData"></Modal>
-    <!--  todo 闄勪欢棰勮鐩稿叧 -->
-    <FileListDialog 
-      ref="fileListRef" 
-      v-model="fileListDialogVisible"
-      :show-upload-button="true"
-      :show-delete-button="true"
-      :upload-method="handleUpload"
-      :delete-method="handleFileDelete"
-    />
+    <FileListDialog v-if="fileListDialogVisible" :record-id="currentRecordId" record-type="account_income" v-model:visible="fileListDialogVisible"/>
   </div>
 </template>
 
 <script setup>
-import { usePaginationApi } from "@/hooks/usePaginationApi";
-import { listPage, delAccountIncome, fileListPage, fileAdd, fileDel } from "@/api/financialManagement/revenueManagement";
-import { onMounted, getCurrentInstance, ref, computed } from "vue";
-import Modal from "./Modal.vue";
-import { ElMessageBox, ElMessage } from "element-plus";
+import {usePaginationApi} from "@/hooks/usePaginationApi";
+import {listPage, delAccountIncome} from "@/api/financialManagement/revenueManagement";
+import {onMounted, getCurrentInstance, ref, computed} from "vue";
+import {ElMessageBox, ElMessage} from "element-plus";
 import dayjs from "dayjs";
-import FileListDialog from "@/components/Dialog/FileListDialog.vue";
-import request from "@/utils/request";
-import { getToken } from "@/utils/auth";
 
 defineOptions({
   name: "鏀跺叆绠$悊",
@@ -110,15 +98,14 @@
 
 // 琛ㄦ牸澶氶�夋閫変腑椤�
 const multipleList = ref([]);
-const { proxy } = getCurrentInstance();
+const {proxy} = getCurrentInstance();
 const modalRef = ref();
-const { payment_methods } = proxy.useDict("payment_methods");
-const { receipt_payment_type } = proxy.useDict("receipt_payment_type");
-const { income_types } = proxy.useDict("income_types");
+const {payment_methods} = proxy.useDict("payment_methods");
+const {receipt_payment_type} = proxy.useDict("receipt_payment_type");
+const {income_types} = proxy.useDict("income_types");
 const fileListRef = ref(null);
 const fileListDialogVisible = ref(false);
-const currentFileRow = ref(null);
-const accountType = ref('鏀跺叆');
+const currentRecordId = ref(0);
 
 const incomeMethodOptions = computed(() => {
   const merged = [...(payment_methods.value || []), ...(receipt_payment_type.value || [])];
@@ -127,7 +114,7 @@
     const label = item?.label;
     if (!label) return;
     if (!uniqueMap.has(label)) {
-      uniqueMap.set(label, { label, value: label });
+      uniqueMap.set(label, {label, value: label});
     }
   });
   return Array.from(uniqueMap.values());
@@ -142,86 +129,86 @@
   resetFilters,
   onCurrentChange,
 } = usePaginationApi(
-  listPage,
-  {
-    incomeMethodLabel: undefined,
-    entryDate: undefined,
-  },
-  [
+    listPage,
     {
-      label: "鏀跺叆鏃ユ湡",
-      prop: "incomeDate",
+      incomeMethodLabel: undefined,
+      entryDate: undefined,
     },
-    {
-      label: "鏀跺叆绫诲瀷",
-      prop: "incomeType",
-      dataType: "tag",
-      formatData: (params) => {
-        if (income_types.value.find((m) => m.value == params)) {
-          return income_types.value.find((m) => m.value == params).label;
-        } else {
-          return null
-        }
+    [
+      {
+        label: "鏀跺叆鏃ユ湡",
+        prop: "incomeDate",
       },
-    },
-    {
-      label: "瀹㈡埛鍚嶇О",
-      prop: "customerName",
-			width: '200'
+      {
+        label: "鏀跺叆绫诲瀷",
+        prop: "incomeType",
+        dataType: "tag",
+        formatData: (params) => {
+          if (income_types.value.find((m) => m.value == params)) {
+            return income_types.value.find((m) => m.value == params).label;
+          } else {
+            return null
+          }
+        },
+      },
+      {
+        label: "瀹㈡埛鍚嶇О",
+        prop: "customerName",
+        width: '200'
 
-    },
-    {
-      label: "鏀跺叆閲戦",
-      prop: "incomeMoney",
+      },
+      {
+        label: "鏀跺叆閲戦",
+        prop: "incomeMoney",
 
-    },
-    {
-      label: "鏀跺叆鎻忚堪",
-      prop: "incomeDescribed",
+      },
+      {
+        label: "鏀跺叆鎻忚堪",
+        prop: "incomeDescribed",
 
-    },
-    {
-      label: "鏀舵鏂瑰紡",
-      prop: "incomeMethodLabel",
-			align: 'center',
-			width: '100',
-      dataType: "slot",
-      slot: "incomeMethodSlot",
-    },
-    {
-      label: "鍙戠エ鍙风爜",
-      prop: "invoiceNumber",
+      },
+      {
+        label: "鏀舵鏂瑰紡",
+        prop: "incomeMethodLabel",
+        align: 'center',
+        width: '100',
+        dataType: "slot",
+        slot: "incomeMethodSlot",
+      },
+      {
+        label: "鍙戠エ鍙风爜",
+        prop: "invoiceNumber",
 
-    },
-    {
-      label: "澶囨敞",
-      prop: "note",
+      },
+      {
+        label: "澶囨敞",
+        prop: "note",
 
-    },
-    {
-      label: "褰曞叆浜�",
-      prop: "inputUser",
-    },
-    {
-      label: "褰曞叆鏃ユ湡",
-      prop: "inputTime",
+      },
+      {
+        label: "褰曞叆浜�",
+        prop: "inputUser",
+      },
+      {
+        label: "褰曞叆鏃ユ湡",
+        prop: "inputTime",
 
-    },
+      },
+      {
+        fixed: "right",
+        label: "鎿嶄綔",
+        dataType: "slot",
+        slot: "operation",
+        align: "center",
+        width: "160px",
+      },
+    ],
+    undefined,
     {
-      fixed: "right",
-      label: "鎿嶄綔",
-      dataType: "slot",
-      slot: "operation",
-      align: "center",
-      width: "160px",
-    },
-  ],
-  undefined,
-  {
-    incomeMethodLabel: (value) => ({
-      incomeMethodLabel: value || undefined,
-    }),
-  }
+      incomeMethodLabel: (value) => ({
+        incomeMethodLabel: value || undefined,
+      }),
+    }
 );
 
 // 琛ㄦ牸鍚堣锛氭敹鍏ラ噾棰�
@@ -232,8 +219,8 @@
 const getIncomeMethodLabel = (row) => {
   const methodValue = row?.incomeMethod;
   const dictList = String(row?.businessType) === "1"
-    ? receipt_payment_type.value
-    : payment_methods.value;
+      ? receipt_payment_type.value
+      : payment_methods.value;
   return dictList.find((item) => item.value == methodValue)?.label || "--";
 };
 
@@ -259,9 +246,9 @@
   }
   modalRef.value.loadForm(id);
 };
-const changePage = ({ page, limit }) => {
+const changePage = ({page, limit}) => {
   pagination.currentPage = page;
-	pagination.pageSize = limit;
+  pagination.pageSize = limit;
   onCurrentChange(page);
 };
 const deleteRow = (id) => {
@@ -283,13 +270,13 @@
       return;
     }
   }
-  
+
   ElMessageBox.confirm("姝ゆ搷浣滃皢姘镐箙鍒犻櫎璇ユ暟鎹�, 鏄惁缁х画?", "鎻愮ず", {
     confirmButtonText: "纭畾",
     cancelButtonText: "鍙栨秷",
     type: "warning",
   }).then(async () => {
-    const { code } = await delAccountIncome(id);
+    const {code} = await delAccountIncome(id);
     if (code == 200) {
       ElMessage({
         type: "success",
@@ -306,13 +293,13 @@
     proxy.$modal.msgWarning("璇烽�夋嫨瑕佸垹闄ょ殑鏁版嵁");
     return;
   }
-  
+
   // 妫�鏌ユ槸鍚︽湁 businessId
   if (hasBusinessIdInSelection.value) {
     proxy.$modal.msgWarning("閫変腑鐨勮褰曚腑鍖呭惈宸插叧鑱斾笟鍔$殑璁板綍锛屼笉鑳藉垹闄�");
     return;
   }
-  
+
   const ids = multipleList.value.map((item) => item.id);
   deleteRow(ids);
 };
@@ -336,162 +323,17 @@
     cancelButtonText: "鍙栨秷",
     type: "warning",
   })
-    .then(() => {
-      proxy.download(`/account/accountIncome/export`, {}, "鏀跺叆鍙拌处.xlsx");
-    })
-    .catch(() => {
-      proxy.$modal.msg("宸插彇娑�");
-    });
+      .then(() => {
+        proxy.download(`/account/accountIncome/export`, {}, "鏀跺叆鍙拌处.xlsx");
+      })
+      .catch(() => {
+        proxy.$modal.msg("宸插彇娑�");
+      });
 };
 // 鎵撳紑闄勪欢寮规
 const openFilesFormDia = async (row) => {
-  currentFileRow.value = row;
-  accountType.value = '鏀跺叆';
-  try {
-    const res = await fileListPage({
-      accountId: row.id,
-      accountType: accountType.value,
-      current: 1,
-      size: 100
-    });
-    if (res.code === 200 && fileListRef.value) {
-      // 灏嗘暟鎹浆鎹负 FileListDialog 闇�瑕佺殑鏍煎紡
-      const fileList = (res.data?.records || []).map(item => ({
-        name: item.name,
-        url: item.url,
-        id: item.id,
-        ...item
-      }));
-      fileListRef.value.open(fileList);
-      fileListDialogVisible.value = true;
-    }
-  } catch (error) {
-    proxy.$modal.msgError("鑾峰彇闄勪欢鍒楄〃澶辫触");
-  }
-};
-
-// 涓婁紶闄勪欢
-const handleUpload = async () => {
-  if (!currentFileRow.value) {
-    proxy.$modal.msgWarning("璇峰厛閫夋嫨鏁版嵁");
-    return null;
-  }
-  
-  return new Promise((resolve) => {
-    // 鍒涘缓涓�涓殣钘忕殑鏂囦欢杈撳叆鍏冪礌
-    const input = document.createElement('input');
-    input.type = 'file';
-    input.style.display = 'none';
-    input.onchange = async (e) => {
-      const file = e.target.files[0];
-      if (!file) {
-        resolve(null);
-        return;
-      }
-      
-      try {
-        // 浣跨敤 FormData 涓婁紶鏂囦欢
-        const formData = new FormData();
-        formData.append('file', file);
-        
-        const uploadRes = await request({
-          url: '/file/upload',
-          method: 'post',
-          data: formData,
-          headers: {
-            'Content-Type': 'multipart/form-data',
-            Authorization: `Bearer ${getToken()}`
-          }
-        });
-        
-        if (uploadRes.code === 200) {
-          // 淇濆瓨闄勪欢淇℃伅
-          const fileData = {
-            accountId: currentFileRow.value.id,
-            accountType: accountType.value,
-            name: uploadRes.data.originalName || file.name,
-            url: uploadRes.data.tempPath || uploadRes.data.url
-          };
-          
-          const saveRes = await fileAdd(fileData);
-          if (saveRes.code === 200) {
-            proxy.$modal.msgSuccess("鏂囦欢涓婁紶鎴愬姛");
-            // 閲嶆柊鍔犺浇鏂囦欢鍒楄〃
-            const listRes = await fileListPage({
-              accountId: currentFileRow.value.id,
-              accountType: accountType.value,
-              current: 1,
-              size: 100
-            });
-            if (listRes.code === 200 && fileListRef.value) {
-              const fileList = (listRes.data?.records || []).map(item => ({
-                name: item.name,
-                url: item.url,
-                id: item.id,
-                ...item
-              }));
-              fileListRef.value.setList(fileList);
-            }
-            // 杩斿洖鏂版枃浠朵俊鎭�
-            resolve({
-              name: fileData.name,
-              url: fileData.url,
-              id: saveRes.data?.id
-            });
-          } else {
-            proxy.$modal.msgError(saveRes.msg || "鏂囦欢淇濆瓨澶辫触");
-            resolve(null);
-          }
-        } else {
-          proxy.$modal.msgError(uploadRes.msg || "鏂囦欢涓婁紶澶辫触");
-          resolve(null);
-        }
-      } catch (error) {
-        proxy.$modal.msgError("鏂囦欢涓婁紶澶辫触");
-        resolve(null);
-      } finally {
-        document.body.removeChild(input);
-      }
-    };
-    
-    document.body.appendChild(input);
-    input.click();
-  });
-};
-
-// 鍒犻櫎闄勪欢
-const handleFileDelete = async (row) => {
-  try {
-    const res = await fileDel([row.id]);
-    if (res.code === 200) {
-      proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
-      // 閲嶆柊鍔犺浇鏂囦欢鍒楄〃
-      if (currentFileRow.value && fileListRef.value) {
-        const listRes = await fileListPage({
-          accountId: currentFileRow.value.id,
-          accountType: accountType.value,
-          current: 1,
-          size: 100
-        });
-        if (listRes.code === 200) {
-          const fileList = (listRes.data?.records || []).map(item => ({
-            name: item.name,
-            url: item.url,
-            id: item.id,
-            ...item
-          }));
-          fileListRef.value.setList(fileList);
-        }
-      }
-      return true; // 杩斿洖 true 琛ㄧず鍒犻櫎鎴愬姛锛岀粍浠朵細鏇存柊鍒楄〃
-    } else {
-      proxy.$modal.msgError(res.msg || "鍒犻櫎澶辫触");
-      return false;
-    }
-  } catch (error) {
-    proxy.$modal.msgError("鍒犻櫎澶辫触");
-    return false;
-  }
+  currentRecordId.value = row.id;
+  fileListDialogVisible.value = true;
 };
 
 onMounted(() => {
@@ -503,6 +345,7 @@
 .table_list {
   margin-top: unset;
 }
+
 .actions {
   display: flex;
   justify-content: space-between;
diff --git a/src/views/inventoryManagement/stockManagement/New.vue b/src/views/inventoryManagement/stockManagement/New.vue
index 1c9b333..2addb95 100644
--- a/src/views/inventoryManagement/stockManagement/New.vue
+++ b/src/views/inventoryManagement/stockManagement/New.vue
@@ -57,14 +57,7 @@
                            style="width: 100%" />
         </el-form-item>
         <el-form-item label="鎵瑰彿"
-                      prop="batchNo"
-                      :rules="[
-                {
-                required: true,
-                message: '璇疯緭鍏ユ壒鍙�',
-                trigger: 'blur',
-              }
-            ]">
+                      prop="batchNo">
           <el-input v-model="formState.batchNo"
                     placeholder="璇疯緭鍏ユ壒鍙�" />
         </el-form-item>
diff --git a/src/views/procurementManagement/procurementInvoiceLedger/index.vue b/src/views/procurementManagement/procurementInvoiceLedger/index.vue
index d82e3e7..c94d8c2 100644
--- a/src/views/procurementManagement/procurementInvoiceLedger/index.vue
+++ b/src/views/procurementManagement/procurementInvoiceLedger/index.vue
@@ -69,7 +69,7 @@
           <el-button
             type="primary"
             link
-            @click="downLoadFile(row)"
+            @click="openFileDialog(row)"
           >
             闄勪欢
           </el-button>
@@ -83,16 +83,7 @@
         </template>
       </PIMTable>
     </div>
-    <FileListDialog 
-      ref="fileListRef" 
-      v-model="fileListDialogVisible"
-      title="闄勪欢鍒楄〃"
-      :showUploadButton="true"
-      :showDeleteButton="true"
-      :deleteMethod="handleDeleteFile"
-      :uploadMethod="handleFileUpload"
-      :rulesRegulationsManagementId="currentRowId"
-    />
+    <FileList v-if="fileDialogVisible"  v-model:visible="fileDialogVisible" record-type="ticket_registration" :record-id="recordId"  />
     <EditModal ref="editmodalRef" @success="getTableData"></EditModal>
   </div>
 </template>
@@ -113,9 +104,9 @@
 import { onMounted } from "vue";
 import { ElMessageBox } from "element-plus";
 import EditModal from "./Modal/EditModal.vue";
-import FileListDialog from '@/components/Dialog/FileListDialog.vue';
 import useUserStore from "@/store/modules/user.js";
 const userStore = useUserStore();
+const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue"));
 
 defineOptions({
   name: "鏉ョエ鍙拌处",
@@ -290,143 +281,15 @@
   onCurrentChange(page);
 };
 
-const downLoadFile = row => {
-  currentRowId.value = row.id;
-  if (fileListRef.value) {
-    fileListRef.value.open(row.commonFiles || []);
-  }
-};
+// 鎵撳紑闄勪欢寮圭獥
+const recordId =ref(0)
+const fileDialogVisible = ref(false)
 
-// 涓婁紶闄勪欢锛堣嚜瀹氫箟涓婁紶鏂规硶锛�
-const handleFileUpload = async () => {
-  if (!currentRowId.value) {
-    proxy.$modal.msgWarning("缂哄皯鐧昏ID锛屾棤娉曚繚瀛橀檮浠�");
-    return;
-  }
-  
-  return new Promise((resolve) => {
-    // 鍒涘缓涓�涓殣钘忕殑鏂囦欢杈撳叆鍏冪礌
-    const input = document.createElement('input');
-    input.type = 'file';
-    input.style.display = 'none';
-    input.onchange = async (e) => {
-      const file = e.target.files[0];
-      if (!file) {
-        resolve(null);
-        return;
-      }
-      
-      try {
-        // 浣跨敤 FormData 涓婁紶鏂囦欢
-        const formData = new FormData();
-        formData.append('file', file);
-        formData.append('type', '4'); // type 鍙傛暟锛岀敤鎴锋湭鎸囧畾鍏蜂綋鍊硷紝鍏堜紶绌哄瓧绗︿覆
-        formData.append('id', currentRowId.value); // 褰撳墠琛岀殑 id
-        
-        const uploadRes = await request({
-          url: '/file/uploadByCommon',
-          method: 'post',
-          data: formData,
-          headers: {
-            'Content-Type': 'multipart/form-data',
-            Authorization: `Bearer ${getToken()}`
-          }
-        });
-        
-        if (uploadRes.code === 200) {
-          proxy.$modal.msgSuccess("闄勪欢涓婁紶鎴愬姛");
-          
-          // 鍒锋柊鍒楄〃鑾峰彇鏈�鏂版暟鎹�
-          await new Promise((resolveRefresh) => {
-            // 璋冪敤 API 鑾峰彇鏈�鏂板垪琛ㄦ暟鎹�
-            productRecordPage({
-              ...filters,
-              current: pagination.currentPage,
-              size: pagination.pageSize
-            }).then(({ code, data }) => {
-              if (code === 200) {
-                // 鏇存柊鏁版嵁鍒楄〃
-                dataList.value = data.records;
-                pagination.total = data.total;
-                
-                // 浠庡閮ㄦ暟鎹幏鍙� commonFiles
-                const currentRow = dataList.value.find(row => row.id === currentRowId.value);
-                if (currentRow && fileListRef.value) {
-                  // 鍒锋柊闄勪欢鍒楄〃锛屼娇鐢ㄤ粠澶栭儴鑾峰彇鐨勬渶鏂� commonFiles
-                  fileListRef.value.open(currentRow.commonFiles || []);
-                }
-                resolveRefresh();
-              } else {
-                resolveRefresh();
-              }
-            }).catch(() => {
-              resolveRefresh();
-            });
-          });
-          
-          resolve({
-            name: uploadRes.data?.originalName || file.name,
-            url: uploadRes.data?.tempPath || uploadRes.data?.url,
-            id: uploadRes.data?.id
-          });
-        } else {
-          proxy.$modal.msgError(uploadRes.msg || "鏂囦欢涓婁紶澶辫触");
-          resolve(null);
-        }
-      } catch (error) {
-        console.error("闄勪欢涓婁紶澶辫触:", error);
-        proxy.$modal.msgError("闄勪欢涓婁紶澶辫触");
-        resolve(null);
-      } finally {
-        document.body.removeChild(input);
-      }
-    };
-    
-    document.body.appendChild(input);
-    input.click();
-  });
-};
-
-// 鍒犻櫎闄勪欢
-const handleDeleteFile = async (file) => {
-  try {
-    await delCommonFile([file.id]);
-    proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
-    
-    // 鍒锋柊鍒楄〃鑾峰彇鏈�鏂版暟鎹�
-    await new Promise((resolveRefresh) => {
-      // 璋冪敤 API 鑾峰彇鏈�鏂板垪琛ㄦ暟鎹�
-      productRecordPage({
-        ...filters,
-        current: pagination.currentPage,
-        size: pagination.pageSize
-      }).then(({ code, data }) => {
-        if (code === 200) {
-          // 鏇存柊鏁版嵁鍒楄〃
-          dataList.value = data.records;
-          pagination.total = data.total;
-          
-          // 浠庡閮ㄦ暟鎹幏鍙� commonFiles
-          const currentRow = dataList.value.find(row => row.id === currentRowId.value);
-          if (currentRow && fileListRef.value) {
-            // 鍒锋柊闄勪欢鍒楄〃锛屼娇鐢ㄤ粠澶栭儴鑾峰彇鐨勬渶鏂� commonFiles
-            fileListRef.value.open(currentRow.commonFiles || []);
-          }
-          resolveRefresh();
-        } else {
-          resolveRefresh();
-        }
-      }).catch(() => {
-        resolveRefresh();
-      });
-    });
-    
-    return true;
-  } catch (error) {
-    proxy.$modal.msgError("鍒犻櫎澶辫触");
-    return false;
-  }
-};
+// 鎵撳紑闄勪欢寮规
+const openFileDialog = async (row) => {
+  recordId.value = row.id
+  fileDialogVisible.value = true
+}
 
 const openEdit = (row) => {
   editmodalRef.value.open(row);
diff --git a/src/views/procurementManagement/procurementLedger/index.vue b/src/views/procurementManagement/procurementLedger/index.vue
index 32b54a9..1991342 100644
--- a/src/views/procurementManagement/procurementLedger/index.vue
+++ b/src/views/procurementManagement/procurementLedger/index.vue
@@ -9,7 +9,7 @@
                       placeholder="璇疯緭鍏�"
                       clearable
                       prefix-icon="Search"
-                      @change="handleQuery" />
+                      @change="handleQuery"/>
           </el-form-item>
           <el-form-item label="閲囪喘鍚堝悓鍙凤細">
             <el-input v-model="searchForm.purchaseContractNumber"
@@ -17,21 +17,21 @@
                       placeholder="璇疯緭鍏�"
                       @change="handleQuery"
                       clearable
-                      :prefix-icon="Search" />
+                      :prefix-icon="Search"/>
           </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"
@@ -40,11 +40,12 @@
                             type="daterange"
                             placeholder="璇烽�夋嫨"
                             clearable
-                            @change="changeDaterange" />
+                            @change="changeDaterange"/>
           </el-form-item>
           <el-form-item>
             <el-button type="primary"
-                       @click="handleQuery"> 鎼滅储 </el-button>
+                       @click="handleQuery"> 鎼滅储
+            </el-button>
           </el-form-item>
         </el-form>
       </div>
@@ -57,7 +58,8 @@
         <el-button @click="handleOut">瀵煎嚭</el-button>
         <el-button type="danger"
                    plain
-                   @click="handleDelete">鍒犻櫎</el-button>
+                   @click="handleDelete">鍒犻櫎
+        </el-button>
       </div>
       <el-table :data="tableData"
                 border
@@ -71,7 +73,7 @@
                 height="calc(100vh - 21.5em)">
         <el-table-column align="center"
                          type="selection"
-                         width="55" />
+                         width="55"/>
         <el-table-column type="expand">
           <template #default="props">
             <el-table :data="props.row.children"
@@ -81,62 +83,62 @@
               <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="availableQuality" />
+                               prop="availableQuality"/>
               <el-table-column label="閫�璐ф暟閲�"
-                               prop="returnQuality" />
-                               
+                               prop="returnQuality"/>
+
               <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>
           </template>
         </el-table-column>
         <el-table-column align="center"
                          label="搴忓彿"
                          type="index"
-                         width="60" />
+                         width="60"/>
         <el-table-column label="閲囪喘鍚堝悓鍙�"
                          prop="purchaseContractNumber"
                          width="160"
-                         show-overflow-tooltip />
+                         show-overflow-tooltip/>
         <el-table-column label="閿�鍞悎鍚屽彿"
                          prop="salesContractNo"
-                          width="160"
-                         show-overflow-tooltip />
+                         width="160"
+                         show-overflow-tooltip/>
         <el-table-column label="渚涘簲鍟嗗悕绉�"
                          prop="supplierName"
-                          width="160"
-                         show-overflow-tooltip />
+                         width="160"
+                         show-overflow-tooltip/>
         <el-table-column label="椤圭洰鍚嶇О"
                          prop="projectName"
                          width="320"
-                         show-overflow-tooltip />
+                         show-overflow-tooltip/>
         <el-table-column label="瀹℃壒鐘舵��"
                          prop="approvalStatus"
                          width="100"
                          show-overflow-tooltip>
           <template #default="scope">
-            <el-tag 
-              :type="getApprovalStatusType(scope.row.approvalStatus)"
-              size="small">
+            <el-tag
+                :type="getApprovalStatusType(scope.row.approvalStatus)"
+                size="small">
               {{ approvalStatusText[scope.row.approvalStatus] || '鏈煡鐘舵��' }}
             </el-tag>
           </template>
@@ -144,28 +146,28 @@
         <el-table-column label="绛捐鏃ユ湡"
                          prop="executionDate"
                          width="100"
-                         show-overflow-tooltip />
+                         show-overflow-tooltip/>
         <el-table-column label="浠樻鏂瑰紡"
                          width="100"
                          prop="paymentMethod"
-                         show-overflow-tooltip />
+                         show-overflow-tooltip/>
         <el-table-column label="鍚堝悓閲戦(鍏�)"
                          prop="contractAmount"
                          width="200"
                          show-overflow-tooltip
-                         :formatter="formattedNumber" />
+                         :formatter="formattedNumber"/>
         <el-table-column label="褰曞叆浜�"
                          prop="recorderName"
                          width="120"
-                         show-overflow-tooltip />
+                         show-overflow-tooltip/>
         <el-table-column label="褰曞叆鏃ユ湡"
                          prop="entryDate"
                          width="100"
-                         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="120"
@@ -174,10 +176,11 @@
             <el-button link
                        type="primary"
                        @click="openForm('edit', scope.row)"
-                       :disabled="scope.row.approvalStatus !== 1 && scope.row.approvalStatus !== 4">缂栬緫</el-button>
+                       :disabled="scope.row.approvalStatus !== 1 && scope.row.approvalStatus !== 4">缂栬緫
+            </el-button>
             <el-button link
                        type="primary"
-                       @click="downLoadFile(scope.row)">闄勪欢</el-button>
+                       @click="openFileDialog(scope.row)">闄勪欢</el-button>
           </template>
         </el-table-column>
       </el-table>
@@ -186,15 +189,15 @@
                   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' ? '鏂板閲囪喘鍙拌处椤甸潰' : '缂栬緫閲囪喘鍙拌处椤甸潰'"
-               :width="'70%'"
-               :operation-type="operationType"
-               @close="closeDia"
-               @confirm="submitForm"
-               @cancel="closeDia">
+                :title="operationType === 'add' ? '鏂板閲囪喘鍙拌处椤甸潰' : '缂栬緫閲囪喘鍙拌处椤甸潰'"
+                :width="'70%'"
+                :operation-type="operationType"
+                @close="closeDia"
+                @confirm="submitForm"
+                @cancel="closeDia">
       <el-form :model="form"
                label-width="140px"
                label-position="top"
@@ -206,7 +209,7 @@
                           prop="purchaseContractNumber">
               <el-input v-model="form.purchaseContractNumber"
                         placeholder="璇疯緭鍏�"
-                        clearable />
+                        clearable/>
             </el-form-item>
           </el-col>
           <el-col :span="12">
@@ -220,7 +223,7 @@
                 <el-option v-for="item in salesContractList"
                            :key="item.id"
                            :label="item.salesContractNo"
-                           :value="item.id" />
+                           :value="item.id"/>
               </el-select>
             </el-form-item>
           </el-col>
@@ -236,7 +239,8 @@
                 <el-option v-for="item in supplierList"
                            :key="item.id"
                            :label="item.supplierName"
-													 :value="item.id" >{{item.supplierName + '---' + item.supplierType}}</el-option>
+                           :value="item.id">{{ item.supplierName + '---' + item.supplierType }}
+                </el-option>
               </el-select>
             </el-form-item>
           </el-col>
@@ -245,7 +249,7 @@
                           prop="projectName">
               <el-input v-model="form.projectName"
                         placeholder="璇疯緭鍏�"
-                        clearable />
+                        clearable/>
             </el-form-item>
           </el-col>
         </el-row>
@@ -254,7 +258,7 @@
             <el-form-item label="浠樻鏂瑰紡">
               <el-input v-model="form.paymentMethod"
                         placeholder="璇疯緭鍏�"
-                        clearable />
+                        clearable/>
             </el-form-item>
           </el-col>
           <el-col :span="12">
@@ -266,7 +270,7 @@
                               format="YYYY-MM-DD"
                               type="date"
                               placeholder="璇烽�夋嫨"
-                              clearable />
+                              clearable/>
             </el-form-item>
           </el-col>
         </el-row>
@@ -274,7 +278,7 @@
           <el-col :span="12">
             <el-form-item label="褰曞叆浜猴細"
                           prop="recorderId">
-              <el-input v-model="form.recorderName" placeholder="鑷姩濉厖" disabled />
+              <el-input v-model="form.recorderName" placeholder="鑷姩濉厖" disabled/>
             </el-form-item>
           </el-col>
           <el-col :span="12">
@@ -286,7 +290,7 @@
                               format="YYYY-MM-DD"
                               type="date"
                               placeholder="璇烽�夋嫨"
-                              clearable />
+                              clearable/>
             </el-form-item>
           </el-col>
         </el-row>
@@ -294,10 +298,12 @@
           <el-form-item label="浜у搧淇℃伅锛�"
                         prop="entryDate">
             <el-button type="primary"
-                       @click="openProductForm('add')">娣诲姞</el-button>
+                       @click="openProductForm('add')">娣诲姞
+            </el-button>
             <el-button plain
                        type="danger"
-                       @click="deleteProduct">鍒犻櫎</el-button>
+                       @click="deleteProduct">鍒犻櫎
+            </el-button>
           </el-form-item>
           <div class="select-button-group"
                style="width: 500px; margin: 20px 0;"
@@ -321,12 +327,12 @@
                          :value="item.templateName">
                 <div style="display: flex; justify-content: space-between; align-items: center;">
                   <span>{{ item.templateName }}</span>
-                  <el-icon 
-                    v-if="item.id"
-                    class="delete-icon"
-                    @click.stop="handleDeleteTemplate(item)"
-                    style="cursor: pointer; color: #f56c6c; font-size: 14px; margin-left: 8px;">
-                    <Delete />
+                  <el-icon
+                      v-if="item.id"
+                      class="delete-icon"
+                      @click.stop="handleDeleteTemplate(item)"
+                      style="cursor: pointer; color: #f56c6c; font-size: 14px; margin-left: 8px;">
+                    <Delete/>
                   </el-icon>
                 </div>
               </el-option>
@@ -347,40 +353,40 @@
                   :summary-method="summarizeProTable">
           <el-table-column align="center"
                            type="selection"
-                           width="55" />
+                           width="55"/>
           <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"
-                           width="70" />
+                           width="70"/>
           <el-table-column label="鏁伴噺"
                            prop="quantity"
-                           width="70" />
+                           width="70"/>
           <el-table-column label="搴撳瓨棰勮鏁伴噺"
                            prop="warnNum"
                            width="120"
-                           show-overflow-tooltip />
+                           show-overflow-tooltip/>
           <el-table-column label="绋庣巼(%)"
                            prop="taxRate"
-                           width="80" />
+                           width="80"/>
           <el-table-column label="鍚◣鍗曚环(鍏�)"
                            prop="taxInclusiveUnitPrice"
                            :formatter="formattedNumber"
-                           width="150" />
+                           width="150"/>
           <el-table-column label="鍚◣鎬讳环(鍏�)"
                            prop="taxInclusiveTotalPrice"
                            :formatter="formattedNumber"
-                           width="150" />
+                           width="150"/>
           <el-table-column label="涓嶅惈绋庢�讳环(鍏�)"
                            prop="taxExclusiveTotalPrice"
                            :formatter="formattedNumber"
-                           width="150" />
+                           width="150"/>
           <el-table-column label="鏄惁璐ㄦ"
                            prop="isChecked"
                            width="150">
@@ -397,7 +403,8 @@
             <template #default="scope">
               <el-button link
                          type="primary"
-                         @click="openProductForm('edit', scope.row, scope.$index)">缂栬緫</el-button>
+                         @click="openProductForm('edit', scope.row, scope.$index)">缂栬緫
+              </el-button>
             </template>
           </el-table-column>
         </el-table>
@@ -409,7 +416,7 @@
                         placeholder="璇疯緭鍏�"
                         clearable
                         type="textarea"
-                        :rows="2" />
+                        :rows="2"/>
             </el-form-item>
           </el-col>
         </el-row>
@@ -417,24 +424,7 @@
           <el-col :span="24">
             <el-form-item label="闄勪欢鏉愭枡锛�"
                           prop="purchaseLedgerFiles">
-              <el-upload v-model:file-list="fileList"
-                         :action="upload.url"
-                         multiple
-                         ref="fileUpload"
-                         auto-upload
-                         :headers="upload.headers"
-                         :before-upload="handleBeforeUpload"
-                         :on-error="handleUploadError"
-                         :on-success="handleUploadSuccess"
-                         :on-remove="handleRemove">
-                <el-button type="primary">涓婁紶</el-button>
-                <template #tip>
-                  <div class="el-upload__tip">
-                    鏂囦欢鏍煎紡鏀寔
-                    doc锛宒ocx锛寈ls锛寈lsx锛宲pt锛宲ptx锛宲df锛宼xt锛寈ml锛宩pg锛宩peg锛宲ng锛実if锛宐mp锛宺ar锛寊ip锛�7z
-                  </div>
-                </template>
-              </el-upload>
+              <FileUpload v-model:file-list="fileList"/>
             </el-form-item>
           </el-col>
         </el-row>
@@ -442,26 +432,26 @@
     </FormDialog>
     <!-- 瀵煎叆寮圭獥 -->
     <FormDialog
-      v-model="importUpload.open"
-      :title="importUpload.title"
-      :width="'600px'"
-      @close="importUpload.open = false"
-      @confirm="submitImportFile"
-      @cancel="importUpload.open = false"
+        v-model="importUpload.open"
+        :title="importUpload.title"
+        :width="'600px'"
+        @close="importUpload.open = false"
+        @confirm="submitImportFile"
+        @cancel="importUpload.open = false"
     >
       <el-upload
-        ref="importUploadRef"
-        :limit="1"
-        accept=".xlsx,.xls"
-        :action="importUpload.url"
-        :headers="importUpload.headers"
-        :before-upload="importUpload.beforeUpload"
-        :on-success="importUpload.onSuccess"
-        :on-error="importUpload.onError"
-        :on-progress="importUpload.onProgress"
-        :on-change="importUpload.onChange"
-        :auto-upload="false"
-        drag
+          ref="importUploadRef"
+          :limit="1"
+          accept=".xlsx,.xls"
+          :action="importUpload.url"
+          :headers="importUpload.headers"
+          :before-upload="importUpload.beforeUpload"
+          :on-success="importUpload.onSuccess"
+          :on-error="importUpload.onError"
+          :on-progress="importUpload.onProgress"
+          :on-change="importUpload.onChange"
+          :auto-upload="false"
+          drag
       >
         <i class="el-icon-upload"></i>
         <div class="el-upload__text">
@@ -476,12 +466,12 @@
       </el-upload>
     </FormDialog>
     <FormDialog v-model="productFormVisible"
-               :title="productOperationType === 'add' ? '鏂板浜у搧' : '缂栬緫浜у搧'"
-               :width="'40%'"
-               :operation-type="productOperationType"
-               @close="closeProductDia"
-               @confirm="submitProduct"
-               @cancel="closeProductDia">
+                :title="productOperationType === 'add' ? '鏂板浜у搧' : '缂栬緫浜у搧'"
+                :width="'40%'"
+                :operation-type="productOperationType"
+                @close="closeProductDia"
+                @confirm="submitProduct"
+                @cancel="closeProductDia">
       <el-form :model="productForm"
                label-width="140px"
                label-position="top"
@@ -499,7 +489,7 @@
                               @change="getModels"
                               :data="productOptions"
                               :render-after-expand="false"
-                              style="width: 100%" />
+                              style="width: 100%"/>
             </el-form-item>
           </el-col>
         </el-row>
@@ -515,7 +505,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>
@@ -526,7 +516,7 @@
                           prop="unit">
               <el-input v-model="productForm.unit"
                         placeholder="璇疯緭鍏�"
-                        clearable />
+                        clearable/>
             </el-form-item>
           </el-col>
           <el-col :span="12">
@@ -537,11 +527,11 @@
                          clearable
                          @change="mathNum">
                 <el-option label="1"
-                           value="1" />
+                           value="1"/>
                 <el-option label="6"
-                           value="6" />
+                           value="6"/>
                 <el-option label="13"
-                           value="13" />
+                           value="13"/>
               </el-select>
             </el-form-item>
           </el-col>
@@ -556,7 +546,7 @@
                                :min="0"
                                clearable
                                style="width: 100%"
-                               @change="mathNum" />
+                               @change="mathNum"/>
             </el-form-item>
           </el-col>
           <el-col :span="12">
@@ -569,7 +559,7 @@
                                style="width: 100%"
                                v-model="productForm.quantity"
                                placeholder="璇疯緭鍏�"
-                               @change="mathNum" />
+                               @change="mathNum"/>
             </el-form-item>
           </el-col>
         </el-row>
@@ -583,7 +573,7 @@
                                :min="0"
                                clearable
                                style="width: 100%"
-                               @change="reverseMathNum('taxInclusiveTotalPrice')" />
+                               @change="reverseMathNum('taxInclusiveTotalPrice')"/>
             </el-form-item>
           </el-col>
           <el-col :span="12">
@@ -595,7 +585,7 @@
                                :min="0"
                                clearable
                                style="width: 100%"
-                               @change="reverseMathNum('taxExclusiveTotalPrice')" />
+                               @change="reverseMathNum('taxExclusiveTotalPrice')"/>
             </el-form-item>
           </el-col>
         </el-row>
@@ -607,9 +597,9 @@
                          placeholder="璇烽�夋嫨"
                          clearable>
                 <el-option label="澧炴櫘绁�"
-                           value="澧炴櫘绁�" />
+                           value="澧炴櫘绁�"/>
                 <el-option label="澧炰笓绁�"
-                           value="澧炰笓绁�" />
+                           value="澧炰笓绁�"/>
               </el-select>
             </el-form-item>
           </el-col>
@@ -621,7 +611,7 @@
                                :step="0.1"
                                :min="0"
                                clearable
-                               style="width: 100%" />
+                               style="width: 100%"/>
             </el-form-item>
           </el-col>
         </el-row>
@@ -631,24 +621,23 @@
                           prop="isChecked">
               <el-radio-group v-model="productForm.isChecked">
                 <el-radio label="鏄�"
-                          :value="true" />
+                          :value="true"/>
                 <el-radio label="鍚�"
-                          :value="false" />
+                          :value="false"/>
               </el-radio-group>
             </el-form-item>
           </el-col>
         </el-row>
       </el-form>
     </FormDialog>
-    <FileListDialog 
-      ref="fileListRef" 
-      v-model="fileListDialogVisible"
-      title="闄勪欢鍒楄〃"
-    />
+    <FileList v-if="fileListDialogVisible"  v-model:visible="fileListDialogVisible" record-type="purchase_ledger" :record-id="recordId"  />
   </div>
 </template>
 
 <script setup>
+import {Search, Delete} from "@element-plus/icons-vue";
+import FormDialog from '@/components/Dialog/FormDialog.vue';
+import FileListDialog from '@/components/Dialog/FileListDialog.vue';
   import { getToken } from "@/utils/auth";
   import pagination from "@/components/PIMTable/Pagination.vue";
   import {
@@ -661,10 +650,7 @@
   } from "vue";
   import { Search, Delete } from "@element-plus/icons-vue";
   import { ElMessageBox, ElMessage } from "element-plus";
-  import FormDialog from '@/components/Dialog/FormDialog.vue';
-  import FileListDialog from '@/components/Dialog/FileListDialog.vue';
   import {
-    getSalesLedgerWithProducts,
     addOrUpdateSalesLedgerProduct,
     delProduct,
     delLedgerFile,
@@ -685,431 +671,434 @@
     delPurchaseTemplate,
   } from "@/api/procurementManagement/procurementLedger.js";
   import useFormData from "@/hooks/useFormData.js";
+  const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue"));
 
-  const { proxy } = getCurrentInstance();
-  const tableData = ref([]);
-  const productData = ref([]);
-  const selectedRows = ref([]);
-  const productSelectedRows = ref([]);
-  const modelOptions = ref([]);
-  const productOptions = ref([]);
-  const salesContractList = ref([]);
-  const supplierList = ref([]);
-  const tableLoading = ref(false);
-  const page = reactive({
-    current: 1,
-    size: 100,
-  });
-  const total = ref(0);
-  const fileList = ref([]);
-  import useUserStore from "@/store/modules/user";
-  import { modelList, productTreeList } from "@/api/basicData/product.js";
-  import dayjs from "dayjs";
+const {proxy} = getCurrentInstance();
+const tableData = ref([]);
+const productData = ref([]);
+const selectedRows = ref([]);
+const productSelectedRows = ref([]);
+const modelOptions = ref([]);
+const productOptions = ref([]);
+const salesContractList = ref([]);
+const supplierList = ref([]);
+const tableLoading = ref(false);
+const fileListDialogVisible = ref(false)
+const page = reactive({
+  current: 1,
+  size: 100,
+});
+const total = ref(0);
+const fileList = ref([]);
+import useUserStore from "@/store/modules/user";
+import {modelList, productTreeList} from "@/api/basicData/product.js";
+import dayjs from "dayjs";
+import FileUpload from "@/components/AttachmentUpload/file/index.vue";
 
-  const userStore = useUserStore();
+const userStore = useUserStore();
 
-  // 璁㈠崟瀹℃壒鐘舵�佹樉绀烘枃鏈�
-  const approvalStatusText = {
-    1: "寰呭鏍�",
-    2: "瀹℃壒涓�",
-    3: "瀹℃壒閫氳繃",
-    4: "瀹℃壒澶辫触",
+// 璁㈠崟瀹℃壒鐘舵�佹樉绀烘枃鏈�
+const approvalStatusText = {
+  1: "寰呭鏍�",
+  2: "瀹℃壒涓�",
+  3: "瀹℃壒閫氳繃",
+  4: "瀹℃壒澶辫触",
+};
+
+// 鑾峰彇瀹℃壒鐘舵�佹爣绛剧被鍨�
+const getApprovalStatusType = (status) => {
+  const typeMap = {
+    1: "info",      // 寰呭鏍� - 鐏拌壊
+    2: "warning",   // 瀹℃壒涓� - 姗欒壊
+    3: "success",   // 瀹℃壒閫氳繃 - 缁胯壊
+    4: "danger",    // 瀹℃壒澶辫触 - 绾㈣壊
   };
+  return typeMap[status] || "";
+};
 
-  // 鑾峰彇瀹℃壒鐘舵�佹爣绛剧被鍨�
-  const getApprovalStatusType = (status) => {
-    const typeMap = {
-      1: "info",      // 寰呭鏍� - 鐏拌壊
-      2: "warning",   // 瀹℃壒涓� - 姗欒壊
-      3: "success",   // 瀹℃壒閫氳繃 - 缁胯壊
-      4: "danger",    // 瀹℃壒澶辫触 - 绾㈣壊
-    };
-    return typeMap[status] || "";
-  };
+const templateName = ref("");
+const filterInputValue = ref("");
+const templateList = ref([]);
+const isTemplateNameDuplicate = ref(false); // 鏍囪妯℃澘鍚嶇О鏄惁閲嶅
+// 褰撳墠閫変腑鐨勬ā鏉縄D锛堢敤浜庡尯鍒嗘柊澧炴ā鏉胯繕鏄洿鏂版ā鏉匡級
+const currentTemplateId = ref(null);
 
-  const templateName = ref("");
-  const filterInputValue = ref("");
-  const templateList = ref([]);
-  const isTemplateNameDuplicate = ref(false); // 鏍囪妯℃澘鍚嶇О鏄惁閲嶅
-  // 褰撳墠閫変腑鐨勬ā鏉縄D锛堢敤浜庡尯鍒嗘柊澧炴ā鏉胯繕鏄洿鏂版ā鏉匡級
-  const currentTemplateId = ref(null);
-
-  // 妫�鏌ユā鏉垮悕绉版槸鍚﹂噸澶�
-  const checkTemplateNameDuplicate = name => {
-    if (!name || name.trim() === "") {
-      isTemplateNameDuplicate.value = false;
-      return false;
-    }
-    const isDuplicate = templateList.value.some(
+// 妫�鏌ユā鏉垮悕绉版槸鍚﹂噸澶�
+const checkTemplateNameDuplicate = name => {
+  if (!name || name.trim() === "") {
+    isTemplateNameDuplicate.value = false;
+    return false;
+  }
+  const isDuplicate = templateList.value.some(
       item => item.templateName === name.trim()
-    );
-    isTemplateNameDuplicate.value = isDuplicate;
-    return isDuplicate;
-  };
+  );
+  isTemplateNameDuplicate.value = isDuplicate;
+  return isDuplicate;
+};
 
-  // 闃叉姈瀹氭椂鍣�
-  let duplicateCheckTimer = null;
-  const onTemplateFilterChange = val => {
-    filterInputValue.value = val ?? "";
-    // 娓呴櫎涔嬪墠鐨勫畾鏃跺櫒
-    if (duplicateCheckTimer) {
-      clearTimeout(duplicateCheckTimer);
-    }
-    // 瀹炴椂妫�鏌ユā鏉垮悕绉版槸鍚﹂噸澶嶏紙闃叉姈澶勭悊锛岄伩鍏嶉绻佹彁绀猴級
-    if (val && val.trim()) {
-      duplicateCheckTimer = setTimeout(() => {
-        const isDuplicate = checkTemplateNameDuplicate(val);
-        if (isDuplicate) {
-          ElMessage({
-            message: "妯℃澘鍚嶇О宸插瓨鍦紝璇锋洿鎹㈡ā鏉垮悕绉�",
-            type: "warning",
-            duration: 2000,
-          });
-        }
-      }, 300); // 300ms 闃叉姈
-    } else {
-      isTemplateNameDuplicate.value = false;
-    }
-  };
-
-  // allow-create 鏃讹紝杈撳叆涓嶅瓨鍦ㄧ殑鍐呭浼氫綔涓� string 鍊艰繑鍥烇紱杩欓噷鍚屾鍥炶緭鍏ユ浠ョ‘淇濇枃瀛椾笉涓�
-  const onTemplateChange = async val => {
-    if (typeof val === "string") {
-      filterInputValue.value = val;
-      // 閫夋嫨鎴栬緭鍏ユ椂妫�鏌ラ噸澶�
-      checkTemplateNameDuplicate(val);
-    }
-
-    // 杩囨护鏁版嵁锛屾煡鎵惧尮閰嶇殑妯℃澘
-    const matchedTemplate = templateList.value.find(
-      item => item.templateName === val
-    );
-
-    if (matchedTemplate?.id) {
-      // 璁板綍褰撳墠閫変腑鐨勬ā鏉縄D锛屽悗缁繚瀛樻椂杩涜鏇存柊鎿嶄綔
-      currentTemplateId.value = matchedTemplate.id;
-      // 閫変腑宸叉湁妯℃澘鏃讹紝涓嶅簲瑙嗕负鈥滄ā鏉垮悕绉伴噸澶嶅鑷翠笉鍙繚瀛樷��
-      isTemplateNameDuplicate.value = false;
-      // 濡傛灉鎵惧埌妯℃澘锛屽彧璧嬪�间緵搴斿晢銆侀」鐩悕绉般�佷粯娆炬柟寮忓拰浜у搧淇℃伅
-      if (matchedTemplate.supplierId) {
-        form.value.supplierId = matchedTemplate.supplierId;
-      }
-      if (matchedTemplate.supplierName) {
-        form.value.supplierName = matchedTemplate.supplierName;
-      }
-      if (matchedTemplate.projectName) {
-        form.value.projectName = matchedTemplate.projectName;
-      }
-      if (matchedTemplate.paymentMethod) {
-        form.value.paymentMethod = matchedTemplate.paymentMethod;
-      }
-      // 妯℃澘鏁版嵁涓殑浜у搧瀛楁鏄� productList锛岄渶瑕佽浆鎹负 productData
-      productData.value = matchedTemplate.productList || matchedTemplate.productData || [];
-    } else {
-      // 鏈尮閰嶅埌宸叉湁妯℃澘锛岃涓烘柊妯℃澘
-      currentTemplateId.value = null;
-      // 濡傛灉娌℃湁鎵惧埌妯℃澘锛岄噸缃〃鍗曪紙淇濇寔褰撳墠琛ㄥ崟鐘舵�侊級
-      const currentFormData = { ...form.value };
-      const currentProductData = [...productData.value];
-
-      // 濡傛灉瀵硅瘽妗嗘湭鎵撳紑锛屽厛鎵撳紑
-      if (!dialogFormVisible.value) {
-        operationType.value = "add";
-        dialogFormVisible.value = true;
-      }
-
-      // 绛夊緟涓嬩竴涓� tick 鍚庢仮澶嶆暟鎹�
-      await nextTick();
-      form.value = {
-        ...form.value,
-        ...currentFormData,
-      };
-      productData.value = currentProductData;
-    }
-  };
-
-  // 鐢ㄦ埛淇℃伅琛ㄥ崟寮规鏁版嵁
-  const operationType = ref("");
-  const dialogFormVisible = ref(false);
-  const data = reactive({
-    searchForm: {
-      supplierName: "", // 渚涘簲鍟嗗悕绉�
-      purchaseContractNumber: "", // 閲囪喘鍚堝悓缂栧彿
-      salesContractNo: "", // 閿�鍞悎鍚岀紪鍙�
-      projectName: "", // 椤圭洰鍚嶇О
-      entryDate: null, // 褰曞叆鏃ユ湡
-      entryDateStart: undefined,
-      entryDateEnd: undefined,
-    },
-    form: {
-      purchaseContractNumber: "",
-      salesLedgerId: "",
-      projectName: "",
-      recorderId: "",
-			recorderName: "",
-      entryDate: "",
-      productData: [],
-      supplierName: "",
-      supplierId: "",
-      paymentMethod: "",
-      executionDate: "",
-      isChecked: false,
-    },
-    rules: {
-      purchaseContractNumber: [
-        { required: true, message: "璇疯緭鍏�", trigger: "blur" },
-      ],
-      projectName: [
-        { required: true, message: "璇疯緭鍏ラ」鐩悕绉�", trigger: "blur" },
-      ],
-      supplierId: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
-      entryDate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
-      executionDate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
-    },
-  });
-  const { form, rules } = toRefs(data);
-  const { form: searchForm } = useFormData({
-    ...data.searchForm,
-    // 璁剧疆褰曞叆鏃ユ湡鑼冨洿涓哄綋澶�
-    entryDate: [
-      dayjs().startOf("day").format("YYYY-MM-DD"),
-      dayjs().endOf("day").format("YYYY-MM-DD"),
-    ],
-    entryDateStart: dayjs().startOf("day").format("YYYY-MM-DD"),
-    entryDateEnd: dayjs().endOf("day").format("YYYY-MM-DD"),
-  });
-
-  // 浜у搧琛ㄥ崟寮规鏁版嵁
-  const productFormVisible = ref(false);
-  const productOperationType = ref("");
-  const productOperationIndex = ref("");
-  const currentId = ref("");
-  const productFormData = reactive({
-    productForm: {
-      productId: "",
-      productCategory: "",
-      productModelId: "",
-      specificationModel: "",
-      unit: "",
-      quantity: "",
-      taxInclusiveUnitPrice: "",
-      taxRate: "",
-      taxInclusiveTotalPrice: "",
-      taxExclusiveTotalPrice: "",
-      invoiceType: "",
-      warnNum: "",
-      isChecked: false,
-    },
-    productRules: {
-      productId: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
-      productModelId: [{ 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" }],
-      warnNum: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
-      taxInclusiveTotalPrice: [
-        { required: true, message: "璇疯緭鍏�", trigger: "blur" },
-      ],
-      taxExclusiveTotalPrice: [
-        { required: true, message: "璇疯緭鍏�", trigger: "blur" },
-      ],
-      invoiceType: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
-      isChecked: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
-    },
-  });
-  const { productForm, productRules } = toRefs(productFormData);
-  const upload = reactive({
-    // 涓婁紶鐨勫湴鍧�
-    url: import.meta.env.VITE_APP_BASE_API + "/file/upload",
-    // 璁剧疆涓婁紶鐨勮姹傚ご閮�
-    headers: { Authorization: "Bearer " + getToken() },
-  });
-
-  // 瀵煎叆鐩稿叧
-  const importUploadRef = ref(null);
-  const importUpload = reactive({
-    title: "瀵煎叆閲囪喘鍙拌处",
-    open: false,
-    url: import.meta.env.VITE_APP_BASE_API + "/purchase/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) => {
-      // noop
-    },
-    onProgress: (event, file, fileList) => {
-      // noop
-    },
-    onSuccess: (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: () => {
-      importUpload.isUploading = false;
-      proxy.$modal.msgError("瀵煎叆澶辫触锛岃閲嶈瘯");
-    },
-  });
-
-  const handleImport = () => {
-    importUpload.title = "瀵煎叆閲囪喘鍙拌处";
-    importUpload.open = true;
-    importUpload.isUploading = false;
-    if (importUploadRef.value) {
-      importUploadRef.value.clearFiles?.();
-    }
-  };
-
-  // 涓嬭浇瀵煎叆妯℃澘锛堝鍚庣璺緞涓嶅悓锛屽彲鍦ㄦ澶勮皟鏁达級
-  const downloadTemplate = () => {
-    proxy.download("/purchase/ledger/exportTemplate", {}, "閲囪喘鍙拌处瀵煎叆妯℃澘.xlsx");
-  };
-
-  const submitImportFile = () => {
-    importUpload.isUploading = true;
-    proxy.$refs["importUploadRef"]?.submit?.();
-  };
-
-  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 formattedNumber = (row, column, cellValue) => {
-    return parseFloat(cellValue).toFixed(2);
-  };
-  // 鏌ヨ鍒楄〃
-  /** 鎼滅储鎸夐挳鎿嶄綔 */
-  const handleQuery = () => {
-    page.current = 1;
-    getList();
-  };
-
-  // 淇濆瓨妯℃澘
-  const handleButtonClick = async () => {
-    // 妫�鏌ユā鏉垮悕绉版槸鍚︿负绌�
-    if (!templateName.value || templateName.value.trim() === "") {
-      ElMessage({
-        message: "璇疯緭鍏ユā鏉垮悕绉�",
-        type: "warning",
-      });
-      return;
-    }
-
-    // 濡傛灉鏄�滄柊澧炴ā鏉库�濓紙娌℃湁閫変腑宸叉湁妯℃澘锛夛紝鎵嶉渶瑕佸仛閲嶅悕鏍¢獙锛�
-    // 鑻ユ槸閫変腑宸叉湁妯℃澘鍚庝慨鏀癸紝鍒欏厑璁镐娇鐢ㄥ師鍚嶇О锛堣涓烘洿鏂帮級
-    if (!currentTemplateId.value) {
-      const isDuplicate = checkTemplateNameDuplicate(templateName.value);
+// 闃叉姈瀹氭椂鍣�
+let duplicateCheckTimer = null;
+const onTemplateFilterChange = val => {
+  filterInputValue.value = val ?? "";
+  // 娓呴櫎涔嬪墠鐨勫畾鏃跺櫒
+  if (duplicateCheckTimer) {
+    clearTimeout(duplicateCheckTimer);
+  }
+  // 瀹炴椂妫�鏌ユā鏉垮悕绉版槸鍚﹂噸澶嶏紙闃叉姈澶勭悊锛岄伩鍏嶉绻佹彁绀猴級
+  if (val && val.trim()) {
+    duplicateCheckTimer = setTimeout(() => {
+      const isDuplicate = checkTemplateNameDuplicate(val);
       if (isDuplicate) {
         ElMessage({
           message: "妯℃澘鍚嶇О宸插瓨鍦紝璇锋洿鎹㈡ā鏉垮悕绉�",
           type: "warning",
+          duration: 2000,
         });
-        return;
       }
+    }, 300); // 300ms 闃叉姈
+  } else {
+    isTemplateNameDuplicate.value = false;
+  }
+};
+
+// allow-create 鏃讹紝杈撳叆涓嶅瓨鍦ㄧ殑鍐呭浼氫綔涓� string 鍊艰繑鍥烇紱杩欓噷鍚屾鍥炶緭鍏ユ浠ョ‘淇濇枃瀛椾笉涓�
+const onTemplateChange = async val => {
+  if (typeof val === "string") {
+    filterInputValue.value = val;
+    // 閫夋嫨鎴栬緭鍏ユ椂妫�鏌ラ噸澶�
+    checkTemplateNameDuplicate(val);
+  }
+
+  // 杩囨护鏁版嵁锛屾煡鎵惧尮閰嶇殑妯℃澘
+  const matchedTemplate = templateList.value.find(
+      item => item.templateName === val
+  );
+
+  if (matchedTemplate?.id) {
+    // 璁板綍褰撳墠閫変腑鐨勬ā鏉縄D锛屽悗缁繚瀛樻椂杩涜鏇存柊鎿嶄綔
+    currentTemplateId.value = matchedTemplate.id;
+    // 閫変腑宸叉湁妯℃澘鏃讹紝涓嶅簲瑙嗕负鈥滄ā鏉垮悕绉伴噸澶嶅鑷翠笉鍙繚瀛樷��
+    isTemplateNameDuplicate.value = false;
+    // 濡傛灉鎵惧埌妯℃澘锛屽彧璧嬪�间緵搴斿晢銆侀」鐩悕绉般�佷粯娆炬柟寮忓拰浜у搧淇℃伅
+    if (matchedTemplate.supplierId) {
+      form.value.supplierId = matchedTemplate.supplierId;
+    }
+    if (matchedTemplate.supplierName) {
+      form.value.supplierName = matchedTemplate.supplierName;
+    }
+    if (matchedTemplate.projectName) {
+      form.value.projectName = matchedTemplate.projectName;
+    }
+    if (matchedTemplate.paymentMethod) {
+      form.value.paymentMethod = matchedTemplate.paymentMethod;
+    }
+    // 妯℃澘鏁版嵁涓殑浜у搧瀛楁鏄� productList锛岄渶瑕佽浆鎹负 productData
+    productData.value = matchedTemplate.productList || matchedTemplate.productData || [];
+  } else {
+    // 鏈尮閰嶅埌宸叉湁妯℃澘锛岃涓烘柊妯℃澘
+    currentTemplateId.value = null;
+    // 濡傛灉娌℃湁鎵惧埌妯℃澘锛岄噸缃〃鍗曪紙淇濇寔褰撳墠琛ㄥ崟鐘舵�侊級
+    const currentFormData = {...form.value};
+    const currentProductData = [...productData.value];
+
+    // 濡傛灉瀵硅瘽妗嗘湭鎵撳紑锛屽厛鎵撳紑
+    if (!dialogFormVisible.value) {
+      operationType.value = "add";
+      dialogFormVisible.value = true;
     }
 
-    // 妫�鏌ヤ緵搴斿晢鏄惁閫夋嫨
-    if (!form.value.supplierId) {
+    // 绛夊緟涓嬩竴涓� tick 鍚庢仮澶嶆暟鎹�
+    await nextTick();
+    form.value = {
+      ...form.value,
+      ...currentFormData,
+    };
+    productData.value = currentProductData;
+  }
+};
+
+// 鐢ㄦ埛淇℃伅琛ㄥ崟寮规鏁版嵁
+const operationType = ref("");
+const dialogFormVisible = ref(false);
+const data = reactive({
+  searchForm: {
+    supplierName: "", // 渚涘簲鍟嗗悕绉�
+    purchaseContractNumber: "", // 閲囪喘鍚堝悓缂栧彿
+    salesContractNo: "", // 閿�鍞悎鍚岀紪鍙�
+    projectName: "", // 椤圭洰鍚嶇О
+    entryDate: null, // 褰曞叆鏃ユ湡
+    entryDateStart: undefined,
+    entryDateEnd: undefined,
+  },
+  form: {
+    purchaseContractNumber: "",
+    salesLedgerId: "",
+    projectName: "",
+    recorderId: "",
+    recorderName: "",
+    entryDate: "",
+    productData: [],
+    supplierName: "",
+    supplierId: "",
+    paymentMethod: "",
+    executionDate: "",
+    isChecked: false,
+  },
+  rules: {
+    purchaseContractNumber: [
+      {required: true, message: "璇疯緭鍏�", trigger: "blur"},
+    ],
+    projectName: [
+      {required: true, message: "璇疯緭鍏ラ」鐩悕绉�", trigger: "blur"},
+    ],
+    supplierId: [{required: true, message: "璇疯緭鍏�", trigger: "blur"}],
+    entryDate: [{required: true, message: "璇烽�夋嫨", trigger: "change"}],
+    executionDate: [{required: true, message: "璇烽�夋嫨", trigger: "change"}],
+  },
+});
+const {form, rules} = toRefs(data);
+const {form: searchForm} = useFormData({
+  ...data.searchForm,
+  // 璁剧疆褰曞叆鏃ユ湡鑼冨洿涓哄綋澶�
+  entryDate: [
+    dayjs().startOf("day").format("YYYY-MM-DD"),
+    dayjs().endOf("day").format("YYYY-MM-DD"),
+  ],
+  entryDateStart: dayjs().startOf("day").format("YYYY-MM-DD"),
+  entryDateEnd: dayjs().endOf("day").format("YYYY-MM-DD"),
+});
+
+// 浜у搧琛ㄥ崟寮规鏁版嵁
+const productFormVisible = ref(false);
+const productOperationType = ref("");
+const productOperationIndex = ref("");
+const currentId = ref("");
+const productFormData = reactive({
+  productForm: {
+    productId: "",
+    productCategory: "",
+    productModelId: "",
+    specificationModel: "",
+    unit: "",
+    quantity: "",
+    taxInclusiveUnitPrice: "",
+    taxRate: "",
+    taxInclusiveTotalPrice: "",
+    taxExclusiveTotalPrice: "",
+    invoiceType: "",
+    warnNum: "",
+    isChecked: false,
+  },
+  productRules: {
+    productId: [{required: true, message: "璇烽�夋嫨", trigger: "change"}],
+    productModelId: [{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"}],
+    warnNum: [{required: true, message: "璇烽�夋嫨", trigger: "change"}],
+    taxInclusiveTotalPrice: [
+      {required: true, message: "璇疯緭鍏�", trigger: "blur"},
+    ],
+    taxExclusiveTotalPrice: [
+      {required: true, message: "璇疯緭鍏�", trigger: "blur"},
+    ],
+    invoiceType: [{required: true, message: "璇烽�夋嫨", trigger: "change"}],
+    isChecked: [{required: true, message: "璇烽�夋嫨", trigger: "change"}],
+  },
+});
+const {productForm, productRules} = toRefs(productFormData);
+const upload = reactive({
+  // 涓婁紶鐨勫湴鍧�
+  url: import.meta.env.VITE_APP_BASE_API + "/file/upload",
+  // 璁剧疆涓婁紶鐨勮姹傚ご閮�
+  headers: {Authorization: "Bearer " + getToken()},
+});
+
+// 瀵煎叆鐩稿叧
+const importUploadRef = ref(null);
+const importUpload = reactive({
+  title: "瀵煎叆閲囪喘鍙拌处",
+  open: false,
+  url: import.meta.env.VITE_APP_BASE_API + "/purchase/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) => {
+    // noop
+  },
+  onProgress: (event, file, fileList) => {
+    // noop
+  },
+  onSuccess: (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: () => {
+    importUpload.isUploading = false;
+    proxy.$modal.msgError("瀵煎叆澶辫触锛岃閲嶈瘯");
+  },
+});
+
+const handleImport = () => {
+  importUpload.title = "瀵煎叆閲囪喘鍙拌处";
+  importUpload.open = true;
+  importUpload.isUploading = false;
+  if (importUploadRef.value) {
+    importUploadRef.value.clearFiles?.();
+  }
+};
+
+// 涓嬭浇瀵煎叆妯℃澘锛堝鍚庣璺緞涓嶅悓锛屽彲鍦ㄦ澶勮皟鏁达級
+const downloadTemplate = () => {
+  proxy.download("/purchase/ledger/exportTemplate", {}, "閲囪喘鍙拌处瀵煎叆妯℃澘.xlsx");
+};
+
+const submitImportFile = () => {
+  importUpload.isUploading = true;
+  proxy.$refs["importUploadRef"]?.submit?.();
+};
+
+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 formattedNumber = (row, column, cellValue) => {
+  return parseFloat(cellValue).toFixed(2);
+};
+// 鏌ヨ鍒楄〃
+/** 鎼滅储鎸夐挳鎿嶄綔 */
+const handleQuery = () => {
+  page.current = 1;
+  getList();
+};
+
+// 淇濆瓨妯℃澘
+const handleButtonClick = async () => {
+  // 妫�鏌ユā鏉垮悕绉版槸鍚︿负绌�
+  if (!templateName.value || templateName.value.trim() === "") {
+    ElMessage({
+      message: "璇疯緭鍏ユā鏉垮悕绉�",
+      type: "warning",
+    });
+    return;
+  }
+
+  // 濡傛灉鏄�滄柊澧炴ā鏉库�濓紙娌℃湁閫変腑宸叉湁妯℃澘锛夛紝鎵嶉渶瑕佸仛閲嶅悕鏍¢獙锛�
+  // 鑻ユ槸閫変腑宸叉湁妯℃澘鍚庝慨鏀癸紝鍒欏厑璁镐娇鐢ㄥ師鍚嶇О锛堣涓烘洿鏂帮級
+  if (!currentTemplateId.value) {
+    const isDuplicate = checkTemplateNameDuplicate(templateName.value);
+    if (isDuplicate) {
       ElMessage({
-        message: "璇峰厛閫夋嫨渚涘簲鍟�",
+        message: "妯℃澘鍚嶇О宸插瓨鍦紝璇锋洿鎹㈡ā鏉垮悕绉�",
         type: "warning",
       });
       return;
     }
+  }
 
-    // 妫�鏌ユ槸鍚︽湁浜у搧鏁版嵁
-    if (!productData.value || productData.value.length === 0) {
-      ElMessage({
-        message: '璇峰厛娣诲姞浜у搧淇℃伅',
-        type: 'warning',
+  // 妫�鏌ヤ緵搴斿晢鏄惁閫夋嫨
+  if (!form.value.supplierId) {
+    ElMessage({
+      message: "璇峰厛閫夋嫨渚涘簲鍟�",
+      type: "warning",
+    });
+    return;
+  }
+
+  // 妫�鏌ユ槸鍚︽湁浜у搧鏁版嵁
+  if (!productData.value || productData.value.length === 0) {
+    ElMessage({
+      message: '璇峰厛娣诲姞浜у搧淇℃伅',
+      type: 'warning',
+    });
+    return;
+  }
+
+  try {
+    let params = {
+      productData: proxy.HaveJson(productData.value),
+      supplierId: form.value.supplierId,
+      paymentMethod: form.value.paymentMethod,
+      recorderId: form.value.recorderId,
+      recorderName: form.value.recorderName,
+      projectName: form.value.projectName,
+      templateName: templateName.value.trim(),
+    };
+    console.log("template params ===>", params, "currentTemplateId:", currentTemplateId.value);
+
+    // 濡傛灉 currentTemplateId 鏈夊�硷紝璇存槑褰撳墠鏄�滅紪杈戝凡鏈夋ā鏉库�� 鈫� 璋冪敤鏇存柊鎺ュ彛
+    // 鍚﹀垯涓衡�滄柊寤烘ā鏉库�� 鈫� 璋冪敤鏂板鎺ュ彛
+    let res;
+    if (currentTemplateId.value) {
+      res = await updatePurchaseTemplate({
+        id: currentTemplateId.value,
+        ...params,
       });
-      return;
+    } else {
+      res = await addPurchaseTemplate(params);
     }
 
-    try {
-      let params = {
-        productData: proxy.HaveJson(productData.value),
-        supplierId: form.value.supplierId,
-        paymentMethod: form.value.paymentMethod,
-        recorderId: form.value.recorderId,
-				recorderName: form.value.recorderName,
-        projectName: form.value.projectName,
-        templateName: templateName.value.trim(),
-      };
-      console.log("template params ===>", params, "currentTemplateId:", currentTemplateId.value);
-
-      // 濡傛灉 currentTemplateId 鏈夊�硷紝璇存槑褰撳墠鏄�滅紪杈戝凡鏈夋ā鏉库�� 鈫� 璋冪敤鏇存柊鎺ュ彛
-      // 鍚﹀垯涓衡�滄柊寤烘ā鏉库�� 鈫� 璋冪敤鏂板鎺ュ彛
-      let res;
-      if (currentTemplateId.value) {
-        res = await updatePurchaseTemplate({
-          id: currentTemplateId.value,
-          ...params,
-        });
-      } else {
-        res = await addPurchaseTemplate(params);
-      }
-
-      if (res && res.code === 200) {
-        ElMessage({
-          message: currentTemplateId.value ? "妯℃澘鏇存柊鎴愬姛" : "妯℃澘淇濆瓨鎴愬姛",
-          type: "success",
-        });
-        // 淇濆瓨鎴愬姛鍚庨噸鏂拌幏鍙栨ā鏉垮垪琛�
-        await getTemplateList();
-        // 娓呯┖妯℃澘鍚嶇О杈撳叆
-        templateName.value = "";
-        filterInputValue.value = "";
-        isTemplateNameDuplicate.value = false;
-        // 淇濆瓨/鏇存柊瀹屾垚鍚庯紝閲嶇疆褰撳墠妯℃澘ID
-        currentTemplateId.value = null;
-      } else {
-        ElMessage({
-          message: res?.msg || "妯℃澘淇濆瓨澶辫触",
-          type: "error",
-        });
-      }
-    } catch (error) {
-      console.error("淇濆瓨妯℃澘澶辫触:", error);
+    if (res && res.code === 200) {
       ElMessage({
-        message: "妯℃澘淇濆瓨澶辫触锛岃绋嶅悗閲嶈瘯",
+        message: currentTemplateId.value ? "妯℃澘鏇存柊鎴愬姛" : "妯℃澘淇濆瓨鎴愬姛",
+        type: "success",
+      });
+      // 淇濆瓨鎴愬姛鍚庨噸鏂拌幏鍙栨ā鏉垮垪琛�
+      await getTemplateList();
+      // 娓呯┖妯℃澘鍚嶇О杈撳叆
+      templateName.value = "";
+      filterInputValue.value = "";
+      isTemplateNameDuplicate.value = false;
+      // 淇濆瓨/鏇存柊瀹屾垚鍚庯紝閲嶇疆褰撳墠妯℃澘ID
+      currentTemplateId.value = null;
+    } else {
+      ElMessage({
+        message: res?.msg || "妯℃澘淇濆瓨澶辫触",
         type: "error",
       });
     }
-  };
-  // 瀛愯〃鍚堣鏂规硶
-  const summarizeChildrenTable = param => {
-    return proxy.summarizeTable(
+  } catch (error) {
+    console.error("淇濆瓨妯℃澘澶辫触:", error);
+    ElMessage({
+      message: "妯℃澘淇濆瓨澶辫触锛岃绋嶅悗閲嶈瘯",
+      type: "error",
+    });
+  }
+};
+// 瀛愯〃鍚堣鏂规硶
+const summarizeChildrenTable = param => {
+  return proxy.summarizeTable(
       param,
       [
         "taxInclusiveUnitPrice",
@@ -1121,20 +1110,20 @@
         "futureTicketsAmount",
       ],
       {
-        ticketsNum: { noDecimal: true }, // 涓嶄繚鐣欏皬鏁�
-        futureTickets: { noDecimal: true }, // 涓嶄繚鐣欏皬鏁�
+        ticketsNum: {noDecimal: true}, // 涓嶄繚鐣欏皬鏁�
+        futureTickets: {noDecimal: true}, // 涓嶄繚鐣欏皬鏁�
       }
-    );
-  };
-  const paginationChange = obj => {
-    page.current = obj.page;
-    page.size = obj.limit;
-    getList();
-  };
-  const getList = () => {
-    tableLoading.value = true;
-    const { entryDate, ...rest } = searchForm;
-    purchaseListPage({ ...rest, ...page })
+  );
+};
+const paginationChange = obj => {
+  page.current = obj.page;
+  page.size = obj.limit;
+  getList();
+};
+const getList = () => {
+  tableLoading.value = true;
+  const {entryDate, ...rest} = searchForm;
+  purchaseListPage({...rest, ...page})
       .then(res => {
         tableLoading.value = false;
         // tableData.value = res.data.records;
@@ -1151,458 +1140,461 @@
       .catch(() => {
         tableLoading.value = false;
       });
-  };
-  // 琛ㄦ牸閫夋嫨鏁版嵁
-  const handleSelectionChange = selection => {
-    selectedRows.value = selection;
-  };
-  const productSelected = selectedRows => {
-    productSelectedRows.value = selectedRows;
-  };
-  const expandedRowKeys = ref([]);
-  // 灞曞紑琛�
-  const expandChange = async (row, expandedRows) => {
-    if (expandedRows.length > 0) {
-      expandedRowKeys.value = [];
+};
+// 琛ㄦ牸閫夋嫨鏁版嵁
+const handleSelectionChange = selection => {
+  selectedRows.value = selection;
+};
+const productSelected = selectedRows => {
+  productSelectedRows.value = selectedRows;
+};
+const expandedRowKeys = ref([]);
+// 灞曞紑琛�
+const expandChange = async (row, expandedRows) => {
+  if (expandedRows.length > 0) {
+    expandedRowKeys.value = [];
+    try {
+      const res = await productList({salesLedgerId: row.id, type: 2});
+      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.error("鍔犺浇浜у搧鍒楄〃澶辫触:", error);
+      proxy.$modal.msgError("鍔犺浇浜у搧鍒楄〃澶辫触");
+      // 灞曞紑澶辫触鏃讹紝绉婚櫎灞曞紑鐘舵��
+      const index = expandedRows.findIndex(item => item.id === row.id);
+      if (index > -1) {
+        expandedRows.splice(index, 1);
+      }
+    }
+  } else {
+    expandedRowKeys.value = [];
+  }
+};
+// 涓昏〃鍚堣鏂规硶
+const summarizeMainTable = param => {
+  return proxy.summarizeTable(param, ["contractAmount"]);
+};
+// 瀛愯〃鍚堣鏂规硶
+const summarizeProTable = param => {
+  return proxy.summarizeTable(param, [
+    "taxInclusiveUnitPrice",
+    "taxInclusiveTotalPrice",
+    "taxExclusiveTotalPrice",
+  ]);
+};
+// 鎵撳紑寮规
+const openForm = async (type, row) => {
+  // 缂栬緫鏃舵鏌ュ鏍哥姸鎬侊紝鍙湁寰呭鏍�(1)鍜屽鎵瑰け璐�(4)鎵嶈兘缂栬緫
+  if (type === "edit" && row) {
+    if (row.approvalStatus !== 1 && row.approvalStatus !== 4) {
+      proxy.$modal.msgWarning("鍙湁寰呭鏍稿拰瀹℃壒澶辫触鐘舵�佺殑璁板綍鎵嶈兘缂栬緫");
+      return;
+    }
+  }
+
+  await getTemplateList();
+  operationType.value = type;
+  form.value = {};
+  productData.value = [];
+  fileList.value = [];
+  templateName.value = "";
+  filterInputValue.value = "";
+  isTemplateNameDuplicate.value = false;
+  try {
+    // 骞惰鍔犺浇鍩虹鏁版嵁
+    const [salesRes, supplierRes] = await Promise.all([
+      getSalesNo(),
+      getOptions(),
+    ]);
+
+    salesContractList.value = salesRes || [];
+    // 渚涘簲鍟嗚繃婊ゅ嚭isWhite=0 鐨勬暟鎹�
+    supplierList.value = (supplierRes.data || []).filter(
+        item => item.isWhite === 0
+    );
+
+    // 璁剧疆榛樿鍊�
+    form.value.recorderName = userStore.nickName;
+    form.value.entryDate = getCurrentDate();
+
+    if (type === "add") {
+      // 鏂板鏃剁敓鎴愰噰璐悎鍚屽彿
       try {
-        const res = await productList({ salesLedgerId: row.id, type: 2 });
-        const index = tableData.value.findIndex(item => item.id === row.id);
-        if (index > -1) {
-          tableData.value[index].children = res.data || [];
-          expandedRowKeys.value.push(row.id);
+        const purchaseNoRes = await createPurchaseNo();
+        if (purchaseNoRes?.data) {
+          form.value.purchaseContractNumber = purchaseNoRes.data;
         }
       } catch (error) {
-        console.error("鍔犺浇浜у搧鍒楄〃澶辫触:", error);
-        proxy.$modal.msgError("鍔犺浇浜у搧鍒楄〃澶辫触");
-        // 灞曞紑澶辫触鏃讹紝绉婚櫎灞曞紑鐘舵��
-        const index = expandedRows.findIndex(item => item.id === row.id);
-        if (index > -1) {
-          expandedRows.splice(index, 1);
-        }
+        console.error("鐢熸垚閲囪喘鍚堝悓鍙峰け璐�:", error);
+        proxy.$modal.msgWarning("鐢熸垚閲囪喘鍚堝悓鍙峰け璐�");
       }
-    } else {
-      expandedRowKeys.value = [];
-    }
-  };
-  // 涓昏〃鍚堣鏂规硶
-  const summarizeMainTable = param => {
-    return proxy.summarizeTable(param, ["contractAmount"]);
-  };
-  // 瀛愯〃鍚堣鏂规硶
-  const summarizeProTable = param => {
-    return proxy.summarizeTable(param, [
-      "taxInclusiveUnitPrice",
-      "taxInclusiveTotalPrice",
-      "taxExclusiveTotalPrice",
-    ]);
-  };
-  // 鎵撳紑寮规
-  const openForm = async (type, row) => {
-    // 缂栬緫鏃舵鏌ュ鏍哥姸鎬侊紝鍙湁寰呭鏍�(1)鍜屽鎵瑰け璐�(4)鎵嶈兘缂栬緫
-    if (type === "edit" && row) {
-      if (row.approvalStatus !== 1 && row.approvalStatus !== 4) {
-        proxy.$modal.msgWarning("鍙湁寰呭鏍稿拰瀹℃壒澶辫触鐘舵�佺殑璁板綍鎵嶈兘缂栬緫");
+    } else if (type === "edit" && row?.id) {
+      // 缂栬緫鏃跺姞杞芥暟鎹�
+      currentId.value = row.id;
+      try {
+        const purchaseRes = await getPurchaseById({id: row.id, type: 2});
+        form.value = {...purchaseRes};
+        productData.value = purchaseRes.productData || [];
+        fileList.value = purchaseRes.storageBlobVOS || [];
+      } catch (error) {
+        console.error("鍔犺浇閲囪喘鍙拌处鏁版嵁澶辫触:", error);
+        proxy.$modal.msgError("鍔犺浇鏁版嵁澶辫触");
         return;
       }
     }
-    
-    await getTemplateList();
-    operationType.value = type;
-    form.value = {};
-    productData.value = [];
-    fileList.value = [];
-    templateName.value = "";
-    filterInputValue.value = "";
-    isTemplateNameDuplicate.value = false;
+
+    if (form.value.salesLedgerId == -1) {
+      form.value.salesLedgerId = null;
+    }
+    console.log(form.value, "form.value===========");
+    dialogFormVisible.value = true;
+  } catch (error) {
+    console.error("鎵撳紑琛ㄥ崟澶辫触:", error);
+    proxy.$modal.msgError("鍔犺浇鍩虹鏁版嵁澶辫触");
+  }
+};
+
+// 涓婁紶鍓嶆牎妫�
+function handleBeforeUpload(file) {
+  // 鏍℃鏂囦欢澶у皬
+  if (file.size > 1024 * 1024 * 10) {
+    proxy.$modal.msgError("涓婁紶鏂囦欢澶у皬涓嶈兘瓒呰繃10MB!");
+    return false;
+  }
+  proxy.$modal.loading("姝e湪涓婁紶鏂囦欢锛岃绋嶅��...");
+  return true;
+}
+
+// 涓婁紶澶辫触
+function handleUploadError(err) {
+  proxy.$modal.msgError("涓婁紶鏂囦欢澶辫触");
+  proxy.$modal.closeLoading();
+}
+
+// 涓婁紶鎴愬姛鍥炶皟
+function handleUploadSuccess(res, file, uploadFiles) {
+  proxy.$modal.closeLoading();
+  if (res.code === 200) {
+    file.tempId = res.data.tempId;
+    proxy.$modal.msgSuccess("涓婁紶鎴愬姛");
+  } else {
+    proxy.$modal.msgError(res.msg);
+    proxy.$refs.fileUpload.handleRemove(file);
+  }
+}
+
+// 绉婚櫎鏂囦欢
+async function handleRemove(file) {
+  if (!file?.id) {
+    return;
+  }
+  console.log("handleRemove", file.id);
+  if (file.size > 1024 * 1024 * 10) {
+    // 浠呭墠绔竻鐞嗭紝涓嶈皟鐢ㄥ垹闄ゆ帴鍙e拰鎻愮ず
+    return;
+  }
+
+  if (operationType.value === "edit" && file.id) {
     try {
-      // 骞惰鍔犺浇鍩虹鏁版嵁
-      const [salesRes, supplierRes] = await Promise.all([
-        getSalesNo(),
-        getOptions(),
-      ]);
-
-      salesContractList.value = salesRes || [];
-      // 渚涘簲鍟嗚繃婊ゅ嚭isWhite=0 鐨勬暟鎹�
-      supplierList.value = (supplierRes.data || []).filter(
-        item => item.isWhite === 0
-      );
-
-      // 璁剧疆榛樿鍊�
-      form.value.recorderName = userStore.nickName;
-      form.value.entryDate = getCurrentDate();
-
-      if (type === "add") {
-        // 鏂板鏃剁敓鎴愰噰璐悎鍚屽彿
-        try {
-          const purchaseNoRes = await createPurchaseNo();
-          if (purchaseNoRes?.data) {
-            form.value.purchaseContractNumber = purchaseNoRes.data;
-          }
-        } catch (error) {
-          console.error("鐢熸垚閲囪喘鍚堝悓鍙峰け璐�:", error);
-          proxy.$modal.msgWarning("鐢熸垚閲囪喘鍚堝悓鍙峰け璐�");
-        }
-      } else if (type === "edit" && row?.id) {
-        // 缂栬緫鏃跺姞杞芥暟鎹�
-        currentId.value = row.id;
-        try {
-          const purchaseRes = await getPurchaseById({ id: row.id, type: 2 });
-          form.value = { ...purchaseRes };
-          productData.value = purchaseRes.productData || [];
-          fileList.value = purchaseRes.salesLedgerFiles || [];
-        } catch (error) {
-          console.error("鍔犺浇閲囪喘鍙拌处鏁版嵁澶辫触:", error);
-          proxy.$modal.msgError("鍔犺浇鏁版嵁澶辫触");
-          return;
-        }
-      }
-
-      if (form.value.salesLedgerId == -1) {
-        form.value.salesLedgerId = null;
-      }
-      console.log(form.value, "form.value===========");
-      dialogFormVisible.value = true;
+      await delLedgerFile([file.id]);
+      proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
     } catch (error) {
-      console.error("鎵撳紑琛ㄥ崟澶辫触:", error);
-      proxy.$modal.msgError("鍔犺浇鍩虹鏁版嵁澶辫触");
-    }
-  };
-  // 涓婁紶鍓嶆牎妫�
-  function handleBeforeUpload(file) {
-    // 鏍℃鏂囦欢澶у皬
-    if (file.size > 1024 * 1024 * 10) {
-      proxy.$modal.msgError("涓婁紶鏂囦欢澶у皬涓嶈兘瓒呰繃10MB!");
-      return false;
-    }
-    proxy.$modal.loading("姝e湪涓婁紶鏂囦欢锛岃绋嶅��...");
-    return true;
-  }
-  // 涓婁紶澶辫触
-  function handleUploadError(err) {
-    proxy.$modal.msgError("涓婁紶鏂囦欢澶辫触");
-    proxy.$modal.closeLoading();
-  }
-  // 涓婁紶鎴愬姛鍥炶皟
-  function handleUploadSuccess(res, file, uploadFiles) {
-    proxy.$modal.closeLoading();
-    if (res.code === 200) {
-      file.tempId = res.data.tempId;
-      proxy.$modal.msgSuccess("涓婁紶鎴愬姛");
-    } else {
-      proxy.$modal.msgError(res.msg);
-      proxy.$refs.fileUpload.handleRemove(file);
+      console.error("鍒犻櫎鏂囦欢澶辫触:", error);
+      proxy.$modal.msgError("鍒犻櫎鏂囦欢澶辫触");
     }
   }
-  // 绉婚櫎鏂囦欢
-  async function handleRemove(file) {
-    if (!file?.id) {
-      return;
-    }
-    console.log("handleRemove", file.id);
-    if (file.size > 1024 * 1024 * 10) {
-      // 浠呭墠绔竻鐞嗭紝涓嶈皟鐢ㄥ垹闄ゆ帴鍙e拰鎻愮ず
-      return;
-    }
+}
 
-    if (operationType.value === "edit" && file.id) {
-      try {
-        await delLedgerFile([file.id]);
-        proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
-      } catch (error) {
-        console.error("鍒犻櫎鏂囦欢澶辫触:", error);
-        proxy.$modal.msgError("鍒犻櫎鏂囦欢澶辫触");
-      }
-    }
-  }
-  // 鎻愪氦琛ㄥ崟
-  const submitForm = () => {
-    proxy.$refs["formRef"].validate(valid => {
-      if (valid) {
-        if (productData.value.length > 0) {
-          // 鏂板鏃讹紝闇�瑕佷粠姣忎釜浜у搧瀵硅薄涓垹闄� id 瀛楁
-          let processedProductData = productData.value;
-          if (operationType.value === "add") {
-            processedProductData = productData.value.map(product => {
-              const { id, ...rest } = product;
-              return rest;
-            });
-          }
-          form.value.productData = proxy.HaveJson(processedProductData);
-        } else {
-          proxy.$modal.msgWarning("璇锋坊鍔犱骇鍝佷俊鎭�");
-          return;
-        }
-        let tempFileIds = [];
-        if (fileList.value.length > 0) {
-          tempFileIds = fileList.value.map(item => item.tempId);
-        }
-        form.value.tempFileIds = tempFileIds;
-        form.value.type = 2;
-
-        // 濡傛灉salesLedgerId涓虹┖锛屽垯涓嶄紶閫抯alesContractNo
-        if (!form.value.salesLedgerId) {
-          form.value.salesContractNo = "";
-        }
-
-        // 鏂板鏃朵笉浼犻�抜d
-        const submitData = { ...form.value };
+// 鎻愪氦琛ㄥ崟
+const submitForm = () => {
+  proxy.$refs["formRef"].validate(valid => {
+    if (valid) {
+      if (productData.value.length > 0) {
+        // 鏂板鏃讹紝闇�瑕佷粠姣忎釜浜у搧瀵硅薄涓垹闄� id 瀛楁
+        let processedProductData = productData.value;
         if (operationType.value === "add") {
-          delete submitData.id;
+          processedProductData = productData.value.map(product => {
+            const {id, ...rest} = product;
+            return rest;
+          });
         }
-
-        addOrEditPurchase(submitData).then(res => {
-          proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
-          closeDia();
-          getList();
-        });
+        form.value.productData = proxy.HaveJson(processedProductData);
+      } else {
+        proxy.$modal.msgWarning("璇锋坊鍔犱骇鍝佷俊鎭�");
+        return;
       }
-    });
-  };
-  // 鍏抽棴寮规
-  const closeDia = () => {
-    proxy.resetForm("formRef");
-    dialogFormVisible.value = false;
-  };
-  // 鎵撳紑浜у搧寮规
-  const openProductForm = async (type, row, index) => {
-    productOperationType.value = type;
-    productOperationIndex.value = index;
-    productForm.value = {};
-    proxy.resetForm("productFormRef");
-    productFormVisible.value = true;
-    
-    // 鍏堣幏鍙栦骇鍝侀�夐」锛岀‘淇濇暟鎹姞杞藉畬鎴�
-    await getProductOptions();
-    
-    // 绛夊緟 DOM 鏇存柊
-    await nextTick();
-    
-    if (type === "add") {
-      productForm.value.isChecked = false;
-    }
+      form.value.storageBlobDTOS = fileList.value;
+      form.value.type = 2;
 
-    if (type === "edit") {
-      // 澶嶅埗琛屾暟鎹�
-      productForm.value = { ...row };
-      
-      // 濡傛灉鏄粠妯℃澘鍔犺浇鐨勬暟鎹紝鍙兘娌℃湁 productId 鍜� productModelId
-      // 闇�瑕佹牴鎹� productCategory 鍜� specificationModel 鏉ユ煡鎵惧搴旂殑 ID
-      if (!productForm.value.productId && productForm.value.productCategory) {
-        // 鏍规嵁 productCategory 鏌ユ壘 productId
-        const findProductIdByCategory = (nodes, categoryName) => {
-          for (let i = 0; i < nodes.length; i++) {
-            if (nodes[i].label === categoryName) {
-              return nodes[i].value;
-            }
-            if (nodes[i].children && nodes[i].children.length > 0) {
-              const found = findProductIdByCategory(nodes[i].children, categoryName);
-              if (found) return found;
-            }
+      // 濡傛灉salesLedgerId涓虹┖锛屽垯涓嶄紶閫抯alesContractNo
+      if (!form.value.salesLedgerId) {
+        form.value.salesContractNo = "";
+      }
+
+      // 鏂板鏃朵笉浼犻�抜d
+      const submitData = {...form.value};
+      if (operationType.value === "add") {
+        delete submitData.id;
+      }
+
+      addOrEditPurchase(submitData).then(res => {
+        proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+        closeDia();
+        getList();
+      });
+    }
+  });
+};
+// 鍏抽棴寮规
+const closeDia = () => {
+  proxy.resetForm("formRef");
+  dialogFormVisible.value = false;
+};
+// 鎵撳紑浜у搧寮规
+const openProductForm = async (type, row, index) => {
+  productOperationType.value = type;
+  productOperationIndex.value = index;
+  productForm.value = {};
+  proxy.resetForm("productFormRef");
+  productFormVisible.value = true;
+
+  // 鍏堣幏鍙栦骇鍝侀�夐」锛岀‘淇濇暟鎹姞杞藉畬鎴�
+  await getProductOptions();
+
+  // 绛夊緟 DOM 鏇存柊
+  await nextTick();
+
+  if (type === "add") {
+    productForm.value.isChecked = false;
+  }
+
+  if (type === "edit") {
+    // 澶嶅埗琛屾暟鎹�
+    productForm.value = {...row};
+
+    // 濡傛灉鏄粠妯℃澘鍔犺浇鐨勬暟鎹紝鍙兘娌℃湁 productId 鍜� productModelId
+    // 闇�瑕佹牴鎹� productCategory 鍜� specificationModel 鏉ユ煡鎵惧搴旂殑 ID
+    if (!productForm.value.productId && productForm.value.productCategory) {
+      // 鏍规嵁 productCategory 鏌ユ壘 productId
+      const findProductIdByCategory = (nodes, categoryName) => {
+        for (let i = 0; i < nodes.length; i++) {
+          if (nodes[i].label === categoryName) {
+            return nodes[i].value;
           }
-          return null;
-        };
-        
-        const productId = findProductIdByCategory(productOptions.value, productForm.value.productCategory);
-        if (productId) {
-          productForm.value.productId = productId;
-          // 鑾峰彇鍨嬪彿鍒楄〃骞剁瓑寰呭畬鎴�
-          const modelRes = await modelList({ id: productId });
-          modelOptions.value = modelRes;
-          
-          // 绛夊緟 DOM 鏇存柊
-          await nextTick();
-          
-          // 鏍规嵁 specificationModel 鏌ユ壘 productModelId
-          if (productForm.value.specificationModel && modelOptions.value.length > 0) {
-            const modelItem = modelOptions.value.find(
-              item => item.model === productForm.value.specificationModel
-            );
-            if (modelItem) {
-              productForm.value.productModelId = modelItem.id;
-              // 璁剧疆瑙勬牸鍨嬪彿鍜屽崟浣�
-              getProductModel(modelItem.id);
-            }
+          if (nodes[i].children && nodes[i].children.length > 0) {
+            const found = findProductIdByCategory(nodes[i].children, categoryName);
+            if (found) return found;
           }
         }
-      } else if (productForm.value.productId) {
-        // 濡傛灉鏈� productId锛屾甯稿姞杞藉瀷鍙峰垪琛�
-        await getModels(productForm.value.productId);
-        
+        return null;
+      };
+
+      const productId = findProductIdByCategory(productOptions.value, productForm.value.productCategory);
+      if (productId) {
+        productForm.value.productId = productId;
+        // 鑾峰彇鍨嬪彿鍒楄〃骞剁瓑寰呭畬鎴�
+        const modelRes = await modelList({id: productId});
+        modelOptions.value = modelRes;
+
         // 绛夊緟 DOM 鏇存柊
         await nextTick();
-        
-        if (productForm.value.productModelId) {
-          getProductModel(productForm.value.productModelId);
+
+        // 鏍规嵁 specificationModel 鏌ユ壘 productModelId
+        if (productForm.value.specificationModel && modelOptions.value.length > 0) {
+          const modelItem = modelOptions.value.find(
+              item => item.model === productForm.value.specificationModel
+          );
+          if (modelItem) {
+            productForm.value.productModelId = modelItem.id;
+            // 璁剧疆瑙勬牸鍨嬪彿鍜屽崟浣�
+            getProductModel(modelItem.id);
+          }
         }
       }
-      
-      // 鏈�鍚庡啀绛夊緟涓�娆� DOM 鏇存柊锛岀‘淇濇墍鏈夋暟鎹兘宸茶缃�
+    } else if (productForm.value.productId) {
+      // 濡傛灉鏈� productId锛屾甯稿姞杞藉瀷鍙峰垪琛�
+      await getModels(productForm.value.productId);
+
+      // 绛夊緟 DOM 鏇存柊
       await nextTick();
+
+      if (productForm.value.productModelId) {
+        getProductModel(productForm.value.productModelId);
+      }
     }
-  };
-  const getProductOptions = () => {
-    return productTreeList().then(res => {
-      productOptions.value = convertIdToValue(res);
+
+    // 鏈�鍚庡啀绛夊緟涓�娆� DOM 鏇存柊锛岀‘淇濇墍鏈夋暟鎹兘宸茶缃�
+    await nextTick();
+  }
+};
+const getProductOptions = () => {
+  return productTreeList().then(res => {
+    productOptions.value = convertIdToValue(res);
+    return res;
+  });
+};
+const getModels = value => {
+  if (value) {
+    productForm.value.productCategory =
+        findNodeById(productOptions.value, value) || "";
+    return modelList({id: value}).then(res => {
+      modelOptions.value = res;
       return res;
     });
-  };
-  const getModels = value => {
-    if (value) {
-      productForm.value.productCategory =
-        findNodeById(productOptions.value, value) || "";
-      return modelList({ id: value }).then(res => {
-        modelOptions.value = res;
-        return res;
-      });
-    } else {
-      productForm.value.productCategory = "";
-      modelOptions.value = [];
-      return Promise.resolve([]);
-    }
-  };
-  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; // 鎵惧埌鑺傜偣锛岃繑鍥炶鑺傜偣鐨刲abel
-      }
-      if (nodes[i].children && nodes[i].children.length > 0) {
-        const foundNode = findNodeById(nodes[i].children, productId);
-        if (foundNode) {
-          return foundNode; // 鍦ㄥ瓙鑺傜偣涓壘鍒帮紝鐩存帴杩斿洖锛堝凡缁忔槸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;
-    });
+  } else {
+    productForm.value.productCategory = "";
+    modelOptions.value = [];
+    return Promise.resolve([]);
   }
-  // 鎻愪氦浜у搧琛ㄥ崟
-  const submitProduct = () => {
-    proxy.$refs["productFormRef"].validate(valid => {
-      if (valid) {
-        if (operationType.value === "edit") {
-          submitProductEdit();
-        } else {
-          if (productOperationType.value === "add") {
-            productData.value.push({ ...productForm.value });
-            console.log("productData.value---", productData.value);
-          } else {
-            productData.value[productOperationIndex.value] = {
-              ...productForm.value,
-            };
-          }
-          closeProductDia();
-        }
-      }
-    });
-  };
-  const submitProductEdit = () => {
-    productForm.value.salesLedgerId = currentId.value;
-    productForm.value.type = 2;
-    addOrUpdateSalesLedgerProduct(productForm.value).then(res => {
-      proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
-      closeProductDia();
-      getPurchaseById({ id: currentId.value, type: 2 }).then(res => {
-        productData.value = res.productData;
-      });
-    });
-  };
-  // 鍒犻櫎浜у搧
-  const deleteProduct = () => {
-    if (productSelectedRows.value.length === 0) {
-      proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
-      return;
+};
+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; // 鎵惧埌鑺傜偣锛岃繑鍥炶鑺傜偣鐨刲abel
     }
-    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 (nodes[i].children && nodes[i].children.length > 0) {
+      const foundNode = findNodeById(nodes[i].children, productId);
+      if (foundNode) {
+        return foundNode; // 鍦ㄥ瓙鑺傜偣涓壘鍒帮紝鐩存帴杩斿洖锛堝凡缁忔槸label瀛楃涓诧級
       }
-      ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "瀵煎嚭", {
-        confirmButtonText: "纭",
-        cancelButtonText: "鍙栨秷",
-        type: "warning",
-      })
+    }
+  }
+  return null; // 娌℃湁鎵惧埌鑺傜偣锛岃繑鍥瀗ull
+};
+
+function convertIdToValue(data) {
+  return data.map(item => {
+    const {id, children, ...rest} = item;
+    const newItem = {
+      ...rest,
+      value: id, // 灏� id 鏀逛负 value
+    };
+    if (children && children.length > 0) {
+      newItem.children = convertIdToValue(children);
+    }
+
+    return newItem;
+  });
+}
+
+// 鎻愪氦浜у搧琛ㄥ崟
+const submitProduct = () => {
+  proxy.$refs["productFormRef"].validate(valid => {
+    if (valid) {
+      if (operationType.value === "edit") {
+        submitProductEdit();
+      } else {
+        if (productOperationType.value === "add") {
+          productData.value.push({...productForm.value});
+          console.log("productData.value---", productData.value);
+        } else {
+          productData.value[productOperationIndex.value] = {
+            ...productForm.value,
+          };
+        }
+        closeProductDia();
+      }
+    }
+  });
+};
+const submitProductEdit = () => {
+  productForm.value.salesLedgerId = currentId.value;
+  productForm.value.type = 2;
+  addOrUpdateSalesLedgerProduct(productForm.value).then(res => {
+    proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+    closeProductDia();
+    getPurchaseById({id: currentId.value, type: 2}).then(res => {
+      productData.value = res.productData;
+    });
+  });
+};
+// 鍒犻櫎浜у搧
+const deleteProduct = () => {
+  if (productSelectedRows.value.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);
+    }
+    ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "瀵煎嚭", {
+      confirmButtonText: "纭",
+      cancelButtonText: "鍙栨秷",
+      type: "warning",
+    })
         .then(() => {
           delProduct(ids).then(res => {
             proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
             closeProductDia();
-            getPurchaseById({ id: currentId.value, type: 2 }).then(
-              res => {
-                productData.value = res.productData;
-              }
+            getPurchaseById({id: currentId.value, type: 2}).then(
+                res => {
+                  productData.value = res.productData;
+                }
             );
           });
         })
         .catch(() => {
           proxy.$modal.msg("宸插彇娑�");
         });
-    }
-  };
-  // 鍏抽棴浜у搧寮规
-  const closeProductDia = () => {
-    proxy.resetForm("productFormRef");
-    productFormVisible.value = false;
-  };
-  // 瀵煎嚭
-  const handleOut = () => {
-    ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
-      confirmButtonText: "纭",
-      cancelButtonText: "鍙栨秷",
-      type: "warning",
-    })
+  }
+};
+// 鍏抽棴浜у搧寮规
+const closeProductDia = () => {
+  proxy.resetForm("productFormRef");
+  productFormVisible.value = false;
+};
+// 瀵煎嚭
+const handleOut = () => {
+  ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
+    confirmButtonText: "纭",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  })
       .then(() => {
         proxy.download("/purchase/ledger/export", {}, "閲囪喘鍙拌处.xlsx");
       })
       .catch(() => {
         proxy.$modal.msg("宸插彇娑�");
       });
-  };
-  // 鍒犻櫎
-  const handleDelete = () => {
-    let ids = [];
-    if (selectedRows.value.length > 0) {
-      ids = selectedRows.value.filter(item => item.salesLedgerId === null).map(item => item.id);
-    } else {
-      proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
-      return;
-    }
-    ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "鍒犻櫎", {
-      confirmButtonText: "纭",
-      cancelButtonText: "鍙栨秷",
-      type: "warning",
-    })
+};
+// 鍒犻櫎
+const handleDelete = () => {
+  let ids = [];
+  if (selectedRows.value.length > 0) {
+    ids = selectedRows.value.filter(item => item.salesLedgerId === null).map(item => item.id);
+  } else {
+    proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
+    return;
+  }
+  ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "鍒犻櫎", {
+    confirmButtonText: "纭",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  })
       .then(() => {
         delPurchase(ids).then(res => {
           proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
@@ -1612,172 +1604,172 @@
       .catch(() => {
         proxy.$modal.msg("宸插彇娑�");
       });
-  };
-  // 鑾峰彇褰撳墠鏃ユ湡骞舵牸寮忓寲涓� YYYY-MM-DD
-  function getCurrentDate() {
-    const today = new Date();
-    const year = today.getFullYear();
-    const month = String(today.getMonth() + 1).padStart(2, "0"); // 鏈堜唤浠�0寮�濮�
-    const day = String(today.getDate()).padStart(2, "0");
-    return `${year}-${month}-${day}`;
-  }
-  const mathNum = () => {
-    if (!productForm.value.taxRate) {
-      proxy.$modal.msgWarning("璇峰厛閫夋嫨绋庣巼");
-      return;
-    }
-    if (!productForm.value.taxInclusiveUnitPrice) {
-      return;
-    }
-    if (!productForm.value.quantity) {
-      return;
-    }
-    // 鍚◣鎬讳环璁$畻
-    productForm.value.taxInclusiveTotalPrice =
-      proxy.calculateTaxIncludeTotalPrice(
-        productForm.value.taxInclusiveUnitPrice,
-        productForm.value.quantity
-      );
-    if (productForm.value.taxRate) {
-      // 涓嶅惈绋庢�讳环璁$畻
-      productForm.value.taxExclusiveTotalPrice =
-        proxy.calculateTaxExclusiveTotalPrice(
-          productForm.value.taxInclusiveTotalPrice,
-          productForm.value.taxRate
-        );
-    }
-  };
-  const reverseMathNum = field => {
-    if (!productForm.value.taxRate) {
-      proxy.$modal.msgWarning("璇峰厛閫夋嫨绋庣巼");
-      return;
-    }
-    const taxRate = Number(productForm.value.taxRate);
-    if (!taxRate) return;
+};
 
-    // 纭繚杈撳叆鍊间笉涓鸿礋鏁�
-    if (
+// 鑾峰彇褰撳墠鏃ユ湡骞舵牸寮忓寲涓� YYYY-MM-DD
+function getCurrentDate() {
+  const today = new Date();
+  const year = today.getFullYear();
+  const month = String(today.getMonth() + 1).padStart(2, "0"); // 鏈堜唤浠�0寮�濮�
+  const day = String(today.getDate()).padStart(2, "0");
+  return `${year}-${month}-${day}`;
+}
+
+const mathNum = () => {
+  if (!productForm.value.taxRate) {
+    proxy.$modal.msgWarning("璇峰厛閫夋嫨绋庣巼");
+    return;
+  }
+  if (!productForm.value.taxInclusiveUnitPrice) {
+    return;
+  }
+  if (!productForm.value.quantity) {
+    return;
+  }
+  // 鍚◣鎬讳环璁$畻
+  productForm.value.taxInclusiveTotalPrice =
+      proxy.calculateTaxIncludeTotalPrice(
+          productForm.value.taxInclusiveUnitPrice,
+          productForm.value.quantity
+      );
+  if (productForm.value.taxRate) {
+    // 涓嶅惈绋庢�讳环璁$畻
+    productForm.value.taxExclusiveTotalPrice =
+        proxy.calculateTaxExclusiveTotalPrice(
+            productForm.value.taxInclusiveTotalPrice,
+            productForm.value.taxRate
+        );
+  }
+};
+const reverseMathNum = field => {
+  if (!productForm.value.taxRate) {
+    proxy.$modal.msgWarning("璇峰厛閫夋嫨绋庣巼");
+    return;
+  }
+  const taxRate = Number(productForm.value.taxRate);
+  if (!taxRate) return;
+
+  // 纭繚杈撳叆鍊间笉涓鸿礋鏁�
+  if (
       field === "taxInclusiveTotalPrice" ||
       field === "taxExclusiveTotalPrice"
-    ) {
-      const value = Number(productForm.value[field]);
-      if (value < 0) {
-        productForm.value[field] = "0";
-        proxy.$modal.msgWarning("鍊间笉鑳藉皬浜�0");
-        return;
-      }
-    }
-
-    if (field === "taxInclusiveTotalPrice") {
-      // 宸茬煡鍚◣鎬讳环鍜屾暟閲忥紝鍙嶇畻鍚◣鍗曚环
-      if (productForm.value.quantity) {
-        productForm.value.taxInclusiveUnitPrice = (
-          Number(productForm.value.taxInclusiveTotalPrice) /
-          Number(productForm.value.quantity)
-        ).toFixed(2);
-        // 纭繚缁撴灉涓嶄负璐熸暟
-        if (Number(productForm.value.taxInclusiveUnitPrice) < 0) {
-          productForm.value.taxInclusiveUnitPrice = "0";
-        }
-      }
-      // 宸茬煡鍚◣鎬讳环鍜屽惈绋庡崟浠凤紝鍙嶇畻鏁伴噺
-      else if (productForm.value.taxInclusiveUnitPrice) {
-        productForm.value.quantity = (
-          Number(productForm.value.taxInclusiveTotalPrice) /
-          Number(productForm.value.taxInclusiveUnitPrice)
-        ).toFixed(2);
-        // 纭繚缁撴灉涓嶄负璐熸暟
-        if (Number(productForm.value.quantity) < 0) {
-          productForm.value.quantity = "0";
-        }
-      }
-      // 鍙嶇畻涓嶅惈绋庢�讳环
-      productForm.value.taxExclusiveTotalPrice = (
-        Number(productForm.value.taxInclusiveTotalPrice) /
-        (1 + taxRate / 100)
-      ).toFixed(2);
-      // 纭繚缁撴灉涓嶄负璐熸暟
-      if (Number(productForm.value.taxExclusiveTotalPrice) < 0) {
-        productForm.value.taxExclusiveTotalPrice = "0";
-      }
-    } else if (field === "taxExclusiveTotalPrice") {
-      // 鍙嶇畻鍚◣鎬讳环
-      productForm.value.taxInclusiveTotalPrice = (
-        Number(productForm.value.taxExclusiveTotalPrice) *
-        (1 + taxRate / 100)
-      ).toFixed(2);
-      // 纭繚缁撴灉涓嶄负璐熸暟
-      if (Number(productForm.value.taxInclusiveTotalPrice) < 0) {
-        productForm.value.taxInclusiveTotalPrice = "0";
-      }
-      // 宸茬煡鏁伴噺锛屽弽绠楀惈绋庡崟浠�
-      if (productForm.value.quantity) {
-        productForm.value.taxInclusiveUnitPrice = (
-          Number(productForm.value.taxInclusiveTotalPrice) /
-          Number(productForm.value.quantity)
-        ).toFixed(2);
-        // 纭繚缁撴灉涓嶄负璐熸暟
-        if (Number(productForm.value.taxInclusiveUnitPrice) < 0) {
-          productForm.value.taxInclusiveUnitPrice = "0";
-        }
-      }
-      // 宸茬煡鍚◣鍗曚环锛屽弽绠楁暟閲�
-      else if (productForm.value.taxInclusiveUnitPrice) {
-        productForm.value.quantity = (
-          Number(productForm.value.taxInclusiveTotalPrice) /
-          Number(productForm.value.taxInclusiveUnitPrice)
-        ).toFixed(2);
-        // 纭繚缁撴灉涓嶄负璐熸暟
-        if (Number(productForm.value.quantity) < 0) {
-          productForm.value.quantity = "0";
-        }
-      }
-    }
-  };
-  // 閿�鍞悎鍚岄�夋嫨鏀瑰彉鏂规硶
-  const salesLedgerChange = async row => {
-    console.log("row", row);
-    var index = salesContractList.value.findIndex(item => item.id == row);
-    console.log("index", index);
-    if (index > -1) {
-      await querygProductInfoByContractNo();
-    }
-  };
-
-  const querygProductInfoByContractNo = async () => {
-    const { code, data } = await getProductInfoByContractNo({
-      contractNo: form.value.salesLedgerId,
-    });
-    if (code == 200) {
-      productData.value = data;
-    }
-  };
-
-  const fileListRef = ref(null);
-  const fileListDialogVisible = ref(false);
-  const downLoadFile = row => {
-    if (fileListRef.value) {
-      fileListRef.value.open(row.salesLedgerFiles);
-    }
-  };
-
-  // 鑾峰彇妯℃澘淇℃伅
-  const getTemplateList = async () => {
-    let res = await getPurchaseTemplateList();
-    if (res && res.code === 200 && Array.isArray(res.data)) {
-      templateList.value = res.data;
-    }
-  };
-
-  // 鍒犻櫎妯℃澘
-  const handleDeleteTemplate = async (item) => {
-    if (!item.id) {
-      proxy.$modal.msgWarning("鏃犳硶鍒犻櫎璇ユā鏉�");
+  ) {
+    const value = Number(productForm.value[field]);
+    if (value < 0) {
+      productForm.value[field] = "0";
+      proxy.$modal.msgWarning("鍊间笉鑳藉皬浜�0");
       return;
     }
-    
-    try {
-      await ElMessageBox.confirm(
+  }
+
+  if (field === "taxInclusiveTotalPrice") {
+    // 宸茬煡鍚◣鎬讳环鍜屾暟閲忥紝鍙嶇畻鍚◣鍗曚环
+    if (productForm.value.quantity) {
+      productForm.value.taxInclusiveUnitPrice = (
+          Number(productForm.value.taxInclusiveTotalPrice) /
+          Number(productForm.value.quantity)
+      ).toFixed(2);
+      // 纭繚缁撴灉涓嶄负璐熸暟
+      if (Number(productForm.value.taxInclusiveUnitPrice) < 0) {
+        productForm.value.taxInclusiveUnitPrice = "0";
+      }
+    }
+    // 宸茬煡鍚◣鎬讳环鍜屽惈绋庡崟浠凤紝鍙嶇畻鏁伴噺
+    else if (productForm.value.taxInclusiveUnitPrice) {
+      productForm.value.quantity = (
+          Number(productForm.value.taxInclusiveTotalPrice) /
+          Number(productForm.value.taxInclusiveUnitPrice)
+      ).toFixed(2);
+      // 纭繚缁撴灉涓嶄负璐熸暟
+      if (Number(productForm.value.quantity) < 0) {
+        productForm.value.quantity = "0";
+      }
+    }
+    // 鍙嶇畻涓嶅惈绋庢�讳环
+    productForm.value.taxExclusiveTotalPrice = (
+        Number(productForm.value.taxInclusiveTotalPrice) /
+        (1 + taxRate / 100)
+    ).toFixed(2);
+    // 纭繚缁撴灉涓嶄负璐熸暟
+    if (Number(productForm.value.taxExclusiveTotalPrice) < 0) {
+      productForm.value.taxExclusiveTotalPrice = "0";
+    }
+  } else if (field === "taxExclusiveTotalPrice") {
+    // 鍙嶇畻鍚◣鎬讳环
+    productForm.value.taxInclusiveTotalPrice = (
+        Number(productForm.value.taxExclusiveTotalPrice) *
+        (1 + taxRate / 100)
+    ).toFixed(2);
+    // 纭繚缁撴灉涓嶄负璐熸暟
+    if (Number(productForm.value.taxInclusiveTotalPrice) < 0) {
+      productForm.value.taxInclusiveTotalPrice = "0";
+    }
+    // 宸茬煡鏁伴噺锛屽弽绠楀惈绋庡崟浠�
+    if (productForm.value.quantity) {
+      productForm.value.taxInclusiveUnitPrice = (
+          Number(productForm.value.taxInclusiveTotalPrice) /
+          Number(productForm.value.quantity)
+      ).toFixed(2);
+      // 纭繚缁撴灉涓嶄负璐熸暟
+      if (Number(productForm.value.taxInclusiveUnitPrice) < 0) {
+        productForm.value.taxInclusiveUnitPrice = "0";
+      }
+    }
+    // 宸茬煡鍚◣鍗曚环锛屽弽绠楁暟閲�
+    else if (productForm.value.taxInclusiveUnitPrice) {
+      productForm.value.quantity = (
+          Number(productForm.value.taxInclusiveTotalPrice) /
+          Number(productForm.value.taxInclusiveUnitPrice)
+      ).toFixed(2);
+      // 纭繚缁撴灉涓嶄负璐熸暟
+      if (Number(productForm.value.quantity) < 0) {
+        productForm.value.quantity = "0";
+      }
+    }
+  }
+};
+// 閿�鍞悎鍚岄�夋嫨鏀瑰彉鏂规硶
+const salesLedgerChange = async row => {
+  console.log("row", row);
+  var index = salesContractList.value.findIndex(item => item.id == row);
+  console.log("index", index);
+  if (index > -1) {
+    await querygProductInfoByContractNo();
+  }
+};
+
+const querygProductInfoByContractNo = async () => {
+  const {code, data} = await getProductInfoByContractNo({
+    contractNo: form.value.salesLedgerId,
+  });
+  if (code == 200) {
+    productData.value = data;
+  }
+};
+
+// 鑾峰彇妯℃澘淇℃伅
+const getTemplateList = async () => {
+  let res = await getPurchaseTemplateList();
+  if (res && res.code === 200 && Array.isArray(res.data)) {
+    templateList.value = res.data;
+  }
+};
+
+// 鎵撳紑闄勪欢寮规
+const openFileDialog = async (row) => {
+  recordId.value = row.id
+  fileListDialogVisible.value = true
+}
+
+// 鍒犻櫎妯℃澘
+const handleDeleteTemplate = async (item) => {
+  if (!item.id) {
+    proxy.$modal.msgWarning("鏃犳硶鍒犻櫎璇ユā鏉�");
+    return;
+  }
+
+  try {
+    await ElMessageBox.confirm(
         `纭畾瑕佸垹闄ゆā鏉�"${item.templateName}"鍚楋紵`,
         "鍒犻櫎纭",
         {
@@ -1785,118 +1777,122 @@
           cancelButtonText: "鍙栨秷",
           type: "warning",
         }
-      );
-      
-      const res = await delPurchaseTemplate([item.id]);
-      if (res && res.code === 200) {
-        ElMessage({
-          message: "鍒犻櫎鎴愬姛",
-          type: "success",
-        });
-        // 濡傛灉鍒犻櫎鐨勬槸褰撳墠閫変腑鐨勬ā鏉匡紝娓呯┖閫夋嫨
-        if (templateName.value === item.templateName) {
-          templateName.value = "";
-          filterInputValue.value = "";
-        }
-        // 閲嶆柊鑾峰彇妯℃澘鍒楄〃
-        await getTemplateList();
-      } else {
-        ElMessage({
-          message: res?.msg || "鍒犻櫎澶辫触",
-          type: "error",
-        });
-      }
-    } catch (error) {
-      if (error !== "cancel") {
-        console.error("鍒犻櫎妯℃澘澶辫触:", error);
-        ElMessage({
-          message: "鍒犻櫎澶辫触锛岃绋嶅悗閲嶈瘯",
-          type: "error",
-        });
-      }
-    }
-  };
+    );
 
-  onMounted(() => {
-    getList();
-    getTemplateList();
-  });
+    const res = await delPurchaseTemplate([item.id]);
+    if (res && res.code === 200) {
+      ElMessage({
+        message: "鍒犻櫎鎴愬姛",
+        type: "success",
+      });
+      // 濡傛灉鍒犻櫎鐨勬槸褰撳墠閫変腑鐨勬ā鏉匡紝娓呯┖閫夋嫨
+      if (templateName.value === item.templateName) {
+        templateName.value = "";
+        filterInputValue.value = "";
+      }
+      // 閲嶆柊鑾峰彇妯℃澘鍒楄〃
+      await getTemplateList();
+    } else {
+      ElMessage({
+        message: res?.msg || "鍒犻櫎澶辫触",
+        type: "error",
+      });
+    }
+  } catch (error) {
+    if (error !== "cancel") {
+      console.error("鍒犻櫎妯℃澘澶辫触:", error);
+      ElMessage({
+        message: "鍒犻櫎澶辫触锛岃绋嶅悗閲嶈瘯",
+        type: "error",
+      });
+    }
+  }
+};
+
+onMounted(() => {
+  getList();
+  getTemplateList();
+});
 </script>
 
 <style scoped lang="scss">
-  .invalid-row {
-    opacity: 0.6;
-    background-color: #f5f7fa;
+.invalid-row {
+  opacity: 0.6;
+  background-color: #f5f7fa;
+}
+
+.el-row {
+  justify-content: space-between;
+  align-items: center;
+}
+
+.no-arrow-select {
+  --el-select-suffix-icon-color: transparent; /* 闅愯棌榛樿涓嬫媺绠ご */
+}
+
+.select-button-group {
+  display: flex;
+  align-items: center;
+}
+
+// 瀹℃壒浜鸿妭鐐瑰鍣ㄦ牱寮�
+.approver-nodes-container {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 16px;
+  padding: 16px;
+  background-color: #f8f9fa;
+  border-radius: 4px;
+  border: 1px solid #e4e7ed;
+}
+
+.approver-node-item {
+  flex: 0 0 calc(33.333% - 12px);
+  min-width: 200px;
+  padding: 12px;
+  background-color: #fff;
+  border-radius: 4px;
+  border: 1px solid #dcdfe6;
+  transition: all 0.3s;
+
+  &:hover {
+    border-color: #409eff;
+    box-shadow: 0 2px 8px rgba(64, 158, 255, 0.1);
   }
-  .el-row {
-    justify-content: space-between;
-    align-items: center;
-  }
-  .no-arrow-select {
-    --el-select-suffix-icon-color: transparent; /* 闅愯棌榛樿涓嬫媺绠ご */
-  }
-  .select-button-group {
-    display: flex;
-    align-items: center;
-  }
-  
-  // 瀹℃壒浜鸿妭鐐瑰鍣ㄦ牱寮�
-  .approver-nodes-container {
-    display: flex;
-    flex-wrap: wrap;
-    gap: 16px;
-    padding: 16px;
-    background-color: #f8f9fa;
-    border-radius: 4px;
-    border: 1px solid #e4e7ed;
-  }
-  
+}
+
+.approver-node-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 8px;
+}
+
+.approver-node-label {
+  font-size: 13px;
+  font-weight: 500;
+  color: #606266;
+}
+
+@media (max-width: 1200px) {
   .approver-node-item {
-    flex: 0 0 calc(33.333% - 12px);
-    min-width: 200px;
-    padding: 12px;
-    background-color: #fff;
-    border-radius: 4px;
-    border: 1px solid #dcdfe6;
-    transition: all 0.3s;
-    
-    &:hover {
-      border-color: #409eff;
-      box-shadow: 0 2px 8px rgba(64, 158, 255, 0.1);
-    }
+    flex: 0 0 calc(50% - 8px);
   }
-  
-  .approver-node-header {
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
-    margin-bottom: 8px;
+}
+
+@media (max-width: 768px) {
+  .approver-node-item {
+    flex: 0 0 100%;
   }
-  
-  .approver-node-label {
-    font-size: 13px;
-    font-weight: 500;
-    color: #606266;
+}
+
+// 鍒犻櫎鍥炬爣鏍峰紡
+.delete-icon {
+  transition: all 0.3s;
+
+  &:hover {
+    color: #f56c6c !important;
+    transform: scale(1.2);
   }
-  
-  @media (max-width: 1200px) {
-    .approver-node-item {
-      flex: 0 0 calc(50% - 8px);
-    }
-  }
-  
-  @media (max-width: 768px) {
-    .approver-node-item {
-      flex: 0 0 100%;
-    }
-  }
-  
-  // 鍒犻櫎鍥炬爣鏍峰紡
-  .delete-icon {
-    transition: all 0.3s;
-    &:hover {
-      color: #f56c6c !important;
-      transform: scale(1.2);
-    }
-  }
+}
 </style>
diff --git a/src/views/productionManagement/processRoute/index.vue b/src/views/productionManagement/processRoute/index.vue
index 4a713dc..43425c6 100644
--- a/src/views/productionManagement/processRoute/index.vue
+++ b/src/views/productionManagement/processRoute/index.vue
@@ -61,7 +61,8 @@
   import EditProcess from "@/views/productionManagement/processRoute/Edit.vue";
   import RouteItemForm from "@/views/productionManagement/processRoute/ItemsForm.vue";
   import { listPage, del } from "@/api/productionManagement/processRoute.js";
-  import FileList from "@/components/Dialog/FileList.vue";
+  const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue"));
+
   import { useRouter } from "vue-router";
   import { ElMessage, ElMessageBox } from "element-plus";
 
diff --git a/src/views/productionManagement/processRoute/processRouteItem/index.vue b/src/views/productionManagement/processRoute/processRouteItem/index.vue
index fd1a6a8..6d64c30 100644
--- a/src/views/productionManagement/processRoute/processRouteItem/index.vue
+++ b/src/views/productionManagement/processRoute/processRouteItem/index.vue
@@ -68,7 +68,8 @@
                    style="margin-right: 10px;">
           鍗$墖瑙嗗浘
         </el-button>
-        <el-button type="primary"
+        <el-button v-if="editable"
+                   type="primary"
                    @click="handleAdd">鏂板</el-button>
       </div>
     </div>
@@ -133,12 +134,12 @@
                      link
                      size="small"
                      @click="handleEdit(scope.row)"
-                     :disabled="scope.row.isComplete">缂栬緫</el-button>
+                     :disabled="scope.row.isComplete || !editable">缂栬緫</el-button>
           <el-button type="danger"
                      link
                      size="small"
                      @click="handleDelete(scope.row)"
-                     :disabled="scope.row.isComplete">鍒犻櫎</el-button>
+                     :disabled="scope.row.isComplete || !editable">鍒犻櫎</el-button>
         </template>
       </el-table-column>
     </el-table>
@@ -152,7 +153,8 @@
                      style="margin-right: 10px;">
             琛ㄦ牸瑙嗗浘
           </el-button>
-          <el-button type="primary"
+          <el-button v-if="editable"
+                     type="primary"
                      @click="handleAdd">鏂板</el-button>
         </div>
       </div>
@@ -196,7 +198,7 @@
                          link
                          size="small"
                          @click="handleEdit(item)"
-                         :disabled="item.isComplete">缂栬緫</el-button>
+                         :disabled="item.isComplete || !editable">缂栬緫</el-button>
               <el-button type="info"
                          link
                          size="small"
@@ -205,7 +207,7 @@
                          link
                          size="small"
                          @click="handleDelete(item)"
-                         :disabled="item.isComplete">鍒犻櫎</el-button>
+                         :disabled="item.isComplete || !editable">鍒犻櫎</el-button>
             </div>
           </div>
         </div>
@@ -216,7 +218,7 @@
          style="margin-top: 20px;">
       <div class="section-title">BOM 缁撴瀯</div>
       <div class="section-actions"
-           v-if="pageType === 'order'">
+           v-if="pageType === 'order' && editable">
         <el-button v-if="!bomDataValue.isEdit"
                    type="primary"
                    @click="bomDataValue.isEdit = true">
@@ -447,7 +449,6 @@
                          @confirm="handleProductSelect"
                          single />
     <!-- 鍙傛暟鍒楄〃瀵硅瘽妗� -->
-    <!-- :editable="!routeInfo.status" -->
     <ProcessParamListDialog v-model="showParamListDialog"
                             :title="`${currentProcess ? (currentProcess.processName || currentProcess.technologyOperationName || currentProcess.operationName) : ''} - 鍙傛暟鍒楄〃`"
                             :route-id="routeId"
@@ -455,6 +456,7 @@
                             :process="currentProcess"
                             :page-type="pageType"
                             :param-list="paramList"
+                            :editable="editable"
                             @getsyncProcessParamItem="getsyncProcessParamItem"
                             @refresh="refreshParamList" />
   </div>
@@ -509,6 +511,7 @@
   const routeId = computed(() => route.query.id);
   const orderId = computed(() => route.query.orderId);
   const pageType = computed(() => route.query.type);
+  const editable = computed(() => route.query.editable !== "false");
 
   const tableLoading = ref(false);
   const tableData = ref([]);
@@ -878,6 +881,7 @@
   // 鍒濆鍖栨嫋鎷芥帓搴�
   const initSortable = () => {
     destroySortable();
+    if (!editable.value) return;
 
     if (viewMode.value === "table") {
       // 琛ㄦ牸瑙嗗浘鐨勬嫋鎷芥帓搴�
diff --git a/src/views/productionManagement/productionOrder/components/MaterialDetailDialog.vue b/src/views/productionManagement/productionOrder/components/MaterialDetailDialog.vue
index e9b2646..370815e 100644
--- a/src/views/productionManagement/productionOrder/components/MaterialDetailDialog.vue
+++ b/src/views/productionManagement/productionOrder/components/MaterialDetailDialog.vue
@@ -55,14 +55,15 @@
                              controls-position="right"
                              placeholder="杈撳叆瀹為檯鏁伴噺"
                              style="width: 100%;"
-                             :disabled="row.returned"
+                             :disabled="row.returned || orderRow?.end"
                              @change="val => handleActualQtyChange(row, val)" />
           </template>
         </el-table-column>
       </el-table>
       <template #footer>
         <span class="dialog-footer">
-          <el-button type="warning"
+          <el-button v-if="!orderRow?.end"
+                     type="warning"
                      :loading="materialReturnConfirming"
                      :disabled="!canOpenReturnSummary"
                      @click="openReturnSummaryDialog">
diff --git a/src/views/productionManagement/productionOrder/index.vue b/src/views/productionManagement/productionOrder/index.vue
index 28356dd..93fc177 100644
--- a/src/views/productionManagement/productionOrder/index.vue
+++ b/src/views/productionManagement/productionOrder/index.vue
@@ -40,6 +40,8 @@
                        value="3" />
             <el-option label="宸插彇娑�"
                        value="4" />
+            <el-option label="宸茬粨鏉�"
+                       value="5" />
           </el-select>
         </el-form-item>
         <el-form-item>
@@ -65,6 +67,7 @@
                 :tableLoading="tableLoading"
                 :row-class-name="tableRowClassName"
                 :isSelection="true"
+                :selectable="row => !row.endOrder"
                 @selection-change="handleSelectionChange"
                 @pagination="pagination">
         <template #completionStatus="{ row }">
@@ -210,6 +213,7 @@
     listProcessBom,
     delProductOrder,
     getProductOrderSource,
+    updateProductOrder,
   } from "@/api/productionManagement/productionOrder.js";
   import { listMain as getOrderProcessRouteMain } from "@/api/productionManagement/productProcessRoute.js";
   import MaterialLedgerDialog from "@/views/productionManagement/productionOrder/components/MaterialLedgerDialog.vue";
@@ -243,7 +247,7 @@
       prop: "npsNo",
       width: "150px",
     },
-    // 1.寰呭紑濮嬨��2.杩涜涓��3.宸插畬鎴愩��4.宸插彇娑�
+    // 1.寰呭紑濮嬨��2.杩涜涓��3.宸插畬鎴愩��4.宸插彇娑堛��5.宸茬粨鏉�
     {
       label: "鐘舵��",
       prop: "status",
@@ -256,6 +260,8 @@
           ? "杩涜涓�"
           : val === 3
           ? "宸插畬鎴�"
+          : val === 5
+          ? "宸茬粨鏉�"
           : "宸插彇娑�",
       formatType: val =>
         val === 1
@@ -264,7 +270,9 @@
           ? "warning"
           : val === 3
           ? "success"
-          : "danger",
+          : val === 5
+          ? "danger"
+          : "info",
     },
     {
       label: "浜у搧鍚嶇О",
@@ -319,7 +327,7 @@
       label: "鎿嶄綔",
       align: "center",
       fixed: "right",
-      width: 260,
+      width: 280,
       operation: [
         {
           name: "宸ヨ壓璺嚎",
@@ -332,7 +340,7 @@
         {
           name: "缁戝畾宸ヨ壓璺嚎",
           type: "text",
-          showHide: row => !row.processRouteCode,
+          showHide: row => !row.processRouteCode && !row.endOrder,
           clickFun: row => {
             openBindRouteDialog(row, "add");
           },
@@ -340,7 +348,7 @@
         {
           name: "鏇存崲宸ヨ壓璺嚎",
           type: "text",
-          showHide: row => row.processRouteCode,
+          showHide: row => row.processRouteCode && !row.endOrder,
           clickFun: row => {
             openBindRouteDialog(row, "change");
           },
@@ -356,6 +364,7 @@
           name: "棰嗘枡",
           type: "text",
           color: "#5EC7AB",
+          showHide: row => !row.endOrder,
           clickFun: row => {
             openMaterialDialog(row);
           },
@@ -364,6 +373,7 @@
           name: "琛ユ枡",
           type: "text",
           color: "#5EC7AB",
+          showHide: row => !row.endOrder,
           clickFun: row => {
             openMaterialSupplementDialog(row);
           },
@@ -379,9 +389,34 @@
         {
           name: "鎵撳嵃棰嗘枡鍗�",
           type: "text",
-          color: "#409eff",
+          color: "#5EC7AB",
+          showHide: row => !row.endOrder,
           clickFun: row => {
             handlePrint(row);
+          },
+        },
+        {
+          name: "鐢熶骇杩芥函",
+          type: "text",
+          color: "#409eff",
+          clickFun: row => {
+            router.push({
+              path: "/productionManagement/productionTraceability",
+              query: {
+                npsNo: row.npsNo,
+                productName: row.productName,
+                model: row.model,
+              },
+            });
+          },
+        },
+        {
+          name: "缁撴潫璁㈠崟",
+          type: "text",
+          color: "red",
+          showHide: row => !row.endOrder,
+          clickFun: row => {
+            handleEndOrder(row);
           },
         },
       ],
@@ -627,6 +662,7 @@
           quantity: row.quantity || 0,
           orderId,
           type: "order",
+          editable: !row.endOrder,
         },
       });
     } catch (e) {
@@ -721,6 +757,26 @@
       });
   };
 
+  // 缁撴潫璁㈠崟
+  const handleEndOrder = row => {
+    ElMessageBox.confirm(`鏄惁纭缁撴潫璁㈠崟锛�${row.npsNo}锛焋, "鎻愮ず", {
+      confirmButtonText: "纭畾",
+      cancelButtonText: "鍙栨秷",
+      type: "warning",
+    })
+      .then(() => {
+        const params = {
+          id: row.id,
+          endOrder: true,
+        };
+        updateProductOrder(params).then(() => {
+          proxy.$modal.msgSuccess("缁撴潫璁㈠崟鎴愬姛");
+          getList();
+        });
+      })
+      .catch(() => {});
+  };
+
   const handleConfirmRoute = () => {};
 
   onMounted(() => {
diff --git a/src/views/productionManagement/productionTraceability/index.vue b/src/views/productionManagement/productionTraceability/index.vue
new file mode 100644
index 0000000..e2ac6df
--- /dev/null
+++ b/src/views/productionManagement/productionTraceability/index.vue
@@ -0,0 +1,831 @@
+<template>
+  <div class="app-container">
+    <el-card style="height:82vh;overflow:auto;">
+      <template #header>
+        <div class="card-header">
+          <el-form :inline="true"
+                   :model="searchForm"
+                   class="search-form">
+            <el-form-item label="鐢熶骇璁㈠崟鍙�">
+              <el-select v-model="selectedNpsNo"
+                         filterable
+                         remote
+                         reserve-keyword
+                         placeholder="璇疯緭鍏ョ敓浜ц鍗曞彿"
+                         :loading="npsNoLoading"
+                         :remote-method="handleNpsNoSearch"
+                         @change="handleSearch"
+                         style="width: 400px;">
+                <el-option v-for="option in npsNoOptions"
+                           :key="option.id"
+                           :label="option.npsNo + '-' + option.productName + '-' + option.model"
+                           :value="option.id" />
+              </el-select>
+            </el-form-item>
+            <el-form-item>
+              <el-button @click="handleBack">杩斿洖</el-button>
+            </el-form-item>
+          </el-form>
+        </div>
+      </template>
+      <!-- 鍩虹淇℃伅 -->
+      <div v-if="rowData.productionOrderDto"
+           class="detail-section">
+        <h3 class="section-title">鍩虹淇℃伅</h3>
+        <el-descriptions :column="3"
+                         border>
+          <el-descriptions-item label="鐢熶骇璁㈠崟鍙�">{{ rowData.productionOrderDto?.npsNo || '-' }}</el-descriptions-item>
+          <el-descriptions-item label="浜у搧鍚嶇О">{{ rowData.productionOrderDto?.productName || '-' }}</el-descriptions-item>
+          <el-descriptions-item label="浜у搧瑙勬牸">{{ rowData.productionOrderDto?.model || '-' }}</el-descriptions-item>
+          <el-descriptions-item label="鐗╂枡缂栫爜">{{ rowData.productionOrderDto?.materialCode || '-' }}</el-descriptions-item>
+          <el-descriptions-item label="璁″垝鏁伴噺">{{ rowData.productionOrderDto?.quantity || 0 }} <span class="unit">{{ rowData.productionOrderDto?.unit || '-' }}</span></el-descriptions-item>
+          <el-descriptions-item label="褰撳墠鐘舵��">
+            <el-tag :type="getStatusType(rowData.productionOrderDto?.status)">
+              {{ getStatusText(rowData.productionOrderDto?.status) }}
+            </el-tag>
+          </el-descriptions-item>
+          <el-descriptions-item label="瀹㈡埛鍚嶇О">{{ rowData.productionOrderDto?.customerName || '-' }}</el-descriptions-item>
+          <el-descriptions-item label="寮�濮嬫棩鏈�">{{ rowData.productionOrderDto?.startTime || '-' }}</el-descriptions-item>
+          <el-descriptions-item label="瀹屾垚杩涘害">
+            <el-progress :percentage="rowData.productionOrderDto?.completionStatus"
+                         :color="customColors(rowData.productionOrderDto?.completionStatus)"
+                         :status="rowData.productionOrderDto?.completionStatus === 100 ? 'success' : ''"
+                         style="width: 120px;" />
+          </el-descriptions-item>
+        </el-descriptions>
+      </div>
+      <el-empty v-else
+                description="璇锋悳绱㈢敓浜ц鍗曞彿" />
+      <!-- 鐢熶骇鎶ュ伐璁板綍 -->
+      <div v-if="rowData.productionRecords && rowData.productionRecords.length > 0"
+           class="progress-container">
+        <div class="progress-section">
+          <h3 class="section-title">宸ュ崟淇℃伅</h3>
+          <div class="order-item">
+            <el-table :data="rowData.productionRecords"
+                      border
+                      style="width: 100%">
+              <el-table-column prop="productNo"
+                               label="宸ュ崟缂栧彿"
+                               align="center">
+              </el-table-column>
+              <el-table-column prop="productName"
+                               label="浜у搧鍚嶇О"
+                               align="center" />
+              <el-table-column prop="model"
+                               label="瑙勬牸"
+                               align="center" />
+              <el-table-column prop="processName"
+                               label="宸ュ簭鍚嶇О"
+                               align="center" />
+              <el-table-column prop="requiredQuantity"
+                               label="闇�姹傛暟閲�"
+                               align="center" />
+              <el-table-column prop="completedQuantity"
+                               label="瀹屾垚鏁伴噺"
+                               align="center" />
+              <el-table-column label="璇︽儏"
+                               align="center"
+                               width="200">
+                <template #default="{ row }">
+                  <el-link @click="handleClickStep(row)"
+                           type="primary">鎶ュ伐璁板綍</el-link>
+                  <el-link @click="handleClickQuality(row)"
+                           style="margin-left:20px"
+                           type="primary">璐ㄦ淇℃伅</el-link>
+                </template>
+              </el-table-column>
+            </el-table>
+          </div>
+        </div>
+      </div>
+      <el-empty v-else-if="rowData.productionOrderDto"
+                description="鏆傛棤鎶ュ伐璁板綍" />
+    </el-card>
+    <!-- 鐢熶骇鎶ュ伐璇︽儏寮圭獥 -->
+    <el-dialog v-model="detailDialogVisible"
+               title="鐢熶骇鎶ュ伐璇︽儏"
+               width="1000px"
+               :close-on-click-modal="false"
+               custom-class="custom-dialog">
+      <div class="detail-container">
+        <!-- 鍩虹淇℃伅 -->
+        <div class="detail-section">
+          <h3 class="section-title">鍩虹淇℃伅</h3>
+          <el-descriptions :column="3"
+                           border>
+            <el-descriptions-item label="鐢熶骇宸ュ崟鍙�">{{ detailData.npsNo || '-' }}</el-descriptions-item>
+            <el-descriptions-item label="鐝粍">
+              <el-tag :type="detailData.schedule === '鐧界彮' ? 'primary' : 'warning'">{{ detailData.schedule || '-' }}</el-tag>
+            </el-descriptions-item>
+            <el-descriptions-item label="浜у搧缂栫爜">{{ detailData.materialCode || '-' }}</el-descriptions-item>
+            <el-descriptions-item label="浜у搧鍚嶇О">{{ detailData.productName || '-' }}</el-descriptions-item>
+            <el-descriptions-item label="瑙勬牸">{{ detailData.model || '-' }}</el-descriptions-item>
+            <el-descriptions-item label="鍚堟牸鏁伴噺"><span class="num2">{{ detailData.qualifiedQuantity || 0 }}</span> <span class="unit">{{ detailData.unit || '-' }}</span></el-descriptions-item>
+            <el-descriptions-item label="涓嶅悎鏍兼暟閲�"><span class="num3">{{ detailData.unqualifiedQuantity || 0 }}</span> <span class="unit">{{ detailData.unit || '-' }}</span></el-descriptions-item>
+            <el-descriptions-item label="鎬绘暟閲�"><span class="num1">{{ detailData.quantity || 0 }}</span> <span class="unit">{{ detailData.unit || '-' }}</span></el-descriptions-item>
+            <el-descriptions-item label="寮�濮嬫椂闂�">{{ detailData.reportingTime || '-' }}</el-descriptions-item>
+          </el-descriptions>
+        </div>
+        <div class="detail-section">
+          <h3 class="section-title">鎶ュ伐鏄庣粏</h3>
+          <el-table :data="[detailData]"
+                    border
+                    style="width: 100%">
+            <el-table-column label="鎶ュ伐鍗曞彿"
+                             prop="productNo"
+                             align="center" />
+            <el-table-column label="浜у嚭鏁伴噺"
+                             prop="qualifiedQuantity"
+                             align="center" />
+            <el-table-column label="鎶ュ簾鏁伴噺"
+                             prop="unqualifiedQuantity"
+                             align="center" />
+            <el-table-column label="鍒涘缓鏃堕棿"
+                             prop="reportingTime"
+                             align="center" />
+            <el-table-column label="鎿嶄綔"
+                             align="center"
+                             width="200">
+              <template #default="{ row }">
+                <el-button type="primary"
+                           link
+                           @click="showInput(row.id)">鏌ョ湅鎶曞叆</el-button>
+                <el-button type="primary"
+                           link
+                           @click="showParamDetail(row.productionOperationParamList)">鍙傛暟璇︽儏</el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </div>
+      </div>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="detailDialogVisible = false">鍏抽棴</el-button>
+        </div>
+      </template>
+    </el-dialog>
+    <!-- 鎶曞叆妯℃�佹 -->
+    <input-modal v-if="isShowInput"
+                 v-model:visible="isShowInput"
+                 :production-product-main-id="isShowingId" />
+    <!-- 鍙傛暟璇︽儏寮圭獥 -->
+    <el-dialog v-model="paramDetailVisible"
+               title="鍙傛暟璇︽儏"
+               width="600px">
+      <div v-if="currentParams && currentParams.length > 0"
+           class="param-detail-list">
+        <el-descriptions :column="1"
+                         border>
+          <el-descriptions-item v-for="param in currentParams"
+                                :key="param.id"
+                                :label="param.paramName">
+            {{ param.inputValue }}
+            <span v-if="param.unit && param.unit !== '/'"
+                  class="unit-text">({{ param.unit }})</span>
+          </el-descriptions-item>
+        </el-descriptions>
+      </div>
+      <el-empty v-else
+                description="鏆傛棤鍙傛暟鏁版嵁" />
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button @click="paramDetailVisible = false">鍏抽棴</el-button>
+        </span>
+      </template>
+    </el-dialog>
+    <!-- 璐ㄦ淇℃伅寮圭獥 -->
+    <el-dialog v-model="qualityDialogVisible"
+               title="璐ㄦ璇︽儏"
+               width="1000px"
+               :close-on-click-modal="false"
+               custom-class="custom-dialog">
+      <div class="detail-container">
+        <div v-for="(record, index) in qualityRecords"
+             :key="record.id"
+             class="quality-record-block">
+          <div class="detail-section">
+            <h3 class="section-title">妫�娴嬭褰� {{ index + 1 }} - {{ record.checkTime }}</h3>
+            <el-descriptions :column="3"
+                             border>
+              <el-descriptions-item label="妫�娴嬫棩鏈�">{{ record.checkTime || '-' }}</el-descriptions-item>
+              <el-descriptions-item label="鐢熶骇宸ュ崟鍙�">{{ record.workOrderNo || '-' }}</el-descriptions-item>
+              <el-descriptions-item label="宸ュ簭">{{ record.process || '-' }}</el-descriptions-item>
+              <el-descriptions-item label="妫�楠屽憳">{{ record.checkName || '-' }}</el-descriptions-item>
+              <el-descriptions-item label="浜у搧鍚嶇О">{{ record.productName || '-' }}</el-descriptions-item>
+              <el-descriptions-item label="瑙勬牸鍨嬪彿">{{ record.model || '-' }}</el-descriptions-item>
+              <el-descriptions-item label="鏁伴噺">{{ record.quantity || 0 }} {{ record.unit || '-' }}</el-descriptions-item>
+              <el-descriptions-item label="妫�娴嬪崟浣�">{{ record.checkCompany || '-' }}</el-descriptions-item>
+              <el-descriptions-item label="妫�娴嬬粨鏋�">
+                <el-tag :type="record.checkResult === '鍚堟牸' ? 'success' : 'danger'">
+                  {{ record.checkResult || '-' }}
+                </el-tag>
+              </el-descriptions-item>
+            </el-descriptions>
+            <h4 class="sub-section-title">妫�楠屾寚鏍囧垪琛�</h4>
+            <el-table :data="record.inspectItems"
+                      border
+                      style="width: 100%">
+              <el-table-column label="搴忓彿"
+                               type="index"
+                               width="60"
+                               align="center" />
+              <el-table-column label="鎸囨爣"
+                               prop="itemName"
+                               align="center" />
+              <el-table-column label="鍗曚綅"
+                               prop="unit"
+                               align="center" />
+              <el-table-column label="鏍囧噯鍊�"
+                               prop="standardValue"
+                               align="center" />
+              <el-table-column label="鍐呮帶鍊�"
+                               prop="controlValue"
+                               align="center" />
+              <el-table-column label="瀹為檯鍊�"
+                               prop="actualValue"
+                               align="center" />
+            </el-table>
+          </div>
+          <!-- <div class="detail-section">
+
+          </div> -->
+          <el-divider v-if="index < qualityRecords.length - 1" />
+        </div>
+      </div>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="qualityDialogVisible = false">鍏抽棴</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+  import { ref, reactive, onMounted } from "vue";
+  import { useRoute, useRouter } from "vue-router";
+  import { ElMessage } from "element-plus";
+  import InputModal from "@/views/productionManagement/productionReporting/Input.vue";
+
+  const route = useRoute();
+  const router = useRouter();
+
+  // 鎼滅储鐩稿叧
+  const searchForm = reactive({
+    npsNo: "",
+  });
+  const selectedNpsNo = ref(null);
+  const npsNoLoading = ref(false);
+  const npsNoOptions = ref([
+    {
+      id: 1,
+      npsNo: "PO20240301001",
+      productName: "绮惧瘑娑插帇缂�",
+      model: "HG-100/50-500",
+      materialCode: "MAT-2024-001",
+      quantity: 500,
+      unit: "浠�",
+      status: 1,
+      customerName: "閲嶅伐鏈烘鏈夐檺鍏徃",
+      startTime: "2024-03-01",
+      completionStatus: 65,
+    },
+    {
+      id: 2,
+      npsNo: "PO20240301002",
+      productName: "宸ヤ笟浼烘湇鐢垫満",
+      model: "SV-400W-3000",
+      materialCode: "MAT-2024-002",
+      quantity: 200,
+      unit: "鍙�",
+      status: 2,
+      customerName: "鑷姩鍖栬澶囩鎶�鍏徃",
+      startTime: "2024-03-02",
+      completionStatus: 100,
+    },
+    {
+      id: 3,
+      npsNo: "PO20240301003",
+      productName: "楂樺帇瀵嗗皝鍦�",
+      model: "SR-80-5",
+      materialCode: "MAT-2024-003",
+      quantity: 5000,
+      unit: "涓�",
+      status: 0,
+      customerName: "瀵嗗皝绯荤粺閰嶄欢鍘�",
+      startTime: "2024-03-05",
+      completionStatus: 0,
+    },
+  ]);
+
+  // 璇︽儏鏁版嵁
+  const rowData = reactive({
+    productionOrderDto: null,
+    productionRecords: [],
+  });
+
+  // 鎶ュ伐璇︽儏寮圭獥
+  const detailDialogVisible = ref(false);
+  const detailData = ref({});
+
+  // 鎶曞叆妯℃�佹
+  const isShowInput = ref(false);
+  const isShowingId = ref(0);
+  const showInput = id => {
+    isShowInput.value = true;
+    isShowingId.value = id;
+  };
+
+  // 鍙傛暟璇︽儏寮圭獥
+  const paramDetailVisible = ref(false);
+  const currentParams = ref([]);
+  const showParamDetail = params => {
+    currentParams.value = params || [];
+    paramDetailVisible.value = true;
+  };
+
+  // 璐ㄦ淇℃伅寮圭獥
+  const qualityDialogVisible = ref(false);
+  const qualityRecords = ref([]);
+
+  // 鐘舵�佸鐞�
+  const getStatusType = status => {
+    const typeMap = { 0: "info", 1: "primary", 2: "success" };
+    return typeMap[status] || "info";
+  };
+  const getStatusText = status => {
+    const statusMap = { 0: "鏈紑濮�", 1: "鐢熶骇涓�", 2: "宸插畬鎴�" };
+    return statusMap[status] || "鏈煡";
+  };
+  const customColors = percentage => {
+    if (percentage < 30) return "#f56c6c";
+    if (percentage < 70) return "#e6a23c";
+    return "#67c23a";
+  };
+
+  // 妯℃嫙鎼滅储鏂规硶
+  const handleNpsNoSearch = query => {
+    if (query) {
+      npsNoLoading.value = true;
+      setTimeout(() => {
+        npsNoLoading.value = false;
+      }, 300);
+    }
+  };
+
+  const handleSearch = id => {
+    const selected = npsNoOptions.value.find(item => item.id === id);
+    if (selected) {
+      rowData.productionOrderDto = selected;
+      rowData.productionRecords = [
+        {
+          id: 1001,
+          productNo: "MO-2024-001-01",
+          productName: selected.productName,
+          model: selected.model,
+          processName: "姣涘澂鍔犲伐",
+          requiredQuantity: selected.quantity,
+          completedQuantity: Math.floor(selected.quantity * 0.4),
+          qualifiedQuantity: Math.floor(selected.quantity * 0.4) - 2,
+          unqualifiedQuantity: 2,
+          reportingTime: "2024-03-01 10:00:00",
+          schedule: "鐧界彮",
+          postName: "寮犱笁",
+          unit: selected.unit,
+        },
+        {
+          id: 1002,
+          productNo: "MO-2024-001-02",
+          productName: selected.productName,
+          model: selected.model,
+          processName: "绮惧姞宸�",
+          requiredQuantity: Math.floor(selected.quantity * 0.4),
+          completedQuantity: Math.floor(selected.quantity * 0.25),
+          qualifiedQuantity: Math.floor(selected.quantity * 0.25),
+          unqualifiedQuantity: 0,
+          reportingTime: "2024-03-01 16:00:00",
+          schedule: "鐧界彮",
+          postName: "鏉庡洓",
+          unit: selected.unit,
+        },
+      ];
+    }
+  };
+
+  const handleBack = () => {
+    router.back();
+  };
+
+  const handleClickStep = row => {
+    detailData.value = {
+      id: row.id || Math.floor(Math.random() * 1000),
+      productNo: row.productNo,
+      npsNo: rowData.productionOrderDto.npsNo,
+      schedule: row.schedule,
+      postName: row.postName,
+      materialCode: rowData.productionOrderDto.materialCode,
+      productName: row.productName,
+      model: row.model,
+      qualifiedQuantity: row.qualifiedQuantity,
+      unqualifiedQuantity: row.unqualifiedQuantity || 0,
+      quantity: row.completedQuantity,
+      unit: row.unit,
+      reportingTime: row.reportingTime,
+      productionOperationParamList: [
+        { id: 1, paramName: "涓昏酱杞��", inputValue: "2400", unit: "rpm" },
+        { id: 2, paramName: "杩涚粰閫熷害", inputValue: "120", unit: "mm/min" },
+        { id: 3, paramName: "鍒囧墛娣卞害", inputValue: "0.5", unit: "mm" },
+        { id: 4, paramName: "鍐峰嵈娑插帇鍔�", inputValue: "0.6", unit: "Mpa" },
+      ],
+    };
+    detailDialogVisible.value = true;
+  };
+
+  const handleClickQuality = row => {
+    qualityRecords.value = [
+      {
+        id: 2001,
+        checkTime: "2024-03-01 11:30:00",
+        workOrderNo: row.productNo,
+        process: row.processName,
+        checkName: "璐ㄩ噺閮�-鐜嬪缓鍥�",
+        productName: row.productName,
+        model: row.model,
+        unit: row.unit,
+        quantity: row.completedQuantity,
+        checkCompany: "鍐呴儴瀹為獙瀹�",
+        checkResult: "鍚堟牸",
+        inspectItems: [
+          {
+            id: 1,
+            itemName: "澶栧緞灏哄",
+            unit: "mm",
+            standardValue: "100.00卤0.05",
+            controlValue: "100.00卤0.03",
+            actualValue: "100.01",
+            result: "鍚堟牸",
+          },
+          {
+            id: 2,
+            itemName: "鍐呭緞灏哄",
+            unit: "mm",
+            standardValue: "50.00+0.02/-0",
+            controlValue: "50.00+0.01/-0",
+            actualValue: "50.01",
+            result: "鍚堟牸",
+          },
+          {
+            id: 3,
+            itemName: "琛ㄩ潰绮楃硻搴�",
+            unit: "Ra",
+            standardValue: "鈮�1.6",
+            controlValue: "鈮�1.2",
+            actualValue: "0.8",
+            result: "鍚堟牸",
+          },
+        ],
+      },
+      {
+        id: 2001,
+        checkTime: "2024-03-01 11:30:00",
+        workOrderNo: row.productNo,
+        process: row.processName,
+        checkName: "璐ㄩ噺閮�-鐜嬪缓鍥�",
+        productName: row.productName,
+        model: row.model,
+        unit: row.unit,
+        quantity: row.completedQuantity,
+        checkCompany: "鍐呴儴瀹為獙瀹�",
+        checkResult: "鍚堟牸",
+        inspectItems: [
+          {
+            id: 1,
+            itemName: "澶栧緞灏哄",
+            unit: "mm",
+            standardValue: "100.00卤0.05",
+            controlValue: "100.00卤0.03",
+            actualValue: "100.01",
+            result: "鍚堟牸",
+          },
+          {
+            id: 2,
+            itemName: "鍐呭緞灏哄",
+            unit: "mm",
+            standardValue: "50.00+0.02/-0",
+            controlValue: "50.00+0.01/-0",
+            actualValue: "50.01",
+            result: "鍚堟牸",
+          },
+          {
+            id: 3,
+            itemName: "琛ㄩ潰绮楃硻搴�",
+            unit: "Ra",
+            standardValue: "鈮�1.6",
+            controlValue: "鈮�1.2",
+            actualValue: "0.8",
+            result: "鍚堟牸",
+          },
+        ],
+      },
+    ];
+    qualityDialogVisible.value = true;
+  };
+
+  onMounted(() => {
+    if (route.query.npsNo) {
+      const npsNo = route.query.npsNo;
+      const found = npsNoOptions.value.find(item => item.npsNo === npsNo);
+      if (found) {
+        selectedNpsNo.value = found.id;
+        handleSearch(found.id);
+      } else {
+        // 濡傛灉娌℃壘鍒帮紝鍒涘缓涓�涓复鏃剁殑
+        const mockItem = {
+          id: Date.now(),
+          npsNo: npsNo,
+          productName: route.query.productName || "绮惧瘑娑插帇缂�",
+          model: route.query.model || "HG-100/50-500",
+          materialCode: "MAT-2024-MOCK",
+          quantity: 100,
+          unit: "浠�",
+          status: 1,
+          customerName: "妯℃嫙瀹㈡埛",
+          startTime: "2024-03-01",
+          completionStatus: 50,
+        };
+        npsNoOptions.value.push(mockItem);
+        selectedNpsNo.value = mockItem.id;
+        handleSearch(mockItem.id);
+      }
+    }
+  });
+</script>
+
+<style scoped>
+  .app-container {
+    padding: 20px;
+    background-color: #f5f7fa;
+    min-height: 100vh;
+  }
+
+  .card-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    padding: 0 10px;
+  }
+
+  .search-form {
+    width: 100%;
+  }
+
+  .search-form .el-form-item {
+    margin-right: 10px;
+  }
+
+  .detail-section {
+    margin-bottom: 24px;
+    background-color: #ffffff;
+    border-radius: 10px;
+    padding: 24px;
+    box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.08);
+    transition: all 0.3s ease;
+  }
+
+  .detail-section:hover {
+    box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.12);
+  }
+
+  .section-title {
+    font-size: 16px;
+    font-weight: 600;
+    margin-bottom: 20px;
+    color: #1a1a1a;
+    border-bottom: 2px solid #409eff;
+    padding-bottom: 10px;
+    display: flex;
+    align-items: center;
+  }
+
+  .section-title::before {
+    content: "";
+    display: inline-block;
+    width: 4px;
+    height: 16px;
+    background-color: #409eff;
+    margin-right: 8px;
+    border-radius: 2px;
+  }
+
+  .sub-section-title {
+    font-size: 14px;
+    font-weight: 600;
+    margin-bottom: 16px;
+    color: #303133;
+    display: flex;
+    align-items: center;
+  }
+
+  .sub-section-title::before {
+    content: "";
+    display: inline-block;
+    width: 3px;
+    height: 12px;
+    background-color: #67c23a;
+    margin-right: 8px;
+    border-radius: 2px;
+  }
+
+  .unit {
+    font-size: 12px;
+    color: #909399;
+    margin-left: 4px;
+  }
+
+  :deep(.el-descriptions) {
+    border-radius: 8px;
+    overflow: hidden;
+    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
+  }
+
+  :deep(.el-descriptions__row:nth-child(odd)) {
+    background-color: #f9f9f9;
+  }
+
+  :deep(.el-descriptions__label) {
+    font-weight: 500;
+    color: #606266;
+    background-color: #f5f7fa;
+  }
+
+  :deep(.el-descriptions__content) {
+    color: #303133;
+    font-weight: 500;
+  }
+
+  .progress-container {
+    display: flex;
+    gap: 24px;
+  }
+
+  .progress-section {
+    margin-bottom: 24px;
+    background-color: #ffffff;
+    border-radius: 10px;
+    padding: 24px;
+    box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.08);
+    flex: 1;
+    transition: all 0.3s ease;
+    width: 100%;
+  }
+
+  .progress-section:hover {
+    box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.12);
+  }
+
+  .order-item {
+    margin-bottom: 20px;
+    border-radius: 8px;
+    overflow: hidden;
+    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
+  }
+
+  :deep(.el-table) {
+    border-radius: 8px;
+    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
+  }
+
+  :deep(.el-table th) {
+    background-color: #f5f7fa !important;
+    font-weight: 600;
+    color: #606266;
+  }
+
+  :deep(.el-progress-bar__inner) {
+    border-radius: 10px;
+  }
+
+  :deep(.el-tag) {
+    border-radius: 12px;
+    padding: 2px 10px;
+  }
+
+  /* 寮圭獥鏍峰紡 */
+  .detail-container {
+    max-height: 600px;
+    overflow-y: auto;
+    padding: 0 16px;
+  }
+
+  .process-item {
+    margin-bottom: 24px;
+    padding: 20px;
+    background-color: #ffffff;
+    border-radius: 8px;
+    border: 1px solid #ebeef5;
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
+  }
+
+  .process-header {
+    margin-bottom: 20px;
+    padding-bottom: 12px;
+    border-bottom: 1px solid #f0f2f5;
+  }
+
+  .process-title {
+    font-size: 15px;
+    font-weight: 600;
+    margin-bottom: 12px;
+    color: #1a1a1a;
+    display: flex;
+    align-items: center;
+  }
+
+  .process-title::before {
+    content: "";
+    display: inline-block;
+    width: 4px;
+    height: 16px;
+    background-color: #409eff;
+    margin-right: 8px;
+    border-radius: 2px;
+  }
+
+  .process-info {
+    display: flex;
+    gap: 20px;
+    font-size: 13px;
+    color: #606266;
+  }
+
+  .process-label {
+    padding: 4px 12px;
+    background-color: #ecf5ff;
+    border-radius: 4px;
+    color: #409eff;
+    font-weight: 500;
+  }
+
+  .process-details {
+    margin-bottom: 20px;
+  }
+
+  .num1 {
+    color: #1107cc;
+    font-weight: 600;
+  }
+
+  .num2 {
+    color: #0fcf25;
+    font-weight: 600;
+  }
+
+  .num3 {
+    color: #d31818;
+    font-weight: 600;
+  }
+
+  .dialog-footer {
+    text-align: center;
+    padding: 20px;
+    border-top: 1px solid #ebeef5;
+  }
+
+  .dialog-footer .el-button {
+    min-width: 100px;
+    padding: 8px 20px;
+  }
+
+  /* 鑷畾涔夊璇濇鏍峰紡 */
+  :deep(.custom-dialog) {
+    border-radius: 12px;
+    overflow: hidden;
+  }
+
+  :deep(.custom-dialog .el-dialog__header) {
+    background-color: #f5f7fa;
+    padding: 20px;
+    border-bottom: 1px solid #ebeef5;
+  }
+
+  :deep(.custom-dialog .el-dialog__title) {
+    font-size: 18px;
+    font-weight: 600;
+    color: #1a1a1a;
+  }
+
+  :deep(.custom-dialog .el-dialog__body) {
+    padding: 20px;
+  }
+
+  .unit-text {
+    margin-left: 5px;
+    color: #909399;
+    font-size: 12px;
+  }
+
+  .param-detail-list {
+    padding: 10px;
+  }
+</style>
diff --git a/src/views/productionManagement/workOrderEdit/index.vue b/src/views/productionManagement/workOrderEdit/index.vue
index fe75df3..693fea0 100644
--- a/src/views/productionManagement/workOrderEdit/index.vue
+++ b/src/views/productionManagement/workOrderEdit/index.vue
@@ -204,6 +204,11 @@
       width: "140",
     },
     {
+      label: "鎸囧畾鎶ュ伐浜�",
+      prop: "userNames",
+      width: "180",
+    },
+    {
       label: "鎿嶄綔",
       width: "200",
       align: "center",
diff --git a/src/views/productionManagement/workOrderManagement/index.vue b/src/views/productionManagement/workOrderManagement/index.vue
index c1b0474..dda27fc 100644
--- a/src/views/productionManagement/workOrderManagement/index.vue
+++ b/src/views/productionManagement/workOrderManagement/index.vue
@@ -244,6 +244,7 @@
                     @refresh="getList" />
     <FileList v-if="fileDialogVisible"
               v-model:visible="fileDialogVisible"
+              :editable="!currentWorkOrderRow?.endOrder"
               :record-type="'production_operation_task'"
               :record-id="currentWorkOrderId" />
   </div>
@@ -264,8 +265,11 @@
   import QRCode from "qrcode";
   import { getCurrentInstance, reactive, toRefs } from "vue";
   import MaterialDialog from "./components/MaterialDialog.vue";
-  import FileList from "@/components/Dialog/FileList.vue";
+  const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue"));
+
+  import useUserStore from "@/store/modules/user";
   const { proxy } = getCurrentInstance();
+  const userStore = useUserStore();
 
   const tableColumn = ref([
     {
@@ -368,7 +372,23 @@
           clickFun: row => {
             showReportDialog(row);
           },
-          disabled: row => row.planQuantity <= 0,
+          showHide: row => !row.endOrder,
+          disabled: row => {
+            if (row.planQuantity <= 0) return true;
+            if (!row.userIds) return false;
+            try {
+              const userIds =
+                typeof row.userIds === "string"
+                  ? JSON.parse(row.userIds)
+                  : row.userIds;
+              if (Array.isArray(userIds)) {
+                return !userIds.some(id => String(id) === String(userStore.id));
+              }
+              return true;
+            } catch (e) {
+              return true;
+            }
+          },
         },
       ],
     },
@@ -614,9 +634,11 @@
   const printTransferCard = () => {
     window.print();
   };
+  const currentWorkOrderRow = ref(null);
 
   const openWorkOrderFiles = row => {
     currentWorkOrderId.value = row.id;
+    currentWorkOrderRow.value = row;
     fileDialogVisible.value = true;
   };
 
@@ -801,6 +823,7 @@
   };
 
   onMounted(() => {
+    userStore.getInfo();
     getList();
     // 鑾峰彇鐢ㄦ埛鍒楄〃
     userListNoPageByTenantId().then(res => {
diff --git a/src/views/safeProduction/dangerInvestigation/index.vue b/src/views/safeProduction/dangerInvestigation/index.vue
index 12da6da..cb09e52 100644
--- a/src/views/safeProduction/dangerInvestigation/index.vue
+++ b/src/views/safeProduction/dangerInvestigation/index.vue
@@ -415,17 +415,12 @@
         </el-row>
       </el-form>
     </FormDialog>
-  <!--  todo 闄勪欢棰勮鐩稿叧 -->
-    <FileListDialog ref="fileListRef"
-                    v-model="fileListDialogVisible"
-                    :show-upload-button="true"
-                    :show-delete-button="true"
-                    :is-show-pagination="true"
-                    :page="filePagination"
-                    :upload-method="handleUpload"
-                    :delete-method="handleFileDelete"
-                    @pagination="paginationSearch"
-                    title="闄勪欢鍒楄〃" />
+    <FileListDialog
+        v-if="fileListDialogVisible"
+        :record-id="currentRecordId"
+        record-type="safe_hidden"
+        v-model:visible="fileListDialogVisible"/>
+
   </div>
 </template>
 
@@ -436,7 +431,6 @@
   import { ElMessageBox, ElMessage } from "element-plus";
   import useUserStore from "@/store/modules/user";
   import { userListNoPage } from "@/api/system/user.js";
-  import FileListDialog from "@/components/Dialog/FileListDialog.vue";
   import FormDialog from "@/components/Dialog/FormDialog.vue";
   import { getQuotationList } from "@/api/salesManagement/salesQuotation.js";
   import {
@@ -445,13 +439,9 @@
     safeHiddenUpdate,
     safeHiddenDel,
     fileListPage,
-    safeHiddenFileAdd,
-    safeHiddenFileDel,
   } from "@/api/safeProduction/dangerInvestigation.js";
   import useFormData from "@/hooks/useFormData.js";
-  import request from "@/utils/request";
   import dayjs from "dayjs";
-  import { get } from "@vueuse/core";
 
   const userStore = useUserStore();
   const { proxy } = getCurrentInstance();
@@ -459,6 +449,7 @@
   const selectedRows = ref([]);
   const userList = ref([]);
   const tableLoading = ref(false);
+  const currentRecordId = ref(0);
   const page = reactive({
     current: 1,
     size: 100,
@@ -943,18 +934,8 @@
   const fileListDialogVisible = ref(false);
   const currentFileRow = ref(null);
   const downLoadFile = row => {
-    currentFileRow.value = row;
-    fileListPage({
-      safeHiddenId: row.id,
-      current: filePagination.value.current,
-      size: filePagination.value.size,
-    }).then(res => {
-      if (fileListRef.value) {
-        fileListRef.value.open(res.data.records || []);
-        console.log("res.data", res.data);
-        filePagination.value.total = res.data.total || 0;
-      }
-    });
+    currentRecordId.value = row.id;
+    fileListDialogVisible.value = true;
   };
   const currentUserId = ref("");
   const currentUserName = ref("");
@@ -990,147 +971,6 @@
       userList.value = res.data;
     });
   });
-  // 涓婁紶闄勪欢
-  const handleUpload = async () => {
-    if (!currentFileRow.value) {
-      proxy.$modal.msgWarning("璇峰厛閫夋嫨鏁版嵁");
-      return null;
-    }
-
-    return new Promise(resolve => {
-      // 鍒涘缓涓�涓殣钘忕殑鏂囦欢杈撳叆鍏冪礌
-      const input = document.createElement("input");
-      input.type = "file";
-      input.style.display = "none";
-      input.onchange = async e => {
-        const file = e.target.files[0];
-        if (!file) {
-          resolve(null);
-          return;
-        }
-
-        try {
-          // 浣跨敤 FormData 涓婁紶鏂囦欢
-          const formData = new FormData();
-          formData.append("file", file);
-
-          const uploadRes = await request({
-            url: "/file/upload",
-            method: "post",
-            data: formData,
-            headers: {
-              "Content-Type": "multipart/form-data",
-              Authorization: `Bearer ${getToken()}`,
-            },
-          });
-
-          if (uploadRes.code === 200) {
-            // 淇濆瓨闄勪欢淇℃伅
-            const fileData = {
-              safeHiddenId: currentFileRow.value.id,
-              name: uploadRes.data.originalName || file.name,
-              url: uploadRes.data.tempPath || uploadRes.data.url,
-            };
-
-            const saveRes = await safeHiddenFileAdd(fileData);
-            if (saveRes.code === 200) {
-              proxy.$modal.msgSuccess("鏂囦欢涓婁紶鎴愬姛");
-              // 閲嶆柊鍔犺浇鏂囦欢鍒楄〃
-              const listRes = await fileListPage({
-                safeHiddenId: currentFileRow.value.id,
-                current: filePagination.value.current,
-                size: filePagination.value.size,
-              });
-              if (listRes.code === 200 && fileListRef.value) {
-                const fileList = (listRes.data?.records || []).map(item => ({
-                  name: item.name,
-                  url: item.url,
-                  id: item.id,
-                  ...item,
-                }));
-                fileListRef.value.setList(fileList);
-                filePagination.value.total = listRes.data?.total || 0;
-              }
-              // 杩斿洖鏂版枃浠朵俊鎭�
-              resolve({
-                name: fileData.name,
-                url: fileData.url,
-                id: saveRes.data?.id,
-              });
-            } else {
-              proxy.$modal.msgError(saveRes.msg || "鏂囦欢淇濆瓨澶辫触");
-              resolve(null);
-            }
-          } else {
-            proxy.$modal.msgError(uploadRes.msg || "鏂囦欢涓婁紶澶辫触");
-            resolve(null);
-          }
-        } catch (error) {
-          proxy.$modal.msgError("鏂囦欢涓婁紶澶辫触");
-          resolve(null);
-        } finally {
-          document.body.removeChild(input);
-        }
-      };
-
-      document.body.appendChild(input);
-      input.click();
-    });
-  };
-  // 鍒嗛〉鏌ヨ鏂囦欢鍒楄〃
-  const paginationSearch = async (page, size) => {
-    filePagination.value.current = page;
-    filePagination.value.size = size;
-    const listRes = await fileListPage({
-      safeHiddenId: currentFileRow.value.id,
-      current: filePagination.value.current,
-      size: filePagination.value.size,
-    });
-    if (listRes.code === 200) {
-      const fileList = (listRes.data?.records || []).map(item => ({
-        name: item.name,
-        url: item.url,
-        id: item.id,
-        ...item,
-      }));
-      fileListRef.value.setList(fileList);
-      filePagination.value.total = listRes.data?.total || 0;
-    }
-  };
-  // 鍒犻櫎闄勪欢
-  const handleFileDelete = async row => {
-    try {
-      const res = await safeHiddenFileDel([row.id]);
-      if (res.code === 200) {
-        proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
-        // 閲嶆柊鍔犺浇鏂囦欢鍒楄〃
-        if (currentFileRow.value && fileListRef.value) {
-          const listRes = await fileListPage({
-            safeHiddenId: currentFileRow.value.id,
-            current: filePagination.value.current,
-            size: filePagination.value.size,
-          });
-          if (listRes.code === 200) {
-            const fileList = (listRes.data?.records || []).map(item => ({
-              name: item.name,
-              url: item.url,
-              id: item.id,
-              ...item,
-            }));
-            fileListRef.value.setList(fileList);
-            filePagination.value.total = listRes.data?.total || 0;
-          }
-        }
-        return true; // 杩斿洖 true 琛ㄧず鍒犻櫎鎴愬姛锛岀粍浠朵細鏇存柊鍒楄〃
-      } else {
-        proxy.$modal.msgError(res.msg || "鍒犻櫎澶辫触");
-        return false;
-      }
-    } catch (error) {
-      proxy.$modal.msgError("鍒犻櫎澶辫触");
-      return false;
-    }
-  };
 </script>
 
 <style scoped lang="scss">
diff --git a/src/views/safeProduction/safeQualifications/index.vue b/src/views/safeProduction/safeQualifications/index.vue
index 819c6da..39111be 100644
--- a/src/views/safeProduction/safeQualifications/index.vue
+++ b/src/views/safeProduction/safeQualifications/index.vue
@@ -110,7 +110,7 @@
             <el-button link
                        type="primary"
                        size="small"
-                       @click="downLoadFile(scope.row)">闄勪欢</el-button>
+                       @click="openFileDialog(scope.row)">闄勪欢</el-button>
           </template>
         </el-table-column>
       </el-table>
@@ -203,16 +203,7 @@
       </el-form>
     </FormDialog>
 <!-- todo 闄勪欢棰勮鐩稿叧 -->
-    <FileListDialog ref="fileListRef"
-                    v-model="fileListDialogVisible"
-                    :show-upload-button="true"
-                    :show-delete-button="true"
-                    :is-show-pagination="true"
-                    :page="filePagination"
-                    :upload-method="handleUpload"
-                    :delete-method="handleFileDelete"
-                    @pagination="paginationSearch"
-                    title="闄勪欢鍒楄〃" />
+    <FileList v-if="fileDialogVisible"  v-model:visible="fileDialogVisible" record-type="safe_certification" :record-id="recordId"  />
   </div>
 </template>
 
@@ -223,7 +214,6 @@
   import { ElMessageBox, ElMessage } from "element-plus";
   import useUserStore from "@/store/modules/user";
   import { userListNoPage } from "@/api/system/user.js";
-  import FileListDialog from "@/components/Dialog/FileListDialog.vue";
   import FormDialog from "@/components/Dialog/FormDialog.vue";
   import { getQuotationList } from "@/api/salesManagement/salesQuotation.js";
   import {
@@ -238,7 +228,7 @@
   import useFormData from "@/hooks/useFormData.js";
   import request from "@/utils/request";
   import dayjs from "dayjs";
-
+  const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue"));
   const userStore = useUserStore();
   const { proxy } = getCurrentInstance();
   const tableData = ref([]);
@@ -524,19 +514,17 @@
     size: 10,
     total: 0,
   });
-  const downLoadFile = row => {
-    currentFileRow.value = row;
-    fileListPage({
-      safeCertificationId: row.id,
-      current: filePagination.value.current,
-      size: filePagination.value.size,
-    }).then(res => {
-      if (fileListRef.value) {
-        fileListRef.value.open(res.data.records);
-      }
-      filePagination.value.total = res.data.total || 0;
-    });
-  };
+
+  // 鎵撳紑闄勪欢寮圭獥
+  const recordId =ref(0)
+  const fileDialogVisible = ref(false)
+
+  // 鎵撳紑闄勪欢寮规
+  const openFileDialog = async (row) => {
+    recordId.value = row.id
+    fileDialogVisible.value = true
+  }
+  
   const currentFactoryName = ref("");
   const getCurrentFactoryName = async () => {
     let res = await userStore.getInfo();
diff --git a/src/views/safeProduction/safetyTrainingAssessment/index.vue b/src/views/safeProduction/safetyTrainingAssessment/index.vue
index b595bf6..2c98308 100644
--- a/src/views/safeProduction/safetyTrainingAssessment/index.vue
+++ b/src/views/safeProduction/safetyTrainingAssessment/index.vue
@@ -239,7 +239,7 @@
           <el-descriptions-item label="闄勪欢鍒楄〃:">
             <el-button type="primary"
                        size="small"
-                       @click="downLoadFile(endform)">闄勪欢鍒楄〃</el-button>
+                       @click="openFileDialog(endform)">闄勪欢鍒楄〃</el-button>
           </el-descriptions-item>
         </el-descriptions>
         <!-- <el-divider style="margin: 20px 0;" /> -->
@@ -359,22 +359,12 @@
       </template>
     </el-dialog>
     <!--  todo 闄勪欢棰勮鐩稿叧 -->
-    <FileListDialog ref="fileListRef"
-                    v-model="fileListDialogVisible"
-                    :show-upload-button="true"
-                    :show-delete-button="true"
-                    :is-show-pagination="true"
-                    :page="filePagination"
-                    :upload-method="handleUpload"
-                    :delete-method="handleFileDelete"
-                    @pagination="paginationSearch"
-                    title="闄勪欢鍒楄〃" />
+    <FileList v-if="fileDialogVisible"  v-model:visible="fileDialogVisible" record-type="safe_training" :record-id="recordId"  />
   </div>
 </template>
 
 <script setup>
   import { Search } from "@element-plus/icons-vue";
-  import FileListDialog from "@/components/Dialog/FileListDialog.vue";
   import {
     onMounted,
     ref,
@@ -403,6 +393,7 @@
   import useUserStore from "@/store/modules/user";
   import dayjs from "dayjs";
   const userStore = useUserStore();
+  const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue"));
 
   // 琛ㄥ崟楠岃瘉瑙勫垯
   const rules = {
@@ -621,7 +612,7 @@
           name: "闄勪欢",
           type: "text",
           clickFun: row => {
-            downLoadFile(row);
+            openFileDialog(row);
           },
           color: "#007AFF",
         },
@@ -783,27 +774,17 @@
       form.value.principalMobile = selectedUser.phonenumber;
     }
   };
-  /**
-   * 涓嬭浇鏂囦欢
-   *
-   * @param row 涓嬭浇鏂囦欢鐨勭浉鍏充俊鎭璞�
-   */
-  const fileListRef = ref(null);
-  const fileListDialogVisible = ref(false);
-  const currentFileRow = ref(null);
-  const downLoadFile = row => {
-    currentFileRow.value = row;
-    safeTrainingFileListPage({
-      safeTrainingId: row.id,
-      current: filePagination.value.current,
-      size: filePagination.value.size,
-    }).then(res => {
-      if (fileListRef.value) {
-        fileListRef.value.open(res.data.records);
-        filePagination.value.total = res.data?.total || 0;
-      }
-    });
-  };
+
+  // 鎵撳紑闄勪欢寮圭獥
+  const recordId =ref(0)
+  const fileDialogVisible = ref(false)
+
+  // 鎵撳紑闄勪欢寮规
+  const openFileDialog = async (row) => {
+    recordId.value = row.id
+    fileDialogVisible.value = true
+  }
+  
   // 涓婁紶闄勪欢
   const handleUpload = async () => {
     if (!currentFileRow.value) {
diff --git a/src/views/salesManagement/invoiceLedger/index.vue b/src/views/salesManagement/invoiceLedger/index.vue
index 3827854..444560d 100644
--- a/src/views/salesManagement/invoiceLedger/index.vue
+++ b/src/views/salesManagement/invoiceLedger/index.vue
@@ -44,7 +44,7 @@
         <el-table-column fixed="right" label="鎿嶄綔" width="150" align="center">
           <template #default="scope">
             <el-button link type="primary" @click="openForm(scope.row)">缂栬緫</el-button>
-            <el-button link type="primary" @click="downLoadFile(scope.row)">闄勪欢</el-button>
+            <el-button link type="primary" @click="openFileDialog(scope.row)">闄勪欢</el-button>
             <el-button link type="primary" @click="delInvoiceLedger(scope.row)">鍒犻櫎</el-button>
           </template>
         </el-table-column>
@@ -134,7 +134,7 @@
         </div>
       </template>
     </el-dialog>
-    <FileListDialog ref="fileListRef" v-model="fileListDialogVisible" />
+    <FileList v-if="fileDialogVisible"  v-model:visible="fileDialogVisible" record-type="invoice_registration_product" :record-id="recordId"  />
   </div>
 </template>
 
@@ -155,8 +155,8 @@
 import useUserStore from "@/store/modules/user.js";
 import useFormData from "@/hooks/useFormData";
 import dayjs from "dayjs";
-import FileListDialog from '@/components/Dialog/FileListDialog.vue';
 import { getCurrentDate } from "@/utils/index.js";
+const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue"));
 
 const { proxy } = getCurrentInstance();
 const tableData = ref([]);
@@ -422,17 +422,14 @@
   getList();
 };
 
-//闄勪欢鐩稿叧
-const fileListRef = ref(null)
-const fileListDialogVisible = ref(false)
-//鏌ョ湅闄勪欢
-const downLoadFile = (row) => {
-	invoiceLedgerProductInfo({ id: row.id }).then((res) => {
-		if (fileListRef.value) {
-			fileListRef.value.open(res.data.fileList)
-			fileListDialogVisible.value = true
-		}
-	});
+// 鎵撳紑闄勪欢寮圭獥
+const recordId =ref(0)
+const fileDialogVisible = ref(false)
+
+// 鎵撳紑闄勪欢寮规
+const openFileDialog = async (row) => {
+  recordId.value = row.id
+  fileDialogVisible.value = true
 }
 
 onMounted(() => {
diff --git a/src/views/salesManagement/salesLedger/index.vue b/src/views/salesManagement/salesLedger/index.vue
index dc648be..1235f94 100644
--- a/src/views/salesManagement/salesLedger/index.vue
+++ b/src/views/salesManagement/salesLedger/index.vue
@@ -231,7 +231,7 @@
                        :disabled="!scope.row.isEdit || scope.row.hasProductionRecord || !canEditLedger(scope.row)">缂栬緫</el-button>
             <el-button link
                        type="primary"
-                       @click="downLoadFile(scope.row)">闄勪欢</el-button>
+                       @click="openFileDialog(scope.row)">闄勪欢</el-button>
           </template>
         </el-table-column>
       </el-table>
@@ -740,9 +740,7 @@
     </FormDialog>
 <!-- // todo 闄勪欢棰勮鐩稿叧 -->
     <!-- 闄勪欢鍒楄〃寮圭獥 -->
-    <FileListDialog ref="fileListRef"
-                    v-model="fileListDialogVisible"
-                    title="闄勪欢鍒楄〃" />
+    <FileList v-if="fileDialogVisible"  v-model:visible="fileDialogVisible" record-type="sales_ledger" :record-id="recordId"  />
     <!-- 鎵撳嵃棰勮寮圭獥 -->
     <el-dialog v-model="printPreviewVisible"
                title="鎵撳嵃棰勮"
@@ -904,10 +902,8 @@
   import { onMounted, ref, getCurrentInstance } from "vue";
   import { addShippingInfo } from "@/api/salesManagement/deliveryLedger.js";
   import { ElMessageBox, ElMessage } from "element-plus";
-  import { UploadFilled, Download } from "@element-plus/icons-vue";
   import useUserStore from "@/store/modules/user";
   import { userListNoPage } from "@/api/system/user.js";
-  import FileListDialog from "@/components/Dialog/FileListDialog.vue";
   import FormDialog from "@/components/Dialog/FormDialog.vue";
   import { getQuotationList } from "@/api/salesManagement/salesQuotation.js";
   import {
@@ -929,6 +925,9 @@
   import { useRouter, useRoute } from "vue-router";
   import { listCustomerPrivatePool } from "@/api/basicData/customerFile.js";
   import FileUpload from "@/components/AttachmentUpload/file/index.vue";
+
+  const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue"));
+
   const router = useRouter();
   const route = useRoute();
   const userStore = useUserStore();
@@ -2440,20 +2439,15 @@
     return statusStr === "寰呭彂璐�" || statusStr === "瀹℃牳鎷掔粷";
   };
 
-  /**
-   * 涓嬭浇鏂囦欢
-   *
-   * @param row 涓嬭浇鏂囦欢鐨勭浉鍏充俊鎭璞�
-   */
-  const fileListRef = ref(null);
-  const fileListDialogVisible = ref(false);
-  const downLoadFile = row => {
-    getSalesLedgerWithProducts({ id: row.id, type: 1 }).then(res => {
-      if (fileListRef.value) {
-        fileListRef.value.open(res.salesLedgerFiles);
-      }
-    });
-  };
+  // 鎵撳紑闄勪欢寮圭獥
+  const recordId =ref(0)
+  const fileDialogVisible = ref(false)
+
+  // 鎵撳紑闄勪欢寮规
+  const openFileDialog = async (row) => {
+    recordId.value = row.id
+    fileDialogVisible.value = true
+  }
 
   // 鎵撳紑鍙戣揣寮规
   const openDeliveryForm = row => {

--
Gitblit v1.9.3