'use client'; import Link from 'next/link'; import { motion, AnimatePresence, useScroll, useTransform } from 'framer-motion'; import { useState, useCallback, useEffect } from 'react'; import { HomeIcon, ArrowLeftIcon, ExclamationTriangleIcon, XCircleIcon, ClockIcon, ServerIcon, WifiIcon, ClipboardDocumentIcon, ArrowPathIcon, CubeIcon, QuestionMarkCircleIcon, SparklesIcon, RocketLaunchIcon } from '@heroicons/react/24/outline'; import { messageManager } from './MessageNotification'; export interface ErrorPageProps { code?: number; title?: string; message?: string; description?: string; type?: '404' | '500' | '403' | 'network' | 'timeout' | 'maintenance' | 'custom'; actions?: { primary?: { label: string; href?: string; onClick?: () => void; }; secondary?: { label: string; href?: string; onClick?: () => void; }; }; showContact?: boolean; showRetry?: boolean; onRetry?: () => void; showCopyError?: boolean; errorDetails?: string; className?: string; } const errorConfigs = { '404': { icon: , title: '页面未找到', message: '这个页面似乎不存在于我们的世界中', description: '页面可能已被移除、重命名,或者您输入的地址不正确。', suggestions: [ '检查网址拼写是否正确', '返回主页重新探索', '使用搜索功能寻找内容' ] }, '500': { icon: , title: '服务器错误', message: '我们的服务器遇到了一些技术问题', description: '工程师们正在紧急修复中,请稍后再试。', suggestions: [ '稍后刷新页面重试', '清除浏览器缓存', '检查网络连接' ] }, '403': { icon: , title: '访问被拒绝', message: '您没有权限进入这个区域', description: '请检查您的权限等级或联系管理员获取访问权限。', suggestions: [ '确认您是否已登录', '检查账户权限等级', '联系管理员申请权限' ] }, network: { icon: , title: '网络连接问题', message: '与我们的连接出现了问题', description: '请检查您的网络连接,然后重新尝试。', suggestions: [ '检查网络连接状态', '尝试重新连接', '检查防火墙设置' ] }, timeout: { icon: , title: '连接超时', message: '服务器响应时间过长', description: '服务器响应缓慢,请稍后再试。', suggestions: [ '检查网络连接状态', '稍后重新尝试连接', '联系技术支持团队' ] }, maintenance: { icon: , title: '系统维护中', message: '我们正在对系统进行升级改造', description: '为了提供更好的体验,系统暂时关闭维护。', suggestions: [ '关注官方公告获取开放时间', '加入官方群组了解进度', '稍后再试' ] }, custom: { icon: , title: '未知错误', message: '发生了一些奇怪的事情', description: '请稍后再试或联系我们的支持团队。', suggestions: [] } }; // Action Button Component function ActionButton({ action, colorClass, primary = false }: { action: { label: string; href?: string; onClick?: () => void }; colorClass?: string; primary?: boolean; }) { const buttonContent = ( <> {primary ? : } {action.label} ); const buttonClass = primary ? `inline-flex items-center justify-center px-6 py-4 bg-gradient-to-r ${colorClass} text-white font-semibold rounded-xl transition-all duration-200 shadow-lg hover:shadow-xl transform hover:scale-105` : 'inline-flex items-center justify-center px-6 py-4 border-2 border-orange-500 text-orange-500 hover:bg-orange-500 hover:text-white font-semibold rounded-xl transition-all duration-200'; if ('href' in action && action.href) { return ( {buttonContent} ); } else if ('onClick' in action && action.onClick) { return ( ); } return null; } export function ErrorPage({ code, title, message, description, type = 'custom', actions, showContact = true, showRetry = true, onRetry, showCopyError = true, errorDetails, className = '' }: ErrorPageProps) { const [isRetrying, setIsRetrying] = useState(false); const [showDetails, setShowDetails] = useState(false); const [copySuccess, setCopySuccess] = useState(false); const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 }); const { scrollYProgress } = useScroll(); const opacity = useTransform(scrollYProgress, [0, 0.3], [1, 0.8]); const config = errorConfigs[type] || {}; const displayTitle = title || config.title || '出错了'; const displayMessage = message || config.message || '发生了一些错误'; const displayDescription = description || config.description || ''; // 生成详细的错误信息 const generateErrorDetails = useCallback(() => { const details = { timestamp: new Date().toISOString(), errorType: type, errorCode: code, userAgent: typeof window !== 'undefined' ? window.navigator.userAgent : 'Unknown', url: typeof window !== 'undefined' ? window.location.href : 'Unknown', customDetails: errorDetails }; return JSON.stringify(details, null, 2); }, [type, code, errorDetails]); const defaultActions = { primary: { label: '返回主城', href: '/' }, secondary: { label: '返回上页', onClick: () => { if (typeof window !== 'undefined') { window.history.back(); } } } }; const finalActions = { ...defaultActions, ...actions }; const getThemeStyles = () => { return { bg: 'bg-gradient-to-br from-slate-50 via-orange-50 to-amber-50 dark:from-gray-900 dark:via-gray-800 dark:to-gray-900', card: 'bg-white/70 dark:bg-gray-800/70 backdrop-blur-lg', text: 'text-gray-900 dark:text-white', subtext: 'text-gray-600 dark:text-gray-300', accent: 'text-orange-500 dark:text-orange-400' }; }; const getIconColor = () => { const colors = { '404': 'text-orange-500', '500': 'text-red-500', '403': 'text-yellow-500', 'network': 'text-blue-500', 'timeout': 'text-purple-500', 'maintenance': 'text-gray-500', 'custom': 'text-gray-500' }; return colors[type] || 'text-gray-500'; }; const getCodeColor = () => { const colors = { '404': 'from-orange-400 via-orange-500 to-amber-500', '500': 'from-red-400 via-red-500 to-pink-500', '403': 'from-yellow-400 via-yellow-500 to-orange-500', 'network': 'from-blue-400 via-blue-500 to-cyan-500', 'timeout': 'from-purple-400 via-purple-500 to-pink-500', 'maintenance': 'from-gray-400 via-gray-500 to-slate-500', 'custom': 'from-gray-400 via-gray-500 to-slate-500' }; return colors[type] || 'from-gray-400 via-gray-500 to-slate-500'; }; const getButtonColor = () => { return 'from-orange-500 to-amber-500 hover:from-orange-600 hover:to-amber-600'; }; const handleRetry = async () => { if (onRetry) { setIsRetrying(true); try { await onRetry(); messageManager.success('重试成功!', { duration: 3000 }); } catch (error) { messageManager.error('重试失败,请稍后重试', { duration: 5000 }); } finally { setIsRetrying(false); } } else { // 默认重试逻辑:刷新页面 if (typeof window !== 'undefined') { window.location.reload(); } } }; const handleCopyError = async () => { try { const details = generateErrorDetails(); if (typeof navigator !== 'undefined' && navigator.clipboard) { await navigator.clipboard.writeText(details); setCopySuccess(true); messageManager.success('错误信息已复制到剪贴板', { duration: 2000 }); setTimeout(() => setCopySuccess(false), 2000); } else { // 降级方案 const textArea = document.createElement('textarea'); textArea.value = details; document.body.appendChild(textArea); textArea.select(); document.execCommand('copy'); document.body.removeChild(textArea); setCopySuccess(true); messageManager.success('错误信息已复制到剪贴板', { duration: 2000 }); setTimeout(() => setCopySuccess(false), 2000); } } catch (error) { messageManager.error('复制失败,请手动复制', { duration: 3000 }); } }; const handleReportError = () => { messageManager.info('感谢您的反馈,我们会尽快处理', { duration: 3000 }); // 这里可以添加实际的错误报告逻辑 }; // 键盘快捷键支持 useEffect(() => { const handleKeyDown = (event: KeyboardEvent) => { if (event.key === 'r' && (event.ctrlKey || event.metaKey)) { event.preventDefault(); handleRetry(); } }; if (typeof window !== 'undefined') { window.addEventListener('keydown', handleKeyDown); return () => window.removeEventListener('keydown', handleKeyDown); } }, [handleRetry]); const themeStyles = getThemeStyles(); return (
{/* Animated Background - 简化背景动画 */}
{/* Main Content - 考虑navbar高度的居中布局 */}
{/* Error Code - 更突出的错误代码 */} {code && (

{code}

)} {/* Main Error Message - 简洁有力的错误信息 */}

