Kaynağa Gözat

附件预览调整测试

qymljy 6 ay önce
ebeveyn
işleme
661dee02a4

Dosya farkı çok büyük olduğundan ihmal edildi
+ 703 - 58
package-lock.json


+ 3 - 1
package.json

@@ -24,13 +24,14 @@
     "dom-to-image": "^2.6.0",
     "element-ui": "^2.15.6",
     "file-saver": "^2.0.5",
+    "howler.js": "^2.1.2",
     "increase-memory-limit": "^1.0.7",
     "js-md5": "^0.7.3",
     "less-loader": "^11.1.0",
     "mammoth": "^1.11.0",
     "moment": "^2.29.4",
     "nprogress": "^0.2.0",
-    "pdfjs-dist": "^5.4.296",
+    "pdfjs-dist": "^2.11.338",
     "print-js": "^1.6.0",
     "qrcodejs2": "^0.0.2",
     "sass-loader": "^16.0.2",
@@ -42,6 +43,7 @@
     "vue-countupjs": "^1.0.0",
     "vue-i18n": "^8.27.0",
     "vue-image-viewer": "^1.1.8",
+    "vue-pdf": "^4.2.0",
     "vue-qr": "^4.0.9",
     "vue-router": "^3.5.1",
     "vuex": "^3.6.2",

+ 1 - 2
src/components/attachment_list/index.vue

@@ -81,7 +81,6 @@
 
 <script>
 import SeeFile from "@/components/file-block/components/SeeFile1";
