Переделана навигация к датчикам, добавлена работа поиска тултипов на модели, добавлен функционал перехода из дашборда и истории тревог к датчику с тревогой на 3д модели
This commit is contained in:
@@ -38,10 +38,37 @@ interface DetectorListProps {
|
||||
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<DetectorListProps> = ({ objectId, selectedDetectors, onDetectorSelect, initialSearchTerm = '' }) => {
|
||||
const [detectors, setDetectors] = useState<Detector[]>([])
|
||||
const [searchTerm, setSearchTerm] = useState<string>(initialSearchTerm)
|
||||
const [currentPage, setCurrentPage] = useState(1)
|
||||
const itemsPerPage = 20
|
||||
|
||||
useEffect(() => {
|
||||
const loadDetectors = async () => {
|
||||
@@ -76,6 +103,24 @@ const DetectorList: React.FC<DetectorListProps> = ({ objectId, selectedDetectors
|
||||
|
||||
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 (
|
||||
<div className="space-y-6">
|
||||
@@ -109,16 +154,16 @@ const DetectorList: React.FC<DetectorListProps> = ({ objectId, selectedDetectors
|
||||
<th className="text-left text-white font-medium py-3 w-12">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={selectedDetectors.length === filteredDetectors.length && filteredDetectors.length > 0}
|
||||
checked={selectedDetectors.length === currentDetectors.length && currentDetectors.length > 0}
|
||||
onChange={(e) => {
|
||||
if (e.target.checked) {
|
||||
filteredDetectors.forEach(detector => {
|
||||
currentDetectors.forEach(detector => {
|
||||
if (!selectedDetectors.includes(detector.detector_id)) {
|
||||
onDetectorSelect(detector.detector_id, true)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
filteredDetectors.forEach(detector => {
|
||||
currentDetectors.forEach(detector => {
|
||||
if (selectedDetectors.includes(detector.detector_id)) {
|
||||
onDetectorSelect(detector.detector_id, false)
|
||||
}
|
||||
@@ -135,7 +180,7 @@ const DetectorList: React.FC<DetectorListProps> = ({ objectId, selectedDetectors
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{filteredDetectors.map((detector) => {
|
||||
{currentDetectors.map((detector) => {
|
||||
const isSelected = selectedDetectors.includes(detector.detector_id)
|
||||
|
||||
return (
|
||||
@@ -183,9 +228,76 @@ const DetectorList: React.FC<DetectorListProps> = ({ objectId, selectedDetectors
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{/* Пагинация */}
|
||||
{totalPages > 1 && (
|
||||
<div className="mt-6 flex flex-col items-center gap-4">
|
||||
{/* Кнопки пагинации */}
|
||||
<div className="flex items-center gap-2">
|
||||
{/* Кнопка "Предыдущая" */}
|
||||
<button
|
||||
onClick={() => handlePageChange(currentPage - 1)}
|
||||
disabled={currentPage === 1}
|
||||
className={`px-4 py-2 rounded-lg text-sm font-medium transition-colors ${
|
||||
currentPage === 1
|
||||
? 'text-gray-600 cursor-not-allowed'
|
||||
: 'text-gray-300 hover:text-white hover:bg-[#1E293B]'
|
||||
}`}
|
||||
>
|
||||
← Предыдущая
|
||||
</button>
|
||||
|
||||
{/* Номера страниц */}
|
||||
{paginationRange.map((page, index) => {
|
||||
if (page === '...') {
|
||||
return (
|
||||
<span key={`ellipsis-${index}`} className="px-3 py-2 text-gray-500">
|
||||
...
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
const pageNumber = page as number
|
||||
const isActive = pageNumber === currentPage
|
||||
|
||||
return (
|
||||
<button
|
||||
key={pageNumber}
|
||||
onClick={() => handlePageChange(pageNumber)}
|
||||
className={`min-w-[40px] px-3 py-2 rounded-lg text-sm font-medium transition-colors ${
|
||||
isActive
|
||||
? 'bg-blue-500 text-white'
|
||||
: 'text-gray-300 hover:text-white hover:bg-[#1E293B]'
|
||||
}`}
|
||||
>
|
||||
{pageNumber}
|
||||
</button>
|
||||
)
|
||||
})}
|
||||
|
||||
{/* Кнопка "Следующая" */}
|
||||
<button
|
||||
onClick={() => handlePageChange(currentPage + 1)}
|
||||
disabled={currentPage === totalPages}
|
||||
className={`px-4 py-2 rounded-lg text-sm font-medium transition-colors ${
|
||||
currentPage === totalPages
|
||||
? 'text-gray-600 cursor-not-allowed'
|
||||
: 'text-gray-300 hover:text-white hover:bg-[#1E293B]'
|
||||
}`}
|
||||
>
|
||||
Следующая →
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Счётчик */}
|
||||
<div className="text-sm text-gray-400">
|
||||
Показано {startIndex + 1}-{Math.min(endIndex, filteredDetectors.length)} из {filteredDetectors.length} датчиков
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Статы детекторров*/}
|
||||
{/* Статы детекторов */}
|
||||
<div className="mt-6 grid grid-cols-4 gap-4">
|
||||
<div className="bg-[#161824] p-4 rounded-lg">
|
||||
<div className="text-2xl font-bold text-white">{filteredDetectors.length}</div>
|
||||
|
||||
Reference in New Issue
Block a user