- 판정 = 저장 노선 대 초안이 그릴 선 정점 1 mm(`routeShapeChanged` · 파이썬 `route_shape_changed` 짝) · 스냅 · 간격 · 지형만 = 아님 - 띠 = 평면(노선 편집) 위 한 줄 · B06 평면 패널로 같이 옮겨짐 · 저장 노선 = 페이지 자료 줄 `pageRoutePlan`(조작마다 안 물음) - [저장] 확인 창 = 잠금 막 · 서버 요청 앞 · 구조물 · 관 · 추가 측점 · 종단 편집 수 · [취소] = 요청 0 · 추천 [적용] 같은 글 · 수 - 저장 뒤 = 응답 `steps.route.route_reset` 지운 수 한 줄 · 초기화면 세션 초안 통째 비움 → 서버 정본으로 다시 세움 · 옛 서버(칸 없음) = 알림 건너뜀 - 시험: 새 test_283_route_reset_confirm(띠 · 확인 창 수 · [취소] · 스냅만 · 거울) · 저장 헬퍼 셋 확인 창 가짜 · 476-2 확인 글 기대 고침 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
78 lines
3.7 KiB
TypeScript
78 lines
3.7 KiB
TypeScript
/* =============================================================================
|
|
* B05_Profile/logic/B05_Profile_Route_Reset.ts
|
|
* 노선 모양 바뀐 [저장] = 초기화(요구 283 · 284 · 285 · 492-2) — 브라우저 판정 · 띠 글 · 확인 창 글 · 저장 뒤 알림 글.
|
|
*
|
|
* 판정 = 저장 노선(그린 선) 대 초안이 그릴 선(`draftLine` · 서버가 쓰는 자릿수) — `routeShapeChanged`
|
|
* (짝 = 파이썬 `B05_Profile_Engine_Grade_Carry.route_shape_changed` · 정점 1 mm · 거울 시험
|
|
* resources/tester/test_283_route_reset_confirm.py). 스냅 켬끔 · 간격만 = 선 그대로 = 초기화 아님.
|
|
* 정본은 서버 판정(응답 `route_reset`) — 여기는 저장 전에 무엇이 지워지는지 알리는 몫.
|
|
* ========================================================================== */
|
|
|
|
import type { RouteDraft } from "../../A00_Common/design/logic/design_pipeline_types";
|
|
import { routeShapeChanged } from "./B05_Profile_Grade_Carry";
|
|
import { draftLine } from "./B05_Profile_Pipeline_RouteGround";
|
|
|
|
type Vertex = [number, number];
|
|
|
|
/** 지금 캐시에서 지워질 수 — 사용자 구조물 · 관 · 추가 측점 · 종단 편집. */
|
|
export interface RouteResetCounts {
|
|
structures: number;
|
|
pipes: number;
|
|
plusStations: number;
|
|
profileEdits: number;
|
|
}
|
|
|
|
/** 서버 응답 `route_reset`(sub4 약속) — 초기화했나 · 지운 수. */
|
|
export interface RouteReset {
|
|
reset: boolean;
|
|
dropped?: { structures?: number; pipes?: number; plus_stations?: number };
|
|
}
|
|
|
|
export const ROUTE_RESET_BAND =
|
|
"노선이 바뀌어 [저장] 하면 초기화 — 구조물 · 관 · 추가 측점 · 종단 · 횡단 손 입력이 지워지고 새 노선으로 다시 셈";
|
|
|
|
const xy = (line: ReadonlyArray<Vertex>) => line.map(([x, y]) => ({ x, y }));
|
|
|
|
/** 초안이 저장 노선 모양을 바꾸나 — 초안 없음 = 아님 · 저장 선을 모름 = 바뀜으로 봄(묻는 쪽이 안전). */
|
|
export function draftShapeChanged(
|
|
savedLine: ReadonlyArray<Vertex> | null,
|
|
draft: RouteDraft | null,
|
|
minRadiusM: number,
|
|
): boolean {
|
|
if (!draft?.nodes || draft.nodes.length < 2) return false;
|
|
if (!savedLine || savedLine.length < 2) return true;
|
|
return routeShapeChanged(xy(savedLine), xy(draftLine(draft, minRadiusM).line));
|
|
}
|
|
|
|
/** 확인 창 글 — [저장](노선 고침) · [적용](추천 노선) 같은 글 · 수. */
|
|
export function routeResetConfirmText(counts: RouteResetCounts, action: "저장" | "적용"): string {
|
|
const head = action === "저장" ? "노선이 바뀌어 [저장]하면" : "추천 노선을 [적용]하면";
|
|
return (
|
|
`${head} 초기화합니다 — 구조물 ${counts.structures} · 관 ${counts.pipes} · ` +
|
|
`추가 측점 ${counts.plusStations} · 종단 편집 ${counts.profileEdits} · 횡단 손 입력이 지워지고 ` +
|
|
`새 노선으로 다시 셉니다(세류선 교차 관 · 측점 · 초기 종단 · 횡단). ${action}할까요?`
|
|
);
|
|
}
|
|
|
|
/** 모양 바뀐 초안이면 묻고 답(지워질 수는 물을 때만 셈) · 안 바뀌면 묻지 않고 true. */
|
|
export async function askRouteReset(
|
|
changed: boolean,
|
|
counts: () => Promise<RouteResetCounts>,
|
|
ask: (text: string) => Promise<boolean>,
|
|
): Promise<boolean> {
|
|
return !changed || ask(routeResetConfirmText(await counts(), "저장"));
|
|
}
|
|
|
|
/** 저장 뒤 알림 한 줄 — 초기화가 아니면 null. */
|
|
export function routeResetNotice(
|
|
reset: RouteReset | null | undefined,
|
|
crossing = 0,
|
|
): string | null {
|
|
if (!reset?.reset) return null;
|
|
const dropped = reset.dropped ?? {};
|
|
return (
|
|
`노선이 바뀌어 초기화했습니다 — 지움: 구조물 ${dropped.structures ?? 0} · 관 ${dropped.pipes ?? 0} · ` +
|
|
`추가 측점 ${dropped.plus_stations ?? 0} · 새 교차 관 ${crossing}`
|
|
);
|
|
}
|