文件上传组件:UploadFile.vue
<template>
<div>
<el-upload
ref="upload"
class="upload-demo"
drag
multiple
:http-request="HttpUploadFile"
:file-list="config.fileList"
:on-success="handleFileSuccess"
:on-change="changeFileList"
:before-remove="fileRemove"
:accept="config.accept"
:auto-upload="false"
>
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
<div class="el-upload__text">将文件拖入此处,导入文件</div>
<div class="el-upload__text">
<img
:src="uploadfiletips"
alt=""
style="margin-top: 10px; height: 30px"
/>
</div>
</el-upload>
<el-progress class="circle-flag" type="circle" v-if="currentFlag" :percentage="percentage">
<template #default="{ percentage }">
<p class="percentage-value">{{ percentage }}%</p>
<p class="percentage-label">上传进度</p>
</template>
</el-progress>
</div>
</template>
<script setup>
import { ref, defineProps, defineExpose,toRefs,watch } from "vue";
import { UploadFilled } from "@element-plus/icons-vue";
import { ElNotification } from "element-plus";
import uploadfiletips from "@/assets/uploadfiletips.png";
import { uploadFile } from "@/api/upload";
const config = ref({
// 上传的文件列表
fileList: [],
accept: ".txt,.doc,.docx,.pdf,.xps"
});
const emits = defineEmits(["removeFile"])
const props = defineProps({
fileList: Array,
});
const { fileList } = toRefs(props)
const upload = ref();
watch(()=>fileList.value,(val) => {
config.value.fileList = []
if(val.length > 0){
val.forEach(item => {
item.name = item.fileName
config.value.fileList.push(item)
});
}
},{immediate: true,deep: true})
//文件上传成功后的钩子函数
const handleFileSuccess = () => {
config.value.fileList = [];
};
//fileList长度改变时触发
const changeFileList = (file, fileList) => {
config.value.fileList = fileList;
if(fileList.length > 101){
ElNotification({
title: "提示",
message: "文件数量不能超过100个",
type: "warning",
});
config.value.fileList = config.value.fileList.slice(0, 100);
}
if(file.size > 1024 * 1024 * 50){
let message = file.name + "文件大小不能超过50M!"
ElNotification({
title: "提示",
message: message,
type: "warning",
});
config.value.fileList = config.value.fileList.filter(item => item.size <= 1024 * 1024 * 50);
}
};
const fileRemove = (file) => {
if(file?.fileId){
// 删除 编辑 数据库文件
emits("removeFile",file)
}
};
// const fileData = ref();
const percentage = ref(0)
const currentFlag = ref(false)
const submitUpload = () => {
// 假设你有一个表单的引用(upload.value),但在这里我们不需要提交表单
// upload.value.submit(); // 这行代码可能不需要,取决于你的实现
let promise = new Promise((resolve, reject) => {
let newFileList = []
let oldFileList = []
config.value.fileList.forEach((item) => {
if(item?.fileId){
oldFileList.push(item)
}
else{
newFileList.push(item)
}
})
if (newFileList?.length > 0) {
currentFlag.value = true
uploadFile(newFileList,(progress)=>{
percentage.value = progress
}).then((res) => {
if (res.code === 200) {
config.value.fileList = [];
const result = parseCustomFilesArray(res.msg);
resolve(result); // 解析成功后,通过 resolve 返回结果
} else {
ElNotification({
title: "提示",
message: "上传失败",
type: "error",
});
resolve([]); // 即便上传失败,也通过 resolve 返回一个空数组
}
currentFlag.value = false;
newFileList = [];
}).catch((error) => {
reject(error); // 如果 uploadFile 抛出错误,通过 reject 拒绝 Promise
});
} else {
resolve([]); // 文件列表为空时,立即解析一个空数组
}
});
return promise; // 返回 Promise
};
const HttpUploadFile = () => {
// fileData.value.append("files", file.file); // append增加数据
};
function parseCustomFilesArray(data) {
// 移除开头和结尾的非法字符(如果有的话)
data = data.trim().replace(/^\[|\]$/g, '');
// 使用正则表达式找到所有的Files(...)部分
const filesMatches = data.match(/Files\(([^)]+)\)/g);
// 初始化结果数组
const result = [];
// 遍历每个匹配项
filesMatches?.forEach((match) => {
// 移除Files(...)的包装,并分割属性和值
const properties = match.slice(6, -1).split(', '); // 移除"Files("和")",并分割属性和值
// 初始化一个空对象来保存当前文件的属性
const file = {};
// 遍历每个属性和值
properties?.forEach((property) => {
// 分割属性和值
const [key, value] = property.split('=');
// 去除键和值周围的空白字符,并转换为合适的类型(这里我们假设所有值都是字符串)
file[key.trim()] = value.trim();
});
// 将文件对象添加到结果数组中
result.push(file);
});
// 假设您有一个名为"Files"的构造函数或类,您可以在这里实例化它
// 但由于这里只是一个简单的示例,我们将直接使用普通对象
// 返回结果数组
return result;
}
defineExpose({ submitUpload });
</script>
<style scoped>
:deep(.el-upload-dragger){
height: 160px;
padding: 0;
}
:deep(.el-icon--upload){
margin: 0;
padding: 0;
}
.circle-flag{
position: fixed;
right: 50%;
top: 50%;
transform: translate(50%, -50%);
z-index: 101;
}
:deep(.el-upload-list__item){
border: 1px dotted rgba(0, 34, 102, 0.63);
border-radius: 10px;
}
</style>
父组件触发
<upload-file
ref="uploadRef"
:fileList="reFileList"
@removeFile="removeFile"
/>
<el-button type="primary" @click="handleUploadSubmit">
提 交
</el-button>
const reFileList= ref([]);
const uploadRef = ref(null);
async function handleUploadSubmit(){
let results = await uploadRef.value.submitUpload();
console.log(results)
}
文件上传方法处理:upload.js
/*
* @Author : Zhao Han(2117961151qq.com)
* @Version : V1.0.0
* @Date : 2024-06-11 08:55:13
* @Description : 仅提供web界面支持文件上传
*/
import { getToken } from "@/utils/auth"
import axios from "axios"
export const uploadFile = async (files, onUploadProgress) => {
try {
// let dtoJsonString = JSON.stringify("data")
let formData = new FormData()
files.forEach((file) => {
if (file?.raw) formData.append(`files`, file.raw, file.raw.name);
})
// 添加 dtoJson 作为一个字符串字段
// formData.append('dtoJson', dtoJsonString);
const res = await axios({
url: process.env.VUE_APP_BASE_URL + '/record/files/test_upload',
method: 'POST',
headers: {
'Authorization': 'Bearer ' + getToken(),
'Content-Type': 'multipart/form-data'
},
onUploadProgress: (progressEvent) => {
// 计算上传进度
const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total);
// 调用传递给 uploadFile 函数的 onUploadProgress 回调
onUploadProgress(percentCompleted);
},
data: formData
})
return res.data
} catch (error) {
console.log(error)
}
}