master 220b0aee8250 cached
281 files
551.1 KB
161.8k tokens
541 symbols
1 requests
Download .txt
Showing preview only (646K chars total). Download the full file or copy to clipboard to get everything.
Repository: biaochenxuying/blog-react-admin
Branch: master
Commit: 220b0aee8250
Files: 281
Total size: 551.1 KB

Directory structure:
gitextract_4hkosi02/

├── .circleci/
│   └── config.yml
├── .dockerignore
├── .editorconfig
├── .eslintignore
├── .eslintrc.js
├── .firebaserc
├── .gitignore
├── .prettierignore
├── .prettierrc
├── .stylelintrc.json
├── CODE_OF_CONDUCT.md
├── Dockerfile
├── Dockerfile.dev
├── LICENSE
├── README.md
├── README.ru-RU.md
├── README.zh-CN.md
├── appveyor.yml
├── config/
│   ├── config.js
│   ├── plugin.config.js
│   └── router.config.js
├── docker/
│   ├── docker-compose.dev.yml
│   ├── docker-compose.yml
│   └── nginx.conf
├── firebase.json
├── functions/
│   ├── index.js
│   ├── matchMock.js
│   └── package.json
├── jest.config.js
├── jsconfig.json
├── mock/
│   ├── api.js
│   ├── blog.js
│   ├── chart.js
│   ├── geographic/
│   │   ├── city.json
│   │   └── province.json
│   ├── geographic.js
│   ├── notices.js
│   ├── profile.js
│   ├── rule.js
│   └── user.js
├── package.json
├── scripts/
│   └── generateMock.js
├── src/
│   ├── components/
│   │   ├── Authorized/
│   │   │   ├── Authorized.js
│   │   │   ├── AuthorizedRoute.js
│   │   │   ├── CheckPermissions.js
│   │   │   ├── CheckPermissions.test.js
│   │   │   ├── PromiseRender.js
│   │   │   ├── Secured.js
│   │   │   ├── demo/
│   │   │   │   ├── AuthorizedArray.md
│   │   │   │   ├── AuthorizedFunction.md
│   │   │   │   ├── basic.md
│   │   │   │   └── secured.md
│   │   │   ├── index.d.ts
│   │   │   ├── index.js
│   │   │   ├── index.md
│   │   │   └── renderAuthorize.js
│   │   ├── Charts/
│   │   │   ├── Bar/
│   │   │   │   ├── index.d.ts
│   │   │   │   └── index.js
│   │   │   ├── ChartCard/
│   │   │   │   ├── index.d.ts
│   │   │   │   ├── index.js
│   │   │   │   └── index.less
│   │   │   ├── Field/
│   │   │   │   ├── index.d.ts
│   │   │   │   ├── index.js
│   │   │   │   └── index.less
│   │   │   ├── Gauge/
│   │   │   │   ├── index.d.ts
│   │   │   │   └── index.js
│   │   │   ├── MiniArea/
│   │   │   │   ├── index.d.ts
│   │   │   │   └── index.js
│   │   │   ├── MiniBar/
│   │   │   │   ├── index.d.ts
│   │   │   │   └── index.js
│   │   │   ├── MiniProgress/
│   │   │   │   ├── index.d.ts
│   │   │   │   ├── index.js
│   │   │   │   └── index.less
│   │   │   ├── Pie/
│   │   │   │   ├── index.d.ts
│   │   │   │   ├── index.js
│   │   │   │   └── index.less
│   │   │   ├── Radar/
│   │   │   │   ├── index.d.ts
│   │   │   │   ├── index.js
│   │   │   │   └── index.less
│   │   │   ├── TagCloud/
│   │   │   │   ├── index.d.ts
│   │   │   │   ├── index.js
│   │   │   │   └── index.less
│   │   │   ├── TimelineChart/
│   │   │   │   ├── index.d.ts
│   │   │   │   ├── index.js
│   │   │   │   └── index.less
│   │   │   ├── WaterWave/
│   │   │   │   ├── index.d.ts
│   │   │   │   ├── index.js
│   │   │   │   └── index.less
│   │   │   ├── autoHeight.js
│   │   │   ├── bizcharts.d.ts
│   │   │   ├── bizcharts.js
│   │   │   ├── demo/
│   │   │   │   ├── bar.md
│   │   │   │   ├── chart-card.md
│   │   │   │   ├── gauge.md
│   │   │   │   ├── mini-area.md
│   │   │   │   ├── mini-bar.md
│   │   │   │   ├── mini-pie.md
│   │   │   │   ├── mini-progress.md
│   │   │   │   ├── mix.md
│   │   │   │   ├── pie.md
│   │   │   │   ├── radar.md
│   │   │   │   ├── tag-cloud.md
│   │   │   │   ├── timeline-chart.md
│   │   │   │   └── waterwave.md
│   │   │   ├── g2.js
│   │   │   ├── index.d.ts
│   │   │   ├── index.js
│   │   │   ├── index.less
│   │   │   └── index.md
│   │   ├── Exception/
│   │   │   ├── demo/
│   │   │   │   ├── 403.md
│   │   │   │   ├── 404.md
│   │   │   │   └── 500.md
│   │   │   ├── index.d.ts
│   │   │   ├── index.en-US.md
│   │   │   ├── index.js
│   │   │   ├── index.less
│   │   │   ├── index.zh-CN.md
│   │   │   └── typeConfig.js
│   │   ├── FooterToolbar/
│   │   │   ├── demo/
│   │   │   │   └── basic.md
│   │   │   ├── index.d.ts
│   │   │   ├── index.en-US.md
│   │   │   ├── index.js
│   │   │   ├── index.less
│   │   │   └── index.zh-CN.md
│   │   ├── GlobalFooter/
│   │   │   ├── demo/
│   │   │   │   └── basic.md
│   │   │   ├── index.d.ts
│   │   │   ├── index.js
│   │   │   ├── index.less
│   │   │   └── index.md
│   │   ├── GlobalHeader/
│   │   │   ├── RightContent.js
│   │   │   ├── index.js
│   │   │   └── index.less
│   │   ├── Login/
│   │   │   ├── LoginItem.js
│   │   │   ├── LoginSubmit.js
│   │   │   ├── LoginTab.js
│   │   │   ├── demo/
│   │   │   │   └── basic.md
│   │   │   ├── index.d.ts
│   │   │   ├── index.en-US.md
│   │   │   ├── index.js
│   │   │   ├── index.less
│   │   │   ├── index.zh-CN.md
│   │   │   ├── loginContext.js
│   │   │   └── map.js
│   │   ├── NoticeIcon/
│   │   │   ├── NoticeIconTab.d.ts
│   │   │   ├── NoticeList.js
│   │   │   ├── NoticeList.less
│   │   │   ├── demo/
│   │   │   │   ├── basic.md
│   │   │   │   └── popover.md
│   │   │   ├── index.d.ts
│   │   │   ├── index.en-US.md
│   │   │   ├── index.js
│   │   │   ├── index.less
│   │   │   └── index.zh-CN.md
│   │   ├── PageHeader/
│   │   │   ├── breadcrumb.d.ts
│   │   │   ├── breadcrumb.js
│   │   │   ├── demo/
│   │   │   │   ├── image.md
│   │   │   │   ├── simple.md
│   │   │   │   ├── standard.md
│   │   │   │   └── structure.md
│   │   │   ├── index.d.ts
│   │   │   ├── index.js
│   │   │   ├── index.less
│   │   │   ├── index.md
│   │   │   └── index.test.js
│   │   ├── PageHeaderWrapper/
│   │   │   ├── GridContent.js
│   │   │   ├── GridContent.less
│   │   │   ├── index.js
│   │   │   └── index.less
│   │   ├── PageLoading/
│   │   │   └── index.js
│   │   ├── Result/
│   │   │   ├── demo/
│   │   │   │   ├── classic.md
│   │   │   │   ├── error.md
│   │   │   │   └── structure.md
│   │   │   ├── index.d.ts
│   │   │   ├── index.js
│   │   │   ├── index.less
│   │   │   └── index.md
│   │   ├── SelectLang/
│   │   │   ├── index.js
│   │   │   └── index.less
│   │   ├── SettingDrawer/
│   │   │   ├── BlockChecbox.js
│   │   │   ├── ThemeColor.js
│   │   │   ├── ThemeColor.less
│   │   │   ├── index.js
│   │   │   └── index.less
│   │   ├── SiderMenu/
│   │   │   ├── BaseMenu.js
│   │   │   ├── SiderMenu.js
│   │   │   ├── SiderMenu.test.js
│   │   │   ├── index.js
│   │   │   └── index.less
│   │   ├── StandardTable/
│   │   │   ├── index.js
│   │   │   └── index.less
│   │   ├── TopNavHeader/
│   │   │   ├── index.js
│   │   │   └── index.less
│   │   └── _utils/
│   │       ├── pathTools.js
│   │       └── pathTools.test.js
│   ├── defaultSettings.js
│   ├── e2e/
│   │   ├── home.e2e.js
│   │   └── login.e2e.js
│   ├── global.less
│   ├── layouts/
│   │   ├── BasicLayout.js
│   │   ├── BlankLayout.js
│   │   ├── Footer.js
│   │   ├── Header.js
│   │   ├── Header.less
│   │   ├── MenuContext.js
│   │   ├── UserLayout.js
│   │   └── UserLayout.less
│   ├── locales/
│   │   ├── en-US.js
│   │   ├── pt-BR.js
│   │   ├── zh-CN.js
│   │   └── zh-TW.js
│   ├── models/
│   │   ├── article.js
│   │   ├── category.js
│   │   ├── global.js
│   │   ├── link.js
│   │   ├── list.js
│   │   ├── login.js
│   │   ├── message.js
│   │   ├── otherUser.js
│   │   ├── project.js
│   │   ├── setting.js
│   │   ├── tag.js
│   │   ├── timeAxis.js
│   │   └── user.js
│   ├── pages/
│   │   ├── 404.js
│   │   ├── Account/
│   │   │   └── Settings/
│   │   │       ├── BaseView.js
│   │   │       ├── BaseView.less
│   │   │       ├── Info.js
│   │   │       ├── Info.less
│   │   │       └── PersonalLinkView.js
│   │   ├── Article/
│   │   │   ├── ArticleComponent.js
│   │   │   ├── ArticleCreate.js
│   │   │   ├── CommentsComponent.js
│   │   │   ├── List.js
│   │   │   └── style.less
│   │   ├── Authorized.js
│   │   ├── Category/
│   │   │   ├── CategoryComponent.js
│   │   │   └── List.js
│   │   ├── Dashboard/
│   │   │   ├── Workplace.js
│   │   │   ├── Workplace.less
│   │   │   └── models/
│   │   │       └── activities.js
│   │   ├── Exception/
│   │   │   ├── 403.js
│   │   │   ├── 404.js
│   │   │   ├── 500.js
│   │   │   ├── TriggerException.js
│   │   │   ├── models/
│   │   │   │   └── error.js
│   │   │   └── style.less
│   │   ├── Link/
│   │   │   ├── LinkComponent.js
│   │   │   └── List.js
│   │   ├── Message/
│   │   │   ├── List.js
│   │   │   └── MessageComponent.js
│   │   ├── OtherUser/
│   │   │   ├── List.js
│   │   │   ├── OtherUserComponent.js
│   │   │   └── style.less
│   │   ├── Project/
│   │   │   ├── List.js
│   │   │   └── ProjectComponent.js
│   │   ├── Tag/
│   │   │   ├── List.js
│   │   │   └── TagComponent.js
│   │   ├── TimeAxis/
│   │   │   ├── List.js
│   │   │   └── TimeAxisComponent.js
│   │   ├── User/
│   │   │   ├── Login.js
│   │   │   ├── Login.less
│   │   │   ├── Register.js
│   │   │   ├── Register.less
│   │   │   ├── RegisterResult.js
│   │   │   ├── RegisterResult.less
│   │   │   └── models/
│   │   │       └── register.js
│   │   └── document.ejs
│   ├── services/
│   │   ├── api.js
│   │   ├── error.js
│   │   ├── geographic.js
│   │   └── user.js
│   └── utils/
│       ├── Authorized.js
│       ├── Yuan.js
│       ├── authority.js
│       ├── authority.test.js
│       ├── domain.js
│       ├── request.js
│       ├── utils.js
│       └── utils.less
└── tests/
    ├── fix_puppeteer.sh
    └── run-tests.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .circleci/config.yml
================================================
version: 2
jobs:
  build:
    docker:
      - image: circleci/node:8.11.4
    steps:
      - checkout
      - run: npm install
      - run: npm run build
  test:
    docker:
      - image: circleci/node:8.11.4
    steps:
      - checkout
      - run: sh ./tests/fix_puppeteer.sh
      - run: npm install
      - run: 
          command : npm run test:all
          no_output_timeout : 30m
workflows:
  version: 2
  build_and_test:
    jobs:
      - build
      - test

================================================
FILE: .dockerignore
================================================
# 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
/.vscode

# misc
.DS_Store
npm-debug.log*
yarn-error.log

/coverage
.idea
yarn.lock
package-lock.json
*bak
.vscode

# visual studio code
.history
*.log

functions/mock
.temp/**

# umi
.umi
.umi-production

# screenshot
screenshot
.firebase

================================================
FILE: .editorconfig
================================================
# http://editorconfig.org
root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.md]
trim_trailing_whitespace = false

[Makefile]
indent_style = tab


================================================
FILE: .eslintignore
================================================
/functions/mock


================================================
FILE: .eslintrc.js
================================================
module.exports = {
  parser: 'babel-eslint',
  extends: ['airbnb', 'prettier', 'plugin:compat/recommended'],
  env: {
    browser: true,
    node: true,
    es6: true,
    mocha: true,
    jest: true,
    jasmine: true,
  },
  globals: {
    APP_TYPE: true,
  },
  rules: {
    'react/jsx-filename-extension': [1, { extensions: ['.js'] }],
    'react/jsx-wrap-multilines': 0,
    'react/prop-types': 0,
    'react/forbid-prop-types': 0,
    'react/jsx-one-expression-per-line': 0,
    'import/no-unresolved': [2, { ignore: ['^@/', '^umi/'] }],
    'import/no-extraneous-dependencies': [2, { optionalDependencies: true }],
    'jsx-a11y/no-noninteractive-element-interactions': 0,
    'jsx-a11y/click-events-have-key-events': 0,
    'jsx-a11y/no-static-element-interactions': 0,
    'jsx-a11y/anchor-is-valid': 0,
    'linebreak-style': 0,
  },
  settings: {
    polyfills: ['fetch', 'promises', 'url'],
  },
};


================================================
FILE: .firebaserc
================================================
{
  "projects": {
    "default": "antd-pro"
  }
}


================================================
FILE: .gitignore
================================================
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
**/node_modules
/dist
# roadhog-api-doc ignore
/src/utils/request-temp.js
_roadhog-api-doc

# production

/.vscode

# misc
.DS_Store
npm-debug.log*
yarn-error.log

/coverage
.idea
yarn.lock
package-lock.json
*bak
.vscode

# visual studio code
.history
*.log

functions/mock
.temp/**

# umi
.umi
.umi-production

# screenshot
screenshot
.firebase

================================================
FILE: .prettierignore
================================================
**/*.md
**/*.svg
**/*.ejs
**/*.html
package.json
.umi
.umi-production


================================================
FILE: .prettierrc
================================================
{
  "singleQuote": true,
  "trailingComma": "es5",
  "printWidth": 100,
  "overrides": [
    {
      "files": ".prettierrc",
      "options": { "parser": "json" }
    }
  ]
}


================================================
FILE: .stylelintrc.json
================================================
{
  "extends": ["stylelint-config-standard", "stylelint-config-prettier"],
  "rules": {
    "declaration-empty-line-before": null,
    "no-descending-specificity": null,
    "selector-pseudo-class-no-unknown": null,
    "selector-pseudo-element-colon-notation": null
  }
}


================================================
FILE: CODE_OF_CONDUCT.md
================================================
# 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/


================================================
FILE: Dockerfile
================================================
FROM node:latest

WORKDIR /usr/src/app/

COPY package.json ./
RUN npm install --silent --no-cache

COPY ./ ./

RUN apt-get update
RUN apt-get install -yq gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 \
  libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 \
  libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 \
  libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 \
  ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget

CMD ["npm", "run", "build"]


================================================
FILE: Dockerfile.dev
================================================
FROM node:latest

WORKDIR /usr/src/app/

COPY package.json ./
RUN npm install --silent --no-cache

COPY ./ ./


CMD ["npm", "run", "start"]


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2018 Alipay.inc

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================

![效果图1.gif](https://upload-images.jianshu.io/upload_images/12890819-226f48af9087c3cf.gif?imageMogr2/auto-orient/strip)

![文章列表效果](https://upload-images.jianshu.io/upload_images/12890819-470c8996b8ebdfaf.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


![评论审核效果](https://upload-images.jianshu.io/upload_images/12890819-80ae92fc0e493805.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


## 前言

此 blog-react-admin 项目是基于 [蚂蚁金服开源的 ant design pro](https://pro.ant.design/index-cn) 之上,用 react 全家桶 + Ant Design  的进行再次开发的,项目已经开源,项目地址在 github 上。

效果预览 [https://preview.pro.ant.design/user/login](https://preview.pro.ant.design/user/login)


## 已实现功能

- [x] 登录  
- [x] 文章管理
- [x] 标签管理  
- [x] 留言管理
- [x] 用户管理
- [x] 友情链接管理
- [x] 时间轴管理
- [x] 富文本编辑器(支持 MarkDown 语法)
- [x] 项目展示
- [x] 评论管理

## 待实现功能

- [ ] 个人中心(用来设置博主的各种信息)
- [ ] 工作台( 接入百度统计接口,查看网站浏览量和用户访问等数据 )

## 主要项目结构

```
- pages
  - Account 博主个人中心
  - article 文章管理
  - Category 分类
  - Dashboard 工作台
  - Exection 403 404 500 等页面
  - Link 链接管理
  - Message 留言管理
  - OtherUser 用户管理
  - Project 项目
  - Tag 标签管理
  - TimeAsix 时间轴
  - User 登录注册管理
```

文章管理、用户管理、留言等 具体业务需求,都是些常用的逻辑可以实现的,也很简单,这里就不展开讲了。

## 添加富文本编辑器,同样支持 markdown 语法 

添加的编辑器为 [simplemde-markdown-editor](https://github.com/sparksuite/simplemde-markdown-editor)

效果图


![效果图1](https://user-images.githubusercontent.com/24362914/49021611-01c45080-f1ce-11e8-988a-8c1064a448de.png)


参考的文章为 [react 搭建博客---支持markdown的富文本编辑器](https://segmentfault.com/a/1190000010616632)


## 搭建

使用详情请查看 [Ant Design Pro ](https://pro.ant.design/docs/getting-started-cn),因为本项目也是在这个基础之上,按这个规范来构建的。


## 缺点

开发时,程序出错后,修改正确后,webpack 有时不会及时查觉到内容已经更改,从而不能及时编译,要重新运行命令打包。

笔者的文章里面的图片都是上传到简书上的,创建文章时,只是写个图片链接而已,你们也可以上传到简书或者七牛云,或者其他第三方。


## Build Setup ( 构建安装 )

``` 
# install dependencies
npm install 

# serve with hot reload at localhost: 3000
npm start 

# build for production with minification
npm run build 
```

如果要看完整的效果,是要和后台项目  **[blog-node](https://github.com/biaochenxuying/blog-node)** 一起运行才行的,不然接口请求会失败。


## 项目常见问题


### 管理后台登录

管理后台登录是用 **邮箱加密码** 进行登录


### 管理员账号创建

![](https://upload-images.jianshu.io/upload_images/12890819-67861a912768e646.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

管理后台的登录账号并不是 admin/user ,也不是搭建 mongodb 数据库时创建的 user 用户,这里的账号和密码要自己创建,至于怎样创建呢?

### 用 postman 调接口注册

如果是本地的可以像这样子创建,如果是服务器上的,请把 url 修改一下,


![注册](https://upload-images.jianshu.io/upload_images/12890819-3772744f72b8ed3e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


- 1.  url 

```
http://127.0.0.1:3000/register
```

- 2. param
```
{
 "name": "BiaoChenXuYing",
 "password": "888888",
 "email": "admin@qq.com",
 "phone": 1380013800,
 "type": 0,
 "introduce":"加班到天明,学习到昏厥!!! 微信公众号:【 BiaoChenXuYing 】,分享 WEB 全栈开发等相关的技术文章,热点资源,全栈程序员的成长之路。"
}
```
这里的 type 为 0 是管理员账号,为 1 时,是普通用户。

### 权限

注册了管理员账号,并用管理员账号登录,还不能正常登录管理后台的,会被重定向加登录页面。因为权限管理的限制,要把自己注册的管理员账号的 **名字** 加在 config/router.config.js 的 authority 里面。

详情请看:

```
https://pro.ant.design/docs/authority-management-cn
```

### 登录

登录博客管理后台是用 **邮箱** 加 **密码** 登录。

## 项目地址与文档教程

开源不易,如果觉得该项目不错或者对你有所帮助,欢迎到 github 上给个 star,谢谢。

**项目地址:**

> [前台展示: https://github.com/biaochenxuying/blog-react](https://github.com/biaochenxuying/blog-react)

> [前台展示: https://github.com/biaochenxuying/blog-vue-typescript](https://github.com/biaochenxuying/blog-vue-typescript)

> [管理后台:https://github.com/biaochenxuying/blog-react-admin](https://github.com/biaochenxuying/blog-react-admin)

> [后端:https://github.com/biaochenxuying/blog-node](https://github.com/biaochenxuying/blog-node)

> [blog:https://github.com/biaochenxuying/blog](https://github.com/biaochenxuying/blog)

**本博客系统的系列文章:**

- 1. [react + node + express + ant + mongodb 的简洁兼时尚的博客网站](https://biaochenxuying.cn/articleDetail?article_id=5bf57a8f85e0f13af26e579b)
- 2. [react + Ant Design + 支持 markdown 的 blog-react 项目文档说明](https://biaochenxuying.cn/articleDetail?article_id=5bf6bb5e85e0f13af26e57b7)
- 3. [基于 node + express + mongodb 的 blog-node 项目文档说明](https://biaochenxuying.cn/articleDetail?article_id=5bf8c57185e0f13af26e7d0d)
- 4. [服务器小白的我,是如何将 node+mongodb 项目部署在服务器上并进行性能优化的](https://biaochenxuying.cn/articleDetail?article_id=5bfa728bb54f044b4f9da240)
- 5. [github 授权登录教程与如何设计第三方授权登录的用户表](https://biaochenxuying.cn/articleDetail?article_id=5c7bd34e42b55e2ecc90976d)
- 6. [一次网站的性能优化之路 -- 天下武功,唯快不破](https://biaochenxuying.cn/articleDetail?article_id=5c8ca2d3b87b8a04f1860c9a)
- 7. [Vue + TypeScript + Element 搭建简洁时尚的博客网站及踩坑记](https://biaochenxuying.cn/articleDetail?article_id=5c9d8ce5f181945ddd6b0ffc)
- 8. [前端解决第三方图片防盗链的办法 - html referrer 访问图片资源403问题](https://biaochenxuying.cn/articleDetail?article_id=5cfcc6798090bd3c84138a08)


## 服务器

笔者觉得每个开发者都应该拥有自己的网站和服务器,这可是很酷的事情,学习 Linux、跑跑脚本、建站、搭博客啥的都行啊。

因为笔者就有自己的服务器,而且有两台了,用于平时的学习,还搭建了自己的网站。

有不少读者问过我,为什么我学的那么快的呢 ? 怎么在一年内学了那么知识的...

其实也没什么秘决,就是平时有自己的服务器了,就爱折腾,学到的知识能很快得到验证,所以学起来兴致高一点。

特别是大三和大四的学生,买了服务器,搭建个项目给面试官看也香,对找工作和面试都加分,还可以熟悉技术栈。

[想学得快,就得有自己的服务器来折腾才行(低于 1 折、89/年、229/3年,比学生机还便宜)](https://biaochenxuying.cn/articleDetail?article_id=5de65dd90283dc742f8f633a)

比如笔者的两个网站:

> https://biaochenxuying.cn/

> https://www.kwgg2020.com/



## 最后

如果您觉得本项目和文章不错或者对你有所帮助,请给个星吧,你的肯定就是我继续创作的最大动力。

<!-- 鉴于问问题的人有点多,笔者时间有限,处理不过来,大家可以加入 QQ 群:**186045338**,加群暗号:**全栈修炼** ,一起相互交流学习。 -->




================================================
FILE: README.ru-RU.md
================================================
[English](./README.md) | [简体中文](./README.zh-CN.md) | Русский

<h1 align="center">Ant Design Pro</h1>

<div align="center">

UI-решение "из коробки" для корпоративных приложений как React boilerplate

[![CircleCI Status](https://circleci.com/gh/ant-design/ant-design-pro.svg?style=svg)](https://circleci.com/gh/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)
[![Dependencies](https://img.shields.io/david/ant-design/ant-design-pro.svg)](https://david-dm.org/ant-design/ant-design-pro)
[![DevDependencies](https://img.shields.io/david/dev/ant-design/ant-design-pro.svg)](https://david-dm.org/ant-design/ant-design-pro?type=dev)
[![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://user-images.githubusercontent.com/8186664/44953195-581e3d80-aec4-11e8-8dcb-54b9db38ec11.png)

</div>

- Демо: http://preview.pro.ant.design
- Домашняя страница: http://pro.ant.design
- Документация: http://pro.ant.design/docs/getting-started
- История изменений: http://pro.ant.design/docs/changelog
- FAQ: http://pro.ant.design/docs/faq
- Китайское зеркало сайта: http://ant-design-pro.gitee.io

## Поиск переводчиков :loudspeaker:

Нам нужна ваша помощь: https://github.com/ant-design/ant-design-pro/issues/120

## Возможности

- :gem: **Аккуратный дизайн**: Посмотрите [спецификацию Ant Design](http://ant.design/)
- :triangular_ruler: **Общие шаблоны**: Стандартные шаблоны для корпоративных приложений
- :rocket: **Разработка, как искусство**: Новейший стек технологий React/umi/dva/antd
- :iphone: **Отзывчивая верстка**: Создан для экранов разных размеров
- :art: **Темизация**: Возможность изменения темы с помощью конфигурации
- :globe_with_meridians: **Мультиязычность**: Встроенное i18n решение
- :gear: **Лучшие практики**: Надежные процессы для хорошего кода
- :1234: **Разработка по шаблону**: Простое в использовании решение для разработки
- :white_check_mark: **UI тесты**: Разрабатывайте безопасно с юнит и e2e тестами

## Шаблоны

```
- 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
- Account
  - Account Center
  - Account Settings
- Result
  - Success
  - Failed
- Exception
  - 403
  - 404
  - 500
- User
  - Login
  - Register
  - Register Result
```

## Использование

```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
```

Больше информации в [документации](http://pro.ant.design/docs/getting-started).

## Совместимость

Современные браузеры и IE11.

| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/opera/opera_48x48.png" alt="Opera" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Opera |
| --------- | --------- | --------- | --------- | --------- |
| IE11, Edge| last 2 versions| last 2 versions| last 2 versions| last 2 versions

## Распространение

Любые варианты распространения приветствуются! Вот несколько примероы того, как вы можете помочь распространению проекта:

- Использовать Ant Design Pro в ежедневной работе.
- Создавать [задачи](http://github.com/ant-design/ant-design-pro/issues) заводить баги или отвечать на вопросы.
- Делать [pull-реквесты](http://github.com/ant-design/ant-design-pro/pulls) для совершенствования нашего кода.


================================================
FILE: README.zh-CN.md
================================================
[English](./README.md) | 简体中文 | [Русский](./README.ru-RU.md)

<h1 align="center">Ant Design Pro</h1>

<div align="center">

开箱即用的中台前端/设计解决方案。

[![CircleCI Status](https://circleci.com/gh/ant-design/ant-design-pro.svg?style=svg)](https://circleci.com/gh/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)
[![Dependencies](https://img.shields.io/david/ant-design/ant-design-pro.svg)](https://david-dm.org/ant-design/ant-design-pro)
[![DevDependencies](https://img.shields.io/david/dev/ant-design/ant-design-pro.svg)](https://david-dm.org/ant-design/ant-design-pro?type=dev)
[![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://user-images.githubusercontent.com/8186664/44953195-581e3d80-aec4-11e8-8dcb-54b9db38ec11.png)

</div>

- 预览: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
- 国内镜像:http://ant-design-pro.gitee.io

## 特性

- :gem: **优雅美观**:基于 Ant Design 体系精心设计
- :triangular_ruler: **常见设计模式**:提炼自中后台应用的典型页面和场景
- :rocket: **最新技术栈**:使用 React/umi/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
```

### 使用 docker

```bash
// dev 
$ npm run docker:dev

// build 
$ npm run docker:build


// production dev 
$ npm run docker-prod:dev

// production build 
$ npm run docker-prod:build
```

更多信息请参考 [使用文档](http://pro.ant.design/docs/getting-started)。

## 支持环境

现代浏览器及 IE11。

| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/opera/opera_48x48.png" alt="Opera" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Opera |
| --------- | --------- | --------- | --------- | --------- |
| IE11, Edge| last 2 versions| last 2 versions| last 2 versions| last 2 versions

## 参与贡献

我们非常欢迎你的贡献,你可以通过以下方式和我们一起共建 :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 的代码。


================================================
FILE: appveyor.yml
================================================
# Test against the latest version of this Node.js version
environment:
  nodejs_version: "8"

# this is how to allow failing jobs in the matrix
matrix:
  fast_finish: true     # set this flag to immediately finish build once one of the jobs fails.

# 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


================================================
FILE: config/config.js
================================================
// https://umijs.org/config/
import os from 'os';
import pageRoutes from './router.config';
import webpackplugin from './plugin.config';
import defaultSettings from '../src/defaultSettings';

export default {
  // add for transfer to umi
  plugins: [
    [
      'umi-plugin-react',
      {
        antd: true,
        dva: {
          hmr: true,
        },
        targets: {
          ie: 11,
        },
        locale: {
          enable: true, // default false
          default: 'zh-CN', // default zh-CN
          baseNavigator: true, // default true, when it is true, will use `navigator.language` overwrite default
        },
        dynamicImport: {
          loadingComponent: './components/PageLoading/index',
        },
        ...(!process.env.TEST && os.platform() === 'darwin'
          ? {
              dll: {
                include: ['dva', 'dva/router', 'dva/saga', 'dva/fetch'],
                exclude: ['@babel/runtime'],
              },
              hardSource: true,
            }
          : {}),
      },
    ],
    [
      'umi-plugin-ga',
      {
        code: 'UA-72788897-6',
      },
    ],
  ],
  targets: {
    ie: 11,
  },
  define: {
    APP_TYPE: process.env.APP_TYPE || '',
  },
  // 路由配置
  routes: pageRoutes,
  // Theme for antd
  // https://ant.design/docs/react/customize-theme-cn
  theme: {
    'primary-color': defaultSettings.primaryColor,
  },
  externals: {
    '@antv/data-set': 'DataSet',
  },
  proxy: {
    '/api': {
      target: 'http://127.0.0.1:3000',
      changeOrigin: true,
      pathRewrite: { '^/api': '' },
    },
  },
  ignoreMomentLocale: true,
  lessLoaderOptions: {
    javascriptEnabled: true,
  },
  disableRedirectHoist: true,
  cssLoaderOptions: {
    modules: true,
    getLocalIdent: (context, localIdentName, localName) => {
      if (
        context.resourcePath.includes('node_modules') ||
        context.resourcePath.includes('ant.design.pro.less') ||
        context.resourcePath.includes('global.less')
      ) {
        return localName;
      }
      const match = context.resourcePath.match(/src(.*)/);
      if (match && match[1]) {
        const antdProPath = match[1].replace('.less', '');
        const arr = antdProPath
          .split('/')
          .map(a => a.replace(/([A-Z])/g, '-$1'))
          .map(a => a.toLowerCase());
        return `antd-pro${arr.join('-')}-${localName}`.replace(/--/g, '-');
      }
      return localName;
    },
  },
  manifest: {
    name: 'reac-blog',
    background_color: '#FFF',
    description: 'An out-of-box UI solution for enterprise applications as a React boilerplate.',
    display: 'standalone',
    start_url: '/index.html',
    icons: [
      {
        src: '/favicon.png',
        sizes: '48x48',
        type: 'image/png',
      },
    ],
  },

  chainWebpack: webpackplugin,
  cssnano: {
    mergeRules: false,
  },
};


================================================
FILE: config/plugin.config.js
================================================
// Change theme plugin

import MergeLessPlugin from 'antd-pro-merge-less';
import AntDesignThemePlugin from 'antd-pro-theme-webpack-plugin';
import path from 'path';

export default config => {
  // 将所有 less 合并为一个供 themePlugin使用
  const outFile = path.join(__dirname, '../.temp/ant-design-pro.less');
  const stylesDir = path.join(__dirname, '../src/');

  config.plugin('merge-less').use(MergeLessPlugin, [
    {
      stylesDir,
      outFile,
    },
  ]);

  config.plugin('ant-design-theme').use(AntDesignThemePlugin, [
    {
      antDir: path.join(__dirname, '../node_modules/antd'),
      stylesDir,
      varFile: path.join(__dirname, '../node_modules/antd/lib/style/themes/default.less'),
      mainLessFile: outFile, //     themeVariables: ['@primary-color'],
      indexFileName: 'index.html',
    },
  ]);
};


================================================
FILE: config/router.config.js
================================================
export default [
  // user
  {
    path: '/user',
    component: '../layouts/UserLayout',
    routes: [
      { path: '/user', redirect: '/user/login' },
      { path: '/user/login', component: './User/Login' },
      // { path: '/user/register', component: './User/Register' },
      // { path: '/user/register-result', component: './User/RegisterResult' },
    ],
  },
  // app
  {
    path: '/',
    component: '../layouts/BasicLayout',
    Routes: ['src/pages/Authorized'],
    authority: ['admin', 'user', 'xuying', 'biaochenxuying'],
    routes: [
      // dashboard
      { path: '/', redirect: '/user/login' },
      // { path: '/', redirect: '/dashboard/workplace' },
      {
        path: '/dashboard',
        name: 'dashboard',
        icon: 'dashboard',
        routes: [
          {
            path: '/dashboard/workplace',
            name: 'workplace',
            component: './Dashboard/Workplace',
          },
        ],
      },
      {
        path: '/otherUser',
        name: 'otherUser',
        icon: 'usergroup-add',
        routes: [
          {
            path: '/otherUser/list',
            name: 'list',
            component: './OtherUser/List',
          },
        ],
      },
      {
        path: '/article',
        name: 'article',
        icon: 'file-markdown',
        routes: [
          {
            path: '/article/list',
            name: 'list',
            component: './Article/List',
          },
          {
            path: '/article/create',
            name: 'create',
            component: './Article/ArticleCreate',
          },
        ],
      },
      {
        path: '/message',
        name: 'message',
        icon: 'message',
        routes: [
          {
            path: '/message/list',
            name: 'list',
            component: './Message/List',
          },
        ],
      },
      {
        path: '/tag',
        name: 'tag',
        icon: 'tags',
        routes: [
          {
            path: '/tag/list',
            name: 'list',
            component: './Tag/List',
          },
        ],
      },
      {
        path: '/link',
        name: 'link',
        icon: 'link',
        routes: [
          {
            path: '/link/list',
            name: 'list',
            component: './Link/List',
          },
        ],
      },
      {
        path: '/category',
        name: 'category',
        icon: 'book',
        routes: [
          {
            path: '/category/list',
            name: 'list',
            component: './Category/List',
          },
        ],
      },
      {
        path: '/timeAxis',
        name: 'timeAxis',
        icon: 'clock-circle',
        routes: [
          {
            path: '/timeAxis/list',
            name: 'list',
            component: './TimeAxis/List',
          },
        ],
      },
      {
        path: '/project',
        name: 'project',
        icon: 'clock-circle',
        routes: [
          {
            path: '/project/list',
            name: 'list',
            component: './Project/List',
          },
        ],
      },
      {
        name: 'exception',
        icon: 'warning',
        path: '/exception',
        routes: [
          // exception
          {
            path: '/exception/403',
            name: 'not-permission',
            component: './Exception/403',
          },
          {
            path: '/exception/404',
            name: 'not-find',
            component: './Exception/404',
          },
          {
            path: '/exception/500',
            name: 'server-error',
            component: './Exception/500',
          },
          {
            path: '/exception/trigger',
            name: 'trigger',
            hideInMenu: true,
            component: './Exception/TriggerException',
          },
        ],
      },
      {
        name: 'account',
        icon: 'user',
        path: '/account',
        routes: [
          {
            path: '/account/settings',
            name: 'settings',
            component: './Account/Settings/Info',
            routes: [
              {
                path: '/account/settings',
                redirect: '/account/settings/base',
              },
              {
                path: '/account/settings/base',
                component: './Account/Settings/BaseView',
              },
              {
                path: '/account/settings/personalLink',
                component: './Account/Settings/PersonalLinkView',
              },
            ],
          },
        ],
      },
      {
        component: '404',
      },
    ],
  },
];


================================================
FILE: docker/docker-compose.dev.yml
================================================
version: "3.5"

services:
  ant-design-pro_dev:
    ports:
      - 8000:8000
    build:
      context: ../
      dockerfile: Dockerfile.dev
    container_name: "ant-design-pro_dev"
    volumes:
      - ../src:/usr/src/app/src
      - ../config:/usr/src/app/config
      - ../mock:/usr/src/app/mock


================================================
FILE: docker/docker-compose.yml
================================================
version: "3.5"

services:
  ant-design-pro_build:
    build: ../
    container_name: "ant-design-pro_build"
    volumes:
      - dist:/usr/src/app/dist

  ant-design-pro_web:
    image: nginx
    ports:
      - 80:80
    container_name: "ant-design-pro_web"
    restart: unless-stopped
    volumes:
      - dist:/usr/share/nginx/html:ro
      - ./nginx.conf:/etc/nginx/conf.d/default.conf

volumes:
  dist:


================================================
FILE: docker/nginx.conf
================================================
server {
    listen 80;
    # gzip config
    gzip on;
    gzip_min_length 1k;
    gzip_comp_level 9
    gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
    gzip_vary on;
    gzip_disable "MSIE [1-6]\.";

    root /usr/share/nginx/html;

    location / {
        try_files $uri $uri/ /index.html;
    }
    location /api {
        proxy_pass https://preview.pro.ant.design;
        proxy_set_header   X-Forwarded-Proto $scheme;
        proxy_set_header   Host              $http_host;
        proxy_set_header   X-Real-IP         $remote_addr;
    }
}


================================================
FILE: firebase.json
================================================
{
  "hosting": {
    "public": "dist",
    "rewrites": [
      { "source": "/api/**", "function": "api" },
      {
        "source": "**",
        "destination": "/index.html"
      }
    ],
    "ignore": ["firebase.json", "**/.*", "**/node_modules/**"]
  }
}


================================================
FILE: functions/index.js
================================================
// [START functionsimport]
const functions = require('firebase-functions');
const express = require('express');
const matchMock = require('./matchMock');
const app = express();

app.use(matchMock);

exports.api = functions.https.onRequest(app);


================================================
FILE: functions/matchMock.js
================================================
const mockFile = require('./mock/index');
const pathToRegexp = require('path-to-regexp');
const debug = console.log;
const bodyParser = require('body-parser');

const BODY_PARSED_METHODS = ['post', 'put', 'patch'];

function parseKey(key) {
  let method = 'get';
  let path = key;
  if (key.indexOf(' ') > -1) {
    const splited = key.split(' ');
    method = splited[0].toLowerCase();
    path = splited[1]; // eslint-disable-line
  }
  return {
    method,
    path,
  };
}

function createHandler(method, path, handler) {
  return function(req, res, next) {
    if (BODY_PARSED_METHODS.includes(method)) {
      bodyParser.json({ limit: '5mb', strict: false })(req, res, () => {
        bodyParser.urlencoded({ limit: '5mb', extended: true })(req, res, () => {
          sendData();
        });
      });
    } else {
      sendData();
    }

    function sendData() {
      if (typeof handler === 'function') {
        handler(req, res, next);
      } else {
        res.json(handler);
      }
    }
  };
}

function normalizeConfig(config) {
  return Object.keys(config).reduce((memo, key) => {
    const handler = config[key];
    const { method, path } = parseKey(key);
    const keys = [];
    const re = pathToRegexp(path, keys);
    memo.push({
      method,
      path,
      re,
      keys,
      handler: createHandler(method, path, handler),
    });
    return memo;
  }, []);
}

const mockData = normalizeConfig(mockFile);

function matchMock(req) {
  const { path: exceptPath } = req;
  const exceptMethod = req.method.toLowerCase();
  for (const mock of mockData) {
    const { method, re, keys } = mock;
    if (method === exceptMethod) {
      const match = re.exec(req.path);
      if (match) {
        const params = {};

        for (let i = 1; i < match.length; i = i + 1) {
          const key = keys[i - 1];
          const prop = key.name;
          const val = decodeParam(match[i]);

          if (val !== undefined || !hasOwnProperty.call(params, prop)) {
            params[prop] = val;
          }
        }
        req.params = params;
        return mock;
      }
    }
  }

  function decodeParam(val) {
    if (typeof val !== 'string' || val.length === 0) {
      return val;
    }

    try {
      return decodeURIComponent(val);
    } catch (err) {
      if (err instanceof URIError) {
        err.message = `Failed to decode param ' ${val} '`;
        err.status = err.statusCode = 400;
      }

      throw err;
    }
  }

  return mockData.filter(({ method, re }) => {
    return method === exceptMethod && re.test(exceptPath);
  })[0];
}
module.exports = (req, res, next) => {
  const match = matchMock(req);
  if (match) {
    debug(`mock matched: [${match.method}] ${match.path}`);
    return match.handler(req, res, next);
  } else {
    return next();
  }
};


================================================
FILE: functions/package.json
================================================
{
  "name": "functions",
  "description": "Cloud Functions for Firebase",
  "scripts": {
    "serve": "npm run mock && firebase serve --only functions",
    "shell": "firebase functions:shell",
    "start": "npm run shell",
    "deploy": "firebase deploy --only functions",
    "logs": "firebase functions:log",
    "mock": "node ../scripts/generateMock.js"
  },
  "dependencies": {
    "@babel/runtime": "^7.0.0",
    "body-parser": "^1.18.3",
    "express": "^4.16.3",
    "firebase-admin": "^5.12.1",
    "firebase-functions": "^2.0.5",
    "mockjs": "^1.0.1-beta3",
    "moment": "^2.22.2",
    "path-to-regexp": "^2.2.1"
  },
  "private": true
}


================================================
FILE: jest.config.js
================================================
module.exports = {
  testURL: 'http://localhost:8000',
};


================================================
FILE: jsconfig.json
================================================
{
  "compilerOptions": {
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}


================================================
FILE: mock/api.js
================================================
import mockjs from 'mockjs';

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/iXjVmWVHbCJAyqvDxdtx.png',
  'https://gw.alipayobjects.com/zos/rmsportal/gLaIAoVWTtLbBWZNYEMg.png',
];
const desc = [
  '那是一种内在的东西, 他们到达不了,也无法触及的',
  '希望是一个好东西,也许是最好的,好东西是不会消亡的',
  '生命就像一盒巧克力,结果往往出人意料',
  '城镇中有那么多的酒馆,她却偏偏走进了我的酒馆',
  '那时候我只会想自己想要什么,从不想自己拥有什么',
];

const user = [
  '付小小',
  '曲丽丽',
  '林东东',
  '周星星',
  '吴加好',
  '朱偏右',
  '鱼酱',
  '乐哥',
  '谭小仪',
  '仲尼',
];

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: '曲丽丽',
          id: 'member1',
        },
        {
          avatar: 'https://gw.alipayobjects.com/zos/rmsportal/tBOxZPlITHqwlGjsJWaF.png',
          name: '王昭君',
          id: 'member2',
        },
        {
          avatar: 'https://gw.alipayobjects.com/zos/rmsportal/sBxjgqiuHMGRkIjqlQCd.png',
          name: '董娜娜',
          id: 'member3',
        },
      ],
    });
  }

  return list;
}

let sourceData;

function getFakeList(req, res) {
  const params = req.query;

  const count = params.count * 1 || 20;

  const result = fakeList(count);
  sourceData = result;
  return res.json(result);
}

function postFakeList(req, res) {
  const { /* url = '', */ body } = req;
  // const params = getUrlParams(url);
  const { method, id } = body;
  // const count = (params.count * 1) || 20;
  let result = sourceData;

  switch (method) {
    case 'delete':
      result = result.filter(item => item.id !== id);
      break;
    case 'update':
      result.forEach((item, i) => {
        if (item.id === id) {
          result[i] = Object.assign(item, body);
        }
      });
      break;
    case 'post':
      result.unshift({
        body,
        id: `fake-list-${result.length}`,
        createdAt: new Date().getTime(),
      });
      break;
    default:
      break;
  }

  return res.json(result);
}

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: '',
  },
];

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}',
  },
];

