liu
2026-09-18 91dcbcbd7e5813a2c382d7aa57c5483c06fdf225
feat(生产报工): 报工弹窗按四类数量录入并展示分类去向

- 工单管理报工弹窗:合格/轻微返工/严重返工/报废四个数量录入 + 计数合计实时展示与校验
- 报工台账、生产报工列表增加轻微/严重返工数量列
- 过程检验、成品检验增加报工单号筛选与「来源报工单号」列
- 不合格品管理增加「来源报工单号」筛选与列
- 生产报工列表增加产品大类筛选

Co-Authored-By: Claude <noreply@anthropic.com>
已修改6个文件
260 ■■■■■ 文件已修改
src/views/productionManagement/productionReporting/index.vue 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/productionReportingEntry/index.vue 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/workOrderManagement/index.vue 166 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/finalInspection/index.vue 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/nonconformingManagement/index.vue 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/processInspection/index.vue 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/productionReporting/index.vue
@@ -32,6 +32,17 @@
            <el-option label="报废" :value="3" />
          </el-select>
        </el-form-item>
        <el-form-item label="产品大类:">
          <el-select v-model="searchForm.majorCategory"
                     placeholder="请选择"
                     clearable
                     style="width: 200px;"
                     @change="handleQuery">
            <el-option label="小提琴" value="小提琴" />
            <el-option label="大提琴" value="大提琴" />
            <el-option label="贝斯" value="贝斯" />
          </el-select>
        </el-form-item>
        <el-form-item>
          <el-button type="primary"
                     @click="handleQuery">搜索</el-button>
@@ -181,6 +192,7 @@
      workOrderNo: "",
      workOrderStatus: "",
      reportType: "",
      majorCategory: "",
    },
  });
  const { searchForm } = toRefs(data);
