2024-07-16 10:02:54 +08:00
|
|
|
|
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router'
|
|
|
|
|
import NProgress from 'nprogress'
|
|
|
|
|
import 'nprogress/nprogress.css'
|
|
|
|
|
import { useAppStore } from '@/store/modules/app'
|
|
|
|
|
import { useUserStore } from '@/store/modules/user'
|
|
|
|
|
import { useRouterStore } from '@/store/modules/router'
|
|
|
|
|
import { isExternalLink, pathToCamel } from '@/utils/tool'
|
|
|
|
|
import constant from '@/utils/constant'
|
|
|
|
|
|
|
|
|
|
NProgress.configure({ showSpinner: false })
|
|
|
|
|
|
|
|
|
|
const constantRoutes: RouteRecordRaw[] = [
|
|
|
|
|
{
|
|
|
|
|
path: '/redirect',
|
|
|
|
|
component: () => import('../layout/index.vue'),
|
|
|
|
|
children: [
|
|
|
|
|
{
|
|
|
|
|
path: '/redirect/:path(.*)',
|
|
|
|
|
component: () => import('../layout/components/Router/Redirect.vue')
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
2024-07-17 17:21:52 +08:00
|
|
|
|
path: '/',
|
|
|
|
|
redirect: '/book/index'
|
|
|
|
|
},
|
|
|
|
|
{
|
2024-07-16 10:02:54 +08:00
|
|
|
|
path: '/iframe/:query?',
|
|
|
|
|
component: () => import('../layout/components/Router/Iframe.vue')
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: '/login',
|
|
|
|
|
component: () => import('../views/login/index.vue')
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: '/404',
|
|
|
|
|
component: () => import('../views/404.vue')
|
2024-07-17 17:21:52 +08:00
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: '/book/index',
|
|
|
|
|
component: () => import('../views/book/index.vue'),
|
|
|
|
|
redirect: '/book/home',
|
|
|
|
|
children: [
|
|
|
|
|
{
|
|
|
|
|
path: '/book/home',
|
|
|
|
|
component: () => import('../views/book/component/home.vue')
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: '/book/collection',
|
|
|
|
|
component: () => import('../views/book/component/collection.vue')
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: '/book/trolley',
|
|
|
|
|
component: () => import('../views/book/component/trolley.vue')
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: '/book/my',
|
|
|
|
|
component: () => import('../views/book/component/my.vue')
|
2024-07-18 16:39:55 +08:00
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: '/book/details',
|
|
|
|
|
component: () => import('../views/book/component/details.vue')
|
2024-07-17 17:21:52 +08:00
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: '/book/login',
|
|
|
|
|
component: () => import('../views/book/login.vue')
|
2024-07-18 16:39:55 +08:00
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: '/book/personal',
|
|
|
|
|
component: () => import('../views/user/index.vue')
|
2024-07-16 10:02:54 +08:00
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
const asyncRoutes: RouteRecordRaw = {
|
|
|
|
|
path: '/',
|
|
|
|
|
component: () => import('../layout/index.vue'),
|
2024-07-17 17:21:52 +08:00
|
|
|
|
redirect: '/book/index',
|
2024-07-16 10:02:54 +08:00
|
|
|
|
children: [
|
|
|
|
|
{
|
|
|
|
|
path: '/profile',
|
|
|
|
|
name: 'ProfileIndex',
|
|
|
|
|
component: () => import('../views/profile/index.vue'),
|
|
|
|
|
meta: {
|
|
|
|
|
title: '个人中心',
|
|
|
|
|
cache: true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 配置控制台菜单
|
|
|
|
|
export const dashboardMenu = [
|
|
|
|
|
{
|
|
|
|
|
id: 100,
|
2024-07-17 17:21:52 +08:00
|
|
|
|
name: '控制台',
|
2024-07-16 10:02:54 +08:00
|
|
|
|
url: null,
|
|
|
|
|
openStyle: 0,
|
|
|
|
|
icon: 'icon-appstore',
|
|
|
|
|
children: [
|
|
|
|
|
{
|
|
|
|
|
id: 101,
|
|
|
|
|
name: '首页',
|
|
|
|
|
url: 'dashboard/index',
|
|
|
|
|
openStyle: 0,
|
|
|
|
|
icon: 'icon-home',
|
|
|
|
|
affix: true
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 102,
|
|
|
|
|
name: '工作台',
|
|
|
|
|
url: 'dashboard/workbench',
|
|
|
|
|
openStyle: 0,
|
|
|
|
|
icon: 'icon-appstore'
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
// 配置常量菜单
|
|
|
|
|
export const constantMenu = [
|
|
|
|
|
{
|
|
|
|
|
id: 1000,
|
|
|
|
|
name: 'Demo',
|
|
|
|
|
url: null,
|
|
|
|
|
openStyle: 0,
|
|
|
|
|
icon: 'icon-windows',
|
|
|
|
|
children: [
|
|
|
|
|
{
|
|
|
|
|
id: 1001,
|
|
|
|
|
name: 'Icon 图标',
|
|
|
|
|
url: 'demo/icons/index',
|
|
|
|
|
openStyle: 0,
|
|
|
|
|
icon: 'icon-unorderedlist'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 1002,
|
|
|
|
|
name: '表单设计器',
|
|
|
|
|
url: 'demo/formDesign/form',
|
|
|
|
|
openStyle: 0,
|
|
|
|
|
icon: 'icon-unorderedlist'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 1003,
|
|
|
|
|
name: '表单生成器',
|
|
|
|
|
url: 'demo/formDesign/generate',
|
|
|
|
|
openStyle: 0,
|
|
|
|
|
icon: 'icon-unorderedlist'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 1004,
|
|
|
|
|
name: '二维码生成',
|
|
|
|
|
url: 'demo/qrcode/index',
|
|
|
|
|
openStyle: 0,
|
|
|
|
|
icon: 'icon-unorderedlist'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 1005,
|
|
|
|
|
name: '页面打印',
|
|
|
|
|
url: 'demo/printJs/index',
|
|
|
|
|
openStyle: 0,
|
|
|
|
|
icon: 'icon-unorderedlist'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 1006,
|
|
|
|
|
name: '图片裁剪',
|
|
|
|
|
url: 'demo/cropper/index',
|
|
|
|
|
openStyle: 0,
|
|
|
|
|
icon: 'icon-unorderedlist'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 1007,
|
|
|
|
|
name: '富文本编辑器',
|
|
|
|
|
url: 'demo/editor/index',
|
|
|
|
|
openStyle: 0,
|
|
|
|
|
icon: 'icon-unorderedlist'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 1008,
|
|
|
|
|
name: 'Markdown',
|
|
|
|
|
url: 'demo/markdown/index',
|
|
|
|
|
openStyle: 0,
|
|
|
|
|
icon: 'icon-unorderedlist'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 1009,
|
|
|
|
|
name: 'ECharts图表',
|
|
|
|
|
url: 'demo/echarts/index',
|
|
|
|
|
openStyle: 0,
|
|
|
|
|
icon: 'icon-unorderedlist'
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
export const errorRoute: RouteRecordRaw = {
|
|
|
|
|
path: '/:pathMatch(.*)',
|
|
|
|
|
redirect: '/404'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const router = createRouter({
|
|
|
|
|
history: createWebHashHistory(),
|
|
|
|
|
routes: constantRoutes
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// 白名单列表
|
2024-07-18 16:39:55 +08:00
|
|
|
|
const whiteList = [
|
|
|
|
|
'/login',
|
|
|
|
|
'/book/index',
|
|
|
|
|
'/book/login',
|
|
|
|
|
'/book/home',
|
|
|
|
|
'/book/collection',
|
|
|
|
|
'/book/trolley',
|
|
|
|
|
'/book/my',
|
|
|
|
|
'/book/personal',
|
|
|
|
|
'/book/details'
|
|
|
|
|
]
|
2024-07-16 10:02:54 +08:00
|
|
|
|
|
|
|
|
|
// 路由跳转前
|
|
|
|
|
router.beforeEach(async (to, from, next) => {
|
|
|
|
|
NProgress.start()
|
|
|
|
|
|
|
|
|
|
const appStore = useAppStore()
|
|
|
|
|
const userStore = useUserStore()
|
|
|
|
|
const routerStore = useRouterStore()
|
|
|
|
|
|
|
|
|
|
// token存在的情况
|
|
|
|
|
if (userStore.token) {
|
|
|
|
|
if (to.path === '/login') {
|
|
|
|
|
next(constant.loginPage)
|
|
|
|
|
} else {
|
|
|
|
|
// 用户信息不存在,则重新拉取
|
|
|
|
|
if (!userStore.user.id) {
|
|
|
|
|
try {
|
|
|
|
|
await userStore.getUserInfoAction()
|
|
|
|
|
await userStore.getAuthorityListAction()
|
|
|
|
|
await appStore.getDictListAction()
|
|
|
|
|
} catch (error) {
|
|
|
|
|
// 请求异常,则跳转到登录页
|
|
|
|
|
userStore?.setToken('')
|
|
|
|
|
next('/login')
|
|
|
|
|
return Promise.reject(error)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 动态菜单+常量菜单
|
|
|
|
|
const menuRoutes = await routerStore.getMenuRoutes()
|
|
|
|
|
|
|
|
|
|
// 获取扁平化路由,将多级路由转换成一级路由
|
|
|
|
|
const keepAliveRoutes = getKeepAliveRoutes(menuRoutes, [])
|
|
|
|
|
|
|
|
|
|
// 添加菜单路由
|
|
|
|
|
asyncRoutes.children?.push(...keepAliveRoutes)
|
|
|
|
|
router.addRoute(asyncRoutes)
|
|
|
|
|
|
2024-07-17 17:21:52 +08:00
|
|
|
|
// // 添加商城首页菜单
|
|
|
|
|
// router.addRoute(bookIndexRouter)
|
|
|
|
|
|
2024-07-16 10:02:54 +08:00
|
|
|
|
// 错误路由
|
|
|
|
|
router.addRoute(errorRoute)
|
|
|
|
|
|
|
|
|
|
// 保存路由数据
|
|
|
|
|
routerStore.setRoutes(constantRoutes.concat(asyncRoutes))
|
|
|
|
|
|
|
|
|
|
// 搜索菜单需要使用
|
|
|
|
|
routerStore.setSearchMenu(keepAliveRoutes)
|
|
|
|
|
|
|
|
|
|
next({ ...to, replace: true })
|
|
|
|
|
} else {
|
|
|
|
|
next()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// 没有token的情况下,可以进入白名单
|
|
|
|
|
if (whiteList.indexOf(to.path) > -1) {
|
|
|
|
|
next()
|
|
|
|
|
} else {
|
|
|
|
|
next('/login')
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// 路由加载后
|
|
|
|
|
router.afterEach(() => {
|
|
|
|
|
NProgress.done()
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// 获取扁平化路由,将多级路由转换成一级路由
|
|
|
|
|
export const getKeepAliveRoutes = (rs: RouteRecordRaw[], breadcrumb: string[]): RouteRecordRaw[] => {
|
|
|
|
|
const routerList: RouteRecordRaw[] = []
|
|
|
|
|
|
|
|
|
|
rs.forEach((item: any) => {
|
|
|
|
|
if (item.meta.title) {
|
|
|
|
|
breadcrumb.push(item.meta.title)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (item.children && item.children.length > 0) {
|
|
|
|
|
routerList.push(...getKeepAliveRoutes(item.children, breadcrumb))
|
|
|
|
|
} else {
|
|
|
|
|
item.meta.breadcrumb.push(...breadcrumb)
|
|
|
|
|
routerList.push(item)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
breadcrumb.pop()
|
|
|
|
|
})
|
|
|
|
|
return routerList
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 加载vue组件
|
|
|
|
|
export interface ModuleMap {
|
|
|
|
|
[key: string]: any
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const layoutModules = () => {
|
|
|
|
|
return import.meta.glob('/src/views/**/*.vue')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 根据路径,动态获取vue组件
|
|
|
|
|
const getDynamicComponent = (path: string): any => {
|
|
|
|
|
const modules: ModuleMap = layoutModules()
|
|
|
|
|
return modules[`/src/views/${path}.vue`]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 根据菜单列表,生成路由数据
|
|
|
|
|
export const generateRoutes = (menuList: any): RouteRecordRaw[] => {
|
|
|
|
|
const routerList: RouteRecordRaw[] = []
|
|
|
|
|
|
|
|
|
|
menuList.forEach((menu: any) => {
|
|
|
|
|
let component
|
|
|
|
|
let path
|
|
|
|
|
if (menu.children && menu.children.length > 0) {
|
|
|
|
|
component = () => import('@/layout/index.vue')
|
|
|
|
|
path = '/p/' + menu.id
|
|
|
|
|
} else {
|
|
|
|
|
// 判断是否iframe
|
|
|
|
|
if (isIframeUrl(menu)) {
|
|
|
|
|
component = () => import('@/layout/components/Router/Iframe.vue')
|
|
|
|
|
path = '/iframe/' + menu.id
|
|
|
|
|
} else {
|
|
|
|
|
component = getDynamicComponent(menu.url)
|
|
|
|
|
path = '/' + menu.url
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
const route: RouteRecordRaw = {
|
|
|
|
|
path: path,
|
|
|
|
|
name: pathToCamel(path),
|
|
|
|
|
component: component,
|
|
|
|
|
children: [],
|
|
|
|
|
meta: {
|
|
|
|
|
title: menu.name,
|
|
|
|
|
icon: menu.icon,
|
|
|
|
|
id: '' + menu.id,
|
|
|
|
|
url: menu.url,
|
|
|
|
|
cache: true,
|
|
|
|
|
newOpen: menu.openStyle === 1,
|
|
|
|
|
affix: menu.affix,
|
|
|
|
|
breadcrumb: []
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 有子菜单的情况
|
|
|
|
|
if (menu.children && menu.children.length > 0) {
|
|
|
|
|
route.children?.push(...generateRoutes(menu.children))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
routerList.push(route)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
return routerList
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 判断是否iframe
|
|
|
|
|
const isIframeUrl = (menu: any): boolean => {
|
|
|
|
|
// 如果是新页面打开,则不用iframe
|
|
|
|
|
if (menu.openStyle === 1) {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 是否外部链接
|
|
|
|
|
return isExternalLink(menu.url)
|
|
|
|
|
}
|