Przeglądaj źródła

处理docx文档无法预览

yangg 7 miesięcy temu
rodzic
commit
24b3f186bc
38 zmienionych plików z 206 dodań i 47 usunięć
  1. 0 0
      dist/index.html
  2. 0 0
      dist/static/css/app.6152db31.css
  3. 0 0
      dist/static/js/app.3150a46f.js
  4. 0 0
      dist/static/js/app.3a5a5d3d.js
  5. 0 0
      dist/static/js/chunk-0678749f.9716ca6a.js
  6. 0 0
      dist/static/js/chunk-079de15b.66a8c030.js
  7. 0 0
      dist/static/js/chunk-0ec56e2a.0fd33f7a.js
  8. 0 0
      dist/static/js/chunk-10b289e2.535d88e0.js
  9. 0 0
      dist/static/js/chunk-10bfc27e.1e981c2c.js
  10. 0 0
      dist/static/js/chunk-11ff1a32.3852b5ea.js
  11. 0 0
      dist/static/js/chunk-138f7583.959f960c.js
  12. 0 0
      dist/static/js/chunk-2d0d3705.d472fd4e.js
  13. 0 0
      dist/static/js/chunk-35464144.ee717bf0.js
  14. 0 0
      dist/static/js/chunk-36afbef8.de33445d.js
  15. 0 0
      dist/static/js/chunk-3d8a6649.8b5c38c7.js
  16. 0 0
      dist/static/js/chunk-44eee83d.f4a33f22.js
  17. 0 0
      dist/static/js/chunk-4ac7f82e.cad131ec.js
  18. 0 0
      dist/static/js/chunk-4f553f97.bd1b35b8.js
  19. 0 0
      dist/static/js/chunk-52f685c2.565f33ed.js
  20. 0 0
      dist/static/js/chunk-548f9440.f47e066a.js
  21. 0 0
      dist/static/js/chunk-5a3bdf57.fea2fdaa.js
  22. 0 0
      dist/static/js/chunk-5bc2c8fb.7690dd7e.js
  23. 0 0
      dist/static/js/chunk-6711f3a4.ac83e4ef.js
  24. 0 0
      dist/static/js/chunk-683feb49.2d0a946e.js
  25. 0 0
      dist/static/js/chunk-6a80e4ca.0a39a7e4.js
  26. 0 0
      dist/static/js/chunk-6ddf6871.c63064b6.js
  27. 0 0
      dist/static/js/chunk-708604c0.d3dafd10.js
  28. 0 0
      dist/static/js/chunk-7431502d.dabfc9e1.js
  29. 0 0
      dist/static/js/chunk-77e7ad00.9fe9e5c4.js
  30. 0 0
      dist/static/js/chunk-7a88741c.76b0301a.js
  31. 0 0
      dist/static/js/chunk-7f485efb.4e741a97.js
  32. 0 0
      dist/static/js/chunk-9235c1ae.100a27d2.js
  33. 0 0
      dist/static/js/chunk-a577192a.ce6cbb52.js
  34. 0 0
      dist/static/js/chunk-b144ff6a.98dac70f.js
  35. 0 0
      dist/static/js/chunk-d09dbc1a.5bd2494e.js
  36. 0 0
      dist/static/js/chunk-libs.74cd510b.js
  37. 2 1
      package.json
  38. 204 46
      src/components/FilePreview/index.vue

Plik diff jest za duży
+ 0 - 0
dist/index.html


Plik diff jest za duży
+ 0 - 0
dist/static/css/app.6152db31.css


Plik diff jest za duży
+ 0 - 0
dist/static/js/app.3150a46f.js


Plik diff jest za duży
+ 0 - 0
dist/static/js/app.3a5a5d3d.js


+ 0 - 0
dist/static/js/chunk-0678749f.d60a12a9.js → dist/static/js/chunk-0678749f.9716ca6a.js


+ 0 - 0
dist/static/js/chunk-079de15b.e6b30f72.js → dist/static/js/chunk-079de15b.66a8c030.js


+ 0 - 0
dist/static/js/chunk-0ec56e2a.0f2d613f.js → dist/static/js/chunk-0ec56e2a.0fd33f7a.js


+ 0 - 0
dist/static/js/chunk-10b289e2.35f756ba.js → dist/static/js/chunk-10b289e2.535d88e0.js


+ 0 - 0
dist/static/js/chunk-10bfc27e.160fd027.js → dist/static/js/chunk-10bfc27e.1e981c2c.js


+ 0 - 0
dist/static/js/chunk-11ff1a32.d2899384.js → dist/static/js/chunk-11ff1a32.3852b5ea.js


+ 0 - 0
dist/static/js/chunk-138f7583.afc8a722.js → dist/static/js/chunk-138f7583.959f960c.js


