| |
| |
| |
| |
| |
| |
|
|
| import React from 'react'; |
| import { ProjectStats } from '@/types/project'; |
| import { AlertTriangle, Clock, CheckCircle2, FolderOpen } from 'lucide-react'; |
|
|
| interface StatsPanelProps { |
| stats: ProjectStats; |
| onFilterChange?: (status: string) => void; |
| activeFilter?: string; |
| } |
|
|
| export default function StatsPanel({ stats, onFilterChange, activeFilter = 'ALL' }: StatsPanelProps) { |
| const statCards = [ |
| { |
| label: '全部项目', |
| value: stats.total, |
| icon: FolderOpen, |
| bgColor: 'from-slate-500/10 to-slate-500/5', |
| textColor: 'text-slate-700', |
| borderColor: 'border-slate-200', |
| filterValue: 'ALL' |
| }, |
| { |
| label: '超时项目', |
| value: stats.highRisk, |
| icon: AlertTriangle, |
| bgColor: 'from-red-500/10 to-red-500/5', |
| textColor: 'text-red-600', |
| borderColor: 'border-red-200', |
| filterValue: '已超时' |
| }, |
| { |
| label: '进行中', |
| value: stats.inProgress, |
| icon: Clock, |
| bgColor: 'from-blue-500/10 to-blue-500/5', |
| textColor: 'text-blue-600', |
| borderColor: 'border-blue-200', |
| filterValue: '进行中' |
| }, |
| { |
| label: '已完成', |
| value: stats.completed, |
| icon: CheckCircle2, |
| bgColor: 'from-emerald-500/10 to-emerald-500/5', |
| textColor: 'text-emerald-600', |
| borderColor: 'border-emerald-200', |
| filterValue: '已完成' |
| } |
| ]; |
|
|
| return ( |
| <div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-8 mb-12"> |
| {statCards.map((stat, index) => { |
| const Icon = stat.icon; |
| return ( |
| <button |
| key={index} |
| type="button" |
| className="group relative cursor-pointer text-left touch-manipulation select-none" |
| onClick={(e) => { |
| e.preventDefault(); |
| e.stopPropagation(); |
| onFilterChange?.(stat.filterValue); |
| }} |
| > |
| {/* Gradient background */} |
| <div className={`absolute inset-0 bg-gradient-to-br ${stat.bgColor} rounded-xl`} /> |
| |
| {/* Main card */} |
| <div className={`relative backdrop-blur-sm bg-white/60 border-2 ${stat.borderColor} rounded-xl p-8 transition-all duration-300 ease-out hover:shadow-xl hover:-translate-y-1 hover:scale-105 ${ |
| activeFilter === stat.filterValue ? 'ring-4 ring-offset-2 ' + (stat.filterValue === 'ALL' ? 'ring-slate-300' : stat.filterValue === '已超时' ? 'ring-red-300' : stat.filterValue === '进行中' ? 'ring-blue-300' : 'ring-emerald-300') : '' |
| }`}> |
| <div className="flex items-start justify-between"> |
| <div className="space-y-3 min-w-0"> |
| <p className={`text-base font-bold ${stat.textColor} tracking-wide whitespace-nowrap`}> |
| {stat.label} |
| </p> |
| <p className={`text-5xl font-bold ${stat.textColor} tabular-nums whitespace-nowrap`}> |
| {stat.value} |
| </p> |
| </div> |
| |
| {/* Icon */} |
| <div className="relative"> |
| <div className={`absolute inset-0 ${stat.textColor} opacity-10 rounded-full blur-xl group-hover:opacity-20 transition-opacity duration-300`} /> |
| <div className={`relative p-4 rounded-full bg-gradient-to-br ${stat.bgColor}`}> |
| <Icon className={`w-8 h-8 ${stat.textColor}`} strokeWidth={2} /> |
| </div> |
| </div> |
| </div> |
| </div> |
| </button> |
| ); |
| })} |
| </div> |
| ); |
| } |
|
|