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:
@@ -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 宽度
|
||||
```
|
||||
|
||||
### 禁止行为列表
|
||||
|
||||
@@ -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 → 返回校验通过
|
||||
|
||||
@@ -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%"
|
||||
```
|
||||
|
||||
### ⛔ 用户旅程真实性原则
|
||||
|
||||
@@ -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` |
|
||||
|
||||
**门禁规则再强调**:
|
||||
|
||||
Reference in New Issue
Block a user