const API = (() => { const BASE = '/api'; function token() { return localStorage.getItem('ev_token') || ''; } async function req(method, path, body = null, isForm = false) { const headers = {}; if (token()) headers['Authorization'] = 'Bearer ' + token(); let fetchBody = null; if (body) { if (isForm) { fetchBody = body; } else { headers['Content-Type'] = 'application/json'; fetchBody = JSON.stringify(body); } } const res = await fetch(BASE + path, { method, headers, body: fetchBody }); if (res.status === 401) { Auth.logout(); return; } if (!res.ok) { const err = await res.json().catch(() => ({ detail: '오류가 발생했습니다.' })); throw new Error(err.detail || '오류'); } const ct = res.headers.get('content-type') || ''; if (ct.includes('spreadsheet') || ct.includes('octet') || ct.includes('excel')) { return res.blob(); } return res.json().catch(() => ({})); } // 엑셀 다운로드 전용 함수 — 인증 토큰 포함, 에러 처리 강화 async function download(path, filename) { try { const headers = {}; if (token()) headers['Authorization'] = 'Bearer ' + token(); const res = await fetch(BASE + path, { method: 'GET', headers }); if (res.status === 401) { Auth.logout(); return; } if (!res.ok) { const err = await res.json().catch(() => ({ detail: '다운로드 오류' })); throw new Error(err.detail || '다운로드 오류'); } const blob = await res.blob(); if (!blob || blob.size === 0) { alert('데이터가 없어 엑셀 파일을 생성할 수 없습니다.'); return; } const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = filename; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); } catch(e) { alert('엑셀 다운로드 실패: ' + e.message); } } return { get: (path) => req('GET', path), post: (path, body) => req('POST', path, body, body instanceof FormData), put: (path, body) => req('PUT', path, body, body instanceof FormData), patch: (path, body) => req('PATCH', path, body, body instanceof FormData), delete: (path) => req('DELETE', path), download, }; })();