You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@skywalking.apache.org by ha...@apache.org on 2018/02/24 08:35:54 UTC

[incubator-skywalking-ui] 01/01: update antd

This is an automated email from the ASF dual-hosted git repository.

hanahmily pushed a commit to branch update-antdpro
in repository https://gitbox.apache.org/repos/asf/incubator-skywalking-ui.git

commit 086555818b47c1b9fc0446959e1d29c6b0a4df8f
Author: gaohongtao <ha...@gmail.com>
AuthorDate: Sat Feb 24 16:04:06 2018 +0800

    update antd
---
 src/main/frontend/.editorconfig => .editorconfig   |   0
 src/main/frontend/.eslintrc => .eslintrc           |  16 +-
 src/main/frontend/.ga => .ga                       |   0
 .gitignore                                         |  33 +-
 .../src/routes/Service/Service.less => .localized  |   0
 .roadhogrc.mock.js                                 | 137 ++++++
 src/main/frontend/.stylelintrc => .stylelintrc     |   1 +
 .travis.yml                                        |  39 +-
 src/main/frontend/.roadhogrc.js => .webpackrc.js   |  17 +-
 CHECKSTYLE_HEAD                                    |  17 -
 CODE_OF_CONDUCT.md                                 |  46 ++
 HEADER                                             |  14 -
 README.md                                          | 123 ++++--
 README.zh-CN.md                                    |  90 ++++
 appveyor.yml                                       |  22 +
 checkStyle.xml                                     | 113 -----
 {src/main/frontend/mock => mock}/.gitkeep          |   0
 mock/api.js                                        | 295 +++++++++++++
 mock/chart.js                                      | 197 +++++++++
 {src/main/frontend/mock => mock}/notices.js        |  52 ++-
 mock/profile.js                                    | 158 +++++++
 {src/main/frontend/mock => mock}/rule.js           |  12 +-
 {src/main/frontend/mock => mock}/utils.js          |   0
 package.json                                       |  95 ++++
 pom.xml                                            | 175 --------
 public/favicon.png                                 | Bin 0 -> 6716 bytes
 src/assets/logo.svg                                |  43 ++
 .../frontend/public/img/logo => assets}/sw-2.png   | Bin
 src/common/menu.js                                 | 141 ++++++
 src/common/router.js                               | 196 +++++++++
 src/components/ActiveChart/index.js                |  82 ++++
 src/components/ActiveChart/index.less              |  31 ++
 src/components/Authorized/Authorized.js            |  16 +
 src/components/Authorized/AuthorizedRoute.js       |  23 +
 src/components/Authorized/CheckPermissions.js      |  67 +++
 src/components/Authorized/CheckPermissions.test.js |  45 ++
 src/components/Authorized/PromiseRender.js         |  39 ++
 src/components/Authorized/Secured.js               |  49 +++
 src/components/Authorized/demo/AuthorizedArray.md  |  23 +
 .../Authorized/demo/AuthorizedFunction.md          |  31 ++
 src/components/Authorized/demo/basic.md            |  25 ++
 src/components/Authorized/demo/secured.md          |  28 ++
 src/components/Authorized/index.d.ts               |  48 ++
 src/components/Authorized/index.js                 |  32 ++
 src/components/Authorized/index.md                 |  58 +++
 src/components/AvatarList/demo/simple.md           |  20 +
 src/components/AvatarList/index.d.ts               |  23 +
 src/components/AvatarList/index.en-US.md           |  22 +
 src/components/AvatarList/index.js                 |  43 ++
 src/components/AvatarList/index.less               |  45 ++
 src/components/AvatarList/index.zh-CN.md           |  23 +
 .../src => }/components/Charts/Bar/index.d.ts      |   3 +-
 src/components/Charts/Bar/index.js                 | 113 +++++
 .../components/Charts/ChartCard/index.d.ts         |   1 +
 .../src => }/components/Charts/ChartCard/index.js  |   2 +-
 .../components/Charts/ChartCard/index.less         |   4 +
 .../src => }/components/Charts/Field/index.d.ts    |   1 +
 .../src => }/components/Charts/Field/index.js      |   0
 .../src => }/components/Charts/Field/index.less    |   0
 .../src => }/components/Charts/Gauge/index.d.ts    |   1 +
 src/components/Charts/Gauge/index.js               | 167 +++++++
 .../src => }/components/Charts/MiniArea/index.d.ts |   0
 src/components/Charts/MiniArea/index.js            | 106 +++++
 .../src => }/components/Charts/MiniBar/index.d.ts  |   5 +-
 src/components/Charts/MiniBar/index.js             |  50 +++
 .../components/Charts/MiniProgress/index.d.ts      |   1 +
 .../components/Charts/MiniProgress/index.js        |   0
 .../components/Charts/MiniProgress/index.less      |   0
 .../src => }/components/Charts/Pie/index.d.ts      |   6 +-
 src/components/Charts/Pie/index.js                 | 247 +++++++++++
 .../src => }/components/Charts/Pie/index.less      |   0
 .../src => }/components/Charts/Radar/index.d.ts    |   3 +-
 src/components/Charts/Radar/index.js               | 180 ++++++++
 .../src => }/components/Charts/Radar/index.less    |   0
 .../src => }/components/Charts/TagCloud/index.d.ts |   1 +
 src/components/Charts/TagCloud/index.js            | 164 +++++++
 .../src => }/components/Charts/TagCloud/index.less |   1 +
 .../components/Charts/TimelineChart/index.d.ts     |   2 +
 src/components/Charts/TimelineChart/index.js       | 123 ++++++
 .../components/Charts/TimelineChart/index.less     |   0
 .../components/Charts/WaterWave/index.d.ts         |   3 +-
 .../src => }/components/Charts/WaterWave/index.js  |  47 +-
 .../components/Charts/WaterWave/index.less         |   0
 src/components/Charts/autoHeight.js                |  63 +++
 .../src => }/components/Charts/demo/bar.md         |   0
 .../src => }/components/Charts/demo/chart-card.md  |   0
 .../src => }/components/Charts/demo/gauge.md       |   0
 .../src => }/components/Charts/demo/mini-area.md   |   0
 .../src => }/components/Charts/demo/mini-bar.md    |   0
 .../src => }/components/Charts/demo/mini-pie.md    |   0
 .../components/Charts/demo/mini-progress.md        |   0
 .../src => }/components/Charts/demo/mix.md         |   0
 .../src => }/components/Charts/demo/pie.md         |   0
 .../src => }/components/Charts/demo/radar.md       |   0
 .../src => }/components/Charts/demo/tag-cloud.md   |   0
 .../components/Charts/demo/timeline-chart.md       |   0
 .../src => }/components/Charts/demo/waterwave.md   |   0
 src/components/Charts/g2.js                        |  15 +
 src/components/Charts/index.d.ts                   |  17 +
 .../frontend/src => }/components/Charts/index.js   |   9 +-
 .../frontend/src => }/components/Charts/index.less |   4 +-
 .../frontend/src => }/components/Charts/index.md   |   0
 src/components/CountDown/demo/simple.md            |  24 +
 src/components/CountDown/index.d.ts                |   9 +
 src/components/CountDown/index.en-US.md            |  15 +
 src/components/CountDown/index.js                  | 108 +++++
 src/components/CountDown/index.zh-CN.md            |  16 +
 .../components/DescriptionList/Description.js      |   9 +
 .../components/DescriptionList/DescriptionList.js  |   4 +-
 .../components/DescriptionList/demo/basic.md       |   0
 .../components/DescriptionList/demo/vertical.md    |   0
 .../src => }/components/DescriptionList/index.d.ts |   8 +-
 .../src => }/components/DescriptionList/index.js   |   0
 .../src => }/components/DescriptionList/index.less |  44 +-
 .../src => }/components/DescriptionList/index.md   |   0
 .../components/DescriptionList/responsive.js       |   0
 src/components/Duration/Icon/index.js              |  30 ++
 .../Duration/Panel}/index.js                       |  30 +-
 src/components/Duration/Panel/index.less           | 142 ++++++
 src/components/EditableItem/index.js               |  55 +++
 src/components/EditableItem/index.less             |  25 ++
 src/components/EditableLinkGroup/index.js          |  44 ++
 src/components/EditableLinkGroup/index.less        |  16 +
 src/components/Ellipsis/demo/line.md               |  20 +
 src/components/Ellipsis/demo/number.md             |  20 +
 src/components/Ellipsis/index.d.ts                 |  12 +
 src/components/Ellipsis/index.js                   | 224 ++++++++++
 src/components/Ellipsis/index.less                 |  24 +
 src/components/Ellipsis/index.md                   |  18 +
 src/components/Exception/demo/403.md               |  21 +
 src/components/Exception/demo/404.md               |  14 +
 src/components/Exception/demo/500.md               |  14 +
 src/components/Exception/index.d.ts                |  12 +
 src/components/Exception/index.js                  |  33 ++
 src/components/Exception/index.less                |  88 ++++
 src/components/Exception/index.md                  |  21 +
 src/components/Exception/typeConfig.js             |  19 +
 src/components/FooterToolbar/demo/basic.md         |  36 ++
 src/components/FooterToolbar/index.d.ts            |  10 +
 src/components/FooterToolbar/index.js              |  18 +
 src/components/FooterToolbar/index.less            |  33 ++
 src/components/FooterToolbar/index.md              |  21 +
 src/components/GlobalFooter/demo/basic.md          |  37 ++
 src/components/GlobalFooter/index.d.ts             |  15 +
 src/components/GlobalFooter/index.js               |  27 ++
 src/components/GlobalFooter/index.less             |  29 ++
 src/components/GlobalFooter/index.md               |  17 +
 src/components/GlobalHeader/index.js               | 119 +++++
 .../GlobalHeader/index.less}                       | 102 +++--
 src/components/HeaderSearch/demo/basic.md          |  34 ++
 src/components/HeaderSearch/index.d.ts             |  14 +
 src/components/HeaderSearch/index.js               |  85 ++++
 src/components/HeaderSearch/index.less             |  32 ++
 src/components/HeaderSearch/index.md               |  20 +
 src/components/Login/LoginItem.js                  | 104 +++++
 src/components/Login/LoginSubmit.js                |  15 +
 src/components/Login/LoginTab.js                   |  32 ++
 src/components/Login/demo/basic.md                 | 113 +++++
 src/components/Login/index.d.ts                    |  32 ++
 src/components/Login/index.js                      | 124 ++++++
 src/components/Login/index.less                    |  45 ++
 src/components/Login/index.md                      |  51 +++
 src/components/Login/map.js                        |  55 +++
 src/components/NoticeIcon/NoticeList.js            |  55 +++
 src/components/NoticeIcon/NoticeList.less          |  78 ++++
 src/components/NoticeIcon/demo/basic.md            |  12 +
 src/components/NoticeIcon/demo/popover.md          | 176 ++++++++
 src/components/NoticeIcon/index.d.ts               |  45 ++
 src/components/NoticeIcon/index.js                 | 100 +++++
 src/components/NoticeIcon/index.less               |  30 ++
 src/components/NoticeIcon/index.md                 |  43 ++
 src/components/NumberInfo/demo/basic.md            |  22 +
 src/components/NumberInfo/index.d.ts               |  13 +
 src/components/NumberInfo/index.js                 |  34 ++
 src/components/NumberInfo/index.less               |  68 +++
 src/components/NumberInfo/index.md                 |  22 +
 src/components/PageHeader/demo/image.md            |  75 ++++
 src/components/PageHeader/demo/simple.md           |  32 ++
 src/components/PageHeader/demo/standard.md         | 102 +++++
 src/components/PageHeader/demo/structure.md        |  68 +++
 src/components/PageHeader/index.d.ts               |  19 +
 src/components/PageHeader/index.js                 | 194 ++++++++
 src/components/PageHeader/index.less               | 138 ++++++
 src/components/PageHeader/index.md                 |  31 ++
 src/components/Result/demo/classic.md              |  80 ++++
 src/components/Result/demo/error.md                |  39 ++
 src/components/Result/demo/structure.md            |  20 +
 src/components/Result/index.d.ts                   |  11 +
 src/components/Result/index.js                     |  23 +
 src/components/Result/index.less                   |  51 +++
 src/components/Result/index.md                     |  20 +
 src/components/SiderMenu/SiderMenu.js              | 241 ++++++++++
 src/components/SiderMenu/index.js                  |  19 +
 src/components/SiderMenu/index.less                |  43 ++
 .../src => }/components/StandardFormRow/index.js   |   0
 .../src => }/components/StandardFormRow/index.less |   3 +-
 src/components/StandardTable/index.js              | 120 +++++
 .../src => }/components/StandardTable/index.less   |   0
 src/components/TagSelect/demo/expandable.md        |  31 ++
 src/components/TagSelect/demo/simple.md            |  25 ++
 src/components/TagSelect/index.d.ts                |  23 +
 src/components/TagSelect/index.js                  | 129 ++++++
 src/components/TagSelect/index.less                |  33 ++
 src/components/TagSelect/index.md                  |  29 ++
 .../src => }/components/Trend/demo/basic.md        |   0
 .../frontend/src => }/components/Trend/index.d.ts  |   5 +-
 .../frontend/src => }/components/Trend/index.js    |   0
 .../frontend/src => }/components/Trend/index.less  |   0
 .../frontend/src => }/components/Trend/index.md    |   0
 src/{main/frontend/src => }/e2e/home.e2e.js        |   4 +-
 src/index.ejs                                      |  16 +
 src/index.js                                       |  33 ++
 src/index.less                                     |  31 ++
 src/layouts/BasicLayout.js                         | 267 +++++++++++
 src/{main/frontend/src => }/layouts/BlankLayout.js |   0
 .../frontend/src => }/layouts/PageHeaderLayout.js  |   4 +-
 .../src => }/layouts/PageHeaderLayout.less         |   0
 src/layouts/UserLayout.js                          |  72 +++
 src/layouts/UserLayout.less                        |  60 +++
 src/main/frontend/.gitignore                       |  17 -
 src/main/frontend/.roadhogrc.mock.js               |  35 --
 src/main/frontend/LICENSE                          | 201 ---------
 src/main/frontend/README.md                        |   1 -
 src/main/frontend/jsconfig.json                    |   5 -
 src/main/frontend/mock/alarm.js                    |  93 ----
 src/main/frontend/mock/application.js              |  99 -----
 src/main/frontend/mock/dashboard.js                |  27 --
 src/main/frontend/mock/server.js                   |  49 ---
 src/main/frontend/mock/service.js                  |  93 ----
 src/main/frontend/mock/topology.js                 | 114 -----
 src/main/frontend/mock/trace.js                    | 148 -------
 src/main/frontend/package.json                     | 112 -----
 src/main/frontend/public/alert.png                 | Bin 4326 -> 0 bytes
 src/main/frontend/public/alert.svg                 |   1 -
 src/main/frontend/public/app.jpg                   | Bin 8847 -> 0 bytes
 src/main/frontend/public/app.svg                   |   1 -
 src/main/frontend/public/css/iconfont.css          |  71 ---
 src/main/frontend/public/css/iconfont.eot          | Bin 5116 -> 0 bytes
 src/main/frontend/public/css/iconfont.js           |   1 -
 src/main/frontend/public/css/iconfont.svg          |  57 ---
 src/main/frontend/public/css/iconfont.ttf          | Bin 4948 -> 0 bytes
 src/main/frontend/public/css/iconfont.woff         | Bin 3216 -> 0 bytes
 src/main/frontend/public/data.png                  | Bin 7245 -> 0 bytes
 src/main/frontend/public/database.svg              |   1 -
 src/main/frontend/public/img/node/DUBBO.png        | Bin 3537 -> 0 bytes
 .../frontend/public/img/node/FeignDefaultHttp.png  | Bin 3892 -> 0 bytes
 src/main/frontend/public/img/node/H2.png           | Bin 2681 -> 0 bytes
 src/main/frontend/public/img/node/HPROSE.png       | Bin 2158 -> 0 bytes
 src/main/frontend/public/img/node/HTTPCLIENT.png   | Bin 10718 -> 0 bytes
 src/main/frontend/public/img/node/JETTY.png        | Bin 2838 -> 0 bytes
 src/main/frontend/public/img/node/JETTYSERVER.png  | Bin 9889 -> 0 bytes
 src/main/frontend/public/img/node/MONGODB.png      | Bin 4161 -> 0 bytes
 src/main/frontend/public/img/node/MOTAN.png        | Bin 17288 -> 0 bytes
 src/main/frontend/public/img/node/MYSQL.png        | Bin 4980 -> 0 bytes
 src/main/frontend/public/img/node/NutzHttp.png     | Bin 12509 -> 0 bytes
 src/main/frontend/public/img/node/NutzMvc.png      | Bin 14196 -> 0 bytes
 src/main/frontend/public/img/node/OKHTTP.png       | Bin 4070 -> 0 bytes
 src/main/frontend/public/img/node/Oracle.png       | Bin 4312 -> 0 bytes
 src/main/frontend/public/img/node/REDIS.png        | Bin 5178 -> 0 bytes
 src/main/frontend/public/img/node/RESIN.png        | Bin 15092 -> 0 bytes
 src/main/frontend/public/img/node/SPRINGMVC.png    | Bin 11226 -> 0 bytes
 src/main/frontend/public/img/node/STRUTS2.png      | Bin 11643 -> 0 bytes
 src/main/frontend/public/img/node/UNDEFINED.png    | Bin 2918 -> 0 bytes
 src/main/frontend/public/img/node/USER.png         | Bin 2444 -> 0 bytes
 src/main/frontend/public/img/node/tomcat.png       | Bin 4302 -> 0 bytes
 src/main/frontend/public/index.html                |  16 -
 src/main/frontend/public/redis.svg                 |   1 -
 src/main/frontend/public/service.svg               |   1 -
 src/main/frontend/src/common/nav.js                |  62 ---
 .../frontend/src/components/Charts/Area/index.js   | 132 ------
 .../frontend/src/components/Charts/Bar/index.js    | 151 -------
 .../frontend/src/components/Charts/Gauge/index.js  | 202 ---------
 .../frontend/src/components/Charts/Line/index.js   | 129 ------
 .../src/components/Charts/MiniArea/index.js        | 125 ------
 .../src/components/Charts/MiniBar/index.js         |  87 ----
 .../frontend/src/components/Charts/Pie/index.js    | 260 -----------
 .../frontend/src/components/Charts/Radar/index.js  | 189 --------
 .../src/components/Charts/StackBar/index.js        | 109 -----
 .../src/components/Charts/TagCloud/index.js        | 170 -------
 .../src/components/Charts/TimelineChart/index.js   | 125 ------
 src/main/frontend/src/components/Charts/equal.js   |  17 -
 src/main/frontend/src/components/Charts/index.d.ts |  17 -
 .../frontend/src/components/Page/Panel/index.js    |  30 --
 .../frontend/src/components/Page/Ranking/index.js  |  29 --
 .../frontend/src/components/Page/Search/index.js   |  68 ---
 src/main/frontend/src/components/Page/index.js     |   9 -
 .../frontend/src/components/StandardTable/index.js | 154 -------
 .../src/components/Time/TimeSelect/index.less      |   3 -
 .../src/components/Topology/AppTopology.js         |  79 ----
 src/main/frontend/src/components/Topology/Base.js  |  66 ---
 .../src/components/Topology/ServiceTopology.js     |  77 ----
 src/main/frontend/src/components/Topology/conf.js  |  13 -
 src/main/frontend/src/components/Topology/index.js |   7 -
 .../frontend/src/components/Topology/index.less    |  17 -
 .../frontend/src/components/TraceStack/index.js    | 334 --------------
 .../frontend/src/components/TraceStack/index.less  |  51 ---
 .../frontend/src/components/TraceTable/index.js    |  57 ---
 .../frontend/src/components/TraceTable/index.less  |  13 -
 src/main/frontend/src/index.js                     |  23 -
 src/main/frontend/src/index.less                   |  16 -
 src/main/frontend/src/layouts/BasicLayout.js       | 412 -----------------
 src/main/frontend/src/models/alarm.js              |  93 ----
 src/main/frontend/src/models/application.js        |  65 ---
 src/main/frontend/src/models/dashboard.js          |  52 ---
 src/main/frontend/src/models/global.js             | 106 -----
 src/main/frontend/src/models/index.js              |  11 -
 src/main/frontend/src/models/server.js             |  52 ---
 src/main/frontend/src/models/service.js            |  60 ---
 src/main/frontend/src/models/topology.js           |  40 --
 src/main/frontend/src/models/trace.js              | 101 -----
 src/main/frontend/src/polyfill.js                  |   7 -
 src/main/frontend/src/router.js                    |  60 ---
 src/main/frontend/src/routes/Alarm/Alarm.js        | 132 ------
 src/main/frontend/src/routes/Alarm/Alarm.less      |  50 ---
 .../frontend/src/routes/Application/Application.js | 121 -----
 .../src/routes/Application/Application.less        |  28 --
 .../frontend/src/routes/Dashboard/Dashboard.js     | 137 ------
 src/main/frontend/src/routes/List/TableList.less   |  45 --
 src/main/frontend/src/routes/Server/Server.js      | 193 --------
 src/main/frontend/src/routes/Service/Service.js    | 139 ------
 src/main/frontend/src/routes/Topology/Topology.js  |  37 --
 src/main/frontend/src/routes/Trace/Trace.js        | 184 --------
 src/main/frontend/src/services/api.js              |  30 --
 src/main/frontend/src/services/graphql.js          |   8 -
 src/main/frontend/src/utils/request.js             |  72 ---
 src/main/frontend/src/utils/utils.js               | 284 ------------
 src/main/frontend/tests/jasmine.js                 |   1 -
 src/main/frontend/tests/setupTests.js              |  13 -
 src/main/frontend/tests/styleMock.js               |   1 -
 .../skywalking/apm/ui/ApplicationStartUp.java      |  42 --
 .../apache/skywalking/apm/ui/config/UIConfig.java  |  34 --
 .../apm/ui/tools/CollectorServerList.java          |  90 ----
 .../skywalking/apm/ui/tools/HttpClientTools.java   |  73 ---
 .../skywalking/apm/ui/tools/RewritePathFilter.java |  63 ---
 src/main/resources/application.yml                 |  32 --
 src/models/activities.js                           |  28 ++
 src/models/chart.js                                |  61 +++
 src/models/error.js                                |  49 +++
 src/models/form.js                                 |  47 ++
 src/models/global.js                               | 108 +++++
 src/models/index.js                                |   4 +
 src/models/list.js                                 |  41 ++
 src/models/login.js                                |  58 +++
 src/models/monitor.js                              |  28 ++
 src/models/profile.js                              |  38 ++
 src/models/project.js                              |  28 ++
 src/models/register.js                             |  32 ++
 src/{main/frontend/src => }/models/rule.js         |  33 --
 src/{main/frontend/src => }/models/user.js         |  15 -
 src/router.js                                      |  41 ++
 src/routes/Dashboard/Analysis.js                   | 488 +++++++++++++++++++++
 src/routes/Dashboard/Analysis.less                 | 170 +++++++
 src/routes/Dashboard/Monitor.js                    | 171 ++++++++
 .../Dashboard/Monitor.less}                        |   5 -
 src/routes/Dashboard/Workplace.js                  | 275 ++++++++++++
 src/routes/Dashboard/Workplace.less                | 233 ++++++++++
 src/routes/Exception/403.js                        |   7 +
 src/routes/Exception/404.js                        |   7 +
 src/routes/Exception/500.js                        |   7 +
 src/routes/Exception/style.less                    |   7 +
 src/routes/Exception/triggerException.js           |  65 +++
 src/routes/Forms/AdvancedForm.js                   | 290 ++++++++++++
 src/routes/Forms/BasicForm.js                      | 188 ++++++++
 src/routes/Forms/StepForm/Step1.js                 | 122 ++++++
 src/routes/Forms/StepForm/Step2.js                 | 114 +++++
 src/routes/Forms/StepForm/Step3.js                 |  59 +++
 src/routes/Forms/StepForm/index.js                 |  53 +++
 src/routes/Forms/StepForm/style.less               |  75 ++++
 src/routes/Forms/TableForm.js                      | 245 +++++++++++
 src/routes/Forms/style.less                        |  90 ++++
 src/routes/List/Applications.js                    | 200 +++++++++
 src/routes/List/Applications.less                  |  49 +++
 src/routes/List/Articles.js                        | 236 ++++++++++
 src/routes/List/Articles.less                      |  65 +++
 src/routes/List/BasicList.js                       | 148 +++++++
 src/routes/List/BasicList.less                     | 176 ++++++++
 src/routes/List/CardList.js                        |  90 ++++
 src/routes/List/CardList.less                      | 105 +++++
 src/routes/List/List.js                            |  79 ++++
 src/routes/List/Projects.js                        | 172 ++++++++
 src/routes/List/Projects.less                      |  49 +++
 .../frontend/src => }/routes/List/TableList.js     | 150 +++++--
 .../Trace.less => routes/List/TableList.less}      |  96 ++--
 src/routes/Profile/AdvancedProfile.js              | 292 ++++++++++++
 src/routes/Profile/AdvancedProfile.less            |  52 +++
 src/routes/Profile/BasicProfile.js                 | 167 +++++++
 src/routes/Profile/BasicProfile.less               |   8 +
 src/routes/Result/Error.js                         |  37 ++
 src/routes/Result/Success.js                       |  78 ++++
 src/routes/Result/Success.test.js                  |   9 +
 src/routes/User/Login.js                           |  95 ++++
 src/routes/User/Login.less                         |  29 ++
 src/routes/User/Register.js                        | 295 +++++++++++++
 src/routes/User/Register.less                      |  57 +++
 src/routes/User/RegisterResult.js                  |  27 ++
 src/routes/User/RegisterResult.less                |  18 +
 src/services/api.js                                |  79 ++++
 src/services/error.js                              |  17 +
 src/{main/frontend/src => }/services/user.js       |   0
 src/{main/frontend/src => }/theme.js               |   0
 src/utils/Authorized.js                            |  12 +
 src/utils/authority.js                             |   8 +
 src/utils/request.js                               |  88 ++++
 src/utils/time.js                                  |  34 ++
 src/utils/utils.js                                 | 159 +++++++
 src/{main/frontend/src => }/utils/utils.less       |   0
 {src/main/frontend/tests => tests}/run-tests.js    |   2 +-
 407 files changed, 15043 insertions(+), 7522 deletions(-)

diff --git a/src/main/frontend/.editorconfig b/.editorconfig
similarity index 100%
rename from src/main/frontend/.editorconfig
rename to .editorconfig
diff --git a/src/main/frontend/.eslintrc b/.eslintrc
similarity index 76%
rename from src/main/frontend/.eslintrc
rename to .eslintrc
index 5209bd9..db4c05c 100755
--- a/src/main/frontend/.eslintrc
+++ b/.eslintrc
@@ -1,6 +1,7 @@
 {
   "parser": "babel-eslint",
   "extends": "airbnb",
+  "plugins": ["compat"],
   "env": {
     "browser": true,
     "node": true,
@@ -19,6 +20,15 @@
     "react/jsx-no-bind": [0],
     "react/prop-types": [0],
     "react/prefer-stateless-function": [0],
+    "react/jsx-wrap-multilines": ["error", {
+      "declaration": "parens-new-line",
+      "assignment": "parens-new-line",
+      "return": "parens-new-line",
+      "arrow": "parens-new-line",
+      "condition": "parens-new-line",
+      "logical": "parens-new-line",
+      "prop": "ignore"
+    }],
     "no-else-return": [0],
     "no-restricted-syntax": [0],
     "import/no-extraneous-dependencies": [0],
@@ -43,11 +53,15 @@
     "object-curly-newline": [0],
     "function-paren-newline": [0],
     "no-restricted-globals": [0],
-    "require-yield": [1]
+    "require-yield": [1],
+    "compat/compat": "error"
   },
   "parserOptions": {
     "ecmaFeatures": {
       "experimentalObjectRestSpread": true
     }
+  },
+  "settings": {
+    "polyfills": ["fetch", "promises"]
   }
 }
diff --git a/src/main/frontend/.ga b/.ga
similarity index 100%
rename from src/main/frontend/.ga
rename to .ga
diff --git a/.gitignore b/.gitignore
old mode 100644
new mode 100755
index 80ca62b..3c56a42
--- a/.gitignore
+++ b/.gitignore
@@ -1,12 +1,23 @@
-/build/
-target/
-.idea/
-*.iml
-.classpath
-.project
-.settings/
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+# roadhog-api-doc ignore
+/src/utils/request-temp.js
+_roadhog-api-doc
+
+# production
+/dist
+
+# misc
 .DS_Store
-*~
-packages/
-**/dependency-reduced-pom.xml
-src/main/frontend/package-lock.json
+npm-debug.log*
+yarn-error.log
+
+/coverage
+.idea
+yarn.lock
+package-lock.json
+*bak
+jsconfig.json
+.vscode
diff --git a/src/main/frontend/src/routes/Service/Service.less b/.localized
similarity index 100%
rename from src/main/frontend/src/routes/Service/Service.less
rename to .localized
diff --git a/.roadhogrc.mock.js b/.roadhogrc.mock.js
new file mode 100644
index 0000000..076ee0c
--- /dev/null
+++ b/.roadhogrc.mock.js
@@ -0,0 +1,137 @@
+import mockjs from 'mockjs';
+import { getRule, postRule } from './mock/rule';
+import { getActivities, getNotice, getFakeList } from './mock/api';
+import { getFakeChartData } from './mock/chart';
+import { imgMap } from './mock/utils';
+import { getProfileBasicData } from './mock/profile';
+import { getProfileAdvancedData } from './mock/profile';
+import { getNotices } from './mock/notices';
+import { format, delay } from 'roadhog-api-doc';
+
+// 是否禁用代理
+const noProxy = process.env.NO_PROXY === 'true';
+
+// 代码中会兼容本地 service mock 以及部署站点的静态数据
+const proxy = {
+  // 支持值为 Object 和 Array
+  'GET /api/currentUser': {
+    $desc: "获取当前用户接口",
+    $params: {
+      pageSize: {
+        desc: '分页',
+        exp: 2,
+      },
+    },
+    $body: {
+      name: 'Serati Ma',
+      avatar: 'https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png',
+      userid: '00000001',
+      notifyCount: 12,
+    },
+  },
+  // GET POST 可省略
+  'GET /api/users': [{
+    key: '1',
+    name: 'John Brown',
+    age: 32,
+    address: 'New York No. 1 Lake Park',
+  }, {
+    key: '2',
+    name: 'Jim Green',
+    age: 42,
+    address: 'London No. 1 Lake Park',
+  }, {
+    key: '3',
+    name: 'Joe Black',
+    age: 32,
+    address: 'Sidney No. 1 Lake Park',
+  }],
+  'GET /api/project/notice': getNotice,
+  'GET /api/activities': getActivities,
+  'GET /api/rule': getRule,
+  'POST /api/rule': {
+    $params: {
+      pageSize: {
+        desc: '分页',
+        exp: 2,
+      },
+    },
+    $body: postRule,
+  },
+  'POST /api/forms': (req, res) => {
+    res.send({ message: 'Ok' });
+  },
+  'GET /api/tags': mockjs.mock({
+    'list|100': [{ name: '@city', 'value|1-100': 150, 'type|0-2': 1 }]
+  }),
+  'GET /api/fake_list': getFakeList,
+  'GET /api/fake_chart_data': getFakeChartData,
+  'GET /api/profile/basic': getProfileBasicData,
+  'GET /api/profile/advanced': getProfileAdvancedData,
+  'POST /api/login/account': (req, res) => {
+    const { password, userName, type } = req.body;
+    if(password === '888888' && userName === 'admin'){
+      res.send({
+        status: 'ok',
+        type,
+        currentAuthority: 'admin'
+      });
+      return ;
+    }
+    if(password === '123456' && userName === 'user'){
+      res.send({
+        status: 'ok',
+        type,
+        currentAuthority: 'user'
+      });
+      return ;
+    }
+    res.send({
+      status: 'error',
+      type,
+      currentAuthority: 'guest'
+    });
+  },
+  'POST /api/register': (req, res) => {
+    res.send({ status: 'ok', currentAuthority: 'user' });
+  },
+  'GET /api/notices': getNotices,
+  'GET /api/500': (req, res) => {
+    res.status(500).send({
+      "timestamp": 1513932555104,
+      "status": 500,
+      "error": "error",
+      "message": "error",
+      "path": "/base/category/list"
+    });
+  },
+  'GET /api/404': (req, res) => {
+    res.status(404).send({
+      "timestamp": 1513932643431,
+      "status": 404,
+      "error": "Not Found",
+      "message": "No message available",
+      "path": "/base/category/list/2121212"
+    });
+  },
+  'GET /api/403': (req, res) => {
+    res.status(403).send({
+      "timestamp": 1513932555104,
+      "status": 403,
+      "error": "Unauthorized",
+      "message": "Unauthorized",
+      "path": "/base/category/list"
+    });
+  },
+  'GET /api/401': (req, res) => {
+    res.status(401).send({
+      "timestamp": 1513932555104,
+      "status": 401,
+      "error": "Unauthorized",
+      "message": "Unauthorized",
+      "path": "/base/category/list"
+    });
+  },
+};
+
+export default noProxy ? {} : delay(proxy, 1000);
diff --git a/src/main/frontend/.stylelintrc b/.stylelintrc
similarity index 95%
rename from src/main/frontend/.stylelintrc
rename to .stylelintrc
index b4331fb..1027152 100644
--- a/src/main/frontend/.stylelintrc
+++ b/.stylelintrc
@@ -20,6 +20,7 @@
     "selector-list-comma-newline-after": null,
     "selector-pseudo-element-colon-notation": null,
     "unit-no-unknown": null,
+    "no-descending-specificity": null,
     "value-list-max-empty-lines": null
   }
 }
diff --git a/.travis.yml b/.travis.yml
index 3dce299..7f55537 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,7 +1,36 @@
-language: java
+language: node_js
 
-jdk:
-  - oraclejdk8
+node_js:
+  - "8"
 
