zhangwencui
2026-04-29 7d9414ea1746d4ac7175ae27062620e03eb83f38
本次生产数量字段改为生产合格数量的逻辑
已修改3个文件
742 ■■■■ 文件已修改
src/views/productionManagement/productionCosting/index.vue 700 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/workOrder/index.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/workOrderManagement/index.vue 40 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/productionCosting/index.vue
@@ -1,373 +1,389 @@
<template>
    <div class="app-container">
        <div class="table_list">
            <el-row :gutter="16" class="content-row">
                <!-- 左侧台账 + 顶部筛选 -->
                <el-col :xs="24" :sm="24" :md="24" :lg="8" :xl="8" class="left-col">
                    <div class="left-panel">
                        <div class="left-header">
                            <el-form :model="searchForm" inline>
                                <el-form-item prop="dateType">
                                    <el-radio-group v-model="searchForm.dateType" size="small" @change="handleDateTypeChange">
                                        <el-radio-button label="day">日</el-radio-button>
                                        <el-radio-button label="month">月</el-radio-button>
                                    </el-radio-group>
                                </el-form-item>
                                <el-form-item label="日期:" prop="dateRange">
                                    <el-date-picker
                                        v-model="searchForm.dateRange"
                                        :type="searchForm.dateType === 'day' ? 'date' : 'daterange'"
                                        range-separator="至"
                                        start-placeholder="开始日期"
                                        end-placeholder="结束日期"
                                        format="YYYY-MM-DD"
                                        value-format="YYYY-MM-DD"
                                        style="width: 200px"
                                        @change="handleDateRangeChange"
                                    />
                                </el-form-item>
                            </el-form>
                        </div>
                        <PIMTable
                            rowKey="id"
                            :column="leftTableColumn"
                            :tableData="leftTableData"
                            :tableLoading="tableLoading"
                            :page="page"
                            @row-click="handleLeftRowClick"
                            @pagination="pagination"
                        ></PIMTable>
                    </div>
                </el-col>
                <!-- 右侧明细 -->
                <el-col :xs="24" :sm="24" :md="24" :lg="16" :xl="16" class="right-col">
                    <div class="right-panel">
                        <el-form inline>
                            <el-form-item>
                                <el-button type="primary" @click="handleOut">导出</el-button>
                            </el-form-item>
                        </el-form>
                        <PIMTable
                            rowKey="id"
                            :column="tableColumn"
                            :tableData="tableData"
                            :page="page1"
                            :tableLoading="tableLoading1"
                            style="margin-right: 20px;"
                            @pagination="pagination1"
                        ></PIMTable>
                    </div>
                </el-col>
            </el-row>
        </div>
    </div>
  <div class="app-container">
    <div class="table_list">
      <el-row :gutter="16"
              class="content-row">
        <!-- 左侧台账 + 顶部筛选 -->
        <el-col :xs="24"
                :sm="24"
                :md="24"
                :lg="8"
                :xl="8"
                class="left-col">
          <div class="left-panel">
            <div class="left-header">
              <el-form :model="searchForm"
                       inline>
                <el-form-item prop="dateType">
                  <el-radio-group v-model="searchForm.dateType"
                                  size="small"
                                  @change="handleDateTypeChange">
                    <el-radio-button label="day">日</el-radio-button>
                    <el-radio-button label="month">月</el-radio-button>
                  </el-radio-group>
                </el-form-item>
                <el-form-item label="日期:"
                              prop="dateRange">
                  <el-date-picker v-model="searchForm.dateRange"
                                  :type="searchForm.dateType === 'day' ? 'date' : 'daterange'"
                                  range-separator="至"
                                  start-placeholder="开始日期"
                                  end-placeholder="结束日期"
                                  format="YYYY-MM-DD"
                                  value-format="YYYY-MM-DD"
                                  style="width: 200px"
                                  @change="handleDateRangeChange" />
                </el-form-item>
              </el-form>
            </div>
            <PIMTable rowKey="id"
                      :column="leftTableColumn"
                      :tableData="leftTableData"
                      :tableLoading="tableLoading"
                      :page="page"
                      @row-click="handleLeftRowClick"
                      @pagination="pagination"></PIMTable>
          </div>
        </el-col>
        <!-- 右侧明细 -->
        <el-col :xs="24"
                :sm="24"
                :md="24"
                :lg="16"
                :xl="16"
                class="right-col">
          <div class="right-panel">
            <el-form inline>
              <el-form-item>
                <el-button type="primary"
                           @click="handleOut">导出</el-button>
              </el-form-item>
            </el-form>
            <PIMTable rowKey="id"
                      :column="tableColumn"
                      :tableData="tableData"
                      :page="page1"
                      :tableLoading="tableLoading1"
                      style="margin-right: 20px;"
                      @pagination="pagination1"></PIMTable>
          </div>
        </el-col>
      </el-row>
    </div>
  </div>
