feat: PDF 매칭 필터링 및 서적 정보 UI 개선
- 서적 편집 페이지에서 PDF 매칭 드롭다운이 현재 서적의 PDF만 표시하도록 수정 - PDF 관리 페이지에 서적 정보 표시 UI 추가 - 타입 안전한 비교로 book_id 필터링 개선 - PDF 통계 카드에 서적별 분류 추가 - 필터 기능에 '서적 포함' 옵션 추가 - 디버깅 로그 추가로 문제 추적 개선 주요 변경사항: - book-editor.js: String() 타입 변환으로 안전한 book_id 비교 - pdf-manager.html/js: 서적 정보 배지 및 통계 카드 추가 - book-documents.js: HTML 문서 필터링 로직 개선
This commit is contained in:
@@ -8,7 +8,7 @@ class DocumentServerAPI {
|
||||
this.token = localStorage.getItem('access_token');
|
||||
|
||||
console.log('🐳 API Base URL (DOCKER BACKEND):', this.baseURL);
|
||||
console.log('🔧 도커 환경 설정 완료 - 버전 2025012384');
|
||||
console.log('🔧 도커 환경 설정 완료 - 버전 2025012415');
|
||||
}
|
||||
|
||||
// 토큰 설정
|
||||
@@ -387,6 +387,11 @@ class DocumentServerAPI {
|
||||
return await this.put(`/books/${bookId}`, bookData);
|
||||
}
|
||||
|
||||
// 문서 네비게이션 정보 조회
|
||||
async getDocumentNavigation(documentId) {
|
||||
return await this.get(`/documents/${documentId}/navigation`);
|
||||
}
|
||||
|
||||
async searchBooks(query, limit = 10) {
|
||||
const params = new URLSearchParams({ q: query, limit });
|
||||
return await this.get(`/books/search/?${params}`);
|
||||
@@ -518,6 +523,36 @@ class DocumentServerAPI {
|
||||
async exportMemoTree(exportData) {
|
||||
return await this.post('/memo-trees/export', exportData);
|
||||
}
|
||||
|
||||
// 문서 링크 관련 API
|
||||
async createDocumentLink(documentId, linkData) {
|
||||
return await this.post(`/documents/${documentId}/links`, linkData);
|
||||
}
|
||||
|
||||
async getDocumentLinks(documentId) {
|
||||
return await this.get(`/documents/${documentId}/links`);
|
||||
}
|
||||
|
||||
async getLinkableDocuments(documentId) {
|
||||
return await this.get(`/documents/${documentId}/linkable-documents`);
|
||||
}
|
||||
|
||||
async updateDocumentLink(linkId, linkData) {
|
||||
return await this.put(`/documents/links/${linkId}`, linkData);
|
||||
}
|
||||
|
||||
async deleteDocumentLink(linkId) {
|
||||
return await this.delete(`/documents/links/${linkId}`);
|
||||
}
|
||||
|
||||
// 백링크 관련 API
|
||||
async getDocumentBacklinks(documentId) {
|
||||
return await this.get(`/documents/${documentId}/backlinks`);
|
||||
}
|
||||
|
||||
async getDocumentLinkFragments(documentId) {
|
||||
return await this.get(`/documents/${documentId}/link-fragments`);
|
||||
}
|
||||
}
|
||||
|
||||
// 전역 API 인스턴스
|
||||
|
||||
@@ -78,7 +78,7 @@ window.bookDocumentsApp = () => ({
|
||||
this.documents = allDocuments.filter(doc =>
|
||||
!doc.book_id &&
|
||||
doc.html_path &&
|
||||
!doc.pdf_path?.includes('/pdfs/') // pdfs 폴더에 있는 건 제외
|
||||
doc.html_path.includes('/documents/') // HTML은 documents 폴더에 저장됨
|
||||
);
|
||||
|
||||
// 서적 미분류 PDF 문서들 (매칭용)
|
||||
@@ -97,7 +97,7 @@ window.bookDocumentsApp = () => ({
|
||||
this.documents = allDocuments.filter(doc =>
|
||||
doc.book_id === this.bookId &&
|
||||
doc.html_path &&
|
||||
!doc.pdf_path?.includes('/pdfs/') // pdfs 폴더에 있는 건 제외
|
||||
doc.html_path.includes('/documents/') // HTML은 documents 폴더에 저장됨
|
||||
);
|
||||
|
||||
// 특정 서적의 PDF 문서들 (매칭용)
|
||||
@@ -132,6 +132,8 @@ window.bookDocumentsApp = () => ({
|
||||
|
||||
console.log('📚 서적 문서 로드 완료:', this.documents.length, '개');
|
||||
console.log('📕 사용 가능한 PDF:', this.availablePDFs.length, '개');
|
||||
console.log('📎 PDF 목록:', this.availablePDFs.map(pdf => ({ title: pdf.title, book_id: pdf.book_id })));
|
||||
console.log('🔍 현재 서적 ID:', this.bookId);
|
||||
|
||||
// 디버깅: 문서들의 original_filename 확인
|
||||
console.log('🔍 문서들 확인:');
|
||||
|
||||
@@ -84,20 +84,49 @@ window.bookEditorApp = () => ({
|
||||
.filter(doc =>
|
||||
doc.book_id === this.bookId &&
|
||||
doc.html_path &&
|
||||
!doc.pdf_path?.includes('/pdfs/') // pdfs 폴더에 있는 건 제외
|
||||
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 타입 문서들)
|
||||
// PDF 문서들만 필터링 (폴더 경로 기준)
|
||||
this.availablePDFs = allDocuments.filter(doc =>
|
||||
// 사용 가능한 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);
|
||||
|
||||
console.log('📎 사용 가능한 PDF:', this.availablePDFs.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);
|
||||
|
||||
@@ -5,7 +5,7 @@ window.pdfManagerApp = () => ({
|
||||
allDocuments: [],
|
||||
loading: false,
|
||||
error: '',
|
||||
filterType: 'all', // 'all', 'linked', 'standalone'
|
||||
filterType: 'all', // 'all', 'book', 'linked', 'standalone'
|
||||
|
||||
// 인증 상태
|
||||
isAuthenticated: false,
|
||||
@@ -66,7 +66,7 @@ window.pdfManagerApp = () => ({
|
||||
(doc.html_path === null && doc.pdf_path) // PDF만 업로드된 경우
|
||||
);
|
||||
|
||||
// 연결 상태 확인
|
||||
// 연결 상태 및 서적 정보 확인
|
||||
this.pdfDocuments.forEach(pdf => {
|
||||
// 이 PDF를 참조하는 다른 문서가 있는지 확인
|
||||
const linkedDocuments = this.allDocuments.filter(doc =>
|
||||
@@ -74,9 +74,27 @@ window.pdfManagerApp = () => ({
|
||||
);
|
||||
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);
|
||||
@@ -90,22 +108,28 @@ window.pdfManagerApp = () => ({
|
||||
// 필터링된 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);
|
||||
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).length;
|
||||
return this.pdfDocuments.filter(pdf => !pdf.isLinked && !pdf.book_title).length;
|
||||
},
|
||||
|
||||
// PDF 새로고침
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user