Files
photo-live/docs/plans/2026-09-21-UI01-App与悬浮组件体验优化实施方案.md
T
2026-09-21 10:17:16 +08:00

34 KiB
Raw Blame History

UI-01:App 与 JS 悬浮组件体验优化实施方案

版本:1.0
日期:2026-09-21
状态:待执行;本文件中的复选框均表示待完成工作,不代表已经实施。
目标执行者:Claude 或其他接手本仓库的开发者。

关联:实施总纲、需求说明书、技术实施方案、P3 验收记录、P4b 验收记录。

1. 执行目标与使用方法

在现有功能基础上完成 App 与嵌入组件的产品化体验升级:工作人员能凭图片识别相册与照片,快速拍摄上传、定位异常;网站观众能在不被遮挡的情况下浏览轮播、打开相册。保留现有权限、上传恢复、多语言、海外读取和版本同步机制。

执行顺序:先阅读本文件与当前仓库说明,执行 U00 基线核对,再依次完成 U01–U09。每个任务交付可运行增量,记录改动、验证和剩余问题。不要只修改颜色后宣布完成,也不要把本方案写成另一份计划代替实现。

本文件给出了无需再次询问的设计默认值。常规组件划分、命名和排版由执行者决定。只有缺少真实资源、现有权限语义发生实质冲突或必须突破本文件范围时,列出具体依赖;继续完成不依赖该条件的工作。不得虚构接口、数据、图片或测试结果。

本文是范围明确的执行计划,不要求安装指定插件或使用特定子代理。实际执行仍遵循用户当次授权和适用的仓库规则。

1.1 当前基线

  • 总纲登记 P1–P4b 本地阶段完成,P5 准备件完成;这不表示真实 OSS/CDN、用户源及双平台真机验收已完成。
  • Flutter 已有登录、相册、拍摄、上传队列、上传历史、语言设置及原生上传桥接。
  • App 主题仅定义 Material 种子色;相册卡片以字段和开关为主;管理照片列表使用占位图标、照片编号和文件大小。
  • 嵌入组件已有 loader、iframe 轮播、收起、语言、轮询退避和版本判断。
  • 管理后台已有展示位设置表单,但没有本方案要求的完整视觉预览。
  • 本方案基于代码与文档静态核对。运行时截图、真机表现和性能数据必须在实施时补证据。

1.2 范围

必须完成 本阶段不包含
App 统一主题、相册列表/详情、图片管理、上传中心、拍摄/表单/分享/设置页整理 重写上传引擎、原生传输和国内海外架构
受权限保护的管理照片预览、相册封面摘要等必要契约补齐 AI 修图、自动翻译、视频、公众账号体系
悬浮组件布局、交互、状态、可访问性、宿主适配 全站观众页和管理后台全面重新设计
展示位视觉配置与本地预览 真实部署、域名变更、云资源操作
中英文、截图检查、针对性回归 全局品牌重命名、替换应用包名与桥接通道

保留当前英文品牌显示,若仓库已有正式品牌资产则复用。没有确定资产时使用现有英文名称和通用图片图标,不自行把 Framevia 等候选名称批量写入产品。界面仍支持中英文;“英文品牌”不等于强制全部界面使用英文。

2. 实施保护规则

  1. 开始前检查 Git 状态并记录已有改动。编制时已有 AndroidManifest.xml 修改以及 demo-seed.mjs、g1-oss-smoke.mjs 未跟踪文件;实施时重新核对,不覆盖、清理或提交他人改动。
  2. 保留账号隔离、权限校验、上传幂等标识、数据库持久队列、凭证续签、原生事件确认和恢复逻辑。
  3. 不把“上传完成”改成“已公开”。传输、核验、处理、公开是不同事实。
  4. 不通过观众公开 API 获取管理端隐藏照片,不把永久 OSS 地址放进页面。
  5. 不新增重型 UI 框架;Flutter 复用 Material 与 Riverpod,Web 复用 Vue;loader 保持零运行时依赖。
  6. 兼容已有 API 消费者、已有展示位与脚本。新增字段采用兼容扩展,更新生成类型,不直接编辑生成文件。
  7. 所有用户文案进入现有语言资源。日志、代码变量、数据库状态不能直接作为用户提示。
  8. 测试使用隔离环境;运行前检查脚本是否清库、seed 或覆盖配置。禁止对真实业务数据库执行测试初始化。
  9. 此阶段不自动发布、推送、修改云配置或创建正式版本标签。提交行为按用户授权执行。
  10. 旧的后端正确性问题单独登记:补漏分页未推进、发布覆盖删除状态、同步签名防重放等。本阶段不把它们默认视为已解决,也不顺手扩大成后端全面重构。

