需求一
实现上传文件夹功能;一级文件夹包含多个二级文件夹,一级文件夹命名随意,二级文件夹按照 【标签1-标签2-标签3】系列名-作者名
格式进行命名;手动触发上传(遍历循环上传文件);
代码实现
1、
<el-button size="small" class="uploadBtn" :disabled="loading">
<input ref="file" class="fileUploaderClass" type='file' name="file" webkitdirectory @change.stop="changesData" />
{{ fileLists.length === 0 ? '选择文件夹' : '重新选择' }}
</el-button>
<el-button type="primary" v-if="this.fileLists.length > 0" @click="uploadFile" size="small" :loading="loading" :disabled="loading">
{{ loading ? '上传中...' : '点击上传' }}
</el-button>
2、
/** 选择文件夹 */
changesData() {
/** 获取文件夹里面包含的图片文件对象 */
const fileList = this.$refs.file.files;
/** 子文件夹命名规范校验规则 */
const folderRegex = /^\【([^\]]+)\】(.+)-(.+)$/;
/** 子文件夹名称切割规则 */
const regex = /【(.*?)】(.*?)-(.*)/;
for (const i in fileList) {
if (fileList.hasOwnProperty(i)) {
/** 根据"/"切割文件路径 */
const webkitRelativePath = fileList[i].webkitRelativePath;
const parts = webkitRelativePath.split('/');
/** 一级文件夹名称 */
const oneFolderName = parts[0];
/** 二级文件夹名称 */
const secondaryFolderName = parts[1];
if (folderRegex.test(secondaryFolderName) === false) {
this.$message.error(`${secondaryFolderName} 文件夹命名不规范,请认真学习【命名规范】和详细检查【文件夹层级】之后重新上传`);
/** 清空input上传的文件 */
this.$refs.file.value = '';
break;
}
const secondaryFolderNameList = secondaryFolderName.match(regex);
/** match切割的结果为一个数组,数组第一项为字符串本身 */
/** 标签 */
const labels = secondaryFolderNameList[1];
/** 系列 */
const series = secondaryFolderNameList[2];
/** 作者 */
const author = secondaryFolderNameList[3];
/** 文件名称 */
const fileName = parts[2];
/** 图片文件的宽高获取 */
let _URL = window.URL || window.webkitURL;
let image = new Image();
image.src = _URL.createObjectURL(fileList[i]);
image.onload = () => {
/** 整合上传参数 */
let item = {
file: fileList[i],
labels: labels,
series: series,
author: author,
height: image.height,
width: image.width,
};
this.fileLists.push(item);
};
}
}
},
/** 上传文件 */
uploadFile() {
let successNum = 0;
let errorNum = 0;
let promises = [];
this.loading = true;
/** 遍历文件列表并创建上传请求的 Promise */
for (let i = 0; i < this.fileLists.length; i++) {
const uploadPromise = materialUpload({ ...this.fileLists[i] }).then((res) => {
if (res && res.code === 0) {
successNum += 1;
} else {
errorNum += 1;
}
}).catch((error) => {
errorNum += 1;
console.error('Error uploading file:', error);
});
promises.push(uploadPromise);
}
/** 使用 Promise.all 等待所有的上传请求完成 */
Promise.all(promises)
.finally(() => {
this.loading = false;
this.$message({
message: `成功上传文件 ${successNum} 个,失败 ${errorNum} 个。`,
duration: 30000,
showClose: true,
offset: 50
})
});
},
}
需求二
该需求与需求一的区别是,选择之后自动上传,并且文件夹名称没有格式限制,关于上传后的数据处理自由度更高,而且使用批量上传。
<div class="fileUpload">
<el-button class="uploadBtn" :disabled="loading">
<input ref="file" class="fileUploaderClass" type='file' name="file" webkitdirectory
@change.stop="changesData()" />
{{ this.form.labelList.length === 0 ? '选择文件夹' : '重新选择' }}
</el-button>
</div>
/** 选择文件夹 */
changesData(event) {
/** 文件夹里面包含的图片文件对象 */
let fileObject = this.$refs.file.files;
const formData = new FormData();
/** file对象不能为空 */
if (!(Object.keys(fileObject).length === 0 && fileObject.constructor === Object)) {
/** 遍历检查文件类型,逻辑自行处理 */
for (const i in fileObject) {
/** hasOwnProperty防止i为undefined */
if (fileObject.hasOwnProperty(i)) {
}
}
const params = {
url: 'xxx',
formData: formData
};
this.loading = true;
uploadFiles(params).then((res) => {
if (res && res.code === 0) {
/** 一级文件夹的文件,只能有一个斜杠,但斜杠前后字符不限 */
const folderRegex = /^[^/]+\/[^/]+$/;
let labelList = [];
res.data.forEach((item, index) => {
/** 根据"/"切割文件路径 */
const webkitRelativePath = item.name;
const parts = webkitRelativePath.split('/');
/** 一级文件夹名称 */
const oneFolderName = parts[0];
/** 如果文件路径是二级 */
if (folderRegex.test(item.name) === false) {
/** 二级文件夹名称 */
const secondaryFolderName = parts[1];
/** 文件名称 */
const fileName = parts[2];
/** ... 其他逻辑 */
} else {
/** ... 其他逻辑 */
}
})
if (labelList.length === 0) {
this.$confirm('未识别到素材内容,请注意所选文件夹层级结构、文件格式是否符合要求。', '提示', {
confirmButtonText: "确定",
showCancelButton: false
}).then(() => { }).catch(() => { });
} else {
this.$message.success('上传成功!');
/** 根据二级文件夹进行分类 */
this.form.labelList = labelList.reduce((acc, curr) => {
/** 检查结果数组中是否已存在具有相同 labelName 的对象 */
const existingItem = acc.find(item => item.labelName === curr.labelName);
if (existingItem) {
/** 如果存在,将当前对象添加到 materialList 数组中 */
existingItem.materialList.push({...});
}
} else {
/** 如果不存在,创建一个新的对象并添加到结果数组中 */
const item = {
labelName: curr.labelName,
materialList: [{ imageUrl: curr.imageUrl, name: curr.name, sort: 0 }]
};
acc.push(item);
}
return acc;
}, []);
};
} else {
/** 清空文件选择 */
this.$refs.file.value = '';
this.$confirm('未识别到素材内容,请注意所选文件夹层级结构、文件格式是否符合要求。', '提示', {
confirmButtonText: "确定",
showCancelButton: false
}).then(() => { }).catch(() => { });
}
}).finally(() => { this.loading = false; })
}
},
小结
记录学习 +1。