首次提交:姜十三论坛
后端 Go+Gin:认证/CSRF/限流、板块、帖子、评论、点赞、通知、用户资料、置顶推荐;前端 Next.js 16:发帖/编辑/删除、搜索、分页、点赞、通知中心、设置;基础设施 docker-compose 与配置模板;添加 .gitignore 与专有许可证(保留所有权利)
This commit is contained in:
93
frontend/app/u/[id]/page.tsx
Normal file
93
frontend/app/u/[id]/page.tsx
Normal file
@@ -0,0 +1,93 @@
|
||||
import Link from "next/link";
|
||||
import { Metadata } from "next";
|
||||
import { fetchUserProfile, type UserProfile } from "@/lib/api";
|
||||
import Pagination from "@/components/Pagination";
|
||||
import UserProfileClient from "./UserProfileClient";
|
||||
|
||||
interface UserPageProps {
|
||||
params: Promise<{ id: string }>;
|
||||
searchParams: Promise<{ page?: string; tab?: string }>;
|
||||
}
|
||||
|
||||
export async function generateMetadata({ params }: UserPageProps): Promise<Metadata> {
|
||||
const { id } = await params;
|
||||
return {
|
||||
title: `用户资料 - 姜十三论坛`,
|
||||
description: `查看用户 ${id} 的资料、发帖与评论`,
|
||||
};
|
||||
}
|
||||
|
||||
export default async function UserPage({ params, searchParams }: UserPageProps) {
|
||||
const { id } = await params;
|
||||
const { page: pageStr } = await searchParams;
|
||||
const page = Math.max(1, parseInt(pageStr || "1", 10) || 1);
|
||||
|
||||
let data: UserProfile;
|
||||
try {
|
||||
data = await fetchUserProfile(id, page);
|
||||
} catch {
|
||||
return (
|
||||
<div className="text-center py-16" style={{ color: "var(--text-secondary)" }}>
|
||||
<p className="text-lg">用户不存在</p>
|
||||
<Link href="/" className="mt-4 inline-block hover:underline" style={{ color: "var(--primary)" }}>
|
||||
返回首页
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const u = data.user;
|
||||
const roleLabel = u.role === "admin" ? "管理员" : "用户";
|
||||
|
||||
return (
|
||||
<div className="max-w-4xl mx-auto">
|
||||
{/* 用户信息卡片 */}
|
||||
<div
|
||||
className="rounded-xl border p-6 mb-6 flex items-start gap-5"
|
||||
style={{ borderColor: "var(--border)", background: "var(--bg)" }}
|
||||
>
|
||||
<div
|
||||
className="w-20 h-20 rounded-full flex items-center justify-center text-2xl font-bold shrink-0"
|
||||
style={{ background: "var(--bg-secondary)", color: "var(--primary)" }}
|
||||
>
|
||||
{u.avatar ? (
|
||||
<img src={u.avatar} alt={u.nickname} className="w-full h-full rounded-full object-cover" />
|
||||
) : (
|
||||
(u.nickname || u.username).charAt(0).toUpperCase()
|
||||
)}
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="flex items-center gap-2 flex-wrap">
|
||||
<h1 className="text-2xl font-bold" style={{ color: "var(--text)" }}>
|
||||
{u.nickname || u.username}
|
||||
</h1>
|
||||
{u.role === "admin" && (
|
||||
<span
|
||||
className="text-xs px-2 py-0.5 rounded font-medium"
|
||||
style={{ background: "var(--primary)", color: "white" }}
|
||||
>
|
||||
{roleLabel}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<p className="text-sm mt-1" style={{ color: "var(--text-secondary)" }}>
|
||||
@{u.username} · 加入于 {new Date(u.created_at).toLocaleDateString("zh-CN")}
|
||||
</p>
|
||||
<div className="flex gap-6 mt-3 text-sm">
|
||||
<span style={{ color: "var(--text)" }}>
|
||||
<strong>{data.stats.post_count}</strong>{" "}
|
||||
<span style={{ color: "var(--text-secondary)" }}>帖子</span>
|
||||
</span>
|
||||
<span style={{ color: "var(--text)" }}>
|
||||
<strong>{data.stats.comment_count}</strong>{" "}
|
||||
<span style={{ color: "var(--text-secondary)" }}>评论</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 发帖 / 评论 切换 */}
|
||||
<UserProfileClient userId={id} initialPosts={data} initialPage={page} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user