zouyu
9 天以前 1c0863efe062af3ebcdecb8c10568d779f5c8295
src/views/productionManagement/productStructure/Detail/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,449 @@
<template>
  <div class="app-container">
    <PageHeader content="产品结构详情">
      <template #right-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">取消
        </el-button>
        <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-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="规格">
                <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"
                    :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 || dataValue.dataList.some(item => (item as any).tempId === row.tempId)">
                      <el-option v-for="item in dataValue.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, $index }">
                  <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" :precision="2" :step="1"
                      controls-position="right" style="width: 100%"
                      :disabled="!dataValue.isEdit || dataValue.dataList.some(item => (item as any).tempId === row.tempId)" />
                  </el-form-item>
                </template>
              </el-table-column>
              <el-table-column v-if="isOrderPage" prop="demandedQuantity" label="需求总量">
                <template #default="{ row, $index }">
                  <el-form-item v-if="dataValue.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="!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 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 || dataValue.dataList.some(item => (item as any).tempId === row.tempId)" />
                  </el-form-item>
                </template>
              </el-table-column>
              <el-table-column label="操作" fixed="right" width="200">
                <template #default="{ row, $index }">
                  <el-button
                    v-if="dataValue.isEdit && !dataValue.dataList.some(item => (item as any).tempId === row.tempId)"
                    type="danger" text @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>
            </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>
    <product-select-dialog v-if="dataValue.showProductDialog" v-model:model-value="dataValue.showProductDialog"
      @confirm="handleProduct" />
  </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";
defineComponent({
  name: "StructureEdit",
});
const ProductSelectDialog = defineAsyncComponent(
  () => import("@/views/basicData/product/ProductSelectDialog.vue")
);
const emit = defineEmits(["update:router"]);
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,
  currentRowName: null,
  loading: false,
  isEdit: false,
});
const tableData = reactive([
  {
    productName: "",
    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.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.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 (!isTopLevel && !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, 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 cancelEdit = () => {
  dataValue.isEdit = false;
  // dataValue.dataList = dataValue.dataList.filter(item => item.id !== undefined);
  fetchData();
};
onMounted(async () => {
  // ä»Žè·¯ç”±å‚数回显数据
  tableData[0].productName = routeProductName.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>