2D-карта (станции, заявки) и вкладка «Заявки»
Новая вкладка «Заявки»: показ заявок за интервал на 2D-карте, создание заявки рисованием полигона на карте с формой параметров (Оптика/РСА) и удаление выбранной заявки (createRequest/deleteRequest, RequestCreatePanel/RequestDetailsPanel, polygonToWkt). В Tgu2DMapView добавлен изолированный режим рисования полигона. 2D-карта: панели информации о станции и о заявках, слой станций (stationsApi), поддержка выбора объектов через спатиальный индекс. Список слоёв упрощён — трасса/полоса/маркеры КА убраны из переключателя, по умолчанию включены работы плана, станции и заявки.
This commit is contained in:
@@ -1,13 +1,17 @@
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { fetchRequestsForMap } from "../../api/requestApi";
|
||||
import { fetchStations, type StationDto } from "../../api/stationsApi";
|
||||
import type { RequestMapItem } from "../../model/requestTypes";
|
||||
import type { TguPlanUi, TguPlatformUi, TimelineRange } from "../../model/timelineTypes";
|
||||
import { platformLabel } from "../tgu-planning/tguTimelineMapper";
|
||||
import { DEFAULT_TGU_2D_MAP_LAYERS, type Tgu2DMapLayerKey, type Tgu2DMapLayersState } from "./model/mapLayerTypes";
|
||||
import type { Tgu2DMapSelection } from "./model/mapSelectionTypes";
|
||||
import type { MapPolygon } from "./model/mapTypes";
|
||||
import { buildTgu2DMapScene, getLayerAvailability } from "./Tgu2DMapLayers";
|
||||
import { Tgu2DMapDetails } from "./Tgu2DMapDetails";
|
||||
import { Tgu2DMapRequestsPanel, type RequestAtPoint } from "./Tgu2DMapRequestsPanel";
|
||||
import { Tgu2DMapSidebar } from "./Tgu2DMapSidebar";
|
||||
import { Tgu2DMapStationPanel } from "./Tgu2DMapStationPanel";
|
||||
import { Tgu2DMapToolbar } from "./Tgu2DMapToolbar";
|
||||
import { Tgu2DMapView } from "./Tgu2DMapView";
|
||||
import { getTgu2DMapIntervalState, TGU_2D_MAP_INTERVAL_WARNING } from "./tgu2DMapInterval";
|
||||
@@ -56,6 +60,18 @@ export function Tgu2DMapTab({
|
||||
const [selectedObject, setSelectedObject] = useState<Tgu2DMapSelection>();
|
||||
const [hiddenIds, setHiddenIds] = useState<ReadonlySet<string>>(new Set());
|
||||
const [requestsState, setRequestsState] = useState<RequestsState>(() => buildInitialRequestsState(range));
|
||||
const [stations, setStations] = useState<StationDto[]>([]);
|
||||
const [stationsFetchFailed, setStationsFetchFailed] = useState(false);
|
||||
const [requestsAtPoint, setRequestsAtPoint] = useState<RequestAtPoint[]>([]);
|
||||
const [selectedRequestPolygonId, setSelectedRequestPolygonId] = useState<string | undefined>();
|
||||
const [hoveredRequestPolygonId, setHoveredRequestPolygonId] = useState<string | undefined>();
|
||||
const [stationPanel, setStationPanel] = useState<(Tgu2DMapSelection & { type: "marker"; layer: "stations" }) | undefined>();
|
||||
|
||||
useEffect(() => {
|
||||
fetchStations()
|
||||
.then((items) => { setStations(items); setStationsFetchFailed(false); })
|
||||
.catch(() => setStationsFetchFailed(true));
|
||||
}, []);
|
||||
|
||||
const mapInterval = getTgu2DMapIntervalState(range, selectedPlan);
|
||||
const mapInvalidRange = invalidRange || mapInterval.tooLarge;
|
||||
@@ -146,11 +162,15 @@ export function Tgu2DMapTab({
|
||||
selectedPlan,
|
||||
platforms,
|
||||
hiddenSpacecraftIds: hiddenIds,
|
||||
requestItems: layers.requests ? requestsState.items : []
|
||||
requestItems: layers.requests ? requestsState.items : [],
|
||||
stationItems: layers.stations ? stations : []
|
||||
}),
|
||||
[mapInterval.range, platforms, selectedPlan, hiddenIds, requestsState.items, layers.requests]
|
||||
[mapInterval.range, platforms, selectedPlan, hiddenIds, requestsState.items, layers.requests, stations, layers.stations]
|
||||
);
|
||||
const layerAvailability = useMemo(
|
||||
() => getLayerAvailability(layers, scene, stationsFetchFailed),
|
||||
[layers, scene, stationsFetchFailed]
|
||||
);
|
||||
const layerAvailability = useMemo(() => getLayerAvailability(layers, scene), [layers, scene]);
|
||||
|
||||
const overlayMessage = invalidRange
|
||||
? "Некорректный интервал: from должен быть меньше to."
|
||||
@@ -162,6 +182,49 @@ export function Tgu2DMapTab({
|
||||
setLayers((current) => ({ ...current, [key]: !current[key] }));
|
||||
};
|
||||
|
||||
const handleObjectSelect = useCallback((selection?: Tgu2DMapSelection) => {
|
||||
if (selection?.type === "marker" && selection.layer === "stations") {
|
||||
setStationPanel(selection as Tgu2DMapSelection & { type: "marker"; layer: "stations" });
|
||||
setRequestsAtPoint([]);
|
||||
setSelectedRequestPolygonId(undefined);
|
||||
setHoveredRequestPolygonId(undefined);
|
||||
setSelectedObject(undefined);
|
||||
} else {
|
||||
setStationPanel(undefined);
|
||||
setSelectedObject(selection);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleRequestsAtPoint = useCallback(
|
||||
(polygons: MapPolygon[]) => {
|
||||
if (polygons.length === 0) {
|
||||
setRequestsAtPoint([]);
|
||||
setSelectedRequestPolygonId(undefined);
|
||||
setHoveredRequestPolygonId(undefined);
|
||||
return;
|
||||
}
|
||||
const joined = polygons.flatMap((polygon) => {
|
||||
const item = requestsState.items.find((r) => r.id === polygon.requestId);
|
||||
return item ? [{ polygon, item }] : [];
|
||||
});
|
||||
setRequestsAtPoint(joined);
|
||||
setSelectedRequestPolygonId(undefined);
|
||||
setHoveredRequestPolygonId(undefined);
|
||||
setStationPanel(undefined);
|
||||
},
|
||||
[requestsState.items]
|
||||
);
|
||||
|
||||
const closeRequestsPanel = useCallback(() => {
|
||||
setRequestsAtPoint([]);
|
||||
setSelectedRequestPolygonId(undefined);
|
||||
setHoveredRequestPolygonId(undefined);
|
||||
}, []);
|
||||
|
||||
const closeStationPanel = useCallback(() => {
|
||||
setStationPanel(undefined);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<main className="tgu-map-workspace">
|
||||
<Tgu2DMapToolbar
|
||||
@@ -172,7 +235,7 @@ export function Tgu2DMapTab({
|
||||
onToggleLayer={toggleLayer}
|
||||
/>
|
||||
|
||||
<div className="tgu-map-content">
|
||||
<div className={`tgu-map-content${(requestsAtPoint.length > 0 || stationPanel != null) ? " has-requests-panel" : ""}`}>
|
||||
<Tgu2DMapSidebar
|
||||
platforms={platforms}
|
||||
selectedPlanId={selectedPlan?.planId}
|
||||
@@ -196,9 +259,24 @@ export function Tgu2DMapTab({
|
||||
scene={mapInvalidRange ? { polygons: [], lines: [], markers: [] } : scene}
|
||||
layers={layers}
|
||||
redrawToken={redrawToken}
|
||||
onObjectSelect={setSelectedObject}
|
||||
onObjectSelect={handleObjectSelect}
|
||||
onRequestsAtPoint={handleRequestsAtPoint}
|
||||
hoveredRequestPolygonId={hoveredRequestPolygonId}
|
||||
selectedRequestPolygonId={selectedRequestPolygonId}
|
||||
/>
|
||||
</section>
|
||||
{requestsAtPoint.length > 0 && (
|
||||
<Tgu2DMapRequestsPanel
|
||||
requests={requestsAtPoint}
|
||||
selectedPolygonId={selectedRequestPolygonId}
|
||||
onHover={setHoveredRequestPolygonId}
|
||||
onSelect={setSelectedRequestPolygonId}
|
||||
onClose={closeRequestsPanel}
|
||||
/>
|
||||
)}
|
||||
{stationPanel != null && (
|
||||
<Tgu2DMapStationPanel selection={stationPanel} onClose={closeStationPanel} />
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="tgu-map-errors">
|
||||
|
||||
Reference in New Issue
Block a user