zhangwencui
2026-04-25 93d2a0bd19ffb1d86c6807a4d93d0eff580c14f1
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) {
            // 为BOM数据设置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) {
            // 为BOM数据设置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>