Files
aerbim-ht-monitor/frontend/components/navigation/Monitoring.tsx
2025-11-11 18:32:36 +03:00

160 lines
6.6 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 React, { useState, useEffect, useCallback } from 'react';
import Image from 'next/image';
interface MonitoringProps {
objectId?: string;
onClose?: () => void;
onSelectModel?: (modelPath: string) => void;
}
const Monitoring: React.FC<MonitoringProps> = ({ onClose, onSelectModel }) => {
const [objectImageError, setObjectImageError] = useState(false);
const [models, setModels] = useState<{ title: string; path: string }[]>([]);
const [loadError, setLoadError] = useState<string | null>(null);
const handleSelectModel = useCallback((modelPath: string) => {
console.log(`[NavigationPage] Model selected: ${modelPath}`);
onSelectModel?.(modelPath);
}, [onSelectModel]);
console.log('[Monitoring] Models:', models, 'Error:', loadError);
// Загружаем список доступных моделей из assets/big-models через API
useEffect(() => {
const fetchModels = async () => {
try {
setLoadError(null);
const res = await fetch('/api/big-models/list');
if (!res.ok) {
const text = await res.text();
throw new Error(text || 'Failed to fetch models list');
}
const data = await res.json();
const items: { name: string; path: string }[] = Array.isArray(data?.models) ? data.models : [];
// Приоритизируем указанную модель, чтобы она была первой карточкой
const preferred = 'AerBIM-Monitor_ASM-HT-Viewer_Expo2017Astana_20250910';
const formatted = items
.map((it) => ({ title: it.name, path: it.path }))
.sort((a, b) => {
const ap = a.path.includes(preferred) ? -1 : 0;
const bp = b.path.includes(preferred) ? -1 : 0;
if (ap !== bp) return ap - bp;
return a.title.localeCompare(b.title);
});
setModels(formatted);
} catch (error) {
console.error('[Monitoring] Error loading models list:', error);
setLoadError(error instanceof Error ? error.message : String(error));
setModels([]);
}
};
fetchModels();
}, []);
return (
<div className="w-full">
<div className="bg-[rgb(22,24,36)] rounded-[12px] p-4 space-y-4">
<div className="flex items-center justify-between">
<h2 className="text-white text-2xl font-semibold">Зоны мониторинга</h2>
{onClose && (
<button
onClick={onClose}
className="text-white hover:text-gray-300 transition-colors"
>
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
)}
</div>
{loadError && (
<div className="rounded-lg bg-red-600/20 border border-red-600/40 text-red-200 text-xs px-3 py-2">
Ошибка загрузки списка моделей: {loadError}
</div>
)}
{models.length > 0 && (
<>
{/* Большая панорамная карточка для приоритетной модели */}
{models[0] && (
<button
key={`${models[0].path}-panorama`}
type="button"
onClick={() => handleSelectModel(models[0].path)}
className="w-full bg-gray-300 rounded-lg h-[200px] flex items-center justify-center hover:bg-gray-400 transition-colors mb-4"
title={`Загрузить модель: ${models[0].title}`}
>
<div className="w-full h-full bg-gray-200 rounded flex flex-col items-center justify-center relative">
<Image
src="/images/test_image.png"
alt={models[0].title}
width={200}
height={200}
className="max-w-full max-h-full object-contain opacity-50"
style={{ height: 'auto' }}
onError={(e) => {
const target = e.target as HTMLImageElement;
target.style.display = 'none';
}}
/>
<div className="absolute bottom-2 left-2 right-2 text-sm text-gray-700 bg-white/80 rounded px-3 py-1 truncate">
{models[0].title}
</div>
</div>
</button>
)}
{/* Сетка маленьких карточек для остальных моделей */}
{models.length > 1 && (
<div className="grid grid-cols-2 gap-3">
{models.slice(1).map((model, idx) => (
<button
key={`${model.path}-${idx}`}
type="button"
onClick={() => handleSelectModel(model.path)}
className="relative flex-1 bg-gray-300 rounded-lg h-[120px] flex items-center justify-center hover:bg-gray-400 transition-colors"
title={`Загрузить модель: ${model.title}`}
>
<div className="w-full h-full bg-gray-200 rounded flex flex-col items-center justify-center relative">
<Image
src="/images/test_image.png"
alt={model.title}
width={120}
height={120}
className="max-w-full max-h-full object-contain opacity-50"
style={{ height: 'auto' }}
onError={(e) => {
const target = e.target as HTMLImageElement;
target.style.display = 'none';
}}
/>
<div className="absolute bottom-1 left-1 right-1 text-[10px] text-gray-700 bg-white/70 rounded px-2 py-0.5 truncate">
{model.title}
</div>
</div>
</button>
))}
</div>
)}
</>
)}
{models.length === 0 && (
<div className="col-span-2">
<div className="rounded-lg bg-gray-200 text-gray-700 text-xs px-3 py-2 border border-gray-300">
Список моделей пуст. Добавьте файлы в assets/big-models или проверьте API /api/big-models/list.
</div>
</div>
)}
</div>
</div>
);
};
export default Monitoring;