zhangwencui
2026-04-30 f606f0dd0bba1e666c7de2f1bb56a3a641b65581
src/views/productionManagement/processRoute/processRouteItem/index.vue
@@ -38,6 +38,15 @@
            <span class="info-value">{{ routeInfo.bomNo || '-' }}</span>
          </div>
        </div>
        <div class="info-item"
             v-if="routeInfo.quantity && routeInfo.quantity !== 0">
          <div class="info-label-wrapper">
            <span class="info-label">需求数量</span>
          </div>
          <div class="info-value-wrapper">
            <span class="info-value">{{ routeInfo.quantity || '-' }}</span>
          </div>
        </div>
        <div class="info-item full-width"
             v-if="routeInfo.description">
          <div class="info-label-wrapper">
@@ -59,7 +68,8 @@
                   style="margin-right: 10px;">
          卡片视图
        </el-button>
        <el-button type="primary"
        <el-button v-if="editable"
                   type="primary"
                   @click="handleAdd">新增</el-button>
      </div>
    </div>
@@ -80,7 +90,7 @@
                       prop="technologyOperationId"
                       width="200">
        <template #default="scope">
          {{ getProcessName(scope.row.technologyOperationId) || '-' }}
          {{ scope.row.technologyOperationName || scope.row.operationName || '-' }}
        </template>
      </el-table-column>
      <el-table-column label="参数列表"
@@ -108,6 +118,13 @@
          {{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="操作"
                       align="center"
                       fixed="right"
@@ -117,12 +134,12 @@
                     link
                     size="small"
                     @click="handleEdit(scope.row)"
                     :disabled="scope.row.isComplete">编辑</el-button>
                     :disabled="scope.row.isComplete || !editable">编辑</el-button>
          <el-button type="danger"
                     link
                     size="small"
                     @click="handleDelete(scope.row)"
                     :disabled="scope.row.isComplete">删除</el-button>
                     :disabled="scope.row.isComplete || !editable">删除</el-button>
        </template>
      </el-table-column>
    </el-table>
@@ -136,7 +153,8 @@
                     style="margin-right: 10px;">
            表格视图
          </el-button>
          <el-button type="primary"
          <el-button v-if="editable"
                     type="primary"
                     @click="handleAdd">新增</el-button>
        </div>
      </div>
@@ -151,7 +169,7 @@
            <!-- 序号圆圈 -->
            <div class="card-header">
              <div class="card-number">{{ index + 1 }}</div>
              <div class="card-process-name">{{ getProcessName(item.technologyOperationId) || '-' }}</div>
              <div class="card-process-name">{{ item.technologyOperationName || item.operationName || '-' }}</div>
            </div>
            <!-- 产品信息 -->
            <div class="card-content">
@@ -166,6 +184,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>
@@ -176,7 +198,7 @@
                         link
                         size="small"
                         @click="handleEdit(item)"
                         :disabled="item.isComplete">编辑</el-button>
                         :disabled="item.isComplete || !editable">编辑</el-button>
              <el-button type="info"
                         link
                         size="small"
@@ -185,7 +207,7 @@
                         link
                         size="small"
                         @click="handleDelete(item)"
                         :disabled="item.isComplete">删除</el-button>
                         :disabled="item.isComplete || !editable">删除</el-button>
            </div>
          </div>
        </div>
@@ -196,7 +218,7 @@
         style="margin-top: 20px;">
      <div class="section-title">BOM 结构</div>
      <div class="section-actions"
           v-if="pageType === 'order'">
           v-if="pageType === 'order' && editable">
        <el-button v-if="!bomDataValue.isEdit"
                   type="primary"
                   @click="bomDataValue.isEdit = true">
@@ -220,8 +242,8 @@
              :default-expand-all="true"
              style="width: 100%">
      <el-table-column type="expand">
        <template #default="props">
          <el-form ref="form"
        <template #default>
          <el-form ref="bomFormRef"
                   :model="bomDataValue">
            <el-table :data="bomDataValue.dataList"
                      row-key="tempId"
@@ -282,6 +304,7 @@
                                     :step="1"
                                     controls-position="right"
                                     style="width: 100%"
                                     @change="handleUnitQuantityChange(row)"
                                     :disabled="!bomDataValue.isEdit || bomDataValue.dataList.some(item => (item).tempId === row.tempId)" />
                  </el-form-item>
                </template>
@@ -345,7 +368,7 @@
                       prop="model" />
    </el-table>
    <ProductSelectDialog v-if="bomDataValue.showProductDialog"
                         v-model:model-value="bomDataValue.showProductDialog"
                         v-model="bomDataValue.showProductDialog"
                         :single="true"
                         @confirm="handleBomProduct" />
    <!-- 新增/编辑弹窗 -->
@@ -358,10 +381,12 @@
               :rules="rules"
               label-width="120px">
        <el-form-item label="工序"
                      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"
@@ -369,27 +394,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>
@@ -404,14 +449,14 @@
                         @confirm="handleProductSelect"
                         single />
    <!-- 参数列表对话框 -->
    <!-- :editable="!routeInfo.status" -->
    <ProcessParamListDialog v-model="showParamListDialog"
                            :title="`${currentProcess ? (currentProcess.processName || getProcessName(currentProcess.technologyOperationId)) : ''} - 参数列表`"
                            :title="`${currentProcess ? (currentProcess.processName || currentProcess.technologyOperationName || currentProcess.operationName) : ''} - 参数列表`"
                            :route-id="routeId"
                            :order-id="orderId"
                            :process="currentProcess"
                            :page-type="pageType"
                            :param-list="paramList"
                            :editable="editable"
                            @getsyncProcessParamItem="getsyncProcessParamItem"
                            @refresh="refreshParamList" />
  </div>
@@ -436,7 +481,10 @@
    batchDeleteProcessRouteItem,
    getProcessParamList,
  } from "@/api/productionManagement/processRouteItem.js";
  import { syncProcessParamItem } from "@/api/productionManagement/processRouteItem.js";
  import {
    syncProcessParamItem,
    syncProcessParamItemOrder,
  } from "@/api/productionManagement/processRouteItem.js";
  import {
    findProductProcessRouteItemList,
    deleteRouteItem,
@@ -449,8 +497,10 @@
  import { listProcessBom } from "@/api/productionManagement/productionOrder.js";
  import {
    queryList,
    addBomDetail,
    queryList2,
    add2,
  } from "@/api/productionManagement/productStructure.js";
  import { useRoute } from "vue-router";
  import { ElMessageBox, ElMessage } from "element-plus";
  import Sortable from "sortablejs";
@@ -461,12 +511,14 @@
  const routeId = computed(() => route.query.id);
  const orderId = computed(() => route.query.orderId);
  const pageType = computed(() => route.query.type);
  const editable = computed(() => route.query.editable !== "false");
  const tableLoading = ref(false);
  const tableData = ref([]);
  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);
@@ -477,6 +529,7 @@
    model: "",
    bomNo: "",
    description: "",
    quantity: 0,
  });
  const processOptions = ref([]);
