Files
Aislo/E02_StabGround/E02_StabGround_UI_Water.ts
T
eomsangdonandClaude Opus 5.5 f4077fbcf6 feat(532-3): E02 지하수 갈래 — 우기 규칙 넷(KDS 기본 · 지표 아래 깊이 비율 · r_u · 사용자 수위선 구간) · 엔진 꼴 바꿈 · 지하수 카드
- ground.json groundwater 칸 덧붙임(wet_mode · depth_ratio · ru · lines · 기존 칸 그대로) · 기본값 = KDS · 범위 칸 넷
- check_ground ↔ checkGround 짝 고침(갈래 · 비율 · r_u · 수위선 구간 · 점) · 거울 시험 판 넷 더함
- groundwater_for · station_groundwater — 측점 모형 → {mode: none | ru | line}(좌 · 우 비탈 높이 따로 · 덮지 않은 측점 = KDS)
- GET · [초기화] = 옛 정본 빠진 칸 기본값으로 채움 · 화면 옛 캐시도 서버 값으로 채움
- 화면 = 지하수 카드 따로(「KDS 기본 · 우기 기준안전율 1.2 와 짝」 안내) · 하중 카드 = 노면 하중 · 지진
- 시험 test_532_4_stab_walls_water(벽 · 지하수) · test_532_3 기본값 지하수 칸 대조 고침(칸 늘어남)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 20:44:00 +09:00

183 lines
5.9 KiB
TypeScript

/* =============================================================================
* E02_StabGround_UI_Water.ts
* E02 지하수 카드(요구 347 · 351 · PLAN 532-3) — 건기 규칙 · 우기 갈래 넷(KDS 기본 · 지표 아래 깊이 비율 ·
* r_u · 사용자 수위선 구간) · 「KDS 기본 · 우기 기준안전율 1.2 와 짝」 안내 · [기본값].
* 엔진 꼴로 바꾸기는 서버(`E02_StabGround_Model.station_groundwater`) — 여기는 값만 고침.
* ========================================================================== */
import { createButton, el } from "@ui/ui_template_elements";
import { t, type LocaleKey } from "@ui/ui_template_locale";
import { WATER_KEYS, WATER_RULES, WET_MODES, type WetMode } from "./logic/E02_StabGround_Check";
import {
card,
clone,
headButtons,
numInput,
selectInput,
table,
type E02View,
} from "./E02_StabGround_UI_Tables";
const L = (key: string): string => t(key as LocaleKey);
function field(label: string, input: HTMLElement): HTMLElement {
const node = el("label", { className: "e02-field" });
node.append(el("span", { text: label }), input);
return node;
}
function removeButton(view: E02View, onClick: () => void): HTMLButtonElement {
const button = createButton({
label: t("E02_Btn_Remove"),
variant: "danger-ghost",
size: "sm",
onClick,
});
button.hidden = !view.editable;
return button;
}
/** 사용자 수위선 구간 표 — 줄마다 시작 · 끝 · 점(offset · 깊이) · [점 추가] · [지움] */
function linesBody(view: E02View): HTMLElement {
const water = view.ground.groundwater;
if (!water.lines.length) return el("p", { className: "e02-empty", text: t("E02_Line_Empty") });
const rows = water.lines.map((line, i) => {
const base = `groundwater.lines.${i}`;
const points = el("div", { className: "e02-points" });
points.dataset.path = `${base}.points`;
line.points.forEach((point, k) => {
const pair = el("span", { className: "e02-point" });
pair.append(
numInput(view, `${base}.points.${k}.0`, point[0], (v) => (point[0] = v as number)),
numInput(view, `${base}.points.${k}.1`, point[1], (v) => (point[1] = v as number)),
removeButton(view, () => {
line.points.splice(k, 1);
view.rebuild();
}),
);
points.append(pair);
});
const addPoint = createButton({
label: t("E02_Btn_AddPoint"),
variant: "ghost",
size: "sm",
onClick: () => {
const last = line.points[line.points.length - 1];
line.points.push(last ? [last[0] + 5, last[1]] : [0, 1]);
view.rebuild();
},
});
addPoint.hidden = !view.editable;
points.append(addPoint);
return [
numInput(view, `${base}.from_m`, line.from_m, (v) => (line.from_m = v as number)),
numInput(view, `${base}.to_m`, line.to_m, (v) => (line.to_m = v as number)),
points,
removeButton(view, () => {
water.lines.splice(i, 1);
view.rebuild();
}),
];
});
return table([t("E02_Col_From"), t("E02_Col_To"), t("E02_Col_Points"), ""], rows);
}
export function waterCard(view: E02View): HTMLElement {
const water = view.ground.groundwater;
const d = view.defaults.groundwater;
const rule = (key: (typeof WATER_KEYS)[number]): HTMLElement =>
field(
L(`E02_Water_${key}`),
selectInput(
view,
`groundwater.${key}`,
WATER_RULES.map((r) => ({ value: r, text: L(`E02_Rule_${r}`) })),
water[key],
(v) => (water[key] = v as (typeof WATER_RULES)[number]),
{ src: `groundwater.${key}`, def: L(`E02_Rule_${d[key]}`) },
),
);
const mode = selectInput(
view,
"groundwater.wet_mode",
WET_MODES.map((m) => ({ value: m, text: L(`E02_WetMode_${m}`) })),
water.wet_mode,
(v) => {
water.wet_mode = v as WetMode;
view.rebuild();
},
{ src: "groundwater.wet_mode", def: L(`E02_WetMode_${d.wet_mode}`) },
);
const grid = el("div", { className: "e02-grid" });
grid.append(rule("dry"), field(t("E02_WetMode"), mode));
const body: HTMLElement[] = [];
if (water.wet_mode === "kds") grid.append(rule("wet_soil"), rule("wet_rock"));
if (water.wet_mode === "depth_ratio")
grid.append(
field(
t("E02_DepthRatio"),
numInput(
view,
"groundwater.depth_ratio",
water.depth_ratio,
(v) => (water.depth_ratio = v as number),
{ src: "groundwater.depth_ratio", def: d.depth_ratio },
),
),
);
if (water.wet_mode === "ru")
grid.append(
field(
t("E02_Ru"),
numInput(view, "groundwater.ru", water.ru, (v) => (water.ru = v as number), {
src: "groundwater.ru",
def: d.ru,
}),
),
);
if (water.wet_mode === "line")
body.push(el("p", { className: "e02-hint", text: t("E02_Line_Hint") }), linesBody(view));
const { section, head } = card(
"E02_Card_Water",
el("p", { className: "e02-hint", text: t("E02_Water_Hint") }),
grid,
...body,
);
const stations = view.ground.stations;
const first = stations[0]?.chainage_m ?? 0;
const last = stations[stations.length - 1]?.chainage_m ?? 100;
const buttons = [
createButton({
label: t("E02_Btn_Defaults"),
variant: "ghost",
size: "sm",
onClick: () => {
view.ground.groundwater = clone(d);
view.rebuild();
},
}),
];
if (water.wet_mode === "line")
buttons.unshift(
createButton({
label: t("E02_Btn_AddLine"),
variant: "ghost",
size: "sm",
onClick: () => {
water.lines.push({
from_m: first,
to_m: last > first ? last : first + 20,
points: [
[-10, 1],
[10, 1],
],
});
view.rebuild();
},
}),
);
headButtons(view, head, ...buttons);
return section;
}