5 天以前 fb6e4a0041575dfacc4da9f8fc66d9a3d1f8a6b8
src/views/productionManagement/productStructure/Detail/index.vue
@@ -86,6 +86,7 @@
                                     :step="1"
                                     controls-position="right"
                                     style="width: 100%"
                                     @change="handleUnitQuantityChange"
                                     :disabled="!dataValue.isEdit || dataValue.dataList.some(item => (item as any).tempId === row.tempId)" />
                  </el-form-item>
                </template>
@@ -103,7 +104,7 @@
                                     :step="1"
                                     controls-position="right"
                                     style="width: 100%"
                                     :disabled="!dataValue.isEdit || dataValue.dataList.some(item => (item as any).tempId === row.tempId)" />
                                     :disabled="true" />
                  </el-form-item>
                </template>
              </el-table-column>
@@ -268,6 +269,42 @@
    });
  };
  const toQuantityNumber = (value: any) => {
    const numberValue = Number(value);
    if (!Number.isFinite(numberValue)) {
      return 0;
    }
    return Number(numberValue.toFixed(2));
  };
  const syncDemandedQuantityTree = (
    items: any[],
    parentDemandedQuantity: number | null = null
  ) => {
    items.forEach((item: any) => {
      if (parentDemandedQuantity !== null) {
        item.demandedQuantity = toQuantityNumber(
          parentDemandedQuantity * toQuantityNumber(item.unitQuantity)
        );
      }
      if (Array.isArray(item.children) && item.children.length > 0) {
        syncDemandedQuantityTree(
          item.children,
          toQuantityNumber(item.demandedQuantity)
        );
      }
    });
  };
  const recalculateDemandedQuantities = () => {
    if (!isOrderPage.value) {
      return;
    }
    syncDemandedQuantityTree(dataValue.dataList);
  };
  const buildSubmitTree = (items: any[]) => {
    return items.map((item: any) => {
      const current = { ...item };
@@ -279,9 +316,45 @@
    });
  };
  const findSiblings = (items: any[], tempId: string): any[] | null => {
    if (!items || items.length === 0) return null;
    // 检查当前层级
    if (items.some(item => item.tempId === tempId)) {
      return items;
    }
    // 递归查找子级
    for (const item of items) {
      if (item.children && item.children.length > 0) {
        const result = findSiblings(item.children, tempId);
        if (result) return result;
      }
    }
    return null;
  };
  const handleProcessChange = (row: any, value: any) => {
    if (value) {
      const siblings = findSiblings(dataValue.dataList, row.tempId);
      if (siblings) {
        const isDuplicate = siblings.some(
          s => s.tempId !== row.tempId && s.processId === value
        );
        if (isDuplicate) {
          const option = getProcessOptionById(value);
          const processName = option?.name || "该工序";
          ElMessage.warning(`同一层级下不能选择重复的消耗工序:${processName}`);
          row.processId = "";
          syncProcessOperationFields(row);
          return;
        }
      }
    }
    row.processId = value || "";
    syncProcessOperationFields(row);
  };
  const handleUnitQuantityChange = () => {
    recalculateDemandedQuantities();
  };
  const tableData = reactive([
@@ -304,6 +377,7 @@
      const { data } = await listProcessBom({ orderId: routeOrderId.value });
      dataValue.dataList = (data as any) || [];
      normalizeTreeData(dataValue.dataList);
      recalculateDemandedQuantities();
    } else {
      // 非订单情况:使用原来的接口
      const { data } = await queryList(routeId.value);
@@ -389,8 +463,37 @@
  const validateAll = () => {
    let isValid = true;
    // 校验一组兄弟节点的工序是否唯一
    const checkProcessUniqueness = (items: any[]) => {
      if (!items || items.length === 0 || !isValid) return;
      const processIds = new Set();
      for (const item of items) {
        if (item.processId) {
          if (processIds.has(item.processId)) {
            const option = getProcessOptionById(item.processId);
            const processName = option?.name || item.processName || "未知工序";
            ElMessage.error(
              `产品「${item.productName}」的消耗工序「${processName}」在当前层级已存在,请勿重复设置`
            );
            isValid = false;
            return;
          }
          processIds.add(item.processId);
        }
      }
      // 递归校验子级的兄弟节点
      for (const item of items) {
        if (item.children && item.children.length > 0) {
          checkProcessUniqueness(item.children);
        }
      }
    };
    // 校验函数
    const validateItem = (item: any, isTopLevel = false) => {
      if (!isValid) return;
      // 校验当前项的必填字段
      if (!item.model) {
        ElMessage.error("请选择规格");
@@ -418,7 +521,7 @@
      //   return;
      // }
      // 递归校验子项
      // 递归校验子项字段
      if (item.children && item.children.length > 0) {
        item.children.forEach(child => {
          validateItem(child, false);
@@ -426,7 +529,11 @@
      }
    };
    // 遍历所有顶层项
    // 1. 首先校验同一父级下的同层消耗工序是否唯一
    checkProcessUniqueness(dataValue.dataList);
    if (!isValid) return false;
    // 2. 然后遍历校验所有顶层项的字段必填情况
    dataValue.dataList.forEach(item => {
      validateItem(item, true);
    });
@@ -437,6 +544,7 @@
  const submit = () => {
    dataValue.loading = true;
    normalizeTreeData(dataValue.dataList);
    recalculateDemandedQuantities();
    // 先进行表单校验
    const valid = validateAll();
@@ -514,6 +622,7 @@
          tempId: new Date().getTime(),
        });
        recalculateDemandedQuantities();
        return;
      }
      addchildItem(item, tempId);
@@ -542,6 +651,7 @@
        unit: "",
        tempId: new Date().getTime(),
      });
      recalculateDemandedQuantities();
      return true;
    }
    if (item.children && item.children.length > 0) {