Files
ai-showcase-platform/app/smart-cleanup-test/page.tsx
2025-09-21 03:08:41 +08:00

281 lines
9.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use client';
import React, { useState, useEffect } from 'react';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { Alert, AlertDescription } from '@/components/ui/alert';
import { Loader2, Database, CheckCircle, AlertTriangle, RefreshCw, Trash2, BarChart3 } from 'lucide-react';
interface ConnectionStats {
total: number;
user: number;
infrastructure: number;
other: number;
details: Array<{
id: number;
host: string;
time: number;
state: string;
type: 'user' | 'infrastructure' | 'other';
}>;
}
interface CleanupResult {
success: boolean;
message: string;
data: {
killedCount: number;
details: {
userRealIP?: string;
infrastructureIPs?: string[];
cleanedConnections: Array<{
id: number;
host: string;
time: number;
state: string;
}>;
};
};
}
export default function SmartCleanupTestPage() {
const [stats, setStats] = useState<ConnectionStats | null>(null);
const [loading, setLoading] = useState(false);
const [message, setMessage] = useState<string>('');
const [error, setError] = useState<string>('');
// 獲取連線統計
const fetchStats = async () => {
try {
setLoading(true);
const response = await fetch('/api/smart-cleanup');
const data = await response.json();
if (data.success) {
setStats(data.data.stats);
setMessage('連線統計更新成功');
setError('');
} else {
setError(data.error || '獲取連線統計失敗');
}
} catch (err) {
setError('網路錯誤: ' + (err instanceof Error ? err.message : '未知錯誤'));
} finally {
setLoading(false);
}
};
// 執行智能清理
const performSmartCleanup = async () => {
try {
setLoading(true);
const response = await fetch('/api/smart-cleanup', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
});
const data: CleanupResult = await response.json();
if (data.success) {
setMessage(`智能清理完成: ${data.message}`);
setError('');
// 重新獲取統計
await fetchStats();
} else {
setError(data.error || '智能清理失敗');
}
} catch (err) {
setError('清理錯誤: ' + (err instanceof Error ? err.message : '未知錯誤'));
} finally {
setLoading(false);
}
};
// 組件載入時獲取統計
useEffect(() => {
fetchStats();
}, []);
// 獲取類型顏色
const getTypeColor = (type: 'user' | 'infrastructure' | 'other') => {
switch (type) {
case 'user': return 'default';
case 'infrastructure': return 'destructive';
case 'other': return 'secondary';
default: return 'outline';
}
};
// 獲取類型標籤
const getTypeLabel = (type: 'user' | 'infrastructure' | 'other') => {
switch (type) {
case 'user': return '用戶連線';
case 'infrastructure': return '基礎設施';
case 'other': return '其他';
default: return '未知';
}
};
return (
<div className="container mx-auto p-6 space-y-6">
<div className="flex items-center justify-between">
<div>
<h1 className="text-3xl font-bold"></h1>
<p className="text-muted-foreground">
IP
</p>
</div>
<div className="flex gap-2">
<Button
onClick={fetchStats}
disabled={loading}
variant="outline"
>
{loading ? <Loader2 className="h-4 w-4 animate-spin" /> : <RefreshCw className="h-4 w-4" />}
</Button>
<Button
onClick={performSmartCleanup}
disabled={loading}
variant="destructive"
>
{loading ? <Loader2 className="h-4 w-4 animate-spin" /> : <Trash2 className="h-4 w-4" />}
</Button>
</div>
</div>
{/* 連線統計概覽 */}
{stats && (
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<BarChart3 className="h-5 w-5" />
</CardTitle>
<CardDescription>
</CardDescription>
</CardHeader>
<CardContent>
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
<div className="text-center">
<div className="text-2xl font-bold">{stats.total}</div>
<div className="text-sm text-muted-foreground"></div>
</div>
<div className="text-center">
<div className="text-2xl font-bold text-blue-600">{stats.user}</div>
<div className="text-sm text-muted-foreground"></div>
</div>
<div className="text-center">
<div className="text-2xl font-bold text-red-600">{stats.infrastructure}</div>
<div className="text-sm text-muted-foreground"></div>
</div>
<div className="text-center">
<div className="text-2xl font-bold text-gray-600">{stats.other}</div>
<div className="text-sm text-muted-foreground"></div>
</div>
</div>
</CardContent>
</Card>
)}
{/* 連線詳情 */}
{stats && stats.details.length > 0 && (
<Card>
<CardHeader>
<CardTitle></CardTitle>
<CardDescription>
</CardDescription>
</CardHeader>
<CardContent>
<div className="space-y-2 max-h-96 overflow-y-auto">
{stats.details.map((conn, index) => (
<div key={index} className="flex items-center justify-between p-3 border rounded">
<div className="flex items-center gap-3">
<Badge variant={getTypeColor(conn.type)}>
{getTypeLabel(conn.type)}
</Badge>
<span className="font-mono text-sm">ID: {conn.id}</span>
<span className="text-sm text-muted-foreground">
{conn.host}
</span>
</div>
<div className="flex items-center gap-3">
<span className="text-sm">: {conn.time}s</span>
<span className="text-sm text-muted-foreground">
: {conn.state}
</span>
</div>
</div>
))}
</div>
</CardContent>
</Card>
)}
{/* 功能說明 */}
<Card>
<CardHeader>
<CardTitle></CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<h4 className="font-semibold text-blue-600 mb-2"></h4>
<ul className="text-sm text-muted-foreground space-y-1">
<li> IP (61-227-253-171)</li>
<li> IP </li>
<li> </li>
<li> </li>
</ul>
</div>
<div>
<h4 className="font-semibold text-red-600 mb-2"></h4>
<ul className="text-sm text-muted-foreground space-y-1">
<li> AWS EC2 </li>
<li> Vercel </li>
<li> </li>
<li> </li>
</ul>
</div>
</div>
</CardContent>
</Card>
{/* 使用說明 */}
<Card>
<CardHeader>
<CardTitle>使</CardTitle>
</CardHeader>
<CardContent className="space-y-2 text-sm text-muted-foreground">
<p> <strong>:</strong> </p>
<p> <strong>:</strong> IP </p>
<p> <strong>:</strong> IP </p>
<p> <strong>:</strong> Vercel/AWS </p>
<p> <strong>:</strong> </p>
</CardContent>
</Card>
{/* 訊息顯示 */}
{message && (
<Alert>
<CheckCircle className="h-4 w-4" />
<AlertDescription>{message}</AlertDescription>
</Alert>
)}
{error && (
<Alert variant="destructive">
<AlertTriangle className="h-4 w-4" />
<AlertDescription>{error}</AlertDescription>
</Alert>
)}
</div>
);
}