服务器拆分接口
This commit is contained in:
parent
44de0ca028
commit
81a11c4594
@ -15,6 +15,7 @@ import {
|
|||||||
Tags,
|
Tags,
|
||||||
Tag,
|
Tag,
|
||||||
FileText,
|
FileText,
|
||||||
|
RefreshCw,
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import { Card, CardContent } from '@/components/ui/card';
|
import { Card, CardContent } from '@/components/ui/card';
|
||||||
import { Badge } from '@/components/ui/badge';
|
import { Badge } from '@/components/ui/badge';
|
||||||
@ -36,11 +37,13 @@ interface ServerCardProps {
|
|||||||
onEdit: (server: ServerResponse) => void;
|
onEdit: (server: ServerResponse) => void;
|
||||||
onDelete: (server: ServerResponse) => void;
|
onDelete: (server: ServerResponse) => void;
|
||||||
onSSHConnect: (server: ServerResponse) => void;
|
onSSHConnect: (server: ServerResponse) => void;
|
||||||
|
onCollectHardware: (server: ServerResponse) => void;
|
||||||
isTesting?: boolean;
|
isTesting?: boolean;
|
||||||
|
isCollecting?: boolean;
|
||||||
getOsIcon: (osType?: string) => React.ReactNode;
|
getOsIcon: (osType?: string) => React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ServerCard: React.FC<ServerCardProps> = ({ server, onTest, onEdit, onDelete, onSSHConnect, isTesting, getOsIcon }) => {
|
export const ServerCard: React.FC<ServerCardProps> = ({ server, onTest, onEdit, onDelete, onSSHConnect, onCollectHardware, isTesting, isCollecting, getOsIcon }) => {
|
||||||
const [expanded, setExpanded] = React.useState(false);
|
const [expanded, setExpanded] = React.useState(false);
|
||||||
|
|
||||||
const formatTime = (time?: string) => {
|
const formatTime = (time?: string) => {
|
||||||
@ -252,7 +255,7 @@ export const ServerCard: React.FC<ServerCardProps> = ({ server, onTest, onEdit,
|
|||||||
size="icon"
|
size="icon"
|
||||||
className="h-7 w-7"
|
className="h-7 w-7"
|
||||||
onClick={() => onTest(server)}
|
onClick={() => onTest(server)}
|
||||||
disabled={isTesting}
|
disabled={isTesting || isCollecting}
|
||||||
>
|
>
|
||||||
{isTesting ? (
|
{isTesting ? (
|
||||||
<Loader2 className="h-3.5 w-3.5 animate-spin" />
|
<Loader2 className="h-3.5 w-3.5 animate-spin" />
|
||||||
@ -263,6 +266,25 @@ export const ServerCard: React.FC<ServerCardProps> = ({ server, onTest, onEdit,
|
|||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent>测试连接</TooltipContent>
|
<TooltipContent>测试连接</TooltipContent>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="ghost"
|
||||||
|
size="icon"
|
||||||
|
className="h-7 w-7"
|
||||||
|
onClick={() => onCollectHardware(server)}
|
||||||
|
disabled={isTesting || isCollecting}
|
||||||
|
>
|
||||||
|
{isCollecting ? (
|
||||||
|
<Loader2 className="h-3.5 w-3.5 animate-spin" />
|
||||||
|
) : (
|
||||||
|
<RefreshCw className="h-3.5 w-3.5" />
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent>刷新硬件信息</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger asChild>
|
<TooltipTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@ -37,9 +37,9 @@ import {
|
|||||||
} from '@/components/ui/collapsible';
|
} from '@/components/ui/collapsible';
|
||||||
import type { ServerResponse, ServerCategoryResponse } from '../types';
|
import type { ServerResponse, ServerCategoryResponse } from '../types';
|
||||||
import { OsType, OsTypeLabels, AuthType, AuthTypeLabels, ServerStatus } from '../types';
|
import { OsType, OsTypeLabels, AuthType, AuthTypeLabels, ServerStatus } from '../types';
|
||||||
import { createServer, updateServer, getServerCategories } from '../service';
|
import { createServer, updateServer, getServerCategories, testServerConnection, collectServerHardware } from '../service';
|
||||||
import { serverFormSchema, type ServerFormValues } from '../schema';
|
import { serverFormSchema, type ServerFormValues } from '../schema';
|
||||||
import { Eye, EyeOff, X, Plus, ChevronDown } from 'lucide-react';
|
import { Eye, EyeOff, X, Plus, ChevronDown, Loader2, CheckCircle } from 'lucide-react';
|
||||||
|
|
||||||
interface ServerEditDialogProps {
|
interface ServerEditDialogProps {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
@ -61,6 +61,9 @@ export const ServerEditDialog: React.FC<ServerEditDialogProps> = ({
|
|||||||
const [showPassphrase, setShowPassphrase] = useState(false);
|
const [showPassphrase, setShowPassphrase] = useState(false);
|
||||||
const [tagInput, setTagInput] = useState('');
|
const [tagInput, setTagInput] = useState('');
|
||||||
const [systemInfoOpen, setSystemInfoOpen] = useState(true);
|
const [systemInfoOpen, setSystemInfoOpen] = useState(true);
|
||||||
|
const [testing, setTesting] = useState(false);
|
||||||
|
const [collecting, setCollecting] = useState(false);
|
||||||
|
const [testSuccess, setTestSuccess] = useState(false);
|
||||||
const isEdit = !!server?.id;
|
const isEdit = !!server?.id;
|
||||||
|
|
||||||
const form = useForm<ServerFormValues>({
|
const form = useForm<ServerFormValues>({
|
||||||
@ -150,6 +153,129 @@ export const ServerEditDialog: React.FC<ServerEditDialogProps> = ({
|
|||||||
}
|
}
|
||||||
}, [server, open, form]);
|
}, [server, open, form]);
|
||||||
|
|
||||||
|
// 测试连接并采集硬件信息
|
||||||
|
const handleTestAndCollect = async () => {
|
||||||
|
// 验证必填的连接信息
|
||||||
|
const hostIp = form.getValues('hostIp');
|
||||||
|
const sshPort = form.getValues('sshPort');
|
||||||
|
const sshUser = form.getValues('sshUser');
|
||||||
|
const authType = form.getValues('authType');
|
||||||
|
const sshPassword = form.getValues('sshPassword');
|
||||||
|
const sshPrivateKey = form.getValues('sshPrivateKey');
|
||||||
|
|
||||||
|
if (!hostIp || !sshPort || !sshUser) {
|
||||||
|
toast({
|
||||||
|
variant: 'destructive',
|
||||||
|
title: '缺少必填信息',
|
||||||
|
description: '请先填写IP地址、SSH端口和用户名',
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (authType === AuthType.PASSWORD && !sshPassword) {
|
||||||
|
toast({
|
||||||
|
variant: 'destructive',
|
||||||
|
title: '缺少密码',
|
||||||
|
description: '请填写SSH密码',
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (authType === AuthType.KEY && !sshPrivateKey) {
|
||||||
|
toast({
|
||||||
|
variant: 'destructive',
|
||||||
|
title: '缺少私钥',
|
||||||
|
description: '请填写SSH私钥',
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果是新增服务器,需要先创建临时服务器记录
|
||||||
|
let serverId = server?.id;
|
||||||
|
|
||||||
|
if (!serverId) {
|
||||||
|
// 新增服务器:先保存基础信息
|
||||||
|
try {
|
||||||
|
setLoading(true);
|
||||||
|
const tempServer = await createServer({
|
||||||
|
serverName: form.getValues('serverName') || '临时服务器',
|
||||||
|
hostIp,
|
||||||
|
sshPort,
|
||||||
|
sshUser,
|
||||||
|
authType,
|
||||||
|
sshPassword,
|
||||||
|
sshPrivateKey,
|
||||||
|
sshPassphrase: form.getValues('sshPassphrase'),
|
||||||
|
categoryId: form.getValues('categoryId'),
|
||||||
|
osType: form.getValues('osType'),
|
||||||
|
description: form.getValues('description'),
|
||||||
|
});
|
||||||
|
serverId = tempServer.id;
|
||||||
|
toast({
|
||||||
|
title: '服务器已保存',
|
||||||
|
description: '正在测试连接...',
|
||||||
|
});
|
||||||
|
} catch (error: any) {
|
||||||
|
return;
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 步骤1:测试连接
|
||||||
|
setTesting(true);
|
||||||
|
setTestSuccess(false);
|
||||||
|
try {
|
||||||
|
const testResult = await testServerConnection(serverId);
|
||||||
|
if (!testResult.connected) {
|
||||||
|
toast({
|
||||||
|
variant: 'destructive',
|
||||||
|
title: '连接失败',
|
||||||
|
description: testResult.errorMessage || '无法连接到服务器',
|
||||||
|
});
|
||||||
|
setTesting(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
toast({
|
||||||
|
title: '连接成功',
|
||||||
|
description: `响应时间: ${testResult.responseTime}ms`,
|
||||||
|
});
|
||||||
|
setTestSuccess(true);
|
||||||
|
|
||||||
|
// 步骤2:自动采集硬件信息
|
||||||
|
setTesting(false);
|
||||||
|
setCollecting(true);
|
||||||
|
|
||||||
|
const hardwareResult = await collectServerHardware(serverId);
|
||||||
|
|
||||||
|
// 自动填充表单
|
||||||
|
form.setValue('hostname', hardwareResult.hostname);
|
||||||
|
form.setValue('osVersion', hardwareResult.osVersion);
|
||||||
|
form.setValue('cpuCores', hardwareResult.cpuCores);
|
||||||
|
form.setValue('memorySize', hardwareResult.memorySize);
|
||||||
|
form.setValue('diskSize', hardwareResult.diskSize);
|
||||||
|
|
||||||
|
toast({
|
||||||
|
title: '硬件信息采集成功',
|
||||||
|
description: `${hardwareResult.hostname} - CPU: ${hardwareResult.cpuCores}核 内存: ${hardwareResult.memorySize}GB`,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 展开系统信息区域
|
||||||
|
setSystemInfoOpen(true);
|
||||||
|
|
||||||
|
} catch (error: any) {
|
||||||
|
toast({
|
||||||
|
variant: 'destructive',
|
||||||
|
title: '操作失败',
|
||||||
|
description: error.response?.data?.message || '无法完成操作',
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
setTesting(false);
|
||||||
|
setCollecting(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const onSubmit = async (values: ServerFormValues) => {
|
const onSubmit = async (values: ServerFormValues) => {
|
||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
@ -558,6 +684,41 @@ export const ServerEditDialog: React.FC<ServerEditDialogProps> = ({
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* 测试连接按钮 */}
|
||||||
|
<div className="mt-4 flex items-center gap-3">
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="outline"
|
||||||
|
onClick={handleTestAndCollect}
|
||||||
|
disabled={testing || collecting || loading}
|
||||||
|
className="flex-1"
|
||||||
|
>
|
||||||
|
{testing ? (
|
||||||
|
<>
|
||||||
|
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||||
|
测试连接中...
|
||||||
|
</>
|
||||||
|
) : collecting ? (
|
||||||
|
<>
|
||||||
|
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||||
|
采集硬件信息中...
|
||||||
|
</>
|
||||||
|
) : testSuccess ? (
|
||||||
|
<>
|
||||||
|
<CheckCircle className="mr-2 h-4 w-4 text-green-500" />
|
||||||
|
测试连接并采集信息
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
'测试连接并采集信息'
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
{testSuccess && !isEdit && (
|
||||||
|
<span className="text-xs text-green-600 dark:text-green-400">
|
||||||
|
✓ 连接成功,硬件信息已采集
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Separator />
|
<Separator />
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import {
|
|||||||
AlertCircle,
|
AlertCircle,
|
||||||
HelpCircle,
|
HelpCircle,
|
||||||
Terminal,
|
Terminal,
|
||||||
|
RefreshCw,
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import {
|
import {
|
||||||
Table,
|
Table,
|
||||||
@ -36,7 +37,9 @@ interface ServerTableProps {
|
|||||||
onEdit: (server: ServerResponse) => void;
|
onEdit: (server: ServerResponse) => void;
|
||||||
onDelete: (server: ServerResponse) => void;
|
onDelete: (server: ServerResponse) => void;
|
||||||
onSSHConnect: (server: ServerResponse) => void;
|
onSSHConnect: (server: ServerResponse) => void;
|
||||||
|
onCollectHardware: (server: ServerResponse) => void;
|
||||||
isTesting?: (serverId: number) => boolean;
|
isTesting?: (serverId: number) => boolean;
|
||||||
|
isCollecting?: (serverId: number) => boolean;
|
||||||
getOsIcon: (osType?: string) => React.ReactNode;
|
getOsIcon: (osType?: string) => React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,7 +49,9 @@ export const ServerTable: React.FC<ServerTableProps> = ({
|
|||||||
onEdit,
|
onEdit,
|
||||||
onDelete,
|
onDelete,
|
||||||
onSSHConnect,
|
onSSHConnect,
|
||||||
|
onCollectHardware,
|
||||||
isTesting,
|
isTesting,
|
||||||
|
isCollecting,
|
||||||
getOsIcon,
|
getOsIcon,
|
||||||
}) => {
|
}) => {
|
||||||
const formatTime = (time?: string) => {
|
const formatTime = (time?: string) => {
|
||||||
@ -155,7 +160,7 @@ export const ServerTable: React.FC<ServerTableProps> = ({
|
|||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="sm"
|
size="sm"
|
||||||
onClick={() => onTest(server)}
|
onClick={() => onTest(server)}
|
||||||
disabled={isTesting?.(server.id)}
|
disabled={isTesting?.(server.id) || isCollecting?.(server.id)}
|
||||||
className="h-8 w-8 p-0"
|
className="h-8 w-8 p-0"
|
||||||
>
|
>
|
||||||
{isTesting?.(server.id) ? (
|
{isTesting?.(server.id) ? (
|
||||||
@ -167,6 +172,24 @@ export const ServerTable: React.FC<ServerTableProps> = ({
|
|||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent>测试连接</TooltipContent>
|
<TooltipContent>测试连接</TooltipContent>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
onClick={() => onCollectHardware(server)}
|
||||||
|
disabled={isTesting?.(server.id) || isCollecting?.(server.id)}
|
||||||
|
className="h-8 w-8 p-0"
|
||||||
|
>
|
||||||
|
{isCollecting?.(server.id) ? (
|
||||||
|
<Loader2 className="h-4 w-4 animate-spin" />
|
||||||
|
) : (
|
||||||
|
<RefreshCw className="h-4 w-4" />
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent>刷新硬件信息</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger asChild>
|
<TooltipTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@ -36,7 +36,7 @@ import { DataTablePagination } from '@/components/ui/pagination';
|
|||||||
import { Input } from '@/components/ui/input';
|
import { Input } from '@/components/ui/input';
|
||||||
import type { ServerResponse, ServerCategoryResponse, ServerStatus, OsType } from './types';
|
import type { ServerResponse, ServerCategoryResponse, ServerStatus, OsType } from './types';
|
||||||
import { ServerStatusLabels, OsTypeLabels } from './types';
|
import { ServerStatusLabels, OsTypeLabels } from './types';
|
||||||
import { getServers, getServerCategories, deleteServer, testServerConnection } from './service';
|
import { getServers, getServerCategories, deleteServer, testServerConnection, collectServerHardware } from './service';
|
||||||
import { CategoryManageDialog } from './components/CategoryManageDialog';
|
import { CategoryManageDialog } from './components/CategoryManageDialog';
|
||||||
import { AlertRuleManageDialog } from './components/AlertRuleManageDialog';
|
import { AlertRuleManageDialog } from './components/AlertRuleManageDialog';
|
||||||
import { ServerEditDialog } from './components/ServerEditDialog';
|
import { ServerEditDialog } from './components/ServerEditDialog';
|
||||||
@ -79,6 +79,7 @@ const ServerList: React.FC = () => {
|
|||||||
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
||||||
const [serverToDelete, setServerToDelete] = useState<ServerResponse | null>(null);
|
const [serverToDelete, setServerToDelete] = useState<ServerResponse | null>(null);
|
||||||
const [testingServerId, setTestingServerId] = useState<number | null>(null);
|
const [testingServerId, setTestingServerId] = useState<number | null>(null);
|
||||||
|
const [collectingServerId, setCollectingServerId] = useState<number | null>(null);
|
||||||
const [statsData, setStatsData] = useState<{
|
const [statsData, setStatsData] = useState<{
|
||||||
total: number;
|
total: number;
|
||||||
online: number;
|
online: number;
|
||||||
@ -167,7 +168,7 @@ const ServerList: React.FC = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 测试连接
|
// 测试连接(轻量级)
|
||||||
const handleTestConnection = async (server: ServerResponse) => {
|
const handleTestConnection = async (server: ServerResponse) => {
|
||||||
setTestingServerId(server.id);
|
setTestingServerId(server.id);
|
||||||
try {
|
try {
|
||||||
@ -175,10 +176,8 @@ const ServerList: React.FC = () => {
|
|||||||
if (result.connected) {
|
if (result.connected) {
|
||||||
toast({
|
toast({
|
||||||
title: '连接成功',
|
title: '连接成功',
|
||||||
description: `${result.hostname} - ${result.osVersion} (响应时间: ${result.responseTime}ms)`,
|
description: `响应时间: ${result.responseTime}ms`,
|
||||||
});
|
});
|
||||||
// 测试连接成功后刷新数据
|
|
||||||
await loadServers();
|
|
||||||
} else {
|
} else {
|
||||||
toast({
|
toast({
|
||||||
variant: 'destructive',
|
variant: 'destructive',
|
||||||
@ -197,6 +196,29 @@ const ServerList: React.FC = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 刷新硬件信息
|
||||||
|
const handleCollectHardware = async (server: ServerResponse) => {
|
||||||
|
setCollectingServerId(server.id);
|
||||||
|
try {
|
||||||
|
const result = await collectServerHardware(server.id);
|
||||||
|
toast({
|
||||||
|
title: '硬件信息已更新',
|
||||||
|
description: `${result.hostname} - CPU: ${result.cpuCores}核 内存: ${result.memorySize}GB`,
|
||||||
|
});
|
||||||
|
// 刷新服务器列表
|
||||||
|
await loadServers();
|
||||||
|
await loadStats();
|
||||||
|
} catch (error: any) {
|
||||||
|
toast({
|
||||||
|
variant: 'destructive',
|
||||||
|
title: '采集失败',
|
||||||
|
description: error.response?.data?.message || '无法采集硬件信息',
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
setCollectingServerId(null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 编辑服务器
|
// 编辑服务器
|
||||||
const handleEdit = (server: ServerResponse) => {
|
const handleEdit = (server: ServerResponse) => {
|
||||||
setEditingServer(server);
|
setEditingServer(server);
|
||||||
@ -532,7 +554,9 @@ const ServerList: React.FC = () => {
|
|||||||
onEdit={handleEdit}
|
onEdit={handleEdit}
|
||||||
onDelete={handleDelete}
|
onDelete={handleDelete}
|
||||||
onSSHConnect={handleSSHConnect}
|
onSSHConnect={handleSSHConnect}
|
||||||
|
onCollectHardware={handleCollectHardware}
|
||||||
isTesting={testingServerId === server.id}
|
isTesting={testingServerId === server.id}
|
||||||
|
isCollecting={collectingServerId === server.id}
|
||||||
getOsIcon={getOsIcon}
|
getOsIcon={getOsIcon}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
@ -548,7 +572,9 @@ const ServerList: React.FC = () => {
|
|||||||
onEdit={handleEdit}
|
onEdit={handleEdit}
|
||||||
onDelete={handleDelete}
|
onDelete={handleDelete}
|
||||||
onSSHConnect={handleSSHConnect}
|
onSSHConnect={handleSSHConnect}
|
||||||
|
onCollectHardware={handleCollectHardware}
|
||||||
isTesting={(serverId) => testingServerId === serverId}
|
isTesting={(serverId) => testingServerId === serverId}
|
||||||
|
isCollecting={(serverId) => collectingServerId === serverId}
|
||||||
getOsIcon={getOsIcon}
|
getOsIcon={getOsIcon}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import type {
|
|||||||
ServerResponse,
|
ServerResponse,
|
||||||
ServerRequest,
|
ServerRequest,
|
||||||
ServerConnectionTestResult,
|
ServerConnectionTestResult,
|
||||||
|
ServerHardwareCollectionResult,
|
||||||
AlertRuleResponse,
|
AlertRuleResponse,
|
||||||
AlertRuleQuery,
|
AlertRuleQuery,
|
||||||
AlertRuleRequest,
|
AlertRuleRequest,
|
||||||
@ -115,12 +116,19 @@ export const batchDeleteServers = (ids: number[]) =>
|
|||||||
request.post<void>(`${SERVER_URL}/batch-delete`, { ids });
|
request.post<void>(`${SERVER_URL}/batch-delete`, { ids });
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 测试服务器连接
|
* 测试服务器连接(轻量级)
|
||||||
* 返回连接测试结果,包含连接状态和服务器信息
|
* 仅验证连接是否成功,不采集硬件信息
|
||||||
*/
|
*/
|
||||||
export const testServerConnection = (id: number) =>
|
export const testServerConnection = (id: number) =>
|
||||||
request.post<ServerConnectionTestResult>(`${SERVER_URL}/${id}/test-connection`);
|
request.post<ServerConnectionTestResult>(`${SERVER_URL}/${id}/test-connection`);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 采集服务器硬件信息
|
||||||
|
* 采集并更新服务器硬件信息(hostname、CPU、内存、磁盘等)
|
||||||
|
*/
|
||||||
|
export const collectServerHardware = (id: number) =>
|
||||||
|
request.post<ServerHardwareCollectionResult>(`${SERVER_URL}/${id}/collect-hardware`);
|
||||||
|
|
||||||
// ==================== 告警规则 ====================
|
// ==================== 告警规则 ====================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -239,7 +239,7 @@ export const AuthTypeLabels: Record<AuthType, { label: string; description: stri
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 服务器连接测试结果
|
* 服务器连接测试结果(轻量级,仅测试连通性)
|
||||||
*/
|
*/
|
||||||
export interface ServerConnectionTestResult {
|
export interface ServerConnectionTestResult {
|
||||||
/** 是否连接成功 */
|
/** 是否连接成功 */
|
||||||
@ -250,6 +250,20 @@ export interface ServerConnectionTestResult {
|
|||||||
connectTime: string;
|
connectTime: string;
|
||||||
/** 响应时间(ms) */
|
/** 响应时间(ms) */
|
||||||
responseTime: number;
|
responseTime: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 服务器硬件信息采集结果
|
||||||
|
*/
|
||||||
|
export interface ServerHardwareCollectionResult {
|
||||||
|
/** 是否连接成功 */
|
||||||
|
connected: boolean;
|
||||||
|
/** 错误信息(连接失败时返回) */
|
||||||
|
errorMessage: string | null;
|
||||||
|
/** 连接时间 */
|
||||||
|
connectTime: string;
|
||||||
|
/** 响应时间(ms) */
|
||||||
|
responseTime: number;
|
||||||
/** 主机名 */
|
/** 主机名 */
|
||||||
hostname: string;
|
hostname: string;
|
||||||
/** 操作系统版本 */
|
/** 操作系统版本 */
|
||||||
@ -260,6 +274,8 @@ export interface ServerConnectionTestResult {
|
|||||||
memorySize: number;
|
memorySize: number;
|
||||||
/** 磁盘大小(GB) */
|
/** 磁盘大小(GB) */
|
||||||
diskSize: number;
|
diskSize: number;
|
||||||
|
/** 磁盘详细信息 */
|
||||||
|
diskInfo?: DiskInfo[];
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== 告警规则 ====================
|
// ==================== 告警规则 ====================
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user