3. 视觉规范(默认执行值)

3.1 基础样式

元素 浅色默认值 使用要求
品牌/主要操作 #1A73E8 主要 CTA、选中态;每个操作区一个主要动作
页面背景 #F6F8FB 列表与工作区背景
内容表面 #FFFFFF 卡片、表单、底部操作区
主文字 #172033 标题、关键数字
次文字 #5E6878 时间、地点、说明
分隔线 #E5EAF1 轻分隔,不用粗边框
成功 #16794B 已上传等完成事实
等待 #996300 等待网络、等待调度
错误 #B42318 需要用户处理的失败
  • 间距:4/8/12/16/24/32;页面左右默认 16。
  • 卡片圆角 16,输入框与按钮 12,小标签 6–8;避免所有元素都做成胶囊。
  • 页面标题 22–24,分组标题 17–18,正文 14–16,辅助文字 12–13。字号必须随系统缩放。
  • App 主要按钮高 48–52;图标按钮有效触控区至少 44×44;图标本身可为 20–24。
  • 状态同时用文案和图标表达,不能仅靠颜色。
  • 深色主题使用对应语义色,不直接反转图片;图片不加彩色滤镜。沿用已有跟随系统逻辑。
  • App 轻量状态动效约 150–220ms;轮播约 250–350ms;减少动态效果开启时禁用非必要动效。
  • 正文对比度目标 4.5:1,重要控件和焦点清晰可见;实施时实际验证。

3.2 组件组织

修改 apps/mobile/lib/app/theme.dart,建立统一 ColorScheme、TextTheme、按钮、输入框、AppBar、NavigationBar、Dialog、BottomSheet 主题。可在 apps/mobile/lib/ui/ 新增 tokens 与公共组件,例如 StateBadge、EmptyState、ErrorState、PhotoThumbnail、SectionHeader。

只抽取真正跨页面复用的组件,避免为每个 SizedBox 建一层封装。Web 在 viewer 样式目录建立 embed 专用变量,loader 外层通过受控参数同步;禁止污染宿主全局 CSS。

4. App 页面规格

4.1 导航与相册首页

保留三个页签,显示为“相册 / 上传 / 设置”,英文为 Albums / Uploads / Settings。沿用 IndexedStack,保持页面状态。

相册卡片顺序:封面 → 活动标题 → 时间/地点 → 公开与上传状态。标题最多两行,正文完整标题在详情可见。移除主卡片的 publicToken 以及下载/原图四开关堆叠,完整配置仍可在详情设置访问。

Albums                                  +
┌───────────────────────────────────────┐
│              活动封面                 │
├───────────────────────────────────────┤
│ Canton Fair · Autumn                  │
│ Sep 21–25 · Guangzhou                 │
│ Public                    Uploads on  │
└───────────────────────────────────────┘
Albums            Uploads · 3     Settings
  • 手机单列卡片;平板按可用宽度使用两列,每张卡片不得挤压英文标题。
  • 无封面显示固定比例中性占位,网络失败显示替代图与可重试状态。
  • 不为每张卡片单独请求相册详情。摘要响应批量提供封面信息。
  • 标题按当前界面语言 → 相册默认语言 → 首个有效翻译回退。
  • 活动时间使用相册时区,不用设备时区悄悄改变日期;详情明确时区。
  • 上传页签角标表示当前账号尚未结束的任务数,明确统计范围;不跨账号显示。
  • 不添加没有后端支持的全量搜索或“我的/协作”筛选。本轮保留现有分页,若增加筛选必须另列兼容 API 任务,禁止只筛已加载页却声称全量。

4.2 相册详情

