feat(B05): 부속 옵션 폼을 사이드 구조물 배치 섹션으로 이동

- 구조물 수정은 사이드 패널이 정위치(2026-08-17 사용자 지시) — 시설 편집 폼
  DOM을 배수유역 패널에서 분리(DrainagePanel.facilityForm)해 구조물 배치
  섹션 목록 위에 마운트(mountFacilityForm). 데이터·정본 동기화는 배수유역
  패널 소유 유지, 위치만 이동
- 전역 선택 동기화(97dd7cb9)와 결합: 리스트·그래프·3D·배수유역도 어느
  경로든 사이드에서 폼 개방. A군 [추가] 시 자동 선택으로 즉시 폼 개방
- 사이드 폭 대응 CSS flex-wrap. typecheck/build 통과
This commit is contained in:
2026-08-17 14:50:21 +09:00
parent 97dd7cb968
commit 1e4da21dbc
4 changed files with 26 additions and 9 deletions
+7 -9
View File
@@ -91,6 +91,9 @@ export interface DrainagePanel {
/** 밖(리스트·그래프·3D)에서 관을 고른다 — 마커 선택·시설 폼·유역 강조까지 연다.
* 이미 같으면 무시(2026-08-17 전역 선택 동기화). */
selectPipeAtChainage: (chainageM: number | null) => void;
/** 부속 옵션 폼(시설 편집) DOM — 사이드 「구조물 배치」 섹션이 가져다 붙인다
* (구조물 편집은 사이드 패널이 정위치, 2026-08-17 사용자 지시). */
facilityForm: HTMLElement;
/** 측점 선택 마킹 — 계획선 위 해당 누가거리에 표식을 그린다(null이면 지움). */
markStation: (chainageM: number | null) => void;
dispose: () => void;
@@ -204,15 +207,9 @@ export function createDrainagePanel(callbacks: DrainagePanelCallbacks = {}): Dra
},
});
root.append(
panelHandle.root,
widthResizer.root,
header,
viewport,
facilityEditor.root,
summary,
basinList,
);
root.append(panelHandle.root, widthResizer.root, header, viewport, summary, basinList);
// 시설 폼은 여기 두지 않는다 — 사이드 「구조물 배치」 섹션이 `facilityForm`으로
// 가져다 붙인다(구조물 편집은 사이드가 정위치, 2026-08-17 사용자 지시).
let projectId: string | null = null;
let meta: VWorldMeta | null = null;
@@ -772,6 +769,7 @@ export function createDrainagePanel(callbacks: DrainagePanelCallbacks = {}): Dra
syncPipeSelection();
scheduleDraw();
},
facilityForm: facilityEditor.root,
async savePipes() {
if (!projectId) return 0;
const response = await saveDetailPipePoints(
+5
View File
@@ -396,6 +396,11 @@ export async function renderB05Route(root: HTMLElement): Promise<void> {
if (currentSectionDetail) renderStationLines(currentSectionDetail);
}
// 부속 옵션 폼(시설 편집)은 사이드 「구조물 배치」 섹션 안에 붙인다 — 구조물
// 편집은 사이드가 정위치(2026-08-17 사용자 지시). 폼 데이터는 배수유역 패널이
// 정본(pipe_points)과 동기화한다.
panel.structures.mountFacilityForm(profilePanel.drainage.facilityForm);
viewer.markers.onChange(markStale);
viewer.markers.onSelectionChange(panel.setSelected);
viewer.markers.onStationSelectionChange((stationId) => {
@@ -62,6 +62,10 @@ export interface StructuresSection {
getStructures: () => StructureInstance[];
/** 계곡 통과 시설 목록을 병합 표시한다(정본 = pipe_points, 배수유역 패널 경유). */
setPipeFacilities: (pipes: PipeFacilityItem[]) => void;
/** 부속 옵션 폼(배수유역 패널 소유 시설 편집 DOM)을 이 섹션 안에 붙인다 —
* 구조물 편집은 사이드 패널이 정위치(2026-08-17 사용자 지시). 표시/숨김은
* 폼 스스로(선택된 관이 없으면 hidden) 관리한다. */
mountFacilityForm: (element: HTMLElement) => void;
/** 그래프·3D에서 고른 계곡 통과 시설을 목록에서 강조한다(null = 해제). */
selectPipeByChainage: (chainageM: number | null) => void;
/** 종단도·3D에서 고른 구조물을 폼에 올린다. null이면 선택 해제. */
@@ -616,6 +620,10 @@ export function createStructuresSection(callbacks: StructuresCallbacks): Structu
renderList();
},
getStructures: () => [...structures],
mountFacilityForm(element) {
// 목록 위, 액션 버튼 다음 — 계곡 시설을 고르면 그 자리에서 부속 옵션을 편집한다.
body.insertBefore(element, list);
},
setPipeFacilities(pipes) {
pipeFacilities = pipes.map((pipe) => ({ ...pipe }));
if (
@@ -97,6 +97,12 @@
.b05-drainage__facility .b05-route__irregular-row {
display: flex;
gap: 6px;
/* 사이드 「구조물 배치」 섹션 폭에서는 행이 줄바꿈되며 들어간다(2026-08-17 이동). */
flex-wrap: wrap;
}
.b05-drainage__facility .b05-route__field {
min-width: 96px;
}
.b05-drainage__facility .b05-route__field {