@@ -505,6 +558,7 @@
    model: "",
    unit: "",
    isQuality: false,
    isProduction: false,
  });
  const rules = {
@@ -523,17 +577,31 @@
      type: "warning",
    })
      .then(() => {
        syncProcessParamItem({
          replaceExisting: true,
          technologyRoutingOperationId: currentProcess.value.id,
        }).then(res => {
          if (res.code === 200) {
            ElMessage.success("同步成功");
            refreshParamList();
          } else {
            ElMessage.error(res.msg || "同步失败");
          }
        });
        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(() => {});
  };
@@ -592,6 +660,7 @@
      bomNo: route.query.bomNo || "",
      bomId: route.query.bomId || "",
      description: route.query.description || "",
      quantity: route.query.quantity || 0,
      status: !(route.query.status == 1 || route.query.status === "false"),
    };
    bomTableData.value[0].productName = routeInfo.value.productName;
@@ -618,6 +687,7 @@
      model: row.model || "",
      unit: row.unit || "",
      isQuality: row.isQuality,
      isProduction: row.isProduction,
    };
    dialogVisible.value = true;
  };
@@ -650,15 +720,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");
    }
  };
@@ -676,11 +751,14 @@
          const addPromise = isOrderPage
            ? addRouteItem({
                productOrderId: orderId.value,
                productRouteId: routeId.value,
                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({
@@ -688,6 +766,7 @@
                technologyOperationId: form.value.technologyOperationId,
                productModelId: form.value.productModelId,
                isQuality: form.value.isQuality,
                isProduction: form.value.isProduction,
                dragSort,
              });
@@ -711,8 +790,10 @@
            ? addOrUpdateProductProcessRouteItem({
                id: form.value.id,
                technologyOperationId: form.value.technologyOperationId,
                operationName: getProcessName(form.value.technologyOperationId),
                productModelId: form.value.productModelId,
                isQuality: form.value.isQuality,
                isProduction: form.value.isProduction,
              })
            : addOrUpdateProcessRouteItem1({
                technologyRoutingId: Number(routeId.value),
@@ -720,6 +801,7 @@
                productModelId: form.value.productModelId,
                id: form.value.id,
                isQuality: form.value.isQuality,
                isProduction: form.value.isProduction,
              });
          updatePromise
@@ -749,6 +831,8 @@
      productName: "",
      model: "",
      unit: "",
      isQuality: false,
      isProduction: false,
    };
    formRef.value?.resetFields();
  };
