BUR-58 добавлен видео-блок

This commit is contained in:
Первов Артем
2026-07-05 06:55:17 +03:00
parent 743e3c52b7
commit 6dac1ed2bd
13 changed files with 291 additions and 2 deletions

View File

@@ -0,0 +1,27 @@
import { useMemo } from 'react';
import { useQuery } from '@tanstack/react-query';
import { useParams } from 'react-router-dom';
import { getCameras } from '../../entities/camera/api';
import { EdgePageLayout } from './components/EdgePageLayout';
import { VideoView } from './components/VideoView';
export function EdgeVideoPage() {
const { edgeId = '' } = useParams();
const cameras = useQuery({
queryKey: ['camera', edgeId],
queryFn: () => getCameras(edgeId),
enabled: Boolean(edgeId),
});
const cameraItems = useMemo(() => cameras.data?.items ?? [], [cameras.data?.items]);
return (
<EdgePageLayout
currentEventsConnected={false}
edgeId={edgeId}
view="video"
onRefresh={() => void cameras.refetch()}
>
<VideoView cameras={cameraItems} loading={cameras.isPending} isError={cameras.isError} error={cameras.error} />
</EdgePageLayout>
);
}

View File

@@ -1,4 +1,4 @@
import { Activity, BarChart3, Gauge, Menu, PanelLeftClose, PanelLeftOpen } from 'lucide-react';
import { Activity, BarChart3, Gauge, Menu, PanelLeftClose, PanelLeftOpen, Video } from 'lucide-react';
import type { DetailView } from '../types';
type EdgeSidebarProps = {
@@ -56,6 +56,14 @@ export function EdgeSidebar({ collapsed, edgePath, view, onNavigate, onToggleCol
<Activity size={18} />
<span className="nav-label">Показатели</span>
</button>
<button
className={`nav-item nav-item--button ${view === 'video' ? 'nav-item--active' : ''}`}
type="button"
onClick={() => onNavigate(`${edgePath}/video`)}
>
<Video size={18} />
<span className="nav-label">Видео</span>
</button>
</nav>
</aside>
);

View File

@@ -0,0 +1,46 @@
import { Video } from 'lucide-react';
import { CameraView } from '../../../components/CameraView';
import { CameraViewsContainer } from '../../../components/CameraViewsContainer';
import type { CameraItem } from '../../../entities/camera/types';
type VideoViewProps = {
cameras: CameraItem[];
error: unknown;
isError: boolean;
loading: boolean;
};
function createWsUrl(camera: CameraItem): string {
const protocol = camera.protocol.replace(/:\/?\/?$/, '');
const source = camera.source.replace(/^\/\//, '');
return `${protocol}://${source}`;
}
export function VideoView({ cameras, error, isError, loading }: VideoViewProps) {
return (
<section className="video-section">
<div className="section-header">
<div>
<span className="page-kicker">
<Video size={14} />
Видео
</span>
<h2>Видеопотоки буровой</h2>
</div>
</div>
{loading ? <div className="empty-panel">Загрузка камер...</div> : null}
{isError ? <div className="empty-panel">Не удалось загрузить камеры: {String(error)}</div> : null}
{!loading && !isError && cameras.length === 0 ? <div className="empty-panel">Камеры для этой буровой не настроены</div> : null}
{!loading && !isError && cameras.length > 0 ? (
<CameraViewsContainer>
{cameras.map((camera, index) => {
const wsUrl = createWsUrl(camera);
return <CameraView key={`${camera.protocol}:${camera.source}`} title={`Камера ${index + 1}`} wsUrl={wsUrl} />;
})}
</CameraViewsContainer>
) : null}
</section>
);
}

View File

@@ -1 +1 @@
export type DetailView = 'overview' | 'archive' | 'indicators';
export type DetailView = 'overview' | 'archive' | 'indicators' | 'video';