'use client' import React, { useEffect, useState, useMemo } from 'react' import { useRouter } from 'next/navigation' import Sidebar from '../ui/Sidebar' import AnimatedBackground from '../ui/AnimatedBackground' import useNavigationStore from '../../app/store/navigationStore' import ChartCard from './ChartCard' import AreaChart from './AreaChart' import BarChart from './BarChart' import { aggregateChartDataByDays, aggregateAlertsBySeverity } from '../../lib/chartDataAggregator' const Dashboard: React.FC = () => { const router = useRouter() const { currentObject, setCurrentSubmenu, closeMonitoring, closeFloorNavigation, closeNotifications, navigateToSensor } = useNavigationStore() const objectTitle = currentObject?.title const [dashboardAlerts, setDashboardAlerts] = useState([]) const [rawChartData, setRawChartData] = useState<{ timestamp: string; value: number }[]>([]) const [sensorTypes] = useState>([ { code: '', name: 'Все датчики' }, { code: 'GA', name: 'Инклинометр' }, { code: 'PE', name: 'Танзометр' }, { code: 'GLE', name: 'Гидроуровень' } ]) const [selectedSensorType, setSelectedSensorType] = useState('') const [selectedChartPeriod, setSelectedChartPeriod] = useState('168') const [selectedTablePeriod, setSelectedTablePeriod] = useState('168') useEffect(() => { const loadDashboard = async () => { try { const params = new URLSearchParams() params.append('time_period', selectedChartPeriod) const res = await fetch(`/api/get-dashboard?${params.toString()}`, { cache: 'no-store' }) if (!res.ok) return const payload = await res.json() console.log('[Dashboard] GET /api/get-dashboard', { status: res.status, payload }) let tableData = payload?.data?.table_data ?? [] tableData = Array.isArray(tableData) ? tableData : [] if (objectTitle) { tableData = tableData.filter((a: any) => a.object === objectTitle) } if (selectedSensorType && selectedSensorType !== '') { tableData = tableData.filter((a: any) => { return a.detector_type?.toLowerCase() === selectedSensorType.toLowerCase() }) } setDashboardAlerts(tableData as any[]) const cd = Array.isArray(payload?.data?.chart_data) ? payload.data.chart_data : [] setRawChartData(cd as any[]) } catch (e) { console.error('Failed to load dashboard:', e) } } loadDashboard() }, [objectTitle, selectedChartPeriod, selectedSensorType]) // Отдельный эффект для загрузки таблицы по выбранному периоду useEffect(() => { const loadTableData = async () => { try { const params = new URLSearchParams() params.append('time_period', selectedTablePeriod) const res = await fetch(`/api/get-dashboard?${params.toString()}`, { cache: 'no-store' }) if (!res.ok) return const payload = await res.json() console.log('[Dashboard] GET /api/get-dashboard (table)', { status: res.status, payload }) let tableData = payload?.data?.table_data ?? [] tableData = Array.isArray(tableData) ? tableData : [] if (objectTitle) { tableData = tableData.filter((a: any) => a.object === objectTitle) } if (selectedSensorType && selectedSensorType !== '') { tableData = tableData.filter((a: any) => { return a.detector_type?.toLowerCase() === selectedSensorType.toLowerCase() }) } setDashboardAlerts(tableData as any[]) } catch (e) { console.error('Failed to load table data:', e) } } loadTableData() }, [objectTitle, selectedTablePeriod, selectedSensorType]) const handleBackClick = () => { router.push('/objects') } const filteredAlerts = dashboardAlerts.filter((alert: any) => { if (selectedSensorType === '') return true return alert.detector_type?.toLowerCase() === selectedSensorType.toLowerCase() }) // Статусы const statusCounts = filteredAlerts.reduce((acc: { critical: number; warning: number; normal: number }, a: any) => { if (a.severity === 'critical') acc.critical++ else if (a.severity === 'warning') acc.warning++ else acc.normal++ return acc }, { critical: 0, warning: 0, normal: 0 }) const handleNavigationClick = () => { closeMonitoring() closeFloorNavigation() closeNotifications() setCurrentSubmenu(null) router.push('/navigation') } const handleGoTo3D = async (alert: any, viewType: 'building' | 'floor') => { // Используем alert.name как идентификатор датчика (например, "GA-11") const sensorId = alert.serial_number || alert.name if (!sensorId) { console.warn('[Dashboard] Alert missing sensor identifier:', alert) return } const result = await navigateToSensor( sensorId, alert.floor || null, viewType ) if (result) { // Переходим на страницу навигации с параметрами focusSensorId и modelPath router.push(`/navigation?focusSensorId=${encodeURIComponent(result.sensorSerialNumber)}&modelPath=${encodeURIComponent(result.modelPath)}`) } } const handleSensorTypeChange = (sensorType: string) => { setSelectedSensorType(sensorType) } const handleChartPeriodChange = (period: string) => { setSelectedChartPeriod(period) } const handleTablePeriodChange = (period: string) => { setSelectedTablePeriod(period) } // Агрегируем данные графика в зависимости от периода с разделением по severity const chartData = useMemo(() => { return aggregateAlertsBySeverity(dashboardAlerts, selectedChartPeriod) }, [dashboardAlerts, selectedChartPeriod]) const interSemiboldStyle = { fontFamily: 'Inter, sans-serif', fontWeight: 600 } const interRegularStyle = { fontFamily: 'Inter, sans-serif', fontWeight: 400 } return (

{objectTitle || 'Объект'}

{/* Карты-графики */}
{/* Список детекторов */}

Тренды

{/* Таблица */}
{filteredAlerts.map((alert: any) => ( ))}
Детектор Сообщение Серьезность Дата Решен 3D Вид
{alert.name} {alert.message} {alert.severity === 'critical' ? 'Критическое' : alert.severity === 'warning' ? 'Предупреждение' : 'Норма'} {new Date(alert.created_at).toLocaleString()} {alert.resolved ? ( Да ) : ( Нет ) }
{/* Статистика */}
{filteredAlerts.length}
Всего
{statusCounts.normal}
Норма
{statusCounts.warning}
Предупреждения
{statusCounts.critical}
Критические
) } export default Dashboard