# LotteryService 抽奖服务类文档 ## 概述 `LotteryService` 是抽奖系统的核心服务类,负责处理抽奖的核心业务逻辑,包括抽奖执行、奖品管理、活动状态管理等功能。 ## 类结构 ```php 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` 各种验证失败异常 **使用示例**: ```php 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() - 执行抽奖算法 **功能**: 基于概率权重的抽奖算法实现。 **算法原理**: - 计算所有奖品的总概率 - 生成随机数 - 按概率权重选择奖品 - 保底返回第一个奖品(通常是未中奖) **使用示例**: ```php $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` 机会信息 **返回格式**: ```php [ '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. 基本抽奖流程 ```php // 用户抽奖 try { $result = LotteryService::drawLottery(1, 123); if ($result['is_win']) { echo "恭喜中奖!奖品:" . $result['prize']['name']; } else { echo "很遗憾,未中奖"; } } catch (Exception $e) { echo "抽奖失败:" . $e->getMessage(); } ``` ### 2. 检查活动状态 ```php $activity = LotteryActivity::find(1); if (LotteryService::isActivityRunning($activity)) { echo "活动正在进行中"; } elseif (LotteryService::isActivityEnded($activity)) { echo "活动已结束"; } elseif (LotteryService::isActivityNotStarted($activity)) { echo "活动未开始"; } ``` ### 3. 获取用户机会 ```php $chances = LotteryService::getUserChances(1, 123); echo "剩余抽奖机会:" . $chances['remain_chances']; ``` ### 4. 检查奖品库存 ```php $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. 监控和统计 - 添加详细的统计功能 - 实现实时监控 - 支持数据导出