"use client"; import { useState, useEffect, useRef } from "react"; import { useRouter } from "next/navigation"; import Link from "next/link"; import { Pencil, Trash2, Pin, Star, SlidersHorizontal, ChevronDown, Check, Loader2, X } from "lucide-react"; import { apiMe, apiDeletePost, apiTogglePin, apiToggleRecommend, type User } from "@/lib/api"; import { canModerateBoard, isAdminOrAbove } from "@/lib/roles"; import { toast } from "@/lib/toast"; interface PostActionsProps { postId: string; authorId: number; boardId: number; pinned: number; recommended: boolean; } export default function PostActions({ postId, authorId, boardId, pinned, recommended }: PostActionsProps) { const router = useRouter(); const [user, setUser] = useState(null); const [open, setOpen] = useState(false); const [deleting, setDeleting] = useState(false); const [isPinned, setIsPinned] = useState(pinned > 0); const [isRecommended, setIsRecommended] = useState(recommended); const [acting, setActing] = useState(false); const [confirmDelete, setConfirmDelete] = useState(false); const menuRef = useRef(null); useEffect(() => { apiMe() .then((res) => setUser(res.user || null)) .catch(() => setUser(null)); }, []); // 点击外部 / Esc 关闭菜单(与通知铃铛同一交互模式) useEffect(() => { if (!open) return; const onDown = (e: MouseEvent) => { if (menuRef.current && !menuRef.current.contains(e.target as Node)) setOpen(false); }; const onKey = (e: KeyboardEvent) => { if (e.key === "Escape") setOpen(false); }; document.addEventListener("mousedown", onDown); document.addEventListener("keydown", onKey); return () => { document.removeEventListener("mousedown", onDown); document.removeEventListener("keydown", onKey); }; }, [open]); // 作者本人或有该板块审核权的管理团队可管理;置顶/加精仅管理员及以上 const canManage = !!user && (user.id === authorId || canModerateBoard(user, boardId)); const isAdmin = !!user && isAdminOrAbove(user.role); const handleDelete = async () => { setDeleting(true); try { const res = await apiDeletePost(postId); if (res.message) { setConfirmDelete(false); router.push("/"); toast("帖子已删除", "ok"); } else { toast(res.error || "删除失败"); } } catch { toast("网络错误,删除失败"); } finally { setDeleting(false); } }; const handlePin = async () => { setActing(true); setOpen(false); try { const res = await apiTogglePin(postId); setIsPinned(res.pinned > 0); toast(res.pinned > 0 ? "已置顶" : "已取消置顶", "ok"); router.refresh(); } catch { toast("操作失败,请稍后重试"); } finally { setActing(false); } }; const handleRecommend = async () => { setActing(true); setOpen(false); try { const res = await apiToggleRecommend(postId); setIsRecommended(res.recommended); toast(res.recommended ? "已设为推荐" : "已取消推荐", "ok"); router.refresh(); } catch { toast("操作失败,请稍后重试"); } finally { setActing(false); } }; if (!canManage) return null; const itemCls = "w-full flex items-center gap-2.5 px-4 py-2.5 text-[13px] transition-colors hover:bg-[var(--accent-soft)] focus-visible:bg-[var(--accent-soft)]"; return (
{open && (
{isAdmin && ( <>
)} 编辑帖子
)} {confirmDelete && (
!deleting && setConfirmDelete(false)} >
e.stopPropagation()} role="dialog" aria-modal="true" >

删除帖子

确定要删除这篇帖子吗?此操作不可恢复。

)}
); }