엑셀 다운로드, 업로드, 사진촬영(바코드 스캔기능) 추가
This commit is contained in:
172
frontend/lib/utils/excelExport.ts
Normal file
172
frontend/lib/utils/excelExport.ts
Normal file
@@ -0,0 +1,172 @@
|
||||
/**
|
||||
* 엑셀 내보내기 유틸리티
|
||||
* xlsx 라이브러리를 사용하여 데이터를 엑셀 파일로 변환
|
||||
*/
|
||||
|
||||
import * as XLSX from "xlsx";
|
||||
|
||||
/**
|
||||
* 데이터를 엑셀 파일로 내보내기
|
||||
* @param data 내보낼 데이터 배열
|
||||
* @param fileName 파일명 (기본: "export.xlsx")
|
||||
* @param sheetName 시트명 (기본: "Sheet1")
|
||||
* @param includeHeaders 헤더 포함 여부 (기본: true)
|
||||
*/
|
||||
export async function exportToExcel(
|
||||
data: Record<string, any>[],
|
||||
fileName: string = "export.xlsx",
|
||||
sheetName: string = "Sheet1",
|
||||
includeHeaders: boolean = true
|
||||
): Promise<void> {
|
||||
try {
|
||||
console.log("📥 엑셀 내보내기 시작:", {
|
||||
dataCount: data.length,
|
||||
fileName,
|
||||
sheetName,
|
||||
includeHeaders,
|
||||
});
|
||||
|
||||
if (data.length === 0) {
|
||||
throw new Error("내보낼 데이터가 없습니다.");
|
||||
}
|
||||
|
||||
// 워크북 생성
|
||||
const workbook = XLSX.utils.book_new();
|
||||
|
||||
// 데이터를 워크시트로 변환
|
||||
const worksheet = XLSX.utils.json_to_sheet(data, {
|
||||
header: includeHeaders ? undefined : [],
|
||||
skipHeader: !includeHeaders,
|
||||
});
|
||||
|
||||
// 컬럼 너비 자동 조정
|
||||
const columnWidths = autoSizeColumns(data);
|
||||
worksheet["!cols"] = columnWidths;
|
||||
|
||||
// 워크시트를 워크북에 추가
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, sheetName);
|
||||
|
||||
// 파일 다운로드
|
||||
XLSX.writeFile(workbook, fileName);
|
||||
|
||||
console.log("✅ 엑셀 내보내기 완료:", fileName);
|
||||
} catch (error) {
|
||||
console.error("❌ 엑셀 내보내기 실패:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 컬럼 너비 자동 조정
|
||||
*/
|
||||
function autoSizeColumns(data: Record<string, any>[]): Array<{ wch: number }> {
|
||||
if (data.length === 0) return [];
|
||||
|
||||
const keys = Object.keys(data[0]);
|
||||
const columnWidths: Array<{ wch: number }> = [];
|
||||
|
||||
keys.forEach((key) => {
|
||||
// 헤더 길이
|
||||
let maxWidth = key.length;
|
||||
|
||||
// 데이터 길이 확인
|
||||
data.forEach((row) => {
|
||||
const value = row[key];
|
||||
const valueLength = value ? String(value).length : 0;
|
||||
maxWidth = Math.max(maxWidth, valueLength);
|
||||
});
|
||||
|
||||
// 최소 10, 최대 50으로 제한
|
||||
columnWidths.push({ wch: Math.min(Math.max(maxWidth, 10), 50) });
|
||||
});
|
||||
|
||||
return columnWidths;
|
||||
}
|
||||
|
||||
/**
|
||||
* 엑셀 파일을 읽어서 JSON 데이터로 변환
|
||||
* @param file 읽을 파일
|
||||
* @param sheetName 읽을 시트명 (기본: 첫 번째 시트)
|
||||
* @returns JSON 데이터 배열
|
||||
*/
|
||||
export async function importFromExcel(
|
||||
file: File,
|
||||
sheetName?: string
|
||||
): Promise<Record<string, any>[]> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onload = (e) => {
|
||||
try {
|
||||
const data = e.target?.result;
|
||||
if (!data) {
|
||||
reject(new Error("파일을 읽을 수 없습니다."));
|
||||
return;
|
||||
}
|
||||
|
||||
// 워크북 읽기
|
||||
const workbook = XLSX.read(data, { type: "binary" });
|
||||
|
||||
// 시트 선택 (지정된 시트 또는 첫 번째 시트)
|
||||
const targetSheetName = sheetName || workbook.SheetNames[0];
|
||||
const worksheet = workbook.Sheets[targetSheetName];
|
||||
|
||||
if (!worksheet) {
|
||||
reject(new Error(`시트 "${targetSheetName}"를 찾을 수 없습니다.`));
|
||||
return;
|
||||
}
|
||||
|
||||
// JSON으로 변환
|
||||
const jsonData = XLSX.utils.sheet_to_json(worksheet);
|
||||
|
||||
console.log("✅ 엑셀 가져오기 완료:", {
|
||||
sheetName: targetSheetName,
|
||||
rowCount: jsonData.length,
|
||||
});
|
||||
|
||||
resolve(jsonData as Record<string, any>[]);
|
||||
} catch (error) {
|
||||
console.error("❌ 엑셀 가져오기 실패:", error);
|
||||
reject(error);
|
||||
}
|
||||
};
|
||||
|
||||
reader.onerror = () => {
|
||||
reject(new Error("파일 읽기 중 오류가 발생했습니다."));
|
||||
};
|
||||
|
||||
reader.readAsBinaryString(file);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 엑셀 파일의 시트 목록 가져오기
|
||||
*/
|
||||
export async function getExcelSheetNames(file: File): Promise<string[]> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onload = (e) => {
|
||||
try {
|
||||
const data = e.target?.result;
|
||||
if (!data) {
|
||||
reject(new Error("파일을 읽을 수 없습니다."));
|
||||
return;
|
||||
}
|
||||
|
||||
const workbook = XLSX.read(data, { type: "binary" });
|
||||
resolve(workbook.SheetNames);
|
||||
} catch (error) {
|
||||
console.error("❌ 시트 목록 가져오기 실패:", error);
|
||||
reject(error);
|
||||
}
|
||||
};
|
||||
|
||||
reader.onerror = () => {
|
||||
reject(new Error("파일 읽기 중 오류가 발생했습니다."));
|
||||
};
|
||||
|
||||
reader.readAsBinaryString(file);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user