diff --git a/packages/common/business_components/src/ui/excel/excelStyle.tsx b/packages/common/business_components/src/ui/excel/excelStyle.tsx index 3c8f8d219..221e1387c 100644 --- a/packages/common/business_components/src/ui/excel/excelStyle.tsx +++ b/packages/common/business_components/src/ui/excel/excelStyle.tsx @@ -53,7 +53,8 @@ export const excelArrayStyle = async (data: ArrayBuffer, range: SheetParameter[] if (item.data && item.data.length > 0) { const numCols = item.data[0]?.length || 0; const numRows = item.data.length; - const dataRange = workbook.activeSheet(index)?.sheet(index)?.range(`A1:${String.fromCharCode(65 + numCols - 1)}${numRows}`); + const lastColLetter = getExcelColumnLetter(numCols); + const dataRange = workbook.activeSheet(index)?.sheet(index)?.range(`A1:${lastColLetter}${numRows}`); dataRange?.style((styleQ) => { styleQ.verticalAlignment("center"); }); @@ -62,4 +63,60 @@ export const excelArrayStyle = async (data: ArrayBuffer, range: SheetParameter[] } makeExcelFile(workbook, fileNm) -} \ No newline at end of file +} + +export const excelStyleWithKoreanHeaders = async ( + data: ArrayBuffer, + range: string = "A1:V3", + fileNm: string, + headerMapping: { [key: string]: string }, + sampleData: any +) => { + const workbook = await XlsxPopulate.Workbook.fromData(data); + const sheet = workbook.activeSheet(); + + if (!sheet) { + throw new Error('워크시트를 찾을 수 없습니다.'); + } + + // 1. 영문 헤더를 한글로 교체 + const englishHeaders = Object.keys(sampleData); + englishHeaders.forEach((englishHeader, index) => { + const koreanHeader = headerMapping[englishHeader] || englishHeader; + const cellAddress = String.fromCharCode(65 + index) + '1'; // A1, B1, C1, ... + sheet.cell(cellAddress).value(koreanHeader); + }); + + // 2. 헤더 스타일 적용 + const headerCells = sheet.range(range); + headerCells?.style((styleQ) => { + makeCellStyle(styleQ); + }); + + // 3. 모든 데이터 셀에 세로 가운데 정렬 적용 + const numCols = englishHeaders.length; + const numRows = sheet.usedRange()?.endCell()?.rowNumber() || 1; + + if (numRows > 1) { + const dataRange = sheet.range(`A1:${String.fromCharCode(65 + numCols - 1)}${numRows}`); + dataRange?.style((styleQ) => { + styleQ.verticalAlignment("center"); + styleQ.borderEach({ style: "thin", color: { rgb: "CCCCCC" } }); + }); + } + + // 4. 파일 다운로드 + await makeExcelFile(workbook, fileNm); +}; + + +const getExcelColumnLetter = (colIndex: number): string => { + let letter = ''; + while (colIndex > 0) { + const mod = (colIndex - 1) % 26; + letter = String.fromCharCode(65 + mod) + letter; + colIndex = Math.floor((colIndex - 1) / 26); + } + return letter; + }; + diff --git a/packages/common/business_components/src/ui/excel/index.tsx b/packages/common/business_components/src/ui/excel/index.tsx index 96f3b3e5d..cbe77293b 100644 --- a/packages/common/business_components/src/ui/excel/index.tsx +++ b/packages/common/business_components/src/ui/excel/index.tsx @@ -1,5 +1,5 @@ import * as XLSX from 'xlsx'; -import { excelArrayStyle, excelStyle } from './excelStyle'; +import { excelArrayStyle, excelStyle, excelStyleWithKoreanHeaders } from './excelStyle'; type ExcelDownloadProps = { data: JSON | JSON[]; @@ -164,4 +164,38 @@ export const filePickedBlobArray = (oFile: ArrayBuffer, fileNm: string, sheetArr }); await excelArrayStyle(XLSX.write(wb, { bookType: "xlsx", type: "buffer" }), sheetArray, fileNm) }); -} \ No newline at end of file +} + +type ExcelDownloadWithHeaderProps = { + data: JSON | JSON[]; + fileName: string; + sheetNameArray: string[]; + headerRange?: string; + headerMapping: { [key: string]: string }; +} + +export const downloadExcelWithKoreanHeaders = async ({ + data, + fileName = new Date().getTime().toString() + '.xlsx', + sheetNameArray = ["Sheet1"], + headerRange = 'A1:V3', + headerMapping +}: ExcelDownloadWithHeaderProps) => { + + const dataArray = Array.isArray(data) ? data : [data]; + + if (dataArray.length === 0) { + throw new Error('데이터가 없습니다.'); + } + + // 1. 원본 데이터로 워크시트 생성 + const worksheet = XLSX.utils.json_to_sheet(dataArray); + const workbook = XLSX.utils.book_new(); + XLSX.utils.book_append_sheet(workbook, worksheet, sheetNameArray[0]); + + // 2. 워크북을 ArrayBuffer로 변환 + const buffer = XLSX.write(workbook, { bookType: "xlsx", type: "buffer" }); + + // 3. 헤더만 한글로 교체하는 커스텀 스타일 함수 호출 + await excelStyleWithKoreanHeaders(buffer, headerRange, fileName, headerMapping, dataArray[0]); +}; \ No newline at end of file diff --git a/packages/common/business_components/src/ui/file-upload/lib/file_upload.tsx b/packages/common/business_components/src/ui/file-upload/lib/file_upload.tsx index 96f150ee3..60bfdacfd 100644 --- a/packages/common/business_components/src/ui/file-upload/lib/file_upload.tsx +++ b/packages/common/business_components/src/ui/file-upload/lib/file_upload.tsx @@ -308,7 +308,6 @@ export const FileUploaderItem = forwardRef< {children}