@szc-ft/mcp-szcd-client 0.24.0 → 0.26.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.
Files changed (34) hide show
  1. package/agents/build.js +22 -12
  2. package/agents/opencode-extension/agents/szcd-component-expert.md +235 -49
  3. package/agents/qwen-extension/agents/szcd-component-expert.md +235 -49
  4. package/agents/src/szcd-component-expert.md +262 -49
  5. package/agents/src/tools.json +1 -1
  6. package/agents/szcd-component-expert.md +235 -49
  7. package/agents/szcd-component-expert.qoder.md +261 -50
  8. package/agents/szcd-component-expert.trae.md +260 -49
  9. package/opencode-extension/agents/szcd-component-expert.md +235 -49
  10. package/opencode-extension/skills/local-api-tool/SKILL.md +296 -60
  11. package/opencode-extension/skills/local-api-tool/scripts/extract-swagger.mjs +625 -0
  12. package/opencode-extension/skills/local-api-tool/scripts/extract_swagger.py +593 -0
  13. package/opencode-extension/skills/szcd-component-helper/SKILL.md +7 -4
  14. package/opencode-extension/skills/szcd-design-to-code/SKILL.md +267 -25
  15. package/package.json +1 -1
  16. package/qwen-extension/agents/szcd-component-expert.md +235 -49
  17. package/qwen-extension/qwen-extension.json +1 -1
  18. package/qwen-extension/skills/local-api-tool/SKILL.md +296 -60
  19. package/qwen-extension/skills/local-api-tool/scripts/extract-swagger.mjs +625 -0
  20. package/qwen-extension/skills/local-api-tool/scripts/extract_swagger.py +593 -0
  21. package/qwen-extension/skills/szcd-component-helper/SKILL.md +7 -4
  22. package/qwen-extension/skills/szcd-design-to-code/SKILL.md +267 -25
  23. package/scripts/lib/claude-code.js +1 -1
  24. package/scripts/lib/common.js +44 -0
  25. package/scripts/lib/opencode.js +1 -1
  26. package/scripts/lib/qoder.js +1 -1
  27. package/scripts/lib/trae-cli.js +1 -1
  28. package/scripts/lib/trae-ide.js +1 -1
  29. package/scripts/postinstall.js +1 -0
  30. package/standard-skill/local-api-tool/SKILL.md +296 -60
  31. package/standard-skill/local-api-tool/scripts/extract-swagger.mjs +625 -0
  32. package/standard-skill/local-api-tool/scripts/extract_swagger.py +593 -0
  33. package/standard-skill/szcd-component-helper/SKILL.md +7 -4
  34. package/standard-skill/szcd-design-to-code/SKILL.md +267 -25
@@ -55,34 +55,62 @@ Ant Design → ProComponents → Cover 层 → Wrapper 层 → ProPackages →
55
55
 
56
56
  ### 步骤2.5:Sketch 文件解析(有 .sketch 文件时执行)
57
57
 
58
- **核心原则**:写代码之前必须拿到所有 `text` 和 `rectangle` 节点的完整样式 Token,禁止凭节点名猜测颜色/字号/背景色。`getMultipleNodeInfo` 支持任意数量 ID(内部自动分片),比逐个 `getNodeInfo` 快 10 倍以上。
58
+ **核心原则**:写代码之前必须拿到所有 `text`、`rectangle`、`group` 节点的完整样式 Token + 父子层级,禁止凭节点名猜测颜色/字号/背景色,禁止用 x 坐标平面判定元素归属。`queryNodes.type` 接受数组、`getMultipleNodeInfo` 内部自动分片,比逐个 `getNodeInfo` 快 10 倍以上。
59
59
 
60
- **工具调用顺序(优化后,4 次主调用)**:
60
+ **工具调用顺序(sketch-mcp-server ≥ v1.5.0,4 次主调用)**:
61
61
 
62
62
  1. `mcp__sketch-mcp-server__loadSketchByPath` — 加载文件(内部自动解压并保存目录,供后续 extractBitmaps 使用)
63
63
  2. `mcp__sketch-mcp-server__listPages` — 获取页面列表
64
64
  3. `mcp__sketch-mcp-server__queryNodes`(pageId, type="artboard")— 获取画板列表,确定目标画板
