<template>
|
<el-dialog v-model="dialogVisible" title="预览" width="100%" fullscreen align-center :before-close="handleClose" append-to-body>
|
<div>
|
<!-- 图片预览 -->
|
<div v-if="isImage">
|
<img :src="imgUrl" alt="Image Preview" />
|
</div>
|
|
<!-- PDF预览提示 -->
|
<div v-if="isPdf" style="height: 100vh; display: flex; align-items: center; justify-content: center;">
|
<p>正在准备PDF预览...</p>
|
</div>
|
|
<!-- Word文档预览 -->
|
<div v-if="isDoc">
|
<p v-if="!isDocShow">文档无法直接预览,请下载查看。</p>
|
<a :href="fileUrl" v-if="!isDocShow">下载文件</a>
|
<vue-office-docx
|
v-else
|
:src="fileUrl"
|
style="height: 100vh;"
|
@rendered="renderedHandler"
|
@error="errorHandler"
|
/>
|
</div>
|
|
<!-- Excel文档预览 -->
|
<div v-if="isXls">
|
<p v-if="!isDocShow">文档无法直接预览,请下载查看。</p>
|
<a :href="fileUrl" v-if="!isDocShow">下载文件</a>
|
<vue-office-excel
|
v-else
|
:src="fileUrl"
|
:options="options"
|
style="height: 100vh;"
|
@rendered="renderedHandler"
|
@error="errorHandler"
|
/>
|
</div>
|
|
<!-- 压缩文件处理 -->
|
<div v-if="isZipOrRar">
|
<p>压缩文件无法直接预览,请下载查看。</p>
|
<a :href="fileUrl">下载文件</a>
|
</div>
|
|
<!-- 不支持的格式 -->
|
<div v-if="!isSupported">
|
<p>不支持的文件格式</p>
|
</div>
|
</div>
|
</el-dialog>
|
</template>
|
|
<script setup>
|
import { ref, computed, getCurrentInstance, watch } from 'vue';
|
import VueOfficeDocx from '@vue-office/docx';
|
import '@vue-office/docx/lib/index.css';
|
import VueOfficeExcel from '@vue-office/excel';
|
import '@vue-office/excel/lib/index.css';
|
|
// 响应式变量
|
const fileUrl = ref('')
|
const dialogVisible = ref(false)
|
const { proxy } = getCurrentInstance();
|
const javaApi = proxy.javaApi;
|
|
// 文档预览状态
|
const isDocShow = ref(true);
|
const imgUrl = ref('');
|
const options = ref({
|
xls: false,
|
minColLength: 0,
|
minRowLength: 0,
|
widthOffset: 10,
|
heightOffset: 10,
|
beforeTransformData: (workbookData) => workbookData,
|
transformData: (workbookData) => workbookData,
|
});
|
|
// 计算属性 - 判断文件类型
|
const isImage = computed(() => {
|
const state = /\.(jpg|jpeg|png|gif)$/i.test(fileUrl.value);
|
if (state) {
|
imgUrl.value = fileUrl.value.replaceAll('word', 'img');
|
}
|
return state;
|
});
|
|
const isPdf = computed(() => {
|
console.log(fileUrl.value)
|
return /\.pdf$/i.test(fileUrl.value);
|
});
|
|
const isDoc = computed(() => {
|
return /\.(doc|docx)$/i.test(fileUrl.value);
|
});
|
|
const isXls = computed(() => {
|
const state = /\.(xls|xlsx)$/i.test(fileUrl.value);
|
if (state) {
|
options.value.xls = /\.(xls)$/i.test(fileUrl.value);
|
}
|
return state;
|
});
|
|
const isZipOrRar = computed(() => {
|
return /\.(zip|rar)$/i.test(fileUrl.value);
|
});
|
|
const isSupported = computed(() => {
|
return isImage.value || isPdf.value || isDoc.value || isXls.value || isZipOrRar.value;
|
});
|
|
// 动态创建a标签并跳转预览PDF
|
const previewPdf = (url) => {
|
// 创建a标签
|
const link = document.createElement('a');
|
// 设置PDF文件URL
|
link.href = url;
|
// 在新标签页打开
|
link.target = '_blank';
|
// 安全属性,防止新页面访问原页面
|
link.rel = 'noopener noreferrer';
|
// 可选:设置链接文本
|
link.textContent = '预览PDF';
|
// 将a标签添加到页面(部分浏览器要求必须在DOM中)
|
document.body.appendChild(link);
|
// 触发点击事件
|
link.click();
|
// 移除a标签,清理DOM
|
document.body.removeChild(link);
|
};
|
|
|
// 监听PDF状态变化,自动触发跳转
|
watch(
|
() => isPdf.value,
|
(newVal) => {
|
|
// 当确认是PDF且文件URL有效时
|
if (newVal && fileUrl.value) {
|
// 关闭对话框
|
dialogVisible.value = false;
|
// 加个小延迟确保状态更新完成
|
setTimeout(() => {
|
previewPdf(fileUrl.value);
|
fileUrl.value = '';
|
}, 100);
|
}
|
}
|
);
|
|
// 方法定义
|
const renderedHandler = () => {
|
console.log("渲染完成");
|
isDocShow.value = true;
|
resetStyle();
|
};
|
|
const errorHandler = () => {
|
console.log("渲染失败");
|
isDocShow.value = false;
|
};
|
|
const open = (url) => {
|
fileUrl.value = window.location.protocol+'//'+window.location.host+ url;
|
dialogVisible.value = true;
|
};
|
const handleClose = () => {
|
dialogVisible.value = false;
|
};
|
|
const resetStyle = () => {
|
const elements = document.querySelectorAll('[style*="pt"]');
|
for (const element of elements) {
|
const style = element.getAttribute('style');
|
if (style) {
|
element.setAttribute('style', style.replace(/pt/g, 'px'));
|
}
|
}
|
};
|
|
// 暴露open方法供外部调用
|
defineExpose({
|
open
|
})
|
</script>
|
|
<style scoped>
|
img {
|
max-width: 100%;
|
display: block;
|
margin: 0 auto;
|
}
|
|
.oneLine {
|
overflow: hidden;
|
white-space: nowrap;
|
text-overflow: ellipsis;
|
}
|
</style>
|