import { type Table } from "@tanstack/react-table"; import ExcelJS from "exceljs"; import { type RegEvalCriteriaView } from "@/db/schema"; import { REG_EVAL_CRITERIA_CATEGORY, REG_EVAL_CRITERIA_CATEGORY2, REG_EVAL_CRITERIA_ITEM, } from "@/db/schema"; /** * 평가 기준 데이터를 Excel로 내보내기 */ export async function exportRegEvalCriteriaToExcel( table: Table, { filename = "Regular_Evaluation_Criteria", excludeColumns = ["select", "actions"], sheetName = "평가 기준", }: { filename?: string; excludeColumns?: string[]; sheetName?: string; } = {} ): Promise { // 워크북 생성 const workbook = new ExcelJS.Workbook(); workbook.creator = "EVCP System"; workbook.created = new Date(); // 메인 워크시트 생성 const worksheet = workbook.addWorksheet(sheetName); // 한글 헤더 매핑 const columnHeaders = [ { key: "category", header: "평가부문", width: 15 }, { key: "category2", header: "점수구분", width: 15 }, { key: "item", header: "항목", width: 15 }, { key: "classification", header: "구분", width: 20 }, { key: "range", header: "범위", width: 20 }, { key: "detail", header: "평가내용", width: 30 }, { key: "scoreEquipShip", header: "장비-조선 점수", width: 18 }, { key: "scoreEquipMarine", header: "장비-해양 점수", width: 18 }, { key: "scoreBulkShip", header: "벌크-조선 점수", width: 18 }, { key: "scoreBulkMarine", header: "벌크-해양 점수", width: 18 }, { key: "remarks", header: "비고", width: 20 }, { key: "id", header: "ID", width: 10 }, { key: "criteriaId", header: "기준 ID", width: 12 }, { key: "orderIndex", header: "정렬 순서", width: 12 }, ].filter(col => !excludeColumns.includes(col.key)); // 컬럼 설정 worksheet.columns = columnHeaders; // 헤더 스타일 적용 const headerRow = worksheet.getRow(1); headerRow.font = { bold: true }; headerRow.fill = { type: "pattern", pattern: "solid", fgColor: { argb: "FFCCCCCC" }, }; headerRow.alignment = { horizontal: "center", vertical: "middle" }; // 데이터 행 추가 const rowModel = table.getRowModel(); rowModel.rows.forEach((row) => { const rowData: Record = {}; columnHeaders.forEach((col) => { let value = row.original[col.key as keyof RegEvalCriteriaView]; // 특정 컬럼들에 대해 한글 라벨로 변환 if (col.key === "category") { value = REG_EVAL_CRITERIA_CATEGORY.find(item => item.value === value)?.label || value; } else if (col.key === "category2") { value = REG_EVAL_CRITERIA_CATEGORY2.find(item => item.value === value)?.label || value; } else if (col.key === "item") { value = REG_EVAL_CRITERIA_ITEM.find(item => item.value === value)?.label || value; } rowData[col.key] = value || ""; }); worksheet.addRow(rowData); }); // 셀 스타일 적용 worksheet.eachRow((row, rowNumber) => { row.eachCell((cell) => { cell.border = { top: { style: "thin" }, left: { style: "thin" }, bottom: { style: "thin" }, right: { style: "thin" }, }; // 데이터 행 가운데 정렬 if (rowNumber > 1) { cell.alignment = { horizontal: "center", vertical: "middle" }; } }); }); // 유효성 검사 시트 생성 (풀다운용) const validationSheet = workbook.addWorksheet("ValidationData"); validationSheet.state = "hidden"; // 풀다운 옵션 데이터 추가 const categoryOptions = REG_EVAL_CRITERIA_CATEGORY.map(item => item.label); const category2Options = REG_EVAL_CRITERIA_CATEGORY2.map(item => item.label); const itemOptions = REG_EVAL_CRITERIA_ITEM.map(item => item.label); validationSheet.getColumn(1).values = ["평가부문", ...categoryOptions]; validationSheet.getColumn(2).values = ["점수구분", ...category2Options]; validationSheet.getColumn(3).values = ["항목", ...itemOptions]; // 메인 시트에 데이터 유효성 검사 적용 const categoryColIndex = columnHeaders.findIndex(col => col.key === "category") + 1; const category2ColIndex = columnHeaders.findIndex(col => col.key === "category2") + 1; const itemColIndex = columnHeaders.findIndex(col => col.key === "item") + 1; if (categoryColIndex > 0) { (worksheet as any).dataValidations.add(`${worksheet.getColumn(categoryColIndex).letter}2:${worksheet.getColumn(categoryColIndex).letter}1000`, { type: "list", allowBlank: false, formulae: [`ValidationData!$A$2:$A$${categoryOptions.length + 1}`], }); } if (category2ColIndex > 0) { (worksheet as any).dataValidations.add(`${worksheet.getColumn(category2ColIndex).letter}2:${worksheet.getColumn(category2ColIndex).letter}1000`, { type: "list", allowBlank: false, formulae: [`ValidationData!$B$2:$B$${category2Options.length + 1}`], }); } if (itemColIndex > 0) { (worksheet as any).dataValidations.add(`${worksheet.getColumn(itemColIndex).letter}2:${worksheet.getColumn(itemColIndex).letter}1000`, { type: "list", allowBlank: false, formulae: [`ValidationData!$C$2:$C$${itemOptions.length + 1}`], }); } // 파일 다운로드 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); } /** * 평가 기준 템플릿 다운로드 */ export async function exportRegEvalCriteriaTemplate(): Promise { // 워크북 생성 const workbook = new ExcelJS.Workbook(); workbook.creator = "EVCP System"; workbook.created = new Date(); // 템플릿 워크시트 생성 const worksheet = workbook.addWorksheet("평가 기준 템플릿"); // 한글 헤더 설정 const templateHeaders = [ { key: "category", header: "평가부문", width: 15 }, { key: "category2", header: "점수구분", width: 15 }, { key: "item", header: "항목", width: 15 }, { key: "classification", header: "구분", width: 20 }, { key: "range", header: "범위", width: 20 }, { key: "detail", header: "평가내용", width: 30 }, { key: "scoreEquipShip", header: "장비-조선 점수", width: 18 }, { key: "scoreEquipMarine", header: "장비-해양 점수", width: 18 }, { key: "scoreBulkShip", header: "벌크-조선 점수", width: 18 }, { key: "scoreBulkMarine", header: "벌크-해양 점수", width: 18 }, { key: "remarks", header: "비고", width: 20 }, { key: "orderIndex", header: "정렬 순서", width: 12 }, ]; // 컬럼 설정 worksheet.columns = templateHeaders; // 헤더 스타일 적용 const headerRow = worksheet.getRow(1); headerRow.font = { bold: true }; headerRow.fill = { type: "pattern", pattern: "solid", fgColor: { argb: "FFCCCCCC" }, }; headerRow.alignment = { horizontal: "center", vertical: "middle" }; // 유효성 검사 시트 생성 const validationSheet = workbook.addWorksheet("ValidationData"); validationSheet.state = "hidden"; // 풀다운 옵션 데이터 추가 const categoryOptions = REG_EVAL_CRITERIA_CATEGORY.map(item => item.label); const category2Options = REG_EVAL_CRITERIA_CATEGORY2.map(item => item.label); const itemOptions = REG_EVAL_CRITERIA_ITEM.map(item => item.label); validationSheet.getColumn(1).values = ["평가부문", ...categoryOptions]; validationSheet.getColumn(2).values = ["점수구분", ...category2Options]; validationSheet.getColumn(3).values = ["항목", ...itemOptions]; // 데이터 유효성 검사 적용 (worksheet as any).dataValidations.add("A2:A1000", { type: "list", allowBlank: false, formulae: [`ValidationData!$A$2:$A$${categoryOptions.length + 1}`], }); (worksheet as any).dataValidations.add("B2:B1000", { type: "list", allowBlank: false, formulae: [`ValidationData!$B$2:$B$${category2Options.length + 1}`], }); (worksheet as any).dataValidations.add("C2:C1000", { type: "list", allowBlank: false, formulae: [`ValidationData!$C$2:$C$${itemOptions.length + 1}`], }); // 테두리 스타일 적용 headerRow.eachCell((cell) => { cell.border = { top: { style: "thin" }, left: { style: "thin" }, bottom: { style: "thin" }, right: { style: "thin" }, }; }); // 샘플 데이터 추가 (2-3줄) worksheet.addRow([ "품질", "공정", "품질", "품질시스템", "ISO 9001 인증", "품질경영시스템 운영 현황", "10", "10", "10", "10", "품질시스템 운영", "1" ]); worksheet.addRow([ "관리자", "가격", "납기", "납기준수", "최근 3년", "납기준수율 90% 이상", "5", "5", "5", "5", "납기준수 실적", "2" ]); // 샘플 데이터 행에 테두리 적용 worksheet.getRow(2).eachCell((cell) => { cell.border = { top: { style: "thin" }, left: { style: "thin" }, bottom: { style: "thin" }, right: { style: "thin" }, }; cell.alignment = { horizontal: "center", vertical: "middle" }; }); worksheet.getRow(3).eachCell((cell) => { cell.border = { top: { style: "thin" }, left: { style: "thin" }, bottom: { style: "thin" }, right: { style: "thin" }, }; cell.alignment = { horizontal: "center", vertical: "middle" }; }); // 파일 다운로드 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 = "평가기준_템플릿.xlsx"; link.click(); URL.revokeObjectURL(url); }