12-23-上传master
This commit is contained in:
173
src/layouts/BasicLayout.tsx
Normal file
173
src/layouts/BasicLayout.tsx
Normal file
@ -0,0 +1,173 @@
|
||||
import ProLayout, {
|
||||
MenuDataItem,
|
||||
BasicLayoutProps as ProLayoutProps,
|
||||
Settings,
|
||||
DefaultFooter,
|
||||
} from '@ant-design/pro-layout';
|
||||
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 { getMatchMenu } from '@umijs/route-utils';
|
||||
import logo from '../assets/logo.svg';
|
||||
|
||||
const noMatch = (
|
||||
<Result
|
||||
status={403}
|
||||
title="403"
|
||||
subTitle="Sorry, you are not authorized to access this page."
|
||||
extra={
|
||||
<Button type="primary">
|
||||
<Link to="/user/login">Go Login</Link>
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
);
|
||||
export interface BasicLayoutProps extends ProLayoutProps {
|
||||
breadcrumbNameMap: {
|
||||
[path: string]: MenuDataItem;
|
||||
};
|
||||
route: ProLayoutProps['route'] & {
|
||||
authority: string[];
|
||||
};
|
||||
settings: Settings;
|
||||
dispatch: Dispatch;
|
||||
}
|
||||
export type BasicLayoutContext = { [K in 'location']: BasicLayoutProps[K] } & {
|
||||
breadcrumbNameMap: {
|
||||
[path: string]: MenuDataItem;
|
||||
};
|
||||
};
|
||||
/**
|
||||
* use Authorized check all menu item
|
||||
*/
|
||||
|
||||
const menuDataRender = (menuList: MenuDataItem[]): MenuDataItem[] =>
|
||||
menuList.map((item) => {
|
||||
const localItem = {
|
||||
...item,
|
||||
children: item.children ? menuDataRender(item.children) : undefined,
|
||||
};
|
||||
return Authorized.check(item.authority, localItem, null) as MenuDataItem;
|
||||
});
|
||||
|
||||
const defaultFooterDom = (
|
||||
<DefaultFooter
|
||||
copyright={`${new Date().getFullYear()} 蚂蚁集团体验技术部出品`}
|
||||
links={[
|
||||
{
|
||||
key: 'Ant Design Pro',
|
||||
title: 'Ant Design Pro',
|
||||
href: 'https://pro.ant.design',
|
||||
blankTarget: true,
|
||||
},
|
||||
{
|
||||
key: 'github',
|
||||
title: <GithubOutlined />,
|
||||
href: 'https://github.com/ant-design/ant-design-pro',
|
||||
blankTarget: true,
|
||||
},
|
||||
{
|
||||
key: 'Ant Design',
|
||||
title: 'Ant Design',
|
||||
href: 'https://ant.design',
|
||||
blankTarget: true,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
);
|
||||
|
||||
const BasicLayout: React.FC<BasicLayoutProps> = (props) => {
|
||||
const {
|
||||
dispatch,
|
||||
children,
|
||||
settings,
|
||||
location = {
|
||||
pathname: '/',
|
||||
},
|
||||
} = props;
|
||||
|
||||
const menuDataRef = useRef<MenuDataItem[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (dispatch) {
|
||||
dispatch({
|
||||
type: 'user/fetchCurrent',
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
/**
|
||||
* init variables
|
||||
*/
|
||||
|
||||
const handleMenuCollapse = (payload: boolean): void => {
|
||||
if (dispatch) {
|
||||
dispatch({
|
||||
type: 'global/changeLayoutCollapsed',
|
||||
payload,
|
||||
});
|
||||
}
|
||||
};
|
||||
// get children authority
|
||||
const authorized = useMemo(
|
||||
() =>
|
||||
getMatchMenu(location.pathname || '/', menuDataRef.current).pop() || {
|
||||
authority: undefined,
|
||||
},
|
||||
[location.pathname],
|
||||
);
|
||||
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
return (
|
||||
<ProLayout
|
||||
logo={logo}
|
||||
formatMessage={formatMessage}
|
||||
onCollapse={handleMenuCollapse}
|
||||
onMenuHeaderClick={() => history.push('/')}
|
||||
menuItemRender={(menuItemProps, defaultDom) => {
|
||||
if (menuItemProps.isUrl || !menuItemProps.path) {
|
||||
return defaultDom;
|
||||
}
|
||||
return <Link to={menuItemProps.path}>{defaultDom}</Link>;
|
||||
}}
|
||||
breadcrumbRender={(routers = []) => [
|
||||
{
|
||||
path: '/',
|
||||
breadcrumbName: formatMessage({ id: 'menu.home' }),
|
||||
},
|
||||
...routers,
|
||||
]}
|
||||
itemRender={(route, params, routes, paths) => {
|
||||
const first = routes.indexOf(route) === 0;
|
||||
return first ? (
|
||||
<Link to={paths.join('/')}>{route.breadcrumbName}</Link>
|
||||
) : (
|
||||
<span>{route.breadcrumbName}</span>
|
||||
);
|
||||
}}
|
||||
footerRender={() => defaultFooterDom}
|
||||
menuDataRender={menuDataRender}
|
||||
rightContentRender={() => <RightContent />}
|
||||
postMenuData={(menuData) => {
|
||||
menuDataRef.current = menuData || [];
|
||||
return menuData || [];
|
||||
}}
|
||||
{...props}
|
||||
{...settings}
|
||||
>
|
||||
<Authorized authority={authorized!.authority} noMatch={noMatch}>
|
||||
{children}
|
||||
|
||||
</Authorized>
|
||||
</ProLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default connect(({ global, settings }: ConnectState) => ({
|
||||
collapsed: global.collapsed,
|
||||
settings,
|
||||
}))(BasicLayout);
|
5
src/layouts/BlankLayout.tsx
Normal file
5
src/layouts/BlankLayout.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import React from 'react';
|
||||
|
||||
const Layout: React.FC = ({ children }) => <>{children}</>;
|
||||
|
||||
export default Layout;
|
43
src/layouts/RoomLayout.tsx
Normal file
43
src/layouts/RoomLayout.tsx
Normal file
@ -0,0 +1,43 @@
|
||||
import { MenuDataItem, getMenuData, getPageTitle } from '@ant-design/pro-layout';
|
||||
import { useIntl, ConnectProps, connect } from 'umi';
|
||||
import React from 'react';
|
||||
import { ConnectState } from '@/models/connect';
|
||||
import { Layout } from 'antd';
|
||||
|
||||
export interface UserLayoutProps extends Partial<ConnectProps> {
|
||||
// breadcrumbNameMap: {
|
||||
// [path: string]: MenuDataItem;
|
||||
// };
|
||||
}
|
||||
|
||||
const RoomLayout: React.FC<UserLayoutProps> = (props) => {
|
||||
// const {
|
||||
// route = {
|
||||
// routes: [],
|
||||
// },
|
||||
// } = props;
|
||||
// const { routes = [] } = route;
|
||||
const {
|
||||
children,
|
||||
// location = {
|
||||
// pathname: '',
|
||||
// },
|
||||
} = props;
|
||||
// const { formatMessage } = useIntl();
|
||||
// const { breadcrumb } = getMenuData(routes);
|
||||
// const title = getPageTitle({
|
||||
// pathname: location.pathname,
|
||||
// formatMessage,
|
||||
// breadcrumb,
|
||||
// ...props,
|
||||
// });
|
||||
const { Content } = Layout;
|
||||
return (
|
||||
<Layout>
|
||||
<Content>{children}</Content>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
// export default connect(({ settings }: ConnectState) => ({ ...settings }))(RoomLayout);
|
||||
export default RoomLayout;
|
57
src/layouts/SecurityLayout.tsx
Normal file
57
src/layouts/SecurityLayout.tsx
Normal file
@ -0,0 +1,57 @@
|
||||
import React from 'react';
|
||||
import { PageLoading } from '@ant-design/pro-layout';
|
||||
import { Redirect, connect, ConnectProps } from 'umi';
|
||||
import { stringify } from 'querystring';
|
||||
import { ConnectState } from '@/models/connect';
|
||||
import { CurrentUser } from '@/models/user';
|
||||
|
||||
interface SecurityLayoutProps extends ConnectProps {
|
||||
loading?: boolean;
|
||||
currentUser?: CurrentUser;
|
||||
}
|
||||
|
||||
interface SecurityLayoutState {
|
||||
isReady: boolean;
|
||||
}
|
||||
|
||||
class SecurityLayout extends React.Component<SecurityLayoutProps, SecurityLayoutState> {
|
||||
state: SecurityLayoutState = {
|
||||
isReady: false,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.setState({
|
||||
isReady: true,
|
||||
});
|
||||
const { dispatch } = this.props;
|
||||
if (dispatch) {
|
||||
dispatch({
|
||||
type: 'user/fetchCurrent',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { isReady } = this.state;
|
||||
const { children, loading, currentUser } = this.props;
|
||||
// You can replace it to your authentication rule (such as check token exists)
|
||||
// 你可以把它替换成你自己的登录认证规则(比如判断 token 是否存在)
|
||||
const isLogin = currentUser && currentUser.userid;
|
||||
const queryString = stringify({
|
||||
redirect: window.location.href,
|
||||
});
|
||||
|
||||
if ((!isLogin && loading) || !isReady) {
|
||||
return <PageLoading />;
|
||||
}
|
||||
if (!isLogin && window.location.pathname !== '/user/login') {
|
||||
return <Redirect to={`/user/login?${queryString}`} />;
|
||||
}
|
||||
return children;
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(({ user, loading }: ConnectState) => ({
|
||||
currentUser: user.currentUser,
|
||||
loading: loading.models.user,
|
||||
}))(SecurityLayout);
|
71
src/layouts/UserLayout.less
Normal file
71
src/layouts/UserLayout.less
Normal file
@ -0,0 +1,71 @@
|
||||
@import '~antd/es/style/themes/default.less';
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
overflow: auto;
|
||||
background: @layout-body-background;
|
||||
}
|
||||
|
||||
.lang {
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
line-height: 44px;
|
||||
text-align: right;
|
||||
:global(.ant-dropdown-trigger) {
|
||||
margin-right: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: 1;
|
||||
padding: 32px 0;
|
||||
}
|
||||
|
||||
@media (min-width: @screen-md-min) {
|
||||
.container {
|
||||
background-image: url('https://gw.alipayobjects.com/zos/rmsportal/TVYTbAXWheQpRcWDaDMu.svg');
|
||||
background-repeat: no-repeat;
|
||||
background-position: center 110px;
|
||||
background-size: 100%;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 32px 0 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.top {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.header {
|
||||
height: 44px;
|
||||
line-height: 44px;
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
.logo {
|
||||
height: 44px;
|
||||
margin-right: 16px;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.title {
|
||||
position: relative;
|
||||
top: 2px;
|
||||
color: @heading-color;
|
||||
font-weight: 600;
|
||||
font-size: 33px;
|
||||
font-family: Avenir, 'Helvetica Neue', Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
.desc {
|
||||
margin-top: 12px;
|
||||
margin-bottom: 40px;
|
||||
color: @text-color-secondary;
|
||||
font-size: @font-size-base;
|
||||
}
|
65
src/layouts/UserLayout.tsx
Normal file
65
src/layouts/UserLayout.tsx
Normal file
@ -0,0 +1,65 @@
|
||||
import { DefaultFooter, MenuDataItem, getMenuData, getPageTitle } from '@ant-design/pro-layout';
|
||||
import { Helmet, HelmetProvider } from 'react-helmet-async';
|
||||
import { Link, SelectLang, useIntl, ConnectProps, connect } from 'umi';
|
||||
import React from 'react';
|
||||
import { ConnectState } from '@/models/connect';
|
||||
import logo from '../assets/logo.svg';
|
||||
import styles from './UserLayout.less';
|
||||
|
||||
export interface UserLayoutProps extends Partial<ConnectProps> {
|
||||
breadcrumbNameMap: {
|
||||
[path: string]: MenuDataItem;
|
||||
};
|
||||
}
|
||||
|
||||
const UserLayout: React.FC<UserLayoutProps> = (props) => {
|
||||
const {
|
||||
route = {
|
||||
routes: [],
|
||||
},
|
||||
} = props;
|
||||
const { routes = [] } = route;
|
||||
const {
|
||||
children,
|
||||
location = {
|
||||
pathname: '',
|
||||
},
|
||||
} = props;
|
||||
const { formatMessage } = useIntl();
|
||||
const { breadcrumb } = getMenuData(routes);
|
||||
const title = getPageTitle({
|
||||
pathname: location.pathname,
|
||||
formatMessage,
|
||||
breadcrumb,
|
||||
...props,
|
||||
});
|
||||
return (
|
||||
<HelmetProvider>
|
||||
<Helmet>
|
||||
<title>{title}</title>
|
||||
<meta name="description" content={title} />
|
||||
</Helmet>
|
||||
|
||||
<div className={styles.container}>
|
||||
<div className={styles.lang}>
|
||||
<SelectLang />
|
||||
</div>
|
||||
<div className={styles.content}>
|
||||
<div className={styles.top}>
|
||||
<div className={styles.header}>
|
||||
<Link to="/">
|
||||
<img alt="logo" className={styles.logo} src={logo} />
|
||||
<span className={styles.title}>Ant Design</span>
|
||||
</Link>
|
||||
</div>
|
||||
<div className={styles.desc}>Ant Design 是西湖区最具影响力的 Web 设计规范</div>
|
||||
</div>
|
||||
{children}
|
||||
</div>
|
||||
<DefaultFooter />
|
||||
</div>
|
||||
</HelmetProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export default connect(({ settings }: ConnectState) => ({ ...settings }))(UserLayout);
|
Reference in New Issue
Block a user