170 lines
5.0 KiB
Vue
170 lines
5.0 KiB
Vue
<script setup>
|
|
import { ref, onMounted } from 'vue';
|
|
import { useAuthStore } from '../stores/auth';
|
|
import { usePermissionStore } from '../stores/permissions';
|
|
import AppMenuItem from './AppMenuItem.vue';
|
|
|
|
const authStore = useAuthStore();
|
|
const permissionStore = usePermissionStore();
|
|
|
|
// Core-Menü mit Permission-Prüfungen
|
|
const coreMenu = [
|
|
{
|
|
label: 'Home',
|
|
items: [
|
|
{
|
|
label: 'Dashboard',
|
|
icon: 'pi pi-fw pi-home',
|
|
to: '/',
|
|
visible: () => permissionStore.canView('dashboard')
|
|
}
|
|
]
|
|
},
|
|
{
|
|
label: 'CRM',
|
|
items: [
|
|
{
|
|
label: 'Kontakte',
|
|
icon: 'pi pi-fw pi-users',
|
|
to: '/contacts',
|
|
visible: () => permissionStore.canView('contacts')
|
|
},
|
|
{
|
|
label: 'Projekte',
|
|
icon: 'pi pi-fw pi-briefcase',
|
|
to: '/projects',
|
|
visible: () => permissionStore.canView('projects')
|
|
},
|
|
{
|
|
label: 'Tätigkeiten',
|
|
icon: 'pi pi-fw pi-list-check',
|
|
to: '/project-tasks',
|
|
visible: () => permissionStore.canView('project_tasks')
|
|
}
|
|
]
|
|
}
|
|
];
|
|
|
|
// Administration-Menü mit Permission-Prüfungen
|
|
const adminMenu = {
|
|
label: 'Administration',
|
|
items: [
|
|
{
|
|
label: 'Projekt-Status',
|
|
icon: 'pi pi-fw pi-tag',
|
|
to: '/project-statuses',
|
|
visible: () => permissionStore.canView('projects')
|
|
},
|
|
{
|
|
label: 'Benutzerverwaltung',
|
|
icon: 'pi pi-fw pi-user-edit',
|
|
to: '/users',
|
|
visible: () => permissionStore.canView('users')
|
|
},
|
|
{
|
|
label: 'Rollenverwaltung',
|
|
icon: 'pi pi-fw pi-shield',
|
|
to: '/roles',
|
|
visible: () => permissionStore.canView('roles')
|
|
},
|
|
{
|
|
label: 'Einstellungen',
|
|
icon: 'pi pi-fw pi-cog',
|
|
to: '/settings',
|
|
visible: () => permissionStore.canView('settings')
|
|
}
|
|
]
|
|
};
|
|
|
|
// Dynamisches Menü (wird geladen)
|
|
const model = ref([...coreMenu]);
|
|
|
|
// Hilfsfunktion: Konvertiert ein Menü-Item und alle Sub-Items
|
|
const convertMenuItem = (item) => {
|
|
// Erstelle Permission-Prüfung
|
|
let visibleFn;
|
|
|
|
if (item.permission) {
|
|
// Explizite Permission aus Plugin (z.B. "billing.view")
|
|
visibleFn = () => authStore.hasPermission(item.permission);
|
|
} else if (item.module) {
|
|
// Fallback: Modulname + ".view" (z.B. "billing" -> "billing.view")
|
|
visibleFn = () => authStore.hasPermission(`${item.module}.view`);
|
|
} else if (item.source) {
|
|
// Fallback: Plugin-Identifier + ".view" (z.B. "billing" -> "billing.view")
|
|
visibleFn = () => authStore.hasPermission(`${item.source}.view`);
|
|
}
|
|
|
|
const converted = {
|
|
label: item.label,
|
|
icon: item.icon ? `pi pi-fw ${item.icon}` : 'pi pi-fw pi-circle',
|
|
to: item.to,
|
|
...(visibleFn && { visible: visibleFn })
|
|
};
|
|
|
|
// Rekursiv Sub-Items verarbeiten
|
|
if (item.items && Array.isArray(item.items)) {
|
|
converted.items = item.items
|
|
.filter(subItem => !subItem.separator) // Separators filtern
|
|
.map(subItem => convertMenuItem(subItem));
|
|
}
|
|
|
|
// Separators beibehalten
|
|
if (item.separator) {
|
|
return { separator: true };
|
|
}
|
|
|
|
return converted;
|
|
};
|
|
|
|
// Plugin-Menüs laden
|
|
const loadPluginMenus = async () => {
|
|
try {
|
|
const response = await fetch('/api/plugin-menu/grouped');
|
|
const data = await response.json();
|
|
|
|
if (data.success && data.data) {
|
|
// Plugin-Menüs als eigene Gruppen hinzufügen
|
|
Object.entries(data.data).forEach(([groupLabel, items]) => {
|
|
// Konvertiere zu PrimeVue Menü-Format
|
|
const menuGroup = {
|
|
label: groupLabel,
|
|
items: items.map(item => convertMenuItem(item))
|
|
};
|
|
|
|
model.value.push(menuGroup);
|
|
});
|
|
}
|
|
|
|
// Administration-Menü am Ende hinzufügen
|
|
model.value.push(adminMenu);
|
|
|
|
} catch (error) {
|
|
console.error('Fehler beim Laden der Plugin-Menüs:', error);
|
|
// Fallback: Nur Core + Admin Menü
|
|
model.value = [...coreMenu, adminMenu];
|
|
}
|
|
};
|
|
|
|
// Beim Mount laden - warten bis Permissions geladen sind
|
|
onMounted(async () => {
|
|
// Warten bis Permissions geladen sind
|
|
while (!permissionStore.loaded) {
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
|
|
loadPluginMenus();
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<ul class="layout-menu">
|
|
<template v-for="(item, i) in model" :key="item">
|
|
<app-menu-item v-if="!item.separator && (!item.visible || item.visible())" :item="item" :index="i"></app-menu-item>
|
|
<li v-if="item.separator" class="menu-separator"></li>
|
|
</template>
|
|
</ul>
|
|
</template>
|
|
|
|
<style lang="scss" scoped></style>
|