import { useState } from 'react'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Badge } from '@/components/ui/badge'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { Textarea } from '@/components/ui/textarea'; import { Label } from '@/components/ui/label'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table'; import { Play, Plus, Search, Clock, Pause, RotateCw, Edit, Trash2, History, CheckCircle, XCircle, Loader2, Server, Calendar, Terminal, MoreHorizontal, Eye, Copy, } from 'lucide-react'; import { cronJobs } from '@/mocks/data'; interface CronJob { id: string; name: string; description: string; schedule: string; command: string; status: 'enabled' | 'disabled'; lastRun: string; lastStatus: 'success' | 'failed' | 'running' | 'never'; nextRun: string; targetServers: string[]; createdAt: string; createdBy: string; } const mockCronJobs: CronJob[] = [ { id: 'cron-001', name: '数据库备份', description: '每日凌晨2点备份数据库', schedule: '0 2 * * *', command: '/scripts/backup-db.sh --type=full', status: 'enabled', lastRun: '2025-04-14 02:00:00', lastStatus: 'success', nextRun: '2025-04-15 02:00:00', targetServers: ['db-server-01', 'db-server-02'], createdAt: '2025-01-15', createdBy: 'admin', }, { id: 'cron-002', name: '日志清理', description: '每周日凌晨3点清理过期日志', schedule: '0 3 * * 0', command: '/scripts/clean-logs.sh --days=30', status: 'enabled', lastRun: '2025-04-13 03:00:00', lastStatus: 'success', nextRun: '2025-04-20 03:00:00', targetServers: ['all'], createdAt: '2025-01-20', createdBy: 'admin', }, { id: 'cron-003', name: '健康检查', description: '每5分钟执行健康检查', schedule: '*/5 * * * *', command: '/scripts/health-check.sh', status: 'enabled', lastRun: '2025-04-14 11:55:00', lastStatus: 'running', nextRun: '2025-04-14 12:00:00', targetServers: ['web-server-01', 'web-server-02', 'app-server-01'], createdAt: '2025-02-01', createdBy: 'ops01', }, { id: 'cron-004', name: '数据同步', description: '每小时同步数据到备份服务器', schedule: '0 * * * *', command: '/scripts/sync-data.sh --target=backup', status: 'disabled', lastRun: '2025-04-14 10:00:00', lastStatus: 'failed', nextRun: '-', targetServers: ['app-server-01'], createdAt: '2025-02-15', createdBy: 'ops02', }, { id: 'cron-005', name: '生成报表', description: '每周一上午9点生成业务报表', schedule: '0 9 * * 1', command: '/scripts/generate-report.sh --type=weekly', status: 'enabled', lastRun: '2025-04-07 09:00:00', lastStatus: 'success', nextRun: '2025-04-21 09:00:00', targetServers: ['report-server'], createdAt: '2025-03-01', createdBy: 'admin', }, ]; const executionLogs = [ { id: 1, jobName: '数据库备份', startTime: '2025-04-14 02:00:00', endTime: '2025-04-14 02:15:30', duration: '15m 30s', status: 'success', output: '备份完成: 15.2GB' }, { id: 2, jobName: '健康检查', startTime: '2025-04-14 11:55:00', endTime: '2025-04-14 11:55:05', duration: '5s', status: 'success', output: '所有服务正常' }, { id: 3, jobName: '数据同步', startTime: '2025-04-14 10:00:00', endTime: '2025-04-14 10:05:23', duration: '5m 23s', status: 'failed', output: '连接超时' }, { id: 4, jobName: '日志清理', startTime: '2025-04-13 03:00:00', endTime: '2025-04-13 03:02:15', duration: '2m 15s', status: 'success', output: '清理完成: 2.3GB' }, ]; export function CronJobManager() { const [searchQuery, setSearchQuery] = useState(''); const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false); const [isLogDialogOpen, setIsLogDialogOpen] = useState(false); const [selectedJob, setSelectedJob] = useState(null); const [newJob, setNewJob] = useState({ name: '', description: '', schedule: '', command: '', targetServers: '', }); const filteredJobs = mockCronJobs.filter( (job) => job.name.toLowerCase().includes(searchQuery.toLowerCase()) || job.description.toLowerCase().includes(searchQuery.toLowerCase()) ); const getStatusBadge = (status: CronJob['lastStatus']) => { switch (status) { case 'success': return ( 成功 ); case 'failed': return ( 失败 ); case 'running': return ( 执行中 ); default: return ( 从未执行 ); } }; const parseCron = (schedule: string) => { const patterns: Record = { '0 2 * * *': '每天 02:00', '0 3 * * 0': '每周日 03:00', '*/5 * * * *': '每 5 分钟', '0 * * * *': '每小时', '0 9 * * 1': '每周一 09:00', }; return patterns[schedule] || schedule; }; const handleCreateJob = () => { setIsCreateDialogOpen(false); setNewJob({ name: '', description: '', schedule: '', command: '', targetServers: '' }); }; return (
{/* Header */}

定时任务

Cron 任务管理与执行

{/* Stats */}

任务总数

{mockCronJobs.length}

已启用

{mockCronJobs.filter((j) => j.status === 'enabled').length}

执行中

{mockCronJobs.filter((j) => j.lastStatus === 'running').length}

今日失败

{mockCronJobs.filter((j) => j.lastStatus === 'failed').length}

{/* Filters */}
setSearchQuery(e.target.value)} className="pl-10 bg-slate-800 border-slate-700 text-slate-100" />
{/* Job List */}
{filteredJobs.map((job) => (

{job.name}

{job.status === 'enabled' ? '已启用' : '已禁用'} {getStatusBadge(job.lastStatus)}

{job.description}

{parseCron(job.schedule)} {job.command}
上次执行: {job.lastRun} 下次执行: {job.nextRun} 目标: {job.targetServers.join(', ')}
))}
{/* Create Job Dialog */} 新建定时任务 配置 Cron 定时任务
setNewJob({ ...newJob, name: e.target.value })} placeholder="例如: 数据库备份" className="bg-slate-800 border-slate-700 text-slate-100 mt-1" />