From 95dfb19dd32b3f9d0afdacc4cb327c9d85a57bf7 Mon Sep 17 00:00:00 2001 From: swcho Date: Thu, 26 Jun 2025 10:29:15 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=ED=97=A4=EB=8D=94=EB=AA=85=20=EB=B0=94?= =?UTF-8?q?=EA=BF=94=EC=84=9C=20=EC=97=91=EC=85=80=20=EB=8B=A4=EC=9A=B4?= =?UTF-8?q?=EB=A1=9C=EB=93=9C=ED=95=98=EB=8A=94=20=ED=95=A8=EC=88=98=20dow?= =?UTF-8?q?nloadExcelWithKoreanHeaders=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/ui/excel/excelStyle.tsx | 46 ++++++++++++++++++- .../src/ui/excel/index.tsx | 38 ++++++++++++++- 2 files changed, 81 insertions(+), 3 deletions(-) diff --git a/packages/common/business_components/src/ui/excel/excelStyle.tsx b/packages/common/business_components/src/ui/excel/excelStyle.tsx index 3c8f8d219..1319aad82 100644 --- a/packages/common/business_components/src/ui/excel/excelStyle.tsx +++ b/packages/common/business_components/src/ui/excel/excelStyle.tsx @@ -62,4 +62,48 @@ 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); +}; \ No newline at end of file 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