LotteryService文档说明.md 12 KB

LotteryService 抽奖服务类文档

概述

LotteryService 是抽奖系统的核心服务类,负责处理抽奖的核心业务逻辑,包括抽奖执行、奖品管理、活动状态管理等功能。

类结构

namespace app\common\Service\lottery;

class LotteryService
{
    // 核心抽奖方法
    public static function drawLottery($activityId, $userId, $triggerType, $triggerOrderId, $triggerAmount)
    
    // 奖品管理方法
    public static function hasPrizeStock(LotteryPrize $prize, $quantity)
    public static function decreasePrizeStock(LotteryPrize $prize, $quantity)
    public static function getAvailableExchangeCode(LotteryPrize $prize)
    public static function markExchangeCodeUsed(LotteryPrize $prize, $code)
    public static function getValidPrizes($activityId)
    public static function isPrizeUnlocked(LotteryPrize $prize, $currentPeopleCount)
    
    // 活动状态管理方法
    public static function isActivityRunning(LotteryActivity $activity)
    public static function isActivityEnded(LotteryActivity $activity)
    public static function isActivityNotStarted(LotteryActivity $activity)
    public static function isActivitySuspended(LotteryActivity $activity)
    public static function isActivityCancelled(LotteryActivity $activity)
    public static function isInDrawTime(LotteryActivity $activity)
    public static function getRunningActivities()
    public static function getNotStartedActivities()
    public static function getEndedActivities()
    public static function getDisplayableActivities()
    public static function isValidActivityStatus(LotteryActivity $activity)
    public static function isValidLotteryType(LotteryActivity $activity)
    
    // 用户机会管理方法
    public static function getUserChances($activityId, $userId)
}

核心方法详解

1. drawLottery() - 执行抽奖

功能: 执行抽奖的核心方法,包含完整的抽奖流程验证和处理。

参数:

  • $activityId (int): 活动ID
  • $userId (int): 用户ID
  • $triggerType (int): 触发类型,默认1
  • $triggerOrderId (int|null): 触发订单ID
  • $triggerAmount (float|null): 触发金额

返回值: array 抽奖结果

异常: Exception 各种验证失败异常

使用示例:

try {
    $result = LotteryService::drawLottery(1, 123, 1, 456, 100.00);
    echo "抽奖成功: " . json_encode($result);
} catch (Exception $e) {
    echo "抽奖失败: " . $e->getMessage();
}

抽奖流程:

  1. 验证活动有效性
  2. 验证抽奖时间
  3. 验证用户资格
  4. 检查用户抽奖机会
  5. 检查用户参与次数限制
  6. 防重复抽奖检查
  7. 使用Redis锁防止并发
  8. 执行抽奖核心逻辑
  9. 返回抽奖结果

2. processDrawLottery() - 处理抽奖核心逻辑

功能: 私有方法,处理抽奖的核心业务逻辑。

流程:

  1. 开启数据库事务
  2. 获取可用奖品列表
  3. 执行抽奖算法
  4. 减少奖品库存
  5. 消耗用户抽奖机会
  6. 创建抽奖记录
  7. 创建中奖记录(如果中奖)
  8. 自动发放奖品(如果配置为自动发放)
  9. 更新活动统计
  10. 提交事务
  11. 返回抽奖结果

3. executeLotteryAlgorithm() - 执行抽奖算法

功能: 基于概率权重的抽奖算法实现。

算法原理:

  • 计算所有奖品的总概率
  • 生成随机数
  • 按概率权重选择奖品
  • 保底返回第一个奖品(通常是未中奖)

使用示例:

$prizes = LotteryService::getValidPrizes($activityId);
$selectedPrize = LotteryService::executeLotteryAlgorithm($prizes);

奖品管理方法

1. hasPrizeStock() - 检查奖品库存

功能: 检查奖品库存是否充足。

参数:

  • $prize (LotteryPrize): 奖品对象
  • $quantity (int): 需要数量,默认1

返回值: bool 库存是否充足

2. decreasePrizeStock() - 减少奖品库存

功能: 减少奖品库存并增加中奖次数。

参数:

  • $prize (LotteryPrize): 奖品对象
  • $quantity (int): 减少数量,默认1

返回值: bool 操作是否成功

3. getAvailableExchangeCode() - 获取可用兑换码

功能: 获取奖品中可用的兑换码。

参数:

  • $prize (LotteryPrize): 奖品对象

返回值: string|null 可用兑换码或null

4. markExchangeCodeUsed() - 标记兑换码已使用

功能: 将兑换码标记为已使用状态。

参数:

  • $prize (LotteryPrize): 奖品对象
  • $code (string): 兑换码

返回值: bool 操作是否成功

5. getValidPrizes() - 获取有效奖品

功能: 获取活动的有效奖品列表(库存大于0且状态正常)。

参数:

  • $activityId (int): 活动ID

返回值: Collection 奖品集合

6. isPrizeUnlocked() - 检查奖品是否已解锁

功能: 检查奖品是否已按人数解锁。

参数:

  • $prize (LotteryPrize): 奖品对象
  • $currentPeopleCount (int): 当前参与人数

返回值: bool 是否已解锁

活动状态管理方法

1. isActivityRunning() - 检查活动是否正在进行

功能: 检查活动是否处于进行中状态。

参数:

  • $activity (LotteryActivity): 活动对象

返回值: bool 是否正在进行

2. isActivityEnded() - 检查活动是否已结束

功能: 检查活动是否已结束。

参数:

  • $activity (LotteryActivity): 活动对象

返回值: bool 是否已结束

3. isActivityNotStarted() - 检查活动是否未开始

功能: 检查活动是否还未开始。

参数:

  • $activity (LotteryActivity): 活动对象

返回值: bool 是否未开始

4. isActivitySuspended() - 检查活动是否已暂停

功能: 检查活动是否已暂停。

参数:

  • $activity (LotteryActivity): 活动对象

返回值: bool 是否已暂停

5. isActivityCancelled() - 检查活动是否已取消

功能: 检查活动是否已取消。

参数:

  • $activity (LotteryActivity): 活动对象

返回值: bool 是否已取消

6. isInDrawTime() - 检查是否在抽奖时间内

功能: 检查当前时间是否在活动的抽奖时间范围内。

参数:

  • $activity (LotteryActivity): 活动对象

返回值: bool 是否在抽奖时间内

7. getRunningActivities() - 获取正在进行的活动

功能: 获取所有正在进行的抽奖活动。

返回值: Collection 活动集合

8. getNotStartedActivities() - 获取未开始的活动

功能: 获取所有未开始的抽奖活动。

返回值: Collection 活动集合

9. getEndedActivities() - 获取已结束的活动

功能: 获取所有已结束的抽奖活动。

返回值: Collection 活动集合

10. getDisplayableActivities() - 获取可显示的活动

功能: 获取可显示的活动(排除逻辑状态)。

返回值: Collection 活动集合

11. isValidActivityStatus() - 验证活动状态

功能: 验证活动状态是否有效。

参数:

  • $activity (LotteryActivity): 活动对象

返回值: bool 状态是否有效

12. isValidLotteryType() - 验证开奖方式

功能: 验证开奖方式是否有效。

参数:

  • $activity (LotteryActivity): 活动对象

返回值: bool 开奖方式是否有效

用户机会管理方法

getUserChances() - 获取用户抽奖机会

功能: 获取用户在指定活动中的抽奖机会信息。

参数:

  • $activityId (int): 活动ID
  • $userId (int): 用户ID

返回值: array 机会信息

返回格式:

[
    'total_chances' => 10,      // 总机会数
    'used_chances' => 3,        // 已使用机会数
    'remain_chances' => 7,      // 剩余机会数
    'last_get_time' => 1234567890,  // 最后获得时间
    'last_use_time' => 1234567890   // 最后使用时间
]

私有辅助方法

1. validateUserQualification() - 验证用户资格

功能: 验证用户是否符合活动参与资格。

验证内容:

  • 用户群体限制(全部会员/会员等级/会员标签)

2. checkUserLevel() - 检查用户等级

功能: 检查用户等级是否符合限制条件。

3. checkUserTag() - 检查用户标签

功能: 检查用户标签是否符合限制条件。

4. checkUserDrawLimit() - 检查用户抽奖次数限制

功能: 检查用户是否已达到参与次数上限。

5. hasDrawnForOrder() - 检查订单是否已抽奖

功能: 检查用户是否已为指定订单进行过抽奖。

6. buildWinInfo() - 构建中奖信息

功能: 构建中奖记录的详细信息。

7. buildPrizeValue() - 构建奖品价值信息

功能: 根据奖品类型构建奖品价值信息。

8. autoDeliverPrize() - 自动发放奖品

功能: 根据奖品类型自动发放奖品。

9. deliverCoupon() - 发放优惠券

功能: 发放优惠券类型的奖品。

10. deliverRedPacket() - 发放红包

功能: 发放红包类型的奖品。

11. deliverExchangeCode() - 发放兑换码

功能: 发放兑换码类型的奖品。

12. deliverGoods() - 发放商城商品

功能: 发放商城商品类型的奖品。

13. updateActivityStats() - 更新活动统计

功能: 更新活动的抽奖和中奖统计。

14. buildDrawResult() - 构建抽奖结果

功能: 构建返回给客户端的抽奖结果。

使用示例

1. 基本抽奖流程

// 用户抽奖
try {
    $result = LotteryService::drawLottery(1, 123);
    if ($result['is_win']) {
        echo "恭喜中奖!奖品:" . $result['prize']['name'];
    } else {
        echo "很遗憾,未中奖";
    }
} catch (Exception $e) {
    echo "抽奖失败:" . $e->getMessage();
}

2. 检查活动状态

$activity = LotteryActivity::find(1);
if (LotteryService::isActivityRunning($activity)) {
    echo "活动正在进行中";
} elseif (LotteryService::isActivityEnded($activity)) {
    echo "活动已结束";
} elseif (LotteryService::isActivityNotStarted($activity)) {
    echo "活动未开始";
}

3. 获取用户机会

$chances = LotteryService::getUserChances(1, 123);
echo "剩余抽奖机会:" . $chances['remain_chances'];

4. 检查奖品库存

$prize = LotteryPrize::find(1);
if (LotteryService::hasPrizeStock($prize, 1)) {
    echo "奖品库存充足";
} else {
    echo "奖品库存不足";
}

注意事项

1. 并发控制

  • 使用Redis锁防止并发抽奖
  • 锁超时时间设置为10秒
  • 确保锁的释放

2. 事务处理

  • 抽奖过程使用数据库事务
  • 确保数据一致性
  • 异常时自动回滚

3. 库存管理

  • 抽奖前检查库存
  • 抽奖成功后立即减少库存
  • 防止超发奖品

4. 时间验证

  • 验证活动时间范围
  • 验证抽奖时间限制
  • 考虑时区问题

5. 用户资格

  • 验证用户群体限制
  • 检查参与次数限制
  • 防止重复参与

错误处理

常见异常

  1. 活动不存在或未开始 - 活动状态验证失败
  2. 不在抽奖时间内 - 时间验证失败
  3. 用户不符合参与条件 - 用户资格验证失败
  4. 没有抽奖机会 - 机会不足
  5. 已达到参与次数上限 - 次数限制
  6. 该订单已参与过抽奖 - 重复参与
  7. 操作太频繁,请稍后再试 - 并发控制
  8. 暂无可抽取的奖品 - 奖品库存不足
  9. 奖品库存不足 - 库存验证失败
  10. 抽奖机会使用失败 - 机会使用失败

异常处理建议

  • 在API层捕获异常并返回友好提示
  • 记录详细的错误日志
  • 监控异常频率和类型

性能优化

1. 数据库优化

  • 使用索引优化查询
  • 减少不必要的查询
  • 使用批量操作

2. 缓存优化

  • 缓存活动信息
  • 缓存奖品信息
  • 使用Redis锁

3. 算法优化

  • 优化抽奖算法
  • 减少循环次数
  • 使用高效的数据结构

扩展建议

1. 抽奖算法扩展

  • 支持更多抽奖算法
  • 支持动态概率调整
  • 支持保底机制

2. 奖品类型扩展

  • 支持更多奖品类型
  • 支持组合奖品
  • 支持条件奖品

3. 活动类型扩展

  • 支持更多活动类型
  • 支持活动组合
  • 支持活动联动

4. 监控和统计

  • 添加详细的统计功能
  • 实现实时监控
  • 支持数据导出