fix(B06): 횡단 카드 버튼이 서버에 바로 저장하던 것을 캐시로 바꿈
사용자 확정(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>
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
/* =============================================================================
|
||||
* 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;
|
||||
}
|
||||
Reference in New Issue
Block a user