refactor(tgu-ui): единый инспектор объектов карты (MapObjectInspector) на вкладках «Карта» и «Комплексный план»
Обобщил ComplexInfoPanel в общий MapObjectInspector (tgu-map-2d): карточки для всех типов объектов — заявка, включение комплексного плана, ячейка тепловой карты, маршрут planWorks, станция, маркер КА, линия; список с раскрытием при наложении. Вкладка «Карта» переведена на enableObjectChooser + onObjectsAtPoint + правый инспектор — заменила разрозненные Tgu2DMapRequestsPanel/Tgu2DMapStationPanel (удалены) и объектную часть нижней плашки (Tgu2DMapDetails ужат до контекста плана). Вкладка «Комплексный план» использует тот же инспектор. RequestAtPoint переехал в tgu-requests/RequestDetailsPanel (нужен вкладке «Заявки»).
This commit is contained in:
@@ -6,12 +6,10 @@ import type { TguPlanUi, TguPlatformUi, TimelineRange } from "../../model/timeli
|
||||
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 { MapObjectInspector } from "./MapObjectInspector";
|
||||
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";
|
||||
@@ -58,15 +56,13 @@ export function Tgu2DMapTab({
|
||||
const [layers, setLayers] = useState<Tgu2DMapLayersState>(DEFAULT_TGU_2D_MAP_LAYERS);
|
||||
const [search, setSearch] = useState("");
|
||||
const [redrawToken, setRedrawToken] = useState(0);
|
||||
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>();
|
||||
// Инспектор объекта карты справа (единый для всех вкладок): объекты под кликом и раскрытый.
|
||||
const [mapHits, setMapHits] = useState<Tgu2DMapSelection[]>([]);
|
||||
const [activeHitId, setActiveHitId] = useState<string>();
|
||||
|
||||
useEffect(() => {
|
||||
fetchStations()
|
||||
@@ -183,47 +179,24 @@ export function Tgu2DMapTab({
|
||||
setLayers((current) => ({ ...current, [key]: !current[key] }));
|
||||
};
|
||||
|
||||
// Клик по карте: 0/1 объект — карточка сразу; ≥2 (наложение) — список под точкой клика.
|
||||
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);
|
||||
}
|
||||
setMapHits(selection ? [selection] : []);
|
||||
setActiveHitId(selection?.id);
|
||||
}, []);
|
||||
|
||||
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 handleObjectsAtPoint = useCallback((selections: Tgu2DMapSelection[]) => {
|
||||
setMapHits(selections);
|
||||
setActiveHitId(selections[0]?.id);
|
||||
}, []);
|
||||
|
||||
const closeStationPanel = useCallback(() => {
|
||||
setStationPanel(undefined);
|
||||
const toggleHit = useCallback((selection: Tgu2DMapSelection) => {
|
||||
setActiveHitId((current) => (current === selection.id ? undefined : selection.id));
|
||||
}, []);
|
||||
|
||||
const closeInfoPanel = useCallback(() => {
|
||||
setMapHits([]);
|
||||
setActiveHitId(undefined);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
@@ -236,7 +209,7 @@ export function Tgu2DMapTab({
|
||||
onToggleLayer={toggleLayer}
|
||||
/>
|
||||
|
||||
<div className={`tgu-map-content${(requestsAtPoint.length > 0 || stationPanel != null) ? " has-requests-panel" : ""}`}>
|
||||
<div className={`tgu-map-content${mapHits.length > 0 ? " has-side-panel" : ""}`}>
|
||||
<Tgu2DMapSidebar
|
||||
platforms={platforms}
|
||||
selectedPlanId={selectedPlan?.planId}
|
||||
@@ -260,23 +233,22 @@ export function Tgu2DMapTab({
|
||||
scene={mapInvalidRange ? { polygons: [], lines: [], markers: [] } : scene}
|
||||
layers={layers}
|
||||
redrawToken={redrawToken}
|
||||
enableObjectChooser
|
||||
onObjectsAtPoint={handleObjectsAtPoint}
|
||||
onObjectSelect={handleObjectSelect}
|
||||
onRequestsAtPoint={handleRequestsAtPoint}
|
||||
hoveredRequestPolygonId={hoveredRequestPolygonId}
|
||||
selectedRequestPolygonId={selectedRequestPolygonId}
|
||||
selectedObjectId={activeHitId}
|
||||
/>
|
||||
</section>
|
||||
{requestsAtPoint.length > 0 && (
|
||||
<Tgu2DMapRequestsPanel
|
||||
requests={requestsAtPoint}
|
||||
selectedPolygonId={selectedRequestPolygonId}
|
||||
onHover={setHoveredRequestPolygonId}
|
||||
onSelect={setSelectedRequestPolygonId}
|
||||
onClose={closeRequestsPanel}
|
||||
/>
|
||||
)}
|
||||
{stationPanel != null && (
|
||||
<Tgu2DMapStationPanel selection={stationPanel} onClose={closeStationPanel} />
|
||||
{mapHits.length > 0 && (
|
||||
<aside className="tgu-editor-side-panel">
|
||||
<MapObjectInspector
|
||||
hits={mapHits}
|
||||
activeId={activeHitId}
|
||||
onToggle={toggleHit}
|
||||
onClose={closeInfoPanel}
|
||||
requestItems={requestsState.items}
|
||||
/>
|
||||
</aside>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -290,7 +262,7 @@ export function Tgu2DMapTab({
|
||||
)}
|
||||
</div>
|
||||
|
||||
<Tgu2DMapDetails selectedPlan={selectedPlan} selectedObject={selectedObject} />
|
||||
<Tgu2DMapDetails selectedPlan={selectedPlan} />
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user