Files
Aislo/config/config_frontend.ts
T
eomsangdonandClaude Opus 5 1eb5ad4a60 feat(B03): 입력 화면을 계획노선/지형 두 컨테이너로 나누고 파일마다 카드를 준다
노선 파일이 다섯이면 카드도 다섯이어야 어느 것이 왔는지 보인다(사용자 지시).
세트를 슬롯 하나에 몰아 담던 companions 구조를 걷어내고, 슬롯 하나가 파일 하나를
갖는 기존 구조로 되돌렸다 - 업로드 루프도 원래대로다.

- 왼쪽 컨테이너 계획노선 자료: csv(.csv/.shp) shx dbf cpg route_prj
- 오른쪽 컨테이너 지형 자료(LAS): las_laz prj(지형 좌표계) tfw tif + LAS 없는 설계 토글
- .prj만 확장자로 안 갈린다 - 노선 도형과 basename이 같으면 노선 좌표계 카드,
  아니면 지형 카드(planSlotAssignments). 재접속 현황은 저장 경로(input/shp/)로 가른다.
- 재접속 현황 응답에 relative_path 추가.
- 필수 판정이 노선 PRJ를 route_prj로 따로 센다 - 지형 PRJ 없이 통과하던 구멍을 막았다.
- 형제 카드(shx/dbf/route_prj)는 노선 도형이 shapefile일 때만 필수 - 확장자 줄의
  "선택" 꼬리표가 실시간으로 붙고 떨어진다.
- 카드가 좁아져 한글 제목이 글자 단위로 접히던 것을 word-break: keep-all과 헤더
  flex-wrap으로 고쳤다.

화면 검증(공용 브라우저): 실물 7파일을 한 번에 떨어뜨려 배정 실측 - route.prj는
노선 좌표계 카드, terrain.prj는 지형 카드로 갈렸고 카드 제목 9개 모두 한 줄.
tmp/tests/test_route_shapefile_input.py 9개 통과, tsc --noEmit 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-31 19:50:39 +09:00

190 lines
7.8 KiB
TypeScript

