/* ============================================================================= * B09_Draft_Print_Cost.ts * 인쇄 미리보기(PLAN 302-4 · 초안) 「원가계산」 영역 — B09 18장을 실무 내역서 차례로 모음. * 차례 · 이름 · 방향 = 기번3 내역서 xlsx 시트(목차 · 안내 빼고 · page_setup.orientation) * 값 = GET …/estimation + 화면 캐시(`b09-estimation`) → `computeSheets` = B09 화면과 같은 값 * 표 = 화면 표 짜기(`…_UI_Builders`) 그대로 · 링크 · 강조 · 고칠 칸 표시 · 단가연결 칸만 뺌 * 공기 초안 탭(공기집계 · 공기산출) = 내역서 차례 밖 → 안 넣음 * ========================================================================== */ import { API_BASE_URL } from "@config/config_frontend"; import type { DataTableOptions } from "@ui/ui_template_data_table"; import { readState } from "../../A00_Common/b_page_state"; import type { Row } from "../B09_Estimation_Calc_Base"; import { tableOptionsOf, tabTableOf } from "../B09_Estimation_UI_Builders"; import { computeSheets } from "../B09_Estimation_UI_Shell"; import type { TabContext, TabId } from "../B09_Estimation_UI_Tabs"; import type { CollectSheets, PrintSheet } from "./B09_Draft_Print_Types"; type Orientation = NonNullable; /** 기번3 내역서 시트 차례 — [탭, 시트 이름, 인쇄 방향] */ export const COST_SHEETS: Array<[TabId, string, Orientation]> = [ ["cost", "공사원가계산서", "landscape"], ["total", "총괄설계내역서", "landscape"], ["bill", "설계내역서", "landscape"], ["dg_list", "일위대가목록표", "landscape"], ["dg", "일위대가표", "landscape"], ["sg_list", "단가산출근거목록표", "landscape"], ["sg", "단가산출근거", "landscape"], ["basis", "환율및기초자료", "landscape"], ["machine", "중기목록표", "landscape"], ["machine_blocks", "중기사용료", "landscape"], ["material", "재료비목록표", "landscape"], ["labor", "노무비목록표", "landscape"], ["expense", "경비목록표", "landscape"], ["compare", "자재단가대비표", "landscape"], ["sum_material", "재료비수량금액집계표", "landscape"], ["sum_labor", "노무비수량금액집계표", "landscape"], ["sum_expense", "경비수량금액집계표", "landscape"], ["sum_machine", "중기시간금액집계표", "landscape"], ]; /** 화면 조작 전용 칸(설계내역서 「단가연결 ▾」) */ const UI_COLUMNS = new Set(["connect"]); /** 인쇄에 남길 줄 꼴(제목 줄 굵게) — 손 줄 · 고른 줄 표시는 뺌 */ const KEEP_ROW = new Set(["is-title"]); /** 화면 표 옵션 → 인쇄 표(값 · 머리 · 레벨 · 합계 · 병합 그대로 · 누름 · 고침 · 강조 뺌) */ export function printTable(options: DataTableOptions, caption: string): DataTableOptions { const { columns, rows, total, frozen, empty, level, mergeSame, rowClass } = options; return { columns: columns.filter((c) => !UI_COLUMNS.has(c.key)), rows, total, frozen, empty, caption, mergeSame, level: level && { ...level, tree: false }, rowClass: rowClass && ((i) => rowClass(i) ?.split(" ") .filter((c) => KEEP_ROW.has(c)) .join(" ") || null), }; } /** 받은 자료 + 사용자 값 → 18장(차례 그대로 · 표가 없는 탭 = 빈 표) */ export function costSheetsOf(payload: Row, user: Row): PrintSheet[] { const ctx: TabContext = { sheets: computeSheets(payload, user), payload, user, setUser: () => {}, }; return COST_SHEETS.map(([id, name, orientation]) => { const spec = tabTableOf(id, ctx); const table = !spec || typeof spec === "string" ? { columns: [], rows: [], caption: name } : printTable(tableOptionsOf(spec, id), name); return { id, name, orientation, table }; }); } export const collectCostSheets: CollectSheets = async (projectId) => { const response = await fetch(`${API_BASE_URL}/projects/${projectId}/estimation`, { credentials: "include", }); if (!response.ok) throw new Error(`원가 자료를 불러오지 못했습니다 — HTTP ${response.status}`); const payload = (await response.json()) as Row; const user = readState("b09-estimation", projectId) ?? payload.user ?? {}; return costSheetsOf(payload, user); };