import { App, Button, Form, Input, Modal, Select } from "antd"; import type { ColumnsType } from "antd/es/table"; import { Plus, Search } from "lucide-react"; import { useCallback, useEffect, useState } from "react"; import { PaginationBar } from "@/components/layout/workspace-page"; import { useDebouncedValue } from "@/hooks/use-debounced-value"; import { closeAdminAnnouncement, createAdminAnnouncement, listAdminAnnouncements, updateAdminAnnouncement, type AnnouncementLevel, type AnnouncementStatus, type SystemAnnouncement, } from "@/services/api/announcements"; import { AdminDataTable, AdminFilterChip, AdminRowActions, AdminStatusBadge, AdminTableEmpty } from "./admin-ui"; type AnnouncementFormValues = { title: string; content: string; level: AnnouncementLevel; }; const levelOptions: Array<{ value: AnnouncementLevel; label: string }> = [ { value: "info", label: "平台通知" }, { value: "success", label: "状态恢复" }, { value: "warning", label: "服务提醒" }, { value: "critical", label: "重要通知" }, ]; const levelMeta: Record = { info: { label: "平台通知", tone: "info" }, success: { label: "状态恢复", tone: "success" }, warning: { label: "服务提醒", tone: "warning" }, critical: { label: "重要通知", tone: "error" }, }; export default function AdminAnnouncementsPanel() { const { message } = App.useApp(); const [form] = Form.useForm(); const [announcements, setAnnouncements] = useState([]); const [keyword, setKeyword] = useState(""); const debouncedKeyword = useDebouncedValue(keyword); const [status, setStatus] = useState<"all" | AnnouncementStatus>("all"); const [page, setPage] = useState(1); const [pageSize, setPageSize] = useState(20); const [total, setTotal] = useState(0); const [loading, setLoading] = useState(false); const [modalOpen, setModalOpen] = useState(false); const [editingAnnouncement, setEditingAnnouncement] = useState(null); const [publishing, setPublishing] = useState(false); const [closingId, setClosingId] = useState(""); const reload = useCallback(async () => { setLoading(true); try { const data = await listAdminAnnouncements({ keyword: debouncedKeyword || undefined, status: status === "all" ? undefined : status, page, limit: pageSize }); setAnnouncements(data.announcements || []); setTotal(data.total || 0); } catch (error) { message.error(error instanceof Error ? error.message : "读取公告列表失败"); } finally { setLoading(false); } }, [debouncedKeyword, message, page, pageSize, status]); useEffect(() => { void reload(); }, [reload]); const openPublishModal = () => { setEditingAnnouncement(null); form.setFieldsValue({ title: "", content: "", level: "info" }); setModalOpen(true); }; const openEditModal = (announcement: SystemAnnouncement) => { setEditingAnnouncement(announcement); form.setFieldsValue({ title: announcement.title, content: announcement.content, level: announcement.level }); setModalOpen(true); }; const publish = async () => { const values = await form.validateFields(); setPublishing(true); try { const input = { title: values.title.trim(), content: values.content.trim(), level: values.level }; if (editingAnnouncement) await updateAdminAnnouncement(editingAnnouncement.id, input); else await createAdminAnnouncement(input); setModalOpen(false); setEditingAnnouncement(null); setPage(1); await reload(); message.success(editingAnnouncement ? "公告已更新并重新发布" : "公告已发布"); } catch (error) { message.error(error instanceof Error ? error.message : editingAnnouncement ? "更新公告失败" : "发布公告失败"); } finally { setPublishing(false); } }; const closeAnnouncement = async (announcement: SystemAnnouncement) => { setClosingId(announcement.id); try { await closeAdminAnnouncement(announcement.id); await reload(); message.success("公告已关闭"); } catch (error) { message.error(error instanceof Error ? error.message : "关闭公告失败"); } finally { setClosingId(""); } }; const columns: ColumnsType = [ { title: "公告内容", dataIndex: "title", minWidth: 360, render: (_, announcement) => (
{announcement.title}
{announcement.content}
), }, { title: "级别", dataIndex: "level", width: 120, render: (level: AnnouncementLevel) => { const meta = levelMeta[level] || levelMeta.info; return ; }, }, { title: "状态", dataIndex: "status", width: 100, render: (value: AnnouncementStatus) => , }, { title: "发布时间", dataIndex: "publishedAt", width: 170, render: formatDateTime, }, { title: "关闭时间", dataIndex: "closedAt", width: 170, render: (value?: string) => value ? formatDateTime(value) : "--", }, { title: "操作", key: "actions", width: 160, render: (_, announcement) => openEditModal(announcement) }} actions={announcement.status === "active" ? [{ key: "close", label: "关闭", danger: true, disabled: closingId === announcement.id, onClick: () => void closeAnnouncement(announcement), confirm: { title: "关闭这条公告?", description: "关闭后用户公告中心将不再展示,历史记录会保留。", okText: "关闭公告" } }] : []} />, }, ]; return ( <> } value={keyword} placeholder="搜索公告标题或正文" onChange={(event) => { setKeyword(event.target.value); setPage(1); }} />} toolbarActiveFilters={<>{keyword ? { setKeyword(""); setPage(1); }} /> : null}{status !== "all" ? { setStatus("all"); setPage(1); }} /> : null}} toolbarActive={Boolean(keyword || status !== "all")} toolbarFilters={