// 서적 편집 애플리케이션 컴포넌트 window.bookEditorApp = () => ({ // 상태 관리 documents: [], bookInfo: {}, availablePDFs: [], loading: false, saving: false, error: '', // 인증 상태 isAuthenticated: false, currentUser: null, // URL 파라미터 bookId: null, // SortableJS 인스턴스 sortableInstance: null, // 초기화 async init() { console.log('🚀 Book Editor App 초기화 시작'); // URL 파라미터 파싱 this.parseUrlParams(); // 인증 상태 확인 await this.checkAuthStatus(); if (this.isAuthenticated) { await this.loadBookData(); this.initSortable(); } // 헤더 로드 await this.loadHeader(); }, // URL 파라미터 파싱 parseUrlParams() { const urlParams = new URLSearchParams(window.location.search); this.bookId = urlParams.get('bookId'); console.log('📖 편집할 서적 ID:', this.bookId); }, // 인증 상태 확인 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); } }, // 서적 데이터 로드 async loadBookData() { this.loading = true; this.error = ''; try { // 서적 정보 로드 this.bookInfo = await window.api.getBook(this.bookId); console.log('📚 서적 정보 로드:', this.bookInfo); // 모든 문서 가져와서 이 서적에 속한 HTML 문서들만 필터링 (폴더로 구분) const allDocuments = await window.api.getDocuments(); this.documents = allDocuments .filter(doc => doc.book_id === this.bookId && doc.html_path && doc.html_path.includes('/documents/') // HTML은 documents 폴더에 저장됨 ) .sort((a, b) => (a.sort_order || 0) - (b.sort_order || 0)); // 순서대로 정렬 console.log('📄 서적 문서들:', this.documents.length, '개'); // 사용 가능한 PDF 문서들 로드 (현재 서적의 PDF만) console.log('🔍 현재 서적 ID:', this.bookId); console.log('🔍 전체 문서 수:', allDocuments.length); // PDF 문서들 먼저 필터링 const allPDFs = allDocuments.filter(doc => doc.pdf_path && doc.pdf_path.includes('/pdfs/') // PDF는 pdfs 폴더에 저장됨 ); console.log('🔍 전체 PDF 문서 수:', allPDFs.length); // 같은 서적의 PDF 문서들만 필터링 this.availablePDFs = allPDFs.filter(doc => { const match = String(doc.book_id) === String(this.bookId); if (!match && allPDFs.indexOf(doc) < 5) { console.log(`🔍 PDF "${doc.title}": book_id="${doc.book_id}" (${typeof doc.book_id}) vs bookId="${this.bookId}" (${typeof this.bookId})`); } return match; }); console.log('📎 현재 서적의 PDF:', this.availablePDFs.length, '개'); console.log('📎 현재 서적 PDF 목록:', this.availablePDFs.map(pdf => ({ title: pdf.title, book_id: pdf.book_id, book_title: pdf.book_title }))); // 디버깅: 다른 서적의 PDF들도 확인 const otherBookPDFs = allPDFs.filter(doc => doc.book_id !== this.bookId); console.log('🔍 다른 서적의 PDF:', otherBookPDFs.length, '개'); if (otherBookPDFs.length > 0) { console.log('🔍 다른 서적 PDF 예시:', otherBookPDFs.slice(0, 3).map(pdf => ({ title: pdf.title, book_id: pdf.book_id, book_title: pdf.book_title }))); } } catch (error) { console.error('서적 데이터 로드 실패:', error); this.error = '데이터를 불러오는데 실패했습니다: ' + error.message; } finally { this.loading = false; } }, // SortableJS 초기화 initSortable() { this.$nextTick(() => { const sortableList = document.getElementById('sortable-list'); if (sortableList && !this.sortableInstance) { this.sortableInstance = Sortable.create(sortableList, { animation: 150, ghostClass: 'sortable-ghost', chosenClass: 'sortable-chosen', dragClass: 'sortable-drag', handle: '.fa-grip-vertical', onEnd: (evt) => { // 배열 순서 업데이트 const item = this.documents.splice(evt.oldIndex, 1)[0]; this.documents.splice(evt.newIndex, 0, item); this.updateDisplayOrder(); } }); console.log('✅ SortableJS 초기화 완료'); } }); }, // 표시 순서 업데이트 updateDisplayOrder() { this.documents.forEach((doc, index) => { doc.sort_order = index + 1; }); console.log('🔢 표시 순서 업데이트됨'); }, // 위로 이동 moveUp(index) { if (index > 0) { const item = this.documents.splice(index, 1)[0]; this.documents.splice(index - 1, 0, item); this.updateDisplayOrder(); } }, // 아래로 이동 moveDown(index) { if (index < this.documents.length - 1) { const item = this.documents.splice(index, 1)[0]; this.documents.splice(index + 1, 0, item); this.updateDisplayOrder(); } }, // 이름순 정렬 autoSortByName() { this.documents.sort((a, b) => { return a.title.localeCompare(b.title, 'ko', { numeric: true }); }); this.updateDisplayOrder(); console.log('📝 이름순 정렬 완료'); }, // 순서 뒤집기 reverseOrder() { this.documents.reverse(); this.updateDisplayOrder(); console.log('🔄 순서 뒤집기 완료'); }, // 변경사항 저장 async saveChanges() { if (this.saving) return; this.saving = true; console.log('💾 저장 시작...'); try { // 저장 전에 순서 업데이트 this.updateDisplayOrder(); // 서적 정보 업데이트 console.log('📚 서적 정보 업데이트 중...'); await window.api.updateBook(this.bookId, { title: this.bookInfo.title, author: this.bookInfo.author, description: this.bookInfo.description }); console.log('✅ 서적 정보 업데이트 완료'); // 각 문서의 순서와 PDF 매칭 정보 업데이트 console.log('📄 문서 업데이트 시작...'); const updatePromises = this.documents.map((doc, index) => { console.log(`📄 문서 ${index + 1}/${this.documents.length}: ${doc.title}`); console.log(` - sort_order: ${doc.sort_order}`); console.log(` - matched_pdf_id: ${doc.matched_pdf_id || 'null'}`); return window.api.updateDocument(doc.id, { sort_order: doc.sort_order, matched_pdf_id: doc.matched_pdf_id || null }); }); const results = await Promise.all(updatePromises); console.log('✅ 모든 문서 업데이트 완료:', results.length, '개'); console.log('✅ 모든 변경사항 저장 완료'); this.showNotification('변경사항이 저장되었습니다', 'success'); // 잠시 후 서적 페이지로 돌아가기 setTimeout(() => { this.goBack(); }, 1500); } catch (error) { console.error('❌ 저장 실패:', error); this.showNotification('저장에 실패했습니다: ' + error.message, 'error'); } finally { this.saving = false; } }, // 뒤로가기 goBack() { window.location.href = `book-documents.html?bookId=${this.bookId}`; }, // 알림 표시 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('📄 Book Editor 페이지 로드됨'); });