Archived
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:
@@ -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 复核过:
|
||||
* ① **带下划线的枚举值一律显示成「待定」**——平台有两套互相打架的消毒规则:
|
||||
|
||||
@@ -567,6 +567,11 @@ export const ASSESSMENT_STEPS = [
|
||||
item: 'S3_review' as const,
|
||||
intent: '把逐条结论摆给人过目,他就地改四态与影响说明,改到没问题为止',
|
||||
guide: '',
|
||||
/* Task 8:人核对结论用的验收工单 —— 对决头(原 PN → 候选 PN)+ 四态分布带 + 推荐等级大徽章
|
||||
只读,逐条明细可就地改(四态 / 影响说明 / 判断依据 / UNKNOWN 去向),收口四格
|
||||
(推荐理由 / 差异摘要 / 风险 / 验证要求)只读——它们是配方按规则算的,人改了上面的四态,
|
||||
这一步的 auto.do 里那两笔投影(RELATION_PROJECTION / VALIDATION_PROJECTION)会重算它们。 */
|
||||
view: 'difference-review',
|
||||
writes: ['substitution.difference_item', 'substitution.relation', 'validation.record'],
|
||||
reads: ['substitution.difference_item', 'substitution.relation'],
|
||||
tools: [],
|
||||
|
||||
@@ -39,7 +39,7 @@ import type { ActivityManifest } from '@contracts';
|
||||
import { activityIdSchema } from '@contracts';
|
||||
import { CMMN_XML, NARRATIVE, ASSESSMENT_PHASES, ASSESSMENT_STEPS } from './case-model.ts';
|
||||
import { LEDGER_BOARD, LEDGER_BOARD_DATA } from './views/ledger-board.ts';
|
||||
import { INPUT_SUPPLEMENT } from './views/report.ts';
|
||||
import { INPUT_SUPPLEMENT, DIFFERENCE_REVIEW } from './views/report.ts';
|
||||
import { ACTIVITY_ID_TEXT, D } from './constants.ts';
|
||||
|
||||
export { D, RULE_VERSION } from './constants.ts';
|
||||
@@ -440,14 +440,17 @@ export const manifest: ActivityManifest = {
|
||||
/*
|
||||
* 五张旧局面全部作废(它们绑的九步与旧台账地址已经不存在)。**Task 7 已补回第一张**:
|
||||
* `input-supplement`(评估输入补全,S1 的数据工单,三块竖排 —— 存在性与主数据 /
|
||||
* 芯片类型字段 / 参数值)。`difference-review` / `landing-confirm` 两张新件由 Task 8/9
|
||||
* 各自加回;中途(Task 7–Task 9 之间)包不装,不会被静态审拦下。看板自己的 `data` 声明
|
||||
* 现在也引着已经不存在的台账地址(`sub_eval.pn_check` 等)——Task 9「运营中心看板重绑」
|
||||
* 会把它换成新九张表。
|
||||
* 芯片类型字段 / 参数值)。**Task 8 已补回第二张**:`difference-review`(差异评估结论审核,
|
||||
* S3 的验收工单 —— 对决头 + 四态分布带 + 推荐等级大徽章只读,逐条明细可就地改四态 /
|
||||
* 影响说明 / 判断依据 / UNKNOWN 去向,收口四格只读)。`landing-confirm` 仍待 Task 9 加回;
|
||||
* 中途(Task 8–Task 9 之间)包不装,不会被静态审拦下。看板自己的 `data` 声明现在也引着
|
||||
* 已经不存在的台账地址(`sub_eval.pn_check` 等)——Task 9「运营中心看板重绑」会把它换成
|
||||
* 新九张表。
|
||||
*/
|
||||
viewTemplates: [
|
||||
{ name: 'activity-ledger', html: LEDGER_BOARD, data: LEDGER_BOARD_DATA },
|
||||
{ name: 'input-supplement', html: INPUT_SUPPLEMENT },
|
||||
{ name: 'difference-review', html: DIFFERENCE_REVIEW },
|
||||
],
|
||||
cardSchemas: {},
|
||||
/* 蒸馏钩子撤空:它是给 agent 在终态回看轨迹用的,而这个活动全程无 agent(AI 只出场一次、答一份结构化判断,没有可供归纳的多轮轨迹) */
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
* 顶部一条红带摆 S1 配方算好的 `gate_reason`(「还差什么」的一句话,配方 §see case-model.ts
|
||||
* 的 step④),够不够齐、该不该出现由样式表判(§5「模版不许算」)。
|
||||
*
|
||||
* `difference-review`(件② 差异评估结论审核)与 `landing-confirm`(件④ 评审放行与落账确认)
|
||||
* 由 Task 8 / 9 分别重做(同名新建),这份文件此刻只有一张工单件。
|
||||
* `difference-review`(件② 差异评估结论审核)已由 Task 8 重做并交付(见文件尾「局面:差异评估
|
||||
* 结论审核」一节);`landing-confirm`(件③ 落账确认)仍待 Task 9 重做(同名新建)。
|
||||
*
|
||||
* 版面语言仍是「搬,不要照着做」(《HTML报告生成规范》§7):`P08_CSS`(逐字节抽自
|
||||
* `docs/SS02-ACT-WORK-05-html/ACT-WORK-05-数据工单-01-芯片主数据创建.html`,
|
||||
@@ -25,7 +25,7 @@
|
||||
* `data-class-of` 的 `v-*` 别名):目标件是写死数据的静态 demo,没有「N 行草稿」
|
||||
* 「编辑态与归档态二选一」这些平台概念。
|
||||
*/
|
||||
import { P08_CSS } from './target-style.ts';
|
||||
import { P08_CSS, ACC1_CSS } from './target-style.ts';
|
||||
import { D } from '../constants.ts';
|
||||
|
||||
/* ====================================================================================
|
||||
@@ -407,3 +407,243 @@ export const INPUT_SUPPLEMENT = doc({
|
||||
PARAMETER_TABLE +
|
||||
flow('<b>提交 / 确认:</b>本工单只承载内容;确认请在对话区的【执行卡】中进行。确认后活动自动从「等待数据」唤醒。'),
|
||||
});
|
||||
|
||||
/* ==================== 局面:差异评估结论审核(difference-review,S3 的验收工单) ==================== */
|
||||
|
||||
/*
|
||||
* **这一段是本活动自己的平台绑定,不是「抽目标件」**(与 BIND_P08 不同源)。
|
||||
* 老目标件(`docs/SS02-ACT-WORK-05-html/ACT-WORK-05-验收工单-01-差异评估结论审核.html`)
|
||||
* 整页只读——「通过 / 驳回」写死在对话区的验收卡里,demo 本身从没有过「点开编辑」这回事,
|
||||
* 所以它被机械抽出来的 `ACC1_CSS` 里没有 `.jc-vcell`/`.jc-cell`/`.jc-editgate`/`table.on`
|
||||
* 这一整套(`P08_CSS` 有,是因为「数据工单-01」目标件自己的原型 demo 就带点击编辑的 JS)。
|
||||
* spec §4.4/§6.2 把这一步从纯只读改成「人就地改四态,配方重算」——这是这次重写新加的能力,
|
||||
* 我们不能假装老目标件本来就有、只是「漏抄」了它。尺寸按 ACC1 的表格字号(13px)调,
|
||||
* 强调色用页面自己的 `--ledger`(验收绿),不借 P08 的 `--data`(蓝)。
|
||||
*/
|
||||
const BIND_ACC1_EDIT = `
|
||||
.jc-vcell{display:block;font-size:13px;color:var(--ink);line-height:1.6;overflow-wrap:anywhere}
|
||||
.jc-vcell.mono{font-family:var(--mono);font-size:12px;color:var(--ink-2)}
|
||||
.jc-vcell.ro{display:block}
|
||||
.jc-cell{display:none;width:100%;min-width:64px;border:1px solid var(--line);border-radius:6px;padding:6px 8px;font:inherit;font-size:12.5px;color:var(--ink);background:#fff}
|
||||
.jc-cell:focus{border-color:var(--ledger);box-shadow:0 0 0 3px var(--ledger-soft);outline:none}
|
||||
table.on td>.jc-vcell{display:none}
|
||||
table.on td>.jc-vcell.ro{display:block}
|
||||
table.on td>.jc-cell{display:block}
|
||||
/* 主键的隐藏钥匙格(substitution_relation_id / difference_item_id)—— 不给人看(一串内部编号),
|
||||
但必须真在 DOM 里挂 data-col:漏了钥匙,人保存的行服务端凑不出主键(2026-08-02 栽过)。 */
|
||||
.rowkey{display:none}
|
||||
th.req::after{content:" *";color:var(--danger);font-size:11px}
|
||||
.desc{color:var(--ink-3);font-size:12px;line-height:1.5}
|
||||
.jc-editgate{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin:14px 0 10px;padding:9px 12px;border-radius:9px;background:var(--soft);border:1px solid var(--line-soft);font-size:12px;color:var(--ink-3)}
|
||||
.jc-editgate-t{flex:1 1 auto;min-width:0}
|
||||
.jc-editgate-t b{color:var(--ink-2);font-weight:700}
|
||||
.jc-egbtn{flex:none;display:inline-flex;align-items:center;gap:5px;cursor:pointer;border:1px solid var(--line);border-radius:7px;padding:6px 13px;font:inherit;font-size:12px;font-weight:700;color:var(--ink-2);background:#fff;transition:border-color .16s,color .16s,background .16s}
|
||||
.jc-egbtn:hover{border-color:var(--ledger);color:var(--ledger)}
|
||||
.jc-egbtn.save{color:#fff;background:var(--ledger);border-color:var(--ledger)}
|
||||
.jc-egbtn.save:hover{filter:brightness(1.06);color:#fff}
|
||||
.jc-editgate .eg-cancel,.jc-editgate .eg-save{display:none}
|
||||
.jc-editgate.on{background:var(--ledger-soft);border-color:var(--ledger-line);color:#0f6a5d}
|
||||
.jc-editgate.on .eg-open{display:none}
|
||||
.jc-editgate.on .eg-cancel,.jc-editgate.on .eg-save{display:inline-flex}
|
||||
`;
|
||||
|
||||
/**
|
||||
* 徽标别名 —— 四态(可改列的只读孪生)/ 约束类型(只读)/ 推荐等级(只读,规则算的)/ 替代风险(只读)。
|
||||
* 全部走 `badgeCss()`(与 `BIND_P08` 同一套机制):选择器与文案从 `[值, 人读名, 颜色]` 算,
|
||||
* 不手写 —— `data-class-of` 消毒出来的是 `v-<值>`,手写选择器对不上是本仓踩过三次的坑。
|
||||
*/
|
||||
const DIFF_STATUS_OPTIONS: ReadonlyArray<readonly [string, string]> = [
|
||||
['match', 'MATCH'],
|
||||
['mismatch', 'MISMATCH'],
|
||||
['unknown', 'UNKNOWN'],
|
||||
['conditional', 'CONDITIONAL'],
|
||||
];
|
||||
const BIND_ACC1_BADGE = `
|
||||
/* 四态(substitution.difference_item.difference_status)—— 徽标文案与下面下拉框的选项同一份字面量表(陷阱表:上下两态得说同一个字) */
|
||||
${badgeCss('.st', [
|
||||
['match', 'MATCH', OK],
|
||||
['mismatch', 'MISMATCH', DANGER],
|
||||
['unknown', 'UNKNOWN', AMBER],
|
||||
['conditional', 'CONDITIONAL', 'color: var(--brand-deep); background: var(--brand-wash); border-color: var(--brand-soft);'],
|
||||
])}
|
||||
/* 约束类型(hard/soft)—— 只读,与 input-supplement 同一套颜色语义 */
|
||||
${badgeCss('.ct', [
|
||||
['hard', '硬约束', DANGER],
|
||||
['soft', '软约束', MUTED],
|
||||
])}
|
||||
/* 推荐等级(substitution.relation.recommendation_level)—— 规则算的,人不改;.rec-lg 放大成头部大徽章 */
|
||||
${badgeCss('.rec', [
|
||||
['recommended', '推荐', OK],
|
||||
['conditional', '有条件推荐', AMBER],
|
||||
['not_recommended', '不推荐', DANGER],
|
||||
])}
|
||||
.rec.rec-lg{font-size:14px;padding:6px 18px;letter-spacing:.02em}
|
||||
/* 替代风险(收口四格的「风险」,substitution.relation.risk_level)—— 走徽标而不裸摆英文枚举值 */
|
||||
${badgeCss('.risk-badge', [
|
||||
['low', '低风险', OK],
|
||||
['medium', '中风险', AMBER],
|
||||
['high', '高风险', DANGER],
|
||||
])}
|
||||
`;
|
||||
|
||||
/**
|
||||
* 对决头(原 PN → 候选 PN,共享同一个芯片类型)+ 四态分布带 + 收口四格的 kv 行样式 —— spec §6.2「顶」「下」。
|
||||
* 分布条的宽度梯子照 quote-pricing 的 `.jc-distbar` 抄同一招(`data-class-of` 把条数投影成 `v-<N>`,
|
||||
* 梯子在样式表里取宽;模版仍只取值不算)。
|
||||
*/
|
||||
const BIND_ACC1_LAYOUT = `
|
||||
.duel{display:flex;align-items:center;gap:16px;flex-wrap:wrap;margin:0 0 16px;padding:16px 18px;border:1px solid var(--ledger-line);border-radius:12px;background:linear-gradient(120deg,#f5fdfb 0%,#fff 60%)}
|
||||
.duel-pn{flex:1 1 190px;min-width:150px}
|
||||
.duel-role{display:block;font-size:10.5px;font-weight:800;letter-spacing:.1em;color:var(--ink-4);margin-bottom:4px}
|
||||
.duel-name{display:block;font-size:18px;font-weight:800;color:var(--ink);font-family:var(--mono);overflow-wrap:anywhere}
|
||||
.duel-mid{flex:none;display:flex;flex-direction:column;align-items:center;gap:6px}
|
||||
.duel-arrow{font-size:20px;color:var(--ledger);font-weight:800;line-height:1}
|
||||
.duel-type{font-size:11px;font-weight:700;color:var(--ink-3);background:var(--soft);border:1px solid var(--line-soft);border-radius:999px;padding:2px 10px;white-space:nowrap}
|
||||
.duel-rec{flex:none}
|
||||
@media(max-width:640px){.duel{flex-direction:column;align-items:stretch}.duel-mid{flex-direction:row;justify-content:center}}
|
||||
.dist{margin:0 0 18px}
|
||||
.dist-bar{display:flex;height:10px;border-radius:999px;overflow:hidden;background:var(--soft);border:1px solid var(--line-soft)}
|
||||
.dist-bar>i{flex:0;display:block}
|
||||
.dist-bar>i.v-0,.dist-bar>i:not([class*=" v-"]){display:none}
|
||||
.dist-bar>i.v-1{flex:1}.dist-bar>i.v-2{flex:2}.dist-bar>i.v-3{flex:3}.dist-bar>i.v-4{flex:4}
|
||||
.dist-bar>i.v-5{flex:5}.dist-bar>i.v-6{flex:6}.dist-bar>i.v-7{flex:7}.dist-bar>i.v-8{flex:8}
|
||||
.dist-bar>i.v-9{flex:9}.dist-bar>i.v-10{flex:10}.dist-bar>i.v-11{flex:11}.dist-bar>i.v-12{flex:12}
|
||||
.dist-bar>i.v-13{flex:13}.dist-bar>i.v-14{flex:14}.dist-bar>i.v-15{flex:15}.dist-bar>i.v-16{flex:16}
|
||||
.dist-bar>i.v-17{flex:17}.dist-bar>i.v-18{flex:18}.dist-bar>i.v-19{flex:19}.dist-bar>i.v-20{flex:20}
|
||||
.dist-bar>i.m{background:var(--ok)}.dist-bar>i.x{background:var(--danger)}.dist-bar>i.u{background:var(--amber)}.dist-bar>i.c{background:var(--brand-deep)}
|
||||
.dist-lg{display:flex;flex-wrap:wrap;gap:14px;margin-top:8px;font-size:11.5px;color:var(--ink-3)}
|
||||
.dist-lg em{display:inline-block;width:9px;height:9px;border-radius:3px;margin-right:5px;vertical-align:-1px}
|
||||
.dist-lg em.m{background:var(--ok)}.dist-lg em.x{background:var(--danger)}.dist-lg em.u{background:var(--amber)}.dist-lg em.c{background:var(--brand-deep)}
|
||||
.dist-lg b{color:var(--ink);font-weight:800}
|
||||
.kv{display:flex;gap:10px;padding:9px 0;border-bottom:1px solid var(--line-soft);font-size:12.5px}
|
||||
.kv:last-child{border-bottom:0}
|
||||
.kv i{flex:0 0 84px;font-style:normal;color:var(--ink-4);font-size:11px;padding-top:1px}
|
||||
.kv span{flex:1 1 auto;color:var(--ink-2);line-height:1.6;overflow-wrap:anywhere}
|
||||
.kv span:empty::after{content:"—";color:var(--ink-4)}
|
||||
.summary-box{border:1px solid var(--line-soft);border-radius:10px;background:var(--soft);padding:2px 16px;margin-bottom:4px}
|
||||
`;
|
||||
|
||||
/**
|
||||
* 对决头 —— **只读**。`original_internal_pn`/`candidate_internal_pn` 是 `substitution.relation`
|
||||
* 这一单唯一一行草稿写下的字段,任务视图把它们摊到了顶层作用域(裸 `data-slot` 就取得到,
|
||||
* 与 `eval_ref`/`gate_reason` 同一条道理)。类型名沿用 `input-supplement` 的 `PART_TABLE`
|
||||
* 已验证过的查表写法:`data-rows="parts.chip_type" data-by="type_id=chip_type_id"` ——
|
||||
* `chip_type_id` 在两颗料上必须相等(S2 的入场哨兵已经把关过),这里只需查一次。
|
||||
*/
|
||||
const DUEL = `<div class="duel">
|
||||
<div class="duel-pn">
|
||||
<span class="duel-role">原内部料号</span>
|
||||
<span class="duel-name mono" data-slot="original_internal_pn" data-blank></span>
|
||||
</div>
|
||||
<div class="duel-mid">
|
||||
<span class="duel-type">芯片类型 · <span data-rows="parts.chip_type" data-by="type_id=chip_type_id"><i data-slot="type_name" data-blank></i></span></span>
|
||||
<span class="duel-arrow">→</span>
|
||||
</div>
|
||||
<div class="duel-pn">
|
||||
<span class="duel-role">候选内部料号</span>
|
||||
<span class="duel-name mono" data-slot="candidate_internal_pn" data-blank></span>
|
||||
</div>
|
||||
<div class="duel-rec"><span class="rec rec-lg" data-class-of="recommendation_level"></span></div>
|
||||
</div>`;
|
||||
|
||||
/**
|
||||
* 四态分布带 —— 四个基座 tally 读数各自身兼两职:`data-slot` 摆计数字面值,
|
||||
* `data-class-of` 把同一个数投影成宽度梯子的 class(`v-<N>`)。两个属性长在同一个元素上,
|
||||
* 与 `quote-pricing` 的 `.jc-distbar` 完全同款(见该文件 `DIST` 常量)。
|
||||
*/
|
||||
const DIST_PREFIX = 'substitution_difference_item_difference_status_';
|
||||
const DIST = `<div class="dist">
|
||||
<div class="dist-bar">
|
||||
<i class="m" data-class-of="${DIST_PREFIX}match" data-slot="${DIST_PREFIX}match"></i>
|
||||
<i class="x" data-class-of="${DIST_PREFIX}mismatch" data-slot="${DIST_PREFIX}mismatch"></i>
|
||||
<i class="u" data-class-of="${DIST_PREFIX}unknown" data-slot="${DIST_PREFIX}unknown"></i>
|
||||
<i class="c" data-class-of="${DIST_PREFIX}conditional" data-slot="${DIST_PREFIX}conditional"></i>
|
||||
</div>
|
||||
<div class="dist-lg">
|
||||
<span><em class="m"></em>MATCH · <b data-slot="${DIST_PREFIX}match"></b></span>
|
||||
<span><em class="x"></em>MISMATCH · <b data-slot="${DIST_PREFIX}mismatch"></b></span>
|
||||
<span><em class="u"></em>UNKNOWN · <b data-slot="${DIST_PREFIX}unknown"></b></span>
|
||||
<span><em class="c"></em>CONDITIONAL · <b data-slot="${DIST_PREFIX}conditional"></b></span>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
/**
|
||||
* 逐条差异明细 —— **唯一可改的一张表**。四态 / 影响说明 / 判断依据 / UNKNOWN 去向四列可改,
|
||||
* 其余(参数项 / 说明 / 约束 / 原值 / 候选值 / 单位)只读。
|
||||
*
|
||||
* **两枚主键都挂 `data-col`**(`substitution_relation_id` + `difference_item_id`,复合主键,
|
||||
* 与 `input-supplement` 的 `PARAMETER_TABLE` 同一条约定):它们不摆给人看(一串内部编号,
|
||||
* 对审核没有信息量),裹进 `.rowkey`(`display:none`)藏起来 —— 但必须真的在 DOM 里,
|
||||
* 人保存这一行时服务端 `resolveRowKey` 才凑得出主键。表头补一个不显示文字的 `<th>` 与它对位,
|
||||
* 首尾列数对得上。
|
||||
*/
|
||||
const DIFF_ITEM_TABLE = `<div class="tbl-wrap"><table>
|
||||
<thead><tr>
|
||||
<th style="width:36px">#</th>
|
||||
<th data-h="参数项 parameter_name">参数项</th>
|
||||
<th data-h="参数说明 parameter_desc">参数说明</th>
|
||||
<th data-h="约束类型 constraint_type">约束</th>
|
||||
<th data-h="原PN值 original_value">原 PN 值</th>
|
||||
<th data-h="候选PN值 candidate_value">候选 PN 值</th>
|
||||
<th data-h="单位 parameter_unit">单位</th>
|
||||
<th class="req" data-h="结论 difference_status">结论(四态)</th>
|
||||
<th class="req" data-h="影响说明 impact_statement">影响说明</th>
|
||||
<th class="req" data-h="判断依据 evidence_note">判断依据</th>
|
||||
<th data-h="UNKNOWN去向 unknown_disposition">UNKNOWN 去向</th>
|
||||
<th style="display:none"></th>
|
||||
</tr></thead>
|
||||
<tbody data-rows="mine:substitution.difference_item" data-edit="substitution.difference_item"><tr>
|
||||
<td class="num"></td>
|
||||
<td class="cust" data-slot="parameter_name" data-blank></td>
|
||||
<td class="desc" data-slot="parameter_desc" data-blank></td>
|
||||
<td><span class="jc-vcell ro">${badge('ct', 'constraint_type')}</span></td>
|
||||
<td class="mono" data-slot="original_value" data-blank></td>
|
||||
<td class="mono" data-slot="candidate_value" data-blank></td>
|
||||
<td data-slot="parameter_unit" data-blank></td>
|
||||
<td>${badge('st', 'difference_status', true)}${select('difference_status', DIFF_STATUS_OPTIONS, true)}</td>
|
||||
<td>${cell('impact_statement')}</td>
|
||||
<td>${cell('evidence_note')}</td>
|
||||
<td>${cell('unknown_disposition')}</td>
|
||||
<td class="rowkey">${cell('difference_item_id')}${cell('substitution_relation_id')}</td>
|
||||
</tr></tbody>
|
||||
</table></div>`;
|
||||
|
||||
/**
|
||||
* 收口四格 —— **只读**。推荐理由 / 差异摘要 / 验证要求三格是自由文本,裸 `data-slot`;
|
||||
* 风险走徽标(`data-class-of`,避免直显 `low`/`medium`/`high` 这类英文枚举原值,
|
||||
* 与「陷阱表:枚举列不许 data-slot 直显机器码」同一条纪律)。四格全部读 `substitution.relation`,
|
||||
* 但**这一段没有任何 `data-edit`**——它们是配方按 §3.5 规则算出来的,要改就去改上面的四态。
|
||||
*/
|
||||
const CLOSING_SUMMARY = `<div class="summary-box">
|
||||
<div class="kv"><i>推荐理由</i><span data-slot="recommendation_reason" data-blank></span></div>
|
||||
<div class="kv"><i>差异摘要</i><span data-slot="difference_summary" data-blank></span></div>
|
||||
<div class="kv"><i>替代风险</i><span class="risk-badge" data-class-of="risk_level"></span></div>
|
||||
<div class="kv"><i>验证要求</i><span data-slot="verification_requirement" data-blank></span></div>
|
||||
</div>`;
|
||||
|
||||
export const DIFFERENCE_REVIEW = doc({
|
||||
css: ACC1_CSS,
|
||||
alias: BIND_ACC1_EDIT + BIND_ACC1_BADGE + BIND_ACC1_LAYOUT,
|
||||
badge: '验收',
|
||||
tag: '验收工单',
|
||||
kicker: 'SS02 · ACT-WORK-05 差异评估 · 验收工单 1/2',
|
||||
title: '差异评估结论审核',
|
||||
step: '步骤 3/4 · 结论审核',
|
||||
footTag: '工单类型:验收',
|
||||
body:
|
||||
zone('AI 结论说明', '结论是怎么算出来的', ZIC_TASK) +
|
||||
note([
|
||||
'<span class="done">AI 已完成的判定</span>:按差异规则(锁定版本 <b data-slot="rule_version" data-blank></b>),对两颗料在同一芯片类型下的每一条核心参数逐一比对,给出 MATCH / MISMATCH / UNKNOWN / CONDITIONAL 四态之一 —— 硬约束不满足即 MISMATCH,证据不足即 UNKNOWN,不会被措辞改判成 MATCH。',
|
||||
'<span class="need">系统按规则算出</span>:推荐等级、替代风险、差异摘要、推荐理由、验证要求 —— 这五项不是 AI 编的,是规则按下面四态分布算出来的;你改动下表里任何一条四态,这五项当场重算。',
|
||||
'<span class="need">就地核对</span>:逐条对过原 PN 与候选 PN 的取值、硬约束是否含糊放过、UNKNOWN 是否有验证去向 —— 要改就在下表里改四态、影响说明、判断依据、UNKNOWN 去向,改完保存即生效,不必重新调用 AI。',
|
||||
]) +
|
||||
DUEL +
|
||||
DIST +
|
||||
zone('逐条差异明细', '一行一参数,与原 PN 逐项对比;结论 / 影响说明 / 判断依据 / UNKNOWN 去向可就地改', ZIC_TABLE) +
|
||||
editGate('substitution.difference_item', '逐条核对结论、影响说明、判断依据,点「编辑」开表') +
|
||||
gapbar('substitution_difference_item', '必填') +
|
||||
DIFF_ITEM_TABLE +
|
||||
zone('收口结论', '系统按规则算出,要改就去改上面的四态 —— 让人直接改这几格,等于让他给自己没做的判断盖章', ZIC_TASK) +
|
||||
CLOSING_SUMMARY +
|
||||
flow('<b>审批:</b>本工单只承载内容;逐条核对无误后,请在对话区的【验收卡】中确认通过。通过后进入落账放行(T_release),签字后正式落账并发口。'),
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user