diff options
Diffstat (limited to 'lib/tech-vendors/table/vendor-all-export.ts')
| -rw-r--r-- | lib/tech-vendors/table/vendor-all-export.ts | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/lib/tech-vendors/table/vendor-all-export.ts b/lib/tech-vendors/table/vendor-all-export.ts new file mode 100644 index 00000000..4278249a --- /dev/null +++ b/lib/tech-vendors/table/vendor-all-export.ts @@ -0,0 +1,252 @@ +// /lib/vendor-export.ts +import ExcelJS from "exceljs" +import { TechVendor, TechVendorContact, TechVendorItem } from "@/db/schema/techVendors" +import { exportTechVendorDetails } from "../service"; + +/** + * 선택된 벤더의 모든 관련 정보를 통합 시트 형식으로 엑셀로 내보내는 함수 + * - 기본정보 시트 + * - 연락처 시트 + * - 아이템 시트 + * 각 시트에는 식별을 위한 벤더 코드, 벤더명, 세금ID가 포함됨 + */ +export async function exportVendorsWithRelatedData( + vendors: TechVendor[], + filename = "tech-vendors-detailed" +): Promise<void> { + if (!vendors.length) return; + + // 선택된 벤더 ID 목록 + const vendorIds = vendors.map(vendor => vendor.id); + + try { + // 서버로부터 모든 관련 데이터 가져오기 + const vendorsWithDetails = await exportTechVendorDetails(vendorIds); + + if (!vendorsWithDetails.length) { + throw new Error("내보내기 데이터를 가져오는 중 오류가 발생했습니다."); + } + + // 워크북 생성 + const workbook = new ExcelJS.Workbook(); + + // 데이터 타입 확인 (서비스에서 반환하는 실제 데이터 형태) + const vendorData = vendorsWithDetails as unknown as any[]; + + // ===== 1. 기본 정보 시트 ===== + createBasicInfoSheet(workbook, vendorData); + + // ===== 2. 연락처 시트 ===== + createContactsSheet(workbook, vendorData); + + // ===== 3. 아이템 시트 ===== + createItemsSheet(workbook, vendorData); + + + // 파일 다운로드 + 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}-${new Date().toISOString().split("T")[0]}.xlsx`; + link.click(); + URL.revokeObjectURL(url); + + return; + } catch (error) { + console.error("Export error:", error); + throw error; + } +} + +// 기본 정보 시트 생성 함수 +function createBasicInfoSheet( + workbook: ExcelJS.Workbook, + vendors: TechVendor[] +): void { + const basicInfoSheet = workbook.addWorksheet("기본정보"); + + // 기본 정보 시트 헤더 설정 + basicInfoSheet.columns = [ + { header: "업체코드", key: "vendorCode", width: 15 }, + { header: "업체명", key: "vendorName", width: 20 }, + { header: "세금ID", key: "taxId", width: 15 }, + { header: "국가", key: "country", width: 10 }, + { header: "상태", key: "status", width: 15 }, + { header: "이메일", key: "email", width: 20 }, + { header: "전화번호", key: "phone", width: 15 }, + { header: "웹사이트", key: "website", width: 20 }, + { header: "주소", key: "address", width: 30 }, + { header: "대표자명", key: "representativeName", width: 15 }, + { header: "생성일", key: "createdAt", width: 15 }, + ]; + + // 헤더 스타일 설정 + applyHeaderStyle(basicInfoSheet); + + // 벤더 데이터 추가 + vendors.forEach((vendor: TechVendor) => { + basicInfoSheet.addRow({ + vendorCode: vendor.vendorCode || "", + vendorName: vendor.vendorName, + taxId: vendor.taxId, + country: vendor.country, + status: getStatusText(vendor.status), // 상태 코드를 읽기 쉬운 텍스트로 변환 + email: vendor.email, + phone: vendor.phone, + website: vendor.website, + address: vendor.address, + representativeName: vendor.representativeName, + createdAt: vendor.createdAt ? formatDate(vendor.createdAt) : "", + }); + }); +} + +// 연락처 시트 생성 함수 +function createContactsSheet( + workbook: ExcelJS.Workbook, + vendors: TechVendor[] +): void { + const contactsSheet = workbook.addWorksheet("연락처"); + + contactsSheet.columns = [ + // 벤더 식별 정보 + { header: "업체코드", key: "vendorCode", width: 15 }, + { header: "업체명", key: "vendorName", width: 20 }, + { header: "세금ID", key: "taxId", width: 15 }, + // 연락처 정보 + { header: "이름", key: "contactName", width: 15 }, + { header: "직책", key: "contactPosition", width: 15 }, + { header: "이메일", key: "contactEmail", width: 25 }, + { header: "전화번호", key: "contactPhone", width: 15 }, + { header: "주요 연락처", key: "isPrimary", width: 10 }, + ]; + + // 헤더 스타일 설정 + applyHeaderStyle(contactsSheet); + + // 벤더별 연락처 데이터 추가 + vendors.forEach((vendor: TechVendor) => { + if (vendor.contacts && vendor.contacts.length > 0) { + vendor.contacts.forEach((contact: TechVendorContact) => { + contactsSheet.addRow({ + // 벤더 식별 정보 + vendorCode: vendor.vendorCode || "", + vendorName: vendor.vendorName, + taxId: vendor.taxId, + // 연락처 정보 + contactName: contact.contactName, + contactPosition: contact.contactPosition || "", + contactEmail: contact.contactEmail, + contactPhone: contact.contactPhone || "", + isPrimary: contact.isPrimary ? "예" : "아니오", + }); + }); + } else { + // 연락처가 없는 경우에도 벤더 정보만 추가 + contactsSheet.addRow({ + vendorCode: vendor.vendorCode || "", + vendorName: vendor.vendorName, + taxId: vendor.taxId, + contactName: "", + contactPosition: "", + contactEmail: "", + contactPhone: "", + isPrimary: "", + }); + } + }); +} + +// 아이템 시트 생성 함수 +function createItemsSheet( + workbook: ExcelJS.Workbook, + vendors: TechVendor[] +): void { + const itemsSheet = workbook.addWorksheet("아이템"); + + itemsSheet.columns = [ + // 벤더 식별 정보 + { header: "업체코드", key: "vendorCode", width: 15 }, + { header: "업체명", key: "vendorName", width: 20 }, + { header: "세금ID", key: "taxId", width: 15 }, + // 아이템 정보 + { header: "아이템 코드", key: "itemCode", width: 15 }, + { header: "아이템명", key: "itemName", width: 25 }, + { header: "설명", key: "description", width: 30 }, + { header: "등록일", key: "createdAt", width: 15 }, + ]; + + // 헤더 스타일 설정 + applyHeaderStyle(itemsSheet); + + // 벤더별 아이템 데이터 추가 + vendors.forEach((vendor: TechVendor) => { + if (vendor.items && vendor.items.length > 0) { + vendor.items.forEach((item: TechVendorItem) => { + itemsSheet.addRow({ + // 벤더 식별 정보 + vendorCode: vendor.vendorCode || "", + vendorName: vendor.vendorName, + taxId: vendor.taxId, + // 아이템 정보 + itemCode: item.itemCode, + itemName: item.itemName, + createdAt: item.createdAt ? formatDate(item.createdAt) : "", + }); + }); + } else { + // 아이템이 없는 경우에도 벤더 정보만 추가 + itemsSheet.addRow({ + vendorCode: vendor.vendorCode || "", + vendorName: vendor.vendorName, + taxId: vendor.taxId, + itemCode: "", + itemName: "", + createdAt: "", + }); + } + }); +} + + +// 헤더 스타일 적용 함수 +function applyHeaderStyle(sheet: ExcelJS.Worksheet): void { + const headerRow = sheet.getRow(1); + headerRow.font = { bold: true }; + headerRow.alignment = { horizontal: "center" }; + headerRow.eachCell((cell: ExcelJS.Cell) => { + cell.fill = { + type: "pattern", + pattern: "solid", + fgColor: { argb: "FFCCCCCC" }, + }; + }); +} + +// 날짜 포맷 함수 +function formatDate(date: Date | string): string { + if (!date) return ""; + if (typeof date === 'string') { + date = new Date(date); + } + return date.toISOString().split('T')[0]; +} + + +// 상태 코드를 읽기 쉬운 텍스트로 변환하는 함수 +function getStatusText(status: string): string { + const statusMap: Record<string, string> = { + "PENDING_REVIEW": "검토 대기중", + "IN_REVIEW": "검토 중", + "REJECTED": "거부됨", + "ACTIVE": "활성", + "INACTIVE": "비활성", + "BLACKLISTED": "거래 금지" + }; + + return statusMap[status] || status; +}
\ No newline at end of file |
