gongchunyi
2026-05-15 c6c1caafba75438cc0eff215f19e9e0b900778d7
feat: 质检数量区分合格/不合格
已修改9个文件
640 ■■■■ 文件已修改
src/views/qualityManagement/finalInspection/components/formDia.vue 149 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/finalInspection/components/inspectionFormDia.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/finalInspection/index.vue 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/processInspection/components/formDia.vue 150 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/processInspection/components/inspectionFormDia.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/processInspection/index.vue 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/rawMaterialInspection/components/formDia.vue 143 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/rawMaterialInspection/components/inspectionFormDia.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/rawMaterialInspection/index.vue 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/finalInspection/components/formDia.vue
@@ -62,8 +62,21 @@
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="数量:" prop="quantity">
              <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.quantity" placeholder="请输入" clearable :precision="2" :disabled="quantityDisabled"/>
            <el-form-item label="总数量:" prop="quantity">
              <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.quantity" placeholder="请输入" clearable :precision="2" :disabled="quantityDisabled"
                               @change="onTotalQuantityChange"/>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="合格数量:" prop="qualifiedQuantity">
              <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.qualifiedQuantity" placeholder="请输入" clearable :precision="2" @change="onQualifiedQuantityChange"/>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="不合格数量:" prop="unqualifiedQuantity">
              <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.unqualifiedQuantity" placeholder="请输入" clearable :precision="2" @change="onUnqualifiedQuantityChange"/>
            </el-form-item>
          </el-col>
        </el-row>
@@ -74,16 +87,6 @@
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="检测结果:" prop="checkResult">
              <el-select v-model="form.checkResult">
                <el-option label="合格" value="合格" />
                <el-option label="不合格" value="不合格" />
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="检验员:" prop="checkName">
                            <el-select v-model="form.checkName" placeholder="请选择" clearable>
                                <el-option v-for="item in userList" :key="item.nickName" :label="item.nickName"
@@ -91,6 +94,8 @@
                            </el-select>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="检测日期:" prop="checkTime">
              <el-date-picker
