From 4bd1a045114aa228b78f2fcd333c5687c81d9d6b Mon Sep 17 00:00:00 2001 From: xcs Date: Sat, 29 Aug 2026 20:53:23 +0800 Subject: [PATCH] =?UTF-8?q?feat(w05):=20=E4=BB=B6=E2=91=A2=20=E8=90=BD?= =?UTF-8?q?=E8=B4=A6=E7=A1=AE=E8=AE=A4=E4=B8=8E=E7=9C=8B=E6=9D=BF=E9=87=8D?= =?UTF-8?q?=E7=BB=91=20=E2=80=94=E2=80=94=20=E7=AD=BE=E4=B9=8B=E5=89=8D?= =?UTF-8?q?=E5=8F=AA=E6=A0=B8=E5=AF=B9,=E7=A1=AC=E7=BA=A6=E6=9D=9F?= =?UTF-8?q?=E4=B8=8D=E7=AC=A6=E9=80=90=E6=9D=A1=E7=82=B9=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task 9: 新增 landing-confirm(T_release 的终局验收工单,全只读,答「这一 签下去发生什么」——落账去向/结论卡/四态分布/硬约束逐条点名/待验项/发口), 三张件此刻齐了;activity-ledger 看板的 data 声明与 HTML 一并重绑到新九 张表(P-01/P-10 两域随重写撤下),解封 3 条等待三张件齐的 skip。 Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01LKMZDwMbyKzjw6Hembwvet --- .../__tests__/activity.test.ts | 146 +++++++-- .../src/case-model.ts | 4 + .../src/manifest.ts | 13 +- .../src/views/ledger-board.ts | 285 +++++++----------- .../src/views/report.ts | 150 ++++++++- 5 files changed, 379 insertions(+), 219 deletions(-) diff --git a/activities/part-substitution-assessment/__tests__/activity.test.ts b/activities/part-substitution-assessment/__tests__/activity.test.ts index 2402e2c..f55816b 100644 --- a/activities/part-substitution-assessment/__tests__/activity.test.ts +++ b/activities/part-substitution-assessment/__tests__/activity.test.ts @@ -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('
')).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(' { + 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(''); + expect(html).toContain(``); expect(html).toContain('
'); expect(html).toContain(''); 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 ['内部料号', '替代关系 ID', '参数项', '关联料号', '验证 ID', '标准化参数集']) 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 ['内部料号', '替代关系 ID', '参数项', '验证 ID', '标准化参数集', '参数名']) 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(''); 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); + } }); }); diff --git a/activities/part-substitution-assessment/src/case-model.ts b/activities/part-substitution-assessment/src/case-model.ts index d8e2d1d..a89b6cb 100644 --- a/activities/part-substitution-assessment/src/case-model.ts +++ b/activities/part-substitution-assessment/src/case-model.ts @@ -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: [ '推荐等级与四态分布对得上:有硬约束不符的没给「推荐」', diff --git a/activities/part-substitution-assessment/src/manifest.ts b/activities/part-substitution-assessment/src/manifest.ts index d8f67a0..98ac155 100644 --- a/activities/part-substitution-assessment/src/manifest.ts +++ b/activities/part-substitution-assessment/src/manifest.ts @@ -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 只出场一次、答一份结构化判断,没有可供归纳的多轮轨迹) */ diff --git a/activities/part-substitution-assessment/src/views/ledger-board.ts b/activities/part-substitution-assessment/src/views/ledger-board.ts index ff52b46..91a9101 100644 --- a/activities/part-substitution-assessment/src/views/ledger-board.ts +++ b/activities/part-substitution-assessment/src/views/ledger-board.ts @@ -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`,不是整表;`.<列>` 是那一集合首行的标量,`_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- 决定;没投出 class 的格子摆「—」,客户批准那格摆「未提交」 */ +/* 徽标:值域各归各族(同一个词在不同列意思不同),文案与颜色由 data-class-of 投出的 v- 决定; + 没投出 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 = `
SS02 需求分析与方案匹配 · 活动台账视图

ACT-WORK-05关键台账数据

-

视角:本活动最近一次已放行实例 ( 开案 · 放行 · 负责人 )的落账快照 · 案号 · 关联需求 (客户 )· 评估基准 ()→ 候选 · 规则版本

-

评估结论:

+

视角:本活动最近一次已放行实例 ( 开案 · 放行 · 负责人 )的落账快照 · 案号 · 评估基准 → 候选 · 芯片类型 · 规则版本

+

评估结论:

正式台账直读 —— 放行落地后的事实,按案号圈出这一单的行 同料号的历史验证记录(别单 / 线下留下的,作本次评估的证据引用) @@ -319,64 +282,57 @@ export const LEDGER_BOARD = `
P-08 芯片主数据核心输入 · 评估原材料,查无即硬阻塞
+
字段字典 类型与核心参数比对基准 · 按芯片类型定义要比的字段与硬软约束
P-11 替代批准关系库核心产出 · 结论与明细的落账地
-
P-10 原厂技术资料库证据链 · 每项结论的版本化出处
P-06 样品验证记录闭环去向 · UNKNOWN 的实测收口
-
P-01 客户需求主台账上下文 · 需求源头与回写对象
- -
-
-

P-01客户需求主台账

- 上下文 · R+W - 启动时新建需求;结束时回写风险 / 验证要求 / 输出链接 / 下一步 / 当前阶段 - 正式表 · 条 -
-
-
需求编号
-
客户
-
需求版本
-
需求状态
-
需求描述
-
应用场景
-
BOM 位
-
原内部料号
-
候选内部料号
-
风险等级(回写)
-
验证要求(回写)
-
当前阶段
-
标准输出链接
-
下一步动作
-
-
-

P-08芯片主数据台账

核心输入 · R(查无 → 数据工单创建) 原 PN 与候选 PN 的物料基准 + 标准化参数集(子表 P-08 参数),逐项比对的原材料 - 正式表 · 条(本活动相关) + 正式表 · 条(本次评估相关)
- ${th('内部料号', '品牌', '规格描述', '封装', '生命周期', 'Datasheet 版本', '标准化参数集', '适配场景')} + ${th('内部料号', '品牌', '规格描述', '生命周期', 'Datasheet 版本', '标准化参数集')} - + - -
-

本轮放弃的候选(未建档、未评估):

+
+ + +
+
+

字段字典芯片类型与核心参数

+ 比对基准 · R + 两颗料共同归属的芯片类型,及该类型定义的核心参数字段(名字 / 说明 / 硬软约束 / 单位) + 类型 · · 字段 条 +
+
+ + ${th('参数名', '参数说明', '约束', '参考单位')} + + + + + + + + +
+
@@ -384,71 +340,44 @@ export const LEDGER_BOARD = `

P-11替代选型与批准关系库 · 替代关系主记录

核心产出 · R+W - 每个候选一条关系记录;客户批准状态为只读边界,本活动不写 + 原 PN → 候选 PN 一条关系记录;推荐等级 / 风险 / 摘要由规则算出,客户批准状态为只读边界,本活动不写 正式表 · 条
- ${th('替代关系 ID', '原 → 候选', '替代类型', '推荐等级', '分析状态', '风险', '差异摘要', '验证要求 / 回链', '规则版本', '客户批准(只读)')} + ${th('替代关系 ID', '原 → 候选', '推荐等级', '分析状态', '风险', '差异摘要 / 理由', '验证要求 / 回链', '规则版本')} - -
→
-

P-11差异明细子表(由双方 P-08 标准化参数集逐项比对得出;MATCH 项淡显)

+

P-11差异明细子表(按字段字典逐项比对得出;MATCH 项淡显)

条 · MATCH · MISMATCH · UNKNOWN · CONDITIONAL
- ${th('所属关系', '参数项', '原值 → 候选值', '约束', '结论', '风险', '证据引用', '影响说明')} + ${th('参数项', '约束', '原值 → 候选值', '单位', '结论', '风险', '判断依据', '影响说明')} - - + + - - - - -
→ →
-
- - - -
-
-

P-10原厂技术资料库

- 证据链 · R(查无 → 数据工单创建) - 每项结论的 datasheet 出处,版本回链 - 正式表 · 条(本活动相关料号) -
-
- - ${th('关联料号', '品牌', '资料类型', '资料文件', '版本', '状态')} - - - - - - - - + +
·
@@ -460,33 +389,29 @@ export const LEDGER_BOARD = `

P-06样品交付与芯片验证记录台账

闭环去向 · R + 条件写(不可创建,只能实测产生) - UNKNOWN / CONDITIONAL 的收口处;验证完成后回链 P-11 + UNKNOWN / CONDITIONAL 的收口处;一单固定一条 本单挂的 · 条 · 同料号历史 · 条
- ${th('验证 ID', '关联需求', '验证料号', '验证类型', '测试条件', '结果 / 状态', '问题与风险', '后续动作')} + ${th('验证 ID', '验证料号', '验证类型', '测试条件', '结果 / 状态', '后续动作')} - - - + - - - + @@ -500,15 +425,13 @@ export const LEDGER_BOARD = `

次要台账(只读引用,不进主看板)

-
P-09客户技术与机会档案提供 BOM 位与客户技术栈背景;缺口由执行工单补齐。
-
EXT-02外部来源清单登记本次评估用到的可信外部来源(原厂官网 datasheet 等)。
-
GOV评估规则库四态判定口径;本次锁定版本 ,随结论一并落账。
+
GOV评估规则库四态判定与推荐等级口径;本次锁定版本 ,随结论一并落账。
SS02 · ACT-WORK-05 差异评估 · 关键台账数据视图 - 数据来源:正式台账(parts / demand / substitution / validation / sub_eval)· 实例 · 案号 + 数据来源:正式台账(parts / substitution / validation / sub_eval)· 实例 · 案号
diff --git a/activities/part-substitution-assessment/src/views/report.ts b/activities/part-substitution-assessment/src/views/report.ts index 9e6999d..3d14c99 100644 --- a/activities/part-substitution-assessment/src/views/report.ts +++ b/activities/part-substitution-assessment/src/views/report.ts @@ -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('审批:本工单只承载内容;逐条核对无误后,请在对话区的【验收卡】中确认通过。通过后进入落账放行(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 各有各的 `