From 4e62fd388119141405e33ecc28cad2638617603f Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期六, 25 四月 2026 17:22:14 +0800
Subject: [PATCH] 天津宝东 1.修改生产流程

---
 src/views/productionManagement/productionOrder/components/MaterialDetailDialog.vue |   94 ++++------
 src/views/productionManagement/productionOrder/components/MaterialLedgerDialog.vue |  153 ++++++-----------
 src/views/productionManagement/productionOrder/index.vue                           |  272 +++++++++++++++++++++++++++++
 src/api/productionManagement/productionOrder.js                                    |    2 
 src/views/productionManagement/workOrderManagement/index.vue                       |   14 
 5 files changed, 369 insertions(+), 166 deletions(-)

diff --git a/src/api/productionManagement/productionOrder.js b/src/api/productionManagement/productionOrder.js
index b8468eb..c62ffa2 100644
--- a/src/api/productionManagement/productionOrder.js
+++ b/src/api/productionManagement/productionOrder.js
@@ -73,7 +73,7 @@
 // 鐢熶骇璁㈠崟-淇濆瓨棰嗘枡鍙拌处
 export function saveMaterialPickingLedger(data) {
   return request({
-    url: "/productOrderMaterial/save",
+    url: "/productOrderMaterial/update",
     method: "post",
     data,
   });
diff --git a/src/views/productionManagement/productionOrder/components/MaterialDetailDialog.vue b/src/views/productionManagement/productionOrder/components/MaterialDetailDialog.vue
index 9c50fc8..2379076 100644
--- a/src/views/productionManagement/productionOrder/components/MaterialDetailDialog.vue
+++ b/src/views/productionManagement/productionOrder/components/MaterialDetailDialog.vue
@@ -2,47 +2,29 @@
   <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="basePaperQty" min-width="120" />
+        <el-table-column label="绾哥闇�瑕侀噺" prop="cartonQty" min-width="120" />
+        <el-table-column label="濉戞枡琚嬫暟閲�" prop="plasticBagQty" min-width="120" />
         <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="basePaperPickQty" min-width="120" />
+        <el-table-column label="绾哥棰嗙敤鏁伴噺" prop="cartonPickQty" min-width="120" />
+        <el-table-column label="濉戞枡琚嬮鐢ㄦ暟閲�" prop="plasticBagPickQty" min-width="120" />
         <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-->
+<!--            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>
@@ -68,7 +50,7 @@
 <script setup>
 import { computed, ref, watch } from "vue";
 import { ElMessage } from "element-plus";
-import { listMaterialPickingDetail, listMaterialSupplementRecord, confirmMaterialReturn } from "@/api/productionManagement/productionOrder.js";
+import { listMaterialPickingDetail, confirmMaterialReturn } from "@/api/productionManagement/productionOrder.js";
 
 const props = defineProps({
   modelValue: { type: Boolean, default: false },
@@ -84,24 +66,37 @@
 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 getPickQty = item => {
+  const directPick = Number(item.pickQty ?? NaN);
+  if (Number.isFinite(directPick)) return directPick;
+  return (
+    Number(item.basePaperPickQty || 0) +
+    Number(item.cartonPickQty || 0) +
+    Number(item.plasticBagPickQty || 0)
+  );
+};
 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)
-);
+  getPickQty(item) - Number(item.actualQty || 0);
+const normalizeList = (res) => {
+  if (Array.isArray(res?.data)) return res.data;
+  if (Array.isArray(res?.data?.records)) return res.data.records;
+  if (Array.isArray(res?.records)) return res.records;
+  return [];
+};
+const canOpenReturnSummary = computed(() => {
+  const list = Array.isArray(materialDetailTableData.value) ? materialDetailTableData.value : [];
+  return list.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 || [];
+    const res = await listMaterialPickingDetail({ productOrderId: props.orderRow.id });
+    materialDetailTableData.value = normalizeList(res);
   } finally {
     materialDetailLoading.value = false;
   }
@@ -118,19 +113,6 @@
 
 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 = () => {
@@ -154,7 +136,7 @@
 
 const openReturnSummaryDialog = async () => {
   if (!canOpenReturnSummary.value) {
-    ElMessage.warning("閫�鏂欐暟閲�=棰嗙敤鏁伴噺+琛ユ枡鏁伴噺-瀹為檯鏁伴噺锛屼笖闇�澶т簬0");
+    ElMessage.warning("閫�鏂欐暟閲�=棰嗙敤鏁伴噺-瀹為檯鏁伴噺锛屼笖闇�澶т簬0");
     return;
   }
   returnSummaryList.value = buildReturnSummary();
diff --git a/src/views/productionManagement/productionOrder/components/MaterialLedgerDialog.vue b/src/views/productionManagement/productionOrder/components/MaterialLedgerDialog.vue
index 9e1a852..7442a11 100644
--- a/src/views/productionManagement/productionOrder/components/MaterialLedgerDialog.vue
+++ b/src/views/productionManagement/productionOrder/components/MaterialLedgerDialog.vue
@@ -5,59 +5,61 @@
         <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 label="鍘熸枡鍚嶇О" min-width="160" prop="materialName">
         </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">
+        <el-table-column label="鍘熺焊闇�瑕侀噺" min-width="120">
           <template #default="{ row }">
-            <span v-if="row.bom === true">{{ row.requiredQty ?? "-" }}</span>
+            {{ row.basePaperQty ?? "-" }}
+          </template>
+        </el-table-column>
+        <el-table-column label="绾哥闇�瑕侀噺" min-width="120">
+          <template #default="{ row }">
+            {{ row.cartonQty ?? "-" }}
+          </template>
+        </el-table-column>
+        <el-table-column label="濉戞枡琚嬫暟閲�" min-width="120">
+          <template #default="{ row }">
+            {{ row.plasticBagQty ?? "-" }}
+          </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-else
-              v-model="row.requiredQty"
+              v-model="row.basePaperPickQty"
               :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">
+        <el-table-column label="绾哥棰嗙敤鏁伴噺" min-width="120">
           <template #default="{ row }">
             <el-input-number
-              v-model="row.pickQty"
+              v-model="row.cartonPickQty"
+              :min="0"
+              :precision="3"
+              :step="1"
+              controls-position="right"
+              style="width: 100%;"
+            />
+          </template>
+        </el-table-column>
+        <el-table-column label="濉戞枡琚嬮鐢ㄦ暟閲�" min-width="120">
+          <template #default="{ row }">
+            <el-input-number
+              v-model="row.plasticBagPickQty"
               :min="0"
               :precision="3"
               :step="1"
@@ -84,7 +86,6 @@
       v-model="materialProductDialogVisible"
       @confirm="handleMaterialProductConfirm"
       single
-      request-url="/stockInventory/rawMaterials"
     />
   </div>
 </template>
@@ -93,7 +94,6 @@
 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,
@@ -115,7 +115,6 @@
 const materialTableLoading = ref(false);
 const materialSaving = ref(false);
 const materialTableData = ref([]);
-const processOptions = ref([]);
 const currentMaterialSelectRowIndex = ref(-1);
 let materialTempId = 0;
 
@@ -129,38 +128,21 @@
   materialModelId: row.materialModelId,
   materialName: row.materialName || "",
   materialModel: row.materialModel || "",
-  requiredQty: Number(row.requiredQty ?? 0),
+  basePaperQty: Number(row.basePaperQty ?? row.requiredQty ?? 0),
+  cartonQty: Number(row.cartonQty ?? 0),
+  plasticBagQty: Number(row.plasticBagQty ?? 0),
+  basePaperPickQty: Number(row.basePaperPickQty ?? row.pickQty ?? 0),
+  cartonPickQty: Number(row.cartonPickQty ?? 0),
+  plasticBagPickQty: Number(row.plasticBagPickQty ?? 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 detailRes = await listMaterialPickingDetail({ productOrderId: props.orderRow.id });
     const detailList = Array.isArray(detailRes?.data)
       ? detailRes.data
       : detailRes?.data?.records || [];
@@ -200,19 +182,6 @@
   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;
@@ -237,22 +206,23 @@
     return { valid: false, message: "璇峰厛鏂板棰嗘枡鏁版嵁" };
   }
   const invalidNewRow = materialTableData.value.find(
-    item => item.bom !== true && (!item.processName || !item.materialName)
+    item => item.bom !== true && !item.materialName
   );
   if (invalidNewRow) {
-    return { valid: false, message: "鏂板琛岀殑宸ュ簭鍚嶇О鍜屽師鏂欏悕绉颁负蹇呭~椤�" };
+    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
+      item.basePaperPickQty === null ||
+      item.basePaperPickQty === undefined ||
+      item.cartonPickQty === null ||
+      item.cartonPickQty === undefined ||
+      item.plasticBagPickQty === null ||
+      item.plasticBagPickQty === undefined
   );
   if (invalidRow) {
-    return { valid: false, message: "璇峰畬鍠勫伐搴忋�佸師鏂欏拰鏁伴噺鍚庡啀淇濆瓨" };
+    return { valid: false, message: "璇峰畬鍠勯鐢ㄦ暟閲忓悗鍐嶄繚瀛�" };
   }
   return { valid: true, message: "" };
 };
@@ -266,22 +236,7 @@
   }
   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,
-      })),
-    });
+    await saveMaterialPickingLedger(materialTableData.value[0]);
     emit("saved");
     dialogVisible.value = false;
   } finally {
diff --git a/src/views/productionManagement/productionOrder/index.vue b/src/views/productionManagement/productionOrder/index.vue
index 667688e..e00becb 100644
--- a/src/views/productionManagement/productionOrder/index.vue
+++ b/src/views/productionManagement/productionOrder/index.vue
@@ -75,7 +75,7 @@
     </div>
     <el-dialog v-model="bindRouteDialogVisible"
                title="缁戝畾宸ヨ壓璺嚎"
-               width="500px">
+               width="1280px">
       <el-form label-width="90px">
         <el-form-item label="宸ヨ壓璺嚎">
           <el-select v-model="bindForm.routeId"
@@ -87,6 +87,106 @@
                        :label="`${item.processRouteCode || ''}`"
                        :value="item.id" />
           </el-select>
+        </el-form-item>
+        <el-form-item label="鐢ㄦ枡淇℃伅">
+          <el-table :data="bindRouteTableData"
+                    border
+                    size="small"
+                    class="bind-route-table">
+<!--            <el-table-column label="鍝佺墝"-->
+<!--                             min-width="90"-->
+<!--                             align="center">-->
+<!--              <template #default="{ row }">-->
+<!--                {{ row.brand || row.productBrand || "&#45;&#45;" }}-->
+<!--              </template>-->
+<!--            </el-table-column>-->
+            <el-table-column label="鍝佸悕"
+                             prop="productCategory"
+                             min-width="130"
+                             align="center"
+                             show-overflow-tooltip />
+            <el-table-column label="棰勫畾浜よ揣鏃ユ湡"
+                             min-width="120"
+                             align="center">
+              <template #default="{ row }">
+                {{ formatBindDate(row.deliveryDate) }}
+              </template>
+            </el-table-column>
+            <el-table-column label="璁㈠崟鏁伴噺"
+                             prop="quantity"
+                             min-width="100"
+                             align="center" />
+            <el-table-column label="鍘熺焊瑙勬牸"
+                             min-width="160"
+                             align="center">
+              <template #default>
+                <el-tree-select v-model="bindForm.productCategoryId"
+                           placeholder="璇烽�夋嫨鍘熺焊瑙勬牸"
+                           filterable
+                           clearable
+                           check-strictly
+                           :render-after-expand="false"
+                           style="width: 100%;"
+                           :loading="bindProductLoading"
+                           :data="bindProductOptions"
+                           @change="handleBindCategoryChange" />
+              </template>
+            </el-table-column>
+            <el-table-column label="鍘熸枡鍨嬪彿"
+                             min-width="160"
+                             align="center">
+              <template #default>
+                <el-select
+                  v-model="bindForm.materialModel"
+                  placeholder="璇烽�夋嫨鍘熸枡鍨嬪彿"
+                  filterable
+                  clearable
+                  style="width: 100%;"
+                  :loading="bindMaterialModelLoading"
+                >
+                  <el-option
+                    v-for="item in bindMaterialModelOptions"
+                    :key="item.value"
+                    :label="item.label"
+                    :value="item.value"
+                  />
+                </el-select>
+              </template>
+            </el-table-column>
+            <el-table-column label="鍘熺焊闇�瑕侀噺"
+                             min-width="120"
+                             align="center">
+              <template #default>
+                <el-input-number v-model="bindForm.basePaperQty"
+                                 :min="0"
+                                 :precision="2"
+                                 controls-position="right"
+                                 style="width: 100%" />
+              </template>
+            </el-table-column>
+            <el-table-column label="绾哥闇�瑕侀噺"
+                             min-width="120"
+                             align="center">
+              <template #default>
+                <el-input-number v-model="bindForm.cartonQty"
+                                 :min="0"
+                                 :precision="2"
+                                 controls-position="right"
+                                 style="width: 100%" />
+              </template>
+            </el-table-column>
+            <el-table-column label="濉戞枡琚嬫暟閲�"
+                             min-width="120"
+                             align="center">
+              <template #default>
+                <el-input-number v-model="bindForm.plasticBagQty"
+                                 :min="0"
+                                 :precision="2"
+                                 controls-position="right"
+                                 style="width: 100%" />
+              </template>
+            </el-table-column>
+          </el-table>
         </el-form-item>
       </el-form>
       <template #footer>
@@ -125,8 +225,9 @@
     productOrderListPage,
     listProcessRoute,
     bindingRoute,
-    listProcessBom, delProductOrder,
+    delProductOrder,
   } from "@/api/productionManagement/productionOrder.js";
