import React, { useState, useEffect } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { AlertTriangle, X, Send, Bug, CheckCircle } from 'lucide-react'; import { supabase } from '../supabase/client'; interface CrashReport { error: Error; errorInfo: React.ErrorInfo; timestamp: string; userAgent: string; url: string; } export function CrashReporter() { const [crash, setCrash] = useState(null); const [isSubmitting, setIsSubmitting] = useState(false); const [isSubmitted, setIsSubmitted] = useState(false); const [userDescription, setUserDescription] = useState(''); useEffect(() => { // 监听全局错误 const handleError = (event: ErrorEvent) => { const crashData: CrashReport = { error: event.error || new Error(event.message), errorInfo: { componentStack: '' }, timestamp: new Date().toISOString(), userAgent: navigator.userAgent, url: window.location.href, }; setCrash(crashData); }; window.addEventListener('error', handleError); return () => window.removeEventListener('error', handleError); }, []); const handleSubmit = async () => { if (!crash) return; setIsSubmitting(true); try { // 获取当前用户信息 const { data: { user } } = await supabase.auth.getUser(); // 提交崩溃报告 await supabase.from('crash_reports').insert({ error_message: crash.error.message, error_stack: crash.error.stack, component_stack: crash.errorInfo.componentStack, user_description: userDescription.trim() || null, user_agent: crash.userAgent, url: crash.url, user_id: user?.id || null, status: 'pending', }); setIsSubmitted(true); setTimeout(() => { setCrash(null); setIsSubmitted(false); setUserDescription(''); }, 3000); } catch (error) { console.error('提交崩溃报告失败:', error); // 即使失败也关闭弹窗 setIsSubmitted(true); } finally { setIsSubmitting(false); } }; const handleClose = () => { setCrash(null); setUserDescription(''); }; if (!crash) return null; return (
{/* 头部 */}

程序异常

发生了一个意外错误

{/* 内容 */}
{isSubmitted ? (

报告已发送

感谢您的反馈,我们会尽快修复

) : ( <> {/* 错误信息 */}
错误信息

{crash.error.message}

{/* 用户描述 */}