From cdf8190c92a536dabdbd3dfd6758cf67320ff6df Mon Sep 17 00:00:00 2001
From: huminmin <mac@MacBook-Pro.local>
Date: 星期五, 16 一月 2026 17:47:21 +0800
Subject: [PATCH] Merge branch 'dev_New' of http://114.132.189.42:9002/r/product-inventory-management into dev_New

---
 src/views/procurementManagement/paymentHistory/index.vue                   |   87 
 src/views/productionManagement/productionProcess/index.vue                 |   96 
 src/views/productionManagement/processRoute/index.vue                      |   12 
 src/views/productionManagement/workOrder/index.vue                         |  108 
 src/views/productionManagement/processRoute/processRouteItem/index.vue     | 1133 +++++++----
 src/api/productionManagement/productionOrder.js                            |   28 
 src/api/inventoryManagement/stockIn.js                                     |   87 
 src/views/procurementManagement/paymentEntry/index.vue                     |    2 
 src/components/PageHeader/index.vue                                        |   53 
 src/views/financialManagement/revenueManagement/Modal.vue                  |  192 +
 src/views/productionManagement/productionProcess/Edit.vue                  |   32 
 src/views/productionManagement/productStructure/index.vue                  |  301 ++
 src/api/inventoryManagement/stockManage.js                                 |   27 
 src/api/productionManagement/processRouteItem.js                           |   41 
 src/views/productionManagement/processRoute/New.vue                        |  171 
 src/api/productionManagement/processRoute.js                               |    8 
 src/api/productionManagement/productStructure.js                           |    4 
 src/api/productionManagement/productBom.js                                 |   47 
 src/components/Dialog/FileListDialog.vue                                   |    7 
 src/views/financialManagement/financialStatements/index.vue                |  194 +
 src/views/financialManagement/expenseManagement/Modal.vue                  |  192 +
 src/views/salesManagement/receiptPayment/index.vue                         |    2 
 src/api/productionManagement/productionProcess.js                          |   18 
 src/components/PIMTable/PIMTable.vue                                       |    2 
 src/views/financialManagement/loanManagement/index.vue                     |    9 
 src/views/financialManagement/revenueManagement/index.vue                  |  249 ++
 src/views/collaborativeApproval/approvalProcess/components/infoFormDia.vue |   25 
 src/components/QRCodeGenerator/index.vue                                   |  859 ++++----
 src/views/productionManagement/productionReporting/Input.vue               |   10 
 src/api/productionManagement/productProcessRoute.js                        |   62 
 src/views/financialManagement/expenseManagement/index.vue                  |  245 ++
 src/views/productionManagement/productStructure/Detail/index.vue           |  109 
 /dev/null                                                                  |  555 -----
 src/layout/components/NotificationCenter/index.vue                         |    4 
 src/views/productionManagement/productionReporting/index.vue               |  109 
 src/api/inventoryManagement/stockOut.js                                    |   21 
 src/main.js                                                                |    3 
 src/views/productionManagement/productionOrder/index.vue                   |  234 ++
 src/views/productionManagement/processRoute/Edit.vue                       |  232 +
 src/views/salesManagement/receiptPaymentHistory/index.vue                  |   91 
 src/views/collaborativeApproval/noticeManagement/index.vue                 |    3 
 src/views/productionManagement/productionProcess/New.vue                   |    3 
 42 files changed, 3,674 insertions(+), 1,993 deletions(-)

diff --git a/src/api/inventoryManagement/stockIn.js b/src/api/inventoryManagement/stockIn.js
index 55cef01..3481415 100644
--- a/src/api/inventoryManagement/stockIn.js
+++ b/src/api/inventoryManagement/stockIn.js
@@ -9,6 +9,50 @@
     });
 };
 
+// 鏌ヨ鐢熶骇鍏ュ簱淇℃伅鍒楄〃
+export const getStockInPageByProduction = (params) => {
+    return request({
+        url: "/stockin/listPageByProduction",
+        method: "get",
+        params,
+    });
+};
+
+// 鏌ヨ鐢熶骇鍏ュ簱淇℃伅鍒楄〃
+export const getStockInPageByProductProduction = (params) => {
+    return request({
+        url: "/stockin/listPageByProductProduction",
+        method: "get",
+        params,
+    });
+};
+
+// 鍑哄簱鍙拌处-鏌ヨ鑷畾涔夊叆搴撲俊鎭垪琛�
+export const getStockInPageByCustom = (params) => {
+    return request({
+        url: "/stockmanagement/listPageByCustom",
+        method: "get",
+        params,
+    });
+};
+// 鍏ュ簱绠$悊-鏌ヨ鑷畾涔夊叆搴撲俊鎭垪琛�
+export const getInPageByCustom = (params) => {
+    return request({
+        url: "/stockin/listPageByCustom",
+        method: "get",
+        params,
+    });
+};
+
+// 鍑哄簱鍙拌处-鏌ヨ鐢熶骇鍑哄簱淇℃伅鍒楄〃
+export const getStockInPageByProduct = (params) => {
+    return request({
+        url: "/stockmanagement/listPageByProduct",
+        method: "get",
+        params,
+    });
+};
+
 // 淇敼鍏ュ簱瀛樹俊鎭�
 export const updateStockIn = (data) => {
     return request({
@@ -26,6 +70,14 @@
         data,
     });
 };
+// 淇敼鏉愭枡搴撳瓨淇℃伅
+export const updateManagementByCustom = (data) => {
+    return request({
+        url: "/stockin/updateManagementByCustom ",
+        method: "post",
+        data,
+    });
+};
 
 // 鏂板鍟嗗搧鍏ュ簱淇℃伅
 export function addSutockIn(data) {
@@ -36,6 +88,32 @@
     })
 }
 
+// 鏂板鑷畾涔夊叆搴撲俊鎭�
+export function addStockInCustom(data) {
+    return request({
+        url: '/stockin/addCustom',
+        method: 'post',
+        data: data
+    })
+}
+
+// 缂栬緫鑷畾涔夊叆搴撲俊鎭�
+export function updateStockInCustom(data) {
+    return request({
+        url: '/stockin/updateCustom',
+        method: 'post',
+        data: data
+    })
+}
+// 缂栬緫鎴愬搧鍏ュ簱淇℃伅
+export function updateProduct(data) {
+    return request({
+        url: '/stockin/update',
+        method: 'post',
+        data: data
+    })
+}
+
 // 鍒犻櫎鍏ュ簱淇℃伅
 export function delStockIn(ids) {
     return request({
@@ -45,6 +123,15 @@
     })
 }
 
+// 鍒犻櫎鑷畾涔夊叆搴撲俊鎭�
+export function delStockInCustom(ids) {
+    return request({
+        url: '/stockin/delteCustom',
+        method: 'post',
+        data: ids
+    })
+}
+
 // 瀵煎嚭鍏ュ簱淇℃伅
 export function exportStockIn(query) {
     return request({
diff --git a/src/api/inventoryManagement/stockManage.js b/src/api/inventoryManagement/stockManage.js
index bb2081b..e2a4ebf 100644
--- a/src/api/inventoryManagement/stockManage.js
+++ b/src/api/inventoryManagement/stockManage.js
@@ -9,6 +9,31 @@
     });
 };
 
+// 鏌ヨ鐢熶骇鍏ュ簱搴撳瓨淇℃伅鍒楄〃
+export const getStockManagePageByProduction = (params) => {
+    return request({
+        url: "/stockin/listPageCopyByProduction",
+        method: "get",
+        params,
+    });
+};
+// 鏌ヨ鎴愬搧搴撳瓨淇℃伅鍒楄〃
+export const getStockManageProduction = (params) => {
+    return request({
+        url: "/stockin/listPageProductionStock",
+        method: "get",
+        params,
+    });
+};
+// 鏌ヨ鑷畾涔夊叆搴撳簱瀛樹俊鎭垪琛�
+export const getStockManagePageByCustom = (params) => {
+    return request({
+        url: "/stockin/listPageCopyByCustom",
+        method: "get",
+        params,
+    });
+};
+
 
 // 淇敼搴撳瓨淇℃伅
 export const updateStockManage = (data) => {
@@ -38,7 +63,7 @@
     })
 }
 
-//鍑哄簱鎺ュ彛
+// 鍑哄簱绠$悊-棰嗙敤鎺ュ彛
 export const stockOut = (data) => {
     return request({
         url: '/stockmanagement/stockout',
diff --git a/src/api/inventoryManagement/stockOut.js b/src/api/inventoryManagement/stockOut.js
index 5d410d9..f1b36d9 100644
--- a/src/api/inventoryManagement/stockOut.js
+++ b/src/api/inventoryManagement/stockOut.js
@@ -1,9 +1,18 @@
 import request from "@/utils/request";
 
-//鏌ヨ鍑哄簱鍒楄〃
+// 鍑哄簱鍙拌处-閲囪喘鍑哄簱鏌ヨ鍑哄簱鍒楄〃
 export const getStockOutPage = (params) => {
     return request({
         url: "/stockmanagement/listPage",
+        method: "get",
+        params,
+    });
+};
+
+// 鍑哄簱鍙拌处-鐢熶骇鍑哄簱鏌ヨ鍑哄簱鍒楄〃
+export const getStockOutSemiProductPage = (params) => {
+    return request({
+        url: "/stockmanagement/listPageBySemiProduct",
         method: "get",
         params,
     });
@@ -35,13 +44,3 @@
         data: ids
     })
 }
-
-//瀵煎嚭鍑哄簱淇℃伅
-export const exportStockOut = (query) => {
-    return request({
-        url: '/stockmanagement/export',
-        method: 'get',
-        params: query,
-        responseType: 'blob'
-    })
-}
\ No newline at end of file
diff --git a/src/api/productionManagement/processRoute.js b/src/api/productionManagement/processRoute.js
index 4d16775..c13b2fc 100644
--- a/src/api/productionManagement/processRoute.js
+++ b/src/api/productionManagement/processRoute.js
@@ -31,4 +31,12 @@
     method: 'put',
     data: data,
   })
+}
+
+// 鑾峰彇璇︽儏
+export function getById(id) {
+  return request({
+    url: `/processRoute/${id}`,
+    method: 'get',
+  })
 }
\ No newline at end of file
diff --git a/src/api/productionManagement/processRouteItem.js b/src/api/productionManagement/processRouteItem.js
index ad4861c..9e81406 100644
--- a/src/api/productionManagement/processRouteItem.js
+++ b/src/api/productionManagement/processRouteItem.js
@@ -3,17 +3,36 @@
 
 // 鍒楄〃鏌ヨ
 export function findProcessRouteItemList(query) {
-    return request({
-        url: "/processRouteItem/list",
-        method: "get",
-        params: query,
-    });
+  return request({
+    url: "/processRouteItem/list",
+    method: "get",
+    params: query,
+  });
 }
 
 export function addOrUpdateProcessRouteItem(data) {
-    return request({
-        url: "/processRouteItem",
-        method: "post",
-        data: data,
-    });
-}
\ No newline at end of file
+  return request({
+    url: "/processRouteItem",
+    method: "post",
+    data: data,
+  });
+}
+
+// 鎺掑簭鎺ュ彛
+export function sortProcessRouteItem(data) {
+  return request({
+    url: "/processRouteItem/sort",
+    method: "post",
+    data: data,
+  });
+}
+
+// 鎵归噺鍒犻櫎鎺ュ彛
+export function batchDeleteProcessRouteItem(ids) {
+  // 灏唅d鏁扮粍杞崲涓洪�楀彿鍒嗛殧鐨勫瓧绗︿覆锛屾嫾鎺ュ埌URL鍚庨潰
+  const idsStr = Array.isArray(ids) ? ids.join(",") : ids;
+  return request({
+    url: `/processRouteItem/batchDelete/${idsStr}`,
+    method: "delete",
+  });
+}
diff --git a/src/api/productionManagement/productBom.js b/src/api/productionManagement/productBom.js
new file mode 100644
index 0000000..893755b
--- /dev/null
+++ b/src/api/productionManagement/productBom.js
@@ -0,0 +1,47 @@
+// 浜у搧BOM椤甸潰鎺ュ彛
+import request from "@/utils/request";
+
+// 鍒嗛〉鏌ヨ
+export function listPage(query) {
+  return request({
+    url: "/productBom/listPage",
+    method: "get",
+    params: query,
+  });
+}
+
+// 鏂板
+export function add(data) {
+  return request({
+    url: "/productBom/add",
+    method: "post",
+    data: data,
+  });
+}
+
+// 淇敼
+export function update(data) {
+  return request({
+    url: "/productBom/update",
+    method: "put",
+    data: data,
+  });
+}
+
+// 鎵归噺鍒犻櫎
+export function batchDelete(ids) {
+  return request({
+    url: "/productBom/batchDelete",
+    method: "delete",
+    data: ids,
+  });
+}
+
+// 鏍规嵁浜у搧鍨嬪彿ID鏌ヨBOM
+export function getByModel(productModelId) {
+  return request({
+    url: "/productBom/getByModel",
+    method: "get",
+    params: { productModelId },
+  });
+}
diff --git a/src/api/productionManagement/productProcessRoute.js b/src/api/productionManagement/productProcessRoute.js
index d756e26..e8d5da5 100644
--- a/src/api/productionManagement/productProcessRoute.js
+++ b/src/api/productionManagement/productProcessRoute.js
@@ -3,26 +3,52 @@
 
 // 鍒楄〃鏌ヨ
 export function findProductProcessRouteItemList(query) {
-    return request({
-        url: "/productProcessRoute/list",
-        method: "get",
-        params: query,
-    });
+  return request({
+    url: "/productProcessRoute/list",
+    method: "get",
+    params: query,
+  });
 }
 
 export function addOrUpdateProductProcessRouteItem(data) {
-    return request({
-        url: "/productProcessRoute/updateRouteItem",
-        method: "post",
-        data: data,
-    });
+  return request({
+    url: "/productProcessRoute/updateRouteItem",
+    method: "post",
+    data: data,
+  });
 }
 
-// 鍒犻櫎瀹㈡埛妗f
-export function deleteRouteItem(ids) {
-    return request({
-        url: '/productProcessRoute/deleteRouteItem',
-        method: 'delete',
-        data: ids
-    })
-}
\ No newline at end of file
+// 鐢熶骇璁㈠崟涓嬶細鏂板宸ヨ壓璺嚎椤圭洰
+export function addRouteItem(data) {
+  return request({
+    url: "/productProcessRoute/addRouteItem",
+    method: "post",
+    data,
+  });
+}
+
+// 鑾峰彇鐢熶骇璁㈠崟鍏宠仈鐨勫伐鑹鸿矾绾夸富淇℃伅
+export function listMain(orderId) {
+  return request({
+    url: "/productProcessRoute/listMain",
+    method: "get",
+    params: { orderId },
+  });
+}
+
+// 鍒犻櫎宸ヨ壓璺嚎椤圭洰锛堣矾鐢卞悗鎷兼帴 id锛�
+export function deleteRouteItem(id) {
+  return request({
+    url: `/productProcessRoute/deleteRouteItem/${id}`,
+    method: "delete",
+  });
+}
+
+// 鐢熶骇璁㈠崟涓嬶細鎺掑簭宸ヨ壓璺嚎椤圭洰
+export function sortRouteItem(data) {
+  return request({
+    url: "/productProcessRoute/sortRouteItem",
+    method: "post",
+    data,
+  });
+}
diff --git a/src/api/productionManagement/productStructure.js b/src/api/productionManagement/productStructure.js
index 074e27a..e69e14a 100644
--- a/src/api/productionManagement/productStructure.js
+++ b/src/api/productionManagement/productStructure.js
@@ -4,7 +4,7 @@
 // 鍒嗛〉鏌ヨ
 export function queryList(id) {
   return request({
-    url: "/productStructure/listByproductModelId/" + id,
+    url: "/productStructure/listBybomId/" + id,
     method: "get",
   });
 }
@@ -15,4 +15,4 @@
     method: "post",
     data: data,
   });
-}
\ No newline at end of file
+}
diff --git a/src/api/productionManagement/productionOrder.js b/src/api/productionManagement/productionOrder.js
index 0c37be1..9f110a7 100644
--- a/src/api/productionManagement/productionOrder.js
+++ b/src/api/productionManagement/productionOrder.js
@@ -10,7 +10,6 @@
   });
 }
 
-
 export function productOrderListPage(query) {
   return request({
     url: "/productOrder/page",
@@ -19,6 +18,33 @@
   });
 }
 
+// 鐢熶骇璁㈠崟-鎸変骇鍝佸瀷鍙锋煡璇㈠彲鐢ㄥ伐鑹鸿矾绾垮垪琛�
+export function listProcessRoute(query) {
+  return request({
+    url: "/productOrder/listProcessRoute",
+    method: "get",
+    params: query,
+  });
+}
+
+// 鐢熶骇璁㈠崟-缁戝畾宸ヨ壓璺嚎
+export function bindingRoute(data) {
+  return request({
+    url: "/productOrder/bindingRoute",
+    method: "post",
+    data,
+  });
+}
+
+// 鐢熶骇璁㈠崟-鏌ヨ浜у搧缁撴瀯鍒楄〃
+export function listProcessBom(query) {
+  return request({
+    url: "/productOrder/listProcessBom",
+    method: "get",
+    params: query,
+  });
+}
+
 // 鑾峰彇鐐掓満姝e湪宸ヤ綔閲忔暟鎹�
 export function schedulingList(query) {
   return request({
diff --git a/src/api/productionManagement/productionProcess.js b/src/api/productionManagement/productionProcess.js
index e3cd929..d3a453c 100644
--- a/src/api/productionManagement/productionProcess.js
+++ b/src/api/productionManagement/productionProcess.js
@@ -48,4 +48,22 @@
         url: "/productProcess/list",
         method: "get",
     });
+}
+
+// 瀵煎叆鏁版嵁
+export function importData(data) {
+  return request({
+    url: "/productProcess/importData",
+    method: "post",
+    data: data,
+  });
+}
+
+// 涓嬭浇妯℃澘
+export function downloadTemplate() {
+  return request({
+    url: "/productProcess/downloadTemplate",
+    method: "post",
+    responseType: "blob",
+  });
 }
\ No newline at end of file
diff --git a/src/components/Dialog/FileListDialog.vue b/src/components/Dialog/FileListDialog.vue
index ebe81dd..0721a55 100644
--- a/src/components/Dialog/FileListDialog.vue
+++ b/src/components/Dialog/FileListDialog.vue
@@ -229,10 +229,9 @@
 
 const handleUpload = async () => {
   if (props.uploadMethod) {
-    const newItem = await props.uploadMethod()
-    if (newItem) {
-      addAttachment(newItem)
-    }
+    // 濡傛灉鎻愪緵浜嗚嚜瀹氫箟涓婁紶鏂规硶锛岀敱鐖剁粍浠惰礋璐f洿鏂板垪琛紙閫氳繃 setList锛�
+    // 杩欓噷涓嶅啀鑷姩娣诲姞锛岄伩鍏嶄笌鐖剁粍浠剁殑 setList 閲嶅
+    await props.uploadMethod()
   }
   emit('upload')
 }
diff --git a/src/components/PIMTable/PIMTable.vue b/src/components/PIMTable/PIMTable.vue
index 01462f0..1480893 100644
--- a/src/components/PIMTable/PIMTable.vue
+++ b/src/components/PIMTable/PIMTable.vue
@@ -40,7 +40,7 @@
       :fixed="item.fixed"
       :label="item.label"
       :prop="item.prop"
-      :show-overflow-tooltip="item.dataType !== 'action'"
+      :show-overflow-tooltip="item.dataType !== 'action' && item.dataType !== 'slot'"
       :align="item.align"
       :sortable="!!item.sortable"
       :type="item.type"
diff --git a/src/components/PageHeader/index.vue b/src/components/PageHeader/index.vue
new file mode 100644
index 0000000..d8fc6fa
--- /dev/null
+++ b/src/components/PageHeader/index.vue
@@ -0,0 +1,53 @@
+<template>
+  <div class="page-header-wrapper">
+    <el-page-header @back="handleBack" :content="content">
+      <template #icon v-if="$slots.icon">
+        <slot name="icon"></slot>
+      </template>
+      <template #title v-if="$slots.title">
+        <slot name="title"></slot>
+      </template>
+      <template #content v-if="$slots.content">
+        <slot name="content"></slot>
+      </template>
+      <template #extra>
+        <slot name="extra">
+          <slot name="right-button"></slot>
+        </slot>
+      </template>
+    </el-page-header>
+  </div>
+</template>
+
+<script setup>
+import { useRouter } from 'vue-router'
+
+const props = defineProps({
+  content: {
+    type: String,
+    default: ''
+  }
+})
+
+const emit = defineEmits(['back'])
+
+const router = useRouter()
+
+const handleBack = () => {
+  emit('back')
+  // 榛樿杩斿洖鍒颁笂涓�绾�
+  router.back()
+}
+</script>
+
+<style scoped>
+.page-header-wrapper {
+  margin-bottom: 16px;
+}
+
+.page-header-wrapper :deep(.el-page-header__extra) {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+}
+</style>
diff --git a/src/components/QRCodeGenerator/index.vue b/src/components/QRCodeGenerator/index.vue
index 1708130..fd44f44 100644
--- a/src/components/QRCodeGenerator/index.vue
+++ b/src/components/QRCodeGenerator/index.vue
@@ -1,70 +1,79 @@
 <template>
   <div class="qr-code-generator">
     <!-- 浜岀淮鐮佺敓鎴愯〃鍗� -->
-    <el-form :model="form" :rules="rules" ref="formRef" label-width="120px" class="qr-form">
+    <el-form :model="form"
+             :rules="rules"
+             ref="formRef"
+             label-width="120px"
+             class="qr-form">
       <el-row :gutter="20">
         <el-col :span="12">
-          <el-form-item label="鏍囪瘑绫诲瀷" prop="type">
-            <el-select v-model="form.type" placeholder="璇烽�夋嫨鏍囪瘑绫诲瀷" style="width: 100%">
-              <el-option label="浜岀淮鐮�" value="qrcode"></el-option>
-              <el-option label="闃蹭吉鐮�" value="security"></el-option>
+          <el-form-item label="鏍囪瘑绫诲瀷"
+                        prop="type">
+            <el-select v-model="form.type"
+                       placeholder="璇烽�夋嫨鏍囪瘑绫诲瀷"
+                       style="width: 100%">
+              <el-option label="浜岀淮鐮�"
+                         value="qrcode"></el-option>
+              <el-option label="闃蹭吉鐮�"
+                         value="security"></el-option>
             </el-select>
           </el-form-item>
         </el-col>
         <el-col :span="12">
-          <el-form-item label="鍐呭" prop="content">
-            <el-input 
-              v-model="form.content" 
-              placeholder="璇疯緭鍏ヨ缂栫爜鐨勫唴瀹�"
-              :type="form.type === 'security' ? 'textarea' : 'text'"
-              :rows="form.type === 'security' ? 3 : 1"
-            ></el-input>
+          <el-form-item label="鍐呭"
+                        prop="content">
+            <el-input v-model="form.content"
+                      placeholder="璇疯緭鍏ヨ缂栫爜鐨勫唴瀹�"
+                      :type="form.type === 'security' ? 'textarea' : 'text'"
+                      :rows="form.type === 'security' ? 3 : 1"></el-input>
           </el-form-item>
         </el-col>
       </el-row>
-      
       <el-row :gutter="20">
         <el-col :span="12">
-          <el-form-item label="灏哄" prop="size">
-            <el-input-number 
-              v-model="form.size" 
-              :min="100" 
-              :max="500" 
-              :step="50"
-              style="width: 100%"
-            ></el-input-number>
+          <el-form-item label="灏哄"
+                        prop="size">
+            <el-input-number v-model="form.size"
+                             :min="100"
+                             :max="500"
+                             :step="50"
+                             style="width: 100%"></el-input-number>
           </el-form-item>
         </el-col>
         <el-col :span="12">
-          <el-form-item label="杈硅窛" prop="margin">
-            <el-input-number 
-              v-model="form.margin" 
-              :min="0" 
-              :max="10" 
-              :step="1"
-              style="width: 100%"
-            ></el-input-number>
+          <el-form-item label="杈硅窛"
+                        prop="margin">
+            <el-input-number v-model="form.margin"
+                             :min="0"
+                             :max="10"
+                             :step="1"
+                             style="width: 100%"></el-input-number>
           </el-form-item>
         </el-col>
       </el-row>
-      
       <el-row :gutter="20">
         <el-col :span="12">
-          <el-form-item label="鍓嶆櫙鑹�" prop="foregroundColor">
-            <el-color-picker v-model="form.foregroundColor" style="width: 100%"></el-color-picker>
+          <el-form-item label="鍓嶆櫙鑹�"
+                        prop="foregroundColor">
+            <el-color-picker v-model="form.foregroundColor"
+                             style="width: 100%"></el-color-picker>
           </el-form-item>
         </el-col>
         <el-col :span="12">
-          <el-form-item label="鑳屾櫙鑹�" prop="backgroundColor">
-            <el-color-picker v-model="form.backgroundColor" style="width: 100%"></el-color-picker>
+          <el-form-item label="鑳屾櫙鑹�"
+                        prop="backgroundColor">
+            <el-color-picker v-model="form.backgroundColor"
+                             style="width: 100%"></el-color-picker>
           </el-form-item>
         </el-col>
       </el-row>
-      
       <el-row :gutter="20">
         <el-col :span="24">
           <el-form-item>
-            <el-button type="primary" @click="generateCode" :loading="generating">
+            <el-button type="primary"
+                       @click="generateCode"
+                       :loading="generating">
               鐢熸垚{{ form.type === 'qrcode' ? '浜岀淮鐮�' : '闃蹭吉鐮�' }}
             </el-button>
             <el-button @click="resetForm">閲嶇疆</el-button>
@@ -72,18 +81,17 @@
         </el-col>
       </el-row>
     </el-form>
-
     <!-- 鐢熸垚鐨勭爜鏄剧ず鍖哄煙 -->
-    <div v-if="generatedCodeUrl" class="code-display">
+    <div v-if="generatedCodeUrl"
+         class="code-display">
       <el-divider content-position="center">
         {{ form.type === 'qrcode' ? '鐢熸垚鐨勪簩缁寸爜' : '鐢熸垚鐨勯槻浼爜' }}
       </el-divider>
-      
       <div class="code-container">
         <div class="code-image">
-          <img :src="generatedCodeUrl" :alt="form.type === 'qrcode' ? '浜岀淮鐮�' : '闃蹭吉鐮�'" />
+          <img :src="generatedCodeUrl"
+               :alt="form.type === 'qrcode' ? '浜岀淮鐮�' : '闃蹭吉鐮�'" />
         </div>
-        
         <div class="code-info">
           <p><strong>鍐呭锛�</strong>{{ form.content }}</p>
           <p><strong>绫诲瀷锛�</strong>{{ form.type === 'qrcode' ? '浜岀淮鐮�' : '闃蹭吉鐮�' }}</p>
@@ -91,60 +99,71 @@
           <p><strong>鐢熸垚鏃堕棿锛�</strong>{{ generateTime }}</p>
         </div>
       </div>
-      
       <div class="code-actions">
-        <el-button type="success" @click="downloadCode" icon="Download">
+        <el-button type="success"
+                   @click="downloadCode"
+                   icon="Download">
           涓嬭浇鍥剧墖
         </el-button>
-        <el-button type="primary" @click="copyToClipboard" icon="CopyDocument">
+        <el-button type="primary"
+                   @click="copyToClipboard"
+                   icon="CopyDocument">
           澶嶅埗鍐呭
         </el-button>
-        <el-button @click="printCode" icon="Printer">
+        <el-button @click="printCode"
+                   icon="Printer">
           鎵撳嵃
         </el-button>
       </div>
     </div>
-
     <!-- 鎵归噺鐢熸垚瀵硅瘽妗� -->
-    <el-dialog v-model="batchDialogVisible" title="鎵归噺鐢熸垚" width="600px">
-      <el-form :model="batchForm" label-width="120px">
+    <el-dialog v-model="batchDialogVisible"
+               title="鎵归噺鐢熸垚"
+               width="600px">
+      <el-form :model="batchForm"
+               label-width="120px">
         <el-form-item label="鐢熸垚鏁伴噺">
-          <el-input-number v-model="batchForm.quantity" :min="1" :max="100" style="width: 100%"></el-input-number>
+          <el-input-number v-model="batchForm.quantity"
+                           :min="1"
+                           :max="100"
+                           style="width: 100%"></el-input-number>
         </el-form-item>
         <el-form-item label="鍓嶇紑">
-          <el-input v-model="batchForm.prefix" placeholder="璇疯緭鍏ュ墠缂�锛屽锛歅ROD_"></el-input>
+          <el-input v-model="batchForm.prefix"
+                    placeholder="璇疯緭鍏ュ墠缂�锛屽锛歅ROD_"></el-input>
         </el-form-item>
         <el-form-item label="璧峰缂栧彿">
-          <el-input-number v-model="batchForm.startNumber" :min="1" style="width: 100%"></el-input-number>
+          <el-input-number v-model="batchForm.startNumber"
+                           :min="1"
+                           style="width: 100%"></el-input-number>
         </el-form-item>
       </el-form>
-      
       <template #footer>
         <div class="dialog-footer">
+          <el-button type="primary"
+                     @click="generateBatchCodes">寮�濮嬬敓鎴�</el-button>
           <el-button @click="batchDialogVisible = false">鍙栨秷</el-button>
-          <el-button type="primary" @click="generateBatchCodes">寮�濮嬬敓鎴�</el-button>
         </div>
       </template>
     </el-dialog>
-
     <!-- 鎵归噺鐢熸垚缁撴灉 -->
-    <div v-if="batchCodes.length > 0" class="batch-results">
+    <div v-if="batchCodes.length > 0"
+         class="batch-results">
       <el-divider content-position="center">鎵归噺鐢熸垚缁撴灉</el-divider>
-      
       <div class="batch-grid">
-        <div 
-          v-for="(code, index) in batchCodes" 
-          :key="index" 
-          class="batch-item"
-        >
-          <img :src="code.url" :alt="code.content" />
+        <div v-for="(code, index) in batchCodes"
+             :key="index"
+             class="batch-item">
+          <img :src="code.url"
+               :alt="code.content" />
           <p class="batch-content">{{ code.content }}</p>
-          <el-button size="small" @click="downloadSingleCode(code)">涓嬭浇</el-button>
+          <el-button size="small"
+                     @click="downloadSingleCode(code)">涓嬭浇</el-button>
         </div>
       </div>
-      
       <div class="batch-actions">
-        <el-button type="success" @click="downloadAllCodes">涓嬭浇鍏ㄩ儴</el-button>
+        <el-button type="success"
+                   @click="downloadAllCodes">涓嬭浇鍏ㄩ儴</el-button>
         <el-button @click="clearBatchCodes">娓呯┖缁撴灉</el-button>
       </div>
     </div>
@@ -152,390 +171,396 @@
 </template>
 
 <script setup>
-import { ref, reactive, computed, onMounted } from 'vue'
-import QRCode from 'qrcode'
-import { ElMessage, ElMessageBox } from 'element-plus'
-import { Download, CopyDocument, Printer } from '@element-plus/icons-vue'
+  import { ref, reactive, computed, onMounted } from "vue";
+  import QRCode from "qrcode";
+  import { ElMessage, ElMessageBox } from "element-plus";
+  import { Download, CopyDocument, Printer } from "@element-plus/icons-vue";
 
-// 瀹氫箟缁勪欢鍚嶇О
-defineOptions({
-  name: 'QRCodeGenerator'
-})
+  // 瀹氫箟缁勪欢鍚嶇О
+  defineOptions({
+    name: "QRCodeGenerator",
+  });
 
