Archived
feat(w05): 件③ 落账确认与看板重绑 —— 签之前只核对,硬约束不符逐条点名
Task 9: 新增 landing-confirm(T_release 的终局验收工单,全只读,答「这一 签下去发生什么」——落账去向/结论卡/四态分布/硬约束逐条点名/待验项/发口), 三张件此刻齐了;activity-ledger 看板的 data 声明与 HTML 一并重绑到新九 张表(P-01/P-10 两域随重写撤下),解封 3 条等待三张件齐的 skip。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LKMZDwMbyKzjw6Hembwvet
This commit is contained in:
@@ -104,11 +104,11 @@ describe('清单本身合规', () => {
|
||||
});
|
||||
|
||||
/*
|
||||
* SKIP(2026-08-29,Task 2 → Task 7 部分交付):`input-supplement` 已随 Task 7 补回
|
||||
* `assets.viewTemplates`(`VIEWS` 已更新),但 `difference-review` / `landing-confirm`
|
||||
* 两张还在等 Task 8 / 9 —— `new Set(...)` 的整体相等要三张都在才成立,继续跳过。
|
||||
* 解封(2026-08-29,Task 9):`landing-confirm` 已随 Task 9 补回 —— `input-supplement`
|
||||
* (Task 7)/`difference-review`(Task 8)/`landing-confirm`(Task 9)三张全在了,
|
||||
* `new Set(...)` 的整体相等条件此刻才第一次成立。
|
||||
*/
|
||||
it.skip('三张工单视图 + 一张运营侧看板都声明了,剧本每一步引用的 view 都在其中', () => {
|
||||
it('三张工单视图 + 一张运营侧看板都声明了,剧本每一步引用的 view 都在其中', () => {
|
||||
expect(new Set(manifest.assets.viewTemplates.map((v) => v.name))).toEqual(new Set([...VIEWS, BOARD_VIEW]));
|
||||
for (const step of manifest.assets.businessModel.steps as ReadonlyArray<{ view?: string }>) {
|
||||
if (step.view !== undefined) expect(VIEWS, step.view).toContain(step.view);
|
||||
@@ -378,7 +378,15 @@ describe('报告模版:编辑面与只读面各就各位', () => {
|
||||
}
|
||||
});
|
||||
|
||||
/* SKIP(2026-08-29,Task 2 → Task 8/9):`difference-review` / `landing-confirm` 两张局面已撤下(新的两张由 Task 8/9 重做);它们绑的字段(recommendation_level 已只剩三档、analysis_status 已不带 tally)到时也会一并对齐 */
|
||||
/*
|
||||
* SKIP(2026-08-29,Task 9 复核后维持 skip):`difference-review` 那半句(第 383-385 行)
|
||||
* 这次实测确已成立(与「件②」组的等价断言重复,不必再靠这条揭封);但 `landing-confirm`
|
||||
* 那半句(第 386-390 行)测的 `request_status`/`current_stage` 是 `demand.request` 的列 ——
|
||||
* 这个活动的清单里从没声明过 `demand.request`(见「台账声明」组「这个活动不碰 P-01 / P-10 /
|
||||
* 客户档案」那条,已通过),`landing-confirm` 全只读、答的是「进哪几张表各几行」不是需求状态回写,
|
||||
* 这两个字段**不属于新设计的任何一步**。这不是「还没轮到」,是测的东西这次重写里压根不存在 ——
|
||||
* 一个 `it` 体绑死两半、拆不开,继续整条跳过,不强救。
|
||||
*/
|
||||
it.skip('枚举列只用 data-class-of 投影,不摆 ASCII 原值', () => {
|
||||
expect(viewHtml('difference-review')).toContain('data-class-of="difference_status"');
|
||||
expect(viewHtml('difference-review')).toContain('data-class-of="recommendation_level"');
|
||||
@@ -395,13 +403,8 @@ describe('报告模版:编辑面与只读面各就各位', () => {
|
||||
await expect(host.base.interaction.pushHtml('<div><script>x()</script></div>')).rejects.toThrow(/无脚本执行权/);
|
||||
});
|
||||
|
||||
/*
|
||||
* SKIP(2026-08-29,Task 2 → Task 7 部分交付):VIEWS 现在是三张新局面的名单,`input-supplement`
|
||||
* 已随 Task 7 补回、这一条本身可以对它验(外壳确实是 page/card),但 `difference-review` /
|
||||
* `landing-confirm` 两张还没有(viewHtml 返回空串,`toContain('class="card-head"')` 会假),
|
||||
* 循环体没法只验一部分 —— 等 Task 8/9 补齐三张再一起解封。
|
||||
*/
|
||||
it.skip('三张模版的外壳都是搬自目标件的 page/card,不再含 E04/I01 那套视觉底(.proto-root)的痕迹', () => {
|
||||
/* 解封(2026-08-29,Task 9):`landing-confirm` 补齐,三张全能验了 —— 都走同一个 `doc()` 壳。 */
|
||||
it('三张模版的外壳都是搬自目标件的 page/card,不再含 E04/I01 那套视觉底(.proto-root)的痕迹', () => {
|
||||
for (const view of VIEWS) {
|
||||
const html = viewHtml(view);
|
||||
expect(html, view).toContain('class="card-head"');
|
||||
@@ -549,6 +552,68 @@ describe('件② 差异评估结论审核', () => {
|
||||
});
|
||||
});
|
||||
|
||||
/*
|
||||
* 件③ 落账确认(2026-08-29,Task 9):T_release 的终局验收工单,`view: 'landing-confirm'` 指向它。
|
||||
* **全只读,答「这一签下去发生什么」(spec §6.3)**:进哪几张表各几行(摆人读名)· 结论卡
|
||||
* (等级 + 一句话)· 四态分布并把硬约束不符的逐条点名 · 待验项(P-06 的测试条件与后续动作)·
|
||||
* 发哪一口。复用文件顶部已有的 `viewHtml` 短写。
|
||||
*/
|
||||
describe('件③ 落账确认', () => {
|
||||
const html = viewHtml('landing-confirm');
|
||||
|
||||
it('在 viewTemplates 里,T_release 指向它', () => {
|
||||
expect(html).not.toBe('');
|
||||
expect((manifest.assets.businessModel.steps as ReadonlyArray<{ item: string; view?: string }>)
|
||||
.find((s) => s.item === 'T_release')?.view).toBe('landing-confirm');
|
||||
});
|
||||
|
||||
it('**全只读** —— 签之前只核对,不改', () => {
|
||||
expect(html).not.toContain('data-edit=');
|
||||
expect(html).not.toContain('data-col=');
|
||||
expect(html).not.toContain('<script');
|
||||
});
|
||||
|
||||
it('把「进哪几张表各几行」摆出来,用的是基座读数', () => {
|
||||
for (const reading of ['substitution_relation_rows', 'substitution_difference_item_rows', 'validation_record_rows']) {
|
||||
expect(html).toContain(`data-slot="${reading}"`);
|
||||
}
|
||||
});
|
||||
|
||||
it('硬约束不符的逐条点名 —— 签字的人最该看见的就是它', () => {
|
||||
expect(html).toContain('data-rows="mine:substitution.difference_item"');
|
||||
/*
|
||||
* **筛选交给样式表,不是 `data-by`** —— `data-by` 过滤的是「子列 = 外层那一行的父列」,
|
||||
* 这里没有外层行可依。做法:整表逐行渲出来,行上挂 `data-class-of="judgement_class"`,
|
||||
* 由 CSS 只显 `.v-hard_mismatch` 那几行(判断留在样式表,模版不判)。
|
||||
*/
|
||||
expect(html).toContain('data-class-of="judgement_class"');
|
||||
});
|
||||
|
||||
/*
|
||||
* `judgement_class` 的 tally 值 `hard_mismatch` 带下划线 —— `classToken`/`vtok` 只留
|
||||
* `[a-z0-9-]`(**吃掉下划线**),真正生效的选择器是 `.v-hardmismatch` 不是手写直觉的
|
||||
* `.v-hard_mismatch`(2026-08-27 已在这个包里踩过一次同款事故,`vtok` 是这条回归网)。
|
||||
*/
|
||||
it('过滤用的选择器是从值算出来的(vtok),不是手写的 —— 不许踩「带下划线的值显示成待定」那个坑', () => {
|
||||
expect(html).not.toContain('.v-hard_mismatch');
|
||||
expect(html).toContain('.v-hardmismatch');
|
||||
});
|
||||
});
|
||||
|
||||
describe('运营中心看板', () => {
|
||||
const board = manifest.assets.viewTemplates.find((v) => v.name === 'activity-ledger');
|
||||
|
||||
it('取数声明改绑新表,不再引已退役的那几张', () => {
|
||||
const json = JSON.stringify(board?.data ?? {});
|
||||
for (const gone of ['demand.request', 'parts.document', 'sub_eval.pn_check', 'sub_eval.input_gap', 'sub_eval.verdict']) {
|
||||
expect(json).not.toContain(gone);
|
||||
}
|
||||
for (const kept of ['sub_eval.case', 'substitution.relation', 'substitution.difference_item']) {
|
||||
expect(json).toContain(kept);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/*
|
||||
* 2026-08-27 实测账,两条都真截图 + SQL 复核过:
|
||||
* ① **带下划线的枚举值一律显示成「待定」**——平台有两套互相打架的消毒规则:
|
||||
@@ -561,10 +626,15 @@ describe('件② 差异评估结论审核', () => {
|
||||
* 静态 `class="req"` 把整列都标了必填。
|
||||
*/
|
||||
/*
|
||||
* SKIP(2026-08-29,Task 2 → Task 7-9 补回):`BADGED` 列表里的每一项都指着已撤下的五张局面
|
||||
* (p08-master-create 等)或已改动的字段(recommendation_level 掉了 alternate 档、
|
||||
* analysis_status 不再带 tally、`sub_eval.pn_check` 整个改名 `sub_eval.part`)。
|
||||
* 这整组「回归网」要等 Task 7–9 把新三张件补回来、字段清单也重新对齐后才谈得上继续钉。
|
||||
* SKIP(2026-08-29,Task 9 复核后维持 skip):三张新件与看板全部到位后复查过 ——
|
||||
* `BADGED` 列表 35 条里没有一条能原样救活:半数指着已彻底撤下的局面(`p08-master-create` /
|
||||
* `eval-input-list`,Task 7 范围内已不存在)或已退役的字段(`substitution_type` 整列退休、
|
||||
* `${D}.pn_check` 整个改名 `${D}.part`、`demand.request`/`parts.document` 两域这次重写
|
||||
* 本活动已不碰),另一半虽然指向真实存在的 view/字段(`difference-review`/`landing-confirm`
|
||||
* 的 `recommendation_level`/`risk_level`/`difference_status`/`constraint_type` 等),
|
||||
* 但混在同一个数组里没法只救活这几行 —— 拆开重写等于另起一份测试,超出「回归网」这条 skip
|
||||
* 本该做的事。这几条真正要钉的口径,「件②」「件③」两组已经用**显式点名**的断言钉过一遍
|
||||
* (逐条明细六列只读 / judgement_class 的 vtok 选择器),不必靠这条泛化清单再验一遍。
|
||||
*/
|
||||
describe.skip('徽标别名与值域相关的坑(2026-08-27 实测账,回归网)', () => {
|
||||
/** 必须与 `apps/api/src/modules/interaction/internal/domain/view-render.ts` 的 `classToken` 一字不差 */
|
||||
@@ -773,13 +843,13 @@ describe('activity-ledger:关键台账数据看板', () => {
|
||||
const declaredAddresses = new Set(manifest.declarations.ledger.map((l) => `${l.domain}.${l.object}`));
|
||||
|
||||
/*
|
||||
* SKIP(2026-08-29,Task 2 → Task 9 补回):看板的 `data` 声明(`views/ledger-board.ts` 的
|
||||
* `LEDGER_BOARD_DATA`)还圈着已退休的旧台账(`sub_eval.pn_check` / `sub_eval.verdict` /
|
||||
* `demand.request` / `customer.profile` / `parts.document`)—— Task 9「运营中心看板重绑」
|
||||
* 会把它换成新九张表;这条取数声明的自洽性检查到那时再验。html 自身的结构测试(下面三条)
|
||||
* 不依赖 `declarations.ledger`,仍然有效、继续跑。
|
||||
* 解封(2026-08-29,Task 9「运营中心看板重绑」):`LEDGER_BOARD_DATA` 已换成新九张表 ——
|
||||
* 案卷两张(`sub_eval.case`/`sub_eval.part`)+ 字段字典两张(`parts.chip_type`/`parts.type_param`)+
|
||||
* 参数对照两张(`parts.profile`/`parts.parameter`)+ 明细/关系(`substitution.difference_item`/
|
||||
* `substitution.relation`)+ P-06(`validation.record`,含同料号历史 `validation.history`),
|
||||
* 这条取数声明的自洽性检查此刻才第一次能验。
|
||||
*/
|
||||
it.skip('取数声明:案号台账是 record 且 key 是它的 caseKey、前缀 W05-;每条 rows 的表都已声明;from 只指 case 或前面的 as.列', () => {
|
||||
it('取数声明:案号台账是 record 且 key 是它的 caseKey、前缀 W05-;每条 rows 的表都已声明;from 只指 case 或前面的 as.列', () => {
|
||||
expect(data).toBeDefined();
|
||||
if (data === undefined) return;
|
||||
const caseLedger = manifest.declarations.ledger.find((l) => `${l.domain}.${l.object}` === data.case.ledger);
|
||||
@@ -803,18 +873,23 @@ describe('activity-ledger:关键台账数据看板', () => {
|
||||
}
|
||||
seen.add(entry.as);
|
||||
}
|
||||
// 六张主表 + 案号两张 + 同料号历史都圈了
|
||||
// 案卷两张 + 字段字典两张 + 参数对照两张 + 明细/关系 + P-06(含历史)都圈了
|
||||
expect([...seen]).toEqual(
|
||||
expect.arrayContaining([`${D}.verdict`, `${D}.pn_check`, 'demand.request', 'customer.profile', 'parts.profile', 'parts.parameter', 'parts.document', 'substitution.relation', 'substitution.difference_item', 'validation.record', 'validation.history']),
|
||||
expect.arrayContaining([`${D}.case`, `${D}.part`, 'parts.chip_type', 'parts.type_param', 'parts.profile', 'parts.parameter', 'substitution.relation', 'substitution.difference_item', 'validation.record', 'validation.history']),
|
||||
);
|
||||
});
|
||||
|
||||
it('html 里每个 data-rows 键都是声明里的一个 as(行由基座圈过,不是整表);嵌套只用 data-by 父键过滤', () => {
|
||||
const as = new Set(data?.rows.map((r) => r.as) ?? []);
|
||||
const keys = [...html.matchAll(/data-rows="([^"]+)"/g)].map((m) => m[1] ?? '');
|
||||
expect(keys.length).toBeGreaterThan(8);
|
||||
/*
|
||||
* 2026-08-29 Task 9:门槛从「> 8」(旧六张主表设计)降到「> 6」——新设计收成 8 处绑定
|
||||
* (P-08 主表 + 两处嵌套查表 / 字段字典 / 关系 / 明细 / P-06 本单 + 历史),门槛仍要求
|
||||
* 「不止一两处」这条哨兵语义,只是数字跟着新设计的真实形状改小,不是放水。
|
||||
*/
|
||||
expect(keys.length).toBeGreaterThan(6);
|
||||
for (const key of keys) expect(as.has(key), key).toBe(true);
|
||||
expect(html).toContain('<span class="pnrow" data-rows="sub_eval.pn_check" data-by="internal_pn">');
|
||||
expect(html).toContain(`<span class="pnrow" data-rows="${D}.part" data-by="internal_pn">`);
|
||||
expect(html).toContain('<div class="pchips" data-rows="parts.parameter" data-by="internal_pn">');
|
||||
expect(html).toContain('<tbody class="hist" data-rows="validation.history">');
|
||||
expect(html).not.toContain('mine:');
|
||||
@@ -833,15 +908,24 @@ describe('activity-ledger:关键台账数据看板', () => {
|
||||
expect(html).not.toContain('data-col=');
|
||||
});
|
||||
|
||||
it('目标件六张表的表头与页头要素都在;MATCH 行淡显、放弃的候选只在有 abandoned 时露面 —— 都是 class 交样式表,模版不判', () => {
|
||||
for (const header of ['<th>内部料号</th>', '<th>替代关系 ID</th>', '<th>参数项</th>', '<th>关联料号</th>', '<th>验证 ID</th>', '<th>标准化参数集</th>']) expect(html).toContain(header);
|
||||
/*
|
||||
* 2026-08-29 Task 9 改窄:六张表收成新九张(P-01/P-10 两张连同「关联需求」「关联料号」
|
||||
* 两列一起退休 —— 本活动已不碰 demand.request / parts.document);案号台账从 `${D}.verdict`
|
||||
* 改名 `${D}.case`;「放弃的候选」这一概念随多候选并行设计一起退役(新设计一次评估恰一对一
|
||||
* 候选,没有「本轮放弃的候选」这件事)。补一条**已退役地址不再出现**的回归网,同「运营中心看板」组同款纪律。
|
||||
*/
|
||||
it('新九张表的表头与页头要素都在;MATCH 行淡显 —— 都是 class 交样式表,模版不判', () => {
|
||||
for (const header of ['<th>内部料号</th>', '<th>替代关系 ID</th>', '<th>参数项</th>', '<th>验证 ID</th>', '<th>标准化参数集</th>', '<th>参数名</th>']) expect(html).toContain(header);
|
||||
expect(html).toContain('data-slot="case:instanceNo"');
|
||||
expect(html).toContain('data-slot="case:ref"');
|
||||
expect(html).toContain(`data-slot="${D}.verdict.original_internal_pn"`);
|
||||
expect(html).toContain('data-slot="demand.request.request_id"');
|
||||
expect(html).toContain('data-slot="substitution.relation.original_internal_pn"');
|
||||
expect(html).toContain(`data-slot="${D}.case.summary"`);
|
||||
expect(html).toContain('<tr data-class-of="difference_status">');
|
||||
expect(html).toContain('tr.v-match td{opacity:.55}');
|
||||
expect(html).toContain('.aband:has(i.v-abandoned){display:block}');
|
||||
expect(html).toContain('data-slot="substitution_difference_item_difference_status_unknown"');
|
||||
// 已退役的旧域 / 旧字段一律不出现
|
||||
for (const gone of ['demand.request', 'parts.document', `${D}.pn_check`, `${D}.verdict`, 'substitution_type', 'customer_approval', 'v-abandoned']) {
|
||||
expect(html, gone).not.toContain(gone);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -616,6 +616,10 @@ export const ASSESSMENT_STEPS = [
|
||||
item: 'T_release' as const,
|
||||
intent: '把这一签下去会落哪几张表、几行摆清楚,人签字后落账并发口',
|
||||
guide: '',
|
||||
/* Task 9:落账确认用的终局验收工单 —— 全只读,答「这一签下去发生什么」(spec §6.3):
|
||||
进哪几张表各几行 / 结论卡(等级 + 一句话)/ 四态分布并把硬约束不符逐条点名 /
|
||||
待验项(P-06 的测试条件与后续动作)/ 发哪一口。 */
|
||||
view: 'landing-confirm',
|
||||
/* 人工验收清单:一条一句他拿着这份工单要**亲自核**的动作,不是系统判的判据 */
|
||||
acceptanceChecklist: [
|
||||
'推荐等级与四态分布对得上:有硬约束不符的没给「推荐」',
|
||||
|
||||
@@ -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, DIFFERENCE_REVIEW } from './views/report.ts';
|
||||
import { INPUT_SUPPLEMENT, DIFFERENCE_REVIEW, LANDING_CONFIRM } from './views/report.ts';
|
||||
import { ACTIVITY_ID_TEXT, D } from './constants.ts';
|
||||
|
||||
export { D, RULE_VERSION } from './constants.ts';
|
||||
@@ -442,15 +442,18 @@ export const manifest: ActivityManifest = {
|
||||
* `input-supplement`(评估输入补全,S1 的数据工单,三块竖排 —— 存在性与主数据 /
|
||||
* 芯片类型字段 / 参数值)。**Task 8 已补回第二张**:`difference-review`(差异评估结论审核,
|
||||
* S3 的验收工单 —— 对决头 + 四态分布带 + 推荐等级大徽章只读,逐条明细可就地改四态 /
|
||||
* 影响说明 / 判断依据 / UNKNOWN 去向,收口四格只读)。`landing-confirm` 仍待 Task 9 加回;
|
||||
* 中途(Task 8–Task 9 之间)包不装,不会被静态审拦下。看板自己的 `data` 声明现在也引着
|
||||
* 已经不存在的台账地址(`sub_eval.pn_check` 等)——Task 9「运营中心看板重绑」会把它换成
|
||||
* 新九张表。
|
||||
* 影响说明 / 判断依据 / UNKNOWN 去向,收口四格只读)。**Task 9 已补回第三张**:
|
||||
* `landing-confirm`(落账确认,T_release 的终局验收工单 —— 全只读,答「这一签下去发生
|
||||
* 什么」:进哪几张表各几行 / 结论卡 / 四态分布并把硬约束不符逐条点名 / 待验项 / 发哪一口)。
|
||||
* 三张件此刻齐了。看板自己的 `data` 声明(`LEDGER_BOARD_DATA`)同批换成了新九张表 ——
|
||||
* `sub_eval.pn_check`/`sub_eval.verdict`/`demand.request`/`customer.profile`/
|
||||
* `parts.document` 这五张已退役地址不再出现。
|
||||
*/
|
||||
viewTemplates: [
|
||||
{ name: 'activity-ledger', html: LEDGER_BOARD, data: LEDGER_BOARD_DATA },
|
||||
{ name: 'input-supplement', html: INPUT_SUPPLEMENT },
|
||||
{ name: 'difference-review', html: DIFFERENCE_REVIEW },
|
||||
{ name: 'landing-confirm', html: LANDING_CONFIRM },
|
||||
],
|
||||
cardSchemas: {},
|
||||
/* 蒸馏钩子撤空:它是给 agent 在终态回看轨迹用的,而这个活动全程无 agent(AI 只出场一次、答一份结构化判断,没有可供归纳的多轮轨迹) */
|
||||
|
||||
@@ -1,52 +1,74 @@
|
||||
/**
|
||||
* 运营中心 L2 沙箱视图 —— ACT-WORK-05「关键台账数据」看板(2026-08-27)。
|
||||
* 运营中心 L2 沙箱视图 —— ACT-WORK-05「关键台账数据」看板(2026-08-27 初版,2026-08-29 Task 9 重绑)。
|
||||
*
|
||||
* 版式与样式逐字节搬自 `docs/ss02-act-05/ACT-WORK-05-关键台账数据.html`(只改两处:`.tbl-wrap` 放开横滑;
|
||||
* 徽标文案由 `data-class-of` 投影 + 生成式 `::after` 出,不再写死)。溯源口径照 `…-数据溯源.md`:
|
||||
* 页头 / P-01 一条 / P-08 逐颗 + 参数瓷贴(一格一列,不叠灰字次列 —— 2026-08-27 用户定)/ P-11 主记录 + 差异明细 / P-10(同样一格一列)/ P-06(本单 + 同料号历史)。
|
||||
* **2026-08-29 Task 9「运营中心看板重绑」**:2026-08-29 整体重写(spec
|
||||
* `docs/superpowers/specs/2026-08-29-act-work-05-rewrite-design.md`)把九步案例模型砍成四步、
|
||||
* 台账从旧的 `sub_eval.pn_check`/`sub_eval.verdict` 三张单据 + `demand.request`/`customer.profile`/
|
||||
* `parts.document` 五张外域表,换成本活动自持的 `sub_eval.case`/`sub_eval.part` 两张 + 新增的
|
||||
* `parts.chip_type`/`parts.type_param` 两张类型字典 —— 这份看板原样引着已退役的五张地址,
|
||||
* 装包会被静态审拦下。本轮把 `LEDGER_BOARD_DATA` 与 `LEDGER_BOARD` 一并**重绑**到新九张表:
|
||||
* 案卷(`sub_eval.case`)→ 两颗料(`sub_eval.part`)→ 类型与字段字典(`parts.chip_type`/
|
||||
* `parts.type_param`)→ 参数对照(`parts.profile`/`parts.parameter`)→ 关系与明细
|
||||
* (`substitution.relation`/`substitution.difference_item`)→ P-06(`validation.record`,
|
||||
* 含同料号历史 `validation.history`)。P-01 需求主台账 / P-10 原厂资料两个板块随之整段撤下 ——
|
||||
* 本活动这次重写已经不碰这两张表(见 manifest.ts「这个活动不碰 P-01 / P-10 / 客户档案」)。
|
||||
* 新设计是**一次评估恰一对一候选**(不再是「多候选,部分放弃」),`substitution.relation`
|
||||
* 一单一行、`sub_eval.part` 一单两行(原/候选各一),「候选」不再是需要 `data-rows` 逐个复制的
|
||||
* 集合,页头 / P-08 两处原来的 `.cands`(多候选并排)、`.aband`(放弃候选的候选行)两个概念
|
||||
* 一并撤下 —— 新模型里没有「本轮放弃的候选」这件事。
|
||||
*
|
||||
* 版式与样式**沿用**(重绑不是重做):页头 / 数据来源图例 / 分层图例 / 表格样式 / 三态横幅
|
||||
* 这几段版面语言原样保留;`.tbl-wrap` 放开横滑、徽标文案由 `data-class-of` 投影 + 生成式
|
||||
* `::after` 出的既有约定不变。溯源口径参照 `…-数据溯源.md`(该文档写在旧九步年代,
|
||||
* 域名对照以本文件为准)。
|
||||
*
|
||||
* **它摆的是最近一次已放行实例的落账快照**(用户定):行由基座按 `LEDGER_BOARD_DATA` 的声明从**正式表**圈出 ——
|
||||
* 每个 `data-rows` 键都是声明里的一个 `as`,不是整表;`<as>.<列>` 是那一集合首行的标量,`<as 去符号>_rows` /
|
||||
* `_<列>_<值>` 是基座数出来的读数(`apps/api/src/app/activity-ops/view-scope.ts`)。模版仍**不算不判**:
|
||||
* MATCH 行淡显、放弃的候选、三态横幅,全是 `data-class-of` 投出的 class 交样式表。
|
||||
* MATCH 行淡显、三态横幅,全是 `data-class-of` 投出的 class 交样式表。
|
||||
* 无脚本、无外链(过安装静态审);报高脚本由服务端出口注入。
|
||||
*/
|
||||
import type { ViewData } from '@contracts';
|
||||
import { badgeCss } from './badge.ts';
|
||||
import { D } from '../constants.ts';
|
||||
|
||||
/** 案号 `W05-<开案时刻 14 位>`(与说明书让模型铸 `eval_ref` 的写法同源);行集按案号 → 核对表 → 料号 / 需求逐表圈 */
|
||||
/**
|
||||
* 案号 `W05-<开案时刻 14 位>`(与说明书让模型铸 `eval_ref` 的写法同源);行集按案号 → 案卷 →
|
||||
* 两颗料 → 类型字典(按案卷锁定的 `chip_type_id` 查)→ 主数据 / 参数(按两颗料的 `internal_pn` 查)→
|
||||
* 关系(按案号查,一单一行)→ 明细(按关系的主键查,`by.from` 必须指向**前面**已求出的集合 ——
|
||||
* 明细依赖关系的主键,所以 `rows` 数组里关系排在明细**之前**,即便「关系」是这一签最终的结论、
|
||||
* 「明细」是支撑结论的逐条证据,版面上想先摆哪个都行,数据依赖顺序是另一件事)→ P-06(按案号查,
|
||||
* 一单固定一条;同料号历史另开一集,按两颗料的 `internal_pn` 查、排除本单自己那一条)。
|
||||
*/
|
||||
export const LEDGER_BOARD_DATA: ViewData = {
|
||||
case: { ledger: `${D}.verdict`, key: 'eval_ref', prefix: 'W05-' },
|
||||
case: { ledger: `${D}.case`, key: 'eval_ref', prefix: 'W05-' },
|
||||
rows: [
|
||||
{ as: `${D}.verdict`, ledger: `${D}.verdict`, by: { column: 'eval_ref', from: 'case' } },
|
||||
/* 原 PN 排第一(original > candidate),下游按料号圈的表都随这个顺序 */
|
||||
{ as: `${D}.pn_check`, ledger: `${D}.pn_check`, by: { column: 'eval_ref', from: 'case' }, orderBy: [{ field: 'role', dir: 'desc' }, { field: 'internal_pn', dir: 'asc' }] },
|
||||
{ as: 'demand.request', ledger: 'demand.request', by: { column: 'request_id', from: `${D}.verdict.request_id` } },
|
||||
{ as: 'customer.profile', ledger: 'customer.profile', by: { column: 'customer_code', from: 'demand.request.customer_code' } },
|
||||
{ as: 'parts.profile', ledger: 'parts.profile', by: { column: 'internal_pn', from: `${D}.pn_check.internal_pn` } },
|
||||
{ as: 'parts.parameter', ledger: 'parts.parameter', by: { column: 'internal_pn', from: `${D}.pn_check.internal_pn` }, orderBy: [{ field: 'param_name', dir: 'asc' }] },
|
||||
{ as: 'parts.document', ledger: 'parts.document', by: { column: 'internal_pn', from: `${D}.pn_check.internal_pn` }, orderBy: [{ field: 'doc_seq', dir: 'asc' }] },
|
||||
{ as: 'substitution.relation', ledger: 'substitution.relation', by: { column: 'eval_ref', from: 'case' }, orderBy: [{ field: 'substitution_relation_id', dir: 'asc' }] },
|
||||
{ as: `${D}.case`, ledger: `${D}.case`, by: { column: 'eval_ref', from: 'case' } },
|
||||
{ as: `${D}.part`, ledger: `${D}.part`, by: { column: 'eval_ref', from: 'case' }, orderBy: [{ field: 'role', dir: 'desc' }, { field: 'internal_pn', dir: 'asc' }] },
|
||||
{ as: 'parts.chip_type', ledger: 'parts.chip_type', by: { column: 'type_id', from: `${D}.case.chip_type_id` } },
|
||||
{ as: 'parts.type_param', ledger: 'parts.type_param', by: { column: 'type_id', from: `${D}.case.chip_type_id` }, orderBy: [{ field: 'param_name', dir: 'asc' }] },
|
||||
{ as: 'parts.profile', ledger: 'parts.profile', by: { column: 'internal_pn', from: `${D}.part.internal_pn` } },
|
||||
{ as: 'parts.parameter', ledger: 'parts.parameter', by: { column: 'internal_pn', from: `${D}.part.internal_pn` }, orderBy: [{ field: 'param_name', dir: 'asc' }] },
|
||||
{ as: 'substitution.relation', ledger: 'substitution.relation', by: { column: 'eval_ref', from: 'case' } },
|
||||
{
|
||||
as: 'substitution.difference_item',
|
||||
ledger: 'substitution.difference_item',
|
||||
by: { column: 'substitution_relation_id', from: 'substitution.relation.substitution_relation_id' },
|
||||
orderBy: [{ field: 'difference_item_id', dir: 'asc' }],
|
||||
},
|
||||
{ as: 'validation.record', ledger: 'validation.record', by: { column: 'request_id', from: `${D}.verdict.request_id` }, orderBy: [{ field: 'validation_id', dir: 'asc' }] },
|
||||
/* 同料号在别单 / 别处留下的验证记录:本次评估的历史证据引用(目标件 P-06 里 VAL-2026-0040 / 0032 那两行的位置) */
|
||||
{ as: 'validation.record', ledger: 'validation.record', by: { column: 'eval_ref', from: 'case' } },
|
||||
/* 同料号在别单 / 别处留下的验证记录:本次评估的历史证据引用,排除本单自己那一条 */
|
||||
{
|
||||
as: 'validation.history',
|
||||
ledger: 'validation.record',
|
||||
by: { column: 'validation_internal_pn', from: `${D}.pn_check.internal_pn` },
|
||||
not: { column: 'request_id', from: `${D}.verdict.request_id` },
|
||||
by: { column: 'validation_internal_pn', from: `${D}.part.internal_pn` },
|
||||
not: { column: 'eval_ref', from: 'case' },
|
||||
orderBy: [{ field: 'validation_id', dir: 'desc' }],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
/* ==================== 目标件样式(逐字节搬;两处改动标了 [改]) ==================== */
|
||||
/* ==================== 目标件样式(基座壳与版面语言沿用旧版;域名相关内容按新九张表改写) ==================== */
|
||||
const TARGET_CSS = `
|
||||
:root{
|
||||
--ink:#1f2329; --ink-2:#41464e; --ink-3:#646a73; --ink-4:#8f959e;
|
||||
@@ -80,15 +102,14 @@ body{font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,
|
||||
.dot.full{background:var(--brand)}
|
||||
.dot.half{background:var(--amber)}
|
||||
|
||||
/* 分层图例 */
|
||||
.layers{display:grid;grid-template-columns:repeat(5,1fr);gap:10px;margin:14px 0 18px}
|
||||
/* 分层图例 —— 新九张表收成四层(P-01/P-10 两层随重写撤下) */
|
||||
.layers{display:grid;grid-template-columns:repeat(4,1fr);gap:10px;margin:14px 0 18px}
|
||||
.layer{background:#fff;border:1px solid var(--line-soft);border-radius:11px;padding:11px 14px;font-size:12px;color:var(--ink-2);border-top:3px solid var(--brand)}
|
||||
.layer b{display:block;font-size:12.5px;color:var(--ink);margin-bottom:2px}
|
||||
.layer .lg{font-family:var(--mono);font-weight:800;color:var(--brand-deep)}
|
||||
.layer.core-out{border-top-color:var(--ledger)} .layer.core-out .lg{color:var(--ledger)}
|
||||
.layer.evid{border-top-color:var(--human)} .layer.evid .lg{color:var(--human)}
|
||||
.layer.loop{border-top-color:var(--amber)} .layer.loop .lg{color:var(--amber)}
|
||||
.layer.ctx{border-top-color:var(--ink-4)} .layer.ctx .lg{color:var(--ink-3)}
|
||||
|
||||
/* 区块 */
|
||||
section{background:#fff;border:1px solid var(--line-soft);border-radius:14px;padding:18px 22px;margin-bottom:16px}
|
||||
@@ -100,11 +121,10 @@ section{background:#fff;border:1px solid var(--line-soft);border-radius:14px;pad
|
||||
.ltag.out{color:var(--ledger);background:var(--ledger-soft);border-color:var(--ledger-line)}
|
||||
.ltag.evid{color:var(--human);background:var(--human-soft);border-color:var(--human-line)}
|
||||
.ltag.loop{color:var(--amber);background:var(--amber-soft);border-color:var(--amber-line)}
|
||||
.ltag.ctx{color:var(--ink-3);background:var(--soft);border-color:var(--line)}
|
||||
.sec-head .why{font-size:12px;color:var(--ink-4)}
|
||||
.sec-head .cnt{margin-left:auto;font-size:11.5px;color:var(--ink-4);font-family:var(--mono)}
|
||||
|
||||
/* 表格 —— [改] 目标件写 overflow:hidden,列一多右边被裁且滑不动;本仓 2026-08-23 定:表宽超出就得能横滑 */
|
||||
/* 表格 —— 表宽超出就得能横滑(本仓 2026-08-23 定) */
|
||||
.tbl-wrap{border:1px solid var(--line-soft);border-radius:10px;overflow-x:auto;overflow-y:hidden}
|
||||
.jc-tbl-wrap, .tbl-wrap { overflow-x: auto; overflow-y: hidden; }
|
||||
table{width:100%;border-collapse:collapse;font-size:12.5px}
|
||||
@@ -115,6 +135,7 @@ tbody tr{transition:background .15s}
|
||||
tbody tr:hover{background:var(--brand-wash)}
|
||||
.mono{font-family:var(--mono);font-size:12px;color:var(--ink-2)}
|
||||
.pn{font-weight:700}
|
||||
.cust{font-weight:700}
|
||||
|
||||
/* 状态 pill */
|
||||
.st{display:inline-block;padding:1px 9px;border-radius:999px;font-size:11px;font-weight:800;white-space:nowrap;border:1px solid transparent}
|
||||
@@ -125,13 +146,6 @@ tbody tr:hover{background:var(--brand-wash)}
|
||||
.st.gray{color:var(--ink-3);background:var(--soft);border-color:var(--line)}
|
||||
.st.warn{color:var(--human);background:var(--human-soft);border-color:var(--human-line)}
|
||||
|
||||
/* P-01 单记录 KV 卡 */
|
||||
.kv{display:grid;grid-template-columns:repeat(4,1fr);gap:1px;background:var(--line-soft);border:1px solid var(--line-soft);border-radius:10px;overflow:hidden}
|
||||
.kv .cell{background:#fff;padding:10px 14px}
|
||||
.kv .k{font-size:11px;font-weight:800;color:var(--ink-4);margin-bottom:2px}
|
||||
.kv .v{font-size:12.5px;color:var(--ink);line-height:1.5}
|
||||
.kv .span2{grid-column:span 2}
|
||||
|
||||
/* 参数集摘要 chips */
|
||||
.pchips{display:flex;flex-wrap:wrap;gap:4px}
|
||||
.pchips span{font-size:11px;font-family:var(--mono);background:var(--soft);border:1px solid var(--line-soft);border-radius:6px;padding:1px 7px;color:var(--ink-2);white-space:nowrap}
|
||||
@@ -143,48 +157,40 @@ tbody tr:hover{background:var(--brand-wash)}
|
||||
.minor .m .lid{font-family:var(--mono);color:var(--ink-4);font-weight:700;margin-right:6px}
|
||||
|
||||
footer{margin-top:18px;font-size:11.5px;color:var(--ink-4);display:flex;justify-content:space-between;flex-wrap:wrap;gap:8px}
|
||||
@media(max-width:900px){.layers{grid-template-columns:repeat(2,1fr)}.kv{grid-template-columns:1fr 1fr}.kv .span2{grid-column:span 2}}
|
||||
@media(max-width:900px){.layers{grid-template-columns:repeat(2,1fr)}}
|
||||
`;
|
||||
|
||||
/* ==================== 绑定层:徽标别名 / 三态横幅 / 淡显 —— 只取值,不算不判 ==================== */
|
||||
/* ==================== 绑定层:徽标别名 —— 只取值,不算不判 ==================== */
|
||||
const OK = 'color:var(--ok);background:var(--ok-soft);border-color:#bfe6b4;';
|
||||
const MISS = 'color:var(--danger);background:var(--danger-soft);border-color:#f3b9b5;';
|
||||
const UNKNOWN = 'color:var(--amber);background:var(--amber-soft);border-color:var(--amber-line);';
|
||||
const COND = 'color:var(--brand-deep);background:var(--brand-wash);border-color:var(--brand-soft);';
|
||||
const GRAY = 'color:var(--ink-3);background:var(--soft);border-color:var(--line);';
|
||||
const WARN = 'color:var(--human);background:var(--human-soft);border-color:var(--human-line);';
|
||||
|
||||
const BIND_CSS = `
|
||||
/* 徽标:值域各归各族(同一个词在不同列意思不同,如 pending 在资料状态是待生效、在需求状态是待处理),
|
||||
文案与颜色由 data-class-of 投出的 v-<token> 决定;没投出 class 的格子摆「—」,客户批准那格摆「未提交」 */
|
||||
/* 徽标:值域各归各族(同一个词在不同列意思不同),文案与颜色由 data-class-of 投出的 v-<token> 决定;
|
||||
没投出 class 的格子摆「—」 */
|
||||
.st::after{content:"—"}
|
||||
.st.ap::after{content:"未提交"}
|
||||
${badgeCss('.st.lc', [
|
||||
['active', 'Active', OK],
|
||||
['nrnd', 'NRND', MISS],
|
||||
['eol', 'EOL', MISS],
|
||||
['discontinued', '停产', MISS],
|
||||
['risk', '风险', WARN],
|
||||
['risk', '风险', UNKNOWN],
|
||||
])}
|
||||
${badgeCss('.st.rec', [
|
||||
['recommended', '推荐', OK],
|
||||
['conditional', '条件推荐', WARN],
|
||||
['alternate', '备选', COND],
|
||||
['conditional', '条件推荐', UNKNOWN],
|
||||
['not_recommended', '不推荐', MISS],
|
||||
])}
|
||||
/* analysis_status 这次重写没有再声明 tally(本活动只写这一个固定值,分析层与客户批准层分离) */
|
||||
${badgeCss('.st.an', [
|
||||
['ai_draft', 'AI 草稿', GRAY],
|
||||
['fae_confirmed', 'FAE确认', COND],
|
||||
['pending_customer', '待客户验证', WARN],
|
||||
['customer_approved', '客户已批准', OK],
|
||||
['rejected', '不批准', MISS],
|
||||
['void', '作废', GRAY],
|
||||
['fae_confirmed', 'FAE已确认', COND],
|
||||
])}
|
||||
${badgeCss('.st.rk', [
|
||||
['low', '低', OK],
|
||||
['medium', '中', WARN],
|
||||
['medium', '中', UNKNOWN],
|
||||
['high', '高', MISS],
|
||||
['critical', '危急', MISS],
|
||||
])}
|
||||
${badgeCss('.st.dst', [
|
||||
['match', 'MATCH', OK],
|
||||
@@ -192,36 +198,15 @@ ${badgeCss('.st.dst', [
|
||||
['unknown', 'UNKNOWN', UNKNOWN],
|
||||
['conditional', 'CONDITIONAL', COND],
|
||||
])}
|
||||
/* validation_status 同样没有声明 tally(本活动只写 not_started —— 验证是否通过不是这个活动的事) */
|
||||
${badgeCss('.st.vs', [
|
||||
['not_started', '未开始', GRAY],
|
||||
['in_progress', '进行中', COND],
|
||||
['passed', '通过', OK],
|
||||
['failed', '未通过', MISS],
|
||||
['conditional', '条件通过', WARN],
|
||||
['pending_evidence', '待证据', UNKNOWN],
|
||||
])}
|
||||
${badgeCss('.st.ds', [
|
||||
['valid', '有效', OK],
|
||||
['expired', '过期', MISS],
|
||||
['pending', '待生效', WARN],
|
||||
['void', '作废', GRAY],
|
||||
])}
|
||||
${badgeCss('.st.rq', [
|
||||
['pending', '待处理', GRAY],
|
||||
['responded', '已响应', COND],
|
||||
['won', '已成交', OK],
|
||||
['abandoned', '已放弃', MISS],
|
||||
['closed', '已关闭', GRAY],
|
||||
])}
|
||||
${badgeCss('.st.stg', [
|
||||
['assessing', '评估中', GRAY],
|
||||
['gate03', '提交 ACT-GATE-03', OK],
|
||||
])}
|
||||
/* 在库状态(sub_eval.part.exists_status)—— 这次重写只剩两档(found/absent),
|
||||
「本单建档」「已放弃」两档随旧的多候选设计一起退役 */
|
||||
${badgeCss('.st.ex', [
|
||||
['found', '在库直读', COND],
|
||||
['created', '本单建档', OK],
|
||||
['absent', '缺库', MISS],
|
||||
['abandoned', '已放弃', GRAY],
|
||||
])}
|
||||
${badgeCss('.st.rl', [
|
||||
['original', '原 PN', COND],
|
||||
@@ -229,36 +214,20 @@ ${badgeCss('.st.rl', [
|
||||
])}
|
||||
/* 纯文字的枚举列:只补文案 */
|
||||
.enumtxt::after{content:"—"}
|
||||
${badgeCss('.enumtxt.ty', [
|
||||
['pin_to_pin', 'Pin-to-Pin'],
|
||||
['functional', '功能替代'],
|
||||
['parametric', '参数替代'],
|
||||
['other', '其他'],
|
||||
])}
|
||||
${badgeCss('.enumtxt.con', [
|
||||
['hard', '硬约束'],
|
||||
['soft', '软约束'],
|
||||
])}
|
||||
/* validation_type 这次重写多了 parametric 一档(S2 的验证记录投影固定写它) */
|
||||
${badgeCss('.enumtxt.vt', [
|
||||
['pin_to_pin', 'Pin-to-Pin'],
|
||||
['functional', '功能'],
|
||||
['reliability', '可靠性'],
|
||||
['certification', '认证'],
|
||||
['retest', '复测'],
|
||||
])}
|
||||
${badgeCss('.enumtxt.dt', [
|
||||
['datasheet', 'Datasheet'],
|
||||
['app_note', '应用笔记'],
|
||||
['reference_design', '参考设计'],
|
||||
['white_paper', '白皮书'],
|
||||
['sample_doc', '样品资料'],
|
||||
['commitment_letter', '承诺函'],
|
||||
['other', '其他'],
|
||||
['parametric', '参数验证'],
|
||||
])}
|
||||
|
||||
/* 页头候选料号:一行内逐个摆,用顿号连;一个都没有就摆「—」 */
|
||||
.cands b+b::before{content:"、";font-weight:400;color:var(--ink-3)}
|
||||
.cands:empty::after{content:"—"}
|
||||
/* 参数瓷贴:参数名淡、值粗、单位紧跟 */
|
||||
.pchips i{font-style:normal;color:var(--ink-4);margin-right:3px}
|
||||
.pchips b{font-weight:700}
|
||||
@@ -269,12 +238,6 @@ ${badgeCss('.enumtxt.dt', [
|
||||
.pnrow .st{font-size:10px;padding:0 7px}
|
||||
/* 差异明细:MATCH 行淡显(不藏:那也是比对过的事实),非 MATCH 才是要看的 */
|
||||
tr.v-match td{opacity:.55}
|
||||
/* 已放弃的候选:只在有 abandoned 行时露面,别的核对行不显 */
|
||||
.aband{display:none;font-size:12px;color:var(--ink-3);margin:8px 0 0}
|
||||
.aband i{font-style:normal;font-family:var(--mono);color:var(--ink-2)}
|
||||
.aband i:not(.v-abandoned){display:none}
|
||||
.aband i+i.v-abandoned::before{content:"、"}
|
||||
.aband:has(i.v-abandoned){display:block}
|
||||
/* P-06 历史行:首格挂一枚「历史」灰签 */
|
||||
tbody.hist td:first-child::after{content:"历史";display:inline-block;margin-left:6px;font-size:10px;font-weight:800;padding:0 6px;border-radius:999px;color:var(--ink-3);background:var(--soft);border:1px solid var(--line);font-family:Inter,ui-sans-serif,system-ui,sans-serif}
|
||||
td .sub{display:block;font-size:11px;color:var(--ink-3);font-weight:400}
|
||||
@@ -305,8 +268,8 @@ export const LEDGER_BOARD = `<!doctype html>
|
||||
<header class="mast">
|
||||
<div class="kick">SS02 需求分析与方案匹配 · 活动台账视图</div>
|
||||
<h1><span class="code">ACT-WORK-05</span>关键台账数据</h1>
|
||||
<p class="sub case">视角:本活动最近一次已放行实例 <b data-slot="case:instanceNo"></b>(<b data-slot="case:openedAt"></b> 开案 · <b data-slot="case:releasedAt"></b> 放行 · 负责人 <b data-slot="case:owner" data-blank></b>)的落账快照 · 案号 <b class="mono" data-slot="case:ref"></b> · 关联需求 <b data-slot="demand.request.request_id"></b>(客户 <b data-slot="demand.request.customer_code"></b> <span data-slot="customer.profile.name" data-blank></span>)· 评估基准 <b data-slot="${D}.verdict.original_internal_pn"></b>(<span data-slot="parts.profile.brand_name" data-blank></span>)→ 候选 <span class="cands" data-rows="substitution.relation"><b data-slot="candidate_internal_pn"></b></span> · 规则版本 <b data-slot="${D}.verdict.rule_version"></b></p>
|
||||
<p class="sub verdict">评估结论:<span data-slot="${D}.verdict.summary" data-blank></span></p>
|
||||
<p class="sub case">视角:本活动最近一次已放行实例 <b data-slot="case:instanceNo"></b>(<b data-slot="case:openedAt"></b> 开案 · <b data-slot="case:releasedAt"></b> 放行 · 负责人 <b data-slot="case:owner" data-blank></b>)的落账快照 · 案号 <b class="mono" data-slot="case:ref"></b> · 评估基准 <b data-slot="substitution.relation.original_internal_pn"></b> → 候选 <b data-slot="substitution.relation.candidate_internal_pn"></b> · 芯片类型 <span data-slot="parts.chip_type.type_name" data-blank></span> · 规则版本 <b data-slot="substitution.relation.rule_version"></b></p>
|
||||
<p class="sub verdict">评估结论:<span data-slot="${D}.case.summary" data-blank></span></p>
|
||||
<div class="legend">
|
||||
<span class="li"><span class="dot full"></span>正式台账直读 —— 放行落地后的事实,按案号圈出这一单的行</span>
|
||||
<span class="li"><span class="dot half"></span>同料号的历史验证记录(别单 / 线下留下的,作本次评估的证据引用)</span>
|
||||
@@ -319,64 +282,57 @@ export const LEDGER_BOARD = `<!doctype html>
|
||||
<!-- 重要性分层 -->
|
||||
<div class="layers">
|
||||
<div class="layer"><b><span class="lg">P-08</span> 芯片主数据</b>核心输入 · 评估原材料,查无即硬阻塞</div>
|
||||
<div class="layer evid"><b><span class="lg">字段字典</span> 类型与核心参数</b>比对基准 · 按芯片类型定义要比的字段与硬软约束</div>
|
||||
<div class="layer core-out"><b><span class="lg">P-11</span> 替代批准关系库</b>核心产出 · 结论与明细的落账地</div>
|
||||
<div class="layer evid"><b><span class="lg">P-10</span> 原厂技术资料库</b>证据链 · 每项结论的版本化出处</div>
|
||||
<div class="layer loop"><b><span class="lg">P-06</span> 样品验证记录</b>闭环去向 · UNKNOWN 的实测收口</div>
|
||||
<div class="layer ctx"><b><span class="lg">P-01</span> 客户需求主台账</b>上下文 · 需求源头与回写对象</div>
|
||||
</div>
|
||||
|
||||
<!-- P-01 -->
|
||||
<section id="p01">
|
||||
<div class="sec-head">
|
||||
<h2><span class="lid">P-01</span>客户需求主台账</h2>
|
||||
<span class="ltag ctx">上下文 · R+W</span>
|
||||
<span class="why">启动时新建需求;结束时回写风险 / 验证要求 / 输出链接 / 下一步 / 当前阶段</span>
|
||||
<span class="cnt">正式表 · <i data-slot="demand_request_rows"></i> 条</span>
|
||||
</div>
|
||||
<div class="kv">
|
||||
<div class="cell"><div class="k">需求编号</div><div class="v mono" data-slot="demand.request.request_id"></div></div>
|
||||
<div class="cell"><div class="k">客户</div><div class="v mono"><span data-slot="demand.request.customer_code"></span> <span class="sub" data-slot="customer.profile.name" data-blank></span></div></div>
|
||||
<div class="cell"><div class="k">需求版本</div><div class="v mono" data-slot="demand.request.requirement_version"></div></div>
|
||||
<div class="cell"><div class="k">需求状态</div><div class="v"><span class="st rq" data-class-of="demand.request.request_status"></span></div></div>
|
||||
<div class="cell span2"><div class="k">需求描述</div><div class="v" data-slot="demand.request.request_description"></div></div>
|
||||
<div class="cell"><div class="k">应用场景</div><div class="v" data-slot="demand.request.application_scenario" data-blank></div></div>
|
||||
<div class="cell"><div class="k">BOM 位</div><div class="v mono" data-slot="demand.request.bom_position" data-blank></div></div>
|
||||
<div class="cell"><div class="k">原内部料号</div><div class="v mono" data-slot="demand.request.original_internal_pn"></div></div>
|
||||
<div class="cell"><div class="k">候选内部料号</div><div class="v mono cands" data-rows="substitution.relation"><b data-slot="candidate_internal_pn"></b></div></div>
|
||||
<div class="cell"><div class="k">风险等级(回写)</div><div class="v"><span class="st rk" data-class-of="demand.request.risk_level"></span></div></div>
|
||||
<div class="cell"><div class="k">验证要求(回写)</div><div class="v mono" data-slot="demand.request.verification_requirement" data-blank></div></div>
|
||||
<div class="cell"><div class="k">当前阶段</div><div class="v"><span class="st stg" data-class-of="demand.request.current_stage"></span></div></div>
|
||||
<div class="cell"><div class="k">标准输出链接</div><div class="v mono" data-slot="demand.request.output_ref" data-blank></div></div>
|
||||
<div class="cell span2"><div class="k">下一步动作</div><div class="v" data-slot="demand.request.next_action" data-blank></div></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- P-08 -->
|
||||
<section id="p08">
|
||||
<div class="sec-head">
|
||||
<h2><span class="lid">P-08</span>芯片主数据台账</h2>
|
||||
<span class="ltag in">核心输入 · R(查无 → 数据工单创建)</span>
|
||||
<span class="why">原 PN 与候选 PN 的物料基准 + 标准化参数集(子表 P-08 参数),逐项比对的原材料</span>
|
||||
<span class="cnt">正式表 · <i data-slot="parts_profile_rows"></i> 条(本活动相关)</span>
|
||||
<span class="cnt">正式表 · <i data-slot="parts_profile_rows"></i> 条(本次评估相关)</span>
|
||||
</div>
|
||||
<div class="tbl-wrap">
|
||||
<table>
|
||||
${th('内部料号', '品牌', '规格描述', '封装', '生命周期', 'Datasheet 版本', '标准化参数集', '适配场景')}
|
||||
${th('内部料号', '品牌', '规格描述', '生命周期', 'Datasheet 版本', '标准化参数集')}
|
||||
<tbody data-rows="parts.profile">
|
||||
<tr>
|
||||
<td class="pn mono"><span data-slot="internal_pn"></span><span class="pnrow" data-rows="${D}.pn_check" data-by="internal_pn"><i class="st rl" data-class-of="role"></i><i class="st ex" data-class-of="exists_status"></i></span></td>
|
||||
<td class="pn mono"><span data-slot="internal_pn"></span><span class="pnrow" data-rows="${D}.part" data-by="internal_pn"><i class="st rl" data-class-of="role"></i><i class="st ex" data-class-of="exists_status"></i></span></td>
|
||||
<td data-slot="brand_name" data-blank></td>
|
||||
<td data-slot="specification_description" data-blank></td>
|
||||
<td class="mono" data-slot="package" data-blank></td>
|
||||
<td><span class="st lc" data-class-of="lifecycle_status"></span></td>
|
||||
<td class="mono" data-slot="datasheet_version" data-blank></td>
|
||||
<td><div class="pchips" data-rows="parts.parameter" data-by="internal_pn"><span><i data-slot="param_name"></i><b data-slot="param_value" data-blank></b><em data-slot="param_unit" data-blank></em></span></div></td>
|
||||
<td data-slot="application_scenarios" data-blank></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p class="aband">本轮放弃的候选(未建档、未评估):<span data-rows="${D}.pn_check"><i data-class-of="exists_status" data-slot="internal_pn"></i></span></p>
|
||||
</section>
|
||||
|
||||
<!-- 字段字典 -->
|
||||
<section id="dict">
|
||||
<div class="sec-head">
|
||||
<h2><span class="lid">字段字典</span>芯片类型与核心参数</h2>
|
||||
<span class="ltag evid">比对基准 · R</span>
|
||||
<span class="why">两颗料共同归属的芯片类型,及该类型定义的核心参数字段(名字 / 说明 / 硬软约束 / 单位)</span>
|
||||
<span class="cnt">类型 · <b data-slot="parts.chip_type.type_name" data-blank></b> · 字段 <i data-slot="parts_type_param_rows"></i> 条</span>
|
||||
</div>
|
||||
<div class="tbl-wrap">
|
||||
<table>
|
||||
${th('参数名', '参数说明', '约束', '参考单位')}
|
||||
<tbody data-rows="parts.type_param">
|
||||
<tr>
|
||||
<td class="cust" data-slot="param_name"></td>
|
||||
<td class="sub" data-slot="param_desc" data-blank></td>
|
||||
<td><span class="enumtxt con" data-class-of="constraint_type"></span></td>
|
||||
<td class="mono" data-slot="param_unit" data-blank></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- P-11 -->
|
||||
@@ -384,71 +340,44 @@ export const LEDGER_BOARD = `<!doctype html>
|
||||
<div class="sec-head">
|
||||
<h2><span class="lid">P-11</span>替代选型与批准关系库 · 替代关系主记录</h2>
|
||||
<span class="ltag out">核心产出 · R+W</span>
|
||||
<span class="why">每个候选一条关系记录;客户批准状态为只读边界,本活动不写</span>
|
||||
<span class="why">原 PN → 候选 PN 一条关系记录;推荐等级 / 风险 / 摘要由规则算出,客户批准状态为只读边界,本活动不写</span>
|
||||
<span class="cnt">正式表 · <i data-slot="substitution_relation_rows"></i> 条</span>
|
||||
</div>
|
||||
<div class="tbl-wrap" style="margin-bottom:14px">
|
||||
<table>
|
||||
${th('替代关系 ID', '原 → 候选', '替代类型', '推荐等级', '分析状态', '风险', '差异摘要', '验证要求 / 回链', '规则版本', '客户批准(只读)')}
|
||||
${th('替代关系 ID', '原 → 候选', '推荐等级', '分析状态', '风险', '差异摘要 / 理由', '验证要求 / 回链', '规则版本')}
|
||||
<tbody data-rows="substitution.relation">
|
||||
<tr>
|
||||
<td class="mono" data-slot="substitution_relation_id"></td>
|
||||
<td class="mono"><span data-slot="original_internal_pn"></span> → <b data-slot="candidate_internal_pn"></b></td>
|
||||
<td><span class="enumtxt ty" data-class-of="substitution_type"></span></td>
|
||||
<td><span class="st rec" data-class-of="recommendation_level"></span></td>
|
||||
<td><span class="st an" data-class-of="analysis_status"></span></td>
|
||||
<td><span class="st rk" data-class-of="risk_level"></span></td>
|
||||
<td><span data-slot="difference_summary" data-blank></span><span class="sub" data-slot="recommendation_reason" data-blank></span></td>
|
||||
<td class="mono"><span data-slot="validation_id" data-blank></span><span class="sub" data-slot="verification_requirement" data-blank></span></td>
|
||||
<td class="mono" data-slot="rule_version" data-blank></td>
|
||||
<td><span class="st ap" data-class-of="customer_approval_status"></span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="sec-head" style="margin-bottom:10px">
|
||||
<h2 style="font-size:13.5px"><span class="lid">P-11</span>差异明细子表(由双方 P-08 标准化参数集逐项比对得出;MATCH 项淡显)</h2>
|
||||
<h2 style="font-size:13.5px"><span class="lid">P-11</span>差异明细子表(按字段字典逐项比对得出;MATCH 项淡显)</h2>
|
||||
<span class="cnt"><i data-slot="substitution_difference_item_rows"></i> 条 · MATCH <i data-slot="substitution_difference_item_difference_status_match"></i> · MISMATCH <i data-slot="substitution_difference_item_difference_status_mismatch"></i> · UNKNOWN <i data-slot="substitution_difference_item_difference_status_unknown"></i> · CONDITIONAL <i data-slot="substitution_difference_item_difference_status_conditional"></i></span>
|
||||
</div>
|
||||
<div class="tbl-wrap">
|
||||
<table>
|
||||
${th('所属关系', '参数项', '原值 → 候选值', '约束', '结论', '风险', '证据引用', '影响说明')}
|
||||
${th('参数项', '约束', '原值 → 候选值', '单位', '结论', '风险', '判断依据', '影响说明')}
|
||||
<tbody data-rows="substitution.difference_item">
|
||||
<tr data-class-of="difference_status">
|
||||
<td class="mono" data-slot="substitution_relation_id"></td>
|
||||
<td data-slot="parameter_name"></td>
|
||||
<td class="mono"><span data-slot="original_value" data-blank></span> → <span data-slot="candidate_value" data-blank></span> <span data-slot="parameter_unit" data-blank></span></td>
|
||||
<td><span class="enumtxt con" data-class-of="constraint_type"></span></td>
|
||||
<td class="mono"><span data-slot="original_value" data-blank></span> → <span data-slot="candidate_value" data-blank></span></td>
|
||||
<td data-slot="parameter_unit" data-blank></td>
|
||||
<td><span class="st dst" data-class-of="difference_status"></span></td>
|
||||
<td><span class="st rk" data-class-of="risk_level"></span></td>
|
||||
<td class="mono" data-slot="evidence_ref" data-blank></td>
|
||||
<td><span data-slot="impact_statement" data-blank></span><span class="sub" data-slot="unknown_disposition" data-blank></span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- P-10 -->
|
||||
<section id="p10">
|
||||
<div class="sec-head">
|
||||
<h2><span class="lid">P-10</span>原厂技术资料库</h2>
|
||||
<span class="ltag evid">证据链 · R(查无 → 数据工单创建)</span>
|
||||
<span class="why">每项结论的 datasheet 出处,版本回链</span>
|
||||
<span class="cnt">正式表 · <i data-slot="parts_document_rows"></i> 条(本活动相关料号)</span>
|
||||
</div>
|
||||
<div class="tbl-wrap">
|
||||
<table>
|
||||
${th('关联料号', '品牌', '资料类型', '资料文件', '版本', '状态')}
|
||||
<tbody data-rows="parts.document">
|
||||
<tr>
|
||||
<td class="mono"><span data-slot="internal_pn"></span> · <span data-slot="doc_seq" data-blank></span></td>
|
||||
<td data-slot="brand_name" data-blank></td>
|
||||
<td><span class="enumtxt dt" data-class-of="document_type"></span></td>
|
||||
<td class="mono" data-slot="document_ref" data-blank></td>
|
||||
<td class="mono" data-slot="document_version" data-blank></td>
|
||||
<td><span class="st ds" data-class-of="document_status"></span></td>
|
||||
<td class="mono" data-slot="evidence_note" data-blank></td>
|
||||
<td data-slot="impact_statement" data-blank></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -460,33 +389,29 @@ export const LEDGER_BOARD = `<!doctype html>
|
||||
<div class="sec-head">
|
||||
<h2><span class="lid">P-06</span>样品交付与芯片验证记录台账</h2>
|
||||
<span class="ltag loop">闭环去向 · R + 条件写(不可创建,只能实测产生)</span>
|
||||
<span class="why">UNKNOWN / CONDITIONAL 的收口处;验证完成后回链 P-11</span>
|
||||
<span class="why">UNKNOWN / CONDITIONAL 的收口处;一单固定一条</span>
|
||||
<span class="cnt">本单挂的 · <i data-slot="validation_record_rows"></i> 条 · 同料号历史 · <i data-slot="validation_history_rows"></i> 条</span>
|
||||
</div>
|
||||
<div class="tbl-wrap">
|
||||
<table>
|
||||
${th('验证 ID', '关联需求', '验证料号', '验证类型', '测试条件', '结果 / 状态', '问题与风险', '后续动作')}
|
||||
${th('验证 ID', '验证料号', '验证类型', '测试条件', '结果 / 状态', '后续动作')}
|
||||
<tbody data-rows="validation.record">
|
||||
<tr>
|
||||
<td class="mono" data-slot="validation_id"></td>
|
||||
<td class="mono" data-slot="request_id" data-blank></td>
|
||||
<td class="mono" data-slot="validation_internal_pn"></td>
|
||||
<td><span class="enumtxt vt" data-class-of="validation_type"></span></td>
|
||||
<td data-slot="test_condition" data-blank></td>
|
||||
<td><span class="st vs" data-class-of="validation_status"></span><span class="sub" data-slot="test_result" data-blank></span><span class="sub mono" data-slot="evidence_ref" data-blank></span></td>
|
||||
<td data-slot="issue_risk" data-blank></td>
|
||||
<td><span class="st vs" data-class-of="validation_status"></span></td>
|
||||
<td data-slot="next_validation_action" data-blank></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tbody class="hist" data-rows="validation.history">
|
||||
<tr>
|
||||
<td class="mono" data-slot="validation_id"></td>
|
||||
<td class="mono" data-slot="request_id" data-blank></td>
|
||||
<td class="mono" data-slot="validation_internal_pn"></td>
|
||||
<td><span class="enumtxt vt" data-class-of="validation_type"></span></td>
|
||||
<td data-slot="test_condition" data-blank></td>
|
||||
<td><span class="st vs" data-class-of="validation_status"></span><span class="sub" data-slot="test_result" data-blank></span><span class="sub mono" data-slot="evidence_ref" data-blank></span></td>
|
||||
<td data-slot="issue_risk" data-blank></td>
|
||||
<td><span class="st vs" data-class-of="validation_status"></span></td>
|
||||
<td data-slot="next_validation_action" data-blank></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@@ -500,15 +425,13 @@ export const LEDGER_BOARD = `<!doctype html>
|
||||
<h2>次要台账(只读引用,不进主看板)</h2>
|
||||
</div>
|
||||
<div class="minor">
|
||||
<div class="m"><b><span class="lid">P-09</span>客户技术与机会档案</b>提供 BOM 位与客户技术栈背景;缺口由执行工单补齐。</div>
|
||||
<div class="m"><b><span class="lid">EXT-02</span>外部来源清单</b>登记本次评估用到的可信外部来源(原厂官网 datasheet 等)。</div>
|
||||
<div class="m"><b><span class="lid">GOV</span>评估规则库</b>四态判定口径;本次锁定版本 <span class="mono" data-slot="${D}.verdict.rule_version"></span>,随结论一并落账。</div>
|
||||
<div class="m"><b><span class="lid">GOV</span>评估规则库</b>四态判定与推荐等级口径;本次锁定版本 <span class="mono" data-slot="substitution.relation.rule_version"></span>,随结论一并落账。</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer>
|
||||
<span>SS02 · ACT-WORK-05 差异评估 · 关键台账数据视图</span>
|
||||
<span style="font-family:var(--mono)">数据来源:正式台账(parts / demand / substitution / validation / sub_eval)· 实例 <span data-slot="case:instanceNo"></span> · 案号 <span data-slot="case:ref"></span></span>
|
||||
<span style="font-family:var(--mono)">数据来源:正式台账(parts / substitution / validation / sub_eval)· 实例 <span data-slot="case:instanceNo"></span> · 案号 <span data-slot="case:ref"></span></span>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
* 的 step④),够不够齐、该不该出现由样式表判(§5「模版不许算」)。
|
||||
*
|
||||
* `difference-review`(件② 差异评估结论审核)已由 Task 8 重做并交付(见文件尾「局面:差异评估
|
||||
* 结论审核」一节);`landing-confirm`(件③ 落账确认)仍待 Task 9 重做(同名新建)。
|
||||
* 结论审核」一节);`landing-confirm`(件③ 落账确认)已由 Task 9 重做并交付(见文件尾
|
||||
* 「局面:落账确认」一节)—— 三张件此刻齐了。
|
||||
*
|
||||
* 版面语言仍是「搬,不要照着做」(《HTML报告生成规范》§7):`P08_CSS`(逐字节抽自
|
||||
* `docs/SS02-ACT-WORK-05-html/ACT-WORK-05-数据工单-01-芯片主数据创建.html`,
|
||||
@@ -25,7 +26,7 @@
|
||||
* `data-class-of` 的 `v-*` 别名):目标件是写死数据的静态 demo,没有「N 行草稿」
|
||||
* 「编辑态与归档态二选一」这些平台概念。
|
||||
*/
|
||||
import { P08_CSS, ACC1_CSS } from './target-style.ts';
|
||||
import { P08_CSS, ACC1_CSS, ACC2_CSS } from './target-style.ts';
|
||||
import { D } from '../constants.ts';
|
||||
|
||||
/* ====================================================================================
|
||||
@@ -647,3 +648,148 @@ export const DIFFERENCE_REVIEW = doc({
|
||||
CLOSING_SUMMARY +
|
||||
flow('<b>审批:</b>本工单只承载内容;逐条核对无误后,请在对话区的【验收卡】中确认通过。通过后进入落账放行(T_release),签字后正式落账并发口。'),
|
||||
});
|
||||
|
||||
/* ==================== 局面:落账确认(landing-confirm,T_release 的终局验收工单) ==================== */
|
||||
|
||||
/*
|
||||
* **全只读,答「这一签下去发生什么」(spec §6.3)**:进哪几张表各几行(摆人读名)· 结论卡
|
||||
* (等级 + 一句话)· 四态分布并把硬约束不符的逐条点名 · 待验项(P-06 的测试条件与后续动作)·
|
||||
* 发哪一口。这不是签字前要核的判据表(那张表已经在 S3 核过一遍;T_release 自己的
|
||||
* `acceptanceChecklist` 由验收卡渲染,不在这份 HTML 里重复一遍)—— 这里摆的是**事实**:
|
||||
* 签下去会落地成什么样子,签字的人拿它核对「摆出来的这些是不是要落的」。
|
||||
*
|
||||
* 主题色沿用 `ACC2_CSS`(目标件「验收工单-02」抽出来的样式表,已改成验收绿 --ledger:#0aa294,
|
||||
* 见 target-style.ts 头注)——但 `ACC2_CSS` 只有基座壳与 `.st`/`.risk` 两族徽标,**没有**
|
||||
* `.rec`(推荐等级)那族大徽章的基座形状与 `.tbl-wrap` 的横滑修正,这份文件独立声明
|
||||
* `BIND_LANDING`(与 `BIND_ACC1_EDIT`/`BIND_ACC1_BADGE`/`BIND_ACC1_LAYOUT` 互不共享 ——
|
||||
* 两份 HTML 各有各的 `<style>`,不存在跨文档级联)。
|
||||
*/
|
||||
const BIND_LANDING = `
|
||||
/* 表宽超出要能横着滑(陷阱表规矩)—— ACC2_CSS 的 .tbl-wrap 写的是 overflow:hidden */
|
||||
.tbl-wrap { overflow-x: auto; overflow-y: hidden; }
|
||||
/* 结论卡:推荐等级大徽章 + 一句话摘要 */
|
||||
.verdict-card{display:flex;align-items:center;gap:14px;flex-wrap:wrap;margin:0 0 18px;padding:14px 16px;border:1px solid var(--ledger-line);border-radius:12px;background:var(--ledger-soft)}
|
||||
.verdict-sum{flex:1 1 260px;min-width:0;font-size:13px;color:var(--ink-2);line-height:1.6;overflow-wrap:anywhere}
|
||||
/* 推荐等级徽标 —— ACC2_CSS 没有 .rec 基座形状(那是 ACC1_CSS 才有的),这里补齐,与差异评估结论审核件同一套值域 */
|
||||
.rec{display:inline-block;font-size:11px;font-weight:800;padding:2px 12px;border-radius:999px;border:1px solid transparent;white-space:nowrap}
|
||||
${badgeCss('.rec', [
|
||||
['recommended', '推荐', OK],
|
||||
['conditional', '有条件推荐', AMBER],
|
||||
['not_recommended', '不推荐', DANGER],
|
||||
])}
|
||||
.rec.rec-lg{font-size:15px;padding:6px 20px;letter-spacing:.02em}
|
||||
/* 约束类型徽标(hard/soft)—— 与 input-supplement/difference-review 同一套颜色语义,独立声明(不跨文档共享) */
|
||||
.ct{display:inline-block;font-size:11px;font-weight:700;padding:1px 8px;border-radius:999px;border:1px solid transparent;white-space:nowrap}
|
||||
${badgeCss('.ct', [
|
||||
['hard', '硬约束', DANGER],
|
||||
['soft', '软约束', MUTED],
|
||||
])}
|
||||
/* 四态计数 —— 签字页只摆数,不摆宽度分布条 */
|
||||
.four{display:flex;flex-wrap:wrap;gap:16px;margin:0 0 18px}
|
||||
.four-item{font-size:12.5px;color:var(--ink-3);display:inline-flex;align-items:center;gap:5px}
|
||||
.four-item b{font-weight:800;color:var(--ink);font-size:13.5px;font-family:var(--mono)}
|
||||
.four-item.m b{color:var(--ok)}
|
||||
.four-item.x b{color:var(--danger)}
|
||||
.four-item.u b{color:#8f6a12}
|
||||
.four-item.c b{color:var(--brand-deep)}
|
||||
/* 硬约束不符逐条点名 —— 整表渲出来,CSS 只留 judgement_class = hard_mismatch 的那几行(判断留在样式表,模版不判) */
|
||||
.hardbox{margin:0 0 18px}
|
||||
.hardbox-empty{display:none;margin:0;padding:10px 14px;border-radius:9px;background:var(--ok-soft);border:1px solid #bfe6b4;color:var(--ok);font-size:12.5px}
|
||||
.hardbox:not(:has(tr.v-${vtok('hard_mismatch')})) .hardbox-empty{display:block}
|
||||
.hardbox:not(:has(tr.v-${vtok('hard_mismatch')})) .tbl-wrap{display:none}
|
||||
.hardbox table tbody tr:not(.v-${vtok('hard_mismatch')}){display:none}
|
||||
/* 待验项 —— kv 行,与差异评估结论审核件「收口结论」同一套版式,独立声明 */
|
||||
.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)}
|
||||
`;
|
||||
|
||||
/**
|
||||
* 落账去向 —— 摆「进哪几张表各几行」,人读名 + 基座读数(spec §6.3 第一件事)。
|
||||
* 三行是**固定的**(必交付物 `landing`/`difference-items` 承载的正是这三张表,见 manifest.ts
|
||||
* `contract.output.requiredDeliverables`),不是 `data-rows` 驱动的动态表 —— 行数本身才是
|
||||
* 要摆的数据,行的「有没有」不需要模版去猜。
|
||||
*/
|
||||
const LANDING_TABLE = `<div class="tbl-wrap"><table>
|
||||
<thead><tr><th style="width:260px" data-h="落账表">落账表</th><th data-h="行数">行数</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td class="cust">替代关系主记录(P-11)</td><td class="mono"><span data-slot="substitution_relation_rows"></span> 行</td></tr>
|
||||
<tr><td class="cust">差异明细(P-11 子表)</td><td class="mono"><span data-slot="substitution_difference_item_rows"></span> 行</td></tr>
|
||||
<tr><td class="cust">验证记录(P-06)</td><td class="mono"><span data-slot="validation_record_rows"></span> 行</td></tr>
|
||||
</tbody>
|
||||
</table></div>`;
|
||||
|
||||
/** 结论卡 —— 推荐等级大徽章 + 一句话摘要(`sub_eval.case.summary`,T_release 自己那笔投影拼的整句)。 */
|
||||
const VERDICT_CARD = `<div class="verdict-card">
|
||||
<span class="rec rec-lg" data-class-of="recommendation_level"></span>
|
||||
<span class="verdict-sum" data-slot="summary" data-blank></span>
|
||||
</div>`;
|
||||
|
||||
/** 四态计数 —— 与差异评估结论审核件同一批基座读数,这里不画宽度条,只摆数。 */
|
||||
const FOUR_STATE = `<div class="four">
|
||||
<span class="four-item m">MATCH · <b data-slot="${DIST_PREFIX}match"></b></span>
|
||||
<span class="four-item x">MISMATCH · <b data-slot="${DIST_PREFIX}mismatch"></b></span>
|
||||
<span class="four-item u">UNKNOWN · <b data-slot="${DIST_PREFIX}unknown"></b></span>
|
||||
<span class="four-item c">CONDITIONAL · <b data-slot="${DIST_PREFIX}conditional"></b></span>
|
||||
</div>`;
|
||||
|
||||
/**
|
||||
* 硬约束不符逐条点名 —— **签字的人最该看见的就是它**。整表渲出来(`mine:substitution.difference_item`),
|
||||
* 行上挂 `data-class-of="judgement_class"`,CSS 只留 `judgement_class = hard_mismatch` 的那几行
|
||||
* (见 `BIND_LANDING` 里 `.hardbox table tbody tr:not(.v-${vtok('hard_mismatch')})`)——
|
||||
* **`vtok('hard_mismatch')` 不是 `hard_mismatch` 本身**:`classToken` 只留 `[a-z0-9-]`、
|
||||
* 吃掉下划线,选择器一律从值算出来,不手写(本包已在 2026-08-27 栽过一次同款事故)。
|
||||
* 一条都没有时摆一句正面的话(`.hardbox-empty`),不是留一张空表让人猜「是没有还是没算」。
|
||||
*/
|
||||
const HARD_MISMATCH_TABLE = `<div class="hardbox">
|
||||
<p class="hardbox-empty">没有硬约束不符项。</p>
|
||||
<div class="tbl-wrap"><table>
|
||||
<thead><tr><th data-h="参数项">参数项</th><th data-h="约束">约束</th><th data-h="原PN值">原 PN 值</th><th data-h="候选PN值">候选 PN 值</th><th data-h="判断依据">判断依据</th><th data-h="影响说明">影响说明</th></tr></thead>
|
||||
<tbody data-rows="mine:substitution.difference_item">
|
||||
<tr data-class-of="judgement_class">
|
||||
<td class="cust" data-slot="parameter_name"></td>
|
||||
<td><span class="ct" data-class-of="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="evidence_note" data-blank></td>
|
||||
<td data-slot="impact_statement" data-blank></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></div>
|
||||
</div>`;
|
||||
|
||||
/** 待验项 —— P-06 的测试条件与后续动作(一单固定一条,直接 kv 行摆,不必 data-rows)。 */
|
||||
const VALIDATION_BLOCK = `<div class="kv-box">
|
||||
<div class="kv"><i>测试条件</i><span data-slot="test_condition" data-blank></span></div>
|
||||
<div class="kv"><i>后续动作</i><span data-slot="next_validation_action" data-blank></span></div>
|
||||
</div>`;
|
||||
|
||||
export const LANDING_CONFIRM = doc({
|
||||
css: ACC2_CSS,
|
||||
alias: BIND_LANDING,
|
||||
badge: '验收',
|
||||
tag: '验收工单',
|
||||
kicker: 'SS02 · ACT-WORK-05 差异评估 · 验收工单 2/2',
|
||||
title: '评审放行与落账确认',
|
||||
step: '步骤 4/4 · 提交 ACT-GATE-03',
|
||||
footTag: '工单类型:验收',
|
||||
body:
|
||||
zone('这一签下去发生什么', '全只读 —— 签之前只核对,要改回上一步的验收工单重做', ZIC_TASK) +
|
||||
note([
|
||||
'<span class="need">这一步做什么</span>:核对下面即将落账的内容,确认无误后在对话区的【验收卡】里签字放行 —— 签字后正式落账,不能撤回。',
|
||||
'<span class="done">系统已完成</span>:推荐等级 / 差异摘要 / 风险按规则从下面的差异明细算出,不是这一步现拟 —— 签字确认的是「摆出来的这些是不是要落的」,不是重新判断。',
|
||||
'<span class="need">不写客户批准</span>:客户批准状态由独立审批流维护,本活动只答技术可替代性,不产生那一列。',
|
||||
]) +
|
||||
zone('落账去向', '进哪几张表、各几行 —— 表由必交付物声明承载,行数即将落定', ZIC_TABLE) +
|
||||
LANDING_TABLE +
|
||||
zone('结论', '推荐等级 + 一句话摘要', ZIC_TASK) +
|
||||
VERDICT_CARD +
|
||||
zone('四态分布', '逐条差异明细的结论分布;硬约束不符的逐条点名 —— 签字前最该看的就是它', ZIC_TABLE) +
|
||||
FOUR_STATE +
|
||||
HARD_MISMATCH_TABLE +
|
||||
zone('待验项', 'P-06 的测试条件与后续动作 —— 有 UNKNOWN / CONDITIONAL 才有内容,全推荐则写「本轮无待验项」', ZIC_TASK) +
|
||||
VALIDATION_BLOCK +
|
||||
flow('<b>签字与发射:</b>本工单只承载内容;确认请在对话区的【验收卡】中签字放行。签字后即落账,发射 <b>assessment-released</b>(评估结论已落账)—— 载荷:评估案号 / 替代关系ID / 原内部料号 / 候选内部料号 / 推荐等级 / MATCH·MISMATCH·UNKNOWN·CONDITIONAL 条数 / 关联验证ID。'),
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user