This commit is contained in:
guochunsi
2026-01-07 16:17:49 +08:00
parent e1cb334fbf
commit 9490c6670c
21 changed files with 642 additions and 603 deletions

View File

@@ -1,15 +1,43 @@
<template>
<div style="width: 100%;height: 100%;">
<viewer :images="[authSrc]" v-if="!showIframe">
<img v-if="!showIframe" ref="imgRef" :width="imgWidth || '100%'" :height="imgHeight || '100%'" :src="authSrc" />
</viewer>
<iframe v-if="showIframe" ref="authIframeRef" style="width: 100%;height: 100%;" >
</iframe>
<!-- 组件不占据任何布局空间所有预览组件都是 teleported -->
<div style="display: none;">
<!-- 图片直接使用 el-image-viewer 全屏预览 -->
<el-image-viewer
v-if="!showIframe && imageSrc && imagePreviewVisible"
:url-list="[imageSrc]"
:teleported="true"
hide-on-click-modal
@close="imagePreviewVisible = false"
/>
<!-- PDF dialog 中显示 -->
<el-dialog
v-if="showIframe"
v-model="pdfDialogVisible"
:title="dialogTitle || '文件预览'"
append-to-body
width="90%"
class="pdf-preview-dialog"
>
<iframe ref="authIframeRef" :style="{ width: '100%', height: pdfIframeHeight }" />
<!-- <div class="pdf-iframe-wrapper">
<iframe
ref="authIframeRef"
:style="{
width: '100%',
height: pdfIframeHeight,
border: 'none',
display: 'block'
}"
/>
</div> -->
</el-dialog>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, nextTick } from 'vue';
import { ref, onMounted, nextTick, computed, onUnmounted } from 'vue';
import { ElImageViewer } from 'element-plus';
import { Session } from "/@/utils/storage";
// 定义 props
@@ -17,17 +45,47 @@ const props = defineProps<{
authSrc: string;
imgWidth?: string;
imgHeight?: string;
dialogTitle?: string;
}>();
// 定义响应式数据
const showIframe = ref(false);
const imgRef = ref<HTMLImageElement | null>(null);
const imageSrc = ref<string>('');
const imagePreviewVisible = ref(false);
const pdfDialogVisible = ref(false);
const authIframeRef = ref<HTMLIFrameElement | null>(null);
const windowHeight = ref(window.innerHeight);
// 计算 PDF iframe 的合适高度(优先使用外部传入的 imgHeight否则根据窗口高度动态计算
const pdfIframeHeight = computed(() => {
// 如果外部传入了 imgHeight优先使用
if (props.imgHeight) {
return props.imgHeight;
}
// 否则根据窗口高度动态计算dialog header 约 50pxpadding 约 40px留一些余量
return `${windowHeight.value - 120}px`;
});
// 监听窗口大小变化
const handleResize = () => {
windowHeight.value = window.innerHeight;
};
onMounted(() => {
window.addEventListener('resize', handleResize);
getImgSrcByToken();
});
onUnmounted(() => {
window.removeEventListener('resize', handleResize);
});
// 携带token请求img的src
const getImgSrcByToken = (src?: string) => {
if (props.authSrc.indexOf(".pdf") >= 0) {
showIframe.value = true;
pdfDialogVisible.value = true;
nextTick(() => {
const imgSrc = src || props.authSrc;
const tenantId = Session.getTenant();
@@ -52,12 +110,11 @@ const getImgSrcByToken = (src?: string) => {
request.send(null);
});
} else {
// 图片处理逻辑(已注释,如需要可取消注释并更新)
// 图片处理逻辑:加载后直接打开预览
showIframe.value = false;
pdfDialogVisible.value = false;
const imgSrc = src || props.authSrc;
const tenantId = Session.getTenant();
const img = imgRef.value;
if (!img) return;
const request = new XMLHttpRequest();
request.responseType = 'blob';
@@ -66,10 +123,8 @@ const getImgSrcByToken = (src?: string) => {
request.setRequestHeader('TENANT-ID', tenantId);
request.onreadystatechange = () => {
if (request.readyState == XMLHttpRequest.DONE && request.status == 200) {
img.src = URL.createObjectURL(request.response);
img.onload = () => {
URL.revokeObjectURL(img.src);
}
imageSrc.value = URL.createObjectURL(request.response);
imagePreviewVisible.value = true;
}
};
request.send(null);
@@ -86,8 +141,10 @@ defineExpose({
refreshImg
});
// 组件挂载时执行
onMounted(() => {
getImgSrcByToken();
});
</script>
<style scoped>
.pdf-preview-dialog :deep(.el-dialog__body) {
padding: 20px !important;
overflow-y: hidden !important;
}
</style>