function getFakeCaptcha(req, res) {
  return res.json('captcha-xxx');
}

export default {
  'GET /api/project/notice': getNotice,
  'GET /api/activities': getActivities,
  '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,
  'POST /api/fake_list': postFakeList,
  'GET /api/captcha': getFakeCaptcha,
};


================================================
FILE: mock/blog.js
================================================
const getArticle = (req, res) =>
  res.json([
    {
      id: '000000001',
      avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png',
      title: '你收到了 14 份新周报',
      datetime: '2017-08-09',
      type: 'notification',
    },
    {
      id: '000000002',
      avatar: 'https://gw.alipayobjects.com/zos/rmsportal/OKJXDXrmkNshAMvwtvhu.png',
      title: '你推荐的 曲妮妮 已通过第三轮面试',
      datetime: '2017-08-08',
      type: 'notification',
    },
    {
      id: '000000003',
      avatar: 'https://gw.alipayobjects.com/zos/rmsportal/kISTdvpyTAhtGxpovNWd.png',
      title: '这种模板可以区分多种通知类型',
      datetime: '2017-08-07',
      read: true,
      type: 'notification',
    },
    {
      id: '000000004',
      avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png',
      title: '左侧图标用于区分不同的类型',
      datetime: '2017-08-07',
      type: 'notification',
    },
    {
      id: '000000005',
      avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png',
      title: '内容不要超过两行字,超出时自动截断',
      datetime: '2017-08-07',
      type: 'notification',
    },
    {
      id: '000000006',
      avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg',
      title: '曲丽丽 评论了你',
      description: '描述信息描述信息描述信息',
      datetime: '2017-08-07',
      type: 'message',
    },
    {
      id: '000000007',
      avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg',
      title: '朱偏右 回复了你',
      description: '这种模板用于提醒谁与你发生了互动,左侧放『谁』的头像',
      datetime: '2017-08-07',
      type: 'message',
    },
    {
      id: '000000008',
      avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg',
      title: '标题',
      description: '这种模板用于提醒谁与你发生了互动,左侧放『谁』的头像',
      datetime: '2017-08-07',
      type: 'message',
    },
    {
      id: '000000009',
      title: '任务名称',
      description: '任务需要在 2017-01-12 20:00 前启动',
      extra: '未开始',
      status: 'todo',
      type: 'event',
    },
    {
      id: '000000010',
      title: '第三方紧急代码变更',
      description: '冠霖提交于 2017-01-06,需在 2017-01-07 前完成代码变更任务',
      extra: '马上到期',
      status: 'urgent',
      type: 'event',
    },
    {
      id: '000000011',
      title: '信息安全考试',
      description: '指派竹尔于 2017-01-09 前完成更新并发布',
      extra: '已耗时 8 天',
      status: 'doing',
      type: 'event',
    },
    {
      id: '000000012',
      title: 'ABCD 版本发布',
      description: '冠霖提交于 2017-01-06,需在 2017-01-07 前完成代码变更任务',
      extra: '进行中',
      status: 'processing',
      type: 'event',
    },
  ]);

export default {
  'GET /api/article': getArticle,
};


