🪙 在多数平台/字体上渲染为银灰色,与「金币」语义不符; 💰 各平台均渲染为金黄色,更直观传达金币概念。 涉及文件(43处): - app/Jobs:百家乐、赛马结算广播 - app/Http/Controllers:管理员命令、红包、老虎机、神秘箱子 - app/Listeners - resources/views:聊天室各游戏面板、商店、toolbar、后台页面等
226 lines
9.8 KiB
PHP
226 lines
9.8 KiB
PHP
{{--
|
||
文件功能:节日福利弹窗组件
|
||
|
||
后台配置的节日活动触发时,通过 WebSocket 广播到达前端,
|
||
弹出全屏福利领取弹窗,用户点击领取后金币自动入账。
|
||
|
||
WebSocket 监听:chat:holiday.started
|
||
领取接口:POST /holiday/{event}/claim
|
||
--}}
|
||
|
||
{{-- ─── 节日福利领取弹窗 ─── --}}
|
||
<div id="holiday-event-modal" x-data="holidayEventModal()" x-show="show" x-cloak>
|
||
<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"
|
||
style="position:fixed; inset:0; background:rgba(0,0,0,.65); z-index:9950; display:flex; align-items:center; justify-content:center;">
|
||
|
||
<div
|
||
style="width:400px; max-width:95vw; border-radius:24px; overflow:hidden; text-align:center;
|
||
box-shadow:0 24px 80px rgba(245,158,11,.4);">
|
||
|
||
{{-- 顶部渐变区域 --}}
|
||
<div style="background:linear-gradient(145deg,#92400e,#b45309,#d97706); padding:28px 24px 20px;">
|
||
{{-- 主图标动效 --}}
|
||
<div style="font-size:56px; margin-bottom:10px; animation:holiday-bounce 1.2s infinite;">🎊</div>
|
||
<div style="color:#fef3c7; font-weight:bold; font-size:20px; margin-bottom:4px;" x-text="eventName">
|
||
</div>
|
||
<div style="color:rgba(254,243,199,.8); font-size:13px;" x-text="eventDesc"></div>
|
||
</div>
|
||
|
||
{{-- 主体内容 --}}
|
||
<div style="background:linear-gradient(160deg,#7c2d12,#9a3412); padding:20px 24px;">
|
||
|
||
{{-- 奖池信息 --}}
|
||
<div style="background:rgba(0,0,0,.25); border-radius:14px; padding:12px 16px; margin-bottom:16px;">
|
||
<div style="color:rgba(254,243,199,.6); font-size:11px; margin-bottom:4px;">💰 本次节日总奖池</div>
|
||
<div style="color:#fcd34d; font-size:24px; font-weight:bold;"
|
||
x-text="totalAmount.toLocaleString() + ' 金币'"></div>
|
||
<div style="color:rgba(254,243,199,.5); font-size:11px; margin-top:4px;">
|
||
<span x-show="maxClaimants > 0" x-text="'前 ' + maxClaimants + ' 名在线用户可领取'"></span>
|
||
<span x-show="maxClaimants === 0">全体在线用户均可领取</span>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- 有效期 --}}
|
||
<div style="color:rgba(254,243,199,.55); font-size:11px; margin-bottom:14px;">
|
||
领取有效期 <strong style="color:#fcd34d;" x-text="expiresIn"></strong>,过期作废
|
||
</div>
|
||
|
||
{{-- 领取按钮 --}}
|
||
<div x-show="!claimed">
|
||
<div style="background:rgba(0,0,0,.3); border-radius:16px; padding:5px;">
|
||
<button x-on:click="doClaim()" :disabled="claiming"
|
||
style="display:block; width:100%; padding:14px 0; border:none; border-radius:12px;
|
||
font-size:16px; font-weight:bold; cursor:pointer; transition:all .15s;
|
||
letter-spacing:1px; color:#fff;"
|
||
:style="claiming
|
||
?
|
||
'background:#b45309; opacity:.65; cursor:not-allowed;' :
|
||
'background:#d97706; box-shadow:0 2px 12px rgba(0,0,0,.4);'"
|
||
onmouseover="if(!this.disabled) this.style.filter='brightness(1.12)'"
|
||
onmouseout="this.style.filter=''">
|
||
<span x-text="claiming ? '领取中…' : '🎁 立即领取福利'"></span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- 已领取 --}}
|
||
<div x-show="claimed" style="display:none;">
|
||
<div style="font-size:36px; margin-bottom:6px; color:#fcd34d; font-weight:bold;"
|
||
x-text="'+' + claimedAmount.toLocaleString() + ' 金币'"></div>
|
||
<div style="color:#fef3c7; font-size:13px;">🎉 恭喜!节日福利已入账!</div>
|
||
<div style="color:rgba(254,243,199,.6); font-size:11px; margin-top:4px;">金币已自动到账,新年快乐 🥳</div>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- 关闭按钮 --}}
|
||
<div style="background:rgba(120,40,10,.95); padding:14px 20px;">
|
||
<button x-on:click="close()"
|
||
style="padding:9px 32px; background:rgba(0,0,0,.35); border:none; border-radius:30px;
|
||
font-size:12px; color:rgba(254,243,199,.7); cursor:pointer; transition:all .2s;"
|
||
onmouseover="this.style.background='rgba(0,0,0,.5)'"
|
||
onmouseout="this.style.background='rgba(0,0,0,.35)'">
|
||
<span x-text="claimed ? '收好了 ✨' : '关闭'"></span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<style>
|
||
@keyframes holiday-bounce {
|
||
|
||
0%,
|
||
100% {
|
||
transform: scale(1) rotate(0deg);
|
||
}
|
||
|
||
25% {
|
||
transform: scale(1.1) rotate(-5deg);
|
||
}
|
||
|
||
75% {
|
||
transform: scale(1.1) rotate(5deg);
|
||
}
|
||
}
|
||
</style>
|
||
|
||
<script>
|
||
/**
|
||
* 节日福利弹窗组件
|
||
* 监听 WebSocket 事件 holiday.started,弹出领取弹窗
|
||
*/
|
||
function holidayEventModal() {
|
||
return {
|
||
show: false,
|
||
claiming: false,
|
||
claimed: false,
|
||
|
||
// 活动数据
|
||
eventId: null,
|
||
eventName: '',
|
||
eventDesc: '',
|
||
totalAmount: 0,
|
||
maxClaimants: 0,
|
||
distributeType: 'random',
|
||
fixedAmount: null,
|
||
expiresAt: null,
|
||
expiresIn: '',
|
||
claimedAmount: 0,
|
||
|
||
/**
|
||
* 打开弹窗并填充活动数据
|
||
*/
|
||
open(detail) {
|
||
this.eventId = detail.event_id;
|
||
this.eventName = detail.name ?? '节日福利';
|
||
this.eventDesc = detail.description ?? '';
|
||
this.totalAmount = detail.total_amount ?? 0;
|
||
this.maxClaimants = detail.max_claimants ?? 0;
|
||
this.distributeType = detail.distribute_type ?? 'random';
|
||
this.fixedAmount = detail.fixed_amount;
|
||
this.expiresAt = detail.expires_at ? new Date(detail.expires_at) : null;
|
||
this.claimed = false;
|
||
this.claiming = false;
|
||
this.claimedAmount = 0;
|
||
this.updateExpiresIn();
|
||
this.show = true;
|
||
},
|
||
|
||
/**
|
||
* 关闭弹窗
|
||
*/
|
||
close() {
|
||
this.show = false;
|
||
},
|
||
|
||
/**
|
||
* 更新有效期显示文字
|
||
*/
|
||
updateExpiresIn() {
|
||
if (!this.expiresAt) {
|
||
this.expiresIn = '30 分钟';
|
||
return;
|
||
}
|
||
const diff = Math.max(0, Math.round((this.expiresAt - Date.now()) / 60000));
|
||
this.expiresIn = diff > 0 ? diff + ' 分钟' : '即将过期';
|
||
},
|
||
|
||
/**
|
||
* 发起领取请求
|
||
*/
|
||
async doClaim() {
|
||
if (this.claiming || this.claimed || !this.eventId) return;
|
||
this.claiming = true;
|
||
|
||
try {
|
||
const res = await fetch(`/holiday/${this.eventId}/claim`, {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'Accept': 'application/json',
|
||
'X-CSRF-TOKEN': document.querySelector('meta[name=csrf-token]').content,
|
||
},
|
||
});
|
||
const data = await res.json();
|
||
|
||
if (data.ok) {
|
||
this.claimed = true;
|
||
this.claimedAmount = data.amount || 0;
|
||
} else {
|
||
window.chatDialog?.alert(data.message || '领取失败,请稍后重试。', '提示', '#f59e0b');
|
||
if (data.message?.includes('已结束') || data.message?.includes('过期')) {
|
||
this.close();
|
||
}
|
||
}
|
||
} catch {
|
||
window.chatDialog?.alert('网络异常,请稍后重试。', '错误', '#cc4444');
|
||
}
|
||
|
||
this.claiming = false;
|
||
},
|
||
};
|
||
}
|
||
|
||
// ─── WebSocket 事件监听:节日福利开始 ─────────────────────────
|
||
window.addEventListener('chat:holiday.started', (e) => {
|
||
const detail = e.detail;
|
||
|
||
// 公屏追加系统消息
|
||
if (typeof appendSystemMessage === 'function') {
|
||
const typeLabel = detail.distribute_type === 'fixed' ?
|
||
`每人固定 ${Number(detail.fixed_amount).toLocaleString()} 金币` :
|
||
'随机金额';
|
||
const quotaText = detail.max_claimants > 0 ? `前 ${detail.max_claimants} 名` : '全体';
|
||
appendSystemMessage(
|
||
`🎊 【${detail.name}】节日福利开始啦!总奖池 💰${Number(detail.total_amount).toLocaleString()} 金币,${typeLabel},${quotaText}在线用户可领取!`
|
||
);
|
||
}
|
||
|
||
// 弹出全屏领取弹窗
|
||
const el = document.getElementById('holiday-event-modal');
|
||
if (el) Alpine.$data(el).open(detail);
|
||
});
|
||
</script>
|