refactor: 增加顶部菜单权限判断
This commit is contained in:
parent
2359bea50a
commit
29fc604d6b
|
@ -73,11 +73,6 @@
|
|||
const checkIsLogin = async () => {
|
||||
const isLogin = await userStore.isLogin();
|
||||
const isLoginPage = route.name === 'login';
|
||||
if (isLoginPage && isLogin) {
|
||||
// 当前页面为登录页面,且已经登录,跳转到首页
|
||||
const currentRouteName = getFirstRouteNameByPermission(router.getRoutes());
|
||||
router.push({ name: currentRouteName });
|
||||
}
|
||||
if (isLogin && appStore.currentProjectId && appStore.currentProjectId !== 'no_such_project') {
|
||||
// 当前为登陆状态,且已经选择了项目,初始化当前项目配置
|
||||
try {
|
||||
|
@ -94,6 +89,11 @@
|
|||
console.log(err);
|
||||
}
|
||||
}
|
||||
if (isLoginPage && isLogin) {
|
||||
// 当前页面为登录页面,且已经登录,跳转到首页
|
||||
const currentRouteName = getFirstRouteNameByPermission(router.getRoutes());
|
||||
router.push({ name: currentRouteName });
|
||||
}
|
||||
};
|
||||
// 获取公钥
|
||||
const getPublicKey = async () => {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
import { useAppStore, useUserStore } from '@/store';
|
||||
import useLicenseStore from '@/store/modules/setting/license';
|
||||
import { openWindow, regexUrl } from '@/utils';
|
||||
import { getFisrtRouterNameByCurrentRoute } from '@/utils/permission';
|
||||
import { listenerRouteChange } from '@/utils/route-listener';
|
||||
|
||||
import useMenuTree from './use-menu-tree';
|
||||
|
@ -58,9 +59,17 @@
|
|||
selectedKey.value = [item.name as string];
|
||||
return;
|
||||
}
|
||||
if (item.meta?.hideChildrenInMenu) {
|
||||
// 顶级菜单路由跳转到该菜单下有权限的第一个顶部子菜单
|
||||
const childName = getFisrtRouterNameByCurrentRoute(item.name as string);
|
||||
router.push({
|
||||
name: childName,
|
||||
});
|
||||
} else {
|
||||
router.push({
|
||||
name: item.name,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
router.push({
|
||||
name: 'notFound',
|
||||
|
@ -365,7 +374,6 @@
|
|||
}
|
||||
return nodes;
|
||||
}
|
||||
|
||||
return travel(menuTree.value);
|
||||
};
|
||||
|
||||
|
|
|
@ -82,17 +82,22 @@
|
|||
);
|
||||
}
|
||||
|
||||
const filterMenuTopRouter = currentParent?.children
|
||||
const filterMenuTopRouter =
|
||||
currentParent?.children
|
||||
?.filter((item: any) => permission.accessRouter(item) && item.meta?.isTopMenu)
|
||||
.filter((item: any) => {
|
||||
if (item.name === RouteEnum.SETTING_SYSTEM_AUTHORIZED_MANAGEMENT) {
|
||||
return appStore.packageType === 'enterprise';
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}) || [];
|
||||
|
||||
appStore.setTopMenus(filterMenuTopRouter);
|
||||
if (!newRoute.meta.isTopMenu) {
|
||||
setCurrentTopMenu(filterMenuTopRouter[0].name as string);
|
||||
} else {
|
||||
setCurrentTopMenu(name as string);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -458,10 +458,22 @@
|
|||
popVisible.value[id] = visibleItem;
|
||||
}
|
||||
if (item.eventTag === 'delete') {
|
||||
let content = '';
|
||||
switch (authScope) {
|
||||
case AuthScopeEnum.SYSTEM:
|
||||
content = t('system.userGroup.beforeDeleteUserGroup');
|
||||
break;
|
||||
case AuthScopeEnum.ORGANIZATION:
|
||||
content = t('org.userGroup.beforeDeleteUserGroup');
|
||||
break;
|
||||
default:
|
||||
content = t('project.userGroup.beforeDeleteUserGroup');
|
||||
break;
|
||||
}
|
||||
openModal({
|
||||
type: 'error',
|
||||
title: t('system.userGroup.isDeleteUserGroup', { name: characterLimit(currentName.value) }),
|
||||
content: t('system.userGroup.beforeDeleteUserGroup'),
|
||||
content,
|
||||
okText: t('system.userGroup.confirmDelete'),
|
||||
cancelText: t('system.userGroup.cancel'),
|
||||
okButtonProps: {
|
||||
|
|
|
@ -267,6 +267,7 @@
|
|||
BatchActionQueryParams,
|
||||
MsPaginationI,
|
||||
MsTableColumn,
|
||||
MsTableDataItem,
|
||||
MsTableProps,
|
||||
} from './type';
|
||||
import type { TableColumnData, TableData } from '@arco-design/web-vue';
|
||||
|
@ -322,11 +323,11 @@
|
|||
const selectTotal = computed(() => {
|
||||
const { selectorStatus } = props;
|
||||
if (selectorStatus === SelectAllEnum.CURRENT) {
|
||||
const { pageSize, total } = attrs.msPagination as MsPaginationI;
|
||||
if (!attrs.showPagination) {
|
||||
// 不展示分页时直接返回total
|
||||
return total;
|
||||
return (attrs.data as MsTableDataItem<TableData>[]).length;
|
||||
}
|
||||
const { pageSize, total } = attrs.msPagination as MsPaginationI;
|
||||
if (pageSize > total) {
|
||||
return total;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
// 这里控制项目模块选择,如果是顶层则验证 appStore 里的 currentMenuConfig
|
||||
// 项目管理 和 系统设置 不受此控制
|
||||
export const firstLevelMenu = [
|
||||
'workstation',
|
||||
'testPlan',
|
||||
'bugManagement',
|
||||
'caseManagement',
|
||||
'apiTest',
|
||||
'uiTest',
|
||||
'loadTest',
|
||||
];
|
||||
export default {};
|
|
@ -1,10 +1,9 @@
|
|||
import { RouteLocationNormalized, RouteRecordRaw } from 'vue-router';
|
||||
import { includes } from 'lodash-es';
|
||||
|
||||
import { firstLevelMenu } from '@/config/permission';
|
||||
import { hasAnyPermission, topLevelMenuHasPermission } from '@/utils/permission';
|
||||
|
||||
const firstLevelMenu = ['workstation', 'testPlan', 'bugManagement', 'caseManagement', 'apiTest', 'uiTest', 'loadTest'];
|
||||
|
||||
/**
|
||||
* 用户权限
|
||||
* @returns 调用方法
|
||||
|
|
|
@ -10,7 +10,6 @@ export default function setupPermissionGuard(router: Router) {
|
|||
const permissionsAllow = Permission.accessRouter(to);
|
||||
|
||||
const exist = WHITE_LIST.find((el) => el.name === to.name);
|
||||
|
||||
if (exist || permissionsAllow) {
|
||||
next();
|
||||
} else {
|
||||
|
|
|
@ -44,7 +44,7 @@ const ProjectManagement: AppRouteRecordRaw = {
|
|||
meta: {
|
||||
locale: 'menu.projectManagement.projectPermission',
|
||||
roles: [
|
||||
'SYSTEM_PARAMETER_SETTING_BASE:READ',
|
||||
'PROJECT_BASE_INFO:READ',
|
||||
// 菜单管理
|
||||
'PROJECT_APPLICATION_WORKSTATION:READ',
|
||||
'PROJECT_APPLICATION_TEST_PLAN:READ',
|
||||
|
@ -67,7 +67,7 @@ const ProjectManagement: AppRouteRecordRaw = {
|
|||
component: () => import('@/views/project-management/projectAndPermission/basicInfos/index.vue'),
|
||||
meta: {
|
||||
locale: 'project.permission.basicInfo',
|
||||
roles: ['SYSTEM_PARAMETER_SETTING_BASE:READ'],
|
||||
roles: ['PROJECT_BASE_INFO:READ'],
|
||||
},
|
||||
},
|
||||
// 菜单管理
|
||||
|
|
|
@ -19,18 +19,19 @@ const Setting: AppRouteRecordRaw = {
|
|||
'SYSTEM_TEST_RESOURCE_POOL:READ',
|
||||
'SYSTEM_AUTH:READ',
|
||||
'SYSTEM_PLUGIN:READ',
|
||||
'SYSTEM_LOG:READ',
|
||||
'ORGANIZATION_MEMBER:READ',
|
||||
'ORGANIZATION_USER_ROLE:READ',
|
||||
'ORGANIZATION_PROJECT:READ',
|
||||
'SYSTEM_SERVICE_INTEGRATION:READ',
|
||||
'ORGANIZATION_TEMPLATE:READ',
|
||||
'ORGANIZATION_LOG:READ',
|
||||
],
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'system',
|
||||
name: SettingRouteEnum.SETTING_SYSTEM,
|
||||
redirect: '/setting/system/user',
|
||||
component: null,
|
||||
meta: {
|
||||
locale: 'menu.settings.system',
|
||||
|
@ -42,6 +43,7 @@ const Setting: AppRouteRecordRaw = {
|
|||
'SYSTEM_TEST_RESOURCE_POOL:READ',
|
||||
'SYSTEM_AUTH:READ',
|
||||
'SYSTEM_PLUGIN:READ',
|
||||
'SYSTEM_LOG:READ',
|
||||
],
|
||||
hideChildrenInMenu: true,
|
||||
},
|
||||
|
@ -152,7 +154,7 @@ const Setting: AppRouteRecordRaw = {
|
|||
{
|
||||
path: 'organization',
|
||||
name: SettingRouteEnum.SETTING_ORGANIZATION,
|
||||
redirect: '/setting/organization/member',
|
||||
redirect: '',
|
||||
component: null,
|
||||
meta: {
|
||||
locale: 'menu.settings.organization',
|
||||
|
@ -162,6 +164,7 @@ const Setting: AppRouteRecordRaw = {
|
|||
'ORGANIZATION_PROJECT:READ',
|
||||
'SYSTEM_SERVICE_INTEGRATION:READ',
|
||||
'ORGANIZATION_TEMPLATE:READ',
|
||||
'ORGANIZATION_LOG:READ',
|
||||
],
|
||||
hideChildrenInMenu: true,
|
||||
},
|
||||
|
@ -267,7 +270,7 @@ const Setting: AppRouteRecordRaw = {
|
|||
component: () => import('@/views/setting/organization/template/components/templateDetail.vue'),
|
||||
meta: {
|
||||
locale: 'menu.settings.organization.templateManagementDetail',
|
||||
roles: ['*'],
|
||||
roles: ['ORGANIZATION_TEMPLATE:READ+UPDATE', 'ORGANIZATION_TEMPLATE:READ+ADD'],
|
||||
breadcrumbs: [
|
||||
{
|
||||
name: SettingRouteEnum.SETTING_ORGANIZATION_TEMPLATE,
|
||||
|
@ -295,7 +298,7 @@ const Setting: AppRouteRecordRaw = {
|
|||
component: () => import('@/views/setting/organization/template/components/workFlowTableIndex.vue'),
|
||||
meta: {
|
||||
locale: 'menu.settings.organization.templateManagementWorkFlow',
|
||||
roles: ['*'],
|
||||
roles: ['ORGANIZATION_TEMPLATE:READ+UPDATE'],
|
||||
breadcrumbs: [
|
||||
{
|
||||
name: SettingRouteEnum.SETTING_ORGANIZATION_TEMPLATE,
|
||||
|
|
|
@ -1,22 +1,12 @@
|
|||
import { RouteLocationNormalized, RouteRecordNormalized, RouteRecordRaw } from 'vue-router';
|
||||
import { includes } from 'lodash-es';
|
||||
|
||||
import { firstLevelMenu } from '@/config/permission';
|
||||
import { INDEX_ROUTE } from '@/router/routes/base';
|
||||
import appRoutes from '@/router/routes/index';
|
||||
import { useAppStore, useUserStore } from '@/store';
|
||||
import { SystemScopeType, UserRole, UserRolePermissions } from '@/store/modules/user/types';
|
||||
|
||||
const firstLevelMenuNames = [
|
||||
'workstation',
|
||||
'testPlan',
|
||||
'bugManagement',
|
||||
'caseManagement',
|
||||
'apiTest',
|
||||
'uiTest',
|
||||
'loadTest',
|
||||
'setting',
|
||||
'projectManagement',
|
||||
];
|
||||
|
||||
export function hasPermission(permission: string, typeList: string[]) {
|
||||
const userStore = useUserStore();
|
||||
if (userStore.isAdmin) {
|
||||
|
@ -92,7 +82,7 @@ export function topLevelMenuHasPermission(route: RouteLocationNormalized | Route
|
|||
// 有权限的第一个路由名,如果没有找到则返回IndexRoute
|
||||
export function getFirstRouteNameByPermission(routerList: RouteRecordNormalized[]) {
|
||||
const currentRoute = routerList
|
||||
.filter((item) => includes(firstLevelMenuNames, item.name))
|
||||
.filter((item) => includes(firstLevelMenu, item.name))
|
||||
.sort((a, b) => {
|
||||
return (a.meta.order || 0) - (b.meta.order || 0);
|
||||
})
|
||||
|
@ -105,3 +95,30 @@ export function routerNameHasPermission(routerName: string, routerList: RouteRec
|
|||
const currentRoute = routerList.find((item) => item.name === routerName);
|
||||
return currentRoute ? hasAnyPermission(currentRoute.meta?.roles || []) : false;
|
||||
}
|
||||
|
||||
export function findRouteByName(name: string) {
|
||||
const queue: RouteRecordNormalized[] = [...appRoutes];
|
||||
while (queue.length > 0) {
|
||||
const currentRoute = queue.shift();
|
||||
if (!currentRoute) {
|
||||
return;
|
||||
}
|
||||
if (currentRoute.name === name) {
|
||||
return currentRoute;
|
||||
}
|
||||
if (currentRoute.children) {
|
||||
queue.push(...(currentRoute.children as RouteRecordNormalized[]));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// 找到当前路由下 第一个由权限的子路由
|
||||
export function getFisrtRouterNameByCurrentRoute(parentName: string) {
|
||||
const currentRoute = findRouteByName(parentName);
|
||||
if (currentRoute) {
|
||||
const hasAuthChildrenRouter = currentRoute.children.find((item) => hasAnyPermission(item.meta?.roles || []));
|
||||
return hasAuthChildrenRouter ? hasAuthChildrenRouter.name : parentName;
|
||||
}
|
||||
return parentName;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<span class="font-medium text-[var(--color-text-000)]">{{ t('project.basicInfo.basicInfo') }}</span>
|
||||
<a-button
|
||||
v-if="!projectDetail?.deleted"
|
||||
v-permission="['SYSTEM_PARAMETER_SETTING_BASE:READ+UPDATE']"
|
||||
v-permission="['PROJECT_BASE_INFO:READ+UPDATE']"
|
||||
type="outline"
|
||||
@click="editHandler"
|
||||
>{{ t('project.basicInfo.edit') }}</a-button
|
||||
|
|
|
@ -49,7 +49,7 @@ export default {
|
|||
LOAD_TEST: '性能测试',
|
||||
PERSONAL: '我的设置',
|
||||
isDeleteUserGroup: '是否删除: {name}?',
|
||||
beforeDeleteUserGroup: '删除后,该组织下的项目数据将一起删除,请谨慎操作!',
|
||||
beforeDeleteUserGroup: '删除后,该系统下的项目数据将一起删除,请谨慎操作!',
|
||||
confirmDelete: '确认删除',
|
||||
function: '功能',
|
||||
operationObject: '操作对象',
|
||||
|
@ -98,4 +98,14 @@ export default {
|
|||
recover: '恢复',
|
||||
},
|
||||
},
|
||||
org: {
|
||||
userGroup: {
|
||||
beforeDeleteUserGroup: '删除后,组织下用户组数据将一起删除,请谨慎操作!',
|
||||
},
|
||||
},
|
||||
project: {
|
||||
userGroup: {
|
||||
beforeDeleteUserGroup: '删除后,项目下用户组数据将一起删除,请谨慎操作!',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue