refactor: 增加顶部菜单权限判断

This commit is contained in:
RubyLiu 2024-02-02 17:00:02 +08:00 committed by Craftsman
parent 2359bea50a
commit 29fc604d6b
13 changed files with 111 additions and 45 deletions

View File

@ -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 () => {

View File

@ -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;
}
router.push({
name: item.name,
});
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);
};

View File

@ -82,17 +82,22 @@
);
}
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;
});
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);
setCurrentTopMenu(name as string);
if (!newRoute.meta.isTopMenu) {
setCurrentTopMenu(filterMenuTopRouter[0].name as string);
} else {
setCurrentTopMenu(name as string);
}
return;
}
}

View File

@ -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: {

View File

@ -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;
}

View File

@ -0,0 +1,12 @@
// 这里控制项目模块选择,如果是顶层则验证 appStore 里的 currentMenuConfig
// 项目管理 和 系统设置 不受此控制
export const firstLevelMenu = [
'workstation',
'testPlan',
'bugManagement',
'caseManagement',
'apiTest',
'uiTest',
'loadTest',
];
export default {};

View File

@ -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

View File

@ -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 {

View File

@ -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'],
},
},
// 菜单管理

View File

@ -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,

View File

@ -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;
}

View File

@ -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

View File

@ -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: '删除后,项目下用户组数据将一起删除,请谨慎操作!',
},
},
};