Files
aerbim-ht-monitor/frontend/app/store/navigationStore — копия 2.ts

380 lines
12 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { create } from 'zustand'
import { persist } from 'zustand/middleware'
import type { Zone } from '@/app/types'
export interface DetectorType {
detector_id: number
name: string
serial_number: string
object: string
status: string
type: string
detector_type: string
location: string
floor: number
checked: boolean
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
}
interface AlertType {
id: number
detector_id: number
detector_name: string
type: string
status: string
message: string
timestamp: string
location: string
object: string
acknowledged: boolean
priority: string
}
export interface NavigationStore {
currentObject: { id: string | undefined; title: string | undefined }
navigationHistory: string[]
currentSubmenu: string | null
currentModelPath: string | null
// Состояния Зон
currentZones: Zone[]
zonesCache: Record<string, Zone[]>
zonesLoading: boolean
zonesError: string | null
showMonitoring: boolean
showFloorNavigation: boolean
showNotifications: boolean
showListOfDetectors: boolean
showSensors: boolean
showSensorHighlights: boolean
selectedDetector: DetectorType | null
showDetectorMenu: boolean
selectedNotification: NotificationType | null
showNotificationDetectorInfo: boolean
selectedAlert: AlertType | null
showAlertMenu: boolean
setCurrentObject: (id: string | undefined, title: string | undefined) => void
clearCurrentObject: () => void
addToHistory: (path: string) => void
goBack: () => string | null
setCurrentModelPath: (path: string) => void
setCurrentSubmenu: (submenu: string | null) => void
clearSubmenu: () => void
// Действия с зонами
loadZones: (objectId: string) => Promise<void>
setZones: (zones: Zone[]) => void
clearZones: () => void
openMonitoring: () => void
closeMonitoring: () => void
openFloorNavigation: () => void
closeFloorNavigation: () => void
openNotifications: () => void
closeNotifications: () => void
openListOfDetectors: () => void
closeListOfDetectors: () => void
openSensors: () => void
closeSensors: () => void
toggleSensorHighlights: () => void
setSensorHighlights: (show: boolean) => void
closeAllMenus: () => void
clearSelections: () => void
setSelectedDetector: (detector: DetectorType | null) => void
setShowDetectorMenu: (show: boolean) => void
setSelectedNotification: (notification: NotificationType | null) => void
setShowNotificationDetectorInfo: (show: boolean) => void
setSelectedAlert: (alert: AlertType | null) => void
setShowAlertMenu: (show: boolean) => void
isOnNavigationPage: () => boolean
getCurrentRoute: () => string | null
getActiveSidebarItem: () => number
}
const useNavigationStore = create<NavigationStore>()(
persist(
(set, get) => ({
currentObject: {
id: undefined,
title: undefined,
},
navigationHistory: [],
currentSubmenu: null,
currentModelPath: null,
currentZones: [],
zonesCache: {},
zonesLoading: false,
zonesError: null,
showMonitoring: false,
showFloorNavigation: false,
showNotifications: false,
showListOfDetectors: false,
showSensors: false,
showSensorHighlights: true,
selectedDetector: null,
showDetectorMenu: false,
selectedNotification: null,
showNotificationDetectorInfo: false,
selectedAlert: null,
showAlertMenu: false,
setCurrentObject: (id: string | undefined, title: string | undefined) =>
set({ currentObject: { id, title } }),
clearCurrentObject: () =>
set({ currentObject: { id: undefined, title: undefined } }),
setCurrentModelPath: (path: string) => set({ currentModelPath: path }),
addToHistory: (path: string) => {
const { navigationHistory } = get()
const newHistory = [...navigationHistory, path]
if (newHistory.length > 10) {
newHistory.shift()
}
set({ navigationHistory: newHistory })
},
goBack: () => {
const { navigationHistory } = get()
if (navigationHistory.length > 1) {
const newHistory = [...navigationHistory]
newHistory.pop()
const previousPage = newHistory.pop()
set({ navigationHistory: newHistory })
return previousPage || null
}
return null
},
setCurrentSubmenu: (submenu: string | null) =>
set({ currentSubmenu: submenu }),
clearSubmenu: () =>
set({ currentSubmenu: null }),
loadZones: async (objectId: string) => {
const cache = get().zonesCache
const cached = cache[objectId]
const hasCached = Array.isArray(cached) && cached.length > 0
if (hasCached) {
// Показываем кэшированные зоны сразу, но обновляем в фоне
set({ currentZones: cached, zonesLoading: true, zonesError: null })
} else {
set({ zonesLoading: true, zonesError: null })
}
try {
const res = await fetch(`/api/get-zones?objectId=${encodeURIComponent(objectId)}`, { cache: 'no-store' })
const text = await res.text()
let payload: string | Record<string, unknown>
try { payload = JSON.parse(text) } catch { payload = text }
if (!res.ok) throw new Error(typeof payload === 'string' ? payload : (payload?.error as string || 'Не удалось получить зоны'))
const zones: Zone[] = typeof payload === 'string' ? [] :
Array.isArray(payload?.data) ? payload.data as Zone[] :
(payload?.data && typeof payload.data === 'object' && 'zones' in payload.data ? (payload.data as { zones?: Zone[] }).zones :
payload?.zones ? payload.zones as Zone[] : []) || []
const normalized = zones.map((z) => ({
...z,
image_path: z.image_path ?? null,
}))
set((state) => ({
currentZones: normalized,
zonesCache: { ...state.zonesCache, [objectId]: normalized },
zonesLoading: false,
zonesError: null,
}))
} catch (e: unknown) {
set({ zonesLoading: false, zonesError: (e as Error)?.message || 'Ошибка при загрузке зон' })
}
},
setZones: (zones: Zone[]) => set({ currentZones: zones }),
clearZones: () => set({ currentZones: [] }),
openMonitoring: () => {
set({
showMonitoring: true,
showFloorNavigation: false,
showNotifications: false,
showListOfDetectors: false,
currentSubmenu: 'monitoring',
showDetectorMenu: false,
selectedDetector: null,
showNotificationDetectorInfo: false,
selectedNotification: null,
zonesError: null // Очищаем ошибку зон при открытии мониторинга
})
const objId = get().currentObject.id
if (objId) {
// Вызываем загрузку зон сразу, но обновляем в фоне
get().loadZones(objId)
}
},
closeMonitoring: () => set({
showMonitoring: false,
currentSubmenu: null
}),
openFloorNavigation: () => set({
showFloorNavigation: true,
showMonitoring: false,
showNotifications: false,
showListOfDetectors: false,
currentSubmenu: 'floors',
showNotificationDetectorInfo: false,
selectedNotification: null
}),
closeFloorNavigation: () => set({
showFloorNavigation: false,
showDetectorMenu: false,
selectedDetector: null,
currentSubmenu: null
}),
openNotifications: () => set({
showNotifications: true,
showMonitoring: false,
showFloorNavigation: false,
showListOfDetectors: false,
currentSubmenu: 'notifications',
showDetectorMenu: false,
selectedDetector: null
}),
closeNotifications: () => set({
showNotifications: false,
showNotificationDetectorInfo: false,
selectedNotification: null,
currentSubmenu: null
}),
openListOfDetectors: () => set({
showListOfDetectors: true,
showMonitoring: false,
showFloorNavigation: false,
showNotifications: false,
currentSubmenu: 'detectors',
showDetectorMenu: false,
selectedDetector: null,
showNotificationDetectorInfo: false,
selectedNotification: null
}),
closeListOfDetectors: () => set({
showListOfDetectors: false,
showDetectorMenu: false,
selectedDetector: null,
currentSubmenu: null
}),
openSensors: () => set({
showSensors: true,
showMonitoring: false,
showFloorNavigation: false,
showNotifications: false,
showListOfDetectors: false,
currentSubmenu: 'sensors',
showDetectorMenu: false,
selectedDetector: null,
showNotificationDetectorInfo: false,
selectedNotification: null
}),
closeSensors: () => set({
showSensors: false,
showDetectorMenu: false,
selectedDetector: null,
currentSubmenu: null
}),
toggleSensorHighlights: () => set((state) => ({ showSensorHighlights: !state.showSensorHighlights })),
setSensorHighlights: (show: boolean) => set({ showSensorHighlights: show }),
closeAllMenus: () => {
set({
showMonitoring: false,
showFloorNavigation: false,
showNotifications: false,
showListOfDetectors: false,
showSensors: false,
currentSubmenu: null,
});
get().clearSelections();
},
clearSelections: () => set({
selectedDetector: null,
showDetectorMenu: false,
selectedAlert: null,
showAlertMenu: false,
}),
setSelectedDetector: (detector: DetectorType | null) => set({ selectedDetector: detector }),
setShowDetectorMenu: (show: boolean) => set({ showDetectorMenu: show }),
setSelectedNotification: (notification: NotificationType | null) => set({ selectedNotification: notification }),
setShowNotificationDetectorInfo: (show: boolean) => set({ showNotificationDetectorInfo: show }),
setSelectedAlert: (alert: AlertType | null) => set({ selectedAlert: alert }),
setShowAlertMenu: (show: boolean) => set({ showAlertMenu: show }),
isOnNavigationPage: () => {
const { navigationHistory } = get()
const currentRoute = navigationHistory[navigationHistory.length - 1]
return currentRoute === '/navigation'
},
getCurrentRoute: () => {
const { navigationHistory } = get()
return navigationHistory[navigationHistory.length - 1] || null
},
getActiveSidebarItem: () => {
const { showMonitoring, showFloorNavigation, showNotifications, showListOfDetectors, showSensors } = get()
if (showMonitoring) return 3 // Зоны Мониторинга
if (showFloorNavigation) return 4 // Навигация по этажам
if (showNotifications) return 5 // Уведомления
if (showListOfDetectors) return 7 // Список датчиков
if (showSensors) return 8 // Сенсоры
return 2 // Навигация (базовая)
}
}),
{
name: 'navigation-store',
}
)
)
export default useNavigationStore