"use client"; import { useCallback, useEffect, useState } from "react"; import Link from "next/link"; import { Plus, Pencil, Trash2, Loader2, Save, X, ExternalLink, Megaphone, FileText, } from "lucide-react"; import { apiAdminListAnnouncements, apiAdminCreateAnnouncement, apiAdminUpdateAnnouncement, apiAdminDeleteAnnouncement, type Announcement, type AnnouncementColor, type AnnouncementInput, } from "@/lib/api"; import { formatDate } from "@/lib/format"; import { toast } from "@/lib/toast"; const COLORS: { value: AnnouncementColor; label: string }[] = [ { value: "blue", label: "蓝色" }, { value: "green", label: "绿色" }, { value: "orange", label: "橙色" }, { value: "red", label: "红色" }, { value: "purple", label: "紫色" }, { value: "gray", label: "灰色" }, ]; type FormState = AnnouncementInput & { id: number | null }; const EMPTY_FORM: FormState = { id: null, title: "", content: "", tag: "公告", tag_color: "blue", published: true, }; export default function AnnouncementAdmin() { const [list, setList] = useState([]); const [loading, setLoading] = useState(true); const [loadError, setLoadError] = useState(""); const [form, setForm] = useState(null); const [saving, setSaving] = useState(false); const [deletingId, setDeletingId] = useState(null); const load = useCallback(async () => { setLoading(true); try { const res = await apiAdminListAnnouncements(); setList(res.announcements); setLoadError(""); } catch (e) { setLoadError(e instanceof Error ? e.message : "加载公告失败"); } finally { setLoading(false); } }, []); useEffect(() => { load(); }, [load]); const startCreate = () => setForm({ ...EMPTY_FORM }); const startEdit = (a: Announcement) => setForm({ id: a.id, title: a.title, content: a.content, tag: a.tag, tag_color: a.tag_color, published: a.published, }); async function save() { if (!form) return; const payload: AnnouncementInput = { title: form.title.trim(), content: form.content.trim(), tag: form.tag.trim() || "公告", tag_color: form.tag_color, published: form.published, }; if (!payload.title || !payload.content) { toast("标题和内容不能为空"); return; } setSaving(true); try { if (form.id == null) { await apiAdminCreateAnnouncement(payload); toast("公告已发布", "ok"); } else { await apiAdminUpdateAnnouncement(form.id, payload); toast("公告已更新", "ok"); } setForm(null); await load(); } catch (e) { toast(e instanceof Error ? e.message : "保存失败"); } finally { setSaving(false); } } async function remove(a: Announcement) { if (!window.confirm(`确定删除公告「${a.title}」吗?此操作不可撤销。`)) return; setDeletingId(a.id); try { await apiAdminDeleteAnnouncement(a.id); setList((l) => l.filter((x) => x.id !== a.id)); if (form?.id === a.id) setForm(null); toast("公告已删除", "ok"); } catch (e) { toast(e instanceof Error ? e.message : "删除失败"); } finally { setDeletingId(null); } } return (
{/* 页头 */}

站点公告管理

发布、编辑与下线右栏站点公告,支持自定义标签与标签颜色

{form?.id == null && ( )}
{/* 编辑/新建表单 */} {form ? (

{form.id == null ? "新建公告" : "编辑公告"}

setForm({ ...form, title: e.target.value })} placeholder="请输入公告标题" />
setForm({ ...form, tag: e.target.value })} placeholder="公告" />

标签颜色

{COLORS.map((c) => (

发布状态