pms-front-react/src/pages/monitor/ServerMonitorPage.tsx

186 lines
7.3 KiB
TypeScript

import { useEffect, useState } from 'react';
import { Card, Col, Row, message, Typography, Descriptions, Progress, Table, Space } from 'antd';
import type { TableColumnsType } from 'antd';
import {
SettingOutlined,
FileTextOutlined,
DesktopOutlined,
CoffeeOutlined,
HddOutlined,
} from '@ant-design/icons';
import dayjs from 'dayjs';
import { getServerInfo } from '../../api/monitor/server';
import type { ServerDiskInfo, ServerInfoResponse } from '@/types/api';
import './server-monitor.css';
const { Text } = Typography;
const defaultServerInfo: ServerInfoResponse = {
cpu: {},
mem: {},
jvm: {},
sys: {},
sysFiles: [],
};
const parseTime = (time?: string | number | Date, pattern = 'YYYY-MM-DD HH:mm:ss'): string => {
return time ? dayjs(time).format(pattern) : '';
};
const toNumber = (value: unknown): number => {
if (typeof value === 'number') {
return Number.isFinite(value) ? value : 0;
}
if (typeof value === 'string') {
const parsed = Number.parseFloat(value);
return Number.isFinite(parsed) ? parsed : 0;
}
return 0;
};
const renderUsageProgress = (usage: unknown) => {
const percent = Math.floor(toNumber(usage));
let status: 'normal' | 'exception' | 'active' | 'success' = 'normal';
if (percent > 80) {
status = 'exception';
} else if (percent > 60) {
status = 'active';
}
return <Progress percent={percent} status={status} />;
};
const ServerMonitorPage = () => {
const [serverInfo, setServerInfo] = useState<ServerInfoResponse>(defaultServerInfo);
const [loading, setLoading] = useState(true);
useEffect(() => {
const getList = async () => {
setLoading(true);
const hide = message.loading('正在加载服务监控数据,请稍候!', 0);
try {
const response = await getServerInfo();
setServerInfo(response);
} catch (error: unknown) {
console.error('Failed to fetch server info:', error);
message.error('获取服务监控数据失败');
} finally {
setLoading(false);
hide();
}
};
void getList();
}, []);
const diskColumns: TableColumnsType<ServerDiskInfo> = [
{ title: '盘符路径', dataIndex: 'dirName', align: 'center' },
{ title: '文件系统', dataIndex: 'sysTypeName', align: 'center' },
{ title: '盘符类型', dataIndex: 'typeName', align: 'center' },
{ title: '总大小', dataIndex: 'total', align: 'center' },
{ title: '可用大小', dataIndex: 'free', align: 'center' },
{ title: '已用大小', dataIndex: 'used', align: 'center' },
{
title: '已用百分比',
dataIndex: 'usage',
align: 'center',
render: (usage) => (
<Text type={toNumber(usage) > 80 ? 'danger' : 'secondary'}>
{toNumber(usage)}% {renderUsageProgress(usage)}
</Text>
),
},
];
return (
<div className="app-container server-monitor-container">
<Row gutter={[16, 16]}>
<Col span={12} className="card-box">
<Card title={<Space><SettingOutlined /> CPU</Space>} loading={loading}>
<Descriptions column={1} bordered size="small">
<Descriptions.Item label="核心数">{serverInfo.cpu?.cpuNum}</Descriptions.Item>
<Descriptions.Item label="用户使用率">
{serverInfo.cpu?.used}% {renderUsageProgress(serverInfo.cpu?.used)}
</Descriptions.Item>
<Descriptions.Item label="系统使用率">
{serverInfo.cpu?.sys}% {renderUsageProgress(serverInfo.cpu?.sys)}
</Descriptions.Item>
<Descriptions.Item label="当前空闲率">
{serverInfo.cpu?.free}% {renderUsageProgress(serverInfo.cpu?.free)}
</Descriptions.Item>
</Descriptions>
</Card>
</Col>
<Col span={12} className="card-box">
<Card title={<Space><FileTextOutlined /> </Space>} loading={loading}>
<Descriptions column={2} bordered size="small">
<Descriptions.Item label="属性"></Descriptions.Item>
<Descriptions.Item label="内存">{serverInfo.mem?.total}G</Descriptions.Item>
<Descriptions.Item label="JVM">{serverInfo.jvm?.total}M</Descriptions.Item>
<Descriptions.Item label="已用内存">
<Text type={toNumber(serverInfo.mem?.usage) > 80 ? 'danger' : 'secondary'}>
{serverInfo.mem?.used}G
</Text>
</Descriptions.Item>
<Descriptions.Item label="已用内存">
<Text type={toNumber(serverInfo.jvm?.usage) > 80 ? 'danger' : 'secondary'}>
{serverInfo.jvm?.used}M
</Text>
</Descriptions.Item>
<Descriptions.Item label="剩余内存">{serverInfo.mem?.free}G</Descriptions.Item>
<Descriptions.Item label="剩余内存">{serverInfo.jvm?.free}M</Descriptions.Item>
<Descriptions.Item label="使用率">{renderUsageProgress(serverInfo.mem?.usage)}</Descriptions.Item>
<Descriptions.Item label="使用率">{renderUsageProgress(serverInfo.jvm?.usage)}</Descriptions.Item>
</Descriptions>
</Card>
</Col>
<Col span={24} className="card-box">
<Card title={<Space><DesktopOutlined /> </Space>} loading={loading}>
<Descriptions column={2} bordered size="small">
<Descriptions.Item label="服务器名称">{serverInfo.sys?.computerName}</Descriptions.Item>
<Descriptions.Item label="操作系统">{serverInfo.sys?.osName}</Descriptions.Item>
<Descriptions.Item label="服务器IP">{serverInfo.sys?.computerIp}</Descriptions.Item>
<Descriptions.Item label="系统架构">{serverInfo.sys?.osArch}</Descriptions.Item>
</Descriptions>
</Card>
</Col>
<Col span={24} className="card-box">
<Card title={<Space><CoffeeOutlined /> Java</Space>} loading={loading}>
<Descriptions column={2} bordered size="small">
<Descriptions.Item label="Java名称">{serverInfo.jvm?.name}</Descriptions.Item>
<Descriptions.Item label="Java版本">{serverInfo.jvm?.version}</Descriptions.Item>
<Descriptions.Item label="启动时间">{parseTime(serverInfo.jvm?.startTime)}</Descriptions.Item>
<Descriptions.Item label="运行时长">{serverInfo.jvm?.runTime}</Descriptions.Item>
<Descriptions.Item label="安装路径" span={2}>{serverInfo.jvm?.home}</Descriptions.Item>
<Descriptions.Item label="项目路径" span={2}>{serverInfo.sys?.userDir}</Descriptions.Item>
<Descriptions.Item label="运行参数" span={2}>{serverInfo.jvm?.inputArgs}</Descriptions.Item>
</Descriptions>
</Card>
</Col>
<Col span={24} className="card-box">
<Card title={<Space><HddOutlined /> </Space>} loading={loading}>
<Table
dataSource={serverInfo.sysFiles ?? []}
rowKey={(record) =>
`${record.dirName ?? 'disk'}-${record.sysTypeName ?? ''}-${record.typeName ?? ''}`
}
pagination={false}
size="small"
bordered
columns={diskColumns}
/>
</Card>
</Col>
</Row>
</div>
);
};
export default ServerMonitorPage;