这里遇到了问题,引入xlsx插件的时候出现"export 'default' (imported as 'XLSX') was not found in 'xlsx'报错 解决:
直接将import XLSX from 'xlsx'改为import * as XLSX from 'xlsx/xlsx.mjs'即可
完整代码
<template> <el-dialog v-model="uploadDialogVisible" title="上传" width="800px" label-width="100px" @close="uploadDialogVisible = false" > <el-upload ref="uploadRef" v-model:file-list="fileList" class="upload-demo" drag :multiple="true" :auto-upload="false" :accept="props.allowType" :limit="props.limit" :before-upload="beforeAvatarUpload" :on-preview="previewFun" > <el-icon class="el-icon--upload"><upload-filled /></el-icon> <div class="el-upload__text"> <em>选择文件</em> </div> <template #tip> <div class="el-upload__tip"> 支持格式:{{ props.allowType }};限制大小{{ props.size }}M </div> </template> </el-upload> <template #footer> <span class="dialog-footer"> <el-button round @click="cancelFun">取消</el-button> <el-button round type="primary" @click="submitFun">确定</el-button> <el-button round type="primary" @click="getFileList" >获取文件</el-button > </span> </template> </el-dialog> <!-- 查看 --> <viewer ref="fileViewerRef" :dialog-doc="dialogDoc" /> </template> <script setup lang="ts"> /* eslint-disable */ import { defineProps, defineEmits, ref, reactive, computed } from "vue"; import type { FormInstance, UploadProps, UploadUserFile, UploadRawFile } from "element-plus"; import { ElMessage } from "element-plus"; import { UploadFilled } from "@element-plus/icons-vue"; import { api } from "@/api"; import SparkMD5 from "spark-md5"; import Viewer from "./viewer.vue"; interface Props { uploadDialogVisible?: boolean; allowType?: string; limit?: number; fileList?: any; size?: number; fileExtendId?: string; fileCategory?: number; folderName?: string; systemSource?: string; uploadUrl?: string; } //props const props: any = withDefaults(defineProps<Props>(), { uploadDialogVisible: false, allowType: "doc,docx,jpg,jpeg,png,xlsx,pdf", limit: 5, size: 5, fileExtendId: "", fileCategory: 2, folderName: "ceshi", systemSource: "ceshi", uploadUrl: "http://192.168.188.3:7001" }); const uploadDialogVisible = computed(() => { return props.uploadDialogVisible; }); const uploadRef = ref<FormInstance>(); const fileList = ref(([] as any)); const fileExtendId = ref("682D0E35121A4D4E831714CDACD5A18E"); const beforeAvatarUpload = () => { const flag = ref(true); fileList.value.forEach((item: any) => { console.log(item); const type = item.name.split(".")[1]; if (props.allowType.indexOf(type) == -1) { ElMessage({ type: "error", message: `格式错误,支持格式:${props.allowType}!` }); flag.value = false; return; } else if (item.size / 1024 / 1024 > props.size) { ElMessage.error(`文件最大${props.size}MB!`); flag.value = false; return; } }); return flag.value; }; //取消 const cancelFun = () => { emit("cancel", false); }; const submitFun = (formEl: FormInstance | undefined) => { // 判断是否有文件需要上传 if (fileList.value.length) { const flag = beforeAvatarUpload(); if (!flag) { return; } // 组合数据 const params = new FormData(); const fileConfigs: any = []; if (fileList.value.length) { fileList.value.forEach((item: any, index: number) => { // 判断一下是不是新上传的 if (item.id) { fileConfigs.push({ fileId: item.id, fileName: item.name, sort: ++index, // 必须从1开始,依次12345往下 md5: "" }); } else { params.append("file", item.raw); const spark = new SparkMD5.ArrayBuffer(); spark.append(item.raw); const md5 = spark.end(); fileConfigs.push({ fileId: "", fileName: item.name, sort: ++index, // 必须从1开始,依次12345往下 md5: md5 }); }; } ); } params.append("fileExtendId", fileExtendId.value); params.append("fileCategory", props.fileCategory); params.append("folderName", props.folderName); params.append("systemSource", props.systemSource); params.append("FileConfigs", JSON.stringify(fileConfigs)); console.log(params); api.adminCenter.UploadFiles(params).then((res: any) => { if (res.status.code == 200) { fileExtendId.value = res.result.fileExtendId; // 拿到了组合id,继续做业务 } }); } else { console.log("直接做业务"); } }; // 获取附件 const getFileList = () => { api.adminCenter .GetFileList({ fileExtendIds: fileExtendId.value }) .then((res: any) => { if (res.status.code == 200) { res.result.forEach((ele: any) => { ele.name = ele.fileOldName; fileList.value.push(ele); }); } else { } }); }; let dialogDoc: any = ref(false); const fileViewerRef = ref<any>(null); const previewFun = (file: any) => { console.log(file.halfPath); dialogDoc.value = true; let data = file; // 上传过的文件组成完成的网络路径 if (file.halfPath) { data.src = `${props.uploadUrl}${file.halfPath}`; } const suffix = data.name.split(".")[1]; if (suffix == "docx") { fileViewerRef.value?.viewDocx(data); } else if (suffix == "xlsx") { fileViewerRef.value?.viewXlsx(data); } else if (suffix == "jpg" || suffix == "jpeg" || suffix == "png") { fileViewerRef.value?.viewImg(data); } else if (suffix == "pdf") { fileViewerRef.value?.viewPdf(data); } }; // 声明emit const emit = defineEmits(["cancel"]); </script>
<template> <!-- doc --> <el-dialog v-model="dialogDocxValue" :title="dialogTitle" width="80%" @close="dialogDocxClose" > <div ref="docxRef" class="word-div"></div> </el-dialog> <!-- xlsx --> <el-dialog v-model="dialogXlsxValue" :title="dialogTitle" width="80%" @close="dialogXlsxClose" > <div ref="xlsxRef" class="xlsx-div"> <el-tabs v-model="activeName" type="border-card"> <el-tab-pane v-for="(item, index) in excelSheet" :key="index" :label="item.name" :name="item.name" > <div class="table" v-html="item.html"></div> </el-tab-pane> </el-tabs> </div> </el-dialog> <!-- 图片 --> <el-dialog v-model="dialogImgValue" :title="dialogTitle" width="80%" @close="dialogImgClose" > <div class="img-div"> <el-image :src="fileData.src" :alt="fileData.fileOldName" /> </div> </el-dialog> <!-- pdf --> <el-dialog v-model="dialogPdfValue" :title="dialogTitle" width="80%" @close="dialogPdfClose" > <div class="pdf-div"> <iframe id="pdfRef" :src="iframeUrl" frameborder="0" style="width: 100%; height: 99%" ></iframe> </div> </el-dialog> </template> <script setup lang="ts"> import axios from "axios"; import { defineProps, ref, reactive, computed, nextTick } from "vue"; import { renderAsync } from "docx-preview"; import * as XLSX from "xlsx"; interface Props { dialogDocx?: boolean; dialogXlsx?: boolean; dialogTitle?: string; } const props: any = withDefaults(defineProps<Props>(), { dialogDocx: false, dialogTitle: "", dialogXlsx: false }); const dialogDocxValue: any = ref(false); let dialogTitle = computed(() => { return props.dialogTitle; }); const fileHtml = ref(""); const docxRef = ref<any>(); // doc 文档预览 const viewDocx = (data: any) => { docxRef.value = ""; dialogDocxValue.value = true; console.log(data); if (data.src) { // 已上传的文件 axios({ url: data.src, method: "get", responseType: "blob" }).then((res) => { console.log(res); if (res.status == 200) { const content = res.data; const blob = new Blob([content]); nextTick(() => { dialogDocxValue.value = true; renderAsync(blob, docxRef.value); dialogTitle = data.fileOldName || data.name; }); } }); } else { // 本地文件 const blob = new Blob([data.raw]); nextTick(() => { dialogDocxValue.value = true; renderAsync(blob, docxRef.value); dialogTitle = data.fileOldName || data.name; }); } }; const dialogXlsxValue: any = ref(false); const excelSheet: any = ref([]); const activeName = ref(""); const dialogDocxClose = () => { dialogDocxValue.value = false; docxRef.value = ""; }; // xlsx 预览 const viewXlsx = (data: any) => { dialogXlsxValue.value = true; console.log(data); if (data.src) { axios({ url: data.src, method: "get", responseType: "blob" }).then((res) => { console.log(res); if (res.status == 200) { const content = res.data; // const blob = new Blob(content); const reader = new FileReader(); reader.readAsArrayBuffer(content); reader.onload = function (loadEvent: any) { const arrayBuffer = loadEvent.target["result"]; const workbook = XLSX.read(new Uint8Array(arrayBuffer), { type: "array" }); const list = []; const sheetNames = workbook.SheetNames; activeName.value = sheetNames[0]; for (const p of sheetNames) { let html = ""; try { html = XLSX.utils.sheet_to_html(workbook.Sheets[p]); } catch (e) { html = ""; } const map = { name: p, html: html }; list.push(map); } excelSheet.value = list; dialogTitle = data.fileName || data.name; }; } }); } else { const blob = new Blob([data.raw]); const reader = new FileReader(); reader.readAsArrayBuffer(blob); reader.onload = function (loadEvent: any) { const arrayBuffer = loadEvent.target["result"]; const workbook = XLSX.read(new Uint8Array(arrayBuffer), { type: "array" }); const list = []; const sheetNames = workbook.SheetNames; activeName.value = sheetNames[0]; for (const p of sheetNames) { let html = ""; try { html = XLSX.utils.sheet_to_html(workbook.Sheets[p]); } catch (e) { html = ""; } const map = { name: p, html: html }; list.push(map); } excelSheet.value = list; dialogTitle = data.fileName || data.name; }; } }; const dialogXlsxClose = () => { dialogXlsxValue.value = false; excelSheet.value = ""; activeName.value = ""; }; const fileData: any = ref({}); const dialogImgValue: any = ref(false); // 图片预览 const viewImg = (data: any) => { if (data.src) { // 已上传的图片 fileData.value = data; } else { // 本地图片 const freader = new FileReader(); freader.readAsDataURL(data.raw); freader.onload = (e: any) => { fileData.value = { src: e.target.result, id: new Date(), fileName: data.fileOldName || data.name }; }; } dialogTitle = data.fileOldName || data.name; dialogImgValue.value = true; }; const dialogImgClose = () => { dialogImgValue.value = false; }; const dialogPdfValue: any = ref(false); const iframeUrl: any = ref(""); const pdfRef = ref<any>(); const viewPdf = (data: any) => { if (data.src) { axios({ url: data.src, method: "get", responseType: "blob" }).then((res) => { if (res.status == 200) { // 把文件流转化为url iframeUrl.value = URL.createObjectURL(res.data); dialogPdfValue.value = true; } }); } else { iframeUrl.value = URL.createObjectURL(data.raw); dialogPdfValue.value = true; } }; const dialogPdfClose = () => { dialogPdfValue.value = false; }; defineExpose({ viewDocx, viewXlsx, viewImg, viewPdf }); </script> <style scoped lang="scss"> .word-div { height: calc(70vh); overflow: auto; } .xlsx-div { height: calc(70vh); overflow: auto; } .img-div { height: calc(70vh); overflow: auto; img { width: 100%; height: 100%; } } .pdf-div { height: calc(70vh); overflow: auto; } </style> <style lang="scss"> .xlsx-div { .table-html-wrap table { border-right: 1px solid #fff; border-bottom: 1px solid #e8eaec; border-collapse: collapse; // margin: auto; } .table-html-wrap table td { border-left: 1px solid #e8eaec; border-top: 1px solid #e8eaec; white-space: wrap; text-align: left; min-width: 100px; padding: 4px; } table { border-top: 1px solid #ebeef5; border-left: 1px solid #ebeef5; width: 100%; // overflow: auto; tr { height: 44px; } td { min-width: 200px; max-width: 400px; padding: 4px 8px; border-right: 1px solid #ebeef5; border-bottom: 1px solid #ebeef5; } } .el-tabs--border-card > .el-tabs__content { overflow-x: auto; } } </style>