@@ -762,15 +846,19 @@
  // 查看参数列表
  const handleViewParams = row => {
    currentProcess.value = row;
    const query = {
    const param = {
      productionOrderRoutingOperationId: row.id,
      productionOrderId: orderId.value,
    };
    const param1 = {
      technologyRoutingOperationId: row.id,
      orderId: orderId.value,
      productionOrderId: orderId.value,
    };
    const apiPromise =
      pageType.value === "order"
        ? findProcessParamListOrder(query)
        : getProcessParamList(query);
        ? findProcessParamListOrder(param)
        : getProcessParamList(param1);
    apiPromise
      .then(res => {
@@ -793,6 +881,7 @@
  // 初始化拖拽排序
  const initSortable = () => {
    destroySortable();
    if (!editable.value) return;
    if (viewMode.value === "table") {
      // 表格视图的拖拽排序
@@ -944,7 +1033,8 @@
  });
  const syncProcessOperationFields = item => {
    const processId = item.processId ?? item.operationId ?? "";
    const processId =
      item.processId ?? item.operationId ?? item.technologyOperationId ?? "";
    if (!processId) {
      item.processId = "";
      return;
@@ -956,7 +1046,11 @@
      option?.name || item.processName || item.operationName || "";
    item.processId = processId;
    item.operationId = processId;
    if (pageType.value === "order") {
      item.technologyOperationId = processId;
    } else {
      item.operationId = processId;
    }
    item.processName = processName;
    item.operationName = processName;
  };
@@ -967,6 +1061,14 @@
      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;
      }
    });
  };
@@ -983,7 +1085,10 @@
  const fetchBomData = async () => {
    try {
      const { data } = await queryList(routeInfo.value.bomId);
      const isOrderPage = pageType.value === "order";
      const { data } = await (isOrderPage ? queryList2 : queryList)(
        routeInfo.value.bomId
      );
      bomDataValue.value.dataList = data || [];
      normalizeTreeData(bomDataValue.value.dataList);
    } catch (err) {
@@ -1081,6 +1186,12 @@
    });
  };
  const handleUnitQuantityChange = row => {
    if (routeInfo.value.quantity && routeInfo.value.quantity !== 0) {
      row.demandedQuantity = (row.unitQuantity || 0) * routeInfo.value.quantity;
    }
  };
  const addchildItem = (item, tempId) => {
    if (item.tempId === tempId) {
      if (!item.children) {
@@ -1095,10 +1206,14 @@
        productModelId: undefined,
        processId: "",
        processName: "",
        operationId: "",
        [pageType.value === "order" ? "technologyOperationId" : "operationId"]:
          "",
        operationName: "",
        unitQuantity: 1,
        demandedQuantity: 0,
        demandedQuantity:
          routeInfo.value.quantity && routeInfo.value.quantity !== 0
            ? 1 * routeInfo.value.quantity
            : 0,
        children: [],
        unit: "",
        tempId: new Date().getTime(),
@@ -1130,10 +1245,14 @@
          productModelId: undefined,
          processId: "",
          processName: "",
          operationId: "",
          [pageType.value === "order" ? "technologyOperationId" : "operationId"]:
            "",
          operationName: "",
          unitQuantity: 1,
          demandedQuantity: 0,
          demandedQuantity:
            routeInfo.value.quantity && routeInfo.value.quantity !== 0
              ? 1 * routeInfo.value.quantity
              : 0,
          unit: "",
          children: [],
          tempId: new Date().getTime(),
@@ -1202,12 +1321,15 @@
  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: routeInfo.value.bomId,
      add2({
        // bomId: Number(routeInfo.value.bomId),
        productionOrderBomId: Number(routeInfo.value.bomId) || null,
        children: buildSubmitTree(bomDataValue.value.dataList || []),
      })
        .then(() => {