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: `
{{ file.file.name }} ({{ formatSize(file.file.size) }})
Fehler Fertig
`, 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'; } } } })