- 세션 칸 pagesettings(설계속도 · 지형 · 기준값 · 최소고 강제 · 시작 측점) · 열 때 최신 응답 위에 얹음 - 저장 차례 settings = 노선 뒤 · 관 앞(기본 창구 · 노선 바꾼 [저장]에도 돎) - PUT /route/page-settings — stage 2 params 에 사용자 값만 병합(상태 · STALE 그대로) · 종단 정책 · criteria 갱신 뒤 위반 · 요약 다시 셈(기하 그대로) - 시 · 종점 계획고 조정 = 첫 · 끝 측점 계획고 편집(끝점 ▲▼ 와 같은 길) · 샘플 간격 두 칸 읽기 전용 - E1 재설계 요청이 설계속도 · 최소고 강제 · 시작 측점 옮김 · E2 B06 재생성 지형 기본 특수 · E3 초기값 스냅샷 stage 2 params 뜸 · 되돌림 - 노선 추천 · 평면 R 설정 읽기가 params.options 를 봄(옛 맨 위 칸 폴백) - 시험 test_442_2_page_settings · test_442_2_grade_limit_mirror · design_store_save 차례 갱신 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
89 lines
4.1 KiB
TypeScript
89 lines
4.1 KiB
TypeScript
/* =============================================================================
|
|
* B05_Profile_UI_Page_Latest.ts
|
|
* 종단 보기의 **최신 노선 · 설정값** 창구 — 세션 캐시 우선 읽기 · 뒤에서 신선도 확인 · 좌측 폼 되살리기
|
|
* 값. 종단 보기 본체(`design_view_profile`)가 700줄을 넘어 여기로 뗐다(계획서 24-3b).
|
|
* ========================================================================== */
|
|
|
|
import {
|
|
fetchLatestRoute,
|
|
readRouteLatestCache,
|
|
writeRouteLatestCache,
|
|
type RouteLatestResponse,
|
|
} from "./B05_Profile_Api_Fetch";
|
|
import { panelValuesOfDraft, readPageSettings } from "./B05_Profile_Api_PageSettings";
|
|
import type { RoutePanelValues } from "./B05_Profile_UI_Panel";
|
|
|
|
/**
|
|
* 확정 이력이 있으면 매 진입마다 DB(latest) 조회 대신 브라우저 세션 캐시를 우선 사용해
|
|
* 응답속도를 높인다. 캐시 미스면 latest를 조회해 적재하고, solve·확정 성공 시 신선한 값으로
|
|
* 갱신한다(세션 = 탭 단위, 탭 종료 시 소멸).
|
|
*/
|
|
export function createLatestSource(projectId: string) {
|
|
const read = (): RouteLatestResponse | null => readRouteLatestCache(projectId);
|
|
const write = (value: RouteLatestResponse): void => writeRouteLatestCache(projectId, value);
|
|
|
|
/** 캐시 우선 latest 로드. forceFresh=true(solve/확정 직후)는 항상 DB를 읽고 캐시를 갱신한다. */
|
|
async function load(forceFresh = false): Promise<RouteLatestResponse> {
|
|
if (!forceFresh) {
|
|
const cached = read();
|
|
if (cached) return cached;
|
|
}
|
|
const fresh = await fetchLatestRoute(projectId);
|
|
write(fresh);
|
|
return fresh;
|
|
}
|
|
|
|
/** 이 응답이 "같은 자료"인지 가리는 서명 — 노선 번호·지표면 모델·지표면 설정. */
|
|
const signature = (value: RouteLatestResponse): string =>
|
|
[
|
|
value.route?.id ?? "",
|
|
value.route?.surface_model_id ?? "",
|
|
value.surface_params.source_filter,
|
|
value.surface_params.method,
|
|
String(value.surface_params.smooth),
|
|
].join("|");
|
|
|
|
/**
|
|
* 캐시로 먼저 그린 뒤 **뒤에서** 신선도를 확인한다(2026-09-06 캐시·세션 일원화).
|
|
* 서명(노선번호·지표면)이 달라졌을 때만 `onChanged` 로 다시 그린다.
|
|
*/
|
|
async function verify(
|
|
shown: RouteLatestResponse,
|
|
onChanged: (fresh: RouteLatestResponse) => Promise<void>,
|
|
): Promise<void> {
|
|
try {
|
|
const fresh = await fetchLatestRoute(projectId);
|
|
write(fresh);
|
|
if (signature(fresh) === signature(shown)) return;
|
|
await onChanged(fresh);
|
|
} catch {
|
|
/* 확인 실패는 조용히 넘긴다 — 화면은 캐시로 이미 서 있다. */
|
|
}
|
|
}
|
|
|
|
return { read, write, load, verify };
|
|
}
|
|
|
|
/** 저장된 노선 설정값 → 좌측 폼 되살리기 값 — 세션 페이지 설정 초안이 있으면 그 위에(448).
|
|
* 시 · 종점 계획고 조정은 종단 편집이 비추므로 여기서 안 채움(옛 params 값은 자동 선형에 이미 듦). */
|
|
export function panelValuesOf(next: RouteLatestResponse): Partial<RoutePanelValues> {
|
|
const options = next.route_params?.options ?? {};
|
|
const draft = readPageSettings(next.project_id);
|
|
return {
|
|
contourInterval: next.surface_params.contour_interval_m,
|
|
gradeClass: options.grade_class as RoutePanelValues["gradeClass"] | undefined,
|
|
stationInterval: next.route_params?.station_interval_m ?? undefined,
|
|
crossSampleInterval: next.route_params?.cross_sample_interval_m ?? undefined,
|
|
longSampleInterval: next.route_params?.long_sample_interval_m ?? undefined,
|
|
terrainType: options.terrain_type as RoutePanelValues["terrainType"] | undefined,
|
|
designSpeed: options.design_speed_kph as RoutePanelValues["designSpeed"] | undefined,
|
|
maxGradePct: next.route_params?.max_grade_pct ?? undefined,
|
|
minVerticalRadius: next.route_params?.min_vertical_radius_m ?? undefined,
|
|
minTangentLength: next.route_params?.min_tangent_length_m ?? undefined,
|
|
enforcePipeClearance:
|
|
(next.route_params?.enforce_pipe_clearance as boolean | undefined) ?? undefined,
|
|
stationDisplay: next.route_params?.station_display ?? undefined,
|
|
...(draft ? panelValuesOfDraft(draft) : {}),
|
|
};
|
|
}
|