Files
continew-admin-ui/src/components/FilePreview/index.vue
KAI 51aceac988 refactor: 使用 vue-office 重构文件预览(移除KKFileView)
移除 KKFileView
使用 vue-office 重构文件预览
移除依赖  editor,md-editor-v3,editor-for-vue
2024-10-14 06:51:52 +00:00

165 lines
4.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<a-modal
v-model:visible="visible"
:width="width >= 1350 ? 1350 : '100%'"
:on-before-close="onClose"
:footer="false"
esc-to-close="esc-to-close"
@close="onClose"
>
<template #title>
{{ modalTitle }}
<div class="toolbar">
<a-tooltip position="tl" content="在新标签页打开">
<icon-launch style="cursor: pointer" @click="onOpen" />
</a-tooltip>
</div>
</template>
<a-spin :loading="loading" class="w-full mt--10">
<a-card class="preview-content">
<VueOfficePdf
v-if="filePreview.fileInfo?.fileType === 'pdf'"
:src="filePreview.fileInfo?.data"
class="h-full"
@rendered="renderedHandler"
@error="errorHandler"
/>
<VueOfficeDocx
v-else-if="WordTypes.includes(filePreview.fileInfo?.fileType || '')"
:src="filePreview.fileInfo?.data"
class="h-full"
@rendered="renderedHandler"
@error="errorHandler"
/>
<VueOfficeExcel
v-else-if="ExcelTypes.includes(filePreview.fileInfo?.fileType || '')"
:src="filePreview.fileInfo?.data"
style="height: 80vh; width: 100%"
:options="filePreview.excelConfig"
@rendered="renderedHandler"
@error="errorHandler"
/>
</a-card>
</a-spin>
</a-modal>
</template>
<script setup lang="ts">
import VueOfficePdf from '@vue-office/pdf'
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'
import { Message } from '@arco-design/web-vue'
import { useWindowSize } from '@vueuse/core'
import type { FilePreview } from '@/components/FilePreview/type'
import { ExcelTypes, WordTypes } from '@/constant/file'
const visible = ref<boolean>(false)
const loading = ref<boolean>(false)
const { width } = useWindowSize()
// 用于关闭弹框时销毁,释放内存
const blobUrl = ref<string>('')
// 文件预览对象
const filePreview = reactive<FilePreview>({
fileInfo: {},
excelConfig: {}
})
// 弹框标题
const modalTitle = computed(() => {
const { fileName, fileType } = filePreview.fileInfo || {}
return fileName && fileType ? `${fileName}.${fileType}` : '文件预览'
})
// 预览
const onPreview = (previewInfo: FilePreview) => {
filePreview.fileInfo = previewInfo.fileInfo
visible.value = true
loading.value = true
}
const renderedHandler = () => {
loading.value = false
}
const errorHandler = () => {
loading.value = false
Message.error('文件加载失败')
}
// 新标签页打开
const onOpen = () => {
const data = filePreview.fileInfo?.data
if (!data) {
console.error('没有数据提供')
return
}
let url: string | null = null
if (typeof data === 'string') {
// 如果是字符串,假设它是一个 URL直接使用
url = data
} else if (data instanceof Blob || data instanceof ArrayBuffer) {
// 如果之前创建了 Blob URL先释放
if (blobUrl.value) {
URL.revokeObjectURL(blobUrl.value)
}
// 如果是 Blob 或 ArrayBuffer则将其转换为 Blob
const blob = data instanceof Blob ? data : new Blob([data])
url = URL.createObjectURL(blob)
blobUrl.value = url
} else {
console.error('不支持的类型')
return
}
// 打开生成的 URL
window.open(url)
}
// 关闭弹框
const onClose = () => {
Object.assign(filePreview, {
fileInfo: {},
excelConfig: {}
})
loading.value = false
visible.value = false
// 关闭时释放 Blob URL
if (blobUrl.value) {
URL.revokeObjectURL(blobUrl.value)
blobUrl.value = ''
}
}
onUnmounted(() => {
if (blobUrl.value) {
URL.revokeObjectURL(blobUrl.value)
}
})
defineExpose({ onPreview })
</script>
<style scoped lang="scss">
.h-full {
height: 100vh;
}
.card {
background: white !important;
padding-bottom: 5px;
}
.toolbar {
position: absolute;
float: right;
right: 50px;
top: 10px;
}
</style>