gaoluyang
2 天以前 79fb20a2102f2d6a050b83f20477aa13b221f096
src/views/productionManagement/productStructure/Detail/index.vue
@@ -3,72 +3,73 @@
    <PageHeader content="产品结构详情">
      <template #right-button>
        <el-button v-if="dataValue.isEdit && !isOrderPage"
                   type="primary"
                   @click="addItem">添加
                   @click="cancelEdit">取消
        </el-button>
        <el-button v-if="!dataValue.isEdit && !isOrderPage"
                   type="primary"
                   @click="dataValue.isEdit = true">编辑
        </el-button>
        <el-button v-if="dataValue.isEdit && !isOrderPage"
                   type="primary"
                   @click="cancelEdit">取消
                   @click="dataValue.isEdit = true">点击进行修改
        </el-button>
        <el-button v-if="!isOrderPage"
                   type="primary"
                   @click="openBomAddDialog"
                   :disabled="!dataValue.isEdit">
          <el-icon><Document /></el-icon> 按BOM添加
        </el-button>
        <el-button v-if="!isOrderPage"
                   type="success"
                   :loading="dataValue.loading"
                   @click="submit"
                   :disabled="!dataValue.isEdit">确认
        </el-button>
      </template>
    </PageHeader>
    <el-table
        :data="tableData"
        border
        :preserve-expanded-content="false"
        :default-expand-all="true"
        style="width: 100%"
    >
    <el-table :data="tableData"
              border
              :preserve-expanded-content="false"
              :default-expand-all="true"
              style="width: 100%">
      <el-table-column type="expand">
        <template #default="props">
          <el-form ref="form"
                   :model="dataValue">
            <el-table :data="dataValue.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="规格">
                               label="产品" />
                     <el-table-column prop="model"
                                              label="图纸编号">
                        <template #default="{ row, $index }">
                           <el-form-item v-if="dataValue.isEdit"
                                             :rules="[{ required: true, message: '请选择规格', trigger: ['blur','change'] }]"
                                             style="margin: 0">
                              <el-select v-model="row.model"
                                              placeholder="请选择规格"
                                              clearable
                                              :disabled="!dataValue.isEdit || dataValue.dataList.some(item => (item as any).tempId === row.tempId)"
                                              style="width: 100%"
                                              @visible-change="(v) => { if (v) openDialog(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, $index }">
                  <el-form-item v-if="dataValue.isEdit"
                                :prop="`dataList.${$index}.model`"
                                :rules="[{ required: true, message: '请选择规格', trigger: ['blur','change'] }]"
                                style="margin: 0">
                    <el-select v-model="row.model"
                               placeholder="请选择规格"
                               clearable
                               :disabled="!dataValue.isEdit"
                               style="width: 100%"
                               @visible-change="(v) => { if (v) openDialog($index) }">
                      <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="processId"
                               label="消耗工序">
                <template #default="{ row, $index }">
                  <el-form-item :prop="`dataList.${$index}.processId`"
                                :rules="[{ required: true, message: '请选择消耗工序', trigger: 'change' }]"
                                :rules="dataValue.dataList.some(item => (item as any).tempId === row.tempId) ? [] : [{ required: true, message: '请选工序', trigger: 'change' }]"
                                style="margin: 0">
                    <el-select v-model="row.processId"
                               placeholder="请选择"
                               filterable
                               clearable
                               style="width: 100%"
                               :disabled="!dataValue.isEdit">
                               :disabled="!dataValue.isEdit || dataValue.dataList.some(item => (item as any).tempId === row.tempId)">
                      <el-option v-for="item in dataValue.processOptions"
                                 :key="item.id"
                                 :label="item.name"
@@ -78,10 +79,10 @@
                </template>
              </el-table-column>
              <el-table-column prop="unitQuantity"
                               label="单位产出所需数量">
                               label="单位用量">
                <template #default="{ row, $index }">
                  <el-form-item :prop="`dataList.${$index}.unitQuantity`"
                                :rules="[{ required: true, message: '请输入单位产出所需数量', trigger: ['blur','change'] }]"
                  <el-form-item v-if="dataValue.isEdit"
                                :rules="[{ required: true, message: '请输入单位用量', trigger: ['blur','change'] }]"
                                style="margin: 0">
                    <el-input-number v-model="row.unitQuantity"
                                     :min="0"
