Dateimodal überarbeiten und Dateitypen pflegen

This commit is contained in:
2026-05-19 12:47:51 +02:00
parent 941f1d819b
commit 5fc7cc9604
13 changed files with 360 additions and 319 deletions

View File

@@ -0,0 +1,6 @@
ALTER TABLE "filetags" ADD COLUMN "isSystemUsed" boolean DEFAULT false NOT NULL;
UPDATE "filetags"
SET "isSystemUsed" = true
WHERE COALESCE("createddocumenttype", '') <> ''
OR COALESCE("incomingDocumentType", '') <> '';

View File

@@ -281,6 +281,13 @@
"when": 1779840000000,
"tag": "0039_events_repeat_interval",
"breakpoints": true
},
{
"idx": 40,
"version": "7",
"when": 1779141600000,
"tag": "0040_filetag_system_types",
"breakpoints": true
}
]
}

View File

@@ -26,6 +26,8 @@ export const filetags = pgTable("filetags", {
createdDocumentType: text("createddocumenttype").default(""),
incomingDocumentType: text("incomingDocumentType"),
isSystemUsed: boolean("isSystemUsed").notNull().default(false),
archived: boolean("archived").notNull().default(false),
})

View File

@@ -116,12 +116,12 @@ async function ensureTenantFileDefaults(server: FastifyInstance, tenantId: numbe
const timestamp = new Date()
const tagDefaults = [
{ name: "Rechnungen", color: "#16a34a", createdDocumentType: "invoices" },
{ name: "Angebote", color: "#2563eb", createdDocumentType: "quotes" },
{ name: "Auftragsbestätigungen", color: "#7c3aed", createdDocumentType: "confirmationOrders" },
{ name: "Lieferscheine", color: "#ea580c", createdDocumentType: "deliveryNotes" },
{ name: "Eingangsrechnungen", color: "#dc2626", incomingDocumentType: "invoices" },
{ name: "Mahnungen", color: "#b91c1c", incomingDocumentType: "reminders" },
{ name: "Rechnungen", color: "#16a34a", createdDocumentType: "invoices", isSystemUsed: true },
{ name: "Angebote", color: "#2563eb", createdDocumentType: "quotes", isSystemUsed: true },
{ name: "Auftragsbestätigungen", color: "#7c3aed", createdDocumentType: "confirmationOrders", isSystemUsed: true },
{ name: "Lieferscheine", color: "#ea580c", createdDocumentType: "deliveryNotes", isSystemUsed: true },
{ name: "Eingangsrechnungen", color: "#dc2626", incomingDocumentType: "invoices", isSystemUsed: true },
{ name: "Mahnungen", color: "#b91c1c", incomingDocumentType: "reminders", isSystemUsed: true },
]
for (const tag of tagDefaults) {

View File

@@ -45,36 +45,42 @@ export default async function adminRoutes(server: FastifyInstance) {
name: "Rechnungen",
color: "#16a34a",
createdDocumentType: "invoices",
isSystemUsed: true,
},
{
tenant: tenantId,
name: "Angebote",
color: "#2563eb",
createdDocumentType: "quotes",
isSystemUsed: true,
},
{
tenant: tenantId,
name: "Auftragsbestätigungen",
color: "#7c3aed",
createdDocumentType: "confirmationOrders",
isSystemUsed: true,
},
{
tenant: tenantId,
name: "Lieferscheine",
color: "#ea580c",
createdDocumentType: "deliveryNotes",
isSystemUsed: true,
},
{
tenant: tenantId,
name: "Eingangsrechnungen",
color: "#dc2626",
incomingDocumentType: "invoices",
isSystemUsed: true,
},
{
tenant: tenantId,
name: "Mahnungen",
color: "#b91c1c",
incomingDocumentType: "reminders",
isSystemUsed: true,
},
])
.returning({

View File

@@ -968,6 +968,14 @@ export default async function resourceRoutes(server: FastifyInstance) {
//@ts-ignore
delete data.updatedBy; delete data.updatedAt;
if (resource === "filetags") {
delete data.isSystemUsed
if (oldRecord.isSystemUsed && data.archived === true) {
return reply.code(400).send({ error: "System-Dateitypen können nicht archiviert werden" })
}
}
if (portalCustomerId) {
data = {
...sanitizePortalCustomerUpdate(data),

View File

@@ -105,7 +105,22 @@ export const resourceConfig = {
numberRangeHolder: "vendorNumber",
},
files: {
table: files
table: files,
mtoLoad: [
"project",
"customer",
"contract",
"vendor",
"incominginvoice",
"plant",
"createddocument",
"vehicle",
"product",
"check",
"inventoryitem",
"authProfile",
"type",
],
},
folders: {
table: folders
@@ -113,6 +128,9 @@ export const resourceConfig = {
filetags: {
table: filetags
},
type: {
table: filetags
},
inventoryitems: {
table: inventoryitems,
numberRangeHolder: "articleNumber",
@@ -201,6 +219,11 @@ export const resourceConfig = {
tenantKey: "tenant_id",
searchColumns: ["first_name", "last_name", "full_name", "email", "employee_number"],
},
authProfile: {
table: authProfiles,
tenantKey: "tenant_id",
searchColumns: ["first_name", "last_name", "full_name", "email", "employee_number"],
},
letterheads: {
table: letterheads,

View File

@@ -1,8 +1,7 @@
<script setup>
const toast = useToast()
const dataStore = useDataStore()
const modal = useModal()
const props = defineProps({
documentData: {
type: Object,
@@ -15,353 +14,264 @@ const props = defineProps({
returnEmit: {
type: Boolean
},
})
const emit = defineEmits(["updateNeeded"])
const folders = ref([])
const filetypes = ref([])
const documentboxes = 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 () => {
const data = await useEntities("folders").select()
data.forEach(folder => {
let name = folder.name
const addParent = (item) => {
name = `${item.name} > ${name}`
if(item.parent){
addParent(data.find(i => i.id === item.parent))
} else {
folders.value.push({
id: folder.id,
name: name,
})
}
}
if(folder.parent) {
addParent(data.find(i => i.id === folder.parent))
} else {
folders.value.push({
id: folder.id,
name: folder.name,
})
}
})
filetypes.value = await useEntities("filetags").select()
//documentboxes.value = await useEntities("documentboxes").select()
selectedFiletype.value = getFiletypeId()
await getItemsBySelectedResource()
}
setup()
const updateDocument = async () => {
const {url, ...objData} = props.documentData
delete objData.url
delete objData.filetags
/*console.log(objData)
if(objData.project) objData.project = objData.project.id
if(objData.customer) objData.customer = objData.customer.id
if(objData.contract) objData.contract = objData.contract.id
if(objData.vendor) objData.vendor = objData.vendor.id
if(objData.plant) objData.plant = objData.plant.id
if(objData.createddocument) objData.createddocument = objData.createddocument.id
if(objData.vehicle) objData.vehicle = objData.vehicle.id
if(objData.product) objData.product = objData.product.id
if(objData.profile) objData.profile = objData.profile.id
if(objData.check) objData.check = objData.check.id
if(objData.inventoryitem) objData.inventoryitem = objData.inventoryitem.id
if(objData.incominginvoice) objData.incominginvoice = objData.incominginvoice.id*/
console.log(objData)
const {data,error} = await useEntities("files").update(objData.id, objData)
if(error) {
console.log(error)
} else {
console.log(data)
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"})
modal.close()
emit("updateNeeded")
//openShowModal.value = false
if (closeAfterUpdate) modal.close()
} catch (error) {
console.error(error)
toast.add({title: "Datei konnte nicht aktualisiert werden", color: "error"})
}
}
const archiveDocument = async () => {
props.documentData.archived = true
await updateDocument()
modal.close()
emit("update")
await updateDocument({archived: true}, true)
}
const resourceOptions = ref([
{label: 'Projekt', value: 'project', optionAttr: "name"},
{label: 'Kunde', value: 'customer', optionAttr: "name"},
{label: 'Lieferant', value: 'vendor', optionAttr: "name"},
{label: 'Fahrzeug', value: 'vehicle', optionAttr: "licensePlate"},
{label: 'Objekt', value: 'plant', optionAttr: "name"},
{label: 'Vertrag', value: 'contract', optionAttr: "name"},
{label: 'Produkt', value: 'product', optionAttr: "name"}
])
const resourceToAssign = ref("project")
const itemOptions = ref([])
const idToAssign = ref(null)
const getItemsBySelectedResource = async () => {
if(resourceToAssign.value === "project") {
itemOptions.value = await useEntities("projects").select()
} else if(resourceToAssign.value === "customer") {
itemOptions.value = await useEntities("customers").select()
} else if(resourceToAssign.value === "vendor") {
itemOptions.value = await useEntities("vendors").select()
} else if(resourceToAssign.value === "vehicle") {
itemOptions.value = await useEntities("vehicles").select()
} else if(resourceToAssign.value === "product") {
itemOptions.value = await useEntities("products").select()
} else if(resourceToAssign.value === "plant") {
itemOptions.value = await useEntities("plants").select()
} else if(resourceToAssign.value === "contract") {
itemOptions.value = await useEntities("contracts").select()
} else {
itemOptions.value = []
}
idToAssign.value = null
itemOptions.value = selectedResource.value?.entity
? await useEntities(selectedResource.value.entity).select()
: []
}
getItemsBySelectedResource()
const updateDocumentAssignment = async () => {
props.documentData[resourceToAssign.value] = idToAssign.value
await updateDocument()
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 folderToMoveTo = ref(null)
const moveFile = async () => {
const res = await useEntities("files").update(props.documentData.id, {folder: folderToMoveTo.value})
modal.close()
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 >
<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 props.documentData.filetags"
>
{{tag.name}}
</UBadge>
<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>
<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="false ? ['w-full'] : ['w-1/3']">
<PDFViewer
v-if="props.documentData.id && props.documentData.path.toLowerCase().includes('pdf')"
:file-id="props.documentData.id" />
<img
class=" w-full"
:src="props.documentData.url"
alt=""
v-else
/>
</div>
<div class="w-2/3 p-5" v-if="!false">
<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 label="Zuweisungen"/>
<table class="w-full">
<tr v-if="props.documentData.project">
<td>Projekt</td>
<td>
<nuxt-link :to="`/standardEntity/projects/show/${props.documentData.project.id}`">{{props.documentData.project.name}}</nuxt-link>
</td>
</tr>
<tr v-if="props.documentData.customer">
<td>Kunde</td>
<td>
<nuxt-link :to="`/standardEntity/customers/show/${props.documentData.customer.id}`">{{props.documentData.customer.name}}</nuxt-link>
</td>
</tr>
<tr v-if="props.documentData.vendor">
<td>Lieferant</td>
<td>
<nuxt-link :to="`/standardEntity/vendors/show/${props.documentData.vendor.id}`">{{props.documentData.vendor.name}}</nuxt-link>
</td>
</tr>
<tr v-if="props.documentData.createddocument">
<td>Ausgangsbeleg</td>
<td>
<nuxt-link :to="`/createDocument/show/${props.documentData.createddocument.id}`">{{props.documentData.createddocument.documentNumber}}</nuxt-link>
</td>
</tr>
<tr v-if="props.documentData.plant">
<td>Objekt</td>
<td>
<nuxt-link :to="`/standardEntity/plants/show/${props.documentData.plant.id}`">{{props.documentData.plant.name}}</nuxt-link>
</td>
</tr>
<tr v-if="props.documentData.contract">
<td>Vertrag</td>
<td>
<nuxt-link :to="`/standardEntity/contracts/show/${props.documentData.contract.id}`">{{props.documentData.contract.name}}</nuxt-link>
</td>
</tr>
<tr v-if="props.documentData.vehicle">
<td>Fahrzeug</td>
<td>
<nuxt-link :to="`/standardEntity/vehicles/show/${props.documentData.vehicle.id}`">{{props.documentData.vehicle.licensePlate}}</nuxt-link>
</td>
</tr>
<tr v-if="props.documentData.product">
<td>Artikel</td>
<td>
<nuxt-link :to="`/standardEntity/products/show/${props.documentData.product.id}`">{{props.documentData.product.name}}</nuxt-link>
</td>
</tr>
<tr v-if="props.documentData.inventoryitem">
<td>Inventarartikel</td>
<td>
<nuxt-link :to="`/standardEntity/inventoryitem/show/${props.documentData.inventoryitem.id}`">{{props.documentData.inventoryitem.name}}</nuxt-link>
</td>
</tr>
<tr v-if="props.documentData.check">
<td>Überprüfung</td>
<td>
<nuxt-link :to="`/standardEntity/checks/show/${props.documentData.check.id}`">{{props.documentData.check.name}}</nuxt-link>
</td>
</tr>
<tr v-if="props.documentData.profile">
<td>Mitarbeiter</td>
<td>
<nuxt-link :to="`/profiles/show/${props.documentData.profile.id}`">{{props.documentData.profile.fullName}}</nuxt-link>
</td>
</tr>
<tr v-if="props.documentData.incominginvoice">
<td>Eingangsrechnung</td>
<td>
<nuxt-link :to="`/incomingInvoices/show/${props.documentData.incominginvoice.id}`">{{props.documentData.incominginvoice.reference}}</nuxt-link>
</td>
</tr>
</table>
<USeparator class="my-3" label="Datei zuweisen"/>
<UFormField
label="Resource auswählen"
>
<USelectMenu
:items="resourceOptions"
v-model="resourceToAssign"
value-key="value"
label-key="label"
@change="getItemsBySelectedResource"
>
</USelectMenu>
</UFormField>
<UFormField
label="Eintrag auswählen:"
>
<USelectMenu
:items="itemOptions"
v-model="idToAssign"
:label-key="resourceOptions.find(i => i.value === resourceToAssign)? resourceOptions.find(i => i.value === resourceToAssign).optionAttr : 'name'"
value-key="id"
@change="updateDocumentAssignment"
></USelectMenu>
</UFormField>
<USeparator class="my-5" label="Datei verschieben"/>
<InputGroup class="w-full">
<USelectMenu
class="flex-auto"
v-model="folderToMoveTo"
value-key="id"
label-key="name"
:items="folders"
/>
<UButton
@click="moveFile"
variant="outline"
:disabled="!folderToMoveTo"
>Verschieben</UButton>
</InputGroup>
<USeparator class="my-5" label="Dateityp"/>
<InputGroup class="w-full">
<USelectMenu
class="flex-auto"
v-model="props.documentData.type"
value-key="id"
label-key="name"
:items="filetypes"
@change="updateDocument"
/>
</InputGroup>
<USeparator class="my-5" label="Dokumentenbox" />
<InputGroup class="w-full">
<USelectMenu
class="flex-auto"
v-model="props.documentData.documentbox"
value-key="id"
label-key="key"
:items="documentboxes"
@change="updateDocument"
/>
</InputGroup>
</div>
</div>
</UCard>
</template>
</UModal>
</template>
<style scoped>
.bigPreview {
width: 100%;
aspect-ratio: 1/ 1.414;
}
</style>

View File

@@ -394,6 +394,12 @@ const getPostSaveRoute = () => {
return null
}
const canArchiveItem = computed(() => {
if (!item.value?.id) return false
if (dataType.canArchiveFunction) return dataType.canArchiveFunction(item.value)
return true
})
const createItem = async () => {
let ret = null
@@ -461,7 +467,7 @@ const updateItem = async () => {
<template #right>
<ArchiveButton
color="error"
v-if="platform !== 'mobile'"
v-if="platform !== 'mobile' && canArchiveItem"
variant="outline"
:type="type"
@confirmed="useEntities(type).archive(item.id)"

View File

@@ -289,6 +289,11 @@ const links = computed(() => {
to: "/standardEntity/contracttypes",
icon: "i-heroicons-document-duplicate",
} : null,
featureEnabled("files") ? {
label: "Dateitypen",
to: "/standardEntity/filetags",
icon: "i-heroicons-tag",
} : null,
has("vehicles") && featureEnabled("vehicles") ? {
label: "Fahrzeuge",
to: "/standardEntity/vehicles",

View File

@@ -48,9 +48,13 @@ export const useFiles = () => {
}
})
console.log(res)
const fileDataById = new Map(data.map((file) => [file.id, file]))
return res.files
return (res.files || []).map((file) => ({
...file,
...(fileDataById.get(file.id) || {}),
url: file.url
}))
}
const selectSomeDocuments = async (documentIds, sortColumn = null, folder = null) => {
@@ -73,6 +77,7 @@ export const useFiles = () => {
const selectDocument = async (id) => {
let documentIds = [id]
if(documentIds.length === 0) return []
const fileData = await useEntities("files").selectSingle(id)
const res = await useNuxtApp().$api("/api/files/presigned",{
method: "POST",
body: {
@@ -80,9 +85,8 @@ export const useFiles = () => {
}
})
console.log(res)
return res.files[0]
const file = res.files?.[0] || null
return file ? {...file, ...(fileData || {}), url: file.url} : null
}
const downloadFile = async (id?: string, ids?: string[], returnAsBlob: Boolean = false) => {

View File

@@ -50,6 +50,10 @@ const type = route.params.type
const dataType = dataStore.dataTypes[type]
const canCreate = computed(() => {
if (type === "filetags") {
return true
}
if (type === "members") {
return has("members-create") || has("customers-create")
}

View File

@@ -2337,6 +2337,66 @@ export const useDataStore = defineStore('data', () => {
labelSingle: "Datei",
selectWithInformation: "*",
},
filetags: {
isArchivable: true,
label: "Dateitypen",
labelSingle: "Dateityp",
isStandardEntity: true,
redirect: true,
inputColumns: [
"Allgemeines",
"Automatik",
],
filters: [{
name: "Archivierte ausblenden",
default: true,
"filterFunction": function (row) {
return !row.archived
}
}],
canArchiveFunction: function (row) {
return !row.isSystemUsed
},
templateColumns: [
{
key: "name",
label: "Name",
title: true,
required: true,
inputType: "text",
inputColumn: "Allgemeines",
sortable: true,
},
{
key: "color",
label: "Farbe",
inputType: "text",
inputColumn: "Allgemeines",
},
{
key: "createdDocumentType",
label: "Ausgangsbeleg-Typ",
inputType: "text",
inputColumn: "Automatik",
},
{
key: "incomingDocumentType",
label: "Eingangsbeleg-Typ",
inputType: "text",
inputColumn: "Automatik",
},
{
key: "isSystemUsed",
label: "Systemtyp",
inputType: "bool",
inputColumn: "Automatik",
disabledFunction: function () {
return true
}
},
],
showTabs: [{label: "Informationen"}]
},
folders: {
isArchivable: true,
label: "Ordner",