From 93d2a0bd19ffb1d86c6807a4d93d0eff580c14f1 Mon Sep 17 00:00:00 2001
From: zhangwencui <1064582902@qq.com>
Date: 星期六, 25 四月 2026 16:39:26 +0800
Subject: [PATCH] 生产计划和生产订单一些修改

---
 src/views/productionManagement/processRoute/processRouteItem/index.vue | 1130 ++++++++++++++++++++++++++++++++---------------------------
 1 files changed, 617 insertions(+), 513 deletions(-)

diff --git a/src/views/productionManagement/processRoute/processRouteItem/index.vue b/src/views/productionManagement/processRoute/processRouteItem/index.vue
index be7138d..44fef19 100644
--- a/src/views/productionManagement/processRoute/processRouteItem/index.vue
+++ b/src/views/productionManagement/processRoute/processRouteItem/index.vue
@@ -77,10 +77,10 @@
                        width="60"
                        type="index" />
       <el-table-column label="宸ュ簭鍚嶇О"
-                       prop="processId"
+                       prop="technologyOperationId"
                        width="200">
         <template #default="scope">
-          {{ getProcessName(scope.row.processId) || '-' }}
+          {{ scope.row.technologyOperationName || scope.row.operationName || '-' }}
         </template>
       </el-table-column>
       <el-table-column label="鍙傛暟鍒楄〃"
@@ -106,6 +106,13 @@
                        width="100">
         <template #default="scope">
           {{scope.row.isQuality ? "鏄�" : "鍚�"}}
+        </template>
+      </el-table-column>
+      <el-table-column label="鏄惁鐢熶骇"
+                       prop="isProduction"
+                       width="100">
+        <template #default="scope">
+          {{scope.row.isProduction ? "鏄�" : "鍚�"}}
         </template>
       </el-table-column>
       <el-table-column label="鎿嶄綔"
@@ -151,7 +158,7 @@
             <!-- 搴忓彿鍦嗗湀 -->
             <div class="card-header">
               <div class="card-number">{{ index + 1 }}</div>
-              <div class="card-process-name">{{ getProcessName(item.processId) || '-' }}</div>
+              <div class="card-process-name">{{ item.technologyOperationName || item.operationName || '-' }}</div>
             </div>
             <!-- 浜у搧淇℃伅 -->
             <div class="card-content">
@@ -166,6 +173,10 @@
                 <el-tag type="primary"
                         class="product-tag"
                         v-if="item.isQuality">璐ㄦ</el-tag>
+                <el-tag type="primary"
+                        class="product-tag"
+                        :style="item.isQuality?'margin-left:8px':''"
+                        v-if="item.isProduction">鐢熶骇</el-tag>
               </div>
               <div v-else
                    class="product-info empty">鏆傛棤浜у搧淇℃伅</div>
@@ -191,168 +202,163 @@
         </div>
       </div>
     </template>
