'use client' import React, { useState, useEffect } from 'react' import * as statusColors from '../../lib/statusColors' interface Detector { detector_id: number name: string location: string status: string object: string floor: number checked: boolean } interface RawDetector { detector_id: number name: string object: string status: string type: string detector_type: string location: string floor: number notifications: Array<{ id: number type: string message: string timestamp: string acknowledged: boolean priority: string }> } interface DetectorListProps { objectId?: string selectedDetectors: number[] onDetectorSelect: (detectorId: number, selected: boolean) => void initialSearchTerm?: string } // Функция для генерации умного диапазона страниц function getPaginationRange(currentPage: number, totalPages: number): (number | string)[] { if (totalPages <= 7) { // Если страниц мало - показываем все return Array.from({ length: totalPages }, (_, i) => i + 1) } // Всегда показываем первые 3 и последние 3 const start = [1, 2, 3] const end = [totalPages - 2, totalPages - 1, totalPages] if (currentPage <= 4) { // Начало: 1 2 3 4 5 ... 11 12 13 return [1, 2, 3, 4, 5, '...', ...end] } if (currentPage >= totalPages - 3) { // Конец: 1 2 3 ... 9 10 11 12 13 return [...start, '...', totalPages - 4, totalPages - 3, totalPages - 2, totalPages - 1, totalPages] } // Середина: 1 2 3 ... 6 7 8 ... 11 12 13 return [...start, '...', currentPage - 1, currentPage, currentPage + 1, '...', ...end] } const DetectorList: React.FC = ({ objectId, selectedDetectors, onDetectorSelect, initialSearchTerm = '' }) => { const [detectors, setDetectors] = useState([]) const [searchTerm, setSearchTerm] = useState(initialSearchTerm) const [currentPage, setCurrentPage] = useState(1) const itemsPerPage = 20 useEffect(() => { const loadDetectors = async () => { try { const res = await fetch('/api/get-detectors', { cache: 'no-store' }) if (!res.ok) return const payload = await res.json() const detectorsData: Record = payload?.data?.detectors ?? {} const rawArray: RawDetector[] = Object.values(detectorsData).filter( (detector) => (objectId ? detector.object === objectId : true) ) const normalized: Detector[] = rawArray.map((d) => ({ detector_id: d.detector_id, name: d.name, location: d.location, status: d.status, object: d.object, floor: d.floor, checked: false, })) console.log('[DetectorList] Payload:', payload) setDetectors(normalized) } catch (e) { console.error('Failed to load detectors:', e) } } loadDetectors() }, [objectId]) const filteredDetectors = detectors.filter(detector => { const matchesSearch = searchTerm === '' || detector.detector_id.toString() === searchTerm return matchesSearch }) // Сброс на первую страницу при изменении поиска useEffect(() => { setCurrentPage(1) }, [searchTerm]) // Пагинация const totalPages = Math.ceil(filteredDetectors.length / itemsPerPage) const startIndex = (currentPage - 1) * itemsPerPage const endIndex = startIndex + itemsPerPage const currentDetectors = filteredDetectors.slice(startIndex, endIndex) const paginationRange = getPaginationRange(currentPage, totalPages) const handlePageChange = (page: number) => { setCurrentPage(page) // Скролл наверх таблицы window.scrollTo({ top: 0, behavior: 'smooth' }) } return (
setSearchTerm(e.target.value)} className="bg-[#161824] text-white placeholder-gray-400 px-4 py-2 rounded-lg border border-gray-600 focus:border-blue-500 focus:outline-none w-64 text-sm font-medium" style={{ fontFamily: 'Inter, sans-serif' }} />
{/* Таблица детекторов */}
{currentDetectors.map((detector) => { const isSelected = selectedDetectors.includes(detector.detector_id) return ( ) })}
0} onChange={(e) => { if (e.target.checked) { currentDetectors.forEach(detector => { if (!selectedDetectors.includes(detector.detector_id)) { onDetectorSelect(detector.detector_id, true) } }) } else { currentDetectors.forEach(detector => { if (selectedDetectors.includes(detector.detector_id)) { onDetectorSelect(detector.detector_id, false) } }) } }} className="w-4 h-4 text-blue-600 bg-gray-700 border-gray-600 rounded focus:ring-blue-500 focus:ring-2" /> Детектор Статус Местоположение Проверен
onDetectorSelect(detector.detector_id, e.target.checked)} className="w-4 h-4 text-blue-600 bg-gray-700 border-gray-600 rounded focus:ring-blue-500 focus:ring-2" /> {detector.name}
{detector.status === statusColors.STATUS_COLOR_CRITICAL ? 'Критическое' : detector.status === statusColors.STATUS_COLOR_WARNING ? 'Предупреждение' : 'Норма'}
{detector.location} {detector.checked ? (
Да
) : ( Нет )}
{/* Пагинация */} {totalPages > 1 && (
{/* Кнопки пагинации */}
{/* Кнопка "Предыдущая" */} {/* Номера страниц */} {paginationRange.map((page, index) => { if (page === '...') { return ( ... ) } const pageNumber = page as number const isActive = pageNumber === currentPage return ( ) })} {/* Кнопка "Следующая" */}
{/* Счётчик */}
Показано {startIndex + 1}-{Math.min(endIndex, filteredDetectors.length)} из {filteredDetectors.length} датчиков
)}
{/* Статы детекторов */}
{filteredDetectors.length}
Всего
{filteredDetectors.filter(d => d.status === statusColors.STATUS_COLOR_NORMAL).length}
Норма
{filteredDetectors.filter(d => d.status === statusColors.STATUS_COLOR_WARNING).length}
Предупреждения
{filteredDetectors.filter(d => d.status === statusColors.STATUS_COLOR_CRITICAL).length}
Критические
{filteredDetectors.length === 0 && (

Детекторы не найдены

)}
) } export default DetectorList