================================================
FILE: mock/chart.js
================================================
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: `Stores ${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],
      });
    }
  });
});

const getFakeChartData = {
  visitData,
  visitData2,
  salesData,
  searchData,
  offlineData,
  offlineChartData,
  salesTypeData,
  salesTypeDataOnline,
  salesTypeDataOffline,
  radarData,
};

export default {
  'GET /api/fake_chart_data': getFakeChartData,
};


================================================
FILE: mock/geographic/city.json
================================================
{
  "110000": [
    {
      "province": "北京市",
      "name": "市辖区",
      "id": "110100"
    }
  ],
  "120000": [
    {
      "province": "天津市",
      "name": "市辖区",
      "id": "120100"
    }
  ],
  "130000": [
    {
      "province": "河北省",
      "name": "石家庄市",
      "id": "130100"
    },
    {
      "province": "河北省",
      "name": "唐山市",
      "id": "130200"
    },
    {
      "province": "河北省",
      "name": "秦皇岛市",
      "id": "130300"
    },
    {
      "province": "河北省",
      "name": "邯郸市",
      "id": "130400"
    },
    {
      "province": "河北省",
      "name": "邢台市",
      "id": "130500"
    },
    {
      "province": "河北省",
      "name": "保定市",
      "id": "130600"
    },
    {
      "province": "河北省",
      "name": "张家口市",
      "id": "130700"
    },
    {
      "province": "河北省",
      "name": "承德市",
      "id": "130800"
    },
    {
      "province": "河北省",
      "name": "沧州市",
      "id": "130900"
    },
    {
      "province": "河北省",
      "name": "廊坊市",
      "id": "131000"
    },
    {
      "province": "河北省",
      "name": "衡水市",
      "id": "131100"
    },
    {
      "province": "河北省",
      "name": "省直辖县级行政区划",
      "id": "139000"
    }
  ],
  "140000": [
    {
      "province": "山西省",
      "name": "太原市",
      "id": "140100"
    },
    {
      "province": "山西省",
      "name": "大同市",
      "id": "140200"
    },
    {
      "province": "山西省",
      "name": "阳泉市",
      "id": "140300"
    },
    {
      "province": "山西省",
      "name": "长治市",
      "id": "140400"
    },
    {
      "province": "山西省",
      "name": "晋城市",
      "id": "140500"
    },
    {
      "province": "山西省",
      "name": "朔州市",
      "id": "140600"
    },
    {
      "province": "山西省",
      "name": "晋中市",
      "id": "140700"
    },
    {
      "province": "山西省",
      "name": "运城市",
      "id": "140800"
    },
    {
      "province": "山西省",
      "name": "忻州市",
      "id": "140900"
    },
    {
      "province": "山西省",
      "name": "临汾市",
      "id": "141000"
    },
    {
      "province": "山西省",
      "name": "吕梁市",
      "id": "141100"
    }
  ],
  "150000": [
    {
      "province": "内蒙古自治区",
      "name": "呼和浩特市",
      "id": "150100"
    },
    {
      "province": "内蒙古自治区",
      "name": "包头市",
      "id": "150200"
    },
    {
      "province": "内蒙古自治区",
      "name": "乌海市",
      "id": "150300"
    },
    {
      "province": "内蒙古自治区",
      "name": "赤峰市",
      "id": "150400"
    },
    {
      "province": "内蒙古自治区",
      "name": "通辽市",
      "id": "150500"
    },
    {
      "province": "内蒙古自治区",
      "name": "鄂尔多斯市",
      "id": "150600"
    },
    {
      "province": "内蒙古自治区",
      "name": "呼伦贝尔市",
      "id": "150700"
    },
    {
      "province": "内蒙古自治区",
      "name": "巴彦淖尔市",
      "id": "150800"
    },
    {
      "province": "内蒙古自治区",
      "name": "乌兰察布市",
      "id": "150900"
    },
    {
      "province": "内蒙古自治区",
      "name": "兴安盟",
      "id": "152200"
    },
    {
      "province": "内蒙古自治区",
      "name": "锡林郭勒盟",
      "id": "152500"
    },
    {
      "province": "内蒙古自治区",
      "name": "阿拉善盟",
      "id": "152900"
    }
  ],
  "210000": [
    {
      "province": "辽宁省",
      "name": "沈阳市",
      "id": "210100"
    },
    {
      "province": "辽宁省",
      "name": "大连市",
      "id": "210200"
    },
    {
      "province": "辽宁省",
      "name": "鞍山市",
      "id": "210300"
    },
    {
      "province": "辽宁省",
      "name": "抚顺市",
      "id": "210400"
    },
    {
      "province": "辽宁省",
      "name": "本溪市",
      "id": "210500"
    },
    {
      "province": "辽宁省",
      "name": "丹东市",
      "id": "210600"
    },
    {
      "province": "辽宁省",
      "name": "锦州市",
      "id": "210700"
    },
    {
      "province": "辽宁省",
      "name": "营口市",
      "id": "210800"
    },
    {
      "province": "辽宁省",
      "name": "阜新市",
      "id": "210900"
    },
    {
      "province": "辽宁省",
      "name": "辽阳市",
      "id": "211000"
    },
    {
      "province": "辽宁省",
      "name": "盘锦市",
      "id": "211100"
    },
    {
      "province": "辽宁省",
      "name": "铁岭市",
      "id": "211200"
    },
    {
      "province": "辽宁省",
      "name": "朝阳市",
      "id": "211300"
    },
    {
      "province": "辽宁省",
      "name": "葫芦岛市",
      "id": "211400"
    }
  ],
  "220000": [
    {
      "province": "吉林省",
      "name": "长春市",
      "id": "220100"
    },
    {
      "province": "吉林省",
      "name": "吉林市",
      "id": "220200"
    },
    {
      "province": "吉林省",
      "name": "四平市",
      "id": "220300"
    },
    {
      "province": "吉林省",
      "name": "辽源市",
      "id": "220400"
    },
    {
      "province": "吉林省",
      "name": "通化市",
      "id": "220500"
    },
    {
      "province": "吉林省",
      "name": "白山市",
      "id": "220600"
    },
    {
      "province": "吉林省",
      "name": "松原市",
      "id": "220700"
    },
    {
      "province": "吉林省",
      "name": "白城市",
      "id": "220800"
    },
    {
      "province": "吉林省",
      "name": "延边朝鲜族自治州",
      "id": "222400"
    }
  ],
  "230000": [
    {
      "province": "黑龙江省",
      "name": "哈尔滨市",
      "id": "230100"
    },
    {
      "province": "黑龙江省",
      "name": "齐齐哈尔市",
      "id": "230200"
    },
    {
      "province": "黑龙江省",
      "name": "鸡西市",
      "id": "230300"
    },
    {
      "province": "黑龙江省",
      "name": "鹤岗市",
      "id": "230400"
    },
    {
      "province": "黑龙江省",
      "name": "双鸭山市",
      "id": "230500"
    },
    {
      "province": "黑龙江省",
      "name": "大庆市",
      "id": "230600"
    },
    {
      "province": "黑龙江省",
      "name": "伊春市",
      "id": "230700"
    },
    {
      "province": "黑龙江省",
      "name": "佳木斯市",
      "id": "230800"
    },
    {
      "province": "黑龙江省",
      "name": "七台河市",
      "id": "230900"
    },
    {
      "province": "黑龙江省",
      "name": "牡丹江市",
      "id": "231000"
    },
    {
      "province": "黑龙江省",
      "name": "黑河市",
      "id": "231100"
    },
    {
      "province": "黑龙江省",
      "name": "绥化市",
      "id": "231200"
    },
    {
      "province": "黑龙江省",
      "name": "大兴安岭地区",
      "id": "232700"
    }
  ],
  "310000": [
    {
      "province": "上海市",
      "name": "市辖区",
      "id": "310100"
    }
  ],
  "320000": [
    {
      "province": "江苏省",
      "name": "南京市",
      "id": "320100"
    },
    {
      "province": "江苏省",
      "name": "无锡市",
      "id": "320200"
    },
    {
      "province": "江苏省",
      "name": "徐州市",
      "id": "320300"
    },
    {
      "province": "江苏省",
      "name": "常州市",
      "id": "320400"
    },
    {
      "province": "江苏省",
      "name": "苏州市",
      "id": "320500"
    },
    {
      "province": "江苏省",
      "name": "南通市",
      "id": "320600"
    },
    {
      "province": "江苏省",
      "name": "连云港市",
      "id": "320700"
    },
    {
      "province": "江苏省",
      "name": "淮安市",
      "id": "320800"
    },
    {
      "province": "江苏省",
      "name": "盐城市",
      "id": "320900"
    },
    {
      "province": "江苏省",
      "name": "扬州市",
      "id": "321000"
    },
    {
      "province": "江苏省",
      "name": "镇江市",
      "id": "321100"
    },
    {
      "province": "江苏省",
      "name": "泰州市",
      "id": "321200"
    },
    {
      "province": "江苏省",
      "name": "宿迁市",
      "id": "321300"
    }
  ],
  "330000": [
    {
      "province": "浙江省",
      "name": "杭州市",
      "id": "330100"
    },
    {
      "province": "浙江省",
      "name": "宁波市",
      "id": "330200"
    },
    {
      "province": "浙江省",
      "name": "温州市",
      "id": "330300"
    },
    {
      "province": "浙江省",
      "name": "嘉兴市",
      "id": "330400"
    },
    {
      "province": "浙江省",
      "name": "湖州市",
      "id": "330500"
    },
    {
      "province": "浙江省",
      "name": "绍兴市",
      "id": "330600"
    },
    {
      "province": "浙江省",
      "name": "金华市",
      "id": "330700"
    },
    {
      "province": "浙江省",
      "name": "衢州市",
      "id": "330800"
    },
    {
      "province": "浙江省",
      "name": "舟山市",
      "id": "330900"
    },
    {
      "province": "浙江省",
      "name": "台州市",
      "id": "331000"
    },
    {
      "province": "浙江省",
      "name": "丽水市",
      "id": "331100"
    }
  ],
  "340000": [
    {
      "province": "安徽省",
      "name": "合肥市",
      "id": "340100"
    },
    {
      "province": "安徽省",
      "name": "芜湖市",
      "id": "340200"
    },
    {
      "province": "安徽省",
      "name": "蚌埠市",
      "id": "340300"
    },
    {
      "province": "安徽省",
      "name": "淮南市",
      "id": "340400"
    },
    {
      "province": "安徽省",
      "name": "马鞍山市",
      "id": "340500"
    },
    {
      "province": "安徽省",
      "name": "淮北市",
      "id": "340600"
    },
    {
      "province": "安徽省",
      "name": "铜陵市",
      "id": "340700"
    },
    {
      "province": "安徽省",
      "name": "安庆市",
      "id": "340800"
    },
    {
      "province": "安徽省",
      "name": "黄山市",
      "id": "341000"
    },
    {
      "province": "安徽省",
      "name": "滁州市",
      "id": "341100"
    },
    {
      "province": "安徽省",
      "name": "阜阳市",
      "id": "341200"
    },
    {
      "province": "安徽省",
      "name": "宿州市",
      "id": "341300"
    },
    {
      "province": "安徽省",
      "name": "六安市",
      "id": "341500"
    },
    {
      "province": "安徽省",
      "name": "亳州市",
      "id": "341600"
    },
    {
      "province": "安徽省",
      "name": "池州市",
      "id": "341700"
    },
    {
      "province": "安徽省",
      "name": "宣城市",
      "id": "341800"
    }
  ],
  "350000": [
    {
      "province": "福建省",
      "name": "福州市",
      "id": "350100"
    },
    {
      "province": "福建省",
      "name": "厦门市",
      "id": "350200"
    },
    {
      "province": "福建省",
      "name": "莆田市",
      "id": "350300"
    },
    {
      "province": "福建省",
      "name": "三明市",
      "id": "350400"
    },
    {
      "province": "福建省",
      "name": "泉州市",
      "id": "350500"
    },
    {
      "province": "福建省",
      "name": "漳州市",
      "id": "350600"
    },
    {
      "province": "福建省",
      "name": "南平市",
      "id": "350700"
    },
    {
      "province": "福建省",
      "name": "龙岩市",
      "id": "350800"
    },
    {
      "province": "福建省",
      "name": "宁德市",
      "id": "350900"
    }
  ],
  "360000": [
    {
      "province": "江西省",
      "name": "南昌市",
      "id": "360100"
    },
    {
      "province": "江西省",
      "name": "景德镇市",
      "id": "360200"
    },
    {
      "province": "江西省",
      "name": "萍乡市",
      "id": "360300"
    },
    {
      "province": "江西省",
      "name": "九江市",
      "id": "360400"
    },
    {
      "province": "江西省",
      "name": "新余市",
      "id": "360500"
    },
    {
      "province": "江西省",
      "name": "鹰潭市",
      "id": "360600"
    },
    {
      "province": "江西省",
      "name": "赣州市",
      "id": "360700"
    },
    {
      "province": "江西省",
      "name": "吉安市",
      "id": "360800"
    },
    {
      "province": "江西省",
      "name": "宜春市",
      "id": "360900"
    },
    {
      "province": "江西省",
      "name": "抚州市",
      "id": "361000"
    },
    {
      "province": "江西省",
      "name": "上饶市",
      "id": "361100"
    }
  ],
  "370000": [
    {
      "province": "山东省",
      "name": "济南市",
      "id": "370100"
    },
    {
      "province": "山东省",
      "name": "青岛市",
      "id": "370200"
    },
    {
      "province": "山东省",
      "name": "淄博市",
      "id": "370300"
    },
    {
      "province": "山东省",
      "name": "枣庄市",
      "id": "370400"
    },
    {
      "province": "山东省",
      "name": "东营市",
      "id": "370500"
    },
    {
      "province": "山东省",
      "name": "烟台市",
      "id": "370600"
    },
    {
      "province": "山东省",
      "name": "潍坊市",
      "id": "370700"
    },
    {
      "province": "山东省",
      "name": "济宁市",
      "id": "370800"
    },
    {
      "province": "山东省",
      "name": "泰安市",
      "id": "370900"
    },
    {
      "province": "山东省",
      "name": "威海市",
      "id": "371000"
    },
    {
      "province": "山东省",
      "name": "日照市",
      "id": "371100"
    },
    {
      "province": "山东省",
      "name": "莱芜市",
      "id": "371200"
    },
    {
      "province": "山东省",
      "name": "临沂市",
      "id": "371300"
    },
    {
      "province": "山东省",
      "name": "德州市",
      "id": "371400"
    },
    {
      "province": "山东省",
      "name": "聊城市",
      "id": "371500"
    },
    {
      "province": "山东省",
      "name": "滨州市",
      "id": "371600"
    },
    {
      "province": "山东省",
      "name": "菏泽市",
      "id": "371700"
    }
  ],
  "410000": [
    {
      "province": "河南省",
      "name": "郑州市",
      "id": "410100"
    },
    {
      "province": "河南省",
      "name": "开封市",
      "id": "410200"
    },
    {
      "province": "河南省",
      "name": "洛阳市",
      "id": "410300"
    },
    {
      "province": "河南省",
      "name": "平顶山市",
      "id": "410400"
    },
    {
      "province": "河南省",
      "name": "安阳市",
      "id": "410500"
    },
    {
      "province": "河南省",
      "name": "鹤壁市",
      "id": "410600"
    },
    {
      "province": "河南省",
      "name": "新乡市",
      "id": "410700"
    },
    {
      "province": "河南省",
      "name": "焦作市",
      "id": "410800"
    },
    {
      "province": "河南省",
      "name": "濮阳市",
      "id": "410900"
    },
    {
      "province": "河南省",
      "name": "许昌市",
      "id": "411000"
    },
    {
      "province": "河南省",
      "name": "漯河市",
      "id": "411100"
    },
    {
      "province": "河南省",
      "name": "三门峡市",
      "id": "411200"
    },
    {
      "province": "河南省",
      "name": "南阳市",
      "id": "411300"
    },
    {
      "province": "河南省",
      "name": "商丘市",
      "id": "411400"
    },
    {
      "province": "河南省",
      "name": "信阳市",
      "id": "411500"
    },
    {
      "province": "河南省",
      "name": "周口市",
      "id": "411600"
    },
    {
      "province": "河南省",
      "name": "驻马店市",
      "id": "411700"
    },
    {
      "province": "河南省",
      "name": "省直辖县级行政区划",
      "id": "419000"
    }
  ],
  "420000": [
    {
      "province": "湖北省",
      "name": "武汉市",
      "id": "420100"
    },
    {
      "province": "湖北省",
      "name": "黄石市",
      "id": "420200"
    },
    {
      "province": "湖北省",
      "name": "十堰市",
      "id": "420300"
    },
    {
      "province": "湖北省",
      "name": "宜昌市",
      "id": "420500"
    },
    {
      "province": "湖北省",
      "name": "襄阳市",
      "id": "420600"
    },
    {
      "province": "湖北省",
      "name": "鄂州市",
      "id": "420700"
    },
    {
      "province": "湖北省",
      "name": "荆门市",
      "id": "420800"
    },
    {
      "province": "湖北省",
      "name": "孝感市",
      "id": "420900"
    },
    {
      "province": "湖北省",
      "name": "荆州市",
      "id": "421000"
    },
    {
      "province": "湖北省",
      "name": "黄冈市",
      "id": "421100"
    },
    {
      "province": "湖北省",
      "name": "咸宁市",
      "id": "421200"
    },
    {
      "province": "湖北省",
      "name": "随州市",
      "id": "421300"
    },
    {
      "province": "湖北省",
      "name": "恩施土家族苗族自治州",
      "id": "422800"
    },
    {
      "province": "湖北省",
      "name": "省直辖县级行政区划",
      "id": "429000"
    }
  ],
  "430000": [
    {
      "province": "湖南省",
      "name": "长沙市",
      "id": "430100"
    },
    {
      "province": "湖南省",
      "name": "株洲市",
      "id": "430200"
    },
    {
      "province": "湖南省",
      "name": "湘潭市",
      "id": "430300"
    },
    {
      "province": "湖南省",
      "name": "衡阳市",
      "id": "430400"
    },
    {
      "province": "湖南省",
      "name": "邵阳市",
      "id": "430500"
    },
    {
      "province": "湖南省",
      "name": "岳阳市",
      "id": "430600"
    },
    {
      "province": "湖南省",
      "name": "常德市",
      "id": "430700"
    },
    {
      "province": "湖南省",
      "name": "张家界市",
      "id": "430800"
    },
    {
      "province": "湖南省",
      "name": "益阳市",
      "id": "430900"
    },
    {
      "province": "湖南省",
      "name": "郴州市",
      "id": "431000"
    },
    {
      "province": "湖南省",
      "name": "永州市",
      "id": "431100"
    },
    {
      "province": "湖南省",
      "name": "怀化市",
      "id": "431200"
    },
    {
      "province": "湖南省",
      "name": "娄底市",
      "id": "431300"
    },
    {
      "province": "湖南省",
      "name": "湘西土家族苗族自治州",
      "id": "433100"
    }
  ],
  "440000": [
    {
      "province": "广东省",
      "name": "广州市",
      "id": "440100"
    },
    {
      "province": "广东省",
      "name": "韶关市",
      "id": "440200"
    },
    {
      "province": "广东省",
      "name": "深圳市",
      "id": "440300"
    },
    {
      "province": "广东省",
      "name": "珠海市",
      "id": "440400"
    },
    {
      "province": "广东省",
      "name": "汕头市",
      "id": "440500"
    },
    {
      "province": "广东省",
      "name": "佛山市",
      "id": "440600"
    },
    {
      "province": "广东省",
      "name": "江门市",
      "id": "440700"
    },
    {
      "province": "广东省",
      "name": "湛江市",
      "id": "440800"
    },
    {
      "province": "广东省",
      "name": "茂名市",
      "id": "440900"
    },
    {
      "province": "广东省",
      "name": "肇庆市",
      "id": "441200"
    },
    {
      "province": "广东省",
      "name": "惠州市",
      "id": "441300"
    },
    {
      "province": "广东省",
      "name": "梅州市",
      "id": "441400"
    },
    {
      "province": "广东省",
      "name": "汕尾市",
      "id": "441500"
    },
    {
      "province": "广东省",
      "name": "河源市",
      "id": "441600"
    },
    {
      "province": "广东省",
      "name": "阳江市",
      "id": "441700"
    },
    {
      "province": "广东省",
      "name": "清远市",
      "id": "441800"
    },
    {
      "province": "广东省",
      "name": "东莞市",
      "id": "441900"
    },
    {
      "province": "广东省",
      "name": "中山市",
      "id": "442000"
    },
    {
      "province": "广东省",
      "name": "潮州市",
      "id": "445100"
    },
    {
      "province": "广东省",
      "name": "揭阳市",
      "id": "445200"
    },
    {
      "province": "广东省",
      "name": "云浮市",
      "id": "445300"
    }
  ],
  "450000": [
    {
      "province": "广西壮族自治区",
      "name": "南宁市",
      "id": "450100"
    },
    {
      "province": "广西壮族自治区",
      "name": "柳州市",
      "id": "450200"
    },
    {
      "province": "广西壮族自治区",
      "name": "桂林市",
      "id": "450300"
    },
    {
      "province": "广西壮族自治区",
      "name": "梧州市",
      "id": "450400"
    },
    {
      "province": "广西壮族自治区",
      "name": "北海市",
      "id": "450500"
    },
    {
      "province": "广西壮族自治区",
      "name": "防城港市",
      "id": "450600"
    },
    {
      "province": "广西壮族自治区",
      "name": "钦州市",
      "id": "450700"
    },
    {
      "province": "广西壮族自治区",
      "name": "贵港市",
      "id": "450800"
    },
    {
      "province": "广西壮族自治区",
      "name": "玉林市",
      "id": "450900"
    },
    {
      "province": "广西壮族自治区",
      "name": "百色市",
      "id": "451000"
    },
    {
      "province": "广西壮族自治区",
      "name": "贺州市",
      "id": "451100"
    },
    {
      "province": "广西壮族自治区",
      "name": "河池市",
      "id": "451200"
    },
    {
      "province": "广西壮族自治区",
      "name": "来宾市",
      "id": "451300"
    },
    {
      "province": "广西壮族自治区",
      "name": "崇左市",
      "id": "451400"
    }
  ],
  "460000": [
    {
      "province": "海南省",
      "name": "海口市",
      "id": "460100"
    },
    {
      "province": "海南省",
      "name": "三亚市",
      "id": "460200"
    },
    {
      "province": "海南省",
      "name": "三沙市",
      "id": "460300"
    },
    {
      "province": "海南省",
      "name": "儋州市",
      "id": "460400"
    },
    {
      "province": "海南省",
      "name": "省直辖县级行政区划",
      "id": "469000"
    }
  ],
  "500000": [
    {
      "province": "重庆市",
      "name": "市辖区",
      "id": "500100"
    },
    {
      "province": "重庆市",
      "name": "县",
      "id": "500200"
    }
  ],
  "510000": [
    {
      "province": "四川省",
      "name": "成都市",
      "id": "510100"
    },
    {
      "province": "四川省",
      "name": "自贡市",
      "id": "510300"
    },
    {
      "province": "四川省",
      "name": "攀枝花市",
      "id": "510400"
    },
    {
      "province": "四川省",
      "name": "泸州市",
      "id": "510500"
    },
    {
      "province": "四川省",
      "name": "德阳市",
      "id": "510600"
    },
    {
      "province": "四川省",
      "name": "绵阳市",
      "id": "510700"
    },
    {
      "province": "四川省",
      "name": "广元市",
      "id": "510800"
    },
    {
      "province": "四川省",
      "name": "遂宁市",
      "id": "510900"
    },
    {
      "province": "四川省",
      "name": "内江市",
      "id": "511000"
    },
    {
      "province": "四川省",
      "name": "乐山市",
      "id": "511100"
    },
    {
      "province": "四川省",
      "name": "南充市",
      "id": "511300"
    },
    {
      "province": "四川省",
      "name": "眉山市",
      "id": "511400"
    },
    {
      "province": "四川省",
      "name": "宜宾市",
      "id": "511500"
    },
    {
      "province": "四川省",
      "name": "广安市",
      "id": "511600"
    },
    {
      "province": "四川省",
      "name": "达州市",
      "id": "511700"
    },
    {
      "province": "四川省",
      "name": "雅安市",
      "id": "511800"
    },
    {
      "province": "四川省",
      "name": "巴中市",
      "id": "511900"
    },
    {
      "province": "四川省",
      "name": "资阳市",
      "id": "512000"
    },
    {
      "province": "四川省",
      "name": "阿坝藏族羌族自治州",
      "id": "513200"
    },
    {
      "province": "四川省",
      "name": "甘孜藏族自治州",
      "id": "513300"
    },
    {
      "province": "四川省",
      "name": "凉山彝族自治州",
      "id": "513400"
    }
  ],
  "520000": [
    {
      "province": "贵州省",
      "name": "贵阳市",
      "id": "520100"
    },
    {
      "province": "贵州省",
      "name": "六盘水市",
      "id": "520200"
    },
    {
      "province": "贵州省",
      "name": "遵义市",
      "id": "520300"
    },
    {
      "province": "贵州省",
      "name": "安顺市",
      "id": "520400"
    },
    {
      "province": "贵州省",
      "name": "毕节市",
      "id": "520500"
    },
    {
      "province": "贵州省",
      "name": "铜仁市",
      "id": "520600"
    },
    {
      "province": "贵州省",
      "name": "黔西南布依族苗族自治州",
      "id": "522300"
    },
    {
      "province": "贵州省",
      "name": "黔东南苗族侗族自治州",
      "id": "522600"
    },
    {
      "province": "贵州省",
      "name": "黔南布依族苗族自治州",
      "id": "522700"
    }
  ],
  "530000": [
    {
      "province": "云南省",
      "name": "昆明市",
      "id": "530100"
    },
    {
      "province": "云南省",
      "name": "曲靖市",
      "id": "530300"
    },
    {
      "province": "云南省",
      "name": "玉溪市",
      "id": "530400"
    },
    {
      "province": "云南省",
      "name": "保山市",
      "id": "530500"
    },
    {
      "province": "云南省",
      "name": "昭通市",
      "id": "530600"
    },
    {
      "province": "云南省",
      "name": "丽江市",
      "id": "530700"
    },
    {
      "province": "云南省",
      "name": "普洱市",
      "id": "530800"
    },
    {
      "province": "云南省",
      "name": "临沧市",
      "id": "530900"
    },
    {
      "province": "云南省",
      "name": "楚雄彝族自治州",
      "id": "532300"
    },
    {
      "province": "云南省",
      "name": "红河哈尼族彝族自治州",
      "id": "532500"
    },
    {
      "province": "云南省",
      "name": "文山壮族苗族自治州",
      "id": "532600"
    },
    {
      "province": "云南省",
      "name": "西双版纳傣族自治州",
      "id": "532800"
    },
    {
      "province": "云南省",
      "name": "大理白族自治州",
      "id": "532900"
    },
    {
      "province": "云南省",
      "name": "德宏傣族景颇族自治州",
      "id": "533100"
    },
    {
      "province": "云南省",
      "name": "怒江傈僳族自治州",
      "id": "533300"
    },
    {
      "province": "云南省",
      "name": "迪庆藏族自治州",
      "id": "533400"
    }
  ],
  "540000": [
    {
      "province": "西藏自治区",
      "name": "拉萨市",
      "id": "540100"
    },
    {
      "province": "西藏自治区",
      "name": "日喀则市",
      "id": "540200"
    },
    {
      "province": "西藏自治区",
      "name": "昌都市",
      "id": "540300"
    },
    {
      "province": "西藏自治区",
      "name": "林芝市",
      "id": "540400"
    },
    {
      "province": "西藏自治区",
      "name": "山南市",
      "id": "540500"
    },
    {
      "province": "西藏自治区",
      "name": "那曲地区",
      "id": "542400"
    },
    {
      "province": "西藏自治区",
      "name": "阿里地区",
      "id": "542500"
    }
  ],
  "610000": [
    {
      "province": "陕西省",
      "name": "西安市",
      "id": "610100"
    },
    {
      "province": "陕西省",
      "name": "铜川市",
      "id": "610200"
    },
    {
      "province": "陕西省",
      "name": "宝鸡市",
      "id": "610300"
    },
    {
      "province": "陕西省",
      "name": "咸阳市",
      "id": "610400"
    },
    {
      "province": "陕西省",
      "name": "渭南市",
      "id": "610500"
    },
    {
      "province": "陕西省",
      "name": "延安市",
      "id": "610600"
    },
    {
      "province": "陕西省",
      "name": "汉中市",
      "id": "610700"
    },
    {
      "province": "陕西省",
      "name": "榆林市",
      "id": "610800"
    },
    {
      "province": "陕西省",
      "name": "安康市",
      "id": "610900"
    },
    {
      "province": "陕西省",
      "name": "商洛市",
      "id": "611000"
    }
  ],
  "620000": [
    {
      "province": "甘肃省",
      "name": "兰州市",
      "id": "620100"
    },
    {
      "province": "甘肃省",
      "name": "嘉峪关市",
      "id": "620200"
    },
    {
      "province": "甘肃省",
      "name": "金昌市",
      "id": "620300"
    },
    {
      "province": "甘肃省",
      "name": "白银市",
      "id": "620400"
    },
    {
      "province": "甘肃省",
      "name": "天水市",
      "id": "620500"
    },
    {
      "province": "甘肃省",
      "name": "武威市",
      "id": "620600"
    },
    {
      "province": "甘肃省",
      "name": "张掖市",
      "id": "620700"
    },
    {
      "province": "甘肃省",
      "name": "平凉市",
      "id": "620800"
    },
    {
      "province": "甘肃省",
      "name": "酒泉市",
      "id": "620900"
    },
    {
      "province": "甘肃省",
      "name": "庆阳市",
      "id": "621000"
    },
    {
      "province": "甘肃省",
      "name": "定西市",
      "id": "621100"
    },
    {
      "province": "甘肃省",
      "name": "陇南市",
      "id": "621200"
    },
    {
      "province": "甘肃省",
      "name": "临夏回族自治州",
      "id": "622900"
    },
    {
      "province": "甘肃省",
      "name": "甘南藏族自治州",
      "id": "623000"
    }
  ],
  "630000": [
    {
      "province": "青海省",
      "name": "西宁市",
      "id": "630100"
    },
    {
      "province": "青海省",
      "name": "海东市",
      "id": "630200"
    },
    {
      "province": "青海省",
      "name": "海北藏族自治州",
      "id": "632200"
    },
    {
      "province": "青海省",
      "name": "黄南藏族自治州",
      "id": "632300"
    },
    {
      "province": "青海省",
      "name": "海南藏族自治州",
      "id": "632500"
    },
    {
      "province": "青海省",
      "name": "果洛藏族自治州",
      "id": "632600"
    },
    {
      "province": "青海省",
      "name": "玉树藏族自治州",
      "id": "632700"
    },
    {
      "province": "青海省",
      "name": "海西蒙古族藏族自治州",
      "id": "632800"
    }
  ],
  "640000": [
    {
      "province": "宁夏回族自治区",
      "name": "银川市",
      "id": "640100"
    },
    {
      "province": "宁夏回族自治区",
      "name": "石嘴山市",
      "id": "640200"
    },
    {
      "province": "宁夏回族自治区",
      "name": "吴忠市",
      "id": "640300"
    },
    {
      "province": "宁夏回族自治区",
      "name": "固原市",
      "id": "640400"
    },
    {
      "province": "宁夏回族自治区",
      "name": "中卫市",
      "id": "640500"
    }
  ],
  "650000": [
    {
      "province": "新疆维吾尔自治区",
      "name": "乌鲁木齐市",
      "id": "650100"
    },
    {
      "province": "新疆维吾尔自治区",
      "name": "克拉玛依市",
      "id": "650200"
    },
    {
      "province": "新疆维吾尔自治区",
      "name": "吐鲁番市",
      "id": "650400"
    },
    {
      "province": "新疆维吾尔自治区",
      "name": "哈密市",
      "id": "650500"
    },
    {
      "province": "新疆维吾尔自治区",
      "name": "昌吉回族自治州",
      "id": "652300"
    },
    {
      "province": "新疆维吾尔自治区",
      "name": "博尔塔拉蒙古自治州",
      "id": "652700"
    },
    {
      "province": "新疆维吾尔自治区",
      "name": "巴音郭楞蒙古自治州",
      "id": "652800"
    },
    {
      "province": "新疆维吾尔自治区",
      "name": "阿克苏地区",
      "id": "652900"
    },
    {
      "province": "新疆维吾尔自治区",
      "name": "克孜勒苏柯尔克孜自治州",
      "id": "653000"
    },
    {
      "province": "新疆维吾尔自治区",
      "name": "喀什地区",
      "id": "653100"
    },
    {
      "province": "新疆维吾尔自治区",
      "name": "和田地区",
      "id": "653200"
    },
    {
      "province": "新疆维吾尔自治区",
      "name": "伊犁哈萨克自治州",
      "id": "654000"
    },
    {
      "province": "新疆维吾尔自治区",
      "name": "塔城地区",
      "id": "654200"
    },
    {
      "province": "新疆维吾尔自治区",
      "name": "阿勒泰地区",
      "id": "654300"
    },
    {
      "province": "新疆维吾尔自治区",
      "name": "自治区直辖县级行政区划",
      "id": "659000"
    }
  ]
}


================================================
FILE: mock/geographic/province.json
================================================
[
  {
    "name": "北京市",
    "id": "110000"
  },
  {
    "name": "天津市",
    "id": "120000"
  },
  {
    "name": "河北省",
    "id": "130000"
  },
  {
    "name": "山西省",
    "id": "140000"
  },
  {
    "name": "内蒙古自治区",
    "id": "150000"
  },
  {
    "name": "辽宁省",
    "id": "210000"
  },
  {
    "name": "吉林省",
    "id": "220000"
  },
  {
    "name": "黑龙江省",
    "id": "230000"
  },
  {
    "name": "上海市",
    "id": "310000"
  },
  {
    "name": "江苏省",
    "id": "320000"
  },
  {
    "name": "浙江省",
    "id": "330000"
  },
  {
    "name": "安徽省",
    "id": "340000"
  },
  {
    "name": "福建省",
    "id": "350000"
  },
  {
    "name": "江西省",
    "id": "360000"
  },
  {
    "name": "山东省",
    "id": "370000"
  },
  {
    "name": "河南省",
    "id": "410000"
  },
  {
    "name": "湖北省",
    "id": "420000"
  },
  {
    "name": "湖南省",
    "id": "430000"
  },
  {
    "name": "广东省",
    "id": "440000"
  },
  {
    "name": "广西壮族自治区",
    "id": "450000"
  },
  {
    "name": "海南省",
    "id": "460000"
  },
  {
    "name": "重庆市",
    "id": "500000"
  },
  {
    "name": "四川省",
    "id": "510000"
  },
  {
    "name": "贵州省",
    "id": "520000"
  },
  {
    "name": "云南省",
    "id": "530000"
  },
  {
    "name": "西藏自治区",
    "id": "540000"
  },
  {
    "name": "陕西省",
    "id": "610000"
  },
  {
    "name": "甘肃省",
    "id": "620000"
  },
  {
    "name": "青海省",
    "id": "630000"
  },
  {
    "name": "宁夏回族自治区",
    "id": "640000"
  },
  {
    "name": "新疆维吾尔自治区",
    "id": "650000"
  },
  {
    "name": "台湾省",
    "id": "710000"
  },
  {
    "name": "香港特别行政区",
    "id": "810000"
  },
  {
    "name": "澳门特别行政区",
    "id": "820000"
  }
]


================================================
FILE: mock/geographic.js
================================================
import city from './geographic/city.json';
import province from './geographic/province.json';

function getProvince(req, res) {
  return res.json(province);
}

function getCity(req, res) {
  return res.json(city[req.params.province]);
}

export default {
  'GET /api/geographic/province': getProvince,
  'GET /api/geographic/city/:province': getCity,
};


================================================
FILE: mock/notices.js
================================================
const getNotices = (req, res) =>
  res.json([
    {
      id: '000000001',
      avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png',
      title: '你收到了 14 份新周报',
      datetime: '2017-08-09',
      type: 'notification',
    },
    {
      id: '000000002',
      avatar: 'https://gw.alipayobjects.com/zos/rmsportal/OKJXDXrmkNshAMvwtvhu.png',
      title: '你推荐的 曲妮妮 已通过第三轮面试',
      datetime: '2017-08-08',
      type: 'notification',
    },
    {
      id: '000000003',
      avatar: 'https://gw.alipayobjects.com/zos/rmsportal/kISTdvpyTAhtGxpovNWd.png',
      title: '这种模板可以区分多种通知类型',
      datetime: '2017-08-07',
      read: true,
      type: 'notification',
    },
    {
      id: '000000004',
      avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png',
      title: '左侧图标用于区分不同的类型',
      datetime: '2017-08-07',
      type: 'notification',
    },
    {
      id: '000000005',
      avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png',
      title: '内容不要超过两行字,超出时自动截断',
      datetime: '2017-08-07',
      type: 'notification',
    },
    {
      id: '000000006',
      avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg',
      title: '曲丽丽 评论了你',
      description: '描述信息描述信息描述信息',
      datetime: '2017-08-07',
      type: 'message',
    },
    {
      id: '000000007',
      avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg',
      title: '朱偏右 回复了你',
      description: '这种模板用于提醒谁与你发生了互动,左侧放『谁』的头像',
      datetime: '2017-08-07',
      type: 'message',
    },
    {
      id: '000000008',
      avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg',
      title: '标题',
      description: '这种模板用于提醒谁与你发生了互动,左侧放『谁』的头像',
      datetime: '2017-08-07',
      type: 'message',
    },
    {
      id: '000000009',
      title: '任务名称',
      description: '任务需要在 2017-01-12 20:00 前启动',
      extra: '未开始',
      status: 'todo',
      type: 'event',
    },
    {
      id: '000000010',
      title: '第三方紧急代码变更',
      description: '冠霖提交于 2017-01-06,需在 2017-01-07 前完成代码变更任务',
      extra: '马上到期',
      status: 'urgent',
      type: 'event',
    },
    {
      id: '000000011',
      title: '信息安全考试',
      description: '指派竹尔于 2017-01-09 前完成更新并发布',
      extra: '已耗时 8 天',
      status: 'doing',
      type: 'event',
    },
    {
      id: '000000012',
      title: 'ABCD 版本发布',
      description: '冠霖提交于 2017-01-06,需在 2017-01-07 前完成代码变更任务',
      extra: '进行中',
      status: 'processing',
      type: 'event',
    },
  ]);

export default {
  'GET /api/notices': getNotices,
};


================================================
FILE: mock/profile.js
================================================
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: '-',
  },
];

const getProfileBasicData = {
  basicGoods,
  basicProgress,
};

const getProfileAdvancedData = {
  advancedOperation1,
  advancedOperation2,
  advancedOperation3,
};

export default {
  'GET /api/profile/advanced': getProfileAdvancedData,
  'GET /api/profile/basic': getProfileBasicData,
};


================================================
FILE: mock/rule.js
================================================
import { parse } from 'url';

// mock tableListDataSource
let tableListDataSource = [];
for (let i = 0; i < 46; i += 1) {
  tableListDataSource.push({
    key: i,
    disabled: i % 6 === 0,
    href: 'https://ant.design',
    avatar: [
      'https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png',
      'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png',
    ][i % 2],
    name: `TradeCode ${i}`,
    title: `一个任务名称 ${i}`,
    owner: '曲丽丽',
    desc: '这是一段描述',
    callNo: Math.floor(Math.random() * 1000),
    status: Math.floor(Math.random() * 10) % 4,
    updatedAt: new Date(`2017-07-${Math.floor(i / 2) + 1}`),
    createdAt: new Date(`2017-07-${Math.floor(i / 2) + 1}`),
    progress: Math.ceil(Math.random() * 100),
  });
}

function getRule(req, res, u) {
  let url = u;
  if (!url || Object.prototype.toString.call(url) !== '[object String]') {
    url = req.url; // eslint-disable-line
  }

  const params = parse(url, true).query;

  let dataSource = tableListDataSource;

  if (params.sorter) {
    const s = params.sorter.split('_');
    dataSource = dataSource.sort((prev, next) => {
      if (s[1] === 'descend') {
        return next[s[0]] - prev[s[0]];
      }
      return prev[s[0]] - next[s[0]];
    });
  }

  if (params.status) {
    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.name) {
    dataSource = dataSource.filter(data => data.name.indexOf(params.name) > -1);
  }

  let pageSize = 10;
  if (params.pageSize) {
    pageSize = params.pageSize * 1;
  }

  const result = {
    list: dataSource,
    pagination: {
      total: dataSource.length,
      pageSize,
      current: parseInt(params.currentPage, 10) || 1,
    },
  };

  return res.json(result);
}

function postRule(req, res, u, b) {
  let url = u;
  if (!url || Object.prototype.toString.call(url) !== '[object String]') {
    url = req.url; // eslint-disable-line
  }

  const body = (b && b.body) || req.body;
  const { method, name, desc, key } = body;

  switch (method) {
    /* eslint no-case-declarations:0 */
    case 'delete':
      tableListDataSource = tableListDataSource.filter(item => key.indexOf(item.key) === -1);
      break;
    case 'post':
      const i = Math.ceil(Math.random() * 10000);
      tableListDataSource.unshift({
        key: i,
        href: 'https://ant.design',
        avatar: [
          'https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png',
          'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png',
        ][i % 2],
        name: `TradeCode ${i}`,
        title: `一个任务名称 ${i}`,
        owner: '曲丽丽',
        desc,
        callNo: Math.floor(Math.random() * 1000),
        status: Math.floor(Math.random() * 10) % 2,
        updatedAt: new Date(),
        createdAt: new Date(),
        progress: Math.ceil(Math.random() * 100),
      });
      break;
    case 'update':
      tableListDataSource = tableListDataSource.map(item => {
        if (item.key === key) {
          Object.assign(item, { desc, name });
          return item;
        }
        return item;
      });
      break;
    default:
      break;
  }

  const result = {
    list: tableListDataSource,
    pagination: {
      total: tableListDataSource.length,
    },
  };

  return res.json(result);
}

export default {
  'GET /api/rule': getRule,
  'POST /api/rule': postRule,
};


================================================
FILE: mock/user.js
================================================
// 代码中会兼容本地 service mock 以及部署站点的静态数据
export default {
  // 支持值为 Object 和 Array
  'GET /api/currentUser': {
    name: 'BiaoChenXuying',
    // avatar: 'https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png',
    avatar: 'http://p61te2jup.bkt.clouddn.com/WechatIMG8.jpeg',
    userid: '00000001',
    email: 'antdesign@alipay.com',
    signature: '海纳百川,有容乃大',
    title: '交互专家',
    group: 'BiaoChenXuying',
    tags: [
      {
        key: '0',
        label: '很有想法的',
      },
      {
        key: '1',
        label: '专注设计',
      },
      {
        key: '2',
        label: '辣~',
      },
      {
        key: '3',
        label: '大长腿',
      },
      {
        key: '4',
        label: '川妹子',
      },
      {
        key: '5',
        label: '海纳百川',
      },
    ],
    notifyCount: 12,
    country: 'China',
    geographic: {
      province: {
        label: '浙江省',
        key: '330000',
      },
      city: {
        label: '杭州市',
        key: '330100',
      },
    },
    address: '西湖区工专路 77 号',
    phone: '0752-268888888',
  },
  // 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',
    },
  ],
  '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/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',
    });
  },
};


================================================
FILE: package.json
================================================
{
  "name": "ant-design-pro",
  "version": "2.0.0",
  "description": "An out-of-box UI solution for enterprise applications",
  "private": true,
  "scripts": {
    "precommit": "npm run lint-staged",
    "presite": "node ./scripts/generateMock.js && cd functions && npm install",
    "start": "cross-env APP_TYPE=site umi dev",
    "start:no-mock": "cross-env MOCK=none umi dev",
    "build": "umi build",
    "site": "npm run presite && cross-env APP_TYPE=site npm run build && firebase deploy",
    "analyze": "cross-env ANALYZE=1 umi 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": "umi test",
    "test:component": "umi test ./src/components",
    "test:all": "node ./tests/run-tests.js",
    "prettier": "prettier --write ./src/**/**/**/*",
    "docker:dev": "docker-compose -f ./docker/docker-compose.dev.yml up",
    "docker:build": "docker-compose -f ./docker/docker-compose.dev.yml build",
    "docker-prod:dev": "docker-compose -f ./docker/docker-compose.yml up",
    "docker-prod:build": "docker-compose -f ./docker/docker-compose.yml build"
  },
  "dependencies": {
    "@antv/data-set": "^0.9.6",
    "@babel/runtime": "^7.0.0",
    "antd": "^3.11.6",
    "bizcharts": "^3.2.2",
    "bizcharts-plugin-slider": "^2.0.3",
    "classnames": "^2.2.6",
    "dva": "^2.4.0",
    "enquire-js": "^0.2.1",
    "hash.js": "^1.1.5",
    "highlight.js": "^9.13.1",
    "lodash": "^4.17.10",
    "lodash-decorators": "^6.0.0",
    "marked": "^0.5.2",
    "memoize-one": "^4.0.0",
    "moment": "^2.22.2",
    "numeral": "^2.0.6",
    "nzh": "^1.0.3",
    "omit.js": "^1.0.0",
    "path-to-regexp": "^2.4.0",
    "prop-types": "^15.5.10",
    "qs": "^6.5.2",
    "rc-animate": "^2.4.4",
    "react": "^16.5.1",
    "react-container-query": "^0.11.0",
    "react-copy-to-clipboard": "^5.0.1",
    "react-document-title": "^2.0.3",
    "react-dom": "^16.5.1",
    "react-fittext": "^1.0.0",
    "react-router-dom": "^4.3.1",
    "save": "^2.3.2",
    "simplemde": "^1.11.2"
  },
  "devDependencies": {
    "@types/react": "^16.4.11",
    "@types/react-dom": "^16.0.6",
    "antd-pro-merge-less": "^0.0.9",
    "antd-pro-theme-webpack-plugin": "^1.1.8",
    "babel-eslint": "^9.0.0",
    "babel-plugin-transform-decorators-legacy": "^1.3.5",
    "cross-env": "^5.1.1",
    "cross-port-killer": "^1.0.1",
    "enzyme": "^3.4.4",
    "eslint": "^5.4.0",
    "eslint-config-airbnb": "^17.0.0",
    "eslint-config-prettier": "^3.0.1",
    "eslint-plugin-babel": "^5.1.0",
    "eslint-plugin-compat": "^2.5.1",
    "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.11.1",
    "gh-pages": "^2.0.0",
    "husky": "^0.14.3",
    "lint-staged": "^7.2.0",
    "merge-umi-mock-data": "^0.0.3",
    "mockjs": "^1.0.1-beta3",
    "prettier": "1.14.2",
    "pro-download": "^1.0.1",
    "stylelint": "^9.4.0",
    "stylelint-config-prettier": "^4.0.0",
    "stylelint-config-standard": "^18.0.0",
    "umi": "^2.1.1",
    "umi-plugin-ga": "^1.0.3",
    "umi-plugin-react": "^1.1.1"
  },
  "optionalDependencies": {
    "puppeteer": "^1.6.0"
  },
  "lint-staged": {
    "**/*.{js,jsx,less}": [
      "prettier --write",
      "git add"
    ],
    "**/*.{js,jsx}": "npm run lint-staged:js",
    "**/*.less": "stylelint --syntax less"
  },
  "engines": {
    "node": ">=8.0.0"
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not ie <= 10"
  ]
}


================================================
FILE: scripts/generateMock.js
================================================
const generateMock = require('merge-umi-mock-data');
const path = require('path');
generateMock(path.join(__dirname, '../mock'), path.join(__dirname, '../functions/mock/index.js'));


================================================
FILE: src/components/Authorized/Authorized.js
================================================
import CheckPermissions from './CheckPermissions';

const Authorized = ({ children, authority, noMatch = null }) => {
  const childrenRender = typeof children === 'undefined' ? null : children;
  return CheckPermissions(authority, childrenRender, noMatch);
};

export default Authorized;


================================================
FILE: src/components/Authorized/AuthorizedRoute.js
================================================
import React from 'react';
import { Route, Redirect } from 'react-router-dom';
import Authorized from './Authorized';

// TODO: umi只会返回render和rest
const AuthorizedRoute = ({ component: Component, render, authority, redirectPath, ...rest }) => (
  <Authorized
    authority={authority}
    noMatch={<Route {...rest} render={() => <Redirect to={{ pathname: redirectPath }} />} />}
  >
    <Route {...rest} render={props => (Component ? <Component {...props} /> : render(props))} />
  </Authorized>
);

export default AuthorizedRoute;


================================================
FILE: src/components/Authorized/CheckPermissions.js
================================================
import React from 'react';
import PromiseRender from './PromiseRender';
import { CURRENT } from './renderAuthorize';

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;
    }
    if (Array.isArray(currentAuthority)) {
      for (let i = 0; i < currentAuthority.length; i += 1) {
        const element = currentAuthority[i];
        if (authority.indexOf(element) >= 0) {
          return target;
        }
      }
    }
    return Exception;
  }

  // string 处理
  if (typeof authority === 'string') {
    if (authority === currentAuthority) {
      return target;
    }
    if (Array.isArray(currentAuthority)) {
      for (let i = 0; i < currentAuthority.length; i += 1) {
        const element = currentAuthority[i];
        if (authority.indexOf(element) >= 0) {
          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);
      // 函数执行后返回值是 Promise
      if (isPromise(bool)) {
        return <PromiseRender ok={target} error={Exception} promise={bool} />;
      }
      if (bool) {
        return target;
      }
      return Exception;
    } catch (error) {
      throw error;
    }
  }
  throw new Error('unsupported parameters');
};

export { checkPermissions };

const check = (authority, target, Exception) =>
  checkPermissions(authority, CURRENT, target, Exception);

export default check;


================================================
FILE: src/components/Authorized/CheckPermissions.test.js
================================================
import { checkPermissions } from './CheckPermissions';

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');
  });
  it('authority is string, currentAuthority is array, return ok', () => {
    expect(checkPermissions('user', ['user'], target, error)).toEqual('ok');
  });
  it('authority is string, currentAuthority is array, return ok', () => {
    expect(checkPermissions('user', ['user', 'admin'], target, error)).toEqual('ok');
  });
  it('authority is array, currentAuthority is array, return ok', () => {
    expect(checkPermissions(['user', 'admin'], ['user', 'admin'], target, error)).toEqual('ok');
  });
  it('Wrong Function permission authentication', () => {
    expect(checkPermissions(() => false, ['user'], target, error)).toEqual('error');
  });
  it('Correct Function permission authentication', () => {
    expect(checkPermissions(() => true, ['user'], target, error)).toEqual('ok');
  });
  it('authority is undefined , return ok', () => {
    expect(checkPermissions(null, ['user'], target, error)).toEqual('ok');
  });
});


================================================
FILE: src/components/Authorized/PromiseRender.js
================================================
import React from 'react';
import { Spin } from 'antd';

export default class PromiseRender extends React.PureComponent {
  state = {
    component: null,
  };

  componentDidMount() {
    this.setRenderComponent(this.props);
  }

  componentDidUpdate(nextProps) {
    // new Props enter
    this.setRenderComponent(nextProps);
  }

  // set render Component : ok or error
  setRenderComponent(props) {
    const ok = this.checkIsInstantiation(props.ok);
    const error = this.checkIsInstantiation(props.error);
    props.promise
      .then(() => {
        this.setState({
          component: ok,
        });
      })
      .catch(() => {
        this.setState({
          component: error,
        });
      });
  }

  // Determine whether the incoming component has been instantiated
  // AuthorizedRoute is already instantiated
  // Authorized  render is already instantiated, children is no instantiated
  // Secured is not instantiated
  checkIsInstantiation = target => {
    if (!React.isValidElement(target)) {
      return target;
    }
    return () => target;
  };

  render() {
    const { component: Component } = this.state;
    const { ok, error, promise, ...rest } = this.props;
    return Component ? (
      <Component {...rest} />
    ) : (
      <div
        style={{
          width: '100%',
          height: '100%',
          margin: 'auto',
          paddingTop: 50,
          textAlign: 'center',
        }}
      >
        <Spin size="large" />
      </div>
    );
  }
}


================================================
FILE: src/components/Authorized/Secured.js
================================================
import React from 'react';
import Exception from '../Exception';
import CheckPermissions from './CheckPermissions';
/**
 * 默认不能访问任何页面
 * default is "NULL"
 */
const Exception403 = () => <Exception type="403" />;

// Determine whether the incoming component has been instantiated
// AuthorizedRoute is already instantiated
// Authorized  render is already instantiated, children is no instantiated
// Secured is not instantiated
const checkIsInstantiation = target => {
  if (!React.isValidElement(target)) {
    return target;
  }
  return () => target;
};

/**
 * 用于判断是否拥有权限访问此view权限
 * authority 支持传入 string, function:()=>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, function: () => 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(target) {
    const component = CheckPermissions(authority, target, classError || Exception403);
    return checkIsInstantiation(component);
  };
};

export default authorize;


================================================
FILE: src/components/Authorized/demo/AuthorizedArray.md
================================================
---
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,
);
```