-    <div class="section-BOM">
-      <div class="section-header">
-        <div class="section-title">BOM</div>
-        <div class="section-actions">
-          <el-button type="primary"
-                     @click="toggleBomEdit">
-            {{ bomDataValue.isEdit ? '鍙栨秷' : '缂栬緫' }}
-          </el-button>
-          <el-button v-if=" bomDataValue.isEdit"
-                     type="success"
-                     @click="saveBomChanges">淇濆瓨</el-button>
-        </div>
-      </div>
-      <div>
-        <!-- BOM琛ㄦ牸 -->
-        <el-table :data="bomTableData"
-                  border
-                  :preserve-expanded-content="false"
-                  :default-expand-all="true"
-                  style="width: 100%">
-          <el-table-column type="expand">
-            <template #default="props">
-              <el-form ref="bomFormRef"
-                       :model="bomDataValue">
-                <el-table :data="props.row.bomList"
-                          row-key="tempId"
-                          default-expand-all
-                          :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
-                          style="width: 100%">
-                  <el-table-column prop="productName"
-                                   label="浜у搧" />
-                  <el-table-column prop="model"
-                                   label="瑙勬牸">
-                    <template #default="{ row }">
-                      <el-form-item v-if="bomDataValue.isEdit"
-                                    :rules="[{ required: true, message: '璇烽�夋嫨瑙勬牸', trigger: ['blur','change'] }]"
-                                    style="margin: 0">
-                        <el-select v-model="row.model"
-                                   placeholder="璇烽�夋嫨瑙勬牸"
-                                   clearable
-                                   :disabled="!bomDataValue.isEdit"
-                                   style="width: 100%"
-                                   @visible-change="(v) => { if (v) openBomProductDialog(row.tempId) }">
-                          <el-option v-if="row.model"
-                                     :label="row.model"
-                                     :value="row.model" />
-                        </el-select>
-                      </el-form-item>
-                      <span v-else>{{ row.model }}</span>
-                    </template>
-                  </el-table-column>
-                  <el-table-column prop="processName"
-                                   label="娑堣�楀伐搴�">
-                    <template #default="{ row }">
-                      <el-form-item v-if="bomDataValue.isEdit"
-                                    :rules="[{ required: true, message: '璇烽�夋嫨娑堣�楀伐搴�', trigger: 'change' }]"
-                                    style="margin: 0">
-                        <el-select v-model="row.processId"
-                                   placeholder="璇烽�夋嫨"
-                                   filterable
-                                   clearable
-                                   :disabled="!bomDataValue.isEdit"
-                                   style="width: 100%">
-                          <el-option v-for="process in processOptions"
-                                     :key="process.id"
-                                     :label="process.name"
-                                     :value="process.id" />
-                        </el-select>
-                      </el-form-item>
-                      <span v-else>{{ row.processName }}</span>
-                    </template>
-                  </el-table-column>
-                  <el-table-column prop="unitQuantity"
-                                   label="鍗曚綅浜у嚭鎵�闇�鏁伴噺">
-                    <template #default="{ row }">
-                      <el-form-item v-if="bomDataValue.isEdit"
-                                    :rules="[{ required: true, message: '璇疯緭鍏ュ崟浣嶄骇鍑烘墍闇�鏁伴噺', trigger: ['blur','change'] }]"
-                                    style="margin: 0">
-                        <el-input-number v-model="row.unitQuantity"
-                                         :min="0"
-                                         :precision="2"
-                                         :step="1"
-                                         controls-position="right"
-                                         style="width: 100%"
-                                         :disabled="!bomDataValue.isEdit" />
-                      </el-form-item>
-                      <span v-else>{{ row.unitQuantity }}</span>
-                    </template>
-                  </el-table-column>
-                  <el-table-column v-if="pageType === 'order'"
-                                   prop="demandedQuantity"
-                                   label="闇�姹傛�婚噺">
-                    <template #default="{ row }">
-                      <el-form-item v-if="bomDataValue.isEdit"
-                                    :rules="[{ required: true, message: '璇疯緭鍏ラ渶姹傛�婚噺', trigger: ['blur','change'] }]"
-                                    style="margin: 0">
-                        <el-input-number v-model="row.demandedQuantity"
-                                         :min="0"
-                                         :precision="2"
-                                         :step="1"
-                                         controls-position="right"
-                                         style="width: 100%"
-                                         :disabled="!bomDataValue.isEdit" />
-                      </el-form-item>
-                      <span v-else>{{ row.demandedQuantity }}</span>
-                    </template>
-                  </el-table-column>
-                  <el-table-column prop="unit"
-                                   label="鍗曚綅">
-                    <template #default="{ row }">
-                      <el-form-item v-if="bomDataValue.isEdit"
-                                    :rules="[{ required: true, message: '璇疯緭鍏ュ崟浣�', trigger: ['blur','change'] }]"
-                                    style="margin: 0">
-                        <el-input v-model="row.unit"
-                                  placeholder="璇疯緭鍏ュ崟浣�"
-                                  clearable
-                                  :disabled="!bomDataValue.isEdit" />
-                      </el-form-item>
-                      <span v-else>{{ row.unit }}</span>
-                    </template>
-                  </el-table-column>
-                  <el-table-column label="鎿嶄綔"
-                                   fixed="right"
-                                   width="180">
-                    <template #default="{ row }">
-                      <el-button v-if="bomDataValue.isEdit"
-                                 type="danger"
-                                 text
-                                 size="small"
-                                 @click="removeBomItem(row.tempId)">鍒犻櫎</el-button>
-                      <el-button v-if="bomDataValue.isEdit"
-                                 type="primary"
-                                 text
-                                 size="small"
-                                 @click="addBomItem2(row.tempId)">娣诲姞瀛愰」</el-button>
-                    </template>
-                  </el-table-column>
-                </el-table>
-              </el-form>
-            </template>
-          </el-table-column>
-          <el-table-column label="BOM缂栧彿"
-                           prop="bomNo" />
-          <el-table-column label="浜у搧鍚嶇О"
-                           prop="productName" />
-          <el-table-column label="瑙勬牸鍨嬪彿"
-                           prop="model" />
-        </el-table>
-        <!-- <div v-if="bomDataValue.isEdit"
-             style="text-align: center;border: 1px solid #e4e7ed;padding: 10px;transition: all 0.3s ease;cursor: pointer;"
-             :class="{'hover-effect': bomDataValue.isEdit}">
-          <el-button type="primary"
-                     text
-                     @click="addBomItem">
-            <el-icon style="vertical-align: middle;margin-right: 5px;">
-              <Plus />
-            </el-icon>
-            娣诲姞
-          </el-button>
-        </div> -->
-      </div>
+    <!-- bom妯″潡 -->
+    <div class="section-header"
+         style="margin-top: 20px;">
+      <div class="section-title">BOM 缁撴瀯</div>
+      <!-- <div class="section-actions"
+           v-if="pageType === 'order'">
+        <el-button v-if="!bomDataValue.isEdit"
+                   type="primary"
+                   @click="bomDataValue.isEdit = true">
+          缂栬緫
+        </el-button>
+        <el-button v-if="bomDataValue.isEdit"
+                   @click="cancelEditBom">
+          鍙栨秷
+        </el-button>
+        <el-button v-if="bomDataValue.isEdit"
+                   type="primary"
+                   @click="handleSaveBom"
+                   :loading="bomDataValue.loading">
+          淇濆瓨BOM
+        </el-button>
+      </div> -->
     </div>