布局:紧凑封面与活动信息 → 上传/公开状态 → 照片入口或照片预览 → 次级管理入口;底部固定“拍摄上传 / 从相册选择”,避让系统安全区。

  • 拍摄是主要按钮,选择照片为次按钮;目标相册与分类清晰可见。
  • 编辑、成员、分类、分享进入工具菜单或次级区域,不再全部用同等强调的按钮。
  • 公开关闭不等于上传关闭,分别显示;上传关闭时说明原因并禁用上传操作。
  • 创建者和管理员可管理相册;协作者仅显示自己被授权的内容与动作。
  • App 列表统计如果使用海外回传值,附最近更新时间,不声称实时在线人数。
  • 无照片时显示“拍摄第一张照片”入口;正在处理不显示为空且无解释。

4.3 照片管理与大图

将 album_photos_page.dart 文本列表替换为默认三列网格;极窄屏两列,平板按最小格宽扩列。

  • 网格使用缩略图,允许 cover 裁切;大图使用 contain 完整展示。网格角标仅提示处理中、失败、隐藏、删除等必要状态。
  • 点开大图,支持已加载照片间左右切换,临近边缘按现有游标加载更多;关闭后回到原网格位置。
  • 大图详情显示上传者、活动时区时间、尺寸/大小,ID 放诊断区域。
  • 隐藏、恢复、删除操作沿用权限;删除确认明确影响云端照片,与本机任务记录清理区分。
  • 本轮单张操作必做。批量照片管理不新增到 App,以免牵连现有批量权限与部分成功语义;后续单独排期。
  • 隐藏照片允许有权限的管理者预览。已删除照片默认不签发预览,显示删除占位;后续若需要回收站预览,独立定义权限。
  • 未准备好缩略图时显示处理状态。签名 URL 过期允许一次受控刷新,不无限重试。
  • 协作者“自己的照片”通过受权限控制的数据接口实现;不能先获取他人数据再前端过滤。现有列表若只允许创建者/管理员,按第 6 节增加明确 own 范围支持。

4.4 上传中心

保留当前相册/时间/状态筛选、缩略图、重试、跨设备历史。顶部增加当前筛选范围的任务摘要,并标注范围。

Uploads                         History
Today · This device
82 completed   3 uploading   13 waiting   2 need attention
All / In progress / Needs attention / Completed
[图] IMG_001.jpg     Uploading 68%
                    ━━━━━━━━━━━
[图] IMG_002.jpg     Waiting for network
[图] IMG_003.jpg     File unavailable       Select again
内部状态 界面含义 行为
preparing 正在准备照片 保留已有取消能力
queued 等待上传 保留取消
uploading 正在上传,传输进度 不伪造暂停能力
uploadedConfirming 正在确认上传 不确定进度,不显示已公开
completed 上传完成 可移除本机记录;不表示海外已可见
waitingNetwork 等待网络 橙色说明,自动恢复,保留已有重试
preparationFailed 无法准备文件 重新选择,不能普通重试冒充恢复
retryableFailed 上传失败 本地化原因与重试
cancelled 已取消 保留清理记录
  • 摘要按任务数统计,单任务百分比按字节进度;不把两者混成不明口径的总百分比。
  • “一键重试”仅作用于已有可重试任务,文案说明范围。
  • 已完成任务清理按钮改为“移除记录”,明确不会删除 OSS 照片。
  • 不把网络等待和上传成功使用相同状态颜色。
  • 摘要使用现有聚合能力或本地数据库聚合,不把全部任务加载到内存计数。
  • 进度保持行级订阅,不让整个列表随每个字节回调重建。
  • 本机队列与服务端历史采用不同标题和说明;不要将两者相加成去重后的全局数量。

4.5 拍摄、表单、分享、设置

  • 拍摄:深色取景,顶部相册/分类,底部清晰快门与入队计数。入队成功用短暂反馈,不每张弹确认。保留现有权限拒绝和相机失败恢复。
  • 创建/编辑:分组为活动信息、多语言内容、访问设置;默认语言必填,另一语言页签按需填写。沿用现有校验,不把未填写文案自动翻译。保存按钮在键盘打开时可达。
  • 分享:名称、二维码、链接操作清晰分层;无现成封面也能使用。复制链接必做;系统分享仅在现有依赖可用或新增依赖经过实际兼容验证时实施,否则明确登记,不放无效按钮。
  • 设置:账号信息、语言、密码、上传帮助、版本分组;退出登录保留任务数据与账号隔离语义。不要在退出弹窗承诺后台会继续上传。
  • 后台帮助说明区分系统限制、用户强制退出和网络等待;根据真实权限状态提示,不固定显示“已开启后台上传”。

