// PDF 관리 애플리케이션 컴포넌트 window.pdfManagerApp = () => ({ // 상태 관리 pdfDocuments: [], allDocuments: [], loading: false, error: '', filterType: 'all', // 'all', 'book', 'linked', 'standalone' // 인증 상태 isAuthenticated: false, currentUser: null, // 초기화 async init() { console.log('🚀 PDF Manager App 초기화 시작'); // 인증 상태 확인 await this.checkAuthStatus(); if (this.isAuthenticated) { await this.loadPDFs(); } // 헤더 로드 await this.loadHeader(); }, // 인증 상태 확인 async checkAuthStatus() { try { const user = await window.api.getCurrentUser(); this.isAuthenticated = true; this.currentUser = user; console.log('✅ 인증됨:', user.username); } catch (error) { console.log('❌ 인증되지 않음'); this.isAuthenticated = false; this.currentUser = null; window.location.href = '/login.html'; } }, // 헤더 로드 async loadHeader() { try { await window.headerLoader.loadHeader(); } catch (error) { console.error('헤더 로드 실패:', error); } }, // PDF 파일들 로드 async loadPDFs() { this.loading = true; this.error = ''; try { // 모든 문서 가져오기 this.allDocuments = await window.api.getDocuments(); // PDF 파일들만 필터링 this.pdfDocuments = this.allDocuments.filter(doc => (doc.original_filename && doc.original_filename.toLowerCase().endsWith('.pdf')) || (doc.pdf_path && doc.pdf_path !== '') || (doc.html_path === null && doc.pdf_path) // PDF만 업로드된 경우 ); // 연결 상태 및 서적 정보 확인 this.pdfDocuments.forEach(pdf => { // 이 PDF를 참조하는 다른 문서가 있는지 확인 const linkedDocuments = this.allDocuments.filter(doc => doc.matched_pdf_id === pdf.id ); pdf.isLinked = linkedDocuments.length > 0; pdf.linkedDocuments = linkedDocuments; // 서적 정보 추가 (PDF가 속한 서적 또는 연결된 문서의 서적) if (pdf.book_title) { // PDF 자체가 서적에 속한 경우 pdf.book_title = pdf.book_title; } else if (linkedDocuments.length > 0) { // 연결된 문서가 있는 경우, 첫 번째 연결 문서의 서적 정보 사용 const firstLinked = linkedDocuments[0]; pdf.book_title = firstLinked.book_title; } }); console.log('📕 PDF 문서들:', this.pdfDocuments.length, '개'); console.log('📚 서적 포함 PDF:', this.bookPDFs, '개'); console.log('🔗 HTML 연결 PDF:', this.linkedPDFs, '개'); console.log('📄 독립 PDF:', this.standalonePDFs, '개'); // 디버깅: PDF 서적 정보 확인 this.pdfDocuments.slice(0, 5).forEach(pdf => { console.log(`📋 ${pdf.title}: 서적=${pdf.book_title || '없음'}, 연결=${pdf.isLinked ? '예' : '아니오'}`); }); } catch (error) { console.error('PDF 로드 실패:', error); this.error = 'PDF 파일을 불러오는데 실패했습니다: ' + error.message; this.pdfDocuments = []; } finally { this.loading = false; } }, // 필터링된 PDF 목록 get filteredPDFs() { switch (this.filterType) { case 'book': return this.pdfDocuments.filter(pdf => pdf.book_title); case 'linked': return this.pdfDocuments.filter(pdf => pdf.isLinked); case 'standalone': return this.pdfDocuments.filter(pdf => !pdf.isLinked && !pdf.book_title); default: return this.pdfDocuments; } }, // 통계 계산 get bookPDFs() { return this.pdfDocuments.filter(pdf => pdf.book_title).length; }, get linkedPDFs() { return this.pdfDocuments.filter(pdf => pdf.isLinked).length; }, get standalonePDFs() { return this.pdfDocuments.filter(pdf => !pdf.isLinked && !pdf.book_title).length; }, // PDF 새로고침 async refreshPDFs() { await this.loadPDFs(); }, // PDF 다운로드 async downloadPDF(pdf) { try { console.log('📕 PDF 다운로드 시작:', pdf.id); // PDF 파일 다운로드 URL 생성 const downloadUrl = `/api/documents/${pdf.id}/download`; // 인증 헤더 추가를 위해 fetch 사용 const response = await fetch(downloadUrl, { method: 'GET', headers: { 'Authorization': `Bearer ${localStorage.getItem('access_token')}` } }); if (!response.ok) { throw new Error('PDF 다운로드에 실패했습니다'); } // Blob으로 변환하여 다운로드 const blob = await response.blob(); const url = window.URL.createObjectURL(blob); // 다운로드 링크 생성 및 클릭 const link = document.createElement('a'); link.href = url; link.download = pdf.original_filename || `${pdf.title}.pdf`; document.body.appendChild(link); link.click(); document.body.removeChild(link); // URL 정리 window.URL.revokeObjectURL(url); console.log('✅ PDF 다운로드 완료'); } catch (error) { console.error('❌ PDF 다운로드 실패:', error); alert('PDF 다운로드에 실패했습니다: ' + error.message); } }, // PDF 삭제 async deletePDF(pdf) { // 연결된 문서가 있는지 확인 if (pdf.isLinked && pdf.linkedDocuments.length > 0) { const linkedTitles = pdf.linkedDocuments.map(doc => doc.title).join('\n- '); const confirmMessage = `이 PDF는 다음 문서들과 연결되어 있습니다:\n\n- ${linkedTitles}\n\n정말 삭제하시겠습니까? 연결된 문서들의 PDF 링크가 해제됩니다.`; if (!confirm(confirmMessage)) { return; } } else { if (!confirm(`"${pdf.title}" PDF 파일을 삭제하시겠습니까?`)) { return; } } try { await window.api.deleteDocument(pdf.id); // 목록에서 제거 this.pdfDocuments = this.pdfDocuments.filter(p => p.id !== pdf.id); this.showNotification('PDF 파일이 삭제되었습니다', 'success'); // 목록 새로고침 (연결 상태 업데이트를 위해) await this.loadPDFs(); } catch (error) { console.error('PDF 삭제 실패:', error); this.showNotification('PDF 삭제에 실패했습니다: ' + error.message, 'error'); } }, // 날짜 포맷팅 formatDate(dateString) { if (!dateString) return ''; const date = new Date(dateString); return date.toLocaleDateString('ko-KR', { year: 'numeric', month: 'long', day: 'numeric' }); }, // 알림 표시 showNotification(message, type = 'info') { console.log(`${type.toUpperCase()}: ${message}`); // 간단한 토스트 알림 생성 const toast = document.createElement('div'); toast.className = `fixed top-4 right-4 px-6 py-3 rounded-lg text-white z-50 ${ type === 'success' ? 'bg-green-600' : type === 'error' ? 'bg-red-600' : 'bg-blue-600' }`; toast.textContent = message; document.body.appendChild(toast); // 3초 후 제거 setTimeout(() => { if (toast.parentNode) { toast.parentNode.removeChild(toast); } }, 3000); } }); // 페이지 로드 시 초기화 document.addEventListener('DOMContentLoaded', () => { console.log('📄 PDF Manager 페이지 로드됨'); });