+    <el-table :data="bomTableData"
+              border
+              :preserve-expanded-content="false"
+              :default-expand-all="true"
+              style="width: 100%">
+      <el-table-column type="expand">
+        <template #default>
+          <el-form ref="bomFormRef"
+                   :model="bomDataValue">
+            <el-table :data="bomDataValue.dataList"
+                      row-key="tempId"
+                      default-expand-all
+                      :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
+                      style="width: 100%">
+              <el-table-column prop="productName"
+                               label="浜у搧" />
+              <el-table-column prop="model"
+                               label="瑙勬牸">
+                <template #default="{ row }">
+                  <el-form-item v-if="pageType === 'order' && bomDataValue.isEdit"
+                                :rules="[{ required: true, message: '璇烽�夋嫨瑙勬牸', trigger: ['blur','change'] }]"
+                                style="margin: 0">
+                    <el-select v-model="row.model"
+                               placeholder="璇烽�夋嫨瑙勬牸"
+                               clearable
+                               :disabled="!bomDataValue.isEdit || bomDataValue.dataList.some(item => (item).tempId === row.tempId)"
+                               style="width: 100%"
+                               @visible-change="(v) => { if (v) openBomDialog(row.tempId) }">
+                      <el-option v-if="row.model"
+                                 :label="row.model"
+                                 :value="row.model" />
+                    </el-select>
+                  </el-form-item>
+                </template>
+              </el-table-column>
+              <el-table-column prop="processName"
+                               label="娑堣�楀伐搴�">
+                <template #default="{ row }">
+                  <el-form-item v-if="pageType === 'order' && bomDataValue.isEdit"
+                                :rules="bomDataValue.dataList.some(item => (item).tempId === row.tempId) ? [] : [{ required: true, message: '璇烽�夋嫨娑堣�楀伐搴�', trigger: 'change' }]"
+                                style="margin: 0">
+                    <el-select v-model="row.processId"
+                               placeholder="璇烽�夋嫨"
+                               filterable
+                               clearable
+                               style="width: 100%"
+                               @change="value => handleBomProcessChange(row, value)"
+                               :disabled="!bomDataValue.isEdit || bomDataValue.dataList.some(item => (item).tempId === row.tempId)">
+                      <el-option v-for="item in bomDataValue.processOptions"
+                                 :key="item.id"
+                                 :label="item.name"
+                                 :value="item.id" />
+                    </el-select>
+                  </el-form-item>
+                </template>
+              </el-table-column>
+              <el-table-column prop="unitQuantity"
+                               label="鍗曚綅浜у嚭鎵�闇�鏁伴噺">
+                <template #default="{ row }">
+                  <el-form-item v-if="pageType === 'order' && bomDataValue.isEdit"
+                                :rules="[{ required: true, message: '璇疯緭鍏ュ崟浣嶄骇鍑烘墍闇�鏁伴噺', trigger: ['blur','change'] }]"
+                                style="margin: 0">
+                    <el-input-number v-model="row.unitQuantity"
+                                     :min="0"
+                                     :precision="2"
+                                     :step="1"
+                                     controls-position="right"
+                                     style="width: 100%"
+                                     :disabled="!bomDataValue.isEdit || bomDataValue.dataList.some(item => (item).tempId === row.tempId)" />
+                  </el-form-item>
+                </template>
+              </el-table-column>
+              <el-table-column v-if="pageType === 'order'"
+                               prop="demandedQuantity"
+                               label="闇�姹傛�婚噺">
+                <template #default="{ row }">
+                  <el-form-item v-if="pageType === 'order' && bomDataValue.isEdit"
+                                :rules="[{ required: true, message: '璇疯緭鍏ラ渶姹傛�婚噺', trigger: ['blur','change'] }]"
+                                style="margin: 0">
+                    <el-input-number v-model="row.demandedQuantity"
+                                     :min="0"
+                                     :precision="2"
+                                     :step="1"
+                                     controls-position="right"
+                                     style="width: 100%"
+                                     :disabled="!bomDataValue.isEdit || bomDataValue.dataList.some(item => (item).tempId === row.tempId)" />
+                  </el-form-item>
+                </template>
+              </el-table-column>
+              <el-table-column prop="unit"
+                               label="鍗曚綅">
+                <template #default="{ row }">
+                  <el-form-item v-if="pageType === 'order' && bomDataValue.isEdit"
+                                :rules="[{ required: true, message: '璇疯緭鍏ュ崟浣�', trigger: ['blur','change'] }]"
+                                style="margin: 0">
+                    <el-input v-model="row.unit"
+                              placeholder="璇疯緭鍏ュ崟浣�"
+                              clearable
+                              :disabled="!bomDataValue.isEdit || bomDataValue.dataList.some(item => (item).tempId === row.tempId)" />
+                  </el-form-item>
+                </template>
+              </el-table-column>
+              <el-table-column label="鎿嶄綔"
+                               fixed="right"
+                               width="200"
+                               v-if="pageType === 'order' && bomDataValue.isEdit">
+                <template #default="{ row }">
+                  <el-button v-if="bomDataValue.isEdit && !bomDataValue.dataList.some(item => (item).tempId === row.tempId)"
+                             type="danger"
+                             text
+                             @click="removeBomItem(row.tempId)">鍒犻櫎
+                  </el-button>
+                  <el-button v-if="bomDataValue.isEdit"
+                             type="primary"
+                             text
+                             @click="addBomItem(row.tempId)">娣诲姞
+                  </el-button>
+                </template>
+              </el-table-column>
+            </el-table>
+          </el-form>
+        </template>
+      </el-table-column>
+      <el-table-column label="BOM缂栧彿"
+                       prop="bomNo" />
+      <el-table-column label="浜у搧鍚嶇О"
+                       prop="productName" />
+      <el-table-column label="瑙勬牸鍨嬪彿"
+                       prop="model" />
+    </el-table>
+    <ProductSelectDialog v-if="bomDataValue.showProductDialog"
+                         v-model="bomDataValue.showProductDialog"
+                         :single="true"
+                         @confirm="handleBomProduct" />
     <!-- 鏂板/缂栬緫寮圭獥 -->
     <el-dialog v-model="dialogVisible"
                :title="operationType === 'add' ? '鏂板宸ヨ壓璺嚎椤圭洰' : '缂栬緫宸ヨ壓璺嚎椤圭洰'"
@@ -363,10 +369,12 @@
                :rules="rules"
                label-width="120px">
         <el-form-item label="宸ュ簭"
-                      prop="processId">
-          <el-select v-model="form.processId"
+                      v-if="operationType === 'add' || pageType === 'route'"
+                      prop="technologyOperationId">
+          <el-select v-model="form.technologyOperationId"
                      placeholder="璇烽�夋嫨宸ュ簭"
                      clearable
+                     @change="processChange"
                      style="width: 100%">
             <el-option v-for="process in processOptions"
                        :key="process.id"
