1. 去掉PK10结算中is_virtual过滤,统一更新余额和写入transactions - PK10PeriodController.php (手动结算) - auto_period_task.php (自动结算) 2. live.php轮询回调增加余额同步显示
1833 lines
73 KiB
PHP
Executable File
1833 lines
73 KiB
PHP
Executable File
<html lang="vi">
|
|
<?php
|
|
// Odds Lookup Helper
|
|
$getOdds = function($type, $target = 'all') use ($oddsList) {
|
|
if (!empty($oddsList)) {
|
|
foreach ($oddsList as $item) {
|
|
if ($item['type'] == $type && $item['target'] == $target) {
|
|
return (float)$item['odds'] == (int)$item['odds'] ? (int)$item['odds'] : $item['odds'];
|
|
}
|
|
}
|
|
}
|
|
// Fallbacks
|
|
if ($type == 'tai' || $type == 'xiu' || $type == 'chan' || $type == 'le' || $type == 'dice') return 0.97;
|
|
if ($type == 'combo') return 120;
|
|
if ($type == 'sum') {
|
|
if (in_array($target, [4, 17])) return 30;
|
|
if (in_array($target, [5, 16])) return 18;
|
|
if (in_array($target, [6, 15])) return 14;
|
|
if (in_array($target, [7, 14])) return 12;
|
|
if (in_array($target, [8, 13])) return 8;
|
|
return 6;
|
|
}
|
|
return 1;
|
|
};
|
|
?>
|
|
|
|
<head>
|
|
<title><?= htmlspecialchars($settings['site_title'] ?? '') ?></title>
|
|
<meta charset="utf-8">
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
|
<meta name="viewport"
|
|
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
|
|
<meta name="description" content="<?= htmlspecialchars($settings['site_description'] ?? '') ?>">
|
|
<meta name="keywords" content="<?= htmlspecialchars($settings['site_keywords'] ?? '') ?>">
|
|
<!-- CSS -->
|
|
<link rel="stylesheet" href="/Static/css/style.css">
|
|
<link rel="stylesheet" href="/Static/ckplayer/css/ckplayer.css">
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
|
|
<!-- Layui -->
|
|
<link rel="stylesheet" href="/Static/layui/css/layui.css">
|
|
<style>
|
|
/* 隐藏ckplayer控制条和所有操作元素 */
|
|
.ckplayer-ckplayer .ck-bar {
|
|
display: none !important;
|
|
}
|
|
|
|
.ckplayer-ckplayer .ck-center-play {
|
|
display: none !important;
|
|
}
|
|
|
|
.ckplayer-ckplayer .ck-controls {
|
|
display: none !important;
|
|
}
|
|
|
|
/* PC端终极还原 - 严格匹配原图结构 */
|
|
@media (min-width: 769px) {
|
|
|
|
html,
|
|
body {
|
|
height: 100%;
|
|
overflow: hidden;
|
|
margin: 0;
|
|
padding: 0;
|
|
background: #000;
|
|
}
|
|
|
|
.live-wrapper {
|
|
height: 111vh;
|
|
/* 配合 scale(0.9) */
|
|
width: 98%;
|
|
padding: 5px 10px;
|
|
box-sizing: border-box;
|
|
display: flex;
|
|
flex-direction: column;
|
|
max-width: 1900px;
|
|
margin: 0 auto;
|
|
/* 还原用户习惯的缩放感 */
|
|
transform: scale(0.9);
|
|
transform-origin: top center;
|
|
}
|
|
|
|
.live-topbar {
|
|
height: 50px;
|
|
flex: 0 0 auto;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
/* 使用 Grid 强制复原两栏布局 */
|
|
.live-layout {
|
|
flex: 1;
|
|
display: grid !important;
|
|
/* 调整比例:左侧进一步缩小 (1.8),右侧进一步扩大 (3.2) */
|
|
grid-template-columns: 1.8fr 3.2fr !important;
|
|
/* 行高:第一行视频自适应,第二行路图自适应 */
|
|
grid-template-rows: auto 1fr !important;
|
|
gap: 15px !important;
|
|
overflow: hidden !important;
|
|
min-height: 0;
|
|
}
|
|
|
|
/* 1. 视频区域 -> 左上 (Row 1, Col 1) */
|
|
.live-left {
|
|
grid-column: 1 / 2 !important;
|
|
grid-row: 1 / 2 !important;
|
|
display: flex;
|
|
flex-direction: column;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.live-stream {
|
|
width: 100%;
|
|
aspect-ratio: 16 / 9;
|
|
max-height: 60vh;
|
|
background: #000;
|
|
border-radius: 12px;
|
|
}
|
|
|
|
/* 2. 路图区域 -> 左下 (Row 2, Col 1)
|
|
这是关键!强行把 HTML 里排在最后的元素搬到左下角 */
|
|
.live-history {
|
|
grid-column: 1 / 2 !important;
|
|
grid-row: 2 / 3 !important;
|
|
margin-top: 0 !important;
|
|
background: rgba(255, 255, 255, 0.95) !important;
|
|
border-radius: 12px;
|
|
display: flex !important;
|
|
flex-direction: row !important;
|
|
overflow: hidden;
|
|
min-height: 200px;
|
|
padding: 0 !important;
|
|
}
|
|
|
|
.live-roadmap-v2 {
|
|
flex: 1 1 auto !important;
|
|
width: auto !important;
|
|
min-width: 0 !important;
|
|
overflow-x: auto !important;
|
|
overflow-y: hidden !important;
|
|
padding: 5px;
|
|
border-right: 1px solid rgba(0, 0, 0, 0.1);
|
|
display: block !important;
|
|
}
|
|
|
|
/* 还原Mini Table - 显示在路图右侧 */
|
|
.live-mini-table-v2 {
|
|
display: flex !important;
|
|
flex: 0 0 320px !important;
|
|
width: 320px !important;
|
|
border-radius: 0 !important;
|
|
margin: 0 !important;
|
|
background: transparent !important;
|
|
border: none !important;
|
|
box-shadow: none !important;
|
|
}
|
|
|
|
.live-mini-table-v2::before {
|
|
display: none !important;
|
|
}
|
|
|
|
/* 4. 投注格子 PC端重排序 (蛇形/特定顺序) */
|
|
.bet-grid-v2 {
|
|
display: grid !important;
|
|
grid-template-columns: repeat(8, 1fr) !important;
|
|
gap: 6px !important;
|
|
}
|
|
|
|
/* 正常顺序 4-10 */
|
|
.bet-grid-v2>button:nth-child(1) {
|
|
order: 1;
|
|
}
|
|
|
|
/* 4 */
|
|
.bet-grid-v2>button:nth-child(2) {
|
|
order: 2;
|
|
}
|
|
|
|
/* 5 */
|
|
.bet-grid-v2>button:nth-child(3) {
|
|
order: 3;
|
|
}
|
|
|
|
/* 6 */
|
|
.bet-grid-v2>button:nth-child(4) {
|
|
order: 4;
|
|
}
|
|
|
|
/* 7 */
|
|
.bet-grid-v2>button:nth-child(5) {
|
|
order: 5;
|
|
}
|
|
|
|
/* 8 */
|
|
.bet-grid-v2>button:nth-child(6) {
|
|
order: 6;
|
|
}
|
|
|
|
/* 9 */
|
|
.bet-grid-v2>button:nth-child(7) {
|
|
order: 7;
|
|
}
|
|
|
|
/* 10 */
|
|
|
|
/* CHẴN (HTML第12个) -> 第一行末尾 (Order 8) */
|
|
.bet-grid-v2>button:nth-child(12) {
|
|
order: 8;
|
|
}
|
|
|
|
/* 下面一行倒序 17-11 */
|
|
.bet-grid-v2>button:nth-child(15) {
|
|
order: 9;
|
|
}
|
|
|
|
/* 17 */
|
|
.bet-grid-v2>button:nth-child(14) {
|
|
order: 10;
|
|
}
|
|
|
|
/* 16 */
|
|
.bet-grid-v2>button:nth-child(13) {
|
|
order: 11;
|
|
}
|
|
|
|
/* 15 */
|
|
.bet-grid-v2>button:nth-child(11) {
|
|
order: 12;
|
|
}
|
|
|
|
/* 14 */
|
|
.bet-grid-v2>button:nth-child(10) {
|
|
order: 13;
|
|
}
|
|
|
|
/* 13 */
|
|
.bet-grid-v2>button:nth-child(9) {
|
|
order: 14;
|
|
}
|
|
|
|
/* 12 */
|
|
.bet-grid-v2>button:nth-child(8) {
|
|
order: 15;
|
|
}
|
|
|
|
/* 11 */
|
|
|
|
/* LẺ (HTML第16个) -> 第二行末尾 (Order 16) */
|
|
.bet-grid-v2>button:nth-child(16) {
|
|
order: 16;
|
|
}
|
|
|
|
/* 3. 投注区域 -> 右侧全高 (Row 1-3, Col 2) */
|
|
.bet-panel-v2 {
|
|
position: relative; /* 必需:让 betOverlay 相对于此容器定位 */
|
|
grid-column: 2 / 3 !important;
|
|
grid-row: 1 / 3 !important;
|
|
/* 跨越两行,独占右侧 */
|
|
height: 100% !important;
|
|
overflow: hidden !important; /* 改为 hidden,让内层容器处理滚动 */
|
|
display: flex;
|
|
flex-direction: column;
|
|
padding: 0 !important; /* 移除 padding,由内层容器控制 */
|
|
background: rgba(255, 255, 255, 0.98) !important;
|
|
border-radius: 12px;
|
|
margin: 0 !important;
|
|
}
|
|
|
|
/* 内层滚动容器 */
|
|
.bet-panel-v2 > *:not(#betOverlay):not(#activeCountdown) {
|
|
padding: 0 14px; /* 应用原来的 padding */
|
|
}
|
|
|
|
.bet-panel-content-wrapper {
|
|
flex: 1;
|
|
overflow-y: auto;
|
|
padding: 10px 14px;
|
|
}
|
|
|
|
.bet-top {
|
|
display: grid !important;
|
|
/* 缩小侧边栏宽度 140 -> 110 */
|
|
grid-template-columns: 110px 1fr 110px !important;
|
|
gap: 8px !important;
|
|
margin-bottom: 10px !important;
|
|
min-height: 100px;
|
|
}
|
|
|
|
/* 缩小中间的骰子历史记录骰子大小 */
|
|
.bet-dice-combo .bet-dice-cell {
|
|
width: 24px !important;
|
|
height: 24px !important;
|
|
}
|
|
|
|
.bet-dice-combo .bet-dice-cell img {
|
|
width: 20px !important;
|
|
height: 20px !important;
|
|
}
|
|
|
|
/* 缩小下注格子 (4-17) */
|
|
.bet-cell {
|
|
min-height: 44px !important;
|
|
padding: 4px !important;
|
|
font-size: 14px !important;
|
|
}
|
|
|
|
.bet-odds-mini {
|
|
font-size: 10px !important;
|
|
}
|
|
|
|
/* 筹码区域 - 弹性换行,避免太小 */
|
|
.bet-chips-v2 {
|
|
display: flex !important;
|
|
flex-wrap: wrap !important;
|
|
justify-content: center !important;
|
|
gap: 6px !important;
|
|
margin-top: 10px !important;
|
|
padding-bottom: 5px;
|
|
}
|
|
|
|
/* 缩小筹码按钮 60 -> 48 */
|
|
.bet-chip-btn {
|
|
width: 48px !important;
|
|
height: 48px !important;
|
|
flex: 0 0 auto;
|
|
}
|
|
|
|
.bet-chip-display {
|
|
width: 44px !important;
|
|
height: 44px !important;
|
|
font-size: 11px !important;
|
|
border-width: 2px !important;
|
|
}
|
|
|
|
/* 滚动条 */
|
|
.bet-panel-v2::-webkit-scrollbar {
|
|
width: 6px;
|
|
}
|
|
|
|
.bet-panel-v2::-webkit-scrollbar-thumb {
|
|
background: #bbb;
|
|
border-radius: 3px;
|
|
}
|
|
}
|
|
|
|
/* 移动端筹码 - Grid 2行4列布局 */
|
|
@media (max-width: 768px) {
|
|
|
|
.bet-chips,
|
|
.bet-chips-v2 {
|
|
display: grid !important;
|
|
grid-template-columns: repeat(4, 1fr) !important;
|
|
grid-template-rows: repeat(2, 1fr) !important;
|
|
gap: 6px !important;
|
|
padding: 8px !important;
|
|
margin-top: 8px !important;
|
|
justify-items: center !important;
|
|
align-items: center !important;
|
|
}
|
|
|
|
.bet-chip-btn {
|
|
width: 100% !important;
|
|
display: flex !important;
|
|
justify-content: center !important;
|
|
align-items: center !important;
|
|
}
|
|
|
|
.bet-chip-display {
|
|
width: 44px !important;
|
|
height: 44px !important;
|
|
font-size: 10px !important;
|
|
border-width: 2px !important;
|
|
}
|
|
|
|
.bet-chip-display i {
|
|
font-size: 14px !important;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* Betting Overlay - 状态遮罩层 */
|
|
.bet-overlay {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: linear-gradient(135deg, rgba(0, 0, 0, 0.75), rgba(0, 0, 0, 0.85));
|
|
display: flex !important; /* 强制显示 */
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
align-items: center;
|
|
z-index: 9999 !important; /* 提高到最高层级 */
|
|
border-radius: 12px;
|
|
color: white;
|
|
font-weight: bold;
|
|
pointer-events: auto; /* Block clicks */
|
|
backdrop-filter: blur(4px);
|
|
transition: opacity 0.3s ease;
|
|
}
|
|
.bet-overlay.hidden {
|
|
display: none !important; /* 强制隐藏 */
|
|
pointer-events: none;
|
|
opacity: 0;
|
|
visibility: hidden;
|
|
}
|
|
.countdown-number {
|
|
font-size: 72px;
|
|
color: #ffeb3b;
|
|
font-family: 'Arial Black', monospace;
|
|
font-weight: 900;
|
|
text-shadow:
|
|
0 0 10px rgba(255, 235, 59, 0.8),
|
|
0 0 20px rgba(255, 235, 59, 0.6),
|
|
0 4px 8px rgba(0, 0, 0, 0.5);
|
|
animation: pulse 1s infinite;
|
|
}
|
|
.status-text {
|
|
font-size: 28px;
|
|
margin-top: 20px;
|
|
text-transform: uppercase;
|
|
letter-spacing: 3px;
|
|
text-shadow:
|
|
0 2px 4px rgba(0, 0, 0, 0.8),
|
|
0 0 10px rgba(255, 255, 255, 0.3);
|
|
padding: 12px 24px;
|
|
background: rgba(255, 255, 255, 0.1);
|
|
border-radius: 8px;
|
|
border: 2px solid rgba(255, 255, 255, 0.2);
|
|
}
|
|
@keyframes pulse {
|
|
0% { transform: scale(1); }
|
|
50% { transform: scale(1.05); }
|
|
100% { transform: scale(1); }
|
|
}
|
|
|
|
/* 通用隐藏类 */
|
|
.hidden {
|
|
display: none !important;
|
|
visibility: hidden !important;
|
|
}
|
|
</style>
|
|
<!-- Favicon -->
|
|
<link rel="shortcut icon" href="<?= htmlspecialchars($settings['site_favicon'] ?? '') ?>" type="image/x-icon">
|
|
<!-- Web App Manifest -->
|
|
<!-- iOS PWA Support -->
|
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
|
<meta name="apple-mobile-web-app-title" content="TM68">
|
|
<link rel="apple-touch-icon" href="/Static/css/favicon-192x192.png">
|
|
</head>
|
|
|
|
<body class="live-body" style="background-color: black;">
|
|
<img id="bg-img" src="/Static/tm68/background.png" alt="Background">
|
|
|
|
<div class="live-wrapper">
|
|
<div class="live-topbar">
|
|
<div class="live-topbar-left">
|
|
<button class="live-circle-btn" type="button" aria-label="Back">
|
|
<i class="fa-solid fa-arrow-left"></i>
|
|
</button>
|
|
|
|
<div class="live-balance">
|
|
<div class="live-balance-coin">
|
|
<i class="fa-solid fa-dollar-sign"></i>
|
|
</div>
|
|
<div class="live-balance-text">
|
|
<div class="live-balance-id">ID: <?= htmlspecialchars($user['username'] ?? '') ?></div>
|
|
<div class="live-balance-amount"><?= number_format(($user['balance'] ?? 0) / 1000, 0, ',', '.') ?>k</div>
|
|
</div>
|
|
<button class="live-circle-btn live-refresh" type="button" aria-label="Refresh">
|
|
<i class="fa-solid fa-rotate-right"></i>
|
|
</button>
|
|
</div>
|
|
|
|
<button class="live-pill-btn" type="button">NẠP RÚT</button>
|
|
</div>
|
|
|
|
<div class="live-topbar-right">
|
|
<button class="lobby-icon-btn" type="button" aria-label="Account">
|
|
<i class="fa-solid fa-user"></i>
|
|
</button>
|
|
<button class="lobby-icon-btn" type="button" aria-label="Home">
|
|
<i class="fa-solid fa-house"></i>
|
|
</button>
|
|
<button class="lobby-icon-btn" type="button" id="soundToggle" aria-label="Sound">
|
|
<i class="fa-solid fa-volume-xmark"></i>
|
|
</button>
|
|
<button class="lobby-icon-btn" type="button" id="headerMenuToggle" aria-label="Menu">
|
|
<i class="fa-solid fa-bars"></i>
|
|
</button>
|
|
<div class="header-menu" id="headerMenu">
|
|
<button class="header-menu-item" type="button">
|
|
<span class="header-menu-icon"><i class="fa-solid fa-lock"></i></span>
|
|
<span>Đổi mật khẩu</span>
|
|
</button>
|
|
<button class="header-menu-item" type="button">
|
|
<span class="header-menu-icon"><i class="fa-solid fa-clock-rotate-left"></i></span>
|
|
<span>Lịch sử</span>
|
|
</button>
|
|
<button class="header-menu-item" type="button">
|
|
<span class="header-menu-icon"><i class="fa-solid fa-book-open"></i></span>
|
|
<span>Luật chơi</span>
|
|
</button>
|
|
<a href="/logout" class="header-menu-item" style="text-decoration: none;">
|
|
<span class="header-menu-icon"><i class="fa-solid fa-right-from-bracket"></i></span>
|
|
<span>Đăng xuất</span>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="live-layout live-layout-v2">
|
|
<!-- 左侧播放器 -->
|
|
<div class="live-left">
|
|
<?php if ($hasStreamUrl ?? false): ?>
|
|
<div class="live-panel live-stream live-stream-v2">
|
|
<div class="live-stream-main">
|
|
<div id="tm68LivePlayerLeft" class="live-player" data-stream="<?= htmlspecialchars($streamUrl ?? '') ?>">
|
|
</div>
|
|
<!-- 左上角Logo -->
|
|
<?php if (!empty($settings['site_logo'] ?? '')): ?>
|
|
<div class="live-player-logo">
|
|
<img src="<?= htmlspecialchars($settings['site_logo']) ?>" alt="Logo">
|
|
</div>
|
|
<?php endif; ?>
|
|
<!-- 右下角期号和日期 -->
|
|
<div class="live-player-info">
|
|
<div class="live-player-period">G1202512200001</div>
|
|
<div class="live-player-datetime">
|
|
<span class="live-player-date">20/12/2025</span>
|
|
<span class="live-player-time">17:20:17</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<?php else: ?>
|
|
<div class="live-panel live-stream live-stream-v2" style="display: none;">
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<?php if ($gameType === 'xocdia'): ?>
|
|
<!-- Xóc Đĩa 投注面板 -->
|
|
<?php include __DIR__ . '/components/xocdia-bet-panel.php'; ?>
|
|
<?php else: ?>
|
|
<!-- 骰子游戏投注面板(默认) -->
|
|
<div class="live-panel bet-panel bet-panel-v2" <?= ($hasStreamUrl ?? false) ? '' : 'style="pointer-events: none; opacity: 0.5;"' ?>>
|
|
<!-- Status Overlay -->
|
|
<div id="betOverlay" class="bet-overlay">
|
|
<div id="countdownDisplay" class="countdown-number" style="display: none;"></div>
|
|
<div id="statusDisplay" class="status-text">Đang tải...</div>
|
|
</div>
|
|
|
|
<!-- Active Countdown (visible when betting is open) -->
|
|
<div id="activeCountdown" class="hidden" style="position: absolute; top: 10px; right: 10px; background: rgba(0,0,0,0.5); color: #ffeb3b; padding: 5px 10px; border-radius: 5px; font-weight: bold; font-family: monospace; z-index: 40;">
|
|
<i class="fa-regular fa-clock"></i> <span id="activeTimer">60</span>s
|
|
</div>
|
|
|
|
<div class="bet-top">
|
|
<div class="bet-side bet-xiu" data-bet-type="xiu" data-odds="1:<?= $getOdds('xiu') ?>">
|
|
<div class="bet-side-decoration bet-side-decoration-top-left"></div>
|
|
<div class="bet-side-decoration bet-side-decoration-top-right"></div>
|
|
<div class="bet-side-decoration bet-side-decoration-bottom-left"></div>
|
|
<div class="bet-side-decoration bet-side-decoration-bottom-right"></div>
|
|
<div class="bet-side-title">XỈU</div>
|
|
<div class="bet-side-odds">1:<?= $getOdds('xiu') ?></div>
|
|
</div>
|
|
<div class="bet-dice-history">
|
|
<div class="bet-dice-combo" data-bet-type="combo" data-combo-value="3" data-odds="1:<?= $getOdds('combo', 'specific_triple') ?>">
|
|
<div class="bet-dice-combo-dices">
|
|
<div class="bet-dice-cell"><img src="/Static/tm68/1.png" alt=""></div>
|
|
<div class="bet-dice-cell"><img src="/Static/tm68/1.png" alt=""></div>
|
|
<div class="bet-dice-cell"><img src="/Static/tm68/1.png" alt=""></div>
|
|
</div>
|
|
|
|
<div class="bet-dice-combo-odds">1:<?= $getOdds('combo', 'specific_triple') ?></div>
|
|
</div>
|
|
<div class="bet-dice-combo" data-bet-type="combo" data-combo-value="18" data-odds="1:<?= $getOdds('combo', 'specific_triple') ?>">
|
|
<div class="bet-dice-combo-dices">
|
|
<div class="bet-dice-cell"><img src="/Static/tm68/6.png" alt=""></div>
|
|
<div class="bet-dice-cell"><img src="/Static/tm68/6.png" alt=""></div>
|
|
<div class="bet-dice-cell"><img src="/Static/tm68/6.png" alt=""></div>
|
|
</div>
|
|
|
|
<div class="bet-dice-combo-odds">1:<?= $getOdds('combo', 'specific_triple') ?></div>
|
|
</div>
|
|
<div class="bet-dice-combo" data-bet-type="combo" data-combo-value="6" data-odds="1:<?= $getOdds('combo', 'specific_triple') ?>">
|
|
<div class="bet-dice-combo-dices">
|
|
<div class="bet-dice-cell"><img src="/Static/tm68/2.png" alt=""></div>
|
|
<div class="bet-dice-cell"><img src="/Static/tm68/2.png" alt=""></div>
|
|
<div class="bet-dice-cell"><img src="/Static/tm68/2.png" alt=""></div>
|
|
</div>
|
|
|
|
<div class="bet-dice-combo-odds">1:<?= $getOdds('combo', 'specific_triple') ?></div>
|
|
</div>
|
|
<div class="bet-dice-combo" data-bet-type="combo" data-combo-value="15" data-odds="1:<?= $getOdds('combo', 'specific_triple') ?>">
|
|
<div class="bet-dice-combo-dices">
|
|
<div class="bet-dice-cell"><img src="/Static/tm68/5.png" alt=""></div>
|
|
<div class="bet-dice-cell"><img src="/Static/tm68/5.png" alt=""></div>
|
|
<div class="bet-dice-cell"><img src="/Static/tm68/5.png" alt=""></div>
|
|
</div>
|
|
|
|
<div class="bet-dice-combo-odds">1:<?= $getOdds('combo', 'specific_triple') ?></div>
|
|
</div>
|
|
<div class="bet-dice-combo" data-bet-type="combo" data-combo-value="3" data-odds="1:<?= $getOdds('combo', 'specific_triple') ?>">
|
|
<div class="bet-dice-combo-dices">
|
|
<div class="bet-dice-cell "><img src="/Static/tm68/3.png" alt=""></div>
|
|
<div class="bet-dice-cell "><img src="/Static/tm68/3.png" alt=""></div>
|
|
<div class="bet-dice-cell "><img src="/Static/tm68/3.png" alt=""></div>
|
|
</div>
|
|
|
|
<div class="bet-dice-combo-odds">1:<?= $getOdds('combo', 'specific_triple') ?></div>
|
|
</div>
|
|
<div class="bet-dice-combo" data-bet-type="combo" data-combo-value="12" data-odds="1:<?= $getOdds('combo', 'specific_triple') ?>">
|
|
<div class="bet-dice-combo-dices">
|
|
<div class="bet-dice-cell "><img src="/Static/tm68/4.png" alt=""></div>
|
|
<div class="bet-dice-cell "><img src="/Static/tm68/4.png" alt=""></div>
|
|
<div class="bet-dice-cell "><img src="/Static/tm68/4.png" alt=""></div>
|
|
</div>
|
|
|
|
<div class="bet-dice-combo-odds">1:<?= $getOdds('combo', 'specific_triple') ?></div>
|
|
</div>
|
|
</div>
|
|
<div class="bet-side bet-tai" data-bet-type="tai" data-odds="1:<?= $getOdds('tai') ?>">
|
|
<div class="bet-side-decoration bet-side-decoration-top-left"></div>
|
|
<div class="bet-side-decoration bet-side-decoration-top-right"></div>
|
|
<div class="bet-side-decoration bet-side-decoration-bottom-left"></div>
|
|
<div class="bet-side-decoration bet-side-decoration-bottom-right"></div>
|
|
<div class="bet-side-title">TÀI</div>
|
|
<div class="bet-side-odds">1:<?= $getOdds('tai') ?></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="bet-grid bet-grid-v2">
|
|
<button class="bet-cell bet-cell-white" type="button" data-bet-number="4" data-odds="1:<?= $getOdds('sum', '4') ?>">4<div
|
|
class="bet-odds-mini">1:<?= $getOdds('sum', '4') ?></div></button>
|
|
<button class="bet-cell bet-cell-white" type="button" data-bet-number="5" data-odds="1:<?= $getOdds('sum', '5') ?>">5<div
|
|
class="bet-odds-mini">1:<?= $getOdds('sum', '5') ?></div></button>
|
|
<button class="bet-cell bet-cell-white" type="button" data-bet-number="6" data-odds="1:<?= $getOdds('sum', '6') ?>">6<div
|
|
class="bet-odds-mini">1:<?= $getOdds('sum', '6') ?></div></button>
|
|
<button class="bet-cell bet-cell-white" type="button" data-bet-number="7" data-odds="1:<?= $getOdds('sum', '7') ?>">7<div
|
|
class="bet-odds-mini">1:<?= $getOdds('sum', '7') ?></div></button>
|
|
<button class="bet-cell bet-cell-white" type="button" data-bet-number="8" data-odds="1:<?= $getOdds('sum', '8') ?>">8<div
|
|
class="bet-odds-mini">1:<?= $getOdds('sum', '8') ?></div></button>
|
|
<button class="bet-cell bet-cell-white" type="button" data-bet-number="9" data-odds="1:<?= $getOdds('sum', '9') ?>">9<div
|
|
class="bet-odds-mini">1:<?= $getOdds('sum', '9') ?></div></button>
|
|
<button class="bet-cell bet-cell-white" type="button" data-bet-number="10" data-odds="1:<?= $getOdds('sum', '10') ?>">10<div
|
|
class="bet-odds-mini">1:<?= $getOdds('sum', '10') ?></div></button>
|
|
<button class="bet-cell bet-cell-green" type="button" data-bet-number="11" data-odds="1:<?= $getOdds('sum', '11') ?>">11<div
|
|
class="bet-odds-mini">1:<?= $getOdds('sum', '11') ?></div></button>
|
|
|
|
<button class="bet-cell bet-cell-green" type="button" data-bet-number="12" data-odds="1:<?= $getOdds('sum', '12') ?>">12<div
|
|
class="bet-odds-mini">1:<?= $getOdds('sum', '12') ?></div></button>
|
|
<button class="bet-cell bet-cell-red" type="button" data-bet-number="13" data-odds="1:<?= $getOdds('sum', '13') ?>">13<div
|
|
class="bet-odds-mini">1:<?= $getOdds('sum', '13') ?></div></button>
|
|
<button class="bet-cell bet-cell-red" type="button" data-bet-number="14" data-odds="1:<?= $getOdds('sum', '14') ?>">14<div
|
|
class="bet-odds-mini">1:<?= $getOdds('sum', '14') ?></div></button>
|
|
<button class="bet-cell bet-cell-outline-red" type="button" data-bet-type="chan" data-odds="1:<?= $getOdds('chan') ?>">CHẴN<div
|
|
class="bet-odds-mini">1:<?= $getOdds('chan') ?></div></button>
|
|
|
|
<button class="bet-cell bet-cell-red" type="button" data-bet-number="15" data-odds="1:<?= $getOdds('sum', '15') ?>">15<div
|
|
class="bet-odds-mini">1:<?= $getOdds('sum', '15') ?></div></button>
|
|
<button class="bet-cell bet-cell-red" type="button" data-bet-number="16" data-odds="1:<?= $getOdds('sum', '16') ?>">16<div
|
|
class="bet-odds-mini">1:<?= $getOdds('sum', '16') ?></div></button>
|
|
<button class="bet-cell bet-cell-red" type="button" data-bet-number="17" data-odds="1:<?= $getOdds('sum', '17') ?>">17<div
|
|
class="bet-odds-mini">1:<?= $getOdds('sum', '17') ?></div></button>
|
|
<button class="bet-cell bet-cell-outline-green" type="button" data-bet-type="le" data-odds="1:<?= $getOdds('le') ?>">LẺ<div
|
|
class="bet-odds-mini">1:<?= $getOdds('le') ?></div></button>
|
|
</div>
|
|
|
|
<div class="bet-dice-row-v2">
|
|
<button class="bet-dice-single" type="button" data-dice="1" data-odds="1:<?= $getOdds('dice', '1') ?>">
|
|
<div class="bet-dice-cell bet-dice-cell-gray "><img src="/Static/tm68/1.png" alt="1"></div>
|
|
<div class="bet-dice-single-odds">1:<?= $getOdds('dice', '1') ?></div>
|
|
</button>
|
|
<button class="bet-dice-single" type="button" data-dice="2" data-odds="1:<?= $getOdds('dice', '2') ?>">
|
|
<div class="bet-dice-cell bet-dice-cell-gray"><img src="/Static/tm68/2.png" alt="2"></div>
|
|
<div class="bet-dice-single-odds">1:<?= $getOdds('dice', '2') ?></div>
|
|
</button>
|
|
<button class="bet-dice-single" type="button" data-dice="3" data-odds="1:<?= $getOdds('dice', '3') ?>">
|
|
<div class="bet-dice-cell bet-dice-cell-gray"><img src="/Static/tm68/3.png" alt="3"></div>
|
|
<div class="bet-dice-single-odds">1:<?= $getOdds('dice', '3') ?></div>
|
|
</button>
|
|
<button class="bet-dice-single" type="button" data-dice="4" data-odds="1:<?= $getOdds('dice', '4') ?>">
|
|
<div class="bet-dice-cell bet-dice-cell-gray "><img src="/Static/tm68/4.png" alt="4"></div>
|
|
<div class="bet-dice-single-odds">1:<?= $getOdds('dice', '4') ?></div>
|
|
</button>
|
|
<button class="bet-dice-single" type="button" data-dice="5" data-odds="1:<?= $getOdds('dice', '5') ?>">
|
|
<div class="bet-dice-cell bet-dice-cell-gray"><img src="/Static/tm68/5.png" alt="5"></div>
|
|
<div class="bet-dice-single-odds">1:<?= $getOdds('dice', '5') ?></div>
|
|
</button>
|
|
<button class="bet-dice-single" type="button" data-dice="6" data-odds="1:<?= $getOdds('dice', '6') ?>">
|
|
<div class="bet-dice-cell bet-dice-cell-gray"><img src="/Static/tm68/6.png" alt="6"></div>
|
|
<div class="bet-dice-single-odds">1:<?= $getOdds('dice', '6') ?></div>
|
|
</button>
|
|
</div>
|
|
|
|
<div class="bet-actions bet-actions-v2">
|
|
<button class="bet-action bet-action-green" type="button" id="confirmBetBtn">
|
|
<i class="fa-solid fa-check"></i>
|
|
<span>ĐẶT CƯỢC</span>
|
|
</button>
|
|
<button class="bet-action bet-action-red" type="button" id="cancelBetBtn">
|
|
<i class="fa-solid fa-xmark"></i>
|
|
<span>HỦY</span>
|
|
</button>
|
|
</div>
|
|
|
|
<div class="bet-chips bet-chips-v2">
|
|
<button class="bet-chip-btn" type="button" data-amount="100000" data-label="100K">
|
|
<div class="bet-chip-display chip-red">100K</div>
|
|
</button>
|
|
<button class="bet-chip-btn" type="button" data-amount="200000" data-label="200K">
|
|
<div class="bet-chip-display chip-purple">200K</div>
|
|
</button>
|
|
<button class="bet-chip-btn" type="button" data-amount="500000" data-label="500K">
|
|
<div class="bet-chip-display chip-blue">500K</div>
|
|
</button>
|
|
<button class="bet-chip-btn" type="button" data-amount="1000000" data-label="1M">
|
|
<div class="bet-chip-display chip-gold">1M</div>
|
|
</button>
|
|
<button class="bet-chip-btn" type="button" data-amount="2000000" data-label="2M">
|
|
<div class="bet-chip-display chip-orange">2M</div>
|
|
</button>
|
|
<button class="bet-chip-btn" type="button" data-amount="5000000" data-label="5M">
|
|
<div class="bet-chip-display chip-green">5M</div>
|
|
</button>
|
|
<button class="bet-chip-btn" type="button" data-amount="10000000" data-label="10M">
|
|
<div class="bet-chip-display chip-lime">10M</div>
|
|
</button>
|
|
<button class="bet-chip-btn bet-chip-custom" type="button" data-amount="custom" data-label="+">
|
|
<div class="bet-chip-display chip-add">
|
|
<i class="fa-solid fa-plus"></i>
|
|
</div>
|
|
</button>
|
|
</div>
|
|
|
|
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<div class="live-panel live-history live-history-v2" style="margin-top: 10px;">
|
|
<div class="live-roadmap live-roadmap-v2">
|
|
<div class="road-grid">
|
|
<?php
|
|
// 动态生成历史开奖记录
|
|
if (!empty($recentPeriods) && is_array($recentPeriods)):
|
|
$row = 1;
|
|
$col = 1;
|
|
// 调试:输出期号数量
|
|
// echo "<!-- 历史期号数量: " . count($recentPeriods) . ", 游戏类型: $gameType -->";
|
|
foreach (array_reverse($recentPeriods) as $period):
|
|
// 判断游戏类型并设置显示内容
|
|
if ($gameType === 'xocdia'):
|
|
// Xóc Đĩa: 显示红色硬币数量
|
|
$redCount = $period['dice1'] ?? 0;
|
|
$dotClass = ($redCount == 0 || $redCount == 2 || $redCount == 4) ? 'blue' : 'red';
|
|
$displayText = $redCount . 'Đ';
|
|
else:
|
|
// 骰子游戏: 显示总和
|
|
$total = $period['total'] ?? 0;
|
|
$dotClass = ($total >= 4 && $total <= 10) ? 'blue' : 'red';
|
|
$displayText = $total;
|
|
endif;
|
|
|
|
// 调试:输出当前位置
|
|
// echo "<!-- 位置: col=$col, row=$row, 显示: $displayText, dice1={$period['dice1']}, result={$period['result']} -->";
|
|
?>
|
|
<div class="road-cell" style="grid-column: <?= $col ?>; grid-row: <?= $row ?>;"><span class="road-dot <?= $dotClass ?>"><?= $displayText ?></span></div>
|
|
<?php
|
|
// 更新列和行(在循环外部,确保每次都执行)
|
|
$col++;
|
|
if ($col > 15) {
|
|
$col = 1;
|
|
$row++;
|
|
}
|
|
endforeach;
|
|
else:
|
|
// 如果没有历史记录,显示占位符
|
|
for ($i = 1; $i <= 15; $i++):
|
|
?>
|
|
<div class="road-cell" style="grid-column: <?= $i ?>; grid-row: 1;"><span class="road-dot gray">-</span></div>
|
|
<?php
|
|
endfor;
|
|
endif;
|
|
?>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="live-mini-table live-mini-table-v2">
|
|
<div class="live-mini-table-header">
|
|
<span></span>
|
|
<span></span>
|
|
<span></span>
|
|
<span></span>
|
|
<span></span>
|
|
</div>
|
|
<div class="live-mini-table-body">
|
|
<?php
|
|
// 显示最近5期详细记录
|
|
if (!empty($recentPeriods) && is_array($recentPeriods)):
|
|
$displayCount = 0;
|
|
foreach ($recentPeriods as $period):
|
|
if ($displayCount >= 5) break;
|
|
if ($gameType === 'xocdia'):
|
|
// Xóc Đĩa: 显示硬币颜色
|
|
$coins = json_decode($period['result'] ?? '[]', true);
|
|
if (!is_array($coins) || count($coins) !== 4) continue;
|
|
$redCount = count(array_filter($coins, fn($c) => $c === 'red'));
|
|
$resultClass = ($redCount == 0 || $redCount == 2 || $redCount == 4) ? 'blue' : 'red';
|
|
$resultText = ($redCount == 0 || $redCount == 2 || $redCount == 4) ? 'Chẵn' : 'Lẻ';
|
|
?>
|
|
<div class="live-mini-row">
|
|
<span><?= $coins[0] === 'red' ? 'Đ' : 'T' ?></span>
|
|
<span><?= $coins[1] === 'red' ? 'Đ' : 'T' ?></span>
|
|
<span><?= $coins[2] === 'red' ? 'Đ' : 'T' ?></span>
|
|
<span><?= $coins[3] === 'red' ? 'Đ' : 'T' ?></span>
|
|
<span class="<?= $resultClass ?>"><?= $resultText ?></span>
|
|
</div>
|
|
<?php
|
|
else:
|
|
// 骰子游戏: 显示骰子点数
|
|
$dice1 = $period['dice1'] ?? 0;
|
|
$dice2 = $period['dice2'] ?? 0;
|
|
$dice3 = $period['dice3'] ?? 0;
|
|
$total = $period['total'] ?? 0;
|
|
$result = $period['result'] ?? '';
|
|
$resultClass = ($total >= 4 && $total <= 10) ? 'blue' : 'red';
|
|
?>
|
|
<div class="live-mini-row">
|
|
<span><?= $dice1 ?></span>
|
|
<span><?= $dice2 ?></span>
|
|
<span><?= $dice3 ?></span>
|
|
<span class="<?= $resultClass ?>"><?= $total ?></span>
|
|
<span><?= htmlspecialchars($result) ?></span>
|
|
</div>
|
|
<?php
|
|
endif;
|
|
$displayCount++;
|
|
endforeach;
|
|
endif;
|
|
?>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 投注面板 -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="/Static/ckplayer/hls.js/hls.min.js"></script>
|
|
<script src="/Static/ckplayer/flv.js/flv.min.js"></script>
|
|
<script src="/Static/ckplayer/mpegts.js/mpegts.min.js"></script>
|
|
<script src="/Static/ckplayer/js/ckplayer.js"></script>
|
|
<script src="/Static/layui/layui.js"></script>
|
|
|
|
<script>
|
|
layui.use(['layer'], function () {
|
|
var layer = layui.layer;
|
|
|
|
(function () {
|
|
var playerLogo = <?= !empty($settings['site_logo'] ?? '') ? json_encode($settings['site_logo']) : "''" ?>;
|
|
var currentGameId = <?= isset($game['id']) ? (int)$game['id'] : 1 ?>;
|
|
// 获取后端传来的当前期号信息
|
|
var serverPeriodNumber = <?= !empty($currentPeriod['period_number']) ? json_encode($currentPeriod['period_number']) : "''" ?>;
|
|
|
|
// 更新播放器期号和日期时间
|
|
function updatePlayerInfo() {
|
|
var periodEl = document.querySelector('.live-player-period');
|
|
var dateEl = document.querySelector('.live-player-date');
|
|
var timeEl = document.querySelector('.live-player-time');
|
|
|
|
if (periodEl) {
|
|
// 如果有后端真实期号,直接显示
|
|
if (serverPeriodNumber) {
|
|
periodEl.textContent = serverPeriodNumber;
|
|
} else {
|
|
// 如果没有期号,显示等待提示,不随机生成
|
|
periodEl.textContent = 'Đang chờ...';
|
|
}
|
|
}
|
|
|
|
if (dateEl && timeEl) {
|
|
var now = new Date();
|
|
// 更新日期:DD/MM/YYYY
|
|
var day = String(now.getDate()).padStart(2, '0');
|
|
var month = String(now.getMonth() + 1).padStart(2, '0');
|
|
var year = now.getFullYear();
|
|
dateEl.textContent = day + '/' + month + '/' + year;
|
|
|
|
// 更新时间:HH:MM:SS(红色)
|
|
var hours = String(now.getHours()).padStart(2, '0');
|
|
var minutes = String(now.getMinutes()).padStart(2, '0');
|
|
var seconds = String(now.getSeconds()).padStart(2, '0');
|
|
timeEl.textContent = hours + ':' + minutes + ':' + seconds;
|
|
}
|
|
}
|
|
|
|
// 初始化显示
|
|
updatePlayerInfo();
|
|
|
|
// 每秒更新一次时间
|
|
setInterval(updatePlayerInfo, 1000);
|
|
|
|
// 初始化左侧播放器(仅在有流地址时初始化)
|
|
var hasStreamUrl = <?= ($hasStreamUrl ?? false) ? 'true' : 'false' ?>;
|
|
var leftPlayerContainer = document.getElementById('tm68LivePlayerLeft');
|
|
if (leftPlayerContainer && typeof ckplayer === 'function' && hasStreamUrl) {
|
|
var leftStreamUrl = leftPlayerContainer.getAttribute('data-stream') || '';
|
|
// 如果没有配置流地址,不初始化播放器
|
|
if (!leftStreamUrl) {
|
|
return;
|
|
}
|
|
|
|
window.tm68LivePlayerLeft = ckplayer({
|
|
container: '#tm68LivePlayerLeft',
|
|
live: true,
|
|
autoplay: true,
|
|
volume: 0,
|
|
controls: false,
|
|
rightBar: false,
|
|
bar: false,
|
|
video: leftStreamUrl,
|
|
type: 'hls',
|
|
playsinline: true
|
|
});
|
|
|
|
// 拦截CKPlayer的pause方法,禁止暂停
|
|
if (window.tm68LivePlayerLeft && typeof window.tm68LivePlayerLeft.pause === 'function') {
|
|
var originalLeftPause = window.tm68LivePlayerLeft.pause;
|
|
window.tm68LivePlayerLeft.pause = function () {
|
|
// 禁止暂停,直接返回
|
|
return;
|
|
};
|
|
}
|
|
|
|
// 确保播放器自动播放并禁止暂停
|
|
setTimeout(function () {
|
|
try {
|
|
// 直接查找并操作video元素
|
|
var leftVideo = document.querySelector('#tm68LivePlayerLeft video');
|
|
if (leftVideo) {
|
|
leftVideo.muted = true;
|
|
leftVideo.play().catch(function (e) {
|
|
console.log('Left video autoplay failed:', e);
|
|
});
|
|
|
|
// 禁止暂停:监听pause事件并立即恢复播放
|
|
leftVideo.addEventListener('pause', function (e) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
var video = this;
|
|
setTimeout(function () {
|
|
video.play().catch(function (err) {
|
|
console.log('Left video resume failed:', err);
|
|
});
|
|
}, 10);
|
|
}, true);
|
|
|
|
// 重写pause方法,禁止暂停
|
|
var originalPause = leftVideo.pause;
|
|
leftVideo.pause = function () {
|
|
// 不执行暂停操作,直接返回
|
|
return;
|
|
};
|
|
} else if (window.tm68LivePlayerLeft && typeof window.tm68LivePlayerLeft.play === 'function') {
|
|
window.tm68LivePlayerLeft.play();
|
|
}
|
|
} catch (e) {
|
|
console.log('Left player autoplay failed:', e);
|
|
}
|
|
}, 800);
|
|
}
|
|
|
|
// 初始化右侧主播放器(仅在有流地址时初始化)
|
|
var playerContainer = document.getElementById('tm68LivePlayer');
|
|
if (playerContainer && typeof ckplayer === 'function' && hasStreamUrl) {
|
|
var streamUrl = playerContainer.getAttribute('data-stream') || '';
|
|
// 如果没有配置流地址,不初始化播放器
|
|
if (!streamUrl) {
|
|
return;
|
|
}
|
|
|
|
window.tm68LivePlayer = ckplayer({
|
|
container: '#tm68LivePlayer',
|
|
live: true,
|
|
autoplay: true,
|
|
volume: 0,
|
|
controls: false,
|
|
rightBar: false,
|
|
bar: false,
|
|
video: streamUrl,
|
|
type: 'hls',
|
|
logo: playerLogo || undefined,
|
|
playsinline: true
|
|
});
|
|
|
|
// 拦截CKPlayer的pause方法,禁止暂停
|
|
if (window.tm68LivePlayer && typeof window.tm68LivePlayer.pause === 'function') {
|
|
var originalMainPause = window.tm68LivePlayer.pause;
|
|
window.tm68LivePlayer.pause = function () {
|
|
// 禁止暂停,直接返回
|
|
return;
|
|
};
|
|
}
|
|
|
|
// 确保播放器自动播放并禁止暂停
|
|
setTimeout(function () {
|
|
try {
|
|
// 直接查找并操作video元素
|
|
var rightVideo = document.querySelector('#tm68LivePlayer video');
|
|
if (rightVideo) {
|
|
rightVideo.muted = true;
|
|
rightVideo.play().catch(function (e) {
|
|
console.log('Main video autoplay failed:', e);
|
|
});
|
|
|
|
// 禁止暂停:监听pause事件并立即恢复播放
|
|
rightVideo.addEventListener('pause', function (e) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
var video = this;
|
|
setTimeout(function () {
|
|
video.play().catch(function (err) {
|
|
console.log('Main video resume failed:', err);
|
|
});
|
|
}, 10);
|
|
}, true);
|
|
|
|
// 重写pause方法,禁止暂停
|
|
var originalPause = rightVideo.pause;
|
|
rightVideo.pause = function () {
|
|
// 不执行暂停操作,直接返回
|
|
return;
|
|
};
|
|
} else if (window.tm68LivePlayer && typeof window.tm68LivePlayer.play === 'function') {
|
|
window.tm68LivePlayer.play();
|
|
}
|
|
} catch (e) {
|
|
console.log('Main player autoplay failed:', e);
|
|
}
|
|
}, 800);
|
|
}
|
|
|
|
var toggle = document.getElementById('headerMenuToggle');
|
|
var menu = document.getElementById('headerMenu');
|
|
if (toggle && menu) {
|
|
toggle.addEventListener('click', function (e) {
|
|
e.stopPropagation();
|
|
menu.classList.toggle('is-open');
|
|
});
|
|
|
|
document.addEventListener('click', function () {
|
|
menu.classList.remove('is-open');
|
|
});
|
|
|
|
menu.addEventListener('click', function (e) {
|
|
e.stopPropagation();
|
|
});
|
|
}
|
|
|
|
// 返回按钮 - 返回上一页
|
|
var backBtn = document.querySelector('.live-circle-btn[aria-label="Back"]');
|
|
if (backBtn) {
|
|
backBtn.addEventListener('click', function (e) {
|
|
e.preventDefault();
|
|
window.history.back();
|
|
});
|
|
}
|
|
|
|
// 首页按钮 - 跳转到首页
|
|
var homeBtn = document.querySelector('.lobby-icon-btn[aria-label="Home"]');
|
|
if (homeBtn) {
|
|
homeBtn.addEventListener('click', function (e) {
|
|
e.preventDefault();
|
|
window.location.href = '/';
|
|
});
|
|
}
|
|
|
|
var soundToggle = document.getElementById('soundToggle');
|
|
if (soundToggle) {
|
|
var icon = soundToggle.querySelector('i');
|
|
var muted = true; // 默认静音
|
|
|
|
soundToggle.addEventListener('click', function (e) {
|
|
e.stopPropagation();
|
|
muted = !muted;
|
|
if (muted) {
|
|
icon.classList.remove('fa-volume-high');
|
|
icon.classList.add('fa-volume-xmark');
|
|
} else {
|
|
icon.classList.remove('fa-volume-xmark');
|
|
icon.classList.add('fa-volume-high');
|
|
}
|
|
|
|
try {
|
|
document.dispatchEvent(new CustomEvent('tm68SoundToggle', {
|
|
detail: { muted: muted }
|
|
}));
|
|
} catch (err) {
|
|
console.warn('tm68SoundToggle event dispatch failed', err);
|
|
}
|
|
});
|
|
|
|
// 初始化时发送静音事件
|
|
try {
|
|
document.dispatchEvent(new CustomEvent('tm68SoundToggle', {
|
|
detail: { muted: true }
|
|
}));
|
|
} catch (err) {
|
|
console.warn('tm68SoundToggle initial event dispatch failed', err);
|
|
}
|
|
}
|
|
|
|
document.addEventListener('tm68SoundToggle', function (e) {
|
|
if (!hasStreamUrl) return; // 如果没有流地址,不处理音量控制
|
|
|
|
// 控制右侧主播放器音量
|
|
var player = window.tm68LivePlayer;
|
|
if (player) {
|
|
if (e && e.detail && e.detail.muted) {
|
|
player.muted();
|
|
} else {
|
|
player.exitMuted();
|
|
player.volume(0.8);
|
|
}
|
|
}
|
|
|
|
// 控制左侧播放器音量
|
|
var leftPlayer = window.tm68LivePlayerLeft;
|
|
if (leftPlayer) {
|
|
if (e && e.detail && e.detail.muted) {
|
|
leftPlayer.muted();
|
|
} else {
|
|
leftPlayer.exitMuted();
|
|
leftPlayer.volume(0.8);
|
|
}
|
|
}
|
|
});
|
|
|
|
// 页面加载完成后再次尝试播放(确保自动播放,仅在有流地址时)
|
|
if (hasStreamUrl) {
|
|
window.addEventListener('load', function () {
|
|
setTimeout(function () {
|
|
try {
|
|
// 左侧播放器
|
|
if (window.tm68LivePlayerLeft) {
|
|
// 直接设置video元素的muted属性确保自动播放
|
|
var leftVideo = document.querySelector('#tm68LivePlayerLeft video');
|
|
if (leftVideo) {
|
|
leftVideo.muted = true;
|
|
leftVideo.play().catch(function (e) {
|
|
console.log('Left video autoplay failed:', e);
|
|
});
|
|
|
|
// 再次确保禁止暂停
|
|
if (!leftVideo._pauseDisabled) {
|
|
leftVideo._pauseDisabled = true;
|
|
leftVideo.addEventListener('pause', function (e) {
|
|
e.preventDefault();
|
|
var video = this;
|
|
setTimeout(function () {
|
|
video.play().catch(function (err) { });
|
|
}, 10);
|
|
}, true);
|
|
var originalPause = leftVideo.pause;
|
|
leftVideo.pause = function () { return; };
|
|
}
|
|
} else if (typeof window.tm68LivePlayerLeft.play === 'function') {
|
|
window.tm68LivePlayerLeft.play();
|
|
}
|
|
}
|
|
|
|
// 右侧播放器
|
|
if (window.tm68LivePlayer) {
|
|
// 直接设置video元素的muted属性确保自动播放
|
|
var rightVideo = document.querySelector('#tm68LivePlayer video');
|
|
if (rightVideo) {
|
|
rightVideo.muted = true;
|
|
rightVideo.play().catch(function (e) {
|
|
console.log('Main video autoplay failed:', e);
|
|
});
|
|
|
|
// 再次确保禁止暂停
|
|
if (!rightVideo._pauseDisabled) {
|
|
rightVideo._pauseDisabled = true;
|
|
rightVideo.addEventListener('pause', function (e) {
|
|
e.preventDefault();
|
|
var video = this;
|
|
setTimeout(function () {
|
|
video.play().catch(function (err) { });
|
|
}, 10);
|
|
}, true);
|
|
var originalPause = rightVideo.pause;
|
|
rightVideo.pause = function () { return; };
|
|
}
|
|
} else if (typeof window.tm68LivePlayer.play === 'function') {
|
|
window.tm68LivePlayer.play();
|
|
}
|
|
}
|
|
} catch (e) {
|
|
console.log('Autoplay retry failed:', e);
|
|
}
|
|
}, 1000);
|
|
});
|
|
}
|
|
|
|
// 定期检查播放状态,如果暂停则立即恢复(防止意外暂停,仅在有流地址时)
|
|
if (hasStreamUrl) {
|
|
setInterval(function () {
|
|
try {
|
|
// 检查左侧播放器
|
|
var leftVideo = document.querySelector('#tm68LivePlayerLeft video');
|
|
if (leftVideo && leftVideo.paused) {
|
|
leftVideo.play().catch(function (e) { });
|
|
}
|
|
|
|
// 检查右侧播放器
|
|
var rightVideo = document.querySelector('#tm68LivePlayer video');
|
|
if (rightVideo && rightVideo.paused) {
|
|
rightVideo.play().catch(function (e) { });
|
|
}
|
|
} catch (e) {
|
|
// 忽略错误
|
|
}
|
|
}, 500); // 每500ms检查一次
|
|
}
|
|
|
|
// ========== 下注功能模块 ==========
|
|
(function (layer) {
|
|
// 如果没有流地址,禁止投注功能
|
|
var hasStreamUrlForBet = <?= ($hasStreamUrl ?? false) ? 'true' : 'false' ?>;
|
|
if (!hasStreamUrlForBet) {
|
|
// 禁用所有投注按钮
|
|
var betButtons = document.querySelectorAll('.bet-cell, .bet-side, .bet-dice-single, .bet-dice-combo, .bet-chip-btn, #confirmBetBtn, #cancelBetBtn');
|
|
betButtons.forEach(function (btn) {
|
|
btn.disabled = true;
|
|
btn.style.cursor = 'not-allowed';
|
|
btn.style.opacity = '0.5';
|
|
});
|
|
return; // 不初始化投注功能
|
|
}
|
|
|
|
// ========== Period Polling & Countdown ==========
|
|
var periodState = {
|
|
status: 'loading',
|
|
remaining: 0,
|
|
periodNumber: serverPeriodNumber
|
|
};
|
|
|
|
var betOverlay = document.getElementById('betOverlay');
|
|
var countdownDisplay = document.getElementById('countdownDisplay');
|
|
var statusDisplay = document.getElementById('statusDisplay');
|
|
var activeCountdown = document.getElementById('activeCountdown');
|
|
var activeTimer = document.getElementById('activeTimer');
|
|
var periodEl = document.querySelector('.live-player-period');
|
|
|
|
// 调试:检查元素是否存在
|
|
console.log('DOM 元素检查:', {
|
|
betOverlay: !!betOverlay,
|
|
countdownDisplay: !!countdownDisplay,
|
|
statusDisplay: !!statusDisplay,
|
|
activeCountdown: !!activeCountdown,
|
|
activeTimer: !!activeTimer,
|
|
periodEl: !!periodEl
|
|
});
|
|
|
|
// 调试:检查遮罩层的初始样式
|
|
if (betOverlay) {
|
|
console.log('betOverlay 初始状态:', {
|
|
className: betOverlay.className,
|
|
display: getComputedStyle(betOverlay).display,
|
|
position: getComputedStyle(betOverlay).position,
|
|
zIndex: getComputedStyle(betOverlay).zIndex,
|
|
visibility: getComputedStyle(betOverlay).visibility
|
|
});
|
|
}
|
|
|
|
// 测试函数:强制显示遮罩层
|
|
window.testShowOverlay = function() {
|
|
if (betOverlay) {
|
|
betOverlay.classList.remove('hidden');
|
|
betOverlay.style.display = 'flex';
|
|
betOverlay.style.visibility = 'visible';
|
|
betOverlay.style.zIndex = '9999';
|
|
if (statusDisplay) statusDisplay.textContent = '测试遮罩层';
|
|
console.log('测试:强制显示遮罩层');
|
|
}
|
|
};
|
|
|
|
function updatePeriodUI() {
|
|
console.log('更新期号状态:', periodState);
|
|
|
|
if (periodState.status === 'pending') {
|
|
if (periodState.remaining > 0) {
|
|
// Betting Open - 投注开放
|
|
console.log('✅ 投注开放,剩余时间:', periodState.remaining + 's');
|
|
if (betOverlay) {
|
|
betOverlay.classList.add('hidden');
|
|
betOverlay.style.display = 'none';
|
|
betOverlay.style.visibility = 'hidden';
|
|
}
|
|
if (activeCountdown) {
|
|
activeCountdown.classList.remove('hidden');
|
|
activeCountdown.style.display = 'block';
|
|
}
|
|
if (activeTimer) activeTimer.textContent = periodState.remaining;
|
|
|
|
// Enable buttons
|
|
var confirmBtn = document.getElementById('confirmBetBtn');
|
|
if (confirmBtn) confirmBtn.disabled = false;
|
|
} else {
|
|
// Betting Closed - 封盘
|
|
console.log('⏸️ 封盘 - 停止下注');
|
|
if (betOverlay) {
|
|
betOverlay.classList.remove('hidden');
|
|
betOverlay.style.display = 'flex';
|
|
betOverlay.style.visibility = 'visible';
|
|
betOverlay.style.opacity = '1';
|
|
console.log('遮罩层显示:', {
|
|
display: getComputedStyle(betOverlay).display,
|
|
classes: betOverlay.className,
|
|
zIndex: getComputedStyle(betOverlay).zIndex
|
|
});
|
|
}
|
|
if (activeCountdown) activeCountdown.classList.add('hidden');
|
|
if (countdownDisplay) {
|
|
countdownDisplay.style.display = 'none'; // 不显示倒计时数字
|
|
}
|
|
if (statusDisplay) statusDisplay.textContent = '⏸️ ĐÓNG CƯỢC'; // Stop Betting
|
|
|
|
// Disable buttons
|
|
var confirmBtn = document.getElementById('confirmBetBtn');
|
|
if (confirmBtn) confirmBtn.disabled = true;
|
|
}
|
|
} else if (periodState.status === 'locked') {
|
|
// Locked - 锁定(开奖前锁定)
|
|
console.log('🔒 锁定期号');
|
|
if (betOverlay) {
|
|
betOverlay.classList.remove('hidden');
|
|
betOverlay.style.display = 'flex';
|
|
betOverlay.style.visibility = 'visible';
|
|
betOverlay.style.opacity = '1';
|
|
}
|
|
if (activeCountdown) activeCountdown.classList.add('hidden');
|
|
if (countdownDisplay) countdownDisplay.style.display = 'none';
|
|
if (statusDisplay) statusDisplay.textContent = '🔒 ĐÃ KHÓA'; // Locked
|
|
var confirmBtn = document.getElementById('confirmBetBtn');
|
|
if (confirmBtn) confirmBtn.disabled = true;
|
|
} else if (periodState.status === 'drawn') {
|
|
// Drawing/Payout - 正在开奖/派奖
|
|
console.log('💰 正在派奖');
|
|
if (betOverlay) {
|
|
betOverlay.classList.remove('hidden');
|
|
betOverlay.style.display = 'flex';
|
|
betOverlay.style.visibility = 'visible';
|
|
betOverlay.style.opacity = '1';
|
|
}
|
|
if (activeCountdown) activeCountdown.classList.add('hidden');
|
|
if (countdownDisplay) countdownDisplay.style.display = 'none';
|
|
if (statusDisplay) statusDisplay.textContent = '💰 ĐANG TRẢ THƯỞNG'; // Payout
|
|
var confirmBtn = document.getElementById('confirmBetBtn');
|
|
if (confirmBtn) confirmBtn.disabled = true;
|
|
} else if (periodState.status === 'settled') {
|
|
// Settled - 已结算,等待下一局
|
|
console.log('⏳ 等待新一局, remaining:', periodState.remaining);
|
|
if (betOverlay) {
|
|
betOverlay.classList.remove('hidden');
|
|
// 强制设置样式
|
|
betOverlay.style.display = 'flex';
|
|
betOverlay.style.visibility = 'visible';
|
|
betOverlay.style.opacity = '1';
|
|
console.log('settled状态 - 遮罩层强制显示:', {
|
|
classes: betOverlay.className,
|
|
display: getComputedStyle(betOverlay).display,
|
|
zIndex: getComputedStyle(betOverlay).zIndex
|
|
});
|
|
}
|
|
if (activeCountdown) activeCountdown.classList.add('hidden');
|
|
if (countdownDisplay) countdownDisplay.style.display = 'none';
|
|
if (statusDisplay) {
|
|
statusDisplay.textContent = '⏳ CHỜ VÁN MỚI'; // Waiting for next round
|
|
console.log('状态文本已更新:', statusDisplay.textContent);
|
|
}
|
|
var confirmBtn = document.getElementById('confirmBetBtn');
|
|
if (confirmBtn) confirmBtn.disabled = true;
|
|
} else {
|
|
// Loading or Error - 加载中或错误
|
|
console.log('⏱️ 加载中... 状态:', periodState.status);
|
|
if (betOverlay) {
|
|
betOverlay.classList.remove('hidden');
|
|
betOverlay.style.display = 'flex';
|
|
betOverlay.style.visibility = 'visible';
|
|
betOverlay.style.opacity = '1';
|
|
}
|
|
if (countdownDisplay) countdownDisplay.style.display = 'none';
|
|
if (statusDisplay) statusDisplay.textContent = '⏱️ ĐANG TẢI...';
|
|
var confirmBtn = document.getElementById('confirmBetBtn');
|
|
if (confirmBtn) confirmBtn.disabled = true;
|
|
}
|
|
|
|
// Update Period Number Display
|
|
if (periodEl && periodState.periodNumber) {
|
|
periodEl.textContent = periodState.periodNumber;
|
|
}
|
|
|
|
// Update global serverPeriodNumber for bet submission
|
|
serverPeriodNumber = periodState.periodNumber;
|
|
}
|
|
|
|
var _lastPollPeriodId = 0;
|
|
var _lastPollStatus = '';
|
|
|
|
function checkPeriodStatus() {
|
|
fetch('/api/period/current?game_id=' + currentGameId)
|
|
.then(res => res.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
var serverRemaining = data.data.remaining_seconds || 0;
|
|
var periodChanged = (data.data.id && data.data.id !== _lastPollPeriodId);
|
|
var statusChanged = (data.data.status !== _lastPollStatus);
|
|
var driftTooMuch = Math.abs(periodState.remaining - serverRemaining) > 3;
|
|
|
|
periodState.status = data.data.status;
|
|
periodState.periodNumber = data.data.period_number;
|
|
|
|
// 只在必要时同步服务端倒计时(防止跳数)
|
|
if (periodChanged || statusChanged || driftTooMuch || periodState.remaining <= 0) {
|
|
periodState.remaining = serverRemaining;
|
|
}
|
|
|
|
_lastPollPeriodId = data.data.id || 0;
|
|
_lastPollStatus = data.data.status;
|
|
|
|
// 同步余额(结算后中奖加款)
|
|
if (data.balance !== null && data.balance !== undefined) {
|
|
var balanceEl = document.querySelector('.live-balance-amount');
|
|
if (balanceEl) balanceEl.textContent = formatAmount(data.balance);
|
|
}
|
|
|
|
updatePeriodUI();
|
|
} else {
|
|
periodState.status = 'settled';
|
|
periodState.periodNumber = 'Đang chờ...';
|
|
updatePeriodUI();
|
|
}
|
|
})
|
|
.catch(err => console.error('Poll error:', err));
|
|
}
|
|
|
|
// 本地倒计时 —— 每秒 -1,丝滑不跳
|
|
setInterval(function() {
|
|
if (periodState.remaining > 0) {
|
|
periodState.remaining--;
|
|
// 只更新倒计时数字,不触发完整UI更新
|
|
if (activeTimer) activeTimer.textContent = periodState.remaining;
|
|
}
|
|
}, 1000);
|
|
|
|
// 轮询:3秒同步一次(比原来1秒降低66%请求量)
|
|
setInterval(checkPeriodStatus, 3000);
|
|
checkPeriodStatus(); // Initial check
|
|
|
|
// 初始化或重置全局投注状态
|
|
window.betState = {
|
|
selectedChip: null, // 当前选中的筹码 {amount, label, color}
|
|
bets: {} // 每个投注选项的金额 {betKey: {amount, chipInfo, betInfo}}
|
|
};
|
|
|
|
// 创建局部变量引用,方便后续代码使用
|
|
var betState = window.betState;
|
|
|
|
// 清理可能残留的旧数据
|
|
console.log('投注状态已初始化:', betState);
|
|
|
|
// 初始化筹码按钮
|
|
var chipButtons = document.querySelectorAll('.bet-chip-btn');
|
|
chipButtons.forEach(function (btn) {
|
|
btn.addEventListener('click', function () {
|
|
var amount = this.getAttribute('data-amount');
|
|
var label = this.getAttribute('data-label');
|
|
|
|
// 移除其他选中状态
|
|
chipButtons.forEach(function (b) {
|
|
b.classList.remove('chip-selected');
|
|
});
|
|
|
|
if (amount === 'custom') {
|
|
// 自定义金额
|
|
layer.prompt({
|
|
formType: 0,
|
|
title: 'Nhập số tiền cược',
|
|
placeholder: 'Nhập số tiền',
|
|
area: ['300px', 'auto']
|
|
}, function (value, index, elem) {
|
|
if (value && !isNaN(value) && parseFloat(value) > 0) {
|
|
betState.selectedChip = {
|
|
amount: parseFloat(value),
|
|
label: formatAmount(parseFloat(value)),
|
|
color: 'custom'
|
|
};
|
|
}
|
|
layer.close(index);
|
|
});
|
|
} else {
|
|
this.classList.add('chip-selected');
|
|
var chipDisplay = this.querySelector('.bet-chip-display');
|
|
var colorClass = chipDisplay.className.match(/chip-(\w+)/);
|
|
betState.selectedChip = {
|
|
amount: parseInt(amount),
|
|
label: label,
|
|
color: colorClass ? colorClass[1] : 'default'
|
|
};
|
|
}
|
|
});
|
|
});
|
|
|
|
// 获取投注选项的唯一标识
|
|
function getBetKey(element) {
|
|
var betInfo = parseBetOption(element);
|
|
if (!betInfo) return null;
|
|
return betInfo.type + '_' + betInfo.value;
|
|
}
|
|
|
|
// 初始化投注选项按钮
|
|
var betOptions = document.querySelectorAll('.bet-cell, .bet-side, .bet-dice-single, .bet-dice-combo');
|
|
betOptions.forEach(function (option) {
|
|
// 为每个投注选项添加筹码显示容器
|
|
if (!option.querySelector('.bet-amount-display')) {
|
|
var amountDisplay = document.createElement('div');
|
|
amountDisplay.className = 'bet-amount-display';
|
|
option.appendChild(amountDisplay);
|
|
}
|
|
|
|
option.addEventListener('click', function () {
|
|
if (!betState.selectedChip) {
|
|
layer.msg('Vui lòng chọn số tiền cược trước!', { icon: 0 });
|
|
return;
|
|
}
|
|
|
|
var betKey = getBetKey(this);
|
|
if (!betKey) return;
|
|
|
|
// 解析投注信息
|
|
var betInfo = parseBetOption(this);
|
|
if (!betInfo) {
|
|
console.error('无法解析投注选项:', this);
|
|
layer.msg('Loại cược không hợp lệ!', { icon: 0 });
|
|
return;
|
|
}
|
|
|
|
// 累加金额
|
|
if (!betState.bets[betKey]) {
|
|
betState.bets[betKey] = {
|
|
amount: 0,
|
|
chipInfo: betState.selectedChip,
|
|
betInfo: betInfo
|
|
};
|
|
}
|
|
|
|
// 累加当前选择的筹码金额
|
|
betState.bets[betKey].amount += betState.selectedChip.amount;
|
|
|
|
// 更新显示
|
|
updateBetDisplay(this, betState.bets[betKey]);
|
|
|
|
// 添加选中状态
|
|
this.classList.add('bet-selected');
|
|
});
|
|
});
|
|
|
|
// 更新投注选项的显示
|
|
function updateBetDisplay(element, betData) {
|
|
var amountDisplay = element.querySelector('.bet-amount-display');
|
|
if (!amountDisplay) return;
|
|
|
|
var totalAmount = betData.amount;
|
|
var chipInfo = betData.chipInfo;
|
|
|
|
// 清空现有内容
|
|
amountDisplay.innerHTML = '';
|
|
|
|
// 创建筹码显示 - 只显示一个筹码图标
|
|
var chipWrapper = document.createElement('div');
|
|
chipWrapper.className = 'bet-chip-wrapper';
|
|
|
|
// 只显示一个筹码图标
|
|
var chipEl = document.createElement('div');
|
|
chipEl.className = 'bet-chip-icon chip-' + chipInfo.color;
|
|
chipWrapper.appendChild(chipEl);
|
|
|
|
// 显示总金额(根据累计金额更新)
|
|
var amountText = document.createElement('div');
|
|
amountText.className = 'bet-amount-text';
|
|
amountText.textContent = formatAmount(totalAmount);
|
|
|
|
amountDisplay.appendChild(chipWrapper);
|
|
amountDisplay.appendChild(amountText);
|
|
amountDisplay.style.display = 'flex';
|
|
}
|
|
|
|
// 确认下注
|
|
var confirmBtn = document.getElementById('confirmBetBtn');
|
|
if (confirmBtn) {
|
|
confirmBtn.addEventListener('click', function () {
|
|
var betKeys = Object.keys(betState.bets);
|
|
if (betKeys.length === 0) {
|
|
layer.msg('Vui lòng chọn ít nhất một loại cược!', { icon: 0 });
|
|
return;
|
|
}
|
|
|
|
// 准备下注数据
|
|
var betsToSubmit = [];
|
|
betKeys.forEach(function (betKey) {
|
|
var betData = betState.bets[betKey];
|
|
|
|
// 兼容两种数据结构
|
|
if (betData && betData.amount > 0) {
|
|
// 标准结构:{amount, chipInfo, betInfo: {type, value, odds}}
|
|
if (betData.betInfo && betData.betInfo.type) {
|
|
betsToSubmit.push({
|
|
type: betData.betInfo.type,
|
|
value: betData.betInfo.value,
|
|
amount: betData.amount,
|
|
odds: betData.betInfo.odds
|
|
});
|
|
}
|
|
// 兼容旧结构:{type, value, amount, odds, chipInfo}
|
|
else if (betData.type) {
|
|
betsToSubmit.push({
|
|
type: betData.type,
|
|
value: betData.value,
|
|
amount: betData.amount,
|
|
odds: betData.odds
|
|
});
|
|
} else {
|
|
console.warn('跳过无效投注 (缺少type):', betKey, betData);
|
|
}
|
|
} else {
|
|
console.warn('跳过无效投注 (金额<=0或无数据):', betKey, betData);
|
|
}
|
|
});
|
|
|
|
if (betsToSubmit.length === 0) return;
|
|
|
|
// 使用服务端传来的期号,或者从界面获取(必须确保不是模拟数据)
|
|
var periodNumber = serverPeriodNumber;
|
|
|
|
// 如果服务端期号为空,尝试从界面获取,但要排除模拟数据
|
|
if (!periodNumber) {
|
|
var periodEl = document.querySelector('.live-player-period');
|
|
var text = periodEl ? periodEl.textContent.trim() : '';
|
|
// 简单的校验:必须以G开头,且不能包含#,且长度要合理
|
|
if (text && text.indexOf('G') === 0 && text.indexOf('#') === -1 && text !== 'Đang chờ...') {
|
|
periodNumber = text;
|
|
}
|
|
}
|
|
|
|
if (!periodNumber) {
|
|
layer.msg('Đang chờ kỳ quay mới...', {icon: 0});
|
|
return;
|
|
}
|
|
|
|
// 锁定按钮
|
|
confirmBtn.disabled = true;
|
|
confirmBtn.innerHTML = '<i class="fa-solid fa-spinner fa-spin"></i> <span>ĐANG XỬ LÝ...</span>';
|
|
|
|
// 发送请求
|
|
fetch('/api/bet', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({
|
|
bets: betsToSubmit,
|
|
period_number: periodNumber,
|
|
game_id: currentGameId
|
|
})
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
layer.msg('Đặt cược thành công!', { icon: 1 });
|
|
|
|
// 更新余额显示
|
|
if (data.new_balance !== undefined) {
|
|
var balanceEl = document.querySelector('.live-balance-amount');
|
|
if (balanceEl) {
|
|
balanceEl.textContent = formatAmount(data.new_balance);
|
|
}
|
|
}
|
|
|
|
resetBetSelection();
|
|
|
|
} else {
|
|
layer.msg(data.message || 'Đặt cược thất bại', { icon: 2 });
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Bet error:', error);
|
|
layer.msg('Lỗi kết nối máy chủ', { icon: 2 });
|
|
})
|
|
.finally(() => {
|
|
confirmBtn.disabled = false;
|
|
confirmBtn.innerHTML = '<i class="fa-solid fa-check"></i> <span>ĐẶT CƯỢC</span>';
|
|
});
|
|
});
|
|
}
|
|
|
|
// 取消下注
|
|
var cancelBtn = document.getElementById('cancelBetBtn');
|
|
if (cancelBtn) {
|
|
cancelBtn.addEventListener('click', function () {
|
|
resetBetSelection();
|
|
});
|
|
}
|
|
|
|
// 解析投注选项
|
|
function parseBetOption(element) {
|
|
var betType = null;
|
|
var betValue = null;
|
|
var odds = null;
|
|
|
|
if (element.classList.contains('bet-side')) {
|
|
if (element.classList.contains('bet-xiu')) {
|
|
betType = 'xiu';
|
|
betValue = 'XỈU';
|
|
odds = '1:0.97';
|
|
} else if (element.classList.contains('bet-tai')) {
|
|
betType = 'tai';
|
|
betValue = 'TÀI';
|
|
odds = '1:0.97';
|
|
}
|
|
} else if (element.classList.contains('bet-dice-combo')) {
|
|
// 处理骰子组合投注
|
|
betType = element.getAttribute('data-bet-type') || 'combo';
|
|
betValue = element.getAttribute('data-combo-value') || '0';
|
|
odds = element.getAttribute('data-odds') || '1:120';
|
|
} else if (element.classList.contains('bet-dice-single')) {
|
|
betType = 'dice';
|
|
betValue = parseInt(element.getAttribute('data-dice'));
|
|
odds = element.getAttribute('data-odds') || '1:0.97';
|
|
} else if (element.classList.contains('bet-cell-outline-red')) {
|
|
betType = 'chan';
|
|
betValue = 'CHẴN';
|
|
odds = '1:0.97';
|
|
} else if (element.classList.contains('bet-cell-outline-green')) {
|
|
betType = 'le';
|
|
betValue = 'LẺ';
|
|
odds = '1:0.97';
|
|
} else if (element.classList.contains('bet-cell')) {
|
|
// 优先使用data属性
|
|
var betNumber = element.getAttribute('data-bet-number');
|
|
var betTypeAttr = element.getAttribute('data-bet-type');
|
|
|
|
if (betTypeAttr) {
|
|
betType = betTypeAttr;
|
|
betValue = element.textContent.trim().split('\n')[0];
|
|
} else if (betNumber) {
|
|
betType = 'number';
|
|
betValue = parseInt(betNumber);
|
|
} else {
|
|
// 回退到文本解析
|
|
var text = element.textContent.trim();
|
|
var numberMatch = text.match(/^(\d+)/);
|
|
if (numberMatch) {
|
|
betType = 'number';
|
|
betValue = parseInt(numberMatch[1]);
|
|
}
|
|
}
|
|
|
|
// 获取赔率
|
|
var oddsAttr = element.getAttribute('data-odds');
|
|
if (oddsAttr) {
|
|
odds = oddsAttr;
|
|
} else {
|
|
var oddsEl = element.querySelector('.bet-odds-mini');
|
|
if (oddsEl) {
|
|
odds = oddsEl.textContent.trim();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (betType && betValue !== null) {
|
|
return { type: betType, value: betValue, odds: odds };
|
|
}
|
|
return null;
|
|
}
|
|
|
|
// 重置选择
|
|
function resetBetSelection() {
|
|
betState.bets = {};
|
|
betState.selectedChip = null;
|
|
|
|
betOptions.forEach(function (o) {
|
|
o.classList.remove('bet-selected');
|
|
var amountDisplay = o.querySelector('.bet-amount-display');
|
|
if (amountDisplay) {
|
|
amountDisplay.innerHTML = '';
|
|
amountDisplay.style.display = 'none';
|
|
}
|
|
});
|
|
|
|
chipButtons.forEach(function (b) {
|
|
b.classList.remove('chip-selected');
|
|
});
|
|
}
|
|
|
|
// 格式化金额
|
|
function formatAmount(amount) {
|
|
if (amount >= 1000000) {
|
|
return (amount / 1000000).toFixed(0) + 'M';
|
|
} else if (amount >= 1000) {
|
|
return (amount / 1000).toFixed(0) + 'K';
|
|
}
|
|
return amount.toString();
|
|
}
|
|
|
|
|
|
})(layer);
|
|
})();
|
|
});
|
|
</script>
|
|
|
|
</body>
|
|
|
|
</html>
|