146 lines
5.2 KiB
TypeScript
146 lines
5.2 KiB
TypeScript
import { useState, useEffect } from 'react';
|
|
import { Row, Col, Card, Descriptions, Spin, message, Typography } from 'antd';
|
|
import ReactEChartsCore from 'echarts-for-react/lib/core';
|
|
import { echarts } from '@/utils/echarts';
|
|
import { macarons } from '../../themes/macarons';
|
|
import { getCache } from '../../api/monitor/cache';
|
|
import type { CacheMonitorResponse } from '@/types/api';
|
|
import './cache-monitor.css';
|
|
|
|
const { Text } = Typography;
|
|
|
|
echarts.registerTheme('macarons', macarons);
|
|
|
|
const defaultCacheData: CacheMonitorResponse = {
|
|
info: {},
|
|
dbSize: 0,
|
|
commandStats: [],
|
|
};
|
|
|
|
const toDisplayText = (value: string | number | undefined): string => {
|
|
if (value === undefined || value === null) {
|
|
return '';
|
|
}
|
|
return String(value);
|
|
};
|
|
|
|
const CacheMonitorPage = () => {
|
|
const [loading, setLoading] = useState(true);
|
|
const [cacheData, setCacheData] = useState<CacheMonitorResponse>(defaultCacheData);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
useEffect(() => {
|
|
getCache()
|
|
.then((response) => {
|
|
setCacheData(response);
|
|
})
|
|
.catch(() => {
|
|
const errorMsg = '加载缓存数据失败,请确认后端服务是否正常。';
|
|
setError(errorMsg);
|
|
message.error(errorMsg);
|
|
})
|
|
.finally(() => {
|
|
setLoading(false);
|
|
});
|
|
}, []);
|
|
|
|
if (loading) {
|
|
return <Spin spinning={true} description="正在加载缓存监控数据..." style={{ display: 'block', marginTop: '50px' }} />;
|
|
}
|
|
|
|
if (error) {
|
|
return <div style={{ textAlign: 'center', marginTop: '50px' }}><Text type="danger">{error}</Text></div>;
|
|
}
|
|
|
|
const commandStatsOptions = {
|
|
tooltip: {
|
|
trigger: 'item',
|
|
formatter: '{a} <br/>{b} : {c} ({d}%)',
|
|
},
|
|
series: [
|
|
{
|
|
name: '命令',
|
|
type: 'pie',
|
|
roseType: 'radius',
|
|
radius: [15, 95],
|
|
center: ['50%', '38%'],
|
|
data: cacheData.commandStats || [],
|
|
animationEasing: 'cubicInOut',
|
|
animationDuration: 1000,
|
|
},
|
|
],
|
|
};
|
|
|
|
const usedMemoryOptions = {
|
|
tooltip: {
|
|
formatter: `{b} <br/>{a} : ${toDisplayText(cacheData.info?.used_memory_human)}`,
|
|
},
|
|
series: [
|
|
{
|
|
name: '峰值',
|
|
type: 'gauge',
|
|
min: 0,
|
|
max: 1000,
|
|
detail: {
|
|
formatter: toDisplayText(cacheData.info?.used_memory_human),
|
|
},
|
|
data: [
|
|
{
|
|
value: Number.parseFloat(toDisplayText(cacheData.info?.used_memory_human)) || 0,
|
|
name: '内存消耗',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
};
|
|
|
|
return (
|
|
<div className="app-container cache-monitor-container">
|
|
<Row gutter={[16, 16]}>
|
|
<Col span={24} className="card-box">
|
|
<Card title="基本信息">
|
|
<Descriptions bordered column={4}>
|
|
<Descriptions.Item label="Redis版本">{toDisplayText(cacheData.info?.redis_version)}</Descriptions.Item>
|
|
<Descriptions.Item label="运行模式">
|
|
{cacheData.info?.redis_mode === 'standalone' ? '单机' : toDisplayText(cacheData.info?.redis_mode)}
|
|
</Descriptions.Item>
|
|
<Descriptions.Item label="端口">{toDisplayText(cacheData.info?.tcp_port)}</Descriptions.Item>
|
|
<Descriptions.Item label="客户端数">{toDisplayText(cacheData.info?.connected_clients)}</Descriptions.Item>
|
|
<Descriptions.Item label="运行时间(天)">{toDisplayText(cacheData.info?.uptime_in_days)}</Descriptions.Item>
|
|
<Descriptions.Item label="使用内存">{toDisplayText(cacheData.info?.used_memory_human)}</Descriptions.Item>
|
|
<Descriptions.Item label="使用CPU">
|
|
{cacheData.info?.used_cpu_user_children
|
|
? Number.parseFloat(toDisplayText(cacheData.info.used_cpu_user_children)).toFixed(2)
|
|
: ''}
|
|
</Descriptions.Item>
|
|
<Descriptions.Item label="内存配置">{toDisplayText(cacheData.info?.maxmemory_human)}</Descriptions.Item>
|
|
<Descriptions.Item label="AOF是否开启">
|
|
{cacheData.info?.aof_enabled === '0' ? '否' : (cacheData.info?.aof_enabled ? '是' : '')}
|
|
</Descriptions.Item>
|
|
<Descriptions.Item label="RDB是否成功">{toDisplayText(cacheData.info?.rdb_last_bgsave_status)}</Descriptions.Item>
|
|
<Descriptions.Item label="Key数量">{cacheData.dbSize || ''}</Descriptions.Item>
|
|
<Descriptions.Item label="网络入口/出口">
|
|
{cacheData.info?.instantaneous_input_kbps
|
|
? `${cacheData.info.instantaneous_input_kbps}kps/${cacheData.info.instantaneous_output_kbps}kps`
|
|
: ''}
|
|
</Descriptions.Item>
|
|
</Descriptions>
|
|
</Card>
|
|
</Col>
|
|
<Col span={12} className="card-box">
|
|
<Card title="命令统计">
|
|
<ReactEChartsCore echarts={echarts} theme="macarons" option={commandStatsOptions} style={{ height: '420px' }} />
|
|
</Card>
|
|
</Col>
|
|
<Col span={12} className="card-box">
|
|
<Card title="内存信息">
|
|
<ReactEChartsCore echarts={echarts} theme="macarons" option={usedMemoryOptions} style={{ height: '420px' }} />
|
|
</Card>
|
|
</Col>
|
|
</Row>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default CacheMonitorPage;
|