merge: sub_laptop_2 52-8 — 충돌(Panel_Options 종류 단위 잇기 가림) = 두 조건 합침(명세 · 정의 그룹 · 종단배수)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FJqWQpoB1RE7hiaQ2wH8qV
This commit is contained in:
@@ -17,6 +17,7 @@ import {
|
||||
} from "./B05_Profile_UI_IrregularStations";
|
||||
import { structureAnchorM, type StructureInstance } from "./B05_Profile_Api_Structures";
|
||||
import { GROUP_LABELS } from "./B05_Profile_UI_Structures_Panel";
|
||||
import { HIDDEN_PICK_GROUPS } from "./B05_Profile_UI_Structures_Panel_Types";
|
||||
|
||||
/** 우클릭 메뉴용 최소 타입 정보 — 사이드 「구조물 배치」 종류 목록과 같은 원천. */
|
||||
export interface StructureMenuType {
|
||||
@@ -32,7 +33,9 @@ export function structureGroupMenuItems(
|
||||
types: ReadonlyArray<StructureMenuType>,
|
||||
onPick: (typeId: string) => void,
|
||||
): MapContextMenuItem[] {
|
||||
const groups = [...new Set(types.map((type) => type.group))];
|
||||
const groups = [...new Set(types.map((type) => type.group))].filter(
|
||||
(group) => !HIDDEN_PICK_GROUPS.has(group),
|
||||
);
|
||||
return groups.map((group) => ({
|
||||
label: GROUP_LABELS[group] ?? group,
|
||||
children: types
|
||||
|
||||
@@ -78,7 +78,9 @@ export function createFacilityDefinition(root: HTMLElement): FacilityDefinition
|
||||
root
|
||||
.querySelectorAll(".is-rule-hidden")
|
||||
.forEach((node) => node.classList.remove("is-rule-hidden"));
|
||||
root.querySelectorAll<HTMLOptionElement>("option[hidden]").forEach((o) => (o.hidden = false));
|
||||
root
|
||||
.querySelectorAll<HTMLOptionElement>("option[hidden]:not([data-pick-hidden])")
|
||||
.forEach((o) => (o.hidden = false));
|
||||
paint();
|
||||
},
|
||||
};
|
||||
|
||||
@@ -24,7 +24,7 @@ import type { PipeFacility } from "../B04_PreProcess/B04_PreProcess_Api_Fetch";
|
||||
import { type FacilityAttributes } from "./B05_Profile_UI_Drainage_Facility";
|
||||
import { field, optionDefaults } from "./B05_Profile_UI_Structures_Fields";
|
||||
import {
|
||||
hasSpecContainers,
|
||||
hidesTypeSummary,
|
||||
paintStale,
|
||||
renderOptionFields as renderOptionFieldsInto,
|
||||
} from "./B05_Profile_UI_Structures_Panel_Options";
|
||||
@@ -54,6 +54,7 @@ export type { PipeFacilityItem, StructuresSection } from "./B05_Profile_UI_Struc
|
||||
import {
|
||||
DEFAULT_INTERVAL_LENGTH_M,
|
||||
GROUP_LABELS,
|
||||
groupOption,
|
||||
hasComputedRange,
|
||||
readBeforeOption,
|
||||
readLengthOption,
|
||||
@@ -227,7 +228,7 @@ export function createStructuresSection(
|
||||
!!type && !managed && type.placement === "interval" && !hasComputedRange(type);
|
||||
positionRow.hidden = !type;
|
||||
positionDivider.hidden = !type;
|
||||
summary.root.hidden = !type || hasSpecContainers(type); // 컨테이너 종류는 컨테이너마다 잇기(52-1)
|
||||
summary.root.hidden = !type || hidesTypeSummary(type); // 컨테이너 종류는 컨테이너마다 잇기(52-1)
|
||||
startFields.wrap.hidden = !isInterval;
|
||||
endFields.wrap.hidden = !isInterval;
|
||||
primary.disabled = !type;
|
||||
@@ -544,7 +545,7 @@ export function createStructuresSection(
|
||||
// 첫 항목은 빈칸 — 진입·리셋 상태에서 군·종류를 강제로 고르게 두지 않는다. 이름은 정의(48) 먼저.
|
||||
groupSelect.replaceChildren(
|
||||
new Option("— 선택 —", ""),
|
||||
...[...groups].map(([g, name]) => new Option(name ?? GROUP_LABELS[g] ?? g, g)),
|
||||
...[...groups].map(([g, name]) => groupOption(g, name ?? GROUP_LABELS[g] ?? g)),
|
||||
);
|
||||
groupSelect.value = "";
|
||||
syncTypeOptions();
|
||||
|
||||
@@ -23,10 +23,10 @@ import { FORM_OPTION_KEYS } from "./B05_Profile_UI_Drainage_Facility_Merge";
|
||||
import { STRUCTURE_SPECS } from "../A00_Common/design/design_structure_pipe";
|
||||
import { specKeys } from "../A00_Common/design/design_structure_spec";
|
||||
|
||||
/** 구조물 명세 컨테이너 · 정의 그룹 상자(그룹마다 잇기 줄)로 그리는 종류인지 — 그때 종류 단위
|
||||
* 「구조물 조합」 줄은 가림(PLAN 52-1 · 52-6b). */
|
||||
export const hasSpecContainers = (type: StructureType): boolean =>
|
||||
!!STRUCTURE_SPECS[type.type_id]?.containers.length || !!type.groups?.length;
|
||||
/** 종류 단위 「구조물 조합」 줄을 가릴 종류인지 — 구조물 명세 컨테이너 · 정의 그룹 상자(그룹마다 잇기 줄)로
|
||||
* 그리는 종류(PLAN 52-1 · 52-6b) · 종단배수(B군 · 조합 잇기 없음 · 표 07). */
|
||||
export const hidesTypeSummary = (type: StructureType): boolean =>
|
||||
!!STRUCTURE_SPECS[type.type_id]?.containers.length || !!type.groups?.length || type.group === "B";
|
||||
|
||||
/** 패널이 쥔 값 중 옵션 그리기에 필요한 것들. 이름은 분리 전 지역변수와 같다. */
|
||||
export interface OptionRenderContext {
|
||||
|
||||
@@ -34,6 +34,18 @@ export const GROUP_LABELS: Record<string, string> = {
|
||||
호환: "기타",
|
||||
};
|
||||
|
||||
/** 새로 놓을 때 고르기 목록(군 드롭다운 · 우클릭 메뉴)에서 뺄 군 — 종단배수·계류사방(표 07).
|
||||
* 옛 값 · 도면 · 집계는 그대로이고 데이터도 지우지 않는다. */
|
||||
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 = ""; // 정의 폼의 「가림 풀기」가 건드리지 않게
|
||||
return option;
|
||||
}
|
||||
|
||||
/** 구간형 신규 추가 시 기본 구간 길이(m). 사용자가 종점을 바로 고칠 수 있게 짧게 잡는다. */
|
||||
export const DEFAULT_INTERVAL_LENGTH_M = 15;
|
||||
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/* 52-8 — B05 · B06 좌측 「구조물 배치」 종단배수(B) · 계류사방(D) 고르기 목록에서 숨김
|
||||
* 시작 화면: B05 종단설계(#/b05-profile) · 검증 프로젝트(sub2_검증)
|
||||
* 부르는 법: 앞에 `window.__m528 = "단계";` 를 붙여
|
||||
* orca eval --expression "window.__m528='seed'; $(cat 이 파일)" → 옛 값 둘(골막이 D · 측구 B)을 세션 초안에만 둠
|
||||
* (orca reload)
|
||||
* orca eval --expression "window.__m528='verify'; $(cat 이 파일)" → 군 목록 · 우클릭 메뉴 · 옛 값 열기 (B05)
|
||||
* (#/b06-section 으로 가서 reload 후 verify 한 번 더)
|
||||
* orca eval --expression "window.__m528='clear'; $(cat 이 파일)" → 세션 초안 비움(서버 저장 안 함)
|
||||
* 기대 수치(verify): visibleGroups 에 B · D 없음(0) · hiddenGroups 가림만 · menuHasBD 0 ·
|
||||
* 옛 값 목록 둘 그대로 · 옛 값을 열면 군 = D / B 로 열림(editGroup) · 잇기 칸 pickLinks 골막이(D) 1 · 측구(B) 0
|
||||
*/
|
||||
(async () => {
|
||||
const MODE = window.__m528 || "verify";
|
||||
const w = (ms) => new Promise((r) => setTimeout(r, ms));
|
||||
const projectId = localStorage.getItem("frd_current_project_id");
|
||||
const modUrl = (part) =>
|
||||
performance
|
||||
.getEntriesByType("resource")
|
||||
.map((e) => e.name)
|
||||
.filter((n) => n.includes(part))
|
||||
.pop();
|
||||
const api = await import(modUrl("/B05_Profile/B05_Profile_Api_Structures.ts"));
|
||||
const out = { mode: MODE, hash: location.hash };
|
||||
if (MODE === "seed") {
|
||||
const base = {
|
||||
placement_source: "manual",
|
||||
status: "draft",
|
||||
revision: 0,
|
||||
geometry: null,
|
||||
memo: "",
|
||||
options: {},
|
||||
};
|
||||
api.writePendingStructures(projectId, [
|
||||
{
|
||||
...base,
|
||||
structure_id: "m528d",
|
||||
type_id: "erosion_check",
|
||||
placement: "point",
|
||||
chainage_m: 40,
|
||||
},
|
||||
{
|
||||
...base,
|
||||
structure_id: "m528b",
|
||||
type_id: "ditch_side",
|
||||
placement: "interval",
|
||||
start_m: 60,
|
||||
end_m: 80,
|
||||
},
|
||||
]);
|
||||
out.seeded = api.readPendingStructures(projectId).length;
|
||||
return JSON.stringify(out);
|
||||
}
|
||||
if (MODE === "clear") {
|
||||
api.writePendingStructures(projectId, null);
|
||||
out.cleared = api.readPendingStructures(projectId) === null;
|
||||
return JSON.stringify(out);
|
||||
}
|
||||
const groupSel = [...document.querySelectorAll("select")].find((s) =>
|
||||
[...s.options].some((o) => o.text.includes("A 횡단배수")),
|
||||
);
|
||||
const isBD = (o) => /^(B|D) /.test(o.text);
|
||||
out.visibleGroups = [...groupSel.options].filter((o) => !o.hidden && o.value).map((o) => o.text);
|
||||
out.visibleBD = [...groupSel.options].filter((o) => !o.hidden && isBD(o)).length;
|
||||
out.hiddenGroups = [...groupSel.options].filter((o) => o.hidden).map((o) => o.text);
|
||||
// 우클릭 메뉴 목록(공용 만들기) — 종류 전부를 줘도 B · D 군이 안 나옴
|
||||
const menuMod = await import(modUrl("/B05_Profile/B05_Profile_UI_Profile_Structures.ts"));
|
||||
const types = (await api.fetchStructureTypes(true)).map((t) => ({
|
||||
type_id: t.type_id,
|
||||
group: t.group,
|
||||
name: t.name,
|
||||
}));
|
||||
const menu = menuMod.structureGroupMenuItems(types, () => {});
|
||||
out.menuGroups = menu.map((m) => m.label);
|
||||
out.menuHasBD = menu.filter((m) => /^(B|D) /.test(m.label)).length;
|
||||
// 옛 값 — 목록에 그대로 · 열면 그 군으로 열림
|
||||
const rows = [...document.querySelectorAll(".b05-route__irregular-list li")];
|
||||
out.rows = rows.map((r) => r.textContent.trim().replace(/\s+/g, " ").slice(0, 40));
|
||||
const old = rows.find((r) =>
|
||||
(window.__m528row ? new RegExp(window.__m528row) : /골막이/).test(r.textContent),
|
||||
);
|
||||
if (old) {
|
||||
(old.querySelector("button") ?? old).click();
|
||||
await w(1500);
|
||||
const sels = [...document.querySelectorAll("select")].filter((s) =>
|
||||
[...s.options].some((o) => o.text.includes("A 횡단배수")),
|
||||
);
|
||||
// 다시 열면 고른 것이 복원돼 있음 — 누르면 풀리므로 풀렸으면 한 번 더
|
||||
if (!sels[0]?.value) {
|
||||
(old.querySelector("button") ?? old).click();
|
||||
await w(1500);
|
||||
}
|
||||
out.editGroup = sels[0]?.value;
|
||||
// 종단배수(B)는 조합 잇기 칸이 없음(0) · 계류사방(D)은 옛 그대로(1)
|
||||
out.pickLinks = [...document.querySelectorAll('[data-b05-summary="pick"]')].filter(
|
||||
(n) => n.offsetParent,
|
||||
).length;
|
||||
}
|
||||
return JSON.stringify(out);
|
||||
})();
|
||||
Reference in New Issue
Block a user