|
|
@@ -1,106 +1,144 @@
|
|
|
<template>
|
|
|
<div>
|
|
|
- <input type="file" @change="handleFileUpload" />
|
|
|
- <div v-if="previewUrl">
|
|
|
- <!-- 图片预览 -->
|
|
|
- <img v-if="isImage" :src="previewUrl" alt="预览" style="max-width: 100%; max-height: 500px;">
|
|
|
-
|
|
|
- <!-- PDF预览 -->
|
|
|
- <iframe
|
|
|
- v-else-if="isPdf"
|
|
|
+ <div style="width: 100%; height: 700px">
|
|
|
+ <img
|
|
|
:src="previewUrl"
|
|
|
- width="100%"
|
|
|
- height="800px"
|
|
|
- frameborder="0"
|
|
|
- ></iframe>
|
|
|
-
|
|
|
- <!-- 文本预览 -->
|
|
|
- <pre v-else-if="isText" style="white-space: pre-wrap;">{{ textContent }}</pre>
|
|
|
-
|
|
|
- <!-- 通用预览(未知类型) -->
|
|
|
- <div v-else>
|
|
|
- <p>不支持直接预览此文件类型</p>
|
|
|
- <a :href="previewUrl" download>点击下载</a>
|
|
|
- </div>
|
|
|
+ style="width: 95%"
|
|
|
+ v-show="currentFileType === 'image'"
|
|
|
+ />
|
|
|
+ <el-table
|
|
|
+ :data="tableData"
|
|
|
+ height="650px"
|
|
|
+ v-show="currentFileType === 'excel'">
|
|
|
+ <el-table-column
|
|
|
+ v-for="(header, index) in headers"
|
|
|
+ :key="index"
|
|
|
+ :prop="`col_${index}`"
|
|
|
+ :label="header"
|
|
|
+ />
|
|
|
+ </el-table>
|
|
|
+ <div v-show="currentFileType === 'word'" v-html="wordHtml" />
|
|
|
</div>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
-<script>
|
|
|
-import { ref } from 'vue';
|
|
|
-
|
|
|
-export default {
|
|
|
- setup() {
|
|
|
- const previewUrl = ref(null);
|
|
|
- const textContent = ref('');
|
|
|
- const fileType = ref('');
|
|
|
-
|
|
|
- // 文件类型判断
|
|
|
- const detectFileType = (blob) => {
|
|
|
- const type = blob.type;
|
|
|
-
|
|
|
- // 图片类型检测
|
|
|
- if (type.startsWith('image/')) {
|
|
|
- return 'image';
|
|
|
- }
|
|
|
-
|
|
|
- // PDF检测
|
|
|
- if (type === 'application/pdf') {
|
|
|
- return 'pdf';
|
|
|
- }
|
|
|
-
|
|
|
- // 文本类型检测
|
|
|
- if (type.includes('text/') ||
|
|
|
- type === 'application/json' ||
|
|
|
- type === 'application/javascript') {
|
|
|
- return 'text';
|
|
|
- }
|
|
|
-
|
|
|
- // 可通过文件签名扩展更多类型检测
|
|
|
- return 'unknown';
|
|
|
- };
|
|
|
-
|
|
|
- const handleFileUpload = async (e) => {
|
|
|
- const file = e.target.files[0];
|
|
|
- if (!file) return;
|
|
|
-
|
|
|
- const blob = new Blob([file], { type: file.type });
|
|
|
- const type = detectFileType(blob);
|
|
|
-
|
|
|
- // 清理之前的URL
|
|
|
- if (previewUrl.value) {
|
|
|
- URL.revokeObjectURL(previewUrl.value);
|
|
|
- }
|
|
|
-
|
|
|
- // 生成新的预览URL
|
|
|
- previewUrl.value = URL.createObjectURL(blob);
|
|
|
- fileType.value = type;
|
|
|
-
|
|
|
- // 处理文本内容
|
|
|
- if (type === 'text') {
|
|
|
- const text = await file.text();
|
|
|
- textContent.value = text;
|
|
|
- }
|
|
|
-
|
|
|
- // 更新响应式变量
|
|
|
- e.target.value = '';
|
|
|
+<script setup>
|
|
|
+import { ref, defineExpose, computed, reactive } from 'vue';
|
|
|
+import { fileDownload } from "@/api/dailyFile";
|
|
|
+const currentFileType = ref('')
|
|
|
+import * as XLSX from 'xlsx'
|
|
|
+import { saveAs } from 'file-saver'
|
|
|
+import * as mammoth from 'mammoth';
|
|
|
+const getFileExtension = (filename, toLowerCase = true) => {
|
|
|
+ if (typeof filename !== 'string') return '';
|
|
|
+
|
|
|
+ // 正则匹配:匹配最后一个点之后的有效扩展名
|
|
|
+ const match = filename.match(/\.([^.]+)$/);
|
|
|
+
|
|
|
+ return match ? (toLowerCase ? match[1].toLowerCase() : match[1]) : '';
|
|
|
+}
|
|
|
+
|
|
|
+const getFileType = (ext) => {
|
|
|
+ const extensionMap = {
|
|
|
+ jpg: 'image',
|
|
|
+ jpeg: 'image',
|
|
|
+ png: 'image',
|
|
|
+ gif: 'image',
|
|
|
+ webp: 'image',
|
|
|
+ pdf: 'pdf',
|
|
|
+ doc: 'word',
|
|
|
+ docx: 'word',
|
|
|
+ xls: 'excel',
|
|
|
+ xlsx: 'excel',
|
|
|
+ ppt: 'ppt',
|
|
|
+ pptx: 'ppt',
|
|
|
+ txt: 'text',
|
|
|
+ csv: 'csv',
|
|
|
+ json: 'json',
|
|
|
+ zip: 'archive',
|
|
|
+ rar: 'archive',
|
|
|
+ '7z': 'archive',
|
|
|
+ mp3: 'audio',
|
|
|
+ wav: 'audio',
|
|
|
+ mp4: 'video',
|
|
|
+ mov: 'video',
|
|
|
+ avi: 'video'
|
|
|
+ }
|
|
|
+ return extensionMap[ext] || 'unknown'
|
|
|
+}
|
|
|
+const getFile = (data) => {
|
|
|
+ const fileType = getFileType(getFileExtension(data.name))
|
|
|
+ currentFileType.value = fileType
|
|
|
+ fileDownload(data).then(res => {
|
|
|
+ if (fileType === 'image') {
|
|
|
+ previewImage(res.data)
|
|
|
+ } else if (fileType === 'excel') {
|
|
|
+ previewExcel(res.data)
|
|
|
+ } else if (fileType === 'word') {
|
|
|
+ previewOffice(res.data)
|
|
|
}
|
|
|
-
|
|
|
- // 组件卸载时清理内存
|
|
|
- onUnmounted(() => {
|
|
|
- if (previewUrl.value) {
|
|
|
- URL.revokeObjectURL(previewUrl.value);
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
- return {
|
|
|
- previewUrl,
|
|
|
- isImage: computed(() => fileType.value === 'image'),
|
|
|
- isPdf: computed(() => fileType.value === 'pdf'),
|
|
|
- isText: computed(() => fileType.value === 'text'),
|
|
|
- textContent,
|
|
|
- handleFileUpload
|
|
|
- };
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+const previewUrl = ref('')
|
|
|
+// 图片预览.....................................................
|
|
|
+async function previewImage(data) {
|
|
|
+ try {
|
|
|
+ previewUrl.value = URL.createObjectURL(data)
|
|
|
+ } catch (err) {
|
|
|
+ throw new Error('图片预览失败', { cause: err })
|
|
|
+ }
|
|
|
+}
|
|
|
+// Excel 预览...................................................
|
|
|
+async function previewExcel(val) {
|
|
|
+ // console.log(val)
|
|
|
+ // console.log('val',new Uint8Array(val.arrayBuffer()))
|
|
|
+ try {
|
|
|
+ const data = new Uint8Array(await val.arrayBuffer())
|
|
|
+ const workbook = XLSX.read(data, { type: 'array' })
|
|
|
+ // 获取所有工作表名
|
|
|
+ sheets.splice(0, sheets.length, ...workbook.SheetNames)
|
|
|
+
|
|
|
+ if (sheets.length) {
|
|
|
+ activeSheet.value = sheets[0]
|
|
|
+ renderSheet(workbook.Sheets[sheets[0]])
|
|
|
+ }
|
|
|
+ } catch (err) {
|
|
|
+ throw new Error('Excel 文件解析失败', { cause: err })
|
|
|
}
|
|
|
-};
|
|
|
+}
|
|
|
+const headers = ref([])
|
|
|
+const tableData = ref([])
|
|
|
+const sheets = reactive([])
|
|
|
+const activeSheet = ref('')
|
|
|
+// 渲染指定工作表................................................
|
|
|
+const wordHtml = ref('')
|
|
|
+const renderSheet = (worksheet) => {
|
|
|
+ // 提取表头(第一行)
|
|
|
+ const headerRow = XLSX.utils.sheet_to_json(worksheet, { header: 1 })[0] || []
|
|
|
+ headers.value = headerRow.map(header => header || '空列')
|
|
|
+
|
|
|
+ // 提取数据(跳过表头)
|
|
|
+ const jsonData = XLSX.utils.sheet_to_json(worksheet, { skipHeader: 1 })
|
|
|
+ // 转换为表格数据格式
|
|
|
+ tableData.value = jsonData.map(row => {
|
|
|
+ const rowData = {}
|
|
|
+ headers.value.forEach((header, index) => {
|
|
|
+ rowData[`col_${index}`] = row[header] || ''
|
|
|
+ })
|
|
|
+ return rowData
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+const previewOffice = async (val) => {
|
|
|
+ const arrayBuffer = await val.arrayBuffer()
|
|
|
+ console.log('arrayBuffer', arrayBuffer)
|
|
|
+ const { value } = await mammoth.extractRawText({ arrayBuffer })
|
|
|
+ console.log('value', value)
|
|
|
+ wordHtml.value = value;
|
|
|
+}
|
|
|
+
|
|
|
+defineExpose({
|
|
|
+ getFile
|
|
|
+})
|
|
|
</script>
|