"use client" import { useEffect, useState } from "react" import Link from "next/link" import { useRouter } from "next/navigation" import { toast } from "sonner" import { useTranslations } from "next-intl" import { Archive, ArrowLeft, CheckCircle2, Megaphone, Pencil, Pin, Send, Trash2, } from "lucide-react" import { Badge } from "@/shared/components/ui/badge" import { Button } from "@/shared/components/ui/button" import { Card, CardContent, CardHeader, CardTitle } from "@/shared/components/ui/card" import { ConfirmDeleteDialog } from "@/shared/components/ui/confirm-delete-dialog" import { cn, formatDate } from "@/shared/lib/utils" import { archiveAnnouncementAction, deleteAnnouncementAction, markAnnouncementAsReadAction, publishAnnouncementAction, toggleAnnouncementPinAction, } from "../actions" import type { Announcement } from "../types" export function AnnouncementDetail({ announcement, canManage, editHref, backHref, }: { announcement: Announcement canManage?: boolean editHref?: string backHref?: string }) { const t = useTranslations("announcements") const router = useRouter() const [isWorking, setIsWorking] = useState(false) const [deleteOpen, setDeleteOpen] = useState(false) const [isPinned, setIsPinned] = useState(announcement.isPinned) const [isTogglingPin, setIsTogglingPin] = useState(false) const [isRead, setIsRead] = useState(announcement.isReadByCurrentUser ?? false) // 用户端自动标记已读(非管理端且未读时) useEffect(() => { if (canManage) return if (isRead) return let cancelled = false void markAnnouncementAsReadAction(announcement.id) .then((res) => { if (cancelled) return if (res.success) { setIsRead(true) } }) .catch(() => { // 静默处理 }) return () => { cancelled = true } }, [canManage, isRead, announcement.id]) const handlePublish = async () => { setIsWorking(true) try { const res = await publishAnnouncementAction(announcement.id) if (res.success) { toast.success(res.message) router.refresh() } else { toast.error(res.message || t("messages.publishFailed")) } } catch { toast.error(t("messages.publishFailed")) } finally { setIsWorking(false) } } const handleArchive = async () => { setIsWorking(true) try { const res = await archiveAnnouncementAction(announcement.id) if (res.success) { toast.success(res.message) router.refresh() } else { toast.error(res.message || t("messages.archiveFailed")) } } catch { toast.error(t("messages.archiveFailed")) } finally { setIsWorking(false) } } const handleDelete = async () => { setIsWorking(true) try { const res = await deleteAnnouncementAction(announcement.id) if (res.success) { toast.success(res.message) router.push("/admin/announcements") router.refresh() } else { toast.error(res.message || t("messages.deleteFailed")) } } catch { toast.error(t("messages.deleteFailed")) } finally { setIsWorking(false) setDeleteOpen(false) } } const handleTogglePin = async () => { setIsTogglingPin(true) const prevPinned = isPinned // 乐观更新 setIsPinned(!prevPinned) try { const res = await toggleAnnouncementPinAction(announcement.id) if (res.success) { toast.success(t("messages.pinToggled")) router.refresh() } else { // 回滚 setIsPinned(prevPinned) toast.error(res.message) } } catch { // 回滚 setIsPinned(prevPinned) toast.error(t("messages.publishFailed")) } finally { setIsTogglingPin(false) } } return (
{backHref ? ( ) : null}

{t("title.detail")}

{canManage ? (
{announcement.status !== "published" ? ( ) : null} {announcement.status !== "archived" ? ( ) : null} {editHref ? ( ) : null}
) : null}
{t(`type.${announcement.type}`)} {t(`status.${announcement.status}`)} {isPinned ? ( ) : null} {/* 用户端:显示已读/未读状态 */} {!canManage ? ( {isRead ? ( <> ) : null} {/* 管理端:显示已读人数 */} {canManage && announcement.readCount !== undefined ? ( {t("meta.readCount", { count: announcement.readCount })} ) : null}
{isPinned ? (
{announcement.publishedAt ? t("meta.publishedAt", { date: formatDate(announcement.publishedAt) }) : t("meta.createdAt", { date: formatDate(announcement.createdAt) })} {announcement.authorName ? {t("meta.author", { name: announcement.authorName })} : null}

{announcement.content}

) }