Files
photo-live/docs/plans/progress/UI04-验收记录.md
T
2026-09-22 13:28:26 +08:00

157 lines
10 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 连续滚动(登记见下)
- [x] 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 不无限增长(上限断言)。
### E04 登记(2026-09-22)
- 暂停原因集合(§4.2):Set 管理(hiddenDocument/offscreen/hoverFinePointer/
focusWithin/pointerActive/manualScroll + reducedMotion/userPaused/active 经 running
闸门汇聚到引擎);瞬态原因清空后 500ms 恢复(scheduleResume 复评);hover 仅
(hover:hover)+(pointer:fine) 媒体查询命中才生效(触摸不粘滞);Space 为用户显式
暂停不自动恢复;aria-live 播报(streamPaused/streamResumed,视觉隐藏不抢布局)。
- 点击语义(§4.1):pointerdown 锁定 data-photo-id;位移 >8px 抑制 click(拖动同时
以 nudgeOffset 跟手平移);pointerup 校验锁定目标一致才放行;照片下线清锁定目标。
- 手动查看(§4.3):滚轮/拖动/上下方向键经引擎 nudgeOffset 平移有限窗口(夹取
窗口范围,不重放历史;实现选择登记:不切换 scrollTop DOM 模式,transform 单一
路径满足无跳变/有限 DOM/锚点恢复);viewport touch-action none 承接触摸手势。
- 键盘(§4.2):viewport tabindex=0 聚焦;Space 暂停切换 / Escape 收起 / Arrow±60px
手动;不抢 INPUT/TEXTAREA/SELECT。
- e2e(E04 块 5 用例全过):悬停冻结+离开恢复;点击弹窗 URL 命中 /p/{photoId};
拖动 30px 不开弹窗;Space 暂停不自动恢复+Escape 收起(宿主把手出现/iframe 隐藏);
槽停用 destroy 无残影(data-poll=1000 加速)。
- E04 出口确认:小窗可操作(暂停/手动/键盘/点击四通道),动画不造成点错照片
(点击锁定+拖动取消断言)。
## 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;
网络不可用时降级为记录待验,不标记通过。