BasicLayout.tsx 4.78 KB
Newer Older
zombieJ's avatar
zombieJ committed
1 2 3 4 5
/**
 * Ant Design Pro v4 use `@ant-design/pro-layout` to handle Layout.
 * You can view component api by:
 * https://github.com/ant-design/ant-design-pro-layout
 */
duanledexianxianxian's avatar
sync  
duanledexianxianxian committed
6
import { ConnectProps, ConnectState, Dispatch } from '@/models/connect';
7
import ProLayout, {
陈帅's avatar
陈帅 committed
8
  MenuDataItem,
9
  BasicLayoutProps as ProLayoutProps,
陈帅's avatar
陈帅 committed
10
  Settings,
duanledexianxianxian's avatar
duanledexianxianxian committed
11
  SettingDrawer,
陈帅's avatar
陈帅 committed
12
} from '@ant-design/pro-layout';
duanledexianxianxian's avatar
duanledexianxianxian committed
13
import React, { useState, useEffect } from 'react';
陈帅's avatar
陈帅 committed
14
import Authorized from '@/utils/Authorized';
陈帅's avatar
陈帅 committed
15
import Link from 'umi/link';
duanledexianxianxian's avatar
sync  
duanledexianxianxian committed
16 17
import router from 'umi/router';

陈帅's avatar
陈帅 committed
18 19 20 21
import RightContent from '@/components/GlobalHeader/RightContent';
import { connect } from 'dva';
import { formatMessage } from 'umi-plugin-react/locale';
import { isAntDesignPro } from '@/utils/utils';
duanledexianxianxian's avatar
sync  
duanledexianxianxian committed
22 23
import { message } from 'antd';
import store from '@/utils/store';
duanledexianxianxian's avatar
duanledexianxianxian committed
24
import { async } from 'q';
25
export interface BasicLayoutProps extends ProLayoutProps, Omit<ConnectProps, 'location'> {
陈帅's avatar
陈帅 committed
26 27 28
  breadcrumbNameMap: {
    [path: string]: MenuDataItem;
  };
陈帅's avatar
陈帅 committed
29
  settings: Settings;
陈小聪's avatar
陈小聪 committed
30
}
何乐's avatar
何乐 committed
31
export type BasicLayoutContext = { [K in 'location']: BasicLayoutProps[K] } & {
陈帅's avatar
陈帅 committed
32 33 34
  breadcrumbNameMap: {
    [path: string]: MenuDataItem;
  };
何乐's avatar
何乐 committed
35
};
陈帅's avatar
陈帅 committed
36
/**
陈帅's avatar
陈帅 committed
37
 * use Authorized check all menu item
陈帅's avatar
陈帅 committed
38
 */
duanledexianxianxian's avatar
duanledexianxianxian committed
39

陈帅's avatar
陈帅 committed
40 41
const menuDataRender = (menuList: MenuDataItem[]): MenuDataItem[] =>
  menuList.map(item => {
duanledexianxianxian's avatar
duanledexianxianxian committed
42
    // 遍历给所有的children加上了[]
duanledexianxianxian's avatar
duanledexianxianxian committed
43
    const localItem = { ...item, children: item.children ? menuDataRender(item.children) : [] };
duanledexianxianxian's avatar
duanledexianxianxian committed
44
    // 检查菜单项是否有权限
陈帅's avatar
陈帅 committed
45 46 47
    return Authorized.check(item.authority, localItem, null) as MenuDataItem;
  });

duanledexianxianxian's avatar
duanledexianxianxian committed
48
// footer渲染
陈帅's avatar
陈帅 committed
49
const footerRender: BasicLayoutProps['footerRender'] = (_, defaultDom) => {
陈帅's avatar
陈帅 committed
50
  if (!isAntDesignPro()) {
陈帅's avatar
陈帅 committed
51 52
    return defaultDom;
  }
duanledexianxianxian's avatar
duanledexianxianxian committed
53

陈帅's avatar
陈帅 committed
54 55 56 57 58
  return (
    <>
      {defaultDom}
      <div
        style={{
陈帅's avatar
陈帅 committed
59
          padding: '0px 24px 24px',
陈帅's avatar
陈帅 committed
60
          textAlign: 'center',
陈帅's avatar
陈帅 committed
61 62
        }}
      >
陈帅's avatar
陈帅 committed
63
        <a href="https://www.netlify.com" target="_blank" rel="noopener noreferrer">
陈帅's avatar
陈帅 committed
64
          <img
陈帅's avatar
陈帅 committed
65
            src="https://www.netlify.com/img/global/badges/netlify-color-bg.svg"
陈帅's avatar
陈帅 committed
66
            width="82px"
陈帅's avatar
陈帅 committed
67 68 69 70 71 72 73 74
            alt="netlify logo"
          />
        </a>
      </div>
    </>
  );
};

