html
复制代码
<!-- 文书预览弹窗 -->
<template>
<el-dialog :visible.sync="dialogVisible" width="80%" top="5vh" @close="close">
<template #title>
<div class="dialog_title">
<span>{{ file.wjmc }}</span>
<el-button type="primary" size="mini" icon="el-icon-download">下载</el-button>
</div>
</template>
<el-carousel ref="ElCarouselRef" :autoplay="false" arrow="always" :initial-index="fileIndex" @change="carouselChange">
<el-carousel-item v-for="(item, index) in fileList" :key="index">
<template v-if="['.pdf'].includes(item.wjgs)">
<embed :src="item.wjlj" type="application/pdf" width="100%" height="100%" />
</template>
<template v-else-if="['.doc', '.docx'].includes(item.wjgs)">
<!-- 【主要代码】word文档预览 -->
<div class="word" :ref="`word_container_${index}`" />
<div v-show="wordLoading[index]" class="word_loading">
<i class="el-icon-loading"></i>正在加载文档...
</div>
<div v-show="item.showFail && index in wordLoading && !wordLoading[index]" class="word_error">
<i class="el-icon-document-delete"></i>文档渲染失败
</div>
</template>
<template v-else>
<el-image :src="item.wjlj" fit="cover" :preview-src-list="[item.wjlj]"></el-image>
</template>
</el-carousel-item>
</el-carousel>
</el-dialog>
</template>
<script>
import Axios from 'axios' // 方法二获取线上文件
import * as docx from 'docx-preview' // 【主要代码】使用到的插件
export default {
name: 'FlwsPreviewDialog',
components: {},
props: {
fileList: {
type: Array,
default: () => [
{
wjlj: '/XXX/p4OmsfvdjAN8f2h2tp23Q==.pdf',
wjmc: '测试.pdf',
wjgs: '.pdf'
},
{
wjlj: '/XXX/Hmeydz0LjY1DPrk0OY4WJw==.docx',
wjmc: '测试.docx',
wjgs: '.docx'
},
{
wjlj: '/XXX/KRcIS5uN4jN8uW+yOnI3Q==.png',
wjmc: '截图_①.png',
wjgs: '.png'
},
{
wjlj: '/XXX/zOU3u8F7mYewaL2dCmPCkg==.png',
wjmc: '截图-button.png',
wjgs: '.png'
},
{
wjlj: '/XXX/uYIy0yhNFSTFrIC5fW2Zw==.jpg',
wjmc: '高拍仪扫描文件_1766988435595.jpg',
wjgs: '.jpg'
}
]
}
},
data() {
return {
dialogVisible: false,
fileIndex: 0,
wordLoading: {}
}
},
computed: {
file() {
return this.fileList[this.fileIndex] || {}
}
},
methods: {
open(index) {
this.fileIndex = index
this.dialogVisible = true
this.getDoc()
this.$refs.ElCarouselRef?.setActiveItem(this.fileIndex)
},
getDoc() {
// 【主要代码】word文档预览处理
this.fileList.forEach((i, index) => {
if (['.doc', '.docx'].includes(i.wjgs) && i.wjlj && !(index in this.wordLoading)) {
this.wordLoading[index] = true
setTimeout(() => {
this.handleFileChange(i.wjlj, index)
}, 2000)
}
})
},
async handleFileChange(url, index) {
try {
/** ** 【主要代码】方法一 fetch 获取线上文件 start ****/
const response = await fetch(url) // 获取线上文件
const arrayBuffer = await response.arrayBuffer()
await docx.renderAsync(
arrayBuffer,
this.$refs[`word_container_${index}`][0],
null,
this.getOptions()
)
/** ** 【主要代码】方法一 fetch 获取线上文件 end ****/
/** ** 【主要代码】方法二 axios 获取线上文件 start ****/
// Axios.get(url, {
// responseType: 'arraybuffer'
// }).then((res) => { // 获取线上文件
// docx.renderAsync(
// res.data,
// this.$refs[`word_container_${index}`][0],
// null,
// this.getOptions()
// )
// })
/** ** 【主要代码】方法二 axios 获取线上文件 end ****/
} catch (error) {
// this.$message.error('文档渲染失败')
this.fileList[index].showFail = true
console.error('渲染失败:', error)
} finally {
this.wordLoading[index] = false
this.$forceUpdate()
}
},
getOptions() {
return {
className: 'docx',
inWrapper: true,
ignoreWidth: false,
ignoreHeight: false,
ignoreFonts: false,
breakPages: true,
debug: false,
experimental: false,
trimXmlDeclaration: true,
useBase64URL: false,
useMathMLPolyfill: true,
showChanges: false,
ignoreLastRenderedPageBreak: true
}
},
carouselChange(index) {
this.fileIndex = index
},
close() {
this.dialogVisible = false
this.fileIndex = 0
}
}
}
</script>
<style lang='scss' scoped>
::v-deep .el-dialog {
.dialog_title {
display: flex;
justify-content: space-between;
align-items: center;
padding-right: 27px;
}
.el-dialog__headerbtn {
top: 15px;
}
.el-dialog__body {
height: 85vh;
.el-carousel {
width: 100%;
height: 100%;
.el-carousel__container {
height: 100%;
position: relative;
.el-image {
width: 100%;
height: 100%;
}
.word {
width: 100%;
height: 100%;
overflow: auto;
}
.word_loading,
.word_error {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
i {
display: block;
font-size: 50px;
margin-block: 10px;
}
}
}
}
}
}
</style>