================================================
FILE: src/components/Authorized/demo/AuthorizedFunction.md
================================================
---
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,
);
```


================================================
FILE: src/components/Authorized/demo/basic.md
================================================
---
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,
);
```


================================================
FILE: src/components/Authorized/demo/secured.md
================================================
---
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,
);
```


================================================
FILE: src/components/Authorized/index.d.ts
================================================
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;
}

export 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;


================================================
FILE: src/components/Authorized/index.js
================================================
import Authorized from './Authorized';
import AuthorizedRoute from './AuthorizedRoute';
import Secured from './Secured';
import check from './CheckPermissions';
import renderAuthorize from './renderAuthorize';

Authorized.Secured = Secured;
Authorized.AuthorizedRoute = AuthorizedRoute;
Authorized.check = check;

export default renderAuthorize(Authorized);


================================================
FILE: src/components/Authorized/index.md
================================================
---
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 | Promise` | - |
| noMatch     | 权限异常渲染元素,权限判断不通过时展示        | ReactNode  | - |

### Authorized.AuthorizedRoute

| 参数      | 说明                                      | 类型         | 默认值 |
|----------|------------------------------------------|-------------|-------|
| authority     | 准入权限/权限判断         | `string | array | Promise | (currentAuthority) => boolean | Promise` | - |
| redirectPath  | 权限异常时重定向的页面路由                | string  | - |

其余参数与 `Route` 相同。

### Authorized.Secured

注解方式,`@Authorized.Secured(authority, error)`

| 参数      | 说明                                      | 类型         | 默认值 |
|----------|------------------------------------------|-------------|-------|
| authority     | 准入权限/权限判断         | `string | Promise | (currentAuthority) => boolean | Promise` | - |
| error  | 权限异常时渲染元素                |  ReactNode | <Exception type="403" /> |

### Authorized.check

函数形式的 Authorized,用于某些不能被 HOC 包裹的组件。 `Authorized.check(authority, target, Exception)`
注意:传入一个 Promise 时,无论正确还是错误返回的都是一个 ReactClass。

| 参数      | 说明                                      | 类型         | 默认值 |
|----------|------------------------------------------|-------------|-------|
| authority     | 准入权限/权限判断         | `string | Promise | (currentAuthority) => boolean | Promise` | - |
| target     | 权限判断通过时渲染的元素         | ReactNode | - |
| Exception  | 权限异常时渲染元素                |  ReactNode | - |


================================================
FILE: src/components/Authorized/renderAuthorize.js
================================================
/* eslint-disable import/no-mutable-exports */
let CURRENT = 'NULL';
/**
 * use  authority or getAuthority
 * @param {string|()=>String} currentAuthority
 */
const renderAuthorize = Authorized => currentAuthority => {
  if (currentAuthority) {
    if (typeof currentAuthority === 'function') {
      CURRENT = currentAuthority();
    }
    if (
      Object.prototype.toString.call(currentAuthority) === '[object String]' ||
      Array.isArray(currentAuthority)
    ) {
      CURRENT = currentAuthority;
    }
  } else {
    CURRENT = 'NULL';
  }
  return Authorized;
};

export { CURRENT };
export default Authorized => renderAuthorize(Authorized);


================================================
FILE: src/components/Charts/Bar/index.d.ts
================================================
import * as React from 'react';
export interface IBarProps {
  title: React.ReactNode;
  color?: string;
  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<IBarProps, any> {}


================================================
FILE: src/components/Charts/Bar/index.js
================================================
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, { passive: true });
  }

  componentWillUnmount() {
    window.removeEventListener('resize', this.resize);
  }

  handleRoot = n => {
    this.root = n;
  };

  handleRef = n => {
    this.node = n;
  };

  @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,
      });
    }
  }

  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;


================================================
FILE: src/components/Charts/ChartCard/index.d.ts
================================================
import * as React from 'react';
import { CardProps } from 'antd/lib/card';

export interface IChartCardProps extends CardProps {
  title: React.ReactNode;
  action?: React.ReactNode;
  total?: React.ReactNode | number | (() => React.ReactNode | number);
  footer?: React.ReactNode;
  contentHeight?: number;
  avatar?: React.ReactNode;
  style?: React.CSSProperties;
}

export default class ChartCard extends React.Component<IChartCardProps, any> {}


================================================
FILE: src/components/Charts/ChartCard/index.js
================================================
import React from 'react';
import { Card } from 'antd';
import classNames from 'classnames';

import styles from './index.less';

const renderTotal = total => {
  let totalDom;
  switch (typeof total) {
    case 'undefined':
      totalDom = null;
      break;
    case 'function':
      totalDom = <div className={styles.total}>{total()}</div>;
      break;
    default:
      totalDom = <div className={styles.total}>{total}</div>;
  }
  return totalDom;
};

class ChartCard extends React.PureComponent {
  renderConnet = () => {
    const { contentHeight, title, avatar, action, total, footer, children, loading } = this.props;
    if (loading) {
      return false;
    }
    return (
      <div className={styles.chartCard}>
        <div
          className={classNames(styles.chartTop, {
            [styles.chartTopMargin]: !children && !footer,
          })}
        >
          <div className={styles.avatar}>{avatar}</div>
          <div className={styles.metaWrap}>
            <div className={styles.meta}>
              <span className={styles.title}>{title}</span>
              <span className={styles.action}>{action}</span>
            </div>
            {renderTotal(total)}
          </div>
        </div>
        {children && (
          <div className={styles.content} style={{ height: contentHeight || 'auto' }}>
            <div className={contentHeight && styles.contentFixed}>{children}</div>
          </div>
        )}
        {footer && (
          <div
            className={classNames(styles.footer, {
              [styles.footerMargin]: !children,
            })}
          >
            {footer}
          </div>
        )}
      </div>
    );
  };

  render() {
    const {
      loading = false,
      contentHeight,
      title,
      avatar,
      action,
      total,
      footer,
      children,
      ...rest
    } = this.props;
    return (
      <Card loading={loading} bodyStyle={{ padding: '20px 24px 8px 24px' }} {...rest}>
        {this.renderConnet()}
      </Card>
    );
  }
}

export default ChartCard;


================================================
FILE: src/components/Charts/ChartCard/index.less
================================================
@import '~antd/lib/style/themes/default.less';

.chartCard {
  position: relative;
  .chartTop {
    position: relative;
    overflow: hidden;
    width: 100%;
  }
  .chartTopMargin {
    margin-bottom: 12px;
  }
  .chartTopHasMargin {
    margin-bottom: 20px;
  }
  .metaWrap {
    float: left;
  }
  .avatar {
    position: relative;
    top: 4px;
    float: left;
    margin-right: 20px;
    img {
      border-radius: 100%;
    }
  }
  .meta {
    color: @text-color-secondary;
    font-size: @font-size-base;
    line-height: 22px;
    height: 22px;
  }
  .action {
    cursor: pointer;
    position: absolute;
    top: 0;
    right: 0;
  }
  .total {
    overflow: hidden;
    text-overflow: ellipsis;
    word-break: break-all;
    white-space: nowrap;
    color: @heading-color;
    margin-top: 4px;
    margin-bottom: 0;
    font-size: 30px;
    line-height: 38px;
    height: 38px;
  }
  .content {
    margin-bottom: 12px;
    position: relative;
    width: 100%;
  }
  .contentFixed {
    position: absolute;
    left: 0;
    bottom: 0;
    width: 100%;
  }
  .footer {
    border-top: 1px solid @border-color-split;
    padding-top: 9px;
    margin-top: 8px;
    & > * {
      position: relative;
    }
  }
  .footerMargin {
    margin-top: 20px;
  }
}


================================================
FILE: src/components/Charts/Field/index.d.ts
================================================
import * as React from 'react';
export interface IFieldProps {
  label: React.ReactNode;
  value: React.ReactNode;
  style?: React.CSSProperties;
}

export default class Field extends React.Component<IFieldProps, any> {}


================================================
FILE: src/components/Charts/Field/index.js
================================================
import React from 'react';

import styles from './index.less';

const Field = ({ label, value, ...rest }) => (
  <div className={styles.field} {...rest}>
    <span>{label}</span>
    <span>{value}</span>
  </div>
);

export default Field;


================================================
FILE: src/components/Charts/Field/index.less
================================================
@import '~antd/lib/style/themes/default.less';

.field {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  margin: 0;
  span {
    font-size: @font-size-base;
    line-height: 22px;
  }
  span:last-child {
    margin-left: 8px;
    color: @heading-color;
  }
}


================================================
FILE: src/components/Charts/Gauge/index.d.ts
================================================
import * as React from 'react';
export interface IGaugeProps {
  title: React.ReactNode;
  color?: string;
  height: number;
  bgColor?: number;
  percent: number;
  style?: React.CSSProperties;
}

export default class Gauge extends React.Component<IGaugeProps, any> {}


