diff --git a/resources/js/admin/game-configs.js b/resources/js/admin/game-configs.js
new file mode 100644
index 0000000..530d249
--- /dev/null
+++ b/resources/js/admin/game-configs.js
@@ -0,0 +1,253 @@
+// 游戏管理后台事件代理,逐步替代 game-configs Blade 内联脚本。
+
+let adminGameConfigControlsBound = false;
+
+/**
+ * 读取后台 layout 注入的 CSRF token。
+ *
+ * @returns {string}
+ */
+function getCsrfToken() {
+ return document.querySelector('meta[name="csrf-token"]')?.getAttribute("content") || "";
+}
+
+/**
+ * 生成单个统计卡片 HTML。
+ *
+ * @param {{icon:string,title:string,color:string,items:Array<{label:string,value:string|number}>}} card 统计卡片
+ * @returns {string}
+ */
+function renderStatsCard(card) {
+ return `
+
+
+ ${card.icon}
+ ${card.title}
+
+
+ ${card.items.map((item) => `
+
+ ${item.label}
+ ${item.value}
+
+ `).join("")}
+
+
+ `;
+}
+
+/**
+ * 将游戏统计接口响应转换为顶部统计卡片。
+ *
+ * @param {Record>} data 统计接口响应
+ * @returns {string}
+ */
+function renderGameStats(data) {
+ const cards = [
+ {
+ icon: "🎲",
+ title: "百家乐",
+ items: [
+ { label: "总局数", value: data.baccarat.total_rounds.toLocaleString() },
+ { label: "总下注", value: `${data.baccarat.total_bets.toLocaleString()} 笔` },
+ { label: "今日局数", value: data.baccarat.today_rounds.toLocaleString() },
+ ],
+ color: "border-red-200 bg-red-50",
+ },
+ {
+ icon: "🎰",
+ title: "老虎机",
+ items: [
+ { label: "总转动", value: `${data.slot.total_spins.toLocaleString()} 次` },
+ { label: "三7大奖", value: `${data.slot.jackpot_count.toLocaleString()} 次` },
+ { label: "今日转动", value: data.slot.today_spins.toLocaleString() },
+ ],
+ color: "border-amber-200 bg-amber-50",
+ },
+ {
+ icon: "🐎",
+ title: "赛马竞猜",
+ items: [
+ { label: "总场次", value: data.horse.total_races.toLocaleString() },
+ { label: "总注池", value: `${data.horse.total_pool.toLocaleString()} 金` },
+ { label: "今日场次", value: data.horse.today_races.toLocaleString() },
+ ],
+ color: "border-emerald-200 bg-emerald-50",
+ },
+ {
+ icon: "📦",
+ title: "神秘箱子",
+ items: [
+ { label: "总投放", value: data.mystery_box.total_dropped.toLocaleString() },
+ { label: "已领取", value: data.mystery_box.total_claimed.toLocaleString() },
+ { label: "今日投放", value: data.mystery_box.today_dropped.toLocaleString() },
+ ],
+ color: "border-purple-200 bg-purple-50",
+ },
+ {
+ icon: "🔮",
+ title: "神秘占卜",
+ items: [
+ { label: "总占卜", value: `${data.fortune.total_times.toLocaleString()} 次` },
+ { label: "吉签/凶签", value: `${data.fortune.jackpot_count} / ${data.fortune.curse_count}` },
+ { label: "今日占卜", value: data.fortune.today_times.toLocaleString() },
+ ],
+ color: "border-fuchsia-200 bg-fuchsia-50",
+ },
+ {
+ icon: "🎟️",
+ title: "双色球彩票",
+ items: [
+ { label: "总期数", value: `${data.lottery.total_issues.toLocaleString()} 期` },
+ { label: "历史彩票", value: `${data.lottery.total_bets.toLocaleString()} 张` },
+ { label: "累计奖池", value: `${data.lottery.total_pool.toLocaleString()} 金` },
+ ],
+ color: "border-rose-200 bg-rose-50",
+ },
+ {
+ icon: "♟️",
+ title: "五子棋",
+ items: [
+ { label: "总对局", value: `${data.gomoku.total_games.toLocaleString()} 局` },
+ { label: "人机/对战", value: `${data.gomoku.pve_count} / ${data.gomoku.pvp_count}` },
+ { label: "今日对局", value: data.gomoku.today_games.toLocaleString() },
+ ],
+ color: "border-blue-200 bg-blue-50",
+ },
+ ];
+
+ return cards.map((card) => renderStatsCard(card)).join("");
+}
+
+/**
+ * 加载各游戏实时统计摘要并渲染到顶部面板。
+ *
+ * @param {HTMLButtonElement} button 触发按钮
+ * @returns {Promise}
+ */
+async function loadGameStats(button) {
+ const statsUrl = button.getAttribute("data-game-stats-url") || "";
+ const panel = document.getElementById("game-stats-panel");
+ const grid = document.getElementById("game-stats-grid");
+
+ if (!statsUrl || !panel || !grid) {
+ return;
+ }
+
+ grid.innerHTML = '⏳ 加载中...
';
+ panel.classList.remove("hidden");
+
+ try {
+ const response = await fetch(statsUrl, {
+ headers: { "Accept": "application/json" },
+ });
+ const data = await response.json();
+
+ grid.innerHTML = renderGameStats(data);
+ } catch (error) {
+ grid.innerHTML = '❌ 加载失败,请重试
';
+ }
+}
+
+/**
+ * 根据开关接口响应更新游戏卡片状态。
+ *
+ * @param {HTMLButtonElement} button 开关按钮
+ * @param {boolean} enabled 是否启用
+ * @returns {void}
+ */
+function updateGameToggleState(button, enabled) {
+ const gameKey = button.getAttribute("data-game-key") || "";
+ const card = document.getElementById(`game-card-${gameKey}`);
+ const badge = document.getElementById(`badge-${gameKey}`);
+ const header = card?.querySelector(".flex.items-center.justify-between");
+
+ if (badge) {
+ badge.textContent = enabled ? "运行中" : "已关闭";
+ badge.className = `text-xs px-2 py-0.5 rounded-full font-bold ${
+ enabled ? "bg-emerald-100 text-emerald-700" : "bg-gray-200 text-gray-500"
+ }`;
+ }
+
+ button.textContent = enabled ? "⏸ 关闭游戏" : "▶ 开启游戏";
+ button.className = `px-5 py-2 rounded-lg font-bold text-sm transition shadow-sm ${
+ enabled ? "bg-red-500 hover:bg-red-600 text-white" : "bg-emerald-500 hover:bg-emerald-600 text-white"
+ }`;
+
+ // 卡片头部背景是游戏状态的主要视觉反馈,需要和按钮、徽章同步。
+ if (header) {
+ header.classList.toggle("bg-emerald-50", enabled);
+ header.classList.toggle("bg-gray-50", !enabled);
+ }
+}
+
+/**
+ * 切换游戏开启/关闭状态。
+ *
+ * @param {HTMLButtonElement} button 开关按钮
+ * @returns {Promise}
+ */
+async function toggleGame(button) {
+ const toggleUrl = button.getAttribute("data-game-toggle-url") || "";
+
+ if (!toggleUrl || button.disabled) {
+ return;
+ }
+
+ button.disabled = true;
+
+ try {
+ const response = await fetch(toggleUrl, {
+ method: "POST",
+ headers: {
+ "X-CSRF-TOKEN": getCsrfToken(),
+ "Accept": "application/json",
+ },
+ });
+ const data = await response.json();
+
+ if (!data?.ok) {
+ return;
+ }
+
+ updateGameToggleState(button, Boolean(data.enabled));
+ window.adminDialog?.alert(
+ data.message,
+ data.enabled ? "游戏已开启" : "游戏已关闭",
+ data.enabled ? "✅" : "⏸",
+ );
+ } finally {
+ button.disabled = false;
+ }
+}
+
+/**
+ * 绑定游戏管理页通用操作按钮。
+ *
+ * @returns {void}
+ */
+export function bindAdminGameConfigControls() {
+ if (adminGameConfigControlsBound || typeof document === "undefined") {
+ return;
+ }
+
+ adminGameConfigControlsBound = true;
+ document.addEventListener("click", (event) => {
+ if (!(event.target instanceof Element)) {
+ return;
+ }
+
+ const statsButton = event.target.closest("[data-game-stats-url]");
+ if (statsButton instanceof HTMLButtonElement) {
+ event.preventDefault();
+ void loadGameStats(statsButton);
+ return;
+ }
+
+ const toggleButton = event.target.closest("[data-game-toggle-url]");
+ if (toggleButton instanceof HTMLButtonElement) {
+ event.preventDefault();
+ void toggleGame(toggleButton);
+ }
+ });
+}
diff --git a/resources/js/app.js b/resources/js/app.js
index a7fcbdc..506a854 100644
--- a/resources/js/app.js
+++ b/resources/js/app.js
@@ -1,9 +1,11 @@
import './bootstrap';
import { bindAdminAutoactControls } from './admin/autoact.js';
import { bindAdminFishingEventsControls } from './admin/fishing-events.js';
+import { bindAdminGameConfigControls } from './admin/game-configs.js';
import { bindAdminSignInRulesControls } from './admin/sign-in-rules.js';
// 后台共用入口只注册轻量事件代理,具体页面通过 data-* 属性决定是否响应。
bindAdminAutoactControls();
bindAdminFishingEventsControls();
+bindAdminGameConfigControls();
bindAdminSignInRulesControls();
diff --git a/resources/views/admin/game-configs/index.blade.php b/resources/views/admin/game-configs/index.blade.php
index 73a687f..a7ac5ab 100644
--- a/resources/views/admin/game-configs/index.blade.php
+++ b/resources/views/admin/game-configs/index.blade.php
@@ -11,7 +11,7 @@
🎮 游戏管理
统一管理聊天室所有娱乐游戏的开关状态与核心参数,所有游戏默认关闭。
-
@@ -70,7 +70,8 @@
@endif
{{-- 大开关按钮 --}}
-