feat(admin): 系统公告 - 支持置顶排序与管理端标识

Adapted from ddcat-ai/open-ai-canvas#339

Original commit: fcdbe2aa833f31f683f709b7f409a0534ed78e20

Refs #339

Co-authored-by: 宇熙 <101980758+yuxiwl@users.noreply.github.com>
This commit is contained in:
ddCat
2026-08-29 15:06:11 +08:00
parent d84b2b69cc
commit bf37e45dae
8 changed files with 84 additions and 12 deletions

View File

@@ -1,6 +1,6 @@
import { App, Button, Form, Input, Modal, Select } from "antd";
import { App, Button, Form, Input, Modal, Select, Switch, Tag } from "antd";
import type { ColumnsType } from "antd/es/table";
import { Plus, Search } from "lucide-react";
import { Pin, Plus, Search } from "lucide-react";
import { useCallback, useEffect, useState } from "react";
import { PaginationBar } from "@/components/layout/workspace-page";
@@ -20,6 +20,7 @@ type AnnouncementFormValues = {
title: string;
content: string;
level: AnnouncementLevel;
pinned: boolean;
};
const levelOptions: Array<{ value: AnnouncementLevel; label: string }> = [
@@ -71,13 +72,13 @@ export default function AdminAnnouncementsPanel() {
const openPublishModal = () => {
setEditingAnnouncement(null);
form.setFieldsValue({ title: "", content: "", level: "info" });
form.setFieldsValue({ title: "", content: "", level: "info", pinned: false });
setModalOpen(true);
};
const openEditModal = (announcement: SystemAnnouncement) => {
setEditingAnnouncement(announcement);
form.setFieldsValue({ title: announcement.title, content: announcement.content, level: announcement.level });
form.setFieldsValue({ title: announcement.title, content: announcement.content, level: announcement.level, pinned: announcement.pinned });
setModalOpen(true);
};
@@ -85,7 +86,7 @@ export default function AdminAnnouncementsPanel() {
const values = await form.validateFields();
setPublishing(true);
try {
const input = { title: values.title.trim(), content: values.content.trim(), level: values.level };
const input = { title: values.title.trim(), content: values.content.trim(), level: values.level, pinned: Boolean(values.pinned) };
if (editingAnnouncement) await updateAdminAnnouncement(editingAnnouncement.id, input);
else await createAdminAnnouncement(input);
setModalOpen(false);
@@ -125,6 +126,12 @@ export default function AdminAnnouncementsPanel() {
</div>
),
},
{
title: "置顶",
dataIndex: "pinned",
width: 90,
render: (pinned: boolean) => pinned ? <Tag color="gold" icon={<Pin className="size-3" />}>置顶</Tag> : <span className="text-foreground/35">--</span>,
},
{
title: "级别",
dataIndex: "level",
@@ -182,6 +189,9 @@ export default function AdminAnnouncementsPanel() {
<Form.Item name="level" label="公告级别" rules={[{ required: true, message: "请选择公告级别" }]}>
<Select options={levelOptions} />
</Form.Item>
<Form.Item name="pinned" label="展示方式" valuePropName="checked" extra="置顶公告会优先展示。">
<Switch checkedChildren="置顶" unCheckedChildren="普通" />
</Form.Item>
<Form.Item name="content" label="公告正文" rules={[{ required: true, whitespace: true, message: "请填写公告正文" }, { max: 4000, message: "正文不能超过 4000 个字符" }]}>
<Input.TextArea maxLength={4000} showCount autoSize={{ minRows: 6, maxRows: 12 }} placeholder="填写服务状态、影响范围和用户需要采取的操作" />
</Form.Item>