feat(admin): 用户主页增加封禁与改角色快捷菜单
超管/站长可在他人主页就地管理账号;待审评论支持拒绝;角色弹窗前后台共用。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -15,6 +15,7 @@ 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 }>;
|
||||
@@ -50,9 +51,13 @@ export default async function UserPage({ params, searchParams }: UserPageProps)
|
||||
rawTab === "settings" ? "settings" :
|
||||
rawTab === "security" ? "security" : "posts";
|
||||
|
||||
const cookie = authCookieHeader(await cookies());
|
||||
const me = await getMeCached(cookie || undefined);
|
||||
|
||||
let data: UserProfile;
|
||||
try {
|
||||
data = await fetchUserProfile(id, page);
|
||||
// 带 cookie:超管/站长才能拿到 banned 字段
|
||||
data = await fetchUserProfile(id, page, cookie || undefined);
|
||||
} catch {
|
||||
return (
|
||||
<div className="max-w-md mx-auto text-center py-24">
|
||||
@@ -68,8 +73,6 @@ export default async function UserPage({ params, searchParams }: UserPageProps)
|
||||
}
|
||||
|
||||
// 判断是否本人(决定能否看到 settings / security tab)
|
||||
const cookie = authCookieHeader(await cookies());
|
||||
const me = await getMeCached(cookie || undefined);
|
||||
const isOwner = me.user?.id === data.user.id;
|
||||
const currentUser = me.user;
|
||||
const effectiveTab: UserTab =
|
||||
@@ -116,8 +119,8 @@ export default async function UserPage({ params, searchParams }: UserPageProps)
|
||||
</nav>
|
||||
|
||||
{/* ═══ Hero:石墨面板 + 淡靛几何装饰 + 身份信息 + 统计条 ═══ */}
|
||||
<section className="panel relative mb-6 overflow-hidden">
|
||||
{/* 装饰层:裁在面板圆角内 */}
|
||||
<section className="panel relative mb-6">
|
||||
{/* 装饰层单独裁圆角,避免 overflow-hidden 裁掉管理下拉菜单 */}
|
||||
<div aria-hidden className="pointer-events-none absolute inset-0 overflow-hidden rounded-[inherit]">
|
||||
<span
|
||||
className="absolute -top-28 -right-24 w-[440px] h-[440px] rounded-full"
|
||||
@@ -151,7 +154,17 @@ export default async function UserPage({ params, searchParams }: UserPageProps)
|
||||
</Link>
|
||||
</div>
|
||||
) : currentUser ? (
|
||||
<div className="absolute top-3 right-3 sm:top-4 sm:right-4 z-20">
|
||||
<div className="absolute top-3 right-3 sm:top-4 sm:right-4 z-20 flex items-center gap-2">
|
||||
<StaffUserMenu
|
||||
target={{
|
||||
id: u.id,
|
||||
username: u.username,
|
||||
nickname: u.nickname,
|
||||
role: u.role,
|
||||
board_ids: u.board_ids,
|
||||
banned: u.banned,
|
||||
}}
|
||||
/>
|
||||
<StartDMButton userId={data.user.id} />
|
||||
</div>
|
||||
) : null}
|
||||
@@ -186,6 +199,14 @@ export default async function UserPage({ params, searchParams }: UserPageProps)
|
||||
{u.role !== "user" && (
|
||||
<RoleBadge role={u.role} boardIds={u.board_ids} />
|
||||
)}
|
||||
{u.banned === true && (
|
||||
<span
|
||||
className="inline-flex items-center rounded-full px-2 py-0.5 text-[11px] font-semibold"
|
||||
style={{ background: "var(--danger-soft)", color: "var(--danger)" }}
|
||||
>
|
||||
已封禁
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<p className="meta mt-1 flex items-center gap-1.5 text-[12.5px] flex-wrap">
|
||||
<span>@{u.username}</span>
|
||||
|
||||
Reference in New Issue
Block a user