Files
FEDEO/frontend/components/DocumentDisplayModal.vue

278 lines
9.9 KiB
Vue

<script setup>
const toast = useToast()
const modal = useModal()
const props = defineProps({
documentData: {
type: Object,
required: true
},
openShowModal: {
type: Boolean,
required: false,
},
returnEmit: {
type: Boolean
},
})
const emit = defineEmits(["updateNeeded"])
const filetypes = ref([])
const getFiletypeId = () => props.documentData.type && typeof props.documentData.type === "object"
? props.documentData.type.id
: props.documentData.type || null
const selectedFiletype = ref(getFiletypeId())
const resourceOptions = ref([
{label: "Projekt", value: "project", entity: "projects", optionAttr: "name", route: (item) => `/standardEntity/projects/show/${item.id}`},
{label: "Kunde", value: "customer", entity: "customers", optionAttr: "name", route: (item) => `/standardEntity/customers/show/${item.id}`},
{label: "Lieferant", value: "vendor", entity: "vendors", optionAttr: "name", route: (item) => `/standardEntity/vendors/show/${item.id}`},
{label: "Fahrzeug", value: "vehicle", entity: "vehicles", optionAttr: "licensePlate", route: (item) => `/standardEntity/vehicles/show/${item.id}`},
{label: "Objekt", value: "plant", entity: "plants", optionAttr: "name", route: (item) => `/standardEntity/plants/show/${item.id}`},
{label: "Vertrag", value: "contract", entity: "contracts", optionAttr: "name", route: (item) => `/standardEntity/contracts/show/${item.id}`},
{label: "Produkt", value: "product", entity: "products", optionAttr: "name", route: (item) => `/standardEntity/products/show/${item.id}`},
{label: "Ausgangsbeleg", value: "createddocument", entity: "createddocuments", optionAttr: "documentNumber", route: (item) => `/createDocument/show/${item.id}`},
{label: "Eingangsrechnung", value: "incominginvoice", entity: "incominginvoices", optionAttr: "reference", route: (item) => `/incomingInvoices/show/${item.id}`},
{label: "Inventarartikel", value: "inventoryitem", entity: "inventoryitems", optionAttr: "name", route: (item) => `/standardEntity/inventoryitems/show/${item.id}`},
{label: "Überprüfung", value: "check", entity: "checks", optionAttr: "name", route: (item) => `/standardEntity/checks/show/${item.id}`},
{label: "Mitarbeiter", value: "authProfile", entity: "profiles", optionAttr: "fullName", route: (item) => `/staff/profiles/${item.id}`}
])
const resourceToAssign = ref("project")
const itemOptions = ref([])
const idToAssign = ref(null)
const selectedResource = computed(() => resourceOptions.value.find((option) => option.value === resourceToAssign.value))
const setup = async () => {
filetypes.value = await useEntities("filetags").select()
selectedFiletype.value = getFiletypeId()
await getItemsBySelectedResource()
}
const updateDocument = async (payload, closeAfterUpdate = false) => {
try {
await useEntities("files").update(props.documentData.id, payload, true)
Object.assign(props.documentData, payload)
toast.add({title: "Datei aktualisiert"})
emit("updateNeeded")
if (closeAfterUpdate) modal.close()
} catch (error) {
console.error(error)
toast.add({title: "Datei konnte nicht aktualisiert werden", color: "error"})
}
}
const archiveDocument = async () => {
await updateDocument({archived: true}, true)
}
const getItemsBySelectedResource = async () => {
idToAssign.value = null
itemOptions.value = selectedResource.value?.entity
? await useEntities(selectedResource.value.entity).select()
: []
}
const updateDocumentAssignment = async () => {
if (!selectedResource.value || !idToAssign.value) return
await updateDocument({[selectedResource.value.value]: idToAssign.value})
props.documentData[selectedResource.value.value] = itemOptions.value.find((item) => item.id === idToAssign.value) || idToAssign.value
idToAssign.value = null
}
const removeAssignment = async (assignment) => {
await updateDocument({[assignment.value]: null})
props.documentData[assignment.value] = null
}
const getAssignmentItem = (assignment) => {
const value = props.documentData[assignment.value]
return value && typeof value === "object" ? value : null
}
const getAssignmentLabel = (assignment) => {
const value = props.documentData[assignment.value]
if (!value) return ""
if (typeof value === "object") return value[assignment.optionAttr] || value.name || value.id
return value
}
const currentAssignments = computed(() =>
resourceOptions.value
.filter((assignment) => Boolean(props.documentData[assignment.value]))
.map((assignment) => ({
...assignment,
item: getAssignmentItem(assignment),
display: getAssignmentLabel(assignment)
}))
)
const displayedFileTags = computed(() => {
if (Array.isArray(props.documentData.filetags) && props.documentData.filetags.length) {
return props.documentData.filetags
}
if (props.documentData.type && typeof props.documentData.type === "object") {
return [props.documentData.type]
}
const selected = filetypes.value.find((filetype) => filetype.id === props.documentData.type)
return selected ? [selected] : []
})
const updateFiletype = async () => {
await updateDocument({type: selectedFiletype.value || null})
props.documentData.type = selectedFiletype.value || null
}
setup()
</script>
<template>
<UModal fullscreen>
<template #content>
<UCard :ui="{ body: { base: 'flex-1' }, ring: '', divide: 'divide-y divide-gray-100 dark:divide-gray-800' }" class="h-full">
<template #header>
<div class="flex flex-row justify-between">
<div class="flex items-center gap-2">
<UBadge
v-for="tag in displayedFileTags"
:key="tag.id"
>
{{tag.name}}
</UBadge>
</div>
<UButton color="gray" variant="ghost" icon="i-heroicons-x-mark-20-solid" class="-my-1" @click="modal.close()" />
</div>
</template>
<div class="flex flex-row">
<div class="w-1/3">
<PDFViewer
v-if="props.documentData.id && props.documentData.path.toLowerCase().includes('pdf')"
:file-id="props.documentData.id" />
<img
v-else
class="w-full"
:src="props.documentData.url"
alt=""
/>
</div>
<div class="w-2/3 p-5">
<UButtonGroup>
<ArchiveButton
color="error"
variant="outline"
type="files"
@confirmed="archiveDocument"
/>
<UButton
:to="props.documentData.url"
variant="outline"
icon="i-heroicons-arrow-top-right-on-square"
target="_blank"
>
Öffnen
</UButton>
</UButtonGroup>
<USeparator class="my-3" label="Zuweisungen"/>
<div class="space-y-2">
<div
v-for="assignment in currentAssignments"
:key="assignment.value"
class="flex items-center justify-between gap-3 rounded-md border border-gray-200 p-2 dark:border-gray-800"
>
<div class="min-w-0">
<div class="text-xs text-gray-500">{{ assignment.label }}</div>
<nuxt-link
v-if="assignment.item"
:to="assignment.route(assignment.item)"
class="block truncate font-medium text-primary"
>
{{ assignment.display }}
</nuxt-link>
<span v-else class="font-medium">{{ assignment.display }}</span>
</div>
<UButton
icon="i-heroicons-x-mark"
color="neutral"
variant="ghost"
@click="removeAssignment(assignment)"
/>
</div>
<UAlert
v-if="currentAssignments.length === 0"
icon="i-heroicons-link"
title="Noch keine Zuweisungen vorhanden"
color="neutral"
variant="soft"
/>
</div>
<USeparator class="my-3" label="Datei zuweisen"/>
<UFormField label="Bereich auswählen">
<USelectMenu
v-model="resourceToAssign"
:items="resourceOptions"
value-key="value"
label-key="label"
@update:model-value="getItemsBySelectedResource"
/>
</UFormField>
<UFormField class="mt-3" label="Eintrag auswählen">
<USelectMenu
v-model="idToAssign"
:items="itemOptions"
:label-key="selectedResource ? selectedResource.optionAttr : 'name'"
value-key="id"
:search-input="{ placeholder: 'Eintrag suchen...' }"
:filter-fields="[selectedResource ? selectedResource.optionAttr : 'name']"
/>
</UFormField>
<div class="mt-2 flex justify-end">
<UButton
icon="i-heroicons-link"
:disabled="!idToAssign"
@click="updateDocumentAssignment"
>
Zuweisen
</UButton>
</div>
<USeparator class="my-5" label="Dateityp"/>
<InputGroup class="w-full">
<USelectMenu
v-model="selectedFiletype"
class="flex-auto"
value-key="id"
label-key="name"
:items="filetypes"
@update:model-value="updateFiletype"
/>
</InputGroup>
</div>
</div>
</UCard>
</template>
</UModal>
</template>
<style scoped>
.bigPreview {
width: 100%;
aspect-ratio: 1/ 1.414;
}
</style>