@ithinkdt/core
Version:
iThinkDT Core
223 lines (212 loc) • 8.26 kB
JavaScript
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
}