pages_alert_trend_chart.tsx 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. import React, { useState } from 'react';
  2. import {
  3. Button, Form, Select, Card, Typography, DatePicker
  4. } from 'antd';
  5. import {
  6. useQuery,
  7. } from '@tanstack/react-query';
  8. import dayjs from 'dayjs';
  9. import { Line } from "@ant-design/plots";
  10. import 'dayjs/locale/zh-cn';
  11. import { MonitorChartsAPI } from './api/index.ts';
  12. interface ChartTooltipInfo {
  13. items: Array<Record<string, any>>;
  14. title: string;
  15. }
  16. // 告警数据变化图表页面
  17. export const AlertTrendChartPage = () => {
  18. const [timeRange, setTimeRange] = useState<[dayjs.Dayjs, dayjs.Dayjs]>([
  19. dayjs().subtract(1, 'day').startOf('day'),
  20. dayjs().endOf('day')
  21. ]);
  22. const [dimension, setDimension] = useState<'hour' | 'day' | 'month'>('hour');
  23. const { data: alarmData, isLoading, refetch } = useQuery({
  24. queryKey: ['adminZichanAlarm', timeRange, dimension],
  25. queryFn: async () => {
  26. const params = {
  27. created_at_gte: timeRange[0].format('YYYY-MM-DD HH:mm:ss'),
  28. created_at_lte: timeRange[1].format('YYYY-MM-DD HH:mm:ss'),
  29. dimension
  30. };
  31. // const res = await axios.get<AlarmChartData[]>(`${API_BASE_URL}/big/zichan_alarm_chart`, { params });
  32. const res = await MonitorChartsAPI.fetchAlarmData(params);
  33. return res;
  34. }
  35. });
  36. const { Title } = Typography;
  37. const { RangePicker } = DatePicker;
  38. const handleSearch = () => {
  39. refetch();
  40. };
  41. return (
  42. <div>
  43. <Title level={2}>告警数据趋势</Title>
  44. <Card>
  45. <Form layout="inline" style={{ marginBottom: '16px' }}>
  46. <Form.Item label="时间范围">
  47. <RangePicker
  48. value={timeRange}
  49. onChange={(dates) => dates && setTimeRange(dates as [dayjs.Dayjs, dayjs.Dayjs])}
  50. showTime
  51. />
  52. </Form.Item>
  53. <Form.Item label="时间维度">
  54. <Select
  55. value={dimension}
  56. onChange={setDimension}
  57. options={[
  58. { label: '小时', value: 'hour' },
  59. { label: '天', value: 'day' },
  60. { label: '月', value: 'month' }
  61. ]}
  62. style={{ width: '100px' }}
  63. />
  64. </Form.Item>
  65. <Form.Item>
  66. <Button type="primary" onClick={handleSearch}>查询</Button>
  67. </Form.Item>
  68. </Form>
  69. <div style={{ height: '500px' }}>
  70. {!isLoading && alarmData && (
  71. <Line
  72. data={alarmData}
  73. xField="time_interval"
  74. yField="total_devices"
  75. smooth={true}
  76. color="#36cfc9"
  77. label={{
  78. position: 'top',
  79. style: {
  80. fill: '#000',
  81. fontSize: 12,
  82. fontWeight: 500,
  83. },
  84. text: (items: Record<string, any>) => {
  85. const value = items['total_devices'];
  86. // if (value === 0) return null;
  87. // const maxValue = Math.max(...(alarmData || []).map(item => item.total_devices));
  88. // if (value < maxValue * 0.3 && alarmData && alarmData.length > 8) return null;
  89. return `${items['time_interval']}\n(${value})`;
  90. },
  91. transform: [{ type: 'overlapDodgeY' }],
  92. }}
  93. point={{
  94. size: 5,
  95. shape: 'diamond',
  96. }}
  97. xAxis={{
  98. label: {
  99. style: {
  100. fill: '#000',
  101. },
  102. autoHide: true,
  103. autoRotate: true,
  104. },
  105. }}
  106. yAxis={{
  107. label: {
  108. style: {
  109. fill: '#000',
  110. },
  111. },
  112. }}
  113. autoFit={true}
  114. interaction={{
  115. tooltip: {
  116. render: (_: unknown, { items, title }: ChartTooltipInfo) => {
  117. if (!items || items.length === 0) return '';
  118. // 获取当前选中项的数据
  119. const item = items[0];
  120. // 根据value找到对应的完整数据项
  121. const fullData = alarmData?.find(d => d.total_devices === item.value);
  122. if (!fullData) return '';
  123. return `<div class="bg-white p-2 rounded">
  124. <div class="flex items-center">
  125. <div class="w-3 h-3 rounded-full mr-2" style="background:${item.color}"></div>
  126. <span class="font-semibold text-gray-900">${fullData.time_interval}</span>
  127. </div>
  128. <p class="text-sm text-gray-800">数量: ${item.value}</p>
  129. </div>`;
  130. }
  131. }
  132. }}
  133. />
  134. )}
  135. </div>
  136. </Card>
  137. </div>
  138. );
  139. };