From 29d7648a2b681b0c8b78eec31ba7bacea3f4ccf1 Mon Sep 17 00:00:00 2001 From: yml Date: Fri, 5 Jun 2026 20:52:12 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=AE=A1=E7=90=86=E5=90=8E?= =?UTF-8?q?=E5=8F=B0=E5=85=AC=E5=91=8A=E7=AE=A1=E7=90=86=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 新增功能 - 管理后台公告管理页面(/admin/announcements) - 公告 CRUD 操作(创建、编辑、删除) - 公告发布和归档功能 - 按状态和分类筛选 - 在侧边栏添加公告管理入口 ## 功能特性 - 支持设置优先级、置顶、重要标记 - 富文本编辑器(支持 Markdown/HTML) - 实时查看浏览次数 - 权限控制(announcement:view 和 announcement:manage) Co-Authored-By: Claude Opus 4.6 (1M context) --- .../features/admin/api/adminAnnouncements.ts | 58 +++ .../admin/components/AnnouncementDialog.vue | 169 +++++++++ .../admin/views/AdminAnnouncementsView.vue | 330 ++++++++++++++++++ frontend/src/layouts/AdminLayout.vue | 2 + frontend/src/router/adminRoutes.ts | 6 + 5 files changed, 565 insertions(+) create mode 100644 frontend/src/features/admin/api/adminAnnouncements.ts create mode 100644 frontend/src/features/admin/components/AnnouncementDialog.vue create mode 100644 frontend/src/features/admin/views/AdminAnnouncementsView.vue diff --git a/frontend/src/features/admin/api/adminAnnouncements.ts b/frontend/src/features/admin/api/adminAnnouncements.ts new file mode 100644 index 0000000..c946c72 --- /dev/null +++ b/frontend/src/features/admin/api/adminAnnouncements.ts @@ -0,0 +1,58 @@ +import { apiClient } from '@/shared/api/client' +import type { ApiResponse } from '@/shared/types/types' +import type { Announcement, PaginatedResult } from './announcements' + +export interface CreateAnnouncementRequest { + title: string + content: string + category: 'notice' | 'tutorial' | 'rule' | 'faq' + priority?: number + is_pinned?: boolean + is_important?: boolean +} + +export interface UpdateAnnouncementRequest { + title?: string + content?: string + category?: 'notice' | 'tutorial' | 'rule' | 'faq' + priority?: number + is_pinned?: boolean + is_important?: boolean +} + +export async function fetchAdminAnnouncements(params: { + status?: string + category?: string + page?: number + page_size?: number +}): Promise> { + const { data } = await apiClient.get>>('/admin/announcements', { params }) + return data.data +} + +export async function fetchAdminAnnouncementDetail(id: number): Promise { + const { data } = await apiClient.get>(`/admin/announcements/${id}`) + return data.data +} + +export async function createAnnouncement(req: CreateAnnouncementRequest): Promise { + const { data } = await apiClient.post>('/admin/announcements', req) + return data.data +} + +export async function updateAnnouncement(id: number, req: UpdateAnnouncementRequest): Promise { + const { data } = await apiClient.put>(`/admin/announcements/${id}`, req) + return data.data +} + +export async function publishAnnouncement(id: number): Promise { + await apiClient.post(`/admin/announcements/${id}/publish`) +} + +export async function archiveAnnouncement(id: number): Promise { + await apiClient.post(`/admin/announcements/${id}/archive`) +} + +export async function deleteAnnouncement(id: number): Promise { + await apiClient.delete(`/admin/announcements/${id}`) +} diff --git a/frontend/src/features/admin/components/AnnouncementDialog.vue b/frontend/src/features/admin/components/AnnouncementDialog.vue new file mode 100644 index 0000000..60dfea2 --- /dev/null +++ b/frontend/src/features/admin/components/AnnouncementDialog.vue @@ -0,0 +1,169 @@ + + + + + diff --git a/frontend/src/features/admin/views/AdminAnnouncementsView.vue b/frontend/src/features/admin/views/AdminAnnouncementsView.vue new file mode 100644 index 0000000..4a2b2a5 --- /dev/null +++ b/frontend/src/features/admin/views/AdminAnnouncementsView.vue @@ -0,0 +1,330 @@ + + + + + diff --git a/frontend/src/layouts/AdminLayout.vue b/frontend/src/layouts/AdminLayout.vue index 3f170a8..b7c5794 100644 --- a/frontend/src/layouts/AdminLayout.vue +++ b/frontend/src/layouts/AdminLayout.vue @@ -1,5 +1,6 @@