Files
photo-live/docs/plans/progress/UI04-验收记录.md
T
浅念 998565e439 feat(viewer,ui04): E03 continuous scroll engine — pure state machine, rAF orchestration, boundary continuity
- stream.ts: advanceStream (per-frame, dt cap 50ms), loop generation keys, window math (DOM<=16, queue<=30, 480px buffer), anchorRebuild (photo-position preserving), removePhoto, single-photo static
- useVerticalPhotoStream: rAF integration, direct transform writes (no per-frame Vue reactivity), low-frequency item sync, ResizeObserver re-anchor, stepForTest hook
- EmbedStream wired to engine; cycle copies aria-hidden; img error -> controlled drop
- tests: 14 unit cases (236 viewer total), e2e: 32px/2s speed, boundary continuity <2.5px, DOM<=16 over 20s, 32s recording with loop boundaries

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-22 13:19:21 +08:00

137 lines
8.8 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-04 验收记录:嵌入组件自动上滚照片窗
对应方案:[2026-09-22-UI04-嵌入组件上滚照片窗高保真实施方案](../2026-09-22-UI04-嵌入组件上滚照片窗高保真实施方案.md)
执行日期:2026-09-22 起
交付目录:[docs/designs/ui04-implementation/](../../designs/ui04-implementation/)
## 0 基线与保护
- 基线 commit:f435d7b(docs: UI-03 acceptance record)+ 本记录随 E00 提交。
- 工作树既有改动保护:E00 起始时工作树存在 **UI03R(App 高保真还原)未提交改动**
(apps/mobile/*、apps/mobile/android/*)——与本任务文件集(packages/embed-loader、
apps/viewer、apps/admin、packages/contracts、services/api)不相交;全程不暂存、
不 reset/clean、不 checkout 这些路径。
- 本任务新入库文件:docs/designs/embed-widget-*-2026-09-22.{png,md}(设计稿三组)、
docs/plans/2026-09-22-UI04-*.md(方案)、docs/designs/ui04-implementation/**(证据)。
## 1 E00 基线(v1 现状采集)
- 现状代码核对:loader(packages/embed-loader/src/loader.js 424 行 + params.js 197 行);
viewer 嵌入页(EmbedPage.vue + pages/embed/{EmbedCarousel,EmbedStage,EmbedFooterBar};
embed/{useEmbedFeed,feed,postMessage,images}.ts);实时(realtime/ws.ts RealtimeClient,
likes.burst 契约见 packages/contracts/src/realtime.ts);API 侧 embed(cn 管理)与
embed-ov(ov 公开数据,settings 归一化投影);admin embed-slots 五视图。
- v1 运行截图(跨源宿主 127.0.0.1:3999 ← viewer 5175,slot 绑定 6 张种子照片):
- [v1-desktop-baseline.png](../../designs/ui04-implementation/reference/v1-desktop-baseline.png)
- [v1-mobile-baseline.png](../../designs/ui04-implementation/reference/v1-mobile-baseline.png)
- v1 尺寸实测(getBoundingClientRect,viewport 1440×900 / 390×844):
| 端 | 元素 | 尺寸 |
|---|---|---|
| 桌面 | wrapper/iframe(md) | 320×339(宽度 md=320;高度为 iframe resize 上报的内容高) |
| 手机 | 收起把手 | 97×44 |
| 手机 | 展开 wrapper(sm 强制) | 280×309 |
- v1 行为登记:窄屏(<480px)默认收起 + 强制 sm;配置优先级 data-* > config 消息 >
默认;postMessage 白名单 {resize,collapse,expand,config,destroy};轮询 30s + ETag
304 + 失败退避 ×5;destroy 于 404/410。
- 采集方式:临时 Playwright 规格(复用 embed-crossorigin 夹具模式,种子经 e2e helpers
直种 cn 库 + flushSync/flushOutbox 同步 ov),采集后已删除;本地栈复用既有进程
(compose 容器已运行 26h+,cn:8080 / ov:8081 / viewer:5175 复用)。
## 2 版本与兼容策略(E01 定案登记)
- **入口形态**:新发布物 `/embed/v2/loader.js`(源 src/loader-v2.js,v1 源 loader.js 冻结
零改动,双产物同 build/sync 脚本);iframe 复用同一路由 `/embed/:slotToken` + 白名单
版本查询 `v=2`(v1 loader 不拼 v → 旧 carousel 分支,旧 v1 接入零变化)。
- **契约扩展**(全部可选、响应恒归一化全集):EmbedSlotSettings += `displayMode`
(carousel|vertical-stream,默认 carousel)、`scrollSpeed`(8..32 CSS px/s,默认 16)、
`reactionsEnabled`(默认 true);事件载荷 SlotSettingsPayload 同步可选字段。
- **缺省语义**:契约/服务端缺省 displayMode=carousel(存量记录读取归一为旧模式,
不一夜切换);管理端新建默认 vertical-stream 由表单显式提交(§8.2)。
- **v2 尺寸硬性**:loader 侧 V2_WIDTH/V2_HEIGHT=195/280 常量;size/intervalMs/imageFit
不进 v2 配置面(data-* 不解析、snippet 不生成、iframe 布局忽略);resize 消息 v2 忽略。
- **E01 证据**:v2 跨源宿主桌面/手机双端 getBoundingClientRect 实测 195×280(e2e
embed-v2.spec.ts E01 出口门 2 用例);ov 公开端点响应含新字段全集(实测 200);
v1 回归 20 e2e 全绿(EMB-A14 部分证据);loader 36 测试(+9 v2 参数面)。
## 3 任务进度
- [x] E00 基线(本记录第 1 节)
- [x] E01 契约和版本骨架(第 2 节;改动面:contracts openapi+events+gen、api dto/
embed.service(cn 管理与 ov 投影共用归一化)、embed-loader params+loader-v2+build/sync、
viewer EmbedPage v=2 分支+EmbedStream+stream.ts+i18n、admin 类型+utils+snippet v1/v2 版本选择)
- [x] E02 静态高保真样板(登记见下)
- [x] E03 连续滚动(登记见下)
- [ ] E04 操作和生命周期
- [ ] E05 实时气泡
- [ ] E06 管理预览与接入
- [ ] E07 验收(EMB-A01…A16 逐项见第 5 节)
### E02 登记(2026-09-22)
- 真实摄影素材:e2e/fixtures/photo-01..08.jpg(picsum 固定 seed 下载,800×500 ~
1200×400 混合比例);helpers.seedPhoto 扩展 thumbBytes/browseBytes 注入(向后兼容)。
- 静态测量(e2e/embed-v2.spec.ts E02 块,全部断言过):
- wrapper 195×280 / radius 12px / border 1px rgba(255,255,255,0.8) / bg rgb(16,22,30)
/ box-sizing border-box(§2.1 全项);
- 首图(最新序)193 宽 ×135 高(1000×700 原比例);track rowGap 3px(§2.2/2.3);
- 收起:44×44 触区锚定右上、可视圆 24×24 内缩 6px;全窗唯一 button(§2.4);
- 上下 12px 弱暗渐隐(rgba(16,22,30,0.12),§2.3 可选项落地)。
- 截图:actual/desktop/e02-static-desktop.png、actual/mobile/e02-static-mobile.png
(390×844 展开态同尺寸 195×280)。
- 存量偏差修复登记:admin eslint globals 缺 ElNotification(模板 .auto-import.json
生成缓存不含、types/import d.ts 已声明——login/index.vue 存量问题,UI-04 前即红;
最小修复 eslint.config.mjs globals 补 readonly)。
- E02 出口确认:无标题/底栏/页码/左右按钮,图片窗口形态与目标图一致(截图对照)。
### E03 登记(2026-09-22)
- 引擎架构:纯状态机 stream.ts(advanceStream 单帧推进/advanceStreamFor 分块/
anchorRebuild 锚定重建/removePhoto 移除;窗口数学、循环代次 key、DOM 上限 16/
队列上限 30/缓冲 480px 常量)+ 编排 useVerticalPhotoStream.ts(rAF 积分、transform
逐帧直写 DOM 不经响应式、退役/补尾低频同步渲染列表、ResizeObserver 重测锚定、
单张静态不 rAF、恢复重置 lastTime 不补跑;stepForTest 受控时间测试接口)。
- 单测:embed-stream.spec.ts 14 用例(比例防御/窗口覆盖与副本 key/匀速积分与 dt
封顶/退役边界与多帧跨界/锚定保位/新图入未显示区/锚移除回退/removePhoto 保位/
装配推进 transform/单张静态/dropPhoto 清理)——全仓 viewer 236 绿。
- 动态 e2e(embed-v2.spec.ts E03 块):①16px/s 实测 2s 位移 32px(30-34 断言过);
②12s 逐 250ms 采样跨退役边界:匹配照片连续性 -4px/250ms、最大误差 <2.5px;
③20s DOM 实例恒 ≤16;④32s 录屏 recordings/e03-scroll-32s.webm(含 ≥4 个循环
边界,7.7s/条退役节奏)。
- 修复记录:anchorInPhoto 方向(-acc);transform 写入 0.01px 取整(浮点噪声不进
DOM);单张照片窗口副本刷屏违 §3.2.8 → rebuildItems 单张特判恒一实例。
- E03 出口确认:不瞬移(边界连续性断言)、不露空白(匹配采样全程有内容)、
DOM 不无限增长(上限断言)。
## 4 测量与证据索引
(E02+ 起登记:尺寸实测、位移曲线、DOM/连接上限统计、录屏清单。)
## 5 验收矩阵 EMB-A01…A16
| 编号 | 场景 | 状态 | 证据 |
|---|---|---|---|
| EMB-A01 | 多视口固定尺寸 195×280 | 待验 | |
| EMB-A02 | 狭窄/横屏/安全区/多实例不越界 | 待验 | |
| EMB-A03 | 横/竖/全景/单图/0图/2图短循环 | 待验 | |
| EMB-A04 | decode 慢/破图/签名到期/304/失败恢复 | 待验 | |
| EMB-A05 | 循环锚定 + DOM 上限 | 待验 | |
| EMB-A06 | 隐藏/删除/关闭/换绑/停用清理 | 待验 | |
| EMB-A07 | 点击/拖动/悬停/键盘/reducedMotion | 待验 | |
| EMB-A08 | 收起展开/记忆/默认收起/后台配置更新 | 待验 | |
| EMB-A09 | 双上下文真实点赞/重复 burst/错相册/不可见归属 | 待验 | |
| EMB-A10 | WS 断线不假造气泡 | 待验 | |
| EMB-A11 | 真跨源 + 消息伪造拒绝 | 待验 | |
| EMB-A12 | 宿主全局 CSS/重复 script/SPA 移除 | 待验 | |
| EMB-A13 | 后台预览隔离 + v2 接入代码 | 待验 | |
| EMB-A14 | v1 保留 + 普通 viewer 无回归 | 待验 | |
| EMB-A15 | 不上报浏览/不提交点赞 | 待验 | |
| EMB-A16 | 证据完整、未测项如实标注 | 本记录即载体 | |
## 6 未完成项与外部资源
- 真实 CDN/发布不在本轮(方案 §1.2);本轮只产出构建产物与文档。
- E02 起静态样板需真实摄影素材(非 sharp 色块)——种子照片拟下载固定摄影样本入 MinIO;
网络不可用时降级为记录待验,不标记通过。