Files
photo-live/docs/plans/progress/UI01-验收记录.md
T
2026-09-21 20:15:36 +08:00

153 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-01 App 与悬浮组件体验优化 验收记录
基线 commit:6754cd4 · 完成 commit:本提交(tag `ui01`)· 日期:2026-09-21 · 执行环境:Windows 11 + Docker Desktop(mysql/redis×2 + minio)+ MuMu 模拟器(Android 15,540×960@240dpi ≈ 360dp 逻辑宽)+ Playwright Chromium(1440×900 / 390×844)
## 1. 基线与完成 commit
| 项 | 值 |
|---|---|
| 基线 | 6754cd4(UI-01 实施计划提交后、U00 执行前) |
| 完成 | Task 8 文档提交(含本记录 + after 截图),tag `ui01` |
| 工作树 | 基线时清洁;验收提交仅含本记录、总纲注记与 after 截图目录 |
任务提交链:3b5f8d2 → 8f4ad11 → c94b9e5 → f6929ae → 1f67b7c → ddf26a1 → ac23a4c → 本提交,共 8 个。
## 2. 任务完成表(U00–U09)
| 任务 | 状态 | commit | 备注 |
|---|---|---|---|
| Task 1: U00 基线 | ✅ | 3b5f8d2 | 6 张 App 基线截图;嵌入组件/后台基线因当时 Playwright 环境冲突未采集(见偏差 2) |
| Task 2: U01 契约与数据 | ✅ | 8f4ad11 | cover/preview/scope=own/embed 新配置字段 + 权限矩阵 e2e(services/api/test/ui01-contracts.e2e-spec.ts) |
| Task 3: U02 主题与导航 | ✅ | c94b9e5 | tokens + ColorScheme 浅/深 + 公共组件 + 三 tab 导航 + 角标 |
| Task 4: U03 相册与照片 | ✅ | f6929ae | 封面卡片列表 / 紧凑详情 / 三列网格 / 大图查看器 / 权限操作 / URL 刷新 |
| Task 5: U04+U05 上传与辅助页 | ✅ | 1f67b7c | 上传中心摘要+筛选+状态映射 / 深色取景 / 分组表单 / 分享分层 / 设置分组 |
| Task 6: U06 嵌入组件 | ✅ | ddf26a1 | loader 新配置+收起重设计+destroy;轮播页组件拆分+预加载+暂停恢复+可访问性;跨源宿主测试 |
| Task 7: U07 后台配置与预览 | ✅ | ac23a4c | 新字段表单 + 桌面/手机双预览(本地数据)+ 嵌入代码卡仅显式覆盖 |
| Task 8: U08+U09 验收交接 | ✅ | 本提交 | 全量回归 + 13 张 after 截图 + 本记录 + 总纲注记 + tag `ui01` |
## 3. 验收矩阵(方案 §9.1)
| 编号 | 状态 | 证据 |
|---|---|---|
| UI-A01 | ✅ | apps/mobile/test/app/theme_test.dart(11 用例:浅色 §3.1 精确值、深色语义对应、字阶、动效时长/reducedMotion 归零);截图 01–08(设备浅色实拍) |
| UI-A02 | ✅ | albums_tab_test(封面有无占位、标题回退、390 单列/900 双列);截图 02(封面卡片:图→标题→时间地点→状态 badge) |
| UI-A03 | ✅ | album_photos_page_test(350→2/390→3/800→5 列、大图切换、返回位置、角标);截图 05/06(网格 + contain 大图 1/12) |
| UI-A04 | ✅ | services/api/test/ui01-contracts.e2e-spec.ts 权限矩阵(admin/owner/collab-own/collab-other × cover/preview/scope;隐藏照片有权限可见无权限 404;删除照片 preview=null) |
| UI-A05 | ✅ | queue_tab_test(摘要计算、状态映射、行级进度订阅);截图 07(摘要条"今天·本设备"+ 状态 chips + 服务端历史分区) |
| UI-A06 | ✅ | capture_page 测试(连拍模式、入队反馈不弹窗、拍摄不被上传打断)——Task 5 提交内用例 |
| UI-A07 | ⚠️ 部分验证 | 自动化覆盖 350/390/800/900 逻辑宽(widget 测试)+ 设备 ≈360dp 实拍;**320/430 宽度与文字 1.0/1.3/2.0 缩放未系统覆盖**,列入 G2 真机清单 |
| UI-A08 | ⚠️ 部分验证 | 窄屏 375(playwright embed.spec "narrow viewport starts collapsed and downgrades to sm size")+ 390/1440 实拍(截图 10/09)+ admin 预览 320px 框(截图 12);**320/768 宿主未逐一实拍** |
| UI-A09 | ✅ | EmbedStage 固定 4:3 舞台 + object-fit contain(换图不跳高由舞台固定保证);失败图片保留上一张(viewer vitest);演示 12 张渐变图 contain 实拍(截图 09/11);真实全景/文字海报样本列入 G2 |
| UI-A10 | ✅ | embed.spec 6 项暂停恢复(按钮/悬停/键盘焦点/页面隐藏/reducedMotion/收起)+ collapse 持久化;截图 10(390 默认收起)/11(展开) |
| UI-A11 | ✅ | embed.spec(rebinding resets the feed、admin settings apply live via config message、ghost slot 404 destroy);304/签名过期刷新 viewer vitest(ETag + 受控刷新有限重试) |
| UI-A12 | ✅ | embed-crossorigin.spec.ts(真实双端口跨源宿主 7 用例:渲染、非法 source 消息忽略、ghost destroy、多 slot 纵向 8px 间距、全局 button CSS 干扰、窄屏收起) |
| UI-A13 | ✅ | admin e2e embed-slot-config(表单交互窗口零 /v1/ 请求);截图 12(未保存修改即时反映在本地预览,含"未保存"标记) |
| UI-A14 | ✅ | embed-loader 单测 27 用例(缺省/显式/config 消息合并+边界+优先级 data-* > config > 后台 > 默认);v1 兼容入口保留(dist/embed/v1/loader.js);截图 13(代码卡仅含显式覆盖) |
| UI-A15 | ✅ | P4b 三端语言守护(键集相等 + 错误码枚举全覆盖)延续有效;UI-01 新键入 arb 双语;embed.spec "lang=en renders English copy";运行时长文案无裁切由 footer 布局测试覆盖 |
| UI-A16 | ✅ | 本记录 §8 外部关口明确列 G2/G4/P5 为待验证,未宣称生产验收完成 |
## 4. API 新字段与权限变化(全部可选/nullable,旧客户端零 break)
| 契约 | 变更 | 服务端 |
|---|---|---|
| AlbumSummary | `cover: SignedUrl \| null` | albums 列表按页批量查 album_assets(kind=cover, effective)+ 短期签名 URL,无 N+1 |
| AdminPhoto | `preview: {thumb: SignedUrl, browse: SignedUrl} \| null` | 管理列表按权限逐张判断(admin 全部/owner 本相册/collab 仅自己);已删除返回 null |
| listAlbumPhotos | query `scope: 'all' \| 'own'`(默认 all 行为不变) | own=服务端过滤仅本人上传 + 成员资格逐次检查 |
| EmbedSlotSettings | `imageFit: 'contain'\|'cover'`、`offsetX: 0-120`、`offsetBottom: 0-240`、`zIndex: 1-2147483000`(均带默认) | cn 管理 PATCH 校验 → slot-state payload → ov 公开响应投影完整传递(sync 验证) |
旧客户端兼容:全部字段缺省不 break(ui01-contracts.e2e-spec 含旧请求无新字段用例);ov 侧旧响应消费者不受影响。
## 5. 截图索引
基线(2026-09-21 采集,commit 3b5f8d2):`ui01-screenshots/baseline/`
| 编号 | 页面 | 文件 | 备注 |
|---|---|---|---|
| 01 | 登录页 | baseline/01-login.png | Flutter App |
| 02 | 相册列表 | baseline/02-albums.png | 当前卡片无封面图 |
| 03 | 相册详情(上半) | baseline/03-album-detail.png | 字段堆叠布局 |
| 04 | 相册详情(滚动后) | baseline/04-album-detail-scrolled.png | 按钮均等强调 |
| 05 | 上传队列 | baseline/05-queue.png | 状态筛选/进度/操作 |
| 06 | 设置 | baseline/06-settings.png | 分组/语言/密码 |
| 07-09 | 嵌入组件/后台 | (未采集) | 当时 Playwright 环境冲突;after 侧本次补齐,基线以 P4b 验收记录组件描述为对照 |
优化后(2026-09-21 采集,本次提交):`ui01-screenshots/after/`
| 编号 | 页面 | 文件 | 验证点 |
|---|---|---|---|
| 01 | 登录页 | after/01-login.png | 主题化登录(logo/品牌/输入/主按钮) |
| 02 | 相册列表 | after/02-albums.png | 封面卡片:图→标题→时间地点→状态 badge;无 publicToken 堆叠 |
| 03 | 相册详情 | after/03-album-detail.png | 大图封面+信息+公开/允许上传 badge+照片条预览 |
| 04 | 详情滚动后 | after/04-album-detail-scrolled.png | 照片区(12 张·3 分类 + 管理入口)/分类 chips/底部"从相册选择 + 拍摄上传"双按钮 |
| 05 | 照片网格 | after/05-photo-grid.png | 三列网格 + scope chips(全部/我的)+ 排序/筛选 |
| 06 | 大图查看器 | after/06-photo-viewer.png | contain 展示 + 1/12 页码 + 深色舞台 + 操作入口 |
| 07 | 上传中心 | after/07-queue.png | 摘要条(今天·本设备)+ 状态 chips + 服务端历史分区 |
| 08 | 设置 | after/08-settings.png | 账号/通用/安全/上传帮助/关于分组 + 退出登录 |
| 09 | 组件·桌面 1440 | after/09-embed-desktop-1440.png | md 320px 卡片、offsetX16/offsetBottom24、页码 1/12、收起把手、外链 |
| 10 | 组件·390 收起 | after/10-embed-mobile-390-collapsed.png | 窄屏默认收起 + sm 尺寸把手(≥44px 高) |
| 11 | 组件·390 展开 | after/11-embed-mobile-390-expanded.png | sm 280px 卡片无横向溢出 |
| 12 | 后台配置+预览 | after/12-admin-slot-config.png | 新字段全套(位置/尺寸/间隔/语言/收起/适配/偏移/层级)+ 桌面 320/手机 375 双预览 + 未保存标记 |
| 13 | 嵌入代码卡 | after/13-admin-embed-code.png | 仅 data-slot 显式覆盖 + 参数说明表 |
采集环境:01–08 MuMu 强杀冷启 + 本地 dev 栈(cn 8080 / ov 8081 / worker / MinIO 9000 + adb reverse);09–13 vite preview dist + 独立宿主页(http.server 8090)+ 真实跨源 loader 接入,数据为 demo-seed 12 张渐变图 + 上传封面资产。
## 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` + sync 校验。
| 门 | 结果 |
|---|---|
| pnpm lint | 10/10 任务通过 |
| pnpm typecheck | 13/13 任务通过 |
| pnpm test(单元) | 12/12 任务、**359 用例全绿**:embed-loader 27 / contracts 29 / storage 6 / api-cn 51 / worker 14 / viewer 155(20 文件)/ admin 77(14 文件) |
| pnpm build | 10/10 任务通过 |
| pnpm e2e | **364 全绿**(第二跑;磁盘用例计数 api-cn 255(24 套件,含 ui01-contracts)+ viewer 44(9 specs,含 embed-crossorigin)+ admin 23(7 specs,含 embed-slot-config)+ sync 27 + worker 13 = 362,运行总数含 it.each 展开) |
| flutter analyze | No issues found!(0 问题) |
| flutter test | **341/341 全绿**(+61 相对 P4b 280) |
| loader build+sync | dist/v1/loader.js 与 apps/viewer/public/embed/v1/loader.js 字节一致(cmp 相同) |
测试统计对比(P4b 基线 → UI-01 后):
| 维度 | 前(P4b) | 后(UI-01) | Δ |
|---|---|---|---|
| Web 单元 | 316(embed-loader 11 / viewer 136 / admin 69 / 其余 100) | 359(embed-loader 27 / viewer 155 / admin 77 / 其余 100) | +43 |
| Web e2e | 339(api-cn 247/23 套件 / viewer 32/8 / admin 20/6 / sync 27 / worker 13) | 364(api-cn 24 套件 / viewer 9 specs / admin 7 specs / sync 4 / worker 2) | +25 |
| Mobile | 280/280 | 341/341 | +61 |
| 合计 | 935 | 1064 | +129 |
性能观察(实测记录,不做百分比推算):
- loader 体积:dist/v1/loader.js **9462 B 原始 / 3728 B gzip**(P4b 基线未记录 gzip 值,无从对比,不编数字)
- 相册列表封面:每页 1 次批量 album_assets 查询 + 按页签发,无 N+1(实现 + e2e 断言)
- 组件预加载窗口:仅当前 + 下一张(2 张),decode 成功才切换
- 轮播 intervalMs 与取数轮询(30s 基准)解耦,互不牵引
- 组件首屏(ov 日志实测):slot-state 1 次 + visits 信标 1 次,之后按帧取图
## 7. 既有改动保护与外部环境
- 基线工作树清洁;全程未覆盖任何未提交改动。
- 无关未跟踪文件未纳入提交:`.playwright-mcp/`、`docs/designs/`、`docs/plans/2026-09-21-UI02-*.md` 保持原状。
- 未触碰用户自有进程(`scripts/serve.mjs` 4173 端口、Playwright MCP/Codex 进程保留);仅清理本仓库残留 dev 服务(e2e 首跑失败的根因,见偏差 3)。
- 演示数据写入本地 dev 库(demo-seed + 封面资产),不影响任何远程/云资源。
## 8. 方案偏差与剩余事项
偏差:
1. **cover 契约无 width/height**:方案 Task 2 文稿为 `{url, expiresAt, width, height}`,实现为既有 `SignedUrl` 引用(url/expiresAt)。理由:卡片封面按固定宽高比占位(无图回退中性占位),客户端不需要服务端尺寸;避免契约膨胀。旧客户端零影响。
2. **基线嵌入组件/后台截图缺失**:U00 时 Playwright 环境冲突未采集;本次 after 侧补齐(09–13),基线对照沿用 P4b 验收记录的组件行为描述。
3. **e2e 首跑 sync 套件 9/27 失败**:根因是上一会话残留 dev:worker/dev:sync 进程消费了 BullMQ 任务与 outbox 事件(processPhoto 命中 'already' 快路径、picked 数被抢),属环境干扰非代码回归;清理后全量第二跑 364 全绿。
4. **320/430 逻辑宽、文字 1.3/2.0 缩放、深色模式真机截图**未系统采集(A07/A08 部分验证),随 G2 真机一并执行。
剩余(交接):
- **G2 真机关口**(既定强制关口):追加 UI-01 视觉项——深色模式实拍、320/430 宽度、文字缩放 1.0/1.3/2.0、横图/竖图/全景/文字海报真实样本。
- **G4/D08 用户接口**、**P5 真实环境接入**(G5/G6)按总纲推进;P4b 移交项(真实域名/CDN 预热/embed 页 frame-ancestors CSP/展示位授权 UI 按需/轮询参数冻结)继续有效。
- A22 展示位授权(embed_slot_members 建而未用)维持 P4b 状态,未在 UI-01 范围。
## 9. 外部关口(不变)
- G2 真机(未执行,不阻塞 UI-01 本地验收)
- G4/D08 用户接口(未到位,不阻塞 UI-01)
- P5 真实部署(测试服务器 219.157.255.213 已部署;UI-01 全部为本地开发环境验证)