fix(B06): 측점만 골랐을 때 기슭막이 조정창이 뜨지 않게 한다

원인: 앞선 커밋에서 넣은 '대표 벽 자동 선택'(selectDefaultWall)이 카드를 고를
때마다 벽을 골라 조정창까지 띄웠다(2026-08-29 사용자 보고: 기슭막이(유출) 창이
계속 떠 있음).

- selectDefaultWall과 그에 딸린 자동 선택 표시(withAutoAdopt 등)를 걷어냈다.
- 카드·목록 선택 리스너에서 남아 있는 벽 선택을 비운다. 벽을 찍어 카드가 딸려
  선택된 경우는 건드리지 않는다(isWallSelecting 가드).

부작용: 단 수·옵션 행은 도면에서 벽을 고른 뒤에만 유입구·유출구에 붙는다
(사용자 확인: 측점 선택 시 자동 구조물 선택은 필요 없음).

검증: 목록 선택·카드 선택 시 조정창 0개·강조 없음, 벽 클릭 시 기슭막이(유출) 창
+ 유출구 강조 + 단 수·옵션 행 표시.
This commit is contained in:
2026-08-29 16:28:11 +09:00
parent 068eac7f6a
commit a485e22851
3 changed files with 32 additions and 66 deletions
+2 -16
View File
@@ -21,20 +21,6 @@ export function setAdjustSideSlots(next: { inlet: HTMLElement; outlet: HTMLEleme
sideSlots = next;
}
/** 지금 붙는 사본이 **자동 선택**(카드를 골라 대표 벽이 딸려 온 경우)인가.
* 자동이면 그룹 강조를 켜지 않는다 — 강조는 도면에서 구조물을 직접 고를 때만
* 쓴다(2026-08-29 사용자 지시). */
let autoAdopt = false;
export function withAutoAdopt(run: () => void): void {
autoAdopt = true;
try {
run();
} finally {
autoAdopt = false;
}
}
/** 이식 자리가 지금 화면에 서 있는지 — 숨겨진 그룹(다른 시설)이면 옮기지 않는다. */
function slotUsable(target: HTMLElement | undefined): target is HTMLElement {
if (!target) return false;
@@ -67,8 +53,8 @@ function relocateSideRows(panelRoot: HTMLElement): void {
if (row.classList.contains("is-hidden")) return;
target.append(row);
});
// 도면에서 직접 고른 구조물만 그룹 테두리로 알린다(2026-08-29 사용자 지시 3).
if (!autoAdopt) target.closest("fieldset")?.classList.add("is-active");
// 고른 구조물이 어느 쪽인지 그룹 테두리로 알린다(2026-08-29 사용자 지시 3).
target.closest("fieldset")?.classList.add("is-active");
}
function ensureDock(): void {
+7 -21
View File
@@ -46,9 +46,9 @@ import { staleDesignChainages } from "./B06_Section_UI_Section_Common";
import { createStandardPanel, type StandardPanelController } from "./B06_Section_UI_Standard_Panel";
import {
createB06StructuresPanel,
isWallSelecting,
wireStructureSelection,
} from "./B06_Section_UI_Page_Structures_Panel";
import { withAutoAdopt } from "./B06_Section_UI_Adjust_Dock";
import "./B06_Section_UI_Style.css";
import "./B06_Section_UI_Style_Cross.css";
import "./B06_Section_UI_Style_Cross_Controls.css";
@@ -471,7 +471,6 @@ export async function renderB06ProfileCross(root: HTMLElement): Promise<void> {
stationControls,
() => sectionDetail,
structuresPanel,
(chainageM) => sectionView.refreshCard(chainageM),
);
// 횡단도(카드) 자체를 골라도 그 측점 구조물 정보를 폼에 올린다(2026-08-29 사용자).
// 연동으로 옆에서 넘어온 카드는 **소유 측점** 시설을 보여 준다.
@@ -486,27 +485,14 @@ export async function renderB06ProfileCross(root: HTMLElement): Promise<void> {
const owner = stationControls.structureSpan.ownerOf(target);
structuresPanel.showAtChainage(owner?.chainage_m ?? target.chainage_m);
structureSelection.syncInletStructure();
selectDefaultWall(owner ?? target);
// 카드만 고른 경우엔 구조물(벽·구체) 선택을 비운다 — 조정창이 저절로 뜨면 안 된다
// (2026-08-29 사용자). 벽을 찍어 카드가 딸려 선택된 경우는 건드리지 않는다.
if (!isWallSelecting() && stationControls.revetOffset.selectedFor(target)) {
stationControls.revetOffset.select(target.chainage_m, null);
sectionView.refreshCard(target.chainage_m);
}
});
/**
* 시설을 폼에 올릴 때 **대표 벽**(유출 기준벽, 없으면 유입)을 함께 고른다 —
* 단 수·옵션 행은 고른 벽에 딸린 것이라 벽이 없으면 유입구·유출구 그룹이 빈다
* (2026-08-29 사용자 보고). 이미 고른 벽이 있으면 건드리지 않는다.
*/
function selectDefaultWall(section: NonNullable<typeof sectionDetail>["cross_sections"][number]) {
const culvert = section.culvert;
if (!culvert) return;
if (stationControls.revetOffset.selectedFor(section)) return;
const key = culvert.outlet ? "outlet" : culvert.inlet ? "inlet" : null;
if (!key) return;
// 자동으로 딸려 온 선택이라 그룹 강조는 켜지 않는다(2026-08-29 사용자 지시).
withAutoAdopt(() => {
stationControls.revetOffset.select(section.chainage_m, key);
sectionView.refreshCard(section.chainage_m);
});
}
// 메인 영역: 종·횡단 도면(sectionView) 또는 안내 메시지를 표시한다.
const mainArea = document.createElement("div");
mainArea.className = "b06-profile__main";
@@ -24,12 +24,7 @@ import {
} from "../B05_Profile/B05_Profile_Api_Structures";
import { fetchDetailPipePoints } from "../B04_PreProcess/B04_PreProcess_Api_Fetch";
import { showToast } from "@ui/ui_template_elements";
import {
adjustDockRoot,
resetAdjustDock,
setAdjustSideSlots,
withAutoAdopt,
} from "./B06_Section_UI_Adjust_Dock";
import { adjustDockRoot, resetAdjustDock, setAdjustSideSlots } from "./B06_Section_UI_Adjust_Dock";
import type { SectionDetailResponse } from "./B06_Section_Api_Fetch";
import type { StationControls } from "./B06_Section_UI_Page_Station_Controls";
@@ -208,12 +203,26 @@ export function createB06StructuresPanel(deps: B06StructuresPanelDeps): B06Struc
* 구조물의 **소유 측점** 시설을 좌측 폼에 올린다(2026-08-29 일원화 3단계).
* 제어 객체의 select를 감싸기만 한다 — 조작·저장 경로는 그대로다.
*/
/** 지금 처리 중인 선택이 **도면에서 벽·구체를 찍은 것**인가 — 카드 선택 리스너가
* 이 값으로 "카드만 고른 경우"를 가려낸다(2026-08-29 사용자: 측점 선택 때 구조물이
* 자동으로 골라지면 안 된다). 같은 턴에서만 참이다. */
let wallSelecting = false;
export function isWallSelecting(): boolean {
return wallSelecting;
}
function markWallSelecting(): void {
wallSelecting = true;
queueMicrotask(() => {
wallSelecting = false;
});
}
export function wireStructureSelection(
stationControls: StationControls,
detail: () => SectionDetailResponse | null,
panel: B06StructuresPanel,
/** 대표 벽으로 되돌릴 때 카드를 다시 그린다 — 없으면 되돌리지 않는다. */
refreshCard?: (chainageM: number) => void,
): { syncInletStructure: () => void } {
const ownerChainageOf = (chainageM: number): number => {
const sectionAt = detail()?.cross_sections.find(
@@ -240,36 +249,21 @@ export function wireStructureSelection(
const origRevet = stationControls.revetOffset.select;
stationControls.revetOffset.select = (chainageM, key) => {
markWallSelecting();
origRevet(chainageM, key);
if (key) {
panel.showPipeAt(ownerChainageOf(chainageM));
syncInletStructure();
return;
}
// 선택을 풀어도 폼의 단 수·옵션 행은 남아야 한다 — 그 행들은 벽에 딸려 있으므로
// 대표 벽으로 조용히 되돌린다(강조만 꺼진다, 2026-08-29 사용자 지시).
const target = detail()?.cross_sections.find(
(entry) => Math.abs(entry.chainage_m - chainageM) < 0.01,
);
const fallback = target?.culvert ? (target.culvert.outlet ? "outlet" : "inlet") : null;
if (!fallback || !refreshCard) {
panel.showPipeAt(null);
return;
}
withAutoAdopt(() => {
origRevet(chainageM, fallback);
refreshCard(chainageM);
});
panel.showPipeAt(ownerChainageOf(chainageM));
syncInletStructure();
panel.showPipeAt(key ? ownerChainageOf(chainageM) : null);
if (key) syncInletStructure();
};
const origFord = stationControls.ford.select;
stationControls.ford.select = (chainageM, role) => {
markWallSelecting();
origFord(chainageM, role);
panel.showPipeAt(role ? chainageM : null);
};
const origBox = stationControls.box.select;
stationControls.box.select = (chainageM, role) => {
markWallSelecting();
origBox(chainageM, role);
panel.showPipeAt(role ? chainageM : null);
};