【若依Vue3批量上传图片、文件上传时传递其他参数的处理方式】
- 若依(ruoyi)
- 时间:2024-10-21 22:26
- 1111人已阅读
简介
由于近期需要处理图片批量上传的业务,去网上查关于Vue3的图片批量上传解决方案,发现资料确实比较繁杂,甚至很多都要收费,对于功能来说也有一些缺失,我就自己整理了一下包括 (批量图片上传、阿里云OSS、文件上传时传递其他参数到后台、批量上传时重命名处理),希望能帮到友友们!【注:在组件上传文件时不可以直接修改文件的属性如:file.name=XXX,因为文件属性属于只读】前端代码调用<
🔔🔔🔔好消息!好消息!🔔🔔🔔
有需要的朋友👉:联系凯哥
由于近期需要处理图片批量上传的业务,去网上查关于Vue3的图片批量上传解决方案,发现资料确实比较繁杂,甚至很多都要收费,对于功能来说也有一些缺失,我就自己整理了一下包括 (批量图片上传、阿里云OSS、文件上传时传递其他参数到后台、批量上传时重命名处理),希望能帮到友友们!
【注:在组件上传文件时不可以直接修改文件的属性如:file.name=XXX,因为文件属性属于只读】
前端代码
调用
<oss-image-batch-upload v-model="form.img" :isView="isUpdate" :matchName="matchName" :matchId="form.matchId"/>
批量上传图片
<template> <div> <el-upload // 打开多文件上传 :multiple="true" :action="uploadImgUrl" list-type="picture-card" :on-success="handleUploadSuccess" :before-upload="handleBeforeUpload" :limit="limit" :on-error="handleUploadError" :on-exceed="handleExceed" ref="imageUpload" :before-remove="handleDelete" :show-file-list="true" :headers="headers" // 除了file之外需要传递给后端的参数 :data="data" :file-list="fileList" :on-preview="handlePictureCardPreview" :class="{ hide: fileList.length >= limit }" :disabled="isView" > <el-icon> <plus/> </el-icon> </el-upload> <!-- 上传提示 --> <div v-if="showTip" v-show="!isView"> 请上传 <template v-if="fileSize"> 单张大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b> </template> <template v-if="fileType"> 格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b> </template> 的文件(单次最多上传100张) </div> <el-dialog v-model="dialogVisible" title="预览" width="800px" append-to-body > <img :src="dialogImageUrl" style="display: block; max-width: 100%; margin: 0 auto" /> </el-dialog> </div> </template> <script setup> import {getToken} from "@/utils/auth"; import {deleteFile} from "@/api/cms/oss/upload.js"; const props = defineProps({ modelValue: [String, Object, Array], // 调用组件传递的参数 isView: null, matchName: null, matchId: null, // 图片数量限制 limit: { type: Number, default: 100, }, // 大小限制(MB) fileSize: { type: Number, default: 20, }, // 文件类型, 例如['png', 'jpg', 'jpeg'] fileType: { type: Array, default: () => ["png", "jpg", "jpeg"], }, // 是否显示提示 isShowTip: { type: Boolean, default: true }, }); const data = { matchName: "", matchId: null }; const {proxy} = getCurrentInstance(); const emit = defineEmits(); const number = ref(0); const uploadList = ref([]); const dialogImageUrl = ref(""); const dialogVisible = ref(false); const baseUrl = import.meta.env.VITE_APP_BASE_API; const uploadImgUrl = ref(import.meta.env.VITE_APP_BASE_API + "/oss/uploadImageBatch") // 上传文件服务器地址); // 上传的图片服务器地址 const headers = ref({Authorization: "Bearer " + getToken()}); const fileList = ref([]); const showTip = computed( () => props.isShowTip && (props.fileType || props.fileSize) ); watch(() => props.modelValue, val => { if (val) { // 首先将值转为数组 const list = Array.isArray(val) ? val : props.modelValue.split(","); // 然后将数组转为对象数组 fileList.value = list.map(item => { if (typeof item === "string") { item = {name: item, url: item}; } return item; }); } else { fileList.value = []; return []; } }, {deep: true, immediate: true}); // 上传前loading加载 function handleBeforeUpload(file) { // 添加上传前的校验 if (props.matchName === null && props.matchId === null) { proxy.$modal.msgError( `请选择赛事!!!` ); return false; } // 赋值传递后端的参数 data.matchName = props.matchName; data.matchId = proxy.matchId; let isImg = false; if (props.fileType.length) { let fileExtension = ""; if (file.name.lastIndexOf(".") > -1) { fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1); } isImg = props.fileType.some(type => { if (file.type.indexOf(type) > -1) return true; if (fileExtension && fileExtension.indexOf(type) > -1) return true; return false; }); } else { isImg = file.type.indexOf("image") > -1; } if (!isImg) { proxy.$modal.msgError( `文件格式不正确, 请上传${props.fileType.join("/")}图片格式文件!` ); return false; } if (props.fileSize) { const isLt = file.size / 1024 / 1024 < props.fileSize; if (!isLt) { proxy.$modal.msgError(`上传头像图片大小不能超过 ${props.fileSize} MB!`); return false; } } proxy.$modal.loading("正在上传图片,请稍候..."); number.value++; } // 文件个数超出 function handleExceed() { proxy.$modal.msgError(`上传文件数量不能超过 ${props.limit} 个!`); } // 上传成功回调 function handleUploadSuccess(res, file) { if (res.code === 200) { uploadList.value.push({name: res.fileName, url: res.url}); uploadedSuccessfully(); } else { number.value--; proxy.$modal.closeLoading(); proxy.$modal.msgError(res.msg); proxy.$refs.imageUpload.handleRemove(file); uploadedSuccessfully(); } } // 删除图片 function handleDelete(file) { const findex = fileList.value.map(f => f.name).indexOf(file.name); if (findex > -1 && uploadList.value.length === number.value) { let fileUrl = fileList.value[findex].url deleteFile(fileUrl).then(res => { if (res.code === 200) { fileList.value.splice(findex, 1); emit("update:modelValue", listToString(fileList.value)); return false; } }) } } // 上传结束处理 function uploadedSuccessfully() { if (number.value > 0 && uploadList.value.length === number.value) { fileList.value = fileList.value.filter(f => f.url !== undefined).concat(uploadList.value); uploadList.value = []; number.value = 0; // 重置传递后端的参数 data.matchName = null; data.matchId = null; emit("update:modelValue", listToString(fileList.value)); proxy.$modal.closeLoading(); } } // 上传失败 function handleUploadError() { proxy.$modal.msgError("上传图片失败"); proxy.$modal.closeLoading(); } // 预览 function handlePictureCardPreview(file) { dialogImageUrl.value = file.url; dialogVisible.value = true; } // 对象转成指定字符串分隔 function listToString(list, separator) { let strs = ""; separator = separator || ","; for (let i in list) { if (undefined !== list[i].url && list[i].url.indexOf("blob:") !== 0) { strs += list[i].url.replace(baseUrl, "") + separator; } } return strs != "" ? strs.substr(0, strs.length - 1) : ""; } </script> <style scoped> // .el-upload--picture-card 控制加号部分 :deep(.hide .el-upload--picture-card) { display: none; } </style>
后端代码:
// 批量上传图片 @PostMapping("uploadImageBatch") public AjaxResult uploadImageBatch(@RequestParam("file") MultipartFile file, @RequestParam("matchName")String matchName,@RequestParam("matchId")String matchId) { //返回上传oss的url String url = ossUtils.uploadImageBatch(file,matchName,matchId); AjaxResult ajax = AjaxResult.success(); ajax.put("fileName", file.getOriginalFilename()); ajax.put("url", url); return ajax; }
OSS上传:
/** * 批量上传图片,统一命名 */ public synchronized String uploadImageBatch(MultipartFile file, String matchName, String matchId) { // 图片上传计数器 int num; Object obj = redisCache.getCacheObject("matchId_" + matchId); if (ObjectUtil.isNotEmpty(obj)) { num = Integer.parseInt(obj.toString()) + 1; //设置路径和文件名 String path = "dlz/image/" + new Date().getTime() + "-" + matchName + "-" + num; redisCache.setCacheObject("matchId_" + matchId, num, 365, TimeUnit.DAYS); return upload(file, path); } else { num = 1; //设置路径和文件名 String path = "dlz/image/" + new Date().getTime() + "-" + matchName + "-" + num; redisCache.setCacheObject("matchId_" + matchId, num, 365, TimeUnit.DAYS); return upload(file, path); } }
效果图: