Files
chatroom/app/Http/Controllers/HolidayController.php
T

136 lines
4.3 KiB
PHP

<?php
/**
* 文件功能:节日福利前台领取控制器
*
* 用户通过聊天室内弹窗点击"立即领取"调用此接口,
* 完成金币入账并返回领取结果。
*
* @author ChatRoom Laravel
*
* @version 1.0.0
*/
namespace App\Http\Controllers;
use App\Enums\CurrencySource;
use App\Models\HolidayClaim;
use App\Models\HolidayEventRun;
use App\Services\UserCurrencyService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
/**
* 类功能:处理节日福利批次的前台领取与状态查询。
*/
class HolidayController extends Controller
{
/**
* 注入用户金币服务。
*/
public function __construct(
private readonly UserCurrencyService $currency,
) {}
/**
* 用户领取节日福利红包。
*
* 从 holiday_claims 中查找当前用户在指定批次下的待领取记录,
* 入账金币并更新批次统计数据。
*/
public function claim(Request $request, HolidayEventRun $run): JsonResponse
{
$user = $request->user();
// 批次是否在领取有效期内。
if (! $run->isClaimable()) {
return response()->json(['ok' => false, 'message' => '活动已结束或已过期。']);
}
return DB::transaction(function () use ($run, $user): JsonResponse {
/** @var HolidayEventRun|null $lockedRun */
$lockedRun = HolidayEventRun::query()
->whereKey($run->id)
->lockForUpdate()
->first();
if (! $lockedRun || ! $lockedRun->isClaimable()) {
return response()->json(['ok' => false, 'message' => '活动已结束或已过期。']);
}
/** @var HolidayClaim|null $claim */
$claim = HolidayClaim::query()
->where('run_id', $lockedRun->id)
->where('user_id', $user->id)
->lockForUpdate()
->first();
if (! $claim) {
return response()->json(['ok' => false, 'message' => '您不在本次福利名单内,或活动已结束。']);
}
// claimed_at 不为空代表本轮已领过,直接返回幂等提示。
if ($claim->claimed_at !== null) {
return response()->json([
'ok' => false,
'message' => '您已领取过本轮福利。',
'amount' => $claim->amount,
]);
}
// 金币入账。
$this->currency->change(
$user,
'gold',
$claim->amount,
CurrencySource::HOLIDAY_BONUS,
"节日福利:{$lockedRun->event_name}",
);
// 领取成功后只更新 claimed_at,不再删除记录,便于幂等和历史追踪。
$claim->update(['claimed_at' => now()]);
// 批次领取统计按成功领取次数累计。
$lockedRun->increment('claimed_count');
$lockedRun->increment('claimed_amount', $claim->amount);
$remainingPendingClaims = HolidayClaim::query()
->where('run_id', $lockedRun->id)
->whereNull('claimed_at')
->count();
if ($remainingPendingClaims === 0) {
$lockedRun->update(['status' => 'completed']);
}
return response()->json([
'ok' => true,
'message' => "🎉 恭喜!已领取 {$claim->amount} 金币!",
'amount' => $claim->amount,
]);
});
}
/**
* 查询当前用户在指定批次中的待领取状态。
*/
public function status(Request $request, HolidayEventRun $run): JsonResponse
{
$user = $request->user();
$claim = HolidayClaim::query()
->where('run_id', $run->id)
->where('user_id', $user->id)
->first();
return response()->json([
'claimable' => $claim !== null && $claim->claimed_at === null && $run->isClaimable(),
'claimed' => $claim?->claimed_at !== null,
'amount' => $claim?->amount ?? 0,
'status' => $run->status,
'expires_at' => $run->expires_at?->toIso8601String(),
]);
}
}