import { useUserStore } from '@/store/user' const ADMIN_ROLES = ['admin', 'sys_admin'] const normalizePermissionList = (permissions) => { if (!permissions) return [] if (Array.isArray(permissions)) return permissions.filter(Boolean) if (typeof permissions === 'object') { return Object.keys(permissions).filter(key => !!permissions[key]) } if (typeof permissions === 'string') { return permissions .split(',') .map((perm) => perm.trim()) .filter(Boolean) } return [] } const resolveRequiredPermissions = (value) => { if (!value) return [] if (Array.isArray(value)) return value.filter(Boolean) if (typeof value === 'string') { return value .split(',') .map((item) => item.trim()) .filter(Boolean) } return [] } const evaluatePermission = (userStore, requiredPermissions, modifiers = {}) => { if (!userStore) return false const { requireAll = modifiers.all } = modifiers const permissionsToCheck = resolveRequiredPermissions(requiredPermissions) if (permissionsToCheck.length === 0) return true const userInfo = userStore.userInfo const userRoles = userInfo?.roles || [] const isAdmin = Array.isArray(userRoles) && userRoles.some((role) => ADMIN_ROLES.includes(role)) if (isAdmin) return true const userPermissions = normalizePermissionList(userInfo?.permissions) if (userPermissions.length === 0) return false if (requireAll) { return permissionsToCheck.every((permission) => userPermissions.includes(permission)) } return permissionsToCheck.some((permission) => userPermissions.includes(permission)) } const getUserStore = (binding, vnode) => { const piniaInstance = binding?.instance?.proxy?.$pinia || binding?.instance?.appContext?.app?.$pinia || vnode?.context?.$pinia || binding?.instance?.appContext?.appContext?.provides?.pinia try { if (piniaInstance) { return useUserStore(piniaInstance) } return useUserStore() } catch (error) { console.warn('[v-permission] failed to access pinia instance:', error) return null } } const toggleElementVisibility = (el, shouldShow) => { if (shouldShow) { el.style.display = el.__vOriginalDisplay || '' } else { if (el.style.display !== 'none') { el.__vOriginalDisplay = el.style.display } el.style.display = 'none' } el.__vPermissionVisible = shouldShow } const handleDirective = (el, binding, vnode) => { const userStore = getUserStore(binding, vnode) const shouldShow = evaluatePermission(userStore, binding.value, binding.modifiers) toggleElementVisibility(el, shouldShow) } export const registerPermissionDirective = (appOrVue) => { if (!appOrVue) return const directiveConfig = { mounted: handleDirective, updated: handleDirective, beforeMount: handleDirective, beforeUpdate: handleDirective } if (typeof appOrVue.directive === 'function') { // Vue3 appOrVue.directive('permission', directiveConfig) } else if (typeof appOrVue.prototype?.directive === 'function' || typeof appOrVue.directive === 'function') { // Vue2 global Vue constructor const VueCtor = appOrVue.prototype?.constructor || appOrVue VueCtor.directive('permission', { inserted: handleDirective, update: handleDirective, componentUpdated: handleDirective }) } } export default registerPermissionDirective