陈帅 пре 6 година
родитељ
комит
7e187a90f6

+ 0 - 1
.eslintrc.js

@@ -10,7 +10,6 @@ module.exports = {
     jasmine: true,
   },
   globals: {
-    ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION: true, // preview.pro.ant.design only do not use in your production ; preview.pro.ant.design 专用环境变量,请不要在你的项目中使用它。
     page: true,
   },
   rules: {

+ 4 - 2
.prettierrc

@@ -6,7 +6,9 @@
   "overrides": [
     {
       "files": ".prettierrc",
-      "options": { "parser": "json" }
+      "options": {
+        "parser": "json"
+      }
     }
   ]
-}
+}

+ 9 - 3
config/config.ts

@@ -121,7 +121,13 @@ export default {
   disableRedirectHoist: true,
   cssLoaderOptions: {
     modules: true,
-    getLocalIdent: (context, localIdentName, localName) => {
+    getLocalIdent: (
+      context: {
+        resourcePath: string;
+      },
+      localIdentName: string,
+      localName: string,
+    ) => {
       if (
         context.resourcePath.includes('node_modules') ||
         context.resourcePath.includes('ant.design.pro.less') ||
@@ -134,8 +140,8 @@ export default {
         const antdProPath = match[1].replace('.less', '');
         const arr = slash(antdProPath)
           .split('/')
-          .map(a => a.replace(/([A-Z])/g, '-$1'))
-          .map(a => a.toLowerCase());
+          .map((a: string) => a.replace(/([A-Z])/g, '-$1'))
+          .map((a: string) => a.toLowerCase());
         return `antd-pro${arr.join('-')}-${localName}`.replace(/--/g, '-');
       }
       return localName;

+ 3 - 3
package.json

@@ -54,9 +54,9 @@
     "not ie <= 10"
   ],
   "dependencies": {
-    "@ant-design/pro-layout": "^4.1.0",
+    "@ant-design/pro-layout": "^4.2.0",
     "@antv/data-set": "^0.10.1",
-    "antd": "^3.16.1",
+    "antd": "^3.18.1",
     "bizcharts": "3.5.2-beta.1",
     "bizcharts-plugin-slider": "^2.1.1-beta.1",
     "classnames": "^2.2.6",
@@ -146,4 +146,4 @@
     "config/**/*.js*",
     "scripts/**/*.js"
   ]
-}
+}

+ 0 - 4
src/app.ts

@@ -5,7 +5,3 @@ export const dva = {
     },
   },
 };
-
-export function render(oldRender) {
-  oldRender();
-}

+ 1 - 1
src/components/Authorized/AuthorizedRoute.tsx

@@ -6,7 +6,7 @@ import { IAuthorityType } from './CheckPermissions';
 interface IAuthorizedRoutePops {
   currentAuthority: string;
   component: React.ComponentClass<any, any>;
-  render: () => React.ReactNode;
+  render: (props: any) => React.ReactNode;
   redirectPath: string;
   authority: IAuthorityType;
 }

+ 9 - 11
src/components/Authorized/CheckPermissions.tsx

@@ -17,12 +17,12 @@ export type IAuthorityType =
  * @param { 通过的组件 | Passing components } target
  * @param { 未通过的组件 | no pass components } Exception
  */
