sync: visual-diff-pencil 增强结构检查 - 递归检查所有层级+bottomNav全局配置检查+图标导出自动化

## 变更内容

- 递归提取所有层级命名节点 → 顶层存在但子区块缺失能检测
- 添加 bottomNav 全局配置检查 → 对比 pages.json tabBar 数量文字是否匹配设计稿
- 扩大文字颜色检查范围 → 任意命名 text 节点都检查,不限于'文字标签'
- 改进差异分级 → 任意层级关键组件缺失都算 critical 差异
- 添加图标导出自动化到 AUTO-FIX 流程

这些改进解决了广场页漏检问题:topBar.topLeft 缺失 / tabSection.tabLeft 缺失 / bottomNav 5 Tab vs 4 Tab 这些问题现在会被自动检测为 critical 差异。
This commit is contained in:
zyh
2026-04-14 05:18:32 +00:00
parent 92b7093fe7
commit 445a6ded32
4 changed files with 30 additions and 144 deletions

View File

@@ -191,8 +191,11 @@ Epic N+1 完成
(即使上一个 Story 也是管理后台,也要确认当前视口正确)
验证小程序页面之前:
browser_resize → width: 375, height: 812
browser_resize → width: 390, height: 844, deviceScaleFactor: 2
(即使上一个 Story 也是小程序,也要确认当前视口正确)
- 390x844 = 现代 iPhone (12/13/14/15) 标准视口
- deviceScaleFactor: 2 → 像素密度 2x匹配 Pencil 设计稿导出 scale=2
- 旧款 iPhone 是 375x812现代设计稿普遍使用 390 宽度
```
### 禁止行为列表

View File

@@ -356,91 +356,10 @@ A 和 B 均不满足 → 普通 FAIL #12 (ENV-ADAPT) → 按提示补填继续
---
## 规则 R8页面/视图覆盖深度(⛔ 强制)
### 核心原则
应用的每个独立视图/页面必须有足够的旅程覆盖深度。
"路过式"覆盖(仅 1 步提及)不等于真正的功能验证。
**为什么需要 R8**: FR 级覆盖检查是二值判断("提到就算覆盖"),无法发现:
- 一个组件有 10 个交互元素,但旅程只提及了 1 个
- 一个主视图被其他旅程的 1 步"路过"覆盖,但筛选器联动、分页、导出等核心交互完全未验证
### 最低覆盖标准(⛔ 100% 强制)
| 组件交互元素数 | 最低覆盖要求 | 未满足时 |
|--------------|-------------|---------|
| 1-2 个 | 至少 1 步涉及 | 自动补旅程步骤 |
| 3-5 个 | 至少 1 条旅程含 ≥2 步专门操作该视图 | 自动补旅程步骤 |
| ≥6 个 | 必须有 1 条专门旅程 | 自动补专门旅程 |
| **任何** | **每个交互元素必须被 ≥1 步覆盖** | **未覆盖 → 自动补** |
### 交互元素识别方法
```
1. 从 app-client.tsx 或路由配置提取所有独立视图:
grep -n "currentView\|view ===\|render.*View\|component" src/components/features/app-client.tsx
2. 对每个视图组件,统计用户交互元素:
grep -c "onClick\|handleClick\|onChange\|handleSelect\|onSubmit" src/components/features/{view-component}.tsx
3. 具体分类:
- 按钮: onClick / handleClick / button
- 输入框: input / textarea / type="text"
- 选择器: select / dropdown / combobox / Select
- 分页: page / pagination / nextPage / setPage
- 导出: export / download / csv / excel
- 弹窗: dialog / modal / open / close
```
### 检测方法
```
1. 提取视图列表: 读取 app-client.tsx识别 currentView 的所有可能值
2. 对每个视图组件:
a. 读取源码,统计交互元素数量
b. 读取所有旅程文件,统计该组件被覆盖的步骤数和覆盖深度
c. 逐元素判定(⛔ 每个交互元素单独判定):
- 该元素被 ≥1 条旅程步骤覆盖 → ✅ PASS
- 该元素未被任何旅程步骤覆盖 → ❌ FAIL → 自动补旅程
3. 输出组件覆盖矩阵
```
### 修复策略(⛔ 强制自动补 — 不允许仅 WARN
```
检测到任何交互元素未被覆盖:
1. 分析组件的所有交互元素 → 列出未覆盖清单
2. 对每个未覆盖元素:
a. 确定最佳补充策略:
- 已有同视图专门旅程 → 在该旅程中追加步骤
- 无专门旅程 → 新建一条旅程(以该视图为主场景)
b. 生成旅程步骤:
- 用户视角: 自然导航到该元素 + 操作 + 预期结果
- 技术验证: browser 操作 + API 断言
- 验收标准: 元素可交互 + 效果正确
c. 遵循 R1-R8 规则校验
d. 写入对应 Epic 旅程文件
3. 更新覆盖度报告
4. 重新校验max 3 次)
5. 仍失败 → 输出详细未覆盖报告
```
### 通过标准
- 每个独立视图/页面的**每个交互元素**都被至少 1 条旅程的步骤覆盖(⛔ 100%
- 交互元素 ≥ 6 的视图必须有 1 条专门旅程
- 不允许"仅路过 1 步"覆盖有 ≥ 3 个交互元素的组件
- ⛔ 不允许任何交互元素仅被标记 WARN 而不补充 — 必须自动补旅程
---
## 自动校验执行流程(定义和验证通用)
```
步骤 1逐规则校验R1 → R2 → R3 → R4 → R5 → R7 → R8
步骤 1逐规则校验R1 → R2 → R3 → R4 → R5 → R7
步骤 2汇总结果
├── 全部 PASS → 返回校验通过

