100 lines
2.9 KiB
TypeScript
100 lines
2.9 KiB
TypeScript
|
|
"use client"
|
|||
|
|
|
|||
|
|
import React, { type ErrorInfo } from "react"
|
|||
|
|
import { Card, CardContent, CardFooter } from "@/components/ui/card"
|
|||
|
|
import { Button } from "@/components/ui/button"
|
|||
|
|
import { useRouter } from "next/navigation"
|
|||
|
|
import { useToast } from "@/components/ui/use-toast"
|
|||
|
|
|
|||
|
|
interface ErrorBoundaryProps {
|
|||
|
|
children: React.ReactNode
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
interface ErrorBoundaryState {
|
|||
|
|
hasError: boolean
|
|||
|
|
error?: Error
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
class ErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {
|
|||
|
|
constructor(props: ErrorBoundaryProps) {
|
|||
|
|
super(props)
|
|||
|
|
this.state = { hasError: false }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static getDerivedStateFromError(error: Error): ErrorBoundaryState {
|
|||
|
|
// 更新state使下一次渲染可以显示错误界面
|
|||
|
|
return { hasError: true, error }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
componentDidCatch(error: Error, errorInfo: ErrorInfo) {
|
|||
|
|
// 记录错误信息
|
|||
|
|
console.error("错误边界捕获到错误:", error, errorInfo)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
render() {
|
|||
|
|
if (this.state.hasError) {
|
|||
|
|
return <ErrorScreen error={this.state.error} onReset={() => this.setState({ hasError: false })} />
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return this.props.children
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 错误显示界面
|
|||
|
|
function ErrorScreen({ error, onReset }: { error?: Error; onReset: () => void }) {
|
|||
|
|
const router = useRouter()
|
|||
|
|
const { toast } = useToast()
|
|||
|
|
|
|||
|
|
// 导航到主页
|
|||
|
|
const goHome = () => {
|
|||
|
|
router.push("/dashboard")
|
|||
|
|
onReset()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 刷新当前页面
|
|||
|
|
const refreshPage = () => {
|
|||
|
|
if (typeof window !== "undefined") {
|
|||
|
|
toast({
|
|||
|
|
title: "正在刷新页面",
|
|||
|
|
description: "正在重新加载页面内容...",
|
|||
|
|
variant: "default",
|
|||
|
|
})
|
|||
|
|
setTimeout(() => {
|
|||
|
|
window.location.reload()
|
|||
|
|
}, 500)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<div className="w-full h-[calc(100vh-200px)] flex items-center justify-center p-4">
|
|||
|
|
<Card className="w-full max-w-md">
|
|||
|
|
<CardContent className="pt-6">
|
|||
|
|
<div className="flex flex-col gap-4">
|
|||
|
|
<div className="bg-red-50 text-red-600 p-4 rounded-md">
|
|||
|
|
<h2 className="text-xl font-semibold mb-2">页面出错了</h2>
|
|||
|
|
<p className="text-sm text-red-700 mb-4">
|
|||
|
|
很抱歉,页面加载过程中遇到了问题。
|
|||
|
|
</p>
|
|||
|
|
{error && (
|
|||
|
|
<div className="bg-white/50 p-2 rounded text-xs font-mono overflow-auto max-h-24">
|
|||
|
|
{error.message}
|
|||
|
|
</div>
|
|||
|
|
)}
|
|||
|
|
</div>
|
|||
|
|
<p className="text-sm text-gray-500">
|
|||
|
|
您可以尝试刷新页面或返回首页。如果问题持续存在,请联系系统管理员。
|
|||
|
|
</p>
|
|||
|
|
</div>
|
|||
|
|
</CardContent>
|
|||
|
|
<CardFooter className="flex justify-end gap-2">
|
|||
|
|
<Button variant="outline" onClick={goHome}>
|
|||
|
|
返回首页
|
|||
|
|
</Button>
|
|||
|
|
<Button onClick={refreshPage}>刷新页面</Button>
|
|||
|
|
</CardFooter>
|
|||
|
|
</Card>
|
|||
|
|
</div>
|
|||
|
|
)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export default ErrorBoundary
|