Files
photo-live/docs/plans/progress/UI02-验收记录.md
T
2026-09-21 23:10:58 +08:00

140 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# UI-02 观众页视觉重构 验收记录
基线 commit:f31388c(tag `ui01`)· 完成 commit:本提交(tag `ui02`)· 日期:2026-09-21 · 执行环境:Windows 11 + Docker Desktop(mysql/redis×2 + minio)+ Playwright Chromium(1440×900 / 390×844 / 320×568)
## 1. 基线与完成 commit
| 项 | 值 |
|---|---|
| 基线 | f31388c(UI-01 完成提交,tag `ui01`) |
| 完成 | Task 6 验收提交(含代码修正 + 本记录 + after 截图 + 总纲注记),tag `ui02` |
| 工作树 | 基线后首个提交为方案文档(3327551);验收提交仅含 apps/viewer 代码/测试、本记录、总纲注记与 after 截图目录 |
任务提交链:3327551(方案)→ 2cbd167 → 9c3915b → 3d89fcd → 89f4589 → 160e7e5 → 本提交,代码提交共 6 个。
## 2. 任务完成表(Task 1–6)
| 任务 | 状态 | commit | 备注 |
|---|---|---|---|
| Task 1: 基线截图与验收骨架 | ✅ | 2cbd167 | 改版前观众页 4 张基线截图(首页/大图 × 中/英)+ 本记录骨架 |
| Task 2: V01+V02 视觉基础与活动信息 | ✅ | 9c3915b | 作用域 token / 顶栏(品牌+语言+减少动画)/ 宣传图 / 信息区(标题/说明/元信息/分享)/ 排序与分类工具栏(AlbumHeader 提取) |
| Task 3: V03 瀑布流 | ✅ | 3d89fcd | 响应式列数 / 真实宽高 / 点赞角标 / 新图提示 / 懒加载与占位 |
| Task 4: V04 深色大图查看器 | ✅ | 89f4589 | 深色沉浸式布局 / 缩略图条 / 操作栏 / 保留缩放·导航·路由编排 |
| Task 5: V05 互动与分享下载 | ✅ | 160e7e5 | 心形粒子 / 互动轻提示 / 相册与单图分享(navigator.share + 复制回退)/ 下载菜单 |
| Task 6: V06+V07 状态国际化与验收 | ✅ | 本提交 | 全量回归 / 状态矩阵核验 / l10n 补齐(?lang= 参数)/ a11y 抽查 / 截图 / 本记录 / tag |
## 3. 验收矩阵(方案 §9.2)
| 编号 | 状态 | 证据 |
|---|---|---|
| V-A01 | ✅ | App.vue 无手机外壳/假内容/底部导航;层级=顶栏→宣传图→信息→工具栏→瀑布流;截图 after/home-390-zh.png、home-1440.png;album-header.spec.ts(标题/说明/元信息结构) |
| V-A02 | ✅ | PhotoFeed 瀑布流(真实宽高绝对定位,非等高网格);feed.spec.ts(列数/占位/懒加载/身份保持);截图 home-320(2 列)/ home-390 / home-1440 |
| V-A03 | ✅ | album-header.spec.ts:宣传图缺失/加载失败收起且信息可用、标题两行钳制+展开、说明三行+展开/收起、日期地点缺失自然省略、窄屏元信息换行 |
| V-A04 | ✅ | 浏览数=album.viewCount 初值 + 上报回调/stats.updated 校准(ActivityPage useVisitReport);e2e journey.spec '1 次浏览';分页/点赞/切图不重复计访问(visitor 幂等键,A14 沿用) |
| V-A05 | ✅ | e2e album.spec(sort-tabs 文案 ['最新','热门']、分类筛选列收窄断言);likes.spec(热门快照重取+锁定);feed.spec 新图提示(不强制跳顶);分类 ID 跨语言保留(activity.spec) |
| V-A06 | ✅ | lightbox.spec.ts(完整显示/左右切换/越过末尾自动翻页/位置指示/缩略图条同步);截图 after/lightbox-390-zh.png、lightbox-1440.png;缩放交互沿用 Task 8 既有实现 |
| V-A07 | ✅ | activity.spec.ts:深链直达(solo 兜底+相邻页归位)、push/back 关闭回位(滚动锚点恢复)、浏览器后退关闭、照片移除(WS/404)轻提示+邻居回退;lightbox.spec 'layers above sticky topbar'(z=200) |
| V-A08 | ✅ | 分享 URL 携带 ?lang=(ActivityPage photoShareUrl);接收端首载优先参数——i18n.spec 'initial locale honors the ?lang= share parameter';复制失败回退显示 URL(shareState 'failed',album-header.spec);分享菜单(lightbox share-btn + 头部分享) |
| V-A09 | ✅ | e2e download.spec(.download-main 菜单 ['浏览图','原图']、相册开关关闭时入口隐藏);useDownload 单测(签名 URL 过期→受控刷新有限重试→占位);失败仅本地反馈(InteractionNotice) |
| V-A10 | ✅ | e2e likes.spec(连续点赞真实累计、自己回声不重复计入、WS 实时多观众可见、断连降级轮询后恢复);useLikes 批次+校准单测 |
| V-A11 | ✅ | likes.spec(他人点赞不污染当前数值);LikeBubbles 数量上限+点击定位;大图打开时页面级气泡清空(ActivityPage `lightboxPhotoId === null ? bubbles : []`),改由查看器内互动提示承载(§6.2) |
| V-A12 | ✅ | 减少动画:HeartParticles/LikeBubbles/过渡尊重 prefers-reduced-motion 与顶栏开关(heart-particles 单测);lightbox.spec 'traps Tab focus inside the dialog'(含首尾环绕);:focus-visible 全套主色描边;aria-modal/role=dialog/aria-label |
| V-A13 | ✅ | viewer/position.ts 诚实口径单测:solo/未定位→'照片预览'、无总数且还有页→'已加载 N 张'、到底→'i / n'、总数仅服务端提供才显示;新图提示数量来自 realtime 实际合并数 |
| V-A14 | ✅ | 中英模板零硬编码(i18n 键集相等守护 error-coverage.spec);html lang 随 locale(App.vue watchEffect);320/390/1440 截图无横向溢出(320 实测 scrollWidth=clientWidth);lightbox 100dvh+safe-area、数字 tabular-nums;⚠️ 横屏与系统字体放大留 G2 真机(同 UI-01 A07 口径) |
| V-A15 | ✅ | `git diff ui01..HEAD` 范围=apps/viewer + docs(业务后端/移动端/嵌入链零改动);embed 页独立外壳无顶栏无外边距(embed.spec 全绿);loader 构建字节一致(9462 B);api-cn/sync/worker/admin e2e 全绿 |
## 4. 状态矩阵核验(方案 §7)
| 状态 | 结果 | 证据 |
|---|---|---|
| 加载中 | ✅ | 相册状态文本 + PhotoFeed 骨架占位(feed.spec) |
| 相册不存在/未公开 | ✅ | 本地化不可用提示 + 重试(ActivityPage loadError;activity.spec) |
| 无照片 | ✅ | '照片即将上线' 空态,无上传按钮(e2e 实拍 after/empty-album-390.png;feed.spec) |
| 首载网络失败 | ✅ | 错误提示 + 重试按钮(activity.spec) |
| 加载更多失败 | ✅ | 已加载照片保留 + 底部重试(Task 6 新增 feed.spec 'load-more failure keeps the loaded photos and offers a bottom retry') |
| URL 过期 | ✅ | 受控刷新有限重试→占位(useDownload/lightbox 单测) |
| 照片下线/删除 | ✅ | 移除 + 邻居回退 + 轻提示(z=210 盖查看器;activity.spec) |
| 深链照片不存在 | ✅ | 本地化提示 + 返回相册链接(deep-link-notice;activity.spec) |
| WS 断连 | ✅ | 降级轮询继续合并新图(e2e likes.spec 'WS loss degrades to polling'),提示为连接态而非'无新照片' |
| 分享/下载失败 | ✅ | 仅本地轻提示/回退(shareState failed 显示 URL;下载失败 InteractionNotice),不弹全局错误 |
## 5. 截图索引
基线(2026-09-21,commit 2cbd167):`ui02-screenshots/baseline/`(改版前观众页)
| 编号 | 页面 | 文件 |
|---|---|---|
| 01 | 首页(中/英) | baseline/01-home-zh-CN.png、01-home-en.png |
| 02 | 大图(中/英) | baseline/02-lightbox-zh-CN.png、02-lightbox-en.png |
优化后(2026-09-21,本提交):`ui02-screenshots/after/`
| 编号 | 页面 | 文件 | 验证点 |
|---|---|---|---|
| 01 | 首页·390·中 | after/home-390-zh.png | 层级/对齐(标题=tab=胶囊 16px)/无横向滚动 |
| 02 | 首页·390·英 | after/home-390-en.png | `?lang=en` 直达英文(html lang=en) |
| 03 | 大图·390·中 | after/lightbox-390-zh.png | 深色沉浸/顶栏关闭/位置指示/操作栏/缩略图条 |
| 04 | 大图·390·英 | after/lightbox-390-en.png | 英文文案(Share 等) |
| 05 | 首页·320 | after/home-320.png | 最窄无溢出(实测 scrollWidth=clientWidth=305) |
| 06 | 大图·320 | after/lightbox-320.png | 操作栏/缩略图条不溢出 |
| 07 | 首页·1440 | after/home-1440.png | 居中 1120 列 + 对齐 168.5px(列边+16) |
| 08 | 大图·1440 | after/lightbox-1440.png | 桌面深色大图 + 悬停控件 |
| 09 | 空相册·390 | after/empty-album-390.png | '照片即将上线' 空态无上传按钮 |
采集环境:demo-seed 12 张渐变真实上传图 + 本地 dev 栈(cn 8080 / ov 8081 / worker / sync 2s 推送 / viewer 5175);320/390 检查含 JS 实测文档横向溢出(修复后均为 0)。
与效果图差异:效果图中的手机外壳/编号/投影为展示板元素未带入(§3.1 约定);分类胶囊数、浏览数等为真实接口数据,与效果图的假数据不同属预期。
## 6. 测试命令与真实结果
命令序列:清场(杀残留 dev 进程)→ `pnpm lint` → `pnpm typecheck` → `pnpm test` → `pnpm build` → `pnpm e2e` → `source scripts/flutter-env.sh && cd apps/mobile && flutter analyze && flutter test` → `pnpm --filter @photo/embed-loader build` + 字节比对。
| 门 | 结果 |
|---|---|
| pnpm lint | 全部任务通过(Task 6 后 viewer 单包复跑 ✓) |
| pnpm typecheck | 全部任务通过(含 Task 6 新增/修改测试;CSS 修正后 viewer 复跑 ✓) |
| pnpm test(单元) | **426 用例全绿**:viewer 222(28 文件)/ admin 77(14)/ embed-loader 27 / contracts 29 / storage 6 / api-cn 51 / worker 14 |
| pnpm build | 全部任务通过(viewer dist 223.85 kB JS / 78.42 gzip;CSS 27.24 kB / 5.25 gzip) |
| pnpm e2e | api-cn 257/257(24 套件)/ sync 27/27 / worker 13/13 / admin 全绿 / viewer 44:41 通过 + 1 环境性抖动(隔离复跑 6/6 ✓,见偏差 4)+ 2 未运行(同文件串行连带,复跑含于 6/6) |
| flutter analyze | No issues found!(0 问题) |
| flutter test | 341/341 全绿(UI-02 未触及移动端,回归保护) |
| loader build+比对 | dist/v1/loader.js 9462 B 与 apps/viewer/public/embed/v1/loader.js 字节一致 |
测试统计对比(UI-01 → UI-02):
| 维度 | 前(UI-01) | 后(UI-02) | Δ |
|---|---|---|---|
| Web 单元 | 359(viewer 155/20 文件) | 426(viewer 222/28 文件) | +67 |
| Web e2e | 364(viewer 44/9 specs) | 364(viewer 44/9 specs,选择器全面迁移至新结构) | 0 |
| Mobile | 341/341 | 341/341 | 0(保护性回归) |
## 7. 既有改动保护与外部环境
- 纯 viewer 前端改造:`git diff ui01..HEAD` = apps/viewer + docs(73 文件),业务数据流/API/同步/嵌入链零变更;EmbedPage 独立外壳未受 token 作用域影响(embed e2e 全绿)。
- 无关未跟踪文件未纳入提交:`.playwright-mcp/`、`docs/designs/app-redesign-2026-09-21/` 保持原状。
- 未触碰用户自有进程(scripts/serve.mjs 4173、Playwright MCP);截图用 dev 栈用毕已清理(8080/8081/5175 释放)。
- 演示数据(demo-seed 相册 + 空相册)写入本地 dev 库,不涉及远程/云资源。
## 8. 方案偏差与剩余事项
偏差:
1. **顶栏 z-index 压盖大图(Task 6 发现并修复)**:sticky 顶栏 z=120 盖住 .photo-viewer z=100,关闭按钮不可点(e2e 首跑 4 项失败定位)。修复:查看器 z=200、下线轻提示 z=210,并补 lightbox.spec 源码断言防回归。
2. **工具栏对齐与 1px 横向溢出(Task 6 截图核验发现并修复)**:.chips-track 横向负边距在通栏父级上把盒子推出视口(390 视口 scrollWidth 391→页面横向滚动),且排序 tab/分类胶囊与信息区 16px 缩进不齐(效果图三者同缩进)。修复:去掉横向负边距、.sort-tabs 补 16px 内边距;320/390/1440 实测零溢出并对齐,截图为修复后版本。
3. **e2e 选择器迁移收敛在 Task 6**:Tasks 2–5 专注实现与单元测试,5 个 e2e spec 仍指向旧结构(首跑 15 项失败);Task 6 完成 album/download/likes/viewer/journey 全量迁移(含两步语言切换、下载菜单文案)。
4. **embed-crossorigin 环境性抖动**:全量并行下 outbox_events.updateMany 偶发 MySQL 写冲突/死锁(PrismaClientKnownRequestError,种子并行 flushSync 竞争),两轮全量各命中 1 例且不同用例;隔离复跑 6/6 通过。与 UI-01 偏差 3 同类的测试基建问题,非代码回归;后续可为 flushOutbox 加重试(独立小改,未夹带)。
5. **`?lang=` 分享参数(Task 6 补齐)**:方案 §5.4 要求分享链接携带语言,Task 5 已带参但接收端未优先解析;Task 6 在 resolveInitialLocale 增加 ?lang= 最高优先(不写 localStorage——接收者未做选择),配 i18n.spec 用例。
6. **26 个 .playwright-mcp 快照文件误入 3327551(方案文档提交)**:不影响运行;建议后续以一次 `git rm` 清理(本次不重写历史)。
7. **加载中状态形态**:相册加载为诚实状态文本 + 瀑布流骨架占位,未做信息区整块骨架(字段未知时无法诚实渲染占位文案);与方案 §7 'loading→skeleton' 的合理收敛。
剩余(交接):
- G2 真机追加:横屏实拍、系统字体放大 1.3/2.0、真实全景/长图样本(沿 UI-01 清单)。
- flushOutbox 死锁重试(测试基建小改,见偏差 4)。
- .playwright-mcp 历史文件清理(见偏差 6)。
## 9. 外部关口(不变)
- G2 真机(未执行,不阻塞 UI-02 本地验收)
- G4/D08 用户接口、P5 真实环境接入按总纲推进;UI-02 全部为本地开发环境验证。