5. 悬浮组件规格

5.1 两种形态

展开卡片:标题栏 → 4:3 图片舞台 → 活动名称与页码/入口。桌面默认宽 320px,小档 280px。旧配置 sm/md 保留兼容语义;本轮 md 统一为 320px,列入视觉变更说明。

┌────────────────────────────┐
│ Event photos            −  │
├────────────────────────────┤
│                            │
│          活动图片          │
│                            │
├────────────────────────────┤
│ Canton Fair · Autumn       │
│ 03 / 12   Pause  View album│
└────────────────────────────┘

收起入口:图片图标 + Photos/照片;有效高度至少 44px。窄屏默认收起,用户展开后不因轮询再次收起。记住会话内偏好,配置默认值只在没有用户选择时生效。

照片点击打开当前单图深链;View album 打开相册首页。继续保持用户手势触发新页、noopener/noreferrer 和相同语言参数。不要自动跳转宿主。

5.2 图片与动效

  • 默认 object-fit: contain,中性深色舞台,完整显示合影和海报;cover 作为配置可选项。
  • 舞台比例固定,高度不随图片横竖改变。标题允许两行,入口文本不能被裁掉。
  • 轮播默认 5000ms,合法范围保持 3000–30000ms;淡入默认 300ms。
  • 用“当前序号 / 当前轮播队列数量”替代无限圆点;不得把队列数量标为相册照片总数。
  • 仅当前图和下一张预加载;旧图最多保留一个过渡层,避免同时请求整队列图片。
  • 新图 decode 成功再切换;失败保留上一张并尝试后续图片,循环失败有上限和退避。
  • 用户暂停、指针悬停、键盘焦点在组件内时停止自动切换;离开后仅在用户未手动暂停时恢复。
  • 减少动态效果时取消过渡,默认暂停自动切换并提供手动上一张/下一张。
  • 页面隐藏、组件收起/不可见停止轮询和切换;恢复立即校准一次,避免重复启动计时器。

5.3 状态与可访问性

状态 展示要求
初次加载 等比例静态骨架,收起入口可用
成功 图片、活动名、序号、暂停和相册入口
空相册 照片即将上线/Photos coming soon,精简占位
临时断网,有缓存 保留可用图片、安静退避,不显示技术错误
临时断网,无缓存 紧凑暂不可用状态,可收起,不永久骨架
签名失效 刷新元数据后有限重试,避免破图闪烁
停用/解绑/相册不可公开 移除卡片和收起入口,不留无效按钮
  • 将“用户收起”与“服务端终止展示”区分为不同消息语义;新增 destroy 消息时双向严格检查 origin/source/type。
  • 隐藏轮播帧不能进入 Tab 顺序或读屏内容;优先只渲染当前可交互帧,过渡层设置不可交互及辅助技术隐藏。
  • 所有操作使用 button/a 语义,提供中英文标签,保留可见焦点,不用轮播消息持续打断读屏。
  • 图片没有真实描述时用本地化的“活动照片,第 N 张”等上下文标签,不编造画面描述。
  • 修复 loader 内联 SVG 的 fill="%23ffffff" 为有效颜色;关闭按钮视觉可小,有效点击区至少 44×44。

5.4 宿主适配与配置

配置优先级:系统默认 < 展示位配置 < script 显式 data-* 覆盖;用户会话收起/暂停选择高于默认值。禁止解析器把“参数缺省”立即变为显式覆盖,导致后台设置永远不生效。

