一、准备工作
安装预览依赖包:exceljs、mammoth、vue-pdf
二、封装组件
文件上传组件
fileUploadPro.vue。默认预览、下载是true,可通过isPreView、isDownLoad控制
javascript
<template>
<div style="display: flex">
<el-upload
multiple
action=""
ref="uploadF"
:show-file-list="false"
:file-list="fileList"
:http-request="fileUpLoad"
>
<el-button v-if="!readOnly" size="mini" type="primary">点击上传</el-button>
</el-upload>
<div style="flex-grow: 1;flex-wrap: wrap">
<el-tag
@close="removeFile(index)"
v-for="(tag, index) in fileList"
:key="tag.fileId"
:closable="true"
type="info">
<div style="float: left">
{{tag.name}}
</div>
<div v-if="isPreView" class="iconStyle" @click="preView(tag)">
<i class="el-icon-view"></i>
</div>
<div v-if="isDownLoad" class="iconStyle" @click="downLoad(tag)">
<i class="el-icon-download"></i>
</div>
</el-tag>
</div>
</div>
</template>
<script>
export default {
name: "fileUploadPro",
props: {
fileList: {
type: Array,
default: []
},
isPreView: {
type: Boolean,
default: true
},
isDownLoad: {
type: Boolean,
default: true
},
readOnly:{
type: Boolean,
default: false
}
},
data() {
return {
}
},
methods:{
fileUpLoad(e) {
let file = e.file
let formData = new FormData();
formData.append("file", file); // 'file' 可变 相当于 input 表单的name 属性
formData.append("name", file.name);
formData.append("type", file.type);
formData.append("size", file.size);
formData.append("lastModifiedDate", file.lastModifiedDate);
this.$http({
method: 'post',
url: "/base/ctBaseFile/saveFile50",
data: formData
}).then((response) => {
if (response.data.code === 200) {
this.$message.success('上传成功')
this.fileList.push({
fileId: response.data.data.ctBaseFile.id,
name: file.name
})
}
})
},
removeFile(index) {
this.fileList.splice(index, 1)
},
preView(file) {
let fileUrl = '';
let fileType = '';
if (file) {
fileUrl = this.$fileUrl + '/common/getFileRes/' + file.fileId
const addTypeArray = file.name.split(".");
const addType = addTypeArray[addTypeArray.length - 1];
if (addType === "pdf") {
fileType = 'pdf'
}else if(addType === 'xls' || addType === 'xlsx'){
fileType = 'excel'
}else if (addType === "doc" || addType === "docx") {
fileType = 'word'
} else if (["png", "jpg", "jpeg"].includes(addType)) {
fileType = 'image'
} else {
fileType = addType
}
}
this.$emit("preView",fileType,fileUrl);
//that.showModal = true
},
downLoad(file){
let a = document.createElement("a");//创建a标签
a.setAttribute("href", this.$fileUrl + '/common/getFileRes/' + file.fileId);//设置文件下载地址
a.setAttribute('target', '_blank');//在当前页面创建下载
document.body.appendChild(a);//添加到body
a.click();//触发事件
document.body.removeChild(a);//移除标签
},
}
}
</script>
<style scope>
.iconStyle{
float: left;
width: 16px;
height: 16px;
line-height: 16px;
text-align: center;
position: relative;
top:7px;
margin-left: 6px;
border-radius: 50%;
cursor: pointer;
}
.iconStyle:hover{
background-color: #909399;
color: #fff;
}
</style>
预览组件
preViewDialog.vue
javascript
<template>
<div>
<!-- Modal -->
<el-dialog
:title="'预览' + fileType"
:visible.sync="showModal"
width="70%"
top="5vh"
:before-close="handleClose"
:close-on-click-modal="false"
>
<!-- Conditional rendering based on fileType -->
<div v-if="fileType === 'image'" style="text-align:center">
<img v-loading="loading" style="height: 400px" :src="fileUrl" alt="预览图片">
</div>
<div v-else-if="fileType === 'excel'">
<el-table v-loading="loading" size="mini" :data="excelData" height="400" width="100%" :show-header="false">
<el-table-column width="150" v-for="(cell, key) in excelData[0]" :key="key" :prop="key" :label="key">
</el-table-column>
</el-table>
</div>
<div v-else-if="fileType === 'pdf'">
<!-- Render PDF preview here -->
<VuePdf v-loading="loading" :src="pdfUrl"></VuePdf>
</div>
<div v-else-if="fileType === 'word'">
<!-- Render Word preview here -->
<div v-loading="loading" v-html="wordContent"></div>
</div>
<div v-else>
<p>不支持的文件类型或未提供URL。</p>
</div>
<!-- Close Button -->
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="downLoad(fileUrl)">下 载</el-button>
<el-button type="info" @click="closeModal">关 闭</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import ExcelJS from 'exceljs';
import mammoth from 'mammoth';
import VuePdf from 'vue-pdf';
export default {
props: {
fileType: {
type: String,
required: true,
},
fileUrl: {
type: String,
required: true
}
},
components: {
VuePdf,
},
data() {
return {
pdfUrl:'',
loading: true,
excelContent: '',
wordContent: '',
showModal: false,
excelData: [],
};
},
mounted() {
this.showModal = true
this.loadFile();
},
methods: {
async loadFile() {
switch (this.fileType) {
case 'excel':
await this.loadExcel();
break;
case 'word':
await this.loadWord();
break;
case 'pdf':
// 加载 PDF 的逻辑
await this.loadPdf();
break;
default:
this.loading = false;
break;
}
},
closeModal() {
this.loading = true;
this.$emit('close-modal');
},
async loadExcel() {
try {
const response = await fetch(this.fileUrl);
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const arrayBuffer = await response.arrayBuffer();
const workbook = new ExcelJS.Workbook();
await workbook.xlsx.load(arrayBuffer);
const worksheet = workbook.worksheets[0]; // Assuming you want the first worksheet
if (worksheet) {
let data = [];
worksheet.eachRow((row, rowIndex) => {
let rowData = {};
row.eachCell((cell, colIndex) => {
rowData[`col${colIndex}`] = cell.value;
});
data.push(rowData);
});
this.excelData = data;
} else {
this.excelData = [];
}
} catch (error) {
console.error('Error loading Excel:', error);
this.excelData = [];
} finally {
this.loading = false;
}
},
async loadWord() {
try {
const response = await fetch(this.fileUrl);
const arrayBuffer = await response.arrayBuffer();
const result = await mammoth.extractRawText({ arrayBuffer });
this.wordContent = result.value;
} catch (error) {
this.wordContent = '加载Word文件失败。';
} finally {
this.loading = false;
}
},
async loadPdf() {
try {
this.pdfUrl = VuePdf.createLoadingTask({
url:this.fileUrl,
cMapUrl: 'https://cdn.jsdelivr.net/npm/pdfjs-dist@2.6.347/cmaps/',
cMapPacked: true
})
const response = await fetch(this.pdfUrl);
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
} catch (error) {
console.error('Error fetching data:', error);
}finally {
this.loading = false
}
},
handleClose() {
this.closeModal()
},
downLoad(file){
let a = document.createElement("a");//创建a标签
a.setAttribute("href", file);//设置文件下载地址
a.setAttribute('target', '_blank');//在当前页面创建下载
document.body.appendChild(a);//添加到body
a.click();//触发事件
document.body.removeChild(a);//移除标签
},
},
};
</script>
<style scoped>
</style>
三、组件调用
javascript
<template>
<div>
<fileUploadPro
:file-list.sync="fileList"
:isPreView="true"
:isDownLoad="false"
@preView="preView"/>
<previewDialog
v-if="showModal"
:file-type="fileType"
:file-url="fileUrl"
@close-modal="showModal = false"/>
</div>
</template>
<script>
import previewDialog from '../components/previewDialog';
import fileUploadPro from "../components/fileUploadPro";
export default {
name: "parentXXX",
components:{previewDialog,fileUploadPro},
data() {
return{
fileList:[],
fileType: '',
fileUrl:'',
showModal: false,
}
},
methods:{
preView(type,url){
this.fileUrl = url;
this.fileType = type;
this.showModal = true
},
}
}
</script>
四、效果