172 lines
5.6 KiB
TypeScript
172 lines
5.6 KiB
TypeScript
import React, { useEffect, useRef, useState } from 'react';
|
|
import { Card, Row, Col, Space } from 'antd';
|
|
import {
|
|
BellOutlined,
|
|
ExclamationCircleOutlined,
|
|
ClockCircleOutlined,
|
|
CheckCircleOutlined
|
|
} from '@ant-design/icons';
|
|
import * as echarts from 'echarts';
|
|
|
|
// 接口引入
|
|
import { getAlarmStatistics } from '../../api/alarmApi.js';
|
|
import { useTranslation } from 'react-i18next';
|
|
|
|
const AlarmStatistics = () => {
|
|
const { t } = useTranslation();
|
|
const barChartRef = useRef(null);
|
|
const pieChartRef = useRef(null);
|
|
|
|
const [statData, setStatData] = useState({
|
|
total: 0,
|
|
levelStats: {},
|
|
pending: 0,
|
|
processing: 0,
|
|
closed: 0,
|
|
});
|
|
|
|
// 获取统计(修复:接口 code = 0 才是成功)
|
|
const fetchStat = async () => {
|
|
try {
|
|
const res = await getAlarmStatistics();
|
|
if (res.code === 200) {
|
|
setStatData(res.data || {});
|
|
}
|
|
} catch (err) { }
|
|
};
|
|
|
|
// 柱状图
|
|
useEffect(() => {
|
|
if (!barChartRef.current) return;
|
|
const chart = echarts.init(barChartRef.current);
|
|
|
|
const option = {
|
|
title: { text: t('alerts.sevenDayTrend'), textStyle: { fontSize: 14 } },
|
|
xAxis: { type: 'category', data: [t('devices.daySuffix', { day: 1 }), t('devices.daySuffix', { day: 2 }), t('devices.daySuffix', { day: 3 }), t('devices.daySuffix', { day: 4 }), t('devices.daySuffix', { day: 5 }), t('devices.daySuffix', { day: 6 }), t('devices.daySuffix', { day: 7 })] },
|
|
yAxis: { type: 'value' },
|
|
series: [{
|
|
data: [5, 8, 12, 9, 15, 7, statData.total || 2],
|
|
type: 'bar',
|
|
itemStyle: { color: '#165DFF', borderRadius: 4 }
|
|
}]
|
|
};
|
|
|
|
chart.setOption(option);
|
|
const resize = () => chart.resize();
|
|
window.addEventListener('resize', resize);
|
|
return () => {
|
|
chart.dispose();
|
|
window.removeEventListener('resize', resize);
|
|
};
|
|
}, [statData]);
|
|
|
|
// 饼图
|
|
useEffect(() => {
|
|
if (!pieChartRef.current) return;
|
|
const chart = echarts.init(pieChartRef.current);
|
|
|
|
const pieData = [
|
|
{ value: statData.levelStats?.[1] || 0, name: t('alerts.criticalAlert') },
|
|
{ value: statData.levelStats?.[2] || 0, name: t('alerts.importantAlert') },
|
|
{ value: statData.levelStats?.[3] || 0, name: t('alerts.generalAlert') },
|
|
{ value: statData.levelStats?.[4] || 0, name: t('alerts.infoAlert') },
|
|
].filter(i => i.value > 0);
|
|
|
|
const option = {
|
|
title: { text: t('alerts.alertLevelDistribution') },
|
|
tooltip: { trigger: 'item' },
|
|
legend: { bottom: 0 },
|
|
series: [{
|
|
type: 'pie',
|
|
radius: ['40%', '70%'],
|
|
data: pieData.length ? pieData : [{ value: 1, name: t('common.noData') }],
|
|
color: ['#F53F3F', '#FF7D00', '#F7BA1E', '#165DFF'],
|
|
}]
|
|
};
|
|
|
|
chart.setOption(option);
|
|
const resize = () => chart.resize();
|
|
window.addEventListener('resize', resize);
|
|
return () => {
|
|
chart.dispose();
|
|
window.removeEventListener('resize', resize);
|
|
};
|
|
}, [statData]);
|
|
|
|
useEffect(() => {
|
|
fetchStat();
|
|
}, []);
|
|
|
|
return (
|
|
<div style={{ padding: 24, background: '#f5f7fa', minHeight: '100vh' }}>
|
|
<Card title={t('alerts.alertOverview')} variant="borderless" style={{ marginBottom: 24, borderRadius: 8 }}>
|
|
<Row gutter={16} align="middle">
|
|
<Col xs={24} sm={12} md={6}>
|
|
<Space size={16}>
|
|
<div style={{ width: 48, height: 48, background: '#FFF1F0', borderRadius: '50%', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
|
|
<BellOutlined style={{ fontSize: 24, color: '#F53F3F' }} />
|
|
</div>
|
|
<div>
|
|
<div style={{ fontSize: 14, color: '#4E5969' }}>{t('report.totalAlerts')}</div>
|
|
<div style={{ fontSize: 24, fontWeight: 700 }}>{statData.total || 0}</div>
|
|
</div>
|
|
</Space>
|
|
</Col>
|
|
|
|
<Col xs={24} sm={12} md={6}>
|
|
<Space size={16}>
|
|
<div style={{ width: 48, height: 48, background: '#FFF1F0', borderRadius: '50%', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
|
|
<ExclamationCircleOutlined style={{ fontSize: 24, color: '#F53F3F' }} />
|
|
</div>
|
|
<div>
|
|
<div style={{ fontSize: 14, color: '#4E5969' }}>{t('alerts.criticalAlert')}</div>
|
|
<div style={{ fontSize: 24, fontWeight: 700 }}>{statData.levelStats?.[1] || 0}</div>
|
|
</div>
|
|
</Space>
|
|
</Col>
|
|
|
|
<Col xs={24} sm={12} md={6}>
|
|
<Space size={16}>
|
|
<div style={{ width: 48, height: 48, background: '#FFF7E8', borderRadius: '50%', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
|
|
<ClockCircleOutlined style={{ fontSize: 24, color: '#FF7D00' }} />
|
|
</div>
|
|
<div>
|
|
<div style={{ fontSize: 14, color: '#4E5969' }}>{t('constants.pending')}</div>
|
|
<div style={{ fontSize: 24, fontWeight: 700 }}>{statData.pending || 0}</div>
|
|
</div>
|
|
</Space>
|
|
</Col>
|
|
|
|
<Col xs={24} sm={12} md={6}>
|
|
<Space size={16}>
|
|
<div style={{ width: 48, height: 48, background: '#E8FFEA', borderRadius: '50%', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
|
|
<CheckCircleOutlined style={{ fontSize: 24, color: '#00B42A' }} />
|
|
</div>
|
|
<div>
|
|
<div style={{ fontSize: 14, color: '#4E5969' }}>{t('constants.closed')}</div>
|
|
<div style={{ fontSize: 24, fontWeight: 700 }}>{statData.closed || 0}</div>
|
|
</div>
|
|
</Space>
|
|
</Col>
|
|
</Row>
|
|
</Card>
|
|
|
|
<Row gutter={16}>
|
|
<Col xs={24} md={12}>
|
|
<Card variant="borderless" style={{ borderRadius: 8 }}>
|
|
<div ref={barChartRef} style={{ width: '100%', height: 360 }} />
|
|
</Card>
|
|
</Col>
|
|
|
|
<Col xs={24} md={12}>
|
|
<Card variant="borderless" style={{ borderRadius: 8 }}>
|
|
<div ref={pieChartRef} style={{ width: '100%', height: 360 }} />
|
|
</Card>
|
|
</Col>
|
|
</Row>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default AlarmStatistics;
|