"use client"; import { useCallback, useRef, useState } from "react"; import Link from "next/link"; import { ArrowLeft, ExternalLink, FileText, MessageCircle, MessagesSquare } from "lucide-react"; import { apiAdminUserAuditComments, apiAdminUserAuditMessages, apiAdminUserAuditPosts, type AdminAuditCommentItem, type AdminAuditMessageItem, type AdminAuditPostItem, type AdminUserAuditProfile, } from "@/lib/api"; import { formatDate, formatRelative } from "@/lib/format"; import Avatar from "@/components/Avatar"; import RoleBadge from "@/components/RoleBadge"; import { AdminEmpty, AdminPager, AdminSegmented, AdminStatusChip, type AdminStatusTone, } from "@/components/admin"; type TabKey = "posts" | "comments" | "messages"; const PAGE_SIZE = 20; /** 内容/消息状态粒:可叠加(如已删除 + 待审) */ function StatusChips({ status, deleted, recalled, }: { status?: string; deleted?: boolean; recalled?: boolean; }) { const chips: { label: string; tone: AdminStatusTone }[] = []; if (deleted) chips.push({ label: "已删除", tone: "danger" }); if (recalled) chips.push({ label: "已撤回", tone: "muted" }); if (status === "pending") chips.push({ label: "待审", tone: "warn" }); if (status === "rejected") chips.push({ label: "已驳回", tone: "danger" }); if (status === "published" && !deleted) { chips.push({ label: "已发布", tone: "ok" }); } if (chips.length === 0 && !recalled) { chips.push({ label: "正常", tone: "muted" }); } return ( {chips.map((c) => ( {c.label} ))} ); } export default function UserAuditClient({ userId, initial, initialPosts, initialPostsTotal, initError, }: { userId: number; initial: AdminUserAuditProfile; initialPosts: AdminAuditPostItem[]; initialPostsTotal: number; initError: string; }) { const [profile] = useState(initial); const [tab, setTab] = useState("posts"); const [loading, setLoading] = useState(false); const [error, setError] = useState(initError); const [posts, setPosts] = useState(initialPosts); const [comments, setComments] = useState([]); const [messages, setMessages] = useState([]); const [postsTotal, setPostsTotal] = useState(initialPostsTotal); const [commentsTotal, setCommentsTotal] = useState(0); const [messagesTotal, setMessagesTotal] = useState(0); const [postsPage, setPostsPage] = useState(1); const [commentsPage, setCommentsPage] = useState(1); const [messagesPage, setMessagesPage] = useState(1); const loadSeq = useRef(0); const loadedRef = useRef({ posts: true, comments: false, messages: false }); const u = profile.user; const loadPosts = useCallback( async (p: number) => { const seq = ++loadSeq.current; setLoading(true); try { const res = await apiAdminUserAuditPosts(userId, p); if (seq !== loadSeq.current) return; setPosts(res.items || []); setPostsTotal(res.total); setPostsPage(p); loadedRef.current.posts = true; setTab("posts"); setError(""); } catch (e) { if (seq !== loadSeq.current) return; setError(e instanceof Error ? e.message : "加载失败"); } finally { if (seq === loadSeq.current) setLoading(false); } }, [userId] ); const loadComments = useCallback( async (p: number) => { const seq = ++loadSeq.current; setLoading(true); try { const res = await apiAdminUserAuditComments(userId, p); if (seq !== loadSeq.current) return; setComments(res.items || []); setCommentsTotal(res.total); setCommentsPage(p); loadedRef.current.comments = true; setTab("comments"); setError(""); } catch (e) { if (seq !== loadSeq.current) return; setError(e instanceof Error ? e.message : "加载失败"); } finally { if (seq === loadSeq.current) setLoading(false); } }, [userId] ); const loadMessages = useCallback( async (p: number) => { const seq = ++loadSeq.current; setLoading(true); try { const res = await apiAdminUserAuditMessages(userId, p); if (seq !== loadSeq.current) return; setMessages(res.items || []); setMessagesTotal(res.total); setMessagesPage(p); loadedRef.current.messages = true; setTab("messages"); setError(""); } catch (e) { if (seq !== loadSeq.current) return; setError(e instanceof Error ? e.message : "加载失败"); } finally { if (seq === loadSeq.current) setLoading(false); } }, [userId] ); const switchTab = (t: TabKey) => { if (t === tab) return; setError(""); if (loadedRef.current[t]) { loadSeq.current += 1; setLoading(false); setTab(t); return; } if (t === "posts") void loadPosts(1); else if (t === "comments") void loadComments(1); else void loadMessages(1); }; const goPage = (p: number) => { if (tab === "posts") void loadPosts(p); else if (tab === "comments") void loadComments(p); else void loadMessages(p); }; const tabCount = (t: TabKey) => { if (t === "posts") return profile.posts_total; if (t === "comments") return profile.comments_total; return profile.messages_total; }; const page = tab === "posts" ? postsPage : tab === "comments" ? commentsPage : messagesPage; const total = tab === "posts" ? postsTotal : tab === "comments" ? commentsTotal : messagesTotal; const empty = tab === "posts" ? posts.length === 0 : tab === "comments" ? comments.length === 0 : messages.length === 0; const emptyIcon = tab === "posts" ? ( ) : tab === "comments" ? ( ) : ( ); return (
返回用户列表

{u.nickname}

{u.banned && 已封禁}

@{u.username}

注册于 {formatDate(u.created_at)} · 已发布帖 {profile.published_posts} / 评{" "} {profile.published_comments}

主页
{[ { label: "全部帖子", value: profile.posts_total }, { label: "全部评论", value: profile.comments_total }, { label: "全部消息", value: profile.messages_total }, ].map((c) => (

{c.value.toLocaleString("zh-CN")}

{c.label}

))}
ariaLabel="内容分类" value={tab} onChange={switchTab} options={[ { key: "posts", label: "帖子", icon: , count: tabCount("posts"), }, { key: "comments", label: "评论", icon: , count: tabCount("comments"), }, { key: "messages", label: "私信与群消息", icon: , count: tabCount("messages"), }, ]} />
{error && (

{error}

)} {!error && empty && } {tab === "posts" && posts.map((p) => (
{p.board_name && ( {p.board_name} )}
{p.deleted ? (

{p.title || "(无标题)"}

) : ( {p.title || "(无标题)"} )} {p.content && (

{p.content}

)}
{formatRelative(p.created_at)}
))} {tab === "comments" && comments.map((c) => (
{c.deleted ? ( 帖子 #{c.post_id} ) : ( 帖子 #{c.post_id} )}

{c.content || "(空)"}

{formatRelative(c.created_at)}
))} {tab === "messages" && messages.map((m) => (
{m.room_name} {m.room_type === "direct" ? " · 私聊" : m.room_type === "group" ? " · 群聊" : ""}

{m.content || "(空)"}

{formatRelative(m.created_at)}
))}
); }