refactor(387-4): 횡단 다시 셈 창구 하나 · 면적 얹기 한 곳 — 화면은 묶음에 부탁

- 다시 셈(refreshCrossDesigns) 부르는 곳 = 묶음 cross 단계 하나(design_shared savedCross)
- 종단 미리 셈 · B06 설계 맞춤 · 3D 업데이트 = pipelineCross · reconcilePagePipeline(▲ 한 번 = cross 한 번)
- 입력 칸 밖 세션 고침(노견 · 소단 · 단면 유형 · 조정창)은 forceCross 로 같은 입력이어도 한 번 더
- 카드 그리기 · 횡단 보기 면적 쓰기 지움 · 다시 셈 창구가 면적을 늘 얹음(바뀐 측점만 알림)
- 저장 안 한 조정창 값을 상세 가게가 읽을 때 얹음(새 Section_Adjusts · B05 만 열어도 같은 면적)
- 새 test_384_4_cross_window · 옛 약속 시험 넷 새 약속으로

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014utrjfoW831Vc5wJUd13kL
This commit is contained in:
2026-10-17 18:19:21 +09:00
co-authored by Claude Opus 5.5
parent 1fa5717fca
commit 6a3f9647f3
17 changed files with 342 additions and 259 deletions
+6 -1
View File
@@ -56,6 +56,11 @@ function digest(text: string): string {
return `${text.length}:${hash >>> 0}`;
}
/** 다시 셈 부탁 수(387-4) — 입력 칸에 없는 세션 고침(노견 · 소단 구간 · 조정창 4축 · 단면 유형)을 고친 화면이
* 올림 · cross 입력 지문에 들어가 같은 입력이어도 묶음 cross 가 한 번 더 돎(다시 셈 창구 한 곳). */
let forced = 0;
export const forceCross = (): void => void (forced += 1);
const finite = (value: unknown): number | null =>
typeof value === "number" && Number.isFinite(value) ? value : null;
@@ -180,7 +185,7 @@ export function pipelineCrossSource(
standard,
byKey,
rockBoundaryDefaultM: readRockBoundaryDefault(projectId),
specsKey: digest(JSON.stringify([...specs])),
specsKey: `${digest(JSON.stringify([...specs]))}|${forced}`,
},
specs,
};
+7 -22
View File
@@ -67,10 +67,6 @@ import "../../B06_Section/B06_Section_UI_Style_Cross.css";
import "../../B06_Section/B06_Section_UI_Style_Cross_Controls.css";
import "../../B06_Section/B06_Section_UI_Style_Cross_Areas.css";
import { loadSectionDetail } from "../../B06_Section/B06_Section_Section_Store";
import {
applyStructureAreaRows,
structureAreaRows,
} from "../../B06_Section/B06_Section_Structure_Layouts";
import { createSampleWidener, L } from "../../B06_Section/B06_Section_UI_Page_Common";
import {
createCrossViewPart,
@@ -228,14 +224,7 @@ export async function mountCrossView(
await new Promise((next) => setTimeout(next, 0)); // 겹친 신호(갈아끼움 · 묶음 · 초안) = 한 번(365-4)
const fresh = await loadSectionDetail(projectId, currentRouteId);
if (seq !== structuresRefreshSeq) return;
sectionDetail = fresh;
// 면적을 **먼저** 다시 얹는다 — 유토곡선은 카드보다 앞서 셈(카드만 고치면 곡선이 옛 면적 · 2026-09-06 실측).
if (sectionDetail) {
applyStructureAreaRows(
sectionDetail.cross_sections,
structureAreaRows(sectionDetail.cross_sections),
);
}
sectionDetail = fresh; // 구조물 면적은 상세 가게가 읽을 때 얹음(387-4 · 화면은 안 얹음)
renderSectionDetail();
void reconcileStaleDesigns(); // 구조물 제원 ↔ 저장분 값 다른 측점 다시 셈(측구 · 포장 · 노면 하강 · 314)
} catch (error) {
@@ -292,7 +281,9 @@ export async function mountCrossView(
const stationControls = createStationControls({
// 키는 등록표(`b_page_state`)가 만든다 — 등록표에 없는 이름을 쓰면 **컴파일에서** 걸린다.
sessionKey: (kind) => stateKey(kind, projectId, currentRouteId),
refreshCard: (chainageM) => sectionView.refreshCard(chainageM),
// 조정창 값 = 입력 칸 밖 세션 고침 → 묶음 cross 한 번 더 · 면적은 거기서(387-4 · 카드 그리기는 안 고침)
refreshCard: (chainageM) =>
void (sectionView.refreshCard(chainageM), reconcileStaleDesigns({ force: true })),
detail: () => sectionDetail,
crossHalfWidth,
sampledHalfWidth,
@@ -366,7 +357,8 @@ export async function mountCrossView(
structureSpan: stationControls.structureSpan,
soilTiers: pipeExtraCount,
overrideOptions: (chainageM, values) => structuresPanel.overrideOptions(chainageM, values),
refreshCard: (chainageM) => sectionView.refreshCard(chainageM),
refreshCard: (chainageM) =>
void (sectionView.refreshCard(chainageM), reconcileStaleDesigns({ force: true })),
};
// 횡단도 벽·구체 선택 → 좌측 「구조물 배치」 폼에 그 시설 로드(2026-08-29 일원화).
const structureSelection = wireStructureSelection(
@@ -631,14 +623,7 @@ export async function mountCrossView(
// 공유 캐시 — 종단 보기가 이미 받아 뒀으면 같은 객체를 즉시 재사용한다.
sectionDetail = await loadSectionDetail(projectId, context.route_id);
structuresPanel.facility.recount(); // 단 수는 횡단 자료로 셈 — 흙막이 상자 · 목록 램프 다시(54-15)
// 구조물 초안(저장 안 한 벽)은 저장소가 이미 얹어 준다. 면적만 여기서 다시 얹으면
// 첫 화면의 카드·유토곡선이 초안 기준으로 선다(2026-09-06 실측).
if (sectionDetail) {
applyStructureAreaRows(
sectionDetail.cross_sections,
structureAreaRows(sectionDetail.cross_sections),
);
}
// 구조물 초안(저장 안 한 벽) · 그 면적은 상세 가게가 얹어 줌(387-4 · 화면은 안 얹음).
// 단일 소스(DB data.options) 우선, options 스냅샷이 없는 과거 데이터는 샘플 최대 offset으로 추정
const summaryData = existing.longitudinal.data as {
options?: {