/* ============================================================================= * 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; 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; points: [number, number, number][]; rgb?: [number, number, number][]; } export interface SurfaceGroundStatsResponse { status: string; project_id: string; filters: Record>; } 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(path: string, init: RequestInit): Promise { 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 { return requestJson(`/projects/${projectId}/surface/analyze`, { method: "POST", body: JSON.stringify(request), }); } /** 프로젝트의 지표면 모델 목록을 조회한다. */ export async function listSurfaceModels(projectId: string): Promise { return requestJson(`/projects/${projectId}/surface/models`, { method: "GET", }); } export async function listSurfaceInputFiles( projectId: string, ): Promise { return requestJson(`/projects/${projectId}/surface/input-files`, { method: "GET", }); } export async function fetchSurfacePointCloud( projectId: string, ): Promise { return requestJson( `/projects/${projectId}/surface/point-cloud`, { method: "GET", }, ); } export async function fetchSurfaceGroundStats( projectId: string, ): Promise { return requestJson(`/projects/${projectId}/surface/ground-stats`, { method: "GET", }); } export async function fetchSurfaceStatus(projectId: string): Promise { return requestJson(`/projects/${projectId}/surface/status`, { method: "GET", }); }