+ 0 - 0
dist/static/js/chunk-2d0d3705.705fb721.js → dist/static/js/chunk-2d0d3705.d472fd4e.js


+ 0 - 0
dist/static/js/chunk-35464144.0740381d.js → dist/static/js/chunk-35464144.ee717bf0.js


+ 0 - 0
dist/static/js/chunk-36afbef8.16916b9d.js → dist/static/js/chunk-36afbef8.de33445d.js


+ 0 - 0
dist/static/js/chunk-3d8a6649.e1abeef2.js → dist/static/js/chunk-3d8a6649.8b5c38c7.js


+ 0 - 0
dist/static/js/chunk-44eee83d.2835accc.js → dist/static/js/chunk-44eee83d.f4a33f22.js


+ 0 - 0
dist/static/js/chunk-4ac7f82e.7cf386bf.js → dist/static/js/chunk-4ac7f82e.cad131ec.js


Plik diff jest za duży
+ 0 - 0
dist/static/js/chunk-4f553f97.bd1b35b8.js


+ 0 - 0
dist/static/js/chunk-52f685c2.0707d273.js → dist/static/js/chunk-52f685c2.565f33ed.js


+ 0 - 0
dist/static/js/chunk-548f9440.7c018f8b.js → dist/static/js/chunk-548f9440.f47e066a.js


+ 0 - 0
dist/static/js/chunk-5a3bdf57.961d76c5.js → dist/static/js/chunk-5a3bdf57.fea2fdaa.js


+ 0 - 0
dist/static/js/chunk-5bc2c8fb.8af52844.js → dist/static/js/chunk-5bc2c8fb.7690dd7e.js


+ 0 - 0
dist/static/js/chunk-6711f3a4.efb6e7d1.js → dist/static/js/chunk-6711f3a4.ac83e4ef.js


+ 0 - 0
dist/static/js/chunk-683feb49.8709c304.js → dist/static/js/chunk-683feb49.2d0a946e.js


+ 0 - 0
dist/static/js/chunk-6a80e4ca.5db802a1.js → dist/static/js/chunk-6a80e4ca.0a39a7e4.js


+ 0 - 0
dist/static/js/chunk-6ddf6871.ac73ac06.js → dist/static/js/chunk-6ddf6871.c63064b6.js


+ 0 - 0
dist/static/js/chunk-708604c0.01129860.js → dist/static/js/chunk-708604c0.d3dafd10.js


+ 0 - 0
dist/static/js/chunk-7431502d.a0289a62.js → dist/static/js/chunk-7431502d.dabfc9e1.js


+ 0 - 0
dist/static/js/chunk-77e7ad00.624a586e.js → dist/static/js/chunk-77e7ad00.9fe9e5c4.js


+ 0 - 0
dist/static/js/chunk-7a88741c.ed9e1ae2.js → dist/static/js/chunk-7a88741c.76b0301a.js


+ 0 - 0
dist/static/js/chunk-7f485efb.b2f872ec.js → dist/static/js/chunk-7f485efb.4e741a97.js


+ 0 - 0
dist/static/js/chunk-9235c1ae.9539ac07.js → dist/static/js/chunk-9235c1ae.100a27d2.js


+ 0 - 0
dist/static/js/chunk-a577192a.7933353b.js → dist/static/js/chunk-a577192a.ce6cbb52.js


+ 0 - 0
dist/static/js/chunk-b144ff6a.bcb3a8be.js → dist/static/js/chunk-b144ff6a.98dac70f.js


+ 0 - 0
dist/static/js/chunk-d09dbc1a.8b21f794.js → dist/static/js/chunk-d09dbc1a.5bd2494e.js


Plik diff jest za duży
+ 0 - 0
dist/static/js/chunk-libs.74cd510b.js


+ 2 - 1
package.json

@@ -28,6 +28,7 @@
     "core-js": "3.6.5",
     "cos-js-sdk-v5": "^1.4.22",
     "docx": "^8.5.0",
+    "docx-preview": "^0.3.3",
     "docxtemplater": "^3.46.0",
     "docxtemplater-image-module-free": "^1.1.1",
     "driver.js": "0.9.5",
@@ -47,7 +48,7 @@
     "js-table2excel": "^1.1.2",
     "jsonlint": "1.6.3",
     "jspdf": "^2.5.1",
-    "jszip": "^3.2.1",
+    "jszip": "^3.10.1",
     "jszip-utils": "^0.1.0",
     "lodash-es": "^4.17.21",
     "luckyexcel": "^1.0.1",

+ 204 - 46
src/components/FilePreview/index.vue

@@ -18,14 +18,38 @@
       />
 
       <!-- Word 文档预览 -->
