[前端+RAG] PDF原生渲染(pdfjs text layer);Excel列宽优化+水平滚动

This commit is contained in:
2026-04-02 13:24:41 +08:00
parent 200ccac9b9
commit f508a8b6b1
4 changed files with 282 additions and 6 deletions

View File

@@ -103,7 +103,12 @@
<div class="center-header">
<span class="center-title" :title="selectedFile.fileName">{{ selectedFile.fileName }}</span>
</div>
<div class="file-content" ref="fileContent" id="file-content">
<!-- PDF 原生渲染 -->
<div v-if="fileType === 'pdf'" class="file-content" ref="fileContent" id="file-content">
<PdfViewer v-if="pdfData" :src="pdfData" :scale="1.3" />
</div>
<!-- 其他文件类型HTML 渲染 -->
<div v-else class="file-content" ref="fileContent" id="file-content">
<div class="view-md" id="file-html-content" v-html="docHtml"></div>
<div id="note-content" :title="noteContent" class="file-note"></div>
</div>
@@ -207,6 +212,7 @@ import {withLoading} from "@/utils/loading";
import {copyToClip, getGlobalSelectionPosition} from "@/utils";
import {transforMd} from "@/utils/markdown";
import ReadingBox from "@/components/ReadingBox.vue";
import PdfViewer from "@/components/PdfViewer.vue";
import Loading from "@/components/Loading.vue";
import {UploadFilled} from '@element-plus/icons-vue';
import {ElMessage, ElMessageBox, type UploadFile, type UploadFiles} from "element-plus";
@@ -271,6 +277,11 @@ provide('selectedFile', selectedFile);
const docHtml = ref('');
const fileContent = ref(null);
const readingBox = ref(null);
const pdfData = ref<ArrayBuffer | null>(null);
const fileType = computed(() => {
const name = selectedFile.value?.fileName || '';
return name.split('.').pop()?.toLowerCase() || '';
});
// ===================== 笔记 =====================
const fileNote = reactive({ notes: [] as any[] });
@@ -412,7 +423,55 @@ const handleNodeClick = async (data: any) => {
articleParagraph: doc.articleParagraph || '暂无内容,请重试',
fullContent: doc.context
};
await loadFileContent();
// 根据文件类型加载内容
const ext = doc.filename?.split('.').pop()?.toLowerCase() || '';
if (ext === 'pdf') {
await loadPdfFile();
} else {
pdfData.value = null;
await loadFileContent();
}
};
const loadPdfFile = async () => {
if (!selectedFile.value) return;
docHtml.value = '';
try {
const blob = await downloadFile({ fileId: selectedFile.value.fileId });
const arrayBuffer = await (blob as Blob).arrayBuffer();
pdfData.value = arrayBuffer;
} catch (e: any) {
pdfData.value = null;
docHtml.value = '<p style="color:#999;text-align:center;margin-top:40px;">PDF 文件加载失败</p>';
}
// 同时加载 HTML 用于笔记功能(后台)
try {
let res = await getFileContent({
fileId: selectedFile.value.fileId,
embeddingId: selectedFile.value.embeddingId,
knowledgeBaseId: selectedFile.value.folderId
});
if (res?.code === 200 && res.data) {
fileNote.notes = res.data.notes || [];
}
} catch {}
// 绑定 PDF text layer 的选择事件
await nextTick();
setTimeout(() => {
if (fileContent.value) {
fileContent.value.addEventListener('mouseup', (event: MouseEvent) => {
setTimeout(() => {
const sel = window.getSelection(); if (!sel) return;
selectText.value = sel.toString();
if (selectText.value && shortMenuDom.value) {
shortMenuShow.value = true;
(shortMenuDom.value as HTMLElement).style.left = event.clientX + 'px';
(shortMenuDom.value as HTMLElement).style.top = event.clientY + 'px';
}
});
});
}
}, 500);
};
const handleCheckChange = () => {