/* =============================================================================
* config_frontend.ts
* 프론트엔드 제어 및 웹 환경 설정 (API 주소, 업로드 제한, 라우트 등)
*
* 규칙:
* - 프론트엔드의 모든 제어 상수는 여기서 관리. 컴포넌트 내 하드코딩 금지.
* - API 주소, 파일 제한, WebCAD 렌더 옵션 등을 중앙 집중.
* ========================================================================== */
/* -----------------------------------------------------------------------------
* 1. API 통신
* -------------------------------------------------------------------------- */
/** 백엔드 API 기본 경로. vite proxy(/api → :8000)를 통해 FastAPI로 전달. */
export const API_BASE_URL = "/api";
/** API 요청 타임아웃 (ms) */
export const API_TIMEOUT_MS = 30_000;
/** 격자 해석처럼 수십 초가 걸리는 분석 요청용 타임아웃 (ms).
* 일반 요청에 이 값을 쓰면 장애 시 화면이 오래 멈추므로 분석 엔드포인트에만 쓴다. */
export const API_ANALYSIS_TIMEOUT_MS = 60_000;
/** B03~B09 워크플로우에서 사용할 현재 프로젝트 UUID 저장 키 */
export const CURRENT_PROJECT_ID_KEY = "frd_current_project_id";
/* -----------------------------------------------------------------------------
* 2. 파일 업로드 제한 (B03_FileInput)
* -------------------------------------------------------------------------- */
/** 단일 파일 최대 크기 (MB) */
export const UPLOAD_MAX_MB = 30 * 1024;
/** 한 요청에서 선택 가능한 최대 파일 수 */
// 한 번에 채울 수 있는 **카드 수**. 계획노선 shapefile이 카드 5장을 쓰므로
// 노선 5 + 지형 4 = 9가 최대다(2026-08-31).
export const UPLOAD_MAX_FILES = 10;
/** 청크 업로드 단위 (MB) */
export const UPLOAD_CHUNK_SIZE_MB = 1024;
/** 업로드 진행 UI 갱신 주기 (ms) */
export const PROGRESS_UPDATE_INTERVAL_MS = 10_000;
/** B03 업로드 Service Worker 번들 경로 */
export const SERVICE_WORKER_PATH = "/assets/B03_FileInput_ServiceWorker.js";
/** 허용 확장자 (계획노선/지형/포인트클라우드/도면) */
export const UPLOAD_ALLOWED_EXT = [
".csv",
".shp",
".shx",
".dbf",
".cpg",
".las",
".laz",
".tif",
".tfw",
".prj",
".dxf",
] as const;
/** 계획노선 shapefile 한 벌 — 카드 다섯 장에 한 개씩 담긴다. */
export const SHAPEFILE_MEMBER_EXT = [".shp", ".shx", ".dbf", ".cpg", ".prj"] as const;
/* -----------------------------------------------------------------------------
* 3. WebCAD / 3D 렌더링 옵션
* -------------------------------------------------------------------------- */
export const RENDER_OPTIONS = {
/** Three.js 배경색 (theme.css 변수와 별개로 캔버스 clear color) */
canvasClearColorLight: 0xf6f7fa,
canvasClearColorDark: 0x16121f,
pointColor: 0x3e0079,
gridCenterColor: 0x9491a1,
gridLineColor: 0xe6e2e3,
/** 카메라 기본 시야각 */
cameraFov: 60,
/** 카메라 near/far */
cameraNear: 0.1,
cameraFar: 100_000,
/** 안티앨리어싱 사용 여부 */
antialias: true,
/** 픽셀 비율 상한 (고DPI 성능 보호) */
maxPixelRatio: 2,
} as const;
/* -----------------------------------------------------------------------------
* 4. 라우트 상수 (해시 기반 SPA 라우팅)
* 각 페이지 폴더명과 1:1 매핑.
* -------------------------------------------------------------------------- */
export const ROUTES = {
// 로그인 전
A01_HOME: "a01-home",
A02_PROG_DETAIL: "a02-prog-detail",
A03_COMP_DETAIL: "a03-comp-detail",
A04_NEWS_HISTORY: "a04-news-history",
A05_EDU_DETAIL: "a05-edu-detail",
A06_LOGIN: "a06-login",
A07_REGISTER: "a07-register",
A08_SUPPORT: "a08-support",
A09_SECURITY: "a09-security",
// 로그인 후
B01_ACCOUNT: "b01-account",
B02_PROJ_REGISTER: "b02-proj-register",
B03_FILE_INPUT: "b03-file-input",
B04_PREPROCESS: "b04-preprocess",
B05_PROFILE: "b05-profile",
B06_SECTION: "b06-section",
B07_DESIGN_DETAIL: "b07-design-detail",
B08_QUANTITY: "b08-quantity",
B09_ESTIMATION: "b09-estimation",
B10_PAYMENT: "b10-payment",
B11_STATUS: "b11-status",
// 대시보드에서 B그룹으로 처음 들어갈 때 3D·등고선을 미리 받아 두는 준비 화면.
B11_LOADING: "b11-loading",
} as const;
export type RouteKey = keyof typeof ROUTES;
export type RoutePath = (typeof ROUTES)[RouteKey];
/** 기본 진입 라우트 */
export const DEFAULT_ROUTE: RoutePath = ROUTES.A01_HOME;
/** 로그인이 필요한 라우트 (인증 가드용) */
export const PROTECTED_ROUTES: readonly RoutePath[] = [
ROUTES.B01_ACCOUNT,
ROUTES.B02_PROJ_REGISTER,
ROUTES.B03_FILE_INPUT,
ROUTES.B04_PREPROCESS,
ROUTES.B05_PROFILE,
ROUTES.B06_SECTION,
ROUTES.B07_DESIGN_DETAIL,
ROUTES.B08_QUANTITY,
ROUTES.B09_ESTIMATION,
ROUTES.B10_PAYMENT,
ROUTES.B11_STATUS,
ROUTES.B11_LOADING,
];
/* -----------------------------------------------------------------------------
* 5. 테마 / 언어 저장 키
* -------------------------------------------------------------------------- */
export const THEME_STORAGE_KEY = "frd_theme";
export const LANG_STORAGE_KEY = "frd_lang";
/* -----------------------------------------------------------------------------
* 6. B05 구조물 옵션 (드롭다운 목록·기본값)
* 정본은 config/config_system.py의 STRUCTURE_* / PIPE_* 상수 — 값을 바꿀 때는
* 양쪽을 함께 고친다(2026-08-05 사용자 확정. 계산은 백엔드, 표시는 프론트).
* -------------------------------------------------------------------------- */
export const STRUCTURE_TYPES = ["배관", "기성막이", "대피로", "기타"] as const;
export type StructureType = (typeof STRUCTURE_TYPES)[number];
export const STRUCTURE_DEFAULT_TYPE: StructureType = "배관";
/** 관종별 직경(mm) 목록. */
export const PIPE_DIAMETERS_MM: Record<string, readonly number[]> = {
이중벽관: [150, 200, 250, 300, 400, 450, 500, 600, 700, 800, 900, 1000, 1200, 1500],
삼중벽관: [200, 250, 300, 400, 450, 500, 600, 700, 800, 900, 1000, 1200, 1500],
파형강관: [
150, 200, 250, 300, 350, 400, 450, 500, 600, 700, 800, 900, 1000, 1200, 1350, 1500, 1650, 1800,
2000,
],
} as const;
export const PIPE_TYPES = Object.keys(PIPE_DIAMETERS_MM);
export const PIPE_DEFAULT_TYPE = "파형강관";
/** 자동 지정 기본 관경 — 별표2 (나) 예외 하한 800mm. 유효직경이 더 크면 바로 위 규격. */
export const PIPE_DEFAULT_DIAMETER_MM = 800;
/** 월류 폭 기본값(m) — 세월교 10m·물넘이포장 5m (2026-08-18 사용자 확정, 지식DB 근거 없음).
* 백엔드 `B06_Section_Engine_Culvert.FORD_DEFAULT_WIDTH_M`·`FORD_PAVEMENT_DEFAULT_WIDTH_M`과
* 같은 값이어야 한다. */
export const FORD_BRIDGE_DEFAULT_WIDTH_M = 10;
export const FORD_PAVEMENT_DEFAULT_WIDTH_M = 5;
/** 물넘이 개수로 조도계수 — KDS 표 2.7-1 콘크리트 수로 "보통"값이자 실무 물넘이 관측치.
* 백엔드 `config_system.FORD_MANNING_N`과 같은 값이어야 한다. */
export const FORD_MANNING_N = 0.017;
/** 물넘이 수리계산 경사 — 실무 수리계산서 역산값 10%(2026-08-17 확인).
* 백엔드 `config_system.FORD_SLOPE`와 같은 값이어야 한다. */
export const FORD_SLOPE = 0.1;
export const ESCAPE_ROUTE_WIDTHS_M = [1.5, 2.0, 2.5, 3.0] as const;
export const ESCAPE_ROUTE_DEFAULT_WIDTH_M = 2.0;
export const STRUCTURE_ETC_DEFAULT_NAME = "기타 구조물";
/** 유효직경(mm) 이상인 가장 작은 규격을 고른다. 목록을 넘으면 최대 규격. */
export function pickPipeDiameter(pipeType: string, effectiveDiameterMm: number | null): number {
const sizes = PIPE_DIAMETERS_MM[pipeType] ?? PIPE_DIAMETERS_MM[PIPE_DEFAULT_TYPE];
const need = Math.max(PIPE_DEFAULT_DIAMETER_MM, effectiveDiameterMm ?? 0);
return sizes.find((size) => size >= need) ?? sizes[sizes.length - 1];
}