From 3e0219388aca744a0880ee90f4b61d509cfa75df Mon Sep 17 00:00:00 2001 From: ByungCheol Date: Sat, 11 Jul 2026 21:48:47 +0900 Subject: [PATCH] =?UTF-8?q?feat(admin):=20=ED=94=BC=EC=8B=A0=EA=B3=A0?= =?UTF-8?q?=EC=9E=90=20=EA=B4=80=EB=A6=AC=20+=20=EB=B8=94=EB=9E=99?= =?UTF-8?q?=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=ED=99=94=EB=A9=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 피신고자 관리(/reports): 피신고자 집계 표(총/미처리/사유), 신고 내역 다이얼로그(처리/기각), 블랙리스트 차단 - 블랙리스트(/blacklist): 목록·이메일 차단 추가·해제 - api/reports, api/blacklist, 라우트·좌측 메뉴 추가 Co-Authored-By: Claude Opus 4.8 (1M context) --- src/api/blacklist.ts | 22 ++++ src/api/reports.ts | 32 ++++++ src/layouts/AdminLayout.vue | 2 + src/pages/BlacklistPage.vue | 123 +++++++++++++++++++++++ src/pages/ReportsPage.vue | 193 ++++++++++++++++++++++++++++++++++++ src/router/index.ts | 2 + 6 files changed, 374 insertions(+) create mode 100644 src/api/blacklist.ts create mode 100644 src/api/reports.ts create mode 100644 src/pages/BlacklistPage.vue create mode 100644 src/pages/ReportsPage.vue diff --git a/src/api/blacklist.ts b/src/api/blacklist.ts new file mode 100644 index 0000000..6e4f759 --- /dev/null +++ b/src/api/blacklist.ts @@ -0,0 +1,22 @@ +import { http } from './http' + +export interface BlacklistItem { + id: number + userId: number | null + email: string | null + nickname: string | null + reason: string | null + createdAt: string +} + +export interface BlacklistAdd { + userId?: number + email?: string + reason?: string +} + +export const blacklistApi = { + list: () => http.get('/api/admin/blacklist'), + add: (body: BlacklistAdd) => http.post('/api/admin/blacklist', body), + remove: (id: number) => http.del(`/api/admin/blacklist/${id}`), +} diff --git a/src/api/reports.ts b/src/api/reports.ts new file mode 100644 index 0000000..ece9ed0 --- /dev/null +++ b/src/api/reports.ts @@ -0,0 +1,32 @@ +import { http } from './http' + +export interface ReportedUser { + userId: number + email: string + nickname: string + status: string + totalReports: number + pendingReports: number + lastReportedAt: string | null + reasons: string[] +} + +export interface ReportItem { + id: number + reporter: string | null + targetType: string + reason: string + detail: string | null + status: string + createdAt: string +} + +export type ReportStatus = 'PENDING' | 'RESOLVED' | 'DISMISSED' + +export const reportsApi = { + reportedUsers: () => http.get('/api/admin/reports/reported-users'), + byUser: (reportedUserId: number) => + http.get(`/api/admin/reports?reportedUserId=${reportedUserId}`), + updateStatus: (id: number, status: ReportStatus) => + http.put(`/api/admin/reports/${id}/status`, { status }), +} diff --git a/src/layouts/AdminLayout.vue b/src/layouts/AdminLayout.vue index 9ad4b76..11090b5 100644 --- a/src/layouts/AdminLayout.vue +++ b/src/layouts/AdminLayout.vue @@ -61,6 +61,8 @@ const menu = [ { name: 'dashboard', label: '대시보드', icon: 'dashboard' }, { name: 'members', label: '회원 관리', icon: 'group' }, { name: 'subscriptions', label: '구독 관리', icon: 'card_membership' }, + { name: 'reports', label: '피신고자 관리', icon: 'report' }, + { name: 'blacklist', label: '블랙리스트', icon: 'block' }, ] async function onLogout() { diff --git a/src/pages/BlacklistPage.vue b/src/pages/BlacklistPage.vue new file mode 100644 index 0000000..daeb4bf --- /dev/null +++ b/src/pages/BlacklistPage.vue @@ -0,0 +1,123 @@ + + + diff --git a/src/pages/ReportsPage.vue b/src/pages/ReportsPage.vue new file mode 100644 index 0000000..99a68bb --- /dev/null +++ b/src/pages/ReportsPage.vue @@ -0,0 +1,193 @@ + + + diff --git a/src/router/index.ts b/src/router/index.ts index 0ff25a3..c9f1a36 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -17,6 +17,8 @@ const routes: RouteRecordRaw[] = [ { path: 'members', name: 'members', component: () => import('@/pages/MembersPage.vue') }, { path: 'members/:id', name: 'member-detail', component: () => import('@/pages/MemberDetailPage.vue') }, { path: 'subscriptions', name: 'subscriptions', component: () => import('@/pages/SubscriptionsPage.vue') }, + { path: 'reports', name: 'reports', component: () => import('@/pages/ReportsPage.vue') }, + { path: 'blacklist', name: 'blacklist', component: () => import('@/pages/BlacklistPage.vue') }, ], }, ]