@qilitt-mickey/vue3-temp-skill 1.1.47 → 1.1.48
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -58,6 +58,22 @@
|
|
|
58
58
|
"hover_color": "--el-pagination-hover-color"
|
|
59
59
|
},
|
|
60
60
|
"custom_style_map": {}
|
|
61
|
+
},
|
|
62
|
+
"component.tooltip.base": {
|
|
63
|
+
"type": "global_component",
|
|
64
|
+
"component": "ElTooltip(原生)/ v-tippy(指令)",
|
|
65
|
+
"style_scope": ":root",
|
|
66
|
+
"css_vars": {
|
|
67
|
+
"bg_color": "--el-tooltip-bg-color",
|
|
68
|
+
"text_color": "--el-tooltip-color"
|
|
69
|
+
},
|
|
70
|
+
"custom_style_map": {
|
|
71
|
+
"radius": "border-radius",
|
|
72
|
+
"padding": "padding",
|
|
73
|
+
"font_size": "font-size",
|
|
74
|
+
"max_width": "max-width"
|
|
75
|
+
},
|
|
76
|
+
"$note": "全局提示气泡。项目内提示有**两条来路**——Element Plus 原生 ElTooltip(继承 --el-tooltip-* 令牌,如 ReAvatars 的 el-tooltip)与 v-tippy 指令(ReTableBar / ReCollapsible / ReAnchor / lay-tag 等处使用,走 tippy 主题,**不自动继承 --el-* 令牌**)。本条目面向 ElTooltip;若设计要求覆盖 v-tippy 气泡,须先确认 tippy 主题变量与本节令牌的对应关系,未映射时按「补通道」补主题变量并在交付说明单列申报(**不得假设自动生效**)。本条目为补建通道——此前登记表标 pending。"
|
|
61
77
|
}
|
|
62
78
|
}
|
|
63
79
|
}
|
|
@@ -308,6 +308,62 @@
|
|
|
308
308
|
},
|
|
309
309
|
"$note": "设计意图(§11.108-11.109):列宽 72px 居中,缩略盒 40×40 圆角 6px。落地手段:列 className=col-thumb + el-image 40×40"
|
|
310
310
|
},
|
|
311
|
+
"admin.content.table.selection_column": {
|
|
312
|
+
"type": "element",
|
|
313
|
+
"selector": ".vts-table-area .el-table__cell.el-table-column--selection",
|
|
314
|
+
"file": "业务 views(el-table-column type=\"selection\";Element Plus 给选择列表头与单元格自动加 el-table-column--selection 类,无需业务自定义类名)",
|
|
315
|
+
"style_scope": ".vts-page-card",
|
|
316
|
+
"css_vars": {
|
|
317
|
+
"checked_bg": "--el-checkbox-checked-bg-color",
|
|
318
|
+
"checked_border": "--el-checkbox-checked-input-border-color",
|
|
319
|
+
"hover_border": "--el-checkbox-input-border-color-hover"
|
|
320
|
+
},
|
|
321
|
+
"custom_style_map": {
|
|
322
|
+
"text_align": "text-align",
|
|
323
|
+
"padding": "padding"
|
|
324
|
+
},
|
|
325
|
+
"anchors": [
|
|
326
|
+
{ "kind": "class", "layer": "host", "target": ".vts-table-area .el-table__cell.el-table-column--selection" },
|
|
327
|
+
{ "kind": "class", "layer": "inner", "target": ".vts-table-area .el-table__cell.el-table-column--selection > .cell" },
|
|
328
|
+
{ "kind": "css_var", "target": "--el-checkbox-checked-bg-color" }
|
|
329
|
+
],
|
|
330
|
+
"preconditions": [
|
|
331
|
+
"选择列由 el-table-column type=\"selection\" 渲染,Element Plus 自动在表头与单元格上加 el-table-column--selection 类——列未声明 type=selection 时本条目永不命中(项目源码实证:views/table/base/index.vue 已用 <el-table-column type=\"selection\" reserve-selection />)。",
|
|
332
|
+
"列宽与其他业务列同属**业务层**(设计侧不声明列宽);本条目只承载对齐与勾选态配色。"
|
|
333
|
+
],
|
|
334
|
+
"priority": {
|
|
335
|
+
"strategy": "scope_qualified",
|
|
336
|
+
"reason": "选择列无行内样式竞争,作用域限定到 .vts-page-card 即可覆盖。"
|
|
337
|
+
},
|
|
338
|
+
"$note": "设计意图(list-page §11.44 选择列):窄列、居中、勾选态用主题主色。本条目为**补建通道**——此前登记表标 pending(项目侧无承载点位),选择列样式无处可落;勾选色走 EP 原生 --el-checkbox-* 令牌,随主题切换。"
|
|
339
|
+
},
|
|
340
|
+
"admin.content.table.row_density": {
|
|
341
|
+
"type": "element",
|
|
342
|
+
"selector": ".vts-table-area .el-table .el-table__cell",
|
|
343
|
+
"file": "src/components/ReTableBar/src/bar.vue(密度下拉:宽松/默认/紧凑 → el-table size = large/default/small)+ src/styles/element-plus.scss(单元格 padding 承载行高)",
|
|
344
|
+
"style_scope": ".vts-page-card",
|
|
345
|
+
"forms": {
|
|
346
|
+
"density": ["loose", "default", "compact"]
|
|
347
|
+
},
|
|
348
|
+
"css_vars": {},
|
|
349
|
+
"custom_style_map": {
|
|
350
|
+
"row_height": "min-height",
|
|
351
|
+
"cell_padding_y": "padding-block"
|
|
352
|
+
},
|
|
353
|
+
"anchors": [
|
|
354
|
+
{ "kind": "class", "layer": "host", "target": ".vts-table-area .el-table .el-table__cell" },
|
|
355
|
+
{ "kind": "class", "layer": "inner", "target": ".vts-table-area .el-table .el-table__cell > .cell" }
|
|
356
|
+
],
|
|
357
|
+
"preconditions": [
|
|
358
|
+
"行高由「单元格 padding + 内容行高」共同决定(见 admin.content.table.cell)——声明行高档位时必须同时给出 padding 取值,只改其一会得到非预期行高。",
|
|
359
|
+
"出厂密度档位由 ReTableBar 的 size(large/default/small,源码实证 bar.vue 的宽松/默认/紧凑三项)驱动;设计侧只声明档位意图(form.density),具体 padding 由本项目按常规取值落定,不得照抄效果图某实例数据的行高。"
|
|
360
|
+
],
|
|
361
|
+
"priority": {
|
|
362
|
+
"strategy": "scope_qualified",
|
|
363
|
+
"reason": "单元格 padding 属全局样式,作用域限定到 .vts-page-card 即可覆盖。"
|
|
364
|
+
},
|
|
365
|
+
"$note": "设计意图(list-page §11.40 行密度):表格行高三档取一(宽松/默认/紧凑)。本条目为**补建通道**——此前登记表标 pending;语义档位 loose/default/compact ↔ 出厂 size large/default/small,项目侧负责映射。"
|
|
366
|
+
},
|
|
311
367
|
"admin.content.table.area": {
|
|
312
368
|
"type": "component",
|
|
313
369
|
"component": "ElTable(useTableSearch tableHeight 定高)",
|
package/package.json
CHANGED
package/parser/index.js
CHANGED
|
@@ -84,7 +84,7 @@ function main() {
|
|
|
84
84
|
case "audit":
|
|
85
85
|
return cmdAudit(args, dataset);
|
|
86
86
|
case "verify":
|
|
87
|
-
return cmdVerify(args);
|
|
87
|
+
return cmdVerify(args, dataset);
|
|
88
88
|
case "registry":
|
|
89
89
|
return cmdRegistry(args, dataset);
|
|
90
90
|
default:
|
|
@@ -104,6 +104,8 @@ function printHelp() {
|
|
|
104
104
|
node parser/index.js audit --project <dir> [<cs.json…>] 挂载点存在性 + 死通道静态审计(需目标项目源码)
|
|
105
105
|
node parser/index.js verify --oracle <o.json> --actual <a.json> [--sids a,b]
|
|
106
106
|
渲染态逐点验收:computed style 期望 vs 实测 diff
|
|
107
|
+
node parser/index.js verify --oracle <o.json> --resolve [--sids a,b]
|
|
108
|
+
实测端定位计划:sid → 词典 selector(项目页不打 data-sid 时按此抽取)
|
|
107
109
|
node parser/index.js verify … --from-theme 钴蓝 --to-theme 橘橙
|
|
108
110
|
同构异色复用:按语义槽位把效果图色值归一为本主题色值再比(配合 oracle.theme_mapping)
|
|
109
111
|
node parser/index.js registry <registry.json> [--verbose]
|
|
@@ -844,7 +846,29 @@ function checkRegistryCoverage(changeset, plan, opts = {}) {
|
|
|
844
846
|
}
|
|
845
847
|
if (changeset.global && Object.keys(changeset.global).length > 0)
|
|
846
848
|
declared.add(GLOBAL_PSEUDO_ID);
|
|
847
|
-
const
|
|
849
|
+
const declaredSids = new Set(Array.isArray(changeset.oracle?.sids) ? changeset.oracle.sids : []);
|
|
850
|
+
|
|
851
|
+
// 实物闭合:打开 oracle.mockup 这个 HTML,数真实存在的 data-sid(不只看设计侧自报的 oracle.sids)
|
|
852
|
+
const mockupRef = changeset.oracle?.mockup;
|
|
853
|
+
let physicalSids = null;
|
|
854
|
+
let mockupFile = null;
|
|
855
|
+
if (typeof mockupRef === "string" && mockupRef.trim()) {
|
|
856
|
+
const cands = [path.resolve(mockupRef), path.resolve(ROOT, mockupRef), path.resolve(process.cwd(), mockupRef)];
|
|
857
|
+
for (const c of cands) {
|
|
858
|
+
try {
|
|
859
|
+
const html = readFileSync(c, "utf-8");
|
|
860
|
+
// 先剥离 HTML 注释再数 data-sid:注释内的同形串是说明文字、不是点位。
|
|
861
|
+
// 不剥离 → 注释可「兜住」一个实际缺失的标注,闸门全绿而基线为空(详见 mockup-extraction-spec.md §7.1)。
|
|
862
|
+
const stripped = html.replace(/<!--[\s\S]*?-->/g, "");
|
|
863
|
+
physicalSids = new Set([...stripped.matchAll(/data-sid\s*=\s*["']([^"']+)["']/g)].map(m => m[1]));
|
|
864
|
+
mockupFile = c;
|
|
865
|
+
break;
|
|
866
|
+
}
|
|
867
|
+
catch { /* 该候选路径不可读,试下一个 */ }
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
// 比对基准:优先效果图实物;实物读不到时退化为自报清单(并在下方告警)
|
|
871
|
+
const mockupSids = physicalSids || declaredSids;
|
|
848
872
|
|
|
849
873
|
const applicable = items.filter(it => it.always === true || registrySids(it).some(s => mockupSids.has(s)));
|
|
850
874
|
const gaps = applicable.filter(it => !registrySids(it).every(s => declared.has(s)));
|
|
@@ -853,6 +877,23 @@ function checkRegistryCoverage(changeset, plan, opts = {}) {
|
|
|
853
877
|
console.log(` 登记表:${registryPath}(登记项 R=${items.length})`);
|
|
854
878
|
console.log(` 适用 A=${applicable.length} / 已兑现 C=${applicable.length - gaps.length} / 缺口 ${gaps.length}`);
|
|
855
879
|
|
|
880
|
+
// 实物校验:标注缺口的权威来源是效果图 HTML 里的 data-sid,而不是自报的 oracle.sids
|
|
881
|
+
let physicalGap = false;
|
|
882
|
+
if (physicalSids) {
|
|
883
|
+
console.log(` 效果图实物:${mockupFile}(实测 data-sid ${physicalSids.size} 个)`);
|
|
884
|
+
const declaredNoPhysical = [...declaredSids].filter(s => !physicalSids.has(s));
|
|
885
|
+
const physicalNoDeclared = [...physicalSids].filter(s => !declaredSids.has(s));
|
|
886
|
+
if (declaredNoPhysical.length > 0) {
|
|
887
|
+
console.log(` ⚠ oracle.sids 声明了 ${declaredNoPhysical.length} 个点位,但效果图实物里没有对应 data-sid(无基线):${declaredNoPhysical.join("、")}`);
|
|
888
|
+
physicalGap = true;
|
|
889
|
+
}
|
|
890
|
+
if (physicalNoDeclared.length > 0)
|
|
891
|
+
console.log(` ℹ 效果图实物另有 ${physicalNoDeclared.length} 个 data-sid 未列入 oracle.sids(自报清单不全,不阻塞):${physicalNoDeclared.join("、")}`);
|
|
892
|
+
}
|
|
893
|
+
else {
|
|
894
|
+
console.log(` ⚠ 未能打开效果图实物(oracle.mockup 不可读)→ 本轮退化为按自报 oracle.sids 校验,实物闭合未生效`);
|
|
895
|
+
}
|
|
896
|
+
|
|
856
897
|
// 效果图标注完整性:恒存在的子项必须能在效果图上找到同名 data-sid,否则基线根本抽不出来
|
|
857
898
|
const unannotated = items.filter(it => it.always === true && !registrySids(it).some(s => mockupSids.has(s)));
|
|
858
899
|
if (unannotated.length > 0) {
|
|
@@ -863,13 +904,20 @@ function checkRegistryCoverage(changeset, plan, opts = {}) {
|
|
|
863
904
|
}
|
|
864
905
|
console.log(` ⚠ 效果图标注缺口 ${unannotated.length} 条:这些子项恒存在,却无同名 data-sid → 基线抽取不全`);
|
|
865
906
|
console.log(` 涉及点位:${[...bySid.entries()].map(([s, n]) => `${s}(${n})`).join("、")}`);
|
|
907
|
+
physicalGap = true;
|
|
866
908
|
}
|
|
867
909
|
|
|
868
|
-
if (gaps.length === 0) {
|
|
869
|
-
console.log(` ✔ 覆盖率通过:C = A
|
|
910
|
+
if (gaps.length === 0 && !physicalGap) {
|
|
911
|
+
console.log(` ✔ 覆盖率通过:C = A,无子项被静默丢失;效果图实物标注闭合`);
|
|
870
912
|
return 0;
|
|
871
913
|
}
|
|
872
914
|
|
|
915
|
+
if (gaps.length === 0 && physicalGap) {
|
|
916
|
+
console.log(`\n✘ 效果图实物标注不闭合 → exit 1(oracle.sids 与效果图 HTML 的 data-sid 不一致 / 恒存在子项缺标注)`);
|
|
917
|
+
console.log(` 处置:给效果图对应元素补 data-sid,或把该登记项降级 source: spec(见 mockup-extraction-spec.md §7)`);
|
|
918
|
+
return 1;
|
|
919
|
+
}
|
|
920
|
+
|
|
873
921
|
const byGroup = new Map();
|
|
874
922
|
for (const it of gaps) {
|
|
875
923
|
const g = it.group || "(未分组)";
|
|
@@ -1296,9 +1344,10 @@ function cmdAudit(args, dataset) {
|
|
|
1296
1344
|
* 本命令不做抽取,只做归一化 + 逐点 diff + 三类归因。
|
|
1297
1345
|
*
|
|
1298
1346
|
* CLI:node parser/index.js verify --oracle <oracle.json> --actual <actual.json> [--sids a,b,c]
|
|
1347
|
+
* 实测端定位计划:node parser/index.js verify --oracle <oracle.json> --resolve [--sids a,b,c]
|
|
1299
1348
|
* 退出码:存在缺口 → 1;全部命中 → 0。
|
|
1300
1349
|
*/
|
|
1301
|
-
function cmdVerify(args) {
|
|
1350
|
+
function cmdVerify(args, dataset) {
|
|
1302
1351
|
// 几何 / 盒模型属性:值对不上 = 语境错位(宿主盒 / 内层盒模型 / 层叠上下文不同)
|
|
1303
1352
|
const GEOMETRY_PROPS = new Set([
|
|
1304
1353
|
"display", "position", "top", "right", "bottom", "left", "box-sizing",
|
|
@@ -1322,8 +1371,10 @@ function cmdVerify(args) {
|
|
|
1322
1371
|
};
|
|
1323
1372
|
const oraclePath = get("--oracle");
|
|
1324
1373
|
const actualPath = get("--actual");
|
|
1325
|
-
|
|
1374
|
+
const resolveOnly = args.includes("--resolve");
|
|
1375
|
+
if (!oraclePath || (!resolveOnly && !actualPath)) {
|
|
1326
1376
|
console.error("✖ 缺少参数:node parser/index.js verify --oracle <oracle.json> --actual <actual.json> [--sids a,b,c]");
|
|
1377
|
+
console.error(" 或输出实测端定位计划:node parser/index.js verify --oracle <oracle.json> --resolve [--sids a,b,c]");
|
|
1327
1378
|
process.exit(1);
|
|
1328
1379
|
}
|
|
1329
1380
|
const sidsArg = get("--sids");
|
|
@@ -1356,12 +1407,53 @@ function cmdVerify(args) {
|
|
|
1356
1407
|
};
|
|
1357
1408
|
|
|
1358
1409
|
const oracle = readDump(oraclePath, "效果图期望");
|
|
1359
|
-
const actual = readDump(actualPath, "项目实测");
|
|
1360
1410
|
|
|
1361
1411
|
let sids = Object.keys(oracle);
|
|
1362
1412
|
if (sidFilter)
|
|
1363
1413
|
sids = sids.filter(s => sidFilter.has(s));
|
|
1364
1414
|
|
|
1415
|
+
// 实测端定位闭合:--resolve 输出「sid → 词典 selector」抽取计划。
|
|
1416
|
+
// 效果图端用 data-sid(设计侧自控);项目页端不要求打 data-sid —— 浏览器按本计划的 selector 抽取。
|
|
1417
|
+
if (resolveOnly) {
|
|
1418
|
+
const index = buildMergedIndex(dataset || {});
|
|
1419
|
+
console.log(`\n=== 实测端定位计划(sid → 词典 selector)===`);
|
|
1420
|
+
console.log(`用途:项目页不要求打 data-sid —— 浏览器抽取脚本按下列 selector 定位元素取 computed style 生成 actual.json`);
|
|
1421
|
+
console.log(`selector 挂载点存在性由 audit 静态校验;本计划只回答「按什么定位」。\n`);
|
|
1422
|
+
let missing = 0;
|
|
1423
|
+
for (const sid of sids) {
|
|
1424
|
+
const entry = index[sid];
|
|
1425
|
+
if (!entry) {
|
|
1426
|
+
console.log(` ✘ ${sid} —— 词典无此条目(L3 新点位,先落地并回写临时映射)`);
|
|
1427
|
+
missing++;
|
|
1428
|
+
continue;
|
|
1429
|
+
}
|
|
1430
|
+
const sels = [];
|
|
1431
|
+
if (Array.isArray(entry.anchors)) {
|
|
1432
|
+
for (const a of entry.anchors) {
|
|
1433
|
+
if (a && a.kind === "class" && a.target)
|
|
1434
|
+
sels.push(`[${a.layer || "host"}] ${a.target}`);
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
if (sels.length === 0 && entry.selector)
|
|
1438
|
+
sels.push(`[host] ${entry.selector}`);
|
|
1439
|
+
if (sels.length === 0) {
|
|
1440
|
+
console.log(` ✘ ${sid} —— 词典条目无 selector / anchors,无法定位`);
|
|
1441
|
+
missing++;
|
|
1442
|
+
continue;
|
|
1443
|
+
}
|
|
1444
|
+
console.log(` · ${sid}`);
|
|
1445
|
+
for (const s of sels)
|
|
1446
|
+
console.log(` ${s}`);
|
|
1447
|
+
}
|
|
1448
|
+
console.log(`\n汇总:${sids.length} 点位,${missing} 个无法定位`);
|
|
1449
|
+
console.log(`抽取属性白名单两端必须一致(padding / font-size / font-weight / text-align / color / background-color / border-radius / gap 等,见 mockup-extraction-spec §3);同构异色复用再加 --from-theme/--to-theme 做色值归一。`);
|
|
1450
|
+
if (missing > 0)
|
|
1451
|
+
process.exitCode = 1;
|
|
1452
|
+
return;
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
const actual = readDump(actualPath, "项目实测");
|
|
1456
|
+
|
|
1365
1457
|
const normProp = p => String(p).trim().toLowerCase().replace(/_/g, "-");
|
|
1366
1458
|
const normValue = v => {
|
|
1367
1459
|
let s = String(v == null ? "" : v).trim().toLowerCase().replace(/\s+/g, " ");
|
|
@@ -103,11 +103,41 @@ parser match(确定性翻译)→ 施工坐标 → AI 按坐标改代码 →
|
|
|
103
103
|
|
|
104
104
|
## 执行流程(按序,禁止跳步)
|
|
105
105
|
|
|
106
|
-
### 第 0 步 · 版本与场景检查
|
|
106
|
+
### 第 0 步 · 版本与场景检查 · 对接匹配(适配前置)· 运行时清场
|
|
107
|
+
|
|
108
|
+
**0.1 版本与场景检查**
|
|
107
109
|
|
|
108
110
|
- 变更集 `schema` 版本不在支持范围 → 停止,向上游(用户/设计侧)报告版本不匹配,不降级猜测。
|
|
109
111
|
- `scene` 在 `parser list` 场景清单中无对应域 → 报告并列出支持的场景,等待确认。
|
|
110
112
|
|
|
113
|
+
**0.2 对接匹配(适配前置)——把散落的匹配收拢为一个前置阶段**
|
|
114
|
+
|
|
115
|
+
在施工前,把「设计意图 ⇄ 模板能力」整体对一遍,输出匹配结论,供**生成前**决策(而不是落地时才发现对不上)。三步判定:
|
|
116
|
+
|
|
117
|
+
| 级 | 判定 | 依据 |
|
|
118
|
+
|---|---|---|
|
|
119
|
+
| **布局级** | `layout_type` 命中标准枚举? | 命中 → 切布局模板池(§5.2);未命中 → 变体派生 / 定制生成骨架(§5.3 / §5.4) |
|
|
120
|
+
| **点位级** | 逐 id 三级匹配 | 一级完整命中 / 二级父级命中 / 三级未命中(§4.1) |
|
|
121
|
+
| **形态级** | `form` 在条目 `forms` 枚举内?`structure_ops` 所需 DOM 钩子是否存在? | 词典 `forms` / 模板源码 / `audit` |
|
|
122
|
+
|
|
123
|
+
**输出三类结论,处置全在项目侧**:
|
|
124
|
+
|
|
125
|
+
| 结论 | 判据 | 处置 |
|
|
126
|
+
|---|---|---|
|
|
127
|
+
| 完全匹配 | L1 ∧ form 在枚举 ∧ 无需结构 | 直接施工 |
|
|
128
|
+
| 可派生 | L2 / 变体布局 / form 可映射 | 派生骨架或继承父级后施工 |
|
|
129
|
+
| 需适配 | L3 / 定制布局 / 缺通道 / 需新 DOM | **先补通道 / 结构增量 / 生成骨架,再生成**;交付说明单列申报 |
|
|
130
|
+
|
|
131
|
+
> **总原则(红线):设计为主,项目侧适配。** 设计效果是目标态,模板是待适配的一方。"设计 ↔ 模板对不上"的出口**永远在项目侧**——**不回流设计侧改设计**。只有「设计侧未给值 / 值非法」(**意图缺口**)才回流设计侧。严禁以「模板不支持」为由要求设计改图。
|
|
132
|
+
|
|
133
|
+
**0.3 运行时主题清场(T 通道先于 D/S/C)**
|
|
134
|
+
|
|
135
|
+
主色 / 主题走的是**运行时通道**:`setEpThemeColor()` 把 `--el-color-primary` 写成 `documentElement` 的**内联样式**并持久化到 localStorage(读取优先级 = 浏览器持久化 ?? `platform-config.json`)。**内联样式 + 运行时持久化 ⇒ 设计层 CSS 与词典 selector 都赢不了。**
|
|
136
|
+
|
|
137
|
+
- 落地前先读 localStorage(键 `responsive-layout`)的 `theme` / `epThemeColor`,与本变更集主题**不一致时清 key 或显式重设**;
|
|
138
|
+
- 清场动作与结果写入交付说明(可回溯);
|
|
139
|
+
- **不清场则颜色类差异全部失真**——归因前必须先确认起点已对齐,否则会把「环境残留」误判成「落地失败」。
|
|
140
|
+
|
|
111
141
|
### 第 1 步 · parser 确定性匹配
|
|
112
142
|
|
|
113
143
|
```bash
|
|
@@ -347,6 +377,7 @@ html .navbar .navbar-breadcrumb-wrap {
|
|
|
347
377
|
|
|
348
378
|
### 第 4 步 · L3 新模块处理(分级布局)
|
|
349
379
|
|
|
380
|
+
- **验收对象闸(角色集合必须齐)**:验收页面的**角色集合**必须覆盖变更集声明的角色。缺角色的,按第 0.2 步「对接匹配 → 需适配」处置——**项目侧补齐该角色的骨架 / 结构**(走 `crud-pages` 样板 + L3 落地并申报),**不是要求设计侧换页面**。不得用出厂 demo 页充数:demo 页**结构上就没有**标题区 / 批量按钮 / 状态 Tag 这些角色 → 这类差异**无论怎么调 CSS 都消不掉**(不是样式问题,是角色集合不匹配)。
|
|
350
381
|
- **列宽口径(业务层 / 设计层边界)**:表格**业务列宽度属业务层**,设计侧不声明、项目侧不按效果图硬套——效果图里的列宽只是其示例数据下的参考值。**唯一例外是操作列**:宽度由组件公式推算(`resolveOperateColumnWidth`,已含分割线占位),业务页禁止写死。**固定列自查(落完后必做,防「符合规范但不合常规」)**:操作列按钮不被裁、不换行、分割线居中可见;状态列标签完整;表头/单元格标题不被省略号截断——任何一项不满足即返工,禁止用「设计值就是对的」搪塞。
|
|
351
382
|
|
|
352
383
|
- **L3 是施工指令,不是待办**:词典未命中的点位一律当场落地、交付说明申报「补映射」,不留待确认。新模块按「定制布局」三步走:① 基于全局规范生成结构(继承命名/作用域/组件规范)② 原子层字段(色彩/圆角/组件级)从 `basic/` + `component/` 词典借力 ③ 场景专属点位生成后**立即写入 mapping/ 对应场景域**(临时映射),累计复用 ≥3 次建议升级标准(由人工评审)。
|
|
@@ -398,8 +429,12 @@ html .navbar .navbar-breadcrumb-wrap {
|
|
|
398
429
|
**链路(抽取由浏览器完成,diff 由 parser 完成)**:
|
|
399
430
|
|
|
400
431
|
1. **抽取期望值**:在浏览器打开效果图(`oracle.mockup`,元素已带 `data-sid`),对 `oracle.sids` 中每个 sid 取其代表性元素的 computed style,导出为 `{ "<sid>": { "<css属性>": "<值>" } }` → `oracle.json`。
|
|
401
|
-
2.
|
|
402
|
-
|
|
432
|
+
2. **抽取实测值**:在浏览器打开已落地页面,**按词典 `selector` / `anchors.target` 定位元素**(**项目页不要求打 `data-sid`**)做抽取 → `actual.json`。
|
|
433
|
+
- 先跑 `node parser/index.js verify --oracle oracle.json --resolve` 得到「sid → 词典 selector」定位计划;
|
|
434
|
+
- 抽取脚本(Playwright / 浏览器控制台)按计划 selector 取 `getComputedStyle(el)` 的白名单属性(padding / font-size / font-weight / text-align / color / background-color / border-radius / gap 等);
|
|
435
|
+
- **期望端(效果图)用 `data-sid`、实测端(项目页)用词典 selector——两侧定位方式不必对称**:效果图是设计侧自控产物,项目页是消费方、不感知设计坐标。selector 挂载点错位由 `audit` 先于 `verify` 报出,责任链回到词典;
|
|
436
|
+
- 期望值**优先直接消费设计侧交付的 `oracle.json` 抽取产物**(期望 / 实测同源同口径);无产物时再从 `oracle.mockup` 现场抽取;
|
|
437
|
+
- 两个页面的属性白名单必须一致,否则出现假缺口。
|
|
403
438
|
3. **逐点 diff**:
|
|
404
439
|
```bash
|
|
405
440
|
node parser/index.js verify --oracle oracle.json --actual actual.json
|