offer fix
This commit is contained in:
@@ -0,0 +1,181 @@
|
||||
Vue.component('tt-file-upload-light', {
|
||||
props: {
|
||||
/**
|
||||
* Allows multiple files to be selected.
|
||||
*/
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
/**
|
||||
* Text for the upload button.
|
||||
*/
|
||||
buttonText: {
|
||||
type: String,
|
||||
default: 'Datei hochladen'
|
||||
},
|
||||
/**
|
||||
* Optional icon for the upload button.
|
||||
*/
|
||||
buttonIcon: {
|
||||
type: String,
|
||||
default: 'fas fa-paperclip'
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<div class="tt-file-upload-light">
|
||||
<!-- Hidden file input, triggered by the button -->
|
||||
<input type="file" :multiple="multiple" @change="handleFileSelect" ref="fileInput" style="display: none;"/>
|
||||
|
||||
<!-- The button that users click to select files -->
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm" @click="triggerFileInput" :disabled="isUploading">
|
||||
<i :class="buttonIcon"></i>
|
||||
<span v-if="buttonText" class="ml-1">{{ buttonText }}</span>
|
||||
</button>
|
||||
|
||||
<!-- List of files being uploaded or already uploaded -->
|
||||
<div v-if="files.length > 0" class="file-list mt-2">
|
||||
<div v-for="(file, index) in files" :key="index" class="file-item">
|
||||
<div class="file-info">
|
||||
<i :class="fileIcon(file)" class="file-icon"></i>
|
||||
<span class="file-name">{{ file.file.name }}</span>
|
||||
<span class="file-size">({{ formatSize(file.file.size) }})</span>
|
||||
</div>
|
||||
<div class="file-status">
|
||||
<!-- Progress bar during upload -->
|
||||
<div v-if="file.status === 'uploading'" class="progress" style="height: 10px; width: 100px;">
|
||||
<div class="progress-bar" role="progressbar" :style="{ width: file.progress + '%' }" aria-valuenow="file.progress" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
<!-- Status text -->
|
||||
<span v-if="file.status === 'error'" class="text-danger small">Fehler</span>
|
||||
<span v-if="file.status === 'success'" class="text-success small">Fertig</span>
|
||||
|
||||
<!-- Remove button -->
|
||||
<button type="button" class="btn btn-link btn-sm text-danger p-0 ml-2" @click="removeFile(index)">
|
||||
<i class="fas fa-times"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
files: [], // Array to store file wrappers { file, progress, status, response }
|
||||
uploadUrl: window.TT_CONFIG['BASE_PATH'] + '/File/upload', // Standard file upload endpoint
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
/**
|
||||
* Checks if any file is currently being uploaded.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isUploading() {
|
||||
return this.files.some(f => f.status === 'uploading');
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* Programmatically clicks the hidden file input element.
|
||||
*/
|
||||
triggerFileInput() {
|
||||
this.$refs.fileInput.click();
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles the file selection event when the user chooses files.
|
||||
* @param {Event} event - The file input change event.
|
||||
*/
|
||||
handleFileSelect(event) {
|
||||
const selectedFiles = event.target.files;
|
||||
if (!selectedFiles) return;
|
||||
|
||||
// Create a wrapper for each file and start the upload
|
||||
Array.from(selectedFiles).forEach(file => {
|
||||
const fileWrapper = {
|
||||
file: file,
|
||||
progress: 0,
|
||||
status: 'pending', // Status: pending, uploading, success, error
|
||||
response: null,
|
||||
};
|
||||
this.files.push(fileWrapper);
|
||||
this.uploadFile(fileWrapper);
|
||||
});
|
||||
|
||||
// Reset the input value to allow selecting the same file again
|
||||
event.target.value = '';
|
||||
},
|
||||
|
||||
/**
|
||||
* Uploads a single file to the server.
|
||||
* @param {object} fileWrapper - The file object wrapper.
|
||||
*/
|
||||
async uploadFile(fileWrapper) {
|
||||
const formData = new FormData();
|
||||
formData.append('file', fileWrapper.file);
|
||||
fileWrapper.status = 'uploading';
|
||||
|
||||
try {
|
||||
const response = await axios.post(this.uploadUrl, formData, {
|
||||
onUploadProgress: (progressEvent) => {
|
||||
fileWrapper.progress = Math.round((progressEvent.loaded * 100) / progressEvent.total);
|
||||
}
|
||||
});
|
||||
|
||||
fileWrapper.status = 'success';
|
||||
fileWrapper.response = response.data;
|
||||
|
||||
// Emit an event with the successful upload data
|
||||
this.$emit('uploaded', response.data);
|
||||
window.notify('success', `${fileWrapper.file.name} erfolgreich hochgeladen.`);
|
||||
|
||||
} catch (error) {
|
||||
fileWrapper.status = 'error';
|
||||
console.error('File upload failed:', error);
|
||||
window.notify('error', `Upload von ${fileWrapper.file.name} fehlgeschlagen.`);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Public method to reset the component state, clearing all files.
|
||||
*/
|
||||
reset() {
|
||||
this.files = [];
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes a file from the list.
|
||||
* @param {number} index - The index of the file to remove.
|
||||
*/
|
||||
removeFile(index) {
|
||||
this.files.splice(index, 1);
|
||||
},
|
||||
|
||||
/**
|
||||
* Formats file size from bytes to a readable string.
|
||||
* @param {number} bytes - The file size in bytes.
|
||||
* @returns {string}
|
||||
*/
|
||||
formatSize(bytes) {
|
||||
if (bytes === 0) return '0 Bytes';
|
||||
const k = 1024;
|
||||
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a Font Awesome icon class based on the file status.
|
||||
* @param {object} file - The file wrapper object.
|
||||
* @returns {string}
|
||||
*/
|
||||
fileIcon(file) {
|
||||
switch (file.status) {
|
||||
case 'uploading': return 'fas fa-spinner fa-spin';
|
||||
case 'success': return 'fas fa-check-circle text-success';
|
||||
case 'error': return 'fas fa-exclamation-circle text-danger';
|
||||
default: return 'fas fa-file-alt';
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user