- A00_Common/design/design_store.ts — useDesignStore(projectId, routeId) get · set · subscribe
(structures · pipes · alignmentDraft · sectionDetail · selection) · 밑은 b_page_state 등록 키
(selection 등록 · alignmentDraft 는 옛 키 감쌈 — 브레인 판정 B)
- A00_Common/design/design_save.ts — saveDesign(ctx, {confirm}) 한 줄기:
관 → 구조물 → 계획고 → 암거 옵션 → 오르막 → 횡단 · B05 [임시저장] · B06 [저장] · [확정]이 같은 차례
- 계획고 초안 가게 노선마다 한 벌(B05 Profile_Edit 주인 · B06 Grade_Edit 는 useProfileEditStore)
- 관 목록 주인 = 가게 pipes(Pipes_Draft 창구)
- 시험: test_design_store_save 추가 · save_channels · save_recompute · save_roundtrip 새 차례로
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KmELpdXFDRZHhfbGuRhSmL
86 lines
3.9 KiB
TypeScript
86 lines
3.9 KiB
TypeScript
/* =============================================================================
|
|
* B06_Section_UI_Page_Grade_Edit.ts
|
|
* 종단 계획선 편집(▲/▼) 제공자. `_UI_Page` 700줄 제한 대응으로 떼어낸 것이며
|
|
* 동작은 그대로다(2026-09-13 분리).
|
|
* ========================================================================== */
|
|
|
|
import {
|
|
useProfileEditStore,
|
|
type ProfileEditStore,
|
|
} from "../B05_Profile/B05_Profile_UI_Profile_Edit";
|
|
import { readAlignment, toDesignProfile } from "../B05_Profile/B05_Profile_UI_Profile_Data";
|
|
import {
|
|
adjustStation,
|
|
buildAlignment,
|
|
toAlignmentBase,
|
|
} from "../B05_Profile/B05_Profile_UI_Profile_Alignment";
|
|
import type { SectionDetailResponse } from "./B06_Section_Api_Fetch";
|
|
import type { SectionViewController } from "./B06_Section_UI_Section_View";
|
|
|
|
type GradeEditProvider = NonNullable<Parameters<SectionViewController["setGradeEdit"]>[0]>;
|
|
|
|
export interface GradeEditContext {
|
|
routeId: () => number | null;
|
|
detail: () => SectionDetailResponse | null;
|
|
view: () => SectionViewController;
|
|
/** 전 측점 횡단 재계산 — 손을 뗀 뒤 한 번만 돈다. */
|
|
reconcile: () => Promise<void>;
|
|
}
|
|
|
|
/**
|
|
* 계획선 편집(▲/▼) — B05 종단 패널의 **같은 가게**(노선마다 한 벌)를 쓴다(계획서 24-2a ·
|
|
* 2026-09-12 사용자: B06 에만 버튼이 없었다). 누르면 그 자리에서 계획선·전 측점 횡단을 다시 풀고(`reconcile`),
|
|
* 영구저장은 [저장]·[확정]에서만 한다(CLAUDE.md 5장).
|
|
*/
|
|
export function createGradeEdit(ctx: GradeEditContext): GradeEditProvider {
|
|
let gradeStore: ProfileEditStore | null = null;
|
|
let gradeRouteId: number | null = null;
|
|
/** ▲▼ 길게 누르기는 초당 10회(`HOLD_INTERVAL_MS`) 들어온다 — 그보다 길게 잡아
|
|
* 누르는 동안은 선만 움직이고, 손을 뗀 뒤 재계산이 한 번 돈다. */
|
|
const GRADE_RECONCILE_DEBOUNCE_MS = 120;
|
|
let gradeReconcileTimer = 0;
|
|
const scheduleGradeReconcile = (): void => {
|
|
window.clearTimeout(gradeReconcileTimer);
|
|
gradeReconcileTimer = window.setTimeout(() => {
|
|
void ctx.reconcile().then(() => ctx.view().setGradeEdit(gradeEditFor));
|
|
}, GRADE_RECONCILE_DEBOUNCE_MS);
|
|
};
|
|
const gradeEditFor: GradeEditProvider = () => {
|
|
const detail = ctx.detail();
|
|
const currentRouteId = ctx.routeId();
|
|
if (!detail || currentRouteId === null) return null;
|
|
const stored = readAlignment(detail.longitudinal);
|
|
if (!stored) return null; // 선형 저장분이 없는 옛 노선 — 편집할 기준선이 없다.
|
|
if (!gradeStore || gradeRouteId !== currentRouteId) {
|
|
gradeRouteId = currentRouteId;
|
|
gradeStore = useProfileEditStore(currentRouteId, stored.edits, () => undefined);
|
|
}
|
|
const store = gradeStore;
|
|
const base = toAlignmentBase(stored);
|
|
const alignment = buildAlignment(base, store.edits());
|
|
return {
|
|
alignment,
|
|
stepM: alignment.policy.edit_step_m,
|
|
onStation: (chainageM, delta) => {
|
|
store.replace(adjustStation(base, store.edits(), chainageM, delta));
|
|
// ① 선은 **그 자리에서** 움직인다 — 그래프가 읽는 계획선(`design_profiles`)만
|
|
// 갈아 끼우고 다시 그린다(재계산을 기다리면 누른 뒤 한참 뒤에 움직였다).
|
|
const current = ctx.detail();
|
|
if (current) {
|
|
current.longitudinal.design_profiles = [
|
|
toDesignProfile(
|
|
buildAlignment(base, store.edits()),
|
|
current.longitudinal.design_profiles?.[0],
|
|
),
|
|
];
|
|
}
|
|
ctx.view().setGradeEdit(gradeEditFor);
|
|
// ② 전 측점 횡단 재계산·카드 갱신은 무겁다 — 마지막 한 번만(B05 프리뷰와 같은 규칙).
|
|
// 편집분은 세션 초안에 있으므로 재계산이 그것을 그대로 읽는다.
|
|
scheduleGradeReconcile();
|
|
},
|
|
};
|
|
};
|
|
return gradeEditFor;
|
|
}
|