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";
|
} from "./B05_Profile_UI_IrregularStations";
|
||||||
import { structureAnchorM, type StructureInstance } from "./B05_Profile_Api_Structures";
|
import { structureAnchorM, type StructureInstance } from "./B05_Profile_Api_Structures";
|
||||||
import { GROUP_LABELS } from "./B05_Profile_UI_Structures_Panel";
|
import { GROUP_LABELS } from "./B05_Profile_UI_Structures_Panel";
|
||||||
|
import { HIDDEN_PICK_GROUPS } from "./B05_Profile_UI_Structures_Panel_Types";
|
||||||
|
|
||||||
/** 우클릭 메뉴용 최소 타입 정보 — 사이드 「구조물 배치」 종류 목록과 같은 원천. */
|
/** 우클릭 메뉴용 최소 타입 정보 — 사이드 「구조물 배치」 종류 목록과 같은 원천. */
|
||||||
export interface StructureMenuType {
|
export interface StructureMenuType {
|
||||||
@@ -32,7 +33,9 @@ export function structureGroupMenuItems(
|
|||||||
types: ReadonlyArray<StructureMenuType>,
|
types: ReadonlyArray<StructureMenuType>,
|
||||||
onPick: (typeId: string) => void,
|
onPick: (typeId: string) => void,
|
||||||
): MapContextMenuItem[] {
|
): 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) => ({
|
return groups.map((group) => ({
|
||||||
label: GROUP_LABELS[group] ?? group,
|
label: GROUP_LABELS[group] ?? group,
|
||||||
children: types
|
children: types
|
||||||
|
|||||||
@@ -78,7 +78,9 @@ export function createFacilityDefinition(root: HTMLElement): FacilityDefinition
|
|||||||
root
|
root
|
||||||
.querySelectorAll(".is-rule-hidden")
|
.querySelectorAll(".is-rule-hidden")
|
||||||
.forEach((node) => node.classList.remove("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();
|
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 { type FacilityAttributes } from "./B05_Profile_UI_Drainage_Facility";
|
||||||
import { field, optionDefaults } from "./B05_Profile_UI_Structures_Fields";
|
import { field, optionDefaults } from "./B05_Profile_UI_Structures_Fields";
|
||||||
import {
|
import {
|
||||||
hasSpecContainers,
|
hidesTypeSummary,
|
||||||
paintStale,
|
paintStale,
|
||||||
renderOptionFields as renderOptionFieldsInto,
|
renderOptionFields as renderOptionFieldsInto,
|
||||||
} from "./B05_Profile_UI_Structures_Panel_Options";
|
} from "./B05_Profile_UI_Structures_Panel_Options";
|
||||||
@@ -54,6 +54,7 @@ export type { PipeFacilityItem, StructuresSection } from "./B05_Profile_UI_Struc
|
|||||||
import {
|
import {
|
||||||
DEFAULT_INTERVAL_LENGTH_M,
|
DEFAULT_INTERVAL_LENGTH_M,
|
||||||
GROUP_LABELS,
|
GROUP_LABELS,
|
||||||
|
groupOption,
|
||||||
hasComputedRange,
|
hasComputedRange,
|
||||||
readBeforeOption,
|
readBeforeOption,
|
||||||
readLengthOption,
|
readLengthOption,
|
||||||
@@ -227,7 +228,7 @@ export function createStructuresSection(
|
|||||||
!!type && !managed && type.placement === "interval" && !hasComputedRange(type);
|
!!type && !managed && type.placement === "interval" && !hasComputedRange(type);
|
||||||
positionRow.hidden = !type;
|
positionRow.hidden = !type;
|
||||||
positionDivider.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;
|
startFields.wrap.hidden = !isInterval;
|
||||||
endFields.wrap.hidden = !isInterval;
|
endFields.wrap.hidden = !isInterval;
|
||||||
primary.disabled = !type;
|
primary.disabled = !type;
|
||||||
@@ -544,7 +545,7 @@ export function createStructuresSection(
|
|||||||
// 첫 항목은 빈칸 — 진입·리셋 상태에서 군·종류를 강제로 고르게 두지 않는다. 이름은 정의(48) 먼저.
|
// 첫 항목은 빈칸 — 진입·리셋 상태에서 군·종류를 강제로 고르게 두지 않는다. 이름은 정의(48) 먼저.
|
||||||
groupSelect.replaceChildren(
|
groupSelect.replaceChildren(
|
||||||
new Option("— 선택 —", ""),
|
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 = "";
|
groupSelect.value = "";
|
||||||
syncTypeOptions();
|
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 { STRUCTURE_SPECS } from "../A00_Common/design/design_structure_pipe";
|
||||||
import { specKeys } from "../A00_Common/design/design_structure_spec";
|
import { specKeys } from "../A00_Common/design/design_structure_spec";
|
||||||
|
|
||||||
/** 구조물 명세 컨테이너 · 정의 그룹 상자(그룹마다 잇기 줄)로 그리는 종류인지 — 그때 종류 단위
|
/** 종류 단위 「구조물 조합」 줄을 가릴 종류인지 — 구조물 명세 컨테이너 · 정의 그룹 상자(그룹마다 잇기 줄)로
|
||||||
* 「구조물 조합」 줄은 가림(PLAN 52-1 · 52-6b). */
|
* 그리는 종류(PLAN 52-1 · 52-6b) · 종단배수(B군 · 조합 잇기 없음 · 표 07). */
|
||||||
export const hasSpecContainers = (type: StructureType): boolean =>
|
export const hidesTypeSummary = (type: StructureType): boolean =>
|
||||||
!!STRUCTURE_SPECS[type.type_id]?.containers.length || !!type.groups?.length;
|
!!STRUCTURE_SPECS[type.type_id]?.containers.length || !!type.groups?.length || type.group === "B";
|
||||||
|
|
||||||
/** 패널이 쥔 값 중 옵션 그리기에 필요한 것들. 이름은 분리 전 지역변수와 같다. */
|
/** 패널이 쥔 값 중 옵션 그리기에 필요한 것들. 이름은 분리 전 지역변수와 같다. */
|
||||||
export interface OptionRenderContext {
|
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). 사용자가 종점을 바로 고칠 수 있게 짧게 잡는다. */
|
/** 구간형 신규 추가 시 기본 구간 길이(m). 사용자가 종점을 바로 고칠 수 있게 짧게 잡는다. */
|
||||||
export const DEFAULT_INTERVAL_LENGTH_M = 15;
|
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