isPublished()) { throw new BizException('抽奖活动未发布'); } if ($drawActivity->isUnstart()) { throw new BizException('抽奖活动未开始'); } if ($drawActivity->isClosed()) { throw new BizException('抽奖活动已结束'); } (new DrawTicketService())->change($user, $drawActivity, -1, '活动抽奖'); $prize = $this->getDrawActivityPrize($drawActivity); // 如果限制了奖品数量,则需扣除奖品库存 if ($prize->limited) { $prize->update([ 'stock' => DB::raw('stock-1'), 'winnings' => DB::raw('winnings+1'), ]); } else { $prize->increment('winnings', 1); } $drawLog = DrawLog::create([ 'user_id' => $user->id, 'draw_activity_id' => $drawActivity->id, 'draw_activity_prize_id' => $prize->id, 'status' => match ($prize->type) { DrawPrizeType::None => DrawLogStatus::Completed, default => DrawLogStatus::Pending, }, ]); return $drawLog->setRelation('prize', $prize); } /** * @param \App\Models\DrawActivity $drawActivity * @return \App\Models\DrawActivityPrize */ protected function getDrawActivityPrize(DrawActivity $drawActivity): DrawActivityPrize { $drawActivityPrizes = $drawActivity->prizes()->get(); // 过滤权重为0或库存不足的奖品 $prizes = $drawActivityPrizes->filter(function ($item) { if ($item->weight === 0 || ($item->limited && $item->stock === 0)) { return false; } return true; }); $max = $prizes->sum('weight'); if ($max > 0) { $rand = mt_rand($min = 1, $max); foreach ($prizes as $prize) { if ($rand <= $prize->weight + $min) { return $prize; } $min += $prize->weight; } } throw new BizException('抽奖活动异常'); } }