diff --git a/.env b/.env index b48df03..77ad0d3 100644 --- a/.env +++ b/.env @@ -5,7 +5,7 @@ VITE_APP_NAME=Nova - Admin # 路由模式 VITE_ROUTE_MODE = web # 权限路由模式: static | dynamic -VITE_AUTH_ROUTE_MODE=static +VITE_AUTH_ROUTE_MODE=dynamic # 设置登陆后跳转地址 VITE_HOME_PATH = /dashboard/workbench diff --git a/src/router/routes.static.ts b/src/router/routes.static.ts index 9971d0a..2acfc26 100644 --- a/src/router/routes.static.ts +++ b/src/router/routes.static.ts @@ -5,6 +5,7 @@ export const staticRoutes: AppRoute.RowRoute[] = [ 'meta.title': '仪表盘', 'meta.requiresAuth': true, 'meta.icon': 'icon-park-outline:analysis', + 'meta.menuType': 'dir', 'componentPath': null, 'id': 1, 'pid': null, @@ -16,6 +17,7 @@ export const staticRoutes: AppRoute.RowRoute[] = [ 'meta.requiresAuth': true, 'meta.icon': 'icon-park-outline:alarm', 'meta.pinTab': true, + 'meta.menuType': 'page', 'componentPath': '/dashboard/workbench/index.vue', 'id': 2, 'pid': 1, @@ -26,6 +28,7 @@ export const staticRoutes: AppRoute.RowRoute[] = [ 'meta.title': '监控页', 'meta.requiresAuth': true, 'meta.icon': 'icon-park-outline:anchor', + 'meta.menuType': 'page', 'componentPath': '/dashboard/monitor/index.vue', 'id': 3, 'pid': 1, @@ -36,6 +39,7 @@ export const staticRoutes: AppRoute.RowRoute[] = [ 'meta.title': '多级菜单演示', 'meta.requiresAuth': true, 'meta.icon': 'icon-park-outline:list', + 'meta.menuType': 'dir', 'componentPath': null, 'id': 4, 'pid': null, @@ -46,6 +50,7 @@ export const staticRoutes: AppRoute.RowRoute[] = [ 'meta.title': '多级菜单子页', 'meta.requiresAuth': true, 'meta.icon': 'icon-park-outline:list', + 'meta.menuType': 'page', 'componentPath': '/test/test2/index.vue', 'id': 6, 'pid': 4, @@ -58,6 +63,7 @@ export const staticRoutes: AppRoute.RowRoute[] = [ 'meta.icon': 'icon-park-outline:list', 'meta.hide': true, 'meta.activeMenu': '/test/test2', + 'meta.menuType': 'page', 'componentPath': '/test/test2/detail/index.vue', 'id': 7, 'pid': 4, @@ -68,6 +74,7 @@ export const staticRoutes: AppRoute.RowRoute[] = [ 'meta.title': '多级菜单', 'meta.requiresAuth': true, 'meta.icon': 'icon-park-outline:list', + 'meta.menuType': 'dir', 'componentPath': null, 'id': 8, 'pid': 4, @@ -88,6 +95,7 @@ export const staticRoutes: AppRoute.RowRoute[] = [ 'meta.title': '列表页', 'meta.requiresAuth': true, 'meta.icon': 'icon-park-outline:list-two', + 'meta.menuType': 'dir', 'componentPath': null, 'id': 10, 'pid': null, @@ -118,6 +126,7 @@ export const staticRoutes: AppRoute.RowRoute[] = [ 'meta.title': '功能示例', 'meta.requiresAuth': true, 'meta.icon': 'icon-park-outline:application-one', + 'meta.menuType': 'dir', 'componentPath': null, 'id': 13, 'pid': null, @@ -159,6 +168,7 @@ export const staticRoutes: AppRoute.RowRoute[] = [ 'meta.title': '编辑器', 'meta.requiresAuth': true, 'meta.icon': 'icon-park-outline:editor', + 'meta.menuType': 'dir', 'componentPath': null, 'id': 18, 'pid': 13, @@ -219,6 +229,7 @@ export const staticRoutes: AppRoute.RowRoute[] = [ 'meta.title': '外链文档', 'meta.requiresAuth': true, 'meta.icon': 'icon-park-outline:file-doc', + 'meta.menuType': 'dir', 'componentPath': null, 'id': 24, 'pid': null, @@ -260,6 +271,7 @@ export const staticRoutes: AppRoute.RowRoute[] = [ 'meta.title': '权限', 'meta.requiresAuth': true, 'meta.icon': 'icon-park-outline:people-safe', + 'meta.menuType': 'dir', 'componentPath': null, 'id': 28, 'pid': null, @@ -293,6 +305,7 @@ export const staticRoutes: AppRoute.RowRoute[] = [ 'meta.title': '异常页', 'meta.requiresAuth': true, 'meta.icon': 'icon-park-outline:error-computer', + 'meta.menuType': 'dir', 'componentPath': null, 'id': 31, 'pid': null, @@ -336,6 +349,7 @@ export const staticRoutes: AppRoute.RowRoute[] = [ 'meta.title': '系统设置', 'meta.requiresAuth': true, 'meta.icon': 'icon-park-outline:setting', + 'meta.menuType': 'dir', 'componentPath': null, 'id': 35, 'pid': null, diff --git a/src/service/api/login.ts b/src/service/api/login.ts index 59b41b4..09bd04b 100644 --- a/src/service/api/login.ts +++ b/src/service/api/login.ts @@ -1,7 +1,7 @@ import { request } from '../http' interface Ilogin { - username: string + userName: string password: string } diff --git a/src/store/auth.ts b/src/store/auth.ts index ff66f27..8605590 100644 --- a/src/store/auth.ts +++ b/src/store/auth.ts @@ -52,8 +52,8 @@ export const useAuthStore = defineStore('auth-store', { }, /* 用户登录 */ - async login(username: string, password: string) { - const { isSuccess, data } = await fetchLogin({ username, password }) + async login(userName: string, password: string) { + const { isSuccess, data } = await fetchLogin({ userName, password }) if (!isSuccess) { window.$message.error('登录失败,请检查用户名和密码') return diff --git a/src/store/route.ts b/src/store/route.ts index 4274b88..316172e 100644 --- a/src/store/route.ts +++ b/src/store/route.ts @@ -72,7 +72,7 @@ export const useRouteStore = defineStore('route-store', { id: item.id, pid: item.pid, label: - (!item.children || item.children.length === 0) + (!item.meta.menuType || item.meta.menuType === 'page') ? () => h( RouterLink, @@ -83,36 +83,13 @@ export const useRouteStore = defineStore('route-store', { }, { default: () => $t(`route.${String(item.name)}`, item.meta.title) }, ) - : $t(`route.${String(item.name)}`, item.meta.title), + : () => $t(`route.${String(item.name)}`, item.meta.title), key: item.path, icon: item.meta.icon ? renderIcon(item.meta.icon) : undefined, } return target }) }, - setRedirect(routes: AppRoute.Route[]) { - routes.forEach((route) => { - if (route.children) { - if (!route.redirect) { - // 过滤出没有隐藏的子元素集 - const visibleChilds = route.children.filter(child => !child.meta.hide) - - // 过滤出含有order属性的页面 - const orderChilds = visibleChilds.filter(child => child.meta.order) - - // 重定向页默认第一个子元素的路径 - let target = route.children[0] - if (orderChilds.length > 0) - // 有order则取最小者重定向 - target = min(orderChilds, i => i.meta.order as number) as AppRoute.Route - - route.redirect = target.path - } - - this.setRedirect(route.children) - } - }) - }, createRoutes(routes: AppRoute.RowRoute[]) { const { hasPermission } = usePermission() // 结构化meta字段 @@ -128,14 +105,19 @@ export const useRouteStore = defineStore('route-store', { // 生成路由,有redirect的不需要引入文件 const modules = import.meta.glob('@/views/**/*.vue') - resultRouter = resultRouter.map((item: any) => { + resultRouter = resultRouter.map((item: AppRoute.Route) => { if (item.componentPath && !item.redirect) item.component = modules[`/src/views${item.componentPath}`] + + // 判断是否是目录,代表目录的路由没有实际页面 + if (item.meta.menuType === 'dir') + item.redirect = '/404' + return item }) + // 生成路由表 resultRouter = arrayToTree(resultRouter) as AppRoute.Route[] - this.setRedirect(resultRouter) const appRootRoute: RouteRecordRaw = { path: '/appRoot', name: 'appRoot', diff --git a/src/typings/api.d.ts b/src/typings/api.d.ts index 337f3ca..e561316 100644 --- a/src/typings/api.d.ts +++ b/src/typings/api.d.ts @@ -7,7 +7,7 @@ declare namespace ApiAuth { /** 用户id */ id: number /** 用户名 */ - username: string + userName: string /* 用户头像 */ avatar?: string /* 用户邮箱 */ diff --git a/src/typings/route.d.ts b/src/typings/route.d.ts index 85c4a22..7b89166 100644 --- a/src/typings/route.d.ts +++ b/src/typings/route.d.ts @@ -23,10 +23,10 @@ declare namespace AppRoute { withoutTab?: boolean /** 当前路由是否会被固定在Tab中,用于一些常驻页面 */ pinTab?: boolean - /** 当前路由i18n标识 */ - i18nKey?: string + /** 当前路由在左侧菜单是目录还是页面,不设置默认为page */ + menuType?: 'dir' | 'page' } - /** 单个路由的类型结构(动态路由模式:后端返回此类型结构的路由) */ + interface baseRoute { /** 路由名称(路由唯一标识) */ name: string @@ -42,6 +42,7 @@ declare namespace AppRoute { pid: number | null } + /** 单个路由的类型结构(动态路由模式:后端返回此类型结构的路由) */ type RowRoute = { [K in keyof RouteMeta as `meta.${K}`]?: RouteMeta[K] } & baseRoute diff --git a/src/views/userCenter/index.vue b/src/views/userCenter/index.vue index 7e440ae..33c7e1e 100644 --- a/src/views/userCenter/index.vue +++ b/src/views/userCenter/index.vue @@ -52,7 +52,7 @@ function handleValidateClick() { {{ userInfo?.id }} - {{ userInfo?.username }} + {{ userInfo?.userName }} {{ userInfo?.nickname }}