- 구조물(H6) — 409 · 그 밖 실패를 토스트로 삼키지 않고 던짐 · 저장 줄이 앞 실패에 막히지 않음 - 상단측(M3) — 차례 성공하면 uphill 세션 비움 · 종단 보기도 세션에서 읽음 - 확정 하위(M6) — 응답 failed_parts(비정규 측점 횡단 · 상단측 병합 · 종단 없음) · 화면이 던짐 - 시험 test_443_save_stops.py Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014utrjfoW831Vc5wJUd13kL
87 lines
4.8 KiB
TypeScript
87 lines
4.8 KiB
TypeScript
/* =============================================================================
|
|
* B05_Profile_UI_Page_Actions.ts
|
|
* 종단 보기의 **버튼 동작** — [저장]·[확정]에 보태는 종단 보기 몫. [경로 계산]은 `Old/` 로 옮김(54-24).
|
|
*
|
|
* 종단 보기 본체(`design_view_profile`)에서 떼어냈다(700줄 제한, 2026-09-02). 화면 조립·로딩
|
|
* 순서는 본체에 남고, 여기에는 영구저장소를 건드리는 갈래만 둔다(CLAUDE.md 5장: 세션에 쌓인
|
|
* 조작은 [저장]·[확정]에서만 정본으로 나간다). [초기화]는 한 벌(`design_reset`)이 한다.
|
|
* ========================================================================== */
|
|
|
|
import { saveRouteParts, type RouteLatestResponse } from "./B05_Profile_Api_Fetch";
|
|
import { loadUphillOverrides } from "./B05_Profile_UI_Page_Helpers";
|
|
import type { DesignViewSave } from "../A00_Common/design/design_shared";
|
|
import { pageRouteId } from "../A00_Common/design/design_page_route";
|
|
import type { createRoutePanel } from "./B05_Profile_UI_Panel";
|
|
import type { createRouteProfilePanel } from "./B05_Profile_UI_Profile_Panel";
|
|
import type { createStructuresBridge } from "./B05_Profile_UI_Page_Structures";
|
|
import type { createRouteViewer } from "./B05_Profile_UI_Viewer";
|
|
|
|
/** 버튼 동작이 페이지에서 받아 쓰는 창구 — 값은 바뀌므로 함수로 받는다. */
|
|
export interface PageActionContext {
|
|
projectId: string;
|
|
latest: () => RouteLatestResponse | null;
|
|
/** 확정 지표면 응답 — 모델 id 는 `model_id` 다(2026-09-06 호출 정리). */
|
|
confirmedSurface: () => { model_id: number | null } | null;
|
|
routeReady: () => boolean;
|
|
viewer: () => ReturnType<typeof createRouteViewer>;
|
|
panel: () => ReturnType<typeof createRoutePanel>;
|
|
profilePanel: () => ReturnType<typeof createRouteProfilePanel>;
|
|
bridge: () => ReturnType<typeof createStructuresBridge>;
|
|
/** 상단측(측구 방향) 사용자 변경분 — 키는 누가거리 문자열. */
|
|
uphillOverrides: Map<string, "left" | "right">;
|
|
persistUphillOverrides: () => void;
|
|
loadLatest: (forceFresh?: boolean) => Promise<RouteLatestResponse>;
|
|
renderLatest: (next: RouteLatestResponse) => void;
|
|
restoreSections: (routeId: number) => Promise<void>;
|
|
}
|
|
|
|
/** [저장] · [확정]에 종단 보기가 보태는 몫 — 차례는 저장 한 줄기(`saveDesign`)가 정하고
|
|
* 한 벌(`design_shared`)이 두 보기 몫을 모아 한 번에 보낸다(계획서 24-2a · 24-3b). 관(배수유역도) ·
|
|
* 계획고는 한 벌 종단도가 낸다. */
|
|
export function profileSaveParts(ctx: PageActionContext): DesignViewSave {
|
|
const projectId = ctx.projectId;
|
|
return {
|
|
routeId: () => (ctx.routeReady() ? pageRouteId(projectId) : null), // 노선 id 한 칸(386-2b)
|
|
steps: {
|
|
// 구조물 — 저장 뒤 서버 목록(새 식별자)으로 화면을 맞춘다. 실패는 초안을 남기고 던져
|
|
// 저장 한 줄기가 이 차례에서 멈춘다(443).
|
|
structures: () => ctx.bridge().saveStructuresIfDirty(),
|
|
// 상단측 + 비정규 측점 — 데이터로는 확정 저장하되, 단계 완료 전이는 하지 않는다.
|
|
// 하위 실패 = 던짐 · 성공 = 상단측 세션 비움(443). 상단측은 세션에서 읽음 — 노선 바꾼 [저장]이
|
|
// 기본 창구로 세션을 비웠으면 메모리 값을 다시 보내지 않게.
|
|
uphill: async () => {
|
|
const latest = ctx.latest();
|
|
await saveRouteParts(projectId, {
|
|
filter_key: latest?.surface_params.source_filter,
|
|
method: latest?.surface_params.method,
|
|
smooth: latest?.surface_params.smooth,
|
|
surface_model_id: ctx.confirmedSurface()?.model_id ?? undefined,
|
|
irregular_stations: ctx
|
|
.bridge()
|
|
.irregularStations()
|
|
.map((station) => ({
|
|
chainage_m: station.chainage_m,
|
|
structure: station.structure,
|
|
})),
|
|
// 상단측(측구 방향) 사용자 변경분 — 종단 정본에 병합되어 B06이 그대로 소비한다.
|
|
uphill_overrides: [...loadUphillOverrides(projectId).entries()].map(
|
|
([chainage, side]) => ({
|
|
chainage_m: Number(chainage),
|
|
side,
|
|
}),
|
|
),
|
|
});
|
|
ctx.uphillOverrides.clear();
|
|
},
|
|
},
|
|
// 횡단 본문은 늘 횡단 보기 몫 — [저장]이 숨긴 채라도 세움(386-6 · 옛 캐시 패치 길 지움)
|
|
// 공유 캐시는 한 벌(`design_shared`)이 저장 끝에 한 번 비움 — 여기서는 새 자료를 다시 읽어 종단 ·
|
|
// 평면 오른쪽 판을 그림(416 · 노선 안 바뀐 [저장]도 · B06 다녀오지 않아도 면적 = B06)
|
|
done: async () => {
|
|
ctx.renderLatest(await ctx.loadLatest(true));
|
|
const routeId = pageRouteId(projectId);
|
|
if (routeId !== null) await ctx.restoreSections(routeId);
|
|
},
|
|
};
|
|
}
|