yyb
7 小时以前 04d6024553ac73e67148ce578cb01b541eebd02a
src/views/productionPlan/productionPlan/index.vue
@@ -2,16 +2,27 @@
  <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="salesContractNo">
          <el-input v-model="searchForm.salesContractNo"
                    placeholder="请输入"
                    clearable
                    style="width: 160px;"
                    @keyup.enter="handleQuery" />
        </el-form-item>
        <el-form-item label="需求日期范围:"
                      prop="dateRange">
          <el-date-picker v-model="searchForm.dateRange"
                          type="daterange"
                          range-separator="至"
@@ -21,7 +32,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 +48,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 +72,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 +81,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"
@@ -106,6 +96,13 @@
        <template #qtyRequired="{ row }">
          {{ row.qtyRequired || '-' }}<span style="color:rgba(12, 46, 40, 0.76)"> {{ row.unit || '方' }}</span>
        </template>
        <template #salesContractNo="{ row }">
          <el-button type="primary"
                     text
                     link
                     @click="showDetail(row)">{{ row.salesContractNo }}
          </el-button>
        </template>
      </PIMTable>
    </div>
    <!-- 合并下发弹窗 -->
@@ -117,23 +114,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 +132,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"
@@ -152,9 +142,9 @@
      </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="isShowNewModal = false">取消</el-button>
          <el-button type="primary"
                     @click="handleMergeSubmit">确定下发</el-button>
          <el-button @click="isShowNewModal = false">取消</el-button>
        </span>
      </template>
    </el-dialog>
@@ -182,16 +172,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"
@@ -250,9 +236,9 @@
      </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="dialogVisible = false">取消</el-button>
          <el-button type="primary"
                     @click="handleSubmit">确定</el-button>
          <el-button @click="dialogVisible = false">取消</el-button>
        </span>
      </template>
    </el-dialog>
@@ -279,6 +265,8 @@
    productionPlanAdd,
    productionPlanUpdate,
    productionPlanDelete,
    productionPlanCombine,
    exportProductionPlan,
  } from "@/api/productionPlan/productionPlan.js";
  import { productTreeList, modelListPage } from "@/api/basicData/product.js";
  import PIMTable from "./components/PIMTable.vue";