-      <div
+      <div v-if="isWord" class="word-container">
+        <!-- 加载中状态 -->
+        <div v-if="!wordLoaded && !previewError" class="loading-word">
+          <el-progress
+            v-if="loadingProgress > 0"
+            type="circle"
+            :percentage="loadingProgress"
+          ></el-progress>
+          <span v-else>文档加载中...</span>
+        </div>
+
+        <!-- 预览错误状态 -->
+        <div v-else-if="previewError" class="preview-error">
+          <i class="el-icon-warning-outline"></i>
+          <p>{{ errorMessage }}</p>
+          <div class="error-actions">
+            <el-button type="primary" @click="retryPreview">重试</el-button>
+            <el-button @click="downloadFile">下载文件</el-button>
+          </div>
+        </div>
+
+        <!-- 预览内容 -->
+        <div v-else v-html="wordContent" class="word-preview"></div>
+      </div>
+      <!--  <div
         v-if="isWord && wordLoaded"
         v-html="wordContent"
         class="word-preview"
       ></div>
       <div v-else-if="isWord && !wordLoaded" class="loading-word">
         {{ wordLoadingError ? "加载失败,请重试" : "加载中..." }}
-      </div>
+      </div> -->
       <div
         v-if="isExcel"
         id="luckysheet"
@@ -57,6 +81,8 @@ import { searchTaskInfo } from "@/api/knowledge";
 import mammoth from "mammoth";
 // 添加 LuckyExcel 导入
 import LuckyExcel from "luckyexcel";
