diff --git a/apps/sn/app/(with-base-layout)/ii/rdii_result/page.tsx b/apps/sn/app/(with-base-layout)/ii/rdii_result/page.tsx index 95397a13c..4bbfd0619 100644 --- a/apps/sn/app/(with-base-layout)/ii/rdii_result/page.tsx +++ b/apps/sn/app/(with-base-layout)/ii/rdii_result/page.tsx @@ -1,6 +1,6 @@ 'use client' import { deleteData, getData } from '@/components/lib/api' -import { UiTable, downloadExcel } from '@common/business_components/ui' +import { UiTable, downloadExcelWithKoreanHeaders } from '@common/business_components/ui' import { zodResolver } from '@hookform/resolvers/zod' import { useState } from 'react' import { useForm } from 'react-hook-form' @@ -138,14 +138,23 @@ const Result = () => { // 선택된 행 데이터를 Excel 다운로드 형식으로 변환 const excelData = data.content; // 배열로 감싸서 전달 - // 파일명 생성 (분석번호 기반) - const fileName = `RDII분석결과_${selectedRowData.rainInfwtAnlsSn}_${selectedRowData.aplcnYm}`; + // 헤더 매핑 정의 + const headerMapping: { [key: string]: string } = { + 'rainInfwtAnlsSn': 'RDII분석\n일련번호', + 'pplMngNo': '관로\n관리번호', + 'anlsTm': '분석시각', + 'predcOilq': '예측유량' + }; - downloadExcel({ + // 파일명 생성 (분석번호 기반) + const fileName = `RDII분석결과_${selectedRowData.swageTmplntNm}_${selectedRowData.aplcnYm}_${selectedRowData.rainInfwtAnlsSn}`; + + await downloadExcelWithKoreanHeaders({ data: excelData as JSON[], fileName: fileName, sheetNameArray: ["RDII 분석결과"], - headerRange: "A1:D1" // 테이블 컬럼 수에 맞춰 조정 + headerRange: "A1:D1", + headerMapping: headerMapping }); setIsLoadingResult(false); } catch (error) { diff --git a/apps/sn/app/(with-base-layout)/ii/result/page.tsx b/apps/sn/app/(with-base-layout)/ii/result/page.tsx index ecdce6566..ee2bbe905 100644 --- a/apps/sn/app/(with-base-layout)/ii/result/page.tsx +++ b/apps/sn/app/(with-base-layout)/ii/result/page.tsx @@ -1,6 +1,6 @@ 'use client' import { deleteData, getData } from '@/components/lib/api' -import { UiTable, downloadExcel } from '@common/business_components/ui' +import { UiTable, downloadExcelWithKoreanHeaders } from '@common/business_components/ui' import { zodResolver } from '@hookform/resolvers/zod' import { useState } from 'react' import { useForm } from 'react-hook-form' @@ -137,14 +137,23 @@ const Result = () => { // 선택된 행 데이터를 Excel 다운로드 형식으로 변환 const excelData = data.content; // 배열로 감싸서 전달 - // 파일명 생성 (분석번호 기반) - const fileName = `침입수분석결과_${selectedRowData.inftwtAnlsSn}_${selectedRowData.aplcnYm}`; + // 헤더 매핑 정의 + const headerMapping: { [key: string]: string } = { + 'inftwtAnlsSn': '침입수분석\n일련번호', + 'pplMngNo': '관로\n관리번호', + 'anlsTm': '분석시각', + 'predcOilq': '예측유량' + }; - downloadExcel({ + // 파일명 생성 (분석번호 기반) + const fileName = `침입수분석결과_${selectedRowData.swageTmplntNm}_${selectedRowData.aplcnYm}_${selectedRowData.inftwtAnlsSn}`; + + await downloadExcelWithKoreanHeaders({ data: excelData as JSON[], fileName: fileName, sheetNameArray: ["침입수 분석결과"], - headerRange: "A1:D1" // 테이블 컬럼 수에 맞춰 조정 + headerRange: "A1:D1", + headerMapping: headerMapping }); setIsLoadingResult(false); } catch (error) { 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