功能详细设计文档:F2 随机盲盒
功能优先级:P0(核心) 文档版本:v1.0 关联 PRD:PRD-v1.0.md
一、页面结构
1.1 页面名称
盲盒首页 / 盲盒结果页(MysteryBoxPage)
1.2 页面位置
首页主入口 → 盲盒首页(选择模式)
↓
开盒动画 → 盲盒结果页
1.3 页面布局
┌──────────────────────────────────────┐
│ │
│ 🍱 今日吃什么? │
│ 交给命运来决定! │
│ │
│ ┌─────────────────────────┐ │
│ │ │ │
│ │ 🎁 点击开启今日盲盒 │ │ ← 主 CTA 按钮
│ │ │ │
│ └─────────────────────────┘ │
│ │
│ ─────── 选择盲盒模式 ─────── │
│ │
│ [🌍 全局随机] [🍜 分类选择] │
│ [👴 老人版] [💪 健身版] │
│ [⚖️ 减肥版] [🏥 病患版] │
│ │
│ 已选:[全局随机] │
│ │
└──────────────────────────────────────┘
┌──────────────────────────────────────┐
│ 🎉 开盒动画(过渡页) │
│ 1.5s │
│ │
│ ┌───────────────┐ │
│ │ ??? │ │ ← 问号翻转为菜品名
│ │ ↓ ↓ ↓ │ │
│ │ 番茄炒蛋 │ │
│ └───────────────┘ │
│ │
└──────────────────────────────────────┘
┌──────────────────────────────────────┐
│ ← 返回 今日菜品 🎲 │ ← 再开一个
├──────────────────────────────────────┤
│ │
│ ┌─────────────────────┐ │
│ │ │ │
│ │ 菜品封面大图 │ │
│ │ │ │
│ └─────────────────────┘ │
│ │
│ 🍅 番茄炒蛋 │
│ 一道简单家常菜,酸甜可口老少皆宜 │
│ │
│ 🔥 180kcal 🟢轻卡 │
│ [高蛋白] [家常] [5分钟] │
│ │
│ ┌────────────┐ ┌────────────┐ │
│ │ 查看详情 │ │ 再开一个 │ │
│ └────────────┘ └────────────┘ │
│ │
│ [🍳 再来一道?换个菜] │
│ │
└──────────────────────────────────────┘
二、盲盒模式设计
2.1 模式分类
| 模式 | 入口文案 | 说明 | 筛选逻辑 |
|---|---|---|---|
| 全局随机 | 🌍 全局随机 | 从全量菜品库随机抽取 | 无任何限制 |
| 分类随机 | 🍜 分类选择 | 用户指定 1 个或多个菜系 | 中式/日式/韩式/西式/意式/东南亚/印度 |
| 人群随机 | 👴/💪/⚖️/🏥 | 指定人群后随机 | 仅返回该人群适合的菜品 |
2.2 分类标签(分类随机用)
中式 · 日式 · 韩式 · 西式 · 意式
法式 · 东南亚 · 印度 · 墨西哥 · 美式
素食主义 · 斋菜 · 生酮饮食(可选)
2.3 模式切换
- 用户切换模式时,已选模式高亮
- 默认选中「全局随机」
- 分类随机 + 人群随机可叠加(如:中式 + 健身人群)
三、开盒动画设计
3.1 动画流程(时长 1.5s)
0ms → 点击按钮,按钮缩小进入加载态
0-300ms → 屏幕中央出现盲盒图形(盒子关闭状态)
300-600ms → 盒子轻微晃动(模拟悬念)
600-1000ms → 盒子打开,光效从盒内爆发
1000-1500ms → 问号变为菜品名,菜品图片渐入
1500ms → 动画结束,结果页完全展开
3.2 动画元素
| 元素 | 说明 |
|---|---|
| 盲盒图标 | 拟物化餐盒样式,带品牌色 |
| 光效 | 从盒内爆发的暖黄色光芒 |
| 菜品名 | 大号字体从问号翻牌效果 |
| 粒子效果 | 可选,增加仪式感(控制包体) |
3.3 音效设计(可选)
| 音效 | 触发时机 | 设置项 |
|---|---|---|
| 背景音 | 点击按钮后播放 | 用户可关闭 |
| 开盒音 | 盒子打开瞬间 | 用户可关闭 |
| 结果揭晓音 | 菜品名出现时 | 用户可关闭 |
注:小程序包体紧张,音效走 CDN 按需加载,非必须实现
3.4 动画实现建议
- 使用 Lottie 动画或 CSS3 关键帧动画
- 控制素材包体 < 100KB
- 低端机降级:直接跳过动画,0.5s 后展示结果
四、防重复机制
4.1 规则
| 条件 | 规则 |
|---|---|
| 连续 3 次 | 不出现相同菜品 |
| 当天已展示过 | 权重降低(但仍可能随机到) |
| 30 天内高频菜品 | 降低出现概率 |
4.2 实现方式
// 伪代码
function selectRandomDish(excludeIds: string[]): Dish {
// 1. 从库中排除最近 3 次已展示的菜品
const candidates = allDishes.filter(d => !excludeIds.includes(d.id));
// 2. 降低高频菜品权重(根据历史点击数据)
const weightedCandidates = candidates.map(d => ({
dish: d,
weight: highFrequencyDishIds.includes(d.id) ? 0.3 : 1.0
}));
// 3. 加权随机抽取
return weightedRandomSelect(weightedCandidates);
}
五、结果页交互
5.1 结果展示卡片
| 字段 | 说明 |
|---|---|
| 菜品封面图 | 占据页面 40% 高度 |
| 菜品名称 | 28pt,居中 |
| 一句话简介 | 16pt,灰色文字 |
| 热量标签 | 带颜色标识(🟢/🟡/🔴) |
| 推荐标签 | [高蛋白] [5分钟] [家常] 等 |
| 操作按钮 | 「查看详情」/ 「再开一个」 |
5.2 操作按钮逻辑
| 按钮 | 行为 |
|---|---|
| 查看详情 | 跳转菜品详情页(F4) |
| 再开一个 | 重新执行盲盒逻辑,保留当前模式 |
| 换个菜 | 不换模式,直接换一道推荐(跳过动画) |
5.3 分享功能
- 分享卡片自动生成
- 分享文案:「今天命运告诉我吃 [菜名],你也来试试?」
- 附带小程序码,他人可直接跳转查看该菜品
六、技术实现
6.1 推荐接口
// 请求
interface MysteryBoxRequest {
mode: 'global' | 'category' | 'crowd';
category?: string[]; // 分类随机时传入
crowdType?: string; // 人群随机时传入
excludeIds?: string[]; // 排除最近已展示的菜品
}
// 响应
interface MysteryBoxResponse {
dish: Dish; // 抽取到的菜品
animationUrl?: string; // 动画素材 CDN 地址
shareImageUrl: string; // 分享图 CDN 地址
}
6.2 盲盒记录
interface MysteryBoxRecord {
userId: string;
openedAt: Date;
mode: string;
dishId: string;
viewed: boolean; // 是否点击查看了详情
adopted: boolean; // 是否采纳(加入今日计划)
}
用于:防重复推荐、用户行为分析
七、复核检查项
| 检查点 | 状态 |
|---|---|
| 模式覆盖完整(全局+分类+人群) | ✅ |
| 动画时序设计清晰 | ✅ |
| 防重复机制可实现 | ✅ |
| 结果页 CTA 逻辑完整 | ✅ |
| 分享功能设计完整 | ✅ |
| 接口设计合理 | ✅ |
| 低端机降级方案 | ✅ |