Files
yihuiyong-ui/apps/web-ele/src/views/database/info/components/FileUploadDialog.vue
2026-04-23 11:37:37 +08:00

155 lines
3.6 KiB
Vue

<script setup lang="ts">
import { ref, watch, onMounted } from 'vue'
import { ElDialog, ElUpload, ElButton, ElMessage } from 'element-plus'
import type { UploadProps, UploadFile, UploadRawFile } from 'element-plus'
import { useUpload } from '#/components/upload/use-upload'
import { loadPdfLib,checkPdfJavaScript } from './pdf'
interface RowData {
id?: number
name?: string
[key: string]: any
}
const props = defineProps<{
visible: boolean
rowData: RowData | null
directory?: string
}>()
const emit = defineEmits<{
'update:visible': [value: boolean]
'success': [url: string, file: UploadFile]
}>()
const fileList = ref<UploadFile[]>([])
const uploading = ref(false)
const { uploadUrl, httpRequest } = useUpload(props.directory)
// 文件大小限制 10MB
const maxFileSize = 10
// 允许的文件类型
const acceptTypes = '.pdf'
// 监听弹窗关闭时清空文件列表
watch(() => props.visible, (val) => {
if (!val) {
fileList.value = []
uploading.value = false
}
})
// 上传前校验
const beforeUpload: UploadProps['beforeUpload'] = async (file: UploadRawFile) => {
const isLt20M = file.size / 1024 / 1024 < maxFileSize
if (!isLt20M) {
ElMessage.error(`文件大小不能超过 ${maxFileSize}MB!`)
return false
}
try {
await loadPdfLib()
const bytes = await file.arrayBuffer()
const hasJavaScript = await checkPdfJavaScript(bytes)
if (hasJavaScript) {
ElMessage.error('PDF 文件包含 JavaScript 代码,不允许上传')
return false
}
return true
} catch (error) {
console.error('PDF 检测失败:', error)
ElMessage.error('PDF 文件检测失败,请重试')
return false
}
}
// 自定义上传请求
const handleHttpRequest = (options: any) => {
uploading.value = true
return httpRequest(options.file)
}
// 上传成功
const handleSuccess: UploadProps['onSuccess'] = (response: any, file: UploadFile) => {
uploading.value = false
ElMessage.success('上传成功')
emit('success', response, file)
handleClose()
}
// 上传失败
const handleError: UploadProps['onError'] = () => {
uploading.value = false
ElMessage.error('上传失败,请重试')
}
// 关闭弹窗
const handleClose = () => {
emit('update:visible', false)
}
onMounted(async () => {
})
</script>
<template>
<ElDialog
:model-value="visible"
title="附件上传"
width="500px"
@update:model-value="emit('update:visible', $event)"
@close="handleClose"
>
<div class="upload-container">
<ElUpload
v-model:file-list="fileList"
class="upload-demo"
drag
:action="uploadUrl"
:http-request="handleHttpRequest"
:before-upload="beforeUpload"
:on-success="handleSuccess"
:on-error="handleError"
:accept="acceptTypes"
:limit="1"
:disabled="uploading"
>
<div
class="flex min-h-[200px] flex-col items-center justify-center py-8"
>
<span
class="icon-[mdi--cloud-upload-outline] mb-4 text-6xl text-gray-400"
></span>
<div class="text-base text-gray-600">
点击或拖拽文件到此区域上传
</div>
<div class="mt-2 text-sm text-gray-400">
支持 {{acceptTypes}} 文件
</div>
</div>
</ElUpload>
</div>
<template #footer>
<ElButton @click="handleClose" :disabled="uploading">取消</ElButton>
</template>
</ElDialog>
</template>
<style scoped>
.upload-container {
padding: 10px 0;
}
.upload-demo {
width: 100%;
}
:deep(.el-upload-dragger) {
width: 100%;
padding: 40px 20px;
}
</style>