'use client' import React from 'react' import { useRouter } from 'next/navigation' import useNavigationStore from '@/app/store/navigationStore' import AreaChart from '../dashboard/AreaChart' interface DetectorType { detector_id: number name: string serial_number: string object: string status: string checked: boolean type: string detector_type: string location: string floor: number notifications: Array<{ id: number type: string message: string timestamp: string acknowledged: boolean priority: string }> } interface DetectorMenuProps { detector: DetectorType isOpen: boolean onClose: () => void getStatusText: (status: string) => string compact?: boolean anchor?: { left: number; top: number } | null } // Главный компонент меню детектора // Показывает детальную информацию о датчике с возможностью навигации к отчетам и истории const DetectorMenu: React.FC = ({ detector, isOpen, onClose, getStatusText, compact = false, anchor = null }) => { const router = useRouter() const { setSelectedDetector, currentObject } = useNavigationStore() if (!isOpen) return null // Определение последней временной метки из уведомлений детектора const latestTimestamp = (() => { const list = detector.notifications ?? [] if (!Array.isArray(list) || list.length === 0) return null const dates = list.map(n => new Date(n.timestamp)).filter(d => !isNaN(d.getTime())) if (dates.length === 0) return null dates.sort((a, b) => b.getTime() - a.getTime()) return dates[0] })() const formattedTimestamp = latestTimestamp ? latestTimestamp.toLocaleString('ru-RU', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' }) : 'Нет данных' // Данные для графика за последние 3 дня (мок данные) const chartData: { timestamp: string; value: number }[] = [ { timestamp: new Date(Date.now() - 3 * 24 * 60 * 60 * 1000).toISOString(), value: 75 }, { timestamp: new Date(Date.now() - 2 * 24 * 60 * 60 * 1000).toISOString(), value: 82 }, { timestamp: new Date(Date.now() - 1 * 24 * 60 * 60 * 1000).toISOString(), value: 78 }, { timestamp: new Date().toISOString(), value: 85 }, ] // Определение типа детектора и его отображаемого названия const rawDetectorTypeCode = (detector.detector_type || '').toUpperCase() const deriveCodeFromType = (): string => { const t = (detector.type || '').toLowerCase() if (!t) return '' if (t.includes('инклинометр')) return 'GA' if (t.includes('тензометр')) return 'PE' if (t.includes('гидроуров')) return 'GLE' return '' } const effectiveDetectorTypeCode = rawDetectorTypeCode || deriveCodeFromType() // Карта соответствия кодов типов детекторов их русским названиям const detectorTypeLabelMap: Record = { GA: 'Инклинометр', PE: 'Тензометр', GLE: 'Гидроуровень', } const displayDetectorTypeLabel = detectorTypeLabelMap[effectiveDetectorTypeCode] || '—' // Обработчик клика по кнопке "Отчет" - навигация на страницу отчетов с выбранным детектором const handleReportsClick = () => { const currentUrl = new URL(window.location.href) const objectId = currentUrl.searchParams.get('objectId') || currentObject.id const objectTitle = currentUrl.searchParams.get('objectTitle') || currentObject.title const detectorData = { ...detector, notifications: detector.notifications || [] } setSelectedDetector(detectorData) let reportsUrl = '/reports' const params = new URLSearchParams() if (objectId) params.set('objectId', objectId) if (objectTitle) params.set('objectTitle', objectTitle) if (params.toString()) { reportsUrl += `?${params.toString()}` } router.push(reportsUrl) } // Обработчик клика по кнопке "История" - навигация на страницу истории тревог с выбранным детектором const handleHistoryClick = () => { const currentUrl = new URL(window.location.href) const objectId = currentUrl.searchParams.get('objectId') || currentObject.id const objectTitle = currentUrl.searchParams.get('objectTitle') || currentObject.title const detectorData = { ...detector, notifications: detector.notifications || [] } setSelectedDetector(detectorData) let alertsUrl = '/alerts' const params = new URLSearchParams() if (objectId) params.set('objectId', objectId) if (objectTitle) params.set('objectTitle', objectTitle) if (params.toString()) { alertsUrl += `?${params.toString()}` } router.push(alertsUrl) } // Компонент секции деталей детектора // Отображает информацию о датчике в компактном или полном формате const DetailsSection: React.FC<{ compact?: boolean }> = ({ compact = false }) => (
{compact ? ( // Компактный режим: 4 строки по 2 колонки с основной информацией <> {/* Строка 1: Маркировка и тип детектора */}
Маркировка по проекту
{detector.name}
Тип детектора
{displayDetectorTypeLabel}
{/* Строка 2: Местоположение и статус */}
Местоположение
{detector.location}
Статус
{getStatusText(detector.status)}
{/* Строка 3: Временная метка и этаж */}
Временная метка
{formattedTimestamp}
Этаж
{detector.floor}
{/* Строка 4: Серийный номер */}
Серийный номер
{detector.serial_number}
) : ( // Полный режим: 3 строки по 2 колонки с рамками между элементами <> {/* Строка 1: Маркировка по проекту и тип детектора */}
Маркировка по проекту
{detector.name}
Тип детектора
{displayDetectorTypeLabel}
{/* Строка 2: Местоположение и статус */}
Местоположение
{detector.location}
Статус
{getStatusText(detector.status)}
{/* Строка 3: Временная метка и серийный номер */}
Временная метка
{formattedTimestamp}
Серийный номер
{detector.serial_number}
)}
) // Компактный режим с якорной позицией (всплывающее окно) // Используется для отображения информации при наведении на детектор в списке if (compact && anchor) { // Проверяем границы экрана и корректируем позицию const tooltipHeight = 450 // Примерная высота толтипа с графиком const viewportHeight = typeof window !== 'undefined' ? window.innerHeight : 800 const bottomOverflow = anchor.top + tooltipHeight - viewportHeight // Если толтип выходит за нижнюю границу, сдвигаем вверх const adjustedTop = bottomOverflow > 0 ? anchor.top - bottomOverflow - 20 : anchor.top return (
{detector.name}
{/* График за последние 3 дня */}
График за 3 дня
) } // Полный режим боковой панели (основной режим) // Отображается как правая панель с полной информацией о детекторе return (
{/* Заголовок с названием детектора */}

{detector.name}

{/* Кнопки действий: Отчет и История */}
{/* Секция с детальной информацией о детекторе */} {/* График за последние 3 дня */}

График за последние 3 дня

{/* Кнопка закрытия панели */}
) } export default DetectorMenu