-import previewFile from '@/components/preview_file/index'
 export default {
   props: ["attinfos", "onlyread", "status","attachmentDisabled","disabled","minWidth","issalehr"],
   data() {
@@ -91,7 +90,7 @@ export default {
       isSeeFileShow: false,
     };
   },
-  components: { SeeFile,previewFile },
+  components: { SeeFile },
   methods: {
     refresh() {
       this.$emit("cancelEdit");

+ 157 - 0
src/components/attachment_list/index1.vue

@@ -0,0 +1,157 @@
+<template>
+  <div>
+    <div class="flex-align-center flex-between normal-margin">
+      <div v-if="$slots.title">
+        <slot name="title"></slot>
+      </div>
+      <!-- <p v-else>附件列表</p> -->
+      <slot v-if="!onlyread" name="upload"></slot>
+    </div>
+    <el-table
+      :header-cell-style="{background:'#EEEEEE',color:'#333'}"
+      size="mini"
+      border
+      :data="attinfos"
+      style="width: 100%"
+    >
+      <el-table-column prop="document" :label="$t(`文件名称`)"  min-width="170">
+        <template slot-scope="scope">
+          <el-input
+            v-if="actid === scope.row.attachmentid"
+            size="mini"
+            v-model="scope.row.document"
+          ></el-input>
+          <span v-else>{{scope.row.document}}</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="createdate" :label="$t(`上传时间`)" min-width="136"></el-table-column>
+      <el-table-column prop="contentlength" :label="$t(`文件大小`)" min-width="69">
+        <template
+          slot-scope="scope"
+        >{{scope.row.contentlength > 1073741824?(scope.row.contentlength / Math.pow(1024,3)).toFixed(2)+'GB':scope.row.contentlength > 1048576?(scope.row.contentlength / Math.pow(1024,2)).toFixed(2)+'MB':scope.row.contentlength > 1024?(scope.row.contentlength / Math.pow(1024,1)).toFixed(2)+'KB':scope.row.contentlength+'B'}}</template>
+      </el-table-column>
+      <el-table-column :label="$t(`操作`)" :min-width="minWidth?minWidth:170">
+        <template slot-scope="scope">
+          <div v-if="actid === scope.row.attachmentid">
+            <el-button
+              type="text"
+              size="small"
+              @click="saveEdit(scope.row)"
+              :disabled="status === '已失败' || status === '已结案' || attachmentDisabled"
+            >{{$t(`保 存`)}}</el-button>
+            <el-button
+              type="text"
+              size="small"
+              @click="refresh(actid = 0)"
+              :disabled="status === '已失败' || status === '已结案' || attachmentDisabled"
+            >{{$t(`取 消`)}}</el-button>
+          </div>
+          <div v-else>
+            <el-button
+              type="text"
+              size="small"
+              @click="download(scope.row)"
+              :disabled="status === '已失败' || status === '已结案'"
+            >{{$t(`下 载`)}}</el-button>
+            <el-button type="text" size="small" @click="seeClick(scope.row)">{{$t(`预 览`)}}</el-button>
+            <el-button
+              :disabled="onlyread || status === '已失败' || status === '已结案' || attachmentDisabled || disabled"
+              v-if="!onlyread && status !== '已失败' && status !== '已结案' && !attachmentDisabled"
+              class="inline-16"
+              type="text"
+              size="small"
+              @click="editAttachment(scope.row)"
+            >{{$t(`编 辑`)}}</el-button>
+            <el-popconfirm :title="$t(`确定删除当前附件吗`)+'?'" :confirm-button-text="$t('确定')" :cancel-button-text="$t('取消')" @confirm="deleteAttachment(scope.row)">
+              <el-button
+                :disabled="onlyread || status === '已失败' || status === '已结案' ||  attachmentDisabled || disabled || ($route.path == '/serveBillDetail' && status != '新建') || ($route.path == '/serveBillMagDetail' && status != '新建') || issalehr"
+                v-if="!onlyread && status !== '已失败' && status !== '已结案'  && !attachmentDisabled"
+                slot="reference"
+                size="small"
+                type="text"
+              >{{$t(`删 除`)}}</el-button>
+            </el-popconfirm>
+          </div>
+        </template>
+      </el-table-column>
+    </el-table>
+    <filePreviewer ref="previewerRef" :fileUrl="fileUrl" :fileName="fileName"></filePreviewer>
+  </div>
+</template>
+
+<script>
+import filePreviewer from '@/components/preview/index'
+export default {
+  props: ["attinfos", "onlyread", "status","attachmentDisabled","disabled","minWidth","issalehr"],
+  data() {
+    return {
+      actid: null,
+      seeFile: "",
+      isSeeFileShow: false,
+      fileUrl:'',
+      fileName:''
+    };
+  },
+  components: { filePreviewer },
+  methods: {
+    refresh() {
+      this.$emit("cancelEdit");
+    },
+    editAttachment(row) {
+      this.actid = row.attachmentid;
+    },
+    download(row) {
+      window.open(row.url);
+      this.downloadRecord(row);
+    },
+    /*保存下载操作记录*/
+    async downloadRecord(row) {
+      const res = await this.$api.requested({
+        id: 10020701,
+        content: {
+          linksid: row.linksid,
+          attachmentid: row.attachmentid,
+        },
+      });
+    },
+    async saveEdit(row) {
+      let param = {
+        classname: "system.attachment.MediaCenter",
+        method: "changeAttachment",
+        content: {
+          files: [
+            {
+              attachmentid: row.attachmentid,
+              document: row.document,
+              parentid: row.parentid,
+            },
+          ],
+        },
+      };
+      const res = await this.$api.requested(param);
+      res.code === 1 ? this.$emit("onSuccess") : "";
+      res.code === 1 ? (this.actid = "") : "";
+    },
+
+    async deleteAttachment(row) {
+      const res = await this.$api.requested({
+        classname: "system.attachment.Attachment",
+        method: "deleteFileLink",
+        content: {
+          linksids: [row.linksid],
+        },
+      });
+      res.code === 1 ? this.tool.showMessage(res) : "";
+      res.code === 1 ? this.$emit("onSuccess") : "";
+    },
+    seeClick(item) {
+      console.log(item);
+      this.fileUrl = item.url
+      this.fileName = item.document
+      this.$refs.previewerRef.dialogVisible = true
+    },
+  },
+};
+</script>
+<style>
+</style>

+ 1 - 1
src/components/normal-basic-layout/details/modules/tabs/tab.vue

@@ -29,7 +29,7 @@
 </template>
 
 <script>
-import attachmentList from '@/components/attachment_list/index.vue'
+import attachmentList from '@/components/attachment_list/index1.vue'
 import upload from '@/components/upload/hw_obs_upload.vue'
 import datalog from '../datalog/index.vue'
 import followTable from '../followTable/index'

+ 16 - 0
src/components/preview/audioPlayer.vue

@@ -0,0 +1,16 @@
+<template>
+  <div class="audio-player">
+    <audio controls :src="src"></audio>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "audioPlayer",
+  props: ['src']
+}
+</script>
+
+<style scoped>
+
+</style>

+ 36 - 0
src/components/preview/excelViewer.vue

@@ -0,0 +1,36 @@
+<template>
+  <div class="excel-container">
+    <table border="1" cellspacing="0">
+      <tr v-for="(row, i) in tableData" :key="i">
+        <td v-for="cell in row">{{ cell }}</td>
+      </tr>
+    </table>
+  </div>
+</template>
+
+<script>
+import * as XLSX from 'xlsx';
+export default {
+  name: "excelViewer",
+  props: ['src'],
+  data() {
+    return { tableData: [] };
+  },
+  async created() {
+    try {
+      const response = await fetch(this.src);
+      const arrayBuffer = await response.arrayBuffer();
+      const workbook = XLSX.read(arrayBuffer);
+      const sheetName = workbook.SheetNames[0];
+      const sheet = workbook.Sheets[sheetName];
+      this.tableData = XLSX.utils.sheet_to_json(sheet);
+    } catch (error) {
+      console.error('解析Excel失败:', error);
+    }
+  }
+}
+</script>
+
+<style scoped>
+
+</style>

+ 16 - 0
src/components/preview/imageViewer.vue

@@ -0,0 +1,16 @@
+<template>
+  <div class="image-viewer">
+    <img :src="src" alt="预览图片" style="max-width:100%;">
+  </div>
+</template>
+
+<script>
+export default {
+  name: "imageViewer",
+  props: ['src']
+}
+</script>
+
+<style scoped>
+
+</style>

+ 113 - 0
src/components/preview/index.vue

@@ -0,0 +1,113 @@
+<template>
+  <el-dialog
+      append-to-body
+      :title="$t(`预览`)"
+      :visible.sync="dialogVisible"
+      :before-close="handleClose"
+  >
+    <div class="file-previewer">
+      <!-- 根据文件类型显示不同预览组件 -->
+      <pdfViewer v-if="isPdf" :src="fileUrl" :pageNum="1"></pdfViewer>
+      <wordViewer v-else-if="isWord" :src="fileUrl"></wordViewer>
+      <excelViewer v-else-if="isExcel" :src="fileUrl"></excelViewer>
+      <textViewer v-else-if="isText" :src="fileUrl"></textViewer>
+      <audioPlayer v-else-if="isAudio" :src="fileUrl"></audioPlayer>
+      <videoPlayer v-else-if="isVideo" :src="fileUrl"></videoPlayer>
+      <imageViewer v-else-if="isImage" :src="fileUrl"></imageViewer>
+      <div v-else class="unsupported">
+        ⚠️ 当前浏览器不支持预览此类型文件 ({{ fileType }})
+        <a :href="fileUrl" download>点击下载</a>
+      </div>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+import pdfViewer from './pdfViewer.vue';
+import wordViewer from './wordViewer.vue';
+import excelViewer from './excelViewer.vue';
+import textViewer from './textViewer.vue';
+import audioPlayer from './audioPlayer.vue';
+import videoPlayer from './videoPlayer.vue';
+import imageViewer from './imageViewer.vue';
+export default {
+  name: "index",
+  data() {
+    return {
+      dialogVisible:false
+    }
+  },
+  components:{
+    pdfViewer,
+    wordViewer,
+    excelViewer,
+    textViewer,
+    audioPlayer,
+    videoPlayer,
+    imageViewer
+  },
+  props: {
+    fileUrl: { type: String, required: true },      // 文件访问URL
+    fileName: { type: String, required: true }     // 原始文件名用于判断类型
+  },
+  computed: {
+    // 提取文件扩展名并转为小写
+    fileExt() {
+      return this.fileName.split('.').pop().toLowerCase();
+    },
+    // 判断是否为PDF
+    isPdf() { return this.fileExt === 'pdf'; },
+    // 判断是否为Word文档
+    isWord() { return ['doc', 'docx'].includes(this.fileExt); },
+    // 判断是否为Excel表格
+    isExcel() { return ['xls', 'xlsx'].includes(this.fileExt); },
+    // 判断是否为纯文本
+    isText() { return this.fileExt === 'txt'; },
+    // 判断是否为音频文件
+    isAudio() { return this.fileExt === 'mp3'; },
+    // 判断是否为视频文件
+    isVideo() { return this.fileExt === 'mp4'; },
+    // 判断是否为图片
+    isImage() { return ['png', 'jpg', 'gif'].includes(this.fileExt); },
+    // 获取友好的文件类型名称
+    fileType() {
+      const types = {
+        pdf: 'PDF文档',
+        doc: 'Word文档', docx: 'Word文档',
+        xls: 'Excel表格', xlsx: 'Excel表格',
+        txt: '文本文件',
+        mp3: '音频文件',
+        mp4: '视频文件',
+        png: 'PNG图片', jpg: 'JPG图片', gif: 'GIF动图'
+      };
+      return types[this.fileExt] || `未知格式(${this.fileExt})`;
+    }
+  },
+  methods:{
+    handleClose() {
+      this.dialogVisible = false;
+    },
+  }
+}
+</script>
+
+<style scoped>
+.file-previewer {
+  max-width: 800px;
+  margin: 0 auto;
+  border: 1px solid #eee;
+  padding: 20px;
+}
+.unsupported {
+  text-align: center;
+  color: #666;
+  padding: 50px 0;
+}
+a {
+  color: #409EFF;
+  text-decoration: none;
+}
+a:hover {
+  text-decoration: underline;
+}
+</style>

+ 45 - 0
src/components/preview/mediaPlayer.vue

@@ -0,0 +1,45 @@
+<template>
+  <div class="media-wrapper">
+    <!-- 音频模式 -->
+    <audio v-if="isAudio" ref="player" :src="src"></audio>
+
+    <!-- 视频模式 -->
+    <video v-else ref="player" :src="src" controls></video>
+
+    <div class="controls">
+      <button @click="playPause">{{ playing ? '⏸' : '▶️' }}</button>
+      <progress :value="progress" max="100"></progress>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "mediaPlayer",
+  props: ['src'],
+  data() {
+    return {
+      isAudio: this.src.endsWith('.mp3'),
+      playing: false,
+      progress: 0
+    };
+  },
+  methods: {
+    playPause() {
+      const el = this.$refs.player;
+      if (el) {
+        this.playing ? el.pause() : el.play();
+        this.playing = !this.playing;
+      }
+    },
+    updateProgress() { /* 实时更新进度条逻辑 */ }
+  },
+  mounted() {
+    this.$refs.player?.addEventListener('timeupdate', this.updateProgress);
+  }
+}
+</script>
+
+<style scoped>
+
+</style>

+ 137 - 0
src/components/preview/pdfViewer.vue

@@ -0,0 +1,137 @@
+<template>
+  <div class="pdf-container">
+    <canvas ref="pdfCanvas"></canvas>
+    <p v-if="errorMsg" class="error">{{ errorMsg }}</p>
+    <div v-if="loading" class="loader">加载中...</div>
+  </div>
+</template>
+
+<script>
+import { getDocument } from 'pdfjs-dist/build/pdf'; // 用于加载文档
+import * as pdfjsLib from 'pdfjs-dist/web/pdf_viewer'; // 获取全局配置接口
+export default {
+  name: "pdfViewer",
+  // props: {
+  //   src: { type: String, required: true }, // PDF文件URL或Base64数据
+  //   pageNum: { type: Number, default: 1 } // 可选参数:指定显示哪一页
+  // },
+  props:['src','pageNum'],
+  data() {
+    return {
+      pdfDoc: null,
+      loading: true,
+      errorMsg: null
+    };
+  },
+  async mounted() {
+    try {
+      // ✅ 关键步骤:动态加载 Worker 脚本并设置路径
+      const workerBundle = await import('pdfjs-dist/build/pdf.worker.entry');
+      pdfjsLib.GlobalWorkerOptions.workerSrc = workerBundle.default;
+
+      // 可选:配置中文字体支持(解决乱码问题)
+      pdfjsLib.GlobalWorkerOptions.cMapUrl = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.11.338/cmaps/';
+      pdfjsLib.GlobalWorkerOptions.cMapPacked = true;
+
+      // 发起文档加载请求
+      console.log(this.src,'src浏览的地址内容')
+      const docPromise = getDocument({ url: this.src, withCredentials: true });
+      this.pdfDoc = await docPromise.promise;
+      await this.renderPage(this.pageNum); // 触发渲染
+      this.loading = false;
+    } catch (err) {
+      console.error("PDF初始化失败:", err);
+      this.errorMsg = `无法加载PDF文件 (${err.message})`;
+      this.loading = false;
+    }
+  },
+  methods:{
+    async loadNewDocument(newSrc) { // 新增的核心方法!
+      console.log(newSrc,'newSrc')
+      try {
+        this.loading = true;
+        this.errorMsg = null;
+        const docPromise = getDocument({ url: newSrc, withCredentials: true });
+        this.pdfDoc = await docPromise.promise;
+        await this.renderPage(this.pageNum);
+        this.loading = false;
+      } catch (err) {
+        console.error("新文档加载失败:", err);
+        this.errorMsg = `无法加载新PDF文件 (${err.message})`;
+        this.loading = false;
+      }
+    },
+    async renderPage(pageNumber) {
+      if (!this.pdfDoc) return;
+
+      try {
+        const page = await this.pdfDoc.getPage(pageNumber);
+        const canvas = this.$refs.pdfCanvas;
+        const context = canvas.getContext('2d');
+
+        // 动态计算最佳缩放比例以适应容器
+        const scaleFactor = Math.min(
+            this.$el.clientWidth / page.view[2],
+            this.$el.clientHeight / page.view[3]
+        );
+        const viewport = page.getViewport({ scale: scaleFactor });
+
+        // 更新画布尺寸并清除旧内容
+        canvas.width = viewport.width;
+        canvas.height = viewport.height;
+        context.clearRect(0, 0, canvas.width, canvas.height);
+
+        // 执行实际渲染操作
+        await page.render({
+          canvasContext: context,
+          viewport: viewport,
+          intent: 'display' // 确保高质量输出
+        }).promise;
+      } catch (err) {
+        console.error(`第${pageNumber}页渲染失败`, err);
+        this.errorMsg = `页面 ${pageNumber} 渲染出错`;
+      }
+    }
+  },
+  watch: {
+    src: {
+      handler: function(newVal) {
+        if (!newVal) return;
+        this.loading = true;
+        this.errorMsg = null;
+        this.loadNewDocument(newVal);
+      },
+      immediate: true
+    }
+  },
+  beforeDestroy() {
+    // 清理Worker防止内存泄漏
+    if (pdfjsLib.GlobalWorkerOptions.worker) {
+      pdfjsLib.GlobalWorkerOptions.worker.terminate();
+    }
+  }
+}
+</script>
+
+<style scoped>
+.pdf-container {
+  position: relative;
+  width: 100%;
+  max-height: 80vh; /* 限制最大可视高度 */
+  border: 1px solid #eee;
+}
+canvas {
+  display: block;
+  margin: auto; /* 居中显示 */
+  box-shadow: 0 2px 10px rgba(0,0,0,0.1);
+}
+.error {
+  color: red;
+  text-align: center;
+  padding: 1rem;
+}
+.loader {
+  text-align: center;
+  padding: 2rem;
+}
+</style>

+ 0 - 0
src/components/preview/pdf_viewer.vue


+ 28 - 0
src/components/preview/textViewer.vue

@@ -0,0 +1,28 @@
+<template>
+  <pre class="text-content">{{ content }}</pre>
+</template>
+
+<script>
+export default {
+  name: "textViewer",
+  props: ['src'],
+  data() {
+    return { content: '' };
+  },
+  async created() {
+    try {
+      const response = await fetch(this.src);
+      this.content = await response.text();
+    } catch (error) {
+      console.error('加载文本失败:', error);
+    }
+  }
+}
+</script>
+
+<style scoped>
+.text-content {
+  white-space: pre-wrap;
+  word-break: break-all;
+}
+</style>

+ 16 - 0
src/components/preview/videoPlayer.vue

@@ -0,0 +1,16 @@
+<template>
+  <div class="video-player">
+    <video controls :src="src"></video>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "videoPlayer",
+  props: ['src']
+}
+</script>
+
+<style scoped>
+
+</style>

