import { useState, useRef, useEffect } from "react"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { Textarea } from "@/components/ui/textarea"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Progress } from "@/components/ui/progress"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { ScrollArea } from "@/components/ui/scroll-area"; import { AlertTriangle, CheckCircle, Clock, Code, FileText, Info, Lightbulb, Shield, Target, TrendingUp, Upload, Zap, X, Download, History, ChevronRight } from "lucide-react"; import { CodeAnalysisEngine } from "@/features/analysis/services"; import { api } from "@/shared/config/database"; import type { CodeAnalysisResult, InstantAnalysis as InstantAnalysisType } from "@/shared/types"; import { toast } from "sonner"; import InstantExportDialog from "@/components/reports/InstantExportDialog"; // AI解释解析函数 function parseAIExplanation(aiExplanation: string) { try { const parsed = JSON.parse(aiExplanation); // 检查是否有xai字段 if (parsed.xai) { return parsed.xai; } // 检查是否直接包含what, why, how字段 if (parsed.what || parsed.why || parsed.how) { return parsed; } // 如果都没有,返回null表示无法解析 return null; } catch (error) { // JSON解析失败,返回null return null; } } export default function InstantAnalysis() { const user = null as any; const [code, setCode] = useState(""); const [language, setLanguage] = useState(""); const [analyzing, setAnalyzing] = useState(false); const [result, setResult] = useState(null); const [analysisTime, setAnalysisTime] = useState(0); const [exportDialogOpen, setExportDialogOpen] = useState(false); const [currentAnalysisId, setCurrentAnalysisId] = useState(null); const fileInputRef = useRef(null); const loadingCardRef = useRef(null); // 历史记录相关状态 const [showHistory, setShowHistory] = useState(false); const [historyRecords, setHistoryRecords] = useState([]); const [loadingHistory, setLoadingHistory] = useState(false); const [selectedHistoryId, setSelectedHistoryId] = useState(null); const supportedLanguages = CodeAnalysisEngine.getSupportedLanguages(); // 加载历史记录 const loadHistory = async () => { setLoadingHistory(true); try { const records = await api.getInstantAnalyses(); setHistoryRecords(records); } catch (error) { console.error('Failed to load history:', error); toast.error('加载历史记录失败'); } finally { setLoadingHistory(false); } }; // 查看历史记录详情 const viewHistoryRecord = (record: InstantAnalysisType) => { try { const analysisResult = JSON.parse(record.analysis_result) as CodeAnalysisResult; setResult(analysisResult); setLanguage(record.language); setAnalysisTime(record.analysis_time); setSelectedHistoryId(record.id); setCurrentAnalysisId(record.id); // 设置当前分析 ID 用于导出 setShowHistory(false); toast.success('已加载历史分析结果'); } catch (error) { console.error('Failed to parse history record:', error); toast.error('解析历史记录失败'); } }; // 格式化日期 const formatDate = (dateStr: string) => { const date = new Date(dateStr); return date.toLocaleString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' }); }; // 删除单条历史记录 const deleteHistoryRecord = async (e: React.MouseEvent, recordId: string) => { e.stopPropagation(); // 阻止触发查看详情 try { await api.deleteInstantAnalysis(recordId); setHistoryRecords(prev => prev.filter(r => r.id !== recordId)); if (selectedHistoryId === recordId) { setSelectedHistoryId(null); setResult(null); } toast.success('删除成功'); } catch (error) { console.error('Failed to delete history:', error); toast.error('删除失败'); } }; // 清空所有历史记录 const clearAllHistory = async () => { if (!confirm('确定要清空所有历史记录吗?此操作不可恢复。')) return; try { await api.deleteAllInstantAnalyses(); setHistoryRecords([]); setSelectedHistoryId(null); toast.success('已清空所有历史记录'); } catch (error) { console.error('Failed to clear history:', error); toast.error('清空失败'); } }; // 切换历史记录面板 const toggleHistory = () => { if (!showHistory) { loadHistory(); } setShowHistory(!showHistory); }; // 监听analyzing状态变化,自动滚动到加载卡片 useEffect(() => { if (analyzing && loadingCardRef.current) { // 使用requestAnimationFrame确保DOM更新完成后再滚动 requestAnimationFrame(() => { setTimeout(() => { if (loadingCardRef.current) { loadingCardRef.current.scrollIntoView({ behavior: 'smooth', block: 'center' }); } }, 50); }); } }, [analyzing]); // 示例代码 const exampleCodes = { javascript: `// 示例JavaScript代码 - 包含多种问题 var userName = "admin"; var password = "123456"; // 硬编码密码 function validateUser(input) { if (input == userName) { // 使用 == 比较 console.log("User validated"); // 生产代码中的console.log return true; } return false; } // 性能问题:循环中重复计算长度 function processItems(items) { for (var i = 0; i < items.length; i++) { for (var j = 0; j < items.length; j++) { console.log(items[i] + items[j]); } } } // 安全问题:使用eval function executeCode(userInput) { eval(userInput); // 危险的eval使用 }`, python: `# 示例Python代码 - 包含多种问题 import * # 通配符导入 password = "secret123" # 硬编码密码 def process_data(data): try: result = [] for item in data: print(item) # 使用print而非logging result.append(item * 2) return result except: # 裸露的except语句 pass def complex_function(): # 函数过长示例 if True: if True: if True: if True: if True: # 嵌套过深 print("Deep nesting")`, java: `// 示例Java代码 - 包含多种问题 public class Example { private String password = "admin123"; // 硬编码密码 public void processData() { System.out.println("Processing..."); // 使用System.out.print try { // 一些处理逻辑 String data = getData(); } catch (Exception e) { // 空的异常处理 } } private String getData() { return "data"; } }`, swift: `// 示例Swift代码 - 包含多种问题 import Foundation class UserManager { var password = "admin123" // 硬编码密码 func validateUser(input: String) -> Bool { if input == password { // 直接比较密码 print("User validated") // 使用print而非日志 return true } return false } // 强制解包可能导致崩溃 func processData(data: [String]?) { let items = data! // 强制解包 for item in items { print(item) } } // 内存泄漏风险:循环引用 var closure: (() -> Void)? func setupClosure() { closure = { print(self.password) // 未使用 [weak self] } } }`, kotlin: `// 示例Kotlin代码 - 包含多种问题 class UserManager { private val password = "admin123" // 硬编码密码 fun validateUser(input: String): Boolean { if (input == password) { // 直接比较密码 println("User validated") // 使用println而非日志 return true } return false } // 空指针风险 fun processData(data: List?) { val items = data!! // 强制非空断言 for (item in items) { println(item) } } // 性能问题:循环中重复计算 fun inefficientLoop(items: List) { for (i in 0 until items.size) { for (j in 0 until items.size) { // O(n²) 复杂度 println(items[i] + items[j]) } } } }` }; const handleAnalyze = async () => { if (!code.trim()) { toast.error("请输入要分析的代码"); return; } if (!language) { toast.error("请选择编程语言"); return; } try { setAnalyzing(true); // 立即滚动到页面底部(加载卡片会出现的位置) setTimeout(() => { window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' }); }, 100); const startTime = Date.now(); const analysisResult = await CodeAnalysisEngine.analyzeCode(code, language); const endTime = Date.now(); const duration = (endTime - startTime) / 1000; setResult(analysisResult); // 使用后端返回的 analysis_time,如果没有则使用前端计算的 setAnalysisTime(analysisResult.analysis_time || duration); // 保存后端返回的 analysis_id 用于导出 setCurrentAnalysisId(analysisResult.analysis_id || null); toast.success(`分析完成!发现 ${analysisResult.issues.length} 个问题`); } catch (error: any) { console.error('Analysis failed:', error); // 显示详细的错误信息 const errorMessage = error?.message || "分析失败,请稍后重试"; toast.error(errorMessage); } finally { setAnalyzing(false); // 即时分析结束后清空前端内存中的代码(满足NFR-2销毁要求) setCode(""); } }; const handleFileUpload = (event: React.ChangeEvent) => { const file = event.target.files?.[0]; if (!file) return; const reader = new FileReader(); reader.onload = (e) => { const content = e.target?.result as string; setCode(content); // 根据文件扩展名自动选择语言 const extension = file.name.split('.').pop()?.toLowerCase(); const languageMap: Record = { 'js': 'javascript', 'jsx': 'javascript', 'ts': 'typescript', 'tsx': 'typescript', 'py': 'python', 'java': 'java', 'go': 'go', 'rs': 'rust', 'cpp': 'cpp', 'c': 'cpp', 'cc': 'cpp', 'h': 'cpp', 'hh': 'cpp', 'cs': 'csharp', 'php': 'php', 'rb': 'ruby', 'swift': 'swift', 'kt': 'kotlin' }; if (extension && languageMap[extension]) { setLanguage(languageMap[extension]); } }; reader.readAsText(file); }; const loadExampleCode = (lang: string) => { const example = exampleCodes[lang as keyof typeof exampleCodes]; if (example) { setCode(example); setLanguage(lang); toast.success(`已加载${lang}示例代码`); } }; const getSeverityColor = (severity: string) => { switch (severity) { case 'critical': return 'bg-red-100 text-red-800 border-red-200'; case 'high': return 'bg-orange-100 text-orange-800 border-orange-200'; case 'medium': return 'bg-yellow-100 text-yellow-800 border-yellow-200'; case 'low': return 'bg-red-50 text-red-800 border-red-200'; default: return 'bg-gray-100 text-gray-800 border-gray-200'; } }; const getTypeIcon = (type: string) => { switch (type) { case 'security': return ; case 'bug': return ; case 'performance': return ; case 'style': return ; case 'maintainability': return ; default: return ; } }; const clearAnalysis = () => { setCode(""); setLanguage(""); setResult(null); setAnalysisTime(0); }; // 渲染问题的函数,使用复古样式 const renderIssue = (issue: any, index: number) => (
{getTypeIcon(issue.type)}

