import * as XLSX from 'xlsx'; export interface HardwareAsset { id: string; type: string; // '개인PC', '서버', '스토리지', '전산비품' 법인: string; 자산코드: string; 명칭: string; 위치: string; 관리자: string; IP주소: string; IP2?: string; MACaddress: string; HW사양: string; OS: string; 사용자?: string; CPU?: string; GPU?: string; RAM?: string; SSD1?: string; SSD2?: string; HDD1?: string; HDD2?: string; storage유형?: string; 비품유형?: string; 모델명?: string; 용량?: string; 담당자_정?: string; 담당자_부?: string; 구매일?: string; 금액?: string; 납품업체: string; 품의서명: string; 용도?: string; 상세?: string; 원격접속?: string; 서버ID?: string; 서버PW?: string; 모니터링?: string; 비고?: string; 현사용조직?: string; } export interface SoftwareAsset { id: string; type: string; // '구독SW', '영구SW' 분야?: string; 법인: string; 부서?: string; 제품명: string; 구매일: string; 구독일?: string; 유지보수여부?: boolean; 금액: string; 수량: number; 계정명: string; 납품업체: string; 비고: string; } export interface SWUser { id: string; swId: string; 법인: string; 부서: string; 팀: string; 직위: string; 이름: string; 사용기간: string; 신청서명: string; } export interface HardwareLog { id: string; assetId: string; date: string; details: string; user: string; } export interface MasterAssetData { hw: HardwareAsset[]; sw: SoftwareAsset[]; swUsers: SWUser[]; logs: HardwareLog[]; } const HW_TABS = ['개인PC', '서버', '스토리지', '전산비품']; const SW_TABS = ['구독SW', '영구SW']; const HW_HEADERS = ['법인', '자산코드', '명칭', '위치', '관리자', 'IP주소', 'MACaddress', 'HW사양', 'OS', '구매일', '금액', '납품업체', '품의서명']; const PC_HEADERS = ['법인', '자산코드', '사용자', '위치', 'CPU', 'GPU', 'RAM', 'SSD1', 'SSD2', 'HDD1', 'HDD2', '구매일', '금액', '납품업체', '품의서명']; const SERVER_HEADERS = ['법인', '자산번호', '유형', '용도', '설치위치', '담당자(정)', '담당자(부)', 'IP 주소', '원격접속', '모델명', 'OS', 'CPU', 'RAM', 'GPU', 'Storage1', 'Storage2', 'Storage3', '모니터링', '비고']; const STORAGE_HEADERS = ['법인', '유형', '자산코드', '명칭', '위치', '모델명', '용량', '담당자(정)', '담당자(부)', 'IP주소', 'MAC주소', '구매일', '금액', '납품업체', '품의서명']; const SUB_SW_HEADERS = ['ID', '분야', '법인', '부서', '제품명', '구매일', '구독일', '금액', '수량', '계정명', '납품업체', '비고']; const PERM_SW_HEADERS = ['ID', '분야', '법인', '부서', '제품명', '구매일', '유지보수여부', '금액', '수량', '계정명', '납품업체', '비고']; const SW_USER_HEADERS = ['id', 'swId', '법인', '부서', '팀', '직위', '이름', '사용기간', '신청서명']; const HISTORY_HEADERS = ['id', 'assetId', 'date', 'details', 'user']; /** * 템플릿 엑셀 다중 시트로 다운로드 */ export function downloadTemplate() { const wb = XLSX.utils.book_new(); HW_TABS.forEach(tab => { let hd = HW_HEADERS; let wscols: any[] = []; if (tab === '개인PC') { hd = PC_HEADERS; wscols = [{wch:15}, {wch:25}, {wch:15}, {wch:20}, {wch:20}, {wch:20}, {wch:15}, {wch:15}, {wch:15}, {wch:15}, {wch:15}, {wch:15}, {wch:15}, {wch:20}, {wch:25}]; } else if (tab === '서버') { hd = SERVER_HEADERS; wscols = [{wch:15}, {wch:20}, {wch:15}, {wch:25}, {wch:20}, {wch:15}, {wch:15}, {wch:20}, {wch:20}, {wch:25}, {wch:20}, {wch:15}, {wch:15}, {wch:15}, {wch:15}, {wch:15}, {wch:15}, {wch:15}, {wch:30}]; } else if (tab === '스토리지') { hd = STORAGE_HEADERS; wscols = [{wch:15}, {wch:15}, {wch:25}, {wch:25}, {wch:20}, {wch:25}, {wch:15}, {wch:15}, {wch:15}, {wch:15}, {wch:20}, {wch:15}, {wch:15}, {wch:20}, {wch:25}]; } else { hd = HW_HEADERS; wscols = [{wch:15}, {wch:20}, {wch:25}, {wch:20}, {wch:15}, {wch:15}, {wch:20}, {wch:40}, {wch:20}, {wch:15}, {wch:15}, {wch:20}, {wch:25}]; } const ws = XLSX.utils.aoa_to_sheet([hd]); ws['!cols'] = wscols; XLSX.utils.book_append_sheet(wb, ws, tab); }); SW_TABS.forEach(tab => { let hd = tab === '구독SW' ? SUB_SW_HEADERS : PERM_SW_HEADERS; const ws = XLSX.utils.aoa_to_sheet([hd]); ws['!cols'] = [{wch:15}, {wch:15}, {wch:15}, {wch:20}, {wch:30}, {wch:15}, {wch:20}, {wch:15}, {wch:10}, {wch:20}, {wch:20}, {wch:30}]; XLSX.utils.book_append_sheet(wb, ws, tab); }); const swUserWs = XLSX.utils.aoa_to_sheet([SW_USER_HEADERS]); swUserWs['!cols'] = [{wch:15}, {wch:15}, {wch:15}, {wch:15}, {wch:15}, {wch:15}, {wch:15}, {wch:20}, {wch:25}]; XLSX.utils.book_append_sheet(wb, swUserWs, 'SW_사용자'); const historyWs = XLSX.utils.aoa_to_sheet([HISTORY_HEADERS]); historyWs['!cols'] = [{wch:15}, {wch:20}, {wch:20}, {wch:50}, {wch:15}]; XLSX.utils.book_append_sheet(wb, historyWs, 'History'); XLSX.writeFile(wb, 'itam_assets_template.xlsx'); } /** * 마스터 데이터를 여러 시트로 쪼개서 내보내기 */ export function exportToExcel(masterData: MasterAssetData) { const wb = XLSX.utils.book_new(); HW_TABS.forEach(tab => { const targetAssets = masterData.hw.filter(a => a.type === tab); let wsData; let colsConfig; if (tab === '개인PC') { wsData = [ PC_HEADERS, ...targetAssets.map(a => [a.법인, a.자산코드, a.사용자, a.위치, a.CPU, a.GPU, a.RAM, a.SSD1, a.SSD2, a.HDD1, a.HDD2, a.구매일, a.금액, a.납품업체, a.품의서명]) ]; colsConfig = [{wch:15}, {wch:25}, {wch:15}, {wch:20}, {wch:20}, {wch:20}, {wch:15}, {wch:15}, {wch:15}, {wch:15}, {wch:15}, {wch:15}, {wch:15}, {wch:20}, {wch:25}]; } else if (tab === '서버') { wsData = [ SERVER_HEADERS, ...targetAssets.map(a => [a.법인, a.자산코드, a.storage유형 || '물리', a.용도 || '', a.위치, a.담당자_정 || '', a.담당자_부 || '', a.IP주소, a.원격접속 || '', a.모델명 || '', a.OS, a.CPU, a.RAM, a.GPU || '', a.SSD1 || '', a.SSD2 || '', a.HDD1 || '', a.모니터링 || '', a.비고 || '']) ]; colsConfig = [{wch:15}, {wch:20}, {wch:15}, {wch:25}, {wch:20}, {wch:15}, {wch:15}, {wch:20}, {wch:20}, {wch:25}, {wch:20}, {wch:15}, {wch:15}, {wch:15}, {wch:15}, {wch:15}, {wch:15}, {wch:15}, {wch:30}]; } else if (tab === '스토리지') { wsData = [ STORAGE_HEADERS, ...targetAssets.map(a => [a.법인, a.storage유형, a.자산코드, a.명칭, a.위치, a.모델명, a.용량, a.담당자_정, a.담당자_부, a.IP주소, a.MACaddress, a.구매일, a.금액, a.납품업체, a.품의서명]) ]; colsConfig = [{wch:15}, {wch:15}, {wch:25}, {wch:25}, {wch:20}, {wch:25}, {wch:15}, {wch:15}, {wch:15}, {wch:15}, {wch:20}, {wch:15}, {wch:15}, {wch:20}, {wch:25}]; } else { wsData = [ HW_HEADERS, ...targetAssets.map(a => [a.법인, a.자산코드, a.명칭, a.위치, a.관리자, a.IP주소, a.MACaddress, a.HW사양, a.OS, a.구매일, a.금액, a.납품업체, a.품의서명]) ]; colsConfig = [{wch:15}, {wch:20}, {wch:25}, {wch:20}, {wch:15}, {wch:15}, {wch:20}, {wch:40}, {wch:20}, {wch:15}, {wch:15}, {wch:20}, {wch:25}]; } const ws = XLSX.utils.aoa_to_sheet(wsData); ws['!cols'] = colsConfig; XLSX.utils.book_append_sheet(wb, ws, tab); }); SW_TABS.forEach(tab => { const targetAssets = masterData.sw.filter(a => a.type === tab); let wsData; if (tab === '구독SW') { wsData = [ SUB_SW_HEADERS, ...targetAssets.map(a => [a.id, a.분야||'', a.법인, a.부서||'', a.제품명, a.구매일, a.구독일, a.금액, a.수량, a.계정명, a.납품업체, a.비고]) ]; } else { wsData = [ PERM_SW_HEADERS, ...targetAssets.map(a => [a.id, a.분야||'', a.법인, a.부서||'', a.제품명, a.구매일, a.유지보수여부 ? 'Y' : 'N', a.금액, a.수량, a.계정명, a.납품업체, a.비고]) ]; } const ws = XLSX.utils.aoa_to_sheet(wsData); ws['!cols'] = [{wch:15}, {wch:15}, {wch:15}, {wch:20}, {wch:30}, {wch:15}, {wch:20}, {wch:15}, {wch:10}, {wch:20}, {wch:20}, {wch:30}]; XLSX.utils.book_append_sheet(wb, ws, tab); }); const swUserWsData = [ SW_USER_HEADERS, ...masterData.swUsers.map(u => [u.id, u.swId, u.법인, u.부서, u.팀, u.직위, u.이름, u.사용기간, u.신청서명]) ]; const swUserWs = XLSX.utils.aoa_to_sheet(swUserWsData); swUserWs['!cols'] = [{wch:15}, {wch:15}, {wch:15}, {wch:15}, {wch:15}, {wch:15}, {wch:15}, {wch:20}, {wch:25}]; XLSX.utils.book_append_sheet(wb, swUserWs, 'SW_사용자'); const historyWsData = [ HISTORY_HEADERS, ...masterData.logs.map(l => [l.id, l.assetId, l.date, l.details, l.user]) ]; const historyWs = XLSX.utils.aoa_to_sheet(historyWsData); historyWs['!cols'] = [{wch:15}, {wch:20}, {wch:20}, {wch:50}, {wch:15}]; XLSX.utils.book_append_sheet(wb, historyWs, 'History'); const dateStr = new Date().toISOString().split('T')[0]; XLSX.writeFile(wb, `itam_assets_master_${dateStr}.xlsx`); } export async function parseExcel(file: File): Promise { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = (e) => { try { const data = e.target?.result; const workbook = XLSX.read(data, { type: 'binary' }); const hwAssets: HardwareAsset[] = []; const swAssets: SoftwareAsset[] = []; const swUsers: SWUser[] = []; const logs: HardwareLog[] = []; workbook.SheetNames.forEach(sheetName => { const worksheet = workbook.Sheets[sheetName]; const json = XLSX.utils.sheet_to_json(worksheet) as any[]; if (HW_TABS.includes(sheetName)) { json.forEach(row => { if (sheetName === '개인PC') { hwAssets.push({ id: Math.random().toString(36).substring(2, 9), type: sheetName, 법인: row['법인'] || '', 자산코드: row['자산코드'] || '', 명칭: '', 위치: row['위치'] || '', 사용자: row['사용자'] || '', 관리자: '', IP주소: '', MACaddress: '', HW사양: '', OS: '', CPU: row['CPU'] || '', GPU: row['GPU'] || '', RAM: row['RAM'] || '', SSD1: row['SSD1'] || '', SSD2: row['SSD2'] || '', HDD1: row['HDD1'] || '', HDD2: row['HDD2'] || '', 구매일: row['구매일'] || '', 금액: row['금액'] ? String(row['금액']) : '', 납품업체: row['납품업체'] || '', 품의서명: row['품의서명'] || '', }); } else if (sheetName === '서버') { hwAssets.push({ id: Math.random().toString(36).substring(2, 9), type: sheetName, 법인: row['법인'] || '', 자산코드: row['자산번호'] || row['자산코드'] || '', 명칭: row['용도'] || row['명칭'] || '', 용도: row['용도'] || '', 위치: row['설치위치'] || row['위치'] || '', 관리자: row['담당자(정)'] || '', 담당자_정: row['담당자(정)'] || '', 담당자_부: row['담당자(부)'] || '', IP주소: row['IP 주소'] || row['IP주소'] || '', IP2: row['IP2'] || '', 원격접속: row['원격접속'] || '', 서버ID: row['서버ID'] || '', 서버PW: row['서버PW'] || '', 모델명: row['모델명'] || '', OS: row['OS'] || '', CPU: row['CPU'] || '', RAM: row['RAM'] || '', GPU: row['GPU'] || '', SSD1: row['Storage1'] || row['SSD1'] || '', SSD2: row['Storage2'] || row['SSD2'] || '', HDD1: row['Storage3'] || row['HDD1'] || '', 모니터링: row['모니터링'] || '', 비고: row['비고'] || '', storage유형: row['유형'] || '물리', MACaddress: '', HW사양: '', 구매일: '', 금액: '', 납품업체: '', 품의서명: '', }); } else if (sheetName === '스토리지') { hwAssets.push({ id: Math.random().toString(36).substring(2, 9), type: sheetName, 법인: row['법인'] || '', 자산코드: row['자산코드'] || '', 명칭: row['명칭'] || '', 위치: row['위치'] || '', 관리자: '', IP주소: row['IP주소'] || '', MACaddress: row['MAC주소'] || '', HW사양: '', OS: '', storage유형: row['유형'] || '', 모델명: row['모델명'] || '', 용량: row['용량'] || '', 담당자_정: row['담당자(정)'] || '', 담당자_부: row['담당자(부)'] || '', 구매일: row['구매일'] || '', 금액: row['금액'] ? String(row['금액']) : '', 납품업체: row['납품업체'] || '', 품의서명: row['품의서명'] || '', }); } else { hwAssets.push({ id: Math.random().toString(36).substring(2, 9), type: sheetName, 법인: row['법인'] || '', 자산코드: row['자산코드'] || '', 명칭: row['명칭'] || '', 위치: row['위치'] || '', 관리자: row['관리자'] || '', IP주소: row['IP주소'] || '', MACaddress: row['MACaddress'] || '', HW사양: row['HW사양'] || '', OS: row['OS'] || '', 구매일: row['구매일'] || '', 금액: row['금액'] ? String(row['금액']) : '', 납품업체: row['납품업체'] || '', 품의서명: row['품의서명'] || '', }); } }); } if (SW_TABS.includes(sheetName)) { json.forEach(row => { swAssets.push({ id: row['ID'] ? String(row['ID']) : Math.random().toString(36).substring(2, 9), type: sheetName, 분야: row['분야'] || '', 법인: row['법인'] || '', 부서: row['부서'] || '', 제품명: row['제품명'] || '', 구매일: row['구매일'] || '', 구독일: row['구독일'] || '', 유지보수여부: row['유지보수여부'] === 'Y' || row['유지보수여부'] === true, 금액: row['금액'] ? String(row['금액']) : '', 수량: parseInt(row['수량'] || '1', 10), 계정명: row['계정명'] || '', 납품업체: row['납품업체'] || '', 비고: row['비고'] || '', }); }); } if (sheetName === 'SW_사용자') { json.forEach(row => { swUsers.push({ id: row['id'] ? String(row['id']) : Math.random().toString(36).substring(2, 9), swId: row['swId'] ? String(row['swId']) : '', 법인: row['법인'] || '', 부서: row['부서'] || '', 팀: row['팀'] || '', 직위: row['직위'] || '', 이름: row['이름'] || '', 사용기간: row['사용기간'] || '', 신청서명: row['신청서명'] || '', }); }); } if (sheetName === 'History') { json.forEach(row => { logs.push({ id: row['id'] ? String(row['id']) : Math.random().toString(36).substring(2, 9), assetId: row['assetId'] ? String(row['assetId']) : '', date: row['date'] || '', details: row['details'] || '', user: row['user'] || '', }); }); } }); resolve({ hw: hwAssets, sw: swAssets, swUsers, logs }); } catch (err) { reject(err); } }; reader.onerror = (err) => reject(err); reader.readAsBinaryString(file); }); }