feat: 集成错误处理与网络状态管理
- 在 Providers 组件中引入 ErrorProvider 以处理全局错误状态 - 更新 PlayerAppShell 组件的注释,说明网络状态横幅的用途 - 在 lotteryHttp 中添加对 500、502、503 错误的处理,更新全局错误状态 - 导出 useNetworkStatus 和 useIsOffline 钩子以支持网络状态管理
This commit is contained in:
154
src/components/server-error.tsx
Normal file
154
src/components/server-error.tsx
Normal file
@@ -0,0 +1,154 @@
|
||||
"use client";
|
||||
|
||||
import { ServerCrash, Home, RefreshCw } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
|
||||
import { useErrorStore, ERROR_COLORS } from "@/stores/error-store";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
/**
|
||||
* 服务器错误 (500) 全屏错误页面组件
|
||||
* 当 API 返回 500 错误时显示
|
||||
* 消息:"服务器暂时不可用,请稍后重试"
|
||||
* 包含 "返回首页" 按钮
|
||||
*/
|
||||
export function ServerError(): React.ReactElement | null {
|
||||
const { isServerError, serverErrorMessage, clearServerError } = useErrorStore();
|
||||
|
||||
const handleRetry = (): void => {
|
||||
clearServerError();
|
||||
// 刷新页面尝试重新加载
|
||||
if (typeof window !== "undefined") {
|
||||
window.location.reload();
|
||||
}
|
||||
};
|
||||
|
||||
// 没有服务器错误时不显示
|
||||
if (!isServerError) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 z-[100] flex items-center justify-center bg-background p-4">
|
||||
<div className="flex w-full max-w-md flex-col items-center text-center">
|
||||
{/* 错误图标 */}
|
||||
<div
|
||||
className="mb-6 flex size-20 items-center justify-center rounded-full"
|
||||
style={{ backgroundColor: `${ERROR_COLORS.error}15` }}
|
||||
>
|
||||
<ServerCrash
|
||||
className="size-10"
|
||||
style={{ color: ERROR_COLORS.error }}
|
||||
aria-hidden
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 错误标题 */}
|
||||
<h1
|
||||
className="mb-2 text-2xl font-bold"
|
||||
style={{ color: ERROR_COLORS.error }}
|
||||
>
|
||||
服务器错误
|
||||
</h1>
|
||||
|
||||
{/* 错误消息 */}
|
||||
<p className="mb-8 text-base text-muted-foreground">
|
||||
{serverErrorMessage}
|
||||
</p>
|
||||
|
||||
{/* 操作按钮 */}
|
||||
<div className="flex flex-col gap-3 sm:flex-row">
|
||||
<Button
|
||||
onClick={handleRetry}
|
||||
variant="outline"
|
||||
className={cn(
|
||||
"gap-2 border-current hover:bg-current/5",
|
||||
)}
|
||||
style={{ borderColor: ERROR_COLORS.error, color: ERROR_COLORS.error }}
|
||||
>
|
||||
<RefreshCw className="size-4" />
|
||||
重试
|
||||
</Button>
|
||||
|
||||
<Link
|
||||
href="/hall"
|
||||
className="inline-flex items-center justify-center gap-2 rounded-lg px-4 py-2 text-sm font-medium text-white"
|
||||
style={{ backgroundColor: ERROR_COLORS.error }}
|
||||
>
|
||||
<Home className="size-4" />
|
||||
返回首页
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{/* 状态码提示 */}
|
||||
<p className="mt-8 text-xs text-muted-foreground/60">
|
||||
错误代码: 500 Internal Server Error
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 服务器错误弹窗/遮罩组件(适用于在现有页面中显示)
|
||||
*/
|
||||
export function ServerErrorModal(): React.ReactElement | null {
|
||||
const { isServerError, serverErrorMessage, clearServerError } = useErrorStore();
|
||||
|
||||
const handleRetry = (): void => {
|
||||
clearServerError();
|
||||
window.location.reload();
|
||||
};
|
||||
|
||||
if (!isServerError) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 z-[100] flex items-center justify-center bg-black/50 p-4 backdrop-blur-sm">
|
||||
<div className="w-full max-w-sm rounded-xl bg-card p-6 shadow-lg">
|
||||
<div className="flex flex-col items-center text-center">
|
||||
{/* 错误图标 */}
|
||||
<div
|
||||
className="mb-4 flex size-16 items-center justify-center rounded-full"
|
||||
style={{ backgroundColor: `${ERROR_COLORS.error}15` }}
|
||||
>
|
||||
<ServerCrash
|
||||
className="size-8"
|
||||
style={{ color: ERROR_COLORS.error }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 错误消息 */}
|
||||
<h2 className="mb-2 text-lg font-semibold text-foreground">
|
||||
服务器暂时不可用
|
||||
</h2>
|
||||
<p className="mb-6 text-sm text-muted-foreground">
|
||||
{serverErrorMessage}
|
||||
</p>
|
||||
|
||||
{/* 按钮 */}
|
||||
<div className="flex w-full gap-3">
|
||||
<Button
|
||||
variant="outline"
|
||||
className="flex-1"
|
||||
onClick={handleRetry}
|
||||
>
|
||||
<RefreshCw className="mr-2 size-4" />
|
||||
重试
|
||||
</Button>
|
||||
<Link
|
||||
href="/hall"
|
||||
className="flex flex-1 items-center justify-center gap-2 rounded-lg px-4 py-2 text-sm font-medium text-white"
|
||||
style={{ backgroundColor: ERROR_COLORS.error }}
|
||||
>
|
||||
<Home className="size-4" />
|
||||
返回首页
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user