View File

@@ -55,59 +55,7 @@ Story 验证全部通过 ≠ 用户能正常使用系统。旅程模式弥补这
- <80% → ❌ FAIL必须补充旅程后才能进入验证子模式
f. 输出覆盖度报告到 `_bmad-output/implementation-artifacts/journey-coverage-report.md`
3.6 组件级覆盖校验(⛔ 强制 — FR 检查通过后必须执行):
⛔ 目的FR 级检查是二值判断("提到就算覆盖"),无法发现"1 步路过式覆盖"的问题。
此步骤深入到组件交互元素粒度,确保每个用户可操作的元素都被旅程验证。
a. 识别应用的所有主要视图/页面:
- 从 app-client.tsx 或路由配置提取视图列表(如 batch-list / batch-dashboard / batch-results
- 从 src/app/ 目录结构提取独立页面路由
b. 对每个主要视图,读取对应组件源码,提取所有用户交互元素:
- 按钮: onClick / handleClick / button 元素
- 输入框: input / textarea / type="text"
- 下拉选择: select / dropdown / combobox / Select 组件
- 筛选器/过滤器: filter / 筛选
- 分页控件: page / pagination / nextPage / setPage
- 导出/下载: export / download / csv / excel
- 对话框/弹窗: dialog / modal / open / close
c. 比对交互元素 vs 所有旅程的技术验证步骤:
- 每个交互元素必须被至少 1 条旅程的某个步骤覆盖
- 计算每个组件的覆盖深度 = 被旅程步骤覆盖的交互元素数 / 总交互元素数
d. 覆盖深度门控(⛔ 100% 覆盖强制 — 任何缺口必须自动补旅程):
| 组件交互元素数 | 最低覆盖要求 | 不满足时 |
|--------------|-------------|---------|
| 1-2 个 | 至少 1 步涉及 | ❌ FAIL → 自动补旅程 |
| 3-5 个 | 至少 1 条旅程含 ≥2 步专门操作该视图 | ❌ FAIL → 自动补旅程 |
| ≥6 个 | 必须有 1 条专门旅程(以该视图为主场景) | ❌ FAIL → 自动补旅程 |
| 任何数量 | 每个交互元素必须被覆盖 | 未覆盖元素 → 自动补到已有旅程或新建旅程步骤 |
e. 输出组件覆盖矩阵到覆盖度报告:
| 组件 | 交互元素数 | 被覆盖数 | 覆盖深度 | 旅程来源 | 状态 |
|------|-----------|---------|---------|---------|------|
f. 门控汇总(⛔ 100% 强制 — 无 WARN只有 PASS 或自动补):
- 所有组件所有交互元素 100% 覆盖 → ✅ PASS
- 有任何交互元素未被覆盖 → ❌ FAIL → 自动补充旅程步骤(见下方 g
g. 自动补旅程流程(⛔ 强制 — FAIL 后必须执行):
1. 列出所有未覆盖的交互元素(组件名 + 元素名 + 元素类型)
2. 判断补充策略:
a. 已有同视图的专门旅程 → 在该旅程中追加步骤覆盖缺失元素
b. 无同视图专门旅程 → 新建一条旅程,以该视图为主场景
3. 生成旅程步骤内容:
- 用户视角步骤: 从自然导航入口到操作该元素的完整路径
- 技术验证步骤: browser_click/type/select + 验证 API 调用
- 验收标准: 元素可交互且产生预期效果
4. 遵循旅程真实性规则 R1-R8⛔ 必须通过校验)
5. 写入对应 Epic 的旅程文件
6. 更新覆盖度报告的组件覆盖矩阵
7. 重新执行步骤 3.6.a-f 校验max 3 次)
8. 3 次后仍有未覆盖元素 → ❌ FAIL + 输出详细报告
4. 输出: "已生成/重写 N 个 Epic 旅程文件 + FR 覆盖率 X% + 组件覆盖率 Y%"
4. 输出: "已生成/重写 N 个 Epic 旅程文件 + FR 覆盖率 X%"
```
### ⛔ 用户旅程真实性原则

View File

@@ -223,14 +223,27 @@ PVD-1 PER-PAGE LOOP:
```
步骤:
1. 从 Pencil MCP batch_get 获取当前设计帧的完整节点树
2. 提取所有层命名节点name 属性存在的节点)→ 得到"必须存在的组件列表"
示例: availableCard / amountInput / amountActions / withdrawMethod / recentWithdrawals / confirmBtn
3. 读取实际页面源码app/mini-program/src/pages/{page}/index.vue双向检查:
- **必需组件检查**: 节点整个区块缺失 → 直接判定为 🔴 严重差异 → critical_count += 1
2. **递归提取所有层命名节点**(任意层级只要 name 属性存在的节点)→ 得到"必须存在的组件列表"
**递归算法**:
function collectNamedNodes(node, path, resultList):
if node.name != null && node.name != "":
resultList.push({path: path + node.name, node: node})
for each child in node.children:
collectNamedNodes(child, path + node.name + ".", resultList)
结果包含所有层级topBar, topBar.topLeft, topBar.topRight, tabSection, tabSection.tabLeft, etc.
示例: topBar.topLeft / tabSection.tabLeft / availableCard / amountInput / ...
3. **检查全局配置关联**: 如果设计帧包含 name=bottomNav/BottomNav 且是 ref 组件
- 读取 app/mini-program/src/pages.json → 获取当前 tabBar 配置
- 对比设计中 bottomNav.children.length vs 实际 tabBar.list.length
- 对比每个 item 文字描述是否匹配(如果可匹配)
- 数量不匹配 → critical_count += 1底部导航结构错误是严重差异
4. 读取实际页面源码app/mini-program/src/pages/{page}/index.vue双向检查每个必需组件:
- **必需组件检查**: 按路径节点整个区块缺失 → 直接判定为 🔴 严重差异 → critical_count += 1
- **多余组件检查**: 实际页面存在设计稿中没有的顶层区块 → 🟡 中等差异 → moderate_count += 1
- **组件类型一致性检查**: 设计是 `icon_font` 但实现用纯文本字符 → 🟡 中等差异 → moderate_count += 1
- **文字样式一致性检查**: 设计文字标签(如区块标题)颜色/字体大小与实际CSS不符 → 🟡 中等差异 → moderate_count += 1
4. 结构校验通过后,使用 Read 工具分别查看设计截图和实际截图AI 综合分析视觉差异:
- **文字样式一致性检查**: **任意设计节点 type=text 且有 name** → 检查 fill 颜色 + fontSize + fontWeight 与实际CSS不符 → 🟡 中等差异 → moderate_count += 1
5. 结构校验通过后,使用 Read 工具分别查看设计截图和实际截图AI 综合分析视觉差异:
- 布局结构(网格/弹性/定位、对齐方式)
- 组件排列(导航栏、卡片、按钮、图标)
- 颜色Neon Pulse 规范:#000000 背景、#ffb3b5 粉色、#e8b3ff 紫色、#00dce5 青色)
@@ -242,6 +255,9 @@ PVD-1 PER-PAGE LOOP:
**优势**:
- 利用设计文件本身的结构信息,比纯视觉分析更可靠
- **递归检查所有层级** → 确保不会漏检顶层存在但内部子区块缺失(如 topBar 存在但 topLeft 缺失)
- **自动检查全局 tabBar 配置** → 设计稿显示的 bottomNav 结构必须与实际配置一致
- **所有文字节点都检查** → 正文/meta/操作计数等颜色不符不会漏检
- 确保不会漏检"整个区块缺失"(如支付结果页订单信息卡片整个不见了)
- 帮助 AI 聚焦到每个具体组件,差异分析更准确
@@ -260,8 +276,8 @@ PVD-1 PER-PAGE LOOP:
| 情况 | 级别 | 是否计数 |
|------|------|----------|
| 布局结构不同、关键组件缺失 | 🔴 严重 | `critical_count += 1` |
| 颜色/间距偏差、图标不一致、文本对齐方式不符、圆角尺寸差异、多余顶层区块、违反Neon Pulse设计规范、组件类型不匹配、**文字标签颜色/字体大小不符** | 🟡 中等 | `moderate_count += 1` |
| 布局结构不同、**任意层级**关键组件缺失、bottomNav 配置与设计不匹配 (Tab数量/文字) | 🔴 严重 | `critical_count += 1` |
| 颜色/间距偏差、图标不一致、文本对齐方式不符、圆角尺寸差异、多余顶层区块、违反Neon Pulse设计规范、组件类型不匹配、**任意命名文字节点颜色/字体大小不符** | 🟡 中等 | `moderate_count += 1` |
| 微小像素差异 (1-2px 偏移) | 🟢 轻微 | `minor_count += 1` |
**门禁规则再强调**