|
|
@@ -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>
|