消费抽奖系统架构流程图.md 7.8 KB

消费抽奖系统架构流程图

概述

本文档展示了消费抽奖系统优化后的三种抽奖方式处理流程。系统支持即抽即中、定时开奖、按人数开奖三种模式,通过统一的入口进行处理。

主要抽奖流程图

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());
        }
    }
}

优化特点

  1. 统一入口: 所有抽奖方式都通过统一的流程处理
  2. 状态管理: 明确的抽奖状态流转
  3. 并发安全: 使用事务和锁机制保证数据一致性
  4. 可扩展性: 便于增加新的开奖方式
  5. 容错性: 完善的异常处理机制
  6. 性能优化: 批量处理减少数据库压力

注意事项

  1. 定时任务: 需要配置定时任务处理定时开奖
  2. 人数开奖: 达到人数后可以异步处理避免阻塞
  3. 库存控制: 抽奖前必须检查奖品库存
  4. 事务处理: 关键操作使用数据库事务
  5. 状态一致性: 确保抽奖记录状态的正确更新