-before_script:
-  - echo "MAVEN_OPTS='-Xmx1024m -XX:MaxPermSize=256m'" > ~/.mavenrc
+env:
+  matrix:
+    - TEST_TYPE=lint
+    - TEST_TYPE=build
+    - TEST_TYPE=test-all
+    - TEST_TYPE=test-dist
+
+addons:
+  apt:
+    packages:
+      - xvfb
+
+install:
+  - export DISPLAY=':99.0'
+  - Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &
+  - npm install
+
+script:
+  - |
+    if [ "$TEST_TYPE" = lint ]; then
+      npm run lint
+    elif [ "$TEST_TYPE" = build ]; then
+      npm run build
+    elif [ "$TEST_TYPE" = test-all ]; then
+      npm run test:all
+    elif [ "$TEST_TYPE" = test-dist ]; then
+      npm run site
+      mv dist/* ./
+      php -S localhost:8000 &
+      DEBUG=* npm test .e2e.js
+    fi
diff --git a/src/main/frontend/.roadhogrc.js b/.webpackrc.js
old mode 100644
new mode 100755
similarity index 75%
rename from src/main/frontend/.roadhogrc.js
rename to .webpackrc.js
index ba91eb6..64972cf
--- a/src/main/frontend/.roadhogrc.js
+++ b/.webpackrc.js
@@ -1,9 +1,7 @@
 const config = {
   "entry": "src/index.js",
   "extraBabelPlugins": [
-    "transform-runtime",
     "transform-decorators-legacy",
-    "transform-class-properties",
     ["import", { "libraryName": "antd", "libraryDirectory": "es", "style": true }]
   ],
   "env": {
@@ -13,14 +11,15 @@ const config = {
       ]
     }
   },
-  "externals": {
-    "g2": "G2",
-    "g-cloud": "Cloud",
-    "g2-plugin-slider": "G2.Plugin.slider"
-  },
   "ignoreMomentLocale": true,
-  "theme": "./src/theme.js"
-};
+  "theme": "./src/theme.js",
+  "html": {
+    "template": "./src/index.ejs"
+  },
+  "publicPath": "/",
+  "disableDynamicImport": true,
+  "hash": true
+}
 
 if (process.env.NO_MOCK) {
   config.proxy = {
diff --git a/CHECKSTYLE_HEAD b/CHECKSTYLE_HEAD
deleted file mode 100644
index 70774e0..0000000
--- a/CHECKSTYLE_HEAD
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..9e41f2e
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,46 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at afc163@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
+
+[homepage]: http://contributor-covenant.org
+[version]: http://contributor-covenant.org/version/1/4/
diff --git a/HEADER b/HEADER
deleted file mode 100644
index 1745cfe..0000000
--- a/HEADER
+++ /dev/null
@@ -1,14 +0,0 @@
-Licensed to the Apache Software Foundation (ASF) under one or more
-contributor license agreements.  See the NOTICE file distributed with
-this work for additional information regarding copyright ownership.
-The ASF licenses this file to You under the Apache License, Version 2.0
-(the "License"); you may not use this file except in compliance with
-the License.  You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
diff --git a/README.md b/README.md
index d215396..84df26a 100644
--- a/README.md
+++ b/README.md
@@ -1,57 +1,94 @@
-Apache SkyWalking Web UI
-===============
+English | [简体中文](./README.zh-CN.md)
 
-<img src="https://skywalkingtest.github.io/page-resources/3.0/skywalking.png" alt="Sky Walking logo" height="90px" align="right" />
+# Ant Design Pro
 
-The web UI for [SkyWalking APM](https://github.com/apache/incubator-skywalking).
+[![](https://img.shields.io/travis/ant-design/ant-design-pro/master.svg?style=flat-square)](https://travis-ci.org/ant-design/ant-design-pro) [![Build status](https://ci.appveyor.com/api/projects/status/67fxu2by3ibvqtat/branch/master?svg=true)](https://ci.appveyor.com/project/afc163/ant-design-pro/branch/master)  [![Gitter](https://badges.gitter.im/ant-design/ant-design-pro.svg)](https://gitter.im/ant-design/ant-design-pro?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
 
-[![Build Status](https://travis-ci.org/apache/incubator-skywalking-ui.svg?branch=master)](https://travis-ci.org/apache/incubator-skywalking-ui)
+An out-of-box UI solution for enterprise applications as a React boilerplate.
 
-SkyWalking Web UI 5.0 is developing, **NOW!!**. Submit issue and [@hanahmily](https://github.com/hanahmily) if you want to proposal something. 
+![](https://gw.alipayobjects.com/zos/rmsportal/xEdBqwSzvoSapmnSnYjU.png)
 
-___
-_SkyWalking 3.0 documents:_
+- Preview: http://preview.pro.ant.design
+- Home Page: http://pro.ant.design
+- Documentation: http://pro.ant.design/docs/getting-started
+- ChangeLog: http://pro.ant.design/docs/changelog
+- FAQ: http://pro.ant.design/docs/faq
 
-This independent UI repository works since sky-walking 3.0.
+## Translation Recruitment :loudspeaker:
 
-1. Realtime Application Topological Graph
-1. Distributed Trace Query.
-1. Application Instances Overview.
-1. JVM Metric View of application instances.
-1. The relationship of services.
+We need your help: https://github.com/ant-design/ant-design-pro/issues/120
 
-Recommand browsers: Safari & Chrome
+## Features
 
-#### QuickStart
-1. Requirement: Java 8+
-2. Download and startup
+- :gem: **Neat Design**: Follow [Ant Design specification](http://ant.design/)
+- :triangular_ruler: **Common Templates**: Typical templates for enterprise applications
+- :rocket: **State of The Art Development**: Newest development stack of React/dva/antd
+- :iphone: **Responsive**: Designed for varies of screen size
+- :art: **Themeing**: Customizable theme with simple config
+- :globe_with_meridians: **International**: Built-in i18n solution
+- :gear: **Best Practice**: Solid workflow make your code health
+- :1234: **Mock development**: Easy to use mock development solution
+- :white_check_mark: **UI Test**: Fly safely with unit test and e2e test
 
-```shell
-> curl -O https://github.com/wu-sheng/sky-walking-ui/releases/download/<project-version>/skywalking-web.tar.gz
-> tar -xvf skywalking-web.tar.gz
-> cd skywalking-web/bin
-> ./startup.sh
+## Templates
+
+```
+- Dashboard
+  - Analytic
+  - Monitor
+  - Workspace
+- Form
+  - Basic Form
+  - Step Form
+  - Advanced From
+- List
+  - Standard Table
+  - Standard List
+  - Card List
+  - Search List (Project/Applications/Article)
+- Profile
+  - Simple Profile
+  - Advanced Profile
+- Result
+  - Success
+  - Failed
+- Exception
+  - 403
+  - 404
+  - 500
+- User
+  - Login
+  - Register
+  - Register Result
 ```
-3. Configuring skywalking-ui
-* Set server listening port in `config/application.properties`
-* Set log in `config/log4j2.xml`
-* Set addresses of collector servers in `config/collector_config.properties`
-
-4. open `http://127.0.0.1:8080/`
-
-#### QuickStart-zh
-1. 需要JDK8+
-2. 通过命令下载应用程序,或直接前往[发布页面](https://github.com/wu-sheng/sky-walking-ui/releases)下载
-
-```shell
-> curl -O https://github.com/wu-sheng/sky-walking-ui/releases/download/<project-version>/skywalking-web.tar.gz
-> tar -xvf skywalking-web.tar.gz
-> cd skywalking-web/bin
-> ./startup.sh
+
+## Usage
+
+```bash
+$ git clone https://github.com/ant-design/ant-design-pro.git --depth=1
+$ cd ant-design-pro
+$ npm install
+$ npm start         # visit http://localhost:8000
 ```
 
-3. 配置应用程序
-* 在`config/application.properties`文件中,设置webui的监听端口
-* 在`config/collector_config.properties`文件中,设置collector集群或单实例地址,地址对应的是 `skywalking-collector` 项目中配置文件 `config/application.yml` 中配置项 `naming.jetty.host` 和 `naming.jetty.port`
+Or you can use the command tool: [ant-design-pro-cli](https://github.com/ant-design/ant-design-pro-cli)
+
+```bash
+$ npm install ant-design-pro-cli -g
+$ mkdir pro-demo && cd pro-demo
+$ pro new
+```
+
+More instruction at [documentation](http://pro.ant.design/docs/getting-started).
+
+## Compatibility
+
+Modern browsers and IE11.
+
+## Contributing
+
+Any Contribution of following ways will be welcome:
 
-4. 浏览器打开 `http://127.0.0.1:8080/`
\ No newline at end of file
+- Use Ant Design Pro in your daily work.
+- Submit [issue](http://github.com/ant-design/ant-design-pro/issues) to report bug or ask questions.
+- Propose [pull request](http://github.com/ant-design/ant-design-pro/pulls) to improve our code.
diff --git a/README.zh-CN.md b/README.zh-CN.md
new file mode 100644
index 0000000..d428f3e
--- /dev/null
+++ b/README.zh-CN.md
@@ -0,0 +1,90 @@
+[English](./README.md) | 简体中文
+
+# Ant Design Pro
+
+[![](https://img.shields.io/travis/ant-design/ant-design-pro.svg?style=flat-square)](https://travis-ci.org/ant-design/ant-design-pro) [![Build status](https://ci.appveyor.com/api/projects/status/67fxu2by3ibvqtat/branch/master?svg=true)](https://ci.appveyor.com/project/afc163/ant-design-pro/branch/master)  [![Gitter](https://badges.gitter.im/ant-design/ant-design-pro.svg)](https://gitter.im/ant-design/ant-design-pro?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
+
+开箱即用的中台前端/设计解决方案。
+
+![](https://gw.alipayobjects.com/zos/rmsportal/xEdBqwSzvoSapmnSnYjU.png)
+
+- 预览:http://preview.pro.ant.design
+- 首页:http://pro.ant.design/index-cn
+- 使用文档:http://pro.ant.design/docs/getting-started-cn
+- 更新日志: http://pro.ant.design/docs/changelog-cn
+- 常见问题:http://pro.ant.design/docs/faq-cn
+
+## 特性
+
+- :gem: **优雅美观**:基于 Ant Design 体系精心设计
+- :triangular_ruler: **常见设计模式**:提炼自中后台应用的典型页面和场景
+- :rocket: **最新技术栈**:使用 React/dva/antd 等前端前沿技术开发
+- :iphone: **响应式**:针对不同屏幕大小设计
+- :art: **主题**:可配置的主题满足多样化的品牌诉求
+- :globe_with_meridians: **国际化**:内建业界通用的国际化方案
+- :gear: **最佳实践**:良好的工程实践助您持续产出高质量代码
+- :1234: **Mock 数据**:实用的本地数据调试方案
+- :white_check_mark: **UI 测试**:自动化测试保障前端产品质量
+
+## 模板
+
+```
+- Dashboard
+  - 分析页
+  - 监控页
+  - 工作台
+- 表单页
+  - 基础表单页
+  - 分步表单页
+  - 高级表单页
+- 列表页
+  - 查询表格
+  - 标准列表
+  - 卡片列表
+  - 搜索列表(项目/应用/文章)
+- 详情页
+  - 基础详情页
+  - 高级详情页
+- 结果
+  - 成功页
+  - 失败页
+- 异常
+  - 403 无权限
+  - 404 找不到
+  - 500 服务器出错
+- 帐户
+  - 登录
+  - 注册
+  - 注册成功
+```
+
+## 使用
+
+```bash
+$ git clone https://github.com/ant-design/ant-design-pro.git --depth=1
+$ cd ant-design-pro
+$ npm install
+$ npm start         # 访问 http://localhost:8000
+```
+
+也可以使用集成化的 [ant-design-pro-cli](https://github.com/ant-design/ant-design-pro-cli) 工具。
+
+```bash
+$ npm install ant-design-pro-cli -g
+$ mkdir pro-demo && cd pro-demo
+$ pro new
+```
+
+更多信息请参考 [使用文档](http://pro.ant.design/docs/getting-started)。
+
+## 兼容性
+
+现代浏览器及 IE11。
+
+## 参与贡献
+
+我们非常欢迎你的贡献,你可以通过以下方式和我们一起共建 :smiley::
+
+- 在你的公司或个人项目中使用 Ant Design Pro。
+- 通过 [Issue](http://github.com/ant-design/ant-design-pro/issues) 报告 bug 或进行咨询。
+- 提交 [Pull Request](http://github.com/ant-design/ant-design-pro/pulls) 改进 Pro 的代码。
diff --git a/appveyor.yml b/appveyor.yml
new file mode 100644
index 0000000..ee06d65
--- /dev/null
+++ b/appveyor.yml
@@ -0,0 +1,22 @@
+# Test against the latest version of this Node.js version
+environment:
+  nodejs_version: "8"
+
+# Install scripts. (runs after repo cloning)
+install:
+  # Get the latest stable version of Node.js or io.js
+  - ps: Install-Product node $env:nodejs_version
+  # install modules
+  - npm install
+  # Output useful info for debugging.
+  - node --version
+  - npm --version
+
+# Post-install test scripts.
+test_script:
+  - npm run lint
+  - npm run test:all
+  - npm run build
+
+# Don't actually build.
+build: off
diff --git a/checkStyle.xml b/checkStyle.xml
deleted file mode 100644
index 9f1e70f..0000000
--- a/checkStyle.xml
+++ /dev/null
@@ -1,113 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  ~ Licensed to the Apache Software Foundation (ASF) under one or more
-  ~ contributor license agreements.  See the NOTICE file distributed with
-  ~ this work for additional information regarding copyright ownership.
-  ~ The ASF licenses this file to You under the Apache License, Version 2.0
-  ~ (the "License"); you may not use this file except in compliance with
-  ~ the License.  You may obtain a copy of the License at
-  ~
-  ~     http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  ~
-  -->
-
-<!DOCTYPE module PUBLIC
-    "-//Puppy Crawl//DTD Check Configuration 1.3//EN"
-    "http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
-<!--Refer http://checkstyle.sourceforge.net/reports/google-java-style.html#s2.2-file-encoding -->
-<module name="Checker">
-
-    <property name="localeLanguage" value="en"/>
-
-    <!--To configure the check to report on the first instance in each file-->
-    <module name="FileTabCharacter"/>
-
-    <!-- header -->
-    <module name="Header">
-        <property name="headerFile" value="CHECKSTYLE_HEAD"/>
-    </module>
-
-    <module name="RegexpSingleline">
-        <property name="format" value="System\.out\.println"/>
-        <property name="message" value="Prohibit invoking System.out.println in source code !"/>
-    </module>
-
-    <module name="RegexpSingleline">
-        <property name="format"
-                  value=".*[\u3400-\u4DB5\u4E00-\u9FA5\u9FA6-\u9FBB\uF900-\uFA2D\uFA30-\uFA6A\uFA70-\uFAD9\uFF00-\uFFEF\u2E80-\u2EFF\u3000-\u303F\u31C0-\u31EF]+.*"/>
-        <property name="message" value="Not allow chinese character !"/>
-    </module>
-
-    <module name="FileLength">
-        <property name="max" value="3000"/>
-    </module>
-
-    <module name="TreeWalker">
-
-        <module name="UnusedImports">
-            <property name="processJavadoc" value="true"/>
-        </module>
-        <module name="RedundantImport"/>
-
-        <!--Checks that classes that override equals() also override hashCode()-->
-        <module name="EqualsHashCode"/>
-        <!--Checks for over-complicated boolean expressions. Currently finds code like if (topic == true), topic || true, !false, etc.-->
-        <module name="SimplifyBooleanExpression"/>
-        <module name="OneStatementPerLine"/>
-        <module name="UnnecessaryParentheses"/>
-        <!--Checks for over-complicated boolean return statements. For example the following code-->
-        <module name="SimplifyBooleanReturn"/>
-
-        <!--Check that the default is after all the cases in producerGroup switch statement-->
-        <module name="DefaultComesLast"/>
-        <!--Detects empty statements (standalone ";" semicolon)-->
-        <module name="EmptyStatement"/>
-        <!--Checks that long constants are defined with an upper ell-->
-        <module name="UpperEll"/>
-        <module name="ConstantName">
-            <property name="format" value="(^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$)|(^logger)"/>
-        </module>
-        <!--Checks that local, non-final variable names conform to producerGroup format specified by the format property-->
-        <module name="LocalVariableName"/>
-        <!--Validates identifiers for local, final variables, including catch parameters-->
-        <module name="LocalFinalVariableName"/>
-        <!--Validates identifiers for non-static fields-->
-        <module name="MemberName"/>
-        <!--Validates identifiers for class type parameters-->
-        <module name="ClassTypeParameterName">
-            <property name="format" value="^[A-Z0-9]*$"/>
-        </module>
-        <!--Validates identifiers for method type parameters-->
-        <module name="MethodTypeParameterName">
-            <property name="format" value="^[A-Z0-9]*$"/>
-        </module>
-        <module name="PackageName"/>
-        <module name="ParameterName"/>
-        <module name="StaticVariableName">
-            <property name="format" value="(^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$)"/>
-        </module>
-        <module name="TypeName">
-            <property name="format" value="(^[A-Z][a-zA-Z0-9]*$)|(^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$)"/>
-        </module>
-
-        <!--whitespace-->
-        <module name="GenericWhitespace"/>
-        <module name="NoWhitespaceBefore"/>
-        <module name="NoWhitespaceAfter"/>
-        <module name="WhitespaceAround">
-            <property name="allowEmptyConstructors" value="true"/>
-            <property name="allowEmptyMethods" value="true"/>
-        </module>
-        <module name="Indentation"/>
-        <module name="MethodParamPad"/>
-        <module name="ParenPad"/>
-        <module name="TypecastParenPad"/>
-        <module name="TypecastParenPad"/>
-    </module>
-</module>
diff --git a/src/main/frontend/mock/.gitkeep b/mock/.gitkeep
similarity index 100%
rename from src/main/frontend/mock/.gitkeep
rename to mock/.gitkeep
diff --git a/mock/api.js b/mock/api.js
new file mode 100644
index 0000000..35b6494
--- /dev/null
+++ b/mock/api.js
@@ -0,0 +1,295 @@
+import { getUrlParams } from './utils';
+
+const titles = [
+  'Alipay',
+  'Angular',
+  'Ant Design',
+  'Ant Design Pro',
+  'Bootstrap',
+  'React',
+  'Vue',
+  'Webpack',
+];
+const avatars = [
+  'https://gw.alipayobjects.com/zos/rmsportal/WdGqmHpayyMjiEhcKoVE.png', // Alipay
+  'https://gw.alipayobjects.com/zos/rmsportal/zOsKZmFRdUtvpqCImOVY.png', // Angular
+  'https://gw.alipayobjects.com/zos/rmsportal/dURIMkkrRFpPgTuzkwnB.png', // Ant Design
+  'https://gw.alipayobjects.com/zos/rmsportal/sfjbOqnsXXJgNCjCzDBL.png', // Ant Design Pro
+  'https://gw.alipayobjects.com/zos/rmsportal/siCrBXXhmvTQGWPNLBow.png', // Bootstrap
+  'https://gw.alipayobjects.com/zos/rmsportal/kZzEzemZyKLKFsojXItE.png', // React
+  'https://gw.alipayobjects.com/zos/rmsportal/ComBAopevLwENQdKWiIn.png', // Vue
+  'https://gw.alipayobjects.com/zos/rmsportal/nxkuOJlFJuAUhzlMTCEe.png', // Webpack
+];
+
+const avatars2 = [
+  'https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png',
+  'https://gw.alipayobjects.com/zos/rmsportal/cnrhVkzwxjPwAaCfPbdc.png',
+  'https://gw.alipayobjects.com/zos/rmsportal/gaOngJwsRYRaVAuXXcmB.png',
+  'https://gw.alipayobjects.com/zos/rmsportal/ubnKSIfAJTxIgXOKlciN.png',
+  'https://gw.alipayobjects.com/zos/rmsportal/WhxKECPNujWoWEFNdnJE.png',
+  'https://gw.alipayobjects.com/zos/rmsportal/jZUIxmJycoymBprLOUbT.png',
+  'https://gw.alipayobjects.com/zos/rmsportal/psOgztMplJMGpVEqfcgF.png',
+  'https://gw.alipayobjects.com/zos/rmsportal/ZpBqSxLxVEXfcUNoPKrz.png',
+  'https://gw.alipayobjects.com/zos/rmsportal/laiEnJdGHVOhJrUShBaJ.png',
+  'https://gw.alipayobjects.com/zos/rmsportal/UrQsqscbKEpNuJcvBZBu.png',
+];
+
+const covers = [
+  'https://gw.alipayobjects.com/zos/rmsportal/uMfMFlvUuceEyPpotzlq.png',
+  'https://gw.alipayobjects.com/zos/rmsportal/iZBVOIhGJiAnhplqjvZW.png',
+  'https://gw.alipayobjects.com/zos/rmsportal/uVZonEtjWwmUZPBQfycs.png',
+  'https://gw.alipayobjects.com/zos/rmsportal/gLaIAoVWTtLbBWZNYEMg.png',
+];
+const desc = [
+  '那是一种内在的东西, 他们到达不了,也无法触及的',
+  '希望是一个好东西,也许是最好的,好东西是不会消亡的',
+  '生命就像一盒巧克力,结果往往出人意料',
+  '城镇中有那么多的酒馆,她却偏偏走进了我的酒馆',
+  '那时候我只会想自己想要什么,从不想自己拥有什么',
+];
+
+const user = [
+  '付小小',
+  '曲丽丽',
+  '林东东',
+  '周星星',
+  '吴加好',
+  '朱偏右',
+  '鱼酱',
+  '乐哥',
+  '谭小仪',
+  '仲尼',
+];
+
+export function fakeList(count) {
+  const list = [];
+  for (let i = 0; i < count; i += 1) {
+    list.push({
+      id: `fake-list-${i}`,
+      owner: user[i % 10],
+      title: titles[i % 8],
+      avatar: avatars[i % 8],
+      cover: parseInt(i / 4, 10) % 2 === 0 ? covers[i % 4] : covers[3 - (i % 4)],
+      status: ['active', 'exception', 'normal'][i % 3],
+      percent: Math.ceil(Math.random() * 50) + 50,
+      logo: avatars[i % 8],
+      href: 'https://ant.design',
+      updatedAt: new Date(new Date().getTime() - (1000 * 60 * 60 * 2 * i)),
+      createdAt: new Date(new Date().getTime() - (1000 * 60 * 60 * 2 * i)),
+      subDescription: desc[i % 5],
+      description: '在中台产品的研发过程中,会出现不同的设计规范和实现方式,但其中往往存在很多类似的页面和组件,这些类似的组件会被抽离成一套标准规范。',
+      activeUser: Math.ceil(Math.random() * 100000) + 100000,
+      newUser: Math.ceil(Math.random() * 1000) + 1000,
+      star: Math.ceil(Math.random() * 100) + 100,
+      like: Math.ceil(Math.random() * 100) + 100,
+      message: Math.ceil(Math.random() * 10) + 10,
+      content: '段落示意:蚂蚁金服设计平台 ant.design,用最小的工作量,无缝接入蚂蚁金服生态,提供跨越设计与开发的体验解决方案。蚂蚁金服设计平台 ant.design,用最小的工作量,无缝接入蚂蚁金服生态,提供跨越设计与开发的体验解决方案。',
+      members: [
+        {
+          avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ZiESqWwCXBRQoaPONSJe.png',
+          name: '曲丽丽',
+        },
+        {
+          avatar: 'https://gw.alipayobjects.com/zos/rmsportal/tBOxZPlITHqwlGjsJWaF.png',
+          name: '王昭君',
+        },
+        {
+          avatar: 'https://gw.alipayobjects.com/zos/rmsportal/sBxjgqiuHMGRkIjqlQCd.png',
+          name: '董娜娜',
+        },
+      ],
+    });
+  }
+
+  return list;
+}
+
+export function getFakeList(req, res, u) {
+  let url = u;
+  if (!url || Object.prototype.toString.call(url) !== '[object String]') {
+    url = req.url; // eslint-disable-line
+  }
+
+  const params = getUrlParams(url);
+
+  const count = (params.count * 1) || 20;
+
+  const result = fakeList(count);
+
+  if (res && res.json) {
+    res.json(result);
+  } else {
+    return result;
+  }
+}
+
+export const getNotice = [
+  {
+    id: 'xxx1',
+    title: titles[0],
+    logo: avatars[0],
+    description: '那是一种内在的东西,他们到达不了,也无法触及的',
+    updatedAt: new Date(),
+    member: '科学搬砖组',
+    href: '',
+    memberLink: '',
+  },
+  {
+    id: 'xxx2',
+    title: titles[1],
+    logo: avatars[1],
+    description: '希望是一个好东西,也许是最好的,好东西是不会消亡的',
+    updatedAt: new Date('2017-07-24'),
+    member: '全组都是吴彦祖',
+    href: '',
+    memberLink: '',
+  },
+  {
+    id: 'xxx3',
+    title: titles[2],
+    logo: avatars[2],
+    description: '城镇中有那么多的酒馆,她却偏偏走进了我的酒馆',
+    updatedAt: new Date(),
+    member: '中二少女团',
+    href: '',
+    memberLink: '',
+  },
+  {
+    id: 'xxx4',
+    title: titles[3],
+    logo: avatars[3],
+    description: '那时候我只会想自己想要什么,从不想自己拥有什么',
+    updatedAt: new Date('2017-07-23'),
+    member: '程序员日常',
+    href: '',
+    memberLink: '',
+  },
+  {
+    id: 'xxx5',
+    title: titles[4],
+    logo: avatars[4],
+    description: '凛冬将至',
+    updatedAt: new Date('2017-07-23'),
+    member: '高逼格设计天团',
+    href: '',
+    memberLink: '',
+  },
+  {
+    id: 'xxx6',
+    title: titles[5],
+    logo: avatars[5],
+    description: '生命就像一盒巧克力,结果往往出人意料',
+    updatedAt: new Date('2017-07-23'),
+    member: '骗你来学计算机',
+    href: '',
+    memberLink: '',
+  },
+];
+
+export const getActivities = [
+  {
+    id: 'trend-1',
+    updatedAt: new Date(),
+    user: {
+      name: '曲丽丽',
+      avatar: avatars2[0],
+    },
+    group: {
+      name: '高逼格设计天团',
+      link: 'http://github.com/',
+    },
+    project: {
+      name: '六月迭代',
+      link: 'http://github.com/',
+    },
+    template: '在 @{group} 新建项目 @{project}',
+  },
+  {
+    id: 'trend-2',
+    updatedAt: new Date(),
+    user: {
+      name: '付小小',
+      avatar: avatars2[1],
+    },
+    group: {
+      name: '高逼格设计天团',
+      link: 'http://github.com/',
+    },
+    project: {
+      name: '六月迭代',
+      link: 'http://github.com/',
+    },
+    template: '在 @{group} 新建项目 @{project}',
+  },
+  {
+    id: 'trend-3',
+    updatedAt: new Date(),
+    user: {
+      name: '林东东',
+      avatar: avatars2[2],
+    },
+    group: {
+      name: '中二少女团',
+      link: 'http://github.com/',
+    },
+    project: {
+      name: '六月迭代',
+      link: 'http://github.com/',
+    },
+    template: '在 @{group} 新建项目 @{project}',
+  },
+  {
+    id: 'trend-4',
+    updatedAt: new Date(),
+    user: {
+      name: '周星星',
+      avatar: avatars2[4],
+    },
+    project: {
+      name: '5 月日常迭代',
+      link: 'http://github.com/',
+    },
+    template: '将 @{project} 更新至已发布状态',
+  },
+  {
+    id: 'trend-5',
+    updatedAt: new Date(),
+    user: {
+      name: '朱偏右',
+      avatar: avatars2[3],
+    },
+    project: {
+      name: '工程效能',
+      link: 'http://github.com/',
+    },
+    comment: {
+      name: '留言',
+      link: 'http://github.com/',
+    },
+    template: '在 @{project} 发布了 @{comment}',
+  },
+  {
+    id: 'trend-6',
+    updatedAt: new Date(),
+    user: {
+      name: '乐哥',
+      avatar: avatars2[5],
+    },
+    group: {
+      name: '程序员日常',
+      link: 'http://github.com/',
+    },
+    project: {
+      name: '品牌迭代',
+      link: 'http://github.com/',
+    },
+    template: '在 @{group} 新建项目 @{project}',
+  },
+];
+
+
+export default {
+  getNotice,
+  getActivities,
+  getFakeList,
+};
diff --git a/mock/chart.js b/mock/chart.js
new file mode 100644
index 0000000..e167334
--- /dev/null
+++ b/mock/chart.js
@@ -0,0 +1,197 @@
+import moment from 'moment';
+
+// mock data
+const visitData = [];
+const beginDay = new Date().getTime();
+
+const fakeY = [7, 5, 4, 2, 4, 7, 5, 6, 5, 9, 6, 3, 1, 5, 3, 6, 5];
+for (let i = 0; i < fakeY.length; i += 1) {
+  visitData.push({
+    x: moment(new Date(beginDay + (1000 * 60 * 60 * 24 * i))).format('YYYY-MM-DD'),
+    y: fakeY[i],
+  });
+}
+
+const visitData2 = [];
+const fakeY2 = [1, 6, 4, 8, 3, 7, 2];
+for (let i = 0; i < fakeY2.length; i += 1) {
+  visitData2.push({
+    x: moment(new Date(beginDay + (1000 * 60 * 60 * 24 * i))).format('YYYY-MM-DD'),
+    y: fakeY2[i],
+  });
+}
+
+const salesData = [];
+for (let i = 0; i < 12; i += 1) {
+  salesData.push({
+    x: `${i + 1}月`,
+    y: Math.floor(Math.random() * 1000) + 200,
+  });
+}
+const searchData = [];
+for (let i = 0; i < 50; i += 1) {
+  searchData.push({
+    index: i + 1,
+    keyword: `搜索关键词-${i}`,
+    count: Math.floor(Math.random() * 1000),
+    range: Math.floor(Math.random() * 100),
+    status: Math.floor((Math.random() * 10) % 2),
+  });
+}
+const salesTypeData = [
+  {
+    x: '家用电器',
+    y: 4544,
+  },
+  {
+    x: '食用酒水',
+    y: 3321,
+  },
+  {
+    x: '个护健康',
+    y: 3113,
+  },
+  {
+    x: '服饰箱包',
+    y: 2341,
+  },
+  {
+    x: '母婴产品',
+    y: 1231,
+  },
+  {
+    x: '其他',
+    y: 1231,
+  },
+];
+
+const salesTypeDataOnline = [
+  {
+    x: '家用电器',
+    y: 244,
+  },
+  {
+    x: '食用酒水',
+    y: 321,
+  },
+  {
+    x: '个护健康',
+    y: 311,
+  },
+  {
+    x: '服饰箱包',
+    y: 41,
+  },
+  {
+    x: '母婴产品',
+    y: 121,
+  },
+  {
+    x: '其他',
+    y: 111,
+  },
+];
+
+const salesTypeDataOffline = [
+  {
+    x: '家用电器',
+    y: 99,
+  },
+  {
+    x: '个护健康',
+    y: 188,
+  },
+  {
+    x: '服饰箱包',
+    y: 344,
+  },
+  {
+    x: '母婴产品',
+    y: 255,
+  },
+  {
+    x: '其他',
+    y: 65,
+  },
+];
+
+const offlineData = [];
+for (let i = 0; i < 10; i += 1) {
+  offlineData.push({
+    name: `门店${i}`,
+    cvr: Math.ceil(Math.random() * 9) / 10,
+  });
+}
+const offlineChartData = [];
+for (let i = 0; i < 20; i += 1) {
+  offlineChartData.push({
+    x: (new Date().getTime()) + (1000 * 60 * 30 * i),
+    y1: Math.floor(Math.random() * 100) + 10,
+    y2: Math.floor(Math.random() * 100) + 10,
+  });
+}
+
+const radarOriginData = [
+  {
+    name: '个人',
+    ref: 10,
+    koubei: 8,
+    output: 4,
+    contribute: 5,
+    hot: 7,
+  },
+  {
+    name: '团队',
+    ref: 3,
+    koubei: 9,
+    output: 6,
+    contribute: 3,
+    hot: 1,
+  },
+  {
+    name: '部门',
+    ref: 4,
+    koubei: 1,
+    output: 6,
+    contribute: 5,
+    hot: 7,
+  },
+];
+
+//
+const radarData = [];
+const radarTitleMap = {
+  ref: '引用',
+  koubei: '口碑',
+  output: '产量',
+  contribute: '贡献',
+  hot: '热度',
+};
+radarOriginData.forEach((item) => {
+  Object.keys(item).forEach((key) => {
+    if (key !== 'name') {
+      radarData.push({
+        name: item.name,
+        label: radarTitleMap[key],
+        value: item[key],
+      });
+    }
+  });
+});
+
+export const getFakeChartData = {
+  visitData,
+  visitData2,
+  salesData,
+  searchData,
+  offlineData,
+  offlineChartData,
+  salesTypeData,
+  salesTypeDataOnline,
+  salesTypeDataOffline,
+  radarData,
+};
+
+export default {
+  getFakeChartData,
+};
diff --git a/src/main/frontend/mock/notices.js b/mock/notices.js
similarity index 90%
rename from src/main/frontend/mock/notices.js
rename to mock/notices.js
index 2b69a25..7e1b3ce 100644
--- a/src/main/frontend/mock/notices.js
+++ b/mock/notices.js
@@ -1,85 +1,99 @@
-export default {
-  getNotices(req, res) {
-    res.json([{
+export const getNotices = (req, res) => {
+  res.json([
+    {
       id: '000000001',
       avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png',
       title: '你收到了 14 份新周报',
       datetime: '2017-08-09',
-      type: '告警',
-    }, {
+      type: '通知',
+    },
+    {
       id: '000000002',
       avatar: 'https://gw.alipayobjects.com/zos/rmsportal/OKJXDXrmkNshAMvwtvhu.png',
       title: '你推荐的 曲妮妮 已通过第三轮面试',
       datetime: '2017-08-08',
-      type: '告警',
-    }, {
+      type: '通知',
+    },
+    {
       id: '000000003',
       avatar: 'https://gw.alipayobjects.com/zos/rmsportal/kISTdvpyTAhtGxpovNWd.png',
       title: '这种模板可以区分多种通知类型',
       datetime: '2017-08-07',
       read: true,
-      type: '告警',
-    }, {
+      type: '通知',
+    },
+    {
       id: '000000004',
       avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png',
       title: '左侧图标用于区分不同的类型',
       datetime: '2017-08-07',
       type: '通知',
-    }, {
+    },
+    {
       id: '000000005',
       avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png',
       title: '内容不要超过两行字,超出时自动截断',
       datetime: '2017-08-07',
       type: '通知',
-    }, {
+    },
+    {
       id: '000000006',
       avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg',
       title: '曲丽丽 评论了你',
       description: '描述信息描述信息描述信息',
       datetime: '2017-08-07',
       type: '消息',
-    }, {
+    },
+    {
       id: '000000007',
       avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg',
       title: '朱偏右 回复了你',
       description: '这种模板用于提醒谁与你发生了互动,左侧放『谁』的头像',
       datetime: '2017-08-07',
       type: '消息',
-    }, {
+    },
+    {
       id: '000000008',
       avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg',
       title: '标题',
       description: '这种模板用于提醒谁与你发生了互动,左侧放『谁』的头像',
       datetime: '2017-08-07',
       type: '消息',
-    }, {
+    },
+    {
       id: '000000009',
       title: '任务名称',
       description: '任务需要在 2017-01-12 20:00 前启动',
       extra: '未开始',
       status: 'todo',
       type: '待办',
-    }, {
+    },
+    {
       id: '000000010',
       title: '第三方紧急代码变更',
       description: '冠霖提交于 2017-01-06,需在 2017-01-07 前完成代码变更任务',
       extra: '马上到期',
       status: 'urgent',
       type: '待办',
-    }, {
+    },
+    {
       id: '000000011',
       title: '信息安全考试',
       description: '指派竹尔于 2017-01-09 前完成更新并发布',
       extra: '已耗时 8 天',
       status: 'doing',
       type: '待办',
-    }, {
+    },
+    {
       id: '000000012',
       title: 'ABCD 版本发布',
       description: '冠霖提交于 2017-01-06,需在 2017-01-07 前完成代码变更任务',
       extra: '进行中',
       status: 'processing',
       type: '待办',
-    }]);
-  },
+    },
+  ]);
+};
+export default {
+  getNotices,
 };
diff --git a/mock/profile.js b/mock/profile.js
new file mode 100644
index 0000000..7c24be1
--- /dev/null
+++ b/mock/profile.js
@@ -0,0 +1,158 @@
+const basicGoods = [
+  {
+    id: '1234561',
+    name: '矿泉水 550ml',
+    barcode: '12421432143214321',
+    price: '2.00',
+    num: '1',
+    amount: '2.00',
+  },
+  {
+    id: '1234562',
+    name: '凉茶 300ml',
+    barcode: '12421432143214322',
+    price: '3.00',
+    num: '2',
+    amount: '6.00',
+  },
+  {
+    id: '1234563',
+    name: '好吃的薯片',
+    barcode: '12421432143214323',
+    price: '7.00',
+    num: '4',
+    amount: '28.00',
+  },
+  {
+    id: '1234564',
+    name: '特别好吃的蛋卷',
+    barcode: '12421432143214324',
+    price: '8.50',
+    num: '3',
+    amount: '25.50',
+  },
+];
+
+const basicProgress = [
+  {
+    key: '1',
+    time: '2017-10-01 14:10',
+    rate: '联系客户',
+    status: 'processing',
+    operator: '取货员 ID1234',
+    cost: '5mins',
+  },
+  {
+    key: '2',
+    time: '2017-10-01 14:05',
+    rate: '取货员出发',
+    status: 'success',
+    operator: '取货员 ID1234',
+    cost: '1h',
+  },
+  {
+    key: '3',
+    time: '2017-10-01 13:05',
+    rate: '取货员接单',
+    status: 'success',
+    operator: '取货员 ID1234',
+    cost: '5mins',
+  },
+  {
+    key: '4',
+    time: '2017-10-01 13:00',
+    rate: '申请审批通过',
+    status: 'success',
+    operator: '系统',
+    cost: '1h',
+  },
+  {
+    key: '5',
+    time: '2017-10-01 12:00',
+    rate: '发起退货申请',
+    status: 'success',
+    operator: '用户',
+    cost: '5mins',
+  },
+];
+
+const advancedOperation1 = [
+  {
+    key: 'op1',
+    type: '订购关系生效',
+    name: '曲丽丽',
+    status: 'agree',
+    updatedAt: '2017-10-03  19:23:12',
+    memo: '-',
+  },
+  {
+    key: 'op2',
+    type: '财务复审',
+    name: '付小小',
+    status: 'reject',
+    updatedAt: '2017-10-03  19:23:12',
+    memo: '不通过原因',
+  },
+  {
+    key: 'op3',
+    type: '部门初审',
+    name: '周毛毛',
+    status: 'agree',
+    updatedAt: '2017-10-03  19:23:12',
+    memo: '-',
+  },
+  {
+    key: 'op4',
+    type: '提交订单',
+    name: '林东东',
+    status: 'agree',
+    updatedAt: '2017-10-03  19:23:12',
+    memo: '很棒',
+  },
+  {
+    key: 'op5',
+    type: '创建订单',
+    name: '汗牙牙',
+    status: 'agree',
+    updatedAt: '2017-10-03  19:23:12',
+    memo: '-',
+  },
+];
+
+const advancedOperation2 = [
+  {
+    key: 'op1',
+    type: '订购关系生效',
+    name: '曲丽丽',
+    status: 'agree',
+    updatedAt: '2017-10-03  19:23:12',
+    memo: '-',
+  },
+];
+
+const advancedOperation3 = [
+  {
+    key: 'op1',
+    type: '创建订单',
+    name: '汗牙牙',
+    status: 'agree',
+    updatedAt: '2017-10-03  19:23:12',
+    memo: '-',
+  },
+];
+
+export const getProfileBasicData = {
+  basicGoods,
+  basicProgress,
+};
+
+export const getProfileAdvancedData = {
+  advancedOperation1,
+  advancedOperation2,
+  advancedOperation3,
+};
+
+export default {
+  getProfileBasicData,
+  getProfileAdvancedData,
+};
diff --git a/src/main/frontend/mock/rule.js b/mock/rule.js
similarity index 91%
rename from src/main/frontend/mock/rule.js
rename to mock/rule.js
index 4a1a4da..2090ce8 100644
--- a/src/main/frontend/mock/rule.js
+++ b/mock/rule.js
@@ -41,10 +41,14 @@ export function getRule(req, res, u) {
   }
 
   if (params.status) {
-    const s = params.status.split(',');
-    if (s.length === 1) {
-      dataSource = dataSource.filter(data => parseInt(data.status, 10) === parseInt(s[0], 10));
-    }
+    const status = params.status.split(',');
+    let filterDataSource = [];
+    status.forEach((s) => {
+      filterDataSource = filterDataSource.concat(
+        [...dataSource].filter(data => parseInt(data.status, 10) === parseInt(s[0], 10))
+      );
+    });
+    dataSource = filterDataSource;
   }
 
   if (params.no) {
diff --git a/src/main/frontend/mock/utils.js b/mock/utils.js
similarity index 100%
rename from src/main/frontend/mock/utils.js
rename to mock/utils.js
diff --git a/package.json b/package.json
new file mode 100755
index 0000000..3fb1b92
--- /dev/null
+++ b/package.json
@@ -0,0 +1,95 @@
+{
+  "name": "skywalking-ui",
+  "version": "5.0.0-alpha",
+  "description": "A web interface of SkyWalking",
+  "private": true,
+  "scripts": {
+    "precommit": "npm run lint-staged",
+    "start": "cross-env DISABLE_ESLINT=true roadhog dev",
+    "start:no-mock": "cross-env NO_MOCK=true DISABLE_ESLINT=true roadhog dev",
+    "build": "cross-env DISABLE_ESLINT=true roadhog build",
+    "site": "roadhog-api-doc static && gh-pages -d dist",
+    "analyze": "cross-env ANALYZE=true roadhog build",
+    "lint:style": "stylelint \"src/**/*.less\" --syntax less",
+    "lint": "eslint --ext .js src mock tests && npm run lint:style",
+    "lint:fix": "eslint --fix --ext .js src mock tests && npm run lint:style",
+    "lint-staged": "lint-staged",
+    "lint-staged:js": "eslint --ext .js",
+    "test": "roadhog test",
+    "test:component": "roadhog test ./src/components",
+    "test:all": "node ./tests/run-tests.js"
+  },
+  "dependencies": {
+    "@antv/data-set": "^0.8.0",
+    "@babel/polyfill": "^7.0.0-beta.36",
+    "antd": "^3.1.0",
+    "babel-runtime": "^6.9.2",
+    "bizcharts": "^3.1.0-beta.4",
+    "bizcharts-plugin-slider": "^2.0.1",
+    "classnames": "^2.2.5",
+    "cytoscape": "^3.2.7",
+    "cytoscape-cose-bilkent": "^4.0.0",
+    "cytoscape-node-html-label": "^1.0.3",
+    "d3": "^4.12.2",
+    "dva": "^2.1.0",
+    "dva-loading": "^1.0.4",
+    "enquire-js": "^0.1.1",
+    "fastclick": "^1.0.6",
+    "lodash": "^4.17.4",
+    "lodash-decorators": "^4.4.1",
+    "moment": "^2.19.1",
+    "numeral": "^2.0.6",
+    "omit.js": "^1.0.0",
+    "path-to-regexp": "^2.1.0",
+    "prop-types": "^15.5.10",
+    "qs": "^6.5.0",
+    "rc-drawer-menu": "^0.5.0",
+    "react": "^16.2.0",
+    "react-container-query": "^0.9.1",
+    "react-document-title": "^2.0.3",
+    "react-dom": "^16.2.0",
+    "react-fittext": "^1.0.0",
+    "url-polyfill": "^1.0.10"
+  },
+  "devDependencies": {
+    "babel-eslint": "^8.1.2",
+    "babel-plugin-dva-hmr": "^0.4.1",
+    "babel-plugin-import": "^1.6.3",
+    "babel-plugin-transform-decorators-legacy": "^1.3.4",
+    "cross-env": "^5.1.1",
+    "cross-port-killer": "^1.0.1",
+    "enzyme": "^3.1.0",
+    "eslint": "^4.14.0",
+    "eslint-config-airbnb": "^16.0.0",
+    "eslint-plugin-babel": "^4.0.0",
+    "eslint-plugin-compat": "^2.1.0",
+    "eslint-plugin-import": "^2.8.0",
+    "eslint-plugin-jsx-a11y": "^6.0.3",
+    "eslint-plugin-markdown": "^1.0.0-beta.6",
+    "eslint-plugin-react": "^7.0.1",
+    "gh-pages": "^1.0.0",
+    "husky": "^0.14.3",
+    "lint-staged": "^6.0.0",
+    "mockjs": "^1.0.1-beta3",
+    "pro-download": "^1.0.1",
+    "redbox-react": "^1.5.0",
+    "regenerator-runtime": "^0.11.1",
+    "roadhog": "^2.1.0",
+    "roadhog-api-doc": "^0.3.4",
+    "rollbar": "^2.3.4",
+    "stylelint": "^8.4.0",
+    "stylelint-config-standard": "^18.0.0"
+  },
+  "optionalDependencies": {
+    "nightmare": "^2.10.0"
+  },
+  "lint-staged": {
+    "**/*.{js,jsx}": "lint-staged:js",
+    "**/*.less": "stylelint --syntax less"
+  },
+  "browserslist": [
+    "> 1%",
+    "last 2 versions",
+    "not ie <= 10"
+  ]
+}
diff --git a/pom.xml b/pom.xml
deleted file mode 100644
index cfc23cd..0000000
--- a/pom.xml
+++ /dev/null
@@ -1,175 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  ~ Licensed to the Apache Software Foundation (ASF) under one or more
-  ~ contributor license agreements.  See the NOTICE file distributed with
-  ~ this work for additional information regarding copyright ownership.
-  ~ The ASF licenses this file to You under the Apache License, Version 2.0
-  ~ (the "License"); you may not use this file except in compliance with
-  ~ the License.  You may obtain a copy of the License at
-  ~
-  ~     http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  ~
-  -->
-
-<project xmlns="http://maven.apache.org/POM/4.0.0"
-         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <modelVersion>4.0.0</modelVersion>
-
-    <groupId>org.apache.skywalking</groupId>
-    <artifactId>apm-ui</artifactId>
-    <version>5.0-2018-preview</version>
-    <packaging>jar</packaging>
-
-    <parent>
-        <groupId>org.springframework.boot</groupId>
-        <artifactId>spring-boot-starter-parent</artifactId>
-        <version>1.5.9.RELEASE</version>
-        <relativePath/>
-    </parent>
-
-    <properties>
-        <compiler.version>1.8</compiler.version>
-        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-        
-        <log4j.version>2.6.2</log4j.version>
-    </properties>
-
-    <dependencyManagement>
-        <dependencies>
-            <dependency>
-                <groupId>org.springframework.cloud</groupId>
-                <artifactId>spring-cloud-dependencies</artifactId>
-                <version>Edgware.SR1</version>
-                <type>pom</type>
-                <scope>import</scope>
-            </dependency>
-        </dependencies>
-    </dependencyManagement>
-
-    <dependencies>
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-web</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-actuator</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-configuration-processor</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-devtools</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.projectlombok</groupId>
-            <artifactId>lombok</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>com.google.code.gson</groupId>
-            <artifactId>gson</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.httpcomponents</groupId>
-            <artifactId>httpclient</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.springframework.cloud</groupId>
-            <artifactId>spring-cloud-starter-config</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.springframework.cloud</groupId>
-            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
-        </dependency>
-        
-        <dependency>
-            <groupId>junit</groupId>
-            <artifactId>junit</artifactId>
-            <scope>test</scope>
-        </dependency>
-    </dependencies>
-
-    <build>
-        <finalName>skywalking-web</finalName>
-        <resources>
-
-        </resources>
-        <plugins>
-            <plugin>
-                <artifactId>maven-compiler-plugin</artifactId>
-                <configuration>
-                    <source>${compiler.version}</source>
-                    <target>${compiler.version}</target>
-                    <encoding>${project.build.sourceEncoding}</encoding>
-                </configuration>
-            </plugin>
-            <plugin>
-                <groupId>com.github.eirslett</groupId>
-                <artifactId>frontend-maven-plugin</artifactId>
-                <version>1.6</version>
-                <configuration>
-                    <workingDirectory>src/main/frontend</workingDirectory>
-                    <nodeVersion>v8.9.4</nodeVersion>
-                </configuration>
-                <executions>
-                    <execution>
-                        <id>install node and npm</id>
-                        <goals>
-                            <goal>install-node-and-npm</goal>
-                        </goals>
-                    </execution>
-                    <execution>
-                        <id>npm install</id>
-                        <goals>
-                            <goal>npm</goal>
-                        </goals>
-                        <configuration>
-                            <arguments>install</arguments>
-                        </configuration>
-                    </execution>
-                    <execution>
-                        <id>npm run build</id>
-                        <goals>
-                            <goal>npm</goal>
-                        </goals>
-                        <configuration>
-                            <arguments>run build</arguments>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-resources-plugin</artifactId>
-                <configuration>
-                    <encoding>${project.build.sourceEncoding}</encoding>
-                    <outputDirectory>${project.build.directory}</outputDirectory>
-                    <resources>
-                        <resource>
-                            <targetPath>${basedir}/target/classes/public</targetPath>
-                            <directory>src/main/frontend/dist</directory>
-                        </resource>
-                        <resource>
-                            <targetPath>${basedir}/target/classes</targetPath>
-                            <directory>src/main/resources</directory>
-                        </resource>
-                    </resources>
-                </configuration>
-            </plugin>
-            <plugin>
-                <groupId>org.springframework.boot</groupId>
-                <artifactId>spring-boot-maven-plugin</artifactId>
-            </plugin>
-        </plugins>
-    </build>
-</project>
diff --git a/public/favicon.png b/public/favicon.png
new file mode 100644
index 0000000..cc27768
Binary files /dev/null and b/public/favicon.png differ
diff --git a/src/assets/logo.svg b/src/assets/logo.svg
new file mode 100644
index 0000000..e9f8c2a
--- /dev/null
+++ b/src/assets/logo.svg
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg width="200px" height="200px" viewBox="0 0 200 200" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <!-- Generator: Sketch 47.1 (45422) - http://www.bohemiancoding.com/sketch -->
+    <title>Group 28 Copy 5</title>
+    <desc>Created with Sketch.</desc>
+    <defs>
+        <linearGradient x1="62.1023273%" y1="0%" x2="108.19718%" y2="37.8635764%" id="linearGradient-1">
+            <stop stop-color="#4285EB" offset="0%"></stop>
+            <stop stop-color="#2EC7FF" offset="100%"></stop>
+        </linearGradient>
+        <linearGradient x1="69.644116%" y1="0%" x2="54.0428975%" y2="108.456714%" id="linearGradient-2">
+            <stop stop-color="#29CDFF" offset="0%"></stop>
+            <stop stop-color="#148EFF" offset="37.8600687%"></stop>
+            <stop stop-color="#0A60FF" offset="100%"></stop>
+        </linearGradient>
+        <linearGradient x1="69.6908165%" y1="-12.9743587%" x2="16.7228981%" y2="117.391248%" id="linearGradient-3">
+            <stop stop-color="#FA816E" offset="0%"></stop>
+            <stop stop-color="#F74A5C" offset="41.472606%"></stop>
+            <stop stop-color="#F51D2C" offset="100%"></stop>
+        </linearGradient>
+        <linearGradient x1="68.1279872%" y1="-35.6905737%" x2="30.4400914%" y2="114.942679%" id="linearGradient-4">
+            <stop stop-color="#FA8E7D" offset="0%"></stop>
+            <stop stop-color="#F74A5C" offset="51.2635191%"></stop>
+            <stop stop-color="#F51D2C" offset="100%"></stop>
+        </linearGradient>
+    </defs>
+    <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="logo" transform="translate(-20.000000, -20.000000)">
+            <g id="Group-28-Copy-5" transform="translate(20.000000, 20.000000)">
+                <g id="Group-27-Copy-3">
+                    <g id="Group-25" fill-rule="nonzero">
+                        <g id="2">
+                            <path d="M91.5880863,4.17652823 L4.17996544,91.5127728 C-0.519240605,96.2081146 -0.519240605,103.791885 4.17996544,108.487227 L91.5880863,195.823472 C96.2872923,200.518814 103.877304,200.518814 108.57651,195.823472 L145.225487,159.204632 C149.433969,154.999611 149.433969,148.181924 145.225487,143.976903 C141.017005,139.771881 134.193707,139.771881 129.985225,143.976903 L102.20193,171.737352 C101.032305,172.906015 99.2571609,172.906015 98.0875359,171.737352 L28 [...]
+                            <path d="M91.5880863,4.17652823 L4.17996544,91.5127728 C-0.519240605,96.2081146 -0.519240605,103.791885 4.17996544,108.487227 L91.5880863,195.823472 C96.2872923,200.518814 103.877304,200.518814 108.57651,195.823472 L145.225487,159.204632 C149.433969,154.999611 149.433969,148.181924 145.225487,143.976903 C141.017005,139.771881 134.193707,139.771881 129.985225,143.976903 L102.20193,171.737352 C101.032305,172.906015 99.2571609,172.906015 98.0875359,171.737352 L28 [...]
+                        </g>
+                        <path d="M153.685633,135.854579 C157.894115,140.0596 164.717412,140.0596 168.925894,135.854579 L195.959977,108.842726 C200.659183,104.147384 200.659183,96.5636133 195.960527,91.8688194 L168.690777,64.7181159 C164.472332,60.5180858 157.646868,60.5241425 153.435895,64.7316526 C149.227413,68.936674 149.227413,75.7543607 153.435895,79.9593821 L171.854035,98.3623765 C173.02366,99.5310396 173.02366,101.304724 171.854035,102.473387 L153.685633,120.626849 C149.47715,124.8 [...]
+                    </g>
+                    <ellipse id="Combined-Shape" fill="url(#linearGradient-4)" cx="100.519339" cy="100.436681" rx="23.6001926" ry="23.580786"></ellipse>
+                </g>
+            </g>
+        </g>
+    </g>
+</svg>
\ No newline at end of file
diff --git a/src/main/frontend/public/img/logo/sw-2.png b/src/assets/sw-2.png
similarity index 100%
rename from src/main/frontend/public/img/logo/sw-2.png
rename to src/assets/sw-2.png
diff --git a/src/common/menu.js b/src/common/menu.js
new file mode 100644
index 0000000..75f47dc
--- /dev/null
+++ b/src/common/menu.js
@@ -0,0 +1,141 @@
+import { isUrl } from '../utils/utils';
+
+const menuData = [{
+  name: 'dashboard',
+  icon: 'dashboard',
+  path: 'dashboard',
+  children: [{
+    name: '分析页',
+    path: 'analysis',
+  }, {
+    name: '监控页',
+    path: 'monitor',
+  }, {
+    name: '工作台',
+    path: 'workplace',
+    // hideInMenu: true,
+  }],
+}, {
+  name: '表单页',
+  icon: 'form',
+  path: 'form',
+  children: [{
+    name: '基础表单',
+    path: 'basic-form',
+  }, {
+    name: '分步表单',
+    path: 'step-form',
+  }, {
+    name: '高级表单',
+    authority: 'admin',
+    path: 'advanced-form',
+  }],
+}, {
+  name: '列表页',
+  icon: 'table',
+  path: 'list',
+  children: [{
+    name: '查询表格',
+    path: 'table-list',
+  }, {
+    name: '标准列表',
+    path: 'basic-list',
+  }, {
+    name: '卡片列表',
+    path: 'card-list',
+  }, {
+    name: '搜索列表',
+    path: 'search',
+    children: [{
+      name: '搜索列表(文章)',
+      path: 'articles',
+    }, {
+      name: '搜索列表(项目)',
+      path: 'projects',
+    }, {
+      name: '搜索列表(应用)',
+      path: 'applications',
+    }],
+  }],
+}, {
+  name: '详情页',
+  icon: 'profile',
+  path: 'profile',
+  children: [{
+    name: '基础详情页',
+    path: 'basic',
+  }, {
+    name: '高级详情页',
+    path: 'advanced',
+    authority: 'admin',
+  }],
+}, {
+  name: '结果页',
+  icon: 'check-circle-o',
+  path: 'result',
+  children: [{
+    name: '成功',
+    path: 'success',
+  }, {
+    name: '失败',
+    path: 'fail',
+  }],
+}, {
+  name: '异常页',
+  icon: 'warning',
+  path: 'exception',
+  children: [{
+    name: '403',
+    path: '403',
+  }, {
+    name: '404',
+    path: '404',
+  }, {
+    name: '500',
+    path: '500',
+  }, {
+    name: '触发异常',
+    path: 'trigger',
+    hideInMenu: true,
+  }],
+}, {
+  name: '账户',
+  icon: 'user',
+  path: 'user',
+  authority: 'guest',
+  children: [{
+    name: '登录',
+    path: 'login',
+  }, {
+    name: '注册',
+    path: 'register',
+  }, {
+    name: '注册结果',
+    path: 'register-result',
+  }],
+}, {
+  name: '使用文档',
+  icon: 'book',
+  path: 'http://pro.ant.design/docs/getting-started',
+  target: '_blank',
+}];
+
+function formatter(data, parentPath = '', parentAuthority) {
+  return data.map((item) => {
+    let { path } = item;
+    if (!isUrl(path)) {
+      path = parentPath + item.path;
+    }
+    const result = {
+      ...item,
+      path,
+      authority: item.authority || parentAuthority,
+    };
+    if (item.children) {
+      result.children = formatter(item.children, `${parentPath}${item.path}/`, item.authority);
+    }
+    return result;
+  });
+}
+
+export const getMenuData = () => formatter(menuData);
diff --git a/src/common/router.js b/src/common/router.js
new file mode 100644
index 0000000..5df2477
--- /dev/null
+++ b/src/common/router.js
@@ -0,0 +1,196 @@
+import { createElement } from 'react';
+import dynamic from 'dva/dynamic';
+import pathToRegexp from 'path-to-regexp';
+import { getMenuData } from './menu';
+
+let routerDataCache;
+
+const modelNotExisted = (app, model) => (
+  // eslint-disable-next-line
+  !app._models.some(({ namespace }) => {
+    return namespace === model.substring(model.lastIndexOf('/') + 1);
+  })
+);
+
+// wrapper of dynamic
+const dynamicWrapper = (app, models, component) => {
+  // () => require('module')
+  // transformed by babel-plugin-dynamic-import-node-sync
+  if (component.toString().indexOf('.then(') < 0) {
+    models.forEach((model) => {
+      if (modelNotExisted(app, model)) {
+        // eslint-disable-next-line
+        app.model(require(`../models/${model}`).default);
+      }
+    });
+    return (props) => {
+      if (!routerDataCache) {
+        routerDataCache = getRouterData(app);
+      }
+      return createElement(component().default, {
+        ...props,
+        routerData: routerDataCache,
+      });
+    };
+  }
+  // () => import('module')
+  return dynamic({
+    app,
+    models: () => models.filter(
+      model => modelNotExisted(app, model)).map(m => import(`../models/${m}.js`)
+    ),
+    // add routerData prop
+    component: () => {
+      if (!routerDataCache) {
+        routerDataCache = getRouterData(app);
+      }
+      return component().then((raw) => {
+        const Component = raw.default || raw;
+        return props => createElement(Component, {
+          ...props,
+          routerData: routerDataCache,
+        });
+      });
+    },
+  });
+};
+
+function getFlatMenuData(menus) {
+  let keys = {};
+  menus.forEach((item) => {
+    if (item.children) {
+      keys[item.path] = { ...item };
+      keys = { ...keys, ...getFlatMenuData(item.children) };
+    } else {
+      keys[item.path] = { ...item };
+    }
+  });
+  return keys;
+}
+
+export const getRouterData = (app) => {
+  const routerConfig = {
+    '/': {
+      component: dynamicWrapper(app, ['user', 'login'], () => import('../layouts/BasicLayout')),
+    },
+    '/dashboard/analysis': {
+      component: dynamicWrapper(app, ['chart'], () => import('../routes/Dashboard/Analysis')),
+    },
+    '/dashboard/monitor': {
+      component: dynamicWrapper(app, ['monitor'], () => import('../routes/Dashboard/Monitor')),
+    },
+    '/dashboard/workplace': {
+      component: dynamicWrapper(app, ['project', 'activities', 'chart'], () => import('../routes/Dashboard/Workplace')),
+      // hideInBreadcrumb: true,
+      // name: '工作台',
+      // authority: 'admin',
+    },
+    '/form/basic-form': {
+      component: dynamicWrapper(app, ['form'], () => import('../routes/Forms/BasicForm')),
+    },
+    '/form/step-form': {
+      component: dynamicWrapper(app, ['form'], () => import('../routes/Forms/StepForm')),
+    },
+    '/form/step-form/info': {
+      component: dynamicWrapper(app, ['form'], () => import('../routes/Forms/StepForm/Step1')),
+    },
+    '/form/step-form/confirm': {
+      component: dynamicWrapper(app, ['form'], () => import('../routes/Forms/StepForm/Step2')),
+    },
+    '/form/step-form/result': {
+      component: dynamicWrapper(app, ['form'], () => import('../routes/Forms/StepForm/Step3')),
+    },
+    '/form/advanced-form': {
+      component: dynamicWrapper(app, ['form'], () => import('../routes/Forms/AdvancedForm')),
+    },
+    '/list/table-list': {
+      component: dynamicWrapper(app, ['rule'], () => import('../routes/List/TableList')),
+    },
+    '/list/basic-list': {
+      component: dynamicWrapper(app, ['list'], () => import('../routes/List/BasicList')),
+    },
+    '/list/card-list': {
+      component: dynamicWrapper(app, ['list'], () => import('../routes/List/CardList')),
+    },
+    '/list/search': {
+      component: dynamicWrapper(app, ['list'], () => import('../routes/List/List')),
+    },
+    '/list/search/projects': {
+      component: dynamicWrapper(app, ['list'], () => import('../routes/List/Projects')),
+    },
+    '/list/search/applications': {
+      component: dynamicWrapper(app, ['list'], () => import('../routes/List/Applications')),
+    },
+    '/list/search/articles': {
+      component: dynamicWrapper(app, ['list'], () => import('../routes/List/Articles')),
+    },
+    '/profile/basic': {
+      component: dynamicWrapper(app, ['profile'], () => import('../routes/Profile/BasicProfile')),
+    },
+    '/profile/advanced': {
+      component: dynamicWrapper(app, ['profile'], () => import('../routes/Profile/AdvancedProfile')),
+    },
+    '/result/success': {
+      component: dynamicWrapper(app, [], () => import('../routes/Result/Success')),
+    },
+    '/result/fail': {
+      component: dynamicWrapper(app, [], () => import('../routes/Result/Error')),
+    },
+    '/exception/403': {
+      component: dynamicWrapper(app, [], () => import('../routes/Exception/403')),
+    },
+    '/exception/404': {
+      component: dynamicWrapper(app, [], () => import('../routes/Exception/404')),
+    },
+    '/exception/500': {
+      component: dynamicWrapper(app, [], () => import('../routes/Exception/500')),
+    },
+    '/exception/trigger': {
+      component: dynamicWrapper(app, ['error'], () => import('../routes/Exception/triggerException')),
+    },
+    '/user': {
+      component: dynamicWrapper(app, [], () => import('../layouts/UserLayout')),
+    },
+    '/user/login': {
+      component: dynamicWrapper(app, ['login'], () => import('../routes/User/Login')),
+    },
+    '/user/register': {
+      component: dynamicWrapper(app, ['register'], () => import('../routes/User/Register')),
+    },
+    '/user/register-result': {
+      component: dynamicWrapper(app, [], () => import('../routes/User/RegisterResult')),
+    },
+    // '/user/:id': {
+    //   component: dynamicWrapper(app, [], () => import('../routes/User/SomeComponent')),
+    // },
+  };
+  // Get name from ./menu.js or just set it in the router data.
+  const menuData = getFlatMenuData(getMenuData());
+
+  // Route configuration data
+  // eg. {name,authority ...routerConfig }
+  const routerData = {};
+  // The route matches the menu
+  Object.keys(routerConfig).forEach((path) => {
+    // Regular match item name
+    // eg.  router /user/:id === /user/chen
+    const pathRegexp = pathToRegexp(path);
+    const menuKey = Object.keys(menuData).find(key => pathRegexp.test(`/${key}`));
+    let menuItem = {};
+    // If menuKey is not empty
+    if (menuKey) {
+      menuItem = menuData[menuKey];
+    }
+    let router = routerConfig[path];
+    // If you need to configure complex parameter routing,
+    // https://github.com/ant-design/ant-design-pro-site/blob/master/docs/router-and-nav.md#%E5%B8%A6%E5%8F%82%E6%95%B0%E7%9A%84%E8%B7%AF%E7%94%B1%E8%8F%9C%E5%8D%95
+    // eg . /list/:type/user/info/:id
+    router = {
+      ...router,
+      name: router.name || menuItem.name,
+      authority: router.authority || menuItem.authority,
+    };
+    routerData[path] = router;
+  });
+  return routerData;
+};
diff --git a/src/components/ActiveChart/index.js b/src/components/ActiveChart/index.js
new file mode 100644
index 0000000..d708641
--- /dev/null
+++ b/src/components/ActiveChart/index.js
@@ -0,0 +1,82 @@
+import React, { Component } from 'react';
+
+import { MiniArea } from '../Charts';
+import NumberInfo from '../NumberInfo';
+
+import styles from './index.less';
+
+function fixedZero(val) {
+  return val * 1 < 10 ? `0${val}` : val;
+}
+
+function getActiveData() {
+  const activeData = [];
+  for (let i = 0; i < 24; i += 1) {
+    activeData.push({
+      x: `${fixedZero(i)}:00`,
+      y: Math.floor(Math.random() * 200) + (i * 50),
+    });
+  }
+  return activeData;
+}
+
+export default class ActiveChart extends Component {
+  state = {
+    activeData: getActiveData(),
+  };
+
+  componentDidMount() {
+    this.timer = setInterval(() => {
+      this.setState({
+        activeData: getActiveData(),
+      });
+    }, 1000);
+  }
+
+  componentWillUnmount() {
+    clearInterval(this.timer);
+  }
+
+  render() {
+    const { activeData = [] } = this.state;
+
+    return (
+      <div className={styles.activeChart}>
+        <NumberInfo subTitle="目标评估" total="有望达到预期" />
+        <div style={{ marginTop: 32 }}>
+          <MiniArea
+            animate={false}
+            line
+            borderWidth={2}
+            height={84}
+            scale={{
+              y: {
+                tickCount: 3,
+              },
+            }}
+            yAxis={{
+              tickLine: false,
+              label: false,
+              title: false,
+              line: false,
+            }}
+            data={activeData}
+          />
+        </div>
+        {activeData && (
+          <div className={styles.activeChartGrid}>
+            <p>{[...activeData].sort()[activeData.length - 1].y + 200} 亿元</p>
+            <p>{[...activeData].sort()[Math.floor(activeData.length / 2)].y} 亿元</p>
+          </div>
+        )}
+        {activeData && (
+          <div className={styles.activeChartLegend}>
+            <span>00:00</span>
+            <span>{activeData[Math.floor(activeData.length / 2)].x}</span>
+            <span>{activeData[activeData.length - 1].x}</span>
+          </div>
+        )}
+      </div>
+    );
+  }
+}
diff --git a/src/components/ActiveChart/index.less b/src/components/ActiveChart/index.less
new file mode 100644
index 0000000..8ecc323
--- /dev/null
+++ b/src/components/ActiveChart/index.less
@@ -0,0 +1,31 @@
+.activeChart {
+  position: relative;
+}
+.activeChartGrid {
+  p {
+    position: absolute;
+    top: 80px;
+  }
+  p:last-child {
+    top: 115px;
+  }
+}
+.activeChartLegend {
+  position: relative;
+  font-size: 0;
+  margin-top: 8px;
+  height: 20px;
+  line-height: 20px;
+  span {
+    display: inline-block;
+    font-size: 12px;
+    text-align: center;
+    width: 33.33%;
+  }
+  span:first-child {
+    text-align: left;
+  }
+  span:last-child {
+    text-align: right;
+  }
+}
diff --git a/src/components/Authorized/Authorized.js b/src/components/Authorized/Authorized.js
new file mode 100644
index 0000000..d9a2a78
--- /dev/null
+++ b/src/components/Authorized/Authorized.js
@@ -0,0 +1,16 @@
+import React from 'react';
+import CheckPermissions from './CheckPermissions';
+
+class Authorized extends React.Component {
+  render() {
+    const { children, authority, noMatch = null } = this.props;
+    const childrenRender = typeof children === 'undefined' ? null : children;
+    return CheckPermissions(
+      authority,
+      childrenRender,
+      noMatch
+    );
+  }
+}
+
+export default Authorized;
diff --git a/src/components/Authorized/AuthorizedRoute.js b/src/components/Authorized/AuthorizedRoute.js
new file mode 100644
index 0000000..3d03226
--- /dev/null
+++ b/src/components/Authorized/AuthorizedRoute.js
@@ -0,0 +1,23 @@
+import React from 'react';
+import { Route, Redirect } from 'react-router-dom';
+import Authorized from './Authorized';
+
+class AuthorizedRoute extends React.Component {
+  render() {
+    const { component: Component, render, authority,
+      redirectPath, ...rest } = this.props;
+    return (
+      <Authorized
+        authority={authority}
+        noMatch={<Route {...rest} render={() => <Redirect to={{ pathname: redirectPath }} />} />}
+      >
+        <Route
+          {...rest}
+          render={props => (Component ? <Component {...props} /> : render(props))}
+        />
+      </Authorized>
+    );
+  }
+}
+
+export default AuthorizedRoute;
diff --git a/src/components/Authorized/CheckPermissions.js b/src/components/Authorized/CheckPermissions.js
new file mode 100644
index 0000000..0a7dbae
--- /dev/null
+++ b/src/components/Authorized/CheckPermissions.js
@@ -0,0 +1,67 @@
+import React from 'react';
+import PromiseRender from './PromiseRender';
+import { CURRENT } from './index';
+
+function isPromise(obj) {
+  return !!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function';
+}
+
+/**
+ * 通用权限检查方法
+ * Common check permissions method
+ * @param { 权限判定 Permission judgment type string |array | Promise | Function } authority
+ * @param { 你的权限 Your permission description  type:string} currentAuthority
+ * @param { 通过的组件 Passing components } target
+ * @param { 未通过的组件 no pass components } Exception
+ */
+const checkPermissions = (authority, currentAuthority, target, Exception) => {
+  // 没有判定权限.默认查看所有
+  // Retirement authority, return target;
+  if (!authority) {
+    return target;
+  }
+  // 数组处理
+  if (Array.isArray(authority)) {
+    if (authority.indexOf(currentAuthority) >= 0) {
+      return target;
+    }
+    return Exception;
+  }
+
+  // string 处理
+  if (typeof authority === 'string') {
+    if (authority === currentAuthority) {
+      return target;
+    }
+    return Exception;
+  }
+
+  // Promise 处理
+  if (isPromise(authority)) {
+    return () => (
+      <PromiseRender ok={target} error={Exception} promise={authority} />
+    );
+  }
+
+  // Function 处理
+  if (typeof authority === 'function') {
+    try {
+      const bool = authority(currentAuthority);
+      if (bool) {
+        return target;
+      }
+      return Exception;
+    } catch (error) {
+      throw error;
+    }
+  }
+  throw new Error('unsupported parameters');
+};
+
+export { checkPermissions };
+
+const check = (authority, target, Exception) => {
+  return checkPermissions(authority, CURRENT, target, Exception);
+};
+
+export default check;
diff --git a/src/components/Authorized/CheckPermissions.test.js b/src/components/Authorized/CheckPermissions.test.js
new file mode 100644
index 0000000..eda08a7
--- /dev/null
+++ b/src/components/Authorized/CheckPermissions.test.js
@@ -0,0 +1,45 @@
+import { checkPermissions } from './CheckPermissions.js';
+
+const target = 'ok';
+const error = 'error';
+
+describe('test CheckPermissions', () => {
+  it('Correct string permission authentication', () => {
+    expect(checkPermissions('user', 'user', target, error)).toEqual('ok');
+  });
+  it('Correct string permission authentication', () => {
+    expect(checkPermissions('user', 'NULL', target, error)).toEqual('error');
+  });
+  it('authority is undefined , return ok', () => {
+    expect(checkPermissions(null, 'NULL', target, error)).toEqual('ok');
+  });
+  it('currentAuthority is undefined , return error', () => {
+    expect(checkPermissions('admin', null, target, error)).toEqual('error');
+  });
+  it('Wrong string permission authentication', () => {
+    expect(checkPermissions('admin', 'user', target, error)).toEqual('error');
+  });
+  it('Correct Array permission authentication', () => {
+    expect(checkPermissions(['user', 'admin'], 'user', target, error)).toEqual(
+      'ok'
+    );
+  });
+  it('Wrong Array permission authentication,currentAuthority error', () => {
+    expect(
+      checkPermissions(['user', 'admin'], 'user,admin', target, error)
+    ).toEqual('error');
+  });
+  it('Wrong Array permission authentication', () => {
+    expect(checkPermissions(['user', 'admin'], 'guest', target, error)).toEqual(
+      'error'
+    );
+  });
+  it('Wrong Function permission authentication', () => {
+    expect(checkPermissions(() => false, 'guest', target, error)).toEqual(
+      'error'
+    );
+  });
+  it('Correct Function permission authentication', () => {
+    expect(checkPermissions(() => true, 'guest', target, error)).toEqual('ok');
+  });
+});
diff --git a/src/components/Authorized/PromiseRender.js b/src/components/Authorized/PromiseRender.js
new file mode 100644
index 0000000..78f762d
--- /dev/null
+++ b/src/components/Authorized/PromiseRender.js
@@ -0,0 +1,39 @@
+import React from 'react';
+import { Spin } from 'antd';
+
+export default class PromiseRender extends React.PureComponent {
+  state = {
+    component: false,
+  };
+  async componentDidMount() {
+    this.props.promise
+      .then(() => {
+        this.setState({
+          component: this.props.ok,
+        });
+      })
+      .catch(() => {
+        this.setState({
+          component: this.props.error,
+        });
+      });
+  }
+  render() {
+    const C = this.state.component;
+    return C ? (
+      <C {...this.props} />
+    ) : (
+      <div
+        style={{
+          width: '100%',
+          height: '100%',
+          margin: 'auto',
+          paddingTop: 50,
+          textAlign: 'center',
+        }}
+      >
+        <Spin size="large" />
+      </div>
+    );
+  }
+}
diff --git a/src/components/Authorized/Secured.js b/src/components/Authorized/Secured.js
new file mode 100644
index 0000000..1dc6fb1
--- /dev/null
+++ b/src/components/Authorized/Secured.js
@@ -0,0 +1,49 @@
+import React from 'react';
+import Exception from '../Exception/index';
+import CheckPermissions from './CheckPermissions';
+/**
+ * 默认不能访问任何页面
+ * default is "NULL"
+ */
+const Exception403 = () => (
+  <Exception type="403" style={{ minHeight: 500, height: '80%' }} />
+);
+
+/**
+ * 用于判断是否拥有权限访问此view权限
+ * authority 支持传入  string ,funtion:()=>boolean|Promise
+ * e.g. 'user' 只有user用户能访问
+ * e.g. 'user,admin' user和 admin 都能访问
+ * e.g. ()=>boolean 返回true能访问,返回false不能访问
+ * e.g. Promise  then 能访问   catch不能访问
+ * e.g. authority support incoming string, funtion: () => boolean | Promise
+ * e.g. 'user' only user user can access
+ * e.g. 'user, admin' user and admin can access
+ * e.g. () => boolean true to be able to visit, return false can not be accessed
+ * e.g. Promise then can not access the visit to catch
+ * @param {string | function | Promise} authority
+ * @param {ReactNode} error 非必需参数
+ */
+const authorize = (authority, error) => {
+  /**
+   * conversion into a class
+   * 防止传入字符串时找不到staticContext造成报错
+   * String parameters can cause staticContext not found error
+   */
+  let classError = false;
+  if (error) {
+    classError = () => error;
+  }
+  if (!authority) {
+    throw new Error('authority is required');
+  }
+  return function decideAuthority(targer) {
+    return CheckPermissions(
+      authority,
+      targer,
+      classError || Exception403
+    );
+  };
+};
+
+export default authorize;
diff --git a/src/components/Authorized/demo/AuthorizedArray.md b/src/components/Authorized/demo/AuthorizedArray.md
new file mode 100644
index 0000000..46eaf76
--- /dev/null
+++ b/src/components/Authorized/demo/AuthorizedArray.md
@@ -0,0 +1,23 @@
+---
+order: 1
+title: 
+  zh-CN: 使用数组作为参数
+  en-US: Use Array as a parameter
+---
+
+Use Array as a parameter
+
+```jsx
+import RenderAuthorized from 'ant-design-pro/lib/Authorized';
+import { Alert } from 'antd';
+
+const Authorized = RenderAuthorized('user');
+const noMatch = <Alert message="No permission." type="error" showIcon />;
+
+ReactDOM.render(
+  <Authorized authority={['user', 'admin']} noMatch={noMatch}>
+    <Alert message="Use Array as a parameter passed!" type="success" showIcon />
+  </Authorized>,
+  mountNode,
+);
+```
diff --git a/src/components/Authorized/demo/AuthorizedFunction.md b/src/components/Authorized/demo/AuthorizedFunction.md
new file mode 100644
index 0000000..8ad8b91
--- /dev/null
+++ b/src/components/Authorized/demo/AuthorizedFunction.md
@@ -0,0 +1,31 @@
+---
+order: 2
+title: 
+  zh-CN: 使用方法作为参数
+  en-US: Use function as a parameter
+---
+
+Use Function as a parameter
+
+```jsx
+import RenderAuthorized from 'ant-design-pro/lib/Authorized';
+import { Alert } from 'antd';
+
+const Authorized = RenderAuthorized('user');
+const noMatch = <Alert message="No permission." type="error" showIcon />;
+
+const havePermission = () => {
+  return false;
+};
+
+ReactDOM.render(
+  <Authorized authority={havePermission} noMatch={noMatch}>
+    <Alert
+      message="Use Function as a parameter passed!"
+      type="success"
+      showIcon
+    />
+  </Authorized>,
+  mountNode,
+);
+```
diff --git a/src/components/Authorized/demo/basic.md b/src/components/Authorized/demo/basic.md
new file mode 100644
index 0000000..a5f12f2
--- /dev/null
+++ b/src/components/Authorized/demo/basic.md
@@ -0,0 +1,25 @@
+---
+order: 0
+title: 
+  zh-CN: 基本使用
+  en-US: Basic use
+---
+
+Basic use
+
+```jsx
+import RenderAuthorized from 'ant-design-pro/lib/Authorized';
+import { Alert } from 'antd';
+
+const Authorized = RenderAuthorized('user');
+const noMatch = <Alert message="No permission." type="error" showIcon />;
+
+ReactDOM.render(
+  <div>
+    <Authorized authority="admin" noMatch={noMatch}>
+      <Alert message="user Passed!" type="success" showIcon />
+    </Authorized>
+  </div>,
+  mountNode,
+);
+```
diff --git a/src/components/Authorized/demo/secured.md b/src/components/Authorized/demo/secured.md
new file mode 100644
index 0000000..1e9537a
--- /dev/null
+++ b/src/components/Authorized/demo/secured.md
@@ -0,0 +1,28 @@
+---
+order: 3
+title: 
+  zh-CN: 注解基本使用
+  en-US: Basic use secured
+---
+
+secured demo used
+
+```jsx
+import RenderAuthorized from 'ant-design-pro/lib/Authorized';
+import { Alert } from 'antd';
+
+const { Secured } = RenderAuthorized('user');
+
+@Secured('admin')
+class TestSecuredString extends React.Component {
+  render() {
+    <Alert message="user Passed!" type="success" showIcon />;
+  }
+}
+ReactDOM.render(
+  <div>
+    <TestSecuredString />
+  </div>,
+  mountNode,
+);
+```
diff --git a/src/components/Authorized/index.d.ts b/src/components/Authorized/index.d.ts
new file mode 100644
index 0000000..4a68fa1
--- /dev/null
+++ b/src/components/Authorized/index.d.ts
@@ -0,0 +1,48 @@
+import * as React from 'react';
+import { RouteProps } from 'react-router';
+
+type authorityFN = (currentAuthority?: string) => boolean;
+
+type authority = string | Array<string> | authorityFN | Promise<any>;
+
+export type IReactComponent<P = any> =
+  | React.StatelessComponent<P>
+  | React.ComponentClass<P>
+  | React.ClassicComponentClass<P>;
+
+interface Secured {
+  (authority: authority, error?: React.ReactNode): <T extends IReactComponent>(
+    target: T,
+  ) => T;
+}
+
+export interface AuthorizedRouteProps extends RouteProps {
+  authority: authority;
+}
+export class AuthorizedRoute extends React.Component<
+  AuthorizedRouteProps,
+  any
+> {}
+
+interface check {
+  <T extends IReactComponent, S extends IReactComponent>(
+    authority: authority,
+    target: T,
+    Exception: S,
+  ): T | S;
+}
+
+interface AuthorizedProps {
+  authority: authority;
+  noMatch?: React.ReactNode;
+}
+
+export class Authorized extends React.Component<AuthorizedProps, any> {
+  static Secured: Secured;
+  static AuthorizedRoute: typeof AuthorizedRoute;
+  static check: check;
+}
+
+declare function renderAuthorize(currentAuthority: string): typeof Authorized;
+
+export default renderAuthorize;
diff --git a/src/components/Authorized/index.js b/src/components/Authorized/index.js
new file mode 100644
index 0000000..c39de29
--- /dev/null
+++ b/src/components/Authorized/index.js
@@ -0,0 +1,32 @@
+import Authorized from './Authorized';
+import AuthorizedRoute from './AuthorizedRoute';
+import Secured from './Secured';
+import check from './CheckPermissions.js';
+
+/* eslint-disable import/no-mutable-exports */
+let CURRENT = 'NULL';
+
+Authorized.Secured = Secured;
+Authorized.AuthorizedRoute = AuthorizedRoute;
+Authorized.check = check;
+
+/**
+ * use  authority or getAuthority
+ * @param {string|()=>String} currentAuthority
+ */
+const renderAuthorize = (currentAuthority) => {
+  if (currentAuthority) {
+    if (currentAuthority.constructor.name === 'Function') {
+      CURRENT = currentAuthority();
+    }
+    if (currentAuthority.constructor.name === 'String') {
+      CURRENT = currentAuthority;
+    }
+  } else {
+    CURRENT = 'NULL';
+  }
+  return Authorized;
+};
+
+export { CURRENT };
+export default renderAuthorize;
diff --git a/src/components/Authorized/index.md b/src/components/Authorized/index.md
new file mode 100644
index 0000000..51588bb
--- /dev/null
+++ b/src/components/Authorized/index.md
@@ -0,0 +1,58 @@
+---
+title:
+  en-US: Authorized
+  zh-CN: Authorized
+subtitle: 权限
+cols: 1
+order: 15
+---
+
+权限组件,通过比对现有权限与准入权限,决定相关元素的展示。
+
+## API
+
+### RenderAuthorized
+
+`RenderAuthorized: (currentAuthority: string | () => string) => Authorized`
+
+权限组件默认 export RenderAuthorized 函数,它接收当前权限作为参数,返回一个权限对象,该对象提供以下几种使用方式。
+
+
+### Authorized
+
+最基础的权限控制。
+
+| 参数      | 说明                                      | 类型         | 默认值 |
+|----------|------------------------------------------|-------------|-------|
+| children    | 正常渲染的元素,权限判断通过时展示           | ReactNode  | - |
+| authority   | 准入权限/权限判断         | `string | array | Promise | (currentAuthority) => boolean` | - |
+| noMatch     | 权限异常渲染元素,权限判断不通过时展示        | ReactNode  | - |
+
+### Authorized.AuthorizedRoute
+
+| 参数      | 说明                                      | 类型         | 默认值 |
+|----------|------------------------------------------|-------------|-------|
+| authority     | 准入权限/权限判断         | `string | array | Promise | (currentAuthority) => boolean` | - |
+| redirectPath  | 权限异常时重定向的页面路由                | string  | - |
+
+其余参数与 `Route` 相同。
+
+### Authorized.Secured
+
+注解方式,`@Authorized.Secured(authority, error)`
+
+| 参数      | 说明                                      | 类型         | 默认值 |
+|----------|------------------------------------------|-------------|-------|
+| authority     | 准入权限/权限判断         | `string | Promise | (currentAuthority) => boolean` | - |
+| error  | 权限异常时渲染元素                |  ReactNode | <Exception type="403" /> |
+
+### Authorized.check
+
+函数形式的 Authorized,用于某些不能被 HOC 包裹的组件。 `Authorized.check(authority, target, Exception)`  
+注意:传入一个 Promise 时,无论正确还是错误返回的都是一个 ReactClass。
+
+| 参数      | 说明                                      | 类型         | 默认值 |
+|----------|------------------------------------------|-------------|-------|
+| authority     | 准入权限/权限判断         | `string | Promise | (currentAuthority) => boolean` | - |
+| target     | 权限判断通过时渲染的元素         | ReactNode | - |
+| Exception  | 权限异常时渲染元素                |  ReactNode | - |
diff --git a/src/components/AvatarList/demo/simple.md b/src/components/AvatarList/demo/simple.md
new file mode 100644
index 0000000..e941aea
--- /dev/null
+++ b/src/components/AvatarList/demo/simple.md
@@ -0,0 +1,20 @@
+---
+order: 0
+title: 
+  zh-CN: 基础样例 
+  en-US: Basic Usage
+---
+
+Simplest of usage.
+
+````jsx
+import AvatarList from 'ant-design-pro/lib/AvatarList';
+
+ReactDOM.render(
+  <AvatarList size="mini">
+    <AvatarList.Item tips="Jake" src="https://gw.alipayobjects.com/zos/rmsportal/zOsKZmFRdUtvpqCImOVY.png" />
+    <AvatarList.Item tips="Andy" src="https://gw.alipayobjects.com/zos/rmsportal/sfjbOqnsXXJgNCjCzDBL.png" />
+    <AvatarList.Item tips="Niko" src="https://gw.alipayobjects.com/zos/rmsportal/kZzEzemZyKLKFsojXItE.png" />
+  </AvatarList>
+, mountNode);
+````
diff --git a/src/components/AvatarList/index.d.ts b/src/components/AvatarList/index.d.ts
new file mode 100644
index 0000000..101a70d
--- /dev/null
+++ b/src/components/AvatarList/index.d.ts
@@ -0,0 +1,23 @@
+import * as React from "react";
+export interface AvatarItemProps {
+  tips: React.ReactNode;
+  src: string;
+  style?: React.CSSProperties;
+}
+
+export interface AvatarListProps {
+  size?: "large" | "small" | "mini" | "default";
+  style?: React.CSSProperties;
+  children:
+    | React.ReactElement<AvatarItem>
+    | Array<React.ReactElement<AvatarItem>>;
+}
+
+declare class AvatarItem extends React.Component<AvatarItemProps, any> {
+  constructor(props: AvatarItemProps);
+}
+
+export default class AvatarList extends React.Component<AvatarListProps, any> {
+  constructor(props: AvatarListProps);
+  static Item: typeof AvatarItem;
+}
diff --git a/src/components/AvatarList/index.en-US.md b/src/components/AvatarList/index.en-US.md
new file mode 100644
index 0000000..58daaf9
--- /dev/null
+++ b/src/components/AvatarList/index.en-US.md
@@ -0,0 +1,22 @@
+---
+title: AvatarList
+order: 1
+cols: 1
+---
+
+A list of user's avatar for project or group member list frequently. If a large or small AvatarList is desired, set the `size` property to either `large` or `small` and `mini` respectively. Omit the `size` property for a AvatarList with the default size.
+
+## API
+
+### AvatarList
+
+| Property | Description | Type | Default |
+|----------|------------------------------------------|-------------|-------|
+| size | size of list | `large`、`small` 、`mini`, `default` | `default` |
+
+### AvatarList.Item
+
+| Property | Description | Type | Default |
+|----------|------------------------------------------|-------------|-------|
+| tips | title tips for avatar item | ReactNode\/string | - |
+| src | the address of the image for an image avatar | string | - |
diff --git a/src/components/AvatarList/index.js b/src/components/AvatarList/index.js
new file mode 100644
index 0000000..08c502f
--- /dev/null
+++ b/src/components/AvatarList/index.js
@@ -0,0 +1,43 @@
+import React from 'react';
+import { Tooltip, Avatar } from 'antd';
+import classNames from 'classnames';
+
+import styles from './index.less';
+
+const AvatarList = ({ children, size, ...other }) => {
+  const childrenWithProps = React.Children.map(children, child =>
+    React.cloneElement(child, {
+      size,
+    })
+  );
+
+  return (
+    <div {...other} className={styles.avatarList}>
+      <ul> {childrenWithProps} </ul>
+    </div>
+  );
+};
+
+const Item = ({ src, size, tips, onClick = (() => {}) }) => {
+  const cls = classNames(styles.avatarItem, {
+    [styles.avatarItemLarge]: size === 'large',
+    [styles.avatarItemSmall]: size === 'small',
+    [styles.avatarItemMini]: size === 'mini',
+  });
+
+  return (
+    <li className={cls} onClick={onClick} >
+      {
+        tips ? (
+          <Tooltip title={tips}>
+            <Avatar src={src} size={size} style={{ cursor: 'pointer' }} />
+          </Tooltip>
+        ) : <Avatar src={src} size={size} />
+      }
+    </li>
+  );
+};
+
+AvatarList.Item = Item;
+
+export default AvatarList;
diff --git a/src/components/AvatarList/index.less b/src/components/AvatarList/index.less
new file mode 100644
index 0000000..601babd
--- /dev/null
+++ b/src/components/AvatarList/index.less
@@ -0,0 +1,45 @@
+@import "~antd/lib/style/themes/default.less";
+
+.avatarList {
+  display: inline-block;
+  ul {
+    display: inline-block;
+    margin-left: 8px;
+    font-size: 0;
+  }
+}
+
+.avatarItem {
+  display: inline-block;
+  font-size: @font-size-base;
+  margin-left: -8px;
+  width: @avatar-size-base;
+  height: @avatar-size-base;
+  :global {
+    .ant-avatar {
+      border: 1px solid #fff;
+    }
+  }
+}
+
+.avatarItemLarge {
+  width: @avatar-size-lg;
+  height: @avatar-size-lg;
+}
+
+.avatarItemSmall {
+  width: @avatar-size-sm;
+  height: @avatar-size-sm;
+}
+
+.avatarItemMini {
+  width: 20px;
+  height: 20px;
+  :global {
+    .ant-avatar {
+      width: 20px;
+      height: 20px;
+      line-height: 20px;
+    }
+  }
+}
diff --git a/src/components/AvatarList/index.zh-CN.md b/src/components/AvatarList/index.zh-CN.md
new file mode 100644
index 0000000..c229a5d
--- /dev/null
+++ b/src/components/AvatarList/index.zh-CN.md
@@ -0,0 +1,23 @@
+---
+title: AvatarList
+subtitle: 用户头像列表
+order: 1
+cols: 1
+---
+
+一组用户头像,常用在项目/团队成员列表。可通过设置 `size` 属性来指定头像大小。
+
+## API
+
+### AvatarList
+
+| 参数      | 说明                                      | 类型         | 默认值 |
+|----------|------------------------------------------|-------------|-------|
+| size | 头像大小 | `large`、`small` 、`mini`, `default` | `default` |
+
+### AvatarList.Item
+
+| 参数      | 说明                                      | 类型         | 默认值 |
+|----------|------------------------------------------|-------------|-------|
+| tips | 头像展示文案 | ReactNode\/string | - |
+| src | 头像图片连接 | string | - |
diff --git a/src/main/frontend/src/components/Charts/Bar/index.d.ts b/src/components/Charts/Bar/index.d.ts
similarity index 77%
rename from src/main/frontend/src/components/Charts/Bar/index.d.ts
rename to src/components/Charts/Bar/index.d.ts
index fd2d05d..7be2a1a 100644
--- a/src/main/frontend/src/components/Charts/Bar/index.d.ts
+++ b/src/components/Charts/Bar/index.d.ts
@@ -2,13 +2,14 @@ import * as React from "react";
 export interface BarProps {
   title: React.ReactNode;
   color?: string;
-  margin?: [number, number, number, number];
+  padding?: [number, number, number, number];
   height: number;
   data: Array<{
     x: string;
     y: number;
   }>;
   autoLabel?: boolean;
+  style?: React.CSSProperties;
 }
 
 export default class Bar extends React.Component<BarProps, any> {}
diff --git a/src/components/Charts/Bar/index.js b/src/components/Charts/Bar/index.js
new file mode 100644
index 0000000..9eee7a0
--- /dev/null
+++ b/src/components/Charts/Bar/index.js
@@ -0,0 +1,113 @@
+import React, { Component } from 'react';
+import { Chart, Axis, Tooltip, Geom } from 'bizcharts';
+import Debounce from 'lodash-decorators/debounce';
+import Bind from 'lodash-decorators/bind';
+import autoHeight from '../autoHeight';
+import styles from '../index.less';
+
+@autoHeight()
+class Bar extends Component {
+  state = {
+    autoHideXLabels: false,
+  };
+
+  componentDidMount() {
+    window.addEventListener('resize', this.resize);
+  }
+
+  componentWillUnmount() {
+    window.removeEventListener('resize', this.resize);
+  }
+
+  @Bind()
+  @Debounce(400)
+  resize() {
+    if (!this.node) {
+      return;
+    }
+    const canvasWidth = this.node.parentNode.clientWidth;
+    const { data = [], autoLabel = true } = this.props;
+    if (!autoLabel) {
+      return;
+    }
+    const minWidth = data.length * 30;
+    const { autoHideXLabels } = this.state;
+
+    if (canvasWidth <= minWidth) {
+      if (!autoHideXLabels) {
+        this.setState({
+          autoHideXLabels: true,
+        });
+      }
+    } else if (autoHideXLabels) {
+      this.setState({
+        autoHideXLabels: false,
+      });
+    }
+  }
+
+  handleRoot = (n) => {
+    this.root = n;
+  };
+
+  handleRef = (n) => {
+    this.node = n;
+  };
+
+  render() {
+    const {
+      height,
+      title,
+      forceFit = true,
+      data,
+      color = 'rgba(24, 144, 255, 0.85)',
+      padding,
+    } = this.props;
+
+    const { autoHideXLabels } = this.state;
+
+    const scale = {
+      x: {
+        type: 'cat',
+      },
+      y: {
+        min: 0,
+      },
+    };
+
+    const tooltip = [
+      'x*y',
+      (x, y) => ({
+        name: x,
+        value: y,
+      }),
+    ];
+
+    return (
+      <div className={styles.chart} style={{ height }} ref={this.handleRoot}>
+        <div ref={this.handleRef}>
+          {title && <h4 style={{ marginBottom: 20 }}>{title}</h4>}
+          <Chart
+            scale={scale}
+            height={title ? height - 41 : height}
+            forceFit={forceFit}
+            data={data}
+            padding={padding || 'auto'}
+          >
+            <Axis
+              name="x"
+              title={false}
+              label={autoHideXLabels ? false : {}}
+              tickLine={autoHideXLabels ? false : {}}
+            />
+            <Axis name="y" min={0} />
+            <Tooltip showTitle={false} crosshairs={false} />
+            <Geom type="interval" position="x*y" color={color} tooltip={tooltip} />
+          </Chart>
+        </div>
+      </div>
+    );
+  }
+}
+
+export default Bar;
diff --git a/src/main/frontend/src/components/Charts/ChartCard/index.d.ts b/src/components/Charts/ChartCard/index.d.ts
similarity index 91%
rename from src/main/frontend/src/components/Charts/ChartCard/index.d.ts
rename to src/components/Charts/ChartCard/index.d.ts
index 21d2be3..35a5852 100644
--- a/src/main/frontend/src/components/Charts/ChartCard/index.d.ts
+++ b/src/components/Charts/ChartCard/index.d.ts
@@ -6,6 +6,7 @@ export interface ChartCardProps {
   footer?: React.ReactNode;
   contentHeight?: number;
   avatar?: React.ReactNode;
+  style?: React.CSSProperties;
 }
 
 export default class ChartCard extends React.Component<ChartCardProps, any> {}
