From 04687ca035e6fa517e88470aac7247812f85eb95 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期五, 17 四月 2026 17:09:29 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/dev_New' into dev_New

---
 src/views/productionManagement/productionOrder/components/MaterialLedgerDialog.vue |  109 +++++++++++++++++++++++++++++++++++++++++-------------
 1 files changed, 83 insertions(+), 26 deletions(-)

diff --git a/src/views/productionManagement/productionOrder/components/MaterialLedgerDialog.vue b/src/views/productionManagement/productionOrder/components/MaterialLedgerDialog.vue
index f9db112..9e1a852 100644
--- a/src/views/productionManagement/productionOrder/components/MaterialLedgerDialog.vue
+++ b/src/views/productionManagement/productionOrder/components/MaterialLedgerDialog.vue
@@ -7,21 +7,24 @@
       <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-model="row.processId"
+              v-else
+              v-model="row.processName"
               placeholder="璇烽�夋嫨宸ュ簭"
               clearable
               filterable
               style="width: 100%;"
-              @change="val => handleProcessChange(row, val)"
+              @change="val => handleProcessNameChange(row, val)"
             >
-              <el-option v-for="item in processOptions" :key="item.id" :label="item.name" :value="item.id" />
+              <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 }">
-            <el-button type="primary" link @click="openMaterialProductSelect(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>
@@ -33,7 +36,9 @@
         </el-table-column>
         <el-table-column label="闇�姹傛暟閲�" min-width="120">
           <template #default="{ row }">
+            <span v-if="row.bom === true">{{ row.requiredQty ?? "-" }}</span>
             <el-input-number
+              v-else
               v-model="row.requiredQty"
               :min="0"
               :precision="3"
@@ -62,8 +67,8 @@
           </template>
         </el-table-column>
         <el-table-column label="鎿嶄綔" width="90" fixed="right">
-          <template #default="{ $index }">
-            <el-button type="danger" link @click="handleDeleteMaterialRow($index)">鍒犻櫎</el-button>
+          <template #default="{ $index, row }">
+            <el-button v-if="row.bom !== true" type="danger" link @click="handleDeleteMaterialRow($index)">鍒犻櫎</el-button>
           </template>
         </el-table-column>
       </el-table>
@@ -79,15 +84,21 @@
       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 { processList } from "@/api/productionManagement/productionProcess.js";
-import { listMaterialPickingLedger, saveMaterialPickingLedger } from "@/api/productionManagement/productionOrder.js";
+import { findProductProcessRouteItemList } from "@/api/productionManagement/productProcessRoute.js";
+import {
+  listMaterialPickingDetail,
+  listMaterialPickingLedger,
+  saveMaterialPickingLedger,
+} from "@/api/productionManagement/productionOrder.js";
 
 const props = defineProps({
   modelValue: { type: Boolean, default: false },
@@ -112,7 +123,9 @@
   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 || "",
@@ -122,9 +135,23 @@
 });
 
 const getProcessOptions = async () => {
-  if (processOptions.value.length > 0) return;
-  const res = await processList({});
-  processOptions.value = res.data || [];
+  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 () => {
@@ -133,8 +160,19 @@
   materialTableData.value = [];
   await getProcessOptions();
   try {
-    const res = await listMaterialPickingLedger({ orderId: props.orderRow.id });
-    materialTableData.value = (res.data || []).map(item => createMaterialRow(item));
+    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;
   }
@@ -162,9 +200,9 @@
   materialTableData.value.splice(index, 1);
 };
 
-const handleProcessChange = (row, processId) => {
-  const process = processOptions.value.find(item => item.id === processId);
-  row.processName = process?.name || "";
+const handleProcessNameChange = (row, processName) => {
+  const process = processOptions.value.find(item => item.name === processName);
+  row.productProcessId = process?.id;
 };
 
 const handleRequiredQtyChange = (row, val) => {
@@ -186,37 +224,56 @@
   if (index < 0 || !materialTableData.value[index]) return;
   const product = products[0];
   const row = materialTableData.value[index];
-  row.materialModelId = product.id;
-  row.materialName = product.productName || "";
-  row.materialModel = product.model || "";
-  row.unit = product.unit || "";
+  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 false;
-  return !materialTableData.value.find(
+  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.processId ||
-      !item.materialModelId ||
+      !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 || !validateMaterialRows()) return;
+  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.processId,
+        processId: item.processName,
+        productProcessId: item.productProcessId,
         processName: item.processName,
+        bom: item.bom === true,
         materialModelId: item.materialModelId,
         materialName: item.materialName,
         materialModel: item.materialModel,

--
Gitblit v1.9.3