/* ============================================================================= * B09_Estimation_UI_MachineExpense.ts * 각종 중기경비계산서 — 기종마다 한 장(별표2 (5)(가) 아홉째) · 중기 탭 아래에 붙음 * * - 옛 `B09_Estimation_UI_BaseData.ts` 의 중기경비계산서를 그대로 옮김(PLAN 12장 옛 탭 옮기기). * - ⚠ 목록표가 「얼마」라면 이 장은 **왜 그 값인가** — 계산 과정을 감추지 않음. * ========================================================================== */ import { API_BASE_URL } from "@config/config_frontend"; import { el } from "./B09_Estimation_UI_Sheet"; import { head, infoTable, money, note } from "./B09_Estimation_UI_Table"; export interface MachineExpenseDto { summary: string; notes: string[]; sheets: Array<{ machine_code: string; name: string; spec: string; price_thousand_krw: string | null; economic_life_hours: number | null; annual_standard_hours: number | null; depreciation_coefficient: number | null; maintenance_coefficient: number | null; management_coefficient: number | null; loss_coefficient: number | null; loss_krw_per_hour: string | null; fuel_liters_per_hour: string | null; fuel_price_per_liter: string | null; fuel_scope: string; misc_material_percent: string | null; operator_code: string; operator_daily_wage: string | null; operator_krw_per_hour: string | null; material_krw: string | null; labor_krw: string | null; expense_krw: string | null; total_krw: string | null; variant: string; attachment: boolean; attachment_note: string; gaps: string[]; }>; } export async function fetchMachineExpense(projectId: string): Promise { const response = await fetch( `${API_BASE_URL}/projects/${encodeURIComponent(projectId)}/estimation/machine-expense`, { credentials: "include" }, ); if (!response.ok) throw new Error(`machine-expense ${response.status}`); return (await response.json()) as MachineExpenseDto; } /** 기종 한 장 — 손료·운전경비·시간당 사용료를 차례로. */ function machineExpenseSheet(sheet: MachineExpenseDto["sheets"][number]): HTMLElement { const box = el("div", "b09s-group"); box.append( el( "div", "b09s-head", `${sheet.machine_code} ${sheet.name} ${sheet.spec}`.trim() + (sheet.variant ? ` — ${sheet.variant}` : ""), ), ); const coefficient = (value: number | null) => (value === null ? "—" : String(value)); box.append( infoTable( ["구 분", "내 용", "값"], [ ["① 손료", "취득가격(천원)", money(sheet.price_thousand_krw)], [ "", "내용시간 / 연간표준가동시간", `${coefficient(sheet.economic_life_hours)} / ${coefficient(sheet.annual_standard_hours)}`, ], [ "", "상각비·정비비·관리비 계수 (10⁻⁷)", `${coefficient(sheet.depreciation_coefficient)} + ${coefficient(sheet.maintenance_coefficient)} + ${coefficient(sheet.management_coefficient)} = ${coefficient(sheet.loss_coefficient)}`, ], ["", "시간당 손료(원)", money(sheet.loss_krw_per_hour)], [ "② 운전경비", `주연료(L/hr) × 유가(${sheet.fuel_scope})`, `${sheet.fuel_liters_per_hour ?? "—"} × ${money(sheet.fuel_price_per_liter)}`, ], ["", "잡재료(주연료의 %)", sheet.misc_material_percent ?? "—"], [ "", `조종원(${sheet.operator_code || "—"}) 일당 → 시간당`, `${money(sheet.operator_daily_wage)} → ${money(sheet.operator_krw_per_hour)}`, ], [ "③ 시간당 사용료", "재료비 / 노무비 / 경비", `${money(sheet.material_krw)} / ${money(sheet.labor_krw)} / ${money(sheet.expense_krw)}`, ], ["", "합 계", money(sheet.total_krw)], ], [0, 1], ), ); if (sheet.variant) { box.append( note( "같은 기종이라도 조합 사용이면 잡재료가 16% 로 줄어 재료비가 달라집니다 —" + " 그래서 층이 따로 섭니다(건설품셈 제8장 [주]⑤).", ), ); } if (sheet.attachment_note) box.append(note(sheet.attachment_note)); for (const gap of sheet.gaps) box.append(note(`⚠ ${gap}`)); return box; } export function drawMachineExpense(body: HTMLElement, data: MachineExpenseDto): void { body.append(head(`각종 중기경비계산서 (${data.sheets.length})`)); body.append(note(data.summary)); for (const line of data.notes) body.append(note(line)); for (const sheet of data.sheets) body.append(machineExpenseSheet(sheet)); }