
// 组件引用界面
<template>
<div>
<FileUpload ref="fileUploadRef" :fileId="ruleForm.fileId" :fileName="ruleForm.fileName" accept=".xlsx,.xls,.pdf,.doc,.docx,.jpg,.png" :max-size="50" tip-text="最大上传50MB" disabled />
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import FileUpload from '@workspace/components/fileUpload.vue'
const ruleForm = ref({
fileId:'',
fileName:''
})
</script>
//组件界面
<template>
<div class="file-upload-container">
<el-upload
class="upload-dragger"
drag
action="#"
:auto-upload="false"
:accept="accept"
:on-change="handleFileChange"
:on-remove="handleFileRemove"
:file-list="fileList"
:disabled="loading || disabled"
>
<i class="el-icon-upload" />
<div class="el-upload__text">拖拽文件到此处,或<em>点击上传</em></div>
<template #tip>
<div class="el-upload__tip">
<span v-if="!disabled">{{ tipText }}</span>
<span v-if="currentFile" style="color: #409eff; cursor: pointer; margin-left: 10px" @click="downloadFile"> 下载当前文件 </span>
</div>
</template>
</el-upload>
<!-- 加载状态 -->
<el-text v-if="loading" style="margin-left: 10px; color: #666">
<el-icon><Loading /></el-icon>
文件处理中...
</el-text>
</div>
</template>
<script setup>
import { ref, watch, defineProps, defineExpose, nextTick } from 'vue'
import { ElMessage } from 'element-plus'
import { downFile } from '@workspace/api/driver.ts' // 换成自己项目的
// 组件配置 Props
const props = defineProps({
// 文件ID,用于回显
fileId: { type: [String, Number], default: '' },
// 文件名
fileName: { type: String, default: '' },
// 文件类型,例如:.xlsx,.xls,.pdf,.doc,.docx
accept: { type: String, default: '' },
// 是否禁用
disabled: { type: Boolean, default: false },
// 文件大小限制,单位 MB
maxSize: { type: Number, default: 10 },
// 文件类型提示
tipText: { type: String, default: '支持所有格式文件,大小不超过 10MB' }
})
// 响应式数据
const fileList = ref([])
const loading = ref(false)
// 当前文件对象(包含raw/name/size/fileId)
const currentFile = ref(null)
// ===================== 核心:文件选择 =====================
const handleFileChange = (file) => {
console.log(file)
clearAll()
const rawFile = file.raw
// 大小校验
const maxSizeByte = props.maxSize * 1024 * 1024
if (rawFile.size > maxSizeByte) {
ElMessage.error(`文件大小不能超过 ${props.maxSize}MB!`)
return
}
// 赋值
fileList.value = [file]
currentFile.value = {
...file,
raw: rawFile,
name: file.name,
size: rawFile.size
}
ElMessage.success('文件选择成功!')
}
// ===================== 移除文件 =====================
const handleFileRemove = () => {
clearAll()
ElMessage.success('文件已移除')
}
// ===================== 下载文件 =====================
const downloadFile = () => {
if (!currentFile.value) return
// 本地文件直接下载
if (currentFile.value.raw) {
const blob = currentFile.value.raw
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = currentFile.value.name
a.click()
URL.revokeObjectURL(url)
ElMessage.success('文件下载成功')
return
}
// 通过 fileId 下载(接口)
if (props.fileId) {
downloadFileById(props.fileId, currentFile.value.name)
}
}
// 接口下载文件
const downloadFileById = async (fileId, fileName) => {
try {
loading.value = true
const res = await downFile(fileId)
const blob = new Blob([res.data])
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = fileName || `文件_${fileId}`
a.click()
URL.revokeObjectURL(url)
ElMessage.success('文件下载成功')
} catch (err) {
console.error('下载失败:', err)
ElMessage.error('文件下载失败')
} finally {
loading.value = false
}
}
// ===================== 清空数据 =====================
const clearAll = () => {
fileList.value = []
currentFile.value = null
}
// ===================== 监听 fileId 自动回显文件 =====================
watch(
() => [props.fileId, props.fileName],
async ([newId, newName]) => {
if (newId) {
loading.value = true
try {
// 仅构造文件对象,不读取内容(无预览)
const mockFile = {
name: newName || `文件_${newId}`,
status: 'success',
fileId: newId
}
fileList.value = [mockFile]
currentFile.value = mockFile
} catch (err) {
console.error('文件回显失败:', err)
clearAll()
} finally {
loading.value = false
}
} else {
nextTick(() => clearAll())
}
},
{ immediate: true }
)
// 暴露给父组件使用
defineExpose({
currentFile, // 当前文件对象
fileList, // 文件列表
clearAll, // 清空方法
downloadFile // 下载方法
})
</script>
<style scoped>
.file-upload-container {
width: 100%;
}
.upload-dragger {
--el-upload-dragger-bg-color: #fafafa;
}
:deep(.el-mp-upload.is-disabled) {
display: none !important;
}
</style>
<style>
/* 全局样式调整上传区域 */
.el-upload--disabled .el-upload__text {
color: #c0c4cc !important;
}
</style>
拖拽和点击上传都可实现




被折叠的 条评论
为什么被折叠?



