zhangwencui
2026-04-24 759f41097324fa1ade4060fc838d700d8c8fa55f
src/views/productionPlan/productionPlan/index.vue
@@ -2,16 +2,19 @@
  <div class="app-container">
    <div class="search_form">
      <el-form :model="searchForm"
               ref="queryRef"
               :inline="true">
        <!-- 简化版搜索条件 -->
        <el-form-item label="主生产计划号:">
        <el-form-item label="主生产计划号:"
                      prop="mpsNo">
          <el-input v-model="searchForm.mpsNo"
                    placeholder="请输入"
                    clearable
                    style="width: 160px;"
                    @keyup.enter="handleQuery" />
        </el-form-item>
        <el-form-item label="需求日期范围:">
        <el-form-item label="需求日期范围:"
                      prop="dateRange">
          <el-date-picker v-model="searchForm.dateRange"
                          type="daterange"
                          range-separator="至"
@@ -21,7 +24,8 @@
                          style="width: 240px;"
                          @change="handleQuery" />
        </el-form-item>
        <el-form-item label="下发状态:">
        <el-form-item label="下发状态:"
                      prop="status">
          <el-select v-model="searchForm.status"
                     placeholder="请选择状态"
                     clearable
@@ -36,36 +40,22 @@
          </el-select>
        </el-form-item>
        <!-- 展开版搜索条件 -->
        <template v-if="searchFormExpanded">
          <el-form-item label="产品名称:">
            <el-input v-model="searchForm.productName"
                      placeholder="请输入"
                      clearable
                      style="width: 160px;"
                      @keyup.enter="handleQuery" />
          </el-form-item>
          <el-form-item label="产品规格:">
            <el-input v-model="searchForm.model"
                      placeholder="请输入"
                      clearable
                      style="width: 160px;"
                      @keyup.enter="handleQuery" />
          </el-form-item>
          <el-form-item label="物料编码:">
            <el-input v-model="searchForm.materialCode"
                      placeholder="请输入"
                      clearable
                      style="width: 160px;"
                      @keyup.enter="handleQuery" />
          </el-form-item>
          <el-form-item label="申请单编号:">
            <el-input v-model="searchForm.applyNo"
                      placeholder="请输入"
                      clearable
                      style="width: 160px;"
                      @keyup.enter="handleQuery" />
          </el-form-item>
        </template>
        <el-form-item label="产品名称:"
                      prop="productName">
          <el-input v-model="searchForm.productName"
                    placeholder="请输入"
                    clearable
                    style="width: 160px;"
                    @keyup.enter="handleQuery" />
        </el-form-item>
        <el-form-item label="产品规格:"
                      prop="model">
          <el-input v-model="searchForm.model"
                    placeholder="请输入"
                    clearable
                    style="width: 160px;"
                    @keyup.enter="handleQuery" />
        </el-form-item>
        <el-form-item>
          <el-button type="primary"
                     @click="handleQuery">搜索</el-button>
@@ -74,6 +64,8 @@
          <el-button type="primary"
                     @click="handleAdd">新增</el-button>
          <el-button type="warning"
                     @click="handleMerge">合并下发</el-button>
          <el-button type="warning"
                     @click="handleImport">导入</el-button>
          <el-button type="warning"
                     @click="handleExport">导出</el-button>
@@ -81,16 +73,6 @@
      </el-form>
      <div>
      </div>
    </div>
    <div class="search-header">
      <el-button type="text"
                 @click="toggleSearchForm">
        <el-icon>
          <ArrowUp v-if="searchFormExpanded" />
          <ArrowDown v-else />
        </el-icon>
        {{ searchFormExpanded ? '收起搜索条件' : '展开搜索条件' }}
      </el-button>
    </div>
    <div class="table_list">
      <PIMTable rowKey="id"
@@ -117,23 +99,16 @@
               label-width="120px">
        <el-row :gutter="20">
          <el-col :span="10">
            <el-form-item label="物料编码">
              <div class="info-display">{{ mergeForm.materialCode || '-' }}</div>
            </el-form-item>
          </el-col>
          <el-col :span="10">
            <el-form-item label="产品名称">
              <el-tag class="info-display">{{ mergeForm.productName || '-' }}</el-tag>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="10">
          <el-col>
            <el-form-item label="产品规格">
              <div class="info-display">{{ mergeForm.model || '-' }}</div>
            </el-form-item>
          </el-col>
          <el-col :span="10">
          </el-col>
        </el-row>
        <el-form-item label="计划完成时间">
