import type { RouteRecordRaw } from 'vue-router'; export interface MenuAccessIdentity { currentRole: string | null; permissions: string[]; } export function hasRoleAccess(roles: string[], currentRole: string | null): boolean { return roles.length === 0 || currentRole === 'SYSTEM_ADMIN' || roles.includes(currentRole || ''); } export function hasPermissionAccess( currentRole: string | null, permissions: string[], required: string | string[], ): boolean { if (currentRole === 'SYSTEM_ADMIN') return true; return Array.isArray(required) ? required.some((permission) => permissions.includes(permission)) : permissions.includes(required); } export function canAccess(route: RouteRecordRaw, user: MenuAccessIdentity): boolean { const meta = route.meta || {}; const roles = (meta.roleCodes || []) as string[]; const permission = meta.permission as string | string[] | undefined; if (!hasRoleAccess(roles, user.currentRole)) return false; if (permission && !hasPermissionAccess(user.currentRole, user.permissions, permission)) return false; return true; } function childLocation(parentPath: string, childPath: string): string { if (childPath.startsWith('/')) return childPath; if (!childPath) return parentPath; return `${parentPath}/${childPath}`.replace(/\/{2,}/g, '/'); } export function filterMenu(routes: RouteRecordRaw[], user: MenuAccessIdentity): RouteRecordRaw[] { return routes .map((route) => { const children = route.children ? filterMenu(route.children, user) : []; const selfAllowed = canAccess(route, user); if (route.children && children.length === 0) return null; if (!route.children && !selfAllowed) return null; const copy: RouteRecordRaw = { ...route, meta: route.meta ? { ...route.meta } : undefined, ...(route.children ? { children } : {}), } as RouteRecordRaw; if (route.children) { const firstChild = children[0]; if (firstChild) copy.redirect = childLocation(route.path, firstChild.path); } return copy; }) .filter((route): route is RouteRecordRaw => route !== null); }