From 181002704e5df616539e6250f975fe7de783b6e2 Mon Sep 17 00:00:00 2001
From: buhuazhen <hua100783@gmail.com>
Date: 星期二, 12 五月 2026 17:56:40 +0800
Subject: [PATCH] feat(productionOrder): 新增修改工艺路线功能,优化绑定弹窗逻辑

---
 src/views/productionManagement/productionOrder/BindRouteDialog.vue |  174 ++++++++++++++++++++++++++++++++++---------
 src/views/productionManagement/productionOrder/index.vue           |   37 +++++++--
 2 files changed, 165 insertions(+), 46 deletions(-)

diff --git a/src/views/productionManagement/productionOrder/BindRouteDialog.vue b/src/views/productionManagement/productionOrder/BindRouteDialog.vue
index ea5574f..35ea376 100644
--- a/src/views/productionManagement/productionOrder/BindRouteDialog.vue
+++ b/src/views/productionManagement/productionOrder/BindRouteDialog.vue
@@ -62,7 +62,7 @@
         <el-table-column label="鏉愭枡鍚嶇О">
           <template #default="{ row, $index }">
             <el-tree-select
-                v-if="!isDetail"
+                v-if="props.type === 'add'"
                 v-model="row.productById"
                 placeholder="璇烽�夋嫨"
                 clearable
@@ -82,7 +82,7 @@
           </template>
           <template #default="{ row }">
             <el-select
-                v-if="!isDetail"
+                v-if="props.type === 'add'"
                 v-model="row.productModelId"
                 placeholder="璇烽�夋嫨瑙勬牸"
                 filterable
@@ -97,8 +97,7 @@
                   :value="item.id"
               />
             </el-select>
-            <el-text class="mx-1" v-else>Default</el-text>
-<!--            <span v-else>{{ row.model }}</span>-->
+            <span v-else>{{ row.model }}</span>
           </template>
         </el-table-column>
         <el-table-column label="鏁伴噺">
@@ -108,8 +107,9 @@
           </template>
         </el-table-column>
         <el-table-column label="璁¢噺鍗曚綅">
-          <template #default="{ row }">
-            <el-input v-model="row.unit" placeholder="璁¢噺鍗曚綅" :disabled="isDetail"/>
+          <template  #default="{ row }">
+            <el-input  v-if="props.type === 'add'" v-model="row.unit" placeholder="璁¢噺鍗曚綅" :disabled="isDetail"/>
+            <span v-else>{{ row.unit }}</span>
           </template>
         </el-table-column>
         <el-table-column label="鍗曚环">
