import { useState, useEffect } from "react"; import { useParams, Link } from "react-router-dom"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { Progress } from "@/components/ui/progress"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { ArrowLeft, Activity, AlertTriangle, CheckCircle, Clock, FileText, Shield, Code, Zap, Info, Lightbulb } from "lucide-react"; import { api } from "@/shared/config/database"; import type { AuditTask, AuditIssue } from "@/shared/types"; import { toast } from "sonner"; export default function TaskDetail() { const { id } = useParams<{ id: string }>(); const [task, setTask] = useState(null); const [issues, setIssues] = useState([]); const [loading, setLoading] = useState(true); useEffect(() => { if (id) { loadTaskData(); } }, [id]); const loadTaskData = async () => { if (!id) return; try { setLoading(true); const [taskData, issuesData] = await Promise.all([ api.getAuditTaskById(id), api.getAuditIssues(id) ]); setTask(taskData); setIssues(issuesData); } catch (error) { console.error('Failed to load task data:', error); toast.error("加载任务数据失败"); } finally { setLoading(false); } }; const getStatusColor = (status: string) => { switch (status) { case 'completed': return 'bg-green-100 text-green-800'; case 'running': return 'bg-blue-100 text-blue-800'; case 'failed': return 'bg-red-100 text-red-800'; default: return 'bg-gray-100 text-gray-800'; } }; const getStatusIcon = (status: string) => { switch (status) { case 'completed': return ; case 'running': return ; case 'failed': return ; default: return ; } }; 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-blue-100 text-blue-800 border-blue-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 formatDate = (dateString: string) => { return new Date(dateString).toLocaleDateString('zh-CN', { year: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' }); }; if (loading) { return (
); } if (!task) { return (

任务未找到

请检查任务ID是否正确

); } return (
{/* 页面标题 */}

{task.task_type === 'repository' ? '仓库审计任务' : '即时分析任务'}

项目:{task.project?.name || '未知项目'}

{getStatusIcon(task.status)} {task.status === 'completed' ? '已完成' : task.status === 'running' ? '运行中' : task.status === 'failed' ? '失败' : '等待中'}
{/* 任务概览 */}

扫描文件

{task.scanned_files}/{task.total_files}

代码行数

{task.total_lines.toLocaleString()}

发现问题

{task.issues_count}

质量评分

{task.quality_score.toFixed(1)}

{/* 主要内容 */} 任务概览 问题详情 配置信息
{/* 任务信息 */} 任务信息
任务类型 {task.task_type === 'repository' ? '仓库审计' : '即时分析'}
创建时间 {formatDate(task.created_at)}
{task.started_at && (
开始时间 {formatDate(task.started_at)}
)} {task.completed_at && (
完成时间 {formatDate(task.completed_at)}
)}
创建者 {task.creator?.full_name || task.creator?.phone || '未知'}
{/* 扫描进度 */} {task.status === 'running' && (
扫描进度 {task.scanned_files}/{task.total_files}
)} {/* 质量评分 */} {task.status === 'completed' && (
代码质量评分 {task.quality_score.toFixed(1)}/100
)}
{/* 问题统计 */} 问题统计 {issues.length > 0 ? (

{issues.filter(i => i.severity === 'critical').length}

严重问题

{issues.filter(i => i.severity === 'high').length}

高优先级

{issues.filter(i => i.severity === 'medium').length}

中等优先级

{issues.filter(i => i.severity === 'low').length}

低优先级

{/* 问题类型分布 */}

问题类型分布

{['security', 'bug', 'performance', 'style', 'maintainability'].map(type => { const count = issues.filter(i => i.issue_type === type).length; const percentage = issues.length > 0 ? (count / issues.length) * 100 : 0; return (
{getTypeIcon(type)} {type}
{count}
); })}
) : (

未发现问题

代码质量良好

)}
{issues.length > 0 ? (
{issues.map((issue, index) => (
{getTypeIcon(issue.issue_type)}

{issue.title}

{issue.file_path}:{issue.line_number}

{issue.severity}

{issue.description}

{issue.code_snippet && (

代码片段:

                          {issue.code_snippet}
                        
)} {issue.suggestion && (

修复建议:

{issue.suggestion}

)} {issue.ai_explanation && (

AI 解释:

{issue.ai_explanation}

)}
))}
) : (

代码质量良好!

未发现任何问题

)}
扫描配置

分支信息

{task.branch_name || '默认分支'}

排除模式

{JSON.parse(task.exclude_patterns || '[]').length > 0 ? ( JSON.parse(task.exclude_patterns).map((pattern: string, index: number) => ( {pattern} )) ) : (

无排除模式

)}

扫描配置

                  {JSON.stringify(JSON.parse(task.scan_config || '{}'), null, 2)}
                
); }