gaoluyang
22 小时以前 a342672f32352c1337b8977c25c101725fccedd5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
/**
 * 探针:确认前端判定器把「无判定规则」和「待判定」分开,且前者不计入合格率与报告结论。
 *
 * 背景:报告里常有「试样质量 m」「称量瓶 m0」这类只供公式取数的过程参数,它们没有规格、
 * 也没有规则,属于「无从判定」。若照常算进分母,一份本来全合格的报告会被这些行压成「待判定」。
 *
 * 只读,不改代码、不碰数据库。用法:npx tsx .qc-conformance/verify-undecidable.ts
 */
import type { ReportContextItem } from '../src/components/quality/engine/context';
 
import { createContext } from '../src/components/quality/engine/context';
import { evaluateReport } from '../src/components/quality/engine/report-evaluator';
 
type Item = Partial<ReportContextItem> & { itemName: string };
 
const base = { reportNo: 'QC-2026-0001', reportName: '来料检验报告' };
 
function evaluate(items: Item[], rules: unknown[] = []) {
  const context = createContext({ report: base, inspectionItems: items as ReportContextItem[] });
  return evaluateReport(context, rules as never);
}
 
/** 一条带规格上下限的项,用来当「正常可判定」的对照组 */
const withLimits = (name: string, actual: string, upper: number, lower: number): Item => ({
  itemName: name,
  actualValue: actual,
  upperLimit: upper,
  lowerLimit: lower,
});
 
/** 一条只供公式取数的过程参数:既没有上下限、也没有自带结果 */
const processParam = (name: string, actual: string): Item => ({ itemName: name, actualValue: actual });
 
const failures: string[] = [];
 
function expect(label: string, actual: unknown, wanted: unknown) {
  const ok = actual === wanted;
  if (!ok) {
    failures.push(`${label}:期望 ${JSON.stringify(wanted)},实际 ${JSON.stringify(actual)}`);
  }
  // eslint-disable-next-line no-console
  console.log(`${ok ? '  ok  ' : ' FAIL '} ${label} = ${JSON.stringify(actual)}`);
}
 
// --------- 场景 1:过程参数 + 可判定项混排,报告仍然应当给出「合格」
{
  // eslint-disable-next-line no-console
  console.log('\n===== 场景 1:试样质量 m(过程参数)不该把全合格的报告压成待判定 =====');
  const outcome = evaluate([withLimits('长度', '10.2', 10.5, 9.5), processParam('试样质量 m', '50.2')]);
  const report = outcome.context.report;
  const items = outcome.context.inspectionItems;
 
  expect('长度.resultText', items[0].resultText, '合格');
  expect('试样质量 m.resultText', items[1].resultText, '无判定规则');
  expect('试样质量 m.result', items[1].result, '');
  expect('report.total(真实项数)', report.total, 2);
  expect('report.passCount', report.passCount, 1);
  expect('report.failCount', report.failCount, 0);
  expect('report.passRate(分母只算可判定项)', report.passRate, '100.00%');
  expect('report.result', report.result, 'PASS');
  expect('report.conclusion', report.conclusion, '合格');
  // eslint-disable-next-line no-console
  console.log(`  问题清单:${JSON.stringify(outcome.errors)}`);
}
 
// --------- 场景 2:一项都判不了时不硬给结论
{
  // eslint-disable-next-line no-console
  console.log('\n===== 场景 2:全部是无判定规则项,合格率留空、不给结论 =====');
  const outcome = evaluate([processParam('试样质量 m', '50.2'), processParam('称量瓶 m0', '28.7')]);
  const report = outcome.context.report;
 
  expect('report.total', report.total, 2);
  expect('report.passRate', report.passRate, '');
  expect('report.result', report.result, '');
  expect('report.conclusion', report.conclusion, '待判定');
}
 
// --------- 场景 3:待判定(规则跑挂)仍留在分母里,仍压住合格结论
{
  // eslint-disable-next-line no-console
  console.log('\n===== 场景 3:待判定(规则跑挂)仍计入分母、仍不给合格结论 =====');
  const outcome = evaluate(
    [withLimits('长度', '10.2', 10.5, 9.5), withLimits('宽度', '4.9', 5.0, 4.0), processParam('外观', '无划痕')],
    // 「无划痕」不是数字,ABS 在它身上算不出来 → 该项待判定
    [{ id: 'r1', name: '实测值可算', scope: 'item', expression: 'ABS(item.actualValue) >= 0' }],
  );
  const report = outcome.context.report;
  const items = outcome.context.inspectionItems;
 
  expect('长度.resultText', items[0].resultText, '合格');
  expect('外观.resultText', items[2].resultText, '待判定');
  expect('report.total', report.total, 3);
  expect('report.passCount', report.passCount, 2);
  expect('report.passRate(待判定项留在分母里)', report.passRate, '66.67%');
  expect('report.result(没验过不给合格)', report.result, '');
  expect('report.conclusion', report.conclusion, '待判定');
}
 
// eslint-disable-next-line no-console
console.log(
  failures.length === 0
    ? '\n全部通过:无判定规则不计入分母与结论,待判定仍计入分母并压住合格结论。'
    : `\n有 ${failures.length} 处不符:\n${failures.map((line) => `  - ${line}`).join('\n')}`,
);
process.exitCode = failures.length === 0 ? 0 : 1;