@@ -89,7 +90,7 @@
                                     :step="1"
                                     controls-position="right"
                                     style="width: 100%"
                                     :disabled="!dataValue.isEdit" />
                                     :disabled="!dataValue.isEdit || dataValue.dataList.some(item => (item as any).tempId === row.tempId)" />
                  </el-form-item>
                </template>
              </el-table-column>
@@ -97,7 +98,7 @@
                               prop="demandedQuantity"
                               label="需求总量">
                <template #default="{ row, $index }">
                  <el-form-item :prop="`dataList.${$index}.demandedQuantity`"
                  <el-form-item v-if="dataValue.isEdit"
                                :rules="[{ required: true, message: '请输入需求总量', trigger: ['blur','change'] }]"
                                style="margin: 0">
                    <el-input-number v-model="row.demandedQuantity"
@@ -106,29 +107,36 @@
                                     :step="1"
                                     controls-position="right"
                                     style="width: 100%"
                                     :disabled="!dataValue.isEdit" />
                                     :disabled="!dataValue.isEdit || dataValue.dataList.some(item => (item as any).tempId === row.tempId)" />
                  </el-form-item>
                </template>
              </el-table-column>
              <el-table-column prop="unit"
                               label="单位">
                <template #default="{ row, $index }">
                  <el-form-item :prop="`dataList.${$index}.unit`"
                  <el-form-item v-if="dataValue.isEdit"
                                :rules="[{ required: true, message: '请输入单位', trigger: ['blur','change'] }]"
                                style="margin: 0">
                    <el-input v-model="row.unit"
                              placeholder="请输入单位"
                              clearable
                              :disabled="!dataValue.isEdit" />
                              :disabled="!dataValue.isEdit || dataValue.dataList.some(item => (item as any).tempId === row.tempId)" />
                  </el-form-item>
                </template>
              </el-table-column>
              <el-table-column label="操作" fixed="right" width="100">
              <el-table-column label="操作"
                               fixed="right"
                               width="200">
                <template #default="{ row, $index }">
                  <el-button v-if="dataValue.isEdit"
                  <el-button v-if="dataValue.isEdit && !dataValue.dataList.some(item => (item as any).tempId === row.tempId)"
                             type="danger"
                             text
                             @click="dataValue.dataList.splice($index, 1)">删除
                             @click="removeItem(row.tempId)">删除
                  </el-button>
                  <el-button v-if="dataValue.isEdit"
                             type="primary"
                             text
                             @click="addItem2(row.tempId)">添加
                  </el-button>
                </template>
              </el-table-column>