-// 琛ㄥ崟鏁版嵁
-const form = reactive({
-  type: 'qrcode',
-  content: '',
-  size: 200,
-  margin: 2,
-  foregroundColor: '#000000',
-  backgroundColor: '#FFFFFF'
-})
+  // 琛ㄥ崟鏁版嵁
+  const form = reactive({
+    type: "qrcode",
+    content: "",
+    size: 200,
+    margin: 2,
+    foregroundColor: "#000000",
+    backgroundColor: "#FFFFFF",
+  });
 
-// 琛ㄥ崟楠岃瘉瑙勫垯
-const rules = {
-  type: [{ required: true, message: '璇烽�夋嫨鏍囪瘑绫诲瀷', trigger: 'change' }],
-  content: [{ required: true, message: '璇疯緭鍏ュ唴瀹�', trigger: 'blur' }]
-}
+  // 琛ㄥ崟楠岃瘉瑙勫垯
+  const rules = {
+    type: [{ required: true, message: "璇烽�夋嫨鏍囪瘑绫诲瀷", trigger: "change" }],
+    content: [{ required: true, message: "璇疯緭鍏ュ唴瀹�", trigger: "blur" }],
+  };
 
-// 鍝嶅簲寮忔暟鎹�
-const formRef = ref()
-const generating = ref(false)
-const generatedCodeUrl = ref('')
-const generateTime = ref('')
-const batchDialogVisible = ref(false)
-const batchForm = reactive({
-  quantity: 10,
-  prefix: '',
-  startNumber: 1
-})
-const batchCodes = ref([])
+  // 鍝嶅簲寮忔暟鎹�
+  const formRef = ref();
+  const generating = ref(false);
+  const generatedCodeUrl = ref("");
+  const generateTime = ref("");
+  const batchDialogVisible = ref(false);
+  const batchForm = reactive({
+    quantity: 10,
+    prefix: "",
+    startNumber: 1,
+  });
+  const batchCodes = ref([]);
 
-// 鐢熸垚浜岀淮鐮佹垨闃蹭吉鐮�
-const generateCode = async () => {
-  try {
-    await formRef.value.validate()
-    
-    if (!form.content.trim()) {
-      ElMessage.warning('璇疯緭鍏ヨ缂栫爜鐨勫唴瀹�')
-      return
-    }
-    
-    generating.value = true
-    
-    if (form.type === 'qrcode') {
-      // 鐢熸垚浜岀淮鐮�
-      generatedCodeUrl.value = await QRCode.toDataURL(form.content, {
-        width: form.size,
-        margin: form.margin,
-        color: {
-          dark: form.foregroundColor,
-          light: form.backgroundColor
-        },
-        errorCorrectionLevel: 'M'
-      })
-    } else {
-      // 鐢熸垚闃蹭吉鐮侊紙浣跨敤浜岀淮鐮佹妧鏈紝浣嗗唴瀹规牸寮忎笉鍚岋級
-      const securityContent = generateSecurityCode(form.content)
-      generatedCodeUrl.value = await QRCode.toDataURL(securityContent, {
-        width: form.size,
-        margin: form.margin,
-        color: {
-          dark: form.foregroundColor,
-          light: form.backgroundColor
-        },
-        errorCorrectionLevel: 'H' // 闃蹭吉鐮佷娇鐢ㄦ渶楂樼籂閿欑骇鍒�
-      })
-    }
-    
-    generateTime.value = new Date().toLocaleString()
-    ElMessage.success('鐢熸垚鎴愬姛锛�')
-    
-  } catch (error) {
-    console.error('鐢熸垚澶辫触:', error)
-    ElMessage.error('鐢熸垚澶辫触锛�' + error.message)
-  } finally {
-    generating.value = false
-  }
-}
+  // 鐢熸垚浜岀淮鐮佹垨闃蹭吉鐮�
+  const generateCode = async () => {
+    try {
+      await formRef.value.validate();
 
-// 鐢熸垚闃蹭吉鐮佸唴瀹�
-const generateSecurityCode = (content) => {
-  const timestamp = Date.now()
-  const random = Math.random().toString(36).substr(2, 8)
-  return `SEC_${content}_${timestamp}_${random}`
-}
+      if (!form.content.trim()) {
+        ElMessage.warning("璇疯緭鍏ヨ缂栫爜鐨勫唴瀹�");
+        return;
+      }
 
-// 涓嬭浇鐢熸垚鐨勭爜
-const downloadCode = () => {
-  if (!generatedCodeUrl.value) {
-    ElMessage.warning('璇峰厛鐢熸垚鐮�')
-    return
-  }
-  
-  const a = document.createElement('a')
-  a.href = generatedCodeUrl.value
-  a.download = `${form.type === 'qrcode' ? '浜岀淮鐮�' : '闃蹭吉鐮�'}_${new Date().getTime()}.png`
-  document.body.appendChild(a)
-  a.click()
-  document.body.removeChild(a)
-  ElMessage.success('涓嬭浇鎴愬姛锛�')
-}
+      generating.value = true;
 
-// 澶嶅埗鍐呭鍒板壀璐存澘
-const copyToClipboard = async () => {
-  try {
-    await navigator.clipboard.writeText(form.content)
-    ElMessage.success('鍐呭宸插鍒跺埌鍓创鏉�')
-  } catch (error) {
-    // 闄嶇骇鏂规
-    const textArea = document.createElement('textarea')
-    textArea.value = form.content
-    document.body.appendChild(textArea)
-    textArea.select()
-    document.execCommand('copy')
-    document.body.removeChild(textArea)
-    ElMessage.success('鍐呭宸插鍒跺埌鍓创鏉�')
-  }
-}
-
-// 鎵撳嵃鐮�
-const printCode = () => {
-  if (!generatedCodeUrl.value) {
-    ElMessage.warning('璇峰厛鐢熸垚鐮�')
-    return
-  }
-  
-  const printWindow = window.open('', '_blank')
-  printWindow.document.write(`
-    <html>
-      <head>
-        <title>鎵撳嵃${form.type === 'qrcode' ? '浜岀淮鐮�' : '闃蹭吉鐮�'}</title>
-        <style>
-          body { text-align: center; padding: 20px; }
-          img { max-width: 100%; height: auto; }
-          .info { margin: 20px 0; }
-        </style>
-      </head>
-      <body>
-        <h2>${form.type === 'qrcode' ? '浜岀淮鐮�' : '闃蹭吉鐮�'}</h2>
-        <img src="${generatedCodeUrl.value}" alt="${form.type === 'qrcode' ? '浜岀淮鐮�' : '闃蹭吉鐮�'}" />
-        <div class="info">
-          <p><strong>鍐呭锛�</strong>${form.content}</p>
-          <p><strong>鐢熸垚鏃堕棿锛�</strong>${generateTime.value}</p>
-        </div>
-      </body>
-    </html>
-  `)
-  printWindow.document.close()
-  printWindow.print()
-}
-
-// 閲嶇疆琛ㄥ崟
-const resetForm = () => {
-  formRef.value.resetFields()
-  generatedCodeUrl.value = ''
-  generateTime.value = ''
-  batchCodes.value = []
-}
-
-// 鎵归噺鐢熸垚
-const generateBatchCodes = async () => {
-  if (!batchForm.prefix.trim()) {
-    ElMessage.warning('璇疯緭鍏ュ墠缂�')
-    return
-  }
-  
-  batchCodes.value = []
-  generating.value = true
-  
-  try {
-    for (let i = 0; i < batchForm.quantity; i++) {
-      const number = batchForm.startNumber + i
-      const content = `${batchForm.prefix}${number.toString().padStart(6, '0')}`
-      
-      let codeUrl
-      if (form.type === 'qrcode') {
-        codeUrl = await QRCode.toDataURL(content, {
+      if (form.type === "qrcode") {
+        // 鐢熸垚浜岀淮鐮�
+        generatedCodeUrl.value = await QRCode.toDataURL(form.content, {
           width: form.size,
           margin: form.margin,
           color: {
             dark: form.foregroundColor,
-            light: form.backgroundColor
-          }
-        })
+            light: form.backgroundColor,
+          },
+          errorCorrectionLevel: "M",
+        });
       } else {
-        const securityContent = generateSecurityCode(content)
-        codeUrl = await QRCode.toDataURL(securityContent, {
+        // 鐢熸垚闃蹭吉鐮侊紙浣跨敤浜岀淮鐮佹妧鏈紝浣嗗唴瀹规牸寮忎笉鍚岋級
+        const securityContent = generateSecurityCode(form.content);
+        generatedCodeUrl.value = await QRCode.toDataURL(securityContent, {
           width: form.size,
           margin: form.margin,
           color: {
             dark: form.foregroundColor,
-            light: form.backgroundColor
-          }
-        })
+            light: form.backgroundColor,
+          },
+          errorCorrectionLevel: "H", // 闃蹭吉鐮佷娇鐢ㄦ渶楂樼籂閿欑骇鍒�
+        });
       }
-      
-      batchCodes.value.push({
-        content,
-        url: codeUrl
-      })
+
+      generateTime.value = new Date().toLocaleString();
+      ElMessage.success("鐢熸垚鎴愬姛锛�");
+    } catch (error) {
+      console.error("鐢熸垚澶辫触:", error);
+      ElMessage.error("鐢熸垚澶辫触锛�" + error.message);
+    } finally {
+      generating.value = false;
     }
-    
-    ElMessage.success(`鎵归噺鐢熸垚瀹屾垚锛屽叡鐢熸垚 ${batchForm.quantity} 涓爜`)
-    batchDialogVisible.value = false
-    
-  } catch (error) {
-    console.error('鎵归噺鐢熸垚澶辫触:', error)
-    ElMessage.error('鎵归噺鐢熸垚澶辫触锛�' + error.message)
-  } finally {
-    generating.value = false
-  }
-}
+  };
 
-// 涓嬭浇鍗曚釜鎵归噺鐢熸垚鐨勭爜
-const downloadSingleCode = (code) => {
-  const a = document.createElement('a')
-  a.href = code.url
-  a.download = `${code.content}.png`
-  document.body.appendChild(a)
-  a.click()
-  document.body.removeChild(a)
-}
+  // 鐢熸垚闃蹭吉鐮佸唴瀹�
+  const generateSecurityCode = content => {
+    const timestamp = Date.now();
+    const random = Math.random().toString(36).substr(2, 8);
+    return `SEC_${content}_${timestamp}_${random}`;
+  };
 
-// 涓嬭浇鎵�鏈夋壒閲忕敓鎴愮殑鐮�
-const downloadAllCodes = async () => {
-  if (batchCodes.value.length === 0) {
-    ElMessage.warning('娌℃湁鍙笅杞界殑鐮�')
-    return
-  }
-  
-  try {
-    // 浣跨敤JSZip鎵撳寘涓嬭浇
-    const JSZip = await import('jszip')
-    const zip = new JSZip.default()
-    
-    batchCodes.value.forEach((code, index) => {
-      // 灏哹ase64杞崲涓篵lob
-      const base64Data = code.url.split(',')[1]
-      const byteCharacters = atob(base64Data)
-      const byteNumbers = new Array(byteCharacters.length)
-      for (let i = 0; i < byteCharacters.length; i++) {
-        byteNumbers[i] = byteCharacters.charCodeAt(i)
+  // 涓嬭浇鐢熸垚鐨勭爜
+  const downloadCode = () => {
+    if (!generatedCodeUrl.value) {
+      ElMessage.warning("璇峰厛鐢熸垚鐮�");
+      return;
+    }
+
+    const a = document.createElement("a");
+    a.href = generatedCodeUrl.value;
+    a.download = `${
+      form.type === "qrcode" ? "浜岀淮鐮�" : "闃蹭吉鐮�"
+    }_${new Date().getTime()}.png`;
+    document.body.appendChild(a);
+    a.click();
+    document.body.removeChild(a);
+    ElMessage.success("涓嬭浇鎴愬姛锛�");
+  };
+
+  // 澶嶅埗鍐呭鍒板壀璐存澘
+  const copyToClipboard = async () => {
+    try {
+      await navigator.clipboard.writeText(form.content);
+      ElMessage.success("鍐呭宸插鍒跺埌鍓创鏉�");
+    } catch (error) {
+      // 闄嶇骇鏂规
+      const textArea = document.createElement("textarea");
+      textArea.value = form.content;
+      document.body.appendChild(textArea);
+      textArea.select();
+      document.execCommand("copy");
+      document.body.removeChild(textArea);
+      ElMessage.success("鍐呭宸插鍒跺埌鍓创鏉�");
+    }
+  };
+
+  // 鎵撳嵃鐮�
+  const printCode = () => {
+    if (!generatedCodeUrl.value) {
+      ElMessage.warning("璇峰厛鐢熸垚鐮�");
+      return;
+    }
+
+    const printWindow = window.open("", "_blank");
+    printWindow.document.write(`
+      <html>
+        <head>
+          <title>鎵撳嵃${form.type === "qrcode" ? "浜岀淮鐮�" : "闃蹭吉鐮�"}</title>
+          <style>
+            body { text-align: center; padding: 20px; }
+            img { max-width: 100%; height: auto; }
+            .info { margin: 20px 0; }
+          </style>
+        </head>
+        <body>
+          <h2>${form.type === "qrcode" ? "浜岀淮鐮�" : "闃蹭吉鐮�"}</h2>
+          <img src="${generatedCodeUrl.value}" alt="${
+      form.type === "qrcode" ? "浜岀淮鐮�" : "闃蹭吉鐮�"
+    }" />
+          <div class="info">
+            <p><strong>鍐呭锛�</strong>${form.content}</p>
+            <p><strong>鐢熸垚鏃堕棿锛�</strong>${generateTime.value}</p>
+          </div>
+        </body>
+      </html>
+    `);
+    printWindow.document.close();
+    printWindow.print();
+  };
+
+  // 閲嶇疆琛ㄥ崟
+  const resetForm = () => {
+    formRef.value.resetFields();
+    generatedCodeUrl.value = "";
+    generateTime.value = "";
+    batchCodes.value = [];
+  };
+
+  // 鎵归噺鐢熸垚
+  const generateBatchCodes = async () => {
+    if (!batchForm.prefix.trim()) {
+      ElMessage.warning("璇疯緭鍏ュ墠缂�");
+      return;
+    }
+
+    batchCodes.value = [];
+    generating.value = true;
+
+    try {
+      for (let i = 0; i < batchForm.quantity; i++) {
+        const number = batchForm.startNumber + i;
+        const content = `${batchForm.prefix}${number
+          .toString()
+          .padStart(6, "0")}`;
+
+        let codeUrl;
+        if (form.type === "qrcode") {
+          codeUrl = await QRCode.toDataURL(content, {
+            width: form.size,
+            margin: form.margin,
+            color: {
+              dark: form.foregroundColor,
+              light: form.backgroundColor,
+            },
+          });
+        } else {
+          const securityContent = generateSecurityCode(content);
+          codeUrl = await QRCode.toDataURL(securityContent, {
+            width: form.size,
+            margin: form.margin,
+            color: {
+              dark: form.foregroundColor,
+              light: form.backgroundColor,
+            },
+          });
+        }
+
+        batchCodes.value.push({
+          content,
+          url: codeUrl,
+        });
       }
-      const byteArray = new Uint8Array(byteNumbers)
-      
-      zip.file(`${code.content}.png`, byteArray)
-    })
-    
-    const content = await zip.generateAsync({ type: 'blob' })
-    const a = document.createElement('a')
-    a.href = URL.createObjectURL(content)
-    a.download = `鎵归噺${form.type === 'qrcode' ? '浜岀淮鐮�' : '闃蹭吉鐮�'}_${new Date().getTime()}.zip`
-    document.body.appendChild(a)
-    a.click()
-    document.body.removeChild(a)
-    URL.revokeObjectURL(a.href)
-    
-    ElMessage.success('鎵归噺涓嬭浇瀹屾垚锛�')
-  } catch (error) {
-    console.error('鎵归噺涓嬭浇澶辫触:', error)
-    ElMessage.error('鎵归噺涓嬭浇澶辫触锛岃閫愪釜涓嬭浇')
-  }
-}
 
-// 娓呯┖鎵归噺鐢熸垚缁撴灉
-const clearBatchCodes = () => {
-  batchCodes.value = []
-}
+      ElMessage.success(`鎵归噺鐢熸垚瀹屾垚锛屽叡鐢熸垚 ${batchForm.quantity} 涓爜`);
+      batchDialogVisible.value = false;
+    } catch (error) {
+      console.error("鎵归噺鐢熸垚澶辫触:", error);
+      ElMessage.error("鎵归噺鐢熸垚澶辫触锛�" + error.message);
+    } finally {
+      generating.value = false;
+    }
+  };
 
-// 鏆撮湶鏂规硶缁欑埗缁勪欢
-defineExpose({
-  generateCode,
-  downloadCode,
-  resetForm,
-  form
-})
+  // 涓嬭浇鍗曚釜鎵归噺鐢熸垚鐨勭爜
+  const downloadSingleCode = code => {
+    const a = document.createElement("a");
+    a.href = code.url;
+    a.download = `${code.content}.png`;
+    document.body.appendChild(a);
+    a.click();
+    document.body.removeChild(a);
+  };
+
+  // 涓嬭浇鎵�鏈夋壒閲忕敓鎴愮殑鐮�
+  const downloadAllCodes = async () => {
+    if (batchCodes.value.length === 0) {
+      ElMessage.warning("娌℃湁鍙笅杞界殑鐮�");
+      return;
+    }
+
+    try {
+      // 浣跨敤JSZip鎵撳寘涓嬭浇
+      const JSZip = await import("jszip");
+      const zip = new JSZip.default();
+
+      batchCodes.value.forEach((code, index) => {
+        // 灏哹ase64杞崲涓篵lob
+        const base64Data = code.url.split(",")[1];
+        const byteCharacters = atob(base64Data);
+        const byteNumbers = new Array(byteCharacters.length);
+        for (let i = 0; i < byteCharacters.length; i++) {
+          byteNumbers[i] = byteCharacters.charCodeAt(i);
+        }
+        const byteArray = new Uint8Array(byteNumbers);
+
+        zip.file(`${code.content}.png`, byteArray);
+      });
+
+      const content = await zip.generateAsync({ type: "blob" });
+      const a = document.createElement("a");
+      a.href = URL.createObjectURL(content);
+      a.download = `鎵归噺${
+        form.type === "qrcode" ? "浜岀淮鐮�" : "闃蹭吉鐮�"
+      }_${new Date().getTime()}.zip`;
+      document.body.appendChild(a);
+      a.click();
+      document.body.removeChild(a);
+      URL.revokeObjectURL(a.href);
+
+      ElMessage.success("鎵归噺涓嬭浇瀹屾垚锛�");
+    } catch (error) {
+      console.error("鎵归噺涓嬭浇澶辫触:", error);
+      ElMessage.error("鎵归噺涓嬭浇澶辫触锛岃閫愪釜涓嬭浇");
+    }
+  };
+
+  // 娓呯┖鎵归噺鐢熸垚缁撴灉
+  const clearBatchCodes = () => {
+    batchCodes.value = [];
+  };
+
+  // 鏆撮湶鏂规硶缁欑埗缁勪欢
+  defineExpose({
+    generateCode,
+    downloadCode,
+    resetForm,
+    form,
+  });
 </script>
 
 <style scoped>
-.qr-code-generator {
-  padding: 20px;
-}
+  .qr-code-generator {
+    padding: 20px;
+  }
 
-.qr-form {
-  background: #f8f9fa;
-  padding: 20px;
-  border-radius: 8px;
-  margin-bottom: 20px;
-}
+  .qr-form {
+    background: #f8f9fa;
+    padding: 20px;
+    border-radius: 8px;
+    margin-bottom: 20px;
+  }
 
-.code-display {
-  margin-top: 30px;
-}
+  .code-display {
+    margin-top: 30px;
+  }
 
-.code-container {
-  display: flex;
-  justify-content: center;
-  align-items: flex-start;
-  gap: 40px;
-  margin: 20px 0;
-}
-
-.code-image img {
-  border: 2px solid #e0e0e0;
-  border-radius: 8px;
-  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
-}
-
-.code-info {
-  text-align: left;
-  min-width: 200px;
-}
-
-.code-info p {
-  margin: 8px 0;
-  color: #666;
-}
-
-.code-actions {
-  text-align: center;
-  margin: 20px 0;
-}
-
-.code-actions .el-button {
-  margin: 0 10px;
-}
-
-.batch-results {
-  margin-top: 30px;
-}
-
-.batch-grid {
-  display: grid;
-  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
-  gap: 20px;
-  margin: 20px 0;
-}
-
-.batch-item {
-  text-align: center;
-  padding: 15px;
-  border: 1px solid #e0e0e0;
-  border-radius: 8px;
-  background: #fff;
-}
-
-.batch-item img {
-  width: 100px;
-  height: 100px;
-  margin-bottom: 10px;
-}
-
-.batch-content {
-  font-size: 12px;
-  color: #666;
-  margin: 10px 0;
-  word-break: break-all;
-}
-
-.batch-actions {
-  text-align: center;
-  margin: 20px 0;
-}
-
-.batch-actions .el-button {
-  margin: 0 10px;
-}
-
-@media (max-width: 768px) {
   .code-container {
-    flex-direction: column;
-    align-items: center;
+    display: flex;
+    justify-content: center;
+    align-items: flex-start;
+    gap: 40px;
+    margin: 20px 0;
   }
-  
+
+  .code-image img {
+    border: 2px solid #e0e0e0;
+    border-radius: 8px;
+    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
+  }
+
+  .code-info {
+    text-align: left;
+    min-width: 200px;
+  }
+
+  .code-info p {
+    margin: 8px 0;
+    color: #666;
+  }
+
+  .code-actions {
+    text-align: center;
+    margin: 20px 0;
+  }
+
+  .code-actions .el-button {
+    margin: 0 10px;
+  }
+
+  .batch-results {
+    margin-top: 30px;
+  }
+
   .batch-grid {
-    grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
+    display: grid;
+    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
+    gap: 20px;
+    margin: 20px 0;
   }
-}
+
+  .batch-item {
+    text-align: center;
+    padding: 15px;
+    border: 1px solid #e0e0e0;
+    border-radius: 8px;
+    background: #fff;
+  }
+
+  .batch-item img {
+    width: 100px;
+    height: 100px;
+    margin-bottom: 10px;
+  }
+
+  .batch-content {
+    font-size: 12px;
+    color: #666;
+    margin: 10px 0;
+    word-break: break-all;
+  }
+
+  .batch-actions {
+    text-align: center;
+    margin: 20px 0;
+  }
+
+  .batch-actions .el-button {
+    margin: 0 10px;
+  }
+
+  @media (max-width: 768px) {
+    .code-container {
+      flex-direction: column;
+      align-items: center;
+    }
+
+    .batch-grid {
+      grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
+    }
+  }
 </style>
diff --git a/src/layout/components/NotificationCenter/index.vue b/src/layout/components/NotificationCenter/index.vue
index df42650..6098153 100644
--- a/src/layout/components/NotificationCenter/index.vue
+++ b/src/layout/components/NotificationCenter/index.vue
@@ -107,8 +107,8 @@
     }
     const params = {
       consigneeId: consigneeId,
-      pageNum: pageNum.value,
-      pageSize: pageSize.value,
+      current: pageNum.value,
+      size: pageSize.value,
       status: activeTab.value === 'read' ? 1 : 0
     }
     const res = await listMessage(params)
diff --git a/src/main.js b/src/main.js
index abaac2e..0b3f714 100644
--- a/src/main.js
+++ b/src/main.js
@@ -52,6 +52,8 @@
 import DictTag from "@/components/DictTag";
 // 琛ㄦ牸缁勪欢
 import PIMTable from "@/components/PIMTable/PIMTable.vue";
