This repository has been archived on 2026-09-13. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
BPOS-TMP-REPO/activities/part-substitution-assessment/src/views/report.ts
T
xcsandClaude Fable 5 51c87af583 数据工单有了自己的面孔;件上四处样式对齐;缺库不再问人;5173 反代改回本机
用户在工作台上连报六条(2026-08-27):
- 对话区把数据工单摆成「执行工单」→ 契约 ExecutionWorkOrder.variant:'data'(引擎侧与执行工单无异,
  只换面孔),归一层从卡上带下来,web 新增 DataForm(同一套办法、另一副面孔:色/图标/「数据工单」/「确认写入」),
  办结卡与治理台人类工具目录同步;活动的两张数据工单卡骨架标 variant:"data"。
- 表显示不全不能右滑 → 目标件把 overflow-x:auto 写在 .tbl-wrap,平台包装是 .jc-tbl-wrap,谁都没管到;补一条。
- 表头只留中文 → 三张数据工单表去英文列名与 .thd 小字。
- 编辑态内部料号「只读字 + 输入框」并排 → 目标件 #tbl1 .jc-vcell{display:inline}(id 特异度)盖过
  table.on 的隐藏规则,表 1 每格其实都并排,PN 那格恰好有字;用 id 特异度覆盖回去。
- input 与 select 没对齐 → 徽标从前包 .ro 编辑态留着、压在下拉框头上把那格顶低 13px,改成随只读格一起藏;
  input/select 钉同一高度。
- 第一步「派数据工单还是放弃候选」不该问人 → 决策卡退役(覆盖规格「候选 ≥2 可放弃」那一条,用户定),
  查无记录一律自动派;剧本/说明书/测试/e2e 同步(e2e 新增 expectAsks.max 断言「不该问的没问」)。
顺带:5173 的 /api 反代默认指向一条公网隧道(150.158.83.131:46100 → nps → npc → 本机 :8787),
浏览器每次请求先出公网再绕回来;默认改回本机,要远端的显式给 API_PROXY_TARGET。

静态渲染实证:900px 宽的框里横向能滑 200px;编辑态同一行 3 input + 1 select 全部 32px 同一 y;
只读 PN 格 display:none。活动包 1.4.0;2097 测 / typecheck / lint / depcruise 绿。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FJcX8A6TWp4GRs41TYryEh
2026-08-27 12:36:13 +08:00

670 lines
45 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* ACT-WORK-05 差异评估的 HTML 报告模版 —— **活动自己持有的资产**,随包版本冻结。
*
* 五个局面各一张,版面语言**逐块搬自** `docs/SS02-ACT-WORK-05-html/` 的四份目标件
* (《HTML报告生成规范》§7:有目标件时「搬」,不要「照着做」——样式表整段搬,标记逐块搬,
* 只把写死的数据换成绑定):
* · `p08-master-create` —— S0d 摆,数据工单(P-08 芯片主数据),搬自「数据工单-01」
* (2026-08-27:补齐目标件里原本就有、之前漏搬的【创建什么 · 表 2】标准化参数子表 `parts.parameter`
* —— 用户核对实跑页面后指出「页面结构必须与目标件一致」,目标件本就是两张表);
* · `p10-document-create` —— S0d 摆,数据工单(P-10 原厂技术资料),**没有自己的目标件**
* (规格里数据工单是「一个统一模板按目标台账实例化」),复用「数据工单-01」的样式表与版面骨架;
* · `eval-input-list` —— S0/S1 摆,评估输入清单,搬自「执行工单-01」;
* · `difference-review` —— S2/S3/S4 摆,差异评估结论审核,搬自「验收工单-01」;
* · `landing-confirm` —— S5/T_release 摆,评审放行与落账确认,搬自「验收工单-02」。
*
* 目标件的样式表逐字节存在 `./target-style.ts`(`P08_CSS`/`EXEC_CSS`/`ACC1_CSS`/`ACC2_CSS`,
* 抽取与 diff 验证过程见 task-5-report.md)。**这份文件只做取值绑定,不算不判**;
* `BIND_COMMON`/`BIND_P08`/`BIND_EXEC`/`BIND_ACC1`/`BIND_ACC2` 是平台绑定层必须新增的东西
* (目标件是写死数据的静态demo,没有「N 行草稿」「编辑态与归档态二选一」这些平台概念):
* 缺项红带、编辑闸/增删行按 `html.editable` 收起、序号列换成 CSS 计数器(目标件靠 JS 脚本
* 重排数字,沙箱零脚本改用它)、`data-class-of` 的 `v-*` 别名(枚举列不许摆 ASCII 原值 ——
* 有色徽标的地方原样复制目标件自己那几条颜色声明当 `v-` 版,目标件本来是纯文字的地方
* 就只补 `::after` 文案、不额外配色)。
*/
import { P08_CSS, EXEC_CSS, ACC1_CSS, ACC2_CSS } from './target-style.ts';
import { D } from '../constants.ts';
/* ====================================================================================
* 绑定层公共开关 —— 五张模版共用,与目标件自己的样式表分开存(那份要保持逐字节可比)
* ==================================================================================== */
const BIND_COMMON = `
/* ── 2026-08-27 用户四连指出的件上毛病,病根三处都在「目标件的样式与平台的编辑态没对上」 ── */
/* ① 表宽超出就得能横着滑(E04/I01 08-23 同款):目标件把 overflow-x:auto 写在 .tbl-wrap 上,而平台包装是 .jc-tbl-wrap,谁都没管到 */
.jc-tbl-wrap { overflow-x: auto; overflow-y: hidden; }
/* ② 编辑态只留输入格:目标件 #tbl1 .jc-vcell{display:inline}(id 特异度)盖过了 table.on td>.jc-vcell{display:none},
于是表 1 每格都是「只读字 + 输入框」并排 —— 内部料号那格恰好有字,人看见的就是它 */
#tbl1.on td > .jc-vcell:not(.ro) { display: none; }
/* ③ 一行里的 input 与 select 同高同线:select 天生比 input 矮 4px,编辑态里一排格子高低不齐 */
input.jc-cell, select.jc-cell { height: 32px; box-sizing: border-box; padding-top: 0; padding-bottom: 0; vertical-align: middle; }
/* 只在「待处理」这一态露面;归档 / 验收只读态即便 HTML 里还带着 data-edit 也不摆闸和加行钮
(目标件是静态 demo,不区分这两态;html.editable 是平台在 iframe 根节点上真开的关) */
html:not(.editable) .jc-editgate, html:not(.editable) .jc-addrow { display: none !important; }
/* 「加一行」钮跟着紧邻的表进不进编辑态现身(目标件靠 JS 脚本的 classList.toggle('show',on),
沙箱零脚本,改用 :has() 认「紧挨着的表是不是 .on」) */
.jc-tbl-wrap:has(table.on) + .jc-addrow { display: flex; align-items: center; gap: 8px; }
/* 序号列交给 CSS 计数器 —— 目标件的 JS 脚本在增删行后重写 .jc-rn-num / .num 的文本,
沙箱零脚本,新增的行 / 删掉的行让计数器自己算对,不必比对哪一行手改过数字。
两种列名都要接(.rn 用于 P08/P10/执行工单 —— 目标件里那三份自己就用它;
.num 用于两份验收工单 —— 目标件里那两份自己就用它,静态数字,这里换成动态计数)。 */
.tbl-wrap table { counter-reset: rn; }
.tbl-wrap table td.rn { counter-increment: rn; }
.tbl-wrap table td.rn .jc-rn-num::before { content: counter(rn); }
.tbl-wrap table td.num { counter-increment: rn; }
.tbl-wrap table td.num::before { content: counter(rn); }
/* 缺项红带 —— 目标件没有这个概念(它是静态 demo,不会「缺东西」);
这是本仓的必填提示机制,与提交闸同源,配色用目标件自己 :root 里那两个 --danger 变量
(四份目标件的 :root 对这两个变量给的是同一组值,借用不算改目标件的数值)。 */
.jc-gapbar { display: none; }
html.editable .jc-gapbar {
display: flex; align-items: flex-start; gap: 8px; margin: 0 0 10px; padding: 9px 12px;
border-radius: 9px; background: #fff5f5; border: 1px solid #f3b9b5; color: var(--danger); font-size: 12px; line-height: 1.65;
}
.jc-gapbar b { font-weight: 800; }
.jc-gapbar span { color: #9a3b36; }
html.editable .jc-gapbar.v-0 { display: none; }
`;
/*
* ==================== 徽标别名的生成器 ====================
*
* **2026-08-27 实测事故**:手写的 `.jc-tag.v-pin_to_pin::after{…}` 永远匹配不上,件上显示「待定」,
* 而台账里 `substitution_type` 明明是 `pin_to_pin`。病根是平台有两套互相打架的消毒规则:
* `data-class-of` 投影出的 class 走 `view-render.ts` 的 `classToken`(只留 `[a-z0-9-]`,
* **吃掉下划线**,`pin_to_pin` → `v-pintopin`,封顶 24 字);基座读数名走 `engines.ts` 的
* `slug`(只留 `[a-z0-9_]`,吃掉连字符)。两套规则不一样,tally 值一旦带下划线,手写的
* `.v-xxx` 选择器就必然是错的。**判据那一侧(读数名)一个字都不碰**——那已经审查通过、
* 与 `slug` 一致;这里改的只是展示层:选择器一律用 `vtok()` 从 tally 值**算**出来,不再手写。
*/
/** 必须与 `classToken` 一字不差:小写、只留 `[a-z0-9-]`、封顶 24 字。 */
const vtok = (v: string): string => v.toLowerCase().replace(/[^a-z0-9-]/g, '').slice(0, 24);
/** 一族徽标的 CSS:选择器与文案从 `[值, 人读名, 可选颜色声明]` 表算出来,值与文案成对写在一处 */
type BadgeSpec = readonly [value: string, label: string, color?: string];
const badgeCss = (selector: string, specs: readonly BadgeSpec[]): string =>
specs
.map(([v, label, color]) => {
const cls = `${selector}.v-${vtok(v)}`;
return color === undefined ? `${cls}::after { content: "${label}"; }` : `${cls}::after { content: "${label}"; }\n${cls} { ${color} }`;
})
.join('\n');
const OK = 'color: var(--ok); background: var(--ok-soft); border-color: #c9ecc2;';
const DANGER = 'color: var(--danger); background: var(--danger-soft); border-color: #f3b9b5;';
const AMBER = 'color: #8f6a12; background: #fdf3d7; border-color: #ecd9a0;';
const MUTED = 'color: var(--ink-3); background: #eef1f6; border-color: var(--line);';
/* ==================== 数据工单(P08/P10 共用):徽标别名 ==================== */
const BIND_P08 = `
/* 生命周期 / 资料类型 / 资料状态 三个枚举列共用同一个徽标类 —— 取值域互不重叠(active/nrnd/eol/
discontinued/risk 与 datasheet/app_note/… 与 valid/expired/pending/void 三组没有一个词撞车),
同一页内不必再分家。配色借的是本设计语言在别的目标件里已经出现过的那几个色(ok/danger/琥珀),
不是新配的颜色。 */
.stx { display: inline-block; font-size: 11px; font-weight: 700; padding: 1px 8px; border-radius: 999px; border: 1px solid transparent; white-space: nowrap; }
${badgeCss('.stx', [
['active', 'Active', OK],
['nrnd', 'NRND', AMBER],
['eol', 'EOL', DANGER],
['discontinued', '停产', MUTED],
['risk', '风险', DANGER],
['datasheet', 'Datasheet', 'color: var(--ink-2); background: var(--soft); border-color: var(--line);'],
['app_note', '应用笔记', 'color: var(--ink-2); background: var(--soft); border-color: var(--line);'],
['reference_design', '参考设计', 'color: var(--ink-2); background: var(--soft); border-color: var(--line);'],
['white_paper', '白皮书', 'color: var(--ink-2); background: var(--soft); border-color: var(--line);'],
['sample_doc', '样片资料', 'color: var(--ink-2); background: var(--soft); border-color: var(--line);'],
['commitment_letter', '承诺函', 'color: var(--ink-2); background: var(--soft); border-color: var(--line);'],
['other', '其他', 'color: var(--ink-2); background: var(--soft); border-color: var(--line);'],
['valid', '有效', OK],
['expired', '过期', DANGER],
['pending', '待核实', AMBER],
['void', '作废', MUTED],
])}
/*
* 表 2(标准化参数集)的约束类型(硬/软)—— 目标件里这一格是字面类名 .ct.hard / .ct.soft
* (P08_CSS 已带这两条颜色声明,.ct 基座形状也在);平台的 data-class-of 走的是
* v-<token> 别名机制,不是字面枚举值,这里用 badgeCss 生成 .ct.v-hard / .ct.v-soft,
* 颜色原样照抄目标件那两条声明的数值(DANGER/MUTED 与 .ct.hard / .ct.soft 同一份值)。
*/
${badgeCss('.ct', [
['hard', '硬约束', DANGER],
['soft', '软约束', MUTED],
])}
`;
/* ==================== 执行工单(评估输入清单):徽标别名 ==================== */
const BIND_EXEC = `
/* 存在性核对的两列(角色 / 在库状态)与评估输入清单的状态列共用目标件自己的 .st 徽标基座 ——
取值域互不重叠(found/absent/created/abandoned 与 gap/default/ok 没有一个词撞车)。
四档配色**原样照抄目标件自己的 .st.bound / .st.ok / .st.miss / .st.def 那四条声明**,只换成 v- 版。 */
${badgeCss('.st', [
['found', '在库', OK],
['absent', '不在库', 'color: var(--human); background: var(--human-soft); border-color: var(--human-line);'],
['created', '本单新建', 'color: var(--brand-deep); background: var(--brand-wash); border-color: var(--brand-soft);'],
['abandoned', '已放弃', MUTED],
['gap', '待补*', 'color: var(--human); background: var(--human-soft); border-color: var(--human-line);'],
['default', '默认·可改', 'color: var(--brand-deep); background: var(--brand-wash); border-color: var(--brand-soft);'],
['ok', '齐备', OK],
])}
/* 角色(原 PN / 候选 PN)是分类标签不是状态,目标件里这类描述文字从不配色,这里只补 ::after 文案 */
${badgeCss('.rl', [
['original', '原内部料号'],
['candidate', '候选内部料号'],
])}
/*
* **补充内容按行投影必填**(2026-08-27 实测:11 行全摆红「必填」胶囊,而闸只认 3 行)——
* \`sub_eval.input_gap.supplement\` 的必填是 \`requiredWhen:{status:'gap'}\`,按行不按列;
* 静态 \`class="req"\` 会把每一行都标必填。改成 \`<td data-class-of="status">\` 按本行的
* status 值投影,只在 v-gap 那一档出红胶囊与行首红条,default / ok 两档不出。
*/
td.sup.v-gap > .jc-vcell:empty::after {
content: "必填"; display: inline-flex; align-items: center; font-style: normal; font-size: 10px; font-weight: 700;
line-height: 1; padding: 3px 7px; border-radius: 5px; border: 1px dashed #f3b9b5; color: var(--danger); background: var(--danger-soft);
}
tbody tr:has(td.sup.v-gap > .jc-vcell:empty) td { background: #fffbfb; }
tbody tr:has(td.sup.v-gap > .jc-vcell:empty) td.rn { color: var(--danger); font-weight: 800; }
`;
/* ==================== 验收工单 01(差异评估结论审核):徽标别名 ==================== */
const BIND_ACC1 = `
/* 差异四态与推荐等级**都**落在这一屏(本活动数据面的既有约定 —— 各候选推荐等级摘要与
逐项差异明细同屏摆),两者取值域都含 "conditional",光认 .st 分不清是哪一列,
加 .dst / .rec 两个字段级修饰类各自配色(**原样照抄目标件 .st.ok/.miss/.unknown/.cond
四条声明**,只是同一份颜色现在要接两条不同的人读文案)。 */
${badgeCss('.st.dst', [
['match', 'MATCH', OK],
['mismatch', 'MISMATCH', DANGER],
['unknown', 'UNKNOWN', AMBER],
['conditional', 'CONDITIONAL', 'color: var(--ledger); background: var(--ledger-soft); border-color: var(--ledger-line);'],
])}
${badgeCss('.st.rec', [
['recommended', '推荐', OK],
['conditional', '条件推荐', 'color: var(--ledger); background: var(--ledger-soft); border-color: var(--ledger-line);'],
['alternate', '备选', AMBER],
['not_recommended', '不推荐', DANGER],
])}
/*
* 风险等级(原样照抄目标件 .risk.low/.mid/.hi 三条声明)——加 critical 一档:这一屏「各候选
* 推荐等级」摘要读的是 substitution.relation.risk_level(声明了 low/medium/high/critical
* 四档),差异明细本身的 risk_level 只有三档,共用同一族选择器,多出的第四档不会撞车。
*/
${badgeCss('.risk', [
['low', '低', 'color: var(--ok);'],
['medium', '中', 'color: #8f6a12;'],
['high', '高', 'color: var(--danger);'],
['critical', '危急', 'color: var(--danger); font-weight: 900;'],
])}
/*
* 约束类型(硬/软)—— 目标件的差异明细表里这一列是纯文字,没有配色(数据工单-01 的 .ct.hard/
* .ct.soft 才是这两个值真正的徽标声明,只是它长在另一份目标件里)。这里把那两条颜色声明
* 原样搬过来当 v- 版(数值不改,只换了外壳类名,因为这一页的样式表里从未定义过 .ct)。
*/
.con { display: inline-block; font-size: 11px; font-weight: 700; padding: 1px 8px; border-radius: 999px; border: 1px solid transparent; white-space: nowrap; }
${badgeCss('.con', [
['hard', '硬约束', DANGER],
['soft', '软约束', MUTED],
])}
/* 替代类型 —— 目标件里也是纯文字,不配色,只补文案 */
${badgeCss('.enumtxt', [
['pin_to_pin', 'Pin-to-Pin'],
['functional', '功能替代'],
['parametric', '参数替代'],
['other', '其他'],
])}
`;
/* ==================== 验收工单 02(评审放行与落账确认):徽标别名 ==================== */
const BIND_ACC2 = `
/* 这一屏四个枚举列(推荐等级 / 分析状态 / 需求状态 / 当前阶段)取值域两两不重叠,共用 .st 即可。
推荐等级、分析状态目标件里本就是 .st 徽标(原样照抄 .st.ok/.miss/.unknown/.cond 四条声明);
需求状态 / 当前阶段目标件没有这两列,借同一套配色,不新配颜色。 */
${badgeCss('.st', [
['recommended', '推荐', OK],
['conditional', '条件推荐', 'color: var(--ledger); background: var(--ledger-soft); border-color: var(--ledger-line);'],
['alternate', '备选', AMBER],
['not_recommended', '不推荐', DANGER],
['ai_draft', 'AI 草稿', AMBER],
['fae_confirmed', 'FAE确认', OK],
['pending_customer', '待客户验证', 'color: var(--ledger); background: var(--ledger-soft); border-color: var(--ledger-line);'],
['customer_approved', '客户已批准', OK],
['rejected', '不批准', DANGER],
['void', '作废', MUTED],
['pending', '待处理', MUTED],
['responded', '已响应', 'color: var(--ledger); background: var(--ledger-soft); border-color: var(--ledger-line);'],
['won', '已成交', OK],
['abandoned', '已放弃', DANGER],
['closed', '已关闭', MUTED],
['assessing', '评估中', MUTED],
['gate03', '提交 ACT-GATE-03', OK],
])}
/* 风险等级比验收 01 多一档 critical(P-11 主记录的 risk_level 声明了它,差异明细没有) */
${badgeCss('.risk', [
['low', '低', 'color: var(--ok);'],
['medium', '中', 'color: #8f6a12;'],
['high', '高', 'color: var(--danger);'],
['critical', '危急', 'color: var(--danger); font-weight: 900;'],
])}
/* 替代类型 —— 目标件里是纯文字,不配色,只补文案(与验收 01 同一套值域,各自页面各存一份) */
${badgeCss('.enumtxt', [
['pin_to_pin', 'Pin-to-Pin'],
['functional', '功能替代'],
['parametric', '参数替代'],
['other', '其他'],
])}
`;
/** 三层壳照目标件:`<div class="page"><div class="card">`,不再套 `.proto-root`/`.app-shell`/`.jc-stage`
* (那是 E04/I01 自己的视觉底约定,不是平台要求 —— ui-kit / view-render 从未引用过这几个类名;
* 目标件本身就是直接 `page > card`,搬版面就该原样搬这一层)。
* 收件人 / 关联任务两格由引擎注入;目标件的「最迟交回」(`card.deadline`)本仓没有真数据源,不摆;
* 工单编号(`card.id`)换成本次评估案号 `eval_ref`。
*/
const doc = (input: { css: string; alias: string; badge: string; hic?: string; tag: string; kicker: string; title: string; step: string; body: string; footTag: string }): string =>
`<style>${input.css}${BIND_COMMON}${input.alias}</style>
<div class="page"><div class="card">
<header class="card-head">
<div class="badge">${input.badge}</div>
${input.hic ?? ''}
<div class="tit">
<div class="kick">${input.kicker}</div>
<h1>${input.title}</h1>
<div class="sub">收件人:<span data-slot="case:owner"></span> · 关联任务:<span class="mono" data-slot="case:taskId" data-blank></span></div>
</div>
<div class="side">
<span class="tag">${input.tag}</span>
<span class="step">${input.step}</span>
</div>
</header>
<div class="card-bd">${input.body}</div>
<footer class="card-foot">
<span>${input.kicker} · ${input.title}</span>
<span style="font-family:'SF Mono',Menlo,Consolas,monospace">${input.footTag} · <span data-slot="eval_ref" data-blank></span></span>
</footer>
</div></div>`;
/* ==================== 内联 SVG 图标 —— 逐字节搬自「数据工单-01」目标件(它们是版面语言的一部分) ==================== */
const HIC =
'<svg class="hic" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><ellipse cx="10" cy="5" rx="7" ry="3"/><path d="M3 5v14c0 1.66 3.13 3 7 3 1.13 0 2.21-.09 3.2-.26"/><path d="M3 12c0 1.66 3.13 3 7 3 1.13 0 2.21-.09 3.2-.26"/><circle cx="18" cy="18" r="4.2"/><path d="M18 15.8v4.4M15.8 18h4.4"/></svg>';
const ZIC_TASK =
'<svg class="zic" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="8" y="2" width="8" height="4" rx="1"/><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"/><path d="M9 12h6M9 16h4"/></svg>';
const ZIC_TABLE =
'<svg class="zic" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M3 10h18M9 10v10"/></svg>';
/* ==================== 通用绑定小工具 ==================== */
const zone = (label: string, aside: string, icon = ''): string => `<p class="zone">${icon}<b>【${label}】</b>—— ${aside}</p>`;
const note = (items: readonly string[]): string => `<div class="note">${items.map((p) => `<p>${p}</p>`).join('')}</div>`;
const criteria = (title: string, items: readonly string[]): string =>
`<div class="criteria"><div class="c-title">${title}</div><ul>${items.map((i) => `<li>${i}</li>`).join('')}</ul></div>`;
const flow = (text: string): string => `<div class="flow">${text}</div>`;
const editGate = (address: string, label: string): string => `<div class="jc-editgate" data-edit-for="${address}">
<span class="jc-editgate-t">${label}</span>
<button class="jc-egbtn eg-open" type="button" data-edit-open="${address}">编辑</button>
<button class="jc-egbtn eg-cancel" type="button" data-edit-cancel="${address}">取消</button>
<button class="jc-egbtn eg-save" type="button" data-edit-save="${address}">保存</button>
</div>`;
const gapbar = (object: string, what: string): string => `<div class="jc-gapbar" data-class-of="${object}_missing">
<span><b>还差 <span data-slot="${object}_missing"></span> 行${what}没填</b> —— <span data-slot="${object}_missing_keys"></span>。按「编辑」开表,红框那几格就是要填的。补齐了才确认得了。</span>
</div>`;
const addrow = (address: string, label: string, hint: string): string => `<div class="jc-addrow">
<button type="button" data-edit-add="${address}">${label}</button>
<em>${hint}</em>
</div>`;
/** 可改格:只读那一份留空,渲染器自动配孪生 `<input>`(手写 input 会不填值,人一点编辑就是白框) */
const cell = (col: string, cls = ''): string => `<span class="jc-vcell${cls === '' ? '' : ` ${cls}`}" data-slot="${col}" data-col="${col}" data-blank></span>`;
/** 只读格:即便挂在可改的表里也不许被 `table.on` 藏起来 —— 目标件自己就有这条覆盖(`.jc-vcell.ro`) */
const ro = (col: string, cls = ''): string => `<span class="jc-vcell ro${cls === '' ? '' : ` ${cls}`}" data-slot="${col}" data-blank></span>`;
const select = (col: string, options: ReadonlyArray<readonly [string, string]>, required = false): string =>
`<select class="jc-cell" data-col="${col}"${required ? ' required' : ''}><option value=""></option>${options.map(([v, l]) => `<option value="${v}">${l}</option>`).join('')}</select>`;
/**
* 枚举徽标。可改表里挨着 `<select class="jc-cell">` 孪生件时包一层 `.jc-vcell`(不带 `.ro`):
* 看的时候摆徽标,**编辑态随只读格一起藏起来,只留下拉框** —— 从前包的是 `.ro`(编辑态留着),
* 徽标压在下拉框头上把那一格顶低 13px,一排格子高低不齐(2026-08-27 用户指出)。
*/
const badge = (klass: string, col: string, wrapTwin = false): string => {
const inner = `<span class="${klass}" data-class-of="${col}"></span>`;
return wrapTwin ? `<span class="jc-vcell">${inner}</span>` : inner;
};
/* ==================== 局面 0 · 数据工单 P-08(搬自「数据工单-01」)==================== */
const P08_TABLE = `<div class="jc-tbl-wrap"><table id="tbl1">
<thead><tr>
<th style="width:38px">#</th>
<th class="req" data-h="内部料号">内部料号</th>
<th class="req" data-h="品牌名称">品牌</th>
<th data-h="制造商名称">制造商</th>
<th class="req" data-h="规格描述">规格描述</th>
<th class="req" data-h="封装">封装</th>
<th data-h="工艺">工艺</th>
<th class="req" data-h="生命周期状态">生命周期</th>
<th data-h="EOL/PCN状态">EOL/PCN</th>
<th data-h="Datasheet引用">Datasheet 引用</th>
<th data-h="Datasheet版本">Datasheet 版本</th>
<th data-h="适配应用场景">适配场景</th>
</tr></thead>
<tbody data-rows="mine:parts.profile" data-edit="parts.profile"><tr>
<td class="rn"><span class="jc-rn-num"></span><button class="jc-rowdel" type="button" title="删除此行" data-edit-del="parts.profile">×</button></td>
<td>${cell('internal_pn', 'mono')}</td>
<td>${cell('brand_name')}</td>
<td>${cell('manufacturer_name')}</td>
<td>${cell('specification_description')}</td>
<td>${cell('package', 'mono')}</td>
<td>${cell('process_technology')}</td>
<td>${badge('stx', 'lifecycle_status', true)}${select('lifecycle_status', [['active', 'Active'], ['nrnd', 'NRND'], ['eol', 'EOL'], ['discontinued', '停产'], ['risk', '风险']], true)}</td>
<td>${cell('eol_pcn_status')}</td>
<td>${cell('datasheet_ref', 'mono')}</td>
<td>${cell('datasheet_version')}</td>
<td>${cell('application_scenarios')}</td>
</tr></tbody>
</table></div>`;
/*
* 表 2 · 标准化参数集(P-08 子表 `parts.parameter`)—— 粒度与表 1 不同(一个参数一行,
* 行数不固定),不能塞进表 1 的一格(《统一方案》§六:重复明细用子表承载),
* 逐块搬自目标件《数据工单-01》的【创建什么 · 表 2】,`id="tbl2"` 沿用目标件自己的
* 列宽声明(P08_CSS 里 `#tbl2 th:nth-child(n)` 那几条,不必在这里重复)。
* 「说明」列是系统只读注释(目标件原话:「说明列为系统注释,无需填写」),不给 data-col。
*/
const P08_PARAMS_TABLE = `<div class="jc-tbl-wrap"><table id="tbl2">
<thead><tr>
<th style="width:38px">#</th>
<th class="req" data-h="所属料号">所属料号</th>
<th class="req" data-h="参数名">参数名</th>
<th class="req" data-h="值">值</th>
<th data-h="单位">单位</th>
<th class="req" data-h="约束类型">约束(硬/软)</th>
<th data-h="说明">说明</th>
</tr></thead>
<tbody data-rows="mine:parts.parameter" data-edit="parts.parameter"><tr>
<td class="rn"><span class="jc-rn-num"></span><button class="jc-rowdel" type="button" title="删除此行" data-edit-del="parts.parameter">×</button></td>
<td>${cell('internal_pn', 'mono')}</td>
<td>${cell('param_name')}</td>
<td>${cell('param_value', 'mono')}</td>
<td>${cell('param_unit')}</td>
<td>${badge('ct', 'constraint_type', true)}${select('constraint_type', [['hard', '硬约束'], ['soft', '软约束']], true)}</td>
<td class="desc">${ro('param_note')}</td>
</tr></tbody>
</table></div>`;
export const P08_MASTER_CREATE = doc({
css: P08_CSS,
alias: BIND_P08,
badge: '数据',
hic: HIC,
tag: '数据工单',
kicker: 'SS02 · ACT-WORK-05 差异评估 · 数据工单 1/2',
title: '芯片主数据创建(P-08)',
step: '步骤 0.5 · 等待数据',
footTag: '工单类型:数据',
body:
zone('做什么', '批量创建 P-08 主数据记录', ZIC_TASK) +
note([
'<span class="need">模板定位</span>:本单是「数据工单」统一模板的实例——<b>一单一类(可多条)</b>:目标台账 = <b>芯片主数据(P-08)</b>;<b>字段即表头、每行一条新记录</b>;标准化参数集是它的结构子表(表 2,一行一参数,按所属料号归属)。',
'<span class="need">触发原因</span>:系统按内部料号查芯片主数据<b>查无记录</b>——是「完全没有」,不是字段缺失(那归执行工单)。',
'<span class="done">AI 预填</span>:上传了 datasheet 的料号 AI 已按资料预填,标着值的格子请核对;没上传的料号全部手填,同为合法路径。',
'<span class="need">纪律</span>:必填列全齐才允许确认;确认后这批记录进本单草稿,放行时并入正式库并留痕(确认人 = 数据责任人);只建主数据,验证记录等事实类不在此建。',
]) +
zone('创建什么 · 表 1', '主数据记录(每行一条,*为必填列)', ZIC_TABLE) +
gapbar('parts_profile', '必填') +
editGate('parts.profile', `<b>待建 <span data-slot="parts_profile_rows"></span> 条记录</b>,点「编辑」核对预填、补齐空缺;「+ 加一行」= 再建一条`) +
P08_TABLE +
addrow('parts.profile', '+ 加一行(再建一条记录)', '新行的内部料号必须写(它是这一行的钥匙);其余必填列全部填写后才允许确认;删一行 = 该记录不建') +
`<p class="zone tbl-gap">${ZIC_TABLE}<b>【创建什么 · 表 2】</b>—— 标准化参数集(每行一个参数,按所属料号归属,*必填)</p>` +
gapbar('parts_parameter', '必填') +
editGate('parts.parameter', `<b>已铺 <span data-slot="parts_parameter_rows"></span> 行参数</b>(有 datasheet 的已按资料预填),点「编辑」核对修正;「+ 加一行」补充未列出的参数`) +
P08_PARAMS_TABLE +
addrow('parts.parameter', '+ 加一行(补充参数)', '所属料号 / 参数名 / 值 / 单位 / 约束类型齐全;「未披露」请直接写未披露,将进入 UNKNOWN 并挂验证任务;「说明」列为系统注释,无需填写') +
flow('<b>提交 / 确认:</b>本工单只承载内容;确认请在对话区的【执行卡】中进行。确认后活动自动从「等待数据」唤醒。'),
});
/* ==================== 局面 0′ · 数据工单 P-10(复用「数据工单-01」的样式与骨架,没有独立目标件)==================== */
const P10_TABLE = `<div class="jc-tbl-wrap"><table>
<thead><tr>
<th style="width:38px">#</th>
<th class="req" data-h="关联料号">关联料号</th>
<th class="req" data-h="资料序号">资料序号</th>
<th class="req" data-h="资料类型">资料类型</th>
<th data-h="品牌名称">品牌</th>
<th class="req" data-h="资料标题">资料标题</th>
<th class="req" data-h="资料版本">资料版本</th>
<th class="req" data-h="文件链接">文件链接</th>
<th data-h="证据定位">证据定位</th>
<th class="req" data-h="资料状态">资料状态</th>
</tr></thead>
<tbody data-rows="mine:parts.document" data-edit="parts.document"><tr>
<td class="rn"><span class="jc-rn-num"></span><button class="jc-rowdel" type="button" title="删除此行" data-edit-del="parts.document">×</button></td>
<td>${cell('internal_pn', 'mono')}</td>
<td>${cell('doc_seq', 'mono')}</td>
<td>${badge('stx', 'document_type', true)}${select('document_type', [['datasheet', 'Datasheet'], ['app_note', '应用笔记'], ['reference_design', '参考设计'], ['white_paper', '白皮书'], ['sample_doc', '样片资料'], ['commitment_letter', '承诺函'], ['other', '其他']], true)}</td>
<td>${cell('brand_name')}</td>
<td>${cell('document_title')}</td>
<td>${cell('document_version')}</td>
<td>${cell('document_ref', 'mono')}</td>
<td>${cell('citation_locator')}</td>
<td>${badge('stx', 'document_status', true)}${select('document_status', [['valid', '有效'], ['expired', '过期'], ['pending', '待核实'], ['void', '作废']], true)}</td>
</tr></tbody>
</table></div>`;
export const P10_DOCUMENT_CREATE = doc({
css: P08_CSS,
alias: BIND_P08,
badge: '数据',
hic: HIC,
tag: '数据工单',
kicker: 'SS02 · ACT-WORK-05 差异评估 · 数据工单 2/2',
title: '原厂技术资料创建(P-10)',
step: '步骤 0.5 · 等待数据',
footTag: '工单类型:数据',
body:
zone('做什么', '为本单新建的料号登记原厂资料(P-10)', ZIC_TASK) +
note([
'<span class="need">模板定位</span>:与 P-08 同一套「数据工单」统一模板——目标台账 = <b>原厂技术资料库(P-10)</b>;一份资料一行,同一料号多份资料序号 01/02… 自己续。',
'<span class="need">触发原因</span>:按内部料号查原厂技术资料库<b>查无记录</b>(P-08 那张先确认过,这一批料号才会走到这里)。',
'<span class="need">为什么要它</span>:差异明细的证据引用要指到具体资料的版本与页码——没有这一行,结论就追溯不到来源。',
]) +
zone('创建什么', '资料记录(每行一条,*为必填列)', ZIC_TABLE) +
gapbar('parts_document', '必填') +
editGate('parts.document', `<b>待建 <span data-slot="parts_document_rows"></span> 条资料记录</b>,点「编辑」补齐`) +
P10_TABLE +
addrow('parts.document', '+ 加一行(再登记一份资料)', '关联料号与序号是这一行的钥匙,新行都要写;必填列全齐才允许确认;删一行 = 该资料不建') +
flow('<b>提交 / 确认:</b>本工单只承载内容;确认请在对话区的【执行卡】中进行。'),
});
/* ==================== 局面 1 · 评估输入清单(搬自「执行工单-01」)==================== */
const PN_CHECK_TABLE = `<div class="jc-tbl-wrap"><table>
<thead><tr>
<th style="width:38px">#</th>
<th data-h="料号">料号</th>
<th data-h="角色">角色</th>
<th data-h="在库状态">在库状态</th>
<th data-h="备注/放弃原因">备注 / 放弃原因</th>
</tr></thead>
<tbody data-rows="mine:${D}.pn_check"><tr>
<td class="rn"><span class="jc-rn-num"></span></td>
<td>${ro('internal_pn', 'mono')}</td>
<td><span class="jc-vcell ro"><span class="rl" data-class-of="role"></span></span></td>
<td>${badge('st', 'exists_status', true)}</td>
<td>${ro('note')} ${ro('abandon_reason')}</td>
</tr></tbody>
</table></div>`;
const GAP_TABLE = `<div class="jc-tbl-wrap"><table id="tbl">
<thead><tr>
<th style="width:38px">#</th>
<th style="width:120px" data-h="键">键</th>
<th data-h="输入项">输入项</th>
<th data-h="来源">来源</th>
<th data-h="状态">状态</th>
<th data-h="绑定值/缺口说明">绑定值 / 缺口说明</th>
<th data-h="补充内容">补充内容</th>
</tr></thead>
<tbody data-rows="mine:${D}.input_gap" data-edit="${D}.input_gap"><tr>
<td class="rn"><span class="jc-rn-num"></span><button class="jc-rowdel" type="button" title="删除此行" data-edit-del="${D}.input_gap">×</button></td>
<td>${cell('item_key', 'mono')}</td>
<td>${cell('input_item')}</td>
<td>${cell('source_ledger', 'mono')}</td>
<td>${select('status', [['gap', '待补'], ['default', '默认·可改'], ['ok', '齐备']], true)}${badge('st', 'status')}</td>
<td>${cell('detail')}</td>
<td class="sup" data-class-of="status">${cell('supplement')}</td>
</tr></tbody>
</table></div>`;
export const EVAL_INPUT_LIST = doc({
css: EXEC_CSS,
alias: BIND_EXEC,
badge: '执行',
tag: '执行工单',
kicker: 'SS02 · ACT-WORK-05 差异评估 · 执行工单 1/1',
title: '评估输入与资料补齐确认',
step: '步骤 1/5 · 建立评估上下文',
footTag: '工单类型:执行',
body:
zone('做什么', '启动 4 项已绑定,其余信息在工单里补齐') +
note([
'<span class="done">AI 已完成</span>:系统已按启动传入的 <b>4 项</b>完成绑定——客户、客户需求(新建 P-01 · 版本 V1)、原 PN、候选 PN(数组,逐个评估)——并生成输入快照。',
'<span class="need">需要你补齐</span>:启动时未收的信息(应用场景、BOM 位)<b>直接在下表补</b>;默认值(替代类型 / 规则版本 / 负责人期限)可确认可改。本单缺口只覆盖「<b>有而不全</b>」;「完全没有」(料号不在库)已由数据工单创建。未补齐的缺口项将按 <b>UNKNOWN</b> 进入差异评估。',
]) +
zone('料号存在性核对', '只读参考 · 与下表「补充内容」互不冲突') +
PN_CHECK_TABLE +
zone('交回什么', '评估输入清单(已绑定项照实核对,缺口项补齐,*为必填)') +
gapbar(`${D}_input_gap`, '补充内容') +
editGate(`${D}.input_gap`, `<b>还有 <span data-slot="${D}_input_gap_missing"></span> 项待补 / 待确认</b>,点「编辑」在「补充内容」列填入 —— 已绑定那几行的「输入项/来源/绑定值」抄的是启动入参,发现记录本身有误请退回触发方重新启动,不要在这里改`) +
GAP_TABLE +
addrow(`${D}.input_gap`, '+ 加一行(补充资料项)', '新行的「键」必须写(它是这一行的钥匙,写一个英文短名,如 thermal_note);「输入项」与「补充内容」也是必填;删一行 = 该输入项不适用;补不了的写「留 UNKNOWN」或「挂验证任务」') +
flow(
'<b>审批 / 提交:</b>本工单只承载内容;「提交」请在对话区的【执行卡】中进行。<b>提交后去向:</b>进入步骤 2 · AI 读取与标准化,仍缺失的项将按 UNKNOWN 进入差异评估。<b>注意:</b>启动参数如有误,需退回触发方修订后重新触发,本单不可改。',
),
});
/* ==================== 局面 2 · 差异评估结论审核(搬自「验收工单-01」)==================== */
const RELATION_SUMMARY_TABLE = `<div class="tbl-wrap"><table>
<thead><tr>
<th style="width:40px">#</th>
<th data-h="候选料号">候选料号</th>
<th data-h="替代类型">替代类型</th>
<th data-h="推荐等级">推荐等级</th>
<th data-h="风险等级">风险等级</th>
<th data-h="推荐理由">推荐理由</th>
<th data-h="差异摘要">差异摘要</th>
</tr></thead>
<tbody data-rows="mine:substitution.relation"><tr>
<td class="num"></td>
<td class="mono" data-slot="candidate_internal_pn" data-blank></td>
<td><span class="enumtxt" data-class-of="substitution_type"></span></td>
<td>${badge('st rec', 'recommendation_level')}</td>
<td>${badge('risk', 'risk_level')}</td>
<td class="reason" data-slot="recommendation_reason" data-blank></td>
<td class="reason" data-slot="difference_summary" data-blank></td>
</tr></tbody>
</table></div>`;
const DIFFERENCE_ITEM_TABLE = `<div class="tbl-wrap"><table>
<thead><tr><th style="width:40px">#</th><th data-h="参数项 parameter_name">参数项 parameter_name</th><th data-h="原PN值 original_value">原 PN 值 original_value</th><th data-h="候选PN值 candidate_value">候选 PN 值 candidate_value</th><th data-h="单位 parameter_unit">单位 parameter_unit</th><th data-h="约束类型 constraint_type">约束类型 constraint_type</th><th data-h="结论 difference_status">结论 difference_status</th><th data-h="风险等级">风险等级</th><th data-h="证据引用 evidence_ref">证据引用 evidence_ref</th><th data-h="AI置信度">AI 置信度</th></tr></thead>
<tbody data-rows="mine:substitution.difference_item"><tr>
<td class="num"></td>
<td class="cust" data-slot="parameter_name" data-blank></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><span class="con" data-class-of="constraint_type"></span></td>
<td>${badge('st dst', 'difference_status')}</td>
<td>${badge('risk', 'risk_level')}</td>
<td class="mono" data-slot="evidence_ref" data-blank></td>
<td class="mono" data-slot="confidence" data-blank></td>
</tr></tbody>
</table></div>`;
export const DIFFERENCE_REVIEW = doc({
css: ACC1_CSS,
alias: BIND_ACC1,
badge: '验收',
tag: '验收工单',
kicker: 'SS02 · ACT-WORK-05 差异评估 · 验收工单 1/2',
title: '差异评估结论审核',
step: '步骤 3~4/5 · 逐项差异评估 + FAE/RI 审核',
footTag: '工单类型:验收',
body:
zone('AI 结论说明', '结论是怎么算出来的') +
note([
'<b>AI 已完成的计算</b>:按 GOV 评估规则(锁定版本 <b class="mono" data-slot="rule_version" data-blank></b>),对原 PN <b class="mono" data-slot="original_internal_pn" data-blank></b> 与每个候选逐项比对,产出四态结论——<b>MATCH / MISMATCH / UNKNOWN / CONDITIONAL</b>,并给出风险等级、证据引用与置信度。差异明细 = <b>P-11 差异明细子表</b>(一条参数差异一条记录);当前为 AI 草稿,<b>FAE 审核通过前不落账</b>。评估参数可能含本次数据工单创建的主数据(确认人背书;未附 datasheet 的参数项会显式标注「人工录入」)。',
]) +
criteria('判断这份差异评估结论是否可信,请逐项核对', [
'<b>关键参数差异均有明确状态</b>:逐项结论无漏项,每个参数都有四态之一的判定;',
'<b>UNKNOWN 项均有去向</b>:每个 UNKNOWN 都挂了验证任务或补来源动作,不允许悬空;',
'<b>证据链完整</b>:每项结论可追溯至 P-08 / P-10 / P-06 的具体记录,或本单数据工单的创建记录(标注:人工录入);',
'<b>硬约束项未被自动判 MATCH</b>:封装 / 工艺等硬约束未经证据支持不得判 MATCH。',
]) +
zone('各候选推荐等级', '只读展示(P-11 主记录草稿,一个候选一条)') +
RELATION_SUMMARY_TABLE +
zone('AI 产出的差异明细', '只读展示(P-11 差异明细子表草稿 · 一条参数一条记录 difference_item_id)') +
DIFFERENCE_ITEM_TABLE +
flow(
'<b>审批:</b>本工单只承载内容;「通过 / 驳回」请在对话区的【验收卡】中进行。审核意见与补充条件写入 P-06(验证要求 verification_requirement);<b>通过后去向:</b>进入步骤 5 · 评审放行与落账确认。',
),
});
/* ==================== 局面 3 · 评审放行与落账确认(搬自「验收工单-02」)==================== */
/** 字段:值 两列表 —— 逐字节搬自目标件「拟写 P-11」「拟回写 P-01」的版式(一行一个字段),
* 用 `data-rows` 包一整张小表当行模版,一个候选 / 一条需求各重复出一份,天然支持多候选。 */
const P11_FIELD_TABLE = `<div class="tbl-wrap"><table>
<thead><tr><th style="width:40px">#</th><th style="width:180px" data-h="字段">字段</th><th data-h="拟写入值">拟写入值</th></tr></thead>
<tbody data-rows="mine:substitution.relation">
<tr><td class="num"></td><td class="cust">替代类型 substitution_type</td><td><span class="enumtxt" data-class-of="substitution_type"></span></td></tr>
<tr><td class="num"></td><td class="cust">原内部料号 original_internal_pn</td><td class="mono" data-slot="original_internal_pn" data-blank></td></tr>
<tr><td class="num"></td><td class="cust">候选内部料号 candidate_internal_pn</td><td class="mono" data-slot="candidate_internal_pn" data-blank></td></tr>
<tr><td class="num"></td><td class="cust">推荐等级 recommendation_level</td><td>${badge('st', 'recommendation_level')} <span class="reason">(枚举:推荐 / 条件推荐 / 备选 / 不推荐,四态之一)</span></td></tr>
<tr><td class="num"></td><td class="cust">推荐理由 recommendation_reason</td><td data-slot="recommendation_reason" data-blank></td></tr>
<tr><td class="num"></td><td class="cust">差异摘要 difference_summary</td><td data-slot="difference_summary" data-blank></td></tr>
<tr><td class="num"></td><td class="cust">替代分析报告 analysis_report_ref</td><td class="mono" data-slot="analysis_report_ref" data-blank></td></tr>
<tr><td class="num"></td><td class="cust">分析状态 analysis_status</td><td>${badge('st', 'analysis_status')} <span class="reason">(枚举:AI草稿 / FAE确认 / 待客户验证 / 客户已批准 / 不批准 / 作废)</span></td></tr>
<tr><td class="num"></td><td class="cust">客户批准状态 customer_approval_status</td><td>未提交 <span class="reason">(由审批流程维护,本活动不产生)</span></td></tr>
<tr><td class="num"></td><td class="cust">风险等级 risk_level</td><td>${badge('risk', 'risk_level')}</td></tr>
<tr><td class="num"></td><td class="cust">验证要求 verification_requirement</td><td class="mono" data-slot="verification_requirement" data-blank></td></tr>
<tr><td class="num"></td><td class="cust">证据可信度 confidence_score</td><td class="mono" data-slot="confidence_score" data-blank></td></tr>
<tr><td class="num"></td><td class="cust">差异规则版本 rule_version</td><td class="mono" data-slot="rule_version" data-blank></td></tr>
</tbody>
</table></div>`;
const P01_FIELD_TABLE = `<div class="tbl-wrap"><table>
<thead><tr><th style="width:40px">#</th><th style="width:180px" data-h="字段">字段</th><th data-h="拟写入值">拟写入值</th></tr></thead>
<tbody data-rows="mine:demand.request">
<tr><td class="num"></td><td class="cust">风险等级 risk_level</td><td>${badge('risk', 'risk_level')}</td></tr>
<tr><td class="num"></td><td class="cust">验证要求 verification_requirement</td><td class="mono" data-slot="verification_requirement" data-blank></td></tr>
<tr><td class="num"></td><td class="cust">输出链接 output_ref</td><td class="mono" data-slot="output_ref" data-blank></td></tr>
<tr><td class="num"></td><td class="cust">下一步动作 next_action</td><td data-slot="next_action" data-blank></td></tr>
<tr><td class="num"></td><td class="cust">当前阶段 current_stage</td><td>${badge('st', 'current_stage')}</td></tr>
<tr><td class="num"></td><td class="cust">需求状态 request_status</td><td>${badge('st', 'request_status')}</td></tr>
</tbody>
</table></div>`;
export const LANDING_CONFIRM = doc({
css: ACC2_CSS,
alias: BIND_ACC2,
badge: '验收',
tag: '验收工单',
kicker: 'SS02 · ACT-WORK-05 差异评估 · 验收工单 2/2',
title: '评审放行与落账确认',
step: '步骤 5/5 · 提交 ACT-GATE-03',
footTag: '工单类型:验收',
body:
zone('AI 结论说明', '本单确认什么') +
note([
'<b>本活动以 ACT-GATE-03 评审放行为终点。</b>本单确认拟落账内容:评估结论层写 <b>P-11 替代关系主记录</b>(替代类型 / 原内部料号 / 候选内部料号 / 推荐等级 / 推荐理由 / 差异摘要 / 替代分析报告 / 分析状态 / 风险等级 / 验证要求 / 证据可信度 / 差异规则版本),需求状态回写 <b>P-01</b>(风险等级 / 验证要求 / 输出链接 / 下一步动作 / 当前阶段)。<b>客户批准不属于本活动</b>——客户批准状态由审批流程维护,本单只写分析层(分析状态 = FAE 确认),customer_approval_status 保持「未提交」,不由差异评估产生。',
]) +
criteria('放行与落账前,请逐项核对', [
'<b>推荐等级与差异明细一致</b>:差异明细中存在 UNKNOWN / CONDITIONAL 时,推荐等级不得给「推荐」;',
'<b>分析状态与客户批准状态分离</b>:本单只写分析层(分析状态 = FAE 确认),客户批准状态保持「未提交」;',
'<b>GOV 规则版本已锁定</b>:规则版本随结论一并落账;',
'<b>回写 P-01 字段完整</b>:风险等级、验证要求、输出链接、下一步动作、当前阶段五项齐全。',
]) +
zone('拟写 P-11 · 替代关系主记录', '只读展示') +
P11_FIELD_TABLE +
zone('拟回写 P-01 · 需求状态', '只读展示') +
P01_FIELD_TABLE +
flow(
'<b>审批:</b>本工单只承载内容;「通过 / 驳回」请在对话区的【验收卡】中进行。<b>通过后去向:</b>在对话区卡提交 ACT-GATE-03 评审放行;放行后结论供 ACT-WORK-08 证据归集消费。',
),
});