@@ -136,165 +144,643 @@
          </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-column label="BOM编号"
                       prop="bomNo" />
      <el-table-column label="产品名称"
                       prop="productName" />
         <el-table-column label="图纸编号"
                                           prop="model" />
    </el-table>
    <product-select-dialog v-if="dataValue.showProductDialog"
                           v-model:model-value="dataValue.showProductDialog"
                           @confirm="handleProduct" />
    <!-- 按BOM添加弹窗 -->
    <el-dialog v-model="bomAddDialogVisible" title="按BOM添加" width="500px" @close="closeBomAddDialog">
      <el-form ref="bomAddFormRef" :model="bomAddForm" :rules="bomAddRules" label-width="100px">
        <el-form-item label="父项产品" prop="parentProductId">
          <el-select v-model="bomAddForm.parentProductId" placeholder="请选择" clearable filterable
            style="width: 100%" @change="handleBomParentProductChange">
            <el-option v-for="item in parentProductOptions" :key="item.id"
              :label="`${item.model || item.productCode || item.id} | ${item.productName}`"
              :value="item.id" />
          </el-select>
        </el-form-item>
        <!-- 选中产品后展示产品信息 -->
        <div v-if="selectedBomProduct" class="selected-product-info">
          <div class="product-info-row">
            <span class="info-label">产品编号</span>
            <span class="info-value">{{ selectedBomProduct.model || selectedBomProduct.productCode || '-' }}</span>
          </div>
          <div class="product-info-row">
            <span class="info-label">产品名称</span>
            <span class="info-value">{{ selectedBomProduct.productName || '-' }}</span>
          </div>
          <div class="product-info-row">
            <span class="info-label">产品规格</span>
            <span class="info-value">{{ selectedBomProduct.spec || selectedBomProduct.drawingNumber || '-' }}</span>
          </div>
          <div class="stock-info-box">
            <div class="stock-number">{{ selectedBomProduct.stockQuantity || 0 }}</div>
            <div class="stock-label">库存数量(台)</div>
          </div>
        </div>
        <el-form-item label="用量系数" prop="coefficient" style="margin-top: 20px;">
          <el-input-number v-model="bomAddForm.coefficient" :min="0.01" :precision="2" :step="1"
            controls-position="right" style="width: 100%" />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button type="primary" @click="submitBomAdd">确定</el-button>
        <el-button @click="closeBomAddDialog">取消</el-button>
      </template>
    </el-dialog>
    <!-- 高级选择产品弹窗 -->
    <product-select-dialog v-if="showAdvancedProductDialog" v-model:model-value="showAdvancedProductDialog"
      @confirm="handleAdvancedProductSelect" />
  </div>
</template>
<script setup lang="ts">
import {
  computed,
  defineAsyncComponent,
  defineComponent,
  onMounted,
  reactive,
  ref,
} from "vue";
import { queryList, add } from "@/api/productionManagement/productStructure.js";
import { listProcessBom } from "@/api/productionManagement/productionOrder.js";
import { list } from "@/api/productionManagement/productionProcess";
import { ElMessage } from "element-plus";
import {useRoute, useRouter} from "vue-router";
  import {
    computed,
    defineAsyncComponent,
    defineComponent,
    onMounted,
    reactive,
    ref,
  } from "vue";
  import { queryList, add, listByBomIdIsParent } from "@/api/productionManagement/productStructure.js";
  import { listProcessBom } from "@/api/productionManagement/productionOrder.js";
  import { list } from "@/api/productionManagement/productionProcess";
  import { productListPage } from "@/api/basicData/product.js";
  import { listPage as listBomPage } from "@/api/productionManagement/productBom.js";
  import { ElMessage } from "element-plus";
  import { useRoute, useRouter } from "vue-router";
  import { Search, Document } from '@element-plus/icons-vue'
