Archived
feat(w05): 比对基准合一卡 + prune:'live' —— 类型与字段跟手,只显当前那一种
2026-08-31 用户第二轮:「芯片类型列表还是有问题…和核心参数字段不能合并成一个卡片吗… 两个芯片都选一样的就应该只显示一种,现在只会跟着变多不会跟着变少」+ 「卡片下面那个容器黑色和页面背景不搭」。 ① 比对基准卡(类型 + 字段合一,只读、跟手):不再列 mine: 草稿镜像(镜像里积着改选前的 旧类型 —— 撤行只在确认那一拍跑,F3 不许在人编辑时静默删行),按案卷锚 (sub_eval.case.chip_type_id,配方每拍现算)嵌套查字典:卡上改选、按保存,quiet 拍 project 照跑,这张卡当场换脸 —— 两颗料同类型时恰好只有那一种;没人选时空态指路。 新建类型收进 details 抽屉(零脚本),两张编辑表原样在抽屉里(种子行/加行机制不动)。 ② 契约新增 prune:'live'(quiet 拍也撤):只给**人不会在件上加行**的表用 —— F3 防的是 「人刚加的行被撤」,人加不了行的表没有这个风险,而「改了类型,旧类型的参数行还摆在 屏上」是另一种撒谎。W05 参数骨架 ⑤ 改 'live':改选类型,参数行跟手换。 static-audit 的 prune×humanWrites 审计盖住 'live';规范 §4.6 纪律 5 补这条反面特例; 两档都跳过已落地的行并出声(skipLanded)。 ③ 板底改浅色蓝图:深色容器与纸面色阶断裂(用户点名),换强调色极浅晕染 + 淡格线, 走线与信号点用强调色 —— 电路语汇留着,整页只剩 hero 一处深色。 测:契约 'live' 解析 + runner quiet-live 对齐(变异验证)+ 基准卡锚(变异验证)+ steps ⑤ 钉 'live';108 包内 + 全仓四门绿;2.8.1 装库 SQL 核过;:8787 已跑新构建 (watcher 又断,按应急程序手起 node dist/main.js)。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LKMZDwMbyKzjw6Hembwvet
This commit is contained in:
@@ -581,6 +581,31 @@ describe('件① 评估输入补全', () => {
|
||||
expect(html).not.toContain(':has(+ select.jc-cell:not(:has(');
|
||||
});
|
||||
|
||||
/*
|
||||
* 2026-08-31 用户第二轮:「芯片类型列表和核心参数字段,不能合并成一个卡片吗…两个芯片都
|
||||
* 选一样的,就应该只显示一种」。合并 = 比对基准卡(类型名 + 字段清单一张只读卡);
|
||||
* 「只显示一种、跟手」= 不列 mine: 草稿镜像(会积旧选择),按案卷锚(case.chip_type_id,
|
||||
* 配方每拍现算)嵌套查字典 —— quiet 拍 project 照跑,保存即换脸。
|
||||
* 新建类型收进 details 抽屉(零脚本),两张编辑表原样在抽屉里(种子行/加行机制不动)。
|
||||
*/
|
||||
it('比对基准卡:case 锚嵌套查字典,类型与字段合一、全只读;编辑表收进抽屉', () => {
|
||||
expect(html).toContain('data-rows="mine:sub_eval.case"');
|
||||
const basis = /<article class="basis"[\s\S]*?<\/article>/.exec(html)?.[0] ?? '';
|
||||
expect(basis).not.toBe('');
|
||||
expect(basis).toContain('data-rows="parts.chip_type" data-by="type_id=chip_type_id"');
|
||||
expect(basis).toContain('data-rows="parts.type_param" data-by="type_id=chip_type_id"');
|
||||
/* 全只读:选类型在档案卡,建类型在抽屉 —— 基准卡上一个编辑面都不许有 */
|
||||
expect(basis).not.toContain('data-col');
|
||||
expect(basis).not.toContain('data-edit');
|
||||
/* 抽屉存在,且两张编辑表都住在里面 */
|
||||
const labAt = html.indexOf('<details class="lab">');
|
||||
const labEnd = html.indexOf('</details>');
|
||||
expect(labAt).toBeGreaterThanOrEqual(0);
|
||||
expect(html.indexOf('<table data-edit="parts.chip_type">')).toBeGreaterThan(labAt);
|
||||
expect(html.indexOf('<table data-edit="parts.type_param">')).toBeGreaterThan(labAt);
|
||||
expect(labEnd).toBeGreaterThan(html.indexOf('<table data-edit="parts.type_param">'));
|
||||
});
|
||||
|
||||
it('三级占位:必填红 / 建议橘 —— 空格子直说要不要填(档案卡与参数值表两处)', () => {
|
||||
expect(html).toContain('.fcell.req .jc-vcell:empty::after{content:"必填"');
|
||||
expect(html).toContain('.fcell.sug .jc-vcell:empty::after{content:"建议"');
|
||||
@@ -744,14 +769,14 @@ describe('件① 评估输入补全', () => {
|
||||
* 只读态与编辑态下「#」列逐行都是空白。钉死 `.jc-tbl-wrap` 现在也接了这五条规则,
|
||||
* 且这张件确实只用 `.jc-tbl-wrap`(没有表在用没打这条补丁就会数不出来的 `.tbl-wrap`)。
|
||||
*/
|
||||
it('三张表的序号列真的会数:.jc-tbl-wrap 也接了 CSS 计数器(不再只认 .tbl-wrap)', () => {
|
||||
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*\}/);
|
||||
// 这张件的三张表都走 .jc-tbl-wrap(没有 .tbl-wrap)—— 2026-08-31 块① 换成档案卡(不是表),4→3
|
||||
// 四张:比对基准卡的字段表 + 抽屉里两张编辑表 + 参数值表(2026-08-31 类型/字段并成基准卡后的账)
|
||||
expect(html).not.toContain('class="tbl-wrap"');
|
||||
const jcTblWrapCount = html.match(/class="jc-tbl-wrap"/g)?.length ?? 0;
|
||||
expect(jcTblWrapCount).toBe(3);
|
||||
expect(jcTblWrapCount).toBe(4);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -214,7 +214,8 @@ describe('S1 配方', () => {
|
||||
|
||||
it('参数骨架:两颗料都铺、值回填现值 —— 「在库但当年参数没录全」也要被拦住', () => {
|
||||
const params = acts[4];
|
||||
expect(params?.kind === 'project' && params.prune).toBe(true);
|
||||
/* 'live':人加不了行的表,quiet 拍也撤 —— 改类型后旧参数行跟手消失(2026-08-31 用户点名「只会变多不会变少」) */
|
||||
expect(params?.kind === 'project' && params.prune).toBe('live');
|
||||
const from = params?.kind === 'project' ? params.from : undefined;
|
||||
/* 外层是本单两颗料,里层是该类型的字段清单 —— 人没挑类型时 where 一行不命中,什么也不铺 */
|
||||
expect(from).toMatchObject({ each: 'mine:sub_eval.part', then: { each: 'parts.type_param' } });
|
||||
|
||||
@@ -492,7 +492,13 @@ export const ASSESSMENT_STEPS = [
|
||||
{
|
||||
kind: 'project' as const,
|
||||
into: 'parts.parameter',
|
||||
prune: true,
|
||||
/*
|
||||
* **`prune: 'live'`(2026-08-31 用户:「切换料号类型时…只会跟着变多,不会跟着变少」)**:
|
||||
* 参数骨架的行集全由这一笔按「料 × 类型字段」铺,人在件上**加不了行**(没有加行钮),
|
||||
* F3 那条「quiet 拍不撤行」防的风险在这张表上不存在 —— 人改了类型、按保存,旧类型的
|
||||
* 参数行当场撤掉,屏上跟手。已落地的行照旧跳过并出声(skipLanded)。
|
||||
*/
|
||||
prune: 'live' as const,
|
||||
from: {
|
||||
each: 'mine:sub_eval.part',
|
||||
then: { each: 'parts.type_param', where: { type_id: { outer: 'chip_type_id' } } },
|
||||
|
||||
@@ -54,7 +54,7 @@ export const manifest: ActivityManifest = {
|
||||
activityId: ACTIVITY_ID,
|
||||
name: 'ACT-WORK-05 · 差异评估',
|
||||
/* 重写不是改 —— 同版重装是 no-op(静默丢失,踩过) */
|
||||
packageVersion: '2.7.0',
|
||||
packageVersion: '2.8.1',
|
||||
category: '需求分析与方案匹配',
|
||||
sdkVersion: '0.1.0-m5',
|
||||
checksum: 'dev-checksum-part-substitution-assessment',
|
||||
|
||||
@@ -204,6 +204,43 @@ const DOSSIERS = `<section class="board"><article class="dossiers" data-rows="mi
|
||||
</div>
|
||||
</section></article></section>`;
|
||||
|
||||
/**
|
||||
* 比对基准卡 —— 芯片类型与它的核心参数字段**合成一张只读卡**(2026-08-31 用户:
|
||||
* 「芯片类型列表和核心参数字段,不能合并成一个卡片吗…两个芯片都选一样的,就应该只显示一种」)。
|
||||
*
|
||||
* **显示永远跟手、永远只有当前那一种**:不列 `mine:parts.chip_type` 草稿(镜像里会积着
|
||||
* 改选前的旧类型 —— 撤行只在确认工单那一拍跑,F3 不许在人编辑时静默删行),而是按**案卷锚**
|
||||
* (`sub_eval.case.chip_type_id`,配方 ⑥ 每拍从原 PN 的选择现算)嵌套查字典:人卡上改选、
|
||||
* 按保存,quiet 拍照样跑 project,锚跟着动,这张卡当场换脸 —— 两颗料选同一类型时,这里
|
||||
* 恰好就是那一种;还没人选类型时零行,空态一句话指路。
|
||||
*
|
||||
* 全只读(一个 data-col 都没有)—— 选类型在档案卡上,建类型在下面的工作抽屉里。
|
||||
* 嵌套三层:case(恰一行)→ chip_type 按锚查名 → type_param 按锚列字段;
|
||||
* 宿主标签各不与行模版里的标签撞(article / span / tbody)。
|
||||
*/
|
||||
const BASIS_CARD = `<article class="basis" data-rows="mine:${D}.case"><section class="basis-in">
|
||||
<header class="basis-hd">
|
||||
<span class="basis-lb">比对基准</span>
|
||||
<span class="basis-chip" data-rows="parts.chip_type" data-by="type_id=chip_type_id"><b data-slot="type_name" data-blank></b><i class="basis-desc" data-slot="description" data-blank></i></span>
|
||||
</header>
|
||||
<div class="jc-tbl-wrap"><table>
|
||||
<thead><tr>
|
||||
<th style="width:38px">#</th>
|
||||
<th data-h="参数名">参数名</th>
|
||||
<th data-h="参数说明">参数说明</th>
|
||||
<th data-h="约束类型">约束(硬/软)</th>
|
||||
<th data-h="参考单位">参考单位</th>
|
||||
</tr></thead>
|
||||
<tbody data-rows="parts.type_param" data-by="type_id=chip_type_id"><tr>
|
||||
<td class="rn"><span class="jc-rn-num"></span></td>
|
||||
<td class="cust" data-slot="param_name" data-blank></td>
|
||||
<td class="desc" data-slot="param_desc" data-blank></td>
|
||||
<td><span class="ct" data-class-of="constraint_type"></span></td>
|
||||
<td data-slot="param_unit" data-blank></td>
|
||||
</tr></tbody>
|
||||
</table></div>
|
||||
</section></article>`;
|
||||
|
||||
/**
|
||||
* 块②a 新建芯片类型 —— `parts.chip_type`。类型下拉(块①)里没有合适的,人在这里现造一个。
|
||||
* `type_id` 是自增主键 —— **人不填它**,自增列不问人;已有行只读态摆 `ro()`。
|
||||
@@ -352,16 +389,19 @@ export const INPUT_SUPPLEMENT = doc({
|
||||
editGate('parts.profile', '两张档案卡上的主数据核对 / 补齐,点「编辑」开卡') +
|
||||
gapbar('parts_profile', '必填') +
|
||||
DOSSIERS +
|
||||
zone('芯片类型', '本单选用 / 新建的类型;卡上改选之后,旧选择在你确认工单那一刻自动清掉(已入库的留档)', ZIC_TABLE) +
|
||||
editGate('parts.chip_type', '新建一个类型:表尾那一行填类型名称与说明,保存后立刻出现在上面的下拉里') +
|
||||
zone('比对基准 · 芯片类型与核心参数字段', '两颗料归到哪个类型,就按哪个类型的字段逐项比 —— 档案卡上改选,这张卡当场跟着换', ZIC_TABLE) +
|
||||
BASIS_CARD +
|
||||
gapbar('parts_chip_type', '必填') +
|
||||
gapbar('parts_type_param', '必填') +
|
||||
`<details class="lab"><summary class="lab-sm"><b>类型库里没有合适的?</b>展开新建一个类型,并把它的核心参数字段定下来 —— 定完回到上面的档案卡挑它<span class="lab-caret"></span></summary><div class="lab-bd">` +
|
||||
editGate('parts.chip_type', '新建一个类型:表尾那一行填类型名称与说明,保存后立刻出现在档案卡的下拉里') +
|
||||
CHIP_TYPE_TABLE +
|
||||
addrow('parts.chip_type', '+ 再建一个类型', '两颗料若都要新建、且类型不同,先各自保存,「加一行」能再建一个') +
|
||||
zone('核心参数字段', '这个类型逐条比对时要看哪些参数(新建类型时必填,*为必填列)', ZIC_TABLE) +
|
||||
`<p class="lab-sub">这个类型逐条比对时要看哪些参数 —— 名字 / 说明 / 硬软约束(*为必填列)</p>` +
|
||||
editGate('parts.type_param', '字段名字 / 说明 / 硬软约束,点「编辑」核对;表尾那一行 / 「加一行」补字段') +
|
||||
gapbar('parts_type_param', '必填') +
|
||||
TYPE_PARAM_TABLE +
|
||||
addrow('parts.type_param', '+ 加一行(补一个核心参数字段)', '所属类型 / 参数名 / 参数说明 / 约束类型必须写;参考单位选填') +
|
||||
`</div></details>` +
|
||||
zone('参数值', '逐条核心参数的实测 / 规格值(一字段一行,*为必填列;单位由字典定,这里不改)', ZIC_TABLE) +
|
||||
editGate('parts.parameter', '逐条参数值核对 / 补齐,点「编辑」开表') +
|
||||
gapbar('parts_parameter', '必填') +
|
||||
|
||||
@@ -246,18 +246,19 @@ table.on tr.jc-row-static td{background:var(--acc-wash);border-top:1px dashed va
|
||||
*{animation:none !important;transition:none !important}
|
||||
}
|
||||
|
||||
/* ================= 电路板工作台(件① 的两张档案卡)================= */
|
||||
.board{position:relative;margin:0 0 6px;padding:20px 16px 18px;border-radius:16px;
|
||||
/* ================= 电路蓝图工作台(件① 的两张档案卡)=================
|
||||
2026-08-31 用户:「卡片下面那个容器黑色和页面背景不搭」—— 深色板底退场,换**浅色蓝图**:
|
||||
底是强调色的极浅晕染 + 淡格线,走线与信号点用强调色 —— 电路语汇留着,纸面色阶不断裂。 */
|
||||
.board{position:relative;margin:0 0 6px;padding:18px 14px 16px;border-radius:16px;border:1px solid var(--acc-line);
|
||||
background:
|
||||
repeating-linear-gradient(0deg, rgba(255,255,255,.03) 0 1px, transparent 1px 26px),
|
||||
repeating-linear-gradient(90deg, rgba(255,255,255,.03) 0 1px, transparent 1px 26px),
|
||||
radial-gradient(700px 260px at 16% -30%, var(--hero-tint), transparent 62%),
|
||||
linear-gradient(158deg, #13212f 0%, var(--board) 58%, #0f1d2b 100%)}
|
||||
.board::before{content:"";position:absolute;left:4%;right:4%;top:50%;border-top:2px dashed var(--glow-line)}
|
||||
.board::after{content:"";position:absolute;top:50%;left:4%;width:9px;height:9px;margin-top:-4px;border-radius:999px;background:var(--glow);box-shadow:0 0 14px 3px var(--glow-line),0 0 4px 1px var(--glow);animation:sig 3.4s linear infinite}
|
||||
repeating-linear-gradient(0deg, rgba(46,107,255,.045) 0 1px, transparent 1px 26px),
|
||||
repeating-linear-gradient(90deg, rgba(46,107,255,.045) 0 1px, transparent 1px 26px),
|
||||
linear-gradient(158deg, var(--acc-wash) 0%, #fff 62%, var(--acc-wash) 100%)}
|
||||
.board::before{content:"";position:absolute;left:4%;right:4%;top:50%;border-top:2px dashed var(--acc-line)}
|
||||
.board::after{content:"";position:absolute;top:50%;left:4%;width:8px;height:8px;margin-top:-4px;border-radius:999px;background:var(--acc);box-shadow:0 0 8px 2px var(--acc-soft);animation:sig 3.4s linear infinite}
|
||||
.dossiers{position:relative;z-index:1;display:grid;grid-template-columns:repeat(auto-fit,minmax(272px,1fr));gap:16px}
|
||||
.dossier{display:flex;flex-direction:column;gap:11px;background:rgba(255,255,255,.97);border-radius:16px;padding:15px 16px 14px;box-shadow:0 14px 30px rgba(3,10,18,.5),inset 0 1px 0 rgba(255,255,255,.7);transition:box-shadow .18s,transform .18s}
|
||||
.dossier:hover{transform:translateY(-2px);box-shadow:0 18px 36px rgba(3,10,18,.55),inset 0 1px 0 rgba(255,255,255,.7)}
|
||||
.dossier{display:flex;flex-direction:column;gap:11px;background:#fff;border:1px solid var(--line-soft);border-radius:16px;padding:15px 16px 14px;box-shadow:0 8px 22px rgba(18,38,63,.09);transition:box-shadow .18s,transform .18s}
|
||||
.dossier:hover{transform:translateY(-2px);box-shadow:0 12px 28px rgba(18,38,63,.13)}
|
||||
.dz-top{display:flex;align-items:center;gap:12px}
|
||||
.dz-top .csvg{width:64px;flex:none}
|
||||
.dz-id{display:flex;flex-direction:column;gap:4px;min-width:0}
|
||||
@@ -297,6 +298,31 @@ table.on tr.jc-row-static td{background:var(--acc-wash);border-top:1px dashed va
|
||||
.jc-tbl-wrap td.pv .jc-vcell:empty::after{content:"必填";font-size:10.5px;font-weight:800;color:var(--danger);background:var(--danger-soft);border-radius:999px;padding:0 9px}
|
||||
.jc-tbl-wrap td.sg .jc-vcell:empty::after{content:"建议";font-size:10.5px;font-weight:800;color:var(--amber);background:var(--amber-soft);border-radius:999px;padding:0 9px}
|
||||
|
||||
/* ================= 比对基准卡(类型 + 字段合一,只读、跟手)================= */
|
||||
.basis{display:block;margin:0 0 10px}
|
||||
.basis:empty{border:1.5px dashed var(--line);border-radius:12px;padding:16px;display:block}
|
||||
.basis:empty::after{content:"还没定比对基准 —— 先在上面任一张档案卡上挑一个芯片类型,或展开下面的抽屉新建一个。";font-size:12.5px;color:var(--ink-3)}
|
||||
.basis-in{display:flex;flex-direction:column;gap:10px;border:1px solid var(--acc-line);border-radius:12px;background:var(--acc-wash);padding:12px 14px 14px}
|
||||
.basis-hd{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap}
|
||||
.basis-lb{flex:none;font-size:10.5px;font-weight:800;letter-spacing:.08em;color:var(--acc-deep)}
|
||||
.basis-chip b{display:inline-block;font-size:13px;font-weight:800;color:#fff;background:var(--acc);border-radius:999px;padding:2px 14px;margin-right:8px}
|
||||
.basis-desc{font-style:normal;font-size:11.5px;color:var(--ink-3)}
|
||||
.basis-hd:has(.basis-chip:empty)::after{content:"待选择";font-size:11px;font-weight:700;color:var(--amber);background:var(--amber-soft);border:1px dashed #eeda9e;border-radius:999px;padding:1px 10px}
|
||||
.basis-in:has(tbody:empty) .jc-tbl-wrap{display:none}
|
||||
.basis-in .jc-tbl-wrap{background:#fff}
|
||||
|
||||
/* ================= 新建类型工作抽屉(details,零脚本)================= */
|
||||
.lab{margin:0 0 6px;border:1.5px dashed var(--line);border-radius:12px;background:var(--soft)}
|
||||
.lab[open]{border-style:solid;background:#fff}
|
||||
.lab-sm{cursor:pointer;list-style:none;display:flex;align-items:center;gap:8px;padding:11px 14px;font-size:12.5px;color:var(--ink-3);user-select:none}
|
||||
.lab-sm::-webkit-details-marker{display:none}
|
||||
.lab-sm b{color:var(--ink-2)}
|
||||
.lab-sm:hover{color:var(--acc-deep)}
|
||||
.lab-caret{margin-left:auto;flex:none;width:8px;height:8px;border-right:2px solid var(--ink-4);border-bottom:2px solid var(--ink-4);transform:rotate(45deg);transition:transform .16s}
|
||||
.lab[open] .lab-caret{transform:rotate(-135deg)}
|
||||
.lab-bd{padding:2px 14px 14px}
|
||||
.lab-sub{margin:16px 0 8px;font-size:11.5px;color:var(--ink-3)}
|
||||
|
||||
/* ================= 窄屏 ================= */
|
||||
@media(max-width:620px){
|
||||
.card-head{padding:16px 14px 18px}
|
||||
|
||||
Reference in New Issue
Block a user