Co-Authored-By: Claude Code <noreply@anthropic.com>
34 KiB
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. 实施保护规则
- 开始前检查 Git 状态并记录已有改动。编制时已有 AndroidManifest.xml 修改以及 demo-seed.mjs、g1-oss-smoke.mjs 未跟踪文件;实施时重新核对,不覆盖、清理或提交他人改动。
- 保留账号隔离、权限校验、上传幂等标识、数据库持久队列、凭证续签、原生事件确认和恢复逻辑。
- 不把“上传完成”改成“已公开”。传输、核验、处理、公开是不同事实。
- 不通过观众公开 API 获取管理端隐藏照片,不把永久 OSS 地址放进页面。
- 不新增重型 UI 框架;Flutter 复用 Material 与 Riverpod,Web 复用 Vue;loader 保持零运行时依赖。
- 兼容已有 API 消费者、已有展示位与脚本。新增字段采用兼容扩展,更新生成类型,不直接编辑生成文件。
- 所有用户文案进入现有语言资源。日志、代码变量、数据库状态不能直接作为用户提示。
- 测试使用隔离环境;运行前检查脚本是否清库、seed 或覆盖配置。禁止对真实业务数据库执行测试初始化。
- 此阶段不自动发布、推送、修改云配置或创建正式版本标签。提交行为按用户授权执行。
- 旧的后端正确性问题单独登记:补漏分页未推进、发布覆盖删除状态、同步签名防重放等。本阶段不把它们默认视为已解决,也不顺手扩大成后端全面重构。
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 填写:
- 基线与完成 commit(未提交则记录工作树状态),日期与执行环境。
- U00–U09 完成表,未完成项原因。
- UI-A01–UI-A16:通过/失败/待验证、证据位置。
- API 新字段与权限变化、旧客户端兼容结果。
- App 各页、组件两形态、后台预览的前后截图索引。
- 测试命令与真实结果,性能观察而非推测。
- 既有改动保护情况、未触碰的外部环境。
- 方案偏差及理由;仍需真机、OSS/CDN、用户接口的事项。
完成定义:规定页面和组件实现可运行、必要接口已落地、针对性回归通过、视觉证据可核查、剩余外部关口清晰。不以“代码生成完”“本地构建通过”单独替代完成定义。
11. 可直接交给 Claude 的执行指令
请执行
docs/plans/2026-09-21-UI01-App与悬浮组件体验优化实施方案.md,从 U00 开始核对当前仓库,按 U01–U09 实际完成 App 与 JS 悬浮组件的界面和体验调整。沿用文档默认设计,不重复询问常规样式选择。保护当前未提交改动,不重写上传引擎,不绕过管理预览权限,不虚构数据或测试结论。接口缺口按文档兼容扩展;每步执行相应验证。遇到真机或外部环境依赖,明确登记并继续不受影响的工作。最终提供可运行实现、UI01 验收记录、截图证据和剩余事项,不只返回计划。未经另外授权不要发布、推送、修改云资源或创建正式版本标签。