Archived
revert(w05): 数据工单退回换版面之前的旧版面(2.3.0),新版面存在 feat/w05-view-swap
用户实测新版面「感觉有点问题」,先退回稳定的旧版面,新版面原样留在分支上随时可切。
退法不是 reset —— 历史与素材都留着:report.ts / target-style.ts / activity.test.ts
三个文件逐字节恢复到 45cec82 的样子(已 diff 核对为零差异),平台侧的探针测试
(view-container-collect-div-rows / -nested / view-render-nested-editable)、目标件 html、
交接件文档全部留在主支 —— 它们钉的是平台行为与素材,不随这次退回作废。
版本号 2.2.2 -> 2.3.0 而不是退回 2.1.9:store.manifest 不传版本时按 installedAt 取
**最近安装**的那一条(不是版本号最大的),库里 2.1.9 那行的 installedAt 比 2.2.2 早,
同版重装又是 no-op —— 只有拿一个新号把旧版面装进去,注册表才真的换回旧版面。
CLAUDE.md 那条战果记录改口标注「已退回」并指向分支,原文留着当索引。
pnpm gates 退出码 0(2487 测;比换版面那版少的 10 条正是随 UI 一起退掉的新版面钉子)。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LKMZDwMbyKzjw6Hembwvet
This commit is contained in:
@@ -527,11 +527,10 @@ describe('报告模版:编辑面与只读面各就各位', () => {
|
||||
});
|
||||
|
||||
/*
|
||||
* 件① 评估输入补全(2026-08-29 Task 7/7b;**2026-08-30 照新目标件换版面**):S1 的配方
|
||||
* 缺什么就发一张数据工单,`view: 'input-supplement'` 指向它。新版面 —— 两条并列轨道
|
||||
* (每颗料一条:档案卡 + 主数据 + 类型选择)/ `<details>` 新增类型面板(chip_type +
|
||||
* type_param 两张表,即「每行四格」的核心参数字段清单)/ 核心参数值瓷贴(单块平铺);
|
||||
* 顶部一条红带摆配方算好的 `gate_reason`。台账绑定面与换版面前一个不差。
|
||||
* 件① 评估输入补全(2026-08-29,Task 7;Task 7b 补②a 块):S1 的配方缺什么就发一张数据工单,
|
||||
* `view: 'input-supplement'` 指向它。四块竖排——要评估什么(两颗料的存在性 + 主数据)/
|
||||
* 芯片类型(选型 + 新建类型)/ 核心参数字段清单(新建类型时要填)/ 参数值(逐条实测/规格值);
|
||||
* 顶部一条红带摆配方算好的 `gate_reason`。
|
||||
* 复用文件顶部已有的 `viewHtml` 短写(与 brief 草稿里的 `viewOf` 同一件事,不重复定义一个)。
|
||||
*/
|
||||
describe('件① 评估输入补全', () => {
|
||||
@@ -621,11 +620,9 @@ describe('件① 评估输入补全', () => {
|
||||
expect(html).toContain('data-col="param_name"');
|
||||
});
|
||||
|
||||
it('可改的四张表各有一道编辑闸 —— 查的是闸([data-edit-for] + 开钮),不是宿主:2026-08-30 换版面第一版恰好漏掉 profile 的闸,宿主在而闸不在,轨道打不开编辑,XL 的必填永远补不上(Task 7 那颗「按不下去的确认钮」同款),旧断言只查宿主没逮到', () => {
|
||||
it('可改的四张表各有一道编辑闸', () => {
|
||||
for (const address of ['parts.profile', 'parts.chip_type', 'parts.type_param', 'parts.parameter']) {
|
||||
expect(html).toContain(`data-edit="${address}"`);
|
||||
expect(html).toContain(`data-edit-for="${address}"`);
|
||||
expect(html).toContain(`data-edit-open="${address}"`);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -702,108 +699,20 @@ describe('件① 评估输入补全', () => {
|
||||
});
|
||||
|
||||
/*
|
||||
* 2026-08-29 评审 Important:BIND_COMMON 的序号计数器规则原来只认 `.tbl-wrap`,而工单件的表
|
||||
* 走平台的 `.jc-tbl-wrap` —— 两个 class 对不上,计数器永不触发,「#」列逐行空白。
|
||||
* 2026-08-30 换版面后这张件只剩面板里两张表(chip_type / type_param),包装是
|
||||
* `jc-tbl-wrap tbl-wrap` 双类(平台钩子 + 目标件的边框圆角);轨道与瓷贴没有 # 列,
|
||||
* 不走计数器。钉死:五条计数器规则还在,且两张表的双类包装恰好两处。
|
||||
* 2026-08-29 评审 Important:BIND_COMMON 的序号计数器规则原来只认 `.tbl-wrap`
|
||||
* (继承自已删除的旧 P08_MASTER_CREATE,同一个 wrapper class,同一个坑),
|
||||
* 而这张件的三张表全用平台的 `.jc-tbl-wrap` —— 两个 class 对不上,计数器永不触发,
|
||||
* 只读态与编辑态下「#」列逐行都是空白。钉死 `.jc-tbl-wrap` 现在也接了这五条规则,
|
||||
* 且这张件确实只用 `.jc-tbl-wrap`(没有表在用没打这条补丁就会数不出来的 `.tbl-wrap`)。
|
||||
*/
|
||||
it('面板两张表的序号列真的会数:计数器规则在,双类包装恰两处', () => {
|
||||
it('四张表的序号列真的会数:.jc-tbl-wrap 也接了 CSS 计数器(不再只认 .tbl-wrap)', () => {
|
||||
expect(html).toMatch(/\.jc-tbl-wrap\s+table\s*,\s*\.tbl-wrap\s+table\s*\{\s*counter-reset:\s*rn;?\s*\}/);
|
||||
expect(html).toMatch(/\.jc-tbl-wrap\s+table\s+td\.rn\s*,\s*\.tbl-wrap\s+table\s+td\.rn\s*\{\s*counter-increment:\s*rn;?\s*\}/);
|
||||
expect(html).toMatch(/\.jc-tbl-wrap\s+table\s+td\.rn\s+\.jc-rn-num::before\s*,\s*\.tbl-wrap\s+table\s+td\.rn\s+\.jc-rn-num::before\s*\{\s*content:\s*counter\(rn\);?\s*\}/);
|
||||
const wrapCount = html.match(/class="jc-tbl-wrap tbl-wrap"/g)?.length ?? 0;
|
||||
expect(wrapCount).toBe(2);
|
||||
// 不许再有单类的表包装 —— 单 .jc-tbl-wrap 缺目标件的边框,单 .tbl-wrap 缺平台的 :has 加行钩子
|
||||
expect(html).not.toMatch(/class="jc-tbl-wrap"/);
|
||||
expect(html).not.toMatch(/class="tbl-wrap"/);
|
||||
});
|
||||
|
||||
/* ==================== 2026-08-30 换版面(照 docs/ss02-act-05-new 新目标件)专属的钉子 ==================== */
|
||||
|
||||
it('**每个台账地址恰一个收值宿主**(chip_type/type_param 的两处是「外层 table + 内层 tbody」同宿主写法):bodyOf 是单 querySelector,同一地址挂两个各自独立的宿主,第二个的值一格都收不上去且不报错(终审 C1 / Task 7b 的族坑)', () => {
|
||||
const countOf = (addr: string): number => (html.match(new RegExp(`data-edit="${addr.replace('.', '\\.')}"`, 'g')) ?? []).length;
|
||||
expect(countOf('parts.profile')).toBe(1);
|
||||
expect(countOf('parts.parameter')).toBe(1);
|
||||
expect(countOf('parts.chip_type')).toBe(2);
|
||||
expect(countOf('parts.type_param')).toBe(2);
|
||||
});
|
||||
|
||||
it('**两条轨道:行源与写向同一元素,行模版是宿主直接子元素**(rowOf 认宿主直接子元素 —— 一条 lane = 一行;行模版里不许再有 <section>,行展开按第一个同名闭合标签截行内容)', () => {
|
||||
expect(html).toMatch(/<article class="lanes" data-rows="mine:sub_eval\.part" data-edit="parts\.profile">\s*<section class="lane">/);
|
||||
const laneBody = /<section class="lane">([\s\S]*?)<\/section>/.exec(html)?.[1] ?? '';
|
||||
expect(laneBody).not.toBe('');
|
||||
expect(laneBody).not.toContain('<section');
|
||||
});
|
||||
|
||||
it('**参数瓷贴单块平铺,瓷贴是宿主直接子元素** —— 按料嵌一层分栏会把一颗料的所有参数格并成一条记录(ui-kit view-container-collect-div-rows.test.ts 用真实 renderView+collect 钉死的「必然归并」)', () => {
|
||||
expect(html).toMatch(/<article class="pvgrid" data-rows="mine:parts\.parameter" data-edit="parts\.parameter"><section class="pv">/);
|
||||
const pvBody = /<section class="pv">([\s\S]*?)<\/section>/.exec(html)?.[1] ?? '';
|
||||
expect(pvBody).not.toBe('');
|
||||
expect(pvBody).not.toContain('<section');
|
||||
/* 瓷贴的主键钥匙(internal_pn / param_name)收在 .rowkey 里 —— 藏起来但必须真挂 data-col */
|
||||
expect(pvBody).toContain('class="rowkey"');
|
||||
expect(pvBody).toContain('data-col="internal_pn"');
|
||||
expect(pvBody).toContain('data-col="param_name"');
|
||||
expect(html).toContain('.pv .rowkey{display:none}');
|
||||
});
|
||||
|
||||
it('**data-rows 宿主的闭合标签不许出现在自己的行模版里** —— renderRows 的正则按宿主闭合标签非贪婪截取,撞上就把行模版截半、后一行嵌进前一行没闭合的标签里(2026-08-30 浏览器走查逮到:<div class="lanes"> 被 lab 那格的 </div> 截断,档案卡串行)。判法:照 ROWS 正则同款截取,截出来的行模版必须**标签配平**(截断必然留下没闭合的标签 —— 直接查「不含闭合标签」是空话,非贪婪截取本来就停在闭合标签之前)', () => {
|
||||
const hosts = [...html.matchAll(/<([a-zA-Z][\w-]*)\b[^>]*\bdata-rows="[^"]+"[^>]*>([\s\S]*?)<\/\1>/g)];
|
||||
expect(hosts.length).toBeGreaterThanOrEqual(2);
|
||||
const VOID = new Set(['input', 'br', 'img', 'hr', 'meta', 'link']);
|
||||
for (const m of hosts) {
|
||||
const inner = m[2] ?? '';
|
||||
const opens = new Map<string, number>();
|
||||
for (const tm of inner.matchAll(/<(\/?)([a-zA-Z][\w-]*)\b/g)) {
|
||||
const tag = (tm[2] ?? '').toLowerCase();
|
||||
if (VOID.has(tag)) continue;
|
||||
opens.set(tag, (opens.get(tag) ?? 0) + (tm[1] === '/' ? -1 : 1));
|
||||
}
|
||||
for (const [tag, n] of opens) {
|
||||
expect(n, `data-rows 宿主 <${m[1]}> 截出的行模版里 <${tag}> 开 ${n} 个没闭合 —— 宿主的闭合标签把模版截半了`).toBe(0);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('**类型不一致护栏**:distinct 是基座数,红带只在 v-2 档现身,模版不算不判', () => {
|
||||
expect(html).toMatch(/class="jc-typewarn" data-class-of="sub_eval_part_distinct_chip_type_id"/);
|
||||
expect(html).toContain('.jc-typewarn{display:none}');
|
||||
expect(html).toContain('.jc-typewarn.v-2{display:flex');
|
||||
});
|
||||
|
||||
it('**步骤圆点只按基座数点亮,投影挂在行外的包裹层** —— 行内 data-class-of 只认行作用域,作用域级读数在行内投不出(实测圆点永远不亮);圆点自己不许再挂 data-class-of(挂了也是死属性)', () => {
|
||||
expect(html).toContain('class="pj pj-profile" data-class-of="parts_profile_missing"');
|
||||
expect(html).toContain('class="pj pj-type" data-class-of="sub_eval_part_distinct_chip_type_id"');
|
||||
expect(html).toContain('class="pj pj-param" data-class-of="parts_parameter_missing"');
|
||||
expect(html).toContain('.pj-profile.v-0 .sdot.sd-1,.pj-type.v-1 .sdot.sd-2,.pj-param.v-0 .sdot.sd-3{background:var(--data)');
|
||||
expect(html).not.toMatch(/class="sdot[^"]*" data-class-of=/);
|
||||
});
|
||||
|
||||
it('**类型查名有诚实守卫**(data-by 行缺键落回外层同名字段,终审 I3):行里没真选上类型(selectCurrent 没写下 option[selected]),查名 pill 与字段行的名字都不摆', () => {
|
||||
expect(html).toContain('.lane:not(:has(select[data-col="chip_type_id"] option[selected])) .idcard .tpill{display:none}');
|
||||
expect(html).toContain('.lane:not(:has(select[data-col="chip_type_id"] option[selected])) .tywrap span{display:none}');
|
||||
expect(html).toContain('class="jc-vcell tywrap"');
|
||||
});
|
||||
|
||||
it('**新增类型面板是 <details>,且绑定层把抽取样式的 display:none 让开** —— 少了这条让位规则,整个面板(含两道闸与两张表)永远不可见', () => {
|
||||
expect(html).toContain('<details class="newtype">');
|
||||
expect(html).toContain('details.newtype{display:block');
|
||||
});
|
||||
|
||||
it('**目标件里靠脚本驱动的两样,搬过来时如实退掉**:进度条 gateprog 的分母不是基座现有的数(编一个就是界面撒谎);viewarea/editarea 双区靠 body.editing 切换,沙箱零脚本切不动 —— 抽取的 CSS 里留着它们的规则,但标记一处都不许用', () => {
|
||||
const body = html.slice(html.indexOf('</style>'));
|
||||
expect(body).not.toContain('gateprog');
|
||||
expect(body).not.toContain('class="viewarea"');
|
||||
expect(body).not.toContain('class="editarea"');
|
||||
/* .editarea{display:none} 还在 CSS 里 —— 谁把内容包进它,那块就永远消失 */
|
||||
expect(html).toContain('.editarea{display:none}');
|
||||
});
|
||||
|
||||
it('**保存即铺格之前的空态**:pvnull 按 parts_parameter_rows 的 v-0 档现身(零行才摆提示,有行不摆 —— 界面不撒谎)', () => {
|
||||
expect(html).toContain('class="pv-empty pvnull" data-class-of="parts_parameter_rows"');
|
||||
expect(html).toContain('.pvnull{display:none}');
|
||||
expect(html).toContain('.pv-empty.pvnull.v-0{display:block}');
|
||||
// 这张件的四张表都走 .jc-tbl-wrap(没有 .tbl-wrap)—— 补丁真的接在会用到的类上(Task 7b 新增 parts.chip_type 这一张,3→4)
|
||||
expect(html).not.toContain('class="tbl-wrap"');
|
||||
const jcTblWrapCount = html.match(/class="jc-tbl-wrap"/g)?.length ?? 0;
|
||||
expect(jcTblWrapCount).toBe(4);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user