Files
chatroom/app/Http/Controllers/BaccaratController.php

202 lines
7.0 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* 文件功能:百家乐前台下注控制器
*
* 提供用户在聊天室内下注的 API 接口:
* - 查询当前局次信息
* - 提交下注(扣除金币 + 写入下注记录)
* - 查询本人在当前局的下注状态
*
* @author ChatRoom Laravel
*
* @version 1.0.0
*/
namespace App\Http\Controllers;
use App\Enums\CurrencySource;
use App\Models\BaccaratBet;
use App\Models\BaccaratRound;
use App\Models\GameConfig;
use App\Services\UserCurrencyService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class BaccaratController extends Controller
{
public function __construct(
private readonly UserCurrencyService $currency,
) {}
/**
* 获取当前进行中的局次信息(前端轮询或开局事件后调用)。
*/
public function currentRound(Request $request): JsonResponse
{
$round = BaccaratRound::currentRound();
if (! $round) {
return response()->json(['round' => null]);
}
$user = $request->user();
$myBet = BaccaratBet::query()
->where('round_id', $round->id)
->where('user_id', $user->id)
->first();
return response()->json([
'round' => [
'id' => $round->id,
'status' => $round->status,
'bet_closes_at' => $round->bet_closes_at->toIso8601String(),
'seconds_left' => max(0, (int) now()->diffInSeconds($round->bet_closes_at, false)),
'total_bet_big' => $round->total_bet_big,
'total_bet_small' => $round->total_bet_small,
'total_bet_triple' => $round->total_bet_triple,
'bet_count_big' => $round->bet_count_big,
'bet_count_small' => $round->bet_count_small,
'bet_count_triple' => $round->bet_count_triple,
'my_bet' => $myBet ? [
'bet_type' => $myBet->bet_type,
'amount' => $myBet->amount,
] : null,
],
]);
}
/**
* 用户提交下注。
*
* 同一局每人限下一注(后台强制幂等)。
* 下注成功后立即扣除金币,结算时中奖者才返还本金+赔付。
*/
public function bet(Request $request): JsonResponse
{
if (! GameConfig::isEnabled('baccarat')) {
return response()->json(['ok' => false, 'message' => '百家乐游戏当前未开启。']);
}
$data = $request->validate([
'round_id' => 'required|integer|exists:baccarat_rounds,id',
'bet_type' => 'required|in:big,small,triple',
'amount' => 'required|integer|min:1',
]);
$config = GameConfig::forGame('baccarat')?->params ?? [];
$minBet = (int) ($config['min_bet'] ?? 100);
$maxBet = (int) ($config['max_bet'] ?? 50000);
if ($data['amount'] < $minBet || $data['amount'] > $maxBet) {
return response()->json(['ok' => false, 'message' => "押注金额须在 {$minBet}~{$maxBet} 金币之间。"]);
}
$round = BaccaratRound::find($data['round_id']);
if (! $round || ! $round->isBettingOpen()) {
return response()->json(['ok' => false, 'message' => '当前不在下注时间内。']);
}
$user = $request->user();
// 检查用户金币余额(金币字段为 jjb
if (($user->jjb ?? 0) < $data['amount']) {
return response()->json(['ok' => false, 'message' => '金币不足,无法下注。']);
}
$currency = $this->currency;
return DB::transaction(function () use ($user, $round, $data, $currency): JsonResponse {
// 幂等:同一局只能下一注
$existing = BaccaratBet::query()
->where('round_id', $round->id)
->where('user_id', $user->id)
->lockForUpdate()
->exists();
if ($existing) {
return response()->json(['ok' => false, 'message' => '本局您已下注,请等待开奖。']);
}
// 扣除金币
$currency->change(
$user,
'gold',
-$data['amount'],
CurrencySource::BACCARAT_BET,
"百家乐 #{$round->id}".match ($data['bet_type']) {
'big' => '大', 'small' => '小', default => '豹子'
},
);
// 写入下注记录
BaccaratBet::create([
'round_id' => $round->id,
'user_id' => $user->id,
'bet_type' => $data['bet_type'],
'amount' => $data['amount'],
'status' => 'pending',
]);
// 更新局次汇总统计
$field = 'total_bet_'.$data['bet_type'];
$countField = 'bet_count_'.$data['bet_type'];
$round->increment($field, $data['amount']);
$round->increment($countField);
$round->increment('bet_count');
// 广播各选项的最新押注人数
event(new \App\Events\BaccaratPoolUpdated($round));
$betLabel = match ($data['bet_type']) {
'big' => '大', 'small' => '小', default => '豹子'
};
// 发送系统传音到聊天室,公示该用户的押注信息
$chatState = app(\App\Services\ChatStateService::class);
$formattedAmount = number_format($data['amount']);
$roomId = $round->room_id ?? 1;
// 格式:🌟 🎲 娜姐 押注了 119 金币(大)!✨
$content = "🌟 🎲 <b>{$user->username}</b> 押注了 <b>{$formattedAmount}</b> 金币({$betLabel})!✨";
$msg = [
'id' => $chatState->nextMessageId($roomId),
'room_id' => $roomId,
'from_user' => '系统传音',
'to_user' => '大家',
'content' => $content,
'is_secret' => false,
'font_color' => '#d97706',
'action' => '',
'sent_at' => now()->toDateTimeString(),
];
$chatState->pushMessage($roomId, $msg);
event(new \App\Events\MessageSent($roomId, $msg));
\App\Jobs\SaveMessageJob::dispatch($msg);
return response()->json([
'ok' => true,
'message' => "✅ 已押注「{$betLabel}{$data['amount']} 金币,等待开奖!",
'amount' => $data['amount'],
'bet_type' => $data['bet_type'],
]);
});
}
/**
* 查询最近5局的历史记录前端展示趋势
*/
public function history(): JsonResponse
{
$rounds = BaccaratRound::query()
->where('status', 'settled')
->orderByDesc('id')
->limit(10)
->get(['id', 'dice1', 'dice2', 'dice3', 'total_points', 'result', 'settled_at']);
return response()->json(['history' => $rounds]);
}
}