@@ -152,13 +157,14 @@
    testStandardId: "",
    unit: "",
    quantity: "",
    qualifiedQuantity: null,
    unqualifiedQuantity: null,
    checkCompany: "",
    checkResult: "",
    thickness:""
  },
  rules: {
    checkTime: [{ required: true, message: "请输入", trigger: "blur" },],
    process: [{ required: true, message: "请输入", trigger: "blur" }],
    process: [{ required: false, message: "请输入", trigger: "blur" }],
    checkName: [{ required: false, message: "请输入", trigger: "blur" }],
    productId: [{ required: true, message: "请输入", trigger: "blur" }],
    productModelId: [{ required: true, message: "请选择", trigger: "change" }],
@@ -166,10 +172,118 @@
    unit: [{ required: false, message: "请输入", trigger: "blur" }],
    quantity: [{ required: true, message: "请输入", trigger: "blur" }],
    checkCompany: [{ required: false, message: "请输入", trigger: "blur" }],
    checkResult: [{ required: true, message: "请输入", trigger: "change" }],
    qualifiedQuantity: [{ required: true, message: "请输入合格数量", trigger: "blur" }],
    unqualifiedQuantity: [{ required: true, message: "请输入不合格数量", trigger: "blur" }],
  },
});
const { form, rules } = toRefs(data);
function normalizeQuantitiesFromLegacy() {
  const qty = form.value.quantity != null ? Number(form.value.quantity) : null
  if (qty == null || Number.isNaN(qty)) return
  const hasQ = form.value.qualifiedQuantity != null && form.value.qualifiedQuantity !== ''
  const hasU = form.value.unqualifiedQuantity != null && form.value.unqualifiedQuantity !== ''
  if (hasQ && hasU) return
  if (form.value.checkResult === '不合格') {
    form.value.qualifiedQuantity = 0
    form.value.unqualifiedQuantity = qty
  } else {
    form.value.qualifiedQuantity = qty
    form.value.unqualifiedQuantity = 0
  }
}
function assertQtySplitOrError() {
  const total = Number(form.value.quantity)
  const a = form.value.qualifiedQuantity != null ? Number(form.value.qualifiedQuantity) : NaN
  const b = form.value.unqualifiedQuantity != null ? Number(form.value.unqualifiedQuantity) : NaN
  if (!Number.isFinite(total) || total < 0) {
    proxy.$modal.msgError('请先填写有效的总数量')
    return false
  }
  if (!Number.isFinite(a) || !Number.isFinite(b) || a < 0 || b < 0) {
    proxy.$modal.msgError('请填写合格数量与不合格数量')
    return false
  }
  if (a + b - total > 0.001) {
    proxy.$modal.msgError('合格数量与不合格数量之和不能超过总数量')
    return false
  }
  return true
}
function roundQty(n) {
  if (!Number.isFinite(n)) return 0
  return Math.round(n * 100) / 100
}
function parseTotalQty() {
  const t = Number(form.value.quantity)
  return Number.isFinite(t) && t >= 0 ? t : null
}
function onQualifiedQuantityChange(val) {
  const total = parseTotalQty()
  if (total == null) return
  let q = val == null || val === '' ? 0 : Number(val)
  if (!Number.isFinite(q) || q < 0) q = 0
  if (q > total) q = total
  q = roundQty(q)
  form.value.qualifiedQuantity = q
  form.value.unqualifiedQuantity = roundQty(total - q)
}
function onUnqualifiedQuantityChange(val) {
  const total = parseTotalQty()
  if (total == null) return
  let u = val == null || val === '' ? 0 : Number(val)
  if (!Number.isFinite(u) || u < 0) u = 0
  if (u > total) u = total
  u = roundQty(u)
  form.value.unqualifiedQuantity = u
  form.value.qualifiedQuantity = roundQty(total - u)
}
function onTotalQuantityChange() {
  const total = parseTotalQty()
  if (total == null) return
  const q = form.value.qualifiedQuantity != null && form.value.qualifiedQuantity !== '' ? Number(form.value.qualifiedQuantity) : NaN
  const u = form.value.unqualifiedQuantity != null && form.value.unqualifiedQuantity !== '' ? Number(form.value.unqualifiedQuantity) : NaN
  if (!Number.isFinite(q) && !Number.isFinite(u)) {
    form.value.qualifiedQuantity = roundQty(total)
    form.value.unqualifiedQuantity = 0
    return
  }
  if (Number.isFinite(q) && Number.isFinite(u)) {
    const sum = q + u
    if (sum > total + 0.001) {
      const nq = roundQty(Math.min(Math.max(0, q), total))
      form.value.qualifiedQuantity = nq
      form.value.unqualifiedQuantity = roundQty(total - nq)
    }
    return
  }
  if (Number.isFinite(q)) {
    const nq = roundQty(Math.min(Math.max(0, q), total))
    form.value.qualifiedQuantity = nq
    form.value.unqualifiedQuantity = roundQty(total - nq)
  } else if (Number.isFinite(u)) {
    const nu = roundQty(Math.min(Math.max(0, u), total))
    form.value.unqualifiedQuantity = nu
    form.value.qualifiedQuantity = roundQty(total - nu)
  }
}
function ensureQtyPairInitialized() {
  const total = parseTotalQty()
  if (total == null) return
  const qEmpty = form.value.qualifiedQuantity == null || form.value.qualifiedQuantity === ''
  const uEmpty = form.value.unqualifiedQuantity == null || form.value.unqualifiedQuantity === ''
  if (qEmpty && uEmpty) {
    form.value.qualifiedQuantity = roundQty(total)
    form.value.unqualifiedQuantity = 0
  }
}
// 编辑时:productMainId 或 purchaseLedgerId 任一有值则数量置灰
const quantityDisabled = computed(() => {
  const v = form.value || {};
@@ -235,6 +349,7 @@
    const savedTestStandardId = row.testStandardId;
    // 先设置表单数据,但暂时清空 testStandardId,等选项加载完成后再设置
    form.value = {...row, testStandardId: ''}
    normalizeQuantitiesFromLegacy()
    currentProductId.value = row.productId || 0
    // 清空验证状态,避免数据加载过程中的校验闪烁
    nextTick(() => {
@@ -353,6 +468,10 @@
const submitForm = () => {
  proxy.$refs.formRef.validate(valid => {
    if (valid) {
      ensureQtyPairInitialized()
      if (!assertQtySplitOrError()) {
        return
      }
      form.value.inspectType = 2
            if (operationType.value === "add") {
                tableData.value.forEach((item) => {
src/views/qualityManagement/finalInspection/components/inspectionFormDia.vue
@@ -33,7 +33,7 @@
</template>
<script setup>
import {ref} from "vue";
import {ref, getCurrentInstance} from "vue";
import {Search} from "@element-plus/icons-vue";
import {
  qualityInspectParamDel,
src/views/qualityManagement/finalInspection/index.vue
@@ -126,34 +126,46 @@
    width: 100
  },
  {
    label: "合格数量",
    prop: "qualifiedQuantity",
    width: 100
  },
  {
    label: "不合格数量",
    prop: "unqualifiedQuantity",
    width: 100
  },
  {
    label: "合格率",
    prop: "passRate",
    width: 100,
    dataType: "tag",
    formatData: (params) => {
      if (params == null || params === '') return '—';
      const n = Number(params);
      if (Number.isNaN(n)) return '—';
      return `${n.toFixed(2)}%`;
    },
    formatType: (params) => {
      if (params == null || params === '') return 'info';
      const n = Number(params);
      if (Number.isNaN(n)) return 'info';
      if (n >= 100) return 'success';
      if (n >= 90) return 'warning';
      return 'danger';
    },
  },
  {
    label: "检测单位",
    prop: "checkCompany",
    width: 120
  },
  {
    label: "检测结果",
    prop: "checkResult",
    dataType: "tag",
    formatType: (params) => {
      if (params == '不合格') {
        return "danger";
      } else if (params == '合格') {
        return "success";
      } else {
        return null;
      }
    },
  },
    {
        label: "提交状态",
        prop: "inspectState",
        formatData: (params) => {
            if (params) {
                return "已提交";
            } else {
                return "未提交";
            }
        },
    dataType: "tag",
    formatData: (params) => (params == 1 || params === true ? '已提交' : '未提交'),
    formatType: (params) => (params == 1 || params === true ? 'success' : 'info'),
    },
  {
    dataType: "action",
@@ -189,7 +201,7 @@
                name: "提交",
                type: "text",
                clickFun: (row) => {
                    submit(row.id);
                    submit(row);
                },
                disabled: (row) => {
                    // 已提交则禁用
@@ -342,8 +354,12 @@
};
// 提价
const submit = async (id) => {
    const res = await submitQualityInspect({id: id})
const submit = async (row) => {
    const res = await submitQualityInspect({
    id: row.id,
    qualifiedQuantity: row.qualifiedQuantity,
    unqualifiedQuantity: row.unqualifiedQuantity
  })
    if (res.code === 200) {
        proxy.$modal.msgSuccess("提交成功");
        getList();
src/views/qualityManagement/processInspection/components/formDia.vue
@@ -73,8 +73,21 @@
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="数量:" prop="quantity">
              <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.quantity" placeholder="请输入" clearable :precision="2" :disabled="processQuantityDisabled"/>
            <el-form-item label="总数量:" prop="quantity">
              <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.quantity" placeholder="请输入" clearable :precision="2" :disabled="processQuantityDisabled"
                               @change="onTotalQuantityChange"/>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="合格数量:" prop="qualifiedQuantity">
              <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.qualifiedQuantity" placeholder="请输入" clearable :precision="2" @change="onQualifiedQuantityChange"/>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="不合格数量:" prop="unqualifiedQuantity">
              <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.unqualifiedQuantity" placeholder="请输入" clearable :precision="2" @change="onUnqualifiedQuantityChange"/>
            </el-form-item>
          </el-col>
        </el-row>
@@ -85,16 +98,6 @@
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="检测结果:" prop="checkResult">
              <el-select v-model="form.checkResult">
                <el-option label="合格" value="合格" />
                <el-option label="不合格" value="不合格" />
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="检验员:" prop="checkName">
                            <el-select v-model="form.checkName" placeholder="请选择" clearable>
                                <el-option v-for="item in userList" :key="item.nickName" :label="item.nickName"
@@ -102,6 +105,8 @@
                            </el-select>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="检测日期:" prop="checkTime">
              <el-date-picker
@@ -167,8 +172,9 @@
    unit: "",
    thickness: "",
    quantity: "",
    qualifiedQuantity: null,
    unqualifiedQuantity: null,
    checkCompany: "",
    checkResult: "",
  },
  rules: {
    checkTime: [{ required: true, message: "请输入", trigger: "blur" },],
@@ -181,11 +187,119 @@
    thickness: [{ required: false, message: "请输入", trigger: "blur" }],
    quantity: [{ required: true, message: "请输入", trigger: "blur" }],
    checkCompany: [{ required: false, message: "请输入", trigger: "blur" }],
    checkResult: [{ required: true, message: "请输入", trigger: "change" }],
    qualifiedQuantity: [{ required: true, message: "请输入合格数量", trigger: "blur" }],
    unqualifiedQuantity: [{ required: true, message: "请输入不合格数量", trigger: "blur" }],
  },
});
const userList = ref([]);
const { form, rules } = toRefs(data);
function normalizeQuantitiesFromLegacy() {
  const qty = form.value.quantity != null ? Number(form.value.quantity) : null
  if (qty == null || Number.isNaN(qty)) return
  const hasQ = form.value.qualifiedQuantity != null && form.value.qualifiedQuantity !== ''
  const hasU = form.value.unqualifiedQuantity != null && form.value.unqualifiedQuantity !== ''
  if (hasQ && hasU) return
  if (form.value.checkResult === '不合格') {
    form.value.qualifiedQuantity = 0
    form.value.unqualifiedQuantity = qty
  } else {
    form.value.qualifiedQuantity = qty
    form.value.unqualifiedQuantity = 0
  }
}
function assertQtySplitOrError() {
  const total = Number(form.value.quantity)
  const a = form.value.qualifiedQuantity != null ? Number(form.value.qualifiedQuantity) : NaN
  const b = form.value.unqualifiedQuantity != null ? Number(form.value.unqualifiedQuantity) : NaN
  if (!Number.isFinite(total) || total < 0) {
    proxy.$modal.msgError('请先填写有效的总数量')
    return false
  }
  if (!Number.isFinite(a) || !Number.isFinite(b) || a < 0 || b < 0) {
    proxy.$modal.msgError('请填写合格数量与不合格数量')
    return false
  }
  if (a + b - total > 0.001) {
    proxy.$modal.msgError('合格数量与不合格数量之和不能超过总数量')
    return false
  }
  return true
}
function roundQty(n) {
  if (!Number.isFinite(n)) return 0
  return Math.round(n * 100) / 100
}
function parseTotalQty() {
  const t = Number(form.value.quantity)
  return Number.isFinite(t) && t >= 0 ? t : null
}
function onQualifiedQuantityChange(val) {
  const total = parseTotalQty()
  if (total == null) return
  let q = val == null || val === '' ? 0 : Number(val)
  if (!Number.isFinite(q) || q < 0) q = 0
  if (q > total) q = total
  q = roundQty(q)
  form.value.qualifiedQuantity = q
  form.value.unqualifiedQuantity = roundQty(total - q)
}
function onUnqualifiedQuantityChange(val) {
  const total = parseTotalQty()
  if (total == null) return
  let u = val == null || val === '' ? 0 : Number(val)
  if (!Number.isFinite(u) || u < 0) u = 0
  if (u > total) u = total
  u = roundQty(u)
  form.value.unqualifiedQuantity = u
  form.value.qualifiedQuantity = roundQty(total - u)
}
function onTotalQuantityChange() {
  const total = parseTotalQty()
  if (total == null) return
  const q = form.value.qualifiedQuantity != null && form.value.qualifiedQuantity !== '' ? Number(form.value.qualifiedQuantity) : NaN
  const u = form.value.unqualifiedQuantity != null && form.value.unqualifiedQuantity !== '' ? Number(form.value.unqualifiedQuantity) : NaN
  if (!Number.isFinite(q) && !Number.isFinite(u)) {
    form.value.qualifiedQuantity = roundQty(total)
    form.value.unqualifiedQuantity = 0
    return
  }
  if (Number.isFinite(q) && Number.isFinite(u)) {
    const sum = q + u
    if (sum > total + 0.001) {
      const nq = roundQty(Math.min(Math.max(0, q), total))
      form.value.qualifiedQuantity = nq
      form.value.unqualifiedQuantity = roundQty(total - nq)
    }
    return
  }
  if (Number.isFinite(q)) {
    const nq = roundQty(Math.min(Math.max(0, q), total))
    form.value.qualifiedQuantity = nq
    form.value.unqualifiedQuantity = roundQty(total - nq)
  } else if (Number.isFinite(u)) {
    const nu = roundQty(Math.min(Math.max(0, u), total))
    form.value.unqualifiedQuantity = nu
    form.value.qualifiedQuantity = roundQty(total - nu)
  }
}
function ensureQtyPairInitialized() {
  const total = parseTotalQty()
  if (total == null) return
  const qEmpty = form.value.qualifiedQuantity == null || form.value.qualifiedQuantity === ''
  const uEmpty = form.value.unqualifiedQuantity == null || form.value.unqualifiedQuantity === ''
  if (qEmpty && uEmpty) {
    form.value.qualifiedQuantity = roundQty(total)
    form.value.unqualifiedQuantity = 0
  }
}
// 编辑时:productMainId 或 purchaseLedgerId 任一有值则工序、数量置灰
const processQuantityDisabled = computed(() => {
  const v = form.value || {};
@@ -253,8 +367,9 @@
        unit: "",
        thickness: "",
        quantity: "",
        qualifiedQuantity: null,
        unqualifiedQuantity: null,
        checkCompany: "",
        checkResult: "",
    }
    testStandardOptions.value = [];
    tableData.value = [];
@@ -265,6 +380,7 @@
        const savedTestStandardId = row.testStandardId;
        // 先设置表单数据,但暂时清空 testStandardId,等选项加载完成后再设置
        form.value = {...row, testStandardId: ''}
        normalizeQuantitiesFromLegacy()
        currentProductId.value = row.productId || 0
        // 关键:编辑时加载规格型号下拉选项,才能反显 productModelId
        if (currentProductId.value) {
@@ -388,6 +504,10 @@
const submitForm = () => {
  proxy.$refs.formRef.validate(valid => {
    if (valid) {
      ensureQtyPairInitialized()
      if (!assertQtySplitOrError()) {
        return
      }
      form.value.inspectType = 1
            const processName = form.value.process || '';
            if (operationType.value === "add") {
src/views/qualityManagement/processInspection/components/inspectionFormDia.vue
@@ -33,7 +33,7 @@
</template>
<script setup>
import {ref} from "vue";
import {ref, getCurrentInstance} from "vue";
import {Search} from "@element-plus/icons-vue";
import {
  qualityInspectParamDel,
src/views/qualityManagement/processInspection/index.vue
@@ -131,34 +131,46 @@
    width: 100
  },
  {
    label: "合格数量",
    prop: "qualifiedQuantity",
    width: 100
  },
  {
    label: "不合格数量",
    prop: "unqualifiedQuantity",
    width: 100
  },
  {
    label: "合格率",
    prop: "passRate",
    width: 100,
    dataType: "tag",
    formatData: (params) => {
      if (params == null || params === '') return '—';
      const n = Number(params);
      if (Number.isNaN(n)) return '—';
      return `${n.toFixed(2)}%`;
    },
    formatType: (params) => {
      if (params == null || params === '') return 'info';
      const n = Number(params);
      if (Number.isNaN(n)) return 'info';
      if (n >= 100) return 'success';
      if (n >= 90) return 'warning';
      return 'danger';
    },
  },
  {
    label: "检测单位",
    prop: "checkCompany",
    width: 120
  },
  {
    label: "检测结果",
    prop: "checkResult",
    dataType: "tag",
    formatType: (params) => {
      if (params == '不合格') {
        return "danger";
      } else if (params == '合格') {
        return "success";
      } else {
        return null;
      }
    },
  },
    {
        label: "提交状态",
        prop: "inspectState",
        formatData: (params) => {
            if (params) {
                return "已提交";
            } else {
                return "未提交";
            }
        },
    dataType: "tag",
    formatData: (params) => (params == 1 || params === true ? '已提交' : '未提交'),
    formatType: (params) => (params == 1 || params === true ? 'success' : 'info'),
    },
  {
    dataType: "action",
@@ -194,7 +206,7 @@
                name: "提交",
                type: "text",
                clickFun: (row) => {
                    submit(row.id);
                    submit(row);
                },
                disabled: (row) => {
                    // 已提交则禁用
@@ -305,8 +317,12 @@
  })
};
// 提价
const submit = async (id) => {
    const res = await submitQualityInspect({id: id})
const submit = async (row) => {
    const res = await submitQualityInspect({
    id: row.id,
    qualifiedQuantity: row.qualifiedQuantity,
    unqualifiedQuantity: row.unqualifiedQuantity
  })
    if (res.code === 200) {
        proxy.$modal.msgSuccess("提交成功");
        getList();
src/views/qualityManagement/rawMaterialInspection/components/formDia.vue
@@ -83,9 +83,10 @@
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="数量:" prop="quantity">
            <el-form-item label="总数量:" prop="quantity">
              <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.quantity" placeholder="请输入"
                               clearable :precision="2" :disabled="supplierQuantityDisabled"/>
                               clearable :precision="2" :disabled="supplierQuantityDisabled"
                               @change="onTotalQuantityChange"/>
            </el-form-item>
          </el-col>
          <el-col :span="12">
@@ -96,13 +97,19 @@
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="检测结果:" prop="checkResult">
              <el-select v-model="form.checkResult">
                <el-option label="合格" value="合格"/>
                <el-option label="不合格" value="不合格"/>
              </el-select>
            <el-form-item label="合格数量:" prop="qualifiedQuantity">
              <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.qualifiedQuantity" placeholder="请输入"
                               clearable :precision="2" @change="onQualifiedQuantityChange"/>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="不合格数量:" prop="unqualifiedQuantity">
              <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.unqualifiedQuantity" placeholder="请输入"
                               clearable :precision="2" @change="onUnqualifiedQuantityChange"/>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="检验员:" prop="checkName">
              <el-select v-model="form.checkName" placeholder="请选择" clearable style="width: 100%">
@@ -220,8 +227,9 @@
    unit: "",
    thickness: "",
    quantity: "",
    qualifiedQuantity: null,
    unqualifiedQuantity: null,
    checkCompany: "",
    checkResult: "",
    reviewName: "",
  },
  rules: {
@@ -235,7 +243,8 @@
    thickness: [{required: false, message: "请输入", trigger: "blur"}],
    quantity: [{required: true, message: "请输入", trigger: "blur"}],
    checkCompany: [{required: false, message: "请输入", trigger: "blur"}],
    checkResult: [{required: true, message: "请选择检测结果", trigger: "change"}],
    qualifiedQuantity: [{required: true, message: "请输入合格数量", trigger: "blur"}],
    unqualifiedQuantity: [{required: true, message: "请输入不合格数量", trigger: "blur"}],
  },
});
const tableColumn = ref([
@@ -266,6 +275,114 @@
const tableLoading = ref(false);
const {form, rules} = toRefs(data);
function normalizeQuantitiesFromLegacy() {
  const qty = form.value.quantity != null ? Number(form.value.quantity) : null
  if (qty == null || Number.isNaN(qty)) return
  const hasQ = form.value.qualifiedQuantity != null && form.value.qualifiedQuantity !== ''
  const hasU = form.value.unqualifiedQuantity != null && form.value.unqualifiedQuantity !== ''
  if (hasQ && hasU) return
  if (form.value.checkResult === '不合格') {
    form.value.qualifiedQuantity = 0
    form.value.unqualifiedQuantity = qty
  } else {
    form.value.qualifiedQuantity = qty
    form.value.unqualifiedQuantity = 0
  }
}
function assertQtySplitOrError() {
  const total = Number(form.value.quantity)
  const a = form.value.qualifiedQuantity != null ? Number(form.value.qualifiedQuantity) : NaN
  const b = form.value.unqualifiedQuantity != null ? Number(form.value.unqualifiedQuantity) : NaN
  if (!Number.isFinite(total) || total < 0) {
    proxy.$modal.msgError('请先填写有效的总数量')
    return false
  }
  if (!Number.isFinite(a) || !Number.isFinite(b) || a < 0 || b < 0) {
    proxy.$modal.msgError('请填写合格数量与不合格数量')
    return false
  }
  if (a + b - total > 0.001) {
    proxy.$modal.msgError('合格数量与不合格数量之和不能超过总数量')
    return false
  }
  return true
}
function roundQty(n) {
  if (!Number.isFinite(n)) return 0
  return Math.round(n * 100) / 100
}
function parseTotalQty() {
  const t = Number(form.value.quantity)
  return Number.isFinite(t) && t >= 0 ? t : null
}
function onQualifiedQuantityChange(val) {
  const total = parseTotalQty()
  if (total == null) return
  let q = val == null || val === '' ? 0 : Number(val)
  if (!Number.isFinite(q) || q < 0) q = 0
  if (q > total) q = total
  q = roundQty(q)
  form.value.qualifiedQuantity = q
  form.value.unqualifiedQuantity = roundQty(total - q)
}
function onUnqualifiedQuantityChange(val) {
  const total = parseTotalQty()
  if (total == null) return
  let u = val == null || val === '' ? 0 : Number(val)
  if (!Number.isFinite(u) || u < 0) u = 0
  if (u > total) u = total
  u = roundQty(u)
  form.value.unqualifiedQuantity = u
  form.value.qualifiedQuantity = roundQty(total - u)
}
function onTotalQuantityChange() {
  const total = parseTotalQty()
  if (total == null) return
  const q = form.value.qualifiedQuantity != null && form.value.qualifiedQuantity !== '' ? Number(form.value.qualifiedQuantity) : NaN
  const u = form.value.unqualifiedQuantity != null && form.value.unqualifiedQuantity !== '' ? Number(form.value.unqualifiedQuantity) : NaN
  if (!Number.isFinite(q) && !Number.isFinite(u)) {
    form.value.qualifiedQuantity = roundQty(total)
    form.value.unqualifiedQuantity = 0
    return
  }
  if (Number.isFinite(q) && Number.isFinite(u)) {
    const sum = q + u
    if (sum > total + 0.001) {
      const nq = roundQty(Math.min(Math.max(0, q), total))
      form.value.qualifiedQuantity = nq
      form.value.unqualifiedQuantity = roundQty(total - nq)
    }
    return
  }
  if (Number.isFinite(q)) {
    const nq = roundQty(Math.min(Math.max(0, q), total))
    form.value.qualifiedQuantity = nq
    form.value.unqualifiedQuantity = roundQty(total - nq)
  } else if (Number.isFinite(u)) {
    const nu = roundQty(Math.min(Math.max(0, u), total))
    form.value.unqualifiedQuantity = nu
    form.value.qualifiedQuantity = roundQty(total - nu)
  }
}
function ensureQtyPairInitialized() {
  const total = parseTotalQty()
  if (total == null) return
  const qEmpty = form.value.qualifiedQuantity == null || form.value.qualifiedQuantity === ''
  const uEmpty = form.value.unqualifiedQuantity == null || form.value.unqualifiedQuantity === ''
  if (qEmpty && uEmpty) {
    form.value.qualifiedQuantity = roundQty(total)
    form.value.unqualifiedQuantity = 0
  }
}
const supplierList = ref([]);
const productOptions = ref([]);
const currentProductId = ref(0);
@@ -318,8 +435,9 @@
    unit: "",
    thickness: "",
    quantity: "",
    qualifiedQuantity: null,
    unqualifiedQuantity: null,
    checkCompany: "",
    checkResult: "",
    reviewName: "",
  }
  approverNodes.value = [{ id: 1, userId: null }];
@@ -332,6 +450,7 @@
    // 先保存 testStandardId,避免被清空
    const savedTestStandardId = row.testStandardId;
    form.value = {...row}
    normalizeQuantitiesFromLegacy()
    if (form.value.approveUserIds) {
      const ids = String(form.value.approveUserIds)
        .split(",")
@@ -474,6 +593,10 @@
const submitForm = () => {
  proxy.$refs.formRef.validate(valid => {
    if (valid) {
      ensureQtyPairInitialized()
      if (!assertQtySplitOrError()) {
        return
      }
      const hasEmptyApprover = approverNodes.value.some(node => !node.userId);
      if (hasEmptyApprover) {
        proxy.$modal.msgError("请为所有审批节点选择审批人!");
src/views/qualityManagement/rawMaterialInspection/components/inspectionFormDia.vue
@@ -33,7 +33,7 @@
</template>
<script setup>
import {ref} from "vue";
import {ref, getCurrentInstance} from "vue";
import {Search} from "@element-plus/icons-vue";
import {
  qualityInspectParamDel,
src/views/qualityManagement/rawMaterialInspection/index.vue
@@ -133,34 +133,46 @@
    width: 120
  },
  {
    label: "合格数量",
    prop: "qualifiedQuantity",
    width: 100
  },
  {
    label: "不合格数量",
    prop: "unqualifiedQuantity",
    width: 100
  },
  {
    label: "合格率",
    prop: "passRate",
    width: 100,
    dataType: "tag",
    formatData: (params) => {
      if (params == null || params === '') return '—';
      const n = Number(params);
      if (Number.isNaN(n)) return '—';
      return `${n.toFixed(2)}%`;
    },
    formatType: (params) => {
      if (params == null || params === '') return 'info';
      const n = Number(params);
      if (Number.isNaN(n)) return 'info';
      if (n >= 100) return 'success';
      if (n >= 90) return 'warning';
      return 'danger';
    },
  },
  {
    label: "检测单位",
    prop: "checkCompany",
    width: 120
  },
  {
    label: "检测结果",
    prop: "checkResult",
    dataType: "tag",
    formatType: (params) => {
      if (params === '不合格') {
        return "danger";
      } else if (params === '合格') {
        return "success";
      } else {
        return null;
      }
    },
  },
  {
    label: "提交状态",
    prop: "inspectState",
    formatData: (params) => {
      if (params) {
        return "已提交";
      } else {
        return "未提交";
      }
    },
    dataType: "tag",
    formatData: (params) => (params == 1 || params === true ? '已提交' : '未提交'),
    formatType: (params) => (params == 1 || params === true ? 'success' : 'info'),
  },
  {
    dataType: "action",
@@ -196,7 +208,7 @@
        name: "提交",
        type: "text",
        clickFun: (row) => {
          submit(row.id);
          submit(row);
        },
                disabled: (row) => {
                    // 已提交则禁用
@@ -341,8 +353,12 @@
};
// 提价
const submit = async (id) => {
  const res = await submitQualityInspect({id: id})
const submit = async (row) => {
  const res = await submitQualityInspect({
    id: row.id,
    qualifiedQuantity: row.qualifiedQuantity,
    unqualifiedQuantity: row.unqualifiedQuantity
  })
  if (res.code === 200) {
    proxy.$modal.msgSuccess("提交成功");
    getList();