1121 lines
54 KiB
PHP
Executable File
1121 lines
54 KiB
PHP
Executable File
<h1 class="text-2xl font-bold text-gray-800 mb-6 flex items-center">
|
||
<i class="fas fa-dice text-primary mr-3"></i>
|
||
游戏管理
|
||
</h1>
|
||
|
||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6">
|
||
<div class="bg-white rounded-xl p-5 card-shadow hover-lift">
|
||
<div class="flex items-center justify-between">
|
||
<div>
|
||
<p class="text-gray-500 text-sm">游戏总数</p>
|
||
<h3 class="text-2xl font-bold mt-1">
|
||
<?= isset($games) && is_array($games) ? count($games) : 0 ?>
|
||
</h3>
|
||
</div>
|
||
<div class="w-10 h-10 rounded-full bg-primary/10 flex items-center justify-center">
|
||
<i class="fas fa-dice text-primary"></i>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="bg-white rounded-xl p-5 card-shadow hover-lift">
|
||
<div class="flex items-center justify-between">
|
||
<div>
|
||
<p class="text-gray-500 text-sm">已启用游戏</p>
|
||
<h3 class="text-2xl font-bold mt-1">
|
||
<?php
|
||
$enabledCount = 0;
|
||
if (isset($games) && is_array($games)) {
|
||
foreach ($games as $g) {
|
||
if (!empty($g['status'])) {
|
||
$enabledCount++;
|
||
}
|
||
}
|
||
}
|
||
echo $enabledCount;
|
||
?>
|
||
</h3>
|
||
</div>
|
||
<div class="w-10 h-10 rounded-full bg-success/10 flex items-center justify-center">
|
||
<i class="fas fa-check text-success"></i>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="bg-white rounded-xl p-5 card-shadow hover-lift">
|
||
<div class="flex items-center justify-between">
|
||
<div>
|
||
<p class="text-gray-500 text-sm">未启用游戏</p>
|
||
<h3 class="text-2xl font-bold mt-1">
|
||
<?php
|
||
$disabledCount = 0;
|
||
if (isset($games) && is_array($games)) {
|
||
foreach ($games as $g) {
|
||
if (empty($g['status'])) {
|
||
$disabledCount++;
|
||
}
|
||
}
|
||
}
|
||
echo $disabledCount;
|
||
?>
|
||
</h3>
|
||
</div>
|
||
<div class="w-10 h-10 rounded-full bg-gray-medium/30 flex items-center justify-center">
|
||
<i class="fas fa-times text-gray-medium"></i>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="bg-white rounded-xl shadow-md p-6 mb-8">
|
||
<div class="flex flex-col md:flex-row md:items-center md:justify-between gap-4 mb-6">
|
||
<div>
|
||
<h2 class="text-xl font-semibold text-gray-800">游戏列表</h2>
|
||
<p class="text-sm text-gray-500 mt-1">管理骰子类游戏的基础信息、直播流和启用状态</p>
|
||
</div>
|
||
<div class="flex flex-col sm:flex-row gap-3 w-full md:w-auto">
|
||
<div class="flex-1 relative">
|
||
<input
|
||
type="text"
|
||
id="gameSearchInput"
|
||
class="w-full pl-9 pr-3 py-2 border border-gray-300 rounded-lg text-sm focus:ring-2 focus:ring-primary/50 focus:border-primary"
|
||
placeholder="按游戏名称或标识搜索"
|
||
>
|
||
<span class="absolute inset-y-0 left-3 flex items-center text-gray-400 text-sm">
|
||
<i class="fas fa-search"></i>
|
||
</span>
|
||
</div>
|
||
<select
|
||
id="gameStatusFilter"
|
||
class="sm:w-40 px-3 py-2 border border-gray-300 rounded-lg text-sm focus:ring-2 focus:ring-primary/50 focus:border-primary bg-white"
|
||
>
|
||
<option value="">全部状态</option>
|
||
<option value="1">仅显示启用</option>
|
||
<option value="0">仅显示未启用</option>
|
||
</select>
|
||
<button
|
||
id="openGameFormBtn"
|
||
type="button"
|
||
class="sm:w-auto bg-primary hover:bg-primary/90 text-white px-5 py-2.5 rounded-lg shadow hover:shadow-md transition-all duration-200 flex items-center justify-center text-sm"
|
||
>
|
||
<i class="fas fa-plus mr-2"></i>
|
||
<span>新增游戏</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="overflow-x-auto">
|
||
<table class="w-full bg-white rounded-xl overflow-hidden">
|
||
<thead class="bg-gray-50">
|
||
<tr>
|
||
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">游戏信息</th>
|
||
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">直播流地址</th>
|
||
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider hidden lg:table-cell">类型与玩法</th>
|
||
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider hidden md:table-cell">最近更新</th>
|
||
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">状态</th>
|
||
<th class="px-4 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">操作</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody class="divide-y divide-gray-200" id="gameList">
|
||
<?php if (!empty($games) && is_array($games)): ?>
|
||
<?php foreach ($games as $game): ?>
|
||
<tr class="hover:bg-gray-50 transition-colors" data-id="<?= htmlspecialchars((string)($game['id'] ?? '')) ?>">
|
||
<td class="px-4 py-4 align-top">
|
||
<div class="flex items-start gap-3">
|
||
<div class="w-10 h-10 rounded-lg bg-primary/10 flex items-center justify-center flex-shrink-0">
|
||
<i class="fas fa-dice text-primary"></i>
|
||
</div>
|
||
<div class="min-w-0 flex-1">
|
||
<div class="flex items-center gap-2">
|
||
<span class="text-sm font-semibold text-gray-900 truncate">
|
||
<?= htmlspecialchars((string)($game['name'] ?? '未命名游戏')) ?>
|
||
</span>
|
||
<?php if (!empty($game['code'])): ?>
|
||
<span class="inline-flex items-center px-2 py-0.5 rounded-full text-[11px] bg-gray-100 text-gray-600">
|
||
<?= htmlspecialchars((string)$game['code']) ?>
|
||
</span>
|
||
<?php endif; ?>
|
||
</div>
|
||
<?php if (!empty($game['description'])): ?>
|
||
<p class="mt-1 text-xs text-gray-500 line-clamp-2">
|
||
<?= htmlspecialchars((string)$game['description']) ?>
|
||
</p>
|
||
<?php else: ?>
|
||
<p class="mt-1 text-xs text-gray-400">
|
||
暂无描述
|
||
</p>
|
||
<?php endif; ?>
|
||
</div>
|
||
</div>
|
||
</td>
|
||
<td class="px-4 py-4 align-top">
|
||
<?php if (!empty($game['stream_url'])): ?>
|
||
<div class="max-w-xs">
|
||
<p class="text-xs text-gray-500 break-all">
|
||
<?= htmlspecialchars((string)$game['stream_url']) ?>
|
||
</p>
|
||
<p class="mt-1 text-[11px] text-gray-400">
|
||
建议使用稳定的直播推流地址
|
||
</p>
|
||
</div>
|
||
<?php else: ?>
|
||
<span class="inline-flex items-center px-2 py-1 rounded-full text-[11px] bg-warning/10 text-warning">
|
||
<i class="fas fa-exclamation-triangle mr-1"></i>
|
||
未配置
|
||
</span>
|
||
<?php endif; ?>
|
||
</td>
|
||
<td class="px-4 py-4 align-top hidden lg:table-cell">
|
||
<div class="space-y-1 text-xs text-gray-600">
|
||
<div>
|
||
<span class="text-gray-500">类型:</span>
|
||
<span><?= htmlspecialchars((string)($game['type'] ?? '骰子游戏')) ?></span>
|
||
</div>
|
||
<div class="flex flex-wrap gap-1 mt-1">
|
||
<?php
|
||
$tags = $game['tags'] ?? null;
|
||
if (is_string($tags)) {
|
||
$tags = explode(',', $tags);
|
||
}
|
||
if (is_array($tags) && count($tags) > 0):
|
||
foreach ($tags as $tag):
|
||
?>
|
||
<span class="px-2 py-0.5 rounded-full bg-gray-100 text-gray-600 text-[11px]">
|
||
<?= htmlspecialchars(trim((string)$tag)) ?>
|
||
</span>
|
||
<?php endforeach; ?>
|
||
<?php else: ?>
|
||
<span class="text-gray-400">未配置玩法标签</span>
|
||
<?php endif; ?>
|
||
</div>
|
||
</div>
|
||
</td>
|
||
<td class="px-4 py-4 align-top hidden md:table-cell">
|
||
<?php if (!empty($game['updated_at'])): ?>
|
||
<div class="text-xs text-gray-500">
|
||
<?= date('Y-m-d H:i', strtotime((string)$game['updated_at'])) ?>
|
||
</div>
|
||
<?php elseif (!empty($game['created_at'])): ?>
|
||
<div class="text-xs text-gray-500">
|
||
创建于 <?= date('Y-m-d H:i', strtotime((string)$game['created_at'])) ?>
|
||
</div>
|
||
<?php else: ?>
|
||
<span class="text-xs text-gray-400">时间未知</span>
|
||
<?php endif; ?>
|
||
</td>
|
||
<td class="px-4 py-4 align-top">
|
||
<?php
|
||
$status = !empty($game['status']);
|
||
$statusClass = $status ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800';
|
||
$statusText = $status ? '启用' : '停用';
|
||
?>
|
||
<span class="inline-flex items-center px-2 py-1 rounded-full text-xs <?= $statusClass; ?>">
|
||
<span class="w-2 h-2 rounded-full mr-1 <?= $status ? 'bg-green-500' : 'bg-gray-400'; ?>"></span>
|
||
<?= $statusText; ?>
|
||
</span>
|
||
</td>
|
||
<td class="px-4 py-4 align-top text-right text-sm font-medium">
|
||
<div class="flex items-center justify-end gap-2">
|
||
<button
|
||
type="button"
|
||
class="game-edit-btn text-gray-500 hover:text-blue-500"
|
||
data-id="<?= htmlspecialchars((string)($game['id'] ?? '')) ?>"
|
||
>
|
||
<i class="fas fa-edit"></i>
|
||
</button>
|
||
<button
|
||
type="button"
|
||
class="game-odds-btn text-gray-500 hover:text-purple-500 hidden sm:inline-flex"
|
||
data-id="<?= htmlspecialchars((string)($game['id'] ?? '')) ?>"
|
||
>
|
||
<i class="fas fa-percentage"></i>
|
||
</button>
|
||
<button
|
||
type="button"
|
||
class="game-toggle-status-btn text-gray-500 hover:text-yellow-500"
|
||
data-id="<?= htmlspecialchars((string)($game['id'] ?? '')) ?>"
|
||
>
|
||
<i class="fas fa-power-off"></i>
|
||
</button>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
<?php endforeach; ?>
|
||
<?php else: ?>
|
||
<tr>
|
||
<td colspan="6" class="px-6 py-12 text-center">
|
||
<div class="flex flex-col items-center">
|
||
<i class="fas fa-dice text-gray-300 text-5xl mb-4"></i>
|
||
<h3 class="text-lg font-medium text-gray-900">暂无游戏配置</h3>
|
||
<p class="mt-1 text-gray-500 text-sm">
|
||
当前还没有配置任何游戏,可以点击“新增游戏”进行配置。
|
||
</p>
|
||
<button
|
||
type="button"
|
||
class="mt-4 bg-primary hover:bg-primary/90 text-white px-5 py-2 rounded-lg shadow hover:shadow-md transition-all duration-200 flex items-center text-sm"
|
||
onclick="document.getElementById('openGameFormBtn').click();"
|
||
>
|
||
<i class="fas fa-plus mr-2"></i>
|
||
<span>新增游戏</span>
|
||
</button>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
<?php endif; ?>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<div
|
||
id="gameFormBackdrop"
|
||
class="fixed inset-0 bg-black/50 backdrop-blur-sm opacity-0 pointer-events-none transition-opacity duration-300 z-40"
|
||
></div>
|
||
|
||
<div
|
||
id="gameFormModal"
|
||
class="fixed inset-0 z-50 flex items-center justify-center p-4 invisible pointer-events-none transition-all duration-300 scale-95"
|
||
>
|
||
<div class="bg-white rounded-xl shadow-xl w-full max-w-xl max-h-[90vh] overflow-hidden">
|
||
<div class="border-b border-gray-100 px-6 py-4 flex justify-between items-center">
|
||
<h3 id="gameFormTitle" class="text-xl font-bold text-gray-800 flex items-center">
|
||
<i class="fas fa-dice text-primary mr-2"></i>
|
||
配置游戏
|
||
</h3>
|
||
<button id="closeGameFormBtn" class="text-gray-400 hover:text-gray-600 transition-colors p-1">
|
||
<i class="fas fa-times"></i>
|
||
</button>
|
||
</div>
|
||
|
||
<div class="px-6 py-5 overflow-y-auto max-h-[calc(90vh-130px)]">
|
||
<form id="gameForm" class="space-y-5">
|
||
<input type="hidden" id="gameId" name="id">
|
||
|
||
<div>
|
||
<label for="gameName" class="block text-sm font-medium text-gray-700 mb-1">
|
||
游戏名称 <span class="text-red-500">*</span>
|
||
</label>
|
||
<input
|
||
type="text"
|
||
id="gameName"
|
||
name="name"
|
||
required
|
||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary/50 focus:border-primary text-sm"
|
||
placeholder="例如:Tài Xỉu"
|
||
>
|
||
<input type="hidden" id="gameCode" name="code">
|
||
</div>
|
||
|
||
<div>
|
||
<label for="gameStreamUrl" class="block text-sm font-medium text-gray-700 mb-1">
|
||
直播流地址
|
||
</label>
|
||
<input
|
||
type="text"
|
||
id="gameStreamUrl"
|
||
name="stream_url"
|
||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary/50 focus:border-primary text-sm"
|
||
placeholder="输入直播推流地址或播放地址"
|
||
>
|
||
</div>
|
||
|
||
<div>
|
||
<label class="block text-sm font-medium text-gray-700 mb-1">
|
||
游戏封面图片
|
||
</label>
|
||
<div class="flex items-center gap-3">
|
||
<div class="flex-1">
|
||
<input
|
||
type="text"
|
||
id="gameImage"
|
||
name="image"
|
||
readonly
|
||
class="w-full px-4 py-2 border border-gray-300 rounded-lg bg-gray-50 text-sm"
|
||
placeholder="点击右侧按钮选择图片"
|
||
>
|
||
</div>
|
||
<button
|
||
type="button"
|
||
onclick="OpenGallery('gameImage', 'gameImagePreview')"
|
||
class="px-4 py-2 bg-primary text-white rounded-lg hover:bg-primary/90 transition-colors text-sm whitespace-nowrap"
|
||
>
|
||
<i class="fas fa-image mr-2"></i>选择图片
|
||
</button>
|
||
</div>
|
||
<div id="gameImagePreview" class="mt-2" style="display: none;">
|
||
<img src="" alt="预览图" class="max-w-xs h-32 object-cover rounded-lg border border-gray-200">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
<div>
|
||
<label for="gameType" class="block text-sm font-medium text-gray-700 mb-1">
|
||
游戏类型
|
||
</label>
|
||
<select
|
||
id="gameType"
|
||
name="type"
|
||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary/50 focus:border-primary text-sm bg-white"
|
||
>
|
||
<option value="dice">骰子游戏</option>
|
||
<option value="xocdia">Xóc Đĩa(色碟)</option>
|
||
<option value="other">其他</option>
|
||
</select>
|
||
</div>
|
||
<div>
|
||
<label for="gameSortOrder" class="block text-sm font-medium text-gray-700 mb-1">
|
||
排序权重
|
||
</label>
|
||
<input
|
||
type="number"
|
||
id="gameSortOrder"
|
||
name="sort_order"
|
||
value="0"
|
||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary/50 focus:border-primary text-sm"
|
||
>
|
||
<p class="mt-1 text-[11px] text-gray-400">数字越大越靠前,默认为 0。</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div>
|
||
<span class="block text-sm font-medium text-gray-700 mb-2">
|
||
支持玩法标签
|
||
</span>
|
||
<div class="grid grid-cols-2 md:grid-cols-3 gap-2 text-sm">
|
||
<!-- 骰子游戏标签 -->
|
||
<label class="inline-flex items-center">
|
||
<input
|
||
type="checkbox"
|
||
name="tags[]"
|
||
value="大小"
|
||
class="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary"
|
||
>
|
||
<span class="ml-2 text-gray-700">大小</span>
|
||
</label>
|
||
<label class="inline-flex items-center">
|
||
<input
|
||
type="checkbox"
|
||
name="tags[]"
|
||
value="单双"
|
||
class="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary"
|
||
>
|
||
<span class="ml-2 text-gray-700">单双</span>
|
||
</label>
|
||
<label class="inline-flex items-center">
|
||
<input
|
||
type="checkbox"
|
||
name="tags[]"
|
||
value="总点数"
|
||
class="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary"
|
||
>
|
||
<span class="ml-2 text-gray-700">总点数</span>
|
||
</label>
|
||
<label class="inline-flex items-center">
|
||
<input
|
||
type="checkbox"
|
||
name="tags[]"
|
||
value="三同号"
|
||
class="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary"
|
||
>
|
||
<span class="ml-2 text-gray-700">三同号</span>
|
||
</label>
|
||
<label class="inline-flex items-center">
|
||
<input
|
||
type="checkbox"
|
||
name="tags[]"
|
||
value="两同号"
|
||
class="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary"
|
||
>
|
||
<span class="ml-2 text-gray-700">两同号</span>
|
||
</label>
|
||
<!-- Xóc Đĩa 标签 -->
|
||
<label class="inline-flex items-center">
|
||
<input
|
||
type="checkbox"
|
||
name="tags[]"
|
||
value="traditional"
|
||
class="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary"
|
||
>
|
||
<span class="ml-2 text-gray-700">传统玩法</span>
|
||
</label>
|
||
<label class="inline-flex items-center">
|
||
<input
|
||
type="checkbox"
|
||
name="tags[]"
|
||
value="hot"
|
||
class="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary"
|
||
>
|
||
<span class="ml-2 text-gray-700">热门</span>
|
||
</label>
|
||
<label class="inline-flex items-center">
|
||
<input
|
||
type="checkbox"
|
||
name="tags[]"
|
||
value="其他"
|
||
class="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary"
|
||
>
|
||
<span class="ml-2 text-gray-700">其他</span>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 状态和推荐选项(默认启用并显示在游戏大厅) -->
|
||
<input type="hidden" id="gameStatus" name="status" value="1">
|
||
<input type="hidden" id="gameFeatured" name="featured" value="1">
|
||
</form>
|
||
</div>
|
||
|
||
<div class="border-t border-gray-100 px-6 py-4 flex justify-end gap-3">
|
||
<button
|
||
id="cancelGameFormBtn"
|
||
type="button"
|
||
class="px-5 py-2 border border-gray-300 rounded-lg text-gray-700 hover:bg-gray-50 text-sm"
|
||
>
|
||
取消
|
||
</button>
|
||
<button
|
||
id="submitGameFormBtn"
|
||
type="button"
|
||
class="bg-primary hover:bg-primary/90 text-white px-5 py-2 rounded-lg shadow hover:shadow-md transition-all duration-200 text-sm"
|
||
>
|
||
保存游戏
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div
|
||
id="oddsFormModal"
|
||
class="fixed inset-0 z-50 flex items-center justify-center p-4 invisible pointer-events-none transition-all duration-300 scale-95"
|
||
>
|
||
<div class="bg-white rounded-xl shadow-xl w-full max-w-5xl max-h-[90vh] overflow-hidden flex flex-col">
|
||
<div class="border-b border-gray-100 px-6 py-4 flex justify-between items-center flex-shrink-0">
|
||
<h3 id="oddsFormTitle" class="text-xl font-bold text-gray-800 flex items-center">
|
||
<i class="fas fa-percentage text-purple-500 mr-2"></i>
|
||
配置赔率
|
||
</h3>
|
||
<button id="closeOddsFormBtn" class="text-gray-400 hover:text-gray-600 transition-colors p-1">
|
||
<i class="fas fa-times"></i>
|
||
</button>
|
||
</div>
|
||
|
||
<div class="px-6 py-5 overflow-y-auto flex-1 bg-gray-50/50">
|
||
<form id="oddsForm" class="space-y-6">
|
||
<input type="hidden" id="oddsGameId" name="game_id">
|
||
|
||
<div class="bg-blue-50 border-l-4 border-blue-500 p-4 mb-4 rounded-r">
|
||
<div class="flex">
|
||
<div class="flex-shrink-0">
|
||
<i class="fas fa-info-circle text-blue-500"></i>
|
||
</div>
|
||
<div class="ml-3">
|
||
<p class="text-sm text-blue-700">
|
||
<b>赔率说明:</b>输入的数字 = 玩家赢了能赚多少倍。
|
||
<br>
|
||
例如:赔率 <b>0.97</b> → 玩家下注100中奖后,赚97(拿回100+97=197)
|
||
<br>
|
||
例如:赔率 <b>30</b> → 玩家下注100中奖后,赚3000(拿回100+3000=3100)
|
||
<br>
|
||
<span class="text-blue-500">赔率越高,玩家赢得越多,平台风险越大。</span>
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 赔率配置区域 -->
|
||
<div id="oddsContainer" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
|
||
<!-- 动态生成 -->
|
||
</div>
|
||
</form>
|
||
</div>
|
||
|
||
<div class="border-t border-gray-100 px-6 py-4 flex justify-end gap-3 flex-shrink-0 bg-white">
|
||
<button
|
||
id="cancelOddsFormBtn"
|
||
type="button"
|
||
class="px-5 py-2 border border-gray-300 rounded-lg text-gray-700 hover:bg-gray-50 text-sm"
|
||
>
|
||
取消
|
||
</button>
|
||
<button
|
||
id="submitOddsFormBtn"
|
||
type="button"
|
||
class="bg-purple-600 hover:bg-purple-700 text-white px-5 py-2 rounded-lg shadow hover:shadow-md transition-all duration-200 text-sm font-medium"
|
||
>
|
||
<i class="fas fa-save mr-2"></i>保存赔率配置
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
// 缓存DOM元素
|
||
const gameFormModal = document.getElementById('gameFormModal');
|
||
const gameFormBackdrop = document.getElementById('gameFormBackdrop');
|
||
const openGameFormBtn = document.getElementById('openGameFormBtn');
|
||
const closeGameFormBtn = document.getElementById('closeGameFormBtn');
|
||
const cancelGameFormBtn = document.getElementById('cancelGameFormBtn');
|
||
const submitGameFormBtn = document.getElementById('submitGameFormBtn');
|
||
const gameFormTitle = document.getElementById('gameFormTitle');
|
||
const gameForm = document.getElementById('gameForm');
|
||
const gameList = document.getElementById('gameList');
|
||
|
||
// 检查元素是否存在
|
||
function checkElements() {
|
||
const elements = [
|
||
gameFormModal, gameFormBackdrop, openGameFormBtn,
|
||
closeGameFormBtn, cancelGameFormBtn, submitGameFormBtn
|
||
];
|
||
|
||
const missing = elements.filter(el => !el);
|
||
if (missing.length > 0) {
|
||
console.error('缺少必要的DOM元素,功能无法正常工作');
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
// 显示表单弹窗
|
||
function openGameFormModal() {
|
||
if (!checkElements()) return;
|
||
|
||
resetGameForm();
|
||
gameFormModal.classList.remove('invisible', 'pointer-events-none', 'scale-95');
|
||
gameFormModal.classList.add('scale-100');
|
||
gameFormBackdrop.classList.remove('opacity-0', 'pointer-events-none');
|
||
document.body.style.overflow = 'hidden';
|
||
void gameFormModal.offsetWidth; // 强制重绘
|
||
}
|
||
|
||
// 隐藏表单弹窗
|
||
function closeGameFormModal() {
|
||
if (!checkElements()) return;
|
||
|
||
gameFormModal.classList.add('invisible', 'pointer-events-none', 'scale-95');
|
||
gameFormModal.classList.remove('scale-100');
|
||
gameFormBackdrop.classList.add('opacity-0', 'pointer-events-none');
|
||
document.body.style.overflow = '';
|
||
}
|
||
|
||
// 重置表单(新增模式)
|
||
function resetGameForm() {
|
||
gameForm.reset();
|
||
document.getElementById('gameId').value = '';
|
||
document.getElementById('gameCode').value = '';
|
||
document.getElementById('gameStatus').value = '1';
|
||
document.getElementById('gameFeatured').value = '1';
|
||
document.getElementById('gameImagePreview').style.display = 'none';
|
||
gameFormTitle.innerHTML = '<i class="fas fa-dice text-primary mr-2"></i> 配置游戏';
|
||
submitGameFormBtn.innerHTML = '保存游戏';
|
||
submitGameFormBtn.disabled = false;
|
||
}
|
||
|
||
// 加载游戏数据(编辑模式)
|
||
async function loadGameData(id) {
|
||
submitGameFormBtn.disabled = true;
|
||
submitGameFormBtn.innerHTML = '<i class="fa fa-spinner fa-spin mr-2"></i> 加载中...';
|
||
|
||
try {
|
||
const response = await fetch(`/admin/games/${id}`);
|
||
if (!response.ok) throw new Error('获取数据失败');
|
||
const data = await response.json();
|
||
|
||
if (data.success && data.data) {
|
||
const game = data.data;
|
||
document.getElementById('gameId').value = game.id || '';
|
||
document.getElementById('gameName').value = game.name || '';
|
||
document.getElementById('gameCode').value = game.code || '';
|
||
document.getElementById('gameStreamUrl').value = game.stream_url || '';
|
||
document.getElementById('gameType').value = game.type || 'dice';
|
||
document.getElementById('gameSortOrder').value = game.sort_order || 0;
|
||
document.getElementById('gameStatus').value = game.status == 1 ? '1' : '0';
|
||
document.getElementById('gameFeatured').value = game.featured == 1 ? '1' : '0';
|
||
|
||
// 处理图片
|
||
if (game.image) {
|
||
document.getElementById('gameImage').value = game.image;
|
||
const previewImg = document.querySelector('#gameImagePreview img');
|
||
if (previewImg) {
|
||
previewImg.src = game.image;
|
||
document.getElementById('gameImagePreview').style.display = 'block';
|
||
}
|
||
} else {
|
||
document.getElementById('gameImage').value = '';
|
||
document.getElementById('gameImagePreview').style.display = 'none';
|
||
}
|
||
|
||
// 处理标签复选框
|
||
const tags = game.tags ? game.tags.split(',') : [];
|
||
document.querySelectorAll('input[name="tags[]"]').forEach(checkbox => {
|
||
checkbox.checked = tags.includes(checkbox.value);
|
||
});
|
||
|
||
gameFormTitle.innerHTML = '<i class="fas fa-edit text-primary mr-2"></i> 编辑游戏';
|
||
} else {
|
||
throw new Error(data.message || '获取数据失败');
|
||
}
|
||
} catch (e) {
|
||
showMessage(e.message, 'error');
|
||
closeGameFormModal();
|
||
} finally {
|
||
submitGameFormBtn.disabled = false;
|
||
submitGameFormBtn.innerHTML = '保存游戏';
|
||
}
|
||
}
|
||
|
||
// 表单验证
|
||
function validateGameForm() {
|
||
const name = document.getElementById('gameName').value.trim();
|
||
|
||
if (!name) {
|
||
showMessage('请输入游戏名称', 'error');
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
// 提交表单(创建/更新)
|
||
async function submitGameFormData() {
|
||
if (!validateGameForm()) return;
|
||
|
||
const formData = new FormData(gameForm);
|
||
const isEditMode = !!document.getElementById('gameId').value;
|
||
|
||
// status和featured已经是隐藏字段,保持默认值1即可
|
||
|
||
submitGameFormBtn.disabled = true;
|
||
submitGameFormBtn.innerHTML = '<i class="fa fa-spinner fa-spin mr-2"></i> 保存中...';
|
||
|
||
try {
|
||
const response = await fetch('/admin/games/update', {
|
||
method: 'POST',
|
||
body: formData,
|
||
headers: { 'X-Requested-With': 'XMLHttpRequest' }
|
||
});
|
||
|
||
const data = await response.json();
|
||
if (data.success) {
|
||
showMessage(isEditMode ? '游戏更新成功' : '游戏创建成功');
|
||
closeGameFormModal();
|
||
setTimeout(() => location.reload(), 1000);
|
||
} else {
|
||
throw new Error(data.message || (isEditMode ? '更新失败' : '创建失败'));
|
||
}
|
||
} catch (e) {
|
||
showMessage(e.message, 'error');
|
||
} finally {
|
||
submitGameFormBtn.disabled = false;
|
||
submitGameFormBtn.innerHTML = '保存游戏';
|
||
}
|
||
}
|
||
|
||
// 删除游戏
|
||
async function deleteGame(id) {
|
||
if (!confirm('确定要删除该游戏吗?此操作不可恢复!')) return;
|
||
|
||
try {
|
||
const response = await fetch(`/admin/games/delete/${id}`, {
|
||
method: 'POST',
|
||
headers: {
|
||
'X-Requested-With': 'XMLHttpRequest',
|
||
'Content-Type': 'application/json'
|
||
}
|
||
});
|
||
const data = await response.json();
|
||
if (data.success) {
|
||
showMessage('游戏已删除');
|
||
setTimeout(() => location.reload(), 500);
|
||
} else {
|
||
throw new Error(data.message || '删除失败');
|
||
}
|
||
} catch (e) {
|
||
showMessage(e.message, 'error');
|
||
}
|
||
}
|
||
|
||
// 切换游戏状态
|
||
async function toggleGameStatus(id) {
|
||
try {
|
||
const response = await fetch(`/admin/games/toggle/${id}`, {
|
||
method: 'POST',
|
||
headers: {
|
||
'X-Requested-With': 'XMLHttpRequest',
|
||
'Content-Type': 'application/json'
|
||
}
|
||
});
|
||
const data = await response.json();
|
||
if (data.success) {
|
||
showMessage(data.message);
|
||
setTimeout(() => location.reload(), 500);
|
||
} else {
|
||
throw new Error(data.message || '操作失败');
|
||
}
|
||
} catch (e) {
|
||
showMessage(e.message, 'error');
|
||
}
|
||
}
|
||
|
||
// 绑定事件
|
||
if (checkElements()) {
|
||
// 打开表单
|
||
openGameFormBtn.addEventListener('click', openGameFormModal);
|
||
|
||
// 关闭表单
|
||
closeGameFormBtn.addEventListener('click', closeGameFormModal);
|
||
cancelGameFormBtn.addEventListener('click', closeGameFormModal);
|
||
gameFormBackdrop.addEventListener('click', () => {
|
||
if (!gameFormModal.classList.contains('invisible')) closeGameFormModal();
|
||
});
|
||
|
||
// 提交表单
|
||
submitGameFormBtn.addEventListener('click', submitGameFormData);
|
||
|
||
// 编辑、删除、切换状态事件委托
|
||
if (gameList) {
|
||
gameList.addEventListener('click', function(e) {
|
||
const editBtn = e.target.closest('.game-edit-btn');
|
||
const deleteBtn = e.target.closest('.game-delete-btn');
|
||
const toggleBtn = e.target.closest('.game-toggle-status-btn');
|
||
|
||
const oddsBtn = e.target.closest('.game-odds-btn');
|
||
|
||
if (editBtn) {
|
||
const id = editBtn.getAttribute('data-id');
|
||
if (id) {
|
||
openGameFormModal();
|
||
setTimeout(() => loadGameData(id), 300);
|
||
}
|
||
} else if (oddsBtn) {
|
||
const id = oddsBtn.getAttribute('data-id');
|
||
if (id) {
|
||
openOddsFormModal();
|
||
loadOddsData(id);
|
||
}
|
||
} else if (deleteBtn) {
|
||
const id = deleteBtn.getAttribute('data-id');
|
||
if (id) deleteGame(id);
|
||
} else if (toggleBtn) {
|
||
const id = toggleBtn.getAttribute('data-id');
|
||
if (id) toggleGameStatus(id);
|
||
}
|
||
});
|
||
}
|
||
|
||
// ESC键关闭弹窗
|
||
document.addEventListener('keydown', e => {
|
||
if (e.key === 'Escape') {
|
||
if (!gameFormModal.classList.contains('invisible')) closeGameFormModal();
|
||
}
|
||
});
|
||
|
||
// ================= 赔率配置功能 =================
|
||
const oddsFormModal = document.getElementById('oddsFormModal');
|
||
const closeOddsFormBtn = document.getElementById('closeOddsFormBtn');
|
||
const cancelOddsFormBtn = document.getElementById('cancelOddsFormBtn');
|
||
const submitOddsFormBtn = document.getElementById('submitOddsFormBtn');
|
||
const oddsForm = document.getElementById('oddsForm');
|
||
const oddsContainer = document.getElementById('oddsContainer');
|
||
const oddsFormTitle = document.getElementById('oddsFormTitle');
|
||
// gameFormBackdrop is already defined
|
||
|
||
function openOddsFormModal() {
|
||
if (!oddsFormModal) return;
|
||
oddsFormModal.classList.remove('invisible', 'pointer-events-none', 'scale-95');
|
||
oddsFormModal.classList.add('scale-100');
|
||
gameFormBackdrop.classList.remove('opacity-0', 'pointer-events-none');
|
||
document.body.style.overflow = 'hidden';
|
||
}
|
||
|
||
function closeOddsFormModal() {
|
||
if (!oddsFormModal) return;
|
||
oddsFormModal.classList.add('invisible', 'pointer-events-none', 'scale-95');
|
||
oddsFormModal.classList.remove('scale-100');
|
||
|
||
// Only hide backdrop if gameFormModal is also closed
|
||
if (gameFormModal && gameFormModal.classList.contains('invisible')) {
|
||
gameFormBackdrop.classList.add('opacity-0', 'pointer-events-none');
|
||
document.body.style.overflow = '';
|
||
}
|
||
}
|
||
|
||
async function loadOddsData(gameId) {
|
||
document.getElementById('oddsGameId').value = gameId;
|
||
oddsContainer.innerHTML = '<div class="col-span-full text-center py-10"><i class="fas fa-spinner fa-spin text-3xl text-gray-300"></i><p class="mt-2 text-gray-500">加载赔率配置...</p></div>';
|
||
|
||
try {
|
||
const response = await fetch(`/admin/games/odds/${gameId}`);
|
||
const json = await response.json();
|
||
|
||
if (json.success) {
|
||
renderOddsForm(json.data.odds);
|
||
const gameName = json.data.game ? json.data.game.name : '';
|
||
oddsFormTitle.innerHTML = `<i class="fas fa-percentage text-purple-500 mr-2"></i> 配置赔率 ${gameName ? '- ' + gameName : ''}`;
|
||
} else {
|
||
showMessage(json.message, 'error');
|
||
closeOddsFormModal();
|
||
}
|
||
} catch (e) {
|
||
showMessage('加载失败: ' + e.message, 'error');
|
||
closeOddsFormModal();
|
||
}
|
||
}
|
||
|
||
function renderOddsForm(oddsList) {
|
||
oddsContainer.innerHTML = '';
|
||
|
||
// ========== 分组定义 ==========
|
||
const groups = {
|
||
// PK10 分组
|
||
'pk10_rank': { title: '🏎️ PK10 名次(猜第N名是几号车)', icon: 'fa-flag-checkered', items: [], order: 1 },
|
||
'pk10_bs': { title: '🔢 PK10 大小(车号≥6大 ≤5小)', icon: 'fa-arrows-alt-v', items: [], order: 2 },
|
||
'pk10_oe': { title: '🎯 PK10 单双(车号的奇偶)', icon: 'fa-adjust', items: [], order: 3 },
|
||
'pk10_dt': { title: '🐉 PK10 龙虎(前名次vs后名次比大小)', icon: 'fa-dragon', items: [], order: 4 },
|
||
'pk10_sum': { title: '➕ PK10 冠亚和值(冠军+亚军车号之和)', icon: 'fa-plus-circle', items: [], order: 5 },
|
||
'pk10_sum_bs': { title: '📊 PK10 冠亚和大小单双', icon: 'fa-chart-bar', items: [], order: 6 },
|
||
// 骰子分组
|
||
'dice_basic': { title: '🎲 骰子 大小/单双', icon: 'fa-balance-scale', items: [], order: 10 },
|
||
'dice_sum': { title: '🔢 骰子 点数竞猜(4-17点)', icon: 'fa-sort-numeric-up', items: [], order: 11 },
|
||
'dice_single': { title: '🎯 骰子 单骰点数', icon: 'fa-dice-one', items: [], order: 12 },
|
||
'dice_combo': { title: '💎 骰子 豹子(三颗相同)', icon: 'fa-cubes', items: [], order: 13 },
|
||
// Xóc Đĩa 分组
|
||
'xd_basic': { title: '🪙 色碟 基础玩法', icon: 'fa-circle', items: [], order: 20 },
|
||
'xd_special': { title: '🪙 色碟 特殊组合', icon: 'fa-star', items: [], order: 21 },
|
||
// 兜底
|
||
'other': { title: '⚙️ 其他', icon: 'fa-cog', items: [], order: 99 }
|
||
};
|
||
|
||
// ========== PK10 target 中文翻译 ==========
|
||
const rankNames = {1:'冠军',2:'亚军',3:'第3名',4:'第4名',5:'第5名',6:'第6名',7:'第7名',8:'第8名',9:'第9名',10:'第10名'};
|
||
const dtPairs = {1:[1,10],2:[2,9],3:[3,8],4:[4,7],5:[5,6]};
|
||
|
||
function getPK10Label(type, target) {
|
||
let m;
|
||
if (type === 'rank') {
|
||
m = target.match(/^rank(\d+)_(\d+)$/);
|
||
if (m) return (rankNames[+m[1]]||'第'+m[1]+'名') + ' ' + m[2] + '号车';
|
||
return target;
|
||
}
|
||
if (type === 'bs') {
|
||
m = target.match(/^rank(\d+)_(big|small)$/);
|
||
if (m) return (rankNames[+m[1]]||'第'+m[1]+'名') + ' ' + (m[2]==='big'?'大':'小');
|
||
return target;
|
||
}
|
||
if (type === 'oe') {
|
||
m = target.match(/^rank(\d+)_(odd|even)$/);
|
||
if (m) return (rankNames[+m[1]]||'第'+m[1]+'名') + ' ' + (m[2]==='odd'?'单':'双');
|
||
return target;
|
||
}
|
||
if (type === 'dt') {
|
||
m = target.match(/^dt(\d+)_(dragon|tiger)$/);
|
||
if (m) {
|
||
const p = dtPairs[+m[1]] || [m[1], 11-m[1]];
|
||
return '第' + p[0] + 'vs第' + p[1] + ' ' + (m[2]==='dragon'?'龙':'虎');
|
||
}
|
||
return target;
|
||
}
|
||
if (type === 'sum') {
|
||
m = target.match(/^sum_(\d+)$/);
|
||
if (m) return '和值 ' + m[1];
|
||
return target;
|
||
}
|
||
if (type === 'sum_bs') {
|
||
const sumMap = {sum_big:'和大',sum_small:'和小',sum_odd:'和单',sum_even:'和双'};
|
||
return sumMap[target] || target;
|
||
}
|
||
return target;
|
||
}
|
||
|
||
// ========== 分类逻辑 ==========
|
||
oddsList.forEach(item => {
|
||
const t = item.type;
|
||
let groupKey = 'other';
|
||
// PK10 类型
|
||
if (t === 'rank') groupKey = 'pk10_rank';
|
||
else if (t === 'bs') groupKey = 'pk10_bs';
|
||
else if (t === 'oe') groupKey = 'pk10_oe';
|
||
else if (t === 'dt') groupKey = 'pk10_dt';
|
||
else if (t === 'sum' && item.target && item.target.startsWith('sum_')) groupKey = 'pk10_sum';
|
||
else if (t === 'sum_bs') groupKey = 'pk10_sum_bs';
|
||
// 骰子类型
|
||
else if (['tai', 'xiu', 'chan', 'le'].includes(t)) groupKey = 'dice_basic';
|
||
else if (t === 'sum' || t === 'number') groupKey = 'dice_sum';
|
||
else if (t === 'dice') groupKey = 'dice_single';
|
||
else if (t === 'combo') groupKey = 'dice_combo';
|
||
// Xóc Đĩa 类型
|
||
else if (['even', 'odd', 'big_small', 'odd_even'].includes(t)) groupKey = 'xd_basic';
|
||
else if (['4red', '4white'].includes(t)) groupKey = 'xd_special';
|
||
|
||
if (!groups[groupKey]) groups[groupKey] = { title: '其他', icon: 'fa-cog', items: [], order: 99 };
|
||
groups[groupKey].items.push(item);
|
||
});
|
||
|
||
// ========== 标签翻译 ==========
|
||
function getLabel(item) {
|
||
const t = item.type;
|
||
const tg = item.target || '';
|
||
// PK10
|
||
if (['rank','bs','oe','dt','sum_bs'].includes(t)) return getPK10Label(t, tg);
|
||
if (t === 'sum' && tg.startsWith('sum_')) return getPK10Label(t, tg);
|
||
// 骰子
|
||
if (t === 'tai') return '大(总点≥11)';
|
||
if (t === 'xiu') return '小(总点≤10)';
|
||
if (t === 'chan') return '双(总点偶数)';
|
||
if (t === 'le') return '单(总点奇数)';
|
||
if (t === 'sum' || t === 'number') return '押 ' + tg + ' 点';
|
||
if (t === 'dice') return '单骰 ' + tg + ' 点';
|
||
if (t === 'combo' && tg === 'any_triple') return '任意豹子';
|
||
if (t === 'combo' && tg === 'specific_triple') return '指定豹子';
|
||
if (t === 'combo') return '豹子 ' + tg;
|
||
// Xóc Đĩa
|
||
if (t === 'even') return '偶数红';
|
||
if (t === 'odd') return '奇数红';
|
||
if (t === 'big_small') return '大小';
|
||
if (t === 'odd_even') return '单双';
|
||
if (t === '4red') return '四红 🔴🔴🔴🔴';
|
||
if (t === '4white') return '四白 ⚪⚪⚪⚪';
|
||
return t.toUpperCase() + (tg ? ' ' + tg : '');
|
||
}
|
||
|
||
function getBadgeClass(item) {
|
||
const t = item.type;
|
||
if (t === 'rank') return 'bg-yellow-100 text-yellow-800';
|
||
if (t === 'bs') return 'bg-blue-100 text-blue-700';
|
||
if (t === 'oe') return 'bg-green-100 text-green-700';
|
||
if (t === 'dt') return 'bg-red-100 text-red-700';
|
||
if (t === 'sum' && (item.target||'').startsWith('sum_')) return 'bg-orange-100 text-orange-700';
|
||
if (t === 'sum_bs') return 'bg-indigo-100 text-indigo-700';
|
||
if (['tai','xiu'].includes(t)) return 'bg-blue-100 text-blue-700';
|
||
if (['chan','le'].includes(t)) return 'bg-green-100 text-green-700';
|
||
if (t === 'sum' || t === 'number') return 'bg-orange-100 text-orange-700 font-bold';
|
||
if (t === 'dice') return 'bg-purple-100 text-purple-700';
|
||
if (t === 'combo') return 'bg-red-100 text-red-700';
|
||
if (['even','odd','big_small','odd_even'].includes(t)) return 'bg-teal-100 text-teal-700';
|
||
if (['4red','4white'].includes(t)) return 'bg-pink-100 text-pink-700';
|
||
return 'bg-gray-100 text-gray-600';
|
||
}
|
||
|
||
// ========== 按 order 排序渲染 ==========
|
||
const sortedGroups = Object.entries(groups).sort((a,b) => (a[1].order||99) - (b[1].order||99));
|
||
|
||
for (const [key, group] of sortedGroups) {
|
||
if (group.items.length === 0) continue;
|
||
|
||
const groupHtml = `
|
||
<div class="bg-white rounded-lg border border-gray-200 shadow-sm overflow-hidden col-span-1 md:col-span-2 lg:col-span-1 xl:col-span-1">
|
||
<div class="bg-gray-50 px-4 py-2 border-b border-gray-200 flex items-center">
|
||
<i class="fas ${group.icon} text-gray-400 mr-2"></i>
|
||
<h4 class="font-bold text-gray-700 text-sm">${group.title}</h4>
|
||
<span class="ml-auto text-xs text-gray-400">${group.items.length}项</span>
|
||
</div>
|
||
<div class="p-4 space-y-3">
|
||
${group.items.map(item => {
|
||
const label = getLabel(item);
|
||
const badgeClass = getBadgeClass(item);
|
||
|
||
return `
|
||
<div class="flex items-center justify-between group">
|
||
<span class="px-2 py-1 rounded text-xs ${badgeClass} min-w-[80px] text-center" title="${item.type}:${item.target||''}">${label}</span>
|
||
<div class="flex items-center gap-2 relative">
|
||
<span class="text-xs text-gray-400 absolute right-full mr-2 whitespace-nowrap opacity-0 group-hover:opacity-100 transition-opacity">1 : </span>
|
||
<input type="number" step="0.01"
|
||
class="w-24 px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-purple-500 transition-shadow text-right font-medium"
|
||
value="${item.odds}"
|
||
data-type="${item.type}"
|
||
data-target="${item.target}"
|
||
>
|
||
</div>
|
||
</div>
|
||
`;
|
||
}).join('')}
|
||
</div>
|
||
</div>
|
||
`;
|
||
oddsContainer.innerHTML += groupHtml;
|
||
}
|
||
}
|
||
|
||
async function submitOdds() {
|
||
const gameId = document.getElementById('oddsGameId').value;
|
||
const inputs = oddsContainer.querySelectorAll('input[type="number"]');
|
||
const oddsData = [];
|
||
|
||
inputs.forEach(input => {
|
||
oddsData.push({
|
||
type: input.dataset.type,
|
||
target: input.dataset.target,
|
||
odds: input.value
|
||
});
|
||
});
|
||
|
||
submitOddsFormBtn.disabled = true;
|
||
submitOddsFormBtn.innerHTML = '<i class="fas fa-spinner fa-spin mr-2"></i> 保存中...';
|
||
|
||
try {
|
||
const response = await fetch('/admin/games/odds/update', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'X-Requested-With': 'XMLHttpRequest'
|
||
},
|
||
body: JSON.stringify({
|
||
game_id: gameId,
|
||
odds: oddsData
|
||
})
|
||
});
|
||
|
||
const json = await response.json();
|
||
if (json.success) {
|
||
showMessage('赔率配置已更新', 'success');
|
||
closeOddsFormModal();
|
||
} else {
|
||
showMessage(json.message, 'error');
|
||
}
|
||
} catch (e) {
|
||
showMessage('保存失败: ' + e.message, 'error');
|
||
} finally {
|
||
submitOddsFormBtn.disabled = false;
|
||
submitOddsFormBtn.innerHTML = '<i class="fas fa-save mr-2"></i>保存赔率配置';
|
||
}
|
||
}
|
||
|
||
if (closeOddsFormBtn) closeOddsFormBtn.addEventListener('click', closeOddsFormModal);
|
||
if (cancelOddsFormBtn) cancelOddsFormBtn.addEventListener('click', closeOddsFormModal);
|
||
if (submitOddsFormBtn) submitOddsFormBtn.addEventListener('click', submitOdds);
|
||
|
||
// 阻止表单默认提交
|
||
gameForm.addEventListener('submit', e => {
|
||
e.preventDefault();
|
||
submitGameFormData();
|
||
});
|
||
|
||
// 图片预览功能(当SetImageUrl被调用时更新预览)
|
||
const gameImageInput = document.getElementById('gameImage');
|
||
const gameImagePreview = document.querySelector('#gameImagePreview img');
|
||
if (gameImageInput && gameImagePreview) {
|
||
// 监听输入框变化
|
||
gameImageInput.addEventListener('input', function() {
|
||
if (this.value) {
|
||
gameImagePreview.src = this.value;
|
||
document.getElementById('gameImagePreview').style.display = 'block';
|
||
} else {
|
||
document.getElementById('gameImagePreview').style.display = 'none';
|
||
}
|
||
});
|
||
|
||
// 如果SetImageUrl函数存在,保存引用以便更新预览
|
||
if (typeof window.SetImageUrl === 'function') {
|
||
const originalSetImageUrl = window.SetImageUrl;
|
||
window.SetImageUrl = function(url) {
|
||
originalSetImageUrl(url);
|
||
if (gameImageInput && gameImagePreview) {
|
||
gameImageInput.value = url;
|
||
gameImagePreview.src = url;
|
||
document.getElementById('gameImagePreview').style.display = 'block';
|
||
}
|
||
};
|
||
}
|
||
}
|
||
}
|
||
});
|
||
</script>
|