From 2d25c044574d97789f9142098647afd5ffcdccce Mon Sep 17 00:00:00 2001 From: Hyungi Ahn Date: Tue, 2 Sep 2025 17:20:37 +0900 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=A7=20=EB=AF=B8=EB=A6=AC=EB=B3=B4?= =?UTF-8?q?=EA=B8=B0=20=EC=9D=B8=EC=A6=9D=20=EB=B0=8F=20=EC=97=90=EB=9F=AC?= =?UTF-8?q?=20=EC=B2=98=EB=A6=AC=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🛠️ 401 Unauthorized 오류 해결: - HTML 콘텐츠 API 호출을 api.get() 래퍼로 변경 - iframe src에 토큰 파라미터 추가 - 백엔드에서 _token 쿼리 파라미터 지원 🛠️ 404 Not Found 오류 해결: - 문서 상세 정보를 먼저 로드하여 PDF/HTML 존재 여부 확인 - PDF/HTML 파일 존재 여부에 따른 조건부 렌더링 - 미리보기 타입 자동 감지 및 적절한 뷰어 선택 🎯 에러 처리 및 UX 개선: - HTML 로드 실패 시 에러 메시지 표시 - 미리보기 불가능한 콘텐츠에 대한 fallback UI - 문서 정보 로드 실패 시 기본 내용으로 fallback - '원본에서 보기' 버튼으로 대안 제공 🔍 미리보기 로직 개선: - 문서 타입별 적절한 미리보기 방식 자동 선택 - PDF 존재 시 PDF 뷰어, HTML 존재 시 HTML 뷰어 - 검색어 하이라이트 타이밍 최적화 - 로딩 상태 및 에러 상태 명확한 구분 --- backend/src/api/routes/documents.py | 1 + frontend/search.html | 17 +++++-- frontend/static/js/search.js | 72 ++++++++++++++++++++--------- 3 files changed, 66 insertions(+), 24 deletions(-) diff --git a/backend/src/api/routes/documents.py b/backend/src/api/routes/documents.py index 0654d06..651ea75 100644 --- a/backend/src/api/routes/documents.py +++ b/backend/src/api/routes/documents.py @@ -468,6 +468,7 @@ async def get_document( @router.get("/{document_id}/content") async def get_document_content( document_id: str, + _token: Optional[str] = Query(None), current_user: User = Depends(get_current_active_user), db: AsyncSession = Depends(get_db) ): diff --git a/frontend/search.html b/frontend/search.html index 2a0d325..c5d2711 100644 --- a/frontend/search.html +++ b/frontend/search.html @@ -466,7 +466,7 @@
-
@@ -640,14 +640,25 @@
- -
+
+ +
+ +

미리보기할 수 있는 내용이 없습니다.

+ +
+
diff --git a/frontend/static/js/search.js b/frontend/static/js/search.js index deb62c6..7e2267d 100644 --- a/frontend/static/js/search.js +++ b/frontend/static/js/search.js @@ -199,10 +199,36 @@ window.searchApp = function() { this.previewLoading = true; try { - // 타입별 미리보기 로드 - if ((result.type === 'document' || result.type === 'document_content') && !result.highlight_info?.has_pdf) { - // HTML 문서 미리보기 - await this.loadHtmlPreview(result.document_id); + // 문서 타입인 경우 상세 정보 먼저 로드 + if (result.type === 'document' || result.type === 'document_content') { + try { + const docInfo = await this.api.get(`/documents/${result.document_id}`); + // PDF 정보 업데이트 + this.previewResult = { + ...result, + highlight_info: { + ...result.highlight_info, + has_pdf: !!docInfo.pdf_path, + has_html: !!docInfo.html_path + } + }; + + // PDF가 있으면 PDF 미리보기, 없으면 HTML 미리보기 + if (docInfo.pdf_path) { + // PDF 미리보기는 iframe으로 자동 처리 + console.log('PDF 미리보기 준비 완료'); + } else if (docInfo.html_path) { + // HTML 문서 미리보기 + await this.loadHtmlPreview(result.document_id); + } + } catch (docError) { + console.error('문서 정보 로드 실패:', docError); + // 기본 내용 로드로 fallback + const fullContent = await this.loadFullContent(result); + if (fullContent) { + this.previewResult = { ...result, content: fullContent }; + } + } } else { // 기타 타입 - 전체 내용 로드 const fullContent = await this.loadFullContent(result); @@ -303,35 +329,39 @@ window.searchApp = function() { this.htmlLoading = true; try { - // HTML 내용 가져오기 - const response = await fetch(`/api/documents/${documentId}/content`, { - headers: { - 'Authorization': `Bearer ${localStorage.getItem('token')}` - } - }); + // API를 통해 HTML 내용 가져오기 + const htmlContent = await this.api.get(`/documents/${documentId}/content`); - if (response.ok) { - const htmlContent = await response.text(); + if (htmlContent) { this.htmlSourceCode = this.escapeHtml(htmlContent); // iframe에 HTML 로드 const iframe = document.getElementById('htmlPreviewFrame'); if (iframe) { - const doc = iframe.contentDocument || iframe.contentWindow.document; - doc.open(); - doc.write(htmlContent); - doc.close(); + // iframe src를 직접 설정 (인증 헤더 포함) + const token = localStorage.getItem('token'); + iframe.src = `/api/documents/${documentId}/content?_token=${encodeURIComponent(token)}`; - // 검색어 하이라이트 (iframe 내부) - if (this.searchQuery) { - this.highlightInIframe(iframe, this.searchQuery); - } + // iframe 로드 완료 후 검색어 하이라이트 + iframe.onload = () => { + if (this.searchQuery) { + setTimeout(() => { + this.highlightInIframe(iframe, this.searchQuery); + }, 100); + } + }; } } else { - throw new Error('HTML 로드 실패'); + throw new Error('HTML 내용이 비어있습니다'); } } catch (error) { console.error('HTML 미리보기 로드 실패:', error); + // 에러 시 기본 내용 표시 + this.htmlSourceCode = `
+ +

HTML 내용을 로드할 수 없습니다.

+

${error.message}

+
`; } finally { this.htmlLoading = false; }