/* ============================================================================= * B09_Estimation_UI_Tab_Supply.ts * B09 관급·사급 탭 — 자재대: B08 수량·할증에 단가를 붙인 표 (PLAN 8-7 「금액은 B09」) * * - 옛 `B09_Estimation_UI_Page.ts` 의 자재대 탭을 그대로 옮김(PLAN 12장 옛 탭 옮기기). * - 사급(도급 재료비) · 관급(총원가 밖 별도 표기) · 안 갈린 것(어느 합계에도 안 넣음) 세 무리. * ⚠ 「안 갈린 것」은 못 세운 것이 아니라 **세면 안 되는 것** — 채우면 이중계상(PLAN 8-36 ㉱). * - 자료는 설계내역서 응답 한 벌(`summary.material_sheet`) — 내역 탭들과 같은 응답을 봄. * ========================================================================== */ import type { ui_locales } from "@ui/ui_template_locale"; import type { B09Tab } from "./B09_Estimation_UI_Shell_Types"; import { L, hint, quantity } from "./B09_Estimation_UI_Sheet"; import { infoTable, note } from "./B09_Estimation_UI_Table"; import { loadBill, type BillDto, type MaterialSheetRowDto } from "./B09_Estimation_UI_Store"; const MATERIAL_KEYS = [ "name", "spec", "unit", "total_amount", "unit_price_krw", "amount_krw", "note", ]; function draw(body: HTMLElement, bill: BillDto): void { const sheet = bill.summary.material_sheet; if (!sheet) { body.append(hint(L("B09_Estimation_Mat_Empty"))); return; } // 자재가 아예 없으면 **빈 표 셋을 늘어놓지 않음** — 「없다」 한 줄이면 됨(2026-09-08 화면 전수). if (sheet.contractor.length === 0 && sheet.owner.length === 0 && sheet.unknown.length === 0) { body.append(hint(L("B09_Estimation_Mat_None"))); return; } const groups: Array<[keyof typeof ui_locales, MaterialSheetRowDto[], string | null, string]> = [ ["B09_Estimation_Mat_Contractor", sheet.contractor, sheet.contractor_total_krw, "material"], ["B09_Estimation_Mat_Owner", sheet.owner, sheet.owner_total_krw, "material"], ["B09_Estimation_Mat_Unknown", sheet.unknown, null, "material_unknown"], ]; for (const [labelKey, rows, total, sheetName] of groups) { body.append(note(`${L(labelKey)} (${rows.length})` + (total === null ? "" : ` — ${total}`))); if (rows.length === 0) continue; body.append( infoTable( ["자재", "규격", "단위", "수량", "단가", "금액", "비고"], rows.map((row) => [ row.name, row.spec, row.unit, quantity(row.total_amount, 2), row.unit_price_krw ?? "", row.amount_krw ?? "", row.note, ]), [0, 1, 2, 6], MATERIAL_KEYS, bill.provenance?.sheets?.[sheetName], ), ); } for (const line of sheet.notes) body.append(note(line.replace(/\*\*/g, ""))); } export const supplyTab: B09Tab = { key: "supply", label: () => L("B09_Estimation_Tab_Supply"), 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.body, bill); }) .catch((error: Error) => { ctx.body.replaceChildren(hint(`${L("B09_Sheet_LoadFailed")} ${error.message}`, true)); }); }, };