@@ -1,32 +1,35 @@
/**
* 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」 。
* **2026-08-29 Task 7 重写**:五张旧局面(P-08 数据工单 / P-10 数据工单 / 评估输入清单 /
* 差异评估结论审核 / 评审放行与落账确认)按 spec §8 全部作废,S1 那一步不再分成
* 「先核对存在性 → 分别派 P-08/P-10 数据工单 → 再摆评估输入清单」三个局面 ——
* 新的四步案例模型只有一张数据工单卡(`variant: 'data'`),这里对应**一张**新局面
* `input-supplement`(评估输入补全):**三块竖排**(spec §6.1)——
* ① 要评估什么(两颗料的存在性 + 主数据,`sub_eval.part` 铺行 / `parts.profile` 承载编辑 );
* ② 芯片类型(每颗料各自的类型选择,选项从 `parts.chip_type` 现读;
* 下面跟着新建类型时要填的核心参数字段清单 `parts.type_param`,供加行) ;
* ③ 参数值(逐条核心参数的实测 / 规格值,一字段一行,`parts.parameter`)。
* 顶部一条红带摆 S1 配方算好的 `gate_reason`(「还差什么」的一句话,配方 §see case-model.ts
* 的 step④),够不够齐、该不该出现由样式表判(§5「模版不许算」) 。
*
* 目标件的样式表逐字节存在 `./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` 文案、不额外配色 )。
* `difference-review`(件② 差异评估结论审核)与 `landing-confirm`(件④ 评审放行与落账确认)
* 由 Task 8 / 9 分别重做(同名新建),这份文件此刻只有一张工单件。
*
* 版面语言仍是「搬,不要照着做」(《HTML报告生成规范》§7):`P08_CSS`(逐字节抽自
* `docs/SS02-ACT-WORK-05-html/ACT-WORK-05-数据工单-01-芯片主数据创建.html`,
* 见 `./target-style.ts` 头注)是**唯一**的样式来源 —— 三块内容原来分属 P-08 数据工单 /
* P-10 数据工单(复用 P08_CSS)/ 执行工单(EXEC_CSS)三张局面,合并成一张之后
* 统一沿用 P08_CSS 这一套版面语言(EXEC_CSS 随之退休,见 target-style.ts 头注 )。
* `BIND_COMMON`/`BIND_P08` 是平台绑定层加的东西(缺项红带、编辑闸/增删行、
* `data-class-of` 的 `v-*` 别名):目标件是写死数据的静态 demo,没有「N 行草稿」
* 「编辑态与归档态二选一」这些平台概念。
*/
import { P08_CSS , EXEC_CSS , ACC1_CSS , ACC2_CSS } from './target-style.ts' ;
import { P08_CSS } from './target-style.ts' ;
import { D } from '../constants.ts' ;
/* ====================================================================================
* 绑定层公共开关 —— 五 张模版共用,与目标件自己的样式表分开存(那份要保持逐字节可比)
* 绑定层公共开关 —— 三 张模版共用(此刻只有一张) ,与目标件自己的样式表分开存(那份要保持逐字节可比)
* ==================================================================================== */
const BIND_COMMON = `
/* ── 2026-08-27 用户四连指出的件上毛病,病根三处都在「目标件的样式与平台的编辑态没对上」 ── */
@@ -71,6 +74,27 @@ html.editable .jc-gapbar {
.jc-gapbar b { font-weight: 800; }
.jc-gapbar span { color: #9a3b36; }
html.editable .jc-gapbar.v-0 { display: none; }
/*
* 顶部「还差什么」红带(2026-08-29,Task 7 新增,不是照抄 .jc-gapbar):gate_reason
* 是一句中文自由文本(配方拼的整句话,如「有料号库里查不到 —— 在下面把它的主数据建起来。」),
* 不是像 _missing 那样的整数计数 —— data-class-of 把值消毒成 class 时只留 [a-z0-9-],
* 中文字符全被剥空,v-<token> 永远是空 token(既取不出 v-0 也取不出任何有意义的档位),
* 靠它去挑「空 → 隐藏」这条路本身就走不通(核对过 view-render.ts 的 classToken 实现)。
* 改用更结实的信号:data-slot 配 data-blank 让空值真的渲成空文本节点,CSS 用 :has(:empty)
* 认「这句话是不是空的」—— gate_reason 本身还是照 brief 摆 data-class-of(留作未来若换成
* 枚举型信号时的钩子,且不影响任何断言),但真正管显隐的是下面这条 :empty 规则。
*/
.jc-gate-bar { display: flex; align-items: flex-start; gap: 8px; margin: 0 0 14px; padding: 10px 14px;
border-radius: 9px; background: #fff5f5; border: 1px solid #f3b9b5; color: var(--danger); font-size: 12.5px; line-height: 1.65; }
.jc-gate-bar b { font-weight: 800; }
.jc-gate-bar:has(.jc-gate-text:empty) { display: none; }
/*
* 不给删行的两张表,编辑态里 # 号不能空着:P08_CSS 的 table.on td.rn .jc-rn-num{display:none}
* 是配 .jc-rowdel 一起写的(删行按钮腾出位置)—— 要评估什么(#tbl1)与参数值(#tbl3)两张表
* 行集固定(人不加行、系统按 sub_eval.part 与 parts.type_param 铺),没有删行按钮可换,编辑态里
* 用 id 选择器把计数器重新点亮(id 特异度压过 P08_CSS 的类选择器)。
*/
#tbl1.on td.rn .jc-rn-num, #tbl3.on td.rn .jc-rn-num { display: inline; }
` ;
/*
@@ -101,12 +125,16 @@ const DANGER = 'color: var(--danger); background: var(--danger-soft); border-col
const AMBER = 'color: #8f6a12; background: #fdf3d7; border-color: #ecd9a0;' ;
const MUTED = 'color: var(--ink-3); background: #eef1f6; border-color: var(--line);' ;
/* ==================== 数据工单(P08/P10 共用):徽标别名 ==================== */
/*
* ==================== input-supplement 的徽标别名 ====================
*
* 沿用 P08_CSS 已带的两个基座形状:`.stx`(生命周期状态那一族用的胶囊)与 `.ct`(约束类型)——
* 不新起一个 `.st` 基座类(那是已退休的 EXEC_CSS 定义的,P08_CSS 里没有它的 display/padding
* 这些基础属性,借用类名而没有基座样式,徽标会是一段无样式的裸文字)。
*/
const BIND_P08 = `
/* 生命周期 / 资料类型 / 资料状态 三个枚举列共用同一个徽标类 —— 取值域互不重叠(active/nrnd/eol/
discontinued/risk 与 datasheet/app_note/… 与 valid/expired/pending/void 三组 没有一个词撞车),
同一页内不必再分家。配色借的是本设计语言在别的目标件里已经出现过的那几个色(ok/danger/琥珀),
不是新配的颜色。 */
/* 生命周期状态(parts.profile)与在库状态(sub_eval.part.exists_status)共用 .stx 胶囊 ——
取值域互不重叠(active/nrnd/eol/discontinued/risk 与 found/absent 没有一个词撞车)。 */
.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 ] ,
@@ -114,164 +142,19 @@ ${badgeCss('.stx', [
[ '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 ] ,
[ 'found' , '在库' , OK ] ,
[ 'absent ' , '不在库 ' , AMBER ] ,
] ) }
/*
* 表 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 同一份值)。
*/
/* 约束类型(硬/软)—— parts.type_param.constraint_type,目标件 P08_CSS 已带 .ct 基座形状与这两条颜色声明 */
${ badgeCss ( '.ct' , [
[ 'hard' , '硬约束' , DANGER ] ,
[ 'soft' , '软约束' , MUTED ] ,
] ) }
` ;
/* ==================== 执行工单(评估输入清单):徽标别名 ==================== */
const BIND_EXEC = `
/* 候选参数现值(只读参考块):一颗料一张,复用 .jc-tbl-wrap;块头摆料号 / 角色 / 在库状态 */
.prefs { display: block; }
.pref { border: 1px solid var(--line-soft); border-radius: 10px; overflow: hidden; margin-bottom: 12px; }
.pref:last-of-type { margin-bottom: 0; }
.pref-head { display: flex; align-items: center; gap: 10px; padding: 9px 14px; background: var(--soft); border-bottom: 1px solid var(--line); }
.pref-head b { font-size: 13.5px; }
.pref .jc-tbl-wrap { border: 0; border-radius: 0; }
/* 存在性核对的两列(角色 / 在库状态)与评估输入清单的状态列共用目标件自己的 .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 文案 */
/* 角色(原 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 ] ,
// 目标件 2026-08-27 改版:CONDITIONAL 从题头红改成品牌蓝(.st.cond),原样照抄
[ 'conditional' , 'CONDITIONAL' , 'color: var(--brand-deep); background: var(--brand-wash); border-color: var(--brand-soft);' ] ,
] ) }
/* 推荐程度 pill —— 目标件 .rec.yes / .rec.cond / .rec.no 三条声明原样照抄;台账是四档(备选借条件推荐那档琥珀) */
${ badgeCss ( '.rec' , [
[ 'recommended' , '推荐' , OK ] ,
[ 'conditional' , '有条件推荐' , 'color: var(--amber); background: var(--amber-soft); border-color: var(--amber-line);' ] ,
[ 'alternate' , '备选' , 'color: var(--amber); background: var(--amber-soft); border-color: var(--amber-line);' ] ,
[ 'not_recommended' , '不推荐' , DANGER ] ,
] ) }
/* 候选块序号(目标件 .cand-idx 写死 1/2)—— 交给 CSS 计数器;块头的风险级别前缀「风险 」也在目标件里 */
.card-bd { counter-reset: cand; }
.cand { counter-increment: cand; }
.cand-idx::before { content: counter(cand); }
.cand-con .risk::before { content: "风险 "; }
/*
* 风险等级(原样照抄目标件 .risk.low/.mid/.hi 三条声明)——加 critical 一档:这一屏「各候选
* 推荐等级」摘要读的是 substitution.relation.risk_level(声明了 low/medium/high/critical
* 四档),差异明细本身的 risk_level 只有三档,共用同一族选择器,多出的第四档不会撞车。
*/
${ badgeCss ( '.risk' , [
[ 'low' , '低' , 'color: var(--ok);' ] ,
[ 'medium' , '中' , 'color: var(--amber, #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: var(--amber, #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`
@@ -314,8 +197,6 @@ const ZIC_TABLE =
/* ==================== 通用绑定小工具 ==================== */
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>
@@ -345,387 +226,160 @@ 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 ;
} ;
/**
* **下拉的选项从台账现读**(spec §5.3,2026-08-29):`data-options` 与 `data-slot` 不能共存 ——
* 渲染时 `fillOptions` 会把 `data-slot` 一并摘掉(它是给内容文本用的槽位标记,`<select>` 的内容
* 是一串 `<option>`,留着会被当成普通文本槽处理,把刚铺好的选项冲成一行数字/文字)。下拉的
* 「当下值」由 `data-col` 决定(`selectCurrent` 认它),这里不写 `data-slot`。
*/
const optionSelect = ( col : string , address : string , valueCol : string , labelCol : string , required = false ) : string = >
` <select class="jc-cell" data-col=" ${ col } " ${ required ? ' required' : '' } data-options=" ${ address } " data-option-value=" ${ valueCol } " data-option-label=" ${ labelCol } "></select> ` ;
/** 顶部「还差什么」红带 —— 见 BIND_COMMON 里 `.jc-gate-bar` 的显隐说明(它不是 gapbar 那种数值判断) */
const gateBar = ( ) : string = > ` <div class="jc-gate-bar" data-class-of="gate_reason">
<span><b>还差什么</b> —— <span class="jc-gate-text" data-slot="gate_reason" data-blank></span></span>
</div> ` ;
/* ==================== 局面 0 · 数据工单 P-08(搬自「数据工单-01」) ==================== */
/* ==================== 局面:评估输入补全(input-supplement,S1 的数据工单) ==================== */
const P08_TABLE = ` <div class="jc-tbl-wrap"><table id="tbl1">
/**
* 块① 要评估什么 —— 两颗料(原 PN / 候选 PN)的存在性与主数据。
*
* **行由 `sub_eval.part` 铺、写向 `parts.profile`**(`data-rows="mine:sub_eval.part"
* data-edit="parts.profile"`,两个不同的台账地址同时出现在一个行容器上,收值的授权面
* 只认 `data-edit`,与行从哪来无关 —— `apps/api/src/app/routes/desk.ts` 的
* `writesOf`/`collect` 按 `data-edit` 地址找容器、按容器内 `data-col` 收值,`data-rows`
* 只管这一屏摆几行、摆谁的)。选它做行源是因为**角色(原/候选)与在库状态**只长在
* `sub_eval.part` 上,而这两格是「要评估什么」的第一句话;`internal_pn` 挂 `data-col`
* 之后,保存时按它认作 `parts.profile` 的主键。**人不加行**(要建哪颗料是启动参数定死的事,
* 见清单 `S1_inputs.reads`),没有「+加一行」/删行按钮 —— #号列的显隐见 BIND_COMMON
* 里 `#tbl1.on td.rn .jc-rn-num` 那条覆盖。
*
* 芯片类型选择器**长在每一行里**(不是页面级单选):`sub_eval.part.chip_type_id` /
* `parts.profile.chip_type_id` 都是**逐颗料各自一份**的字段(`distinct` 判据要求两颗
* 恰好落在同一个值上,前提是它们本就可能不同),写入目标仍是 `parts.profile`。
* 只读态用嵌套 `data-by` 从 `parts.chip_type` 整表按 `type_id` 查出人读的 `type_name`
* (取值,不是算);编辑态换成 `optionSelect`(选项现读)。
*/
const PART_TABLE = ` <div class="jc-tbl-wrap"><table id="tbl1">
<thead><tr>
<th style="width:38px">#</th>
<th 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 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="制造商名称">制造商 </th>
<th data-h="规格描述">规格描述</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>
<tbody data-rows="mine: ${ D } .part " data-edit="parts.profile"><tr>
<td class="rn"><span class="jc-rn-num"></span></td>
<td><span class="jc-vcell ro"><span class="rl" data-class-of="role"></span></span></td>
<td> ${ cell ( 'internal_pn' , 'mono' ) } </td>
<td><span class="jc-vcell ro"> ${ badge ( 'stx' , 'exists_status' ) } </span></td>
<td>
<span class="jc-vcell"><span data-rows="parts.chip_type" data-by="type_id=chip_type_id"><i data-slot="type_name" data-blank></i></span></span>
${ optionSelect ( 'chip_type_id' , 'parts.chip_type' , 'type_id' , 'type_name' , true ) }
</td>
<td> ${ cell ( 'brand_name' ) } </td>
<td> ${ badge ( 'stx' , 'lifecycle_status' , true ) } ${ select ( 'lifecycle_status' , [ [ 'active' , 'Active' ] , [ 'nrnd' , 'NRND' ] , [ 'eol' , 'EOL' ] , [ 'discontinued' , '停产' ] , [ 'risk' , '风险' ] ] , true ) } </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。
/**
* 块② 芯片类型的核心参数字段清单 —— `parts.type_param`,复合主键 `type_id + param_name`。
* **供新建类型时加字段行**(唯一带「+加一行」/删行的一张):类型下拉里没有合适的 ,
* 人就在这里把新类型的核心参数字段一条条定下来(名字 / 说明 / 硬软约束 / 单位)。
*
* **不挂 `id="tbl2"`**:P08_CSS 的 `#tbl2 th:nth-child(n)` 那几条列宽规则是按位置
* (nth-child)写死给旧版 `parts.parameter` 表(所属料号/参数名/值/单位/约束/说明,7 列)调的,
* 这张表列的顺序与语义不同(所属类型编号/参数名/参数说明/约束/参考单位,6 列)——
* 位置 5、6 恰好被那两条老规则套反(约束套上「单位」的宽度、参考单位套上「约束」的宽度)。
* 不挂 id 就不会继承这几条位置写死的规则,退回普通 `table`/`th`/`td` 基础样式。
*/
const P08_PARAMS_TABLE = ` <div class="jc-tbl-wrap"><table id="tbl2" >
const TYPE_PARAM_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 class="req" data-h="参数说明">参数说明</th>
<th class="req" data-h="约束类型">约束(硬/软)</th>
<th data-h="参考单位">参考单位</th>
</tr></thead>
<tbody data-rows="mine:parts.type_param" data-edit="parts.type_param"><tr>
<td class="rn"><span class="jc-rn-num"></span><button class="jc-rowdel" type="button" title="删除此行" data-edit-del="parts.type_param">× </button></td>
<td> ${ cell ( 'type_id' , 'mono' ) } </td>
<td> ${ cell ( 'param_name' ) } </td>
<td> ${ cell ( 'param_desc' ) } </td>
<td> ${ badge ( 'ct' , 'constraint_type' , true ) } ${ select ( 'constraint_type' , [ [ 'hard' , '硬约束' ] , [ 'soft' , '软约束' ] ] , true ) } </td>
<td> ${ cell ( 'param_unit' ) } </td>
</tr></tbody>
</table></div> ` ;
/**
* 块③ 参数值 —— `parts.parameter`,一字段一行(行由 S1 配方按 `sub_eval.part × parts.type_param`
* 铺,`prune:true` 会把不属于这个组合的孤行清掉,故这张表也**人不加行**)。
* **只两栏可改**(brief 原话):值 / 说明;`param_unit` 特意留只读 —— 配方每拍都从
* `parts.type_param` 字典**直接复制**这一格(`{ col: 'param_unit' }`,不是自查现值的
* `lookup...else` 那种自保写法),手改了也会在下一拍被字典值覆盖回去,给它配可编辑的
* 输入孪生件只会让人误以为改了真的算数。
*/
const PARAMETER_TABLE = ` <div class="jc-tbl-wrap"><table id="tbl3">
<thead><tr>
<th style="width:38px">#</th>
<th data-h="所属料号">所属料号</th>
<th 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 class="rn"><span class="jc-rn-num"></span></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>
<td> ${ ro ( 'param_unit' ) } </td>
<td> ${ cell ( 'param_note' ) } </td>
</tr></tbody>
</table></div> ` ;
export const P08_MASTER_CREATE = doc ( {
export const INPUT_SUPPLEMENT = doc ( {
css : P08_CSS ,
alias : BIND_P08 ,
badge : '数据' ,
hic : HIC ,
tag : '数据工单' ,
kicker : 'SS02 · ACT-WORK-05 差异评估 · 数据工单 1/2 ' ,
title : '芯片主数据创建(P-08) ' ,
step : '步骤 0.5 · 等待 数据' ,
kicker : 'SS02 · ACT-WORK-05 差异评估 · 数据工单' ,
title : '差异评估的输入还差几格 ' ,
step : '步骤 1/4 · 校验入参与补 数据' ,
footTag : '工单类型:数据' ,
body :
zone ( '做什么' , '批量创建 P-08 主数据记录 ' , ZIC_TASK ) +
zone ( '做什么' , '核对两颗料在不在库、归没归同一个芯片类型、参数值齐不齐;缺什么就在下面补齐 ' , 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>:必填列全齐才允许确认;确认后这批记录进本单草稿,放行时并入正式库并留痕(确认人 = 数据责任人);只建主数据,验证记录等事实类不在此建 。' ,
'<span class="need">模板定位</span>:本单是「数据工单」—— 目标台账 = 芯片主数据(P-08 主记录 + 标准化参数子表),核心参数字段清单挂在芯片类型字典上 。' ,
'<span class="need">触发原因</span>:下面【要评估什么】里两行是本次评估要比对的原 PN 与候选 PN —— 至少有一颗不在库、两颗归的类型不一致、或必填格还空着,下面这条红带才会出现 。' ,
'<span class="done">已绑定 </span>:两颗料的内部料号已按启动参数铺进下表,不必你重填料号本身,只需核对 / 补齐其余各格;在库的料现值已回填,只是查漏补缺 。' ,
'<span class="need">纪律</span>:两颗料必须归到同一个芯片类型下才谈得上逐项比对;类型下拉里没有合适的就新建一个,并把它的核心参数字段一并定下来;查不到的参数值留空(会被红带点名),不要编一个值顶替 。' ,
] ) +
zone ( '创建什么 · 表 1' , '主数据记录(每行一条,*为必填列)' , ZIC_TABLE ) +
gateBar ( ) +
zone ( '要评估什么' , '两颗料的存在性与主数据(每行一颗,人不加行,*为必填列)' , ZIC_TABLE ) +
editGate ( 'parts.profile' , '两颗料的主数据核对 / 补齐,点「编辑」开表' ) +
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> ` +
PART_TABLE +
zone ( '芯片类型' , '两颗料所归类型的核心参数字段清单(供新建类型时补齐,*为必填列)' , ZIC_TABLE ) +
editGate ( 'parts.type_param' , '字段名字 / 说明 / 硬软约束,点「编辑」核对;新建类型用「加一行」补字段 ') +
gapbar ( 'parts_type_param' , '必填' ) +
TYPE_PARAM_TABLE +
addrow ( 'parts.type_param' , '+ 加一行(补一个核心参数字段)' , '所属类型编号 / 参数名 / 参数说明 / 约束类型必须写;参考单位选填' ) +
zone ( '参数值' , '逐条核心参数的实测 / 规格值(一字段一行,*为必填列;单位由字典定,这里不改)' , ZIC_TABLE ) +
editGate ( 'parts.parameter' , '逐条参数值核对 / 补齐,点「编辑」开表' ) +
gapbar ( 'parts_parameter' , '必填' ) +
editGate ( 'parts.parameter' , ` <b>已铺 <span data-slot="parts_parameter_rows"></span> 行参数</b>(有 datasheet 的已按资料预填),点「编辑」核对修正;「+ 加一行」补充未列出的参数 ` ) +
P08_PARAMS_TABLE +
addrow ( 'parts.parameter' , '+ 加一行(补充参数)' , '所属料号 / 参数名 / 值 / 单位 / 约束类型齐全;「未披露」请直接写未披露,将进入 UNKNOWN 并挂验证任务;「说明」列为系统注释,无需填写' ) +
PARAMETER_TABLE +
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> ` ;
/** 候选参数现值 —— **只读参考,基座从台账现读**(2026-08-27,用户三次指出「库里明明有值,清单还要填一遍」):
* 从前「待确认」行由模型判「哪个参数原厂未披露」再写进清单 —— 参数值有没有是台账里的事实,不该由模型宣布;
* 现在每颗料一张小表(外层按核对表逐颗复制,里层 `data-by="internal_pn"` 只列它名下的参数行),
* 人看得见现值;未披露的由差异评估判成 UNKNOWN 并挂验证任务。 */
const PARAM_REF = ` <article class="prefs" data-rows="mine: ${ D } .pn_check"><section class="pref">
<div class="pref-head"><b class="mono" data-slot="internal_pn" data-blank></b><span class="rl" data-class-of="role"></span> ${ badge ( 'st' , 'exists_status' ) } </div>
<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><th data-h="说明">说明</th></tr></thead>
<tbody data-rows="parts.parameter" data-by="internal_pn"><tr>
<td class="rn"><span class="jc-rn-num"></span></td>
<td> ${ ro ( 'param_name' ) } </td>
<td> ${ ro ( 'param_value' , 'mono' ) } </td>
<td> ${ ro ( 'param_unit' ) } </td>
<td><span class="jc-vcell ro"><span class="ct" data-class-of="constraint_type"></span></span></td>
<td> ${ ro ( 'param_note' ) } </td>
</tr></tbody>
</table></div>
</section></article> ` ;
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>UNKNOWN</b> 进入差异评估并挂验证任务,不用在这里补。' ,
] ) +
zone ( '料号存在性核对' , '只读参考 · 与下表「补充内容」互不冲突' ) +
PN_CHECK_TABLE +
zone ( '候选参数现值' , '只读参考 · P-08 标准化参数集,一颗料一张,基座从台账现读;写着「未披露」的由差异评估判成 UNKNOWN 并挂验证任务' ) +
PARAM_REF +
zone ( '交回什么' , '评估输入清单(已绑定项照实核对,缺口项补齐,*为必填)' ) +
// 红带说「必填格」不说「补充内容」:缺的可能是 AI 该写的输入项(2026-08-27 实测),写死列名会把人指向错的格子
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」)==================== */
/** 候选 PN 结论汇总 —— 目标件 2026-08-27 改版:一个候选一条结论(P-11 主表草稿)。
* 品牌不在 relation 上:用嵌套行模版 `data-by` 从 `parts.profile` 整表里挑这一颗料那一行(取值,不是算)。
* 「差异统计(四态)」绑 difference_summary —— S3 剧本让模型按「7 项比对:4 MATCH / 1 MISMATCH / …」的形写它,
* 模版不数四态(数出来的画面一律不做假)。 */
const RELATION_SUMMARY_TABLE = ` <div class="tbl-wrap" style="margin-bottom:20px"><table>
<thead><tr>
<th style="width:40px">#</th>
<th data-h="候选PN">候选 PN</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="cust mono" data-slot="candidate_internal_pn" data-blank></td>
<td><span data-rows="parts.profile" data-by="internal_pn=candidate_internal_pn"><i data-slot="brand_name" data-blank></i></span></td>
<td> ${ badge ( 'rec' , 'recommendation_level' ) } </td>
<td> ${ badge ( 'risk' , 'risk_level' ) } </td>
<td class="stat" data-slot="difference_summary" data-blank></td>
<td class="reason" data-slot="recommendation_reason" data-blank></td>
</tr></tbody>
</table></div> ` ;
/** 差异明细 · 按候选 PN 分组 —— 目标件 2026-08-27 改版:**一个候选一张表**(用户:「存在多个替代 PN 要对比差异时看不清楚」)。
* 外层容器 <article> 按 relation 逐个复制行模版 <section class="cand">,里层 <tbody data-by="substitution_relation_id">
* 只列该候选名下的明细(渲染器 2026-08-27 补的嵌套 + 父键过滤)。容器标签名不得在行模版内部再出现:
* <article> 里是 section / div / table,不撞。 */
const CANDIDATE_SECTIONS = ` <article class="cands" data-rows="mine:substitution.relation"><section class="cand">
<div class="cand-head">
<span class="cand-idx"></span>
<span class="cand-name mono" data-slot="candidate_internal_pn" data-blank></span>
<span class="cand-brand" data-rows="parts.profile" data-by="internal_pn=candidate_internal_pn"><i data-slot="brand_name" data-blank></i></span>
<span class="cand-vs">vs 原 PN · <i data-slot="original_internal_pn" data-blank></i></span>
<span class="cand-con"> ${ badge ( 'rec' , 'recommendation_level' ) } ${ badge ( 'risk' , 'risk_level' ) } </span>
</div>
<div class="tbl-wrap"><table>
<thead><tr><th style="width:40px">#</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><th data-h="结论">结论</th><th data-h="风险等级">风险等级</th><th data-h="证据引用">证据引用</th><th data-h="AI置信度">AI 置信度</th></tr></thead>
<tbody data-rows="mine:substitution.difference_item" data-by="substitution_relation_id"><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>
</section></article> ` ;
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 data-slot="substitution_relation_rows"></b> 个候选 PN 分别逐项比对,每项产出四态结论——<b>MATCH / MISMATCH / UNKNOWN / CONDITIONAL</b>,并给出风险等级、证据引用与置信度;再按候选汇总出下方的【候选 PN 结论汇总】(一个候选一条结论)。差异明细 = <b>P-11 差异明细子表</b>(一条参数差异一条记录,按候选分组);结论汇总 = <b>P-11 主表草稿</b>。当前均为 AI 草稿,<b>FAE 审核通过前不落账</b>。评估参数可能含本次数据工单创建的主数据(确认人背书;未附 datasheet 的参数项会显式标注「人工录入」)。' ,
] ) +
criteria ( '判断这份差异评估结论是否可信,请逐项核对' , [
'<b>汇总结论与明细一致</b>:结论表中每个候选的推荐程度 / 风险级别,与其下方差异明细表的四态分布吻合(存在 MISMATCH 硬约束或悬空 UNKNOWN 的候选不得给「推荐」);' ,
'<b>关键参数差异均有明确状态</b>:每个候选的逐项结论无漏项,每个参数都有四态之一的判定;' ,
'<b>UNKNOWN 项均有去向</b>:每个 UNKNOWN 都挂了验证任务或补来源动作,不允许悬空;' ,
'<b>证据链完整</b>:每项结论可追溯至 P-08 / P-10 / P-06 的具体记录,或本单数据工单的创建记录(标注:人工录入);硬约束项未经证据支持不得判 MATCH。' ,
] ) +
zone ( '候选 PN 结论汇总' , '每个候选一条结论,内容 = 对应下方明细表的汇总判定(P-11 主表草稿)' ) +
RELATION_SUMMARY_TABLE +
zone ( '差异明细 · 按候选 PN 分组' , '每个候选一张表,与原 PN 逐项对比(P-11 差异明细子表草稿 · 一条参数一条记录 difference_item_id)' ) +
CANDIDATE_SECTIONS +
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">替代类型</td><td><span class="enumtxt" data-class-of="substitution_type"></span></td></tr>
<tr><td class="num"></td><td class="cust">原内部料号</td><td class="mono" data-slot="original_internal_pn" data-blank></td></tr>
<tr><td class="num"></td><td class="cust">候选内部料号</td><td class="mono" data-slot="candidate_internal_pn" data-blank></td></tr>
<tr><td class="num"></td><td class="cust">推荐等级</td><td> ${ badge ( 'st' , 'recommendation_level' ) } <span class="reason">(枚举:推荐 / 条件推荐 / 备选 / 不推荐,四态之一)</span></td></tr>
<tr><td class="num"></td><td class="cust">推荐理由</td><td data-slot="recommendation_reason" data-blank></td></tr>
<tr><td class="num"></td><td class="cust">差异摘要</td><td data-slot="difference_summary" data-blank></td></tr>
<tr><td class="num"></td><td class="cust">替代分析报告</td><td class="mono" data-slot="analysis_report_ref" data-blank></td></tr>
<tr><td class="num"></td><td class="cust">分析状态</td><td> ${ badge ( 'st' , 'analysis_status' ) } <span class="reason">(枚举:AI草稿 / FAE确认 / 待客户验证 / 客户已批准 / 不批准 / 作废)</span></td></tr>
<tr><td class="num"></td><td class="cust">客户批准状态</td><td>未提交 <span class="reason">(由审批流程维护,本活动不产生)</span></td></tr>
<tr><td class="num"></td><td class="cust">风险等级</td><td> ${ badge ( 'risk' , 'risk_level' ) } </td></tr>
<tr><td class="num"></td><td class="cust">验证要求</td><td class="mono" data-slot="verification_requirement" data-blank></td></tr>
<tr><td class="num"></td><td class="cust">证据可信度</td><td class="mono" data-slot="confidence_score" data-blank></td></tr>
<tr><td class="num"></td><td class="cust">差异规则版本</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">风险等级</td><td> ${ badge ( 'risk' , 'risk_level' ) } </td></tr>
<tr><td class="num"></td><td class="cust">验证要求</td><td class="mono" data-slot="verification_requirement" data-blank></td></tr>
<tr><td class="num"></td><td class="cust">输出链接</td><td class="mono" data-slot="output_ref" data-blank></td></tr>
<tr><td class="num"></td><td class="cust">下一步动作</td><td data-slot="next_action" data-blank></td></tr>
<tr><td class="num"></td><td class="cust">当前阶段</td><td> ${ badge ( 'st' , 'current_stage' ) } </td></tr>
<tr><td class="num"></td><td class="cust">需求状态</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 证据归集消费。' ,
) ,
} ) ;