feat: upload queue
parent
c9cc0d3d5d
commit
6ec6a23861
|
@ -1,34 +1,95 @@
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
|
import { files as api } from '@/api'
|
||||||
|
import throttle from 'lodash.throttle'
|
||||||
|
import buttons from '@/utils/buttons'
|
||||||
|
|
||||||
|
const UPLOADS_LIMIT = 5;
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
id: 0,
|
id: 0,
|
||||||
count: 0,
|
|
||||||
size: 0,
|
size: 0,
|
||||||
progress: []
|
progress: [],
|
||||||
|
queue: [],
|
||||||
|
uploads: {}
|
||||||
}
|
}
|
||||||
|
|
||||||
const mutations = {
|
const mutations = {
|
||||||
incrementId: (state) => {
|
|
||||||
state.id = state.id + 1
|
|
||||||
},
|
|
||||||
incrementSize: (state, value) => {
|
|
||||||
state.size = state.size + value
|
|
||||||
},
|
|
||||||
incrementCount: (state) => {
|
|
||||||
state.count = state.count + 1
|
|
||||||
},
|
|
||||||
decreaseCount: (state) => {
|
|
||||||
state.count = state.count - 1
|
|
||||||
},
|
|
||||||
setProgress(state, { id, loaded }) {
|
setProgress(state, { id, loaded }) {
|
||||||
Vue.set(state.progress, id, loaded)
|
Vue.set(state.progress, id, loaded)
|
||||||
},
|
},
|
||||||
reset: (state) => {
|
reset: (state) => {
|
||||||
state.id = 0
|
state.id = 0
|
||||||
state.size = 0
|
state.size = 0
|
||||||
state.count = 0
|
|
||||||
state.progress = []
|
state.progress = []
|
||||||
|
},
|
||||||
|
addJob: (state, item) => {
|
||||||
|
state.queue.push(item)
|
||||||
|
state.size += item.file.size
|
||||||
|
state.id++
|
||||||
|
},
|
||||||
|
moveJob(state) {
|
||||||
|
const item = state.queue[0]
|
||||||
|
state.queue.shift()
|
||||||
|
Vue.set(state.uploads, item.id, item)
|
||||||
|
},
|
||||||
|
removeJob(state, id) {
|
||||||
|
delete state.uploads[id]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default { state, mutations, namespaced: true }
|
const actions = {
|
||||||
|
upload: (context, item) => {
|
||||||
|
let uploadsCount = Object.keys(context.state.uploads).length;
|
||||||
|
|
||||||
|
let isQueueEmpty = context.state.queue.length == 0
|
||||||
|
let isUploadsEmpty = uploadsCount == 0
|
||||||
|
|
||||||
|
if (isQueueEmpty && isUploadsEmpty) {
|
||||||
|
buttons.loading('upload')
|
||||||
|
}
|
||||||
|
|
||||||
|
context.commit('addJob', item)
|
||||||
|
context.dispatch('processUploads')
|
||||||
|
},
|
||||||
|
finishUpload: (context, item) => {
|
||||||
|
context.commit('setProgress', { id: item.id, loaded: item.file.size })
|
||||||
|
context.commit('removeJob', item.id)
|
||||||
|
context.dispatch('processUploads')
|
||||||
|
},
|
||||||
|
processUploads: async (context) => {
|
||||||
|
let uploadsCount = Object.keys(context.state.uploads).length;
|
||||||
|
|
||||||
|
let isBellowLimit = uploadsCount < UPLOADS_LIMIT
|
||||||
|
let isQueueEmpty = context.state.queue.length == 0
|
||||||
|
let isUploadsEmpty = uploadsCount == 0
|
||||||
|
|
||||||
|
let isFinished = isQueueEmpty && isUploadsEmpty
|
||||||
|
let canProcess = isBellowLimit && !isQueueEmpty
|
||||||
|
|
||||||
|
if (isFinished) {
|
||||||
|
buttons.success('upload')
|
||||||
|
context.commit('reset')
|
||||||
|
context.commit('setReload', true, { root: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
if (canProcess) {
|
||||||
|
const item = context.state.queue[0];
|
||||||
|
context.commit('moveJob')
|
||||||
|
|
||||||
|
if (item.file.isDir) {
|
||||||
|
await api.post(item.path).catch(Vue.prototype.$showError)
|
||||||
|
} else {
|
||||||
|
let onUpload = throttle(
|
||||||
|
(event) => context.commit('setProgress', { id: item.id, loaded: event.loaded }),
|
||||||
|
100, { leading: true, trailing: false }
|
||||||
|
)
|
||||||
|
|
||||||
|
await api.post(item.path, item.file, item.overwrite, onUpload).catch(Vue.prototype.$showError)
|
||||||
|
}
|
||||||
|
|
||||||
|
context.dispatch('finishUpload', item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default { state, mutations, actions, namespaced: true }
|
|
@ -1,7 +1,4 @@
|
||||||
import store from '@/store'
|
import store from '@/store'
|
||||||
import { files as api } from '@/api'
|
|
||||||
import throttle from 'lodash.throttle'
|
|
||||||
import buttons from '@/utils/buttons'
|
|
||||||
import url from '@/utils/url'
|
import url from '@/utils/url'
|
||||||
|
|
||||||
export function checkConflict(files, items) {
|
export function checkConflict(files, items) {
|
||||||
|
@ -71,6 +68,7 @@ export function scanFiles(dt) {
|
||||||
} else if (entry.isDirectory) {
|
} else if (entry.isDirectory) {
|
||||||
const dir = {
|
const dir = {
|
||||||
isDir: true,
|
isDir: true,
|
||||||
|
size: 0,
|
||||||
path: `${directory}${entry.name}`
|
path: `${directory}${entry.name}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,67 +100,34 @@ export function scanFiles(dt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function handleFiles(files, path, overwrite = false) {
|
export function handleFiles(files, path, overwrite = false) {
|
||||||
if (store.state.upload.count == 0) {
|
|
||||||
buttons.loading('upload')
|
|
||||||
}
|
|
||||||
|
|
||||||
let promises = []
|
|
||||||
|
|
||||||
let onupload = (id) => (event) => {
|
|
||||||
store.commit('upload/setProgress', { id, loaded: event.loaded })
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = 0; i < files.length; i++) {
|
for (let i = 0; i < files.length; i++) {
|
||||||
let file = files[i]
|
let file = files[i]
|
||||||
|
|
||||||
if (!file.isDir) {
|
|
||||||
let filename = (file.fullPath !== undefined) ? file.fullPath : file.name
|
let filename = (file.fullPath !== undefined) ? file.fullPath : file.name
|
||||||
let filenameEncoded = url.encodeRFC5987ValueChars(filename)
|
let filenameEncoded = url.encodeRFC5987ValueChars(filename)
|
||||||
|
|
||||||
let id = store.state.upload.id
|
let id = store.state.upload.id
|
||||||
|
|
||||||
store.commit('upload/incrementSize', file.size)
|
let itemPath = path + filenameEncoded
|
||||||
store.commit('upload/incrementId')
|
|
||||||
store.commit('upload/incrementCount')
|
|
||||||
|
|
||||||
let promise = api.post(path + filenameEncoded, file, overwrite, throttle(onupload(id), 100)).finally(() => {
|
if (file.isDir) {
|
||||||
store.commit('upload/decreaseCount')
|
itemPath = path
|
||||||
})
|
|
||||||
|
|
||||||
promises.push(promise)
|
|
||||||
} else {
|
|
||||||
let uri = path
|
|
||||||
let folders = file.path.split("/")
|
let folders = file.path.split("/")
|
||||||
|
|
||||||
for (let i = 0; i < folders.length; i++) {
|
for (let i = 0; i < folders.length; i++) {
|
||||||
let folder = folders[i]
|
let folder = folders[i]
|
||||||
let folderEncoded = encodeURIComponent(folder)
|
let folderEncoded = encodeURIComponent(folder)
|
||||||
uri += folderEncoded + "/"
|
itemPath += folderEncoded + "/"
|
||||||
}
|
|
||||||
|
|
||||||
api.post(uri)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let finish = () => {
|
const item = {
|
||||||
if (store.state.upload.count > 0) {
|
id,
|
||||||
return
|
path: itemPath,
|
||||||
|
file,
|
||||||
|
overwrite
|
||||||
}
|
}
|
||||||
|
|
||||||
buttons.success('upload')
|
store.dispatch('upload/upload', item);
|
||||||
|
|
||||||
store.commit('setReload', true)
|
|
||||||
store.commit('upload/reset')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Promise.all(promises)
|
|
||||||
.then(() => {
|
|
||||||
finish()
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
finish()
|
|
||||||
this.$showError(error)
|
|
||||||
})
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue