98 lines
2.7 KiB
PHP
98 lines
2.7 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Enums\DrawLogStatus;
|
|
use App\Enums\DrawPrizeType;
|
|
use App\Exceptions\BizException;
|
|
use App\Models\DrawActivity;
|
|
use App\Models\DrawActivityPrize;
|
|
use App\Models\DrawLog;
|
|
use App\Models\User;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
class DrawActivityService
|
|
{
|
|
/**
|
|
* 活动抽奖
|
|
*
|
|
* @param \App\Models\DrawActivity $drawActivity
|
|
* @param \App\Models\User $user
|
|
* @return \App\Models\DrawLog
|
|
*/
|
|
public function draw(DrawActivity $drawActivity, User $user): DrawLog
|
|
{
|
|
if (! $drawActivity->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('抽奖活动异常');
|
|
}
|
|
}
|