278 lines
9.9 KiB
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>
|