Files
klp-oa/klp-ui/src/components/FilePreview/index.vue

185 lines
3.6 KiB
Vue
Raw Normal View History

<template>
<el-dialog
:title="title"
:visible.sync="dialogVisible"
:width="width"
:close-on-click-modal="false"
destroy-on-close
append-to-body
@close="handleClose"
>
<!-- 图片预览 -->
<div v-if="fileType === 'image'" class="preview-image">
<div class="image-controls">
<el-button type="primary" size="small" @click="zoomIn">放大</el-button>
<el-button type="primary" size="small" @click="zoomOut">缩小</el-button>
<el-button type="primary" size="small" @click="resetZoom">重置</el-button>
</div>
<div class="image-container" ref="imageContainer">
<img
:src="fileUrl"
:style="{ transform: `scale(${scale})` }"
class="preview-image-content"
@wheel="handleWheel"
/>
</div>
</div>
<!-- PDF预览 -->
<div v-else-if="fileType === 'pdf'" class="preview-pdf">
<iframe
:src="fileUrl"
class="preview-pdf-content"
frameborder="0"
/>
</div>
<!-- 不支持的文件类型 -->
<div v-else class="preview-not-supported">
<el-empty description="暂不支持预览此文件类型"></el-empty>
</div>
</el-dialog>
</template>
<script>
export default {
name: "FilePreview",
props: {
visible: {
type: Boolean,
default: false
},
fileUrl: {
type: String,
required: true
},
fileName: {
type: String,
default: "文件预览"
},
width: {
type: String,
default: "80%"
}
},
data() {
return {
dialogVisible: false,
scale: 1
};
},
watch: {
visible: {
handler(val) {
this.dialogVisible = val;
},
immediate: true
},
dialogVisible(val) {
if (!val) {
this.$emit('update:visible', false);
}
}
},
computed: {
title() {
return this.fileName || "文件预览";
},
fileType() {
const fileName = this.fileName || '';
const ext = fileName.split('.').pop()?.toLowerCase();
if (['png', 'jpg', 'jpeg', 'bmp', 'webp'].includes(ext)) {
return 'image';
} else if (ext === 'pdf') {
return 'pdf';
} else {
return 'other';
}
}
},
methods: {
handleClose() {
this.$emit('update:visible', false);
},
// 放大图片
zoomIn() {
if (this.scale < 3) {
this.scale += 0.1;
}
},
// 缩小图片
zoomOut() {
if (this.scale > 0.1) {
this.scale -= 0.1;
}
},
// 重置缩放
resetZoom() {
this.scale = 1;
},
// 鼠标滚轮缩放
handleWheel(event) {
event.preventDefault();
const delta = event.deltaY > 0 ? -0.1 : 0.1;
if ((this.scale > 0.1 || delta > 0) && (this.scale < 3 || delta < 0)) {
this.scale += delta;
}
}
}
};
</script>
<style scoped>
.preview-image {
width: 100%;
height: 70vh;
background-color: #f5f7fa;
display: flex;
flex-direction: column;
}
.image-controls {
padding: 10px;
display: flex;
gap: 10px;
border-bottom: 1px solid #e4e7ed;
background-color: #ffffff;
}
.image-container {
flex: 1;
overflow: auto;
display: flex;
justify-content: center;
align-items: flex-start;
padding: 20px;
}
.preview-image-content {
transition: transform 0.3s ease;
cursor: zoom-in;
max-width: 100%;
max-height: 100%;
}
.preview-image-content:hover {
cursor: zoom-in;
}
.preview-pdf {
width: 100%;
height: 70vh;
}
.preview-pdf-content {
width: 100%;
height: 100%;
}
.preview-not-supported {
display: flex;
justify-content: center;
align-items: center;
height: 400px;
}
</style>