{issue.title}

📍 第 {issue.line} 行 {issue.column && ,第 {issue.column} 列}
{issue.severity === 'critical' ? '严重' : issue.severity === 'high' ? '高' : issue.severity === 'medium' ? '中等' : '低'}
{issue.description && (
问题详情

{issue.description}

)} {issue.code_snippet && (
Code
问题代码
Line {issue.line}
            {issue.code_snippet}
          
)}
{issue.suggestion && (
修复建议

{issue.suggestion}

)} {issue.ai_explanation && (() => { const parsedExplanation = parseAIExplanation(issue.ai_explanation); if (parsedExplanation) { return (
AI 解释
{parsedExplanation.what && (
问题: {parsedExplanation.what}
)} {parsedExplanation.why && (
原因: {parsedExplanation.why}
)} {parsedExplanation.how && (
方案: {parsedExplanation.how}
)} {parsedExplanation.learn_more && ( )}
); } else { // 如果无法解析JSON,回退到原始显示方式 return (
AI 解释

{issue.ai_explanation}

); } })()}
); return (
{/* Decorative Background */}
{/* 历史记录面板 */} {showHistory && (

分析历史记录

{historyRecords.length > 0 && ( )}
{loadingHistory ? (

加载中...

) : historyRecords.length === 0 ? (

暂无历史记录

完成代码分析后,记录将显示在这里

) : (
{historyRecords.map((record) => (
viewHistoryRecord(record)} >
{record.language} {formatDate(record.created_at)}
= 80 ? 'bg-green-100 text-green-800' : record.quality_score >= 60 ? 'bg-yellow-100 text-yellow-800' : 'bg-red-100 text-red-800' }`} > 评分: {(record.quality_score ?? 0).toFixed(1)}
{record.issues_count} 个问题 {(record.analysis_time ?? 0).toFixed(2)}s
))}
)}
)} {/* 代码输入区域 */}

代码分析

{result && ( )}
{/* 工具栏 */}
{/* 快速示例 */}
示例:
{/* 代码编辑器 */}
Editor