import { useState, useEffect } from "react"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { LineChart, Line, PieChart, Pie, Cell, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from "recharts"; import { Activity, AlertTriangle, Clock, Code, FileText, GitBranch, Shield, TrendingUp, Zap, BarChart3, Target, ArrowUpRight, Calendar } from "lucide-react"; import { api, dbMode, isDemoMode } from "@/shared/config/database"; import type { Project, AuditTask, ProjectStats } from "@/shared/types"; import { Link } from "react-router-dom"; import { toast } from "sonner"; import { Info } from "lucide-react"; export default function Dashboard() { const [stats, setStats] = useState(null); const [recentProjects, setRecentProjects] = useState([]); const [recentTasks, setRecentTasks] = useState([]); const [loading, setLoading] = useState(true); const [issueTypeData, setIssueTypeData] = useState>([]); const [qualityTrendData, setQualityTrendData] = useState>([]); useEffect(() => { loadDashboardData(); }, []); const loadDashboardData = async () => { try { setLoading(true); const results = await Promise.allSettled([ api.getProjectStats(), api.getProjects(), api.getAuditTasks() ]); // 统计数据 - 使用真实数据或空数据 if (results[0].status === 'fulfilled') { setStats(results[0].value); } else { console.error('获取统计数据失败:', results[0].reason); // 使用空数据而不是假数据 setStats({ total_projects: 0, active_projects: 0, total_tasks: 0, completed_tasks: 0, total_issues: 0, resolved_issues: 0, avg_quality_score: 0 }); } // 项目列表 - 使用真实数据 if (results[1].status === 'fulfilled') { setRecentProjects(Array.isArray(results[1].value) ? results[1].value.slice(0, 5) : []); } else { console.error('获取项目列表失败:', results[1].reason); setRecentProjects([]); } // 任务列表 - 使用真实数据 let tasks: AuditTask[] = []; if (results[2].status === 'fulfilled') { tasks = Array.isArray(results[2].value) ? results[2].value : []; setRecentTasks(tasks.slice(0, 10)); } else { console.error('获取任务列表失败:', results[2].reason); setRecentTasks([]); } // 基于真实任务数据生成质量趋势 if (tasks.length > 0) { // 按日期分组计算平均质量分 const tasksByDate = tasks .filter(t => t.completed_at && t.quality_score > 0) .sort((a, b) => new Date(a.completed_at!).getTime() - new Date(b.completed_at!).getTime()) .slice(-6); // 最近6个任务 const trendData = tasksByDate.map((task) => ({ date: new Date(task.completed_at!).toLocaleDateString('zh-CN', { month: 'short', day: 'numeric' }), score: task.quality_score })); setQualityTrendData(trendData.length > 0 ? trendData : []); } else { setQualityTrendData([]); } // 基于真实数据生成问题类型分布 // 需要获取所有问题数据来统计 try { const allIssues = await Promise.all( tasks.map(task => api.getAuditIssues(task.id).catch(() => [])) ); const flatIssues = allIssues.flat(); if (flatIssues.length > 0) { const typeCount: Record = {}; flatIssues.forEach(issue => { typeCount[issue.issue_type] = (typeCount[issue.issue_type] || 0) + 1; }); const typeMap: Record = { security: { name: '安全问题', color: '#dc2626' }, bug: { name: '潜在Bug', color: '#7f1d1d' }, performance: { name: '性能问题', color: '#b91c1c' }, style: { name: '代码风格', color: '#991b1b' }, maintainability: { name: '可维护性', color: '#450a0a' } }; const issueData = Object.entries(typeCount).map(([type, count]) => ({ name: typeMap[type]?.name || type, value: count, color: typeMap[type]?.color || '#6b7280' })); setIssueTypeData(issueData); } else { setIssueTypeData([]); } } catch (error) { console.error('获取问题数据失败:', error); setIssueTypeData([]); } } catch (error) { console.error('仪表盘数据加载失败:', error); toast.error("数据加载失败"); } finally { setLoading(false); } }; const getStatusColor = (status: string) => { switch (status) { case 'completed': return 'bg-emerald-100 text-emerald-700 border-emerald-200'; case 'running': return 'bg-red-50 text-red-700 border-red-200'; case 'failed': return 'bg-red-100 text-red-800 border-red-300'; default: return 'bg-gray-100 text-gray-700 border-gray-200'; } }; if (loading) { return (

加载仪表盘数据...

); } return (
{/* Decorative Background */}
{/* 数据库模式提示 */} {isDemoMode && (
当前使用演示模式,显示的是模拟数据。 配置数据库后将显示真实数据。 前往数据库管理 >
)} {/* Stats Cards */}

总项目数

{stats?.total_projects || 0}

活跃: {stats?.active_projects || 0}

审计任务

{stats?.total_tasks || 0}

已完成: {stats?.completed_tasks || 0}

发现问题

{stats?.total_issues || 0}

已解决: {stats?.resolved_issues || 0}

平均质量分

{stats?.avg_quality_score ? stats.avg_quality_score.toFixed(1) : '0.0'}

{stats?.avg_quality_score ? (
持续改进
) : (

暂无数据

)}
{/* Main Content - 重新设计为更紧凑的布局 */}
{/* 左侧主要内容区 */}
{/* 图表区域 - 使用更紧凑的网格布局 */} {/* 图表区域 - 使用更紧凑的网格布局 */}
{/* 质量趋势图 */}

代码质量趋势

{qualityTrendData.length > 0 ? ( ) : (

暂无质量趋势数据

)}
{/* 问题分布图 */}

问题类型分布

{issueTypeData.length > 0 ? ( `${name} ${(percent * 100).toFixed(0)}%`} outerRadius={70} fill="#8884d8" dataKey="value" stroke="#000" strokeWidth={2} > {issueTypeData.map((entry) => ( ))} ) : (

暂无问题分布数据

)}
{/* 项目概览 */} {/* 项目概览 */}

项目概览

{recentProjects.length > 0 ? ( recentProjects.map((project) => (

{project.name}

{project.is_active ? '活跃' : '暂停'}

{project.description || '暂无描述'}

{new Date(project.created_at).toLocaleDateString('zh-CN')}
)) ) : (

暂无项目

)}
{/* 最近任务 */} {/* 最近任务 */}

最近任务

{recentTasks.length > 0 ? ( recentTasks.slice(0, 6).map((task) => (
{task.status === 'completed' ? : task.status === 'running' ? : }

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

质量分: {task.quality_score?.toFixed(1) || '0.0'}

{task.status === 'completed' ? '完成' : task.status === 'running' ? '运行中' : '失败'} )) ) : (

暂无任务

)}
{/* 右侧边栏 - 紧凑设计 */}
{/* 快速操作 */} {/* 快速操作 */}

快速操作

{/* 系统状态 */} {/* 系统状态 */}

系统状态

数据库模式 {dbMode === 'api' ? '后端' : dbMode === 'local' ? '本地' : dbMode === 'supabase' ? '云端' : '演示'}
活跃项目 {stats?.active_projects || 0}
运行中任务 {recentTasks.filter(t => t.status === 'running').length}
待解决问题 {stats ? stats.total_issues - stats.resolved_issues : 0}
{/* 最新活动 */} {/* 最新活动 */}

最新活动

{recentTasks.length > 0 ? ( recentTasks.slice(0, 3).map((task) => { const timeAgo = (() => { const now = new Date(); const taskDate = new Date(task.created_at); const diffMs = now.getTime() - taskDate.getTime(); const diffMins = Math.floor(diffMs / 60000); const diffHours = Math.floor(diffMs / 3600000); const diffDays = Math.floor(diffMs / 86400000); if (diffMins < 60) return `${diffMins}分钟前`; if (diffHours < 24) return `${diffHours}小时前`; return `${diffDays}天前`; })(); const bgColor = task.status === 'completed' ? 'bg-green-50 border-black' : task.status === 'running' ? 'bg-blue-50 border-black' : task.status === 'failed' ? 'bg-red-50 border-black' : 'bg-gray-50 border-black'; const statusText = task.status === 'completed' ? '任务完成' : task.status === 'running' ? '任务运行中' : task.status === 'failed' ? '任务失败' : '任务待处理'; return (

{statusText}

项目 "{task.project?.name || '未知项目'}" {task.status === 'completed' && task.issues_count > 0 && ` - 发现 ${task.issues_count} 个问题` }

{timeAgo}

); }) ) : (

暂无活动记录

)}
); }