</template>
<script setup>
import {onMounted, ref} from "vue";
import { ElMessageBox } from "element-plus";
import dayjs from "dayjs";
import {salesLedgerProductionAccountingListProductionDetails, salesLedgerProductionAccountingList} from "@/api/productionManagement/productionCosting.js";
const { proxy } = getCurrentInstance();
  import { onMounted, ref } from "vue";
  import { ElMessageBox } from "element-plus";
  import dayjs from "dayjs";
  import {
    salesLedgerProductionAccountingListProductionDetails,
    salesLedgerProductionAccountingList,
  } from "@/api/productionManagement/productionCosting.js";
  const { proxy } = getCurrentInstance();
const tableColumn = ref([
    {
        label: "生产日期",
        prop: "schedulingDate",
    minWidth: 100,
    },
    {
        label: "生产人",
        prop: "schedulingUserName",
    minWidth: 100,
    },
    {
        label: "合同号",
        prop: "salesContractNo",
    minWidth: 100,
    },
    {
        label: "客户名称",
        prop: "customerName",
    minWidth: 100,
    },
    {
        label: "产品大类",
        prop: "productName",
    minWidth: 100,
    },
    {
        label: "规格型号",
        prop: "productModelName",
    minWidth: 100,
    },
    {
        label: "单位",
        prop: "unit",
    minWidth: 100,
    },
    {
        label: "工序",
        prop: "process",
    minWidth: 100,
    },
    {
        label: "生产数量",
        prop: "quantity",
    minWidth: 100,
    },
    {
        label: "工时定额",
        prop: "workHours",
    minWidth: 100,
    },
    {
        label: "工资",
        prop: "wages",
    minWidth: 100,
    },
]);
// 左侧汇总台账列(生产人、产量、工资、合格率)
const leftTableColumn = ref([
    {
        label: "生产人",
        prop: "schedulingUserName",
    minWidth: 100,
    },
    {
        label: "产量",
        prop: "outputNum",
    minWidth: 100,
  },
    {
        label: "工资",
        prop: "wages",
    minWidth: 100,
    },
    {
        label: "合格率",
        prop: "outputRate",
    minWidth: 100,
    formatData: (val) => {
      if (val == null || val === '') return '-'
      return parseFloat(val).toFixed(2)
  const tableColumn = ref([
    {
      label: "生产日期",
      prop: "schedulingDate",
      minWidth: 100,
    },
    },
]);
    {
      label: "生产人",
      prop: "schedulingUserName",
      minWidth: 100,
    },
    // {
    //   label: "合同号",
    //   prop: "salesContractNo",
    //   minWidth: 100,
    // },
    // {
    //   label: "客户名称",
    //   prop: "customerName",
    //   minWidth: 100,
    // },
    {
      label: "产品大类",
      prop: "productName",
      minWidth: 100,
    },
    {
      label: "规格型号",
      prop: "productModelName",
      minWidth: 100,
    },
    {
      label: "单位",
      prop: "unit",
      minWidth: 100,
    },
    {
      label: "工序",
      prop: "process",
      minWidth: 100,
    },
    {
      label: "生产数量",
      prop: "quantity",
      minWidth: 100,
    },
    {
      label: "工时定额",
      prop: "workHours",
      minWidth: 100,
    },
    {
      label: "工资",
      prop: "wages",
      minWidth: 100,
    },
  ]);
const tableData = ref([]);
const tableLoading = ref(false);
const tableLoading1 = ref(false);
const leftTableData = ref([]);
// 日 / 月 切换(默认按日)
const page = reactive({
    current: 1,
    size: 100,
    total: 0,
});
  // 左侧汇总台账列(生产人、产量、工资、合格率)
  const leftTableColumn = ref([
    {
      label: "生产人",
      prop: "schedulingUserName",
      minWidth: 100,
    },
    {
      label: "产量",
      prop: "finishedNum",
      minWidth: 100,
    },
    {
      label: "工资",
      prop: "wages",
      minWidth: 100,
    },
    {
      label: "合格率",
      prop: "outputRate",
      minWidth: 100,
      formatData: val => {
        if (val == null || val === "") return "-";
        return parseFloat(val).toFixed(2);
      },
    },
  ]);
const page1 = reactive({
  current: 1,
  size: 100,
  total: 0,
});
  const tableData = ref([]);
  const tableLoading = ref(false);
  const tableLoading1 = ref(false);
  const leftTableData = ref([]);
  // 日 / 月 切换(默认按日)
  const page = reactive({
    current: 1,
    size: 100,
    total: 0,
  });
const data = reactive({
    searchForm: {
        schedulingUserName: "",
        salesContractNo: "",
    dateType: "day",
    dateRange: dayjs().format("YYYY-MM-DD"),
        entryDate: dayjs().format("YYYY-MM-DD"),
        entryDateStart: undefined,
        entryDateEnd: undefined,
    },
});
const { searchForm } = toRefs(data);
  const page1 = reactive({
    current: 1,
    size: 100,
    total: 0,
  });
const pagination = (obj) => {
    page.current = obj.page;
    page.size = obj.limit;
    getList();
};
  const data = reactive({
    searchForm: {
      schedulingUserName: "",
      salesContractNo: "",
      dateType: "day",
      dateRange: dayjs().format("YYYY-MM-DD"),
      entryDate: dayjs().format("YYYY-MM-DD"),
      entryDateStart: undefined,
      entryDateEnd: undefined,
    },
  });
  const { searchForm } = toRefs(data);
const pagination1 = (obj) => {
  page1.current = obj.page;
  page1.size = obj.limit;
    getList1();
};
  const pagination = obj => {
    page.current = obj.page;
    page.size = obj.limit;
    getList();
  };
const handleDateRangeChange = (value) => {
    if (value) {
    if (searchForm.value.dateType === "day") {
      searchForm.value.entryDate = value;
  const pagination1 = obj => {
    page1.current = obj.page;
    page1.size = obj.limit;
    getList1();
  };
  const handleDateRangeChange = value => {
    if (value) {
      if (searchForm.value.dateType === "day") {
        searchForm.value.entryDate = value;
      } else {
        searchForm.value.entryDateStart = dayjs(value[0]).format("YYYY-MM-DD");
        searchForm.value.entryDateEnd = dayjs(value[1]).format("YYYY-MM-DD");
      }
    } else {
      searchForm.value.entryDateStart = dayjs(value[0]).format("YYYY-MM-DD");
      searchForm.value.entryDateEnd = dayjs(value[1]).format("YYYY-MM-DD");
      searchForm.value.entryDate = undefined;
      searchForm.value.entryDateStart = undefined;
      searchForm.value.entryDateEnd = undefined;
    }
    reloadData();
  };
  const getList = () => {
    tableLoading.value = true;
    const params = { ...searchForm.value, ...page };
    salesLedgerProductionAccountingList(params)
      .then(res => {
        const records = res.data.records || [];
        leftTableData.value = records;
        page.total = res.data.total || 0;
      })
      .finally(() => {
        tableLoading.value = false;
      });
  };
  const getList1 = () => {
    tableLoading1.value = true;
    const params = { ...page1, ...searchForm.value };
    salesLedgerProductionAccountingListProductionDetails(params)
      .then(res => {
        tableData.value = res.data.records || [];
        page1.total = res.data.total || 0;
      })
      .finally(() => {
        tableLoading1.value = false;
      });
  };
  // 构建左侧汇总台账(按生产人汇总产量、工资等)
  const buildLeftTableData = records => {
    const map = {};
    records.forEach(item => {
      const key = item.schedulingUserName || "未知";
      if (!map[key]) {
        map[key] = {
          id: key,
          schedulingUserName: key,
          finishedNum: 0,
          wages: 0,
          qualifiedRate: item.qualifiedRate ?? null,
        };
      }
      map[key].finishedNum += Number(item.finishedNum || 0);
      map[key].wages += Number(item.wages || 0);
      if (item.qualifiedRate != null) {
        map[key].qualifiedRate = item.qualifiedRate;
      }
    });
    leftTableData.value = Object.values(map);
  };
  // 左侧日/月切换
  const handleDateTypeChange = value => {
    // 这里只作为筛选条件的一部分,直接重新查询列表
    if (value === "day") {
      searchForm.value.entryDate = dayjs().format("YYYY-MM-DD");
      searchForm.value.dateRange = searchForm.value.entryDate;
    } else {
      searchForm.value.entryDateStart = dayjs()
        .startOf("month")
        .format("YYYY-MM-DD");
      searchForm.value.entryDateEnd = dayjs().endOf("month").format("YYYY-MM-DD");
      searchForm.value.dateRange = [
        searchForm.value.entryDateStart,
        searchForm.value.entryDateEnd,
      ];
    }
    } else {
        searchForm.value.entryDate = undefined;
        searchForm.value.entryDateStart = undefined;
        searchForm.value.entryDateEnd = undefined;
    }
  reloadData()
};
    reloadData();
  };
const getList = () => {
    tableLoading.value = true;
    const params = { ...searchForm.value, ...page };
  const reloadData = () => {
    page.current = 1;
    page1.current = 1;
    getList();
    tableData.value = [];
  };
  salesLedgerProductionAccountingList(params).then((res) => {
        const records = res.data.records || [];
    leftTableData.value = records;
        page.total = res.data.total || 0;
    }).finally(() => {
    tableLoading.value = false;
  })
  // 点击左侧行,刷右侧明细(按生产人过滤)
  const handleLeftRowClick = row => {
    searchForm.value.schedulingUserName = row.schedulingUserName || "";
    handleQuery();
  };
  // 查询列表
  /** 搜索按钮操作 */
  const handleQuery = () => {
    page1.current = 1;
    getList1();
  };
  // 导出
  const handleOut = () => {
    ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", {
      confirmButtonText: "确认",
      cancelButtonText: "取消",
      type: "warning",
    })
      .then(() => {
        proxy.download(
          "/salesLedger/productionAccounting/export",
          {},
          "生产核算.xlsx"
        );
      })
      .catch(() => {
        proxy.$modal.msg("已取消");
      });
  };
};
const getList1 = () => {
  tableLoading1.value = true;
  const params = { ...page1, ...searchForm.value };
  salesLedgerProductionAccountingListProductionDetails(params).then((res) => {
    tableData.value = res.data.records || [];;
    page1.total = res.data.total || 0;
  }).finally(() => {
    tableLoading1.value = false;
  })
};
// 构建左侧汇总台账(按生产人汇总产量、工资等)
const buildLeftTableData = (records) => {
    const map = {};
    records.forEach((item) => {
        const key = item.schedulingUserName || "未知";
        if (!map[key]) {
            map[key] = {
                id: key,
                schedulingUserName: key,
                finishedNum: 0,
                wages: 0,
                qualifiedRate: item.qualifiedRate ?? null,
            };
        }
        map[key].finishedNum += Number(item.finishedNum || 0);
        map[key].wages += Number(item.wages || 0);
        if (item.qualifiedRate != null) {
            map[key].qualifiedRate = item.qualifiedRate;
        }
    });
    leftTableData.value = Object.values(map);
};
// 左侧日/月切换
const handleDateTypeChange = (value) => {
    // 这里只作为筛选条件的一部分,直接重新查询列表
  if (value === "day") {
    searchForm.value.entryDate = dayjs().format("YYYY-MM-DD");
    searchForm.value.dateRange = searchForm.value.entryDate
  } else {
    searchForm.value.entryDateStart = dayjs().startOf("month").format("YYYY-MM-DD");
    searchForm.value.entryDateEnd = dayjs().endOf("month").format("YYYY-MM-DD");
    searchForm.value.dateRange = [searchForm.value.entryDateStart, searchForm.value.entryDateEnd]
  }
  reloadData()
};
const reloadData = () => {
  page.current = 1;
  page1.current = 1;
  getList();
  tableData.value = []
}
// 点击左侧行,刷右侧明细(按生产人过滤)
const handleLeftRowClick = (row) => {
    searchForm.value.schedulingUserName = row.schedulingUserName || "";
    handleQuery();
};
// 查询列表
/** 搜索按钮操作 */
const handleQuery = () => {
  page1.current = 1;
  getList1();
};
// 导出
const handleOut = () => {
    ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", {
        confirmButtonText: "确认",
        cancelButtonText: "取消",
        type: "warning",
    })
        .then(() => {
            proxy.download("/salesLedger/productionAccounting/export", {}, "生产核算.xlsx");
        })
        .catch(() => {
            proxy.$modal.msg("已取消");
        });
};
onMounted(() => {
    getList();
});
  onMounted(() => {
    getList();
  });