+ 19 - 0
src/components/preview/wordViewer.vue

@@ -0,0 +1,19 @@
+<template>
+  <div class="word-container">
+    <iframe :src="`https://view.officeapps.live.com/op/embed.aspx?src=${encodeURIComponent(src)}`"
+            frameborder="0"
+            style="width:100%;height:600px;">
+    </iframe>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "wordViewer",
+  props: ['src']
+}
+</script>
+
+<style scoped>
+
+</style>

+ 0 - 291
src/components/preview_file/index.vue

@@ -1,291 +0,0 @@
-<template>
-  <div class="file-preview">
-    <!-- 图片预览 -->
-    <div v-if="isImage" class="preview-container">
-      <img :src="fileUrl" :alt="fileName" class="preview-image" @click="showImageViewer" />
-    </div>
-
-    <!-- PDF 预览 -->
-    <div v-else-if="isPdf" class="preview-container">
-      <div class="pdf-controls">
-        <button @click="prevPage" :disabled="currentPage <= 1">上一页</button>
-        <span>第 {{ currentPage }} 页 / 共 {{ totalPages }} 页</span>
-        <button @click="nextPage" :disabled="currentPage >= totalPages">下一页</button>
-      </div>
-      <canvas ref="pdfCanvas" class="pdf-canvas"></canvas>
-    </div>
-
-    <!-- Word 文档预览 -->
-    <div v-else-if="isWord" class="preview-container">
-      <div v-if="wordContent" v-html="wordContent" class="word-content"></div>
-      <div v-else-if="loading" class="loading">加载中...</div>
-      <div v-else class="error">无法加载文档</div>
-    </div>
-
-    <!-- Excel 预览 -->
-    <div v-else-if="isExcel" class="preview-container">
-      <div class="excel-controls">
-        <select v-model="currentSheet" @change="renderSheet">
-          <option v-for="(sheet, index) in sheetNames" :key="index" :value="index">
-            {{ sheet }}
-          </option>
-        </select>
-      </div>
-      <div ref="excelTable" class="excel-table"></div>
-    </div>
-
-    <!-- 文本文件预览 -->
-    <div v-else-if="isText" class="preview-container">
-      <pre class="text-content">{{ textContent }}</pre>
-    </div>
-
-    <!-- 不支持的文件类型 -->
-    <div v-else class="unsupported">
-      不支持预览该文件类型
-    </div>
-  </div>
-</template>
-
-<script>
-import * as mammoth from 'mammoth';
-import * as pdfjsLib from 'pdfjs-dist/build/pdf';
-import * as XLSX from 'xlsx';
-
-// 配置 PDF.js worker
-pdfjsLib.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjsLib.version}/pdf.worker.min.js`;
-
-export default {
-  name: 'FilePreview',
-  props: {
-    fileUrl: {
-      type: String,
-      required: true
-    },
-    fileName: {
-      type: String,
-      default: ''
-    }
-  },
-  data() {
-    return {
-      loading: false,
-      // PDF 相关
-      currentPage: 1,
-      totalPages: 0,
-      pdfDoc: null,
-      // Word 相关
-      wordContent: '',
-      // Excel 相关
-      workbook: null,
-      sheetNames: [],
-      currentSheet: 0,
-      // 文本相关
-      textContent: ''
-    };
-  },
-  computed: {
-    fileType() {
-      if (!this.fileName) return '';
-      return this.fileName.split('.').pop().toLowerCase();
-    },
-    isImage() {
-      return ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'].includes(this.fileType);
-    },
-    isPdf() {
-      return this.fileType === 'pdf';
-    },
-    isWord() {
-      return ['doc', 'docx'].includes(this.fileType);
-    },
-    isExcel() {
-      return ['xls', 'xlsx', 'csv'].includes(this.fileType);
-    },
-    isText() {
-      return ['txt', 'js', 'html', 'css', 'json', 'xml'].includes(this.fileType);
-    }
-  },
-  watch: {
-    fileUrl: {
-      immediate: true,
-      handler(newUrl) {
-        if (newUrl) {
-          this.loadFile();
-        }
-      }
-    }
-  },
-  methods: {
-    async loadFile() {
-      this.loading = true;
-
-      try {
-        if (this.isPdf) {
-          await this.loadPdf();
-        } else if (this.isWord) {
-          await this.loadWord();
-        } else if (this.isExcel) {
-          await this.loadExcel();
-        } else if (this.isText) {
-          await this.loadText();
-        }
-      } catch (error) {
-        console.error('文件加载失败:', error);
-      } finally {
-        this.loading = false;
-      }
-    },
-
-    // 加载 PDF
-    async loadPdf() {
-      const loadingTask = pdfjsLib.getDocument(this.fileUrl);
-      this.pdfDoc = await loadingTask.promise;
-      this.totalPages = this.pdfDoc.numPages;
-      await this.renderPdfPage();
-    },
-
-    async renderPdfPage() {
-      if (!this.pdfDoc) return;
-
-      const page = await this.pdfDoc.getPage(this.currentPage);
-      const canvas = this.$refs.pdfCanvas;
-      const ctx = canvas.getContext('2d');
-
-      const viewport = page.getViewport({ scale: 1.5 });
-      canvas.width = viewport.width;
-      canvas.height = viewport.height;
-
-      await page.render({
-        canvasContext: ctx,
-        viewport: viewport
-      }).promise;
-    },
-
-    prevPage() {
-      if (this.currentPage > 1) {
-        this.currentPage--;
-        this.renderPdfPage();
-      }
-    },
-
-    nextPage() {
-      if (this.currentPage < this.totalPages) {
-        this.currentPage++;
-        this.renderPdfPage();
-      }
-    },
-
-    // 加载 Word 文档
-    async loadWord() {
-      const response = await fetch(this.fileUrl);
-      const arrayBuffer = await response.arrayBuffer();
-
-      const result = await mammoth.convertToHtml({ arrayBuffer });
-      this.wordContent = result.value;
-    },
-
-    // 加载 Excel
-    async loadExcel() {
-      const response = await fetch(this.fileUrl);
-      const arrayBuffer = await response.arrayBuffer();
-
-      this.workbook = XLSX.read(arrayBuffer, { type: 'array' });
-      this.sheetNames = this.workbook.SheetNames;
-      this.renderSheet();
-    },
-
-    renderSheet() {
-      if (!this.workbook) return;
-
-      const worksheet = this.workbook.Sheets[this.workbook.SheetNames[this.currentSheet]];
-      const html = XLSX.utils.sheet_to_html(worksheet);
-      this.$refs.excelTable.innerHTML = html;
-    },
-
-    // 加载文本文件
-    async loadText() {
-      const response = await fetch(this.fileUrl);
-      this.textContent = await response.text();
-    },
-
-    // 图片查看器
-    showImageViewer() {
-      this.$viewerApi({
-        images: [this.fileUrl]
-      });
-    }
-  },
-  mounted() {
-    // 注册图片查看器
-    if (!this.$viewerApi) {
-      import('v-viewer').then(module => {
-        const Viewer = module.default;
-        Vue.use(Viewer);
-      });
-    }
-  }
-};
-</script>
-
-<style scoped>
-.preview-container {
-  border: 1px solid #ddd;
-  border-radius: 4px;
-  padding: 20px;
-  max-height: 80vh;
-  overflow: auto;
-}
-
-.preview-image {
-  max-width: 100%;
-  max-height: 70vh;
-  cursor: zoom-in;
-}
-
-.pdf-canvas {
-  border: 1px solid #ccc;
-  margin-top: 10px;
-}
-
-.pdf-controls, .excel-controls {
-  margin-bottom: 10px;
-  display: flex;
-  gap: 10px;
-  align-items: center;
-}
-
-.word-content {
-  font-family: Arial, sans-serif;
-  line-height: 1.6;
-}
-
-.excel-table {
-  overflow: auto;
-}
-
-.text-content {
-  white-space: pre-wrap;
-  font-family: monospace;
-  background: #f5f5f5;
-  padding: 10px;
-  border-radius: 4px;
-}
-
-.loading, .error, .unsupported {
-  text-align: center;
-  padding: 40px;
-  color: #666;
-}
-
-button {
-  padding: 5px 10px;
-  border: 1px solid #ccc;
-  background: white;
-  border-radius: 3px;
-  cursor: pointer;
-}
-
-button:disabled {
-  opacity: 0.5;
-  cursor: not-allowed;
-}
-</style>

+ 20 - 0
src/utils/fileType.js

@@ -0,0 +1,20 @@
+export default {
+    getFileType(url) {
+        const extMap = {
+            'pdf': ['pdf'],
+            'doc': ['doc', 'docx'],
+            'xls': ['xls', 'xlsx'],
+            'txt': ['txt'],
+            'mp3': ['mp3'],
+            'mp4': ['mp4'],
+            'img': ['png', 'jpg', 'jpeg', 'gif']
+        };
+
+        const matchTypes = Object.entries(extMap).reduce((acc, [key, vals]) => {
+            if (vals.some(ext => url.endsWith(`.${ext}`))) acc.push(key);
+            return acc;
+        }, []);
+
+        return matchTypes[0] || 'unknown'; // 返回优先级最高的匹配类型
+    };
+}

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor