- 구조물 초안 쓰기 = useDesignStore().set("structures")(칸 그대로) → 관 초안과 같은 구독 · 횡단 보기 watchDrafts(구조물 = 늘 · 관 = 자리 · 종류 · 구간 · 잇기가 바뀔 때만 · 옵션만은 폼 길이 그 카드만 · 카드 줌 · 팬 지킴) · 옛 되부름 onStructuresChanged 걷음
- 종류 바꿈 = 표(catalog) swapsInPlace — 정본 다름 · 구조물 자리꼴 다름(E · F) = 지우고 같은 기준 측점에 새로(구간 = 기본 길이) · 같으면 종류 키만 · 막히면 옛 기록 · 옛 종류 폼 + 알림(전엔 [수정] 조기 반환 → 조용히 되돌림 · 드롭다운만 새 종류)
- syncApplied = 사용자가 조작한 세션이 있을 때만 깎음(카드 그리기가 자동 배치를 조정값으로 굳혀 [저장]으로 내보내던 것)
- replayDraftPipeOptions 걷음 — 그림 자료는 형상 얹기(초안 현황) · 다단 조정값은 조정 세션이 정본
- 시험: test_323_6_change(신호 · 거르기 · 표 규칙 · 그리기 · 걷음) · test_319 점형 ↔ 구간형 · 막힘 알림 · 되얹기 시험 = 형상 얹기로 · 옛 기대 글 고침
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ji4nuyLVHcxrXWHTdb5nRD
78 lines
3.5 KiB
TypeScript
78 lines
3.5 KiB
TypeScript
/* =============================================================================
|
|
* A00_Common/design/design_structure_status.ts
|
|
* 구조물 현황 한 벌(322-3) — 저장분 둘(관 `pipe_points.json` · 구조물 `structures.json`) + 초안 둘(세션)
|
|
* → 한 목록(초안이 있으면 초안 · 없으면 저장분 · 종류마다 따로) · 측점 계획 한 벌(`planStations`) →
|
|
* 종단 측점 목록(B05 종단 · 3D 막대 · B06 종단 띠가 같은 꼴).
|
|
*
|
|
* 구조물 id = 구조물은 structure_id · 관은 세션 id(`design_pipe_ids` · 323-5 · 파일 모양 그대로 · 저장 안 함).
|
|
* ========================================================================== */
|
|
|
|
import type { IrregularStation } from "../../B05_Profile/B05_Profile_UI_IrregularStations";
|
|
import type { PlannedStation } from "../../common_util/common_util_structure_station";
|
|
import { useDesignStore, type DesignStoreValues } from "./design_store";
|
|
|
|
/** 현황 — 종류마다 초안이 앞섬(초안 null = 만진 적 없음 · 빈 목록 = 다 지움). */
|
|
export function structureStatus<P, S>(
|
|
saved: readonly [ReadonlyArray<P>, ReadonlyArray<S>],
|
|
drafts: readonly [ReadonlyArray<P> | null, ReadonlyArray<S> | null],
|
|
): { pipes: P[]; structures: S[] } {
|
|
return { pipes: [...(drafts[0] ?? saved[0])], structures: [...(drafts[1] ?? saved[1])] };
|
|
}
|
|
|
|
/**
|
|
* 측점 계획 → 종단 측점(측점번호 · 잔여거리 = 간격 기준) — 기준 측점 id = 첫 주인 id(관 = `pipe-…` ·
|
|
* 구조물 = structure_id) · 시작 · 끝 = `{id}:{역할}`(옮겨도 계획고 편집이 따라감 · 272) · 관 기준 측점 =
|
|
* 「배관」 꼴(관 끌기 · 지우기 길).
|
|
*/
|
|
export function plannedIrregular(
|
|
planned: ReadonlyArray<PlannedStation>,
|
|
intervalM: number,
|
|
): IrregularStation[] {
|
|
const interval = intervalM > 0 ? intervalM : 20;
|
|
return planned.map((station) => {
|
|
const owner = station.owners[0];
|
|
const pipe = owner.startsWith("pipe-") && station.role === "anchor";
|
|
const number = Math.floor(station.chainage_m / interval);
|
|
return {
|
|
id: station.role === "anchor" ? owner : `${owner}:${station.role}`,
|
|
station: number,
|
|
remainder: station.chainage_m - number * interval,
|
|
chainage_m: station.chainage_m,
|
|
structure: station.title,
|
|
...(pipe ? { structureType: "배관" as const, origin: "pipe" as const } : {}),
|
|
};
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 바뀜 신호 하나(323-6) — 관 · 구조물 초안을 구독(어느 길로 쓰든 설계 가게 한 곳). 구조물 = 늘 · 관 = 자리 · 종류 ·
|
|
* 구간 · 잇기가 바뀔 때만(옵션만 고친 것은 폼 길 `applyPipeOptions` 가 그 카드만 고침 — 카드 줌 · 팬 지킴).
|
|
* 돌려주는 함수로 끊음.
|
|
*/
|
|
export function watchDrafts(projectId: string | null, onChange: () => void): () => void {
|
|
const shop = useDesignStore(projectId, null);
|
|
type Pipe = NonNullable<DesignStoreValues["pipes"]>[number];
|
|
const layout = (pipes: ReadonlyArray<Pipe> | null): string =>
|
|
JSON.stringify(
|
|
(pipes ?? []).map((p) => [
|
|
p.chainage_m,
|
|
p.facility ?? "pipe",
|
|
p.start_m ?? null,
|
|
p.end_m ?? null,
|
|
p.summary_item ?? null,
|
|
p.group_items ?? null,
|
|
]),
|
|
);
|
|
let seen = layout(shop.get("pipes"));
|
|
const offs = [
|
|
shop.subscribe("structures", onChange),
|
|
shop.subscribe("pipes", (pipes) => {
|
|
const key = layout(pipes);
|
|
if (key === seen) return;
|
|
seen = key;
|
|
onChange();
|
|
}),
|
|
];
|
|
return () => offs.forEach((off) => off());
|
|
}
|