diff --git a/package.json b/package.json index 7b6213a363..b0a75833d3 100644 --- a/package.json +++ b/package.json @@ -57,12 +57,12 @@ "@ant-design/pro-descriptions": "^1.0.16", "@ant-design/pro-layout": "^6.4.16", "@ant-design/pro-table": "^2.7.2", + "@umijs/route-utils": "^1.0.32", "antd": "^4.6.3", "classnames": "^2.2.6", "lodash": "^4.17.11", "moment": "^2.25.3", "omit.js": "^2.0.2", - "path-to-regexp": "2.4.0", "qs": "^6.9.0", "react": "^16.8.6", "react-dom": "^16.8.6", diff --git a/src/layouts/BasicLayout.tsx b/src/layouts/BasicLayout.tsx index 6cd15d9fe3..5ee8b7e51a 100644 --- a/src/layouts/BasicLayout.tsx +++ b/src/layouts/BasicLayout.tsx @@ -9,14 +9,14 @@ import ProLayout, { Settings, DefaultFooter, } from '@ant-design/pro-layout'; -import React, { useEffect } from 'react'; +import React, { useEffect, useMemo, useRef } from 'react'; import { Link, useIntl, connect, Dispatch, history } from 'umi'; import { GithubOutlined } from '@ant-design/icons'; import { Result, Button } from 'antd'; import Authorized from '@/utils/Authorized'; import RightContent from '@/components/GlobalHeader/RightContent'; import { ConnectState } from '@/models/connect'; -import { getAuthorityFromRouter } from '@/utils/utils'; +import { getMatchMenu } from '@umijs/route-utils'; import logo from '../assets/logo.svg'; const noMatch = ( @@ -94,9 +94,8 @@ const BasicLayout: React.FC = (props) => { pathname: '/', }, } = props; - /** - * constructor - */ + + const menuDataRef = useRef([]); useEffect(() => { if (dispatch) { @@ -116,11 +115,16 @@ const BasicLayout: React.FC = (props) => { payload, }); } - }; // get children authority - - const authorized = getAuthorityFromRouter(props.route.routes, location.pathname || '/') || { - authority: undefined, }; + // get children authority + const authorized = useMemo( + () => + getMatchMenu(location.pathname || '/', menuDataRef.current).pop() || { + authority: undefined, + }, + [location.pathname], + ); + const { formatMessage } = useIntl(); return ( @@ -153,6 +157,10 @@ const BasicLayout: React.FC = (props) => { footerRender={() => defaultFooterDom} menuDataRender={menuDataRender} rightContentRender={() => } + postMenuData={(menuData) => { + menuDataRef.current = menuData || []; + return menuData || []; + }} {...props} {...settings} > diff --git a/src/pages/Authorized.tsx b/src/pages/Authorized.tsx deleted file mode 100644 index 468543d657..0000000000 --- a/src/pages/Authorized.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import React from 'react'; -import { Redirect, connect, ConnectProps } from 'umi'; -import Authorized from '@/utils/Authorized'; -import { getRouteAuthority } from '@/utils/utils'; -import { ConnectState, UserModelState } from '@/models/connect'; - -interface AuthComponentProps extends ConnectProps { - user: UserModelState; -} - -const AuthComponent: React.FC = ({ - children, - route = { - routes: [], - }, - location = { - pathname: '', - }, - user, -}) => { - const { currentUser } = user; - const { routes = [] } = route; - const isLogin = currentUser && currentUser.name; - return ( - : } - > - {children} - - ); -}; - -export default connect(({ user }: ConnectState) => ({ - user, -}))(AuthComponent); diff --git a/src/utils/utils.test.ts b/src/utils/utils.test.ts index ea848193c0..c2bb32dc70 100644 --- a/src/utils/utils.test.ts +++ b/src/utils/utils.test.ts @@ -1,4 +1,4 @@ -import { isUrl, getRouteAuthority } from './utils'; +import { isUrl } from './utils'; describe('isUrl tests', (): void => { it('should return false for invalid and corner case inputs', (): void => { @@ -35,42 +35,3 @@ describe('isUrl tests', (): void => { expect(isUrl('https://www.example.com/test/123?foo=bar')).toBeTruthy(); }); }); - -describe('getRouteAuthority tests', () => { - it('should return authority for each route', (): void => { - const routes = [ - { path: '/user', name: 'user', authority: ['user'], exact: true }, - { path: '/admin', name: 'admin', authority: ['admin'], exact: true }, - ]; - expect(getRouteAuthority('/user', routes)).toEqual(['user']); - expect(getRouteAuthority('/admin', routes)).toEqual(['admin']); - }); - - it('should return inherited authority for unconfigured route', (): void => { - const routes = [ - { path: '/nested', authority: ['admin', 'user'], exact: true }, - { path: '/nested/user', name: 'user', exact: true }, - ]; - expect(getRouteAuthority('/nested/user', routes)).toEqual(['admin', 'user']); - }); - - it('should return authority for configured route', (): void => { - const routes = [ - { path: '/nested', authority: ['admin', 'user'], exact: true }, - { path: '/nested/user', name: 'user', authority: ['user'], exact: true }, - { path: '/nested/admin', name: 'admin', authority: ['admin'], exact: true }, - ]; - expect(getRouteAuthority('/nested/user', routes)).toEqual(['user']); - expect(getRouteAuthority('/nested/admin', routes)).toEqual(['admin']); - }); - - it('should return authority for substring route', (): void => { - const routes = [ - { path: '/nested', authority: ['user', 'users'], exact: true }, - { path: '/nested/users', name: 'users', authority: ['users'], exact: true }, - { path: '/nested/user', name: 'user', authority: ['user'], exact: true }, - ]; - expect(getRouteAuthority('/nested/user', routes)).toEqual(['user']); - expect(getRouteAuthority('/nested/users', routes)).toEqual(['users']); - }); -}); diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 1f43882cd5..71ed4ca595 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -1,6 +1,4 @@ import { parse } from 'querystring'; -import pathRegexp from 'path-to-regexp'; -import { Route } from '@/models/connect'; /* eslint no-useless-escape:0 import/prefer-default-export:0 */ const reg = /(((^https?:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)$/; @@ -24,42 +22,3 @@ export const isAntDesignProOrDev = (): boolean => { }; export const getPageQuery = () => parse(window.location.href.split('?')[1]); - -/** - * props.route.routes - * @param router [{}] - * @param pathname string - */ -export const getAuthorityFromRouter = ( - router: T[] = [], - pathname: string, -): T | undefined => { - const authority = router.find( - ({ routes, path = '/', target = '_self' }) => - (path && target !== '_blank' && pathRegexp(path).exec(pathname)) || - (routes && getAuthorityFromRouter(routes, pathname)), - ); - if (authority) return authority; - return undefined; -}; - -export const getRouteAuthority = (path: string, routeData: Route[]) => { - let authorities: string[] | string | undefined; - routeData.forEach((route) => { - // match prefix - if (pathRegexp(`${route.path}/(.*)`).test(`${path}/`)) { - if (route.authority) { - authorities = route.authority; - } - // exact match - if (route.path === path) { - authorities = route.authority || authorities; - } - // get children authority recursively - if (route.routes) { - authorities = getRouteAuthority(path, route.routes) || authorities; - } - } - }); - return authorities; -};