161 lines
4.8 KiB
Vue
161 lines
4.8 KiB
Vue
<script setup>
|
|
// Falls useDropZone nicht auto-importiert wird:
|
|
// import { useDropZone } from '@vueuse/core'
|
|
|
|
const props = defineProps({
|
|
fileData: {
|
|
type: Object,
|
|
default: {
|
|
type: null
|
|
}
|
|
}
|
|
})
|
|
|
|
const emit = defineEmits(["uploadFinished"])
|
|
|
|
const modal = useModal()
|
|
// const profileStore = useProfileStore() // Wird im Snippet nicht genutzt, aber ich lasse es drin
|
|
|
|
const uploadInProgress = ref(false)
|
|
const availableFiletypes = ref([])
|
|
|
|
// 1. State für die Dateien und die Dropzone Referenz
|
|
const selectedFiles = ref([])
|
|
const dropZoneRef = ref(null)
|
|
|
|
// 2. Setup der Dropzone
|
|
const onDrop = (files) => {
|
|
// Wenn Dateien gedroppt werden, speichern wir sie
|
|
// files ist hier meist ein Array, wir stellen sicher, dass es passt
|
|
selectedFiles.value = files || []
|
|
}
|
|
|
|
const { isOverDropZone } = useDropZone(dropZoneRef, {
|
|
onDrop,
|
|
// Verhindert, dass der Browser das Bild einfach öffnet
|
|
preventDefaultForDrop: true,
|
|
})
|
|
|
|
// 3. Handler für den klassischen Datei-Input Klick
|
|
const onFileInputChange = (e) => {
|
|
if (e.target.files) {
|
|
selectedFiles.value = Array.from(e.target.files)
|
|
}
|
|
}
|
|
|
|
const setup = async () => {
|
|
availableFiletypes.value = await useEntities("filetags").select()
|
|
}
|
|
|
|
setup()
|
|
|
|
const uploadFiles = async () => {
|
|
// Validierung: Keine Dateien ausgewählt
|
|
if (!selectedFiles.value || selectedFiles.value.length === 0) {
|
|
alert("Bitte wählen Sie zuerst Dateien aus.") // Oder eine schönere Toast Notification
|
|
return
|
|
}
|
|
|
|
uploadInProgress.value = true;
|
|
|
|
let fileData = props.fileData
|
|
delete fileData.typeEnabled
|
|
|
|
// 4. Hier nutzen wir nun selectedFiles.value statt document.getElementById
|
|
await useFiles().uploadFiles(fileData, selectedFiles.value, [], true)
|
|
|
|
uploadInProgress.value = false;
|
|
emit("uploadFinished")
|
|
modal.close()
|
|
}
|
|
|
|
// Helper Funktion um Dateinamen anzuzeigen (da das Input Feld leer bleibt beim Droppen)
|
|
const fileNames = computed(() => {
|
|
if (!selectedFiles.value.length) return ''
|
|
return selectedFiles.value.map(f => f.name).join(', ')
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<UModal>
|
|
<div ref="dropZoneRef" class="relative h-full flex flex-col">
|
|
|
|
<div
|
|
v-if="isOverDropZone"
|
|
class="absolute inset-0 z-50 flex items-center justify-center bg-primary-500/10 border-2 border-primary-500 border-dashed rounded-lg backdrop-blur-sm transition-all"
|
|
>
|
|
<span class="text-xl font-bold text-primary-600 bg-white/80 px-4 py-2 rounded shadow-sm">
|
|
Dateien hier ablegen
|
|
</span>
|
|
</div>
|
|
|
|
<UCard :ui="{ body: { base: 'flex-1' }, ring: '', divide: 'divide-y divide-gray-100 dark:divide-gray-800' }">
|
|
<template #header>
|
|
<div class="flex items-center justify-between">
|
|
<h3 class="text-base font-semibold leading-6 text-gray-900 dark:text-white">
|
|
Datei hochladen
|
|
</h3>
|
|
<UButton
|
|
color="gray"
|
|
variant="ghost"
|
|
icon="i-heroicons-x-mark-20-solid"
|
|
class="-my-1"
|
|
@click="modal.close()"
|
|
:disabled="uploadInProgress"
|
|
/>
|
|
</div>
|
|
</template>
|
|
|
|
<UFormGroup
|
|
label="Datei:"
|
|
:help="selectedFiles.length > 0 ? `${selectedFiles.length} Datei(en) ausgewählt` : 'Ziehen Sie Dateien hierher oder klicken Sie'"
|
|
>
|
|
<UInput
|
|
v-if="selectedFiles.length === 0"
|
|
type="file"
|
|
id="fileUploadInput"
|
|
multiple
|
|
accept="image/jpeg, image/png, image/gif, application/pdf"
|
|
@change="onFileInputChange"
|
|
/>
|
|
|
|
<div v-if="selectedFiles.length > 0" class="mt-2 text-sm text-gray-500">
|
|
Ausgewählt: <span class="font-medium text-gray-700 dark:text-gray-300">{{ fileNames }}</span>
|
|
</div>
|
|
</UFormGroup>
|
|
|
|
<UFormGroup
|
|
label="Typ:"
|
|
class="mt-3"
|
|
>
|
|
<USelectMenu
|
|
option-attribute="name"
|
|
value-attribute="id"
|
|
searchable
|
|
searchable-placeholder="Suchen..."
|
|
:options="availableFiletypes"
|
|
v-model="props.fileData.type"
|
|
:disabled="!props.fileData.typeEnabled"
|
|
>
|
|
<template #label>
|
|
<span v-if="availableFiletypes.find(x => x.id === props.fileData.type)">{{availableFiletypes.find(x => x.id === props.fileData.type).name}}</span>
|
|
<span v-else>Kein Typ ausgewählt</span>
|
|
</template>
|
|
</USelectMenu>
|
|
</UFormGroup>
|
|
|
|
<template #footer>
|
|
<UButton
|
|
@click="uploadFiles"
|
|
:loading="uploadInProgress"
|
|
:disabled="uploadInProgress || selectedFiles.length === 0"
|
|
>Hochladen</UButton>
|
|
</template>
|
|
</UCard>
|
|
</div>
|
|
</UModal>
|
|
</template>
|
|
|
|
<style scoped>
|
|
/* Optional: Animationen für das Overlay */
|
|
</style> |