未验证 提交 7679507b 编写于 作者: 陈帅 提交者: GitHub

use antd page-header (#3881)

* use antd page-header

* remove page-header

* up ant version

* up antd version

* up antd verison

* use umi-request (#3883)

* use umi-request

* use data repalce to body

* 401 不需要提示请求错误。

* use netlify functions (#3882)

* use netlify functions

* rm .gitignore key

* fix build error

* use new folder

* change config

* add redirects

* add redirects

* add router

* remobe "/"

* remove code

* add tag

* remove babel loader

* rm firebase config

* remove babel

* bugfix: fix#3891 ,dll config error

* add function build

* fix error script

* feat: win add test script (#3845)

* feat: win add test script

* bugfix: fix test error

* use new config

* style: change title size

* style: change title size
上级 b86048b4
import React from 'react';
import { PageHeaderProps } from './index';
export default class BreadcrumbView extends React.Component<PageHeaderProps, any> {}
export function getBreadcrumb(breadcrumbNameMap: object, url: string): object;
import React, { PureComponent, createElement } from 'react';
import pathToRegexp from 'path-to-regexp';
import { Breadcrumb } from 'antd';
import styles from './index.less';
import { urlToList } from '../_utils/pathTools';
export const getBreadcrumb = (breadcrumbNameMap, url) => {
let breadcrumb = breadcrumbNameMap[url];
if (!breadcrumb) {
Object.keys(breadcrumbNameMap).forEach(item => {
if (pathToRegexp(item).test(url)) {
breadcrumb = breadcrumbNameMap[item];
}
});
}
return breadcrumb || {};
};
export default class BreadcrumbView extends PureComponent {
state = {
breadcrumb: null,
};
componentDidMount() {
this.getBreadcrumbDom();
}
componentDidUpdate(preProps) {
const { location } = this.props;
if (!location || !preProps.location) {
return;
}
const prePathname = preProps.location.pathname;
if (prePathname !== location.pathname) {
this.getBreadcrumbDom();
}
}
getBreadcrumbDom = () => {
const breadcrumb = this.conversionBreadcrumbList();
this.setState({
breadcrumb,
});
};
getBreadcrumbProps = () => {
const { routes, params, location, breadcrumbNameMap } = this.props;
return {
routes,
params,
routerLocation: location,
breadcrumbNameMap,
};
};
// Generated according to props
conversionFromProps = () => {
const { breadcrumbList, breadcrumbSeparator, itemRender, linkElement = 'a' } = this.props;
return (
<Breadcrumb className={styles.breadcrumb} separator={breadcrumbSeparator}>
{breadcrumbList.map(item => {
const title = itemRender ? itemRender(item) : item.title;
return (
<Breadcrumb.Item key={item.title}>
{item.href
? createElement(
linkElement,
{
[linkElement === 'a' ? 'href' : 'to']: item.href,
},
title
)
: title}
</Breadcrumb.Item>
);
})}
</Breadcrumb>
);
};
conversionFromLocation = (routerLocation, breadcrumbNameMap) => {
const { breadcrumbSeparator, home, itemRender, linkElement = 'a' } = this.props;
// Convert the url to an array
const pathSnippets = urlToList(routerLocation.pathname);
// Loop data mosaic routing
const extraBreadcrumbItems = pathSnippets.map((url, index) => {
const currentBreadcrumb = getBreadcrumb(breadcrumbNameMap, url);
if (currentBreadcrumb.inherited) {
return null;
}
const isLinkable = index !== pathSnippets.length - 1 && currentBreadcrumb.component;
const name = itemRender ? itemRender(currentBreadcrumb) : currentBreadcrumb.name;
return currentBreadcrumb.name && !currentBreadcrumb.hideInBreadcrumb ? (
<Breadcrumb.Item key={url}>
{createElement(
isLinkable ? linkElement : 'span',
{ [linkElement === 'a' ? 'href' : 'to']: url },
name
)}
</Breadcrumb.Item>
) : null;
});
// Add home breadcrumbs to your head if defined
if (home) {
extraBreadcrumbItems.unshift(
<Breadcrumb.Item key="home">
{createElement(
linkElement,
{
[linkElement === 'a' ? 'href' : 'to']: '/',
},
home
)}
</Breadcrumb.Item>
);
}
return (
<Breadcrumb className={styles.breadcrumb} separator={breadcrumbSeparator}>
{extraBreadcrumbItems}
</Breadcrumb>
);
};
/**
* 将参数转化为面包屑
* Convert parameters into breadcrumbs
*/
conversionBreadcrumbList = () => {
const { breadcrumbList, breadcrumbSeparator } = this.props;
const { routes, params, routerLocation, breadcrumbNameMap } = this.getBreadcrumbProps();
if (breadcrumbList && breadcrumbList.length) {
return this.conversionFromProps();
}
// 如果传入 routes 和 params 属性
// If pass routes and params attributes
if (routes && params) {
return (
<Breadcrumb
className={styles.breadcrumb}
routes={routes.filter(route => route.breadcrumbName)}
params={params}
itemRender={this.itemRender}
separator={breadcrumbSeparator}
/>
);
}
// 根据 location 生成 面包屑
// Generate breadcrumbs based on location
if (routerLocation && routerLocation.pathname) {
return this.conversionFromLocation(routerLocation, breadcrumbNameMap);
}
return null;
};
// 渲染Breadcrumb 子节点
// Render the Breadcrumb child node
itemRender = (route, params, routes, paths) => {
const { linkElement = 'a' } = this.props;
const last = routes.indexOf(route) === routes.length - 1;
return last || !route.component ? (
<span>{route.breadcrumbName}</span>
) : (
createElement(
linkElement,
{
href: paths.join('/') || '/',
to: paths.join('/') || '/',
},
route.breadcrumbName
)
);
};
render() {
const { breadcrumb } = this.state;
return breadcrumb;
}
}
---
order: 2
title: With Image
---
带图片的页头。
````jsx
import PageHeader from 'ant-design-pro/lib/PageHeader';
const content = (
<div>
<p>段落示意:蚂蚁金服务设计平台 ant.design,用最小的工作量,无缝接入蚂蚁金服生态,提供跨越设计与开发的体验解决方案。</p>
<div className="link">
<a>
<img alt="" src="https://gw.alipayobjects.com/zos/rmsportal/MjEImQtenlyueSmVEfUD.svg" /> 快速开始
</a>
<a>
<img alt="" src="https://gw.alipayobjects.com/zos/rmsportal/NbuDUAuBlIApFuDvWiND.svg" /> 产品简介
</a>
<a>
<img alt="" src="https://gw.alipayobjects.com/zos/rmsportal/ohOEPSYdDTNnyMbGuyLb.svg" /> 产品文档
</a>
</div>
</div>
);
const extra = (
<div className="imgContainer">
<img style={{ width: '100%' }} alt="" src="https://gw.alipayobjects.com/zos/rmsportal/RzwpdLnhmvDJToTdfDPe.png" />
</div>
);
const breadcrumbList = [{
title: '一级菜单',
href: '/',
}, {
title: '二级菜单',
href: '/',
}, {
title: '三级菜单',
}];
ReactDOM.render(
<div>
<PageHeader
title="这是一个标题"
content={content}
extraContent={extra}
breadcrumbList={breadcrumbList}
/>
</div>
, mountNode);
````
<style>
#scaffold-src-components-PageHeader-demo-image .code-box-demo {
background: #f2f4f5;
}
#scaffold-src-components-PageHeader-demo-image .imgContainer {
margin-top: -60px;
text-align: center;
width: 195px;
}
#scaffold-src-components-PageHeader-demo-image .link {
margin-top: 16px;
}
#scaffold-src-components-PageHeader-demo-image .link a {
margin-right: 32px;
}
#scaffold-src-components-PageHeader-demo-image .link img {
vertical-align: middle;
margin-right: 8px;
}
</style>
---
order: 3
title: Simple
---
简单的页头。
````jsx
import PageHeader from 'ant-design-pro/lib/PageHeader';
const breadcrumbList = [{
title: '一级菜单',
href: '/',
}, {
title: '二级菜单',
href: '/',
}, {
title: '三级菜单',
}];
ReactDOM.render(
<div>
<PageHeader title="页面标题" breadcrumbList={breadcrumbList} />
</div>
, mountNode);
````
<style>
#scaffold-src-components-PageHeader-demo-simple .code-box-demo {
background: #f2f4f5;
}
</style>
---
order: 1
title: Standard
---
标准页头。
````jsx
import PageHeader from 'ant-design-pro/lib/PageHeader';
import DescriptionList from 'ant-design-pro/lib/DescriptionList';
import { Button, Menu, Dropdown, Icon, Row, Col } from 'antd';
const { Description } = DescriptionList;
const ButtonGroup = Button.Group;
const description = (
<DescriptionList size="small" col="2">
<Description term="创建人">曲丽丽</Description>
<Description term="订购产品">XX 服务</Description>
<Description term="创建时间">2017-07-07</Description>
<Description term="关联单据"><a href="">12421</a></Description>
</DescriptionList>
);
const menu = (
<Menu>
<Menu.Item key="1">选项一</Menu.Item>
<Menu.Item key="2">选项二</Menu.Item>
<Menu.Item key="3">选项三</Menu.Item>
</Menu>
);
const action = (
<div>
<ButtonGroup>
<Button>操作</Button>
<Button>操作</Button>
<Dropdown overlay={menu} placement="bottomRight">
<Button><Icon type="ellipsis" /></Button>
</Dropdown>
</ButtonGroup>
<Button type="primary">主操作</Button>
</div>
);
const extra = (
<Row>
<Col sm={24} md={12}>
<div style={{ color: 'rgba(0, 0, 0, 0.43)' }}>状态</div>
<div style={{ color: 'rgba(0, 0, 0, 0.85)', fontSize: 20 }}>待审批</div>
</Col>
<Col sm={24} md={12}>
<div style={{ color: 'rgba(0, 0, 0, 0.43)' }}>订单金额</div>
<div style={{ color: 'rgba(0, 0, 0, 0.85)', fontSize: 20 }}>¥ 568.08</div>
</Col>
</Row>
);
const breadcrumbList = [{
title: '一级菜单',
href: '/',
}, {
title: '二级菜单',
href: '/',
}, {
title: '三级菜单',
}];
const tabList = [{
key: 'detail',
tab: '详情',
}, {
key: 'rule',
tab: '规则',
}];
function onTabChange(key) {
console.log(key);
}
ReactDOM.render(
<div>
<PageHeader
title="单号:234231029431"
logo={<img alt="" src="https://gw.alipayobjects.com/zos/rmsportal/nxkuOJlFJuAUhzlMTCEe.png" />}
action={action}
content={description}
extraContent={extra}
breadcrumbList={breadcrumbList}
tabList={tabList}
tabActiveKey="detail"
onTabChange={onTabChange}
/>
</div>
, mountNode);
````
<style>
#scaffold-src-components-PageHeader-demo-standard .code-box-demo {
background: #f2f4f5;
}
</style>
---
order: 0
title: Structure
---
基本结构,具备响应式布局功能,主要断点为 768px 和 576px,拖动窗口改变大小试试看。
````jsx
import PageHeader from 'ant-design-pro/lib/PageHeader';
const breadcrumbList = [{
title: '面包屑',
}];
const tabList = [{
key: '1',
tab: '页签一',
}, {
key: '2',
tab: '页签二',
}, {
key: '3',
tab: '页签三',
}];
ReactDOM.render(
<div>
<PageHeader
className="tabs"
title={<div className="title">Title</div>}
logo={<div className="logo">logo</div>}
action={<div className="action">action</div>}
content={<div className="content">content</div>}
extraContent={<div className="extraContent">extraContent</div>}
breadcrumbList={breadcrumbList}
tabList={tabList}
tabActiveKey="1"
/>
</div>
, mountNode);
````
<style>
#scaffold-src-components-PageHeader-demo-structure .code-box-demo {
background: #f2f4f5;
}
#scaffold-src-components-PageHeader-demo-structure .logo {
background: #3ba0e9;
color: #fff;
height: 100%;
}
#scaffold-src-components-PageHeader-demo-structure .title {
background: rgba(16, 142, 233, 1);
color: #fff;
}
#scaffold-src-components-PageHeader-demo-structure .action {
background: #7dbcea;
color: #fff;
}
#scaffold-src-components-PageHeader-demo-structure .content {
background: #7dbcea;
color: #fff;
}
#scaffold-src-components-PageHeader-demo-structure .extraContent {
background: #7dbcea;
color: #fff;
}
</style>
import React from 'react';
import { Location } from 'history';
export interface PageHeaderProps {
title?: React.ReactNode | string | number;
logo?: React.ReactNode | string;
action?: React.ReactNode | string;
content?: React.ReactNode;
extraContent?: React.ReactNode;
routes?: any[];
params?: any;
breadcrumbList?: Array<{ title: string | number; href?: string }>;
tabList?: Array<{ key: string; tab: React.ReactNode }>;
tabActiveKey?: string;
tabDefaultActiveKey?: string;
onTabChange?: (key: string) => void;
tabBarExtraContent?: React.ReactNode;
linkElement?: React.ReactNode | string;
style?: React.CSSProperties;
home?: React.ReactNode;
wide?: boolean;
hiddenBreadcrumb?: boolean;
className?: string;
loading?: boolean;
breadcrumbSeparator?: React.ReactNode;
location?: Location;
itemRender: (menuItem: any) => React.ReactNode;
breadcrumbNameMap?: any;
}
export default class PageHeader extends React.Component<PageHeaderProps, any> {}
import React, { PureComponent } from 'react';
import { Tabs, Skeleton } from 'antd';
import classNames from 'classnames';
import styles from './index.less';
import BreadcrumbView from './breadcrumb';
const { TabPane } = Tabs;
export default class PageHeader extends PureComponent {
onChange = key => {
const { onTabChange } = this.props;
if (onTabChange) {
onTabChange(key);
}
};
render() {
const {
title = '',
logo,
action,
content,
extraContent,
tabList,
className,
tabActiveKey,
tabDefaultActiveKey,
tabBarExtraContent,
loading = false,
wide = false,
hiddenBreadcrumb = false,
} = this.props;
const clsString = classNames(styles.pageHeader, className);
const activeKeyProps = {};
if (tabDefaultActiveKey !== undefined) {
activeKeyProps.defaultActiveKey = tabDefaultActiveKey;
}
if (tabActiveKey !== undefined) {
activeKeyProps.activeKey = tabActiveKey;
}
return (
<div className={clsString}>
<div className={wide ? styles.wide : ''}>
<Skeleton
loading={loading}
title={false}
active
paragraph={{ rows: 3 }}
avatar={{ size: 'large', shape: 'circle' }}
>
{hiddenBreadcrumb ? null : <BreadcrumbView {...this.props} />}
<div className={styles.detail}>
{logo && <div className={styles.logo}>{logo}</div>}
<div className={styles.main}>
<div className={styles.row}>
<h1 className={styles.title}>{title}</h1>
{action && <div className={styles.action}>{action}</div>}
</div>
<div className={styles.row}>
{content && <div className={styles.content}>{content}</div>}
{extraContent && <div className={styles.extraContent}>{extraContent}</div>}
</div>
</div>
</div>
{tabList && tabList.length ? (
<Tabs
className={styles.tabs}
{...activeKeyProps}
onChange={this.onChange}
tabBarExtraContent={tabBarExtraContent}
>
{tabList.map(item => (
<TabPane tab={item.tab} key={item.key} />
))}
</Tabs>
) : null}
</Skeleton>
</div>
</div>
);
}
}
@import '~antd/lib/style/themes/default.less';
.pageHeader {
padding: 16px 32px 0 32px;
background: @component-background;
border-bottom: @border-width-base @border-style-base @border-color-split;
.wide {
max-width: 1200px;
margin: auto;
}
.detail {
display: flex;
}
.row {
display: flex;
width: 100%;
}
.breadcrumb {
margin-bottom: 16px;
}
.tabs {
margin: 0 0 0 -8px;
:global {
// 1px 可以让选中效果显示完成
.ant-tabs-bar {
margin-bottom: 1px;
border-bottom: none;
}
}
}
.logo {
flex: 0 1 auto;
margin-right: 16px;
padding-top: 1px;
> img {
display: block;
width: 28px;
height: 28px;
border-radius: @border-radius-base;
}
}
.title {
color: @heading-color;
font-weight: 500;
font-size: 20px;
}
.action {
min-width: 266px;
margin-left: 56px;
:global {
.ant-btn-group:not(:last-child),
.ant-btn:not(:last-child) {
margin-right: 8px;
}
.ant-btn-group > .ant-btn {
margin-right: 0;
}
}
}
.title,
.content {
flex: auto;
}
.action,
.extraContent,
.main {
flex: 0 1 auto;
}
.main {
width: 100%;
}
.title,
.action {
margin-bottom: 16px;
}
.logo,
.content,
.extraContent {
margin-bottom: 16px;
}
.action,
.extraContent {
text-align: right;
}
.extraContent {
min-width: 242px;
margin-left: 88px;
}
}
@media screen and (max-width: @screen-xl) {
.pageHeader {
.extraContent {
margin-left: 44px;
}
}
}
@media screen and (max-width: @screen-lg) {
.pageHeader {
.extraContent {
margin-left: 20px;
}
}
}
@media screen and (max-width: @screen-md) {
.pageHeader {
.row {
display: block;
}
.action,
.extraContent {
margin-left: 0;
text-align: left;
}
}
}
@media screen and (max-width: @screen-sm) {
.pageHeader {
.detail {
display: block;
}
}
}
@media screen and (max-width: @screen-xs) {
.pageHeader {
.action {
:global {
.ant-btn-group,
.ant-btn {
display: block;
margin-bottom: 8px;
}
.ant-btn-group > .ant-btn {
display: inline-block;
margin-bottom: 0;
}
}
}
}
}
---
title: PageHeader
subtitle: 页头
cols: 1
order: 11
---
页头用来声明页面的主题,包含了用户所关注的最重要的信息,使用户可以快速理解当前页面是什么以及它的功能。
## API
| 参数 | 说明 | 类型 | 默认值 |
|----------|------------------------------------------|-------------|-------|
| title | title 区域 | ReactNode | - |
| loading | 骨架屏loading状态 | boolean | false |
| logo | logo区域 | ReactNode | - |
| action | 操作区,位于 title 行的行尾 | ReactNode | - |
| home | 默认的主页说明文字 | ReactNode | - |
| content | 内容区 | ReactNode | - |
| extraContent | 额外内容区,位于content的右侧 | ReactNode | - |
| breadcrumbList | 面包屑数据,配置了此属性时 `routes` `params` `location` `breadcrumbNameMap` 无效 | array<{title: ReactNode, href?: string}> | - |
| hiddenBreadcrumb |隐藏面包屑 | boolean | false |
| routes | 面包屑相关属性,router 的路由栈信息 | object[] | - |
| params | 面包屑相关属性,路由的参数 | object | - |
| location | 面包屑相关属性,当前的路由信息 | object | - |
| breadcrumbNameMap | 面包屑相关属性,路由的地址-名称映射表 | object | - |
| tabList | tab 标题列表 | array<{key: string, tab: ReactNode}> | - |
| tabActiveKey | 当前高亮的 tab 项 | string | - |
| tabDefaultActiveKey | 默认高亮的 tab 项 | string | 第一项 |
| wide | 是否定宽 | boolean | false |
| onTabChange | 切换面板的回调 | (key) => void | - |
| itemRender | 自定义节点方法 | (menuItem) => ReactNode | - |
| linkElement | 定义链接的元素,默认为 `a`,可传入 react-router 的 Link | string\|ReactElement | - |
> 面包屑的配置方式有三种,一是直接配置 `breadcrumbList`,二是结合 `react-router@2` `react-router@3`,配置 `routes` 及 `params` 实现,类似 [面包屑 Demo](https://ant.design/components/breadcrumb-cn/#components-breadcrumb-demo-router),三是结合 `react-router@4`,配置 `location` `breadcrumbNameMap`,优先级依次递减,脚手架中使用最后一种。 对于后两种用法,你也可以将 `routes` `params` 及 `location` `breadcrumbNameMap` 放到 context 中,组件会自动获取。
import { getBreadcrumb } from './breadcrumb';
import { urlToList } from '../_utils/pathTools';
const routerData = {
'/dashboard/analysis': {
name: '分析页',
},
'/userinfo': {
name: '用户列表',
},
'/userinfo/:id': {
name: '用户信息',
},
'/userinfo/:id/addr': {
name: '收货订单',
},
};
describe('test getBreadcrumb', () => {
it('Simple url', () => {
expect(getBreadcrumb(routerData, '/dashboard/analysis').name).toEqual('分析页');
});
it('Parameters url', () => {
expect(getBreadcrumb(routerData, '/userinfo/2144').name).toEqual('用户信息');
});
it('The middle parameter url', () => {
expect(getBreadcrumb(routerData, '/userinfo/2144/addr').name).toEqual('收货订单');
});
it('Loop through the parameters', () => {
const urlNameList = urlToList('/userinfo/2144/addr').map(
url => getBreadcrumb(routerData, url).name
);
expect(urlNameList).toEqual(['用户列表', '用户信息', '收货订单']);
});
it('a path', () => {
const urlNameList = urlToList('/userinfo').map(url => getBreadcrumb(routerData, url).name);
expect(urlNameList).toEqual(['用户列表']);
});
it('Secondary path', () => {
const urlNameList = urlToList('/userinfo/2144').map(url => getBreadcrumb(routerData, url).name);
expect(urlNameList).toEqual(['用户列表', '用户信息']);
});
});
import React from 'react';
import pathToRegexp from 'path-to-regexp';
import Link from 'umi/link';
import { FormattedMessage } from 'umi-plugin-react/locale';
import { urlToList } from '../_utils/pathTools';
// 渲染Breadcrumb 子节点
// Render the Breadcrumb child node
const itemRender = (route, params, routes, paths) => {
const last = routes.indexOf(route) === routes.length - 1;
return last || !route.component ? (
<span>{route.breadcrumbName}</span>
) : (
<Link to={paths.join('/')}>{route.breadcrumbName}</Link>
);
};
const renderItemLocal = item => {
if (item.locale) {
return <FormattedMessage id={item.locale} defaultMessage={item.name} />;
}
return item.name;
};
export const getBreadcrumb = (breadcrumbNameMap, url) => {
let breadcrumb = breadcrumbNameMap[url];
if (!breadcrumb) {
Object.keys(breadcrumbNameMap).forEach(item => {
if (pathToRegexp(item).test(url)) {
breadcrumb = breadcrumbNameMap[item];
}
});
}
return breadcrumb || {};
};
export const getBreadcrumbProps = props => {
const { routes, params, location, breadcrumbNameMap } = props;
return {
routes,
params,
routerLocation: 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 conversionFromLocation = (routerLocation, breadcrumbNameMap, props) => {
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;
});
// Add home breadcrumbs to your head if defined
if (home) {
extraBreadcrumbItems.unshift({
path: '/',
breadcrumbName: home,
});
}
return extraBreadcrumbItems;
};
/**
* 将参数转化为面包屑
* Convert parameters into breadcrumbs
*/
export const conversionBreadcrumbList = props => {
const { breadcrumbList } = props;
const { routes, params, routerLocation, 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,
itemRender,
};
}
// 根据 location 生成 面包屑
// Generate breadcrumbs based on location
if (routerLocation && routerLocation.pathname) {
return {
routes: conversionFromLocation(routerLocation, breadcrumbNameMap, props),
itemRender,
};
}
return {};
};
import React from 'react'; import React from 'react';
import { FormattedMessage } from 'umi-plugin-react/locale'; import { FormattedMessage } from 'umi-plugin-react/locale';
import Link from 'umi/link'; import Link from 'umi/link';
import PageHeader from '@/components/PageHeader'; import { PageHeader, Tabs, Typography } from 'antd';
import { connect } from 'dva'; import { connect } from 'dva';
import classNames from 'classnames';
import GridContent from './GridContent'; import GridContent from './GridContent';
import styles from './index.less'; import styles from './index.less';
import MenuContext from '@/layouts/MenuContext'; import MenuContext from '@/layouts/MenuContext';
import { conversionBreadcrumbList } from './breadcrumb';
const PageHeaderWrapper = ({ children, contentWidth, wrapperClassName, top, ...restProps }) => ( const { Title } = Typography;
<div style={{ margin: '-24px -24px 0' }} className={wrapperClassName}>
/**
* 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} {top}
{title && content && (
<MenuContext.Consumer> <MenuContext.Consumer>
{value => ( {value => {
return (
<PageHeader <PageHeader
wide={contentWidth === 'Fixed'} wide={contentWidth === 'Fixed'}
home={<FormattedMessage id="menu.home" defaultMessage="Home" />} title={
{...value} <Title
level={4}
style={{
marginBottom: 0,
}}
>
{title}
</Title>
}
key="pageheader" key="pageheader"
{...restProps} {...restProps}
breadcrumb={conversionBreadcrumbList({
...value,
...restProps,
home: <FormattedMessage id="menu.home" defaultMessage="Home" />,
})}
className={styles.pageHeader}
linkElement={Link} linkElement={Link}
itemRender={item => { footer={renderFooter(restProps)}
if (item.locale) { >
return <FormattedMessage id={item.locale} defaultMessage={item.title} />; <div className={styles.detail}>
} {logo && <div className={styles.logo}>{logo}</div>}
return item.title; <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> </MenuContext.Consumer>
)}
{children ? ( {children ? (
<div className={styles.content}> <div className={styles['children-content']}>
<GridContent>{children}</GridContent> <GridContent>{children}</GridContent>
</div> </div>
) : null} ) : null}
</div> </div>
); );
};
export default connect(({ setting }) => ({ export default connect(({ setting }) => ({
contentWidth: setting.contentWidth, contentWidth: setting.contentWidth,
......
@import '~antd/lib/style/themes/default.less'; @import '~antd/lib/style/themes/default.less';
.content { .children-content {
margin: 24px 24px 0; margin: 24px 24px 0;
} }
@media screen and (max-width: @screen-sm) { .main {
:global {
.ant-page-header {
padding: 16px 32px 0;
background: #fff;
border-bottom: 1px solid #e8e8e8;
}
}
.wide {
max-width: 1200px;
margin: auto;
}
.detail {
display: flex;
}
.row {
display: flex;
width: 100%;
}
.logo {
flex: 0 1 auto;
margin-right: 16px;
padding-top: 1px;
> img {
display: block;
width: 28px;
height: 28px;
border-radius: @border-radius-base;
}
}
.title-content {
margin-bottom: 16px;
}
@media screen and (max-width: @screen-sm) {
.content { .content {
margin: 24px 0 0; margin: 24px 0 0;
} }
}
.title,
.content {
flex: auto;
}
.extraContent,
.main {
flex: 0 1 auto;
}
.main {
width: 100%;
}
.title {
margin-bottom: 16px;
}
.logo,
.content,
.extraContent {
margin-bottom: 16px;
}
.extraContent {
min-width: 242px;
margin-left: 88px;
text-align: right;
}
}
@media screen and (max-width: @screen-xl) {
.extraContent {
margin-left: 44px;
}
}
@media screen and (max-width: @screen-lg) {
.extraContent {
margin-left: 20px;
}
}
@media screen and (max-width: @screen-md) {
.row {
display: block;
}
.action,
.extraContent {
margin-left: 0;
text-align: left;
}
}
@media screen and (max-width: @screen-sm) {
.detail {
display: block;
}
} }
...@@ -120,7 +120,10 @@ class HeaderView extends Component { ...@@ -120,7 +120,10 @@ class HeaderView extends Component {
const isTop = layout === 'topmenu'; const isTop = layout === 'topmenu';
const width = this.getHeadWidth(); const width = this.getHeadWidth();
const HeaderDom = visible ? ( const HeaderDom = visible ? (
<Header style={{ padding: 0, width }} className={fixedHeader ? styles.fixedHeader : ''}> <Header
style={{ padding: 0, width, zIndex: 2 }}
className={fixedHeader ? styles.fixedHeader : ''}
>
{isTop && !isMobile ? ( {isTop && !isMobile ? (
<TopNavHeader <TopNavHeader
theme={navTheme} theme={navTheme}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册