feat(tgu-ops-ui): display request polygons on 2D map
Добавлен слой заявок (КНС) на 2D карту ТГУ: - requestApi.ts — загрузка заявок постранично через GET /v1/requests/map с прогресс-коллбэком; автоматически собирает все страницы - wktParser.ts — парсинг WKT POLYGON/MULTIPOLYGON в массив координат - drawRequests.ts — Canvas-рендеринг полигонов заявок - Tgu2DMapLayers.ts — buildTgu2DMapScene строит MapPolygon[] из RequestMapItem[] - Tgu2DMapTab.tsx — состояние requestsState, кнопка «Загрузить», фильтры по дате - Tgu2DMapSidebar.tsx — панель слоя заявок: счётчик, ошибки, truncated-предупреждение - requestTypes.ts — RequestMapItem, RequestMapPage модели - Поддержка выбора заявки на карте (mapSelectionTypes, mapTypes) - nginx.conf, vite.config.ts — проксирование /v1 на pcp-request-service в dev Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
import type { RequestFilter, RequestMapItem } from "../model/requestTypes";
|
||||
|
||||
const BASE = "/api/pcp-request/v1";
|
||||
const PAGE_SIZE = 500;
|
||||
const MAX_PAGES = 10; // up to 5000 requests
|
||||
|
||||
type WithGeometryPage = {
|
||||
items: RequestMapItem[];
|
||||
page: number;
|
||||
size: number;
|
||||
totalItems: number;
|
||||
totalPages: number;
|
||||
};
|
||||
|
||||
async function fetchWithGeometryPage(filter: RequestFilter, page: number): Promise<WithGeometryPage> {
|
||||
const params = new URLSearchParams();
|
||||
if (filter.beginFrom) params.set("beginFrom", filter.beginFrom);
|
||||
if (filter.beginTo) params.set("beginTo", filter.beginTo);
|
||||
if (filter.endFrom) params.set("endFrom", filter.endFrom);
|
||||
if (filter.endTo) params.set("endTo", filter.endTo);
|
||||
if (filter.status) params.set("status", filter.status);
|
||||
if (filter.surveyType) params.set("surveyType", filter.surveyType);
|
||||
params.set("size", String(PAGE_SIZE));
|
||||
params.set("page", String(page));
|
||||
params.set("sort", "beginDateTime,asc");
|
||||
|
||||
const response = await fetch(`${BASE}/requests/map?${params}`, {
|
||||
headers: { Accept: "application/json" }
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Ошибка загрузки заявок: ${response.status}`);
|
||||
}
|
||||
|
||||
return response.json() as Promise<WithGeometryPage>;
|
||||
}
|
||||
|
||||
export async function fetchRequestsForMap(
|
||||
filter: RequestFilter,
|
||||
onProgress?: (loaded: number, total: number) => void
|
||||
): Promise<{ items: RequestMapItem[]; totalItems: number; truncated: boolean }> {
|
||||
const first = await fetchWithGeometryPage(filter, 0);
|
||||
onProgress?.(first.items.length, first.totalItems);
|
||||
|
||||
if (first.totalPages <= 1) {
|
||||
return { items: first.items, totalItems: first.totalItems, truncated: false };
|
||||
}
|
||||
|
||||
const pagesToLoad = Math.min(first.totalPages, MAX_PAGES) - 1;
|
||||
const remaining = await Promise.all(
|
||||
Array.from({ length: pagesToLoad }, (_, i) => fetchWithGeometryPage(filter, i + 1))
|
||||
);
|
||||
|
||||
const allItems = [...first.items, ...remaining.flatMap((page) => page.items)];
|
||||
onProgress?.(allItems.length, first.totalItems);
|
||||
|
||||
return {
|
||||
items: allItems,
|
||||
totalItems: first.totalItems,
|
||||
truncated: first.totalPages > MAX_PAGES
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user