사용자 확정(2026-09-06): 조작은 캐시에 쌓이고 [저장]·[확정]에서만 영구저장소에 나간다. 카드 버튼(지반유형·단면유형·측구·포장·2단 비탈)은 누를 때마다 POST cross-design 이 나가 서버가 계산하고 바로 저장하고 있었다. - 세션 초안 crossdesign 신설(B06_Section_Cross_Design_Session) — 선택값만 담는다. - 계산은 브라우저 재계산 창구 하나로 돌린다(B05·B06 공용). - 재계산 때 세션 선택이 정본보다 우선 — 새로고침 뒤에도 고른 값이 남는다. - [저장]·[확정] patch 에 선택값 + 전 측점 면적을 실어 보낸다. 카드 버튼을 바꾸면 구조물이 없는 측점 면적도 달라지므로 구조물 측점만 보내면 수량이 어긋난다. - 구조물 목록 주석 정정(이미 초안 방식인데 옛 주석만 남아 있었다). 검증: tsc --noEmit 통과, pytest 389 passed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
68 lines
2.6 KiB
TypeScript
68 lines
2.6 KiB
TypeScript
/* =============================================================================
|
|
* B06_Section_Cross_Design_Session.ts
|
|
* 횡단 카드 버튼(지반유형·단면유형·측구·포장·2단 비탈) 선택의 **세션 보관소**.
|
|
*
|
|
* 왜 생겼나(2026-09-06 사용자 확정) — 예전에는 버튼을 누를 때마다
|
|
* `POST …/sections/{route}/cross-design` 이 나가 서버가 계산하고 **바로 저장**했다.
|
|
* 조작은 캐시에 쌓이고 [저장]·[확정]에서만 정본으로 나가야 한다는 규칙에 어긋난다.
|
|
* 계산은 브라우저가 하고(`common_util_cross_design.ts`), 선택값은 여기 담긴다.
|
|
*
|
|
* 담는 것은 **사용자가 고른 것만**이다 — 계산 결과(면적·설계선)는 담지 않는다.
|
|
* ========================================================================== */
|
|
|
|
import { readState, writeState } from "../A00_Common/b_page_state";
|
|
|
|
/** 카드에서 고를 수 있는 값 한 벌 — 서버 `CrossDesignRequest` 와 같은 이름을 쓴다. */
|
|
export interface CrossDesignChoice {
|
|
ground_type: string;
|
|
section_mode: string;
|
|
ditch_side?: string | null;
|
|
ditch_type?: string | null;
|
|
paved?: boolean;
|
|
two_stage_slope?: boolean;
|
|
}
|
|
|
|
type ChoiceMap = Record<string, CrossDesignChoice>;
|
|
|
|
/** 측점 키 — 암 경계선 저장소와 같은 규칙(0.01m 단위). */
|
|
const keyOf = (chainageM: number): string => chainageM.toFixed(2);
|
|
|
|
function readAll(projectId: string, routeId: number): ChoiceMap {
|
|
return readState<ChoiceMap>("crossdesign", projectId, routeId) ?? {};
|
|
}
|
|
|
|
/** 이 측점의 선택값(없으면 null). */
|
|
export function readCrossDesignChoice(
|
|
projectId: string,
|
|
routeId: number,
|
|
chainageM: number,
|
|
): CrossDesignChoice | null {
|
|
return readAll(projectId, routeId)[keyOf(chainageM)] ?? null;
|
|
}
|
|
|
|
/** 선택값을 세션에 담는다. 같은 측점의 앞선 값은 덮어쓴다. */
|
|
export function writeCrossDesignChoice(
|
|
projectId: string,
|
|
routeId: number,
|
|
chainageM: number,
|
|
choice: CrossDesignChoice,
|
|
): void {
|
|
const all = readAll(projectId, routeId);
|
|
all[keyOf(chainageM)] = choice;
|
|
writeState("crossdesign", all, projectId, routeId);
|
|
}
|
|
|
|
/** [저장]·[확정]이 patch 로 실을 목록 — 누가거리(숫자) → 선택값. */
|
|
export function crossDesignChoices(
|
|
projectId: string | null,
|
|
routeId: number | null,
|
|
): Map<number, CrossDesignChoice> {
|
|
const choices = new Map<number, CrossDesignChoice>();
|
|
if (!projectId || routeId === null) return choices;
|
|
for (const [key, value] of Object.entries(readAll(projectId, routeId))) {
|
|
const chainage = Number(key);
|
|
if (Number.isFinite(chainage) && value) choices.set(chainage, value);
|
|
}
|
|
return choices;
|
|
}
|