/* ============================================================================= * M02_MasterTemplete_Sangeun_BaseHead.ts * 단가산출(SK) 둘째 기초 머리 줄(PLAN 748-0) — 기초마다 한 줄: 이름 · 「수량(기준단위 몇 개)」 칸 하나 · * [되돌림](넣을 때 수량으로) · [기초 빼기]. 세부 품은 M01 원문 그대로 보임(머리 수량은 이 칸 하나로). * 값은 문서 `더한줄[k].수량`(화면배 t 로 나눈 화면 값) — 금액은 서버가 셈 · 여기는 칸 · 단추만. * ========================================================================== */ import { createBadge } from "@ui/ui_template_badge"; import { createButton } from "@ui/ui_template_button"; import { createCard } from "@ui/ui_template_card"; import { el } from "@ui/ui_template_elements"; import { createInputField } from "@ui/ui_template_input"; import { t as L } from "@ui/ui_template_locale"; import { createText } from "@ui/ui_template_text"; import type { SkAnswer, SkDoc } from "./logic/M02_Sangeun_Cover_Model"; export interface BaseHeadOptions { doc: SkDoc; ans: SkAnswer | null; edit: boolean; /** 칸에서 고른 새 수량(화면 값) */ onQty: (k: number, qty: number) => void; onReset: (k: number) => void; onDrop: (k: number, name: string) => void; } const shown = (v: number): string => String(Number(v.toPrecision(8))); const same = (a: number, b: number): boolean => Math.abs(a - b) <= 1e-9 * Math.max(1, Math.abs(a)); /** 둘째 기초(더한줄 로직)마다 머리 줄 한 상자 — 없으면 빈 목록 */ export function baseHeads(o: BaseHeadOptions): HTMLElement[] { const t = o.ans?.화면배 ?? 1; const rows = (o.doc.더한줄 ?? []).flatMap((one, k) => { if (one.종류 !== "로직") return []; const line = o.ans?.줄.find((x) => x.cid === `add:#${k}`); const name = line?.이름 || String(one.로직 ?? ""); const box = createInputField({ label: L("M02_SangeunBaseQty"), value: shown(one.수량 / t), compact: true, size: 28, }); box.input.inputMode = "decimal"; box.input.disabled = !o.edit; box.input.dataset.baseQty = String(k); box.input.addEventListener("change", () => { const v = Number(box.input.value.replaceAll(",", "").trim()); if (box.input.value.trim() === "" || !Number.isFinite(v) || v < 0) return box.setError(L("M02_SangeunBaseQtyBad")); box.setError(undefined); if (!same(v, one.수량 / t)) o.onQty(k, v); }); const first = one.처음수량; return [ el("div", { className: "m02-sk__basehead", attrs: { "data-base-head": String(k) }, children: [ el("span", { className: "m02-sk__basename", text: name }), ...(line?.꼬리표 ? [createBadge(line.꼬리표, "neutral")] : []), box.root, ...(line?.단위 ? [createText(line.단위, "muted")] : []), ...(o.edit && first != null && !same(first, one.수량) ? [ createButton({ label: L("M02_SangeunQtyUndo"), variant: "ghost", size: 28, onClick: () => o.onReset(k), }), ] : []), ...(o.edit ? [ createButton({ label: L("M02_SangeunDropBase"), variant: "danger-ghost", size: 28, onClick: () => o.onDrop(k, name), }), ] : []), ], }), ]; }); if (!rows.length) return []; const card = createCard({ title: L("M02_SangeunBases"), pad: 12, body: rows }); card.classList.add("m01lab__ho-box"); // 상자 제목 · 안 간격 = 공용 상세 상자와 같음 card.dataset.baseHeads = ""; return [card]; }