From 29fc604d6b3a01a781b3524f95ea82266c91ef54 Mon Sep 17 00:00:00 2001 From: RubyLiu Date: Fri, 2 Feb 2024 17:00:02 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E5=A2=9E=E5=8A=A0=E9=A1=B6?= =?UTF-8?q?=E9=83=A8=E8=8F=9C=E5=8D=95=E6=9D=83=E9=99=90=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/App.vue | 10 ++--- .../src/components/business/ms-menu/index.vue | 16 +++++-- .../components/business/ms-top-menu/index.vue | 23 ++++++---- .../ms-user-group-comp/msUserGroupLeft.vue | 14 +++++- .../components/pure/ms-table/base-table.vue | 5 ++- frontend/src/config/permission.ts | 12 ++++++ frontend/src/hooks/usePermission.ts | 3 +- frontend/src/router/guard/permission.ts | 1 - .../routes/modules/projectManagement.ts | 4 +- frontend/src/router/routes/modules/setting.ts | 11 +++-- frontend/src/utils/permission.ts | 43 +++++++++++++------ .../projectAndPermission/basicInfos/index.vue | 2 +- .../setting/system/usergroup/locale/zh-CN.ts | 12 +++++- 13 files changed, 111 insertions(+), 45 deletions(-) create mode 100644 frontend/src/config/permission.ts diff --git a/frontend/src/App.vue b/frontend/src/App.vue index af59467e2c..dc9e75104d 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -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 () => { diff --git a/frontend/src/components/business/ms-menu/index.vue b/frontend/src/components/business/ms-menu/index.vue index 269e27a607..fbe1040da8 100644 --- a/frontend/src/components/business/ms-menu/index.vue +++ b/frontend/src/components/business/ms-menu/index.vue @@ -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); }; diff --git a/frontend/src/components/business/ms-top-menu/index.vue b/frontend/src/components/business/ms-top-menu/index.vue index 9560240aa7..6fc3b09d56 100644 --- a/frontend/src/components/business/ms-top-menu/index.vue +++ b/frontend/src/components/business/ms-top-menu/index.vue @@ -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; } } diff --git a/frontend/src/components/business/ms-user-group-comp/msUserGroupLeft.vue b/frontend/src/components/business/ms-user-group-comp/msUserGroupLeft.vue index 7becd73aa6..344abbf911 100644 --- a/frontend/src/components/business/ms-user-group-comp/msUserGroupLeft.vue +++ b/frontend/src/components/business/ms-user-group-comp/msUserGroupLeft.vue @@ -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: { diff --git a/frontend/src/components/pure/ms-table/base-table.vue b/frontend/src/components/pure/ms-table/base-table.vue index e1533c7255..af45567893 100644 --- a/frontend/src/components/pure/ms-table/base-table.vue +++ b/frontend/src/components/pure/ms-table/base-table.vue @@ -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[]).length; } + const { pageSize, total } = attrs.msPagination as MsPaginationI; if (pageSize > total) { return total; } diff --git a/frontend/src/config/permission.ts b/frontend/src/config/permission.ts new file mode 100644 index 0000000000..99878dc811 --- /dev/null +++ b/frontend/src/config/permission.ts @@ -0,0 +1,12 @@ +// 这里控制项目模块选择,如果是顶层则验证 appStore 里的 currentMenuConfig +// 项目管理 和 系统设置 不受此控制 +export const firstLevelMenu = [ + 'workstation', + 'testPlan', + 'bugManagement', + 'caseManagement', + 'apiTest', + 'uiTest', + 'loadTest', +]; +export default {}; diff --git a/frontend/src/hooks/usePermission.ts b/frontend/src/hooks/usePermission.ts index 1ad5488b57..ea47f6a184 100644 --- a/frontend/src/hooks/usePermission.ts +++ b/frontend/src/hooks/usePermission.ts @@ -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 调用方法 diff --git a/frontend/src/router/guard/permission.ts b/frontend/src/router/guard/permission.ts index cfe056a148..e334252366 100644 --- a/frontend/src/router/guard/permission.ts +++ b/frontend/src/router/guard/permission.ts @@ -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 { diff --git a/frontend/src/router/routes/modules/projectManagement.ts b/frontend/src/router/routes/modules/projectManagement.ts index 23ab6d7eab..3a89c0cd7e 100644 --- a/frontend/src/router/routes/modules/projectManagement.ts +++ b/frontend/src/router/routes/modules/projectManagement.ts @@ -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'], }, }, // 菜单管理 diff --git a/frontend/src/router/routes/modules/setting.ts b/frontend/src/router/routes/modules/setting.ts index 0634d69863..2f98d60e28 100644 --- a/frontend/src/router/routes/modules/setting.ts +++ b/frontend/src/router/routes/modules/setting.ts @@ -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, diff --git a/frontend/src/utils/permission.ts b/frontend/src/utils/permission.ts index f83b1371d1..f68ae3a8e9 100644 --- a/frontend/src/utils/permission.ts +++ b/frontend/src/utils/permission.ts @@ -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; +} diff --git a/frontend/src/views/project-management/projectAndPermission/basicInfos/index.vue b/frontend/src/views/project-management/projectAndPermission/basicInfos/index.vue index 4ba0e36320..7b027ebb62 100644 --- a/frontend/src/views/project-management/projectAndPermission/basicInfos/index.vue +++ b/frontend/src/views/project-management/projectAndPermission/basicInfos/index.vue @@ -6,7 +6,7 @@ {{ t('project.basicInfo.basicInfo') }} {{ t('project.basicInfo.edit') }}