diff --git a/docs/designs/embed-widget-concept-2026-09-22.md b/docs/designs/embed-widget-concept-2026-09-22.md new file mode 100644 index 0000000..50f7eff --- /dev/null +++ b/docs/designs/embed-widget-concept-2026-09-22.md @@ -0,0 +1,35 @@ +# 嵌入组件效果图 · 2026-09-22 + +![嵌入组件](embed-widget-concept-2026-09-22.png) + +内置 image_gen 生成,imagegen 技能。视觉概念稿,不是已运行截图。宿主网站、活动、照片及数字均为示例。 + +## 展示状态 + +- 桌面展开:网站右下方白色卡片,照片轮播、上一张/下一张、暂停、相册入口。 +- 收起:Photos 胶囊入口,会话内记住用户选择。示例蓝点仅表示拟议的新内容提示,未取得真实新内容状态时不显示。 +- 手机展开:默认收起,点击后展开,留出左右边距和底部安全区。 +- 空相册:Photos coming soon,占位不显示假图或假数量。 + +## 实现约束 + +照片使用 contain 完整显示,竖图两侧留中性底。页码为轮播队列位置,不是相册总照片数。点击图片打开单图观众深链;View album 打开相册首页。中文与英文均支持。收起和永久停用分开处理。保持iframe隔离、消息来源验证、不可见暂停与配置版本控制。宿主页面只作接入示意,不属于待重建的网站。暂停和切图为拟议交互,是否已实现需核对现有代码。 + +## 完整生成提示词 + +```text +Use case: ui-mockup. Create one polished high fidelity UI concept board for PhotoLive EMBEDDABLE PHOTO CAROUSEL WIDGET on a third-party corporate website. English UI only. Landscape 2400x1500 or equivalent sharp high resolution. Clean pale cool grey design presentation, heading "PHOTOLIVE / EMBEDDED GALLERY", small subheading "One event. Every moment." Three sections with clear labels: "01 / Desktop expanded" taking left 55% width, "02 / Collapsed" in a compact upper middle-right area, "03 / Mobile expanded" a tall mobile webpage right 25%. Show the widget IN CONTEXT on actual host website mockups. No native app bottom nav. +Visual system matches professional photography app: #1A73E8 blue, white card, navy text #172033, secondary slate #647084, 16px corners, subtle shadow, precise thin icons and legible type. +LEFT: desktop corporate website browser viewport with modest chrome, neutral header "NORTHLINE" and navigation About / Solutions / Events / Contact. Main website has understated architectural expo hero photo, large headline "Meet us at the fair", blue "Explore our exhibits" button, small content cards below. The host is low contrast but still legible. Float PHOTO WIDGET anchored lower right inside browser viewport, around 300px wide proportion relative website. Widget is visually prominent white card with header small blue aperture icon + "Event photos", top-right minus collapse button with generous click area. A FIXED 4:3 photo stage, dark charcoal background, shows a realistic landscape photograph fully contained, international adult visitors meeting at exhibition booth; do NOT crop faces. Delicate left/right navigation buttons over photo at edges. Below photo title "Canton Fair · Autumn", a compact bottom row "03 / 12", small pause control labelled "Pause", and clear blue link "View album ↗". No likes, no comments, no download, no photo count stats beyond carousel index. Entire card balanced and practical. Widget should not cover host's main blue CTA. +UPPER MIDDLE-RIGHT small vignette under "02 / Collapsed": slice of same pale corporate webpage with a compact white pill anchored at bottom-right, blue photo icon + "Photos" + small blue notification dot. Pill 44px high equivalent, rounded, tasteful shadow, not a giant chat bubble. Label below in light grey "A quiet entry point". +RIGHT: flat mobile website viewport without physical phone hardware, browser header tiny URL "northline.example", website brand and hamburger, host website heading "Meet us at the fair" remains visible near top. Lower area has expanded same photo widget nearly full width with 16px side margins, ABOVE mobile bottom safe area, same white header Event photos and minus button, 4:3 dark image stage with a DIFFERENT VERTICAL portrait-format photograph of an adult speaker on stage shown FULLY CONTAINED with dark side gutters. Same footer title "Canton Fair · Autumn" and "04 / 12", Pause, View album ↗. Make mobile photo visibly portrait within landscape stage demonstrating non-cropping. Host site content behind card remains discernible. No bottom navigation, no login, no uploading, no social feed. Entire mobile expanded card fits screen and is dismissible. +Below center vignette include a small standalone horizontal design detail sample, not another full screen: same widget card empty-state mini version with a line photo icon and exact text "Photos coming soon", collapse minus button. Label "Empty state". +Composition impeccable spacing, no arrows or huge explanatory annotation blocks, product screenshot quality, clean understated enterprise aesthetic. Photos realistic and attractive. All event data illustrative. No giant watermarks, no extra floating objects, no device perspective. Prioritize widget readability and matching card components across desktop and mobile. +``` + +## 清理修订提示词 + +```text +Edit this UI design board. Preserve the three website mockups, photo carousel widgets, photography, typography, layout, all inside-screen content exactly. REPLACE ALL exterior presentation-board background with completely solid opaque very pale gray #F3F6FA. Remove every black/blue speckle, transparency artifact, noisy texture, scribble, gradient streak from outside browser/mobile/vignette boundaries. Render a clean entirely opaque professional design board. Retain main top-left heading PHOTOLIVE / EMBEDDED GALLERY and subtitle, section headings. Remove tiny extra slogan at top right and entire decorative footer branding and footer text. Neutral clean margins. Do not change actual widgets or website screenshots. Absolutely no transparency or distressed texture. +``` + diff --git a/docs/designs/embed-widget-concept-2026-09-22.png b/docs/designs/embed-widget-concept-2026-09-22.png new file mode 100644 index 0000000..deb8528 Binary files /dev/null and b/docs/designs/embed-widget-concept-2026-09-22.png differ diff --git a/docs/designs/embed-widget-fixed-size-2026-09-22.md b/docs/designs/embed-widget-fixed-size-2026-09-22.md new file mode 100644 index 0000000..37f17e6 --- /dev/null +++ b/docs/designs/embed-widget-fixed-size-2026-09-22.md @@ -0,0 +1,18 @@ +# 嵌入组件 · PC与手机统一紧凑尺寸 + +![效果图](embed-widget-fixed-size-2026-09-22.png) + +日期:2026-09-22。内置image_gen生成的概念稿,非实际网页截图。 + +本版替代上一版大卡片尺寸方向:PC与手机均按195×280 CSS px作为实现参考,不使用桌面50vw/33vh,也不随桌面屏幕放大。手机390×844视口时约为宽度一半、高度三分之一。设计图的两个视口展示缩放略有差异;工程验收以CSS实测195×280为准,不能按画板截图像素反推。 + +卡片结构:紧凑Photos标题与收起、图片轮播、相册名、页码/暂停/观众页入口。统一右下悬浮,PC右16/下24px,手机右12/下24px并避让安全区。极端小视口允许缩小以免越界,不能放大。示例网站、图片和数字不写入产品;点击图片打开单图深链,View打开相册。交互目标仍应保证可点击,暂停/关闭有效区域需在实现时核验。 + +## 完整提示词 + +```text +Use case: ui-mockup. Create a precise clean high-fidelity responsive web design comparison board showing ONE SMALL FIXED-SIZE embeddable photo carousel on BOTH DESKTOP AND MOBILE. Critical requirement: widget CSS size is identical on both platforms, WIDTH 195px HEIGHT 280px. It does NOT scale to 50% of desktop width. Both website viewports shown at approximately SAME SCALE on the design board so the two widgets visibly have the same physical pixel dimensions. Large landscape canvas approx 2000x1100. Desktop website mockup left: logical 1100x760. Mobile website mockup right: logical390x844. Both displayed at same scale, with ample margins on solid opaque #F3F6FA background. NO third enlarged component detail; only desktop and mobile comparison. Heading "ONE WIDGET. SAME SIZE." Subheading "Desktop & mobile · 195 × 280 px". Labels "DESKTOP" and "MOBILE" above the corresponding viewports. +Desktop host website subtle neutral corporate NORTHLINE page with header About Solutions Events Contact, hero architectural trade show photograph, headline "Meet us at the fair", blue Explore exhibits CTA, lower three feature cards. Actual carousel is SMALL, anchored bottom-right of desktop browser content, 16px right and24px bottom, width195px andheight280px relative1100x760 host. Most desktop site remains unobstructed. Mobile host website SAME NORTHLINE theme, stacked content, menu, hero and CTA, lower content; carousel floats bottom right, right12 bottom24, SAME195x280 logical size, taking HALF mobile width andONE THIRD mobile height. Left half of mobile content remains visible. Both widgets show same photo and EXACT same layout and dimensions, do not enlarge desktop widget. The mobile viewport is much narrower than desktop because same scale. +Widget: clean white radius12 small shadow, header36px blue photo icon and 'Photos' in12px, minus collapse control at top-right. Image stage195x174px showing natural trade fair networking photograph of adult business visitors fully contained on charcoal backing. Title row26px 'Canton Fair' bold12px. Bottom44px action row: tiny '3 / 12', pause icon with generous clickable spacing, blue 'View ↗'. Total280. Thin small previous/next arrows on photo sides. No likes, downloads, comments, login, upload or large toolbar. No mock data outside widget except host. Photos realistic, text crisp. Add discreet dimension annotations '195 px' below each widget or each same-size outline, and '280 px' alongside if room; no arrows over actual content. Blue #1A73E8 accent navy #172033 text. Flat front-facing browser website frames, no device hardware, no perspective, no busy graphic decorations. Entire canvas opaque pristine light background. PRIORITIZE visibly identical widget size on desktop and mobile. This is an implementable UI design mockup, not code or an infographic. +``` + diff --git a/docs/designs/embed-widget-fixed-size-2026-09-22.png b/docs/designs/embed-widget-fixed-size-2026-09-22.png new file mode 100644 index 0000000..1019fe9 Binary files /dev/null and b/docs/designs/embed-widget-fixed-size-2026-09-22.png differ diff --git a/docs/designs/embed-widget-scroll-hearts-2026-09-22.md b/docs/designs/embed-widget-scroll-hearts-2026-09-22.md new file mode 100644 index 0000000..4f09486 --- /dev/null +++ b/docs/designs/embed-widget-scroll-hearts-2026-09-22.md @@ -0,0 +1,32 @@ +# 嵌入组件:自动向上滚动与点赞气泡 + +日期:2026-09-22。内置 image_gen 生成的静态概念图,不是运行中的动画或已实现页面。 + +![最新效果](embed-widget-scroll-hearts-2026-09-22.png) + +## 最新设计要求 + +- PC、移动端统一195×280 CSS px,右下悬浮,不按PC屏幕百分比放大。画板两视口缩放不同,实际尺寸按CSS验收。 +- 移除标题栏、底部数量、暂停、切图按钮和View入口。仅保留照片右上轻量收起入口。 +- 单列照片带自动连续向上滚动,上方逐渐移出,下方新图进入,不是横向切换或淡入淡出轮播。 +- 图片宽度填满窗口,高度优先按原比例;窗口裁出滚动中片段,不把每张照片固定裁成窗口比例。照片间距约3–4px。 +- 右侧覆盖珊瑚粉色半透明心形气泡,轻量上浮,不挡脸、不拦截照片点击。 +- 点击某张照片打开对应观众单图深链;不需要底部跳转按钮。 +- 宿主网站、照片、尺寸箭头及画板底部英文说明只作设计示意,不属于组件实际内容。 + +## 实现时需保留的约束 + +收起、页面不可见暂停动画和取数;减少动态效果时停止自动滚动并提供手动滚动。键盘焦点/悬停暂停便于点击,避免照片移动造成点击错图。少量照片不重复创建无限DOM,可用有限窗口循环并在边界无缝衔接;单图时静态展示,无图显示精简空态。 + +点赞气泡应使用真实相册点赞事件并限制粒子数量,不能随机制造他人点赞。当前嵌入模块是否已接入实时事件须实现前核对;事件对应不在视口的照片时不得误暗示当前图被赞,可在下一次对应图可见时展示尚新鲜事件或直接丢弃视觉展示,不改真实计数。缩略图签名、隐藏/删除、换绑及停用需沿用既有权限和版本机制。以上为交互建议,不代表已实现。 + +## 完整生成提示词 + +```text +Use case: ui-mockup. Create a high fidelity design comparison board for a TINY FIXED-SIZE AUTO VERTICALLY SCROLLING event photo window embedded on desktop AND mobile corporate websites. This is NOT a slideshow carousel. Both widgets same CSS size 195px wide x280px high on desktop and mobile. No sizing relative to desktop. Landscape clean opaque pale grey board, two front-on website viewports: desktop1100x760 logical left, mobile390x844 logical right, near same scale. Heading "LIVE MOMENTS, FLOWING UP". Subtitle "Auto-scroll photo window · 195 × 280 px". Labels DESKTOP / MOBILE. +Host website NORTHLINE, architectural trade exhibition photography hero, heading "Meet us at the fair", blue Explore exhibits button, quiet feature content below. Widget floats bottom right of each viewport at fixed small size. Most host content remains clear. +CRITICAL WIDGET DESIGN: a rounded12 rectangular PHOTOS-ONLY WINDOW, edge-to-edge photographs, no card header, no footer, NO photo counts, NO pause button, NO arrows, NO dots, NO view link, NO title, NO toolbar. Only a tiny subtle translucent minus/collapse affordance top right over the photo. Photo content scrolls AUTOMATICALLY UPWARD like a continuous vertical filmstrip: inside each 195x280 viewport show bottom portion of preceding exhibition photo at the TOP (~45px), one main natural photograph of diverse adult business visitors networking at trade booth in the MIDDLE (~155px), top portion of next photo of speaker/stage entering at the BOTTOM (~75px), separated by slim4px pale gutters. Horizontal photo edges make the vertical stacking explicit. NOT horizontal slides. Two to three image fragments visible at once. Realistic photography no distortion. Add subtle soft fade only at very top/bottom edges to suggest clipped moving stream. +Over the RIGHT SIDE of photos, independent translucent coral/pink HEART BUBBLES gently rising, 4-6 varied size12-20px, soft opacity, no black bubbles, no text counts, no avatars, no likes toolbar. Bubbles do not obscure faces. Both desktop and mobile have exactly matching window style and same logical size. +Outside the website frames, a discreet small upward motion annotation with arrow and label "Photos move upward automatically" near lower margin, and a small note "Tap a photo to open the gallery". These labels are on design board only, not widget UI. A small195×280px dimension label may be outside each card. Make actual widget visually photos-only; no whitespace below images. Corporate host website is background context only. English text clean and crisp. Professional restrained white/blue websites with tiny photorealistic photo windows and coral hearts. No mobile native navigation, login, upload or dashboard. No physical devices, perspective, ornamental objects, transparency noise. Full crisp opaque board. Show the static mid-scroll state clearly; do not falsely depict animation as video. +``` + diff --git a/docs/designs/embed-widget-scroll-hearts-2026-09-22.png b/docs/designs/embed-widget-scroll-hearts-2026-09-22.png new file mode 100644 index 0000000..e31e3a7 Binary files /dev/null and b/docs/designs/embed-widget-scroll-hearts-2026-09-22.png differ diff --git a/docs/designs/ui04-implementation/reference/v1-desktop-baseline.png b/docs/designs/ui04-implementation/reference/v1-desktop-baseline.png new file mode 100644 index 0000000..a5fcc92 Binary files /dev/null and b/docs/designs/ui04-implementation/reference/v1-desktop-baseline.png differ diff --git a/docs/designs/ui04-implementation/reference/v1-mobile-baseline.png b/docs/designs/ui04-implementation/reference/v1-mobile-baseline.png new file mode 100644 index 0000000..683477a Binary files /dev/null and b/docs/designs/ui04-implementation/reference/v1-mobile-baseline.png differ diff --git a/docs/plans/2026-09-22-UI04-嵌入组件上滚照片窗高保真实施方案.md b/docs/plans/2026-09-22-UI04-嵌入组件上滚照片窗高保真实施方案.md new file mode 100644 index 0000000..6c5a9dc --- /dev/null +++ b/docs/plans/2026-09-22-UI04-嵌入组件上滚照片窗高保真实施方案.md @@ -0,0 +1,507 @@ +# UI-04:嵌入组件自动上滚照片窗高保真实施方案 + +版本:1.0 +日期:2026-09-22 +状态:待执行;任务复选框与验收项均须实现后填写。 +执行对象:Claude 或其他接手本仓库的开发者。 + +## 0. 执行目标 + +将新版嵌入组件实现为:**PC和手机均195×280 CSS px、照片连续自动向上滚动、真实点赞心形气泡、无标题栏和底部数量/操作栏,点击照片进入对应观众页,仅保留照片右上收起入口。** + +这不是旧轮播改颜色任务。必须改变展示模型:从单张横向/淡入轮播改成单列连续照片带。交付真实可运行的loader、iframe、相关配置/预览与测试证据,不能仅制作静态页面或另写方案。 + +### 唯一目标图 + +![最终目标图](../designs/embed-widget-scroll-hearts-2026-09-22.png) + +- [最新设计说明](../designs/embed-widget-scroll-hearts-2026-09-22.md) +- 旧的大卡片、固定小卡片带底栏两版图不再是本次目标。 +- [UI-01](2026-09-21-UI01-App与悬浮组件体验优化实施方案.md)中组件的通用安全、权限和生命周期要求继续有效;展示样式以本文为准。 +- 图上宿主网站、尺寸箭头、外部英文说明是展示板内容,不得注入用户网站。 +- 画板中的PC/手机窗口缩放不同,实际尺寸以浏览器getBoundingClientRect测量为准,不能从画板像素反推。 +- 图是静态中途滚动示意;完整验收必须含动态视频与状态测试。 + +## 1. 当前实现与改造边界 + +### 1.1 已核对的现状 + +- `packages/embed-loader/src/params.js` 当前sm=280、md=320。 +- 已有脚本显式参数 > 后台配置 > 默认值的优先级,configVersion校验、collapse/expand/config/destroy消息。 +- loader已有宿主定位、多实例排列、收起记忆与窗口适配。 +- `EmbedPage.vue` 是数据/生命周期薄壳;现有 `pages/embed/` 展示组件包含轮播舞台与底栏。 +- `useEmbedFeed.ts` 已有取数、退避、可见性、停用处理,优先复用。 +- 观众页已有 `RealtimeClient` 及点赞事件处理,但不能假设嵌入组件已经有独立实时订阅。 +- 现有布局/配置不是本效果图,不能仅把SIZE_WIDTH改195就宣布完成。 + +### 1.2 本轮范围 + +必须完成:新展示模式、尺寸规则、无缝向上滚动、真实气泡、点击/暂停/收起、数据更新一致性、后台预览/接入代码、版本兼容、视觉及动态验收。 + +不包含:重做宿主网站、App、普通观众页、后端全部同步系统;新增嵌入组件点赞提交按钮;登录/注册、评论、统计看板、原图下载、自动弹新页。 + +保护当前工作树改动,不执行reset/clean;不自动推送、部署、打发布标签或修改CDN。外部资源不足要登记,继续可完成任务,但不得把关键视觉/动态项标通过。 + +## 2. 固定视觉规格 + +### 2.1 尺寸与定位(硬性要求) + +| 属性 | 新版固定值 | +|---|---| +| 宽 | 195 CSS px | +| 高 | 280 CSS px(包含边框) | +| box-sizing | border-box | +| 桌面位置 | 默认right:16px,bottom:24px + safe-area | +| 手机位置 | 默认right:12px,bottom:24px + safe-area | +| 圆角 | 12px | +| 边框 | 1px rgba(255,255,255,0.80),不叠两圈边框 | +| 阴影 | 0 4px 16px rgba(15,23,42,0.16) | +| 背景 | #10161E,加载/缺口不露宿主内容 | +| z-index | 默认1000,沿用显式可配置范围 | +| 外部留白 | 0,照片铺满内部舞台 | + +- PC不能使用50vw/33vh,手机也不是随任意屏幕比例无限伸缩。以390×844手机的半宽/约三分之一高为设计来源,但生产两端固定195×280。 +- 320、390、430、768、1440px常见视口都保持相同CSS尺寸。 +- 可用宽/高不足时才缩小:W=min(195,可用宽),H=min(280,可用高)。仍需保持有效收起触控;小到无法操作时改成收起入口,而不是缩成不可点。 +- 不用transform:scale整体缩放卡片(会同时缩小文字/触控区)。 +- wrapper与iframe都使用固定height,iframe内容不能通过旧resize消息把新版改回内容高度。 +- 默认手机仍沿用已有“首次收起”策略以减少遮挡,展开后尺寸必须一致;视觉验收要主动展开,不得拿收起截图替代。 +- 用户主动展开/收起优先于默认值,不因轮询、换向或配置刷新反复弹出。 +- 自定义position/offset/zIndex继续支持,显式值优先;默认12/16只有未配置时按视口取值。 + +### 2.2 层级与DOM结构 + +```text +host fixed wrapper (195×280, clip radius) + iframe (100%×100%, no border) + PhotoStreamViewport (relative, 100%, overflow hidden / manual mode scroll) + Track (vertical photo instances, translateY) + PhotoLink > img + 3px separator + PhotoLink > img + ... + HeartParticleLayer (absolute, clipped, pointer-events:none) + CollapseButton (absolute top-right, accessible) + StateOverlay (loading/empty/error when needed) +``` + +- 没有header、相册标题、footer、页码、Pause按钮、左右箭头、圆点和View链接。 +- 不留已删除工具栏的padding/空白高度。 +- 关闭控件层级最高,心形层其次,照片层最低;组件外不拦截宿主点击。 +- 控件/气泡裁切在窗口内,阴影可以在wrapper外;无需模糊大块背景。 +- 图片间隙3px,颜色#F6F8FB。不要每张图再加圆角,外窗负责整体圆角。 + +### 2.3 图片呈现 + +- 内容宽为实际内宽(195减边框);依据元数据宽高按原比例计算图片高度,使用block、width:100%、height:auto。 +- **每张照片不固定为195×280**;窗口剪切的是滚动照片带,不是把每张图强制裁到窗口比例。 +- 真实横图会较矮、竖图较高;图上同时出现2–3个照片片段是示例,生产不强制每时刻恰好三张。 +- 超长图默认保持比例;如当前数据存在异常宽高,使用安全占位比例并记录,不让无穷高度破坏循环。 +- 确定元数据可用范围和fallback(建议宽高>0且finite;异常值按4:3占位),实际解码与元数据方向不符时受控修正高度并锚定当前位置。 +- 只用thumb或适合该宽度的浏览变体;禁止预加载所有原图。 +- 可选上下12px弱暗渐隐,opacity≤0.12;不得用强白雾遮掉照片内容。 +- 图片内容靠真实API;测试使用固定摄影素材,不能用sharp色块证明摄影视觉还原。 + +### 2.4 收起入口 + +- 可视按钮:右上6px,圆形24×24,背景rgba(255,255,255,0.82),minus图标12,颜色#647084。 +- 触控区域44×44,锚定右上;可视圆居于点击区右上内缩6px。这个区域不同时触发照片链接。 +- 明确aria-label“收起照片窗 / Collapse photo window”,不是永久关闭展示位。 +- 收起后沿用小型Photos/照片入口,建议88–104×44,圆角22、白底、蓝图标16与12px文字。 +- 图中没有展示收起样式,沿用此前轻量入口,不能变成195×280白空框。 +- 停用/解绑的destroy与用户collapse不同:前者移除照片窗及入口,不允许打开空壳。 + +## 3. 自动向上滚动:确定性算法 + +### 3.1 速度和时序 + +| 参数 | 默认值 | +|---|---| +| scrollSpeed | 16 CSS px/秒 | +| 可配置范围 | 8–32 CSS px/秒 | +| 帧驱动 | requestAnimationFrame | +| 启动 | 首个可见区域与其下一张已decode,初始至少静置500ms | +| 首帧等待上限 | 取数/加载失败按状态机,不永久骨架 | +| 手动交互恢复 | 指针/焦点离开后500ms,且没有其他暂停原因 | +| deltaTime | 恢复时重置lastTime;单帧上限50ms,长停顿不补跑 | + +保持匀速linear,不要“一张停留5秒→切换”也不要ease-in-out反复加减速。每帧通过elapsed time积分,不能固定每帧移动1px,否则高刷新率设备速度不同。 + +不在每帧触发整个Vue树更新:用DOM transform/animation state精简更新;测量尺寸在布局事件和队列变更时进行,避免每帧读layout后写style。 + +### 3.2 有限环形队列(建议实现) + +数据层按photoId保存唯一照片队列;渲染层是有限窗口的实例,不是无限追加DOM。 + +1. 计算照片高度及3px间距,装入足够覆盖窗口和预加载区域的条目。 +2. 保存头实例ID、头部被移出像素offset及sequence游标。 +3. rAF增加offset,track translateY(-offset)。 +4. offset超过头条目高度+gap时,将头条目退役,offset减去该值,并在尾部补下一张;跨界过程应保持屏幕内容相同。 +5. render实例key包含循环代次,避免photoId重复出现造成重复key。 +6. 只保留可见窗口+前后缓冲。建议最多16个DOM图片实例、数据队列最多30张;尺寸极矮照片无法填满窗口时使用受控补位或静态回退,不能无限扩DOM。 +7. 内容两张以上但一轮高度短于窗口,可使用少量可见循环副本填充;副本不要全部可聚焦。相同photoId的非主要副本对辅助技术隐藏,并处理点击到对应原图。 +8. 仅一张照片时静态展示,不把同一张复制成刷屏。单张长图在减少动画/手动模式下可滚动查看;自动状态优先完整contain单张,不上下无穷重复。 +9. 无照片使用空态,不启动rAF。 + +若采用不同循环实现,必须满足相同无跳变、有限DOM、唯一事件绑定、焦点安全和动态更新要求,在验收记录解释;不能用整条CSS动画固定时长后瞬移回原点且露出空白。 + +### 3.3 图像预加载和失败 + +- 启动前固定metadata比例占位,decode成功再显示,避免高度由0膨胀。 +- 预加载当前可见项及接下来2张;复用浏览器缓存,不对每个循环重复刷新URL。 +- 单张失败:受控刷新签名一次;仍失败则在安全边界跳过该照片,后续刷新成功可恢复。 +- 全部失败:停止滚动,紧凑“暂时无法加载照片”状态,保留收起;后台按既有退避继续尝试。 +- 首屏网络失败不能永远显示骨架。 +- 304不代表签名永久有效;继续复用/修正既有签名刷新策略,重试需有次数和速率上限。 + +## 4. 连续滚动下的交互和可访问性 + +用户要求无底部按钮,不等于去掉暂停/可访问机制。 + +### 4.1 照片点击 + +- 照片用真实a链接,目标为观众 `/a/:albumToken/p/:photoId?lang=...`。 +- 用户手势新标签打开,保留noopener/noreferrer;不打开OSS URL,不自动弹窗。 +- pointerdown时暂停并锁定当前目标photoId;pointerup确认未拖动且目标未被删除后才允许点击。 +- 位移超过8px或被识别为滚动手势时不触发打开。 +- 点击到循环副本仍定位同一照片,不能按当前队列索引重新计算。 +- 照片隐藏/换绑后取消待触发点击,防止已下线图仍被打开。 + +### 4.2 暂停原因集合 + +使用Set或等价状态管理以下原因,不能多个布尔值互相误覆盖: +hiddenDocument、parentCollapsed、offscreen、hoverFinePointer、focusWithin、pointerActive、manualScroll、reducedMotion、destroyed、loading、insufficientContent。 + +所有原因清空才可自动滚动。hover仅对支持hover的精细指针启用;触摸手机不能因粘滞hover永久停住。 + +- 细指针悬停暂停,离开恢复。 +- 键盘焦点进入暂停;离开恢复。Space在容器聚焦时切换暂停/恢复,Escape收起;不抢输入字段或宿主按键。 +- 减少动态效果时默认禁自动滚动与粒子,允许手指/滚轮/键盘手动查看,不能仅停止在一张不可浏览的裁片。 +- 用户手动暂停需有内部状态及aria状态说明,无需额外底部按钮;可以在聚焦时显示非布局占位的小提示,不能常驻抢视觉。 +- 普通模式触摸垂直手势进入手动滚动,保留清晰的恢复规则(离开后500ms;用户明确键盘暂停则不自动恢复)。 +- 装饰粒子aria-hidden,不让屏幕阅读器逐颗播报。 +- 照片链接可访问名称使用真实上下文或“活动照片”,不编造画面描述。 +- 不用外层div假装按钮而缺少键盘操作;循环复制内容不可制造无穷Tab顺序。 + +### 4.3 手动模式与自动模式转换 + +切换时用当前photoId + 图内偏移作为锚点。不能将transform的自动视图直接切成scrollTop=0导致回顶。手动模式保持有限真实列表并可滚动;自动恢复时从可见锚点恢复,不重放所有历史。 +图内图片的交互与收起入口都必须可用,不能用全窗透明div拦截所有点击实现暂停。 + +## 5. 点赞心形气泡 + +### 5.1 视觉冻结值 + +| 项目 | 值 | +|---|---| +| 区域 | 右侧宽54px,上避让收起44px | +| 颜色 | #FF6B7A、#FF8B98,两档即可 | +| 形状 | 同一实心heart,可有微弱白色中心高光;非聊天气泡 | +| 大小 | 12、16、20px | +| 透明度 | 从0→0.85→0,尾部淡出 | +| 生命周期 | 1400–1800ms | +| 上移距离 | 90–130px | +| 左右漂移 | -8..8px的预定义曲线 | +| 旋转 | -8..8度 | +| 同时在屏数量 | 最大8 | +| 发射频率 | 最大每250ms一颗,事件可合并 | +| 点击/读屏 | pointer-events:none、aria-hidden=true | + +照片本身和气泡都是向上运动,但气泡更快,不附着在照片track上;用独立overlay定位。不能用emoji字体爱心代替统一形状而在不同平台变成不同图案。可用固定SVG心形或已有图标资源。 + +### 5.2 必须真实事件驱动 + +- 不用随机计时器伪造他人点赞。 +- iframe只订阅当前公开相册的真实likes.burst,不新增点赞写请求,也不创建虚假的own batch。 +- 复用底层 `RealtimeClient`,新增轻量 `useEmbedReactions` 编排;不要直接调用整个 `useAlbumRealtime` 并带出观众浏览上报/点赞提交副作用。 +- 不订阅slotToken当作albumToken:从公开展示位响应的album.publicToken解析。 +- 事件校验:当前album、photoId、delta合法,按burstId去重;短期去重表有TTL和容量上限。 +- 一个delta=100批次不创建100个节点;例如1→1颗、2–5→2颗、更大→3颗,并受全局限量;这只是视觉抽样,不修改真实统计。 +- 只对当前可见照片的真实事件显示气泡,确保不会误暗示另一照片被赞。可见定义:与视口交集面积>0且高度至少20px。 +- 未可见照片事件最多缓存5秒(总缓存上限50条),5秒内对应图进入可见区可展示,否则丢弃视觉事件。不为了展示旧事件让滚动跳转。 +- 气泡起点取相应可见照片交集的下侧且不压操作区;上移过程裁在照片窗中。 +- 收起/隐藏/切相册清空粒子和短期缓存;恢复不重放大量旧点赞。 +- WebSocket失败时照片继续按取数运行,**没有事件就不造气泡**;不要用点赞总数差值冒充实时事件。 + +### 5.3 订阅生命周期 + +- 公开相册已解析且组件活跃才建立订阅。 +- 一个iframe最多一个实时连接;多个相册实例不盲目共享错误token。连接池是后续优化,不要求新增宿主跨iframe中转。 +- 相册换绑:先停止旧连接、清气泡和去重、清旧内容,再订阅新相册。 +- 收起/隐藏超过短宽限期可断开以节省连接,恢复校准后重连;不能每一帧可见性变化都重连。 +- 卸载/destroy清理socket、重连timer和事件监听。 +- 暂停自动滚动不等于断开实时:hover/focus期间可接收计数事件,但reducedMotion不生成动效。 +- 宿主隐藏与iframe可见性需结合父消息和document.visibilityState,不能只依赖iframe内部IntersectionObserver推断宿主遮挡。 + +## 6. 数据更新:不能抖动、复活或串相册 + +### 6.1 轮询/动画分离 + +- 默认公开数据轮询30000ms,复用ETag和退避;scrollSpeed是像素/秒,与轮询毫无绑定。 +- 后台标签页、收起、destroy停止动画及不必要轮询,恢复立即取一次当前配置。 +- 不为每张图片边界调用API。 +- 每次有效响应不重置offset和头照片,不让30秒一次刷新导致回顶部。 + +### 6.2 锚定策略 + +更新前保存首个可见photoId及其图内偏移;更新后若仍存在,用新尺寸重算位置保持该照片相同屏幕位置。 +新增图排入尚未显示区域,在下一安全边界进入;不插到用户点击中的照片前。URL更新不视作新照片。 +元数据宽高变化使用同样锚定。photoId作为身份,render instance key仅用于循环实例区分。 + +### 6.3 删除、隐藏和内容窗口 + +- 若接口返回的是完整“近期窗口”,其缺席表示从当前轮播候选窗口淘汰,**不直接声称照片被删除**。 +- 明确photo.hidden/deleted事件则立刻从渲染及缓存移除;正在显示的移除要选择下一有效项,清它的气泡/待点击目标。 +- 区分“新增”“窗口滑出”“显式下线”,不要把队列永远追加成无限列表。 +- 暂停状态也要应用隐藏/停用,不能因暂停而继续展示已撤下图。 +- 相册关闭、展示位解绑/禁用返回相应不可访问状态时清照片并destroy入口。 +- 普通网络错误不当作停用:保留仍有效缓存,退避重试。 +- 配置版本低/旧请求响应一律丢弃;相册换绑不复用旧图片或旧事件缓存。 +- 下线可见性延迟沿用现有后端通知能力并实测记录,不宣称前端能保证跨境零延迟。 + +## 7. 配置与兼容:新增v2,不破坏现有接入 + +### 7.1 推荐版本策略(执行默认) + +- 新设计作为 `/embed/v2/loader.js` 发布入口,新增输出,不覆盖旧v1语义。 +- v2默认mode=vertical-stream、195×280;v1保留旧carousel,避免正在使用旧站点一夜改变尺寸。 +- 可继续使用同一iframe路由并传入经过白名单的mode/version,或独立路由;必须使旧v1不渲染新footerless结构。最终选择在验收记录写清。 +- 新版后台生成代码默认v2;既有站点想使用新版需更新script URL或显式选新模式,这一点在接入文档写明。 +- 新构建产物采用hash或可追踪版本文件,保留稳定v2入口的合理缓存策略;本轮只产出方案/文件,不自动刷新真实CDN。 +- 若仓库已有不可变hash发布实现,复用,不另造冲突机制。 + +### 7.2 新模式配置 + +| 配置 | 默认/规则 | +|---|---| +| displayMode | 新版vertical-stream;旧记录缺省按版本决定旧carousel | +| scrollSpeed | 16,范围8–32,单位CSS px/s | +| reactionsEnabled | true,关闭只隐藏气泡不影响照片 | +| position | right,沿用白名单 | +| offsetX/offsetBottom/zIndex | 沿用字段及范围,默认见第2节 | +| lang | auto,沿用相册语言回退 | +| collapsedDefault | 沿用用户选择优先与手机默认收起 | +| size / intervalMs / imageFit | v1仍有效;v2尺寸固定、连续原比例照片,不用旧字段改变新布局 | + +优先级:版本定义的硬性尺寸 > script显式有效设置 > 展示位配置 > 默认值。v2不可通过旧data-size=md恢复320px;后台预览清楚显示其在新模式无效,而不是保存后偷偷生效。 + +- 缺省与显式参数继续区分。 +- 新字段采用兼容扩展:更新契约、生成类型、DTO验证、国内设置、海外投影与admin编辑,缺字段有正确回退。 +- 设置JSON整体替换时必须保留完整既有字段,不因新增两项丢其他配置。 +- 不新增任意CSS/HTML传输。 +- 数据是否需要迁移取决于当前schema字段类型;JSON新增可选字段不自动要求破坏性迁移。 + +### 7.3 消息协议 + +保留origin+source+type检查。 +- config:只传白名单字段和configVersion;v2忽略旧size带来的尺寸变更。 +- collapse/expand:用户行为;父向子同步暂停原因及实际状态,不能仅设父高度0而iframe继续动画。 +- destroy:移除DOM、入口、listeners、timers和实例注册。 +- resize:v1按旧行为;v2只能使用固定280或极小视口裁决后的高度,不能被子内容撑大。 +- 可新增visibility/layout消息:布尔可见性、有效宽高、版本;验证数值范围,不透传对象到style。 +- 多实例使用iframe contentWindow识别,不能只按相同origin广播所有状态。 +- 第三方脚本伪造消息不能展开、移位或改变其他实例;不能接受任意targetOrigin='*'配置变更。 + +## 8. 宿主适配与管理预览 + +### 8.1 宿主 + +- iframe维持跨域隔离和最小sandbox,链接新页保持安全。 +- wrapper样式限定自身,禁止修改宿主body滚动、字体、全局img/button样式。 +- SPA重复插入同slot不能重复创建,移除/再引入的行为需明确;沿用已有去重能力并回归。 +- 多slot同侧纵排,间隔12;空间不足后续实例收起,不重叠、不把第一实例突然放大。 +- 更新窗口方向、安全区、浏览器地址栏变化时重新计算位置,但不重置滚动队列。 +- 无法自动避让全部客服/Cookie浮层,提供offset/zIndex配置,不承诺智能识别所有宿主。 +- 卡片边缘外不放透明大框拦截网页,阴影不影响点击范围。 + +### 8.2 后台预览 + +- 新增“照片上滚 / 旧版轮播”模式选择,默认新建选择新版;旧记录仍按旧模式显示。 +- 新版只显示相关配置:速度(px/s)、气泡开关、位置/偏移、语言、收起默认;宽高只读195×280。 +- preview用真实展示组件,数据源注入;不要再写一套静态好看的preview而生产是旧轮播。 +- PC与手机预览都按同一CSS尺寸渲染,避免把preview整体缩放后误判尺寸。 +- 预览可以提供宿主尺寸切换和“模拟真实点赞事件”按钮,但按钮只在管理预览工具区,不在实际组件;事件明确是测试模拟。 +- 未保存预览不得修改线上slot,不上报浏览、不提交点赞、不订阅真实观众事件后当作模拟。 +- 生成的接入代码使用v2,语言/参数正确;保存后真实跨源宿主页能更新。 + +## 9. 文件地图 + +| 位置 | 任务 | +|---|---| +| packages/embed-loader/src/params.js | v1/v2参数、速度/模式、硬性尺寸、兼容归一化 | +| packages/embed-loader/src/loader.js | 固定外壳、消息、收起/visible、多实例生命周期 | +| packages/embed-loader/package.json、sync-to-viewer.js | v2和hash产物构建/同步,保留v1 | +| packages/embed-loader/README-embed.md | 新旧接入、固定尺寸、偏移、暂停与限制 | +| apps/viewer/src/pages/EmbedPage.vue | 按版本/模式分支,接入新流与气泡 | +| apps/viewer/src/pages/embed/(现有组件) | 旧轮播保留;新建StreamViewport/StreamPhoto/ReactionLayer等 | +| apps/viewer/src/embed/useEmbedFeed.ts、feed.ts | 数据队列、版本、过期刷新、生命周期复用 | +| apps/viewer/src/embed/useVerticalPhotoStream.ts(建议新增) | rAF、锚定、有限队列、手动模式 | +| apps/viewer/src/embed/useEmbedReactions.ts(建议新增) | 轻量实时订阅、去重、可见归属与粒子限量 | +| apps/viewer/src/embed/postMessage.ts | v2消息形状与验证 | +| apps/viewer/src/realtime/ws.ts | 复用连接层,避免破坏普通观众页 | +| apps/viewer/src/i18n/locales/ | 英中文案和ARIA | +| apps/admin/src/views/system/embed-slots/ | 模式/速度/气泡/预览/代码生成 | +| apps/admin/src/types、api、utils相应模块 | 配置类型、默认值和校验 | +| packages/contracts/openapi.yaml及生成物 | 兼容字段,不手改生成文件 | +| services/api/src/embed/、embed-ov/、同步投影 | 设置验证与海外响应 | +| apps/viewer/e2e/embed.spec.ts等 | 跨源、动态、尺寸、安全回归 | + +以当前文件为准追踪调用链。建议新增组件名可以调整,但职责不能散落成不可测试的大文件。共享样式不得影响普通观众页。 + +## 10. 分步执行任务 + +### E00 基线 +- [ ] 阅读目标图、当前代码及已有UI-01验收。 +- [ ] 保存旧v1运行截图、尺寸、网络和配置行为。 +- [ ] 记录Git已有改动、隔离测试资源,建立UI04验收记录。 +出口:明确旧版保留、新版新增边界。 + +### E01 契约和版本骨架 +- [ ] v2路由/参数/构建规划,新增兼容字段。 +- [ ] admin、API、海外投影、新旧缺省值一致。 +- [ ] 验证旧v1配置不变,新v2固定195×280。 +出口:先得到跨源可见的固定小窗,不存在footer。 + +### E02 静态高保真样板 +- [ ] 注入固定摄影数据,搭好单列照片片段、边框、收起、粒子层。 +- [ ] PC1440×900、手机390×844同时截图并测量尺寸。 +- [ ] 先对照修好样式,再加入滚动,不能用动画掩盖布局错误。 +出口:无标题/底栏/页码/左右按钮,图片窗口形态与图一致。 + +### E03 连续滚动 +- [ ] rAF匀速、有限环形队列、预加载与失败跳过。 +- [ ] 锚定更新、新照片、单图、短队列、长图验证。 +- [ ] 连续录制至少30秒包含循环边界。 +出口:不瞬移、不露空白、不无限增长DOM。 + +### E04 操作和生命周期 +- [ ] 点击目标锁定、拖动取消、hover/focus暂停、手动模式。 +- [ ] 收起/展开/不可见/方向变化,destroy彻底清理。 +- [ ] reducedMotion与键盘语义。 +出口:小窗可操作,动画不会造成点错照片。 + +### E05 实时气泡 +- [ ] 只读轻量订阅当前相册、去重、可见照片归属。 +- [ ] 独立粒子层、限量、真实burst驱动。 +- [ ] 换绑/断线/隐藏/销毁清理,不假造事件。 +出口:两个浏览器上下文中真实点赞可触发正确图的气泡。 + +### E06 管理预览与接入 +- [ ] 模式/速度/气泡设置与v2代码生成。 +- [ ] 共享展示组件、未保存预览隔离、模拟事件明确标识。 +- [ ] 构建同步新产物,版本/缓存说明。 +出口:后台保存与第三方跨源实际效果一致。 + +### E07 验收 +- [ ] 全部第11节矩阵、静态对照、动态录屏与网络检查。 +- [ ] 修复回归;普通viewer和v1不受影响。 +- [ ] docs/plans/progress/UI04-验收记录.md,截图索引、待验证事项。 +出口:功能/视觉/动态分别有结论,不用测试数量替代看图看视频。 + +任务依赖E00→E01→E02→E03→E04→E05→E06→E07;不要求额外代理。缺环境继续不受影响的工作,不把关键缺失项改成“已完成”。 + +## 11. 精确验收标准与证据 + +### 11.1 视觉测量 + +| 项目 | 通过标准 | +|---|---| +| 正常视口卡片 | getBoundingClientRect宽195±1、高280±1 CSS px | +| 桌面/手机尺寸 | 两端同值,不因screen width放大 | +| 边距 | 默认16/12、24+safearea,误差≤1px | +| 圆角 | 12±1px | +| 图片缝 | 3±1px | +| 收起 | 可视24、有效44,不挡其他区域点击 | +| 表面 | 无标题/底栏/页码/暂停/前后箭头/查看按钮 | +| 摄影 | 正常态真实摄影素材,无渐变色块假图 | +| 气泡 | 12/16/20、右侧小范围、无计数/头像/聊天框 | +| 外部网站 | 无样式污染、无组件外透明点击遮罩 | + +截图只验证静态;不能因图上有上箭头就证明自动滚动。所有尺寸注释在比较报告中,不出现在产品UI。 + +### 11.2 动态测量 + +- 16px/s默认速度,在未跨循环边界的可见图锚点连续2秒向上移动约32px(±2px,测试虚拟时钟可更精确)。 +- 30/60/120Hz模拟下按相同elapsed time位移一致。 +- 循环边界、队列更新、URL更新不出现超过2px的无故锚点跳动;显式删图/换绑属于允许改变,另测正确性。 +- 暂停后至少2秒位置不变;恢复从原位继续,不瞬间补跑隐藏时间。 +- 运行5分钟后图片DOM≤设定上限,事件监听/连接不持续增加。 +- 200次点赞事件压力下粒子≤8,限速符合规格,动画不提交点赞请求。 +- 新照片/下线与点击同时发生不打开错误photoId。 + +### 11.3 场景矩阵 + +| 编号 | 场景 | +|---|---| +| EMB-A01 | PC1440×900/1920×1080,手机320×568/390×844/430×932固定尺寸 | +| EMB-A02 | 狭窄/横屏/安全区,位置和多实例不越界 | +| EMB-A03 | 横图、竖图、全景、单图、0图、2图短循环 | +| EMB-A04 | decode慢/破图/签名到期/304/接口失败,恢复正常 | +| EMB-A05 | 自动循环与新增队列锚定,DOM有上限 | +| EMB-A06 | 隐藏/删除/相册关闭/slot换绑/停用,旧数据与气泡清理 | +| EMB-A07 | 点击/拖动/悬停/键盘焦点/减少动态效果 | +| EMB-A08 | 收起与展开、刷新记忆、默认手机收起、后台设置更新 | +| EMB-A09 | 两浏览器上下文真实点赞、重复burst、错相册、不可见照片 | +| EMB-A10 | WS断线恢复,不假造气泡,照片仍能滚动 | +| EMB-A11 | 真正不同origin的宿主与iframe,消息伪造被拒 | +| EMB-A12 | 宿主全局button/img样式、客服浮层、重复script、SPA移除 | +| EMB-A13 | 后台未保存预览隔离、配置保存、v2接入代码正确 | +| EMB-A14 | v1旧接入保留,普通观众页样式/互动不回归 | +| EMB-A15 | 嵌入显示/滚动/气泡不增加相册浏览次数,不提交点赞 | +| EMB-A16 | 截图、录屏、测量、测试结果完整,不宣称未测项已通过 | + +### 11.4 建议自动化 + +- 纯函数:高度计算、循环边界、锚定、配置优先级、事件归属和限量。 +- 组件:零/单/多图、失败、reducedMotion、focus、销毁后不继续更新。 +- Playwright:两个HTTP端口构成真实跨源,getBoundingClientRect量尺寸;截正常/空/收起/手机。 +- 动态使用受控时间/rAF或测试接口复现,不靠大量真实sleep造成不稳定。 +- 真实服务双上下文:一个观众页点赞,一个embed接收,核对photoId和burst去重;不能只mock事件却声称实时链路完成。 +- 生命周期统计:活跃socket/rAF/timer计数、DOM数量、测试结束资源释放。 + +执行前核对各package脚本。已知入口: + +```text +pnpm --filter @photo/embed-loader lint +pnpm --filter @photo/embed-loader test +pnpm --filter @photo/embed-loader build +pnpm --filter @photo/embed-loader sync +pnpm --filter @photo/viewer lint +pnpm --filter @photo/viewer typecheck +pnpm --filter @photo/viewer test +pnpm --filter @photo/viewer build +pnpm --filter @photo/viewer test:e2e +``` + +新增契约/API/admin则额外运行实际对应的生成、类型、权限和E2E脚本。运行前确认测试库,禁止用生产环境初始化数据。没有运行就明确未运行,不能引用旧验收计数。 + +## 12. 交付清单和完成定义 + +建议目录: + +```text +docs/designs/ui04-implementation/ + reference/ 原图/裁片索引,不伪装实际截图 + actual/desktop/ + actual/mobile/ + comparisons/ + recordings/ 含循环边界/点赞/暂停恢复的录屏 + measurements/ CSS尺寸、位移、DOM/连接统计 + README.md 复现入口、样本数据和截图说明 +docs/plans/progress/UI04-验收记录.md +``` + +验收记录包含: +1. 基线commit与现有工作树改动保护。 +2. E00–E07完成表,修改文件/接口/版本兼容策略。 +3. EMB-A01–A16逐项通过/失败/待验及证据链接。 +4. 195×280实测结果、运动位移、资源上限。 +5. v1/v2接入样例、未保存预览与真实服务验证说明。 +6. 未完成项、外部资源、真实CDN部署不在本轮的说明。 + +**完成定义:静态外观、连续运动、真实互动和安全兼容四者都具备证据。** 只有静态截图、只有单测通过、只有示例气泡或仍保留旧底栏,均不能标记完成。 + +## 13. 可直接复制给 Claude 的执行指令 + +> 请执行 docs/plans/2026-09-22-UI04-嵌入组件上滚照片窗高保真实施方案.md,先打开 docs/designs/embed-widget-scroll-hearts-2026-09-22.png。目标是PC/手机固定195×280 CSS px、单列照片连续向上滚动、真实点赞心形气泡、无标题/底部工具栏,仅右上收起,点击照片进入对应观众深链。不是旧轮播改颜色。按E00–E07先做固定尺寸静态样板并量尺寸,再实现有限队列滚动、暂停/点击、真实事件、管理预览和v2接入,保留旧v1兼容。不得假造点赞、不得用50vw放大PC、不得用随机动画代替实时数据。保护已有改动,不影响App/普通viewer,不自动发布。最终交付真实实现、跨源截图、动态录屏、尺寸/位移测量、测试结果及UI04验收记录;不完整项如实标待验,不只返回方案。 + diff --git a/docs/plans/progress/UI04-验收记录.md b/docs/plans/progress/UI04-验收记录.md new file mode 100644 index 0000000..1260df9 --- /dev/null +++ b/docs/plans/progress/UI04-验收记录.md @@ -0,0 +1,86 @@ +# 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 定案登记) + +(E01 完成后填写:v2 入口形态、路由/参数、新字段清单、v1 保留验证。) + +## 3 任务进度 + +- [x] E00 基线(本记录第 1 节) +- [ ] E01 契约和版本骨架 +- [ ] E02 静态高保真样板 +- [ ] E03 连续滚动 +- [ ] E04 操作和生命周期 +- [ ] E05 实时气泡 +- [ ] E06 管理预览与接入 +- [ ] E07 验收(EMB-A01…A16 逐项见第 5 节) + +## 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; + 网络不可用时降级为记录待验,不标记通过。