feat(B05·B06): 구조물 좌측 패널 「집계 항목」 줄 · 옵션 보이기 · [수정] 옵션 보존 · 목록 지정 색(21-4)

- 폼 옵션 아래 「집계 항목」 줄(이름 · 미지정 · [고르기] · [해제]) — 구조물 · 관 계열 하위 폼 · B05 · B06 한 코드
- 옵션 `visible:false` 는 폼에서 숨김(정의 · 옛 값 그대로) · [수정]은 폼이 그린 칸만 갈아 끼우고 안 그린 칸(상세 · 숨긴 칸) 보존 — 옵션 덮어쓰기 흠 고침
- 목록 줄 `.is-assigned` 색 · 툴팁 항목 이름 · 캐시는 지금 초안 기록 칸(structures · pipes) 안 summary_item
- 미지정이면 칸을 안 실음 · 관은 서버 응답에 칸이 없으면 같은 측점에서 화면이 이어받음
- 항목 고르기 모달은 21-5 가 오기 전까지 같은 이름의 임시 함수 · Structures_Panel 700줄 넘어 옵션 그리기를 Panel_Options 로 나눔

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TULoa94ZFL26KU6ZqVpjkF
This commit is contained in:
2026-09-29 12:19:31 +09:00
co-authored by Claude Sonnet 5.5
parent 9d85ce8b4a
commit 71fac35dab
23 changed files with 1018 additions and 104 deletions
@@ -26,6 +26,7 @@ import {
} from "../B05_Profile/B05_Profile_Api_Structures";
import { readPendingPipes, writePendingPipes } from "../B05_Profile/B05_Profile_Api_Pipes_Draft";
import { fetchDetailPipePoints } from "../B04_PreProcess/B04_PreProcess_Api_Fetch";
import { readSummaryItem } from "../common_util/common_util_summary_item";
import {
readStructurePick,
writeStructurePick,
@@ -323,6 +324,7 @@ export function createB06StructuresPanel(deps: B06StructuresPanelDeps): B06Struc
facility: attributes.facility ?? "pipe",
source: "user",
options: attributes.options ?? {},
summary_item: attributes.summary_item ?? null,
});
pipeFacilities.sort((left, right) => left.chainage_m - right.chainage_m);
currentChainageM = at;
@@ -340,6 +342,18 @@ export function createB06StructuresPanel(deps: B06StructuresPanelDeps): B06Struc
// (2026-08-29 사용자 보고: 높이만 바꿨는데 이동 안내가 떴다).
if (Math.abs(fromChainageM - toChainageM) > PIPE_MATCH_M)
movePipeTo(fromChainageM, toChainageM);
if (attributes.summary_item !== undefined) {
// 옮긴 뒤 자리(toChainageM)에서 찾는다 — 안 옮겼으면 from 과 0.51m 안이라 같은 관이다.
const mine = pipeFacilities.find(
(entry) => Math.abs(entry.chainage_m - toChainageM) < PIPE_MATCH_M,
);
if (mine && (mine.summary_item ?? null)?.key !== attributes.summary_item?.key) {
mine.summary_item = attributes.summary_item;
persistPipes();
section.setPipeFacilities(pipeFacilities);
deps.onStructuresChanged?.();
}
}
const patch = attributes.options;
if (!patch || !Object.keys(patch).length) return;
if (!deps.queuePipeOptions) {
@@ -418,6 +432,7 @@ export function createB06StructuresPanel(deps: B06StructuresPanelDeps): B06Struc
start_m: pipe.start_m,
end_m: pipe.end_m,
source: pipe.source,
summary_item: readSummaryItem(pipe.summary_item),
// 폼 기본값 = 조정창이 쓰던 값(횡단 스펙). 저장된 옵션이 있으면 그쪽이 이긴다.
options: withSpecDefaults(
pipe.options,
@@ -491,6 +506,7 @@ export function createB06StructuresPanel(deps: B06StructuresPanelDeps): B06Struc
...(pipe.start_m !== undefined ? { start_m: pipe.start_m } : {}),
...(pipe.end_m !== undefined ? { end_m: pipe.end_m } : {}),
...(pipe.options ? { options: pipe.options } : {}),
...(pipe.summary_item ? { summary_item: pipe.summary_item } : {}),
})),
);
}