- 新增 src/views/PrizeDraw 抽奖视图及抽奖配置 store - 更新 defaultPersonList 为 82 位真实参与者名单 - 调整主页、路由、i18n 及音乐播放以支持抽奖入口 - 附抽奖需求及实现报告文档 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
141 lines
4.4 KiB
Markdown
141 lines
4.4 KiB
Markdown
# Claude Code 提示词:实现抽奖系统
|
||
|
||
## 项目概述
|
||
这是一个年会抽奖系统,当前已有"抽人"功能(从88人中抽取中奖者)。现在需要新增一个"抽奖"页面,为88个人每人抽取一个奖品。
|
||
|
||
## 核心需求
|
||
为88个人(LN-001 到 LN-088)抽取奖品,每人抽一次,共88次。奖品配置如下:
|
||
1. 快乐通勤奖(25个)- 可提前1小时下班或晚到1小时
|
||
2. 跑马场自由日(18个)- 可选在家或其他场所办公
|
||
3. 前途光明奖(2个)- 获得boss 1对1畅聊1小时
|
||
4. 现金红包500元(3个)
|
||
5. 现金红包300元(8个)
|
||
6. 现金红包200元(15个)
|
||
7. 现金红包100元(17个)
|
||
|
||
## 技术栈
|
||
- Vue 3 + TypeScript + Vite
|
||
- Pinia (状态管理)
|
||
- 复用现有组件和样式
|
||
|
||
## 实现步骤
|
||
|
||
### Step 1: 创建 Pinia Store
|
||
创建 `src/store/prizeDrawConfig.ts`,包含:
|
||
- 奖品配置(7种奖品,共88个)
|
||
- 人员列表(从 `defaultPersonList` 获取88个人)
|
||
- 抽奖结果数组
|
||
- 抽奖逻辑:
|
||
- `executeDraw()`: 随机从剩余人员中选一个,随机从剩余奖品中选一个,记录结果
|
||
- `reset()`: 重置所有数据
|
||
- `canDraw`: 计算属性,判断是否还能继续抽奖
|
||
- 使用 IndexedDB 持久化数据
|
||
|
||
### Step 2: 创建页面组件
|
||
创建 `src/views/PrizeDraw/index.vue`,布局包含:
|
||
1. **顶部区域**:标题 + 进度(已抽 X/88)
|
||
2. **左侧/顶部**:奖品池展示(7个奖品卡片,显示剩余数量)
|
||
3. **中央区域**:
|
||
- 大按钮:"开始抽奖" / "继续抽奖" / "抽奖完成"
|
||
- 抽奖动画区域(可复用现有卡片动画)
|
||
- 结果展示:人员编号 + 奖品名称
|
||
4. **右侧/底部**:已抽奖记录列表(可滚动)
|
||
|
||
### Step 3: 实现抽奖逻辑
|
||
```typescript
|
||
// 核心算法
|
||
function executeDraw() {
|
||
// 1. 从剩余人员中随机选一个
|
||
const randomPersonIndex = Math.floor(Math.random() * remainingPersons.length)
|
||
const person = remainingPersons.splice(randomPersonIndex, 1)[0]
|
||
|
||
// 2. 从剩余奖品中随机选一个
|
||
const randomPrizeIndex = Math.floor(Math.random() * remainingPrizes.length)
|
||
const prize = remainingPrizes.splice(randomPrizeIndex, 1)[0]
|
||
|
||
// 3. 记录结果
|
||
drawResults.push({
|
||
drawIndex: drawResults.length + 1,
|
||
personId: person.uid,
|
||
personName: person.name,
|
||
prizeId: prize.id,
|
||
prizeName: prize.name,
|
||
drawTime: new Date().toISOString()
|
||
})
|
||
|
||
// 4. 更新奖品剩余数量
|
||
updatePrizeRemaining(prize.id)
|
||
}
|
||
```
|
||
|
||
### Step 4: 添加动画效果
|
||
- 点击按钮后,显示1-2秒的滚动/加载动画
|
||
- 可以复用 `src/views/Home` 中的卡片动画效果
|
||
- 结果展示时添加庆祝动画(可选)
|
||
|
||
### Step 5: 添加路由
|
||
在 `src/router/index.ts` 中添加:
|
||
```typescript
|
||
{
|
||
path: '/prize-draw',
|
||
name: 'PrizeDraw',
|
||
component: () => import('@/views/PrizeDraw/index.vue'),
|
||
meta: { title: '抽奖系统' }
|
||
}
|
||
```
|
||
|
||
### Step 6: 添加导航入口
|
||
在主页或顶部菜单添加"抽奖"按钮,跳转到 `/prize-draw`
|
||
|
||
### Step 7: 实现额外功能
|
||
1. **导出功能**:将抽奖结果导出为 CSV/Excel
|
||
2. **重置功能**:清空所有数据,重新开始
|
||
3. **撤销功能**:撤销最后一次抽奖(可选)
|
||
|
||
## 数据结构参考
|
||
|
||
```typescript
|
||
// 奖品配置
|
||
interface Prize {
|
||
id: string
|
||
name: string
|
||
description: string
|
||
total: number // 总数量
|
||
remaining: number // 剩余数量
|
||
color: string // 显示颜色
|
||
}
|
||
|
||
// 抽奖结果
|
||
interface DrawResult {
|
||
drawIndex: number // 第几次抽奖
|
||
personId: string // LN-001
|
||
personName: string // LN-001
|
||
prizeId: string
|
||
prizeName: string
|
||
drawTime: string
|
||
}
|
||
```
|
||
|
||
## UI 要求
|
||
- 复用现有主题配置(绿色系:#4cb050, #05a045, #a5d6a7)
|
||
- 响应式布局,支持移动端
|
||
- 动画流畅自然
|
||
- 进度清晰可见
|
||
|
||
## 注意事项
|
||
1. 确保随机算法公平(使用 `Math.random()`)
|
||
2. 处理边界情况(最后一个人、最后一个奖品)
|
||
3. 数据持久化到 IndexedDB(刷新页面不丢失)
|
||
4. 代码结构清晰,遵循现有项目规范
|
||
|
||
## 验收标准
|
||
- [ ] 可以完整执行88次抽奖
|
||
- [ ] 每个人只抽一次,每个奖品数量准确
|
||
- [ ] 动画效果流畅
|
||
- [ ] 数据可以持久化
|
||
- [ ] 可以导出结果
|
||
- [ ] 移动端可用
|
||
|
||
## 开始实现
|
||
请按照上述步骤实现抽奖系统。如果有任何疑问,请先查看现有代码结构(特别是 `src/store/personConfig.ts` 和 `src/views/Home/index.vue`)作为参考。
|