mirror of
https://github.com/jekip/naive-ui-admin.git
synced 2026-02-04 13:42:27 +08:00
Fixes bug 动态路由配置重构
This commit is contained in:
16
CHANGELOG.md
16
CHANGELOG.md
@@ -1,3 +1,19 @@
|
|||||||
|
# CHANGELOG
|
||||||
|
|
||||||
|
## 1.5.4 (2021-08-10)
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
- `暗色模式下多页签背景问题 ` 合并 [#23](https://github.com/jekip/naive-ui-admin/pull/23) 感谢 [@Dishone](https://github.com/Dishone)
|
||||||
|
- `表格设置列,重复添加action列样式错乱问题` 合并 [#24](https://github.com/jekip/naive-ui-admin/pull/24) 感谢 [@CasbaL](https://github.com/CasbaL)
|
||||||
|
|
||||||
|
- ### ✨ Features
|
||||||
|
-(破坏性更新)
|
||||||
|
- 优化 `动态路由配置` 取消`constantRouterComponents.ts`,中组件映射配置,更名为 `router-icons.ts`
|
||||||
|
- 优化 `admin_info接口结构`,roles 更名为:permissions,roles.roleName,更名为:label
|
||||||
|
- 优化 多级路由,当没有配置时,`redirect` ,`redirect` 默认为第一个子路由,配置则优先按配置
|
||||||
|
- 依赖升级
|
||||||
|
|
||||||
# 1.5.3 (2021-08-09)
|
# 1.5.3 (2021-08-09)
|
||||||
### 🐛 Bug Fixes
|
### 🐛 Bug Fixes
|
||||||
- 修复顶部菜单,选中联动
|
- 修复顶部菜单,选中联动
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ const menusList = [
|
|||||||
{
|
{
|
||||||
path: '/dashboard',
|
path: '/dashboard',
|
||||||
name: 'Dashboard',
|
name: 'Dashboard',
|
||||||
component: 'Layout',
|
component: 'LAYOUT',
|
||||||
redirect: '/dashboard/console',
|
redirect: '/dashboard/console',
|
||||||
meta: {
|
meta: {
|
||||||
icon: 'DashboardOutlined',
|
icon: 'DashboardOutlined',
|
||||||
@@ -14,7 +14,7 @@ const menusList = [
|
|||||||
{
|
{
|
||||||
path: 'console',
|
path: 'console',
|
||||||
name: 'dashboard_console',
|
name: 'dashboard_console',
|
||||||
component: 'DashboardConsole',
|
component: '/dashboard/console/console',
|
||||||
meta: {
|
meta: {
|
||||||
title: '主控台',
|
title: '主控台',
|
||||||
},
|
},
|
||||||
@@ -22,7 +22,7 @@ const menusList = [
|
|||||||
{
|
{
|
||||||
path: 'monitor',
|
path: 'monitor',
|
||||||
name: 'dashboard_monitor',
|
name: 'dashboard_monitor',
|
||||||
component: 'DashboardMonitor',
|
component: '/dashboard/monitor/monitor',
|
||||||
meta: {
|
meta: {
|
||||||
title: '监控页',
|
title: '监控页',
|
||||||
},
|
},
|
||||||
@@ -30,7 +30,7 @@ const menusList = [
|
|||||||
{
|
{
|
||||||
path: 'workplace',
|
path: 'workplace',
|
||||||
name: 'dashboard_workplace',
|
name: 'dashboard_workplace',
|
||||||
component: 'DashboardWorkplace',
|
component: '/dashboard/workplace/workplace',
|
||||||
meta: {
|
meta: {
|
||||||
hidden: true,
|
hidden: true,
|
||||||
title: '工作台',
|
title: '工作台',
|
||||||
|
|||||||
@@ -13,25 +13,25 @@ const adminInfo = {
|
|||||||
desc: 'manager',
|
desc: 'manager',
|
||||||
password: Random.string('upper', 4, 16),
|
password: Random.string('upper', 4, 16),
|
||||||
token,
|
token,
|
||||||
roles: [
|
permissions: [
|
||||||
{
|
{
|
||||||
roleName: '主控台',
|
label: '主控台',
|
||||||
value: 'dashboard_console',
|
value: 'dashboard_console',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
roleName: '监控页',
|
label: '监控页',
|
||||||
value: 'dashboard_monitor',
|
value: 'dashboard_monitor',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
roleName: '工作台',
|
label: '工作台',
|
||||||
value: 'dashboard_workplace',
|
value: 'dashboard_workplace',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
roleName: '基础列表',
|
label: '基础列表',
|
||||||
value: 'basic_list',
|
value: 'basic_list',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
roleName: '基础列表删除',
|
label: '基础列表删除',
|
||||||
value: 'basic_list_delete',
|
value: 'basic_list_delete',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "naive-ui-admin",
|
"name": "naive-ui-admin",
|
||||||
"version": "1.5.3",
|
"version": "1.5.4",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Ahjung",
|
"name": "Ahjung",
|
||||||
"email": "735878602@qq.com",
|
"email": "735878602@qq.com",
|
||||||
@@ -87,7 +87,7 @@
|
|||||||
"stylelint-scss": "^3.19.0",
|
"stylelint-scss": "^3.19.0",
|
||||||
"tailwindcss": "^2.2.7",
|
"tailwindcss": "^2.2.7",
|
||||||
"typescript": "^4.3.5",
|
"typescript": "^4.3.5",
|
||||||
"vite": "2.3.6",
|
"vite": "2.4.4",
|
||||||
"vite-plugin-compression": "^0.3.1",
|
"vite-plugin-compression": "^0.3.1",
|
||||||
"vite-plugin-html": "^2.0.7",
|
"vite-plugin-html": "^2.0.7",
|
||||||
"vite-plugin-mock": "^2.9.3",
|
"vite-plugin-mock": "^2.9.3",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { NButton } from 'naive-ui';
|
import { NButton } from 'naive-ui';
|
||||||
import { RoleEnum } from '@/enums/roleEnum';
|
import { PermissionsEnum } from '@/enums/permissionsEnum';
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
export interface ActionItem extends NButton.props {
|
export interface ActionItem extends NButton.props {
|
||||||
onClick?: Fn;
|
onClick?: Fn;
|
||||||
@@ -11,7 +11,7 @@ export interface ActionItem extends NButton.props {
|
|||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
divider?: boolean;
|
divider?: boolean;
|
||||||
// 权限编码控制是否显示
|
// 权限编码控制是否显示
|
||||||
auth?: RoleEnum | RoleEnum[] | string | string[];
|
auth?: PermissionsEnum | PermissionsEnum[] | string | string[];
|
||||||
// 业务控制是否显示
|
// 业务控制是否显示
|
||||||
ifShow?: boolean | ((action: ActionItem) => boolean);
|
ifShow?: boolean | ((action: ActionItem) => boolean);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ export function usePermission() {
|
|||||||
* 检查权限
|
* 检查权限
|
||||||
* @param accesses
|
* @param accesses
|
||||||
*/
|
*/
|
||||||
function _someRoles(accesses: string[]) {
|
function _somePermissions(accesses: string[]) {
|
||||||
return userStore.getRoles.some((item) => {
|
return userStore.getPermissions.some((item) => {
|
||||||
const { value }: any = item;
|
const { value }: any = item;
|
||||||
return accesses.includes(value);
|
return accesses.includes(value);
|
||||||
});
|
});
|
||||||
@@ -20,7 +20,7 @@ export function usePermission() {
|
|||||||
* */
|
* */
|
||||||
function hasPermission(accesses: string[]): boolean {
|
function hasPermission(accesses: string[]): boolean {
|
||||||
if (!accesses || !accesses.length) return true;
|
if (!accesses || !accesses.length) return true;
|
||||||
return _someRoles(accesses);
|
return _somePermissions(accesses);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -28,9 +28,9 @@ export function usePermission() {
|
|||||||
* @param accesses
|
* @param accesses
|
||||||
*/
|
*/
|
||||||
function hasEveryPermission(accesses: string[]): boolean {
|
function hasEveryPermission(accesses: string[]): boolean {
|
||||||
const rolesList = userStore.getRoles;
|
const permissionsList = userStore.getPermissions;
|
||||||
if (Array.isArray(accesses)) {
|
if (Array.isArray(accesses)) {
|
||||||
return accesses.every((access) => !!rolesList[access]);
|
return accesses.every((access) => !!permissionsList[access]);
|
||||||
}
|
}
|
||||||
throw new Error(`[hasEveryPermission]: ${accesses} should be a array !`);
|
throw new Error(`[hasEveryPermission]: ${accesses} should be a array !`);
|
||||||
}
|
}
|
||||||
@@ -41,9 +41,9 @@ export function usePermission() {
|
|||||||
* @param accessMap
|
* @param accessMap
|
||||||
*/
|
*/
|
||||||
function hasSomePermission(accesses: string[]): boolean {
|
function hasSomePermission(accesses: string[]): boolean {
|
||||||
const rolesList = userStore.getRoles;
|
const permissionsList = userStore.getPermissions;
|
||||||
if (Array.isArray(accesses)) {
|
if (Array.isArray(accesses)) {
|
||||||
return accesses.some((access) => !!rolesList[access]);
|
return accesses.some((access) => !!permissionsList[access]);
|
||||||
}
|
}
|
||||||
throw new Error(`[hasSomePermission]: ${accesses} should be a array !`);
|
throw new Error(`[hasSomePermission]: ${accesses} should be a array !`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export const ErrorPageRoute: AppRouteRecordRaw = {
|
|||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '/:path(.*)*',
|
path: '/:path(.*)*',
|
||||||
name: 'ErrorPage',
|
name: 'ErrorPageSon',
|
||||||
component: ErrorPage,
|
component: ErrorPage,
|
||||||
meta: {
|
meta: {
|
||||||
title: 'ErrorPage',
|
title: 'ErrorPage',
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
import { renderIcon } from '@/utils/index';
|
|
||||||
import { DashboardOutlined } from '@vicons/antd';
|
|
||||||
// import { RouterTransition } from '@/components/transition'
|
|
||||||
|
|
||||||
//前端路由映射表
|
|
||||||
export const constantRouterComponents = {
|
|
||||||
Layout: () => import('@/layout/index.vue'), //布局
|
|
||||||
DashboardConsole: () => import('@/views/dashboard/console/console.vue'), // 主控台
|
|
||||||
DashboardMonitor: () => import('@/views/dashboard/monitor/monitor.vue'), // 监控页
|
|
||||||
DashboardWorkplace: () => import('@/views/dashboard/workplace/workplace.vue'), // 工作台
|
|
||||||
};
|
|
||||||
|
|
||||||
//前端路由图标映射表
|
|
||||||
export const constantRouterIcon = {
|
|
||||||
DashboardOutlined: renderIcon(DashboardOutlined),
|
|
||||||
};
|
|
||||||
@@ -1,12 +1,19 @@
|
|||||||
import { adminMenus } from '@/api/system/menu';
|
import { adminMenus } from '@/api/system/menu';
|
||||||
import { constantRouterComponents, constantRouterIcon } from './constantRouterComponents';
|
import { constantRouterIcon } from './router-icons';
|
||||||
import router from '@/router/index';
|
import router from '@/router/index';
|
||||||
import { constantRouter } from '@/router/index';
|
import { constantRouter } from '@/router/index';
|
||||||
import { RouteRecordRaw } from 'vue-router';
|
import { RouteRecordRaw } from 'vue-router';
|
||||||
|
import { Layout, ParentLayout } from '@/router/constant';
|
||||||
|
import type { AppRouteRecordRaw } from '@/router/types';
|
||||||
|
|
||||||
|
const Iframe = () => import('@/views/iframe/index.vue');
|
||||||
|
const LayoutMap = new Map<string, () => Promise<typeof import('*.vue')>>();
|
||||||
|
|
||||||
|
LayoutMap.set('LAYOUT', Layout);
|
||||||
|
LayoutMap.set('IFRAME', Iframe);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 格式化 后端 结构信息并递归生成层级路由表
|
* 格式化 后端 结构信息并递归生成层级路由表
|
||||||
*
|
|
||||||
* @param routerMap
|
* @param routerMap
|
||||||
* @param parent
|
* @param parent
|
||||||
* @returns {*}
|
* @returns {*}
|
||||||
@@ -19,21 +26,24 @@ export const routerGenerator = (routerMap, parent?): any[] => {
|
|||||||
// 路由名称,建议唯一
|
// 路由名称,建议唯一
|
||||||
name: item.name || '',
|
name: item.name || '',
|
||||||
// 该路由对应页面的 组件
|
// 该路由对应页面的 组件
|
||||||
component: constantRouterComponents[item.component],
|
component: item.component,
|
||||||
// meta: 页面标题, 菜单图标, 页面权限(供指令权限用,可去掉)
|
// meta: 页面标题, 菜单图标, 页面权限(供指令权限用,可去掉)
|
||||||
meta: {
|
meta: {
|
||||||
...item.meta,
|
...item.meta,
|
||||||
label: item.meta.title,
|
label: item.meta.title,
|
||||||
icon: constantRouterIcon[item.meta.icon] || null,
|
icon: constantRouterIcon[item.meta.icon] || null,
|
||||||
permission: item.meta.permission || null,
|
permissions: item.meta.permissions || null,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// 为了防止出现后端返回结果不规范,处理有可能出现拼接出两个 反斜杠
|
// 为了防止出现后端返回结果不规范,处理有可能出现拼接出两个 反斜杠
|
||||||
currentRouter.path = currentRouter.path.replace('//', '/');
|
currentRouter.path = currentRouter.path.replace('//', '/');
|
||||||
// 重定向
|
// 重定向
|
||||||
item.redirect && (currentRouter.redirect = item.redirect);
|
item.redirect && (currentRouter.redirect = item.redirect);
|
||||||
// 是否有子菜单,并递归处理
|
// 是否有子菜单,并递归处理
|
||||||
if (item.children && item.children.length > 0) {
|
if (item.children && item.children.length > 0) {
|
||||||
|
//如果未定义 redirect 默认第一个子路由为 redirect
|
||||||
|
!item.redirect && (currentRouter.redirect = `${item.path}/${item.children[0].path}`);
|
||||||
// Recursion
|
// Recursion
|
||||||
currentRouter.children = routerGenerator(item.children, currentRouter);
|
currentRouter.children = routerGenerator(item.children, currentRouter);
|
||||||
}
|
}
|
||||||
@@ -43,7 +53,6 @@ export const routerGenerator = (routerMap, parent?): any[] => {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 动态生成菜单
|
* 动态生成菜单
|
||||||
* @param token
|
|
||||||
* @returns {Promise<Router>}
|
* @returns {Promise<Router>}
|
||||||
*/
|
*/
|
||||||
export const generatorDynamicRouter = (): Promise<RouteRecordRaw[]> => {
|
export const generatorDynamicRouter = (): Promise<RouteRecordRaw[]> => {
|
||||||
@@ -51,7 +60,8 @@ export const generatorDynamicRouter = (): Promise<RouteRecordRaw[]> => {
|
|||||||
adminMenus()
|
adminMenus()
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
const routeList = routerGenerator(result);
|
const routeList = routerGenerator(result);
|
||||||
const asyncRoutesList = [...constantRouter, ...routeList];
|
asyncImportRoute(routeList);
|
||||||
|
const asyncRoutesList = [...routeList, ...constantRouter];
|
||||||
asyncRoutesList.forEach((item) => {
|
asyncRoutesList.forEach((item) => {
|
||||||
router.addRoute(item);
|
router.addRoute(item);
|
||||||
});
|
});
|
||||||
@@ -62,3 +72,56 @@ export const generatorDynamicRouter = (): Promise<RouteRecordRaw[]> => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查找views中对应的组件文件
|
||||||
|
* */
|
||||||
|
let viewsModules: Record<string, () => Promise<Recordable>>;
|
||||||
|
export const asyncImportRoute = (routes: AppRouteRecordRaw[] | undefined): void => {
|
||||||
|
viewsModules = viewsModules || import.meta.glob('../views/**/*.{vue,tsx}');
|
||||||
|
if (!routes) return;
|
||||||
|
routes.forEach((item) => {
|
||||||
|
if (!item.component && item.meta?.frameSrc) {
|
||||||
|
item.component = 'IFRAME';
|
||||||
|
}
|
||||||
|
const { component, name } = item;
|
||||||
|
const { children } = item;
|
||||||
|
if (component) {
|
||||||
|
const layoutFound = LayoutMap.get(component as string);
|
||||||
|
if (layoutFound) {
|
||||||
|
item.component = layoutFound;
|
||||||
|
} else {
|
||||||
|
item.component = dynamicImport(viewsModules, component as string);
|
||||||
|
}
|
||||||
|
} else if (name) {
|
||||||
|
item.component = ParentLayout;
|
||||||
|
}
|
||||||
|
children && asyncImportRoute(children);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 动态导入
|
||||||
|
* */
|
||||||
|
export const dynamicImport = (
|
||||||
|
viewsModules: Record<string, () => Promise<Recordable>>,
|
||||||
|
component: string
|
||||||
|
) => {
|
||||||
|
const keys = Object.keys(viewsModules);
|
||||||
|
const matchKeys = keys.filter((key) => {
|
||||||
|
let k = key.replace('../views', '');
|
||||||
|
const lastIndex = k.lastIndexOf('.');
|
||||||
|
k = k.substring(0, lastIndex);
|
||||||
|
return k === component;
|
||||||
|
});
|
||||||
|
if (matchKeys?.length === 1) {
|
||||||
|
const matchKey = matchKeys[0];
|
||||||
|
return viewsModules[matchKey];
|
||||||
|
}
|
||||||
|
if (matchKeys?.length > 1) {
|
||||||
|
console.warn(
|
||||||
|
'Please do not create `.vue` and `.TSX` files with the same file name in the same hierarchical directory under the views folder. This will cause dynamic introduction failure'
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { App } from 'vue';
|
import { App } from 'vue';
|
||||||
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router';
|
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router';
|
||||||
import { ErrorPageRoute, RedirectRoute } from '@/router/base';
|
import { RedirectRoute } from '@/router/base';
|
||||||
import { PageEnum } from '@/enums/pageEnum';
|
import { PageEnum } from '@/enums/pageEnum';
|
||||||
import { createRouterGuards } from './router-guards';
|
import { createRouterGuards } from './router-guards';
|
||||||
|
|
||||||
@@ -40,7 +40,7 @@ export const LoginRoute: RouteRecordRaw = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
//需要验证权限
|
//需要验证权限
|
||||||
export const asyncRoutes = [ErrorPageRoute, ...routeModuleList];
|
export const asyncRoutes = [...routeModuleList];
|
||||||
|
|
||||||
//普通路由 无需验证权限
|
//普通路由 无需验证权限
|
||||||
export const constantRouter: any[] = [LoginRoute, RootRoute, RedirectRoute];
|
export const constantRouter: any[] = [LoginRoute, RootRoute, RedirectRoute];
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
meta: {
|
meta: {
|
||||||
title: 'Dashboard',
|
title: 'Dashboard',
|
||||||
icon: renderIcon(DashboardOutlined),
|
icon: renderIcon(DashboardOutlined),
|
||||||
permission: ['dashboard_console', 'dashboard_console', 'dashboard_workplace'],
|
permissions: ['dashboard_console', 'dashboard_console', 'dashboard_workplace'],
|
||||||
sort: 0,
|
sort: 0,
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
@@ -33,7 +33,7 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
name: `${routeName}_console`,
|
name: `${routeName}_console`,
|
||||||
meta: {
|
meta: {
|
||||||
title: '主控台',
|
title: '主控台',
|
||||||
permission: ['dashboard_console'],
|
permissions: ['dashboard_console'],
|
||||||
},
|
},
|
||||||
component: () => import('@/views/dashboard/console/console.vue'),
|
component: () => import('@/views/dashboard/console/console.vue'),
|
||||||
},
|
},
|
||||||
@@ -42,7 +42,7 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
// name: `${ routeName }_monitor`,
|
// name: `${ routeName }_monitor`,
|
||||||
// meta: {
|
// meta: {
|
||||||
// title: '监控页',
|
// title: '监控页',
|
||||||
// permission: ['dashboard_monitor']
|
// permissions: ['dashboard_monitor']
|
||||||
// },
|
// },
|
||||||
// component: () => import('@/views/dashboard/monitor/monitor.vue')
|
// component: () => import('@/views/dashboard/monitor/monitor.vue')
|
||||||
// },
|
// },
|
||||||
@@ -52,7 +52,7 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
meta: {
|
meta: {
|
||||||
title: '工作台',
|
title: '工作台',
|
||||||
keepAlive: true,
|
keepAlive: true,
|
||||||
permission: ['dashboard_workplace'],
|
permissions: ['dashboard_workplace'],
|
||||||
},
|
},
|
||||||
component: () => import('@/views/dashboard/workplace/workplace.vue'),
|
component: () => import('@/views/dashboard/workplace/workplace.vue'),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
|
import type { RouteRecordRaw } from 'vue-router';
|
||||||
import { isNavigationFailure, Router } from 'vue-router';
|
import { isNavigationFailure, Router } from 'vue-router';
|
||||||
import { useUserStoreWidthOut } from '@/store/modules/user';
|
import { useUserStoreWidthOut } from '@/store/modules/user';
|
||||||
import { useAsyncRouteStoreWidthOut } from '@/store/modules/asyncRoute';
|
import { useAsyncRouteStoreWidthOut } from '@/store/modules/asyncRoute';
|
||||||
import { ACCESS_TOKEN } from '@/store/mutation-types';
|
import { ACCESS_TOKEN } from '@/store/mutation-types';
|
||||||
import { storage } from '@/utils/Storage';
|
import { storage } from '@/utils/Storage';
|
||||||
import { PageEnum } from '@/enums/pageEnum';
|
import { PageEnum } from '@/enums/pageEnum';
|
||||||
|
import { ErrorPageRoute } from '@/router/base';
|
||||||
|
|
||||||
const LOGIN_PATH = PageEnum.BASE_LOGIN;
|
const LOGIN_PATH = PageEnum.BASE_LOGIN;
|
||||||
|
|
||||||
@@ -29,7 +31,7 @@ export function createRouterGuards(router: Router) {
|
|||||||
const token = storage.get(ACCESS_TOKEN);
|
const token = storage.get(ACCESS_TOKEN);
|
||||||
|
|
||||||
if (!token) {
|
if (!token) {
|
||||||
// You can access without permission. You need to set the routing meta.ignoreAuth to true
|
// You can access without permissions. You need to set the routing meta.ignoreAuth to true
|
||||||
if (to.meta.ignoreAuth) {
|
if (to.meta.ignoreAuth) {
|
||||||
next();
|
next();
|
||||||
return;
|
return;
|
||||||
@@ -60,9 +62,15 @@ export function createRouterGuards(router: Router) {
|
|||||||
|
|
||||||
// 动态添加可访问路由表
|
// 动态添加可访问路由表
|
||||||
routes.forEach((item) => {
|
routes.forEach((item) => {
|
||||||
router.addRoute(item);
|
router.addRoute(item as unknown as RouteRecordRaw);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//添加404
|
||||||
|
const isErrorPage = router.getRoutes().findIndex((item) => item.name === ErrorPageRoute.name);
|
||||||
|
if (isErrorPage === -1) {
|
||||||
|
router.addRoute(ErrorPageRoute as unknown as RouteRecordRaw);
|
||||||
|
}
|
||||||
|
|
||||||
const redirectPath = (from.query.redirect || to.path) as string;
|
const redirectPath = (from.query.redirect || to.path) as string;
|
||||||
const redirect = decodeURIComponent(redirectPath);
|
const redirect = decodeURIComponent(redirectPath);
|
||||||
const nextData = to.path === redirect ? { ...to, replace: true } : { path: redirect };
|
const nextData = to.path === redirect ? { ...to, replace: true } : { path: redirect };
|
||||||
|
|||||||
7
src/router/router-icons.ts
Normal file
7
src/router/router-icons.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { renderIcon } from '@/utils/index';
|
||||||
|
import { DashboardOutlined } from '@vicons/antd';
|
||||||
|
|
||||||
|
//前端路由图标映射表
|
||||||
|
export const constantRouterIcon = {
|
||||||
|
DashboardOutlined: renderIcon(DashboardOutlined),
|
||||||
|
};
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
import type { RouteRecordRaw, RouteMeta } from 'vue-router';
|
import type { RouteRecordRaw, RouteMeta } from 'vue-router';
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { RoleEnum } from '@/enums/roleEnum';
|
|
||||||
|
|
||||||
export type Component<T extends any = any> =
|
export type Component<T extends any = any> =
|
||||||
| ReturnType<typeof defineComponent>
|
| ReturnType<typeof defineComponent>
|
||||||
@@ -23,7 +22,7 @@ export interface Meta {
|
|||||||
title: string;
|
title: string;
|
||||||
// 是否忽略权限
|
// 是否忽略权限
|
||||||
ignoreAuth?: boolean;
|
ignoreAuth?: boolean;
|
||||||
roles?: RoleEnum[];
|
permissions?: string[];
|
||||||
// 是否不缓存
|
// 是否不缓存
|
||||||
noKeepAlive?: boolean;
|
noKeepAlive?: boolean;
|
||||||
// 是否固定在tab上
|
// 是否固定在tab上
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ const setting = {
|
|||||||
//显示图标
|
//显示图标
|
||||||
showIcon: false,
|
showIcon: false,
|
||||||
},
|
},
|
||||||
//菜单权限模式 ROLE 前端固定角色 BACK 动态获取
|
//菜单权限模式 FIXED 前端固定路由 BACK 动态获取
|
||||||
permissionMode: 'ROLE',
|
permissionMode: 'FIXED',
|
||||||
};
|
};
|
||||||
export default setting;
|
export default setting;
|
||||||
|
|||||||
@@ -88,12 +88,12 @@ export const useAsyncRouteStore = defineStore({
|
|||||||
},
|
},
|
||||||
async generateRoutes(data) {
|
async generateRoutes(data) {
|
||||||
let accessedRouters;
|
let accessedRouters;
|
||||||
const roleList = data.roles || [];
|
const permissionsList = data.permissions || [];
|
||||||
const routeFilter = (route) => {
|
const routeFilter = (route) => {
|
||||||
const { meta } = route;
|
const { meta } = route;
|
||||||
const { permission } = meta || {};
|
const { permissions } = meta || {};
|
||||||
if (!permission) return true;
|
if (!permissions) return true;
|
||||||
return roleList.some((role) => permission.includes(role.value));
|
return permissionsList.some((item) => permissions.includes(item.value));
|
||||||
};
|
};
|
||||||
const { getPermissionMode } = useProjectSetting();
|
const { getPermissionMode } = useProjectSetting();
|
||||||
const permissionMode = unref(getPermissionMode);
|
const permissionMode = unref(getPermissionMode);
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export interface IUserState {
|
|||||||
username: string;
|
username: string;
|
||||||
welcome: string;
|
welcome: string;
|
||||||
avatar: string;
|
avatar: string;
|
||||||
roles: any[];
|
permissions: any[];
|
||||||
info: any;
|
info: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ export const useUserStore = defineStore({
|
|||||||
username: '',
|
username: '',
|
||||||
welcome: '',
|
welcome: '',
|
||||||
avatar: '',
|
avatar: '',
|
||||||
roles: [],
|
permissions: [],
|
||||||
info: Storage.get(CURRENT_USER, {}),
|
info: Storage.get(CURRENT_USER, {}),
|
||||||
}),
|
}),
|
||||||
getters: {
|
getters: {
|
||||||
@@ -37,8 +37,8 @@ export const useUserStore = defineStore({
|
|||||||
getNickname(): string {
|
getNickname(): string {
|
||||||
return this.username;
|
return this.username;
|
||||||
},
|
},
|
||||||
getRoles(): [any][] {
|
getPermissions(): [any][] {
|
||||||
return this.roles;
|
return this.permissions;
|
||||||
},
|
},
|
||||||
getUserInfo(): object {
|
getUserInfo(): object {
|
||||||
return this.info;
|
return this.info;
|
||||||
@@ -51,8 +51,8 @@ export const useUserStore = defineStore({
|
|||||||
setAvatar(avatar: string) {
|
setAvatar(avatar: string) {
|
||||||
this.avatar = avatar;
|
this.avatar = avatar;
|
||||||
},
|
},
|
||||||
setRoles(roles) {
|
setPermissions(permissions) {
|
||||||
this.roles = roles;
|
this.permissions = permissions;
|
||||||
},
|
},
|
||||||
setUserInfo(info) {
|
setUserInfo(info) {
|
||||||
this.info = info;
|
this.info = info;
|
||||||
@@ -83,12 +83,12 @@ export const useUserStore = defineStore({
|
|||||||
getUserInfo()
|
getUserInfo()
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
const result = res;
|
const result = res;
|
||||||
if (result.roles && result.roles.length) {
|
if (result.permissions && result.permissions.length) {
|
||||||
const roles = result.roles;
|
const permissionsList = result.permissions;
|
||||||
that.setRoles(roles);
|
that.setPermissions(permissionsList);
|
||||||
that.setUserInfo(result);
|
that.setUserInfo(result);
|
||||||
} else {
|
} else {
|
||||||
reject(new Error('getInfo: roles must be a non-null array !'));
|
reject(new Error('getInfo: permissionsList must be a non-null array !'));
|
||||||
}
|
}
|
||||||
that.setAvatar(result.avatar);
|
that.setAvatar(result.avatar);
|
||||||
resolve(res);
|
resolve(res);
|
||||||
@@ -101,7 +101,7 @@ export const useUserStore = defineStore({
|
|||||||
|
|
||||||
// 登出
|
// 登出
|
||||||
async logout() {
|
async logout() {
|
||||||
this.setRoles([]);
|
this.setPermissions([]);
|
||||||
this.setUserInfo('');
|
this.setUserInfo('');
|
||||||
storage.remove(ACCESS_TOKEN);
|
storage.remove(ACCESS_TOKEN);
|
||||||
storage.remove(CURRENT_USER);
|
storage.remove(CURRENT_USER);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="console">
|
<div class="console">
|
||||||
<!--数据卡片-->
|
<!--数据卡片-->
|
||||||
<n-grid cols="1 s:2 m:3 l:4 xl:4 2xl:4" responsive="screen" :x-gap="12" :y-gap="8" :cols="4">
|
<n-grid cols="1 s:2 m:3 l:4 xl:4 2xl:4" responsive="screen" :x-gap="12" :y-gap="8">
|
||||||
<n-grid-item>
|
<n-grid-item>
|
||||||
<NCard
|
<NCard
|
||||||
title="访问量"
|
title="访问量"
|
||||||
@@ -19,14 +19,14 @@
|
|||||||
<div class="text-sn">
|
<div class="text-sn">
|
||||||
日同比
|
日同比
|
||||||
<CountTo :startVal="1" suffix="%" :endVal="visits.rise" />
|
<CountTo :startVal="1" suffix="%" :endVal="visits.rise" />
|
||||||
<n-icon size="12" style="color: #00ff6f">
|
<n-icon size="12" color="#00ff6f">
|
||||||
<component is="CaretUpOutlined" />
|
<component is="CaretUpOutlined" />
|
||||||
</n-icon>
|
</n-icon>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-sn">
|
<div class="text-sn">
|
||||||
周同比
|
周同比
|
||||||
<CountTo :startVal="1" suffix="%" :endVal="visits.decline" />
|
<CountTo :startVal="1" suffix="%" :endVal="visits.decline" />
|
||||||
<n-icon size="12" style="color: #ffde66">
|
<n-icon size="12" color="#ffde66">
|
||||||
<component is="CaretDownOutlined" />
|
<component is="CaretDownOutlined" />
|
||||||
</n-icon>
|
</n-icon>
|
||||||
</div>
|
</div>
|
||||||
@@ -91,14 +91,14 @@
|
|||||||
<div class="text-sn">
|
<div class="text-sn">
|
||||||
日同比
|
日同比
|
||||||
<CountTo :startVal="1" suffix="%" :endVal="orderLarge.rise" />
|
<CountTo :startVal="1" suffix="%" :endVal="orderLarge.rise" />
|
||||||
<n-icon size="12" style="color: #00ff6f">
|
<n-icon size="12" color="#00ff6f">
|
||||||
<component is="CaretUpOutlined" />
|
<component is="CaretUpOutlined" />
|
||||||
</n-icon>
|
</n-icon>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-sn">
|
<div class="text-sn">
|
||||||
周同比
|
周同比
|
||||||
<CountTo :startVal="1" suffix="%" :endVal="orderLarge.rise" />
|
<CountTo :startVal="1" suffix="%" :endVal="orderLarge.rise" />
|
||||||
<n-icon size="12" style="color: #ffde66">
|
<n-icon size="12" color="#ffde66">
|
||||||
<component is="CaretDownOutlined" />
|
<component is="CaretDownOutlined" />
|
||||||
</n-icon>
|
</n-icon>
|
||||||
</div>
|
</div>
|
||||||
@@ -130,14 +130,14 @@
|
|||||||
<div class="text-sn">
|
<div class="text-sn">
|
||||||
月同比
|
月同比
|
||||||
<CountTo :startVal="1" suffix="%" :endVal="volume.rise" />
|
<CountTo :startVal="1" suffix="%" :endVal="volume.rise" />
|
||||||
<n-icon size="12" style="color: #00ff6f">
|
<n-icon size="12" color="#00ff6f">
|
||||||
<component is="CaretUpOutlined" />
|
<component is="CaretUpOutlined" />
|
||||||
</n-icon>
|
</n-icon>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-sn">
|
<div class="text-sn">
|
||||||
月同比
|
月同比
|
||||||
<CountTo :startVal="1" suffix="%" :endVal="volume.decline" />
|
<CountTo :startVal="1" suffix="%" :endVal="volume.decline" />
|
||||||
<n-icon size="12" style="color: #ffde66">
|
<n-icon size="12" color="#ffde66">
|
||||||
<component is="CaretDownOutlined" />
|
<component is="CaretDownOutlined" />
|
||||||
</n-icon>
|
</n-icon>
|
||||||
</div>
|
</div>
|
||||||
@@ -156,14 +156,14 @@
|
|||||||
|
|
||||||
<!--导航卡片-->
|
<!--导航卡片-->
|
||||||
<div class="mt-4">
|
<div class="mt-4">
|
||||||
<n-grid cols="1 s:2 m:3 l:8 xl:8 2xl:8" responsive="screen" :x-gap="16" :y-gap="8" :cols="8">
|
<n-grid cols="1 s:2 m:3 l:8 xl:8 2xl:8" responsive="screen" :x-gap="16" :y-gap="8">
|
||||||
<n-grid-item v-for="(item, index) in iconList" :key="index">
|
<n-grid-item v-for="(item, index) in iconList" :key="index">
|
||||||
<NCard content-style="padding-top: 0;" size="small" :bordered="false">
|
<NCard content-style="padding-top: 0;" size="small" :bordered="false">
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div class="cursor-pointer">
|
<div class="cursor-pointer">
|
||||||
<p class="flex justify-center">
|
<p class="flex justify-center">
|
||||||
<span>
|
<span>
|
||||||
<n-icon :size="item.size" class="flex-1" :style="{ color: `${item.color}` }">
|
<n-icon :size="item.size" class="flex-1" :color="item.color">
|
||||||
<component :is="item.icon" v-on="item.eventObject || {}" />
|
<component :is="item.icon" v-on="item.eventObject || {}" />
|
||||||
</n-icon>
|
</n-icon>
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -29,9 +29,9 @@
|
|||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.page-container {
|
.page-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-color: white;
|
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 50px 0;
|
padding: 50px 0;
|
||||||
|
height: 100vh;
|
||||||
|
|
||||||
.text-center {
|
.text-center {
|
||||||
h1 {
|
h1 {
|
||||||
|
|||||||
@@ -29,9 +29,9 @@
|
|||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.page-container {
|
.page-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-color: white;
|
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 50px 0;
|
padding: 50px 0;
|
||||||
|
height: 100vh;
|
||||||
|
|
||||||
.text-center {
|
.text-center {
|
||||||
h1 {
|
h1 {
|
||||||
|
|||||||
@@ -29,9 +29,9 @@
|
|||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.page-container {
|
.page-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-color: white;
|
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 50px 0;
|
padding: 50px 0;
|
||||||
|
height: 100vh;
|
||||||
|
|
||||||
.text-center {
|
.text-center {
|
||||||
h1 {
|
h1 {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
ref="actionRef"
|
ref="actionRef"
|
||||||
:actionColumn="actionColumn"
|
:actionColumn="actionColumn"
|
||||||
@update:checked-row-keys="onCheckedRow"
|
@update:checked-row-keys="onCheckedRow"
|
||||||
:scroll-x="1010"
|
:scroll-x="1090"
|
||||||
>
|
>
|
||||||
<template #tableTitle>
|
<template #tableTitle>
|
||||||
<n-button type="primary" @click="addTable">
|
<n-button type="primary" @click="addTable">
|
||||||
|
|||||||
32
yarn.lock
32
yarn.lock
@@ -2696,11 +2696,6 @@ esbuild@0.11.3:
|
|||||||
resolved "https://registry.nlark.com/esbuild/download/esbuild-0.11.3.tgz#b57165b907be4ffba651f6450538ce8d8c1d5eb0"
|
resolved "https://registry.nlark.com/esbuild/download/esbuild-0.11.3.tgz#b57165b907be4ffba651f6450538ce8d8c1d5eb0"
|
||||||
integrity sha1-tXFluQe+T/umUfZFBTjOjYwdXrA=
|
integrity sha1-tXFluQe+T/umUfZFBTjOjYwdXrA=
|
||||||
|
|
||||||
esbuild@^0.12.5:
|
|
||||||
version "0.12.15"
|
|
||||||
resolved "https://registry.nlark.com/esbuild/download/esbuild-0.12.15.tgz?cache=0&sync_timestamp=1625545660518&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fesbuild%2Fdownload%2Fesbuild-0.12.15.tgz#9d99cf39aeb2188265c5983e983e236829f08af0"
|
|
||||||
integrity sha1-nZnPOa6yGIJlxZg+mD4jaCnwivA=
|
|
||||||
|
|
||||||
esbuild@^0.12.6, esbuild@^0.12.8:
|
esbuild@^0.12.6, esbuild@^0.12.8:
|
||||||
version "0.12.14"
|
version "0.12.14"
|
||||||
resolved "https://registry.nlark.com/esbuild/download/esbuild-0.12.14.tgz?cache=0&sync_timestamp=1625183314696&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fesbuild%2Fdownload%2Fesbuild-0.12.14.tgz#43157dbd0b36d939247d4eb4909a4886ac40f82e"
|
resolved "https://registry.nlark.com/esbuild/download/esbuild-0.12.14.tgz?cache=0&sync_timestamp=1625183314696&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fesbuild%2Fdownload%2Fesbuild-0.12.14.tgz#43157dbd0b36d939247d4eb4909a4886ac40f82e"
|
||||||
@@ -5569,7 +5564,7 @@ postcss@^8.1.10:
|
|||||||
nanoid "^3.1.23"
|
nanoid "^3.1.23"
|
||||||
source-map-js "^0.6.2"
|
source-map-js "^0.6.2"
|
||||||
|
|
||||||
postcss@^8.1.6, postcss@^8.2.1, postcss@^8.2.10, postcss@^8.3.5:
|
postcss@^8.1.6, postcss@^8.2.1, postcss@^8.3.5:
|
||||||
version "8.3.5"
|
version "8.3.5"
|
||||||
resolved "https://registry.nlark.com/postcss/download/postcss-8.3.5.tgz#982216b113412bc20a86289e91eb994952a5b709"
|
resolved "https://registry.nlark.com/postcss/download/postcss-8.3.5.tgz#982216b113412bc20a86289e91eb994952a5b709"
|
||||||
integrity sha1-mCIWsRNBK8IKhiiekeuZSVKltwk=
|
integrity sha1-mCIWsRNBK8IKhiiekeuZSVKltwk=
|
||||||
@@ -5578,6 +5573,15 @@ postcss@^8.1.6, postcss@^8.2.1, postcss@^8.2.10, postcss@^8.3.5:
|
|||||||
nanoid "^3.1.23"
|
nanoid "^3.1.23"
|
||||||
source-map-js "^0.6.2"
|
source-map-js "^0.6.2"
|
||||||
|
|
||||||
|
postcss@^8.3.6:
|
||||||
|
version "8.3.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.6.tgz#2730dd76a97969f37f53b9a6096197be311cc4ea"
|
||||||
|
integrity sha512-wG1cc/JhRgdqB6WHEuyLTedf3KIRuD0hG6ldkFEZNCjRxiC+3i6kkWUUbiJQayP28iwG35cEmAbe98585BYV0A==
|
||||||
|
dependencies:
|
||||||
|
colorette "^1.2.2"
|
||||||
|
nanoid "^3.1.23"
|
||||||
|
source-map-js "^0.6.2"
|
||||||
|
|
||||||
prelude-ls@^1.2.1:
|
prelude-ls@^1.2.1:
|
||||||
version "1.2.1"
|
version "1.2.1"
|
||||||
resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
|
resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
|
||||||
@@ -6858,17 +6862,17 @@ vite-plugin-style-import@^1.0.1:
|
|||||||
es-module-lexer "^0.6.0"
|
es-module-lexer "^0.6.0"
|
||||||
magic-string "^0.25.7"
|
magic-string "^0.25.7"
|
||||||
|
|
||||||
vite@2.3.6:
|
vite@2.4.4:
|
||||||
version "2.3.6"
|
version "2.4.4"
|
||||||
resolved "https://registry.nlark.com/vite/download/vite-2.3.6.tgz#1f7cfde88a51a802d69000c7bac85d481c2e871c"
|
resolved "https://registry.yarnpkg.com/vite/-/vite-2.4.4.tgz#8c402a07ad45f168f6eb5428bead38f3e4363e47"
|
||||||
integrity sha1-H3z96IpRqALWkADHushdSBwuhxw=
|
integrity sha512-m1wK6pFJKmaYA6AeZIUXyiAgUAAJzVXhIMYCdZUpCaFMGps0v0IlNJtbmPvkUhVEyautalajmnW5X6NboUPsnw==
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild "^0.12.5"
|
esbuild "^0.12.8"
|
||||||
postcss "^8.2.10"
|
postcss "^8.3.6"
|
||||||
resolve "^1.19.0"
|
resolve "^1.20.0"
|
||||||
rollup "^2.38.5"
|
rollup "^2.38.5"
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents "~2.3.1"
|
fsevents "~2.3.2"
|
||||||
|
|
||||||
vooks@^0.2.4, vooks@^0.2.6:
|
vooks@^0.2.4, vooks@^0.2.6:
|
||||||
version "0.2.6"
|
version "0.2.6"
|
||||||
|
|||||||
Reference in New Issue
Block a user