572 lines
17 KiB
Vue
572 lines
17 KiB
Vue
<script setup>
|
|
const props = defineProps({
|
|
collapsed: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
})
|
|
|
|
const route = useRoute()
|
|
const auth = useAuthStore()
|
|
const { has } = usePermission()
|
|
const tenantExtraModules = computed(() => {
|
|
const modules = auth.activeTenantData?.extraModules
|
|
return Array.isArray(modules) ? modules : []
|
|
})
|
|
const showMembersNav = computed(() => {
|
|
return tenantExtraModules.value.includes("verein") && (has("members") || has("customers"))
|
|
})
|
|
const showMemberRelationsNav = computed(() => {
|
|
return tenantExtraModules.value.includes("verein") && has("members")
|
|
})
|
|
const isAdmin = computed(() => Boolean(auth.user?.is_admin))
|
|
const tenantFeatures = computed(() => auth.activeTenantData?.features || {})
|
|
const featureEnabled = (key) => tenantFeatures.value?.[key] !== false
|
|
const visibleItems = (items) => items.filter(item => item && !item.disabled)
|
|
const isRouteActive = (to) => {
|
|
if (!to) {
|
|
return false
|
|
}
|
|
|
|
if (to === '/') {
|
|
return route.path === '/'
|
|
}
|
|
|
|
return route.path === to || route.path.startsWith(`${to}/`)
|
|
}
|
|
|
|
const links = computed(() => {
|
|
const organisationChildren = [
|
|
has("tasks") && featureEnabled("tasks") ? {
|
|
label: "Aufgaben",
|
|
to: "/tasks",
|
|
icon: "i-heroicons-rectangle-stack"
|
|
} : null,
|
|
featureEnabled("planningBoard") ? {
|
|
label: "Plantafel",
|
|
to: "/organisation/plantafel",
|
|
icon: "i-heroicons-calendar-days"
|
|
} : null,
|
|
featureEnabled("wiki") ? {
|
|
label: "Wiki",
|
|
to: "/wiki",
|
|
icon: "i-heroicons-book-open"
|
|
} : null,
|
|
featureEnabled("files") ? {
|
|
label: "Dateien",
|
|
to: "/files",
|
|
icon: "i-heroicons-document"
|
|
} : null,
|
|
]
|
|
|
|
const documentChildren = [
|
|
featureEnabled("createdletters") ? {
|
|
label: "Anschreiben",
|
|
to: "/createdletters",
|
|
icon: "i-heroicons-document",
|
|
disabled: true
|
|
} : null,
|
|
featureEnabled("documentboxes") ? {
|
|
label: "Boxen",
|
|
to: "/standardEntity/documentboxes",
|
|
icon: "i-heroicons-archive-box",
|
|
disabled: true
|
|
} : null,
|
|
]
|
|
|
|
const communicationChildren = [
|
|
{
|
|
label: "Chat",
|
|
to: "/communication/chat",
|
|
icon: "i-heroicons-chat-bubble-left-right"
|
|
},
|
|
{
|
|
label: "Telefonie",
|
|
to: "/communication/phone",
|
|
icon: "i-heroicons-phone"
|
|
},
|
|
featureEnabled("helpdesk") ? {
|
|
label: "Helpdesk",
|
|
to: "/helpdesk",
|
|
icon: "i-heroicons-chat-bubble-left-right",
|
|
disabled: true
|
|
} : null,
|
|
featureEnabled("email") ? {
|
|
label: "E-Mail",
|
|
to: "/email/new",
|
|
icon: "i-heroicons-envelope",
|
|
disabled: true
|
|
} : null,
|
|
]
|
|
|
|
const contactsChildren = [
|
|
showMembersNav.value && featureEnabled("members") ? {
|
|
label: "Mitglieder",
|
|
to: "/standardEntity/members",
|
|
icon: "i-heroicons-user-group"
|
|
} : null,
|
|
has("customers") && featureEnabled("customers") ? {
|
|
label: "Kunden",
|
|
to: "/standardEntity/customers",
|
|
icon: "i-heroicons-user-group"
|
|
} : null,
|
|
has("vendors") && featureEnabled("vendors") ? {
|
|
label: "Lieferanten",
|
|
to: "/standardEntity/vendors",
|
|
icon: "i-heroicons-truck"
|
|
} : null,
|
|
has("contacts") && featureEnabled("contactsList") ? {
|
|
label: "Ansprechpartner",
|
|
to: "/standardEntity/contacts",
|
|
icon: "i-heroicons-user-group"
|
|
} : null,
|
|
]
|
|
|
|
const staffChildren = [
|
|
featureEnabled("staffProfiles") ? {
|
|
label: "Mitarbeiterprofile",
|
|
to: "/staff/profiles",
|
|
icon: "i-heroicons-user-group"
|
|
} : null,
|
|
featureEnabled("teams") ? {
|
|
label: "Teams",
|
|
to: "/standardEntity/teams",
|
|
icon: "i-heroicons-users"
|
|
} : null,
|
|
featureEnabled("staffTime") ? {
|
|
label: "Zeiten",
|
|
to: "/staff/time",
|
|
icon: "i-heroicons-clock",
|
|
} : null,
|
|
]
|
|
|
|
const accountingChildren = [
|
|
featureEnabled("createDocument") ? {
|
|
label: "Ausgangsbelege",
|
|
to: "/createDocument",
|
|
icon: "i-heroicons-document-text"
|
|
} : null,
|
|
featureEnabled("serialInvoice") ? {
|
|
label: "Serienvorlagen",
|
|
to: "/createDocument/serialInvoice",
|
|
icon: "i-heroicons-document-text"
|
|
} : null,
|
|
featureEnabled("incomingInvoices") ? {
|
|
label: "Eingangsbelege",
|
|
to: "/incomingInvoices",
|
|
icon: "i-heroicons-document-text",
|
|
} : null,
|
|
featureEnabled("outgoingsepamandates") ? {
|
|
label: "SEPA-Mandate",
|
|
to: "/standardEntity/outgoingsepamandates",
|
|
icon: "i-heroicons-identification",
|
|
} : null,
|
|
(featureEnabled("incomingInvoices") || featureEnabled("banking")) ? {
|
|
label: "Abschreibungen",
|
|
to: "/accounting/depreciation",
|
|
icon: "i-heroicons-calendar-days",
|
|
} : null,
|
|
((featureEnabled("createDocument") || featureEnabled("incomingInvoices")) || featureEnabled("accounts") || featureEnabled("ownaccounts") || featureEnabled("costcentres") || featureEnabled("banking")) ? {
|
|
label: "Auswertungen",
|
|
icon: "i-heroicons-chart-pie",
|
|
defaultOpen: false,
|
|
children: visibleItems([
|
|
(featureEnabled("createDocument") || featureEnabled("incomingInvoices")) ? {
|
|
label: "USt",
|
|
to: "/accounting/tax",
|
|
icon: "i-heroicons-calculator",
|
|
} : null,
|
|
(featureEnabled("createDocument") || featureEnabled("incomingInvoices") || featureEnabled("accounts") || featureEnabled("ownaccounts")) ? {
|
|
label: "BWA",
|
|
to: "/accounting/bwa",
|
|
icon: "i-heroicons-chart-bar-square",
|
|
} : null,
|
|
featureEnabled("banking") ? {
|
|
label: "Liquidität",
|
|
to: "/accounting/liquidity",
|
|
icon: "i-heroicons-banknotes",
|
|
} : null,
|
|
featureEnabled("costcentres") ? {
|
|
label: "Kostenstellen",
|
|
to: "/standardEntity/costcentres",
|
|
icon: "i-heroicons-document-currency-euro"
|
|
} : null,
|
|
featureEnabled("accounts") ? {
|
|
label: "Buchungskonten",
|
|
to: "/accounts",
|
|
icon: "i-heroicons-document-text",
|
|
} : null,
|
|
featureEnabled("ownaccounts") ? {
|
|
label: "Zusätzliche Buchungskonten",
|
|
to: "/standardEntity/ownaccounts",
|
|
icon: "i-heroicons-document-text"
|
|
} : null,
|
|
])
|
|
} : null,
|
|
featureEnabled("banking") ? {
|
|
label: "Bank",
|
|
to: "/banking",
|
|
icon: "i-heroicons-document-text",
|
|
} : null,
|
|
featureEnabled("banking") ? {
|
|
label: "Kassenbuch",
|
|
to: "/accounting/cashbooks",
|
|
icon: "i-heroicons-banknotes",
|
|
} : null,
|
|
(featureEnabled("accounts") || featureEnabled("ownaccounts")) ? {
|
|
label: "Manuelle Buchungen",
|
|
to: "/accounting/manual-bookings",
|
|
icon: "i-heroicons-arrows-right-left",
|
|
} : null,
|
|
]
|
|
|
|
const inventoryChildren = [
|
|
has("spaces") && featureEnabled("spaces") ? {
|
|
label: "Lagerplätze",
|
|
to: "/standardEntity/spaces",
|
|
icon: "i-heroicons-square-3-stack-3d"
|
|
} : null,
|
|
has("inventoryitems") && featureEnabled("customerspaces") ? {
|
|
label: "Kundenlagerplätze",
|
|
to: "/standardEntity/customerspaces",
|
|
icon: "i-heroicons-squares-plus"
|
|
} : null,
|
|
has("inventoryitems") && featureEnabled("customerinventoryitems") ? {
|
|
label: "Kundeninventar",
|
|
to: "/standardEntity/customerinventoryitems",
|
|
icon: "i-heroicons-qr-code"
|
|
} : null,
|
|
has("inventoryitems") && featureEnabled("inventoryitems") ? {
|
|
label: "Inventar",
|
|
to: "/standardEntity/inventoryitems",
|
|
icon: "i-heroicons-puzzle-piece"
|
|
} : null,
|
|
has("inventoryitems") && featureEnabled("inventoryitemgroups") ? {
|
|
label: "Inventargruppen",
|
|
to: "/standardEntity/inventoryitemgroups",
|
|
icon: "i-heroicons-puzzle-piece"
|
|
} : null,
|
|
]
|
|
|
|
const masterDataChildren = [
|
|
has("products") && featureEnabled("products") ? {
|
|
label: "Artikel",
|
|
to: "/standardEntity/products",
|
|
icon: "i-heroicons-puzzle-piece"
|
|
} : null,
|
|
has("productcategories") && featureEnabled("productcategories") ? {
|
|
label: "Artikelkategorien",
|
|
to: "/standardEntity/productcategories",
|
|
icon: "i-heroicons-puzzle-piece"
|
|
} : null,
|
|
has("services") && featureEnabled("services") ? {
|
|
label: "Leistungen",
|
|
to: "/standardEntity/services",
|
|
icon: "i-heroicons-wrench-screwdriver"
|
|
} : null,
|
|
has("servicecategories") && featureEnabled("servicecategories") ? {
|
|
label: "Leistungskategorien",
|
|
to: "/standardEntity/servicecategories",
|
|
icon: "i-heroicons-wrench-screwdriver"
|
|
} : null,
|
|
showMemberRelationsNav.value && featureEnabled("memberrelations") ? {
|
|
label: "Mitgliedsverhältnisse",
|
|
to: "/standardEntity/memberrelations",
|
|
icon: "i-heroicons-identification"
|
|
} : null,
|
|
featureEnabled("branches") ? {
|
|
label: "Niederlassungen",
|
|
to: "/standardEntity/branches",
|
|
icon: "i-heroicons-building-office-2"
|
|
} : null,
|
|
featureEnabled("hourrates") ? {
|
|
label: "Stundensätze",
|
|
to: "/standardEntity/hourrates",
|
|
icon: "i-heroicons-user-group"
|
|
} : null,
|
|
featureEnabled("projecttypes") ? {
|
|
label: "Projekttypen",
|
|
to: "/projecttypes",
|
|
icon: "i-heroicons-clipboard-document-list",
|
|
} : null,
|
|
featureEnabled("contracttypes") ? {
|
|
label: "Vertragstypen",
|
|
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",
|
|
icon: "i-heroicons-truck"
|
|
} : null,
|
|
]
|
|
|
|
const settingsChildren = [
|
|
featureEnabled("settingsNumberRanges") ? {
|
|
label: "Nummernkreise",
|
|
to: "/settings/numberRanges",
|
|
icon: "i-heroicons-clipboard-document-list",
|
|
} : null,
|
|
featureEnabled("settingsEmailAccounts") ? {
|
|
label: "E-Mail Konten",
|
|
to: "/settings/emailaccounts",
|
|
icon: "i-heroicons-envelope",
|
|
} : null,
|
|
featureEnabled("settingsBanking") ? {
|
|
label: "Bankkonten",
|
|
to: "/settings/banking",
|
|
icon: "i-heroicons-currency-euro",
|
|
} : null,
|
|
featureEnabled("settingsTexttemplates") ? {
|
|
label: "Textvorlagen",
|
|
to: "/settings/texttemplates",
|
|
icon: "i-heroicons-clipboard-document-list",
|
|
} : null,
|
|
featureEnabled("settingsLetterheads") ? {
|
|
label: "Briefpapiere",
|
|
to: "/settings/letterheads",
|
|
icon: "i-heroicons-document",
|
|
} : null,
|
|
featureEnabled("settingsTenant") ? {
|
|
label: "Firmeneinstellungen",
|
|
to: "/settings/tenant",
|
|
icon: "i-heroicons-building-office",
|
|
} : null,
|
|
{
|
|
label: "Telefonie",
|
|
to: "/settings/telephony",
|
|
icon: "i-heroicons-phone",
|
|
},
|
|
{
|
|
label: "Matrix-Setup",
|
|
to: "/communication",
|
|
icon: "i-heroicons-chat-bubble-left-right",
|
|
},
|
|
featureEnabled("export") ? {
|
|
label: "Export",
|
|
to: "/export",
|
|
icon: "i-heroicons-clipboard-document-list"
|
|
} : null,
|
|
]
|
|
|
|
const administrationChildren = isAdmin.value ? [
|
|
{
|
|
label: "Benutzer",
|
|
to: "/administration/users",
|
|
icon: "i-heroicons-users",
|
|
},
|
|
{
|
|
label: "Tenants",
|
|
to: "/administration/tenants",
|
|
icon: "i-heroicons-building-office-2",
|
|
},
|
|
{
|
|
label: "Systemstatus",
|
|
to: "/administration/system",
|
|
icon: "i-heroicons-server-stack",
|
|
},
|
|
] : []
|
|
|
|
const visibleOrganisationChildren = visibleItems(organisationChildren)
|
|
const visibleDocumentChildren = visibleItems(documentChildren)
|
|
const visibleCommunicationChildren = visibleItems(communicationChildren)
|
|
const visibleContactsChildren = visibleItems(contactsChildren)
|
|
const visibleStaffChildren = visibleItems(staffChildren)
|
|
const visibleAccountingChildren = visibleItems(accountingChildren)
|
|
const visibleInventoryChildren = visibleItems(inventoryChildren)
|
|
const visibleMasterDataChildren = visibleItems(masterDataChildren)
|
|
const visibleSettingsChildren = visibleItems(settingsChildren)
|
|
const visibleAdministrationChildren = visibleItems(administrationChildren)
|
|
|
|
return visibleItems([
|
|
...(auth.profile?.pinned_on_navigation || []).map(pin => {
|
|
if (pin.type === "external") {
|
|
return {
|
|
label: pin.label,
|
|
to: pin.link,
|
|
icon: pin.icon,
|
|
target: "_blank"
|
|
}
|
|
} else if (pin.type === "standardEntity") {
|
|
return {
|
|
label: pin.label,
|
|
to: pin.datatype === "tasks" ? `/tasks/show/${pin.id}` : `/standardEntity/${pin.datatype}/show/${pin.id}`,
|
|
icon: pin.icon
|
|
}
|
|
}
|
|
}),
|
|
|
|
featureEnabled("dashboard") ? {
|
|
id: 'dashboard',
|
|
label: "Dashboard",
|
|
to: "/",
|
|
icon: "i-heroicons-home"
|
|
} : null,
|
|
featureEnabled("historyitems") ? {
|
|
id: 'historyitems',
|
|
label: "Logbuch",
|
|
to: "/historyitems",
|
|
icon: "i-heroicons-book-open"
|
|
} : null,
|
|
...(has("projects") && featureEnabled("projects")) ? [{
|
|
label: "Projekte",
|
|
to: "/standardEntity/projects",
|
|
icon: "i-heroicons-clipboard-document-check"
|
|
}] : [],
|
|
...(has("contracts") && featureEnabled("contracts")) ? [{
|
|
label: "Verträge",
|
|
to: "/standardEntity/contracts",
|
|
icon: "i-heroicons-clipboard-document"
|
|
}] : [],
|
|
...(has("plants") && featureEnabled("plants")) ? [{
|
|
label: "Objekte",
|
|
to: "/standardEntity/plants",
|
|
icon: "i-heroicons-clipboard-document"
|
|
}] : [],
|
|
...(visibleOrganisationChildren.length > 0 ? [{
|
|
label: "Organisation",
|
|
icon: "i-heroicons-rectangle-stack",
|
|
defaultOpen: false,
|
|
children: visibleOrganisationChildren
|
|
}] : []),
|
|
...(visibleDocumentChildren.length > 0 ? [{
|
|
label: "Dokumente",
|
|
icon: "i-heroicons-rectangle-stack",
|
|
defaultOpen: false,
|
|
children: visibleDocumentChildren
|
|
}] : []),
|
|
...(visibleCommunicationChildren.length > 0 ? [{
|
|
label: "Kommunikation",
|
|
icon: "i-heroicons-megaphone",
|
|
defaultOpen: false,
|
|
children: visibleCommunicationChildren
|
|
}] : []),
|
|
...(visibleContactsChildren.length > 0 ? [{
|
|
label: "Kontakte",
|
|
defaultOpen: false,
|
|
icon: "i-heroicons-user-group",
|
|
children: visibleContactsChildren
|
|
}] : []),
|
|
...(visibleStaffChildren.length > 0 ? [{
|
|
label: "Mitarbeiter",
|
|
defaultOpen: false,
|
|
icon: "i-heroicons-user-group",
|
|
children: visibleStaffChildren
|
|
}] : []),
|
|
...(visibleAccountingChildren.length > 0 ? [{
|
|
label: "Buchhaltung",
|
|
defaultOpen: false,
|
|
icon: "i-heroicons-chart-bar-square",
|
|
children: visibleAccountingChildren
|
|
}] : []),
|
|
...(visibleInventoryChildren.length > 0 ? [{
|
|
label: "Lager",
|
|
icon: "i-heroicons-puzzle-piece",
|
|
defaultOpen: false,
|
|
children: visibleInventoryChildren
|
|
}] : []),
|
|
...(visibleMasterDataChildren.length > 0 ? [{
|
|
label: "Stammdaten",
|
|
defaultOpen: false,
|
|
icon: "i-heroicons-clipboard-document",
|
|
children: visibleMasterDataChildren
|
|
}] : []),
|
|
...(visibleAdministrationChildren.length > 0 ? [{
|
|
label: "Administration",
|
|
defaultOpen: false,
|
|
icon: "i-heroicons-shield-check",
|
|
children: visibleAdministrationChildren
|
|
}] : []),
|
|
|
|
...(visibleSettingsChildren.length > 0 ? [{
|
|
label: "Einstellungen",
|
|
defaultOpen: false,
|
|
icon: "i-heroicons-cog-8-tooth",
|
|
children: visibleSettingsChildren
|
|
}] : []),
|
|
])
|
|
})
|
|
|
|
const mapNavItem = (item, valuePrefix = "item") => {
|
|
const children = Array.isArray(item.children)
|
|
? item.children
|
|
.filter(Boolean)
|
|
.map((child, index) => mapNavItem(child, `${valuePrefix}-${index}`))
|
|
: undefined
|
|
|
|
const active = item.active || isRouteActive(item.to) || Boolean(children?.some(child => child.active))
|
|
|
|
return {
|
|
...item,
|
|
children,
|
|
value: item.id || item.label || valuePrefix,
|
|
defaultOpen: item.defaultOpen || active,
|
|
active,
|
|
tooltip: true,
|
|
popover: true,
|
|
trailingIcon: children?.length ? undefined : ''
|
|
}
|
|
}
|
|
|
|
const navItems = computed(() =>
|
|
links.value
|
|
.filter(Boolean)
|
|
.map((item, index) => mapNavItem(item, String(index)))
|
|
)
|
|
</script>
|
|
|
|
<template>
|
|
<UNavigationMenu
|
|
:items="navItems"
|
|
orientation="vertical"
|
|
:collapsed="props.collapsed"
|
|
tooltip
|
|
popover
|
|
color="neutral"
|
|
highlight
|
|
highlight-color="primary"
|
|
class="w-full"
|
|
:ui="{
|
|
root: 'w-full',
|
|
list: 'space-y-1',
|
|
link: 'min-w-0 rounded-lg px-2.5 py-2',
|
|
linkLeadingIcon: 'size-5 shrink-0',
|
|
linkLabel: 'truncate',
|
|
childList: 'ms-0 space-y-1 border-l border-default ps-3',
|
|
childLink: 'min-w-0 rounded-lg px-2 py-1.5',
|
|
childLinkLabel: 'truncate'
|
|
}"
|
|
>
|
|
<template #item-leading="{ item, active }">
|
|
<UIcon
|
|
v-if="item.icon"
|
|
:name="item.icon"
|
|
class="size-5 shrink-0"
|
|
:class="active ? 'text-primary' : 'text-muted'"
|
|
/>
|
|
</template>
|
|
|
|
<template #item-trailing="{ item, active }">
|
|
<UBadge
|
|
v-if="item.badge && !props.collapsed"
|
|
color="primary"
|
|
variant="soft"
|
|
size="xs"
|
|
>
|
|
{{ item.badge }}
|
|
</UBadge>
|
|
<UIcon
|
|
v-else-if="item.children?.length"
|
|
name="i-heroicons-chevron-down-20-solid"
|
|
class="size-4 shrink-0 transition-transform"
|
|
:class="active ? 'text-primary' : 'text-muted'"
|
|
/>
|
|
</template>
|
|
</UNavigationMenu>
|
|
</template>
|