Merge remote-tracking branch 'origin/sub_laptop_4' into sub_laptop_5

This commit is contained in:
2026-10-06 00:11:56 +09:00
8 changed files with 213 additions and 6 deletions
@@ -85,6 +85,8 @@ export interface B06StructuresPanelDeps {
stationInterval: () => number;
/** 목록·폼에서 고른 시설의 측점 카드를 선택·스크롤한다. */
focusChainage: (chainageM: number) => void;
/** 종단 알약 강조를 목록에서 고른 것에 맞춘다(null = 관 · 해제 — 측점선 짝을 따름). */
markStructure?: (structureId: string | null) => void;
/** 목록이 바뀔 때마다 종단 알약 레인에 같은 목록을 넘긴다(2026-09-07 표시 통일). */
onMarks?: (structures: StructureInstance[], types: StructureType[]) => void;
/** 바뀐 값을 그 측점 횡단 캐시(culvert 스펙)에 얹고 카드를 다시 그린다 —
@@ -116,6 +118,10 @@ export interface B06StructuresPanel {
releasePipe: () => void;
/** 그 측점에서 폼이 열 항목을 **열지 않고** 고름 값으로 풀어 준다(세션에 적는 데 쓴다). */
selectionAt: (chainageM: number | null) => DesignSelection;
/** 다음 카드 고름이 측점보다 먼저 열 구조물 — 알약 · 넘김값이 누른 것(null = 측점 규칙대로). */
prefer: (structureId: string | null) => void;
/** 구조물 하나를 폼에 올리고 그 카드로 간다 — 알약을 누른 길(목록 클릭과 같은 흐름). */
selectStructure: (structureId: string) => void;
/** 지금 목록의 구조물 정본(미저장분 포함) — 카드 찾기에 쓴다. */
getStructures: () => StructureInstance[];
/** 지금 폼에 올라온 계곡 통과 시설의 누가거리(없으면 null). */
@@ -148,6 +154,8 @@ export function createB06StructuresPanel(deps: B06StructuresPanelDeps): B06Struc
);
let markTypes: StructureType[] = [];
/** 다음 카드 고름이 열 구조물 — 같은 측점에 관이 있어도 누른 것이 먼저다(52-15). */
let preferredId: string | null = null;
/** 종단 알약 레인에 올릴 목록 — 구조물 정본 + 관 정본(가상 구조물). */
const pushMarks = (): void =>
deps.onMarks?.([...structures, ...pipesToStructureMarks(pipeFacilities)], markTypes);
@@ -164,7 +172,12 @@ export function createB06StructuresPanel(deps: B06StructuresPanelDeps): B06Struc
deps.onStructuresChanged?.();
},
onSelect: (structure) => {
if (structure) deps.focusChainage(structureAnchorM(structure));
if (!structure) return;
deps.markStructure?.(structure.structure_id ?? null);
// 카드 고름이 측점으로 다시 풀면 같은 측점 관이 먼저 열린다 — 누른 구조물을 넘긴다.
preferredId = structure.structure_id ?? null;
deps.focusChainage(structureAnchorM(structure));
preferredId = null;
},
getInterval: deps.stationInterval,
// 관 추가 — 정본은 [저장]·[확정]에서 나간다. 화면 목록·알약은 바로 세운다.
@@ -241,6 +254,7 @@ export function createB06StructuresPanel(deps: B06StructuresPanelDeps): B06Struc
},
onPipeRemove: (chainageM) => removePipeAt(chainageM),
onPipeSelect: (chainageM) => {
deps.markStructure?.(null); // 알약 강조는 관 측점선 짝으로(같은 측점 구조물 강조를 푼다).
// 목록에서 고른 것도 세션에 남긴다 — B05로 돌아가면 그 시설이 그대로 열린다.
selectDesign(
deps.projectId,
@@ -464,9 +478,13 @@ export function createB06StructuresPanel(deps: B06StructuresPanelDeps): B06Struc
const selection = { chainageM, structureId: null };
return { chainageM, structureId: section.resolveAt(selection).structureId };
},
prefer: (structureId) => {
preferredId = structureId;
},
selectStructure: (structureId) => section.selectById(structureId),
showAtChainage: (chainageM) => {
currentChainageM = null;
const selection: DesignSelection = { chainageM, structureId: null };
const selection: DesignSelection = { chainageM, structureId: preferredId };
// 계곡 통과 시설이 먼저다 — 같은 측점에 구조물 정본 항목이 겹쳐도 횡단도에
// 그려지는 것은 이쪽이다(순서 · 거리는 `resolveSelection` 한 곳).
const hit = resolveSelection(selection, pipeFacilities, structures);
+8 -1
View File
@@ -446,8 +446,15 @@ export function createSectionView(
refreshCards,
focusStation(stationId) {
if (selectedStationId !== stationId) selectStation(stationId, true);
else revealCard(stationId, "smooth");
else {
revealCard(stationId, "smooth");
// 같은 카드라도 알약 강조는 다시 맞춘다 — 목록에서 같은 측점 다른 항목을 고른 경우(52-15).
profile.showCard(
currentDetail?.cross_sections.find((entry) => entry.station_id === stationId) ?? null,
);
}
},
selectMark: (structureId) => profile.selectMark(structureId),
setStationSelectListener(listener) {
stationSelectListener = listener;
},
@@ -29,6 +29,8 @@ export interface SectionStructureEdit {
movePipe: (fromChainageM: number, toChainageM: number) => void;
/** 구조물(관 아님)을 다른 측점으로 옮긴다. */
moveStructure: (structureId: string, toChainageM: number) => void;
/** 구조물(관 아님) 하나를 폼에 올리고 그 카드로 간다 — 같은 측점 관보다 먼저(52-15). */
selectStructure: (structureId: string) => void;
}
/**
@@ -74,6 +74,8 @@ export interface SectionProfile {
redraw: () => void;
/** 카드를 골랐다 — 종단도 선택 표시가 따라간다. */
showCard: (section: CrossSection | null) => void;
/** 알약 강조를 그 구조물로(null = 풀기). */
selectMark: (structureId: string | null) => void;
}
/** 알약 목록 중 관(계곡 통과 시설)만 종단 측점선으로 편다 — 종단 보기와 같은 규칙. */
@@ -189,9 +191,14 @@ export function createSectionProfile(
onIrregularSelect: (station) =>
host.selectCard(nearestCard(station.chainage_m)?.station_id ?? null),
// 알약을 누르면 그 자리에 가장 가까운 측점 카드를 고른다 — 목록 클릭과 같은 규칙.
// 구조물 알약은 그 구조물을 폼에 올린다 — 카드가 측점으로 풀면 같은 측점 관이 먼저다(52-15).
onStructureSelect: (structureId) => {
const hit = marks.find((entry) => entry.structure_id === structureId);
if (hit) host.selectCard(nearestCard(structureAnchorM(hit))?.station_id ?? null);
if (!hit) return;
const edit = host.edit();
if (!isPipeMark(hit) && hit.structure_id && edit)
edit.selectStructure(hit.structure_id);
else host.selectCard(nearestCard(structureAnchorM(hit))?.station_id ?? null);
},
onStructureMarkMove: (structureId, toChainageM) => {
const edit = host.edit();
@@ -245,6 +252,9 @@ export function createSectionProfile(
redraw() {
profile?.redraw();
},
selectMark(structureId) {
profile?.setSelectedStructure(structureId);
},
showCard(section) {
if (!profile) return;
if (!section) {
@@ -40,6 +40,8 @@ export interface SectionViewController {
/** 좌측 구조물 목록에서 고른 측점 카드를 선택하고 화면에 드러낸다 — 재클릭 토글 없음
* (2026-08-29 B05/B06 일원화: 목록 클릭 → 해당 카드 스크롤·강조). */
focusStation: (stationId: string) => void;
/** 종단 알약 강조를 그 구조물로(null = 풀기 — 카드 측점선 짝을 따름). */
selectMark: (structureId: string | null) => void;
/** 카드(측점) 선택이 바뀔 때 알림 — 좌측 「구조물 배치」 폼이 그 측점 구조물을
* 올린다(2026-08-29 일원화). null = 선택 해제. */
setStationSelectListener: (listener: (stationId: string | null) => void) => void;