From 23ad2619d81e9e45a7fb4715b4b850e94bd843e7 Mon Sep 17 00:00:00 2001
From: yuan <123@>
Date: 星期五, 24 四月 2026 15:29:25 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/dev_NEW_pro' into dev_NEW_pro

---
 src/views/index.vue                                                                |    2 
 src/views/salesManagement/deliveryLedger/index.vue                                 |  363 +++++++------------
 src/components/AttachmentUpload/image/index.vue                                    |    2 
 src/views/productionManagement/processRoute/processRouteItem/index.vue             |   74 ++-
 src/components/ProcessParamListDialog.vue                                          |    9 
 src/api/productionManagement/productionOrder.js                                    |    6 
 src/api/productionManagement/productProcessRoute.js                                |   20 
 src/views/equipmentManagement/inspectionManagement/components/viewFiles.vue        |   63 --
 src/views/productionManagement/productionOrder/components/MaterialLedgerDialog.vue |  517 ++++++++++++++------------
 src/api/productionManagement/processRouteItem.js                                   |    8 
 src/api/productionManagement/processRoute.js                                       |    4 
 src/main.js                                                                        |    6 
 src/views/productionManagement/productionOrder/index.vue                           |   20 
 src/views/productionPlan/productionPlan/index.vue                                  |   24 
 src/components/AttachmentPreview/image/index.vue                                   |    4 
 15 files changed, 526 insertions(+), 596 deletions(-)

diff --git a/src/api/productionManagement/processRoute.js b/src/api/productionManagement/processRoute.js
index c07c6d3..a0cb6c8 100644
--- a/src/api/productionManagement/processRoute.js
+++ b/src/api/productionManagement/processRoute.js
@@ -12,7 +12,7 @@
 
 export function add(data) {
   return request({
-    url: "/technologyRouting",
+    url: "/technologyRouting/addTechRoute",
     method: "post",
     data: data,
   });
@@ -34,7 +34,7 @@
 
 export function update(data) {
   return request({
-    url: "/technologyRouting",
+    url: "/technologyRouting/editTechRoute",
     method: "put",
     data: data,
   });
diff --git a/src/api/productionManagement/processRouteItem.js b/src/api/productionManagement/processRouteItem.js
index 4c4bf53..0a9dc66 100644
--- a/src/api/productionManagement/processRouteItem.js
+++ b/src/api/productionManagement/processRouteItem.js
@@ -82,3 +82,11 @@
     data: data,
   });
 }
