Merge remote-tracking branch 'origin/sub_laptop_5' into main_laptop_1
This commit is contained in:
@@ -49,7 +49,6 @@ import {
|
||||
} from "./B05_Profile_UI_Drainage_Facility_Fields";
|
||||
import { revetChoiceRow } from "./B05_Profile_UI_Drainage_Revet_Choice";
|
||||
import { createSpecForm, type SpecLinks } from "../A00_Common/design/design_structure_form";
|
||||
import { branchOf } from "../A00_Common/design/design_structure_spec";
|
||||
import { PIPE_SPEC } from "../A00_Common/design/design_structure_pipe";
|
||||
import {
|
||||
BOX_SPEC,
|
||||
@@ -60,7 +59,6 @@ import {
|
||||
import { FORD_SPEC, withLegacyGuards } from "../A00_Common/design/design_structure_ford";
|
||||
import { fordHeightHint, fordHeightM } from "../A00_Common/design/design_structure_ford_calc";
|
||||
import {
|
||||
DEFAULT_BASIN_SHAPE,
|
||||
pipeDrawn,
|
||||
pipeExtraCount,
|
||||
pipeLengthM,
|
||||
@@ -275,19 +273,7 @@ export function createFacilityOptionsForm(
|
||||
clear: (key) => linkSource?.clear(key),
|
||||
set: (key, item) => linkSource?.set(key, item),
|
||||
};
|
||||
// 그림이 쓰는 값(54-13) — 빈 고르기 칸 = 정의 기본값(엔진 · 횡단도가 그 값으로 그림) · 보여 주기만
|
||||
let defaults: Record<string, unknown> = {};
|
||||
const byDefault = (key: string | undefined): { value: string; tag: string } | null => {
|
||||
const value = key ? defaults[key] : null;
|
||||
return value === null || value === undefined || value === ""
|
||||
? null
|
||||
: { value: String(value), tag: "기본" };
|
||||
};
|
||||
/** 빈 날개벽 설치 = 정의 기본 설치(옛 「있음」 · 빈 값 = 날개벽 · 엔진 `_wing_spec`). */
|
||||
const wingDefault = (key: string): { value: string; tag: string } => {
|
||||
const value = String(defaults[key] ?? "");
|
||||
return { value: ["없음", "흙막이"].includes(value) ? value : "날개벽", tag: "기본" };
|
||||
};
|
||||
// 기본값은 새 시설 칸에 실제 값으로만(54-39) — 빈 칸에 「(기본)」 꼬리 · 안내 없음
|
||||
// 유입 「자동(규칙)」 = 기슭막이 + 유입 형식 auto(옛 값 · 정의 기본) — 그림은 지형 규칙이 집수정 · 흙막이를
|
||||
// 정함. 사용자가 유입 구조를 고를 때까지 저장도 그대로(흙막이 고름의 형식 revet 을 안 적음)
|
||||
let inletAuto: { structure?: string | number } | null = null;
|
||||
@@ -331,12 +317,12 @@ export function createFacilityOptionsForm(
|
||||
() => pipeForm.refresh(),
|
||||
);
|
||||
const pipeForm = createSpecForm(specLinks, {
|
||||
// 관 보호공 [연동] · [경사](54-30) — 유입 · 유출 상자 각각 한 줄(같은 값) · 집수정이면 숨김
|
||||
// 관 보호공 [연동] · [경사](54-30) — 유입 · 유출 상자 각각 한 줄(같은 값) · 길이 있는 흙막이만(54-40 · 집수정 · 안 고름은 숨김)
|
||||
fields: (c, values) =>
|
||||
c.id === "outlet"
|
||||
? [paintTiers(values), outletChoice.paint(false)]
|
||||
? [paintTiers(values), outletChoice.paint(values.structure !== "기슭막이")]
|
||||
: c.id === "inlet"
|
||||
? [inletChoice.paint(values.structure === "집수정")]
|
||||
? [inletChoice.paint(values.structure !== "기슭막이")]
|
||||
: c.id === "soil_add" // 추가 흙막이 상자도 같은 줄(54-36 · 상자마다 한 줄 · 같은 값)
|
||||
? [
|
||||
revetChoiceRow(
|
||||
@@ -345,23 +331,15 @@ export function createFacilityOptionsForm(
|
||||
).paint(false),
|
||||
]
|
||||
: [],
|
||||
shown: (c, item, values, index) => {
|
||||
shown: (c, item) => {
|
||||
if (c.id === "inlet" && item.id === "structure" && inletIsAuto()) {
|
||||
const drawn = drawnNow();
|
||||
return drawn
|
||||
? { value: drawn.basin ? "집수정" : "기슭막이", tag: "자동" }
|
||||
: { value: "", tag: "자동(지형 규칙)" };
|
||||
}
|
||||
if (values[item.id]) return null;
|
||||
if (item.id !== "form") return byDefault(branchOf(item, values)?.key);
|
||||
const basin = c.id === "inlet" && values.structure === "집수정";
|
||||
const drawn = drawnNow();
|
||||
const form = basin
|
||||
? (drawn?.basin ?? DEFAULT_BASIN_SHAPE)
|
||||
: c.id === "soil_add"
|
||||
? drawn?.extras[index]
|
||||
: drawn?.forms[c.id];
|
||||
return form ? { value: form, tag: "기본" } : null;
|
||||
// 빈 고르기 칸 = 「선택 안 함」 그대로(54-39 · 기본값 꼬리 없음)
|
||||
return null;
|
||||
},
|
||||
auto: (_c, item) => {
|
||||
if (item.id !== "length") return "";
|
||||
@@ -370,16 +348,6 @@ export function createFacilityOptionsForm(
|
||||
},
|
||||
// 흙막이 개수 = 유출 「추가 기슭막이(단)」(54-1)
|
||||
count: (c) => (c.id === "soil_add" ? pipeExtraCount(chainage) : undefined),
|
||||
hint: (c, item, state) => {
|
||||
if (item.default) return ""; // 명세 기본값 안내는 폼이 그림(추가 흙막이 · 54-36)
|
||||
// 빈 칸 = 정의 기본값 「값 (기본)」(54-36) — 구조가 비었으면 기본 구조의 칸
|
||||
const raw = state[c.id]?.[0] ?? {};
|
||||
const top = c.items.find((i) => i.id === "structure");
|
||||
const values =
|
||||
raw.structure || !top ? raw : { ...raw, structure: byDefault(top.key)?.value ?? "" };
|
||||
const fallback = item.kind === "number" ? byDefault(branchOf(item, values)?.key) : null;
|
||||
return fallback ? `${fallback.value} (기본)` : "";
|
||||
},
|
||||
onChange: (c, item) => {
|
||||
if (c.id === "inlet" && item.id === "structure") inletAuto = null;
|
||||
if (c.id === "inlet" && (item.id === "structure" || item.id === "form"))
|
||||
@@ -410,11 +378,6 @@ export function createFacilityOptionsForm(
|
||||
const fordNeed = (): number | null =>
|
||||
fordHeightM(fordFlow, Number(fordForm.state().ford?.[0]?.width ?? ""));
|
||||
const fordForm = createSpecForm(specLinks, {
|
||||
shown: (c, item, values) => {
|
||||
if (values[item.id]) return null;
|
||||
if (c.id !== "ford") return wingDefault(c.id === "inlet" ? "wing_in" : "wing_out");
|
||||
return item.id === "diameter" ? byDefault("pipe_diameter_mm") : null;
|
||||
},
|
||||
hint: (c, item, state) =>
|
||||
c.id === "ford" && item.id === "height"
|
||||
? fordHeightHint(fordFlow, Number(state.ford?.[0]?.width ?? ""))
|
||||
@@ -480,18 +443,7 @@ export function createFacilityOptionsForm(
|
||||
};
|
||||
|
||||
// ── BOX암거 = 사용자 구조물 표 02 명세(PLAN 52-2) — 본체 · 유입 구조 · 유출 구조 ──
|
||||
const boxForm = createSpecForm(specLinks, {
|
||||
onChange: () => emit(),
|
||||
shown: (c, item, values) => {
|
||||
if (values[item.id]) return null;
|
||||
if (c.id !== "body") return wingDefault(c.id === "inlet" ? "wing_in" : "wing_out");
|
||||
const size = bodyOf({
|
||||
body_width_m: Number(defaults.body_width_m ?? 2),
|
||||
body_height_m: Number(defaults.body_height_m ?? 2),
|
||||
}).size;
|
||||
return item.id === "size" && size ? { value: size, tag: "기본" } : null;
|
||||
},
|
||||
});
|
||||
const boxForm = createSpecForm(specLinks, { onChange: () => emit() });
|
||||
// 날개벽 칸 — 세월교 · BOX 가 같은 조각을 쓰던 자리 · 조정 행은 명세 유입 · 유출 칸으로 옮겨 붙음
|
||||
const wingInFields = createWingFields("날개벽(유입)", WING_IN_KEYS);
|
||||
const wingOutFields = createWingFields("날개벽(유출)", WING_OUT_KEYS);
|
||||
@@ -630,7 +582,6 @@ export function createFacilityOptionsForm(
|
||||
// 받은 값만 칸에 — 없으면 「안 정함」(새 시설은 부르는 쪽이 등록부 기본값을 실어 줌 · 46-7).
|
||||
const groups = Object.fromEntries((definition?.groups ?? []).map((g) => [g.id, g.name]));
|
||||
const names = definition?.spec_names ?? {};
|
||||
defaults = Object.fromEntries((definition?.options ?? []).map((o) => [o.key, o.default]));
|
||||
if (facility === "pipe") {
|
||||
// 정의 파일의 옛 이름 「흙막이 추가」 — 명세 이름 「흙막이」가 앞섬(54-1)
|
||||
const { soil_add: _old, ...pipeNames } = names;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* · 컨테이너 = 좌측 패널 폼과 같은 상자 — 명세 종류(`STRUCTURE_SPECS`)는 명세 컨테이너(선택 컨테이너는
|
||||
* 인스턴스마다) · 그 밖 종류는 정의 옵션 그룹(`StructureType.groups`)
|
||||
* · 첫 옵션 = 지금 보이는 첫 입력 칸(자동 칸 · 갈래가 없어 가린 칸 · 끈 칸은 건너뜀)
|
||||
* · 빈 값 = 등록부 기본값 「(기본)」 · 값 `auto` = 「(자동)」(54-13 표시와 같음) · 그것도 없으면 「—」
|
||||
* · 값 `auto` = 「(자동)」 · 빈 값 = 「—」(54-39 · 기본값으로 안 바꿈 · 기본값은 새 구조물 칸에 실제 값)
|
||||
* ========================================================================== */
|
||||
|
||||
import type { StructureInstance, StructureType } from "./B05_Profile_Api_Structures";
|
||||
@@ -27,7 +27,6 @@ import {
|
||||
type StructureSpec,
|
||||
} from "../A00_Common/design/design_structure_spec";
|
||||
|
||||
const DEFAULT_MARK = "(기본)";
|
||||
const AUTO_MARK = "(자동)";
|
||||
const NONE = "—";
|
||||
|
||||
@@ -62,8 +61,6 @@ function specLines(
|
||||
names = pipeNames;
|
||||
}
|
||||
const state = formState(spec, structure.type_id, structure.options ?? {});
|
||||
// 빈 칸이 그림에서 쓰는 값 — 등록부 기본값을 같은 길로 읽은 필수 컨테이너 값
|
||||
const fallback = formState(spec, structure.type_id, registryDefaults(type));
|
||||
const groups = Object.fromEntries((type?.groups ?? []).map((g) => [g.id, g.name]));
|
||||
return spec.containers.flatMap((c) => {
|
||||
const title = containerTitle(c, names, groups[c.link]);
|
||||
@@ -72,9 +69,8 @@ function specLines(
|
||||
(entry) => entry.kind !== "auto" && (!entry.by || branchOf(entry, values)),
|
||||
);
|
||||
const head = c.required ? title : `${title} ${index + 1}`;
|
||||
const base = c.required ? (fallback[c.id]?.[0]?.[item?.id ?? ""] ?? "") : "";
|
||||
return item
|
||||
? `${head}: ${itemLabel(c, item, names)} ${specValue(c, item, values, names, base)}`
|
||||
? `${head}: ${itemLabel(c, item, names)} ${specValue(c, item, values, names)}`
|
||||
: `${head}: ${NONE}`;
|
||||
});
|
||||
});
|
||||
@@ -113,7 +109,6 @@ function specValue(
|
||||
item: SpecItem,
|
||||
values: Instance,
|
||||
names: Record<string, string>,
|
||||
fallback: string,
|
||||
): string {
|
||||
const shown = (raw: string): string => {
|
||||
const choice = choicesOf(item, values).find((ch) => ch.value === raw);
|
||||
@@ -121,8 +116,7 @@ function specValue(
|
||||
};
|
||||
const raw = (values[item.id] ?? "").trim();
|
||||
if (raw === "auto") return AUTO_MARK;
|
||||
if (raw) return shown(raw);
|
||||
return fallback.trim() ? `${shown(fallback.trim())} ${DEFAULT_MARK}` : NONE;
|
||||
return raw ? shown(raw) : NONE;
|
||||
}
|
||||
|
||||
/** 정의 옵션 그룹 줄 — 그룹마다 첫 옵션(정의에 있고 켜진 칸). */
|
||||
@@ -139,22 +133,7 @@ function groupLines(
|
||||
const unit = option.unit ?? "";
|
||||
const raw = options[option.key];
|
||||
const value =
|
||||
raw === "auto"
|
||||
? AUTO_MARK
|
||||
: raw !== undefined && raw !== ""
|
||||
? `${raw}${unit}`
|
||||
: option.default !== null && option.default !== undefined && option.default !== ""
|
||||
? `${option.default}${unit} ${DEFAULT_MARK}`
|
||||
: NONE;
|
||||
raw === "auto" ? AUTO_MARK : raw !== undefined && raw !== "" ? `${raw}${unit}` : NONE;
|
||||
return `${group.name}: ${option.label} ${value}`;
|
||||
});
|
||||
}
|
||||
|
||||
/** 등록부 기본값(키 → 값) — 빈 칸이 그림에서 쓰는 값. */
|
||||
function registryDefaults(type: StructureType | undefined): Record<string, string | number> {
|
||||
return Object.fromEntries(
|
||||
(type?.options ?? [])
|
||||
.filter((option) => option.default !== null && option.default !== undefined)
|
||||
.map((option) => [option.key, option.default as string | number]),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
* ========================================================================== */
|
||||
|
||||
import { chainageToStation, stationToChainage } from "./B05_Profile_Util_Station";
|
||||
import { DEFAULT_BASIN_SHAPE } from "../B06_Section/B06_Section_UI_Cross_Culvert_Basin";
|
||||
|
||||
export function field(labelText: string, input: HTMLElement): HTMLLabelElement {
|
||||
const wrapper = document.createElement("label");
|
||||
@@ -65,14 +66,8 @@ export function optionControl(
|
||||
// 툴팁 — 표가 아직 안 읽는 칸이면 그 사유가 먼저(넣어도 안 바뀜을 알아야 함), 아니면 비울 때의 뜻.
|
||||
const tip = option.not_in_table ?? option.empty_means ?? "";
|
||||
if (option.input === "select") {
|
||||
// 빈 칸이 쓰는 정의 기본값은 빈 보기에 꼬리를 달아 보임 — 값은 안 고름(54-13)
|
||||
const fallback = option.default === null || option.default === "" ? null : option.default;
|
||||
const blank =
|
||||
fallback !== null && fallback !== undefined
|
||||
? `${label(String(fallback))} (기본)`
|
||||
: option.required
|
||||
? "— 선택 —"
|
||||
: "— 안 정함 —";
|
||||
// 빈 보기 = 값 없음(54-39) — 기본값은 새 구조물 칸에 실제 값으로만(「(기본)」 꼬리 없음)
|
||||
const blank = option.required ? "— 선택 —" : "선택 안 함";
|
||||
// 정의에서 뺀 선택지(48)를 고른 옛 값 — 그 값만 남겨 보임(값을 잃지 않음)
|
||||
const kept = value && !option.choices.includes(value) ? [value] : [];
|
||||
const element = select([
|
||||
@@ -107,11 +102,14 @@ export function optionControl(
|
||||
export function optionDefaults(
|
||||
options: ReadonlyArray<{ key: string; default: string | number | null }>,
|
||||
): Record<string, string | number> {
|
||||
return Object.fromEntries(
|
||||
const values: Record<string, string | number> = Object.fromEntries(
|
||||
options
|
||||
.filter((option) => option.default !== null && option.default !== "")
|
||||
.map((option) => [option.key, option.default as string | number]),
|
||||
);
|
||||
// 배관 집수정 모양도 실제 값으로(54-39 · 54-36 기본 · 자동 배치 짝 `_apply_new_defaults`)
|
||||
if (values.inlet_type === "집수정") values.inlet_structure ??= DEFAULT_BASIN_SHAPE;
|
||||
return values;
|
||||
}
|
||||
|
||||
/** 측점번호 + 잔여거리 두 칸 묶음. */
|
||||
|
||||
@@ -554,8 +554,19 @@
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 4px;
|
||||
}
|
||||
/* [연동] [경사] 한 줄(54-36) — 안 여백만 줄임 · 높이 그대로 */
|
||||
/* [연동] [경사] 한 줄(54-36) — 안 여백만 줄임 */
|
||||
.b05-structure__half-pair > button {
|
||||
padding-inline: 4px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* 상자 안 작은 단추 템플릿(54-41) — 높이 = 숫자 칸 [-][+](`--b05-control-h`) · 글 · 안 여백도 그 높이에 ·
|
||||
* 상자 이름표 [빼기] · 상자 밖 [추가] · [삭제] · [리셋]은 제외 */
|
||||
.b05-structure__group-body button:not(.b05-structure__step) {
|
||||
box-sizing: border-box;
|
||||
height: var(--b05-control-h);
|
||||
min-height: 0;
|
||||
padding-block: 0;
|
||||
font-size: var(--text-caption);
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user