195 lines
5.4 KiB
Vue
195 lines
5.4 KiB
Vue
<template>
|
|
<div class="flow-upload">
|
|
<div class="upload-progress">
|
|
<template v-for="(file, _) in files">
|
|
<div v-if="file.is_visible" class="uploading-file pt-1" :id="'file_upload_' + file.uniqueIdentifier"
|
|
:class="{ 'text-success': file.is_completed, 'text-danger': file.error }">
|
|
<h6 class="fileuploadname m-0">{{ file.name }}</h6>
|
|
<b-progress v-if="!file.is_completed" :value="file.progress_percent" :max="100"
|
|
show-progress class="h-15 my-1"></b-progress>
|
|
<div class="upload-status" v-if="file.error">
|
|
{{ file.error }}
|
|
</div>
|
|
<div class="size">{{ formatFileSize(file.size) }}</div>
|
|
</div>
|
|
</template>
|
|
</div>
|
|
<div class="file-drop-target" ref="file_drop_target">
|
|
{{ $gettext('Drag file(s) here to upload or') }}
|
|
<button ref="file_browse_target" class="file-upload btn btn-primary text-center ml-1" type="button">
|
|
<icon icon="cloud_upload"></icon>
|
|
{{ $gettext('Select File') }}
|
|
</button>
|
|
<small class="file-name"></small>
|
|
<input type="file" :accept="validMimeTypesList" :multiple="allowMultiple"
|
|
style="visibility: hidden; position: absolute;"/>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style lang="scss">
|
|
div.flow-upload {
|
|
div.upload-progress {
|
|
padding: 4px 0;
|
|
|
|
& > div {
|
|
padding: 3px 0;
|
|
}
|
|
|
|
.error {
|
|
color: #a00;
|
|
}
|
|
|
|
.progress {
|
|
margin-bottom: 5px;
|
|
|
|
.progress-bar {
|
|
border-bottom-width: 10px;
|
|
|
|
&::after {
|
|
height: 10px;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
div.file-drop-target {
|
|
padding: 25px 0;
|
|
text-align: center;
|
|
|
|
input {
|
|
display: inline;
|
|
}
|
|
}
|
|
}
|
|
</style>
|
|
|
|
<script>
|
|
import formatFileSize from '~/functions/formatFileSize.js';
|
|
import Flow from '@flowjs/flow.js';
|
|
import Icon from './Icon';
|
|
import _ from 'lodash';
|
|
|
|
export default {
|
|
name: 'FlowUpload',
|
|
components: {Icon},
|
|
emits: ['complete', 'success', 'error'],
|
|
props: {
|
|
targetUrl: String,
|
|
allowMultiple: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
validMimeTypes: {
|
|
type: Array,
|
|
default() {
|
|
return ['*'];
|
|
}
|
|
},
|
|
flowConfiguration: {
|
|
type: Object,
|
|
default() {
|
|
return {};
|
|
}
|
|
}
|
|
},
|
|
data() {
|
|
return {
|
|
flow: null,
|
|
files: []
|
|
};
|
|
},
|
|
mounted() {
|
|
let defaultConfig = {
|
|
target: () => {
|
|
return this.targetUrl
|
|
},
|
|
singleFile: !this.allowMultiple,
|
|
headers: {
|
|
'Accept': 'application/json',
|
|
'X-API-CSRF': App.api_csrf
|
|
},
|
|
withCredentials: true,
|
|
allowDuplicateUploads: true,
|
|
fileParameterName: 'file_data',
|
|
uploadMethod: 'POST',
|
|
testMethod: 'GET',
|
|
method: 'multipart',
|
|
maxChunkRetries: 3,
|
|
testChunks: false
|
|
};
|
|
let config = _.defaultsDeep({}, this.flowConfiguration, defaultConfig);
|
|
|
|
this.flow = new Flow(config);
|
|
|
|
this.flow.assignBrowse(this.$refs.file_browse_target);
|
|
this.flow.assignDrop(this.$refs.file_drop_target);
|
|
|
|
this.flow.on('fileAdded', (file) => {
|
|
file.progress_percent = 0;
|
|
file.is_completed = false;
|
|
file.error = null;
|
|
file.is_visible = true;
|
|
|
|
this.files.push(file);
|
|
return true;
|
|
});
|
|
|
|
this.flow.on('filesSubmitted', () => {
|
|
this.flow.upload();
|
|
});
|
|
|
|
this.flow.on('fileProgress', (file) => {
|
|
file.progress_percent = file.progress() * 100;
|
|
});
|
|
|
|
this.flow.on('fileSuccess', (file, message) => {
|
|
console.log(message);
|
|
|
|
file.is_completed = true;
|
|
let messageJson = JSON.parse(message);
|
|
this.$emit('success', file, messageJson);
|
|
});
|
|
|
|
this.flow.on('error', (message, file, chunk) => {
|
|
console.error(message, file, chunk);
|
|
|
|
let messageText = this.$gettext('Could not upload file.');
|
|
try {
|
|
if (typeof message !== 'undefined') {
|
|
let messageJson = JSON.parse(message);
|
|
if (typeof messageJson.message !== 'undefined') {
|
|
messageText = messageJson.message;
|
|
if (messageText.indexOf(': ') > -1) {
|
|
messageText = messageText.split(': ')[1];
|
|
}
|
|
}
|
|
}
|
|
} catch (e) {
|
|
}
|
|
|
|
file.error = messageText;
|
|
this.$emit('error', file, messageText);
|
|
});
|
|
|
|
this.flow.on('complete', () => {
|
|
_.forEach(this.files, (file) => {
|
|
file.is_visible = false;
|
|
});
|
|
|
|
this.$emit('complete');
|
|
});
|
|
},
|
|
computed: {
|
|
validMimeTypesList() {
|
|
return this.validMimeTypes.join(', ');
|
|
}
|
|
},
|
|
methods: {
|
|
formatFileSize(bytes) {
|
|
return formatFileSize(bytes);
|
|
}
|
|
}
|
|
};
|
|
</script>
|