- 잇기 단추 글 「고르기」 → 「선택」(명세 · 정의 그룹 · 종류 단위 줄 공용) - 「지난 정의 값」 상자 모든 종류에서 숨김 — 값은 파일에 그대로 · 코드 남김 - 관 길이 = 보여 주는 칸(손 입력 칸 아님 · 정수 · 횡단 전 「횡단 설계 뒤 셈」) - 유입 집수정 = 길이 · 기준측점 전 · 후 칸 숨김 · 옛 값은 병합이 지킴 - 배관 유출 칸에 읽기 줄(관 길이 · 좌우 자동 자리 안내) 안 옮김 - [흙막이 추가] 없앰 — 흙막이 컨테이너 수 = 유출 「추가 기슭막이(단)」 N(늘 보임 · 줄면 끝에서 빠짐 · 잇기 함께 풂 · 이름 흙막이) - 단 수 소스 = 횡단 세션 값 → 캐시 patch · 종단 보기도 같은 횡단 자료(B05 = B06) - 지형이 단을 못 세워 되돌릴 때 캐시 patch 도 맞춤(옛 수로 돌아가던 흠) - 집계표 선택 컨테이너 이름 짝(서버) 흙막이 · 시험 기대값 · 52-1 · 52-13 화면 시나리오 고침 · 54-1 화면 점검 추가 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BVPp2o6Mh2FZJr72yW3ofZ
120 lines
5.7 KiB
TypeScript
120 lines
5.7 KiB
TypeScript
/* =============================================================================
|
|
* B05_Profile_UI_Drainage_Facility_Merge.ts
|
|
* 계곡 통과 시설 [저장] — **폼이 아는 칸만 갈아 끼우고, 폼이 모르는 칸은 건드리지 않음**
|
|
* (2026-09-14 브레인 판정).
|
|
*
|
|
* ⚠ 앞서 저장이 옵션을 **통째로** 갈아 끼웠음 — 구조물 집계표·구조물도로 적은 칸(관 기슭막이
|
|
* 기초 `revet_foundation` · 독립 기슭막이 `foundation`·뒷길이·돌 종류 …)이 B05 에서 그 시설을
|
|
* 한 번 더 저장하면 **조용히 지워졌음**. 「작업본 쓰기는 [저장]에서만」인데 그 [저장]이 옆 칸까지
|
|
* 지우던 자리.
|
|
* ⚠ 통째로 갈아 끼우는 것은 **시설 종류 자체를 바꿀 때만** — 그때는 옛 칸이 뜻을 잃음.
|
|
* ⚠ 폼이 아는 칸을 폼이 비워 보내면(값을 지움·유입구를 집수정 → 기슭막이로 바꿔 집수정 칸이 빠짐)
|
|
* 그 칸은 지워짐 — 사용자가 폼에서 한 일이므로 맞음.
|
|
* ⚠ 폼에 칸을 늘리면 아래 목록에도 넣을 것. 빠뜨리면 그 칸을 **폼에서 지워도 옛 값이 남는**
|
|
* 쪽으로 틀림(지워지는 쪽보다 덜 위험). 거울 시험 `test_b05_facility_options_merge`.
|
|
* ⚠ import 없음 — 시험이 이 파일만 옮겨 돌림.
|
|
* ========================================================================== */
|
|
|
|
const revetKeys = (side: "inlet" | "outlet"): string[] =>
|
|
["form", "length_m", "height_m", "before_m", "after_m"].map((key) => `${side}_revet_${key}`);
|
|
|
|
/** 시설 종류별로 **폼이 적는 칸** — `createFacilityOptionsForm().readOptions()` 가 쓰는 키 전부. */
|
|
export const FORM_OPTION_KEYS: Readonly<Record<string, readonly string[]>> = {
|
|
// 배관 = 표 01 명세 키(PLAN 52-1 · `design_structure_pipe`) — 옛 관종 · 날개벽 · 집수정 형식은 폼에서
|
|
// 빠져 이어 붙임(지난 정의 값) · 선택 컨테이너 키는 `FORM_OPTION_PREFIXES`
|
|
pipe: [
|
|
"pipe_diameter_mm",
|
|
"inlet_type",
|
|
"inlet_structure",
|
|
// 집수정 길이 · 전 · 후는 폼에서 빠짐(54-1) — 옛 값 그대로 둠
|
|
"inlet_basin_height_m",
|
|
...revetKeys("inlet"),
|
|
"outlet_type",
|
|
...revetKeys("outlet"),
|
|
],
|
|
// BOX = 표 02 명세 키(PLAN 52-2) — 옛 날개벽 치수는 폼에서 빠져 이어 붙임(지난 정의 값)
|
|
box_culvert: ["body_width_m", "body_height_m", "body_custom", "wing_in", "wing_out"],
|
|
// 물넘이 포장 = 표 03 명세 키(PLAN 52-3 · `design_structure_ford_pavement`) — 옛 월류 · 경사 · 두께 · 길이는
|
|
// 폼에서 빠져 이어 붙임 · 도수로/돌붙임 키는 `FORM_OPTION_PREFIXES`
|
|
ford_pavement: ["ford_slope_deg"],
|
|
// 세월교 = 표 04 명세 키(PLAN 52-4 · `design_structure_ford`) — 옛 관종 · 날개벽 치수는 폼에서 빠져 이어 붙임
|
|
ford_bridge: [
|
|
"pipe_diameter_mm",
|
|
"pipe_count",
|
|
"ford_width_m",
|
|
"ford_height_m",
|
|
"inlet_type",
|
|
"outlet_type",
|
|
"wing_in",
|
|
"wing_out",
|
|
],
|
|
revetment: ["side", ...revetKeys("inlet"), ...revetKeys("outlet")],
|
|
};
|
|
|
|
/** 폼이 인스턴스 번호를 붙여 적는 키 머리(명세 선택 컨테이너 · `{머리}{n}_{항목}`) — 빼면 지워짐. */
|
|
export const FORM_OPTION_PREFIXES: Readonly<Record<string, readonly string[]>> = {
|
|
pipe: ["soil_add_", "chute_add_"],
|
|
ford_pavement: ["ford_chute_"],
|
|
};
|
|
|
|
/** 독립 기슭막이 레지스트리 키 → 폼은 유입·유출 두 채널 키로 적는다. */
|
|
const REVETMENT_FIELDS = ["form", "length_m", "height_m", "before_m", "after_m"];
|
|
|
|
/** 「구조물 옵션 보이기」에서 끈 레지스트리 키 → 시설 폼이 가릴 칸 키(21-10 흠 8).
|
|
* · 독립 기슭막이는 채널 키(`inlet_revet_*` · `outlet_revet_*`)로 넓힘
|
|
* · 유입구 「구조」한 칸이 `inlet_type` 과 `inlet_structure` 를 함께 적음 */
|
|
export function hiddenFormKeys(
|
|
facility: string | null,
|
|
registryHidden: Iterable<string>,
|
|
): Set<string> {
|
|
const hidden = new Set<string>(registryHidden);
|
|
if (facility === "revetment") {
|
|
for (const field of REVETMENT_FIELDS) {
|
|
if (!hidden.has(field)) continue;
|
|
hidden.add(`inlet_revet_${field}`);
|
|
hidden.add(`outlet_revet_${field}`);
|
|
}
|
|
}
|
|
if (hidden.has("inlet_type")) hidden.add("inlet_structure");
|
|
return hidden;
|
|
}
|
|
|
|
interface MergeableAttributes {
|
|
facility: string;
|
|
start_m?: number;
|
|
end_m?: number;
|
|
options?: Record<string, string | number>;
|
|
/** 집계 항목(options 밖) — 다음 값에 칸이 없으면(undefined) 옛 지정을 그대로 잇는다. */
|
|
summary_item?: unknown;
|
|
/** 옵션 그룹 집계 항목(PLAN 46-3) — 다음 값에 칸이 없으면(undefined) 옛 지정을 그대로 잇는다. */
|
|
group_items?: unknown;
|
|
}
|
|
|
|
/** 저장할 시설 정보 — 같은 종류면 폼이 모르는 옛 칸을 이어 붙임. */
|
|
export function mergeFacilityOptions<T extends MergeableAttributes>(
|
|
previous: T | null,
|
|
next: T,
|
|
): T {
|
|
if (!previous || previous.facility !== next.facility) return next;
|
|
const managed = new Set(FORM_OPTION_KEYS[next.facility] ?? []);
|
|
const heads = FORM_OPTION_PREFIXES[next.facility] ?? [];
|
|
const kept = Object.entries(previous.options ?? {}).filter(
|
|
([key]) => !managed.has(key) && !heads.some((head) => key.startsWith(head)),
|
|
);
|
|
const options = { ...Object.fromEntries(kept), ...(next.options ?? {}) };
|
|
const summary =
|
|
next.summary_item === undefined && previous.summary_item !== undefined
|
|
? { summary_item: previous.summary_item }
|
|
: {};
|
|
const groups =
|
|
next.group_items === undefined && previous.group_items !== undefined
|
|
? { group_items: previous.group_items }
|
|
: {};
|
|
return {
|
|
...next,
|
|
...summary,
|
|
...groups,
|
|
options: Object.keys(options).length ? options : undefined,
|
|
};
|
|
}
|