diff --git a/src/main/frontend/src/components/Charts/ChartCard/index.js b/src/components/Charts/ChartCard/index.js
similarity index 95%
rename from src/main/frontend/src/components/Charts/ChartCard/index.js
rename to src/components/Charts/ChartCard/index.js
index a472682..db2c462 100644
--- a/src/main/frontend/src/components/Charts/ChartCard/index.js
+++ b/src/components/Charts/ChartCard/index.js
@@ -52,7 +52,7 @@ const ChartCard = ({
       bodyStyle={{ padding: '20px 24px 8px 24px' }}
       {...rest}
     >
-      {<Spin spinning={loading}>{content}</Spin>}
+      {<Spin spinning={loading} wrapperClassName={styles.spin}>{content}</Spin>}
     </Card>
   );
 };
diff --git a/src/main/frontend/src/components/Charts/ChartCard/index.less b/src/components/Charts/ChartCard/index.less
similarity index 95%
rename from src/main/frontend/src/components/Charts/ChartCard/index.less
rename to src/components/Charts/ChartCard/index.less
index bdc573b..02a1d7e 100644
--- a/src/main/frontend/src/components/Charts/ChartCard/index.less
+++ b/src/components/Charts/ChartCard/index.less
@@ -72,3 +72,7 @@
     margin-top: 20px;
   }
 }
+
+.spin :global(.ant-spin-container) {
+  overflow: visible;
+}
diff --git a/src/main/frontend/src/components/Charts/Field/index.d.ts b/src/components/Charts/Field/index.d.ts
similarity index 85%
rename from src/main/frontend/src/components/Charts/Field/index.d.ts
rename to src/components/Charts/Field/index.d.ts
index 7fa1328..b1f779c 100644
--- a/src/main/frontend/src/components/Charts/Field/index.d.ts
+++ b/src/components/Charts/Field/index.d.ts
@@ -2,6 +2,7 @@ import * as React from "react";
 export interface FieldProps {
   label: React.ReactNode;
   value: React.ReactNode;
+  style?: React.CSSProperties;
 }
 
 export default class Field extends React.Component<FieldProps, any> {}
diff --git a/src/main/frontend/src/components/Charts/Field/index.js b/src/components/Charts/Field/index.js
similarity index 100%
rename from src/main/frontend/src/components/Charts/Field/index.js
rename to src/components/Charts/Field/index.js
diff --git a/src/main/frontend/src/components/Charts/Field/index.less b/src/components/Charts/Field/index.less
similarity index 100%
rename from src/main/frontend/src/components/Charts/Field/index.less
rename to src/components/Charts/Field/index.less
diff --git a/src/main/frontend/src/components/Charts/Gauge/index.d.ts b/src/components/Charts/Gauge/index.d.ts
similarity index 88%
rename from src/main/frontend/src/components/Charts/Gauge/index.d.ts
rename to src/components/Charts/Gauge/index.d.ts
index 7f196ae..218fccf 100644
--- a/src/main/frontend/src/components/Charts/Gauge/index.d.ts
+++ b/src/components/Charts/Gauge/index.d.ts
@@ -5,6 +5,7 @@ export interface GaugeProps {
   height: number;
   bgColor?: number;
   percent: number;
+  style?: React.CSSProperties;
 }
 
 export default class Gauge extends React.Component<GaugeProps, any> {}
diff --git a/src/components/Charts/Gauge/index.js b/src/components/Charts/Gauge/index.js
new file mode 100644
index 0000000..608b0f2
--- /dev/null
+++ b/src/components/Charts/Gauge/index.js
@@ -0,0 +1,167 @@
+import React from 'react';
+import { Chart, Geom, Axis, Coord, Guide, Shape } from 'bizcharts';
+import autoHeight from '../autoHeight';
+
+const { Arc, Html, Line } = Guide;
+
+const defaultFormatter = (val) => {
+  switch (val) {
+    case '2':
+      return '差';
+    case '4':
+      return '中';
+    case '6':
+      return '良';
+    case '8':
+      return '优';
+    default:
+      return '';
+  }
+};
+
+Shape.registerShape('point', 'pointer', {
+  drawShape(cfg, group) {
+    let point = cfg.points[0];
+    point = this.parsePoint(point);
+    const center = this.parsePoint({
+      x: 0,
+      y: 0,
+    });
+    group.addShape('line', {
+      attrs: {
+        x1: center.x,
+        y1: center.y,
+        x2: point.x,
+        y2: point.y,
+        stroke: cfg.color,
+        lineWidth: 2,
+        lineCap: 'round',
+      },
+    });
+    return group.addShape('circle', {
+      attrs: {
+        x: center.x,
+        y: center.y,
+        r: 6,
+        stroke: cfg.color,
+        lineWidth: 3,
+        fill: '#fff',
+      },
+    });
+  },
+});
+
+@autoHeight()
+export default class Gauge extends React.Component {
+  render() {
+    const {
+      title,
+      height,
+      percent,
+      forceFit = true,
+      formatter = defaultFormatter,
+      color = '#2F9CFF',
+      bgColor = '#F0F2F5',
+    } = this.props;
+    const cols = {
+      value: {
+        type: 'linear',
+        min: 0,
+        max: 10,
+        tickCount: 6,
+        nice: true,
+      },
+    };
+    const data = [{ value: percent / 10 }];
+    return (
+      <Chart height={height} data={data} scale={cols} padding={[-16, 0, 16, 0]} forceFit={forceFit}>
+        <Coord type="polar" startAngle={-1.25 * Math.PI} endAngle={0.25 * Math.PI} radius={0.8} />
+        <Axis name="1" line={null} />
+        <Axis
+          line={null}
+          tickLine={null}
+          subTickLine={null}
+          name="value"
+          zIndex={2}
+          gird={null}
+          label={{
+            offset: -12,
+            formatter,
+            textStyle: {
+              fontSize: 12,
+              fill: 'rgba(0, 0, 0, 0.65)',
+              textAlign: 'center',
+            },
+          }}
+        />
+        <Guide>
+          <Line
+            start={[3, 0.905]}
+            end={[3, 0.85]}
+            lineStyle={{
+              stroke: color,
+              lineDash: null,
+              lineWidth: 2,
+            }}
+          />
+          <Line
+            start={[5, 0.905]}
+            end={[5, 0.85]}
+            lineStyle={{
+              stroke: color,
+              lineDash: null,
+              lineWidth: 3,
+            }}
+          />
+          <Line
+            start={[7, 0.905]}
+            end={[7, 0.85]}
+            lineStyle={{
+              stroke: color,
+              lineDash: null,
+              lineWidth: 3,
+            }}
+          />
+          <Arc
+            zIndex={0}
+            start={[0, 0.965]}
+            end={[10, 0.965]}
+            style={{
+              stroke: bgColor,
+              lineWidth: 10,
+            }}
+          />
+          <Arc
+            zIndex={1}
+            start={[0, 0.965]}
+            end={[data[0].value, 0.965]}
+            style={{
+              stroke: color,
+              lineWidth: 10,
+            }}
+          />
+          <Html
+            position={['50%', '95%']}
+            html={() => {
+              return `
+                <div style="width: 300px;text-align: center;font-size: 12px!important;">
+                  <p style="font-size: 14px; color: rgba(0,0,0,0.43);margin: 0;">${title}</p>
+                  <p style="font-size: 24px;color: rgba(0,0,0,0.85);margin: 0;">
+                    ${data[0].value * 10}%
+                  </p>
+                </div>`;
+            }}
+          />
+        </Guide>
+        <Geom
+          line={false}
+          type="point"
+          position="value*1"
+          shape="pointer"
+          color={color}
+          active={false}
+        />
+      </Chart>
+    );
+  }
+}
diff --git a/src/main/frontend/src/components/Charts/MiniArea/index.d.ts b/src/components/Charts/MiniArea/index.d.ts
similarity index 100%
rename from src/main/frontend/src/components/Charts/MiniArea/index.d.ts
rename to src/components/Charts/MiniArea/index.d.ts
diff --git a/src/components/Charts/MiniArea/index.js b/src/components/Charts/MiniArea/index.js
new file mode 100644
index 0000000..a5526a9
--- /dev/null
+++ b/src/components/Charts/MiniArea/index.js
@@ -0,0 +1,106 @@
+import React from 'react';
+import { Chart, Axis, Tooltip, Geom } from 'bizcharts';
+import autoHeight from '../autoHeight';
+import styles from '../index.less';
+
+@autoHeight()
+export default class MiniArea extends React.Component {
+  render() {
+    const {
+      height,
+      data = [],
+      forceFit = true,
+      color = 'rgba(24, 144, 255, 0.2)',
+      borderColor = '#1089ff',
+      scale = {},
+      borderWidth = 2,
+      line,
+      xAxis,
+      yAxis,
+      animate = true,
+    } = this.props;
+
+    const padding = [36, 5, 30, 5];
+
+    const scaleProps = {
+      x: {
+        type: 'cat',
+        range: [0, 1],
+        ...scale.x,
+      },
+      y: {
+        min: 0,
+        ...scale.y,
+      },
+    };
+
+    const tooltip = [
+      'x*y',
+      (x, y) => ({
+        name: x,
+        value: y,
+      }),
+    ];
+
+    const chartHeight = height + 54;
+
+    return (
+      <div className={styles.miniChart} style={{ height }}>
+        <div className={styles.chartContent}>
+          {height > 0 && (
+            <Chart
+              animate={animate}
+              scale={scaleProps}
+              height={chartHeight}
+              forceFit={forceFit}
+              data={data}
+              padding={padding}
+            >
+              <Axis
+                key="axis-x"
+                name="x"
+                label={false}
+                line={false}
+                tickLine={false}
+                grid={false}
+                {...xAxis}
+              />
+              <Axis
+                key="axis-y"
+                name="y"
+                label={false}
+                line={false}
+                tickLine={false}
+                grid={false}
+                {...yAxis}
+              />
+              <Tooltip showTitle={false} crosshairs={false} />
+              <Geom
+                type="area"
+                position="x*y"
+                color={color}
+                tooltip={tooltip}
+                shape="smooth"
+                style={{
+                  fillOpacity: 1,
+                }}
+              />
+              {line ? (
+                <Geom
+                  type="line"
+                  position="x*y"
+                  shape="smooth"
+                  color={borderColor}
+                  size={borderWidth}
+                  tooltip={false}
+                />
+              ) : (
+                <span style={{ display: 'none' }} />
+              )}
+            </Chart>
+          )}
+        </div>
+      </div>
+    );
+  }
+}
diff --git a/src/main/frontend/src/components/Charts/MiniBar/index.d.ts b/src/components/Charts/MiniBar/index.d.ts
similarity index 67%
rename from src/main/frontend/src/components/Charts/MiniBar/index.d.ts
rename to src/components/Charts/MiniBar/index.d.ts
index 09bd761..3e2f1ec 100644
--- a/src/main/frontend/src/components/Charts/MiniBar/index.d.ts
+++ b/src/components/Charts/MiniBar/index.d.ts
@@ -1,11 +1,12 @@
-import * as React from "react";
+import * as React from 'react';
 export interface MiniBarProps {
   color?: string;
   height: number;
   data: Array<{
-    x: number;
+    x: number | string;
     y: number;
   }>;
+  style?: React.CSSProperties;
 }
 
 export default class MiniBar extends React.Component<MiniBarProps, any> {}
diff --git a/src/components/Charts/MiniBar/index.js b/src/components/Charts/MiniBar/index.js
new file mode 100644
index 0000000..92ee6b5
--- /dev/null
+++ b/src/components/Charts/MiniBar/index.js
@@ -0,0 +1,50 @@
+import React from 'react';
+import { Chart, Tooltip, Geom } from 'bizcharts';
+import autoHeight from '../autoHeight';
+import styles from '../index.less';
+
+@autoHeight()
+export default class MiniBar extends React.Component {
+  render() {
+    const { height, forceFit = true, color = '#1890FF', data = [] } = this.props;
+
+    const scale = {
+      x: {
+        type: 'cat',
+      },
+      y: {
+        min: 0,
+      },
+    };
+
+    const padding = [36, 5, 30, 5];
+
+    const tooltip = [
+      'x*y',
+      (x, y) => ({
+        name: x,
+        value: y,
+      }),
+    ];
+
+    // for tooltip not to be hide
+    const chartHeight = height + 54;
+
+    return (
+      <div className={styles.miniChart} style={{ height }}>
+        <div className={styles.chartContent}>
+          <Chart
+            scale={scale}
+            height={chartHeight}
+            forceFit={forceFit}
+            data={data}
+            padding={padding}
+          >
+            <Tooltip showTitle={false} crosshairs={false} />
+            <Geom type="interval" position="x*y" color={color} tooltip={tooltip} />
+          </Chart>
+        </div>
+      </div>
+    );
+  }
+}
diff --git a/src/main/frontend/src/components/Charts/MiniProgress/index.d.ts b/src/components/Charts/MiniProgress/index.d.ts
similarity index 88%
rename from src/main/frontend/src/components/Charts/MiniProgress/index.d.ts
rename to src/components/Charts/MiniProgress/index.d.ts
index a80b935..4dde605 100644
--- a/src/main/frontend/src/components/Charts/MiniProgress/index.d.ts
+++ b/src/components/Charts/MiniProgress/index.d.ts
@@ -4,6 +4,7 @@ export interface MiniProgressProps {
   color?: string;
   strokeWidth?: number;
   percent?: number;
+  style?: React.CSSProperties;
 }
 
 export default class MiniProgress extends React.Component<
