UNPKG

@ithinkdt/core

Version:

iThinkDT Core

223 lines (212 loc) 8.26 kB
import { h, defineComponent } from 'vue' import { createRouter, createWebHistory, createWebHashHistory } from 'vue-router' import { debounce, walkTree } from '@ithinkdt/common' import { promiseTimeout } from '@vueuse/core' import { $notice } from '../feedback' export const Route = { INDEX: '__$-app-index', LOGIN: '__$-app-login', LOGOUT: '__$-app-logout', NOT_FOUND: '__$-app-404', } export const RouteLoadFailured = Symbol() export function initRouter({ router, base = '', routes, index, logged, Login, Logout, Error, sso = false, setToken, getToken, logout, type, getAuthErrorType, }) { const getIndexRoute = typeof index === 'function' ? index : () => index console.debug(`[router] initing...`, routes) const warn = debounce( () => { $notice({ type: 'warning', title: '请求的资源不存在', content: `可能的原因:\n· 应用配置错误\n· 新版本发布`, meta: '若页面正常请忽略此报告!', action: () => h('span', [ h('span', { style: 'font-size: 12px' }, ['您可以 ']), h('a', { href: `javascript:location.reload()` }, ['刷新页面']), ]), }) }, 30_000, { leading: true }, ) walkTree(routes, (route) => { if (typeof route.component === 'function') { if (!route.meta) { route.meta = {} } const comp = route.component route.component = () => comp() .then((m) => { route.meta.__DT_ROUTE_LOAD_FAILURED = false return m }) .catch((error) => { console.error(`[router] load route component error!`, route, error) route.meta.__DT_ROUTE_LOAD_FAILURED = error warn() return Error }) } }) function redirectOrIndex(redirect) { console.debug(`[login]: logged, redirect to ${redirect ? `'${redirect}'` : 'index'}.`) if (redirect) { location.replace(redirect) } return { path: '/', replace: true } } console.debug( sso ? `[router] sso enabled, self login ${sso.selfLogin ? 'enabled' : 'disabled'}.` : `[router] sso disabled`, ) if (router) { router.addRoute({ path: base, name: Route.INDEX + '/' + base, childrens: routes, beforeEnter: () => { const index = getIndexRoute() ?? '/403' console.debug(`[router] goto page '${index}'.`) return { path: index, replace: true } }, }) } else { let _index, _routes = [] for (const r of routes) { if (r.path === '/') { _index = r } else { _routes.push(r) } } const toIndex = () => { const index = getIndexRoute() if (index) { console.debug(`[router] goto page '${index}'.`) return { path: index, replace: true } } } router = createRouter({ history: (type === 'hash' ? createWebHashHistory : createWebHistory)(base), routes: [ _index ? { beforeEnter: (to) => { if ( to.name !== Route.INDEX || _index.component || _index.children?.find((r) => r.path === '') ) return return toIndex() }, ..._index, name: Route.INDEX, } : { path: '/', name: Route.INDEX, component: defineComponent({ render() { return h(Error, { type: getAuthErrorType() }) }, }), beforeEnter: toIndex, }, { path: '/login', alias: sso && sso.selfLogin ? [typeof sso.selfLogin === 'string' ? sso.selfLogin : '/login!'] : [], name: Route.LOGIN, component: Login, meta: { requiresLogin: false, keepAlive: false }, async beforeEnter(to) { console.debug('[login]: before each...') if (logged.value) { await promiseTimeout(301) let redirect = to.query?.redirect if (to.query?.redirect_with_token) { redirect += redirect.includes('?') ? (redirect.endsWith('?') ? '' : '&') : '?' redirect += to.query?.redirect_with_token + '=' + getToken() } return redirectOrIndex(redirect) } if (!sso || to.path !== '/login') { console.debug('[login]: enter self login!') return } const token = await sso.parseToken(location.origin + (to.href ?? '')) console.debug( `[login]: sso paresd result {\n\ttoken: ${token},\n\tredirect: ${to.query?.redirect}\n}.`, ) if (token) { return setToken(token).then(() => redirectOrIndex(to.query?.redirect)) } console.debug(`[login]: redirect to sso login page...`) window.open(await sso.login(location.origin + (type === 'hash' ? base : '') + to.href), '_self') return false }, }, { path: '/logout', name: Route.LOGOUT, component: Logout, meta: { requiresLogin: false, keepAlive: false }, async beforeEnter(to) { if (Logout) { return } await logout() if (!sso) { if (to.query?.redirect) { window.open(to.query.redirect, '_self') return } return { name: Route.LOGIN } } console.debug(`[login]: redirect to sso logout page...`) window.open( await sso.logout(`${location.origin}${base}`, { ...to.query, token: getToken() }), '_self', ) return false }, }, ..._routes, { path: '/:path(.*)', name: Route.NOT_FOUND, component: Error, meta: { requiresLogin: false, keepAlive: 'path&query' }, beforeEnter() { if (!logged.value) { console.debug(`[router] error view redirect to login...`) return { name: Route.LOGIN, replace: true, } } }, }, ], }) } router.base = base && base[0] !== '.' ? base : '/' return router }