后端 Go+Gin:认证/CSRF/限流、板块、帖子、评论、点赞、通知、用户资料、置顶推荐;前端 Next.js 16:发帖/编辑/删除、搜索、分页、点赞、通知中心、设置;基础设施 docker-compose 与配置模板;添加 .gitignore 与专有许可证(保留所有权利)
94 lines
3.3 KiB
TypeScript
94 lines
3.3 KiB
TypeScript
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>
|
|
);
|
|
}
|