index.js 4.93 KB
Newer Older
偏右's avatar
偏右 committed
1
import React, { PureComponent, createElement } from 'react';
2 3 4 5 6
import PropTypes from 'prop-types';
import { Breadcrumb, Tabs } from 'antd';
import classNames from 'classnames';
import styles from './index.less';

afc163's avatar
afc163 committed
7
const { TabPane } = Tabs;
8

9 10 11 12 13 14 15 16 17 18 19 20
function getBreadcrumbNameWithParams(breadcrumbNameMap, url) {
  let name = '';
  Object.keys(breadcrumbNameMap).forEach((item) => {
    const itemRegExpStr = `^${item.replace(/:[\w-]+/g, '[\\w-]+')}$`;
    const itemRegExp = new RegExp(itemRegExpStr);
    if (itemRegExp.test(url)) {
      name = breadcrumbNameMap[item];
    }
  });
  return name;
}

21 22 23 24
export default class PageHeader extends PureComponent {
  static contextTypes = {
    routes: PropTypes.array,
    params: PropTypes.object,
ddcat1115's avatar
ddcat1115 committed
25 26
    location: PropTypes.object,
    breadcrumbNameMap: PropTypes.object,
27 28 29 30 31 32 33 34 35 36
  };
  onChange = (key) => {
    if (this.props.onTabChange) {
      this.props.onTabChange(key);
    }
  };
  getBreadcrumbProps = () => {
    return {
      routes: this.props.routes || this.context.routes,
      params: this.props.params || this.context.params,
ddcat1115's avatar
ddcat1115 committed
37 38
      location: this.props.location || this.context.location,
      breadcrumbNameMap: this.props.breadcrumbNameMap || this.context.breadcrumbNameMap,
39 40
    };
  };
偏右's avatar
偏右 committed
41 42 43 44 45 46 47 48 49 50
  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);
  }
51
  render() {
ddcat1115's avatar
ddcat1115 committed
52
    const { routes, params, location, breadcrumbNameMap } = this.getBreadcrumbProps();
偏右's avatar
偏右 committed
53 54 55 56
    const {
      title, logo, action, content, extraContent,
      breadcrumbList, tabList, className, linkElement = 'a',
    } = this.props;
57 58 59 60 61 62 63 64
    const clsString = classNames(styles.pageHeader, className);
    let breadcrumb;
    if (routes && params) {
      breadcrumb = (
        <Breadcrumb
          className={styles.breadcrumb}
          routes={routes.filter(route => route.breadcrumbName)}
          params={params}
偏右's avatar
偏右 committed
65
          itemRender={this.itemRender}
66 67
        />
      );
ddcat1115's avatar
ddcat1115 committed
68 69 70 71 72 73
    } else if (location && location.pathname) {
      const pathSnippets = location.pathname.split('/').filter(i => i);
      const extraBreadcrumbItems = pathSnippets.map((_, index) => {
        const url = `/${pathSnippets.slice(0, index + 1).join('/')}`;
        return (
          <Breadcrumb.Item key={url}>
74 75 76 77 78 79 80 81
            {createElement(
              index === pathSnippets.length - 1 ? 'span' : linkElement,
              { [linkElement === 'a' ? 'href' : 'to']: url },
              breadcrumbNameMap[url] ||
              breadcrumbNameMap[url.replace('/', '')] ||
              getBreadcrumbNameWithParams(breadcrumbNameMap, url) ||
              url
            )}
ddcat1115's avatar
ddcat1115 committed
82 83 84 85 86
          </Breadcrumb.Item>
        );
      });
      const breadcrumbItems = [(
        <Breadcrumb.Item key="home">
偏右's avatar
偏右 committed
87
          {createElement(linkElement, {
afc163's avatar
afc163 committed
88
            [linkElement === 'a' ? 'href' : 'to']: '/',
偏右's avatar
偏右 committed
89
          }, 'ι¦–ι‘΅')}
ddcat1115's avatar
ddcat1115 committed
90 91 92 93 94 95 96
        </Breadcrumb.Item>
      )].concat(extraBreadcrumbItems);
      breadcrumb = (
        <Breadcrumb className={styles.breadcrumb}>
          {breadcrumbItems}
        </Breadcrumb>
      );
97 98 99 100 101
    } else if (breadcrumbList && breadcrumbList.length) {
      breadcrumb = (
        <Breadcrumb className={styles.breadcrumb}>
          {
            breadcrumbList.map(item => (
102
              <Breadcrumb.Item key={item.title}>
afc163's avatar
afc163 committed
103 104 105
                {item.href ? (
                  createElement(linkElement, {
                    [linkElement === 'a' ? 'href' : 'to']: item.href,
ddcat1115's avatar
ddcat1115 committed
106
                  }, item.title)
afc163's avatar
afc163 committed
107
                ) : item.title}
108 109 110 111 112 113 114 115 116
              </Breadcrumb.Item>)
            )
          }
        </Breadcrumb>
      );
    } else {
      breadcrumb = null;
    }

afc163's avatar
afc163 committed
117
    const tabDefaultValue = tabList && (tabList.filter(item => item.default)[0] || tabList[0]);
118 119 120 121 122 123 124 125 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

    return (
      <div className={clsString}>
        {breadcrumb}
        <div className={styles.detail}>
          {logo && <div className={styles.logo}>{logo}</div>}
          <div className={styles.main}>
            <div className={styles.row}>
              {title && <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}
            defaultActiveKey={(tabDefaultValue && tabDefaultValue.key)}
            onChange={this.onChange}
          >
            {
              tabList.map(item => <TabPane tab={item.tab} key={item.key} />)
            }
          </Tabs>
        }
      </div>
    );
  }
}