跳到主要内容

功能详细设计文档: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 逻辑完整
分享功能设计完整
接口设计合理
低端机降级方案