Merge remote-tracking branch 'origin/sub_laptop_8' into main_laptop_1

This commit is contained in:
2026-10-06 01:45:01 +09:00
3 changed files with 35 additions and 22 deletions
@@ -313,15 +313,14 @@ export function createStructuresBridge(deps: StructuresBridgeDeps) {
async function loadStructures(): Promise<void> {
try {
// 레지스트리는 **한 번만** 받고 쓰는 자리에 따라 나눈다(2026-09-07).
// · 추가 메뉴 — 켜진 종류만(B05 는 종전대로 여섯 군).
// · 알약 레인·군 판정 — **전부**. B06 에서 넣은 B군(측구·맹암거 등)은 레지스트리에서
// 꺼져 있는데, 켜진 것만 주면 이름·색·군을 못 찾아 종단에 「?」 회색 알약으로 뜬다.
// · 고르기 목록 — 켜진 종류만(B05 는 종전대로 여섯 군).
// · 목록 이름 · 폼 · 알약 레인 · 군 판정 — **전부**. B06 에서 넣은 B군(측구·맹암거 등)은
// 레지스트리에서 꺼져 있는데, 켜진 것만 주면 이름을 못 찾아 영문 키 · 「?」 알약으로 뜬다.
const [allTypes, stored] = await Promise.all([
fetchStructureTypes(true),
fetchStructures(deps.projectId),
]);
const menuTypes = allTypes.filter((type) => type.enabled);
deps.panel().structures.setTypes(menuTypes);
deps.panel().structures.setTypes(allTypes, (type) => type.enabled);
deps.profilePanel().setStructureTypes(allTypes);
// A군 판정에 쓸 타입 정보 — 횡단배수만 그래프 세로선·틸팅 대상이다.
structureTypeMap = new Map(
+8 -10
View File
@@ -53,9 +53,9 @@ export { GROUP_LABELS } from "./B05_Profile_UI_Structures_Panel_Types";
export type { PipeFacilityItem, StructuresSection } from "./B05_Profile_UI_Structures_Panel_Types";
import {
DEFAULT_INTERVAL_LENGTH_M,
GROUP_LABELS,
groupOption,
groupOptions,
hasComputedRange,
pickOption,
readBeforeOption,
readLengthOption,
type PipeFacilityItem,
@@ -165,6 +165,7 @@ export function createStructuresSection(
}
let types: StructureType[] = [];
let canPick: (type: StructureType) => boolean = () => true;
// 배열 자체를 바꾸지 않는다(조각들이 참조로 들고 있음) — 내용만 갈아끼운다.
const structures: StructureInstance[] = [];
let pipeFacilities: PipeFacilityItem[] = [];
@@ -348,7 +349,7 @@ export function createStructuresSection(
const candidates = group ? types.filter((t) => t.group === group && pickable(t)) : [];
typeSelect.replaceChildren(
new Option("— 선택 —", ""),
...candidates.map((type) => new Option(type.name, type.type_id)),
...candidates.map((type) => pickOption(type.name, type.type_id, !canPick(type))),
);
typeSelect.value =
keepTypeId && candidates.some((type) => type.type_id === keepTypeId) ? keepTypeId : "";
@@ -539,14 +540,11 @@ export function createStructuresSection(
facility: facilityOptions,
listRoot: list,
hasSelection: () => editingId !== null || selectedPipeChainage !== null,
setTypes(next) {
setTypes(next, pick = () => true) {
types = next;
const groups = new Map(next.map((t) => [t.group, t.group_name] as const));
// 첫 항목은 빈칸 — 진입·리셋 상태에서 군·종류를 강제로 고르게 두지 않는다. 이름은 정의(48) 먼저.
groupSelect.replaceChildren(
new Option("— 선택 —", ""),
...[...groups].map(([g, name]) => groupOption(g, name ?? GROUP_LABELS[g] ?? g)),
);
canPick = pick;
// 첫 항목은 빈칸 — 진입·리셋 상태에서 군·종류를 강제로 고르게 두지 않는다.
groupSelect.replaceChildren(new Option("— 선택 —", ""), ...groupOptions(next, pick));
groupSelect.value = "";
syncTypeOptions();
},
@@ -38,14 +38,29 @@ export const GROUP_LABELS: Record<string, string> = {
* 옛 값 · 도면 · 집계는 그대로이고 데이터도 지우지 않는다. */
export const HIDDEN_PICK_GROUPS: ReadonlySet<string> = new Set(["B", "D"]);
/** 군 드롭다운 항목 — 뺄 군은 가림(옛 항목을 열 때는 값으로 그대로 고를 수 있음). */
export function groupOption(group: string, name: string): HTMLOptionElement {
const option = new Option(name, group);
option.hidden = HIDDEN_PICK_GROUPS.has(group);
if (option.hidden) option.dataset.pickHidden = ""; // 정의 폼의 「가림 풀기」가 건드리지 않게
/** 고르기 목록 항목 — 가릴 항목은 가림(옛 항목을 열 때는 값으로 그대로 고를 수 있음). */
export function pickOption(text: string, value: string, hidden: boolean): HTMLOptionElement {
const option = new Option(text, value);
option.hidden = hidden;
if (hidden) option.dataset.pickHidden = ""; // 정의 폼의 「가림 풀기」가 건드리지 않게
return option;
}
/** 군 드롭다운 항목들 — 이름은 정의(48) 먼저 · 뺄 군과 고를 종류가 없는 군은 가림. */
export function groupOptions(
types: StructureType[],
pick: (type: StructureType) => boolean,
): HTMLOptionElement[] {
const groups = new Map(types.map((t) => [t.group, t.group_name] as const));
return [...groups].map(([g, name]) =>
pickOption(
name ?? GROUP_LABELS[g] ?? g,
g,
HIDDEN_PICK_GROUPS.has(g) || !types.some((t) => t.group === g && pick(t)),
),
);
}
/** 구간형 신규 추가 시 기본 구간 길이(m). 사용자가 종점을 바로 고칠 수 있게 짧게 잡는다. */
export const DEFAULT_INTERVAL_LENGTH_M = 15;
@@ -95,8 +110,9 @@ export interface StructuresSection {
/** 배치된 구조물 목록(<ul>) — 섹션 본문이 아니라 사이드 하단 고정 영역에 붙인다
* (2026-08-18 사용자 지시: 폼 길이에 밀려 목록이 화면 밖으로 나가던 문제). */
listRoot: HTMLElement;
/** 서버에서 받은 타입 목록을 채운다(최초 1회). */
setTypes: (types: StructureType[]) => void;
/** 서버에서 받은 타입 목록을 채운다(최초 1회). 이름·폼은 넘긴 종류 전부로 풀고,
* 고르기 목록엔 `pick` 이 고른 종류만 보임(빼면 전부). */
setTypes: (types: StructureType[], pick?: (type: StructureType) => boolean) => void;
/** 서버 정본으로 목록을 교체한다(진입·복원·저장 후). */
setStructures: (structures: StructureInstance[]) => void;
getStructures: () => StructureInstance[];