hooks >useUploadByPices
/** * 分片上传成功后提交表单数据到服务器 * @module useUploadByPieces */ import { ref, reactive } from 'vue' import { useStore } from 'vuex' import { ElMessage } from 'element-plus' import { uploadByPieces } from '@/utils/LuploadPieces' /** * @method useUploadByPieces * @param {string} uploadUrl 上传文件的地址 * @param {Object} formParams form表单需要的额外参数 */ function useUploadByPieces(uploadUrl, formParams = { files: [] }) { const store = useStore() let formdata = reactive({ ...formParams }) let loading = ref(false) let LoadingText = ref('Loading...') let fileListshow = ref([]) let fileList = ref([]) /** * @method uploadByPiecesAction * @param {string} sendUrl 表单提交服务器的地址 */ function uploadByPiecesAction(sendUrl) { loading.value = true return new Promise((resolve, reject) => { // 重置相关数据 const reset = () => { fileList.value = [] formdata.files = [] fileListshow.value = [] } // 提交表单数据到服务端 const ajaxDispach = (sendUrl, formdata) => { console.log(55555, formdata) store.dispatch(sendUrl, formdata).then(res => { resolve('success') }).catch(err => { reset() reject(err) }).finally(() => { loading.value = false }) } if (fileList.value.length) { // 用户上传了附件的情况 LoadingText.value = '请耐心等待,附件上传中...' uploadByPieces({ files: fileList.value, pieceSize: 5, chunkUrl: uploadUrl, fileUrl: uploadUrl, validator: (text) => { // 上传文件合法性效验 reset() ElMessage.error(text) loading.value = false }, success: (res, fileName) => { if (res.data.code == 200) { // 文件的所有切片上传成功后 formdata.files.push(res.data.id) } if (fileList.value.length == formdata.files.length) { // 所有多选文件都上传成功后 LoadingText.value = 'Loading...' ajaxDispach(sendUrl, formdata) } }, error: (e) => { reset() reject(e) ElMessage.error('上传失败') return false } }) } else { // 用户没有上传附件的情况 formdata.files = [] ajaxDispach(sendUrl, formdata) } }) } return { formdata, loading, LoadingText, fileListshow, fileList, uploadByPiecesAction } } export default useUploadByPieces
utils > LuploadPieces
/* eslint-disable no-async-promise-executor */ import md5 from 'js-md5' import axios from 'axios' // http request拦截器 添加一个请求拦截器 axios.interceptors.request.use(function(config) { // Do something before request is sent const token = sessionStorage.getItem('T') const prjInternalNum = sessionStorage.getItem('prjInternalNum') if (token) { config.headers.bcmpUserToken = token } if (prjInternalNum) { config.headers.bcmpPrjInternalNum = prjInternalNum } return config }, function(error) { // Do something with request error return Promise.reject(error) }) /* * 分片上传函数 支持多个文件 * @param options * options.file 表示源文件 * options.pieceSize 表示需要分片的大小 默认是5m * options.chunkUrl 分片上传的后端地址 * options.fileUrl 整个文件的上传地址 * progress 进度回调 * success 成功回调 * error 失败回调 * validator 合法性验证回调 */ export const uploadByPieces = ({ files, chunkUrl, fileUrl, pieceSize = 5, progress, success, error, validator }) => { if (!files || !files.length) return // 上传过程中用到的变量 let fileList = [] // 总文件列表 let progressNum = 1 // 进度 let successAllCount = 0 // 上传成功的片数 let AllChunk = 0 // 所有文件的chunk数之和 let AllFileSize = 0 // 所有文件size // 验证方法 const validatorHandle = (files) => { let result = true let filesName = [] for (let i = 0; i < files.length; i++) { if (files[i].size <= 0) { // 为空字节文本 validator && validator('上传附件中不能有空文件') result = false filesName = [] break } filesName.push(files[i].name) } let filesNameSet = new Set(filesName) if (Array.from(filesNameSet).length != filesName.length) { validator && validator('上传附件中不能有重复的文件名') filesName = [] result = false } return result } // 获取md5 const readFileMD5 = (files) => { // 读取每个文件的md5 if (validatorHandle(files)) { return new Promise(async (resolve, reject) => { try { files.map(async (file, index) => { fileList.push({ name: file.name, file }) AllFileSize = AllFileSize + file.size if (index === files.length - 1) await readChunkMD5(fileList) }) resolve() } catch (e) { reject(e) } }) } } const getChunkInfo = (file, currentChunk, chunkSize) => { let start = (currentChunk - 1) * chunkSize let end = Math.min(file.size, start + chunkSize) let chunk = file.slice(start, end) return { start, end, chunk } } const loadChunk = (chunkFR) => { return new Promise(function(resolve, reject) { chunkFR.addEventListener('load', e => { let chunkBolb = e.target.result let chunkMD5 = md5(chunkBolb) resolve(chunkMD5) }, false) }) } // 针对每个文件进行chunk处理 const readChunkMD5 = (fileList) => { return new Promise(async (resolve, reject) => { try { fileList.map(async (currentFile, fileIndex) => { const chunkSize = pieceSize * 1024 * 1024 // 5MB一片 const chunkCount = Math.ceil(currentFile.file.size / chunkSize) // 总片数 AllChunk = AllChunk + chunkCount // 计算全局chunk数 // let fileSize = currentFile.file.size // 文件大小 // 针对单个文件进行chunk上传 let firstRes = {} let chunkMD5O = {} for (let i = 1; i < chunkCount + 1; i++) { const { chunk } = getChunkInfo(currentFile.file, i, chunkSize) let chunkFR = new FileReader() chunkFR.readAsArrayBuffer(chunk) let chunkMD5 = await loadChunk(chunkFR) chunkMD5O[`i${i}`] = chunkMD5 if (i === 1) { firstRes = await uploadChunk(currentFile, { chunkMD5: chunkMD5O.i1, chunk, currentChunk: 1, chunkCount, fileFirstHashCode: chunkMD5O.i1 }, fileIndex) if (firstRes && Number(firstRes.nextPart) > 2) { successAllCount = successAllCount + (Number(firstRes.nextPart) - 2) } } else { if (Number(firstRes.statusCode) !== 200) { if (Number(firstRes.nextPart) > 2) { if (Number(firstRes.nextPart) < i || Number(firstRes.nextPart) == i) { await uploadChunk(currentFile, { chunkMD5: chunkMD5O[`i${i}`], id: firstRes.id, chunk, currentChunk: i, chunkCount, fileFirstHashCode: chunkMD5O.i1 }, fileIndex) } } else { await uploadChunk(currentFile, { chunkMD5: chunkMD5O[`i${i}`], id: firstRes.id, chunk, currentChunk: i, chunkCount, fileFirstHashCode: chunkMD5O.i1 }, fileIndex) } } } } }) resolve() } catch (e) { reject(e) } }) } // 更新进度 const progressFun = () => { progressNum = Math.ceil(successAllCount / AllChunk * 100) progress && progress(progressNum) } const uploadChunk = (currentFile, chunkInfo, fileIndex) => { let fetchForm1 = new FormData() // if (chunkInfo.currentChunk == 1) { fetchForm1.append('fileHashCode', chunkInfo.fileFirstHashCode) // } fetchForm1.append('file', chunkInfo.chunk) fetchForm1.append('fileName', currentFile.name) fetchForm1.append('size', currentFile.file.size) fetchForm1.append('part', chunkInfo.currentChunk) fetchForm1.append('md5Code', chunkInfo.chunkMD5) fetchForm1.append('allCount', chunkInfo.chunkCount) if (chunkInfo.currentChunk != 1) { fetchForm1.append('fileIdFromWeb', chunkInfo.id) } return new Promise(async (resolve, reject) => { axios.post(chunkUrl, fetchForm1) .then(res => { if (chunkInfo.currentChunk == 1 && res.data.code == 200) { successAllCount = successAllCount + chunkInfo.chunkCount } else { successAllCount++ } progressFun() if (res.data.next_part) { let firstRes = { id: res.data.file_id, nextPart: res.data.next_part || 2, statusCode: res.data.code } resolve(firstRes) } else { resolve({ id: res.data.file_id, statusCode: res.data.code }) } success && success(res, currentFile.name) }).catch(e => { error && error(e) reject(e) }) }) } readFileMD5(files) // 开始执行代码 }
/**
* 分片上传成功后提交表单数据到服务器
* @moduleuseUploadByPieces
*/
import { ref, reactive } from 'vue'
import { useStore } from 'vuex'
import { ElMessage } from 'element-plus'
import { uploadByPieces } from '@/utils/LuploadPieces'
/**
* @methoduseUploadByPieces
* @param{string}uploadUrl 上传文件的地址
* @param{Object}formParams form表单需要的额外参数
*/
function useUploadByPieces(uploadUrl, formParams = { files: [] }) {
const store = useStore()
let formdata = reactive({ ...formParams })
let loading = ref(false)
let LoadingText = ref('Loading...')
let fileListshow = ref([])
let fileList = ref([])
/**
* @methoduploadByPiecesAction
* @param{string}sendUrl 表单提交服务器的地址
*/
function uploadByPiecesAction(sendUrl) {
loading.value = true
return new Promise((resolve, reject) => {
// 重置相关数据
const reset = () => {
fileList.value = []
formdata.files = []
fileListshow.value = []
}
// 提交表单数据到服务端
const ajaxDispach = (sendUrl, formdata) => {
console.log(55555, formdata)
store.dispatch(sendUrl, formdata).then(res => {
resolve('success')
}).catch(err => {
reset()
reject(err)
}).finally(() => {
loading.value = false
})
}
if (fileList.value.length) {
// 用户上传了附件的情况
LoadingText.value = '请耐心等待,附件上传中...'
uploadByPieces({
files: fileList.value,
pieceSize: 5,
chunkUrl: uploadUrl,
fileUrl: uploadUrl,
validator: (text) => {
// 上传文件合法性效验
reset()
ElMessage.error(text)
loading.value = false
},
success: (res, fileName) => {
if (res.data.code == 200) {
// 文件的所有切片上传成功后
formdata.files.push(res.data.id)
}
if (fileList.value.length == formdata.files.length) {
// 所有多选文件都上传成功后
LoadingText.value = 'Loading...'
ajaxDispach(sendUrl, formdata)
}
},
error: (e) => {
reset()
reject(e)
ElMessage.error('上传失败')
return false
}
})
} else {
// 用户没有上传附件的情况
formdata.files = []
ajaxDispach(sendUrl, formdata)
}
})
}
return {
formdata,
loading,
LoadingText,
fileListshow,
fileList,
uploadByPiecesAction
}
}
export default useUploadByPieces
LuploadPieces
浙公网安备 33010602011771号