</script>
<style scoped lang="scss">
.content-row {
  width: 100%;
}
  .content-row {
    width: 100%;
  }
.content-row .left-col,
.content-row .right-col {
  margin-bottom: 16px;
}
  .content-row .left-col,
  .content-row .right-col {
    margin-bottom: 16px;
  }
.left-panel,
.right-panel {
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-width: 0;
}
  .left-panel,
  .right-panel {
    display: flex;
    flex-direction: column;
    gap: 10px;
    min-width: 0;
  }
.left-header {
  display: flex;
  align-items: center;
  gap: 12px;
}
  .left-header {
    display: flex;
    align-items: center;
    gap: 12px;
  }
.left-title {
  font-size: 16px;
  color: #ffffff;
}
  .left-title {
    font-size: 16px;
    color: #ffffff;
  }
.header-filters {
  display: flex;
  align-items: center;
  flex: 1;
  justify-content: flex-end;
  gap: 8px;
}
  .header-filters {
    display: flex;
    align-items: center;
    flex: 1;
    justify-content: flex-end;
    gap: 8px;
  }
.search_title {
  color: #ffffff;
}
  .search_title {
    color: #ffffff;
  }
.ml10 {
  margin-left: 10px;
}
  .ml10 {
    margin-left: 10px;
  }
