- 관종 파형강관·관경 1000 · 유입/유출 구조 기슭막이 · 집수정 길이 2 · 날개벽 있음·1·2·45 · BOX 2.0×2.0 · 월류 폭 5/10 · 월류 높이 필요 수심 · 독립 기슭막이 양쪽 — 전부 「안 정함 (제안 …)」·회색 글씨로만 - [제안값 넣기] 누른 때만 빈 칸에 제안값 · 적은 월류 높이가 필요 수심보다 낮으면 여전히 되돌림 - BOX암거 새로 놓을 때 기본값 싣던 자리도 걷음 · 비운 칸은 횡단도가 등록부 기본값으로 그림(저장만 안 함) - 700줄 한계로 물넘이·세월교 칸 묶음을 `_Drainage_Facility_Ford.ts` 로 뗌 - ORCA 936be972: 관종 「안 정함」 · 저장된 관경 1000 은 그대로 · 날개벽 고친 요청에 관경·날개벽만 실림 · 캐시 되돌림 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
152 lines
6.6 KiB
TypeScript
152 lines
6.6 KiB
TypeScript
/* =============================================================================
|
|
* B05_Profile_UI_Drainage_Facility_Ford.ts
|
|
* 물넘이포장·세월교 칸 묶음 — 월류 폭·높이·바닥 경사·포장 두께·길이·련 수 + 개략 단면 줄.
|
|
*
|
|
* 서브폼 본체(`_Drainage_Facility.ts`)가 700줄에 닿아 떼어 냄(2026-09-14).
|
|
* ⚠ 기본값을 칸에 안 채움(2026-09-14 브레인 판정 「기본값을 몰래 확정으로 바꾸지 않는다」):
|
|
* 월류 폭 세월교 10m·물넘이 5m(사용자 확정)는 **회색 제안**, 월류 높이는 설계유량·폭으로 되짚은
|
|
* **필요 최소 수심을 회색 제안**으로만 — 사용자가 적거나 [제안값 넣기]를 누른 때만 값.
|
|
* 적은 높이가 필요 수심보다 낮으면 여전히 되돌림(계산값 미만은 안 받음).
|
|
* ========================================================================== */
|
|
|
|
import {
|
|
FORD_BRIDGE_DEFAULT_WIDTH_M,
|
|
FORD_PAVEMENT_DEFAULT_WIDTH_M,
|
|
} from "@config/config_frontend";
|
|
import {
|
|
fordSection,
|
|
grid,
|
|
labeled,
|
|
numberInput,
|
|
putNumber,
|
|
stepper,
|
|
} from "./B05_Profile_UI_Drainage_Facility_Fields";
|
|
|
|
type FordKind = "ford_pavement" | "ford_bridge";
|
|
|
|
export interface FordFields {
|
|
widthRow: HTMLElement;
|
|
slopeRow: HTMLElement;
|
|
countRow: HTMLElement;
|
|
summary: HTMLElement;
|
|
/** 바뀌면 저장 흐름을 울릴 칸(높이는 자기 검사 뒤 스스로 울림). */
|
|
inputs: HTMLInputElement[];
|
|
setDesignFlow: (designFlow: number | null) => void;
|
|
sync: () => void;
|
|
write: (kind: FordKind, options: Record<string, string | number>) => void;
|
|
read: (kind: FordKind, target: Record<string, string | number>) => void;
|
|
fillSuggested: (kind: FordKind) => void;
|
|
}
|
|
|
|
export function createFordFields(emit: () => void): FordFields {
|
|
// 세월교 — 구체 내 배관 수량(련). 련은 정수라 소수 자릿수를 두지 않는다.
|
|
const count = numberInput("1", "1", "련");
|
|
const countRow = grid(labeled("수량 (련)", stepper(count, 1, 0)));
|
|
const width = numberInput("0.1");
|
|
const height = numberInput("0.01");
|
|
const widthRow = grid(
|
|
labeled("월류 폭 (m)", stepper(width, 0.1)),
|
|
labeled("월류 높이 (m)", stepper(height, 0.1)),
|
|
);
|
|
// 물넘이 바닥은 유입(상류)이 높고 유출이 낮게 기운다(2026-08-28 사용자 확정).
|
|
// 비우면 그 측점의 **노면 횡단경사**를 그대로 쓴다 — 횡단도가 판단한다.
|
|
const slope = numberInput("0.1");
|
|
slope.placeholder = "노면 기울기";
|
|
// 포장 두께·노폭 방향 길이 — 수량(㎡ = 월류 폭 × 길이 · 두께로 원단위 고름)이 읽는 칸(A3).
|
|
const thickness = numberInput("1");
|
|
const length = numberInput("0.1");
|
|
const slopeRow = grid(
|
|
labeled("바닥 경사 유입→유출 (%)", stepper(slope, 0.1)),
|
|
labeled("포장 두께 (㎝)", stepper(thickness, 1, 0)),
|
|
labeled("포장 길이 노폭 방향 (m)", stepper(length, 0.1)),
|
|
);
|
|
const summary = document.createElement("p");
|
|
summary.className = "b05-drainage__facility-note";
|
|
let designFlowM3s: number | null = null;
|
|
/** 현재 조건(설계유량·월류 폭)의 필요 최소 수심(m). 계산 불가면 null. */
|
|
let minDepthM: number | null = null;
|
|
|
|
const suggestedWidth = (kind: FordKind): number =>
|
|
kind === "ford_bridge" ? FORD_BRIDGE_DEFAULT_WIDTH_M : FORD_PAVEMENT_DEFAULT_WIDTH_M;
|
|
|
|
function sync(): void {
|
|
const widthM = Number.parseFloat(width.value || width.dataset.suggested || "");
|
|
const section = designFlowM3s !== null ? fordSection(designFlowM3s, widthM) : null;
|
|
minDepthM = section ? Number(section.depthM.toFixed(2)) : null;
|
|
height.placeholder = minDepthM !== null ? `제안 필요 수심 ${minDepthM.toFixed(2)}` : "";
|
|
if (designFlowM3s === null) {
|
|
summary.textContent =
|
|
"담당 유역의 설계유량이 아직 없습니다 — [유역 분석] 후 개략 단면이 나옵니다.";
|
|
return;
|
|
}
|
|
const head = `설계유량 ${designFlowM3s.toFixed(3)} ㎥/s`;
|
|
if (!section) {
|
|
summary.textContent = `${head} · 월류 폭을 넣으면 필요 수심·단면을 계산합니다.`;
|
|
return;
|
|
}
|
|
// 필요 최소 수심이다 — 월류 높이는 이 값 아래로 내릴 수 없다.
|
|
summary.textContent =
|
|
`${head} · 필요 수심 ${section.depthM.toFixed(2)} m · ` +
|
|
`필요 단면 ${section.areaM2.toFixed(2)} ㎡ · 유속 ${section.velocityMs.toFixed(2)} m/s — ` +
|
|
`월류 높이는 필요 수심 이상만 입력됩니다.`;
|
|
}
|
|
|
|
// 적은 값이 계산값 미만이면 받지 않는다 — 계산값으로 되돌리고 잠깐 붉힌다(빈 칸은 그대로 빈 칸).
|
|
height.addEventListener("change", () => {
|
|
const value = Number.parseFloat(height.value);
|
|
if (
|
|
minDepthM !== null &&
|
|
height.value !== "" &&
|
|
(!Number.isFinite(value) || value < minDepthM)
|
|
) {
|
|
height.value = minDepthM.toFixed(2);
|
|
height.classList.add("is-invalid");
|
|
window.setTimeout(() => height.classList.remove("is-invalid"), 900);
|
|
}
|
|
emit();
|
|
});
|
|
|
|
return {
|
|
widthRow,
|
|
slopeRow,
|
|
countRow,
|
|
summary,
|
|
inputs: [count, width],
|
|
setDesignFlow(designFlow) {
|
|
designFlowM3s = designFlow ?? null;
|
|
},
|
|
sync,
|
|
write(kind, options) {
|
|
const text = (key: string): string =>
|
|
options[key] !== undefined ? String(options[key]) : "";
|
|
count.value = kind === "ford_bridge" ? text("pipe_count") : "";
|
|
width.value = text("ford_width_m");
|
|
width.dataset.suggested = String(suggestedWidth(kind));
|
|
width.placeholder = `제안 ${suggestedWidth(kind)}`;
|
|
height.value = text("ford_height_m");
|
|
slope.value = text("ford_slope_pct");
|
|
thickness.value = text("thickness_cm");
|
|
length.value = text("length_m");
|
|
},
|
|
read(kind, target) {
|
|
putNumber(target, "ford_width_m", width.value);
|
|
// 월류 높이는 cm 단위 수심이라 0.01m 정밀도로 싣는다(putNumber는 0.1m 반올림).
|
|
const value = Number.parseFloat(height.value);
|
|
if (Number.isFinite(value) && value > 0) target.ford_height_m = Number(value.toFixed(2));
|
|
if (kind === "ford_pavement") {
|
|
putNumber(target, "ford_slope_pct", slope.value);
|
|
putNumber(target, "thickness_cm", thickness.value);
|
|
putNumber(target, "length_m", length.value);
|
|
return;
|
|
}
|
|
const pipes = Number.parseInt(count.value, 10);
|
|
if (Number.isFinite(pipes) && pipes > 0) target.pipe_count = pipes;
|
|
},
|
|
fillSuggested(kind) {
|
|
if (!width.value) width.value = String(suggestedWidth(kind));
|
|
sync();
|
|
if (!height.value && minDepthM !== null) height.value = minDepthM.toFixed(2);
|
|
},
|
|
};
|
|
}
|