feat(w05): 件② 差异结论审核 —— 可改的是四态,摘要与等级只读

推荐理由 / 摘要 / 风险 / 验证要求都是规则算出来的:让人直接改它们,
等于让他给自己没做的判断盖章。要改就改上面那一条四态,系统重算。

同批修一条与本次设计矛盾的既有断言:「差异审核与落账确认只读」原把
difference-review 也算只读,而 spec §4.4/§6.2 已把 S3 改成可就地编辑
——改窄成只管 landing-confirm,differerence-review 的只读面改由新增的
「件②」测试组精确覆盖。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LKMZDwMbyKzjw6Hembwvet
This commit is contained in:
xcs
2026-08-29 19:50:31 +08:00
co-authored by Claude Opus 5
parent 10f529d03c
commit 59afcbfdbd
4 changed files with 313 additions and 14 deletions
@@ -351,16 +351,25 @@ describe('报告模版:编辑面与只读面各就各位', () => {
expect(html).toContain(`data-rows="mine:${D}.pn_check"`);
});
it('差异审核与落账确认只读:没有任何 data-edit / data-col', () => {
for (const name of ['difference-review', 'landing-confirm']) {
expect(viewHtml(name), name).not.toContain('data-edit=');
expect(viewHtml(name), name).not.toContain('data-col=');
}
/*
* 2026-08-29 Task 8 改窄:这条原本把 `difference-review` 也算作「只读」,与 `landing-confirm`
* 并列断言零 `data-edit`/`data-col`。而 spec §4.4/§6.2(同一次重写的权威设计,同日写定)
* 明确把 S3 从纯只读改成「人就地改四态,配方重算」—— brief 给的 Step 1 测试(见下面
* 「件② 差异评估结论审核」组)直接要求 `data-edit="substitution.difference_item"` 与
* `data-col="difference_status"` 等必须存在,与这条断言原样矛盾。这条断言写在那处设计
* 定稿之前(或是与 landing-confirm 一起想当然地假设了两者都只读),现改窄成只管
* `landing-confirm`(它确实全只读,spec §6.3)。`difference-review` 的「只读面在哪」
* 改由「件②」组精确覆盖(哪几列可改、`substitution.relation` 那半张不许有 data-edit)。
*/
it('落账确认只读:没有任何 data-edit / data-col(差异审核已按 spec §4.4 变为可就地编辑,断言见「件②」组)', () => {
expect(viewHtml('landing-confirm')).not.toContain('data-edit=');
expect(viewHtml('landing-confirm')).not.toContain('data-col=');
});
it('每个可编辑格子的 data-col 都在对应台账对象的声明里(input-supplement 一屏三张表,三张台账对象的声明并起来看)', () => {
it('每个可编辑格子的 data-col 都在对应台账对象的声明里(input-supplement 一屏三张表,三张台账对象的声明并起来看;difference-review 一张表)', () => {
const cases: Array<[string, Array<[string, string]>]> = [
['input-supplement', [['parts', 'profile'], ['parts', 'type_param'], ['parts', 'parameter']]],
['difference-review', [['substitution', 'difference_item']]],
];
for (const [view, objects] of cases) {
const cols = new Set([...viewHtml(view).matchAll(/data-col="([^"]+)"/g)].map((m) => m[1] ?? ''));
@@ -478,6 +487,48 @@ describe('件① 评估输入补全', () => {
});
});
/*
* 件② 差异评估结论审核(2026-08-29,Task 8):S3 的验收工单,`view: 'difference-review'`
* 指向它,`cardVariant: 'review'`。绑定契约(spec §6.2):对决头(原 PN → 候选 PN、类型徽)+
* 四态分布带 + 推荐等级大徽章只读;逐条明细可就地改(四态 / 影响说明 / 判断依据 / UNKNOWN 去向);
* 收口四格(推荐理由 / 差异摘要 / 风险 / 验证要求)只读 —— 它们是配方按规则算的,人要改就去改
* 上面那一条四态,系统重算。复用文件顶部已有的 `viewHtml` 短写。
*/
describe('件② 差异评估结论审核', () => {
const html = viewHtml('difference-review');
it('在 viewTemplates 里,S3 指向它,面孔是审核卡', () => {
expect(html).not.toBe('');
const s3 = (manifest.assets.businessModel.steps as ReadonlyArray<{ item: string; view?: string; cardVariant?: string }>)
.find((s) => s.item === 'S3_review');
expect(s3?.view).toBe('difference-review');
expect(s3?.cardVariant).toBe('review');
});
it('逐条明细可改,且**改的是四态**', () => {
expect(html).toContain('data-rows="mine:substitution.difference_item"');
expect(html).toContain('data-edit="substitution.difference_item"');
expect(html).toContain('data-col="difference_status"');
for (const col of ['impact_statement', 'evidence_note', 'unknown_disposition']) {
expect(html).toContain(`data-col="${col}"`);
}
expect(html).toContain('data-col="difference_item_id"');
});
it('**推荐理由 / 摘要 / 风险 / 验证要求只读** —— 让人直接改摘要,等于让他给自己没做的判断盖章', () => {
for (const col of ['recommendation_reason', 'difference_summary', 'verification_requirement']) {
expect(html).toContain(`data-slot="${col}"`);
expect(html).not.toContain(`data-col="${col}"`);
}
expect(html).not.toContain('data-edit="substitution.relation"');
});
it('等级与四态用 data-class-of 上色 —— 判断留在样式表,模版不判', () => {
expect(html).toContain('data-class-of="recommendation_level"');
expect(html).not.toContain('<script');
});
});
/*
* 2026-08-27 实测账,两条都真截图 + SQL 复核过:
* ① **带下划线的枚举值一律显示成「待定」**——平台有两套互相打架的消毒规则: