zhangwencui
10 小时以前 f0e3b394502281cee53b4095fc637452204bf726
src/views/productionManagement/productStructure/Detail/index.vue
@@ -2,45 +2,46 @@
  <div class="app-container">
    <PageHeader content="产品结构详情">
      <template #right-button>
        <el-button v-if="dataValue.isEdit"
        <el-button v-if="dataValue.isEdit && !isOrderPage"
                   type="primary"
                   @click="addItem">添加
        </el-button>
        <el-button v-if="!dataValue.isEdit"
        <el-button v-if="!dataValue.isEdit && !isOrderPage"
                   type="primary"
                   @click="dataValue.isEdit = true">编辑
        </el-button>
        <el-button v-if="dataValue.isEdit"
        <el-button v-if="dataValue.isEdit && !isOrderPage"
                   type="primary"
                   @click="cancelEdit">取消
        </el-button>
        <el-button type="primary"
        <el-button v-if="!isOrderPage"
                   type="primary"
                   :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="产品"/>
                               label="产品" />
              <el-table-column prop="model"
                               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"
@@ -48,7 +49,7 @@
                               clearable
                               :disabled="!dataValue.isEdit"
                               style="width: 100%"
                               @visible-change="(v) => { if (v) openDialog($index) }">
                               @visible-change="(v) => { if (v) openDialog(row.tempId) }">
                      <el-option v-if="row.model"
                                 :label="row.model"
                                 :value="row.model" />
@@ -56,10 +57,10 @@
                  </el-form-item>
                </template>
              </el-table-column>
              <el-table-column prop="processId"
              <el-table-column prop="processName"
                               label="消耗工序">
                <template #default="{ row, $index }">
                  <el-form-item :prop="`dataList.${$index}.processId`"
                  <el-form-item v-if="dataValue.isEdit"
                                :rules="[{ required: true, message: '请选择消耗工序', trigger: 'change' }]"
                                style="margin: 0">
                    <el-select v-model="row.processId"
@@ -79,7 +80,7 @@
              <el-table-column prop="unitQuantity"
                               label="单位产出所需数量">
                <template #default="{ row, $index }">
                  <el-form-item :prop="`dataList.${$index}.unitQuantity`"
                  <el-form-item v-if="dataValue.isEdit"
                                :rules="[{ required: true, message: '请输入单位产出所需数量', trigger: ['blur','change'] }]"
                                style="margin: 0">
                    <el-input-number v-model="row.unitQuantity"
@@ -92,10 +93,11 @@
                  </el-form-item>
                </template>
              </el-table-column>
              <el-table-column prop="demandedQuantity"
              <el-table-column v-if="isOrderPage"
                               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"
@@ -111,7 +113,7 @@
              <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"
@@ -121,11 +123,19 @@
                  </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 type="danger"
                  <el-button v-if="dataValue.isEdit"
                             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>
@@ -133,11 +143,13 @@
          </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" />
@@ -145,133 +157,354 @@
</template>
<script setup lang="ts">
import {
  computed,
  defineAsyncComponent,
  defineComponent,
  onMounted,
  reactive,
  ref,
} from "vue";
import { queryList, add } from "@/api/productionManagement/productStructure.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 } 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";
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 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 () => {
  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 form = ref();
onMounted(() => {
  fetchData();
  fetchProcessOptions();
});
  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,
    currentRowName: null,
    loading: false,
    isEdit: false,
  });
  const tableData = reactive([
    {
      productName: "",
      model: "",
      bomNo: "",
    },
  ]);
  const openDialog = tempId => {
    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 || [];
    } else {
      // 非订单情况:使用原来的接口
      const { data } = await queryList(routeId.value);
      dataValue.dataList = data || [];
      // 为所有项及其子项设置name属性
      const setNameRecursively = items => {
        items.forEach(item => {
          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(routeId.value);
    dataValue.processOptions = data;
  };
  const handleProduct = row => {
    if (row?.length > 1) {
      ElMessage.error("只能选择一个产品");
    }
    const productData = row[0];
    // 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.model = productData.model;
        item.productModelId = productData.id;
        item.unit = productData.unit || "";
        return;
      }
      childItem(item, dataValue.currentRowName, productData);
    });
    dataValue.showProductDialog = false;
  };
  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 validateAll = () => {
    let isValid = true;
    // 校验函数
    const validateItem = item => {
      // 校验当前项的必填字段
      if (!item.model) {
        ElMessage.error("请选择规格");
        isValid = false;
        return;
      }
      if (!item.processId) {
        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);
        });
      }
    };
    // 遍历所有顶层项
    dataValue.dataList.forEach(item => {
      validateItem(item);
    });
    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 addItem = () => {
    dataValue.dataList.push({
      productName: "",
      productId: "",
      model: undefined,
      productModelId: undefined,
      processId: "",
      processName: "",
      unitQuantity: 0,
      demandedQuantity: 0,
      unit: "",
      tempId: new Date().getTime(),
    });
  };
  const removeItem = tempId => {
    // 先尝试从顶层删除
    const topIndex = dataValue.dataList.findIndex(item => item.tempId === tempId);
    if (topIndex !== -1) {
      dataValue.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;
    };
    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) {
        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, tempId) => {
    if (item.tempId === tempId) {
      console.log(item, "item");
      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;
    // dataValue.dataList = dataValue.dataList.filter(item => item.id !== undefined);
    fetchData();
  };
  onMounted(async () => {
    // 从路由参数回显数据
    tableData[0].productName = routeProductName.value;
    tableData[0].model = routeProductModelName.value;
    tableData[0].bomNo = routeBomNo.value;
    // 订单情况下禁用编辑
    if (isOrderPage.value) {
      dataValue.isEdit = false;
    }
    // 先加载工序选项,再加载数据,确保el-select能够正确回显
    await fetchProcessOptions();
    await fetchData();
  });
</script>