- 횡단 다시 셈이 화면이 쥔 선(측점 한 벌 · 관 지점 · 옮긴 꼭짓점)을 받음 — 종단도가 선을 맡기고 B06 진입 정합 · 3D [업데이트] 앞 다시 셈도 같은 선 · 낡음 판정도 그 선 기준(staleAgainstScreen) - 다시 셈 뒤에도 낡은 측점이 남으면 유토곡선은 그리고 그 측점만 표시 · 콘솔 경고 한 줄 · 흙 배분도 건너뛰지 않음(09-03 「새 값만 보여주기」 바꿈 · 사용자 확정 10-16) - 흙 배분: 실패한 열쇠 다시 보냄 · 받은 열쇠(누가토량 결과 전체)는 다시 안 물음 · 서버도 같은 열쇠 기억 · 묶음 실패는 500 - 옛 시험 셋 새 동작으로 맞춤 · 서버 열쇠 시험 더함 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QfHKQs7J3hQELKMWQMUJEy
109 lines
4.9 KiB
TypeScript
109 lines
4.9 KiB
TypeScript
/* =============================================================================
|
|
* B05_Profile_UI_Profile_Preview.ts
|
|
* 계획선 편집 → 횡단 설계 프리뷰 반영 (패널 본체에서 분리, 2026-09-02 · 700줄 한계).
|
|
*
|
|
* 계획고가 바뀌면 측점별 횡단 단면적도 바뀐다 — 서버에 한 번 물어 전 측점을 다시 계산해
|
|
* **공유 캐시가 들고 있는 같은 객체**를 제자리 갱신한다. 그래야 횡단 기준 유토곡선과
|
|
* 3D 예상형상이 같은 값으로 따라온다(2026-08-03·08-23 사용자 보고).
|
|
*
|
|
* 끌기 중에는 계속 호출되므로 디바운스하고, 늦게 온 응답은 seq 비교로 버린다.
|
|
* ========================================================================== */
|
|
|
|
import type { AlignmentEdits, ProfileAlignment } from "./B05_Profile_UI_Profile_Alignment";
|
|
import { holdScreenAlignment, refreshCrossDesigns } from "../B06_Section/B06_Section_Cross_Refresh";
|
|
import { staleChainages } from "../B06_Section/B06_Section_UI_Section_Common";
|
|
import type { SectionDetailResponse } from "../B06_Section/B06_Section_Api_Fetch";
|
|
|
|
export interface CrossPreviewContext {
|
|
projectId: string;
|
|
detail: () => SectionDetailResponse | null;
|
|
routeId: () => number | null;
|
|
edits: () => AlignmentEdits;
|
|
/** 화면이 쥔 계획선(측점 한 벌) — 다시 셈 · B06 · 3D 가 같은 선을 받음(342-1). */
|
|
alignment: () => ProfileAlignment | null;
|
|
/** 부를 때마다 읽음 — 보기마다 다름. */
|
|
debounceMs: () => number;
|
|
/** 반영이 끝난 뒤 다시 그린다 — 다시 계산한 측점 누가거리를 넘긴다(횡단 카드 갱신용). */
|
|
onApplied: (updated: number[]) => void;
|
|
}
|
|
|
|
export interface CrossPreview {
|
|
/** 편집이 있을 때마다 부른다 — 마지막 값만 서버로 나간다. */
|
|
schedule: () => void;
|
|
/**
|
|
* 그리기가 잰 낡음 지문 — 새 지문일 때만 `schedule`(같은 낡음 되풀이 · 서버 폴백 반복 막음 · 317-1).
|
|
* 돌려주는 값 = 다시 셈을 기다리는 중인가. 다시 셈 뒤에도 남은 낡음은 false — 곡선은 그리고
|
|
* 그 측점만 표시(342-1 · 09-03 「새 값만 보여주기」를 바꿈 · 사용자 확정 10-16).
|
|
*/
|
|
scheduleIfStale: (key: string) => boolean;
|
|
/** 패널을 걷을 때 대기 중인 요청 타이머를 끈다. */
|
|
dispose: () => void;
|
|
}
|
|
|
|
export function createCrossPreview(ctx: CrossPreviewContext): CrossPreview {
|
|
let timer = 0;
|
|
let seq = 0;
|
|
let lastStale = "";
|
|
/** 다시 셈 예약 · 진행 중 — 이 동안의 낡음은 「다시 계산 중」. */
|
|
let busy = false;
|
|
let warned = "";
|
|
const release = holdScreenAlignment((routeId) =>
|
|
routeId === ctx.routeId() ? ctx.alignment() : null,
|
|
);
|
|
|
|
const preview: CrossPreview = {
|
|
scheduleIfStale(key) {
|
|
if (key && key !== lastStale) preview.schedule();
|
|
else if (key && !busy && key !== warned) {
|
|
warned = key;
|
|
console.warn(
|
|
`[횡단] 다시 셈 뒤에도 낡은 측점 ${staleChainages(key).length}곳 — 곡선은 그리고 그 측점만 표시`,
|
|
staleChainages(key),
|
|
);
|
|
}
|
|
lastStale = key;
|
|
return key !== "" && busy;
|
|
},
|
|
schedule() {
|
|
if (!ctx.detail() || ctx.routeId() === null) return;
|
|
busy = true;
|
|
window.clearTimeout(timer);
|
|
timer = window.setTimeout(() => {
|
|
const detail = ctx.detail();
|
|
const routeId = ctx.routeId();
|
|
if (!detail || routeId === null) return void (busy = false);
|
|
const current = (seq += 1);
|
|
// 재계산은 B06과 **같은 창구**를 쓴다 — 표준 단면값·암 경계 오프셋이 빠지면 서버가
|
|
// 다른 설계를 그려 같은 데이터가 두 화면에서 다른 값이 된다(2026-09-03 일원화).
|
|
const isCurrent = (): boolean =>
|
|
current === seq && ctx.detail() === detail && ctx.routeId() === routeId;
|
|
void refreshCrossDesigns({
|
|
projectId: ctx.projectId,
|
|
routeId,
|
|
detail,
|
|
edits: ctx.edits(),
|
|
alignment: ctx.alignment(),
|
|
// 늦게 온 옛 응답이 새 설계를 덮지 않게 반영 직전에 한 번 더 확인한다.
|
|
shouldApply: isCurrent,
|
|
})
|
|
.then((updated) => {
|
|
if (current === seq) busy = false;
|
|
// 남은 낡음이 있으면 바뀐 것이 없어도 다시 그림 — 「다시 계산 중」에 멈추지 않게(342-1)
|
|
if (updated.length || lastStale) ctx.onApplied(updated);
|
|
})
|
|
.catch(() => {
|
|
/* 프리뷰 실패는 무시 — 화면의 계획선은 그대로 두고 다음 편집에서 다시 시도한다. */
|
|
if (current !== seq) return;
|
|
busy = false;
|
|
if (lastStale) ctx.onApplied([]);
|
|
});
|
|
}, ctx.debounceMs());
|
|
},
|
|
dispose() {
|
|
window.clearTimeout(timer);
|
|
release();
|
|
},
|
|
};
|
|
return preview;
|
|
}
|