配置 默认值 生效范围
position right left/right,兼容现有
size md sm=280、md=320
intervalMs 5000 图片切换,兼容现有 data-interval
lang auto 保留现有相册默认语言回退
collapsedDefault false 手机小于 480px 默认 true;用户选择优先
imageFit(新增) contain contain/cover
offsetX(新增) 16 0–120px
offsetBottom(新增) 24 0–240px,叠加设备安全区
zIndex(新增) 1000 1–2147483000;用于宿主协调
  • CSS 宽度取配置宽与视口剩余宽度的较小值,保证 320px 宿主无溢出;窗口变化和横竖屏切换时重新布局。
  • zIndex 无法自动解决所有第三方弹窗冲突,文档提供宿主配置方法;禁止承诺自动识别所有客服或 Cookie 横幅。
  • 多 slot 同侧时纵向排列并保留间隔;可用高度不足时收起后续实例,不让多张卡片重叠。维持独立用户偏好。
  • loader 不向宿主注入全局字体和标签选择器,使用独立容器内联样式;可聚焦控件显式设置必要基础样式,测试宿主 button 全局 CSS 干扰。
  • 外层位置/尺寸等后台配置经 iframe 校验后通过白名单 config 消息交给 loader;只允许上述字段和范围,不传任意 CSS/HTML。loader 再验证一次。
  • 明确 configVersion 变化后的动态应用规则,旧请求不能覆盖新配置。脚本显式覆盖的字段不会被后端刷新冲掉。

5.5 轮询与版本兼容

  • 轮播与取数彻底解耦:生产轮询基准 30000ms,沿用现有退避;轮播 3000ms 不能导致每 3 秒取数。
  • 保留 ETag、configVersion、旧响应丢弃以及相册换绑清队列语义。
  • 304 路径不能导致签名图片永久失效:核对签名有效期与 ETag 策略,过期刷新必须能取得新 URL;必要时提供明确的强制刷新路径及请求上限。
  • 新增配置 JSON 字段使用默认回退,不要求全量改写旧记录。更新契约、验证、国内管理与海外投影消费者。
  • 展示位未获授权的用户不能通过预览或配置接口读取内部数据。保持当前 admin-only 管理范围,不在本轮悄悄扩展展示位授权体系。
  • 老 loader、老 iframe 与新服务过渡期仍可工作;新增消息被旧端忽略时基础展示不应崩溃。
  • loader 构建并 sync 到 viewer,不手改 dist。检查现有 Nginx 缓存策略:旧 v1 URL 若长期缓存,不直接假定部署后全部刷新。采用带内容哈希的发布文件及生成代码引用,保留旧 v1 兼容入口;正式 CDN 刷新由 P5 执行,不在本轮操作云资源。

6. 必要接口与数据调整

先检查 packages/contracts/openapi.yaml,优先复用已有能力。以下是目标语义;只有不存在等价字段时才新增。新接口最终路径与 operationId 在 U01 完成后登记到验收记录。

6.1 相册封面摘要

  • 在 AlbumSummary 兼容增加可选的 cover 字段(推荐 {url, expiresAt, width, height} 或 null,与已有 SignedUrl 结构复用)。
  • 数据源优先已配置的有效封面;缺失时返回 null,本轮不对每张卡片扫描最新照片自动生成封面。
  • 时间地点使用现有翻译字段,未填不占一整行空白。
  • 列表按页批量查询资产,不引入每相册一次数据库/HTTP 查询。
  • Flutter 模型允许旧响应无 cover;旧客户端忽略新字段不受影响。

6.2 管理照片预览

  • 管理列表条目兼容增加 nullable preview,包含 thumb 与 browse 的短期签名 URL、过期时间;复用现有照片宽高。
  • 权限:管理员全部、创建者本相册、协作者仅自己上传。若现有列表限定管理者,新增 scope=own 的显式查询语义;旧请求权限保持不变。
  • scope=own 过滤在服务端完成,相册成员资格每次检查;无权查看的照片不签发 URL。
  • 增加或复用有鉴权的单图预览刷新端点,大图分页仍使用管理列表,不改走观众公开接口。
  • 没有有效变体、已删除照片返回 null 与真实状态。隐藏照片只给有权限的管理者签名地址。
  • 日志不记录完整签名 URL。签名有效期遵循现有策略;取消权限后停止新签发,旧地址有效期是明确的有限撤销窗口。
  • 不新增 OSS 公共读权限,不把原图下载能力混入浏览预览;水印等策略沿用现有授权和变体约定。

