639 lines
35 KiB
PHP
639 lines
35 KiB
PHP
{{--
|
||
文件功能:双色球彩票前台弹窗组件
|
||
|
||
选号购票面板:
|
||
- 红球 1~12 选3 + 蓝球 1~6 选1,可机选
|
||
- 支持多注购买(单次最多10注)和追加购买
|
||
- 展示当期奖池、倒计时、本期已购记录
|
||
- 展示最近10期历史开奖号码
|
||
- 规则折叠说明卡片
|
||
|
||
@author ChatRoom Laravel
|
||
@version 1.0.0
|
||
--}}
|
||
|
||
{{-- ─── 彩票面板遮罩 ─── --}}
|
||
<div id="lottery-panel" x-data="lotteryPanel()" x-show="show" x-cloak>
|
||
<div x-transition:enter="transition ease-out duration-250" x-transition:enter-start="opacity-0 scale-95"
|
||
x-transition:enter-end="opacity-100 scale-100" x-transition:leave="transition ease-in duration-180"
|
||
x-transition:leave-start="opacity-100 scale-100" x-transition:leave-end="opacity-0 scale-95"
|
||
style="position:fixed; inset:0; background:rgba(0,0,0,.55); z-index:9935;
|
||
display:flex; align-items:center; justify-content:center;">
|
||
|
||
<div
|
||
style="width:480px; max-width:96vw; max-height:92vh; border-radius:10px; overflow:hidden;
|
||
box-shadow:0 8px 32px rgba(0,0,0,.35); font-family:'Microsoft YaHei',SimSun,sans-serif;
|
||
background:#fff; display:flex; flex-direction:column;">
|
||
|
||
{{-- ─── 标题栏 ─── --}}
|
||
<div
|
||
style="background:linear-gradient(135deg,#dc2626,#ef4444); padding:10px 16px;
|
||
display:flex; align-items:center; justify-content:space-between; flex-shrink:0;">
|
||
<div>
|
||
<div style="color:#fff; font-weight:bold; font-size:14px;">🎟️ 双色球彩票</div>
|
||
<div style="color:rgba(255,255,255,.8); font-size:11px; margin-top:1px;">
|
||
第 <span x-text="issueNo">--</span> 期 |
|
||
<span x-text="isOpen ? '🟢 购票中' : (status === 'settled' ? '✅ 已开奖' : '🔴 已停售')"></span>
|
||
</div>
|
||
</div>
|
||
<div style="text-align:right;">
|
||
{{-- 奖池金额 --}}
|
||
<div style="color:#fef08a; font-size:18px; font-weight:900; line-height:1;"
|
||
x-text="'💰 ' + poolAmount.toLocaleString()"></div>
|
||
{{-- 超级期标记 --}}
|
||
<div x-show="isSuperIssue" style="color:#fcd34d; font-size:10px; font-weight:bold; margin-top:2px;">
|
||
🎊
|
||
超级期</div>
|
||
{{-- 距开奖倒计时 --}}
|
||
<div x-show="!isSuperIssue && isOpen"
|
||
style="color:rgba(255,255,255,.8); font-size:10px; margin-top:2px;"
|
||
x-text="'距开奖 ' + countdownText">
|
||
</div>
|
||
</div>
|
||
<span onclick="closeLotteryPanel()"
|
||
style="cursor:pointer; font-size:20px; color:#fff; opacity:.8; line-height:1; margin-left:12px;"
|
||
onmouseover="this.style.opacity=1" onmouseout="this.style.opacity=.8">×</span>
|
||
</div>
|
||
|
||
{{-- ─── 内容区(可滚动)─── --}}
|
||
<div style="flex:1; overflow-y:auto; background:#fafafa;">
|
||
|
||
{{-- 加载中 --}}
|
||
<div x-show="loading" style="text-align:center; padding:40px 0; color:#dc2626; font-size:13px;">
|
||
<div style="font-size:28px; margin-bottom:8px;">⏳</div>加载中…
|
||
</div>
|
||
|
||
<div x-show="!loading">
|
||
|
||
{{-- ─── 规则说明折叠区 ─── --}}
|
||
<div style="border-bottom:1px solid #fee2e2; background:#fff7f7;">
|
||
<div @click="ruleOpen=!ruleOpen"
|
||
style="padding:8px 14px; display:flex; align-items:center; justify-content:space-between;
|
||
cursor:pointer; font-size:12px; color:#b91c1c; font-weight:bold; user-select:none;">
|
||
<span>📖 玩法规则</span>
|
||
<span x-text="ruleOpen ? '▲ 收起' : '▼ 展开'" style="font-size:10px; opacity:.7;"></span>
|
||
</div>
|
||
<div x-show="ruleOpen"
|
||
style="padding:0 14px 10px; font-size:11px; color:#6b7280; line-height:1.8;">
|
||
<div>🔴 <b>红球</b> 1~12 选3 · 🎲 <b>蓝球</b> 1~6 选1,每注 <b style="color:#dc2626;">100 金币</b>
|
||
</div>
|
||
<div>每期单人最多购 <b>50 注</b>,可随时追加(停售前均可)</div>
|
||
<table style="width:100%; margin-top:6px; border-collapse:collapse;">
|
||
<tr style="background:#fee2e2;">
|
||
<th style="padding:3px 6px; text-align:left; font-size:10px;">奖级</th>
|
||
<th style="padding:3px 6px; text-align:left; font-size:10px;">条件</th>
|
||
<th style="padding:3px 6px; text-align:left; font-size:10px;">奖励</th>
|
||
</tr>
|
||
<tr>
|
||
<td style="padding:2px 6px;">🏆 一等奖</td>
|
||
<td>3红+蓝</td>
|
||
<td style="color:#dc2626;">奖池 60% 均分</td>
|
||
</tr>
|
||
<tr style="background:#fff7f7;">
|
||
<td style="padding:2px 6px;">🥇 二等奖</td>
|
||
<td>3红</td>
|
||
<td style="color:#dc2626;">奖池 20% 均分</td>
|
||
</tr>
|
||
<tr>
|
||
<td style="padding:2px 6px;">🥈 三等奖</td>
|
||
<td>2红+蓝</td>
|
||
<td>奖池 10% 均分</td>
|
||
</tr>
|
||
<tr style="background:#fff7f7;">
|
||
<td style="padding:2px 6px;">🥉 四等奖</td>
|
||
<td>2红</td>
|
||
<td>固定 150 金/注</td>
|
||
</tr>
|
||
<tr>
|
||
<td style="padding:2px 6px;">🎫 五等奖</td>
|
||
<td>1红+蓝</td>
|
||
<td>固定 50 金/注</td>
|
||
</tr>
|
||
</table>
|
||
<div style="margin-top:6px; color:#9ca3af;">无一等奖 → 奖池滚存至下期;连续3期无人中 → 超级期系统注入奖池</div>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- 已开奖结果展示 --}}
|
||
<div x-show="status === 'settled' && drawRed1"
|
||
style="padding:10px 14px; background:#fff5f5; border-bottom:1px solid #fee2e2; text-align:center;">
|
||
<div style="font-size:12px; color:#b91c1c; font-weight:bold; margin-bottom:6px;">🎊 开奖结果</div>
|
||
<div style="display:flex; justify-content:center; gap:8px; align-items:center; flex-wrap:wrap;">
|
||
<template x-for="(n, $index) in [drawRed1, drawRed2, drawRed3]" :key="$index">
|
||
<span
|
||
style="width:32px; height:32px; border-radius:50%; background:#dc2626;
|
||
color:#fff; font-weight:bold; font-size:14px;
|
||
display:flex; align-items:center; justify-content:center;"
|
||
x-text="n !== null ? String(n).padStart(2,'0') : '--'"></span>
|
||
</template>
|
||
<span style="color:#6b7280; font-size:18px; font-weight:bold;">+</span>
|
||
<span
|
||
style="width:32px; height:32px; border-radius:50%; background:#2563eb;
|
||
color:#fff; font-weight:bold; font-size:14px;
|
||
display:flex; align-items:center; justify-content:center;"
|
||
x-text="drawBlue"></span>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- ─── 选号区 ─── --}}
|
||
<div x-show="isOpen" style="padding:12px 14px;">
|
||
|
||
{{-- 红球选择 --}}
|
||
<div style="margin-bottom:10px;">
|
||
<div style="font-size:12px; font-weight:bold; color:#b91c1c; margin-bottom:6px;">
|
||
🔴 红球(已选 <span x-text="selectedReds.length" style="color:#dc2626;"></span>/3)
|
||
</div>
|
||
<div style="display:grid; grid-template-columns:repeat(6,1fr); gap:5px;">
|
||
<template x-for="n in 12" :key="n">
|
||
<button @click="toggleRed(n)"
|
||
:style="selectedReds.includes(n) ?
|
||
'background:#dc2626; color:#fff; border:2px solid #b91c1c; font-weight:bold;' :
|
||
'background:#fff; color:#dc2626; border:2px solid #fca5a5;'"
|
||
style="border-radius:50%; width:38px; height:38px; font-size:13px;
|
||
cursor:pointer; transition:all .15s; display:flex; align-items:center; justify-content:center;"
|
||
x-text="String(n).padStart(2,'0')">
|
||
</button>
|
||
</template>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- 蓝球选择 --}}
|
||
<div style="margin-bottom:12px;">
|
||
<div style="font-size:12px; font-weight:bold; color:#1d4ed8; margin-bottom:6px;">
|
||
🎲 蓝球(骰子点数,已选 <span x-text="selectedBlue ?? '—'" style="color:#2563eb;"></span>)
|
||
</div>
|
||
<div style="display:flex; gap:6px; flex-wrap:wrap;">
|
||
<template x-for="n in 6" :key="n">
|
||
<button @click="selectedBlue = (selectedBlue === n ? null : n)"
|
||
:style="selectedBlue === n ?
|
||
'background:#2563eb; color:#fff; border:2px solid #1d4ed8; font-weight:bold;' :
|
||
'background:#fff; color:#2563eb; border:2px solid #93c5fd;'"
|
||
style="border-radius:50%; width:38px; height:38px; font-size:16px;
|
||
cursor:pointer; transition:all .15s;"
|
||
x-text="['🎲','⚀','⚁','⚂','⚃','⚄','⚅'][n]">
|
||
</button>
|
||
</template>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- 当前选号预览 --}}
|
||
<div x-show="selectedReds.length > 0 || selectedBlue"
|
||
style="background:#fff7f7; border:1px dashed #fca5a5; border-radius:8px;
|
||
padding:8px 12px; margin-bottom:10px; font-size:12px; color:#6b7280;">
|
||
已选:
|
||
<template x-for="n in [...selectedReds].sort((a,b)=>a-b)" :key="n">
|
||
<span
|
||
style="display:inline-block; width:26px; height:26px; border-radius:50%; background:#dc2626;
|
||
color:#fff; font-size:11px; font-weight:bold; text-align:center; line-height:26px; margin:0 2px;"
|
||
x-text="String(n).padStart(2,'0')"></span>
|
||
</template>
|
||
<span x-show="selectedBlue"
|
||
style="display:inline-block; width:26px; height:26px; border-radius:50%; background:#2563eb;
|
||
color:#fff; font-size:11px; font-weight:bold; text-align:center; line-height:26px; margin-left:6px;"
|
||
x-text="selectedBlue">
|
||
</span>
|
||
</div>
|
||
|
||
{{-- 操作按钮行(机选1注 + 机选3注 + 清空选号) --}}
|
||
<div style="display:flex; gap:8px; margin-bottom:12px;">
|
||
<button @click="doQuickPick(1)"
|
||
style="flex:1; padding:10px 0; border-radius:10px; font-size:13px; font-weight:bold;
|
||
background:#f0f6ff; color:#336699; border:1.5px solid #c0d8ef;
|
||
cursor:pointer; transition:all .15s; font-family:inherit;"
|
||
onmouseover="this.style.background='#dbeafe'; this.style.borderColor='#93c5fd'"
|
||
onmouseout="this.style.background='#f0f6ff'; this.style.borderColor='#c0d8ef'">
|
||
🎲 机选
|
||
</button>
|
||
<button @click="doQuickPick(3)"
|
||
style="flex:1; padding:10px 0; border-radius:10px; font-size:13px; font-weight:bold;
|
||
background:linear-gradient(135deg,#d97706,#f59e0b); color:#fff; border:none;
|
||
box-shadow:0 3px 10px rgba(217,119,6,.25); cursor:pointer;
|
||
transition:all .15s; font-family:inherit;"
|
||
onmouseover="this.style.transform='translateY(-1px)'; this.style.boxShadow='0 5px 14px rgba(217,119,6,.35)'"
|
||
onmouseout="this.style.transform=''; this.style.boxShadow='0 3px 10px rgba(217,119,6,.25)'">
|
||
🎰 机选 3 注
|
||
</button>
|
||
<button type="button" @click.prevent="selectedReds=[]; selectedBlue=null; cart=[];"
|
||
style="flex:1; padding:10px 0; border-radius:10px; font-size:13px; font-weight:bold;
|
||
background:#f9fafb; color:#6b7280; border:1.5px solid #e5e7eb;
|
||
cursor:pointer; transition:all .15s; font-family:inherit;"
|
||
onmouseover="this.style.background='#f3f4f6'"
|
||
onmouseout="this.style.background='#f9fafb'">
|
||
🗑 清空选号
|
||
</button>
|
||
</div>
|
||
|
||
{{-- 购票结果提示 --}}
|
||
<div id="lottery-buy-msg"
|
||
style="display:none; border-radius:8px; padding:8px 12px; text-align:center;
|
||
margin-bottom:4px; font-size:12px; font-weight:bold;">
|
||
</div>
|
||
|
||
</div>
|
||
|
||
{{-- ─── 购物车(待购清单) ─── --}}
|
||
<div x-show="isOpen && cart.length > 0"
|
||
style="padding:10px 14px; border-top:1px solid #fee2e2;">
|
||
<div style="font-size:12px; font-weight:bold; color:#b91c1c; margin-bottom:6px;">
|
||
🧺 待购清单(<span x-text="cart.length"></span> 注)
|
||
</div>
|
||
<div style="max-height:120px; overflow-y:auto;">
|
||
<template x-for="(item, idx) in cart" :key="idx">
|
||
<div style="display:flex; align-items:center; justify-content:space-between;
|
||
font-size:11px; padding:4px 0; border-bottom:1px dashed #fee2e2;">
|
||
<div style="display:flex; align-items:center; gap:3px;">
|
||
<span style="color:#9ca3af; min-width:28px;" x-text="'注'+(idx+1)"></span>
|
||
<template x-for="(r, $ri) in item.reds" :key="$ri">
|
||
<span
|
||
style="width:18px; height:18px; border-radius:50%; background:#dc2626;
|
||
color:#fff; font-size:9px; text-align:center; line-height:18px;"
|
||
x-text="String(r).padStart(2,'0')"></span>
|
||
</template>
|
||
<span
|
||
style="width:18px; height:18px; border-radius:50%; background:#2563eb;
|
||
color:#fff; font-size:9px; text-align:center; line-height:18px; margin-left:2px;"
|
||
x-text="item.blue"></span>
|
||
<span x-show="item.quick" style="color:#9ca3af; font-size:10px;">机选</span>
|
||
</div>
|
||
{{-- 删除单条 --}}
|
||
<button @click="cart.splice(idx,1)"
|
||
style="background:none; border:none; color:#9ca3af; cursor:pointer;
|
||
font-size:14px; line-height:1; padding:0 2px;"
|
||
title="移除">×</button>
|
||
</div>
|
||
</template>
|
||
</div>
|
||
{{-- 确认购买 --}}
|
||
<button @click="submitCart()"
|
||
:disabled="buying"
|
||
style="margin-top:8px; width:100%; padding:10px 0; border-radius:10px; font-size:13px;
|
||
font-weight:bold; background:linear-gradient(135deg,#dc2626,#b91c1c);
|
||
color:#fff; border:none; cursor:pointer; transition:all .15s; font-family:inherit;"
|
||
onmouseover="this.style.opacity='0.88'"
|
||
onmouseout="this.style.opacity='1'">
|
||
<span x-text="buying ? '⏳ 购买中…' : '✅ 确认购买(' + cart.length + ' 注)'"></span>
|
||
</button>
|
||
</div>
|
||
|
||
{{-- 停售/已开奖时的提示 --}}
|
||
<div x-show="!isOpen && status !== 'settled'"
|
||
style="padding:16px 14px; text-align:center; color:#b91c1c; font-size:13px;">
|
||
🔴 本期已停售,等待开奖中…
|
||
</div>
|
||
|
||
{{-- ─── 本期我的购票记录 ─── --}}
|
||
<div x-show="myTickets.length > 0" style="padding:10px 14px; border-top:1px solid #fee2e2;">
|
||
<div style="font-size:12px; font-weight:bold; color:#b91c1c; margin-bottom:6px;">
|
||
📋 本期我的购票(<span x-text="myTickets.length"></span> 注)
|
||
</div>
|
||
<div style="max-height:120px; overflow-y:auto;">
|
||
<template x-for="(t, idx) in myTickets" :key="t.id">
|
||
<div
|
||
style="display:flex; align-items:center; justify-content:space-between;
|
||
font-size:11px; padding:4px 0; border-bottom:1px dashed #fee2e2;">
|
||
<div style="display:flex; align-items:center; gap:3px;">
|
||
<span style="color:#9ca3af; min-width:28px;" x-text="'注'+(idx+1)"></span>
|
||
<template x-for="(r, $ri) in [t.red1,t.red2,t.red3]" :key="$ri">
|
||
<span
|
||
style="width:20px; height:20px; border-radius:50%; background:#dc2626;
|
||
color:#fff; font-size:10px; text-align:center; line-height:20px;"
|
||
x-text="String(r).padStart(2,'0')"></span>
|
||
</template>
|
||
<span
|
||
style="width:20px; height:20px; border-radius:50%; background:#2563eb;
|
||
color:#fff; font-size:11px; text-align:center; line-height:20px; margin-left:2px;"
|
||
x-text="t.blue"></span>
|
||
<span x-show="t.is_quick" style="color:#9ca3af; font-size:10px;">机选</span>
|
||
</div>
|
||
{{-- 中奖标记 --}}
|
||
<span x-show="t.prize_level > 0"
|
||
style="color:#dc2626; font-weight:bold; font-size:11px;"
|
||
x-text="['','🏆一等','🥇二等','🥈三等','🥉四等','🎫五等'][t.prize_level] + ' +' + t.payout.toLocaleString()"></span>
|
||
<span x-show="t.prize_level === 0 && status === 'settled'"
|
||
style="color:#9ca3af; font-size:11px;">未中奖</span>
|
||
</div>
|
||
</template>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- ─── 历史开奖记录 ─── --}}
|
||
<div style="padding:10px 14px; border-top:1px solid #fee2e2;">
|
||
<div style="font-size:12px; font-weight:bold; color:#b91c1c; margin-bottom:6px;">📜 近期开奖</div>
|
||
<div x-show="history.length === 0"
|
||
style="font-size:11px; color:#9ca3af; text-align:center; padding:8px 0;">
|
||
暂无历史记录
|
||
</div>
|
||
<div style="overflow-x:auto;">
|
||
<table style="width:100%; font-size:10px; border-collapse:collapse; min-width:300px;">
|
||
<tr style="background:#fee2e2; color:#b91c1c;">
|
||
<th style="padding:3px 5px; text-align:left;">期号</th>
|
||
<th style="padding:3px 5px;">开奖号码</th>
|
||
<th style="padding:3px 5px; text-align:right;">奖池</th>
|
||
</tr>
|
||
<template x-for="(h, i) in history.slice(0,8)" :key="h.issue_no">
|
||
<tr :style="i % 2 === 0 ? '' : 'background:#fff7f7;'">
|
||
<td style="padding:3px 5px; color:#6b7280;" x-text="h.issue_no"></td>
|
||
<td style="padding:3px 5px; text-align:center;">
|
||
<template x-for="(r, $ri) in [h.red1,h.red2,h.red3]"
|
||
:key="$ri">
|
||
<span
|
||
style="display:inline-block; width:18px; height:18px; border-radius:50%;
|
||
background:#dc2626; color:#fff; font-size:9px; font-weight:bold;
|
||
text-align:center; line-height:18px; margin:0 1px;"
|
||
x-text="String(r).padStart(2,'0')"></span>
|
||
</template>
|
||
<span
|
||
style="display:inline-block; width:18px; height:18px; border-radius:50%;
|
||
background:#2563eb; color:#fff; font-size:9px; font-weight:bold;
|
||
text-align:center; line-height:18px; margin-left:3px;"
|
||
x-text="h.blue"></span>
|
||
</td>
|
||
<td style="padding:3px 5px; text-align:right; color:#dc2626;"
|
||
x-text="'💰' + Number(h.pool_amount).toLocaleString()"></td>
|
||
</tr>
|
||
</template>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
</div>{{-- /!loading --}}
|
||
</div>{{-- /内容区 --}}
|
||
|
||
{{-- ─── 底部操作栏 ─── --}}
|
||
<div
|
||
style="padding:10px 14px; background:#fff; border-top:1px solid #fee2e2;
|
||
display:flex; justify-content:space-between; align-items:center; flex-shrink:0;">
|
||
<button @click="loadData()"
|
||
style="padding:9px 18px; border-radius:20px; font-size:12px; font-weight:bold;
|
||
background:#f0f6ff; color:#336699; border:1.5px solid #c0d8ef;
|
||
cursor:pointer; transition:all .15s; font-family:inherit;"
|
||
onmouseover="this.style.background='#dbeafe'" onmouseout="this.style.background='#f0f6ff'">
|
||
🔄 刷新
|
||
</button>
|
||
<button @click="closeLotteryPanel()"
|
||
style="padding:9px 18px; border-radius:20px; font-size:12px; font-weight:bold;
|
||
background:#f9fafb; color:#6b7280; border:1.5px solid #e5e7eb;
|
||
cursor:pointer; transition:all .15s; font-family:inherit;"
|
||
onmouseover="this.style.background='#f3f4f6'" onmouseout="this.style.background='#f9fafb'">
|
||
关闭
|
||
</button>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
/**
|
||
* 双色球彩票面板 Alpine.js 组件
|
||
*/
|
||
function lotteryPanel() {
|
||
return {
|
||
// ─── 状态 ───
|
||
show: false,
|
||
loading: true,
|
||
ruleOpen: false,
|
||
buying: false,
|
||
|
||
// ─── 期次数据 ───
|
||
issueNo: '--',
|
||
status: 'open',
|
||
isOpen: false,
|
||
isSuperIssue: false,
|
||
poolAmount: 0,
|
||
secondsLeft: 0,
|
||
drawAt: null,
|
||
drawRed1: null,
|
||
drawRed2: null,
|
||
drawRed3: null,
|
||
drawBlue: null,
|
||
|
||
// ─── 选号 ───
|
||
selectedReds: [],
|
||
selectedBlue: null,
|
||
cart: [], // 待购清单
|
||
|
||
// ─── 数据 ───
|
||
myTickets: [],
|
||
history: [],
|
||
|
||
// ─── 倒计时 ───
|
||
_timer: null,
|
||
|
||
/**
|
||
* 格式化倒计时文字(如 4h 22m 或 01:59)
|
||
*/
|
||
get countdownText() {
|
||
const s = this.secondsLeft;
|
||
if (s <= 0) return '即将开奖';
|
||
if (s >= 3600) return `${Math.floor(s/3600)}h ${Math.floor((s%3600)/60)}m`;
|
||
const m = Math.floor(s / 60);
|
||
const sec = s % 60;
|
||
return `${String(m).padStart(2,'0')}:${String(sec).padStart(2,'0')}`;
|
||
},
|
||
|
||
/**
|
||
* 打开面板并加载数据
|
||
*/
|
||
async open() {
|
||
this.show = true;
|
||
await this.loadData();
|
||
this.startTimer();
|
||
},
|
||
|
||
/**
|
||
* 加载当期状态、我的购票、历史开奖
|
||
*/
|
||
async loadData() {
|
||
this.loading = true;
|
||
try {
|
||
const [currentRes, histRes] = await Promise.all([
|
||
fetch('/lottery/current', {
|
||
headers: {
|
||
'Accept': 'application/json'
|
||
}
|
||
}),
|
||
fetch('/lottery/history', {
|
||
headers: {
|
||
'Accept': 'application/json'
|
||
}
|
||
}),
|
||
]);
|
||
const current = await currentRes.json();
|
||
const hist = await histRes.json();
|
||
|
||
if (current.issue) {
|
||
const iss = current.issue;
|
||
this.issueNo = iss.issue_no;
|
||
this.status = iss.status;
|
||
this.isOpen = current.is_open;
|
||
this.isSuperIssue = iss.is_super_issue;
|
||
this.poolAmount = iss.pool_amount;
|
||
this.secondsLeft = iss.seconds_left;
|
||
this.drawRed1 = iss.red1;
|
||
this.drawRed2 = iss.red2;
|
||
this.drawRed3 = iss.red3;
|
||
this.drawBlue = iss.blue;
|
||
}
|
||
this.myTickets = current.my_tickets ?? [];
|
||
this.history = hist.issues ?? [];
|
||
} catch (e) {
|
||
// 网络异常静默处理
|
||
}
|
||
this.loading = false;
|
||
},
|
||
|
||
/**
|
||
* 启动倒计时 ticker
|
||
*/
|
||
startTimer() {
|
||
clearInterval(this._timer);
|
||
this._timer = setInterval(() => {
|
||
if (this.secondsLeft > 0) {
|
||
this.secondsLeft--;
|
||
}
|
||
}, 1000);
|
||
},
|
||
|
||
/**
|
||
* 切换红球选择状态
|
||
*/
|
||
toggleRed(n) {
|
||
if (this.selectedReds.includes(n)) {
|
||
this.selectedReds = this.selectedReds.filter(r => r !== n);
|
||
} else if (this.selectedReds.length < 3) {
|
||
this.selectedReds = [...this.selectedReds, n];
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 服务端机选号码(立即加入购物车)
|
||
*/
|
||
async doQuickPick(count = 1) {
|
||
try {
|
||
const res = await fetch(`/lottery/quick-pick?count=${count}`);
|
||
const data = await res.json();
|
||
for (const num of data.numbers) {
|
||
if (this.cart.length < 10) {
|
||
this.cart.push({
|
||
reds: num.reds,
|
||
blue: num.blue,
|
||
quick: true
|
||
});
|
||
}
|
||
}
|
||
// 清空当前选号
|
||
this.selectedReds = [];
|
||
this.selectedBlue = null;
|
||
} catch {}
|
||
},
|
||
|
||
/**
|
||
* 将当前选号加入购物车
|
||
*/
|
||
addToCart() {
|
||
if (this.selectedReds.length !== 3 || !this.selectedBlue) {
|
||
showLotteryMsg('⚠️ 请选满 3 个红球和 1 个蓝球', false);
|
||
return;
|
||
}
|
||
if (this.cart.length >= 10) {
|
||
showLotteryMsg('⚠️ 单次最多加入 10 注', false);
|
||
return;
|
||
}
|
||
this.cart.push({
|
||
reds: [...this.selectedReds].sort((a, b) => a - b),
|
||
blue: this.selectedBlue,
|
||
quick: false
|
||
});
|
||
// 清空选号等待下一注
|
||
this.selectedReds = [];
|
||
this.selectedBlue = null;
|
||
},
|
||
|
||
/**
|
||
* 提交购物车(批量购买)
|
||
*/
|
||
async submitCart() {
|
||
if (this.cart.length === 0 || this.buying) return;
|
||
this.buying = true;
|
||
try {
|
||
const res = await fetch('/lottery/buy', {
|
||
method: 'POST',
|
||
headers: {
|
||
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content,
|
||
'Content-Type': 'application/json',
|
||
'Accept': 'application/json',
|
||
},
|
||
body: JSON.stringify({
|
||
numbers: this.cart.map(c => ({
|
||
reds: c.reds,
|
||
blue: c.blue
|
||
})),
|
||
quick_pick: false,
|
||
}),
|
||
});
|
||
const data = await res.json();
|
||
if (res.ok && data.status === 'success') {
|
||
showLotteryMsg('✅ ' + data.message, true);
|
||
this.cart = [];
|
||
|
||
// 更新金币余额显示
|
||
if (window.chatContext) {
|
||
window.chatContext.userJjb = Math.max(0, (window.chatContext.userJjb ?? 0) - data
|
||
.count * 100);
|
||
}
|
||
|
||
// 刷新我的购票列表
|
||
await this.loadData();
|
||
} else {
|
||
showLotteryMsg('❌ ' + (data.message || '购票失败'), false);
|
||
}
|
||
} catch {
|
||
showLotteryMsg('🌐 网络异常,请稍后重试', false);
|
||
}
|
||
this.buying = false;
|
||
},
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 显示彩票面板内联消息(3s 后自动消失)
|
||
*
|
||
* @param {string} msg
|
||
* @param {boolean} success
|
||
*/
|
||
function showLotteryMsg(msg, success) {
|
||
const el = document.getElementById('lottery-buy-msg');
|
||
if (!el) return;
|
||
el.style.background = success ? '#f0fdf4' : '#fff5f5';
|
||
el.style.border = success ? '1px solid #86efac' : '1px solid #fecaca';
|
||
el.style.color = success ? '#16a34a' : '#dc2626';
|
||
el.textContent = msg;
|
||
el.style.display = 'block';
|
||
el.style.opacity = '1';
|
||
clearTimeout(el._t);
|
||
el._t = setTimeout(() => {
|
||
el.style.opacity = '0';
|
||
setTimeout(() => {
|
||
el.style.display = 'none';
|
||
}, 400);
|
||
}, 3000);
|
||
}
|
||
|
||
/** 打开彩票面板 */
|
||
window.openLotteryPanel = function() {
|
||
const panel = document.getElementById('lottery-panel');
|
||
if (panel) Alpine.$data(panel).open();
|
||
};
|
||
|
||
/** 关闭彩票面板 */
|
||
window.closeLotteryPanel = function() {
|
||
const panel = document.getElementById('lottery-panel');
|
||
if (panel) {
|
||
const data = Alpine.$data(panel);
|
||
data.show = false;
|
||
clearInterval(data._timer);
|
||
}
|
||
};
|
||
</script>
|