feat: 🎁 新增破冰抽奖功能及 82 人名单

- 新增 src/views/PrizeDraw 抽奖视图及抽奖配置 store
- 更新 defaultPersonList 为 82 位真实参与者名单
- 调整主页、路由、i18n 及音乐播放以支持抽奖入口
- 附抽奖需求及实现报告文档

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
kkfluous
2026-04-24 16:29:52 +08:00
parent d26c364999
commit 25d0c95dc3
26 changed files with 21649 additions and 281 deletions

140
CLAUDE_CODE_PROMPT.md Normal file
View File

@@ -0,0 +1,140 @@
# 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`)作为参考。