@@ -374,27 +382,47 @@
                        :value="process.id" />
           </el-select>
         </el-form-item>
+        <el-form-item label="宸ュ簭"
+                      v-else>
+          <span>{{ getProcessName(form.technologyOperationId) }}</span>
+        </el-form-item>
         <el-form-item label="浜у搧鍚嶇О"
+                      v-if="operationType === 'add' || pageType === 'route'"
                       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>
+        <el-form-item label="浜у搧鍚嶇О"
+                      v-else>
+          <span>{{ form.productName }}{{ form.model ? ' - ' + form.model : '' }}</span>
+        </el-form-item>
         <el-form-item label="鍗曚綅"
+                      v-if="operationType === 'add' || pageType === 'route'"
                       prop="unit">
           <el-input v-model="form.unit"
                     :placeholder="form.productModelId ? '鏍规嵁閫夋嫨鐨勪骇鍝佽嚜鍔ㄥ甫鍑�' : '璇峰厛閫夋嫨浜у搧'"
                     clearable
                     :disabled="true" />
         </el-form-item>
+        <el-form-item label="鍗曚綅"
+                      v-else>
+          <span>{{ form.unit }}</span>
+        </el-form-item>
         <el-form-item label="鏄惁璐ㄦ"
                       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" />
         </el-form-item>
       </el-form>
       <template #footer>
@@ -408,19 +436,16 @@
     <ProductSelectDialog v-model="showProductSelectDialog"
                          @confirm="handleProductSelect"
                          single />
-    <!-- BOM浜у搧閫夋嫨瀵硅瘽妗� -->
-    <ProductSelectDialog v-model="bomDataValue.showProductDialog"
-                         @confirm="handleBomProductSelect"
-                         single />
     <!-- 鍙傛暟鍒楄〃瀵硅瘽妗� -->
     <!-- :editable="!routeInfo.status" -->
     <ProcessParamListDialog v-model="showParamListDialog"
-                            :title="`${currentProcess ? (currentProcess.processName || getProcessName(currentProcess.processId)) : ''} - 鍙傛暟鍒楄〃`"
+                            :title="`${currentProcess ? (currentProcess.processName || currentProcess.technologyOperationName || currentProcess.operationName) : ''} - 鍙傛暟鍒楄〃`"
                             :route-id="routeId"
                             :order-id="orderId"
                             :process="currentProcess"
                             :page-type="pageType"
                             :param-list="paramList"
+                            @getsyncProcessParamItem="getsyncProcessParamItem"
                             @refresh="refreshParamList" />
   </div>
 </template>
@@ -439,9 +464,14 @@
   import {
     findProcessRouteItemList,
     addOrUpdateProcessRouteItem,
+    addOrUpdateProcessRouteItem1,
     sortProcessRouteItem,
     batchDeleteProcessRouteItem,
     getProcessParamList,
+  } from "@/api/productionManagement/processRouteItem.js";
+  import {
+    syncProcessParamItem,
+    syncProcessParamItemOrder,
   } from "@/api/productionManagement/processRouteItem.js";
   import {
     findProductProcessRouteItemList,
@@ -452,11 +482,13 @@
     sortRouteItem,
   } from "@/api/productionManagement/productProcessRoute.js";
   import { processList } from "@/api/productionManagement/productionProcess.js";
+  import { listProcessBom } from "@/api/productionManagement/productionOrder.js";
   import {
-    queryList2,
     queryList,
-    add2,
+    queryList2,
+    addBomDetail,
   } from "@/api/productionManagement/productStructure.js";
+
   import { useRoute } from "vue-router";
   import { ElMessageBox, ElMessage } from "element-plus";
   import Sortable from "sortablejs";
@@ -473,6 +505,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);
@@ -490,15 +523,6 @@
   const showParamListDialog = ref(false);
   const currentProcess = ref(null);
   const paramList = ref([]);
-  const bomTableData = ref([]);
-  const bomFormRef = ref(null);
-  const bomDataValue = ref({
-    dataList: [],
-    showProductDialog: false,
-    currentRowName: null,
-    loading: false,
-    isEdit: false,
-  });
   let tableSortable = null;
   let cardSortable = null;
 
@@ -514,25 +538,66 @@
   const form = ref({
     id: undefined,
     routeId: routeId.value,
-    processId: undefined,
+    technologyOperationId: undefined,
     productModelId: undefined,
     productName: "",
     model: "",
     unit: "",
     isQuality: false,
+    isProduction: false,
   });
 
   const rules = {
-    processId: [{ required: true, message: "璇烽�夋嫨宸ュ簭", trigger: "change" }],
+    technologyOperationId: [
+      { required: true, message: "璇烽�夋嫨宸ュ簭", trigger: "change" },
+    ],
     productModelId: [
       { required: true, message: "璇烽�夋嫨浜у搧", trigger: "change" },
     ],
   };
 
