import { App, Button, Form, Input, Modal, Popconfirm, Select, Table, Tag } from "antd"; import type { ColumnsType } from "antd/es/table"; import { BellRing, CircleAlert, Info, Plus, Search, ShieldAlert, Wrench } from "lucide-react"; import { useCallback, useEffect, useState } from "react"; import { ListToolbar, TableSurface } from "@/components/layout/workspace-page"; import { useDebouncedValue } from "@/hooks/use-debounced-value"; import { closeAdminAnnouncement, createAdminAnnouncement, listAdminAnnouncements, type AnnouncementLevel, type AnnouncementStatus, type SystemAnnouncement, } from "@/services/api/announcements"; 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: "平台通知", color: "blue", icon: Info }, success: { label: "状态恢复", color: "green", icon: Wrench }, warning: { label: "服务提醒", color: "orange", icon: CircleAlert }, critical: { label: "重要通知", color: "red", icon: ShieldAlert }, }; 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 [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 = () => { form.setFieldsValue({ title: "", content: "", level: "info" }); setModalOpen(true); }; const publish = async () => { const values = await form.validateFields(); setPublishing(true); try { await createAdminAnnouncement({ title: values.title.trim(), content: values.content.trim(), level: values.level }); setModalOpen(false); setPage(1); await reload(); message.success("公告已发布"); } catch (error) { message.error(error instanceof Error ? error.message : "发布公告失败"); } 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; const Icon = meta.icon; return }>{meta.label}; }, }, { title: "状态", dataIndex: "status", width: 100, render: (value: AnnouncementStatus) => value === "active" ? 发布中 : 已关闭, }, { title: "发布时间", dataIndex: "publishedAt", width: 170, render: formatDateTime, }, { title: "关闭时间", dataIndex: "closedAt", width: 170, render: (value?: string) => value ? formatDateTime(value) : "--", }, { title: "操作", key: "actions", fixed: "right", width: 100, render: (_, announcement) => announcement.status === "active" ? ( void closeAnnouncement(announcement)}> ) : 已结束, }, ]; return ( <>
共保留 {total} 条公告记录
关闭公告会立即从用户公告中心移除
{ setKeyword(""); setStatus("all"); setPage(1); }}> } value={keyword} placeholder="搜索公告标题或正文" onChange={(event) => { setKeyword(event.target.value); setPage(1); }} />