diff --git a/B06_Section/B06_Section_Api_Fetch.ts b/B06_Section/B06_Section_Api_Fetch.ts index 59d21970..626813ba 100644 --- a/B06_Section/B06_Section_Api_Fetch.ts +++ b/B06_Section/B06_Section_Api_Fetch.ts @@ -63,13 +63,35 @@ async function requestJson(path: string, init: RequestInit): Promise { * (2026-09-06 호출 정리). 노선이 바뀌면 `clearSectionContextCache` 로 버린다. */ export async function fetchSectionContext(projectId: string): Promise { const cached = readState("section-context", projectId); - if (cached) return cached; + if (cached) return seedStandardCross(projectId, cached); const fresh = await requestJson( `/projects/${projectId}/sections/context`, { method: "GET" }, ); writeState("section-context", fresh, projectId); - return fresh; + return seedStandardCross(projectId, fresh); +} + +/** + * 저장된 표준 횡단면을 **세션이 비어 있을 때만** 채운다(2026-09-07). + * + * 브라우저 횡단 계산은 `세션 ?? config 기본값` 으로 서는데, 표준단면 세션값은 그 탭에서만 + * 산다. 그래서 **탭을 새로 열면** 화면은 config 기본값으로, 서버는 저장분으로 계산해 + * 같은 측점이 갈렸다(실측 — 용화 route 169 저장분은 암반 횡단경사 **5%**·측구 상단폭 + * **0.9m**, config 기본값은 **3%**·**0.69m**). + * + * 여기가 두 화면(B05·B06)이 함께 지나는 유일한 자리라 이 한 곳에서 채운다. 사용자가 + * 그 탭에서 고친 값이 있으면 **건드리지 않는다** — 초안이 언제나 우선이다. + */ +function seedStandardCross( + projectId: string, + context: SectionContextResponse, +): SectionContextResponse { + const stored = context.stored_standard_cross_section; + if (stored && readState("std-cross", projectId) === null) { + writeState("std-cross", stored, projectId); + } + return context; } export function clearSectionContextCache(projectId: string): void { diff --git a/B06_Section/B06_Section_Api_Types.ts b/B06_Section/B06_Section_Api_Types.ts index f0900921..42dacd1b 100644 --- a/B06_Section/B06_Section_Api_Types.ts +++ b/B06_Section/B06_Section_Api_Types.ts @@ -74,6 +74,9 @@ export interface SectionContextResponse { defaults: SectionOptionDefaults; /** 표준 횡단면 설정 패널(토사/암/포장) 기본값. */ standard_cross_section: StandardCrossSection; + /** 이 프로젝트에 **저장된** 표준 횡단면(사용자가 고쳐 확정한 값). 없으면 null. + * 위 `standard_cross_section` 은 config 기본값이라 둘은 다른 것이다(2026-09-07). */ + stored_standard_cross_section?: StandardCrossSection | null; /** 암 경계선 기본 오프셋(m)과 상/하 제어 스텝(m). */ rock_boundary_default_offset_m: number; rock_boundary_step_m: number; diff --git a/B06_Section/B06_Section_Router.py b/B06_Section/B06_Section_Router.py index 2dfe6718..c497a156 100644 --- a/B06_Section/B06_Section_Router.py +++ b/B06_Section/B06_Section_Router.py @@ -113,6 +113,15 @@ async def get_section_context(project_id: UUID) -> SectionContextResponse | JSON run_with_connection(_road_type), ) + # 저장된 표준 횡단면 — 브라우저 계산이 서버와 같은 값을 쓰게 함께 내려보낸다 + # (2026-09-07). 노선이 없으면 저장분도 없다. + stored_standard: dict[str, Any] | None = None + if route_context and route_context.get("route_id") is not None: + longitudinal_row = await run_with_connection( + get_longitudinal_section, project_id, int(route_context["route_id"]) + ) + stored_standard = _stored_standard_cross_section(longitudinal_row) + defaults = SectionGenerationOptions() return SectionContextResponse( project_id=str(project_id), @@ -130,6 +139,7 @@ async def get_section_context(project_id: UUID) -> SectionContextResponse | JSON vertical_exaggeration=SECTION_VERTICAL_EXAGGERATION, ), standard_cross_section=STANDARD_CROSS_SECTION, + stored_standard_cross_section=stored_standard, rock_boundary_default_offset_m=STANDARD_ROCK_BOUNDARY_DEFAULT_OFFSET_M, rock_boundary_step_m=STANDARD_ROCK_BOUNDARY_STEP_M, earthwork_conversion=EARTHWORK_CONVERSION_FACTORS, diff --git a/B06_Section/B06_Section_Schema.py b/B06_Section/B06_Section_Schema.py index 9a24481b..db92a93d 100644 --- a/B06_Section/B06_Section_Schema.py +++ b/B06_Section/B06_Section_Schema.py @@ -238,6 +238,11 @@ class SectionContextResponse(BaseModel): defaults: SectionOptionDefaults # 표준 횡단면 설정 패널(토사/암/포장) 기본값. config STANDARD_CROSS_SECTION 사본. standard_cross_section: dict[str, Any] = Field(default_factory=dict) + # 이 프로젝트에 **저장된** 표준 횡단면(사용자가 고쳐 [확정]한 값). 없으면 None(=기본값 그대로). + # 2026-09-07 추가 — 예전에는 브라우저가 이 값을 받을 길이 없어, 세션이 빈 새 탭에서 + # **화면은 config 기본값으로, 서버는 저장분으로** 계산해 같은 측점이 갈렸다. + # 기존 `standard_cross_section`(기본값)은 그대로 두고 **한 칸만 더한다**. + stored_standard_cross_section: dict[str, Any] | None = None # 암 경계선 기본 오프셋(m)과 상/하 제어 스텝(m). rock_boundary_default_offset_m: float = -0.5 rock_boundary_step_m: float = 0.1