================================================
FILE: src/components/Charts/Gauge/index.js
================================================
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()
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={() => `
                <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>
    );
  }
}

export default Gauge;


================================================
FILE: src/components/Charts/MiniArea/index.d.ts
================================================
import * as React from 'react';

// g2已经更新到3.0
// 不带的写了

export interface IAxis {
  title: any;
  line: any;
  gridAlign: any;
  labels: any;
  tickLine: any;
  grid: any;
}

export interface IMiniAreaProps {
  color?: string;
  height: number;
  borderColor?: string;
  line?: boolean;
  animate?: boolean;
  xAxis?: IAxis;
  yAxis?: IAxis;
  data: Array<{
    x: number | string;
    y: number;
  }>;
}

export default class MiniArea extends React.Component<IMiniAreaProps, any> {}


================================================
FILE: src/components/Charts/MiniArea/index.js
================================================
import React from 'react';
import { Chart, Axis, Tooltip, Geom } from 'bizcharts';
import autoHeight from '../autoHeight';
import styles from '../index.less';

@autoHeight()
class MiniArea extends React.PureComponent {
  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>
    );
  }
}

export default MiniArea;


================================================
FILE: src/components/Charts/MiniBar/index.d.ts
================================================
import * as React from 'react';
export interface IMiniBarProps {
  color?: string;
  height: number;
  data: Array<{
    x: number | string;
    y: number;
  }>;
  style?: React.CSSProperties;
}

export default class MiniBar extends React.Component<IMiniBarProps, any> {}


================================================
FILE: src/components/Charts/MiniBar/index.js
================================================
import React from 'react';
import { Chart, Tooltip, Geom } from 'bizcharts';
import autoHeight from '../autoHeight';
import styles from '../index.less';

@autoHeight()
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>
    );
  }
}
export default MiniBar;


================================================
FILE: src/components/Charts/MiniProgress/index.d.ts
================================================
import * as React from 'react';
export interface IMiniProgressProps {
  target: number;
  color?: string;
  strokeWidth?: number;
  percent?: number;
  style?: React.CSSProperties;
}

export default class MiniProgress extends React.Component<IMiniProgressProps, any> {}


================================================
FILE: src/components/Charts/MiniProgress/index.js
================================================
import React from 'react';
import { Tooltip } from 'antd';

import styles from './index.less';

const MiniProgress = ({ target, color = 'rgb(19, 194, 194)', strokeWidth, percent }) => (
  <div className={styles.miniProgress}>
    <Tooltip title={`目标值: ${target}%`}>
      <div className={styles.target} style={{ left: target ? `${target}%` : null }}>
        <span style={{ backgroundColor: color || null }} />
        <span style={{ backgroundColor: color || null }} />
      </div>
    </Tooltip>
    <div className={styles.progressWrap}>
      <div
        className={styles.progress}
        style={{
          backgroundColor: color || null,
          width: percent ? `${percent}%` : null,
          height: strokeWidth || null,
        }}
      />
    </div>
  </div>
);

export default MiniProgress;


================================================
FILE: src/components/Charts/MiniProgress/index.less
================================================
@import '~antd/lib/style/themes/default.less';

.miniProgress {
  padding: 5px 0;
  position: relative;
  width: 100%;
  .progressWrap {
    background-color: @background-color-base;
    position: relative;
  }
  .progress {
    transition: all 0.4s cubic-bezier(0.08, 0.82, 0.17, 1) 0s;
    border-radius: 1px 0 0 1px;
    background-color: @primary-color;
    width: 0;
    height: 100%;
  }
  .target {
    position: absolute;
    top: 0;
    bottom: 0;
    span {
      border-radius: 100px;
      position: absolute;
      top: 0;
      left: 0;
      height: 4px;
      width: 2px;
    }
    span:last-child {
      top: auto;
      bottom: 0;
    }
  }
}


================================================
FILE: src/components/Charts/Pie/index.d.ts
================================================
import * as React from 'react';
export interface IPieProps {
  animate?: boolean;
  color?: string;
  colors?: string[];
  height: number;
  hasLegend?: boolean;
  padding?: [number, number, number, number];
  percent?: number;
  data?: Array<{
    x: string | string;
    y: number;
  }>;
  total?: React.ReactNode | number | (() => React.ReactNode | number);
  title?: React.ReactNode;
  tooltip?: boolean;
  valueFormat?: (value: string) => string | React.ReactNode;
  subTitle?: React.ReactNode;
}

export default class Pie extends React.Component<IPieProps, any> {}


================================================
FILE: src/components/Charts/Pie/index.js
================================================
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()
class Pie extends Component {
  state = {
    legendData: [],
    legendBlock: false,
  };

  componentDidMount() {
    window.addEventListener(
      'resize',
      () => {
        this.requestRef = requestAnimationFrame(() => this.resize());
      },
      { passive: true }
    );
  }

  componentDidUpdate(preProps) {
    const { data } = this.props;
    if (data !== preProps.data) {
      // because of charts data create when rendered
      // so there is a trick for get rendered time
      this.getLegendData();
    }
  }

  componentWillUnmount() {
    window.cancelAnimationFrame(this.requestRef);
    window.removeEventListener('resize', this.resize);
    this.resize.cancel();
  }

  getG2Instance = chart => {
    this.chart = chart;
    requestAnimationFrame(() => {
      this.getLegendData();
      this.resize();
    });
  };

  // for custom lengend view
  getLegendData = () => {
    if (!this.chart) return;
    const geom = this.chart.getAllGeoms()[0]; // 获取所有的图形
    if (!geom) return;
    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,
    });
  };

  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,
    });
  };

  // for window resize auto responsive legend
  @Bind()
  @Debounce(300)
  resize() {
    const { hasLegend } = this.props;
    const { legendBlock } = this.state;
    if (!hasLegend || !this.root) {
      window.removeEventListener('resize', this.resize);
      return;
    }
    if (this.root.parentNode.clientWidth <= 380) {
      if (!legendBlock) {
        this.setState({
          legendBlock: true,
        });
      }
    } else if (legendBlock) {
      this.setState({
        legendBlock: false,
      });
    }
  }

  render() {
    const {
      valueFormat,
      subTitle,
      total,
      hasLegend = false,
      className,
      style,
      height,
      forceFit = true,
      percent,
      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 {
      data: propsData,
      selected: propsSelected = true,
      tooltip: propsTooltip = true,
    } = this.props;

    let data = propsData || [];
    let selected = propsSelected;
    let tooltip = propsTooltip;

    const defaultColors = colors;
    data = data || [];
    selected = selected || true;
    tooltip = tooltip || true;
    let formatColor;

    const scale = {
      x: {
        type: 'cat',
        range: [0, 1],
      },
      y: {
        min: 0,
      },
    };

    if (percent || percent === 0) {
      selected = false;
      tooltip = false;
      formatColor = value => {
        if (value === '占比') {
          return color || 'rgba(24, 144, 255, 0.85)';
        }
        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 || percent === 0 ? 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">{typeof total === 'function' ? total() : total}</div>
                )}
              </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}>
                  {`${(Number.isNaN(item.percent) ? 0 : item.percent * 100).toFixed(2)}%`}
                </span>
                <span className={styles.value}>{valueFormat ? valueFormat(item.y) : item.y}</span>
              </li>
            ))}
          </ul>
        )}
      </div>
    );
  }
}

export default Pie;


================================================
FILE: src/components/Charts/Pie/index.less
================================================
@import '~antd/lib/style/themes/default.less';

.pie {
  position: relative;
  .chart {
    position: relative;
  }
  &.hasLegend .chart {
    width: ~'calc(100% - 240px)';
  }
  .legend {
    position: absolute;
    right: 0;
    min-width: 200px;
    top: 50%;
    transform: translateY(-50%);
    margin: 0 20px;
    list-style: none;
    padding: 0;
    li {
      cursor: pointer;
      margin-bottom: 16px;
      height: 22px;
      line-height: 22px;
      &:last-child {
        margin-bottom: 0;
      }
    }
  }
  .dot {
    border-radius: 8px;
    display: inline-block;
    margin-right: 8px;
    position: relative;
    top: -1px;
    height: 8px;
    width: 8px;
  }
  .line {
    background-color: @border-color-split;
    display: inline-block;
    margin-right: 8px;
    width: 1px;
    height: 16px;
  }
  .legendTitle {
    color: @text-color;
  }
  .percent {
    color: @text-color-secondary;
  }
  .value {
    position: absolute;
    right: 0;
  }
  .title {
    margin-bottom: 8px;
  }
  .total {
    position: absolute;
    left: 50%;
    top: 50%;
    text-align: center;
    max-height: 62px;
    transform: translate(-50%, -50%);
    & > h4 {
      color: @text-color-secondary;
      font-size: 14px;
      line-height: 22px;
      height: 22px;
      margin-bottom: 8px;
      font-weight: normal;
    }
    & > p {
      color: @heading-color;
      display: block;
      font-size: 1.2em;
      height: 32px;
      line-height: 32px;
      white-space: nowrap;
    }
  }
}

.legendBlock {
  &.hasLegend .chart {
    width: 100%;
    margin: 0 0 32px 0;
  }
  .legend {
    position: relative;
    transform: none;
  }
}


================================================
FILE: src/components/Charts/Radar/index.d.ts
================================================
import * as React from 'react';
export interface IRadarProps {
  title?: React.ReactNode;
  height: 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<IRadarProps, any> {}


================================================
FILE: src/components/Charts/Radar/index.js
================================================
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()
class Radar extends Component {
  state = {
    legendData: [],
  };

  componentDidMount() {
    this.getLegendData();
  }

  componentDidUpdate(preProps) {
    const { data } = this.props;
    if (data !== preProps.data) {
      this.getLegendData();
    }
  }

  getG2Instance = chart => {
    this.chart = chart;
  };

  // for custom lengend view
  getLegendData = () => {
    if (!this.chart) return;
    const geom = this.chart.getAllGeoms()[0]; // 获取所有的图形
    if (!geom) return;
    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 }}>
        {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>
    );
  }
}

export default Radar;


================================================
FILE: src/components/Charts/Radar/index.less
================================================
@import '~antd/lib/style/themes/default.less';

.radar {
  .legend {
    margin-top: 16px;
    .legendItem {
      position: relative;
      text-align: center;
      cursor: pointer;
      color: @text-color-secondary;
      line-height: 22px;
      p {
        margin: 0;
      }
      h6 {
        color: @heading-color;
        padding-left: 16px;
        font-size: 24px;
        line-height: 32px;
        margin-top: 4px;
        margin-bottom: 0;
      }
      &:after {
        background-color: @border-color-split;
        position: absolute;
        top: 8px;
        right: 0;
        height: 40px;
        width: 1px;
        content: '';
      }
    }
    > :last-child .legendItem:after {
      display: none;
    }
    .dot {
      border-radius: 6px;
      display: inline-block;
      margin-right: 6px;
      position: relative;
      top: -1px;
      height: 6px;
      width: 6px;
    }
  }
}


================================================
FILE: src/components/Charts/TagCloud/index.d.ts
================================================
import * as React from 'react';
export interface ITagCloudProps {
  data: Array<{
    name: string;
    value: number;
  }>;
  height: number;
  style?: React.CSSProperties;
}

export default class TagCloud extends React.Component<ITagCloudProps, any> {}


================================================
FILE: src/components/Charts/TagCloud/index.js
================================================
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() {
    requestAnimationFrame(() => {
      this.initTagCloud();
      this.renderChart();
    });
    window.addEventListener('resize', this.resize, { passive: true });
  }

  componentDidUpdate(preProps) {
    const { data } = this.props;
    if (JSON.stringify(preProps.data) !== JSON.stringify(data)) {
      this.renderChart(this.props);
    }
  }

  componentWillUnmount() {
    this.isUnmount = true;
    window.cancelAnimationFrame(this.requestRef);
    window.removeEventListener('resize', this.resize);
  }

  resize = () => {
    this.requestRef = requestAnimationFrame(() => {
      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;


================================================
FILE: src/components/Charts/TagCloud/index.less
================================================
.tagCloud {
  overflow: hidden;
  canvas {
    transform: scale(0.25);
    transform-origin: 0 0;
  }
}


================================================
FILE: src/components/Charts/TimelineChart/index.d.ts
================================================
import * as React from 'react';
export interface ITimelineChartProps {
  data: Array<{
    x: number;
    y1: number;
    y2?: number;
  }>;
  titleMap: { y1: string; y2?: string };
  padding?: [number, number, number, number];
  height?: number;
  style?: React.CSSProperties;
}

export default class TimelineChart extends React.Component<ITimelineChartProps, any> {}


================================================
FILE: src/components/Charts/TimelineChart/index.js
================================================
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()
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',
      tickInterval: 60 * 60 * 1000,
      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>
    );
  }
}

export default TimelineChart;


================================================
FILE: src/components/Charts/TimelineChart/index.less
================================================
.timelineChart {
  background: #fff;
}


================================================
FILE: src/components/Charts/WaterWave/index.d.ts
================================================
import * as React from 'react';
export interface IWaterWaveProps {
  title: React.ReactNode;
  color?: string;
  height: number;
  percent: number;
  style?: React.CSSProperties;
}

export default class WaterWave extends React.Component<IWaterWaveProps, any> {}


================================================
FILE: src/components/Charts/WaterWave/index.js
================================================
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

@autoHeight()
class WaterWave extends PureComponent {
  state = {
    radio: 1,
  };

  componentDidMount() {
    this.renderChart();
    this.resize();
    window.addEventListener(
      'resize',
      () => {
        requestAnimationFrame(() => this.resize());
      },
      { passive: true }
    );
  }

  componentDidUpdate(props) {
    const { percent } = this.props;
    if (props.percent !== percent) {
      // 不加这个会造成绘制缓慢
      this.renderChart('update');
    }
  }

  componentWillUnmount() {
    cancelAnimationFrame(this.timer);
    if (this.node) {
      this.node.innerHTML = '';
    }
    window.removeEventListener('resize', this.resize);
  }

  resize = () => {
    if (this.root) {
      const { height } = this.props;
      const { offsetWidth } = this.root.parentNode;
      this.setState({
        radio: offsetWidth < height ? offsetWidth / height : 1,
      });
    }
  };

  renderChart(type) {
    const { percent, color = '#1890FF' } = this.props;
    const data = percent / 100;
    const self = this;
    cancelAnimationFrame(this.timer);

    if (!this.node || (data !== 0 && !data)) {
      return;
    }

    const canvas = this.node;
    const ctx = canvas.getContext('2d');
    const canvasWidth = canvas.width;
    const canvasHeight = canvas.height;
    const radius = canvasWidth / 2;
    const lineWidth = 2;
    const cR = radius - lineWidth;

    ctx.beginPath();
    ctx.lineWidth = lineWidth * 2;

    const axisLength = canvasWidth - lineWidth;
    const unit = axisLength / 8;
    const range = 0.2; // 振幅
    let currRange = range;
    const xOffset = lineWidth;
    let sp = 0; // 周期偏移量
    let currData = 0;
    const waveupsp = 0.005; // 水波上涨速度

    let arcStack = [];
    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)]);
    }

    const cStartPoint = arcStack.shift();
    ctx.strokeStyle = color;
    ctx.moveTo(cStartPoint[0], cStartPoint[1]);

    function drawSin() {
      ctx.beginPath();
      ctx.save();

      const sinStack = [];
      for (let i = xOffset; i <= xOffset + axisLength; i += 20 / axisLength) {
        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;

        ctx.lineTo(dx, dy);
        sinStack.push([dx, dy]);
      }

      const startPoint = sinStack.shift();

      ctx.lineTo(xOffset + axisLength, canvasHeight);
      ctx.lineTo(xOffset, canvasHeight);
      ctx.lineTo(startPoint[0], startPoint[1]);

      const gradient = ctx.createLinearGradient(0, 0, 0, canvasHeight);
      gradient.addColorStop(0, '#ffffff');
      gradient.addColorStop(1, color);
      ctx.fillStyle = gradient;
      ctx.fill();
      ctx.restore();
    }

    function render() {
      ctx.clearRect(0, 0, canvasWidth, canvasHeight);
      if (circleLock && type !== 'update') {
        if (arcStack.length) {
          const temp = arcStack.shift();
          ctx.lineTo(temp[0], temp[1]);
          ctx.stroke();
        } else {
          circleLock = false;
          ctx.lineTo(cStartPoint[0], cStartPoint[1]);
          ctx.stroke();
          arcStack = null;

          ctx.globalCompositeOperation = 'destination-over';
          ctx.beginPath();
          ctx.lineWidth = lineWidth;
          ctx.arc(radius, radius, bR, 0, 2 * Math.PI, 1);

          ctx.beginPath();
          ctx.save();
          ctx.arc(radius, radius, radius - 3 * lineWidth, 0, 2 * Math.PI, 1);

          ctx.restore();
          ctx.clip();
          ctx.fillStyle = color;
        }
      } else {
        if (data >= 0.85) {
          if (currRange > range / 4) {
            const t = range * 0.01;
            currRange -= t;
          }
        } else if (data <= 0.1) {
          if (currRange < range * 1.5) {
            const t = range * 0.01;
            currRange += t;
          }
        } else {
          if (currRange <= range) {
            const t = range * 0.01;
            currRange += t;
          }
          if (currRange >= range) {
            const t = range * 0.01;
            currRange -= t;
          }
        }
        if (data - currData > 0) {
          currData += waveupsp;
        }
        if (data - currData < 0) {
          currData -= waveupsp;
        }

        sp += 0.07;
        drawSin();
      }
      self.timer = requestAnimationFrame(render);
    }
    render();
  }

  render() {
    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 style={{ width: height, height, overflow: 'hidden' }}>
          <canvas
            className={styles.waterWaveCanvasWrapper}
            ref={n => (this.node = n)}
            width={height * 2}
            height={height * 2}
          />
        </div>
        <div className={styles.text} style={{ width: height }}>
          {title && <span>{title}</span>}
          <h4>{percent}%</h4>
        </div>
      </div>
    );
  }
}

export default WaterWave;


================================================
FILE: src/components/Charts/WaterWave/index.less
================================================
@import '~antd/lib/style/themes/default.less';

.waterWave {
  display: inline-block;
  position: relative;
  transform-origin: left;
  .text {
    position: absolute;
    left: 0;
    top: 32px;
    text-align: center;
    width: 100%;
    span {
      color: @text-color-secondary;
      font-size: 14px;
      line-height: 22px;
    }
    h4 {
      color: @heading-color;
      line-height: 32px;
      font-size: 24px;
    }
  }
  .waterWaveCanvasWrapper {
    transform: scale(0.5);
    transform-origin: 0 0;
  }
}


================================================
FILE: src/components/Charts/autoHeight.js
================================================
/* 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 =>
  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;


================================================
FILE: src/components/Charts/bizcharts.d.ts
================================================
import * as BizChart from 'bizcharts';

export = BizChart;


================================================
FILE: src/components/Charts/bizcharts.js
================================================
import * as BizChart from 'bizcharts';

export default BizChart;


================================================
FILE: src/components/Charts/demo/bar.md
================================================
---
order: 4
title: 柱状图
---

通过设置 `x`,`y` 属性,可以快速的构建出一个漂亮的柱状图,各种纬度的关系则是通过自定义的数据展现。

````jsx
import { Bar } from 'ant-design-pro/lib/Charts';

const salesData = [];
for (let i = 0; i < 12; i += 1) {
  salesData.push({
    x: `${i + 1}月`,
    y: Math.floor(Math.random() * 1000) + 200,
  });
}

ReactDOM.render(
  <Bar
    height={200}
    title="销售额趋势"
    data={salesData}
  />
, mountNode);
````


================================================
FILE: src/components/Charts/demo/chart-card.md
================================================
---
order: 1
title: 图表卡片
---

用于展示图表的卡片容器,可以方便的配合其它图表套件展示丰富信息。

```jsx
import { ChartCard, yuan, Field } from 'ant-design-pro/lib/Charts';
import Trend from 'ant-design-pro/lib/Trend';
import { Row, Col, Icon, Tooltip } from 'antd';
import numeral from 'numeral';

ReactDOM.render(
  <Row>
    <Col span={24}>
      <ChartCard
        title="销售额"
        action={
          <Tooltip title="指标说明">
            <Icon type="info-circle-o" />
          </Tooltip>
        }
        total={() => (
          <span dangerouslySetInnerHTML={{ __html: yuan(126560) }} />
        )}
        footer={
          <Field label="日均销售额" value={numeral(12423).format("0,0")} />
        }
        contentHeight={46}
      >
        <span>
          周同比
          <Trend flag="up" style={{ marginLeft: 8, color: "rgba(0,0,0,.85)" }}>
            12%
          </Trend>
        </span>
        <span style={{ marginLeft: 16 }}>
          日环比
          <Trend
            flag="down"
            style={{ marginLeft: 8, color: "rgba(0,0,0,.85)" }}
          >
            11%
          </Trend>
        </span>
      </ChartCard>
    </Col>
    <Col span={24} style={{ marginTop: 24 }}>
      <ChartCard
        title="移动指标"
        avatar={
          <img
            style={{ width: 56, height: 56 }}
            src="https://gw.alipayobjects.com/zos/rmsportal/sfjbOqnsXXJgNCjCzDBL.png"
            alt="indicator"
          />
        }
        action={
          <Tooltip title="指标说明">
            <Icon type="info-circle-o" />
          </Tooltip>
        }
        total={() => (
          <span dangerouslySetInnerHTML={{ __html: yuan(126560) }} />
        )}
        footer={
          <Field label="日均销售额" value={numeral(12423).format("0,0")} />
        }
      />
    </Col>
    <Col span={24} style={{ marginTop: 24 }}>
      <ChartCard
        title="移动指标"
        avatar={
          <img
            alt="indicator"
            style={{ width: 56, height: 56 }}
            src="https://gw.alipayobjects.com/zos/rmsportal/dURIMkkrRFpPgTuzkwnB.png"
          />
        }
        action={
          <Tooltip title="指标说明">
            <Icon type="info-circle-o" />
          </Tooltip>
        }
        total={() => (
          <span dangerouslySetInnerHTML={{ __html: yuan(126560) }} />
        )}
      />
    </Col>
  </Row>,
  mountNode,
);
```


================================================
FILE: src/components/Charts/demo/gauge.md
================================================
---
order: 7
title: 仪表盘 
---

仪表盘是一种进度展示方式,可以更直观的展示当前的进展情况,通常也可表示占比。

````jsx
import { Gauge } from 'ant-design-pro/lib/Charts';

ReactDOM.render(
  <Gauge
    title="核销率"
    height={164}
    percent={87}
  />
, mountNode);
````


================================================
FILE: src/components/Charts/demo/mini-area.md
================================================
---
order: 2
col: 2
title: 迷你区域图
---

````jsx
import { MiniArea } from 'ant-design-pro/lib/Charts';
import moment from 'moment';

const visitData = [];
const beginDay = new Date().getTime();
for (let i = 0; i < 20; i += 1) {
  visitData.push({
    x: moment(new Date(beginDay + (1000 * 60 * 60 * 24 * i))).format('YYYY-MM-DD'),
    y: Math.floor(Math.random() * 100) + 10,
  });
}

ReactDOM.render(
  <MiniArea
    line
    color="#cceafe"
    height={45}
    data={visitData}
  />
, mountNode);
````


================================================
FILE: src/components/Charts/demo/mini-bar.md
================================================
---
order: 2
col: 2
title: 迷你柱状图
---

迷你柱状图更适合展示简单的区间数据,简洁的表现方式可以很好的减少大数据量的视觉展现压力。

````jsx
import { MiniBar } from 'ant-design-pro/lib/Charts';
import moment from 'moment';

const visitData = [];
const beginDay = new Date().getTime();
for (let i = 0; i < 20; i += 1) {
  visitData.push({
    x: moment(new Date(beginDay + (1000 * 60 * 60 * 24 * i))).format('YYYY-MM-DD'),
    y: Math.floor(Math.random() * 100) + 10,
  });
}

ReactDOM.render(
  <MiniBar
    height={45}
    data={visitData}
  />
, mountNode);
````


================================================
FILE: src/components/Charts/demo/mini-pie.md
================================================
---
order: 6
title: 迷你饼状图
---

通过简化 `Pie` 属性的设置,可以快速的实现极简的饼状图,可配合 `ChartCard` 组合展
现更多业务场景。

```jsx
import { Pie } from 'ant-design-pro/lib/Charts';

ReactDOM.render(
  <Pie percent={28} subTitle="中式快餐" total="28%" height={140} />,
  mountNode
);
```


================================================
FILE: src/components/Charts/demo/mini-progress.md
================================================
---
order: 3
title: 迷你进度条
---

````jsx
import { MiniProgress } from 'ant-design-pro/lib/Charts';

ReactDOM.render(
  <MiniProgress percent={78} strokeWidth={8} target={80} />
, mountNode);
````


================================================
FILE: src/components/Charts/demo/mix.md
================================================
---
order: 0
title: 图表套件组合展示
---

利用 Ant Design Pro 提供的图表套件,可以灵活组合符合设计规范的图表来满足复杂的业务需求。

````jsx
import { ChartCard, Field, MiniArea, MiniBar, MiniProgress } from 'ant-design-pro/lib/Charts';
import Trend from 'ant-design-pro/lib/Trend';
import NumberInfo from 'ant-design-pro/lib/NumberInfo';
import { Row, Col, Icon, Tooltip } from 'antd';
import numeral from 'numeral';
import moment from 'moment';

const visitData = [];
const beginDay = new Date().getTime();
for (let i = 0; i < 20; i += 1) {
  visitData.push({
    x: moment(new Date(beginDay + (1000 * 60 * 60 * 24 * i))).format('YYYY-MM-DD'),
    y: Math.floor(Math.random() * 100) + 10,
  });
}

ReactDOM.render(
  <Row>
    <Col span={24}>
      <ChartCard
        title="搜索用户数量"
        total={numeral(8846).format('0,0')}
        contentHeight={134}
      >
        <NumberInfo
          subTitle={<span>本周访问</span>}
          total={numeral(12321).format('0,0')}
          status="up"
          subTotal={17.1}
        />
        <MiniArea
          line
          height={45}
          data={visitData}
        />
      </ChartCard>
    </Col>
    <Col span={24} style={{ marginTop: 24 }}>
      <ChartCard
        title="访问量"
        action={<Tooltip title="指标说明"><Icon type="info-circle-o" /></Tooltip>}
        total={numeral(8846).format('0,0')}
        footer={<Field label="日访问量" value={numeral(1234).format('0,0')} />}
        contentHeight={46}
      >
        <MiniBar
          height={46}
          data={visitData}
        />
      </ChartCard>
    </Col>
    <Col span={24} style={{ marginTop: 24 }}>
      <ChartCard
        title="线上购物转化率"
        action={<Tooltip title="指标说明"><Icon type="info-circle-o" /></Tooltip>}
        total="78%"
        footer={
          <div>
            <span>
              周同比
              <Trend flag="up" style={{ marginLeft: 8, color: 'rgba(0,0,0,.85)' }}>12%</Trend>
            </span>
            <span style={{ marginLeft: 16 }}>
              日环比
              <Trend flag="down" style={{ marginLeft: 8, color: 'rgba(0,0,0,.85)' }}>11%</Trend>
            </span>
          </div>
        }
        contentHeight={46}
      >
        <MiniProgress percent={78} strokeWidth={8} target={80} />
      </ChartCard>
    </Col>
  </Row>
, mountNode);
````


================================================
FILE: src/components/Charts/demo/pie.md
================================================
---
order: 5
title: 饼状图
---

```jsx
import { Pie, yuan } from 'ant-design-pro/lib/Charts';

const salesPieData = [
  {
    x: '家用电器',
    y: 4544,
  },
  {
    x: '食用酒水',
    y: 3321,
  },
  {
    x: '个护健康',
    y: 3113,
  },
  {
    x: '服饰箱包',
    y: 2341,
  },
  {
    x: '母婴产品',
    y: 1231,
  },
  {
    x: '其他',
    y: 1231,
  },
];

ReactDOM.render(
  <Pie
    hasLegend
    title="销售额"
    subTitle="销售额"
    total={() => (
      <span
        dangerouslySetInnerHTML={{
          __html: yuan(salesPieData.reduce((pre, now) => now.y + pre, 0))
        }}
      />
    )}
    data={salesPieData}
    valueFormat={val => <span dangerouslySetInnerHTML={{ __html: yuan(val) }} />}
    height={294}
  />,
  mountNode,
);
```


================================================
FILE: src/components/Charts/demo/radar.md
================================================
---
order: 7
title: 雷达图
---

````jsx
import { Radar, ChartCard } from 'ant-design-pro/lib/Charts';

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],
      });
    }
  });
});

ReactDOM.render(
  <ChartCard title="数据比例">
    <Radar
      hasLegend
      height={286}
      data={radarData}
    />
  </ChartCard>
, mountNode);
````


================================================
FILE: src/components/Charts/demo/tag-cloud.md
================================================
---
order: 9
title: 标签云
---

标签云是一套相关的标签以及与此相应的权重展示方式,一般典型的标签云有 30 至 150 个标签,而权重影响使用的字体大小或其他视觉效果。

````jsx
import { TagCloud } from 'ant-design-pro/lib/Charts';

const tags = [];
for (let i = 0; i < 50; i += 1) {
  tags.push({
    name: `TagClout-Title-${i}`,
    value: Math.floor((Math.random() * 50)) + 20,
  });
}

ReactDOM.render(
  <TagCloud
    data={tags}
    height={200}
  />
, mountNode);
````


================================================
FILE: src/components/Charts/demo/timeline-chart.md
================================================
---
order: 9
title: 带有时间轴的图表
---

使用 `TimelineChart` 组件可以实现带有时间轴的柱状图展现,而其中的 `x` 属性,则是时间值的指向,默认最多支持同时展现两个指标,分别是 `y1` 和 `y2`。

````jsx
import { TimelineChart } from 'ant-design-pro/lib/Charts';

const chartData = [];
for (let i = 0; i < 20; i += 1) {
  chartData.push({
    x: (new Date().getTime()) + (1000 * 60 * 30 * i),
    y1: Math.floor(Math.random() * 100) + 1000,
    y2: Math.floor(Math.random() * 100) + 10,
  });
}

ReactDOM.render(
  <TimelineChart
    height={200}
    data={chartData}
    titleMap={{ y1: '客流量', y2: '支付笔数' }}
  />
, mountNode);
````


================================================
FILE: src/components/Charts/demo/waterwave.md
================================================
---
order: 8
title: 水波图 
---

水波图是一种比例的展示方式,可以更直观的展示关键值的占比。

````jsx
import { WaterWave } from 'ant-design-pro/lib/Charts';

ReactDOM.render(
  <div style={{ textAlign: 'center' }}>
    <WaterWave
      height={161}
      title="补贴资金剩余"
      percent={34}
    />
  </div>
, mountNode);
````


================================================
FILE: src/components/Charts/g2.js
================================================
// 全局 G2 设置
import { track, setTheme } from 'bizcharts';

track(false);

const config = {
  defaultColor: '#1089ff',
  shape: {
    interval: {
      fillOpacity: 1,
    },
  },
};

setTheme(config);


================================================
FILE: src/components/Charts/index.d.ts
================================================
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 };


================================================
FILE: src/components/Charts/index.js
================================================
import numeral from 'numeral';
import './g2';
import ChartCard from './ChartCard';
import Bar from './Bar';
import Pie from './Pie';
import Radar from './Radar';
import Gauge from './Gauge';
import MiniArea from './MiniArea';
import MiniBar from './MiniBar';
import MiniProgress from './MiniProgress';
import Field from './Field';
import WaterWave from './WaterWave';
import TagCloud from './TagCloud';
import TimelineChart from './TimelineChart';

const yuan = val => `¥ ${numeral(val).format('0,0')}`;

const Charts = {
  yuan,
  Bar,
  Pie,
  Gauge,
  Radar,
  MiniBar,
  MiniArea,
  MiniProgress,
  ChartCard,
  Field,
  WaterWave,
  TagCloud,
  TimelineChart,
};

export {
  Charts as default,
  yuan,
  Bar,
  Pie,
  Gauge,
  Radar,
  MiniBar,
  MiniArea,
  MiniProgress,
  ChartCard,
  Field,
  WaterWave,
  TagCloud,
  TimelineChart,
};


================================================
FILE: src/components/Charts/index.less
================================================
.miniChart {
  position: relative;
  width: 100%;
  .chartContent {
    position: absolute;
    bottom: -28px;
    width: 100%;
    > div {
      margin: 0 -5px;
      overflow: hidden;
    }
  }
  .chartLoading {
    position: absolute;
    top: 16px;
    left: 50%;
    margin-left: -7px;
  }
}


================================================
FILE: src/components/Charts/index.md
================================================
---
title:
  en-US: Charts
  zh-CN: Charts
subtitle: 图表
order: 2
cols: 2
---

Ant Design Pro 提供的业务中常用的图表类型,都是基于 [G2](https://antv.alipay.com/g2/doc/index.html) 按照 Ant Design 图表规范封装,需要注意的是 Ant Design Pro 的图表组件以套件形式提供,可以任意组合实现复杂的业务需求。

因为结合了 Ant Design 的标准设计,本着极简的设计思想以及开箱即用的理念,简化了大量 API 配置,所以如果需要灵活定制图表,可以参考 Ant Design Pro 图表实现,自行基于 [G2](https://antv.alipay.com/g2/doc/index.html) 封装图表组件使用。

## API

### ChartCard

| 参数      | 说明                                      | 类型         | 默认值 |
|----------|------------------------------------------|-------------|-------|
| title | 卡片标题 | ReactNode\|string | - |
| action | 卡片操作 | ReactNode | - |
| total | 数据总量 | ReactNode \| number \| function | - |
| footer | 卡片底部 | ReactNode | - |
| contentHeight | 内容区域高度 | number | - |
| avatar | 右侧图标 | React.ReactNode | - |
### MiniBar

| 参数      | 说明                                      | 类型         | 默认值 |
|----------|------------------------------------------|-------------|-------|
| color | 图表颜色 | string | `#1890FF` |
| height | 图表高度 | number | - |
| data | 数据 | array<{x, y}> | - |

### MiniArea

| 参数      | 说明                                      | 类型         | 默认值 |
|----------|------------------------------------------|-------------|-------|
| color | 图表颜色 | string | `rgba(24, 144, 255, 0.2)` |
| borderColor | 图表边颜色 | string | `#1890FF` |
| height | 图表高度 | number | - |
| line | 是否显示描边 | boolean | false |
| animate | 是否显示动画 | boolean | true |
| xAxis | [x 轴配置](http://antvis.github.io/g2/doc/tutorial/start/axis.html) | object | - |
| yAxis | [y 轴配置](http://antvis.github.io/g2/doc/tutorial/start/axis.html) | object | - |
| data | 数据 | array<{x, y}> | - |

### MiniProgress

| 参数      | 说明                                      | 类型         | 默认值 |
|----------|------------------------------------------|-------------|-------|
| target | 目标比例 | number | - |
| color | 进度条颜色 | string | - |
| strokeWidth | 进度条高度 | number | - |
| percent | 进度比例 | number | - |

### Bar

| 参数      | 说明                                      | 类型         | 默认值 |
|----------|------------------------------------------|-------------|-------|
| title | 图表标题 | ReactNode\|string | - |
| color | 图表颜色 | string | `rgba(24, 144, 255, 0.85)` |
| padding | 图表内部间距 | [array](https://github.com/alibaba/BizCharts/blob/master/doc/api/chart.md#7padding-object--number--array-) | `'auto'` |
| height | 图表高度 | number | - |
| data | 数据 | array<{x, y}> | - |
| autoLabel | 在宽度不足时,自动隐藏 x 轴的 label | boolean | `true` |

### Pie

| 参数      | 说明                                      | 类型         | 默认值 |
|----------|------------------------------------------|-------------|-------|
| animate | 是否显示动画 | boolean | true |
| color | 图表颜色 | string | `rgba(24, 144, 255, 0.85)` |
| height | 图表高度 | number | - |
| hasLegend | 是否显示 legend | boolean | `false` |
| padding | 图表内部间距 | [array](https://github.com/alibaba/BizCharts/blob/master/doc/api/chart.md#7padding-object--number--array-) | `'auto'` |
| percent | 占比 | number | - |
| tooltip | 是否显示 tooltip | boolean | true |
| valueFormat | 显示值的格式化函数 | function | - |
| title | 图表标题 | ReactNode\|string | - |
| subTitle | 图表子标题 | ReactNode\|string | - |
| total | 图标中央的总数 | string | function | - |

### Radar

| 参数      | 说明                                      | 类型         | 默认值 |
|----------|------------------------------------------|-------------|-------|
| title | 图表标题 | ReactNode\|string | - |
| height | 图表高度 | number | - |
| hasLegend | 是否显示 legend | boolean | `false` |
| padding | 图表内部间距 | [array](https://github.com/alibaba/BizCharts/blob/master/doc/api/chart.md#7padding-object--number--array-) | `'auto'` |
| data | 图标数据 | array<{name,label,value}> | - |

### Gauge

| 参数      | 说明                                      | 类型         | 默认值 |
|----------|------------------------------------------|-------------|-------|
| title | 图表标题 | ReactNode\|string | - |
| height | 图表高度 | number | - |
| color | 图表颜色 | string | `#2F9CFF` |
| bgColor | 图表背景颜色 | string | `#F0F2F5` |
| percent | 进度比例 | number | - |

### WaterWave

| 参数      | 说明                                      | 类型         | 默认值 |
|----------|------------------------------------------|-------------|-------|
| title | 图表标题 | ReactNode\|string | - |
| height | 图表高度 | number | - |
| color | 图表颜色 | string | `#1890FF` |
| percent | 进度比例 | number | - |

### TagCloud

| 参数      | 说明                                      | 类型         | 默认值 |
|----------|------------------------------------------|-------------|-------|
| data | 标题 | Array<name, value\> | - |
| height | 高度值 | number | - |

### TimelineChart

| 参数      | 说明                                      | 类型         | 默认值 |
|----------|------------------------------------------|-------------|-------|
| data | 标题 | Array<x, y1, y2\> | - |
| titleMap | 指标别名 | Object{y1: '客流量', y2: '支付笔数'} | - |
| height | 高度值 | number | 400 |

### Field

| 参数      | 说明                                      | 类型         | 默认值 |
|----------|------------------------------------------|-------------|-------|
| label | 标题 | ReactNode\|string | - |
| value | 值 | ReactNode\|string | - |


================================================
FILE: src/components/Exception/demo/403.md
================================================
---
order: 2
title:
  zh-CN: 403
  en-US: 403
---

## zh-CN

403 页面,配合自定义操作。

## en-US

403 page with custom operations.

````jsx
import Exception from 'ant-design-pro/lib/Exception';
import { Button } from 'antd';

const actions = (
  <div>
    <Button type="primary">Home</Button>
    <Button>Detail</Button>
  </div>
);
ReactDOM.render(
  <Exception type="403" actions={actions} />
, mountNode);
````


================================================
FILE: src/components/Exception/demo/404.md
================================================
---
order: 0
title:
  zh-CN: 404
  en-US: 404
---

## zh-CN

404 页面。

## en-US

404 page.

````jsx
import Exception from 'ant-design-pro/lib/Exception';

ReactDOM.render(
  <Exception type="404" />
, mountNode);
````


================================================
FILE: src/components/Exception/demo/500.md
================================================
---
order: 1
title:
  zh-CN: 500
  en-US: 500
---

## zh-CN

500 页面。

## en-US

500 page.

````jsx
import Exception from 'ant-design-pro/lib/Exception';

ReactDOM.render(
  <Exception type="500" />
, mountNode);
````


================================================
FILE: src/components/Exception/index.d.ts
================================================
import * as React from 'react';
export interface IExceptionProps {
  type?: '403' | '404' | '500';
  title?: React.ReactNode;
  desc?: React.ReactNode;
  img?: string;
  actions?: React.ReactNode;
  linkElement?: React.ReactNode;
  style?: React.CSSProperties;
  className?: string;
  backText?: React.ReactNode;
  redirect?: string;
}

export default class Exception extends React.Component<IExceptionProps, any> {}


================================================
FILE: src/components/Exception/index.en-US.md
================================================
---
title: Exception
cols: 1
order: 5
---

Exceptions page is used to provide feedback on specific abnormal state. Usually, it contains an explanation of the error status, and provides users with suggestions or operations, to prevent users from feeling lost and confused.

## API

Property | Description | Type | Default
---------|-------------|------|--------
| backText | default return button text | ReactNode | back to home |
type | type of exception, the corresponding default `title`, `desc`, `img` will be given if set, which can be overridden by explicit setting of `title`, `desc`, `img` | Enum {'403', '404', '500'} | -
title | title | ReactNode | -
desc | supplementary description | ReactNode | -
img | the url of background image | string | -
actions | suggested operations, a default 'Home' link will show if not set | ReactNode | -
linkElement | to specify the element of link | string\|ReactElement | 'a'
redirect | redirect path | string | '/'

================================================
FILE: src/components/Exception/index.js
================================================
import React, { createElement } from 'react';
import classNames from 'classnames';
import { Button } from 'antd';
import config from './typeConfig';
import styles from './index.less';

class Exception extends React.PureComponent {
  static defaultProps = {
    backText: 'back to home',
    redirect: '/',
  };

  constructor(props) {
    super(props);
    this.state = {};
  }

  render() {
    const {
      className,
      backText,
      linkElement = 'a',
      type,
      title,
      desc,
      img,
      actions,
      redirect,
      ...rest
    } = this.props;
    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: redirect,
                  href: redirect,
                },
                <Button type="primary">{backText}</Button>
              )}
          </div>
        </div>
      </div>
    );
  }
}

export default Exception;


================================================
FILE: src/components/Exception/index.less
================================================
@import '~antd/lib/style/themes/default.less';

.exception {
  display: flex;
  align-items: center;
  height: 80%;
  min-height: 500px;

  .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;
    }
  }
}


================================================
FILE: src/components/Exception/index.zh-CN.md
================================================
---
title: Exception
subtitle: 异常
cols: 1
order: 5
---

异常页用于对页面特定的异常状态进行反馈。通常,它包含对错误状态的阐述,并向用户提供建议或操作,避免用户感到迷失和困惑。

## API

| 参数 | 说明| 类型 | 默认值 |
|-------------|------------------------------------------|-------------|-------|
| backText| 默认的返回按钮文本 | ReactNode| back to home |
| type| 页面类型,若配置,则自带对应类型默认的 `title`,`desc`,`img`,此默认设置可以被 `title`,`desc`,`img` 覆盖 | Enum {'403', '404', '500'} | - |
| title | 标题 | ReactNode| -|
| desc| 补充描述| ReactNode| -|
| img | 背景图片地址 | string| -|
| actions | 建议操作,配置此属性时默认的『返回首页』按钮不生效| ReactNode| -|
| linkElement | 定义链接的元素 | string\|ReactElement | 'a' |
| redirect | 返回按钮的跳转地址 | string | '/'


================================================
FILE: src/components/Exception/typeConfig.js
================================================
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;


================================================
FILE: src/components/FooterToolbar/demo/basic.md
================================================
---
order: 0
title:
  zh-CN: 演示
  en-US: demo
iframe: 400
---

## zh-CN

浮动固定页脚。

## en-US

Fixed to the footer.

````jsx
import FooterToolbar from 'ant-design-pro/lib/FooterToolbar';
import { Button } from 'antd';

ReactDOM.render(
  <div style={{ background: '#f7f7f7', padding: 24 }}>
    <p>Content Content Content Content</p>
    <p>Content Content Content Content</p>
    <p>Content Content Content Content</p>
    <p>Content Content Content Content</p>
    <p>Content Content Content Content</p>
    <p>Content Content Content Content</p>
    <p>Content Content Content Content</p>
    <p>Content Content Content Content</p>
    <p>Content Content Content Content</p>
    <p>Content Content Content Content</p>
    <p>Content Content Content Content</p>
    <p>Content Content Content Content</p>
    <p>Content Content Content Content</p>
    <p>Content Content Content Content</p>
    <p>Content Content Content Content</p>
    <FooterToolbar extra="extra information">
      <Button>Cancel</Button>
      <Button type="primary">Submit</Button>
    </FooterToolbar>
  </div>
, mountNode);
````

