Archived
2026-08-31 用户一次点齐九件,逐条落: ① 两行编辑闸退役 → 卡右上角笔(开当前这一面的编辑)↔ 软盘(保存)+ 叉(放弃); 按钮就是平台的 data-edit-open/save/cancel 触发器,快照/取消机制原样,按面显隐全在样式表。 ② 保存一瞬间下拉变数字 → ui-kit mirrorTwins:下拉镜像**选项文案**不镜 value,并把 selected 属性拨到人选的那一项(守卫 CSS 与取消回显都认它)。2 测。 ③ 参数输入框占位提示 → 渲染器 twinInputs 认 data-ph 落成 placeholder(平台小扩面,1 测); 值格「规格书上的值 · 查不到留空」,说明格「补充说明 · 选填」。 ④ 参数说明空着不再摆「建议」→ 什么都不摆(连兜底破折号一起收)。 ⑤ 区序对调:芯片档案在前,比对基准在后。 ⑥ **新建芯片类型整条路移除**(只能选已有类型):抽屉与两张编辑表(种子行/Critical-1 修法/thead 回归网)退役,S1 配方 ②③ 自投影删除(八笔→六笔),gateLedgers 收窄到 profile+parameter,writes 同步,gate_reason 与指导书改口「只选不建」;样例改名 「候选缺库·建档定型」;e2e 案例 0 改走选既有 type_1(type_id=90 那套绕坑法随路退役)。 退役面的七条钉测按仓例 it.skip 留墓志铭(钉的是已移除的路径,不是放松断言)。 ⑦ 题头回浅蓝渐变(原目标件那条 120°),深色夜景只留验收两件。 ⑧ 对话区执行卡不再摆「参考信息」板块(basis 数据照旧随卡走,详情/归档仍有)。 ⑨ 比对基准降噪:字段收成丸(名+硬软徽+单位),说明藏进悬浮气泡指上即看; 类型说明一行截断、悬浮展开。 测:ui-kit 33(mirror 2 新)+ 渲染器 61(ph 1 新)+ 包内 104(38 steps 重排)+ 2525 全仓 四门绿;2.10.0 装库 SQL 六探针全中(hd-light/软盘/data-ph/零表格/无 chip_type 编辑面/ gateLedgers 两张);:8787 已重启载入 data-ph 渲染器。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LKMZDwMbyKzjw6Hembwvet
104 lines
5.8 KiB
TypeScript
104 lines
5.8 KiB
TypeScript
/**
|
|
* **多宿主收值 + 嵌套异地址排除**(2026-08-31,W05 芯片卡翻面逼出的平台扩面)。
|
|
*
|
|
* 版面要求「参数值印在每张芯片卡的**背面**、就地可改」:参数表的行天然分居两张卡,
|
|
* 一个宿主装不下 —— `hostsOf` 把同一地址的全部宿主都数进来,每个宿主各自归行。
|
|
*
|
|
* 更要紧的是**嵌套异地址排除**:卡背的参数宿主(`data-edit="parts.parameter"`)住在
|
|
* 芯片卡宿主(`data-edit="parts.profile"`)的行里 —— 外层收值若把里层宿主的格子也
|
|
* 收走,参数值就会被当成主数据的列并进主数据的行(`view-container-collect-nested.test.ts`
|
|
* 钉过的静默丢数据,换一副面孔回来)。规则:**格子只归它最近的 `data-edit` 祖先**。
|
|
* 嵌套的 `data-rows` 不带 `data-edit` 时行为原样(照旧并行 —— 那两条钉测不动)。
|
|
*/
|
|
// @vitest-environment jsdom
|
|
import { describe, expect, it } from 'vitest';
|
|
import { collect, mirrorTwins, setOpenIn } from '../src/ViewContainer.tsx';
|
|
|
|
/** 两张芯片卡:正面是主数据格(profile),背面各住一个参数宿主(parameter) */
|
|
const FLIP_CARDS =
|
|
'<article data-edit="parts.profile">' +
|
|
'<section class="dossier">' +
|
|
'<div class="front"><input data-col="internal_pn" value="LM2596S-5.0"/><input data-col="brand_name" value="TI"/></div>' +
|
|
'<div class="back"><section class="pback" data-edit="parts.parameter">' +
|
|
'<div class="ptile"><input data-col="internal_pn" value="LM2596S-5.0"/><input data-col="param_name" value="输出电压"/><input data-col="param_value" value="5.0"/></div>' +
|
|
'<div class="ptile"><input data-col="internal_pn" value="LM2596S-5.0"/><input data-col="param_name" value="输出电流"/><input data-col="param_value" value="3"/></div>' +
|
|
'</section></div>' +
|
|
'</section>' +
|
|
'<section class="dossier">' +
|
|
'<div class="front"><input data-col="internal_pn" value="XL2596S-5.0"/><input data-col="brand_name" value="XLSEMI"/></div>' +
|
|
'<div class="back"><section class="pback" data-edit="parts.parameter">' +
|
|
'<div class="ptile"><input data-col="internal_pn" value="XL2596S-5.0"/><input data-col="param_name" value="输出电压"/><input data-col="param_value" value="5.0"/></div>' +
|
|
'<div class="ptile"><input data-col="internal_pn" value="XL2596S-5.0"/><input data-col="param_name" value="输出电流"/><input data-col="param_value" value="2.5"/></div>' +
|
|
'</section></div>' +
|
|
'</section>' +
|
|
'</article>' +
|
|
'<div class="jc-editgate" data-edit-for="parts.parameter"></div>';
|
|
|
|
function docOf(html: string): Document {
|
|
const doc = document.implementation.createHTMLDocument('');
|
|
doc.body.innerHTML = html;
|
|
return doc;
|
|
}
|
|
|
|
describe('多宿主 collect():同一地址的宿主都数进来,格子只归最近的 data-edit 祖先', () => {
|
|
it('parts.parameter 分居两张卡背的两个宿主 —— 4 个瓷贴收到 4 行,主键各自带对', () => {
|
|
const got = collect(docOf(FLIP_CARDS), 'parts.parameter');
|
|
expect(got).toHaveLength(4);
|
|
const xl = got.filter((r) => r['internal_pn'] === 'XL2596S-5.0');
|
|
expect(xl).toHaveLength(2);
|
|
expect(new Map(xl.map((r) => [r['param_name'], r['param_value']])).get('输出电流')).toBe('2.5');
|
|
});
|
|
|
|
it('parts.profile 收值**不含**卡背参数宿主的格子 —— 两行主数据,一列参数都不许混进来', () => {
|
|
const got = collect(docOf(FLIP_CARDS), 'parts.profile');
|
|
expect(got).toHaveLength(2);
|
|
for (const row of got) {
|
|
expect(row['brand_name']).toBeDefined();
|
|
/* 静默丢数据的那副面孔:param_value 若出现在主数据行里,就是里层宿主被外层吞了 */
|
|
expect(row['param_value']).toBeUndefined();
|
|
expect(row['param_name']).toBeUndefined();
|
|
}
|
|
});
|
|
|
|
it('setOpenIn:一把闸开合同一地址的**全部**宿主(非表格容器,.on 落在宿主自身)', () => {
|
|
const doc = docOf(FLIP_CARDS);
|
|
setOpenIn(doc, 'parts.parameter', true);
|
|
const hosts = Array.from(doc.querySelectorAll('.pback'));
|
|
expect(hosts).toHaveLength(2);
|
|
expect(hosts.every((h) => h.classList.contains('on'))).toBe(true);
|
|
expect(doc.querySelector('[data-edit-for="parts.parameter"]')?.classList.contains('on')).toBe(true);
|
|
/* 外层 profile 宿主不许被顺手点亮 —— 两把闸各管各的 */
|
|
expect(doc.querySelector('[data-edit="parts.profile"]')?.classList.contains('on')).toBe(false);
|
|
setOpenIn(doc, 'parts.parameter', false);
|
|
expect(hosts.every((h) => !h.classList.contains('on'))).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('mirrorTwins:下拉镜像的是选项文案,不是 value(2026-08-31「保存一瞬间变数字」)', () => {
|
|
const SEL =
|
|
'<div data-edit="parts.profile"><div class="row">' +
|
|
'<span class="jc-vcell tsel">旧名</span>' +
|
|
'<select class="jc-cell" data-col="chip_type_id">' +
|
|
'<option value=""></option><option value="1">DC-DC 降压稳压器</option><option value="2">LDO 线性稳压器</option>' +
|
|
'</select>' +
|
|
'</div></div>';
|
|
|
|
it('镜进孪生件的是「DC-DC 降压稳压器」,不是「1」;selected 属性拨到人选的那一项(守卫 CSS 认它)', () => {
|
|
const doc = document.implementation.createHTMLDocument('');
|
|
doc.body.innerHTML = SEL;
|
|
const sel = doc.querySelector('select') as HTMLSelectElement;
|
|
sel.value = '1';
|
|
mirrorTwins(doc, 'parts.profile');
|
|
expect(doc.querySelector('.tsel')?.textContent).toBe('DC-DC 降压稳压器');
|
|
expect(doc.querySelector('option[value="1"]')?.hasAttribute('selected')).toBe(true);
|
|
expect(doc.querySelector('option[value="2"]')?.hasAttribute('selected')).toBe(false);
|
|
});
|
|
|
|
it('没选(空占位)= 没答:孪生件一个字不动', () => {
|
|
const doc = document.implementation.createHTMLDocument('');
|
|
doc.body.innerHTML = SEL;
|
|
mirrorTwins(doc, 'parts.profile');
|
|
expect(doc.querySelector('.tsel')?.textContent).toBe('旧名');
|
|
});
|
|
});
|