+  const getsyncProcessParamItem = () => {
+    ElMessageBox.confirm("鏄惁瑕嗙洊褰撳墠宸ュ簭宸插瓨鍦ㄥ弬鏁帮紵", "鎻愮ず", {
+      confirmButtonText: "纭畾",
+      cancelButtonText: "鍙栨秷",
+      type: "warning",
+    })
+      .then(() => {
+        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(() => {});
+  };
+
   // 鏍规嵁宸ュ簭ID鑾峰彇宸ュ簭鍚嶇О
-  const getProcessName = processId => {
-    if (!processId) return "";
-    const process = processOptions.value.find(p => p.id === processId);
+  const getProcessName = technologyOperationId => {
+    if (!technologyOperationId) return "";
+    const process = processOptions.value.find(
+      p => p.id === technologyOperationId
+    );
     return process ? process.name : "";
   };
 
@@ -562,9 +627,10 @@
 
   // 鑾峰彇宸ュ簭鍒楄〃
   const getProcessList = () => {
-    processList({})
+    processList({ size: -1, current: -1 })
       .then(res => {
-        processOptions.value = res.data || [];
+        processOptions.value = res.data.records || [];
+        bomDataValue.value.processOptions = processOptions.value;
       })
       .catch(err => {
         console.error("鑾峰彇宸ュ簭澶辫触锛�", err);
@@ -578,76 +644,13 @@
       productName: route.query.productName || "",
       model: route.query.model || "",
       bomNo: route.query.bomNo || "",
+      bomId: route.query.bomId || "",
       description: route.query.description || "",
       status: !(route.query.status == 1 || route.query.status === "false"),
     };
-    if (pageType.value === "order") {
-      queryList2(route.query.orderId)
-        .then(res => {
-          if (res.data) {
-            // 涓築OM鏁版嵁璁剧疆tempId
-            const setTempIdRecursively = items => {
-              items.forEach(item => {
-                item.tempId = item.id || new Date().getTime();
-                if (item.children && item.children.length > 0) {
-                  setTempIdRecursively(item.children);
-                }
-              });
-            };
-            setTempIdRecursively(res.data);
-
-            bomTableData.value = [
-              {
-                bomNo: routeInfo.value.bomNo,
-                dictLabel: routeInfo.value.dictLabel,
-                productCode: "",
-                productName: routeInfo.value.productName,
-                model: routeInfo.value.model,
-                bomList: res.data,
-              },
-            ];
-
-            // 淇濆瓨鍘熷BOM鏁版嵁
-            bomDataValue.value.dataList = res.data;
-          }
-        })
-        .catch(err => {
-          console.error("鑾峰彇BOM鏁版嵁澶辫触锛�", err);
-        });
-    } else {
-      queryList(Number(route.query.bomId))
-        .then(res => {
-          if (res.data) {
-            // 涓築OM鏁版嵁璁剧疆tempId
-            const setTempIdRecursively = items => {
-              items.forEach(item => {
-                item.tempId = item.id || new Date().getTime();
-                if (item.children && item.children.length > 0) {
-                  setTempIdRecursively(item.children);
-                }
-              });
-            };
-            setTempIdRecursively(res.data);
-
-            bomTableData.value = [
-              {
-                bomNo: routeInfo.value.bomNo,
-                dictLabel: routeInfo.value.dictLabel,
-                productCode: "",
-                productName: routeInfo.value.productName,
-                model: routeInfo.value.model,
-                bomList: res.data,
-              },
-            ];
-
-            // 淇濆瓨鍘熷BOM鏁版嵁
-            bomDataValue.value.dataList = res.data;
-          }
-        })
-        .catch(err => {
-          console.error("鑾峰彇BOM鏁版嵁澶辫触锛�", err);
-        });
-    }
+    bomTableData.value[0].productName = routeInfo.value.productName;
+    bomTableData.value[0].model = routeInfo.value.model;
+    bomTableData.value[0].bomNo = routeInfo.value.bomNo;
   };
 
   // 鏂板
@@ -663,12 +666,13 @@
     form.value = {
       id: row.id,
       routeId: routeId.value,
-      processId: row.processId,
+      technologyOperationId: row.technologyOperationId,
       productModelId: row.productModelId,
       productName: row.productName || "",
       model: row.model || "",
       unit: row.unit || "",
       isQuality: row.isQuality,
+      isProduction: row.isProduction,
     };
     dialogVisible.value = true;
   };
@@ -701,15 +705,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");
     }
   };
 
@@ -727,18 +736,22 @@
 
           const addPromise = isOrderPage
             ? addRouteItem({
-                productOrderId: orderId.value,
-                productRouteId: routeId.value,
-                processId: form.value.processId,
+                productionOrderId: Number(orderId.value),
+                orderRoutingId: Number(routeId.value),
+                technologyOperationId: form.value.technologyOperationId,
+                technologyRoutingId: Number(routeId.value),
+                operationName: getProcessName(form.value.technologyOperationId),
                 productModelId: form.value.productModelId,
                 isQuality: form.value.isQuality,
+                isProduction: form.value.isProduction,
                 dragSort,
               })
             : addOrUpdateProcessRouteItem({
-                routeId: routeId.value,
-                processId: form.value.processId,
+                technologyRoutingId: Number(routeId.value),
+                technologyOperationId: form.value.technologyOperationId,
                 productModelId: form.value.productModelId,
                 isQuality: form.value.isQuality,
+                isProduction: form.value.isProduction,
                 dragSort,
               });
 
@@ -761,16 +774,19 @@
           const updatePromise = isOrderPage
             ? addOrUpdateProductProcessRouteItem({
                 id: form.value.id,
-                processId: form.value.processId,
+                technologyOperationId: form.value.technologyOperationId,
+                operationName: getProcessName(form.value.technologyOperationId),
                 productModelId: form.value.productModelId,
                 isQuality: form.value.isQuality,
+                isProduction: form.value.isProduction,
               })
-            : addOrUpdateProcessRouteItem({
-                routeId: routeId.value,
-                processId: form.value.processId,
+            : addOrUpdateProcessRouteItem1({
+                technologyRoutingId: Number(routeId.value),
+                technologyOperationId: form.value.technologyOperationId,
                 productModelId: form.value.productModelId,
                 id: form.value.id,
                 isQuality: form.value.isQuality,
+                isProduction: form.value.isProduction,
               });
 
           updatePromise
@@ -795,11 +811,13 @@
     form.value = {
       id: undefined,
       routeId: routeId.value,
-      processId: undefined,
+      technologyOperationId: undefined,
       productModelId: undefined,
       productName: "",
       model: "",
       unit: "",
+      isQuality: false,
+      isProduction: false,
     };
     formRef.value?.resetFields();
   };
@@ -814,8 +832,8 @@
   const handleViewParams = row => {
     currentProcess.value = row;
     const query = {
-      routeItemId: row.id,
-      orderId: orderId.value,
+      technologyRoutingOperationId: row.id,
+      productionOrderId: orderId.value,
     };
 
     const apiPromise =
@@ -839,231 +857,6 @@
     if (currentProcess.value) {
       handleViewParams(currentProcess.value);
     }
-  };
-
-  // BOM鐩稿叧鏂规硶
-  // 鍒囨崲BOM缂栬緫妯″紡
-  const toggleBomEdit = () => {
-    bomDataValue.value.isEdit = !bomDataValue.value.isEdit;
-    if (!bomDataValue.value.isEdit) {
-      // 鍙栨秷缂栬緫鏃堕噸鏂板姞杞芥暟鎹�
-      getRouteInfo();
-    }
-  };
-
-  // 娣诲姞BOM椤�
-  const addBomItem = () => {
-    if (bomTableData.value.length > 0) {
-      const newItem = {
-        parentId: "",
-        parentTempId: "",
-        productName: "",
-        productId: "",
-        model: undefined,
-        productModelId: undefined,
-        processId: "",
-        processName: "",
-        unitQuantity: 0,
-        demandedQuantity: 0,
-        unit: "",
-        children: [],
-        tempId: new Date().getTime(),
-      };
-      bomTableData.value[0].bomList.push(newItem);
-    }
-  };
-
-  // 娣诲姞BOM瀛愰」
-  const addBomItem2 = tempId => {
-    const addChildItem = (items, tempId) => {
-      for (let i = 0; i < items.length; i++) {
-        const item = items[i];
-        if (item.tempId === tempId) {
-          if (!item.children) {
-            item.children = [];
-          }
-          item.children.push({
-            parentId: item.id || "",
-            parentTempId: item.tempId || "",
-            productName: "",
-            productId: "",
-            model: undefined,
-            productModelId: undefined,
-            processId: "",
-            processName: "",
-            unitQuantity: 0,
-            demandedQuantity: 0,
-            unit: "",
-            children: [],
-            tempId: new Date().getTime(),
-          });
-          return true;
-        }
-        if (item.children && item.children.length > 0) {
-          if (addChildItem(item.children, tempId)) {
-            return true;
-          }
-        }
-      }
-      return false;
-    };
-
-    if (bomTableData.value.length > 0) {
-      addChildItem(bomTableData.value[0].bomList, tempId);
-    }
-  };
-
-  // 鍒犻櫎BOM椤�
-  const removeBomItem = tempId => {
-    if (bomTableData.value.length > 0) {
-      const removeFromList = (items, tempId) => {
-        for (let i = 0; i < items.length; i++) {
-          const item = items[i];
-          if (item.tempId === tempId) {
-            items.splice(i, 1);
-            return true;
-          }
-          if (item.children && item.children.length > 0) {
-            if (removeFromList(item.children, tempId)) {
-              return true;
-            }
-          }
-        }
-        return false;
-      };
-      removeFromList(bomTableData.value[0].bomList, tempId);
-    }
-  };
-
-  // 鎵撳紑BOM浜у搧閫夋嫨瀵硅瘽妗�
-  const openBomProductDialog = tempId => {
-    bomDataValue.value.currentRowName = tempId;
-    bomDataValue.value.showProductDialog = true;
-  };
-
-  // 澶勭悊BOM浜у搧閫夋嫨
-  const handleBomProductSelect = products => {
-    if (products && products.length > 0) {
-      const product = products[0];
-      const updateProductInfo = (items, tempId, productData) => {
-        for (let i = 0; i < items.length; i++) {
-          const item = items[i];
-          if (item.tempId === tempId) {
-            item.productName = productData.productName;
-            item.model = productData.model;
-            item.productModelId = productData.id;
-            item.unit = productData.unit || "";
-            return true;
-          }
-          if (item.children && item.children.length > 0) {
-            if (updateProductInfo(item.children, tempId, productData)) {
-              return true;
-            }
-          }
-        }
-        return false;
-      };
-
-      if (bomTableData.value.length > 0) {
-        updateProductInfo(
-          bomTableData.value[0].bomList,
-          bomDataValue.value.currentRowName,
-          product
-        );
-      }
-      bomDataValue.value.showProductDialog = false;
-    }
-  };
-
-  // 淇濆瓨BOM鏇存敼
-  const saveBomChanges = () => {
-    const validateBomData = (items, isTopLevel = false) => {
-      for (let i = 0; i < items.length; i++) {
-        const item = items[i];
-        if (!item.productModelId) {
-          ElMessage.error("璇烽�夋嫨浜у搧");
-          return false;
-        }
-        if (!isTopLevel && !item.processId) {
-          ElMessage.error("璇烽�夋嫨娑堣�楀伐搴�");
-          return false;
-        }
-        if (
-          item.unitQuantity === undefined ||
-          item.unitQuantity === null ||
-          item.unitQuantity === 0
-        ) {
-          ElMessage.error("璇峰~鍐欏崟浣嶄骇鍑烘墍闇�鏁伴噺");
-          return false;
-        }
-        if (
-          pageType.value === "order" &&
-          (item.demandedQuantity === undefined ||
-            item.demandedQuantity === null ||
-            item.demandedQuantity === 0)
-        ) {
-          ElMessage.error("璇疯緭鍏ラ渶姹傛�婚噺");
-          return false;
-        }
-        if (item.children && item.children.length > 0) {
-          if (!validateBomData(item.children, false)) {
-            return false;
-          }
-        }
-      }
-      return true;
-    };
-
-    if (bomTableData.value.length > 0) {
-      if (!validateBomData(bomTableData.value[0].bomList, true)) {
-        return;
-      }
-    }
-
-    const processBomItem = (item, parentId = null, parentTempId = null) => {
-      const cleanItem = {
-        id: item.id || null,
-        orderId: Number(orderId.value) || null,
-        parentId: parentId,
-        parentTempId: parentTempId || null,
-        productModelId: item.productModelId || null,
-        processId: item.processId || null,
-        unitQuantity: item.unitQuantity || 0,
-        demandedQuantity: item.demandedQuantity || 0,
-        unit: item.unit || "",
-        tempId: item.tempId || new Date().getTime(),
-        bomId: Number(route.query.bomId) || null,
-        children: [],
-      };
-
-      if (item.children && item.children.length > 0) {
-        cleanItem.children = item.children.map(child =>
-          processBomItem(child, item.id, item.tempId)
-        );
-      }
-
-      return cleanItem;
-    };
-
-    const saveData = {
-      orderId: Number(orderId.value),
-      bomId: Number(route.query.bomId),
-      children: bomTableData.value[0].bomList.map(item => processBomItem(item)),
-    };
-
-    const savePromise =
-      pageType.value === "order" ? add2(saveData) : add(saveData);
-
-    savePromise
-      .then(() => {
-        proxy?.$modal?.msgSuccess("淇濆瓨鎴愬姛");
-        bomDataValue.value.isEdit = false;
-        getRouteInfo();
-      })
-      .catch(err => {
-        console.error("淇濆瓨BOM澶辫触锛�", err);
-        proxy?.$modal?.msgError("淇濆瓨澶辫触");
-      });
   };
 
   // 鍒濆鍖栨嫋鎷芥帓搴�
@@ -1201,10 +994,332 @@
     }
   };
 