@@ -461,6 +461,7 @@
 
 const filePreviewRef = ref()
 const formData = reactive({
+  id: null,
   productOrderList: null,
   salesLedgerId: null,
   productOrderId: null,
@@ -514,6 +515,8 @@
   ],
   materialInfo: [
     {
+      parentId: "",
+      productById: "",
       productId: "",
       name: "",
       productModelId: "",
@@ -562,6 +565,7 @@
 const cloneDeep = (val) => JSON.parse(JSON.stringify(val))
 
 const createDefaultFormData = () => ({
+  id: null,
   productOrderList: null,
   salesLedgerId: null,
   productOrderId: null,
@@ -615,6 +619,8 @@
   ],
   materialInfo: [
     {
+      parentId: "",
+      productById: "",
       productId: "",
       name: "",
       productModelId: "",
@@ -703,6 +709,7 @@
   }
 
   Object.keys(formData).forEach((key) => {
+    if (key === 'id') return
     if (source[key] !== undefined) {
       formData[key] = Array.isArray(source[key]) ? cloneDeep(source[key]) : source[key]
     }
@@ -721,6 +728,20 @@
         }))
   }
 
+  if (Array.isArray(formData.materialInfo)) {
+    formData.materialInfo = formData.materialInfo.map((m) => {
+      const parentId = m?.parentId ? String(m.parentId) : ""
+      const productById = m?.productById ? String(m.productById) : ""
+      const name = m?.name ?? ""
+      return {
+        ...m,
+        parentId,
+        productById: productById || parentId || "",
+        name: name || (parentId ? findProductLabelById(productOptions.value, parentId) : "")
+      }
+    })
+  }
+
   // 鍏煎 index.vue 閲屽父鐢ㄥ瓧娈靛悕涓庡脊绐楀瓧娈靛悕涓嶄竴鑷寸殑鎯呭喌
   if (source.productName === undefined && source.productCategory !== undefined) {
     formData.productName = source.productCategory
@@ -736,6 +757,16 @@
   }
   if (source.productOrderId === undefined && source.id !== undefined) {
     formData.productOrderId = source.id
+  }
+
+  // 缂栬緫/鏌ョ湅鏃堕渶瑕佹妸 productionProductInput 鐨� id 甯﹀洖鍘伙紙鍚庣 save 璧版洿鏂帮級
+  // 鍒楄〃琛岄噷涓�鑸槸 printId锛涜鎯呮帴鍙d竴鑸繑鍥� { id, productOrderId, ... }
+  if (source.printId !== undefined && source.printId !== null && source.printId !== '') {
+    formData.id = source.printId
+  } else if (source.productionProductInputId !== undefined && source.productionProductInputId !== null && source.productionProductInputId !== '') {
+    formData.id = source.productionProductInputId
+  } else if (source.productOrderId !== undefined && source.id !== undefined && source.id !== null && source.id !== '') {
+    formData.id = source.id
   }
 
   introductionLetterList.value = String(formData.introductionLetter || "")
@@ -767,6 +798,7 @@
     (val) => {
       mergeRowDataToForm(val)
       getProductOrder()
+      Promise.resolve().then(() => hydrateMaterialInfo())
     },
     {immediate: true, deep: true}
 )
@@ -793,14 +825,14 @@
 const convertProductOptions = (data) => {
   return data.map(item => ({
     label: item.label || item.productName || item.name || "",
-    value: item.id,
+    value: String(item.id ?? ""),
     children: item.children?.length ? convertProductOptions(item.children) : undefined
   }))
 }
 
 const findProductLabelById = (options, productId) => {
   for (const item of options) {
-    if (item.value === productId) {
+    if (String(item.value) === String(productId)) {
       return item.label
     }
     if (item.children?.length) {
@@ -813,10 +845,69 @@
   return ""
 }
 
+const normalizeId = (v) => {
+  if (v === 0 || v === "0") return "0"
+  if (v === null || v === undefined) return ""
+  const s = String(v)
+  return s === "null" || s === "undefined" ? "" : s
+}
+
+const materialModelOptionsCache = new Map()
+
+const normalizeModelOptions = (res) => {
+  return Array.isArray(res) ? res :
+      Array.isArray(res?.data) ? res.data :
+          Array.isArray(res?.rows) ? res.rows :
+              Array.isArray(res?.data?.records) ? res.data.records :
+                  []
+}
+
+const getModelOptionsByParentId = async (parentId) => {
+  const key = normalizeId(parentId)
+  if (!key) return []
+  if (materialModelOptionsCache.has(key)) return materialModelOptionsCache.get(key)
+  const res = await modelList({id: key})
+  const options = normalizeModelOptions(res)
+  materialModelOptionsCache.set(key, options)
+  return options
+}
+
+const hydrateMaterialInfo = async () => {
+  const rows = Array.isArray(formData.materialInfo) ? formData.materialInfo : []
+  await Promise.all(rows.map(async (row) => {
+    if (!row || typeof row !== 'object') return
+    const parentId = normalizeId(row.parentId || row.productById)
+    if (!parentId) return
+
+    row.parentId = parentId
+    row.productById = parentId
+    if (!row.name) {
+      row.name = findProductLabelById(productOptions.value, parentId)
+    }
+
+    if (!Array.isArray(row.modelOptions) || row.modelOptions.length === 0) {
+      row.modelOptions = await getModelOptionsByParentId(parentId)
+    }
+
+    const productModelId = normalizeId(row.productModelId)
+    if (productModelId && Array.isArray(row.modelOptions) && row.modelOptions.length) {
+      const currentModel = row.modelOptions.find(item => normalizeId(item?.id) === productModelId)
+      if (currentModel) {
+        row.model = currentModel?.model || row.model || ""
+        row.unit = currentModel?.unit || row.unit || ""
+        if (!row.productId) {
+          row.productId = currentModel?.id || ""
+        }
+      }
+    }
+  }))
+}
+
 const getMaterialProductOptions = () => {
   productTreeList().then(res => {
     const rawData = Array.isArray(res?.data) ? res.data : Array.isArray(res) ? res : []
     productOptions.value = convertProductOptions(rawData)
+    Promise.resolve().then(() => hydrateMaterialInfo())
   })
 }
 
@@ -848,26 +939,31 @@
 }
 
 const getModels = async (val, row, index) => {
-  const targetRow = formData.materialInfo[index]
-  row.productId = val || ""
-  row.productById = val || ""
-  row.name = val ? findProductLabelById(productOptions.value, val) : ""
+  const targetRow = formData.materialInfo[index] || {}
+  const parentId = val ? String(val) : ""
+  const name = parentId ? findProductLabelById(productOptions.value, parentId) : ""
 
-  row.productModelId = ""
-  row.model = ""
-  row.unit = ""
-  row.modelOptions = []
-
-  if (!val) return
-
-  const res = await modelList({id: val})
-  formData.materialInfo[index] = {
+  const baseRow = {
     ...targetRow,
-    modelOptions: Array.isArray(res) ? res :
-        Array.isArray(res?.data) ? res.data :
-            Array.isArray(res?.rows) ? res.rows :
-                Array.isArray(res?.data?.records) ? res.data.records :
-                    []
+    parentId,
+    productId: "",
+    productById: parentId,
+    name,
+    productModelId: "",
+    model: "",
+    unit: "",
+    modelOptions: []
+  }
+
+  formData.materialInfo[index] = baseRow
+
+  if (!parentId) return
+
+  const modelOptions = await getModelOptionsByParentId(parentId)
+
+  formData.materialInfo[index] = {
+    ...baseRow,
+    modelOptions
   }
   // row.modelOptions = Array.isArray(res) ? res :
   //     Array.isArray(res?.data) ? res.data :
@@ -889,6 +985,8 @@
 const addMaterialRow = () => {
   formData.materialInfo.push({
     id: Date.now().toString(),
+    parentId: "",
+    productById: "",
     productId: "",
     name: "",
     productModelId: "",
@@ -957,24 +1055,24 @@
   const materialRows = Array.isArray(formData.materialInfo) ? formData.materialInfo : []
   for (let i = 0; i < materialRows.length; i++) {
     const row = materialRows[i] || {}
-    if (!row.productId) {
+    if (!row.productModelId) {
       ElMessage.warning(`鏉愭枡淇℃伅绗�${i + 1}琛岋細	瑙勬牸蹇呭~`)
       return
     }
 
   }
   const rows = Array.isArray(formData.processContent) ? formData.processContent : []
-  for (let i = 0; i < rows.length; i++) {
-    const row = rows[i] || {}
-    if (!row.deviceId) {
-      ElMessage.warning(`宸ヨ壓鍔犲伐绗�${i + 1}琛岋細鏈哄彴蹇呭~`)
-      return
-    }
-    if (!Array.isArray(row.reportUserIds) || row.reportUserIds.length === 0) {
-      ElMessage.warning(`宸ヨ壓鍔犲伐绗�${i + 1}琛岋細鎶ュ伐浜哄繀濉玚)
-      return
-    }
-  }
+  // for (let i = 0; i < rows.length; i++) {
+  //   const row = rows[i] || {}
+  //   if (!row.deviceId) {
+  //     ElMessage.warning(`宸ヨ壓鍔犲伐绗�${i + 1}琛岋細鏈哄彴蹇呭~`)
+  //     return
+  //   }
+  //   if (!Array.isArray(row.reportUserIds) || row.reportUserIds.length === 0) {
+  //     ElMessage.warning(`宸ヨ壓鍔犲伐绗�${i + 1}琛岋細鎶ュ伐浜哄繀濉玚)
+  //     return
+  //   }
+  // }
   const payload = cloneDeep(formData)
   delete payload.productOrderList
   if (Array.isArray(payload.materialInfo)) {
diff --git a/src/views/productionManagement/productionOrder/index.vue b/src/views/productionManagement/productionOrder/index.vue
index 4470b7d..e1aeced 100644
--- a/src/views/productionManagement/productionOrder/index.vue
+++ b/src/views/productionManagement/productionOrder/index.vue
@@ -111,7 +111,11 @@
 const BindRouteDialogRef = ref(null)
 
 const handleBindRouteSubmit = async (data) => {
-  const res = await saveProductionProductInput(data)
+  const payload = { ...(data || {}) }
+  if (bindDialogType.value === "edit" && !payload.id) {
+    payload.id = rowData.value?.printId || rowData.value?.id || null
+  }
+  const res = await saveProductionProductInput(payload)
   if (res.code === 200) {
     proxy.$modal.msgSuccess("缁戝畾鎴愬姛");
     bindRouteDialogVisible.value = false
@@ -229,9 +233,17 @@
       {
         name: "鏌ョ湅宸ヨ壓璺嚎",
         type: "text",
-        showHide: row => row.printId,
+        showHide: row => row.printId && Number(row?.hasProduct) > 0,
         clickFun: row => {
           openBindRouteDialog(row, "view");
+        },
+      },
+      {
+        name: "淇敼宸ヨ壓璺嚎",
+        type: "text",
+        showHide: row => row.printId && !(Number(row?.hasProduct) > 0),
+        clickFun: row => {
+          openBindRouteDialog(row, "edit");
         },
       },
       {
@@ -324,15 +336,24 @@
   bindRouteLoading.value = true;
   try {
     BindRouteDialogRef.value?.resetForm?.()
-    if (type === "view") {
-      bindDialogType.value = "detail"
+    if (type === "view" || type === "edit") {
+      bindDialogType.value = type === "view" ? "detail" : "edit"
       const res = await viewGetByProductWordId(row.id)
-      if (res?.cuttingFileVo?.id == null) {
-        res.cuttingFileVo = []
+
+      const detail = res?.data || res || {}
+      if (detail?.cuttingFileVo?.id == null) {
+        detail.cuttingFileVo = []
       } else {
-        res.cuttingFileVo = [res.cuttingFileVo]
+        detail.cuttingFileVo = [detail.cuttingFileVo]
       }
-      rowData.value = res?.data || res
+
+      if (detail.productOrderId == null) {
+        detail.productOrderId = row.id
+      }
+      if (type === "edit" && (detail.id == null || detail.id === "") && row?.printId) {
+        detail.id = row.printId
+      }
+      rowData.value = detail
     } else {
       bindDialogType.value = "add"
       rowData.value = deepClone( row)

--
Gitblit v1.9.3