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/docs/superpowers/plans/2026-08-30-input-supplement-view-swap.md
T
xcsandClaude Opus 5 4076621e04 docs: 交接件 —— input-supplement 换版面的设计与前提(为上下文压缩而写)
用户已批准的 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
2026-08-30 19:32:15 +08:00

233 lines
14 KiB
Markdown
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.
# `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 列)
- `.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`);<br>**算不出就只摆「还差 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` · 另两张件。
---
## 必须留着的东西(动了就是回归)
1. **`<input class="jc-cell mono" data-col="type_id" placeholder="由系统生成" disabled>`**(`report.ts:407` 一带)
—— 这是**终审 C1 的修复**:没有它,人新建的类型会被「全表一致」认成既有行、**把既有字典行改名并落进共享主数据**。
新版面里这一格换了位置也**必须带着走**,并保留「由系统生成」那句占位
(2026-08-02 立的规矩:自增列不问人,但**不能一声不吭地拿掉**)。
2. **主键列必挂 `data-col`** —— 它不是编辑面,是**行的钥匙**;不挂,服务端按「全表一致」猜,会把两行对到同一行上互相覆盖。
3. `CHIP_TYPE_TABLE` 那个「`data-edit` 外层 `<table>` 与内层 `<tbody>` 两处都写」的写法有原文注释解释原因
(`bodyOf` 要同时收到「已有行」与「加一行」出来的行)—— 换版面时**读那段注释再决定怎么摆**。
4. `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` 的)。
**最后必须做的两步**:
1. `pnpm activities:install` 装包,**用 SQL 核库里那一行**(版本号 / 视图 HTML)—— 装完看库,不看脚本的话;
2. **浏览器走一遍**(起单 → 数据工单 → 新建类型 → 保存即铺格 → 填参数 → 提交)——
**版面对不对只有真看一眼才算数**;脚本 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`(用户尚未决定删留)。
**本次换版面是这之后的新活,与上面那条分支的收尾是两件事。**