6.3 不在本轮虚构的数据

  • 没有照片数/浏览数摘要接口时,不在卡片上放假数字,也不以已加载条数冒充总数。
  • 没有海外逐照片确认状态时,不显示“海外已同步”。
  • 没有可靠活动运行状态时,用 Event photos,不自动显示 LIVE。
  • 没有新的业务批次标识时,上传摘要标注“今天/当前筛选”,不称为“本次活动全部上传”。

7. 文件改动地图

区域 主要文件/目录 目标
契约 packages/contracts/openapi.yaml 及生成脚本/类型 预览、封面、组件配置兼容扩展
国内相册 services/api/src/albums/albums.service.ts、assets.service.ts、dto.ts 封面摘要、批量资产组装
国内照片 services/api/src/photos/photos.service.ts、album-photos.controller.ts、photos.controller.ts、dto.ts own 范围和受控预览
组件服务 services/api/src/embed/、services/api/src/embed-ov/ 新配置校验及公开响应
同步 services/api/src/sync/、sync-inbox/ 中相关展示位投影 新配置完整传递、旧事件兼容
App 主题 apps/mobile/lib/app/theme.dart、app.dart、新增 ui/ 主题与公共组件
App 相册 lib/pages/albums_tab.dart、album_detail_page.dart、album_photos_page.dart 图片主导布局、大图、权限操作
App 上传 lib/pages/home_page.dart、queue_tab.dart、server_history_page.dart、capture_page.dart 导航、汇总、反馈
App 辅助页 lib/pages/album_form_page.dart、share_qr_dialog.dart、login_page.dart、password_change_page.dart 表单及样式统一
App 数据 lib/core/api_client.dart、features/albums/models.dart、features/photos/models.dart 新字段与刷新调用
App 语言 apps/mobile/lib/l10n/app_zh.arb、app_en.arb 双语文案,按工具链生成
loader packages/embed-loader/src/params.js、loader.js、README-embed.md 配置、响应式、生命周期
iframe apps/viewer/src/pages/EmbedPage.vue、embed/useEmbedFeed.ts、feed.ts、postMessage.ts 轮播、焦点、取数与展示解耦
后台预览 apps/admin/src/views/system/embed-slots/SlotFormDialog.vue、EmbedCodeDialog.vue,相关 types/api/utils 配置、预览、代码生成

表中 App 的 lib 相对路径均以 apps/mobile 为根。文件如果在实施前已移动,追踪实际调用链,不复制一套旧实现。

8. 可执行任务清单

U00:基线与现状截图

  • 读取总纲、P3/P4b 验收、当前 scripts/package.json;记录 Git 状态。
  • 运行现有本地环境,采集相册首页、详情、照片页、上传、拍摄、表单、分享、设置、组件展开/收起、后台配置截图。
  • 建立验收记录 docs/plans/progress/UI01-验收记录.md,写入实际基线 commit、环境与外部关口。
  • 如果模拟器/服务不可用,说明原因并继续契约与静态实现,不伪造截图。

出口:当前行为、已有改动、可用环境明确。

U01:契约与数据配合

  • 列出复用字段与必须新增字段,落实第 6 节及配置优先级。
  • 修改 OpenAPI、校验、实现、生成类型、Flutter 数据模型。
  • 完成权限测试:管理员/创建者/协作者/移除成员/跨相册访问/隐藏/删除。
  • 检查封面和预览批量组装、URL 刷新及旧字段缺省兼容。
  • 对组件新配置完成国内→海外投影验证。

出口:有真实数据支撑后续界面,旧消费端可用;不得先用假图片掩盖缺失接口。

U02:设计基础与导航

  • 实现主题、公共状态/空态/缩略图组件、中英文基础文案。
  • 调整底部导航与任务角标,保留页面/账号状态。
  • 相册列表完成一页可运行样板,同时检查浅色/深色、中英文。

出口:视觉规范已在真实页面体现;后续页面复用同一套组件。

