feat(structure): 65-1~5 세월교 · 박스암거 유입 · 유출 흙막이 양식 공통 · 없음 = 램프 뺌 · 세월교 기본값 · 물넘이 월류 폭 · 높이
- 흙막이 양식 한 벌(design_structure_guard) — 배관 · 박스 · 세월교가 같은 칸(형태 · 길이 · 높이 · 측점 전후) · 추가 흙막이 · 도수로/돌붙임 상자
- 세월교 · 박스 유입 · 유출: 흙막이 고르면 흙막이 칸(키 {side}_revet_* · 기본 찰 10 · 1.5 · 5 · 5) · [연동][경사] 옵션 줄
- B06 측벽 높이 · 좌우 · 상하 · 바닥판 읽기 줄을 세월교 · 박스 유입 · 유출 칸에 안 옮김(강조만)
- 유입 · 유출 「없음」 = 목록 램프 · 구조물 조합 잇기 줄 없음(명세 none)
- 세월교: 수량(련) 관경 바로 뒤 · 련 기본 2 · 새 시설 빈 월류 높이 = 유량 오면 필요 수심 · 종류 바꿀 때 유량 넘김
- 물넘이 포장: 경사각 기본 3° · 월류 폭 · 높이 칸(세월교와 같은 키 ford_width_m · ford_height_m · 같은 계산)
- 구조물정의 판 18(판_17 이력) · 이름 표 · 집계표 선택 컨테이너 짝 · 저장 병합 키
- 시험: 세월교 · 박스 · 물넘이 명세 기대값 · 흙막이 짝 자리 옮김
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BVPp2o6Mh2FZJr72yW3ofZ
This commit is contained in:
@@ -2,17 +2,20 @@
|
||||
* design_structure_box.ts
|
||||
* 횡단배수 › 박스암거 명세 — 사용자 구조물 표 02 고친 판(`docs/raw/구조물정의_표/02_횡단배수_박스암거.md`) 그대로.
|
||||
*
|
||||
* 컨테이너 셋(모두 필수): 본체 · 유입 구조 · 유출 구조. 구조 · 정본 = 이 명세 · 이름만 정의(M02)에서 바꿈.
|
||||
* 컨테이너: 본체 · 유입 구조 · 유출 구조(필수) · 흙막이(선택 · 여러 개) · 도수로/돌붙임(선택 · 하나 · 65-2).
|
||||
* 구조 · 정본 = 이 명세 · 이름만 정의(M02)에서 바꿈.
|
||||
* 저장 키 = pipe_points.json 옛 키 그대로(B06 횡단 · B07 · B08 이 읽는 자리):
|
||||
* · 본체 = `body_width_m` · `body_height_m` 수 — 규격 칸은 저장 안 함(폭 · 높이로 되찾음 · `bodyOf`)
|
||||
* · 사용자 입력에 두 칸 다 비면 `body_custom` = 「사용자 입력」 표시만
|
||||
* · 유입 · 유출 구조 = `wing_in` · `wing_out`(없음 · 날개벽 · 흙막이 · 옛 「있음」 = 날개벽)
|
||||
* — 엔진은 날개벽만 세움(`_wing_spec` ↔ `wingSpec` 짝)
|
||||
* — 엔진은 날개벽만 세움(`_wing_spec` ↔ `wingSpec` 짝) · 흙막이 = 배관과 같은 양식(`{side}_revet_*` · 65-2) ·
|
||||
* 「없음」 = 목록 램프 · 잇기 줄 없음(65-3)
|
||||
* 표 02 에 없는 옛 날개벽 치수 칸은 화면에서 빼고 값은 남김(지난 정의 값).
|
||||
* import 없음(꼴만) — 시험이 이 파일만 옮겨 돌림.
|
||||
* import = 같은 폴더 명세뿐 — 시험이 이 폴더 파일만 옮겨 돌림.
|
||||
* ========================================================================== */
|
||||
|
||||
import type { Instance, SpecItem, StructureSpec } from "./design_structure_spec";
|
||||
import type { Instance, SpecContainer, SpecItem, StructureSpec } from "./design_structure_spec";
|
||||
import { CHUTE_ADD, guardItems, revetKeys, SOIL_ADD } from "./design_structure_guard";
|
||||
|
||||
export const BOX_CUSTOM = "사용자 입력";
|
||||
/** 사용자 입력에 가로 · 세로 둘 다 빈 채 저장했다는 표시(폭 · 높이 수가 없을 때만 적음). */
|
||||
@@ -23,16 +26,31 @@ const BOX_PRESETS: Record<string, readonly [number, number]> = {
|
||||
"3.0×3.0": [3, 3],
|
||||
};
|
||||
|
||||
/** 유입 · 유출 구조 — 같은 선택지 · 키만 다름. */
|
||||
const structureItem = (key: string): SpecItem => ({
|
||||
id: "structure",
|
||||
label: "구조",
|
||||
kind: "select",
|
||||
key,
|
||||
choices: [
|
||||
{ value: "없음", label: "없음" },
|
||||
{ value: "날개벽", label: "날개벽" },
|
||||
{ value: "흙막이", label: "흙막이" },
|
||||
/** 유입 · 유출 구조 — 같은 선택지 · 키만 다름 · 흙막이면 흙막이 칸(65-2). */
|
||||
const guardContainer = (
|
||||
id: "inlet" | "outlet",
|
||||
title: string,
|
||||
link: string,
|
||||
key: string,
|
||||
): SpecContainer => ({
|
||||
id,
|
||||
title,
|
||||
required: true,
|
||||
none: "없음",
|
||||
link,
|
||||
items: [
|
||||
{
|
||||
id: "structure",
|
||||
label: "구조",
|
||||
kind: "select",
|
||||
key,
|
||||
choices: [
|
||||
{ value: "없음", label: "없음" },
|
||||
{ value: "날개벽", label: "날개벽" },
|
||||
{ value: "흙막이", label: "흙막이" },
|
||||
],
|
||||
},
|
||||
...guardItems({ 흙막이: revetKeys(id) }, undefined, true),
|
||||
],
|
||||
});
|
||||
|
||||
@@ -70,20 +88,10 @@ export const BOX_SPEC: StructureSpec = {
|
||||
customSide("height", "세로 (m)", "body_height_m"),
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "inlet",
|
||||
title: "유입 구조",
|
||||
required: true,
|
||||
link: "gboxin",
|
||||
items: [structureItem("wing_in")],
|
||||
},
|
||||
{
|
||||
id: "outlet",
|
||||
title: "유출 구조",
|
||||
required: true,
|
||||
link: "gboxout",
|
||||
items: [structureItem("wing_out")],
|
||||
},
|
||||
guardContainer("inlet", "유입 구조", "gboxin", "wing_in"),
|
||||
guardContainer("outlet", "유출 구조", "gboxout", "wing_out"),
|
||||
SOIL_ADD,
|
||||
CHUTE_ADD,
|
||||
],
|
||||
// 표 02 에 없는 옛 날개벽 치수 — 화면에서 빼고 값은 남김(지난 정의 값)
|
||||
retired: ["in", "out"].flatMap((side) =>
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
/* =============================================================================
|
||||
* design_structure_ford.ts
|
||||
* 횡단배수 › 세월교 명세 — 사용자 구조물 표 04(`docs/raw/구조물정의_표/04_횡단배수_세월교.md`) 그대로.
|
||||
* 횡단배수 › 세월교 명세 — 사용자 구조물 표 04(`docs/raw/구조물정의_표/04_횡단배수_세월교.md`) + 65장.
|
||||
*
|
||||
* 컨테이너 셋: 세월교(필수) · 유입 구조(필수) · 유출 구조(필수). 구조 · 정본 = 이 명세 · 이름만 정의(M02)에서 바꿈.
|
||||
* 저장 키 = pipe_points.json 옛 키 그대로(B06 세월교 세트 · B07 · B08 이 읽는 자리) — 새 키 = 유입 · 유출 구조
|
||||
* 컨테이너: 세월교(필수) · 유입 구조(필수) · 유출 구조(필수) · 흙막이(선택 · 여러 개) · 도수로/돌붙임(선택 · 하나).
|
||||
* 구조 · 정본 = 이 명세 · 이름만 정의(M02)에서 바꿈.
|
||||
* 저장 키 = pipe_points.json 옛 키 그대로(B06 세월교 세트 · B07 · B08 이 읽는 자리) — 유입 · 유출 구조
|
||||
* (`inlet_type` · `outlet_type` = 없음 · 날개벽 · 흙막이) · 고르면 옛 날개벽 설치 칸(`wing_in` · `wing_out`)도 함께 적음.
|
||||
* 흙막이 = 배관과 같은 양식(`design_structure_guard` · 키 `{side}_revet_*` · 65-2) · 구조 「없음」 = 목록 램프 · 잇기 줄 없음(65-3).
|
||||
* 월류 높이 = 월류 폭과 연동(폭을 바꾸면 필요 수심으로 채움 · 그 아래로는 안 받음) — 계산은 `design_structure_ford_calc`.
|
||||
* import 없음 — 시험이 이 파일만 옮겨 돌림.
|
||||
* import = 같은 폴더 명세뿐 — 시험이 이 폴더 파일만 옮겨 돌림.
|
||||
* ========================================================================== */
|
||||
|
||||
import type { SpecContainer, SpecChoice, StructureSpec } from "./design_structure_spec";
|
||||
import { CHUTE_ADD, guardItems, revetKeys, SOIL_ADD } from "./design_structure_guard";
|
||||
|
||||
/** 유입 · 유출 구조 — 날개벽만 옛 설치 칸이 「있음」. */
|
||||
const guard = (side: "in" | "out"): SpecChoice[] => [
|
||||
@@ -22,6 +25,7 @@ const guardContainer = (id: "inlet" | "outlet", title: string, link: string): Sp
|
||||
id,
|
||||
title,
|
||||
required: true,
|
||||
none: "없음",
|
||||
link,
|
||||
items: [
|
||||
{
|
||||
@@ -31,6 +35,7 @@ const guardContainer = (id: "inlet" | "outlet", title: string, link: string): Sp
|
||||
key: `${id}_type`,
|
||||
choices: guard(id === "inlet" ? "in" : "out"),
|
||||
},
|
||||
...guardItems({ 흙막이: revetKeys(id) }, undefined, true),
|
||||
],
|
||||
});
|
||||
|
||||
@@ -51,13 +56,16 @@ export const FORD_SPEC: StructureSpec = {
|
||||
asNumber: true,
|
||||
choices: ["800", "1000", "1200", "1500"].map((v) => ({ value: v, label: v })),
|
||||
},
|
||||
{ id: "count", label: "수량 (련)", kind: "number", key: "pipe_count", step: 1 }, // 관경 바로 뒤(65-4)
|
||||
// 월류 폭 · 높이 = 물넘이 포장과 같은 키 · 같은 계산(65-5 · B06 횡단이 읽음)
|
||||
{ id: "width", label: "월류 폭 (m)", kind: "number", key: "ford_width_m", step: 0.1 },
|
||||
{ id: "height", label: "월류 높이 (m)", kind: "number", key: "ford_height_m", step: 0.01 },
|
||||
{ id: "count", label: "수량 (련)", kind: "number", key: "pipe_count", step: 1 },
|
||||
],
|
||||
},
|
||||
guardContainer("inlet", "유입 구조", "gfordin"),
|
||||
guardContainer("outlet", "유출 구조", "gfordout"),
|
||||
SOIL_ADD,
|
||||
CHUTE_ADD,
|
||||
],
|
||||
// 표 04 에 없는 옛 칸 — 화면에서 빼고 값은 남김(지난 정의 값)
|
||||
retired: [
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
* design_structure_ford_pavement.ts
|
||||
* 횡단배수 › 물넘이 포장 명세 — 사용자 구조물 표 03(`docs/raw/구조물정의_표/03_횡단배수_물넘이포장.md`) 그대로.
|
||||
*
|
||||
* 컨테이너 둘: 경사각도(필수 · 각도 손 입력 · 도) · 도수로/돌붙임(선택 · 구조 = 도수로 · 돌붙임).
|
||||
* 저장 = pipe_points.json `options` — 새 키 `ford_slope_deg` · 선택 컨테이너 `ford_chute_{n}_structure`.
|
||||
* 컨테이너 둘: 경사각도(필수 · 각도 손 입력 · 도 + 월류 폭 · 높이 · 65-5) · 도수로/돌붙임(선택 · 구조 = 도수로 · 돌붙임).
|
||||
* 저장 = pipe_points.json `options` — 새 키 `ford_slope_deg` · 선택 컨테이너 `ford_chute_{n}_structure` ·
|
||||
* 월류 폭 · 높이 = 세월교와 같은 키(`ford_width_m` · `ford_height_m`) · 같은 계산(`design_structure_ford_calc`).
|
||||
* 경사각도는 옛 「바닥 경사(%)」(`ford_slope_pct` · B06 파임 기울기)와 뜻이 같은지 또렷하지 않아 잇지 않음.
|
||||
* import 없음 — 시험이 이 파일만 옮겨 돌림.
|
||||
* ========================================================================== */
|
||||
@@ -20,6 +21,8 @@ export const FORD_PAVEMENT_SPEC: StructureSpec = {
|
||||
link: "gfordpaveslope",
|
||||
items: [
|
||||
{ id: "angle", label: "경사각도 (°)", kind: "number", key: "ford_slope_deg", step: 0.1 },
|
||||
{ id: "width", label: "월류 폭 (m)", kind: "number", key: "ford_width_m", step: 0.1 },
|
||||
{ id: "height", label: "월류 높이 (m)", kind: "number", key: "ford_height_m", step: 0.01 },
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -43,5 +46,5 @@ export const FORD_PAVEMENT_SPEC: StructureSpec = {
|
||||
},
|
||||
],
|
||||
// 표 03 에 없는 옛 칸 — 화면에서 빼고 값은 남김(지난 정의 값)
|
||||
retired: ["ford_width_m", "ford_height_m", "ford_slope_pct", "thickness_cm", "length_m"],
|
||||
retired: ["ford_slope_pct", "thickness_cm", "length_m"],
|
||||
};
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
choiceLabel,
|
||||
choicesOf,
|
||||
containerTitle,
|
||||
isNone,
|
||||
itemLabel,
|
||||
linkOf,
|
||||
readState,
|
||||
@@ -190,11 +191,13 @@ export function createSpecForm(links: SpecLinks | null, hooks: SpecFormHooks = {
|
||||
for (const r of ["length", "before", "after"] as SplitRole[])
|
||||
values[role(r).id] = solved[r] ?? "";
|
||||
}
|
||||
// 위 항목이 바뀌면 갈래(선택지 · 저장 키)가 달라짐 — 선택지 밖 값은 비움
|
||||
// 위 항목이 바뀌면 갈래(선택지 · 저장 키)가 달라짐 — 선택지 밖 값은 비움 · 새로 선 빈 칸은 기본값(65-2)
|
||||
for (const child of c.items.filter((i) => i.by?.item === item.id)) {
|
||||
const allowed = choicesOf(child, values);
|
||||
if (child.kind === "select" && !allowed.some((ch) => ch.value === values[child.id]))
|
||||
values[child.id] = "";
|
||||
if (child.default && !values[child.id] && branchOf(child, values))
|
||||
values[child.id] = child.default;
|
||||
}
|
||||
paint();
|
||||
hooks.onChange?.(c, item);
|
||||
@@ -252,7 +255,7 @@ export function createSpecForm(links: SpecLinks | null, hooks: SpecFormHooks = {
|
||||
}
|
||||
box.body.append(slot);
|
||||
}
|
||||
if (links) {
|
||||
if (links && !isNone(c, values)) {
|
||||
const key = linkOf(c, index + 1);
|
||||
const row = buildSummaryRow();
|
||||
row.root.querySelector(".b05-structure__summary-label")!.textContent = "구조물 조합";
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
/* =============================================================================
|
||||
* design_structure_guard.ts
|
||||
* 흙막이 공통 양식 — 배관(표 01) · 박스암거(표 02) · 세월교(표 04)가 같은 칸을 씀(PLAN 65-2).
|
||||
*
|
||||
* · 흙막이 = 형태 6 · 길이 · 높이 · 기준측점 전 · 후(길이 = 전 + 후 맞물림)
|
||||
* · 필수 보호공(유입 · 유출)은 구조 갈래마다 저장 키(`{side}_revet_*` 옛 키) · 선택 흙막이 · 도수로/돌붙임은
|
||||
* 인스턴스 키(`soil_add_{n}_*` · `chute_add_{n}_*`)
|
||||
* import = 꼴만 — 시험이 이 폴더 파일만 옮겨 돌림.
|
||||
* ========================================================================== */
|
||||
|
||||
import type { SpecChoice, SpecContainer, SpecItem } from "./design_structure_spec";
|
||||
|
||||
export const SOIL_FORMS: SpecChoice[] = [
|
||||
{ value: "돌쌓기(찰)", label: "돌 쌓기(찰)" },
|
||||
{ value: "돌쌓기(메)", label: "돌 쌓기(메)" },
|
||||
{ value: "콘크리트", label: "콘크리트" },
|
||||
{ value: "돌망태", label: "돌망태" },
|
||||
{ value: "통나무·목재틀", label: "통나무/목재틀" },
|
||||
{ value: "바자", label: "바자" },
|
||||
];
|
||||
|
||||
/** 흙막이 기본값(54-36 · 사면안정 흙막이 정의 기본값과 같음). */
|
||||
const SOIL_DEFAULTS: Record<string, string> = {
|
||||
form: "돌쌓기(찰)",
|
||||
length: "10",
|
||||
height: "1.5",
|
||||
before: "5",
|
||||
after: "5",
|
||||
};
|
||||
|
||||
/** 형태 · 길이 · 높이 · 전 · 후 — 필수 보호공은 구조 갈래마다 옛 키(`keys`) · 선택 흙막이는 인스턴스 키.
|
||||
* `forms` = 갈래별 형태 선택지(배관 집수정 등) · `defaults` = 새 상자 · 흙막이를 고를 때 칸에 실제 값. */
|
||||
export function guardItems(
|
||||
keys?: Record<string, Record<string, string>>,
|
||||
forms?: Record<string, SpecChoice[]>,
|
||||
defaults = !keys,
|
||||
): SpecItem[] {
|
||||
const by = (field: string, choices?: Record<string, SpecChoice[]>) =>
|
||||
keys
|
||||
? {
|
||||
item: "structure",
|
||||
map: Object.fromEntries(
|
||||
// 키 없는 갈래 = 그 구조에 없는 칸(집수정 길이 · 전 · 후) — 가림
|
||||
Object.entries(keys)
|
||||
.filter(([, k]) => k[field])
|
||||
.map(([structure, k]) => [
|
||||
structure,
|
||||
{ key: k[field], choices: choices?.[structure] },
|
||||
]),
|
||||
),
|
||||
}
|
||||
: undefined;
|
||||
const items: SpecItem[] = [
|
||||
{ id: "form", label: "형태", kind: "select", choices: SOIL_FORMS, by: by("form", forms) },
|
||||
{ id: "length", label: "길이 (m)", kind: "number", split: "length", step: 1, by: by("length") },
|
||||
{ id: "height", label: "높이 (m)", kind: "number", step: 0.1, by: by("height") },
|
||||
{
|
||||
id: "before",
|
||||
label: "기준측점 전 (m)",
|
||||
kind: "number",
|
||||
split: "before",
|
||||
step: 0.5,
|
||||
by: by("before"),
|
||||
},
|
||||
{
|
||||
id: "after",
|
||||
label: "기준측점 후 (m)",
|
||||
kind: "number",
|
||||
split: "after",
|
||||
step: 0.5,
|
||||
by: by("after"),
|
||||
},
|
||||
];
|
||||
return defaults ? items.map((item) => ({ ...item, default: SOIL_DEFAULTS[item.id] })) : items;
|
||||
}
|
||||
|
||||
export const revetKeys = (side: "inlet" | "outlet"): Record<string, string> => ({
|
||||
form: `${side}_revet_form`,
|
||||
length: `${side}_revet_length_m`,
|
||||
height: `${side}_revet_height_m`,
|
||||
before: `${side}_revet_before_m`,
|
||||
after: `${side}_revet_after_m`,
|
||||
});
|
||||
|
||||
/** 추가 흙막이(선택 · 여러 개) — 사면안정 흙막이(표 09 · 54-26)와 같은 칸 · 구조 고르기 없음(54-30). */
|
||||
export const SOIL_ADD: SpecContainer = {
|
||||
id: "soil_add",
|
||||
title: "흙막이",
|
||||
required: false,
|
||||
prefix: "soil_add",
|
||||
link: "gsoiladd",
|
||||
items: guardItems(),
|
||||
};
|
||||
|
||||
/** 도수로/돌붙임(선택 · 하나만 · 54-48) — 옛 둘 이상은 보이되 [추가]만 숨김. */
|
||||
export const CHUTE_ADD: SpecContainer = {
|
||||
id: "chute_add",
|
||||
title: "도수로/돌붙임",
|
||||
required: false,
|
||||
prefix: "chute_add",
|
||||
link: "gchuteadd",
|
||||
max: 1,
|
||||
items: [
|
||||
{
|
||||
id: "structure",
|
||||
label: "구조",
|
||||
kind: "select",
|
||||
choices: [
|
||||
{ value: "도수로", label: "도수로" },
|
||||
{ value: "돌붙임", label: "돌붙임" },
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -13,6 +13,7 @@
|
||||
* ========================================================================== */
|
||||
|
||||
import type { SpecChoice, SpecItem, StructureSpec } from "./design_structure_spec";
|
||||
import { CHUTE_ADD, guardItems, revetKeys, SOIL_ADD, SOIL_FORMS } from "./design_structure_guard";
|
||||
import { BOX_SPEC } from "./design_structure_box";
|
||||
import { FORD_SPEC } from "./design_structure_ford";
|
||||
import { FORD_PAVEMENT_SPEC } from "./design_structure_ford_pavement";
|
||||
@@ -20,83 +21,14 @@ import { ETC_SPEC, PAVEMENT_SPEC } from "./design_structure_road";
|
||||
|
||||
const SOIL = "기슭막이"; // 저장 값(옛 키 그대로) — 화면 이름은 흙막이
|
||||
const BASIN = "집수정";
|
||||
const SOIL_FORMS: SpecChoice[] = [
|
||||
{ value: "돌쌓기(찰)", label: "돌 쌓기(찰)" },
|
||||
{ value: "돌쌓기(메)", label: "돌 쌓기(메)" },
|
||||
{ value: "콘크리트", label: "콘크리트" },
|
||||
{ value: "돌망태", label: "돌망태" },
|
||||
{ value: "통나무·목재틀", label: "통나무/목재틀" },
|
||||
{ value: "바자", label: "바자" },
|
||||
];
|
||||
const BASIN_FORMS: SpecChoice[] = [
|
||||
{ value: "I", label: "I형" },
|
||||
{ value: "L", label: "L형" },
|
||||
{ value: "U", label: "ㄷ형" },
|
||||
];
|
||||
|
||||
/** 추가 흙막이 기본값(54-36 · 사면안정 흙막이 정의 기본값과 같음) — 필수 보호공 기본값은 정의 파일. */
|
||||
const SOIL_ADD_DEFAULTS: Record<string, string> = {
|
||||
form: "돌쌓기(찰)",
|
||||
length: "10",
|
||||
height: "1.5",
|
||||
before: "5",
|
||||
after: "5",
|
||||
};
|
||||
|
||||
/** 형태 · 길이 · 높이 · 전 · 후 — 필수 보호공은 구조 갈래마다 옛 키 · 선택 흙막이는 인스턴스 키. */
|
||||
function guardItems(keys?: Record<string, Record<string, string>>): SpecItem[] {
|
||||
const by = (field: string, choices?: Record<string, SpecChoice[]>) =>
|
||||
keys
|
||||
? {
|
||||
item: "structure",
|
||||
map: Object.fromEntries(
|
||||
// 키 없는 갈래 = 그 구조에 없는 칸(집수정 길이 · 전 · 후) — 가림
|
||||
Object.entries(keys)
|
||||
.filter(([, k]) => k[field])
|
||||
.map(([structure, k]) => [
|
||||
structure,
|
||||
{ key: k[field], choices: choices?.[structure] },
|
||||
]),
|
||||
),
|
||||
}
|
||||
: undefined;
|
||||
const items: SpecItem[] = [
|
||||
{
|
||||
id: "form",
|
||||
label: "형태",
|
||||
kind: "select",
|
||||
choices: SOIL_FORMS,
|
||||
by: by("form", { [BASIN]: BASIN_FORMS, [SOIL]: SOIL_FORMS }),
|
||||
},
|
||||
{ id: "length", label: "길이 (m)", kind: "number", split: "length", step: 1, by: by("length") },
|
||||
{ id: "height", label: "높이 (m)", kind: "number", step: 0.1, by: by("height") },
|
||||
{
|
||||
id: "before",
|
||||
label: "기준측점 전 (m)",
|
||||
kind: "number",
|
||||
split: "before",
|
||||
step: 0.5,
|
||||
by: by("before"),
|
||||
},
|
||||
{
|
||||
id: "after",
|
||||
label: "기준측점 후 (m)",
|
||||
kind: "number",
|
||||
split: "after",
|
||||
step: 0.5,
|
||||
by: by("after"),
|
||||
},
|
||||
];
|
||||
return keys ? items : items.map((item) => ({ ...item, default: SOIL_ADD_DEFAULTS[item.id] }));
|
||||
}
|
||||
|
||||
const revetKeys = (side: "inlet" | "outlet"): Record<string, string> => ({
|
||||
form: `${side}_revet_form`,
|
||||
length: `${side}_revet_length_m`,
|
||||
height: `${side}_revet_height_m`,
|
||||
before: `${side}_revet_before_m`,
|
||||
after: `${side}_revet_after_m`,
|
||||
});
|
||||
/** 보호공 형태 · 길이 · 높이 · 전 · 후 — 구조 갈래마다 옛 키(흙막이 양식 = `design_structure_guard`). */
|
||||
const protectItems = (keys: Record<string, Record<string, string>>): SpecItem[] =>
|
||||
guardItems(keys, { [BASIN]: BASIN_FORMS, [SOIL]: SOIL_FORMS });
|
||||
|
||||
export const PIPE_SPEC: StructureSpec = {
|
||||
typeId: "pipe",
|
||||
@@ -134,7 +66,7 @@ export const PIPE_SPEC: StructureSpec = {
|
||||
{ value: SOIL, label: "흙막이", also: { inlet_structure: "revet" } },
|
||||
],
|
||||
},
|
||||
...guardItems({
|
||||
...protectItems({
|
||||
[BASIN]: { form: "inlet_structure", height: "inlet_basin_height_m" },
|
||||
[SOIL]: revetKeys("inlet"),
|
||||
}),
|
||||
@@ -153,37 +85,11 @@ export const PIPE_SPEC: StructureSpec = {
|
||||
key: "outlet_type",
|
||||
choices: [{ value: SOIL, label: "흙막이" }],
|
||||
},
|
||||
...guardItems({ [SOIL]: revetKeys("outlet") }),
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "soil_add",
|
||||
title: "흙막이",
|
||||
required: false,
|
||||
prefix: "soil_add",
|
||||
link: "gsoiladd",
|
||||
// 사면안정 흙막이(표 09 · 54-26)와 같은 칸 — 형태 6 · 길이 · 높이 · 전 · 후 · 구조 고르기 없음(54-30)
|
||||
items: guardItems(),
|
||||
},
|
||||
{
|
||||
id: "chute_add",
|
||||
title: "도수로/돌붙임",
|
||||
required: false,
|
||||
prefix: "chute_add",
|
||||
link: "gchuteadd",
|
||||
max: 1, // 하나만(54-48) — 옛 둘 이상은 보이되 [추가]만 숨김
|
||||
items: [
|
||||
{
|
||||
id: "structure",
|
||||
label: "구조",
|
||||
kind: "select",
|
||||
choices: [
|
||||
{ value: "도수로", label: "도수로" },
|
||||
{ value: "돌붙임", label: "돌붙임" },
|
||||
],
|
||||
},
|
||||
...protectItems({ [SOIL]: revetKeys("outlet") }),
|
||||
],
|
||||
},
|
||||
SOIL_ADD, // 개수 = 유출 「추가 기슭막이(단)」(54-1)
|
||||
CHUTE_ADD,
|
||||
],
|
||||
// 표 01 에 없는 옛 칸 — 화면에서 빼고 값은 남김(지난 정의 값)
|
||||
retired: ["pipe_kind", "wing_wall_type", "inlet_basin_form", "inlet_basin_material"],
|
||||
|
||||
@@ -59,6 +59,8 @@ export interface SpecContainer {
|
||||
max?: number;
|
||||
/** 구조물 조합 잇기 키 — 필수는 정의 그룹 id 그대로 · 선택은 뒤에 n. */
|
||||
link: string;
|
||||
/** 첫 항목이 이 값이면 그 컨테이너는 없는 셈 — 목록 램프 · 잇기 줄 뺌(65-3 · 세월교 · 박스 유입 · 유출 「없음」). */
|
||||
none?: string;
|
||||
items: SpecItem[];
|
||||
}
|
||||
|
||||
@@ -103,6 +105,10 @@ export function choicesOf(item: SpecItem, values: Instance): SpecChoice[] {
|
||||
return branchOf(item, values)?.choices ?? item.choices ?? [];
|
||||
}
|
||||
|
||||
/** 컨테이너가 「없음」으로 골라졌는지(`none`). */
|
||||
export const isNone = (c: SpecContainer, values: Instance): boolean =>
|
||||
!!c.none && values[c.items[0]?.id] === c.none;
|
||||
|
||||
/** 인스턴스 잇기 키 — 필수 = 그룹 id · 선택 = `{link}{n}`. */
|
||||
export const linkOf = (c: SpecContainer, n: number): string =>
|
||||
c.required ? c.link : `${c.link}${n}`;
|
||||
|
||||
Reference in New Issue
Block a user