+ {/* Back nav */}
+
-
-
-
- {currentCategory ? currentCategory.name : "论坛分类"}
-
- {currentCategory?.description && (
-
{currentCategory.description}
+ {/* Category header */}
+
+
+
+ {currentCategory ? currentCategory.name : "论坛分类"}
+
+ {currentCategory?.description && (
+
+ {currentCategory.description}
+
+ )}
+
+ {isAuthenticated && (
+
)}
+ {/* New post form (collapsible) */}
+ {showForm && (
+
+ )}
+
+ {/* Login prompt */}
+ {!isAuthenticated && (
+
+ 需要登录后才能发帖。请先
+
+ 登录
+
+ 或
+
+ 注册
+
+
+ )}
+
+ {/* Posts list */}
{isLoading ? (
- 正在加载帖子...
+ 正在加载...
) : error ? (
-
- {error}
-
+
+ ) : posts.length === 0 ? (
+
) : (
-
-
- {isAuthenticated ? (
-
-
- 发起讨论
- 发表新的帖子,与大家交流想法。
-
-
-
-
-
- ) : (
-
-
- 需要登录后才能发表帖子。请先
-
- 登录
-
- 或
-
- 注册
-
- 。
-
-
- )}
-
-
-
- {posts.length === 0 ? (
-
-
- 暂时还没有帖子,快来抢先发帖吧!
-
-
- ) : (
- posts.map((post) => (
-
-
-
-
- {post.title}
-
-
-
- 由 {post.author_name} 发布 · {post.reply_count} 条回复 ·{" "}
- {new Date(new Date(post.created_at).getTime() + 8 * 60 * 60 * 1000).toLocaleString()}
-
-
-
- ))
- )}
-
+
+ {posts.map((post) => (
+
+
+
+
+
+
+ {post.title}
+
+
+ {post.author_name}
+
+
+ {formatRelativeTime(post.created_at)}
+
+
+
+ {post.reply_count} 回复
+
+
+
+
+ ))}
)}
);
}
-
diff --git a/web/src/app/forum/post/[postId]/page.tsx b/web/src/app/forum/post/[postId]/page.tsx
index b5b5718..ca1e27e 100644
--- a/web/src/app/forum/post/[postId]/page.tsx
+++ b/web/src/app/forum/post/[postId]/page.tsx
@@ -5,13 +5,27 @@ import { useParams, useRouter } from "next/navigation";
import Link from "next/link";
import { forumAPI } from "@/lib/api";
import type { ForumPostDetail } from "@/types";
-import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
-import { Button } from "@/components/ui/button";
import { Textarea } from "@/components/ui/textarea";
-import { Alert, AlertDescription } from "@/components/ui/alert";
-import { Loader2, MessageCircleReply } from "lucide-react";
+import { Loader2, MessageCircle, Clock, User, Send, ArrowLeft } from "lucide-react";
import { useAuthStore } from "@/store/auth";
+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 ForumPostPage() {
const params = useParams();
const router = useRouter();
@@ -41,7 +55,8 @@ export default function ForumPostPage() {
setPost(detail);
setError(null);
} catch (err) {
- const message = err instanceof Error ? err.message : "加载帖子详情失败";
+ const message =
+ err instanceof Error ? err.message : "加载帖子详情失败";
setError(message);
} finally {
setIsLoading(false);
@@ -74,116 +89,154 @@ export default function ForumPostPage() {
};
return (
-
-
-
+
+
+ {/* Back nav */}
+
{isLoading ? (
- 正在加载帖子...
+ 正在加载...
) : error ? (
-
- {error}
-
+
) : post ? (
-
-
- {post.title}
-
- 由 {post.author_name} 发布 ·{" "}
- {new Date(new Date(post.created_at).getTime() + 8 * 60 * 60 * 1000).toLocaleString()}
-
-
-
+ {/* Post content */}
+
+
+
+ {post.title}
+
+
+
+
+
+
+
{post.author_name}
+
+
+
+ {formatRelativeTime(post.created_at)}
+
+
+
+
{post.content}
-
-
+
+
-
-
-
- 回复({post.replies.length})
-
+ {/* Replies section */}
+
+
+
+
+ 回复({post.replies.length})
+
+
{post.replies.length === 0 ? (
-
-
- 还没有回复,欢迎分享你的观点。
-
-
+
+ 暂无回复,欢迎分享你的观点
+
) : (
- post.replies.map((reply) => (
-
-
- {reply.author_name}
-
- {new Date(new Date(reply.created_at).getTime() + 8 * 60 * 60 * 1000).toLocaleString()}
+
+ {post.replies.map((reply) => (
+
+
+
-
-
- {reply.content}
-
-
- ))
+
+
+
+ {reply.author_name}
+
+
+ {formatRelativeTime(reply.created_at)}
+
+
+
+ {reply.content}
+
+
+
+ ))}
+
)}
-
-
- {isAuthenticated ? (
-
- ) : (
-
-
- 登录后才能回复帖子。前往
-
- 登录
-
- 或
-
- 注册
-
- 。
-
-
- )}
-
-
+ {/* Reply form */}
+
+ {isAuthenticated ? (
+
+ ) : (
+
+ 登录后才能回复。前往
+
+ 登录
+
+ 或
+
+ 注册
+
+
+ )}
+
) : null}
);
}
-
diff --git a/web/src/components/home/home-page-content.tsx b/web/src/components/home/home-page-content.tsx
index f405891..6e28613 100644
--- a/web/src/components/home/home-page-content.tsx
+++ b/web/src/components/home/home-page-content.tsx
@@ -38,7 +38,7 @@ const modules = [
visual: "spatial" as const,
},
{
- title: "论坛社区",
+ title: "课程社区",
description: "课程讨论与学习经验交流平台,促进师生互动与同伴学习",
href: "/forum",
tags: ["协作"],
@@ -436,20 +436,12 @@ export default function HomePageContent() {
基于先进AI技术的国土空间规划智能学习平台,集成RAG检索增强生成、图像生成、数据分析等能力,为专业教学与研究提供全方位支持。
-
+
{/* 快速链接 */}
@@ -463,16 +455,6 @@ export default function HomePageContent() {
))}
-
-
- 学习进度
-
-
-
-
- 系统设置
-
-
diff --git a/web/src/components/home/navbar.tsx b/web/src/components/home/navbar.tsx
index b545647..d9e6d9c 100644
--- a/web/src/components/home/navbar.tsx
+++ b/web/src/components/home/navbar.tsx
@@ -1,12 +1,13 @@
"use client";
import Link from "next/link";
+import { usePathname } from "next/navigation";
import { Button } from "@/components/ui/button";
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
import { ThemeToggle } from "@/components/ui/theme-toggle";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
import { useAuthStore } from "@/store/auth";
-import { BookOpen, LogOut, User as UserIcon, Settings, ChevronDown, MessageSquare, Database, Image, TrendingUp, GraduationCap } from "lucide-react";
+import { BookOpen, LogOut, User as UserIcon, Settings, ChevronDown, MessageSquare, Database, Image, TrendingUp, GraduationCap, Users } from "lucide-react";
import { User } from "@/types";
interface NavbarProps {
@@ -14,14 +15,28 @@ interface NavbarProps {
user: User | null;
}
+const NAV_LINKS = [
+ { href: "/course-content", label: "课程内容", icon: GraduationCap },
+ { href: "/chat", label: "智能问答", icon: MessageSquare },
+ { href: "/knowledge", label: "知识库", icon: Database },
+ { href: "/spatial", label: "空间设计", icon: Image },
+ { href: "/forum", label: "课程社区", icon: Users },
+];
+
export default function Navbar({ isAuthenticated, user }: NavbarProps) {
const { logout } = useAuthStore();
+ const pathname = usePathname();
+
+ const isActive = (href: string) => {
+ if (href === "/forum") return pathname === "/forum" || pathname.startsWith("/forum/");
+ return pathname === href || pathname.startsWith(href + "/");
+ };
return (