{displayTitle}

{displayMessage}

{displayDescription && (

{displayDescription}

)}
{/* Icon - 更简洁的图标展示 */}
{config.icon || }
{/* Action Buttons - 更简洁的按钮布局 */}
{finalActions.primary && ( )} {finalActions.secondary && ( )}
{showRetry && ( {isRetrying ? '重试中...' : '重新加载'} )}
{/* Suggestions - 更简洁的建议展示 */} {config.suggestions && config.suggestions.length > 0 && (

您可以尝试:

{config.suggestions.map((suggestion, index) => (
{suggestion} ))}
)} {/* Error Details - 更简洁的错误详情 */} {showCopyError && (
{showDetails && (

错误详情:

                      {generateErrorDetails()}
                    
)}
)} {/* Contact Info - 更简洁的联系信息 */} {showContact && (

问题仍未解决? { e.preventDefault(); messageManager.info('联系我们页面正在开发中', { duration: 3000 }); }} > 联系我们

)}
); } // 预设的错误页面组件 export function NotFoundPage() { return ; } export function ServerErrorPage() { return ; } export function ForbiddenPage() { return ; } export function NetworkErrorPage() { return ; } export function TimeoutErrorPage() { return ; } export function MaintenancePage() { return ; } // 现代化的错误页面 export function ModernNotFoundPage() { return ; } export function ModernServerErrorPage() { return ; } // 使用示例和最佳实践 /* 增强后的ErrorPage组件提供了以下改进: 1. **统一的消息提示系统** - 使用MessageNotification组件替代alert - 支持成功、错误、警告、信息、加载等多种消息类型 - 更好的用户体验和视觉效果 2. **多种主题风格** - Minecraft风格:适合游戏相关网站 - Modern风格:现代化简洁设计 - Minimal风格:极简主义设计 3. **增强的功能** - 重试功能,支持自定义重试逻辑 - 错误信息复制功能 - 错误详情显示/隐藏 - 键盘快捷键支持 (Ctrl+R/⌘+R 重试) - 进度条显示(可选) - 自定义操作按钮 4. **改进的用户体验** - 针对每种错误类型提供具体建议 - 动态颜色主题匹配错误类型 - 平滑的动画过渡效果 - 响应式设计,适配移动端 - Minecraft风格的游戏化提示 5. **更好的错误处理** - 详细的错误信息生成 - 错误报告功能 - 降级处理(如复制功能) - 支持自定义错误详情 使用示例: ```tsx // 基础使用 - Minecraft风格404页面 // 现代风格500错误 // 自定义错误信息 // 自定义操作按钮 reconnect() }, secondary: { label: '离线模式', href: '/offline' } }} /> // 启用重试功能 { // 自定义重试逻辑 await fetchData(); }} /> // 显示错误详情 ``` 预设组件使用: ```tsx // 在页面中使用预设的错误组件 import { NotFoundPage, ServerErrorPage, ModernNotFoundPage } from '@/components/ErrorPage'; // Minecraft风格404页面 export default function Custom404() { return ; } // 现代化404页面 export default function Modern404() { return ; } // 500页面 export default function Custom500() { return ; } ``` */