duanledexianxianxian's avatar
sync  
duanledexianxianxian committed
75
const loadInitData = (dispatch: Dispatch) => {
duanledexianxianxian's avatar
duanledexianxianxian committed
76 77 78 79
  return Promise.all([
    dispatch({ type: 'user/getCurrent' }),
    dispatch({ type: 'settings/getSettings' }),
  ]);
duanledexianxianxian's avatar
sync  
duanledexianxianxian committed
80 81
};

何乐's avatar
何乐 committed
82
const BasicLayout: React.FC<BasicLayoutProps> = props => {
陈帅's avatar
陈帅 committed
83
  const { dispatch, children, settings } = props;
何乐's avatar
何乐 committed
84 85 86
  /**
   * constructor
   */
duanledexianxianxian's avatar
sync  
duanledexianxianxian committed
87
  const [loaded, setLoaded] = useState(false);
duanledexianxianxian's avatar
duanledexianxianxian committed
88 89

  useEffect(() => {
陈帅's avatar
陈帅 committed
90
    if (dispatch) {
duanledexianxianxian's avatar
sync  
duanledexianxianxian committed
91
      // 查看当前用户是否在登录状态
陈帅's avatar
陈帅 committed
92
      dispatch({
duanledexianxianxian's avatar
duanledexianxianxian committed
93 94
        type: 'user/checkLoginStatus',
      }).then(async ({ code, data = false }: { code: string; data: boolean }) => {
duanledexianxianxian's avatar
sync  
duanledexianxianxian committed
95 96 97
        if (code === 'sys.success') {
          // 登录成功
          if (data) {
duanledexianxianxian's avatar
duanledexianxianxian committed
98 99
            await loadInitData(dispatch);
            setLoaded(true);
duanledexianxianxian's avatar
sync  
duanledexianxianxian committed
100 101 102 103 104 105 106 107 108 109 110
          } else if (store.get('userId')) {
            store.set('token', '');
            store.set('userId', '');
            message.error('登录已过期,请重新登录!');
            router.push('/user/login');
          } else {
            // 此处应该跳转到404或者403页面为佳
            // message.error("用户未登录,请先登录系统!");
            router.push('/404');
          }
        }
陈帅's avatar
陈帅 committed
111 112
      });
    }
duanledexianxianxian's avatar
duanledexianxianxian committed
113
  }, []);
何乐's avatar
何乐 committed
114 115 116
  /**
   * init variables
   */
duanledexianxianxian's avatar
duanledexianxianxian committed
117

陈帅's avatar
陈帅 committed
118
  const handleMenuCollapse = (payload: boolean): void =>
陈帅's avatar
陈帅 committed
119 120
    dispatch &&
    dispatch({
陈帅's avatar
陈帅 committed
121 122 123 124
      type: 'global/changeLayoutCollapsed',
      payload,
    });

陈小聪's avatar
陈小聪 committed
125
  return (
duanledexianxianxian's avatar
sync  
duanledexianxianxian committed
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
    loaded && (
      <div className="kim-layout">
        <ProLayout
          siderWidth={200}
          logo={false}
          navTheme="dark"
          onCollapse={handleMenuCollapse}
          menuItemRender={(menuItemProps, defaultDom) => (
            <Link to={menuItemProps.path}>{defaultDom}</Link>
          )}
          breadcrumbRender={(routers = []) => [
            {
              path: '/',
              breadcrumbName: formatMessage({
                id: 'menu.home',
                defaultMessage: 'Home',
              }),
            },
            ...routers,
          ]}
          footerRender={false} // 不显示footer
          menuDataRender={menuDataRender} // 渲染导航菜单列表
          formatMessage={formatMessage}
          rightContentRender={rightProps => <RightContent {...rightProps} />}
          {...props}
          {...settings}
        >
          {children}
        </ProLayout>
        {/* 主题设置抽屉 */}
        <SettingDrawer
          settings={settings}
          onSettingChange={config =>
            dispatch({
              type: 'settings/changeSetting',
              payload: config,
            })
          }
        />
      </div>
    )
陈小聪's avatar
陈小聪 committed
167 168 169
  );
};

陈帅's avatar
陈帅 committed
170
export default connect(({ global, settings }: ConnectState) => ({
陈小聪's avatar
陈小聪 committed
171
  collapsed: global.collapsed,
陈帅's avatar
陈帅 committed
172
  settings,
陈小聪's avatar
陈小聪 committed
173
}))(BasicLayout);