135 lines
3.6 KiB
Vue
135 lines
3.6 KiB
Vue
<script setup>
|
||
const props = defineProps({
|
||
item: { type: Object, required: true },
|
||
type: { type: String, required: true },
|
||
topLevelType: { type: String, required: true },
|
||
platform: { type: String, required: true }
|
||
})
|
||
|
||
const emit = defineEmits(["updateNeeded"])
|
||
const files = useFiles()
|
||
|
||
const availableFiles = ref([])
|
||
const activeFile = ref(null)
|
||
const showViewer = ref(false)
|
||
|
||
const setup = async () => {
|
||
if (props.item.files?.length > 0) {
|
||
availableFiles.value =
|
||
(await files.selectSomeDocuments(props.item.files.map((f) => f.id))) || []
|
||
}
|
||
}
|
||
setup()
|
||
|
||
// Datei öffnen (Mobile/Tablet)
|
||
function openFile(file) {
|
||
activeFile.value = file
|
||
showViewer.value = true
|
||
}
|
||
|
||
function closeViewer() {
|
||
showViewer.value = false
|
||
activeFile.value = null
|
||
}
|
||
|
||
// PDF oder Bild?
|
||
function isPdf(file) {
|
||
return file.path.includes("pdf")
|
||
}
|
||
function isImage(file) {
|
||
return file.mimetype?.startsWith("image/")
|
||
}
|
||
</script>
|
||
|
||
<template>
|
||
<UCard class="mt-5" :style="props.platform !== 'mobile' ? 'height: 80vh' : ''">
|
||
<template #header>
|
||
<span>Dateien</span>
|
||
</template>
|
||
|
||
<!-- Upload -->
|
||
<Toolbar>
|
||
<DocumentUpload
|
||
:type="props.topLevelType.substring(0, props.topLevelType.length - 1)"
|
||
:element-id="props.item.id"
|
||
@uploadFinished="emit('updateNeeded')"
|
||
/>
|
||
</Toolbar>
|
||
|
||
<!-- 📱 MOBILE: File Cards -->
|
||
<div v-if="props.platform === 'mobile'" class="space-y-3 mt-3">
|
||
<div
|
||
v-for="file in availableFiles"
|
||
:key="file.id"
|
||
class="p-4 border rounded-xl bg-gray-50 dark:bg-gray-900 flex items-center justify-between active:scale-95 transition cursor-pointer"
|
||
@click="openFile(file)"
|
||
>
|
||
<div>
|
||
<p class="font-semibold truncate max-w-[200px]">{{ file?.path?.split("/").pop() }}</p>
|
||
</div>
|
||
|
||
<UIcon
|
||
name="i-heroicons-chevron-right-20-solid"
|
||
class="w-5 h-5 text-gray-400"
|
||
/>
|
||
</div>
|
||
|
||
<UAlert
|
||
v-if="!availableFiles.length"
|
||
icon="i-heroicons-x-mark"
|
||
title="Keine Dateien verfügbar"
|
||
/>
|
||
</div>
|
||
|
||
<!-- 🖥️ DESKTOP: Classic List -->
|
||
<template v-else>
|
||
<DocumentList
|
||
:key="props.item.files.length"
|
||
:documents="availableFiles"
|
||
v-if="availableFiles.length > 0"
|
||
/>
|
||
|
||
<UAlert v-else icon="i-heroicons-x-mark" title="Keine Dateien verfügbar" />
|
||
</template>
|
||
</UCard>
|
||
|
||
<!-- 📱 PDF / IMG Viewer Slideover -->
|
||
<UModal v-model="showViewer" side="bottom" class="h-[100dvh]" fullscreen>
|
||
<!-- Header -->
|
||
<div class="p-4 border-b flex justify-between items-center flex-shrink-0">
|
||
<h3 class="font-bold truncate max-w-[70vw]">{{ activeFile?.path?.split("/").pop() }}</h3>
|
||
<UButton icon="i-heroicons-x-mark" variant="ghost" @click="closeViewer" />
|
||
</div>
|
||
|
||
<!-- Content -->
|
||
<div class="flex-1 overflow-y-auto m-2">
|
||
<!-- PDF -->
|
||
<div v-if="activeFile && isPdf(activeFile)" class="h-full">
|
||
<PDFViewer
|
||
:no-controls="true"
|
||
:file-id="activeFile.id"
|
||
location="fileviewer-mobile"
|
||
class="h-full"
|
||
/>
|
||
</div>
|
||
|
||
<!-- IMAGE -->
|
||
<div
|
||
v-else-if="activeFile && isImage(activeFile)"
|
||
class="p-4 flex justify-center"
|
||
>
|
||
<img
|
||
:src="activeFile.url"
|
||
class="max-w-full max-h-[80vh] rounded-lg shadow"
|
||
/>
|
||
</div>
|
||
|
||
<UAlert
|
||
v-else
|
||
title="Nicht unterstützter Dateityp"
|
||
icon="i-heroicons-exclamation-triangle"
|
||
/>
|
||
</div>
|
||
</UModal>
|
||
</template>
|