diff --git a/packages/stores/src/modules/access.ts b/packages/stores/src/modules/access.ts new file mode 100644 index 0000000..80f422e --- /dev/null +++ b/packages/stores/src/modules/access.ts @@ -0,0 +1,138 @@ +import type { RouteRecordRaw } from 'vue-router'; + +import type { MenuRecordRaw } from '@vben-core/typings'; + +import { acceptHMRUpdate, defineStore } from 'pinia'; + +type AccessToken = null | string; + +interface AccessState { + /** + * 权限码 + */ + accessCodes: string[]; + /** + * 可访问的菜单列表 + */ + accessMenus: MenuRecordRaw[]; + /** + * 可访问的路由列表 + */ + accessRoutes: RouteRecordRaw[]; + /** + * 登录 accessToken + */ + accessToken: AccessToken; + /** + * 是否已经检查过权限 + */ + isAccessChecked: boolean; + /** + * 是否锁屏状态 + */ + isLockScreen: boolean; + /** + * 锁屏密码 + */ + lockScreenPassword?: string; + /** + * 登录是否过期 + */ + loginExpired: boolean; + /** + * 登录 accessToken + */ + refreshToken: AccessToken; + /** + * Token 过期时间戳 + */ + expiresAt: number | null; + } + +/** + * @zh_CN 访问权限相关 + */ +export const useAccessStore = defineStore('core-access', { + actions: { + getMenuByPath(path: string) { + function findMenu( + menus: MenuRecordRaw[], + path: string, + ): MenuRecordRaw | undefined { + for (const menu of menus) { + if (menu.path === path) { + return menu; + } + if (menu.children) { + const matched = findMenu(menu.children, path); + if (matched) { + return matched; + } + } + } + } + return findMenu(this.accessMenus, path); + }, + lockScreen(password: string) { + this.isLockScreen = true; + this.lockScreenPassword = password; + }, + setAccessCodes(codes: string[]) { + this.accessCodes = codes; + }, + setAccessMenus(menus: MenuRecordRaw[]) { + this.accessMenus = menus; + }, + setAccessRoutes(routes: RouteRecordRaw[]) { + this.accessRoutes = routes; + }, + setAccessToken(token: AccessToken) { + this.accessToken = token; + }, + setIsAccessChecked(isAccessChecked: boolean) { + this.isAccessChecked = isAccessChecked; + }, + setLoginExpired(loginExpired: boolean) { + this.loginExpired = loginExpired; + }, + setRefreshToken(token: AccessToken) { + this.refreshToken = token; + }, + setExpiresAt(timestamp: number | null) { + this.expiresAt = timestamp; + }, + unlockScreen() { + this.isLockScreen = false; + this.lockScreenPassword = undefined; + }, + }, + persist: { + // 持久化 + pick: [ + 'accessToken', + 'refreshToken', + 'expiresAt', + 'accessCodes', + 'isLockScreen', + 'lockScreenPassword', + ], + }, + state: (): AccessState => ({ + accessCodes: [], + accessMenus: [], + accessRoutes: [], + accessToken: null, + isAccessChecked: false, + isLockScreen: false, + lockScreenPassword: undefined, + loginExpired: false, + refreshToken: null, + expiresAt: null, + }), +}); + +// 解决热更新问题 +const hot = import.meta.hot; +if (hot) { + hot.accept(acceptHMRUpdate(useAccessStore, hot)); +}