diff --git a/src/main/frontend/src/components/Charts/MiniProgress/index.js b/src/components/Charts/MiniProgress/index.js
similarity index 100%
rename from src/main/frontend/src/components/Charts/MiniProgress/index.js
rename to src/components/Charts/MiniProgress/index.js
diff --git a/src/main/frontend/src/components/Charts/MiniProgress/index.less b/src/components/Charts/MiniProgress/index.less
similarity index 100%
rename from src/main/frontend/src/components/Charts/MiniProgress/index.less
rename to src/components/Charts/MiniProgress/index.less
diff --git a/src/main/frontend/src/components/Charts/Pie/index.d.ts b/src/components/Charts/Pie/index.d.ts
similarity index 78%
rename from src/main/frontend/src/components/Charts/Pie/index.d.ts
rename to src/components/Charts/Pie/index.d.ts
index 44a465d..fe2e2a8 100644
--- a/src/main/frontend/src/components/Charts/Pie/index.d.ts
+++ b/src/components/Charts/Pie/index.d.ts
@@ -1,13 +1,13 @@
-import * as React from "react";
+import * as React from 'react';
 export interface PieProps {
   animate?: boolean;
   color?: string;
   height: number;
   hasLegend?: boolean;
-  margin?: [number, number, number, number];
+  padding?: [number, number, number, number];
   percent?: number;
   data?: Array<{
-    x: string;
+    x: string | string;
     y: number;
   }>;
   total?: string;
diff --git a/src/components/Charts/Pie/index.js b/src/components/Charts/Pie/index.js
new file mode 100644
index 0000000..ac5703c
--- /dev/null
+++ b/src/components/Charts/Pie/index.js
@@ -0,0 +1,247 @@
+import React, { Component } from 'react';
+import { Chart, Tooltip, Geom, Coord } from 'bizcharts';
+import { DataView } from '@antv/data-set';
+import { Divider } from 'antd';
+import classNames from 'classnames';
+import ReactFitText from 'react-fittext';
+import Debounce from 'lodash-decorators/debounce';
+import Bind from 'lodash-decorators/bind';
+import autoHeight from '../autoHeight';
+
+import styles from './index.less';
+
+/* eslint react/no-danger:0 */
+@autoHeight()
+export default class Pie extends Component {
+  state = {
+    legendData: [],
+    legendBlock: false,
+  };
+
+  componentDidMount() {
+    this.getLengendData();
+    this.resize();
+    window.addEventListener('resize', this.resize);
+  }
+
+  componentWillReceiveProps(nextProps) {
+    if (this.props.data !== nextProps.data) {
+      this.getLengendData();
+    }
+  }
+
+  componentWillUnmount() {
+    window.removeEventListener('resize', this.resize);
+    this.resize.cancel();
+  }
+
+  getG2Instance = (chart) => {
+    this.chart = chart;
+  };
+
+  // for custom lengend view
+  getLengendData = () => {
+    if (!this.chart) return;
+    const geom = this.chart.getAllGeoms()[0]; // 获取所有的图形
+    const items = geom.get('dataArray') || []; // 获取图形对应的
+
+    const legendData = items.map((item) => {
+      /* eslint no-underscore-dangle:0 */
+      const origin = item[0]._origin;
+      origin.color = item[0].color;
+      origin.checked = true;
+      return origin;
+    });
+
+    this.setState({
+      legendData,
+    });
+  };
+
+  // for window resize auto responsive legend
+  @Bind()
+  @Debounce(300)
+  resize() {
+    const { hasLegend } = this.props;
+    if (!hasLegend || !this.root) {
+      window.removeEventListener('resize', this.resize);
+      return;
+    }
+    if (this.root.parentNode.clientWidth <= 380) {
+      if (!this.state.legendBlock) {
+        this.setState({
+          legendBlock: true,
+        });
+      }
+    } else if (this.state.legendBlock) {
+      this.setState({
+        legendBlock: false,
+      });
+    }
+  }
+
+  handleRoot = (n) => {
+    this.root = n;
+  };
+
+  handleLegendClick = (item, i) => {
+    const newItem = item;
+    newItem.checked = !newItem.checked;
+
+    const { legendData } = this.state;
+    legendData[i] = newItem;
+
+    const filteredLegendData = legendData.filter(l => l.checked).map(l => l.x);
+
+    if (this.chart) {
+      this.chart.filter('x', val => filteredLegendData.indexOf(val) > -1);
+    }
+
+    this.setState({
+      legendData,
+    });
+  };
+
+  render() {
+    const {
+      valueFormat,
+      subTitle,
+      total,
+      hasLegend = false,
+      className,
+      style,
+      height,
+      forceFit = true,
+      percent = 0,
+      color,
+      inner = 0.75,
+      animate = true,
+      colors,
+      lineWidth = 1,
+    } = this.props;
+
+    const { legendData, legendBlock } = this.state;
+    const pieClassName = classNames(styles.pie, className, {
+      [styles.hasLegend]: !!hasLegend,
+      [styles.legendBlock]: legendBlock,
+    });
+
+    const defaultColors = colors;
+    let data = this.props.data || [];
+    let selected = this.props.selected || true;
+    let tooltip = this.props.tooltip || true;
+    let formatColor;
+
+    const scale = {
+      x: {
+        type: 'cat',
+        range: [0, 1],
+      },
+      y: {
+        min: 0,
+      },
+    };
+
+    if (percent) {
+      selected = false;
+      tooltip = false;
+      formatColor = (value) => {
+        if (value === '占比') {
+          return color || 'rgba(24, 144, 255, 0.85)';
+        } else {
+          return '#F0F2F5';
+        }
+      };
+
+      data = [
+        {
+          x: '占比',
+          y: parseFloat(percent),
+        },
+        {
+          x: '反比',
+          y: 100 - parseFloat(percent),
+        },
+      ];
+    }
+
+    const tooltipFormat = [
+      'x*percent',
+      (x, p) => ({
+        name: x,
+        value: `${(p * 100).toFixed(2)}%`,
+      }),
+    ];
+
+    const padding = [12, 0, 12, 0];
+
+    const dv = new DataView();
+    dv.source(data).transform({
+      type: 'percent',
+      field: 'y',
+      dimension: 'x',
+      as: 'percent',
+    });
+
+    return (
+      <div ref={this.handleRoot} className={pieClassName} style={style}>
+        <ReactFitText maxFontSize={25}>
+          <div className={styles.chart}>
+            <Chart
+              scale={scale}
+              height={height}
+              forceFit={forceFit}
+              data={dv}
+              padding={padding}
+              animate={animate}
+              onGetG2Instance={this.getG2Instance}
+            >
+              {!!tooltip && <Tooltip showTitle={false} />}
+              <Coord type="theta" innerRadius={inner} />
+              <Geom
+                style={{ lineWidth, stroke: '#fff' }}
+                tooltip={tooltip && tooltipFormat}
+                type="intervalStack"
+                position="percent"
+                color={['x', percent ? formatColor : defaultColors]}
+                selected={selected}
+              />
+            </Chart>
+
+            {(subTitle || total) && (
+              <div className={styles.total}>
+                {subTitle && <h4 className="pie-sub-title">{subTitle}</h4>}
+                {/* eslint-disable-next-line */}
+                {total && <div className="pie-stat" dangerouslySetInnerHTML={{ __html: total }} />}
+              </div>
+            )}
+          </div>
+        </ReactFitText>
+
+        {hasLegend && (
+          <ul className={styles.legend}>
+            {legendData.map((item, i) => (
+              <li key={item.x} onClick={() => this.handleLegendClick(item, i)}>
+                <span
+                  className={styles.dot}
+                  style={{ backgroundColor: !item.checked ? '#aaa' : item.color }}
+                />
+                <span className={styles.legendTitle}>{item.x}</span>
+                <Divider type="vertical" />
+                <span className={styles.percent}>
+                  {`${(isNaN(item.percent) ? 0 : item.percent * 100).toFixed(2)}%`}
+                </span>
+                <span
+                  className={styles.value}
+                  dangerouslySetInnerHTML={{
+                    __html: valueFormat ? valueFormat(item.y) : item.y,
+                  }}
+                />
+              </li>
+            ))}
+          </ul>
+        )}
+      </div>
+    );
+  }
+}
diff --git a/src/main/frontend/src/components/Charts/Pie/index.less b/src/components/Charts/Pie/index.less
similarity index 100%
rename from src/main/frontend/src/components/Charts/Pie/index.less
rename to src/components/Charts/Pie/index.less
diff --git a/src/main/frontend/src/components/Charts/Radar/index.d.ts b/src/components/Charts/Radar/index.d.ts
similarity index 78%
rename from src/main/frontend/src/components/Charts/Radar/index.d.ts
rename to src/components/Charts/Radar/index.d.ts
index fa85978..772cbf0 100644
--- a/src/main/frontend/src/components/Charts/Radar/index.d.ts
+++ b/src/components/Charts/Radar/index.d.ts
@@ -2,13 +2,14 @@ import * as React from "react";
 export interface RadarProps {
   title?: React.ReactNode;
   height: number;
-  margin?: [number, number, number, number];
+  padding?: [number, number, number, number];
   hasLegend?: boolean;
   data: Array<{
     name: string;
     label: string;
     value: string;
   }>;
+  style?: React.CSSProperties;
 }
 
 export default class Radar extends React.Component<RadarProps, any> {}
diff --git a/src/components/Charts/Radar/index.js b/src/components/Charts/Radar/index.js
new file mode 100644
index 0000000..03aaa70
--- /dev/null
+++ b/src/components/Charts/Radar/index.js
@@ -0,0 +1,180 @@
+import React, { Component } from 'react';
+import { Chart, Tooltip, Geom, Coord, Axis } from 'bizcharts';
+import { Row, Col } from 'antd';
+import autoHeight from '../autoHeight';
+import styles from './index.less';
+
+/* eslint react/no-danger:0 */
+@autoHeight()
+export default class Radar extends Component {
+  state = {
+    legendData: [],
+  };
+
+  componentDidMount() {
+    this.getLengendData();
+  }
+
+  componentWillReceiveProps(nextProps) {
+    if (this.props.data !== nextProps.data) {
+      this.getLengendData();
+    }
+  }
+
+  getG2Instance = (chart) => {
+    this.chart = chart;
+  };
+
+  // for custom lengend view
+  getLengendData = () => {
+    if (!this.chart) return;
+    const geom = this.chart.getAllGeoms()[0]; // 获取所有的图形
+    const items = geom.get('dataArray') || []; // 获取图形对应的
+
+    const legendData = items.map((item) => {
+      // eslint-disable-next-line
+      const origins = item.map(t => t._origin);
+      const result = {
+        name: origins[0].name,
+        color: item[0].color,
+        checked: true,
+        value: origins.reduce((p, n) => p + n.value, 0),
+      };
+
+      return result;
+    });
+
+    this.setState({
+      legendData,
+    });
+  };
+
+  handleRef = (n) => {
+    this.node = n;
+  };
+
+  handleLegendClick = (item, i) => {
+    const newItem = item;
+    newItem.checked = !newItem.checked;
+
+    const { legendData } = this.state;
+    legendData[i] = newItem;
+
+    const filteredLegendData = legendData.filter(l => l.checked).map(l => l.name);
+
+    if (this.chart) {
+      this.chart.filter('name', val => filteredLegendData.indexOf(val) > -1);
+      this.chart.repaint();
+    }
+
+    this.setState({
+      legendData,
+    });
+  };
+
+  render() {
+    const defaultColors = [
+      '#1890FF',
+      '#FACC14',
+      '#2FC25B',
+      '#8543E0',
+      '#F04864',
+      '#13C2C2',
+      '#fa8c16',
+      '#a0d911',
+    ];
+
+    const {
+      data = [],
+      height = 0,
+      title,
+      hasLegend = false,
+      forceFit = true,
+      tickCount = 4,
+      padding = [35, 30, 16, 30],
+      animate = true,
+      colors = defaultColors,
+    } = this.props;
+
+    const { legendData } = this.state;
+
+    const scale = {
+      value: {
+        min: 0,
+        tickCount,
+      },
+    };
+
+    const chartHeight = height - (hasLegend ? 80 : 22);
+
+    return (
+      <div className={styles.radar} style={{ height }}>
+        <div>
+          {title && <h4>{title}</h4>}
+          <Chart
+            scale={scale}
+            height={chartHeight}
+            forceFit={forceFit}
+            data={data}
+            padding={padding}
+            animate={animate}
+            onGetG2Instance={this.getG2Instance}
+          >
+            <Tooltip />
+            <Coord type="polar" />
+            <Axis
+              name="label"
+              line={null}
+              tickLine={null}
+              grid={{
+                lineStyle: {
+                  lineDash: null,
+                },
+                hideFirstLine: false,
+              }}
+            />
+            <Axis
+              name="value"
+              grid={{
+                type: 'polygon',
+                lineStyle: {
+                  lineDash: null,
+                },
+              }}
+            />
+            <Geom type="line" position="label*value" color={['name', colors]} size={1} />
+            <Geom
+              type="point"
+              position="label*value"
+              color={['name', colors]}
+              shape="circle"
+              size={3}
+            />
+          </Chart>
+          {hasLegend && (
+            <Row className={styles.legend}>
+              {legendData.map((item, i) => (
+                <Col
+                  span={24 / legendData.length}
+                  key={item.name}
+                  onClick={() => this.handleLegendClick(item, i)}
+                >
+                  <div className={styles.legendItem}>
+                    <p>
+                      <span
+                        className={styles.dot}
+                        style={{ backgroundColor: !item.checked ? '#aaa' : item.color }}
+                      />
+                      <span>{item.name}</span>
+                    </p>
+                    <h6>{item.value}</h6>
+                  </div>
+                </Col>
+              ))}
+            </Row>
+          )}
+        </div>
+      </div>
+    );
+  }
+}
diff --git a/src/main/frontend/src/components/Charts/Radar/index.less b/src/components/Charts/Radar/index.less
similarity index 100%
rename from src/main/frontend/src/components/Charts/Radar/index.less
rename to src/components/Charts/Radar/index.less
diff --git a/src/main/frontend/src/components/Charts/TagCloud/index.d.ts b/src/components/Charts/TagCloud/index.d.ts
similarity index 87%
rename from src/main/frontend/src/components/Charts/TagCloud/index.d.ts
rename to src/components/Charts/TagCloud/index.d.ts
index e783213..e2dcc79 100644
--- a/src/main/frontend/src/components/Charts/TagCloud/index.d.ts
+++ b/src/components/Charts/TagCloud/index.d.ts
@@ -5,6 +5,7 @@ export interface TagCloudProps {
     value: number;
   }>;
   height: number;
+  style?: React.CSSProperties;
 }
 
 export default class TagCloud extends React.Component<TagCloudProps, any> {}
