From 0c2901e13dcc61ebae45aa7433d71b43bbf56d25 Mon Sep 17 00:00:00 2001
From: zhangwencui <1064582902@qq.com>
Date: 星期三, 22 四月 2026 15:42:17 +0800
Subject: [PATCH] Merge branch 'dev_New' into dev_NEW_pro

---
 src/views/basicData/product/ProductSelectDialog.vue                                |   27 
 src/views/customerService/feedbackRegistration/components/formDia.vue              |    6 
 src/views/productionManagement/workOrderManagement/components/MaterialDialog.vue   |  278 ++++
 src/api/productionManagement/workOrder.js                                          |   45 
 src/views/basicData/product/index.vue                                              |   17 
 src/api/productionManagement/productionOrder.js                                    |   47 
 src/views/salesManagement/salesLedger/index.vue                                    |   97 +
 src/views/qualityManagement/finalInspection/index.vue                              |  260 ++-
 src/views/productionManagement/productionProcess/Edit.vue                          |    0 
 src/views/productionManagement/workOrderManagement/index.vue                       |   34 
 src/views/productionManagement/productionOrder/components/MaterialLedgerDialog.vue |  298 ++++
 src/views/basicData/customerFile/index.vue                                         |  102 
 src/views/salesManagement/returnOrder/components/formDia.vue                       |   19 
 src/views/procurementManagement/procurementReport/index.vue                        |    1 
 src/api/basicData/customerFile.js                                                  |  104 +
 src/store/modules/permission.js                                                    |    1 
 src/views/basicData/customerFileOpenSea/index.vue                                  | 1794 +++++++++++++++++++++++++++
 src/views/salesManagement/salesQuotation/index.vue                                 |   32 
 src/views/productionManagement/workOrderEdit/index.vue                             |  459 +++---
 src/views/productionManagement/productStructure/Detail/index.vue                   |    2 
 src/views/productionManagement/productionOrder/components/MaterialDetailDialog.vue |  181 ++
 src/views/procurementManagement/procurementLedger/index.vue                        |    6 
 src/views/customerService/feedbackRegistration/index.vue                           |    3 
 src/views/productionManagement/productionOrder/index.vue                           |   71 
 src/api/basicData/productModel.js                                                  |    8 
 src/views/procurementManagement/purchaseReturnOrder/New.vue                        |    1 
 src/views/productionManagement/productionProcess/New.vue                           |    0 
 27 files changed, 3,391 insertions(+), 502 deletions(-)

diff --git a/src/api/basicData/customerFile.js b/src/api/basicData/customerFile.js
index 6a5f049..7b6d7c6 100644
--- a/src/api/basicData/customerFile.js
+++ b/src/api/basicData/customerFile.js
@@ -1,7 +1,5 @@
-// 瀹㈡埛妗f椤甸潰鎺ュ彛
 import request from '@/utils/request'
 
-// 鍒嗛〉鏌ヨ
 export function listCustomer(query) {
     return request({
         url: '/basic/customer/list',
@@ -9,14 +7,76 @@
         params: query
     })
 }
-// 鏌ヨ瀹㈡埛妗f璇︾粏
+
+// 瀹㈡埛妗f绉佹捣鏌ヨ
+export function listCustomerPrivatePool(query) {
+    return request({
+        url: '/customerPrivatePool/listPage',
+        method: 'get',
+        params: query
+    })
+}
+
+export function addCustomerPrivatePool(data) {
+    return request({
+        url: '/customerPrivatePool/add',
+        method: 'post',
+        data: data
+    })
+}
+
+export function addCustomerPrivate(data) {
+    return request({
+        url: '/customerPrivate/add',
+        method: 'post',
+        data: data
+    })
+}
+
+export function delCustomerPrivate(ids) {
+    return request({
+        url: '/customerPrivate/delete',
+        method: 'delete',
+        data: ids
+    })
+}
+
+export function delCustomerPrivatePool(id) {
+    return request({
+        url: '/customerPrivatePool/delete/' + id,
+        method: 'delete',
+    })
+}
+
+export function shareCustomer(data) {
+    return request({
+        url: '/customerPrivatePool/together',
+        method: 'post',
+        data: data
+    })
+}
+
 export function getCustomer(id) {
     return request({
         url: '/basic/customer/' + id,
         method: 'get'
     })
 }
-// 鏂板瀹㈡埛妗f
+
+export function getCustomerPrivatePoolById(id) {
+    return request({
+        url: '/customerPrivatePool/getbyId/' + id,
+        method: 'get'
+    })
+}
+
+export function getCustomerPrivatePoolInfo(id) {
+    return request({
+        url: '/customerPrivatePool/info/' + id,
+        method: 'get'
+    })
+}
+
 export function addCustomer(data) {
     return request({
         url: '/basic/customer/addCustomer',
@@ -24,7 +84,7 @@
         data: data
     })
 }
-// 淇敼瀹㈡埛妗f
+
 export function updateCustomer(data) {
     return request({
         url: '/basic/customer/updateCustomer',
@@ -32,7 +92,15 @@
         data: data
     })
 }
-// 瀵煎嚭瀹㈡埛妗f
+
+export function updateCustomerPrivatePool(data) {
+    return request({
+        url: '/customerPrivatePool/update',
+        method: 'put',
+        data: data
+    })
+}
+
 export function exportCustomer(query) {
     return request({
         url: '/basic/customer/export',
@@ -41,7 +109,7 @@
         responseType: 'blob'
     })
 }
-// 鍒犻櫎瀹㈡埛妗f
+
 export function delCustomer(ids) {
     return request({
         url: '/basic/customer/delCustomer',
@@ -50,8 +118,6 @@
     })
 }
 
-
-// 鏂板瀹㈡埛璺熻繘
 export function addCustomerFollow(data) {
     return request({
         url: '/basic/customer-follow/add',
@@ -60,23 +126,21 @@
     })
 }
 
-// 淇敼瀹㈡埛璺熻繘
 export function updateCustomerFollow(data) {
-  return request({
-    url: '/basic/customer-follow/edit',
-    method: 'put',
-    data: data,
-  })
+    return request({
+        url: '/basic/customer-follow/edit',
+        method: 'put',
+        data: data,
+    })
 }
-// 鍒犻櫎瀹㈡埛璺熻繘
+
 export function delCustomerFollow(id) {
     return request({
-        url: '/basic/customer-follow/'+id,
+        url: '/basic/customer-follow/' + id,
         method: 'delete',
     })
 }
 
-// 鍥炶鎻愰啋-鏂板/鏇存柊
 export function addReturnVisit(data) {
     return request({
         url: '/basic/customer-follow/return-visit',
@@ -84,10 +148,10 @@
         data: data
     })
 }
-// 鑾峰彇鍥炶鎻愰啋璇︽儏
+
 export function getReturnVisit(id) {
     return request({
         url: '/basic/customer-follow/return-visit/' + id,
         method: 'get'
     })
-}
\ No newline at end of file
+}
diff --git a/src/api/basicData/productModel.js b/src/api/basicData/productModel.js
index f048f9e..8acc2ef 100644
--- a/src/api/basicData/productModel.js
+++ b/src/api/basicData/productModel.js
@@ -6,4 +6,12 @@
         method: 'get',
         params: query
     })
+}
+
+export function productModelListByUrl(url, query) {
+    return request({
+        url,
+        method: 'get',
+        params: query
+    })
 }
\ No newline at end of file
diff --git a/src/api/productionManagement/productionOrder.js b/src/api/productionManagement/productionOrder.js
index 6c8dbe2..b8468eb 100644
--- a/src/api/productionManagement/productionOrder.js
+++ b/src/api/productionManagement/productionOrder.js
@@ -61,6 +61,51 @@
   });
 }
 
+// 鐢熶骇璁㈠崟-棰嗘枡鍙拌处鍒楄〃
+export function listMaterialPickingLedger(query) {
+  return request({
+    url: "/productOrderMaterial/list",
+    method: "get",
+    params: query,
+  });
+}
+
+// 鐢熶骇璁㈠崟-淇濆瓨棰嗘枡鍙拌处
+export function saveMaterialPickingLedger(data) {
+  return request({
+    url: "/productOrderMaterial/save",
+    method: "post",
+    data,
+  });
+}
+
+// 鐢熶骇璁㈠崟-棰嗘枡璇︽儏鍒楄〃
+export function listMaterialPickingDetail(query) {
+  return request({
+    url: "/productOrderMaterial/detailList",
+    method: "get",
+    params: query,
+  });
+}
+
+// 鐢熶骇璁㈠崟-琛ユ枡璁板綍鍒楄〃
+export function listMaterialSupplementRecord(query) {
+  return request({
+    url: "/productOrderMaterial/supplementRecord",
+    method: "get",
+    params: query,
+  });
+}
+
+// 鐢熶骇璁㈠崟-閫�鏂欑‘璁�
+export function confirmMaterialReturn(data) {
+  return request({
+    url: "/productOrderMaterial/confirmReturn",
+    method: "post",
+    data,
+  });
+}
+
 // 鑾峰彇鐐掓満姝e湪宸ヤ綔閲忔暟鎹�
 export function schedulingList(query) {
   return request({
@@ -129,4 +174,4 @@
     method: "post",
     data: data,
   });
-}
\ No newline at end of file
+}
diff --git a/src/api/productionManagement/workOrder.js b/src/api/productionManagement/workOrder.js
index 7e8bd86..cdc97cd 100644
--- a/src/api/productionManagement/workOrder.js
+++ b/src/api/productionManagement/workOrder.js
@@ -33,3 +33,48 @@
     responseType: "blob",
   });
 }
+
+// 宸ュ崟-褰撳墠宸ュ簭鐗╂枡鍙拌处
+export function listWorkOrderMaterialLedger(query) {
+  return request({
+    url: "/productOrderMaterial/reportMaterials",
+    method: "get",
+    params: query,
+  });
+}
+
+// 宸ュ崟-琛ユ枡
+export function addWorkOrderMaterialSupplement(data) {
+  return request({
+    url: "/productWorkOrder/material/supplement",
+    method: "post",
+    data,
+  });
+}
+
+// 宸ュ崟-閫�鏂�
+export function addWorkOrderMaterialReturn(data) {
+  return request({
+    url: "/productWorkOrder/material/return",
+    method: "post",
+    data,
+  });
+}
+
+// 宸ュ崟-琛ユ枡璁板綍
+export function listWorkOrderMaterialSupplementRecord(query) {
+  return request({
+    url: "/productWorkOrder/material/supplementRecord",
+    method: "get",
+    params: query,
+  });
+}
+
+// 宸ュ崟-棰嗙敤锛堟彁浜ゅ疄闄呴鐢ㄦ暟閲忥級
+export function pickWorkOrderMaterial(data) {
+  return request({
+    url: "/productWorkOrder/material/pick",
+    method: "post",
+    data,
+  });
+}
diff --git a/src/store/modules/permission.js b/src/store/modules/permission.js
index 6a16d9d..f7a7044 100644
--- a/src/store/modules/permission.js
+++ b/src/store/modules/permission.js
@@ -45,6 +45,7 @@
             const asyncRoutes = filterDynamicRoutes(dynamicRoutes)
             asyncRoutes.forEach(route => { router.addRoute(route) })
             this.setRoutes(rewriteRoutes)
+            // 灏嗚储鍔$鐞嗚矾鐢卞悎骞跺埌渚ц竟鏍�
             this.setSidebarRouters(constantRoutes.concat(sidebarRoutes))
             this.setDefaultRoutes(sidebarRoutes)
             this.setTopbarRoutes(defaultRoutes)
