화면: 칸 빈 값 · 회색 「제안(비우면 안 정함): 성토면 · 기계 · 무한궤도 — 영월 실무…」 · 단추 누르면 칸만 바뀌고 저장값은 그대로 빈 값(저장 안 함) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
125 lines
4.4 KiB
TypeScript
125 lines
4.4 KiB
TypeScript
/* =============================================================================
|
|
* B08_Quantity_UI_Side_FaceDressing.ts
|
|
* 산출 조건 「면고르기」 구획 — 절토면 토질 · 성토면 시공·토질 고르기 둘 + 면적 덮어쓰기 둘
|
|
* (2026-09-14 브레인 판정 Ⓐ~Ⓓ · 서버 ee9368ec).
|
|
*
|
|
* 페이지 본문(`B08_Quantity_UI_Page.ts`)이 700줄을 넘어 새 칸을 이 파일로 뺌(CLAUDE.md 4장).
|
|
* ⚠ 선택지는 **서버가 내려준 목록 그대로**(`face_dressing_choices`) — 화면에 다시 적지 않음(두 벌 금지).
|
|
* ⚠ 스스로 안 고름(판정 Ⓒ) — 첫 보기가 「안 정함」이고 비면 내역 줄이 입력 사유로 섬. 성토면 제안은
|
|
* 회색 근거 + [제안값 넣기]를 **누른 때만**(메인 976e5fd9 `fill_suggested`).
|
|
* ⚠ 면적은 화면이 셈하지 않음 — 비우면 서버가 파종 면적(초류종자살포 × 반영률)을 씀.
|
|
* ========================================================================== */
|
|
|
|
import { ui_locales, currentLanguageIndex } from "@ui/ui_template_locale";
|
|
import { createButton } from "@ui/ui_template_elements";
|
|
import type { SideFieldHelpers } from "./B08_Quantity_UI_Side_TreeWaste";
|
|
|
|
function L(key: keyof typeof ui_locales): string {
|
|
return ui_locales[key][currentLanguageIndex];
|
|
}
|
|
|
|
export interface FaceDressingDraft {
|
|
/** `""` 는 「안 정함」 — 서버가 선택지 밖 값도 `""` 로 되돌림. */
|
|
face_dressing_cut_class: string;
|
|
face_dressing_fill_class: string;
|
|
/** `null` 은 「파종 면적 그대로」. */
|
|
face_dressing_fill_area_m2: number | null;
|
|
face_dressing_cut_area_m2: number | null;
|
|
dirty: boolean;
|
|
}
|
|
|
|
export interface FaceDressingChoices {
|
|
cut: string[];
|
|
fill: string[];
|
|
/** 성토면 제안(서버 한 곳 · 실무 관측) — 회색으로 보이고 [제안값 넣기]를 **누른 때만** 들어감. */
|
|
fill_suggested?: { value: string; basis: string };
|
|
}
|
|
|
|
export function appendFaceDressingFields(
|
|
panel: HTMLElement,
|
|
draft: FaceDressingDraft,
|
|
choices: FaceDressingChoices | undefined,
|
|
h: SideFieldHelpers,
|
|
): void {
|
|
if (!choices) return;
|
|
const pick = (
|
|
label: keyof typeof ui_locales,
|
|
value: string,
|
|
list: string[],
|
|
set: (value: string) => void,
|
|
): HTMLElement =>
|
|
h.selectField(
|
|
L(label),
|
|
value,
|
|
[
|
|
{ value: "", label: L("B08_Quantity_FaceDressing_Unset") },
|
|
...list.map((name) => ({ value: name, label: name })),
|
|
],
|
|
(picked) => {
|
|
set(picked);
|
|
draft.dirty = true;
|
|
},
|
|
);
|
|
const area = (
|
|
label: keyof typeof ui_locales,
|
|
value: number | null,
|
|
set: (v: number | null) => void,
|
|
) => {
|
|
const row = h.optionalNumberField(L(label), value, "0.01", (typed) => {
|
|
set(typed);
|
|
draft.dirty = true;
|
|
});
|
|
const input = row.querySelector("input");
|
|
if (input) input.placeholder = L("B08_Quantity_FaceDressing_Area_Placeholder");
|
|
return row;
|
|
};
|
|
|
|
panel.append(h.field(L("B08_Quantity_Side_FaceDressing"), ""));
|
|
panel.append(
|
|
pick("B08_Quantity_FaceDressing_Cut", draft.face_dressing_cut_class, choices.cut, (v) => {
|
|
draft.face_dressing_cut_class = v;
|
|
}),
|
|
);
|
|
const fillRow = pick(
|
|
"B08_Quantity_FaceDressing_Fill",
|
|
draft.face_dressing_fill_class,
|
|
choices.fill,
|
|
(v) => {
|
|
draft.face_dressing_fill_class = v;
|
|
},
|
|
);
|
|
panel.append(fillRow);
|
|
// 성토면 제안 — 칸은 비워 둔 채 회색 근거 + 단추(층따기와 같은 모양). 비우면 「안 정함」 그대로.
|
|
const suggested = choices.fill_suggested;
|
|
if (suggested?.value) {
|
|
panel.append(
|
|
h.hintRow(
|
|
`${L("B08_Quantity_FaceDressing_Suggest")} ${suggested.value} — ${suggested.basis}`,
|
|
),
|
|
);
|
|
panel.append(
|
|
createButton({
|
|
label: L("B08_Quantity_FaceDressing_FillSuggested"),
|
|
variant: "ghost",
|
|
onClick: () => {
|
|
const select = fillRow.querySelector("select");
|
|
if (select) select.value = suggested.value;
|
|
draft.face_dressing_fill_class = suggested.value;
|
|
draft.dirty = true;
|
|
},
|
|
}),
|
|
);
|
|
}
|
|
panel.append(
|
|
area("B08_Quantity_FaceDressing_FillArea", draft.face_dressing_fill_area_m2, (v) => {
|
|
draft.face_dressing_fill_area_m2 = v;
|
|
}),
|
|
);
|
|
panel.append(
|
|
area("B08_Quantity_FaceDressing_CutArea", draft.face_dressing_cut_area_m2, (v) => {
|
|
draft.face_dressing_cut_area_m2 = v;
|
|
}),
|
|
);
|
|
panel.append(h.hintRow(L("B08_Quantity_Side_FaceDressing_Hint")));
|
|
}
|