"use client"; import { useEffect, useState } from "react"; import Link from "next/link"; import { MessageSquare, Loader2, MessageCircle, BookOpen, Lightbulb, Megaphone, ChevronRight, Clock, User, } from "lucide-react"; import { forumAPI } from "@/lib/api"; import type { ForumCategory, ForumPostSummary } from "@/types"; const CATEGORY_ICONS: Record = { default: , }; const CATEGORY_ORDER = ["公告", "通知", "学习", "讨论", "课程", "反馈", "使用"]; function getCategoryIcon(name: string) { if (name.includes("公告") || name.includes("通知")) return ; if (name.includes("学习") || name.includes("讨论") || name.includes("课程")) return ; if (name.includes("反馈") || name.includes("使用")) return ; return CATEGORY_ICONS.default; } function getCategoryGradient(name: string) { if (name.includes("公告") || name.includes("通知")) return "from-rose-500/10 to-rose-50"; if (name.includes("学习") || name.includes("讨论") || name.includes("课程")) return "from-blue-500/10 to-blue-50"; if (name.includes("反馈") || name.includes("使用")) return "from-amber-500/10 to-amber-50"; return "from-slate-500/10 to-slate-50"; } function getCategoryAccent(name: string) { if (name.includes("公告") || name.includes("通知")) return "text-rose-600"; if (name.includes("学习") || name.includes("讨论") || name.includes("课程")) return "text-blue-600"; if (name.includes("反馈") || name.includes("使用")) return "text-amber-600"; return "text-slate-600"; } function formatRelativeTime(dateStr: string) { const date = new Date( new Date(dateStr).getTime() + 8 * 60 * 60 * 1000 ); const now = new Date(); const diffMs = now.getTime() - date.getTime(); const diffMinutes = Math.floor(diffMs / (1000 * 60)); const diffHours = Math.floor(diffMs / (1000 * 60 * 60)); const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24)); if (diffMinutes < 1) return "刚刚"; if (diffMinutes < 60) return `${diffMinutes} 分钟前`; if (diffHours < 24) return `${diffHours} 小时前`; if (diffDays < 7) return `${diffDays} 天前`; return date.toLocaleDateString("zh-CN", { month: "short", day: "numeric" }); } export default function ForumHomePage() { const [categories, setCategories] = useState([]); const [categoryPosts, setCategoryPosts] = useState< Record >({}); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { const loadCategories = async () => { try { setIsLoading(true); const data = await forumAPI.getCategories(); setCategories(data); const postsEntries = await Promise.all( data.map(async (category) => { try { const posts = await forumAPI.getPosts(category.id, 3); return [category.id, posts] as const; } catch { return [category.id, []] as const; } }) ); setCategoryPosts(Object.fromEntries(postsEntries)); setError(null); } catch (err) { const message = err instanceof Error ? err.message : "加载论坛数据失败"; setError(message); } finally { setIsLoading(false); } }; loadCategories(); }, []); return (
{isLoading ? (
正在加载社区...
) : error ? (

{error}

) : (
{[...categories] .sort((a, b) => { const getOrder = (name: string) => { for (let i = 0; i < CATEGORY_ORDER.length; i++) { if (name.includes(CATEGORY_ORDER[i])) return i; } return CATEGORY_ORDER.length; }; return getOrder(a.name) - getOrder(b.name); }) .map((category) => { const posts = categoryPosts[category.id] || []; return (
{/* Category header */}
{getCategoryIcon(category.name)}

{category.name}

{category.description && (

{category.description}

)}
{category.post_count} 条讨论 查看全部
{/* Posts list */}
{posts.length > 0 ? ( posts.map((post) => (

{post.title}

{post.author_name} {formatRelativeTime(post.created_at)} {post.reply_count}
)) ) : (
暂无讨论,成为第一个发帖的人
)}
); })}
)}
); }