fix(482-1 노선 바뀜 구조물 측점): 노선 초안 중 되돌리기 · 다시하기가 관 · 구조물 · 추가 측점도 그 걸음 사진으로 묶음에 넣음 · 초안 측점 맞춤이 상세 틀(옛 · 새 노선)을 앎

- design_pipeline_page follow 되살림 차례 = 계획고 사진 + 가게 관 · 구조물 · 추가 측점(묶음 측점 유령 · 빠짐 없앰)
- Section_Store 가 노선 초안 동안 상세 틀을 정해 넘김 · Drafts = 옛 틀이면 저장분으로 맞춤 · 얹음 · 새 틀이면 저장분 종류 대조 안 함
- 새 시험 test_280_3_route_undo_facilities(헬퍼 둘 · 검증_sub4 읽기만) · 옛 코드에서 되돌리기 넷 실패

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-19 22:39:37 +09:00
co-authored by Claude Opus 5.5
parent afe6e4a799
commit 4da510f6df
6 changed files with 886 additions and 8 deletions
+14 -5
View File
@@ -33,6 +33,9 @@ import { useStationKeys, useStationOwners } from "./B06_Section_Station_Keys";
import { type CrossSection, type SectionDetailResponse } from "./B06_Section_Api_Fetch";
type Pipes = PendingPipes;
/** 노선 초안 동안 상세의 틀(280-3) — old = 옛 노선 누가거리(저장 정본 · 초안 전 상세 · 초안 대신 저장분으로
* 맞춤 · 얹음) · new = 묶음이 갈아끼운 새 노선 누가거리(저장분 종류 대조 안 함) · null = 노선 초안 없음. */
export type RouteFrame = "old" | "new" | null;
const near = (a: number, b: number): boolean => Math.abs(a - b) < SAME_STATION_M;
const byChainage = (a: { chainage_m: number }, b: { chainage_m: number }) =>
@@ -128,9 +131,11 @@ export async function withDraftShapes(
detail: SectionDetailResponse,
projectId: string,
swapped = false,
frame: RouteFrame = null,
): Promise<void> {
const pipesDraft = readPendingPipes(projectId);
const structuresDraft = readPendingStructures(projectId);
const old = frame === "old"; // 옛 틀 = 저장분으로 얹음(280-3)
const pipesDraft = old ? null : readPendingPipes(projectId);
const structuresDraft = old ? null : readPendingStructures(projectId);
const drafts = !!(pipesDraft || structuresDraft);
if (!drafts && !swapped && !drafted.has(detail)) return;
const inputs = await statusOf(projectId, pipesDraft, structuresDraft);
@@ -161,11 +166,13 @@ export async function withDraftStations(
detail: SectionDetailResponse,
projectId: string,
routeId: number,
frame: RouteFrame = null,
): Promise<void> {
const turn = (turns.get(detail) ?? 0) + 1;
turns.set(detail, turn);
const pipesDraft = readPendingPipes(projectId);
const structuresDraft = readPendingStructures(projectId);
const old = frame === "old"; // 새 틀 초안을 옛 틀 측점에 견주지 않음(280-3)
const pipesDraft = old ? null : readPendingPipes(projectId);
const structuresDraft = old ? null : readPendingStructures(projectId);
const all = [
...detail.cross_sections.filter((section) => !section.preview),
...(parked.get(detail) ?? []),
@@ -173,7 +180,7 @@ export async function withDraftStations(
let live = all;
let stale: CrossSection[] = [];
// 추가 측점 초안(368-2)도 측점 계획을 바꿈 — 계획은 그 초안을 스스로 읽음
if (!(pipesDraft || structuresDraft || readPlusDraft(projectId))) {
if (!(pipesDraft || structuresDraft || (!old && readPlusDraft(projectId)))) {
// 초안 없음 = 저장분 계획으로 열쇠 주인만 — 관 = 저장 id(계산 묶음 열쇠와 같음 · 첫 옮김도 열쇠째 · 415 H1)
const inputs = await statusOf(projectId, null, null);
if (inputs) {
@@ -210,7 +217,9 @@ export async function withDraftStations(
]
.sort()
.join(",");
// 새 틀 = 저장분(옛 틀 누가거리)과 같은 m 로 견주지 않음 — 측점 목록은 묶음 갈아끼움 몫(280-3)
const replaced = (section: CrossSection): boolean => {
if (frame === "new") return false;
const was = kindsAt(oldPipes, oldStructures, section.chainage_m);
return was !== "" && was !== kindsAt(pipes, structures, section.chainage_m);
};
+11 -2
View File
@@ -45,6 +45,7 @@ import {
keepHeldDetail,
keepSavedDetail,
savedDesigns,
savedSectionDetail,
sessionDetail,
} from "./B06_Section_Section_Canon";
import { fetchSectionDetail } from "./B06_Section_Api_Fetch";
@@ -90,8 +91,16 @@ async function withDraftWalls(
setGeneralStations(detail.longitudinal?.stations); // 구조물 기준 측점이 붙을 일반 측점(234-1)
setPlusStations(() => plusStationsOf(projectId)); // 측점 계획이 읽을 추가 측점(368-2)
await loadSavedPlusStations(projectId);
await withDraftStations(detail, projectId, routeId); // 옛 자리 숨김 · 새 자리 미리 뜬 횡단(273-2)
await withDraftShapes(detail, projectId);
// 노선 초안 동안 틀(280-3) — 저장 정본 · 초안 전 상세 = 옛 노선 틀 · 그 밖 = 묶음이 갈아끼운 새 노선 틀
const frame =
useDesignStore(projectId, null).get("routeDraft") === null
? null
: detail === savedSectionDetail(projectId, routeId) ||
detail === heldSectionDetail(projectId, routeId)
? "old"
: "new";
await withDraftStations(detail, projectId, routeId, frame); // 옛 자리 숨김 · 새 자리 미리 뜬 횡단(273-2)
await withDraftShapes(detail, projectId, false, frame);
await withAdjustsAndAreas(detail, projectId, routeId);
// 초안 자리 미리 뜬 횡단 = 서버가 저장 계획선으로 셈 · 묶음 cross 뒤에 얹힐 수 있음 — 다 돈 뒤 지금 계획선과
// 갈리면 cross 한 번 더(387-8 · 낡음 판정 = 가게 몫 · 종단 판이 접혀 그리기가 안 돌아도)