- 화면 확인: 옮기기 전후 같음 — 중기 탭 표 19 · 줄 171 · 계산서 18 장(불도저 19 손료계수 1811 · 시간당 손료 35,884.965) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
123 lines
4.7 KiB
TypeScript
123 lines
4.7 KiB
TypeScript
/* =============================================================================
|
||
* 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<MachineExpenseDto> {
|
||
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));
|
||
}
|