- 브라우저 — 노선 바뀐 [저장]의 계획고 본문 = 묶음 계획고 대 저장분 옮김(같은 carryEdits · 이 초안 첫 기준)의 다른 열쇠 · 지운 열쇠만(`gradeTouch` · `routeGradeTouch`) · 못 가르면 옛 길(노선 0 칸 통째) - 서버 — `alignment_cleared` 가 오면 관 · 구조물 · 추가 측점 차례 뒤 새 종단 편집(서버 옮김) 위에 손댐만 얹어 한 번 저장(`touched_alignment` · 얹기 실패도 되돌림 안) - follow 옮김 측점 = stations 단계와 같은 추가 측점(`plus` 넘김) - 재현: 꼬리 추가 측점 ▲ 뒤 앞 교점 끌기 [저장] = 990 m 편집 버림 · ▲ 잃음 · 최대 −0.50 m → 고친 뒤 버림 0 · 끌 때 = 저장 뒤 - 시험: test_498_2_grade_touch 새로 · helper_design_store_save 에 묶음 창구 가짜 하나(옛 길) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
107 lines
5.5 KiB
TypeScript
107 lines
5.5 KiB
TypeScript
/* =============================================================================
|
|
* A00_Common/design/design_pipeline_page_saved.ts
|
|
* 페이지 묶음의 **저장 기준** — 저장 정본 지문(노선 번호 · 지반 표본) · 종단도가 내준 저장 기준 · 저장 노선
|
|
* 계획고 편집 · 저장 PVI · 횡단 입력(cross). `design_pipeline_page.ts` 에서 갈라냄(700줄 한계 · 472-5).
|
|
* ========================================================================== */
|
|
|
|
import type { SectionDetailResponse } from "../../B06_Section/B06_Section_Api_Fetch";
|
|
import { savedSectionDetail } from "../../B06_Section/B06_Section_Section_Canon";
|
|
import {
|
|
emptyEdits,
|
|
toAlignmentBase,
|
|
type AlignmentEdits,
|
|
} from "../../B05_Profile/logic/B05_Profile_UI_Profile_Alignment";
|
|
import { readAlignmentDraft } from "../../B05_Profile/B05_Profile_UI_Profile_Edit";
|
|
import { readAlignment } from "../../B05_Profile/logic/B05_Profile_UI_Profile_Data";
|
|
import { pipelineCrossSource, type PipelineCrossSource } from "./design_pipeline_cross";
|
|
import type { PipelineStation } from "./logic/design_pipeline_types";
|
|
import type { PagePipelineOptions, ProfileLink } from "./design_pipeline_page_types";
|
|
|
|
export function createPageSaved(
|
|
projectId: string,
|
|
link: ProfileLink,
|
|
options: PagePipelineOptions,
|
|
/** 저장 노선 측점(열쇠) — 페이지가 저장분을 받을 때 셈. */
|
|
savedStations: () => PipelineStation[],
|
|
) {
|
|
/** 저장 정본 지문(노선 번호 · 지반 표본 배열) — 측점 갈아끼움(swap)이 만든 새 상세는 지반 표본 배열을
|
|
* 그대로 둠 → 정본 아님(묶음 출력 → 상세 → 다시 묶음 고리를 끊음). 상세 객체는 상세 가게 칸(472-5). */
|
|
let canon: { routeId: unknown; samples: unknown } | null = null;
|
|
/** 저장 정본 상세 = 상세 가게 칸(가게가 받거나 되돌린 객체 · 갈아끼움 제외). */
|
|
const canonDetail = (): SectionDetailResponse | null =>
|
|
typeof canon?.routeId === "number" ? savedSectionDetail(projectId, canon.routeId) : null;
|
|
/** 마지막으로 모은 횡단 입력(시설 제원 — 새 노선 상세가 씀). */
|
|
let crossSource: PipelineCrossSource | null = null;
|
|
/** 이 묶음이 지은 새 노선 상세들 — 횡단 보기 카드가 그것을 종단도에 그려도 저장 정본이 아님. */
|
|
const drafted = new WeakSet<SectionDetailResponse>();
|
|
let lastSaved: ReturnType<ProfileLink["pipelineSource"]> | null = null;
|
|
/** 종단도가 내준 저장 기준 — 종단도가 묶음 새 노선 상세를 그리는 동안은 그 앞 저장 기준(고리 끊음 ·
|
|
* 새 노선 상세 → 정본으로 오인 → 처음부터 다시 → 새 상세 … 349-0g). */
|
|
const savedSource = (): ReturnType<ProfileLink["pipelineSource"]> => {
|
|
const now = link.pipelineSource();
|
|
if (now.detail && drafted.has(now.detail)) return lastSaved ?? { ...now, detail: null };
|
|
return (lastSaved = now);
|
|
};
|
|
/** 저장 정본이 바뀌었나(새로 받은 상세 · 새 노선) — 바뀌었으면 잡아 둠. */
|
|
const canonChanged = (): boolean => {
|
|
const { detail = null, routeId } = savedSource();
|
|
const samples = detail?.longitudinal.samples;
|
|
if (canon && canon.routeId === routeId && canon.samples === samples) return false;
|
|
canon = { routeId, samples };
|
|
return true;
|
|
};
|
|
/** 저장 노선 계획고 편집(세션 초안 → 저장분) — 노선 초안을 버리면 이것으로 돌아옴. */
|
|
const savedEdits = (): AlignmentEdits => {
|
|
const routeId = canon?.routeId;
|
|
const longitudinal = canonDetail()?.longitudinal;
|
|
return (
|
|
(typeof routeId === "number" ? readAlignmentDraft(routeId) : null) ??
|
|
(longitudinal && readAlignment(longitudinal)?.edits) ??
|
|
emptyEdits()
|
|
);
|
|
};
|
|
const storedPvi = () => {
|
|
const detail = canonDetail();
|
|
const stored = detail && readAlignment(detail.longitudinal);
|
|
return stored ? toAlignmentBase(stored).basePvi : null;
|
|
};
|
|
/** 횡단 입력 — 부를 때마다 저장 상세 + 세션 고침 · 표준을 모음(상세 객체마다 기억하면 고침이 안 감 · 365-2). */
|
|
const crossNow = (): PipelineCrossSource | null => {
|
|
const routeId = canon?.routeId;
|
|
const source = pipelineCrossSource(
|
|
projectId,
|
|
canonDetail(),
|
|
savedStations(),
|
|
typeof routeId === "number" ? routeId : null,
|
|
options.stationKeys, // 초안 자리 측점 짝(457)
|
|
);
|
|
if (source) crossSource = source;
|
|
return source;
|
|
};
|
|
return {
|
|
savedSource,
|
|
canonChanged,
|
|
savedEdits,
|
|
/** 서버 저장분 계획고 편집(세션 초안 뺌) — 노선 바뀐 [저장]에서 서버가 옮기는 그 값(498-2). */
|
|
storedEdits(): AlignmentEdits {
|
|
const longitudinal = canonDetail()?.longitudinal;
|
|
return (longitudinal && readAlignment(longitudinal)?.edits) ?? emptyEdits();
|
|
},
|
|
storedPvi,
|
|
crossNow,
|
|
drafted,
|
|
/** 저장 정본 노선 번호(정본을 아직 안 잡았으면 undefined). */
|
|
canonRouteId: (): unknown => canon?.routeId,
|
|
/** 초안을 버려 되돌린 상세 = 저장 정본(다시 하기도 같은 기준). */
|
|
adoptCanon(routeId: unknown, detail: SectionDetailResponse): void {
|
|
canon = { routeId, samples: detail.longitudinal.samples };
|
|
},
|
|
/** 마지막 횡단 입력의 시설 제원(새 노선 상세가 씀). */
|
|
crossSpecs: () => crossSource?.specs ?? new Map(),
|
|
/** 저장분을 다시 받음 — 횡단 입력도 다시 모음. */
|
|
forgetCross(): void {
|
|
crossSource = null;
|
|
},
|
|
};
|
|
}
|