diff --git a/GAMES_TODO.md b/GAMES_TODO.md
index 8117dd2..c11b7e1 100644
--- a/GAMES_TODO.md
+++ b/GAMES_TODO.md
@@ -1,6 +1,6 @@
# 🎮 聊天室游戏开发进度
-> 更新时间:2026-03-03
+> 更新时间:2026-03-04
---
@@ -76,9 +76,9 @@
## 📌 通用待办(所有游戏共用)
-- [ ] 后台游戏管理页面(`/admin/game-configs`)显示各游戏实时统计数据
-- [ ] 各游戏历史记录在后台可查(管理员视角)
-- [ ] 生产环境部署:`php artisan db:seed --class=GameConfigSeeder`(初始化游戏配置) 已经完成了
+- [x] 后台游戏管理页面(`/admin/game-configs`)显示各游戏实时统计数据(点击"加载实时统计"异步加载各游戏汇总卡片)
+- [x] 各游戏历史记录在后台可查(管理员视角,新增 `/admin/game-history/` 路由组,支持百家乐/老虎机/赛马/神秘箱子/占卜各自的历史记录列表及详情页,含筛选分页)
+- [x] 生产环境部署:`php artisan db:seed --class=GameConfigSeeder`(初始化游戏配置) 已经完成了
- [ ] 百家乐/老虎机 全面测试(多用户并发下注)
---
diff --git a/app/Http/Controllers/Admin/GameHistoryController.php b/app/Http/Controllers/Admin/GameHistoryController.php
new file mode 100644
index 0000000..0b1af7b
--- /dev/null
+++ b/app/Http/Controllers/Admin/GameHistoryController.php
@@ -0,0 +1,244 @@
+ BaccaratRound::query()->where('status', 'settled')->count(),
+ 'total_bets' => BaccaratBet::query()->count(),
+ 'total_payout' => BaccaratRound::query()->where('status', 'settled')->sum('total_payout'),
+ 'today_rounds' => BaccaratRound::query()->where('status', 'settled')->whereDate('settled_at', today())->count(),
+ ];
+
+ // 老虎机
+ $slot = [
+ 'total_spins' => SlotMachineLog::query()->count(),
+ 'total_cost' => SlotMachineLog::query()->sum('cost'),
+ 'total_payout' => SlotMachineLog::query()->sum('payout'),
+ 'jackpot_count' => SlotMachineLog::query()->where('result_type', 'jackpot')->count(),
+ 'today_spins' => SlotMachineLog::query()->whereDate('created_at', today())->count(),
+ ];
+
+ // 赛马
+ $horse = [
+ 'total_races' => HorseRace::query()->where('status', 'settled')->count(),
+ 'total_bets' => HorseBet::query()->count(),
+ 'total_pool' => HorseRace::query()->where('status', 'settled')->sum('total_pool'),
+ 'today_races' => HorseRace::query()->where('status', 'settled')->whereDate('settled_at', today())->count(),
+ ];
+
+ // 神秘箱子
+ $mysteryBox = [
+ 'total_dropped' => MysteryBox::query()->count(),
+ 'total_claimed' => MysteryBox::query()->where('status', 'claimed')->count(),
+ 'total_expired' => MysteryBox::query()->where('status', 'expired')->count(),
+ 'today_dropped' => MysteryBox::query()->whereDate('created_at', today())->count(),
+ ];
+
+ // 占卜
+ $fortune = [
+ 'total_times' => FortuneLog::query()->count(),
+ 'jackpot_count' => FortuneLog::query()->where('grade', 'jackpot')->count(),
+ 'curse_count' => FortuneLog::query()->where('grade', 'curse')->count(),
+ 'today_times' => FortuneLog::query()->whereDate('created_at', today())->count(),
+ ];
+
+ return response()->json([
+ 'baccarat' => $baccarat,
+ 'slot' => $slot,
+ 'horse' => $horse,
+ 'mystery_box' => $mysteryBox,
+ 'fortune' => $fortune,
+ ]);
+ }
+
+ /**
+ * 百家乐历史记录页面(局次列表,支持分页)。
+ */
+ public function baccarat(Request $request): View
+ {
+ // 各局统计摘要
+ $summary = [
+ 'total_rounds' => BaccaratRound::query()->where('status', 'settled')->count(),
+ 'total_bets' => BaccaratBet::query()->count(),
+ 'total_payout' => (int) BaccaratRound::query()->where('status', 'settled')->sum('total_payout'),
+ 'result_dist' => BaccaratRound::query()
+ ->where('status', 'settled')
+ ->select('result', \Illuminate\Support\Facades\DB::raw('count(*) as cnt'))
+ ->groupBy('result')
+ ->pluck('cnt', 'result'),
+ ];
+
+ $rounds = BaccaratRound::query()
+ ->latest()
+ ->paginate(20);
+
+ return view('admin.game-history.baccarat', compact('rounds', 'summary'));
+ }
+
+ /**
+ * 百家乐单局下注明细。
+ */
+ public function baccaratRound(BaccaratRound $round): View
+ {
+ $bets = $round->bets()->with('user')->latest()->paginate(30);
+
+ return view('admin.game-history.baccarat-round', compact('round', 'bets'));
+ }
+
+ /**
+ * 老虎机历史记录页面(支持按结果类型筛选/分页)。
+ */
+ public function slot(Request $request): View
+ {
+ // 统计摘要
+ $summary = [
+ 'total_spins' => SlotMachineLog::query()->count(),
+ 'total_cost' => (int) SlotMachineLog::query()->sum('cost'),
+ 'total_payout' => (int) SlotMachineLog::query()->sum('payout'),
+ 'net_income' => (int) SlotMachineLog::query()->sum('cost') - (int) SlotMachineLog::query()->sum('payout'),
+ 'result_dist' => SlotMachineLog::query()
+ ->select('result_type', \Illuminate\Support\Facades\DB::raw('count(*) as cnt'))
+ ->groupBy('result_type')
+ ->pluck('cnt', 'result_type'),
+ ];
+
+ $query = SlotMachineLog::query()->with('user')->latest();
+
+ // 按结果类型筛选
+ if ($request->filled('result_type')) {
+ $query->where('result_type', $request->input('result_type'));
+ }
+
+ // 按用户名筛选
+ if ($request->filled('username')) {
+ $query->whereHas('user', function ($q) use ($request) {
+ $q->where('username', 'like', '%'.$request->input('username').'%');
+ });
+ }
+
+ $logs = $query->paginate(30)->withQueryString();
+
+ return view('admin.game-history.slot', compact('logs', 'summary'));
+ }
+
+ /**
+ * 赛马竞猜历史记录页面(场次列表,支持分页)。
+ */
+ public function horse(Request $request): View
+ {
+ $summary = [
+ 'total_races' => HorseRace::query()->where('status', 'settled')->count(),
+ 'total_bets' => HorseBet::query()->count(),
+ 'total_pool' => (int) HorseRace::query()->sum('total_pool'),
+ ];
+
+ $races = HorseRace::query()
+ ->latest()
+ ->paginate(20);
+
+ return view('admin.game-history.horse', compact('races', 'summary'));
+ }
+
+ /**
+ * 赛马单场下注明细。
+ */
+ public function horseRace(HorseRace $race): View
+ {
+ $bets = $race->bets()->with('user')->latest()->paginate(30);
+
+ return view('admin.game-history.horse-race', compact('race', 'bets'));
+ }
+
+ /**
+ * 神秘箱子历史记录(投放/领取列表,支持分页和类型筛选)。
+ */
+ public function mysteryBox(Request $request): View
+ {
+ $summary = [
+ 'total_dropped' => MysteryBox::query()->count(),
+ 'total_claimed' => MysteryBox::query()->where('status', 'claimed')->count(),
+ 'total_expired' => MysteryBox::query()->where('status', 'expired')->count(),
+ 'type_dist' => MysteryBox::query()
+ ->select('box_type', \Illuminate\Support\Facades\DB::raw('count(*) as cnt'))
+ ->groupBy('box_type')
+ ->pluck('cnt', 'box_type'),
+ ];
+
+ $query = MysteryBox::query()->with(['claim.user'])->latest();
+
+ if ($request->filled('box_type')) {
+ $query->where('box_type', $request->input('box_type'));
+ }
+
+ if ($request->filled('status')) {
+ $query->where('status', $request->input('status'));
+ }
+
+ $boxes = $query->paginate(20)->withQueryString();
+
+ return view('admin.game-history.mystery-box', compact('boxes', 'summary'));
+ }
+
+ /**
+ * 神秘占卜历史记录(支持按用户/签文等级筛选,分页)。
+ */
+ public function fortune(Request $request): View
+ {
+ $summary = [
+ 'total_times' => FortuneLog::query()->count(),
+ 'grade_dist' => FortuneLog::query()
+ ->select('grade', \Illuminate\Support\Facades\DB::raw('count(*) as cnt'))
+ ->groupBy('grade')
+ ->pluck('cnt', 'grade'),
+ 'total_cost' => (int) FortuneLog::query()->sum('cost'),
+ 'free_count' => FortuneLog::query()->where('is_free', true)->count(),
+ ];
+
+ $query = FortuneLog::query()->with('user')->latest();
+
+ if ($request->filled('grade')) {
+ $query->where('grade', $request->input('grade'));
+ }
+
+ if ($request->filled('username')) {
+ $query->whereHas('user', function ($q) use ($request) {
+ $q->where('username', 'like', '%'.$request->input('username').'%');
+ });
+ }
+
+ $logs = $query->paginate(30)->withQueryString();
+
+ return view('admin.game-history.fortune', compact('logs', 'summary'));
+ }
+}
diff --git a/resources/views/admin/game-configs/index.blade.php b/resources/views/admin/game-configs/index.blade.php
index e81bd30..c9f140a 100644
--- a/resources/views/admin/game-configs/index.blade.php
+++ b/resources/views/admin/game-configs/index.blade.php
@@ -6,9 +6,22 @@
{{-- 页头 --}}
-
-
🎮 游戏管理
-
统一管理聊天室所有娱乐游戏的开关状态与核心参数,所有游戏默认关闭。
+
+
+
🎮 游戏管理
+
统一管理聊天室所有娱乐游戏的开关状态与核心参数,所有游戏默认关闭。
+
+
+
+
+ {{-- 实时统计摘要区(AJAX 异步加载,默认隐藏) --}}
+
+
+ {{-- 由 JS 动态填充 --}}
+
@if (session('success'))
@@ -41,13 +54,33 @@
{{ $game->description }}
- {{-- 大开关按钮 --}}
-
+ {{-- 操作按钮组 --}}
+
+ {{-- 历史记录链接 --}}
+ @php
+ $historyRoute = match ($game->game_key) {
+ 'baccarat' => 'admin.game-history.baccarat',
+ 'slot_machine' => 'admin.game-history.slot',
+ 'mystery_box' => 'admin.game-history.mystery-box',
+ 'horse_racing' => 'admin.game-history.horse',
+ 'fortune_telling' => 'admin.game-history.fortune',
+ default => null,
+ };
+ @endphp
+ @if ($historyRoute)
+
+ 📋 历史记录
+
+ @endif
+ {{-- 大开关按钮 --}}
+
+
{{-- 参数配置区域 --}}
@@ -231,6 +264,139 @@
);
}
+
+
@endsection
@php
diff --git a/resources/views/admin/game-history/baccarat-round.blade.php b/resources/views/admin/game-history/baccarat-round.blade.php
new file mode 100644
index 0000000..e656e28
--- /dev/null
+++ b/resources/views/admin/game-history/baccarat-round.blade.php
@@ -0,0 +1,115 @@
+@extends('admin.layouts.app')
+
+@section('title', "百家乐第 #{$round->id} 局下注明细")
+
+@section('content')
+
+
+ {{-- 页头 --}}
+
+
+
🎲 百家乐 #{{ $round->id }} 局下注明细
+
+ 结算时间:{{ $round->settled_at?->format('Y-m-d H:i:s') ?? '未结算' }}
+ · 结果:
+ {{ $round->resultLabel() }}
+ · 总点数:{{ $round->total_points }}
+
+
+
+ ← 返回历史列表
+
+
+
+ {{-- 本局摘要 --}}
+
+
+
{{ number_format($round->bet_count ?? 0) }}
+
参与下注人数
+
+
+
{{ number_format($round->total_bet_big ?? 0) }}
+
押大总金额
+
+
+
{{ number_format($round->total_bet_small ?? 0) }}
+
押小总金额
+
+
+
{{ number_format($round->total_payout ?? 0) }}
+
本局派奖总额
+
+
+
+ {{-- 下注明细表 --}}
+
+
+
+
+ | 玩家 |
+ 押注方向 |
+ 押注金额 |
+ 实际获得 |
+ 是否中奖 |
+ 下注时间 |
+
+
+
+ @forelse ($bets as $bet)
+ @php
+ $betLabels = ['big' => '大', 'small' => '小', 'triple' => '豹子'];
+ $betColors = [
+ 'big' => 'bg-red-100 text-red-700',
+ 'small' => 'bg-blue-100 text-blue-700',
+ 'triple' => 'bg-purple-100 text-purple-700',
+ ];
+ $won = $bet->payout > 0;
+ @endphp
+
+ |
+ {{ $bet->user?->username ?? '已注销' }}
+ |
+
+
+ {{ $betLabels[$bet->bet_type] ?? $bet->bet_type }}
+
+ |
+
+ {{ number_format($bet->amount) }}
+ |
+
+ {{ $won ? '+' . number_format($bet->payout) : '0' }}
+ |
+
+ @if ($won)
+ 🎉
+ 中奖
+ @else
+ 未中
+ @endif
+ |
+
+ {{ $bet->created_at->format('H:i:s') }}
+ |
+
+ @empty
+
+ | 本局无人下注 |
+
+ @endforelse
+
+
+
+ @if ($bets->hasPages())
+
+ {{ $bets->links() }}
+
+ @endif
+
+
+@endsection
diff --git a/resources/views/admin/game-history/baccarat.blade.php b/resources/views/admin/game-history/baccarat.blade.php
new file mode 100644
index 0000000..78c4480
--- /dev/null
+++ b/resources/views/admin/game-history/baccarat.blade.php
@@ -0,0 +1,139 @@
+@extends('admin.layouts.app')
+
+@section('title', '百家乐历史记录')
+
+@section('content')
+
+
+ {{-- 页头 --}}
+
+
+ {{-- 统计卡片 --}}
+
+
+
{{ number_format($summary['total_rounds']) }}
+
历史总局数
+
+
+
{{ number_format($summary['total_bets']) }}
+
历史总下注次
+
+
+
{{ number_format($summary['total_payout']) }}
+
累计派奖金币
+
+
+
结果分布
+
+ @foreach (['big' => '大', 'small' => '小', 'triple' => '豹子', 'kill' => '收割'] as $key => $label)
+
+ {{ $label }}
+ {{ $summary['result_dist'][$key] ?? 0 }} 局
+
+ @endforeach
+
+
+
+
+ {{-- 局次列表 --}}
+
+
+
+
+ | 局次ID |
+ 结算时间 |
+ 骰子 |
+ 点数 |
+ 结果 |
+ 押注笔数 |
+ 押大/小/豹 |
+ 派奖金币 |
+ 操作 |
+
+
+
+ @forelse ($rounds as $round)
+
+ | #{{ $round->id }} |
+
+ {{ $round->settled_at ? $round->settled_at->format('m-d H:i') : '—' }}
+ |
+
+ @if ($round->dice1)
+ {{ $round->dice1 }} {{ $round->dice2 }} {{ $round->dice3 }}
+ @else
+ —
+ @endif
+ |
+
+ {{ $round->total_points ?? '—' }}
+ |
+
+ @php
+ $resultColors = [
+ 'big' => 'bg-red-100 text-red-700',
+ 'small' => 'bg-blue-100 text-blue-700',
+ 'triple' => 'bg-purple-100 text-purple-700',
+ 'kill' => 'bg-gray-100 text-gray-600',
+ ];
+ $label = match ($round->result) {
+ 'big' => '大',
+ 'small' => '小',
+ 'triple' => '豹子',
+ 'kill' => '收割',
+ default => $round->result ?? '—',
+ };
+ $colorClass = $resultColors[$round->result] ?? 'bg-gray-100 text-gray-600';
+ @endphp
+ @if ($round->result)
+
+ {{ $label }}
+
+ @else
+ 未结算
+ @endif
+ |
+
+ {{ number_format($round->bet_count ?? 0) }}
+ |
+
+ {{ number_format($round->total_bet_big ?? 0) }} /
+ {{ number_format($round->total_bet_small ?? 0) }} /
+ {{ number_format($round->total_bet_triple ?? 0) }}
+ |
+
+ {{ number_format($round->total_payout ?? 0) }}
+ |
+
+
+ 下注明细
+
+ |
+
+ @empty
+
+ | 暂无记录 |
+
+ @endforelse
+
+
+
+ {{-- 分页 --}}
+ @if ($rounds->hasPages())
+
+ {{ $rounds->links() }}
+
+ @endif
+
+
+@endsection
diff --git a/resources/views/admin/game-history/fortune.blade.php b/resources/views/admin/game-history/fortune.blade.php
new file mode 100644
index 0000000..859814c
--- /dev/null
+++ b/resources/views/admin/game-history/fortune.blade.php
@@ -0,0 +1,163 @@
+@extends('admin.layouts.app')
+
+@section('title', '神秘占卜历史记录')
+
+@section('content')
+
+
+ {{-- 页头 --}}
+
+
+
🔮 神秘占卜历史记录
+
查询所有玩家的占卜记录,支持按等级和玩家名筛选。
+
+
+ ⚙️ 游戏配置
+
+
+
+ {{-- 统计卡片 --}}
+
+
+
{{ number_format($summary['total_times']) }}
+
历史总占卜次
+
+
+
{{ number_format($summary['grade_dist']['jackpot'] ?? 0) }}
+
+
✨ 上上签次数
+
+
+
{{ number_format($summary['grade_dist']['curse'] ?? 0) }}
+
💀 大凶签次数
+
+
+
签文分布
+
+ @php
+ $gradeAll = [
+ 'jackpot' => ['label' => '上上签', 'color' => 'text-amber-600'],
+ 'good' => ['label' => '上签', 'color' => 'text-emerald-600'],
+ 'normal' => ['label' => '中签', 'color' => 'text-gray-500'],
+ 'bad' => ['label' => '下签', 'color' => 'text-orange-500'],
+ 'curse' => ['label' => '大凶签', 'color' => 'text-red-600'],
+ ];
+ @endphp
+ @foreach ($gradeAll as $key => $meta)
+
+ {{ $meta['label'] }}
+ {{ $summary['grade_dist'][$key] ?? 0 }}
+
+ @endforeach
+
+
+
+
+ {{-- 筛选 --}}
+
+
+ {{-- 记录列表 --}}
+
+
+
+
+ | 时间 |
+ 玩家 |
+ 签文等级 |
+ 签文内容 |
+ 加成/减益 |
+ 是否免费 |
+ 消耗金币 |
+
+
+
+ @forelse ($logs as $log)
+ @php
+ $gradeInfo = match ($log->grade) {
+ 'jackpot' => ['label' => '✨ 上上签', 'color' => 'bg-amber-100 text-amber-700'],
+ 'good' => ['label' => '🌸 上签', 'color' => 'bg-emerald-100 text-emerald-700'],
+ 'normal' => ['label' => '📜 中签', 'color' => 'bg-gray-100 text-gray-600'],
+ 'bad' => ['label' => '😞 下签', 'color' => 'bg-orange-100 text-orange-700'],
+ 'curse' => ['label' => '💀 大凶签', 'color' => 'bg-red-100 text-red-700'],
+ default => ['label' => $log->grade, 'color' => 'bg-gray-100 text-gray-500'],
+ };
+ @endphp
+
+ |
+ {{ $log->created_at->format('m-d H:i') }}
+ |
+
+ {{ $log->user?->username ?? '已注销' }}
+ |
+
+
+ {{ $gradeInfo['label'] }}
+
+ |
+
+ {{ \Illuminate\Support\Str::limit($log->text, 50) }}
+ |
+
+ {{ $log->buff_desc ?? '—' }}
+ |
+
+ @if ($log->is_free)
+ 免费
+ @else
+ 付费
+ @endif
+ |
+
+ {{ $log->cost > 0 ? '-' . number_format($log->cost) : '0' }}
+ |
+
+ @empty
+
+ | 暂无记录 |
+
+ @endforelse
+
+
+
+ @if ($logs->hasPages())
+
+ {{ $logs->links() }}
+
+ @endif
+
+
+@endsection
diff --git a/resources/views/admin/game-history/horse-race.blade.php b/resources/views/admin/game-history/horse-race.blade.php
new file mode 100644
index 0000000..232afaa
--- /dev/null
+++ b/resources/views/admin/game-history/horse-race.blade.php
@@ -0,0 +1,124 @@
+@extends('admin.layouts.app')
+
+@section('title', "赛马第 #{$race->id} 场下注明细")
+
+@section('content')
+
+
+ {{-- 页头 --}}
+ @php
+ $horses = $race->horses ?? [];
+ $winner = collect($horses)->firstWhere('id', $race->winner_horse_id);
+ @endphp
+
+
+
🐎 赛马 #{{ $race->id }} 场下注明细
+
+ 结算时间:{{ $race->settled_at?->format('Y-m-d H:i:s') ?? '未结算' }}
+ @if ($winner)
+ · 胜者:{{ $winner['emoji'] ?? '' }}
+ {{ $winner['name'] ?? '' }}
+ @endif
+ · 注池:{{ number_format($race->total_pool ?? 0) }}
+ 金币
+
+
+
+ ← 返回场次列表
+
+
+
+ {{-- 马匹信息 --}}
+ @if (count($horses) > 0)
+
+
参赛马匹
+
+ @foreach ($horses as $horse)
+
+
{{ $horse['emoji'] ?? '🐎' }}
+
+ {{ $horse['name'] }}
+ @if ($horse['id'] === $race->winner_horse_id)
+ 🏆
+ @endif
+
+
+ @endforeach
+
+
+ @endif
+
+ {{-- 下注明细表 --}}
+
+
+
+
+ | 玩家 |
+ 押注马匹 |
+ 押注金额 |
+ 实际获得 |
+ 是否中奖 |
+ 下注时间 |
+
+
+
+ @forelse ($bets as $bet)
+ @php
+ $betHorse = collect($horses)->firstWhere('id', $bet->horse_id);
+ $isWinner = $bet->horse_id === $race->winner_horse_id;
+ $won = ($bet->payout ?? 0) > 0;
+ @endphp
+
+ |
+ {{ $bet->user?->username ?? '已注销' }}
+ |
+
+ @if ($betHorse)
+
+ {{ $betHorse['emoji'] ?? '' }} {{ $betHorse['name'] ?? '' }}
+
+ @else
+ #{{ $bet->horse_id }}
+ @endif
+ |
+
+ {{ number_format($bet->amount) }}
+ |
+
+ {{ $won ? '+' . number_format($bet->payout) : '0' }}
+ |
+
+ @if ($won)
+ 🎉
+ 中奖
+ @else
+ 未中
+ @endif
+ |
+
+ {{ $bet->created_at->format('H:i:s') }}
+ |
+
+ @empty
+
+ | 本场无人下注 |
+
+ @endforelse
+
+
+
+ @if ($bets->hasPages())
+
+ {{ $bets->links() }}
+
+ @endif
+
+
+@endsection
diff --git a/resources/views/admin/game-history/horse.blade.php b/resources/views/admin/game-history/horse.blade.php
new file mode 100644
index 0000000..44ca99d
--- /dev/null
+++ b/resources/views/admin/game-history/horse.blade.php
@@ -0,0 +1,113 @@
+@extends('admin.layouts.app')
+
+@section('title', '赛马竞猜历史记录')
+
+@section('content')
+
+
+ {{-- 页头 --}}
+
+
+ {{-- 统计卡片 --}}
+
+
+
{{ number_format($summary['total_races']) }}
+
历史总场次
+
+
+
{{ number_format($summary['total_bets']) }}
+
历史总下注笔
+
+
+
{{ number_format($summary['total_pool']) }}
+
累计注池金币
+
+
+
+ {{-- 场次列表 --}}
+
+
+
+
+ | 场次ID |
+ 结算时间 |
+ 参赛马匹 |
+ 胜者 |
+ 状态 |
+ 下注总笔 |
+ 注池总额 |
+ 操作 |
+
+
+
+ @forelse ($races as $race)
+ @php
+ $horses = $race->horses ?? [];
+ $winner = collect($horses)->firstWhere('id', $race->winner_horse_id);
+ $statusLabel = match ($race->status) {
+ 'betting' => ['label' => '押注中', 'color' => 'bg-blue-100 text-blue-700'],
+ 'running' => ['label' => '比赛中', 'color' => 'bg-amber-100 text-amber-700'],
+ 'settled' => ['label' => '已结算', 'color' => 'bg-emerald-100 text-emerald-700'],
+ 'canceled' => ['label' => '已取消', 'color' => 'bg-red-100 text-red-600'],
+ default => ['label' => $race->status, 'color' => 'bg-gray-100 text-gray-500'],
+ };
+ @endphp
+
+ | #{{ $race->id }} |
+
+ {{ $race->settled_at ? $race->settled_at->format('m-d H:i') : '—' }}
+ |
+
+ {{ collect($horses)->pluck('emoji')->implode('') ?: '—' }}
+ ({{ count($horses) }} 匹)
+ |
+
+ @if ($winner)
+ {{ $winner['emoji'] ?? '' }} {{ $winner['name'] ?? '' }}
+ @else
+ —
+ @endif
+ |
+
+
+ {{ $statusLabel['label'] }}
+
+ |
+
+ {{ number_format($race->total_bets ?? 0) }}
+ |
+
+ {{ number_format($race->total_pool ?? 0) }}
+ |
+
+
+ 下注明细
+
+ |
+
+ @empty
+
+ | 暂无记录 |
+
+ @endforelse
+
+
+
+ @if ($races->hasPages())
+
+ {{ $races->links() }}
+
+ @endif
+
+
+@endsection
diff --git a/resources/views/admin/game-history/mystery-box.blade.php b/resources/views/admin/game-history/mystery-box.blade.php
new file mode 100644
index 0000000..a7390b0
--- /dev/null
+++ b/resources/views/admin/game-history/mystery-box.blade.php
@@ -0,0 +1,174 @@
+@extends('admin.layouts.app')
+
+@section('title', '神秘箱子历史记录')
+
+@section('content')
+
+
+ {{-- 页头 --}}
+
+
+
📦 神秘箱子历史记录
+
查询所有投放过的神秘箱子记录,含领取情况。
+
+
+ ⚙️ 游戏配置
+
+
+
+ {{-- 统计卡片 --}}
+
+
+
{{ number_format($summary['total_dropped']) }}
+
历史总投放数
+
+
+
{{ number_format($summary['total_claimed']) }}
+
已被领取
+
+
+
{{ number_format($summary['total_expired']) }}
+
已过期/未领取
+
+
+
类型分布
+
+
+ 📦 普通箱
+ {{ $summary['type_dist']['normal'] ?? 0 }}
+
+
+ 💎 稀有箱
+ {{ $summary['type_dist']['rare'] ?? 0 }}
+
+
+ ☠️ 黑化箱
+ {{ $summary['type_dist']['trap'] ?? 0 }}
+
+
+
+
+
+ {{-- 筛选条件 --}}
+
+
+ {{-- 箱子列表 --}}
+
+
+
+
+ | 投放时间 |
+ 类型 |
+ 奖励范围 |
+ 暗号 |
+ 状态 |
+ 领取者 |
+ 实际奖励 |
+ 领取时间 |
+
+
+
+ @forelse ($boxes as $box)
+ @php
+ $typeInfo = match ($box->box_type) {
+ 'normal' => ['label' => '📦 普通箱', 'color' => 'bg-emerald-100 text-emerald-700'],
+ 'rare' => ['label' => '💎 稀有箱', 'color' => 'bg-purple-100 text-purple-700'],
+ 'trap' => ['label' => '☠️ 黑化箱', 'color' => 'bg-red-100 text-red-700'],
+ default => ['label' => '📦 未知', 'color' => 'bg-gray-100 text-gray-600'],
+ };
+ $statusInfo = match ($box->status) {
+ 'open' => ['label' => '等待领取', 'color' => 'bg-blue-100 text-blue-700'],
+ 'claimed' => ['label' => '✅ 已领取', 'color' => 'bg-emerald-100 text-emerald-700'],
+ 'expired' => ['label' => '⏰ 已过期', 'color' => 'bg-gray-100 text-gray-500'],
+ default => ['label' => $box->status, 'color' => 'bg-gray-100 text-gray-500'],
+ };
+ $claim = $box->claim;
+ @endphp
+
+ |
+ {{ $box->created_at->format('m-d H:i:s') }}
+ |
+
+
+ {{ $typeInfo['label'] }}
+
+ |
+
+ {{ number_format($box->reward_min) }} ~ {{ number_format($box->reward_max) }}
+ |
+
+
+ {{ $box->passcode ?? '—' }}
+
+ |
+
+
+ {{ $statusInfo['label'] }}
+
+ |
+
+ {{ $claim?->user?->username ?? '—' }}
+ |
+
+ @if ($claim)
+
+ {{ $claim->reward_amount > 0 ? '+' : '' }}{{ number_format($claim->reward_amount) }}
+
+ @else
+ —
+ @endif
+ |
+
+ {{ $claim?->created_at?->format('m-d H:i:s') ?? '—' }}
+ |
+
+ @empty
+
+ | 暂无记录 |
+
+ @endforelse
+
+
+
+ @if ($boxes->hasPages())
+
+ {{ $boxes->links() }}
+
+ @endif
+
+
+@endsection
diff --git a/resources/views/admin/game-history/slot.blade.php b/resources/views/admin/game-history/slot.blade.php
new file mode 100644
index 0000000..5f6c415
--- /dev/null
+++ b/resources/views/admin/game-history/slot.blade.php
@@ -0,0 +1,172 @@
+@extends('admin.layouts.app')
+
+@section('title', '老虎机历史记录')
+
+@section('content')
+
+
+ {{-- 页头 --}}
+
+
+
🎰 老虎机历史记录
+
查询所有玩家的老虎机转动记录,支持按结果类型和玩家名筛选。
+
+
+ ⚙️ 游戏配置
+
+
+
+ {{-- 统计卡片 --}}
+
+
+
{{ number_format($summary['total_spins']) }}
+
总转动次数
+
+
+
{{ number_format($summary['total_cost']) }}
+
总消耗金币
+
+
+
{{ number_format($summary['total_payout']) }}
+
总派奖金币
+
+
+
{{ number_format($summary['net_income']) }}
+
庄家净收(消耗-派奖)
+
+
+
{{ number_format($summary['result_dist']['jackpot'] ?? 0) }}
+
+
🎉 三7大奖次数
+
+
+
+ {{-- 结果分布 --}}
+
+
结果类型分布
+
+ @php
+ $resultLabels = [
+ 'jackpot' => ['label' => '🎉 三个7', 'color' => 'bg-yellow-100 text-yellow-700'],
+ 'triple_gem' => ['label' => '💎 三钻', 'color' => 'bg-blue-100 text-blue-700'],
+ 'triple' => ['label' => '✨ 三同', 'color' => 'bg-green-100 text-green-700'],
+ 'pair' => ['label' => '🎁 两同', 'color' => 'bg-indigo-100 text-indigo-700'],
+ 'curse' => ['label' => '☠️ 三骷髅', 'color' => 'bg-red-100 text-red-700'],
+ 'miss' => ['label' => '😔 未中奖', 'color' => 'bg-gray-100 text-gray-600'],
+ ];
+ @endphp
+ @foreach ($resultLabels as $key => $meta)
+
+ @endforeach
+
+
+
+ {{-- 筛选条件 --}}
+
+
+ {{-- 记录列表 --}}
+
+
+
+
+ | 时间 |
+ 玩家 |
+ 三列图案 |
+ 结果 |
+ 消耗 |
+ 获得 |
+ 净值 |
+
+
+
+ @forelse ($logs as $log)
+ @php
+ $symbols = \App\Models\SlotMachineLog::symbols();
+ $r1Emoji = $symbols[$log->reel1]['emoji'] ?? $log->reel1;
+ $r2Emoji = $symbols[$log->reel2]['emoji'] ?? $log->reel2;
+ $r3Emoji = $symbols[$log->reel3]['emoji'] ?? $log->reel3;
+ $net = $log->payout - $log->cost;
+ $rowBg = match ($log->result_type) {
+ 'jackpot' => 'bg-yellow-50',
+ 'triple_gem' => 'bg-blue-50',
+ 'curse' => 'bg-red-50',
+ default => '',
+ };
+ @endphp
+
+ |
+ {{ $log->created_at->format('m-d H:i:s') }}
+ |
+
+ {{ $log->user?->username ?? '已注销' }}
+ |
+
+ {{ $r1Emoji }} {{ $r2Emoji }} {{ $r3Emoji }}
+ |
+
+
+ {{ $resultLabels[$log->result_type]['label'] ?? $log->result_type }}
+
+ |
+
+ -{{ number_format($log->cost) }}
+ |
+
+ {{ $log->payout > 0 ? '+' . number_format($log->payout) : '0' }}
+ |
+
+ {{ $net >= 0 ? '+' : '' }}{{ number_format($net) }}
+ |
+
+ @empty
+
+ | 暂无记录 |
+
+ @endforelse
+
+
+
+ @if ($logs->hasPages())
+
+ {{ $logs->links() }}
+
+ @endif
+
+
+@endsection
diff --git a/routes/web.php b/routes/web.php
index 84f43f9..7203763 100644
--- a/routes/web.php
+++ b/routes/web.php
@@ -392,6 +392,24 @@ Route::middleware(['chat.auth', 'chat.has_position'])->prefix('admin')->name('ad
Route::post('/{gameConfig}/params', [\App\Http\Controllers\Admin\GameConfigController::class, 'updateParams'])->name('params');
});
+ // 📊 游戏历史记录查询(各游戏历史 + 实时统计摘要)
+ Route::prefix('game-history')->name('game-history.')->group(function () {
+ // 各游戏实时统计摘要(JSON 接口,供游戏管理页 AJAX 加载)
+ Route::get('/stats', [\App\Http\Controllers\Admin\GameHistoryController::class, 'stats'])->name('stats');
+ // 百家乐局次历史
+ Route::get('/baccarat', [\App\Http\Controllers\Admin\GameHistoryController::class, 'baccarat'])->name('baccarat');
+ Route::get('/baccarat/{round}', [\App\Http\Controllers\Admin\GameHistoryController::class, 'baccaratRound'])->name('baccarat.round');
+ // 老虎机历史
+ Route::get('/slot', [\App\Http\Controllers\Admin\GameHistoryController::class, 'slot'])->name('slot');
+ // 赛马场次历史
+ Route::get('/horse', [\App\Http\Controllers\Admin\GameHistoryController::class, 'horse'])->name('horse');
+ Route::get('/horse/{race}', [\App\Http\Controllers\Admin\GameHistoryController::class, 'horseRace'])->name('horse.race');
+ // 神秘箱子投放历史
+ Route::get('/mystery-box', [\App\Http\Controllers\Admin\GameHistoryController::class, 'mysteryBox'])->name('mystery-box');
+ // 神秘占卜历史
+ Route::get('/fortune', [\App\Http\Controllers\Admin\GameHistoryController::class, 'fortune'])->name('fortune');
+ });
+
// 📦 神秘箱子:管理员手动投放
Route::post('/mystery-box/drop', [\App\Http\Controllers\Admin\GameConfigController::class, 'dropMysteryBox'])->name('mystery-box.drop');