@@ -292,15 +280,10 @@
    return Promise.resolve({ code: 200, msg: "同步成功" });
  };
  const exportProductionPlan = () => {
    console.log("Mock exportProductionPlan called");
    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,15 +292,18 @@
      width: "150px",
    },
    {
      label: "申请单编号",
      prop: "applyNo",
      label: "来源",
      prop: "source",
      width: "150px",
      dataType: "tag",
      formatType: params => {
        return params == "销售" ? "primary" : "info";
      },
      formatData: params => {
        return params == "销售" ? "销售" : "内部";
      },
    },
    {
      label: "物料编码",
      prop: "materialCode",
      width: "150px",
    },
    {
      label: "产品名称",
      prop: "productName",
@@ -372,7 +358,7 @@
    },
    {
      label: "已下发数量",
      prop: "assignedQuantity",
      prop: "quantityIssued",
      width: "120px",
      className: "spec-cell",
      // formatData: (cell, row) => (cell ? `${cell}${row.unit || "方"}` : 0),
@@ -392,6 +378,23 @@
      formatData: cell => (cell ? dayjs(cell).format("YYYY-MM-DD") : ""),
    },
    {
      label: "销售合同号",
      prop: "salesContractNo",
      width: "200px",
      dataType: "slot",
      slot: "salesContractNo",
    },
    {
      label: "客户名称",
      prop: "customerName",
      width: "150px",
    },
    {
      label: "项目名称",
      prop: "projectName",
      width: "150px",
    },
    {
      label: "备注",
      width: "150px",
      prop: "remark",
@@ -401,17 +404,36 @@
      label: "操作",
      align: "center",
      fixed: "right",
      width: 150,
      width: 250,
      operation: [
        {
          name: "编辑",
          type: "primary",
          link: true,
          showHide: row => {
            return row.status == 0;
            return row.status == 0 && row.source != "销售";
          },
          clickFun: row => {
            handleEdit(row);
          },
        },
        {
          name: "下发",
          type: "text",
          showHide: row => {
            return row.status != 2;
          },
          clickFun: row => {
            mergeForm.productName = row.productName || "";
            mergeForm.model = row.model || "";
            mergeForm.totalAssignedQuantity =
              Number(row.qtyRequired || 0) - Number(row.quantityIssued || 0);
            mergeForm.planCompleteTime = row.requiredDate || "";
            mergeForm.productId = row.productId || "";
            mergeForm.ids = [row.id];
            sumAssignedQuantity.value =
              Number(row.qtyRequired || 0) - Number(row.quantityIssued || 0);
            isShowNewModal.value = true;
          },
        },
        {
@@ -446,12 +468,11 @@
  const isShowNewModal = ref(false);
  // 合并下发表单数据
  const mergeForm = reactive({
    materialCode: "",
    productName: "",
    model: "",
    totalAssignedQuantity: 0,
    planCompleteTime: "",
    productMaterialId: "",
    productId: "",
  });
  // 导入相关
@@ -468,16 +489,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 +505,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 +522,6 @@
      path: "/productionPlan/trackProgress",
      query: {
        id: row.id,
        applyNo: row.applyNo,
        productName: row.productName,
        model: row.model,
      },
@@ -539,7 +554,6 @@
  const handleProductChange = value => {
    form.productModelId = undefined;
    form.model = undefined;
    form.materialCode = undefined;
    // 查找选中的产品名称
    const findProductName = (options, val) => {
      for (const option of options) {
@@ -569,14 +583,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 || "方";
    }
@@ -585,10 +597,10 @@
  const data = reactive({
    searchForm: {
      mpsNo: "",
      salesContractNo: "",
      productName: "",
      model: "",
      materialCode: "",
      applyNo: "",
      status: "",
      dateRange: [],
    },
    searchFormExpanded: false,
@@ -609,12 +621,15 @@
  /** 重置按钮操作 */
  const handleReset = () => {
    if (proxy.resetForm) {
      proxy.resetForm("queryRef");
    }
    Object.assign(searchForm.value, {
      mpsNo: "",
      salesContractNo: "",
      productName: "",
      model: "",
      materialCode: "",
      applyNo: "",
      status: "",
      dateRange: [],
    });
    page.current = 1;
@@ -631,16 +646,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.quantityIssued || 0)).toFixed(
          4
        )
      );
    });
    // 转换为数组格式
@@ -651,8 +668,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,35 +686,39 @@
      });
  };
  // 选中的序列号
  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 = "";
    }
  };
  // 判断行是否可选择
  const isSelectable = row => {
    // 如果是已下发状态,禁止勾选
    if (row.status == 2) {
      return false;
    }
    // 计算剩余数量
    const remainingQty = (row.qtyRequired || 0) - (row.assignedQuantity || 0);
    const remainingQty = (row.qtyRequired || 0) - (row.quantityIssued || 0);
    // 如果剩余数量小于等于0,禁止选择
    if (remainingQty <= 0) {
      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,47 +734,43 @@
    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) - Number(row.quantityIssued || 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);
    // 打开弹窗
    isShowNewModal.value = true;
  };
  const showDetail = row => {
    router.push({
      path: "/salesManagement/salesLedger",
      query: {
        salesContractNo: row.salesContractNo,
      },
    });
  };
  // 处理合并下发提交
  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 +880,10 @@
    Object.assign(form, {
      id: undefined,
      mpsNo: "",
      applyNo: "",
      productName: "",
      productMaterialId: undefined,
      productId: undefined,
      productModelId: undefined,
      model: "",
      materialCode: "",
      qtyRequired: 0,
      unit: "方",
      requiredDate: "",
@@ -883,12 +900,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 +912,7 @@
    });
    dialogVisible.value = true;
    fetchProductOptions();
    fetchSpecificationOptions(row.productMaterialId);
    fetchSpecificationOptions(row.productId);
  };
  // 删除
@@ -1178,6 +1193,7 @@
    color: #303133;
    font-size: 14px;
    min-height: 32px;
    width: 100%;
    display: flex;
    align-items: center;
  }