211 lines
7.1 KiB
Markdown
211 lines
7.1 KiB
Markdown
# 截图+审计+修正+验证 执行手册
|
||
|
||
> 合并原 screenshot.md / audit.md / fix.md / verify.md 四个文件。
|
||
> 硬性规则(rpx、标签映射、颜色)已在 always-on steering `mp-h5-rules.md` 中,此处不重复。
|
||
|
||
---
|
||
|
||
## 一、截图
|
||
|
||
### H5 截图(Playwright Power → `browser_run_code`)
|
||
|
||
```javascript
|
||
async (page) => {
|
||
const browser = page.context().browser();
|
||
const ctx = await browser.newContext({
|
||
viewport: { width: 430, height: 752 },
|
||
deviceScaleFactor: 1.5
|
||
});
|
||
const p = await ctx.newPage();
|
||
await p.goto('file:///C:/NeoZQYY/docs/h5_ui/pages/<page>.html',
|
||
{ waitUntil: 'domcontentloaded', timeout: 30000 });
|
||
await p.waitForTimeout(3000); // Tailwind CDN JIT
|
||
|
||
await p.evaluate(() => {
|
||
const nav = document.getElementById('bottomNav');
|
||
if (nav) nav.style.display = 'none';
|
||
const safeArea = document.querySelector('.safe-area-top');
|
||
if (safeArea) safeArea.style.paddingTop = '0px';
|
||
const aiFab = document.querySelector('.ai-float-btn-container');
|
||
if (aiFab) aiFab.style.display = 'none';
|
||
const s = document.createElement('style');
|
||
s.textContent = '::-webkit-scrollbar{display:none!important}*{scrollbar-width:none!important}';
|
||
document.head.appendChild(s);
|
||
});
|
||
|
||
await p.evaluate((scrollTop) => window.scrollTo(0, scrollTop), <scrollTop>);
|
||
await p.waitForTimeout(300);
|
||
await p.screenshot({
|
||
path: 'C:/NeoZQYY/docs/h5_ui/compare/<page>/h5--step-<scrollTop>.png',
|
||
type: 'png', scale: 'device'
|
||
});
|
||
await ctx.close();
|
||
return { saved: true };
|
||
}
|
||
```
|
||
|
||
步数 ≥3 的页面可在同一 context 中循环截图。
|
||
|
||
### MP 截图(weixin-devtools Power)
|
||
|
||
```
|
||
1. relaunch → url: "/pages/<page>/<page>"(禁止 switch_tab/navigate_to)
|
||
2. waitFor → delay: 2000
|
||
3. 前置:WXML 中 dev-fab/ai-float-button 加 wx:if="{{false}}"
|
||
4. 滚动到目标 scrollTop
|
||
5. screenshot
|
||
6. 模式 B 页面裁剪头部 96px(PIL: img.crop((0, 96, 645, 1224)))
|
||
```
|
||
|
||
### 滚动策略
|
||
|
||
标准:直接使用 H5 相同 scrollTop。
|
||
|
||
窗口错位判断:上下大块红绿(>200px)=整体偏移→锚点对齐法 | 散布多区域=样式差异→继续修正 | 底部全黑/白>100px=内容更短→锚点对齐法
|
||
|
||
锚点对齐法:确定锚点元素 → `wx.createSelectorQuery` 获取绝对 top → `MP_target = absoluteTop - sticky高度` → 滚动到该位置
|
||
|
||
### 多维度切换
|
||
|
||
board-coach/customer:获取快照 → 点击筛选下拉 → 选择维度 → 等待刷新
|
||
board-finance:H5 `toggleCompare()` / MP 点击环比开关
|
||
|
||
### 截图后行为(严格遵守)
|
||
|
||
- 直接进入审计流程,禁止用 PIL/pixelmatch/image-compare 检查尺寸或做像素 diff
|
||
- 截图参数已固定,尺寸必然正确
|
||
|
||
---
|
||
|
||
## 二、审计
|
||
|
||
### 三阶段流程
|
||
|
||
```
|
||
阶段 0:结构拆解(自顶向下)
|
||
H5 源码 → 首层容器 → 递归到叶子 → 建立 H5↔MP 映射表
|
||
结构完整性校验(缺失/多余/顺序错误 → P0)
|
||
|
||
阶段 1:逐级测量(自底向上)
|
||
叶子:自身尺寸 + 样式属性
|
||
容器:内边距 + 子元素间距 + 总尺寸
|
||
页面级:全局内边距 + 区块间距
|
||
工具:pixel-audit Power → readSteering("measure.md")
|
||
|
||
阶段 2:偏差审计
|
||
逐属性对比 H5 rpx 理论值 vs MP 实测值 → 按偏差量分级
|
||
```
|
||
|
||
### 迁移前置准备(step-0 必做)
|
||
|
||
1. H5 页面结构预扫描:全局结构、CSS 风险特性、字体确认
|
||
2. MP 骨架检查:根容器、navigationBar、safe-area 移除、背景色、浮动按钮隐藏
|
||
3. mock 数据一致性预核对(不一致 = P0)
|
||
4. 多屏页面:测量 MP scrollHeight,与编排值差异 >50px 则重算序列
|
||
|
||
### 审计报告格式
|
||
|
||
产出 `docs/h5_ui/compare/<page>/audit.md`:
|
||
|
||
| 章节 | 内容 |
|
||
|------|------|
|
||
| A. 结构对照 | 区域完整性、顺序 |
|
||
| B. CSS 风险点 | 不支持的 CSS |
|
||
| C. 关键样式映射 | Tailwind→computed→WXSS 现值→是否一致 |
|
||
| D. 图标处理 | 每个图标迁移状态 |
|
||
| E. 偏差清单 | P0-P7 排序,含 H5 值→rpx→MP 现值→差异 |
|
||
| F. 复杂结构专项 | Banner/AI 图标/盖戳/inline SVG/渐变文字 |
|
||
|
||
关键原则:不能只看 diff 图猜测,必须回溯 H5 源码。Tailwind 类名是唯一可信样式来源。
|
||
|
||
---
|
||
|
||
## 三、修正
|
||
|
||
### 优先级定义
|
||
|
||
| 级别 | 类型 | 判定标准 | 阶段 |
|
||
|------|------|---------|------|
|
||
| P0 | 区域缺失/顺序错误 | 整块缺失 | 阶段一 |
|
||
| P1 | 背景色/渐变色不匹配 | 大面积色差 | 阶段一 |
|
||
| P2 | 字号明显偏差 | font-size 差 ≥4rpx | 阶段一 |
|
||
| P3 | 间距明显偏差 | padding/margin/gap 差 ≥4rpx | 阶段一 |
|
||
| P4 | 圆角偏差 | border-radius 差 ±2rpx | 阶段二 |
|
||
| P5 | 颜色微调 | 灰阶偏差、透明度差 0.1 | 阶段二 |
|
||
| P6 | 行高/字重微调 | line-height 缺失或偏差 | 阶段二 |
|
||
| P7 | 阴影微调 | box-shadow 偏差 | 阶段二 |
|
||
|
||
### 两阶段收敛
|
||
|
||
```
|
||
P0-P3 >10 → 结构级重写(每轮 3-8 处)→ 循环
|
||
P0-P3 >0 → 阶段一:结构级修正(每轮 2-5 处)→ 循环直到 P0-P3=0
|
||
P4-P7 >0 → 阶段二:像素级精调(每轮 1-3 处)→ 循环直到可接受
|
||
全部 ≤2rpx → ✅ 通过
|
||
```
|
||
|
||
### 回滚规则(强制)
|
||
|
||
每轮修正后重新截图对比,差异率上升(哪怕 0.01%)→ 立即回滚 → 逐项排查 → 每次只改一处
|
||
|
||
### 最大重试限制
|
||
|
||
差异率下降 >0.5% → 重试计数归零 | 下降 ≤0.5% → 计数+1 | 计数=5 且仍 ≥5% → 跳过(记录到 report.md)
|
||
|
||
### 首屏 >20% 触发结构重写
|
||
|
||
| 页面类型 | 重写范围 | 禁止修改 |
|
||
|---|---|---|
|
||
| 单屏 | 当前维度完整 WXML/WXSS | 其他维度 |
|
||
| 多屏(step-0) | 页面顶部结构 | step-600 以下 |
|
||
| 多屏(step-N>0) | 当前视口内节点 | 其他屏和全局样式 |
|
||
| 变体 | 与主页面差异部分 | 共享布局 |
|
||
|
||
### 修改范围约束
|
||
|
||
- 只改当前屏可见元素
|
||
- 偏差根因在前序屏 → 标注"需回退到 step-X"返回主代理
|
||
- 偏差根因是全局样式 → 标注"全局样式变更"返回主代理
|
||
- 修改后 `getDiagnostics` 确认零 TS 错误,有错误立即回退
|
||
|
||
### 收敛停滞
|
||
|
||
连续 3 轮差异率未下降 >0.5%:分析是否为不可消除结构性差异 → 是则标注可接受 → 否则缩小粒度
|
||
|
||
---
|
||
|
||
## 四、验证
|
||
|
||
### 修正后验证
|
||
|
||
```
|
||
1. 重新截图 → 重新审计
|
||
2. P0-P3=0 → ✅ 通过
|
||
3. P0-P3 减少 → 继续修正
|
||
4. P0-P3 未减少或增加 → 回滚 + 重试计数+1
|
||
5. 重试=5 → 跳过
|
||
```
|
||
|
||
### 全量回归校验(多屏页面所有屏通过后强制执行)
|
||
|
||
```
|
||
1. 逐屏截取双端截图
|
||
2. 每屏结构化审计
|
||
3. 禁止修改任何源码
|
||
4. P0-P3 增加 → 标记"回归"
|
||
5. 返回主代理决定处理方式
|
||
```
|
||
|
||
### Sticky 元素专项
|
||
|
||
step-0 完成后先检测 sticky 差异 → 优先修复(一次修复所有屏受益)→ 再继续后续步骤
|
||
|
||
### 异常处理
|
||
|
||
| 故障 | 处理 | 升级 |
|
||
|------|------|------|
|
||
| MCP 断开 | reconnect_devtools;3次失败→mcp_recompile+5s | 重编译后仍失败→暂停 |
|
||
| Playwright 不可用 | 用已有截图继续审计 | 无截图→报告主代理 |
|
||
| 截图异常(白屏) | 暂停检查页面状态 | 禁止使用异常截图 |
|
||
| MCP 超时 | 重试最多 2 次 | 3次均超时→跳过 |
|