feat(review-meeting): 添加文件预览对话框组件

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
pull/874/head
Codewoc 2026-04-10 15:05:04 +08:00
parent 6f931beed6
commit 422fd7fa2e
1 changed files with 144 additions and 0 deletions

View File

@ -0,0 +1,144 @@
<template>
<el-dialog
v-model="dialogVisible"
:title="previewTitle"
width="80%"
:close-on-click-modal="true"
class="file-preview-dialog"
@close="handleClose"
>
<div class="preview-container" v-loading="loading" element-loading-text="加载预览中...">
<div v-if="error" class="preview-error">
<el-result
icon="error"
title="预览加载失败"
:sub-title="error"
>
<template #extra>
<el-button type="primary" @click="handleOpenInNewWindow"></el-button>
</template>
</el-result>
</div>
<iframe
v-else-if="previewUrl"
:src="previewUrl"
class="preview-iframe"
frameborder="0"
@load="handleIframeLoad"
/>
<el-empty v-else-if="!loading" description="暂无预览内容" />
</div>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, computed, watch } from 'vue'
import { getAttachmentPreviewUrl, type GetAttachmentPreviewUrlParams } from '@/api/review/meeting'
interface Props {
modelValue: boolean
meetingId: number
attachmentType: 'agenda' | 'minutes'
fileName?: string
}
const props = withDefaults(defineProps<Props>(), {
fileName: ''
})
const emit = defineEmits<{
'update:modelValue': [value: boolean]
}>()
const dialogVisible = computed({
get: () => props.modelValue,
set: (val) => emit('update:modelValue', val)
})
const loading = ref(false)
const error = ref('')
const previewUrl = ref('')
const previewTitle = computed(() => {
const typeName = props.attachmentType === 'agenda' ? '议程附件' : '会议纪要'
return props.fileName ? `${props.fileName} - ${typeName}` : typeName
})
watch(() => props.modelValue, async (visible) => {
if (visible && props.meetingId) {
await loadPreviewUrl()
}
})
const loadPreviewUrl = async () => {
loading.value = true
error.value = ''
previewUrl.value = ''
try {
const params: GetAttachmentPreviewUrlParams = {
id: props.meetingId,
attachmentType: props.attachmentType
}
const url = await getAttachmentPreviewUrl(params)
if (!url) {
error.value = '未找到预览文件'
return
}
previewUrl.value = url
} catch (err: any) {
error.value = err.message || '获取预览地址失败'
} finally {
loading.value = false
}
}
const handleIframeLoad = () => {
loading.value = false
}
const handleClose = () => {
previewUrl.value = ''
error.value = ''
}
const handleOpenInNewWindow = () => {
if (previewUrl.value) {
window.open(previewUrl.value, '_blank')
}
}
</script>
<style scoped>
.file-preview-dialog :deep(.el-dialog__body) {
padding: 0;
height: 70vh;
}
.preview-container {
width: 100%;
height: 70vh;
display: flex;
align-items: center;
justify-content: center;
background: #f5f5f5;
}
.preview-iframe {
width: 100%;
height: 100%;
border: none;
background: white;
}
.preview-error {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
</style>