+  import { modelList, productTreeList } from "@/api/basicData/product.js";
   import { listMain as getOrderProcessRouteMain } from "@/api/productionManagement/productProcessRoute.js";
   import MaterialLedgerDialog from "@/views/productionManagement/productionOrder/components/MaterialLedgerDialog.vue";
   import MaterialDetailDialog from "@/views/productionManagement/productionOrder/components/MaterialDetailDialog.vue";
@@ -308,18 +409,129 @@
   const bindRouteLoading = ref(false);
   const bindRouteSaving = ref(false);
   const routeOptions = ref([]);
+  const bindProductOptions = ref([]);
+  const bindProductLoading = ref(false);
+  const bindMaterialModelOptions = ref([]);
+  const bindMaterialModelLoading = ref(false);
+  const currentBindOrderRow = ref(null);
+  const bindRouteTableData = computed(() => currentBindOrderRow.value ? [currentBindOrderRow.value] : []);
   const bindForm = reactive({
     orderId: null,
     routeId: null,
+    productCategoryId: null,
+    productCategory: "",
+    materialModel: "",
+    basePaperQty: null,
+    cartonQty: null,
+    plasticBagQty: null,
   });
   const materialDialogVisible = ref(false);
   const currentMaterialOrder = ref(null);
   const materialDetailDialogVisible = ref(false);
   const currentMaterialDetailOrder = ref(null);
 