@@ -229,6 +241,11 @@
      width: 120,
    },
    {
      label: "产品大类",
      prop: "majorCategory",
      width: 110,
    },
    {
      label: "产品名称",
      prop: "productName",
      width: 120,
@@ -239,11 +256,21 @@
      width: 120,
    },
    {
      label: "产出数量",
      label: "合格数量",
      prop: "quantity",
      width: 120,
    },
    {
      label: "轻微返工数量",
      prop: "reworkMinorQty",
      width: 120,
    },
    {
      label: "严重返工数量",
      prop: "reworkMajorQty",
      width: 120,
    },
    {
      label: "报废数量",
      prop: "scrapQty",
      width: 120,
src/views/productionManagement/productionReportingEntry/index.vue
@@ -44,6 +44,18 @@
          </el-select>
        </div>
        <div class="search-item">
          <span class="search_title">产品大类:</span>
          <el-select v-model="searchForm.majorCategory"
                     style="width: 180px"
                     clearable
                     placeholder="请选择"
                     @change="handleQuery">
            <el-option label="小提琴" value="小提琴" />
            <el-option label="大提琴" value="大提琴" />
            <el-option label="贝斯" value="贝斯" />
          </el-select>
        </div>
        <div class="search-item">
          <el-button type="primary" @click="handleQuery">搜索</el-button>
        </div>
      </div>
@@ -85,6 +97,7 @@
    workOrderNo: "",
    nickName: "",
    reportType: "",
    majorCategory: "",
  },
});
const { searchForm } = toRefs(data);
@@ -92,10 +105,13 @@
const tableColumn = [
  { label: "报工单号", prop: "productNo", width: 140 },
  { label: "报工人员", prop: "nickName", width: 120 },
  { label: "产品大类", prop: "majorCategory", width: 110 },
  { label: "工序", prop: "process", width: 140 },
  { label: "工单编号", prop: "workOrderNo", width: 140 },
  { label: "产出数量", prop: "quantity", width: 120 },
  { label: "报废数量", prop: "scrapQty", width: 120 },
  { label: "合格数量", prop: "quantity", width: 110 },
  { label: "轻微返工数量", prop: "reworkMinorQty", width: 120 },
  { label: "严重返工数量", prop: "reworkMajorQty", width: 120 },
  { label: "报废数量", prop: "scrapQty", width: 110 },
  { label: "工时(h)", prop: "workHour", width: 100 },
  { label: "报工结果", prop: "reportTypeName", width: 100 },
  { label: "审核状态", prop: "auditStatusName", width: 100 },
src/views/productionManagement/workOrderManagement/index.vue
@@ -65,15 +65,35 @@
                    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="0"
                    step="0.001"
                    style="width: 300px"
                    placeholder="请输入生产合格数量"
                    placeholder="请输入合格零件数量"
                    @input="handleQuantityInput" />
        </el-form-item>
        <el-form-item label="轻微返工数量"
                      prop="reworkMinorQty">
          <el-input v-model.number="reportForm.reworkMinorQty"
                    type="number"
                    min="0"
                    step="1"
                    style="width: 300px"
                    placeholder="请输入轻微返工零件数量"
                    @input="handleNonNegativeIntInput('reworkMinorQty', $event)" />
        </el-form-item>
        <el-form-item label="严重返工数量"
                      prop="reworkMajorQty">
          <el-input v-model.number="reportForm.reworkMajorQty"
                    type="number"
                    min="0"
                    step="1"
                    style="width: 300px"
                    placeholder="请输入严重返工零件数量"
                    @input="handleNonNegativeIntInput('reworkMajorQty', $event)" />
        </el-form-item>
        <el-form-item label="报废数量"
                      prop="scrapQty">
@@ -82,19 +102,12 @@
                    min="0"
                    step="1"
                    style="width: 300px"
                    placeholder="请输入报废数量"
                    placeholder="请输入报废零件数量"
                    @input="handleScrapQtyInput" />
        </el-form-item>
        <el-form-item label="报工类型"
                      prop="reportType">
          <el-select v-model="reportForm.reportType"
                     style="width: 300px"
                     placeholder="请选择报工类型">
            <el-option label="合格" :value="0" />
            <el-option label="轻微返工" :value="1" />
            <el-option label="严重返工" :value="2" />
            <el-option label="报废" :value="3" />
          </el-select>
        <el-form-item label="计数合计">
          <span class="counted-total">{{ countedTotal }}</span>
          <span class="counted-total-tip">(合格 + 轻微返工 + 严重返工 + 报废,完成后分类进入质检入库)</span>
        </el-form-item>
        <el-form-item label="班组信息">
          <el-select v-model="reportForm.userId"
@@ -210,7 +223,7 @@
</template>
<script setup>
  import { onMounted, ref, nextTick } from "vue";
  import { onMounted, ref, nextTick, computed } from "vue";
  import { ElMessageBox } from "element-plus";
  import dayjs from "dayjs";
  import {
@@ -375,8 +388,9 @@
  const reportForm = reactive({
    planQuantity: 0,
    quantity: null,
    reworkMinorQty: null,
    reworkMajorQty: null,
    scrapQty: null,
    reportType: 0,
    userName: "",
    workOrderId: "",
    reportWork: "",
@@ -396,28 +410,26 @@
  // 生产合格数量验证规则
  const validateQuantity = (rule, value, callback) => {
    if (value === null || value === undefined || value === "") {
      callback(new Error("请输入生产合格数量"));
      callback();
      return;
    }
    const num = Number(value);
    // 整数且大于等于1
    if (isNaN(num) || num < 0) {
      callback(new Error("生产合格数量必须大于等于0"));
      callback(new Error("合格数量必须大于等于0"));
      return;
    }
    callback();
  };
  // 报废数量验证规则
  const validateScrapQty = (rule, value, callback) => {
  // 分类数量(返工/报废)验证规则:选填,非负
  const validateOptionalCount = label => (rule, value, callback) => {
    if (value === null || value === undefined || value === "") {
      callback();
      return;
    }
    const num = Number(value);
    // 整数且大于等于0
    if (isNaN(num) || num < 0) {
      callback(new Error("报废数量必须大于等于0"));
      callback(new Error(`${label}必须大于等于0`));
      return;
    }
    callback();
@@ -425,9 +437,25 @@
  // 验证规则
  const reportFormRules = {
    quantity: [{ required: true, validator: validateQuantity, trigger: "blur" }],
    scrapQty: [{ validator: validateScrapQty, trigger: "blur" }],
    quantity: [{ validator: validateQuantity, trigger: "blur" }],
    reworkMinorQty: [{ validator: validateOptionalCount("轻微返工数量"), trigger: "blur" }],
    reworkMajorQty: [{ validator: validateOptionalCount("严重返工数量"), trigger: "blur" }],
    scrapQty: [{ validator: validateOptionalCount("报废数量"), trigger: "blur" }],
  };
  // 报工计数合计 = 合格 + 轻微返工 + 严重返工 + 报废
  const countedTotal = computed(() => {
    const total = [
      reportForm.quantity,
      reportForm.reworkMinorQty,
      reportForm.reworkMajorQty,
      reportForm.scrapQty,
    ].reduce((sum, value) => {
      const num = Number(value);
      return sum + (isNaN(num) || num < 0 ? 0 : num);
    }, 0);
    return Math.round(total * 1000) / 1000;
  });
  // 处理生产合格数量输入,限制必须大于等于0
  const handleQuantityInput = value => {
@@ -445,6 +473,20 @@
      return;
    }
    reportForm.quantity = num;
  };
  // 返工分类数量输入:非负整数
  const handleNonNegativeIntInput = (field, value) => {
    if (value === "" || value === null || value === undefined) {
      reportForm[field] = null;
      return;
    }
    const num = Number(value);
    if (isNaN(num) || num < 0) {
      reportForm[field] = null;
      return;
    }
    reportForm[field] = Number.isInteger(num) ? num : Math.floor(num);
  };
  // 处理报废数量
@@ -628,7 +670,8 @@
    reportForm.planQuantity = remainingQuantity;
    reportForm.quantity =
      row.quantity !== undefined && row.quantity !== null ? row.quantity : null;
    reportForm.reportType = row.reportType ?? 0;
    reportForm.reworkMinorQty = row.reworkMinorQty ?? null;
    reportForm.reworkMajorQty = row.reworkMajorQty ?? null;
    reportForm.productProcessRouteItemId = row.productProcessRouteItemId;
    reportForm.workOrderId = row.id;
    reportForm.reportWork = row.reportWork;
@@ -681,49 +724,25 @@
        return;
      }
      // 验证生产合格数量
      if (
        reportForm.quantity === null ||
        reportForm.quantity === undefined ||
        reportForm.quantity === ""
      ) {
        ElMessageBox.alert("请输入生产合格数量", "提示", {
          confirmButtonText: "确定",
        });
      // 分类数量取值:空或非法按0处理
      const toCount = value => {
        const num = Number(value);
        return isNaN(num) || num < 0 ? 0 : num;
      };
      const quantity = toCount(reportForm.quantity);
      const reworkMinorQty = toCount(reportForm.reworkMinorQty);
      const reworkMajorQty = toCount(reportForm.reworkMajorQty);
      const scrapQty = toCount(reportForm.scrapQty);
      // 对计数的零件做区分:四类数量合计必须大于0
      if (quantity + reworkMinorQty + reworkMajorQty + scrapQty <= 0) {
        ElMessageBox.alert(
          "请按合格/轻微返工/严重返工/报废分类填写零件数量,且合计需大于0",
          "提示",
          { confirmButtonText: "确定" }
        );
        return;
      }
      const quantity = Number(reportForm.quantity);
      if (isNaN(quantity) || quantity < 0) {
        ElMessageBox.alert("生产合格数量必须大于等于0", "提示", {
          confirmButtonText: "确定",
        });
        return;
      }
      // if (quantity > reportForm.planQuantity) {
      //   ElMessageBox.alert("本次生产数量不能超过待生产数量", "提示", {
      //     confirmButtonText: "确定",
      //   });
      //   return;
      // }
      // 验证报废数量
      const scrapQty = Number(reportForm.scrapQty);
      if (!isNaN(scrapQty) && scrapQty < 0) {
        ElMessageBox.alert("报废数量不能小于0", "提示", {
          confirmButtonText: "确定",
        });
        return;
      }
      // if (!isNaN(scrapQty) && scrapQty > quantity) {
      //   ElMessageBox.alert("报废数量不能大于本次生产数量", "提示", {
      //     confirmButtonText: "确定",
      //   });
      //   return;
      // }
      const productionOperationParamList = params.value.map(param => ({
        ...param,
@@ -732,8 +751,9 @@
      const submitParams = {
        quantity: quantity,
        scrapQty: isNaN(scrapQty) ? 0 : scrapQty,
        reportType: reportForm.reportType,
        reworkMinorQty: reworkMinorQty,
        reworkMajorQty: reworkMajorQty,
        scrapQty: scrapQty,
        userId: reportForm.userId,
        userName: reportForm.userName,
        productionOperationTaskId: reportForm.workOrderId,
@@ -913,6 +933,16 @@
    font-size: 12px;
    min-width: 30px;
  }
  .counted-total {
    font-size: 16px;
    font-weight: 600;
    color: #409eff;
  }
  .counted-total-tip {
    margin-left: 8px;
    font-size: 12px;
    color: #909399;
  }
</style>
<style  lang="scss">
src/views/qualityManagement/finalInspection/index.vue
@@ -44,6 +44,15 @@
                        clearable />
            </el-form-item>
          </el-col>
          <el-col :span="4">
            <el-form-item label="报工单号"
                          prop="reportNo">
              <el-input v-model="searchForm.reportNo"
                        style="width: 240px"
                        placeholder="请输入报工单号搜索"
                        clearable />
            </el-form-item>
          </el-col>
          <!-- 按钮 -->
          <el-col :span="4">
            <el-form-item>
@@ -143,6 +152,7 @@
      productName: "",
      salesContractNo: "",
      workOrderNo: "",
      reportNo: "",
      entryDate: undefined, // 录入日期
      entryDateStart: undefined,
      entryDateEnd: undefined,
@@ -169,6 +179,11 @@
      width: 120,
    },
    {
      label: "来源报工单号",
      prop: "reportNo",
      width: 140,
    },
    {
      label: "检验员",
      prop: "checkName",
    },
src/views/qualityManagement/nonconformingManagement/index.vue
@@ -25,6 +25,16 @@
              :prefix-icon="Search"
          />
        </el-form-item>
        <el-form-item label="来源报工单号:">
          <el-input
              v-model="searchForm.reportNo"
              style="width: 200px"
              placeholder="请输入报工单号搜索"
              @change="handleQuery"
              clearable
              :prefix-icon="Search"
          />
        </el-form-item>
        <el-form-item label="检测日期:">
          <el-date-picker v-model="searchForm.entryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="daterange"
                          style="width: 300px"
@@ -107,6 +117,7 @@
    inspectType: "",
    inspectState: "",
    productName: "",
    reportNo: "",
    entryDate: undefined, // 录入日期
    entryDateStart: undefined,
    entryDateEnd: undefined,
@@ -167,6 +178,11 @@
    },
  },
  {
    label: "来源报工单号",
    prop: "reportNo",
    width: 140,
  },
  {
    label: "检验员",
    prop: "checkName",
  },
src/views/qualityManagement/processInspection/index.vue
@@ -26,6 +26,14 @@
                  @change="handleQuery"
                  clearable
                  :prefix-icon="Search" />
        <span style="margin-left: 10px"
              class="search_title">报工单号:</span>
        <el-input v-model="searchForm.reportNo"
                  style="width: 240px"
                  placeholder="请输入报工单号搜索"
                  @change="handleQuery"
                  clearable
                  :prefix-icon="Search" />
        <el-button type="primary"
                   @click="handleQuery"
                   style="margin-left: 10px">搜索</el-button>
@@ -118,6 +126,7 @@
      process: "",
      entryDate: undefined, // 录入日期
      workOrderNo: "",
      reportNo: "",
      entryDateStart: undefined,
      entryDateEnd: undefined,
    },
@@ -138,6 +147,11 @@
      width: 120,
    },
    {
      label: "来源报工单号",
      prop: "reportNo",
      width: 140,
    },
    {
      label: "工序",
      prop: "process",
      width: 230,