uploadFile.js 6.05 KB
/**
 * create by xqq @2020-10-20 21:57:51
 */
import request from '@/utils/request';
import BMF from 'browser-md5-file';

const CTX = '/qgyun-service-fs-manager';
const URLS = {
    checkFile: CTX + '/file/checkFile',
    checkChunkExistUrl: CTX + '/file/checkChunkExist',
    uploadChunk: CTX + '/file/uploadChunk',
    uploadByExist: CTX + '/file/uploadByExist',
    mergeFileChunk: CTX + '/file/mergeFileChunk'
};
const CHUNKSIZE = 5 * 1024 * 1024;

let xhrData = {
    appCode: 'dev-uc',
    funCode: 'user'
};

// 检查文件是否存在
const checkFileExist = (fileMd5) => {
    return new Promise((resolve, reject) => {
        request({
            url: URLS.checkFile,
            method: 'get',
            params: {
                fileMd5: fileMd5
            }
        }).then(res => {
            resolve(res);
        }).catch(e => {
            reject(e);
        });
    });
};

// 检查分片是否存在
const checkChunkExist = (file, chunkIndex, chunkSize) => {
    return new Promise((resolve, reject) => {
        request({
            url: URLS.checkChunkExistUrl,
            method: 'get',
            params: {
                fileMd5: file.md5, // 文件唯一标记
                chunkIndex: chunkIndex, // 当前分块下标
                chunkSize: chunkSize // 当前分块大小
            }
        }).then(res => {
            resolve(res);
        }).catch(e => {
            reject(e);
        });
    });
};

// 获取已存在文件信息
const uploadByExist = (file, callback, progress) => {
    request({
        url: URLS.uploadByExist,
        method: 'get',
        params: {
            fileId: file.id,
            fileName: file.name,
            ...xhrData
        }
    }).then(res => {
        progress({
            loaded: file.size,
            total: file.size,
            percent: 100
        });
        callback(res);
    });
};

// 切片上传文件
const uploadChunkFile = (file, index, callback, progress) => {
    // 每CHUNKSIZE切割一段,这里只做一个切割演示,实际切割需要循环切割,
    const startSize = index * CHUNKSIZE;
    const endSize = (index + 1) * CHUNKSIZE > file.size ? file.size : (index + 1) * CHUNKSIZE;
    var slice = file.slice(startSize, endSize);
    checkChunkExist(file, index, endSize - startSize).then(res => {
        if (res.data === true) {
            uploadChunkFile(file, index + 1, callback, progress);
            const percentage = endSize / file.size * 100;
            progress({
                loaded: endSize,
                total: file.size,
                percent: percentage > 100 ? 100 : percentage
            });
        } else {
            var formData = new FormData();
            formData.append('file', slice);
            formData.append('name', file.name);
            formData.append('type', file.type);
            formData.append('fileMd5', file.md5);
            formData.append('size', file.size);
            formData.append('chunkIndex', index);
            formData.append('chunkSize', CHUNKSIZE);
            request({
                url: URLS.uploadChunk,
                method: 'post',
                data: formData,
                headers: {'Content-type': 'multipart/form-data'},
                onUploadProgress: progressEvent => {
                    console.log(progressEvent);
                    const percentage = (startSize + progressEvent.loaded) / file.size * 100;
                    progress({
                        loaded: startSize + progressEvent.loaded,
                        total: file.size,
                        percent: percentage > 100 ? 100 : percentage
                    });
                }
            }).then(res => {
                if (index + 1 >= file.chunks) {
                    mergeFile(file).then(res => {
                        if (res.success) {
                            callback(res);
                        } else {
                            callback(new Error('mergeFile error'));
                        }
                    }).catch(e => {
                        callback(e);
                    });
                } else {
                    uploadChunkFile(file, index + 1, callback, progress);
                }
            }).catch(e => {
                callback(new Error('checkChunkExist error'));
            });
        }
    });
};

// 合并文件
const mergeFile = (file) => {
    return new Promise((resolve, reject) => {
        var formData = new FormData();
        formData.append('fileName', file.name);
        formData.append('fileMd5', file.md5);
        formData.append('chunkCount', file.chunks);
        formData.append('chunkSize', CHUNKSIZE);
        request({
            url: URLS.mergeFileChunk,
            method: 'post',
            data: JSON.stringify({
                ...xhrData,
                fileName: file.name,
                fileMd5: file.md5,
                chunkCount: file.chunks,
                chunkSize: CHUNKSIZE
            }),
            headers: {
                'Content-type': 'application/json;charset=UTF-8'
            }
        }).then(res => {
            resolve(res);
        }).catch(e => {
            reject(e);
        });
    });
};

const uploadFile = (file, formData, callback, progress) => {
    const bmf = new BMF();
    if (formData) {
        xhrData = formData;
    }
    if (!progress) {
        progress = function() {
        };
    }
    bmf.md5(file, (err, md5) => {
        if (err) {
            callback(new Error('md5转化错误'));
        }
        file.md5 = md5;
        checkFileExist(file.md5).then(res => {
            if (!res.success) {
                callback(new Error('上传失败'));
                return;
            }
            if (res.data) {
                file.id = res.msg;
                uploadByExist(file, callback, progress);
                return;
            }
            const chunks = Math.ceil(file.size / CHUNKSIZE);
            file.chunks = chunks;
            uploadChunkFile(file, 0, callback, progress);
        }).catch(e => {
            callback(new Error('上传失败'));
        });
    });
};

export default uploadFile;