-const checkPermissions = (
+const checkPermissions = <T, K>(
   authority: IAuthorityType,
   currentAuthority: string | string[],
-  target: React.ComponentClass<any, any> | React.ReactNode,
-  Exception: React.ReactNode,
-): React.ReactNode => {
+  target: T,
+  Exception: K,
+): T | K | React.ReactNode => {
   // 没有判定权限.默认查看所有
   // Retirement authority, return target;
   if (!authority) {
@@ -52,7 +52,7 @@ const checkPermissions = (
   }
   // Promise 处理
   if (authority instanceof Promise) {
-    return <PromiseRender ok={target} error={Exception} promise={authority} />;
+    return <PromiseRender<T, K> ok={target} error={Exception} promise={authority} />;
   }
   // Function 处理
   if (typeof authority === 'function') {
@@ -60,7 +60,7 @@ const checkPermissions = (
       const bool = authority(currentAuthority);
       // 函数执行后返回值是 Promise
       if (bool instanceof Promise) {
-        return <PromiseRender ok={target} error={Exception} promise={bool} />;
+        return <PromiseRender<T, K> ok={target} error={Exception} promise={bool} />;
       }
       if (bool) {
         return target;
@@ -75,10 +75,8 @@ const checkPermissions = (
 
 export { checkPermissions };
 
-const check = (
-  authority: IAuthorityType,
-  target: React.ComponentClass<any, any> | React.ReactNode,
-  Exception: React.ReactNode,
-): React.ReactNode => checkPermissions(authority, CURRENT, target, Exception);
+function check<T, K>(authority: IAuthorityType, target: T, Exception: K): T | K | React.ReactNode {
+  return checkPermissions<T, K>(authority, CURRENT, target, Exception);
+}
 
 export default check;

+ 10 - 7
src/components/Authorized/PromiseRender.tsx

@@ -4,9 +4,9 @@ import React from 'react';
 // eslint-disable-next-line import/no-cycle
 import { isComponentClass } from './Secured';
 
-interface IPromiseRenderProps {
-  ok: React.ReactNode;
-  error: React.ReactNode;
+interface IPromiseRenderProps<T, K> {
+  ok: T;
+  error: K;
   promise: Promise<any>;
 }
 
@@ -14,8 +14,8 @@ interface IPromiseRenderState {
   component: React.ComponentClass<any, any> | React.FunctionComponent<any>;
 }
 
-export default class PromiseRender extends React.Component<
-  IPromiseRenderProps,
+export default class PromiseRender<T, K> extends React.Component<
+  IPromiseRenderProps<T, K>,
   IPromiseRenderState
 > {
   state: IPromiseRenderState = {
@@ -26,7 +26,10 @@ export default class PromiseRender extends React.Component<
     this.setRenderComponent(this.props);
   }
 
-  shouldComponentUpdate = (nextProps: IPromiseRenderProps, nextState: IPromiseRenderState) => {
+  shouldComponentUpdate = (
+    nextProps: IPromiseRenderProps<T, K>,
+    nextState: IPromiseRenderState,
+  ) => {
     const { component } = this.state;
     if (!isEqual(nextProps, this.props)) {
       this.setRenderComponent(nextProps);
@@ -36,7 +39,7 @@ export default class PromiseRender extends React.Component<
   };
 
   // set render Component : ok or error
-  setRenderComponent(props: IPromiseRenderProps) {
+  setRenderComponent(props: IPromiseRenderProps<T, K>) {
     const ok = this.checkIsInstantiation(props.ok);
     const error = this.checkIsInstantiation(props.error);
     props.promise

+ 1 - 0
src/components/Authorized/index.tsx

@@ -9,4 +9,5 @@ Authorized.AuthorizedRoute = AuthorizedRoute;
 Authorized.check = check;
 
 const RenderAuthorize = renderAuthorize(Authorized);
+
 export default RenderAuthorize;

+ 4 - 4
src/components/Authorized/renderAuthorize.ts

@@ -1,11 +1,11 @@
-/* eslint-disable import/no-mutable-exports */
 let CURRENT: string | string[] = 'NULL';
+type CurrentAuthorityType = string | string[] | (() => typeof CURRENT);
 /**
  * use  authority or getAuthority
  * @param {string|()=>String} currentAuthority
  */
-const renderAuthorize = (Authorized: any) => (
-  currentAuthority: string | string[] | (() => typeof CURRENT),
+const renderAuthorize = <T>(Authorized: T): ((currentAuthority: CurrentAuthorityType) => T) => (
+  currentAuthority: CurrentAuthorityType,
 ) => {
   if (currentAuthority) {
     if (typeof currentAuthority === 'function') {
@@ -24,4 +24,4 @@ const renderAuthorize = (Authorized: any) => (
 };
 
 export { CURRENT };
-export default (Authorized: any) => renderAuthorize(Authorized);
+export default <T>(Authorized: T) => renderAuthorize<T>(Authorized);

+ 0 - 18
src/components/_utils/pathTools.test.ts

@@ -1,18 +0,0 @@
-import 'jest';
-import { urlToList } from './pathTools';
-
-describe('test urlToList', () => {
-  it('A path', () => {
-    expect(urlToList('/userinfo')).toEqual(['/userinfo']);
-  });
-  it('Secondary path', () => {
-    expect(urlToList('/userinfo/2144')).toEqual(['/userinfo', '/userinfo/2144']);
-  });
-  it('Three paths', () => {
-    expect(urlToList('/userinfo/2144/addr')).toEqual([
-      '/userinfo',
-      '/userinfo/2144',
-      '/userinfo/2144/addr',
-    ]);
-  });
-});

+ 0 - 6
src/components/_utils/pathTools.ts

@@ -1,6 +0,0 @@
-// /userinfo/2144/id => ['/userinfo','/useinfo/2144,'/userindo/2144/id']
-// eslint-disable-next-line import/prefer-default-export
-export function urlToList(url: string) {
-  const urllist = url.split('/').filter(i => i);
-  return urllist.map((urlItem, index) => `/${urllist.slice(0, index + 1).join('/')}`);
-}

+ 3 - 7
src/layouts/BasicLayout.tsx

@@ -3,7 +3,6 @@ import RightContent from '@/components/GlobalHeader/RightContent';
 import { connect } from 'dva';
 import React, { useState } from 'react';
 import logo from '../assets/logo.svg';
-
 import {
   BasicLayout as BasicLayoutComponents,
   BasicLayoutProps as BasicLayoutComponentsProps,
@@ -23,21 +22,20 @@ export type BasicLayoutContext = { [K in 'location']: BasicLayoutProps[K] } & {
 };
 
 const BasicLayout: React.FC<BasicLayoutProps> = props => {
-  const { dispatch, children, route, settings } = props;
-  const { routes, authority } = route!;
+  const { dispatch, children, settings } = props;
   /**
    * constructor
    */
   useState(() => {
     dispatch!({ type: 'user/fetchCurrent' });
     dispatch!({ type: 'settings/getSetting' });
-    dispatch!({ type: 'menu/getMenuData', payload: { routes, authority } });
   });
   /**
    * init variables
    */
   const handleMenuCollapse = (payload: boolean) =>
     dispatch!({ type: 'global/changeLayoutCollapsed', payload });
+
   return (
     <>
       <BasicLayoutComponents
@@ -65,9 +63,7 @@ const BasicLayout: React.FC<BasicLayoutProps> = props => {
   );
 };
 
-export default connect(({ global, settings, menu: menuModel }: ConnectState) => ({
+export default connect(({ global, settings }: ConnectState) => ({
   collapsed: global.collapsed,
   settings,
-  menuData: menuModel.menuData,
-  breadcrumbNameMap: menuModel.breadcrumbNameMap,
 }))(BasicLayout);

+ 18 - 19
src/layouts/UserLayout.tsx

@@ -1,16 +1,14 @@
 import SelectLang from '@/components/SelectLang';
 import GlobalFooter from '@/components/GlobalFooter';
-import { ConnectProps, ConnectState } from '@/models/connect';
-import getPageTitle from '@/utils/getPageTitle';
+import { ConnectProps } from '@/models/connect';
 import { Icon } from 'antd';
-import { connect } from 'dva';
 import React, { Component, Fragment } from 'react';
 import DocumentTitle from 'react-document-title';
 import { formatMessage } from 'umi-plugin-locale';
 import Link from 'umi/link';
 import logo from '../assets/logo.svg';
 import styles from './UserLayout.less';
-import { MenuDataItem } from '@ant-design/pro-layout';
+import { MenuDataItem, getPageTitle, getMenuData } from '@ant-design/pro-layout';
 
 const links = [
   {
@@ -42,19 +40,23 @@ export interface UserLayoutProps extends ConnectProps {
 }
 
 class UserLayout extends Component<UserLayoutProps> {
-  componentDidMount() {
-    const { dispatch, route } = this.props;
-    const { routes, authority } = route!;
-    dispatch!({
-      type: 'menu/getMenuData',
-      payload: { routes, authority },
-    });
-  }
-
   render() {
-    const { children, location, breadcrumbNameMap } = this.props;
+    const {
+      route = {
+        routes: [],
+      },
+    } = this.props;
+    const { routes = [] } = route;
+    const { children, location } = this.props;
+    const { breadcrumb } = getMenuData(routes, this.props);
     return (
-      <DocumentTitle title={getPageTitle(location!.pathname, breadcrumbNameMap)}>
+      <DocumentTitle
+        title={getPageTitle({
+          pathname: location!.pathname,
+          breadcrumb,
+          formatMessage,
+        })}
+      >
         <div className={styles.container}>
           <div className={styles.lang}>
             <SelectLang />
@@ -78,7 +80,4 @@ class UserLayout extends Component<UserLayoutProps> {
   }
 }
 
-export default connect(({ menu: menuModel }: ConnectState) => ({
-  menuDaDocumentTitleta: menuModel.menuData,
-  breadcrumbNameMap: menuModel.breadcrumbNameMap,
-}))(UserLayout);
+export default UserLayout;

+ 1 - 3
src/models/connect.d.ts

@@ -2,11 +2,10 @@ import { EffectsCommandMap } from 'dva';
 import { AnyAction } from 'redux';
 import { RouterTypes } from 'umi';
 import { GlobalModelState } from './global';
-import { MenuModelState } from './menu';
 import { UserModelState } from './user';
 import { DefaultSettings as SettingModelState } from '../../config/defaultSettings';
 import { MenuDataItem } from '@ant-design/pro-layout';
-export { GlobalModelState, MenuModelState, SettingModelState, UserModelState };
+export { GlobalModelState, SettingModelState, UserModelState };
 
 export type Effect = (
   action: AnyAction,
@@ -39,7 +38,6 @@ export interface ConnectState {
   global: GlobalModelState;
   loading: Loading;
   settings: SettingModelState;
-  menu: MenuModelState;
   user: UserModelState;
 }
 

+ 0 - 139
src/models/menu.ts

@@ -1,139 +0,0 @@
-import { MenuDataItem } from '@ant-design/pro-layout';
-import Authorized from '@/utils/Authorized';
-import { Effect } from 'dva';
-import isEqual from 'lodash/isEqual';
-import memoizeOne from 'memoize-one';
-import { Reducer } from 'redux';
-import { formatMessage } from 'umi-plugin-react/locale';
-import { IRoute } from 'umi-types';
-import defaultSettings from '../../config/defaultSettings';
-
-// Conversion router to menu.
-function formatter(
-  data: MenuDataItem[],
-  parentAuthority?: string[] | string,
-  parentName?: string,
-): MenuDataItem[] {
-  return data
-    .filter(item => item.name && item.path)
-    .map(item => {
-      const locale = `${parentName || 'menu'}.${item.name!}`;
-      // if enableMenuLocale use item.name,
-      // close menu international
-      const name = defaultSettings.menu.disableLocal
-        ? item.name!
-        : formatMessage({ id: locale, defaultMessage: item.name! });
-      const result: MenuDataItem = {
-        ...item,
-        name,
-        locale,
-        routes: void 0,
-        authority: item.authority || parentAuthority,
-      };
-      if (item.routes) {
-        const children = formatter(item.routes, item.authority, locale);
-        // Reduce memory usage
-        result.children = children;
-      }
-      return result;
-    });
-}
-
-const memoizeOneFormatter = memoizeOne(formatter, isEqual);
-
-/**
- * get SubMenu or Item
- */
-const getSubMenu: (item: MenuDataItem) => MenuDataItem = item => {
-  if (
-    Array.isArray(item.children) &&
-    !item.hideChildrenInMenu &&
-    item.children.some(child => (child.name ? true : false))
-  ) {
-    const children = filterMenuData(item.children);
-    if (children.length) return { ...item, children };
-  }
-  return { ...item, children: void 0 };
-};
-
-/**
- * filter menuData
- */
-const filterMenuData = (menuData: MenuDataItem[] = []): MenuDataItem[] => {
-  return menuData
-    .filter(item => item.name && !item.hideInMenu)
-    .map(item => Authorized.check<any, any>(item.authority!, getSubMenu(item), null))
-    .filter(item => item);
-};
-
-/**
- * 获取面包屑映射
- * @param MenuDataItem[] menuData 菜单配置
- */
-const getBreadcrumbNameMap = (menuData: MenuDataItem[]) => {
-  const routerMap: { [key: string]: MenuDataItem } = {};
-  const flattenMenuData: (data: MenuDataItem[]) => void = data => {
-    data.forEach(menuItem => {
-      if (menuItem.children) {
-        flattenMenuData(menuItem.children);
-      }
-      // Reduce memory usage
-      routerMap[menuItem.path] = menuItem;
-    });
-  };
-  flattenMenuData(menuData);
-  return routerMap;
-};
-
-const memoizeOneGetBreadcrumbNameMap = memoizeOne(getBreadcrumbNameMap, isEqual);
-
-export interface MenuModelState {
-  menuData: MenuDataItem[];
-  routerData: IRoute[];
-  breadcrumbNameMap: object;
-}
-
-export interface MenuModelType {
-  namespace: 'menu';
-  state: MenuModelState;
-  effects: {
-    getMenuData: Effect;
-  };
-  reducers: {
-    save: Reducer<MenuModelState>;
-  };
-}
-
-const MenuModel: MenuModelType = {
-  namespace: 'menu',
-
-  state: {
-    menuData: [],
-    routerData: [],
-    breadcrumbNameMap: {},
-  },
-
-  effects: {
-    *getMenuData({ payload }, { put }) {
-      const { routes, authority } = payload;
-      const originalMenuData = memoizeOneFormatter(routes, authority);
-      const menuData = filterMenuData(originalMenuData);
-      const breadcrumbNameMap = memoizeOneGetBreadcrumbNameMap(originalMenuData);
-      yield put({
-        type: 'save',
-        payload: { menuData, breadcrumbNameMap, routerData: routes },
-      });
-    },
-  },
-
-  reducers: {
-    save(state, action) {
-      return {
-        ...state,
-        ...action.payload,
-      };
-    },
-  },
-};
-
-export default MenuModel;

+ 11 - 5
src/pages/Authorized.tsx

@@ -7,7 +7,6 @@ import React from 'react';
 import Redirect from 'umi/redirect';
 
 interface AuthComponentProps extends ConnectProps {
-  routerData: Route[];
   user: UserModelState;
 }
 
@@ -26,12 +25,20 @@ const getRouteAuthority = (path: string, routeData: Route[]) => {
   return authorities;
 };
 
-const AuthComponent: React.FC<AuthComponentProps> = ({ children, location, routerData, user }) => {
+const AuthComponent: React.FC<AuthComponentProps> = ({
+  children,
+  route = {
+    routes: [],
+  },
+  location,
+  user,
+}) => {
   const { currentUser } = user;
+  const { routes = [] } = route;
   const isLogin = currentUser && currentUser.name;
   return (
     <Authorized
-      authority={getRouteAuthority(location!.pathname, routerData)!}
+      authority={getRouteAuthority(location!.pathname, routes)!}
       noMatch={isLogin ? <Redirect to="/exception/403" /> : <Redirect to="/user/login" />}
     >
       {children}
@@ -39,7 +46,6 @@ const AuthComponent: React.FC<AuthComponentProps> = ({ children, location, route
   );
 };
 
-export default connect(({ menu: menuModel, user }: ConnectState) => ({
-  routerData: menuModel.routerData,
+export default connect(({ user }: ConnectState) => ({
   user,
 }))(AuthComponent);

+ 0 - 36
src/utils/getPageTitle.ts

@@ -1,36 +0,0 @@
-import isEqual from 'lodash/isEqual';
-import memoizeOne from 'memoize-one';
-import pathToRegexp from 'path-to-regexp';
-import { formatMessage } from 'umi-plugin-react/locale';
-import defaultSettings from '../../config/defaultSettings';
-import { MenuDataItem } from '@/components/SiderMenu/BaseMenu';
-
-const { menu, title } = defaultSettings;
-
-export const matchParamsPath = (
-  pathname: string,
-  breadcrumbNameMap: { [path: string]: MenuDataItem },
-): MenuDataItem => {
-  const pathKey = Object.keys(breadcrumbNameMap).find(key => pathToRegexp(key).test(pathname));
-  return breadcrumbNameMap[pathKey!];
-};
-
-const getPageTitle = (
-  pathname: string,
-  breadcrumbNameMap: { [path: string]: MenuDataItem },
-): string => {
-  const currRouterData = matchParamsPath(pathname, breadcrumbNameMap);
-  if (!currRouterData) {
-    return title;
-  }
-  const pageName = menu.disableLocal
-    ? currRouterData.name
-    : formatMessage({
-        id: currRouterData.locale || currRouterData.name!,
-        defaultMessage: currRouterData.name,
-      });
-
-  return `${pageName} - ${title}`;
-};
-
-export default memoizeOne(getPageTitle, isEqual);

+ 0 - 2
tsconfig.json

@@ -9,7 +9,6 @@
     "jsx": "react",
     "allowSyntheticDefaultImports": true,
     "moduleResolution": "node",
-    "rootDirs": ["/src", "/test", "/mock", "./typings"],
     "forceConsistentCasingInFileNames": true,
     "noImplicitReturns": true,
     "suppressImplicitAnyIndexErrors": true,
@@ -21,7 +20,6 @@
       "@/*": ["./src/*"]
     }
   },
-  "include": ["./src", "config/defaultSettings.ts"],
   "exclude": [
     "node_modules",
     "build",

+ 1 - 1
tslint.yml

@@ -1,6 +1,6 @@
 defaultSeverity: error
 globals:
- - ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION: true
+  - ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION: true
 extends:
   - tslint-react
   - tslint-eslint-rules

+ 2 - 0
typings.d.ts

@@ -1,3 +1,5 @@
 declare module 'slash2';
 declare module 'antd-pro-merge-less';
 declare module 'antd-theme-webpack-plugin';
+
+declare let ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION: 'site' | undefined;