feat: add jackpot animations and enhance currency handling across components

- Introduced new CSS animations for jackpot effects to improve visual engagement.
- Integrated CurrencySwitcher into PlayerPanel and HallScreen for better currency management.
- Updated various components to utilize active player currency for consistent display.
- Enhanced event handling for currency changes to ensure real-time updates across the application.
This commit is contained in:
2026-05-25 14:31:38 +08:00
parent 2bf44e4c29
commit 9bd7cc9b9e
37 changed files with 1030 additions and 180 deletions

View File

@@ -1,8 +1,9 @@
"use client";
import { useCallback, useEffect, useState } from "react";
import { useCallback, useEffect, useRef, useState } from "react";
import { getDrawCurrent } from "@/api/draw";
import { isHallSealedCountdownUi } from "@/features/draw/draw-status-meta";
import { getLotteryEcho } from "@/lib/lottery-echo";
import { useNetworkConnectionStore } from "@/stores/network-connection-store";
import type { DrawCurrentPayload, DrawCurrentResponse } from "@/types/api/draw-current";
@@ -105,6 +106,15 @@ export function useHallDrawLive(): HallDrawLiveSnapshot {
return () => window.clearTimeout(timer);
}, [load]);
// 爆池等场景:刷新大厅快照(含奖池余额)
useEffect(() => {
const onHallRefresh = () => {
void load();
};
window.addEventListener("lottery-hall-refresh", onHallRefresh);
return () => window.removeEventListener("lottery-hall-refresh", onHallRefresh);
}, [load]);
// 本地倒计时计时器(用于 UI 更新)
useEffect(() => {
const bump = () => setNowMs(Date.now());
@@ -242,5 +252,53 @@ export function useHallDrawLive(): HallDrawLiveSnapshot {
const isBettable = display != null && display.status === "open";
const zeroRefreshKeyRef = useRef<string | null>(null);
// 本地倒计时归零时主动拉取(冷静期结束、封盘切下一期等;避免只靠手动刷新)
useEffect(() => {
if (!display) return;
const coolingEndMs = display.cooling_end_time
? Date.parse(display.cooling_end_time)
: null;
const coolingDone =
display.status === "cooldown" &&
((display.seconds_remaining_in_cooldown ?? 1) === 0 ||
(coolingEndMs !== null && !Number.isNaN(coolingEndMs) && coolingEndMs <= nowMs));
const sealedDone =
isHallSealedCountdownUi(display.status) && (display.seconds_to_draw ?? 1) === 0;
const closeDone =
display.status === "open" && (display.seconds_to_close ?? 1) === 0;
const trigger = coolingDone
? `${display.draw_no}:cooldown-end`
: sealedDone
? `${display.draw_no}:sealed-end`
: closeDone
? `${display.draw_no}:close-end`
: null;
if (trigger && zeroRefreshKeyRef.current !== trigger) {
zeroRefreshKeyRef.current = trigger;
void load();
}
}, [display, nowMs, load]);
useEffect(() => {
if (display?.draw_no) {
zeroRefreshKeyRef.current = null;
}
}, [display?.draw_no, display?.status]);
// WebSocket 已连接时的兜底轮询tick 最多 1 分钟延迟时的保险)
useEffect(() => {
const intervalId = window.setInterval(() => {
void load();
}, 45_000);
return () => window.clearInterval(intervalId);
}, [load]);
return { raw, display, serverNowMs, error, reload: load, isBettable };
}