@qilitt-mickey/vue3-temp-skill 1.2.5 → 1.2.7

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.
@@ -1,352 +1,57 @@
1
- ---
2
- name: design-apply
3
- description: 视觉契约落地协议。接收设计侧产出的视觉契约 JSON(ui.visual-contract/1.0),照抄生成三份样式文件(令牌 / 角色 / 布局)。AI 在本协议中的工作是翻译,不是判断。
4
- scope: project
5
- tags: [design-apply, visual-contract, design-tokens, role, layout]
6
- ---
7
-
8
- # 视觉契约落地(design-apply)
9
-
10
- ## 定位
11
-
12
- 把设计侧的视觉契约翻译成项目样式。**唯一输入是一份契约 JSON,唯一输出是三份 CSS。**
13
-
14
- ```
15
- 契约 JSON(技术栈中立)
16
- ↓ ① 展开令牌引用 ② 角色 → .role-<name> ③ 布局 → .ui-page 网格
17
- src/styles/ui-tokens.css :root 变量
18
- src/styles/ui-roles.css 角色规则
19
- src/styles/ui-layout.css 区域网格
20
- ```
21
-
22
- **分工**:契约负责精确(写什么值、放哪一层),本协议负责翻译(怎么变成 CSS),组件库差异由 adapter 承担。
23
-
24
- ---
25
-
26
- ## 边界与约束(不可越)
27
-
28
- 本能力组只处理视觉落地,与 AI 工具无关;**只服务 Vue 3 项目**。
29
-
30
- | 约束 | 说明 |
31
- |---|---|
32
- | **契约是唯一输入** | 不引入其他协议、不解析其他格式 |
33
- | **契约里没有技术栈信息** | 只有 CSS 属性、令牌引用、区域与角色——因此不需要理解组件内部实现也能生成样式 |
34
- | **路径约定用通用目录** | 读契约:`<项目根>/.design/visual-contract-*.json`;写样式:`src/styles/ui-*.css`。两者都是通用项目目录 |
35
- | **组件库差异只在 adapter** | 深度选择器语法、组件库前缀、布局占位挂载点——adapter 的全部职责,adapter 只覆盖 Vue 组件库 |
36
-
37
- ---
38
-
39
- ## 执行流程(七步)
40
-
41
- ### 第 0 步 · 落地自检(先跑,断在哪一目了然)
42
-
43
- ```bash
44
- node <技能>/scripts/check-landing.mjs --project <项目根>
45
- ```
46
-
47
- **八项检查,逐项给修复动作,exit 1 表示链路有断点:**
48
-
49
- | # | 检查项 | 断点含义 |
50
- |---|---|---|
51
- | 1 | `contract-found` | `.design/visual-contract-*.json` 不存在 → 设计侧没落盘 |
52
- | 2 | `contract-valid` | 契约字段缺失(`meta.scene` / `tokens.color` / `roles` / `layout.areas`) |
53
- | 3 | `contract-structure` | 角色名不在角色库 / `regions` 与 `areas` 不一致 / 绑定的区域名不存在 → 设计侧结构违规,**回设计侧修** |
54
- | 4 | `css-generated` | 三份 CSS 未生成 → 第 3/4/5 步没执行 |
55
- | 5 | `css-imported` | **生成了但没被 import** → 浏览器根本不加载 |
56
- | 6 | `roles-mounted` | **CSS 有规则但模板没挂类** → 死样式,视觉不变 |
57
- | 7 | `layout-mounted` | 模板没出现 `.ui-page` → 骨架仍是项目原样 |
58
- | 8 | `css-rules` | 模板挂了类但 CSS 里没有对应规则 → 生成不完整或被手改 |
59
-
60
- **八项全过是交付前置条件。** 不过就修断点,**不要直接目视猜问题在哪**。
61
-
62
- > **⚠️ 导入顺序硬坑(实证)**:三份 CSS 必须作为 **TS import 在组件库全量 CSS 之后**引入(如 `main.ts` 里 `import 'element-plus/dist/index.css'` 之后)。若 `@import` 进项目 `index.scss`,而组件库 CSS 在 `main.ts` 中晚于 `index.scss` 加载(独立 `<style>` 标签),则契约层会被组件库同特异性规则**整层盖住**——表现为「只有主题色对、其余全不对」。`adapter.output.entryImport` 指定正确入口。
63
-
64
- ### 第 1 步 · 读契约(只读一次)
65
-
66
- 读取 `<项目根>/.design/visual-contract-*.json`。多份契约(多页型)逐份独立施工。
67
-
68
- **读之前先确认 `meta`**:场景、页型、值来源。契约里已声明这三项,**不从项目源码反推、不自行猜测**。
69
-
70
- 契约是项目的完整视觉事实源——**不读项目现有样式来决定怎么落地**。项目现有样式与契约冲突时,以契约为准。
71
-
72
- ### 第 2 步 · 选 adapter(按项目事实判定)
73
-
74
- 读 `package.json` 判定所用组件库,选取对应 adapter:
75
-
76
- | 项目依赖 | adapter |
77
- |---|---|
78
- | `element-plus` | `adapters/vue-element-plus.md` |
79
- | `ant-design-vue` | `adapters/vue-antdv.md` |
80
- | 其他 / 暂无 | 按 `adapters/_new-adapter.md` 模板补一份 Vue 组件库 adapter |
81
-
82
- **本技能只服务 Vue 3 项目**,因此 adapter 只覆盖 Vue 组件库。需要支持其他前端框架时,由对应框架的项目技能自带 adapter——契约格式不变,改的只是落地那一侧的 adapter。
83
-
84
- **adapter 只回答三件事**:① 深度选择器语法 ② 组件库穿透前缀 ③ 三份 CSS 的落点文件与引入方式。
85
-
86
- **adapter 不定义设计意图、不定义风格、不改写契约值。**
87
-
88
- ### 第 3/4/5 步 · 生成三份 CSS(机器执行,禁止手抄)
89
-
90
- ```bash
91
- node <技能>/scripts/generate-css.mjs --project <项目根>
92
- ```
93
-
94
- **`generate-css.mjs` 是第 3/4/5 步的可执行实现**:读契约 `tokens/roles/layout` + `adapters/<adapter>.json`(机器可读映射:`innerTargets`/`stateChannels`/`extraRules`/`variableBridges`/`layoutBridge`),确定性生成三份 CSS。**同一输入必得同一输出**——手抄会漏值、引错变量名、状态写不全(这正是历次「只有主题色对」事故的根源)。
95
-
96
- 下面第 3/4/5 步的「翻译规则表」是生成器的**行为规格**与人工核对依据,不再让 AI 逐条手写:
97
-
98
- ### 第 3 步 · 写令牌 → `src/styles/ui-tokens.css`
99
-
100
- 契约 `tokens` 逐条转 CSS 变量:
101
-
102
- ```css
103
- :root {
104
- --color-brand: #2B5AED;
105
- --color-brand-hover: #1F4FD8;
106
- --color-text-primary: #1F2329;
107
- --space-4: 16px;
108
- --radius-md: 6px;
109
- --size-control-height: 32px;
110
- }
111
- ```
112
-
113
- **命名规则**:`tokens` 的 `<族>.<名>` → `--<族>-<名>`,点号转连字符(`space.4` → `--space-4`,`control.height` → `--control-height`)。
114
-
115
- **值原样抄**:契约里是实值就写实值,是 `{令牌引用}` 就先完成替换。**不重新取色、不换算、不四舍五入。**
116
-
117
- ### 第 4 步 · 写角色 → `src/styles/ui-roles.css`
118
-
119
- 契约 `roles` 逐条转类规则。**这是纯粹的翻译,每个角色一段:**
120
-
121
- ```css
122
- /* 角色:table.headerCell —— ui-roles.css 是全局文件:内层穿透用普通后代选择器,禁 :deep() */
123
- .role-table-header-cell { background-color: #FAFAFA; height: 48px; padding: 16px; border-bottom: 1px solid var(--color-border-base); }
124
- .role-table-header-cell .cell { font-size: var(--font-size-md); font-weight: 500; color: var(--color-text-primary); text-align: left; white-space: nowrap; }
125
- ```
126
-
127
- **翻译规则表**:
128
-
129
- | 契约结构 | 生成 |
130
- |---|---|
131
- | `roles.<名>.host[]` | `.role-<名转连字符> { … }` |
132
- | `roles.<名>.inner[]` | 同类名 + adapter 给出的内层目标选择器(**全局文件用普通后代选择器**;`:deep()` 只允许出现在 SFC `<style scoped>`——通道写错整条规则被浏览器**静默丢弃、无任何报错**) |
133
- | `roles.<名>.states.hover.host[]` | `.role-<名>:hover { … }` |
134
- | `roles.<名>.states.disabled.inner[]` | `.role-<名>:disabled { … }`(或 adapter 的 disabled 通道) |
135
- | 声明值 `{令牌}` | 替换为 `var(--令牌)` |
136
-
137
- **角色名转换**:`table.headerCell` → 类名 `.role-table-header-cell`(点号转连字符 + `role-` 前缀,避免与组件库类名冲突)。
138
-
139
- **契约值 → 组件库 DOM 的结构等价转换**:组件库真实 DOM 与契约属性并非一一对应(如 Element Plus 输入框边框实际是 `box-shadow: … inset`、表头是 `th > .cell` 双层结构、卡片内边距由 `.el-card__body` 承载并带 `!important`)。这类转换**以 adapter 的「结构等价转换」表为准,禁止现场临时发明**;转换只改「属性落在哪个 DOM 节点、用什么属性表达」,**不改契约值本身**——值仍然来自契约,只是表达载体等价替换。
140
-
141
- **AI 在这一步不做的事**:
142
-
143
- | 不做 | 为什么 |
144
- |---|---|
145
- | 判断某属性落 host 还是 inner | 契约已用两个数组物理二分,照抄 |
146
- | 判断该不该加 `!important` | 契约禁止;层叠由 adapter 统一处理 |
147
- | 判断该不该提权覆盖组件库 | 角色是独立类 + 独立文件,天然不与组件库同类规则竞争;确有冲突时由 adapter 的唯一提权通道处理 |
148
- | 补角色库没有的角色 | 图上没有的角色不写进契约,契约里没有就不生成 |
149
- | 合并 / 简化声明 | 一条声明一个属性,原样生成 |
150
-
151
- ### 第 5 步 · 写布局 → `src/styles/ui-layout.css`
152
-
153
- 契约 `layout` 转网格。**这是布局差异的落点——设计布局与项目布局不一致时,差异只体现在这份文件的取值上。**
154
-
155
- ```css
156
- .ui-page {
157
- display: grid;
158
- grid-template-columns: 208px 1fr;
159
- grid-template-rows: 54px 40px 1fr;
160
- grid-template-areas: "side head" "side tabs" "side body";
161
- }
162
- .ui-region-sidebar { grid-area: side; background-color: var(--color-shell-bg); width: 208px; }
163
- .ui-region-header { grid-area: head; height: 54px; background-color: var(--color-surface); padding: 0 20px; }
164
- .ui-region-tabs { grid-area: tabs; height: 40px; background-color: var(--color-surface); }
165
- .ui-region-content { grid-area: body; padding: 24px; background-color: var(--color-page-bg); gap: 20px; }
166
- ```
167
-
168
- **翻译规则**:
169
-
170
- | 契约字段 | 生成 |
171
- |---|---|
172
- | `layout.grid` | `grid-template-columns` |
173
- | `layout.rows` | `grid-template-rows` |
174
- | `layout.areas[]` | `grid-template-areas`(由各区域的 `area` 值排布)+ `.ui-region-<名> { grid-area: <area> }` |
175
- | `layout.regions.<名>` 几何键 | `width` / `height` / `min-height` / `padding` / `gap` |
176
- | `layout.regions.<名>` 排布键 | `display` / `flex-direction` / `justify-content` / `align-items` / `flex-wrap` |
177
- | `layout.regions.<名>` 定位键 | `position` + `top/right/bottom/left`(`offset` 的键)/ `z-index` |
178
- | `layout.regions.<名>` `bleed` | 负 margin 抵消父容器内边距 + 自身宽度撑回 |
179
- | 未写入 `areas` 的区域 | **不生成规则**(即为不渲染)——不需要单独的显隐声明 |
180
-
181
- **`bleed` 的生成示例**(页签栏在内容区内但要通栏):
182
-
183
- ```css
184
- /* 契约:tabs 区域 bleed: { top: true, left: true, right: true },内容区 padding: 24px */
185
- .ui-region-tabs {
186
- margin: -24px -24px 16px; /* 抵消父内边距 */
187
- padding-left: 24px; /* 自身内容补回 */
188
- }
189
- ```
190
-
191
- **关键**:项目现有的布局组件退化为**占位容器**(保留业务插槽,不参与布局决策)。页面骨架由本步生成的 `.ui-page` 网格决定。
192
-
193
- ### 第 5b 步 · 生成角色的几何与排布
194
-
195
- 角色除视觉声明外还带结构键,**这些键决定元素「为什么在这个位置」**:
196
-
197
- | 契约结构 | 生成 |
198
- |---|---|
199
- | `roles.<名>.box` | `width` / `min-width` / `max-width` / `height` |
200
- | `roles.<名>.flow` | `display` / `align-items` / `gap` / `flex` / `min-width` |
201
- | `roles.<名>.align` | `text-align` / `vertical-align` |
202
- | `roles.<名>.span` | `flex` / `flex-shrink` / `min-width` |
203
- | `roles.<名>.sticky` | `position: sticky` + 对应方位的 `top/right/bottom/left` |
204
- | `pages.<页型>.nodes[].box` | 该节点绑定的几何约束(覆盖角色默认) |
205
- | `pages.<页型>.nodes[].sticky` | 该节点绑定的吸附方位 |
206
-
207
- **三条必须落实的派生规则**:
208
-
209
- | 规则 | 生成什么 |
210
- |---|---|
211
- | **弹性收缩配 `min-width: 0`** | 契约给了 `span: { flex: "1" }` 就必须同时生成 `min-width: 0`,否则长内容撑破容器 |
212
- | **宽度三态照抄** | 契约写 `minWidth` 就生成 `min-width`,不擅自补 `width` |
213
- | **吸附列补底色** | `sticky` 存在时必须给 `background`(否则滚动时透出下层内容) |
214
-
215
- ### 第 5c 步 · 处理跨元素联动
216
-
217
- 契约 `pages.<页型>.nodes[].when` 声明的联动,由 adapter 提供实现方式:
218
-
219
- | `when` | adapter 的实现方式 |
220
- |---|---|
221
- | `rowHover` | 用行状态的 class 覆盖绑定元素底色 |
222
- | `rowSelected` | 用选中态 class 覆盖绑定元素底色 |
223
- | `colSticky` | 吸附列底色跟随所在行——**必须实现**,否则滚动时露底 |
224
- | `groupHover` | 用分组 hover 的 class 覆盖 |
225
-
226
- **实现方式二选一**:能挂 class 就挂 class(简单可靠);挂不上就用组件的 `row-class-name` 回调。**由 adapter 决定,不由落地端临时发明。**
227
-
228
- ### 第 6 步 · 挂载 + 覆盖验证
229
-
230
- 1. 在样式入口引入三份文件(**入口位置按 `adapter.output.entryImport`——通常是 main.ts 在组件库全量 CSS 之后**)
231
- 2. 页面根节点挂 `.ui-page`,各区域挂 `.ui-region-<名>`
232
- 3. 按 adapter 的「角色类挂载方式」给组件挂 `.role-*`(**表格走插槽,不是在 `<el-table>` 上加类**)
233
- 4. **按契约 `structure` 重建页面骨架**——区块数量/顺序、列数与列宽档位、控件类型、图标 path、折叠/吸附结构,**照骨架对齐**。
234
- **⚠️ 形态/内容分离(红线)**:`structure` 里标了 `sampleOnly` 的业务内容(列名文字、筛选项 label、数据行、菜单文字、状态文案)**一律不烧进项目**——项目侧保持自身业务字段(列名/prop/API/mock/权限/字典),只把「形态」对齐骨架。设计稿的演示占位不是目标项目的业务事实;覆盖业务逻辑 = 交付失败。
235
- 5. **重跑第 0 步的落地自检,八项全过才算挂载完成**
236
- 6. 进入第 7 步视觉验收(computed style 逐点比对契约 + visualSanity 通用断言,目视截图只作最后留档)
237
-
238
- | 现象 | 根因 | 修正动作 |
239
- |---|---|---|
240
- | 页面完全没变化 | 三份 CSS 没被 import | 在样式入口 import 一次 |
241
- | 只有个别地方变了 | 角色类挂载覆盖率低 | 按 adapter 挂法补齐,重跑自检 |
242
- | 布局还是项目原样 | 没挂 `.ui-page` / `.ui-region-*` | 布局组件加类 |
243
- | 有差异 | 契约值或落点层不对 | **改契约 → 重新生成 CSS** |
244
- | 颜色不对 | 令牌值抄错 | 改 `tokens` → 重新生成 |
245
- | 字号 / 字重不对 | 落错层(该进 `inner[]` 进了 `host[]`) | 改契约的数组归属 → 重新生成 |
246
- | 表头竖排换行 | `white-space` 没进 `inner[]` | 同上 |
247
- | 组件库样式盖住角色 | adapter 的穿透前缀不对 | 改 adapter 的穿透目标 |
248
- | 布局位置不对 | `areas` 排布或 `regions` 取值不对 | 改 `layout` → 重新生成 |
249
- | 某角色完全没生效 | 该角色没写进契约 | **回设计侧补抽**,不是项目侧猜 |
250
-
251
- ### 第 7 步 · 视觉验收(computed style 逐点比对契约)
252
-
253
- 目视对照只能发现「明显不像」,发现不了「差 2px、差一档灰」。**验收的期望源就是契约 JSON 本身**——不另建期望值文件、不另建长期采集脚本。
254
-
255
- ```bash
256
- node <技能>/scripts/verify-render.mjs --project <项目根> --url http://localhost:<dev端口>
257
- ```
258
-
259
- **`verify-render.mjs` 是本步的可执行实现**:Playwright 登录 → 导航目标页 → 对契约每条声明读 `getComputedStyle` 逐点比对(颜色归一、几何容差 ≤2px、`auto`/`unitless line-height`/`repeat()` 等计算值假差异自动放行)→ 输出 `[FAIL] 角色·选择器·属性 期望/实际/命中元素` 差异报告 + 全页截图。差异清零即视觉验收通过。
260
-
261
- **第二遍:visualSanity 通用断言(契约值之外的 UX 合理性)**
262
-
263
- 契约比对只保证「值抄对了」,不保证「值组合起来合理」——表头换行、文字省略号、操作列截断、元素被隐藏都是**组合性缺陷**,逐点比对全绿也可能发生。断言规则沉淀在 `adapter.visualSanity`(通用编排,换场景/页型自动生效),至少覆盖:
264
-
265
- | 断言 | 判据 | 典型根因 |
266
- |---|---|---|
267
- | no-wrap | 表头/标签/按钮 `.cell` 的 `scrollWidth ≤ clientWidth+1` 且 `white-space:nowrap` | 宽度档位不够 / padding 吃掉空间 |
268
- | no-ellipsis | 可见文本元素计算值 `text-overflow` 未实际截断(scrollWidth 不超) | 列宽写死 / .cell overflow:hidden |
269
- | full-visibility | 契约 structure 声明的每个元素 `display≠none && rect.width>0`(折叠钮、分隔线、操作列按钮组) | 被组件库/UnoCSS 隐藏、图标未注册 |
270
- | padding-sanity | 内容区左右 padding ≥ 契约 region 值(操作列留边) | padding 被归零过头 |
271
- | row-height-sanity | 数据行实际高度 = 密度档值(±2px) | padding/line-height 撑高 |
272
-
273
- **修复定向不变**:visualSanity 失败 → 修 adapter `extraRules`(提权/结构等价转换)或契约值,不手改生成物。
274
-
275
- 1. 启动项目 dev server,跑 `verify-render.mjs`(脚本内置真实账号登录链路,不留特殊开关)
276
- 2. 逐条消化差异,定位顺序(由外向内):**挂载遗漏 → 穿透/选择器通道错 → 提权被组件库盖住(`!important` 对决比特异性)→ 契约值本身错**——前三者修落地侧(第 4/5/6 步或 adapter 的 `extraRules`),最后一种回设计侧改契约后重新生成
277
- 3. 全部命中(契约差异 0 + visualSanity 全过)后截图,与 `meta.source.mockup` 指向的设计稿并排留档
278
-
279
- **永不直接改生成出来的 CSS 来「凑」比对结果**——比对失败的修复动作永远落回第 4/5/6 步或契约。
280
-
281
- ### 修正的唯一定向(不可破)
282
-
283
- **只改契约或改 adapter,永远不直接改生成出来的 CSS。**
284
-
285
- 直接改 CSS 会在下次重新生成时被覆盖,且这份覆盖不会留下痕迹——同类问题会在下一轮以另一种形态复发。改契约的成本远低于改代码,因为契约是结构化的、可定位的、可重放的。
286
-
287
- **不做**:不建独立的期望值文件(期望源就是契约 JSON)、不把验收脚本沉淀进项目长期维护、不跑业务回归、不写长期维护的逐点 diff 报告(第 7 步的一次性比对除外)。
288
-
289
- ---
290
-
291
- ## 三列变量映射表
292
-
293
- `mapping/<场景>.json` 是项目现状与契约区域名的对照表,**只有三列**:
294
-
295
- ```json
296
- {
297
- "schema": "ui.var-map/1.0",
298
- "stack": "vue3 + element-plus",
299
- "adapter": "vue-element-plus",
300
- "layoutHost": "src/layout/lay-admin/index.vue",
301
- "regions": {
302
- "sidebar": { "scope": ".lay-sidebar", "var": "--ui-sidebar-w", "fallback": "208px" },
303
- "header": { "scope": ".lay-header", "var": "--ui-header-h", "fallback": "54px" },
304
- "tabs": { "scope": ".lay-tabs", "var": "--ui-tabs-h", "fallback": "40px" },
305
- "content": { "scope": ".lay-content", "var": "--ui-content-p","fallback": "24px" }
306
- }
307
- }
308
- ```
309
-
310
- | 字段 | 作用 |
311
- |---|---|
312
- | `scope` | 项目里承载该区域的现有类名(供 adapter 定位,生成 CSS 时不必写死) |
313
- | `var` | 项目侧可选的尺寸变量名(项目已有则复用,没有则用契约值直接写) |
314
- | `fallback` | 项目缺该区域时的占位值 |
315
- | `layoutHost` | 布局占位容器路径(保留业务插槽,不参与布局决策) |
316
-
317
- **三列取代了原有的八件套词典**(`selector` / `css_vars` / `custom_style_map` / `style_scope` / `anchors` / `preconditions` / `priority` / `forms`)——落点层级由契约的 `host`/`inner` 二分承载,优先级由 adapter 统一,形态由契约声明本身承载。
318
-
319
- ---
320
-
321
- ## 与项目其他能力的关系
322
-
323
- 本能力组只管视觉落地。项目开发主流程(列表页、表单、API、权限等)见 `SKILL.md` 的能力组路由。
324
-
325
- **两条链路的边界**:
326
-
327
- | 场景 | 入口 | 产物 |
328
- |---|---|---|
329
- | 常规开发 | 能力组路由(`crud-pages` / `form-advanced` / `http-api` …) | 业务代码 |
330
- | **设计契约落地** | 本协议 | `ui-tokens.css` / `ui-roles.css` / `ui-layout.css` |
331
-
332
- 常规开发**不受本协议约束**——它写自己的页面样式,不生成角色类。两条链路的样式互不干扰:角色类是独立命名空间(`role-` 前缀),布局类是独立命名空间(`ui-` 前缀)。
333
-
334
- ---
335
-
336
- ## 红线
337
-
338
- 1. **契约是唯一事实源**——不读项目现有样式来决定怎么落地;冲突时以契约为准。
339
- 2. **照抄不判断**——不判断落点层级、不合并声明、不补角色库没有的角色、不改契约值。
340
- 3. **禁止 `!important`**——角色类是独立命名空间,天然不竞争;确有冲突走 adapter 的唯一提权通道。
341
- 4. **不改项目布局组件的布局决策**——它退化为占位容器;改它等于把设计结论烧进源码。
342
- 5. **工具中立**——协议内容不出现任何 AI 工具的专有概念;路径只用通用项目目录。
343
-
344
- ---
345
-
346
- ## 子文件(按需加载)
347
-
348
- | 文件 | 加载时机 |
349
- |---|---|
350
- | `adapters/vue-element-plus.md` | 项目用 Element Plus |
351
- | `adapters/vue-antdv.md` | 项目用 Ant Design Vue |
352
- | `adapters/_new-adapter.md` | 项目用其他 Vue 组件库,需要补一份适配 |
1
+ # 设计落地执行
2
+
3
+ ## 1. 接入设计与确定范围
4
+
5
+ - 接受原始截图、HTML、设计工程、运行地址、`ui.design-handoff/1.0` 或已有 `ui.visual-contract/1.0`;原稿已有而交接缺失时,在本轮加载 `project-ui-design` 补齐交接并继续,不要求用户切会话。
6
+ - 读取当前任务的交接和原稿;多个任务并存时按用户指定或上下文选择,无法确定时询问,不默认选目录中的第一份 JSON。
7
+ - 从路由与页面确定目标。用户指定页面时使用该页面;用户要求全系统时覆盖共用外壳及受影响页面类型,列出代表性页面和独有视图,不缩成一页。
8
+ - 原稿有外壳而内容页未确定时,可先做已明确的共用外壳;页面锚点存在歧义时一次询问。没有业务页面时不照 Demo 新建业务;只有用户另行授权业务开发才创建路由和业务页。
9
+ - 在 `.design/<任务名>/implementation.json` 记录 `handoff` 路径、目标路由与文件、原稿视图/区域到项目区域的映射、未匹配原稿区域、项目扩展区域、计划修改范围。
10
+ - 完成条件:每个请求区域有实际目标或明确缺口;设计来源和版本已固定。
11
+
12
+ ## 2. 固定业务基线
13
+
14
+ - 阅读目标页面的 script、template、API、types、Hooks、Store、路由和权限;记录当前 Git diff,区分用户原有改动与本轮改动。
15
+ - 在 `.design/<任务名>/business-baseline.json` 记录目标页面已有路由、字段/列/筛选项、API 方法及参数、字典枚举、校验、事件、权限、分页排序、详情跳转和加载/错误状态;记录相关文件指纹或可追溯基线,不保存凭证或业务敏感数据。
16
+ - 以项目当前实现而非仓库 HEAD 作为本轮业务基线;保持原有未提交业务修改。
17
+ - 将 Demo 的字段、菜单、列数、筛选项数、操作数、状态数量、业务顺序、文案和数据视为样例。相同「查询」「重置」文案可以自然重合,不用关键词碰撞判断业务泄漏。
18
+ - 仅迁移布局关系、视觉密度、控件外观、图标绘制风格和展示层交互;保留项目当前功能、数量和语义。
19
+ - 完成条件:受影响业务均有基线,演示业务与项目事实已分离;不得用新增 mock、静态表格或伪接口替代现有数据流。
20
+
21
+ ## 3. 核对模板能力
22
+
23
+ - 读取 `core-kernel.md`,按实际修改读取 `layout-theme.md`、`ui-components.md`、`crud-pages.md` 或其他专项;源码与示例冲突时以当前源码契约为准。
24
+ - 检查 `src/layout`、`src/styles/design-tokens.scss`、`design-shell.scss`、`sidebar.scss`、`element-plus.scss`、页面 scoped 样式和入口导入顺序;读取相关 `Re*` 与 Hooks 的真实 Props、Emits、Slots 和 DOM。
25
+ - 按实际依赖读取适配:Element Plus 用 `references/adapters/vue-element-plus.md`,Ant Design Vue 用 `references/adapters/vue-antdv.md`;其他 Vue 组件库按 `references/adapters/_new-adapter.md` 核对实际 DOM、绘制层和状态。不用静态 adapter 的默认颜色或尺寸覆盖原稿。
26
+ - 检查 fixed 侧栏、主体 margin、固定顶栏、内容 padding、`data-content-mode`、`data-fill` 及内部滚动之间的关系。每项几何只保留一个负责机制,避免旧偏移与新 grid 叠加。
27
+ - 列表保留 `content`、`otherRef`、`multipleTableRef` 和分页/表格容器约束;保留 `ReTableBar` 密度与列控制、`RePagination` 事件、`ReTableOperate` 权限和操作分发。
28
+ - 完成条件:目标区域的 DOM、样式来源和业务依赖均已核对;不存在按想象挂 class 或重复挂载 Layout。
29
+
30
+ ## 4. 改造视图与样式
31
+
32
+ - 按「共用外壳 → 页面结构 → 组件内部 → 字体素材 → 状态与响应式」施工;完成一个区域即运行并对照,不先铺完整站再凭记忆修正。
33
+ - 使用原稿实值定义或映射 CSS 变量;保留项目主题切换能力。只修改用户要求的视觉范围,默认样板尺寸不限制明确设计值。
34
+ - 优先调整已有变量、组件 Props/Slots 和项目样式;必要时重排模板、替换视觉容器、拆分表现组件、调整外壳或项目自有 `Re*` 表现层。无需为已授权的 UI 改版逐处请求许可。
35
+ - 保持 `Re*` 的对外接口、数据、权限与事件兼容;新增可选视觉参数时保留默认行为并验证其他调用处。共享组件改动必须核对全部引用方。
36
+ - 禁止修改 `node_modules`、复制另一套 UI 框架、用 Demo 工程替换项目、为截图隐藏项目业务功能或伪造数据。
37
+ - 主题值写入项目令牌层,外壳规则写入可追踪的项目样式层,页面特有规则使用 scoped 样式;允许直接维护这些手写文件,不强制经过 CSS 生成器。
38
+ - 只在维护既有生成文件时保留其生成来源与手写适配层分离;原有 `generate-css.mjs` 不作为新流程的默认实现,不将三份 CSS 视作唯一产物。
39
+ - 检查真实绘制节点、伪元素、Teleport 浮层、盒模型、选择器权重与注入时序;先处理作用域和变量,必要时对单一属性使用有实测依据的 `!important`,不做全局无边界覆盖。
40
+ - 根据项目内容数量使用相同排布规则;长文案、多列、多菜单仍须可用。与 Demo 业务不同造成的几何变化单独记录,不改业务凑截图。
41
+ - 完成条件:目标路由实际渲染设计形态;所有必要结构与样式已落地,业务绑定及共享组件兼容性保持。
42
+
43
+ ## 5. 双重验收
44
+
45
+ - 执行 `code-quality.md` 的工程及业务检查,再执行 `visual-verification.md` 的原稿对照。
46
+ - 逐项复核业务基线:接口/参数、字段、菜单、路由、权限、字典、校验、事件及状态流。对视图重构后的交互实际操作验证。
47
+ - 在同一运行环境对原稿和实现截图,按映射逐区域测量和目视对照;差异定位到源值、DOM、层叠、字体、素材或布局,修复后重测。
48
+ - 只在原稿证据证明抽取错误时修改交接;不得改原稿、调整阈值、删除必需区域或修改项目业务让验收变绿。
49
+ - 格式检查与旧链路诊断只报告各自覆盖的内容;不得将 `check-landing.mjs` / `verify-render.mjs` 的历史输出当成设计完成凭证。
50
+ - 完成条件:工程检查通过、业务基线保持、每个请求区域完成原稿对照;未验证项和设计/业务不匹配项有具体证据和状态。
51
+
52
+ ## 6. 交付
53
+
54
+ - 更新 `implementation.json` 的实际文件、目标路由、区域映射、业务保护结果和未决差异;保存 `verification.json` 及参考/实际/差异图。
55
+ - 报告已修改范围、可打开页面、检查命令结果、视觉差异和限制;仅有目视检查时如实说明。
56
+ - 用「已对照的区域及状态」描述结果;只在相同环境、相同可比内容的截图确实零像素差且所有请求范围均覆盖时使用「像素一致」。不要承诺所有编辑器和不同环境下都能达到 100%。
57
+ - 完成条件:交付证据与实际文件一致;缺少原稿、素材、登录、浏览器或业务后端时保持相应项未完成,不伪造通过。
@@ -7,6 +7,8 @@ tags: [vue3, layout, theme, dark-mode, css-variables, design-tokens, element-plu
7
7
 
8
8
  # 布局与主题适配
9
9
 
10
+ 设计还原先读取 `design-apply.md`。以下默认尺寸、间距、移动端排布和大屏缩放方案仅在无明确原稿时采用;原稿已有规则时按其视觉及响应式实现,保留项目功能、主题切换与工程约束。当前源码与本文清单冲突时核实源码,不直接复制样例值。
11
+
10
12
  ## 一、CSS 变量体系
11
13
 
12
14
  ### 命名规范
@@ -371,7 +373,7 @@ $sideBarWidth: var(--sidebar-width, 208px);
371
373
  `.vts-page-card`:flex 填满 `.main-content:has(.vts-page-card)`,`overflow: hidden`,`.el-card__body` 高度 100%。样式在 `element-plus.scss` + `lay-content`。
372
374
  `--vts-margin` 可变(模板默认 8px);壳层对 `.main-content` 使用 **padding**(非 margin)承载该间距,定高链为 `height:100%`,避免「高度+外边距」撑出最外层滚动条。
373
375
 
374
- ⚠ **内容区间距双层结构(防叠加)**:`.app-main` 与 `.main-content` 是**父子两层盒**,同链消费 `--layout-content-padding → --vts-margin`(出厂各 8px)。调整内容区间距时**同一间距只允许一个权威来源**——优先重映射令牌(两层同变),禁止在一层抢写物理 `padding` 后任由另一层令牌保留非零值(父层 24px + 子层 8px = 32px/侧,「边距很大」;设计还原链路由 parser G6 与 design-audit E17 机检拦截)。
376
+ ⚠ **内容区间距双层结构(防叠加)**:`.app-main` 与 `.main-content` 是**父子两层盒**,同链消费 `--layout-content-padding → --vts-margin`(出厂各 8px)。调整内容区间距时**同一间距只允许一个权威来源**——优先重映射令牌(两层同变),禁止在一层抢写物理 `padding` 后任由另一层令牌保留非零值(父层 24px + 子层 8px = 32px/侧,「边距很大」)。改完后在浏览器实测两层的 `getComputedStyle(...).padding`,两层之和等于原稿值才算完成。
375
377
 
376
378
  ### 混合布局路由结构
377
379
 
@@ -485,7 +487,7 @@ src/styles/
485
487
 
486
488
  - [ ] 颜色均经 CSS 变量 / 令牌
487
489
  - [ ] `html.dark` 与至少 `light`/`default` 侧栏主题正常
488
- - [ ] 间距遵循 UnoCSS 4px 基数;字号用项目 token
490
+ - [ ] 无原稿时使用项目间距和字号档位;还原时以原稿实值更新或映射 token,不强制四舍五入到 4px 基数
489
491
 
490
492
  ## 九、PC / 移动双端
491
493
 
@@ -500,7 +502,7 @@ src/styles/
500
502
 
501
503
  ## 十、数据大屏
502
504
 
503
- 完整约定 → **`data-screen`**。摘要:1920×1080 + `scale`;独立布局无菜单页头;图表用 ECharts。
505
+ 读取 **`data-screen`**。先按原稿选择固定画布等比缩放或流式响应式;无原稿的固定画布任务可用 1920×1080 + `scale` 默认方案。保留项目已有图表封装与业务导航,仅在任务明确要求时使用独立全屏布局。
504
506
 
505
507
  ## 十一、反例(短)
506
508
 
@@ -509,7 +511,7 @@ src/styles/
509
511
  | 硬编码颜色 | CSS 变量 / 令牌 |
510
512
  | 只写亮色 | 同步 `dark.scss` |
511
513
  | 移动直接复用 PC 表格 | `mobile-h5` 卡片列表 |
512
- | 大屏用流式 flex 替代 scale | 见 `data-screen` |
514
+ | 用固定画布模板覆盖响应式原稿,或反之 | 按原稿选择适配方式并验证全部请求视口 |
513
515
  | 直接改 `--el-color-primary` | `setEpThemeColor()` |
514
516
  | scoped 内写 `:root` / `html.dark` | 放全局样式文件 |
515
517
  | 侧栏样式不测 3 种布局 | 改后回归验证 |
@@ -0,0 +1,48 @@
1
+ # 原稿对照验收
2
+
3
+ ## 1. 固定比较条件
4
+
5
+ - 从交接逐一列出所有视图、区域及 acceptance 条目,结合实施映射建立验收全集;不从实现中挑选已经完成的元素作为分母。
6
+ - 使用相同浏览器、视口、DPR、缩放、主题、字体及滚动位置打开原稿与目标真实路由。等待 `document.fonts.ready`、图片加载及页面布局稳定,暂停会造成截图漂移的非业务动画。
7
+ - 保留实际路由、登录和权限流程;使用用户已授权会话。需要登录而会话不可用时请用户登录;不得内置账号、绕过鉴权或以关闭权限换取截图。
8
+ - 无浏览器时完成静态检查并标记所有渲染验收未执行;不安装未经允许的浏览器依赖,不把源码值当作实测值。
9
+ - 完成条件:原稿和目标的环境可比,差异条件已记录,验收全集已固定。
10
+
11
+ ## 2. 按区域核对
12
+
13
+ - 先对比整体截图,再逐区域裁切对比。检查外壳尺寸与偏移、内容边界、对齐、滚动、控件间距、字体行高、图标路径/线宽、边框圆角、阴影、图片裁切和伪元素。
14
+ - 采集对应节点的 `getBoundingClientRect()` 与实际绘制层 `getComputedStyle()`;每个预期实例分别检查。相同角色存在多个实例时不得以其中一个通过代替全部。
15
+ - 缺失、隐藏、尺寸为零、被遮挡或选择器未命中的必需元素记 `fail`,不记 `skip`。
16
+ - 检查表头换行、长文本、操作列裁切、表格横向滚动及固定列底色、弹层层级、菜单折叠和页签激活/关闭。
17
+ - 可比内容相同时保留全图及区域像素 diff/叠加图;记录工具、算法、阈值、差异像素及区域。没有像素工具时保留并排/叠加图与几何实测,注明「未做像素级检查」。
18
+ - 将尺寸、坐标、间距的目标设为零偏差;亚像素舍入和抗锯齿差异须逐类说明。不得用统一 ±2px 或宽松百分比吞掉可修复偏差。
19
+ - Demo 与项目业务内容不同时,仅对映射后可比的视觉外壳、样式和布局规则做比较;记录非可比文本、数量和业务区域。禁止改业务数据或大面积蒙版后声称全图相同。
20
+ - 完成条件:每个验收条目都有对应实例、证据与 `pass` / `fail` / `unverified`;业务不匹配条目另标 `not-applicable` 并附映射依据,不计作已还原。
21
+
22
+ ## 3. 状态与响应式
23
+
24
+ - 逐一复现原稿观察到的悬停、焦点、禁用、选中、展开、弹窗等状态;状态切换后重新截图和测量。
25
+ - 对原稿提供的视口逐一验收;另测试项目支持范围内的窄屏、长内容、多列、多菜单及密度切换。
26
+ - 原稿未提供的断点和状态以项目行为回归为准,标为扩展适配,不声称与未知设计一致。
27
+ - 共享外壳或 `Re*` 修改时验证全部引用方的受影响能力;至少逐种独有页面结构、状态和主题核查,不只验收首个路由。
28
+ - 完成条件:已观察状态全部检查,项目扩展状态可用,未提供设计的部分与未测试部分明确区分。
29
+
30
+ ## 4. 定位并修正
31
+
32
+ - 按「来源版本 → 素材/字体 → 挂载及实例 → 盒模型/父布局 → 组件内部绘制层 → 变量/层叠 → 状态」定位差异。
33
+ - 在源码中修正实际原因;保持设计参考图只读,保留未修正截图。原稿证实提取错误时更正交接并记录证据。
34
+ - 每轮保存差异位置、原因、修改文件与复测结果;新一轮发现其他区域回归时一并修复。
35
+ - 未解决差异继续迭代;能力或来源受限时报告阻塞,不把阈值调大,不把失败删出分母。
36
+ - 完成条件:请求范围无未解释的可修复差异;所有尚未满足项保持未完成。
37
+
38
+ ## 5. 保存结果
39
+
40
+ - 保存 `.design/<任务名>/verification.json`,包含以下字段:
41
+ - `handoff`:交接相对路径及 SHA-256。
42
+ - `environment`:原稿和目标 URL/路径、浏览器、视口、DPR、缩放、主题、字体。
43
+ - `checks`:每项的视图/区域/验收点、目标定位与实例、状态、实测、截图路径、差异及修正记录。
44
+ - `business`:业务基线逐项对照、实际操作、预期/实际行为、结果与证据。
45
+ - `engineering`:实际执行命令、退出码和日志位置;区分既有错误与新增错误。
46
+ - `unresolved`:全部缺口、不可比范围及未验证项目。
47
+ - 打开参考图、结果图和差异图确认可读取;核对结果中的路径、值和统计与真实输出一致。
48
+ - 仅当请求范围工程、业务与视觉检查均通过,且无未解决必需项时报告完成。只在完整可比范围实际零像素差时声明该范围「像素一致」,不从局部推断全站 100%。