From 27b9c5c1fc914215970d2f580f92b9d0da72aed5 Mon Sep 17 00:00:00 2001 From: Wangxin Date: Fri, 14 Nov 2025 21:15:58 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90web=E3=80=91=20=E9=A2=84=E8=A7=88?= =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ALOps_sys_fe/alops-ui/package.json | 1 + .../src/views/QandA/knowledge/index.vue | 435 +++++++++++++++--- 2 files changed, 383 insertions(+), 53 deletions(-) diff --git a/ALOps_sys_fe/alops-ui/package.json b/ALOps_sys_fe/alops-ui/package.json index 76fbb0c0..40956663 100644 --- a/ALOps_sys_fe/alops-ui/package.json +++ b/ALOps_sys_fe/alops-ui/package.json @@ -39,6 +39,7 @@ "js-cookie": "3.0.1", "jsencrypt": "3.0.0-rc.1", "lodash": "^4.17.21", + "mammoth": "^1.11.0", "nprogress": "0.2.0", "quill": "2.0.2", "screenfull": "5.0.2", diff --git a/ALOps_sys_fe/alops-ui/src/views/QandA/knowledge/index.vue b/ALOps_sys_fe/alops-ui/src/views/QandA/knowledge/index.vue index c4d14133..be963918 100644 --- a/ALOps_sys_fe/alops-ui/src/views/QandA/knowledge/index.vue +++ b/ALOps_sys_fe/alops-ui/src/views/QandA/knowledge/index.vue @@ -90,6 +90,7 @@ import Treeselect from "@riophae/vue-treeselect" import "@riophae/vue-treeselect/dist/vue-treeselect.css" import { Splitpanes, Pane } from "splitpanes" import "splitpanes/dist/splitpanes.css" +import mammoth from 'mammoth' export default { name: "User", @@ -384,74 +385,402 @@ export default { this.$refs.upload.submit() }, // 预览文件 - 基于二进制数据的预览 - previewFile(row) { + async previewFile(row) { // 获取token const token = this.$store.getters.token; // 构建下载URL(与下载使用相同的接口) const previewUrl = `${this.appBase}/QandA/knowledge/file/download/${row.id}`; - // 创建XMLHttpRequest对象 - const xhr = new XMLHttpRequest(); - xhr.open('GET', previewUrl, true); - - // 设置请求头 - xhr.setRequestHeader('Authorization', `Bearer ${token}`); - - // 根据文件类型设置响应类型 - if (row.format === 'txt') { - xhr.responseType = 'text'; // 文本文件直接获取文本内容 - } else if (['png', 'jpg', 'jpeg', 'gif', 'bmp'].includes(row.format.toLowerCase())) { - xhr.responseType = 'blob'; // 图片文件获取Blob对象 - } else if (row.format === 'pdf') { - xhr.responseType = 'blob'; // PDF文件获取Blob对象 - } else { - // 其他格式,先尝试获取文本,不行再提示 - xhr.responseType = 'text'; - } - - // 请求完成处理函数 - xhr.onload = function() { - if (xhr.status === 200) { + // 将XMLHttpRequest包装成Promise + const getFileContent = () => { + return new Promise((resolve, reject) => { + // 创建XMLHttpRequest对象 + const xhr = new XMLHttpRequest(); + xhr.open('GET', previewUrl, true); + + // 设置请求头 + xhr.setRequestHeader('Authorization', `Bearer ${token}`); + + // 根据文件类型设置响应类型 if (row.format === 'txt') { - // 文本文件预览 - this.previewTextFile(xhr.response, row.source); + xhr.responseType = 'text'; // 文本文件直接获取文本内容 } else if (['png', 'jpg', 'jpeg', 'gif', 'bmp'].includes(row.format.toLowerCase())) { - // 图片文件预览 - this.previewImageFile(xhr.response, row.source); + xhr.responseType = 'blob'; // 图片文件获取Blob对象 } else if (row.format === 'pdf') { - // PDF文件预览 - this.previewPdfFile(xhr.response, row.source); + xhr.responseType = 'blob'; // PDF文件获取Blob对象 } else if (row.format === 'docx') { - // Word文件预览 - 使用在线预览服务 - const docxUrl = URL.createObjectURL(new Blob([xhr.response])); - const onlinePreviewUrl = `https://view.officeapps.live.com/op/view.aspx?src=${encodeURIComponent(docxUrl)}`; - window.open(onlinePreviewUrl, '_blank'); + xhr.responseType = 'arraybuffer'; // Word文件获取ArrayBuffer对象 } else { - // 尝试文本预览 - try { - const textContent = xhr.response; - if (textContent && textContent.length > 0) { - this.previewTextFile(textContent, row.source); - } else { - this.$message.info('暂不支持此文件格式的预览'); - } - } catch (e) { - this.$message.info('暂不支持此文件格式的预览'); + // 其他格式,先尝试获取文本,不行再提示 + xhr.responseType = 'text'; + } + + // 请求完成处理函数 + xhr.onload = function() { + if (xhr.status === 200) { + resolve(xhr.response); + } else { + reject(new Error('文件获取失败,状态码: ' + xhr.status)); } + }; + + // 网络错误处理 + xhr.onerror = function() { + reject(new Error('网络错误,文件获取失败')); + }; + + // 发送请求 + xhr.send(); + }); + }; + + try { + const response = await getFileContent(); + + if (row.format === 'txt') { + // 文本文件预览 - 使用与Word类似的HTML界面 + const blob = new Blob([response], { type: 'text/plain;charset=utf-8' }); + const txtUrl = URL.createObjectURL(blob); + + // 创建预览窗口,使用与Word预览类似的界面样式 + const previewWindow = window.open('', '_blank', 'width=1000,height=800'); + previewWindow.document.write(` + + + + + + 文件预览 - ${row.source} + + + +
+

文件预览

+
+

文件名:${row.source}

+

文件格式:TXT (纯文本文件)

+
+
+ ${response.replace(//g, '>')} +
+ 下载原始文件 +
+ + + `); + previewWindow.document.close(); + + // 当新窗口关闭时释放URL对象 + previewWindow.addEventListener('beforeunload', () => { + URL.revokeObjectURL(txtUrl); + }); + } else if (['png', 'jpg', 'jpeg', 'gif', 'bmp'].includes(row.format.toLowerCase())) { + // 图片文件预览 + this.previewImageFile(response, row.source); + } else if (row.format === 'pdf') { + // PDF文件预览 + this.previewPdfFile(response, row.source); + } else if (row.format === 'docx') { + // Word文件预览 - 使用mammoth.js将Word转换为HTML直接在浏览器中预览 + + // 检查响应数据是否完整 + if (!response || response.byteLength < 100) { + console.error('Word文档数据不完整'); + this.$message.error('Word文档数据不完整,请尝试下载查看'); + return; + } + + try { + // 使用mammoth.js转换Word文档为HTML + const result = await mammoth.convertToHtml({ arrayBuffer: response }); + const htmlContent = result.value; + + const blob = new Blob([response], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' }); + const docxUrl = URL.createObjectURL(blob); + + // 创建预览窗口 + const previewWindow = window.open('', '_blank', 'width=1000,height=800'); + previewWindow.document.write(` + + + + + + 文件预览 - ${row.source} + + + +
+

文件预览

+
+

文件名:${row.source}

+

文件格式:DOCX (Word文档)

+
+
+ ${htmlContent} +
+ 下载原始文件 +

注意:预览可能与原始文件格式略有差异,完整格式请下载原始文件查看。

+
+ + + `); + previewWindow.document.close(); + + // 当新窗口关闭时释放URL对象 + previewWindow.addEventListener('beforeunload', () => { + URL.revokeObjectURL(docxUrl); + }); + } catch (err) { + console.error('Word文档转换失败:', err); + + const blob = new Blob([response], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' }); + const docxUrl = URL.createObjectURL(blob); + + // 创建带有错误提示的预览窗口 + const errorWindow = window.open('', '_blank', 'width=800,height=600'); + errorWindow.document.write(` + + + + + + 文件预览 - ${row.source} + + + +
+

文件预览

+
+

文件名:${row.source}

+

文件格式:DOCX (Word文档)

+
+
+

抱歉,Word文档预览失败。可能的原因:

+
    +
  • 文档文件损坏或不完整
  • +
  • 文档格式不受支持
  • +
  • 浏览器内存不足
  • +
+
+ 下载原始文件查看 +
+ + + `); + errorWindow.document.close(); + + // 当新窗口关闭时释放URL对象 + errorWindow.addEventListener('beforeunload', () => { + URL.revokeObjectURL(docxUrl); + }); } } else { - this.$message.error('文件预览失败,请重试'); + // 尝试文本预览 + try { + const textContent = response; + if (textContent && textContent.length > 0) { + this.previewTextFile(textContent, row.source); + } else { + this.$message.info('暂不支持此文件格式的预览'); + } + } catch (e) { + this.$message.info('暂不支持此文件格式的预览'); + } } - }.bind(this); - - // 网络错误处理 - xhr.onerror = function() { - this.$message.error('网络错误,文件预览失败'); - }.bind(this); - - // 发送请求 - xhr.send(); + } catch (error) { + console.error('文件预览失败:', error); + this.$message.error('文件预览失败: ' + error.message); + } }, // 预览文本文件