Разработка интерфейса фронт
This commit is contained in:
241
frontend/app/(protected)/navigation/page.tsx
Normal file
241
frontend/app/(protected)/navigation/page.tsx
Normal file
@@ -0,0 +1,241 @@
|
||||
'use client'
|
||||
|
||||
import React, { useEffect, useCallback } from 'react'
|
||||
import { useRouter, useSearchParams } from 'next/navigation'
|
||||
import Sidebar from '../../../components/ui/Sidebar'
|
||||
import useNavigationStore from '../../store/navigationStore'
|
||||
import Monitoring from '../../../components/navigation/Monitoring'
|
||||
import FloorNavigation from '../../../components/navigation/FloorNavigation'
|
||||
import DetectorMenu from '../../../components/navigation/DetectorMenu'
|
||||
import Notifications from '../../../components/notifications/Notifications'
|
||||
import NotificationDetectorInfo from '../../../components/notifications/NotificationDetectorInfo'
|
||||
import ModelViewer from '../../../components/model/ModelViewer'
|
||||
import detectorsData from '../../../data/detectors.json'
|
||||
|
||||
interface DetectorType {
|
||||
detector_id: number
|
||||
name: string
|
||||
object: string
|
||||
status: string
|
||||
checked: boolean
|
||||
type: string
|
||||
location: string
|
||||
floor: number
|
||||
notifications: Array<{
|
||||
id: number
|
||||
type: string
|
||||
message: string
|
||||
timestamp: string
|
||||
acknowledged: boolean
|
||||
priority: string
|
||||
}>
|
||||
}
|
||||
|
||||
interface NotificationType {
|
||||
id: number
|
||||
detector_id: number
|
||||
detector_name: string
|
||||
type: string
|
||||
status: string
|
||||
message: string
|
||||
timestamp: string
|
||||
location: string
|
||||
object: string
|
||||
acknowledged: boolean
|
||||
priority: string
|
||||
}
|
||||
|
||||
const NavigationPage: React.FC = () => {
|
||||
const router = useRouter()
|
||||
const searchParams = useSearchParams()
|
||||
const {
|
||||
currentObject,
|
||||
setCurrentObject,
|
||||
showMonitoring,
|
||||
showFloorNavigation,
|
||||
showNotifications,
|
||||
selectedDetector,
|
||||
showDetectorMenu,
|
||||
selectedNotification,
|
||||
showNotificationDetectorInfo,
|
||||
closeMonitoring,
|
||||
closeFloorNavigation,
|
||||
closeNotifications,
|
||||
setSelectedDetector,
|
||||
setShowDetectorMenu,
|
||||
setSelectedNotification,
|
||||
setShowNotificationDetectorInfo
|
||||
} = useNavigationStore()
|
||||
|
||||
const urlObjectId = searchParams.get('objectId')
|
||||
const urlObjectTitle = searchParams.get('objectTitle')
|
||||
const objectId = currentObject.id || urlObjectId
|
||||
const objectTitle = currentObject.title || urlObjectTitle
|
||||
|
||||
const handleModelLoaded = useCallback(() => {
|
||||
}, [])
|
||||
|
||||
const handleModelError = useCallback((error: string) => {
|
||||
console.error('Model loading error:', error)
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (urlObjectId && urlObjectTitle && (!currentObject.id || currentObject.id !== urlObjectId)) {
|
||||
setCurrentObject(urlObjectId, urlObjectTitle)
|
||||
}
|
||||
}, [urlObjectId, urlObjectTitle, currentObject.id, setCurrentObject])
|
||||
|
||||
const handleBackClick = () => {
|
||||
router.push('/dashboard')
|
||||
}
|
||||
|
||||
const handleDetectorMenuClick = (detector: DetectorType) => {
|
||||
if (selectedDetector?.detector_id === detector.detector_id && showDetectorMenu) {
|
||||
setShowDetectorMenu(false)
|
||||
setSelectedDetector(null)
|
||||
} else {
|
||||
setSelectedDetector(detector)
|
||||
setShowDetectorMenu(true)
|
||||
}
|
||||
}
|
||||
|
||||
const closeDetectorMenu = () => {
|
||||
setShowDetectorMenu(false)
|
||||
setSelectedDetector(null)
|
||||
}
|
||||
|
||||
const handleNotificationClick = (notification: NotificationType) => {
|
||||
if (selectedNotification?.id === notification.id && showNotificationDetectorInfo) {
|
||||
setShowNotificationDetectorInfo(false)
|
||||
setSelectedNotification(null)
|
||||
} else {
|
||||
setSelectedNotification(notification)
|
||||
setShowNotificationDetectorInfo(true)
|
||||
}
|
||||
}
|
||||
|
||||
const closeNotificationDetectorInfo = () => {
|
||||
setShowNotificationDetectorInfo(false)
|
||||
setSelectedNotification(null)
|
||||
}
|
||||
|
||||
const getStatusText = (status: string) => {
|
||||
switch (status) {
|
||||
case 'active': return 'Активен'
|
||||
case 'inactive': return 'Неактивен'
|
||||
case 'error': return 'Ошибка'
|
||||
case 'maintenance': return 'Обслуживание'
|
||||
default: return 'Неизвестно'
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex h-screen bg-[#0e111a]">
|
||||
<Sidebar
|
||||
activeItem={2}
|
||||
/>
|
||||
|
||||
<div className="flex-1 flex flex-col relative">
|
||||
|
||||
{showMonitoring && (
|
||||
<div className="absolute left-0 top-0 bg-[#161824] border-r border-gray-700 z-20 w-[500px]" style={{height: 'calc(100% - 73px)', top: '73px'}}>
|
||||
<div className="h-full overflow-auto p-4">
|
||||
<Monitoring
|
||||
objectId={objectId || undefined}
|
||||
onClose={closeMonitoring}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{showFloorNavigation && (
|
||||
<div className="absolute left-0 top-0 bg-[#161824] border-r border-gray-700 z-20 w-[500px]" style={{height: 'calc(100% - 73px)', top: '73px'}}>
|
||||
<div className="h-full overflow-auto p-4">
|
||||
<FloorNavigation
|
||||
objectId={objectId || undefined}
|
||||
detectorsData={detectorsData}
|
||||
onDetectorMenuClick={handleDetectorMenuClick}
|
||||
onClose={closeFloorNavigation}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{showNotifications && (
|
||||
<div className="absolute left-0 top-0 bg-[#161824] border-r border-gray-700 z-20 w-[500px]" style={{height: 'calc(100% - 73px)', top: '73px'}}>
|
||||
<div className="h-full overflow-auto p-4">
|
||||
<Notifications
|
||||
objectId={objectId || undefined}
|
||||
detectorsData={detectorsData}
|
||||
onNotificationClick={handleNotificationClick}
|
||||
onClose={closeNotifications}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{showNotifications && showNotificationDetectorInfo && selectedNotification && (() => {
|
||||
const detectorData = Object.values(detectorsData.detectors).find(
|
||||
detector => detector.detector_id === selectedNotification.detector_id
|
||||
);
|
||||
return detectorData ? (
|
||||
<div className="absolute left-[500px] top-0 bg-[#161824] border-r border-gray-700 z-30 w-[454px]" style={{height: 'calc(100% - 73px)', top: '73px'}}>
|
||||
<div className="h-full overflow-auto p-4">
|
||||
<NotificationDetectorInfo
|
||||
detectorData={detectorData}
|
||||
onClose={closeNotificationDetectorInfo}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
) : null;
|
||||
})()}
|
||||
|
||||
{showFloorNavigation && showDetectorMenu && selectedDetector && (
|
||||
<DetectorMenu
|
||||
detector={selectedDetector}
|
||||
isOpen={showDetectorMenu}
|
||||
onClose={closeDetectorMenu}
|
||||
getStatusText={getStatusText}
|
||||
/>
|
||||
)}
|
||||
|
||||
<header className="bg-[#161824] border-b border-gray-700 px-6 py-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-4">
|
||||
<button
|
||||
onClick={handleBackClick}
|
||||
className="text-gray-400 hover:text-white transition-colors"
|
||||
aria-label="Назад к дашборду"
|
||||
>
|
||||
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
|
||||
</svg>
|
||||
</button>
|
||||
<nav className="flex items-center gap-2 text-sm">
|
||||
<span className="text-gray-400">Дашборд</span>
|
||||
<span className="text-gray-600">/</span>
|
||||
<span className="text-white">{objectTitle || 'Объект'}</span>
|
||||
<span className="text-gray-600">/</span>
|
||||
<span className="text-white">Навигация</span>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div className="flex-1 overflow-hidden">
|
||||
<div className="h-full">
|
||||
<ModelViewer
|
||||
modelPath='/models/EXPO_АР_PostRecon_level.gltf'
|
||||
onModelLoaded={handleModelLoaded}
|
||||
onError={handleModelError}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default NavigationPage
|
||||
Reference in New Issue
Block a user