/* ============================================================================= * B06_wf3_ProfileCross_Api_Fetch.ts * 3차 워크플로우(종·횡단 생성) API 클라이언트 * * 백엔드 계약 (B06_wf3_ProfileCross_Router.py): * POST /api/projects/{project_id}/sections/generate → 종횡단 생성 + DB 기록 * GET /api/projects/{project_id}/sections/{route_id} → 종단 요약 조회 * POST /api/projects/{project_id}/sections/{route_id}/confirm → 종횡단 확정 * * 규칙: * - 모든 제어 상수는 config_frontend에서 참조 (하드코딩 금지). * - 오류 응답 형식 {status:"error", message:"..."}을 Error로 변환. * ========================================================================== */ import { API_BASE_URL, API_TIMEOUT_MS, AUTH_TOKEN_KEY } from "@config/config_frontend"; /** 종횡단 생성 실행 요청 (SectionGenerateRequest) */ export interface SectionGenerateRequest { route_id: number; filter_key: string; method?: string; smooth?: boolean; crs?: string | null; station_interval_m?: number | null; cross_half_width_m?: number | null; cross_sample_interval_m?: number | null; long_sample_interval_m?: number | null; } /** 종횡단 생성 결과 (SectionGenerateResponse) */ export interface SectionGenerateResponse { status: string; project_id: string; route_id: number; longitudinal_id: number; cross_section_count: number; length_m: number; longitudinal_file_path: string; } /** 종단 요약 조회 결과 (SectionSummaryResponse) */ export interface SectionSummaryResponse { status: string; project_id: string; route_id: number; longitudinal: Record | null; } /** 종횡단 확정 결과 (SectionConfirmResponse) */ export interface SectionConfirmResponse { status: string; project_id: string; route_id: number; confirmed: boolean; } /** 공통 fetch 헬퍼: 타임아웃 + 인증 헤더 + 오류 응답 변환. */ async function requestJson(path: string, init: RequestInit): Promise { const controller = new AbortController(); const timeoutId = window.setTimeout(() => controller.abort(), API_TIMEOUT_MS); const token = localStorage.getItem(AUTH_TOKEN_KEY); try { const response = await fetch(`${API_BASE_URL}${path}`, { ...init, headers: { "Content-Type": "application/json", ...(token ? { Authorization: `Bearer ${token}` } : {}), ...(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); } } /** 확정 경로에서 종·횡단을 생성한다 (측점 배열 → 종단 프로필 → 횡단 샘플). */ export async function generateSections( projectId: string, request: SectionGenerateRequest, ): Promise { return requestJson(`/projects/${projectId}/sections/generate`, { method: "POST", body: JSON.stringify(request), }); } /** 경로의 종단면 요약을 조회한다. */ export async function getSections( projectId: string, routeId: number, ): Promise { return requestJson(`/projects/${projectId}/sections/${routeId}`, { method: "GET", }); } /** 경로의 종·횡단면을 확정한다. */ export async function confirmSections( projectId: string, routeId: number, ): Promise { return requestJson(`/projects/${projectId}/sections/${routeId}/confirm`, { method: "POST", }); }