U03:相册与照片工作流

  • 完成封面卡片、详情主次操作、底部上传入口。
  • 完成照片网格、大图切换、签名刷新与返回原位置。
  • 完成有权限的隐藏/恢复/删除,协作者 own 列表。
  • 校验分页、图片缺失、长标题、处理失败、上传关闭。

出口:工作人员可凭图找照片,上传入口清楚,权限不退化。

U04:上传与拍摄

  • 完成当前筛选摘要、状态分组、明确错误操作、移除记录文案。
  • 优化拍摄界面和入队反馈;保留原生通道与任务状态机。
  • 验证准备失败、断网、重试、确认中、退出切账号、历史记录。
  • 检查列表滚动与上传并行时,不发生整页高频重建。

出口:异常可理解且可处理,没有“上传完成=公开”的误导。

U05:辅助页面统一

  • 整理登录、密码、创建/编辑、分享、成员/分类、设置及服务端历史页样式。
  • 表单键盘、双语切换、默认语言回退、保存失败均有可用反馈。
  • 深色、大字体和窄屏无溢出;系统分享按第 4.5 节处理。

出口:App 所有主要路径风格统一,不只优化首页。

U06:嵌入轮播与 loader

  • 完成两形态、完整图片模式、页码、暂停/手动切换、加载和失败状态。
  • 完成配置合并、动态 config 消息、收起偏好和 destroy 生命周期。
  • 解耦轮播与轮询;处理焦点、减少动态效果、预加载和过期 URL。
  • 实现窄屏/安全区/窗口变化/多实例布局;修复图标颜色。
  • 保留并测试消息白名单、iframe sandbox、外链安全。
  • build + sync loader,落实带哈希产物与旧入口兼容,更新接入说明。

出口:第三方页面可接入,不遮挡关键内容、不泄漏焦点到隐藏帧。

U07:后台配置与预览

  • 编辑表单提供左右设置、尺寸、轮播间隔、语言、收起默认、图片适配、偏移和层级。
  • 表单旁或下方提供桌面/手机预览,未保存修改即时更新本地预览。
  • 预览使用本地示例数据或授权管理数据,不写展示位、不上报浏览次数、不跳转真实观众页。
  • 预览与生产组件共享展示结构,避免复制两套不同样式;数据获取与展示拆分。
  • 明确“保存”才更新线上配置;接入代码只包含用户选择的显式覆盖,默认让后台配置生效。

出口:后台预览与实际效果一致,配置修改确实传到现有宿主页。

U08:回归与视觉验收

  • 完成第 9 节矩阵,修复实现造成的回归。
  • 对照基线采集优化后截图;记录设备/视口/语言/主题。
  • Android 可用环境执行真实链路冒烟;iOS 没有 macOS/设备时明确待验收,不能以 Dart 测试代替。
  • 记录结果、未执行项、原因、影响与下一步;不引用旧阶段测试数量作为本阶段结果。

U09:文档与交接

  • 更新总纲增加 UI-01 状态,不将 P5 标记完成。
  • 修正直接涉及的旧状态描述;D06/D07/D11 等分别标注“已有工作默认”与“待正式确认”,不擅自替用户确认。
  • 完成验收记录、截图索引、API 变更、脚本兼容和已知问题列表。
  • 总结文件、运行方式、测试、剩余真机关口。无需依赖对话上下文即可接手。

任务依赖:U00 → U01 → U02 → U03/U04/U05;U06 依赖 U01 配置契约;U07 依赖 U06;U08 汇总全部;U09 收尾。这里表达工作依赖,不要求并行代理。

9. 验收矩阵与命令

9.1 验收编号

