文件预览统一组件封装

This commit is contained in:
2026-09-18 14:24:00 +08:00
parent da61394d36
commit 1d980ebcd0
6 changed files with 112 additions and 178 deletions
+63
View File
@@ -0,0 +1,63 @@
<script setup lang="ts">
import PDF from 'pdf-vue3'
import { VueOfficeDocx, VueOfficeExcel, VueOfficePptx } from 'vue3-office-preview'
import 'vue3-office-preview/lib/style.css'
const props = defineProps(['previewFile',])
// 判断文件类型
const handleFileType = (type:string) => {
if(type){
const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg']
const wordExtensions = ['docx']
const excelExtensions = ['xlsx']
const pptExtensions = ['pptx']
if(imageExtensions.includes(type)){
return 'image'
}
if(wordExtensions.includes(type)){
return 'word'
}
if(excelExtensions.includes(type)){
return 'excel'
}
if(pptExtensions.includes(type)){
return 'ppt'
}
if(type==='pdf'){
return 'pdf'
}
}
return ''
}
</script>
<template>
<div class="max-h-[70vh] overflow-x-auto rounded-lg border">
<!-- 图片预览 -->
<template v-if="handleFileType(previewFile?.file_type) === 'image'">
<div class="flex items-center justify-center py-2">
<NImage :src="previewFile?.file_url" />
</div>
</template>
<!-- Word 预览 -->
<template v-if="handleFileType(previewFile?.file_type) === 'word'">
<VueOfficeDocx :src="previewFile?.file_url" class="w-full items-center" />
</template>
<!-- Excel 预览 -->
<template v-if="handleFileType(previewFile?.file_type) === 'excel'">
<VueOfficeExcel :src="previewFile?.file_url" class="w-full items-center" />
</template>
<!-- Ppt 预览 -->
<template v-if="handleFileType(previewFile?.file_type) === 'ppt'">
<VueOfficePptx :src="previewFile?.file_url" class="w-full items-center" />
</template>
<!-- PDF 预览 -->
<template v-if="handleFileType(previewFile?.file_type) === 'pdf'">
<div class="h-[68vh]">
<PDF :src="previewFile?.file_url" class="w-full h-full items-center" />
</div>
</template>
</div>
</template>
+2
View File
@@ -90,6 +90,7 @@ declare module 'vue' {
NUpload: typeof import('naive-ui')['NUpload']
NWatermark: typeof import('naive-ui')['NWatermark']
PinToggler: typeof import('./../components/common/pin-toggler.vue')['default']
PreviewFile: typeof import('./../components/previewFile/index.vue')['default']
ReloadButton: typeof import('./../components/common/reload-button.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
@@ -184,6 +185,7 @@ declare global {
const NUpload: typeof import('naive-ui')['NUpload']
const NWatermark: typeof import('naive-ui')['NWatermark']
const PinToggler: typeof import('./../components/common/pin-toggler.vue')['default']
const PreviewFile: typeof import('./../components/previewFile/index.vue')['default']
const ReloadButton: typeof import('./../components/common/reload-button.vue')['default']
const RouterLink: typeof import('vue-router')['RouterLink']
const RouterView: typeof import('vue-router')['RouterView']
+6 -60
View File
@@ -9,10 +9,7 @@ import { uploadFileApi, deleteFileApi, fileListApi } from "@/service/api/file";
import { systemConfigApi } from '@/service/api/system';
import { getChangeDetailApi } from '@/service/api/change';
import { myTasksCloseMaterialApi } from '@/service/api/myTasks';
import PDF from 'pdf-vue3'
import { VueOfficeDocx, VueOfficeExcel, VueOfficePptx } from 'vue3-office-preview'
import 'vue3-office-preview/lib/style.css'
import previewComponent from '@/components/previewFile/index.vue'
const themeStore = useThemeStore();
const { routerPushByKey } = useRouterPush();
@@ -150,32 +147,6 @@ const removeFile = (index:number, fileIndex:number) => {
}
}
}
// 判断文件类型
const handleFileType = (type:string) => {
if(type){
const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg']
const wordExtensions = ['docx']
const excelExtensions = ['xlsx']
const pptExtensions = ['pptx']
if(imageExtensions.includes(type)){
return 'image'
}
if(wordExtensions.includes(type)){
return 'word'
}
if(excelExtensions.includes(type)){
return 'excel'
}
if(pptExtensions.includes(type)){
return 'ppt'
}
if(type==='pdf'){
return 'pdf'
}
}
return ''
}
// 打开预览
const preview = (file:any) => {
previewFile.value = file;
@@ -630,37 +601,12 @@ onMounted(async () => {
</template>
<template #default>
<div class="space-y-3">
<div class="flex flex-wrap gap-x-4 gap-y-1 text-xs text-slate-400">
<span>上传人{{ previewFile?.uploader_name }}</span>
<span>上传时间{{ previewFile?.created_at }}</span>
<span v-if="previewFile?.version">{{ `版本${previewFile?.version}受控` }}</span>
</div>
<div v-if="previewFile" class="max-h-[70vh] overflow-x-auto rounded-lg border">
<!-- 图片预览 -->
<template v-if="handleFileType(previewFile?.file_type) === 'image'">
<div class="flex items-center justify-center py-2">
<NImage :src="previewFile?.file_url" />
<div class="flex flex-wrap gap-x-4 gap-y-1 text-xs text-slate-400">
<span>上传人{{ previewFile?.uploader_name }}</span>
<span>上传时间{{ previewFile?.created_at }}</span>
<span v-if="previewFile?.version">{{ `版本${previewFile?.version}受控` }}</span>
</div>
</template>
<!-- Word 预览 -->
<template v-if="handleFileType(previewFile?.file_type) === 'word'">
<VueOfficeDocx :src="previewFile?.file_url" class="w-full items-center" />
</template>
<!-- Excel 预览 -->
<template v-if="handleFileType(previewFile?.file_type) === 'excel'">
<VueOfficeExcel :src="previewFile?.file_url" class="w-full items-center" />
</template>
<!-- Ppt 预览 -->
<template v-if="handleFileType(previewFile?.file_type) === 'ppt'">
<VueOfficePptx :src="previewFile?.file_url" class="w-full items-center" />
</template>
<!-- PDF 预览 -->
<template v-if="handleFileType(previewFile?.file_type) === 'pdf'">
<div class="h-[68vh]">
<PDF :src="previewFile?.file_url" class="w-full h-full items-center" />
</div>
</template>
</div>
<previewComponent v-if="previewFile" :previewFile="previewFile" />
</div>
</template>
</NModal>
+6 -59
View File
@@ -9,10 +9,7 @@ import { AiError, aiTypeJudge } from "@/service/api/ai";
import { systemConfigApi } from '@/service/api/system';
import { getChangeDetailApi } from '@/service/api/change';
import { myTasksDisposalSubmitApi, myTasksAddItemApi } from '@/service/api/myTasks';
import PDF from 'pdf-vue3'
import { VueOfficeDocx, VueOfficeExcel, VueOfficePptx } from 'vue3-office-preview'
import 'vue3-office-preview/lib/style.css'
import previewComponent from '@/components/previewFile/index.vue'
const themeStore = useThemeStore();
const { routerPushByKey } = useRouterPush();
@@ -226,31 +223,6 @@ const openPreview = (file:any) => {
previewFile.value = file;
previewModal.value = true;
}
// 判断文件类型
const handleFileType = (type:string) => {
if(type){
const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg']
const wordExtensions = ['docx']
const excelExtensions = ['xlsx']
const pptExtensions = ['pptx']
if(imageExtensions.includes(type)){
return 'image'
}
if(wordExtensions.includes(type)){
return 'word'
}
if(excelExtensions.includes(type)){
return 'excel'
}
if(pptExtensions.includes(type)){
return 'ppt'
}
if(type==='pdf'){
return 'pdf'
}
}
return ''
}
// 催办
const handleReminder = (m: any) => {
@@ -1115,37 +1087,12 @@ onMounted(async () => {
</template>
<template #default>
<div class="space-y-3">
<div class="flex flex-wrap gap-x-4 gap-y-1 text-xs text-slate-400">
<span>上传人{{ previewFile?.uploader_name }}</span>
<span>上传时间{{ previewFile?.created_at }}</span>
<span v-if="previewFile?.version">{{ `版本${previewFile?.version}受控` }}</span>
</div>
<div v-if="previewFile" class="max-h-[70vh] overflow-x-auto rounded-lg border">
<!-- 图片预览 -->
<template v-if="handleFileType(previewFile?.file_type) === 'image'">
<div class="flex items-center justify-center py-2">
<NImage :src="previewFile?.file_url" />
<div class="flex flex-wrap gap-x-4 gap-y-1 text-xs text-slate-400">
<span>上传人{{ previewFile?.uploader_name }}</span>
<span>上传时间{{ previewFile?.created_at }}</span>
<span v-if="previewFile?.version">{{ `版本${previewFile?.version}受控` }}</span>
</div>
</template>
<!-- Word 预览 -->
<template v-if="handleFileType(previewFile?.file_type) === 'word'">
<VueOfficeDocx :src="previewFile?.file_url" class="w-full items-center" />
</template>
<!-- Excel 预览 -->
<template v-if="handleFileType(previewFile?.file_type) === 'excel'">
<VueOfficeExcel :src="previewFile?.file_url" class="w-full items-center" />
</template>
<!-- Ppt 预览 -->
<template v-if="handleFileType(previewFile?.file_type) === 'ppt'">
<VueOfficePptx :src="previewFile?.file_url" class="w-full items-center" />
</template>
<!-- PDF 预览 -->
<template v-if="handleFileType(previewFile?.file_type) === 'pdf'">
<div class="h-[68vh]">
<PDF :src="previewFile?.file_url" class="w-full h-full items-center" />
</div>
</template>
</div>
<previewComponent v-if="previewFile" :previewFile="previewFile" />
</div>
</template>
</NModal>
+33 -3
View File
@@ -8,6 +8,7 @@ import { getColorWithOpacity, tagTextColor, tagBgColor, tagBorderColor } from '@
import { AiError, aiTypeJudge } from "@/service/api/ai";
import { systemConfigApi } from '@/service/api/system';
import { getChangeDetailApi } from '@/service/api/change';
import previewComponent from '@/components/previewFile/index.vue'
const themeStore = useThemeStore();
const { routerPushByKey } = useRouterPush();
@@ -53,6 +54,10 @@ const pssrlist = ref<{ g: string; type:number; na_flag:number; items: any[] }[]>
]);
// 验收评价
const acceptList = ref<any>([]);
// 当前预览文件
const previewFile = ref<any>(null);
// 预览文件弹框
const previewModal = ref<boolean>(false);
// 等级判断问题
const questions = ref<any>([
{
@@ -252,8 +257,9 @@ const downloadFile = (type: string) => {
}
};
// 变更附带资料预览
const previewFile = () => {
window.$message?.info('还没导入插件');
const openPreview = (file:any) => {
previewFile.value = file;
previewModal.value = true;
}
// 催办
@@ -536,7 +542,7 @@ onMounted(async () => {
</td>
<td>
<div class="flex items-center justify-center gap-2">
<NButton text type="primary" class="text-xs" @click="previewFile">预览</NButton>
<NButton text type="primary" class="text-xs" @click="openPreview(doc)">预览</NButton>
<NButton text type="primary" class="text-xs" @click="downloadFile('single')">下载</NButton>
</div>
</td>
@@ -958,6 +964,30 @@ onMounted(async () => {
</div>
</NDrawerContent>
</NDrawer>
<!-- 附件在线预览弹窗 -->
<NModal
v-model:show="previewModal"
preset="card"
:auto-focus="false"
:style="{ width: '80%', height: 'auto' }"
:segmented="{ content: true, footer: true }"
>
<template #header>
<div class="flex items-center gap-2 text-base font-semibold text-slate-800">
<Icon icon="akar-icons:file" class="size-18px" /> {{ previewFile?.file_name }}
</div>
</template>
<template #default>
<div class="space-y-3">
<div class="flex flex-wrap gap-x-4 gap-y-1 text-xs text-slate-400">
<span>上传人{{ previewFile?.uploader_name }}</span>
<span>上传时间{{ previewFile?.created_at }}</span>
<span v-if="previewFile?.version">{{ `版本${previewFile?.version}受控` }}</span>
</div>
<previewComponent v-if="previewFile" :previewFile="previewFile" />
</div>
</template>
</NModal>
</NSpin>
</NSpace>
</template>
@@ -9,10 +9,7 @@ import { useChangeStore } from '@/store/modules/change';
import { AiError, aiTypeJudge, aiLevelScore, aiApplication } from "@/service/api/ai";
import { uploadFileApi, deleteFileApi } from "@/service/api/file";
import Footer from './footer.vue'
import PDF from 'pdf-vue3'
import { VueOfficeDocx, VueOfficeExcel, VueOfficePptx } from 'vue3-office-preview'
import 'vue3-office-preview/lib/style.css'
import previewComponent from '@/components/previewFile/index.vue'
const themeStore = useThemeStore();
const changeStore = useChangeStore();
@@ -364,32 +361,6 @@ const renderSwitcherIcon = (node:any) => {
});
}
// 判断文件类型
const handleFileType = (type:string) => {
if(type){
const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg']
const wordExtensions = ['docx']
const excelExtensions = ['xlsx']
const pptExtensions = ['pptx']
if(imageExtensions.includes(type)){
return 'image'
}
if(wordExtensions.includes(type)){
return 'word'
}
if(excelExtensions.includes(type)){
return 'excel'
}
if(pptExtensions.includes(type)){
return 'ppt'
}
if(type==='pdf'){
return 'pdf'
}
}
return ''
}
// 上传资料
const onUploadFile = async (e:any) => {
const file = e.target.files[0];
@@ -818,32 +789,7 @@ defineExpose({form, questions, applyAiResult, generateLevel: useAiLevel})
<span>上传时间{{ previewFile?.created_at }}</span>
<span v-if="previewFile?.version">{{ `版本${previewFile?.version}受控` }}</span>
</div>
<div v-if="previewFile" class="max-h-[70vh] overflow-x-auto rounded-lg border">
<!-- 图片预览 -->
<template v-if="handleFileType(previewFile?.file_type) === 'image'">
<div class="flex items-center justify-center py-2">
<NImage :src="previewFile?.file_url" />
</div>
</template>
<!-- Word 预览 -->
<template v-if="handleFileType(previewFile?.file_type) === 'word'">
<VueOfficeDocx :src="previewFile?.file_url" class="w-full items-center" />
</template>
<!-- Excel 预览 -->
<template v-if="handleFileType(previewFile?.file_type) === 'excel'">
<VueOfficeExcel :src="previewFile?.file_url" class="w-full items-center" />
</template>
<!-- Ppt 预览 -->
<template v-if="handleFileType(previewFile?.file_type) === 'ppt'">
<VueOfficePptx :src="previewFile?.file_url" class="w-full items-center" />
</template>
<!-- PDF 预览 -->
<template v-if="handleFileType(previewFile?.file_type) === 'pdf'">
<div class="h-[68vh]">
<PDF :src="previewFile?.file_url" class="w-full h-full items-center" />
</div>
</template>
</div>
<previewComponent v-if="previewFile" :previewFile="previewFile" />
</div>
</template>
<template #footer>