diff --git a/frontend/src/pages/pc/admin/dashboard/Dashboard.jsx b/frontend/src/pages/pc/admin/dashboard/Dashboard.jsx
index 4a30d65..6485cbd 100644
--- a/frontend/src/pages/pc/admin/dashboard/Dashboard.jsx
+++ b/frontend/src/pages/pc/admin/dashboard/Dashboard.jsx
@@ -4,7 +4,7 @@
import { Link } from 'react-router-dom';
import { useQuery } from '@tanstack/react-query';
import { motion } from 'framer-motion';
-import { Disc3, Calendar, Users, Home, ChevronRight } from 'lucide-react';
+import { Disc3, Calendar, Users, Home, ChevronRight, ScrollText } from 'lucide-react';
import { AdminLayout } from '@/components/pc/admin';
import { useAdminAuth } from '@/hooks/pc/admin';
import { adminStatsApi } from '@/api/admin';
@@ -88,6 +88,13 @@ function AdminDashboard() {
path: '/admin/schedule',
color: 'bg-blue-500',
},
+ {
+ icon: ScrollText,
+ label: '활동 로그',
+ description: '관리자 및 봇 활동 기록 조회',
+ path: '/admin/logs',
+ color: 'bg-gray-500',
+ },
];
return (
diff --git a/frontend/src/pages/pc/admin/logs/ActivityLogs.jsx b/frontend/src/pages/pc/admin/logs/ActivityLogs.jsx
index 1df507d..06e79f0 100644
--- a/frontend/src/pages/pc/admin/logs/ActivityLogs.jsx
+++ b/frontend/src/pages/pc/admin/logs/ActivityLogs.jsx
@@ -3,12 +3,12 @@
*/
import { useState, useMemo } from 'react';
import { Link } from 'react-router-dom';
-import { motion } from 'framer-motion';
+import { motion, AnimatePresence } from 'framer-motion';
import {
Home, ChevronRight, Search, ChevronLeft, ChevronDown,
User, Bot, ScrollText, X,
} from 'lucide-react';
-import { AdminLayout } from '@/components/pc/admin';
+import { AdminLayout, DatePicker } from '@/components/pc/admin';
import { useAdminAuth } from '@/hooks/pc/admin';
// 더미 데이터
@@ -22,7 +22,7 @@ const DUMMY_LOGS = [
{ id: 7, actor: 'admin', action: 'delete', category: 'schedule', target_type: 'youtube_schedule', target_id: 456, summary: 'YouTube 일정 삭제: 이전 영상', details: null, created_at: '2026-03-02T14:00:00' },
{ id: 8, actor: 'admin', action: 'create', category: 'concert', target_type: 'concert', target_id: 5, summary: '콘서트 일정 생성: fromis_9 팬미팅', details: null, created_at: '2026-03-02T13:55:00' },
{ id: 9, actor: 'admin', action: 'update', category: 'category', target_type: 'category', target_id: 3, summary: '카테고리 수정: 음악방송', details: null, created_at: '2026-03-02T13:50:00' },
- { id: 10, actor: 'admin', action: 'reorder', category: 'category', target_type: 'category', target_id: null, summary: '카테고리 순서 변경', details: null, created_at: '2026-03-02T13:45:00' },
+ { id: 10, actor: 'admin', action: 'update', category: 'category', target_type: 'category', target_id: null, summary: '카테고리 순서 변경', details: null, created_at: '2026-03-02T13:45:00' },
{ id: 11, actor: 'youtube-1', action: 'error', category: 'sync', target_type: 'youtube_bot', target_id: 1, summary: '동기화 에러: API 할당량 초과', details: { error: 'quotaExceeded' }, created_at: '2026-03-02T13:40:00' },
{ id: 12, actor: 'admin', action: 'start', category: 'bot', target_type: 'youtube_bot', target_id: 3, summary: 'YouTube 봇 시작: 스프', details: null, created_at: '2026-03-02T13:35:00' },
{ id: 13, actor: 'admin', action: 'stop', category: 'bot', target_type: 'youtube_bot', target_id: 2, summary: 'YouTube 봇 정지: 채널 비활성화', details: null, created_at: '2026-03-02T13:30:00' },
@@ -57,7 +57,6 @@ const ACTION_STYLES = {
create: 'bg-emerald-100 text-emerald-700',
upload: 'bg-emerald-100 text-emerald-700',
update: 'bg-blue-100 text-blue-700',
- reorder: 'bg-blue-100 text-blue-700',
delete: 'bg-red-100 text-red-700',
sync_complete: 'bg-purple-100 text-purple-700',
error: 'bg-red-100 text-red-700',
@@ -70,7 +69,6 @@ const ACTION_LABELS = {
create: '생성',
upload: '업로드',
update: '수정',
- reorder: '순서변경',
delete: '삭제',
sync_complete: '동기화',
error: '에러',
@@ -137,11 +135,12 @@ function ActivityLogs() {
// 날짜/시간 포맷
const formatDateTime = (dateStr) => {
const date = new Date(dateStr);
+ const y = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
- return `${month}.${day} ${hours}:${minutes}`;
+ return `${y}.${month}.${day} ${hours}:${minutes}`;
};
// 행위자 아이콘
@@ -219,45 +218,55 @@ function ActivityLogs() {
| 시간 | -행위자 | -액션 | -카테고리 | -내용 | +시간 | +행위자 | +액션 | +카테고리 | +내용 | + | {formatDateTime(log.created_at)} | -+ | {renderActorBadge(log.actor)} | -+ | {ACTION_LABELS[log.action] || log.action} | -+ | {CATEGORIES.find((c) => c.value === log.category)?.label || log.category} | -+ | {log.summary} | diff --git a/frontend/src/routes/pc/admin/index.jsx b/frontend/src/routes/pc/admin/index.jsx index afee464..12e2cd9 100644 --- a/frontend/src/routes/pc/admin/index.jsx +++ b/frontend/src/routes/pc/admin/index.jsx @@ -35,6 +35,7 @@ import AdminYouTubeEditForm from '@/pages/pc/admin/schedules/edit/YouTubeEditFor import AdminScheduleCategory from '@/pages/pc/admin/schedules/ScheduleCategory'; import AdminScheduleDict from '@/pages/pc/admin/schedules/ScheduleDict'; import AdminScheduleBots from '@/pages/pc/admin/schedules/ScheduleBots'; +import AdminActivityLogs from '@/pages/pc/admin/logs/ActivityLogs'; import AdminNotFound from '@/pages/pc/admin/common/NotFound'; /** @@ -59,6 +60,7 @@ export default function AdminRoutes() {
|---|