Bladeren bron

use pro-layout Components

陈帅 6 jaren geleden
bovenliggende
commit
d1b6e0fe8c

+ 1 - 0
package.json

@@ -56,6 +56,7 @@
     "not ie <= 10"
   ],
   "dependencies": {
+    "@ant-design/pro-layout": "^4.0.3",
     "ant-design-pro": "^2.3.0",
     "antd": "^3.15.0",
     "classnames": "^2.2.6",

+ 0 - 53
src/components/GlobalHeader/index.tsx

@@ -1,53 +0,0 @@
-import React, { Component } from 'react';
-import { Icon } from 'antd';
-import Link from 'umi/link';
-import debounce from 'lodash/debounce';
-import styles from './index.less';
-import RightContent, { GlobalHeaderRightProps } from './RightContent';
-
-type PartialGlobalHeaderRightProps = {
-  [K in
-    | 'onMenuClick'
-    | 'onNoticeClear'
-    | 'onNoticeVisibleChange'
-    | 'currentUser']?: GlobalHeaderRightProps[K]
-};
-
-export interface GlobalHeaderProps extends PartialGlobalHeaderRightProps {
-  collapsed?: boolean;
-  onCollapse?: (collapsed: boolean) => void;
-  isMobile?: boolean;
-  logo?: string;
-}
-
-export default class GlobalHeader extends Component<GlobalHeaderProps> {
-  triggerResizeEvent = debounce(() => {
-    const event = document.createEvent('HTMLEvents');
-    event.initEvent('resize', true, false);
-    window.dispatchEvent(event);
-  });
-  componentWillUnmount() {
-    this.triggerResizeEvent.cancel();
-  }
-  toggle = () => {
-    const { collapsed, onCollapse } = this.props;
-    if (onCollapse) onCollapse(!collapsed);
-    this.triggerResizeEvent();
-  };
-  render() {
-    const { collapsed, isMobile, logo } = this.props;
-    return (
-      <div className={styles.header}>
-        {isMobile && (
-          <Link to="/" className={styles.logo} key="logo">
-            <img src={logo} alt="logo" width="32" />
-          </Link>
-        )}
-        <span className={styles.trigger} onClick={this.toggle}>
-          <Icon type={collapsed ? 'menu-unfold' : 'menu-fold'} />
-        </span>
-        <RightContent {...this.props} />
-      </div>
-    );
-  }
-}

+ 0 - 9
src/components/IconFont/index.tsx

@@ -1,9 +0,0 @@
-import { Icon } from 'antd';
-import defaultSettings from '../../../config/defaultSettings';
-
-const { iconfontUrl } = defaultSettings;
-const scriptUrl = iconfontUrl;
-// 使用:
-// import IconFont from '@/components/IconFont';
-// <IconFont type='icon-demo' className='xxx-xxx' />
-export default Icon.createFromIconfontCN({ scriptUrl });

+ 0 - 31
src/components/SettingDrawer/BlockCheckbox.tsx

@@ -1,31 +0,0 @@
-import React from 'react';
-import { Tooltip, Icon } from 'antd';
-import style from './index.less';
-
-export interface BlockChecboxProps {
-  value: string;
-  onChange: (key: string) => void;
-  list: any[];
-}
-
-const BlockChecbox: React.FC<BlockChecboxProps> = ({ value, onChange, list }) => (
-  <div className={style.blockChecbox} key={value}>
-    {list.map(item => (
-      <Tooltip title={item.title} key={item.key}>
-        <div className={style.item} onClick={() => onChange(item.key)}>
-          <img src={item.url} alt={item.key} />
-          <div
-            className={style.selectIcon}
-            style={{
-              display: value === item.key ? 'block' : 'none',
-            }}
-          >
-            <Icon type="check" />
-          </div>
-        </div>
-      </Tooltip>
-    ))}
-  </div>
-);
-
-export default BlockChecbox;

+ 0 - 21
src/components/SettingDrawer/ThemeColor.less

@@ -1,21 +0,0 @@
-.themeColor {
-  margin-top: 24px;
-  overflow: hidden;
-  .title {
-    margin-bottom: 12px;
-    color: rgba(0, 0, 0, 0.65);
-    font-size: 14px;
-    line-height: 22px;
-  }
-  .colorBlock {
-    float: left;
-    width: 20px;
-    height: 20px;
-    margin-right: 8px;
-    color: #fff;
-    font-weight: bold;
-    text-align: center;
-    border-radius: 2px;
-    cursor: pointer;
-  }
-}

+ 0 - 80
src/components/SettingDrawer/ThemeColor.tsx

@@ -1,80 +0,0 @@
-import React from 'react';
-import { Tooltip, Icon } from 'antd';
-import { formatMessage } from 'umi-plugin-locale';
-import styles from './ThemeColor.less';
-
-export interface TagProps {
-  color: string;
-  check: boolean;
-  className?: string;
-  onClick?: () => void;
-}
-
-const Tag: React.FC<TagProps> = ({ color, check, ...rest }) => (
-  <div {...rest} style={{ backgroundColor: color }}>
-    {check ? <Icon type="check" /> : ''}
-  </div>
-);
-
-export interface ThemeColorProps {
-  colors?: any[];
-  title?: string;
-  value: string;
-  onChange: (color: string) => void;
-}
-
-const ThemeColor: React.FC<ThemeColorProps> = ({ colors, title, value, onChange }) => {
-  const colorList = colors || [
-    {
-      key: 'dust',
-      color: '#F5222D',
-    },
-    {
-      key: 'volcano',
-      color: '#FA541C',
-    },
-    {
-      key: 'sunset',
-      color: '#FAAD14',
-    },
-    {
-      key: 'cyan',
-      color: '#13C2C2',
-    },
-    {
-      key: 'green',
-      color: '#52C41A',
-    },
-    {
-      key: 'daybreak',
-      color: '#1890FF',
-    },
-    {
-      key: 'geekblue',
-      color: '#2F54EB',
-    },
-    {
-      key: 'purple',
-      color: '#722ED1',
-    },
-  ];
-  return (
-    <div className={styles.themeColor}>
-      <h3 className={styles.title}>{title}</h3>
-      <div className={styles.content}>
-        {colorList.map(({ key, color }) => (
-          <Tooltip key={color} title={formatMessage({ id: `app.setting.themecolor.${key}` })}>
-            <Tag
-              className={styles.colorBlock}
-              color={color}
-              check={value === color}
-              onClick={() => onChange && onChange(color)}
-            />
-          </Tooltip>
-        ))}
-      </div>
-    </div>
-  );
-};
-
-export default ThemeColor;

+ 0 - 81
src/components/SettingDrawer/index.less

@@ -1,81 +0,0 @@
-@import '~antd/lib/style/themes/default.less';
-
-.content {
-  position: relative;
-  min-height: 100%;
-  background: #fff;
-  :global {
-    .ant-list-item {
-      span {
-        flex: 1;
-      }
-    }
-  }
-}
-
-.blockChecbox {
-  display: flex;
-  .item {
-    position: relative;
-    margin-right: 16px;
-    // box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.1);
-    border-radius: @border-radius-base;
-    cursor: pointer;
-    img {
-      width: 48px;
-    }
-  }
-  .selectIcon {
-    position: absolute;
-    top: 0;
-    right: 0;
-    width: 100%;
-    height: 100%;
-    padding-top: 15px;
-    padding-left: 24px;
-    color: @primary-color;
-    font-weight: bold;
-    font-size: 14px;
-  }
-}
-
-.color_block {
-  display: inline-block;
-  width: 38px;
-  height: 22px;
-  margin: 4px;
-  margin-right: 12px;
-  vertical-align: middle;
-  border-radius: 4px;
-  cursor: pointer;
-}
-
-.title {
-  margin-bottom: 12px;
-  color: @heading-color;
-  font-size: 14px;
-  line-height: 22px;
-}
-
-.handle {
-  position: absolute;
-  top: 240px;
-  right: 300px;
-  z-index: 0;
-  display: flex;
-  justify-content: center;
-  align-items: center;
-  width: 48px;
-  height: 48px;
-  font-size: 16px;
-  text-align: center;
-  background: @primary-color;
-  border-radius: 4px 0 0 4px;
-  cursor: pointer;
-  pointer-events: auto;
-}
-
-.productionHint {
-  margin-top: 16px;
-  font-size: 12px;
-}

+ 0 - 272
src/components/SettingDrawer/index.tsx

@@ -1,272 +0,0 @@
-import { ConnectProps, ConnectState, SettingModelState } from '@/models/connect';
-import React, { Component } from 'react';
-import { Select, message, Drawer, List, Switch, Divider, Icon, Button, Alert, Tooltip } from 'antd';
-import { formatMessage } from 'umi-plugin-react/locale';
-import { CopyToClipboard } from 'react-copy-to-clipboard';
-import { connect } from 'dva';
-import omit from 'omit.js';
-import styles from './index.less';
-import ThemeColor from './ThemeColor';
-import BlockCheckbox from './BlockCheckbox';
-
-const { Option } = Select;
-interface BodyProps {
-  title: string;
-  style?: React.CSSProperties;
-}
-
-const Body: React.FC<BodyProps> = ({ children, title, style }) => (
-  <div style={{ ...style, marginBottom: 24 }}>
-    <h3 className={styles.title}>{title}</h3>
-    {children}
-  </div>
-);
-
-interface SettingItemProps {
-  title: React.ReactNode;
-  action: React.ReactElement;
-  disabled?: boolean;
-  disabledReason?: React.ReactNode;
-}
-
-export interface SettingDrawerProps extends ConnectProps {
-  setting?: SettingModelState;
-}
-
-export interface SettingDrawerState extends Partial<SettingModelState> {
-  collapse: boolean;
-}
-
-@connect(({ setting }: ConnectState) => ({ setting }))
-class SettingDrawer extends Component<SettingDrawerProps, SettingDrawerState> {
-  state: SettingDrawerState = {
-    collapse: false,
-  };
-
-  getLayoutSetting = (): SettingItemProps[] => {
-    const { setting } = this.props;
-    const { contentWidth, fixedHeader, layout, autoHideHeader, fixSiderbar } = setting!;
-    return [
-      {
-        title: formatMessage({ id: 'app.setting.content-width' }),
-        action: (
-          <Select
-            value={contentWidth}
-            size="small"
-            onSelect={value => this.changeSetting('contentWidth', value)}
-            style={{ width: 80 }}
-          >
-            {layout === 'sidemenu' ? null : (
-              <Option value="Fixed">
-                {formatMessage({ id: 'app.setting.content-width.fixed' })}
-              </Option>
-            )}
-            <Option value="Fluid">
-              {formatMessage({ id: 'app.setting.content-width.fluid' })}
-            </Option>
-          </Select>
-        ),
-      },
-      {
-        title: formatMessage({ id: 'app.setting.fixedheader' }),
-        action: (
-          <Switch
-            size="small"
-            checked={!!fixedHeader}
-            onChange={checked => this.changeSetting('fixedHeader', checked)}
-          />
-        ),
-      },
-      {
-        title: formatMessage({ id: 'app.setting.hideheader' }),
-        disabled: !fixedHeader,
-        disabledReason: formatMessage({ id: 'app.setting.hideheader.hint' }),
-        action: (
-          <Switch
-            size="small"
-            checked={!!autoHideHeader}
-            onChange={checked => this.changeSetting('autoHideHeader', checked)}
-          />
-        ),
-      },
-      {
-        title: formatMessage({ id: 'app.setting.fixedsidebar' }),
-        disabled: layout === 'topmenu',
-        disabledReason: formatMessage({ id: 'app.setting.fixedsidebar.hint' }),
-        action: (
-          <Switch
-            size="small"
-            checked={!!fixSiderbar}
-            onChange={checked => this.changeSetting('fixSiderbar', checked)}
-          />
-        ),
-      },
-    ];
-  };
-
-  changeSetting = (key: string, value: any) => {
-    const { setting } = this.props;
-    const nextState = { ...setting! };
-    nextState[key] = value;
-    if (key === 'layout') {
-      nextState.contentWidth = value === 'topmenu' ? 'Fixed' : 'Fluid';
-    } else if (key === 'fixedHeader' && !value) {
-      nextState.autoHideHeader = false;
-    }
-    this.setState(nextState, () => {
-      const { dispatch } = this.props;
-      dispatch!({
-        type: 'setting/changeSetting',
-        payload: this.state,
-      });
-    });
-  };
-
-  togglerContent = () => {
-    const { collapse } = this.state;
-    this.setState({ collapse: !collapse });
-  };
-
-  renderLayoutSettingItem = (item: SettingItemProps) => {
-    const action = React.cloneElement(item.action, {
-      disabled: item.disabled,
-    });
-    return (
-      <Tooltip title={item.disabled ? item.disabledReason : ''} placement="left">
-        <List.Item actions={[action]}>
-          <span style={{ opacity: item.disabled ? 0.5 : 1 }}>{item.title}</span>
-        </List.Item>
-      </Tooltip>
-    );
-  };
-
-  render() {
-    const { setting } = this.props;
-    const { navTheme, primaryColor, layout, colorWeak } = setting!;
-    const { collapse } = this.state;
-    return (
-      <Drawer
-        visible={collapse}
-        width={300}
-        onClose={this.togglerContent}
-        placement="right"
-        handler={
-          <div className={styles.handle} onClick={this.togglerContent}>
-            <Icon
-              type={collapse ? 'close' : 'setting'}
-              style={{
-                color: '#fff',
-                fontSize: 20,
-              }}
-            />
-          </div>
-        }
-        style={{
-          zIndex: 999,
-        }}
-      >
-        <div className={styles.content}>
-          <Body title={formatMessage({ id: 'app.setting.pagestyle' })}>
-            <BlockCheckbox
-              list={[
-                {
-                  key: 'dark',
-                  url: 'https://gw.alipayobjects.com/zos/rmsportal/LCkqqYNmvBEbokSDscrm.svg',
-                  title: formatMessage({ id: 'app.setting.pagestyle.dark' }),
-                },
-                {
-                  key: 'light',
-                  url: 'https://gw.alipayobjects.com/zos/rmsportal/jpRkZQMyYRryryPNtyIC.svg',
-                  title: formatMessage({ id: 'app.setting.pagestyle.light' }),
-                },
-              ]}
-              value={navTheme}
-              onChange={value => this.changeSetting('navTheme', value)}
-            />
-          </Body>
-
-          <ThemeColor
-            title={formatMessage({ id: 'app.setting.themecolor' })}
-            value={primaryColor}
-            onChange={color => this.changeSetting('primaryColor', color)}
-          />
-
-          <Divider />
-
-          <Body title={formatMessage({ id: 'app.setting.navigationmode' })}>
-            <BlockCheckbox
-              list={[
-                {
-                  key: 'sidemenu',
-                  url: 'https://gw.alipayobjects.com/zos/rmsportal/JopDzEhOqwOjeNTXkoje.svg',
-                  title: formatMessage({ id: 'app.setting.sidemenu' }),
-                },
-                {
-                  key: 'topmenu',
-                  url: 'https://gw.alipayobjects.com/zos/rmsportal/KDNDBbriJhLwuqMoxcAr.svg',
-                  title: formatMessage({ id: 'app.setting.topmenu' }),
-                },
-              ]}
-              value={layout}
-              onChange={value => this.changeSetting('layout', value)}
-            />
-          </Body>
-
-          <List
-            split={false}
-            dataSource={this.getLayoutSetting()}
-            renderItem={this.renderLayoutSettingItem}
-          />
-
-          <Divider />
-
-          <Body title={formatMessage({ id: 'app.setting.othersettings' })}>
-            <List
-              split={false}
-              renderItem={this.renderLayoutSettingItem}
-              dataSource={[
-                {
-                  title: formatMessage({ id: 'app.setting.weakmode' }),
-                  action: (
-                    <Switch
-                      size="small"
-                      checked={!!colorWeak}
-                      onChange={checked => this.changeSetting('colorWeak', checked)}
-                    />
-                  ),
-                },
-              ]}
-            />
-          </Body>
-          <Divider />
-          <CopyToClipboard
-            text={JSON.stringify(omit(setting, ['colorWeak']), null, 2)}
-            onCopy={() => message.success(formatMessage({ id: 'app.setting.copyinfo' }))}
-          >
-            <Button block icon="copy">
-              {formatMessage({ id: 'app.setting.copy' })}
-            </Button>
-          </CopyToClipboard>
-          <Alert
-            type="warning"
-            className={styles.productionHint}
-            message={
-              <div>
-                {formatMessage({ id: 'app.setting.production.hint' })}{' '}
-                <a
-                  href="https://u.ant.design/pro-v2-default-settings"
-                  target="_blank"
-                  rel="noopener noreferrer"
-                >
-                  src/defaultSettings.js
-                </a>
-              </div>
-            }
-          />
-        </div>
-      </Drawer>
-    );
-  }
-}
-
-export default SettingDrawer;

+ 0 - 206
src/components/SiderMenu/BaseMenu.tsx

@@ -1,206 +0,0 @@
-import IconFont from '@/components/IconFont';
-import { isUrl } from '@/utils/utils';
-import { Icon, Menu } from 'antd';
-import { MenuMode, MenuTheme } from 'antd/es/menu';
-import classNames from 'classnames';
-import React, { Component } from 'react';
-import { RouterTypes } from 'umi';
-import Link from 'umi/link';
-import { urlToList } from '../_utils/pathTools';
-import styles from './index.less';
-import { getMenuMatches } from './SiderMenuUtils';
-
-const { SubMenu } = Menu;
-
-// Allow menu.js config icon as string or ReactNode
-//   icon: 'setting',
-//   icon: 'icon-geren' #For Iconfont ,
-//   icon: 'http://demo.com/icon.png',
-//   icon: <Icon type="setting" />,
-const getIcon = (icon?: string | React.ReactNode) => {
-  if (typeof icon === 'string') {
-    if (isUrl(icon)) {
-      return <Icon component={() => <img src={icon} alt="icon" className={styles.icon} />} />;
-    }
-    if (icon.startsWith('icon-')) {
-      return <IconFont type={icon} />;
-    }
-    return <Icon type={icon} />;
-  }
-  return icon;
-};
-
-export interface MenuDataItem {
-  authority?: string[] | string;
-  children?: MenuDataItem[];
-  hideChildrenInMenu?: boolean;
-  hideInMenu?: boolean;
-  icon?: string;
-  locale?: string;
-  name?: string;
-  path: string;
-  [key: string]: any;
-}
-
-export interface Route extends MenuDataItem {
-  routes?: Route[];
-}
-
-export interface BaseMenuProps extends Partial<RouterTypes<Route>> {
-  className?: string;
-  collapsed?: boolean;
-  flatMenuKeys?: any[];
-  handleOpenChange?: (openKeys: string[]) => void;
-  isMobile?: boolean;
-  menuData?: MenuDataItem[];
-  mode?: MenuMode;
-  onCollapse?: (collapsed: boolean) => void;
-  onOpenChange?: (openKeys: string[]) => void;
-  openKeys?: string[];
-  style?: React.CSSProperties;
-  theme?: MenuTheme;
-}
-
-export default class BaseMenu extends Component<BaseMenuProps> {
-  static defaultProps: Partial<BaseMenuProps> = {
-    flatMenuKeys: [],
-    onCollapse: () => void 0,
-    isMobile: false,
-    openKeys: [],
-    collapsed: false,
-    handleOpenChange: () => void 0,
-    menuData: [],
-    onOpenChange: () => void 0,
-  };
-
-  /**
-   * 获得菜单子节点
-   */
-  getNavMenuItems = (menusData: MenuDataItem[] = []): React.ReactNode[] => {
-    return menusData
-      .filter(item => item.name && !item.hideInMenu)
-      .map(item => this.getSubMenuOrItem(item))
-      .filter(item => item);
-  };
-
-  // Get the currently selected menu
-  getSelectedMenuKeys = (pathname: string): string[] => {
-    const { flatMenuKeys } = this.props;
-    return urlToList(pathname)
-      .map(itemPath => getMenuMatches(flatMenuKeys, itemPath).pop())
-      .filter(item => item) as string[];
-  };
-
-  /**
-   * get SubMenu or Item
-   */
-  getSubMenuOrItem = (item: MenuDataItem): React.ReactNode => {
-    if (
-      Array.isArray(item.children) &&
-      !item.hideChildrenInMenu &&
-      item.children.some(child => (child.name ? true : false))
-    ) {
-      return (
-        <SubMenu
-          title={
-            item.icon ? (
-              <span>
-                {getIcon(item.icon)}
-                <span>{item.name}</span>
-              </span>
-            ) : (
-              item.name
-            )
-          }
-          key={item.path}
-        >
-          {this.getNavMenuItems(item.children)}
-        </SubMenu>
-      );
-    }
-    return <Menu.Item key={item.path}>{this.getMenuItemPath(item)}</Menu.Item>;
-  };
-
-  /**
-   * 判断是否是http链接.返回 Link 或 a
-   * Judge whether it is http link.return a or Link
-   * @memberof SiderMenu
-   */
-  getMenuItemPath = (item: MenuDataItem) => {
-    const { name } = item;
-    const itemPath = this.conversionPath(item.path);
-    const icon = getIcon(item.icon);
-    const { target } = item;
-    // Is it a http link
-    if (/^https?:\/\//.test(itemPath)) {
-      return (
-        <a href={itemPath} target={target}>
-          {icon}
-          <span>{name}</span>
-        </a>
-      );
-    }
-    const { location, isMobile, onCollapse } = this.props;
-    return (
-      <Link
-        to={itemPath}
-        target={target}
-        replace={itemPath === location!.pathname}
-        onClick={isMobile ? () => onCollapse!(true) : void 0}
-      >
-        {icon}
-        <span>{name}</span>
-      </Link>
-    );
-  };
-
-  conversionPath = (path: string) => {
-    if (path && path.indexOf('http') === 0) {
-      return path;
-    }
-    return `/${path || ''}`.replace(/\/+/g, '/');
-  };
-
-  render() {
-    const {
-      openKeys,
-      theme,
-      mode,
-      location,
-      className,
-      collapsed,
-      handleOpenChange,
-      style,
-      menuData,
-    } = this.props;
-    // if pathname can't match, use the nearest parent's key
-    let selectedKeys = this.getSelectedMenuKeys(location!.pathname);
-    if (!selectedKeys.length && openKeys) {
-      selectedKeys = [openKeys[openKeys.length - 1]];
-    }
-    let props = {};
-    if (openKeys && !collapsed) {
-      props = {
-        openKeys: openKeys.length === 0 ? [...selectedKeys] : openKeys,
-      };
-    }
-    const cls = classNames(className, {
-      'top-nav-menu': mode === 'horizontal',
-    });
-
-    return (
-      <Menu
-        key="Menu"
-        mode={mode}
-        theme={theme}
-        onOpenChange={handleOpenChange}
-        selectedKeys={selectedKeys}
-        style={style}
-        className={cls}
-        {...props}
-      >
-        {this.getNavMenuItems(menuData)}
-      </Menu>
-    );
-  }
-}

+ 0 - 124
src/components/SiderMenu/SiderMenu.tsx

@@ -1,124 +0,0 @@
-import { Layout } from 'antd';
-import classNames from 'classnames';
-import React, { Component, Suspense } from 'react';
-import Link from 'umi/link';
-import defaultSettings from '../../../config/defaultSettings';
-import PageLoading from '../PageLoading';
-import { BaseMenuProps } from './BaseMenu';
-import styles from './index.less';
-import { getDefaultCollapsedSubMenus } from './SiderMenuUtils';
-
-const BaseMenu = React.lazy(() => import('./BaseMenu'));
-const { Sider } = Layout;
-const { title } = defaultSettings;
-let firstMount: boolean = true;
-
-export interface SiderMenuProps extends BaseMenuProps {
-  logo?: string;
-  fixSiderbar?: boolean;
-}
-
-interface SiderMenuState {
-  pathname?: string;
-  openKeys?: string[];
-  flatMenuKeysLen?: number;
-}
-
-export default class SiderMenu extends Component<SiderMenuProps, SiderMenuState> {
-  static defaultProps: Partial<SiderMenuProps> = {
-    flatMenuKeys: [],
-    onCollapse: () => void 0,
-    isMobile: false,
-    openKeys: [],
-    collapsed: false,
-    handleOpenChange: () => void 0,
-    menuData: [],
-    onOpenChange: () => void 0,
-  };
-
-  static getDerivedStateFromProps(props: SiderMenuProps, state: SiderMenuState) {
-    const { pathname, flatMenuKeysLen } = state;
-    if (props.location!.pathname !== pathname || props.flatMenuKeys!.length !== flatMenuKeysLen) {
-      return {
-        pathname: props.location!.pathname,
-        flatMenuKeysLen: props.flatMenuKeys!.length,
-        openKeys: getDefaultCollapsedSubMenus(props),
-      };
-    }
-    return null;
-  }
-
-  constructor(props: SiderMenuProps) {
-    super(props);
-    this.state = {
-      openKeys: getDefaultCollapsedSubMenus(props),
-    };
-  }
-
-  componentDidMount() {
-    firstMount = false;
-  }
-
-  isMainMenu: (key: string) => boolean = key => {
-    const { menuData } = this.props;
-    return menuData!.some(item => {
-      if (key) {
-        return item.key === key || item.path === key;
-      }
-      return false;
-    });
-  };
-
-  handleOpenChange: (openKeys: string[]) => void = openKeys => {
-    const moreThanOne = openKeys.filter(openKey => this.isMainMenu(openKey)).length > 1;
-    if (moreThanOne) {
-      this.setState({ openKeys: [openKeys.pop()].filter(item => item) as string[] });
-    } else {
-      this.setState({ openKeys: [...openKeys] });
-    }
-  };
-
-  render() {
-    const { logo, collapsed, onCollapse, fixSiderbar, theme, isMobile } = this.props;
-    const { openKeys } = this.state;
-    const defaultProps = collapsed ? {} : { openKeys };
-
-    const siderClassName = classNames(styles.sider, {
-      [styles.fixSiderBar]: fixSiderbar,
-      [styles.light]: theme === 'light',
-    });
-    return (
-      <Sider
-        collapsible
-        trigger={null}
-        collapsed={collapsed}
-        breakpoint="lg"
-        onCollapse={collapse => {
-          if (firstMount || !isMobile) {
-            onCollapse!(collapse);
-          }
-        }}
-        width={256}
-        theme={theme}
-        className={siderClassName}
-      >
-        <div className={styles.logo} id="logo">
-          <Link to="/">
-            <img src={logo} alt="logo" />
-            <h1>{title}</h1>
-          </Link>
-        </div>
-        <Suspense fallback={<PageLoading />}>
-          <BaseMenu
-            {...this.props}
-            mode="inline"
-            handleOpenChange={this.handleOpenChange}
-            onOpenChange={this.handleOpenChange}
-            style={{ padding: '16px 0', width: '100%' }}
-            {...defaultProps}
-          />
-        </Suspense>
-      </Sider>
-    );
-  }
-}

+ 0 - 33
src/components/SiderMenu/SiderMenuUtils.ts

@@ -1,33 +0,0 @@
-import pathToRegexp from 'path-to-regexp';
-import { urlToList } from '../_utils/pathTools';
-import { MenuDataItem, BaseMenuProps } from './BaseMenu';
-
-/**
- * Recursively flatten the data
- * [{path:string},{path:string}] => {path,path2}
- * @param  menus
- */
-export const getFlatMenuKeys = (menuData: MenuDataItem[] = []) => {
-  let keys: string[] = [];
-  menuData.forEach(item => {
-    keys.push(item.path);
-    if (item.children) {
-      keys = keys.concat(getFlatMenuKeys(item.children));
-    }
-  });
-  return keys;
-};
-
-export const getMenuMatches = (flatMenuKeys: string[] = [], path: string) =>
-  flatMenuKeys.filter(item => item && pathToRegexp(item).test(path));
-
-/**
- * 获得菜单子节点
- */
-export const getDefaultCollapsedSubMenus = (props: BaseMenuProps) => {
-  const { location, flatMenuKeys } = props;
-  return urlToList(location!.pathname)
-    .map(item => getMenuMatches(flatMenuKeys, item)[0])
-    .filter(item => item)
-    .reduce((acc, curr) => [...acc, curr], ['/']);
-};

+ 0 - 105
src/components/SiderMenu/index.less

@@ -1,105 +0,0 @@
-@import '~antd/lib/style/themes/default.less';
-
-@nav-header-height: @layout-header-height;
-
-.logo {
-  position: relative;
-  height: @nav-header-height;
-  padding-left: (@menu-collapsed-width - 32px) / 2;
-  overflow: hidden;
-  line-height: @nav-header-height;
-  background: #002140;
-  transition: all 0.3s;
-  img {
-    display: inline-block;
-    height: 32px;
-    vertical-align: middle;
-  }
-  h1 {
-    display: inline-block;
-    margin: 0 0 0 12px;
-    color: white;
-    font-weight: 600;
-    font-size: 20px;
-    font-family: Avenir, 'Helvetica Neue', Arial, Helvetica, sans-serif;
-    vertical-align: middle;
-  }
-}
-.sider {
-  position: relative;
-  z-index: 10;
-  min-height: 100vh;
-  box-shadow: 2px 0 6px rgba(0, 21, 41, 0.35);
-  &.fixSiderBar {
-    position: fixed;
-    top: 0;
-    left: 0;
-    box-shadow: 2px 0 8px 0 rgba(29, 35, 41, 0.05);
-    :global {
-      .ant-menu-root {
-        height: ~'calc(100vh - @{nav-header-height})';
-        overflow-y: auto;
-      }
-      .ant-menu-inline {
-        border-right: 0;
-        .ant-menu-item,
-        .ant-menu-submenu-title {
-          width: 100%;
-        }
-      }
-    }
-  }
-  &.light {
-    background-color: white;
-    box-shadow: 2px 0 8px 0 rgba(29, 35, 41, 0.05);
-    .logo {
-      background: white;
-      box-shadow: 1px 1px 0 0 @border-color-split;
-      h1 {
-        color: @primary-color;
-      }
-    }
-    :global(.ant-menu-light) {
-      border-right-color: transparent;
-    }
-  }
-}
-
-.icon {
-  width: 14px;
-  vertical-align: baseline;
-}
-
-:global {
-  .top-nav-menu li.ant-menu-item {
-    height: @nav-header-height;
-    line-height: @nav-header-height;
-  }
-  .drawer .drawer-content {
-    background: #001529;
-  }
-  .ant-menu-inline-collapsed {
-    & > .ant-menu-item .sider-menu-item-img + span,
-    &
-      > .ant-menu-item-group
-      > .ant-menu-item-group-list
-      > .ant-menu-item
-      .sider-menu-item-img
-      + span,
-    & > .ant-menu-submenu > .ant-menu-submenu-title .sider-menu-item-img + span {
-      display: inline-block;
-      max-width: 0;
-      opacity: 0;
-    }
-  }
-  .ant-menu-item .sider-menu-item-img + span,
-  .ant-menu-submenu-title .sider-menu-item-img + span {
-    opacity: 1;
-    transition: opacity 0.3s @ease-in-out, width 0.3s @ease-in-out;
-  }
-  .ant-drawer-left {
-    .ant-drawer-body {
-      padding: 0;
-    }
-  }
-}

+ 0 - 34
src/components/SiderMenu/index.tsx

@@ -1,34 +0,0 @@
-import React from 'react';
-import { Drawer } from 'antd';
-import { SiderMenuProps } from './SiderMenu';
-import SiderMenu from './SiderMenu';
-import { getFlatMenuKeys } from './SiderMenuUtils';
-
-export { SiderMenuProps };
-export { MenuDataItem, Route } from './BaseMenu';
-
-const SiderMenuWrapper: React.FC<SiderMenuProps> = props => {
-  const { isMobile, menuData, collapsed, onCollapse } = props;
-  const flatMenuKeys = getFlatMenuKeys(menuData);
-  return isMobile ? (
-    <Drawer
-      visible={!collapsed}
-      placement="left"
-      onClose={() => onCollapse!(true)}
-      style={{
-        padding: 0,
-        height: '100vh',
-      }}
-    >
-      <SiderMenu {...props} flatMenuKeys={flatMenuKeys} collapsed={isMobile ? false : collapsed} />
-    </Drawer>
-  ) : (
-    <SiderMenu {...props} flatMenuKeys={flatMenuKeys} />
-  );
-};
-
-SiderMenuWrapper.defaultProps = {
-  onCollapse: () => void 0,
-};
-
-export default React.memo(SiderMenuWrapper);

+ 0 - 72
src/components/TopNavHeader/index.less

@@ -1,72 +0,0 @@
-@import '~antd/lib/style/themes/default.less';
-
-.head {
-  position: relative;
-  width: 100%;
-  height: @layout-header-height;
-  box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
-  transition: background 0.3s, width 0.2s;
-  :global {
-    .ant-menu-submenu.ant-menu-submenu-horizontal {
-      height: 100%;
-      line-height: @layout-header-height;
-      .ant-menu-submenu-title {
-        height: 100%;
-      }
-    }
-  }
-  &.light {
-    background-color: #fff;
-  }
-  .main {
-    display: flex;
-    height: @layout-header-height;
-    padding-left: 24px;
-    &.wide {
-      max-width: 1200px;
-      margin: auto;
-      padding-left: 0;
-    }
-    .left {
-      display: flex;
-      flex: 1;
-    }
-    .right {
-      width: 324px;
-    }
-  }
-}
-
-.logo {
-  position: relative;
-  width: 165px;
-  height: @layout-header-height;
-  overflow: hidden;
-  line-height: @layout-header-height;
-  transition: all 0.3s;
-  img {
-    display: inline-block;
-    height: 32px;
-    vertical-align: middle;
-  }
-  h1 {
-    display: inline-block;
-    margin: 0 0 0 12px;
-    color: #fff;
-    font-weight: 400;
-    font-size: 16px;
-    vertical-align: top;
-  }
-}
-
-.light {
-  h1 {
-    color: #002140;
-  }
-}
-
-.menu {
-  height: @layout-header-height;
-  line-height: @layout-header-height;
-  border: none;
-}

+ 0 - 59
src/components/TopNavHeader/index.tsx

@@ -1,59 +0,0 @@
-import { SiderMenuProps } from '@/components/SiderMenu';
-import React, { Component } from 'react';
-import Link from 'umi/link';
-import RightContent, { GlobalHeaderRightProps } from '../GlobalHeader/RightContent';
-import BaseMenu from '../SiderMenu/BaseMenu';
-import { getFlatMenuKeys } from '../SiderMenu/SiderMenuUtils';
-import styles from './index.less';
-import defaultSettings, { ContentWidth } from '../../../config/defaultSettings';
-
-export interface TopNavHeaderProps extends SiderMenuProps, GlobalHeaderRightProps {
-  contentWidth?: ContentWidth;
-}
-
-interface TopNavHeaderState {
-  maxWidth?: number;
-}
-
-export default class TopNavHeader extends Component<TopNavHeaderProps, TopNavHeaderState> {
-  static getDerivedStateFromProps(props: TopNavHeaderProps) {
-    return {
-      maxWidth:
-        (props.contentWidth === 'Fixed' && window.innerWidth > 1200 ? 1200 : window.innerWidth) -
-        280 -
-        120 -
-        40,
-    };
-  }
-
-  state: TopNavHeaderState = {};
-
-  maim: HTMLDivElement | null = null;
-
-  render() {
-    const { theme, contentWidth, menuData, logo } = this.props;
-    const { maxWidth } = this.state;
-    const flatMenuKeys = getFlatMenuKeys(menuData);
-    return (
-      <div className={`${styles.head} ${theme === 'light' ? styles.light : ''}`}>
-        <div
-          ref={ref => (this.maim = ref)}
-          className={`${styles.main} ${contentWidth === 'Fixed' ? styles.wide : ''}`}
-        >
-          <div className={styles.left}>
-            <div className={styles.logo} key="logo" id="logo">
-              <Link to="/">
-                <img src={logo} alt="logo" />
-                <h1>{defaultSettings.title}</h1>
-              </Link>
-            </div>
-            <div style={{ maxWidth }}>
-              <BaseMenu {...this.props} flatMenuKeys={flatMenuKeys} className={styles.menu} />
-            </div>
-          </div>
-          <RightContent {...this.props} />
-        </div>
-      </div>
-    );
-  }
-}

+ 0 - 6
src/layouts/BasicLayout.less

@@ -1,6 +0,0 @@
-@import '~antd/lib/style/themes/default.less';
-
-.content {
-  margin: 24px;
-  padding-top: @layout-header-height;
-}

+ 30 - 112
src/layouts/BasicLayout.tsx

@@ -1,55 +1,19 @@
-import SiderMenu, { MenuDataItem, SiderMenuProps } from '@/components/SiderMenu';
-import { ConnectProps, ConnectState, SettingModelState } from '@/models/connect';
-import getPageTitle from '@/utils/getPageTitle';
-import { Layout } from 'antd';
-import classNames from 'classnames';
+import { ConnectState, ConnectProps } from '@/models/connect';
+import { formatMessage } from 'umi-plugin-react/locale';
 import { connect } from 'dva';
-import React, { Suspense, useState } from 'react';
-import { ContainerQuery } from 'react-container-query';
-import DocumentTitle from 'react-document-title';
-import useMedia from 'react-media-hook2';
+import React, { useState } from 'react';
 import logo from '../assets/logo.svg';
-import styles from './BasicLayout.less';
-import Footer from './Footer';
-import Header, { HeaderViewProps } from './Header';
-import PageHeaderWrapper from '@/components/PageHeaderWrapper';
 
-// lazy load SettingDrawer
-const SettingDrawer = React.lazy(() => import('@/components/SettingDrawer'));
+import {
+  BasicLayout as BasicLayoutComponents,
+  BasicLayoutProps as BasicLayoutComponentsProps,
+  MenuDataItem,
+  Settings,
+} from '@ant-design/pro-layout';
 
-const { Content } = Layout;
-
-const query = {
-  'screen-xs': {
-    maxWidth: 575,
-  },
-  'screen-sm': {
-    minWidth: 576,
-    maxWidth: 767,
-  },
-  'screen-md': {
-    minWidth: 768,
-    maxWidth: 991,
-  },
-  'screen-lg': {
-    minWidth: 992,
-    maxWidth: 1199,
-  },
-  'screen-xl': {
-    minWidth: 1200,
-    maxWidth: 1599,
-  },
-  'screen-xxl': {
-    minWidth: 1600,
-  },
-};
-
-export interface BasicLayoutProps
-  extends ConnectProps,
-    SiderMenuProps,
-    HeaderViewProps,
-    Partial<SettingModelState> {
+export interface BasicLayoutProps extends BasicLayoutComponentsProps, ConnectProps {
   breadcrumbNameMap: { [path: string]: MenuDataItem };
+  settings: Settings;
 }
 
 export type BasicLayoutContext = { [K in 'location']: BasicLayoutProps[K] } & {
@@ -57,89 +21,43 @@ export type BasicLayoutContext = { [K in 'location']: BasicLayoutProps[K] } & {
 };
 
 const BasicLayout: React.FC<BasicLayoutProps> = props => {
-  const {
-    breadcrumbNameMap,
-    dispatch,
-    children,
-    collapsed,
-    fixedHeader,
-    fixSiderbar,
-    layout: PropsLayout,
-    location,
-    menuData,
-    navTheme,
-    route,
-  } = props;
+  const { dispatch, children, route } = props;
   const { routes, authority } = route!;
   /**
    * constructor
    */
   useState(() => {
     dispatch!({ type: 'user/fetchCurrent' });
-    dispatch!({ type: 'setting/getSetting' });
+    dispatch!({ type: 'settings/getSetting' });
     dispatch!({ type: 'menu/getMenuData', payload: { routes, authority } });
   });
   /**
    * init variables
    */
-  const isMobile = useMedia({ id: 'BasicLayout', query: '(max-width: 599px)' })[0];
-  const hasLeftPadding = fixSiderbar && PropsLayout !== 'topmenu' && !isMobile;
   const handleMenuCollapse = (payload: boolean) =>
     dispatch!({ type: 'global/changeLayoutCollapsed', payload });
-  // Do not render SettingDrawer in production
-  // unless it is deployed in preview.pro.ant.design as demo
-  const renderSettingDrawer = () =>
-    !(process.env.NODE_ENV === 'production' && APP_TYPE !== 'site') && <SettingDrawer />;
-  const layout = (
-    <Layout>
-      {PropsLayout === 'topmenu' && !isMobile ? null : (
-        <SiderMenu
-          logo={logo}
-          theme={navTheme}
-          onCollapse={handleMenuCollapse}
-          menuData={menuData}
-          isMobile={isMobile}
-          {...props}
-        />
-      )}
-      <Layout
-        style={{
-          paddingLeft: hasLeftPadding ? (collapsed ? 80 : 256) : void 0,
-          minHeight: '100vh',
-        }}
-      >
-        <Header
-          menuData={menuData}
-          handleMenuCollapse={handleMenuCollapse}
-          logo={logo}
-          isMobile={isMobile}
-          {...props}
-        />
-        <Content className={styles.content} style={!fixedHeader ? { paddingTop: 0 } : {}}>
-          <PageHeaderWrapper location={location} breadcrumbNameMap={breadcrumbNameMap}>
-            {children}
-          </PageHeaderWrapper>
-        </Content>
-        <Footer />
-      </Layout>
-    </Layout>
-  );
+
   return (
-    <React.Fragment>
-      <DocumentTitle title={getPageTitle(location!.pathname, breadcrumbNameMap)}>
-        <ContainerQuery query={query}>
-          {params => <div className={classNames(params)}>{layout}</div>}
-        </ContainerQuery>
-      </DocumentTitle>
-      <Suspense fallback={null}>{renderSettingDrawer()}</Suspense>
-    </React.Fragment>
+    <BasicLayoutComponents
+      formatMessage={formatMessage}
+      logo={logo}
+      onChangeSetting={settings =>
+        dispatch!({
+          type: 'settings/changeSetting',
+          payload: settings,
+        })
+      }
+      onChangeLayoutCollapsed={handleMenuCollapse}
+      {...props}
+    >
+      {children}
+    </BasicLayoutComponents>
   );
 };
 
-export default connect(({ global, setting, menu: menuModel }: ConnectState) => ({
+export default connect(({ global, settings, menu: menuModel }: ConnectState) => ({
   collapsed: global.collapsed,
-  layout: setting.layout,
+  settings,
   menuData: menuModel.menuData,
   breadcrumbNameMap: menuModel.breadcrumbNameMap,
-  ...setting,
 }))(BasicLayout);

+ 0 - 37
src/layouts/Footer.tsx

@@ -1,37 +0,0 @@
-import { Icon, Layout } from 'antd';
-import React, { Fragment } from 'react';
-import { GlobalFooter } from 'ant-design-pro';
-
-const { Footer } = Layout;
-const FooterView = () => (
-  <Footer style={{ padding: 0 }}>
-    <GlobalFooter
-      links={[
-        {
-          key: 'Pro 首页',
-          title: 'Pro 首页',
-          href: 'https://pro.ant.design',
-          blankTarget: true,
-        },
-        {
-          key: 'github',
-          title: <Icon type="github" />,
-          href: 'https://github.com/ant-design/ant-design-pro',
-          blankTarget: true,
-        },
-        {
-          key: 'Ant Design',
-          title: 'Ant Design',
-          href: 'https://ant.design',
-          blankTarget: true,
-        },
-      ]}
-      copyright={
-        <Fragment>
-          Copyright <Icon type="copyright" /> 2019 蚂蚁金服体验技术部出品
-        </Fragment>
-      }
-    />
-  </Footer>
-);
-export default FooterView;

+ 0 - 8
src/layouts/Header.less

@@ -1,8 +0,0 @@
-.fixedHeader {
-  position: fixed;
-  top: 0;
-  right: 0;
-  z-index: 9;
-  width: 100%;
-  transition: width 0.2s;
-}

+ 0 - 179
src/layouts/Header.tsx

@@ -1,179 +0,0 @@
-import GlobalHeader, { GlobalHeaderProps } from '@/components/GlobalHeader';
-import TopNavHeader, { TopNavHeaderProps } from '@/components/TopNavHeader';
-import { ConnectProps, ConnectState, SettingModelState } from '@/models/connect';
-import React, { Component } from 'react';
-import { formatMessage } from 'umi-plugin-react/locale';
-import { Layout, message } from 'antd';
-import { ClickParam } from 'antd/es/menu';
-import { connect } from 'dva';
-import Animate from 'rc-animate';
-import router from 'umi/router';
-import styles from './Header.less';
-
-const { Header } = Layout;
-
-export interface HeaderViewProps extends ConnectProps, TopNavHeaderProps, GlobalHeaderProps {
-  isMobile?: boolean;
-  collapsed?: boolean;
-  setting?: SettingModelState;
-  autoHideHeader?: boolean;
-  handleMenuCollapse?: (collapse: boolean) => void;
-}
-
-interface HeaderViewState {
-  visible: boolean;
-}
-
-class HeaderView extends Component<HeaderViewProps, HeaderViewState> {
-  static getDerivedStateFromProps(props: HeaderViewProps, state: HeaderViewState) {
-    if (!props.autoHideHeader && !state.visible) {
-      return {
-        visible: true,
-      };
-    }
-    return null;
-  }
-  state = {
-    visible: true,
-  };
-
-  ticking: boolean = false;
-  oldScrollTop: number = 0;
-
-  componentDidMount() {
-    document.addEventListener('scroll', this.handScroll, { passive: true });
-  }
-
-  componentWillUnmount() {
-    document.removeEventListener('scroll', this.handScroll);
-  }
-
-  getHeadWidth = () => {
-    const { isMobile, collapsed, setting } = this.props;
-    const { fixedHeader, layout } = setting!;
-    if (isMobile || !fixedHeader || layout === 'topmenu') {
-      return '100%';
-    }
-    return collapsed ? 'calc(100% - 80px)' : 'calc(100% - 256px)';
-  };
-
-  handleNoticeClear = (type: string) => {
-    const { dispatch } = this.props;
-    message.success(
-      `${formatMessage({ id: 'component.noticeIcon.cleared' })} ${formatMessage({
-        id: `component.globalHeader.${type}`,
-      })}`,
-    );
-    dispatch!({
-      type: 'global/clearNotices',
-      payload: type,
-    });
-  };
-
-  handleMenuClick = ({ key }: ClickParam) => {
-    const { dispatch } = this.props;
-    if (key === 'userCenter') {
-      router.push('/account/center');
-      return;
-    }
-    if (key === 'triggerError') {
-      router.push('/exception/trigger');
-      return;
-    }
-    if (key === 'userinfo') {
-      router.push('/account/settings/base');
-      return;
-    }
-    if (key === 'logout') {
-      dispatch!({
-        type: 'login/logout',
-      });
-    }
-  };
-
-  handleNoticeVisibleChange = (visible: boolean) => {
-    if (visible) {
-      const { dispatch } = this.props;
-      dispatch!({
-        type: 'global/fetchNotices',
-      });
-    }
-  };
-
-  handScroll = () => {
-    const { autoHideHeader } = this.props;
-    const { visible } = this.state;
-    if (!autoHideHeader) {
-      return;
-    }
-    const scrollTop = document.body.scrollTop + document.documentElement.scrollTop;
-    if (!this.ticking) {
-      this.ticking = true;
-      requestAnimationFrame(() => {
-        if (this.oldScrollTop > scrollTop) {
-          this.setState({
-            visible: true,
-          });
-        } else if (scrollTop > 300 && visible) {
-          this.setState({
-            visible: false,
-          });
-        } else if (scrollTop < 300 && !visible) {
-          this.setState({
-            visible: true,
-          });
-        }
-        this.oldScrollTop = scrollTop;
-        this.ticking = false;
-      });
-    }
-  };
-
-  render() {
-    const { isMobile, handleMenuCollapse, setting } = this.props;
-    const { navTheme, layout, fixedHeader } = setting!;
-    const { visible } = this.state;
-    const isTop = layout === 'topmenu';
-    const width = this.getHeadWidth();
-    const HeaderDom = visible ? (
-      <Header
-        style={{ padding: 0, width, zIndex: 2 }}
-        className={fixedHeader ? styles.fixedHeader : ''}
-      >
-        {isTop && !isMobile ? (
-          <TopNavHeader
-            theme={navTheme}
-            mode="horizontal"
-            onCollapse={handleMenuCollapse}
-            onNoticeClear={this.handleNoticeClear}
-            onMenuClick={this.handleMenuClick}
-            onNoticeVisibleChange={this.handleNoticeVisibleChange}
-            {...this.props}
-          />
-        ) : (
-          <GlobalHeader
-            onCollapse={handleMenuCollapse}
-            onNoticeClear={this.handleNoticeClear}
-            onMenuClick={this.handleMenuClick}
-            onNoticeVisibleChange={this.handleNoticeVisibleChange}
-            {...this.props}
-          />
-        )}
-      </Header>
-    ) : null;
-    return (
-      <Animate component="" transitionName="fade">
-        {HeaderDom}
-      </Animate>
-    );
-  }
-}
-
-export default connect(({ user, global, setting, loading }: ConnectState) => ({
-  currentUser: user.currentUser,
-  collapsed: global.collapsed,
-  fetchingMoreNotices: loading.effects['global/fetchMoreNotices'],
-  fetchingNotices: loading.effects['global/fetchNotices'],
-  notices: global.notices,
-  setting,
-}))(HeaderView);

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

@@ -1,4 +1,3 @@
-import { Route } from '@/components/SiderMenu';
 import { EffectsCommandMap } from 'dva';
 import { AnyAction } from 'redux';
 import { RouterTypes } from 'umi';
@@ -6,7 +5,7 @@ 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 type Effect = (
@@ -39,11 +38,15 @@ export interface Loading {
 export interface ConnectState {
   global: GlobalModelState;
   loading: Loading;
+  settings: SettingModelState;
   menu: MenuModelState;
-  setting: SettingModelState;
   user: UserModelState;
 }
 
+export interface Route extends MenuDataItem {
+  routes?: Route[];
+}
+
 /**
  * @type T: Params matched in dynamic routing
  */

+ 2 - 2
src/models/setting.ts

@@ -3,7 +3,7 @@ import { Reducer } from 'redux';
 import defaultSettings, { DefaultSettings } from '../../config/defaultSettings';
 
 export interface SettingModelType {
-  namespace: 'setting';
+  namespace: 'settings';
   state: DefaultSettings;
   reducers: {
     getSetting: Reducer<any>;
@@ -75,7 +75,7 @@ const updateColorWeak: (colorWeak: string) => void = colorWeak => {
 };
 
 const SettingModel: SettingModelType = {
-  namespace: 'setting',
+  namespace: 'settings',
   state: defaultSettings,
   reducers: {
     getSetting(state) {