消费抽奖系统架构流程图
概述
本文档展示了消费抽奖系统优化后的三种抽奖方式处理流程。系统支持即抽即中、定时开奖、按人数开奖三种模式,通过统一的入口进行处理。
主要抽奖流程图
graph TD
A[用户触发抽奖] --> B[验证用户资格]
B --> C[消耗抽奖机会]
C --> D[创建抽奖记录<br/>状态: 已参与]
D --> E{开奖方式}
E -->|即抽即中| F[立即执行抽奖]
F --> G[获取可用奖品]
G --> H[执行抽奖算法]
H --> I[减少奖品库存]
I --> J[更新抽奖记录<br/>状态: 已中奖/未中奖]
J --> K{是否中奖}
K -->|是| L[创建中奖记录]
K -->|否| M[返回未中奖结果]
L --> N[自动发放奖品]
N --> O[更新活动统计]
O --> P[返回中奖结果]
E -->|定时开奖| Q[等待开奖时间]
Q --> R[返回等待状态]
R --> S[定时任务处理]
S --> T[批量处理参与记录]
T --> U[为每个记录执行抽奖]
U --> V[更新记录状态]
E -->|按人数开奖| W[检查参与人数]
W --> X{达到开奖人数?}
X -->|是| Y[触发开奖处理]
X -->|否| Z[返回等待状态]
Y --> AA[批量处理参与记录]
style D fill:#e1f5fe
style J fill:#fff3e0
style L fill:#e8f5e8
style S fill:#f3e5f5
style AA fill:#fff8e1
抽奖状态流转图
stateDiagram-v2
[*] --> 已参与: 用户参与抽奖
已参与 --> 已中奖: 抽奖结果为中奖
已参与 --> 未中奖: 抽奖结果为未中奖
已中奖 --> [*]: 流程结束
未中奖 --> [*]: 流程结束
note right of 已参与
状态码: 1
等待开奖或立即开奖
end note
note right of 已中奖
状态码: 2
创建中奖记录
end note
note right of 未中奖
状态码: 3
记录未中奖
end note
三种抽奖方式详细流程
1. 即抽即中 (LOTTERY_TYPE_INSTANT = 1)
sequenceDiagram
participant User as 用户
participant API as API接口
participant Service as LotteryService
participant DB as 数据库
User->>API: 发起抽奖请求
API->>Service: drawLottery()
Service->>Service: 验证用户资格
Service->>Service: 消耗抽奖机会
Service->>DB: 创建抽奖记录(状态:已参与)
Service->>Service: executeInstantDraw()
Service->>Service: 获取可用奖品
Service->>Service: 执行抽奖算法
Service->>Service: 减少奖品库存
Service->>DB: 更新抽奖记录(状态:已中奖/未中奖)
alt 中奖
Service->>DB: 创建中奖记录
Service->>Service: 自动发放奖品
end
Service->>Service: 更新活动统计
Service->>API: 返回抽奖结果
API->>User: 显示抽奖结果
2. 定时开奖 (LOTTERY_TYPE_TIME = 2)
sequenceDiagram
participant User as 用户
participant API as API接口
participant Service as LotteryService
participant Cron as 定时任务
participant DB as 数据库
User->>API: 发起抽奖请求
API->>Service: drawLottery()
Service->>Service: 验证用户资格
Service->>Service: 消耗抽奖机会
Service->>DB: 创建抽奖记录(状态:已参与)
Service->>Service: handleTimeLottery()
Service->>API: 返回等待状态
API->>User: 显示等待开奖
Note over Cron: 到达开奖时间
Cron->>Service: processScheduledLotteries()
Service->>DB: 查询待开奖记录
loop 处理每个参与记录
Service->>Service: executeDrawForRecord()
Service->>Service: 执行抽奖算法
Service->>DB: 更新记录状态
alt 中奖
Service->>DB: 创建中奖记录
end
end
Service->>DB: 更新活动状态为已结束
3. 按人数开奖 (LOTTERY_TYPE_PEOPLE = 3)
sequenceDiagram
participant User as 用户
participant API as API接口
participant Service as LotteryService
participant DB as 数据库
User->>API: 发起抽奖请求
API->>Service: drawLottery()
Service->>Service: 验证用户资格
Service->>Service: 消耗抽奖机会
Service->>DB: 创建抽奖记录(状态:已参与)
Service->>Service: handlePeopleLottery()
Service->>DB: 查询当前参与人数
alt 人数未达标
Service->>API: 返回等待状态
API->>User: 显示还需X人参与
else 人数达标
Service->>Service: 触发批量开奖
loop 处理所有参与记录
Service->>Service: executeDrawForRecord()
Service->>DB: 更新记录状态
end
Service->>API: 返回开奖中状态
API->>User: 显示正在开奖
end
数据库表结构优化
抽奖记录表 (shop_lottery_draw_record) 新增字段
字段名 |
类型 |
默认值 |
说明 |
status |
tinyint(1) |
1 |
抽奖状态: 1=已参与 2=已中奖 3=未中奖 |
prize_id |
int(11) |
0 |
奖品ID,0表示未开奖 |
抽奖状态枚举
// 抽奖状态常量
const DRAW_STATUS_PARTICIPATED = 1; // 已参与(等待开奖)
const DRAW_STATUS_WIN = 2; // 已中奖
const DRAW_STATUS_NO_WIN = 3; // 未中奖
核心方法说明
统一处理方法
方法名 |
说明 |
公开性 |
handleLotteryByType() |
根据开奖方式分流处理 |
private |
createParticipationRecord() |
创建参与记录统一入口 |
private |
即抽即中方法
方法名 |
说明 |
公开性 |
executeInstantDraw() |
执行即抽即中抽奖 |
private |
定时开奖方法
方法名 |
说明 |
公开性 |
handleTimeLottery() |
处理定时抽奖参与 |
private |
processScheduledLotteries() |
定时任务处理入口 |
public |
executeScheduledDraw() |
执行定时开奖 |
private |
executeDrawForRecord() |
为单个记录执行开奖 |
private |
按人数开奖方法
方法名 |
说明 |
公开性 |
handlePeopleLottery() |
处理按人数抽奖 |
private |
定时任务配置
Linux Cron 配置示例
# 每分钟检查一次定时开奖活动
* * * * * /usr/bin/php /path/to/project/think lottery:process-scheduled
ThinkPHP 命令行示例
<?php
// application/console/command/ProcessScheduledLottery.php
namespace app\console\command;
use think\console\Command;
use think\console\Input;
use think\console\Output;
use app\common\Service\Lottery\LotteryService;
class ProcessScheduledLottery extends Command
{
protected function configure()
{
$this->setName('lottery:process-scheduled')
->setDescription('处理定时开奖活动');
}
protected function execute(Input $input, Output $output)
{
try {
$count = LotteryService::processScheduledLotteries();
$output->writeln("处理完成,共处理 {$count} 条记录");
} catch (\Exception $e) {
$output->writeln("处理失败: " . $e->getMessage());
}
}
}
优化特点
- 统一入口: 所有抽奖方式都通过统一的流程处理
- 状态管理: 明确的抽奖状态流转
- 并发安全: 使用事务和锁机制保证数据一致性
- 可扩展性: 便于增加新的开奖方式
- 容错性: 完善的异常处理机制
- 性能优化: 批量处理减少数据库压力
注意事项
- 定时任务: 需要配置定时任务处理定时开奖
- 人数开奖: 达到人数后可以异步处理避免阻塞
- 库存控制: 抽奖前必须检查奖品库存
- 事务处理: 关键操作使用数据库事务
- 状态一致性: 确保抽奖记录状态的正确更新