65
- 4. `mcp__sketch-mcp-server__getPageStructure`(pageId, mode="ids")**替代旧的 getPageStructure + getNodesSummary 组合**
66
- - 一次返回按类型分组的全量 ID:`{ text: [...], rectangle: [...], bitmap: [...], shapePath: [...] }`
67
- - 可选 `typeFilter` 参数限制返回类型
65
+ 4. `mcp__sketch-mcp-server__getPageStructure`(pageId, mode="tree")— **先看完整层级关系**,识别顶层 group 分区(如 LeftTree 区/Query+Table 区/信息栏区/标题栏区)
66
+ - 再用 `mode="ids"` 拿到按类型分组的全量 ID:`{ text: [...], rectangle: [...], group: [...], bitmap: [...], shapePath: [...] }`
68
67
  - 同时返回 `summary`(各类型统计)和 `totalIds`(总数)
69
- 5. `mcp__sketch-mcp-server__getMultipleNodeInfo`([所有 text + rectangle ID])— **支持任意数量 ID,内部自动分批处理**
70
- - 关键字段:`style.fills[0].color.hex`(背景色)、`text.color`(文字色)、`style.fontSize`、`style.fontWeight`
68
+ 5. `mcp__sketch-mcp-server__getMultipleNodeInfo`([**所有 text + rectangle + group ID 同批提交**])— **支持任意数量 ID,内部自动分批处理**
69
+ - 关键字段:`style.fills[0].color.hex`(背景色)、`text.color`(文字色)、`style.fontSize`、`style.fontWeight`、`style.borders[0]`、`style.shadows`
70
+ - **`parent: { id, name, type }`**(v1.5.0+ 新增)— 元素归属判定的核心字段,**始终用 parent 走 group 父子关系,禁止用 x/y 坐标判定归属**
71
+ - **禁止只取 text 类型**:会遗漏 rectangle/group 容器的渐变背景、边框、阴影;信息栏/卡片类区块必须连容器一起拉
71
72
  - 无需手动分批,传入全部 ID 即可(内部按 100 个一批自动处理)
72
73
 
73
- **与旧策略的差异**:
74
- - 旧策略:`getPageStructure`(可能截断) + `getNodesSummary` + 手动分批 `getMultipleNodeInfo`
75
- - 新策略:`getPageStructure(mode="ids")`(轻量全量 ID) + `getMultipleNodeInfo`(自动分片)
76
- - 调用次数:旧 6 次 4 次(含 loadSketch + listPages 合并)
74
+ **替代方案(更短,3 次主调用)**:当只关心特定类型节点时,可用 `queryNodes` 一次性拿数组类型:
75
+ ```
76
+ queryNodes({ pageId, type: ["text", "rectangle", "group"], limit: 500 })
77
+ 返回这三类节点的 ID 列表,跳过 getPageStructure(mode="ids") 步骤
78
+ ```
79
+ 适用场景:已通过 `getPageStructure(mode="tree")` 看清分区,只想批量获取关键 token 节点时。
77
80
 
78
81
  **步骤 2.5 产出物**(**只产出数据,不做组件映射**):
79
82
  - 按类型分组的全量节点 ID 列表
80
- - text/rectangle 节点的完整样式 Token
83
+ - text/rectangle/group 节点的完整样式 Token + parent 父子关系
81
84
  - bitmap ID 列表(传给步骤 2.5.1)
82
85
  - shapePath 节点名列表(传给步骤 2.5.1)
83
86
 
84
87
  组件候选列表推理**不**在步骤 2.5 内部完成,**统一在主流程中结合步骤 1 的 `templatePatterns` 推理**(详见主流程步骤 4 前置说明)。
85
88
 
