/* ============================================================================= * B09_Estimation_UI_Tab_Summary.ts * B09 집계표 탭 — 재료비·노무비·경비 수량금액집계표 + 중기시간금액집계표 (실무 시트 · PLAN 12장) * * - 칸은 실무 시트 그대로: * 재료비·노무비·경비 호표 · 명칭 · 규격 · 수량 · 단위 · 단가 · 금액 · 비고 * 중기 호표 · 명칭 · 규격 · 수량 · 단위 · 합계 · 노무비 · 재료비 · 경비 · 비고 (⚠ 단가 열 없음) * - 값은 서버가 내역에서 되모은 것(`resources`) — 집계표는 **반올림**이라 내역서 본체(절사)와 원 단위로 * 어긋나는 것이 정상(그 문구를 표 아래에 함께 보임). * - 줄을 누르면 중기는 그 기종의 중기사용료로 들어감. * ========================================================================== */ import type { B09Tab, B09TabContext } from "./B09_Estimation_UI_Shell_Types"; import { L, el, hint, numberCell, plainTable, quantity, segmented, won, } from "./B09_Estimation_UI_Sheet"; import { loadBill, type BillDto, type ResourceGroup } from "./B09_Estimation_UI_Store"; let group: ResourceGroup = "material"; const GROUPS: Array<[ResourceGroup, Parameters[0]]> = [ ["material", "B09_Sheet_Sum_Material"], ["labor", "B09_Sheet_Sum_Labor"], ["expense", "B09_Sheet_Sum_Expense"], ["machine", "B09_Sheet_Sum_Machine"], ]; function draw(ctx: B09TabContext, bill: BillDto): void { ctx.body.append( segmented( GROUPS.map(([key, label]) => [key, L(label)]), group, (key) => { group = key as ResourceGroup; ctx.body.replaceChildren(); draw(ctx, bill); }, ), ); const machine = group === "machine"; const front = [ L("B09_Sheet_Col_Sheet"), L("B09_Sheet_Col_Name"), L("B09_Sheet_Col_Spec"), L("B09_Sheet_Col_Quantity"), L("B09_Sheet_Col_Unit"), ]; const money = machine ? [ L("B09_Sheet_Col_Total"), L("B09_Sheet_Col_Labor"), L("B09_Sheet_Col_Material"), L("B09_Sheet_Col_Expense"), ] : [L("B09_Sheet_Col_UnitPrice"), L("B09_Sheet_Col_Amount")]; const { wrap, tbody } = plainTable([...front, ...money, L("B09_Sheet_Col_Note")]); const rows = bill.resources.groups[group]; for (const row of rows) { const tr = el("tr"); tr.append( el("td", "", String(row.number)), el("td", "", row.name), el("td", "", row.spec), numberCell(quantity(row.quantity, null)), el("td", "", row.unit), ); if (machine) { tr.append( numberCell(won(row.amount_krw)), numberCell(won(row.labor_krw)), numberCell(won(row.material_krw)), numberCell(won(row.expense_krw)), ); tr.classList.add("is-clickable"); tr.title = L("B09_Sheet_Drill"); tr.addEventListener("click", () => ctx.open("machine", row.code)); } else { tr.append(numberCell(won(row.unit_price_krw)), numberCell(won(row.amount_krw))); } tr.append(el("td", "b09s-note", row.note)); tbody.append(tr); } ctx.body.append(wrap); if (rows.length === 0) ctx.body.append(hint(L("B09_Sheet_EmptyGroup"))); ctx.body.append(hint(bill.resources.note)); if (bill.resources.missing.length > 0) { ctx.body.append( hint(`${L("B09_Sheet_SumMissing")} ${bill.resources.missing.join(", ")}`, true), ); } } export const summaryTab: B09Tab = { key: "summary", label: () => L("B09_Sheet_Tab_Summary"), render(ctx) { if (!ctx.projectId) { ctx.body.append(hint(L("B09_Sheet_NoProject"))); return; } ctx.body.append(hint(L("B09_Sheet_Loading"))); loadBill(ctx.projectId) .then((bill) => { ctx.body.replaceChildren(); draw(ctx, bill); }) .catch((error: Error) => { ctx.body.replaceChildren(hint(`${L("B09_Sheet_LoadFailed")} ${error.message}`, true)); }); }, };