编号 必须验证的结果
UI-A01 App 浅色/深色一致,无硬编码浅色导致不可读
UI-A02 相册有/无封面、长标题、中英文回退、时间地点正确
UI-A03 图片网格与大图真实可用,分页及返回位置正确
UI-A04 隐藏照片权限受控,删除照片不继续签预览,协作者无法看他人照片
UI-A05 上传状态、筛选汇总、重试、清理记录不改变队列语义
UI-A06 连拍与上传同时进行,成功提示不打断拍摄
UI-A07 320/390/430 逻辑宽度与平板、文字 1.0/1.3/2.0 倍主要操作可达
UI-A08 组件 320/390/768/1440px 宿主无横向溢出,安全区与偏移生效
UI-A09 横图/竖图/全景/文字海报可看完整,换图不导致卡片跳高
UI-A10 收起/展开/暂停、后台、键盘焦点、减少动态效果行为正确
UI-A11 相册换绑、配置修改、旧响应、304、URL 过期、404/410 正确
UI-A12 双来源真实跨源测试通过,非法 origin/source/config 消息被拒绝
UI-A13 后台未保存预览不改变线上数据,不增加浏览统计
UI-A14 老脚本与旧记录缺字段不崩溃,显式覆盖与后台配置优先级正确
UI-A15 各端中英文键与占位符一致,运行时长文案无裁切
UI-A16 未运行的真机/云资源项明确列为待验证,不宣称生产验收完成

9.2 有意义的自动化

  • API 集成:管理预览权限矩阵、own 过滤、签名刷新、旧响应兼容、无 N+1 查询。
  • Flutter widget:主要布局和关键状态;有稳定渲染环境后给核心页面增加少量 golden,不为每个间距写脆弱测试。
  • Flutter 现有集成:登录→相册→拍摄/选择→队列→历史;修改视觉后维护语义定位,不靠坐标点击。
  • loader 单测:缺省/显式参数区分、上下界、合并优先级、配置消息校验。
  • viewer 单测:暂停和恢复、请求计时器独立、失败图片、签名刷新、非当前帧不可聚焦。
  • Playwright:真实不同 origin 的宿主与 iframe(两个端口即可),至少一次模拟全局 button CSS、客服浮层和多 slot;不能继续只用同源测试替代跨源验证。
  • 性能记录:保存改造前后首屏请求数、组件预加载数、loader gzip 大小;上传中列表滚动使用 profile 观察。不得捏造“提升百分比”。

9.3 执行入口

在仓库根运行现有 Web 检查;先定向再全量,环境缺失与真实失败分开记录:

pnpm lint
pnpm typecheck
pnpm test
pnpm --filter @photo/embed-loader build
pnpm --filter @photo/embed-loader sync
pnpm --filter @photo/viewer build
pnpm --filter @photo/viewer test:e2e

Flutter 在 apps/mobile,使用仓库固定的 Flutter 工具链:

flutter gen-l10n
flutter analyze
flutter test

OpenAPI 生成、后端集成、admin E2E、mobile IT 的命令从对应 package.json 与现有 scripts 核对后运行;不猜不存在的脚本。全量测试可能初始化数据库,必须先确认指向专用测试环境。记录实际命令、退出码、结果和跳过原因。

10. 验收记录模板

在 docs/plans/progress/UI01-验收记录.md 填写:

  1. 基线与完成 commit(未提交则记录工作树状态),日期与执行环境。
  2. U00–U09 完成表,未完成项原因。
  3. UI-A01–UI-A16:通过/失败/待验证、证据位置。
  4. API 新字段与权限变化、旧客户端兼容结果。
  5. App 各页、组件两形态、后台预览的前后截图索引。
  6. 测试命令与真实结果,性能观察而非推测。
  7. 既有改动保护情况、未触碰的外部环境。
  8. 方案偏差及理由;仍需真机、OSS/CDN、用户接口的事项。

完成定义:规定页面和组件实现可运行、必要接口已落地、针对性回归通过、视觉证据可核查、剩余外部关口清晰。不以“代码生成完”“本地构建通过”单独替代完成定义。

11. 可直接交给 Claude 的执行指令

请执行 docs/plans/2026-09-21-UI01-App与悬浮组件体验优化实施方案.md,从 U00 开始核对当前仓库,按 U01–U09 实际完成 App 与 JS 悬浮组件的界面和体验调整。沿用文档默认设计,不重复询问常规样式选择。保护当前未提交改动,不重写上传引擎,不绕过管理预览权限,不虚构数据或测试结论。接口缺口按文档兼容扩展;每步执行相应验证。遇到真机或外部环境依赖,明确登记并继续不受影响的工作。最终提供可运行实现、UI01 验收记录、截图证据和剩余事项,不只返回计划。未经另外授权不要发布、推送、修改云资源或创建正式版本标签。