- 상자 화면(포인트 팔레트 · 알고리즘 · 조건 · 숨긴 [최적 경로 계산]) · solveRouteAction · routePoint/circlePoint 를 B05_Profile/Old/B05_Profile_UI_RouteCalc.ts 로 떼어 옮김 - 좌측 패널 등록 · onSolve · 칸 값(algorithm · paved · 곡선반경 · 경사 상하한 · 회피 통과) 끊음 - tsconfig 에서 B05_Profile/Old 제외 · 서버 경로 계산 API · 자동설계 체인은 그대로 - 시험: 좌측 칸 수 1+4+2 · 칸 제목에서 「경로 계산 설정」 뺌 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W4uKaV4ZBhsJN4GHG7yRj4
96 lines
5.1 KiB
TypeScript
96 lines
5.1 KiB
TypeScript
/* =============================================================================
|
|
* B05_Profile_UI_Page_Actions.ts
|
|
* 종단 보기의 **버튼 동작** — [저장]·[확정]에 보태는 종단 보기 몫. [경로 계산]은 `Old/` 로 옮김(54-24).
|
|
*
|
|
* 종단 보기 본체(`design_view_profile`)에서 떼어냈다(700줄 제한, 2026-09-02). 화면 조립·로딩
|
|
* 순서는 본체에 남고, 여기에는 영구저장소를 건드리는 갈래만 둔다(CLAUDE.md 5장: 세션에 쌓인
|
|
* 조작은 [저장]·[확정]에서만 정본으로 나간다). [초기화]는 한 벌(`design_reset`)이 한다.
|
|
* ========================================================================== */
|
|
|
|
import { confirmRoute, type RouteLatestResponse } from "./B05_Profile_Api_Fetch";
|
|
import type { DesignViewSave } from "../A00_Common/design/design_shared";
|
|
import {
|
|
invalidateSectionDetail,
|
|
saveCachedCrossPatches,
|
|
} from "../B06_Section/B06_Section_Section_Store";
|
|
import { saveCorridorIfDirty } from "./B05_Profile_UI_Corridor";
|
|
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() ? (ctx.latest()?.route?.id ?? null) : null),
|
|
steps: {
|
|
// 구조물 — 저장 뒤 서버 목록(새 식별자)으로 화면을 맞춘다. 실패는 자체 토스트로 알리고
|
|
// 세션에 남겨 두므로 저장 전체를 멈추지 않는다(2026-08-29 — CLAUDE.md 5장).
|
|
structures: () => ctx.bridge().saveStructuresIfDirty(),
|
|
// 상단측 + 비정규 측점 — 데이터로는 확정 저장하되, 단계 완료 전이는 하지 않는다.
|
|
uphill: async () => {
|
|
const latest = ctx.latest();
|
|
await confirmRoute(
|
|
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: [...ctx.uphillOverrides.entries()].map(([chainage, side]) => ({
|
|
chainage_m: Number(chainage),
|
|
side,
|
|
})),
|
|
},
|
|
false,
|
|
);
|
|
},
|
|
},
|
|
// 횡단 보기를 세운 적 없이 [저장]하면 — 캐시에 얹힌 횡단 수정분을 함께 남긴다. 안 보내면
|
|
// 바로 아래 캐시 비우기에서 사라진다. 계획선 저장 **뒤에** 보내야 사용자 수정 1세트가
|
|
// 최종본으로 얹힌다(2026-08-24 사용자 지적). 횡단 보기가 서 있으면 그쪽 본문이 나간다.
|
|
cross: async () => {
|
|
const routeId = ctx.latest()?.route?.id;
|
|
if (routeId != null) await saveCachedCrossPatches(projectId, routeId);
|
|
},
|
|
done: async () => {
|
|
// 서버가 종단 정본의 계획선을 다시 썼다 — 공유 캐시를 비워 횡단 보기가 옛 계획선을 못 보게 한다.
|
|
invalidateSectionDetail(projectId);
|
|
ctx.renderLatest(await ctx.loadLatest(true));
|
|
// 저장 = 코리도 영구저장 시점(2026-08-23) — 실패해도 저장은 성공 처리.
|
|
const routeId = ctx.latest()?.route?.id;
|
|
if (routeId) void saveCorridorIfDirty(projectId, routeId);
|
|
},
|
|
};
|
|
}
|