@brushes/schema-to-view 1.0.0

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.
package/package.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "name": "@brushes/schema-to-view",
3
+ "version": "1.0.0",
4
+ "description": "根据 UI 截图/设计稿动态生成低代码平台 JSON schema。当用户提供 UI 图片要求生成页面、将设计稿转为低代码页面、根据截图创建页面 JSON、图片转 Schema 时使用此 skill。触发条件:UI 截图 + 低代码、设计稿转代码、图片生成页面、schema 生成",
5
+ "keywords": ["@brushes/schema-to-view"]
6
+ }
@@ -0,0 +1,487 @@
1
+ # Schema-to-View 组件目录 & 示例
2
+
3
+ ## 组件全量目录(从真实 pageModel 提取)
4
+
5
+ ### ContainerWrap — 根容器
6
+ ```json
7
+ {
8
+ "type": {"resolvedName": "ContainerWrap"},
9
+ "isCanvas": true,
10
+ "props": {
11
+ "width": "100",
12
+ "height": 0,
13
+ "background": "#00000000",
14
+ "className": "root-container",
15
+ "data-cy": "root-container"
16
+ },
17
+ "displayName": "ContainerWrap",
18
+ "custom": {},
19
+ "hidden": false,
20
+ "nodes": [],
21
+ "linkedNodes": {}
22
+ }
23
+ ```
24
+
25
+ ### OutContainer — 外容器
26
+ ```json
27
+ {
28
+ "type": {"resolvedName": "OutContainer"},
29
+ "isCanvas": true,
30
+ "props": {
31
+ "params": [],
32
+ "width": "1400",
33
+ "height": "auto",
34
+ "backgroundImage": "",
35
+ "background": "rgba(255,255,255,0)",
36
+ "flexDirection": "column"
37
+ },
38
+ "displayName": "外容器",
39
+ "custom": {},
40
+ "hidden": false,
41
+ "parent": "ROOT",
42
+ "nodes": [],
43
+ "linkedNodes": {}
44
+ }
45
+ ```
46
+
47
+ ### Container — 容器(Flexbox)
48
+ ```json
49
+ {
50
+ "type": {"resolvedName": "Container"},
51
+ "isCanvas": true,
52
+ "props": {
53
+ "width": "100%",
54
+ "height": "auto",
55
+ "background": "rgba(255,255,255,0)",
56
+ "backgroundImage": "",
57
+ "flexDirection": "row",
58
+ "justifyContent": "flex-start",
59
+ "alignItems": "flex-start",
60
+ "margin": {},
61
+ "padding": {},
62
+ "positionValue": {},
63
+ "boxShadow": "",
64
+ "color": "",
65
+ "borderRadius": 0
66
+ },
67
+ "displayName": "容器",
68
+ "custom": {},
69
+ "hidden": false,
70
+ "parent": "",
71
+ "nodes": [],
72
+ "linkedNodes": {}
73
+ }
74
+ ```
75
+
76
+ ### Text — 文本(完整示例:商品名称)
77
+ ```json
78
+ {
79
+ "type": {"resolvedName": "Text"},
80
+ "isCanvas": false,
81
+ "props": {
82
+ "module": "moduleStore",
83
+ "storeKey": "_skuInfo",
84
+ "fontWeight": 700,
85
+ "fontSize": 14,
86
+ "num": 1,
87
+ "color": "#444",
88
+ "text": "默认文本",
89
+ "textAlign": "left",
90
+ "padding": {},
91
+ "margin": {"marginTop": 5, "marginBottom": 10},
92
+ "code": "goodsName",
93
+ "width": 190
94
+ },
95
+ "displayName": "文本",
96
+ "custom": {},
97
+ "hidden": false,
98
+ "parent": "",
99
+ "nodes": [],
100
+ "linkedNodes": {}
101
+ }
102
+ ```
103
+ Text props 完整列表:`text`, `fontSize`, `color`, `fontWeight`, `num`(行数截断), `textAlign`, `width`, `height`, `lineHeight`, `minWidth`, `module`(`"moduleStore"`|`"rootStore"`), `storeKey`, `code`(lodash get 路径), `transformData`(`"time"`|`"format"`|`"dataType"`), `format`(日期格式如`"YYYY-MM-DD HH:mm:ss"`), `localScheme: [{label, value}]`, `className`, `padding`, `margin`, `contain`
104
+
105
+ ### ImageComponent — 图片
106
+ ```json
107
+ {
108
+ "type": {"resolvedName": "ImageComponent"},
109
+ "isCanvas": false,
110
+ "props": {
111
+ "width": "100%",
112
+ "height": 250,
113
+ "storeKey": "_skuInfo",
114
+ "image": {"imgUrl": ""},
115
+ "code": "dataPic",
116
+ "borderRadius": 6
117
+ },
118
+ "displayName": "图片",
119
+ "custom": {},
120
+ "hidden": false,
121
+ "parent": "",
122
+ "nodes": [],
123
+ "linkedNodes": {}
124
+ }
125
+ ```
126
+ 额外 props: `objectFit`
127
+
128
+ ### DividerComponent — 分割线
129
+ ```json
130
+ {
131
+ "type": {"resolvedName": "DividerComponent"},
132
+ "isCanvas": false,
133
+ "props": {
134
+ "dashed": false,
135
+ "plain": false,
136
+ "borderWidth": 1,
137
+ "orientationMargin": 0,
138
+ "orientation": "center",
139
+ "type": "horizontal",
140
+ "margin": {"marginBottom": 0, "marginLeft": 0, "marginRight": 0, "marginTop": 0},
141
+ "borderColor": "#f1f1f1"
142
+ },
143
+ "displayName": "线条",
144
+ "custom": {},
145
+ "hidden": false,
146
+ "parent": "",
147
+ "nodes": [],
148
+ "linkedNodes": {}
149
+ }
150
+ ```
151
+
152
+ ### BreadcrumbComponent — 面包屑
153
+ ```json
154
+ {
155
+ "type": {"resolvedName": "BreadcrumbComponent"},
156
+ "isCanvas": false,
157
+ "props": {"color": "#444", "fontSize": 12, "fontWeight": 400},
158
+ "displayName": "面包屑",
159
+ "custom": {},
160
+ "hidden": false,
161
+ "parent": "",
162
+ "nodes": [],
163
+ "linkedNodes": {}
164
+ }
165
+ ```
166
+
167
+ ### GoodCategoryComponent — 商品分类
168
+ ```json
169
+ {
170
+ "type": {"resolvedName": "GoodCategoryComponent"},
171
+ "isCanvas": false,
172
+ "props": {
173
+ "label": "All Fixtures",
174
+ "color": "#444",
175
+ "fontSize": 12,
176
+ "fontWeight": 400,
177
+ "goodsClassName": "goodsClassName",
178
+ "goodsClassCode": "goodsClassCode",
179
+ "api": "/web/rs/rsGoodsClass/queryGoodsClassTreeForBusStr.json",
180
+ "lastCode": "classtreeCode"
181
+ },
182
+ "displayName": "商品分类",
183
+ "custom": {},
184
+ "hidden": false,
185
+ "parent": "",
186
+ "nodes": [],
187
+ "linkedNodes": {}
188
+ }
189
+ ```
190
+
191
+ ### SortComponent — 排序
192
+ ```json
193
+ {
194
+ "type": {"resolvedName": "SortComponent"},
195
+ "isCanvas": false,
196
+ "props": {
197
+ "color": "#444",
198
+ "fontSize": 12,
199
+ "fontWeight": 400,
200
+ "config": [
201
+ {"label": "Default", "value": ""},
202
+ {"label": "Newest", "value": "skuHdate"},
203
+ {"label": "Best Sellers", "value": "pricesetNprice"}
204
+ ]
205
+ },
206
+ "displayName": "商品排序",
207
+ "custom": {},
208
+ "hidden": false,
209
+ "parent": "",
210
+ "nodes": [],
211
+ "linkedNodes": {}
212
+ }
213
+ ```
214
+
215
+ ### ApiComponent — API 列表
216
+ ```json
217
+ {
218
+ "type": {"resolvedName": "ApiComponent"},
219
+ "isCanvas": false,
220
+ "props": {
221
+ "componentType": "list",
222
+ "gap": 10,
223
+ "num": 5,
224
+ "cacheParams": false,
225
+ "isSearch": true,
226
+ "pageSize": 15,
227
+ "defaultValue": "{}",
228
+ "dataPath": "list",
229
+ "description": "No products found",
230
+ "margin": {"marginTop": 15, "marginBottom": 5, "marginLeft": 0, "marginRight": 0},
231
+ "pagination": true,
232
+ "api": "web/es/searchengine/find.json",
233
+ "rows": 24,
234
+ "params": [
235
+ {"key": "goodsClassParentcode", "value": ""},
236
+ {"key": "classtreeCode"},
237
+ {"key": "searchParam"},
238
+ {"key": "goodsType", "value": "00,40,07,12"},
239
+ {"key": "bizType", "value": "sku"},
240
+ {"key": "goodsOrigin", "value": "0,8,6,11,26"},
241
+ {"key": "order"}
242
+ ]
243
+ },
244
+ "displayName": "API组件",
245
+ "custom": {},
246
+ "hidden": false,
247
+ "parent": "",
248
+ "nodes": [],
249
+ "linkedNodes": {"card-basic": "<template-container-id>"}
250
+ }
251
+ ```
252
+
253
+ ### CardComponent — 卡片(含点击跳转)
254
+ ```json
255
+ {
256
+ "type": {"resolvedName": "CardComponent"},
257
+ "isCanvas": false,
258
+ "props": {
259
+ "borderRadius": 6,
260
+ "borderColor": "#f4f4f4",
261
+ "padding": {"paddingLeft": 4, "paddingRight": 4, "paddingTop": 4, "paddingBottom": 4},
262
+ "$_actions": "...source code...",
263
+ "$$_actions": "...compiled code..."
264
+ },
265
+ "displayName": "商品卡片",
266
+ "custom": {},
267
+ "hidden": false,
268
+ "parent": "",
269
+ "nodes": [],
270
+ "linkedNodes": {"card-top": "<card-content-container-id>"}
271
+ }
272
+ ```
273
+
274
+ ### CardLRComponent — 左右卡片
275
+ ```json
276
+ {
277
+ "type": {"resolvedName": "CardLRComponent"},
278
+ "isCanvas": false,
279
+ "props": {
280
+ "borderRadius": 6,
281
+ "borderColor": "rgba(0,0,0,0)",
282
+ "padding": {"paddingLeft": 4, "paddingRight": 4, "paddingTop": 4, "paddingBottom": 4}
283
+ },
284
+ "displayName": "左右卡片",
285
+ "custom": {},
286
+ "hidden": false,
287
+ "parent": "",
288
+ "nodes": [],
289
+ "linkedNodes": {}
290
+ }
291
+ ```
292
+
293
+ ### GoodNumberComponent — 数量选择
294
+ ```json
295
+ {
296
+ "type": {"resolvedName": "GoodNumberComponent"},
297
+ "isCanvas": false,
298
+ "props": {
299
+ "width": 80,
300
+ "storeKey": "_skuInfo",
301
+ "stepKey": "goodsTopnum",
302
+ "min": "goodsMinnum",
303
+ "max": "goodsSupplynum",
304
+ "saveStoreKey": "goodNum"
305
+ },
306
+ "displayName": "商品数量",
307
+ "custom": {},
308
+ "hidden": false,
309
+ "parent": "",
310
+ "nodes": [],
311
+ "linkedNodes": {}
312
+ }
313
+ ```
314
+
315
+ ### AddCartComponent — 加入购物车
316
+ ```json
317
+ {
318
+ "type": {"resolvedName": "AddCartComponent"},
319
+ "isCanvas": false,
320
+ "props": {
321
+ "type": "default",
322
+ "text": "加入购物车",
323
+ "car": {},
324
+ "margin": {"marginLeft": 10}
325
+ },
326
+ "displayName": "加入购物车",
327
+ "custom": {},
328
+ "hidden": false,
329
+ "parent": "",
330
+ "nodes": [],
331
+ "linkedNodes": {}
332
+ }
333
+ ```
334
+
335
+ ### BuyComponent — 立即购买
336
+ ```json
337
+ {
338
+ "type": {"resolvedName": "BuyComponent"},
339
+ "isCanvas": false,
340
+ "props": {
341
+ "type": "default",
342
+ "text": "立即购买",
343
+ "car": {},
344
+ "goGoodsType": true,
345
+ "margin": {"marginLeft": 10}
346
+ },
347
+ "displayName": "立即购买",
348
+ "custom": {},
349
+ "hidden": false,
350
+ "parent": "",
351
+ "nodes": [],
352
+ "linkedNodes": {}
353
+ }
354
+ ```
355
+
356
+ ### ButtonWrap — 按钮外轮廓(渐变色按钮)
357
+ ```json
358
+ {
359
+ "type": {"resolvedName": "ButtonWrap"},
360
+ "isCanvas": false,
361
+ "props": {
362
+ "letterSpacing": 1,
363
+ "fontWeight": 400,
364
+ "startColor": "#fa4c4c",
365
+ "color": "#fff",
366
+ "endColor": "#dc7200",
367
+ "padding": {"paddingTop": 2, "paddingBottom": 2, "paddingLeft": 2, "paddingRight": 2}
368
+ },
369
+ "displayName": "按钮外轮廓",
370
+ "custom": {},
371
+ "hidden": false,
372
+ "parent": "",
373
+ "nodes": [],
374
+ "linkedNodes": {"container-linear": "<inner-container-id>"}
375
+ }
376
+ ```
377
+
378
+ ### IsShowContainer — 条件显示
379
+ ```json
380
+ {
381
+ "type": {"resolvedName": "IsShowContainer"},
382
+ "isCanvas": true,
383
+ "props": {
384
+ "margin": {},
385
+ "isRevert": true,
386
+ "padding": {"paddingTop": 5, "paddingBottom": 5},
387
+ "routerIsShowValue": "",
388
+ "moduleIsShow": "goodsType",
389
+ "moduleShowValue": "07,12,26",
390
+ "storeKey": "_skuInfo"
391
+ },
392
+ "displayName": "条件容器",
393
+ "custom": {},
394
+ "hidden": false,
395
+ "parent": "",
396
+ "nodes": [],
397
+ "linkedNodes": {}
398
+ }
399
+ ```
400
+
401
+ ### NumberComponent — 数字
402
+ ```json
403
+ {
404
+ "type": {"resolvedName": "NumberComponent"},
405
+ "isCanvas": false,
406
+ "props": {"precision": 2},
407
+ "displayName": "数字组件",
408
+ "custom": {},
409
+ "hidden": false,
410
+ "parent": "",
411
+ "nodes": [],
412
+ "linkedNodes": {}
413
+ }
414
+ ```
415
+
416
+ ### NavigatorComponent — 导航
417
+ ```json
418
+ {
419
+ "type": {"resolvedName": "NavigatorComponent"},
420
+ "isCanvas": false,
421
+ "props": {
422
+ "menu": [{"title": "默认导航"}],
423
+ "isNeedLine": true,
424
+ "className": "nav"
425
+ },
426
+ "displayName": "导航",
427
+ "custom": {},
428
+ "hidden": false,
429
+ "parent": "",
430
+ "nodes": [],
431
+ "linkedNodes": {}
432
+ }
433
+ ```
434
+
435
+ ### BannerComponent — 轮播图
436
+ ```json
437
+ {
438
+ "type": {"resolvedName": "BannerComponent"},
439
+ "isCanvas": false,
440
+ "props": {
441
+ "borderRadius": 0,
442
+ "autoplay": {"dotDuration": true},
443
+ "menu": [{"imgUrl": "https://..."}]
444
+ },
445
+ "displayName": "轮播图",
446
+ "custom": {},
447
+ "hidden": false,
448
+ "parent": "",
449
+ "nodes": [],
450
+ "linkedNodes": {}
451
+ }
452
+ ```
453
+
454
+ ## linkedNodes 规则
455
+
456
+ 以下组件使用 linkedNodes 声明命名插槽:
457
+
458
+ | 组件 | linkedNode key | 说明 |
459
+ |------|---------------|------|
460
+ | `ApiComponent` | `"card-basic"` | 列表项模板容器 |
461
+ | `CardComponent` | `"card-top"` | 卡片内容区 |
462
+ | `ButtonWrap` | `"container-linear"` | 按钮内部容器 |
463
+
464
+ linkedNode 本身是一个完整节点,需要:
465
+ - 在字典中作为独立 key 存在
466
+ - `parent` 指向引用它的组件 ID
467
+ - 可以有自己的 `nodes`(子节点)
468
+
469
+ ## 典型数据字段 code 值
470
+
471
+ 常用于 `Text` 和 `ImageComponent`:
472
+
473
+ | code | 含义 |
474
+ |------|------|
475
+ | `goodsName` | 商品名称 |
476
+ | `goodsShowno` | 商品编码 |
477
+ | `goodsType` | 商品类型 |
478
+ | `pricesetNprice` | 销售价格 |
479
+ | `dataPic` | 商品图片 |
480
+ | `skuName` | 规格名称 |
481
+ | `skuCode` | SKU 编码 |
482
+ | `skuNo` | SKU 号 |
483
+ | `goodsTopnum` | 起购数量 |
484
+ | `goodsMinnum` | 最小数量 |
485
+ | `goodsSupplynum` | 供应数量 |
486
+ | `firstAvailableDate` | 最早可交付日期 |
487
+ | `partsnameWeightunit` | 重量单位 |
@@ -0,0 +1,322 @@
1
+ ---
2
+ name: schema-to-view
3
+ description: >
4
+ 根据 UI 截图/设计稿动态生成低代码平台 JSON schema。当用户提供 UI 图片要求生成页面、
5
+ 将设计稿转为低代码页面、根据截图创建页面 JSON、图片转 Schema 时使用此 skill。
6
+ 触发条件:UI 截图 + 低代码、设计稿转代码、图片生成页面、schema 生成。
7
+ argument-hint: "[UI截图路径]"
8
+ allowed-tools: Bash(ls mkdir) Read Write Edit Glob Grep mcp__image-vision-mcp__* mcp__zai-mcp-server__*
9
+ paths: "pageModels/**,apps/editor/**,packages/component-ui/**"
10
+ ---
11
+
12
+ # Schema-to-View:UI 截图 → 低代码 JSON Schema
13
+
14
+ 将 UI 设计稿/截图转换为 web-lowcode 平台可用的 JSON schema 文件。
15
+
16
+ ## 执行流程
17
+
18
+ ### 第一步:分析 UI 截图
19
+
20
+ 使用 MCP 视觉工具分析用户提供的 UI 图片:
21
+
22
+ ```
23
+ mcp__zai-mcp-server__analyze_image 或 mcp__image-vision-mcp__image_understanding
24
+ ```
25
+
26
+ 分析要点:
27
+ - 页面整体布局(行列结构、侧边栏、内容区)
28
+ - 识别每个区域中的 UI 元素类型(文本、图片、按钮、卡片、列表等)
29
+ - 元素之间的层级关系
30
+ - 颜色、字号、间距等样式细节
31
+
32
+ ### 第二步:映射到组件
33
+
34
+ 将识别出的 UI 元素映射为低代码平台组件。可用组件及分类:
35
+
36
+ #### 布局容器
37
+ | resolvedName | 用途 | 关键 props |
38
+ |---|---|---|
39
+ | `ContainerWrap` | 根容器(必须有,节点 ID 固定为 `ROOT`) | `width`, `height`, `background`, `className`, `data-cy` |
40
+ | `OutContainer` | 页面外容器(ROOT 唯一子节点) | `params`, `width`(默认1400), `height`, `background`, `flexDirection` |
41
+ | `Container` | 弹性布局容器 | `width`, `height`, `flexDirection`, `justifyContent`, `alignItems`, `background`, `padding`, `margin`, `borderRadius`, `boxShadow` |
42
+ | `IsShowContainer` | 条件显示容器 | `isRevert`, `storeKey`, `moduleIsShow`, `moduleShowValue`, `routerIsShowValue` |
43
+
44
+ #### 基础组件 (basic)
45
+ | resolvedName | 用途 | 关键 props |
46
+ |---|---|---|
47
+ | `Text` | 文本(支持数据绑定+转换) | `text`, `module("moduleStore"/"rootStore")`, `storeKey("_skuInfo")`, `code`(数据字段路径), `fontSize`, `color`, `fontWeight`, `num`(行数), `textAlign`, `transformData`(`"time"`/`"format"`/`"dataType"`), `format`(日期格式), `localScheme`(码表) |
48
+ | `ImageComponent` | 图片(支持数据绑定) | `width`, `height`, `image: { imgUrl: "" }`, `code`(如`"dataPic"`), `storeKey`, `borderRadius`, `objectFit` |
49
+ | `DividerComponent` | 分割线 | `borderWidth`, `borderColor`, `dashed`, `type("horizontal"/"vertical")`, `margin` |
50
+ | `LinkComponent` | 超链接 | `image: { imgUrl, link }`, `text`, `fontSize` |
51
+ | `FormComponent` | 表单外层容器 | `formName`, `api`, `saveText`, `disabled`, `padding` |
52
+ | `ApiComponent` | API 数据列表 | `api`, `componentType("list")`, `dataPath("list")`, `pageSize`, `num`, `pagination`, `params`, `margin`, `description`(空状态文本), `linkedNodes: { "card-basic": "<template-node-id>" }` |
53
+ | `Button` | 按钮 | 通过 Operate 和 Materials 引用 |
54
+
55
+ #### 业务组件 (service)
56
+ | resolvedName | 用途 | 关键 props |
57
+ |---|---|---|
58
+ | `NavigatorComponent` | 导航栏 | `menu: [{ title }]`, `isNeedLine`, `className` |
59
+ | `CardLRComponent` | 左右卡片布局 | `borderRadius`, `borderColor`, `padding` |
60
+ | `BreadcrumbComponent` | 面包屑 | `color`, `fontSize`, `fontWeight` |
61
+ | `GoodCategoryComponent` | 商品分类树 | `api`, `label`, `color`, `fontSize`, `goodsClassName`, `goodsClassCode`, `lastCode` |
62
+ | `SortComponent` | 排序选择器 | `config: [{ label, value }]`, `color`, `fontSize`, `fontWeight` |
63
+ | `SearchComponent` | 搜索组件 | 搜索相关 props |
64
+ | `CommonListComponent` | 详情页列表 | `dataPath`, `storeKey`, `description`, `defaultKey`, `padding` |
65
+ | `CommmonItem` | 单行条目 | `draggable`, `list`, `speed`, `margin`, `padding` |
66
+ | `NumberComponent` | 数字组件 | `precision` |
67
+ | `ButtonWrap` | 按钮外轮廓 | `letterSpacing`, `fontWeight`, `startColor`, `endColor`, `color`, `padding`, `linkedNodes: { "container-linear": "<id>" }` |
68
+ | `GoodNumberComponent` | 数量选择器 | `width`, `storeKey`, `stepKey`, `min`, `max`, `saveStoreKey` |
69
+ | `MapComponent` | 地图 | 地图相关 props |
70
+ | `Amount` | 金额展示 | 金额相关 props |
71
+
72
+ #### 操作组件 (operate)
73
+ | resolvedName | 用途 | 关键 props |
74
+ |---|---|---|
75
+ | `LogoinComponent` | 登录 | `isNeedRegister`, `protocol`, `type` |
76
+ | `DynamicFormComponent` | 动态表单 | `fieldConfig: []` |
77
+ | `AddCartComponent` | 加入购物车 | `type("default")`, `text`, `car: {}`, `margin` |
78
+ | `BuyComponent` | 立即购买 | `type("default")`, `text`, `car: {}`, `goGoodsType`, `margin` |
79
+ | `SaveComponent` | 保存操作 | 保存相关 props |
80
+ | `LogoutComponent` | 退出登录 | 退出相关 props |
81
+
82
+ #### 复合组件 (components/Materials)
83
+ | resolvedName | 用途 | 关键 props |
84
+ |---|---|---|
85
+ | `CardComponent` | 卡片 | `borderRadius`, `borderColor`, `background`, `boxShadow`, `padding`, `linkedNodes: { "card-top": "<id>" }`, `$_actions`/`$$_actions`(点击跳转) |
86
+ | `BannerComponent` | 轮播图 | `borderRadius`, `autoplay`, `menu: [{ imgUrl }]` |
87
+ | `TabComponent` | 标签页 | `columns: [{ label, key }]`, `fontSize`, `tabPosition` |
88
+ | `AutoTabComponent` | 动态标签页 | `columns: [{ label, key, code }]`, `storeKey`, `keyName`, `fontSize`, `tabPosition` |
89
+ | `RichTextComponent` | 富文本 | `columns` |
90
+ | `DrawerComponent` | 抽屉 | `width`, `destroyOnHidden`, `code`, `placement` |
91
+ | `FormJsxComponent` | 表单 JSX | `formName`, `openKey`, `api`, `activeModule`, `saveText`, `type` |
92
+
93
+ ### 第三步:生成 JSON Schema
94
+
95
+ #### Schema 结构规则
96
+
97
+ JSON schema 是一个 **扁平字典** `Record<NodeId, SerializedNode>`,唯一特殊节点是 `"ROOT"`。
98
+
99
+ #### 单个节点结构
100
+ ```json
101
+ {
102
+ "type": { "resolvedName": "组件名" },
103
+ "isCanvas": true/false, // 能否包含子节点
104
+ "props": { /* 组件属性 */ },
105
+ "displayName": "中文显示名",
106
+ "custom": {},
107
+ "hidden": false,
108
+ "parent": "父节点ID", // ROOT 节点的 parent 为 "ROOT"
109
+ "nodes": ["子节点ID数组"], // 没子节点就是 []
110
+ "linkedNodes": {} // 命名插槽,普通节点为 {}
111
+ }
112
+ ```
113
+
114
+ #### namedNode ID 生成规则
115
+
116
+ - 格式:8-10 位大小写字母数字混合
117
+ - 示例:`"FKp8Qm3vNx"`, `"FCd9Wr8dGf"`, `"sN6ZG4fCJK"`
118
+ - 每个 ID 在整个 JSON 中唯一
119
+ - 可任意生成,但要确保 `parent` 和 `nodes` 引用的 ID 都存在
120
+
121
+ #### 构建步骤
122
+
123
+ 1. **创建 ROOT 节点**(固定模板):
124
+ ```json
125
+ "ROOT": {
126
+ "type": { "resolvedName": "ContainerWrap" },
127
+ "isCanvas": true,
128
+ "props": {
129
+ "width": "100",
130
+ "height": 0,
131
+ "background": "#00000000",
132
+ "className": "root-container",
133
+ "data-cy": "root-container"
134
+ },
135
+ "displayName": "ContainerWrap",
136
+ "custom": {},
137
+ "hidden": false,
138
+ "nodes": ["<outContainerId>"],
139
+ "linkedNodes": {}
140
+ }
141
+ ```
142
+
143
+ 2. **创建 OutContainer**(ROOT 的直接子节点):
144
+ ```json
145
+ "<outContainerId>": {
146
+ "type": { "resolvedName": "OutContainer" },
147
+ "isCanvas": true,
148
+ "props": {
149
+ "params": [],
150
+ "width": "1400",
151
+ "height": "auto",
152
+ "backgroundImage": "",
153
+ "background": "rgba(255,255,255,0)",
154
+ "flexDirection": "column"
155
+ },
156
+ "displayName": "外容器",
157
+ "custom": {},
158
+ "parent": "ROOT",
159
+ "hidden": false,
160
+ "nodes": ["<top-level-children>..."],
161
+ "linkedNodes": {}
162
+ }
163
+ ```
164
+
165
+ 3. **构建布局树**:根据 UI 分析结果,用 Container 组件构建行列布局
166
+
167
+ 4. **放入内容组件**:在合适的 Container 中放入 Text、Image、Button 等
168
+
169
+ 5. **处理数据列表**:如果有列表,使用 ApiComponent + linkedNodes 模式
170
+
171
+ 6. **验证完整性**:确保所有 `parent`、`nodes`、`linkedNodes` 引用的 ID 都存在
172
+
173
+ ### 第四步:输出 JSON 文件
174
+
175
+ 将生成的 JSON 写入 `pageModels/` 目录(单行,无格式化):
176
+ ```
177
+ Write: pageModels/{name}.json
178
+ ```
179
+
180
+ ## 典型页面模板
181
+
182
+ ### 商品列表页(最常用)
183
+
184
+ ```
185
+ ROOT → OutContainer
186
+ ├── Container(row, 100%) ← 顶栏/面包屑
187
+ │ └── Container(column)
188
+ │ ├── BreadcrumbComponent
189
+ │ └── Text ← 页面标题
190
+ ├── Container(row, 100%) ← 分类侧栏 + 内容区
191
+ │ ├── Container(100px, sidebar) ← 侧栏
192
+ │ │ └── Text ← "Category"
193
+ │ └── Container(1300px, content) ← 内容区
194
+ │ └── GoodCategoryComponent
195
+ ├── DividerComponent ← 分割线
196
+ ├── Container(row, 100%) ← 排序栏
197
+ │ ├── Container(100px, sidebar)
198
+ │ │ └── Text ← "Sort By"
199
+ │ └── Container(1300px)
200
+ │ └── SortComponent
201
+ └── Container(column) ← 商品列表区
202
+ └── ApiComponent ← API 数据
203
+ └── [linkedNode: card-basic]
204
+ └── Container
205
+ └── CardComponent
206
+ └── [linkedNode: card-top]
207
+ └── Container(column)
208
+ ├── ImageComponent ← 商品图
209
+ └── Container(column, 内容区)
210
+ ├── Text(goodsName) ← 商品名
211
+ ├── Container(row, 价格行)
212
+ │ ├── Text(pricesetNprice)
213
+ │ └── Text(收藏)
214
+ └── Text(goodsShowno) ← 商品编码
215
+ ```
216
+
217
+ ### 商品详情页
218
+
219
+ ```
220
+ ROOT → OutContainer
221
+ ├── DividerComponent
222
+ └── Container(column)
223
+ └── ApiComponent
224
+ └── [card-basic] → Container
225
+ └── CardComponent
226
+ └── [card-top] → Container(column)
227
+ ├── ImageComponent ← 商品大图
228
+ └── Container(column)
229
+ ├── Text(goodsName) ← 商品名
230
+ ├── Container(row) ← 规格行
231
+ │ ├── Text("SKU编码:")
232
+ │ └── Text(goodsShowno)
233
+ ├── Container(row) ← 价格行
234
+ │ ├── Text("¥")
235
+ │ ├── Text(pricesetNprice)
236
+ │ └── Text(单位)
237
+ └── Container(row, space-between) ← 操作行
238
+ ├── GoodNumberComponent ← 数量
239
+ └── Container(column)
240
+ ├── IsShowContainer → AddCartComponent
241
+ └── IsShowContainer → ButtonWrap
242
+ └── [container-linear]
243
+ └── Container → BuyComponent
244
+ ```
245
+
246
+ ## 组件 Props 完整参考
247
+
248
+ ### 通用 css 属性(多数组件都支持)
249
+ ```json
250
+ {
251
+ "margin": { "marginTop": 5, "marginBottom": 5, "marginLeft": 0, "marginRight": 0 },
252
+ "padding": { "paddingTop": 5, "paddingBottom": 5, "paddingLeft": 5, "paddingRight": 5 }
253
+ }
254
+ ```
255
+
256
+ ### 文本组件数据绑定三要素
257
+ ```json
258
+ {
259
+ "module": "moduleStore", // 数据来源级别
260
+ "storeKey": "_skuInfo", // store 中的 key
261
+ "code": "goodsName" // 数据字段路径(用 lodash.get 取值)
262
+ }
263
+ ```
264
+
265
+ ### ApiComponent 列表模式
266
+ ```json
267
+ {
268
+ "componentType": "list",
269
+ "api": "web/es/searchengine/find.json",
270
+ "dataPath": "list",
271
+ "gap": 10,
272
+ "num": 5,
273
+ "pageSize": 15,
274
+ "pagination": true,
275
+ "params": [
276
+ { "key": "searchParam" },
277
+ { "key": "order" }
278
+ ],
279
+ "description": "暂无数据",
280
+ "margin": { "marginTop": 15, "marginBottom": 5, "marginLeft": 0, "marginRight": 0 }
281
+ }
282
+ ```
283
+
284
+ ### CardComponent 点击跳转
285
+ ```json
286
+ {
287
+ "$_actions": "import { useModuleContext } from \"@brushes/component-core\";\nimport { useNavigateImpl } from \"@brushes/component-tool\";\n\nfunction useDiyHook() {\n const skuInfo = useModuleContext(s=> s.moduleStore._skuInfo)\n const { navigator } = useNavigateImpl();\n return () => {\n navigator(`/goodDetail?skuCode=${skuInfo.skuCode}&skuNo=${skuInfo.skuNo}`);\n }\n}\nexport default useDiyHook;",
288
+ "$$_actions": "\"use strict\";Object.defineProperty(exports, \"__esModule\", {value: true});\nvar _componentcore = require('@brushes/component-core');\nvar _componenttool = require('@brushes/component-tool');\nfunction useDiyHook() {\n const skuInfo = _componentcore.useModuleContext.call(void 0, s=> s.moduleStore._skuInfo)\n const { navigator } = _componenttool.useNavigateImpl.call(void 0, );\n return () => {\n navigator(`/goodDetail?skuCode=${skuInfo.skuCode}&skuNo=${skuInfo.skuNo}`);\n }\n}\nexports. default = useDiyHook;"
289
+ }
290
+ ```
291
+
292
+ ### Container 完整 props
293
+ ```json
294
+ {
295
+ "width": "100%",
296
+ "height": "auto",
297
+ "background": "rgba(255,255,255,0)",
298
+ "backgroundImage": "",
299
+ "flexDirection": "row", // row | column
300
+ "justifyContent": "space-between", // flex-start | center | space-between | flex-end
301
+ "alignItems": "center",
302
+ "margin": {},
303
+ "padding": {},
304
+ "positionValue": {},
305
+ "boxShadow": "",
306
+ "color": "",
307
+ "borderRadius": 0
308
+ }
309
+ ```
310
+
311
+ ## 注意事项
312
+
313
+ 1. `ROOT` 节点 ID 必须是 `"ROOT"`,类型固定 `ContainerWrap`
314
+ 2. `ROOT.nodes[0]` 必须是 `OutContainer`
315
+ 3. 所有 `parent` 引用的 ID 必须是字典中存在的 key
316
+ 4. 所有 `nodes` 数组中的 ID 必须是字典中存在的 key
317
+ 5. `linkedNodes` 中的引用节点其 `parent` 要指向引用它的节点
318
+ 6. 每个节点的 `isCanvas` 设对:Container 类为 `true`,内容组件为 `false`
319
+ 7. JSON 输出为单行(compact),不要格式化
320
+ 8. 文本组件绑定数据必须同时设置 `module`, `storeKey`, `code`
321
+ 9. 生成后写入 `pageModels/{name}.json`
322
+ 10. Container (卡片外层) 比如4列网格布局 (width: 25% ❌) 不管一行多少个 (width: 100% ✅)