Files
zzTaiko/app/page.tsx
2025-12-23 15:28:28 +08:00

153 lines
5.4 KiB
TypeScript

'use client';
import { useState, useEffect } from 'react';
import Navbar from '@/app/components/Navbar';
import MonthlyChallengeTable from '@/app/components/MonthlyChallengeTable';
import { MonthlyChallengeData } from '@/app/types';
import { Calendar, RefreshCw, AlertCircle } from 'lucide-react';
import { useDarkMode } from '@/app/hooks/useDarkMode';
export default function HomePage() {
const { darkMode, toggleDarkMode, isUsingSystem, getToggleLabel, getToggleText } = useDarkMode();
const [monthlyData, setMonthlyData] = useState<MonthlyChallengeData[]>([]);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
// 加载数据
const loadData = async () => {
setIsLoading(true);
setError(null);
try {
const response = await fetch('/api/challenge-data');
if (!response.ok) {
throw new Error(`加载数据失败: ${response.status} ${response.statusText}`);
}
const data = await response.json();
if (data.success && data.files) {
const formattedData: MonthlyChallengeData[] = data.files.map((file: any) => ({
yearMonth: file.yearMonth,
fileName: file.fileName,
data: file.data
}));
setMonthlyData(formattedData);
} else {
throw new Error(data.error || '数据格式错误');
}
} catch (error) {
console.error('加载课题数据失败:', error);
setError(error instanceof Error ? error.message : '未知错误');
} finally {
setIsLoading(false);
}
};
// 组件挂载时加载数据
useEffect(() => {
loadData();
}, []);
return (
<div className="min-h-screen transition-colors duration-200">
{/* 导航栏 */}
<Navbar
darkMode={darkMode}
onToggleDarkMode={toggleDarkMode}
isUsingSystem={isUsingSystem}
toggleLabel={getToggleLabel()}
toggleText={getToggleText()}
/>
{/* 主内容 */}
<main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
{/* 页面标题和刷新按钮 */}
<div className="flex items-center justify-between mb-8">
<h1 className="text-3xl font-bold text-gray-900 dark:text-white">
</h1>
</div>
{/* 加载状态 */}
{isLoading && (
<div className="flex flex-col items-center justify-center py-12">
<RefreshCw className="w-8 h-8 animate-spin mb-4 text-blue-500" />
<p className="text-gray-600 dark:text-gray-400">...</p>
</div>
)}
{/* 错误状态 */}
{error && !isLoading && (
<div className="rounded-xl p-6 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 mb-6">
<div className="flex items-start gap-3">
<AlertCircle className="w-6 h-6 mt-0.5 text-red-500 dark:text-red-400" />
<div className="flex-1">
<h3 className="font-semibold mb-2 text-red-800 dark:text-red-300">
</h3>
<p className="text-sm mb-4 text-red-600 dark:text-red-400">
{error}
</p>
<button
onClick={loadData}
className="px-4 py-2 bg-red-100 dark:bg-red-800 hover:bg-red-200 dark:hover:bg-red-700 text-red-800 dark:text-white rounded-lg flex items-center gap-2"
>
<RefreshCw className="w-4 h-4" />
</button>
</div>
</div>
</div>
)}
{/* 空状态 */}
{!isLoading && !error && monthlyData.length === 0 && (
<div className="text-center py-12">
<Calendar className="w-12 h-12 mx-auto mb-4 text-gray-400" />
<h3 className="text-lg font-medium text-gray-900 dark:text-white mb-2">
</h3>
<p className="text-gray-600 dark:text-gray-400 mb-6">
challenge-data目录中没有找到JSON文件
</p>
<button
onClick={loadData}
className="px-4 py-2 bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600 text-gray-800 dark:text-white rounded-lg flex items-center gap-2 mx-auto"
>
<RefreshCw className="w-4 h-4" />
</button>
</div>
)}
{/* 表格展示 */}
{!isLoading && !error && monthlyData.length > 0 && (
<div className="space-y-8">
{monthlyData.map((monthData, index) => (
<div key={monthData.yearMonth}>
<div className="flex items-center gap-2 mb-4">
<Calendar className="w-5 h-5 text-blue-500" />
<h2 className="text-xl font-semibold text-gray-900 dark:text-white">
{monthData.yearMonth}
<span className="ml-2 text-sm font-normal text-gray-500 dark:text-gray-400">
({monthData.data.totalChallenges})
</span>
</h2>
</div>
<MonthlyChallengeTable
monthlyData={monthData}
darkMode={darkMode}
showHeader={false}
expandable={false}
/>
</div>
))}
</div>
)}
</main>
</div>
);
}