import React, { useState, useEffect, useRef } from 'react'; import ReactECharts from 'echarts-for-react'; import type { EChartsOption } from 'echarts'; import { Card, Statistic, Space, Table, message, Select, Button, DatePicker, Radio, Tabs, Tag } from 'antd'; import { MonitorOutlined, EnvironmentOutlined, CloudOutlined, LineChartOutlined } from '@ant-design/icons'; import dayjs, { Dayjs } from 'dayjs'; import { MonitorAPI, getLatestTemperatureHumidity } from './api/monitor.ts'; import { DeviceMonitorData } from '../share/monitorTypes.ts'; interface SensorData { timestamp: string; temperature?: number; humidity?: number; metric_type: string; } const TemperatureHumidityPage: React.FC = () => { const [currentData, setCurrentData] = useState(null); const [tableData, setTableData] = useState([]); const [loading, setLoading] = useState(false); const [selectedDevice, setSelectedDevice] = useState('device1'); const [timeRange, setTimeRange] = useState<'4h' | '12h' | '1d' | '7d' | 'custom'>('4h'); const [customDateRange, setCustomDateRange] = useState<[dayjs.Dayjs, dayjs.Dayjs]>(); const [activeTab, setActiveTab] = useState('table'); const [isPolling, setIsPolling] = useState(true); const [pollInterval, setPollInterval] = useState(30000); // 默认30秒 const chartRef = useRef(null); const fetchData = async () => { try { setLoading(true); // 获取最新温湿度数据 const latestData = await getLatestTemperatureHumidity(); setCurrentData({ timestamp: latestData.timestamp, temperature: latestData.temperature, humidity: latestData.humidity, metric_type: 'combined' }); let startTime: Date, endTime = new Date(); if (timeRange === '4h') { startTime = new Date(Date.now() - 4 * 60 * 60 * 1000); } else if (timeRange === '12h') { startTime = new Date(Date.now() - 12 * 60 * 60 * 1000); } else if (timeRange === '1d') { startTime = new Date(Date.now() - 24 * 60 * 60 * 1000); } else if (timeRange === '7d') { startTime = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000); } else if (customDateRange) { startTime = customDateRange[0].toDate(); endTime = customDateRange[1].toDate(); } else { // Default to 4h if no range is selected startTime = new Date(Date.now() - 4 * 60 * 60 * 1000); } const response = await MonitorAPI.getMonitorData({ device_type: 'temperature_humidity', start_time: startTime.toISOString(), end_time: endTime.toISOString() }); if (response.data.length > 0) { // 分别获取温度和湿度数据 const tempData = response.data .filter(item => item.metric_type === 'temperature') .map(item => ({ timestamp: item.created_at.toISOString(), temperature: item.metric_value, metric_type: item.metric_type })); const humidityData = response.data .filter(item => item.metric_type === 'humidity') .map(item => ({ timestamp: item.created_at.toISOString(), humidity: item.metric_value, metric_type: item.metric_type })); // 合并数据 const sensorData = tempData.map(temp => { const humidity = humidityData.find(h => h.timestamp === temp.timestamp); return { timestamp: temp.timestamp, temperature: temp.temperature, humidity: humidity?.humidity, metric_type: 'combined' }; }); setCurrentData(sensorData[0]); setTableData(sensorData); } } catch (error) { message.error('获取温湿度数据失败'); } finally { setLoading(false); } }; useEffect(() => { fetchData(); if (!isPolling) return; const timer = setInterval(fetchData, pollInterval); return () => clearInterval(timer); }, [isPolling, pollInterval]); const getChartOption = (): EChartsOption => { const xAxisData = tableData.map(item => new Date(item.timestamp).toLocaleTimeString() ).reverse(); const temperatureData = tableData.map(item => item.temperature).reverse(); const humidityData = tableData.map(item => item.humidity).reverse(); return { title: { text: '温湿度趋势图', left: 'center' }, tooltip: { trigger: 'axis' as const, axisPointer: { type: 'cross' as const } }, legend: { data: ['温度(℃)', '湿度(%)'], top: 30 }, grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true }, xAxis: { type: 'category' as const, boundaryGap: false, data: xAxisData }, yAxis: [ { type: 'value' as const, name: '温度(℃)', min: 10, max: 35, axisLabel: { formatter: '{value} °C' } }, { type: 'value' as const, name: '湿度(%)', min: 20, max: 90, axisLabel: { formatter: '{value} %' } } ], series: [ { name: '温度(℃)', type: 'line' as const, data: temperatureData, smooth: true, lineStyle: { color: '#ff4d4f' }, itemStyle: { color: '#ff4d4f' } }, { name: '湿度(%)', type: 'line' as const, yAxisIndex: 1, data: humidityData, smooth: true, lineStyle: { color: '#1890ff' }, itemStyle: { color: '#1890ff' } } ] }; }; const getStatus = (temp?: number, humidity?: number) => { // 定义正常范围:温度10-30°C,湿度30-70% const isTempNormal = temp && temp >= 10 && temp <= 30; const isHumidityNormal = humidity && humidity >= 30 && humidity <= 70; return isTempNormal && isHumidityNormal ? '正常' : '异常'; }; const columns = [ { title: '序号', key: 'index', render: (text: string, record: any, index: number) => index + 1, width: 80 }, { title: '设备名称', key: 'device', render: () => selectedDevice === 'device1' ? '温湿度1' : '温湿度2', width: 120 }, { title: '温度 (°C)', dataIndex: 'temperature', key: 'temperature', render: (text: number) => text?.toFixed(1), width: 100 }, { title: '湿度 (%)', dataIndex: 'humidity', key: 'humidity', render: (text: number) => text?.toFixed(1), width: 100 }, { title: '状态', key: 'status', render: (text: string, record: SensorData) => ( {getStatus(record.temperature, record.humidity)} ), width: 100 }, { title: '时间', dataIndex: 'timestamp', key: 'timestamp', render: (text: string) => new Date(text).toLocaleString(), width: 180 } ]; return (
setPollInterval(value)} options={[ { value: 10000, label: '10秒' }, { value: 30000, label: '30秒' }, { value: 60000, label: '1分钟' } ]} /> } >
} style={{ textAlign: 'center' }} valueStyle={{ fontSize: '32px' }} />
} style={{ textAlign: 'center' }} valueStyle={{ fontSize: '32px' }} />
setTimeRange(e.target.value)} buttonStyle="solid" > 4小时 12小时 1天 7天 自定义 {timeRange === 'custom' && ( { if (dates && dates[0] && dates[1]) { setCustomDateRange([dates[0], dates[1]]); } }} /> )} } > ); }; export default TemperatureHumidityPage;