defineComponent({
  name: "StructureEdit",
});
const ProductSelectDialog = defineAsyncComponent(
    () => import("@/views/basicData/product/ProductSelectDialog.vue")
);
const form = ref();
const route = useRoute()
const router = useRouter()
const routeId = computed({
  get() {
    return route.query.id;
  },
  set(val) {
    emit('update:router', val)
  }
});
// 从路由参数获取产品信息
const routeBomNo = computed(() => route.query.bomNo || '');
const routeProductName = computed(() => route.query.productName || '');
const routeProductModelName = computed(() => route.query.productModelName || '');
const routeOrderId = computed(() => route.query.orderId);
const pageType = computed(() => route.query.type);
const isOrderPage = computed(() => pageType.value === 'order' && routeOrderId.value);
const dataValue = reactive({
  dataList: [],
  productOptions: [],
  processOptions: [],
  showProductDialog: false,
  currentRowIndex: null,
  loading: false,
  isEdit: false,
});
const tableData = reactive([
  {
    productName: "",
    model: "",
    bomNo: "",
  }
])
const openDialog = index => {
  dataValue.currentRowIndex = index;
  dataValue.showProductDialog = true;
};
const fetchData = async () => {
  if (isOrderPage.value) {
    // 订单情况:使用订单的产品结构接口
    const { data } = await listProcessBom({ orderId: routeOrderId.value });
    dataValue.dataList = data || [];
  } else {
    // 非订单情况:使用原来的接口
    const { data } = await queryList(routeId.value);
    dataValue.dataList = data || [];
  }
};
const fetchProcessOptions = async () => {
  const { data } = await list(routeId.value);
  dataValue.processOptions = data;
};
const handleProduct = row => {
  if (row?.length > 1) {
    ElMessage.error("只能选择一个产品");
  }
  dataValue.dataList[dataValue.currentRowIndex].productName =
      row[0].productName;
  dataValue.dataList[dataValue.currentRowIndex].model = row[0].model;
  dataValue.dataList[dataValue.currentRowIndex].productModelId = row[0].id;
  dataValue.dataList[dataValue.currentRowIndex].unit = row[0].unit || "";
  dataValue.showProductDialog = false;
};
const submit = () => {
  form.value
      .validate(valid => {
        dataValue.loading = true;
        if (valid) {
          add({
            bomId: routeId.value,
            productStructureList: dataValue.dataList || [],
          }).then(res => {
            router.push({
              path: '/productionManagement/productionManagement/productStructure/index',
            })
            ElMessage.success("保存成功");
            dataValue.loading = false;
          });
        }
      })
      .finally(() => {
        dataValue.loading = false;
      });
};
const addItem = () => {
  dataValue.dataList.push({
    productName: "",
    productId: "",
    model: undefined,
    productModelId: undefined,
    processId: "",
    unitQuantity: 0,
    demandedQuantity: 0,
    unit: "",
  defineComponent({
    name: "StructureEdit",
  });
};
const cancelEdit = () => {
  dataValue.isEdit = false;
  dataValue.dataList = dataValue.dataList.filter(item => item.id !== undefined);
};
  const ProductSelectDialog = defineAsyncComponent(
    () => import("@/views/basicData/product/ProductSelectDialog.vue")
  );
  const emit = defineEmits(["update:router"]);
  const form = ref();
onMounted(() => {
  // 从路由参数回显数据
  tableData[0].productName = routeProductName.value;
  tableData[0].model = routeProductModelName.value;
  tableData[0].bomNo = routeBomNo.value;
  // 订单情况下禁用编辑
  if (isOrderPage.value) {
  const route = useRoute();
  const router = useRouter();
  const routeId = computed({
    get() {
      return route.query.id;
    },
    set(val) {
      emit("update:router", val);
    },
  });
  // 从路由参数获取产品信息
  const routeBomNo = computed(() => route.query.bomNo || "");
  const routeProductName = computed(() => route.query.productName || "");
  const routeDrawingNumber = computed(() => route.query.drawingNumber || "");
  const routeProductModelName = computed(
    () => route.query.productModelName || ""
  );
  const routeOrderId = computed(() => route.query.orderId);
  const pageType = computed(() => route.query.type);
  const isOrderPage = computed(
    () => pageType.value === "order" && routeOrderId.value
  );
  const dataValue = reactive({
    dataList: [],
    productOptions: [],
    processOptions: [],
    showProductDialog: false,
    currentRowIndex: null,
    currentRowName: null,
    loading: false,
    isEdit: false,
  });
  // 按BOM添加相关
  const bomAddDialogVisible = ref(false);
  const bomAddFormRef = ref();
  const parentProductOptions = ref([]);
  const selectedBomProduct = ref(null);
  const selectedBomTreeData = ref([]); // 保存选中产品时获取的BOM树数据
  const bomAddForm = reactive({
    parentProductId: undefined,
    coefficient:1
  });
  const bomAddRules = {
    parentProductId: [{ required: true, message: "请选择父项产品", trigger: "change" }],
    coefficient: [{ required: true, message: "请输入用量系数", trigger: "blur" }]
  };
  const tableData = reactive([
    {
      productName: "",
      drawingNumber: "",
      model: "",
      bomNo: "",
    },
  ]);
  const openDialog = (tempId: any) => {
    console.log(tempId, "tempId");
    dataValue.currentRowName = tempId;
    dataValue.showProductDialog = true;
  };
  const fetchData = async () => {
    if (isOrderPage.value) {
      // 订单情况:使用订单的产品结构接口
      const { data } = await listProcessBom({ orderId: routeOrderId.value });
      dataValue.dataList = (data as any) || [];
    } else {
      // 非订单情况:使用原来的接口
      const { data } = await queryList(routeId.value);
      dataValue.dataList = (data as any) || [];
      // 为所有项及其子项设置name属性
      const setNameRecursively = (items: any[]) => {
        items.forEach((item: any) => {
          item.tempId = item.id;
          item.processName =
            dataValue.processOptions.find(option => option.id === item.processId)
              ?.name || "";
          if (item.children && item.children.length > 0) {
            setNameRecursively(item.children);
          }
        });
      };
      setNameRecursively(dataValue.dataList);
      console.log(dataValue.dataList, "dataValue.dataList");
    }
  };
  const fetchProcessOptions = async () => {
    const { data } = await list();
    dataValue.processOptions = data as any;
  };
  const handleProduct = (row: any) => {
    if (row?.length > 1) {
      ElMessage.error("只能选择一个产品");
    }
    const productData = row[0];
    //  最外层组件中,与当前产品相同的产品只能有一个
    const isTopLevel = dataValue.dataList.some(
      item => (item as any).tempId === dataValue.currentRowName
    );
    if (isTopLevel) {
      if (
        productData.productName === tableData[0].productName &&
        productData.model === tableData[0].model
      ) {
        //  查找是否已经有其他顶层行已经是这个产品
        const hasOther = dataValue.dataList.some(
          item =>
            (item as any).tempId !== dataValue.currentRowName &&
            (item as any).productName === tableData[0].productName &&
            (item as any).model === tableData[0].model
        );
        if (hasOther) {
          ElMessage.warning("最外层和当前产品一样的一级只能有一个");
          return;
        }
      }
    }
    // dataValue.dataList[dataValue.currentRowIndex].productName =
    //   row[0].productName;
    // dataValue.dataList[dataValue.currentRowIndex].model = row[0].model;
    // dataValue.dataList[dataValue.currentRowIndex].productModelId = row[0].id;
    // dataValue.dataList[dataValue.currentRowIndex].unit = row[0].unit || "";
    dataValue.dataList.map(item => {
      if (item.tempId === dataValue.currentRowName) {
        item.productName = productData.productName;
        item.drawingNumber = productData.drawingNumber || "";
        item.model = productData.model;
        item.productModelId = productData.id;
        item.unit = productData.unit || "";
        return;
      }
      childItem(item, dataValue.currentRowName, productData);
    });
    dataValue.showProductDialog = false;
  };
  const childItem = (item: any, tempId: any, productData: any) => {
    if (item.tempId === tempId) {
      item.productName = productData.productName;
      item.drawingNumber = productData.drawingNumber || "";
      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 validateAll = () => {
    let isValid = true;
    // 校验函数
    const validateItem = (item: any, isTopLevel = false) => {
      // 校验当前项的必填字段
      if (!item.model) {
        ElMessage.error("请选择规格");
        isValid = false;
        return;
      }
      if (!item.unitQuantity) {
        ElMessage.error("请输入单位用量");
        isValid = false;
        return;
      }
      if (isOrderPage.value && !item.demandedQuantity) {
        ElMessage.error("请输入需求总量");
        isValid = false;
        return;
      }
      // if (!item.unit) {
      //   ElMessage.error("请输入单位");
      //   isValid = false;
      //   return;
      // }
      // 递归校验子项
      if (item.children && item.children.length > 0) {
        item.children.forEach(child => {
          validateItem(child, false);
        });
      }
    };
    // 遍历所有顶层项
    dataValue.dataList.forEach(item => {
      validateItem(item, true);
    });
    return isValid;
  };
  const submit = () => {
    dataValue.loading = true;
    // 先进行表单校验
    const valid = validateAll();
    console.log(dataValue.dataList, "dataValue.dataList");
    if (valid) {
      add({
        bomId: routeId.value,
        children: dataValue.dataList || [],
      })
        .then(res => {
          router.push({
            path: "/productionManagement/productionManagement/productStructure/index",
          });
          ElMessage.success("保存成功");
          dataValue.loading = false;
        })
        .catch(() => {
          dataValue.loading = false;
        });
    } else {
      dataValue.loading = false;
    }
  };
  const removeItem = (tempId: string) => {
    // 先尝试从顶层删除
    const topIndex = dataValue.dataList.findIndex(item => item.tempId === tempId);
    if (topIndex !== -1) {
      dataValue.dataList.splice(topIndex, 1);
      return;
    }
    // 递归删除子项
    const delchildItem = (items: any[], tempId: any) => {
      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;
    };
    dataValue.dataList.forEach(item => {
      if (item.children && item.children.length > 0) {
        delchildItem(item.children, tempId);
      }
    });
  };
  const addItem2 = tempId => {
    dataValue.dataList.map(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: "",
          unitQuantity: 0,
          demandedQuantity: 0,
          unit: "",
          children: [],
          tempId: new Date().getTime(),
        });
        return;
      }
      addchildItem(item, tempId);
    });
  };
  const addchildItem = (item: any, tempId: any) => {
    if (item.tempId === tempId) {
      console.log(item, "item");
      if (!item.children) {
        item.children = [];
      }
      item.children.push({
        parentId: item.id || "",
        parentTempId: item.tempId || "",
        productName: "",
        productId: "",
        model: undefined,
        productModelId: undefined,
        processId: "",
        unitQuantity: 0,
        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 getPropPath = (row, field) => {
    // 为每个row生成唯一的路径
    // 使用row.id或索引作为唯一标识
    let path = "dataList";
    // 简单实现:使用row的id或一个唯一标识
    const uniqueId = row.id || Math.floor(Math.random() * 10000);
    path += `.${uniqueId}`;
    return path + `.${field}`;
  };
  const cancelEdit = () => {
    dataValue.isEdit = false;
  }
  fetchData();
  fetchProcessOptions();
});
</script>
    // dataValue.dataList = dataValue.dataList.filter(item => item.id !== undefined);
    fetchData();
  };
  // 获取父项产品列表
  const getParentProductList = async () => {
    try {
      const { data } = await listBomPage({ current: 1, size: 1000 });
      parentProductOptions.value = data?.records || [];
    } catch (error) {
      console.error("获取父项产品列表失败:", error);
      parentProductOptions.value = [];
    }
  };
  // 打开按BOM添加弹窗
  const openBomAddDialog = () => {
    bomAddDialogVisible.value = true;
    bomAddForm.parentProductId = undefined;
    bomAddForm.coefficient = 1;
    selectedBomProduct.value = null;
    getParentProductList();
  };
  // 关闭按BOM添加弹窗
  const closeBomAddDialog = () => {
    bomAddDialogVisible.value = false;
    bomAddFormRef.value?.resetFields();
    selectedBomProduct.value = null;
  };
  // 打开高级选择
  const openAdvancedSelect = () => {
    showAdvancedProductDialog.value = true;
  };
  // 父项产品变更
  const handleBomParentProductChange = async (val) => {
    if (val) {
      const product = parentProductOptions.value.find(item => item.id === val);
      selectedBomProduct.value = product || null;
      // 直接用选中的 BOM ID 调用 listByBomIdIsParent
      const { data: treeData } = await listByBomIdIsParent(val);
      selectedBomTreeData.value = treeData || [];
      // 将二级树中的产品添加到父项产品选项(从第二级开始)
      const addTreeToOptions = (items: any[]) => {
        items.forEach((item: any) => {
          // 跳过第一级,只添加第二级及以下的产品
          if (item.children && item.children.length > 0) {
            item.children.forEach((child: any) => {
              const exists = parentProductOptions.value.some(opt => opt.id === child.id);
              if (!exists) {
                parentProductOptions.value.push({
                  id: child.id,
                  productName: child.productName,
                  model: child.model,
                  productCode: child.model,
                  spec: child.drawingNumber,
                  drawingNumber: child.drawingNumber,
                  stockQuantity: child.stockQuantity || 0
                });
              }
              // 递归添加子项
              if (child.children && child.children.length > 0) {
                addTreeToOptions([child]);
              }
            });
          }
        });
      };
      if (selectedBomTreeData.value.length > 0) {
        addTreeToOptions(selectedBomTreeData.value);
      }
    } else {
      selectedBomProduct.value = null;
      selectedBomTreeData.value = [];
    }
  };
  // 提交按BOM添加
  const submitBomAdd = () => {
    bomAddFormRef.value.validate(async (valid) => {
      if (!valid) return;
      const product = parentProductOptions.value.find(item => item.id === bomAddForm.parentProductId);
      if (!product) {
        ElMessage.error("未找到选中的产品");
        return;
      }
      try {
        // 使用选择产品时保存的BOM树数据
        const bomItems = selectedBomTreeData.value || [];
        if (bomItems.length === 0) {
          ElMessage.warning("该产品没有BOM信息");
          return;
        }
        // 列表的第一级已经存在,把BOM数据作为第一级的子项(第二级)添加
        if (dataValue.dataList.length > 0) {
          const firstLevelItem = dataValue.dataList[0];
          // 把BOM数据添加到第一级的children中
          const addBomItemsRecursively = (items: any[], parentItem: any) => {
            items.forEach((item: any) => {
              const newItem: any = {
                parentId: item.parentId || "",
                parentTempId: parentItem.tempId || "",
                productName: item.productName || "",
                productId: item.productId || item.productModelId || "",
                model: item.model || "",
                productModelId: item.productModelId || "",
                drawingNumber: item.drawingNumber || "",
                processId: item.processId || "",
                processName: item.processName || "",
                unitQuantity: (item.unitQuantity || 0) * bomAddForm.coefficient,
                demandedQuantity: (item.demandedQuantity || 0) * bomAddForm.coefficient,
                unit: item.unit || "",
                children: [],
                tempId: new Date().getTime() + Math.random(),
              };
              // 添加到父项的children
              if (!parentItem.children) {
                parentItem.children = [];
              }
              parentItem.children.push(newItem);
              // 递归处理子项
              if (item.children && item.children.length > 0) {
                addBomItemsRecursively(item.children, newItem);
              }
            });
          };
          addBomItemsRecursively(bomItems, firstLevelItem);
        }
        ElMessage.success("添加成功");
        closeBomAddDialog();
      } catch (error) {
        console.error("按BOM添加失败:", error);
        ElMessage.error("添加失败");
      }
    });
  };
  onMounted(async () => {
    // 从路由参数回显数据
    tableData[0].productName = routeProductName.value as string;
    tableData[0].drawingNumber = routeDrawingNumber.value as string;
    tableData[0].model = routeProductModelName.value as string;
    tableData[0].bomNo = routeBomNo.value as string;
    // 订单情况下禁用编辑
    if (isOrderPage.value) {
      dataValue.isEdit = false;
    }
    // 先加载工序选项,再加载数据,确保el-select能够正确回显
    await fetchProcessOptions();
    await fetchData();
  });
</script>
<style scoped>
.selected-product-info {
  background-color: #f5f7fa;
  border-radius: 4px;
  padding: 16px;
  margin: 10px 0;
  position: relative;
}
.product-info-row {
  display: flex;
  margin-bottom: 8px;
  font-size: 14px;
}
.product-info-row:last-child {
  margin-bottom: 0;
}
.info-label {
  color: #909399;
  width: 70px;
  flex-shrink: 0;
}
.info-value {
  color: #303133;
  flex: 1;
}
.stock-info-box {
  position: absolute;
  right: 16px;
  top: 50%;
  transform: translateY(-50%);
  text-align: center;
}
.stock-number {
  font-size: 28px;
  font-weight: bold;
  color: #303133;
  line-height: 1;
  margin-bottom: 4px;
}
.stock-label {
  font-size: 12px;
  color: #909399;
}
</style>