Merge remote-tracking branch 'origin/main_laptop_1' into sub_laptop_1
This commit is contained in:
@@ -109,7 +109,14 @@ export const STATE_REGISTRY = {
|
||||
culvertmove: { bucket: "draft", scope: "route", legacy: (p, r) => `b06:culvertmove:${p}:${r}` },
|
||||
/** 암 경계선 오프셋(측점별). */
|
||||
rockb: { bucket: "draft", scope: "route", legacy: (p, r) => `b06:rockb:${p}:${r}` },
|
||||
/** 규격 횡단 측점별 지정. */
|
||||
/** 표준 횡단면 설정 패널의 편집값.
|
||||
*
|
||||
* ⚠ **[저장]·[확정] 뒤에도 지우지 않는다**(2026-09-07 확인). 다른 초안과 달리 이 값은
|
||||
* 브라우저가 가진 **유일한** 사용자 표준단면이다 — `sections/context` 가 주는
|
||||
* `standard_cross_section` 은 저장분이 아니라 **config 기본값**이고(`B06_Section_Router.py:132`),
|
||||
* 저장분(`stored_standard_cross_section`)은 서버 안에서만 쓰인다. 그래서 비우면 브라우저
|
||||
* 횡단 계산이 그 순간 config 기본값으로 되돌아간다. [초기화]에서만 버린다
|
||||
* (`clearStandardCrossSession`). */
|
||||
"std-cross": { bucket: "draft", scope: "project", legacy: (p) => `b06:std-cross:${p}` },
|
||||
/** 표시 반폭 — 사용자가 고른 값이라 초안이되, 바꾸면 횡단 재생성(③)을 함께 부른다. */
|
||||
"cross-display": {
|
||||
|
||||
@@ -63,13 +63,35 @@ async function requestJson<T>(path: string, init: RequestInit): Promise<T> {
|
||||
* (2026-09-06 호출 정리). 노선이 바뀌면 `clearSectionContextCache` 로 버린다. */
|
||||
export async function fetchSectionContext(projectId: string): Promise<SectionContextResponse> {
|
||||
const cached = readState<SectionContextResponse>("section-context", projectId);
|
||||
if (cached) return cached;
|
||||
if (cached) return seedStandardCross(projectId, cached);
|
||||
const fresh = await requestJson<SectionContextResponse>(
|
||||
`/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<unknown>("std-cross", projectId) === null) {
|
||||
writeState("std-cross", stored, projectId);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
export function clearSectionContextCache(projectId: string): void {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -21,6 +21,7 @@ import { flushPendingPipes } from "../B05_Profile/B05_Profile_Api_Pipes_Draft";
|
||||
import { flushPendingStructures } from "../B05_Profile/B05_Profile_Api_Structures";
|
||||
import { flushUphillOverrides } from "../B05_Profile/B05_Profile_Api_Fetch";
|
||||
import { buildCrossPatches, type CrossPatchSources } from "./B06_Section_UI_Page_Patches";
|
||||
import { readState } from "../A00_Common/b_page_state";
|
||||
import {
|
||||
applyStructureAreaRows,
|
||||
STRUCTURE_AREA_KEYS,
|
||||
@@ -33,25 +34,22 @@ import { balloonOffsetsPayload } from "@util/common_util_mass_haul_balance_view"
|
||||
import { L } from "./B06_Section_UI_Page_Common";
|
||||
|
||||
/**
|
||||
* 암 경계선 오프셋 세션 키 — 저장소와 재계산 창구가 **같은 자리**를 보게 정의처를 하나로 둔다.
|
||||
* (`B06_Section_Cross_Refresh` 가 패널 없는 B05에서도 같은 값을 읽어 서버로 보낸다.)
|
||||
* 세션에 쌓인 암 경계선 오프셋(측점키 → m). 없거나 손상되면 빈 객체.
|
||||
*
|
||||
* **등록표를 거쳐 읽는다**(2026-09-07 고침). 예전에는 옛 키 `b06:rockb:{p}:{r}` 를 날문자열로
|
||||
* 읽었는데, 쓰는 쪽(`B06_Section_UI_Page.ts` 의 `stateKey("rockb", …)`)은 새 키
|
||||
* `aislo:draft:rockb:{p}:{r}` 에 쓰고 있어 **읽는 쪽이 늘 빈 값**을 받았다. 그래서
|
||||
* 계획선을 고쳐 횡단을 다시 계산할 때(`B06_Section_Cross_Refresh`) 사용자가 옮긴 암 경계선이
|
||||
* 안 실려 나가 토사/암 나눔이 기본값으로 돌아갔다 — 수량이 갈리는 자리다.
|
||||
* 실측(용화 5601e828, route 169): 경계선을 -0.5 → -0.8m 로 옮기니 새 키에만 `{"0.00":-0.8}`
|
||||
* 가 쌓이고 옛 키는 아예 없었다.
|
||||
*/
|
||||
export function rockBoundarySessionKey(projectId: string, routeId: number): string {
|
||||
return `b06:rockb:${projectId}:${routeId}`;
|
||||
}
|
||||
|
||||
/** 세션에 쌓인 암 경계선 오프셋(측점키 → m). 없거나 손상되면 빈 객체. */
|
||||
export function readRockBoundarySession(
|
||||
projectId: string,
|
||||
routeId: number,
|
||||
): Record<string, number> {
|
||||
try {
|
||||
const raw = window.sessionStorage.getItem(rockBoundarySessionKey(projectId, routeId));
|
||||
const parsed = raw ? (JSON.parse(raw) as unknown) : null;
|
||||
return parsed && typeof parsed === "object" ? (parsed as Record<string, number>) : {};
|
||||
} catch {
|
||||
return {};
|
||||
}
|
||||
const stored = readState<Record<string, number>>("rockb", projectId, routeId);
|
||||
return stored && typeof stored === "object" ? stored : {};
|
||||
}
|
||||
|
||||
/** 암 경계선 오프셋 저장소 — 값(Map)과 조정창 제어기를 함께 낸다. */
|
||||
|
||||
Reference in New Issue
Block a user