提交 1c8dabcf 编写于 作者: 陈帅

change pageHeader

上级 c82c4532
import React from 'react';
import { connect } from 'dva';
import styles from './GridContent.less';
import ConnectState from '@/models/connect';
import { ContentWidth } from 'config/defaultSettings';
const GridContent = props => {
interface GridContentProps {
contentWidth: ContentWidth;
children: React.ReactNode;
}
const GridContent = (props: GridContentProps) => {
const { contentWidth, children } = props;
let className = `${styles.main}`;
if (contentWidth === 'Fixed') {
......@@ -11,6 +18,6 @@ const GridContent = props => {
return <div className={className}>{children}</div>;
};
export default connect(({ setting }) => ({
export default connect(({ setting }: ConnectState) => ({
contentWidth: setting.contentWidth,
}))(GridContent);
......@@ -3,10 +3,15 @@ import pathToRegexp from 'path-to-regexp';
import Link from 'umi/link';
import { FormattedMessage } from 'umi-plugin-react/locale';
import { urlToList } from '../_utils/pathTools';
import { PageHeaderWrapperProps } from './';
import { MenuDataItem } from '../SiderMenu';
import { BreadcrumbProps as AntdBreadcrumbProps } from 'antd/lib/breadcrumb';
type BreadcrumbProps = PageHeaderWrapperProps;
// 渲染Breadcrumb 子节点
// Render the Breadcrumb child node
const itemRender = (route, params, routes, paths) => {
const itemRender: AntdBreadcrumbProps['itemRender'] = (route, params, routes, paths) => {
const last = routes.indexOf(route) === routes.length - 1;
return last || !route.component ? (
<span>{route.breadcrumbName}</span>
......@@ -15,14 +20,22 @@ const itemRender = (route, params, routes, paths) => {
);
};
const renderItemLocal = item => {
const renderItemLocal = (item: MenuDataItem): React.ReactNode => {
if (item.locale) {
return <FormattedMessage id={item.locale} defaultMessage={item.name} />;
}
return item.name;
};
export const getBreadcrumb = (breadcrumbNameMap, url) => {
export const getBreadcrumb = (
breadcrumbNameMap: PageHeaderWrapperProps['breadcrumbNameMap'],
url: string,
): MenuDataItem => {
if (!breadcrumbNameMap) {
return {
path: '',
};
}
let breadcrumb = breadcrumbNameMap[url];
if (!breadcrumb) {
Object.keys(breadcrumbNameMap).forEach(item => {
......@@ -31,50 +44,59 @@ export const getBreadcrumb = (breadcrumbNameMap, url) => {
}
});
}
return breadcrumb || {};
return breadcrumb || { path: '' };
};
export const getBreadcrumbProps = props => {
const { routes, params, location, breadcrumbNameMap } = props;
export const getBreadcrumbProps = (props: BreadcrumbProps): PageHeaderWrapperProps => {
const { location, breadcrumbNameMap } = props;
return {
routes,
params,
routerLocation: location,
location,
breadcrumbNameMap,
};
};
// Generated according to props
const conversionFromProps = props => {
const { breadcrumbList } = props;
return breadcrumbList.map(item => {
const { title, href } = item;
return {
path: href,
breadcrumbName: title,
};
});
const conversionFromProps = (props: BreadcrumbProps): AntdBreadcrumbProps['routes'] => {
const { breadcrumbList = [] } = props;
return breadcrumbList
.map(item => {
const { title, href } = item;
return {
path: href,
breadcrumbName: title,
};
})
.filter(item => item.path);
};
const conversionFromLocation = (routerLocation, breadcrumbNameMap, props) => {
const conversionFromLocation = (
routerLocation: PageHeaderWrapperProps['location'],
breadcrumbNameMap: PageHeaderWrapperProps['breadcrumbNameMap'],
props: BreadcrumbProps,
): AntdBreadcrumbProps['routes'] => {
if (!routerLocation) {
return [];
}
const { home } = props;
// Convert the url to an array
const pathSnippets = urlToList(routerLocation.pathname);
// Loop data mosaic routing
const extraBreadcrumbItems = pathSnippets.map(url => {
const currentBreadcrumb = getBreadcrumb(breadcrumbNameMap, url);
if (currentBreadcrumb.inherited) {
return null;
}
const name = renderItemLocal(currentBreadcrumb);
const { hideInBreadcrumb } = currentBreadcrumb;
return name && !hideInBreadcrumb
? {
path: url,
breadcrumbName: name,
}
: null;
});
const extraBreadcrumbItems: AntdBreadcrumbProps['routes'] = pathSnippets
.map(url => {
const currentBreadcrumb = getBreadcrumb(breadcrumbNameMap, url);
if (currentBreadcrumb.inherited) {
return { path: '', breadcrumbName: '' };
}
const name = renderItemLocal(currentBreadcrumb);
const { hideInBreadcrumb } = currentBreadcrumb;
return name && !hideInBreadcrumb
? {
path: url,
breadcrumbName: name,
}
: { path: '', breadcrumbName: '' };
})
.filter(item => item && item.path);
// Add home breadcrumbs to your head if defined
if (home) {
extraBreadcrumbItems.unshift({
......@@ -89,28 +111,25 @@ const conversionFromLocation = (routerLocation, breadcrumbNameMap, props) => {
* 将参数转化为面包屑
* Convert parameters into breadcrumbs
*/
export const conversionBreadcrumbList = props => {
export const conversionBreadcrumbList = (props: BreadcrumbProps): AntdBreadcrumbProps => {
const { breadcrumbList } = props;
const { routes, params, routerLocation, breadcrumbNameMap } = getBreadcrumbProps(props);
const { location, breadcrumbNameMap } = getBreadcrumbProps(props);
if (breadcrumbList && breadcrumbList.length) {
return conversionFromProps();
}
// 如果传入 routes 和 params 属性
// If pass routes and params attributes
if (routes && params) {
return {
routes: routes.filter(route => route.breadcrumbName),
params,
routes: conversionFromProps(props),
itemRender,
};
}
// 根据 location 生成 面包屑
// Generate breadcrumbs based on location
if (routerLocation && routerLocation.pathname) {
if (location && location.pathname) {
return {
routes: conversionFromLocation(routerLocation, breadcrumbNameMap, props),
routes: conversionFromLocation(location, breadcrumbNameMap, props),
itemRender,
};
}
return {};
return {
routes: [],
};
};
import React from 'react';
import { FormattedMessage } from 'umi-plugin-react/locale';
import Link from 'umi/link';
import { PageHeader, Tabs, Typography } from 'antd';
import { connect } from 'dva';
import classNames from 'classnames';
import GridContent from './GridContent';
import styles from './index.less';
import MenuContext from '@/layouts/MenuContext';
import { conversionBreadcrumbList } from './breadcrumb';
const { Title } = Typography;
/**
* render Footer tabList
* In order to be compatible with the old version of the PageHeader
* basically all the functions are implemented.
*/
const renderFooter = ({ tabList, activeKeyProps, onTabChange, tabBarExtraContent }) => {
return tabList && tabList.length ? (
<Tabs
className={styles.tabs}
{...activeKeyProps}
onChange={key => {
if (onTabChange) {
onTabChange(key);
}
}}
tabBarExtraContent={tabBarExtraContent}
>
{tabList.map(item => (
<Tabs.TabPane tab={item.tab} key={item.key} />
))}
</Tabs>
) : null;
};
const PageHeaderWrapper = ({
children,
contentWidth,
wrapperClassName,
top,
title,
content,
logo,
extraContent,
...restProps
}) => {
return (
<div style={{ margin: '-24px -24px 0' }} className={classNames(classNames, styles.main)}>
{top}
{title && content && (
<MenuContext.Consumer>
{value => {
return (
<PageHeader
wide={contentWidth === 'Fixed'}
title={
<Title
level={4}
style={{
marginBottom: 0,
}}
>
{title}
</Title>
}
key="pageheader"
{...restProps}
breadcrumb={conversionBreadcrumbList({
...value,
...restProps,
home: <FormattedMessage id="menu.home" defaultMessage="Home" />,
})}
className={styles.pageHeader}
linkElement={Link}
footer={renderFooter(restProps)}
>
<div className={styles.detail}>
{logo && <div className={styles.logo}>{logo}</div>}
<div className={styles.main}>
<div className={styles.row}>
{content && <div className={styles.content}>{content}</div>}
{extraContent && <div className={styles.extraContent}>{extraContent}</div>}
</div>
</div>
</div>
</PageHeader>
);
}}
</MenuContext.Consumer>
)}
{children ? (
<div className={styles['children-content']}>
<GridContent>{children}</GridContent>
</div>
) : null}
</div>
);
};
export default connect(({ setting }) => ({
contentWidth: setting.contentWidth,
}))(PageHeaderWrapper);
import React from 'react';
import { FormattedMessage } from 'umi-plugin-react/locale';
import { PageHeader, Tabs, Typography } from 'antd';
import { connect } from 'dva';
import classNames from 'classnames';
import GridContent from './GridContent';
import ConnectState from '@/models/connect';
import { ContentWidth } from 'config/defaultSettings';
import styles from './index.less';
import { conversionBreadcrumbList } from './breadcrumb';
import { MenuDataItem } from '../SiderMenu';
import * as H from 'history';
const { Title } = Typography;
/**
* render Footer tabList
* In order to be compatible with the old version of the PageHeader
* basically all the functions are implemented.
*/
const renderFooter = ({
tabList,
onTabChange,
tabBarExtraContent,
}: Partial<PageHeaderWrapperProps>) => {
return tabList && tabList.length ? (
<Tabs
className={styles.tabs}
onChange={key => {
if (onTabChange) {
onTabChange(key);
}
}}
tabBarExtraContent={tabBarExtraContent}
>
{tabList.map(item => (
<Tabs.TabPane tab={item.tab} key={item.key} />
))}
</Tabs>
) : null;
};
export interface PageHeaderWrapperProps {
title?: React.ReactNode | string | number;
logo?: React.ReactNode | string;
action?: React.ReactNode | string;
content?: React.ReactNode;
extraContent?: React.ReactNode;
breadcrumbList?: Array<{ title: string | number; href: string }>;
tabList?: Array<{ key: string; tab: React.ReactNode }>;
tabActiveKey?: string;
onTabChange?: (key: string) => void;
tabBarExtraContent?: React.ReactNode;
style?: React.CSSProperties;
home?: React.ReactNode;
wide?: boolean;
contentWidth?: ContentWidth;
className?: string;
children?: React.ReactNode;
wrapperClassName?: string;
top?: React.ReactNode;
location?: H.Location;
breadcrumbNameMap?: { [path: string]: MenuDataItem };
}
class PageHeaderWrapper extends React.Component<PageHeaderWrapperProps> {
mergePropsAndChildren = (): PageHeaderWrapperProps => {
return {
...this.props,
};
};
renderPageHeader = () => {
const {
children,
contentWidth,
wrapperClassName,
top,
title,
content,
logo,
extraContent,
...restProps
} = this.mergePropsAndChildren();
if (!title && !content) {
return;
}
return (
<PageHeader
title={
<Title
level={4}
style={{
marginBottom: 0,
}}
>
{title}
</Title>
}
{...restProps}
breadcrumb={conversionBreadcrumbList({
...restProps,
home: <FormattedMessage id="menu.home" defaultMessage="Home" />,
})}
className={styles.pageHeader}
footer={renderFooter(restProps)}
>
<div className={styles.detail}>
{logo && <div className={styles.logo}>{logo}</div>}
<div className={styles.main}>
<div className={styles.row}>
{content && <div className={styles.content}>{content}</div>}
{extraContent && <div className={styles.extraContent}>{extraContent}</div>}
</div>
</div>
</div>
</PageHeader>
);
};
render() {
const { children, top } = this.mergePropsAndChildren();
return (
<div style={{ margin: '-24px -24px 0' }} className={classNames(classNames, styles.main)}>
{top}
{this.renderPageHeader()}
{children ? (
<div className={styles['children-content']}>
<GridContent>{children}</GridContent>
</div>
) : null}
</div>
);
}
}
export default connect(({ setting }: ConnectState) => ({
contentWidth: setting.contentWidth,
}))(PageHeaderWrapper);
......@@ -12,7 +12,7 @@ import logo from '../assets/logo.svg';
import styles from './BasicLayout.less';
import Footer from './Footer';
import Header, { HeaderViewProps } from './Header';
import Context from './MenuContext';
import PageHeaderWrapper from '@/components/PageHeaderWrapper';
// lazy load SettingDrawer
const SettingDrawer = React.lazy(() => import('@/components/SettingDrawer'));
......@@ -90,7 +90,6 @@ const BasicLayout: React.FC<BasicLayoutProps> = props => {
// 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 : (
......@@ -117,7 +116,9 @@ const BasicLayout: React.FC<BasicLayoutProps> = props => {
{...props}
/>
<Content className={styles.content} style={!fixedHeader ? { paddingTop: 0 } : {}}>
{children}
<PageHeaderWrapper location={location} breadcrumbNameMap={breadcrumbNameMap}>
{children}
</PageHeaderWrapper>
</Content>
<Footer />
</Layout>
......@@ -127,11 +128,7 @@ const BasicLayout: React.FC<BasicLayoutProps> = props => {
<React.Fragment>
<DocumentTitle title={getPageTitle(location!.pathname, breadcrumbNameMap)}>
<ContainerQuery query={query}>
{params => (
<Context.Provider value={{ location, breadcrumbNameMap }}>
<div className={classNames(params)}>{layout}</div>
</Context.Provider>
)}
{params => <div className={classNames(params)}>{layout}</div>}
</ContainerQuery>
</DocumentTitle>
<Suspense fallback={null}>{renderSettingDrawer()}</Suspense>
......
import { createContext } from 'react';
export default createContext({});
import React from 'react';
export default () => (
const Welcome = () => (
<p style={{ textAlign: 'center' }}>
想要添加更多页面?请参考{' '}
<a href="https://umijs.org/guide/block.html" target="_blank" rel="noopener noreferrer">
......@@ -9,3 +9,5 @@ export default () => (
</p>
);
Welcome.title = '欢迎使用';
export default Welcome;
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册