+  function convertIdToValue(data) {
+    return (data || []).map((item) => {
+      const { id, children, ...rest } = item;
+      const node = {
+        ...rest,
+        value: id,
+      };
+      if (children && children.length > 0) {
+        node.children = convertIdToValue(children);
+      }
+      return node;
+    });
+  }
+
+  const findNodeById = (nodes, productId) => {
+    const tree = nodes || [];
+    for (let i = 0; i < tree.length; i++) {
+      if (String(tree[i].value) === String(productId)) {
+        return tree[i].label;
+      }
+      if (tree[i].children && tree[i].children.length > 0) {
+        const found = findNodeById(tree[i].children, productId);
+        if (found) return found;
+      }
+    }
+    return "";
+  };
+
+  const loadBindProductOptions = async (row) => {
+    bindProductLoading.value = true;
+    try {
+      const res = await productTreeList();
+      bindProductOptions.value = convertIdToValue(res || []);
+      if (row?.productCategoryId) {
+        bindForm.productCategoryId = row.productCategoryId;
+      } else if (!bindForm.productCategoryId && row?.productCategory) {
+        // 浠呮湁鍚嶇О鏃朵繚鐣欏悕绉帮紝涓嶅己鍒惰鐩�
+        bindForm.productCategory = row.productCategory;
+      }
+    } catch (e) {
+      console.error("鑾峰彇浜у搧閫夐」澶辫触锛�", e);
+    } finally {
+      bindProductLoading.value = false;
+    }
+  };
+
+  const loadBindMaterialModelOptions = async (productCategoryId) => {
+    if (!productCategoryId) {
+      bindMaterialModelOptions.value = [];
+      bindForm.materialModel = "";
+      return;
+    }
+    bindMaterialModelLoading.value = true;
+    try {
+      const res = await modelList({ id: productCategoryId });
+      const list = Array.isArray(res) ? res : (Array.isArray(res?.data) ? res.data : []);
+      const mapped = list
+        .map((item) => ({
+          label: item.model || "",
+          value: item.model || "",
+        }))
+        .filter((item) => item.value);
+      const unique = [];
+      const seen = new Set();
+      mapped.forEach((item) => {
+        if (!seen.has(item.value)) {
+          seen.add(item.value);
+          unique.push(item);
+        }
+      });
+      bindMaterialModelOptions.value = unique;
+      if (!unique.some((item) => item.value === bindForm.materialModel)) {
+        bindForm.materialModel = "";
+      }
+    } catch (e) {
+      console.error("鑾峰彇鍘熸枡鍨嬪彿澶辫触锛�", e);
+      bindMaterialModelOptions.value = [];
+      bindForm.materialModel = "";
+    } finally {
+      bindMaterialModelLoading.value = false;
+    }
+  };
+
+  const handleBindCategoryChange = async (value) => {
+    bindForm.productCategoryId = value;
+    bindForm.productCategory = findNodeById(bindProductOptions.value, value);
+    bindForm.materialModel = "";
+    await loadBindMaterialModelOptions(value);
+  };
+
   const openBindRouteDialog = async row => {
+    currentBindOrderRow.value = row;
     bindForm.orderId = row.id;
     bindForm.routeId = null;
+    bindForm.productCategoryId = row.productCategoryId || null;
+    bindForm.productCategory = row.productCategory || "";
+    bindForm.materialModel = row.materialModel || "";
+    bindForm.basePaperQty = null;
+    bindForm.cartonQty = null;
+    bindForm.plasticBagQty = null;
+    bindProductOptions.value = [];
+    bindMaterialModelOptions.value = [];
     bindRouteDialogVisible.value = true;
     routeOptions.value = [];
     if (!row.productModelId) {
@@ -329,7 +541,7 @@
     }
     bindRouteLoading.value = true;
     try {
-      const res = await listProcessRoute({ productModelId: row.productModelId });
+      const res = await listProcessRoute();
       routeOptions.value = res.data || [];
     } catch (e) {
       console.error("鑾峰彇宸ヨ壓璺嚎鍒楄〃澶辫触锛�", e);
@@ -337,11 +549,40 @@
     } finally {
       bindRouteLoading.value = false;
     }
+    await loadBindProductOptions(row);
+    await loadBindMaterialModelOptions(bindForm.productCategoryId);
   };
