/* ============================================================================= * B09_Estimation_UI_Tabs_Labor.ts * B09 대가 탭 둘(PLAN 145-2) — 일위대가목록표 · 일위대가표(실무 엑셀 꼴 · 값 = `B09_Estimation_Calc_Labor`). * * 목록표 = 호표 한 줄(합계 · 노무비 · 재료비 · 경비) · 줄 누름 = 그 블록으로 * 일위대가표 = 블록(머리 · [품셈 인용] · 줄 · 합계) · 줄 누름 = 단가를 낸 탭 · 줄(대가 줄 = 그 블록) * 줄 꼴(155-2) = 머리 · 합계 굵게(`is-title`) · 인용 · 줄 = 들여쓰기 「ㄴ」(2단 · 겹 대가는 안 펼침) * 연결된 구조물 조합 사본이 없으면 빈 표 「연결 없음」 * ========================================================================== */ import type { DataRow } from "@ui/ui_template_data_table"; import type { Row } from "./B09_Estimation_Calc_Base"; import { money, qty, text, type Link, type TabBuild, type TabId, type TabTable, } from "./B09_Estimation_UI_Tabs"; import { raw } from "./B09_Estimation_UI_Tabs_Sangeun"; const EMPTY = "연결 없음 — 연결된 구조물 조합 사본(일위대가)이 없음 · B05 · B06 에서 조합을 고르고 [저장]"; /** 하위 줄 앞 — 들여쓰기 + 「ㄴ」(공용 표가 앞 빈칸을 접지 않음) */ const CHILD = " ㄴ "; const ROUNDS = "줄 금액 ROUNDDOWN(단가 × 수량, 1) · % 줄 = 밑수 × % / 100 · 합계 ROUNDDOWN 0"; /** 블록 줄 → 단가를 낸 탭 */ const LINE_TAB: Record = { labor: "labor", material: "material", machine: "machine", daega: "dg", sangeun: "sg", }; export const buildDaegaList: TabBuild = ({ sheets }): TabTable | string => { const rows: DataRow[] = (sheets.daega || []).map((r: Row) => ({ ...r, no: `대가${r.no}` })); if (!rows.length) return EMPTY; return { columns: [ text("no", "호표", 80), text("kind", "꼴", 70), text("name", "명칭", 240), text("spec", "규격", 200), text("unit", "단위", 56), money("sum", "합계"), money("labor", "노무비"), money("material", "재료비"), money("expense", "경비"), ], rows, frozen: 3, hint: "호표 = 일위대가표 블록 합계 · 줄을 누르면 그 블록으로", link: (i: number): Link | null => (rows[i] ? { tab: "dg", key: String(rows[i].key) } : null), tip: (i, key) => (key === "spec" ? raw(rows[i]?.spec, rows[i]?.spec_raw) : null), }; }; export const buildDaegaBlocks: TabBuild = ({ sheets }): TabTable | string => { const blocks: Row[] = sheets.daega_blocks || []; if (!blocks.length) return EMPTY; const rows: DataRow[] = []; const links: Array = []; const titles = new Set(); for (const b of blocks) { titles.add(rows.length); rows.push({ key: b.id, name: `제 ${b.no} 호표 ${b.name}`, spec: b.spec, spec_raw: b.spec_raw, unit: b.unit, note: b.kind, }); links.push(null); if (b.cite) { rows.push({ key: `${b.id}|cite`, name: `${CHILD}${b.cite}`, note: "품셈 인용" }); links.push(null); } b.lines.forEach((ln: Row, n: number) => { rows.push({ key: `${b.id}|${n}`, name: `${CHILD}${ln.name || ""}`, spec: ln.spec || "", spec_raw: ln.spec_raw, qty: ln.qty, unit: ln.unit || "", sum_price: ln.price, sum: ln.amount, labor_price: ln.prices.labor, labor: ln.amounts.labor, material_price: ln.prices.material, material: ln.amounts.material, expense_price: ln.prices.expense, expense: ln.amounts.expense, note: ln.ref_no || ln.why || "", }); const tab = LINE_TAB[ln.kind]; links.push(tab && ln.key ? { tab, key: String(ln.key) } : null); }); titles.add(rows.length); rows.push({ key: `${b.id}|합계`, name: " 합 계", sum: b.sum, labor: b.labor, material: b.material, expense: b.expense, }); links.push(null); } const pair = (key: string, label: string) => [ money(`${key}_price`, "단가", [label], 1), money(key, "금액", [label], 1), ]; return { columns: [ text("name", "명칭", 240), text("spec", "규격", 160), qty("qty", "수량"), text("unit", "단위", 56), ...pair("sum", "합계"), ...pair("labor", "노무비"), ...pair("material", "재료비"), ...pair("expense", "경비"), text("note", "비고", 120), ], rows, frozen: 1, hint: `단가 = B09 프로젝트 한 벌 굳힌 단가 · ${ROUNDS} · 줄 누름 = 단가를 낸 탭(대가 줄 = 그 블록)`, link: (i: number) => links[i] ?? null, rowClass: (i: number) => (titles.has(i) ? "is-title" : null), tip: (i: number, key: string) => key === "spec" ? raw(rows[i]?.spec, rows[i]?.spec_raw) : null, }; };