361 lines
10 KiB
JavaScript
361 lines
10 KiB
JavaScript
import { createRouter, createWebHistory } from 'vue-router';
|
|
import store from './store';
|
|
|
|
const ROUTE_NAMES = {
|
|
ADMIN_EDIT_PAGES: 'admin-edit-pages',
|
|
ADMIN_FILE_UPLOAD: 'admin-file-upload',
|
|
ADMIN_NEWSLETTER_IMPORT: 'admin-newsletter-import',
|
|
REGISTER: 'register',
|
|
FORGOT_PASSWORD: 'forgot-password',
|
|
RESET_PASSWORD: 'reset-password',
|
|
AUTH_LOGIN: 'auth-login',
|
|
HOME: 'home',
|
|
TERMS: 'terms',
|
|
PRIVACY_POLICY: 'privacy-policy',
|
|
NOT_FOUND: 'not-found',
|
|
};
|
|
|
|
// Vite kann `import(\`./content/${name}.vue\`)` nicht zuverlässig auflösen.
|
|
// Daher bauen wir eine statische Import-Matrix über import.meta.glob.
|
|
const contentModules = import.meta.glob('./content/**/*.vue');
|
|
|
|
function loadComponent(componentName) {
|
|
return async () => {
|
|
const normalized = componentName || 'DefaultComponent';
|
|
const key = `./content/${normalized}.vue`;
|
|
const loader = contentModules[key];
|
|
|
|
if (!loader) {
|
|
// Fallback, falls DB/Backend einen unbekannten Komponenten-Namen liefert.
|
|
const fallback = contentModules['./content/DefaultComponent.vue'];
|
|
return fallback ? fallback() : import('./content/DefaultComponent.vue');
|
|
}
|
|
|
|
return loader();
|
|
};
|
|
}
|
|
|
|
function normalizePath(path) {
|
|
if (!path || typeof path !== 'string') {
|
|
return '/';
|
|
}
|
|
let value = path.trim();
|
|
if (!value.startsWith('/')) {
|
|
value = `/${value}`;
|
|
}
|
|
if (value.length > 1) {
|
|
value = value.replace(/\/+$/, '');
|
|
}
|
|
return value || '/';
|
|
}
|
|
|
|
function generateRoutesFromMenu(menu) {
|
|
let routes = [];
|
|
menu.forEach(item => {
|
|
const normalizedLink = normalizePath(item.link || '');
|
|
if (normalizedLink === '/admin/edit-pages') {
|
|
return;
|
|
}
|
|
|
|
let route = null;
|
|
if (item.link && item.link !== '') {
|
|
route = {
|
|
path: normalizedLink,
|
|
meta: { requiresAuth: item.requiresAuth || false },
|
|
components: {
|
|
default: loadComponent(item.component),
|
|
rightColumn: loadComponent('ImageContent')
|
|
}
|
|
};
|
|
}
|
|
|
|
if (item.submenu && item.submenu.length > 0) {
|
|
let children = generateRoutesFromMenu(item.submenu);
|
|
routes.push(...children);
|
|
}
|
|
if (route) {
|
|
routes.push(route);
|
|
}
|
|
});
|
|
return routes;
|
|
}
|
|
|
|
function findMenuItemByPath(menu, targetPath) {
|
|
const wanted = normalizePath(targetPath);
|
|
for (const item of menu || []) {
|
|
if (normalizePath(item.link || '') === wanted) {
|
|
return item;
|
|
}
|
|
if (item.submenu && item.submenu.length > 0) {
|
|
const found = findMenuItemByPath(item.submenu, wanted);
|
|
if (found) {
|
|
return found;
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function ensureMenuRouteForPath(path) {
|
|
const normalizedPath = normalizePath(path);
|
|
const exists = router.getRoutes().some(r => normalizePath(r.path) === normalizedPath);
|
|
if (exists) {
|
|
return true;
|
|
}
|
|
const menuItem = findMenuItemByPath(store.state.menuData, normalizedPath);
|
|
if (!menuItem || !menuItem.link) {
|
|
return false;
|
|
}
|
|
router.addRoute({
|
|
path: normalizedPath,
|
|
meta: { requiresAuth: menuItem.requiresAuth || false },
|
|
components: {
|
|
default: loadComponent(menuItem.component),
|
|
rightColumn: loadComponent('ImageContent')
|
|
}
|
|
});
|
|
return true;
|
|
}
|
|
|
|
const router = createRouter({
|
|
history: createWebHistory(),
|
|
routes: []
|
|
});
|
|
|
|
// Verhindert endlose Wiederholungen von fehlgeschlagenen Menü-Ladeversuchen
|
|
let menuDataInitialized = false;
|
|
|
|
router.beforeEach(async (to, from, next) => {
|
|
if (!menuDataInitialized) {
|
|
menuDataInitialized = true;
|
|
|
|
await store.dispatch('loadMenuData');
|
|
const routes = generateRoutesFromMenu(store.state.menuData);
|
|
routes.forEach(route => router.addRoute(route));
|
|
addEditPagesRoute();
|
|
addRegisterRoute();
|
|
addForgotPasswordRoute();
|
|
addResetPasswordRoute();
|
|
addAuthLoginRoute();
|
|
// NotFound-Route existiert bereits als Core-Route; bei DB-Ausfall aktualisieren wir sie.
|
|
if (store.state.menuLoadError && router.hasRoute(ROUTE_NAMES.NOT_FOUND)) {
|
|
router.removeRoute(ROUTE_NAMES.NOT_FOUND);
|
|
router.addRoute({
|
|
path: '/:pathMatch(.*)*',
|
|
components: {
|
|
default: loadComponent('ServiceUnavailableComponent'),
|
|
rightColumn: loadComponent('ImageContent')
|
|
},
|
|
name: ROUTE_NAMES.NOT_FOUND
|
|
});
|
|
}
|
|
|
|
const normalizedToPath = normalizePath(to.path);
|
|
if (normalizedToPath !== to.path) {
|
|
next({ path: normalizedToPath, query: to.query, hash: to.hash, replace: true });
|
|
return;
|
|
}
|
|
next({ ...to, replace: true });
|
|
} else {
|
|
// Sicherstellen, dass Kernrouten immer verfügbar sind
|
|
ensureCoreRoutes();
|
|
const normalizedToPath = normalizePath(to.path);
|
|
if (normalizedToPath !== to.path) {
|
|
next({ path: normalizedToPath, query: to.query, hash: to.hash, replace: true });
|
|
return;
|
|
}
|
|
if (to.matched.length === 0 && ensureMenuRouteForPath(normalizedToPath)) {
|
|
next({ path: normalizedToPath, query: to.query, hash: to.hash, replace: true });
|
|
return;
|
|
}
|
|
if (to.matched.some(record => record.meta.requiresAuth) && !store.getters.isLoggedIn) {
|
|
next('/auth/login');
|
|
} else {
|
|
next();
|
|
}
|
|
}
|
|
});
|
|
|
|
function addEditPagesRoute() {
|
|
if (router.hasRoute(ROUTE_NAMES.ADMIN_EDIT_PAGES)) {
|
|
router.removeRoute(ROUTE_NAMES.ADMIN_EDIT_PAGES);
|
|
}
|
|
router.addRoute({
|
|
path: '/admin/edit-pages',
|
|
components: {
|
|
default: loadComponent('admin/PagePreviewComponent'),
|
|
rightColumn: loadComponent('admin/EditPagesComponent')
|
|
},
|
|
name: ROUTE_NAMES.ADMIN_EDIT_PAGES
|
|
});
|
|
}
|
|
|
|
function addFileUploadRoute() {
|
|
if (router.hasRoute(ROUTE_NAMES.ADMIN_FILE_UPLOAD)) {
|
|
router.removeRoute(ROUTE_NAMES.ADMIN_FILE_UPLOAD);
|
|
}
|
|
router.addRoute({
|
|
path: '/admin/fileupload',
|
|
meta: { requiresAuth: true },
|
|
components: {
|
|
default: loadComponent('admin/UploadFileManagement'),
|
|
rightColumn: loadComponent('ImageContent')
|
|
},
|
|
name: ROUTE_NAMES.ADMIN_FILE_UPLOAD
|
|
});
|
|
}
|
|
|
|
function addNewsletterImportRoute() {
|
|
if (router.hasRoute(ROUTE_NAMES.ADMIN_NEWSLETTER_IMPORT)) {
|
|
router.removeRoute(ROUTE_NAMES.ADMIN_NEWSLETTER_IMPORT);
|
|
}
|
|
router.addRoute({
|
|
path: '/admin/newsletter-import',
|
|
components: {
|
|
default: loadComponent('admin/NewsletterImportManagement'),
|
|
rightColumn: loadComponent('ImageContent')
|
|
},
|
|
name: ROUTE_NAMES.ADMIN_NEWSLETTER_IMPORT
|
|
});
|
|
}
|
|
|
|
function addRegisterRoute() {
|
|
if (router.hasRoute(ROUTE_NAMES.REGISTER)) {
|
|
router.removeRoute(ROUTE_NAMES.REGISTER);
|
|
}
|
|
router.addRoute({
|
|
path: '/register',
|
|
components: {
|
|
default: () => import('./content/authentication/RegisterContent.vue'),
|
|
rightColumn: loadComponent('ImageContent')
|
|
},
|
|
name: ROUTE_NAMES.REGISTER
|
|
});
|
|
}
|
|
|
|
function addForgotPasswordRoute() {
|
|
if (router.hasRoute(ROUTE_NAMES.FORGOT_PASSWORD)) {
|
|
router.removeRoute(ROUTE_NAMES.FORGOT_PASSWORD);
|
|
}
|
|
router.addRoute({
|
|
path: '/forgot-password',
|
|
components: {
|
|
default: () => import('./content/authentication/ForgotPasswordContent.vue'),
|
|
rightColumn: loadComponent('ImageContent')
|
|
},
|
|
name: ROUTE_NAMES.FORGOT_PASSWORD
|
|
});
|
|
}
|
|
|
|
function addResetPasswordRoute() {
|
|
if (router.hasRoute(ROUTE_NAMES.RESET_PASSWORD)) {
|
|
router.removeRoute(ROUTE_NAMES.RESET_PASSWORD);
|
|
}
|
|
router.addRoute({
|
|
path: '/reset-password',
|
|
components: {
|
|
default: () => import('./content/authentication/ResetPasswordContent.vue'),
|
|
rightColumn: loadComponent('ImageContent')
|
|
},
|
|
name: ROUTE_NAMES.RESET_PASSWORD
|
|
});
|
|
}
|
|
|
|
function addAuthLoginRoute() {
|
|
if (router.hasRoute(ROUTE_NAMES.AUTH_LOGIN)) {
|
|
router.removeRoute(ROUTE_NAMES.AUTH_LOGIN);
|
|
}
|
|
router.addRoute({
|
|
path: '/auth/login',
|
|
components: {
|
|
default: () => import('./content/authentication/LoginContent.vue'),
|
|
rightColumn: loadComponent('ImageContent')
|
|
},
|
|
name: ROUTE_NAMES.AUTH_LOGIN
|
|
});
|
|
}
|
|
|
|
function addHomeRoute() {
|
|
if (router.hasRoute(ROUTE_NAMES.HOME)) {
|
|
router.removeRoute(ROUTE_NAMES.HOME);
|
|
}
|
|
router.addRoute({
|
|
path: '/',
|
|
components: {
|
|
default: loadComponent('DefaultContent'),
|
|
rightColumn: loadComponent('ImageContent')
|
|
},
|
|
name: ROUTE_NAMES.HOME
|
|
});
|
|
}
|
|
|
|
function addTermsRoute() {
|
|
if (router.hasRoute(ROUTE_NAMES.TERMS)) {
|
|
router.removeRoute(ROUTE_NAMES.TERMS);
|
|
}
|
|
router.addRoute({
|
|
path: '/terms',
|
|
components: {
|
|
default: () => import('./content/disclaimers/TermsComponent.vue'),
|
|
rightColumn: loadComponent('ImageContent')
|
|
},
|
|
name: ROUTE_NAMES.TERMS
|
|
});
|
|
}
|
|
|
|
function addPrivacyPolicyRoute() {
|
|
if (router.hasRoute(ROUTE_NAMES.PRIVACY_POLICY)) {
|
|
router.removeRoute(ROUTE_NAMES.PRIVACY_POLICY);
|
|
}
|
|
router.addRoute({
|
|
path: '/privacy-policy',
|
|
components: {
|
|
default: () => import('./content/disclaimers/PrivacyPolicyComponent.vue'),
|
|
rightColumn: loadComponent('ImageContent')
|
|
},
|
|
name: ROUTE_NAMES.PRIVACY_POLICY
|
|
});
|
|
}
|
|
|
|
function ensureNotFoundRoute() {
|
|
// Catch-All nur einmal registrieren (sonst Doppelrouten/unklares Matching)
|
|
if (router.hasRoute(ROUTE_NAMES.NOT_FOUND)) return;
|
|
|
|
router.addRoute({
|
|
path: '/:pathMatch(.*)*',
|
|
components: {
|
|
default: loadComponent('DefaultComponent'),
|
|
rightColumn: loadComponent('ImageContent')
|
|
},
|
|
name: ROUTE_NAMES.NOT_FOUND
|
|
});
|
|
}
|
|
|
|
function ensureCoreRoutes() {
|
|
if (!router.hasRoute(ROUTE_NAMES.ADMIN_EDIT_PAGES)) addEditPagesRoute();
|
|
if (!router.hasRoute(ROUTE_NAMES.ADMIN_FILE_UPLOAD)) addFileUploadRoute();
|
|
if (!router.hasRoute(ROUTE_NAMES.ADMIN_NEWSLETTER_IMPORT)) addNewsletterImportRoute();
|
|
if (!router.hasRoute(ROUTE_NAMES.REGISTER)) addRegisterRoute();
|
|
if (!router.hasRoute(ROUTE_NAMES.FORGOT_PASSWORD)) addForgotPasswordRoute();
|
|
if (!router.hasRoute(ROUTE_NAMES.RESET_PASSWORD)) addResetPasswordRoute();
|
|
if (!router.hasRoute(ROUTE_NAMES.AUTH_LOGIN)) addAuthLoginRoute();
|
|
if (!router.hasRoute(ROUTE_NAMES.HOME)) addHomeRoute();
|
|
if (!router.hasRoute(ROUTE_NAMES.TERMS)) addTermsRoute();
|
|
if (!router.hasRoute(ROUTE_NAMES.PRIVACY_POLICY)) addPrivacyPolicyRoute();
|
|
ensureNotFoundRoute();
|
|
}
|
|
|
|
addEditPagesRoute();
|
|
addFileUploadRoute();
|
|
addNewsletterImportRoute();
|
|
addRegisterRoute();
|
|
addForgotPasswordRoute();
|
|
addResetPasswordRoute();
|
|
addAuthLoginRoute();
|
|
addHomeRoute();
|
|
addTermsRoute();
|
|
addPrivacyPolicyRoute();
|
|
ensureNotFoundRoute();
|
|
|
|
export default router;
|