89
+ ### 步骤 2.5 必读:getMultipleNodeInfo 返回字段契约(sketch-mcp-server ≥ v1.6.1)
90
+
91
+ **每个节点的实测返回结构**(与本表不一致即视为版本不匹配,提示用户 `npm i -g @szc-ft/sketch-mcp-server@latest`):
92
+
93
+ | 节点类型 | 必有字段 | 关键样式字段(取值路径) |
94
+ |----------|----------|--------------------------|
95
+ | 所有 | `id`, `name`, `type`, `position:{x,y}`, `size:{width,height}`, `parent:{id,name,type}`, `style:{fills,borders,shadows,innerShadows,blur}`, `isVisible`, `opacity` | `style.fills[i].color.hex` / `style.borders[i].color.hex+thickness` / `style.shadows[i].{color,offsetX,offsetY,blurRadius}` |
96
+ | text | + `text:{content, attributes:[{location,length,attributes:{fontFamily,fontSize,color,alignment,lineHeight,letterSpacing}}]}` | 文字色 `text.attributes[0].attributes.color.hex`、字号 `text.attributes[0].attributes.fontSize`、**字重** = `text.attributes[0].attributes.fontFamily` 末尾(如 `PingFangSC-Semibold` → 600,`-Regular` → 400,`-Medium` → 500) |
97
+ | rectangle/oval | + `shape:{type, cornerRadius}` | `shape.cornerRadius`(圆角);背景 `style.fills[0].color.hex`;描边 `style.borders[0]` |
98
+ | **group/artboard** | + `children:[id]`, **`isVisualContainer:bool`** | **`isVisualContainer === true`** 时:`style.fills[0]`(含 `gradient`)= 容器背景、`style.borders[0]` = 容器边框 ← **渐变盒/卡片样式的唯一来源**;`false` 时只是图层文件夹,无视觉样式 |
99
+ | bitmap | + `image:{imageRef, originalSize}` | 用 `extractBitmaps` 取 base64 |
100
+ | shapePath | + `shape:{path}` | 用 `matchIconFromName` 匹配 iconfont |
101
+
102
+ #### 字段缺失自检(getMultipleNodeInfo 返回后立即跑)
103
+
104
+ 抽样 5 个节点(含至少 1 text + 1 group + 1 rectangle)做契约校验:
105
+
106
+ - [ ] 5 个节点都有 `parent.name`(任一为 undefined → 服务端版本旧,提示升级到 ≥ v1.6.1)
107
+ - [ ] 所有 group/artboard 节点都有 `isVisualContainer` 布尔字段
108
+ - [ ] 所有 group 节点都有 `children` 数组(即使为空)
109
+ - [ ] text 节点 `text.attributes[0].attributes.fontFamily` 不为空
110
+ - [ ] 至少 1 个 rectangle 的 `style.fills.length > 0` 或 `style.borders.length > 0`(若全为 0,可能 .sketch 文件本身无视觉样式,或抽样偏差)
111
+
112
+ **任一项 ❌ → 停下来定位原因,禁止带着不完整的数据进入步骤 2.6**。
113
+
86
114
  ### 步骤2.5.1:图标与位图提取(有 bitmap/shapePath 节点时执行)
87
115
 
88
116
  **输入**:步骤 2.5 产出的 bitmap ID 列表 + shapePath 节点名列表
@@ -92,21 +120,55 @@ Ant Design → ProComponents → Cover 层 → Wrapper 层 → ProPackages →
92
120
  1. `mcp__sketch-mcp-server__extractBitmaps`(bitmapIds)— 从 .sketch 解压目录提取 bitmap PNG 资源
93
121
  - 返回 `{ bitmaps: [{ nodeId, name, base64, mimeType, size, fileName }] }`
94
122
  - 位图资源用于 CSS `background-image` 引用
95
- 2. `mcp__sketch-mcp-server__matchIconFromName`(nodeNames, library="newFont")— 匹配 iconfont 图标库
96
- - 输入 shapePath 节点名列表(如 `["表 icon", "文件 icon"]`)
97
- - 匹配策略:节点名关键词 拼音匹配图标列表
123
+ 2. `mcp__sketch-mcp-server__matchIconFromName`(nodeNames, library="newFont")— 匹配 iconfont 图标库(v1.5.0+ 评分制)
124
+ - 输入 shapePath 节点名列表(如 `["表 icon", "新建文件夹", "编组11备份"]`)
125
+ - **评分机制**:compoundIcons 强映射 +100、keyword 精确 +20、keyword 包含 +10、semanticTag +3
126
+ - 每个 nodeName 返回 **Top-3 候选**(按分数降序),让你做最终选择
98
127
  - 返回格式:
99
128
  ```json
100
129
  {
101
- "matchedIcons": [
102
- { "nodeName": "表 icon", "iconType": "icon-biao", "library": "newFont" }
130
+ "results": [
131
+ {
132
+ "nodeName": "新建文件夹",
133
+ "top3": [
134
+ { "source": "compound", "score": 104, "antdIcon": "FolderAddOutlined", "matchedBy": "文件夹|目录|folder + 新增|添加|add|plus|新建|create", "rationale": "..." },
135
+ { "source": "compound", "score": 104, "antdIcon": "FileAddOutlined" },
136
+ { "source": "compound", "score": 102, "antdIcon": "FolderOutlined" }
137
+ ],
138
+ "bestMatch": { "source": "compound", "antdIcon": "FolderAddOutlined" }
139
+ }
103
140
  ],
104
- "unmatched": ["菜单icon"],
105
- "recommendFallback": { "菜单icon": "antd MenuOutlined" },
106
- "matchRate": "80.0%"
141
+ "matchedIcons": [...], // Top-1 兼容旧字段
142
+ "unmatched": ["编组11备份"], // 无关键词信号的节点
143
+ "recommendFallback": { "编组11备份": "antd QuestionOutlined" },
144
+ "matchRate": "66.7%"
107
145
  }
108
146
  ```