+  // BOM鐩稿叧鐘舵�佸拰鏂规硶
+  const bomTableData = ref([
+    {
+      productName: "",
+      model: "",
+      bomNo: "",
+    },
+  ]);
+
+  const bomDataValue = ref({
+    dataList: [],
+    processOptions: [],
+    showProductDialog: false,
+    currentRowName: null,
+    loading: false,
+    isEdit: false,
+  });
+
+  const syncProcessOperationFields = item => {
+    const processId =
+      item.processId ?? item.operationId ?? item.technologyOperationId ?? "";
+    if (!processId) {
+      item.processId = "";
+      return;
+    }
+    const option = bomDataValue.value.processOptions.find(
+      p => p.id === processId
+    );
+    const processName =
+      option?.name || item.processName || item.operationName || "";
+
+    item.processId = processId;
+    if (pageType.value === "order") {
+      item.technologyOperationId = processId;
+    } else {
+      item.operationId = processId;
+    }
+    item.processName = processName;
+    item.operationName = processName;
+  };
+
+  const normalizeTreeData = items => {
+    items.forEach(item => {
+      item.tempId = item.tempId || item.id || `${Date.now()}_${Math.random()}`;
+      syncProcessOperationFields(item);
+      if (Array.isArray(item.children) && item.children.length > 0) {
+        normalizeTreeData(item.children);
+      }
+    });
+  };
+  const processChange = value => {
+    processOptions.value.forEach(item => {
+      if (item.id == value) {
+        form.value.isQuality = item.isQuality;
+        form.value.isProduction = item.isProduction;
+      }
+    });
+  };
+
+  const handleBomProcessChange = (row, value) => {
+    row.processId = value || "";
+    syncProcessOperationFields(row);
+  };
+
+  const openBomDialog = tempId => {
+    bomDataValue.value.currentRowName = tempId;
+    bomDataValue.value.showProductDialog = true;
+  };
+
+  const fetchBomData = async () => {
+    try {
+      const isOrderPage = pageType.value === "order";
+      const { data } = await (isOrderPage ? queryList2 : queryList)(
+        routeInfo.value.bomId
+      );
+      bomDataValue.value.dataList = data || [];
+      normalizeTreeData(bomDataValue.value.dataList);
+    } catch (err) {
+      console.error("鑾峰彇BOM鏁版嵁澶辫触锛�", err);
+    }
+  };
+
+  const childItem = (item, tempId, productData) => {
+    if (item.tempId === tempId) {
+      item.productName = productData.productName;
+      item.model = productData.model;
+      item.productModelId = productData.id;
+      item.unit = productData.unit || "";
+      return true;
+    }
+    if (item.children && item.children.length > 0) {
+      for (let child of item.children) {
+        if (childItem(child, tempId, productData)) {
+          return true;
+        }
+      }
+    }
+    return false;
+  };
+
+  const handleBomProduct = row => {
+    if (!Array.isArray(row) || row.length === 0) {
+      ElMessage.warning("璇烽�夋嫨涓�涓骇鍝�");
+      return;
+    }
+    const productData = row[row.length - 1];
+
+    const isTopLevel = bomDataValue.value.dataList.some(
+      item => item.tempId === bomDataValue.value.currentRowName
+    );
+    if (isTopLevel) {
+      if (
+        productData.productName === bomTableData.value[0].productName &&
+        productData.model === bomTableData.value[0].model
+      ) {
+        const hasOther = bomDataValue.value.dataList.some(
+          item =>
+            item.tempId !== bomDataValue.value.currentRowName &&
+            item.productName === bomTableData.value[0].productName &&
+            item.model === bomTableData.value[0].model
+        );
+        if (hasOther) {
+          ElMessage.warning("鏈�澶栧眰鍜屽綋鍓嶄骇鍝佷竴鏍风殑涓�绾у彧鑳芥湁涓�涓�");
+          return;
+        }
+      }
+    }
+    bomDataValue.value.dataList.forEach(item => {
+      if (item.tempId === bomDataValue.value.currentRowName) {
+        item.productName = productData.productName;
+        item.model = productData.model;
+        item.productModelId = productData.id;
+        item.unit = productData.unit || "";
+        return;
+      }
+      childItem(item, bomDataValue.value.currentRowName, productData);
+    });
+    bomDataValue.value.showProductDialog = false;
+  };
+
+  const removeBomItem = tempId => {
+    const topIndex = bomDataValue.value.dataList.findIndex(
+      item => item.tempId === tempId
+    );
+    if (topIndex !== -1) {
+      bomDataValue.value.dataList.splice(topIndex, 1);
+      return;
+    }
+
+    const delchildItem = (items, tempId) => {
+      for (let i = 0; i < items.length; i++) {
+        const item = items[i];
+        if (item.tempId === tempId) {
+          items.splice(i, 1);
+          return true;
+        }
+        if (item.children && item.children.length > 0) {
+          if (delchildItem(item.children, tempId)) {
+            return true;
+          }
+        }
+      }
+      return false;
+    };
+
+    bomDataValue.value.dataList.forEach(item => {
+      if (item.children && item.children.length > 0) {
+        delchildItem(item.children, tempId);
+      }
+    });
+  };
+
+  const addchildItem = (item, tempId) => {
+    if (item.tempId === tempId) {
+      if (!item.children) {
+        item.children = [];
+      }
+      item.children.push({
+        parentId: item.id || "",
+        parentTempId: item.tempId || "",
+        productName: "",
+        productId: "",
+        model: undefined,
+        productModelId: undefined,
+        processId: "",
+        processName: "",
+        [pageType.value === "order" ? "technologyOperationId" : "operationId"]:
+          "",
+        operationName: "",
+        unitQuantity: 1,
+        demandedQuantity: 0,
+        children: [],
+        unit: "",
+        tempId: new Date().getTime(),
+      });
+      return true;
+    }
+    if (item.children && item.children.length > 0) {
+      for (let child of item.children) {
+        if (addchildItem(child, tempId)) {
+          return true;
+        }
+      }
+    }
+    return false;
+  };
+
+  const addBomItem = tempId => {
+    bomDataValue.value.dataList.forEach(item => {
+      if (item.tempId === tempId) {
+        if (!item.children) {
+          item.children = [];
+        }
+        item.children.push({
+          parentId: item.id || "",
+          parentTempId: item.tempId || "",
+          productName: "",
+          productId: "",
+          model: undefined,
+          productModelId: undefined,
+          processId: "",
+          processName: "",
+          [pageType.value === "order" ? "technologyOperationId" : "operationId"]:
+            "",
+          operationName: "",
+          unitQuantity: 1,
+          demandedQuantity: 0,
+          unit: "",
+          children: [],
+          tempId: new Date().getTime(),
+        });
+        return;
+      }
+      addchildItem(item, tempId);
+    });
+  };
+
+  const validateAllBom = () => {
+    let isValid = true;
+    const isOrderPage = pageType.value === "order";
+
+    const validateItem = (item, isTopLevel = false) => {
+      if (!item.model) {
+        ElMessage.error("璇烽�夋嫨瑙勬牸");
+        isValid = false;
+        return;
+      }
+      if (!isTopLevel && !item.processId) {
+        ElMessage.error("璇烽�夋嫨娑堣�楀伐搴�");
+        isValid = false;
+        return;
+      }
+      if (!item.unitQuantity) {
+        ElMessage.error("璇疯緭鍏ュ崟浣嶄骇鍑烘墍闇�鏁伴噺");
+        isValid = false;
+        return;
+      }
+      if (isOrderPage && !item.demandedQuantity) {
+        ElMessage.error("璇疯緭鍏ラ渶姹傛�婚噺");
+        isValid = false;
+        return;
+      }
+
+      if (item.children && item.children.length > 0) {
+        item.children.forEach(child => {
+          validateItem(child, false);
+        });
+      }
+    };
+
+    bomDataValue.value.dataList.forEach(item => {
+      validateItem(item, true);
+    });
+
+    return isValid;
+  };
+
+  const buildSubmitTree = items => {
+    return items.map(item => {
+      const current = { ...item };
+      syncProcessOperationFields(current);
+      current.children = Array.isArray(current.children)
+        ? buildSubmitTree(current.children)
+        : [];
+      return current;
+    });
+  };
+
+  const cancelEditBom = () => {
+    bomDataValue.value.isEdit = false;
+    fetchBomData();
+  };
+
+  const handleSaveBom = () => {
+    bomDataValue.value.loading = true;
+    console.log(bomDataValue.value.dataList, "bomDataValue.value.dataList");
+
+    normalizeTreeData(bomDataValue.value.dataList);
+
+    const valid = validateAllBom();
+    if (valid) {
+      addBomDetail({
+        bomId: Number(routeInfo.value.bomId),
+        children: buildSubmitTree(bomDataValue.value.dataList || []),
+      })
+        .then(() => {
+          ElMessage.success("BOM淇濆瓨鎴愬姛");
+          bomDataValue.value.isEdit = false;
+          fetchBomData();
+        })
+        .catch(() => {
+          ElMessage.error("BOM淇濆瓨澶辫触");
+        })
+        .finally(() => {
+          bomDataValue.value.loading = false;
+        });
+    } else {
+      bomDataValue.value.loading = false;
+    }
+  };
+
   onMounted(() => {
     getRouteInfo();
     getList();
     getProcessList();
+    fetchBomData();
   });
 
   onUnmounted(() => {
@@ -1470,16 +1585,5 @@
     font-weight: 500;
     line-height: 1.5;
     word-break: break-all;
-  }
-
-  .section-BOM {
-    margin-top: 20px;
-  }
-
-  .hover-effect:hover {
-    border-color: #409eff;
-    background-color: #ecf5ff;
-    transform: translateY(-2px);
-    box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
   }
 </style>

--
Gitblit v1.9.3