+
+  const formatBindDate = value => {
+    if (!value) return "--";
+    return dayjs(value).format("YYYY-MM-DD");
+  };
+
+  const isEmptyField = (value) => value === null || value === undefined || value === "";
 
   const handleBindRouteConfirm = async () => {
     if (!bindForm.routeId) {
       proxy.$modal.msgWarning("璇烽�夋嫨宸ヨ壓璺嚎");
+      return;
+    }
+    if (!bindForm.productCategoryId && !bindForm.productCategory) {
+      proxy.$modal.msgWarning("璇烽�夋嫨浜у搧澶х被");
+      return;
+    }
+    if (!bindForm.materialModel) {
+      proxy.$modal.msgWarning("璇烽�夋嫨鍘熸枡鍨嬪彿");
+      return;
+    }
+    if (isEmptyField(bindForm.basePaperQty)) {
+      proxy.$modal.msgWarning("璇峰~鍐欏師绾搁渶瑕侀噺");
+      return;
+    }
+    if (isEmptyField(bindForm.cartonQty)) {
+      proxy.$modal.msgWarning("璇峰~鍐欑焊绠遍渶瑕侀噺");
+      return;
+    }
+    if (isEmptyField(bindForm.plasticBagQty)) {
+      proxy.$modal.msgWarning("璇峰~鍐欏鏂欒鏁伴噺");
       return;
     }
     bindRouteSaving.value = true;
@@ -349,6 +590,17 @@
       await bindingRoute({
         id: bindForm.orderId,
         routeId: bindForm.routeId,
+        materialList: [
+          {
+            productCategoryId: bindForm.productCategoryId,
+            productCategory: bindForm.productCategory,
+            materialName: bindForm.productCategory,
+            materialModel: bindForm.materialModel,
+            basePaperQty: bindForm.basePaperQty,
+            cartonQty: bindForm.cartonQty,
+            plasticBagQty: bindForm.plasticBagQty,
+          },
+        ],
       });
       proxy.$modal.msgSuccess("缁戝畾鎴愬姛");
       bindRouteDialogVisible.value = false;
@@ -530,4 +782,18 @@
 	margin-top: unset;
 }
 