@@ -142,7 +117,7 @@
                          value-format="YYYY-MM-DD"
                          style="width: 100%" />
        </el-form-item>
        <el-form-item label="生产方数">
        <el-form-item label="生产数量">
          <el-input-number v-model="mergeForm.totalAssignedQuantity"
                           :min="0"
                           :max="sumAssignedQuantity"
@@ -182,16 +157,12 @@
        <el-form-item label="主生产计划号"
                      prop="mpsNo">
          <el-input v-model="form.mpsNo"
                    placeholder="请输入主生产计划号" />
        </el-form-item>
        <el-form-item label="申请单编号"
                      prop="applyNo">
          <el-input v-model="form.applyNo"
                    placeholder="请输入申请单编号" />
                    disabled
                    placeholder="新增后自动生成" />
        </el-form-item>
        <el-form-item label="产品名称"
                      prop="productMaterialId">
          <el-tree-select v-model="form.productMaterialId"
                      prop="productId">
          <el-tree-select v-model="form.productId"
                          placeholder="请选择"
                          clearable
                          :data="productOptions"
@@ -279,6 +250,7 @@
    productionPlanAdd,
    productionPlanUpdate,
    productionPlanDelete,
    productionPlanCombine,
  } from "@/api/productionPlan/productionPlan.js";
  import { productTreeList, modelListPage } from "@/api/basicData/product.js";
  import PIMTable from "./components/PIMTable.vue";
