/* ============================================================================= * M02_MasterTemplete_Labor_MatTable.ts * 일위대가 자재목록 표(43-3 · `Labor_Rows` 에서 뗌 · 717-3) — 상세 · 보기 갈래가 같이 씀. * 자재목록 = 코드 · 이름 · 규격 · 수량산출 · 단위 · 가격 다섯(기준 칸 강조) · 기준단가 / 반영 금액. * 금액은 calc 답(없으면 「…」) · 줄 누름 · [삭제]는 `on` 이 있을 때만. * ========================================================================== */ import { createButton, el } from "@ui/ui_template_elements"; import { formatMoney } from "../M01_MasterData/M01_MasterData_UI_Logic_Money"; import type { LaborCalc, LaborCalcLine, LaborCalcMat, LaborMat, } from "./M02_MasterTemplete_Labor_Api"; import { markCells, markHeads } from "./M02_MasterTemplete_Labor_MatMarks"; import { moneyCell, PRICE_SLOTS, qtyCell, table, titled, type RowHandlers, } from "./M02_MasterTemplete_Labor_Rows"; import { tc } from "./M02_MasterTemplete_Labor_Text"; export interface MatTableData { mats: LaborMat[]; /** 로직 자재 줄(103-1 · `Labor_LogicMats`) — 사용자 자재 앞 · 같은 칸 */ lead?: HTMLElement[]; calc: LaborCalc | null; fail?: string | null; cells?: ReadonlyMap; } /** 자재목록 표(43-3 · 로직 줄과 같은 꼴) — 코드 · 이름 · 규격 · 수량산출(위 기준 수량 1 단위 / 아래 지금 * 수량) · 단위 · 가격 다섯(빈 것 「—」 · 기준단가가 된 칸 강조) · 금액(위 기준단가 / 아래 반영 = 기준단가 × 수량) · * 보기 갈래는 `on` 없이 */ export function matTable(data: MatTableData, on?: Omit): HTMLElement { const wait = !data.calc && !data.fail; const remove = on?.remove; const show = (v: number | null | undefined): string => wait ? "…" : v === null || v === undefined ? "—" : formatMoney(v); const trs = data.mats.map((mat, i) => { const line: LaborCalcMat | undefined = data.calc?.자재.find((m) => m.코드 === mat.코드); // 수량산출 칸은 로직 줄 칸을 그대로 씀 — 기준 수량 = 자재 단위 1 const qtyLine = { ...line, 배: 1, 분모: mat.단위 ?? "" } as LaborCalcLine; const priceCell = (slot: (typeof PRICE_SLOTS)[number]): HTMLElement => { const base = !!line?.기준칸 && line.기준칸 === slot; return el("td", { className: `m02-labrow__num m02-labrow__price${base ? " is-base-price" : ""}`, text: show(line?.가격?.[slot]), attrs: { "data-label": slot, "data-price-slot": slot, ...(base ? { title: tc("Labor_BasePrice") } : {}), }, }); }; const tr = el("tr", { className: on ? "m02-labrow__row is-open" : "m02-labrow__row", attrs: { "data-labor-mat": mat.코드 }, children: [ el("td", { className: "m02-labrow__code", text: mat.코드 }), titled( el("td", { className: "m02-labrow__name", children: [ el("strong", { text: mat.이름 ?? "" }), ...(line?.까닭 ? [el("small", { className: "ui-text ui-text--error", text: line.까닭 })] : []), ], }), ), el("td", { className: "m02-labrow__spec", text: mat.규격 ?? "", attrs: { title: mat.규격 ?? "" }, }), qtyCell(qtyLine, data.cells, on?.qty ? () => on.qty?.(i) : null), el("td", { className: "m02-labrow__unit", text: mat.단위 ?? "", attrs: { "data-label": tc("Labor_Unit") }, }), ...markCells(mat, on?.mark ? (k, v) => on.mark?.(i, k, v) : undefined), ...PRICE_SLOTS.map(priceCell), moneyCell(line?.기준단가, line?.반영, wait, tc("Labor_AppliedSum")), ...(remove ? [ el("td", { className: "m02-labrow__move", children: [ createButton({ label: tc("Remove"), variant: "danger", onClick: (e) => { e.stopPropagation(); remove(i); }, }), ], }), ] : []), ], }); if (on) tr.addEventListener("click", () => on.open(i)); return tr; }); const heads = [ tc("Labor_Code"), tc("Col_Name"), tc("Labor_Spec"), tc("Labor_QtyCol"), tc("Labor_Unit"), ...markHeads(), ...PRICE_SLOTS, `${tc("Labor_BasePrice")} · ${tc("Labor_AppliedSum")}`, ...(remove ? [tc("Col_Move")] : []), ]; const lead = data.lead ?? []; return data.mats.length || lead.length ? table(heads, [...lead, ...trs], []) : el("p", { className: "ui-text ui-text--muted", text: tc("Labor_NoMat") }); }