// PDF 관리 애플리케이션 컴포넌트 window.pdfManagerApp = () => ({ // 상태 관리 pdfDocuments: [], allDocuments: [], loading: false, error: '', filterType: 'all', // 'all', 'book', 'linked', 'standalone' viewMode: 'books', // 'list', 'books' groupedPDFs: [], // 서적별 그룹화된 PDF 목록 // 인증 상태 isAuthenticated: false, currentUser: null, // PDF 미리보기 상태 showPreviewModal: false, previewPdf: null, pdfPreviewSrc: '', pdfPreviewLoading: false, pdfPreviewError: false, pdfPreviewLoaded: false, // 초기화 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.getAllDocuments(); // 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 ? '예' : '아니오'}`); }); // 서적별 그룹화 실행 this.groupPDFsByBook(); } catch (error) { console.error('PDF 로드 실패:', error); this.error = 'PDF 파일을 불러오는데 실패했습니다: ' + error.message; this.pdfDocuments = []; this.groupedPDFs = []; } 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 그룹화 groupPDFsByBook() { if (!this.pdfDocuments || this.pdfDocuments.length === 0) { this.groupedPDFs = []; return; } const grouped = {}; this.pdfDocuments.forEach(pdf => { const bookKey = pdf.book_id || 'no-book'; if (!grouped[bookKey]) { grouped[bookKey] = { book: pdf.book_id ? { id: pdf.book_id, title: pdf.book_title, author: pdf.book_author } : null, pdfs: [], linkedCount: 0, expanded: false // 기본적으로 축소된 상태 }; } grouped[bookKey].pdfs.push(pdf); if (pdf.isLinked) { grouped[bookKey].linkedCount++; } }); // 배열로 변환하고 정렬 (서적 있는 것 먼저, 그 다음 서적명 순) this.groupedPDFs = Object.values(grouped).sort((a, b) => { if (!a.book && b.book) return 1; if (a.book && !b.book) return -1; if (!a.book && !b.book) return 0; return a.book.title.localeCompare(b.book.title); }); console.log('📚 서적별 PDF 그룹화 완료:', this.groupedPDFs.length, '개 그룹'); // 디버깅: 그룹화 결과 확인 this.groupedPDFs.forEach((group, index) => { console.log(`📖 그룹 ${index + 1}: ${group.book?.title || 'PDF 미분류'} (${group.pdfs.length}개 PDF, ${group.linkedCount}개 연결됨)`); }); }, // 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'); } }, // ==================== PDF 미리보기 관련 ==================== async previewPDF(pdf) { console.log('👁️ PDF 미리보기:', pdf.title); this.previewPdf = pdf; this.showPreviewModal = true; this.pdfPreviewLoading = true; this.pdfPreviewError = false; this.pdfPreviewLoaded = false; try { const token = localStorage.getItem('access_token'); if (!token || token === 'null' || token === null) { throw new Error('인증 토큰이 없습니다. 다시 로그인해주세요.'); } // PDF 미리보기 URL 설정 this.pdfPreviewSrc = `/api/documents/${pdf.id}/pdf?_token=${encodeURIComponent(token)}`; console.log('✅ PDF 미리보기 준비 완료:', this.pdfPreviewSrc); } catch (error) { console.error('❌ PDF 미리보기 로드 실패:', error); this.pdfPreviewError = true; this.showNotification('PDF 미리보기 로드에 실패했습니다: ' + error.message, 'error'); } finally { this.pdfPreviewLoading = false; } }, closePreview() { this.showPreviewModal = false; this.previewPdf = null; this.pdfPreviewSrc = ''; this.pdfPreviewLoading = false; this.pdfPreviewError = false; this.pdfPreviewLoaded = false; }, handlePdfPreviewError() { console.error('❌ PDF 미리보기 iframe 로드 오류'); this.pdfPreviewError = true; this.pdfPreviewLoading = false; }, async retryPdfPreview() { if (this.previewPdf) { await this.previewPDF(this.previewPdf); } }, // 날짜 포맷팅 formatDate(dateString) { if (!dateString) return ''; const date = new Date(dateString); return date.toLocaleDateString('ko-KR', { year: 'numeric', month: 'long', day: 'numeric' }); }, // 로그아웃 async logout() { try { await window.api.logout(); } catch (error) { console.error('Logout error:', error); } finally { // 로컬 스토리지 정리 localStorage.removeItem('access_token'); localStorage.removeItem('refresh_token'); localStorage.removeItem('user_info'); console.log('✅ 로그아웃 완료'); } }, // 알림 표시 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 페이지 로드됨'); });