From 14f61e24947fb92dd71ec0a7196a6e815f8e66da Mon Sep 17 00:00:00 2001 From: dujinkim Date: Mon, 21 Jul 2025 07:54:26 +0000 Subject: (최겸)기술영업 RFQ 담당자 초대, 요구사항 반영 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../table/excel-template.tsx | 151 ++++++++++++++++----- 1 file changed, 119 insertions(+), 32 deletions(-) (limited to 'lib/tech-vendor-possible-items/table/excel-template.tsx') diff --git a/lib/tech-vendor-possible-items/table/excel-template.tsx b/lib/tech-vendor-possible-items/table/excel-template.tsx index 70a7eddf..20880350 100644 --- a/lib/tech-vendor-possible-items/table/excel-template.tsx +++ b/lib/tech-vendor-possible-items/table/excel-template.tsx @@ -2,7 +2,7 @@ import * as ExcelJS from 'exceljs'; import { saveAs } from "file-saver"; /** - * 기술영업 벤더 가능 아이템 Import를 위한 Excel 템플릿 파일 생성 및 다운로드 + * 기술영업 벤더 가능 아이템 Import를 위한 Excel 템플릿 파일 생성 및 다운로드 (새로운 스키마 버전) */ export async function exportTechVendorPossibleItemsTemplate() { // 워크북 생성 @@ -13,11 +13,15 @@ export async function exportTechVendorPossibleItemsTemplate() { // 워크시트 생성 const worksheet = workbook.addWorksheet('기술영업 벤더 가능 아이템'); - // 컬럼 헤더 정의 및 스타일 적용 + // 컬럼 헤더 정의 및 스타일 적용 (새로운 스키마에 맞춰) worksheet.columns = [ - { header: '아이템코드', key: 'itemCode', width: 20 }, - { header: '벤더코드', key: 'vendorCode', width: 15 }, - { header: '벤더이메일', key: 'vendorEmail', width: 30 }, + { header: '벤더이메일 (필수)', key: 'vendorEmail', width: 30 }, + { header: '아이템코드 (필수)', key: 'itemCode', width: 20 }, + { header: '공종 (선택)', key: 'workType', width: 15 }, + { header: '선종 (선택)', key: 'shipTypes', width: 20 }, + { header: '아이템리스트 (선택)', key: 'itemList', width: 35 }, + { header: '서브아이템리스트 (선택)', key: 'subItemList', width: 35 }, + { header: '벤더코드 (호환성)', key: 'vendorCode', width: 15 }, ]; // 헤더 스타일 적용 @@ -44,18 +48,58 @@ export async function exportTechVendorPossibleItemsTemplate() { }; }); - // 샘플 데이터 추가 + // 샘플 데이터 추가 (새로운 스키마에 맞춰) const sampleData = [ - { itemCode: 'ITEM001', vendorCode: 'V001', vendorEmail: '' }, - { itemCode: 'ITEM001', vendorCode: 'V002', vendorEmail: '' }, - { itemCode: 'ITEM002', vendorCode: '', vendorEmail: 'vendor@example.com' }, - { itemCode: 'ITEM002', vendorCode: 'V002', vendorEmail: '' }, - { itemCode: 'ITEM004', vendorCode: '', vendorEmail: 'vendor2@example.com' }, + { + vendorEmail: 'vendor1@example.com', + itemCode: 'ITEM001', + workType: '용접', + shipTypes: '컨테이너선', + itemList: '선체 용접 작업', + subItemList: '외판 용접, 내부 구조 용접', + vendorCode: 'V001' + }, + { + vendorEmail: 'vendor2@example.com', + itemCode: 'ITEM002', + workType: '도장', + shipTypes: '벌크선', + itemList: '선체 도장 작업', + subItemList: '프라이머, 탑코트', + vendorCode: '' + }, + { + vendorEmail: 'vendor3@example.com', + itemCode: 'ITEM003', + workType: '기계', + shipTypes: '탱커', + itemList: '기계 설비 설치', + subItemList: '엔진, 펌프, 배관', + vendorCode: '' + }, + { + vendorEmail: 'vendor1@example.com', + itemCode: 'ITEM004', + workType: '용접', + shipTypes: '컨테이너선, 벌크선', + itemList: '특수 용접 작업', + subItemList: '', + vendorCode: 'V001' + }, + { + vendorEmail: 'vendor4@example.com', + itemCode: 'ITEM005', + workType: '', + shipTypes: '', + itemList: '', + subItemList: '', + vendorCode: 'V004' + }, ]; sampleData.forEach((data) => { const row = worksheet.addRow(data); - row.eachCell((cell) => { + row.eachCell((cell, colNumber) => { cell.border = { top: { style: 'thin' }, left: { style: 'thin' }, @@ -66,35 +110,75 @@ export async function exportTechVendorPossibleItemsTemplate() { vertical: 'middle', horizontal: 'left' }; + + // 긴 텍스트 필드는 줄바꿈 허용 + if (colNumber >= 5 && colNumber <= 6) { // itemList, subItemList + cell.alignment = { + vertical: 'top', + horizontal: 'left', + wrapText: true + }; + } }); }); - // 안내사항 워크시트 생성 + // 안내사항 워크시트 생성 (새로운 스키마에 맞춰) const guideSheet = workbook.addWorksheet('사용 가이드'); const guideData = [ - ['기술영업 벤더 가능 아이템 Import 템플릿', ''], + ['기술영업 벤더 가능 아이템 Import 템플릿 (새로운 스키마)', ''], ['', ''], - ['📋 사용 방법:', ''], + ['📋 새로운 스키마 특징:', ''], + ['- 더욱 구체적인 아이템 정보 관리', ''], + ['- 공종과 선종으로 세분화된 분류', ''], + ['- 아이템 상세 설명 및 서브 아이템 정보', ''], + ['- 중복 아이템도 공종/선종이 다르면 별도 관리', ''], + ['', ''], + ['📌 필수 입력 필드:', ''], + ['1. 벤더이메일: 시스템에 등록된 벤더의 이메일 주소', ''], + [' 예: vendor@company.com', ''], + ['2. 아이템코드: 처리할 아이템의 고유 코드', ''], + [' 예: ITEM001, WELD_001, PAINT_002', ''], + ['', ''], + ['📝 선택 입력 필드:', ''], + ['3. 공종: 작업 유형 분류', ''], + [' 예: 용접, 도장, 기계, 전기, 배관 등', ''], + ['4. 선종: 적용 가능한 선박 유형', ''], + [' 예: 컨테이너선, 벌크선, 탱커, LNG선 등', ''], + [' - 여러 선종은 콤마로 구분: "컨테이너선, 벌크선"', ''], + ['5. 아이템리스트: 아이템에 대한 상세 설명', ''], + [' 예: "선체 용접 작업", "외판 도장 및 마감"', ''], + ['6. 서브아이템리스트: 세부 작업 항목들', ''], + [' 예: "외판 용접, 내부 구조 용접, 배관 용접"', ''], + ['7. 벤더코드: 기존 호환성을 위한 선택 필드', ''], + ['', ''], + ['🔍 중복 처리 로직:', ''], + ['- 동일한 벤더 + 아이템코드 + 공종 + 선종 = 중복으로 처리', ''], + ['- 아이템코드가 같아도 공종이나 선종이 다르면 별도 항목', ''], + ['- 예: ITEM001 + 용접 + 컨테이너선 ≠ ITEM001 + 도장 + 컨테이너선', ''], + ['', ''], + ['💡 사용 방법:', ''], ['1. "기술영업 벤더 가능 아이템" 시트에 데이터를 입력하세요', ''], - ['2. 벤더 식별: 벤더코드 또는 벤더이메일 중 하나는 반드시 입력', ''], - [' • 벤더코드가 있으면 벤더코드를 우선 사용', ''], - [' • 벤더코드가 없으면 벤더이메일로 벤더 검색', ''], - ['3. 아이템코드는 실제 존재하는 아이템코드를 사용하세요', ''], - ['4. 한 아이템코드에 여러 벤더를 매핑할 수 있습니다 (1:N 관계)', ''], - ['5. 중복된 벤더-아이템 조합은 무시됩니다', ''], + ['2. 필수 필드(벤더이메일, 아이템코드)는 반드시 입력', ''], + ['3. 선택 필드는 필요에 따라 입력 (빈 칸으로 두어도 됨)', ''], + ['4. 한 벤더가 여러 아이템을 담당할 수 있습니다 (1:N 관계)', ''], + ['5. 한 아이템에 여러 벤더를 배정할 수 있습니다 (N:M 관계)', ''], ['6. 파일 저장 후 시스템에서 업로드하세요', ''], ['', ''], - ['⚠️ 중요 사항:', ''], - ['- 벤더코드 또는 벤더이메일 중 하나는 반드시 필요', ''], - ['- 벤더코드가 우선, 없으면 벤더이메일로 검색', ''], - ['- 중복된 벤더-아이템 조합은 건너뜁니다', ''], + ['⚠️ 주의사항:', ''], + ['- 벤더이메일은 시스템에 이미 등록된 이메일이어야 함', ''], + ['- 이메일 형식 확인: @를 포함한 올바른 이메일 형식', ''], + ['- 아이템코드는 특수문자나 공백 주의', ''], + ['- 긴 텍스트 필드(아이템리스트, 서브아이템리스트)는 줄바꿈 가능', ''], ['- 오류가 있는 항목은 별도 파일로 다운로드됩니다', ''], - ['- 빈 셀이 있으면 해당 행은 무시됩니다', ''], ['', ''], - ['💡 팁:', ''], - ['- 벤더코드만 존재하면 어떤 아이템코드든 입력 가능합니다', ''], - ['- 아이템코드는 그대로 시스템에 저장됩니다', ''], + ['📊 데이터 예시:', ''], + ['벤더이메일: welding@company.com', ''], + ['아이템코드: WELD_HULL_001', ''], + ['공종: 용접', ''], + ['선종: 컨테이너선, 벌크선', ''], + ['아이템리스트: 선체 구조 용접 작업', ''], + ['서브아이템리스트: 외판 용접, 격벽 용접, 갑판 용접', ''], ['', ''], ['📞 문의사항이 있으시면 시스템 관리자에게 연락하세요.', ''], ]; @@ -104,16 +188,19 @@ export async function exportTechVendorPossibleItemsTemplate() { if (index === 0) { // 제목 스타일 row.getCell(1).font = { bold: true, size: 16, color: { argb: 'FF1F4E79' } }; + } else if (rowData[0]?.includes('📋') || rowData[0]?.includes('📌') || rowData[0]?.includes('📝') || rowData[0]?.includes('🔍') || rowData[0]?.includes('💡') || rowData[0]?.includes('⚠️') || rowData[0]?.includes('📊')) { + // 섹션 제목 스타일 (이모지 포함) + row.getCell(1).font = { bold: true, color: { argb: 'FF1F4E79' } }; } else if (rowData[0]?.includes(':')) { - // 섹션 제목 스타일 + // 일반 제목 스타일 row.getCell(1).font = { bold: true, color: { argb: 'FF1F4E79' } }; - } else if (rowData[0]?.includes('•') || rowData[0]?.includes('-')) { + } else if (rowData[0]?.includes('-') || rowData[0]?.includes('•') || rowData[0]?.includes('예:')) { // 리스트 아이템 스타일 row.getCell(1).font = { color: { argb: 'FF333333' } }; } }); - guideSheet.getColumn(1).width = 70; + guideSheet.getColumn(1).width = 80; guideSheet.getColumn(2).width = 20; // 파일 생성 및 다운로드 -- cgit v1.2.3