</style>
src/views/productionManagement/workOrder/index.vue
@@ -596,7 +596,7 @@
  const showReportDialog = row => {
    currentReportRowData.value = row;
        reportForm.planQuantity = row.planQuantity - row.completeQuantity;
    reportForm.planQuantity = row.planQuantity - row.completeQuantity;
    reportForm.quantity =
      row.quantity !== undefined && row.quantity !== null ? row.quantity : null;
    reportForm.productProcessRouteItemId = row.productProcessRouteItemId;
src/views/productionManagement/workOrderManagement/index.vue
@@ -128,14 +128,14 @@
                    readonly
                    style="width: 300px" />
        </el-form-item>
        <el-form-item label="本次生产数量"
        <el-form-item label="生产合格数量"
                      prop="quantity">
          <el-input v-model.number="reportForm.quantity"
                    type="number"
                    min="1"
                    min="0"
                    step="1"
                    style="width: 300px"
                    placeholder="请输入本次生产数量"
                    placeholder="请输入生产合格数量"
                    @input="handleQuantityInput" />
        </el-form-item>
        <el-form-item label="报废数量"
@@ -403,16 +403,16 @@
  const dictOptions = ref({});
  const paramLoading = ref(false);
  // 本次生产数量验证规则
  // 生产合格数量验证规则
  const validateQuantity = (rule, value, callback) => {
    if (value === null || value === undefined || value === "") {
      callback(new Error("请输入本次生产数量"));
      callback(new Error("请输入生产合格数量"));
      return;
    }
    const num = Number(value);
    // 整数且大于等于1
    if (isNaN(num) || !Number.isInteger(num) || num < 1) {
      callback(new Error("本次生产数量必须大于等于1"));
    if (isNaN(num) || !Number.isInteger(num) || num < 0) {
      callback(new Error("生产合格数量必须大于等于0"));
      return;
    }
    callback();
@@ -439,7 +439,7 @@
    scrapQty: [{ validator: validateScrapQty, trigger: "blur" }],
  };
  // 处理本次生产数量输入,限制必须大于等于1
  // 处理生产合格数量输入,限制必须大于等于0
  const handleQuantityInput = value => {
    if (value === "" || value === null || value === undefined) {
      reportForm.quantity = null;
@@ -450,7 +450,7 @@
      return;
    }
    // 如果小于1,清除
    if (num < 1) {
    if (num < 0) {
      reportForm.quantity = null;
      return;
    }
@@ -458,7 +458,7 @@
    if (!Number.isInteger(num)) {
      const intValue = Math.floor(num);
      // 如果取整后小于1,清除
      if (intValue < 1) {
      if (intValue < 0) {
        reportForm.quantity = null;
        return;
      }
@@ -672,13 +672,13 @@
        return;
      }
      // 验证本次生产数量
      // 验证生产合格数量
      if (
        reportForm.quantity === null ||
        reportForm.quantity === undefined ||
        reportForm.quantity === ""
      ) {
        ElMessageBox.alert("请输入本次生产数量", "提示", {
        ElMessageBox.alert("请输入生产合格数量", "提示", {
          confirmButtonText: "确定",
        });
        return;
@@ -686,8 +686,8 @@
      const quantity = Number(reportForm.quantity);
      if (isNaN(quantity) || quantity <= 0) {
        ElMessageBox.alert("本次生产数量必须大于0", "提示", {
      if (isNaN(quantity) || quantity < 0) {
        ElMessageBox.alert("生产合格数量必须大于等于0", "提示", {
          confirmButtonText: "确定",
        });
        return;
@@ -709,12 +709,12 @@
        return;
      }
      if (!isNaN(scrapQty) && scrapQty > quantity) {
        ElMessageBox.alert("报废数量不能大于本次生产数量", "提示", {
          confirmButtonText: "确定",
        });
        return;
      }
      // if (!isNaN(scrapQty) && scrapQty > quantity) {
      //   ElMessageBox.alert("报废数量不能大于本次生产数量", "提示", {
      //     confirmButtonText: "确定",
      //   });
      //   return;
      // }
      const productionOperationParamList = params.value.map(param => ({
        ...param,