diff --git a/src/components/Charts/TagCloud/index.js b/src/components/Charts/TagCloud/index.js
new file mode 100644
index 0000000..77e63fa
--- /dev/null
+++ b/src/components/Charts/TagCloud/index.js
@@ -0,0 +1,164 @@
+import React, { Component } from 'react';
+import { Chart, Geom, Coord, Shape } from 'bizcharts';
+import DataSet from '@antv/data-set';
+import Debounce from 'lodash-decorators/debounce';
+import Bind from 'lodash-decorators/bind';
+import classNames from 'classnames';
+import autoHeight from '../autoHeight';
+import styles from './index.less';
+
+/* eslint no-underscore-dangle: 0 */
+/* eslint no-param-reassign: 0 */
+
+const imgUrl = 'https://gw.alipayobjects.com/zos/rmsportal/gWyeGLCdFFRavBGIDzWk.png';
+
+@autoHeight()
+class TagCloud extends Component {
+  state = {
+    dv: null,
+  };
+
+  componentDidMount() {
+    this.initTagCloud();
+    this.renderChart();
+    window.addEventListener('resize', this.resize);
+  }
+
+  componentWillReceiveProps(nextProps) {
+    if (JSON.stringify(nextProps.data) !== JSON.stringify(this.props.data)) {
+      this.renderChart(nextProps);
+    }
+  }
+
+  componentWillUnmount() {
+    this.isUnmount = true;
+    window.removeEventListener('resize', this.resize);
+  }
+
+  resize = () => {
+    this.renderChart();
+  };
+
+  saveRootRef = (node) => {
+    this.root = node;
+  };
+
+  initTagCloud = () => {
+    function getTextAttrs(cfg) {
+      return Object.assign(
+        {},
+        {
+          fillOpacity: cfg.opacity,
+          fontSize: cfg.origin._origin.size,
+          rotate: cfg.origin._origin.rotate,
+          text: cfg.origin._origin.text,
+          textAlign: 'center',
+          fontFamily: cfg.origin._origin.font,
+          fill: cfg.color,
+          textBaseline: 'Alphabetic',
+        },
+        cfg.style
+      );
+    }
+
+    // 给point注册一个词云的shape
+    Shape.registerShape('point', 'cloud', {
+      drawShape(cfg, container) {
+        const attrs = getTextAttrs(cfg);
+        return container.addShape('text', {
+          attrs: Object.assign(attrs, {
+            x: cfg.x,
+            y: cfg.y,
+          }),
+        });
+      },
+    });
+  };
+
+  @Bind()
+  @Debounce(500)
+  renderChart = (nextProps) => {
+    // const colors = ['#1890FF', '#41D9C7', '#2FC25B', '#FACC14', '#9AE65C'];
+    const { data, height } = nextProps || this.props;
+
+    if (data.length < 1 || !this.root) {
+      return;
+    }
+
+    const h = height * 4;
+    const w = this.root.offsetWidth * 4;
+
+    const onload = () => {
+      const dv = new DataSet.View().source(data);
+      const range = dv.range('value');
+      const [min, max] = range;
+      dv.transform({
+        type: 'tag-cloud',
+        fields: ['name', 'value'],
+        imageMask: this.imageMask,
+        font: 'Verdana',
+        size: [w, h], // 宽高设置最好根据 imageMask 做调整
+        padding: 5,
+        timeInterval: 5000, // max execute time
+        rotate() {
+          return 0;
+        },
+        fontSize(d) {
+          // eslint-disable-next-line
+          return Math.pow((d.value - min) / (max - min), 2) * (70 - 20) + 20;
+        },
+      });
+
+      if (this.isUnmount) {
+        return;
+      }
+
+      this.setState({
+        dv,
+        w,
+        h,
+      });
+    };
+
+    if (!this.imageMask) {
+      this.imageMask = new Image();
+      this.imageMask.crossOrigin = '';
+      this.imageMask.src = imgUrl;
+
+      this.imageMask.onload = onload;
+    } else {
+      onload();
+    }
+  };
+
+  render() {
+    const { className, height } = this.props;
+    const { dv, w, h } = this.state;
+
+    return (
+      <div
+        className={classNames(styles.tagCloud, className)}
+        style={{ width: '100%', height }}
+        ref={this.saveRootRef}
+      >
+        {dv && (
+          <Chart
+            width={w}
+            height={h}
+            data={dv}
+            padding={0}
+            scale={{
+              x: { nice: false },
+              y: { nice: false },
+            }}
+          >
+            <Coord reflect="y" />
+            <Geom type="point" position="x*y" color="text" shape="cloud" />
+          </Chart>
+        )}
+      </div>
+    );
+  }
+}
+
+export default TagCloud;
diff --git a/src/main/frontend/src/components/Charts/TagCloud/index.less b/src/components/Charts/TagCloud/index.less
similarity index 80%
rename from src/main/frontend/src/components/Charts/TagCloud/index.less
rename to src/components/Charts/TagCloud/index.less
index 96b1006..f5c12ad 100644
--- a/src/main/frontend/src/components/Charts/TagCloud/index.less
+++ b/src/components/Charts/TagCloud/index.less
@@ -1,4 +1,5 @@
 .tagCloud {
+  overflow: hidden;
   canvas {
     transform: scale(0.25);
     transform-origin: 0 0;
diff --git a/src/main/frontend/src/components/Charts/TimelineChart/index.d.ts b/src/components/Charts/TimelineChart/index.d.ts
similarity index 79%
rename from src/main/frontend/src/components/Charts/TimelineChart/index.d.ts
rename to src/components/Charts/TimelineChart/index.d.ts
index 5ea76a1..f9241fa 100644
--- a/src/main/frontend/src/components/Charts/TimelineChart/index.d.ts
+++ b/src/components/Charts/TimelineChart/index.d.ts
@@ -6,7 +6,9 @@ export interface TimelineChartProps {
     y2: string;
   }>;
   titleMap: { y1: string; y2: string };
+  padding?: [number, number, number, number];
   height?: number;
+  style?: React.CSSProperties;
 }
 
 export default class TimelineChart extends React.Component<
diff --git a/src/components/Charts/TimelineChart/index.js b/src/components/Charts/TimelineChart/index.js
new file mode 100644
index 0000000..3864983
--- /dev/null
+++ b/src/components/Charts/TimelineChart/index.js
@@ -0,0 +1,123 @@
+import React from 'react';
+import { Chart, Tooltip, Geom, Legend, Axis } from 'bizcharts';
+import DataSet from '@antv/data-set';
+import Slider from 'bizcharts-plugin-slider';
+import autoHeight from '../autoHeight';
+import styles from './index.less';
+
+@autoHeight()
+export default class TimelineChart extends React.Component {
+  render() {
+    const {
+      title,
+      height = 400,
+      padding = [60, 20, 40, 40],
+      titleMap = {
+        y1: 'y1',
+        y2: 'y2',
+      },
+      borderWidth = 2,
+      data = [
+        {
+          x: 0,
+          y1: 0,
+          y2: 0,
+        },
+      ],
+    } = this.props;
+
+    data.sort((a, b) => a.x - b.x);
+
+    let max;
+    if (data[0] && data[0].y1 && data[0].y2) {
+      max = Math.max(
+        [...data].sort((a, b) => b.y1 - a.y1)[0].y1,
+        [...data].sort((a, b) => b.y2 - a.y2)[0].y2
+      );
+    }
+
+    const ds = new DataSet({
+      state: {
+        start: data[0].x,
+        end: data[data.length - 1].x,
+      },
+    });
+
+    const dv = ds.createView();
+    dv
+      .source(data)
+      .transform({
+        type: 'filter',
+        callback: (obj) => {
+          const date = obj.x;
+          return date <= ds.state.end && date >= ds.state.start;
+        },
+      })
+      .transform({
+        type: 'map',
+        callback(row) {
+          const newRow = { ...row };
+          newRow[titleMap.y1] = row.y1;
+          newRow[titleMap.y2] = row.y2;
+          return newRow;
+        },
+      })
+      .transform({
+        type: 'fold',
+        fields: [titleMap.y1, titleMap.y2], // 展开字段集
+        key: 'key', // key字段
+        value: 'value', // value字段
+      });
+
+    const timeScale = {
+      type: 'time',
+      tickCount: 10,
+      mask: 'HH:MM',
+      range: [0, 1],
+    };
+
+    const cols = {
+      x: timeScale,
+      value: {
+        max,
+        min: 0,
+      },
+    };
+
+    const SliderGen = () => (
+      <Slider
+        padding={[0, padding[1] + 20, 0, padding[3]]}
+        width="auto"
+        height={26}
+        xAxis="x"
+        yAxis="y1"
+        scales={{ x: timeScale }}
+        data={data}
+        start={ds.state.start}
+        end={ds.state.end}
+        backgroundChart={{ type: 'line' }}
+        onChange={({ startValue, endValue }) => {
+          ds.setState('start', startValue);
+          ds.setState('end', endValue);
+        }}
+      />
+    );
+
+    return (
+      <div className={styles.timelineChart} style={{ height: height + 30 }}>
+        <div>
+          {title && <h4>{title}</h4>}
+          <Chart height={height} padding={padding} data={dv} scale={cols} forceFit>
+            <Axis name="x" />
+            <Tooltip />
+            <Legend name="key" position="top" />
+            <Geom type="line" position="x*value" size={borderWidth} color="key" />
+          </Chart>
+          <div style={{ marginRight: -20 }}>
+            <SliderGen />
+          </div>
+        </div>
+      </div>
+    );
+  }
+}
diff --git a/src/main/frontend/src/components/Charts/TimelineChart/index.less b/src/components/Charts/TimelineChart/index.less
similarity index 100%
rename from src/main/frontend/src/components/Charts/TimelineChart/index.less
rename to src/components/Charts/TimelineChart/index.less
diff --git a/src/main/frontend/src/components/Charts/WaterWave/index.d.ts b/src/components/Charts/WaterWave/index.d.ts
similarity index 75%
rename from src/main/frontend/src/components/Charts/WaterWave/index.d.ts
rename to src/components/Charts/WaterWave/index.d.ts
index 0fefbea..309db7b 100644
--- a/src/main/frontend/src/components/Charts/WaterWave/index.d.ts
+++ b/src/components/Charts/WaterWave/index.d.ts
@@ -1,9 +1,10 @@
-import * as React from "react";
+import * as React from 'react';
 export interface WaterWaveProps {
   title: React.ReactNode;
   color?: string;
   height: number;
   percent: number;
+  style?: React.CSSProperties;
 }
 
 export default class WaterWave extends React.Component<WaterWaveProps, any> {}
diff --git a/src/main/frontend/src/components/Charts/WaterWave/index.js b/src/components/Charts/WaterWave/index.js
similarity index 82%
rename from src/main/frontend/src/components/Charts/WaterWave/index.js
rename to src/components/Charts/WaterWave/index.js
index a9eece6..5b463ad 100644
--- a/src/main/frontend/src/components/Charts/WaterWave/index.js
+++ b/src/components/Charts/WaterWave/index.js
@@ -1,16 +1,16 @@
 import React, { PureComponent } from 'react';
+import autoHeight from '../autoHeight';
 import styles from './index.less';
 
 /* eslint no-return-assign: 0 */
+/* eslint no-mixed-operators: 0 */
 // riddle: https://riddle.alibaba-inc.com/riddles/2d9a4b90
 
-class WaterWave extends PureComponent {
-  static defaultProps = {
-    height: 160,
-  }
+@autoHeight()
+export default class WaterWave extends PureComponent {
   state = {
     radio: 1,
-  }
+  };
 
   componentDidMount() {
     this.renderChart();
@@ -33,7 +33,7 @@ class WaterWave extends PureComponent {
     this.setState({
       radio: offsetWidth < height ? offsetWidth / height : 1,
     });
-  }
+  };
 
   renderChart() {
     const { percent, color = '#1890FF' } = this.props;
@@ -51,12 +51,12 @@ class WaterWave extends PureComponent {
     const canvasHeight = canvas.height;
     const radius = canvasWidth / 2;
     const lineWidth = 2;
-    const cR = radius - (lineWidth);
+    const cR = radius - lineWidth;
 
     ctx.beginPath();
     ctx.lineWidth = lineWidth * 2;
 
-    const axisLength = canvasWidth - (lineWidth);
+    const axisLength = canvasWidth - lineWidth;
     const unit = axisLength / 8;
     const range = 0.2; // 振幅
     let currRange = range;
@@ -66,15 +66,12 @@ class WaterWave extends PureComponent {
     const waveupsp = 0.005; // 水波上涨速度
 
     let arcStack = [];
-    const bR = radius - (lineWidth);
+    const bR = radius - lineWidth;
     const circleOffset = -(Math.PI / 2);
     let circleLock = true;
 
-    for (let i = circleOffset; i < circleOffset + (2 * Math.PI); i += 1 / (8 * Math.PI)) {
-      arcStack.push([
-        radius + (bR * Math.cos(i)),
-        radius + (bR * Math.sin(i)),
-      ]);
+    for (let i = circleOffset; i < circleOffset + 2 * Math.PI; i += 1 / (8 * Math.PI)) {
+      arcStack.push([radius + bR * Math.cos(i), radius + bR * Math.sin(i)]);
     }
 
     const cStartPoint = arcStack.shift();
@@ -87,10 +84,10 @@ class WaterWave extends PureComponent {
 
       const sinStack = [];
       for (let i = xOffset; i <= xOffset + axisLength; i += 20 / axisLength) {
-        const x = sp + ((xOffset + i) / unit);
+        const x = sp + (xOffset + i) / unit;
         const y = Math.sin(x) * currRange;
         const dx = i;
-        const dy = ((2 * cR * (1 - currData)) + (radius - cR)) - (unit * y);
+        const dy = 2 * cR * (1 - currData) + (radius - cR) - unit * y;
 
         ctx.lineTo(dx, dy);
         sinStack.push([dx, dy]);
@@ -130,7 +127,7 @@ class WaterWave extends PureComponent {
 
           ctx.beginPath();
           ctx.save();
-          ctx.arc(radius, radius, radius - (3 * lineWidth), 0, 2 * Math.PI, 1);
+          ctx.arc(radius, radius, radius - 3 * lineWidth, 0, 2 * Math.PI, 1);
 
           ctx.restore();
           ctx.clip();
@@ -157,10 +154,10 @@ class WaterWave extends PureComponent {
             currRange -= t;
           }
         }
-        if ((data - currData) > 0) {
+        if (data - currData > 0) {
           currData += waveupsp;
         }
-        if ((data - currData) < 0) {
+        if (data - currData < 0) {
           currData -= waveupsp;
         }
 
@@ -177,7 +174,11 @@ class WaterWave extends PureComponent {
     const { radio } = this.state;
     const { percent, title, height } = this.props;
     return (
-      <div className={styles.waterWave} ref={n => (this.root = n)} style={{ transform: `scale(${radio})` }}>
+      <div
+        className={styles.waterWave}
+        ref={n => (this.root = n)}
+        style={{ transform: `scale(${radio})` }}
+      >
         <div style={{ width: height, height, overflow: 'hidden' }}>
           <canvas
             className={styles.waterWaveCanvasWrapper}
@@ -187,14 +188,10 @@ class WaterWave extends PureComponent {
           />
         </div>
         <div className={styles.text} style={{ width: height }}>
-          {
-            title && <span>{title}</span>
-          }
+          {title && <span>{title}</span>}
           <h4>{percent}%</h4>
         </div>
       </div>
     );
   }
 }
-
-export default WaterWave;
diff --git a/src/main/frontend/src/components/Charts/WaterWave/index.less b/src/components/Charts/WaterWave/index.less
similarity index 100%
rename from src/main/frontend/src/components/Charts/WaterWave/index.less
rename to src/components/Charts/WaterWave/index.less
diff --git a/src/components/Charts/autoHeight.js b/src/components/Charts/autoHeight.js
new file mode 100644
index 0000000..d8582ff
--- /dev/null
+++ b/src/components/Charts/autoHeight.js
@@ -0,0 +1,63 @@
+/* eslint eqeqeq: 0 */
+import React from 'react';
+
+function computeHeight(node) {
+  const totalHeight = parseInt(getComputedStyle(node).height, 10);
+  const padding =
+    parseInt(getComputedStyle(node).paddingTop, 10) +
+    parseInt(getComputedStyle(node).paddingBottom, 10);
+  return totalHeight - padding;
+}
+
+function getAutoHeight(n) {
+  if (!n) {
+    return 0;
+  }
+
+  let node = n;
+
+  let height = computeHeight(node);
+
+  while (!height) {
+    node = node.parentNode;
+    if (node) {
+      height = computeHeight(node);
+    } else {
+      break;
+    }
+  }
+
+  return height;
+}
+
+const autoHeight = () => (WrappedComponent) => {
+  return class extends React.Component {
+    state = {
+      computedHeight: 0,
+    };
+
+    componentDidMount() {
+      const { height } = this.props;
+      if (!height) {
+        const h = getAutoHeight(this.root);
+        // eslint-disable-next-line
+        this.setState({ computedHeight: h });
+      }
+    }
+
+    handleRoot = (node) => {
+      this.root = node;
+    };
+
+    render() {
+      const { height } = this.props;
+      const { computedHeight } = this.state;
+      const h = height || computedHeight;
+      return (
+        <div ref={this.handleRoot}>{h > 0 && <WrappedComponent {...this.props} height={h} />}</div>
+      );
+    }
+  };
+};
+
+export default autoHeight;
diff --git a/src/main/frontend/src/components/Charts/demo/bar.md b/src/components/Charts/demo/bar.md
similarity index 100%
rename from src/main/frontend/src/components/Charts/demo/bar.md
rename to src/components/Charts/demo/bar.md
diff --git a/src/main/frontend/src/components/Charts/demo/chart-card.md b/src/components/Charts/demo/chart-card.md
similarity index 100%
rename from src/main/frontend/src/components/Charts/demo/chart-card.md
rename to src/components/Charts/demo/chart-card.md
diff --git a/src/main/frontend/src/components/Charts/demo/gauge.md b/src/components/Charts/demo/gauge.md
similarity index 100%
rename from src/main/frontend/src/components/Charts/demo/gauge.md
rename to src/components/Charts/demo/gauge.md
diff --git a/src/main/frontend/src/components/Charts/demo/mini-area.md b/src/components/Charts/demo/mini-area.md
similarity index 100%
rename from src/main/frontend/src/components/Charts/demo/mini-area.md
rename to src/components/Charts/demo/mini-area.md
diff --git a/src/main/frontend/src/components/Charts/demo/mini-bar.md b/src/components/Charts/demo/mini-bar.md
similarity index 100%
rename from src/main/frontend/src/components/Charts/demo/mini-bar.md
rename to src/components/Charts/demo/mini-bar.md
diff --git a/src/main/frontend/src/components/Charts/demo/mini-pie.md b/src/components/Charts/demo/mini-pie.md
similarity index 100%
rename from src/main/frontend/src/components/Charts/demo/mini-pie.md
rename to src/components/Charts/demo/mini-pie.md
diff --git a/src/main/frontend/src/components/Charts/demo/mini-progress.md b/src/components/Charts/demo/mini-progress.md
similarity index 100%
rename from src/main/frontend/src/components/Charts/demo/mini-progress.md
rename to src/components/Charts/demo/mini-progress.md
diff --git a/src/main/frontend/src/components/Charts/demo/mix.md b/src/components/Charts/demo/mix.md
similarity index 100%
rename from src/main/frontend/src/components/Charts/demo/mix.md
rename to src/components/Charts/demo/mix.md
diff --git a/src/main/frontend/src/components/Charts/demo/pie.md b/src/components/Charts/demo/pie.md
similarity index 100%
rename from src/main/frontend/src/components/Charts/demo/pie.md
rename to src/components/Charts/demo/pie.md
diff --git a/src/main/frontend/src/components/Charts/demo/radar.md b/src/components/Charts/demo/radar.md
similarity index 100%
rename from src/main/frontend/src/components/Charts/demo/radar.md
rename to src/components/Charts/demo/radar.md
diff --git a/src/main/frontend/src/components/Charts/demo/tag-cloud.md b/src/components/Charts/demo/tag-cloud.md
similarity index 100%
rename from src/main/frontend/src/components/Charts/demo/tag-cloud.md
rename to src/components/Charts/demo/tag-cloud.md
diff --git a/src/main/frontend/src/components/Charts/demo/timeline-chart.md b/src/components/Charts/demo/timeline-chart.md
similarity index 100%
rename from src/main/frontend/src/components/Charts/demo/timeline-chart.md
rename to src/components/Charts/demo/timeline-chart.md
diff --git a/src/main/frontend/src/components/Charts/demo/waterwave.md b/src/components/Charts/demo/waterwave.md
similarity index 100%
rename from src/main/frontend/src/components/Charts/demo/waterwave.md
rename to src/components/Charts/demo/waterwave.md
diff --git a/src/components/Charts/g2.js b/src/components/Charts/g2.js
new file mode 100644
index 0000000..21e22c2
--- /dev/null
+++ b/src/components/Charts/g2.js
@@ -0,0 +1,15 @@
+// 全局 G2 设置
+import { track, setTheme } from 'bizcharts';
+
+track(false);
+
+const config = {
+  defaultColor: '#1089ff',
+  shape: {
+    interval: {
+      fillOpacity: 1,
+    },
+  },
+};
+
+setTheme(config);
diff --git a/src/components/Charts/index.d.ts b/src/components/Charts/index.d.ts
new file mode 100644
index 0000000..1ff27af
--- /dev/null
+++ b/src/components/Charts/index.d.ts
@@ -0,0 +1,17 @@
+import * as numeral from 'numeral';
+export { default as ChartCard } from './ChartCard';
+export { default as Bar } from './Bar';
+export { default as Pie } from './Pie';
+export { default as Radar } from './Radar';
+export { default as Gauge } from './Gauge';
+export { default as MiniArea } from './MiniArea';
+export { default as MiniBar } from './MiniBar';
+export { default as MiniProgress } from './MiniProgress';
+export { default as Field } from './Field';
+export { default as WaterWave } from './WaterWave';
+export { default as TagCloud } from './TagCloud';
+export { default as TimelineChart } from './TimelineChart';
+
+declare const yuan: (value: number | string) => string;
+
+export { yuan };
diff --git a/src/main/frontend/src/components/Charts/index.js b/src/components/Charts/index.js
similarity index 82%
rename from src/main/frontend/src/components/Charts/index.js
rename to src/components/Charts/index.js
index 997b17c..0fbf014 100644
--- a/src/main/frontend/src/components/Charts/index.js
+++ b/src/components/Charts/index.js
@@ -1,8 +1,7 @@
 import numeral from 'numeral';
+import './g2';
 import ChartCard from './ChartCard';
-import Area from './Area';
 import Bar from './Bar';
-import Line from './Line';
 import Pie from './Pie';
 import Radar from './Radar';
 import Gauge from './Gauge';
@@ -13,15 +12,12 @@ import Field from './Field';
 import WaterWave from './WaterWave';
 import TagCloud from './TagCloud';
 import TimelineChart from './TimelineChart';
-import StackBar from './StackBar';
 
 const yuan = val => `&yen; ${numeral(val).format('0,0')}`;
 
-export default {
+export {
   yuan,
-  Area,
   Bar,
-  Line,
   Pie,
   Gauge,
   Radar,
@@ -33,5 +29,4 @@ export default {
   WaterWave,
   TagCloud,
   TimelineChart,
-  StackBar,
 };
diff --git a/src/main/frontend/src/components/Charts/index.less b/src/components/Charts/index.less
similarity index 88%
rename from src/main/frontend/src/components/Charts/index.less
rename to src/components/Charts/index.less
index 52f97c4..190428b 100644
--- a/src/main/frontend/src/components/Charts/index.less
+++ b/src/components/Charts/index.less
@@ -3,9 +3,9 @@
   width: 100%;
   .chartContent {
     position: absolute;
-    bottom: -34px;
+    bottom: -28px;
     width: 100%;
-    & > div {
+    > div {
       margin: 0 -5px;
       overflow: hidden;
     }
diff --git a/src/main/frontend/src/components/Charts/index.md b/src/components/Charts/index.md
similarity index 100%
rename from src/main/frontend/src/components/Charts/index.md
rename to src/components/Charts/index.md
diff --git a/src/components/CountDown/demo/simple.md b/src/components/CountDown/demo/simple.md
new file mode 100644
index 0000000..e42cbf1
--- /dev/null
+++ b/src/components/CountDown/demo/simple.md
@@ -0,0 +1,24 @@
+---
+order: 0
+title:
+  zh-CN: 基本
+  en-US: Basic
+---
+
+## zh-CN
+
+简单的倒计时组件使用。
+
+## en-US
+
+The simplest usage.
+
+````jsx
+import CountDown from 'ant-design-pro/lib/CountDown';
+
+const targetTime = new Date().getTime() + 3900000;
+
+ReactDOM.render(
+  <CountDown style={{ fontSize: 20 }} target={targetTime} />
+, mountNode);
+````
diff --git a/src/components/CountDown/index.d.ts b/src/components/CountDown/index.d.ts
new file mode 100644
index 0000000..3c46ac7
--- /dev/null
+++ b/src/components/CountDown/index.d.ts
@@ -0,0 +1,9 @@
+import * as React from "react";
+export interface CountDownProps {
+  format?: (time: number) => void;
+  target: Date | number;
+  onEnd?: () => void;
+  style?: React.CSSProperties;
+}
+
+export default class CountDown extends React.Component<CountDownProps, any> {}
diff --git a/src/components/CountDown/index.en-US.md b/src/components/CountDown/index.en-US.md
new file mode 100644
index 0000000..7b45240
--- /dev/null
+++ b/src/components/CountDown/index.en-US.md
@@ -0,0 +1,15 @@
+---
+title: CountDown
+cols: 1
+order: 3
+---
+
+Simple CountDown Component.
+
+## API
+
+| Property | Description | Type | Default |
+|----------|------------------------------------------|-------------|-------|
+| format | Formatter of time | Function(time) |  |
+| target | Target time | Date | - |
+| onEnd |  Countdown to the end callback | funtion | -|
diff --git a/src/components/CountDown/index.js b/src/components/CountDown/index.js
new file mode 100644
index 0000000..e1e85bc
--- /dev/null
+++ b/src/components/CountDown/index.js
@@ -0,0 +1,108 @@
+import React, { Component } from 'react';
+
+function fixedZero(val) {
+  return val * 1 < 10 ? `0${val}` : val;
+}
+
+class CountDown extends Component {
+  constructor(props) {
+    super(props);
+
+    const { lastTime } = this.initTime(props);
+
+    this.state = {
+      lastTime,
+    };
+  }
+
+  componentDidMount() {
+    this.tick();
+  }
+
+  componentWillReceiveProps(nextProps) {
+    if (this.props.target !== nextProps.target) {
+      clearTimeout(this.timer);
+      const { lastTime } = this.initTime(nextProps);
+      this.setState({
+        lastTime,
+      }, () => {
+        this.tick();
+      });
+    }
+  }
+
+  componentWillUnmount() {
+    clearTimeout(this.timer);
+  }
+
+  timer = 0;
+  interval = 1000;
+  initTime = (props) => {
+    let lastTime = 0;
+    let targetTime = 0;
+    try {
+      if (Object.prototype.toString.call(props.target) === '[object Date]') {
+        targetTime = props.target.getTime();
+      } else {
+        targetTime = new Date(props.target).getTime();
+      }
+    } catch (e) {
+      throw new Error('invalid target prop', e);
+    }
+
+    lastTime = targetTime - new Date().getTime();
+
+    return {
+      lastTime,
+    };
+  }
+  // defaultFormat = time => (
+  //  <span>{moment(time).format('hh:mm:ss')}</span>
+  // );
+  defaultFormat = (time) => {
+    const hours = 60 * 60 * 1000;
+    const minutes = 60 * 1000;
+
+    const h = fixedZero(Math.floor(time / hours));
+    const m = fixedZero(Math.floor((time - (h * hours)) / minutes));
+    const s = fixedZero(Math.floor((time - (h * hours) - (m * minutes)) / 1000));
+    return (
+      <span>{h}:{m}:{s}</span>
+    );
+  }
+  tick = () => {
+    const { onEnd } = this.props;
+    let { lastTime } = this.state;
+
+    this.timer = setTimeout(() => {
+      if (lastTime < this.interval) {
+        clearTimeout(this.timer);
+        this.setState({
+          lastTime: 0,
+        }, () => {
+          if (onEnd) {
+            onEnd();
+          }
+        });
+      } else {
+        lastTime -= this.interval;
+        this.setState({
+          lastTime,
+        }, () => {
+          this.tick();
+        });
+      }
+    }, this.interval);
+  }
+
+  render() {
+    const { format = this.defaultFormat, ...rest } = this.props;
+    const { lastTime } = this.state;
+
+    const result = format(lastTime);
+
+    return (<span {...rest}>{result}</span>);
+  }
+}
+
+export default CountDown;
diff --git a/src/components/CountDown/index.zh-CN.md b/src/components/CountDown/index.zh-CN.md
new file mode 100644
index 0000000..7e00ba1
--- /dev/null
+++ b/src/components/CountDown/index.zh-CN.md
@@ -0,0 +1,16 @@
+---
+title: CountDown 
+subtitle: 倒计时
+cols: 1
+order: 3
+---
+
+倒计时组件。
+
+## API
+
+| 参数      | 说明                                      | 类型         | 默认值 |
+|----------|------------------------------------------|-------------|-------|
+| format | 时间格式化显示 | Function(time) |  |
+| target | 目标时间 | Date | - |
+| onEnd |  倒计时结束回调 | funtion | -|
diff --git a/src/main/frontend/src/components/DescriptionList/Description.js b/src/components/DescriptionList/Description.js
similarity index 80%
rename from src/main/frontend/src/components/DescriptionList/Description.js
rename to src/components/DescriptionList/Description.js
index 2aae62b..e024796 100644
--- a/src/main/frontend/src/components/DescriptionList/Description.js
+++ b/src/components/DescriptionList/Description.js
@@ -1,4 +1,5 @@
 import React from 'react';
+import PropTypes from 'prop-types';
 import classNames from 'classnames';
 import { Col } from 'antd';
 import styles from './index.less';
@@ -14,4 +15,12 @@ const Description = ({ term, column, className, children, ...restProps }) => {
   );
 };
 
+Description.defaultProps = {
+  term: '',
+};
+
+Description.propTypes = {
+  term: PropTypes.node,
+};
+
 export default Description;
diff --git a/src/main/frontend/src/components/DescriptionList/DescriptionList.js b/src/components/DescriptionList/DescriptionList.js
similarity index 85%
rename from src/main/frontend/src/components/DescriptionList/DescriptionList.js
rename to src/components/DescriptionList/DescriptionList.js
index 7eca3a7..bef2cec 100644
--- a/src/main/frontend/src/components/DescriptionList/DescriptionList.js
+++ b/src/components/DescriptionList/DescriptionList.js
@@ -6,8 +6,8 @@ import styles from './index.less';
 export default ({ className, title, col = 3, layout = 'horizontal', gutter = 32,
   children, size, ...restProps }) => {
   const clsString = classNames(styles.descriptionList, styles[layout], className, {
-    [styles.descriptionListSmall]: size === 'small',
-    [styles.descriptionListLarge]: size === 'large',
+    [styles.small]: size === 'small',
+    [styles.large]: size === 'large',
   });
   const column = col > 4 ? 4 : col;
   return (
diff --git a/src/main/frontend/src/components/DescriptionList/demo/basic.md b/src/components/DescriptionList/demo/basic.md
similarity index 100%
rename from src/main/frontend/src/components/DescriptionList/demo/basic.md
rename to src/components/DescriptionList/demo/basic.md
diff --git a/src/main/frontend/src/components/DescriptionList/demo/vertical.md b/src/components/DescriptionList/demo/vertical.md
similarity index 100%
rename from src/main/frontend/src/components/DescriptionList/demo/vertical.md
rename to src/components/DescriptionList/demo/vertical.md
diff --git a/src/main/frontend/src/components/DescriptionList/index.d.ts b/src/components/DescriptionList/index.d.ts
similarity index 67%
rename from src/main/frontend/src/components/DescriptionList/index.d.ts
rename to src/components/DescriptionList/index.d.ts
index b13c630..fe64433 100644
--- a/src/main/frontend/src/components/DescriptionList/index.d.ts
+++ b/src/components/DescriptionList/index.d.ts
@@ -1,15 +1,17 @@
-import * as React from "react";
+import * as React from 'react';
 export interface DescriptionListProps {
-  layout?: "horizontal" | "vertical";
+  layout?: 'horizontal' | 'vertical';
   col?: number;
   title: React.ReactNode;
   gutter?: number;
-  size?: "large" | "small";
+  size?: 'large' | 'small';
+  style?: React.CSSProperties;
 }
 
 declare class Description extends React.Component<
   {
     term: React.ReactNode;
+    style?: React.CSSProperties;
   },
   any
 > {}
diff --git a/src/main/frontend/src/components/DescriptionList/index.js b/src/components/DescriptionList/index.js
similarity index 100%
rename from src/main/frontend/src/components/DescriptionList/index.js
rename to src/components/DescriptionList/index.js
diff --git a/src/main/frontend/src/components/DescriptionList/index.less b/src/components/DescriptionList/index.less
similarity index 73%
rename from src/main/frontend/src/components/DescriptionList/index.less
rename to src/components/DescriptionList/index.less
index 067144e..e8d5280 100644
--- a/src/main/frontend/src/components/DescriptionList/index.less
+++ b/src/components/DescriptionList/index.less
@@ -40,8 +40,29 @@
     display: table-cell;
   }
 
-  &.vertical {
+  &.small {
+    // offset the padding-bottom of last row
+    :global {
+      .ant-row {
+        margin-bottom: -8px;
+      }
+    }
+    .title {
+      margin-bottom: 12px;
+      color: @text-color;
+    }
+    .term, .detail {
+      padding-bottom: 8px;
+    }
+  }
 
+  &.large {
+    .title {
+      font-size: 16px;
+    }
+  }
+
+  &.vertical {
     .term {
       padding-bottom: 8px;
       display: block;
@@ -52,24 +73,3 @@
     }
   }
 }
-
-.descriptionListSmall {
-  // offset the padding-bottom of last row
-  :global {
-    .ant-row {
-      margin-bottom: -8px;
-    }
-  }
-  .title {
-    margin-bottom: 12px;
-    color: @text-color;
-  }
-  .term, .detail {
-    padding-bottom: 8px;
-  }
-}
-.descriptionListLarge {
-  .title {
-    font-size: 16px;
-  }
-}
diff --git a/src/main/frontend/src/components/DescriptionList/index.md b/src/components/DescriptionList/index.md
similarity index 100%
rename from src/main/frontend/src/components/DescriptionList/index.md
rename to src/components/DescriptionList/index.md
diff --git a/src/main/frontend/src/components/DescriptionList/responsive.js b/src/components/DescriptionList/responsive.js
similarity index 100%
rename from src/main/frontend/src/components/DescriptionList/responsive.js
rename to src/components/DescriptionList/responsive.js
diff --git a/src/components/Duration/Icon/index.js b/src/components/Duration/Icon/index.js
new file mode 100644
index 0000000..bd2596b
--- /dev/null
+++ b/src/components/Duration/Icon/index.js
@@ -0,0 +1,30 @@
+import React, { PureComponent } from 'react';
+import { Icon } from 'antd';
+import moment from 'moment';
+
+export default class DurationIcon extends PureComponent {
+  render() {
+    const { className, onToggle, onReload, selectedDuration = {
+      from() {
+        return moment();
+      },
+      to() {
+        return moment();
+      },
+      lable: 'NaN',
+    } } = this.props;
+    const timeFormat = 'YYYY-MM-DD HH:mm';
+    return (
+      <span>
+        <span
+          className={className}
+          onClick={onToggle}
+        >
+          {selectedDuration.label ? selectedDuration.label : `${selectedDuration.from().format(timeFormat)} ~ ${selectedDuration.to().format(timeFormat)}`}
+          {selectedDuration.step > 0 ? ` Reloading every ${selectedDuration.step / 1000} seconds` : null }
+        </span>
+        <span className={className} onClick={onReload}> <Icon type="reload" /> </span>
+      </span>
+    );
+  }
+}
diff --git a/src/main/frontend/src/components/Time/TimeSelect/index.js b/src/components/Duration/Panel/index.js
similarity index 89%
rename from src/main/frontend/src/components/Time/TimeSelect/index.js
rename to src/components/Duration/Panel/index.js
index 2a74c9a..c41743c 100644
--- a/src/main/frontend/src/components/Time/TimeSelect/index.js
+++ b/src/components/Duration/Panel/index.js
@@ -9,22 +9,22 @@ const { RangePicker } = DatePicker;
 
 @Form.create({
   mapPropsToFields(props) {
-    if (!props.selectedTime) return null;
+    if (!props.selected) return {};
     const result = {
       step: Form.createFormField({
-        value: props.selectedTime.step,
+        value: props.selected.step,
       }),
     };
-    if (props.selectedTime.label) {
+    if (props.selected.label) {
       return result;
     }
     result['range-time-picker'] = Form.createFormField({
-      value: [props.selectedTime.from(), props.selectedTime.to()],
+      value: [props.selected.from(), props.selected.to()],
     });
     return result;
   },
 })
-class TimeSelect extends PureComponent {
+class DurationPanel extends PureComponent {
   constructor(props) {
     super(props);
 
@@ -143,12 +143,12 @@ class TimeSelect extends PureComponent {
     });
   }
   select = (newSelectedTime) => {
-    const { onSelected, selectedTime } = this.props;
-    onSelected({ ...selectedTime, ...newSelectedTime });
+    const { onSelected, selected } = this.props;
+    onSelected({ ...selected, ...newSelectedTime });
   }
   render() {
-    const { isShow, form } = this.props;
-    if (!isShow) {
+    const { collapsed, form } = this.props;
+    if (collapsed) {
       return null;
     }
     const formItemLayout = {
@@ -229,11 +229,11 @@ class TimeSelect extends PureComponent {
       </Row>
     );
     return (
-      <div className="antd-pro-page-header-pageHeader">
-        <div className="antd-pro-page-header-detail">
-          <div className="antd-pro-page-header-main">
-            <div className="antd-pro-page-header-row">
-              <div className="antd-pro-page-header-content">
+      <div className={styles.pageHeader}>
+        <div className={styles.detail}>
+          <div className={styles.main}>
+            <div className={styles.row}>
+              <div className={styles.content}>
                 {content}
               </div>
             </div>
@@ -243,4 +243,4 @@ class TimeSelect extends PureComponent {
     );
   }
 }
-export default TimeSelect;
+export default DurationPanel;
diff --git a/src/components/Duration/Panel/index.less b/src/components/Duration/Panel/index.less
new file mode 100644
index 0000000..7785f4f
--- /dev/null
+++ b/src/components/Duration/Panel/index.less
@@ -0,0 +1,142 @@
+@import "~antd/lib/style/themes/default.less";
+
+.pageHeader {
+  background: @component-background;
+  padding: 16px 32px 0 32px;
+  border-bottom: @border-width-base @border-style-base @border-color-split;
+
+  .detail {
+    display: flex;
+  }
+
+  .row {
+    display: flex;
+  }
+
+  .breadcrumb {
+    margin-bottom: 16px;
+  }
+
+  .tabs {
+    margin: 0 0 -17px -8px;
+
+    :global {
+      .ant-tabs-bar {
+        border-bottom: @border-width-base @border-style-base @border-color-split;
+      }
+    }
+  }
+
+  .logo {
+    flex: 0 1 auto;
+    margin-right: 16px;
+    padding-top: 1px;
+    > img {
+      width: 28px;
+      height: 28px;
+      border-radius: @border-radius-base;
+      display: block;
+    }
+  }
+
+  .title {
+    font-size: 20px;
+    font-weight: 500;
+    color: @heading-color;
+  }
+
+  .action {
+    margin-left: 56px;
+    min-width: 266px;
+
+    :global {
+      .ant-btn-group:not(:last-child),
+      .ant-btn:not(:last-child) {
+        margin-right: 8px;
+      }
+
+      .ant-btn-group > .ant-btn {
+        margin-right: 0;
+      }
+    }
+  }
+
+  .title, .action, .content, .extraContent, .main {
+    flex: auto;
+  }
+
+  .title, .action {
+    margin-bottom: 16px;
+  }
+
+  .logo, .content, .extraContent {
+    margin-bottom: 16px;
+  }
+
+  .action, .extraContent {
+    text-align: right;
+  }
+
+  .extraContent {
+    margin-left: 88px;
+    min-width: 242px;
+  }
+}
+
+@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;
+        }
+      }
+    }
+  }
+}
+
+.list {
+  list-style: none;
+}
diff --git a/src/components/EditableItem/index.js b/src/components/EditableItem/index.js
new file mode 100644
index 0000000..b0563c1
--- /dev/null
+++ b/src/components/EditableItem/index.js
@@ -0,0 +1,55 @@
+import React, { PureComponent } from 'react';
+import { Input, Icon } from 'antd';
+import styles from './index.less';
+
+export default class EditableItem extends PureComponent {
+  state = {
+    value: this.props.value,
+    editable: false,
+  };
+  handleChange = (e) => {
+    const { value } = e.target;
+    this.setState({ value });
+  }
+  check = () => {
+    this.setState({ editable: false });
+    if (this.props.onChange) {
+      this.props.onChange(this.state.value);
+    }
+  }
+  edit = () => {
+    this.setState({ editable: true });
+  }
+  render() {
+    const { value, editable } = this.state;
+    return (
+      <div className={styles.editableItem}>
+        {
+          editable ? (
+            <div className={styles.wrapper}>
+              <Input
+                value={value}
+                onChange={this.handleChange}
+                onPressEnter={this.check}
+              />
+              <Icon
+                type="check"
+                className={styles.icon}
+                onClick={this.check}
+              />
+            </div>
+          ) : (
+            <div className={styles.wrapper}>
+              <span>{value || ' '}</span>
+              <Icon
+                type="edit"
+                className={styles.icon}
+                onClick={this.edit}
+              />
+            </div>
+          )
+        }
+      </div>
+    );
+  }
+}
diff --git a/src/components/EditableItem/index.less b/src/components/EditableItem/index.less
new file mode 100644
index 0000000..8c06868
--- /dev/null
+++ b/src/components/EditableItem/index.less
@@ -0,0 +1,25 @@
+@import "~antd/lib/style/themes/default.less";
+
+.editableItem {
+  line-height: @input-height-base;
+  display: table;
+  width: 100%;
+  margin-top: (@font-size-base * @line-height-base - @input-height-base) / 2;
+
+  .wrapper {
+    display: table-row;
+
+    & > * {
+      display: table-cell;
+    }
+
+    & > *:first-child {
+      width: 85%;
+    }
+
+    .icon {
+      cursor: pointer;
+      text-align: right;
+    }
+  }
+}
diff --git a/src/components/EditableLinkGroup/index.js b/src/components/EditableLinkGroup/index.js
new file mode 100644
index 0000000..97d70fc
--- /dev/null
+++ b/src/components/EditableLinkGroup/index.js
@@ -0,0 +1,44 @@
+import React, { PureComponent, createElement } from 'react';
+import PropTypes from 'prop-types';
+import { Button } from 'antd';
+import styles from './index.less';
+
+// TODO: 添加逻辑
+
+class EditableLinkGroup extends PureComponent {
+  static defaultProps = {
+    links: [],
+    onAdd: () => {},
+    linkElement: 'a',
+  };
+
+  static propTypes = {
+    links: PropTypes.array,
+    onAdd: PropTypes.func,
+    linkElement: PropTypes.oneOfType([PropTypes.func, PropTypes.string]),
+  };
+
+  render() {
+    const { links, linkElement, onAdd } = this.props;
+    return (
+      <div className={styles.linkGroup}>
+        {
+          links.map(link => (
+            createElement(linkElement, {
+              key: `linkGroup-item-${link.id || link.title}`,
+              to: link.href,
+              href: link.href,
+            }, link.title)
+          ))
+        }
+        {
+          <Button size="small" type="primary" ghost onClick={onAdd} icon="plus">
+            添加
+          </Button>
+        }
+      </div>
+    );
+  }
+}
+
+export default EditableLinkGroup;
diff --git a/src/components/EditableLinkGroup/index.less b/src/components/EditableLinkGroup/index.less
new file mode 100644
index 0000000..c3d0b58
--- /dev/null
+++ b/src/components/EditableLinkGroup/index.less
@@ -0,0 +1,16 @@
+@import "~antd/lib/style/themes/default.less";
+
+.linkGroup {
+  padding: 20px 0 8px 24px;
+  font-size: 0;
+  & > a {
+    color: @text-color;
+    display: inline-block;
+    font-size: @font-size-base;
+    margin-bottom: 13px;
+    width: 25%;
+    &:hover {
+      color: @primary-color;
+    }
+  }
+}
diff --git a/src/components/Ellipsis/demo/line.md b/src/components/Ellipsis/demo/line.md
new file mode 100644
index 0000000..60b804c
--- /dev/null
+++ b/src/components/Ellipsis/demo/line.md
@@ -0,0 +1,20 @@
+---
+order: 1
+title: 按照行数省略
+---
+
+通过设置 `lines` 属性指定最大行数,如果超过这个行数的文本会自动截取。但是在这种模式下所有 `children` 将会被转换成纯文本。
+
+并且注意在这种模式下,外容器需要有指定的宽度(或设置自身宽度)。
+
+````jsx
+import Ellipsis from 'ant-design-pro/lib/Ellipsis';
+
+const article = <p>There were injuries alleged in three <a href="#cover">cases in 2015</a>, and a fourth incident in September, according to the safety recall report. After meeting with US regulators in October, the firm decided to issue a voluntary recall.</p>;
+
+ReactDOM.render(
+  <div style={{ width: 200 }}>
+    <Ellipsis tooltip lines={3}>{article}</Ellipsis>
+  </div>
+, mountNode);
+````
diff --git a/src/components/Ellipsis/demo/number.md b/src/components/Ellipsis/demo/number.md
new file mode 100644
index 0000000..9302bb8
--- /dev/null
+++ b/src/components/Ellipsis/demo/number.md
@@ -0,0 +1,20 @@
+---
+order: 0
+title: 按照字符数省略 
+---
+
+通过设置 `length` 属性指定文本最长长度,如果超过这个长度会自动截取。
+
+````jsx
+import Ellipsis from 'ant-design-pro/lib/Ellipsis';
+
+const article = 'There were injuries alleged in three cases in 2015, and a fourth incident in September, according to the safety recall report. After meeting with US regulators in October, the firm decided to issue a voluntary recall.';
+
+ReactDOM.render(
+  <div>
+    <Ellipsis length={100}>{article}</Ellipsis>
+    <h4 style={{ marginTop: 24 }}>Show Tooltip</h4>
+    <Ellipsis length={100} tooltip>{article}</Ellipsis>
+  </div>
+, mountNode);
+````
diff --git a/src/components/Ellipsis/index.d.ts b/src/components/Ellipsis/index.d.ts
new file mode 100644
index 0000000..8421b95
--- /dev/null
+++ b/src/components/Ellipsis/index.d.ts
@@ -0,0 +1,12 @@
+import * as React from "react";
+export interface EllipsisProps {
+  tooltip?: boolean;
+  length?: number;
+  lines?: number;
+  style?: React.CSSProperties;
+}
+
+export default class Ellipsis extends React.Component<
+  EllipsisProps,
+  any
+> {}
diff --git a/src/components/Ellipsis/index.js b/src/components/Ellipsis/index.js
new file mode 100644
index 0000000..351b414
--- /dev/null
+++ b/src/components/Ellipsis/index.js
@@ -0,0 +1,224 @@
+import React, { Component } from 'react';
+import { Tooltip } from 'antd';
+import classNames from 'classnames';
+import styles from './index.less';
+
+/* eslint react/no-did-mount-set-state: 0 */
+/* eslint no-param-reassign: 0 */
+
+const isSupportLineClamp = document.body.style.webkitLineClamp !== undefined;
+
+const EllipsisText = ({ text, length, tooltip, ...other }) => {
+  if (typeof text !== 'string') {
+    throw new Error('Ellipsis children must be string.');
+  }
+  if (text.length <= length || length < 0) {
+    return <span {...other}>{text}</span>;
+  }
+  const tail = '...';
+  let displayText;
+  if (length - tail.length <= 0) {
+    displayText = '';
+  } else {
+    displayText = text.slice(0, length - tail.length);
+  }
+
+  if (tooltip) {
+    return (
+      <Tooltip overlayStyle={{ wordBreak: 'break-all' }} title={text}>
+        <span>
+          {displayText}
+          {tail}
+        </span>
+      </Tooltip>
+    );
+  }
+
+  return (
+    <span {...other}>
+      {displayText}
+      {tail}
+    </span>
+  );
+};
+
+export default class Ellipsis extends Component {
+  state = {
+    text: '',
+    targetCount: 0,
+  };
+
+  componentDidMount() {
+    if (this.node) {
+      this.computeLine();
+    }
+  }
+
+  componentWillReceiveProps(nextProps) {
+    if (this.props.lines !== nextProps.lines) {
+      this.computeLine();
+    }
+  }
+
+  computeLine = () => {
+    const { lines } = this.props;
+    if (lines && !isSupportLineClamp) {
+      const text = this.shadowChildren.innerText;
+      const lineHeight = parseInt(getComputedStyle(this.root).lineHeight, 10);
+      const targetHeight = lines * lineHeight;
+      this.content.style.height = `${targetHeight}px`;
+      const totalHeight = this.shadowChildren.offsetHeight;
+      const shadowNode = this.shadow.firstChild;
+
+      if (totalHeight <= targetHeight) {
+        this.setState({
+          text,
+          targetCount: text.length,
+        });
+        return;
+      }
+
+      // bisection
+      const len = text.length;
+      const mid = Math.floor(len / 2);
+
+      const count = this.bisection(targetHeight, mid, 0, len, text, shadowNode);
+
+      this.setState({
+        text,
+        targetCount: count,
+      });
+    }
+  };
+
+  bisection = (th, m, b, e, text, shadowNode) => {
+    const suffix = '...';
+    let mid = m;
+    let end = e;
+    let begin = b;
+    shadowNode.innerHTML = text.substring(0, mid) + suffix;
+    let sh = shadowNode.offsetHeight;
+
+    if (sh <= th) {
+      shadowNode.innerHTML = text.substring(0, mid + 1) + suffix;
+      sh = shadowNode.offsetHeight;
+      if (sh > th) {
+        return mid;
+      } else {
+        begin = mid;
+        mid = Math.floor((end - begin) / 2) + begin;
+        return this.bisection(th, mid, begin, end, text, shadowNode);
+      }
+    } else {
+      if (mid - 1 < 0) {
+        return mid;
+      }
+      shadowNode.innerHTML = text.substring(0, mid - 1) + suffix;
+      sh = shadowNode.offsetHeight;
+      if (sh <= th) {
+        return mid - 1;
+      } else {
+        end = mid;
+        mid = Math.floor((end - begin) / 2) + begin;
+        return this.bisection(th, mid, begin, end, text, shadowNode);
+      }
+    }
+  };
+
+  handleRoot = (n) => {
+    this.root = n;
+  };
+
+  handleContent = (n) => {
+    this.content = n;
+  };
+
+  handleNode = (n) => {
+    this.node = n;
+  };
+
+  handleShadow = (n) => {
+    this.shadow = n;
+  };
+
+  handleShadowChildren = (n) => {
+    this.shadowChildren = n;
+  };
+
+  render() {
+    const { text, targetCount } = this.state;
+    const { children, lines, length, className, tooltip, ...restProps } = this.props;
+
+    const cls = classNames(styles.ellipsis, className, {
+      [styles.lines]: lines && !isSupportLineClamp,
+      [styles.lineClamp]: lines && isSupportLineClamp,
+    });
+
+    if (!lines && !length) {
+      return (
+        <span className={cls} {...restProps}>
+          {children}
+        </span>
+      );
+    }
+
+    // length
+    if (!lines) {
+      return (
+        <EllipsisText
+          className={cls}
+          length={length}
+          text={children || ''}
+          tooltip={tooltip}
+          {...restProps}
+        />
+      );
+    }
+
+    const id = `antd-pro-ellipsis-${`${new Date().getTime()}${Math.floor(Math.random() * 100)}`}`;
+
+    // support document.body.style.webkitLineClamp
+    if (isSupportLineClamp) {
+      const style = `#${id}{-webkit-line-clamp:${lines};-webkit-box-orient: vertical;}`;
+      return (
+        <div id={id} className={cls} {...restProps}>
+          <style>{style}</style>
+          {tooltip ? (
+            <Tooltip overlayStyle={{ wordBreak: 'break-all' }} title={children}>
+              {children}
+            </Tooltip>
+          ) : (
+            children
+          )}
+        </div>
+      );
+    }
+
+    const childNode = (
+      <span ref={this.handleNode}>
+        {targetCount > 0 && text.substring(0, targetCount)}
+        {targetCount > 0 && targetCount < text.length && '...'}
+      </span>
+    );
+
+    return (
+      <div {...restProps} ref={this.handleRoot} className={cls}>
+        <div ref={this.handleContent}>
+          {tooltip ? (
+            <Tooltip overlayStyle={{ wordBreak: 'break-all' }} title={text}>
+              {childNode}
+            </Tooltip>
+          ) : (
+            childNode
+          )}
+          <div className={styles.shadow} ref={this.handleShadowChildren}>
+            {children}
+          </div>
+          <div className={styles.shadow} ref={this.handleShadow}>
+            <span>{text}</span>
+          </div>
+        </div>
+      </div>
+    );
+  }
+}
diff --git a/src/components/Ellipsis/index.less b/src/components/Ellipsis/index.less
new file mode 100644
index 0000000..dd59e3f
--- /dev/null
+++ b/src/components/Ellipsis/index.less
@@ -0,0 +1,24 @@
+.ellipsis {
+  overflow: hidden;
+  display: inline-block;
+  word-break: break-all;
+  width: 100%;
+}
+
+.lines {
+  position: relative;
+  .shadow {
+    display: block;
+    position: relative;
+    color: transparent;
+    opacity: 0;
+    z-index: -999;
+  }
+}
+
+.lineClamp {
+  position: relative;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  display: -webkit-box;
+}
diff --git a/src/components/Ellipsis/index.md b/src/components/Ellipsis/index.md
new file mode 100644
index 0000000..e53cd1c
--- /dev/null
+++ b/src/components/Ellipsis/index.md
@@ -0,0 +1,18 @@
+---
+title:
+  en-US: Ellipsis 
+  zh-CN: Ellipsis
+subtitle: 文本自动省略号
+cols: 1
+order: 10
+---
+
+文本过长自动处理省略号,支持按照文本长度和最大行数两种方式截取。
+
+## API
+
+参数 | 说明 | 类型 | 默认值
+----|------|-----|------
+tooltip | 移动到文本展示完整内容的提示 | boolean | -
+length | 在按照长度截取下的文本最大字符数,超过则截取省略 | number | -
+lines | 在按照行数截取下最大的行数,超过则截取省略 | number | `1`
diff --git a/src/components/Exception/demo/403.md b/src/components/Exception/demo/403.md
new file mode 100644
index 0000000..85f0ad0
--- /dev/null
+++ b/src/components/Exception/demo/403.md
@@ -0,0 +1,21 @@
+---
+order: 2
+title: 403
+---
+
+403 页面,配合自定义操作。
+
+````jsx
+import Exception from 'ant-design-pro/lib/Exception';
+import { Button } from 'antd';
+
+const actions = (
+  <div>
+    <Button type="primary">回到首页</Button>
+    <Button>查看详情</Button>
+  </div>
+);
+ReactDOM.render(
+  <Exception type="403" actions={actions} />
+, mountNode);
+````
diff --git a/src/components/Exception/demo/404.md b/src/components/Exception/demo/404.md
new file mode 100644
index 0000000..6ff2de7
--- /dev/null
+++ b/src/components/Exception/demo/404.md
@@ -0,0 +1,14 @@
+---
+order: 0
+title: 404
+---
+
+404 页面。
+
+````jsx
+import Exception from 'ant-design-pro/lib/Exception';
+
+ReactDOM.render(
+  <Exception type="404" />
+, mountNode);
+````
diff --git a/src/components/Exception/demo/500.md b/src/components/Exception/demo/500.md
new file mode 100644
index 0000000..0ed9ced
--- /dev/null
+++ b/src/components/Exception/demo/500.md
@@ -0,0 +1,14 @@
+---
+order: 1
+title: 500
+---
+
+500 页面。
+
+````jsx
+import Exception from 'ant-design-pro/lib/Exception';
+
+ReactDOM.render(
+  <Exception type="500" />
+, mountNode);
+````
diff --git a/src/components/Exception/index.d.ts b/src/components/Exception/index.d.ts
new file mode 100644
index 0000000..037f866
--- /dev/null
+++ b/src/components/Exception/index.d.ts
@@ -0,0 +1,12 @@
+import * as React from "react";
+export interface ExceptionProps {
+  type?: "403" | "404" | "500";
+  title?: React.ReactNode;
+  desc?: React.ReactNode;
+  img?: string;
+  actions?: React.ReactNode;
+  linkElement?: React.ReactNode;
+  style?: React.CSSProperties;
+}
+
+export default class Exception extends React.Component<ExceptionProps, any> {}
diff --git a/src/components/Exception/index.js b/src/components/Exception/index.js
new file mode 100644
index 0000000..7d87704
--- /dev/null
+++ b/src/components/Exception/index.js
@@ -0,0 +1,33 @@
+import React, { createElement } from 'react';
+import classNames from 'classnames';
+import { Button } from 'antd';
+import config from './typeConfig';
+import styles from './index.less';
+
+export default ({ className, linkElement = 'a', type, title, desc, img, actions, ...rest }) => {
+  const pageType = type in config ? type : '404';
+  const clsString = classNames(styles.exception, className);
+  return (
+    <div className={clsString} {...rest}>
+      <div className={styles.imgBlock}>
+        <div
+          className={styles.imgEle}
+          style={{ backgroundImage: `url(${img || config[pageType].img})` }}
+        />
+      </div>
+      <div className={styles.content}>
+        <h1>{title || config[pageType].title}</h1>
+        <div className={styles.desc}>{desc || config[pageType].desc}</div>
+        <div className={styles.actions}>
+          {
+            actions ||
+              createElement(linkElement, {
+                to: '/',
+                href: '/',
+              }, <Button type="primary">返回首页</Button>)
+          }
+        </div>
+      </div>
+    </div>
+  );
+};
diff --git a/src/components/Exception/index.less b/src/components/Exception/index.less
new file mode 100644
index 0000000..394af17
--- /dev/null
+++ b/src/components/Exception/index.less
@@ -0,0 +1,88 @@
+@import "~antd/lib/style/themes/default.less";
+
+.exception {
+  display: flex;
+  align-items: center;
+  height: 100%;
+
+  .imgBlock {
+    flex: 0 0 62.5%;
+    width: 62.5%;
+    padding-right: 152px;
+    zoom: 1;
+    &:before,
+    &:after {
+      content: " ";
+      display: table;
+    }
+    &:after {
+      clear: both;
+      visibility: hidden;
+      font-size: 0;
+      height: 0;
+    }
+  }
+
+  .imgEle {
+    height: 360px;
+    width: 100%;
+    max-width: 430px;
+    float: right;
+    background-repeat: no-repeat;
+    background-position: 50% 50%;
+    background-size: contain;
+  }
+
+  .content {
+    flex: auto;
+
+    h1 {
+      color: #434e59;
+      font-size: 72px;
+      font-weight: 600;
+      line-height: 72px;
+      margin-bottom: 24px;
+    }
+
+    .desc {
+      color: @text-color-secondary;
+      font-size: 20px;
+      line-height: 28px;
+      margin-bottom: 16px;
+    }
+
+    .actions {
+      button:not(:last-child) {
+        margin-right: 8px;
+      }
+    }
+  }
+}
+
+@media screen and (max-width: @screen-xl) {
+  .exception {
+    .imgBlock {
+      padding-right: 88px;
+    }
+  }
+}
+
+@media screen and (max-width: @screen-sm) {
+  .exception {
+    display: block;
+    text-align: center;
+    .imgBlock {
+      padding-right: 0;
+      margin: 0 auto 24px;
+    }
+  }
+}
+
+@media screen and (max-width: @screen-xs) {
+  .exception {
+    .imgBlock {
+      margin-bottom: -24px;
+      overflow: hidden;
+    }
+  }
+}
diff --git a/src/components/Exception/index.md b/src/components/Exception/index.md
new file mode 100644
index 0000000..844146e
--- /dev/null
+++ b/src/components/Exception/index.md
@@ -0,0 +1,21 @@
+---
+title:
+  en-US: Exception
+  zh-CN: Exception
+subtitle: 异常
+cols: 1
+order: 5
+---
+
+异常页用于对页面特定的异常状态进行反馈。通常,它包含对错误状态的阐述,并向用户提供建议或操作,避免用户感到迷失和困惑。
+
+## API
+
+| 参数         | 说明                                      | 类型         | 默认值 |
+|-------------|------------------------------------------|-------------|-------|
+| type        | 页面类型,若配置,则自带对应类型默认的 `title`,`desc`,`img`,此默认设置可以被 `title`,`desc`,`img` 覆盖 | Enum {'403', '404', '500'} | - |
+| title       | 标题     | ReactNode  | -    |
+| desc        | 补充描述    | ReactNode  | -    |
+| img         | 背景图片地址     | string  | -    |
+| actions     | 建议操作,配置此属性时默认的『返回首页』按钮不生效    | ReactNode  | -    |
+| linkElement | 定义链接的元素,默认为 `a` | string\|ReactElement | - |
diff --git a/src/components/Exception/typeConfig.js b/src/components/Exception/typeConfig.js
new file mode 100644
index 0000000..b6e1ee5
--- /dev/null
+++ b/src/components/Exception/typeConfig.js
@@ -0,0 +1,19 @@
+const config = {
+  403: {
+    img: 'https://gw.alipayobjects.com/zos/rmsportal/wZcnGqRDyhPOEYFcZDnb.svg',
+    title: '403',
+    desc: '抱歉,你无权访问该页面',
+  },
+  404: {
+    img: 'https://gw.alipayobjects.com/zos/rmsportal/KpnpchXsobRgLElEozzI.svg',
+    title: '404',
+    desc: '抱歉,你访问的页面不存在',
+  },
+  500: {
+    img: 'https://gw.alipayobjects.com/zos/rmsportal/RVRUAYdCGeYNBWoKiIwB.svg',
+    title: '500',
+    desc: '抱歉,服务器出错了',
+  },
+};
+
+export default config;
diff --git a/src/components/FooterToolbar/demo/basic.md b/src/components/FooterToolbar/demo/basic.md
new file mode 100644
index 0000000..6ce15e7
--- /dev/null
+++ b/src/components/FooterToolbar/demo/basic.md
@@ -0,0 +1,36 @@
+---
+order: 0
+title: 演示
+iframe: 400
+---
+
+浮动固定页脚。
+
+````jsx
+import FooterToolbar from 'ant-design-pro/lib/FooterToolbar';
+import { Button } from 'antd';
+
+ReactDOM.render(
+  <div style={{ background: '#f7f7f7', padding: 24 }}>
+    <p>页面内容 页面内容 页面内容 页面内容</p>
+    <p>页面内容 页面内容 页面内容 页面内容</p>
+    <p>页面内容 页面内容 页面内容 页面内容</p>
+    <p>页面内容 页面内容 页面内容 页面内容</p>
+    <p>页面内容 页面内容 页面内容 页面内容</p>
+    <p>页面内容 页面内容 页面内容 页面内容</p>
+    <p>页面内容 页面内容 页面内容 页面内容</p>
+    <p>页面内容 页面内容 页面内容 页面内容</p>
+    <p>页面内容 页面内容 页面内容 页面内容</p>
+    <p>页面内容 页面内容 页面内容 页面内容</p>
+    <p>页面内容 页面内容 页面内容 页面内容</p>
+    <p>页面内容 页面内容 页面内容 页面内容</p>
+    <p>页面内容 页面内容 页面内容 页面内容</p>
+    <p>页面内容 页面内容 页面内容 页面内容</p>
+    <p>页面内容 页面内容 页面内容 页面内容</p>
+    <FooterToolbar extra="提示信息">
+      <Button>取消</Button>
+      <Button type="primary">提交</Button>
+    </FooterToolbar>
+  </div>
+, mountNode);
+````
diff --git a/src/components/FooterToolbar/index.d.ts b/src/components/FooterToolbar/index.d.ts
new file mode 100644
index 0000000..637bd4b
--- /dev/null
+++ b/src/components/FooterToolbar/index.d.ts
@@ -0,0 +1,10 @@
+import * as React from 'react';
+export interface FooterToolbarProps {
+  extra: React.ReactNode;
+  style?: React.CSSProperties;
+}
+
+export default class FooterToolbar extends React.Component<
+  FooterToolbarProps,
+  any
+> {}
diff --git a/src/components/FooterToolbar/index.js b/src/components/FooterToolbar/index.js
new file mode 100644
index 0000000..62527e9
--- /dev/null
+++ b/src/components/FooterToolbar/index.js
@@ -0,0 +1,18 @@
+import React, { Component } from 'react';
+import classNames from 'classnames';
+import styles from './index.less';
+
+export default class FooterToolbar extends Component {
+  render() {
+    const { children, className, extra, ...restProps } = this.props;
+    return (
+      <div
+        className={classNames(className, styles.toolbar)}
+        {...restProps}
+      >
+        <div className={styles.left}>{extra}</div>
+        <div className={styles.right}>{children}</div>
+      </div>
+    );
+  }
+}
diff --git a/src/components/FooterToolbar/index.less b/src/components/FooterToolbar/index.less
new file mode 100644
index 0000000..b6b6399
--- /dev/null
+++ b/src/components/FooterToolbar/index.less
@@ -0,0 +1,33 @@
+@import "~antd/lib/style/themes/default.less";
+
+.toolbar {
+  position: fixed;
+  width: 100%;
+  bottom: 0;
+  right: 0;
+  height: 56px;
+  line-height: 56px;
+  box-shadow: 0 -1px 2px rgba(0, 0, 0, .03);
+  background: #fff;
+  border-top: 1px solid @border-color-split;
+  padding: 0 24px;
+  z-index: 9;
+
+  &:after {
+    content: "";
+    display: block;
+    clear: both;
+  }
+
+  .left {
+    float: left;
+  }
+
+  .right {
+    float: right;
+  }
+
+  button + button {
+    margin-left: 8px;
+  }
+}
diff --git a/src/components/FooterToolbar/index.md b/src/components/FooterToolbar/index.md
new file mode 100644
index 0000000..b0bea3d
--- /dev/null
+++ b/src/components/FooterToolbar/index.md
@@ -0,0 +1,21 @@
+---
+title:
+  en-US: FooterToolbar
+  zh-CN: FooterToolbar
+subtitle: 底部工具栏
+cols: 1
+order: 6
+---
+
+固定在底部的工具栏。
+
+## 何时使用
+
+固定在内容区域的底部,不随滚动条移动,常用于长页面的数据搜集和提交工作。
+
+## API
+
+参数 | 说明 | 类型 | 默认值
+----|------|-----|------
+children | 工具栏内容,向右对齐 | ReactNode | -
+extra | 额外信息,向左对齐 | ReactNode | -
diff --git a/src/components/GlobalFooter/demo/basic.md b/src/components/GlobalFooter/demo/basic.md
new file mode 100644
index 0000000..9a06bad
--- /dev/null
+++ b/src/components/GlobalFooter/demo/basic.md
@@ -0,0 +1,37 @@
+---
+order: 0
+title: 演示
+iframe: 400
+---
+
+基本页脚。
+
+````jsx
+import GlobalFooter from 'ant-design-pro/lib/GlobalFooter';
+import { Icon } from 'antd';
+
+const links = [{
+  key: '帮助',
+  title: '帮助',
+  href: '',
+}, {
+  key: 'github',
+  title: <Icon type="github" />,
+  href: 'https://github.com/ant-design/ant-design-pro',
+  blankTarget: true,
+}, {
+  key: '条款',
+  title: '条款',
+  href: '',
+  blankTarget: true,
+}];
+
+const copyright = <div>Copyright <Icon type="copyright" /> 2017 蚂蚁金服体验技术部出品</div>;
+
+ReactDOM.render(
+  <div style={{ background: '#f5f5f5', overflow: 'hidden' }}>
+    <div style={{ height: 280 }} />
+    <GlobalFooter links={links} copyright={copyright} />
+  </div>
+, mountNode);
+````
diff --git a/src/components/GlobalFooter/index.d.ts b/src/components/GlobalFooter/index.d.ts
new file mode 100644
index 0000000..faf633b
--- /dev/null
+++ b/src/components/GlobalFooter/index.d.ts
@@ -0,0 +1,15 @@
+import * as React from "react";
+export interface GlobalFooterProps {
+  links?: Array<{
+    title: React.ReactNode;
+    href: string;
+    blankTarget?: boolean;
+  }>;
+  copyright?: React.ReactNode;
+  style?: React.CSSProperties;
+}
+
+export default class GlobalFooter extends React.Component<
+  GlobalFooterProps,
+  any
+> {}
diff --git a/src/components/GlobalFooter/index.js b/src/components/GlobalFooter/index.js
new file mode 100644
index 0000000..36abafc
--- /dev/null
+++ b/src/components/GlobalFooter/index.js
@@ -0,0 +1,27 @@
+import React from 'react';
+import classNames from 'classnames';
+import styles from './index.less';
+
+export default ({ className, links, copyright }) => {
+  const clsString = classNames(styles.globalFooter, className);
+  return (
+    <div className={clsString}>
+      {
+        links && (
+          <div className={styles.links}>
+            {links.map(link => (
+              <a
+                key={link.key}
+                target={link.blankTarget ? '_blank' : '_self'}
+                href={link.href}
+              >
+                {link.title}
+              </a>
+            ))}
+          </div>
+        )
+      }
+      {copyright && <div className={styles.copyright}>{copyright}</div>}
+    </div>
+  );
+};
diff --git a/src/components/GlobalFooter/index.less b/src/components/GlobalFooter/index.less
new file mode 100644
index 0000000..7fce600
--- /dev/null
+++ b/src/components/GlobalFooter/index.less
@@ -0,0 +1,29 @@
+@import "~antd/lib/style/themes/default.less";
+
+.globalFooter {
+  padding: 0 16px;
+  margin: 48px 0 24px 0;
+  text-align: center;
+
+  .links {
+    margin-bottom: 8px;
+
+    a {
+      color: @text-color-secondary;
+      transition: all .3s;
+
+      &:not(:last-child) {
+        margin-right: 40px;
+      }
+
+      &:hover {
+        color: @text-color;
+      }
+    }
+  }
+
+  .copyright {
+    color: @text-color-secondary;
+    font-size: @font-size-base;
+  }
+}
diff --git a/src/components/GlobalFooter/index.md b/src/components/GlobalFooter/index.md
new file mode 100644
index 0000000..55b4be4
--- /dev/null
+++ b/src/components/GlobalFooter/index.md
@@ -0,0 +1,17 @@
+---
+title:
+  en-US: GlobalFooter
+  zh-CN: GlobalFooter
+subtitle: 全局页脚
+cols: 1
+order: 7
+---
+
+页脚属于全局导航的一部分,作为对顶部导航的补充,通过传递数据控制展示内容。
+
+## API
+
+参数 | 说明 | 类型 | 默认值
+----|------|-----|------
+links | 链接数据 | array<{ title: ReactNode, href: string, blankTarget?: boolean }> | -
+copyright | 版权信息 | ReactNode | -
diff --git a/src/components/GlobalHeader/index.js b/src/components/GlobalHeader/index.js
new file mode 100644
index 0000000..83898d0
--- /dev/null
+++ b/src/components/GlobalHeader/index.js
@@ -0,0 +1,119 @@
+import React, { PureComponent } from 'react';
+import { Layout, Icon, Tag, Divider } from 'antd';
+import moment from 'moment';
+import groupBy from 'lodash/groupBy';
+import Debounce from 'lodash-decorators/debounce';
+import { Link } from 'dva/router';
+import NoticeIcon from '../NoticeIcon';
+import DurationIcon from '../Duration/Icon';
+import styles from './index.less';
+
+const { Header } = Layout;
+
+export default class GlobalHeader extends PureComponent {
+  componentWillUnmount() {
+    this.triggerResizeEvent.cancel();
+  }
+  getNoticeData() {
+    const { notices = [] } = this.props;
+    if (notices.length === 0) {
+      return {};
+    }
+    const newNotices = notices.map((notice) => {
+      const newNotice = { ...notice };
+      if (newNotice.datetime) {
+        newNotice.datetime = moment(notice.datetime).fromNow();
+      }
+      // transform id to item key
+      if (newNotice.id) {
+        newNotice.key = newNotice.id;
+      }
+      if (newNotice.extra && newNotice.status) {
+        const color = ({
+          todo: '',
+          processing: 'blue',
+          urgent: 'red',
+          doing: 'gold',
+        })[newNotice.status];
+        newNotice.extra = <Tag color={color} style={{ marginRight: 0 }}>{newNotice.extra}</Tag>;
+      }
+      return newNotice;
+    });
+    return groupBy(newNotices, 'type');
+  }
+  toggle = () => {
+    const { collapsed, onCollapse } = this.props;
+    onCollapse(!collapsed);
+    this.triggerResizeEvent();
+  }
+  @Debounce(600)
+  triggerResizeEvent() { // eslint-disable-line
+    const event = document.createEvent('HTMLEvents');
+    event.initEvent('resize', true, false);
+    window.dispatchEvent(event);
+  }
+  render() {
+    const {
+      collapsed, fetchingNotices, isMobile, logo, selectedDuration,
+      onNoticeVisibleChange, onNoticeClear, onDurationToggle, onDurationReload,
+    } = this.props;
+    const noticeData = this.getNoticeData();
+    return (
+      <Header className={styles.header}>
+        {isMobile && (
+          [
+            (
+              <Link to="/" className={styles.logo} key="logo">
+                <img src={logo} alt="logo" width="32" />
+              </Link>
+            ),
+            <Divider type="vertical" key="line" />,
+          ]
+        )}
+        <Icon
+          className={styles.trigger}
+          type={collapsed ? 'menu-unfold' : 'menu-fold'}
+          onClick={this.toggle}
+        />
+        <div className={styles.right}>
+          <DurationIcon
+            className={styles.action}
+            selectedDuration={selectedDuration}
+            onToggle={onDurationToggle}
+            onReload={onDurationReload}
+          />
+          <NoticeIcon
+            className={styles.action}
+            count={1}
+            onItemClick={(item, tabProps) => {
+              console.log(item, tabProps); // eslint-disable-line
+            }}
+            onClear={onNoticeClear}
+            onPopupVisibleChange={onNoticeVisibleChange}
+            loading={fetchingNotices}
+            popupAlign={{ offset: [20, -16] }}
+          >
+            <NoticeIcon.Tab
+              list={noticeData['通知']}
+              title="通知"
+              emptyText="你已查看所有通知"
+              emptyImage="https://gw.alipayobjects.com/zos/rmsportal/wAhyIChODzsoKIOBHcBk.svg"
+            />
+            <NoticeIcon.Tab
+              list={noticeData['消息']}
+              title="消息"
+              emptyText="您已读完所有消息"
+              emptyImage="https://gw.alipayobjects.com/zos/rmsportal/sAuJeJzSKbUmHfBQRzmZ.svg"
+            />
+            <NoticeIcon.Tab
+              list={noticeData['待办']}
+              title="待办"
+              emptyText="你已完成所有待办"
+              emptyImage="https://gw.alipayobjects.com/zos/rmsportal/HsIsxMZiWKrNUavQUXqx.svg"
+            />
+          </NoticeIcon>
+        </div>
+      </Header>
+    );
+  }
+}
diff --git a/src/main/frontend/src/layouts/BasicLayout.less b/src/components/GlobalHeader/index.less
similarity index 58%
rename from src/main/frontend/src/layouts/BasicLayout.less
rename to src/components/GlobalHeader/index.less
index 2d40068..f1c38bd 100644
--- a/src/main/frontend/src/layouts/BasicLayout.less
+++ b/src/components/GlobalHeader/index.less
@@ -7,54 +7,47 @@
   position: relative;
 }
 
+:global {
+  .ant-layout {
+    min-height: 100vh;
+    overflow-x: hidden;
+  }
+}
+
 .logo {
   height: 64px;
-  position: relative;
-  line-height: 64px;
-  padding-left: 24px;
-  transition: all .3s;
-  background: #002140;
-  overflow: hidden;
+  line-height: 58px;
+  vertical-align: top;
+  display: inline-block;
+  padding: 0 0 0 24px;
+  cursor: pointer;
+  font-size: 20px;
   img {
     display: inline-block;
     vertical-align: middle;
-    height: 32px;
-  }
-  h1 {
-    color: #fff;
-    display: inline-block;
-    vertical-align: middle;
-    font-size: 20px;
-    margin: 0 0 0 12px;
-    font-family: 'Myriad Pro', 'Helvetica Neue', Arial, Helvetica, sans-serif;
-    font-weight: 600;
   }
 }
 
-:global(.ant-layout-sider-collapsed) .logo {
-  padding-left: 24px;
-  > a {
-    width: 32px;
+.menu {
+  :global(.anticon) {
+    margin-right: 8px;
+  }
+  :global(.ant-dropdown-menu-item) {
+    width: 160px;
   }
 }
 
-.trigger {
+i.trigger {
   font-size: 20px;
   line-height: 64px;
   cursor: pointer;
-  transition: all .3s;
+  transition: all .3s, padding 0s;
   padding: 0 24px;
   &:hover {
     background: @primary-1;
   }
 }
 
-@media screen and (max-width: @screen-xs) {
-  .trigger {
-    display: none;
-  }
-}
-
 .right {
   float: right;
   height: 100%;
@@ -68,8 +61,8 @@
       font-size: 16px;
       vertical-align: middle;
     }
-    &:global(.ant-popover-open),
-    &:hover {
+    &:hover,
+    &:global(.ant-popover-open) {
       background: @primary-1;
     }
   }
@@ -90,28 +83,31 @@
   }
 }
 
-.menu {
-  :global(.anticon) {
-    margin-right: 8px;
-  }
-  :global(.ant-dropdown-menu-item) {
-    width: 160px;
-  }
-}
-
-:global {
-  .ant-layout {
-    overflow-x: hidden;
+@media only screen and (max-width: @screen-md) {
+  .header {
+    :global(.ant-divider-vertical) {
+      vertical-align: unset;
+    }
+    .name {
+      display: none;
+    }
+    i.trigger {
+      padding: 0 12px;
+    }
+    .logo {
+      padding-right: 12px;
+      position: relative;
+    }
+    .right {
+      position: absolute;
+      right: 12px;
+      top: 0;
+      background: #fff;
+      .account {
+        .avatar {
+          margin-right: 0;
+        }
+      }
+    }
   }
 }
-
-.sider {
-  min-height: 100vh;
-  box-shadow: 2px 0 6px rgba(0, 21, 41, .35);
-  position: relative;
-  z-index: 10;
-}
-
-.selecttime-hide {
-  display: none;
-}
diff --git a/src/components/HeaderSearch/demo/basic.md b/src/components/HeaderSearch/demo/basic.md
new file mode 100644
index 0000000..2139207
--- /dev/null
+++ b/src/components/HeaderSearch/demo/basic.md
@@ -0,0 +1,34 @@
+---
+order: 0
+title: 全局搜索
+---
+
+通常放置在导航工具条右侧。(点击搜索图标预览效果)
+
+````jsx
+import HeaderSearch from 'ant-design-pro/lib/HeaderSearch';
+
+ReactDOM.render(
+  <div
+    style={{
+      textAlign: 'right',
+      height: '64px',
+      lineHeight: '64px',
+      boxShadow: '0 1px 4px rgba(0,21,41,.12)',
+      padding: '0 32px',
+      width: '400px',
+    }}
+  >
+    <HeaderSearch
+      placeholder="站内搜索"
+      dataSource={['搜索提示一', '搜索提示二', '搜索提示三']}
+      onSearch={(value) => {
+        console.log('input', value); // eslint-disable-line
+      }}
+      onPressEnter={(value) => {
+        console.log('enter', value); // eslint-disable-line
+      }}
+    />
+  </div>
+, mountNode);
+````
diff --git a/src/components/HeaderSearch/index.d.ts b/src/components/HeaderSearch/index.d.ts
new file mode 100644
index 0000000..58316df
--- /dev/null
+++ b/src/components/HeaderSearch/index.d.ts
@@ -0,0 +1,14 @@
+import * as React from 'react';
+export interface HeaderSearchProps {
+  placeholder?: string;
+  dataSource?: Array<string>;
+  onSearch?: (value: string) => void;
+  onChange?: (value: string) => void;
+  onPressEnter?: (value: string) => void;
+  style?: React.CSSProperties;
+}
+
+export default class HeaderSearch extends React.Component<
+  HeaderSearchProps,
+  any
+> {}
diff --git a/src/components/HeaderSearch/index.js b/src/components/HeaderSearch/index.js
new file mode 100644
index 0000000..85c990e
--- /dev/null
+++ b/src/components/HeaderSearch/index.js
@@ -0,0 +1,85 @@
+import React, { PureComponent } from 'react';
+import PropTypes from 'prop-types';
+import { Input, Icon, AutoComplete } from 'antd';
+import classNames from 'classnames';
+import styles from './index.less';
+
+export default class HeaderSearch extends PureComponent {
+  static defaultProps = {
+    defaultActiveFirstOption: false,
+    onPressEnter: () => {},
+    onSearch: () => {},
+    className: '',
+    placeholder: '',
+    dataSource: [],
+  };
+  static propTypes = {
+    className: PropTypes.string,
+    placeholder: PropTypes.string,
+    onSearch: PropTypes.func,
+    onPressEnter: PropTypes.func,
+    defaultActiveFirstOption: PropTypes.bool,
+    dataSource: PropTypes.array,
+  };
+  state = {
+    searchMode: false,
+    value: '',
+  };
+  componentWillUnmount() {
+    clearTimeout(this.timeout);
+  }
+  onKeyDown = (e) => {
+    if (e.key === 'Enter') {
+      this.timeout = setTimeout(() => {
+        this.props.onPressEnter(this.state.value); // Fix duplicate onPressEnter
+      }, 0);
+    }
+  }
+  onChange = (value) => {
+    this.setState({ value });
+    if (this.props.onChange) {
+      this.props.onChange();
+    }
+  }
+  enterSearchMode = () => {
+    this.setState({ searchMode: true }, () => {
+      if (this.state.searchMode) {
+        this.input.focus();
+      }
+    });
+  }
+  leaveSearchMode = () => {
+    this.setState({
+      searchMode: false,
+      value: '',
+    });
+  }
+  render() {
+    const { className, placeholder, ...restProps } = this.props;
+    const inputClass = classNames(styles.input, {
+      [styles.show]: this.state.searchMode,
+    });
+    return (
+      <span
+        className={classNames(className, styles.headerSearch)}
+        onClick={this.enterSearchMode}
+      >
+        <Icon type="search" key="Icon" />
+        <AutoComplete
+          key="AutoComplete"
+          {...restProps}
+          className={inputClass}
+          value={this.state.value}
+          onChange={this.onChange}
+        >
+          <Input
+            placeholder={placeholder}
+            ref={(node) => { this.input = node; }}
+            onKeyDown={this.onKeyDown}
+            onBlur={this.leaveSearchMode}
+          />
+        </AutoComplete>
+      </span>
+    );
+  }
+}
diff --git a/src/components/HeaderSearch/index.less b/src/components/HeaderSearch/index.less
new file mode 100644
index 0000000..3743308
--- /dev/null
+++ b/src/components/HeaderSearch/index.less
@@ -0,0 +1,32 @@
+@import "~antd/lib/style/themes/default.less";
+
+.headerSearch {
+  :global(.anticon-search) {
+    cursor: pointer;
+    font-size: 16px;
+  }
+  .input {
+    transition: width .3s, margin-left .3s;
+    width: 0;
+    background: transparent;
+    border-radius: 0;
+    :global(.ant-select-selection) {
+      background: transparent;
+    }
+    input {
+      border: 0;
+      padding-left: 0;
+      padding-right: 0;
+      box-shadow: none !important;
+    }
+    &,
+    &:hover,
+    &:focus {
+      border-bottom: 1px solid @border-color-base;
+    }
+    &.show {
+      width: 210px;
+      margin-left: 8px;
+    }
+  }
+}
diff --git a/src/components/HeaderSearch/index.md b/src/components/HeaderSearch/index.md
new file mode 100644
index 0000000..5c8fd70
--- /dev/null
+++ b/src/components/HeaderSearch/index.md
@@ -0,0 +1,20 @@
+---
+title:
+  en-US: HeaderSearch
+  zh-CN: HeaderSearch
+subtitle: 顶部搜索框
+cols: 1
+order: 8
+---
+
+通常作为全局搜索的入口,放置在导航工具条右侧。
+
+## API
+
+参数 | 说明 | 类型 | 默认值
+----|------|-----|------
+placeholder | 占位文字 | string | -
+dataSource | 当前提示内容列表 | string[] | -
+onSearch | 选择某项或按下回车时的回调 | function(value) | -
+onChange | 输入搜索字符的回调 | function(value) | -
+onPressEnter | 按下回车时的回调 | function(value) | -
diff --git a/src/components/Login/LoginItem.js b/src/components/Login/LoginItem.js
new file mode 100644
index 0000000..b7332b2
--- /dev/null
+++ b/src/components/Login/LoginItem.js
@@ -0,0 +1,104 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import { Form, Button, Row, Col } from 'antd';
+import omit from 'omit.js';
+import styles from './index.less';
+import map from './map';
+
+const FormItem = Form.Item;
+
+function generator({ defaultProps, defaultRules, type }) {
+  return (WrappedComponent) => {
+    return class BasicComponent extends Component {
+      static contextTypes = {
+        form: PropTypes.object,
+        updateActive: PropTypes.func,
+      };
+      constructor(props) {
+        super(props);
+        this.state = {
+          count: 0,
+        };
+      }
+      componentDidMount() {
+        if (this.context.updateActive) {
+          this.context.updateActive(this.props.name);
+        }
+      }
+      componentWillUnmount() {
+        clearInterval(this.interval);
+      }
+      onGetCaptcha = () => {
+        let count = 59;
+        this.setState({ count });
+        if (this.props.onGetCaptcha) {
+          this.props.onGetCaptcha();
+        }
+        this.interval = setInterval(() => {
+          count -= 1;
+          this.setState({ count });
+          if (count === 0) {
+            clearInterval(this.interval);
+          }
+        }, 1000);
+      }
+      render() {
+        const { getFieldDecorator } = this.context.form;
+        const options = {};
+        let otherProps = {};
+        const { onChange, defaultValue, rules, name, ...restProps } = this.props;
+        const { count } = this.state;
+        options.rules = rules || defaultRules;
+        if (onChange) {
+          options.onChange = onChange;
+        }
+        if (defaultValue) {
+          options.initialValue = defaultValue;
+        }
+        otherProps = restProps || otherProps;
+        if (type === 'Captcha') {
+          const inputProps = omit(otherProps, ['onGetCaptcha']);
+          return (
+            <FormItem>
+              <Row gutter={8}>
+                <Col span={16}>
+                  {getFieldDecorator(name, options)(
+                    <WrappedComponent {...defaultProps} {...inputProps} />
+                  )}
+                </Col>
+                <Col span={8}>
+                  <Button
+                    disabled={count}
+                    className={styles.getCaptcha}
+                    size="large"
+                    onClick={this.onGetCaptcha}
+                  >
+                    {count ? `${count} s` : '获取验证码'}
+                  </Button>
+                </Col>
+              </Row>
+            </FormItem>
+          );
+        }
+        return (
+          <FormItem>
+            {getFieldDecorator(name, options)(
+              <WrappedComponent {...defaultProps} {...otherProps} />
+            )}
+          </FormItem>
+        );
+      }
+    };
+  };
+}
+
+const LoginItem = {};
+Object.keys(map).forEach((item) => {
+  LoginItem[item] = generator({
+    defaultProps: map[item].props,
+    defaultRules: map[item].rules,
+    type: item,
+  })(map[item].component);
+});
+
+export default LoginItem;
diff --git a/src/components/Login/LoginSubmit.js b/src/components/Login/LoginSubmit.js
new file mode 100644
index 0000000..8770a97
--- /dev/null
+++ b/src/components/Login/LoginSubmit.js
@@ -0,0 +1,15 @@
+import React from 'react';
+import classNames from 'classnames';
+import { Button, Form } from 'antd';
+import styles from './index.less';
+
+const FormItem = Form.Item;
+
+export default ({ className, ...rest }) => {
+  const clsString = classNames(styles.submit, className);
+  return (
+    <FormItem>
+      <Button size="large" className={clsString} type="primary" htmlType="submit" {...rest} />
+    </FormItem>
+  );
+};
diff --git a/src/components/Login/LoginTab.js b/src/components/Login/LoginTab.js
new file mode 100644
index 0000000..750bfe7
--- /dev/null
+++ b/src/components/Login/LoginTab.js
@@ -0,0 +1,32 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import { Tabs } from 'antd';
+
+const { TabPane } = Tabs;
+
+const generateId = (() => {
+  let i = 0;
+  return (prefix = '') => {
+    i += 1;
+    return `${prefix}${i}`;
+  };
+})();
+
+export default class LoginTab extends Component {
+  static __ANT_PRO_LOGIN_TAB = true;
+  static contextTypes = {
+    tabUtil: PropTypes.object,
+  };
+  constructor(props) {
+    super(props);
+    this.uniqueId = generateId('login-tab-');
+  }
+  componentWillMount() {
+    if (this.context.tabUtil) {
+      this.context.tabUtil.addTab(this.uniqueId);
+    }
+  }
+  render() {
+    return <TabPane {...this.props} />;
+  }
+}
diff --git a/src/components/Login/demo/basic.md b/src/components/Login/demo/basic.md
new file mode 100644
index 0000000..1fca454
--- /dev/null
+++ b/src/components/Login/demo/basic.md
@@ -0,0 +1,113 @@
+---
+order: 0
+title: Standard Login
+---
+
+支持账号密码及手机号登录两种模式。
+
+````jsx
+import Login from 'ant-design-pro/lib/Login';
+import { Alert, Checkbox } from 'antd';
+
+const { Tab, UserName, Password, Mobile, Captcha, Submit } = Login;
+
+class LoginDemo extends React.Component {
+  state = {
+    notice: '',
+    type: 'tab2',
+    autoLogin: true,
+  }
+  onSubmit = (err, values) => {
+    console.log('value collected ->', { ...values, autoLogin: this.state.autoLogin });
+    if (this.state.type === 'tab1') {
+      this.setState({
+        notice: '',
+      }, () => {
+        if (!err && (values.username !== 'admin' || values.password !== '888888')) {
+          setTimeout(() => {
+            this.setState({
+              notice: '账号或密码错误!',
+            });
+          }, 500);
+        }
+      });
+    }
+  }
+  onTabChange = (key) => {
+    this.setState({
+      type: key,
+    });
+  }
+  changeAutoLogin = (e) => {
+    this.setState({
+      autoLogin: e.target.checked,
+    });
+  }
+  render() {
+    return (
+      <Login
+        defaultActiveKey={this.state.type}
+        onTabChange={this.onTabChange}
+        onSubmit={this.onSubmit}
+      >
+        <Tab key="tab1" tab="账号密码登录">
+          {
+            this.state.notice &&
+            <Alert style={{ marginBottom: 24 }} message={this.state.notice} type="error" showIcon closable />
+          }
+          <UserName name="username" />
+          <Password name="password" />
+        </Tab>
+        <Tab key="tab2" tab="手机号登录">
+          <Mobile name="mobile" />
+          <Captcha onGetCaptcha={() => console.log('Get captcha!')} name="captcha" />
+        </Tab>
+        <div>
+          <Checkbox checked={this.state.autoLogin} onChange={this.changeAutoLogin}>自动登录</Checkbox>
+          <a style={{ float: 'right' }} href="">忘记密码</a>
+        </div>
+        <Submit>登录</Submit>
+        <div>
+          其他登录方式
+          <span className="icon icon-alipay" />
+          <span className="icon icon-taobao" />
+          <span className="icon icon-weibo" />
+          <a style={{ float: 'right' }} href="">注册账户</a>
+        </div>
+      </Login>
+    );
+  }
+}
+
+ReactDOM.render(<LoginDemo />, mountNode);
+````
+
+<style>
+#scaffold-src-components-Login-demo-basic .icon {
+  display: inline-block;
+  width: 24px;
+  height: 24px;
+  background: url('https://gw.alipayobjects.com/zos/rmsportal/itDzjUnkelhQNsycranf.svg');
+  margin-left: 16px;
+  vertical-align: middle;
+  cursor: pointer;
+}
+#scaffold-src-components-Login-demo-basic .icon-alipay {
+  background-position: -24px 0;
+}
+#scaffold-src-components-Login-demo-basic .icon-alipay:hover {
+  background-position: 0 0;
+}
+#scaffold-src-components-Login-demo-basic .icon-taobao {
+  background-position: -24px -24px;
+}
+#scaffold-src-components-Login-demo-basic .icon-taobao:hover {
+  background-position: 0 -24px;
+}
+#scaffold-src-components-Login-demo-basic .icon-weibo {
+  background-position: -24px -48px;
+}
+#scaffold-src-components-Login-demo-basic .icon-weibo:hover {
+  background-position: 0 -48px;
+}
+</style>
diff --git a/src/components/Login/index.d.ts b/src/components/Login/index.d.ts
new file mode 100644
index 0000000..7984292
--- /dev/null
+++ b/src/components/Login/index.d.ts
@@ -0,0 +1,32 @@
+import * as React from "react";
+import Button from "antd/lib/button";
+export interface LoginProps {
+  defaultActiveKey?: string;
+  onTabChange?: (key: string) => void;
+  style?: React.CSSProperties;
+  onSubmit?: (error: any, values: any) => void;
+}
+
+export interface TabProps {
+  key?: string;
+  tab?: React.ReactNode;
+}
+export class Tab extends React.Component<TabProps, any> {}
+
+export interface LoginItemProps {
+  name?: string;
+  rules?: any[];
+  style?: React.CSSProperties;
+  onGetCaptcha?: () => void;
+}
+
+export class LoginItem extends React.Component<LoginItemProps, any> {}
+
+export default class Login extends React.Component<LoginProps, any> {
+  static Tab: typeof Tab;
+  static UserName: typeof LoginItem;
+  static Password: typeof LoginItem;
+  static Mobile: typeof LoginItem;
+  static Captcha: typeof LoginItem;
+  static Submit: typeof Button;
+}
diff --git a/src/components/Login/index.js b/src/components/Login/index.js
new file mode 100644
index 0000000..58ce029
--- /dev/null
+++ b/src/components/Login/index.js
@@ -0,0 +1,124 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import { Form, Tabs } from 'antd';
+import classNames from 'classnames';
+import LoginItem from './LoginItem';
+import LoginTab from './LoginTab';
+import LoginSubmit from './LoginSubmit';
+import styles from './index.less';
+
+@Form.create()
+class Login extends Component {
+  static defaultProps = {
+    className: '',
+    defaultActiveKey: '',
+    onTabChange: () => {},
+    onSubmit: () => {},
+  };
+  static propTypes = {
+    className: PropTypes.string,
+    defaultActiveKey: PropTypes.string,
+    onTabChange: PropTypes.func,
+    onSubmit: PropTypes.func,
+  };
+  static childContextTypes = {
+    tabUtil: PropTypes.object,
+    form: PropTypes.object,
+    updateActive: PropTypes.func,
+  };
+  state = {
+    type: this.props.defaultActiveKey,
+    tabs: [],
+    active: {},
+  };
+  getChildContext() {
+    return {
+      tabUtil: {
+        addTab: (id) => {
+          this.setState({
+            tabs: [...this.state.tabs, id],
+          });
+        },
+        removeTab: (id) => {
+          this.setState({
+            tabs: this.state.tabs.filter(currentId => currentId !== id),
+          });
+        },
+      },
+      form: this.props.form,
+      updateActive: (activeItem) => {
+        const { type, active } = this.state;
+        if (active[type]) {
+          active[type].push(activeItem);
+        } else {
+          active[type] = [activeItem];
+        }
+        this.setState({
+          active,
+        });
+      },
+    };
+  }
+  onSwitch = (type) => {
+    this.setState({
+      type,
+    });
+    this.props.onTabChange(type);
+  }
+  handleSubmit = (e) => {
+    e.preventDefault();
+    const { active, type } = this.state;
+    const activeFileds = active[type];
+    this.props.form.validateFields(activeFileds, { force: true },
+      (err, values) => {
+        this.props.onSubmit(err, values);
+      }
+    );
+  }
+  render() {
+    const { className, children } = this.props;
+    const { type, tabs } = this.state;
+    const TabChildren = [];
+    const otherChildren = [];
+    React.Children.forEach(children, (item) => {
+      if (!item) {
+        return;
+      }
+      // eslint-disable-next-line
+      if (item.type.__ANT_PRO_LOGIN_TAB) {
+        TabChildren.push(item);
+      } else {
+        otherChildren.push(item);
+      }
+    });
+    return (
+      <div className={classNames(className, styles.login)}>
+        <Form onSubmit={this.handleSubmit}>
+          {
+            tabs.length ? (
+              <div>
+                <Tabs
+                  animated={false}
+                  className={styles.tabs}
+                  activeKey={type}
+                  onChange={this.onSwitch}
+                >
+                  {TabChildren}
+                </Tabs>
+                {otherChildren}
+              </div>
+            ) : [...children]
+          }
+        </Form>
+      </div>
+    );
+  }
+}
+
+Login.Tab = LoginTab;
+Login.Submit = LoginSubmit;
+Object.keys(LoginItem).forEach((item) => {
+  Login[item] = LoginItem[item];
+});
+
+export default Login;
diff --git a/src/components/Login/index.less b/src/components/Login/index.less
new file mode 100644
index 0000000..331ed5a
--- /dev/null
+++ b/src/components/Login/index.less
@@ -0,0 +1,45 @@
+@import "~antd/lib/style/themes/default.less";
+
+.login {
+
+  .tabs {
+    padding: 0 2px;
+    margin: 0 -2px;
+    :global {
+      .ant-tabs-tab {
+        font-size: 16px;
+        line-height: 24px;
+      }
+      .ant-input-affix-wrapper .ant-input:not(:first-child) {
+        padding-left: 34px;
+      }
+    }
+  }
+
+  :global {
+    .ant-tabs .ant-tabs-bar {
+      border-bottom: 0;
+      margin-bottom: 24px;
+      text-align: center;
+    }
+
+    .ant-form-item {
+      margin-bottom: 24px;
+    }
+  }
+
+  .prefixIcon {
+    font-size: @font-size-base;
+    color: @disabled-color;
+  }
+
+  .getCaptcha {
+    display: block;
+    width: 100%;
+  }
+
+  .submit {
+    width: 100%;
+    margin-top: 24px;
+  }
+}
diff --git a/src/components/Login/index.md b/src/components/Login/index.md
new file mode 100644
index 0000000..a56be08
--- /dev/null
+++ b/src/components/Login/index.md
@@ -0,0 +1,51 @@
+---
+title:
+  en-US: Login
+  zh-CN: Login
+subtitle: 登录
+cols: 1
+order: 15
+---
+
+支持多种登录方式切换,内置了几种常见的登录控件,可以灵活组合,也支持和自定义控件配合使用。
+
+## API
+
+### Login
+
+参数 | 说明 | 类型 | 默认值
+----|------|-----|------
+defaultActiveKey | 默认激活 tab 面板的 key | String | -
+onTabChange | 切换页签时的回调 | (key) => void | -
+onSubmit | 点击提交时的回调 | (err, values) => void | -
+
+### Login.Tab
+
+参数 | 说明 | 类型 | 默认值
+----|------|-----|------
+key | 对应选项卡的 key | String | -
+tab | 选项卡头显示文字 | ReactNode | -
+
+### Login.UserName
+
+参数 | 说明 | 类型 | 默认值
+----|------|-----|------
+name | 控件标记,提交数据中同样以此为 key | String | -
+rules | 校验规则,同 Form getFieldDecorator(id, options) 中 [option.rules 的规则](getFieldDecorator(id, options)) | object[] | -
+
+除上述属性以外,Login.UserName 还支持 antd.Input 的所有属性,并且自带默认的基础配置,包括 `placeholder` `size` `prefix` 等,这些基础配置均可被覆盖。
+
+### Login.Password、Login.Mobile 同 Login.UserName
+
+### Login.Captcha 
+
+参数 | 说明 | 类型 | 默认值
+----|------|-----|------
+onGetCaptcha | 点击获取校验码的回调 | () => void | -
+
+除上述属性以外,Login.Captcha 支持的属性与 Login.UserName 相同。
+
+### Login.Submit
+
+支持 antd.Button 的所有属性。
+
diff --git a/src/components/Login/map.js b/src/components/Login/map.js
new file mode 100644
index 0000000..81fd7a2
--- /dev/null
+++ b/src/components/Login/map.js
@@ -0,0 +1,55 @@
+import React from 'react';
+import { Input, Icon } from 'antd';
+import styles from './index.less';
+
+const map = {
+  UserName: {
+    component: Input,
+    props: {
+      size: 'large',
+      prefix: <Icon type="user" className={styles.prefixIcon} />,
+      placeholder: 'admin',
+    },
+    rules: [{
+      required: true, message: '请输入账户名!',
+    }],
+  },
+  Password: {
+    component: Input,
+    props: {
+      size: 'large',
+      prefix: <Icon type="lock" className={styles.prefixIcon} />,
+      type: 'password',
+      placeholder: '888888',
+    },
+    rules: [{
+      required: true, message: '请输入密码!',
+    }],
+  },
+  Mobile: {
+    component: Input,
+    props: {
+      size: 'large',
+      prefix: <Icon type="mobile" className={styles.prefixIcon} />,
+      placeholder: '手机号',
+    },
+    rules: [{
+      required: true, message: '请输入手机号!',
+    }, {
+      pattern: /^1\d{10}$/, message: '手机号格式错误!',
+    }],
+  },
+  Captcha: {
+    component: Input,
+    props: {
+      size: 'large',
+      prefix: <Icon type="mail" className={styles.prefixIcon} />,
+      placeholder: '验证码',
+    },
+    rules: [{
+      required: true, message: '请输入验证码!',
+    }],
+  },
+};
+
+export default map;
diff --git a/src/components/NoticeIcon/NoticeList.js b/src/components/NoticeIcon/NoticeList.js
new file mode 100644
index 0000000..2ffe72a
--- /dev/null
+++ b/src/components/NoticeIcon/NoticeList.js
@@ -0,0 +1,55 @@
+import React from 'react';
+import { Avatar, List } from 'antd';
+import classNames from 'classnames';
+import styles from './NoticeList.less';
+
+export default function NoticeList({
+  data = [], onClick, onClear, title, locale, emptyText, emptyImage,
+}) {
+  if (data.length === 0) {
+    return (
+      <div className={styles.notFound}>
+        {emptyImage ? (
+          <img src={emptyImage} alt="not found" />
+        ) : null}
+        <div>{emptyText || locale.emptyText}</div>
+      </div>
+    );
+  }
+  return (
+    <div>
+      <List className={styles.list}>
+        {data.map((item, i) => {
+          const itemCls = classNames(styles.item, {
+            [styles.read]: item.read,
+          });
+          return (
+            <List.Item className={itemCls} key={item.key || i} onClick={() => onClick(item)}>
+              <List.Item.Meta
+                className={styles.meta}
+                avatar={item.avatar ? <Avatar className={styles.avatar} src={item.avatar} /> : null}
+                title={
+                  <div className={styles.title}>
+                    {item.title}
+                    <div className={styles.extra}>{item.extra}</div>
+                  </div>
+                }
+                description={
+                  <div>
+                    <div className={styles.description} title={item.description}>
+                      {item.description}
+                    </div>
+                    <div className={styles.datetime}>{item.datetime}</div>
+                  </div>
+                }
+              />
+            </List.Item>
+          );
+        })}
+      </List>
+      <div className={styles.clear} onClick={onClear}>
+        {locale.clear}{title}
+      </div>
+    </div>
+  );
+}
diff --git a/src/components/NoticeIcon/NoticeList.less b/src/components/NoticeIcon/NoticeList.less
new file mode 100644
index 0000000..db2bc6d
--- /dev/null
+++ b/src/components/NoticeIcon/NoticeList.less
@@ -0,0 +1,78 @@
+@import "~antd/lib/style/themes/default.less";
+
+.list {
+  max-height: 400px;
+  overflow: auto;
+  .item {
+    transition: all .3s;
+    overflow: hidden;
+    cursor: pointer;
+    padding-left: 24px;
+    padding-right: 24px;
+
+    .meta {
+      width: 100%;
+    }
+
+    .avatar {
+      background: #fff;
+      margin-top: 4px;
+    }
+
+    &.read {
+      opacity: .4;
+    }
+    &:last-child {
+      border-bottom: 0;
+    }
+    &:hover {
+      background: @primary-1;
+    }
+    .title {
+      font-weight: normal;
+      margin-bottom: 8px;
+    }
+    .description {
+      font-size: 12px;
+      line-height: @line-height-base;
+    }
+    .datetime {
+      font-size: 12px;
+      margin-top: 4px;
+      line-height: @line-height-base;
+    }
+    .extra {
+      float: right;
+      color: @text-color-secondary;
+      font-weight: normal;
+      margin-right: 0;
+      margin-top: -1.5px;
+    }
+  }
+}
+
+.notFound {
+  text-align: center;
+  padding: 73px 0 88px 0;
+  color: @text-color-secondary;
+  img {
+    display: inline-block;
+    margin-bottom: 16px;
+    height: 76px;
+  }
+}
+
+.clear {
+  height: 46px;
+  line-height: 46px;
+  text-align: center;
+  color: @text-color;
+  border-radius: 0 0 @border-radius-base @border-radius-base;
+  border-top: 1px solid @border-color-split;
+  transition: all .3s;
+  cursor: pointer;
+
+  &:hover {
+    color: @heading-color;
+  }
+}
diff --git a/src/components/NoticeIcon/demo/basic.md b/src/components/NoticeIcon/demo/basic.md
new file mode 100644
index 0000000..dc9afea
--- /dev/null
+++ b/src/components/NoticeIcon/demo/basic.md
@@ -0,0 +1,12 @@
+---
+order: 1
+title: 通知图标
+---
+
+通常用在导航工具栏上。
+
+````jsx
+import NoticeIcon from 'ant-design-pro/lib/NoticeIcon';
+
+ReactDOM.render(<NoticeIcon count={5} />, mountNode);
+````
diff --git a/src/components/NoticeIcon/demo/popover.md b/src/components/NoticeIcon/demo/popover.md
new file mode 100644
index 0000000..6c047b7
--- /dev/null
+++ b/src/components/NoticeIcon/demo/popover.md
@@ -0,0 +1,176 @@
+---
+order: 2
+title: 带浮层卡片
+---
+
+点击展开通知卡片,展现多种类型的通知,通常放在导航工具栏。
+
+````jsx
+import NoticeIcon from 'ant-design-pro/lib/NoticeIcon';
+import moment from 'moment';
+import groupBy from 'lodash/groupBy';
+import { Tag } from 'antd';
+
+const data = [{
+  id: '000000001',
+  avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png',
+  title: '你收到了 14 份新周报',
+  datetime: '2017-08-09',
+  type: '通知',
+}, {
+  id: '000000002',
+  avatar: 'https://gw.alipayobjects.com/zos/rmsportal/OKJXDXrmkNshAMvwtvhu.png',
+  title: '你推荐的 曲妮妮 已通过第三轮面试',
+  datetime: '2017-08-08',
+  type: '通知',
+}, {
+  id: '000000003',
+  avatar: 'https://gw.alipayobjects.com/zos/rmsportal/kISTdvpyTAhtGxpovNWd.png',
+  title: '这种模板可以区分多种通知类型',
+  datetime: '2017-08-07',
+  read: true,
+  type: '通知',
+}, {
+  id: '000000004',
+  avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png',
+  title: '左侧图标用于区分不同的类型',
+  datetime: '2017-08-07',
+  type: '通知',
+}, {
+  id: '000000005',
+  avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png',
+  title: '内容不要超过两行字,超出时自动截断',
+  datetime: '2017-08-07',
+  type: '通知',
+}, {
+  id: '000000006',
+  avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg',
+  title: '曲丽丽 评论了你',
+  description: '描述信息描述信息描述信息',
+  datetime: '2017-08-07',
+  type: '消息',
+}, {
+  id: '000000007',
+  avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg',
+  title: '朱偏右 回复了你',
+  description: '这种模板用于提醒谁与你发生了互动,左侧放『谁』的头像',
+  datetime: '2017-08-07',
+  type: '消息',
+}, {
+  id: '000000008',
+  avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg',
+  title: '标题',
+  description: '这种模板用于提醒谁与你发生了互动,左侧放『谁』的头像',
+  datetime: '2017-08-07',
+  type: '消息',
+}, {
+  id: '000000009',
+  title: '任务名称',
+  description: '任务需要在 2017-01-12 20:00 前启动',
+  extra: '未开始',
+  status: 'todo',
+  type: '待办',
+}, {
+  id: '000000010',
+  title: '第三方紧急代码变更',
+  description: '冠霖提交于 2017-01-06,需在 2017-01-07 前完成代码变更任务',
+  extra: '马上到期',
+  status: 'urgent',
+  type: '待办',
+}, {
+  id: '000000011',
+  title: '信息安全考试',
+  description: '指派竹尔于 2017-01-09 前完成更新并发布',
+  extra: '已耗时 8 天',
+  status: 'doing',
+  type: '待办',
+}, {
+  id: '000000012',
+  title: 'ABCD 版本发布',
+  description: '冠霖提交于 2017-01-06,需在 2017-01-07 前完成代码变更任务',
+  extra: '进行中',
+  status: 'processing',
+  type: '待办',
+}];
+
+function onItemClick(item, tabProps) {
+  console.log(item, tabProps);
+}
+
+function onClear(tabTitle) {
+  console.log(tabTitle);
+}
+
+function getNoticeData(notices) {
+  if (notices.length === 0) {
+    return {};
+  }
+  const newNotices = notices.map((notice) => {
+    const newNotice = { ...notice };
+    if (newNotice.datetime) {
+      newNotice.datetime = moment(notice.datetime).fromNow();
+    }
+    // transform id to item key
+    if (newNotice.id) {
+      newNotice.key = newNotice.id;
+    }
+    if (newNotice.extra && newNotice.status) {
+      const color = ({
+        todo: '',
+        processing: 'blue',
+        urgent: 'red',
+        doing: 'gold',
+      })[newNotice.status];
+      newNotice.extra = <Tag color={color} style={{ marginRight: 0 }}>{newNotice.extra}</Tag>;
+    }
+    return newNotice;
+  });
+  return groupBy(newNotices, 'type');
+}
+
+const noticeData = getNoticeData(data);
+
+ReactDOM.render(
+  <div
+    style={{
+      textAlign: 'right',
+      height: '64px',
+      lineHeight: '64px',
+      boxShadow: '0 1px 4px rgba(0,21,41,.12)',
+      padding: '0 32px',
+      width: '400px',
+    }}
+  >
+    <NoticeIcon
+      className="notice-icon"
+      count={5}
+      onItemClick={onItemClick}
+      onClear={onClear}
+      popupAlign={{ offset: [20, -16] }}
+    >
+      <NoticeIcon.Tab
+        list={noticeData['通知']}
+        title="通知"
+        emptyText="你已查看所有通知"
+        emptyImage="https://gw.alipayobjects.com/zos/rmsportal/wAhyIChODzsoKIOBHcBk.svg"
+      />
+      <NoticeIcon.Tab
+        list={noticeData['消息']}
+        title="消息"
+        emptyText="您已读完所有消息"
+        emptyImage="https://gw.alipayobjects.com/zos/rmsportal/sAuJeJzSKbUmHfBQRzmZ.svg"
+      />
+      <NoticeIcon.Tab
+        list={noticeData['待办']}
+        title="待办"
+        emptyText="你已完成所有待办"
+        emptyImage="https://gw.alipayobjects.com/zos/rmsportal/HsIsxMZiWKrNUavQUXqx.svg"
+      />
+    </NoticeIcon>
+  </div>
+, mountNode);
+````
+
+```css
+
+```
diff --git a/src/components/NoticeIcon/index.d.ts b/src/components/NoticeIcon/index.d.ts
new file mode 100644
index 0000000..76541cd
--- /dev/null
+++ b/src/components/NoticeIcon/index.d.ts
@@ -0,0 +1,45 @@
+import * as React from 'react';
+export interface NoticeIconData {
+  avatar?: string;
+  title?: React.ReactNode;
+  description?: React.ReactNode;
+  datetime?: React.ReactNode;
+  extra?: React.ReactNode;
+  style?: React.CSSProperties;
+}
+
+export interface NoticeIconProps {
+  count?: number;
+  className?: string;
+  loading?: boolean;
+  onClear?: (tableTile: string) => void;
+  onItemClick?: (item: NoticeIconData, tabProps: NoticeIconProps) => void;
+  onTabChange?: (tableTile: string) => void;
+  popupAlign?: {
+    points?: [string, string];
+    offset?: [number, number];
+    targetOffset?: [number, number];
+    overflow?: any;
+    useCssRight?: boolean;
+    useCssBottom?: boolean;
+    useCssTransform?: boolean;
+  };
+  style?: React.CSSProperties;
+  onPopupVisibleChange?: (visible: boolean) => void;
+  popupVisible?: boolean;
+  locale?: { emptyText: string; clear: string };
+}
+
+export interface NoticeIconTabProps {
+  list?: Array<NoticeIconData>;
+  title?: string;
+  emptyText?: React.ReactNode;
+  emptyImage?: string;
+  style?: React.CSSProperties;
+}
+
+export class NoticeIconTab extends React.Component<NoticeIconTabProps, any> {}
+
+export default class NoticeIcon extends React.Component<NoticeIconProps, any> {
+  static Tab: typeof NoticeIconTab;
+}
diff --git a/src/components/NoticeIcon/index.js b/src/components/NoticeIcon/index.js
new file mode 100644
index 0000000..3134ace
--- /dev/null
+++ b/src/components/NoticeIcon/index.js
@@ -0,0 +1,100 @@
+import React, { PureComponent } from 'react';
+import { Popover, Icon, Tabs, Badge, Spin } from 'antd';
+import classNames from 'classnames';
+import List from './NoticeList';
+import styles from './index.less';
+
+const { TabPane } = Tabs;
+
+export default class NoticeIcon extends PureComponent {
+  static defaultProps = {
+    onItemClick: () => {},
+    onPopupVisibleChange: () => {},
+    onTabChange: () => {},
+    onClear: () => {},
+    loading: false,
+    locale: {
+      emptyText: '暂无数据',
+      clear: '清空',
+    },
+    emptyImage: 'https://gw.alipayobjects.com/zos/rmsportal/wAhyIChODzsoKIOBHcBk.svg',
+  };
+  static Tab = TabPane;
+  constructor(props) {
+    super(props);
+    this.state = {};
+    if (props.children && props.children[0]) {
+      this.state.tabType = props.children[0].props.title;
+    }
+  }
+  onItemClick = (item, tabProps) => {
+    const { onItemClick } = this.props;
+    onItemClick(item, tabProps);
+  }
+  onTabChange = (tabType) => {
+    this.setState({ tabType });
+    this.props.onTabChange(tabType);
+  }
+  getNotificationBox() {
+    const { children, loading, locale } = this.props;
+    if (!children) {
+      return null;
+    }
+    const panes = React.Children.map(children, (child) => {
+      const title = child.props.list && child.props.list.length > 0
+        ? `${child.props.title} (${child.props.list.length})` : child.props.title;
+      return (
+        <TabPane tab={title} key={child.props.title}>
+          <List
+            {...child.props}
+            data={child.props.list}
+            onClick={item => this.onItemClick(item, child.props)}
+            onClear={() => this.props.onClear(child.props.title)}
+            title={child.props.title}
+            locale={locale}
+          />
+        </TabPane>
+      );
+    });
+    return (
+      <Spin spinning={loading} delay={0}>
+        <Tabs className={styles.tabs} onChange={this.onTabChange}>
+          {panes}
+        </Tabs>
+      </Spin>
+    );
+  }
+  render() {
+    const { className, count, popupAlign, onPopupVisibleChange } = this.props;
+    const noticeButtonClass = classNames(className, styles.noticeButton);
+    const notificationBox = this.getNotificationBox();
+    const trigger = (
+      <span className={noticeButtonClass}>
+        <Badge count={count} className={styles.badge}>
+          <Icon type="bell" className={styles.icon} />
+        </Badge>
+      </span>
+    );
+    if (!notificationBox) {
+      return trigger;
+    }
+    const popoverProps = {};
+    if ('popupVisible' in this.props) {
+      popoverProps.visible = this.props.popupVisible;
+    }
+    return (
+      <Popover
+        placement="bottomRight"
+        content={notificationBox}
+        popupClassName={styles.popover}
+        trigger="click"
+        arrowPointAtCenter
+        popupAlign={popupAlign}
+        onVisibleChange={onPopupVisibleChange}
+        {...popoverProps}
+      >
+        {trigger}
+      </Popover>
+    );
+  }
+}
diff --git a/src/components/NoticeIcon/index.less b/src/components/NoticeIcon/index.less
new file mode 100644
index 0000000..9a93365
--- /dev/null
+++ b/src/components/NoticeIcon/index.less
@@ -0,0 +1,30 @@
+@import "~antd/lib/style/themes/default.less";
+
+.popover {
+  width: 336px;
+  :global(.ant-popover-inner-content) {
+    padding: 0;
+  }
+}
+
+.noticeButton {
+  cursor: pointer;
+  display: inline-block;
+  transition: all .3s;
+}
+
+.icon {
+  font-size: 16px;
+  padding: 4px;
+}
+
+.tabs {
+  :global {
+    .ant-tabs-nav-scroll {
+      text-align: center;
+    }
+    .ant-tabs-bar {
+      margin-bottom: 4px;
+    }
+  }
+}
diff --git a/src/components/NoticeIcon/index.md b/src/components/NoticeIcon/index.md
new file mode 100644
index 0000000..fefdbdc
--- /dev/null
+++ b/src/components/NoticeIcon/index.md
@@ -0,0 +1,43 @@
+---
+title:
+  en-US: NoticeIcon
+  zh-CN: NoticeIcon
+subtitle: 通知菜单
+cols: 1
+order: 9
+---
+
+用在导航工具栏上,作为整个产品统一的通知中心。
+
+## API
+
+参数 | 说明 | 类型 | 默认值
+----|------|-----|------
+count | 图标上的消息总数 | number | -
+loading | 弹出卡片加载状态 | boolean | false
+onClear | 点击清空按钮的回调 | function(tabTitle) | -
+onItemClick | 点击列表项的回调 | function(item, tabProps) | -
+onTabChange | 切换页签的回调 | function(tabTitle) | -
+popupAlign | 弹出卡片的位置配置 | Object [alignConfig](https://github.com/yiminghe/dom-align#alignconfig-object-details) | -
+onPopupVisibleChange | 弹出卡片显隐的回调 | function(visible) | -
+popupVisible | 控制弹层显隐 | boolean | -
+locale | 默认文案 | Object | `{ emptyText: '暂无数据', clear: '清空' }`
+
+### NoticeIcon.Tab
+
+参数 | 说明 | 类型 | 默认值
+----|------|-----|------
+title | 消息分类的页签标题 | string | -
+list | 列表数据,格式参照下表 | Array | `[]`
+emptyText | 针对每个 Tab 定制空数据文案 | ReactNode | -
+emptyImage | 针对每个 Tab 定制空数据图片 | string | -
+
+### Tab data
+
+参数 | 说明 | 类型 | 默认值
+----|------|-----|------
+avatar | 头像图片链接 | string | -
+title | 标题 | ReactNode | -
+description | 描述信息 | ReactNode | -
+datetime | 时间戳 | ReactNode | -
+extra | 额外信息,在列表项右上角 | ReactNode | -
diff --git a/src/components/NumberInfo/demo/basic.md b/src/components/NumberInfo/demo/basic.md
new file mode 100644
index 0000000..a8ce97a
--- /dev/null
+++ b/src/components/NumberInfo/demo/basic.md
@@ -0,0 +1,22 @@
+---
+order: 0
+title: 演示
+---
+
+各种数据文案的展现方式。
+
+````jsx
+import NumberInfo from 'ant-design-pro/lib/NumberInfo';
+import numeral from 'numeral';
+
+ReactDOM.render(
+  <div>
+    <NumberInfo
+      subTitle={<span>本周访问</span>}
+      total={numeral(12321).format('0,0')}
+      status="up"
+      subTotal={17.1}
+    />
+  </div>
+, mountNode);
+````
diff --git a/src/components/NumberInfo/index.d.ts b/src/components/NumberInfo/index.d.ts
new file mode 100644
index 0000000..2370ec6
--- /dev/null
+++ b/src/components/NumberInfo/index.d.ts
@@ -0,0 +1,13 @@
+import * as React from 'react';
+export interface NumberInfoProps {
+  title?: React.ReactNode | string;
+  subTitle?: React.ReactNode | string;
+  total?: React.ReactNode | string;
+  status?: 'up' | 'down';
+  theme?: string;
+  gap?: number;
+  subTotal?: number;
+  style?: React.CSSProperties;
+}
+
+export default class NumberInfo extends React.Component<NumberInfoProps, any> {}
diff --git a/src/components/NumberInfo/index.js b/src/components/NumberInfo/index.js
new file mode 100644
index 0000000..0b90cbd
--- /dev/null
+++ b/src/components/NumberInfo/index.js
@@ -0,0 +1,34 @@
+import React from 'react';
+import { Icon } from 'antd';
+import classNames from 'classnames';
+import styles from './index.less';
+
+export default ({
+  theme, title, subTitle, total, subTotal, status, suffix, gap, ...rest
+}) => (
+  <div
+    className={
+      classNames(styles.numberInfo, {
+        [styles[`numberInfo${theme}`]]: theme,
+      })
+    }
+    {...rest}
+  >
+    {title && <div className={styles.numberInfoTitle}>{title}</div>}
+    {subTitle && <div className={styles.numberInfoSubTitle}>{subTitle}</div>}
+    <div className={styles.numberInfoValue} style={gap ? { marginTop: gap } : null}>
+      <span>
+        {total}
+        {suffix && <em className={styles.suffix}>{suffix}</em>}
+      </span>
+      {
+        (status || subTotal) && (
+          <span className={styles.subTotal}>
+            {subTotal}
+            {status && <Icon type={`caret-${status}`} />}
+          </span>
+        )
+      }
+    </div>
+  </div>
+);
diff --git a/src/components/NumberInfo/index.less b/src/components/NumberInfo/index.less
new file mode 100644
index 0000000..1854dd7
--- /dev/null
+++ b/src/components/NumberInfo/index.less
@@ -0,0 +1,68 @@
+@import "~antd/lib/style/themes/default.less";
+
+.numberInfo {
+  .suffix {
+    color: @text-color;
+    font-size: 16px;
+    font-style: normal;
+    margin-left: 4px;
+  }
+  .numberInfoTitle {
+    color: @text-color;
+    font-size: @font-size-lg;
+    margin-bottom: 16px;
+    transition: all .3s;
+  }
+  .numberInfoSubTitle {
+    color: @text-color-secondary;
+    font-size: @font-size-base;
+    height: 22px;
+    line-height: 22px;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    word-break: break-all;
+    white-space: nowrap;
+  }
+  .numberInfoValue {
+    margin-top: 4px;
+    font-size: 0;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    word-break: break-all;
+    white-space: nowrap;
+    & > span {
+      color: @heading-color;
+      display: inline-block;
+      line-height: 32px;
+      height: 32px;
+      font-size: 24px;
+      margin-right: 32px;
+    }
+    .subTotal {
+      color: @text-color-secondary;
+      font-size: @font-size-lg;
+      vertical-align: top;
+      margin-right: 0;
+      i {
+        font-size: 12px;
+        transform: scale(0.82);
+        margin-left: 4px;
+      }
+      :global {
+        .anticon-caret-up {
+          color: @red-6;
+        }
+        .anticon-caret-down {
+          color: @green-6;
+        }
+      }
+    }
+  }
+}
+.numberInfolight {
+  .numberInfoValue {
+    & > span {
+      color: @text-color;
+    }
+  }
+}
diff --git a/src/components/NumberInfo/index.md b/src/components/NumberInfo/index.md
new file mode 100644
index 0000000..1116f99
--- /dev/null
+++ b/src/components/NumberInfo/index.md
@@ -0,0 +1,22 @@
+---
+title:
+  en-US: NumberInfo
+  zh-CN: NumberInfo
+subtitle: 数据文本
+cols: 1
+order: 10
+---
+
+常用在数据卡片中,用于突出展示某个业务数据。
+
+## API
+
+参数 | 说明 | 类型 | 默认值
+----|------|-----|------
+title | 标题 | ReactNode\|string | -
+subTitle | 子标题 | ReactNode\|string | -
+total | 总量 | ReactNode\|string | -
+subTotal | 子总量 | ReactNode\|string | -
+status | 增加状态 | 'up \| down' | -
+theme | 状态样式 | string | 'light'
+gap | 设置数字和描述直接的间距(像素) | number | 8
diff --git a/src/components/PageHeader/demo/image.md b/src/components/PageHeader/demo/image.md
new file mode 100644
index 0000000..511bac5
--- /dev/null
+++ b/src/components/PageHeader/demo/image.md
@@ -0,0 +1,75 @@
+---
+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>
diff --git a/src/components/PageHeader/demo/simple.md b/src/components/PageHeader/demo/simple.md
new file mode 100644
index 0000000..d0ad1f7
--- /dev/null
+++ b/src/components/PageHeader/demo/simple.md
@@ -0,0 +1,32 @@
+---
+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>
diff --git a/src/components/PageHeader/demo/standard.md b/src/components/PageHeader/demo/standard.md
new file mode 100644
index 0000000..5c59c93
--- /dev/null
+++ b/src/components/PageHeader/demo/standard.md
@@ -0,0 +1,102 @@
+---
+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>
diff --git a/src/components/PageHeader/demo/structure.md b/src/components/PageHeader/demo/structure.md
new file mode 100644
index 0000000..429eed6
--- /dev/null
+++ b/src/components/PageHeader/demo/structure.md
@@ -0,0 +1,68 @@
+---
+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>
diff --git a/src/components/PageHeader/index.d.ts b/src/components/PageHeader/index.d.ts
new file mode 100644
index 0000000..518f203
--- /dev/null
+++ b/src/components/PageHeader/index.d.ts
@@ -0,0 +1,19 @@
+import * as React from 'react';
+export interface PageHeaderProps {
+  title?: React.ReactNode | string;
+  logo?: React.ReactNode | string;
+  action?: React.ReactNode | string;
+  content?: React.ReactNode;
+  extraContent?: React.ReactNode;
+  routes?: Array<any>;
+  params?: any;
+  breadcrumbList?: Array<{ title: React.ReactNode; href?: string }>;
+  tabList?: Array<{ key: string; tab: React.ReactNode }>;
+  tabActiveKey?: string;
+  onTabChange?: (key: string) => void;
+  tabBarExtraContent?: React.ReactNode;
+  linkElement?: React.ReactNode;
+  style?: React.CSSProperties;
+}
+
+export default class PageHeader extends React.Component<PageHeaderProps, any> {}
diff --git a/src/components/PageHeader/index.js b/src/components/PageHeader/index.js
new file mode 100644
index 0000000..7eb6de1
--- /dev/null
+++ b/src/components/PageHeader/index.js
@@ -0,0 +1,194 @@
+import React, { PureComponent, createElement } from 'react';
+import PropTypes from 'prop-types';
+import pathToRegexp from 'path-to-regexp';
+import { Breadcrumb, Tabs } from 'antd';
+import classNames from 'classnames';
+import styles from './index.less';
+
+
+const { TabPane } = Tabs;
+
+function 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 PageHeader extends PureComponent {
+  static contextTypes = {
+    routes: PropTypes.array,
+    params: PropTypes.object,
+    location: PropTypes.object,
+    breadcrumbNameMap: PropTypes.object,
+  };
+  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,
+      routerLocation: this.props.location || this.context.location,
+      breadcrumbNameMap: this.props.breadcrumbNameMap || this.context.breadcrumbNameMap,
+    };
+  };
+  // Generated according to props
+  conversionFromProps= () => {
+    const {
+      breadcrumbList, breadcrumbSeparator, linkElement = 'a',
+    } = this.props;
+    return (
+      <Breadcrumb
+        className={styles.breadcrumb}
+        separator={breadcrumbSeparator}
+      >
+        {breadcrumbList.map(item => (
+          <Breadcrumb.Item key={item.title}>
+            {item.href ? (createElement(linkElement, {
+          [linkElement === 'a' ? 'href' : 'to']: item.href,
+        }, item.title)) : item.title}
+          </Breadcrumb.Item>
+      ))}
+      </Breadcrumb>
+    );
+  }
+  conversionFromLocation = (routerLocation, breadcrumbNameMap) => {
+    const { breadcrumbSeparator, linkElement = 'a' } = this.props;
+    // Convert the path to an array
+    const pathSnippets = routerLocation.pathname.split('/').filter(i => i);
+    // Loop data mosaic routing
+    const extraBreadcrumbItems = pathSnippets.map((_, index) => {
+      const url = `/${pathSnippets.slice(0, index + 1).join('/')}`;
+      const currentBreadcrumb = getBreadcrumb(breadcrumbNameMap, url);
+      const isLinkable = (index !== pathSnippets.length - 1) && currentBreadcrumb.component;
+      return currentBreadcrumb.name && !currentBreadcrumb.hideInBreadcrumb ? (
+        <Breadcrumb.Item key={url}>
+          {createElement(
+            isLinkable ? linkElement : 'span',
+            { [linkElement === 'a' ? 'href' : 'to']: url },
+            currentBreadcrumb.name,
+          )}
+        </Breadcrumb.Item>
+      ) : null;
+    });
+    // Add home breadcrumbs to your head
+    extraBreadcrumbItems.unshift(
+      <Breadcrumb.Item key="home">
+        {createElement(linkElement, {
+        [linkElement === 'a' ? 'href' : 'to']: '/' }, '首页')}
+      </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 (location && location.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 {
+      title, logo, action, content, extraContent,
+      tabList, className, tabActiveKey, tabBarExtraContent,
+    } = this.props;
+    const clsString = classNames(styles.pageHeader, className);
+
+    let tabDefaultValue;
+    if (tabActiveKey !== undefined && tabList) {
+      tabDefaultValue = tabList.filter(item => item.default)[0] || tabList[0];
+    }
+    const breadcrumb = this.conversionBreadcrumbList();
+    const activeKeyProps = {
+      defaultActiveKey: tabDefaultValue && tabDefaultValue.key,
+    };
+    if (tabActiveKey !== undefined) {
+      activeKeyProps.activeKey = tabActiveKey;
+    }
+
+    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}
+              {...activeKeyProps}
+              onChange={this.onChange}
+              tabBarExtraContent={tabBarExtraContent}
+            >
+              {
+                tabList.map(item => <TabPane tab={item.tab} key={item.key} />)
+              }
+            </Tabs>
+          )
+        }
+      </div>
+    );
+  }
+}
diff --git a/src/components/PageHeader/index.less b/src/components/PageHeader/index.less
new file mode 100644
index 0000000..a1e3b2e
--- /dev/null
+++ b/src/components/PageHeader/index.less
@@ -0,0 +1,138 @@
+@import "~antd/lib/style/themes/default.less";
+
+.pageHeader {
+  background: @component-background;
+  padding: 16px 32px 0 32px;
+  border-bottom: @border-width-base @border-style-base @border-color-split;
+
+  .detail {
+    display: flex;
+  }
+
+  .row {
+    display: flex;
+  }
+
+  .breadcrumb {
+    margin-bottom: 16px;
+  }
+
+  .tabs {
+    margin: 0 0 -17px -8px;
+
+    :global {
+      .ant-tabs-bar {
+        border-bottom: @border-width-base @border-style-base @border-color-split;
+      }
+    }
+  }
+
+  .logo {
+    flex: 0 1 auto;
+    margin-right: 16px;
+    padding-top: 1px;
+    > img {
+      width: 28px;
+      height: 28px;
+      border-radius: @border-radius-base;
+      display: block;
+    }
+  }
+
+  .title {
+    font-size: 20px;
+    font-weight: 500;
+    color: @heading-color;
+  }
+
+  .action {
+    margin-left: 56px;
+    min-width: 266px;
+
+    :global {
+      .ant-btn-group:not(:last-child),
+      .ant-btn:not(:last-child) {
+        margin-right: 8px;
+      }
+
+      .ant-btn-group > .ant-btn {
+        margin-right: 0;
+      }
+    }
+  }
+
+  .title, .action, .content, .extraContent, .main {
+    flex: auto;
+  }
+
+  .title, .action {
+    margin-bottom: 16px;
+  }
+
+  .logo, .content, .extraContent {
+    margin-bottom: 16px;
+  }
+
+  .action, .extraContent {
+    text-align: right;
+  }
+
+  .extraContent {
+    margin-left: 88px;
+    min-width: 242px;
+  }
+}
+
+@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;
+        }
+      }
+    }
+  }
+}
diff --git a/src/components/PageHeader/index.md b/src/components/PageHeader/index.md
new file mode 100644
index 0000000..334d354
--- /dev/null
+++ b/src/components/PageHeader/index.md
@@ -0,0 +1,31 @@
+---
+title:
+  en-US: PageHeader
+  zh-CN: PageHeader
+subtitle: 页头
+cols: 1
+order: 11
+---
+
+页头用来声明页面的主题,包含了用户所关注的最重要的信息,使用户可以快速理解当前页面是什么以及它的功能。
+
+## API
+
+| 参数      | 说明                                      | 类型         | 默认值 |
+|----------|------------------------------------------|-------------|-------|
+| title | title 区域 | ReactNode | - |
+| logo | logo区域 | ReactNode | - |
+| action | 操作区,位于 title 行的行尾 | ReactNode | - |
+| content | 内容区 | ReactNode | - |
+| extraContent | 额外内容区,位于content的右侧 | ReactNode | - |
+| breadcrumbList | 面包屑数据,配置了此属性时 `routes` `params` `location` `breadcrumbNameMap` 无效 | array<{title: ReactNode, href?: string}> | - |
+| routes | 面包屑相关属性,router 的路由栈信息 | object[] | - |
+| params | 面包屑相关属性,路由的参数 | object | - |
+| location | 面包屑相关属性,当前的路由信息 | object | - |
+| breadcrumbNameMap | 面包屑相关属性,路由的地址-名称映射表 | object | - |
+| tabList | tab 标题列表 | array<{key: string, tab: ReactNode}> | -  |
+| tabActiveKey | 当前高亮的 tab 项 | string | -  |
+| onTabChange | 切换面板的回调 | (key) => void | -  |
+| 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 中,组件会自动获取。
diff --git a/src/components/Result/demo/classic.md b/src/components/Result/demo/classic.md
new file mode 100644
index 0000000..b4ccdcf
--- /dev/null
+++ b/src/components/Result/demo/classic.md
@@ -0,0 +1,80 @@
+---
+order: 1
+title: Classic
+---
+
+典型结果页面。
+
+````jsx
+import Result from 'ant-design-pro/lib/Result';
+import { Button, Row, Col, Icon, Steps } from 'antd';
+
+const { Step } = Steps;
+
+const desc1 = (
+  <div style={{ fontSize: 14, position: 'relative', left: 38 }}>
+    <div style={{ marginTop: 8, marginBottom: 4 }}>
+      曲丽丽
+      <Icon type="dingding-o" style={{ marginLeft: 8 }} />
+    </div>
+    <div style={{ marginTop: 8, marginBottom: 4 }}>2016-12-12 12:32</div>
+  </div>
+);
+
+const desc2 = (
+  <div style={{ fontSize: 14, position: 'relative', left: 38 }}>
+    <div style={{ marginTop: 8, marginBottom: 4 }}>
+      周毛毛
+      <Icon type="dingding-o" style={{ color: '#00A0E9', marginLeft: 8 }} />
+    </div>
+    <div style={{ marginTop: 8, marginBottom: 4 }}><a href="">催一下</a></div>
+  </div>
+);
+
+const extra = (
+  <div>
+    <div style={{ fontSize: 16, color: 'rgba(0, 0, 0, 0.85)', fontWeight: 500, marginBottom: 20 }}>
+      项目名称
+    </div>
+    <Row style={{ marginBottom: 16 }}>
+      <Col xs={24} sm={12} md={12} lg={12} xl={6}>
+        <span style={{ color: 'rgba(0, 0, 0, 0.85)' }}>项目 ID:</span>
+        23421
+      </Col>
+      <Col xs={24} sm={12} md={12} lg={12} xl={6}>
+        <span style={{ color: 'rgba(0, 0, 0, 0.85)' }}>负责人:</span>
+        曲丽丽
+      </Col>
+      <Col xs={24} sm={24} md={24} lg={24} xl={12}>
+        <span style={{ color: 'rgba(0, 0, 0, 0.85)' }}>生效时间:</span>
+        2016-12-12 ~ 2017-12-12
+      </Col>
+    </Row>
+    <Steps progressDot current={1}>
+      <Step title="创建项目" description={desc1} />
+      <Step title="部门初审" description={desc2} />
+      <Step title="财务复核" />
+      <Step title="完成" />
+    </Steps>
+  </div>
+);
+
+const actions = (
+  <div>
+    <Button type="primary">返回列表</Button>
+    <Button>查看项目</Button>
+    <Button>打 印</Button>
+  </div>
+);
+
+ReactDOM.render(
+  <Result
+    type="success"
+    title="提交成功"
+    description="提交结果页用于反馈一系列操作任务的处理结果,如果仅是简单操作,使用 Message 全局提示反馈即可。本文字区域可以展示简单的补充说明,如果有类似展示“单据”的需求,下面这个灰色区域可以呈现比较复杂的内容。"
+    extra={extra}
+    actions={actions}
+    style={{ width: '100%' }}
+  />
+, mountNode);
+````
diff --git a/src/components/Result/demo/error.md b/src/components/Result/demo/error.md
new file mode 100644
index 0000000..836bd8c
--- /dev/null
+++ b/src/components/Result/demo/error.md
@@ -0,0 +1,39 @@
+---
+order: 2
+title: Failed
+---
+
+提交失败。
+
+````jsx
+import Result from 'ant-design-pro/lib/Result';
+import { Button, Icon } from 'antd';
+
+const extra = (
+  <div>
+    <div style={{ fontSize: 16, color: 'rgba(0, 0, 0, 0.85)', fontWeight: 500, marginBottom: 16 }}>
+      您提交的内容有如下错误:
+    </div>
+    <div style={{ marginBottom: 16 }}>
+      <Icon style={{ color: '#f5222d', marginRight: 8 }} type="close-circle-o" />您的账户已被冻结
+      <a style={{ marginLeft: 16 }}>立即解冻 <Icon type="right" /></a>
+    </div>
+    <div>
+      <Icon style={{ color: '#f5222d', marginRight: 8 }} type="close-circle-o" />您的账户还不具备申请资格
+      <a style={{ marginLeft: 16 }}>立即升级 <Icon type="right" /></a>
+    </div>
+  </div>
+);
+
+const actions = <Button type="primary">返回修改</Button>;
+
+ReactDOM.render(
+  <Result
+    type="error"
+    title="提交失败"
+    description="请核对并修改以下信息后,再重新提交。"
+    extra={extra}
+    actions={actions}
+  />
+, mountNode);
+````
diff --git a/src/components/Result/demo/structure.md b/src/components/Result/demo/structure.md
new file mode 100644
index 0000000..7fcecfd
--- /dev/null
+++ b/src/components/Result/demo/structure.md
@@ -0,0 +1,20 @@
+---
+order: 0
+title: Structure
+---
+
+结构包含 `处理结果`,`补充信息` 以及 `操作建议` 三个部分,其中 `处理结果` 由 `提示图标`,`标题` 和 `结果描述` 组成。
+
+````jsx
+import Result from 'ant-design-pro/lib/Result';
+
+ReactDOM.render(
+  <Result
+    type="success"
+    title={<div style={{ background: '#7dbcea', color: '#fff' }}>标题</div>}
+    description={<div style={{ background: 'rgba(16, 142, 233, 1)', color: '#fff' }}>结果描述</div>}
+    extra="其他补充信息,自带灰底效果"
+    actions={<div style={{ background: '#3ba0e9', color: '#fff' }}>操作建议,一般放置按钮组</div>}
+  />
+, mountNode);
+````
diff --git a/src/components/Result/index.d.ts b/src/components/Result/index.d.ts
new file mode 100644
index 0000000..a316332
--- /dev/null
+++ b/src/components/Result/index.d.ts
@@ -0,0 +1,11 @@
+import * as React from 'react';
+export interface ResultProps {
+  type: 'success' | 'error';
+  title: React.ReactNode;
+  description?: React.ReactNode;
+  extra?: React.ReactNode;
+  actions?: React.ReactNode;
+  style?: React.CSSProperties;
+}
+
+export default class Result extends React.Component<ResultProps, any> {}
diff --git a/src/components/Result/index.js b/src/components/Result/index.js
new file mode 100644
index 0000000..389a4ef
--- /dev/null
+++ b/src/components/Result/index.js
@@ -0,0 +1,23 @@
+import React from 'react';
+import classNames from 'classnames';
+import { Icon } from 'antd';
+import styles from './index.less';
+
+export default function Result({
+  className, type, title, description, extra, actions, ...restProps
+}) {
+  const iconMap = {
+    error: <Icon className={styles.error} type="close-circle" />,
+    success: <Icon className={styles.success} type="check-circle" />,
+  };
... 15984 lines suppressed ...

-- 
To stop receiving notification emails like this one, please contact
hanahmily@apache.org.