+import { saveAs } from "file-saver";
+import JSZip from "jszip";
 export default {
   props: {
     fileUrl: {
@@ -93,6 +119,13 @@ export default {
       wordLoaded: false,
       wordLoadingError: false,
       internalFileUrl: "", // 新增:内部使用的 URL
+
+      loadingProgress: 0,
+      wordContent: "",
+      wordLoaded: false,
+      previewError: false,
+      errorMessage: "",
+      docData: null, // 保存文档数据用于下载
     };
   },
   watch: {
@@ -100,13 +133,25 @@ export default {
       immediate: true,
       handler(newValue) {
         /* this.internalFileUrl = newValue; */
-        /* if (this.isWord) {
+        if (this.isWord) {
           this.loadWordContent();
-        } */
+        }
       },
     },
   },
   computed: {
+    officePreviewUrl() {
+      // 添加此计算属性
+      if (this.isOffice) {
+        // 使用微软Office Online Viewer
+        return `https://view.officeapps.live.com/op/embed.aspx?src=${encodeURIComponent(
+          this.fileUrl
+        )}`;
+        // 或者使用Google Docs Viewer
+        // return `https://docs.google.com/gview?url=${encodeURIComponent(this.fileUrl)}&embedded=true`;
+      }
+      return "";
+    },
     isSupported() {
       return this.supportedTypes.includes(this.fileType);
     },
@@ -114,7 +159,7 @@ export default {
       return ["jpg", "jpeg", "png", "gif"].includes(this.fileType);
     },
     isWord() {
-      return ["doc", "docx"].includes(this.fileType);
+      return ["doc", "docx"].includes(this.fileType) || this.type === "doc";
     },
     isExcel() {
       return ["xls", "xlsx"].includes(this.fileType);
@@ -124,58 +169,131 @@ export default {
     },
   },
   mounted() {
-    console.log(this.isExcel);
+    console.log(this.isWord);
     if (this.fileType === "txt") {
       this.loadTextContent();
     } else if (this.isWord) {
       this.loadWordContent();
-    } else if (this.$route.query.type=='xlsx') {
+    } else if (this.$route.query.type == "xlsx") {
       this.loadExcelContent();
     }
   },
   methods: {
     async loadWordContent() {
       this.wordLoaded = false;
-      this.wordLoadingError = false;
-      try {
-        // 获取文档 URL
-        /* if (this.type !== "ai") { */
-          const res = await searchTaskInfo({
-            page: 1,
-            page_size: 10,
-            document_id: this.$route.query.id,
-          });
-          this.internalFileUrl = res.data.documentUrl;
-      /*   } else {
-          this.internalFileUrl = localStorage.getItem("href");
-        } */
+      this.loadingProgress = 0;
+      this.previewError = false;
+      this.errorMessage = "";
 
-        // 使用 fetch 获取文件内容,指定 responseType 为 'arraybuffer'
-        const response = await fetch(this.internalFileUrl, {
-          method: "GET",
-          headers: {
-            "Content-Type":
-              "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
-          },
+      try {
+        // 获取文档URL
+        const res = await searchTaskInfo({
+          page: 1,
+          page_size: 10,
+          document_id: this.$route.query.id,
         });
 
-        if (!response.ok) {
-          throw new Error(`HTTP error! status: ${response.status}`);
+        const docUrl = res.data.documentUrl;
+
+        // 下载文件并显示进度
+        const response = await fetch(docUrl);
+        const reader = response.body.getReader();
+        const contentLength = +response.headers.get("Content-Length");
+
+        let receivedLength = 0;
+        let chunks = [];
+
+        while (true) {
+          const { done, value } = await reader.read();
+
+          if (done) break;
+
+          chunks.push(value);
+          receivedLength += value.length;
+
+          this.loadingProgress = Math.round(
+            (receivedLength / contentLength) * 100
+          );
         }
 
-        const arrayBuffer = await response.arrayBuffer();
-        const result = await mammoth.convertToHtml({ arrayBuffer });
-        this.wordContent = result.value;
-        this.wordLoaded = true;
+        // 合并数据
+        this.docData = new Uint8Array(receivedLength);
+        let position = 0;
+        for (let chunk of chunks) {
+          this.docData.set(chunk, position);
+          position += chunk.length;
+        }
+
+        // 处理不同的文档格式
+        if (this.fileType === "doc") {
+          try {
+            const result = await mammoth.convertToHtml({
+              arrayBuffer: this.docData.buffer,
+            });
+            this.wordContent = this.enhanceWordContent(result.value);
+            this.wordLoaded = true;
+          } catch (error) {
+            throw new Error("无法预览该文档,可能是格式不兼容或文件已损坏");
+          }
+        } else if (this.fileType === "docx") {
+          const result = await mammoth.convertToHtml({
+            arrayBuffer: this.docData.buffer,
+          });
+          this.wordContent = this.enhanceWordContent(result.value);
+          this.wordLoaded = true;
+        }
       } catch (error) {
-        console.error("加载Word文档内容时出错:", error);
-        this.wordContent = `无法加载Word文档内容: ${error.message}`;
-        this.wordLoadingError = true;
-        this.$message.error(`文档加载失败: ${error.message}`);
-      } finally {
-        this.wordLoaded = true;
+        console.error("文档加载失败:", error);
+        this.previewError = true;
+        this.errorMessage = error.message || "文档加载失败,请重试或下载查看";
       }
     },
+
+    // 重试预览
+    retryPreview() {
+      this.loadWordContent();
+    },
+
+    // 下载文件
+    downloadFile() {
+      if (this.docData) {
+        const blob = new Blob([this.docData], {
+          type:
+            this.fileType === "doc"
+              ? "application/msword"
+              : "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
+        });
+        saveAs(blob, `document.${this.fileType}`);
+      } else {
+        this.$message.error("文件数据不存在,请重试");
+      }
+    },
+
+    // 增强文档内容显示
+    enhanceWordContent(content) {
+      return `
+        <div class="enhanced-word-content">
+          <style>
+            .enhanced-word-content {
+              font-family: "Microsoft YaHei", Arial, sans-serif;
+              line-height: 1.6;
+              color: #333;
+              padding: 20px;
+            }
+            .enhanced-word-content h1 { font-size: 24px; margin: 20px 0; }
+            .enhanced-word-content h2 { font-size: 20px; margin: 16px 0; }
+            .enhanced-word-content p { margin: 12px 0; }
+            .enhanced-word-content img { max-width: 100%; height: auto; }
+            .enhanced-word-content table { border-collapse: collapse; width: 100%; }
+            .enhanced-word-content td, .enhanced-word-content th { 
+              border: 1px solid #ddd; 
+              padding: 8px; 
+            }
+          </style>
+          ${content}
+        </div>
+      `;
+    },
     blobToArrayBuffer(blob) {
       return new Promise((resolve, reject) => {
         const reader = new FileReader();
@@ -187,13 +305,13 @@ export default {
     async loadTextContent() {
       try {
         // 获取文档 URL
-     /*    if (this.type !== "ai") { */
-          const res = await searchTaskInfo({
-            page: 1,
-            page_size: 10,
-            document_id: this.$route.query.id,
-          });
-          this.internalFileUrl = res.data.documentUrl;
+        /*    if (this.type !== "ai") { */
+        const res = await searchTaskInfo({
+          page: 1,
+          page_size: 10,
+          document_id: this.$route.query.id,
+        });
+        this.internalFileUrl = res.data.documentUrl;
         /* } else {
           this.internalFileUrl = localStorage.getItem("href");
         } */
@@ -283,4 +401,44 @@ export default {
   font-size: 18px;
   color: #909399;
 }
+.preview-error {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  height: 400px;
+  color: #909399;
+  text-align: center;
+}
+
+.preview-error i {
+  font-size: 48px;
+  color: #f56c6c;
+  margin-bottom: 20px;
+}
+
+.preview-error p {
+  font-size: 16px;
+  margin-bottom: 20px;
+}
+
+.error-actions {
+  display: flex;
+  gap: 12px;
+}
+
+.loading-word {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  height: 400px;
+  gap: 16px;
+}
+
+.word-preview {
+  overflow-y: auto;
+  max-height: 830px;
+  padding: 20px;
+}
 </style>

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików