上传2

作者: Cherry丶小丸子 | 来源:发表于2022-06-30 00:10 被阅读0次
    <div id="app">
        <el-upload
            class="upload-demo"
            drag
            multiple
            limit="5"
            :file-list="fileList"
    
            :on-exceed="handleExceed"
            :on-change="handleChange"
            :before-upload="handleBeforeUpload"
    
            :http-request="uploadCustomRequest" // 自定义上传
            :http-request="uploadCustomRequestBlock" // 自定义分块上传
    
            :on-progress="handleProgress"
            :on-success="handleSuccess"
            :on-error="handleError"
    
            :on-preview="handlePreview"
    
            :before-remove="handleBeforeRemove"
            :on-remove="handleRemove">
    
            <el-button size="small" type="primary">点击上传</el-button>
            <div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div>
        </el-upload>
    </div>
    <script>
        import axios from "axios"; // 引入 axios,以便获取 axios 取消请求对象
        export default{
            data(){
                return {
                    fileList: [], // 上传成功的文件和回显的文件
                    cancelToken: [], // 每个上传文件的请求的 cancelToken
                    messageInstance: null, // message 提示信息的实例
                }
            },
            methods:{
                /**
                 * 文件超出个数限制时的钩子
                 * @param {Object} files
                 * @param {Object} fileList
                 */
                handleExceed(files, fileList){
                    this.$message.warning(`当前限制选择 5个文件,本次选择了 ${ files.length } 个文件,共选择了 ${ files.length + fileList.length } 个文件`);
                },
                /**
                 * 文件状态改变时的钩子,添加文件、上传成功和上传失败时都会被调用
                 * @param {Object} file
                 * @param {Object} fileList
                 */
                handleChange(file, fileList){
                    // 是否全部文件上传成功
                    let flag = fileList.every(item => item.status == 'success');
                    
                    // 全部文件上传成功,关闭 “上传中” 提示
                    if(flag){
                        this.messageInstance.close();
                        this.messageInstance = null;
                    }
                },
                /**
                 * 上传文件之前的钩子,参数为上传的文件,若返回 false 或者返回 Promise 且被 reject,则停止上传
                 * @param {Object} file
                 */
                handleBeforeUpload(file){
                    // 验证文件类型
                    const isAcceptType = /\.(txt|doc|docx|xls|xlsx|wps|pdf|jar|war|zip|rar|tar|gz)$/.test(file.name.substring(file.name.lastIndexOf('.')));
                    // 验证文件大小(1G),file.size 单位为 B,除以 1024 变为 KB,再除以 1024 变为 MB
                    const isAcceptSize = file.size / 1024 / 1024 <= 1024;
                    
                    if (!isAcceptType) {
                        this.$message.warning({
                            dangerouslyUseHTMLString: true,
                            message: '<p style="white-space: nowrap;">只能上传.txt、.doc、.docx、.xls,.xlsx、.wps、.pdf、.jar、.war、.zip、.rar、.tar、.gz格式的文件!</p>'
                        });
                    } else if (!isAcceptSize) {
                        this.$message.warning('上传的文件过大!');
                    }
    
                    // 如果符合文件类型及大小,则验证文件名是否重名
                    if(isAcceptType && isAcceptSize){
                        this.$axios.checkUploadFileDuplicateName({
                            fileName: info.file.name //文件名称
                        }).then(res => {
                            if(res.code == 0){
                                return true; // 允许上传
                            }else{
                                this.$message.error('文件名重复,请确认该文件是否已存在');
                                return false; // 不允许上传
                            }
                        })
                    }
    
                    // return isAcceptType && isAcceptSize; // 如果不需要验证重名,则使用此代码
                },
                /**
                 * 自定义上传
                 * @param {Object} info
                 */
                uploadCustomRequest(info){
                    const CancelToken = axios.CancelToken; // 获取 axios 取消请求对象
    
                    // 请求配置
                    let config = {
                        url: '/api/door/upload', // url、method、data 属性可以不写在此处,根据自己的 axios 封装方案
                        method: 'post',
                        data: {
                            file: info.file, // 上传的文件
                            hash: this.$uuid.v1(), // 生成的uuid(安装 vue-uuid 插件)
                            chunkNumber: 0
                        },
                        timeout: 0,
                        headers: {
                            'Content-Type': 'multipart/form-data',
                        },
                        cancelToken: new CancelToken(c => {
                            // this.cancelToken = c; // 单文件上传
                            this.cancelToken.push({ // 多文件上传
                                uid: info.file.uid,
                                cancelToken: c
                            })
                        }),
                        // 上传处理进度事件
                        onUploadProgress: progressEvent => {
                            // 获取当前上传进度
                            let complete = (progressEvent.loaded / progressEvent.total * 100 | 0);
                            let progress = { percent: complete };
                            info.onProgress(progress); // 调用 onProgress
                        }
                    };
    
                    // 将 config.data 转为 formData
                    let formData = new FormData();
                    Object.keys(config.data).forEach(key => {
                        const value = config.data[key];
                        formData.append(key, value);
                    });
                    config.data = formData; // 最后将 formData 重新赋值给 data,接口调用参数
    
                    // 打开 “上传中” 提示
                    if(this.messageInstance == null){
                        this.messageInstance = this.$message({
                            type: 'info',
                            message: '正在上传中,请稍后......,上传过程中,请勿关闭弹框或浏览器!',
                            duration: 0
                        })
                    }
    
                    // 调用接口-----文件上传
                    this.$axios.upload(config).then(result => {
                        if (result.code === 0) {
                            info.onSuccess(result); // 解决一直 loading 情况,调用 onSuccess
                        } else {
                            info.onError(); // 调用 onError
                        }
                    }).catch(err =>{
                        if(err.message == 'Operation canceled by the user'){
                            this.$message.warning('用户取消了上传操作')
                        }else{
                            info.onError(); // 调用 onError
                        }
                    });
                },
                /**
                 * 文件自定义分块上传
                 * @param {Object} info
                 */
                uploadCustomRequestBlock(info){
                    const CancelToken = axios.CancelToken; // 获取 axios 取消请求对象
    
                    let MAX_FILE_SIZE = 5 * 1024 * 1024; // 设置分割大小为(5242880 B)==(5M)
                    let index = 0; // 分割数
                    let file = info.file; // 获取文件
                    let fileSize = file.size; // 获取文件大小
                    let start = 0; // 文件切割起始位置
                    let end = 0; // 文件切割结束位置
                    let uuid = this.$uuid.v1(); // 创建uuid
                    let cutNum = Math.ceil(file.size / MAX_FILE_SIZE); // 文件分割的个数
    
                    // 文件上传进度回调函数
                    let handleUploadProgress = (progressEvent) => {
                        // 这里的上传百分比是切割块的百分比,所以要结合整个文件的大小算上传百分比
                        let percent = parseInt((progressEvent.loaded + start) / fileSize * 100);
                        // 如果格式化之后超过了 100% 之后,直接变成 100%
                        if (percent > 100) {
                            percent = 100;
                        }
                        let progress = { percent: percent };
                        info.onProgress(progress); // 调用 onProgress
                    }
                    // 上传成功的回调函数
                    let handleUploadSuccess = (res) => {
                        if (res.code == 0) {
                            // 调用全部分块合并接口
                            this.$axios.uploadBlockMerge({
                                data:{
                                    projectId: '0', //项目主键
                                    hash: uuid, //唯一值
                                    filename: file.name, //文件
                                    dataType: '3', //1 文档数据 2 空间数据 3 文件
                                    total: index + 1, // 文件总数
                                }
                            }).then(message => {
                                if (message.code == 0) {
                                    info.onSuccess(message); // 解决一直 loading 情况,调用onSuccess
                                } else {
                                    info.onError(); // 调用 onError
                                }
                            })
                        } else {
                            info.onError(); // 调用 onError
                        }
                    }
                    // 上传失败的回调函数
                    let handleUploadError = (err) => {
                        if(err.message == 'Operation canceled by the user'){
                            this.$message.warning('用户取消了上传操作')
                        }else{
                            info.onError(); // 调用 onError
                        }
                    }
                    // 文件上传切割方法
                    let uploadFileByBlock = () => {
                        if (start + MAX_FILE_SIZE >= fileSize) { // 判断切割的文件是否大于总文件大小
                            end = fileSize; // 如果大于总文件大小,将总文件大小直接作为一块
                        }else{
                            end = start + MAX_FILE_SIZE; // 如果小于总文件大小,
                        }
                        const fileBlock = file.slice(start, end); // 文件切割
                        const formData = new FormData(); // 创建 FormData 对象
                        // // 数据内容
                        // formData.append('file', fileBlock);
                        // // 第几块数据
                        // formData.append('index', index);
                        // // 上传数据大小
                        // formData.append('size', end - start);
    
                        // 请求配置
                        let config = {
                            data: {
                                file: fileBlock, // 上传的文件
                                hash: uuid, // 生成的 uuid
                                chunkNumber: index, // 第几块
                                dataType: '3', // 1 文档数据 2 空间数据 3 文件
                            },
                            timeout: 0,
                            headers: {
                                'Content-Type': 'multipart/form-data',
                            },
                            cancelToken: new CancelToken(c => {
                                // this.cancelToken = c; // 单文件上传
                                this.cancelToken.push({ // 多文件上传
                                    uid: info.file.uid,
                                    cancelToken: c
                                })
                            }),
                            // 上传处理进度事件
                            onUploadProgress: handleUploadProgress
                        };
    
                        Object.keys(config.data).forEach(key => {
                            const value = config.data[key];
                            formData.append(key, value);
                        });
                        config.data = formData; // 最后将 formData 重新赋值给 data,接口调用参数
    
                        // 打开 “上传中” 提示
                        if(this.messageInstance == null){
                            this.messageInstance = this.$message({
                                type: 'info',
                                message: '正在上传中,请稍后......,上传过程中,请勿关闭弹框或浏览器!',
                                duration: 0
                            })
                        }
    
                        // 调用接口-----文件分割上传
                        this.$axios.uploadBlock(config).then(res => {
                            // 判断当前分割是否是最后一块
                            if (start + MAX_FILE_SIZE >= fileSize) {
                                handleUploadSuccess(res); // 分割全部上传
                            } else {
                                start += MAX_FILE_SIZE;
                                index += 1;
                                uploadFileByBlock();
                            }
                        }).catch(err =>{
                            handleUploadError(err);
                        });
                    }
    
                    uploadFileByBlock(); // 调用文件上传切割方法
                },
                /**
                 * 文件上传时的钩子
                 * @param {Object} event
                 * @param {Object} file
                 * @param {Object} fileList
                 */
                handleProgress(event, file, fileList){
                    console.log(event)
                },
                /**
                 * 文件上传成功时的钩子
                 * @param {Object} response
                 * @param {Object} file
                 * @param {Object} fileList
                 */
                handleSuccess(response, file, fileList){
                    this.$message.success(`文件 ${ file.name } 上传成功!`);
    
                    // 删除 axios 取消请求对象
                    for(let i = 0; i < this.cancelToken.length; i++){
                        if(this.cancelToken[i].uid == file.uid){
                            this.cancelToken.splice(i, 1);
                            break;
                        }
                    }
    
                    this.fileList = fileList;
                },
                /**
                 * 文件上传失败时的钩子
                 * @param {Object} err
                 * @param {Object} file
                 * @param {Object} fileList
                 */
                handleError(err, file, fileList){
                    this.$message.error(`文件 ${ file.name } 上传失败!`);
    
                    // 删除 axios 取消请求对象
                    for(let i = 0; i < this.cancelToken.length; i++){
                        if(this.cancelToken[i].uid == file.uid){
                            this.cancelToken.splice(i, 1);
                            break;
                        }
                    }
                },
                /**
                 * 点击文件列表中已上传的文件时的钩子
                 * @param {Object} file
                 */
                handlePreview(file){
                    console.log(file)
                },
                /**
                 * 删除文件之前的钩子,参数为上传的文件和文件列表,若返回 false 或者返回 Promise 且被 reject,则停止删除
                 * @param {Object} file
                 * @param {Object} fileList
                 */
                handleBeforeRemove(file, fileList){
                    if (file && file.status === 'success') { // 阻止 before-upload 之后触发 before-remove 以及 on-remove 方法
                        return this.$msgbox({
                            title: '提示',
                            // message: `确定移除 ${ file.name }?`,
                            message: '此操作将永久删除此文件,是否继续', // MessageBox 消息正文内容
                            customClass: 'deleteAppMsgbox',
                            showConfirmButton: true, // 是否显示确定按钮
                            showCancelButton: true, // 是否显示取消按钮
                            confirmButtonText: '确定', // 确定按钮的文本内容
                            cancelButtonText: '取消', // 取消按钮的文本内容
                            confirmButtonClass: 'sureBtn', // 确定按钮的自定义类名
                            cancelButtonClass: 'cancelBtn', // 取消按钮的自定义类名
                            closeOnClickModal: false, // 是否可通过点击遮罩关闭 MessageBox
                            closeOnPressEscape: false, // 是否可通过按下 ESC 键关闭 MessageBox
                            type: 'warning'
                        }).then(() => {
                            // this.$emit('handleBeforeRemove', file, fileList, val => {
                                // if(!val){
                                    // reject();
                                // }
                            // });
    
                            this.$axios.questionBank.deleteProblemFile({
                                params: {
                                    filePath: file.response ? file.response.data.data.filePath[0] : file.url
                                }
                            }).then(res => {
                                if(res.data.data == '删除成功'){
                                    this.$message.success('删除成功');
                                }else{
                                    this.$message.error('删除失败');
                                    reject();
                                }
                            }).catch(err => {
                                this.$message.error('删除失败');
                                reject();
                            })
                        }).catch(() => {
                            this.$message.info('已取消删除');
                            reject();
                        })
                    }else if(file && file.status === 'uploading'){ // 当文件状态为 “上传中” ,则取消请求
                        for(let i = 0; i < this.cancelToken.length; i++){
                            if(this.cancelToken[i].uid == file.uid){
                                // 取消上传请求(message 参数是可选的),建议传递 message 字符串,这样请求在被取消后会被 catch 捕获,并提示给用户
                                this.cancelToken[i].cancelToken('Operation canceled by the user');
                                this.cancelToken.splice(i, 1); // 删除 axios 取消请求对象
                                break;
                            }
                        }
                    }
                },
                /**
                 * 文件列表移除文件时的钩子
                 * @param {Object} file
                 * @param {Object} fileList
                 */
                handleRemove(file, fileList){
                    if (file && (file.status === 'success' || file.status === 'uploading')) { // 阻止 before-upload 之后触发 before-remove 以及 on-remove 方法
                        // 是否全部文件上传成功
                        let flag = fileList.every(item => item.status == 'success');
    
                        // 全部文件上传成功,关闭 “上传中” 提示
                        if(flag){
                            if(this.messageInstance != null){
                                this.messageInstance.close();
                                this.messageInstance = null;
                            }               
                        }
    
                        this.fileList = fileList;
                    }
                },
            }
        }
    </script>
    
    注意:如果文件上传后,有提交需求,记得遍历 this.fileList 如果当前对象有 response 代表是上传的,如果没有代表回显的
    

    uploadCustomRequest 参数

    uploadingFileInfo.png

    已上传的文件

    upLoadedFileInfo.png

    相关文章

      网友评论

          本文标题:上传2

          本文链接:https://www.haomeiwen.com/subject/lhxxbrtx.html