109
147
 
148
+ **⚠️ 图标语义优先级(v1.5.0 已内置 compoundIcons,多数场景自动命中)**:
149
+
150
+ 实战教训:Sketch 中"编组11备份"实际是 folder-plus 图标,旧版被误判为通用 PlusOutlined(优先命中"新增"关键词吃掉了 folder 语义)。v1.5.0 评分制 + compoundIcons 强映射已修复该类问题。
151
+
152
+ **判定流程**:
153
+ 1. **优先看 `bestMatch.source`**:`compound` 表示触发了复合词强映射,可直接采用 `antdIcon`
154
+ 2. **看 Top-3 是否有合适的候选**:分数接近的候选都值得考虑
155
+ 3. **`unmatched` 节点(如"编组11备份"无关键词信号)**:必须看节点 `parent.name` 和兄弟节点上下文兜底
156
+ - 例:parent 是 LeftTree 标题区 → 多半是文件夹/分类操作图标 → `FolderAddOutlined` / `FolderOpenOutlined`
157
+ - 例:parent 是 Query 操作栏 → 多半是表单动作图标 → `SearchOutlined` / `PlusOutlined`
158
+
159
+ **参考表(内置 compoundIcons 已覆盖;列出供 unmatched 兜底参考)**:
160
+
161
+ | Sketch 节点上下文 | 期望 antd 图标 | 反例(不要选) |
162
+ |---|---|---|
163
+ | 文件夹+新增/添加 | `FolderAddOutlined` | PlusOutlined |
164
+ | 文件+新增 | `FileAddOutlined` | PlusOutlined |
165
+ | 用户+新增 | `UserAddOutlined` | PlusOutlined |
166
+ | 文件夹+打开 | `FolderOpenOutlined` | FolderOutlined |
167
+ | 编辑+笔 | `EditOutlined` | FormOutlined |
168
+ | 设置+齿轮 | `SettingOutlined` | ToolOutlined |
169
+
170
+ **操作流程**:matchIconFromName 返回 unmatched 或 fallback 为通用 `PlusOutlined/EditOutlined` 时,**先看节点 parent group 的名称/兄弟节点**,按上表选语义更精确的复合图标。
171
+
110
172
  **步骤 2.5.1 产出物**:
111
173
  - bitmap base64 资源列表 → 用于代码中的 CSS background-image
112
174
  - IconfontWapper 代码片段(`<IconfontWapper assets="newFont" type="icon-biao" />`)
@@ -128,15 +190,41 @@ Ant Design → ProComponents → Cover 层 → Wrapper 层 → ProPackages →
128
190
  - 新做法:直接传入全部 ID(如 200 个)→ 内部自动按 100 个一批处理 → 返回合并结果
129
191
  - 返回结构不变:`{ nodes: [...], total, requested, batches }`
130
192
 
131
- **经验3:text 节点是颜色/DOM 映射的两级索引**
193
+ **经验3:归属判定走 x+y+parent 三轴联合,禁止单轴定论(坐标和 parent 互为纠错器)**
194
+
195
+ 实战教训:
196
+ - 反例 A:`'主题'text(x=272,y=149)` 单看 x 在右侧内容区列,但 `parent.name=leftTreeHeader` 强语义 → 归左树(情形 C:parent 修正坐标)
197
+ - 反例 B(反馈 #11):`'段码含义'text(x=300,y=257)` 坐标落在 `渐变容器(x=240..960, y=189..297)` 内,但 parent 是兄弟编组 `cataMain` → 视觉上属于渐变容器内(情形 B:图层拆开,按坐标渲染)
198
+
199
+ 正确做法:
200
+ - 步骤 2.5 第 4 步先 `mode="tree"` 看顶层 group 分区(通常 2-5 个)
201
+ - 步骤 2.6 做双向校验:Pass 1 坐标推假设 → Pass 2 parent 质检 → 四类情形 A/B/C/D 处理
202
+ - 大区归属:`parent.name` 含 `LeftTree/树/PageContent/sidebar/cataMain` 等强语义关键字时优先于 x 分布
203
+ - 容器归属:必须 `x ∈ [容器x, 容器x+w]` **且** `y ∈ [容器y, 容器y+h]`,单轴判定无效
204
+ - 跨分区不比 y;同分区内按 y 升序;同行(y 差<8px)按 x 升序
205
+
206
+ 详细决策矩阵见步骤 2.6。
207
+
208
+ **经验4:信息栏/卡片容器必须先取 group 再取子元素**
209
+
210
+ 实战教训:步骤 2.5 仅提取 text 节点导致信息栏容器样式遗漏(渐变背景 #f3faff→#f8fdff、边框 #e9f5ff、图标编组)。
211
+
212
+ 正确做法:
213
+ - 看到画板里有 `编组N`/`infoCard`/`statBox` 等 group 节点,必须连 group 自身和内部 rectangle 一起拉 `getMultipleNodeInfo`
214
+ - group 节点的 `style.fills` 才是渐变背景、`style.borders` 才是边框
215
+ - 子图标若为 group(rectangle + shapePath),rectangle 是圆形/方形背景,shapePath 是矢量图标
216
+
217
+ **经验5:text 节点是颜色/DOM 映射的两级索引**
132
218
  每个 text 节点同时关联两种上下文,**必须同批拉取**:
133
219
  - 自身样式:`fontSize`、`fontWeight`、`text.color`
134
220
  - 所属 group 父级 rectangle 样式:`bg`、`border`、`radius`、`shadow`
135
221
 
136
222
  错误做法:先查 text 拿自身样式 → 再根据 parent ID 单独查 rectangle(多走一步)
137
- 正确做法:构造查询列表时,**把同一 group 内的 text + rectangle 节点 ID 合并提交**
223
+ 正确做法:
224
+ - 用 `queryNodes({ pageId, type: ["text", "rectangle", "group"], limit: 500 })` 一次拿三类节点的 ID
225
+ - 再用 `getMultipleNodeInfo([...全部ID])` 同批提交,每个节点返回的 `parent` 字段直接告诉你归属关系,无需二次查询
138
226
 
139
- **经验4:图表区样式提取有规律可循**
227
+ **经验6:图表区样式提取有规律可循**
140
228
 
141
229
  | 图表子元素 | 对应 Sketch 节点类型 | 关键样式字段 |
142
230
  |---|---|---|
@@ -151,12 +239,127 @@ Ant Design → ProComponents → Cover 层 → Wrapper 层 → ProPackages →
151
239
 
152
240
  识别出图表后,**图例色块**应归入 ECharts `legend` 配置(不要用 div 硬编码),**柱体色**映射到 `series.itemStyle.color`。
153
241
 
154
- **经验5:矢量图形用 matchIconFromName 自动匹配,无需手动解压**
242
+ **经验7:矢量图形用 matchIconFromName 自动匹配,无需手动解压**
155
243
  - `shapePath` / `shapeGroup` 在 sketch 节点中占比可能高达 46.8%,但 `renderNodeAsBase64` 不支持渲染
156
244
  - **新方案**:`matchIconFromName(shapePathNames)` 自动查询 iconfont 库 → 返回匹配结果
157
245
  - bitmap 用 `extractBitmaps(bitmapIds)` 自动提取 PNG 资源
158
246
  - 兜底:未匹配的节点用 antd `@ant-design/icons` 同语义图标替代,在代码注释中标注“⚠️ 矢量图标用 antd 图标替代,原始 Sketch 为 shapePath”
159
247
 
248
+ **经验8:rectangle 的 fill/border 必须以内联样式或精确选择器落到 DOM,禁止借用通用 CSS class**
249
+
250
+ 实战教训(反馈 #11):5 个段码视觉块的颜色(#f2f8fd/#f5ffed/#fffbe6/#f5f6f7)完整地从 rectangle 节点拿到了,但代码却用了 `.beforebg{background:#ebf0ff}` 这种与设计稿无对应关系的通用 class,导致 5 个块颜色全错。
251
+
252
+ 正确做法:
253
+ - 步骤 2.6 的样式映射表(表 5)必须为每个"颜色块"列出 rectangle 数据 → 内联 style 的对应关系
254
+ - 写代码时直接用 `<div style={{background:'#f2f8fd',border:'1px solid #d9eafb'}}>`
255
+ - 若必须用 CSS class,类名要能反向追到 Sketch 节点(如 `.segmentBlock-blue` 而非 `.beforebg`),且 class 内容必须**精确等于** rectangle 的 fill/border
256
+ - 反例排查:写完代码后 grep 一下 CSS class 名,出现 `.bg1/.box2/.before*` 这类无语义类名、且颜色和设计稿对不上 → 几乎确定是凭空兜底
257
+
258
+ ### 步骤2.6:布局推理(必做,写代码前的最后一道关)
259
+
260
+ ⚠️ 这一步专治"数据全拿到却放错位置"。反馈 #11 的 5 处错位全部由跳过此步骤导致。
261
+
262
+ **核心思路**:x+y 坐标先画"视觉假设",parent 字段做质检纠错。两套信号**互为纠错器**,不是单方向"谁优先"。
263
+
264
+ **输入**:步骤 2.5 产出的 `text + rectangle + group` 节点全量数据(含 `position.{x,y}`、`size.{width,height}`、`parent.{id,name,type}`、`style`、`isVisualContainer`)
265
+
266
+ #### Pass 1:坐标推假设(产出 5 张表)
267
+
268
+ 每张表都必须输出,即使某类节点为空也要写"无"。
269
+
270
+ ##### 表 1:分区识别表(x+y+parent 联合,定大区)
271
+
272
+ ```
273
+ | 节点 name | x | y | parent.name | 推断分区 | 决策依据 |
274
+ |----------------|-----|-----|------------------|--------------|-------------------------|
275
+ | 主题(text) | 272 | 149 | leftTreeHeader | 左树标题区 | parent 强语义压过 x 列 |
276
+ | 段码定义(text) | 320 | 200 | cataMain | 右侧内容-顶部 | parent 含 PageContent 类语义 |
277
+ ```
278
+
279
+ 判定流程:
280
+ 1. 按 x 把画板切成 1-3 列(x<300 → 左区、x≥300 → 右区,或按设计稿实际边界)
281
+ 2. 用 `parent.name` 校验:含 `LeftTree/树/sidebar/cataMain/PageContent/header/footer` 等关键字时以 parent 为准
282
+ 3. 冲突时遵循"经验3"的 A/B/C/D 矩阵(见下方 Pass 2)
283
+
284
+ → 此表输出**布局类型**:UpDown(单列)/ LeftRight(双列)/ LeftMiddleRight(三列)
285
+
286
+ ##### 表 2:纵向顺序表(同分区内按 y)
287
+
288
+ ```
289
+ | 分区 | 节点 | y | 推断角色 |
290
+ |------------|---------------|-----|-------------------|
291
+ | 右侧内容区 | 段码定义 | 200 | 卡片 1 |
292
+ | 右侧内容区 | Tabs | 420 | Tabs(type=card) |
293
+ | 右侧内容区 | 配置说明 | 478 | 卡片 2(Tabs 下方) |
294
+ ```
295
+
296
+ 铁律:**同分区内**渲染顺序按 y 升序。跨分区不比 y(左树第 100 行 y 和右内容区第 1 行 y 没有可比性)。
297
+
298
+ ##### 表 3:横向排列表(同行按 x,y 差<8px 视为同行)
299
+
300
+ ```
301
+ | 分区/容器 | 节点 | x | y | 推断角色 |
302
+ |-----------------|--------------|-----|-----|-------------------------|
303
+ | Query 操作栏 | 名称输入框 | 320 | 50 | Form.Item col-span=6 |
304
+ | Query 操作栏 | 状态下拉 | 540 | 50 | Form.Item col-span=6 |
305
+ | Query 操作栏 | 查询按钮 | 980 | 50 | 操作按钮(右对齐) |
306
+ ```
307
+
308
+ 判定流程:
309
+ 1. y 差<8px 识别同一行
310
+ 2. 同行按 x 升序排
311
+ 3. 计算 x 间距推算 antd Col span(24 栅格)或 flex
312
+ 4. 最右元素若 `x + width` 接近容器右边界 → 右对齐(justify-content: flex-end)
313
+
314
+ ##### 表 4:容器归属表(x+y 双轴边界检测)
315
+
316
+ 仅对 `isVisualContainer === true` 的 group 和带 fill/border 的 rectangle 做检测。
317
+
318
+ ```
319
+ | 容器 | x..x+w | y..y+h | 落入子元素 |
320
+ |------------------|----------|----------|----------------------------------|
321
+ | 渐变容器(group) | 240..960 | 189..297 | 段码含义(x=300,y=257) ✅ |
322
+ | 段码块-蓝(rect) | 320..420 | 320..360 | (无子节点,仅样式) |
323
+ ```
324
+
325
+ 判定式:子元素 `x ∈ [容器x, 容器x+w]` **且** `y ∈ [容器y, 容器y+h]` → 渲染在容器内部。**单轴判定无效**。
326
+
327
+ ##### 表 5:样式映射表(rectangle/group fill → UI 组件内联样式)
328
+
329
+ ```
330
+ | Sketch 节点 | 数据来源 | bg/border | 映射到代码 |
331
+ |----------------------|--------------------------|--------------------------|-----------------------------------------------------------|
332
+ | 段码块-蓝(rectangle) | style.fills[0]/borders[0]| bg #f2f8fd / b #d9eafb | <div style={{background:'#f2f8fd',border:'1px solid #d9eafb'}}> |
333
+ | 渐变容器(group) | style.fills[0].gradient | linear #f3faff→#f8fdff | <div style={{background:'linear-gradient(180deg,#f3faff,#f8fdff)'}}> |
334
+ | Tab 激活态 | rect bg #fff border #0079f7 | bg #fff / b #0079f7 | Tabs type="card" + .segmentTabs .ant-tabs-tab-active 覆盖 |
335
+ ```
336
+
337
+ 铁律(见经验 8):rectangle 的 fill/border 必须以**内联样式**或精确选择器落到代码,**禁止**用 `.beforebg{background:#ebf0ff}` 这类与设计稿无对应关系的 CSS class。
338
+
339
+ #### Pass 2:parent 质检(按 A/B/C/D 矩阵处理冲突)
340
+
341
+ 逐行扫表 1,对照 parent 字段:
342
+
343
+ | 情形 | 坐标判定 | parent 判定 | 处理 |
344
+ |------|----------|-------------|------|
345
+ | A | 在容器 X 内 | parent 链含 X | ✅ 双向一致,直接采用 |
346
+ | B | 在容器 X 内 | parent 是兄弟节点 Y | ⚠️ **视觉容器优先**(设计师把图层拆开了)→ 按坐标渲染到 X 内 |
347
+ | C | 不在容器 X 内 | parent.name 强语义 = X | ⚠️ **parent 优先**(绝对定位/溢出布局)→ 按 parent 归属,加 `position:absolute` 标注 |
348
+ | D | 双向都不落 | parent 是顶层 | 独立元素,按坐标走纵向顺序 |
349
+
350
+ 输出**最终归属表**:在表 1 末尾追加 `情形(A/B/C/D)` 列。
351
+
352
+ #### Pass 3:自检清单(写代码前必跑)
353
+
354
+ - [ ] 表 1 是否按 x 分布判定了布局类型(UpDown / LeftRight / LeftMiddleRight)?
355
+ - [ ] 表 2 同分区内是否按 y 排序,没有跨分区比 y?
356
+ - [ ] 表 3 同行元素(y 差<8px)是否按 x 排序,计算了栅格 span 或右对齐?
357
+ - [ ] 表 4 容器归属是否做了 x+y 双轴检测,不是只看一轴?
358
+ - [ ] 表 5 所有"颜色块/卡片/渐变"样式都来自 rectangle/group 的 style.fills/borders,没有出现凭空 CSS class?
359
+ - [ ] Pass 2 冲突行是否标了 A/B/C/D 情形和决策依据?
360
+
361
+ 任一项 ❌ → 回 Pass 1 补;禁止跳到步骤 3 前未输出全部 5 张表 + 最终归属表。
362
+
160
363
  ### 步骤3:分析设计稿图片(有图片时执行)
161
364
 
162
365
  - 主智能体已提供图片描述时,直接使用,跳过此步
@@ -206,6 +409,19 @@ Ant Design → ProComponents → Cover 层 → Wrapper 层 → ProPackages →
206
409
  | 柱状对比图 | `Bar` |
207
410
  | 饼图/环形图 | `Pie` |
208
411
 
412
+ ### ⚠️ TemplateMode 槽位传参铁律(高频踩坑)
413
+
414
+ **LeftContent / Query / PageContent 三个槽位都接收单个 ReactNode,禁止传数组**:
415
+
416
+ | ❌ 错误 | ✅ 正确 | 后果 |
417
+ |---|---|---|
418
+ | `LeftContent={[<LeftTree/>]}` | `LeftContent={<LeftTree/>}` | 数组会触发多余 tab 渲染 |
419
+ | `LeftContent={[<LeftTree/>, <Filter/>]}` | `LeftContent={<><LeftTree/><Filter/></>}` 或包一层 div | 同上 |
420
+ | `Query={[<Query/>]}` | `Query={<Query/>}` | 同上 |
421
+ | `PageContent={[<TableOrList/>]}` | `PageContent={<TableOrList/>}` | 同上 |
422
+
423
+ **判定方法**:Sketch 中只要某个分区是"单棵树/单个查询面板/单个表格",对应槽位就传单个组件实例。需要多个并列时用 Fragment `<>...</>` 或容器 div 包裹,**不要用数组**。
424
+
209
425
  **长尾场景走语义搜索**(不进文档,避免膨胀):
210
426
  - 数据可视化长尾:`Radar` / `Gauge` / `Funnel`(用 `Line/Bar/Pie` 之外的图表)
211
427
  - 表格子类型长尾:`DragSortTable`(拖拽排序)、`steps` 步骤条表单
@@ -243,8 +459,20 @@ Ant Design → ProComponents → Cover 层 → Wrapper 层 → ProPackages →
243
459
  ### 依赖关系
244
460
  | 组件 | 依赖的 szcd 组件 | 依赖的 hooks |
245
461
  |------|-----------------|-------------|
462
+
463
+ ### 布局顺序(来自步骤 2.6 表 2 压缩,按 y 排序)
464
+ [页面级垂直顺序,如:TitleAndBack → 段码定义卡片 → Tabs → 配置说明卡片]
465
+
466
+ ### 关键样式映射(来自步骤 2.6 表 5,仅列非默认样式)
467
+ | UI 元素 | Sketch 数据来源 | 落地方式 |
468
+ |---------|----------------|----------|
469
+ | 段码块×5 | 5 个 rectangle 的 fills[0]/borders[0] | 内联 style |
470
+ | 渐变容器 | group(isVisualContainer) 的 fills[0].gradient | 内联 linear-gradient |
471
+ | Tab 激活态 | rectangle bg #fff border #0079f7 | type="card" + .segmentTabs 覆盖 |
246
472
  ```
247
473
 
474
+ 用户在确认环节即可发现"段码块颜色没列上"或"Tab 样式漏识别",避免反馈 #11 那样要等代码生成后反复修。
475
+
248
476
  ### 步骤6:生成代码(必做)
249
477
 
250
478
  遵循规范:
@@ -255,7 +483,21 @@ Ant Design → ProComponents → Cover 层 → Wrapper 层 → ProPackages →
255
483
  - Hooks 按依赖关系正确引入(useLeftTree、useTable 等)
256
484
  - 复合组件配合 TemplateMode 使用
257
485
 
258
- 代码生成后询问用户:
486
+ #### 步骤 6 末尾必做:样式落地校验
487
+
488
+ 代码生成完成后,**逐行核对**步骤 2.6 表 5(样式映射表)的每一项是否真落到代码里:
489
+
490
+ ```
491
+ | 样式映射表行 | 代码中对应位置 | 校验 |
492
+ |---------------------------------------------|-------------------------------------------------------------|------|
493
+ | 段码块-蓝 bg #f2f8fd border #d9eafb | CreateOrEdit.tsx:L120 `<div style={{background:'#f2f8fd',border:'1px solid #d9eafb'}}>` | ✅ |
494
+ | 渐变容器 linear #f3faff→#f8fdff | CreateOrEdit.tsx:L98 `style={{background:'linear-gradient(...)'}}` | ✅ |
495
+ | Tab 激活态 bg #fff border #0079f7 | styles.less:L45 `.segmentTabs .ant-tabs-tab-active{...}` | ✅ |
496
+ ```
497
+
498
+ ❌ 如果某行找不到对应代码位置 → 直接补到代码里再继续,**禁止说"代码已生成"前留缺口**。这是反馈 #11"5 个段码块全错"的根因——所有颜色都拿到了,但没逐一回查是否落到了代码上。
499
+
500
+ 代码生成 + 落地校验都通过后,询问用户:
259
501
  > "代码已生成,你可以选择:
260
502
  > 1. 调整样式或交互细节
261
503
  > 2. 补充表单校验/批量操作等功能
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@szc-ft/mcp-szcd-client",
3
- "version": "0.24.0",
3
+ "version": "0.26.0",
4
4
  "description": "MCP client for szcd component library - auto-configures AI coding tools with MCP server, skills, agents and commands",
5
5
  "keywords": [
6
6
  "mcp",