704d381919
- Create unified Admin.css with V21 design tokens - Update Dashboard with stat cards and V21 color scheme - Update Analytics with V21 chart colors and metrics - Update UserManagement with V21 table and search styles - Update LogViewer with V21 filter bar and log level tags - Update SystemMonitor with V21 progress and resource cards - Update AdminComingSoon with V21 result styling - Replace all inline styles with V21 CSS classes - Apply Indigo/Green/Amber/Purple V21 color palette
225 lines
7.8 KiB
TypeScript
225 lines
7.8 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';
|
|
import './Admin.css';
|
|
|
|
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 className={errors > 10 ? 'xx-tag error' : errors > 5 ? 'xx-tag warning' : 'xx-tag success'}>{errors}</Tag>
|
|
),
|
|
},
|
|
];
|
|
|
|
const errorColumns = [
|
|
{ title: '时间', dataIndex: 'time', key: 'time', width: 180 },
|
|
{
|
|
title: '级别',
|
|
dataIndex: 'level',
|
|
key: 'level',
|
|
width: 100,
|
|
render: (level: string) => (
|
|
<Tag className={level === 'ERROR' ? 'xx-tag error' : 'xx-tag warning'}>{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 '#ef4444';
|
|
if (value > 60) return '#f59e0b';
|
|
return '#10b981';
|
|
};
|
|
|
|
const getProgressClass = (value: number) => {
|
|
if (value > 80) return 'xx-progress-warning';
|
|
if (value > 60) return 'xx-progress-warning';
|
|
return 'xx-progress-success';
|
|
};
|
|
|
|
const resourceMetrics = [
|
|
{ key: 'cpu', label: 'CPU 使用率', value: systemMetrics.cpu, icon: <ThunderboltOutlined />, bg: 'linear-gradient(135deg, #6366f1, #4f46e5)' },
|
|
{ key: 'memory', label: '内存使用率', value: systemMetrics.memory, icon: <DatabaseOutlined />, bg: 'linear-gradient(135deg, #34d399, #10b981)' },
|
|
{ key: 'disk', label: '磁盘使用率', value: systemMetrics.disk, icon: <CloudServerOutlined />, bg: 'linear-gradient(135deg, #fbbf24, #f59e0b)' },
|
|
{ key: 'network', label: '网络使用率', value: systemMetrics.network, icon: <ApiOutlined />, bg: 'linear-gradient(135deg, #a78bfa, #8b5cf6)' },
|
|
];
|
|
|
|
return (
|
|
<div className="system-monitor-page">
|
|
<div className="xx-page-head">
|
|
<div className="xx-page-head-content">
|
|
<h2>系统监控</h2>
|
|
<p>服务器资源、服务健康与 API 统计</p>
|
|
</div>
|
|
<div className="xx-page-head-actions">
|
|
<Space>
|
|
<span className="xx-refresh-time">上次更新: {refreshTime.toLocaleTimeString()}</span>
|
|
<Button icon={<ReloadOutlined />} onClick={refreshMetrics} className="xx-primary-btn">
|
|
刷新
|
|
</Button>
|
|
</Space>
|
|
</div>
|
|
</div>
|
|
|
|
{/* 系统资源监控 */}
|
|
<Row gutter={24} className="xx-grid-4">
|
|
{resourceMetrics.map((metric) => (
|
|
<Col span={6} key={metric.key}>
|
|
<div className="xx-resource-card">
|
|
<div
|
|
className="xx-resource-card-icon"
|
|
style={{ background: metric.bg, color: 'white' }}
|
|
>
|
|
{metric.icon}
|
|
</div>
|
|
<div className="xx-resource-card-label">{metric.label}</div>
|
|
<Progress
|
|
type="circle"
|
|
percent={metric.value}
|
|
strokeColor={getProgressColor(metric.value)}
|
|
className={getProgressClass(metric.value)}
|
|
/>
|
|
</div>
|
|
</Col>
|
|
))}
|
|
</Row>
|
|
|
|
{/* 服务健康状态 */}
|
|
<div className="xx-table-wrapper" style={{ marginBottom: 24 }}>
|
|
<Card title="服务健康状态" className="xx-card">
|
|
<Table
|
|
columns={serviceColumns}
|
|
dataSource={services}
|
|
rowKey="name"
|
|
pagination={false}
|
|
/>
|
|
</Card>
|
|
</div>
|
|
|
|
{/* API 请求统计 */}
|
|
<div className="xx-table-wrapper" style={{ marginBottom: 24 }}>
|
|
<Card title="API 请求统计 (最近 1 小时)" className="xx-card">
|
|
<Table
|
|
columns={apiColumns}
|
|
dataSource={apiStats}
|
|
rowKey="endpoint"
|
|
pagination={false}
|
|
/>
|
|
</Card>
|
|
</div>
|
|
|
|
{/* 最近错误 */}
|
|
<div className="xx-table-wrapper">
|
|
<Card title="最近错误日志" className="xx-card">
|
|
<Table
|
|
columns={errorColumns}
|
|
dataSource={recentErrors}
|
|
rowKey="time"
|
|
pagination={false}
|
|
/>
|
|
</Card>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default SystemMonitor;
|
|
|
|
export const Component = SystemMonitor;
|