diff --git a/activities/part-substitution-assessment/__tests__/activity.test.ts b/activities/part-substitution-assessment/__tests__/activity.test.ts index 3e184d4..62b95b2 100644 --- a/activities/part-substitution-assessment/__tests__/activity.test.ts +++ b/activities/part-substitution-assessment/__tests__/activity.test.ts @@ -727,14 +727,14 @@ describe('件① 评估输入补全', () => { }); it('**两条轨道:行源与写向同一元素,行模版是宿主直接子元素**(rowOf 认宿主直接子元素 —— 一条 lane = 一行;行模版里不许再有
,行展开按第一个同名闭合标签截行内容)', () => { - expect(html).toMatch(/
\s*
/); + expect(html).toMatch(/
\s*
/); const laneBody = /
([\s\S]*?)<\/section>/.exec(html)?.[1] ?? ''; expect(laneBody).not.toBe(''); expect(laneBody).not.toContain(' { - expect(html).toMatch(/
/); + expect(html).toMatch(/
/); const pvBody = /
([\s\S]*?)<\/section>/.exec(html)?.[1] ?? ''; expect(pvBody).not.toBe(''); expect(pvBody).not.toContain(' { expect(html).toContain('.pv .rowkey{display:none}'); }); + it('**data-rows 宿主的闭合标签不许出现在自己的行模版里** —— renderRows 的正则按宿主闭合标签非贪婪截取,撞上就把行模版截半、后一行嵌进前一行没闭合的标签里(2026-08-30 浏览器走查逮到:
被 lab 那格的
截断,档案卡串行)。判法:照 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(); + 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}'); diff --git a/activities/part-substitution-assessment/src/manifest.ts b/activities/part-substitution-assessment/src/manifest.ts index 5e1ae0a..546cbc9 100644 --- a/activities/part-substitution-assessment/src/manifest.ts +++ b/activities/part-substitution-assessment/src/manifest.ts @@ -54,7 +54,7 @@ export const manifest: ActivityManifest = { activityId: ACTIVITY_ID, name: 'ACT-WORK-05 · 差异评估', /* 重写不是改 —— 同版重装是 no-op(静默丢失,踩过) */ - packageVersion: '2.2.0', + packageVersion: '2.2.1', category: '需求分析与方案匹配', sdkVersion: '0.1.0-m5', checksum: 'dev-checksum-part-substitution-assessment', diff --git a/activities/part-substitution-assessment/src/views/report.ts b/activities/part-substitution-assessment/src/views/report.ts index 9cfdfa0..186f6fe 100644 --- a/activities/part-substitution-assessment/src/views/report.ts +++ b/activities/part-substitution-assessment/src/views/report.ts @@ -377,14 +377,17 @@ const gateBar = (): string => `
* 收值的授权面只认 `data-edit`,行从哪来只管这一屏摆几行摆谁的 —— 与旧 PART_TABLE 同一条道理)。 * 选 `sub_eval.part` 做行源是因为**角色(原/候选)与在库状态**只长在它身上;`internal_pn` * 挂 `data-col` 之后,保存时按它认作 `parts.profile` 的主键。**人不加行**(要建哪颗料是 - * 启动参数定死的事)。行模版是 `
`,里面不许再出现 `
`(行展开按第一个 - * 同名闭合标签截行内容);档案卡 `.idcard` 是纯投影(`data-slot`,编辑态照常摆着), + * 启动参数定死的事)。**宿主是 `
` 不是 `
`** —— `renderRows` 的正则按 + * **宿主自己的闭合标签**非贪婪截取行模版(`
` 宿主会在行模版里第一个 `
`(lab 那格) + * 处截断,后一行的展开被浏览器塞进前一行没闭合的标签里,档案卡当场串行 —— 浏览器走查 + * 逮到的真事故,A2 立的「行容器用行内不会再出现的标签」说的正是宿主);行模版里 + * 同理不许再出现 `
`/`
`;档案卡 `.idcard` 是纯投影(`data-slot`,编辑态照常摆着), * 字段行 `.fld` 里才是「只读孪生 + 输入件」二选一。 * 芯片类型选择器长在每条轨道里(`chip_type_id` 逐颗料各自一份,`distinct` 判据要求两颗 * 恰好同值);只读态用嵌套 `data-by` 从 `parts.chip_type` 整表查人读的 `type_name`, * 编辑态换 `optionSelect`(选项现读)。 */ -const LANES = `
+const LANES = `
@@ -428,7 +431,7 @@ const LANES = `
* 步骤③ 核心参数值 —— `parts.parameter`,一字段一格(行由 S1 配方按 * `sub_eval.part × parts.type_param` 铺,`prune:true` 清孤行,人不加行不删行)。 * **单块平铺**(不按轨道分两栏的机制原因见上面的大注释):瓷贴 `
` - * 直接是宿主 `.pvgrid` 的子元素 = collect 的一行;所属料号以小字摆在每格头上, + * 直接是宿主 `.pvgrid` 的子元素 = collect 的一行;宿主是 `
`(同 LANES: + * `
` 宿主会被瓷贴里的第一个 `
` 截断行模版);所属料号以小字摆在每格头上, * 配方按料连排,同一颗料的格子天然聚在一起。 * 主键钥匙(`internal_pn`/`param_name`)收进 `.rowkey`(display:none,BIND_ACC1_EDIT * 先立此法):不给人看,但必须真挂 `data-col` —— 漏了钥匙,保存的行凑不出主键, @@ -626,13 +630,13 @@ const PARAM_TILES = `
${editGate('parts.parameter', '逐格参数值核对 / 补齐,点「编辑」开格')} ${gapbar('parts_parameter', '必填')} -
+
${cell('internal_pn', 'mono')}${cell('param_name')}
${cell('param_value', 'mono')}
说明${cell('param_note')}
-
+
参数格还没铺出来 —— 先在上面把两颗料的芯片类型定下来并保存,系统会按类型自动铺出这里的参数格。