@@ -297,10 +269,10 @@
    return Promise.resolve();
  };
  const productionPlanCombine = payload => {
    console.log("Mock productionPlanCombine called with:", payload);
    return Promise.resolve({ code: 200, msg: "合并下发成功" });
  };
  // const productionPlanCombine = payload => {
  //   console.log("Mock productionPlanCombine called with:", payload);
  //   return Promise.resolve({ code: 200, msg: "合并下发成功" });
  // };
  const tableColumn = ref([
    {
@@ -309,14 +281,13 @@
      width: "150px",
    },
    {
      label: "申请单编号",
      prop: "applyNo",
      label: "来源",
      prop: "source",
      width: "150px",
    },
    {
      label: "物料编码",
      prop: "materialCode",
      width: "150px",
      dataType: "tag",
      formatType: params => {
        return params == "内部" ? "info" : "primary";
      },
    },
    {
      label: "产品名称",
@@ -401,7 +372,7 @@
      label: "操作",
      align: "center",
      fixed: "right",
      width: 150,
      width: 250,
      operation: [
        {
          name: "编辑",
@@ -412,6 +383,23 @@
          },
          clickFun: row => {
            handleEdit(row);
          },
        },
        {
          name: "下发",
          type: "text",
          showHide: row => {
            return row.status == 0;
          },
          clickFun: row => {
            mergeForm.productName = row.productName || "";
            mergeForm.model = row.model || "";
            mergeForm.totalAssignedQuantity = Number(row.qtyRequired || 0);
            mergeForm.planCompleteTime = row.requiredDate || "";
            mergeForm.productId = row.productId || "";
            mergeForm.ids = [row.id];
            sumAssignedQuantity.value = Number(row.qtyRequired || 0);
            isShowNewModal.value = true;
          },
        },
        {
@@ -446,12 +434,11 @@
  const isShowNewModal = ref(false);
  // 合并下发表单数据
  const mergeForm = reactive({
    materialCode: "",
    productName: "",
    model: "",
    totalAssignedQuantity: 0,
    planCompleteTime: "",
    productMaterialId: "",
    productId: "",
  });
  // 导入相关
@@ -468,16 +455,15 @@
  const operationType = ref("add"); // add | edit
  const productOptions = ref([]);
  const specificationOptions = ref([]);
  const queryRef = ref(null);
  const formRef = ref(null);
  const form = reactive({
    id: undefined,
    mpsNo: "",
    applyNo: "",
    productMaterialId: undefined,
    productId: undefined,
    productModelId: undefined,
    productName: "",
    model: "",
    materialCode: "",
    qtyRequired: 0,
    unit: "方",
    requiredDate: "",
@@ -485,11 +471,7 @@
    remark: "",
  });
  const rules = reactive({
    mpsNo: [{ required: true, message: "请输入主生产计划号", trigger: "blur" }],
    applyNo: [{ required: true, message: "请输入申请单编号", trigger: "blur" }],
    productMaterialId: [
      { required: true, message: "请选择产品", trigger: "change" },
    ],
    productId: [{ required: true, message: "请选择产品", trigger: "change" }],
    productModelId: [
      { required: true, message: "请选择产品规格", trigger: "change" },
    ],
@@ -506,7 +488,6 @@
      path: "/productionPlan/trackProgress",
      query: {
        id: row.id,
        applyNo: row.applyNo,
        productName: row.productName,
        model: row.model,
      },
@@ -539,7 +520,6 @@
  const handleProductChange = value => {
    form.productModelId = undefined;
    form.model = undefined;
    form.materialCode = undefined;
    // 查找选中的产品名称
    const findProductName = (options, val) => {
      for (const option of options) {
@@ -569,14 +549,12 @@
  };
  const handleChangeSpecification = value => {
    form.materialCode = undefined;
    form.model = undefined;
    form.unit = "";
    const selectedModel = specificationOptions.value.find(
      item => item.id === value
    );
    if (selectedModel) {
      form.materialCode = selectedModel.materialCode;
      form.model = selectedModel.model;
      form.unit = selectedModel.unit || "方";
    }
@@ -587,8 +565,7 @@
      mpsNo: "",
      productName: "",
      model: "",
      materialCode: "",
      applyNo: "",
      status: "",
      dateRange: [],
    },
    searchFormExpanded: false,
@@ -609,12 +586,14 @@
  /** 重置按钮操作 */
  const handleReset = () => {
    if (proxy.resetForm) {
      proxy.resetForm("queryRef");
    }
    Object.assign(searchForm.value, {
      mpsNo: "",
      productName: "",
      model: "",
      materialCode: "",
      applyNo: "",
      status: "",
      dateRange: [],
    });
    page.current = 1;
@@ -631,16 +610,18 @@
    // 遍历表格数据,按产品类别汇总
    tableData.value.forEach(row => {
      const category = row.materialCode;
      const category = row.productName || "未知产品";
      if (!summary[category]) {
        summary[category] = {
          materialCode: category,
          totalAssignedQuantity: 0,
        };
      }
      summary[category].totalAssignedQuantity += (
        Number(row.qtyRequired) - Number(row.assignedQuantity)
      ).toFixed(4);
      summary[category].totalAssignedQuantity += Number(
        (
          Number(row.qtyRequired || 0) - Number(row.assignedQuantity || 0)
        ).toFixed(4)
      );
    });
    // 转换为数组格式
@@ -651,8 +632,10 @@
    tableLoading.value = true;
    // 构造搜索参数
    const params = { ...searchForm.value, ...page };
    params.requiredDateStart = params.dateRange ? params.dateRange[0] : "";
    params.requiredDateEnd = params.dateRange ? params.dateRange[1] : "";
    params.requiredDateStart =
      params.dateRange && params.dateRange.length > 0 ? params.dateRange[0] : "";
    params.requiredDateEnd =
      params.dateRange && params.dateRange.length > 1 ? params.dateRange[1] : "";
    delete params.dateRange;
    productionPlanListPage(params)
      .then(res => {
@@ -667,18 +650,18 @@
      });
  };
  // 选中的序列号
  const selectedserialNo = ref("");
  // 选中的产品规格ID
  const selectedProductModelId = ref("");
  // 表格选择数据
  const handleSelectionChange = selection => {
    selectedRows.value = selection;
    // 如果有选中的行,记录第一个选中行的序列号
    // 如果有选中的行,记录第一个选中行的产品规格ID
    if (selection.length > 0) {
      selectedserialNo.value = selection[0].materialCode;
      selectedProductModelId.value = selection[0].productModelId;
    } else {
      // 如果没有选中的行,清空序列号
      selectedserialNo.value = "";
      // 如果没有选中的行,清空产品规格ID
      selectedProductModelId.value = "";
    }
  };
@@ -691,11 +674,11 @@
      return false;
    }
    // 如果没有选中的行,所有行都可选择
    if (!selectedserialNo.value) {
    if (!selectedProductModelId.value) {
      return true;
    }
    // 如果有选中的行,只有序列号相同的行才可选择
    return row.materialCode === selectedserialNo.value;
    // 如果有选中的行,只有产品规格ID相同的行才可选择
    return row.productModelId === selectedProductModelId.value;
  };
  // 拉取数据按钮操作
  const loadProdDataLoading = ref(false);
@@ -711,26 +694,18 @@
    const firstRow = selectedRows.value[0];
    const productName = firstRow.productName || "";
    // 计算总制造数量
    // 计算总制造数量 (默认qtyRequired的和)
    const totalAssignedQuantity = selectedRows.value.reduce((sum, row) => {
      return (
        sum +
        (row.qtyRequired == null
          ? 0
          : Number(
              Number(row.qtyRequired) - Number(row.assignedQuantity).toFixed(4)
            ))
      );
      return sum + Number(row.qtyRequired || 0);
    }, 0);
    sumAssignedQuantity.value = totalAssignedQuantity;
    console.log(totalAssignedQuantity);
    // 设置表单数据
    mergeForm.materialCode = selectedserialNo.value;
    mergeForm.productName = productName;
    mergeForm.model = firstRow.model || "";
    mergeForm.totalAssignedQuantity = totalAssignedQuantity;
    mergeForm.planCompleteTime = firstRow.planCompleteTime || "";
    mergeForm.productMaterialId = firstRow.productMaterialId || "";
    mergeForm.planCompleteTime = firstRow.requiredDate || "";
    mergeForm.productId = firstRow.productId || "";
    mergeForm.ids = selectedRows.value.map(row => row.id);
    // 打开弹窗
@@ -740,18 +715,14 @@
  // 处理合并下发提交
  const handleMergeSubmit = () => {
    if (mergeForm.totalAssignedQuantity === 0) {
      ElMessage.warning("请输入生产方数");
      ElMessage.warning("请输入生产数量");
      return;
    }
    console.log(sumAssignedQuantity.value, "sumAssignedQuantity");
    // 计算当前选中行的总数量
    const totalVolume = selectedRows.value.reduce((sum, row) => {
      return sum + (Number(row.qtyRequired) - Number(row.assignedQuantity) || 0);
    }, 0);
    // 验证totalAssignedQuantity不能大于总方数
    if (mergeForm.totalAssignedQuantity > sumAssignedQuantity.value) {
      ElMessage.error("生产方数不能大于当前计算的总值");
      ElMessage.error("生产数量不能大于当前计算的总值");
      return;
    }
@@ -861,12 +832,10 @@
    Object.assign(form, {
      id: undefined,
      mpsNo: "",
      applyNo: "",
      productName: "",
      productMaterialId: undefined,
      productId: undefined,
      productModelId: undefined,
      model: "",
      materialCode: "",
      qtyRequired: 0,
      unit: "方",
      requiredDate: "",
@@ -883,12 +852,10 @@
    Object.assign(form, {
      id: row.id,
      mpsNo: row.mpsNo || "",
      applyNo: row.applyNo || "",
      productName: row.productName || "",
      productMaterialId: row.productMaterialId || undefined,
      productId: row.productId || undefined,
      productModelId: row.productModelId || undefined,
      model: row.model || "",
      materialCode: row.materialCode || "",
      qtyRequired: row.qtyRequired || 0,
      unit: row.unit || "方",
      requiredDate: row.requiredDate || "",
@@ -897,7 +864,7 @@
    });
    dialogVisible.value = true;
    fetchProductOptions();
    fetchSpecificationOptions(row.productMaterialId);
    fetchSpecificationOptions(row.productId);
  };
  // 删除
@@ -1178,6 +1145,7 @@
    color: #303133;
    font-size: 14px;
    min-height: 32px;
    width: 100%;
    display: flex;
    align-items: center;
  }