Files
Aislo/B05_Profile/logic/B05_Profile_Drainage_Live.ts
T
eomsangdonandClaude Opus 5.5 44ffb99559 fix(B05 배수유역): 349 수동 [업데이트] 답 머묾 · 저장 뒤 낡음 — 답 받기 = 차례 + 입력 지문
- 묶음 drainage 단계 입력 지문(노선 초안 rev 뺌 · 관 id · 자리 cm) — 같은 노선 · 관으로 다시 돈 묶음은 흘려보냄(떠 있는 요청 안 끊음 · 다시 안 흐림)
- 차례 번호는 요청마다 하나 · 답은 차례 + 지문이 지금과 같을 때만 받음
- 서버 답이 「낡음」(노선 [저장] 뒤 등) = 수동은 흐림 + [업데이트] · 자동은 3 s 뒤 조용히(markStale)
- 시험 test_349_drainage_live_flow(가짜 DOM · 시계 · fetch 로 화면 파일 실행 — 수동 · 자동 · 제안 [적용]) · 347-2 헬퍼 새 받기 규칙
- PLAN.md 349-0b

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XWh5wNNycMkbwMpACz1rte
2026-10-16 14:14:32 +09:00

55 lines
2.7 KiB
TypeScript

/* =============================================================================
* B05_Profile/logic/B05_Profile_Drainage_Live.ts
* 배수유역 자동/수동 다시 셈(347-2) — 순수 규칙만. 화면 · fetch 는 `B05_Profile_UI_Drainage_Live.ts`.
*
* - 대상 = 평면(노선 초안) · 관 자리만 — 종단 · 횡단 조작은 배수유역 결과를 안 바꿈(묶음 deps 와 같음).
* - 노선 초안이 없으면(저장 노선 그대로) 낡음 아님 — 관 조작은 세부 유역 나눔(0.2 s)이 바로 맞춤.
* - 자동 = 조용한 뒤 `QUIET_MS` · 수동 = 흐림 + [업데이트] · 기본 수동.
* - 묶음이 같은 입력으로 다시 돌면(입력 지문 같음) 낡음 · 떠 있는 요청을 그대로 둠.
* - 답 채택 = 보낸 차례 · 입력 지문이 지금과 같고 서버가 그만두지 않았을 때만(늦은 답 버림).
* ========================================================================== */
export type DrainageMode = "manual" | "auto";
/** 자동 모드 — 마지막 조작 뒤 이만큼 조용하면 셈(ms · 341 결정 거리 6 · 3 초). */
export const QUIET_MS = 3000;
/** 계정 화면 설정 글자 → 모드(없거나 모르는 값 = 수동). */
export const parseDrainageMode = (raw: string | null | undefined): DrainageMode =>
raw === "auto" ? "auto" : "manual";
/** 묶음 drainage 단계 입력 → 낡았는가 — 노선 초안이 있을 때만. */
export const draftMakesStale = (route: unknown): boolean => route !== null && route !== undefined;
/** 묶음 drainage 입력 지문 — 노선 초안(판 번호 rev 뺌) · 관 id · 자리(cm). */
export function inputKey(route: unknown, pipes: unknown): string {
const draft = route && typeof route === "object" ? { ...route, rev: undefined } : null;
const spots = Array.isArray(pipes)
? pipes.map((pipe) => `${pipe?.id ?? ""}@${Math.round(Number(pipe?.chainage_m) * 100)}`).sort()
: [];
return JSON.stringify([draft, spots]);
}
/** 「지금 노선으로 셈」 몸통 — 서버 `post_drainage_live`. */
export function liveRequestBody<P>(
generation: number,
route: unknown,
points: P[],
): { generation: number; route: unknown; points: P[] } {
return { generation, route: route ?? null, points };
}
/** 답을 화면에 올리는가 — 서버가 그만둔 답 · 옛 차례 · 입력이 바뀐 뒤 답은 버림. */
export function acceptLive(
response: { status?: string; generation?: number },
sent: { generation: number; key: string },
now: { generation: number; key: string },
): boolean {
return (
response.status !== "superseded" &&
sent.generation === now.generation &&
sent.key === now.key &&
(response.generation === undefined || response.generation === sent.generation)
);
}