feat: 集成网络连接管理与降级轮询功能
- 在 PlayerAppShell 中引入 NetworkStatusBanner 组件以显示网络状态 - 在 HallBettingGrid 中实现下注后触发钱包轮询 - 在 HallWalletStrip 中添加网络连接状态管理与定期刷新逻辑 - 在 useHallDrawLive 中集成 WebSocket 连接状态与降级轮询机制,确保在断开时自动切换到轮询模式
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import Link from "next/link";
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
import { NetworkStatusBanner } from "@/components/network-status-banner";
|
||||
import { PlayerBottomNav } from "@/components/layout/player-bottom-nav";
|
||||
import { PlayerSessionBar } from "@/features/player/player-session-bar";
|
||||
|
||||
@@ -15,6 +16,7 @@ type PlayerAppShellProps = {
|
||||
export function PlayerAppShell({ children }: PlayerAppShellProps): ReactNode {
|
||||
return (
|
||||
<div className="flex min-h-dvh flex-col bg-background text-foreground">
|
||||
<NetworkStatusBanner />
|
||||
<header className="sticky top-0 z-40 shrink-0 border-b border-border bg-background/95 backdrop-blur-sm supports-[backdrop-filter]:bg-background/80">
|
||||
<div className="mx-auto flex h-12 max-w-lg items-center gap-2 px-4">
|
||||
<Link
|
||||
|
||||
96
src/components/network-status-banner.tsx
Normal file
96
src/components/network-status-banner.tsx
Normal file
@@ -0,0 +1,96 @@
|
||||
"use client";
|
||||
|
||||
import { WifiOff, RefreshCw, AlertCircle } from "lucide-react";
|
||||
import { useCallback } from "react";
|
||||
|
||||
import { useWebSocketManager } from "@/hooks/use-websocket-manager";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
// 颜色常量(来自用户需求)
|
||||
const COLORS = {
|
||||
success: "#52c41a",
|
||||
error: "#ff4d4f",
|
||||
warning: "#faad14",
|
||||
neutral: "#d9d9d9",
|
||||
};
|
||||
|
||||
/**
|
||||
* 网络状态横幅组件
|
||||
* 当 WebSocket 断开时显示降级模式提示
|
||||
*/
|
||||
export function NetworkStatusBanner(): React.ReactElement | null {
|
||||
const { showDegradedBanner, mode, reconnect } = useWebSocketManager();
|
||||
|
||||
const handleReconnectClick = useCallback(() => {
|
||||
reconnect();
|
||||
}, [reconnect]);
|
||||
|
||||
// 只有在降级模式或离线模式下才显示
|
||||
if (!showDegradedBanner) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const isOffline = mode === "offline";
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"sticky top-0 z-50 flex items-center justify-center gap-2 px-4 py-2 text-sm",
|
||||
"animate-in slide-in-from-top-2 duration-200",
|
||||
)}
|
||||
style={{
|
||||
backgroundColor: isOffline ? COLORS.error : COLORS.warning,
|
||||
color: "#fff",
|
||||
}}
|
||||
role="status"
|
||||
aria-live="polite"
|
||||
>
|
||||
{isOffline ? (
|
||||
<>
|
||||
<WifiOff className="size-4 shrink-0" aria-hidden />
|
||||
<span className="font-medium">网络已断开,请检查网络连接</span>
|
||||
<button
|
||||
onClick={handleReconnectClick}
|
||||
className="ml-2 flex items-center gap-1 rounded px-2 py-0.5 text-xs font-medium hover:bg-white/20 focus:outline-none focus:ring-2 focus:ring-white/50"
|
||||
aria-label="尝试重连"
|
||||
>
|
||||
<RefreshCw className="size-3" aria-hidden />
|
||||
重试
|
||||
</button>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<AlertCircle className="size-4 shrink-0" aria-hidden />
|
||||
<span className="font-medium">
|
||||
网络不稳定,已切换至降级模式(轮询中...)
|
||||
</span>
|
||||
<button
|
||||
onClick={handleReconnectClick}
|
||||
className="ml-2 flex items-center gap-1 rounded px-2 py-0.5 text-xs font-medium hover:bg-white/20 focus:outline-none focus:ring-2 focus:ring-white/50"
|
||||
aria-label="尝试恢复 WebSocket 连接"
|
||||
>
|
||||
<RefreshCw className="size-3" aria-hidden />
|
||||
恢复
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 带网络状态横幅的页面包装器
|
||||
* 将横幅插入到页面顶部
|
||||
*/
|
||||
export function WithNetworkStatusBanner({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}): React.ReactElement {
|
||||
return (
|
||||
<>
|
||||
<NetworkStatusBanner />
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user