import ExcelJS from "exceljs" import { PRItemInfo } from "@/components/bidding/manage/bidding-items-editor" import { getProjectCodesByIds } from "./project-utils" /** * 입찰품목 목록을 Excel로 내보내기 */ export async function exportBiddingItemsToExcel( items: PRItemInfo[], { filename = "입찰품목목록", }: { filename?: string } = {} ): Promise { // 프로젝트 ID 목록 수집 const projectIds = items .map((item) => item.projectId) .filter((id): id is number => id != null && id > 0) // 프로젝트 코드 맵 조회 const projectCodeMap = await getProjectCodesByIds(projectIds) // 헤더 정의 const headers = [ "프로젝트코드", "프로젝트명", "자재그룹코드", "자재그룹명", "자재코드", "자재명", "수량", "수량단위", "중량", "중량단위", "납품요청일", "가격단위", "구매단위", "자재순중량", "내정단가", "내정금액", "내정통화", "예산금액", "예산통화", "실적금액", "실적통화", "WBS코드", "WBS명", "코스트센터코드", "코스트센터명", "GL계정코드", "GL계정명", "PR번호", ] // 데이터 행 생성 const dataRows = items.map((item) => { // 프로젝트 코드 조회 const projectCode = item.projectId ? projectCodeMap.get(item.projectId) || "" : "" return [ projectCode, item.projectInfo || "", item.materialGroupNumber || "", item.materialGroupInfo || "", item.materialNumber || "", item.materialInfo || "", item.quantity || "", item.quantityUnit || "", item.totalWeight || "", item.weightUnit || "", item.requestedDeliveryDate || "", item.priceUnit || "", item.purchaseUnit || "", item.materialWeight || "", item.targetUnitPrice || "", item.targetAmount || "", item.targetCurrency || "KRW", item.budgetAmount || "", item.budgetCurrency || "KRW", item.actualAmount || "", item.actualCurrency || "KRW", item.wbsCode || "", item.wbsName || "", item.costCenterCode || "", item.costCenterName || "", item.glAccountCode || "", item.glAccountName || "", item.prNumber || "", ] }) // 최종 sheetData const sheetData = [headers, ...dataRows] // ExcelJS로 파일 생성 및 다운로드 await createAndDownloadExcel(sheetData, headers.length, filename) } /** * Excel 파일 생성 및 다운로드 */ async function createAndDownloadExcel( sheetData: any[][], columnCount: number, filename: string ): Promise { // ExcelJS 워크북/시트 생성 const workbook = new ExcelJS.Workbook() const worksheet = workbook.addWorksheet("Sheet1") // 칼럼별 최대 길이 추적 const maxColumnLengths = Array(columnCount).fill(0) sheetData.forEach((row) => { row.forEach((cellValue, colIdx) => { const cellText = cellValue?.toString() ?? "" if (cellText.length > maxColumnLengths[colIdx]) { maxColumnLengths[colIdx] = cellText.length } }) }) // 시트에 데이터 추가 + 헤더 스타일 sheetData.forEach((arr, idx) => { const row = worksheet.addRow(arr) // 헤더 스타일 적용 (첫 번째 행) if (idx === 0) { row.font = { bold: true } row.alignment = { horizontal: "center" } row.eachCell((cell) => { cell.fill = { type: "pattern", pattern: "solid", fgColor: { argb: "FFCCCCCC" }, } }) } }) // 칼럼 너비 자동 조정 maxColumnLengths.forEach((len, idx) => { // 최소 너비 10, +2 여백 worksheet.getColumn(idx + 1).width = Math.max(len + 2, 10) }) // 최종 파일 다운로드 const buffer = await workbook.xlsx.writeBuffer() const blob = new Blob([buffer], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", }) const url = URL.createObjectURL(blob) const link = document.createElement("a") link.href = url link.download = `${filename}.xlsx` link.click() URL.revokeObjectURL(url) }