197 lines
5.7 KiB
TypeScript
197 lines
5.7 KiB
TypeScript
/* =============================================================================
|
|
* B04_wf1_Surface_Api_Fetch.ts
|
|
* 1차 워크플로우(지표면 분석) API 클라이언트
|
|
*
|
|
* 백엔드 계약 (B04_wf1_Surface_Router.py):
|
|
* POST /api/projects/{project_id}/surface/analyze → 분석 실행 + DB 기록
|
|
* GET /api/projects/{project_id}/surface/models → 모델 목록 조회
|
|
*
|
|
* 규칙:
|
|
* - 모든 제어 상수는 config_frontend에서 참조 (하드코딩 금지).
|
|
* - 오류 응답 형식 {status:"error", message:"..."}을 Error로 변환.
|
|
* ========================================================================== */
|
|
|
|
import { API_BASE_URL, API_TIMEOUT_MS } from "@config/config_frontend";
|
|
|
|
/** 지표면 분석 실행 요청 (SurfaceAnalyzeRequest) */
|
|
export interface SurfaceAnalyzeRequest {
|
|
input_file_id: number;
|
|
source_filters?: string[];
|
|
methods?: string[];
|
|
force?: boolean;
|
|
}
|
|
|
|
/** 지표면 분석 실행 결과 (SurfaceAnalyzeResponse) */
|
|
export interface SurfaceAnalyzeResponse {
|
|
status: string;
|
|
project_id: string;
|
|
ground_summary: Record<string, unknown>;
|
|
manifest_status: string;
|
|
surface_model_ids: number[];
|
|
}
|
|
|
|
/** 저장된 지표면 모델 요약 (SurfaceModelSummary) */
|
|
export interface SurfaceModelSummary {
|
|
id: number;
|
|
model_type: string;
|
|
status: string;
|
|
resolution_m: number | null;
|
|
model_file_path: string | null;
|
|
created_at: string | null;
|
|
}
|
|
|
|
export interface SurfaceInputFileSummary {
|
|
id: number;
|
|
file_type: string;
|
|
original_filename: string;
|
|
raw_file_path: string;
|
|
file_size_mb: number | null;
|
|
crs_epsg: number | null;
|
|
status: string | null;
|
|
created_at: string | null;
|
|
}
|
|
|
|
export interface SurfaceInputFileListResponse {
|
|
status: string;
|
|
project_id: string;
|
|
files: SurfaceInputFileSummary[];
|
|
}
|
|
|
|
export interface SurfacePointCloudSampleResponse {
|
|
status: string;
|
|
project_id: string;
|
|
point_count: number;
|
|
sampled_count: number;
|
|
bounds: Record<string, number>;
|
|
points: [number, number, number][];
|
|
rgb?: [number, number, number][];
|
|
}
|
|
|
|
export interface SurfaceGroundStatsResponse {
|
|
status: string;
|
|
project_id: string;
|
|
filters: Record<string, Record<string, unknown>>;
|
|
}
|
|
|
|
export interface SurfaceStatusResponse {
|
|
project_id: string;
|
|
status: "pending" | "in_progress" | "completed" | "failed";
|
|
model_count: number;
|
|
progress_percent: number;
|
|
current_stage: string;
|
|
message: string;
|
|
}
|
|
|
|
/** 지표면 모델 목록 응답 (SurfaceModelListResponse) */
|
|
export interface SurfaceModelListResponse {
|
|
status: string;
|
|
project_id: string;
|
|
models: SurfaceModelSummary[];
|
|
}
|
|
|
|
/** 공통 fetch 헬퍼: 타임아웃 + 인증 헤더 + 오류 응답 변환. */
|
|
async function requestJson<T>(path: string, init: RequestInit): Promise<T> {
|
|
const controller = new AbortController();
|
|
const timeoutId = window.setTimeout(() => controller.abort(), API_TIMEOUT_MS);
|
|
try {
|
|
const response = await fetch(`${API_BASE_URL}${path}`, {
|
|
...init,
|
|
credentials: "include",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
...(init.headers ?? {}),
|
|
},
|
|
signal: controller.signal,
|
|
});
|
|
const payload = (await response.json()) as T & { message?: string };
|
|
if (!response.ok) {
|
|
throw new Error(payload.message ?? `HTTP ${response.status}`);
|
|
}
|
|
return payload;
|
|
} finally {
|
|
window.clearTimeout(timeoutId);
|
|
}
|
|
}
|
|
|
|
/** 지표면 분석을 실행한다 (LAS 구조화 → 지면 필터 → 지표면 모델 생성). */
|
|
export async function analyzeSurface(
|
|
projectId: string,
|
|
request: SurfaceAnalyzeRequest,
|
|
): Promise<SurfaceAnalyzeResponse> {
|
|
return requestJson<SurfaceAnalyzeResponse>(`/projects/${projectId}/surface/analyze`, {
|
|
method: "POST",
|
|
body: JSON.stringify(request),
|
|
});
|
|
}
|
|
|
|
/** 프로젝트의 지표면 모델 목록을 조회한다. */
|
|
export async function listSurfaceModels(projectId: string): Promise<SurfaceModelListResponse> {
|
|
return requestJson<SurfaceModelListResponse>(`/projects/${projectId}/surface/models`, {
|
|
method: "GET",
|
|
});
|
|
}
|
|
|
|
export async function listSurfaceInputFiles(
|
|
projectId: string,
|
|
): Promise<SurfaceInputFileListResponse> {
|
|
return requestJson<SurfaceInputFileListResponse>(`/projects/${projectId}/surface/input-files`, {
|
|
method: "GET",
|
|
});
|
|
}
|
|
|
|
export async function fetchSurfacePointCloud(
|
|
projectId: string,
|
|
): Promise<SurfacePointCloudSampleResponse> {
|
|
return requestJson<SurfacePointCloudSampleResponse>(
|
|
`/projects/${projectId}/surface/point-cloud`,
|
|
{
|
|
method: "GET",
|
|
},
|
|
);
|
|
}
|
|
|
|
export async function fetchSurfaceGroundStats(
|
|
projectId: string,
|
|
): Promise<SurfaceGroundStatsResponse> {
|
|
return requestJson<SurfaceGroundStatsResponse>(`/projects/${projectId}/surface/ground-stats`, {
|
|
method: "GET",
|
|
});
|
|
}
|
|
|
|
export async function fetchSurfaceStatus(projectId: string): Promise<SurfaceStatusResponse> {
|
|
return requestJson<SurfaceStatusResponse>(`/projects/${projectId}/surface/status`, {
|
|
method: "GET",
|
|
});
|
|
}
|
|
|
|
export interface VWorldMeta {
|
|
x_min: number;
|
|
x_max: number;
|
|
y_min: number;
|
|
y_max: number;
|
|
width_meters: number;
|
|
height_meters: number;
|
|
center_x: number;
|
|
center_y: number;
|
|
lon_min: number;
|
|
lon_max: number;
|
|
lat_min: number;
|
|
lat_max: number;
|
|
}
|
|
|
|
export function getVWorldMapUrl(projectId: string, layerName: string): string {
|
|
return `${API_BASE_URL}/projects/${projectId}/vworld-map?layer_name=${layerName}`;
|
|
}
|
|
|
|
export async function fetchVWorldMeta(projectId: string, layerName: string): Promise<VWorldMeta> {
|
|
return requestJson<VWorldMeta>(`/projects/${projectId}/vworld-meta?layer_name=${layerName}`, {
|
|
method: "GET",
|
|
});
|
|
}
|
|
|
|
export async function fetchGisGeoJson(projectId: string, layer: string): Promise<any> {
|
|
return requestJson<any>(`/projects/${projectId}/geojson?layer=${encodeURIComponent(layer)}`, {
|
|
method: "GET",
|
|
});
|
|
}
|