+// 鎸夊伐鑹鸿矾绾垮伐搴忓悓姝ュ伐搴忓弬鏁�-鐢熶骇璁㈠崟
+export function syncProcessParamItemOrder(data) {
+  return request({
+    url: "/productionOrderRoutingOperationParam/sync",
+    method: "post",
+    data: data,
+  });
+}
diff --git a/src/api/productionManagement/productProcessRoute.js b/src/api/productionManagement/productProcessRoute.js
index 9d13c61..d75c239 100644
--- a/src/api/productionManagement/productProcessRoute.js
+++ b/src/api/productionManagement/productProcessRoute.js
@@ -4,7 +4,7 @@
 // 鍒楄〃鏌ヨ
 export function findProductProcessRouteItemList(query) {
   return request({
-    url: "/productProcessRoute/list",
+    url: "/productionOrderRouting/list",
     method: "get",
     params: query,
   });
@@ -12,7 +12,7 @@
 
 export function addOrUpdateProductProcessRouteItem(data) {
   return request({
-    url: "/productProcessRoute/updateRouteItem",
+    url: "/productionOrderRouting/updateRouteItem",
     method: "post",
     data: data,
   });
@@ -21,7 +21,7 @@
 // 鐢熶骇璁㈠崟涓嬶細鏂板宸ヨ壓璺嚎椤圭洰
 export function addRouteItem(data) {
   return request({
-    url: "/productProcessRoute/addRouteItem",
+    url: "/productionOrderRouting/addRouteItem",
     method: "post",
     data,
   });
@@ -30,7 +30,7 @@
 // 鑾峰彇鐢熶骇璁㈠崟鍏宠仈鐨勫伐鑹鸿矾绾夸富淇℃伅
 export function listMain(orderId) {
   return request({
-    url: "/productProcessRoute/listMain",
+    url: "/productionOrderRouting/listMain",
     method: "get",
     params: { orderId },
   });
@@ -39,7 +39,7 @@
 // 鍒犻櫎宸ヨ壓璺嚎椤圭洰锛堣矾鐢卞悗鎷兼帴 id锛�
 export function deleteRouteItem(id) {
   return request({
-    url: `/productProcessRoute/deleteRouteItem/${id}`,
+    url: `/productionOrderRouting/deleteRouteItem/${id}`,
     method: "delete",
   });
 }
@@ -47,7 +47,7 @@
 // 鐢熶骇璁㈠崟涓嬶細鎺掑簭宸ヨ壓璺嚎椤圭洰
 export function sortRouteItem(data) {
   return request({
-    url: "/productProcessRoute/sortRouteItem",
+    url: "/productionOrderRouting/sortRouteItem",
     method: "post",
     data,
   });
@@ -55,7 +55,7 @@
 // 鑾峰彇宸ュ簭鍙傛暟鍒楄〃-鐢熶骇璁㈠崟
 export function findProcessParamListOrder(query) {
   return request({
-    url: `/productionOrderRouteItemParam/list`,
+    url: `/productionOrderRoutingOperationParam/list`,
     method: "get",
     params: query,
   });
@@ -63,7 +63,7 @@
 // 宸ヨ壓璺嚎鍙傛暟鏂板-鐢熶骇璁㈠崟
 export function addProcessRouteItemParamOrder(data) {
   return request({
-    url: "/productionOrderRouteItemParam/add",
+    url: "/productionOrderRoutingOperationParam",
     method: "post",
     data: data,
   });
@@ -71,7 +71,7 @@
 // 宸ヨ壓璺嚎鍙傛暟淇敼-鐢熶骇璁㈠崟
 export function editProcessRouteItemParamOrder(data) {
   return request({
-    url: "/productionOrderRouteItemParam/update",
+    url: "/productionOrderRoutingOperationParam",
     method: "put",
     data: data,
   });
@@ -79,7 +79,7 @@
 // 宸ヨ壓璺嚎鍙傛暟鍒犻櫎-鐢熶骇璁㈠崟
 export function delProcessRouteItemParamOrder(id) {
   return request({
-    url: `/productionOrderRouteItemParam/delete/${id}`,
+    url: `/productionOrderRoutingOperationParam/${id}`,
     method: "delete",
   });
 }
diff --git a/src/api/productionManagement/productionOrder.js b/src/api/productionManagement/productionOrder.js
index ffcf936..e92dc83 100644
--- a/src/api/productionManagement/productionOrder.js
+++ b/src/api/productionManagement/productionOrder.js
@@ -30,7 +30,7 @@
 // 鐢熶骇璁㈠崟-缁戝畾宸ヨ壓璺嚎
 export function bindingRoute(data) {
   return request({
-    url: "/productOrder/bindingRoute",
+    url: "/productionOrder/bindingRoute",
     method: "post",
     data,
   });
@@ -39,7 +39,7 @@
 // 鐢熶骇璁㈠崟-鏂板
 export function addProductOrder(data) {
   return request({
-    url: "/productionOrder",
+    url: "/productionOrder/addOrder",
     method: "post",
     data: data,
   });
@@ -47,7 +47,7 @@
 
 export function delProductOrder(ids) {
   return request({
-    url: `/productOrder/${ids}`,
+    url: `/productionOrder/delete/${ids}`,
     method: "delete",
   });
 }
diff --git a/src/components/AttachmentPreview/image/index.vue b/src/components/AttachmentPreview/image/index.vue
index 5211fac..1c6039b 100644
--- a/src/components/AttachmentPreview/image/index.vue
+++ b/src/components/AttachmentPreview/image/index.vue
@@ -1,6 +1,6 @@
 <script setup>
 const props = defineProps({
-  list: {
+  fileList: {
     type: Array,
     default: () => [],
   },
@@ -15,7 +15,7 @@
 })
 
 const normalizedList = computed(() => {
-  return (props.list || [])
+  return (props.fileList || [])
     .filter((item) => item && item.previewURL)
     .map((item, index) => ({
       id: item.id ?? index,
diff --git a/src/components/AttachmentUpload/image/index.vue b/src/components/AttachmentUpload/image/index.vue
index 25bd13c..8243f9c 100644
--- a/src/components/AttachmentUpload/image/index.vue
+++ b/src/components/AttachmentUpload/image/index.vue
@@ -88,7 +88,7 @@
 })
 
 const uploadTip = computed(() => {
-  return `鏀寔 ${props.fileType.join('/')}锛屽崟寮犱笉瓒呰繃 ${props.fileSize}MB`
+  return `鏀寔 ${props.fileType.join('/')}锛屽崟寮犱笉瓒呰繃 ${props.fileSize}MB锛屾渶澶氫笂浼� ${props.limit} 寮犲浘鐗嘸
 })
 
 function getItemUid(item, index) {
diff --git a/src/components/ProcessParamListDialog.vue b/src/components/ProcessParamListDialog.vue
index dffb7b5..883a94f 100644
--- a/src/components/ProcessParamListDialog.vue
+++ b/src/components/ProcessParamListDialog.vue
@@ -374,10 +374,9 @@
     // 璋冪敤API鏂板鍙傛暟
     if (props.pageType === "order") {
       addProcessRouteItemParamOrder({
-        orderId: Number(props.orderId),
-        // processId: props.process.id,
-        routeItemId: props.process.id,
-        // routeItemId: Number(props.routeId),
+        productionOrderId: Number(props.orderId),
+        productionOrderRoutingOperationId: props.process.id,
+        technologyRoutingOperationParamId: props.process.id,
         paramId: selectedParam.value.id,
         standardValue: selectedParam.value.standardValue || "",
         isRequired: selectedParam.value.isRequired || 0,
@@ -428,8 +427,6 @@
         if (props.pageType === "order") {
           editProcessRouteItemParamOrder({
             id: editParamForm.value.id,
-            // routeItemId: props.process.id,
-            // paramId: editParamForm.value.paramId,
             standardValue: editParamForm.value.standardValue || "",
             isRequired: editParamForm.value.isRequired || 0,
           })
diff --git a/src/main.js b/src/main.js
index 0b3f714..b80c9b6 100644
--- a/src/main.js
+++ b/src/main.js
@@ -43,11 +43,11 @@
 // 瀵屾枃鏈粍浠�
 import Editor from "@/components/Editor";
 // 鏂囦欢涓婁紶缁勪欢
-import FileUpload from "@/components/FileUpload";
+import FileUpload from "@/components/AttachmentUpload/file";
 // 鍥剧墖涓婁紶缁勪欢
-import ImageUpload from "@/components/ImageUpload";
+import ImageUpload from "@/components/AttachmentUpload/image";
 // 鍥剧墖棰勮缁勪欢
-import ImagePreview from "@/components/ImagePreview";
+import ImagePreview from "@/components/AttachmentPreview/image";
 // 瀛楀吀鏍囩缁勪欢
 import DictTag from "@/components/DictTag";
 // 琛ㄦ牸缁勪欢
diff --git a/src/views/equipmentManagement/inspectionManagement/components/viewFiles.vue b/src/views/equipmentManagement/inspectionManagement/components/viewFiles.vue
index 27b4a59..66867e3 100644
--- a/src/views/equipmentManagement/inspectionManagement/components/viewFiles.vue
+++ b/src/views/equipmentManagement/inspectionManagement/components/viewFiles.vue
@@ -134,40 +134,6 @@
 const currentMediaIndex = ref(0);
 const mediaList = ref([]); // 瀛樺偍褰撳墠瑕佹煡鐪嬬殑濯掍綋鍒楄〃锛堝惈鍥剧墖鍜岃棰戝璞★級
 const mediaType = ref('image'); // image | video
-const javaApi = proxy.javaApi;
-
-// 澶勭悊 URL锛氬皢 Windows 璺緞杞崲涓哄彲璁块棶鐨� URL
-function processFileUrl(fileUrl) {
-  if (!fileUrl) return '';
-  
-  // 濡傛灉 URL 鏄� Windows 璺緞鏍煎紡锛堝寘鍚弽鏂滄潬锛夛紝闇�瑕佽浆鎹�
-  if (fileUrl && fileUrl.indexOf('\\') > -1) {
-    // 鏌ユ壘 uploads 鍏抽敭瀛楃殑浣嶇疆锛屼粠閭i噷寮�濮嬫彁鍙栫浉瀵硅矾寰�
-    const uploadsIndex = fileUrl.toLowerCase().indexOf('uploads');
-    if (uploadsIndex > -1) {
-      // 浠� uploads 寮�濮嬫彁鍙栬矾寰勶紝骞跺皢鍙嶆枩鏉犳浛鎹负姝f枩鏉�
-      const relativePath = fileUrl.substring(uploadsIndex).replace(/\\/g, '/');
-      fileUrl = '/' + relativePath;
-    } else {
-      // 濡傛灉娌℃湁鎵惧埌 uploads锛屾彁鍙栨渶鍚庝竴涓洰褰曞拰鏂囦欢鍚�
-      const parts = fileUrl.split('\\');
-      const fileName = parts[parts.length - 1];
-      fileUrl = '/uploads/' + fileName;
-    }
-  }
-  
-  // 纭繚鎵�鏈夐潪 http 寮�澶寸殑 URL 閮芥嫾鎺� baseUrl
-  if (fileUrl && !fileUrl.startsWith('http')) {
-    // 纭繚璺緞浠� / 寮�澶�
-    if (!fileUrl.startsWith('/')) {
-      fileUrl = '/' + fileUrl;
-    }
-    // 鎷兼帴 baseUrl
-    fileUrl = javaApi + fileUrl;
-  }
-  
-  return fileUrl;
-}
 
 // 澶勭悊姣忎竴绫绘暟鎹細鍒嗙鍥剧墖鍜岃棰�
 function processItems(items) {
@@ -180,24 +146,18 @@
   }
   
   items.forEach(item => {
-    if (!item || !item.url) return;
+    if (!item || !item.previewURL || !item.contentType) return;
+
     
     // 澶勭悊鏂囦欢 URL
-    const fileUrl = processFileUrl(item.url);
-    
-    // 鏍规嵁鏂囦欢鎵╁睍鍚嶅垽鏂槸鍥剧墖杩樻槸瑙嗛
-    const urlLower = fileUrl.toLowerCase();
-    if (urlLower.match(/\.(jpg|jpeg|png|gif|bmp|webp)$/)) {
+    const fileUrl = item.previewURL;
+    const contentType = String(item.contentType).toLowerCase();
+
+    // 鏍规嵁 contentType 鍒ゆ柇鏄浘鐗囪繕鏄棰�
+    if (contentType.startsWith('image/')) {
       images.push(fileUrl);
-    } else if (urlLower.match(/\.(mp4|avi|mov|wmv|flv|mkv|webm)$/)) {
+    } else if (contentType.startsWith('video/')) {
       videos.push(fileUrl);
-    } else if (item.contentType) {
-      // 濡傛灉鏈� contentType锛屼娇鐢� contentType 鍒ゆ柇
-      if (item.contentType.startsWith('image/')) {
-        images.push(fileUrl);
-      } else if (item.contentType.startsWith('video/')) {
-        videos.push(fileUrl);
-      }
     }
   });
   
@@ -207,10 +167,9 @@
 // 鎵撳紑寮圭獥骞跺姞杞芥暟鎹�
 const openDialog = async (row) => {
   // 浣跨敤姝g‘鐨勫瓧娈靛悕锛歝ommonFileListBefore, commonFileListAfter
-  // productionIssues 鍙兘涓嶅瓨鍦紝浣跨敤绌烘暟缁�
-  const { images: beforeImgs, videos: beforeVids } = processItems(row.commonFileListBefore || []);
-  const { images: afterImgs, videos: afterVids } = processItems(row.commonFileListAfter || []);
-  const { images: issueImgs, videos: issueVids } = processItems(row.productionIssues || []);
+  const { images: beforeImgs, videos: beforeVids } = processItems(row.commonFileListBeforeVO || []);
+  const { images: afterImgs, videos: afterVids } = processItems(row.commonFileListAfterVO || []);
+  const { images: issueImgs, videos: issueVids } = processItems(row.commonFileListVO || []);
   
   beforeProductionImgs.value = beforeImgs;
   beforeProductionVideos.value = beforeVids;
diff --git a/src/views/index.vue b/src/views/index.vue
index 838182b..00d4312 100644
--- a/src/views/index.vue
+++ b/src/views/index.vue
@@ -8,7 +8,7 @@
           <!-- 椤堕儴闂�欐潯 -->
           <div class="welcome-banner">
             <div class="welcome-title">
-              <span class="welcome-user">{{ userStore.roleName || '绯荤粺绠$悊鍛�' }}</span>
+              <span class="welcome-user">{{ userStore.nickName || '绯荤粺绠$悊鍛�' }}</span>
               <span> 鎮ㄥソ锛佺鎮ㄥ紑蹇冩瘡涓�澶�</span>
             </div>
             <div class="welcome-time">鐧诲綍浜�: {{ userStore.currentLoginTime }}</div>
diff --git a/src/views/productionManagement/processRoute/processRouteItem/index.vue b/src/views/productionManagement/processRoute/processRouteItem/index.vue
index 42fd4b2..b78caad 100644
--- a/src/views/productionManagement/processRoute/processRouteItem/index.vue
+++ b/src/views/productionManagement/processRoute/processRouteItem/index.vue
@@ -232,7 +232,7 @@
               style="width: 100%">
       <el-table-column type="expand">
         <template #default>
-          <el-form ref="form"
+          <el-form ref="bomFormRef"
                    :model="bomDataValue">
             <el-table :data="bomDataValue.dataList"
                       row-key="tempId"
@@ -356,7 +356,7 @@
                        prop="model" />
     </el-table>
     <ProductSelectDialog v-if="bomDataValue.showProductDialog"
-                         v-model:model-value="bomDataValue.showProductDialog"
+                         v-model="bomDataValue.showProductDialog"
                          :single="true"
                          @confirm="handleBomProduct" />
     <!-- 鏂板/缂栬緫寮圭獥 -->
@@ -385,8 +385,8 @@
                       prop="productModelId">
           <el-button type="primary"
                      @click="showProductSelectDialog = true">
-            {{ form.productName && form.model 
-              ? `${form.productName} - ${form.model}` 
+            {{ form.productName
+              ? (form.model ? `${form.productName} - ${form.model}` : form.productName)
               : '閫夋嫨浜у搧' }}
           </el-button>
         </el-form-item>
@@ -401,13 +401,13 @@
                       prop="isQuality">
           <el-switch v-model="form.isQuality"
                      :active-value="true"
-                     inactive-value="false" />
+                     :inactive-value="false" />
         </el-form-item>
         <el-form-item label="鏄惁鐢熶骇"
                       prop="isProduction">
           <el-switch v-model="form.isProduction"
                      :active-value="true"
-                     inactive-value="false" />
+                     :inactive-value="false" />
         </el-form-item>
       </el-form>
       <template #footer>
@@ -454,7 +454,10 @@
     batchDeleteProcessRouteItem,
     getProcessParamList,
   } from "@/api/productionManagement/processRouteItem.js";
-  import { syncProcessParamItem } from "@/api/productionManagement/processRouteItem.js";
+  import {
+    syncProcessParamItem,
+    syncProcessParamItemOrder,
+  } from "@/api/productionManagement/processRouteItem.js";
   import {
     findProductProcessRouteItemList,
     deleteRouteItem,
@@ -469,6 +472,7 @@
     queryList,
     addBomDetail,
   } from "@/api/productionManagement/productStructure.js";
+
   import { useRoute } from "vue-router";
   import { ElMessageBox, ElMessage } from "element-plus";
   import Sortable from "sortablejs";
@@ -485,6 +489,7 @@
   const dialogVisible = ref(false);
   const operationType = ref("add"); // add | edit
   const formRef = ref(null);
+  const bomFormRef = ref(null);
   const submitLoading = ref(false);
   const cardsContainer = ref(null);
   const tableRef = ref(null);
@@ -542,17 +547,31 @@
       type: "warning",
     })
       .then(() => {
-        syncProcessParamItem({
-          replaceExisting: true,
-          technologyRoutingOperationId: currentProcess.value.id,
-        }).then(res => {
-          if (res.code === 200) {
-            ElMessage.success("鍚屾鎴愬姛");
-            refreshParamList();
-          } else {
-            ElMessage.error(res.msg || "鍚屾澶辫触");
-          }
-        });
+        if (pageType.value === "order") {
+          syncProcessParamItemOrder({
+            replaceExisting: true,
+            technologyRoutingOperationId: currentProcess.value.id,
+          }).then(res => {
+            if (res.code === 200) {
+              ElMessage.success("鍚屾鎴愬姛");
+              refreshParamList();
+            } else {
+              ElMessage.error(res.msg || "鍚屾澶辫触");
+            }
+          });
+        } else {
+          syncProcessParamItem({
+            replaceExisting: true,
+            technologyRoutingOperationId: currentProcess.value.id,
+          }).then(res => {
+            if (res.code === 200) {
+              ElMessage.success("鍚屾鎴愬姛");
+              refreshParamList();
+            } else {
+              ElMessage.error(res.msg || "鍚屾澶辫触");
+            }
+          });
+        }
       })
       .catch(() => {});
   };
@@ -670,15 +689,20 @@
 
   // 浜у搧閫夋嫨
   const handleProductSelect = products => {
+    console.log(products, "===products===");
     if (products && products.length > 0) {
       const product = products[0];
-      form.value.productModelId = product.id;
-      form.value.productName = product.productName;
-      form.value.model = product.model;
-      form.value.unit = product.unit || "";
+      console.log(product, "product");
+      form.value = {
+        ...form.value,
+        productModelId: product.id,
+        productName: product.productName,
+        model: product.model,
+        unit: product.unit || "",
+      };
       showProductSelectDialog.value = false;
       // 瑙﹀彂琛ㄥ崟楠岃瘉
-      formRef.value?.validateField("productModelId");
+      // formRef.value?.validateField("productModelId");
     }
   };
 
@@ -773,6 +797,8 @@
       productName: "",
       model: "",
       unit: "",
+      isQuality: false,
+      isProduction: false,
     };
     formRef.value?.resetFields();
   };
@@ -788,7 +814,7 @@
     currentProcess.value = row;
     const query = {
       technologyRoutingOperationId: row.id,
-      orderId: orderId.value,
+      productionOrderId: orderId.value,
     };
 
     const apiPromise =
diff --git a/src/views/productionManagement/productionOrder/components/MaterialLedgerDialog.vue b/src/views/productionManagement/productionOrder/components/MaterialLedgerDialog.vue
index 9e1a852..6b040d6 100644
--- a/src/views/productionManagement/productionOrder/components/MaterialLedgerDialog.vue
+++ b/src/views/productionManagement/productionOrder/components/MaterialLedgerDialog.vue
@@ -1,298 +1,327 @@
 <template>
   <div>
-    <el-dialog v-model="dialogVisible" title="棰嗘枡鍙拌处" width="1200px" @close="handleClose">
+    <el-dialog v-model="dialogVisible"
+               title="棰嗘枡鍙拌处"
+               width="1200px"
+               @close="handleClose">
       <div class="material-toolbar">
-        <el-button type="primary" @click="handleAddMaterialRow">鏂板</el-button>
+        <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">
+      <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 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">
+        <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)">
+            <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">
+        <el-table-column label="鍘熸枡鍨嬪彿"
+                         min-width="180">
           <template #default="{ row }">
             {{ row.materialModel || "-" }}
           </template>
         </el-table-column>
-        <el-table-column label="闇�姹傛暟閲�" min-width="120">
+        <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)"
-            />
+            <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">
+        <el-table-column label="璁¢噺鍗曚綅"
+                         width="120">
           <template #default="{ row }">
             {{ row.unit || "-" }}
           </template>
         </el-table-column>
-        <el-table-column label="棰嗙敤鏁伴噺" min-width="120">
+        <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%;"
-            />
+            <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">
+        <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>
+            <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 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"
-    />
+    <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";
+  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,
-      });
-    }
+  const props = defineProps({
+    modelValue: { type: Boolean, default: false },
+    orderRow: { type: Object, default: null },
   });
-  processOptions.value = Array.from(processMap.values());
-};
+  const emit = defineEmits(["update:modelValue", "saved"]);
 
-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));
+  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;
     }
-    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();
+    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;
     }
-  }
-);
-
-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;
-}
+  .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 a67130c..6480990 100644
--- a/src/views/productionManagement/productionOrder/index.vue
+++ b/src/views/productionManagement/productionOrder/index.vue
@@ -28,7 +28,7 @@
                     @change="handleQuery" />
         </el-form-item>
         <el-form-item label="浜у搧鍚嶇О:">
-          <el-input v-model="searchForm.productCategory"
+          <el-input v-model="searchForm.productName"
                     placeholder="璇疯緭鍏�"
                     clearable
                     prefix-icon="Search"
@@ -36,7 +36,7 @@
                     @change="handleQuery" />
         </el-form-item>
         <el-form-item label="瑙勬牸:">
-          <el-input v-model="searchForm.specificationModel"
+          <el-input v-model="searchForm.model"
                     placeholder="璇疯緭鍏�"
                     clearable
                     prefix-icon="Search"
@@ -269,8 +269,8 @@
       customerName: "",
       salesContractNo: "",
       projectName: "",
-      productCategory: "",
-      specificationModel: "",
+      productName: "",
+      model: "",
     },
   });
   const { searchForm } = toRefs(data);
@@ -354,7 +354,7 @@
     try {
       await bindingRoute({
         id: bindForm.orderId,
-        routeId: bindForm.routeId,
+        technologyRoutingId: bindForm.routeId,
       });
       proxy.$modal.msgSuccess("缁戝畾鎴愬姛");
       bindRouteDialogVisible.value = false;
@@ -429,9 +429,9 @@
           id: data.id,
           bomId: data.bomId,
           processRouteCode: data.processRouteCode || "",
-          productName: data.productName || "",
-          model: data.model || "",
-          bomNo: data.bomNo || "",
+          productName: row.productName || "",
+          model: row.model || "",
+          bomNo: row.bomNo || "",
           description: data.description || "",
           orderId,
           type: "order",
@@ -449,8 +449,8 @@
       query: {
         id: row.id,
         bomNo: row.bomNo || "",
-        productName: row.productCategory || "",
-        productModelName: row.specificationModel || "",
+        productName: row.productName || "",
+        productModelName: row.model || "",
         orderId: row.id,
         type: "order",
       },
diff --git a/src/views/productionPlan/productionPlan/index.vue b/src/views/productionPlan/productionPlan/index.vue
index 9768093..9b39531 100644
--- a/src/views/productionPlan/productionPlan/index.vue
+++ b/src/views/productionPlan/productionPlan/index.vue
@@ -343,7 +343,7 @@
     },
     {
       label: "宸蹭笅鍙戞暟閲�",
-      prop: "assignedQuantity",
+      prop: "quantityIssued",
       width: "120px",
       className: "spec-cell",
       // formatData: (cell, row) => (cell ? `${cell}${row.unit || "鏂�"}` : 0),
@@ -389,16 +389,18 @@
           name: "涓嬪彂",
           type: "text",
           showHide: row => {
-            return row.status == 0;
+            return row.status != 2;
           },
           clickFun: row => {
             mergeForm.productName = row.productName || "";
             mergeForm.model = row.model || "";
-            mergeForm.totalAssignedQuantity = Number(row.qtyRequired || 0);
+            mergeForm.totalAssignedQuantity =
+              Number(row.qtyRequired || 0) - Number(row.quantityIssued || 0);
             mergeForm.planCompleteTime = row.requiredDate || "";
             mergeForm.productId = row.productId || "";
             mergeForm.ids = [row.id];
-            sumAssignedQuantity.value = Number(row.qtyRequired || 0);
+            sumAssignedQuantity.value =
+              Number(row.qtyRequired || 0) - Number(row.quantityIssued || 0);
             isShowNewModal.value = true;
           },
         },
@@ -618,9 +620,9 @@
         };
       }
       summary[category].totalAssignedQuantity += Number(
-        (
-          Number(row.qtyRequired || 0) - Number(row.assignedQuantity || 0)
-        ).toFixed(4)
+        (Number(row.qtyRequired || 0) - Number(row.quantityIssued || 0)).toFixed(
+          4
+        )
       );
     });
 
@@ -667,8 +669,12 @@
 
   // 鍒ゆ柇琛屾槸鍚﹀彲閫夋嫨
   const isSelectable = row => {
+    // 濡傛灉鏄凡涓嬪彂鐘舵�侊紝绂佹鍕鹃��
+    if (row.status == 2) {
+      return false;
+    }
     // 璁$畻鍓╀綑鏁伴噺
-    const remainingQty = (row.qtyRequired || 0) - (row.assignedQuantity || 0);
+    const remainingQty = (row.qtyRequired || 0) - (row.quantityIssued || 0);
     // 濡傛灉鍓╀綑鏁伴噺灏忎簬绛変簬0锛岀姝㈤�夋嫨
     if (remainingQty <= 0) {
       return false;
@@ -696,7 +702,7 @@
 
     // 璁$畻鎬诲埗閫犳暟閲� (榛樿qtyRequired鐨勫拰)
     const totalAssignedQuantity = selectedRows.value.reduce((sum, row) => {
-      return sum + Number(row.qtyRequired || 0);
+      return sum + Number(row.qtyRequired || 0) - Number(row.quantityIssued || 0);
     }, 0);
     sumAssignedQuantity.value = totalAssignedQuantity;
     console.log(totalAssignedQuantity);
diff --git a/src/views/salesManagement/deliveryLedger/index.vue b/src/views/salesManagement/deliveryLedger/index.vue
index 0eb60cc..223c6e9 100644
--- a/src/views/salesManagement/deliveryLedger/index.vue
+++ b/src/views/salesManagement/deliveryLedger/index.vue
@@ -3,19 +3,22 @@
     <div class="search_form">
       <el-form :model="searchForm" :inline="true">
         <el-form-item label="閿�鍞鍗曞彿锛�">
-          <el-input v-model="searchForm.salesContractNo" placeholder="璇疯緭鍏�" clearable prefix-icon="Search" style="width: 200px"
-            @change="handleQuery" />
+          <el-input v-model="searchForm.salesContractNo" placeholder="璇疯緭鍏�" clearable prefix-icon="Search"
+                    style="width: 200px"
+                    @change="handleQuery"/>
         </el-form-item>
         <el-form-item label="杞︾墝鍙凤細">
-          <el-input v-model="searchForm.shippingCarNumber" placeholder="璇疯緭鍏�" clearable prefix-icon="Search" style="width: 200px"
-            @change="handleQuery" />
+          <el-input v-model="searchForm.shippingCarNumber" placeholder="璇疯緭鍏�" clearable prefix-icon="Search"
+                    style="width: 200px"
+                    @change="handleQuery"/>
         </el-form-item>
         <el-form-item label="蹇�掑崟鍙凤細">
-          <el-input v-model="searchForm.expressNumber" placeholder="璇疯緭鍏�" clearable prefix-icon="Search" style="width: 200px"
-            @change="handleQuery" />
+          <el-input v-model="searchForm.expressNumber" placeholder="璇疯緭鍏�" clearable prefix-icon="Search"
+                    style="width: 200px"
+                    @change="handleQuery"/>
         </el-form-item>
         <el-form-item>
-          <el-button type="primary" @click="handleQuery"> 鎼滅储 </el-button>
+          <el-button type="primary" @click="handleQuery"> 鎼滅储</el-button>
         </el-form-item>
       </el-form>
     </div>
@@ -28,18 +31,18 @@
         </div>
       </div>
       <el-table :data="tableData" border v-loading="tableLoading" @selection-change="handleSelectionChange"
-        :row-key="(row) => row.id" style="width: 100%" height="calc(100vh - 21.5em)">
-        <el-table-column align="center" type="selection" width="55" />
-        <el-table-column align="center" label="搴忓彿" type="index" width="60" />
-        <el-table-column label="閿�鍞鍗�" prop="salesContractNo" show-overflow-tooltip />
-        <el-table-column label="鍙戣揣璁㈠崟鍙�" prop="shippingNo" show-overflow-tooltip />
-        <el-table-column label="瀹㈡埛鍚嶇О" prop="customerName" show-overflow-tooltip />
-        <el-table-column label="浜у搧鍚嶇О" prop="productName" show-overflow-tooltip />
-        <el-table-column label="瑙勬牸鍨嬪彿" prop="specificationModel" show-overflow-tooltip />
-        <el-table-column label="鍙戣揣鏃堕棿" prop="shippingDate" show-overflow-tooltip />
-        <el-table-column label="鍙戣揣杞︾墝鍙�" prop="shippingCarNumber" show-overflow-tooltip />
-        <el-table-column label="蹇�掑叕鍙�" prop="expressCompany" show-overflow-tooltip />
-        <el-table-column label="蹇�掑崟鍙�" prop="expressNumber" show-overflow-tooltip />
+                :row-key="(row) => row.id" style="width: 100%" height="calc(100vh - 21.5em)">
+        <el-table-column align="center" type="selection" width="55"/>
+        <el-table-column align="center" label="搴忓彿" type="index" width="60"/>
+        <el-table-column label="閿�鍞鍗�" prop="salesContractNo" show-overflow-tooltip/>
+        <el-table-column label="鍙戣揣璁㈠崟鍙�" prop="shippingNo" show-overflow-tooltip/>
+        <el-table-column label="瀹㈡埛鍚嶇О" prop="customerName" show-overflow-tooltip/>
+        <el-table-column label="浜у搧鍚嶇О" prop="productName" show-overflow-tooltip/>
+        <el-table-column label="瑙勬牸鍨嬪彿" prop="specificationModel" show-overflow-tooltip/>
+        <el-table-column label="鍙戣揣鏃堕棿" prop="shippingDate" show-overflow-tooltip/>
+        <el-table-column label="鍙戣揣杞︾墝鍙�" prop="shippingCarNumber" show-overflow-tooltip/>
+        <el-table-column label="蹇�掑叕鍙�" prop="expressCompany" show-overflow-tooltip/>
+        <el-table-column label="蹇�掑崟鍙�" prop="expressNumber" show-overflow-tooltip/>
         <el-table-column label="瀹℃牳鐘舵��" prop="status" align="center" width="120">
           <template #default="scope">
             <el-tag :type="getApprovalStatusType(scope.row.status)">
@@ -49,42 +52,46 @@
         </el-table-column>
         <el-table-column fixed="right" label="鎿嶄綔" width="220" align="center">
           <template #default="scope">
-            <el-button 
-              link 
-              type="primary"
-              :disabled="!isApproved(scope.row.status)"
-              @click="openForm('edit', scope.row)">琛ュ厖鍙戣揣淇℃伅</el-button>
             <el-button
-              link
-              type="primary"
-							style="color: #67C23A"
-              @click="openDetail(scope.row)"
-            >璇︽儏</el-button>
-            <el-button 
-              link 
-              type="danger"
-              :disabled="isApproving(scope.row.status)"
-              @click="handleDeleteSingle(scope.row)">鍒犻櫎</el-button>
+                link
+                type="primary"
+                :disabled="!isApproved(scope.row.status)"
+                @click="openForm('edit', scope.row)">琛ュ厖鍙戣揣淇℃伅
+            </el-button>
+            <el-button
+                link
+                type="primary"
+                style="color: #67C23A"
+                @click="openDetail(scope.row)"
+            >璇︽儏
+            </el-button>
+            <el-button
+                link
+                type="danger"
+                :disabled="isApproving(scope.row.status)"
+                @click="handleDeleteSingle(scope.row)">鍒犻櫎
+            </el-button>
           </template>
         </el-table-column>
       </el-table>
       <pagination v-show="total > 0" :total="total" layout="total, sizes, prev, pager, next, jumper"
-        :page="page.current" :limit="page.size" @pagination="paginationChange" />
+                  :page="page.current" :limit="page.size" @pagination="paginationChange"/>
     </div>
-    <el-dialog v-model="dialogFormVisible" :title="operationType === 'add' ? '鏂板鍙戣揣鍙拌处' : '缂栬緫鍙戣揣鍙拌处'" width="40%"
-      @close="closeDia">
+    <el-dialog v-model="dialogFormVisible" :title="operationType === 'add' ? '鏂板鍙戣揣鍙拌处' : '缂栬緫鍙戣揣鍙拌处'"
+               width="40%"
+               @close="closeDia">
       <el-form :model="form" label-width="120px" label-position="top" :rules="rules" ref="formRef">
         <el-row :gutter="30">
           <el-col :span="24">
             <el-form-item label="鍙戣揣绫诲瀷锛�" prop="type">
               <el-select
-                v-model="form.type"
-                placeholder="璇烽�夋嫨鍙戣揣绫诲瀷"
-                style="width: 100%"
-                @change="handleShippingTypeChange"
+                  v-model="form.type"
+                  placeholder="璇烽�夋嫨鍙戣揣绫诲瀷"
+                  style="width: 100%"
+                  @change="handleShippingTypeChange"
               >
-                <el-option label="璐ц溅" value="璐ц溅" />
-                <el-option label="蹇��" value="蹇��" />
+                <el-option label="璐ц溅" value="璐ц溅"/>
+                <el-option label="蹇��" value="蹇��"/>
               </el-select>
             </el-form-item>
           </el-col>
@@ -93,13 +100,13 @@
           <el-col :span="24">
             <el-form-item label="鍙戣揣鏃ユ湡锛�" prop="shippingDate">
               <el-date-picker
-                style="width: 100%"
-                v-model="form.shippingDate"
-                value-format="YYYY-MM-DD"
-                format="YYYY-MM-DD"
-                type="date"
-                placeholder="璇烽�夋嫨鍙戣揣鏃ユ湡"
-                clearable
+                  style="width: 100%"
+                  v-model="form.shippingDate"
+                  value-format="YYYY-MM-DD"
+                  format="YYYY-MM-DD"
+                  type="date"
+                  placeholder="璇烽�夋嫨鍙戣揣鏃ユ湡"
+                  clearable
               />
             </el-form-item>
           </el-col>
@@ -108,18 +115,18 @@
           <el-col :span="24" v-if="form.type === '璐ц溅'">
             <el-form-item label="鍙戣揣杞︾墝鍙凤細" prop="shippingCarNumber">
               <el-input
-                v-model="form.shippingCarNumber"
-                placeholder="璇疯緭鍏ュ彂璐ц溅鐗屽彿"
-                clearable
+                  v-model="form.shippingCarNumber"
+                  placeholder="璇疯緭鍏ュ彂璐ц溅鐗屽彿"
+                  clearable
               />
             </el-form-item>
           </el-col>
           <el-col :span="24" v-else>
             <el-form-item label="蹇�掑叕鍙革細" prop="expressCompany">
               <el-input
-                v-model="form.expressCompany"
-                placeholder="璇疯緭鍏ュ揩閫掑叕鍙�"
-                clearable
+                  v-model="form.expressCompany"
+                  placeholder="璇疯緭鍏ュ揩閫掑叕鍙�"
+                  clearable
               />
             </el-form-item>
           </el-col>
@@ -128,9 +135,9 @@
           <el-col :span="24">
             <el-form-item label="蹇�掑崟鍙凤細" prop="expressNumber">
               <el-input
-                v-model="form.expressNumber"
-                placeholder="璇疯緭鍏ュ揩閫掑崟鍙�"
-                clearable
+                  v-model="form.expressNumber"
+                  placeholder="璇疯緭鍏ュ揩閫掑崟鍙�"
+                  clearable
               />
             </el-form-item>
           </el-col>
@@ -138,29 +145,7 @@
         <el-row :gutter="30">
           <el-col :span="24">
             <el-form-item label="鍙戣揣鍥剧墖锛�">
-              <el-upload 
-                v-model:file-list="deliveryFileList" 
-                :action="upload.url" 
-                multiple 
-                ref="deliveryFileUpload" 
-                auto-upload
-                :headers="upload.headers" 
-                :data="{ type: 9 }"
-                :before-upload="handleDeliveryBeforeUpload" 
-                :on-error="handleDeliveryUploadError"
-                :on-success="handleDeliveryUploadSuccess" 
-                :on-remove="handleDeliveryRemove"
-                list-type="picture-card"
-                :limit="9"
-                accept="image/png,image/jpeg,image/jpg"
-              >
-                <el-icon class="avatar-uploader-icon"><Plus /></el-icon>
-                <template #tip>
-                  <div class="el-upload__tip">
-                    鏀寔 jpg銆乯peg銆乸ng 鏍煎紡锛屾渶澶氫笂浼� 9 寮狅紝鍗曞紶澶у皬涓嶈秴杩� 10MB
-                  </div>
-                </template>
-              </el-upload>
+              <ImageUpload v-model:file-list="deliveryFileList" :limit="9"/>
             </el-form-item>
           </el-col>
         </el-row>
@@ -189,19 +174,7 @@
           <el-descriptions-item label="蹇�掑叕鍙�">{{ detailRow.expressCompany || '--' }}</el-descriptions-item>
           <el-descriptions-item label="蹇�掑崟鍙�" :span="2">{{ detailRow.expressNumber || '--' }}</el-descriptions-item>
         </el-descriptions>
-
-        <div class="detail-images" v-if="detailImages.length">
-          <div class="detail-images-title">鍙戣揣鍥剧墖</div>
-          <el-image
-            v-for="img in detailImages"
-            :key="img.url"
-            :src="img.url"
-            :preview-src-list="detailImages.map(i => i.url)"
-            fit="cover"
-            class="detail-image"
-          />
-        </div>
-        <div v-else class="detail-images-empty">鏆傛棤鍙戣揣鍥剧墖</div>
+        <ImagePreview :file-list="detailRow.storageBlobVOs || []" />
       </div>
       <template #footer>
         <div class="dialog-footer">
@@ -214,20 +187,19 @@
 
 <script setup>
 import pagination from "@/components/PIMTable/Pagination.vue";
-import { onMounted, ref, reactive, toRefs, getCurrentInstance } from "vue";
-import { ElMessageBox } from "element-plus";
-import { Plus } from "@element-plus/icons-vue";
-import { getToken } from "@/utils/auth";
-import { getCurrentDate } from "@/utils/index.js";
+import {onMounted, ref, reactive, toRefs, getCurrentInstance} from "vue";
+import {ElMessageBox} from "element-plus";
+import {getCurrentDate} from "@/utils/index.js";
 import {
-	deliveryLedgerListPage,
-	addOrUpdateDeliveryLedger,
-	delDeliveryLedger, deductStock,
+  deliveryLedgerListPage,
+  delDeliveryLedger, deductStock,
 } from "@/api/salesManagement/deliveryLedger.js";
-import { delLedgerFile } from "@/api/salesManagement/salesLedger.js";
- 
+import {delLedgerFile} from "@/api/salesManagement/salesLedger.js";
+import ImageUpload from "@/components/AttachmentUpload/image/index.vue";
+import ImagePreview from "@/components/AttachmentPreview/image/index.vue";
 
-const { proxy } = getCurrentInstance();
+
+const {proxy} = getCurrentInstance();
 const tableData = ref([]);
 const selectedRows = ref([]);
 const tableLoading = ref(false);
@@ -238,40 +210,9 @@
 });
 const total = ref(0);
 const deliveryFileList = ref([]);
-const javaApi = proxy.javaApi;
 // 璇︽儏寮规
 const detailDialogVisible = ref(false);
 const detailRow = ref(null);
-const detailImages = ref([]);
-
-const normalizeFileUrl = (rawUrl = '') => {
-  let fileUrl = rawUrl || '';
-  // Windows 璺緞杞� URL
-  if (fileUrl && fileUrl.indexOf('\\') > -1) {
-    const uploadsIndex = fileUrl.toLowerCase().indexOf('uploads');
-    if (uploadsIndex > -1) {
-      const relativePath = fileUrl.substring(uploadsIndex).replace(/\\/g, '/');
-      fileUrl = '/' + relativePath;
-    } else {
-      const parts = fileUrl.split('\\');
-      const fileName = parts[parts.length - 1];
-      fileUrl = '/uploads/' + fileName;
-    }
-  }
-  if (fileUrl && !fileUrl.startsWith('http')) {
-    if (!fileUrl.startsWith('/')) fileUrl = '/' + fileUrl;
-    fileUrl = javaApi + fileUrl;
-  }
-  return fileUrl;
-};
-
-// 涓婁紶閰嶇疆
-const upload = reactive({
-  // 涓婁紶鐨勫湴鍧�
-  url: import.meta.env.VITE_APP_BASE_API + "/file/upload",
-  // 璁剧疆涓婁紶鐨勮姹傚ご閮�
-  headers: { Authorization: "Bearer " + getToken() },
-});
 
 // 鐢ㄦ埛淇℃伅琛ㄥ崟寮规鏁版嵁
 const operationType = ref("");
@@ -295,24 +236,23 @@
     expressNumber: "", // 蹇�掑崟鍙�
   },
   rules: {
-    salesContractNo: [{ required: true, message: "璇烽�夋嫨閿�鍞鍗�", trigger: "change" }],
-    customerName: [{ required: true, message: "璇疯緭鍏ュ鎴峰悕绉�", trigger: "blur" }],
+    salesContractNo: [{required: true, message: "璇烽�夋嫨閿�鍞鍗�", trigger: "change"}],
+    customerName: [{required: true, message: "璇疯緭鍏ュ鎴峰悕绉�", trigger: "blur"}],
     type: [
-      { required: true, message: "璇烽�夋嫨鍙戣揣绫诲瀷", trigger: "change" }
+      {required: true, message: "璇烽�夋嫨鍙戣揣绫诲瀷", trigger: "change"}
     ],
-    shippingDate: [{ required: true, message: "璇烽�夋嫨鍙戣揣鏃堕棿", trigger: "change" }],
+    shippingDate: [{required: true, message: "璇烽�夋嫨鍙戣揣鏃堕棿", trigger: "change"}],
     shippingCarNumber: [
-      { validator: (_, value, callback) => validateShippingCarNumber(value, callback), trigger: "blur" }
+      {validator: (_, value, callback) => validateShippingCarNumber(value, callback), trigger: "blur"}
     ],
     expressCompany: [
-      { validator: (_, value, callback) => validateExpressCompany(value, callback), trigger: "blur" }
+      {validator: (_, value, callback) => validateExpressCompany(value, callback), trigger: "blur"}
     ],
   },
 });
-const { form, rules } = toRefs(data);
-const { searchForm } = toRefs(data);
+const {form, rules} = toRefs(data);
+const {searchForm} = toRefs(data);
 
- 
 
 // 鏌ヨ鍒楄〃
 const handleQuery = () => {
@@ -328,15 +268,15 @@
 
 const getList = () => {
   tableLoading.value = true;
-  deliveryLedgerListPage({ ...searchForm.value, ...page })
-    .then((res) => {
-      tableLoading.value = false;
-      tableData.value = res.data.records || [];
-      total.value = res.data.total || 0;
-    })
-    .catch(() => {
-      tableLoading.value = false;
-    });
+  deliveryLedgerListPage({...searchForm.value, ...page})
+      .then((res) => {
+        tableLoading.value = false;
+        tableData.value = res.data.records || [];
+        total.value = res.data.total || 0;
+      })
+      .catch(() => {
+        tableLoading.value = false;
+      });
 };
 
 // 閿�鍞鍗曞彉鍖栨椂鑷姩濉厖瀹㈡埛鍚嶇О
@@ -359,10 +299,9 @@
     proxy.$modal.msgWarning("鍙湁瀹℃牳閫氳繃鐨勬暟鎹墠鍙互琛ュ厖鍙戣揣淇℃伅");
     return;
   }
-  
+
   operationType.value = type;
-  const baseUrl = import.meta.env.VITE_APP_BASE_API;
-  
+
   if (type === 'edit' && row) {
     form.value = {
       id: row.id ?? null,
@@ -374,43 +313,9 @@
       expressCompany: row.expressCompany ?? "",
       expressNumber: row.expressNumber ?? "",
     };
-    // 濡傛灉鏈夊浘鐗囷紝灏� commonFileList 杞崲涓烘枃浠跺垪琛ㄦ牸寮�
-    if (row.commonFileList && Array.isArray(row.commonFileList) && row.commonFileList.length > 0) {
-      deliveryFileList.value = row.commonFileList.map((file, index) => {
-        const fileUrl = normalizeFileUrl(file.url || '');
-        
-        return {
-          uid: file.id || Date.now() + index,
-          name: file.name || `image_${index + 1}.jpg`,
-          url: fileUrl,
-          status: 'success',
-          response: {
-            code: 200,
-            data: {
-              tempId: file.id,
-              url: fileUrl
-            }
-          },
-          tempId: file.id // 淇濆瓨鏂囦欢ID锛岀敤浜庢彁浜ゆ椂浣跨敤
-        };
-      });
-    } else {
-      deliveryFileList.value = [];
-    }
-  } else {
-    form.value = {
-      id: null,
-      salesContractNo: "",
-      customerName: "",
-      type: "璐ц溅",
-      shippingDate: getCurrentDate(),
-      shippingCarNumber: "",
-      expressCompany: "",
-      expressNumber: "",
-    };
-    deliveryFileList.value = [];
+    deliveryFileList.value = row.storageBlobVOS || [];
   }
-  
+
   dialogFormVisible.value = true;
 };
 
@@ -418,25 +323,17 @@
 const openDetail = (row) => {
   detailRow.value = row || null;
   const list = Array.isArray(row?.commonFileList) ? row.commonFileList : [];
-  detailImages.value = list
-    .map((f) => ({ url: normalizeFileUrl(f?.url || '') }))
-    .filter((i) => !!i.url);
   detailDialogVisible.value = true;
 };
 const closeDetail = () => {
   detailDialogVisible.value = false;
   detailRow.value = null;
-  detailImages.value = [];
 };
 
 // 鎻愪氦琛ㄥ崟
 const submitForm = () => {
   proxy.$refs["formRef"].validate((valid) => {
     if (valid) {
-      let tempFileIds = [];
-      if (deliveryFileList.value !== null && deliveryFileList.value.length > 0) {
-        tempFileIds = deliveryFileList.value.map((item) => item.tempId);
-      }
       const payload = {
         id: form.value.id,
         type: form.value.type,
@@ -444,9 +341,9 @@
         shippingCarNumber: form.value.type === "璐ц溅" ? form.value.shippingCarNumber : "",
         expressCompany: form.value.type === "蹇��" ? form.value.expressCompany : "",
         expressNumber: form.value.type === "蹇��" ? form.value.expressNumber : "",
-        tempFileIds: tempFileIds,
+        storageBlobDTOs: deliveryFileList.value || [],
       };
-			deductStock(payload).then((res) => {
+      deductStock(payload).then((res) => {
         proxy.$modal.msgSuccess("鎿嶄綔鎴愬姛");
         closeDia();
         getList();
@@ -469,12 +366,12 @@
     cancelButtonText: "鍙栨秷",
     type: "warning",
   })
-    .then(() => {
-      proxy.download("/shippingInfo/export", {}, "鍙戣揣鍙拌处.xlsx");
-    })
-    .catch(() => {
-      proxy.$modal.msg("宸插彇娑�");
-    });
+      .then(() => {
+        proxy.download("/shippingInfo/export", {}, "鍙戣揣鍙拌处.xlsx");
+      })
+      .catch(() => {
+        proxy.$modal.msg("宸插彇娑�");
+      });
 };
 
 // 鎵归噺鍒犻櫎
@@ -483,29 +380,29 @@
     proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
     return;
   }
-  
+
   // 妫�鏌ラ�変腑鐨勮鏄惁鏈�"瀹℃牳涓�"鐘舵��
   const approvingRows = selectedRows.value.filter(row => isApproving(row.status));
   if (approvingRows.length > 0) {
     proxy.$modal.msgWarning("瀹℃牳涓殑鏁版嵁涓嶈兘鍒犻櫎");
     return;
   }
-  
+
   const ids = selectedRows.value.map((item) => item.id);
   ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "鍒犻櫎", {
     confirmButtonText: "纭",
     cancelButtonText: "鍙栨秷",
     type: "warning",
   })
-    .then(() => {
-      delDeliveryLedger(ids).then((res) => {
-        proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
-        getList();
+      .then(() => {
+        delDeliveryLedger(ids).then((res) => {
+          proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+          getList();
+        });
+      })
+      .catch(() => {
+        proxy.$modal.msg("宸插彇娑�");
       });
-    })
-    .catch(() => {
-      proxy.$modal.msg("宸插彇娑�");
-    });
 };
 
 // 鍗曚釜鍒犻櫎
@@ -515,21 +412,21 @@
     proxy.$modal.msgWarning("瀹℃牳涓殑鏁版嵁涓嶈兘鍒犻櫎");
     return;
   }
-  
+
   ElMessageBox.confirm("姝ゆ搷浣滃皢鍒犻櫎璇ヨ褰曪紝鏄惁纭锛�", "鍒犻櫎", {
     confirmButtonText: "纭",
     cancelButtonText: "鍙栨秷",
     type: "warning",
   })
-    .then(() => {
-      delDeliveryLedger([row.id]).then((res) => {
-        proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
-        getList();
+      .then(() => {
+        delDeliveryLedger([row.id]).then((res) => {
+          proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+          getList();
+        });
+      })
+      .catch(() => {
+        proxy.$modal.msg("宸插彇娑�");
       });
-    })
-    .catch(() => {
-      proxy.$modal.msg("宸插彇娑�");
-    });
 };
 
 // 鍙戣揣绫诲瀷鏍¢獙锛氳揣杞︽椂瑕佹眰杞︾墝锛屽揩閫掓椂瑕佹眰蹇�掑叕鍙�
@@ -563,11 +460,13 @@
   proxy.$modal.loading("姝e湪涓婁紶鍥剧墖锛岃绋嶅��...");
   return true;
 }
+
 // 鍙戣揣鍥剧墖涓婁紶澶辫触
 function handleDeliveryUploadError(err) {
   proxy.$modal.msgError("涓婁紶鍥剧墖澶辫触");
   proxy.$modal.closeLoading();
 }
+
 // 鍙戣揣鍥剧墖涓婁紶鎴愬姛鍥炶皟
 function handleDeliveryUploadSuccess(res, file, uploadFiles) {
   proxy.$modal.closeLoading();
@@ -579,6 +478,7 @@
     proxy.$refs.deliveryFileUpload.handleRemove(file);
   }
 }
+
 // 绉婚櫎鍙戣揣鍥剧墖
 function handleDeliveryRemove(file) {
   console.log('file--', file)
@@ -727,17 +627,21 @@
     display: none;
   }
 }
+
 .detail-wrapper {
   padding: 8px 0;
 }
+
 .detail-images {
   margin-top: 16px;
 }
+
 .detail-images-title {
   font-weight: 600;
   margin-bottom: 10px;
   color: #303133;
 }
+
 .detail-image {
   width: 120px;
   height: 120px;
@@ -745,6 +649,7 @@
   margin-bottom: 10px;
   border-radius: 6px;
 }
+
 .detail-images-empty {
   margin-top: 16px;
   color: #909399;

--
Gitblit v1.9.3