Files
Aislo/B08_DesignDetail/B08_DesignDetail_Api_Fetch.ts
T
eomsangdonandClaude Fable 5 2a248ff742 refactor(B07,B08): 도면 코드 B08_DesignDetail 이동 + 수량 슬롯 B07_Quantity 확보
- B07_wf4_DesignDetail(8파일+openwebcad) -> B08_DesignDetail로 git mv (이력 보존)
- B08_wf5_Quantity -> B07_Quantity (구 수량 백업 zip 보관 폴더)
- 파생 문자열 일괄 전환: /b07-cad -> /b08-cad 정적 서빙, CAD 레이어 b07-* -> b08-*,
  postMessage aislo:b07:* -> aislo:b08:*, 패키지명 aislo-b08-cad, CSS .b08-*,
  라우트 키/슬러그(B08_DESIGN_DETAIL/b08-design-detail, B07_QUANTITY/b07-quantity)
- 상세설계 워크플로우 stage 4 -> 5 (확정/무효화 전이 3곳), 확정 완료 시 B09로 이동
- WORKFLOW_STEP_ROUTES 순서 재배열: index4=수량(B07), index5=상세설계(B08)
- [임시] B08 이동 테스트 버튼 제거, openwebcad dist 재빌드
- 주석 의미 정렬: 수량 인계 주석 B08->B07, 도면 참조 B07->B08

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-08 10:10:10 +09:00

130 lines
3.9 KiB
TypeScript

/* B08 상세 설계 도면 목록·단건 API 클라이언트. */
import { API_BASE_URL, API_TIMEOUT_MS } from "@config/config_frontend";
export interface DesignDrawingItem {
id: string;
kind: "longitudinal" | "cross";
label: string;
chainage_m: number | null;
confirmed: boolean;
}
export interface CadDrawing {
entities: Record<string, unknown>[];
layers: {
id: string;
name: string;
isVisible: boolean;
isLocked: boolean;
}[];
}
export interface DesignDrawingListResponse {
status: string;
project_id: string;
route_id: number;
drawings: DesignDrawingItem[];
}
/** 수량 산출표 값 (미산정 항목은 null). 백엔드 `_quantity_table`의 키와 대응. */
export type QuantityTable = Record<string, number | null>;
/** 측구 형식별 규격 (B06 엔진 ditch_spec 신구조와 1:1). */
export type DitchSpec =
| { type: "none" }
| { type: "standard"; top_width_m: number; bottom_width_m: number; depth_m: number }
| { type: "l_type"; width_m: number; depth_m: number };
/** B06에서 지정한 설계(지반정보·계획정보). 횡단도에만 존재. status로 잠정/확정 구분. */
export interface CrossDesignInfo {
ground_type: "soil" | "ripping_rock" | "blasting_rock";
geometry_preset: "soil" | "rock";
section_mode: "left_cut" | "right_cut" | "both_cut" | "both_fill";
ditch_side: "left" | "right";
ditch_type?: "standard" | "l_type" | null;
ditch_enabled?: boolean;
cut_slope_ratio: number;
fill_slope_ratio: number;
roadbed_width_m: number;
carriageway_width_m?: number;
cross_slope_pct?: number;
paved?: boolean;
ditch: DitchSpec;
road_edges?: Record<"left" | "right", { offset_m: number; elevation_m: number }>;
design_elevation_m: number;
cut_area_m2: number;
fill_area_m2: number;
status?: "provisional" | "confirmed";
}
export interface DesignDrawingResponse {
status: string;
project_id: string;
route_id: number;
id: string;
kind: "longitudinal" | "cross";
label: string;
drawing: CadDrawing;
confirmed: boolean;
quantity_table?: QuantityTable | null;
design?: CrossDesignInfo | null;
}
export interface DesignDrawingConfirmResponse {
status: string;
project_id: string;
id: string;
confirmed: boolean;
all_confirmed: boolean;
design?: CrossDesignInfo | null;
}
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" },
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 function fetchDesignDrawingList(projectId: string): Promise<DesignDrawingListResponse> {
return requestJson(`/projects/${projectId}/design-drawings`);
}
export function fetchDesignDrawing(
projectId: string,
drawingId: string,
): Promise<DesignDrawingResponse> {
return requestJson(`/projects/${projectId}/design-drawings/${encodeURIComponent(drawingId)}`);
}
export function confirmDesignDrawing(
projectId: string,
drawingId: string,
drawing: CadDrawing,
quantityTable?: QuantityTable | null,
): Promise<DesignDrawingConfirmResponse> {
return requestJson(
`/projects/${projectId}/design-drawings/${encodeURIComponent(drawingId)}/confirm`,
{ method: "PUT", body: JSON.stringify({ drawing, quantity_table: quantityTable ?? null }) },
);
}
export function invalidateDesignDrawing(projectId: string, drawingId: string): Promise<void> {
return requestJson(
`/projects/${projectId}/design-drawings/${encodeURIComponent(drawingId)}/invalidate`,
{ method: "POST" },
);
}