用户已批准的 bounded 改动:把 S1 数据工单那一屏的视图层换成 docs/ss02-act-05-new/ACT-WORK-05-数据工单-PN主数据创建.html 的版面,绑定与功能不动。 用户已定三件事(压缩后不必再问):两条并列轨道 · 新增类型面板每行扩四格且去掉独立字段表 · 不动平台每步骤卡一道闸。 文档里落了压缩后会用到的全部事实:目标件结构、现有件四个片段的行号与绑定、 P08_CSS 的位置、ViewContainer 的 editable/bodyOf/addRow 机制、gateLedgers 四张表、 必须留着的终审 C1 修复(那个 disabled 的 data-col=type_id)、 以及一条要先验证再往下写的风险(步骤③ 两组瓷贴共用一个宿主时 cellsOf/rowOf 能否正确归行 —— bodyOf 只找得到一个宿主,认错会把两颗料的参数值混成一行)。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LKMZDwMbyKzjw6Hembwvet
14 KiB
input-supplement 换版面 —— 照新目标件重做数据工单那一屏
状态:设计已定、已获用户批准(2026-08-30)。这份文档是为上下文压缩而写的交接件 —— 压缩之后照它直接开工,不必重新 brainstorm、不必再问用户。
分类:bounded(要改的流程仓里已经有;换版面、功能不变)。按 brainstorming 技能的 bounded 路径, 不写 spec、不走 writing-plans;这份文档只是上下文的替身,不是流程意义上的实施计划。
一句话
把 input-supplement(S1 派的那张数据工单)的视图层换成
docs/ss02-act-05-new/ACT-WORK-05-数据工单-PN主数据创建.html 的版面,绑定面与功能一个不动。
用户原话:「功能应该是一样的」「注意页面样式要和这个模版html几乎一样」。
用户已定的三件事(不要再问)
| # | 问题 | 用户的选择 |
|---|---|---|
| 1 | 目标件是单颗 PN 三步向导,而 W05 天生两颗料 | 每颗料一条轨道(两条并列) |
| 2 | 目标件的新增类型面板只收参数名,而 W05 的硬/软约束必填 | 面板里每行扩成四格(参数名/说明/硬软约束/单位),独立的「核心参数字段」表去掉 |
| 3 | 目标件是一道总闸切整页,平台的闸按台账地址走 | 不动平台:每个步骤卡自带一道闸 |
第 1 条我提过风险(类型要在两条轨道各选一次、而它们必须相同,容易选出不一致再被判据拦下), 用户仍选了它 —— 按他的决定走,但加一道无脚本护栏(见下)。
第 2 条的连带代价(要在实现时留意):独立字段表去掉之后,已有类型的字段清单在件上看不到也改不了。
现有件那张表的第二个用途是「在库但当年参数没录全 → 给已有类型补一个字段」。
缓解:把新增类型那个 <details> 面板对已有类型也开放(标题写「类型库里没有?或要给这个类型补一个字段」),
同一个面板兼两用,版面不变而能力不丢。这一条是我在设计里补的,用户没有单独批,但它属于「功能一样」的承诺范围。
现场事实(已逐条核实,不必重查)
目标件
docs/ss02-act-05-new/ACT-WORK-05-数据工单-PN主数据创建.html —— 444 行 / 26KB。
同目录另有 SS02_ACT-WORK-05_差异评估_E04-I01架构版_V1.2.html 等,不在本次范围。
旧目标件在 docs/SS02-ACT-WORK-05-html/ACT-WORK-05-数据工单-01-芯片主数据创建.html(现有件是照它平移的)。
目标件结构:
.card-head(.badge「数据」·.kick/h1/.sub·.side里 tag/step/deadline)- 【触发原因】
.zone+.note(流程 / AI 预填情况) .jc-editgate带.gateprog进度条(.track/.fill/.pct=0 / 3 项)- 渲染态
.viewarea:.idcard两格(PN 名称 / PN 类型,大号 mono 值)+ 核心参数表.tbl-wrap - 编辑态
.editarea:.steps步骤轨道(.stepbox/.sdot/.scard/.fld)- ① PN 名称 ② PN 类型(select 首行
+新增类型)+.newtype面板 ③ 核心参数值.pvgrid瓷贴(2 列)
- ① PN 名称 ② PN 类型(select 首行
.flow底部说明 +.card-foot- 尾部
<script>驱动:类型库PN_TYPES→ 选类型即时加载参数框、新增类型面板、进度条
目标件的闸结构与平台逐字一样(.jc-editgate / .eg-open / .eg-cancel / .eg-save / .on)——
它本来就是照平台做的,只有「一道 vs 四道」这一处对不上。
现有件
activities/part-substitution-assessment/src/views/report.ts(953 行):
| 片段 | 行 | 绑定 |
|---|---|---|
PART_TABLE |
:298 | <tbody data-rows="mine:sub_eval.part" data-edit="parts.profile"> |
CHIP_TYPE_TABLE |
:398 | <table data-edit="parts.chip_type"> + <tbody data-rows="mine:parts.chip_type" data-edit="parts.chip_type">(两处都写,见下)+ addrow |
TYPE_PARAM_TABLE |
:447 | <table data-edit="parts.type_param"> + <tbody data-rows="mine:parts.type_param" …> + addrow |
PARAMETER_TABLE |
:496 | <tbody data-rows="mine:parts.parameter" data-edit="parts.parameter"> |
INPUT_SUPPLEMENT |
:515 | doc({ css: P08_CSS, alias: BIND_P08, badge:'数据', … }) |
四道 editGate + 两处 addrow(parts.chip_type / parts.type_param)。
只读态查类型人读名的写法(已验证可用):
<span data-rows="parts.chip_type" data-by="type_id=chip_type_id"><i data-slot="type_name" data-blank></i></span>
样式
activities/part-substitution-assessment/src/views/target-style.ts:
P08_CSS(:34,数据工单)· ACC1_CSS(:144,结论审核)· ACC2_CSS(:241,落账确认)。
本次只换 P08_CSS,另两段不动。
平台机制(会影响怎么写)
ViewContainer.tsx:548——documentElement.classList.toggle('editable', editable);editable只让闸现身,开不开由人按闸,开了给那张表的宿主挂.on(table.on td>.jc-vcell{display:none})。bodyOf是单个querySelector(ViewContainer.tsx:164-167)——一个地址只找得到一个宿主。 这是终审 C1 与 Task 7b 的教训来源,本次版面成立与否就卡在这一条(见风险)。addRow靠克隆tr:last-of-type,零行时返回 false(Task 7b 的旧账,已由种子行绕开)。- 件是零脚本沙箱;交互靠 CSS(
:has/<details>/:focus-within)与外层容器。
当前版本与闸的名单
packageVersion: '2.1.9'(manifest.ts:57)→ 本次改完升 2.2.0。- S1 卡的
gateLedgers(case-model.ts:592):['parts.chip_type', 'parts.type_param', 'parts.profile', 'parts.parameter']—— 四张,不要动。 - 现有自测:
__tests__/activity.test.ts共 70 条it(。
设计
版面
卡头(数据 badge · kick/h1/sub · 右侧 tag/step/deadline)
【触发原因】zone + note(流程 / AI 预填情况)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
原 PN 轨道 候选 PN 轨道
① 名称·在库·品牌·生命周期 ① 同左 ← 一道闸(parts.profile)
② 芯片类型 [下拉] ② 芯片类型 [下拉]
▸ 类型库里没有?在这里新建 / 补字段 ← 一道闸(chip_type + type_param)
类型名 + 逐行四格(参数名/说明/硬软约束/单位)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
③ 核心参数值:左右两组瓷贴,按料分 ← 一道闸(parts.parameter)
.flow 说明 + 页脚
两条并列轨道怎么出来的:<div class="tracks" data-rows="mine:sub_eval.part" data-edit="parts.profile">
里放 <section class="track">…</section>,.tracks{display:grid;grid-template-columns:1fr 1fr}。
data-rows 逐项复制内部结构,CSS 把它们排成两栏 —— 这是 A2 已验证的写法
(「<article data-rows> 包 <section class="cand">」逐颗料一张卡)。
行容器的坑:行展开按第一个同名闭合标签截行内容 —— 行模版里不许再出现同名标签。
用 <section> / <tbody> 这类行内不会重复的标签。
无脚本翻译
目标件(靠 <script>) |
平台等价物 |
|---|---|
| 选类型 → 即时加载参数输入框 | 保存即铺格(配方按类型的字段清单铺出参数行,已实现且走查验过) |
+新增类型 选中才显示面板 |
<details> 常驻折叠条(A2 方法论条同款,零脚本) |
.stepbox.done 点亮 |
data-class-of 投影 + 样式表判断(模版不许算、不许判) |
进度条 n / m 项 |
分母必须是真数:由配方算进 sub_eval.case 两列(如 fill_done/fill_total);算不出就只摆「还差 N 项」+ 二态条,不许编分母(界面不撒谎) |
body.editing 整页切 |
平台的 editable + 每卡 .on —— 用户选了「每步骤卡一道闸」 |
加的一道护栏(方案 1 的风险缓解)
两条轨道各选一次类型、而它们必须相同(distinct = 1 那条判据)。
基座本来就出 sub_eval_part_distinct_chip_type_id —— 把它投出来,
两处选得不一样时件上直接出红带点名,不必等提交才被判据拦。
用 data-class-of 投影 + 样式表出显隐(v-1 那档 display:none),模版不算不判。
⚠️ 要先验证再往下写的一条(这版面成立的前提)
步骤③ 的两组瓷贴要共用一个 data-edit="parts.parameter" 宿主
——因为 bodyOf 只找得到一个宿主(终审 C1 / Task 7b 的教训:同一地址挂两处,
querySelector 只命中第一个,后面那组的值一格都收不上去,而且不报错)。
宿主内部靠嵌套 data-rows + data-by 父键过滤按料分栏。
必须先钉住的是收值归行:cellsOf 按宿主内所有 [data-col] 取格子,rowOf 按行容器归行。
嵌套之后 rowOf 认的是内层瓷贴组还是外层?认错就会把两颗料的参数值混成一行。
做法:先写一条测试跑真实的 cellsOf/rowOf(或经 resolveRowKey 走一遍),
证明两颗料的瓷贴各归各行。
- 成立 → 按上面的版面写;
- 不成立 → 退回「③ 单独一块、内部分两栏」的形状(轨道只到 ②),并告诉用户这一处与目标件的差别。
顺带留意 data-by 的已知缺陷(终审 I3,已记 debt 未修):
行内没有该键时会落回外层同名字段 —— internal_pn 在多张表上撞名,分栏过滤要用真有值的键。
动的文件
| 文件 | 改什么 |
|---|---|
src/views/target-style.ts |
P08_CSS 整段换成从新目标件机械抽取的样式(数值不改;ACC1_CSS/ACC2_CSS 不动) |
src/views/report.ts |
重写 INPUT_SUPPLEMENT 与它的片段(PART_TABLE/CHIP_TYPE_TABLE/TYPE_PARAM_TABLE/PARAMETER_TABLE) |
src/manifest.ts |
packageVersion → 2.2.0 |
__tests__/activity.test.ts |
断言跟着新版面走(不许放松) |
不动:平台(ViewContainer / view-render / desk.ts)· 配方(case-model.ts)· gateLedgers · 另两张件。
必须留着的东西(动了就是回归)
<input class="jc-cell mono" data-col="type_id" placeholder="由系统生成" disabled>(report.ts:407一带) —— 这是终审 C1 的修复:没有它,人新建的类型会被「全表一致」认成既有行、把既有字典行改名并落进共享主数据。 新版面里这一格换了位置也必须带着走,并保留「由系统生成」那句占位 (2026-08-02 立的规矩:自增列不问人,但不能一声不吭地拿掉)。- 主键列必挂
data-col—— 它不是编辑面,是行的钥匙;不挂,服务端按「全表一致」猜,会把两行对到同一行上互相覆盖。 CHIP_TYPE_TABLE那个「data-edit外层<table>与内层<tbody>两处都写」的写法有原文注释解释原因 (bodyOf要同时收到「已有行」与「加一行」出来的行)—— 换版面时读那段注释再决定怎么摆。gateLedgers四张表与件上的可编辑面同源 —— 闸盯的表,件上必须给得出填的手段 (Task 7 那颗「按不下去的确认钮」就是这么来的)。
验收
现有断言继续绿,一条都不许放松:可改面只有哪几列 · 三份件用到的 class 必须都能在自己那段 CSS 里找到定义 ·
零脚本(not.toContain('<script'))· 主键挂 data-col · 编辑闸外壳那六个属性 · gateLedgers 与件同源。
新增:
- 两条轨道各出一颗料(
mine:sub_eval.part两行 → 两个.track); - 步骤③ 瓷贴按料归行正确(上面那条风险的钉子);
- 类型不一致时红带现身(
distinct > 1→data-class-of投影命中)。
每条新断言都要做变异验证(拿掉修复/改坏一处 → 测试必须真红;复原 → 绿),两段输出贴进报告。 本轮已连吃三次「测试测的是副本」「变异测试本身是空的」「夹具替被测系统干了活」的亏。
门禁:pnpm gates 以退出码验,不许接管道(cmd | tail 的退出码是 tail 的)。
最后必须做的两步:
pnpm activities:install装包,用 SQL 核库里那一行(版本号 / 视图 HTML)—— 装完看库,不看脚本的话;- 浏览器走一遍(起单 → 数据工单 → 新建类型 → 保存即铺格 → 填参数 → 提交)——
版面对不对只有真看一眼才算数;脚本 e2e 逮不到「一个图标 946 像素高」这类事。
跑试跑要用 AI 服务账号或用户授权的账号,跑完
pnpm --filter @app/api reset-runs清运行数据。
环境备忘(压缩后会用到)
- 开发后端
:8787、前端:5173;稳定版:8790目前是停着的(用户授权,大改期间不动它)。 - 起后端要先
set -a; . .stable/env; set +a,否则「缺 KEYCLOAK_URL…」起不来。 - 长跑的 dev 进程可能在跑几小时前的代码 —— 本轮踩过三次;
tsup --watch监视进程本身也可能已死,touch无效,要完整重启pnpm dev:api;杀进程要杀到--onSuccess拉起的那个 node(否则EADDRINUSE)。 - 查库:
docker exec jcai-postgres psql -U jcai -d jcai_wos -c "…"(.stable/env里的DATABASE_URL指向 5432, 而 docker 映的是 54329,直接进容器最省事)。 - 浏览器登录走 Keycloak 用户名密码;密码那一格我不能替用户输,要他自己登。
上下文:这条分支此刻的状态
feat/w05-rewrite,HEAD 45cec82,工作树干净,pnpm gates 退出码 0(2476 测)。
ACT-WORK-05 重写(Task 1–12 + 7b + 全分支终审 + 修复波 + 定向复审)已全部完成,
未合并、未推送 —— 合并方式等用户定(选项已摆给他:本地合进 mvp-foundation / 推送开 PR / 先放着)。
feat/deterministic-steps(第一份计划)已并在这条分支里,合它即合两者。
逐任务账本与全部裁定:.superpowers/sdd/2026-08-29-act-work-05-rewrite/progress.md(用户尚未决定删留)。
本次换版面是这之后的新活,与上面那条分支的收尾是两件事。