Files
chatroom/resources/views/chat/partials/games/horse-race-panel.blade.php
T

338 lines
22 KiB
PHP
Raw Normal View History

{{--
文件功能:赛马竞猜前台弹窗组件
聊天室内赛马竞猜游戏面板:
- 监听 WebSocket horse.opened 事件触发弹窗
- 展示参赛马匹列表和实时注池赔率
- 倒计时押注后进入跑马阶段(动态进度条)
- 监听 horse.progress 更新赛道动画
- 监听 horse.settled 展示结果 + 个人赔付
- 展示近10场历史趋势
--}}
2026-04-25 10:56:49 +08:00
<style>
/* 赛马下注金额输入框聚焦态,替代内联 onfocus/onblur 样式。 */
.horse-race-bet-input:focus {
background: #fff !important;
border-color: #336699 !important;
box-shadow: 0 0 0 2px rgba(51, 102, 153, .1) !important;
}
</style>
{{-- ─── 赛马主面板 ─── --}}
2026-04-25 18:33:08 +08:00
<div id="horse-race-panel"
x-data="horseRacePanel()"
x-show="show"
x-cloak
data-horse-race-current-url="{{ route('horse-race.current') }}"
data-horse-race-bet-url="{{ route('horse-race.bet') }}"
data-horse-race-history-url="{{ route('horse-race.history') }}">
<div x-transition:enter="transition ease-out duration-300" x-transition:enter-start="opacity-0 scale-95"
x-transition:enter-end="opacity-100 scale-100" x-transition:leave="transition ease-in duration-200"
x-transition:leave-start="opacity-100 scale-100" x-transition:leave-end="opacity-0 scale-95"
2026-04-25 02:15:09 +08:00
@click.self="close()"
style="position:fixed; inset:0; background:rgba(0,0,0,.55); z-index:9941;
display:flex; align-items:center; justify-content:center;">
<div
style="width:500px; max-width:96vw; border-radius:8px; overflow:hidden;
box-shadow:0 8px 32px rgba(0,0,0,.3); font-family:'Microsoft YaHei',SimSun,sans-serif; background:#fff;">
{{-- ─── 标题栏(海军蓝风格)─── --}}
<div
style="background:linear-gradient(135deg,#336699,#5a8fc0); padding:10px 16px; display:flex; align-items:center; gap:10px;">
<div style="font-size:14px; font-weight:bold; color:#fff; flex:1;">
🐎 赛马竞猜
<span style="font-size:11px; font-weight:normal; color:rgba(255,255,255,.6); margin-left:4px;"
x-text="raceId ? '#' + raceId + ' 场' : ''"></span>
</div>
2026-04-12 17:46:24 +08:00
{{-- 金币余额 --}}
<div
style="font-size:12px; color:#d0e8ff; display:flex; align-items:center; gap:3px;
background:rgba(0,0,0,.2); padding:2px 8px; border-radius:10px;">
💰 <strong style="color:#ffe082; font-size:13px;" x-text="Number(window.chatContext?.userJjb || 0).toLocaleString()">--</strong> 金币
</div>
{{-- 倒计时(押注阶段) --}}
<div x-show="phase === 'betting'"
style="font-size:12px; color:#fff; background:rgba(255,255,255,.2); padding:4px 12px; border-radius:20px; border:1px solid rgba(255,255,255,.3); box-shadow:0 2px 4px rgba(0,0,0,.1) inset; display:flex; align-items:center; gap:4px;">
<span x-text="countdown" style="font-weight:bold; color:#fef08a; font-size:14px;"></span>
</div>
{{-- 跑马阶段 --}}
<div x-show="phase === 'running'" style="display:none;"
style="font-size:12px; color:rgba(255,255,255,.8); background:rgba(0,0,0,.2); padding:2px 10px; border-radius:10px;">
🏇 跑马中…
</div>
{{-- 结算 --}}
<div x-show="phase === 'settled'" style="display:none;"
style="font-size:12px; color:#ffe082; font-weight:bold;">🏆 已结算</div>
2026-04-25 10:50:35 +08:00
<span data-game-panel-close="horse-race-panel"
style="cursor:pointer; font-size:18px; color:rgba(255,255,255,.8); line-height:1; transition:opacity .15s;"
onmouseover="this.style.opacity=1" onmouseout="this.style.opacity=.8">&times;</span>
</div>
{{-- 押注进度条(蓝色风格) --}}
<div x-show="phase === 'betting'" style="height:3px; background:#d0e4f5; overflow:hidden;">
<div style="height:100%; background:#336699; transition:width 1s linear;"
:style="'width:' + Math.max(0, (countdown / totalSeconds * 100)) + '%'"></div>
</div>
{{-- ─── 历史趋势(蓝白色系)─── --}}
<div
style="background:#f6faff; padding:6px 16px; border-bottom:1px solid #d0e4f5;
display:flex; gap:5px; align-items:center; flex-wrap:wrap; min-height:32px;">
<span style="color:#336699; font-size:11px; margin-right:2px; font-weight:bold;">近期冒涨:</span>
<template x-for="h in history" :key="h.id">
<span
style="padding:1px 8px; border-radius:10px; font-size:10px; font-weight:bold;
background:#e8f0f8; color:#336699; border:1px solid #b8d0e8;"
:title="'#' + h.id + ' 冠军:' + h.winner_name" x-text="h.winner_name"></span>
</template>
<span x-show="history.length === 0" style="color:#aaa; font-size:11px;">暂无记录</span>
</div>
{{-- ─── 主体内容(白底)─── --}}
<div style="background:#fff; padding:14px 16px;">
{{-- ── 押注阶段 ── --}}
<div x-show="phase === 'betting'">
{{-- 注池统计 --}}
<div
style="color:#336699; font-size:11px; margin-bottom:8px; text-align:center; background:#e8f0f8; border-radius:4px; padding:4px 0;">
注池总额:<span style="color:#b45309; font-weight:bold;"
x-text="Number(totalPool).toLocaleString() + ' 金币'"></span>
</div>
{{-- 马匹列表 --}}
<div style="display:flex; flex-direction:column; gap:8px; margin-bottom:12px;">
<template x-for="horse in horses" :key="horse.id">
<div style="border-radius:12px; padding:10px 14px; cursor:pointer; transition:all .15s; border:2px solid transparent;"
2026-04-11 16:58:28 +08:00
:style="myBet && myBetHorseId === horse.id ?
'background:linear-gradient(135deg,#dff7e8,#f5fff8); border-color:#22c55e; box-shadow:0 0 0 3px rgba(34,197,94,.15), 0 10px 24px rgba(34,197,94,.10);' :
(selectedHorse === horse.id ?
'background:linear-gradient(135deg,#e8f0f8,#f7fbff); border-color:#336699; box-shadow:0 0 0 3px rgba(51,102,153,.12), 0 10px 24px rgba(51,102,153,.10); transform:translateY(-1px);' :
'background:#f6faff; border-color:#d0e4f5;')"
@click="myBet ? null : selectedHorse = horse.id">
<div style="display:flex; align-items:center; justify-content:space-between;">
<div style="display:flex; align-items:center; gap:10px;">
{{-- 选中勾选 --}}
2026-04-11 16:58:28 +08:00
<div style="width:24px; height:24px; border-radius:999px; border:2px solid; display:flex; align-items:center; justify-content:center; font-size:12px; font-weight:bold; flex-shrink:0; transition:all .15s;"
:style="myBet && myBetHorseId === horse.id ?
'border-color:#16a34a; background:#16a34a; color:#fff; box-shadow:0 0 0 4px rgba(34,197,94,.16);' :
(selectedHorse === horse.id ?
'border-color:#336699; background:#336699; color:#fff; box-shadow:0 0 0 4px rgba(51,102,153,.14);' :
'border-color:#b0c8e0; color:transparent; background:#fff;')">
<span x-text="myBet && myBetHorseId === horse.id ? '押' : '✓'"></span>
</div>
<div style="font-size:22px;" x-text="horse.emoji"></div>
<div>
2026-04-11 16:58:28 +08:00
<div style="color:#225588; font-weight:bold; font-size:13px; display:flex; align-items:center; gap:6px;"
x-text="horse.name"></div>
2026-04-11 16:58:28 +08:00
<div x-show="myBet && myBetHorseId === horse.id"
style="display:none; margin-top:2px; color:#15803d; font-size:10px; font-weight:bold;">
我的押注
</div>
<div style="color:#888; font-size:10px;">
注池:<span x-text="Number(horse.pool || 0).toLocaleString()"></span>
</div>
</div>
</div>
{{-- 实时赔率 --}}
<div style="text-align:right;">
<div style="color:#b45309; font-weight:900; font-size:15px;"
x-text="horse.odds ? '×' + horse.odds : '—'"></div>
<div style="color:#999; font-size:10px;">赔率</div>
</div>
</div>
</div>
</template>
</div>
{{-- 已下注状态 --}}
<div x-show="myBet">
<div
2026-04-11 16:58:28 +08:00
style="background:linear-gradient(135deg,#e7fbe8,#f6fff7); border:2px solid #86efac; border-radius:14px;
padding:14px 16px; text-align:center; margin-bottom:10px; box-shadow:0 10px 24px rgba(34,197,94,.10);">
<div style="color:#16a34a; font-weight:900; font-size:18px; letter-spacing:.02em;">
已押注「<span x-text="myBetHorseName"></span>
<span x-text="Number(myBetAmount).toLocaleString()"></span> 金币
</div>
2026-04-11 16:58:28 +08:00
<div style="color:#5f7a68; font-size:13px; margin-top:8px; font-weight:bold;">等待开跑…</div>
</div>
</div>
{{-- 下注区 --}}
<div x-show="!myBet">
{{-- 快捷金额 --}}
2026-04-11 16:58:28 +08:00
<div style="display:grid; grid-template-columns:repeat(5,minmax(0,1fr)); gap:10px; margin-bottom:14px;">
2026-04-12 17:56:16 +08:00
<template x-for="preset in quickBetAmounts" :key="preset">
<button @click="betAmount = preset"
2026-04-11 16:58:28 +08:00
style="position:relative; overflow:hidden; border:1px solid #d6e5f6; border-radius:16px; padding:12px 0;
font-size:16px; font-weight:900; letter-spacing:.01em; cursor:pointer; transition:all .18s ease; text-shadow:0 1px 0 rgba(255,255,255,.45);"
:style="betAmount === preset ?
2026-04-11 16:58:28 +08:00
'background:linear-gradient(180deg,#4f89c0 0%,#2d6297 52%,#214f7a 100%); color:#fff; border-color:#1c486f; box-shadow:0 12px 20px rgba(35,89,138,.30), inset 0 1px 0 rgba(255,255,255,.18); transform:translateY(-2px) scale(1.01); text-shadow:none;' :
'background:linear-gradient(180deg,#ffffff 0%,#f3f8ff 65%,#e8f1fb 100%); color:#2f6498; box-shadow:0 6px 12px rgba(76,122,172,.10), inset 0 1px 0 rgba(255,255,255,.92);'"
2026-04-12 17:56:16 +08:00
x-text="preset >= 10000 ? (preset/1000)+'k' : (preset >= 1000 ? (preset/1000)+'k' : preset)"></button>
</template>
</div>
<input type="number" x-model.number="betAmount" min="100" placeholder="自定义金额"
2026-04-25 10:56:49 +08:00
class="horse-race-bet-input"
2026-04-11 16:58:28 +08:00
style="width:100%; background:#f6faff; border:1px solid #d0e4f5; border-radius:16px;
2026-04-25 10:56:49 +08:00
padding:14px 16px; color:#23364d; font-size:16px; font-weight:bold; box-sizing:border-box; margin-bottom:14px; outline:none; transition:all .15s;">
{{-- 下注按钮 --}}
<button @click="submitBet()" :disabled="!selectedHorse || betAmount < 100 || submitting"
:style="(!selectedHorse || betAmount < 100 || submitting) ?
2026-04-12 17:49:49 +08:00
'display:block; width:100%; border:none; border-radius:12px; padding:13px 0; font-size:14px; font-weight:bold; cursor:not-allowed; transition:all .2s; background:#e0e8f0; color:#99a8b8; box-shadow:none; font-family:inherit;' :
'display:block; width:100%; border:none; border-radius:12px; padding:13px 0; font-size:14px; font-weight:bold; cursor:pointer; transition:all .2s; background:linear-gradient(135deg,#336699,#5a8fc0); color:#fff; box-shadow:0 4px 14px rgba(51,102,153,.3); font-family:inherit;'">
<span
2026-04-12 17:49:49 +08:00
x-text="submitting ? '提交中…' : (!selectedHorse ? '请先选择马匹' : '🐎 押注「' + myBetHorsePreviewName + '」 ' + Number(betAmount).toLocaleString() + ' 金币')"></span>
</button>
</div>
</div>
2026-04-11 16:58:28 +08:00
{{-- ── 未开始阶段 ── --}}
<div x-show="phase === 'idle'" style="display:none;">
<div style="padding:16px 4px 10px;">
<div style="background:linear-gradient(135deg,#f7fbff,#eef6ff); border:1px solid #c9def2; border-radius:16px; padding:22px 18px; text-align:center; box-shadow:inset 0 1px 0 rgba(255,255,255,.9);">
<div style="font-size:34px; margin-bottom:8px;">🐎</div>
<div style="color:#24507a; font-size:18px; font-weight:900; margin-bottom:6px;">游戏还没开始</div>
<div style="color:#6b7f95; font-size:13px; line-height:1.7;">
当前暂无进行中的赛马场次。<br>
请等待系统开场后再来下注。
</div>
</div>
</div>
</div>
{{-- ── 跑马阶段 ── --}}
<div x-show="phase === 'running'" style="display:none;">
<div
style="margin-bottom:8px; color:#336699; font-size:11px; font-weight:bold; text-align:center; background:#e8f0f8; border-radius:4px; padding:4px;">
🏁 赛道实况
</div>
<div style="display:flex; flex-direction:column; gap:8px;">
<template x-for="horse in horses" :key="horse.id">
<div style="display:flex; align-items:center; gap:8px;">
<div style="width:30px; text-align:center; font-size:18px;" x-text="horse.emoji"></div>
<div style="flex:1; position:relative;">
{{-- 赛道背景 --}}
<div
style="height:24px; background:#e8f0f8; border-radius:10px; overflow:hidden; position:relative;">
{{-- 进度条 --}}
<div style="height:100%; border-radius:20px; transition:width .9s ease-out;"
:style="'width:' + (positions[horse.id] || 0) + '%; background:' +
(leaderId === horse.id ? '#336699' :
'#b8d0e8')">
</div>
{{-- 马匹图标(跟随进度) --}}
2026-04-12 18:01:35 +08:00
<div style="position:absolute; top:0; bottom:0; display:flex; align-items:center; font-size:18px; line-height:1; transition:left .9s ease-out, transform .25s ease-out; pointer-events:none; will-change:left,transform; z-index:1;"
2026-04-12 17:39:46 +08:00
:style="{
left: (positions[horse.id] || 0) + '%',
2026-04-12 18:01:35 +08:00
transform: 'translateX(-100%) ' + (leaderId === horse.id ? 'scale(1.2)' : 'scale(1)'),
2026-04-12 17:39:46 +08:00
animation: (positions[horse.id] || 0) > 0 ? 'horse-run .45s ease-in-out infinite alternate' : 'none'
}">
<span x-text="horse.emoji"></span>
</div>
</div>
</div>
{{-- 进度数字 --}}
<div style="width:38px; text-align:right; color:#336699; font-size:10px; font-weight:bold;"
x-text="(positions[horse.id] || 0) + '%'"></div>
</div>
</template>
</div>
<div style="margin-top:10px; text-align:center; color:#aaa; font-size:10px; text-align:center;">
🏁 终点线
</div>
</div>
{{-- ── 结算阶段(蓝白风格)── --}}
<div x-show="phase === 'settled'" style="display:none;">
{{-- 获胜马匹 --}}
<div
style="text-align:center; padding:12px 0 10px; border-bottom:1px solid #d0e4f5; margin-bottom:10px;">
<div style="font-size:36px; margin-bottom:4px;" x-text="winnerEmoji"></div>
<div style="color:#336699; font-size:17px; font-weight:bold;"
x-text="'🏆 ' + winnerName + ' 夺冠!'">
</div>
<div style="color:#888; font-size:11px; margin-top:3px;"
x-text="'注池总额:' + Number(totalPool).toLocaleString() + ' 金币'"></div>
</div>
{{-- 个人结果 --}}
<div x-show="myBet">
{{-- 中奖 --}}
<div x-show="myWon"
style="border-radius:6px; padding:12px 14px; text-align:center; margin-bottom:4px;
background:#e8fde8; border:1px solid #a3e6b0;">
<div style="font-size:24px; margin-bottom:4px;">🎉</div>
<div style="color:#16a34a; font-size:16px; font-weight:bold;">恭喜中奖!</div>
<div style="color:#15803d; font-size:18px; font-weight:bold; margin:4px 0;"
x-text="'+' + Number(myPayout).toLocaleString() + ' 💰'"></div>
<div style="color:#888; font-size:10px;"
x-text="'押「' + myBetHorseName + '」' + Number(myBetAmount).toLocaleString() + ' 金币 → 赢得 ' + Number(myPayout).toLocaleString() + ' 金币'">
</div>
</div>
{{-- 未中奖 --}}
<div x-show="!myWon"
style="border-radius:6px; padding:12px 14px; text-align:center;
background:#fff0f0; border:1px solid #fca5a5;">
<div style="font-size:20px; margin-bottom:4px;">😔</div>
<div style="color:#dc2626; font-size:13px; font-weight:bold; margin-bottom:4px;">本场未中奖
</div>
<div style="color:#888; font-size:11px;"
x-text="'押了「' + myBetHorseName + '」' + Number(myBetAmount).toLocaleString() + ' 金币,冠军是「' + winnerName + '」'">
</div>
</div>
</div>
<div x-show="!myBet" style="text-align:center; color:#aaa; font-size:12px; padding:8px 0;">
本场未参与下注
</div>
</div>
</div>
{{-- ─── 底部关闭 ─── --}}
<div
2026-04-12 17:34:07 +08:00
style="background:#fff; border-top:1px solid #d0e4f5; padding:14px 16px; display:flex; flex-direction:column; align-items:center; gap:8px;">
<button @click="close()"
style="padding:10px 48px; min-width:140px; background:#f0f6ff; border:1px solid #b0d0ee; border-radius:12px;
font-size:14px; font-weight:bold; color:#336699; cursor:pointer; transition:all .15s;"
onmouseover="this.style.background='#ddeeff'" onmouseout="this.style.background='#f0f6ff'">
2026-04-12 17:34:07 +08:00
<span x-show="phase !== 'settled'">关闭</span>
<span x-show="phase === 'settled'" x-text="'关闭 (' + settledCountdown + 's)'"></span>
</button>
2026-04-12 17:34:07 +08:00
<div x-show="phase === 'settled'" style="font-size:11px; color:#94a3b8;">窗口将在倒计时结束后自动关闭</div>
</div>
</div>
</div>
</div>
<style>
@keyframes horse-run {
0% {
transform: translateX(-2px);
}
100% {
transform: translateX(2px);
}
}
@keyframes pulse-horse {
0%,
100% {
box-shadow: 0 4px 20px rgba(245, 158, 11, .5);
}
50% {
box-shadow: 0 4px 32px rgba(245, 158, 11, .9);
}
}
</style>
2026-04-25 18:33:08 +08:00
{{-- 赛马竞猜主面板脚本已迁移到 resources/js/chat-room/horse-race-panel.js --}}