UNPKG

@ithinkdt/core

Version:

iThinkDT Core

225 lines (216 loc) 8.73 kB
import { markRaw, reactive } from 'vue' import { defineStore } from 'pinia' import { promiseTimeout } from '@vueuse/core' import { walkTree } from '@ithinkdt/common' import { useFetch } from '../http' export let useAuth export function initAuthInfo({ login, logout, loadAuthInfo, changePwd, router, locale }) { const fn = defineStore(`core:auth`, { state: () => ({ error: false, token: undefined, app: undefined, user: undefined, modules: [], fromModule: undefined, }), getters: { logged(state) { return !!state.token }, moduleMap(state) { const map = {} walkTree(state.modules ?? [], (m, _i, parent) => { m.parent = parent if (m.type !== 'action') { map[m.key] = m if (m.path) { map[m.path] = m } } }) return map }, menus: (() => { function _walk(m) { if (m?.hidden === true) return if (m?.type === 'group' && m?.children?.length) { const children = m.children.map((c) => _walk(c)).filter((m) => !!m) return children.length > 0 ? { ...m, children: children, } : undefined } return m?.type === 'action' ? undefined : { ...m, children: undefined } } return (state) => { const menus = state.modules?.map(_walk).filter((m) => !!m) console.debug('[auth] menus', menus) return menus } })(), menuMap() { const map = {} walkTree(this.menus, (m) => { map[m.key] = m if (m.path) { map[m.path] = m } }) return map }, currentRouteInModule() { const route = router.currentRoute.value return !route?.meta?.activedModule?.trim() && !route?.meta?.activedModuleName?.trim() }, currentModule() { const route = router.currentRoute.value if (!route) return if (this.currentRouteInModule) { return this.moduleMap[route.path] ? route.path : route.matched.at(-1)?.path ?? '' } return ( route.meta.activedModule?.trim() || router.resolve({ name: route.meta.activedModuleName?.trim() })?.path ) }, activedModulePath() { const route = router.currentRoute.value if (!route) return [] let menu = this.moduleMap[this.currentModule] || this.moduleMap[this.fromModule] const paths = [] if ( !this.currentRouteInModule || !(this.moduleMap[route.path] || this.moduleMap[route.matched.at(-1)?.path ?? '']) ) { paths.push( reactive({ key: route.path, parentKey: menu?.key, parent: menu, label: route.path, type: 'module', path: route.path, }), ) } while (menu) { paths.unshift(menu) menu = menu.parent } console.debug('[auth] activedModulePath', paths) return paths }, activedMenuPath() { const paths = this.activedModulePath.map((m) => this.menuMap[m.key]).filter((m) => !!m) console.debug('[auth] activedMenuPath', paths) return paths }, permissions(state) { const permissions = {} walkTree(state.modules, (m) => { m.path && (permissions[m.path] = true) if (m.actions) for (const r of m.actions) permissions[r] = true }) console.debug('[auth] permissions', permissions) return permissions }, }, actions: (() => { let _reject let $load const loginFn = useFetch(login) const logoutFn = logout && useFetch(logout) return { async login(user) { console.debug(`[login]: user [ ${user.username} ].`) try { const res = await loginFn(user) console.debug('[login]: login success.', res) return res } catch (error) { console.debug('[login]: login error.', error) throw error } }, async load(force = false) { if (!this.token) { console.debug('[auth] load not set token!') $load = undefined throw new Error('未设置用户 token') } if ($load) { if (!force) { console.debug('[auth] load having $load, reuse.') return $load } console.debug('[auth] load having $load, but force it.') _reject(new Error('重新 load')) } const req = ($load = new Promise((resolve, reject) => { _reject = reject loadAuthInfo(this.token, locale.value).then( (authInfo) => { if (this.token === undefined || req !== $load) { console.debug('[auth] load fetched auth info, but token or request expired.') return } for (const key of Object.keys(authInfo)) { this[key] = markRaw(authInfo[key]) } console.debug('[auth] load fetched auth info.', authInfo) resolve() }, (error) => { if (req === $load) { if (error?.message === 'forbidden' || error?.message === 'timeout') { this.error = error resolve() return } console.debug('[auth] load fetch auth error.', error) this.error = error $load = undefined } reject(error) }, ) })) return $load }, async logout() { console.debug('[auth] logout.') const { token, user, app } = this.$state await logoutFn?.({ username: user?.username, appCode: app?.appCode, token: token }) this.$reset() this.$clear() await promiseTimeout(300) }, changePwd, } })(), persist: { storage: 'local', version: 1, excludes: ['app', 'modules'], }, }) useAuth = fn return fn } export function getFirstPageModule(modules) { for (const m of modules ?? []) { if (['module', 'lowcode', 'federate', 'external'].includes(m.type)) { return m } if (m.type === 'group') { const child = getFirstPageModule(m.children ?? []) if (child) { return child } } } return }