import Link from "next/link"; import { cookies } from "next/headers"; import { Metadata } from "next"; import { ChevronRight, FileText, MessageCircle, Flame, Calendar, Hash, Shield, Settings, KeyRound, Info, PenLine, } from "lucide-react"; import { fetchUserProfile, fetchUserComments, type UserProfile, type UserCommentsResponse } from "@/lib/api"; import { authCookieHeader } from "@/lib/cookies"; import { getMeCached, getPublicSettingsCached } from "@/lib/serverData"; import UserProfileContent from "./UserProfileContent"; import ProfileForm from "./ProfileForm"; import PasswordForm from "./PasswordForm"; import Avatar from "@/components/Avatar"; import RoleBadge from "@/components/RoleBadge"; import { roleMeta } from "@/lib/roles"; import StartDMButton from "./StartDMButton"; import StaffUserMenu from "@/components/StaffUserMenu"; interface UserPageProps { params: Promise<{ id: string }>; searchParams: Promise<{ page?: string; tab?: string }>; } export type UserTab = "posts" | "comments" | "settings" | "security"; export async function generateMetadata({ params }: UserPageProps): Promise { const { id } = await params; try { const data = await fetchUserProfile(id, 1); const allowComments = (await getPublicSettingsCached()).allow_comments !== false; return { title: data.user.nickname || data.user.username, description: allowComments ? `查看 ${data.user.nickname} 的资料、发帖与评论` : `查看 ${data.user.nickname} 的资料与发帖`, }; } catch { return { title: "用户不存在" }; } } // 装饰几何色:全部由主题变量派生,浅色为淡靛、暗色自动提亮 const ACCENT_RING_1 = "color-mix(in srgb, var(--accent) 14%, transparent)"; const ACCENT_RING_2 = "color-mix(in srgb, var(--accent) 9%, transparent)"; export default async function UserPage({ params, searchParams }: UserPageProps) { const { id } = await params; const sp = await searchParams; const page = Math.max(1, parseInt(sp.page || "1", 10) || 1); const rawTab = sp.tab; const tab: UserTab = rawTab === "comments" ? "comments" : rawTab === "settings" ? "settings" : rawTab === "security" ? "security" : "posts"; const cookie = authCookieHeader(await cookies()); const me = await getMeCached(cookie || undefined); const settings = await getPublicSettingsCached(); const allowComments = settings.allow_comments !== false; const allowMessages = settings.allow_messages !== false; let data: UserProfile; try { // 带 cookie:超管/站长才能拿到 banned 字段 data = await fetchUserProfile(id, page, cookie || undefined); } catch { return (

用户不存在

该用户可能已注销或链接有误

返回首页
); } // 判断是否本人(决定能否看到 settings / security tab) const isOwner = me.user?.id === data.user.id; const currentUser = me.user; let effectiveTab: UserTab = (tab === "settings" || tab === "security") && !isOwner ? "posts" : tab; if (!allowComments && effectiveTab === "comments") effectiveTab = "posts"; // 评论 tab:SSR 直出对应分页 let commentData: UserCommentsResponse | null = null; let commentError = false; if (allowComments && effectiveTab === "comments") { try { commentData = await fetchUserComments(id, page); } catch { commentError = true; } } const u = data.user; const joinDate = new Date(u.created_at).toLocaleDateString("zh-CN"); const showPoints = data.stats.points > 0 || isOwner; // 导航项(桌面左栏 / 移动 chips 共用定义) const navItems: { key: UserTab; label: string; count?: number; icon: React.ReactNode; ownerOnly?: boolean }[] = [ { key: "posts", label: "发帖", count: data.stats.post_count, icon: }, ...(allowComments ? [{ key: "comments" as const, label: "评论", count: data.stats.comment_count, icon: }] : []), { key: "settings", label: "资料设置", icon: , ownerOnly: true }, { key: "security", label: "安全设置", icon: , ownerOnly: true }, ]; const visibleNav = navItems.filter((t) => !t.ownerOnly || isOwner); const tabHref = (t: UserTab) => (t === "posts" ? `/u/${id}` : `/u/${id}?tab=${t}`); // 统计条数据 const heroStats = [ { label: "发帖", value: data.stats.post_count }, ...(allowComments ? [{ label: "评论", value: data.stats.comment_count }] : []), { label: "积分", value: data.stats.points, foot: data.stats.streak > 0 ? `连签 ${data.stats.streak} 天` : undefined }, ]; return (
{/* ═══ Hero:石墨面板 + 淡靛几何装饰 + 身份信息 + 统计条 ═══ */}
{/* 装饰层单独裁圆角,避免 overflow-hidden 裁掉管理下拉菜单 */}
{/* 本人操作按钮 / 访客私聊 */} {isOwner ? (
编辑资料
) : currentUser ? (
{allowMessages ? : null}
) : null} {/* 身份信息:纯文档流,头像 + 右侧文字 baseline 对齐 */}

{u.nickname || u.username}

{u.role !== "user" && ( )} {u.banned === true && ( 已封禁 )}

@{u.username} · {joinDate} 加入

{u.signature && (

{u.signature}

)}
{/* 统计条 */}
{heroStats.map((s, i) => (
0 ? { borderLeft: "1px solid var(--line)" } : undefined} >

{s.value}

{s.label} {s.foot && ( {s.foot} )}

))}
{/* 移动端 Tab chips(lg 以下) */}
{visibleNav.map((t) => ( {t.icon} {t.label} {t.count !== undefined && ( {t.count} )} ))}
{/* ═══ 三栏:左导航 / 中内容 / 右信息 ═══ */}
{/* 左栏:Tab 导航 */} {/* 中栏:Tab 内容 */}
{effectiveTab === "posts" || effectiveTab === "comments" ? ( ) : effectiveTab === "settings" && isOwner && currentUser ? (

编辑个人资料

昵称、头像和签名会公开展示,邮箱仅你自己可见

) : effectiveTab === "security" && isOwner ? (

修改密码

修改成功后将在所有设备登出,需要使用新密码重新登录

) : null}
{/* 右栏:账号信息 + 积分 + 安全提示 */}
); }