232 lines
7.7 KiB
TypeScript
232 lines
7.7 KiB
TypeScript
/**
|
|
* 系统监控页面
|
|
*/
|
|
import React, { useState, useEffect } from 'react';
|
|
import { Card, Row, Col, Progress, Badge, Table, Tag, Button, Space } from 'antd';
|
|
import {
|
|
CheckCircleOutlined,
|
|
CloseCircleOutlined,
|
|
SyncOutlined,
|
|
ReloadOutlined,
|
|
DatabaseOutlined,
|
|
ApiOutlined,
|
|
CloudServerOutlined,
|
|
ThunderboltOutlined,
|
|
} from '@ant-design/icons';
|
|
|
|
const SystemMonitor: React.FC = () => {
|
|
const [refreshTime, setRefreshTime] = useState(new Date());
|
|
|
|
// 模拟实时数据
|
|
const [systemMetrics, setSystemMetrics] = useState({
|
|
cpu: 35,
|
|
memory: 62,
|
|
disk: 48,
|
|
network: 28,
|
|
});
|
|
|
|
// 服务健康状态
|
|
const services = [
|
|
{ name: 'API 服务', status: 'healthy', uptime: '99.98%', responseTime: '45ms' },
|
|
{ name: 'PostgreSQL', status: 'healthy', uptime: '99.99%', responseTime: '8ms' },
|
|
{ name: 'Redis', status: 'healthy', uptime: '99.97%', responseTime: '2ms' },
|
|
{ name: 'Celery Worker', status: 'healthy', uptime: '99.95%', responseTime: '-' },
|
|
{ name: 'Object Storage', status: 'warning', uptime: '99.85%', responseTime: '120ms' },
|
|
];
|
|
|
|
// API 请求统计
|
|
const apiStats = [
|
|
{ endpoint: 'POST /api/v1/auth/login', requests: 15420, avgTime: '48ms', errors: 12 },
|
|
{ endpoint: 'GET /api/v1/workspaces', requests: 89340, avgTime: '32ms', errors: 5 },
|
|
{ endpoint: 'POST /api/v1/projects', requests: 6780, avgTime: '156ms', errors: 8 },
|
|
{ endpoint: 'GET /api/v1/assets', requests: 124560, avgTime: '68ms', errors: 23 },
|
|
{ endpoint: 'POST /api/v1/subscriptions/subscribe', requests: 234, avgTime: '890ms', errors: 2 },
|
|
];
|
|
|
|
// 错误日志
|
|
const recentErrors = [
|
|
{ time: '2024-06-17 16:45:32', level: 'ERROR', service: 'API', message: 'Database connection timeout' },
|
|
{ time: '2024-06-17 16:42:15', level: 'WARN', service: 'Object Storage', message: 'Slow response detected (>1s)' },
|
|
{ time: '2024-06-17 16:38:41', level: 'ERROR', service: 'Celery', message: 'Task retry limit exceeded' },
|
|
];
|
|
|
|
const serviceColumns = [
|
|
{
|
|
title: '服务名称',
|
|
dataIndex: 'name',
|
|
key: 'name',
|
|
render: (text: string) => <><CloudServerOutlined /> {text}</>,
|
|
},
|
|
{
|
|
title: '状态',
|
|
dataIndex: 'status',
|
|
key: 'status',
|
|
render: (status: string) => {
|
|
const config: Record<string, { color: string; icon: React.ReactNode; text: string }> = {
|
|
healthy: { color: 'success', icon: <CheckCircleOutlined />, text: '正常' },
|
|
warning: { color: 'warning', icon: <SyncOutlined spin />, text: '警告' },
|
|
error: { color: 'error', icon: <CloseCircleOutlined />, text: '故障' },
|
|
};
|
|
const { color, text } = config[status] || config.healthy;
|
|
return <Badge status={color as any} text={text} />;
|
|
},
|
|
},
|
|
{ title: '可用性', dataIndex: 'uptime', key: 'uptime' },
|
|
{ title: '响应时间', dataIndex: 'responseTime', key: 'responseTime' },
|
|
];
|
|
|
|
const apiColumns = [
|
|
{ title: 'API 端点', dataIndex: 'endpoint', key: 'endpoint' },
|
|
{ title: '请求数', dataIndex: 'requests', key: 'requests', sorter: (a: any, b: any) => a.requests - b.requests },
|
|
{ title: '平均响应时间', dataIndex: 'avgTime', key: 'avgTime' },
|
|
{
|
|
title: '错误数',
|
|
dataIndex: 'errors',
|
|
key: 'errors',
|
|
render: (errors: number) => (
|
|
<Tag color={errors > 10 ? 'red' : errors > 5 ? 'orange' : 'green'}>{errors}</Tag>
|
|
),
|
|
},
|
|
];
|
|
|
|
const errorColumns = [
|
|
{ title: '时间', dataIndex: 'time', key: 'time', width: 180 },
|
|
{
|
|
title: '级别',
|
|
dataIndex: 'level',
|
|
key: 'level',
|
|
width: 100,
|
|
render: (level: string) => (
|
|
<Tag color={level === 'ERROR' ? 'red' : 'orange'}>{level}</Tag>
|
|
),
|
|
},
|
|
{ title: '服务', dataIndex: 'service', key: 'service', width: 120 },
|
|
{ title: '错误信息', dataIndex: 'message', key: 'message' },
|
|
];
|
|
|
|
const refreshMetrics = () => {
|
|
setSystemMetrics({
|
|
cpu: Math.floor(Math.random() * 30) + 30,
|
|
memory: Math.floor(Math.random() * 20) + 55,
|
|
disk: Math.floor(Math.random() * 10) + 45,
|
|
network: Math.floor(Math.random() * 40) + 20,
|
|
});
|
|
setRefreshTime(new Date());
|
|
};
|
|
|
|
// 模拟实时更新
|
|
useEffect(() => {
|
|
const interval = setInterval(refreshMetrics, 5000);
|
|
|
|
return () => clearInterval(interval);
|
|
}, []);
|
|
|
|
const getProgressColor = (value: number) => {
|
|
if (value > 80) return '#ff4d4f';
|
|
if (value > 60) return '#faad14';
|
|
return '#52c41a';
|
|
};
|
|
|
|
return (
|
|
<div style={{ padding: '24px' }}>
|
|
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 24 }}>
|
|
<h1>系统监控</h1>
|
|
<Space>
|
|
<span style={{ color: '#8c8c8c' }}>上次更新: {refreshTime.toLocaleTimeString()}</span>
|
|
<Button icon={<ReloadOutlined />} onClick={refreshMetrics}>刷新</Button>
|
|
</Space>
|
|
</div>
|
|
|
|
{/* 系统资源监控 */}
|
|
<Row gutter={16} style={{ marginBottom: 24 }}>
|
|
<Col span={6}>
|
|
<Card>
|
|
<div style={{ textAlign: 'center' }}>
|
|
<ThunderboltOutlined style={{ fontSize: 32, color: '#1890ff', marginBottom: 8 }} />
|
|
<div style={{ marginBottom: 16 }}>CPU 使用率</div>
|
|
<Progress
|
|
type="circle"
|
|
percent={systemMetrics.cpu}
|
|
strokeColor={getProgressColor(systemMetrics.cpu)}
|
|
/>
|
|
</div>
|
|
</Card>
|
|
</Col>
|
|
<Col span={6}>
|
|
<Card>
|
|
<div style={{ textAlign: 'center' }}>
|
|
<DatabaseOutlined style={{ fontSize: 32, color: '#52c41a', marginBottom: 8 }} />
|
|
<div style={{ marginBottom: 16 }}>内存使用率</div>
|
|
<Progress
|
|
type="circle"
|
|
percent={systemMetrics.memory}
|
|
strokeColor={getProgressColor(systemMetrics.memory)}
|
|
/>
|
|
</div>
|
|
</Card>
|
|
</Col>
|
|
<Col span={6}>
|
|
<Card>
|
|
<div style={{ textAlign: 'center' }}>
|
|
<CloudServerOutlined style={{ fontSize: 32, color: '#faad14', marginBottom: 8 }} />
|
|
<div style={{ marginBottom: 16 }}>磁盘使用率</div>
|
|
<Progress
|
|
type="circle"
|
|
percent={systemMetrics.disk}
|
|
strokeColor={getProgressColor(systemMetrics.disk)}
|
|
/>
|
|
</div>
|
|
</Card>
|
|
</Col>
|
|
<Col span={6}>
|
|
<Card>
|
|
<div style={{ textAlign: 'center' }}>
|
|
<ApiOutlined style={{ fontSize: 32, color: '#722ed1', marginBottom: 8 }} />
|
|
<div style={{ marginBottom: 16 }}>网络使用率</div>
|
|
<Progress
|
|
type="circle"
|
|
percent={systemMetrics.network}
|
|
strokeColor={getProgressColor(systemMetrics.network)}
|
|
/>
|
|
</div>
|
|
</Card>
|
|
</Col>
|
|
</Row>
|
|
|
|
{/* 服务健康状态 */}
|
|
<Card title="服务健康状态" style={{ marginBottom: 24 }}>
|
|
<Table
|
|
columns={serviceColumns}
|
|
dataSource={services}
|
|
rowKey="name"
|
|
pagination={false}
|
|
/>
|
|
</Card>
|
|
|
|
{/* API 请求统计 */}
|
|
<Card title="API 请求统计 (最近 1 小时)" style={{ marginBottom: 24 }}>
|
|
<Table
|
|
columns={apiColumns}
|
|
dataSource={apiStats}
|
|
rowKey="endpoint"
|
|
pagination={false}
|
|
/>
|
|
</Card>
|
|
|
|
{/* 最近错误 */}
|
|
<Card title="最近错误日志">
|
|
<Table
|
|
columns={errorColumns}
|
|
dataSource={recentErrors}
|
|
rowKey="time"
|
|
pagination={false}
|
|
/>
|
|
</Card>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default SystemMonitor;
|
|
|
|
export const Component = SystemMonitor;
|