diff --git a/src/views/basicData/customerFile/index.vue b/src/views/basicData/customerFile/index.vue
index 79b1616..d0f829c 100644
--- a/src/views/basicData/customerFile/index.vue
+++ b/src/views/basicData/customerFile/index.vue
@@ -612,11 +612,13 @@
   import { onMounted, ref, reactive, getCurrentInstance, toRefs } from "vue";
   import { Search, Paperclip, Upload } from "@element-plus/icons-vue";
   import {
-    addCustomer,
-    delCustomer,
+    addCustomerPrivate,
+    delCustomerPrivate,
     getCustomer,
-    listCustomer,
-    updateCustomer,
+    getCustomerPrivatePoolById,
+    getCustomerPrivatePoolInfo,
+    listCustomerPrivatePool,
+    updateCustomerPrivatePool,
     addCustomerFollow,
     updateCustomerFollow,
     delCustomerFollow,
@@ -654,7 +656,7 @@
   const negotiationFormRef = ref();
   const negotiationForm = reactive({
     customerName: "",
-    customerId: "",
+		customerPrivatePoolId: "",
     followUpMethod: "",
     followUpLevel: "",
     followUpTime: "",
@@ -726,7 +728,7 @@
     },
     {
       label: "鍦板潃鍙婅仈绯绘柟寮�",
-      prop: "addressPhone",
+      prop: "companyAddress",
       width: 250,
     },
     {
@@ -766,6 +768,24 @@
     {
       label: "缁存姢浜�",
       prop: "maintainer",
+    },
+    {
+      label: "瀹㈡埛鏉ユ簮",
+      prop: "type",
+      dataType: "tag",
+      width: 100,
+      formatData: value => {
+        if (value === 1 || value === "1") {
+          return "鍏捣";
+        }
+        return "绉佹捣";
+      },
+      formatType: value => {
+        if (value === 1 || value === "1") {
+          return "warning";
+        }
+        return "success";
+      },
     },
     {
       label: "缁存姢鏃堕棿",
@@ -881,7 +901,7 @@
     // 璁剧疆涓婁紶鐨勮姹傚ご閮�
     headers: { Authorization: "Bearer " + getToken() },
     // 涓婁紶鐨勫湴鍧�
-    url: import.meta.env.VITE_APP_BASE_API + "/basic/customer/importData",
+    url: import.meta.env.VITE_APP_BASE_API + "/customerPrivate/importData",
     // 鏂囦欢涓婁紶鍓嶇殑鍥炶皟
     beforeUpload: file => {
       console.log("鏂囦欢鍗冲皢涓婁紶", file);
@@ -952,10 +972,10 @@
   };
   const getList = () => {
     tableLoading.value = true;
-    listCustomer({ ...searchForm.value, ...page }).then(res => {
+    listCustomerPrivatePool({ ...searchForm.value, ...page }).then(res => {
       tableLoading.value = false;
-      tableData.value = res.records;
-      page.total = res.total;
+      tableData.value = res.data.records;
+      page.total = res.data.total;
     });
   };
   // 琛ㄦ牸閫夋嫨鏁版嵁
@@ -974,7 +994,7 @@
   }
   /** 涓嬭浇妯℃澘 */
   function importTemplate() {
-    proxy.download("/basic/customer/downloadTemplate", {}, "瀹㈡埛瀵煎叆妯℃澘.xlsx");
+    proxy.download("/customerPrivate/downloadTemplate", {}, "瀹㈡埛瀵煎叆妯℃澘.xlsx");
   }
   // 鎵撳紑寮规
   const openForm = (type, row) => {
@@ -992,7 +1012,7 @@
       userList.value = res.data;
     });
     if (type === "edit") {
-      getCustomer(row.id).then(res => {
+      getCustomerPrivatePoolById(row.id).then(res => {
         form.value = { ...res.data };
         formYYs.value.contactList = res.data.contactPerson
           .split(",")
@@ -1029,7 +1049,7 @@
     form.value.contactPhone = formYYs.value.contactList
       .map(item => item.contactPhone)
       .join(",");
-    addCustomer(form.value).then(res => {
+    addCustomerPrivate(form.value).then(res => {
       proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
       closeDia();
       getList();
@@ -1043,7 +1063,7 @@
     form.value.contactPhone = formYYs.value.contactList
       .map(item => item.contactPhone)
       .join(",");
-    updateCustomer(form.value).then(res => {
+    updateCustomerPrivatePool(form.value).then(res => {
       proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
       closeDia();
       getList();
@@ -1062,7 +1082,7 @@
       type: "warning",
     })
       .then(() => {
-        proxy.download("/basic/customer/export", {}, "瀹㈡埛妗f.xlsx");
+        proxy.download("/customerPrivate/export", {}, "瀹㈡埛妗f.xlsx");
       })
       .catch(() => {
         proxy.$modal.msg("宸插彇娑�");
@@ -1072,12 +1092,11 @@
   const handleDelete = () => {
     let ids = [];
     if (selectedRows.value.length > 0) {
-      // 妫�鏌ユ槸鍚︽湁浠栦汉缁存姢鐨勬暟鎹�
       const unauthorizedData = selectedRows.value.filter(
-        item => item.maintainer !== userStore.nickName
+        item => item.type === 1 || item.type === "1"
       );
       if (unauthorizedData.length > 0) {
-        proxy.$modal.msgWarning("涓嶅彲鍒犻櫎浠栦汉缁存姢鐨勬暟鎹�");
+        proxy.$modal.msgWarning("鍏捣鍒嗛厤鐨勫鎴蜂笉鑳藉垹闄�");
         return;
       }
       ids = selectedRows.value.map(item => item.id);
@@ -1092,8 +1111,8 @@
     })
       .then(() => {
         tableLoading.value = true;
-        delCustomer(ids)
-          .then(res => {
+        delCustomerPrivate(ids)
+          .then(() => {
             proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
             getList();
           })
@@ -1146,7 +1165,8 @@
         if (reminderForm.id) {
           submitvalue.value = {
             id: reminderForm.id,
-            customerId: currentCustomerId.value,
+						customerPrivatePoolId: reminderForm.id,
+						customerPrivatePoolId: currentCustomerId.value,
             isEnabled: reminderForm.reminderSwitch ? 1 : 0,
             content: reminderForm.reminderContent,
             reminderTime: reminderForm.reminderTime,
@@ -1154,15 +1174,13 @@
           };
         } else {
           submitvalue.value = {
-            customerId: currentCustomerId.value,
+						customerPrivatePoolId: currentCustomerId.value,
             isEnabled: reminderForm.reminderSwitch ? 1 : 0,
             content: reminderForm.reminderContent,
             reminderTime: reminderForm.reminderTime,
             remindUserId: userStore.id,
           };
         }
-
-        console.log("鎻愪氦鍥炶鎻愰啋鏁版嵁:", submitvalue.value);
 
         // 璋冪敤鎺ュ彛
         addReturnVisit(submitvalue.value)
@@ -1185,20 +1203,12 @@
   // 鎵撳紑娲借皥杩涘害寮圭獥
   const openNegotiationDialog = row => {
     negotiationForm.customerName = row.customerName;
-    negotiationForm.customerId = row.id;
+    negotiationForm.customerPrivatePoolId = row.id;
     negotiationForm.followUpMethod = "";
     negotiationForm.followUpLevel = "";
     negotiationForm.followUpTime = "";
     negotiationForm.followerUserName = userStore.nickName; // 榛樿褰撳墠鐧诲綍浜�
     negotiationForm.content = "";
-    // {
-    // 	"customerId": 152,
-    // 	"followUpMethod": "鐢佃瘽娌熼��",
-    // 	"followUpLevel": "娌℃湁鎰忓悜",
-    // 	"followUpTime": "2026-03-04T15:30:00",
-    // 	"followerUserName": "绠$悊鍛樿处鍙�",
-    // 	"content": "111"
-    // }
     negotiationDialogVisible.value = true;
   };
 
@@ -1220,26 +1230,9 @@
 
         if (isEdit) {
           // 淇敼鎿嶄綔
-          console.log("淇敼娲借皥杩涘害鏁版嵁:", negotiationForm);
-          // 杩欓噷鍙互璋冪敤鏇存柊鎺ュ彛
-          // 瀹為檯椤圭洰涓渶瑕佹牴鎹悗绔帴鍙h繘琛岃皟鏁�
-          // 绀轰緥锛歶pdateCustomerFollow(negotiationForm).then(res => {
-          //   // 鏇存柊鏈湴鏁版嵁
-          //   const index = negotiationForm.editIndex;
-          //   negotiationRecords.value[index] = {
-          //     followUpTime: negotiationForm.followUpTime,
-          //     followUpMethod: negotiationForm.followUpMethod,
-          //     followUpLevel: negotiationForm.followUpLevel,
-          //     followerUserName: negotiationForm.followerUserName,
-          //     content: negotiationForm.content,
-          //     id: negotiationForm.id,
-          //   };
-          //   proxy.$modal.msgSuccess("淇敼鎴愬姛");
-          //   closeNegotiationDialog();
-          // });
           updateCustomerFollow(negotiationForm).then(res => {
             // 鏇存柊鏈湴鏁版嵁
-            getCustomer(negotiationForm.customerId).then(res => {
+            getCustomer(negotiationForm.customerPrivatePoolId).then(res => {
               // 鏇存柊鏈湴鏁版嵁
               negotiationRecords.value = res.data.followUpList || [];
             });
@@ -1271,8 +1264,7 @@
 
   // 鎵撳紑璇︽儏寮圭獥
   const openDetailDialog = row => {
-    // 璋冪敤getCustomer鎺ュ彛鑾峰彇瀹㈡埛璇︽儏
-    getCustomer(row.id).then(res => {
+    getCustomerPrivatePoolInfo(row.id).then(res => {
       // 濉厖瀹㈡埛鍩烘湰淇℃伅
       Object.assign(detailForm, res.data);
 
@@ -1293,7 +1285,7 @@
     // 灏嗗綋鍓嶈褰曟暟鎹~鍏呭埌琛ㄥ崟
     Object.assign(negotiationForm, {
       customerName: row.customerName,
-      customerId: row.customerId,
+			customerPrivatePoolId: row.customerPrivatePoolId,
       followUpMethod: row.followUpMethod,
       followUpLevel: row.followUpLevel,
       followUpTime: row.followUpTime,
@@ -1321,7 +1313,7 @@
         // });
         delCustomerFollow(row.id).then(() => {
           // 鍒犻櫎鎴愬姛鍚庢洿鏂版湰鍦版暟鎹�
-          getCustomer(row.customerId).then(res => {
+          getCustomer(row.customerPrivatePoolId).then(res => {
             // 鏇存柊鏈湴鏁版嵁
             negotiationRecords.value = res.data.followUpList || [];
           });
diff --git a/src/views/basicData/customerFileOpenSea/index.vue b/src/views/basicData/customerFileOpenSea/index.vue
new file mode 100644
index 0000000..71cc051
--- /dev/null
+++ b/src/views/basicData/customerFileOpenSea/index.vue
@@ -0,0 +1,1794 @@
+<template>
+  <div class="app-container">
+    <div class="search_form">
+      <div>
+        <span class="search_title">瀹㈡埛鍚嶇О锛�</span>
+        <el-input v-model="searchForm.customerName"
+                  style="width: 240px;margin-right: 10px"
+                  placeholder="璇疯緭鍏�"
+                  @change="handleQuery"
+                  clearable
+                  :prefix-icon="Search" />
+        <span class="search_title">瀹㈡埛鍒嗙被锛�</span>
+        <el-select v-model="searchForm.customerType"
+                   placeholder="璇烽�夋嫨"
+                   style="width: 240px"
+                   clearable
+                   @change="handleQuery">
+          <el-option label="闆跺敭瀹㈡埛"
+                     value="闆跺敭瀹㈡埛" />
+          <el-option label="杩涢攢鍟嗗鎴�"
+                     value="杩涢攢鍟嗗鎴�" />
+        </el-select>
+        <el-button type="primary"
+                   @click="handleQuery"
+                   style="margin-left: 10px">鎼滅储</el-button>
+      </div>
+      <div>
+        <el-button type="primary"
+                   @click="openForm('add')">鏂板瀹㈡埛</el-button>
+        <el-button @click="handleOut">瀵煎嚭</el-button>
+        <el-button type="info"
+                   plain
+                   icon="Upload"
+                   @click="handleImport">瀵煎叆</el-button>
+        <el-button type="danger"
+                   plain
+                   @click="handleDelete">鍒犻櫎</el-button>
+      </div>
+    </div>
+    <div class="table_list">
+      <PIMTable rowKey="id"
+                :column="tableColumn"
+                :tableData="tableData"
+                :page="page"
+                :isSelection="true"
+                @selection-change="handleSelectionChange"
+                :tableLoading="tableLoading"
+                @pagination="pagination"></PIMTable>
+    </div>
+    <el-dialog v-model="dialogFormVisible"
+               :title="operationType === 'add' ? '鏂板瀹㈡埛淇℃伅' : '缂栬緫瀹㈡埛淇℃伅'"
+               width="70%"
+               @close="closeDia">
+      <el-form :model="form"
+               label-width="140px"
+               label-position="top"
+               :rules="rules"
+               ref="formRef">
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="瀹㈡埛鍚嶇О锛�"
+                          prop="customerName">
+              <el-input v-model="form.customerName"
+                        placeholder="璇疯緭鍏�"
+                        clearable />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="绾崇◣浜鸿瘑鍒彿锛�"
+                          prop="taxpayerIdentificationNumber">
+              <el-input v-model="form.taxpayerIdentificationNumber"
+                        placeholder="璇疯緭鍏�"
+                        clearable />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="鍏徃鍦板潃锛�"
+                          prop="companyAddress">
+              <el-input v-model="form.companyAddress"
+                        placeholder="璇疯緭鍏�"
+                        clearable />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鍏徃鐢佃瘽锛�"
+                          prop="companyPhone">
+              <el-input v-model="form.companyPhone"
+                        placeholder="璇疯緭鍏�"
+                        clearable />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="閾惰鍩烘湰鎴凤細"
+                          prop="basicBankAccount">
+              <el-input v-model="form.basicBankAccount"
+                        placeholder="璇疯緭鍏�"
+                        clearable />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="閾惰璐﹀彿锛�"
+                          prop="bankAccount">
+              <el-input v-model="form.bankAccount"
+                        placeholder="璇疯緭鍏�"
+                        clearable />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="寮�鎴疯鍙凤細"
+                          prop="bankCode">
+              <el-input v-model="form.bankCode"
+                        placeholder="璇疯緭鍏�"
+                        clearable />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="瀹㈡埛鍒嗙被锛�"
+                          prop="customerType">
+              <el-select v-model="form.customerType"
+                         placeholder="璇烽�夋嫨"
+                         clearable>
+                <el-option label="闆跺敭瀹㈡埛"
+                           value="闆跺敭瀹㈡埛" />
+                <el-option label="杩涢攢鍟嗗鎴�"
+                           value="杩涢攢鍟嗗鎴�" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30"
+                v-for="(contact, index) in formYYs.contactList"
+                :key="index">
+          <el-col :span="12">
+            <el-form-item label="鑱旂郴浜猴細"
+                          prop="contactPerson">
+              <el-input v-model="contact.contactPerson"
+                        placeholder="璇疯緭鍏�"
+                        clearable />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鑱旂郴鐢佃瘽锛�"
+                          prop="contactPhone">
+              <div style="display: flex; align-items: center;width: 100%;">
+                <el-input v-model="contact.contactPhone"
+                          placeholder="璇疯緭鍏�"
+                          clearable />
+                <el-button @click="removeContact(index)"
+                           type="danger"
+                           circle
+                           style="margin-left: 5px;">
+                  <el-icon>
+                    <Close />
+                  </el-icon>
+                </el-button>
+              </div>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-button @click="addNewContact"
+                   style="margin-bottom: 10px;">+ 鏂板鑱旂郴浜�</el-button>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="缁存姢浜猴細"
+                          prop="maintainer">
+              <el-select v-model="form.maintainer"
+                         placeholder="璇烽�夋嫨"
+                         clearable
+                         disabled>
+                <el-option v-for="item in userList"
+                           :key="item.nickName"
+                           :label="item.nickName"
+                           :value="item.nickName" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="缁存姢鏃堕棿锛�"
+                          prop="maintenanceTime">
+              <el-date-picker style="width: 100%"
+                              v-model="form.maintenanceTime"
+                              value-format="YYYY-MM-DD"
+                              format="YYYY-MM-DD"
+                              type="date"
+                              placeholder="璇烽�夋嫨"
+                              clearable />
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary"
+                     @click="submitForm">纭</el-button>
+          <el-button @click="closeDia">鍙栨秷</el-button>
+        </div>
+      </template>
+    </el-dialog>
+    <el-dialog v-model="assignDialogVisible"
+               title="鍒嗛厤瀹㈡埛"
+               width="500px"
+               @close="closeAssignDialog">
+      <el-form :model="assignForm"
+               :rules="assignRules"
+               ref="assignFormRef"
+               label-width="100px">
+        <el-form-item label="瀹㈡埛鍚嶇О">
+          <el-input v-model="assignForm.customerName"
+                    disabled />
+        </el-form-item>
+        <el-form-item label="鍒嗛厤浜哄憳"
+                      prop="boundId">
+          <el-select v-model="assignForm.boundId"
+                     placeholder="璇烽�夋嫨鍒嗛厤浜哄憳"
+                     style="width: 100%"
+                     filterable>
+            <el-option v-for="item in userList"
+                       :key="item.userId || item.nickName"
+                       :label="item.nickName"
+                       :value="item.userId" />
+          </el-select>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary"
+                     @click="submitAssignForm">纭</el-button>
+          <el-button @click="closeAssignDialog">鍙栨秷</el-button>
+        </div>
+      </template>
+    </el-dialog>
+    <el-dialog v-model="shareDialogVisible"
+               title="鍏变韩瀹㈡埛"
+               width="500px"
+               @close="closeShareDialog">
+      <el-form :model="shareForm"
+               :rules="shareRules"
+               ref="shareFormRef"
+               label-width="100px">
+        <el-form-item label="瀹㈡埛鍚嶇О">
+          <el-input v-model="shareForm.customerName"
+                    disabled />
+        </el-form-item>
+        <el-form-item label="鍏变韩浜哄憳"
+                      prop="boundIds">
+          <el-select v-model="shareForm.boundIds"
+                     placeholder="璇烽�夋嫨鍏变韩浜哄憳"
+                     style="width: 100%"
+                     filterable
+                     multiple
+                     collapse-tags
+                     collapse-tags-tooltip>
+            <el-option v-for="item in userList"
+                       :key="item.userId || item.nickName"
+                       :label="item.nickName"
+                       :value="item.userId" />
+          </el-select>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary"
+                     @click="submitShareForm">纭</el-button>
+          <el-button @click="closeShareDialog">鍙栨秷</el-button>
+        </div>
+      </template>
+    </el-dialog>
+    <!-- 鐢ㄦ埛瀵煎叆瀵硅瘽妗� -->
+    <el-dialog :title="upload.title"
+               v-model="upload.open"
+               width="400px"
+               append-to-body>
+      <el-upload ref="uploadRef"
+                 :limit="1"
+                 accept=".xlsx, .xls"
+                 :headers="upload.headers"
+                 :action="upload.url + '?updateSupport=' + upload.updateSupport"
+                 :disabled="upload.isUploading"
+                 :before-upload="upload.beforeUpload"
+                 :on-progress="upload.onProgress"
+                 :on-success="upload.onSuccess"
+                 :on-error="upload.onError"
+                 :on-change="upload.onChange"
+                 :auto-upload="false"
+                 drag>
+        <el-icon class="el-icon--upload"><upload-filled /></el-icon>
+        <div class="el-upload__text">灏嗘枃浠舵嫋鍒版澶勶紝鎴�<em>鐐瑰嚮涓婁紶</em></div>
+        <template #tip>
+          <div class="el-upload__tip text-center">
+            <span>浠呭厑璁稿鍏ls銆亁lsx鏍煎紡鏂囦欢銆�</span>
+            <el-link type="primary"
+                     :underline="false"
+                     style="font-size: 12px; vertical-align: baseline"
+                     @click="importTemplate">涓嬭浇妯℃澘</el-link>
+          </div>
+        </template>
+      </el-upload>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary"
+                     @click="submitFileForm">纭� 瀹�</el-button>
+          <el-button @click="upload.open = false">鍙� 娑�</el-button>
+        </div>
+      </template>
+    </el-dialog>
+    <!-- 鍥炶鎻愰啋瀵硅瘽妗� -->
+    <el-dialog title="鍥炶鎻愰啋"
+               v-model="reminderDialogVisible"
+               width="500px"
+               @close="closeReminderDialog">
+      <el-form :model="reminderForm"
+               label-width="100px"
+               :rules="reminderRules"
+               ref="reminderFormRef">
+        <el-form-item label="瀹㈡埛鍚嶇О锛�">
+          <el-input v-model="reminderForm.customerName"
+                    disabled />
+        </el-form-item>
+        <el-form-item label="鎻愰啋寮�鍏筹細">
+          <el-switch v-model="reminderForm.reminderSwitch" />
+        </el-form-item>
+        <el-form-item label="鎻愰啋鍐呭锛�"
+                      prop="reminderContent">
+          <el-input v-model="reminderForm.reminderContent"
+                    type="textarea"
+                    :maxlength="100"
+                    show-word-limit
+                    placeholder="璇疯緭鍏ユ彁閱掑唴瀹�" />
+        </el-form-item>
+        <el-form-item label="鎻愰啋鏃堕棿锛�"
+                      prop="reminderTime">
+          <el-date-picker v-model="reminderForm.reminderTime"
+                          type="datetime"
+                          value-format="YYYY-MM-DD HH:mm:ss"
+                          format="YYYY-MM-DD HH:mm:ss"
+                          placeholder="璇烽�夋嫨鎻愰啋鏃堕棿"
+                          style="width: 100%" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitReminderForm">纭</el-button>
+          <el-button @click="closeReminderDialog">鍙栨秷</el-button>
+        </div>
+      </template>
+    </el-dialog>
+    <!-- 娣诲姞/淇敼娲借皥杩涘害瀵硅瘽妗� -->
+    <el-dialog :title="negotiationForm.editIndex !== undefined ? '淇敼杩涘害' : '娣诲姞杩涘害'"
+               v-model="negotiationDialogVisible"
+               width="600px"
+               @close="closeNegotiationDialog">
+      <el-form :model="negotiationForm"
+               label-width="100px"
+               :rules="negotiationRules"
+               ref="negotiationFormRef">
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="璺熻繘鏂瑰紡锛�"
+                          prop="followUpMethod">
+              <el-select v-model="negotiationForm.followUpMethod"
+                         placeholder="璇烽�夋嫨"
+                         style="width: 100%">
+                <el-option label="鐢佃瘽"
+                           value="鐢佃瘽" />
+                <el-option label="閭欢"
+                           value="閭欢" />
+                <el-option label="涓婇棬"
+                           value="涓婇棬" />
+                <el-option label="寰俊"
+                           value="寰俊" />
+                <el-option label="鍏朵粬"
+                           value="鍏朵粬" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="璺熻繘绋嬪害锛�"
+                          prop="followUpLevel">
+              <el-select v-model="negotiationForm.followUpLevel"
+                         placeholder="璇烽�夋嫨"
+                         style="width: 100%">
+                <el-option label="娼滃湪瀹㈡埛"
+                           value="娼滃湪瀹㈡埛" />
+                <el-option label="鍒濇鎷滆"
+                           value="鍒濇鎷滆" />
+                <el-option label="澶氭鎷滆"
+                           value="澶氭鎷滆" />
+                <el-option label="鎰忓悜瀹㈡埛"
+                           value="鎰忓悜瀹㈡埛" />
+                <el-option label="宸茬绾﹀鎴�"
+                           value="宸茬绾﹀鎴�" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="璺熻繘鏃堕棿锛�"
+                          prop="followUpTime">
+              <el-date-picker v-model="negotiationForm.followUpTime"
+                              type="datetime"
+                              value-format="YYYY-MM-DD HH:mm:ss"
+                              format="YYYY-MM-DD HH:mm:ss"
+                              placeholder="璇烽�夋嫨"
+                              style="width: 100%" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="璺熻繘浜猴細">
+              <el-input v-model="negotiationForm.followerUserName"
+                        disabled />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-form-item label="鍐呭锛�"
+                      prop="content">
+          <el-input v-model="negotiationForm.content"
+                    type="textarea"
+                    :rows="4"
+                    placeholder="璇疯緭鍏�" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitNegotiationForm">纭</el-button>
+          <el-button @click="closeNegotiationDialog">鍙栨秷</el-button>
+        </div>
+      </template>
+    </el-dialog>
+    <!-- 瀹㈡埛璇︽儏瀵硅瘽妗� -->
+    <el-dialog title="瀹㈡埛璇︽儏"
+               v-model="detailDialogVisible"
+               width="1000px"
+               @close="closeDetailDialog">
+      <!-- 瀹㈡埛鍩烘湰淇℃伅 -->
+      <div class="detail-section">
+        <h3 class="section-title">瀹㈡埛鍩烘湰淇℃伅</h3>
+        <div class="info-display">
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <div class="info-item">
+                <span class="info-label">瀹㈡埛鍚嶇О锛�</span>
+                <span class="info-value">{{ detailForm.customerName }}</span>
+              </div>
+            </el-col>
+            <el-col :span="12">
+              <div class="info-item">
+                <span class="info-label">瀹㈡埛鍒嗙被锛�</span>
+                <span class="info-value">{{ detailForm.customerType }}</span>
+              </div>
+            </el-col>
+          </el-row>
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <div class="info-item">
+                <span class="info-label">绾崇◣浜鸿瘑鍒彿锛�</span>
+                <span class="info-value">{{ detailForm.taxpayerIdentificationNumber }}</span>
+              </div>
+            </el-col>
+            <el-col :span="12">
+              <div class="info-item">
+                <span class="info-label">鍏徃鐢佃瘽锛�</span>
+                <span class="info-value">{{ detailForm.companyPhone }}</span>
+              </div>
+            </el-col>
+          </el-row>
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <div class="info-item">
+                <span class="info-label">鍏徃鍦板潃锛�</span>
+                <span class="info-value">{{ detailForm.companyAddress }}</span>
+              </div>
+            </el-col>
+            <el-col :span="12">
+              <div class="info-item">
+                <span class="info-label">閾惰鍩烘湰鎴凤細</span>
+                <span class="info-value">{{ detailForm.basicBankAccount }}</span>
+              </div>
+            </el-col>
+          </el-row>
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <div class="info-item">
+                <span class="info-label">閾惰璐﹀彿锛�</span>
+                <span class="info-value">{{ detailForm.bankAccount }}</span>
+              </div>
+            </el-col>
+            <el-col :span="12">
+              <div class="info-item">
+                <span class="info-label">寮�鎴疯鍙凤細</span>
+                <span class="info-value">{{ detailForm.bankCode }}</span>
+              </div>
+            </el-col>
+          </el-row>
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <div class="info-item">
+                <span class="info-label">鑱旂郴浜猴細</span>
+                <span class="info-value">{{ detailForm.contactPerson }}</span>
+              </div>
+            </el-col>
+            <el-col :span="12">
+              <div class="info-item">
+                <span class="info-label">鑱旂郴鐢佃瘽锛�</span>
+                <span class="info-value">{{ detailForm.contactPhone }}</span>
+              </div>
+            </el-col>
+          </el-row>
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <div class="info-item">
+                <span class="info-label">缁存姢浜猴細</span>
+                <span class="info-value">{{ detailForm.maintainer }}</span>
+              </div>
+            </el-col>
+            <el-col :span="12">
+              <div class="info-item">
+                <span class="info-label">缁存姢鏃堕棿锛�</span>
+                <span class="info-value">{{ detailForm.maintenanceTime }}</span>
+              </div>
+            </el-col>
+          </el-row>
+        </div>
+      </div>
+      <!-- 娲借皥杩涘害璁板綍 -->
+      <div class="detail-section">
+        <div class="section-header">
+          <h3 class="section-title">娲借皥杩涘害璁板綍</h3>
+          <el-button type="primary"
+                     size="small"
+                     @click="openNegotiationDialog(detailForm)">
+            娣诲姞杩涘害
+          </el-button>
+        </div>
+        <el-table :data="negotiationRecords"
+                  border
+                  style="width: 100%">
+          <el-table-column prop="followUpTime"
+                           label="璺熻繘鏃堕棿"
+                           width="160" />
+          <el-table-column prop="followUpMethod"
+                           label="璺熻繘鏂瑰紡"
+                           width="100" />
+          <el-table-column prop="followUpLevel"
+                           label="璺熻繘绋嬪害" />
+          <el-table-column prop="followerUserName"
+                           label="璺熻繘浜�"
+                           width="100" />
+          <el-table-column prop="content"
+                           label="鍐呭"
+                           show-overflow-tooltip />
+          <el-table-column label="闄勪欢"
+                           width="100"
+                           align="center">
+            <template #default="{ row }">
+              <el-button type="info"
+                         link
+                         @click="openAttachmentDialog(row)">
+                <el-icon>
+                  <Paperclip />
+                </el-icon>
+                闄勪欢
+                <!-- {{ row.fileList && row.fileList.length > 0 ? row.fileList.length : '涓婁紶' }} -->
+              </el-button>
+            </template>
+          </el-table-column>
+          <el-table-column label="鎿嶄綔"
+                           width="150"
+                           align="center">
+            <template #default="{ row, $index }">
+              <el-button type="primary"
+                         link
+                         @click="editNegotiationRecord(row, $index)">
+                淇敼
+              </el-button>
+              <el-button type="danger"
+                         link
+                         @click="deleteNegotiationRecord(row, $index)">
+                鍒犻櫎
+              </el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+        <div v-if="negotiationRecords.length === 0"
+             class="no-records">
+          鏆傛棤娲借皥杩涘害璁板綍
+        </div>
+      </div>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="closeDetailDialog">鍏抽棴</el-button>
+        </div>
+      </template>
+    </el-dialog>
+    <!-- 闄勪欢涓婁紶寮圭獥 -->
+    <el-dialog title="闄勪欢绠$悊"
+               v-model="attachmentDialogVisible"
+               width="600px"
+               @close="closeAttachmentDialog">
+      <div class="attachment-section">
+        <div class="upload-area">
+          <el-upload ref="attachmentUploadRef"
+                     :action="getAttachmentUploadUrl()"
+                     :headers="attachmentUploadHeaders"
+                     :file-list="currentAttachmentList"
+                     :on-success="handleAttachmentSuccess"
+                     :on-error="handleAttachmentError"
+                     :on-remove="handleAttachmentRemove"
+                     :before-upload="beforeAttachmentUpload"
+                     multiple
+                     :limit="10"
+                     name="files">
+            <el-button type="primary">
+              <el-icon>
+                <Upload />
+              </el-icon>
+              涓婁紶闄勪欢
+            </el-button>
+            <template #tip>
+              <div class="el-upload__tip">
+                鏀寔涓婁紶鍥剧墖銆佹枃妗g瓑鏂囦欢锛屽崟涓枃浠朵笉瓒呰繃50MB
+              </div>
+            </template>
+          </el-upload>
+        </div>
+        <div v-if="currentAttachmentList.length > 0"
+             class="attachment-list">
+          <h4>宸蹭笂浼犻檮浠讹細</h4>
+          <el-table :data="currentAttachmentList"
+                    border
+                    size="small">
+            <el-table-column prop="name"
+                             label="鏂囦欢鍚�"
+                             show-overflow-tooltip />
+            <el-table-column prop="size"
+                             label="澶у皬"
+                             width="100">
+              <template #default="{ row }">
+                {{ formatFileSize(row.size) }}
+              </template>
+            </el-table-column>
+            <el-table-column label="鎿嶄綔"
+                             width="120"
+                             align="center">
+              <template #default="{ row, $index }">
+                <el-button type="primary"
+                           link
+                           @click="downloadAttachment(row)">
+                  涓嬭浇
+                </el-button>
+                <el-button type="danger"
+                           link
+                           @click="deleteAttachment(row, $index)">
+                  鍒犻櫎
+                </el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </div>
+        <div v-else
+             class="no-attachment">
+          鏆傛棤闄勪欢
+        </div>
+      </div>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="closeAttachmentDialog">鍏抽棴</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+  import { onMounted, ref, reactive, getCurrentInstance, toRefs } from "vue";
+  import { Search, Paperclip, Upload } from "@element-plus/icons-vue";
+  import {
+    addCustomer,
+    addCustomerPrivatePool,
+    delCustomerPrivatePool,
+    delCustomer,
+    getCustomer,
+    shareCustomer,
+    listCustomer,
+    updateCustomer,
+    addCustomerFollow,
+    updateCustomerFollow,
+    delCustomerFollow,
+    addReturnVisit,
+    getReturnVisit,
+  } from "@/api/basicData/customerFile.js";
+  import { ElMessageBox } from "element-plus";
+  import { userListNoPage } from "@/api/system/user.js";
+  import useUserStore from "@/store/modules/user";
+  import { getToken } from "@/utils/auth.js";
+  const { proxy } = getCurrentInstance();
+  const userStore = useUserStore();
+  const assignDialogVisible = ref(false);
+  const assignFormRef = ref();
+  const assignForm = reactive({
+    id: undefined,
+    customerName: "",
+    boundId: undefined,
+  });
+  const assignRules = {
+    boundId: [{ required: true, message: "璇烽�夋嫨鍒嗛厤浜哄憳", trigger: "change" }],
+  };
+  const shareDialogVisible = ref(false);
+  const shareFormRef = ref();
+  const shareForm = reactive({
+    id: undefined,
+    customerName: "",
+    boundIds: [],
+  });
+  const shareRules = {
+    boundIds: [{ required: true, message: "璇烽�夋嫨鍏变韩浜哄憳", trigger: "change" }],
+  };
+
+  // 鍥炶鎻愰啋鐩稿叧
+  const reminderDialogVisible = ref(false);
+  const reminderFormRef = ref();
+  const currentCustomerId = ref();
+  const reminderForm = reactive({
+    customerName: "",
+    reminderSwitch: false,
+    reminderContent: "",
+    reminderTime: "",
+  });
+  const reminderRules = {
+    reminderContent: [
+      { required: true, message: "璇疯緭鍏ユ彁閱掑唴瀹�", trigger: "blur" },
+    ],
+    reminderTime: [
+      { required: true, message: "璇烽�夋嫨鎻愰啋鏃堕棿", trigger: "change" },
+    ],
+  };
+
+  // 娲借皥杩涘害鐩稿叧
+  const negotiationDialogVisible = ref(false);
+  const negotiationFormRef = ref();
+  const negotiationForm = reactive({
+    customerName: "",
+    customerId: "",
+    followUpMethod: "",
+    followUpLevel: "",
+    followUpTime: "",
+    followerUserName: "",
+    content: "",
+  });
+  const negotiationRules = {
+    followUpMethod: [
+      { required: true, message: "璇烽�夋嫨璺熻繘鏂瑰紡", trigger: "change" },
+    ],
+    followUpLevel: [
+      { required: true, message: "璇烽�夋嫨璺熻繘绋嬪害", trigger: "change" },
+    ],
+    followUpTime: [
+      { required: true, message: "璇烽�夋嫨璺熻繘鏃堕棿", trigger: "change" },
+    ],
+    content: [{ required: true, message: "璇疯緭鍏ュ唴瀹�", trigger: "blur" }],
+  };
+
+  // 璇︽儏鐩稿叧
+  const detailDialogVisible = ref(false);
+  const detailForm = reactive({
+    customerName: "",
+    customerType: "",
+    taxpayerIdentificationNumber: "",
+    companyPhone: "",
+    companyAddress: "",
+    basicBankAccount: "",
+    bankAccount: "",
+    bankCode: "",
+    contactPerson: "",
+    contactPhone: "",
+    maintainer: "",
+    maintenanceTime: "",
+  });
+  const negotiationRecords = ref([]);
+
+  // 闄勪欢鐩稿叧
+  const attachmentDialogVisible = ref(false);
+  const attachmentUploadRef = ref();
+  const currentAttachmentList = ref([]);
+  const currentFollowRecord = ref({});
+  const attachmentUploadHeaders = { Authorization: "Bearer " + getToken() };
+
+  // 鍔ㄦ�佹瀯寤轰笂浼燯RL
+  const getAttachmentUploadUrl = () => {
+    const baseUrl =
+      import.meta.env.VITE_APP_BASE_API + "/basic/customer-follow/upload";
+    return currentFollowRecord.value.id
+      ? `${baseUrl}/${currentFollowRecord.value.id}`
+      : baseUrl;
+  };
+
+  const tableColumn = ref([
+    {
+      label: "瀹㈡埛鍒嗙被",
+      prop: "customerType",
+      width: 120,
+    },
+    {
+      label: "瀹㈡埛鍚嶇О",
+      prop: "customerName",
+      width: 220,
+    },
+    {
+      label: "绾崇◣浜鸿瘑鍒爜",
+      prop: "taxpayerIdentificationNumber",
+      width: 220,
+    },
+    {
+      label: "鍦板潃鍙婅仈绯绘柟寮�",
+      prop: "addressPhone",
+      width: 250,
+    },
+    {
+      label: "鑱旂郴浜�",
+      prop: "contactPerson",
+    },
+    {
+      label: "鑱旂郴鐢佃瘽",
+      prop: "contactPhone",
+      width: 150,
+    },
+    // {
+    //   label: "璺熻繘杩涘害",
+    //   prop: "followUpLevel",
+    //   width: 120,
+    // },
+    // {
+    //   label: "璺熻繘鏃堕棿",
+    //   prop: "followUpTime",
+    //   width: 120,
+    // },
+    {
+      label: "閾惰鍩烘湰鎴�",
+      prop: "basicBankAccount",
+      width: 220,
+    },
+    {
+      label: "閾惰璐﹀彿",
+      prop: "bankAccount",
+      width: 220,
+    },
+    {
+      label: "寮�鎴疯鍙�",
+      prop: "bankCode",
+      width: 220,
+    },
+    {
+      label: "缁存姢浜�",
+      prop: "maintainer",
+    },
+		{
+			label: "缁存姢鏃堕棿",
+			prop: "maintenanceTime",
+			width: 100,
+		},
+    {
+      label: "棰嗙敤浜�",
+      prop: "usageUserName",
+      width: 120,
+			fixed: "right",
+    },
+    {
+      label: "棰嗙敤鐘舵��",
+      prop: "usageStatus",
+      dataType: "tag",
+      width: 100,
+			fixed: "right",
+      formatData: value => {
+        if (value === 1 || value === "1") {
+          return "宸查鐢�";
+        }
+        return "鏈鐢�";
+      },
+      formatType: value => {
+        if (value === 1 || value === "1") {
+          return "success";
+        }
+        return "info";
+      },
+    },
+		{
+			label: "鍏变韩浜�",
+			prop: "togetherUserNames",
+			width: 120,
+			fixed: "right",
+		},
+    {
+      dataType: "action",
+      label: "鎿嶄綔",
+      align: "center",
+      fixed: "right",
+      width: 200,
+      operation: [
+        {
+          name: "鍒嗛厤",
+          type: "text",
+          showHide: row => row.usageStatus != 1,
+          clickFun: row => {
+            openAssignDialog(row);
+          },
+        },
+        {
+          name: "鍥炴敹",
+          type: "text",
+          showHide: row => row.usageStatus == 1,
+          clickFun: row => {
+            recycleCustomer(row);
+          },
+        },
+				{
+					name: "鍏变韩",
+					type: "text",
+					showHide: row => row.usageStatus == 1,
+					clickFun: row => {
+						openShareDialog(row);
+					},
+				},
+				{
+					name: "缂栬緫",
+					type: "text",
+					clickFun: row => {
+						openForm("edit", row);
+					},
+				},
+        // {
+        //   name: "璇︽儏",
+        //   type: "text",
+        //   clickFun: row => {
+        //     openDetailDialog(row);
+        //   },
+        // },
+      ],
+    },
+  ]);
+  const tableData = ref([]);
+  const selectedRows = ref([]);
+  const userList = ref([]);
+  const tableLoading = ref(false);
+  const page = reactive({
+    current: 1,
+    size: 100,
+    total: 0,
+  });
+  const total = ref(0);
+
+  // 鐢ㄦ埛淇℃伅琛ㄥ崟寮规鏁版嵁
+  const operationType = ref("");
+  const dialogFormVisible = ref(false);
+  const formYYs = ref({
+    // 鍏朵粬瀛楁...
+    contactList: [
+      {
+        contactPerson: "",
+        contactPhone: "",
+      },
+    ],
+  });
+  const data = reactive({
+    searchForm: {
+      customerName: "",
+      customerType: "",
+    },
+    form: {
+      customerName: "",
+      taxpayerIdentificationNumber: "",
+      companyAddress: "",
+      companyPhone: "",
+      contactPerson: "",
+      contactPhone: "",
+      maintainer: "",
+      maintenanceTime: "",
+      basicBankAccount: "",
+      bankAccount: "",
+      bankCode: "",
+      customerType: "",
+    },
+    rules: {
+      customerName: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+      taxpayerIdentificationNumber: [
+        { required: true, message: "璇疯緭鍏�", trigger: "blur" },
+      ],
+      companyAddress: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+      companyPhone: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+      // contactPerson: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+      // contactPhone: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+      maintainer: [{ required: false, message: "璇烽�夋嫨", trigger: "change" }],
+      maintenanceTime: [
+        { required: false, message: "璇烽�夋嫨", trigger: "change" },
+      ],
+      basicBankAccount: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+      bankAccount: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+      bankCode: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+      customerType: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+    },
+  });
+  const upload = reactive({
+    // 鏄惁鏄剧ず寮瑰嚭灞傦紙瀹㈡埛瀵煎叆锛�
+    open: false,
+    // 寮瑰嚭灞傛爣棰橈紙瀹㈡埛瀵煎叆锛�
+    title: "",
+    // 鏄惁绂佺敤涓婁紶
+    isUploading: false,
+    // 璁剧疆涓婁紶鐨勮姹傚ご閮�
+    headers: { Authorization: "Bearer " + getToken() },
+    // 涓婁紶鐨勫湴鍧�
+    url: import.meta.env.VITE_APP_BASE_API + "/basic/customer/importData",
+    // 鏂囦欢涓婁紶鍓嶇殑鍥炶皟
+    beforeUpload: file => {
+      console.log("鏂囦欢鍗冲皢涓婁紶", file);
+      // 鍙互鍦ㄦ澶勫仛鏂囦欢绫诲瀷鎴栧ぇ灏忔牎楠�
+      const isValid =
+        file.type ===
+          "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ||
+        file.name.endsWith(".xlsx") ||
+        file.name.endsWith(".xls");
+      if (!isValid) {
+        proxy.$modal.msgError("鍙兘涓婁紶 Excel 鏂囦欢");
+      }
+      return isValid;
+    },
+    // 鏂囦欢鐘舵�佹敼鍙樻椂鐨勫洖璋�
+    onChange: (file, fileList) => {
+      console.log("鏂囦欢鐘舵�佹敼鍙�", file, fileList);
+    },
+    // 鏂囦欢涓婁紶鎴愬姛鏃剁殑鍥炶皟
+    onSuccess: (response, file, fileList) => {
+      console.log("涓婁紶鎴愬姛", response, file, fileList);
+      upload.isUploading = false;
+      if (response.code === 200) {
+        proxy.$modal.msgSuccess("鏂囦欢涓婁紶鎴愬姛");
+        upload.open = false;
+        proxy.$refs["uploadRef"].clearFiles();
+        getList();
+      } else if (response.code === 500) {
+        proxy.$modal.msgError(response.msg);
+      } else {
+        proxy.$modal.msgWarning(response.msg);
+      }
+    },
+    // 鏂囦欢涓婁紶澶辫触鏃剁殑鍥炶皟
+    onError: (error, file, fileList) => {
+      console.error("涓婁紶澶辫触", error, file, fileList);
+      upload.isUploading = false;
+      proxy.$modal.msgError("鏂囦欢涓婁紶澶辫触");
+    },
+    // 鏂囦欢涓婁紶杩涘害鍥炶皟
+    onProgress: (event, file, fileList) => {
+      console.log("涓婁紶涓�...", event.percent);
+    },
+  });
+  const { searchForm, form, rules } = toRefs(data);
+  const addNewContact = () => {
+    formYYs.value.contactList.push({
+      contactPerson: "",
+      contactPhone: "",
+    });
+  };
+
+  const removeContact = index => {
+    if (formYYs.value.contactList.length > 1) {
+      formYYs.value.contactList.splice(index, 1);
+    }
+  };
+  // 鏌ヨ鍒楄〃
+  /** 鎼滅储鎸夐挳鎿嶄綔 */
+  const handleQuery = () => {
+    page.current = 1;
+    getList();
+  };
+  const pagination = obj => {
+    page.current = obj.page;
+    page.size = obj.limit;
+    getList();
+  };
+  const getList = () => {
+    tableLoading.value = true;
+    const { total, ...queryPage } = page;
+    listCustomer({ ...searchForm.value, ...queryPage }).then(res => {
+      tableLoading.value = false;
+      tableData.value = res.data.records;
+      page.total = res.data.total;
+    });
+  };
+  // 琛ㄦ牸閫夋嫨鏁版嵁
+  const handleSelectionChange = selection => {
+    selectedRows.value = selection;
+  };
+  /** 鎻愪氦涓婁紶鏂囦欢 */
+  function submitFileForm() {
+    upload.isUploading = true;
+    proxy.$refs["uploadRef"].submit();
+  }
+  /** 瀵煎叆鎸夐挳鎿嶄綔 */
+  function handleImport() {
+    upload.title = "瀹㈡埛瀵煎叆";
+    upload.open = true;
+  }
+  /** 涓嬭浇妯℃澘 */
+  function importTemplate() {
+    proxy.download("/basic/customer/downloadTemplate", {}, "瀹㈡埛瀵煎叆妯℃澘.xlsx");
+  }
+  // 鎵撳紑寮规
+  const openForm = (type, row) => {
+    operationType.value = type;
+    form.value = {};
+    form.value.maintainer = userStore.nickName;
+    formYYs.value.contactList = [
+      {
+        contactPerson: "",
+        contactPhone: "",
+      },
+    ];
+    form.value.maintenanceTime = getCurrentDate();
+    userListNoPage().then(res => {
+      userList.value = res.data;
+    });
+    if (type === "edit") {
+      getCustomer(row.id).then(res => {
+        form.value = { ...res.data };
+        formYYs.value.contactList = res.data.contactPerson
+          .split(",")
+          .map((item, index) => {
+            return {
+              contactPerson: item,
+              contactPhone: res.data.contactPhone.split(",")[index],
+            };
+          });
+      });
+    }
+    dialogFormVisible.value = true;
+  };
+  // 鎻愪氦琛ㄥ崟
+  const submitForm = () => {
+    proxy.$refs["formRef"].validate(valid => {
+      if (valid) {
+        if (operationType.value === "edit") {
+          submitEdit();
+        } else {
+          submitAdd();
+        }
+      }
+    });
+  };
+  // 鎻愪氦鏂板
+  const submitAdd = () => {
+    if (formYYs.value.contactList.length < 1) {
+      return proxy.$modal.msgWarning("璇疯嚦灏戞坊鍔犱竴涓仈绯讳汉");
+    }
+    form.value.contactPerson = formYYs.value.contactList
+      .map(item => item.contactPerson)
+      .join(",");
+    form.value.contactPhone = formYYs.value.contactList
+      .map(item => item.contactPhone)
+      .join(",");
+    addCustomer(form.value).then(res => {
+      proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+      closeDia();
+      getList();
+    });
+  };
+  // 鎻愪氦淇敼
+  const submitEdit = () => {
+    form.value.contactPerson = formYYs.value.contactList
+      .map(item => item.contactPerson)
+      .join(",");
+    form.value.contactPhone = formYYs.value.contactList
+      .map(item => item.contactPhone)
+      .join(",");
+    updateCustomer(form.value).then(res => {
+      proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+      closeDia();
+      getList();
+    });
+  };
+  // 鍏抽棴寮规
+  const closeDia = () => {
+    proxy.resetForm("formRef");
+    dialogFormVisible.value = false;
+  };
+  const ensureUserList = () => {
+    if (userList.value.length) {
+      return Promise.resolve();
+    }
+    return userListNoPage().then(res => {
+      userList.value = res.data || [];
+    });
+  };
+  const openAssignDialog = row => {
+    assignForm.id = row.id;
+    assignForm.customerName = row.customerName;
+    assignForm.boundId = undefined;
+    ensureUserList().then(() => {
+      assignDialogVisible.value = true;
+    });
+  };
+  const closeAssignDialog = () => {
+    proxy.resetForm("assignFormRef");
+    assignForm.id = undefined;
+    assignForm.customerName = "";
+    assignForm.boundId = undefined;
+    assignDialogVisible.value = false;
+  };
+  const openShareDialog = row => {
+    shareForm.id = row.id;
+    shareForm.customerName = row.customerName;
+    shareForm.boundIds = [];
+    ensureUserList().then(() => {
+      shareDialogVisible.value = true;
+    });
+  };
+  const closeShareDialog = () => {
+    proxy.resetForm("shareFormRef");
+    shareForm.id = undefined;
+    shareForm.customerName = "";
+    shareForm.boundIds = [];
+    shareDialogVisible.value = false;
+  };
+  const submitAssignForm = () => {
+    proxy.$refs.assignFormRef.validate(valid => {
+      if (!valid) {
+        return;
+      }
+      addCustomerPrivatePool({
+        customerId: assignForm.id,
+        boundId: assignForm.boundId,
+      }).then(() => {
+        proxy.$modal.msgSuccess("鍒嗛厤鎴愬姛");
+        closeAssignDialog();
+        getList();
+      });
+    });
+  };
+  const submitShareForm = () => {
+    proxy.$refs.shareFormRef.validate(valid => {
+      if (!valid) {
+        return;
+      }
+      shareCustomer({
+        customerId: shareForm.id,
+        boundIds: shareForm.boundIds,
+      }).then(() => {
+        proxy.$modal.msgSuccess("鍏变韩鎴愬姛");
+        closeShareDialog();
+        getList();
+      });
+    });
+  };
+  const recycleCustomer = row => {
+    ElMessageBox.confirm("纭鍥炴敹瀹㈡埛鈥�" + row.customerName + "鈥濆悧锛�", "鍥炴敹鎻愮ず", {
+      confirmButtonText: "纭",
+      cancelButtonText: "鍙栨秷",
+      type: "warning",
+    })
+      .then(() => {
+        return delCustomerPrivatePool(row.id);
+      })
+      .then(() => {
+        proxy.$modal.msgSuccess("鍥炴敹鎴愬姛");
+        getList();
+      })
+      .catch(error => {
+        if (error === "cancel" || error === "close") {
+          proxy.$modal.msg("宸插彇娑�");
+        }
+      });
+  };
+  // 瀵煎嚭
+  const handleOut = () => {
+    ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
+      confirmButtonText: "纭",
+      cancelButtonText: "鍙栨秷",
+      type: "warning",
+    })
+      .then(() => {
+        proxy.download("/basic/customer/export", {}, "瀹㈡埛妗f.xlsx");
+      })
+      .catch(() => {
+        proxy.$modal.msg("宸插彇娑�");
+      });
+  };
+  // 鍒犻櫎
+  const handleDelete = () => {
+    let ids = [];
+    if (selectedRows.value.length > 0) {
+      // 妫�鏌ユ槸鍚︽湁浠栦汉缁存姢鐨勬暟鎹�
+      const unauthorizedData = selectedRows.value.filter(
+        item => item.maintainer !== userStore.nickName
+      );
+      if (unauthorizedData.length > 0) {
+        proxy.$modal.msgWarning("涓嶅彲鍒犻櫎浠栦汉缁存姢鐨勬暟鎹�");
+        return;
+      }
+      ids = selectedRows.value.map(item => item.id);
+    } else {
+      proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
+      return;
+    }
+    ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "鍒犻櫎鎻愮ず", {
+      confirmButtonText: "纭",
+      cancelButtonText: "鍙栨秷",
+      type: "warning",
+    })
+      .then(() => {
+        tableLoading.value = true;
+        delCustomer(ids)
+          .then(res => {
+            proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+            getList();
+          })
+          .finally(() => {
+            tableLoading.value = false;
+          });
+      })
+      .catch(() => {
+        proxy.$modal.msg("宸插彇娑�");
+      });
+  };
+
+  // 鎵撳紑鍥炶鎻愰啋寮圭獥
+  const openReminderDialog = row => {
+    currentCustomerId.value = row.id;
+    reminderForm.customerName = row.customerName;
+    reminderForm.reminderSwitch = false;
+    reminderForm.reminderContent = "";
+    reminderForm.reminderTime = "";
+
+    // 灏濊瘯鑾峰彇宸叉湁鐨勫洖璁挎彁閱�
+    getReturnVisit(row.id)
+      .then(res => {
+        if (res.code === 200 && res.data) {
+          reminderForm.reminderSwitch = res.data.isEnabled === 1;
+          reminderForm.reminderContent = res.data.content;
+          reminderForm.reminderTime = res.data.reminderTime;
+          reminderForm.id = res.data.id;
+        }
+      })
+      .catch(error => {
+        console.error("鑾峰彇鍥炶鎻愰啋澶辫触:", error);
+      });
+
+    reminderDialogVisible.value = true;
+  };
+
+  // 鍏抽棴鍥炶鎻愰啋寮圭獥
+  const closeReminderDialog = () => {
+    proxy.resetForm("reminderFormRef");
+    reminderDialogVisible.value = false;
+  };
+  const submitvalue = ref({});
+
+  // 鎻愪氦鍥炶鎻愰啋
+  const submitReminderForm = () => {
+    console.log("鎻愪氦鍥炶鎻愰啋鏁版嵁:", userStore.id, userStore);
+    proxy.$refs.reminderFormRef.validate(valid => {
+      if (valid) {
+        if (reminderForm.id) {
+          submitvalue.value = {
+            id: reminderForm.id,
+            customerId: currentCustomerId.value,
+            isEnabled: reminderForm.reminderSwitch ? 1 : 0,
+            content: reminderForm.reminderContent,
+            reminderTime: reminderForm.reminderTime,
+            remindUserId: userStore.id,
+          };
+        } else {
+          submitvalue.value = {
+            customerId: currentCustomerId.value,
+            isEnabled: reminderForm.reminderSwitch ? 1 : 0,
+            content: reminderForm.reminderContent,
+            reminderTime: reminderForm.reminderTime,
+            remindUserId: userStore.id,
+          };
+        }
+
+        console.log("鎻愪氦鍥炶鎻愰啋鏁版嵁:", submitvalue.value);
+
+        // 璋冪敤鎺ュ彛
+        addReturnVisit(submitvalue.value)
+          .then(res => {
+            if (res.code === 200) {
+              proxy.$modal.msgSuccess("鍥炶鎻愰啋璁剧疆鎴愬姛");
+              closeReminderDialog();
+            } else {
+              proxy.$modal.msgError(res.msg || "璁剧疆澶辫触");
+            }
+          })
+          .catch(error => {
+            console.error("璁剧疆鍥炶鎻愰啋澶辫触:", error);
+            proxy.$modal.msgError("璁剧疆澶辫触");
+          });
+      }
+    });
+  };
+
+  // 鎵撳紑娲借皥杩涘害寮圭獥
+  const openNegotiationDialog = row => {
+    negotiationForm.customerName = row.customerName;
+    negotiationForm.customerId = row.id;
+    negotiationForm.followUpMethod = "";
+    negotiationForm.followUpLevel = "";
+    negotiationForm.followUpTime = "";
+    negotiationForm.followerUserName = userStore.nickName; // 榛樿褰撳墠鐧诲綍浜�
+    negotiationForm.content = "";
+    // {
+    // 	"customerId": 152,
+    // 	"followUpMethod": "鐢佃瘽娌熼��",
+    // 	"followUpLevel": "娌℃湁鎰忓悜",
+    // 	"followUpTime": "2026-03-04T15:30:00",
+    // 	"followerUserName": "绠$悊鍛樿处鍙�",
+    // 	"content": "111"
+    // }
+    negotiationDialogVisible.value = true;
+  };
+
+  // 鍏抽棴娲借皥杩涘害寮圭獥
+  const closeNegotiationDialog = () => {
+    proxy.resetForm("negotiationFormRef");
+    // 娓呴櫎缂栬緫鐘舵��
+    delete negotiationForm.editIndex;
+    delete negotiationForm.id;
+    negotiationDialogVisible.value = false;
+  };
+
+  // 鎻愪氦娲借皥杩涘害
+  const submitNegotiationForm = () => {
+    proxy.$refs.negotiationFormRef.validate(valid => {
+      if (valid) {
+        // 鍒ゆ柇鏄柊澧炶繕鏄慨鏀�
+        const isEdit = negotiationForm.editIndex !== undefined;
+
+        if (isEdit) {
+          // 淇敼鎿嶄綔
+          console.log("淇敼娲借皥杩涘害鏁版嵁:", negotiationForm);
+          // 杩欓噷鍙互璋冪敤鏇存柊鎺ュ彛
+          // 瀹為檯椤圭洰涓渶瑕佹牴鎹悗绔帴鍙h繘琛岃皟鏁�
+          // 绀轰緥锛歶pdateCustomerFollow(negotiationForm).then(res => {
+          //   // 鏇存柊鏈湴鏁版嵁
+          //   const index = negotiationForm.editIndex;
+          //   negotiationRecords.value[index] = {
+          //     followUpTime: negotiationForm.followUpTime,
+          //     followUpMethod: negotiationForm.followUpMethod,
+          //     followUpLevel: negotiationForm.followUpLevel,
+          //     followerUserName: negotiationForm.followerUserName,
+          //     content: negotiationForm.content,
+          //     id: negotiationForm.id,
+          //   };
+          //   proxy.$modal.msgSuccess("淇敼鎴愬姛");
+          //   closeNegotiationDialog();
+          // });
+          updateCustomerFollow(negotiationForm).then(res => {
+            // 鏇存柊鏈湴鏁版嵁
+            getCustomer(negotiationForm.customerId).then(res => {
+              // 鏇存柊鏈湴鏁版嵁
+              negotiationRecords.value = res.data.followUpList || [];
+            });
+          });
+          proxy.$modal.msgSuccess("淇敼鎴愬姛");
+          closeNegotiationDialog();
+        } else {
+          // 鏂板鎿嶄綔
+          console.log("鎻愪氦娲借皥杩涘害鏁版嵁:", negotiationForm);
+          addCustomerFollow(negotiationForm).then(res => {
+            // 娣诲姞鎴愬姛鍚庢洿鏂拌鎯呴〉闈㈢殑杩涘害璁板綍
+            const newRecord = {
+              followUpTime: negotiationForm.followUpTime,
+              followUpMethod: negotiationForm.followUpMethod,
+              followUpLevel: negotiationForm.followUpLevel,
+              followerUserName: negotiationForm.followerUserName,
+              content: negotiationForm.content,
+            };
+            negotiationRecords.value.unshift(newRecord);
+
+            proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+            closeNegotiationDialog();
+            getList();
+          });
+        }
+      }
+    });
+  };
+
+  // 鎵撳紑璇︽儏寮圭獥
+  const openDetailDialog = row => {
+    // 璋冪敤getCustomer鎺ュ彛鑾峰彇瀹㈡埛璇︽儏
+    getCustomer(row.id).then(res => {
+      // 濉厖瀹㈡埛鍩烘湰淇℃伅
+      Object.assign(detailForm, res.data);
+
+      // 鑾峰彇娲借皥杩涘害璁板綍
+      negotiationRecords.value = res.data.followUpList || [];
+
+      detailDialogVisible.value = true;
+    });
+  };
+
+  // 鍏抽棴璇︽儏寮圭獥
+  const closeDetailDialog = () => {
+    detailDialogVisible.value = false;
+  };
+
+  // 淇敼娲借皥璁板綍
+  const editNegotiationRecord = (row, index) => {
+    // 灏嗗綋鍓嶈褰曟暟鎹~鍏呭埌琛ㄥ崟
+    Object.assign(negotiationForm, {
+      customerName: row.customerName,
+      customerId: row.customerId,
+      followUpMethod: row.followUpMethod,
+      followUpLevel: row.followUpLevel,
+      followUpTime: row.followUpTime,
+      followerUserName: row.followerUserName,
+      content: row.content,
+      id: row.id, // 璁板綍ID鐢ㄤ簬鏇存柊
+      editIndex: index, // 璁板綍绱㈠紩鐢ㄤ簬鏈湴鏇存柊
+    });
+    negotiationDialogVisible.value = true;
+  };
+
+  // 鍒犻櫎娲借皥璁板綍
+  const deleteNegotiationRecord = (row, index) => {
+    ElMessageBox.confirm("纭畾瑕佸垹闄よ繖鏉℃唇璋堣褰曞悧锛�", "鍒犻櫎鎻愮ず", {
+      confirmButtonText: "纭畾",
+      cancelButtonText: "鍙栨秷",
+      type: "warning",
+    })
+      .then(() => {
+        // 杩欓噷鍙互璋冪敤鍒犻櫎鎺ュ彛
+        // 瀹為檯椤圭洰涓渶瑕佹牴鎹悗绔帴鍙h繘琛岃皟鏁�
+        // 绀轰緥锛歞eleteCustomerFollow(row.id).then(() => {
+        //   negotiationRecords.value.splice(index, 1);
+        //   proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+        // });
+        delCustomerFollow(row.id).then(() => {
+          // 鍒犻櫎鎴愬姛鍚庢洿鏂版湰鍦版暟鎹�
+          getCustomer(row.customerId).then(res => {
+            // 鏇存柊鏈湴鏁版嵁
+            negotiationRecords.value = res.data.followUpList || [];
+          });
+          proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+        });
+        // 鏈湴鍒犻櫎锛堟ā鎷燂級
+        negotiationRecords.value.splice(index, 1);
+        proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+      })
+      .catch(() => {
+        proxy.$modal.msg("宸插彇娑堝垹闄�");
+      });
+  };
+
+  // 鎵撳紑闄勪欢寮圭獥
+  const openAttachmentDialog = row => {
+    currentFollowRecord.value = row;
+    // 杞崲涓虹鍚圗lement Plus fileList鏍煎紡鐨勬暟缁�
+    currentAttachmentList.value = (row.fileList || []).map((file, index) => ({
+      name: file.fileName,
+      url: file.fileUrl,
+      size: file.fileSize,
+      id: file.id,
+      uid: file.id || index,
+      status: "success",
+    }));
+
+    attachmentDialogVisible.value = true;
+  };
+
+  // 鍏抽棴闄勪欢寮圭獥
+  const closeAttachmentDialog = () => {
+    attachmentDialogVisible.value = false;
+    currentFollowRecord.value = {};
+    currentAttachmentList.value = [];
+  };
+
+  // 闄勪欢涓婁紶鎴愬姛
+  const handleAttachmentSuccess = (response, file, fileList) => {
+    if (response.code === 200) {
+      proxy.$modal.msgSuccess("涓婁紶鎴愬姛");
+      // 鏇存柊褰撳墠璁板綍鐨勯檮浠跺垪琛�
+      currentAttachmentList.value = fileList.map(item => ({
+        name: item.name,
+        size: item.size,
+        url: item.response?.data?.url || item.url,
+        id: item.response?.data?.id,
+        uid: item.uid,
+        status: "success",
+      }));
+      // 鏇存柊鍘熻褰曚腑鐨刦iles瀛楁
+      if (currentFollowRecord.value) {
+        currentFollowRecord.value.files = [...currentAttachmentList.value];
+      }
+    } else {
+      proxy.$modal.msgError(response.msg || "涓婁紶澶辫触");
+    }
+  };
+
+  // 闄勪欢涓婁紶澶辫触
+  const handleAttachmentError = (error, file, fileList) => {
+    console.error("涓婁紶澶辫触:", error);
+    proxy.$modal.msgError("涓婁紶澶辫触");
+  };
+
+  // 闄勪欢绉婚櫎
+  const handleAttachmentRemove = (file, fileList) => {
+    currentAttachmentList.value = fileList;
+    // 鏇存柊鍘熻褰曚腑鐨刦iles瀛楁
+    if (currentFollowRecord.value) {
+      currentFollowRecord.value.files = [...fileList];
+    }
+  };
+
+  // 闄勪欢涓婁紶鍓嶆牎楠�
+  const beforeAttachmentUpload = file => {
+    const maxSize = 50 * 1024 * 1024; // 50MB
+    if (file.size > maxSize) {
+      proxy.$modal.msgError("鏂囦欢澶у皬涓嶈兘瓒呰繃50MB");
+      return false;
+    }
+    return true;
+  };
+
+  // 鏍煎紡鍖栨枃浠跺ぇ灏�
+  const formatFileSize = size => {
+    if (size < 1024) {
+      return size + " B";
+    } else if (size < 1024 * 1024) {
+      return (size / 1024).toFixed(2) + " KB";
+    } else {
+      return (size / (1024 * 1024)).toFixed(2) + " MB";
+    }
+  };
+
+  // 涓嬭浇闄勪欢
+  const downloadAttachment = row => {
+    if (row.url) {
+      // proxy.download(row.url, {}, row.name);
+      proxy.$download.name(row.url);
+    } else {
+      proxy.$modal.msgError("涓嬭浇閾炬帴涓嶅瓨鍦�");
+    }
+  };
+
+  // 鍒犻櫎闄勪欢
+  const deleteAttachment = (row, index) => {
+    ElMessageBox.confirm("纭畾瑕佸垹闄よ繖涓檮浠跺悧锛�", "鍒犻櫎鎻愮ず", {
+      confirmButtonText: "纭畾",
+      cancelButtonText: "鍙栨秷",
+      type: "warning",
+    })
+      .then(() => {
+        // 璋冪敤鍚庣鎺ュ彛鍒犻櫎闄勪欢
+        const deleteUrl =
+          import.meta.env.VITE_APP_BASE_API +
+          "/basic/customer-follow/file/" +
+          row.id;
+        fetch(deleteUrl, {
+          method: "DELETE",
+          headers: {
+            Authorization: "Bearer " + getToken(),
+            "Content-Type": "application/json",
+          },
+        })
+          .then(response => response.json())
+          .then(res => {
+            if (res.code === 200) {
+              // 鍒犻櫎鎴愬姛鍚庢洿鏂版湰鍦版枃浠跺垪琛�
+              currentAttachmentList.value.splice(index, 1);
+              // 鏇存柊鍘熻褰曚腑鐨刦iles瀛楁
+              if (currentFollowRecord.value) {
+                currentFollowRecord.value.files = [
+                  ...currentAttachmentList.value,
+                ];
+              }
+              proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+            } else {
+              proxy.$modal.msgError(res.msg || "鍒犻櫎澶辫触");
+            }
+          })
+          .catch(error => {
+            console.error("鍒犻櫎闄勪欢澶辫触:", error);
+            proxy.$modal.msgError("鍒犻櫎澶辫触");
+          });
+      })
+      .catch(() => {
+        proxy.$modal.msg("宸插彇娑堝垹闄�");
+      });
+  };
+
+  // 鑾峰彇褰撳墠鏃ユ湡骞舵牸寮忓寲涓� YYYY-MM-DD
+  function getCurrentDate() {
+    const today = new Date();
+    const year = today.getFullYear();
+    const month = String(today.getMonth() + 1).padStart(2, "0"); // 鏈堜唤浠�0寮�濮�
+    const day = String(today.getDate()).padStart(2, "0");
+    return `${year}-${month}-${day}`;
+  }
+
+  onMounted(() => {
+    getList();
+  });
+</script>
+
+<style scoped lang="scss">
+  .detail-section {
+    margin-bottom: 20px;
+    padding: 15px;
+    background-color: #f9f9f9;
+    border-radius: 4px;
+  }
+
+  .section-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 15px;
+  }
+
+  .section-title {
+    font-size: 16px;
+    font-weight: bold;
+    margin: 0 0 15px 0;
+    color: #333;
+  }
+
+  .info-display {
+    background-color: #fff;
+    padding: 15px;
+    border-radius: 4px;
+  }
+
+  .info-item {
+    margin-bottom: 12px;
+    display: flex;
+    align-items: flex-start;
+  }
+
+  .info-label {
+    width: 120px;
+    font-weight: 500;
+    color: #606266;
+    margin-right: 10px;
+  }
+
+  .info-value {
+    flex: 1;
+    color: #303133;
+    word-break: break-word;
+  }
+
+  .no-records {
+    text-align: center;
+    padding: 30px;
+    color: #999;
+    font-size: 14px;
+  }
+
+  .attachment-section {
+    .upload-area {
+      margin-bottom: 20px;
+      padding: 20px;
+      background-color: #f9f9f9;
+      border-radius: 4px;
+      border: 1px dashed #d9d9d9;
+
+      .el-upload__tip {
+        margin-top: 10px;
+        color: #909399;
+      }
+    }
+
+    .attachment-list {
+      h4 {
+        margin: 0 0 10px 0;
+        font-size: 14px;
+        color: #606266;
+      }
+    }
+
+    .no-attachment {
+      text-align: center;
+      padding: 40px;
+      color: #909399;
+      font-size: 14px;
+    }
+  }
+</style>
diff --git a/src/views/basicData/product/ProductSelectDialog.vue b/src/views/basicData/product/ProductSelectDialog.vue
index c10d29e..ad27baa 100644
--- a/src/views/basicData/product/ProductSelectDialog.vue
+++ b/src/views/basicData/product/ProductSelectDialog.vue
@@ -1,12 +1,12 @@
 <template>
   <el-dialog v-model="visible" title="閫夋嫨浜у搧" width="900px" destroy-on-close :close-on-click-modal="false">
     <el-form :inline="true" :model="query" class="mb-2">
-      <el-form-item label="浜у搧澶х被">
-        <el-input v-model="query.productName" placeholder="杈撳叆浜у搧澶х被" clearable @keyup.enter="onSearch" />
+      <el-form-item label="浜у搧鍚嶇О">
+        <el-input v-model="query.productName" placeholder="杈撳叆浜у搧鍚嶇О" clearable @keyup.enter="onSearch" />
       </el-form-item>
 
-      <el-form-item label="鍨嬪彿鍚嶇О">
-        <el-input v-model="query.model" placeholder="杈撳叆鍨嬪彿鍚嶇О" clearable @keyup.enter="onSearch" />
+      <el-form-item label="浜у搧鍨嬪彿">
+        <el-input v-model="query.model" placeholder="杈撳叆浜у搧鍨嬪彿" clearable @keyup.enter="onSearch" />
       </el-form-item>
 
       <el-form-item>
@@ -20,8 +20,8 @@
       @selection-change="handleSelectionChange" @select="handleSelect">
       <el-table-column type="selection" width="55" />
       <el-table-column type="index" label="搴忓彿" width="60" />
-      <el-table-column prop="productName" label="浜у搧澶х被" min-width="160" />
-      <el-table-column prop="model" label="鍨嬪彿鍚嶇О" min-width="200" />
+      <el-table-column prop="productName" label="浜у搧鍚嶇О" min-width="160" />
+      <el-table-column prop="model" label="浜у搧鍨嬪彿" min-width="200" />
       <el-table-column prop="unit" label="鍗曚綅" min-width="160" />
     </el-table>
 
@@ -43,7 +43,7 @@
 <script setup lang="ts">
 import { computed, onMounted, reactive, ref, watch, nextTick } from "vue";
 import { ElMessage } from "element-plus";
-import { productModelList } from '@/api/basicData/productModel'
+import { productModelList, productModelListByUrl } from '@/api/basicData/productModel'
 
 export type ProductRow = {
   id: number;
@@ -56,6 +56,7 @@
   modelValue: boolean;
   single?: boolean; // 鏄惁鍙兘閫夋嫨涓�涓紝榛樿false锛堝彲閫夋嫨澶氫釜锛�
   topProductParentId?: number; // 涓�绾т骇鍝乮d
+  requestUrl?: string; // 鑷畾涔夋煡璇㈡帴鍙�
 }>();
 
 const emit = defineEmits(['update:modelValue', 'confirm']);
@@ -155,15 +156,19 @@
   loading.value = true;
   try {
     multipleSelection.value = []; // 缈婚〉/鎼滅储鍚庢竻绌洪�夋嫨鏇寸鍚堥鏈�
-    const res: any = await productModelList({
+    const params = {
       productName: query.productName.trim(),
       model: query.model.trim(),
       current: page.pageNum,
       size: page.pageSize,
       topProductParentId: props.topProductParentId,
-    });
-    tableData.value = res.records;
-    total.value = res.total;
+    };
+    const res: any = props.requestUrl
+      ? await productModelListByUrl(props.requestUrl, params)
+      : await productModelList(params);
+    const records = res?.records || res?.data?.records || res?.data || [];
+    tableData.value = Array.isArray(records) ? records : [];
+    total.value = Number(res?.total ?? res?.data?.total ?? tableData.value.length);
   } finally {
     loading.value = false;
   }
diff --git a/src/views/basicData/product/index.vue b/src/views/basicData/product/index.vue
index 3b86b37..10b51bf 100644
--- a/src/views/basicData/product/index.vue
+++ b/src/views/basicData/product/index.vue
@@ -12,6 +12,7 @@
           prefix-icon="Search"
         />
         <el-button
+          v-if="false"
           type="primary"
           @click="openProDia('addOne')"
           style="margin-left: 10px"
@@ -49,6 +50,7 @@
                 <el-button
                   type="primary"
                   link
+                  :disabled="isTopLevelNode(data, node)"
                   @click="openProDia('edit', data)"
                 >
                   缂栬緫
@@ -61,6 +63,7 @@
                   style="margin-left: 4px"
                   type="danger"
                   link
+                  :disabled="isTopLevelNode(data, node)"
                   @click="remove(node, data)"
                 >
                   鍒犻櫎
@@ -375,8 +378,18 @@
 const searchFilter = () => {
   proxy.$refs.tree.filter(search.value);
 };
+const isTopLevelNode = (data, node) => {
+  if (node?.level !== undefined) {
+    return node.level === 1;
+  }
+  return [null, undefined, "", 0, "0"].includes(data?.parentId);
+};
 // 鎵撳紑浜у搧寮规
 const openProDia = (type, data) => {
+  if (data && type === "edit" && isTopLevelNode(data)) {
+    proxy.$modal.msgWarning("涓�绾ц妭鐐逛笉鑳界紪杈戞垨鍒犻櫎");
+    return;
+  }
   operationType.value = type;
   productDia.value = true;
   form.value.productName = "";
@@ -425,6 +438,10 @@
 
 // 鍒犻櫎浜у搧
 const remove = (node, data) => {
+  if (isTopLevelNode(data, node)) {
+    proxy.$modal.msgWarning("涓�绾ц妭鐐逛笉鑳界紪杈戞垨鍒犻櫎");
+    return;
+  }
   let ids = [];
   ids.push(data.id);
   ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "鍒犻櫎鎻愮ず", {
diff --git a/src/views/customerService/feedbackRegistration/components/formDia.vue b/src/views/customerService/feedbackRegistration/components/formDia.vue
index 93e5c6b..1fe4eb6 100644
--- a/src/views/customerService/feedbackRegistration/components/formDia.vue
+++ b/src/views/customerService/feedbackRegistration/components/formDia.vue
@@ -79,9 +79,9 @@
               </el-form-item>
             </el-col>
             <el-col :span="4">
-              <el-form-item label="闂鎻忚堪锛�" prop="disRes">
+              <el-form-item label="闂鎻忚堪锛�" prop="proDesc">
                 <el-input
-                    v-model="form.disRes"
+                    v-model="form.proDesc"
                     placeholder="璇疯緭鍏ラ棶棰樻弿杩�"
                 />
               </el-form-item>
@@ -160,7 +160,7 @@
     productModelIds: "",
     customerId: null,
     salesContractNo: "",
-    disRes: "",
+    proDesc: "",
     customerName: ""
 	},
 	rules: {
diff --git a/src/views/customerService/feedbackRegistration/index.vue b/src/views/customerService/feedbackRegistration/index.vue
index 555dab5..40d99be 100644
--- a/src/views/customerService/feedbackRegistration/index.vue
+++ b/src/views/customerService/feedbackRegistration/index.vue
@@ -255,7 +255,7 @@
   },
   {
     label: "闂鎻忚堪",
-    prop: "disRes",
+    prop: "proDesc",
     width:300,
   },
   {
@@ -267,7 +267,6 @@
   {
     dataType: "action",
     label: "鎿嶄綔",
-    align: "center",
     fixed: 'right',
     operation: [
       {
diff --git a/src/views/procurementManagement/procurementLedger/index.vue b/src/views/procurementManagement/procurementLedger/index.vue
index 8a293fc..0543286 100644
--- a/src/views/procurementManagement/procurementLedger/index.vue
+++ b/src/views/procurementManagement/procurementLedger/index.vue
@@ -546,6 +546,7 @@
               <el-tree-select v-model="productForm.productId"
                               placeholder="璇烽�夋嫨"
                               clearable
+                              filterable
                               check-strictly
                               @change="getModels"
                               :data="productOptions"
@@ -560,6 +561,7 @@
                           prop="productModelId">
               <el-select v-model="productForm.productModelId"
                          placeholder="璇烽�夋嫨"
+                         filterable
                          clearable
                          @change="getProductModel">
                 <el-option v-for="item in modelOptions"
@@ -1685,12 +1687,12 @@
   const handleDelete = () => {
     let ids = [];
     if (selectedRows.value.length > 0) {
-      ids = selectedRows.value.map(item => item.id);
+      ids = selectedRows.value.filter(item => item.salesLedgerId === null).map(item => item.id);
     } else {
       proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
       return;
     }
-    ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "瀵煎嚭", {
+    ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "鍒犻櫎", {
       confirmButtonText: "纭",
       cancelButtonText: "鍙栨秷",
       type: "warning",
diff --git a/src/views/procurementManagement/procurementReport/index.vue b/src/views/procurementManagement/procurementReport/index.vue
index 93eb7d9..4ba1802 100644
--- a/src/views/procurementManagement/procurementReport/index.vue
+++ b/src/views/procurementManagement/procurementReport/index.vue
@@ -262,6 +262,7 @@
         businessSummaryStats.value.returnAmount = businessSummaryData.value.reduce((sum, item) => {
           return sum + (parseFloat(item.returnAmount) || 0)
         }, 0)
+        businessSummaryStats.value.productTypes = businessSummaryData.value.length
       } else {
         businessSummaryStats.value = {
           totalAmount: 0,
diff --git a/src/views/procurementManagement/purchaseReturnOrder/New.vue b/src/views/procurementManagement/purchaseReturnOrder/New.vue
index 17e36dc..dffdeea 100644
--- a/src/views/procurementManagement/purchaseReturnOrder/New.vue
+++ b/src/views/procurementManagement/purchaseReturnOrder/New.vue
@@ -70,6 +70,7 @@
               v-model="formState.supplierId"
               placeholder="璇烽�夋嫨渚涘簲鍟�"
               style="width: 240px"
+							filterable
               @focus="fetchSupplierOptions"
               @change="handleChangeSupplierId"
           >
diff --git a/src/views/productionManagement/productStructure/Detail/index.vue b/src/views/productionManagement/productStructure/Detail/index.vue
index 5787c5d..750d584 100644
--- a/src/views/productionManagement/productStructure/Detail/index.vue
+++ b/src/views/productionManagement/productStructure/Detail/index.vue
@@ -587,4 +587,4 @@
     await fetchProcessOptions();
     await fetchData();
   });
-</script>
+</script>
\ No newline at end of file
diff --git a/src/views/productionManagement/productionOrder/components/MaterialDetailDialog.vue b/src/views/productionManagement/productionOrder/components/MaterialDetailDialog.vue
new file mode 100644
index 0000000..9c50fc8
--- /dev/null
+++ b/src/views/productionManagement/productionOrder/components/MaterialDetailDialog.vue
@@ -0,0 +1,181 @@
+<template>
+  <div>
+    <el-dialog v-model="dialogVisible" title="棰嗘枡璇︽儏" width="1400px" @close="handleClose">
+      <el-table v-loading="materialDetailLoading" :data="materialDetailTableData" border row-key="id">
+        <el-table-column label="宸ュ簭鍚嶇О" prop="processName" min-width="180" />
+        <el-table-column label="鍘熸枡鍚嶇О" prop="materialName" min-width="160" />
+        <el-table-column label="鍘熸枡鍨嬪彿" prop="materialModel" min-width="180" />
+        <el-table-column label="闇�姹傛暟閲�" prop="requiredQty" min-width="110" />
+        <el-table-column label="璁¢噺鍗曚綅" prop="unit" width="100" />
+        <el-table-column label="棰嗙敤鏁伴噺" prop="pickQty" min-width="110" />
+        <el-table-column label="琛ユ枡鏁伴噺" min-width="120">
+          <template #default="{ row }">
+            <el-button type="primary" link @click="handleViewSupplementRecord(row)">
+              {{ row.supplementQty ?? 0 }}
+            </el-button>
+          </template>
+        </el-table-column>
+        <el-table-column label="閫�鏂欐暟閲�" prop="returnQty" min-width="110" />
+        <el-table-column label="瀹為檯鏁伴噺" prop="actualQty" min-width="110" />
+      </el-table>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button
+            type="warning"
+            :loading="materialReturnConfirming"
+            :disabled="!canOpenReturnSummary"
+            @click="openReturnSummaryDialog"
+          >
+            閫�鏂欑‘璁�
+          </el-button>
+          <el-button @click="dialogVisible = false">鍙栨秷</el-button>
+        </span>
+      </template>
+    </el-dialog>
+
+    <el-dialog v-model="supplementRecordDialogVisible" title="琛ユ枡璁板綍" width="800px">
+      <el-table v-loading="supplementRecordLoading" :data="supplementRecordTableData" border row-key="id">
+        <el-table-column label="琛ユ枡鏁伴噺" prop="supplementQty" min-width="120" />
+        <el-table-column label="琛ユ枡浜�" prop="supplementUserName" min-width="120" />
+        <el-table-column label="琛ユ枡鏃ユ湡" prop="supplementTime" min-width="160" />
+        <el-table-column label="琛ユ枡鍘熷洜" prop="supplementReason" min-width="200" />
+      </el-table>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button @click="supplementRecordDialogVisible = false">鍏抽棴</el-button>
+        </span>
+      </template>
+    </el-dialog>
+
+    <el-dialog v-model="returnSummaryDialogVisible" title="閫�鏂欐眹鎬荤‘璁�" width="900px">
+      <el-table :data="returnSummaryList" border row-key="summaryKey">
+        <el-table-column label="鍘熸枡鍚嶇О" prop="materialName" min-width="180" />
+        <el-table-column label="鍘熸枡鍨嬪彿" prop="materialModel" min-width="180" />
+        <el-table-column label="璁¢噺鍗曚綅" prop="unit" min-width="100" />
+        <el-table-column label="閫�鏂欐眹鎬绘暟閲�" prop="returnQtyTotal" min-width="140" />
+      </el-table>
+
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button type="primary" :loading="materialReturnConfirming" @click="handleReturnConfirm">纭鎻愪氦</el-button>
+          <el-button @click="returnSummaryDialogVisible = false">鍙栨秷</el-button>
+        </span>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import { computed, ref, watch } from "vue";
+import { ElMessage } from "element-plus";
+import { listMaterialPickingDetail, listMaterialSupplementRecord, confirmMaterialReturn } from "@/api/productionManagement/productionOrder.js";
+
+const props = defineProps({
+  modelValue: { type: Boolean, default: false },
+  orderRow: { type: Object, default: null },
+});
+const emit = defineEmits(["update:modelValue", "confirmed"]);
+
+const dialogVisible = computed({
+  get: () => props.modelValue,
+  set: val => emit("update:modelValue", val),
+});
+
+const materialDetailLoading = ref(false);
+const materialDetailTableData = ref([]);
+const materialReturnConfirming = ref(false);
+const supplementRecordDialogVisible = ref(false);
+const supplementRecordLoading = ref(false);
+const supplementRecordTableData = ref([]);
+const returnSummaryDialogVisible = ref(false);
+const returnSummaryList = ref([]);
+const calcReturnQty = item =>
+  Number(item.pickQty || 0) + Number(item.supplementQty || 0) - Number(item.actualQty || 0);
+const canOpenReturnSummary = computed(() =>
+  materialDetailTableData.value.some(item => calcReturnQty(item) > 0)
+);
+
+const loadDetailList = async () => {
+  if (!props.orderRow?.id) return;
+  materialDetailLoading.value = true;
+  materialDetailTableData.value = [];
+  try {
+    const res = await listMaterialPickingDetail({ orderId: props.orderRow.id });
+    materialDetailTableData.value = res.data || [];
+  } finally {
+    materialDetailLoading.value = false;
+  }
+};
+
+watch(
+  () => dialogVisible.value,
+  visible => {
+    if (visible) {
+      loadDetailList();
+    }
+  }
+);
+
+const handleClose = () => {
+  materialDetailTableData.value = [];
+};
+
+const handleViewSupplementRecord = async row => {
+  if (!row?.id) return;
+  supplementRecordDialogVisible.value = true;
+  supplementRecordLoading.value = true;
+  supplementRecordTableData.value = [];
+  try {
+    const res = await listMaterialSupplementRecord({ materialDetailId: row.id });
+    supplementRecordTableData.value = res.data || [];
+  } finally {
+    supplementRecordLoading.value = false;
+  }
+};
+
+const buildReturnSummary = () => {
+  const map = new Map();
+  materialDetailTableData.value.forEach(item => {
+    const returnQty = calcReturnQty(item);
+    if (returnQty <= 0) return;
+    const key = `${item.materialModelId || ""}_${item.materialName || ""}_${item.materialModel || ""}_${item.unit || ""}`;
+    const old = map.get(key) || {
+      summaryKey: key,
+      materialName: item.materialName || "",
+      materialModel: item.materialModel || "",
+      unit: item.unit || "",
+      returnQtyTotal: 0,
+    };
+    old.returnQtyTotal += returnQty;
+    map.set(key, old);
+  });
+  return Array.from(map.values());
+};
+
+const openReturnSummaryDialog = async () => {
+  if (!canOpenReturnSummary.value) {
+    ElMessage.warning("閫�鏂欐暟閲�=棰嗙敤鏁伴噺+琛ユ枡鏁伴噺-瀹為檯鏁伴噺锛屼笖闇�澶т簬0");
+    return;
+  }
+  returnSummaryList.value = buildReturnSummary();
+  returnSummaryDialogVisible.value = true;
+};
+
+const handleReturnConfirm = async () => {
+  if (!props.orderRow?.id) return;
+  materialReturnConfirming.value = true;
+  try {
+    await confirmMaterialReturn({
+      orderId: props.orderRow.id,
+      returnSummaryList: returnSummaryList.value,
+    });
+    returnSummaryDialogVisible.value = false;
+    dialogVisible.value = false;
+    emit("confirmed");
+  } finally {
+    materialReturnConfirming.value = false;
+  }
+};
+</script>
+
+<style scoped lang="scss"></style>
diff --git a/src/views/productionManagement/productionOrder/components/MaterialLedgerDialog.vue b/src/views/productionManagement/productionOrder/components/MaterialLedgerDialog.vue
new file mode 100644
index 0000000..9e1a852
--- /dev/null
+++ b/src/views/productionManagement/productionOrder/components/MaterialLedgerDialog.vue
@@ -0,0 +1,298 @@
+<template>
+  <div>
+    <el-dialog v-model="dialogVisible" title="棰嗘枡鍙拌处" width="1200px" @close="handleClose">
+      <div class="material-toolbar">
+        <el-button type="primary" @click="handleAddMaterialRow">鏂板</el-button>
+      </div>
+      <el-table v-loading="materialTableLoading" :data="materialTableData" border row-key="tempId">
+        <el-table-column label="宸ュ簭鍚嶇О" min-width="180">
+          <template #default="{ row }">
+            <span v-if="row.bom === true">{{ row.processName || "-" }}</span>
+            <el-select
+              v-else
+              v-model="row.processName"
+              placeholder="璇烽�夋嫨宸ュ簭"
+              clearable
+              filterable
+              style="width: 100%;"
+              @change="val => handleProcessNameChange(row, val)"
+            >
+              <el-option v-for="item in processOptions" :key="item.id" :label="item.name" :value="item.name" />
+            </el-select>
+          </template>
+        </el-table-column>
+        <el-table-column label="鍘熸枡鍚嶇О" min-width="160">
+          <template #default="{ row }">
+            <span v-if="row.bom === true">{{ row.materialName || "-" }}</span>
+            <el-button v-else type="primary" link @click="openMaterialProductSelect(row)">
+              {{ row.materialName || "閫夋嫨鍘熸枡" }}
+            </el-button>
+          </template>
+        </el-table-column>
+        <el-table-column label="鍘熸枡鍨嬪彿" min-width="180">
+          <template #default="{ row }">
+            {{ row.materialModel || "-" }}
+          </template>
+        </el-table-column>
+        <el-table-column label="闇�姹傛暟閲�" min-width="120">
+          <template #default="{ row }">
+            <span v-if="row.bom === true">{{ row.requiredQty ?? "-" }}</span>
+            <el-input-number
+              v-else
+              v-model="row.requiredQty"
+              :min="0"
+              :precision="3"
+              :step="1"
+              controls-position="right"
+              style="width: 100%;"
+              @change="val => handleRequiredQtyChange(row, val)"
+            />
+          </template>
+        </el-table-column>
+        <el-table-column label="璁¢噺鍗曚綅" width="120">
+          <template #default="{ row }">
+            {{ row.unit || "-" }}
+          </template>
+        </el-table-column>
+        <el-table-column label="棰嗙敤鏁伴噺" min-width="120">
+          <template #default="{ row }">
+            <el-input-number
+              v-model="row.pickQty"
+              :min="0"
+              :precision="3"
+              :step="1"
+              controls-position="right"
+              style="width: 100%;"
+            />
+          </template>
+        </el-table-column>
+        <el-table-column label="鎿嶄綔" width="90" fixed="right">
+          <template #default="{ $index, row }">
+            <el-button v-if="row.bom !== true" type="danger" link @click="handleDeleteMaterialRow($index)">鍒犻櫎</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button type="primary" :loading="materialSaving" @click="handleMaterialSave">淇濆瓨</el-button>
+          <el-button @click="dialogVisible = false">鍙栨秷</el-button>
+        </span>
+      </template>
+    </el-dialog>
+
+    <ProductSelectDialog
+      v-model="materialProductDialogVisible"
+      @confirm="handleMaterialProductConfirm"
+      single
+      request-url="/stockInventory/rawMaterials"
+    />
+  </div>
+</template>
+
+<script setup>
+import { computed, ref, watch } from "vue";
+import { ElMessage } from "element-plus";
+import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue";
+import { findProductProcessRouteItemList } from "@/api/productionManagement/productProcessRoute.js";
+import {
+  listMaterialPickingDetail,
+  listMaterialPickingLedger,
+  saveMaterialPickingLedger,
+} from "@/api/productionManagement/productionOrder.js";
+
+const props = defineProps({
+  modelValue: { type: Boolean, default: false },
+  orderRow: { type: Object, default: null },
+});
+const emit = defineEmits(["update:modelValue", "saved"]);
+
+const dialogVisible = computed({
+  get: () => props.modelValue,
+  set: val => emit("update:modelValue", val),
+});
+
+const materialProductDialogVisible = ref(false);
+const materialTableLoading = ref(false);
+const materialSaving = ref(false);
+const materialTableData = ref([]);
+const processOptions = ref([]);
+const currentMaterialSelectRowIndex = ref(-1);
+let materialTempId = 0;
+
+const createMaterialRow = (row = {}) => ({
+  tempId: row.id || `temp_${++materialTempId}`,
+  id: row.id,
+  processId: row.processId,
+  productProcessId: row.productProcessId || row.processId,
+  processName: row.processName || "",
+  bom: row.bom === true,
+  materialModelId: row.materialModelId,
+  materialName: row.materialName || "",
+  materialModel: row.materialModel || "",
+  requiredQty: Number(row.requiredQty ?? 0),
+  unit: row.unit || "",
+  pickQty: Number(row.pickQty ?? row.requiredQty ?? 0),
+});
+
+const getProcessOptions = async () => {
+  if (!props.orderRow?.id) return;
+  const res = await findProductProcessRouteItemList({ orderId: props.orderRow.id });
+  const routeList = Array.isArray(res?.data) ? res.data : res?.data?.records || [];
+  const processMap = new Map();
+  routeList.forEach(item => {
+    const processId = item.processId;
+    const processName = item.processName;
+    if (!processId || !processName) return;
+    const key = `${processId}_${processName}`;
+    if (!processMap.has(key)) {
+      processMap.set(key, {
+        id: processId,
+        name: processName,
+      });
+    }
+  });
+  processOptions.value = Array.from(processMap.values());
+};
+
+const loadMaterialData = async () => {
+  if (!props.orderRow?.id) return;
+  materialTableLoading.value = true;
+  materialTableData.value = [];
+  await getProcessOptions();
+  try {
+    const detailRes = await listMaterialPickingDetail({ orderId: props.orderRow.id });
+    const detailList = Array.isArray(detailRes?.data)
+      ? detailRes.data
+      : detailRes?.data?.records || [];
+    if (detailList.length > 0) {
+      materialTableData.value = detailList.map(item => createMaterialRow(item));
+      return;
+    }
+    const ledgerRes = await listMaterialPickingLedger({ orderId: props.orderRow.id });
+    const ledgerList = Array.isArray(ledgerRes?.data)
+      ? ledgerRes.data
+      : ledgerRes?.data?.records || [];
+    materialTableData.value = ledgerList.map(item => createMaterialRow(item));
+  } finally {
+    materialTableLoading.value = false;
+  }
+};
+
+watch(
+  () => dialogVisible.value,
+  visible => {
+    if (visible) {
+      loadMaterialData();
+    }
+  }
+);
+
+const handleClose = () => {
+  materialTableData.value = [];
+  currentMaterialSelectRowIndex.value = -1;
+};
+
+const handleAddMaterialRow = () => {
+  materialTableData.value.push(createMaterialRow());
+};
+
+const handleDeleteMaterialRow = index => {
+  materialTableData.value.splice(index, 1);
+};
+
+const handleProcessNameChange = (row, processName) => {
+  const process = processOptions.value.find(item => item.name === processName);
+  row.productProcessId = process?.id;
+};
+
+const handleRequiredQtyChange = (row, val) => {
+  const required = Number(val ?? 0);
+  row.requiredQty = required;
+  if (!row.pickQty || Number(row.pickQty) === 0) {
+    row.pickQty = required;
+  }
+};
+
+const openMaterialProductSelect = row => {
+  currentMaterialSelectRowIndex.value = materialTableData.value.findIndex(item => item.tempId === row.tempId);
+  materialProductDialogVisible.value = true;
+};
+
+const handleMaterialProductConfirm = products => {
+  if (!products || products.length === 0) return;
+  const index = currentMaterialSelectRowIndex.value;
+  if (index < 0 || !materialTableData.value[index]) return;
+  const product = products[0];
+  const row = materialTableData.value[index];
+  row.materialModelId = product.materialModelId || product.modelId || product.id;
+  row.materialName = product.materialName || product.productName || product.name || "";
+  row.materialModel = product.materialModel || product.model || "";
+  row.unit = product.unit || product.measureUnit || "";
+  currentMaterialSelectRowIndex.value = -1;
+  materialProductDialogVisible.value = false;
+};
+
+const validateMaterialRows = () => {
+  if (materialTableData.value.length === 0) {
+    return { valid: false, message: "璇峰厛鏂板棰嗘枡鏁版嵁" };
+  }
+  const invalidNewRow = materialTableData.value.find(
+    item => item.bom !== true && (!item.processName || !item.materialName)
+  );
+  if (invalidNewRow) {
+    return { valid: false, message: "鏂板琛岀殑宸ュ簭鍚嶇О鍜屽師鏂欏悕绉颁负蹇呭~椤�" };
+  }
+  const invalidRow = materialTableData.value.find(
+    item =>
+      !item.processName ||
+      !item.materialName ||
+      item.requiredQty === null ||
+      item.requiredQty === undefined ||
+      item.pickQty === null ||
+      item.pickQty === undefined
+  );
+  if (invalidRow) {
+    return { valid: false, message: "璇峰畬鍠勫伐搴忋�佸師鏂欏拰鏁伴噺鍚庡啀淇濆瓨" };
+  }
+  return { valid: true, message: "" };
+};
+
+const handleMaterialSave = async () => {
+  if (!props.orderRow?.id) return;
+  const validateResult = validateMaterialRows();
+  if (!validateResult.valid) {
+    ElMessage.warning(validateResult.message);
+    return;
+  }
+  materialSaving.value = true;
+  try {
+    await saveMaterialPickingLedger({
+      orderId: props.orderRow.id,
+      items: materialTableData.value.map(item => ({
+        id: item.id,
+        processId: item.processName,
+        productProcessId: item.productProcessId,
+        processName: item.processName,
+        bom: item.bom === true,
+        materialModelId: item.materialModelId,
+        materialName: item.materialName,
+        materialModel: item.materialModel,
+        requiredQty: item.requiredQty,
+        unit: item.unit,
+        pickQty: item.pickQty,
+      })),
+    });
+    emit("saved");
+    dialogVisible.value = false;
+  } finally {
+    materialSaving.value = false;
+  }
+};
+</script>
+
+<style scoped lang="scss">
+.material-toolbar {
+  margin-bottom: 12px;
+  text-align: right;
+}
+</style>
diff --git a/src/views/productionManagement/productionOrder/index.vue b/src/views/productionManagement/productionOrder/index.vue
index 729cd5a..667688e 100644
--- a/src/views/productionManagement/productionOrder/index.vue
+++ b/src/views/productionManagement/productionOrder/index.vue
@@ -3,6 +3,14 @@
     <div class="search_form">
       <el-form :model="searchForm"
                :inline="true">
+        <el-form-item label="鐢熶骇璁㈠崟鍙�:">
+          <el-input v-model="searchForm.npsNo"
+                    placeholder="璇疯緭鍏�"
+                    clearable
+                    prefix-icon="Search"
+                    style="width: 160px;"
+                    @change="handleQuery" />
+        </el-form-item>
         <el-form-item label="瀹㈡埛鍚嶇О:">
           <el-input v-model="searchForm.customerName"
                     placeholder="璇疯緭鍏�"
@@ -40,7 +48,7 @@
                      @click="handleQuery">鎼滅储</el-button>
         </el-form-item>
       </el-form>
-      <div>
+      <div class="action-buttons">
         <el-button type="primary" @click="isShowNewModal = true">鏂板</el-button>
         <el-button type="danger" @click="handleDelete">鍒犻櫎</el-button>
         <el-button @click="handleOut">瀵煎嚭</el-button>
@@ -91,6 +99,17 @@
       </template>
     </el-dialog>
 
+    <MaterialLedgerDialog
+      v-model="materialDialogVisible"
+      :order-row="currentMaterialOrder"
+      @saved="getList"
+    />
+    <MaterialDetailDialog
+      v-model="materialDetailDialogVisible"
+      :order-row="currentMaterialDetailOrder"
+      @confirmed="getList"
+    />
+
     <new-product-order v-if="isShowNewModal"
                          v-model:visible="isShowNewModal"
                          @completed="handleQuery" />
@@ -98,7 +117,7 @@
 </template>
 
 <script setup>
-  import { onMounted, ref } from "vue";
+  import { computed, defineAsyncComponent, getCurrentInstance, onMounted, reactive, ref, toRefs } from "vue";
   import { ElMessageBox } from "element-plus";
   import dayjs from "dayjs";
   import { useRouter } from "vue-router";
@@ -109,7 +128,8 @@
     listProcessBom, delProductOrder,
   } from "@/api/productionManagement/productionOrder.js";
   import { listMain as getOrderProcessRouteMain } from "@/api/productionManagement/productProcessRoute.js";
-  import {fileDel} from "@/api/financialManagement/revenueManagement.js";
+  import MaterialLedgerDialog from "@/views/productionManagement/productionOrder/components/MaterialLedgerDialog.vue";
+  import MaterialDetailDialog from "@/views/productionManagement/productionOrder/components/MaterialDetailDialog.vue";
   import PIMTable from "@/components/PIMTable/PIMTable.vue";
   const NewProductOrder = defineAsyncComponent(() => import("@/views/productionManagement/productionOrder/New.vue"));
 
@@ -122,7 +142,7 @@
     {
       label: "鐢熶骇璁㈠崟鍙�",
       prop: "npsNo",
-      width: '120px',
+      width: '150px',
     },
     {
       label: "閿�鍞悎鍚屽彿",
@@ -187,7 +207,7 @@
       label: "鎿嶄綔",
       align: "center",
       fixed: "right",
-      width: 200,
+      width: 340,
       operation: [
         {
           name: "宸ヨ壓璺嚎",
@@ -204,11 +224,25 @@
             openBindRouteDialog(row);
           },
         },
+        // {
+        //   name: "浜у搧缁撴瀯",
+        //   type: "text",
+        //   clickFun: row => {
+        //     showProductStructure(row);
+        //   },
+        // },
         {
-          name: "浜у搧缁撴瀯",
+          name: "棰嗘枡",
           type: "text",
           clickFun: row => {
-            showProductStructure(row);
+            openMaterialDialog(row);
+          },
+        },
+        {
+          name: "棰嗘枡璇︽儏",
+          type: "text",
+          clickFun: row => {
+            openMaterialDetailDialog(row);
           },
         },
       ],
@@ -225,6 +259,7 @@
 
   const data = reactive({
     searchForm: {
+      npsNo: "",
       customerName: "",
       salesContractNo: "",
       projectName: "",
@@ -277,6 +312,10 @@
     orderId: null,
     routeId: null,
   });
+  const materialDialogVisible = ref(false);
+  const currentMaterialOrder = ref(null);
+  const materialDetailDialogVisible = ref(false);
+  const currentMaterialDetailOrder = ref(null);
 
   const openBindRouteDialog = async row => {
     bindForm.orderId = row.id;
@@ -320,6 +359,16 @@
     } finally {
       bindRouteSaving.value = false;
     }
+  };
+
+  const openMaterialDialog = row => {
+    currentMaterialOrder.value = row;
+    materialDialogVisible.value = true;
+  };
+
+  const openMaterialDetailDialog = async row => {
+    currentMaterialDetailOrder.value = row;
+    materialDetailDialogVisible.value = true;
   };
 
   // 鏌ヨ鍒楄〃
@@ -372,6 +421,7 @@
         path: "/productionManagement/processRouteItem",
         query: {
           id: data.id,
+          bomId: data.bomId,
           processRouteCode: data.processRouteCode || "",
           productName: data.productName || "",
           model: data.model || "",
@@ -455,6 +505,12 @@
   align-items: start;
 }
 
+.action-buttons {
+  display: flex;
+  flex-wrap: nowrap;
+  gap: 8px;
+}
+
 :deep(.yellow) {
   background-color: #FAF0DE;
 }
@@ -473,4 +529,5 @@
 .table_list {
 	margin-top: unset;
 }
+
 </style>
diff --git a/src/views/productionManagement/productionProcess/Edit.vue b/src/views/productionManagement/productionProcess/Edit.vue
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/views/productionManagement/productionProcess/Edit.vue
diff --git a/src/views/productionManagement/productionProcess/New.vue b/src/views/productionManagement/productionProcess/New.vue
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/views/productionManagement/productionProcess/New.vue
diff --git a/src/views/productionManagement/workOrderEdit/index.vue b/src/views/productionManagement/workOrderEdit/index.vue
index 50f9fce..52a36cd 100644
--- a/src/views/productionManagement/workOrderEdit/index.vue
+++ b/src/views/productionManagement/workOrderEdit/index.vue
@@ -4,59 +4,74 @@
       <div class="search-row">
         <div class="search-item">
           <span class="search_title">宸ュ崟缂栧彿锛�</span>
-          <el-input v-model="searchForm.workOrderNo"
-                    style="width: 240px"
-                    placeholder="璇疯緭鍏�"
-                    @change="handleQuery"
-                    clearable
-                    prefix-icon="Search" />
+          <el-input
+            v-model="searchForm.workOrderNo"
+            style="width: 240px"
+            placeholder="璇疯緭鍏�"
+            @change="handleQuery"
+            clearable
+            prefix-icon="Search"
+          />
         </div>
         <div class="search-item">
-          <el-button type="primary"
-                     @click="handleQuery">鎼滅储</el-button>
+          <span class="search_title">鐢熶骇璁㈠崟鍙凤細</span>
+          <el-input
+            v-model="searchForm.productOrderNpsNo"
+            style="width: 240px"
+            placeholder="璇疯緭鍏�"
+            @change="handleQuery"
+            clearable
+            prefix-icon="Search"
+          />
+        </div>
+        <div class="search-item">
+          <el-button type="primary" @click="handleQuery">鎼滅储</el-button>
         </div>
       </div>
     </div>
     <div class="table_list">
-      <PIMTable rowKey="id"
-                :column="tableColumn"
-                :tableData="tableData"
-                :page="page"
-                :tableLoading="tableLoading"
-                @pagination="pagination">
+      <PIMTable
+        rowKey="id"
+        :column="tableColumn"
+        :tableData="tableData"
+        :page="page"
+        :tableLoading="tableLoading"
+        @pagination="pagination"
+      >
         <template #completionStatus="{ row }">
-          <el-progress :percentage="toProgressPercentage(row?.completionStatus)"
-                       :color="progressColor(toProgressPercentage(row?.completionStatus))"
-                       :status="toProgressPercentage(row?.completionStatus) >= 100 ? 'success' : ''" />
+          <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="缂栬緫璁″垝鏃堕棿"
-               width="500px">
-      <el-form :model="editrow"
-               label-width="120px">
+
+    <el-dialog v-model="editDialogVisible" title="缂栬緫璁″垝鏃堕棿" width="500px">
+      <el-form :model="editrow" label-width="120px">
         <el-form-item label="璁″垝寮�濮嬫椂闂�">
-          <el-date-picker v-model="editrow.planStartTime"
-                          type="date"
-                          placeholder="璇烽�夋嫨"
-                          value-format="YYYY-MM-DD"
-                          style="width: 300px" />
+          <el-date-picker
+            v-model="editrow.planStartTime"
+            type="date"
+            placeholder="璇烽�夋嫨"
+            value-format="YYYY-MM-DD"
+            style="width: 300px"
+          />
         </el-form-item>
         <el-form-item label="璁″垝缁撴潫鏃堕棿">
-          <el-date-picker v-model="editrow.planEndTime"
-                          type="date"
-                          placeholder="璇烽�夋嫨"
-                          value-format="YYYY-MM-DD"
-                          style="width: 300px" />
+          <el-date-picker
+            v-model="editrow.planEndTime"
+            type="date"
+            placeholder="璇烽�夋嫨"
+            value-format="YYYY-MM-DD"
+            style="width: 300px"
+          />
         </el-form-item>
       </el-form>
       <template #footer>
         <span class="dialog-footer">
-          <el-button type="primary"
-                     @click="handleUpdate">纭畾</el-button>
+          <el-button type="primary" @click="handleUpdate">纭畾</el-button>
           <el-button @click="editDialogVisible = false">鍙栨秷</el-button>
         </span>
       </template>
@@ -65,196 +80,200 @@
 </template>
 
 <script setup>
-  import { onMounted, ref, nextTick } from "vue";
-  import { ElMessageBox } from "element-plus";
-  import dayjs from "dayjs";
-  import {
-    productWorkOrderPage,
-    updateProductWorkOrder,
-  } from "@/api/productionManagement/workOrder.js";
-  import { getCurrentInstance, reactive, toRefs } from "vue";
-  const { proxy } = getCurrentInstance();
+import { getCurrentInstance, onMounted, reactive, ref, toRefs } from "vue";
+import { ElMessageBox } from "element-plus";
+import {
+  productWorkOrderPage,
+  updateProductWorkOrder,
+} from "@/api/productionManagement/workOrder.js";
 
-  const tableColumn = ref([
-    {
-      label: "宸ュ崟绫诲瀷",
-      prop: "workOrderType",
-      width: "80",
-    },
-    {
-      label: "宸ュ崟缂栧彿",
-      prop: "workOrderNo",
-      width: "140",
-    },
-    {
-      label: "鐢熶骇璁㈠崟鍙�",
-      prop: "productOrderNpsNo",
-      width: "140",
-    },
-    {
-      label: "浜у搧鍚嶇О",
-      prop: "productName",
-      width: "140",
-    },
-    {
-      label: "瑙勬牸",
-      prop: "model",
-    },
-    {
-      label: "鍗曚綅",
-      prop: "unit",
-    },
-    {
-      label: "宸ュ簭鍚嶇О",
-      prop: "processName",
-    },
-    {
-      label: "闇�姹傛暟閲�",
-      prop: "planQuantity",
-      width: "140",
-    },
-    {
-      label: "瀹屾垚鏁伴噺",
-      prop: "completeQuantity",
-      width: "140",
-    },
-    {
-      label: "瀹屾垚杩涘害",
-      prop: "completionStatus",
-      dataType: "slot",
-      slot: "completionStatus",
-      width: "140",
-    },
-    {
-      label: "璁″垝寮�濮嬫椂闂�",
-      prop: "planStartTime",
-      width: "140",
-    },
-    {
-      label: "璁″垝缁撴潫鏃堕棿",
-      prop: "planEndTime",
-      width: "140",
-    },
-    {
-      label: "瀹為檯寮�濮嬫椂闂�",
-      prop: "actualStartTime",
-      width: "140",
-    },
-    {
-      label: "瀹為檯缁撴潫鏃堕棿",
-      prop: "actualEndTime",
-      width: "140",
-    },
-    {
-      label: "鎿嶄綔",
-      width: "100",
-      align: "center",
-      dataType: "action",
-      fixed: "right",
-      operation: [
-        {
-          name: "璁″垝鏃堕棿",
-          clickFun: row => {
-            handleEdit(row);
-          },
+const { proxy } = getCurrentInstance();
+
+const tableColumn = ref([
+  {
+    label: "宸ュ崟绫诲瀷",
+    prop: "workOrderType",
+    width: "80",
+  },
+  {
+    label: "宸ュ崟缂栧彿",
+    prop: "workOrderNo",
+    width: "140",
+  },
+  {
+    label: "鐢熶骇璁㈠崟鍙�",
+    prop: "productOrderNpsNo",
+    width: "140",
+  },
+  {
+    label: "浜у搧鍚嶇О",
+    prop: "productName",
+    width: "140",
+  },
+  {
+    label: "瑙勬牸",
+    prop: "model",
+  },
+  {
+    label: "鍗曚綅",
+    prop: "unit",
+  },
+  {
+    label: "宸ュ簭鍚嶇О",
+    prop: "processName",
+  },
+  {
+    label: "闇�姹傛暟閲�",
+    prop: "planQuantity",
+    width: "140",
+  },
+  {
+    label: "瀹屾垚鏁伴噺",
+    prop: "completeQuantity",
+    width: "140",
+  },
+  {
+    label: "瀹屾垚杩涘害",
+    prop: "completionStatus",
+    dataType: "slot",
+    slot: "completionStatus",
+    width: "140",
+  },
+  {
+    label: "璁″垝寮�濮嬫椂闂�",
+    prop: "planStartTime",
+    width: "140",
+  },
+  {
+    label: "璁″垝缁撴潫鏃堕棿",
+    prop: "planEndTime",
+    width: "140",
+  },
+  {
+    label: "瀹為檯寮�濮嬫椂闂�",
+    prop: "actualStartTime",
+    width: "140",
+  },
+  {
+    label: "瀹為檯缁撴潫鏃堕棿",
+    prop: "actualEndTime",
+    width: "140",
+  },
+  {
+    label: "鎿嶄綔",
+    width: "100",
+    align: "center",
+    dataType: "action",
+    fixed: "right",
+    operation: [
+      {
+        name: "璁″垝鏃堕棿",
+        clickFun: row => {
+          handleEdit(row);
         },
-      ],
-    },
-  ]);
-  
-  const tableData = ref([]);
-  const tableLoading = ref(false);
-  const editDialogVisible = ref(false);
-  let editrow = ref(null);
-  const page = reactive({
-    current: 1,
-    size: 100,
-    total: 0,
-  });
+      },
+    ],
+  },
+]);
 
-  const data = reactive({
-    searchForm: {
-      workOrderNo: "",
-    },
-  });
-  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";
-  };
+const tableData = ref([]);
+const tableLoading = ref(false);
+const editDialogVisible = ref(false);
+const editrow = ref(null);
+const page = reactive({
+  current: 1,
+  size: 100,
+  total: 0,
+});
 
-  // 鏌ヨ鍒楄〃
-  /** 鎼滅储鎸夐挳鎿嶄綔 */
-  const handleQuery = () => {
-    page.current = 1;
-    getList();
-  };
-  const pagination = obj => {
-    page.current = obj.page;
-    page.size = obj.limit;
-    getList();
-  };
-  const getList = () => {
-    tableLoading.value = true;
-    const params = { ...searchForm.value, ...page };
-    productWorkOrderPage(params)
-      .then(res => {
-        tableLoading.value = false;
-        tableData.value = res.data.records;
-        page.total = res.data.total;
-      })
-      .catch(() => {
-        tableLoading.value = false;
+const data = reactive({
+  searchForm: {
+    workOrderNo: "",
+    productOrderNpsNo: "",
+  },
+});
+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";
+};
+
+const handleQuery = () => {
+  page.current = 1;
+  getList();
+};
+
+const pagination = obj => {
+  page.current = obj.page;
+  page.size = obj.limit;
+  getList();
+};
+
+const getList = () => {
+  tableLoading.value = true;
+  const params = { ...searchForm.value, ...page };
+  productWorkOrderPage(params)
+    .then(res => {
+      tableLoading.value = false;
+      tableData.value = res.data.records;
+      page.total = res.data.total;
+    })
+    .catch(() => {
+      tableLoading.value = false;
+    });
+};
+
+const handleEdit = row => {
+  editrow.value = JSON.parse(JSON.stringify(row));
+  editDialogVisible.value = true;
+};
+
+const handleUpdate = () => {
+  updateProductWorkOrder(editrow.value)
+    .then(() => {
+      proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+      editDialogVisible.value = false;
+      getList();
+    })
+    .catch(() => {
+      ElMessageBox.alert("淇敼澶辫触", "鎻愮ず", {
+        confirmButtonText: "纭畾",
       });
-  };
+    });
+};
 
-  const handleEdit = row => {
-    editrow.value = JSON.parse(JSON.stringify(row));
-    editDialogVisible.value = true;
-  };
-
-  const handleUpdate = () => {
-    updateProductWorkOrder(editrow.value)
-      .then(res => {
-        proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
-        editDialogVisible.value = false;
-        getList();
-      })
-      .catch(() => {
-        ElMessageBox.alert("淇敼澶辫触", "鎻愮ず", {
-          confirmButtonText: "纭畾",
-        });
-      });
-  };
-
-  onMounted(() => {
-    getList();
-  });
+onMounted(() => {
+  getList();
+});
 </script>
 
 <style scoped lang="scss">
-  .search-row {
-    display: flex;
-    align-items: center;
-    gap: 12px;
-  }
-  .search-item {
-    display: flex;
-    align-items: center;
-  }
-  .search_title {
-    margin-right: 8px;
-    font-size: 14px;
-    color: #606266;
-  }
-</style>
\ No newline at end of file
+.search-row {
+  display: flex;
+  align-items: center;
+  gap: 12px;
+}
+
+.search-item {
+  display: flex;
+  align-items: center;
+}
+
+.search_title {
+  margin-right: 8px;
+  font-size: 14px;
+  color: #606266;
+}
+</style>
diff --git a/src/views/productionManagement/workOrderManagement/components/MaterialDialog.vue b/src/views/productionManagement/workOrderManagement/components/MaterialDialog.vue
new file mode 100644
index 0000000..575d888
--- /dev/null
+++ b/src/views/productionManagement/workOrderManagement/components/MaterialDialog.vue
@@ -0,0 +1,278 @@
+<template>
+  <div>
+    <el-dialog
+      v-model="dialogVisible"
+      title="鐗╂枡"
+      width="1200px"
+      @close="handleCloseMaterialDialog"
+    >
+      <el-table v-loading="materialTableLoading" :data="materialTableData" border row-key="id">
+        <el-table-column label="宸ュ簭鍚嶇О" prop="processName" min-width="140" />
+        <el-table-column label="鍘熸枡鍚嶇О" prop="materialName" min-width="140" />
+        <el-table-column label="鍘熸枡鍨嬪彿" prop="materialModel" min-width="140" />
+        <el-table-column label="璁¢噺鍗曚綅" prop="unit" min-width="100" />
+        <el-table-column label="绾胯竟浠撴暟閲�" prop="pickQty" min-width="100" />
+        <el-table-column label="琛ユ枡鏁伴噺" prop="supplementQty" min-width="100" />
+        <el-table-column label="瀹為檯鏁伴噺" min-width="140">
+          <template #default="{ row }">
+            <el-input-number
+              v-model="row.actualQty"
+              :min="0"
+              :precision="3"
+              :step="1"
+              controls-position="right"
+              style="width: 100%;"
+            />
+          </template>
+        </el-table-column>
+        <el-table-column label="鎿嶄綔" align="center" fixed="right" width="180">
+          <template #default="{ row }">
+            <el-button type="primary" link @click="openSupplementDialog(row)">琛ユ枡</el-button>
+            <el-button type="info" link @click="openSupplementRecordDialog(row)">琛ユ枡璁板綍</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button type="primary" :loading="pickSubmitting" @click="handleSubmitPick">棰嗙敤</el-button>
+          <el-button @click="dialogVisible = false">鍙栨秷</el-button>
+        </span>
+      </template>
+    </el-dialog>
+
+    <FormDialog
+      v-model="supplementDialogVisible"
+      title="琛ユ枡"
+      width="500px"
+      @confirm="handleSubmitSupplement"
+    >
+      <el-form ref="supplementFormRef" :model="supplementForm" :rules="supplementRules" label-width="100px">
+        <el-form-item label="琛ユ枡鏁伴噺" prop="supplementQty">
+          <el-input-number
+            v-model="supplementForm.supplementQty"
+            :min="0.001"
+            :precision="3"
+            :step="1"
+            style="width: 100%;"
+          />
+        </el-form-item>
+        <el-form-item label="琛ユ枡鍘熷洜" prop="supplementReason">
+          <el-input
+            v-model="supplementForm.supplementReason"
+            type="textarea"
+            :rows="3"
+            maxlength="200"
+            show-word-limit
+            placeholder="璇疯緭鍏ヨˉ鏂欏師鍥�"
+          />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button type="primary" :loading="supplementSubmitting" @click="handleSubmitSupplement">纭畾</el-button>
+          <el-button @click="supplementDialogVisible = false">鍙栨秷</el-button>
+        </span>
+      </template>
+    </FormDialog>
+
+    <el-dialog v-model="supplementRecordDialogVisible" title="琛ユ枡璁板綍" width="900px">
+      <el-table v-loading="supplementRecordLoading" :data="supplementRecordTableData" border row-key="id">
+        <el-table-column label="琛ユ枡鏁伴噺" prop="supplementQty" min-width="100" />
+        <el-table-column label="琛ユ枡鍘熷洜" prop="supplementReason" min-width="200" />
+        <el-table-column label="琛ユ枡浜�" prop="supplementUserName" min-width="120" />
+        <el-table-column label="琛ユ枡鏃ユ湡" prop="supplementTime" min-width="160" />
+      </el-table>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button @click="supplementRecordDialogVisible = false">鍏抽棴</el-button>
+        </span>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import { computed, nextTick, reactive, ref, watch } from "vue";
+import { ElMessage } from "element-plus";
+import FormDialog from "@/components/Dialog/FormDialog.vue";
+import {
+  listWorkOrderMaterialLedger,
+  addWorkOrderMaterialSupplement,
+  listWorkOrderMaterialSupplementRecord,
+  pickWorkOrderMaterial,
+} from "@/api/productionManagement/workOrder.js";
+
+const props = defineProps({
+  modelValue: {
+    type: Boolean,
+    default: false,
+  },
+  rowData: {
+    type: Object,
+    default: () => null,
+  },
+});
+
+const emit = defineEmits(["update:modelValue", "refresh"]);
+
+const dialogVisible = computed({
+  get: () => props.modelValue,
+  set: val => emit("update:modelValue", val),
+});
+
+const materialTableLoading = ref(false);
+const materialTableData = ref([]);
+const currentMaterialRow = ref(null);
+const currentMaterialOrderRow = ref(null);
+const pickSubmitting = ref(false);
+
+const supplementDialogVisible = ref(false);
+const supplementSubmitting = ref(false);
+const supplementFormRef = ref(null);
+const supplementForm = reactive({
+  supplementQty: null,
+  supplementReason: "",
+});
+
+const supplementRecordDialogVisible = ref(false);
+const supplementRecordLoading = ref(false);
+const supplementRecordTableData = ref([]);
+
+const supplementRules = {
+  supplementQty: [{ required: true, message: "璇疯緭鍏ヨˉ鏂欐暟閲�", trigger: "blur" }],
+  supplementReason: [{ required: true, message: "璇疯緭鍏ヨˉ鏂欏師鍥�", trigger: "blur" }],
+};
+const loadMaterialTable = async row => {
+  if (!row?.id) return;
+  currentMaterialOrderRow.value = row;
+  materialTableLoading.value = true;
+  materialTableData.value = [];
+  try {
+    const res = await listWorkOrderMaterialLedger({
+      workOrderId: row.id,
+      processId: row.processId,
+      productProcessRouteItemId: row.productProcessRouteItemId,
+    });
+    materialTableData.value = res.data || [];
+  } catch (e) {
+    console.error("鑾峰彇鐗╂枡鍙拌处澶辫触", e);
+    ElMessage.error("鑾峰彇鐗╂枡鍙拌处澶辫触");
+  } finally {
+    materialTableLoading.value = false;
+  }
+};
+
+watch(
+  () => props.modelValue,
+  visible => {
+    if (visible && props.rowData) {
+      loadMaterialTable(props.rowData);
+    }
+  }
+);
+
+const handleCloseMaterialDialog = () => {
+  materialTableData.value = [];
+  currentMaterialRow.value = null;
+  currentMaterialOrderRow.value = null;
+};
+
+const openSupplementDialog = row => {
+  currentMaterialRow.value = row;
+  supplementForm.supplementQty = null;
+  supplementForm.supplementReason = "";
+  supplementDialogVisible.value = true;
+  nextTick(() => {
+    supplementFormRef.value?.clearValidate();
+  });
+};
+
+const handleSubmitSupplement = () => {
+  supplementFormRef.value?.validate(async valid => {
+    if (!valid || !currentMaterialRow.value?.id) {
+      ElMessage.warning("缂哄皯鐗╂枡鏄庣粏ID");
+      return;
+    }
+    supplementSubmitting.value = true;
+    try {
+      await addWorkOrderMaterialSupplement({
+        materialLedgerId: currentMaterialRow.value.id,
+        supplementQty: Number(supplementForm.supplementQty),
+        supplementReason: supplementForm.supplementReason,
+        workOrderId: currentMaterialOrderRow.value?.id,
+      });
+      supplementDialogVisible.value = false;
+      await loadMaterialTable(currentMaterialOrderRow.value);
+      ElMessage.success("琛ユ枡鎴愬姛");
+      emit("refresh");
+    } catch (e) {
+      console.error("琛ユ枡澶辫触", e);
+      ElMessage.error("琛ユ枡澶辫触");
+    } finally {
+      supplementSubmitting.value = false;
+    }
+  });
+};
+
+const openSupplementRecordDialog = async row => {
+  supplementRecordDialogVisible.value = true;
+  supplementRecordLoading.value = true;
+  supplementRecordTableData.value = [];
+  try {
+    const res = await listWorkOrderMaterialSupplementRecord({
+      materialLedgerId: row.id,
+    });
+    supplementRecordTableData.value = res.data || [];
+  } catch (e) {
+    console.error("鑾峰彇琛ユ枡璁板綍澶辫触", e);
+    ElMessage.error("鑾峰彇琛ユ枡璁板綍澶辫触");
+  } finally {
+    supplementRecordLoading.value = false;
+  }
+};
+
+const validatePickRows = () => {
+  if (materialTableData.value.length === 0) {
+    return { valid: false, message: "鏆傛棤鍙鐢ㄧ墿鏂�" };
+  }
+  const invalidRow = materialTableData.value.find(item => item.actualQty === null || item.actualQty === undefined || item.actualQty === "");
+  if (invalidRow) {
+    return { valid: false, message: "璇峰~鍐欏疄闄呮暟閲忓悗鍐嶉鐢�" };
+  }
+  const exceedRow = materialTableData.value.find(item => {
+    const maxQty = Number(item.pickQty || 0) + Number(item.supplementQty || 0);
+    return Number(item.actualQty || 0) > maxQty;
+  });
+  if (exceedRow) {
+    return { valid: false, message: "瀹為檯鏁伴噺涓嶈兘澶т簬棰嗙敤鏁伴噺+琛ユ枡鏁伴噺" };
+  }
+  return { valid: true, message: "" };
+};
+
+const handleSubmitPick = async () => {
+  if (!currentMaterialOrderRow.value?.id) return;
+  const validateResult = validatePickRows();
+  if (!validateResult.valid) {
+    ElMessage.warning(validateResult.message);
+    return;
+  }
+  pickSubmitting.value = true;
+  try {
+    await pickWorkOrderMaterial({
+      workOrderId: currentMaterialOrderRow.value.id,
+      items: materialTableData.value.map(item => ({
+        materialLedgerId: item.id,
+        actualQty: Number(item.actualQty || 0),
+      })),
+    });
+    ElMessage.success("棰嗙敤鎴愬姛");
+    await loadMaterialTable(currentMaterialOrderRow.value);
+    emit("refresh");
+  } catch (e) {
+    console.error("棰嗙敤澶辫触", e);
+    ElMessage.error("棰嗙敤澶辫触");
+  } finally {
+    pickSubmitting.value = false;
+  }
+};
+</script>
diff --git a/src/views/productionManagement/workOrderManagement/index.vue b/src/views/productionManagement/workOrderManagement/index.vue
index 6def04c..48f8839 100644
--- a/src/views/productionManagement/workOrderManagement/index.vue
+++ b/src/views/productionManagement/workOrderManagement/index.vue
@@ -12,6 +12,15 @@
                     prefix-icon="Search" />
         </div>
         <div class="search-item">
+          <span class="search_title">鐢熶骇璁㈠崟鍙凤細</span>
+          <el-input v-model="searchForm.productOrderNpsNo"
+                    style="width: 240px"
+                    placeholder="璇疯緭鍏�"
+                    @change="handleQuery"
+                    clearable
+                    prefix-icon="Search" />
+        </div>
+        <div class="search-item">
           <el-button type="primary"
                      @click="handleQuery">鎼滅储</el-button>
         </div>
@@ -163,6 +172,12 @@
         </span>
       </template>
     </el-dialog>
+
+    <MaterialDialog
+      v-model="materialDialogVisible"
+      :row-data="currentMaterialOrderRow"
+      @refresh="getList"
+    />
     
     <FilesDia ref="workOrderFilesRef" />
   </div>
@@ -181,6 +196,7 @@
   import QRCode from "qrcode";
   import { getCurrentInstance, reactive, toRefs } from "vue";
   import FilesDia from "./components/filesDia.vue";
+  import MaterialDialog from "./components/MaterialDialog.vue";
   const { proxy } = getCurrentInstance();
 
   const tableColumn = ref([
@@ -255,7 +271,7 @@
     },
     {
       label: "鎿嶄綔",
-      width: "200",
+      width: "260",
       align: "center",
       dataType: "action",
       fixed: "right",
@@ -270,6 +286,12 @@
           name: "闄勪欢",
           clickFun: row => {
             openWorkOrderFiles(row);
+          },
+        },
+        {
+          name: "鐗╂枡",
+          clickFun: row => {
+            openMaterialDialog(row);
           },
         },
         {
@@ -396,6 +418,8 @@
   };
   
   const currentReportRowData = ref(null);
+  const materialDialogVisible = ref(false);
+  const currentMaterialOrderRow = ref(null);
   const page = reactive({
     current: 1,
     size: 100,
@@ -405,6 +429,7 @@
   const data = reactive({
     searchForm: {
       workOrderNo: "",
+      productOrderNpsNo: "",
     },
   });
   const { searchForm } = toRefs(data);
@@ -545,6 +570,11 @@
       });
 
     reportDialogVisible.value = true;
+  };
+
+  const openMaterialDialog = row => {
+    currentMaterialOrderRow.value = row;
+    materialDialogVisible.value = true;
   };
 
   const handleReport = () => {
@@ -786,4 +816,4 @@
       height: 140px !important;
     }
   }
-</style>
\ No newline at end of file
+</style>
diff --git a/src/views/qualityManagement/finalInspection/index.vue b/src/views/qualityManagement/finalInspection/index.vue
index db44222..eaed2e9 100644
--- a/src/views/qualityManagement/finalInspection/index.vue
+++ b/src/views/qualityManagement/finalInspection/index.vue
@@ -11,11 +11,12 @@
             clearable
             :prefix-icon="Search"
         />
-        <span  style="margin-left: 10px" class="search_title">妫�娴嬫棩鏈燂細</span>
-        <el-date-picker  v-model="searchForm.entryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="daterange"
-                         placeholder="璇烽�夋嫨" clearable @change="changeDaterange" />
+        <span style="margin-left: 10px" class="search_title">妫�娴嬫棩鏈燂細</span>
+        <el-date-picker v-model="searchForm.entryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="daterange"
+                        placeholder="璇烽�夋嫨" clearable @change="changeDaterange"/>
         <el-button type="primary" @click="handleQuery" style="margin-left: 10px"
-        >鎼滅储</el-button
+        >鎼滅储
+        </el-button
         >
       </div>
       <div>
@@ -40,37 +41,37 @@
     <InspectionFormDia ref="inspectionFormDia" @close="handleQuery"></InspectionFormDia>
     <FormDia ref="formDia" @close="handleQuery"></FormDia>
     <files-dia ref="filesDia" @close="handleQuery"></files-dia>
-		<el-dialog v-model="dialogFormVisible" title="缂栬緫妫�楠屽憳" width="30%"
-							 @close="closeDia">
-			<el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef">
-				<el-form-item label="妫�楠屽憳锛�" prop="checkName">
-					<el-select v-model="form.checkName" placeholder="璇烽�夋嫨" clearable>
-						<el-option v-for="item in userList" :key="item.nickName" :label="item.nickName"
-											 :value="item.nickName"/>
-					</el-select>
-				</el-form-item>
-			</el-form>
-			<template #footer>
-				<div class="dialog-footer">
-					<el-button type="primary" @click="submitForm">纭</el-button>
-					<el-button @click="closeDia">鍙栨秷</el-button>
-				</div>
-			</template>
-		</el-dialog>
+    <el-dialog v-model="dialogFormVisible" title="缂栬緫妫�楠屽憳" width="30%"
+               @close="closeDia">
+      <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef">
+        <el-form-item label="妫�楠屽憳锛�" prop="checkName">
+          <el-select v-model="form.checkName" placeholder="璇烽�夋嫨" clearable>
+            <el-option v-for="item in userList" :key="item.nickName" :label="item.nickName"
+                       :value="item.nickName"/>
+          </el-select>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitForm">纭</el-button>
+          <el-button @click="closeDia">鍙栨秷</el-button>
+        </div>
+      </template>
+    </el-dialog>
   </div>
 </template>
 
 <script setup>
-import { Search } from "@element-plus/icons-vue";
+import {Search} from "@element-plus/icons-vue";
 import {onMounted, ref, reactive, toRefs, getCurrentInstance, nextTick} from "vue";
 import InspectionFormDia from "@/views/qualityManagement/finalInspection/components/inspectionFormDia.vue";
 import FormDia from "@/views/qualityManagement/finalInspection/components/formDia.vue";
 import {ElMessageBox} from "element-plus";
 import {
-	downloadQualityInspect,
-	qualityInspectDel,
-	qualityInspectListPage, qualityInspectUpdate,
-	submitQualityInspect
+  downloadQualityInspect,
+  qualityInspectDel,
+  qualityInspectListPage, qualityInspectUpdate,
+  submitQualityInspect
 } from "@/api/qualityManagement/rawMaterialInspection.js";
 import FilesDia from "@/views/qualityManagement/finalInspection/components/filesDia.vue";
 import dayjs from "dayjs";
@@ -84,15 +85,20 @@
     entryDateStart: undefined,
     entryDateEnd: undefined,
   },
-	rules: {
-		checkName: [{required: true, message: "璇烽�夋嫨", trigger: "change"}],
-	},
+  rules: {
+    checkName: [{required: true, message: "璇烽�夋嫨", trigger: "change"}],
+  },
 });
-const { searchForm } = toRefs(data);
+const {searchForm} = toRefs(data);
 const tableColumn = ref([
   {
     label: "妫�娴嬫棩鏈�",
     prop: "checkTime",
+    width: 120
+  },
+  {
+    label: "閿�鍞崟鍙�",
+    prop: "salesContractNo",
     width: 120
   },
   {
@@ -140,17 +146,17 @@
       }
     },
   },
-	{
-		label: "鎻愪氦鐘舵��",
-		prop: "inspectState",
-		formatData: (params) => {
-			if (params) {
-				return "宸叉彁浜�";
-			} else {
-				return "鏈彁浜�";
-			}
-		},
-	},
+  {
+    label: "鎻愪氦鐘舵��",
+    prop: "inspectState",
+    formatData: (params) => {
+      if (params) {
+        return "宸叉彁浜�";
+      } else {
+        return "鏈彁浜�";
+      }
+    },
+  },
   {
     dataType: "action",
     label: "鎿嶄綔",
@@ -164,15 +170,15 @@
         clickFun: (row) => {
           openForm("edit", row);
         },
-				disabled: (row) => {
-					// 宸叉彁浜ゅ垯绂佺敤
-					if (row.inspectState == 1) return true;
-					// 濡傛灉妫�楠屽憳鏈夊�硷紝鍙湁褰撳墠鐧诲綍鐢ㄦ埛鑳界紪杈�
-					if (row.checkName) {
-						return row.checkName !== userStore.nickName;
-					}
-					return false;
-				}
+        disabled: (row) => {
+          // 宸叉彁浜ゅ垯绂佺敤
+          if (row.inspectState == 1) return true;
+          // 濡傛灉妫�楠屽憳鏈夊�硷紝鍙湁褰撳墠鐧诲綍鐢ㄦ埛鑳界紪杈�
+          if (row.checkName) {
+            return row.checkName !== userStore.nickName;
+          }
+          return false;
+        }
       },
       {
         name: "闄勪欢",
@@ -181,43 +187,43 @@
           openFilesFormDia(row);
         },
       },
-			{
-				name: "鎻愪氦",
-				type: "text",
-				clickFun: (row) => {
-					submit(row.id);
-				},
-				disabled: (row) => {
-					// 宸叉彁浜ゅ垯绂佺敤
-					if (row.inspectState == 1) return true;
-					// 濡傛灉妫�楠屽憳鏈夊�硷紝鍙湁褰撳墠鐧诲綍鐢ㄦ埛鑳芥彁浜�
-					if (row.checkName) {
-						return row.checkName !== userStore.nickName;
-					}
-					return false;
-				}
-			},
-			{
-				name: "鍒嗛厤妫�楠屽憳",
-				type: "text",
-				clickFun: (row) => {
-					if (!row.checkName) {
-						open(row)
-					} else {
-						proxy.$modal.msgError("妫�楠屽憳宸插瓨鍦�");
-					}
-				},
-				disabled: (row) => {
-					return row.inspectState == 1 || row.checkName;
-				}
-			},
-			{
-				name: "涓嬭浇",
-				type: "text",
-				clickFun: (row) => {
-					downLoadFile(row);
-				},
-			},
+      {
+        name: "鎻愪氦",
+        type: "text",
+        clickFun: (row) => {
+          submit(row.id);
+        },
+        disabled: (row) => {
+          // 宸叉彁浜ゅ垯绂佺敤
+          if (row.inspectState == 1) return true;
+          // 濡傛灉妫�楠屽憳鏈夊�硷紝鍙湁褰撳墠鐧诲綍鐢ㄦ埛鑳芥彁浜�
+          if (row.checkName) {
+            return row.checkName !== userStore.nickName;
+          }
+          return false;
+        }
+      },
+      {
+        name: "鍒嗛厤妫�楠屽憳",
+        type: "text",
+        clickFun: (row) => {
+          if (!row.checkName) {
+            open(row)
+          } else {
+            proxy.$modal.msgError("妫�楠屽憳宸插瓨鍦�");
+          }
+        },
+        disabled: (row) => {
+          return row.inspectState == 1 || row.checkName;
+        }
+      },
+      {
+        name: "涓嬭浇",
+        type: "text",
+        clickFun: (row) => {
+          downLoadFile(row);
+        },
+      },
     ],
   },
 ]);
@@ -233,11 +239,11 @@
 const formDia = ref()
 const filesDia = ref()
 const inspectionFormDia = ref()
-const { proxy } = getCurrentInstance()
+const {proxy} = getCurrentInstance()
 const userStore = useUserStore()
 const userList = ref([]);
 const form = ref({
-	checkName: ""
+  checkName: ""
 });
 const dialogFormVisible = ref(false);
 
@@ -263,7 +269,7 @@
 };
 const getList = () => {
   tableLoading.value = true;
-  const params = { ...searchForm.value, ...page };
+  const params = {...searchForm.value, ...page};
   params.entryDate = undefined
   qualityInspectListPage({...params, inspectType: 2}).then(res => {
     tableLoading.value = false;
@@ -338,56 +344,56 @@
 
 // 鎻愪环
 const submit = async (id) => {
-	const res = await submitQualityInspect({id: id})
-	if (res.code === 200) {
-		proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
-		getList();
-	}
+  const res = await submitQualityInspect({id: id})
+  if (res.code === 200) {
+    proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+    getList();
+  }
 }
 
 // 鍏抽棴寮规
 const closeDia = () => {
-	proxy.resetForm("formRef");
-	dialogFormVisible.value = false;
+  proxy.resetForm("formRef");
+  dialogFormVisible.value = false;
 };
 
 const submitForm = () => {
-	if (currentRow.value) {
-		const data = {
-			...form.value,
-			id: currentRow.value.id
-		}
-		qualityInspectUpdate(data).then(res => {
-			proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
-			closeDia();
-			getList();
-		})
-	}
+  if (currentRow.value) {
+    const data = {
+      ...form.value,
+      id: currentRow.value.id
+    }
+    qualityInspectUpdate(data).then(res => {
+      proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+      closeDia();
+      getList();
+    })
+  }
 };
 
 const open = async (row) => {
-	let userLists = await userListNoPage();
-	userList.value = userLists.data;
-	currentRow.value = row
-	dialogFormVisible.value = true
+  let userLists = await userListNoPage();
+  userList.value = userLists.data;
+  currentRow.value = row
+  dialogFormVisible.value = true
 }
 
 const downLoadFile = (row) => {
-	downloadQualityInspect({ id: row.id }).then((blobData) => {
-		const blob = new Blob([blobData], {
-			type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
-		})
-		const downloadUrl = window.URL.createObjectURL(blob)
-		
-		const link = document.createElement('a')
-		link.href = downloadUrl
-		link.download = '鍘熸潗鏂欐楠屾姤鍛�.docx'
-		document.body.appendChild(link)
-		link.click()
-		
-		document.body.removeChild(link)
-		window.URL.revokeObjectURL(downloadUrl)
-	})
+  downloadQualityInspect({id: row.id}).then((blobData) => {
+    const blob = new Blob([blobData], {
+      type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+    })
+    const downloadUrl = window.URL.createObjectURL(blob)
+
+    const link = document.createElement('a')
+    link.href = downloadUrl
+    link.download = '鍘熸潗鏂欐楠屾姤鍛�.docx'
+    document.body.appendChild(link)
+    link.click()
+
+    document.body.removeChild(link)
+    window.URL.revokeObjectURL(downloadUrl)
+  })
 };
 onMounted(() => {
   getList();
diff --git a/src/views/salesManagement/returnOrder/components/formDia.vue b/src/views/salesManagement/returnOrder/components/formDia.vue
index 9f1bb9a..27bbb0d 100644
--- a/src/views/salesManagement/returnOrder/components/formDia.vue
+++ b/src/views/salesManagement/returnOrder/components/formDia.vue
@@ -168,10 +168,10 @@
 <script setup>
 import { reactive, ref, toRefs, getCurrentInstance } from "vue";
 import { returnManagementAdd, returnManagementUpdate, returnManagementGetByShippingId, getSalesLedger, returnManagementGetById } from "@/api/salesManagement/returnOrder.js";
-import { getAllCustomerList } from "@/api/customerService/index.js";
 import useUserStore from "@/store/modules/user.js";
 import { userListNoPageByTenantId } from "@/api/system/user.js";
 import { listProject } from "@/api/oaSystem/projectManagement.js";
+import {listCustomerPrivatePool} from "@/api/basicData/customerFile.js";
 
 const { proxy } = getCurrentInstance();
 const emit = defineEmits(['close'])
@@ -354,15 +354,14 @@
 };
 
 const initCustomers = async () => {
-  const res = await getAllCustomerList({});
-  if (res?.records) {
-    customerNameOptions.value = res.records.map(item => ({
-      label: item.customerName,
-      value: item.customerName, // Keep value as name if needed for other logic, but request says customerId
-      id: item.id,
-      code: item.customerCode
-    }));
-  }
+	listCustomerPrivatePool({current: -1,size:-1}).then((res) => {
+		customerNameOptions.value = res.data.records.map(item => ({
+			label: item.customerName,
+			value: item.customerName, // Keep value as name if needed for other logic, but request says customerId
+			id: item.id,
+			code: item.customerCode
+		}));
+	});
 };
 
 const initUsers = async () => {
diff --git a/src/views/salesManagement/salesLedger/index.vue b/src/views/salesManagement/salesLedger/index.vue
index fa191a0..7c9ebf8 100644
--- a/src/views/salesManagement/salesLedger/index.vue
+++ b/src/views/salesManagement/salesLedger/index.vue
@@ -42,7 +42,7 @@
         <el-table-column align="center" type="selection" width="55" fixed="left"/>
         <el-table-column type="expand" width="60" fixed="left">
           <template #default="props">
-            <el-table :data="props.row.children" border show-summary :summary-method="summarizeChildrenTable">
+            <el-table :data="props.row.children" border show-summary :summary-method="(param) => summarizeChildrenTable(param, props.row)">
               <el-table-column align="center" label="搴忓彿" type="index"/>
               <el-table-column label="浜у搧澶х被" prop="productCategory" />
               <el-table-column label="瑙勬牸鍨嬪彿" prop="specificationModel" />
@@ -89,9 +89,9 @@
               </el-table-column>
               <el-table-column label="鏁伴噺" prop="quantity" />
               <el-table-column label="绋庣巼(%)" prop="taxRate" />
-              <el-table-column label="鍚◣鍗曚环(鍏�)" prop="taxInclusiveUnitPrice" :formatter="formattedNumber" />
-              <el-table-column label="鍚◣鎬讳环(鍏�)" prop="taxInclusiveTotalPrice" :formatter="formattedNumber" />
-              <el-table-column label="涓嶅惈绋庢�讳环(鍏�)" prop="taxExclusiveTotalPrice" :formatter="formattedNumber" />
+              <el-table-column label="鍚◣鍗曚环(鍏�)" prop="taxInclusiveUnitPrice" :formatter="sensitiveAmountFormatter" />
+              <el-table-column label="鍚◣鎬讳环(鍏�)" prop="taxInclusiveTotalPrice" :formatter="sensitiveAmountFormatter" />
+              <el-table-column label="涓嶅惈绋庢�讳环(鍏�)" prop="taxExclusiveTotalPrice" :formatter="sensitiveAmountFormatter" />
             <!--鎿嶄綔-->
               <el-table-column Width="60px" label="鎿嶄綔" align="center">
                 <template #default="scope">
@@ -122,7 +122,7 @@
         <el-table-column label="澶囨敞" prop="remarks" width="200" show-overflow-tooltip />
         <el-table-column fixed="right" label="鎿嶄綔" width="130" align="center">
           <template #default="scope">
-            <el-button link type="primary" @click="openForm('edit', scope.row)" :disabled="!scope.row.isEdit">缂栬緫</el-button>
+            <el-button link type="primary" @click="openForm('edit', scope.row)" :disabled="!scope.row.isEdit || scope.row.hasProductionRecord || !canEditLedger(scope.row)">缂栬緫</el-button>
             <el-button link type="primary" @click="downLoadFile(scope.row)">闄勪欢</el-button>
           </template>
         </el-table-column>
@@ -149,7 +149,7 @@
           </el-col>
           <el-col :span="12">
             <el-form-item label="涓氬姟鍛橈細" prop="salesman">
-              <el-select v-model="form.salesman" placeholder="璇烽�夋嫨" clearable :disabled="operationType === 'view'">
+              <el-select v-model="form.salesman" placeholder="璇烽�夋嫨" clearable :disabled="operationType === 'view'" filterable>
                 <el-option v-for="item in userList" :key="item.nickName" :label="item.nickName"
                   :value="item.nickName" />
               </el-select>
@@ -159,7 +159,7 @@
         <el-row :gutter="30">
           <el-col :span="12">
             <el-form-item label="瀹㈡埛鍚嶇О锛�" prop="customerId">
-              <el-select v-model="form.customerId" placeholder="璇烽�夋嫨" clearable :disabled="operationType === 'view'">
+              <el-select v-model="form.customerId" placeholder="璇烽�夋嫨" clearable :disabled="operationType === 'view'" filterable>
                 <el-option v-for="item in customerOption" :key="item.id" :label="item.customerName" :value="item.id">
                   {{
                     item.customerName + "鈥斺��" + item.taxpayerIdentificationNumber
@@ -343,11 +343,8 @@
 				<el-row :gutter="30">
 					<el-col :span="24">
 						<el-form-item label="浜у搧澶х被锛�" prop="productCategory">
-							<!-- <el-select v-model="productForm.productCategory" placeholder="璇烽�夋嫨" clearable>
-								<el-option v-for="item in userList" :key="item.nickName" :label="item.nickName" :value="item.nickName"/>
-							</el-select> -->
-							<el-tree-select v-model="productForm.productCategory" placeholder="璇烽�夋嫨" clearable check-strictly
-															@change="getModels" :data="productOptions" :render-after-expand="false" style="width: 100%" />
+							<el-tree-select v-model="productForm.productCategory" placeholder="璇烽�夋嫨" clearable filterable check-strictly
+							                @change="getModels" :data="productOptions" :render-after-expand="false" style="width: 100%" />
 						</el-form-item>
 					</el-col>
 				</el-row>
@@ -677,6 +674,7 @@
 import useFormData from "@/hooks/useFormData.js";
 import dayjs from "dayjs";
 import { getCurrentDate } from "@/utils/index.js";
+import {listCustomerPrivatePool} from "@/api/basicData/customerFile.js";
 
 const userStore = useUserStore();
 const { proxy } = getCurrentInstance();
@@ -717,6 +715,7 @@
 		maintenanceTime: "",
 		productData: [],
 		executionDate: "",
+    hasProductionRecord: false,
 	},
 	rules: {
 		salesman: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
@@ -925,7 +924,49 @@
 	});
 };
 const formattedNumber = (row, column, cellValue) => {
+	if (cellValue === undefined || cellValue === null || cellValue === "") {
+		return "0.00";
+	}
 	return parseFloat(cellValue).toFixed(2);
+};
+const findLedgerRecordByRow = (row) => {
+	if (!row) return null;
+	if (
+		row.maintainer !== undefined ||
+		row.maintainerName !== undefined ||
+		row.entryPerson !== undefined ||
+		row.entryPersonName !== undefined
+	) {
+		return row;
+	}
+	if (row.salesLedgerId !== undefined && row.salesLedgerId !== null) {
+		return tableData.value.find((item) => String(item.id) === String(row.salesLedgerId)) || null;
+	}
+	return null;
+};
+const isCurrentUserMaintainer = (row) => {
+	const ledgerRecord = findLedgerRecordByRow(row);
+	if (!ledgerRecord) return true;
+	const currentUserId = String(userStore.id ?? "");
+	const currentNickName = String(userStore.nickName ?? "").trim();
+	const maintainerId = ledgerRecord.maintainerId ?? ledgerRecord.entryPerson;
+	const maintainerName =
+		ledgerRecord.maintainerName ?? ledgerRecord.maintainer ?? ledgerRecord.entryPersonName;
+	if (maintainerId !== undefined && maintainerId !== null && String(maintainerId) !== "") {
+		return String(maintainerId) === currentUserId;
+	}
+	if (maintainerName !== undefined && maintainerName !== null && String(maintainerName).trim() !== "") {
+		return String(maintainerName).trim() === currentNickName;
+	}
+	return true;
+};
+const canEditLedger = (row) => isCurrentUserMaintainer(row);
+const canDeleteLedger = (row) => isCurrentUserMaintainer(row);
+const sensitiveAmountFormatter = (row, column, cellValue) => {
+	if (!isCurrentUserMaintainer(row)) {
+		return "*****";
+	}
+	return formattedNumber(row, column, cellValue);
 };
 // 鑾峰彇tree瀛愭暟鎹�
 const getModels = (value) => {
@@ -1040,7 +1081,19 @@
 	]);
 };
 // 瀛愯〃鍚堣鏂规硶
-const summarizeChildrenTable = (param) => {
+const summarizeChildrenTable = (param, parentRow) => {
+	if (!isCurrentUserMaintainer(parentRow)) {
+		const { columns } = param;
+		return columns.map((column, index) => {
+			if (index === 0) {
+				return "鍚堣";
+			}
+			if (["taxInclusiveUnitPrice", "taxInclusiveTotalPrice", "taxExclusiveTotalPrice"].includes(column.property)) {
+				return "*****";
+			}
+			return "";
+		});
+	}
 	return proxy.summarizeTable(param, [
 		"taxInclusiveUnitPrice",
 		"taxInclusiveTotalPrice",
@@ -1049,14 +1102,18 @@
 };
 // 鎵撳紑寮规
 const openForm = async (type, row) => {
+	if (type === "edit" && row && !canEditLedger(row)) {
+		proxy.$modal.msgWarning("褰撳墠绯荤粺鐧诲綍浜轰笉鏄淮鎶や汉锛屼笉鑳界紪杈戞暟鎹�");
+		return;
+	}
 	operationType.value = type;
 	form.value = {};
 	productData.value = [];
 	selectedQuotation.value = null;
 	let userLists = await userListNoPage();
 	userList.value = userLists.data;
-	customerList().then((res) => {
-		customerOption.value = res;
+	listCustomerPrivatePool({current: -1,size:-1}).then((res) => {
+		customerOption.value = res.data.records;
 	});
 	form.value.entryPerson = userStore.id;
 	if (type === "add") {
@@ -1092,8 +1149,9 @@
 	// 鍏堢‘淇濆鎴峰垪琛ㄥ凡鍔犺浇锛屼究浜庡悗缁洖濉� customerId
 	if (!customerOption.value || customerOption.value.length === 0) {
 		try {
-			const res = await customerList();
-			customerOption.value = res;
+			listCustomerPrivatePool({current: -1,size:-1}).then((res) => {
+				customerOption.value = res.data.records;
+			});
 		} catch (e) {
 			// ignore锛屽厑璁哥敤鎴峰悗缁墜鍔ㄩ�夋嫨瀹㈡埛
 		}
@@ -1432,6 +1490,11 @@
 		proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
 		return;
 	}
+	const unauthorizedRows = selectedRows.value.filter((row) => !canDeleteLedger(row));
+	if (unauthorizedRows.length > 0) {
+		proxy.$modal.msgWarning("褰撳墠鐧诲綍鐢ㄦ埛涓嶆槸褰曞叆浜猴紝涓嶈兘鍒犻櫎璇ユ暟鎹�");
+		return;
+	}
 	const ids = selectedRows.value.map((item) => item.id);
 
 	// 妫�鏌ユ槸鍚︽湁宸茶繘琛屽彂璐ф垨鍙戣揣瀹屾垚鐨勯攢鍞鍗曪紝鑻ユ湁鍒欎笉鍏佽鍒犻櫎
diff --git a/src/views/salesManagement/salesQuotation/index.vue b/src/views/salesManagement/salesQuotation/index.vue
index 5574bce..01174d7 100644
--- a/src/views/salesManagement/salesQuotation/index.vue
+++ b/src/views/salesManagement/salesQuotation/index.vue
@@ -103,18 +103,14 @@
             <el-row :gutter="24">
               <el-col :span="12">
                 <el-form-item label="瀹㈡埛鍚嶇О" prop="customer">
-                  <el-select v-model="form.customer" placeholder="璇烽�夋嫨瀹㈡埛" style="width: 100%" @change="handleCustomerChange" clearable>
-                    <el-option v-for="item in customerOption" :key="item.id" :label="item.customerName" :value="item.customerName">
-                      {{
-                        item.customerName + "鈥斺��" + item.taxpayerIdentificationNumber
-                      }}
-                    </el-option>
+                  <el-select v-model="form.customer" placeholder="璇烽�夋嫨瀹㈡埛" style="width: 100%" clearable filterable>
+                    <el-option v-for="item in customerOption" :key="item.id" :label="item.customerName" :value="item.id"></el-option>
                   </el-select>
                 </el-form-item>
               </el-col>
               <el-col :span="12">
                 <el-form-item label="涓氬姟鍛�" prop="salesperson">
-                  <el-select v-model="form.salesperson" placeholder="璇烽�夋嫨涓氬姟鍛�" style="width: 100%" clearable>
+                  <el-select v-model="form.salesperson" placeholder="璇烽�夋嫨涓氬姟鍛�" style="width: 100%" clearable filterable>
                     <el-option v-for="item in userList" :key="item.nickName" :label="item.nickName"
                       :value="item.nickName" />
                   </el-select>
@@ -190,6 +186,7 @@
                         v-model="node.userId"
                         placeholder="閫夋嫨浜哄憳"
                         class="approver-select"
+												filterable
                         clearable
                       >
                         <el-option
@@ -363,6 +360,7 @@
 import {userListNoPage} from "@/api/system/user.js";
 import {customerList} from "@/api/salesManagement/salesLedger.js";
 import {modelList, productTreeList} from "@/api/basicData/product.js";
+import {listCustomerPrivatePool} from "@/api/basicData/customerFile.js";
 
 // 鍝嶅簲寮忔暟鎹�
 const loading = ref(false)
@@ -492,13 +490,8 @@
     userName: item.userName || ''
   }));
 	getProductOptions();
-	customerList().then((res) => {
-		// 鍙鍒堕渶瑕佺殑瀛楁锛岄伩鍏嶅皢缁勪欢寮曠敤鏀惧叆鍝嶅簲寮忓璞�
-		customerOption.value = (Array.isArray(res) ? res : []).map(item => ({
-      id: item.id,
-      customerName: item.customerName || '',
-      taxpayerIdentificationNumber: item.taxpayerIdentificationNumber || ''
-    }))
+	listCustomerPrivatePool({current: -1,size:-1}).then((res) => {
+		customerOption.value = res.data.records;
 	});
 }
 const getProductOptions = () => {
@@ -783,10 +776,6 @@
   form.totalAmount = form.subtotal + form.freight + form.otherFee - form.discountAmount
 }
 
-const handleCustomerChange = () => {
-  // 鍙互鏍规嵁瀹㈡埛淇℃伅鑷姩濉厖涓�浜涢粯璁ゅ��
-}
-
 const handleSubmit = () => {
   formRef.value.validate((valid) => {
     if (valid) {
@@ -889,12 +878,7 @@
     }
   })
 	customerList().then((res) => {
-		// 鍙鍒堕渶瑕佺殑瀛楁锛岄伩鍏嶅皢缁勪欢寮曠敤鏀惧叆鍝嶅簲寮忓璞�
-		customerOption.value = (Array.isArray(res) ? res : []).map(item => ({
-      id: item.id,
-      customerName: item.customerName || '',
-      taxpayerIdentificationNumber: item.taxpayerIdentificationNumber || ''
-    }))
+		customerOption.value = res;
 	});
 }
 

--
Gitblit v1.9.3