feat: enhance draw status and scheduling display
- Updated DrawStatusHud to include a new countdown kind "start" for better status representation. - Refactored HallDrawPanel to improve time display logic, differentiating between scheduled start and close times. - Added new translations for scheduled start and close times in multiple languages. - Enhanced time formatting functions to support new scheduling features and improve user experience.
This commit is contained in:
@@ -26,23 +26,36 @@ export type HallWsEnvelope = {
|
||||
emitted_at_ms?: number;
|
||||
};
|
||||
|
||||
function secondsUntilIso(iso: string | null | undefined, effectiveNowMs: number): number {
|
||||
if (iso == null || iso === "") {
|
||||
return 0;
|
||||
}
|
||||
const targetMs = Date.parse(iso);
|
||||
if (Number.isNaN(targetMs)) {
|
||||
return 0;
|
||||
}
|
||||
return Math.max(0, Math.ceil((targetMs - effectiveNowMs) / 1000));
|
||||
}
|
||||
|
||||
/**
|
||||
* 「服务器时间为准」:以载荷里的 `seconds_*` 为基准、`emitted_at_ms` 为锚点在本地推演。
|
||||
* 以服务端 `server_now_ms` 为锚、本地时钟仅负责推进,倒计时与 ISO 时刻一致。
|
||||
*/
|
||||
function applySnapshotDrift(
|
||||
payload: DrawCurrentPayload,
|
||||
emittedAtMs: number,
|
||||
nowMs: number,
|
||||
clientNowMs: number,
|
||||
serverNowMs: number,
|
||||
): DrawCurrentPayload {
|
||||
const elapsed = Math.max(0, Math.floor((nowMs - emittedAtMs) / 1000));
|
||||
const effectiveNowMs = serverNowMs + (clientNowMs - emittedAtMs);
|
||||
return {
|
||||
...payload,
|
||||
seconds_to_close: Math.max(0, payload.seconds_to_close - elapsed),
|
||||
seconds_to_draw: Math.max(0, payload.seconds_to_draw - elapsed),
|
||||
seconds_to_close: secondsUntilIso(payload.close_time, effectiveNowMs),
|
||||
seconds_to_start: secondsUntilIso(payload.start_time, effectiveNowMs),
|
||||
seconds_to_draw: secondsUntilIso(payload.draw_time, effectiveNowMs),
|
||||
seconds_remaining_in_cooldown:
|
||||
payload.seconds_remaining_in_cooldown == null
|
||||
payload.cooling_end_time == null
|
||||
? null
|
||||
: Math.max(0, payload.seconds_remaining_in_cooldown - elapsed),
|
||||
: secondsUntilIso(payload.cooling_end_time, effectiveNowMs),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -73,14 +86,18 @@ export function useHallDrawLive(): HallDrawLiveSnapshot {
|
||||
);
|
||||
|
||||
const mergeFromWs = useCallback((evt: HallWsEnvelope) => {
|
||||
const anchor = evt.emitted_at_ms ?? Date.now();
|
||||
setServerNowMs(anchor);
|
||||
setRaw(evt.data);
|
||||
setEmittedAtMs(evt.emitted_at_ms ?? Date.now());
|
||||
setEmittedAtMs(anchor);
|
||||
}, []);
|
||||
|
||||
const mergeCountdownFromWs = useCallback((evt: HallWsEnvelope) => {
|
||||
if (evt.data === null) return;
|
||||
const anchor = evt.emitted_at_ms ?? Date.now();
|
||||
setServerNowMs(anchor);
|
||||
setRaw(evt.data);
|
||||
setEmittedAtMs(evt.emitted_at_ms ?? Date.now());
|
||||
setEmittedAtMs(anchor);
|
||||
}, []);
|
||||
|
||||
const updateFromResponse = useCallback((resp: DrawCurrentResponse) => {
|
||||
@@ -250,7 +267,9 @@ export function useHallDrawLive(): HallDrawLiveSnapshot {
|
||||
}, [isWebSocketConnected, mode, load, setDrawPollingIntervalId]);
|
||||
|
||||
const display: DrawCurrentPayload | null | undefined =
|
||||
raw === undefined || raw === null ? raw : applySnapshotDrift(raw, emittedAtMs, nowMs);
|
||||
raw === undefined || raw === null
|
||||
? raw
|
||||
: applySnapshotDrift(raw, emittedAtMs, nowMs, serverNowMs);
|
||||
|
||||
const isBettable = display != null && display.status === "open";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user