Files
ai-showcase-platform/app/admin/ultimate-kill/page.tsx

315 lines
10 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, AlertTriangle, Trash2, Eye, Zap, Skull } from 'lucide-react';
interface ConnectionStatus {
currentConnections: number;
maxConnections: number;
usagePercentage: number;
connectionDetails: Array<{
ID: number;
USER: string;
HOST: string;
DB: string;
COMMAND: string;
TIME: number;
STATE: string;
INFO?: string;
}>;
connectionCount: number;
}
export default function UltimateKillPage() {
const [status, setStatus] = useState<ConnectionStatus | null>(null);
const [loading, setLoading] = useState(false);
const [message, setMessage] = useState<string>('');
const [error, setError] = useState<string>('');
// 獲取連線狀態
const fetchStatus = async () => {
try {
setLoading(true);
const response = await fetch('/api/ultimate-kill?action=status');
const data = await response.json();
if (data.success) {
setStatus(data.data);
setMessage('狀態更新成功');
setError('');
} else {
setError(data.error || '獲取狀態失敗');
}
} catch (err) {
setError('網路錯誤: ' + (err instanceof Error ? err.message : '未知錯誤'));
} finally {
setLoading(false);
}
};
// 終極清理 - 殺死所有連線
const ultimateKill = async () => {
if (!confirm('確定要執行終極清理嗎?這會強制殺死所有資料庫連線!')) {
return;
}
try {
setLoading(true);
const response = await fetch('/api/ultimate-kill', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ action: 'kill-all' }),
});
const data = await response.json();
if (data.success) {
setMessage(data.message || '終極清理完成');
setError('');
await fetchStatus(); // 重新獲取狀態
} else {
setError(data.error || '終極清理失敗');
}
} catch (err) {
setError('終極清理錯誤: ' + (err instanceof Error ? err.message : '未知錯誤'));
} finally {
setLoading(false);
}
};
// 強制重啟資料庫連線
const forceRestart = async () => {
if (!confirm('確定要強制重啟資料庫連線嗎?這會先殺死所有連線然後重新建立!')) {
return;
}
try {
setLoading(true);
const response = await fetch('/api/ultimate-kill', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ action: 'restart' }),
});
const data = await response.json();
if (data.success) {
setMessage(data.message || '強制重啟完成');
setError('');
await fetchStatus(); // 重新獲取狀態
} else {
setError(data.error || '強制重啟失敗');
}
} catch (err) {
setError('強制重啟錯誤: ' + (err instanceof Error ? err.message : '未知錯誤'));
} finally {
setLoading(false);
}
};
// 組件載入時獲取狀態
useEffect(() => {
fetchStatus();
// 每10秒自動更新狀態
const interval = setInterval(fetchStatus, 10000);
return () => clearInterval(interval);
}, []);
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 text-red-600"></h1>
<p className="text-muted-foreground">
-
</p>
</div>
<Button
onClick={fetchStatus}
disabled={loading}
variant="outline"
>
{loading ? <Loader2 className="h-4 w-4 animate-spin" /> : <Eye className="h-4 w-4" />}
</Button>
</div>
{/* 嚴重警告 */}
<Alert variant="destructive">
<Skull className="h-4 w-4" />
<AlertDescription>
<strong></strong>
</AlertDescription>
</Alert>
{/* 連線狀態概覽 */}
{status && (
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
<Card>
<CardContent className="p-6">
<div className="flex items-center gap-2">
<Database className="h-5 w-5 text-blue-500" />
<div>
<p className="text-sm font-medium text-muted-foreground"></p>
<p className="text-2xl font-bold">{status.currentConnections}</p>
</div>
</div>
</CardContent>
</Card>
<Card>
<CardContent className="p-6">
<div className="flex items-center gap-2">
<AlertTriangle className="h-5 w-5 text-yellow-500" />
<div>
<p className="text-sm font-medium text-muted-foreground"></p>
<p className="text-2xl font-bold">{status.maxConnections}</p>
</div>
</div>
</CardContent>
</Card>
<Card>
<CardContent className="p-6">
<div className="flex items-center gap-2">
<Zap className="h-5 w-5 text-red-500" />
<div>
<p className="text-sm font-medium text-muted-foreground">使</p>
<p className="text-2xl font-bold">{status.usagePercentage.toFixed(1)}%</p>
</div>
</div>
</CardContent>
</Card>
<Card>
<CardContent className="p-6">
<div className="flex items-center gap-2">
<Trash2 className="h-5 w-5 text-green-500" />
<div>
<p className="text-sm font-medium text-muted-foreground"></p>
<p className="text-2xl font-bold">
{status.connectionCount <= 1 ? '正常' : '異常'}
</p>
</div>
</div>
</CardContent>
</Card>
</div>
)}
{/* 終極操作 */}
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2 text-red-600">
<Skull className="h-5 w-5" />
</CardTitle>
<CardDescription>
-
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<Button
onClick={ultimateKill}
disabled={loading}
variant="destructive"
className="w-full"
>
{loading ? <Loader2 className="h-4 w-4 animate-spin" /> : <Skull className="h-4 w-4" />}
-
</Button>
<Button
onClick={forceRestart}
disabled={loading}
variant="destructive"
className="w-full"
>
{loading ? <Loader2 className="h-4 w-4 animate-spin" /> : <Zap className="h-4 w-4" />}
</Button>
</div>
</CardContent>
</Card>
{/* 連線詳情列表 */}
{status && status.connectionDetails.length > 0 && (
<Card>
<CardHeader>
<CardTitle></CardTitle>
<CardDescription>
</CardDescription>
</CardHeader>
<CardContent>
<div className="space-y-2 max-h-96 overflow-y-auto">
{status.connectionDetails.map((conn, index) => (
<div key={conn.ID} className="flex items-center justify-between p-3 border rounded-lg">
<div className="flex items-center gap-4">
<Badge variant="outline">#{conn.ID}</Badge>
<div>
<p className="text-sm font-medium">
: {conn.USER} | : {conn.HOST}
</p>
<p className="text-sm text-muted-foreground">
: {conn.DB} | : {conn.COMMAND}
</p>
<p className="text-sm text-muted-foreground">
: {conn.TIME}s | : {conn.STATE}
</p>
{conn.INFO && (
<p className="text-xs text-muted-foreground mt-1">
: {conn.INFO.length > 100 ? conn.INFO.substring(0, 100) + '...' : conn.INFO}
</p>
)}
</div>
</div>
</div>
))}
</div>
</CardContent>
</Card>
)}
{/* 訊息顯示 */}
{message && (
<Alert>
<Database className="h-4 w-4" />
<AlertDescription>{message}</AlertDescription>
</Alert>
)}
{error && (
<Alert variant="destructive">
<AlertTriangle className="h-4 w-4" />
<AlertDescription>{error}</AlertDescription>
</Alert>
)}
{/* 使用說明 */}
<Card>
<CardHeader>
<CardTitle></CardTitle>
</CardHeader>
<CardContent className="space-y-2 text-sm text-muted-foreground">
<p> <strong>:</strong> </p>
<p> <strong>:</strong> </p>
<p> <strong>:</strong> 10</p>
<p> <strong>:</strong> </p>
<p> 使</p>
</CardContent>
</Card>
</div>
);
}