================================================
FILE: src/components/FooterToolbar/index.d.ts
================================================
import * as React from 'react';
export interface IFooterToolbarProps {
  extra: React.ReactNode;
  style?
Download .txt
gitextract_4hkosi02/

├── .circleci/
│   └── config.yml
├── .dockerignore
├── .editorconfig
├── .eslintignore
├── .eslintrc.js
├── .firebaserc
├── .gitignore
├── .prettierignore
├── .prettierrc
├── .stylelintrc.json
├── CODE_OF_CONDUCT.md
├── Dockerfile
├── Dockerfile.dev
├── LICENSE
├── README.md
├── README.ru-RU.md
├── README.zh-CN.md
├── appveyor.yml
├── config/
│   ├── config.js
│   ├── plugin.config.js
│   └── router.config.js
├── docker/
│   ├── docker-compose.dev.yml
│   ├── docker-compose.yml
│   └── nginx.conf
├── firebase.json
├── functions/
│   ├── index.js
│   ├── matchMock.js
│   └── package.json
├── jest.config.js
├── jsconfig.json
├── mock/
│   ├── api.js
│   ├── blog.js
│   ├── chart.js
│   ├── geographic/
│   │   ├── city.json
│   │   └── province.json
│   ├── geographic.js
│   ├── notices.js
│   ├── profile.js
│   ├── rule.js
│   └── user.js
├── package.json
├── scripts/
│   └── generateMock.js
├── src/
│   ├── components/
│   │   ├── Authorized/
│   │   │   ├── Authorized.js
│   │   │   ├── AuthorizedRoute.js
│   │   │   ├── CheckPermissions.js
│   │   │   ├── CheckPermissions.test.js
│   │   │   ├── PromiseRender.js
│   │   │   ├── Secured.js
│   │   │   ├── demo/
│   │   │   │   ├── AuthorizedArray.md
│   │   │   │   ├── AuthorizedFunction.md
│   │   │   │   ├── basic.md
│   │   │   │   └── secured.md
│   │   │   ├── index.d.ts
│   │   │   ├── index.js
│   │   │   ├── index.md
│   │   │   └── renderAuthorize.js
│   │   ├── Charts/
│   │   │   ├── Bar/
│   │   │   │   ├── index.d.ts
│   │   │   │   └── index.js
│   │   │   ├── ChartCard/
│   │   │   │   ├── index.d.ts
│   │   │   │   ├── index.js
│   │   │   │   └── index.less
│   │   │   ├── Field/
│   │   │   │   ├── index.d.ts
│   │   │   │   ├── index.js
│   │   │   │   └── index.less
│   │   │   ├── Gauge/
│   │   │   │   ├── index.d.ts
│   │   │   │   └── index.js
│   │   │   ├── MiniArea/
│   │   │   │   ├── index.d.ts
│   │   │   │   └── index.js
│   │   │   ├── MiniBar/
│   │   │   │   ├── index.d.ts
│   │   │   │   └── index.js
│   │   │   ├── MiniProgress/
│   │   │   │   ├── index.d.ts
│   │   │   │   ├── index.js
│   │   │   │   └── index.less
│   │   │   ├── Pie/
│   │   │   │   ├── index.d.ts
│   │   │   │   ├── index.js
│   │   │   │   └── index.less
│   │   │   ├── Radar/
│   │   │   │   ├── index.d.ts
│   │   │   │   ├── index.js
│   │   │   │   └── index.less
│   │   │   ├── TagCloud/
│   │   │   │   ├── index.d.ts
│   │   │   │   ├── index.js
│   │   │   │   └── index.less
│   │   │   ├── TimelineChart/
│   │   │   │   ├── index.d.ts
│   │   │   │   ├── index.js
│   │   │   │   └── index.less
│   │   │   ├── WaterWave/
│   │   │   │   ├── index.d.ts
│   │   │   │   ├── index.js
│   │   │   │   └── index.less
│   │   │   ├── autoHeight.js
│   │   │   ├── bizcharts.d.ts
│   │   │   ├── bizcharts.js
│   │   │   ├── demo/
│   │   │   │   ├── bar.md
│   │   │   │   ├── chart-card.md
│   │   │   │   ├── gauge.md
│   │   │   │   ├── mini-area.md
│   │   │   │   ├── mini-bar.md
│   │   │   │   ├── mini-pie.md
│   │   │   │   ├── mini-progress.md
│   │   │   │   ├── mix.md
│   │   │   │   ├── pie.md
│   │   │   │   ├── radar.md
│   │   │   │   ├── tag-cloud.md
│   │   │   │   ├── timeline-chart.md
│   │   │   │   └── waterwave.md
│   │   │   ├── g2.js
│   │   │   ├── index.d.ts
│   │   │   ├── index.js
│   │   │   ├── index.less
│   │   │   └── index.md
│   │   ├── Exception/
│   │   │   ├── demo/
│   │   │   │   ├── 403.md
│   │   │   │   ├── 404.md
│   │   │   │   └── 500.md
│   │   │   ├── index.d.ts
│   │   │   ├── index.en-US.md
│   │   │   ├── index.js
│   │   │   ├── index.less
│   │   │   ├── index.zh-CN.md
│   │   │   └── typeConfig.js
│   │   ├── FooterToolbar/
│   │   │   ├── demo/
│   │   │   │   └── basic.md
│   │   │   ├── index.d.ts
│   │   │   ├── index.en-US.md
│   │   │   ├── index.js
│   │   │   ├── index.less
│   │   │   └── index.zh-CN.md
│   │   ├── GlobalFooter/
│   │   │   ├── demo/
│   │   │   │   └── basic.md
│   │   │   ├── index.d.ts
│   │   │   ├── index.js
│   │   │   ├── index.less
│   │   │   └── index.md
│   │   ├── GlobalHeader/
│   │   │   ├── RightContent.js
│   │   │   ├── index.js
│   │   │   └── index.less
│   │   ├── Login/
│   │   │   ├── LoginItem.js
│   │   │   ├── LoginSubmit.js
│   │   │   ├── LoginTab.js
│   │   │   ├── demo/
│   │   │   │   └── basic.md
│   │   │   ├── index.d.ts
│   │   │   ├── index.en-US.md
│   │   │   ├── index.js
│   │   │   ├── index.less
│   │   │   ├── index.zh-CN.md
│   │   │   ├── loginContext.js
│   │   │   └── map.js
│   │   ├── NoticeIcon/
│   │   │   ├── NoticeIconTab.d.ts
│   │   │   ├── NoticeList.js
│   │   │   ├── NoticeList.less
│   │   │   ├── demo/
│   │   │   │   ├── basic.md
│   │   │   │   └── popover.md
│   │   │   ├── index.d.ts
│   │   │   ├── index.en-US.md
│   │   │   ├── index.js
│   │   │   ├── index.less
│   │   │   └── index.zh-CN.md
│   │   ├── PageHeader/
│   │   │   ├── breadcrumb.d.ts
│   │   │   ├── breadcrumb.js
│   │   │   ├── demo/
│   │   │   │   ├── image.md
│   │   │   │   ├── simple.md
│   │   │   │   ├── standard.md
│   │   │   │   └── structure.md
│   │   │   ├── index.d.ts
│   │   │   ├── index.js
│   │   │   ├── index.less
│   │   │   ├── index.md
│   │   │   └── index.test.js
│   │   ├── PageHeaderWrapper/
│   │   │   ├── GridContent.js
│   │   │   ├── GridContent.less
│   │   │   ├── index.js
│   │   │   └── index.less
│   │   ├── PageLoading/
│   │   │   └── index.js
│   │   ├── Result/
│   │   │   ├── demo/
│   │   │   │   ├── classic.md
│   │   │   │   ├── error.md
│   │   │   │   └── structure.md
│   │   │   ├── index.d.ts
│   │   │   ├── index.js
│   │   │   ├── index.less
│   │   │   └── index.md
│   │   ├── SelectLang/
│   │   │   ├── index.js
│   │   │   └── index.less
│   │   ├── SettingDrawer/
│   │   │   ├── BlockChecbox.js
│   │   │   ├── ThemeColor.js
│   │   │   ├── ThemeColor.less
│   │   │   ├── index.js
│   │   │   └── index.less
│   │   ├── SiderMenu/
│   │   │   ├── BaseMenu.js
│   │   │   ├── SiderMenu.js
│   │   │   ├── SiderMenu.test.js
│   │   │   ├── index.js
│   │   │   └── index.less
│   │   ├── StandardTable/
│   │   │   ├── index.js
│   │   │   └── index.less
│   │   ├── TopNavHeader/
│   │   │   ├── index.js
│   │   │   └── index.less
│   │   └── _utils/
│   │       ├── pathTools.js
│   │       └── pathTools.test.js
│   ├── defaultSettings.js
│   ├── e2e/
│   │   ├── home.e2e.js
│   │   └── login.e2e.js
│   ├── global.less
│   ├── layouts/
│   │   ├── BasicLayout.js
│   │   ├── BlankLayout.js
│   │   ├── Footer.js
│   │   ├── Header.js
│   │   ├── Header.less
│   │   ├── MenuContext.js
│   │   ├── UserLayout.js
│   │   └── UserLayout.less
│   ├── locales/
│   │   ├── en-US.js
│   │   ├── pt-BR.js
│   │   ├── zh-CN.js
│   │   └── zh-TW.js
│   ├── models/
│   │   ├── article.js
│   │   ├── category.js
│   │   ├── global.js
│   │   ├── link.js
│   │   ├── list.js
│   │   ├── login.js
│   │   ├── message.js
│   │   ├── otherUser.js
│   │   ├── project.js
│   │   ├── setting.js
│   │   ├── tag.js
│   │   ├── timeAxis.js
│   │   └── user.js
│   ├── pages/
│   │   ├── 404.js
│   │   ├── Account/
│   │   │   └── Settings/
│   │   │       ├── BaseView.js
│   │   │       ├── BaseView.less
│   │   │       ├── Info.js
│   │   │       ├── Info.less
│   │   │       └── PersonalLinkView.js
│   │   ├── Article/
│   │   │   ├── ArticleComponent.js
│   │   │   ├── ArticleCreate.js
│   │   │   ├── CommentsComponent.js
│   │   │   ├── List.js
│   │   │   └── style.less
│   │   ├── Authorized.js
│   │   ├── Category/
│   │   │   ├── CategoryComponent.js
│   │   │   └── List.js
│   │   ├── Dashboard/
│   │   │   ├── Workplace.js
│   │   │   ├── Workplace.less
│   │   │   └── models/
│   │   │       └── activities.js
│   │   ├── Exception/
│   │   │   ├── 403.js
│   │   │   ├── 404.js
│   │   │   ├── 500.js
│   │   │   ├── TriggerException.js
│   │   │   ├── models/
│   │   │   │   └── error.js
│   │   │   └── style.less
│   │   ├── Link/
│   │   │   ├── LinkComponent.js
│   │   │   └── List.js
│   │   ├── Message/
│   │   │   ├── List.js
│   │   │   └── MessageComponent.js
│   │   ├── OtherUser/
│   │   │   ├── List.js
│   │   │   ├── OtherUserComponent.js
│   │   │   └── style.less
│   │   ├── Project/
│   │   │   ├── List.js
│   │   │   └── ProjectComponent.js
│   │   ├── Tag/
│   │   │   ├── List.js
│   │   │   └── TagComponent.js
│   │   ├── TimeAxis/
│   │   │   ├── List.js
│   │   │   └── TimeAxisComponent.js
│   │   ├── User/
│   │   │   ├── Login.js
│   │   │   ├── Login.less
│   │   │   ├── Register.js
│   │   │   ├── Register.less
│   │   │   ├── RegisterResult.js
│   │   │   ├── RegisterResult.less
│   │   │   └── models/
│   │   │       └── register.js
│   │   └── document.ejs
│   ├── services/
│   │   ├── api.js
│   │   ├── error.js
│   │   ├── geographic.js
│   │   └── user.js
│   └── utils/
│       ├── Authorized.js
│       ├── Yuan.js
│       ├── authority.js
│       ├── authority.test.js
│       ├── domain.js
│       ├── request.js
│       ├── utils.js
│       └── utils.less
└── tests/
    ├── fix_puppeteer.sh
    └── run-tests.js
Download .txt
SYMBOL INDEX (541 symbols across 112 files)

FILE: functions/matchMock.js
  constant BODY_PARSED_METHODS (line 6) | const BODY_PARSED_METHODS = ['post', 'put', 'patch'];
  function parseKey (line 8) | function parseKey(key) {
  function createHandler (line 22) | function createHandler(method, path, handler) {
  function normalizeConfig (line 44) | function normalizeConfig(config) {
  function matchMock (line 63) | function matchMock(req) {

FILE: mock/api.js
  function fakeList (line 64) | function fakeList(count) {
  function getFakeList (line 114) | function getFakeList(req, res) {
  function postFakeList (line 124) | function postFakeList(req, res) {
  function getFakeCaptcha (line 320) | function getFakeCaptcha(req, res) {

FILE: mock/geographic.js
  function getProvince (line 4) | function getProvince(req, res) {
  function getCity (line 8) | function getCity(req, res) {

FILE: mock/rule.js
  function getRule (line 26) | function getRule(req, res, u) {
  function postRule (line 78) | function postRule(req, res, u, b) {

FILE: src/components/Authorized/CheckPermissions.js
  function isPromise (line 5) | function isPromise(obj) {

FILE: src/components/Authorized/PromiseRender.js
  class PromiseRender (line 4) | class PromiseRender extends React.PureComponent {
    method componentDidMount (line 9) | componentDidMount() {
    method componentDidUpdate (line 13) | componentDidUpdate(nextProps) {
    method setRenderComponent (line 19) | setRenderComponent(props) {
    method render (line 46) | render() {

FILE: src/components/Authorized/index.d.ts
  type authorityFN (line 4) | type authorityFN = (currentAuthority?: string) => boolean;
  type authority (line 6) | type authority = string | Array<string> | authorityFN | Promise<any>;
  type IReactComponent (line 8) | type IReactComponent<P = any> =
  type Secured (line 13) | interface Secured {
  type AuthorizedRouteProps (line 17) | interface AuthorizedRouteProps extends RouteProps {
  class AuthorizedRoute (line 20) | class AuthorizedRoute extends React.Component<AuthorizedRouteProps, any> {}
  type check (line 22) | interface check {
  type AuthorizedProps (line 30) | interface AuthorizedProps {
  class Authorized (line 35) | class Authorized extends React.Component<AuthorizedProps, any> {

FILE: src/components/Authorized/renderAuthorize.js
  constant CURRENT (line 2) | let CURRENT = 'NULL';

FILE: src/components/Charts/Bar/index.d.ts
  type IBarProps (line 2) | interface IBarProps {
  class Bar (line 15) | class Bar extends React.Component<IBarProps, any> {}

FILE: src/components/Charts/Bar/index.js
  class Bar (line 8) | @autoHeight()
    method componentDidMount (line 14) | componentDidMount() {
    method componentWillUnmount (line 18) | componentWillUnmount() {
    method resize (line 30) | @Bind()
    method render (line 57) | render() {

FILE: src/components/Charts/ChartCard/index.d.ts
  type IChartCardProps (line 4) | interface IChartCardProps extends CardProps {
  class ChartCard (line 14) | class ChartCard extends React.Component<IChartCardProps, any> {}

FILE: src/components/Charts/ChartCard/index.js
  class ChartCard (line 22) | class ChartCard extends React.PureComponent {
    method render (line 62) | render() {

FILE: src/components/Charts/Field/index.d.ts
  type IFieldProps (line 2) | interface IFieldProps {
  class Field (line 8) | class Field extends React.Component<IFieldProps, any> {}

FILE: src/components/Charts/Gauge/index.d.ts
  type IGaugeProps (line 2) | interface IGaugeProps {
  class Gauge (line 11) | class Gauge extends React.Component<IGaugeProps, any> {}

FILE: src/components/Charts/Gauge/index.js
  method drawShape (line 23) | drawShape(cfg, group) {
  class Gauge (line 54) | @autoHeight()
    method render (line 56) | render() {

FILE: src/components/Charts/MiniArea/index.d.ts
  type IAxis (line 6) | interface IAxis {
  type IMiniAreaProps (line 15) | interface IMiniAreaProps {
  class MiniArea (line 29) | class MiniArea extends React.Component<IMiniAreaProps, any> {}

FILE: src/components/Charts/MiniArea/index.js
  class MiniArea (line 6) | @autoHeight()
    method render (line 8) | render() {

FILE: src/components/Charts/MiniBar/index.d.ts
  type IMiniBarProps (line 2) | interface IMiniBarProps {
  class MiniBar (line 12) | class MiniBar extends React.Component<IMiniBarProps, any> {}

FILE: src/components/Charts/MiniBar/index.js
  class MiniBar (line 6) | @autoHeight()
    method render (line 8) | render() {

FILE: src/components/Charts/MiniProgress/index.d.ts
  type IMiniProgressProps (line 2) | interface IMiniProgressProps {
  class MiniProgress (line 10) | class MiniProgress extends React.Component<IMiniProgressProps, any> {}

FILE: src/components/Charts/Pie/index.d.ts
  type IPieProps (line 2) | interface IPieProps {
  class Pie (line 21) | class Pie extends React.Component<IPieProps, any> {}

FILE: src/components/Charts/Pie/index.js
  class Pie (line 14) | @autoHeight()
    method componentDidMount (line 21) | componentDidMount() {
    method componentDidUpdate (line 31) | componentDidUpdate(preProps) {
    method componentWillUnmount (line 40) | componentWillUnmount() {
    method resize (line 97) | @Bind()
    method render (line 119) | render() {

FILE: src/components/Charts/Radar/index.d.ts
  type IRadarProps (line 2) | interface IRadarProps {
  class Radar (line 15) | class Radar extends React.Component<IRadarProps, any> {}

FILE: src/components/Charts/Radar/index.js
  class Radar (line 8) | @autoHeight()
    method componentDidMount (line 14) | componentDidMount() {
    method componentDidUpdate (line 18) | componentDidUpdate(preProps) {
    method render (line 77) | render() {

FILE: src/components/Charts/TagCloud/index.d.ts
  type ITagCloudProps (line 2) | interface ITagCloudProps {
  class TagCloud (line 11) | class TagCloud extends React.Component<ITagCloudProps, any> {}

FILE: src/components/Charts/TagCloud/index.js
  class TagCloud (line 15) | @autoHeight()
    method componentDidMount (line 21) | componentDidMount() {
    method componentDidUpdate (line 29) | componentDidUpdate(preProps) {
    method componentWillUnmount (line 36) | componentWillUnmount() {
    method getTextAttrs (line 53) | function getTextAttrs(cfg) {
    method drawShape (line 72) | drawShape(cfg, container) {
    method renderChart (line 84) | @Bind()
    method render (line 140) | render() {

FILE: src/components/Charts/TimelineChart/index.d.ts
  type ITimelineChartProps (line 2) | interface ITimelineChartProps {
  class TimelineChart (line 14) | class TimelineChart extends React.Component<ITimelineChartProps, any> {}

FILE: src/components/Charts/TimelineChart/index.js
  class TimelineChart (line 8) | @autoHeight()
    method render (line 10) | render() {

FILE: src/components/Charts/WaterWave/index.d.ts
  type IWaterWaveProps (line 2) | interface IWaterWaveProps {
  class WaterWave (line 10) | class WaterWave extends React.Component<IWaterWaveProps, any> {}

FILE: src/components/Charts/WaterWave/index.js
  class WaterWave (line 9) | @autoHeight()
    method componentDidMount (line 15) | componentDidMount() {
    method componentDidUpdate (line 27) | componentDidUpdate(props) {
    method componentWillUnmount (line 35) | componentWillUnmount() {
    method renderChart (line 53) | renderChart(type) {
    method render (line 187) | render() {

FILE: src/components/Charts/autoHeight.js
  function computeHeight (line 4) | function computeHeight(node) {
  function getAutoHeight (line 12) | function getAutoHeight(n) {
  method componentDidMount (line 39) | componentDidMount() {
  method render (line 52) | render() {

FILE: src/components/Exception/index.d.ts
  type IExceptionProps (line 2) | interface IExceptionProps {
  class Exception (line 15) | class Exception extends React.Component<IExceptionProps, any> {}

FILE: src/components/Exception/index.js
  class Exception (line 7) | class Exception extends React.PureComponent {
    method constructor (line 13) | constructor(props) {
    method render (line 18) | render() {

FILE: src/components/FooterToolbar/index.d.ts
  type IFooterToolbarProps (line 2) | interface IFooterToolbarProps {
  class FooterToolbar (line 7) | class FooterToolbar extends React.Component<IFooterToolbarProps, any> {}

FILE: src/components/FooterToolbar/index.js
  class FooterToolbar (line 6) | class FooterToolbar extends Component {
    method componentDidMount (line 15) | componentDidMount() {
    method componentWillUnmount (line 20) | componentWillUnmount() {
    method render (line 37) | render() {

FILE: src/components/GlobalFooter/index.d.ts
  type IGlobalFooterProps (line 2) | interface IGlobalFooterProps {
  class GlobalFooter (line 13) | class GlobalFooter extends React.Component<IGlobalFooterProps, any> {}

FILE: src/components/GlobalHeader/RightContent.js
  class GlobalHeaderRight (line 10) | class GlobalHeaderRight extends PureComponent {
    method getNoticeData (line 11) | getNoticeData() {
    method render (line 42) | render() {

FILE: src/components/GlobalHeader/index.js
  class GlobalHeader (line 8) | class GlobalHeader extends PureComponent {
    method componentWillUnmount (line 9) | componentWillUnmount() {
    method triggerResizeEvent (line 13) | @Debounce(600)
    method render (line 25) | render() {

FILE: src/components/Login/LoginItem.js
  class WrapFormItem (line 10) | class WrapFormItem extends Component {
    method constructor (line 15) | constructor(props) {
    method componentDidMount (line 22) | componentDidMount() {
    method componentWillUnmount (line 29) | componentWillUnmount() {
    method render (line 72) | render() {

FILE: src/components/Login/LoginTab.js
  class LoginTab (line 15) | class LoginTab extends Component {
    method constructor (line 16) | constructor(props) {
    method componentDidMount (line 21) | componentDidMount() {
    method render (line 26) | render() {

FILE: src/components/Login/index.d.ts
  type LoginProps (line 3) | interface LoginProps {
  type TabProps (line 10) | interface TabProps {
  class Tab (line 14) | class Tab extends React.Component<TabProps, any> {}
  type LoginItemProps (line 16) | interface LoginItemProps {
  class LoginItem (line 25) | class LoginItem extends React.Component<LoginItemProps, any> {}
  class Login (line 27) | class Login extends React.Component<LoginProps, any> {

FILE: src/components/Login/index.js
  class Login (line 11) | class Login extends Component {
    method constructor (line 26) | constructor(props) {
    method render (line 84) | render() {

FILE: src/components/NoticeIcon/NoticeIconTab.d.ts
  type INoticeIconData (line 2) | interface INoticeIconData {
  type INoticeIconTabProps (line 11) | interface INoticeIconTabProps {
  class NoticeIconTab (line 21) | class NoticeIconTab extends React.Component<INoticeIconTabProps, any> {}

FILE: src/components/NoticeIcon/NoticeList.js
  function NoticeList (line 6) | function NoticeList({

FILE: src/components/NoticeIcon/index.d.ts
  type INoticeIconProps (line 4) | interface INoticeIconProps {
  class NoticeIcon (line 27) | class NoticeIcon extends React.Component<INoticeIconProps, any> {

FILE: src/components/NoticeIcon/index.js
  class NoticeIcon (line 9) | class NoticeIcon extends PureComponent {
    method getNotificationBox (line 35) | getNotificationBox() {
    method render (line 67) | render() {

FILE: src/components/PageHeader/breadcrumb.d.ts
  class BreadcrumbView (line 4) | class BreadcrumbView extends React.Component<IPageHeaderProps, any> {}

FILE: src/components/PageHeader/breadcrumb.js
  class BreadcrumbView (line 19) | class BreadcrumbView extends PureComponent {
    method componentDidMount (line 24) | componentDidMount() {
    method componentDidUpdate (line 28) | componentDidUpdate(preProps) {
    method render (line 172) | render() {

FILE: src/components/PageHeader/index.d.ts
  type IPageHeaderProps (line 2) | interface IPageHeaderProps {
  class PageHeader (line 23) | class PageHeader extends React.Component<IPageHeaderProps, any> {}

FILE: src/components/PageHeader/index.js
  class PageHeader (line 8) | class PageHeader extends PureComponent {
    method render (line 16) | render() {

FILE: src/components/PageHeaderWrapper/GridContent.js
  class GridContent (line 5) | class GridContent extends PureComponent {
    method render (line 6) | render() {

FILE: src/components/Result/index.d.ts
  type IResultProps (line 2) | interface IResultProps {
  class Result (line 11) | class Result extends React.Component<IResultProps, any> {}

FILE: src/components/Result/index.js
  function Result (line 6) | function Result({

FILE: src/components/SelectLang/index.js
  class SelectLang (line 7) | class SelectLang extends PureComponent {
    method render (line 12) | render() {

FILE: src/components/SettingDrawer/index.js
  class SettingDrawer (line 25) | @connect(({ setting }) => ({ setting }))
    method render (line 129) | render() {

FILE: src/components/SiderMenu/BaseMenu.js
  class BaseMenu (line 32) | class BaseMenu extends PureComponent {
    method constructor (line 33) | constructor(props) {
    method getFlatMenuKeys (line 44) | getFlatMenuKeys(menus) {
    method render (line 161) | render() {

FILE: src/components/SiderMenu/SiderMenu.js
  class SiderMenu (line 52) | class SiderMenu extends PureComponent {
    method constructor (line 53) | constructor(props) {
    method getDerivedStateFromProps (line 61) | static getDerivedStateFromProps(props, state) {
    method render (line 89) | render() {

FILE: src/components/StandardTable/index.js
  function initTotalList (line 5) | function initTotalList(columns) {
  class StandardTable (line 15) | class StandardTable extends PureComponent {
    method constructor (line 16) | constructor(props) {
    method getDerivedStateFromProps (line 27) | static getDerivedStateFromProps(nextProps) {
    method render (line 64) | render() {

FILE: src/components/TopNavHeader/index.js
  class TopNavHeader (line 7) | class TopNavHeader extends PureComponent {
    method constructor (line 8) | constructor(props) {
    method getDerivedStateFromProps (line 16) | static getDerivedStateFromProps(props) {
    method render (line 22) | render() {

FILE: src/components/_utils/pathTools.js
  function urlToList (line 3) | function urlToList(url) {

FILE: src/layouts/BasicLayout.js
  function formatter (line 25) | function formatter(data, parentPath = '', parentAuthority, parentName) {
  class BasicLayout (line 88) | class BasicLayout extends React.PureComponent {
    method constructor (line 89) | constructor(props) {
    method componentDidMount (line 103) | componentDidMount() {
    method componentDidUpdate (line 126) | componentDidUpdate(preProps) {
    method componentWillUnmount (line 137) | componentWillUnmount() {
    method getContext (line 142) | getContext() {
    method getMenuData (line 150) | getMenuData() {
    method getBreadcrumbNameMap (line 161) | getBreadcrumbNameMap() {
    method renderSettingDrawer (line 223) | renderSettingDrawer() {
    method render (line 233) | render() {

FILE: src/layouts/Header.js
  class HeaderView (line 14) | class HeaderView extends PureComponent {
    method getDerivedStateFromProps (line 19) | static getDerivedStateFromProps(props, state) {
    method componentDidMount (line 28) | componentDidMount() {
    method componentWillUnmount (line 32) | componentWillUnmount() {
    method render (line 117) | render() {

FILE: src/layouts/UserLayout.js
  class UserLayout (line 34) | class UserLayout extends React.PureComponent {
    method render (line 46) | render() {

FILE: src/models/article.js
  method queryArticle (line 38) | *queryArticle({ payload }, { call, put }) {
  method delArticle (line 54) | *delArticle({ payload }, { call, put }) {
  method addArticle (line 59) | *addArticle({ payload }, { call, put }) {
  method updateArticle (line 64) | *updateArticle({ payload }, { call, put }) {
  method getArticleDetail (line 69) | *getArticleDetail({ payload }, { call, put }) {
  method changeComment (line 81) | *changeComment({ payload }, { call, put }) {
  method changeThirdComment (line 86) | *changeThirdComment({ payload }, { call, put }) {
  method saveArticleList (line 94) | saveArticleList(state, { payload }) {
  method saveArticleListTotal (line 100) | saveArticleListTotal(state, { payload }) {
  method saveArticleDetail (line 106) | saveArticleDetail(state, { payload }) {

FILE: src/models/category.js
  method queryCategory (line 12) | *queryCategory({ payload }, { call, put }) {
  method addCategory (line 30) | *addCategory({ payload }, { call, put }) {
  method delCategory (line 35) | *delCategory({ payload }, { call, put }) {
  method saveCategoryList (line 43) | saveCategoryList(state, { payload }) {
  method saveCategoryListTotal (line 49) | saveCategoryListTotal(state, { payload }) {

FILE: src/models/global.js
  method fetchNotices (line 12) | *fetchNotices(_, { call, put }) {
  method clearNotices (line 23) | *clearNotices({ payload }, { put, select }) {
  method changeLayoutCollapsed (line 37) | changeLayoutCollapsed(state, { payload }) {
  method saveNotices (line 43) | saveNotices(state, { payload }) {
  method saveClearedNotices (line 49) | saveClearedNotices(state, { payload }) {
  method setup (line 58) | setup({ history }) {

FILE: src/models/link.js
  method queryLink (line 12) | *queryLink({ payload }, { call, put }) {
  method addLink (line 30) | *addLink({ payload }, { call, put }) {
  method updateLink (line 35) | *updateLink({ payload }, { call, put }) {
  method delLink (line 40) | *delLink({ payload }, { call, put }) {
  method saveLinkList (line 48) | saveLinkList(state, { payload }) {
  method saveLinkListTotal (line 54) | saveLinkListTotal(state, { payload }) {

FILE: src/models/list.js
  method fetch (line 11) | *fetch({ payload }, { call, put }) {
  method appendFetch (line 18) | *appendFetch({ payload }, { call, put }) {
  method submit (line 25) | *submit({ payload }, { call, put }) {
  method queryList (line 41) | queryList(state, action) {
  method appendList (line 47) | appendList(state, action) {

FILE: src/models/login.js
  method loginAdmin (line 16) | *loginAdmin({ payload }, { call, put }) {
  method login (line 56) | *login({ payload }, { call, put }) {
  method getCaptcha (line 87) | *getCaptcha({ payload }, { call }) {
  method logout (line 91) | *logout(_, { put }) {
  method changeLoginStatus (line 112) | changeLoginStatus(state, { payload }) {

FILE: src/models/message.js
  method queryMessage (line 28) | *queryMessage({ payload }, { call, put }) {
  method delMessage (line 44) | *delMessage({ payload }, { call, put }) {
  method addReplyMessage (line 49) | *addReplyMessage({ payload }, { call, put }) {
  method getMessageDetail (line 54) | *getMessageDetail({ payload }, { call, put }) {
  method saveMessageList (line 69) | saveMessageList(state, { payload }) {
  method saveMessageListTotal (line 75) | saveMessageListTotal(state, { payload }) {
  method saveMessageDetail (line 81) | saveMessageDetail(state, { payload }) {

FILE: src/models/otherUser.js
  method queryUser (line 12) | *queryUser({ payload }, { call, put }) {
  method addUser (line 30) | *addUser({ payload }, { call, put }) {
  method updateUser (line 35) | *updateUser({ payload }, { call, put }) {
  method delUser (line 40) | *delUser({ payload }, { call, put }) {
  method saveUserList (line 48) | saveUserList(state, { payload }) {
  method saveUserListTotal (line 54) | saveUserListTotal(state, { payload }) {

FILE: src/models/project.js
  method fetchNotice (line 19) | *fetchNotice(_, { call, put }) {
  method queryProject (line 26) | *queryProject({ payload }, { call, put }) {
  method delProject (line 42) | *delProject({ payload }, { call, put }) {
  method addProject (line 47) | *addProject({ payload }, { call, put }) {
  method updateProject (line 52) | *updateProject({ payload }, { call, put }) {
  method getProjectDetail (line 57) | *getProjectDetail({ payload }, { call, put }) {
  method saveNotice (line 71) | saveNotice(state, action) {
  method saveProjectList (line 77) | saveProjectList(state, { payload }) {
  method saveProjectListTotal (line 83) | saveProjectListTotal(state, { payload }) {
  method saveProjectDetail (line 89) | saveProjectDetail(state, { payload }) {

FILE: src/models/setting.js
  function buildIt (line 15) | function buildIt() {
  method getSetting (line 70) | getSetting(state) {
  method changeSetting (line 89) | changeSetting(state, { payload }) {

FILE: src/models/tag.js
  method queryTag (line 12) | *queryTag({ payload }, { call, put }) {
  method addTag (line 30) | *addTag({ payload }, { call, put }) {
  method delTag (line 35) | *delTag({ payload }, { call, put }) {
  method saveTagList (line 43) | saveTagList(state, { payload }) {
  method saveTagListTotal (line 49) | saveTagListTotal(state, { payload }) {

FILE: src/models/timeAxis.js
  method queryTimeAxis (line 18) | *queryTimeAxis({ payload }, { call, put }) {
  method delTimeAxis (line 34) | *delTimeAxis({ payload }, { call, put }) {
  method addTimeAxis (line 39) | *addTimeAxis({ payload }, { call, put }) {
  method updateTimeAxis (line 44) | *updateTimeAxis({ payload }, { call, put }) {
  method getTimeAxisDetail (line 49) | *getTimeAxisDetail({ payload }, { call, put }) {
  method saveTimeAxisList (line 64) | saveTimeAxisList(state, { payload }) {
  method saveTimeAxisListTotal (line 70) | saveTimeAxisListTotal(state, { payload }) {
  method saveTimeAxisDetail (line 76) | saveTimeAxisDetail(state, { payload }) {

FILE: src/models/user.js
  method fetch (line 12) | *fetch(_, { call, put }) {
  method fetchCurrent (line 19) | *fetchCurrent(_, { call, put }) {
  method delUser (line 26) | *delUser({ payload }, { call, put }) {
  method save (line 34) | save(state, action) {
  method saveCurrentUser (line 40) | saveCurrentUser(state, action) {
  method changeNotifyCount (line 46) | changeNotifyCount(state, action) {
  method saveUserList (line 55) | saveUserList(state, { payload }) {
  method saveUserListTotal (line 61) | saveUserListTotal(state, { payload }) {

FILE: src/pages/Account/Settings/BaseView.js
  class BaseView (line 30) | @connect(({ user }) => ({
    method componentDidMount (line 35) | componentDidMount() {
    method getAvatarURL (line 48) | getAvatarURL() {
    method render (line 61) | render() {

FILE: src/pages/Account/Settings/Info.js
  class Info (line 11) | @connect(({ user }) => ({
    method constructor (line 15) | constructor(props) {
    method getDerivedStateFromProps (line 35) | static getDerivedStateFromProps(props, state) {
    method componentDidMount (line 45) | componentDidMount() {
    method componentWillUnmount (line 50) | componentWillUnmount() {
    method render (line 90) | render() {

FILE: src/pages/Account/Settings/PersonalLinkView.js
  class ModelLink (line 7) | class ModelLink extends Component {
    method constructor (line 8) | constructor(props) {
    method render (line 12) | render() {
  class NotificationView (line 66) | class NotificationView extends Component {
    method constructor (line 67) | constructor(props) {
    method handleChange (line 84) | handleChange(event) {
    method onOk (line 125) | onOk() {
    method onCancel (line 128) | onCancel() {
    method render (line 171) | render() {

FILE: src/pages/Article/ArticleComponent.js
  class ArticleComponent (line 5) | @connect(({ article, tag, category }) => ({
    method constructor (line 11) | constructor(props) {
    method componentDidMount (line 23) | componentDidMount() {
    method render (line 92) | render() {

FILE: src/pages/Article/ArticleCreate.js
  class ArticleCreate (line 10) | @connect(({ article, tag, category }) => ({
    method constructor (line 16) | constructor(props) {
    method componentDidMount (line 52) | componentDidMount() {
    method handleSubmit (line 78) | handleSubmit() {
    method getSmdeValue (line 201) | getSmdeValue() {
    method setSmdeValue (line 206) | setSmdeValue(value) {
    method handleChange (line 210) | handleChange(event) {
    method handleTagChange (line 216) | handleTagChange(value) {
    method handleCategoryChange (line 225) | handleCategoryChange(value) {
    method handleChangeState (line 234) | handleChangeState(value) {
    method handleChangeOrigin (line 240) | handleChangeOrigin(value) {
    method handleChangeType (line 246) | handleChangeType(value) {
    method render (line 317) | render() {

FILE: src/pages/Article/CommentsComponent.js
  class CommentsComponent (line 5) | @connect(({ article }) => ({
    method constructor (line 9) | constructor(props) {
    method componentDidMount (line 20) | componentDidMount() {}
    method render (line 93) | render() {

FILE: src/pages/Article/List.js
  class TableList (line 27) | @connect(({ article }) => ({
    method constructor (line 32) | constructor(props) {
    method componentDidMount (line 234) | componentDidMount() {
    method handleSubmit (line 238) | handleSubmit() {
    method handleChange (line 363) | handleChange(event) {
    method handleChangeAuthor (line 369) | handleChangeAuthor(event) {
    method handleChangeContent (line 375) | handleChangeContent(event) {
    method handleChangeImgUrl (line 381) | handleChangeImgUrl(event) {
    method handleChangeKeyword (line 387) | handleChangeKeyword(event) {
    method handleChangeOrigin (line 393) | handleChangeOrigin(value) {
    method handleChangeDesc (line 399) | handleChangeDesc(event) {
    method handleChangeType (line 405) | handleChangeType(value) {
    method handleTagChange (line 412) | handleTagChange(value) {
    method handleCategoryChange (line 421) | handleCategoryChange(value) {
    method handleChangeState (line 430) | handleChangeState(value) {
    method handleChangeSearchState (line 436) | handleChangeSearchState(searchState) {
    method handleChangeSearchKeyword (line 447) | handleChangeSearchKeyword(event) {
    method handleChangePageParam (line 453) | handleChangePageParam(pageNum, pageSize) {
    method getArticleDetail (line 465) | getArticleDetail(callback) {
    method renderSimpleForm (line 659) | renderSimpleForm() {
    method render (line 710) | render() {

FILE: src/pages/Category/CategoryComponent.js
  class LinkComponent (line 4) | class LinkComponent extends React.Component {
    method constructor (line 5) | constructor(props) {
    method componentDidMount (line 10) | componentDidMount() {}
    method render (line 12) | render() {

FILE: src/pages/Category/List.js
  class TableList (line 12) | @connect(({ category }) => ({
    method constructor (line 17) | constructor(props) {
    method componentDidMount (line 62) | componentDidMount() {
    method handleChange (line 67) | handleChange(event) {
    method handleDescChange (line 73) | handleDescChange(event) {
    method handleChangeKeyword (line 80) | handleChangeKeyword(event) {
    method handleChangePageParam (line 86) | handleChangePageParam(pageNum, pageSize) {
    method renderSimpleForm (line 206) | renderSimpleForm() {
    method render (line 244) | render() {

FILE: src/pages/Dashboard/Workplace.js
  class Workplace (line 10) | @connect(({ user,activities, loading }) => ({
    method componentDidMount (line 18) | componentDidMount() {
    method componentWillUnmount (line 28) | componentWillUnmount() {
    method renderActivities (line 31) | renderActivities() {
    method render (line 68) | render() {

FILE: src/pages/Dashboard/models/activities.js
  method fetchList (line 11) | *fetchList(_, { call, put }) {
  method saveList (line 21) | saveList(state, action) {

FILE: src/pages/Exception/TriggerException.js
  class TriggerException (line 6) | @connect(state => ({
    method render (line 27) | render() {

FILE: src/pages/Exception/models/error.js
  method query (line 12) | *query({ payload }, { call, put }) {
  method trigger (line 22) | trigger(state, action) {

FILE: src/pages/Link/LinkComponent.js
  class LinkComponent (line 4) | class LinkComponent extends React.Component {
    method constructor (line 5) | constructor(props) {
    method componentDidMount (line 10) | componentDidMount() {}
    method render (line 12) | render() {

FILE: src/pages/Link/List.js
  class TableList (line 12) | @connect(({ link }) => ({
    method constructor (line 17) | constructor(props) {
    method componentDidMount (line 89) | componentDidMount() {
    method onChangeState (line 93) | onChangeState(text, record, state) {
    method handleChangeType (line 139) | handleChangeType(type) {
    method handleChange (line 150) | handleChange(event) {
    method handleDescChange (line 156) | handleDescChange(event) {
    method handleUrlChange (line 162) | handleUrlChange(event) {
    method handleIconChange (line 168) | handleIconChange(event) {
    method handleTypeChange (line 174) | handleTypeChange(event) {
    method handleChangeKeyword (line 180) | handleChangeKeyword(event) {
    method handleChangePageParam (line 186) | handleChangePageParam(pageNum, pageSize) {
    method renderSimpleForm (line 311) | renderSimpleForm() {
    method render (line 359) | render() {

FILE: src/pages/Message/List.js
  class TableList (line 26) | @connect(({ message }) => ({
    method constructor (line 31) | constructor(props) {
    method componentDidMount (line 104) | componentDidMount() {
    method handleChangeState (line 108) | handleChangeState(state) {
    method handleChangeKeyword (line 119) | handleChangeKeyword(event) {
    method handleChangePageParam (line 125) | handleChangePageParam(pageNum, pageSize) {
    method renderSimpleForm (line 239) | renderSimpleForm() {
    method render (line 278) | render() {

FILE: src/pages/Message/MessageComponent.js
  class MessageComponent (line 5) | @connect(({ message }) => ({
    method constructor (line 9) | constructor(props) {
    method componentDidMount (line 20) | componentDidMount() {}
    method submit (line 22) | submit() {
    method handleChange (line 51) | handleChange(event) {
    method handleStateChange (line 57) | handleStateChange(value) {
    method render (line 63) | render() {

FILE: src/pages/OtherUser/List.js
  class TableList (line 23) | @connect(({ otherUser }) => ({
    method constructor (line 28) | constructor(props) {
    method componentDidMount (line 89) | componentDidMount() {
    method handleChangeType (line 93) | handleChangeType(type) {
    method handleChangeKeyword (line 104) | handleChangeKeyword(event) {
    method handleChangePageParam (line 110) | handleChangePageParam(pageNum, pageSize) {
    method renderSimpleForm (line 191) | renderSimpleForm() {
    method render (line 230) | render() {

FILE: src/pages/OtherUser/OtherUserComponent.js
  class OtherUserComponent (line 4) | class OtherUserComponent extends React.Component {
    method constructor (line 5) | constructor(props) {
    method componentDidMount (line 10) | componentDidMount() {}
    method render (line 12) | render() {

FILE: src/pages/Project/List.js
  class TableList (line 26) | @connect(({ project }) => ({
    method constructor (line 31) | constructor(props) {
    method componentDidMount (line 126) | componentDidMount() {
    method onChangeTime (line 130) | onChangeTime(date, dateString) {
    method handleSubmit (line 138) | handleSubmit() {
    method handleChange (line 213) | handleChange(event) {
    method handleStateChange (line 220) | handleStateChange(value) {
    method handleChangeState (line 226) | handleChangeState(state) {
    method handleChangePageParam (line 237) | handleChangePageParam(pageNum, pageSize) {
    method renderSimpleForm (line 367) | renderSimpleForm() {
    method render (line 418) | render() {

FILE: src/pages/Project/ProjectComponent.js
  class ProjectComponent (line 7) | @connect(({ project }) => ({
    method constructor (line 11) | constructor(props) {
    method checkUpdate (line 16) | checkUpdate() {
    method render (line 28) | render() {

FILE: src/pages/Tag/List.js
  class TableList (line 12) | @connect(({ tag }) => ({
    method constructor (line 17) | constructor(props) {
    method componentDidMount (line 61) | componentDidMount() {
    method handleChange (line 65) | handleChange(event) {
    method handleDescChange (line 72) | handleDescChange(event) {
    method handleChangeKeyword (line 79) | handleChangeKeyword(event) {
    method handleChangePageParam (line 86) | handleChangePageParam(pageNum, pageSize) {
    method renderSimpleForm (line 207) | renderSimpleForm() {
    method render (line 245) | render() {

FILE: src/pages/Tag/TagComponent.js
  class TagComponent (line 4) | class TagComponent extends React.Component {
    method constructor (line 5) | constructor(props) {
    method componentDidMount (line 10) | componentDidMount() {}
    method render (line 12) | render() {

FILE: src/pages/TimeAxis/List.js
  class TableList (line 25) | @connect(({ timeAxis }) => ({
    method constructor (line 30) | constructor(props) {
    method componentDidMount (line 114) | componentDidMount() {
    method onChangeTime (line 118) | onChangeTime(date, dateString) {
    method handleSubmit (line 126) | handleSubmit() {
    method handleChange (line 197) | handleChange(event) {
    method handleChangeContent (line 203) | handleChangeContent(event) {
    method handleStateChange (line 209) | handleStateChange(value) {
    method handleChangeState (line 215) | handleChangeState(state) {
    method handleChangeKeyword (line 226) | handleChangeKeyword(event) {
    method handleChangePageParam (line 232) | handleChangePageParam(pageNum, pageSize) {
    method renderSimpleForm (line 358) | renderSimpleForm() {
    method render (line 408) | render() {

FILE: src/pages/TimeAxis/TimeAxisComponent.js
  class TimeAxisComponent (line 7) | @connect(({ timeAxis }) => ({
    method constructor (line 11) | constructor(props) {
    method checkUpdate (line 18) | checkUpdate(){
    method render (line 32) | render() {

FILE: src/pages/User/Login.js
  class LoginPage (line 11) | @connect(({ login, loading }) => ({
    method render (line 68) | render() {

FILE: src/pages/User/Register.js
  class Register (line 37) | @connect(({ register, loading }) => ({
    method componentDidUpdate (line 51) | componentDidUpdate() {
    method componentWillUnmount (line 64) | componentWillUnmount() {
    method render (line 176) | render() {

FILE: src/pages/User/models/register.js
  method submit (line 13) | *submit({ payload }, { call, put }) {
  method registerHandle (line 23) | registerHandle(state, { payload }) {

FILE: src/services/api.js
  function queryProjectNotice (line 4) | async function queryProjectNotice() {
  function queryActivities (line 8) | async function queryActivities() {
  function fakeSubmitForm (line 12) | async function fakeSubmitForm(params) {
  function fakeChartData (line 19) | async function fakeChartData() {
  function queryCategory (line 24) | async function queryCategory(params) {
  function addCategory (line 28) | async function addCategory(params) {
  function updateCategory (line 34) | async function updateCategory(params) {
  function delCategory (line 41) | async function delCategory(params) {
  function queryUser (line 49) | async function queryUser(params) {
  function addUser (line 53) | async function addUser(params) {
  function updateUser (line 59) | async function updateUser(params) {
  function delUser (line 66) | async function delUser(params) {
  function queryLink (line 74) | async function queryLink(params) {
  function addLink (line 78) | async function addLink(params) {
  function updateLink (line 84) | async function updateLink(params) {
  function delLink (line 91) | async function delLink(params) {
  function queryMessage (line 99) | async function queryMessage(params) {
  function delMessage (line 103) | async function delMessage(params) {
  function getMessageDetail (line 109) | async function getMessageDetail(params) {
  function addReplyMessage (line 116) | async function addReplyMessage(params) {
  function queryArticle (line 124) | async function queryArticle(params) {
  function addArticle (line 128) | async function addArticle(params) {
  function delArticle (line 134) | async function delArticle(params) {
  function updateArticle (line 141) | async function updateArticle(params) {
  function getArticleDetail (line 148) | async function getArticleDetail(params) {
  function changeComment (line 156) | async function changeComment(params) {
  function changeThirdComment (line 164) | async function changeThirdComment(params) {
  function queryTimeAxis (line 172) | async function queryTimeAxis(params) {
  function addTimeAxis (line 176) | async function addTimeAxis(params) {
  function delTimeAxis (line 182) | async function delTimeAxis(params) {
  function updateTimeAxis (line 189) | async function updateTimeAxis(params) {
  function getTimeAxisDetail (line 196) | async function getTimeAxisDetail(params) {
  function queryProject (line 204) | async function queryProject(params) {
  function addProject (line 208) | async function addProject(params) {
  function delProject (line 214) | async function delProject(params) {
  function updateProject (line 221) | async function updateProject(params) {
  function getProjectDetail (line 228) | async function getProjectDetail(params) {
  function queryTag (line 236) | async function queryTag(params) {
  function addTag (line 240) | async function addTag(params) {
  function delTag (line 247) | async function delTag(params) {
  function queryBasicProfile (line 254) | async function queryBasicProfile() {
  function queryAdvancedProfile (line 258) | async function queryAdvancedProfile() {
  function queryFakeList (line 262) | async function queryFakeList(params) {
  function removeFakeList (line 266) | async function removeFakeList(params) {
  function addFakeList (line 277) | async function addFakeList(params) {
  function updateFakeList (line 288) | async function updateFakeList(params) {
  function loginAdmin (line 299) | async function loginAdmin(params) {
  function fakeAccountLogin (line 306) | async function fakeAccountLogin(params) {
  function fakeRegister (line 313) | async function fakeRegister(params) {
  function queryNotices (line 320) | async function queryNotices() {
  function getFakeCaptcha (line 324) | async function getFakeCaptcha(mobile) {

FILE: src/services/error.js
  function queryError (line 3) | async function queryError(code) {

FILE: src/services/geographic.js
  function queryProvince (line 3) | async function queryProvince() {
  function queryCity (line 7) | async function queryCity(province) {

FILE: src/services/user.js
  function query (line 3) | async function query() {
  function queryCurrent (line 7) | async function queryCurrent() {

FILE: src/utils/Yuan.js
  class Yuan (line 6) | class Yuan extends React.PureComponent {
    method componentDidMount (line 7) | componentDidMount() {
    method componentDidUpdate (line 11) | componentDidUpdate() {
    method render (line 22) | render() {

FILE: src/utils/authority.js
  function getAuthority (line 2) | function getAuthority(str) {
  function setAuthority (line 19) | function setAuthority(authority) {

FILE: src/utils/request.js
  function request (line 66) | function request(

FILE: src/utils/utils.js
  function fixedZero (line 6) | function fixedZero(val) {
  function getTimeDistance (line 10) | function getTimeDistance(type) {
  function getPlainNode (line 55) | function getPlainNode(nodeList, parentPath = '') {
  function digitUppercase (line 73) | function digitUppercase(n) {
  function getRelation (line 77) | function getRelation(str1, str2) {
  function getRenderArr (line 92) | function getRenderArr(routes) {
  function getRoutes (line 113) | function getRoutes(path, routerData) {
  function getPageQuery (line 134) | function getPageQuery() {
  function getQueryPath (line 138) | function getQueryPath(path = '', query = {}) {
  function isUrl (line 149) | function isUrl(path) {
  function formatWan (line 153) | function formatWan(val) {
  function isAntdPro (line 181) | function isAntdPro() {
Condensed preview — 281 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (646K chars).
[
  {
    "path": ".circleci/config.yml",
    "chars": 467,
    "preview": "version: 2\njobs:\n  build:\n    docker:\n      - image: circleci/node:8.11.4\n    steps:\n      - checkout\n      - run: npm i"
  },
  {
    "path": ".dockerignore",
    "chars": 446,
    "preview": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n**/node_modules\n# "
  },
  {
    "path": ".editorconfig",
    "chars": 245,
    "preview": "# http://editorconfig.org\nroot = true\n\n[*]\nindent_style = space\nindent_size = 2\nend_of_line = lf\ncharset = utf-8\ntrim_tr"
  },
  {
    "path": ".eslintignore",
    "chars": 16,
    "preview": "/functions/mock\n"
  },
  {
    "path": ".eslintrc.js",
    "chars": 911,
    "preview": "module.exports = {\n  parser: 'babel-eslint',\n  extends: ['airbnb', 'prettier', 'plugin:compat/recommended'],\n  env: {\n  "
  },
  {
    "path": ".firebaserc",
    "chars": 50,
    "preview": "{\n  \"projects\": {\n    \"default\": \"antd-pro\"\n  }\n}\n"
  },
  {
    "path": ".gitignore",
    "chars": 447,
    "preview": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n**/node_modules\n/d"
  },
  {
    "path": ".prettierignore",
    "chars": 70,
    "preview": "**/*.md\n**/*.svg\n**/*.ejs\n**/*.html\npackage.json\n.umi\n.umi-production\n"
  },
  {
    "path": ".prettierrc",
    "chars": 175,
    "preview": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"es5\",\n  \"printWidth\": 100,\n  \"overrides\": [\n    {\n      \"files\": \".prettier"
  },
  {
    "path": ".stylelintrc.json",
    "chars": 273,
    "preview": "{\n  \"extends\": [\"stylelint-config-standard\", \"stylelint-config-prettier\"],\n  \"rules\": {\n    \"declaration-empty-line-befo"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "chars": 3213,
    "preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, w"
  },
  {
    "path": "Dockerfile",
    "chars": 637,
    "preview": "FROM node:latest\n\nWORKDIR /usr/src/app/\n\nCOPY package.json ./\nRUN npm install --silent --no-cache\n\nCOPY ./ ./\n\nRUN apt-g"
  },
  {
    "path": "Dockerfile.dev",
    "chars": 140,
    "preview": "FROM node:latest\n\nWORKDIR /usr/src/app/\n\nCOPY package.json ./\nRUN npm install --silent --no-cache\n\nCOPY ./ ./\n\n\nCMD [\"np"
  },
  {
    "path": "LICENSE",
    "chars": 1067,
    "preview": "MIT License\n\nCopyright (c) 2018 Alipay.inc\n\nPermission is hereby granted, free of charge, to any person obtaining a copy"
  },
  {
    "path": "README.md",
    "chars": 5247,
    "preview": "\n![效果图1.gif](https://upload-images.jianshu.io/upload_images/12890819-226f48af9087c3cf.gif?imageMogr2/auto-orient/strip)\n"
  },
  {
    "path": "README.ru-RU.md",
    "chars": 4566,
    "preview": "[English](./README.md) | [简体中文](./README.zh-CN.md) | Русский\n\n<h1 align=\"center\">Ant Design Pro</h1>\n\n<div align=\"center"
  },
  {
    "path": "README.zh-CN.md",
    "chars": 3795,
    "preview": "[English](./README.md) | 简体中文 | [Русский](./README.ru-RU.md)\n\n<h1 align=\"center\">Ant Design Pro</h1>\n\n<div align=\"center"
  },
  {
    "path": "appveyor.yml",
    "chars": 652,
    "preview": "# Test against the latest version of this Node.js version\nenvironment:\n  nodejs_version: \"8\"\n\n# this is how to allow fai"
  },
  {
    "path": "config/config.js",
    "chars": 2860,
    "preview": "// https://umijs.org/config/\nimport os from 'os';\nimport pageRoutes from './router.config';\nimport webpackplugin from '."
  },
  {
    "path": "config/plugin.config.js",
    "chars": 821,
    "preview": "// Change theme plugin\n\nimport MergeLessPlugin from 'antd-pro-merge-less';\nimport AntDesignThemePlugin from 'antd-pro-th"
  },
  {
    "path": "config/router.config.js",
    "chars": 4601,
    "preview": "export default [\n  // user\n  {\n    path: '/user',\n    component: '../layouts/UserLayout',\n    routes: [\n      { path: '/"
  },
  {
    "path": "docker/docker-compose.dev.yml",
    "chars": 298,
    "preview": "version: \"3.5\"\n\nservices:\n  ant-design-pro_dev:\n    ports:\n      - 8000:8000\n    build:\n      context: ../\n      dockerf"
  },
  {
    "path": "docker/docker-compose.yml",
    "chars": 407,
    "preview": "version: \"3.5\"\n\nservices:\n  ant-design-pro_build:\n    build: ../\n    container_name: \"ant-design-pro_build\"\n    volumes:"
  },
  {
    "path": "docker/nginx.conf",
    "chars": 671,
    "preview": "server {\n    listen 80;\n    # gzip config\n    gzip on;\n    gzip_min_length 1k;\n    gzip_comp_level 9\n    gzip_types text"
  },
  {
    "path": "firebase.json",
    "chars": 260,
    "preview": "{\n  \"hosting\": {\n    \"public\": \"dist\",\n    \"rewrites\": [\n      { \"source\": \"/api/**\", \"function\": \"api\" },\n      {\n     "
  },
  {
    "path": "functions/index.js",
    "chars": 245,
    "preview": "// [START functionsimport]\nconst functions = require('firebase-functions');\nconst express = require('express');\nconst ma"
  },
  {
    "path": "functions/matchMock.js",
    "chars": 2805,
    "preview": "const mockFile = require('./mock/index');\nconst pathToRegexp = require('path-to-regexp');\nconst debug = console.log;\ncon"
  },
  {
    "path": "functions/package.json",
    "chars": 651,
    "preview": "{\n  \"name\": \"functions\",\n  \"description\": \"Cloud Functions for Firebase\",\n  \"scripts\": {\n    \"serve\": \"npm run mock && f"
  },
  {
    "path": "jest.config.js",
    "chars": 58,
    "preview": "module.exports = {\n  testURL: 'http://localhost:8000',\n};\n"
  },
  {
    "path": "jsconfig.json",
    "chars": 168,
    "preview": "{\n  \"compilerOptions\": {\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"baseUrl\": \".\",\n    "
  },
  {
    "path": "mock/api.js",
    "chars": 8337,
    "preview": "import mockjs from 'mockjs';\n\nconst titles = [\n  'Alipay',\n  'Angular',\n  'Ant Design',\n  'Ant Design Pro',\n  'Bootstrap"
  },
  {
    "path": "mock/blog.js",
    "chars": 2634,
    "preview": "const getArticle = (req, res) =>\n  res.json([\n    {\n      id: '000000001',\n      avatar: 'https://gw.alipayobjects.com/z"
  },
  {
    "path": "mock/chart.js",
    "chars": 3049,
    "preview": "import moment from 'moment';\n\n// mock data\nconst visitData = [];\nconst beginDay = new Date().getTime();\n\nconst fakeY = ["
  },
  {
    "path": "mock/geographic/city.json",
    "chars": 28541,
    "preview": "{\n  \"110000\": [\n    {\n      \"province\": \"北京市\",\n      \"name\": \"市辖区\",\n      \"id\": \"110100\"\n    }\n  ],\n  \"120000\": [\n    {\n"
  },
  {
    "path": "mock/geographic/province.json",
    "chars": 1628,
    "preview": "[\n  {\n    \"name\": \"北京市\",\n    \"id\": \"110000\"\n  },\n  {\n    \"name\": \"天津市\",\n    \"id\": \"120000\"\n  },\n  {\n    \"name\": \"河北省\",\n "
  },
  {
    "path": "mock/geographic.js",
    "chars": 354,
    "preview": "import city from './geographic/city.json';\nimport province from './geographic/province.json';\n\nfunction getProvince(req,"
  },
  {
    "path": "mock/notices.js",
    "chars": 2634,
    "preview": "const getNotices = (req, res) =>\n  res.json([\n    {\n      id: '000000001',\n      avatar: 'https://gw.alipayobjects.com/z"
  },
  {
    "path": "mock/profile.js",
    "chars": 2638,
    "preview": "const basicGoods = [\n  {\n    id: '1234561',\n    name: '矿泉水 550ml',\n    barcode: '12421432143214321',\n    price: '2.00',\n"
  },
  {
    "path": "mock/rule.js",
    "chars": 3610,
    "preview": "import { parse } from 'url';\n\n// mock tableListDataSource\nlet tableListDataSource = [];\nfor (let i = 0; i < 46; i += 1) "
  },
  {
    "path": "mock/user.js",
    "chars": 2957,
    "preview": "// 代码中会兼容本地 service mock 以及部署站点的静态数据\nexport default {\n  // 支持值为 Object 和 Array\n  'GET /api/currentUser': {\n    name: 'Bi"
  },
  {
    "path": "package.json",
    "chars": 3702,
    "preview": "{\n  \"name\": \"ant-design-pro\",\n  \"version\": \"2.0.0\",\n  \"description\": \"An out-of-box UI solution for enterprise applicati"
  },
  {
    "path": "scripts/generateMock.js",
    "chars": 182,
    "preview": "const generateMock = require('merge-umi-mock-data');\nconst path = require('path');\ngenerateMock(path.join(__dirname, '.."
  },
  {
    "path": "src/components/Authorized/Authorized.js",
    "chars": 288,
    "preview": "import CheckPermissions from './CheckPermissions';\n\nconst Authorized = ({ children, authority, noMatch = null }) => {\n  "
  },
  {
    "path": "src/components/Authorized/AuthorizedRoute.js",
    "chars": 532,
    "preview": "import React from 'react';\nimport { Route, Redirect } from 'react-router-dom';\nimport Authorized from './Authorized';\n\n/"
  },
  {
    "path": "src/components/Authorized/CheckPermissions.js",
    "chars": 2285,
    "preview": "import React from 'react';\nimport PromiseRender from './PromiseRender';\nimport { CURRENT } from './renderAuthorize';\n\nfu"
  },
  {
    "path": "src/components/Authorized/CheckPermissions.test.js",
    "chars": 2533,
    "preview": "import { checkPermissions } from './CheckPermissions';\n\nconst target = 'ok';\nconst error = 'error';\n\ndescribe('test Chec"
  },
  {
    "path": "src/components/Authorized/PromiseRender.js",
    "chars": 1500,
    "preview": "import React from 'react';\nimport { Spin } from 'antd';\n\nexport default class PromiseRender extends React.PureComponent "
  },
  {
    "path": "src/components/Authorized/Secured.js",
    "chars": 1710,
    "preview": "import React from 'react';\nimport Exception from '../Exception';\nimport CheckPermissions from './CheckPermissions';\n/**\n"
  },
  {
    "path": "src/components/Authorized/demo/AuthorizedArray.md",
    "chars": 522,
    "preview": "---\norder: 1\ntitle: \n  zh-CN: 使用数组作为参数\n  en-US: Use Array as a parameter\n---\n\nUse Array as a parameter\n\n```jsx\nimport Re"
  },
  {
    "path": "src/components/Authorized/demo/AuthorizedFunction.md",
    "chars": 601,
    "preview": "---\norder: 2\ntitle: \n  zh-CN: 使用方法作为参数\n  en-US: Use function as a parameter\n---\n\nUse Function as a parameter\n\n```jsx\nimp"
  },
  {
    "path": "src/components/Authorized/demo/basic.md",
    "chars": 479,
    "preview": "---\norder: 0\ntitle: \n  zh-CN: 基本使用\n  en-US: Basic use\n---\n\nBasic use\n\n```jsx\nimport RenderAuthorized from 'ant-design-pr"
  },
  {
    "path": "src/components/Authorized/demo/secured.md",
    "chars": 465,
    "preview": "---\norder: 3\ntitle: \n  zh-CN: 注解基本使用\n  en-US: Basic use secured\n---\n\nsecured demo used\n\n```jsx\nimport RenderAuthorized f"
  },
  {
    "path": "src/components/Authorized/index.d.ts",
    "chars": 1158,
    "preview": "import * as React from 'react';\nimport { RouteProps } from 'react-router';\n\ntype authorityFN = (currentAuthority?: strin"
  },
  {
    "path": "src/components/Authorized/index.js",
    "chars": 358,
    "preview": "import Authorized from './Authorized';\nimport AuthorizedRoute from './AuthorizedRoute';\nimport Secured from './Secured';"
  },
  {
    "path": "src/components/Authorized/index.md",
    "chars": 2019,
    "preview": "---\ntitle:\n  en-US: Authorized\n  zh-CN: Authorized\nsubtitle: 权限\ncols: 1\norder: 15\n---\n\n权限组件,通过比对现有权限与准入权限,决定相关元素的展示。\n\n##"
  },
  {
    "path": "src/components/Authorized/renderAuthorize.js",
    "chars": 651,
    "preview": "/* eslint-disable import/no-mutable-exports */\nlet CURRENT = 'NULL';\n/**\n * use  authority or getAuthority\n * @param {st"
  },
  {
    "path": "src/components/Charts/Bar/index.d.ts",
    "chars": 346,
    "preview": "import * as React from 'react';\nexport interface IBarProps {\n  title: React.ReactNode;\n  color?: string;\n  padding?: [nu"
  },
  {
    "path": "src/components/Charts/Bar/index.js",
    "chars": 2481,
    "preview": "import React, { Component } from 'react';\nimport { Chart, Axis, Tooltip, Geom } from 'bizcharts';\nimport Debounce from '"
  },
  {
    "path": "src/components/Charts/ChartCard/index.d.ts",
    "chars": 450,
    "preview": "import * as React from 'react';\nimport { CardProps } from 'antd/lib/card';\n\nexport interface IChartCardProps extends Car"
  },
  {
    "path": "src/components/Charts/ChartCard/index.js",
    "chars": 2055,
    "preview": "import React from 'react';\nimport { Card } from 'antd';\nimport classNames from 'classnames';\n\nimport styles from './inde"
  },
  {
    "path": "src/components/Charts/ChartCard/index.less",
    "chars": 1266,
    "preview": "@import '~antd/lib/style/themes/default.less';\n\n.chartCard {\n  position: relative;\n  .chartTop {\n    position: relative;"
  },
  {
    "path": "src/components/Charts/Field/index.d.ts",
    "chars": 221,
    "preview": "import * as React from 'react';\nexport interface IFieldProps {\n  label: React.ReactNode;\n  value: React.ReactNode;\n  sty"
  },
  {
    "path": "src/components/Charts/Field/index.js",
    "chars": 239,
    "preview": "import React from 'react';\n\nimport styles from './index.less';\n\nconst Field = ({ label, value, ...rest }) => (\n  <div cl"
  },
  {
    "path": "src/components/Charts/Field/index.less",
    "chars": 283,
    "preview": "@import '~antd/lib/style/themes/default.less';\n\n.field {\n  white-space: nowrap;\n  overflow: hidden;\n  text-overflow: ell"
  },
  {
    "path": "src/components/Charts/Gauge/index.d.ts",
    "chars": 270,
    "preview": "import * as React from 'react';\nexport interface IGaugeProps {\n  title: React.ReactNode;\n  color?: string;\n  height: num"
  },
  {
    "path": "src/components/Charts/Gauge/index.js",
    "chars": 3887,
    "preview": "import React from 'react';\nimport { Chart, Geom, Axis, Coord, Guide, Shape } from 'bizcharts';\nimport autoHeight from '."
  },
  {
    "path": "src/components/Charts/MiniArea/index.d.ts",
    "chars": 484,
    "preview": "import * as React from 'react';\n\n// g2已经更新到3.0\n// 不带的写了\n\nexport interface IAxis {\n  title: any;\n  line: any;\n  gridAlign"
  },
  {
    "path": "src/components/Charts/MiniArea/index.js",
    "chars": 2489,
    "preview": "import React from 'react';\nimport { Chart, Axis, Tooltip, Geom } from 'bizcharts';\nimport autoHeight from '../autoHeight"
  },
  {
    "path": "src/components/Charts/MiniBar/index.d.ts",
    "chars": 272,
    "preview": "import * as React from 'react';\nexport interface IMiniBarProps {\n  color?: string;\n  height: number;\n  data: Array<{\n   "
  },
  {
    "path": "src/components/Charts/MiniBar/index.js",
    "chars": 1147,
    "preview": "import React from 'react';\nimport { Chart, Tooltip, Geom } from 'bizcharts';\nimport autoHeight from '../autoHeight';\nimp"
  },
  {
    "path": "src/components/Charts/MiniProgress/index.d.ts",
    "chars": 270,
    "preview": "import * as React from 'react';\nexport interface IMiniProgressProps {\n  target: number;\n  color?: string;\n  strokeWidth?"
  },
  {
    "path": "src/components/Charts/MiniProgress/index.js",
    "chars": 808,
    "preview": "import React from 'react';\nimport { Tooltip } from 'antd';\n\nimport styles from './index.less';\n\nconst MiniProgress = ({ "
  },
  {
    "path": "src/components/Charts/MiniProgress/index.less",
    "chars": 662,
    "preview": "@import '~antd/lib/style/themes/default.less';\n\n.miniProgress {\n  padding: 5px 0;\n  position: relative;\n  width: 100%;\n "
  },
  {
    "path": "src/components/Charts/Pie/index.d.ts",
    "chars": 571,
    "preview": "import * as React from 'react';\nexport interface IPieProps {\n  animate?: boolean;\n  color?: string;\n  colors?: string[];"
  },
  {
    "path": "src/components/Charts/Pie/index.js",
    "chars": 6767,
    "preview": "import React, { Component } from 'react';\nimport { Chart, Tooltip, Geom, Coord } from 'bizcharts';\nimport { DataView } f"
  },
  {
    "path": "src/components/Charts/Pie/index.less",
    "chars": 1653,
    "preview": "@import '~antd/lib/style/themes/default.less';\n\n.pie {\n  position: relative;\n  .chart {\n    position: relative;\n  }\n  &."
  },
  {
    "path": "src/components/Charts/Radar/index.d.ts",
    "chars": 361,
    "preview": "import * as React from 'react';\nexport interface IRadarProps {\n  title?: React.ReactNode;\n  height: number;\n  padding?: "
  },
  {
    "path": "src/components/Charts/Radar/index.js",
    "chars": 4237,
    "preview": "import React, { Component } from 'react';\nimport { Chart, Tooltip, Geom, Coord, Axis } from 'bizcharts';\nimport { Row, C"
  },
  {
    "path": "src/components/Charts/Radar/index.less",
    "chars": 915,
    "preview": "@import '~antd/lib/style/themes/default.less';\n\n.radar {\n  .legend {\n    margin-top: 16px;\n    .legendItem {\n      posit"
  },
  {
    "path": "src/components/Charts/TagCloud/index.d.ts",
    "chars": 255,
    "preview": "import * as React from 'react';\nexport interface ITagCloudProps {\n  data: Array<{\n    name: string;\n    value: number;\n "
  },
  {
    "path": "src/components/Charts/TagCloud/index.js",
    "chars": 4042,
    "preview": "import React, { Component } from 'react';\nimport { Chart, Geom, Coord, Shape } from 'bizcharts';\nimport DataSet from '@a"
  },
  {
    "path": "src/components/Charts/TagCloud/index.less",
    "chars": 104,
    "preview": ".tagCloud {\n  overflow: hidden;\n  canvas {\n    transform: scale(0.25);\n    transform-origin: 0 0;\n  }\n}\n"
  },
  {
    "path": "src/components/Charts/TimelineChart/index.d.ts",
    "chars": 369,
    "preview": "import * as React from 'react';\nexport interface ITimelineChartProps {\n  data: Array<{\n    x: number;\n    y1: number;\n  "
  },
  {
    "path": "src/components/Charts/TimelineChart/index.js",
    "chars": 2918,
    "preview": "import React from 'react';\nimport { Chart, Tooltip, Geom, Legend, Axis } from 'bizcharts';\nimport DataSet from '@antv/da"
  },
  {
    "path": "src/components/Charts/TimelineChart/index.less",
    "chars": 39,
    "preview": ".timelineChart {\n  background: #fff;\n}\n"
  },
  {
    "path": "src/components/Charts/WaterWave/index.d.ts",
    "chars": 262,
    "preview": "import * as React from 'react';\nexport interface IWaterWaveProps {\n  title: React.ReactNode;\n  color?: string;\n  height:"
  },
  {
    "path": "src/components/Charts/WaterWave/index.js",
    "chars": 5586,
    "preview": "import React, { PureComponent } from 'react';\nimport autoHeight from '../autoHeight';\nimport styles from './index.less';"
  },
  {
    "path": "src/components/Charts/WaterWave/index.less",
    "chars": 522,
    "preview": "@import '~antd/lib/style/themes/default.less';\n\n.waterWave {\n  display: inline-block;\n  position: relative;\n  transform-"
  },
  {
    "path": "src/components/Charts/autoHeight.js",
    "chars": 1294,
    "preview": "/* eslint eqeqeq: 0 */\nimport React from 'react';\n\nfunction computeHeight(node) {\n  const totalHeight = parseInt(getComp"
  },
  {
    "path": "src/components/Charts/bizcharts.d.ts",
    "chars": 59,
    "preview": "import * as BizChart from 'bizcharts';\n\nexport = BizChart;\n"
  },
  {
    "path": "src/components/Charts/bizcharts.js",
    "chars": 65,
    "preview": "import * as BizChart from 'bizcharts';\n\nexport default BizChart;\n"
  },
  {
    "path": "src/components/Charts/demo/bar.md",
    "chars": 397,
    "preview": "---\norder: 4\ntitle: 柱状图\n---\n\n通过设置 `x`,`y` 属性,可以快速的构建出一个漂亮的柱状图,各种纬度的关系则是通过自定义的数据展现。\n\n````jsx\nimport { Bar } from 'ant-des"
  },
  {
    "path": "src/components/Charts/demo/chart-card.md",
    "chars": 2341,
    "preview": "---\norder: 1\ntitle: 图表卡片\n---\n\n用于展示图表的卡片容器,可以方便的配合其它图表套件展示丰富信息。\n\n```jsx\nimport { ChartCard, yuan, Field } from 'ant-desig"
  },
  {
    "path": "src/components/Charts/demo/gauge.md",
    "chars": 230,
    "preview": "---\norder: 7\ntitle: 仪表盘 \n---\n\n仪表盘是一种进度展示方式,可以更直观的展示当前的进展情况,通常也可表示占比。\n\n````jsx\nimport { Gauge } from 'ant-design-pro/lib/"
  },
  {
    "path": "src/components/Charts/demo/mini-area.md",
    "chars": 501,
    "preview": "---\norder: 2\ncol: 2\ntitle: 迷你区域图\n---\n\n````jsx\nimport { MiniArea } from 'ant-design-pro/lib/Charts';\nimport moment from '"
  },
  {
    "path": "src/components/Charts/demo/mini-bar.md",
    "chars": 516,
    "preview": "---\norder: 2\ncol: 2\ntitle: 迷你柱状图\n---\n\n迷你柱状图更适合展示简单的区间数据,简洁的表现方式可以很好的减少大数据量的视觉展现压力。\n\n````jsx\nimport { MiniBar } from 'ant"
  },
  {
    "path": "src/components/Charts/demo/mini-pie.md",
    "chars": 250,
    "preview": "---\norder: 6\ntitle: 迷你饼状图\n---\n\n通过简化 `Pie` 属性的设置,可以快速的实现极简的饼状图,可配合 `ChartCard` 组合展\n现更多业务场景。\n\n```jsx\nimport { Pie } from '"
  },
  {
    "path": "src/components/Charts/demo/mini-progress.md",
    "chars": 194,
    "preview": "---\norder: 3\ntitle: 迷你进度条\n---\n\n````jsx\nimport { MiniProgress } from 'ant-design-pro/lib/Charts';\n\nReactDOM.render(\n  <Mi"
  },
  {
    "path": "src/components/Charts/demo/mix.md",
    "chars": 2269,
    "preview": "---\norder: 0\ntitle: 图表套件组合展示\n---\n\n利用 Ant Design Pro 提供的图表套件,可以灵活组合符合设计规范的图表来满足复杂的业务需求。\n\n````jsx\nimport { ChartCard, Fiel"
  },
  {
    "path": "src/components/Charts/demo/pie.md",
    "chars": 728,
    "preview": "---\norder: 5\ntitle: 饼状图\n---\n\n```jsx\nimport { Pie, yuan } from 'ant-design-pro/lib/Charts';\n\nconst salesPieData = [\n  {\n "
  },
  {
    "path": "src/components/Charts/demo/radar.md",
    "chars": 942,
    "preview": "---\norder: 7\ntitle: 雷达图\n---\n\n````jsx\nimport { Radar, ChartCard } from 'ant-design-pro/lib/Charts';\n\nconst radarOriginDat"
  },
  {
    "path": "src/components/Charts/demo/tag-cloud.md",
    "chars": 405,
    "preview": "---\norder: 9\ntitle: 标签云\n---\n\n标签云是一套相关的标签以及与此相应的权重展示方式,一般典型的标签云有 30 至 150 个标签,而权重影响使用的字体大小或其他视觉效果。\n\n````jsx\nimport { TagC"
  },
  {
    "path": "src/components/Charts/demo/timeline-chart.md",
    "chars": 562,
    "preview": "---\norder: 9\ntitle: 带有时间轴的图表\n---\n\n使用 `TimelineChart` 组件可以实现带有时间轴的柱状图展现,而其中的 `x` 属性,则是时间值的指向,默认最多支持同时展现两个指标,分别是 `y1` 和 `y"
  },
  {
    "path": "src/components/Charts/demo/waterwave.md",
    "chars": 291,
    "preview": "---\norder: 8\ntitle: 水波图 \n---\n\n水波图是一种比例的展示方式,可以更直观的展示关键值的占比。\n\n````jsx\nimport { WaterWave } from 'ant-design-pro/lib/Chart"
  },
  {
    "path": "src/components/Charts/g2.js",
    "chars": 200,
    "preview": "// 全局 G2 设置\nimport { track, setTheme } from 'bizcharts';\n\ntrack(false);\n\nconst config = {\n  defaultColor: '#1089ff',\n  s"
  },
  {
    "path": "src/components/Charts/index.d.ts",
    "chars": 693,
    "preview": "import * as numeral from 'numeral';\nexport { default as ChartCard } from './ChartCard';\nexport { default as Bar } from '"
  },
  {
    "path": "src/components/Charts/index.js",
    "chars": 845,
    "preview": "import numeral from 'numeral';\nimport './g2';\nimport ChartCard from './ChartCard';\nimport Bar from './Bar';\nimport Pie f"
  },
  {
    "path": "src/components/Charts/index.less",
    "chars": 297,
    "preview": ".miniChart {\n  position: relative;\n  width: 100%;\n  .chartContent {\n    position: absolute;\n    bottom: -28px;\n    width"
  },
  {
    "path": "src/components/Charts/index.md",
    "chars": 5104,
    "preview": "---\ntitle:\n  en-US: Charts\n  zh-CN: Charts\nsubtitle: 图表\norder: 2\ncols: 2\n---\n\nAnt Design Pro 提供的业务中常用的图表类型,都是基于 [G2](htt"
  },
  {
    "path": "src/components/Exception/demo/403.md",
    "chars": 404,
    "preview": "---\norder: 2\ntitle:\n  zh-CN: 403\n  en-US: 403\n---\n\n## zh-CN\n\n403 页面,配合自定义操作。\n\n## en-US\n\n403 page with custom operations."
  },
  {
    "path": "src/components/Exception/demo/404.md",
    "chars": 217,
    "preview": "---\norder: 0\ntitle:\n  zh-CN: 404\n  en-US: 404\n---\n\n## zh-CN\n\n404 页面。\n\n## en-US\n\n404 page.\n\n````jsx\nimport Exception from"
  },
  {
    "path": "src/components/Exception/demo/500.md",
    "chars": 217,
    "preview": "---\norder: 1\ntitle:\n  zh-CN: 500\n  en-US: 500\n---\n\n## zh-CN\n\n500 页面。\n\n## en-US\n\n500 page.\n\n````jsx\nimport Exception from"
  },
  {
    "path": "src/components/Exception/index.d.ts",
    "chars": 417,
    "preview": "import * as React from 'react';\nexport interface IExceptionProps {\n  type?: '403' | '404' | '500';\n  title?: React.React"
  },
  {
    "path": "src/components/Exception/index.en-US.md",
    "chars": 960,
    "preview": "---\ntitle: Exception\ncols: 1\norder: 5\n---\n\nExceptions page is used to provide feedback on specific abnormal state. Usual"
  },
  {
    "path": "src/components/Exception/index.js",
    "chars": 1509,
    "preview": "import React, { createElement } from 'react';\nimport classNames from 'classnames';\nimport { Button } from 'antd';\nimport"
  },
  {
    "path": "src/components/Exception/index.less",
    "chars": 1433,
    "preview": "@import '~antd/lib/style/themes/default.less';\n\n.exception {\n  display: flex;\n  align-items: center;\n  height: 80%;\n  mi"
  },
  {
    "path": "src/components/Exception/index.zh-CN.md",
    "chars": 626,
    "preview": "---\ntitle: Exception\nsubtitle: 异常\ncols: 1\norder: 5\n---\n\n异常页用于对页面特定的异常状态进行反馈。通常,它包含对错误状态的阐述,并向用户提供建议或操作,避免用户感到迷失和困惑。\n\n## "
  },
  {
    "path": "src/components/Exception/typeConfig.js",
    "chars": 454,
    "preview": "const config = {\n  403: {\n    img: 'https://gw.alipayobjects.com/zos/rmsportal/wZcnGqRDyhPOEYFcZDnb.svg',\n    title: '40"
  },
  {
    "path": "src/components/FooterToolbar/demo/basic.md",
    "chars": 1102,
    "preview": "---\norder: 0\ntitle:\n  zh-CN: 演示\n  en-US: demo\niframe: 400\n---\n\n## zh-CN\n\n浮动固定页脚。\n\n## en-US\n\nFixed to the footer.\n\n````js"
  },
  {
    "path": "src/components/FooterToolbar/index.d.ts",
    "chars": 219,
    "preview": "import * as React from 'react';\nexport interface IFooterToolbarProps {\n  extra: React.ReactNode;\n  style?: React.CSSProp"
  },
  {
    "path": "src/components/FooterToolbar/index.en-US.md",
    "chars": 465,
    "preview": "---\ntitle: FooterToolbar\ncols: 1\norder: 6\n---\n\nA toolbar fixed at the bottom.\n\n## Usage\n\nIt is fixed at the bottom of th"
  },
  {
    "path": "src/components/FooterToolbar/index.js",
    "chars": 1264,
    "preview": "import React, { Component } from 'react';\nimport PropTypes from 'prop-types';\nimport classNames from 'classnames';\nimpor"
  },
  {
    "path": "src/components/FooterToolbar/index.less",
    "chars": 485,
    "preview": "@import '~antd/lib/style/themes/default.less';\n\n.toolbar {\n  position: fixed;\n  width: 100%;\n  bottom: 0;\n  right: 0;\n  "
  },
  {
    "path": "src/components/FooterToolbar/index.zh-CN.md",
    "chars": 246,
    "preview": "---\ntitle: FooterToolbar\nsubtitle: 底部工具栏\ncols: 1\norder: 6\n---\n\n固定在底部的工具栏。\n\n## 何时使用\n\n固定在内容区域的底部,不随滚动条移动,常用于长页面的数据搜集和提交工作。"
  },
  {
    "path": "src/components/GlobalFooter/demo/basic.md",
    "chars": 689,
    "preview": "---\norder: 0\ntitle: 演示\niframe: 400\n---\n\n基本页脚。\n\n````jsx\nimport GlobalFooter from 'ant-design-pro/lib/GlobalFooter';\nimpor"
  },
  {
    "path": "src/components/GlobalFooter/index.d.ts",
    "chars": 336,
    "preview": "import * as React from 'react';\nexport interface IGlobalFooterProps {\n  links?: Array<{\n    key?: string;\n    title: Rea"
  },
  {
    "path": "src/components/GlobalFooter/index.js",
    "chars": 740,
    "preview": "import React from 'react';\nimport classNames from 'classnames';\nimport styles from './index.less';\n\nconst GlobalFooter ="
  },
  {
    "path": "src/components/GlobalFooter/index.less",
    "chars": 454,
    "preview": "@import '~antd/lib/style/themes/default.less';\n\n.globalFooter {\n  padding: 0 16px;\n  margin: 48px 0 24px 0;\n  text-align"
  },
  {
    "path": "src/components/GlobalFooter/index.md",
    "chars": 300,
    "preview": "---\ntitle:\n  en-US: GlobalFooter\n  zh-CN: GlobalFooter\nsubtitle: 全局页脚\ncols: 1\norder: 7\n---\n\n页脚属于全局导航的一部分,作为对顶部导航的补充,通过传递"
  },
  {
    "path": "src/components/GlobalHeader/RightContent.js",
    "chars": 4759,
    "preview": "import React, { PureComponent } from 'react';\nimport { FormattedMessage, formatMessage } from 'umi/locale';\nimport { Spi"
  },
  {
    "path": "src/components/GlobalHeader/index.js",
    "chars": 1221,
    "preview": "import React, { PureComponent } from 'react';\nimport { Icon } from 'antd';\nimport Link from 'umi/link';\nimport Debounce "
  },
  {
    "path": "src/components/GlobalHeader/index.less",
    "chars": 2224,
    "preview": "@import '~antd/lib/style/themes/default.less';\n\n@pro-header-hover-bg: rgba(0, 0, 0, 0.025);\n\n.header {\n  height: 64px;\n "
  },
  {
    "path": "src/components/Login/LoginItem.js",
    "chars": 3355,
    "preview": "import React, { Component } from 'react';\nimport { Form, Input, Button, Row, Col } from 'antd';\nimport omit from 'omit.j"
  },
  {
    "path": "src/components/Login/LoginSubmit.js",
    "chars": 448,
    "preview": "import React from 'react';\nimport classNames from 'classnames';\nimport { Button, Form } from 'antd';\nimport styles from "
  },
  {
    "path": "src/components/Login/LoginTab.js",
    "chars": 840,
    "preview": "import React, { Component } from 'react';\nimport { Tabs } from 'antd';\nimport LoginContext from './loginContext';\n\nconst"
  },
  {
    "path": "src/components/Login/demo/basic.md",
    "chars": 3125,
    "preview": "---\norder: 0\ntitle:\n  zh-CN: 标准登录\n  en-US: Standard Login\n---\n\nSupport login with account and mobile number.\n\n````jsx\nim"
  },
  {
    "path": "src/components/Login/index.d.ts",
    "chars": 915,
    "preview": "import * as React from 'react';\nimport Button from 'antd/lib/button';\nexport interface LoginProps {\n  defaultActiveKey?:"
  },
  {
    "path": "src/components/Login/index.en-US.md",
    "chars": 1645,
    "preview": "---\ntitle: Login\ncols: 1\norder: 15\n---\n\nSupport multiple common ways of login with built-in controls. You can choose you"
  },
  {
    "path": "src/components/Login/index.js",
    "chars": 3192,
    "preview": "import React, { Component } from 'react';\nimport PropTypes from 'prop-types';\nimport { Form, Tabs } from 'antd';\nimport "
  },
  {
    "path": "src/components/Login/index.less",
    "chars": 722,
    "preview": "@import '~antd/lib/style/themes/default.less';\n\n.login {\n  :global {\n    .ant-tabs .ant-tabs-bar {\n      border-bottom: "
  },
  {
    "path": "src/components/Login/index.zh-CN.md",
    "chars": 1096,
    "preview": "---\ntitle: Login\nsubtitle: 登录\ncols: 1\norder: 15\n---\n\n支持多种登录方式切换,内置了几种常见的登录控件,可以灵活组合,也支持和自定义控件配合使用。\n\n## API\n\n### Login\n\n参"
  },
  {
    "path": "src/components/Login/loginContext.js",
    "chars": 107,
    "preview": "import { createContext } from 'react';\n\nconst LoginContext = createContext();\nexport default LoginContext;\n"
  },
  {
    "path": "src/components/Login/map.js",
    "chars": 1277,
    "preview": "import React from 'react';\nimport { Icon } from 'antd';\nimport styles from './index.less';\n\nexport default {\n  UserName:"
  },
  {
    "path": "src/components/NoticeIcon/NoticeIconTab.d.ts",
    "chars": 554,
    "preview": "import * as React from 'react';\nexport interface INoticeIconData {\n  avatar?: string|React.ReactNode;\n  title?: React.Re"
  },
  {
    "path": "src/components/NoticeIcon/NoticeList.js",
    "chars": 2045,
    "preview": "import React from 'react';\nimport { Avatar, List } from 'antd';\nimport classNames from 'classnames';\nimport styles from "
  },
  {
    "path": "src/components/NoticeIcon/NoticeList.less",
    "chars": 1401,
    "preview": "@import '~antd/lib/style/themes/default.less';\n\n.list {\n  max-height: 400px;\n  overflow: auto;\n  .item {\n    transition:"
  },
  {
    "path": "src/components/NoticeIcon/demo/basic.md",
    "chars": 167,
    "preview": "---\norder: 1\ntitle: 通知图标\n---\n\n通常用在导航工具栏上。\n\n````jsx\nimport NoticeIcon from 'ant-design-pro/lib/NoticeIcon';\n\nReactDOM.ren"
  },
  {
    "path": "src/components/NoticeIcon/demo/popover.md",
    "chars": 4255,
    "preview": "---\norder: 2\ntitle: 带浮层卡片\n---\n\n点击展开通知卡片,展现多种类型的通知,通常放在导航工具栏。\n\n````jsx\nimport NoticeIcon from 'ant-design-pro/lib/NoticeI"
  },
  {
    "path": "src/components/NoticeIcon/index.d.ts",
    "chars": 896,
    "preview": "import * as React from 'react';\nimport NoticeIconTab, { INoticeIconData } from './NoticeIconTab';\n\nexport interface INot"
  },
  {
    "path": "src/components/NoticeIcon/index.en-US.md",
    "chars": 1665,
    "preview": "---\ntitle: NoticeIcon\nsubtitle: Notification Menu\ncols: 1\norder: 9\n---\n\n用在导航工具栏上,作为整个产品统一的通知中心。\n\n## API\n\nProperty | Desc"
  },
  {
    "path": "src/components/NoticeIcon/index.js",
    "chars": 2853,
    "preview": "import React, { PureComponent } from 'react';\nimport { Popover, Icon, Tabs, Badge, Spin } from 'antd';\nimport classNames"
  },
  {
    "path": "src/components/NoticeIcon/index.less",
    "chars": 389,
    "preview": "@import '~antd/lib/style/themes/default.less';\n\n.popover {\n  width: 336px;\n  :global(.ant-popover-inner-content) {\n    p"
  },
  {
    "path": "src/components/NoticeIcon/index.zh-CN.md",
    "chars": 1226,
    "preview": "---\ntitle: NoticeIcon\nsubtitle: 通知菜单\ncols: 1\norder: 9\n---\n\n用在导航工具栏上,作为整个产品统一的通知中心。\n\n## API\n\n参数 | 说明 | 类型 | 默认值\n----|----"
  },
  {
    "path": "src/components/PageHeader/breadcrumb.d.ts",
    "chars": 242,
    "preview": "import * as React from 'react';\nimport { IPageHeaderProps } from './index'\n\nexport default class BreadcrumbView extends "
  },
  {
    "path": "src/components/PageHeader/breadcrumb.js",
    "chars": 5126,
    "preview": "import React, { PureComponent, createElement } from 'react';\nimport pathToRegexp from 'path-to-regexp';\nimport { Breadcr"
  },
  {
    "path": "src/components/PageHeader/demo/image.md",
    "chars": 1611,
    "preview": "---\norder: 2\ntitle: With Image\n---\n\n带图片的页头。\n\n````jsx\nimport PageHeader from 'ant-design-pro/lib/PageHeader';\n\nconst cont"
  },
  {
    "path": "src/components/PageHeader/demo/simple.md",
    "chars": 448,
    "preview": "---\norder: 3\ntitle: Simple\n---\n\n简单的页头。\n\n````jsx\nimport PageHeader from 'ant-design-pro/lib/PageHeader';\n\nconst breadcrum"
  },
  {
    "path": "src/components/PageHeader/demo/standard.md",
    "chars": 2223,
    "preview": "---\norder: 1\ntitle: Standard\n---\n\n标准页头。\n\n````jsx\nimport PageHeader from 'ant-design-pro/lib/PageHeader';\nimport Descript"
  },
  {
    "path": "src/components/PageHeader/demo/structure.md",
    "chars": 1414,
    "preview": "---\norder: 0\ntitle: Structure\n---\n\n基本结构,具备响应式布局功能,主要断点为 768px 和 576px,拖动窗口改变大小试试看。\n\n````jsx\nimport PageHeader from 'ant-"
  },
  {
    "path": "src/components/PageHeader/index.d.ts",
    "chars": 758,
    "preview": "import * as React from 'react';\nexport interface IPageHeaderProps {\n  title?: React.ReactNode | string;\n  logo?: React.R"
  },
  {
    "path": "src/components/PageHeader/index.js",
    "chars": 2501,
    "preview": "import React, { PureComponent } from 'react';\nimport { Tabs, Skeleton } from 'antd';\nimport classNames from 'classnames'"
  },
  {
    "path": "src/components/PageHeader/index.less",
    "chars": 2360,
    "preview": "@import '~antd/lib/style/themes/default.less';\n\n.pageHeader {\n  background: @component-background;\n  padding: 16px 32px "
  },
  {
    "path": "src/components/PageHeader/index.md",
    "chars": 1663,
    "preview": "---\ntitle:\n  en-US: PageHeader\n  zh-CN: PageHeader\nsubtitle: 页头\ncols: 1\norder: 11\n---\n\n页头用来声明页面的主题,包含了用户所关注的最重要的信息,使用户可以"
  },
  {
    "path": "src/components/PageHeader/index.test.js",
    "chars": 1290,
    "preview": "import { getBreadcrumb } from './breadcrumb';\nimport { urlToList } from '../_utils/pathTools';\n\nconst routerData = {\n  '"
  },
  {
    "path": "src/components/PageHeaderWrapper/GridContent.js",
    "chars": 518,
    "preview": "import React, { PureComponent } from 'react';\nimport { connect } from 'dva';\nimport styles from './GridContent.less';\n\nc"
  },
  {
    "path": "src/components/PageHeaderWrapper/GridContent.less",
    "chars": 139,
    "preview": ".main {\n  width: 100%;\n  height: 100%;\n  min-height: 100%;\n  transition: 0.3s;\n  &.wide {\n    max-width: 1200px;\n    mar"
  },
  {
    "path": "src/components/PageHeaderWrapper/index.js",
    "chars": 1277,
    "preview": "import React from 'react';\nimport { FormattedMessage } from 'umi/locale';\nimport Link from 'umi/link';\nimport PageHeader"
  },
  {
    "path": "src/components/PageHeaderWrapper/index.less",
    "chars": 170,
    "preview": "@import '~antd/lib/style/themes/default.less';\n\n.content {\n  margin: 24px 24px 0;\n}\n\n@media screen and (max-width: @scre"
  },
  {
    "path": "src/components/PageLoading/index.js",
    "chars": 277,
    "preview": "import React from 'react';\nimport { Spin } from 'antd';\n\n// loading components from code split\n// https://umijs.org/plug"
  },
  {
    "path": "src/components/Result/demo/classic.md",
    "chars": 2067,
    "preview": "---\norder: 1\ntitle: Classic\n---\n\n典型结果页面。\n\n````jsx\nimport Result from 'ant-design-pro/lib/Result';\nimport { Button, Row, "
  },
  {
    "path": "src/components/Result/demo/error.md",
    "chars": 902,
    "preview": "---\norder: 2\ntitle: Failed\n---\n\n提交失败。\n\n````jsx\nimport Result from 'ant-design-pro/lib/Result';\nimport { Button, Icon } f"
  },
  {
    "path": "src/components/Result/demo/structure.md",
    "chars": 519,
    "preview": "---\norder: 0\ntitle: Structure\n---\n\n结构包含 `处理结果`,`补充信息` 以及 `操作建议` 三个部分,其中 `处理结果` 由 `提示图标`,`标题` 和 `结果描述` 组成。\n\n````jsx\nimpor"
  },
  {
    "path": "src/components/Result/index.d.ts",
    "chars": 316,
    "preview": "import * as React from 'react';\nexport interface IResultProps {\n  type: 'success' | 'error';\n  title: React.ReactNode;\n "
  },
  {
    "path": "src/components/Result/index.js",
    "chars": 886,
    "preview": "import React from 'react';\nimport classNames from 'classnames';\nimport { Icon } from 'antd';\nimport styles from './index"
  },
  {
    "path": "src/components/Result/index.less",
    "chars": 938,
    "preview": "@import '~antd/lib/style/themes/default.less';\n\n.result {\n  text-align: center;\n  width: 72%;\n  margin: 0 auto;\n  @media"
  },
  {
    "path": "src/components/Result/index.md",
    "chars": 532,
    "preview": "---\ntitle:\n  en-US: Result\n  zh-CN: Result\nsubtitle: 处理结果\ncols: 1\norder: 12\n---\n\n结果页用于对用户进行的一系列任务处理结果进行反馈。\n\n## API\n\n| 参数"
  },
  {
    "path": "src/components/SelectLang/index.js",
    "chars": 1234,
    "preview": "import React, { PureComponent } from 'react';\nimport { FormattedMessage, setLocale, getLocale } from 'umi/locale';\nimpor"
  },
  {
    "path": "src/components/SelectLang/index.less",
    "chars": 200,
    "preview": "@import '~antd/lib/style/themes/default.less';\n\n.menu {\n  :global(.anticon) {\n    margin-right: 8px;\n  }\n  :global(.ant-"
  },
  {
    "path": "src/components/SettingDrawer/BlockChecbox.js",
    "chars": 698,
    "preview": "import React from 'react';\nimport { Tooltip, Icon } from 'antd';\nimport style from './index.less';\n\nconst BlockChecbox ="
  },
  {
    "path": "src/components/SettingDrawer/ThemeColor.js",
    "chars": 1556,
    "preview": "import React from 'react';\nimport { Tooltip, Icon } from 'antd';\nimport { formatMessage } from 'umi/locale';\nimport styl"
  },
  {
    "path": "src/components/SettingDrawer/ThemeColor.less",
    "chars": 376,
    "preview": ".themeColor {\n  overflow: hidden;\n  margin-top: 24px;\n  .title {\n    font-size: 14px;\n    color: rgba(0, 0, 0, 0.65);\n  "
  },
  {
    "path": "src/components/SettingDrawer/index.js",
    "chars": 7740,
    "preview": "import React, { PureComponent } from 'react';\nimport { Select, message, Drawer, List, Switch, Divider, Icon, Button, Ale"
  },
  {
    "path": "src/components/SettingDrawer/index.less",
    "chars": 1250,
    "preview": "@import '~antd/lib/style/themes/default.less';\n\n.content {\n  min-height: 100%;\n  background: #fff;\n  position: relative;"
  },
  {
    "path": "src/components/SiderMenu/BaseMenu.js",
    "chars": 5053,
    "preview": "import React, { PureComponent } from 'react';\nimport { Menu, Icon } from 'antd';\nimport Link from 'umi/link';\nimport isE"
  },
  {
    "path": "src/components/SiderMenu/SiderMenu.js",
    "chars": 3301,
    "preview": "import React, { PureComponent } from 'react';\nimport { Layout } from 'antd';\nimport pathToRegexp from 'path-to-regexp';\n"
  },
  {
    "path": "src/components/SiderMenu/SiderMenu.test.js",
    "chars": 1578,
    "preview": "import { urlToList } from '../_utils/pathTools';\nimport { getFlatMenuKeys, getMenuMatchKeys } from './SiderMenu';\n\nconst"
  },
  {
    "path": "src/components/SiderMenu/index.js",
    "chars": 1000,
    "preview": "import React from 'react';\nimport { Drawer } from 'antd';\nimport SiderMenu from './SiderMenu';\n\n/**\n * Recursively flatt"
  },
  {
    "path": "src/components/SiderMenu/index.less",
    "chars": 2011,
    "preview": "@import '~antd/lib/style/themes/default.less';\n\n@nav-header-height: 64px;\n\n.logo {\n  height: @nav-header-height;\n  posit"
  },
  {
    "path": "src/components/StandardTable/index.js",
    "chars": 3218,
    "preview": "import React, { PureComponent, Fragment } from 'react';\nimport { Table, Alert } from 'antd';\nimport styles from './index"
  },
  {
    "path": "src/components/StandardTable/index.less",
    "chars": 187,
    "preview": "@import '~antd/lib/style/themes/default.less';\n\n.standardTable {\n  :global {\n    .ant-table-pagination {\n      margin-to"
  },
  {
    "path": "src/components/TopNavHeader/index.js",
    "chars": 1540,
    "preview": "import React, { PureComponent } from 'react';\nimport Link from 'umi/link';\nimport RightContent from '../GlobalHeader/Rig"
  },
  {
    "path": "src/components/TopNavHeader/index.less",
    "chars": 1065,
    "preview": ".head {\n  width: 100%;\n  transition: background 0.3s, width 0.2s;\n  height: 64px;\n  padding: 0 12px 0 0;\n  box-shadow: 0"
  },
  {
    "path": "src/components/_utils/pathTools.js",
    "chars": 301,
    "preview": "// /userinfo/2144/id => ['/userinfo','/useinfo/2144,'/userindo/2144/id']\n// eslint-disable-next-line import/prefer-defau"
  },
  {
    "path": "src/components/_utils/pathTools.test.js",
    "chars": 457,
    "preview": "import { urlToList } from './pathTools';\n\ndescribe('test urlToList', () => {\n  it('A path', () => {\n    expect(urlToList"
  },
  {
    "path": "src/defaultSettings.js",
    "chars": 408,
    "preview": "module.exports = {\n  navTheme: 'dark', // theme for nav menu\n  primaryColor: '#1890FF', // primary color of ant design\n "
  },
  {
    "path": "src/e2e/home.e2e.js",
    "chars": 526,
    "preview": "import puppeteer from 'puppeteer';\n\ndescribe('Homepage', () => {\n  it('it should have logo text', async () => {\n    cons"
  },
  {
    "path": "src/e2e/login.e2e.js",
    "chars": 1330,
    "preview": "import puppeteer from 'puppeteer';\n\ndescribe('Login', () => {\n  let browser;\n  let page;\n\n  beforeAll(async () => {\n    "
  },
  {
    "path": "src/global.less",
    "chars": 509,
    "preview": "html,\nbody,\n#root {\n  height: 100%;\n}\n\n.colorWeak {\n  filter: invert(80%);\n}\n\n.ant-layout {\n  min-height: 100vh;\n}\n\ncanv"
  },
  {
    "path": "src/layouts/BasicLayout.js",
    "chars": 7678,
    "preview": "import React from 'react';\nimport { Layout } from 'antd';\nimport DocumentTitle from 'react-document-title';\nimport isEqu"
  },
  {
    "path": "src/layouts/BlankLayout.js",
    "chars": 72,
    "preview": "import React from 'react';\n\nexport default props => <div {...props} />;\n"
  }
]

// ... and 81 more files (download for full content)

About this extraction

This page contains the full source code of the biaochenxuying/blog-react-admin GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 281 files (551.1 KB), approximately 161.8k tokens, and a symbol index with 541 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!