+.bind-route-table {
+  width: 100%;
+}
+
+.bind-route-table :deep(.el-table__header th) {
+  background: #f5f7fa;
+  font-weight: 600;
+}
+
+.bind-route-table :deep(.el-table td),
+.bind-route-table :deep(.el-table th) {
+  padding: 8px 0;
+}
+
 </style>
diff --git a/src/views/productionManagement/workOrderManagement/index.vue b/src/views/productionManagement/workOrderManagement/index.vue
index 48f8839..32fa471 100644
--- a/src/views/productionManagement/workOrderManagement/index.vue
+++ b/src/views/productionManagement/workOrderManagement/index.vue
@@ -271,7 +271,7 @@
     },
     {
       label: "鎿嶄綔",
-      width: "260",
+      width: "210",
       align: "center",
       dataType: "action",
       fixed: "right",
@@ -288,12 +288,12 @@
             openWorkOrderFiles(row);
           },
         },
-        {
-          name: "鐗╂枡",
-          clickFun: row => {
-            openMaterialDialog(row);
-          },
-        },
+        // {
+        //   name: "鐗╂枡",
+        //   clickFun: row => {
+        //     openMaterialDialog(row);
+        //   },
+        // },
         {
           name: "鎶ュ伐",
           clickFun: row => {

--
Gitblit v1.9.3