refactor(472 마무리): 종단도 계획고 [저장] 조각을 design_profile_save 로 떼어 냄 — design_profile 708 → 683 줄 · 동작 같음
- design_profile_save.ts 새 파일 — 한 본문 [저장] 조각 · [확정] 직전 저장 · 저장 뒤 서버 선형 넘김 - 높이 캐스케이드 설명을 B05_Profile_UI_Profile_Heights 머리로 옮김 - 팝아웃 시험 목록에 새 파일 · 저장 조각 시험(test_472_6_profile_save) 추가 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -23,11 +23,6 @@ import {
|
||||
toDesignProfile,
|
||||
} from "../../B05_Profile/logic/B05_Profile_UI_Profile_Data";
|
||||
import { showToast } from "@ui/ui_template_elements";
|
||||
import {
|
||||
saveProfileAlignment,
|
||||
type ProfileAlignmentSaveResponse,
|
||||
} from "../../B05_Profile/B05_Profile_Api_Fetch";
|
||||
import type { SavePart } from "./design_save_api";
|
||||
import { hasStaleDesigns } from "../../B06_Section/B06_Section_UI_Section_Common";
|
||||
import {
|
||||
blocksMinCover,
|
||||
@@ -88,12 +83,12 @@ import * as pagePipeline from "./design_pipeline_page";
|
||||
import type { ElevationWindowResult } from "@util/common_util_chart_ywindow";
|
||||
import { frameOf } from "@util/common_util_view_window";
|
||||
import type { DesignSideBoard, DesignView } from "./design_profile_slots";
|
||||
import { noticeDroppedEdits } from "./design_save";
|
||||
import { createProfileOverlays } from "./design_profile_overlays";
|
||||
import { bindProfileViewport, createSelectionReveal } from "./design_profile_viewport";
|
||||
import { CROSS_PREVIEW_DEBOUNCE_MS, type DesignProfileContext } from "./design_profile_context";
|
||||
import { pageRouteId } from "./design_page_route";
|
||||
import { createProfileFrame } from "./design_profile_frame"; // 판 뼈대 · 종단 CSS(700줄 한계)
|
||||
import { createProfileSave } from "./design_profile_save"; // 계획고 [저장] 조각(700줄 한계)
|
||||
|
||||
export type {
|
||||
DesignOverlayBoard,
|
||||
@@ -303,29 +298,26 @@ export function createDesignProfile(ctx: DesignProfileContext) {
|
||||
const listed = (): AlignmentBase | null =>
|
||||
listedBase(storedBase, detail, planted ? irregularStations : null);
|
||||
|
||||
/** 계획고 [저장] 조각(472-6) — 저장 뒤 서버 선형으로 기준을 갈아 다시 그림. */
|
||||
const alignmentSave = createProfileSave({
|
||||
projectId,
|
||||
routeId: () => routeId,
|
||||
edits: () => store.edits(),
|
||||
dirty: () => store.dirty(),
|
||||
previewing: () => store === preview, // 노선 초안 미리보기 편집은 안 보냄
|
||||
adopt: (next) => {
|
||||
if (next?.base_pvi?.length) {
|
||||
storedBase = toAlignmentBase(next);
|
||||
base = listed();
|
||||
alignment = buildAlignment(base!, store.edits());
|
||||
if (detail) detail.longitudinal.profile_alignment = next;
|
||||
}
|
||||
store.markSaved();
|
||||
draw();
|
||||
},
|
||||
});
|
||||
|
||||
/** 편집 후 다시 그린다 — 길게 누르기(초당 10회)도 한 프레임에 한 번만 그림. */
|
||||
/** 한 본문 [저장] 조각(472-6) — 편집 없음 · 노선 초안 미리보기면 null · 저장 뒤 서버 선형으로 다시 그림. */
|
||||
function alignmentSavePart(): SavePart | null {
|
||||
if (!routeId || !store.dirty() || store === preview) return null; // 노선 초안 미리보기 편집은 안 보냄
|
||||
return {
|
||||
body: { route_id: routeId, ...store.edits() },
|
||||
after: (response) => adoptSaved(response as unknown as ProfileAlignmentSaveResponse),
|
||||
};
|
||||
}
|
||||
|
||||
function adoptSaved(saved: ProfileAlignmentSaveResponse): void {
|
||||
noticeDroppedEdits(saved);
|
||||
const next = saved.profile_alignment as ProfileAlignment | undefined;
|
||||
if (next?.base_pvi?.length) {
|
||||
storedBase = toAlignmentBase(next);
|
||||
base = listed();
|
||||
alignment = buildAlignment(base!, store.edits());
|
||||
if (detail) detail.longitudinal.profile_alignment = next;
|
||||
}
|
||||
store.markSaved();
|
||||
draw();
|
||||
}
|
||||
|
||||
function rebuild(): void {
|
||||
if (base) alignment = buildAlignment(base, store.edits());
|
||||
pagePipeline.pipelineGrade(projectId, store.edits());
|
||||
@@ -361,15 +353,7 @@ export function createDesignProfile(ctx: DesignProfileContext) {
|
||||
// 노선 초안 동안은 저장 노선 횡단을 안 고침 — 새 노선 횡단은 계산 묶음 cross(346-2)
|
||||
const scheduleCrossPreview = (): void => void (store !== preview && crossPreview.schedule());
|
||||
|
||||
/**
|
||||
* 높이 캐스케이드(2026-08-05 사용자 확정): 자리가 모자라면 ① 종단이 먼저 최소까지
|
||||
* 줄고 → ② 테이블·유토곡선이 **같이**(비례) 각자 최소까지 줄고 → ③ 셋 다 최소면
|
||||
* 메인 패널 리사이저의 동적 하한이 더 못 내려가게 막는다. 반대로 서브패널을 갑자기
|
||||
* 펼쳐 자리가 모자라면 메인 패널 높이를 키운다(deficit 처리).
|
||||
*
|
||||
* draw()(전체 재구성)와 리사이즈 중 경량 동기화가 **같은 계산**을 쓴다 — 끌 때는
|
||||
* 이 함수만 프레임마다 돌리고, 무거운 차트·테이블 재구성은 손을 뗀 뒤 한 번만 한다.
|
||||
*/
|
||||
/** 높이 캐스케이드 — 규칙은 `_Profile_Heights` 머리(700줄 한계). */
|
||||
const heights = createHeightCascade({
|
||||
root,
|
||||
body,
|
||||
@@ -642,18 +626,9 @@ export function createDesignProfile(ctx: DesignProfileContext) {
|
||||
drawSoon();
|
||||
},
|
||||
/** [확정] 직전에 호출한다. 편집이 없으면 아무 것도 하지 않는다. */
|
||||
async save(): Promise<void> {
|
||||
const part = alignmentSavePart();
|
||||
if (!part) return;
|
||||
await part.after?.(
|
||||
(await saveProfileAlignment(projectId, routeId!, store.edits())) as unknown as Record<
|
||||
string,
|
||||
unknown
|
||||
>,
|
||||
);
|
||||
},
|
||||
save: () => alignmentSave.save(),
|
||||
/** 한 본문 [저장] 조각(472-6) — 편집 없음 · 노선 초안 미리보기면 null · 저장 뒤 서버 선형으로 다시 그림. */
|
||||
savePart: () => alignmentSavePart(),
|
||||
savePart: () => alignmentSave.savePart(),
|
||||
clear() {
|
||||
detail = null;
|
||||
base = null;
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/* =============================================================================
|
||||
* A00_Common/design/design_profile_save.ts
|
||||
* 종단도 계획고 편집 저장 — 한 본문 [저장] 조각(472-6) · [확정] 직전 따로 저장.
|
||||
* 편집 없음 · 노선 초안 미리보기면 안 보냄 · 저장 뒤 서버 선형은 `adopt` 로 종단도에 넘김.
|
||||
* `design_profile.ts` 에서 떼어 냄(700줄 한계).
|
||||
* ========================================================================== */
|
||||
|
||||
import {
|
||||
saveProfileAlignment,
|
||||
type ProfileAlignmentSaveResponse,
|
||||
} from "../../B05_Profile/B05_Profile_Api_Fetch";
|
||||
import type {
|
||||
AlignmentEdits,
|
||||
ProfileAlignment,
|
||||
} from "../../B05_Profile/logic/B05_Profile_UI_Profile_Alignment";
|
||||
import type { SavePart } from "./design_save_api";
|
||||
import { noticeDroppedEdits } from "./design_save";
|
||||
|
||||
export function createProfileSave(deps: {
|
||||
projectId: string;
|
||||
routeId: () => number | null;
|
||||
edits: () => AlignmentEdits;
|
||||
dirty: () => boolean;
|
||||
/** 노선 초안 미리보기 편집 중 — 안 보냄. */
|
||||
previewing: () => boolean;
|
||||
/** 서버가 돌려준 선형(없을 수 있음) — 기준 갈아끼움 · 저장 표시 · 다시 그림. */
|
||||
adopt: (saved: ProfileAlignment | undefined) => void;
|
||||
}) {
|
||||
/** 한 본문 [저장] 조각 — 편집 없음 · 노선 초안 미리보기면 null. */
|
||||
function savePart(): SavePart | null {
|
||||
const routeId = deps.routeId();
|
||||
if (!routeId || !deps.dirty() || deps.previewing()) return null;
|
||||
return {
|
||||
body: { route_id: routeId, ...deps.edits() },
|
||||
after: (response) => {
|
||||
const saved = response as unknown as ProfileAlignmentSaveResponse;
|
||||
noticeDroppedEdits(saved);
|
||||
deps.adopt(saved.profile_alignment as ProfileAlignment | undefined);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/** [확정] 직전에 호출한다. 편집이 없으면 아무 것도 하지 않는다. */
|
||||
async function save(): Promise<void> {
|
||||
const part = savePart();
|
||||
if (!part) return;
|
||||
const saved = await saveProfileAlignment(deps.projectId, deps.routeId()!, deps.edits());
|
||||
await part.after?.(saved as unknown as Record<string, unknown>);
|
||||
}
|
||||
|
||||
return { savePart, save };
|
||||
}
|
||||
Reference in New Issue
Block a user