+// 椤甸潰澶撮儴缁勪欢
+import PageHeader from "@/components/PageHeader/index.vue";
 
 import { getToken } from "@/utils/auth";
 import {
@@ -93,6 +95,7 @@
 app.component("RightToolbar", RightToolbar);
 app.component("Editor", Editor);
 app.component("PIMTable", PIMTable);
+app.component("PageHeader", PageHeader);
 
 app.use(router);
 app.use(store);
diff --git a/src/views/collaborativeApproval/approvalProcess/components/infoFormDia.vue b/src/views/collaborativeApproval/approvalProcess/components/infoFormDia.vue
index a269375..01650d4 100644
--- a/src/views/collaborativeApproval/approvalProcess/components/infoFormDia.vue
+++ b/src/views/collaborativeApproval/approvalProcess/components/infoFormDia.vue
@@ -17,19 +17,18 @@
         <el-row>
           <el-col :span="24">
             <el-form-item label="鐢宠閮ㄩ棬锛�" prop="approveDeptName">
-              <el-input v-model="form.approveDeptName" placeholder="璇疯緭鍏�" clearable/>
-<!--							<el-select-->
-<!--								disabled-->
-<!--								v-model="form.approveDeptId"-->
-<!--								placeholder="閫夋嫨閮ㄩ棬"-->
-<!--							>-->
-<!--								<el-option-->
-<!--									v-for="user in productOptions"-->
-<!--									:key="user.deptId"-->
-<!--									:label="user.deptName"-->
-<!--									:value="user.deptId"-->
-<!--								/>-->
-<!--							</el-select>-->
+<!--              <el-input v-model="form.approveDeptName" placeholder="璇疯緭鍏�" clearable/>-->
+							<el-select
+								v-model="form.approveDeptId"
+								placeholder="閫夋嫨閮ㄩ棬"
+							>
+								<el-option
+									v-for="user in productOptions"
+									:key="user.deptId"
+									:label="user.deptName"
+									:value="user.deptId"
+								/>
+							</el-select>
             </el-form-item>
           </el-col>
         </el-row>
diff --git a/src/views/collaborativeApproval/noticeManagement/index.vue b/src/views/collaborativeApproval/noticeManagement/index.vue
index 6b0ea98..d92adea 100644
--- a/src/views/collaborativeApproval/noticeManagement/index.vue
+++ b/src/views/collaborativeApproval/noticeManagement/index.vue
@@ -855,6 +855,9 @@
   color: #606266;
   line-height: 1.6;
   font-size: 14px;
+  word-break: break-all;
+  white-space: pre-wrap;
+  overflow-wrap: break-word;
 }
 
 .card-footer {
diff --git a/src/views/financialManagement/expenseManagement/Form.vue b/src/views/financialManagement/expenseManagement/Form.vue
deleted file mode 100644
index 9cfe5da..0000000
--- a/src/views/financialManagement/expenseManagement/Form.vue
+++ /dev/null
@@ -1,123 +0,0 @@
-<template>
-  <el-form :model="form" label-width="100px" :rules="formRules" ref="formRef">
-    <el-form-item label="鏀嚭鏃ユ湡" prop="expenseDate">
-          <el-date-picker
-            style="width: 100%"
-            v-model="form.expenseDate"
-            format="YYYY-MM-DD"
-            value-format="YYYY-MM-DD"
-            type="date"
-            placeholder="璇烽�夋嫨鏃ユ湡"
-            clearable
-          />
-        </el-form-item>
-        <el-form-item label="鏀嚭绫诲瀷" prop="expenseType">
-          <el-select
-            v-model="form.expenseType"
-            placeholder="璇烽�夋嫨"
-            clearable
-          >
-            <el-option :label="item.label" :value="item.value" v-for="(item,index) in expense_types" :key="index" />
-          </el-select>
-        </el-form-item>
-        <el-form-item label="渚涘簲鍟嗗悕绉�" prop="supplierName">
-          <el-input v-model="form.supplierName" placeholder="璇疯緭鍏�" />
-        </el-form-item>
-        <el-form-item label="鏀嚭閲戦" prop="expenseMoney">
-          <el-input-number :step="0.01" :min="0" style="width: 100%"
-            v-model="form.expenseMoney"
-            placeholder="璇疯緭鍏�"
-          />
-        </el-form-item>
-        <el-form-item label="鏀嚭鎻忚堪" prop="expenseDescribed">
-          <el-input v-model="form.expenseDescribed" placeholder="璇疯緭鍏�" />
-        </el-form-item>
-        <el-form-item label="浠樻鏂瑰紡" prop="expenseMethod">
-          <el-select
-            v-model="form.expenseMethod"
-            placeholder="璇烽�夋嫨"
-            clearable
-          >
-            <el-option :label="item.label" :value="item.value" v-for="(item,index) in checkout_payment" :key="index" />
-          </el-select>
-        </el-form-item>
-        <el-form-item label="鍙戠エ鍙风爜" prop="invoiceNumber">
-          <el-input v-model="form.invoiceNumber" placeholder="璇疯緭鍏�" />
-        </el-form-item>
-        <el-form-item label="澶囨敞" prop="note">
-          <el-input
-            v-model="form.note"
-            placeholder="澶囨敞"
-          />
-        </el-form-item>
-        
-  </el-form>
-</template>
-
-<script setup>
-import useFormData from "@/hooks/useFormData";
-import { getAccountExpense } from "@/api/financialManagement/expenseManagement";
-import {ref} from "vue";
-const { proxy } = getCurrentInstance();
-
-
-defineOptions({
-  name: "鏂板鏀嚭",
-});
-const { expense_types } = proxy.useDict("expense_types");
-const { checkout_payment } = proxy.useDict("checkout_payment");
-const formRef = ref(null);
-const formRules = {
-	supplierName: [{ required: true, trigger: "blur", message: "璇疯緭鍏�" }],
-	expenseMoney: [{ required: true, trigger: "blur", message: "璇疯緭鍏�" }],
-	expenseDescribed: [{ required: true, trigger: "blur", message: "璇疯緭鍏�" }],
-	expenseDate: [{ required: true, trigger: "change", message: "璇烽�夋嫨" }],
-  expenseType: [{ required: true, trigger: "change", message: "璇烽�夋嫨" }],
-  expenseMethod: [{ required: true, trigger: "change", message: "璇烽�夋嫨" }],
-}
-
-const { form, resetForm } = useFormData({
-  expenseDate: undefined, // 鏀嚭鏃ユ湡
-  expenseType: undefined, // 鏀嚭绫诲瀷
-  supplierName: undefined, // 瀹㈡埛鍚嶇О
-  expenseMoney: undefined, // 鏀嚭閲戦
-  expenseDescribed: undefined, // 鏀嚭鎻忚堪
-  expenseMethod: undefined, // 鏀舵鏂瑰紡
-  invoiceNumber: undefined, // 鍙戠エ鍙风爜
-  note: undefined, // 澶囨敞
-});
-
-const loadForm = async (id) => {
-  const { code, data } = await getAccountExpense(id);
-  if (code == 200) {
-    form.expenseDate = data.expenseDate;
-    form.expenseType = data.expenseType;
-    form.supplierName = data.supplierName;
-    form.expenseMoney = data.expenseMoney;
-    form.expenseDescribed = data.expenseDescribed;
-    form.expenseMethod = data.expenseMethod;
-    form.invoiceNumber = data.invoiceNumber;
-    form.note = data.note;
-  }
-};
-
-// 娓呴櫎琛ㄥ崟鏍¢獙鐘舵��
-const clearValidate = () => {
-  formRef.value?.clearValidate();
-};
-
-// 閲嶇疆琛ㄥ崟鏁版嵁鍜屾牎楠岀姸鎬�
-const resetFormAndValidate = () => {
-  resetForm();
-  clearValidate();
-};
-
-defineExpose({
-  form,
-  loadForm,
-  resetForm,
-  clearValidate,
-  resetFormAndValidate,
-	formRef,
-});
-</script>
diff --git a/src/views/financialManagement/expenseManagement/Modal.vue b/src/views/financialManagement/expenseManagement/Modal.vue
index 8e5b171..4d743c1 100644
--- a/src/views/financialManagement/expenseManagement/Modal.vue
+++ b/src/views/financialManagement/expenseManagement/Modal.vue
@@ -1,20 +1,75 @@
 <template>
-  <el-dialog :title="modalOptions.title" v-model="visible" @close="close" width="30%">
-    <Form ref="formRef"></Form>
-    <template #footer>
-			<el-button type="primary" @click="sendForm" :loading="loading">
-				{{ modalOptions.confirmText }}
-			</el-button>
-      <el-button @click="closeModal">{{ modalOptions.cancelText }}</el-button>
-    </template>
-  </el-dialog>
+  <FormDialog
+    v-model="dialogVisible"
+    :title="dialogTitle"
+    :operationType="operationType"
+    width="50%"
+    @confirm="sendForm"
+    @close="close"
+    @cancel="close"
+  >
+    <el-form :model="form" label-width="100px" :rules="formRules" ref="formRef">
+      <el-form-item label="鏀嚭鏃ユ湡" prop="expenseDate">
+        <el-date-picker
+          style="width: 100%"
+          v-model="form.expenseDate"
+          format="YYYY-MM-DD"
+          value-format="YYYY-MM-DD"
+          type="date"
+          placeholder="璇烽�夋嫨鏃ユ湡"
+          clearable
+        />
+      </el-form-item>
+      <el-form-item label="鏀嚭绫诲瀷" prop="expenseType">
+        <el-select
+          v-model="form.expenseType"
+          placeholder="璇烽�夋嫨"
+          clearable
+        >
+          <el-option :label="item.label" :value="item.value" v-for="(item,index) in expense_types" :key="index" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="渚涘簲鍟嗗悕绉�" prop="supplierName">
+        <el-input v-model="form.supplierName" placeholder="璇疯緭鍏�" />
+      </el-form-item>
+      <el-form-item label="鏀嚭閲戦" prop="expenseMoney">
+        <el-input-number :step="0.01" :min="0" style="width: 100%"
+          v-model="form.expenseMoney"
+          placeholder="璇疯緭鍏�"
+        />
+      </el-form-item>
+      <el-form-item label="鏀嚭鎻忚堪" prop="expenseDescribed">
+        <el-input v-model="form.expenseDescribed" placeholder="璇疯緭鍏�" />
+      </el-form-item>
+      <el-form-item label="浠樻鏂瑰紡" prop="expenseMethod">
+        <el-select
+          v-model="form.expenseMethod"
+          placeholder="璇烽�夋嫨"
+          clearable
+        >
+          <el-option :label="item.label" :value="item.value" v-for="(item,index) in checkout_payment" :key="index" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="鍙戠エ鍙风爜" prop="invoiceNumber">
+        <el-input v-model="form.invoiceNumber" placeholder="璇疯緭鍏�" />
+      </el-form-item>
+      <el-form-item label="澶囨敞" prop="note">
+        <el-input
+          v-model="form.note"
+          placeholder="澶囨敞"
+        />
+      </el-form-item>
+    </el-form>
+  </FormDialog>
 </template>
 
 <script setup>
-import { useModal } from "@/hooks/useModal";
-import { add, update } from "@/api/financialManagement/expenseManagement";
-import Form from "./Form.vue";
+import { add, update, getAccountExpense } from "@/api/financialManagement/expenseManagement";
 import { ElMessage } from "element-plus";
+import useFormData from "@/hooks/useFormData";
+import FormDialog from "@/components/Dialog/FormDialog.vue";
+import { ref } from "vue";
+
 const { proxy } = getCurrentInstance()
 
 defineOptions({
@@ -23,43 +78,96 @@
 
 const emits = defineEmits(["success"]);
 
-const formRef = ref();
-const {
-  id,
-  visible,
-  loading,
-  openModal,
-  modalOptions,
-  handleConfirm,
-  closeModal,
-} = useModal({ title: "鏀嚭" });
+const formRef = ref(null);
+const dialogVisible = ref(false);
+const operationType = ref("add"); // add | edit
+const id = ref(undefined);
+const submitting = ref(false);
+
+const dialogTitle = (type) => {
+  if (type === "edit") return "缂栬緫鏀嚭";
+  return "鏂板鏀嚭";
+};
+
+const { expense_types } = proxy.useDict("expense_types");
+const { checkout_payment } = proxy.useDict("checkout_payment");
+
+const formRules = {
+  supplierName: [{ required: true, trigger: "blur", message: "璇疯緭鍏�" }],
+  expenseMoney: [{ required: true, trigger: "blur", message: "璇疯緭鍏�" }],
+  expenseDescribed: [{ required: true, trigger: "blur", message: "璇疯緭鍏�" }],
+  expenseDate: [{ required: true, trigger: "change", message: "璇烽�夋嫨" }],
+  expenseType: [{ required: true, trigger: "change", message: "璇烽�夋嫨" }],
+  expenseMethod: [{ required: true, trigger: "change", message: "璇烽�夋嫨" }],
+}
+
+const { form, resetForm } = useFormData({
+  expenseDate: undefined, // 鏀嚭鏃ユ湡
+  expenseType: undefined, // 鏀嚭绫诲瀷
+  supplierName: undefined, // 渚涘簲鍟嗗悕绉�
+  expenseMoney: undefined, // 鏀嚭閲戦
+  expenseDescribed: undefined, // 鏀嚭鎻忚堪
+  expenseMethod: undefined, // 浠樻鏂瑰紡
+  invoiceNumber: undefined, // 鍙戠エ鍙风爜
+  note: undefined, // 澶囨敞
+});
 
 const sendForm = () => {
-	proxy.$refs.formRef.$refs.formRef.validate(async valid => {
-		if (valid) {
-			const {code} = id.value
-				? await update({id: id.value, ...formRef.value.form})
-				: await add(formRef.value.form);
-			if (code == 200) {
-				emits("success");
-				ElMessage({message: "鎿嶄綔鎴愬姛", type: "success"});
-				close();
-			} else {
-				loading.value = false;
-			}
-		}
-	})
+  if (submitting.value) return;
+  formRef.value?.validate(async (valid) => {
+    if (valid) {
+      submitting.value = true;
+      try {
+        const { code } = id.value
+          ? await update({ id: id.value, ...form })
+          : await add(form);
+        if (code == 200) {
+          emits("success");
+          ElMessage({ message: "鎿嶄綔鎴愬姛", type: "success" });
+          close();
+        }
+      } finally {
+        submitting.value = false;
+      }
+    }
+  })
 };
 
 const close = () => {
-	formRef.value.resetFormAndValidate();
-  closeModal();
+  resetForm();
+  formRef.value?.clearValidate();
+  id.value = undefined;
+  dialogVisible.value = false;
 };
 
-const loadForm = async (id) => {
-  openModal(id);
-  await nextTick();
-  formRef.value.loadForm(id);
+const loadForm = async (rowId) => {
+  operationType.value = "edit";
+  id.value = rowId;
+  dialogVisible.value = true;
+  if (rowId) {
+    const { code, data } = await getAccountExpense(rowId);
+    if (code == 200) {
+      form.expenseDate = data.expenseDate;
+      form.expenseType = data.expenseType;
+      form.supplierName = data.supplierName;
+      form.expenseMoney = data.expenseMoney;
+      form.expenseDescribed = data.expenseDescribed;
+      form.expenseMethod = data.expenseMethod;
+      form.invoiceNumber = data.invoiceNumber;
+      form.note = data.note;
+    }
+  } else {
+    resetForm();
+    formRef.value?.clearValidate();
+  }
+};
+
+const openModal = () => {
+  operationType.value = "add";
+  id.value = undefined;
+  resetForm();
+  formRef.value?.clearValidate();
+  dialogVisible.value = true;
 };
 
 defineExpose({
diff --git a/src/views/financialManagement/expenseManagement/index.vue b/src/views/financialManagement/expenseManagement/index.vue
index a45c32d..801fa1f 100644
--- a/src/views/financialManagement/expenseManagement/index.vue
+++ b/src/views/financialManagement/expenseManagement/index.vue
@@ -34,8 +34,8 @@
           <el-button
             type="danger"
             icon="Delete"
-            :disabled="multipleList.length <= 0"
-            @click="deleteRow(multipleList.map((item) => item.id))"
+            :disabled="multipleList.length <= 0 || hasBusinessIdInSelection"
+            @click="handleBatchDelete"
           >
             鎵归噺鍒犻櫎
           </el-button>
@@ -55,12 +55,17 @@
         @pagination="changePage"
       >
         <template #operation="{ row }">
-          <el-button type="primary" text @click="edit(row.id)" icon="editPen">
+          <el-button 
+            type="primary" 
+            link 
+            :disabled="!!row.businessId"
+            @click="edit(row.id)"
+          >
             缂栬緫
           </el-button>
           <el-button
             type="primary"
-            text
+            link
             @click="openFilesFormDia(row)"
           >
             闄勪欢
@@ -69,18 +74,27 @@
       </PIMTable>
     </div>
     <Modal ref="modalRef" @success="getTableData"></Modal>
-    <files-dia ref="filesDia"></files-dia>
+    <FileListDialog 
+      ref="fileListRef" 
+      v-model="fileListDialogVisible"
+      :show-upload-button="true"
+      :show-delete-button="true"
+      :upload-method="handleUpload"
+      :delete-method="handleFileDelete"
+    />
   </div>
 </template>
 
 <script setup>
 import { usePaginationApi } from "@/hooks/usePaginationApi";
-import { listPage, delAccountExpense } from "@/api/financialManagement/expenseManagement";
-import { onMounted, getCurrentInstance } from "vue";
+import { listPage, delAccountExpense, fileListPage, fileAdd, fileDel } from "@/api/financialManagement/expenseManagement";
+import { onMounted, getCurrentInstance, ref, computed } from "vue";
 import Modal from "./Modal.vue";
 import { ElMessageBox, ElMessage } from "element-plus";
 import dayjs from "dayjs";
-import FilesDia from "../revenueManagement/filesDia.vue";
+import FileListDialog from "@/components/Dialog/FileListDialog.vue";
+import request from "@/utils/request";
+import { getToken } from "@/utils/auth";
 
 defineOptions({
   name: "鏀嚭绠$悊",
@@ -92,7 +106,10 @@
 const modalRef = ref();
 const { checkout_payment } = proxy.useDict("checkout_payment");
 const { expense_types } = proxy.useDict("expense_types");
-const filesDia = ref()
+const fileListRef = ref(null);
+const fileListDialogVisible = ref(false);
+const currentFileRow = ref(null);
+const accountType = ref('鏀嚭');
 
 const {
   filters,
@@ -111,7 +128,6 @@
   [
     {
       label: "鏀嚭鏃ユ湡",
-      align: "center",
       prop: "expenseDate",
     },
     {
@@ -129,19 +145,16 @@
     },
     {
       label: "渚涘簲鍟嗗悕绉�",
-      align: "center",
       prop: "supplierName",
 
     },
     {
       label: "鏀嚭閲戦",
-      align: "center",
       prop: "expenseMoney",
 
     },
     {
       label: "鏀嚭鎻忚堪",
-      align: "center",
       prop: "expenseDescribed",
 
     },
@@ -149,6 +162,7 @@
       label: "浠樻鏂瑰紡",
       align: "center",
       prop: "expenseMethod",
+			width: '120',
       dataType: "tag",
       formatData: (params) => {
         if (checkout_payment.value.find((m) => m.value == params)) {
@@ -160,24 +174,20 @@
     },
     {
       label: "鍙戠エ鍙风爜",
-      align: "center",
       prop: "invoiceNumber",
 
     },
     {
       label: "澶囨敞",
-      align: "center",
       prop: "note",
 
     },
     {
       label: "褰曞叆浜�",
-      align: "center",
       prop: "inputUser",
     },
     {
       label: "褰曞叆鏃ユ湡",
-      align: "center",
       prop: "inputTime",
 
     },
@@ -187,7 +197,7 @@
       dataType: "slot",
       slot: "operation",
       align: "center",
-      width: "200px",
+      width: "160px",
     },
   ]
 );
@@ -197,10 +207,21 @@
   multipleList.value = selectionList;
 };
 
+// 鍒ゆ柇閫変腑鐨勯」涓槸鍚︽湁 businessId
+const hasBusinessIdInSelection = computed(() => {
+  return multipleList.value.some(item => item.businessId);
+});
+
 const add = () => {
   modalRef.value.openModal();
 };
 const edit = (id) => {
+  // 妫�鏌ュ綋鍓嶈鏄惁鏈� businessId
+  const row = dataList.value.find(item => item.id === id);
+  if (row && row.businessId) {
+    proxy.$modal.msgWarning("璇ヨ褰曞凡鍏宠仈涓氬姟锛屼笉鑳界紪杈�");
+    return;
+  }
   modalRef.value.loadForm(id);
 };
 const changePage = ({ page, limit }) => {
@@ -209,6 +230,25 @@
   onCurrentChange(page);
 };
 const deleteRow = (id) => {
+  // 濡傛灉鏄暟缁勶紝妫�鏌ユ槸鍚︽湁 businessId
+  if (Array.isArray(id)) {
+    const hasBusinessId = id.some(itemId => {
+      const row = dataList.value.find(item => item.id === itemId);
+      return row && row.businessId;
+    });
+    if (hasBusinessId) {
+      proxy.$modal.msgWarning("閫変腑鐨勮褰曚腑鍖呭惈宸插叧鑱斾笟鍔$殑璁板綍锛屼笉鑳藉垹闄�");
+      return;
+    }
+  } else {
+    // 鍗曚釜鍒犻櫎锛屾鏌ユ槸鍚︽湁 businessId
+    const row = dataList.value.find(item => item.id === id);
+    if (row && row.businessId) {
+      proxy.$modal.msgWarning("璇ヨ褰曞凡鍏宠仈涓氬姟锛屼笉鑳藉垹闄�");
+      return;
+    }
+  }
+  
   ElMessageBox.confirm("姝ゆ搷浣滃皢姘镐箙鍒犻櫎璇ユ暟鎹�, 鏄惁缁х画?", "鎻愮ず", {
     confirmButtonText: "纭畾",
     cancelButtonText: "鍙栨秷",
@@ -223,6 +263,23 @@
       getTableData();
     }
   });
+};
+
+// 鎵归噺鍒犻櫎
+const handleBatchDelete = () => {
+  if (multipleList.value.length === 0) {
+    proxy.$modal.msgWarning("璇烽�夋嫨瑕佸垹闄ょ殑鏁版嵁");
+    return;
+  }
+  
+  // 妫�鏌ユ槸鍚︽湁 businessId
+  if (hasBusinessIdInSelection.value) {
+    proxy.$modal.msgWarning("閫変腑鐨勮褰曚腑鍖呭惈宸插叧鑱斾笟鍔$殑璁板綍锛屼笉鑳藉垹闄�");
+    return;
+  }
+  
+  const ids = multipleList.value.map((item) => item.id);
+  deleteRow(ids);
 };
 
 const changeDaterange = (value) => {
@@ -252,10 +309,154 @@
     });
 };
 // 鎵撳紑闄勪欢寮规
-const openFilesFormDia = (row) => {
-  nextTick(() => {
-    filesDia.value?.openDialog( row,'鏀嚭')
-  })
+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;
+  }
 };
 
 onMounted(() => {
diff --git a/src/views/financialManagement/financialStatements/index.vue b/src/views/financialManagement/financialStatements/index.vue
index e5f9b23..88aa5d2 100644
--- a/src/views/financialManagement/financialStatements/index.vue
+++ b/src/views/financialManagement/financialStatements/index.vue
@@ -1,16 +1,16 @@
  <template>
   <div style="padding: 20px;">
-    <!-- 椤甸潰鏍囬鍜屾棩鏈熺瓫閫� -->
+    <!-- 椤甸潰鏍囬鍜屾湀浠界瓫閫� -->
     <div class="w-full md:w-auto flex items-center gap-3" style="margin-bottom: 20px;">
       <el-date-picker
         v-model="dateRange"
-        type="daterange"
-        format="YYYY-MM-DD"
-        value-format="YYYY-MM-DD"
+        type="monthrange"
+        format="YYYY-MM"
+        value-format="YYYY-MM"
         range-separator="鑷�"
-        start-placeholder="寮�濮嬫棩鏈�"
-        end-placeholder="缁撴潫鏃ユ湡"
-        clearable
+        start-placeholder="寮�濮嬫湀浠�"
+        end-placeholder="缁撴潫鏈堜唤"
+        :disabled-date="disabledDate"
         @change="handleDateChange"
         class="w-full md:w-auto"
         style="margin-right: 30px;"
@@ -130,7 +130,7 @@
 </template>
 
 <script setup>
-import { ref, computed, onMounted, reactive } from 'vue';
+import { ref, computed, onMounted, reactive, nextTick, getCurrentInstance } from 'vue';
 import 'element-plus/dist/index.css';
 import Echarts from "@/components/Echarts/echarts.vue";
 import { reportForms,reportIncome,reportExpense } from "@/api/financialManagement/financialStatements";
@@ -138,6 +138,7 @@
 
 // 鏃ユ湡鑼冨洿
 const dateRange = ref(null);
+const { proxy } = getCurrentInstance();
 const chartStyle = {
 	width: '100%',
 	height: '100%', // 璁剧疆鍥捐〃瀹瑰櫒鐨勯珮搴�
@@ -172,22 +173,35 @@
     return `<div>${axisLabel}</div><div>${rows}</div>`
   }
 })
-const months = ['1鏈�','2鏈�','3鏈�','4鏈�','5鏈�','6鏈�','7鏈�','8鏈�','9鏈�','10鏈�','11鏈�','12鏈�'];
 const lineSeries0 = ref([])
 const lineSeries1 = ref([])
+
+// 鏍规嵁鏈堜唤鑼冨洿鐢熸垚 x 杞存暟鎹�
+const generateMonthLabels = (startMonth, endMonth) => {
+  const labels = [];
+  let current = dayjs(startMonth);
+  const end = dayjs(endMonth);
+  
+  while (current.isBefore(end) || current.isSame(end, 'month')) {
+    labels.push(`${current.month() + 1}鏈坄);
+    current = current.add(1, 'month');
+  }
+  
+  return labels;
+};
 
 const xAxis0 = ref([
   {
     type: 'category',
     axisTick: { show: true, alignWithLabel: true },
-    data: months,
+    data: [],
   },
 ]);
 const xAxis1 = ref([
   {
     type: 'category',
     axisTick: { show: true, alignWithLabel: true },
-    data: months,
+    data: [],
   },
 ]);
 const yAxis0 = [
@@ -232,9 +246,10 @@
   left: '60%',
   orient: 'vertical',
   icon: 'circle',
-  data: pieData0.value.map(item => item.name),
+  data: (pieData0.value || []).filter(item => item && item.name).map(item => item.name),
   formatter: function(name) {
-    const item = pieData0.value.find(i => i.name === name);
+    if (!name) return '';
+    const item = pieData0.value.find(i => i && i.name === name);
     if (!item) return name;
     return `${name} | ${item.percent} ${item.amount}`;
   },
@@ -250,9 +265,10 @@
   left: '60%',
   orient: 'vertical',
   icon: 'circle',
-  data: pieData1.value.map(item => item.name),
+  data: (pieData1.value || []).filter(item => item && item.name).map(item => item.name),
   formatter: function(name) {
-    const item = pieData1.value.find(i => i.name === name);
+    if (!name) return '';
+    const item = pieData1.value.find(i => i && i.name === name);
     if (!item) return name;
     return `${name} | ${item.percent} ${item.amount}`;
   },
@@ -276,7 +292,7 @@
     label: {
       show: false
     },
-    data: pieData0.value,
+    data: (pieData0.value || []).filter(item => item && item.name),
     color: pieColors
   }
 ]);
@@ -293,7 +309,7 @@
     label: {
       show: false
     },
-    data: pieData1.value,
+    data: (pieData1.value || []).filter(item => item && item.name),
     color: pieColors
   }
 ]);
@@ -318,53 +334,81 @@
 const pageInfo = ref({
 })
 
+// 鑾峰彇鏈�杩戝叚涓湀鐨勮寖鍥�
+const getLastSixMonths = () => {
+  const endMonth = dayjs().format('YYYY-MM');
+  const startMonth = dayjs().subtract(5, 'month').format('YYYY-MM');
+  return [startMonth, endMonth];
+};
+
 const getData = async () => {
-  if (!dateRange.value || !dateRange.value.length) {
+  if (!dateRange.value || !Array.isArray(dateRange.value) || dateRange.value.length !== 2) {
     return;
   }
+  const startDateStr = dateRange.value[0];
+  const endDateStr = dateRange.value[1];
+  if (!startDateStr || !endDateStr) {
+    return;
+  }
+  
+  // 楠岃瘉鏃ユ湡鏍煎紡骞惰浆鎹负瀹屾暣鏃ユ湡
+  const startDate = dayjs(startDateStr);
+  const endDate = dayjs(endDateStr);
+  if (!startDate.isValid() || !endDate.isValid()) {
+    console.error('鏃犳晥鐨勬棩鏈熸牸寮�');
+    return;
+  }
+  
+  // 鏇存柊 x 杞存暟鎹�
+  const monthLabels = generateMonthLabels(startDateStr, endDateStr);
+  xAxis0.value[0].data = monthLabels;
+  xAxis1.value[0].data = monthLabels;
+  
+  // 寮�濮嬫湀浠芥嫾鎺ョ涓�澶╋紝缁撴潫鏈堜唤鎷兼帴鏈�鍚庝竴澶�
+  const entryDateStart = startDate.startOf('month').format('YYYY-MM-DD');
+  const entryDateEnd = endDate.endOf('month').format('YYYY-MM-DD');
+  
   try {
-    const {code,data} = await reportForms({entryDateStart:dateRange.value[0], entryDateEnd:dateRange.value[1]});
-    if(code === 200) {
-      pageInfo.value = data
-      pieData0.value = data.incomeType.map(item=>({
-        name:item.typeName,
-        value:item.account,
-        percent:`${item.proportion*100}%`,
-        amount:`楼${item.account}`
+    const {code,data} = await reportForms({entryDateStart, entryDateEnd});
+    if(code === 200 && data) {
+      pageInfo.value = data || {};
+      // 瀹夊叏澶勭悊鏁版嵁锛岃繃婊ゆ帀 null 鎴� undefined
+      pieData0.value = (data.incomeType || []).filter(item => item && item.typeName).map(item=>({
+        name:item.typeName || '',
+        value:item.account || 0,
+        percent:`${((item.proportion || 0) * 100).toFixed(2)}%`,
+        amount:`楼${(item.account || 0).toFixed(2)}`
       }))
-      pieData1.value = data.expenseType.map(item=>({
-        name:item.typeName,
-        value:item.account,
-        percent:`${item.proportion*100}%`,
-        amount:`楼${item.account}`
+      pieData1.value = (data.expenseType || []).filter(item => item && item.typeName).map(item=>({
+        name:item.typeName || '',
+        value:item.account || 0,
+        percent:`${((item.proportion || 0) * 100).toFixed(2)}%`,
+        amount:`楼${(item.account || 0).toFixed(2)}`
       }))
-
     }
   } catch (error) {
     console.error('鑾峰彇璐㈠姟鎸囨爣鏁版嵁澶辫触锛�', error);
   }
   try{
-    const {code,data} = await reportIncome();
-    if(code==200){
-      lineSeries0.value = data.map(item=>({
-        name:item.typeName,
+    const {code,data} = await reportIncome({entryDateStart, entryDateEnd});
+    if(code==200 && data && Array.isArray(data)){
+      lineSeries0.value = data.filter(item => item && item.typeName).map(item=>({
+        name:item.typeName || '',
         type: 'line',
-        data:item.account.map(item=>Number(item))
+        data:(item.account || []).map(val => Number(val) || 0)
       }))
-
     }
   }catch (error) {
     console.error('鑾峰彇璐㈠姟鎸囨爣鏁版嵁澶辫触锛�', error);
   }
   try{
-    const {code,data} = await reportExpense();
-    if(code==200){
-      lineSeries1.value = data.map(item=>({
-        name:item.typeName,
+    const {code,data} = await reportExpense({entryDateStart, entryDateEnd});
+    if(code==200 && data && Array.isArray(data)){
+      lineSeries1.value = data.filter(item => item && item.typeName).map(item=>({
+        name:item.typeName || '',
         type: 'line',
-        data:item.account.map(item=>Number(item))
+        data:(item.account || []).map(val => Number(val) || 0)
       }))
-
     }
   }catch (error) {
     console.error('鑾峰彇璐㈠姟鎸囨爣鏁版嵁澶辫触锛�', error);
@@ -374,20 +418,66 @@
 
 // 鍒濆鍖�
 onMounted(() => {
-  // 涓嶈缃粯璁ゆ棩鏈燂紝鐢辩敤鎴锋墜鍔ㄩ�夋嫨
+  // 璁剧疆榛樿鍊间负鏈�杩戝叚涓湀
+  const defaultRange = getLastSixMonths();
+  dateRange.value = defaultRange;
+  // 浣跨敤 nextTick 纭繚缁勪欢瀹屽叏娓叉煋鍚庡啀璋冪敤
+  nextTick(() => {
+    getData();
+  });
 });
 
-// 澶勭悊鏃ユ湡鑼冨洿鍙樺寲
-const handleDateChange = (newRange) => {
-  dateRange.value = newRange;
-  if (newRange && newRange.length === 2) {
-    getData()
+// 闄愬埗鏈堜唤閫夋嫨鑼冨洿锛堟渶澶�12涓湀锛�
+const disabledDate = (time) => {
+  // 濡傛灉娌℃湁閫夋嫨寮�濮嬫湀浠斤紝涓嶇鐢ㄤ换浣曟棩鏈�
+  if (!dateRange.value || !Array.isArray(dateRange.value) || !dateRange.value[0]) {
+    return false;
   }
+  
+  const startMonth = dayjs(dateRange.value[0]);
+  const currentMonth = dayjs(time);
+  
+  // 濡傛灉褰撳墠鏈堜唤鍦ㄥ紑濮嬫湀浠戒箣鍓嶏紝绂佺敤
+  if (currentMonth.isBefore(startMonth, 'month')) {
+    return true;
+  }
+  
+  // 璁$畻鏈�澶у厑璁哥殑鏈堜唤锛堝紑濮嬫湀浠� + 11涓湀 = 12涓湀锛�
+  const maxMonth = startMonth.add(11, 'month');
+  
+  // 绂佺敤瓒呰繃12涓湀鐨勬湀浠�
+  return currentMonth.isAfter(maxMonth, 'month');
 };
 
-// 閲嶇疆鏃ユ湡鑼冨洿
+// 澶勭悊鏈堜唤鑼冨洿鍙樺寲
+const handleDateChange = (newRange) => {
+  if (!newRange || !Array.isArray(newRange) || newRange.length !== 2) {
+    return;
+  }
+  
+  // 楠岃瘉鏈堜唤鑼冨洿涓嶈秴杩�12涓湀
+  const startDate = dayjs(newRange[0]);
+  const endDate = dayjs(newRange[1]);
+  const monthDiff = endDate.diff(startDate, 'month');
+  
+  if (monthDiff > 11) {
+    proxy.$modal.msgWarning('鏈�澶氬彧鑳介�夋嫨12涓湀浠�');
+    // 鑷姩璋冩暣涓�12涓湀
+    const adjustedEnd = startDate.add(11, 'month').format('YYYY-MM');
+    dateRange.value = [newRange[0], adjustedEnd];
+    getData();
+    return;
+  }
+  
+  dateRange.value = newRange;
+  getData();
+};
+
+// 閲嶇疆鏈堜唤鑼冨洿
 const resetDateRange = () => {
-  dateRange.value = null;
+  // 閲嶇疆涓烘渶杩戝叚涓湀
+  dateRange.value = getLastSixMonths();
+  getData();
 };
 
 </script>
diff --git a/src/views/financialManagement/loanManagement/index.vue b/src/views/financialManagement/loanManagement/index.vue
index 202313a..7580d3b 100644
--- a/src/views/financialManagement/loanManagement/index.vue
+++ b/src/views/financialManagement/loanManagement/index.vue
@@ -72,7 +72,7 @@
             缂栬緫
           </el-button>
           <el-button
-            v-if="row.status == 1"
+            :disabled="row.status !== 1"
             type="primary"
             link
             @click="repay(row)"
@@ -122,12 +122,10 @@
     {
       label: "鍊熸浜哄鍚�",
       prop: "borrowerName",
-      width: 150,
     },
     {
       label: "鍊熸閲戦锛堝厓锛�",
       prop: "borrowAmount",
-      width: 150,
       formatData: (val) => {
         return val ? `楼${parseFloat(val).toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}` : '楼0.00';
       },
@@ -135,7 +133,6 @@
     {
       label: "鍊熸鍒╃巼锛�%锛�",
       prop: "interestRate",
-      width: 130,
       formatData: (val) => {
         return val ? `${parseFloat(val).toFixed(2)}%` : '-';
       },
@@ -143,18 +140,16 @@
     {
       label: "鍊熸鏃ユ湡",
       prop: "borrowDate",
-      width: 120,
     },
     {
       label: "瀹為檯杩樻鏃ユ湡",
       prop: "repayDate",
-      width: 130,
     },
     {
       label: "鍊熸鐘舵��",
       prop: "status",
-      width: 100,
       dataType: "tag",
+			align: 'center',
       formatData: (params) => {
         if (params == 1) {
           return "寰呰繕娆�";
diff --git a/src/views/financialManagement/revenueManagement/Form.vue b/src/views/financialManagement/revenueManagement/Form.vue
deleted file mode 100644
index 67b175e..0000000
--- a/src/views/financialManagement/revenueManagement/Form.vue
+++ /dev/null
@@ -1,123 +0,0 @@
-<template>
-  <el-form :model="form" label-width="100px" :rules="formRules" ref="formRef">
-    <el-form-item label="鏀跺叆鏃ユ湡" prop="incomeDate">
-          <el-date-picker
-            style="width: 100%"
-            v-model="form.incomeDate"
-            format="YYYY-MM-DD"
-            value-format="YYYY-MM-DD"
-            type="date"
-            placeholder="璇烽�夋嫨鏃ユ湡"
-            clearable
-          />
-        </el-form-item>
-        <el-form-item label="鏀跺叆绫诲瀷" prop="incomeType">
-          <el-select
-            v-model="form.incomeType"
-            placeholder="璇烽�夋嫨"
-            clearable
-          >
-            <el-option :label="item.label" :value="item.value" v-for="(item,index) in income_types" :key="index" />
-          </el-select>
-        </el-form-item>
-        <el-form-item label="瀹㈡埛鍚嶇О" prop="customerName">
-          <el-input v-model="form.customerName" placeholder="璇疯緭鍏�" />
-        </el-form-item>
-        <el-form-item label="鏀跺叆閲戦" prop="incomeMoney">
-          <el-input-number :step="0.01" :min="0" style="width: 100%"
-            v-model="form.incomeMoney"
-            placeholder="璇疯緭鍏�"
-          />
-        </el-form-item>
-        <el-form-item label="鏀跺叆鎻忚堪" prop="incomeDescribed">
-          <el-input v-model="form.incomeDescribed" placeholder="璇疯緭鍏�" />
-        </el-form-item>
-        <el-form-item label="鏀舵鏂瑰紡" prop="incomeMethod">
-          <el-select
-            v-model="form.incomeMethod"
-            placeholder="璇烽�夋嫨"
-            clearable
-          >
-            <el-option :label="item.label" :value="item.value" v-for="(item,index) in payment_methods" :key="index" />
-          </el-select>
-        </el-form-item>
-        <el-form-item label="鍙戠エ鍙风爜" prop="invoiceNumber">
-          <el-input v-model="form.invoiceNumber" placeholder="璇疯緭鍏�" />
-        </el-form-item>
-        <el-form-item label="澶囨敞" prop="note">
-          <el-input
-            v-model="form.note"
-            placeholder="澶囨敞"
-          />
-        </el-form-item>
-        
-  </el-form>
-</template>
-
-<script setup>
-import useFormData from "@/hooks/useFormData";
-import { getAccountIncome } from "@/api/financialManagement/revenueManagement";
-import {ref} from "vue";
-const { proxy } = getCurrentInstance();
-
-
-defineOptions({
-  name: "鏂板鏀跺叆",
-});
-const { income_types } = proxy.useDict("income_types");
-const { payment_methods } = proxy.useDict("payment_methods");
-const formRef = ref(null);
-const formRules = {
-	customerName: [{ required: true, trigger: "blur", message: "璇疯緭鍏�" }],
-	incomeMoney: [{ required: true, trigger: "blur", message: "璇疯緭鍏�" }],
-	incomeDescribed: [{ required: true, trigger: "blur", message: "璇疯緭鍏�" }],
-	incomeDate: [{ required: true, trigger: "change", message: "璇烽�夋嫨" }],
-  incomeType: [{ required: true, trigger: "change", message: "璇烽�夋嫨" }],
-  incomeMethod: [{ required: true, trigger: "change", message: "璇烽�夋嫨" }],
-}
-
-const { form, resetForm } = useFormData({
-  incomeDate: undefined, // 鏀跺叆鏃ユ湡
-  incomeType: undefined, // 鏀跺叆绫诲瀷
-  customerName: undefined, // 瀹㈡埛鍚嶇О
-  incomeMoney: undefined, // 鏀跺叆閲戦
-  incomeDescribed: undefined, // 鏀跺叆鎻忚堪
-  incomeMethod: undefined, // 鏀舵鏂瑰紡
-  invoiceNumber: undefined, // 鍙戠エ鍙风爜
-  note: undefined, // 澶囨敞
-});
-
-const loadForm = async (id) => {
-  const { code, data } = await getAccountIncome(id);
-  if (code == 200) {
-    form.incomeDate = data.incomeDate;
-    form.incomeType = data.incomeType;
-    form.customerName = data.customerName;
-    form.incomeMoney = data.incomeMoney;
-    form.incomeDescribed = data.incomeDescribed;
-    form.incomeMethod = data.incomeMethod;
-    form.invoiceNumber = data.invoiceNumber;
-    form.note = data.note;
-  }
-};
-
-// 娓呴櫎琛ㄥ崟鏍¢獙鐘舵��
-const clearValidate = () => {
-  formRef.value?.clearValidate();
-};
-
-// 閲嶇疆琛ㄥ崟鏁版嵁鍜屾牎楠岀姸鎬�
-const resetFormAndValidate = () => {
-  resetForm();
-  clearValidate();
-};
-
-defineExpose({
-  form,
-  loadForm,
-  resetForm,
-  clearValidate,
-  resetFormAndValidate,
-	formRef,
-});
-</script>
diff --git a/src/views/financialManagement/revenueManagement/Modal.vue b/src/views/financialManagement/revenueManagement/Modal.vue
index 480b4fd..245cdf2 100644
--- a/src/views/financialManagement/revenueManagement/Modal.vue
+++ b/src/views/financialManagement/revenueManagement/Modal.vue
@@ -1,20 +1,75 @@
 <template>
-  <el-dialog :title="modalOptions.title" v-model="visible" @close="close" width="30%">
-    <Form ref="formRef"></Form>
-    <template #footer>
-			<el-button type="primary" @click="sendForm" :loading="loading">
-				{{ modalOptions.confirmText }}
-			</el-button>
-      <el-button @click="closeModal">{{ modalOptions.cancelText }}</el-button>
-    </template>
-  </el-dialog>
+  <FormDialog
+    v-model="dialogVisible"
+    :title="dialogTitle"
+    :operationType="operationType"
+    width="30%"
+    @confirm="sendForm"
+    @close="close"
+    @cancel="close"
+  >
+    <el-form :model="form" label-width="100px" :rules="formRules" ref="formRef">
+      <el-form-item label="鏀跺叆鏃ユ湡" prop="incomeDate">
+        <el-date-picker
+          style="width: 100%"
+          v-model="form.incomeDate"
+          format="YYYY-MM-DD"
+          value-format="YYYY-MM-DD"
+          type="date"
+          placeholder="璇烽�夋嫨鏃ユ湡"
+          clearable
+        />
+      </el-form-item>
+      <el-form-item label="鏀跺叆绫诲瀷" prop="incomeType">
+        <el-select
+          v-model="form.incomeType"
+          placeholder="璇烽�夋嫨"
+          clearable
+        >
+          <el-option :label="item.label" :value="item.value" v-for="(item,index) in income_types" :key="index" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="瀹㈡埛鍚嶇О" prop="customerName">
+        <el-input v-model="form.customerName" placeholder="璇疯緭鍏�" />
+      </el-form-item>
+      <el-form-item label="鏀跺叆閲戦" prop="incomeMoney">
+        <el-input-number :step="0.01" :min="0" style="width: 100%"
+          v-model="form.incomeMoney"
+          placeholder="璇疯緭鍏�"
+        />
+      </el-form-item>
+      <el-form-item label="鏀跺叆鎻忚堪" prop="incomeDescribed">
+        <el-input v-model="form.incomeDescribed" placeholder="璇疯緭鍏�" />
+      </el-form-item>
+      <el-form-item label="鏀舵鏂瑰紡" prop="incomeMethod">
+        <el-select
+          v-model="form.incomeMethod"
+          placeholder="璇烽�夋嫨"
+          clearable
+        >
+          <el-option :label="item.label" :value="item.value" v-for="(item,index) in payment_methods" :key="index" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="鍙戠エ鍙风爜" prop="invoiceNumber">
+        <el-input v-model="form.invoiceNumber" placeholder="璇疯緭鍏�" />
+      </el-form-item>
+      <el-form-item label="澶囨敞" prop="note">
+        <el-input
+          v-model="form.note"
+          placeholder="澶囨敞"
+        />
+      </el-form-item>
+    </el-form>
+  </FormDialog>
 </template>
 
 <script setup>
-import { useModal } from "@/hooks/useModal";
-import { add, update } from "@/api/financialManagement/revenueManagement";
-import Form from "./Form.vue";
+import { add, update, getAccountIncome } from "@/api/financialManagement/revenueManagement";
 import { ElMessage } from "element-plus";
+import useFormData from "@/hooks/useFormData";
+import FormDialog from "@/components/Dialog/FormDialog.vue";
+import { ref } from "vue";
+
 const { proxy } = getCurrentInstance()
 
 defineOptions({
@@ -23,43 +78,96 @@
 
 const emits = defineEmits(["success"]);
 
-const formRef = ref();
-const {
-  id,
-  visible,
-  loading,
-  openModal,
-  modalOptions,
-  handleConfirm,
-  closeModal,
-} = useModal({ title: "鏀跺叆" });
+const formRef = ref(null);
+const dialogVisible = ref(false);
+const operationType = ref("add"); // add | edit
+const id = ref(undefined);
+const submitting = ref(false);
+
+const dialogTitle = (type) => {
+  if (type === "edit") return "缂栬緫鏀跺叆";
+  return "鏂板鏀跺叆";
+};
+
+const { income_types } = proxy.useDict("income_types");
+const { payment_methods } = proxy.useDict("payment_methods");
+
+const formRules = {
+  customerName: [{ required: true, trigger: "blur", message: "璇疯緭鍏�" }],
+  incomeMoney: [{ required: true, trigger: "blur", message: "璇疯緭鍏�" }],
+  incomeDescribed: [{ required: true, trigger: "blur", message: "璇疯緭鍏�" }],
+  incomeDate: [{ required: true, trigger: "change", message: "璇烽�夋嫨" }],
+  incomeType: [{ required: true, trigger: "change", message: "璇烽�夋嫨" }],
+  incomeMethod: [{ required: true, trigger: "change", message: "璇烽�夋嫨" }],
+}
+
+const { form, resetForm } = useFormData({
+  incomeDate: undefined, // 鏀跺叆鏃ユ湡
+  incomeType: undefined, // 鏀跺叆绫诲瀷
+  customerName: undefined, // 瀹㈡埛鍚嶇О
+  incomeMoney: undefined, // 鏀跺叆閲戦
+  incomeDescribed: undefined, // 鏀跺叆鎻忚堪
+  incomeMethod: undefined, // 鏀舵鏂瑰紡
+  invoiceNumber: undefined, // 鍙戠エ鍙风爜
+  note: undefined, // 澶囨敞
+});
 
 const sendForm = () => {
-	proxy.$refs.formRef.$refs.formRef.validate(async valid => {
-		if (valid) {
-			const {code} = id.value
-				? await update({id: id.value, ...formRef.value.form})
-				: await add(formRef.value.form);
-			if (code == 200) {
-				emits("success");
-				ElMessage({message: "鎿嶄綔鎴愬姛", type: "success"});
-				close();
-			} else {
-				loading.value = false;
-			}
-		}
-	})
+  if (submitting.value) return;
+  formRef.value?.validate(async (valid) => {
+    if (valid) {
+      submitting.value = true;
+      try {
+        const { code } = id.value
+          ? await update({ id: id.value, ...form })
+          : await add(form);
+        if (code == 200) {
+          emits("success");
+          ElMessage({ message: "鎿嶄綔鎴愬姛", type: "success" });
+          close();
+        }
+      } finally {
+        submitting.value = false;
+      }
+    }
+  })
 };
 
 const close = () => {
-	formRef.value.resetFormAndValidate();
-  closeModal();
+  resetForm();
+  formRef.value?.clearValidate();
+  id.value = undefined;
+  dialogVisible.value = false;
 };
 
-const loadForm = async (id) => {
-  openModal(id);
-  await nextTick();
-  formRef.value.loadForm(id);
+const loadForm = async (rowId) => {
+  operationType.value = "edit";
+  id.value = rowId;
+  dialogVisible.value = true;
+  if (rowId) {
+    const { code, data } = await getAccountIncome(rowId);
+    if (code == 200) {
+      form.incomeDate = data.incomeDate;
+      form.incomeType = data.incomeType;
+      form.customerName = data.customerName;
+      form.incomeMoney = data.incomeMoney;
+      form.incomeDescribed = data.incomeDescribed;
+      form.incomeMethod = data.incomeMethod;
+      form.invoiceNumber = data.invoiceNumber;
+      form.note = data.note;
+    }
+  } else {
+    resetForm();
+    formRef.value?.clearValidate();
+  }
+};
+
+const openModal = () => {
+  operationType.value = "add";
+  id.value = undefined;
+  resetForm();
+  formRef.value?.clearValidate();
+  dialogVisible.value = true;
 };
 
 defineExpose({
diff --git a/src/views/financialManagement/revenueManagement/filesDia.vue b/src/views/financialManagement/revenueManagement/filesDia.vue
deleted file mode 100644
index f752496..0000000
--- a/src/views/financialManagement/revenueManagement/filesDia.vue
+++ /dev/null
@@ -1,202 +0,0 @@
-<template>
-  <div>
-    <el-dialog
-        v-model="dialogFormVisible"
-        title="涓婁紶闄勪欢"
-        width="50%"
-        @close="closeDia"
-    >
-      <div style="margin-bottom: 10px;text-align: right">
-        <el-upload
-            v-model:file-list="fileList"
-            class="upload-demo"
-            :action="uploadUrl"
-            :on-success="handleUploadSuccess"
-            :on-error="handleUploadError"
-            name="file"
-            :show-file-list="false"
-            :headers="headers"
-            style="display: inline;margin-right: 10px"
-        >
-          <el-button type="primary">涓婁紶闄勪欢</el-button>
-        </el-upload>
-        <el-button type="danger" plain @click="handleDelete">鍒犻櫎</el-button>
-      </div>
-      <PIMTable
-          rowKey="id"
-          :column="tableColumn"
-          :tableData="tableData"
-          :tableLoading="tableLoading"
-          :isSelection="true"
-          @selection-change="handleSelectionChange"
-          height="500"
-      >
-      </PIMTable>
-			<pagination
-				style="margin: 10px 0"
-				v-show="total > 0"
-				@pagination="paginationSearch"
-				:total="total"
-				:page="page.current"
-				:limit="page.size"
-			/>
-      <template #footer>
-        <div class="dialog-footer">
-          <el-button @click="closeDia">鍙栨秷</el-button>
-        </div>
-      </template>
-    </el-dialog>
-    <filePreview ref="filePreviewRef" />
-  </div>
-</template>
-
-<script setup>
-import {ref} from "vue";
-import {ElMessageBox} from "element-plus";
-import {getToken} from "@/utils/auth.js";
-import filePreview from '@/components/filePreview/index.vue'
-import {
-  fileAdd,
-  fileDel,
-  fileListPage
-} from "@/api/financialManagement/revenueManagement.js";
-import Pagination from "@/components/PIMTable/Pagination.vue";
-const { proxy } = getCurrentInstance()
-const emit = defineEmits(['close'])
-
-const dialogFormVisible = ref(false);
-const currentId = ref('')
-const selectedRows = ref([]);
-const filePreviewRef = ref()
-const tableColumn = ref([
-  {
-    label: "鏂囦欢鍚嶇О",
-    prop: "name",
-  },
-  {
-    dataType: "action",
-    label: "鎿嶄綔",
-    align: "center",
-    operation: [
-      {
-        name: "涓嬭浇",
-        type: "text",
-        clickFun: (row) => {
-          downLoadFile(row);
-        },
-      },
-      {
-        name: "棰勮",
-        type: "text",
-        clickFun: (row) => {
-          lookFile(row);
-        },
-      }
-    ],
-  },
-]);
-const page = reactive({
-	current: 1,
-	size: 100,
-});
-const total = ref(0);
-const tableData = ref([]);
-const fileList = ref([]);
-const tableLoading = ref(false);
-const accountType = ref('')
-const headers = ref({
-  Authorization: "Bearer " + getToken(),
-});
-const uploadUrl = ref(import.meta.env.VITE_APP_BASE_API + "/file/upload"); // 涓婁紶鐨勫浘鐗囨湇鍔″櫒鍦板潃
-
-// 鎵撳紑寮规
-const openDialog = (row,type) => {
-  accountType.value = type;
-  dialogFormVisible.value = true;
-  currentId.value = row.id;
-  getList()
-}
-const paginationSearch = (obj) => {
-	page.current = obj.page;
-	page.size = obj.limit;
-	getList();
-};
-const getList = () => {
-  fileListPage({accountId: currentId.value,accountType:accountType.value, ...page}).then(res => {
-    tableData.value = res.data.records;
-		total.value = res.data.total;
-  })
-}
-// 琛ㄦ牸閫夋嫨鏁版嵁
-const handleSelectionChange = (selection) => {
-  selectedRows.value = selection;
-};
-
-// 鍏抽棴寮规
-const closeDia = () => {
-  dialogFormVisible.value = false;
-  emit('close')
-};
-// 涓婁紶鎴愬姛澶勭悊
-function handleUploadSuccess(res, file) {
-  // 濡傛灉涓婁紶鎴愬姛
-  if (res.code == 200) {
-    const fileRow = {}
-    fileRow.name = res.data.originalName
-    fileRow.url = res.data.tempPath
-    uploadFile(fileRow)
-  } else {
-    proxy.$modal.msgError("鏂囦欢涓婁紶澶辫触");
-  }
-}
-function uploadFile(file) {
-  file.accountId = currentId.value;
-  file.accountType = accountType.value;
-  fileAdd(file).then(res => {
-    proxy.$modal.msgSuccess("鏂囦欢涓婁紶鎴愬姛");
-    getList()
-  })
-}
-// 涓婁紶澶辫触澶勭悊
-function handleUploadError() {
-  proxy.$modal.msgError("鏂囦欢涓婁紶澶辫触");
-}
-// 涓嬭浇闄勪欢
-const downLoadFile = (row) => {
-  proxy.$download.name(row.url);
-}
-// 鍒犻櫎
-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(() => {
-    fileDel(ids).then((res) => {
-      proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
-      getList();
-    });
-  }).catch(() => {
-    proxy.$modal.msg("宸插彇娑�");
-  });
-};
-// 棰勮闄勪欢
-const lookFile = (row) => {
-  filePreviewRef.value.open(row.url)
-}
-
-defineExpose({
-  openDialog,
-});
-</script>
-
-<style scoped>
-
-</style>
\ No newline at end of file
diff --git a/src/views/financialManagement/revenueManagement/index.vue b/src/views/financialManagement/revenueManagement/index.vue
index 9dcd23e..a8a59c8 100644
--- a/src/views/financialManagement/revenueManagement/index.vue
+++ b/src/views/financialManagement/revenueManagement/index.vue
@@ -34,8 +34,8 @@
           <el-button
             type="danger"
             icon="Delete"
-            :disabled="multipleList.length <= 0"
-            @click="deleteRow(multipleList.map((item) => item.id))"
+            :disabled="multipleList.length <= 0 || hasBusinessIdInSelection"
+            @click="handleBatchDelete"
           >
             鎵归噺鍒犻櫎
           </el-button>
@@ -55,12 +55,17 @@
         @pagination="changePage"
       >
         <template #operation="{ row }">
-          <el-button type="primary" text @click="edit(row.id)" icon="editPen">
+          <el-button 
+            type="primary" 
+            link 
+            :disabled="!!row.businessId"
+            @click="edit(row.id)"
+          >
             缂栬緫
           </el-button>
           <el-button
             type="primary"
-            text
+						link
             @click="openFilesFormDia(row)"
           >
             闄勪欢
@@ -69,18 +74,27 @@
       </PIMTable>
     </div>
     <Modal ref="modalRef" @success="getTableData"></Modal>
-    <files-dia ref="filesDia"></files-dia>
+    <FileListDialog 
+      ref="fileListRef" 
+      v-model="fileListDialogVisible"
+      :show-upload-button="true"
+      :show-delete-button="true"
+      :upload-method="handleUpload"
+      :delete-method="handleFileDelete"
+    />
   </div>
 </template>
 
 <script setup>
 import { usePaginationApi } from "@/hooks/usePaginationApi";
-import { listPage, delAccountIncome } from "@/api/financialManagement/revenueManagement";
-import { onMounted, getCurrentInstance } from "vue";
+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 dayjs from "dayjs";
-import FilesDia from "./filesDia.vue";
+import FileListDialog from "@/components/Dialog/FileListDialog.vue";
+import request from "@/utils/request";
+import { getToken } from "@/utils/auth";
 
 defineOptions({
   name: "鏀跺叆绠$悊",
@@ -92,7 +106,10 @@
 const modalRef = ref();
 const { payment_methods } = proxy.useDict("payment_methods");
 const { income_types } = proxy.useDict("income_types");
-const filesDia = ref()
+const fileListRef = ref(null);
+const fileListDialogVisible = ref(false);
+const currentFileRow = ref(null);
+const accountType = ref('鏀跺叆');
 
 const {
   filters,
@@ -111,12 +128,10 @@
   [
     {
       label: "鏀跺叆鏃ユ湡",
-      align: "center",
       prop: "incomeDate",
     },
     {
       label: "鏀跺叆绫诲瀷",
-      align: "center",
       prop: "incomeType",
       dataType: "tag",
       formatData: (params) => {
@@ -129,26 +144,25 @@
     },
     {
       label: "瀹㈡埛鍚嶇О",
-      align: "center",
       prop: "customerName",
+			width: '200'
 
     },
     {
       label: "鏀跺叆閲戦",
-      align: "center",
       prop: "incomeMoney",
 
     },
     {
       label: "鏀跺叆鎻忚堪",
-      align: "center",
       prop: "incomeDescribed",
 
     },
     {
       label: "鏀舵鏂瑰紡",
-      align: "center",
       prop: "incomeMethod",
+			align: 'center',
+			width: '100',
       dataType: "tag",
       formatData: (params) => {
         if (payment_methods.value.find((m) => m.value == params)) {
@@ -160,24 +174,20 @@
     },
     {
       label: "鍙戠エ鍙风爜",
-      align: "center",
       prop: "invoiceNumber",
 
     },
     {
       label: "澶囨敞",
-      align: "center",
       prop: "note",
 
     },
     {
       label: "褰曞叆浜�",
-      align: "center",
       prop: "inputUser",
     },
     {
       label: "褰曞叆鏃ユ湡",
-      align: "center",
       prop: "inputTime",
 
     },
@@ -187,7 +197,7 @@
       dataType: "slot",
       slot: "operation",
       align: "center",
-      width: "200px",
+      width: "160px",
     },
   ]
 );
@@ -197,10 +207,21 @@
   multipleList.value = selectionList;
 };
 
+// 鍒ゆ柇閫変腑鐨勯」涓槸鍚︽湁 businessId
+const hasBusinessIdInSelection = computed(() => {
+  return multipleList.value.some(item => item.businessId);
+});
+
 const add = () => {
   modalRef.value.openModal();
 };
 const edit = (id) => {
+  // 妫�鏌ュ綋鍓嶈鏄惁鏈� businessId
+  const row = dataList.value.find(item => item.id === id);
+  if (row && row.businessId) {
+    proxy.$modal.msgWarning("璇ヨ褰曞凡鍏宠仈涓氬姟锛屼笉鑳界紪杈�");
+    return;
+  }
   modalRef.value.loadForm(id);
 };
 const changePage = ({ page, limit }) => {
@@ -209,6 +230,25 @@
   onCurrentChange(page);
 };
 const deleteRow = (id) => {
+  // 濡傛灉鏄暟缁勶紝妫�鏌ユ槸鍚︽湁 businessId
+  if (Array.isArray(id)) {
+    const hasBusinessId = id.some(itemId => {
+      const row = dataList.value.find(item => item.id === itemId);
+      return row && row.businessId;
+    });
+    if (hasBusinessId) {
+      proxy.$modal.msgWarning("閫変腑鐨勮褰曚腑鍖呭惈宸插叧鑱斾笟鍔$殑璁板綍锛屼笉鑳藉垹闄�");
+      return;
+    }
+  } else {
+    // 鍗曚釜鍒犻櫎锛屾鏌ユ槸鍚︽湁 businessId
+    const row = dataList.value.find(item => item.id === id);
+    if (row && row.businessId) {
+      proxy.$modal.msgWarning("璇ヨ褰曞凡鍏宠仈涓氬姟锛屼笉鑳藉垹闄�");
+      return;
+    }
+  }
+  
   ElMessageBox.confirm("姝ゆ搷浣滃皢姘镐箙鍒犻櫎璇ユ暟鎹�, 鏄惁缁х画?", "鎻愮ず", {
     confirmButtonText: "纭畾",
     cancelButtonText: "鍙栨秷",
@@ -223,6 +263,23 @@
       getTableData();
     }
   });
+};
+
+// 鎵归噺鍒犻櫎
+const handleBatchDelete = () => {
+  if (multipleList.value.length === 0) {
+    proxy.$modal.msgWarning("璇烽�夋嫨瑕佸垹闄ょ殑鏁版嵁");
+    return;
+  }
+  
+  // 妫�鏌ユ槸鍚︽湁 businessId
+  if (hasBusinessIdInSelection.value) {
+    proxy.$modal.msgWarning("閫変腑鐨勮褰曚腑鍖呭惈宸插叧鑱斾笟鍔$殑璁板綍锛屼笉鑳藉垹闄�");
+    return;
+  }
+  
+  const ids = multipleList.value.map((item) => item.id);
+  deleteRow(ids);
 };
 
 const changeDaterange = (value) => {
@@ -252,10 +309,154 @@
     });
 };
 // 鎵撳紑闄勪欢寮规
-const openFilesFormDia = (row) => {
-  nextTick(() => {
-    filesDia.value?.openDialog( row,'鏀跺叆')
-  })
+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;
+  }
 };
 
 onMounted(() => {
diff --git a/src/views/procurementManagement/paymentEntry/index.vue b/src/views/procurementManagement/paymentEntry/index.vue
index 89152bf..5ee8d17 100644
--- a/src/views/procurementManagement/paymentEntry/index.vue
+++ b/src/views/procurementManagement/paymentEntry/index.vue
@@ -537,7 +537,7 @@
   })
     .then(() => {
       tableLoading.value = true;
-			delPaymentRegistration(row.id)
+			delPaymentRegistration([row.id])
         .then((res) => {
           proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
           getList();
diff --git a/src/views/procurementManagement/paymentHistory/index.vue b/src/views/procurementManagement/paymentHistory/index.vue
index c38b4b0..179373b 100644
--- a/src/views/procurementManagement/paymentHistory/index.vue
+++ b/src/views/procurementManagement/paymentHistory/index.vue
@@ -43,6 +43,13 @@
           鎼滅储
         </el-button>
         <el-button @click="handleExport">瀵煎嚭</el-button>
+        <el-button
+          type="danger"
+          :disabled="selectedRows.length === 0"
+          @click="handleBatchDelete"
+        >
+          鎵归噺鍒犻櫎 ({{ selectedRows.length }})
+        </el-button>
       </el-form-item>
     </el-form>
     <div class="table_list">
@@ -58,7 +65,18 @@
         :tableLoading="tableLoading"
         @pagination="pagination"
         :total="page.total"
-      ></PIMTable>
+      >
+        <template #operation="{ row }">
+          <el-button
+            type="primary"
+            link
+            size="small"
+            @click="handleDelete(row)"
+          >
+            鍒犻櫎
+          </el-button>
+        </template>
+      </PIMTable>
     </div>
   </div>
 </template>
@@ -66,7 +84,9 @@
 <script setup>
 import { ref, reactive, getCurrentInstance, onMounted } from "vue";
 import { Search } from "@element-plus/icons-vue";
-import { paymentHistoryListPage } from "@/api/procurementManagement/paymentEntry.js";
+import { ElMessageBox } from "element-plus";
+import { paymentHistoryListPage} from "@/api/procurementManagement/paymentEntry.js";
+import {delPaymentRegistration } from "@/api/procurementManagement/procurementInvoiceLedger.js";
 import useFormData from "@/hooks/useFormData";
 import dayjs from "dayjs";
 
@@ -104,6 +124,13 @@
   {
     label: "鐧昏鏃ユ湡",
     prop: "registrationtDate",
+  },
+  {
+    label: "鎿嶄綔",
+    dataType: "slot",
+    slot: "operation",
+    width: 100,
+    align: "center",
   },
 ]);
 const tableData = ref([]);
@@ -170,6 +197,62 @@
   getList();
 };
 
+// 鍒犻櫎
+const handleDelete = (row) => {
+  ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "鍒犻櫎鎻愮ず", {
+    confirmButtonText: "纭",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  })
+    .then(() => {
+      tableLoading.value = true;
+      delPaymentRegistration([row.id])
+        .then((res) => {
+          proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+          getList();
+        })
+        .finally(() => {
+          tableLoading.value = false;
+        });
+    })
+    .catch(() => {
+      proxy.$modal.msg("宸插彇娑�");
+    });
+};
+
+// 鎵归噺鍒犻櫎
+const handleBatchDelete = () => {
+  if (selectedRows.value.length === 0) {
+    proxy.$modal.msgWarning("璇烽�夋嫨瑕佸垹闄ょ殑鏁版嵁");
+    return;
+  }
+  ElMessageBox.confirm(
+    `纭畾瑕佸垹闄ら�変腑鐨� ${selectedRows.value.length} 鏉℃暟鎹悧锛焋,
+    "鍒犻櫎鎻愮ず",
+    {
+      confirmButtonText: "纭",
+      cancelButtonText: "鍙栨秷",
+      type: "warning",
+    }
+  )
+    .then(() => {
+      tableLoading.value = true;
+      const ids = selectedRows.value.map((item) => item.id);
+      delPaymentRegistration(ids)
+        .then((res) => {
+          proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+          selectedRows.value = [];
+          getList();
+        })
+        .finally(() => {
+          tableLoading.value = false;
+        });
+    })
+    .catch(() => {
+      proxy.$modal.msg("宸插彇娑�");
+    });
+};
+
 // 瀵煎嚭
 const handleExport = () => {
   const { paymentDate, ...rest } = searchForm;
diff --git a/src/views/productionManagement/processRoute/Edit.vue b/src/views/productionManagement/processRoute/Edit.vue
index 2ede998..0c0fe0f 100644
--- a/src/views/productionManagement/processRoute/Edit.vue
+++ b/src/views/productionManagement/processRoute/Edit.vue
@@ -8,46 +8,45 @@
     >
       <el-form label-width="140px" :model="formState" label-position="top" ref="formRef">
         <el-form-item
-            label="浜у搧澶х被锛�"
-            prop="productId"
-            :rules="[
-                {
-                required: true,
-                message: '璇烽�夋嫨浜у搧澶х被',
-              }
-            ]"
-        >
-          <el-tree-select
-              v-model="formState.productId"
-              placeholder="璇烽�夋嫨"
-              clearable
-              check-strictly
-              @change="getModels"
-              :data="productOptions"
-              :render-after-expand="false"
-              style="width: 100%"
-          />
-        </el-form-item>
-
-        <el-form-item
-            label="瑙勬牸鍨嬪彿锛�"
+            label="浜у搧鍚嶇О"
             prop="productModelId"
             :rules="[
                 {
                 required: true,
-                message: '璇烽�夋嫨瑙勬牸鍨嬪彿',
+                message: '璇烽�夋嫨浜у搧',
+                trigger: 'change',
+              }
+            ]"
+        >
+          <el-button type="primary" @click="showProductSelectDialog = true">
+            {{ formState.productName && formState.productModelName 
+              ? `${formState.productName} - ${formState.productModelName}` 
+              : '閫夋嫨浜у搧' }}
+          </el-button>
+        </el-form-item>
+
+        <el-form-item
+            label="BOM"
+            prop="bomId"
+            :rules="[
+                {
+                required: true,
+                message: '璇烽�夋嫨BOM',
+                trigger: 'change',
               }
             ]"
         >
           <el-select
-              v-model="formState.productModelId"
-              placeholder="璇烽�夋嫨"
+              v-model="formState.bomId"
+              placeholder="璇烽�夋嫨BOM"
               clearable
+              :disabled="!formState.productModelId || bomOptions.length === 0"
+              style="width: 100%"
           >
             <el-option
-                v-for="item in productModelsOptions"
+                v-for="item in bomOptions"
                 :key="item.id"
-                :label="item.model"
+                :label="item.bomNo || `BOM-${item.id}`"
                 :value="item.id"
             />
           </el-select>
@@ -57,6 +56,13 @@
           <el-input v-model="formState.description" type="textarea" />
         </el-form-item>
       </el-form>
+      
+      <!-- 浜у搧閫夋嫨寮圭獥 -->
+      <ProductSelectDialog
+          v-model="showProductSelectDialog"
+          @confirm="handleProductSelect"
+          single
+      />
       <template #footer>
         <div class="dialog-footer">
           <el-button type="primary" @click="handleSubmit">纭</el-button>
@@ -68,9 +74,10 @@
 </template>
 
 <script setup>
-import {ref, computed, getCurrentInstance, onMounted} from "vue";
+import {ref, computed, getCurrentInstance, onMounted, nextTick, watch} from "vue";
 import {update} from "@/api/productionManagement/processRoute.js";
-import {modelList, productTreeList} from "@/api/basicData/product.js";
+import {getByModel} from "@/api/productionManagement/productBom.js";
+import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue";
 
 const props = defineProps({
   visible: {
@@ -87,7 +94,14 @@
 const emit = defineEmits(['update:visible', 'completed']);
 
 // 鍝嶅簲寮忔暟鎹紙鏇夸唬閫夐」寮忕殑 data锛�
-const formState = ref({});
+const formState = ref({
+  productId: undefined,
+  productModelId: undefined,
+  productName: "",
+  productModelName: "",
+  bomId: undefined,
+  description: '',
+});
 
 const isShow = computed({
   get() {
@@ -98,66 +112,111 @@
   },
 });
 
+const showProductSelectDialog = ref(false);
+const bomOptions = ref([]);
+
 let { proxy } = getCurrentInstance()
-const productModelsOptions = ref([])
-const productOptions = ref([])
 
 const closeModal = () => {
   isShow.value = false;
 };
 
+// 璁剧疆琛ㄥ崟鏁版嵁
 const setFormData = () => {
-  formState.value = props.record
-}
-
-const getProductOptions = () => {
-  productTreeList().then((res) => {
-    productOptions.value = convertIdToValue(res);
-  });
-};
-const getModels = (value) => {
-  formState.value.productModelId = undefined;
-  productModelsOptions.value = [];
-  if (value) {
-    modelList({ id: value }).then((res) => {
-      productModelsOptions.value = res;
-    });
-  }
-};
-
-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 (props.record) {
+    formState.value = {
+      ...props.record,
+      productId: props.record.productId,
+      productModelId: props.record.productModelId,
+      productName: props.record.productName || "",
+      // 娉ㄦ剰锛歳ecord涓殑瀛楁鏄痬odel锛岄渶瑕佹槧灏勫埌productModelName
+      productModelName: props.record.model || props.record.productModelName || "",
+      bomId: props.record.bomId,
+      description: props.record.description || '',
     };
-    if (children && children.length > 0) {
-      newItem.children = convertIdToValue(children);
+    // 濡傛灉鏈変骇鍝佸瀷鍙稩D锛屽姞杞紹OM鍒楄〃
+    if (props.record.productModelId) {
+      loadBomList(props.record.productModelId);
     }
-
-    return newItem;
-  });
+  }
 }
+
+// 鍔犺浇BOM鍒楄〃
+const loadBomList = async (productModelId) => {
+  if (!productModelId) {
+    bomOptions.value = [];
+    return;
+  }
+  try {
+    const res = await getByModel(productModelId);
+    // 澶勭悊杩斿洖鐨凚OM鏁版嵁锛氬彲鑳芥槸鏁扮粍銆佸璞℃垨鍖呭惈data瀛楁
+    let bomList = [];
+    if (Array.isArray(res)) {
+      bomList = res;
+    } else if (res && res.data) {
+      bomList = Array.isArray(res.data) ? res.data : [res.data];
+    } else if (res && typeof res === 'object') {
+      bomList = [res];
+    }
+    bomOptions.value = bomList;
+  } catch (error) {
+    console.error("鍔犺浇BOM鍒楄〃澶辫触锛�", error);
+    bomOptions.value = [];
+  }
+};
+
+// 浜у搧閫夋嫨澶勭悊
+const handleProductSelect = async (products) => {
+  if (products && products.length > 0) {
+    const product = products[0];
+    // 鍏堟煡璇OM鍒楄〃锛堝繀閫夛級
+    try {
+      const res = await getByModel(product.id);
+      // 澶勭悊杩斿洖鐨凚OM鏁版嵁锛氬彲鑳芥槸鏁扮粍銆佸璞℃垨鍖呭惈data瀛楁
+      let bomList = [];
+      if (Array.isArray(res)) {
+        bomList = res;
+      } else if (res && res.data) {
+        bomList = Array.isArray(res.data) ? res.data : [res.data];
+      } else if (res && typeof res === 'object') {
+        bomList = [res];
+      }
+      
+      if (bomList.length > 0) {
+        formState.value.productModelId = product.id;
+        formState.value.productName = product.productName;
+        formState.value.productModelName = product.model;
+        // 濡傛灉褰撳墠閫夋嫨鐨凚OM涓嶅湪鏂板垪琛ㄤ腑锛屽垯閲嶇疆BOM閫夋嫨
+        const currentBomExists = bomList.some(bom => bom.id === formState.value.bomId);
+        if (!currentBomExists) {
+          formState.value.bomId = undefined;
+        }
+        bomOptions.value = bomList;
+        showProductSelectDialog.value = false;
+        // 瑙﹀彂琛ㄥ崟楠岃瘉鏇存柊
+        proxy.$refs["formRef"]?.validateField('productModelId');
+      } else {
+        proxy.$modal.msgError("璇ヤ骇鍝佹病鏈塀OM锛岃鍏堝垱寤築OM");
+      }
+    } catch (error) {
+      // 濡傛灉鎺ュ彛杩斿洖404鎴栧叾浠栭敊璇紝璇存槑娌℃湁BOM
+      proxy.$modal.msgError("璇ヤ骇鍝佹病鏈塀OM锛岃鍏堝垱寤築OM");
+    }
+  }
+};
 
 const handleSubmit = () => {
   proxy.$refs["formRef"].validate(valid => {
     if (valid) {
+      // 楠岃瘉鏄惁閫夋嫨浜嗕骇鍝佸拰BOM
+      if (!formState.value.productModelId) {
+        proxy.$modal.msgError("璇烽�夋嫨浜у搧");
+        return;
+      }
+      if (!formState.value.bomId) {
+        proxy.$modal.msgError("璇烽�夋嫨BOM");
+        return;
+      }
       update(formState.value).then(res => {
         // 鍏抽棴妯℃�佹
         isShow.value = false;
@@ -176,11 +235,18 @@
 });
 
 
+// 鐩戝惉寮圭獥鎵撳紑锛屽垵濮嬪寲琛ㄥ崟鏁版嵁
+watch(() => props.visible, (visible) => {
+  if (visible && props.record) {
+    nextTick(() => {
+      setFormData();
+    });
+  }
+}, { immediate: true });
+
 onMounted(() => {
-  getProductOptions()
-  getModels(props.record.productId)
-  nextTick(() => {
-    setFormData()
-  });
-})
+  if (props.visible && props.record) {
+    setFormData();
+  }
+});
 </script>
diff --git a/src/views/productionManagement/processRoute/New.vue b/src/views/productionManagement/processRoute/New.vue
index 856a2a4..62c6873 100644
--- a/src/views/productionManagement/processRoute/New.vue
+++ b/src/views/productionManagement/processRoute/New.vue
@@ -8,46 +8,45 @@
     >
       <el-form label-width="140px" :model="formState" label-position="top" ref="formRef">
         <el-form-item
-            label="浜у搧澶х被锛�"
-            prop="productId"
-            :rules="[
-                {
-                required: true,
-                message: '璇烽�夋嫨浜у搧澶х被',
-              }
-            ]"
-        >
-          <el-tree-select
-              v-model="formState.productId"
-              placeholder="璇烽�夋嫨"
-              clearable
-              check-strictly
-              @change="getModels"
-              :data="productOptions"
-              :render-after-expand="false"
-              style="width: 100%"
-          />
-        </el-form-item>
-
-        <el-form-item
-            label="瑙勬牸鍨嬪彿锛�"
+            label="浜у搧鍚嶇О"
             prop="productModelId"
             :rules="[
                 {
                 required: true,
-                message: '璇烽�夋嫨瑙勬牸鍨嬪彿',
+                message: '璇烽�夋嫨浜у搧',
+                trigger: 'change',
+              }
+            ]"
+        >
+          <el-button type="primary" @click="showProductSelectDialog = true">
+            {{ formState.productName && formState.productModelName 
+              ? `${formState.productName} - ${formState.productModelName}` 
+              : '閫夋嫨浜у搧' }}
+          </el-button>
+        </el-form-item>
+
+        <el-form-item
+            label="BOM"
+            prop="bomId"
+            :rules="[
+                {
+                required: true,
+                message: '璇烽�夋嫨BOM',
+                trigger: 'change',
               }
             ]"
         >
           <el-select
-              v-model="formState.productModelId"
-              placeholder="璇烽�夋嫨"
+              v-model="formState.bomId"
+              placeholder="璇烽�夋嫨BOM"
               clearable
+              :disabled="!formState.productModelId || bomOptions.length === 0"
+              style="width: 100%"
           >
             <el-option
-                v-for="item in productModelsOptions"
+                v-for="item in bomOptions"
                 :key="item.id"
-                :label="item.model"
+                :label="item.bomNo || `BOM-${item.id}`"
                 :value="item.id"
             />
           </el-select>
@@ -57,6 +56,13 @@
           <el-input v-model="formState.description" type="textarea" />
         </el-form-item>
       </el-form>
+      
+      <!-- 浜у搧閫夋嫨寮圭獥 -->
+      <ProductSelectDialog
+          v-model="showProductSelectDialog"
+          @confirm="handleProductSelect"
+          single
+      />
       <template #footer>
         <div class="dialog-footer">
           <el-button type="primary" @click="handleSubmit">纭</el-button>
@@ -68,9 +74,10 @@
 </template>
 
 <script setup>
-import {ref, computed, getCurrentInstance, onMounted} from "vue";
+import {ref, computed, getCurrentInstance} from "vue";
 import {add} from "@/api/productionManagement/processRoute.js";
-import {modelList, productTreeList} from "@/api/basicData/product.js";
+import {getByModel} from "@/api/productionManagement/productBom.js";
+import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue";
 
 const props = defineProps({
   visible: {
@@ -85,6 +92,9 @@
 const formState = ref({
   productId: undefined,
   productModelId: undefined,
+  productName: "",
+  productModelName: "",
+  bomId: undefined,
   description: '',
 });
 
@@ -97,66 +107,73 @@
   },
 });
 
-const productModelsOptions = ref([])
-const productOptions = ref([])
+const showProductSelectDialog = ref(false);
+const bomOptions = ref([]);
 
 let { proxy } = getCurrentInstance()
 
 const closeModal = () => {
+  // 閲嶇疆琛ㄥ崟鏁版嵁
+  formState.value = {
+    productId: undefined,
+    productModelId: undefined,
+    productName: "",
+    productModelName: "",
+    bomId: undefined,
+    description: '',
+  };
+  bomOptions.value = [];
   isShow.value = false;
 };
 
-const getProductOptions = () => {
-  productTreeList().then((res) => {
-    productOptions.value = convertIdToValue(res);
-  });
-};
-const getModels = (value) => {
-  formState.value.productId = undefined;
-  formState.value.productModelId = undefined;
-  productModelsOptions.value = [];
-
-  if (value) {
-    formState.value.productId = findNodeById(productOptions.value, value) || undefined;
-    modelList({ id: value }).then((res) => {
-      productModelsOptions.value = res;
-    });
-  }
-};
-
-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瀛楃涓诧級
+// 浜у搧閫夋嫨澶勭悊
+const handleProductSelect = async (products) => {
+  if (products && products.length > 0) {
+    const product = products[0];
+    // 鍏堟煡璇OM鍒楄〃锛堝繀閫夛級
+    try {
+      const res = await getByModel(product.id);
+      // 澶勭悊杩斿洖鐨凚OM鏁版嵁锛氬彲鑳芥槸鏁扮粍銆佸璞℃垨鍖呭惈data瀛楁
+      let bomList = [];
+      if (Array.isArray(res)) {
+        bomList = res;
+      } else if (res && res.data) {
+        bomList = Array.isArray(res.data) ? res.data : [res.data];
+      } else if (res && typeof res === 'object') {
+        bomList = [res];
       }
+      
+      if (bomList.length > 0) {
+        formState.value.productModelId = product.id;
+        formState.value.productName = product.productName;
+        formState.value.productModelName = product.model;
+        formState.value.bomId = undefined; // 閲嶇疆BOM閫夋嫨
+        bomOptions.value = bomList;
+        showProductSelectDialog.value = false;
+        // 瑙﹀彂琛ㄥ崟楠岃瘉鏇存柊
+        proxy.$refs["formRef"]?.validateField('productModelId');
+      } else {
+        proxy.$modal.msgError("璇ヤ骇鍝佹病鏈塀OM锛岃鍏堝垱寤築OM");
+      }
+    } catch (error) {
+      // 濡傛灉鎺ュ彛杩斿洖404鎴栧叾浠栭敊璇紝璇存槑娌℃湁BOM
+      proxy.$modal.msgError("璇ヤ骇鍝佹病鏈塀OM锛岃鍏堝垱寤築OM");
     }
   }
-  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 handleSubmit = () => {
   proxy.$refs["formRef"].validate(valid => {
     if (valid) {
+      // 楠岃瘉鏄惁閫夋嫨浜嗕骇鍝佸拰BOM
+      if (!formState.value.productModelId) {
+        proxy.$modal.msgError("璇烽�夋嫨浜у搧");
+        return;
+      }
+      if (!formState.value.bomId) {
+        proxy.$modal.msgError("璇烽�夋嫨BOM");
+        return;
+      }
       add(formState.value).then(res => {
         // 鍏抽棴妯℃�佹
         isShow.value = false;
@@ -174,8 +191,4 @@
   handleSubmit,
   isShow,
 });
-
-onMounted(() => {
-  getProductOptions()
-})
 </script>
diff --git a/src/views/productionManagement/processRoute/index.vue b/src/views/productionManagement/processRoute/index.vue
index 7d5ab5d..41103f9 100644
--- a/src/views/productionManagement/processRoute/index.vue
+++ b/src/views/productionManagement/processRoute/index.vue
@@ -80,6 +80,10 @@
     prop: "model",
   },
   {
+    label: "BOM缂栧彿",
+    prop: "bomNo",
+  },
+  {
     label: "鎻忚堪",
     prop: "description",
   },
@@ -166,7 +170,13 @@
   router.push({
     path: '/productionManagement/processRouteItem',
     query: {
-      id: row.id
+      id: row.id,
+      processRouteCode: row.processRouteCode || '',
+      productName: row.productName || '',
+      model: row.model || '',
+      bomNo: row.bomNo || '',
+      description: row.description || '',
+      type: 'route',
     }
   })
 };
diff --git a/src/views/productionManagement/processRoute/processRouteItem/index.vue b/src/views/productionManagement/processRoute/processRouteItem/index.vue
index 641ffff..18e21e8 100644
--- a/src/views/productionManagement/processRoute/processRouteItem/index.vue
+++ b/src/views/productionManagement/processRoute/processRouteItem/index.vue
@@ -1,133 +1,207 @@
 <template>
   <div class="app-container">
-    <div class="operate-button">
-      <div style="margin-bottom: 15px;">
-        <el-button
-            type="primary"
-            @click="isShowProductSelectDialog = true"
-        >
-          閫夋嫨浜у搧
-        </el-button>
-        <el-button type="primary" @click="handleSubmit">纭</el-button>
+    <PageHeader content="宸ヨ壓璺嚎椤圭洰" />
+    
+    <!-- 宸ヨ壓璺嚎淇℃伅灞曠ず -->
+    <el-card v-if="routeInfo.processRouteCode" class="route-info-card" shadow="hover">
+      <div class="route-info">
+        <div class="info-item">
+          <div class="info-label-wrapper">
+            <span class="info-label">宸ヨ壓璺嚎缂栧彿</span>
+          </div>
+          <div class="info-value-wrapper">
+            <span class="info-value">{{ routeInfo.processRouteCode }}</span>
+          </div>
+        </div>
+        <div class="info-item">
+          <div class="info-label-wrapper">
+            <span class="info-label">浜у搧鍚嶇О</span>
+          </div>
+          <div class="info-value-wrapper">
+            <span class="info-value">{{ routeInfo.productName || '-' }}</span>
+          </div>
+        </div>
+        <div class="info-item">
+          <div class="info-label-wrapper">
+            <span class="info-label">瑙勬牸鍚嶇О</span>
+          </div>
+          <div class="info-value-wrapper">
+            <span class="info-value">{{ routeInfo.model || '-' }}</span>
+          </div>
+        </div>
+        <div class="info-item">
+          <div class="info-label-wrapper">
+            <span class="info-label">BOM缂栧彿</span>
+          </div>
+          <div class="info-value-wrapper">
+            <span class="info-value">{{ routeInfo.bomNo || '-' }}</span>
+          </div>
+        </div>
+        <div class="info-item full-width" v-if="routeInfo.description">
+          <div class="info-label-wrapper">
+            <span class="info-label">鎻忚堪</span>
+          </div>
+          <div class="info-value-wrapper">
+            <span class="info-value">{{ routeInfo.description }}</span>
+          </div>
+        </div>
       </div>
-
-      <el-switch
-          v-model="isTable"
-          inline-prompt
-          active-text="琛ㄦ牸"
-          inactive-text="鍒楄〃"
-          @change="handleViewChange"
-      />
+    </el-card>
+    
+    <!-- 琛ㄦ牸瑙嗗浘 -->
+    <div v-if="viewMode === 'table'" class="section-header">
+      <div class="section-title">宸ヨ壓璺嚎椤圭洰鍒楄〃</div>
+      <div class="section-actions">
+        <el-button 
+            icon="Grid" 
+            @click="toggleView"
+            style="margin-right: 10px;"
+        >
+          鍗$墖瑙嗗浘
+        </el-button>
+        <el-button type="primary" @click="handleAdd">鏂板</el-button>
+      </div>
     </div>
     <el-table
-        v-if="isTable"
-        ref="multipleTable"
+        v-if="viewMode === 'table'"
+        ref="tableRef"
         v-loading="tableLoading"
         border
-        :data="routeItems"
+        :data="tableData"
         :header-cell-style="{ background: '#F0F1F5', color: '#333333' }"
         row-key="id"
         tooltip-effect="dark"
         class="lims-table"
-        style="cursor: move;"
     >
-      <el-table-column align="center" label="搴忓彿" width="60">
+      <el-table-column align="center" label="搴忓彿" width="60" type="index" />
+      <el-table-column label="宸ュ簭鍚嶇О" prop="processId" width="200">
         <template #default="scope">
-          {{ scope.$index + 1 }}
+          {{ getProcessName(scope.row.processId) || '-' }}
         </template>
       </el-table-column>
-
-      <el-table-column
-          v-for="(item, index) in tableColumn"
-          :key="index"
-          :label="item.label"
-          :width="item.width"
-          show-overflow-tooltip
-      >
-        <template #default="scope" v-if="item.dataType === 'action'">
-          <el-button
-              v-for="(op, opIndex) in item.operation"
-              :key="opIndex"
-              :type="op.type"
-              :link="op.link"
-              size="small"
-              @click.stop="op.clickFun(scope.row)"
-          >
-            {{ op.name }}
-          </el-button>
-        </template>
-
-        <template #default="scope" v-else>
-          <template v-if="item.prop === 'processId'">
-            <el-select
-                v-model="scope.row[item.prop]"
-                style="width: 100%;"
-                @mousedown.stop
-            >
-              <el-option
-                  v-for="process in processOptions"
-                  :key="process.id"
-                  :label="process.name"
-                  :value="process.id"
-              />
-            </el-select>
-          </template>
-          <template v-else>
-            {{ scope.row[item.prop] || '-' }}
-          </template>
+      <el-table-column label="浜у搧鍚嶇О" prop="productName" min-width="160" />
+      <el-table-column label="瑙勬牸鍚嶇О" prop="model" min-width="140" />
+      <el-table-column label="鍗曚綅" prop="unit" width="100" />
+      <el-table-column label="鎿嶄綔" align="center" fixed="right" width="150">
+        <template #default="scope">
+          <el-button type="primary" link size="small" @click="handleEdit(scope.row)">缂栬緫</el-button>
+          <el-button type="danger" link size="small" @click="handleDelete(scope.row)">鍒犻櫎</el-button>
         </template>
       </el-table-column>
     </el-table>
-
-    <!-- 浣跨敤鏅�歞iv鏇夸唬el-steps -->
-    <div
-        v-else
-        ref="stepsContainer"
-        class="mb5 custom-steps"
-    >
-      <div
-          v-for="(item, index) in routeItems"
-          :key="item.id"
-          class="custom-step draggable-step"
-          :data-id="item.id"
-          style="cursor: move; flex: 0 0 auto; min-width: 220px;"
-      >
-        <div class="step-content">
-          <div class="step-number">{{ index + 1 }}</div>
-          <el-card
-              :header="item.productName"
-              class="step-card"
-              style="cursor: move;"
+    
+    <!-- 鍗$墖瑙嗗浘 -->
+    <template v-else>
+      <div class="section-header">
+        <div class="section-title">宸ヨ壓璺嚎椤圭洰鍒楄〃</div>
+        <div class="section-actions">
+          <el-button 
+              icon="Menu" 
+              @click="toggleView"
+              style="margin-right: 10px;"
           >
-            <div class="step-card-content">
-              <p>{{ item.model }}</p>
-              <p>{{ item.unit }}</p>
-              <el-select
-                  v-model="item.processId"
-                  style="width: 100%;"
-                  @mousedown.stop
-              >
-                <el-option
-                    v-for="process in processOptions"
-                    :key="process.id"
-                    :label="process.name"
-                    :value="process.id"
-                />
-              </el-select>
-            </div>
-            <template #footer>
-              <div class="step-card-footer">
-                <el-button type="danger" link size="small" @click.stop="removeItemByID(item.id)">鍒犻櫎</el-button>
-              </div>
-            </template>
-          </el-card>
+            琛ㄦ牸瑙嗗浘
+          </el-button>
+          <el-button type="primary" @click="handleAdd">鏂板</el-button>
         </div>
       </div>
-    </div>
+      <div v-loading="tableLoading" class="card-container">
+        <div 
+            ref="cardsContainer" 
+            class="cards-wrapper"
+        >
+        <div
+            v-for="(item, index) in tableData"
+            :key="item.id || index"
+            class="process-card"
+            :data-index="index"
+        >
+          <!-- 搴忓彿鍦嗗湀 -->
+          <div class="card-header">
+            <div class="card-number">{{ index + 1 }}</div>
+            <div class="card-process-name">{{ getProcessName(item.processId) || '-' }}</div>
+          </div>
+          
+          <!-- 浜у搧淇℃伅 -->
+          <div class="card-content">
+            <div v-if="item.productName" class="product-info">
+              <div class="product-name">{{ item.productName }}</div>
+              <div v-if="item.model" class="product-model">
+                {{ item.model }}
+                <!-- <span v-if="item.unit" class="product-unit">{{ item.unit }}</span> -->
+              </div>
+            </div>
+            <div v-else class="product-info empty">鏆傛棤浜у搧淇℃伅</div>
+          </div>
+          
+          <!-- 鎿嶄綔鎸夐挳 -->
+          <div class="card-footer">
+            <el-button type="primary" link size="small" @click="handleEdit(item)">缂栬緫</el-button>
+            <el-button type="danger" link size="small" @click="handleDelete(item)">鍒犻櫎</el-button>
+          </div>
+        </div>
+      </div>
+      </div>
+    </template>
 
+    <!-- 鏂板/缂栬緫寮圭獥 -->
+    <el-dialog
+        v-model="dialogVisible"
+        :title="operationType === 'add' ? '鏂板宸ヨ壓璺嚎椤圭洰' : '缂栬緫宸ヨ壓璺嚎椤圭洰'"
+        width="500px"
+        @close="closeDialog"
+    >
+      <el-form
+          ref="formRef"
+          :model="form"
+          :rules="rules"
+          label-width="120px"
+      >
+        <el-form-item label="宸ュ簭" prop="processId">
+          <el-select
+              v-model="form.processId"
+              placeholder="璇烽�夋嫨宸ュ簭"
+              clearable
+              style="width: 100%"
+          >
+            <el-option
+                v-for="process in processOptions"
+                :key="process.id"
+                :label="process.name"
+                :value="process.id"
+            />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item label="浜у搧鍚嶇О" prop="productModelId">
+          <el-button type="primary" @click="showProductSelectDialog = true">
+            {{ form.productName && form.model 
+              ? `${form.productName} - ${form.model}` 
+              : '閫夋嫨浜у搧' }}
+          </el-button>
+        </el-form-item>
+
+        <el-form-item label="鍗曚綅" prop="unit">
+          <el-input 
+              v-model="form.unit" 
+              :placeholder="form.productModelId ? '鏍规嵁閫夋嫨鐨勪骇鍝佽嚜鍔ㄥ甫鍑�' : '璇峰厛閫夋嫨浜у搧'" 
+              clearable 
+              :disabled="true" 
+          />
+        </el-form-item>
+      </el-form>
+
+      <template #footer>
+        <el-button @click="closeDialog">鍙栨秷</el-button>
+        <el-button type="primary" @click="handleSubmit" :loading="submitLoading">纭畾</el-button>
+      </template>
+    </el-dialog>
+
+    <!-- 浜у搧閫夋嫨瀵硅瘽妗� -->
     <ProductSelectDialog
-        v-model="isShowProductSelectDialog"
-        @confirm="handelSelectProducts"
+        v-model="showProductSelectDialog"
+        @confirm="handleProductSelect"
+        single
     />
   </div>
 </template>
@@ -135,178 +209,285 @@
 <script setup>
 import { ref, computed, getCurrentInstance, onMounted, onUnmounted, nextTick } from "vue";
 import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue";
-import { findProcessRouteItemList, addOrUpdateProcessRouteItem } from "@/api/productionManagement/processRouteItem.js";
+import { findProcessRouteItemList, addOrUpdateProcessRouteItem, sortProcessRouteItem, batchDeleteProcessRouteItem } from "@/api/productionManagement/processRouteItem.js";
+import { findProductProcessRouteItemList, deleteRouteItem, addRouteItem, addOrUpdateProductProcessRouteItem, sortRouteItem } from "@/api/productionManagement/productProcessRoute.js";
 import { processList } from "@/api/productionManagement/productionProcess.js";
-import Sortable from 'sortablejs';
-import { useRoute, useRouter } from 'vue-router'
-
-const processOptions = ref([]);
-const tableLoading = ref(false);
-const isShowProductSelectDialog = ref(false);
-const routeItems = ref([]);
-let tableSortable = null;
-let stepsSortable = null;
-const multipleTable = ref(null);
-const stepsContainer = ref(null);
-const isTable = ref(true);
+import { useRoute } from 'vue-router'
+import { ElMessageBox } from 'element-plus'
+import Sortable from 'sortablejs'
 
 const route = useRoute()
-const router = useRouter()
-const routeId = computed({
-  get() {
-    return route.query.id;
-  },
+const { proxy } = getCurrentInstance() || {};
 
-  set(val) {
-    emit('update:router', val)
-  }
+const routeId = computed(() => route.query.id);
+const orderId = computed(() => route.query.orderId);
+const pageType = computed(() => route.query.type);
+
+const tableLoading = ref(false);
+const tableData = ref([]);
+const dialogVisible = ref(false);
+const operationType = ref('add'); // add | edit
+const formRef = ref(null);
+const submitLoading = ref(false);
+const cardsContainer = ref(null);
+const tableRef = ref(null);
+const viewMode = ref('table'); // table | card
+const routeInfo = ref({
+  processRouteCode: '',
+  productName: '',
+  model: '',
+  bomNo: '',
+  description: ''
 });
 
+const processOptions = ref([]);
+const showProductSelectDialog = ref(false);
+let tableSortable = null;
+let cardSortable = null;
 
-const tableColumn = ref([
-  { label: "浜у搧鍚嶇О", prop: "productName"},
-  { label: "瑙勬牸鍚嶇О", prop: "model" },
-  { label: "鍗曚綅", prop: "unit" },
-  { label: "宸ュ簭鍚嶇О", prop: "processId", width: 200 },
-  {
-    dataType: "action",
-    label: "鎿嶄綔",
-    align: "center",
-    fixed: "right",
-    width: 100,
-    operation: [
-      {
-        name: "鍒犻櫎",
-        type: "danger",
-        link: true,
-        clickFun: (row) => {
-          const idx = routeItems.value.findIndex(item => item.id === row.id);
-          if (idx > -1) {
-            removeItem(idx)
-          }
-        }
-      }
-    ]
-  }
-]);
-
-const removeItem = (index) => {
-  routeItems.value.splice(index, 1);
-  nextTick(() => initSortable());
-};
-
-const removeItemByID = (id) => {
-  const idx = routeItems.value.findIndex(item => item.id === id);
-  if (idx > -1) {
-    routeItems.value.splice(idx, 1);
-    nextTick(() => initSortable());
-  }
-};
-
-const handelSelectProducts = (products) => {
-  destroySortable();
-
-  const newData = products.map(({ id, ...product }) => ({
-    ...product,
-    productModelId: id,
-    routeId: routeId.value,
-    id: `${Date.now()}-${Math.random().toString(36).slice(2)}`,
-    processId: undefined
-  }));
-
-  console.log('閫夋嫨浜у搧鍓嶆暟缁�:', routeItems.value);
-  routeItems.value.push(...newData);
-  routeItems.value = [...routeItems.value];
-  console.log('閫夋嫨浜у搧鍚庢暟缁�:', routeItems.value);
-
-  // 寤惰繜鍒濆鍖栵紝纭繚DOM瀹屽叏娓叉煋
+// 鍒囨崲瑙嗗浘
+const toggleView = () => {
+  viewMode.value = viewMode.value === 'table' ? 'card' : 'table';
+  // 鍒囨崲瑙嗗浘鍚庨噸鏂板垵濮嬪寲鎷栨嫿鎺掑簭
   nextTick(() => {
-    // 寮哄埗閲嶆柊娓叉煋缁勪欢
-    if (proxy?.$forceUpdate) {
-      proxy.$forceUpdate();
-    }
-
-    const temp = [...routeItems.value];
-    routeItems.value = [];
-    nextTick(() => {
-      routeItems.value = temp;
-      initSortable();
-    });
+    initSortable();
   });
 };
 
-const findProcessRouteItems = () => {
+const form = ref({
+  id: undefined,
+  routeId: routeId.value,
+  processId: undefined,
+  productModelId: undefined,
+  productName: "",
+  model: "",
+  unit: "",
+});
+
+const rules = {
+  processId: [{ required: true, message: '璇烽�夋嫨宸ュ簭', trigger: 'change' }],
+  productModelId: [{ required: true, message: '璇烽�夋嫨浜у搧', trigger: 'change' }],
+};
+
+// 鏍规嵁宸ュ簭ID鑾峰彇宸ュ簭鍚嶇О
+const getProcessName = (processId) => {
+  if (!processId) return '';
+  const process = processOptions.value.find(p => p.id === processId);
+  return process ? process.name : '';
+};
+
+// 鑾峰彇鍒楄〃
+const getList = () => {
   tableLoading.value = true;
-  findProcessRouteItemList({ routeId: routeId.value })
-      .then(res => {
-        tableLoading.value = false;
-        routeItems.value = res.data.map(item => ({
-          ...item,
-          processId: item.processId === 0 ? undefined : item.processId
-        }));
-        // 寤惰繜鍒濆鍖栵紝纭繚DOM瀹屽叏娓叉煋
-        nextTick(() => {
-          setTimeout(() => initSortable(), 100);
-        });
-      })
-      .catch(err => {
-        tableLoading.value = false;
-        console.error("鑾峰彇鍒楄〃澶辫触锛�", err);
+  const listPromise =
+    pageType.value === "order"
+      ? findProductProcessRouteItemList({ orderId: orderId.value })
+      : findProcessRouteItemList({ routeId: routeId.value });
+
+  listPromise
+    .then(res => {
+      tableData.value = res.data || [];
+      tableLoading.value = false;
+      // 鍒楄〃鍔犺浇瀹屾垚鍚庡垵濮嬪寲鎷栨嫿鎺掑簭
+      nextTick(() => {
+        initSortable();
       });
+    })
+    .catch(err => {
+      tableLoading.value = false;
+      console.error("鑾峰彇鍒楄〃澶辫触锛�", err);
+      proxy?.$modal?.msgError("鑾峰彇鍒楄〃澶辫触");
+    });
 };
 
-const findProcessList = () => {
+// 鑾峰彇宸ュ簭鍒楄〃
+const getProcessList = () => {
   processList({})
-      .then(res => {
-        processOptions.value = res.data;
-      })
-      .catch(err => {
-        console.error("鑾峰彇宸ュ簭澶辫触锛�", err);
-      });
+    .then(res => {
+      processOptions.value = res.data || [];
+    })
+    .catch(err => {
+      console.error("鑾峰彇宸ュ簭澶辫触锛�", err);
+    });
 };
 
-const { proxy } = getCurrentInstance() || {};
+// 鑾峰彇宸ヨ壓璺嚎璇︽儏锛堜粠璺敱鍙傛暟鑾峰彇锛�
+const getRouteInfo = () => {
+  routeInfo.value = {
+    processRouteCode: route.query.processRouteCode || '',
+    productName: route.query.productName || '',
+    model: route.query.model || '',
+    bomNo: route.query.bomNo || '',
+    description: route.query.description || ''
+  };
+};
 
-const handleSubmit = () => {
-  const hasEmptyProcess = routeItems.value.some(item => !item.processId);
-  if (hasEmptyProcess) {
-    proxy?.$modal?.msgError("璇蜂负鎵�鏈夐」鐩�夋嫨宸ュ簭");
-    return;
-  }
+// 鏂板
+const handleAdd = () => {
+  operationType.value = 'add';
+  resetForm();
+  dialogVisible.value = true;
+};
 
-  addOrUpdateProcessRouteItem({
+// 缂栬緫
+const handleEdit = (row) => {
+  operationType.value = 'edit';
+  form.value = {
+    id: row.id,
     routeId: routeId.value,
-    processRouteItem: routeItems.value.map(({ id, ...item }) => item)
+    processId: row.processId,
+    productModelId: row.productModelId,
+    productName: row.productName || "",
+    model: row.model || "",
+    unit: row.unit || "",
+  };
+  dialogVisible.value = true;
+};
+
+// 鍒犻櫎
+const handleDelete = (row) => {
+  ElMessageBox.confirm('纭鍒犻櫎璇ュ伐鑹鸿矾绾块」鐩紵', '鎻愮ず', {
+    confirmButtonText: '纭',
+    cancelButtonText: '鍙栨秷',
+    type: 'warning'
   })
-      .then(res => {
-        router.push({
-          path: '/productionManagement/processRoute',
+    .then(() => {
+      // 鐢熶骇璁㈠崟涓嬩娇鐢� productProcessRoute 鐨勫垹闄ゆ帴鍙o紙璺敱鍚庢嫾鎺� id锛夛紝鍏跺畠鎯呭喌浣跨敤宸ヨ壓璺嚎椤圭洰鎵归噺鍒犻櫎鎺ュ彛
+      const deletePromise =
+        pageType.value === 'order'
+          ? deleteRouteItem(row.id)
+          : batchDeleteProcessRouteItem([row.id]);
+
+      deletePromise
+        .then(() => {
+          proxy?.$modal?.msgSuccess('鍒犻櫎鎴愬姛');
+          getList();
         })
-        proxy?.$modal?.msgSuccess("鎻愪氦鎴愬姛");
-      })
-      .catch(err => {
-        proxy?.$modal?.msgError(`鎻愪氦澶辫触锛�${err.msg || "缃戠粶寮傚父"}`);
-      });
+        .catch(() => {
+          proxy?.$modal?.msgError('鍒犻櫎澶辫触');
+        });
+    })
+    .catch(() => {});
 };
 
-const destroySortable = () => {
-  if (tableSortable) {
-    tableSortable.destroy();
-    tableSortable = null;
-  }
-  if (stepsSortable) {
-    stepsSortable.destroy();
-    stepsSortable = null;
+// 浜у搧閫夋嫨
+const handleProductSelect = (products) => {
+  if (products && products.length > 0) {
+    const product = products[0];
+    form.value.productModelId = product.id;
+    form.value.productName = product.productName;
+    form.value.model = product.model;
+    form.value.unit = product.unit || "";
+    showProductSelectDialog.value = false;
+    // 瑙﹀彂琛ㄥ崟楠岃瘉
+    formRef.value?.validateField('productModelId');
   }
 };
 
+// 鎻愪氦
+const handleSubmit = () => {
+  formRef.value.validate((valid) => {
+    if (valid) {
+      submitLoading.value = true;
+      
+      if (operationType.value === 'add') {
+        // 鏂板锛氫紶鍗曚釜瀵硅薄锛屽寘鍚玠ragSort瀛楁
+        // dragSort = 褰撳墠鍒楄〃闀垮害 + 1锛岃〃绀烘柊澧炶褰曟帓鍦ㄦ渶鍚�
+        const dragSort = tableData.value.length + 1;
+        const isOrderPage = pageType.value === 'order';
+
+        const addPromise = isOrderPage
+          ? addRouteItem({
+              productOrderId: orderId.value,
+              productRouteId: routeId.value,
+              processId: form.value.processId,
+              productModelId: form.value.productModelId,
+              dragSort,
+            })
+          : addOrUpdateProcessRouteItem({
+              routeId: routeId.value,
+              processId: form.value.processId,
+              productModelId: form.value.productModelId,
+              dragSort,
+            });
+
+        addPromise
+          .then(() => {
+            proxy?.$modal?.msgSuccess('鏂板鎴愬姛');
+            closeDialog();
+            getList();
+          })
+          .catch(() => {
+            proxy?.$modal?.msgError('鏂板澶辫触');
+          })
+          .finally(() => {
+            submitLoading.value = false;
+          });
+      } else {
+        // 缂栬緫锛氱敓浜ц鍗曚笅浣跨敤 productProcessRoute/updateRouteItem锛屽叾瀹冩儏鍐典娇鐢ㄥ伐鑹鸿矾绾块」鐩洿鏂版帴鍙�
+        const isOrderPage = pageType.value === 'order';
+        
+        const updatePromise = isOrderPage
+          ? addOrUpdateProductProcessRouteItem({
+              id: form.value.id,
+              processId: form.value.processId,
+              productModelId: form.value.productModelId,
+            })
+          : addOrUpdateProcessRouteItem({
+              routeId: routeId.value,
+              processId: form.value.processId,
+              productModelId: form.value.productModelId,
+              id: form.value.id,
+            });
+
+        updatePromise
+          .then(() => {
+            proxy?.$modal?.msgSuccess('淇敼鎴愬姛');
+            closeDialog();
+            getList();
+          })
+          .catch(() => {
+            proxy?.$modal?.msgError('淇敼澶辫触');
+          })
+          .finally(() => {
+            submitLoading.value = false;
+          });
+      }
+    }
+  });
+};
+
+// 閲嶇疆琛ㄥ崟
+const resetForm = () => {
+  form.value = {
+    id: undefined,
+    routeId: routeId.value,
+    processId: undefined,
+    productModelId: undefined,
+    productName: "",
+    model: "",
+    unit: "",
+  };
+  formRef.value?.resetFields();
+};
+
+// 鍏抽棴寮圭獥
+const closeDialog = () => {
+  dialogVisible.value = false;
+  resetForm();
+};
+
+// 鍒濆鍖栨嫋鎷芥帓搴�
 const initSortable = () => {
   destroySortable();
-
-  if (isTable.value) {
-    if (!multipleTable.value) return;
-    const tbody = multipleTable.value.$el.querySelector('.el-table__body tbody') ||
-        multipleTable.value.$el.querySelector('.el-table__body-wrapper > table > tbody');
+  
+  if (viewMode.value === 'table') {
+    // 琛ㄦ牸瑙嗗浘鐨勬嫋鎷芥帓搴�
+    if (!tableRef.value) return;
+    
+    const tbody = tableRef.value.$el.querySelector('.el-table__body tbody') ||
+        tableRef.value.$el.querySelector('.el-table__body-wrapper > table > tbody');
+    
     if (!tbody) return;
 
     tableSortable = new Sortable(tbody, {
@@ -315,189 +496,381 @@
       handle: '.el-table__row',
       filter: '.el-button, .el-select',
       onEnd: (evt) => {
-        if (evt.oldIndex === evt.newIndex || !routeItems.value[evt.oldIndex]) return;
+        if (evt.oldIndex === evt.newIndex || !tableData.value[evt.oldIndex]) return;
 
-        // 浣跨敤鏁扮粍 splice 鏂规硶閲嶆柊鎺掑簭锛屼笌琛ㄦ牸妯″紡淇濇寔涓�鑷�
-        const moveItem = routeItems.value.splice(evt.oldIndex, 1)[0];
-        routeItems.value.splice(evt.newIndex, 0, moveItem);
-        routeItems.value = [...routeItems.value];
-        console.log('鎺掑簭鍚庢暟缁�:', routeItems.value);
+        // 閲嶆柊鎺掑簭鏁扮粍
+        const moveItem = tableData.value.splice(evt.oldIndex, 1)[0];
+        tableData.value.splice(evt.newIndex, 0, moveItem);
+        
+        // 璁$畻鏂扮殑搴忓彿锛坉ragSort浠�1寮�濮嬶級
+        const newIndex = evt.newIndex;
+        const dragSort = newIndex + 1;
+        
+        // 璋冪敤鎺掑簭鎺ュ彛
+        if (moveItem.id) {
+          const isOrderPage = pageType.value === 'order';
+          const sortPromise = isOrderPage
+            ? sortRouteItem({
+                id: moveItem.id,
+                dragSort: dragSort
+              })
+            : sortProcessRouteItem({
+                id: moveItem.id,
+                dragSort: dragSort
+              });
+
+          sortPromise
+            .then(() => {
+              // 鏇存柊鎵�鏈夎鐨刣ragSort
+              tableData.value.forEach((item, index) => {
+                if (item.id) {
+                  item.dragSort = index + 1;
+                }
+              });
+              proxy?.$modal?.msgSuccess('鎺掑簭鎴愬姛');
+            })
+            .catch((err) => {
+              // 鎺掑簭澶辫触锛屾仮澶嶅師鏁扮粍
+              tableData.value.splice(newIndex, 1);
+              tableData.value.splice(evt.oldIndex, 0, moveItem);
+              proxy?.$modal?.msgError('鎺掑簭澶辫触');
+              console.error("鎺掑簭澶辫触锛�", err);
+            });
+        }
       }
     });
   } else {
-    if (!stepsContainer.value) return;
+    // 鍗$墖瑙嗗浘鐨勬嫋鎷芥帓搴�
+    if (!cardsContainer.value) return;
 
-    // 淇敼锛氱洿鎺ヤ娇鐢╯tepsContainer.value浣滀负鎷栨嫿瀹瑰櫒
-    const stepsList = stepsContainer.value;
-    if (!stepsList) {
-      console.warn('鏈壘鍒版楠ゆ潯鎷栨嫿瀹瑰櫒');
-      return;
-    }
-
-    // 淇敼锛氱畝鍖栨嫋鎷介厤缃�
-    stepsSortable = new Sortable(stepsList, {
+    cardSortable = new Sortable(cardsContainer.value, {
       animation: 150,
       ghostClass: 'sortable-ghost',
-      draggable: '.draggable-step', // 鍙嫋鎷藉厓绱�
-      handle: '.draggable-step, .step-card', // 鎷栨嫿鎵嬫焺
-      filter: '.el-button, .el-select, .el-input', // 杩囨护鎸夐挳/閫夋嫨鍣�
-      forceFallback: true,
-      fallbackClass: 'sortable-fallback',
-      preventOnFilter: true,
-      scroll: true,
-      scrollSensitivity: 30,
-      scrollSpeed: 10,
-      bubbleScroll: true,
+      handle: '.process-card',
+      filter: '.el-button',
       onEnd: (evt) => {
-        if (evt.oldIndex === evt.newIndex || !routeItems.value[evt.oldIndex]) return;
+        if (evt.oldIndex === evt.newIndex || !tableData.value[evt.oldIndex]) return;
 
-        // 浣跨敤鏁扮粍 splice 鏂规硶閲嶆柊鎺掑簭
-        const moveItem = routeItems.value.splice(evt.oldIndex, 1)[0];
-        routeItems.value.splice(evt.newIndex, 0, moveItem);
-        routeItems.value = [...routeItems.value];
+        // 閲嶆柊鎺掑簭鏁扮粍
+        const moveItem = tableData.value.splice(evt.oldIndex, 1)[0];
+        tableData.value.splice(evt.newIndex, 0, moveItem);
+        
+        // 璁$畻鏂扮殑搴忓彿锛坉ragSort浠�1寮�濮嬶級
+        const newIndex = evt.newIndex;
+        const dragSort = newIndex + 1;
+        
+        // 璋冪敤鎺掑簭鎺ュ彛
+        if (moveItem.id) {
+          const isOrderPage = pageType.value === 'order';
+          const sortPromise = isOrderPage
+            ? sortRouteItem({
+                id: moveItem.id,
+                dragSort: dragSort
+              })
+            : sortProcessRouteItem({
+                id: moveItem.id,
+                dragSort: dragSort
+              });
+
+          sortPromise
+            .then(() => {
+              // 鏇存柊鎵�鏈夎鐨刣ragSort
+              tableData.value.forEach((item, index) => {
+                if (item.id) {
+                  item.dragSort = index + 1;
+                }
+              });
+              proxy?.$modal?.msgSuccess('鎺掑簭鎴愬姛');
+            })
+            .catch((err) => {
+              // 鎺掑簭澶辫触锛屾仮澶嶅師鏁扮粍
+              tableData.value.splice(newIndex, 1);
+              tableData.value.splice(evt.oldIndex, 0, moveItem);
+              proxy?.$modal?.msgError('鎺掑簭澶辫触');
+              console.error("鎺掑簭澶辫触锛�", err);
+            });
+        }
       }
     });
-
-    // 璋冭瘯锛氭墦鍗板鍣ㄥ拰瀹炰緥锛岀‘璁ょ粦瀹氭垚鍔�
-    console.log('姝ラ鏉℃嫋鎷藉鍣�:', stepsList);
-    console.log('Sortable瀹炰緥:', stepsSortable);
   }
 };
 
-const handleViewChange = () => {
-  destroySortable();
-  // 寤惰繜鍒濆鍖栵紝纭繚瑙嗗浘鍒囨崲鍚嶥OM瀹屽叏娓叉煋
-  nextTick(() => {
-    setTimeout(() => initSortable(), 100);
-  });
+// 閿�姣佹嫋鎷芥帓搴�
+const destroySortable = () => {
+  if (tableSortable) {
+    tableSortable.destroy();
+    tableSortable = null;
+  }
+  if (cardSortable) {
+    cardSortable.destroy();
+    cardSortable = null;
+  }
 };
 
 onMounted(() => {
-  findProcessRouteItems();
-  findProcessList();
+  getRouteInfo();
+  getList();
+  getProcessList();
 });
 
 onUnmounted(() => {
   destroySortable();
 });
-
-defineExpose({
-  handleSubmit,
-});
 </script>
 
 <style scoped>
+.card-container {
+  padding: 20px 0;
+}
+
+.cards-wrapper {
+  display: flex;
+  gap: 16px;
+  overflow-x: auto;
+  padding: 10px 0;
+  min-height: 200px;
+}
+
+.cards-wrapper::-webkit-scrollbar {
+  height: 8px;
+}
+
+.cards-wrapper::-webkit-scrollbar-track {
+  background: #f1f1f1;
+  border-radius: 4px;
+}
+
+.cards-wrapper::-webkit-scrollbar-thumb {
+  background: #c1c1c1;
+  border-radius: 4px;
+}
+
+.cards-wrapper::-webkit-scrollbar-thumb:hover {
+  background: #a8a8a8;
+}
+
+.process-card {
+  flex-shrink: 0;
+  width: 220px;
+  background: #fff;
+  border-radius: 8px;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+  padding: 16px;
+  display: flex;
+  flex-direction: column;
+  cursor: move;
+  transition: all 0.3s;
+}
+
+.process-card:hover {
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+  transform: translateY(-2px);
+}
+
+.card-header {
+  text-align: center;
+  margin-bottom: 12px;
+}
+
+.card-number {
+  width: 36px;
+  height: 36px;
+  line-height: 36px;
+  border-radius: 50%;
+  background: #409eff;
+  color: #fff;
+  font-weight: bold;
+  font-size: 16px;
+  margin: 0 auto 8px;
+}
+
+.card-process-name {
+  font-size: 14px;
+  color: #333;
+  font-weight: 500;
+  word-break: break-all;
+}
+
+.card-content {
+  flex: 1;
+  margin-bottom: 12px;
+  min-height: 60px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.product-info {
+  font-size: 13px;
+  color: #666;
+  text-align: center;
+  width: 100%;
+}
+
+.product-info.empty {
+  color: #999;
+  text-align: center;
+  padding: 20px 0;
+}
+
+.product-name {
+  margin-bottom: 6px;
+  word-break: break-all;
+  line-height: 1.5;
+  text-align: center;
+}
+
+.product-model {
+  color: #909399;
+  font-size: 12px;
+  word-break: break-all;
+  line-height: 1.5;
+  text-align: center;
+}
+
+.product-unit {
+  margin-left: 4px;
+  color: #409eff;
+}
+
+.card-footer {
+  display: flex;
+  justify-content: space-around;
+  padding-top: 12px;
+  border-top: 1px solid #f0f0f0;
+}
+
+.card-footer .el-button {
+  padding: 0;
+  font-size: 12px;
+}
+
 :deep(.sortable-ghost) {
-  opacity: 0.6;
+  opacity: 0.5;
   background-color: #f5f7fa !important;
 }
 
+:deep(.sortable-drag) {
+  opacity: 0.8;
+}
+
+/* 琛ㄦ牸瑙嗗浘鏍峰紡 */
 :deep(.el-table__row) {
   transition: background-color 0.2s;
+  cursor: move;
 }
 
 :deep(.el-table__row:hover) {
   background-color: #f9fafc !important;
 }
 
-:deep(.el-card__footer){
-  padding: 0 !important;
+/* 鍖哄煙鏍囬鏍峰紡 */
+.section-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 12px;
 }
 
-.operate-button {
+.section-title {
+  font-size: 16px;
+  font-weight: 600;
+  color: #303133;
+  padding-left: 12px;
+  position: relative;
+  margin-bottom: 0;
+}
+
+.section-title::before {
+  content: '';
+  position: absolute;
+  left: 0;
+  top: 50%;
+  transform: translateY(-50%);
+  width: 3px;
+  height: 16px;
+  background: #409eff;
+  border-radius: 2px;
+}
+
+.section-actions {
   display: flex;
   align-items: center;
-  justify-content: space-between;
 }
 
-/* 淇敼锛氳嚜瀹氫箟姝ラ鏉″鍣ㄦ牱寮� */
-.custom-steps {
-  min-height: 100px;
-  padding: 10px 0;
-  display: flex;
-  flex-wrap: wrap;
-  gap: 20px;
-  align-items: flex-start;
+/* 宸ヨ壓璺嚎淇℃伅鍗$墖鏍峰紡 */
+.route-info-card {
+  margin-bottom: 20px;
+  border: 1px solid #e4e7ed;
+  background: linear-gradient(135deg, #f8f9fa 0%, #ffffff 100%);
+  border-radius: 8px;
+  overflow: hidden;
 }
 
-/* 淇敼锛氳嚜瀹氫箟姝ラ椤规牱寮� */
-.custom-step {
-  cursor: move !important;
-  padding: 8px;
-  position: relative;
-  transition: all 0.2s ease;
-  flex: 0 0 auto;
-  min-width: 220px;
-  touch-action: none;
+.route-info {
+  display: grid;
+  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
+  gap: 16px;
+  padding: 4px;
 }
 
-/* 鎷栨嫿鎮诞鏍峰紡锛屾彁绀哄彲鎷栨嫿 */
-.custom-step:hover {
-  background-color: rgba(64, 158, 255, 0.05);
-  transform: translateY(-2px);
-}
-
-.sortable-ghost {
-  opacity: 0.4;
-  background-color: #f5f7fa !important;
-  border: 2px dashed #409eff;
-  margin: 10px;
-  transform: scale(1.02);
-}
-
-.sortable-fallback {
-  opacity: 0.9;
-  background-color: #f5f7fa;
-  border: 1px solid #409eff;
-  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
-  transform: rotate(2deg);
-  margin: 10px;
-}
-
-.step-card {
-  cursor: move !important;
-  transition: box-shadow 0.2s ease;
-  user-select: none;
-  -webkit-user-select: none;
-  pointer-events: auto;
-  margin: 10px;
-  height: 260px;
-}
-
-.step-card:hover {
-  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
-}
-
-.step-content {
-  width: 245px;
-  user-select: none;
-}
-
-.step-card-content {
+.info-item {
   display: flex;
   flex-direction: column;
-  align-items: center;
-  height: 140px;
+  background: #ffffff;
+  border-radius: 6px;
+  padding: 14px 16px;
+  border: 1px solid #f0f2f5;
+  transition: all 0.3s ease;
+  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
 }
 
-.step-card-footer {
-  display: flex;
-  justify-content: flex-end;
-  align-items: center;
-  padding: 10px;
+.info-item:hover {
+  border-color: #409eff;
+  box-shadow: 0 2px 8px rgba(64, 158, 255, 0.15);
+  transform: translateY(-1px);
 }
 
-/* 鑷畾涔夊簭鍙锋牱寮忎紭鍖� */
-.step-number {
-  font-weight: bold;
-  text-align: center;
-  width: 36px;
-  height: 36px;
-  line-height: 36px;
-  margin: 0 auto 10px;
-  background: #409eff;
-  color: #fff;
-  border-radius: 50%;
-  font-size: 14px;
+.info-item.full-width {
+  grid-column: 1 / -1;
+}
+
+.info-label-wrapper {
+  margin-bottom: 8px;
+}
+
+.info-label {
+  display: inline-block;
+  color: #909399;
+  font-size: 12px;
+  font-weight: 500;
+  text-transform: uppercase;
+  letter-spacing: 0.5px;
+  padding: 2px 0;
+  position: relative;
+}
+
+.info-label::after {
+  content: '';
+  position: absolute;
+  left: 0;
+  bottom: 0;
+  width: 20px;
+  height: 2px;
+  background: linear-gradient(90deg, #409eff, transparent);
+  border-radius: 1px;
+}
+
+.info-value-wrapper {
+  flex: 1;
+}
+
+.info-value {
+  display: block;
+  color: #303133;
+  font-size: 15px;
+  font-weight: 500;
+  line-height: 1.5;
+  word-break: break-all;
 }
 </style>
diff --git a/src/views/productionManagement/productStructure/Detail/index.vue b/src/views/productionManagement/productStructure/Detail/index.vue
index a131830..20a472b 100644
--- a/src/views/productionManagement/productStructure/Detail/index.vue
+++ b/src/views/productionManagement/productStructure/Detail/index.vue
@@ -1,30 +1,32 @@
 <template>
   <div class="app-container">
-    <el-button v-if="dataValue.isEdit"
-               type="primary"
-               @click="addItem"
-               style="margin-bottom: 10px">娣诲姞
-    </el-button>
-    <el-button v-if="!dataValue.isEdit"
-               type="primary"
-               @click="dataValue.isEdit = true"
-               style="margin-bottom: 10px">缂栬緫
-    </el-button>
-    <el-button v-if="dataValue.isEdit"
-               type="primary"
-               @click="cancelEdit"
-               style="margin-bottom: 10px">鍙栨秷
-    </el-button>
-    <el-button type="primary"
-               :loading="dataValue.loading"
-               @click="submit"
-               :disabled="!dataValue.isEdit"
-               style="margin-bottom: 10px">纭
-    </el-button>
+    <PageHeader content="浜у搧缁撴瀯璇︽儏">
+      <template #right-button>
+        <el-button v-if="dataValue.isEdit && !isOrderPage"
+                   type="primary"
+                   @click="addItem">娣诲姞
+        </el-button>
+        <el-button v-if="!dataValue.isEdit && !isOrderPage"
+                   type="primary"
+                   @click="dataValue.isEdit = true">缂栬緫
+        </el-button>
+        <el-button v-if="dataValue.isEdit && !isOrderPage"
+                   type="primary"
+                   @click="cancelEdit">鍙栨秷
+        </el-button>
+        <el-button v-if="!isOrderPage"
+                   type="primary"
+                   :loading="dataValue.loading"
+                   @click="submit"
+                   :disabled="!dataValue.isEdit">纭
+        </el-button>
+      </template>
+    </PageHeader>
     <el-table
         :data="tableData"
         border
         :preserve-expanded-content="false"
+        :default-expand-all="true"
         style="width: 100%"
     >
       <el-table-column type="expand">
@@ -91,7 +93,8 @@
                   </el-form-item>
                 </template>
               </el-table-column>
-              <el-table-column prop="demandedQuantity"
+              <el-table-column v-if="isOrderPage"
+                               prop="demandedQuantity"
                                label="闇�姹傛�婚噺">
                 <template #default="{ row, $index }">
                   <el-form-item :prop="`dataList.${$index}.demandedQuantity`"
@@ -120,25 +123,10 @@
                   </el-form-item>
                 </template>
               </el-table-column>
-              <el-table-column prop="diskQuantity"
-                               label="鐩樻暟锛堢洏锛�">
-                <template #default="{ row, $index }">
-                  <el-form-item :prop="`dataList.${$index}.diskQuantity`"
-                                :rules="[{ required: true, message: '璇疯緭鍏ョ洏鏁�', trigger: ['blur','change'] }]"
-                                style="margin: 0">
-                    <el-input-number v-model="row.diskQuantity"
-                                     :min="0"
-                                     :precision="0"
-                                     :step="1"
-                                     controls-position="right"
-                                     style="width: 100%"
-                                     :disabled="!dataValue.isEdit" />
-                  </el-form-item>
-                </template>
-              </el-table-column>
               <el-table-column label="鎿嶄綔" fixed="right" width="100">
                 <template #default="{ row, $index }">
-                  <el-button type="danger"
+                  <el-button v-if="dataValue.isEdit"
+                             type="danger"
                              text
                              @click="dataValue.dataList.splice($index, 1)">鍒犻櫎
                   </el-button>
@@ -148,10 +136,9 @@
           </el-form>
         </template>
       </el-table-column>
-      <el-table-column label="浜у搧缂栫爜" prop="productCode" />
+      <el-table-column label="BOM缂栧彿" prop="bomNo" />
       <el-table-column label="浜у搧鍚嶇О" prop="productName" />
       <el-table-column label="瑙勬牸鍨嬪彿" prop="model" />
-      <el-table-column label="鍗曚綅" prop="unit" />
     </el-table>
 
     <product-select-dialog v-if="dataValue.showProductDialog"
@@ -170,6 +157,7 @@
   ref,
 } from "vue";
 import { queryList, add } from "@/api/productionManagement/productStructure.js";
+import { listProcessBom } from "@/api/productionManagement/productionOrder.js";
 import { list } from "@/api/productionManagement/productionProcess";
 import { ElMessage } from "element-plus";
 import {useRoute, useRouter} from "vue-router";
@@ -195,6 +183,13 @@
   }
 });
 
+// 浠庤矾鐢卞弬鏁拌幏鍙栦骇鍝佷俊鎭�
+const routeBomNo = computed(() => route.query.bomNo || '');
+const routeProductName = computed(() => route.query.productName || '');
+const routeProductModelName = computed(() => route.query.productModelName || '');
+const routeOrderId = computed(() => route.query.orderId);
+const pageType = computed(() => route.query.type);
+const isOrderPage = computed(() => pageType.value === 'order' && routeOrderId.value);
 
 const dataValue = reactive({
   dataList: [],
@@ -210,8 +205,7 @@
   {
     productName: "",
     model: "",
-    unit: "",
-    productCode: "",
+    bomNo: "",
   }
 ])
 
@@ -221,12 +215,15 @@
 };
 
 const fetchData = async () => {
-  const { data } = await queryList(routeId.value);
-  tableData[0].productName = data.productName;
-  tableData[0].model = data.model;
-  tableData[0].unit = data.unit;
-  tableData[0].productCode = data.productCode;
-  dataValue.dataList = data.productStructureList;
+  if (isOrderPage.value) {
+    // 璁㈠崟鎯呭喌锛氫娇鐢ㄨ鍗曠殑浜у搧缁撴瀯鎺ュ彛
+    const { data } = await listProcessBom({ orderId: routeOrderId.value });
+    dataValue.dataList = data || [];
+  } else {
+    // 闈炶鍗曟儏鍐碉細浣跨敤鍘熸潵鐨勬帴鍙�
+    const { data } = await queryList(routeId.value);
+    dataValue.dataList = data || [];
+  }
 };
 
 const fetchProcessOptions = async () => {
@@ -242,6 +239,7 @@
       row[0].productName;
   dataValue.dataList[dataValue.currentRowIndex].model = row[0].model;
   dataValue.dataList[dataValue.currentRowIndex].productModelId = row[0].id;
+  dataValue.dataList[dataValue.currentRowIndex].unit = row[0].unit || "";
   dataValue.showProductDialog = false;
 };
 
@@ -251,7 +249,7 @@
         dataValue.loading = true;
         if (valid) {
           add({
-            parentId: routeId.value,
+            bomId: routeId.value,
             productStructureList: dataValue.dataList || [],
           }).then(res => {
             router.push({
@@ -277,7 +275,6 @@
     unitQuantity: 0,
     demandedQuantity: 0,
     unit: "",
-    diskQuantity: 0,
   });
 };
 
@@ -287,6 +284,16 @@
 };
 
 onMounted(() => {
+  // 浠庤矾鐢卞弬鏁板洖鏄炬暟鎹�
+  tableData[0].productName = routeProductName.value;
+  tableData[0].model = routeProductModelName.value;
+  tableData[0].bomNo = routeBomNo.value;
+  
+  // 璁㈠崟鎯呭喌涓嬬鐢ㄧ紪杈�
+  if (isOrderPage.value) {
+    dataValue.isEdit = false;
+  }
+  
   fetchData();
   fetchProcessOptions();
 });
diff --git a/src/views/productionManagement/productStructure/index.vue b/src/views/productionManagement/productStructure/index.vue
index e32ff8d..d8ce689 100644
--- a/src/views/productionManagement/productStructure/index.vue
+++ b/src/views/productionManagement/productStructure/index.vue
@@ -1,5 +1,9 @@
 <template>
   <div class="app-container">
+    <div style="text-align: right; margin-bottom: 10px;">
+      <el-button type="primary" @click="handleAdd">鏂板</el-button>
+      <el-button type="danger" plain @click="handleBatchDelete" :disabled="selectedRows.length === 0">鍒犻櫎</el-button>
+    </div>
     <PIMTable
         rowKey="id"
         :column="tableColumn"
@@ -14,100 +18,323 @@
         <el-button
             type="primary"
             text
-            @click="showDetail(row.id)">{{ row.productName }}
+            @click="showDetail(row)">{{ row.bomNo }}
         </el-button>
       </template>
     </PIMTable>
     <StructureEdit v-if="showEdit" v-model:show-model="showEdit" :record="currentRow"/>
+    
+    <!-- 鏂板/缂栬緫寮圭獥 -->
+    <el-dialog
+        v-model="dialogVisible"
+        :title="operationType === 'add' ? '鏂板BOM' : '缂栬緫BOM'"
+        width="600px"
+        @close="closeDialog"
+    >
+      <el-form
+          ref="formRef"
+          :model="form"
+          :rules="rules"
+          label-width="120px"
+      >
+        <el-form-item label="浜у搧鍚嶇О" prop="productModelId">
+          <el-button type="primary" @click="showProductSelectDialog = true">
+            {{ form.productName || '閫夋嫨浜у搧' }}
+          </el-button>
+        </el-form-item>
+        <el-form-item label="鐗堟湰鍙�" prop="version">
+          <el-input v-model="form.version" placeholder="璇疯緭鍏ョ増鏈彿" clearable />
+        </el-form-item>
+        <el-form-item label="澶囨敞" prop="remark">
+          <el-input
+              v-model="form.remark"
+              type="textarea"
+              :rows="3"
+              placeholder="璇疯緭鍏ュ娉�"
+              clearable
+          />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button @click="closeDialog">鍙栨秷</el-button>
+        <el-button type="primary" @click="handleSubmit">纭畾</el-button>
+      </template>
+    </el-dialog>
+    
+    <!-- 浜у搧閫夋嫨寮圭獥 -->
+    <ProductSelectDialog
+        v-model="showProductSelectDialog"
+        @confirm="handleProductSelect"
+        single
+    />
   </div>
 </template>
 
 <script setup>
-import {ref} from "vue";
-import {productModelList} from "@/api/basicData/productModel.js";
+import { ref, reactive, toRefs, onMounted, getCurrentInstance, defineAsyncComponent } from "vue";
+import { listPage, add, update, batchDelete } from "@/api/productionManagement/productBom.js";
 import { useRouter } from 'vue-router'
+import { ElMessageBox } from 'element-plus'
+import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue";
 
 const router = useRouter()
+const { proxy } = getCurrentInstance()
 const StructureEdit = defineAsyncComponent(() => import('@/views/productionManagement/productStructure/StructureEdit.vue'))
 
 const tableColumn = ref([
   {
-    label: "浜у搧缂栫爜",
-    prop: "productCode",
-    slot: "detail"
+    label: "BOM缂栧彿",
+    prop: "bomNo",
+    dataType: 'slot',
+    slot: "detail",
+    minWidth: 140
   },
   {
     label: "浜у搧鍚嶇О",
     prop: "productName",
-    dataType: 'slot',
-    slot: "detail"
+    
+    minWidth: 160
   },
   {
     label: "瑙勬牸鍨嬪彿",
-    prop: "model",
+    prop: "productModelName",
+    minWidth: 140
   },
   {
-    label: "鍗曚綅",
-    prop: "unit",
+    label: "鐗堟湰鍙�",
+    prop: "version",
+    width: 100
+  },
+  {
+    label: "澶囨敞",
+    prop: "remark",
+    minWidth: 160
+  },
+  {
+    dataType: "action",
+    label: "鎿嶄綔",
+    align: "center",
+    fixed: "right",
+    width: 150,
+    operation: [
+      {
+        name: "缂栬緫",
+        type: "text",
+        clickFun: (row) => {
+          handleEdit(row)
+        }
+      },
+      {
+        name: "鍒犻櫎",
+        type: "danger",
+        link: true,
+        clickFun: (row) => {
+          handleDelete(row)
+        }
+      }
+    ]
   }
 ]);
+
 const tableData = ref([]);
 const tableLoading = ref(false);
 const showEdit = ref(false);
 const selectedRows = ref([]);
 const currentRow = ref({});
+const dialogVisible = ref(false);
+const operationType = ref('add'); // add | edit
+const formRef = ref(null);
+const showProductSelectDialog = ref(false);
+
 const page = reactive({
   current: 1,
   size: 10,
   total: 0,
 });
+
 const data = reactive({
   form: {
+    id: undefined,
     productName: "",
+    productModelName: "",
+    productModelId: "",
+    remark: "",
+    version: ""
   },
   rules: {
-    productName: [{required: true, message: "璇疯緭鍏�", trigger: "blur"}],
-  },
-  modelForm: {
-    otherModel: '',
-    model: "",
-    unit: "",
-    speculativeTradingName: [],
-  },
+    productModelId: [{ required: true, message: "璇烽�夋嫨浜у搧", trigger: "change" }],
+    version: [{ required: true, message: "璇疯緭鍏ョ増鏈彿", trigger: "blur" }]
+  }
 });
-const {form, rules} = toRefs(data);
+
+const { form, rules } = toRefs(data);
+
 // 琛ㄦ牸閫夋嫨鏁版嵁
 const handleSelectionChange = (selection) => {
   selectedRows.value = selection;
 };
 
-// 鏌ヨ瑙勬牸鍨嬪彿
+// 鍒嗛〉
 const pagination = (obj) => {
   page.current = obj.page;
   page.size = obj.limit;
-  getModelList();
+  getList();
 };
 
-const showDetail = (id) => {
+// 鏌ヨ鍒楄〃
+const getList = () => {
+  tableLoading.value = true;
+  listPage({
+    current: page.current,
+    size: page.size,
+  })
+    .then((res) => {
+      const records = res?.data?.records || [];
+      tableData.value = records;
+      page.total = res?.data?.total || 0;
+    })
+    .catch((err) => {
+      console.error("鑾峰彇鍒楄〃澶辫触锛�", err);
+    })
+    .finally(() => {
+      tableLoading.value = false;
+    });
+};
+
+// 鏂板
+const handleAdd = () => {
+  operationType.value = 'add';
+  Object.assign(form.value, {
+    id: undefined,
+    productName: "",
+    productModelName: "",
+    productModelId: "",
+    remark: "",
+    version: ""
+  });
+  dialogVisible.value = true;
+};
+
+// 缂栬緫
+const handleEdit = (row) => {
+  operationType.value = 'edit';
+  Object.assign(form.value, {
+    id: row.id,
+    productName: row.productName || "",
+    productModelName: row.productModelName || "",
+    productModelId: row.productModelId || "",
+    remark: row.remark || "",
+    version: row.version || ""
+  });
+  dialogVisible.value = true;
+};
+
+// 鍒犻櫎锛堝崟鏉★級
+const handleDelete = (row) => {
+  ElMessageBox.confirm('纭鍒犻櫎璇OM锛�', '鎻愮ず', {
+    confirmButtonText: '纭',
+    cancelButtonText: '鍙栨秷',
+    type: 'warning'
+  })
+    .then(() => {
+      batchDelete([row.id])
+        .then(() => {
+          proxy.$modal.msgSuccess('鍒犻櫎鎴愬姛');
+          getList();
+        })
+        .catch(() => {
+          proxy.$modal.msgError('鍒犻櫎澶辫触');
+        });
+    })
+    .catch(() => {});
+};
+
+// 鎵归噺鍒犻櫎
+const handleBatchDelete = () => {
+  if (!selectedRows.value.length) {
+    proxy.$modal.msgWarning('璇烽�夋嫨鏁版嵁');
+    return;
+  }
+  const ids = selectedRows.value.map(item => item.id);
+  ElMessageBox.confirm('閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�', '鍒犻櫎鎻愮ず', {
+    confirmButtonText: '纭',
+    cancelButtonText: '鍙栨秷',
+    type: 'warning'
+  })
+    .then(() => {
+      batchDelete(ids)
+        .then(() => {
+          proxy.$modal.msgSuccess('鍒犻櫎鎴愬姛');
+          getList();
+        })
+        .catch(() => {
+          proxy.$modal.msgError('鍒犻櫎澶辫触');
+        });
+    })
+    .catch(() => {});
+};
+
+// 浜у搧閫夋嫨
+const handleProductSelect = (products) => {
+  if (products && products.length > 0) {
+    const product = products[0];
+    form.value.productModelId = product.id;
+    form.value.productName = product.productName;
+    form.value.productModelName = product.model;
+  }
+  showProductSelectDialog.value = false;
+};
+
+// 鎻愪氦琛ㄥ崟
+const handleSubmit = () => {
+  formRef.value.validate((valid) => {
+    if (valid) {
+      const payload = { ...form.value };
+      if (operationType.value === 'add') {
+        add(payload)
+          .then(() => {
+            proxy.$modal.msgSuccess('鏂板鎴愬姛');
+            closeDialog();
+            getList();
+          })
+          .catch(() => {
+            proxy.$modal.msgError('鏂板澶辫触');
+          });
+      } else {
+        update(payload)
+          .then(() => {
+            proxy.$modal.msgSuccess('淇敼鎴愬姛');
+            closeDialog();
+            getList();
+          })
+          .catch(() => {
+            proxy.$modal.msgError('淇敼澶辫触');
+          });
+      }
+    }
+  });
+};
+
+// 鍏抽棴寮圭獥
+const closeDialog = () => {
+  dialogVisible.value = false;
+  formRef.value?.resetFields();
+};
+
+// 鏌ョ湅璇︽儏
+const showDetail = (row) => {
   router.push({
     path: '/productionManagement/productStructureDetail',
     query: {
-      id: id
+      id: row.id,
+      bomNo: row.bomNo || '',
+      productName: row.productName || '',
+      productModelName: row.productModelName || ''
     }
-  })
-}
-const getModelList = () => {
-  tableLoading.value = true;
-  productModelList({
-    current: page.current,
-    size: page.size,
-  }).then((res) => {
-    tableData.value = res.records;
-    page.total = res.total;
-    tableLoading.value = false;
   });
 };
+
 onMounted(() => {
-  getModelList();
-})
+  getList();
+});
 </script>
diff --git a/src/views/productionManagement/productionOrder/ProcessRouteItemForm.vue b/src/views/productionManagement/productionOrder/ProcessRouteItemForm.vue
deleted file mode 100644
index 354f9de..0000000
--- a/src/views/productionManagement/productionOrder/ProcessRouteItemForm.vue
+++ /dev/null
@@ -1,555 +0,0 @@
-<template>
-  <div>
-    <el-dialog v-model="isShow"
-               title="宸ヨ壓璺嚎椤圭洰"
-               width="800px"
-               @close="closeModal">
-      <div class="operate-button">
-        <el-button type="primary"
-                   @click="isShowProductSelectDialog = true"
-                   class="mb5"
-                   style="margin-bottom: 10px;">
-          閫夋嫨浜у搧
-        </el-button>
-        <el-switch v-model="isTable"
-                   inline-prompt
-                   active-text="琛ㄦ牸"
-                   inactive-text="鍒楄〃"
-                   @change="handleViewChange" />
-      </div>
-      <el-table v-if="isTable"
-                ref="multipleTable"
-                v-loading="tableLoading"
-                border
-                :data="routeItems"
-                :header-cell-style="{ background: '#F0F1F5', color: '#333333' }"
-                row-key="id"
-                tooltip-effect="dark"
-                class="lims-table"
-                style="cursor: move;">
-        <el-table-column align="center"
-                         label="搴忓彿"
-                         width="60">
-          <template #default="scope">
-            {{ scope.$index + 1 }}
-          </template>
-        </el-table-column>
-        <el-table-column v-for="(item, index) in tableColumn"
-                         :key="index"
-                         :label="item.label"
-                         :width="item.width"
-                         show-overflow-tooltip>
-          <template #default="scope"
-                    v-if="item.dataType === 'action'">
-            <el-button v-for="(op, opIndex) in item.operation"
-                       :key="opIndex"
-                       :type="op.type"
-                       :link="op.link"
-                       size="small"
-                       @click.stop="op.clickFun(scope.row)">
-              {{ op.name }}
-            </el-button>
-          </template>
-          <template #default="scope"
-                    v-else>
-            <template v-if="item.prop === 'processId'">
-              <el-select v-model="scope.row[item.prop]"
-                         style="width: 100%;"
-                         @mousedown.stop>
-                <el-option v-for="process in processOptions"
-                           :key="process.id"
-                           :label="process.name"
-                           :value="process.id" />
-              </el-select>
-            </template>
-            <template v-else>
-              {{ scope.row[item.prop] || '-' }}
-            </template>
-          </template>
-        </el-table-column>
-      </el-table>
-      <!-- 浣跨敤鏅�歞iv鏇夸唬el-steps -->
-      <div v-else
-           ref="stepsContainer"
-           class="mb5 custom-steps"
-           style="padding: 10px 0; display: flex; flex-wrap: nowrap; gap: 20px; align-items: flex-start;">
-        <div v-for="(item, index) in routeItems"
-             :key="item.id"
-             class="custom-step draggable-step"
-             :data-id="item.id"
-             style="cursor: move; flex: 0 0 auto; min-width: 220px;">
-          <div class="step-content">
-            <div class="step-number">{{ index + 1 }}</div>
-            <el-card :header="item.productName"
-                     class="step-card"
-                     style="cursor: move;">
-              <div class="step-card-content">
-                <p>{{ item.model }}</p>
-                <p>{{ item.unit }}</p>
-                <el-select v-model="item.processId"
-                           style="width: 100%;"
-                           @mousedown.stop>
-                  <el-option v-for="process in processOptions"
-                             :key="process.id"
-                             :label="process.name"
-                             :value="process.id" />
-                </el-select>
-              </div>
-              <template #footer>
-                <div class="step-card-footer">
-                  <el-button type="danger"
-                             link
-                             size="small"
-                             @click.stop="removeItemByID(item.id)">鍒犻櫎</el-button>
-                </div>
-              </template>
-            </el-card>
-          </div>
-        </div>
-      </div>
-      <template #footer>
-        <div class="dialog-footer">
-          <el-button type="primary"
-                     @click="handleSubmit">纭</el-button>
-          <el-button @click="closeModal">鍙栨秷</el-button>
-        </div>
-      </template>
-    </el-dialog>
-    <ProductSelectDialog v-model="isShowProductSelectDialog"
-                         @confirm="handelSelectProducts" />
-  </div>
-</template>
-
-<script setup>
-  import {
-    ref,
-    computed,
-    getCurrentInstance,
-    onMounted,
-    onUnmounted,
-    nextTick,
-  } from "vue";
-  import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue";
-  import {
-    findProductProcessRouteItemList,
-    addOrUpdateProductProcessRouteItem,
-    deleteRouteItem,
-  } from "@/api/productionManagement/productProcessRoute.js";
-  import { processList } from "@/api/productionManagement/productionProcess.js";
-  import Sortable from "sortablejs";
-
-  const props = defineProps({
-    visible: {
-      type: Boolean,
-      required: true,
-      default: false,
-    },
-    record: {
-      type: Object,
-      required: true,
-      default: () => ({}),
-    },
-  });
-
-  const emit = defineEmits(["update:visible", "completed"]);
-
-  const processOptions = ref([]);
-  const tableLoading = ref(false);
-  const isShowProductSelectDialog = ref(false);
-  const routeItems = ref([]);
-  let tableSortable = null;
-  let stepsSortable = null;
-  const multipleTable = ref(null);
-  const stepsContainer = ref(null);
-  const isTable = ref(true);
-
-  const isShow = computed({
-    get() {
-      return props.visible;
-    },
-    set(val) {
-      emit("update:visible", val);
-    },
-  });
-
-  const tableColumn = ref([
-    { label: "浜у搧鍚嶇О", prop: "productName", width: 180 },
-    { label: "瑙勬牸鍚嶇О", prop: "model", width: 150 },
-    { label: "鍗曚綅", prop: "unit", width: 80 },
-    { label: "宸ュ簭鍚嶇О", prop: "processId", width: 180 },
-    {
-      dataType: "action",
-      label: "鎿嶄綔",
-      align: "center",
-      fixed: "right",
-      width: 100,
-      operation: [
-        {
-          name: "鍒犻櫎",
-          type: "danger",
-          link: true,
-          clickFun: row => {
-            console.log(row.id, "鍒犻櫎");
-
-            const dragSortx = routeItems.value.findIndex(
-              item => item.dragSort === row.dragSort
-            );
-            const idx = routeItems.value.findIndex(item => item.id === row.id);
-            console.log(idx, "idx");
-            if (row.id) {
-              deleteRouteItemByIds({ id: row.id }, idx);
-            } else {
-              removeItem(dragSortx);
-            }
-          },
-        },
-      ],
-    },
-  ]);
-
-  const removeItem = index => {
-    console.log("杞垹闄�", index);
-
-    routeItems.value.splice(index, 1);
-    updateDragSort();
-    nextTick(() => initSortable());
-  };
-
-  const removeItemByID = id => {
-    const idx = routeItems.value.findIndex(item => item.id === id);
-    if (idx > -1) {
-      routeItems.value.splice(idx, 1);
-      updateDragSort();
-      nextTick(() => initSortable());
-    }
-  };
-
-  const deleteRouteItemByIds = (ids, index) => {
-    deleteRouteItem(ids).then(res => {
-      routeItems.value.splice(index, 1);
-      updateDragSort();
-      nextTick(() => initSortable());
-    });
-  };
-
-  const closeModal = () => {
-    isShow.value = false;
-  };
-
-  const updateDragSort = () => {
-    routeItems.value.forEach((item, index) => {
-      item.dragSort = index + 1;
-    });
-    routeItems.value = [...routeItems.value];
-    console.log("鏇存柊鍚庣殑鏁扮粍:", routeItems.value);
-  };
-
-  const handelSelectProducts = products => {
-    destroySortable();
-
-    // 璁$畻鏂扮殑dragSort鍊艰捣濮嬬偣
-    const maxDragSort =
-      routeItems.value.length > 0
-        ? Math.max(...routeItems.value.map(item => item.dragSort || 0))
-        : 0;
-
-    const newData = products.map(({ id, ...product }, index) => ({
-      ...product,
-      productModelId: id,
-      routeId: props.record.id,
-      // id: `${Date.now()}-${Math.random().toString(36).slice(2)}`,
-      processId: undefined,
-      dragSort: maxDragSort + index + 1,
-    }));
-
-    console.log("閫夋嫨浜у搧鍓嶆暟缁�:", routeItems.value);
-    routeItems.value.push(...newData);
-    updateDragSort();
-    console.log("閫夋嫨浜у搧鍚庢暟缁�:", routeItems.value);
-
-    // 寤惰繜鍒濆鍖栵紝纭繚DOM瀹屽叏娓叉煋
-    nextTick(() => {
-      // 寮哄埗閲嶆柊娓叉煋缁勪欢
-      if (proxy?.$forceUpdate) {
-        proxy.$forceUpdate();
-      }
-
-      const temp = [...routeItems.value];
-      routeItems.value = [];
-      nextTick(() => {
-        routeItems.value = temp;
-        initSortable();
-      });
-    });
-  };
-
-  const findProcessRouteItems = () => {
-    tableLoading.value = true;
-    findProductProcessRouteItemList({ orderId: props.record.id })
-      .then(res => {
-        tableLoading.value = false;
-        routeItems.value = res.data.map(item => ({
-          ...item,
-          processId: item.processId === 0 ? undefined : item.processId,
-        }));
-        // 寤惰繜鍒濆鍖栵紝纭繚DOM瀹屽叏娓叉煋
-        nextTick(() => {
-          setTimeout(() => initSortable(), 100);
-        });
-      })
-      .catch(err => {
-        tableLoading.value = false;
-        console.error("鑾峰彇鍒楄〃澶辫触锛�", err);
-      });
-  };
-
-  const findProcessList = () => {
-    processList({})
-      .then(res => {
-        processOptions.value = res.data;
-      })
-      .catch(err => {
-        console.error("鑾峰彇宸ュ簭澶辫触锛�", err);
-      });
-  };
-
-  const { proxy } = getCurrentInstance() || {};
-
-  const handleSubmit = () => {
-    const hasEmptyProcess = routeItems.value.some(item => !item.processId);
-    if (hasEmptyProcess) {
-      proxy?.$modal?.msgError("璇蜂负鎵�鏈夐」鐩�夋嫨宸ュ簭");
-      return;
-    }
-
-    addOrUpdateProductProcessRouteItem({
-      routeId: props.record.id,
-      processRouteItem: routeItems.value,
-    })
-      .then(res => {
-        isShow.value = false;
-        emit("completed");
-        proxy?.$modal?.msgSuccess("鎻愪氦鎴愬姛");
-      })
-      .catch(err => {
-        proxy?.$modal?.msgError(`鎻愪氦澶辫触锛�${err.msg || "缃戠粶寮傚父"}`);
-      });
-  };
-
-  const destroySortable = () => {
-    if (tableSortable) {
-      tableSortable.destroy();
-      tableSortable = null;
-    }
-    if (stepsSortable) {
-      stepsSortable.destroy();
-      stepsSortable = null;
-    }
-  };
-
-  const initSortable = () => {
-    destroySortable();
-
-    if (isTable.value) {
-      if (!multipleTable.value) return;
-      const tbody =
-        multipleTable.value.$el.querySelector(".el-table__body tbody") ||
-        multipleTable.value.$el.querySelector(
-          ".el-table__body-wrapper > table > tbody"
-        );
-      if (!tbody) return;
-
-      tableSortable = new Sortable(tbody, {
-        animation: 150,
-        ghostClass: "sortable-ghost",
-        handle: ".el-table__row",
-        filter: ".el-button, .el-select",
-        onEnd: evt => {
-          if (evt.oldIndex === evt.newIndex || !routeItems.value[evt.oldIndex])
-            return;
-
-          // 浣跨敤鏁扮粍 splice 鏂规硶閲嶆柊鎺掑簭锛屼笌琛ㄦ牸妯″紡淇濇寔涓�鑷�
-          const moveItem = routeItems.value.splice(evt.oldIndex, 1)[0];
-          routeItems.value.splice(evt.newIndex, 0, moveItem);
-          updateDragSort();
-          console.log("鎺掑簭鍚庢暟缁�:", routeItems.value);
-        },
-      });
-    } else {
-      if (!stepsContainer.value) return;
-
-      // 淇敼锛氱洿鎺ヤ娇鐢╯tepsContainer.value浣滀负鎷栨嫿瀹瑰櫒
-      const stepsList = stepsContainer.value;
-      if (!stepsList) {
-        console.warn("鏈壘鍒版楠ゆ潯鎷栨嫿瀹瑰櫒");
-        return;
-      }
-
-      // 淇敼锛氱畝鍖栨嫋鎷介厤缃�
-      stepsSortable = new Sortable(stepsList, {
-        animation: 150,
-        ghostClass: "sortable-ghost",
-        draggable: ".draggable-step", // 鍙嫋鎷藉厓绱�
-        handle: ".draggable-step, .step-card", // 鎷栨嫿鎵嬫焺
-        filter: ".el-button, .el-select, .el-input", // 杩囨护鎸夐挳/閫夋嫨鍣�
-        forceFallback: true,
-        fallbackClass: "sortable-fallback",
-        preventOnFilter: true,
-        scroll: true,
-        scrollSensitivity: 30,
-        scrollSpeed: 10,
-        bubbleScroll: true,
-        onEnd: evt => {
-          if (evt.oldIndex === evt.newIndex || !routeItems.value[evt.oldIndex])
-            return;
-
-          // 浣跨敤鏁扮粍 splice 鏂规硶閲嶆柊鎺掑簭
-          const moveItem = routeItems.value.splice(evt.oldIndex, 1)[0];
-          routeItems.value.splice(evt.newIndex, 0, moveItem);
-          updateDragSort();
-        },
-      });
-
-      // 璋冭瘯锛氭墦鍗板鍣ㄥ拰瀹炰緥锛岀‘璁ょ粦瀹氭垚鍔�
-      console.log("姝ラ鏉℃嫋鎷藉鍣�:", stepsList);
-      console.log("Sortable瀹炰緥:", stepsSortable);
-    }
-  };
-
-  const handleViewChange = () => {
-    destroySortable();
-    // 寤惰繜鍒濆鍖栵紝纭繚瑙嗗浘鍒囨崲鍚嶥OM瀹屽叏娓叉煋
-    nextTick(() => {
-      setTimeout(() => initSortable(), 100);
-    });
-  };
-
-  onMounted(() => {
-    findProcessRouteItems();
-    findProcessList();
-  });
-
-  onUnmounted(() => {
-    destroySortable();
-  });
-
-  defineExpose({
-    closeModal,
-    handleSubmit,
-    isShow,
-  });
-</script>
-
-<style scoped>
-  :deep(.sortable-ghost) {
-    opacity: 0.6;
-    background-color: #f5f7fa !important;
-  }
-
-  :deep(.el-table__row) {
-    transition: background-color 0.2s;
-  }
-
-  :deep(.el-table__row:hover) {
-    background-color: #f9fafc !important;
-  }
-
-  :deep(.el-card__footer) {
-    padding: 0 !important;
-  }
-
-  .operate-button {
-    display: flex;
-    align-items: center;
-    justify-content: space-between;
-  }
-
-  /* 淇敼锛氳嚜瀹氫箟姝ラ鏉″鍣ㄦ牱寮� */
-  .custom-steps {
-    display: flex;
-    flex-wrap: wrap;
-    align-items: flex-start;
-    gap: 20px;
-    min-height: 100px;
-  }
-
-  /* 淇敼锛氳嚜瀹氫箟姝ラ椤规牱寮� */
-  .custom-step {
-    cursor: move !important;
-    padding: 8px;
-    position: relative;
-    transition: all 0.2s ease;
-    flex: 0 0 auto;
-    min-width: 220px;
-    touch-action: none;
-  }
-
-  /* 鎷栨嫿鎮诞鏍峰紡锛屾彁绀哄彲鎷栨嫿 */
-  .custom-step:hover {
-    background-color: rgba(64, 158, 255, 0.05);
-    transform: translateY(-2px);
-  }
-
-  .sortable-ghost {
-    opacity: 0.4;
-    background-color: #f5f7fa !important;
-    border: 2px dashed #409eff;
-    margin: 10px;
-    transform: scale(1.02);
-  }
-
-  .sortable-fallback {
-    opacity: 0.9;
-    background-color: #f5f7fa;
-    border: 1px solid #409eff;
-    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
-    transform: rotate(2deg);
-    margin: 10px;
-  }
-
-  .step-card {
-    cursor: move !important;
-    transition: box-shadow 0.2s ease;
-    user-select: none;
-    -webkit-user-select: none;
-    pointer-events: auto;
-    margin: 10px;
-    height: 240px;
-  }
-
-  .step-card:hover {
-    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
-  }
-
-  .step-content {
-    width: 220px;
-    user-select: none;
-  }
-
-  .step-card-content {
-    display: flex;
-    flex-direction: column;
-    align-items: center;
-  }
-
-  .step-card-footer {
-    display: flex;
-    justify-content: flex-end;
-    align-items: center;
-    padding: 10px;
-  }
-
-  /* 鑷畾涔夊簭鍙锋牱寮忎紭鍖� */
-  .step-number {
-    font-weight: bold;
-    text-align: center;
-    width: 36px;
-    height: 36px;
-    line-height: 36px;
-    margin: 0 auto 10px;
-    background: #409eff;
-    color: #fff;
-    border-radius: 50%;
-    font-size: 14px;
-  }
-</style>
diff --git a/src/views/productionManagement/productionOrder/index.vue b/src/views/productionManagement/productionOrder/index.vue
index df7f950..9250eb8 100644
--- a/src/views/productionManagement/productionOrder/index.vue
+++ b/src/views/productionManagement/productionOrder/index.vue
@@ -8,7 +8,7 @@
                     placeholder="璇疯緭鍏�"
                     clearable
                     prefix-icon="Search"
-                    style="width: 200px;"
+                    style="width: 160px;"
                     @change="handleQuery" />
         </el-form-item>
         <el-form-item label="鍚堝悓鍙�:">
@@ -16,7 +16,7 @@
                     placeholder="璇疯緭鍏�"
                     clearable
                     prefix-icon="Search"
-                    style="width: 200px;"
+                    style="width: 160px;"
                     @change="handleQuery" />
         </el-form-item>
         <el-form-item label="浜у搧鍚嶇О:">
@@ -24,7 +24,7 @@
                     placeholder="璇疯緭鍏�"
                     clearable
                     prefix-icon="Search"
-                    style="width: 200px;"
+                    style="width: 160px;"
                     @change="handleQuery" />
         </el-form-item>
         <el-form-item label="瑙勬牸:">
@@ -32,7 +32,7 @@
                     placeholder="璇疯緭鍏�"
                     clearable
                     prefix-icon="Search"
-                    style="width: 200px;"
+                    style="width: 160px;"
                     @change="handleQuery" />
         </el-form-item>
         <el-form-item>
@@ -50,12 +50,41 @@
                 :tableData="tableData"
                 :page="page"
                 :tableLoading="tableLoading"
-                @pagination="pagination"></PIMTable>
+                @pagination="pagination">
+        <template #completionStatus="{ row }">
+          <el-progress
+            :percentage="toProgressPercentage(row?.completionStatus)"
+            :color="progressColor(toProgressPercentage(row?.completionStatus))"
+            :status="toProgressPercentage(row?.completionStatus) >= 100 ? 'success' : ''"
+          />
+        </template>
+      </PIMTable>
     </div>
-    <process-route-item-form v-if="isShowItemModal"
-                             v-model:visible="isShowItemModal"
-                             :record="record"
-                             @completed="getList" />
+    <el-dialog v-model="bindRouteDialogVisible"
+               title="缁戝畾宸ヨ壓璺嚎"
+               width="500px">
+      <el-form label-width="90px">
+        <el-form-item label="宸ヨ壓璺嚎">
+          <el-select v-model="bindForm.routeId"
+                     placeholder="璇烽�夋嫨宸ヨ壓璺嚎"
+                     style="width: 100%;"
+                     :loading="bindRouteLoading">
+            <el-option v-for="item in routeOptions"
+                       :key="item.id"
+                       :label="`${item.processRouteCode || ''}`"
+                       :value="item.id" />
+          </el-select>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button @click="bindRouteDialogVisible = false">鍙� 娑�</el-button>
+          <el-button type="primary"
+                     :loading="bindRouteSaving"
+                     @click="handleBindRouteConfirm">纭� 璁�</el-button>
+        </span>
+      </template>
+    </el-dialog>
   </div>
 </template>
 
@@ -63,30 +92,75 @@
   import { onMounted, ref } from "vue";
   import { ElMessageBox } from "element-plus";
   import dayjs from "dayjs";
-  import { productOrderListPage } from "@/api/productionManagement/productionOrder.js";
+  import { useRouter } from "vue-router";
+  import {
+    productOrderListPage,
+    listProcessRoute,
+    bindingRoute,
+    listProcessBom,
+  } from "@/api/productionManagement/productionOrder.js";
+  import { listMain as getOrderProcessRouteMain } from "@/api/productionManagement/productProcessRoute.js";
   const { proxy } = getCurrentInstance();
-  import ProcessRouteItemForm from "@/views/productionManagement/productionOrder/ProcessRouteItemForm.vue";
+
+  const router = useRouter();
 
   const tableColumn = ref([
     {
       label: "鐢熶骇璁㈠崟鍙�",
       prop: "npsNo",
+      width: '120px',
     },
     {
       label: "閿�鍞悎鍚屽彿",
       prop: "salesContractNo",
+      width: '150px',
     },
     {
       label: "瀹㈡埛鍚嶇О",
       prop: "customerName",
+      width: '200px',
     },
     {
       label: "浜у搧鍚嶇О",
       prop: "productCategory",
+      width: '120px',
     },
     {
       label: "瑙勬牸",
       prop: "specificationModel",
+      width: '120px',
+    },
+    {
+      label: "宸ヨ壓璺嚎缂栧彿",
+      prop: "processRouteCode",
+      width: '140px',
+    },
+    {
+      label: "闇�姹傛暟閲�",
+      prop: "quantity",
+    },
+    {
+      label: "瀹屾垚鏁伴噺",
+      prop: "completeQuantity",
+    },
+    {
+      dataType: "slot",
+      label: "瀹屾垚杩涘害",
+      prop: "completionStatus",
+      slot: "completionStatus",
+      width: 180,
+    },
+    {
+      label: "寮�濮嬫棩鏈�",
+      prop: "startTime",
+      formatData: val => (val ? dayjs(val).format("YYYY-MM-DD") : ""),
+      width: 120,
+    },
+    {
+      label: "缁撴潫鏃ユ湡",
+      prop: "endTime",
+      formatData: val => (val ? dayjs(val).format("YYYY-MM-DD") : ""),
+      width: 120,
     },
     {
       dataType: "action",
@@ -100,6 +174,21 @@
           type: "text",
           clickFun: row => {
             showRouteItemModal(row);
+          },
+        },
+        {
+          name: "缁戝畾宸ヨ壓璺嚎",
+          type: "text",
+          showHide: row => !row.processRouteCode,
+          clickFun: row => {
+            openBindRouteDialog(row);
+          },
+        },
+        {
+          name: "浜у搧缁撴瀯",
+          type: "text",
+          clickFun: row => {
+            showProductStructure(row);
           },
         },
       ],
@@ -123,6 +212,77 @@
     },
   });
   const { searchForm } = toRefs(data);
+
+  const toProgressPercentage = val => {
+    const n = Number(val);
+    if (!Number.isFinite(n)) return 0;
+    if (n <= 0) return 0;
+    if (n >= 100) return 100;
+    return Math.round(n);
+  };
+
+  // 30/50/80/100 鍒嗘棰滆壊锛氱孩/姗�/钃�/缁�
+  const progressColor = percentage => {
+    const p = toProgressPercentage(percentage);
+    if (p < 30) return "#f56c6c";
+    if (p < 50) return "#e6a23c";
+    if (p < 80) return "#409eff";
+    return "#67c23a";
+  };
+
+  // 缁戝畾宸ヨ壓璺嚎寮规
+  const bindRouteDialogVisible = ref(false);
+  const bindRouteLoading = ref(false);
+  const bindRouteSaving = ref(false);
+  const routeOptions = ref([]);
+  const bindForm = reactive({
+    orderId: null,
+    routeId: null,
+  });
+
+  const openBindRouteDialog = async row => {
+    bindForm.orderId = row.id;
+    bindForm.routeId = null;
+    bindRouteDialogVisible.value = true;
+    routeOptions.value = [];
+    if (!row.productModelId) {
+      proxy.$modal.msgWarning("褰撳墠璁㈠崟缂哄皯浜у搧鍨嬪彿锛屾棤娉曟煡璇㈠伐鑹鸿矾绾�");
+      bindRouteDialogVisible.value = false;
+      return;
+    }
+    bindRouteLoading.value = true;
+    try {
+      const res = await listProcessRoute({ productModelId: row.productModelId });
+      routeOptions.value = res.data || [];
+    } catch (e) {
+      console.error("鑾峰彇宸ヨ壓璺嚎鍒楄〃澶辫触锛�", e);
+      proxy.$modal.msgError("鑾峰彇宸ヨ壓璺嚎鍒楄〃澶辫触");
+    } finally {
+      bindRouteLoading.value = false;
+    }
+  };
+
+  const handleBindRouteConfirm = async () => {
+    if (!bindForm.routeId) {
+      proxy.$modal.msgWarning("璇烽�夋嫨宸ヨ壓璺嚎");
+      return;
+    }
+    bindRouteSaving.value = true;
+    try {
+      await bindingRoute({
+        id: bindForm.orderId,
+        routeId: bindForm.routeId,
+      });
+      proxy.$modal.msgSuccess("缁戝畾鎴愬姛");
+      bindRouteDialogVisible.value = false;
+      getList();
+    } catch (e) {
+      console.error("缁戝畾宸ヨ壓璺嚎澶辫触锛�", e);
+      proxy.$modal.msgError("缁戝畾宸ヨ壓璺嚎澶辫触");
+    } finally {
+      bindRouteSaving.value = false;
+    }
+  };
 
   // 鏌ヨ鍒楄〃
   /** 鎼滅储鎸夐挳鎿嶄綔 */
@@ -161,11 +321,46 @@
       });
   };
 
-  const isShowItemModal = ref(false);
-  const record = ref({});
-  const showRouteItemModal = row => {
-    isShowItemModal.value = true;
-    record.value = row;
+  const showRouteItemModal = async row => {
+    const orderId = row.id;
+    try {
+      const res = await getOrderProcessRouteMain(orderId);
+      const data = res.data || {};
+      if (!data || !data.id) {
+        proxy.$modal.msgWarning("鏈壘鍒板叧鑱旂殑宸ヨ壓璺嚎");
+        return;
+      }
+      router.push({
+        path: "/productionManagement/processRouteItem",
+        query: {
+          id: data.id,
+          processRouteCode: data.processRouteCode || "",
+          productName: data.productName || "",
+          model: data.model || "",
+          bomNo: data.bomNo || "",
+          description: data.description || "",
+          orderId,
+          type: "order",
+        },
+      });
+    } catch (e) {
+      console.error("鑾峰彇宸ヨ壓璺嚎涓讳俊鎭け璐ワ細", e);
+      proxy.$modal.msgError("鑾峰彇宸ヨ壓璺嚎淇℃伅澶辫触");
+    }
+  };
+
+  const showProductStructure = row => {
+    router.push({
+      path: "/productionManagement/productStructureDetail",
+      query: {
+        id: row.id,
+        bomNo: row.bomNo || "",
+        productName: row.productCategory || "",
+        productModelName: row.specificationModel || "",
+        orderId: row.id,
+        type: "order",
+      },
+    });
   };
 
   // 瀵煎嚭
@@ -176,7 +371,7 @@
       type: "warning",
     })
       .then(() => {
-        proxy.download("/salesLedger/scheduling/export", {}, "鐢熶骇璁㈠崟.xlsx");
+        proxy.download("/productOrder/export", {...searchForm.value}, "鐢熶骇璁㈠崟.xlsx");
       })
       .catch(() => {
         proxy.$modal.msg("宸插彇娑�");
@@ -190,4 +385,7 @@
   });
 </script>
 
-<style scoped lang="scss"></style>
+<style scoped lang="scss">
+.search_form{
+  align-items: start;
+}</style>
diff --git a/src/views/productionManagement/productionProcess/Edit.vue b/src/views/productionManagement/productionProcess/Edit.vue
index 31e3109..f979d51 100644
--- a/src/views/productionManagement/productionProcess/Edit.vue
+++ b/src/views/productionManagement/productionProcess/Edit.vue
@@ -22,6 +22,9 @@
             ]">
           <el-input v-model="formState.name" />
         </el-form-item>
+        <el-form-item label="宸ュ簭缂栧彿" prop="no">
+          <el-input v-model="formState.no"  />
+        </el-form-item>
         <el-form-item label="宸ヨ祫瀹氶" prop="salaryQuota">
           <el-input v-model="formState.salaryQuota" type="number" :step="0.001" />
         </el-form-item>
@@ -40,7 +43,7 @@
 </template>
 
 <script setup>
-import { ref, computed, getCurrentInstance } from "vue";
+import { ref, computed, getCurrentInstance, watch } from "vue";
 import {update} from "@/api/productionManagement/productionProcess.js";
 
 const props = defineProps({
@@ -61,6 +64,7 @@
 const formState = ref({
   id: props.record.id,
   name: props.record.name,
+  no: props.record.no,
   remark: props.record.remark,
   salaryQuota: props.record.salaryQuota,
 });
@@ -74,6 +78,32 @@
   },
 });
 
+// 鐩戝惉 record 鍙樺寲锛屾洿鏂拌〃鍗曟暟鎹�
+watch(() => props.record, (newRecord) => {
+  if (newRecord && isShow.value) {
+    formState.value = {
+      id: newRecord.id,
+      name: newRecord.name || '',
+      no: newRecord.no || '',
+      remark: newRecord.remark || '',
+      salaryQuota: newRecord.salaryQuota || '',
+    };
+  }
+}, { immediate: true, deep: true });
+
+// 鐩戝惉寮圭獥鎵撳紑锛岄噸鏂板垵濮嬪寲琛ㄥ崟鏁版嵁
+watch(() => props.visible, (visible) => {
+  if (visible && props.record) {
+    formState.value = {
+      id: props.record.id,
+      name: props.record.name || '',
+      no: props.record.no || '',
+      remark: props.record.remark || '',
+      salaryQuota: props.record.salaryQuota || '',
+    };
+  }
+});
+
 let { proxy } = getCurrentInstance()
 
 const closeModal = () => {
diff --git a/src/views/productionManagement/productionProcess/New.vue b/src/views/productionManagement/productionProcess/New.vue
index a73a755..7558ba7 100644
--- a/src/views/productionManagement/productionProcess/New.vue
+++ b/src/views/productionManagement/productionProcess/New.vue
@@ -22,6 +22,9 @@
             ]">
           <el-input v-model="formState.name" />
         </el-form-item>
+        <el-form-item label="宸ュ簭缂栧彿" prop="no">
+          <el-input v-model="formState.no"  />
+        </el-form-item>
         <el-form-item label="宸ヨ祫瀹氶" prop="salaryQuota">
           <el-input v-model="formState.salaryQuota" type="number" :step="0.001" />
         </el-form-item>
diff --git a/src/views/productionManagement/productionProcess/index.vue b/src/views/productionManagement/productionProcess/index.vue
index ea2a341..7ab8c9a 100644
--- a/src/views/productionManagement/productionProcess/index.vue
+++ b/src/views/productionManagement/productionProcess/index.vue
@@ -30,6 +30,7 @@
            class="mb10">
         <el-button type="primary"
                    @click="showNewModal">鏂板宸ュ簭</el-button>
+        <el-button type="info" plain @click="handleImport">瀵煎叆</el-button>
         <el-button type="danger"
                    @click="handleDelete"
                    :disabled="selectedRows.length === 0"
@@ -52,14 +53,29 @@
                   v-model:visible="isShowEditModal"
                   :record="record"
                   @completed="getList" />
+    <ImportDialog
+      ref="importDialogRef"
+      v-model="importDialogVisible"
+      title="瀵煎叆宸ュ簭"
+      :action="importAction"
+      :headers="importHeaders"
+      :auto-upload="false"
+      :on-success="handleImportSuccess"
+      :on-error="handleImportError"
+      @confirm="handleImportConfirm"
+      @download-template="handleDownloadTemplate"
+      @close="handleImportClose"
+    />
   </div>
 </template>
 
 <script setup>
-  import { onMounted, ref } from "vue";
+  import { onMounted, ref, reactive, toRefs, getCurrentInstance } from "vue";
   import NewProcess from "@/views/productionManagement/productionProcess/New.vue";
   import EditProcess from "@/views/productionManagement/productionProcess/Edit.vue";
-  import { listPage, del } from "@/api/productionManagement/productionProcess.js";
+  import ImportDialog from "@/components/Dialog/ImportDialog.vue";
+  import { listPage, del, importData, downloadTemplate } from "@/api/productionManagement/productionProcess.js";
+  import { getToken } from "@/utils/auth";
 
   const data = reactive({
     searchForm: {
@@ -70,13 +86,14 @@
   const { searchForm } = toRefs(data);
   const tableColumn = ref([
     {
-      label: "宸ュ簭鍚嶇О",
-      prop: "name",
-    },
-    {
       label: "宸ュ簭缂栧彿",
       prop: "no",
     },
+    {
+      label: "宸ュ簭鍚嶇О",
+      prop: "name",
+    },
+   
     {
       label: "宸ヨ祫瀹氶",
       prop: "salaryQuota",
@@ -84,6 +101,10 @@
     {
       label: "澶囨敞",
       prop: "remark",
+    },
+     {
+      label: "鏇存柊鏃堕棿",
+      prop: "updateTime",
     },
     {
       dataType: "action",
@@ -108,12 +129,18 @@
   const isShowNewModal = ref(false);
   const isShowEditModal = ref(false);
   const record = ref({});
+  const importDialogVisible = ref(false);
+  const importDialogRef = ref(null);
   const page = reactive({
     current: 1,
     size: 100,
     total: 0,
   });
   const { proxy } = getCurrentInstance();
+  
+  // 瀵煎叆鐩稿叧閰嶇疆
+  const importAction = import.meta.env.VITE_APP_BASE_API + "/productProcess/importData";
+  const importHeaders = { Authorization: "Bearer " + getToken() };
 
   // 鏌ヨ鍒楄〃
   /** 鎼滅储鎸夐挳鎿嶄綔 */
@@ -195,6 +222,63 @@
     }
   }
 
+  // 瀵煎叆
+  const handleImport = () => {
+    importDialogVisible.value = true;
+  };
+
+  // 纭瀵煎叆
+  const handleImportConfirm = () => {
+    if (importDialogRef.value) {
+      importDialogRef.value.submit();
+    }
+  };
+
+  // 瀵煎叆鎴愬姛
+  const handleImportSuccess = (response) => {
+    if (response.code === 200) {
+      proxy.$modal.msgSuccess("瀵煎叆鎴愬姛");
+      importDialogVisible.value = false;
+      if (importDialogRef.value) {
+        importDialogRef.value.clearFiles();
+      }
+      getList();
+    } else {
+      proxy.$modal.msgError(response.msg || "瀵煎叆澶辫触");
+    }
+  };
+
+  // 瀵煎叆澶辫触
+  const handleImportError = (error) => {
+    proxy.$modal.msgError("瀵煎叆澶辫触锛�" + (error.message || "鏈煡閿欒"));
+  };
+
+  // 鍏抽棴瀵煎叆寮圭獥
+  const handleImportClose = () => {
+    if (importDialogRef.value) {
+      importDialogRef.value.clearFiles();
+    }
+  };
+
+  // 涓嬭浇妯℃澘
+  const handleDownloadTemplate = async () => {
+    try {
+      const res = await downloadTemplate();
+      const blob = new Blob([res], {
+        type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+      });
+      const url = window.URL.createObjectURL(blob);
+      const link = document.createElement("a");
+      link.href = url;
+      link.download = "宸ュ簭瀵煎叆妯℃澘.xlsx";
+      link.click();
+      window.URL.revokeObjectURL(url);
+      proxy.$modal.msgSuccess("妯℃澘涓嬭浇鎴愬姛");
+    } catch (error) {
+      proxy.$modal.msgError("妯℃澘涓嬭浇澶辫触");
+    }
+  };
+
   // 瀵煎嚭
   // const handleOut = () => {
   // 	ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
diff --git a/src/views/productionManagement/productionReporting/Input.vue b/src/views/productionManagement/productionReporting/Input.vue
index 7959848..3ba68f7 100644
--- a/src/views/productionManagement/productionReporting/Input.vue
+++ b/src/views/productionManagement/productionReporting/Input.vue
@@ -59,13 +59,21 @@
     prop: 'productNo',
   },
   {
-    label: '浜у搧鍨嬪彿',
+    label: '鎶曞叆浜у搧鍚嶇О',
+    prop: 'productName',
+  },
+  {
+    label: '鎶曞叆浜у搧鍨嬪彿',
     prop: 'model',
   },
   {
     label: '鎶曞叆鏁伴噺',
     prop: 'quantity',
   },
+  {
+    label: '鍗曚綅',
+    prop: 'unit',
+  },
 ]
 
 const isShow = computed({
diff --git a/src/views/productionManagement/productionReporting/index.vue b/src/views/productionManagement/productionReporting/index.vue
index b34b14e..f4137af 100644
--- a/src/views/productionManagement/productionReporting/index.vue
+++ b/src/views/productionManagement/productionReporting/index.vue
@@ -115,7 +115,7 @@
               </template>
             </el-table-column>
             <el-table-column label="鎿嶄綔"
-                             width="60">
+                             >
               <template #default="scope">
                 <el-button link
                            type="primary"
@@ -139,9 +139,6 @@
     <input-modal v-if="isShowInput"
                  v-model:visible="isShowInput"
                  :production-product-main-id="isShowingId" />
-    <output-modal v-if="isShowOutput"
-                  v-model:visible="isShowOutput"
-                  :production-product-main-id="isShowingId" />
   </div>
 </template>
 
@@ -157,7 +154,6 @@
   import { productionProductMainListPage } from "@/api/productionManagement/productionProductMain.js";
   import { userListNoPageByTenantId } from "@/api/system/user.js";
   import InputModal from "@/views/productionManagement/productionReporting/Input.vue";
-  import OutputModal from "@/views/productionManagement/productionReporting/Output.vue";
 
   const data = reactive({
     searchForm: {
@@ -187,92 +183,52 @@
       width: 120,
     },
     {
-      label: "鎶ュ伐鐘舵��",
-      prop: "status",
-      dataType: "tag",
-      formatData: params => {
-        if (params == 3) {
-          return "宸叉姤宸�";
-        } else if (params == 1) {
-          return "寰呯敓浜�";
-        } else {
-          return "鐢熶骇涓�";
-        }
-      },
-      formatType: params => {
-        if (params == 3) {
-          return "success";
-        } else if (params == 1) {
-          return "primary";
-        } else {
-          return "warning";
-        }
-      },
+      label: "閿�鍞悎鍚屽彿",
+      prop: "salesContractNo",
+      width: 120,
     },
     {
-      label: "宸ュ崟鐘舵��",
-      prop: "workOrderStatus",
-      dataType: "tag",
-      formatData: params => {
-        switch (params) {
-          case "1":
-            return "寰呯‘璁�";
-          case "2":
-            return "寰呯敓浜�";
-          case "3":
-            return "鐢熶骇涓�";
-          case "4":
-            return "宸茬敓浜�";
-          default:
-            return "";
-        }
-      },
-      formatType: params => {
-        switch (params) {
-          case "1":
-            return "primary";
-          case "2":
-            return "info";
-          case "3":
-            return "warning";
-          case "4":
-            return "success";
-          default:
-            return "";
-        }
-      },
+      label: "浜у搧鍚嶇О",
+      prop: "productName",
+      width: 120,
     },
     {
-      label: "鐢熶骇鏃堕棿",
+      label: "浜у搧瑙勬牸鍨嬪彿",
+      prop: "productModelName",
+      width: 120,
+    },
+    {
+      label: "浜у嚭鏁伴噺",
+      prop: "quantity",
+      width: 120,
+    },
+    // {
+    //   label: "鎶ュ簾鏁伴噺",
+    //   prop: "scrapQuantity",
+    //   width: 120,
+    // },
+    {
+      label: "鍗曚綅",
+      prop: "unit",
+      width: 120,
+    },
+    
+    {
+      label: "鍒涘缓鏃堕棿",
       prop: "createTime",
       width: 120,
-      formatData: params => {
-        const date = new Date(params);
-        return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(
-          2,
-          "0"
-        )}-${String(date.getDate()).padStart(2, "0")}`;
-      },
     },
     {
       dataType: "action",
       label: "鎿嶄綔",
       align: "center",
       fixed: "right",
-      width: 230,
       operation: [
         {
           name: "鏌ョ湅鎶曞叆",
           type: "text",
           clickFun: row => {
             showInput(row);
-          },
-        },
-        {
-          name: "鏌ョ湅浜у嚭",
-          type: "text",
-          clickFun: row => {
-            showOutput(row);
           },
         },
         {
@@ -449,13 +405,6 @@
   const isShowingId = ref(0);
   const showInput = row => {
     isShowInput.value = true;
-    isShowingId.value = row.id;
-  };
-
-  // 鎵撳紑浜у嚭妯℃�佹
-  const isShowOutput = ref(false);
-  const showOutput = row => {
-    isShowOutput.value = true;
     isShowingId.value = row.id;
   };
 
diff --git a/src/views/productionManagement/workOrder/index.vue b/src/views/productionManagement/workOrder/index.vue
index 34b368d..f5d2bc1 100644
--- a/src/views/productionManagement/workOrder/index.vue
+++ b/src/views/productionManagement/workOrder/index.vue
@@ -23,7 +23,11 @@
                 :tableData="tableData"
                 :page="page"
                 :tableLoading="tableLoading"
-                @pagination="pagination"></PIMTable>
+                @pagination="pagination">
+                <template #completionStatus="{ row }">
+                  <el-progress :percentage="toProgressPercentage(row?.completionStatus)" :color="progressColor(toProgressPercentage(row?.completionStatus))" :status="toProgressPercentage(row?.completionStatus) >= 100 ? 'success' : ''" />
+                </template>
+              </PIMTable>
     </div>
     <el-dialog v-model="editDialogVisible"
                title="缂栬緫鏃堕棿"
@@ -90,7 +94,7 @@
               <span class="info-label">浜у搧瑙勬牸</span>
               <span class="info-value">{{ transferCardRowData.model }}</span>
             </div>
-            <div class="info-item">
+            <!-- <div class="info-item">
               <span class="info-label">宸ュ崟鐘舵��</span>
               <span class="info-value">{{ 
                 transferCardRowData.status === 1 ? '寰呯‘璁�' : 
@@ -99,7 +103,8 @@
                 transferCardRowData.status === 4 ? '宸茬敓浜�' : 
                 transferCardRowData.status 
               }}</span>
-            </div>
+            </div> -->
+           
             <div class="info-item">
               <span class="info-label">璁″垝寮�濮嬫椂闂�</span>
               <span class="info-value">{{ transferCardRowData.planStartTime }}</span>
@@ -115,12 +120,12 @@
           </div>
           <div class="info-group">
             <div class="info-item">
-              <span class="info-label">&nbsp;</span>
-              <span class="info-value">&nbsp;</span>
+              <span class="info-label">闇�姹傛暟閲�</span>
+              <span class="info-value">{{ transferCardRowData.planQuantity }}</span>
             </div>
             <div class="info-item">
-              <span class="info-label">璁″垝鏁伴噺</span>
-              <span class="info-value">{{ transferCardRowData.planQuantity }}</span>
+              <span class="info-label">瀹屾垚鏁伴噺</span>
+              <span class="info-value">{{ transferCardRowData.completeQuantity }}</span>
             </div>
             <div class="info-item">
               <span class="info-label">鑹搧鏁伴噺</span>
@@ -176,10 +181,17 @@
                     placeholder="璇疯緭鍏ユ湰娆$敓浜ф暟閲�" />
         </el-form-item>
         <el-form-item label="鐝粍淇℃伅">
-          <el-input v-model="reportForm.userName"
-                    style="width: 300px"
-                    readonly
-                    placeholder="璇疯緭鍏ョ彮缁勪俊鎭�" />
+          <el-select v-model="reportForm.userId"
+                     style="width: 300px"
+                     placeholder="璇烽�夋嫨鐝粍淇℃伅"
+                     clearable
+                     filterable
+                     @change="handleUserChange">
+            <el-option v-for="user in userOptions"
+                       :key="user.userId"
+                       :label="user.userName"
+                       :value="user.userId" />
+          </el-select>
         </el-form-item>
       </el-form>
       <template #footer>
@@ -202,7 +214,7 @@
     updateProductWorkOrder,
     addProductMain,
   } from "@/api/productionManagement/workOrder.js";
-  import { getUserProfile } from "@/api/system/user.js";
+  import { getUserProfile, userListNoPageByTenantId } from "@/api/system/user.js";
   import QRCode from "qrcode";
   import { getCurrentInstance, reactive, toRefs } from "vue";
   const { proxy } = getCurrentInstance();
@@ -236,13 +248,20 @@
       prop: "processName",
     },
     {
-      label: "寰呯敓浜ф暟閲�",
+      label: "闇�姹傛暟閲�",
       prop: "planQuantity",
       width: "140",
     },
     {
-      label: "璁″垝鐢熶骇鏁伴噺",
-      prop: "quantity",
+      label: "瀹屾垚鏁伴噺",
+      prop: "completeQuantity",
+      width: "140",
+    },
+    {
+      label: "瀹屾垚杩涘害",
+      prop: "completionStatus",
+      dataType: "slot",
+      slot: "completionStatus",
       width: "140",
     },
     {
@@ -304,6 +323,7 @@
   const transferCardQrUrl = ref("");
   const transferCardRowData = ref(null);
   const reportDialogVisible = ref(false);
+  const userOptions = ref([]);
   const reportForm = reactive({
     planQuantity: 0,
     quantity: 0,
@@ -327,6 +347,20 @@
     },
   });
   const { searchForm } = toRefs(data);
+  const toProgressPercentage = val => {
+    const n = Number(val);
+    if (!Number.isFinite(n)) return 0;
+    if (n <= 0) return 0;
+    if (n >= 100) return 100;
+    return Math.round(n);
+  };
+  const progressColor = percentage => {
+    const p = toProgressPercentage(percentage);
+    if (p < 30) return "#f56c6c";
+    if (p < 50) return "#e6a23c";
+    if (p < 80) return "#409eff";
+    return "#67c23a";
+  };
   let editrow = ref(null);
 
   // 鏌ヨ鍒楄〃
@@ -356,9 +390,7 @@
 
   const showTransferCard = async row => {
     transferCardRowData.value = row;
-    const qrContent =
-      proxy.javaApi + "/work-order?orderRow=" + JSON.stringify(row);
-    console.log(qrContent, "qrContent");
+    const qrContent = String(row.id);
 
     transferCardQrUrl.value = await QRCode.toDataURL(qrContent);
     transferCardVisible.value = true;
@@ -395,7 +427,17 @@
     reportForm.workOrderId = row.id;
     reportForm.reportWork = row.reportWork;
     reportForm.productMainId = row.productMainId;
-    // 鑾峰彇褰撳墠鐧诲綍鐢ㄦ埛淇℃伅
+    // 鑾峰彇褰撳墠鐧诲綍鐢ㄦ埛淇℃伅锛岃缃负榛樿閫変腑
+    getUserProfile()
+      .then(res => {
+        if (res.code === 200) {
+          reportForm.userId = res.data.userId;
+          reportForm.userName = res.data.userName;
+        }
+      })
+      .catch(err => {
+        console.error("鑾峰彇鐢ㄦ埛淇℃伅澶辫触", err);
+      });
 
     reportDialogVisible.value = true;
   };
@@ -433,18 +475,34 @@
     });
   };
 
-  onMounted(() => {
-    getList();
-    getUserProfile()
+  // 鑾峰彇鐢ㄦ埛鍒楄〃
+  const getUserList = () => {
+    userListNoPageByTenantId()
       .then(res => {
         if (res.code === 200) {
-          reportForm.userName = res.data.userName;
-          reportForm.userId = res.data.userId;
+          userOptions.value = res.data || [];
         }
       })
       .catch(err => {
-        console.error("鑾峰彇鐢ㄦ埛淇℃伅澶辫触", err);
+        console.error("鑾峰彇鐢ㄦ埛鍒楄〃澶辫触", err);
       });
+  };
+
+  // 鐢ㄦ埛閫夋嫨鍙樺寲鏃舵洿鏂� userName
+  const handleUserChange = (userId) => {
+    if (userId) {
+      const selectedUser = userOptions.value.find(user => user.userId === userId);
+      if (selectedUser) {
+        reportForm.userName = selectedUser.userName;
+      }
+    } else {
+      reportForm.userName = "";
+    }
+  };
+
+  onMounted(() => {
+    getList();
+    getUserList();
   });
 </script>
 
diff --git a/src/views/salesManagement/receiptPayment/index.vue b/src/views/salesManagement/receiptPayment/index.vue
index 40e6f14..66af76a 100644
--- a/src/views/salesManagement/receiptPayment/index.vue
+++ b/src/views/salesManagement/receiptPayment/index.vue
@@ -523,7 +523,7 @@
     receiptPaymentType: row.receiptPaymentType,
     receiptPaymentAmount: row.receiptPaymentAmount,
   };
-  receiptPaymentSaveOrUpdate(updateData).then((res) => {
+  receiptPaymentSaveOrUpdate([updateData]).then((res) => {
     row.editType = !row.editType;
 		getList();
 		proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
diff --git a/src/views/salesManagement/receiptPaymentHistory/index.vue b/src/views/salesManagement/receiptPaymentHistory/index.vue
index 7bcb433..f66bed7 100644
--- a/src/views/salesManagement/receiptPaymentHistory/index.vue
+++ b/src/views/salesManagement/receiptPaymentHistory/index.vue
@@ -27,6 +27,13 @@
       <el-form-item>
         <el-button type="primary" @click="handleQuery"> 鎼滅储 </el-button>
         <el-button @click="handleExport">瀵煎嚭</el-button>
+        <el-button
+          type="danger"
+          :disabled="selectedRows.length === 0"
+          @click="handleBatchDelete"
+        >
+          鎵归噺鍒犻櫎 ({{ selectedRows.length }})
+        </el-button>
       </el-form-item>
     </el-form>
     <div class="table_list">
@@ -42,7 +49,18 @@
         :total="page.total"
         @pagination="pagination"
         @selection-change="handleSelectionChange"
-      ></PIMTable>
+      >
+        <template #operation="{ row }">
+          <el-button
+            type="primary"
+            link
+            size="small"
+            @click="handleDelete(row)"
+          >
+            鍒犻櫎
+          </el-button>
+        </template>
+      </PIMTable>
     </div>
   </div>
 </template>
@@ -50,7 +68,8 @@
 <script setup>
 import { ref, reactive, getCurrentInstance, onMounted } from "vue";
 import { Search } from "@element-plus/icons-vue";
-import { receiptPaymentHistoryListPage } from "@/api/salesManagement/receiptPayment.js";
+import { ElMessageBox } from "element-plus";
+import { receiptPaymentHistoryListPage, receiptPaymentDel } from "@/api/salesManagement/receiptPayment.js";
 import useFormData from "@/hooks/useFormData";
 import dayjs from "dayjs";
 
@@ -104,6 +123,14 @@
     label: "鐧昏鏃ユ湡",
     prop: "createTime",
     width:100
+  },
+  {
+    label: "鎿嶄綔",
+    dataType: "slot",
+    fixed: "right",
+    slot: "operation",
+    width: 100,
+    align: "center",
   },
 ]);
 const tableData = ref([]);
@@ -175,6 +202,66 @@
   getList();
 };
 
+// 鍒犻櫎
+const handleDelete = (row) => {
+  ElMessageBox.confirm("纭鍒犻櫎璇ヨ褰曞悧锛�", "鎻愮ず", {
+    confirmButtonText: "纭畾",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  })
+    .then(async () => {
+      try {
+        tableLoading.value = true;
+        await receiptPaymentDel([row.id]);
+        proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+        getList();
+      } catch (error) {
+        console.error("鍒犻櫎澶辫触:", error);
+        proxy.$modal.msgError("鍒犻櫎澶辫触");
+      } finally {
+        tableLoading.value = false;
+      }
+    })
+    .catch(() => {
+      proxy.$modal.msg("宸插彇娑堝垹闄�");
+    });
+};
+
+// 鎵归噺鍒犻櫎
+const handleBatchDelete = () => {
+  if (selectedRows.value.length === 0) {
+    proxy.$modal.msgWarning("璇烽�夋嫨瑕佸垹闄ょ殑鏁版嵁");
+    return;
+  }
+  ElMessageBox.confirm(
+    `纭畾瑕佸垹闄ら�変腑鐨� ${selectedRows.value.length} 鏉℃暟鎹悧锛焋,
+    "鍒犻櫎鎻愮ず",
+    {
+      confirmButtonText: "纭",
+      cancelButtonText: "鍙栨秷",
+      type: "warning",
+    }
+  )
+    .then(async () => {
+      try {
+        tableLoading.value = true;
+        const ids = selectedRows.value.map((item) => item.id);
+        await receiptPaymentDel(ids);
+        proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+        selectedRows.value = [];
+        getList();
+      } catch (error) {
+        console.error("鍒犻櫎澶辫触:", error);
+        proxy.$modal.msgError("鍒犻櫎澶辫触");
+      } finally {
+        tableLoading.value = false;
+      }
+    })
+    .catch(() => {
+      proxy.$modal.msg("宸插彇娑�");
+    });
+};
+
 // 瀵煎嚭
 const handleExport = () => {
   const { receiptPaymentDate, ...rest } = searchForm;

--
Gitblit v1.9.3