# 寻访网页方案
## 目标
网页继续使用一个 Toy 包和一个 `index.html`,首页展示版本日历,并提供战斗数据解析和寻访统计两个入口。寻访云存档只使用 Toy CloudStorage,不接入 CloudBase。
## 页面与路由
采用当前项目已经使用的 Hash 路由,不新增多个 Toy 入口页面:
```text
#/ 首页(版本日历)
#/combat 战斗数据解析与排行榜
#/gacha 寻访统计
#/archive 云存档管理
#/download 软件下载
#/record/ 公开战斗记录详情
```
Toy 包的根目录仍然只放一个 `index.html`。Toy 文档允许 `share`/`getQrCode` 指向当前 Toy 内的其他相对路径,但真实路径路由刷新时必须有对应 HTML 文件,因此本项目继续采用 Hash 路由更稳定。`toy.navigate` 是跳转 B 站资源,不用于 Toy 内部页面切换。
## 首页
默认首页使用版本日历图片作为第一视图,下方放两个较大的入口:
- 战斗数据解析:进入现有战斗解析/排行榜流程。
- 寻访统计:进入寻访统计页。
图片和脚本全部使用相对资源路径,兼容 `/toy//` 部署路径。
## URL 直达
桌面端可以打开以下形式的 URL:
```text
index.html?mode=gacha#<压缩后的寻访快照>
index.html?mode=combat&r=<公开战斗记录 ID>
```
寻访快照放在 fragment 中,避免随 HTTP 请求发送;网页解码并展示后应使用 `history.replaceState` 清理快照,避免长期出现在地址栏、历史记录和复制链接中。query 只保留短的模式标识,不放完整记录。
带寻访快照时直接进入寻访页,带战斗记录 ID 时进入战斗详情;参数无效时显示可恢复的导入错误,不阻塞首页。
## 寻访快照与增量
网页不接收游戏 Token,也不上传普通四星/五星明细。桌面端只发送网页显示和增量合并所需的紧凑状态:
```text
schemaVersion
卡池元数据(poolId、类型、categoryId、显示名称、时间、规则组)
卡池聚合(总抽数、六星数、UP 数、歪数、当前垫数)
六星结果(角色/武器、是否 UP、抽数、免费十连标志)
各池 seqId 游标
```
六星结果必须带稳定去重 ID,推荐由 `poolId + seqId + itemId + gachaTs` 组成。网页端按 ID 合并后重新计算统计,重复导入不会重复计数。
## Toy 云存档
Toy 云存储按“登录用户 + 当前 Toy”隔离,每个 Toy 最多 128 个 key,每个 value 最多 1024 字节。寻访使用固定命名空间并覆盖更新,不使用战斗存档的随机记录 ID:
```text
gacha_v1_manifest
gacha_v1_state_0
gacha_v1_state_1
...
```
先写分片、校验,再写 manifest;manifest 中包含版本、分片数、更新时间和摘要。读取时先读 manifest,再读取分片并校验。云存档是私有的,只能由同一 Toy 内的同一用户跨设备恢复,不能作为公开分享后端。
现有战斗存档和寻访存档共享 Toy 的 128 个 key 配额,因此寻访只保存聚合状态和六星结果,不能保存完整普通抽卡列表。
## 分阶段实现
1. 本地侧稳定模型、接口、增量游标和 JSON 导入导出。
2. 网页侧 `gacha` 路由、快照解码和统计展示。
3. Toy 固定 key 的寻访云存档合并、校验和恢复。
4. 桌面端一键生成快照并打开网页。