Commit 59636700 authored by super-lin0's avatar super-lin0

Add antd pro

parent e24738e4
{ {
"name": "nemean-cli", "name": "nemean-cli",
"version": "0.1.5", "version": "0.2.7",
"main": "src/index.js", "main": "src/index.js",
"bin": "bin/npmrc.js", "bin": "bin/npmrc.js",
"license": "ISC", "license": "ISC",
......
...@@ -24,7 +24,7 @@ class Factory { ...@@ -24,7 +24,7 @@ class Factory {
switch (this.type) { switch (this.type) {
case "web": case "web":
break; break;
case "mobile": case "pro":
break; break;
default: default:
Factory.log("未知类型", "red"); Factory.log("未知类型", "red");
...@@ -34,6 +34,7 @@ class Factory { ...@@ -34,6 +34,7 @@ class Factory {
filter: src => { filter: src => {
return ( return (
!(src.indexOf("package.json") >= 0) && !(src.indexOf("package.json") >= 0) &&
!(src.indexOf("package-lock.json") >= 0) &&
!(src.indexOf("eslintrc") >= 0) && !(src.indexOf("eslintrc") >= 0) &&
!(src.indexOf("README.md") >= 0) && !(src.indexOf("README.md") >= 0) &&
!(src.indexOf("gitignore") >= 0) !(src.indexOf("gitignore") >= 0)
...@@ -56,7 +57,7 @@ class Factory { ...@@ -56,7 +57,7 @@ class Factory {
case "web": case "web":
temPackage = fs.readJSONSync(`${this.CUR_POJ_PATH}package.json`); temPackage = fs.readJSONSync(`${this.CUR_POJ_PATH}package.json`);
break; break;
case "mobile": case "pro":
temPackage = fs.readJSONSync(`${this.CUR_POJ_PATH}/package.json`); temPackage = fs.readJSONSync(`${this.CUR_POJ_PATH}/package.json`);
break; break;
default: default:
...@@ -111,11 +112,6 @@ class Factory { ...@@ -111,11 +112,6 @@ class Factory {
} }
}); });
if (curPackage.dependencies && curPackage.dependencies["nemean-cli"]) {
Factory.log("删除nemean-cli包");
delete curPackage.dependencies["nemean-cli"];
}
// scripts // scripts
// 暂时不考虑覆盖问题 // 暂时不考虑覆盖问题
curPackage.scripts = temPackage.scripts; curPackage.scripts = temPackage.scripts;
...@@ -125,6 +121,15 @@ class Factory { ...@@ -125,6 +121,15 @@ class Factory {
// pre commit // pre commit
curPackage["pre-commit"] = temPackage["pre-commit"]; curPackage["pre-commit"] = temPackage["pre-commit"];
Factory.log("============================ \n", "yellow");
Factory.log(JSON.stringify(curPackage.dependencies), "yellow");
Factory.log("============================ \n", "yellow");
if (curPackage.dependencies && curPackage.dependencies["nemean-cli"]) {
Factory.log("删除nemean-cli包");
delete curPackage.dependencies["nemean-cli"];
}
fs.writeJSONSync(`${PRO_PATH}/package.json`, curPackage, { fs.writeJSONSync(`${PRO_PATH}/package.json`, curPackage, {
spaces: 2 spaces: 2
}); });
...@@ -132,19 +137,15 @@ class Factory { ...@@ -132,19 +137,15 @@ class Factory {
// 后续工作 // 后续工作
callBack() { callBack() {
if (this.SYS_TYPE && this.SYS_TYPE.toLowerCase().indexOf("window") > 0) { Factory.log("开始卸载nemean-cli依赖 \n");
// windows shell.exec("npm uninstall nemean-cli --save");
} else {
Factory.log("开始安装依赖 \n");
shell.exec("cnpm i --registry=http://101.132.127.199:7001");
}
} }
start() { start() {
try { try {
this.copyFile(); // copy核心文件 this.copyFile(); // copy核心文件
this.trimPackage(); // 处理依赖 this.trimPackage(); // 处理依赖
// this.callBack(); // 执行后续 this.callBack(); // 执行后续
} catch (e) { } catch (e) {
Factory.log("构建失败" + e, "red"); Factory.log("构建失败" + e, "red");
} }
...@@ -160,8 +161,8 @@ module.exports = function begin() { ...@@ -160,8 +161,8 @@ module.exports = function begin() {
message: "请选择项目类型:", message: "请选择项目类型:",
pageSize: 2, pageSize: 2,
choices: [ choices: [
{ name: "Ant Design Pro", value: "web" } { name: "app", value: "web" },
// { name: "Mobile端项目", value: "mobile" }, { name: "Ant design pro", value: "pro" }
] ]
} }
]; ];
......
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
**/node_modules
/src/utils/request-temp.js
# 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
\ No newline at end of file
# 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
/lambda/
/scripts
/config
.history
\ No newline at end of file
module.exports = {
extends: [require.resolve('@umijs/fabric/dist/eslint')],
globals: {
ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION: true,
page: true,
},
};
---
name: '报告Bug 🐛'
about: 报告 Ant Design Pro 的 bug
title: '[BUG]'
labels: bug
assignees: ''
---
**bug 描述** [详细地描述 bug,让大家都能理解]
**复现步骤** [清晰描述复现步骤,让别人也能看到问题]
**期望结果** [描述你原本期望看到的结果]
**复现代码** [提供可复现的代码,仓库,或线上示例]
**版本信息:**
- Ant Design Pro 版本: [e.g. 4.0.0]
- umi 版本
- 浏览器环境
- 开发环境 [e.g. mac OS]
**其他信息** [如截图等其他信息可以贴在这里]
---
name: '功能需求 ✨'
about: 对 Ant Design Pro 的需求或建议
title: '[需求]'
labels: feature
assignees: ''
---
**需求描述** [详细地描述需求,让大家都能理解]
**解决方案** [如果你有解决方案,在这里清晰地阐述]
**其他信息** [如截图等其他信息可以贴在这里]
---
name: '疑问或需要帮助 ❓'
about: 对 Ant Design Pro 使用的疑问或需要帮助
title: '[问题]'
labels: question
assignees: ''
---
**问题描述** [详细地描述问题,让大家都能理解]
**示例代码** [如果有必要,展示代码,线上示例,或仓库]
**其他信息** [如截图等其他信息可以贴在这里]
# 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/*
.temp/**
# umi
.umi
.umi-production
# screenshot
screenshot
.firebase
.eslintcache
build
ports:
- port: 8000
onOpen: open-preview
tasks:
- init: npm install
command: npm start
**/*.svg
package.json
.umi
.umi-production
/dist
.dockerignore
.DS_Store
.eslintignore
*.png
*.toml
docker
.editorconfig
Dockerfile*
.gitignore
.prettierignore
LICENSE
.eslintcache
*.lock
yarn-error.log
.history
\ No newline at end of file
const fabric = require('@umijs/fabric');
module.exports = {
...fabric.prettier,
};
const fabric = require('@umijs/fabric');
module.exports = {
...fabric.stylelint,
};
preview.pro.ant.design
\ No newline at end of file
# 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/
FROM circleci/node:latest-browsers
WORKDIR /usr/src/app/
USER root
COPY package.json ./
RUN yarn
COPY ./ ./
RUN npm run test:all
RUN npm run fetch:blocks
CMD ["npm", "run", "build"]
FROM node:latest
WORKDIR /usr/src/app/
COPY package.json ./
RUN npm install --silent --no-cache --registry=https://registry.npm.taobao.org
COPY ./ ./
RUN npm run fetch:blocks
CMD ["npm", "run", "start"]
FROM circleci/node:latest-browsers as builder
WORKDIR /usr/src/app/
USER root
COPY package.json ./
RUN yarn
COPY ./ ./
RUN npm run test:all
RUN npm run fetch:blocks
RUN npm run build
FROM nginx
WORKDIR /usr/share/nginx/html/
COPY ./docker/nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=builder /usr/src/app/dist /usr/share/nginx/html/
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
\ No newline at end of file
MIT License
Copyright (c) 2019 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.
[English](./README.md) | [简体中文](./README.zh-CN.md) | [Русский](./README.ru-RU.md) | [Türkçe](./README.tr-TR.md) | [日本語](./README.ja-JP.md) | Français
<h1 align="center">Ant Design Pro</h1>
<div align="center">
Une solution UI prête à l'emploi pour des applications d'entreprise en tant que modèle React.
[![Construit avec Umi](https://img.shields.io/badge/build%20with-umi-028fe4.svg?style=flat-square)](http://umijs.org/) [![Status de la construction](https://dev.azure.com/ant-design/ant-design-pro/_apis/build/status/ant-design.ant-design-pro?branchName=master)](https://dev.azure.com/ant-design/ant-design-pro/_build/latest?definitionId=1?branchName=master) [![Dépendences](https://img.shields.io/david/ant-design/ant-design-pro.svg)](https://david-dm.org/ant-design/ant-design-pro) [![Dépendences de développement](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://img.shields.io/gitter/room/ant-design/pro-english.svg?style=flat-square&logoWidth=20&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4NCjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgd2lkdGg9IjEyMzUiIGhlaWdodD0iNjUwIiB2aWV3Qm94PSIwIDAgNzQxMCAzOTAwIj4NCjxyZWN0IHdpZHRoPSI3NDEwIiBoZWlnaHQ9IjM5MDAiIGZpbGw9IiNiMjIyMzQiLz4NCjxwYXRoIGQ9Ik0wLDQ1MEg3NDEwbTAsNjAwSDBtMCw2MDBINzQxMG0wLDYwMEgwbTAsNjAwSDc0MTBtMCw2MDBIMCIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjMwMCIvPg0KPHJlY3Qgd2lkdGg9IjI5NjQiIGhlaWdodD0iMjEwMCIgZmlsbD0iIzNjM2I2ZSIvPg0KPGcgZmlsbD0iI2ZmZiI%2BDQo8ZyBpZD0iczE4Ij4NCjxnIGlkPSJzOSI%2BDQo8ZyBpZD0iczUiPg0KPGcgaWQ9InM0Ij4NCjxwYXRoIGlkPSJzIiBkPSJNMjQ3LDkwIDMxNy41MzQyMzAsMzA3LjA4MjAzOSAxMzIuODczMjE4LDE3Mi45MTc5NjFIMzYxLjEyNjc4MkwxNzYuNDY1NzcwLDMwNy4wODIwMzl6Ii8%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzIiB5PSI0MjAiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3MiIHk9Ijg0MCIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgeT0iMTI2MCIvPg0KPC9nPg0KPHVzZSB4bGluazpocmVmPSIjcyIgeT0iMTY4MCIvPg0KPC9nPg0KPHVzZSB4bGluazpocmVmPSIjczQiIHg9IjI0NyIgeT0iMjEwIi8%2BDQo8L2c%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzOSIgeD0iNDk0Ii8%2BDQo8L2c%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzMTgiIHg9Ijk4OCIvPg0KPHVzZSB4bGluazpocmVmPSIjczkiIHg9IjE5NzYiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3M1IiB4PSIyNDcwIi8%2BDQo8L2c%2BDQo8L3N2Zz4%3D)](https://gitter.im/ant-design/pro-english?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![Rejoignez la discussion dans https://gitter.im/ant-design/ant-design-pro](https://img.shields.io/gitter/room/ant-design/ant-design-pro.svg?style=flat-square&logoWidth=20&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4NCjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgd2lkdGg9IjkwMCIgaGVpZ2h0PSI2MDAiIHZpZXdCb3g9IjAgMCAzMCAyMCI%2BDQo8ZGVmcz4NCjxwYXRoIGlkPSJzIiBkPSJNMCwtMSAwLjU4Nzc4NSwwLjgwOTAxNyAtMC45NTEwNTcsLTAuMzA5MDE3SDAuOTUxMDU3TC0wLjU4Nzc4NSwwLjgwOTAxN3oiIGZpbGw9IiNmZmRlMDAiLz4NCjwvZGVmcz4NCjxyZWN0IHdpZHRoPSIzMCIgaGVpZ2h0PSIyMCIgZmlsbD0iI2RlMjkxMCIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNSw1KSBzY2FsZSgzKSIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTAsMikgcm90YXRlKDIzLjAzNjI0MykiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3MiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDEyLDQpIHJvdGF0ZSg0NS44Njk4OTgpIi8%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMiw3KSByb3RhdGUoNjkuOTQ1Mzk2KSIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTAsOSkgcm90YXRlKDIwLjY1OTgwOCkiLz4NCjwvc3ZnPg%3D%3D)](https://gitter.im/ant-design/ant-design-pro?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![Netlify Status](https://api.netlify.com/api/v1/badges/f2fd24cf-5fa1-4a80-be3a-0dbe72b44c90/deploy-status)](https://app.netlify.com/sites/ant-design-pro/deploys) ![](https://badgen.net/badge/icon/Ant%20Design?icon=https://gw.alipayobjects.com/zos/antfincdn/Pp4WPgVDB3/KDpgvguMpGfqaHPjicRK.svg&label)
![](https://user-images.githubusercontent.com/8186664/44953195-581e3d80-aec4-11e8-8dcb-54b9db38ec11.png)
</div>
- Aperçu: http://preview.pro.ant.design
- Page d'accueil: http://pro.ant.design
- Documentation: http://pro.ant.design/docs/getting-started
- ChangeLog: http://pro.ant.design/docs/changelog
- FAQ: http://pro.ant.design/docs/faq
- Site mirroir en Chine: http://ant-design-pro.gitee.io
## 2.0 Sorti maintenant! 🎉🎉🎉
[Annoncement de Ant Design Pro 2.0.0](https://medium.com/ant-design/beautiful-and-powerful-ant-design-pro-2-0-release-51358da5af95)
## Recrutement pour la traduction :loudspeaker:
Nous avons besoin de votre aide: https://github.com/ant-design/ant-design-pro/issues/120
## Fonctionnalités
- :gem: **Design soigné**: Suit [la spécification Ant Design](http://ant.design/)
- :triangular_ruler: **Modèles communs**: Modèles typiques d'application d'entreprise
- :rocket: **Développement dernier cri**: Infrastructure de développement de React/umi/dva/antd la plus récente
- :iphone: **Design adapté**: Conçu pour des tailles d'écran variables
- :art: **Thématisation**: Thème personnalisable avec configuration simple
- :globe_with_meridians: **International**: Solution i18n intégrée
- :gear: **Meilleures pratiques**: Flux de travail solide pour rendre votre code sain
- :1234: **Développement simulé**: Solution de développement simulée facile à utiliser
- :white_check_mark: **Tests UI**: Volez en toute sécurité avec les tests unitaires et e2e
## Modèles
```
- Tableau de bord
- Analytique
- Moniteur
- Espace de travail
- Formulaire
- Formulaire de base
- Formulaire par étape
- Formulaire avancé
- Liste
- Tableau standard
- Liste standard
- Liste de cartes
- Liste de recherche (Projet/Applications/Article)
- Profil
- Profil simple
- Profil avancé
- Compte
- Centre du compte
- Paramètres du compte
- Résultat
- Succès
- Échec
- Exception
- 403
- 404
- 500
- Utilisateur
- Connexion
- S'inscrire
- Résultat de l'inscription
```
## Utilisation
### Utiliser bash
```bash
$ yarn create umi # or npm create umi
# Choose ant-design-pro:
Select the boilerplate type (Use arrow keys)
❯ ant-design-pro - Create project with an layout-only ant-design-pro boilerplate, use together with umi block.
app - Create project with a simple boilerplate, support typescript.
block - Create a umi block.
library - Create a library with umi.
plugin - Create a umi plugin.
$ npm install
$ npm start # visit http://localhost:8000
```
### Utilisation de Gitpod
Ouvrez le projet avec Gitpod (environnement de développement gratuit pour GitHub) et commencez à coder immédiatement.
[![Ouvrir dans Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/ant-design/ant-design-pro)
Plus d'instructions dans la [documentation](http://pro.ant.design/docs/getting-started).
## Support des navigateurs
Navigateurs modernes et 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 | deux dernières versions | deux dernières versions | deux dernières versions | deux dernières versions |
## Contribution
Toute forme de contribution est la bienvenue, voici quelques exemples de façons dont vous pouvez contribuer à ce projet:
- Utiliser Ant Design Pro dans votre travail quotidien.
- Soumettre des [issues](http://github.com/ant-design/ant-design-pro/issues) pour reporter les bugs ou poser des questions.
- Proposer des [pull requests](http://github.com/ant-design/ant-design-pro/pulls) pour améliorer notre code.
<div align="center">
<a href="https://www.netlify.com">
<img src="https://www.netlify.com/img/global/badges/netlify-color-bg.svg"/>
</a>
</div>
[English](./README.md) | [简体中文](./README.zh-CN.md) | [Русский](./README.ru-RU.md) | [Türkçe](./README.tr-TR.md) | 日本語 | [Français](./README.fr-FR.md)
<h1 align="center">Ant Design Pro</h1>
<div align="center">
独創的な業務システムの UI を解決するための React ボイラープレート。
[![Build With Umi](https://img.shields.io/badge/build%20with-umi-028fe4.svg?style=flat-square)](http://umijs.org/) [![Build Status](https://dev.azure.com/ant-design/ant-design-pro/_apis/build/status/ant-design.ant-design-pro?branchName=master)](https://dev.azure.com/ant-design/ant-design-pro/_build/latest?definitionId=1?branchName=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://img.shields.io/gitter/room/ant-design/pro-english.svg?style=flat-square&logoWidth=20&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4NCjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgd2lkdGg9IjEyMzUiIGhlaWdodD0iNjUwIiB2aWV3Qm94PSIwIDAgNzQxMCAzOTAwIj4NCjxyZWN0IHdpZHRoPSI3NDEwIiBoZWlnaHQ9IjM5MDAiIGZpbGw9IiNiMjIyMzQiLz4NCjxwYXRoIGQ9Ik0wLDQ1MEg3NDEwbTAsNjAwSDBtMCw2MDBINzQxMG0wLDYwMEgwbTAsNjAwSDc0MTBtMCw2MDBIMCIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjMwMCIvPg0KPHJlY3Qgd2lkdGg9IjI5NjQiIGhlaWdodD0iMjEwMCIgZmlsbD0iIzNjM2I2ZSIvPg0KPGcgZmlsbD0iI2ZmZiI%2BDQo8ZyBpZD0iczE4Ij4NCjxnIGlkPSJzOSI%2BDQo8ZyBpZD0iczUiPg0KPGcgaWQ9InM0Ij4NCjxwYXRoIGlkPSJzIiBkPSJNMjQ3LDkwIDMxNy41MzQyMzAsMzA3LjA4MjAzOSAxMzIuODczMjE4LDE3Mi45MTc5NjFIMzYxLjEyNjc4MkwxNzYuNDY1NzcwLDMwNy4wODIwMzl6Ii8%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzIiB5PSI0MjAiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3MiIHk9Ijg0MCIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgeT0iMTI2MCIvPg0KPC9nPg0KPHVzZSB4bGluazpocmVmPSIjcyIgeT0iMTY4MCIvPg0KPC9nPg0KPHVzZSB4bGluazpocmVmPSIjczQiIHg9IjI0NyIgeT0iMjEwIi8%2BDQo8L2c%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzOSIgeD0iNDk0Ii8%2BDQo8L2c%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzMTgiIHg9Ijk4OCIvPg0KPHVzZSB4bGluazpocmVmPSIjczkiIHg9IjE5NzYiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3M1IiB4PSIyNDcwIi8%2BDQo8L2c%2BDQo8L3N2Zz4%3D)](https://gitter.im/ant-design/pro-english?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![Join the chat at https://gitter.im/ant-design/ant-design-pro](https://img.shields.io/gitter/room/ant-design/ant-design-pro.svg?style=flat-square&logoWidth=20&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4NCjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgd2lkdGg9IjkwMCIgaGVpZ2h0PSI2MDAiIHZpZXdCb3g9IjAgMCAzMCAyMCI%2BDQo8ZGVmcz4NCjxwYXRoIGlkPSJzIiBkPSJNMCwtMSAwLjU4Nzc4NSwwLjgwOTAxNyAtMC45NTEwNTcsLTAuMzA5MDE3SDAuOTUxMDU3TC0wLjU4Nzc4NSwwLjgwOTAxN3oiIGZpbGw9IiNmZmRlMDAiLz4NCjwvZGVmcz4NCjxyZWN0IHdpZHRoPSIzMCIgaGVpZ2h0PSIyMCIgZmlsbD0iI2RlMjkxMCIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNSw1KSBzY2FsZSgzKSIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTAsMikgcm90YXRlKDIzLjAzNjI0MykiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3MiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDEyLDQpIHJvdGF0ZSg0NS44Njk4OTgpIi8%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMiw3KSByb3RhdGUoNjkuOTQ1Mzk2KSIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTAsOSkgcm90YXRlKDIwLjY1OTgwOCkiLz4NCjwvc3ZnPg%3D%3D)](https://gitter.im/ant-design/ant-design-pro?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![Netlify Status](https://api.netlify.com/api/v1/badges/f2fd24cf-5fa1-4a80-be3a-0dbe72b44c90/deploy-status)](https://app.netlify.com/sites/ant-design-pro/deploys) ![](https://badgen.net/badge/icon/Ant%20Design?icon=https://gw.alipayobjects.com/zos/antfincdn/Pp4WPgVDB3/KDpgvguMpGfqaHPjicRK.svg&label)
![](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
## 2.0 がリリースされました 🎉🎉🎉
[Announcing Ant Design Pro 2.0.0](https://medium.com/ant-design/beautiful-and-powerful-ant-design-pro-2-0-release-51358da5af95)
## 翻訳の募集 :loudspeaker:
私たちはあなたの助けを必要としています。: https://github.com/ant-design/ant-design-pro/issues/120
## 特徴
- :gem: **きちんとしたデザイン**: [Ant Design specification](http://ant.design/) に従ってくださ い。
- :triangular_ruler: **共通のテンプレート**: 業務システム用のテンプレート
- :rocket: **現状のアート開発**: `React/umi/dva/antd` の最新開発スタック
- :iphone: **レスポンシブ**: さまざまな画面サイズ用の設計
- :art: **テーマ**: シンプルな設定でカスタマイズ可能なテーマ
- :globe_with_meridians: **国際化**: 国際化の解決策を内蔵
- :gear: **ベストプラクティス**: コードを美しくするための正しいワークフロー
- :1234: **モック開発**: 使いやすいモック開発
- :white_check_mark: **UI テスト**: ユニットテストと e2e テスト
## テンプレート
```
- ダッシュボード
- アナリティクス
- モニター
  - ワークスペース
- 形
  - 基本フォーム
  - ステップフォーム
  - 高度なフォーム
- リスト
  - スタンダードテーブル
  - スタンダードリスト
  - カードリスト
  - 検索リスト(プロジェクト/アプリケーション/記事)
- プロフィール
  - 簡単なプロフィール
  - 高度なプロファイル
- アカウント
  - アカウントセンター
  - アカウント設定
- 結果
  - 成功
  - 失敗
- 例外
  - 403
  - 404
  - 500
- ユーザー
  - ログイン
  - 登録
  - 登録結果
```
## 使用法
### bash を使う方法
```bash
$ yarn create umi # or npm create umi
# Choose ant-design-pro:
Select the boilerplate type (Use arrow keys)
❯ ant-design-pro - Create project with an layout-only ant-design-pro boilerplate, use together with umi block.
app - Create project with a simple boilerplate, support typescript.
block - Create a umi block.
library - Create a library with umi.
plugin - Create a umi plugin.
$ npm install
$ npm start # http://localhost:8000 を開く
```
### Gitpod を使う方法
Gitpod(GitHub 用の無料オンライン開発環境)でプロジェクトを開き、すぐにコーディングを開始できます。
[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/ant-design/ant-design-pro)
その他の指示は [ドキュメント](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 | 最新版から 2 バージョン | 最新版から 2 バージョン | 最新版から 2 バージョン | 最新版から 2 バージョン |
## 貢献する
どんな種類の貢献でも大歓迎です。あなたがこのプロジェクトに貢献できる方法のいくつかの例はここにあります。:
- 毎日の仕事に Ant Design Pro を使用すること。
- 報告すること。 [issues](http://github.com/ant-design/ant-design-pro/issues) にバグ報告や質問をしてください。
- 更新すること。 改善を、[pull requests](http://github.com/ant-design/ant-design-pro/pulls) で送ってください。
[![DevDependencies](https://img.shields.io/david/dev/ant-design/ant-design-pro.svg)](https://david-dm.org/ant-design/ant-design-pro?type=dev)
<div align="center">
<a href="https://www.netlify.com">
<img src="https://www.netlify.com/img/global/badges/netlify-color-bg.svg"/>
</a>
</div>
English | [简体中文](./README.zh-CN.md) | [Русский](./README.ru-RU.md) | [Türkçe](./README.tr-TR.md) | [日本語](./README.ja-JP.md) | [Français](./README.fr-FR.md)
<h1 align="center">Ant Design Pro</h1>
<div align="center">
An out-of-box UI solution for enterprise applications as a React boilerplate.
[![Build With Umi](https://img.shields.io/badge/build%20with-umi-028fe4.svg?style=flat-square)](http://umijs.org/) [![Build Status](https://dev.azure.com/ant-design/ant-design-pro/_apis/build/status/ant-design.ant-design-pro?branchName=master)](https://dev.azure.com/ant-design/ant-design-pro/_build/latest?definitionId=1?branchName=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://img.shields.io/gitter/room/ant-design/pro-english.svg?style=flat-square&logoWidth=20&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4NCjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgd2lkdGg9IjEyMzUiIGhlaWdodD0iNjUwIiB2aWV3Qm94PSIwIDAgNzQxMCAzOTAwIj4NCjxyZWN0IHdpZHRoPSI3NDEwIiBoZWlnaHQ9IjM5MDAiIGZpbGw9IiNiMjIyMzQiLz4NCjxwYXRoIGQ9Ik0wLDQ1MEg3NDEwbTAsNjAwSDBtMCw2MDBINzQxMG0wLDYwMEgwbTAsNjAwSDc0MTBtMCw2MDBIMCIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjMwMCIvPg0KPHJlY3Qgd2lkdGg9IjI5NjQiIGhlaWdodD0iMjEwMCIgZmlsbD0iIzNjM2I2ZSIvPg0KPGcgZmlsbD0iI2ZmZiI%2BDQo8ZyBpZD0iczE4Ij4NCjxnIGlkPSJzOSI%2BDQo8ZyBpZD0iczUiPg0KPGcgaWQ9InM0Ij4NCjxwYXRoIGlkPSJzIiBkPSJNMjQ3LDkwIDMxNy41MzQyMzAsMzA3LjA4MjAzOSAxMzIuODczMjE4LDE3Mi45MTc5NjFIMzYxLjEyNjc4MkwxNzYuNDY1NzcwLDMwNy4wODIwMzl6Ii8%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzIiB5PSI0MjAiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3MiIHk9Ijg0MCIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgeT0iMTI2MCIvPg0KPC9nPg0KPHVzZSB4bGluazpocmVmPSIjcyIgeT0iMTY4MCIvPg0KPC9nPg0KPHVzZSB4bGluazpocmVmPSIjczQiIHg9IjI0NyIgeT0iMjEwIi8%2BDQo8L2c%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzOSIgeD0iNDk0Ii8%2BDQo8L2c%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzMTgiIHg9Ijk4OCIvPg0KPHVzZSB4bGluazpocmVmPSIjczkiIHg9IjE5NzYiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3M1IiB4PSIyNDcwIi8%2BDQo8L2c%2BDQo8L3N2Zz4%3D)](https://gitter.im/ant-design/pro-english?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![Join the chat at https://gitter.im/ant-design/ant-design-pro](https://img.shields.io/gitter/room/ant-design/ant-design-pro.svg?style=flat-square&logoWidth=20&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4NCjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgd2lkdGg9IjkwMCIgaGVpZ2h0PSI2MDAiIHZpZXdCb3g9IjAgMCAzMCAyMCI%2BDQo8ZGVmcz4NCjxwYXRoIGlkPSJzIiBkPSJNMCwtMSAwLjU4Nzc4NSwwLjgwOTAxNyAtMC45NTEwNTcsLTAuMzA5MDE3SDAuOTUxMDU3TC0wLjU4Nzc4NSwwLjgwOTAxN3oiIGZpbGw9IiNmZmRlMDAiLz4NCjwvZGVmcz4NCjxyZWN0IHdpZHRoPSIzMCIgaGVpZ2h0PSIyMCIgZmlsbD0iI2RlMjkxMCIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNSw1KSBzY2FsZSgzKSIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTAsMikgcm90YXRlKDIzLjAzNjI0MykiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3MiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDEyLDQpIHJvdGF0ZSg0NS44Njk4OTgpIi8%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMiw3KSByb3RhdGUoNjkuOTQ1Mzk2KSIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTAsOSkgcm90YXRlKDIwLjY1OTgwOCkiLz4NCjwvc3ZnPg%3D%3D)](https://gitter.im/ant-design/ant-design-pro?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![Netlify Status](https://api.netlify.com/api/v1/badges/f2fd24cf-5fa1-4a80-be3a-0dbe72b44c90/deploy-status)](https://app.netlify.com/sites/ant-design-pro/deploys) ![](https://badgen.net/badge/icon/Ant%20Design?icon=https://gw.alipayobjects.com/zos/antfincdn/Pp4WPgVDB3/KDpgvguMpGfqaHPjicRK.svg&label)
![](https://user-images.githubusercontent.com/8186664/44953195-581e3d80-aec4-11e8-8dcb-54b9db38ec11.png)
</div>
- Preview: http://preview.pro.ant.design
- Home Page: http://pro.ant.design
- Documentation: http://pro.ant.design/docs/getting-started
- ChangeLog: http://pro.ant.design/docs/changelog
- FAQ: http://pro.ant.design/docs/faq
- Mirror Site in China: http://ant-design-pro.gitee.io
## 4.0 Released Now! 🎉🎉🎉
[Announcing Ant Design Pro 4.0.0](https://medium.com/ant-design/ant-design-pro-v4-is-here-6f23098ae9d9)
## Translation Recruitment :loudspeaker:
We need your help: https://github.com/ant-design/ant-design-pro/issues/120
## Features
- :bulb: **TypeScript**: A language for application-scale JavaScript
- :scroll: **Blocks**: Build page with block template
- :gem: **Neat Design**: Follow [Ant Design specification](http://ant.design/)
- :triangular_ruler: **Common Templates**: Typical templates for enterprise applications
- :rocket: **State of The Art Development**: Newest development stack of React/umi/dva/antd
- :iphone: **Responsive**: Designed for variable screen sizes
- :art: **Theming**: Customizable theme with simple config
- :globe_with_meridians: **International**: Built-in i18n solution
- :gear: **Best Practices**: Solid workflow to make your code healthy
- :1234: **Mock development**: Easy to use mock development solution
- :white_check_mark: **UI Test**: Fly safely with unit and e2e tests
## Templates
```
- Dashboard
- Analytic
- Monitor
- Workspace
- Form
- Basic Form
- Step Form
- Advanced From
- List
- Standard Table
- Standard List
- Card List
- Search List (Project/Applications/Article)
- Profile
- Simple Profile
- Advanced Profile
- Account
- Account Center
- Account Settings
- Result
- Success
- Failed
- Exception
- 403
- 404
- 500
- User
- Login
- Register
- Register Result
```
## Usage
### Use bash
```bash
$ yarn create umi # or npm create umi
# Choose ant-design-pro:
Select the boilerplate type (Use arrow keys)
❯ ant-design-pro - Create project with an layout-only ant-design-pro boilerplate, use together with umi block.
app - Create project with a simple boilerplate, support typescript.
block - Create a umi block.
library - Create a library with umi.
plugin - Create a umi plugin.
$ npm install
$ npm start # visit http://localhost:8000
```
### Use Gitpod
Open the project in Gitpod (free online dev environment for GitHub) and start coding immediately.
[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/ant-design/ant-design-pro)
More instructions at [documentation](http://pro.ant.design/docs/getting-started).
## Browsers support
Modern browsers and 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 |
## Contributing
Any type of contribution is welcome, here are some examples of how you may contribute to this project:
- Use Ant Design Pro in your daily work.
- Submit [issues](http://github.com/ant-design/ant-design-pro/issues) to report bugs or ask questions.
- Propose [pull requests](http://github.com/ant-design/ant-design-pro/pulls) to improve our code.
<div align="center">
<a href="https://www.netlify.com">
<img src="https://www.netlify.com/img/global/badges/netlify-color-bg.svg"/>
</a>
</div>
English | [简体中文](./README.zh-CN.md) | [Русский](./README.ru-RU.md) | [Türkçe](./README.tr-TR.md) | [日本語](./README.ja-JP.md) | [Français](./README.fr-FR.md) | [Português](./README.fr-FR.md)
<h1 align="center">Ant Design Pro</h1>
<div align="center">
Uma solução de UI pronta para aplicações corporativos na forma de um boilerplate React.
[![Feito Com Umi](https://img.shields.io/badge/build%20with-umi-028fe4.svg?style=flat-square)](http://umijs.org/) [![Status de Build](https://dev.azure.com/ant-design/ant-design-pro/_apis/build/status/ant-design.ant-design-pro?branchName=master)](https://dev.azure.com/ant-design/ant-design-pro/_build/latest?definitionId=1?branchName=master) [![Dependeências](https://img.shields.io/david/ant-design/ant-design-pro.svg)](https://david-dm.org/ant-design/ant-design-pro) [![Dependências de Desenvolvimento](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://img.shields.io/gitter/room/ant-design/pro-english.svg?style=flat-square&logoWidth=20&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4NCjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgd2lkdGg9IjEyMzUiIGhlaWdodD0iNjUwIiB2aWV3Qm94PSIwIDAgNzQxMCAzOTAwIj4NCjxyZWN0IHdpZHRoPSI3NDEwIiBoZWlnaHQ9IjM5MDAiIGZpbGw9IiNiMjIyMzQiLz4NCjxwYXRoIGQ9Ik0wLDQ1MEg3NDEwbTAsNjAwSDBtMCw2MDBINzQxMG0wLDYwMEgwbTAsNjAwSDc0MTBtMCw2MDBIMCIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjMwMCIvPg0KPHJlY3Qgd2lkdGg9IjI5NjQiIGhlaWdodD0iMjEwMCIgZmlsbD0iIzNjM2I2ZSIvPg0KPGcgZmlsbD0iI2ZmZiI%2BDQo8ZyBpZD0iczE4Ij4NCjxnIGlkPSJzOSI%2BDQo8ZyBpZD0iczUiPg0KPGcgaWQ9InM0Ij4NCjxwYXRoIGlkPSJzIiBkPSJNMjQ3LDkwIDMxNy41MzQyMzAsMzA3LjA4MjAzOSAxMzIuODczMjE4LDE3Mi45MTc5NjFIMzYxLjEyNjc4MkwxNzYuNDY1NzcwLDMwNy4wODIwMzl6Ii8%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzIiB5PSI0MjAiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3MiIHk9Ijg0MCIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgeT0iMTI2MCIvPg0KPC9nPg0KPHVzZSB4bGluazpocmVmPSIjcyIgeT0iMTY4MCIvPg0KPC9nPg0KPHVzZSB4bGluazpocmVmPSIjczQiIHg9IjI0NyIgeT0iMjEwIi8%2BDQo8L2c%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzOSIgeD0iNDk0Ii8%2BDQo8L2c%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzMTgiIHg9Ijk4OCIvPg0KPHVzZSB4bGluazpocmVmPSIjczkiIHg9IjE5NzYiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3M1IiB4PSIyNDcwIi8%2BDQo8L2c%2BDQo8L3N2Zz4%3D)](https://gitter.im/ant-design/pro-english?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![Junte-se ao chat em https://gitter.im/ant-design/ant-design-pro](https://img.shields.io/gitter/room/ant-design/ant-design-pro.svg?style=flat-square&logoWidth=20&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4NCjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgd2lkdGg9IjkwMCIgaGVpZ2h0PSI2MDAiIHZpZXdCb3g9IjAgMCAzMCAyMCI%2BDQo8ZGVmcz4NCjxwYXRoIGlkPSJzIiBkPSJNMCwtMSAwLjU4Nzc4NSwwLjgwOTAxNyAtMC45NTEwNTcsLTAuMzA5MDE3SDAuOTUxMDU3TC0wLjU4Nzc4NSwwLjgwOTAxN3oiIGZpbGw9IiNmZmRlMDAiLz4NCjwvZGVmcz4NCjxyZWN0IHdpZHRoPSIzMCIgaGVpZ2h0PSIyMCIgZmlsbD0iI2RlMjkxMCIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNSw1KSBzY2FsZSgzKSIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTAsMikgcm90YXRlKDIzLjAzNjI0MykiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3MiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDEyLDQpIHJvdGF0ZSg0NS44Njk4OTgpIi8%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMiw3KSByb3RhdGUoNjkuOTQ1Mzk2KSIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTAsOSkgcm90YXRlKDIwLjY1OTgwOCkiLz4NCjwvc3ZnPg%3D%3D)](https://gitter.im/ant-design/ant-design-pro?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![Status do Netlify](https://api.netlify.com/api/v1/badges/f2fd24cf-5fa1-4a80-be3a-0dbe72b44c90/deploy-status)](https://app.netlify.com/sites/ant-design-pro/deploys) ![](https://badgen.net/badge/icon/Ant%20Design?icon=https://gw.alipayobjects.com/zos/antfincdn/Pp4WPgVDB3/KDpgvguMpGfqaHPjicRK.svg&label)
![](https://user-images.githubusercontent.com/8186664/44953195-581e3d80-aec4-11e8-8dcb-54b9db38ec11.png)
</div>
- Prévia: http://preview.pro.ant.design
- Página Inicial: http://pro.ant.design
- Documentação: http://pro.ant.design/docs/getting-started
- Mudanças: http://pro.ant.design/docs/changelog
- FAQ: http://pro.ant.design/docs/faq
- Site Alternativo na China: http://ant-design-pro.gitee.io
## 4.0 Lançado! 🎉🎉🎉
[Anúncio do Ant Design Pro 4.0.0](https://medium.com/ant-design/ant-design-pro-v4-is-here-6f23098ae9d9)
## Recrutamento para tradução :loudspeaker:
Precisamos da sua ajuda: https://github.com/ant-design/ant-design-pro/issues/120
## Recursos
- :bulb: **TypeScript**: Uma linguaguem para escalar aplicações JavaScript
- :scroll: **Blocks**: Crie páginas com block template
- :gem: **Design Elegante**: Segue as [especificações do Ant Design](http://ant.design/)
- :triangular_ruler: **Modelos Comuns**: Modelos comuns para apliações empresariais
- :rocket: **Estado da Arte do Desenvolvimento**: Stack de desenvolvimento mais recente do React/umi/dva/antd
- :iphone: **Responsivo**: Projetado para tamanhos de telas variados
- :art: **Personalização**: Customizável através de uma simples configuração
- :globe_with_meridians: **Internacionalização**: Incluso i18n por padrão
- :gear: **Melhores Práticas**: Fluxo de trabalho sólido para manter seu código saudável
- :1234: **Desenvolvimento de Mock**: Fácil solução para desenvolvimento de mocks
- :white_check_mark: **Testes de UI**: Voe tranquilamente com testes unitários e testes e2e
## Modelos
```
- Painel de Controle
- Gráficos
- Monitoramento
- Areás de Trabalho
- Formulários
- Formulários Básicos
- Formulário com Etapas
- Formulários Avançados
- Listas
- Tabela Padrão
- Lista Padrão
- Lista com Cards
- Lista com Busca (Projeto/Aplicações/Artigos)
- Perfís
- Perfil Simples
- Perfil Avançado
- Conta
- Detalhes da Conta
- Configurações da Conta
- Resultados
- Secesso
- Falha
- Exceções
- 403
- 404
- 500
- Usuário
- Login
- Cadastro
- Resultado do Cadastro
```
## Uso
### Use o bash
```bash
$ yarn create umi # ou npm create umi
# Escolha ant-design-pro:
Selecione o tipo do boilerplate (Use as teclas de seta)
❯ ant-design-pro - Create project with an layout-only ant-design-pro boilerplate, use together with umi block.
app - Create project with a simple boilerplate, support typescript.
block - Create a umi block.
library - Create a library with umi.
plugin - Create a umi plugin.
$ npm install
$ npm start # visit http://localhost:8000
```
### Use Gitpod
Abra o projeto no Gitpod (ambiente gratuito de desenvolvimento online para o GitHub) e comece a codificar imediatamente.
[![Abra no Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/ant-design/ant-design-pro)
Mais instruções na [documentação](http://pro.ant.design/docs/getting-started).
## Suporte a navegadores
Navegadores modernos e 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 | últimas 2 versões | últimas 2 versões | últimas 2 versões | últimas 2 versões |
## Contribuindo
Qualquer tipo de contribuição é bem-vinda, aqui estão alguns exemplos de como você pode contribuir com esse projeto:
- Use Ant Design Pro no seu trabalho diário.
- Submeta [issues](http://github.com/ant-design/ant-design-pro/issues) para reportar bugs ou tirar dúvidas.
- Proponha [pull requests](http://github.com/ant-design/ant-design-pro/pulls) para melhorar nosso código.
<div align="center">
<a href="https://www.netlify.com">
<img src="https://www.netlify.com/img/global/badges/netlify-color-bg.svg"/>
</a>
</div>
[English](./README.md) | [简体中文](./README.zh-CN.md) | Русский | [Türkçe](./README.tr-TR.md) | [日本語](./README.ja-JP.md) | [Français](./README.fr-FR.md)
<h1 align="center">Ant Design Pro</h1>
<div align="center">
UI-решение "из коробки" для корпоративных приложений как React boilerplate
[![Build With Umi](https://img.shields.io/badge/build%20with-umi-028fe4.svg?style=flat-square)](http://umijs.org/) [![Build Status](https://dev.azure.com/ant-design/ant-design-pro/_apis/build/status/ant-design.ant-design-pro?branchName=master)](https://dev.azure.com/ant-design/ant-design-pro/_build/latest?definitionId=1?branchName=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://img.shields.io/gitter/room/ant-design/pro-english.svg?style=flat-square&logoWidth=20&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4NCjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgd2lkdGg9IjEyMzUiIGhlaWdodD0iNjUwIiB2aWV3Qm94PSIwIDAgNzQxMCAzOTAwIj4NCjxyZWN0IHdpZHRoPSI3NDEwIiBoZWlnaHQ9IjM5MDAiIGZpbGw9IiNiMjIyMzQiLz4NCjxwYXRoIGQ9Ik0wLDQ1MEg3NDEwbTAsNjAwSDBtMCw2MDBINzQxMG0wLDYwMEgwbTAsNjAwSDc0MTBtMCw2MDBIMCIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjMwMCIvPg0KPHJlY3Qgd2lkdGg9IjI5NjQiIGhlaWdodD0iMjEwMCIgZmlsbD0iIzNjM2I2ZSIvPg0KPGcgZmlsbD0iI2ZmZiI%2BDQo8ZyBpZD0iczE4Ij4NCjxnIGlkPSJzOSI%2BDQo8ZyBpZD0iczUiPg0KPGcgaWQ9InM0Ij4NCjxwYXRoIGlkPSJzIiBkPSJNMjQ3LDkwIDMxNy41MzQyMzAsMzA3LjA4MjAzOSAxMzIuODczMjE4LDE3Mi45MTc5NjFIMzYxLjEyNjc4MkwxNzYuNDY1NzcwLDMwNy4wODIwMzl6Ii8%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzIiB5PSI0MjAiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3MiIHk9Ijg0MCIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgeT0iMTI2MCIvPg0KPC9nPg0KPHVzZSB4bGluazpocmVmPSIjcyIgeT0iMTY4MCIvPg0KPC9nPg0KPHVzZSB4bGluazpocmVmPSIjczQiIHg9IjI0NyIgeT0iMjEwIi8%2BDQo8L2c%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzOSIgeD0iNDk0Ii8%2BDQo8L2c%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzMTgiIHg9Ijk4OCIvPg0KPHVzZSB4bGluazpocmVmPSIjczkiIHg9IjE5NzYiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3M1IiB4PSIyNDcwIi8%2BDQo8L2c%2BDQo8L3N2Zz4%3D)](https://gitter.im/ant-design/pro-english?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![Join the chat at https://gitter.im/ant-design/ant-design-pro](https://img.shields.io/gitter/room/ant-design/ant-design-pro.svg?style=flat-square&logoWidth=20&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4NCjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgd2lkdGg9IjkwMCIgaGVpZ2h0PSI2MDAiIHZpZXdCb3g9IjAgMCAzMCAyMCI%2BDQo8ZGVmcz4NCjxwYXRoIGlkPSJzIiBkPSJNMCwtMSAwLjU4Nzc4NSwwLjgwOTAxNyAtMC45NTEwNTcsLTAuMzA5MDE3SDAuOTUxMDU3TC0wLjU4Nzc4NSwwLjgwOTAxN3oiIGZpbGw9IiNmZmRlMDAiLz4NCjwvZGVmcz4NCjxyZWN0IHdpZHRoPSIzMCIgaGVpZ2h0PSIyMCIgZmlsbD0iI2RlMjkxMCIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNSw1KSBzY2FsZSgzKSIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTAsMikgcm90YXRlKDIzLjAzNjI0MykiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3MiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDEyLDQpIHJvdGF0ZSg0NS44Njk4OTgpIi8%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMiw3KSByb3RhdGUoNjkuOTQ1Mzk2KSIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTAsOSkgcm90YXRlKDIwLjY1OTgwOCkiLz4NCjwvc3ZnPg%3D%3D)](https://gitter.im/ant-design/ant-design-pro?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![Netlify Status](https://api.netlify.com/api/v1/badges/f2fd24cf-5fa1-4a80-be3a-0dbe72b44c90/deploy-status)](https://app.netlify.com/sites/ant-design-pro/deploys) ![](https://badgen.net/badge/icon/Ant%20Design?icon=https://gw.alipayobjects.com/zos/antfincdn/Pp4WPgVDB3/KDpgvguMpGfqaHPjicRK.svg&label)
![](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
$ yarn create umi # or npm create umi
# Choose ant-design-pro:
Select the boilerplate type (Use arrow keys)
❯ ant-design-pro - Create project with an layout-only ant-design-pro boilerplate, use together with umi block.
app - Create project with a simple boilerplate, support typescript.
block - Create a umi block.
library - Create a library with umi.
plugin - Create a umi plugin.
$ 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) для совершенствования нашего кода.
<div align="center">
<a href="https://www.netlify.com">
<img src="https://www.netlify.com/img/global/badges/netlify-color-bg.svg"/>
</a>
</div>
[English](./README.md) | [简体中文](./README.zh-CN.md) | [Русский](./README.ru-RU.md) | Türkçe | [日本語](./README.ja-JP.md) | [Français](./README.fr-FR.md)
<h1 align="center">Ant Design Pro</h1>
<div align="center">
React ile kurumsal uygulamalar için taslak olarak geliştirilmiş kullanıma hazır bir UI çözümü.
[![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://img.shields.io/gitter/room/ant-design/pro-english.svg)](https://gitter.im/ant-design/pro-english?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)(🇺🇸) [![Gitter](https://img.shields.io/gitter/room/ant-design/ant-design-pro.svg?style=flat-square)](https://gitter.im/ant-design/ant-design-pro?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)(🇨🇳) [![Netlify Status](https://api.netlify.com/api/v1/badges/f2fd24cf-5fa1-4a80-be3a-0dbe72b44c90/deploy-status)](https://app.netlify.com/sites/ant-design-pro/deploys) ![](https://badgen.net/badge/icon/Ant%20Design?icon=https://gw.alipayobjects.com/zos/antfincdn/Pp4WPgVDB3/KDpgvguMpGfqaHPjicRK.svg&label)
![](https://user-images.githubusercontent.com/8186664/44953195-581e3d80-aec4-11e8-8dcb-54b9db38ec11.png)
</div>
- Önizleme: http://preview.pro.ant.design
- Anasayfa: http://pro.ant.design
- Dokümantasyon: http://pro.ant.design/docs/getting-started
- ChangeLog: http://pro.ant.design/docs/changelog
- SSS: http://pro.ant.design/docs/faq
- Çinde barındırılan site: http://ant-design-pro.gitee.io
## 2.0 Versiyonu Şimdi Yayında! 🎉🎉🎉
[Announcing Ant Design Pro 2.0.0](https://medium.com/ant-design/beautiful-and-powerful-ant-design-pro-2-0-release-51358da5af95)
## Çeviri Desteği :loudspeaker:
Çeviriler için yardımınıza ihtiyacımız var: https://github.com/ant-design/ant-design-pro/issues/120
## Özellikler
- :gem: **Zarif Tasarım**: Buradan [Ant Design özellikleri](http://ant.design/)
- :triangular_ruler: **Ortak Şablonlar**: Kurumsal uygulamalar için şablonlar
- :rocket: **Sanatsal gelişim durumu**: Newest development stack of React/umi/dva/antd
- :iphone: **Responsive**: Değişken ekran boyutları için tasarlanmıştır
- :art: **Tema Kullanımı**: Basit ayarlar ile özelleştirilebilir tema
- :globe_with_meridians: **Uluslararası**: Built-in i18n solution
- :gear: **Best Practices**: İyi kod için sağlam iş akışı
- :1234: **Mock Geliştirme**: Model(Mock) geliştirmeler için kolay çözüm
- :white_check_mark: **UI Testi**: Unit ve e2e testleri ile güvenli sürdürülebilirlik
## Şablonlar
```
- Dashboard
- Analitik
- Monitör
- Çalışma alanı
- Form
- Basit Form
- Step Form
- Gelişmiş Form
- List
- Standard Tablo
- Standard Liste
- Kart Liste
- Arama Listesi (Project/Applications/Article)
- Profil
- Basit Profil
- Gelişmiş Profil
- Hesap
- Hesap Yönetimi
- Hesap Ayarları
- Sonuç
- Başarılı
- Hatalı
- Hatalar
- 403
- 404
- 500
- Kullanıcı
- Giriş
- Kayıt
- Kayıt Sonucu
```
## Kullanım
```bash
$ yarn create umi # or npm create umi
# Choose ant-design-pro:
Select the boilerplate type (Use arrow keys)
❯ ant-design-pro - Create project with an layout-only ant-design-pro boilerplate, use together with umi block.
app - Create project with a simple boilerplate, support typescript.
block - Create a umi block.
library - Create a library with umi.
plugin - Create a umi plugin.
$ npm install
$ npm start # visit http://localhost:8000
```
Daha fazla talimat için [dokümantasyon](http://pro.ant.design/docs/getting-started) sayfasına göz atın.
## Tarayıcı desteği
Modern internet tarayıcıları ve 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 | son 2 versiyon | son 2 versiyon | son 2 versiyon | son 2 versiyon |
## Destek
Her türlü desteğinize açığız, bu projeye nasıl katkıda bulunabileceğinize dair bazı örnekler:
- Günlük işinizde Ant Design Pro kullanın.
- Hataları bildirmek veya soru sormak için [issues](http://github.com/ant-design/ant-design-pro/issues) gönderin.
- kodumuzu geliştirmek için [pull requests](http://github.com/ant-design/ant-design-pro/pulls) gönderin.
<div align="center">
<a href="https://www.netlify.com">
<img src="https://www.netlify.com/img/global/badges/netlify-color-bg.svg"/>
</a>
</div>
[English](./README.md) | 简体中文 | [Русский](./README.ru-RU.md) | [Türkçe](./README.tr-TR.md) | [日本語](./README.ja-JP.md) | [Français](./README.fr-FR.md)
<h1 align="center">Ant Design Pro</h1>
<div align="center">
开箱即用的中台前端/设计解决方案。
[![Build With Umi](https://img.shields.io/badge/build%20with-umi-028fe4.svg?style=flat-square)](http://umijs.org/) [![Build Status](https://dev.azure.com/ant-design/ant-design-pro/_apis/build/status/ant-design.ant-design-pro?branchName=master)](https://dev.azure.com/ant-design/ant-design-pro/_build/latest?definitionId=1?branchName=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) [![Join the chat at https://gitter.im/ant-design/ant-design-pro](https://img.shields.io/gitter/room/ant-design/ant-design-pro.svg?style=flat-square&logoWidth=20&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4NCjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgd2lkdGg9IjkwMCIgaGVpZ2h0PSI2MDAiIHZpZXdCb3g9IjAgMCAzMCAyMCI%2BDQo8ZGVmcz4NCjxwYXRoIGlkPSJzIiBkPSJNMCwtMSAwLjU4Nzc4NSwwLjgwOTAxNyAtMC45NTEwNTcsLTAuMzA5MDE3SDAuOTUxMDU3TC0wLjU4Nzc4NSwwLjgwOTAxN3oiIGZpbGw9IiNmZmRlMDAiLz4NCjwvZGVmcz4NCjxyZWN0IHdpZHRoPSIzMCIgaGVpZ2h0PSIyMCIgZmlsbD0iI2RlMjkxMCIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNSw1KSBzY2FsZSgzKSIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTAsMikgcm90YXRlKDIzLjAzNjI0MykiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3MiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDEyLDQpIHJvdGF0ZSg0NS44Njk4OTgpIi8%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMiw3KSByb3RhdGUoNjkuOTQ1Mzk2KSIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTAsOSkgcm90YXRlKDIwLjY1OTgwOCkiLz4NCjwvc3ZnPg%3D%3D)](https://gitter.im/ant-design/ant-design-pro?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![Netlify Status](https://api.netlify.com/api/v1/badges/f2fd24cf-5fa1-4a80-be3a-0dbe72b44c90/deploy-status)](https://app.netlify.com/sites/ant-design-pro/deploys) ![](https://badgen.net/badge/icon/Ant%20Design?icon=https://gw.alipayobjects.com/zos/antfincdn/Pp4WPgVDB3/KDpgvguMpGfqaHPjicRK.svg&label)
![](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
## 现在我们发布了 4.0! 🎉🎉🎉
[Announcing Ant Design Pro 4.0.0](https://zhuanlan.zhihu.com/p/67498559)
## 特性
- :bulb: **TypeScript**: 应用程序级 JavaScript 的语言
- :scroll: **区块**: 通过区块模板快速构建页面
- :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
$ yarn create umi # or npm create umi
# Choose ant-design-pro:
Select the boilerplate type (Use arrow keys)
❯ ant-design-pro - Create project with an layout-only ant-design-pro boilerplate, use together with umi block.
app - Create project with a simple boilerplate, support typescript.
block - Create a umi block.
library - Create a library with umi.
plugin - Create a umi plugin.
$ 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 |
## 参与贡献
我们非常欢迎你的贡献,你可以通过以下方式和我们一起共建 :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 的代码。
<div align="center">
<a href="https://www.netlify.com">
<img src="https://www.netlify.com/img/global/badges/netlify-color-bg.svg"/>
</a>
</div>
# Node.js
# Build a general Node.js project with npm.
# Add steps that analyze code, save build artifacts, deploy, and more:
# https://docs.microsoft.com/azure/devops/pipelines/languages/javascript
name: ant design pro
trigger:
- master
jobs:
- job: lintAndBuild
pool:
vmImage: 'Ubuntu-16.04'
steps:
- checkout: self
clean: false
- script: yarn install
displayName: install
- script: npm run lint
displayName: lint
- script: npm run build
env:
PROGRESS: none
displayName: build
- job: test
pool:
vmImage: 'Ubuntu-16.04'
container:
image: circleci/node:latest-browsers
options: '-u root'
steps:
- script: yarn install
displayName: install
- script: npm run test:all
env:
PROGRESS: none
displayName: test
- job: Windows
pool:
vmImage: 'vs2017-win2016'
steps:
- task: NodeTool@0
inputs:
versionSpec: '11.x'
- script: yarn install
displayName: install
- script: npm run lint
displayName: lint
- script: npm run test:all
env:
PROGRESS: none
displayName: test
- script: npm run build
env:
PROGRESS: none
displayName: build
- job: MacOS
pool:
vmImage: 'macOS-10.13'
steps:
- task: NodeTool@0
inputs:
versionSpec: '11.x'
- script: yarn install
displayName: install
- script: npm run lint
displayName: lint
- script: npm run
env:
PROGRESS: none
displayName: build
import { IConfig, IPlugin } from 'umi-types';
import defaultSettings from './defaultSettings'; // https://umijs.org/config/
import slash from 'slash2';
import webpackPlugin from './plugin.config';
const { pwa, primaryColor } = defaultSettings;
// preview.pro.ant.design only do not use in your production ;
// preview.pro.ant.design 专用环境变量,请不要在你的项目中使用它。
const { ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION } = process.env;
const isAntDesignProPreview = ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION === 'site';
const plugins: IPlugin[] = [
[
'umi-plugin-react',
{
antd: true,
dva: {
hmr: true,
},
locale: {
// default false
enable: true,
// default zh-CN
default: 'zh-CN',
// default true, when it is true, will use `navigator.language` overwrite default
baseNavigator: true,
},
// dynamicImport: {
// loadingComponent: './components/PageLoading/index',
// webpackChunkName: true,
// level: 3,
// },
pwa: pwa
? {
workboxPluginMode: 'InjectManifest',
workboxOptions: {
importWorkboxFrom: 'local',
},
}
: false,
// default close dll, because issue https://github.com/ant-design/ant-design-pro/issues/4665
// dll features https://webpack.js.org/plugins/dll-plugin/
// dll: {
// include: ['dva', 'dva/router', 'dva/saga', 'dva/fetch'],
// exclude: ['@babel/runtime', 'netlify-lambda'],
// },
},
],
[
'umi-plugin-pro-block',
{
moveMock: false,
moveService: false,
modifyRequest: true,
autoAddMenu: true,
},
],
]; // 针对 preview.pro.ant.design 的 GA 统计代码
if (isAntDesignProPreview) {
plugins.push([
'umi-plugin-ga',
{
code: 'UA-72788897-6',
},
]);
plugins.push([
'umi-plugin-pro',
{
serverUrl: 'https://ant-design-pro.netlify.com',
},
]);
}
export default {
plugins,
block: {
// 国内用户可以使用码云
// defaultGitUrl: 'https://gitee.com/ant-design/pro-blocks',
defaultGitUrl: 'https://github.com/ant-design/pro-blocks',
},
hash: true,
targets: {
ie: 11,
},
devtool: isAntDesignProPreview ? 'source-map' : false,
// umi routes: https://umijs.org/zh/guide/router.html
routes: [
{
path: '/user',
component: '../layouts/UserLayout',
routes: [
{
name: 'login',
path: '/user/login',
component: './user/login',
},
],
},
{
path: '/',
component: '../layouts/SecurityLayout',
routes: [
{
path: '/',
component: '../layouts/BasicLayout',
authority: ['admin', 'user'],
routes: [
{
path: '/',
redirect: '/welcome',
},
{
path: '/welcome',
name: 'welcome',
icon: 'smile',
component: './Welcome',
},
{
component: './404',
},
],
},
{
component: './404',
},
],
},
{
component: './404',
},
],
// Theme for antd: https://ant.design/docs/react/customize-theme-cn
theme: {
'primary-color': primaryColor,
},
define: {
ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION:
ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION || '', // preview.pro.ant.design only do not use in your production ; preview.pro.ant.design 专用环境变量,请不要在你的项目中使用它。
},
ignoreMomentLocale: true,
lessLoaderOptions: {
javascriptEnabled: true,
},
disableRedirectHoist: true,
cssLoaderOptions: {
modules: true,
getLocalIdent: (
context: {
resourcePath: string;
},
_: string,
localName: string,
) => {
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 = slash(antdProPath)
.split('/')
.map((a: string) => a.replace(/([A-Z])/g, '-$1'))
.map((a: string) => a.toLowerCase());
return `antd-pro${arr.join('-')}-${localName}`.replace(/--/g, '-');
}
return localName;
},
},
manifest: {
basePath: '/',
},
chainWebpack: webpackPlugin,
/*
proxy: {
'/server/api/': {
target: 'https://preview.pro.ant.design/',
changeOrigin: true,
pathRewrite: { '^/server': '' },
},
},
*/
} as IConfig;
import { MenuTheme } from 'antd/es/menu/MenuContext';
export type ContentWidth = 'Fluid' | 'Fixed';
export interface DefaultSettings {
/**
* theme for nav menu
*/
navTheme: MenuTheme;
/**
* primary color of ant design
*/
primaryColor: string;
/**
* nav menu position: `sidemenu` or `topmenu`
*/
layout: 'sidemenu' | 'topmenu';
/**
* layout of content: `Fluid` or `Fixed`, only works when layout is topmenu
*/
contentWidth: ContentWidth;
/**
* sticky header
*/
fixedHeader: boolean;
/**
* auto hide header
*/
autoHideHeader: boolean;
/**
* sticky siderbar
*/
fixSiderbar: boolean;
menu: { locale: boolean };
title: string;
pwa: boolean;
// Your custom iconfont Symbol script Url
// eg://at.alicdn.com/t/font_1039637_btcrd5co4w.js
// 注意:如果需要图标多色,Iconfont 图标项目里要进行批量去色处理
// Usage: https://github.com/ant-design/ant-design-pro/pull/3517
iconfontUrl: string;
colorWeak: boolean;
}
export default {
navTheme: 'dark',
primaryColor: '#1890FF',
layout: 'sidemenu',
contentWidth: 'Fluid',
fixedHeader: false,
autoHideHeader: false,
fixSiderbar: false,
colorWeak: false,
menu: {
locale: true,
},
title: 'Ant Design Pro',
pwa: false,
iconfontUrl: '',
} as DefaultSettings;
// Change theme plugin
// eslint-disable-next-line eslint-comments/abdeils - enable - pair;
/* eslint-disable import/no-extraneous-dependencies */
import ThemeColorReplacer from 'webpack-theme-color-replacer';
import generate from '@ant-design/colors/lib/generate';
import path from 'path';
function getModulePackageName(module: { context: string }) {
if (!module.context) return null;
const nodeModulesPath = path.join(__dirname, '../node_modules/');
if (module.context.substring(0, nodeModulesPath.length) !== nodeModulesPath) {
return null;
}
const moduleRelativePath = module.context.substring(nodeModulesPath.length);
const [moduleDirName] = moduleRelativePath.split(path.sep);
let packageName: string | null = moduleDirName;
// handle tree shaking
if (packageName && packageName.match('^_')) {
// eslint-disable-next-line prefer-destructuring
packageName = packageName.match(/^_(@?[^@]+)/)![1];
}
return packageName;
}
export default (config: any) => {
// preview.pro.ant.design only do not use in your production;
if (
process.env.ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION === 'site' ||
process.env.NODE_ENV !== 'production'
) {
config.plugin('webpack-theme-color-replacer').use(ThemeColorReplacer, [
{
fileName: 'css/theme-colors-[contenthash:8].css',
matchColors: getAntdSerials('#1890ff'), // 主色系列
// 改变样式选择器,解决样式覆盖问题
changeSelector(selector: string): string {
switch (selector) {
case '.ant-calendar-today .ant-calendar-date':
return ':not(.ant-calendar-selected-date)' + selector;
case '.ant-btn:focus,.ant-btn:hover':
return '.ant-btn:focus:not(.ant-btn-primary),.ant-btn:hover:not(.ant-btn-primary)';
case '.ant-btn.active,.ant-btn:active':
return '.ant-btn.active:not(.ant-btn-primary),.ant-btn:active:not(.ant-btn-primary)';
default:
return selector;
}
},
// isJsUgly: true,
},
]);
}
// optimize chunks
config.optimization
// share the same chunks across different modules
.runtimeChunk(false)
.splitChunks({
chunks: 'async',
name: 'vendors',
maxInitialRequests: Infinity,
minSize: 0,
cacheGroups: {
vendors: {
test: (module: { context: string }) => {
const packageName = getModulePackageName(module) || '';
if (packageName) {
return [
'bizcharts',
'gg-editor',
'g6',
'@antv',
'gg-editor-core',
'bizcharts-plugin-slider',
].includes(packageName);
}
return false;
},
name(module: { context: string }) {
const packageName = getModulePackageName(module);
if (packageName) {
if (['bizcharts', '@antv_data-set'].indexOf(packageName) >= 0) {
return 'viz'; // visualization package
}
}
return 'misc';
},
},
},
});
};
const getAntdSerials = (color: string) => {
const lightNum = 9;
const devide10 = 10;
// 淡化(即less的tint)
const lightens = new Array(lightNum).fill(undefined).map((_, i: number) => {
return ThemeColorReplacer.varyColor.lighten(color, i / devide10);
});
const colorPalettes = generate(color);
const rgb = ThemeColorReplacer.varyColor.toNum3(color.replace('#', '')).join(',');
return lightens.concat(colorPalettes).concat(rgb);
};
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
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:
server {
listen 80;
# gzip config
gzip on;
gzip_min_length 1k;
gzip_comp_level 9;
gzip_types text/plain text/css text/javascript application/json application/javascript application/x-javascript application/xml;
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://ant-design-pro.netlify.com;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
}
}
// ps https://github.com/GoogleChrome/puppeteer/issues/3120
module.exports = {
launch: {
args: [
'--disable-gpu',
'--disable-dev-shm-usage',
'--no-first-run',
'--no-zygote',
'--no-sandbox',
],
},
};
module.exports = {
testURL: 'http://localhost:8000',
preset: 'jest-puppeteer',
globals: {
ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION: false,
},
};
{
"compilerOptions": {
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
}
}
// [START functions import]
const express = require('express');
const serverLess = require('serverless-http');
const matchMock = require('./mock/matchMock');
const app = express();
app.all('*', (req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header(
'Access-Control-Allow-Headers',
'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild',
);
res.header('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS');
if (req.method == 'OPTIONS') {
res.send(200);
} else {
next();
}
});
app.use(matchMock);
exports.handler = serverLess(app);
This diff is collapsed.
const pathToRegexp = require('path-to-regexp');
const bodyParser = require('body-parser');
const mockFile = require('./index');
const BODY_PARSED_METHODS = ['post', 'put', 'patch'];
const debug = console.log;
function parseKey(key) {
let method = 'get';
let path = key;
if (key.indexOf(' ') > -1) {
const spliced = key.split(' ');
method = spliced[0].toLowerCase();
path = spliced[1]; // eslint-disable-line
}
const routerBasePath = `${path}`;
return {
method,
path: routerBasePath,
};
}
function createHandler(method, path, handler) {
return (req, res, next) => {
function sendData() {
if (typeof handler === 'function') {
handler(req, res, next);
} else {
res.json(handler);
}
}
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 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();
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.statusCode = 400;
err.status = 400;
}
throw err;
}
}
// eslint-disable-next-line no-restricted-syntax
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 += 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;
}
}
}
return mockData.filter(({ method, re }) => 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);
}
return next();
};
import { Request, Response } from 'express';
const getNotices = (req: Request, res: Response) => {
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',
clickClose: true,
},
{
id: '000000007',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg',
title: '朱偏右 回复了你',
description: '这种模板用于提醒谁与你发生了互动,左侧放『谁』的头像',
datetime: '2017-08-07',
type: 'message',
clickClose: true,
},
{
id: '000000008',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg',
title: '标题',
description: '这种模板用于提醒谁与你发生了互动,左侧放『谁』的头像',
datetime: '2017-08-07',
type: 'message',
clickClose: true,
},
{
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,
};
export default {
'/api/auth_routes': {
'/form/advanced-form': { authority: ['admin', 'user'] },
},
};
import { Request, Response } from 'express';
function getFakeCaptcha(req: Request, res: Response) {
return res.json('captcha-xxx');
}
// 代码中会兼容本地 service mock 以及部署站点的静态数据
export default {
// 支持值为 Object 和 Array
'GET /api/currentUser': {
name: 'Serati Ma',
avatar: 'https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png',
userid: '00000001',
email: 'antdesign@alipay.com',
signature: '海纳百川,有容乃大',
title: '交互专家',
group: '蚂蚁金服-某某某事业群-某某平台部-某某技术部-UED',
tags: [
{
key: '0',
label: '很有想法的',
},
{
key: '1',
label: '专注设计',
},
{
key: '2',
label: '辣~',
},
{
key: '3',
label: '大长腿',
},
{
key: '4',
label: '川妹子',
},
{
key: '5',
label: '海纳百川',
},
],
notifyCount: 12,
unreadCount: 11,
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: Request, res: Response) => {
const { password, userName, type } = req.body;
if (password === 'ant.design' && userName === 'admin') {
res.send({
status: 'ok',
type,
currentAuthority: 'admin',
});
return;
}
if (password === 'ant.design' && userName === 'user') {
res.send({
status: 'ok',
type,
currentAuthority: 'user',
});
return;
}
res.send({
status: 'error',
type,
currentAuthority: 'guest',
});
},
'POST /api/register': (req: Request, res: Response) => {
res.send({ status: 'ok', currentAuthority: 'user' });
},
'GET /api/500': (req: Request, res: Response) => {
res.status(500).send({
timestamp: 1513932555104,
status: 500,
error: 'error',
message: 'error',
path: '/base/category/list',
});
},
'GET /api/404': (req: Request, res: Response) => {
res.status(404).send({
timestamp: 1513932643431,
status: 404,
error: 'Not Found',
message: 'No message available',
path: '/base/category/list/2121212',
});
},
'GET /api/403': (req: Request, res: Response) => {
res.status(403).send({
timestamp: 1513932555104,
status: 403,
error: 'Unauthorized',
message: 'Unauthorized',
path: '/base/category/list',
});
},
'GET /api/401': (req: Request, res: Response) => {
res.status(401).send({
timestamp: 1513932555104,
status: 401,
error: 'Unauthorized',
message: 'Unauthorized',
path: '/base/category/list',
});
},
'GET /api/login/captcha': getFakeCaptcha,
};
[build]
functions = "./functions"
[[redirects]]
from = "/api/*"
to = "/.netlify/functions/api/:splat"
status = 200
force = true
[redirects.headers]
X-From = "Netlify"
X-Api-Key = "some-api-key-string"
[[redirects]]
from = "/*"
to = "/index.html"
status = 200
\ No newline at end of file
{
"name": "ant-design-pro",
"version": "4.0.0",
"private": true,
"description": "An out-of-box UI solution for enterprise applications",
"scripts": {
"analyze": "cross-env ANALYZE=1 umi build",
"build": "umi build",
"ui": "umi ui",
"deploy": "cross-env ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION=site npm run site && npm run gh-pages",
"docker-hub:build": "docker build -f Dockerfile.hub -t ant-design-pro ./",
"docker-prod:build": "docker-compose -f ./docker/docker-compose.yml build",
"docker-prod:dev": "docker-compose -f ./docker/docker-compose.yml up",
"docker:build": "docker-compose -f ./docker/docker-compose.dev.yml build",
"docker:dev": "docker-compose -f ./docker/docker-compose.dev.yml up",
"docker:push": "npm run docker-hub:build && npm run docker:tag && docker push antdesign/ant-design-pro",
"docker:tag": "docker tag ant-design-pro antdesign/ant-design-pro",
"fetch:blocks": "pro fetch-blocks && npm run prettier",
"format-imports": "cross-env import-sort --write '**/*.{js,jsx,ts,tsx}'",
"functions:build": "netlify-lambda build ./lambda",
"functions:run": "cross-env NODE_ENV=dev netlify-lambda serve ./lambda",
"gh-pages": "cp CNAME ./dist/ && gh-pages -d dist",
"i18n-remove": "pro i18n-remove --locale=zh-CN --write",
"lint": "npm run lint:js && npm run lint:style && npm run lint:prettier",
"lint-staged": "lint-staged",
"lint-staged:js": "eslint --ext .js,.jsx,.ts,.tsx ",
"lint:fix": "eslint --fix --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src && npm run lint:style",
"lint:js": "eslint --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src",
"lint:prettier": "check-prettier lint",
"lint:style": "stylelint --fix \"src/**/*.less\" --syntax less",
"prettier": "prettier -c --write \"**/*\"",
"site": "npm run fetch:blocks && npm run build && npm run functions:build",
"start": "umi dev",
"start:no-mock": "cross-env MOCK=none umi dev",
"test": "umi test",
"test:all": "node ./tests/run-tests.js",
"test:component": "umi test ./src/components"
},
"husky": {
"hooks": {
"pre-commit": "npm run lint-staged"
}
},
"lint-staged": {
"**/*.less": "stylelint --syntax less",
"**/*.{js,jsx,tsx,ts,less,md,json}": [
"prettier --write",
"git add"
],
"**/*.{js,jsx}": "npm run lint-staged:js",
"**/*.{js,ts,tsx}": "npm run lint-staged:js"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 10"
],
"dependencies": {
"@ant-design/colors": "^3.1.0",
"@ant-design/pro-layout": "^4.5.16",
"@antv/data-set": "^0.10.2",
"antd": "^3.23.6",
"classnames": "^2.2.6",
"dva": "^2.4.1",
"lodash": "^4.17.11",
"moment": "^2.24.0",
"omit.js": "^1.0.2",
"path-to-regexp": "^3.1.0",
"qs": "^6.9.0",
"react": "^16.8.6",
"react-copy-to-clipboard": "^5.0.1",
"react-document-title": "^2.0.3",
"react-dom": "^16.8.6",
"redux": "^4.0.1",
"slash2": "^2.0.0",
"umi": "^2.9.6",
"umi-plugin-pro-block": "^1.3.4",
"umi-plugin-react": "^1.10.1",
"umi-request": "^1.2.7",
"webpack-theme-color-replacer": "^1.2.15"
},
"devDependencies": {
"@ant-design/pro-cli": "^1.0.13",
"@types/classnames": "^2.2.7",
"@types/express": "^4.17.0",
"@types/history": "^4.7.2",
"@types/jest": "^24.0.13",
"@types/lodash": "^4.14.144",
"@types/qs": "^6.5.3",
"@types/react": "^16.8.19",
"@types/react-document-title": "^2.0.3",
"@types/react-dom": "^16.8.4",
"@umijs/fabric": "^1.2.0",
"chalk": "^2.4.2",
"check-prettier": "^1.0.3",
"cross-env": "^6.0.0",
"cross-port-killer": "^1.1.1",
"enzyme": "^3.9.0",
"eslint": "5.16.0",
"express": "^4.17.1",
"gh-pages": "^2.0.1",
"husky": "^3.0.0",
"import-sort-cli": "^6.0.0",
"import-sort-parser-babylon": "^6.0.0",
"import-sort-parser-typescript": "^6.0.0",
"import-sort-style-module": "^6.0.0",
"jest-puppeteer": "^4.2.0",
"lint-staged": "^9.0.0",
"mockjs": "^1.0.1-beta3",
"netlify-lambda": "^1.4.13",
"node-fetch": "^2.6.0",
"prettier": "^1.17.1",
"pro-download": "1.0.1",
"serverless-http": "^2.0.2",
"stylelint": "^10.1.0",
"umi-plugin-ga": "^1.1.3",
"umi-plugin-pro": "^1.0.2",
"umi-types": "^0.5.0"
},
"optionalDependencies": {
"puppeteer": "^1.17.0"
},
"engines": {
"node": ">=10.0.0"
},
"checkFiles": [
"src/**/*.js*",
"src/**/*.ts*",
"src/**/*.less",
"config/**/*.js*",
"scripts/**/*.js"
],
"create-umi": {
"ignoreScript": [
"docker*",
"functions*",
"site",
"generateMock"
],
"ignoreDependencies": [
"netlify*",
"serverless"
],
"ignore": [
".dockerignore",
".git",
".gitpod.yml",
"CODE_OF_CONDUCT.md",
"Dockerfile",
"Dockerfile.*",
"lambda",
"LICENSE",
"netlify.toml",
"README.*.md",
"azure-pipelines.yml",
"docker",
"CNAME",
"create-umi"
]
}
}
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="200px" height="200px" viewBox="0 0 200 200" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 47.1 (45422) - http://www.bohemiancoding.com/sketch -->
<title>Group 28 Copy 5</title>
<desc>Created with Sketch.</desc>
<defs>
<linearGradient x1="62.1023273%" y1="0%" x2="108.19718%" y2="37.8635764%" id="linearGradient-1">
<stop stop-color="#4285EB" offset="0%"></stop>
<stop stop-color="#2EC7FF" offset="100%"></stop>
</linearGradient>
<linearGradient x1="69.644116%" y1="0%" x2="54.0428975%" y2="108.456714%" id="linearGradient-2">
<stop stop-color="#29CDFF" offset="0%"></stop>
<stop stop-color="#148EFF" offset="37.8600687%"></stop>
<stop stop-color="#0A60FF" offset="100%"></stop>
</linearGradient>
<linearGradient x1="69.6908165%" y1="-12.9743587%" x2="16.7228981%" y2="117.391248%" id="linearGradient-3">
<stop stop-color="#FA816E" offset="0%"></stop>
<stop stop-color="#F74A5C" offset="41.472606%"></stop>
<stop stop-color="#F51D2C" offset="100%"></stop>
</linearGradient>
<linearGradient x1="68.1279872%" y1="-35.6905737%" x2="30.4400914%" y2="114.942679%" id="linearGradient-4">
<stop stop-color="#FA8E7D" offset="0%"></stop>
<stop stop-color="#F74A5C" offset="51.2635191%"></stop>
<stop stop-color="#F51D2C" offset="100%"></stop>
</linearGradient>
</defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="logo" transform="translate(-20.000000, -20.000000)">
<g id="Group-28-Copy-5" transform="translate(20.000000, 20.000000)">
<g id="Group-27-Copy-3">
<g id="Group-25" fill-rule="nonzero">
<g id="2">
<path d="M91.5880863,4.17652823 L4.17996544,91.5127728 C-0.519240605,96.2081146 -0.519240605,103.791885 4.17996544,108.487227 L91.5880863,195.823472 C96.2872923,200.518814 103.877304,200.518814 108.57651,195.823472 L145.225487,159.204632 C149.433969,154.999611 149.433969,148.181924 145.225487,143.976903 C141.017005,139.771881 134.193707,139.771881 129.985225,143.976903 L102.20193,171.737352 C101.032305,172.906015 99.2571609,172.906015 98.0875359,171.737352 L28.285908,101.993122 C27.1162831,100.824459 27.1162831,99.050775 28.285908,97.8821118 L98.0875359,28.1378823 C99.2571609,26.9692191 101.032305,26.9692191 102.20193,28.1378823 L129.985225,55.8983314 C134.193707,60.1033528 141.017005,60.1033528 145.225487,55.8983314 C149.433969,51.69331 149.433969,44.8756232 145.225487,40.6706018 L108.58055,4.05574592 C103.862049,-0.537986846 96.2692618,-0.500797906 91.5880863,4.17652823 Z" id="Shape" fill="url(#linearGradient-1)"></path>
<path d="M91.5880863,4.17652823 L4.17996544,91.5127728 C-0.519240605,96.2081146 -0.519240605,103.791885 4.17996544,108.487227 L91.5880863,195.823472 C96.2872923,200.518814 103.877304,200.518814 108.57651,195.823472 L145.225487,159.204632 C149.433969,154.999611 149.433969,148.181924 145.225487,143.976903 C141.017005,139.771881 134.193707,139.771881 129.985225,143.976903 L102.20193,171.737352 C101.032305,172.906015 99.2571609,172.906015 98.0875359,171.737352 L28.285908,101.993122 C27.1162831,100.824459 27.1162831,99.050775 28.285908,97.8821118 L98.0875359,28.1378823 C100.999864,25.6271836 105.751642,20.541824 112.729652,19.3524487 C117.915585,18.4685261 123.585219,20.4140239 129.738554,25.1889424 C125.624663,21.0784292 118.571995,14.0340304 108.58055,4.05574592 C103.862049,-0.537986846 96.2692618,-0.500797906 91.5880863,4.17652823 Z" id="Shape" fill="url(#linearGradient-2)"></path>
</g>
<path d="M153.685633,135.854579 C157.894115,140.0596 164.717412,140.0596 168.925894,135.854579 L195.959977,108.842726 C200.659183,104.147384 200.659183,96.5636133 195.960527,91.8688194 L168.690777,64.7181159 C164.472332,60.5180858 157.646868,60.5241425 153.435895,64.7316526 C149.227413,68.936674 149.227413,75.7543607 153.435895,79.9593821 L171.854035,98.3623765 C173.02366,99.5310396 173.02366,101.304724 171.854035,102.473387 L153.685633,120.626849 C149.47715,124.83187 149.47715,131.649557 153.685633,135.854579 Z" id="Shape" fill="url(#linearGradient-3)"></path>
</g>
<ellipse id="Combined-Shape" fill="url(#linearGradient-4)" cx="100.519339" cy="100.436681" rx="23.6001926" ry="23.580786"></ellipse>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
import React from 'react';
import check, { IAuthorityType } from './CheckPermissions';
import AuthorizedRoute from './AuthorizedRoute';
import Secured from './Secured';
interface AuthorizedProps {
authority: IAuthorityType;
noMatch?: React.ReactNode;
}
type IAuthorizedType = React.FunctionComponent<AuthorizedProps> & {
Secured: typeof Secured;
check: typeof check;
AuthorizedRoute: typeof AuthorizedRoute;
};
const Authorized: React.FunctionComponent<AuthorizedProps> = ({
children,
authority,
noMatch = null,
}) => {
const childrenRender: React.ReactNode = typeof children === 'undefined' ? null : children;
const dom = check(authority, childrenRender, noMatch);
return <>{dom}</>;
};
export default Authorized as IAuthorizedType;
import { Redirect, Route } from 'umi';
import React from 'react';
import Authorized from './Authorized';
import { IAuthorityType } from './CheckPermissions';
interface AuthorizedRoutePops {
currentAuthority: string;
component: React.ComponentClass<any, any>;
render: (props: any) => React.ReactNode;
redirectPath: string;
authority: IAuthorityType;
}
const AuthorizedRoute: React.SFC<AuthorizedRoutePops> = ({
component: Component,
render,
authority,
redirectPath,
...rest
}) => (
<Authorized
authority={authority}
noMatch={<Route {...rest} render={() => <Redirect to={{ pathname: redirectPath }} />} />}
>
<Route
{...rest}
render={(props: any) => (Component ? <Component {...props} /> : render(props))}
/>
</Authorized>
);
export default AuthorizedRoute;
import React from 'react';
import { CURRENT } from './renderAuthorize';
// eslint-disable-next-line import/no-cycle
import PromiseRender from './PromiseRender';
export type IAuthorityType =
| undefined
| string
| string[]
| Promise<boolean>
| ((currentAuthority: string | string[]) => IAuthorityType);
/**
* 通用权限检查方法
* Common check permissions method
* @param { 权限判定 | Permission judgment } authority
* @param { 你的权限 | Your permission description } currentAuthority
* @param { 通过的组件 | Passing components } target
* @param { 未通过的组件 | no pass components } Exception
*/
const checkPermissions = <T, K>(
authority: IAuthorityType,
currentAuthority: string | string[],
target: T,
Exception: K,
): T | K | React.ReactNode => {
// 没有判定权限.默认查看所有
// Retirement authority, return target;
if (!authority) {
return target;
}
// 数组处理
if (Array.isArray(authority)) {
if (Array.isArray(currentAuthority)) {
if (currentAuthority.some(item => authority.includes(item))) {
return target;
}
} else if (authority.includes(currentAuthority)) {
return target;
}
return Exception;
}
// string 处理
if (typeof authority === 'string') {
if (Array.isArray(currentAuthority)) {
if (currentAuthority.some(item => authority === item)) {
return target;
}
} else if (authority === currentAuthority) {
return target;
}
return Exception;
}
// Promise 处理
if (authority instanceof Promise) {
return <PromiseRender<T, K> ok={target} error={Exception} promise={authority} />;
}
// Function 处理
if (typeof authority === 'function') {
try {
const bool = authority(currentAuthority);
// 函数执行后返回值是 Promise
if (bool instanceof Promise) {
return <PromiseRender<T, K> ok={target} error={Exception} promise={bool} />;
}
if (bool) {
return target;
}
return Exception;
} catch (error) {
throw error;
}
}
throw new Error('unsupported parameters');
};
export { checkPermissions };
function check<T, K>(authority: IAuthorityType, target: T, Exception: K): T | K | React.ReactNode {
return checkPermissions<T, K>(authority, CURRENT, target, Exception);
}
export default check;
import React from 'react';
import { Spin } from 'antd';
import isEqual from 'lodash/isEqual';
import { isComponentClass } from './Secured';
// eslint-disable-next-line import/no-cycle
interface PromiseRenderProps<T, K> {
ok: T;
error: K;
promise: Promise<boolean>;
}
interface PromiseRenderState {
component: React.ComponentClass | React.FunctionComponent;
}
export default class PromiseRender<T, K> extends React.Component<
PromiseRenderProps<T, K>,
PromiseRenderState
> {
state: PromiseRenderState = {
component: () => null,
};
componentDidMount() {
this.setRenderComponent(this.props);
}
shouldComponentUpdate = (nextProps: PromiseRenderProps<T, K>, nextState: PromiseRenderState) => {
const { component } = this.state;
if (!isEqual(nextProps, this.props)) {
this.setRenderComponent(nextProps);
}
if (nextState.component !== component) return true;
return false;
};
// set render Component : ok or error
setRenderComponent(props: PromiseRenderProps<T, K>) {
const ok = this.checkIsInstantiation(props.ok);
const error = this.checkIsInstantiation(props.error);
props.promise
.then(() => {
this.setState({
component: ok,
});
return true;
})
.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: React.ReactNode | React.ComponentClass,
): React.FunctionComponent => {
if (isComponentClass(target)) {
const Target = target as React.ComponentClass;
return (props: any) => <Target {...props} />;
}
if (React.isValidElement(target)) {
return (props: any) => React.cloneElement(target, props);
}
return () => target as (React.ReactNode & null);
};
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>
);
}
}
import React from 'react';
import CheckPermissions from './CheckPermissions';
/**
* 默认不能访问任何页面
* default is "NULL"
*/
const Exception403 = () => 403;
export const isComponentClass = (component: React.ComponentClass | React.ReactNode): boolean => {
if (!component) return false;
const proto = Object.getPrototypeOf(component);
if (proto === React.Component || proto === Function.prototype) return true;
return isComponentClass(proto);
};
// 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: React.ComponentClass | React.ReactNode) => {
if (isComponentClass(target)) {
const Target = target as React.ComponentClass;
return (props: any) => <Target {...props} />;
}
if (React.isValidElement(target)) {
return (props: any) => React.cloneElement(target, props);
}
return () => target;
};
/**
* 用于判断是否拥有权限访问此 view 权限
* authority 支持传入 string, () => 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, () => 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: string, error?: React.ReactNode) => {
/**
* conversion into a class
* 防止传入字符串时找不到staticContext造成报错
* String parameters can cause staticContext not found error
*/
let classError: boolean | React.FunctionComponent = false;
if (error) {
classError = (() => error) as React.FunctionComponent;
}
if (!authority) {
throw new Error('authority is required');
}
return function decideAuthority(target: React.ComponentClass | React.ReactNode) {
const component = CheckPermissions(authority, target, classError || Exception403);
return checkIsInstantiation(component);
};
};
export default authorize;
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;
const RenderAuthorize = renderAuthorize(Authorized);
export default RenderAuthorize;
/* eslint-disable eslint-comments/disable-enable-pair */
/* eslint-disable import/no-mutable-exports */
let CURRENT: string | string[] = 'NULL';
type CurrentAuthorityType = string | string[] | (() => typeof CURRENT);
/**
* use authority or getAuthority
* @param {string|()=>String} currentAuthority
*/
const renderAuthorize = <T>(Authorized: T): ((currentAuthority: CurrentAuthorityType) => T) => (
currentAuthority: CurrentAuthorityType,
): T => {
if (currentAuthority) {
if (typeof currentAuthority === 'function') {
CURRENT = currentAuthority();
}
if (
Object.prototype.toString.call(currentAuthority) === '[object String]' ||
Array.isArray(currentAuthority)
) {
CURRENT = currentAuthority as string[];
}
} else {
CURRENT = 'NULL';
}
return Authorized;
};
export { CURRENT };
export default <T>(Authorized: T) => renderAuthorize<T>(Authorized);
.copy-block {
position: fixed;
right: 80px;
bottom: 40px;
z-index: 99;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
font-size: 20px;
background: #fff;
border-radius: 40px;
box-shadow: 0 2px 4px -1px rgba(0, 0, 0, 0.2), 0 4px 5px 0 rgba(0, 0, 0, 0.14),
0 1px 10px 0 rgba(0, 0, 0, 0.12);
cursor: pointer;
}
.copy-block-view {
position: relative;
.copy-block-code {
display: inline-block;
margin: 0 0.2em;
padding: 0.2em 0.4em 0.1em;
font-size: 85%;
border-radius: 3px;
}
}
import { Icon, Popover, Typography } from 'antd';
import React, { useRef } from 'react';
import { FormattedMessage } from 'umi-plugin-react/locale';
import { connect } from 'dva';
import { isAntDesignPro } from '@/utils/utils';
import styles from './index.less';
const firstUpperCase = (pathString: string): string =>
pathString
.replace('.', '')
.split(/\/|-/)
.map((s): string => s.toLowerCase().replace(/( |^)[a-z]/g, L => L.toUpperCase()))
.filter((s): boolean => !!s)
.join('');
// when click block copy, send block url to ga
const onBlockCopy = (label: string) => {
if (!isAntDesignPro()) {
return;
}
const ga = window && window.ga;
if (ga) {
ga('send', 'event', {
eventCategory: 'block',
eventAction: 'copy',
eventLabel: label,
});
}
};
const BlockCodeView: React.SFC<{
url: string;
}> = ({ url }) => {
const blockUrl = `npx umi block add ${firstUpperCase(url)} --path=${url}`;
return (
<div className={styles['copy-block-view']}>
<Typography.Paragraph
copyable={{
text: blockUrl,
onCopy: () => onBlockCopy(url),
}}
style={{
display: 'flex',
}}
>
<pre>
<code className={styles['copy-block-code']}>{blockUrl}</code>
</pre>
</Typography.Paragraph>
</div>
);
};
interface RoutingType {
location: {
pathname: string;
};
}
export default connect(({ routing }: { routing: RoutingType }) => ({
location: routing.location,
}))(({ location }: RoutingType) => {
const url = location.pathname;
const divDom = useRef<HTMLDivElement>(null);
return (
<Popover
title={<FormattedMessage id="app.preview.down.block" defaultMessage="下载此页面到本地项目" />}
placement="topLeft"
content={<BlockCodeView url={url} />}
trigger="click"
getPopupContainer={dom => (divDom.current ? divDom.current : dom)}
>
<div className={styles['copy-block']} ref={divDom}>
<Icon type="download" />
</div>
</Popover>
);
});
import { Avatar, Icon, Menu, Spin } from 'antd';
import { ClickParam } from 'antd/es/menu';
import { FormattedMessage } from 'umi-plugin-react/locale';
import React from 'react';
import { connect } from 'dva';
import router from 'umi/router';
import { ConnectProps, ConnectState } from '@/models/connect';
import { CurrentUser } from '@/models/user';
import HeaderDropdown from '../HeaderDropdown';
import styles from './index.less';
export interface GlobalHeaderRightProps extends ConnectProps {
currentUser?: CurrentUser;
menu?: boolean;
}
class AvatarDropdown extends React.Component<GlobalHeaderRightProps> {
onMenuClick = (event: ClickParam) => {
const { key } = event;
if (key === 'logout') {
const { dispatch } = this.props;
if (dispatch) {
dispatch({
type: 'login/logout',
});
}
return;
}
router.push(`/account/${key}`);
};
render(): React.ReactNode {
const { currentUser = { avatar: '', name: '' }, menu } = this.props;
const menuHeaderDropdown = (
<Menu className={styles.menu} selectedKeys={[]} onClick={this.onMenuClick}>
{menu && (
<Menu.Item key="center">
<Icon type="user" />
<FormattedMessage id="menu.account.center" defaultMessage="account center" />
</Menu.Item>
)}
{menu && (
<Menu.Item key="settings">
<Icon type="setting" />
<FormattedMessage id="menu.account.settings" defaultMessage="account settings" />
</Menu.Item>
)}
{menu && <Menu.Divider />}
<Menu.Item key="logout">
<Icon type="logout" />
<FormattedMessage id="menu.account.logout" defaultMessage="logout" />
</Menu.Item>
</Menu>
);
return currentUser && currentUser.name ? (
<HeaderDropdown overlay={menuHeaderDropdown}>
<span className={`${styles.action} ${styles.account}`}>
<Avatar size="small" className={styles.avatar} src={currentUser.avatar} alt="avatar" />
<span className={styles.name}>{currentUser.name}</span>
</span>
</HeaderDropdown>
) : (
<Spin size="small" style={{ marginLeft: 8, marginRight: 8 }} />
);
}
}
export default connect(({ user }: ConnectState) => ({
currentUser: user.currentUser,
}))(AvatarDropdown);
import React, { Component } from 'react';
import { Tag, message } from 'antd';
import { connect } from 'dva';
import { formatMessage } from 'umi-plugin-react/locale';
import groupBy from 'lodash/groupBy';
import moment from 'moment';
import { NoticeItem } from '@/models/global';
import NoticeIcon from '../NoticeIcon';
import { CurrentUser } from '@/models/user';
import { ConnectProps, ConnectState } from '@/models/connect';
import styles from './index.less';
export interface GlobalHeaderRightProps extends ConnectProps {
notices?: NoticeItem[];
currentUser?: CurrentUser;
fetchingNotices?: boolean;
onNoticeVisibleChange?: (visible: boolean) => void;
onNoticeClear?: (tabName?: string) => void;
}
class GlobalHeaderRight extends Component<GlobalHeaderRightProps> {
componentDidMount() {
const { dispatch } = this.props;
if (dispatch) {
dispatch({
type: 'global/fetchNotices',
});
}
}
changeReadState = (clickedItem: NoticeItem): void => {
const { id } = clickedItem;
const { dispatch } = this.props;
if (dispatch) {
dispatch({
type: 'global/changeNoticeReadState',
payload: id,
});
}
};
handleNoticeClear = (title: string, key: string) => {
const { dispatch } = this.props;
message.success(`${formatMessage({ id: 'component.noticeIcon.cleared' })} ${title}`);
if (dispatch) {
dispatch({
type: 'global/clearNotices',
payload: key,
});
}
};
getNoticeData = (): { [key: string]: NoticeItem[] } => {
const { notices = [] } = this.props;
if (notices.length === 0) {
return {};
}
const newNotices = notices.map(notice => {
const newNotice = { ...notice };
if (newNotice.datetime) {
newNotice.datetime = moment(notice.datetime as string).fromNow();
}
if (newNotice.id) {
newNotice.key = newNotice.id;
}
if (newNotice.extra && newNotice.status) {
const color = {
todo: '',
processing: 'blue',
urgent: 'red',
doing: 'gold',
}[newNotice.status];
newNotice.extra = (
<Tag color={color} style={{ marginRight: 0 }}>
{newNotice.extra}
</Tag>
);
}
return newNotice;
});
return groupBy(newNotices, 'type');
};
getUnreadData = (noticeData: { [key: string]: NoticeItem[] }) => {
const unreadMsg: { [key: string]: number } = {};
Object.keys(noticeData).forEach(key => {
const value = noticeData[key];
if (!unreadMsg[key]) {
unreadMsg[key] = 0;
}
if (Array.isArray(value)) {
unreadMsg[key] = value.filter(item => !item.read).length;
}
});
return unreadMsg;
};
render() {
const { currentUser, fetchingNotices, onNoticeVisibleChange } = this.props;
const noticeData = this.getNoticeData();
const unreadMsg = this.getUnreadData(noticeData);
return (
<NoticeIcon
className={styles.action}
count={currentUser && currentUser.unreadCount}
onItemClick={item => {
this.changeReadState(item as NoticeItem);
}}
loading={fetchingNotices}
clearText={formatMessage({ id: 'component.noticeIcon.clear' })}
viewMoreText={formatMessage({ id: 'component.noticeIcon.view-more' })}
onClear={this.handleNoticeClear}
onPopupVisibleChange={onNoticeVisibleChange}
onViewMore={() => message.info('Click on view more')}
clearClose
>
<NoticeIcon.Tab
tabKey="notification"
count={unreadMsg.notification}
list={noticeData.notification}
title={formatMessage({ id: 'component.globalHeader.notification' })}
emptyText={formatMessage({ id: 'component.globalHeader.notification.empty' })}
showViewMore
/>
<NoticeIcon.Tab
tabKey="message"
count={unreadMsg.message}
list={noticeData.message}
title={formatMessage({ id: 'component.globalHeader.message' })}
emptyText={formatMessage({ id: 'component.globalHeader.message.empty' })}
showViewMore
/>
<NoticeIcon.Tab
tabKey="event"
title={formatMessage({ id: 'component.globalHeader.event' })}
emptyText={formatMessage({ id: 'component.globalHeader.event.empty' })}
count={unreadMsg.event}
list={noticeData.event}
showViewMore
/>
</NoticeIcon>
);
}
}
export default connect(({ user, global, loading }: ConnectState) => ({
currentUser: user.currentUser,
collapsed: global.collapsed,
fetchingMoreNotices: loading.effects['global/fetchMoreNotices'],
fetchingNotices: loading.effects['global/fetchNotices'],
notices: global.notices,
}))(GlobalHeaderRight);
import { Icon, Tooltip } from 'antd';
import React from 'react';
import { connect } from 'dva';
import { formatMessage } from 'umi-plugin-react/locale';
import { ConnectProps, ConnectState } from '@/models/connect';
import Avatar from './AvatarDropdown';
import HeaderSearch from '../HeaderSearch';
import SelectLang from '../SelectLang';
import styles from './index.less';
export type SiderTheme = 'light' | 'dark';
export interface GlobalHeaderRightProps extends ConnectProps {
theme?: SiderTheme;
layout: 'sidemenu' | 'topmenu';
}
const GlobalHeaderRight: React.SFC<GlobalHeaderRightProps> = props => {
const { theme, layout } = props;
let className = styles.right;
if (theme === 'dark' && layout === 'topmenu') {
className = `${styles.right} ${styles.dark}`;
}
return (
<div className={className}>
<HeaderSearch
className={`${styles.action} ${styles.search}`}
placeholder={formatMessage({
id: 'component.globalHeader.search',
})}
defaultValue="umi ui"
dataSource={[
formatMessage({
id: 'component.globalHeader.search.example1',
}),
formatMessage({
id: 'component.globalHeader.search.example2',
}),
formatMessage({
id: 'component.globalHeader.search.example3',
}),
]}
onSearch={value => {
console.log('input', value);
}}
onPressEnter={value => {
console.log('enter', value);
}}
/>
<Tooltip
title={formatMessage({
id: 'component.globalHeader.help',
})}
>
<a
target="_blank"
href="https://pro.ant.design/docs/getting-started"
rel="noopener noreferrer"
className={styles.action}
>
<Icon type="question-circle-o" />
</a>
</Tooltip>
<Avatar />
<SelectLang className={styles.action} />
</div>
);
};
export default connect(({ settings }: ConnectState) => ({
theme: settings.navTheme,
layout: settings.layout,
}))(GlobalHeaderRight);
@import '~antd/es/style/themes/default.less';
@pro-header-hover-bg: rgba(0, 0, 0, 0.025);
.logo {
display: inline-block;
height: @layout-header-height;
padding: 0 0 0 24px;
font-size: 20px;
line-height: @layout-header-height;
vertical-align: top;
cursor: pointer;
img {
display: inline-block;
vertical-align: middle;
}
}
.menu {
:global(.anticon) {
margin-right: 8px;
}
:global(.ant-dropdown-menu-item) {
min-width: 160px;
}
}
.trigger {
height: @layout-header-height;
padding: ~'calc((@{layout-header-height} - 20px) / 2)' 24px;
font-size: 20px;
cursor: pointer;
transition: all 0.3s, padding 0s;
&:hover {
background: @pro-header-hover-bg;
}
}
.right {
float: right;
height: 100%;
margin-left: auto;
overflow: hidden;
.action {
display: inline-block;
height: 100%;
padding: 0 12px;
cursor: pointer;
transition: all 0.3s;
> i {
color: @text-color;
vertical-align: middle;
}
&:hover {
background: @pro-header-hover-bg;
}
&:global(.opened) {
background: @pro-header-hover-bg;
}
}
.search {
padding: 0 12px;
&:hover {
background: transparent;
}
}
.account {
.avatar {
margin: ~'calc((@{layout-header-height} - 24px) / 2)' 0;
margin-right: 8px;
color: @primary-color;
vertical-align: top;
background: rgba(255, 255, 255, 0.85);
}
}
}
.dark {
height: @layout-header-height;
.action {
color: rgba(255, 255, 255, 0.85);
> i {
color: rgba(255, 255, 255, 0.85);
}
&:hover,
&:global(.opened) {
background: @primary-color;
}
}
}
:global(.ant-pro-global-header) {
.dark {
.action {
color: @text-color;
> i {
color: @text-color;
}
&:hover {
color: rgba(255, 255, 255, 0.85);
> i {
color: rgba(255, 255, 255, 0.85);
}
}
}
}
}
@media only screen and (max-width: @screen-md) {
:global(.ant-divider-vertical) {
vertical-align: unset;
}
.name {
display: none;
}
i.trigger {
padding: 22px 12px;
}
.logo {
position: relative;
padding-right: 12px;
padding-left: 12px;
}
.right {
position: absolute;
top: 0;
right: 12px;
.account {
.avatar {
margin-right: 0;
}
}
}
}
@import '~antd/es/style/themes/default.less';
.container > * {
background-color: #fff;
border-radius: 4px;
box-shadow: @shadow-1-down;
}
@media screen and (max-width: @screen-xs) {
.container {
width: 100% !important;
}
.container > * {
border-radius: 0 !important;
}
}
import { DropDownProps } from 'antd/es/dropdown';
import { Dropdown } from 'antd';
import React from 'react';
import classNames from 'classnames';
import styles from './index.less';
declare type OverlayFunc = () => React.ReactNode;
export interface HeaderDropdownProps extends DropDownProps {
overlayClassName?: string;
overlay: React.ReactNode | OverlayFunc;
placement?: 'bottomLeft' | 'bottomRight' | 'topLeft' | 'topCenter' | 'topRight' | 'bottomCenter';
}
const HeaderDropdown: React.FC<HeaderDropdownProps> = ({ overlayClassName: cls, ...restProps }) => (
<Dropdown overlayClassName={classNames(styles.container, cls)} {...restProps} />
);
export default HeaderDropdown;
@import '~antd/es/style/themes/default.less';
.headerSearch {
:global(.anticon-search) {
font-size: 16px;
cursor: pointer;
}
.input {
width: 0;
background: transparent;
border-radius: 0;
transition: width 0.3s, margin-left 0.3s;
:global(.ant-select-selection) {
background: transparent;
}
input {
padding-right: 0;
padding-left: 0;
border: 0;
box-shadow: none !important;
}
&,
&:hover,
&:focus {
border-bottom: 1px solid @border-color-base;
}
&.show {
width: 210px;
margin-left: 8px;
}
}
}
import { AutoComplete, Icon, Input } from 'antd';
import { AutoCompleteProps, DataSourceItemType } from 'antd/es/auto-complete';
import React, { Component } from 'react';
import classNames from 'classnames';
import debounce from 'lodash/debounce';
import styles from './index.less';
export interface HeaderSearchProps {
onPressEnter: (value: string) => void;
onSearch: (value: string) => void;
onChange: (value: string) => void;
onVisibleChange: (b: boolean) => void;
className: string;
placeholder: string;
defaultActiveFirstOption: boolean;
dataSource: DataSourceItemType[];
defaultOpen: boolean;
open?: boolean;
defaultValue?: string;
}
interface HeaderSearchState {
value?: string;
searchMode: boolean;
}
export default class HeaderSearch extends Component<HeaderSearchProps, HeaderSearchState> {
static defaultProps = {
defaultActiveFirstOption: false,
onPressEnter: () => {},
onSearch: () => {},
onChange: () => {},
className: '',
placeholder: '',
dataSource: [],
defaultOpen: false,
onVisibleChange: () => {},
};
static getDerivedStateFromProps(props: HeaderSearchProps) {
if ('open' in props) {
return {
searchMode: props.open,
};
}
return null;
}
private inputRef: Input | null = null;
constructor(props: HeaderSearchProps) {
super(props);
this.state = {
searchMode: props.defaultOpen,
value: props.defaultValue,
};
this.debouncePressEnter = debounce(this.debouncePressEnter, 500, {
leading: true,
trailing: false,
});
}
onKeyDown = (e: React.KeyboardEvent) => {
if (e.key === 'Enter') {
this.debouncePressEnter();
}
};
onChange: AutoCompleteProps['onChange'] = value => {
if (typeof value === 'string') {
const { onSearch, onChange } = this.props;
this.setState({ value });
if (onSearch) {
onSearch(value);
}
if (onChange) {
onChange(value);
}
}
};
enterSearchMode = () => {
const { onVisibleChange } = this.props;
onVisibleChange(true);
this.setState({ searchMode: true }, () => {
const { searchMode } = this.state;
if (searchMode && this.inputRef) {
this.inputRef.focus();
}
});
};
leaveSearchMode = () => {
this.setState({
searchMode: false,
});
};
debouncePressEnter = () => {
const { onPressEnter } = this.props;
const { value } = this.state;
onPressEnter(value || '');
};
render() {
const { className, defaultValue, placeholder, open, ...restProps } = this.props;
const { searchMode, value } = this.state;
delete restProps.defaultOpen; // for rc-select not affected
const inputClass = classNames(styles.input, {
[styles.show]: searchMode,
});
return (
<span
className={classNames(className, styles.headerSearch)}
onClick={this.enterSearchMode}
onTransitionEnd={({ propertyName }) => {
if (propertyName === 'width' && !searchMode) {
const { onVisibleChange } = this.props;
onVisibleChange(searchMode);
}
}}
>
<Icon type="search" key="Icon" />
<AutoComplete
key="AutoComplete"
{...restProps}
className={inputClass}
value={value}
onChange={this.onChange}
>
<Input
ref={node => {
this.inputRef = node;
}}
defaultValue={defaultValue}
aria-label={placeholder}
placeholder={placeholder}
onKeyDown={this.onKeyDown}
onBlur={this.leaveSearchMode}
/>
</AutoComplete>
</span>
);
}
}
@import '~antd/es/style/themes/default.less';
.list {
max-height: 400px;
overflow: auto;
&::-webkit-scrollbar {
display: none;
}
.item {
padding-right: 24px;
padding-left: 24px;
overflow: hidden;
cursor: pointer;
transition: all 0.3s;
.meta {
width: 100%;
}
.avatar {
margin-top: 4px;
background: #fff;
}
.iconElement {
font-size: 32px;
}
&.read {
opacity: 0.4;
}
&:last-child {
border-bottom: 0;
}
&:hover {
background: @primary-1;
}
.title {
margin-bottom: 8px;
font-weight: normal;
}
.description {
font-size: 12px;
line-height: @line-height-base;
}
.datetime {
margin-top: 4px;
font-size: 12px;
line-height: @line-height-base;
}
.extra {
float: right;
margin-top: -1.5px;
margin-right: 0;
color: @text-color-secondary;
font-weight: normal;
}
}
.loadMore {
padding: 8px 0;
color: @primary-6;
text-align: center;
cursor: pointer;
&.loadedAll {
color: rgba(0, 0, 0, 0.25);
cursor: unset;
}
}
}
.notFound {
padding: 73px 0 88px;
color: @text-color-secondary;
text-align: center;
img {
display: inline-block;
height: 76px;
margin-bottom: 16px;
}
}
.bottomBar {
height: 46px;
color: @text-color;
line-height: 46px;
text-align: center;
border-top: 1px solid @border-color-split;
border-radius: 0 0 @border-radius-base @border-radius-base;
transition: all 0.3s;
div {
display: inline-block;
width: 50%;
cursor: pointer;
transition: all 0.3s;
user-select: none;
&:hover {
color: @heading-color;
}
&:only-child {
width: 100%;
}
&:not(:only-child):last-child {
border-left: 1px solid @border-color-split;
}
}
}
import { Avatar, List } from 'antd';
import React from 'react';
import classNames from 'classnames';
import { NoticeIconData } from './index';
import styles from './NoticeList.less';
export interface NoticeIconTabProps {
count?: number;
name?: string;
showClear?: boolean;
showViewMore?: boolean;
style?: React.CSSProperties;
title: string;
tabKey: string;
data?: NoticeIconData[];
onClick?: (item: NoticeIconData) => void;
onClear?: () => void;
emptyText?: string;
clearText?: string;
viewMoreText?: string;
list: NoticeIconData[];
onViewMore?: (e: any) => void;
}
const NoticeList: React.SFC<NoticeIconTabProps> = ({
data = [],
onClick,
onClear,
title,
onViewMore,
emptyText,
showClear = true,
clearText,
viewMoreText,
showViewMore = false,
}) => {
if (data.length === 0) {
return (
<div className={styles.notFound}>
<img
src="https://gw.alipayobjects.com/zos/rmsportal/sAuJeJzSKbUmHfBQRzmZ.svg"
alt="not found"
/>
<div>{emptyText}</div>
</div>
);
}
return (
<div>
<List<NoticeIconData>
className={styles.list}
dataSource={data}
renderItem={(item, i) => {
const itemCls = classNames(styles.item, {
[styles.read]: item.read,
});
// eslint-disable-next-line no-nested-ternary
const leftIcon = item.avatar ? (
typeof item.avatar === 'string' ? (
<Avatar className={styles.avatar} src={item.avatar} />
) : (
<span className={styles.iconElement}>{item.avatar}</span>
)
) : null;
return (
<List.Item
className={itemCls}
key={item.key || i}
onClick={() => onClick && onClick(item)}
>
<List.Item.Meta
className={styles.meta}
avatar={leftIcon}
title={
<div className={styles.title}>
{item.title}
<div className={styles.extra}>{item.extra}</div>
</div>
}
description={
<div>
<div className={styles.description}>{item.description}</div>
<div className={styles.datetime}>{item.datetime}</div>
</div>
}
/>
</List.Item>
);
}}
/>
<div className={styles.bottomBar}>
{showClear ? (
<div onClick={onClear}>
{clearText} {title}
</div>
) : null}
{showViewMore ? (
<div
onClick={e => {
if (onViewMore) {
onViewMore(e);
}
}}
>
{viewMoreText}
</div>
) : null}
</div>
</div>
);
};
export default NoticeList;
@import '~antd/es/style/themes/default.less';
.popover {
position: relative;
width: 336px;
}
.noticeButton {
display: inline-block;
cursor: pointer;
transition: all 0.3s;
}
.icon {
padding: 4px;
vertical-align: middle;
}
.badge {
font-size: 16px;
}
.tabs {
:global {
.ant-tabs-nav-scroll {
text-align: center;
}
.ant-tabs-bar {
margin-bottom: 0;
}
}
}
import { Badge, Icon, Spin, Tabs } from 'antd';
import React, { Component } from 'react';
import classNames from 'classnames';
import NoticeList, { NoticeIconTabProps } from './NoticeList';
import HeaderDropdown from '../HeaderDropdown';
import styles from './index.less';
const { TabPane } = Tabs;
export interface NoticeIconData {
avatar?: string | React.ReactNode;
title?: React.ReactNode;
description?: React.ReactNode;
datetime?: React.ReactNode;
extra?: React.ReactNode;
style?: React.CSSProperties;
key?: string | number;
read?: boolean;
}
export interface NoticeIconProps {
count?: number;
bell?: React.ReactNode;
className?: string;
loading?: boolean;
onClear?: (tabName: string, tabKey: string) => void;
onItemClick?: (item: NoticeIconData, tabProps: NoticeIconTabProps) => void;
onViewMore?: (tabProps: NoticeIconTabProps, e: MouseEvent) => void;
onTabChange?: (tabTile: string) => void;
style?: React.CSSProperties;
onPopupVisibleChange?: (visible: boolean) => void;
popupVisible?: boolean;
clearText?: string;
viewMoreText?: string;
clearClose?: boolean;
children: React.ReactElement<NoticeIconTabProps>[];
}
export default class NoticeIcon extends Component<NoticeIconProps> {
public static Tab: typeof NoticeList = NoticeList;
static defaultProps = {
onItemClick: (): void => {},
onPopupVisibleChange: (): void => {},
onTabChange: (): void => {},
onClear: (): void => {},
onViewMore: (): void => {},
loading: false,
clearClose: false,
emptyImage: 'https://gw.alipayobjects.com/zos/rmsportal/wAhyIChODzsoKIOBHcBk.svg',
};
state = {
visible: false,
};
onItemClick = (item: NoticeIconData, tabProps: NoticeIconTabProps): void => {
const { onItemClick } = this.props;
if (onItemClick) {
onItemClick(item, tabProps);
}
};
onClear = (name: string, key: string): void => {
const { onClear } = this.props;
if (onClear) {
onClear(name, key);
}
};
onTabChange = (tabType: string): void => {
const { onTabChange } = this.props;
if (onTabChange) {
onTabChange(tabType);
}
};
onViewMore = (tabProps: NoticeIconTabProps, event: MouseEvent): void => {
const { onViewMore } = this.props;
if (onViewMore) {
onViewMore(tabProps, event);
}
};
getNotificationBox(): React.ReactNode {
const { children, loading, clearText, viewMoreText } = this.props;
if (!children) {
return null;
}
const panes = React.Children.map(
children,
(child: React.ReactElement<NoticeIconTabProps>): React.ReactNode => {
if (!child) {
return null;
}
const { list, title, count, tabKey, showClear, showViewMore } = child.props;
const len = list && list.length ? list.length : 0;
const msgCount = count || count === 0 ? count : len;
const tabTitle: string = msgCount > 0 ? `${title} (${msgCount})` : title;
return (
<TabPane tab={tabTitle} key={title}>
<NoticeList
clearText={clearText}
viewMoreText={viewMoreText}
data={list}
onClear={(): void => this.onClear(title, tabKey)}
onClick={(item): void => this.onItemClick(item, child.props)}
onViewMore={(event): void => this.onViewMore(child.props, event)}
showClear={showClear}
showViewMore={showViewMore}
title={title}
{...child.props}
/>
</TabPane>
);
},
);
return (
<>
<Spin spinning={loading} delay={300}>
<Tabs className={styles.tabs} onChange={this.onTabChange}>
{panes}
</Tabs>
</Spin>
</>
);
}
handleVisibleChange = (visible: boolean): void => {
const { onPopupVisibleChange } = this.props;
this.setState({ visible });
if (onPopupVisibleChange) {
onPopupVisibleChange(visible);
}
};
render(): React.ReactNode {
const { className, count, popupVisible, bell } = this.props;
const { visible } = this.state;
const noticeButtonClass = classNames(className, styles.noticeButton);
const notificationBox = this.getNotificationBox();
const NoticeBellIcon = bell || <Icon type="bell" className={styles.icon} />;
const trigger = (
<span className={classNames(noticeButtonClass, { opened: visible })}>
<Badge count={count} style={{ boxShadow: 'none' }} className={styles.badge}>
{NoticeBellIcon}
</Badge>
</span>
);
if (!notificationBox) {
return trigger;
}
const popoverProps: {
visible?: boolean;
} = {};
if ('popupVisible' in this.props) {
popoverProps.visible = popupVisible;
}
return (
<HeaderDropdown
placement="bottomRight"
overlay={notificationBox}
overlayClassName={styles.popover}
trigger={['click']}
visible={visible}
onVisibleChange={this.handleVisibleChange}
{...popoverProps}
>
{trigger}
</HeaderDropdown>
);
}
}
import React from 'react';
import { Spin } from 'antd';
// loading components from code split
// https://umijs.org/plugin/umi-plugin-react.html#dynamicimport
const PageLoading: React.FC = () => (
<div style={{ paddingTop: 100, textAlign: 'center' }}>
<Spin size="large" />
</div>
);
export default PageLoading;
@import '~antd/es/style/themes/default.less';
.menu {
:global(.anticon) {
margin-right: 8px;
}
:global(.ant-dropdown-menu-item) {
min-width: 160px;
}
}
.dropDown {
line-height: @layout-header-height;
vertical-align: top;
cursor: pointer;
> i {
font-size: 16px !important;
transform: none !important;
svg {
position: relative;
top: -1px;
}
}
}
import { Icon, Menu } from 'antd';
import { formatMessage, getLocale, setLocale } from 'umi-plugin-react/locale';
import { ClickParam } from 'antd/es/menu';
import React from 'react';
import classNames from 'classnames';
import HeaderDropdown from '../HeaderDropdown';
import styles from './index.less';
interface SelectLangProps {
className?: string;
}
const SelectLang: React.FC<SelectLangProps> = props => {
const { className } = props;
const selectedLang = getLocale();
const changeLang = ({ key }: ClickParam): void => setLocale(key, false);
const locales = ['zh-CN', 'zh-TW', 'en-US', 'pt-BR'];
const languageLabels = {
'zh-CN': '简体中文',
'zh-TW': '繁体中文',
'en-US': 'English',
'pt-BR': 'Português',
};
const languageIcons = {
'zh-CN': '🇨🇳',
'zh-TW': '🇭🇰',
'en-US': '🇺🇸',
'pt-BR': '🇧🇷',
};
const langMenu = (
<Menu className={styles.menu} selectedKeys={[selectedLang]} onClick={changeLang}>
{locales.map(locale => (
<Menu.Item key={locale}>
<span role="img" aria-label={languageLabels[locale]}>
{languageIcons[locale]}
</span>{' '}
{languageLabels[locale]}
</Menu.Item>
))}
</Menu>
);
return (
<HeaderDropdown overlay={langMenu} placement="bottomRight">
<span className={classNames(styles.dropDown, className)}>
<Icon type="global" title={formatMessage({ id: 'navBar.lang' })} />
</span>
</HeaderDropdown>
);
};
export default SelectLang;
// eslint-disable-next-line eslint-comments/disable-enable-pair
/* eslint-disable import/no-extraneous-dependencies */
import client from 'webpack-theme-color-replacer/client';
import generate from '@ant-design/colors/lib/generate';
export default {
getAntdSerials(color: string): string[] {
const lightCount = 9;
const divide = 10;
// 淡化(即less的tint)
let lightens = new Array(lightCount).fill(0);
lightens = lightens.map((_, i) => client.varyColor.lighten(color, i / divide));
const colorPalettes = generate(color);
const rgb = client.varyColor.toNum3(color.replace('#', '')).join(',');
return lightens.concat(colorPalettes).concat(rgb);
},
changeColor(color?: string): Promise<void> {
if (!color) {
return Promise.resolve();
}
const options = {
// new colors array, one-to-one corresponde with `matchColors`
newColors: this.getAntdSerials(color),
changeUrl(cssUrl: string): string {
// while router is not `hash` mode, it needs absolute path
return `/${cssUrl}`;
},
};
return client.changer.changeColor(options, Promise);
},
};
const { uniq } = require('lodash');
const RouterConfig = require('../../config/config').default.routes;
const BASE_URL = `http://localhost:${process.env.PORT || 8000}`;
function formatter(routes, parentPath = '') {
const fixedParentPath = parentPath.replace(/\/{1,}/g, '/');
let result = [];
routes.forEach(item => {
if (item.path) {
result.push(`${fixedParentPath}/${item.path}`.replace(/\/{1,}/g, '/'));
}
if (item.routes) {
result = result.concat(
formatter(item.routes, item.path ? `${fixedParentPath}/${item.path}` : parentPath),
);
}
});
return uniq(result.filter(item => !!item));
}
describe('Ant Design Pro E2E test', () => {
const testPage = path => async () => {
await page.goto(`${BASE_URL}${path}`);
await page.waitForSelector('footer', {
timeout: 2000,
});
const haveFooter = await page.evaluate(
() => document.getElementsByTagName('footer').length > 0,
);
expect(haveFooter).toBeTruthy();
};
const routers = formatter(RouterConfig);
console.log('routers', routers);
routers.forEach(route => {
it(`test pages ${route}`, testPage(route));
});
});
const BASE_URL = `http://localhost:${process.env.PORT || 8000}`;
describe('Homepage', () => {
it('topmenu should have footer', async () => {
const params = '/form/basic-form?navTheme=light&layout=topmenu';
await page.goto(`${BASE_URL}${params}`);
await page.waitForSelector('footer', {
timeout: 2000,
});
const haveFooter = await page.evaluate(
() => document.getElementsByTagName('footer').length > 0,
);
expect(haveFooter).toBeTruthy();
});
});
@import '~antd/es/style/themes/default.less';
html,
body,
#root {
height: 100%;
}
.colorWeak {
filter: invert(80%);
}
.ant-layout {
min-height: 100vh;
}
canvas {
display: block;
}
body {
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
ul,
ol {
list-style: none;
}
@media (max-width: @screen-xs) {
.ant-table {
width: 100%;
overflow-x: auto;
&-thead > tr,
&-tbody > tr {
> th,
> td {
white-space: pre;
> span {
display: block;
}
}
}
}
}
import { Button, message, notification } from 'antd';
import React from 'react';
import { formatMessage } from 'umi-plugin-react/locale';
import defaultSettings from '../config/defaultSettings';
const { pwa } = defaultSettings;
// if pwa is true
if (pwa) {
// Notify user if offline now
window.addEventListener('sw.offline', () => {
message.warning(formatMessage({ id: 'app.pwa.offline' }));
});
// Pop up a prompt on the page asking the user if they want to use the latest version
window.addEventListener('sw.updated', (event: Event) => {
const e = event as CustomEvent;
const reloadSW = async () => {
// Check if there is sw whose state is waiting in ServiceWorkerRegistration
// https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration
const worker = e.detail && e.detail.waiting;
if (!worker) {
return true;
}
// Send skip-waiting event to waiting SW with MessageChannel
await new Promise((resolve, reject) => {
const channel = new MessageChannel();
channel.port1.onmessage = msgEvent => {
if (msgEvent.data.error) {
reject(msgEvent.data.error);
} else {
resolve(msgEvent.data);
}
};
worker.postMessage({ type: 'skip-waiting' }, [channel.port2]);
});
// Refresh current page to use the updated HTML and other assets after SW has skiped waiting
window.location.reload(true);
return true;
};
const key = `open${Date.now()}`;
const btn = (
<Button
type="primary"
onClick={() => {
notification.close(key);
reloadSW();
}}
>
{formatMessage({ id: 'app.pwa.serviceworker.updated.ok' })}
</Button>
);
notification.open({
message: formatMessage({ id: 'app.pwa.serviceworker.updated' }),
description: formatMessage({ id: 'app.pwa.serviceworker.updated.hint' }),
btn,
key,
onClose: async () => {},
});
});
} else if ('serviceWorker' in navigator) {
// unregister service worker
const { serviceWorker } = navigator;
if (serviceWorker.getRegistrations) {
serviceWorker.getRegistrations().then(sws => {
sws.forEach(sw => {
sw.unregister();
});
});
}
serviceWorker.getRegistration().then(sw => {
if (sw) sw.unregister();
});
// remove all caches
if (window.caches && window.caches.keys) {
caches.keys().then(keys => {
keys.forEach(key => {
caches.delete(key);
});
});
}
}
/**
* Ant Design Pro v4 use `@ant-design/pro-layout` to handle Layout.
* You can view component api by:
* https://github.com/ant-design/ant-design-pro-layout
*/
import ProLayout, {
MenuDataItem,
BasicLayoutProps as ProLayoutProps,
Settings,
DefaultFooter,
SettingDrawer
} from "@ant-design/pro-layout";
import React, { useEffect } from "react";
import Link from "umi/link";
import { Dispatch } from "redux";
import { connect } from "dva";
import { Icon } from "antd";
import { formatMessage } from "umi-plugin-react/locale";
import Authorized from "@/utils/Authorized";
import RightContent from "@/components/GlobalHeader/RightContent";
import { ConnectState } from "@/models/connect";
import { isAntDesignPro } from "@/utils/utils";
import logo from "../assets/logo.svg";
export interface BasicLayoutProps extends ProLayoutProps {
breadcrumbNameMap: {
[path: string]: MenuDataItem;
};
settings: Settings;
dispatch: Dispatch;
}
export type BasicLayoutContext = { [K in "location"]: BasicLayoutProps[K] } & {
breadcrumbNameMap: {
[path: string]: MenuDataItem;
};
};
/**
* use Authorized check all menu item
*/
const menuDataRender = (menuList: MenuDataItem[]): MenuDataItem[] =>
menuList.map(item => {
const localItem = {
...item,
children: item.children ? menuDataRender(item.children) : []
};
return Authorized.check(item.authority, localItem, null) as MenuDataItem;
});
const defaultFooterDom = (
<DefaultFooter
copyright="2019 蚂蚁金服体验技术部出品"
links={[
{
key: "Ant Design Pro",
title: "Ant Design Pro",
href: "https://pro.ant.design",
blankTarget: true
},
{
key: "github",
title: <Icon type="github" />,
href: "https://github.com/ant-design/ant-design-pro",
blankTarget: true
},
{
key: "Ant Design",
title: "Ant Design",
href: "https://ant.design",
blankTarget: true
}
]}
/>
);
const footerRender: BasicLayoutProps["footerRender"] = () => {
if (!isAntDesignPro()) {
return defaultFooterDom;
}
return (
<>
{defaultFooterDom}
<div
style={{
padding: "0px 24px 24px",
textAlign: "center"
}}
>
<a
href="https://www.netlify.com"
target="_blank"
rel="noopener noreferrer"
>
<img
src="https://www.netlify.com/img/global/badges/netlify-color-bg.svg"
width="82px"
alt="netlify logo"
/>
</a>
</div>
</>
);
};
const BasicLayout: React.FC<BasicLayoutProps> = props => {
const { dispatch, children, settings } = props;
const [settingss, setSettingss] = useState({});
/**
* constructor
*/
useEffect(() => {
if (dispatch) {
dispatch({
type: "user/fetchCurrent"
});
dispatch({
type: "settings/getSetting"
});
}
}, []);
/**
* init variables
*/
const handleMenuCollapse = (payload: boolean): void => {
if (dispatch) {
dispatch({
type: "global/changeLayoutCollapsed",
payload
});
}
};
return (
<>
<ProLayout
logo={logo}
onCollapse={handleMenuCollapse}
menuItemRender={(menuItemProps, defaultDom) => {
if (menuItemProps.isUrl) {
return defaultDom;
}
return <Link to={menuItemProps.path}>{defaultDom}</Link>;
}}
breadcrumbRender={(routers = []) => [
{
path: "/",
breadcrumbName: formatMessage({
id: "menu.home",
defaultMessage: "Home"
})
},
...routers
]}
itemRender={(route, params, routes, paths) => {
const first = routes.indexOf(route) === 0;
return first ? (
<Link to={paths.join("/")}>{route.breadcrumbName}</Link>
) : (
<span>{route.breadcrumbName}</span>
);
}}
footerRender={footerRender}
menuDataRender={menuDataRender}
formatMessage={formatMessage}
rightContentRender={rightProps => <RightContent {...rightProps} />}
{...props}
{...settings}
>
{children}
</ProLayout>
<SettingDrawer
settings={settings}
onSettingChange={config => setSettingss(config)}
/>
</>
);
};
export default connect(({ global, settings }: ConnectState) => ({
collapsed: global.collapsed,
settings
}))(BasicLayout);
import React from 'react';
const Layout: React.FC = ({ children }) => <div>{children}</div>;
export default Layout;
import React from 'react';
import { connect } from 'dva';
import { Redirect } from 'umi';
import { stringify } from 'querystring';
import { ConnectState, ConnectProps } from '@/models/connect';
import { CurrentUser } from '@/models/user';
import PageLoading from '@/components/PageLoading';
interface SecurityLayoutProps extends ConnectProps {
loading: boolean;
currentUser: CurrentUser;
}
interface SecurityLayoutState {
isReady: boolean;
}
class SecurityLayout extends React.Component<SecurityLayoutProps, SecurityLayoutState> {
state: SecurityLayoutState = {
isReady: false,
};
componentDidMount() {
this.setState({
isReady: true,
});
const { dispatch } = this.props;
if (dispatch) {
dispatch({
type: 'user/fetchCurrent',
});
}
}
render() {
const { isReady } = this.state;
const { children, loading, currentUser } = this.props;
// You can replace it to your authentication rule (such as check token exists)
// 你可以把它替换成你自己的登录认证规则(比如判断 token 是否存在)
const isLogin = currentUser && currentUser.userid;
const queryString = stringify({
redirect: window.location.href,
});
if ((!isLogin && loading) || !isReady) {
return <PageLoading />;
}
if (!isLogin) {
return <Redirect to={`/user/login?${queryString}`}></Redirect>;
}
return children;
}
}
export default connect(({ user, loading }: ConnectState) => ({
currentUser: user.currentUser,
loading: loading.models.user,
}))(SecurityLayout);
@import '~antd/es/style/themes/default.less';
.container {
display: flex;
flex-direction: column;
height: 100vh;
overflow: auto;
background: @layout-body-background;
}
.lang {
width: 100%;
height: 40px;
line-height: 44px;
text-align: right;
:global(.ant-dropdown-trigger) {
margin-right: 24px;
}
}
.content {
flex: 1;
padding: 32px 0;
}
@media (min-width: @screen-md-min) {
.container {
background-image: url('https://gw.alipayobjects.com/zos/rmsportal/TVYTbAXWheQpRcWDaDMu.svg');
background-repeat: no-repeat;
background-position: center 110px;
background-size: 100%;
}
.content {
padding: 32px 0 24px;
}
}
.top {
text-align: center;
}
.header {
height: 44px;
line-height: 44px;
a {
text-decoration: none;
}
}
.logo {
height: 44px;
margin-right: 16px;
vertical-align: top;
}
.title {
position: relative;
top: 2px;
color: @heading-color;
font-weight: 600;
font-size: 33px;
font-family: Avenir, 'Helvetica Neue', Arial, Helvetica, sans-serif;
}
.desc {
margin-top: 12px;
margin-bottom: 40px;
color: @text-color-secondary;
font-size: @font-size-base;
}
import { DefaultFooter, MenuDataItem, getMenuData, getPageTitle } from '@ant-design/pro-layout';
import DocumentTitle from 'react-document-title';
import Link from 'umi/link';
import React from 'react';
import { connect } from 'dva';
import { formatMessage } from 'umi-plugin-react/locale';
import SelectLang from '@/components/SelectLang';
import { ConnectProps, ConnectState } from '@/models/connect';
import logo from '../assets/logo.svg';
import styles from './UserLayout.less';
export interface UserLayoutProps extends ConnectProps {
breadcrumbNameMap: { [path: string]: MenuDataItem };
}
const UserLayout: React.SFC<UserLayoutProps> = props => {
const {
route = {
routes: [],
},
} = props;
const { routes = [] } = route;
const {
children,
location = {
pathname: '',
},
} = props;
const { breadcrumb } = getMenuData(routes);
return (
<DocumentTitle
title={getPageTitle({
pathname: location.pathname,
breadcrumb,
formatMessage,
...props,
})}
>
<div className={styles.container}>
<div className={styles.lang}>
<SelectLang />
</div>
<div className={styles.content}>
<div className={styles.top}>
<div className={styles.header}>
<Link to="/">
<img alt="logo" className={styles.logo} src={logo} />
<span className={styles.title}>Ant Design</span>
</Link>
</div>
<div className={styles.desc}>Ant Design 是西湖区最具影响力的 Web 设计规范</div>
</div>
{children}
</div>
<DefaultFooter />
</div>
</DocumentTitle>
);
};
export default connect(({ settings }: ConnectState) => ({
...settings,
}))(UserLayout);
import component from './en-US/component';
import globalHeader from './en-US/globalHeader';
import menu from './en-US/menu';
import pwa from './en-US/pwa';
import settingDrawer from './en-US/settingDrawer';
import settings from './en-US/settings';
export default {
'navBar.lang': 'Languages',
'layout.user.link.help': 'Help',
'layout.user.link.privacy': 'Privacy',
'layout.user.link.terms': 'Terms',
'app.preview.down.block': 'Download this page to your local project',
'app.welcome.link.fetch-blocks': 'Get all block',
'app.welcome.link.block-list': 'Quickly build standard, pages based on `block` development',
...globalHeader,
...menu,
...settingDrawer,
...settings,
...pwa,
...component,
};
export default {
'component.tagSelect.expand': 'Expand',
'component.tagSelect.collapse': 'Collapse',
'component.tagSelect.all': 'All',
};
export default {
'component.globalHeader.search': 'Search',
'component.globalHeader.search.example1': 'Search example 1',
'component.globalHeader.search.example2': 'Search example 2',
'component.globalHeader.search.example3': 'Search example 3',
'component.globalHeader.help': 'Help',
'component.globalHeader.notification': 'Notification',
'component.globalHeader.notification.empty': 'You have viewed all notifications.',
'component.globalHeader.message': 'Message',
'component.globalHeader.message.empty': 'You have viewed all messsages.',
'component.globalHeader.event': 'Event',
'component.globalHeader.event.empty': 'You have viewed all events.',
'component.noticeIcon.clear': 'Clear',
'component.noticeIcon.cleared': 'Cleared',
'component.noticeIcon.empty': 'No notifications',
'component.noticeIcon.view-more': 'View more',
};
export default {
'menu.welcome': 'Welcome',
'menu.more-blocks': 'More Blocks',
'menu.home': 'Home',
'menu.login': 'Login',
'menu.register': 'Register',
'menu.register.result': 'Register Result',
'menu.dashboard': 'Dashboard',
'menu.dashboard.analysis': 'Analysis',
'menu.dashboard.monitor': 'Monitor',
'menu.dashboard.workplace': 'Workplace',
'menu.exception.403': '403',
'menu.exception.404': '404',
'menu.exception.500': '500',
'menu.form': 'Form',
'menu.form.basic-form': 'Basic Form',
'menu.form.step-form': 'Step Form',
'menu.form.step-form.info': 'Step Form(write transfer information)',
'menu.form.step-form.confirm': 'Step Form(confirm transfer information)',
'menu.form.step-form.result': 'Step Form(finished)',
'menu.form.advanced-form': 'Advanced Form',
'menu.list': 'List',
'menu.list.table-list': 'Search Table',
'menu.list.basic-list': 'Basic List',
'menu.list.card-list': 'Card List',
'menu.list.search-list': 'Search List',
'menu.list.search-list.articles': 'Search List(articles)',
'menu.list.search-list.projects': 'Search List(projects)',
'menu.list.search-list.applications': 'Search List(applications)',
'menu.profile': 'Profile',
'menu.profile.basic': 'Basic Profile',
'menu.profile.advanced': 'Advanced Profile',
'menu.result': 'Result',
'menu.result.success': 'Success',
'menu.result.fail': 'Fail',
'menu.exception': 'Exception',
'menu.exception.not-permission': '403',
'menu.exception.not-find': '404',
'menu.exception.server-error': '500',
'menu.exception.trigger': 'Trigger',
'menu.account': 'Account',
'menu.account.center': 'Account Center',
'menu.account.settings': 'Account Settings',
'menu.account.trigger': 'Trigger Error',
'menu.account.logout': 'Logout',
'menu.editor': 'Graphic Editor',
'menu.editor.flow': 'Flow Editor',
'menu.editor.mind': 'Mind Editor',
'menu.editor.koni': 'Koni Editor',
};
export default {
'app.pwa.offline': 'You are offline now',
'app.pwa.serviceworker.updated': 'New content is available',
'app.pwa.serviceworker.updated.hint': 'Please press the "Refresh" button to reload current page',
'app.pwa.serviceworker.updated.ok': 'Refresh',
};
export default {
'app.setting.pagestyle': 'Page style setting',
'app.setting.pagestyle.dark': 'Dark style',
'app.setting.pagestyle.light': 'Light style',
'app.setting.content-width': 'Content Width',
'app.setting.content-width.fixed': 'Fixed',
'app.setting.content-width.fluid': 'Fluid',
'app.setting.themecolor': 'Theme Color',
'app.setting.themecolor.dust': 'Dust Red',
'app.setting.themecolor.volcano': 'Volcano',
'app.setting.themecolor.sunset': 'Sunset Orange',
'app.setting.themecolor.cyan': 'Cyan',
'app.setting.themecolor.green': 'Polar Green',
'app.setting.themecolor.daybreak': 'Daybreak Blue (default)',
'app.setting.themecolor.geekblue': 'Geek Glue',
'app.setting.themecolor.purple': 'Golden Purple',
'app.setting.navigationmode': 'Navigation Mode',
'app.setting.sidemenu': 'Side Menu Layout',
'app.setting.topmenu': 'Top Menu Layout',
'app.setting.fixedheader': 'Fixed Header',
'app.setting.fixedsidebar': 'Fixed Sidebar',
'app.setting.fixedsidebar.hint': 'Works on Side Menu Layout',
'app.setting.hideheader': 'Hidden Header when scrolling',
'app.setting.hideheader.hint': 'Works when Hidden Header is enabled',
'app.setting.othersettings': 'Other Settings',
'app.setting.weakmode': 'Weak Mode',
'app.setting.copy': 'Copy Setting',
'app.setting.copyinfo': 'copy success,please replace defaultSettings in src/models/setting.js',
'app.setting.production.hint':
'Setting panel shows in development environment only, please manually modify',
};
export default {
'app.settings.menuMap.basic': 'Basic Settings',
'app.settings.menuMap.security': 'Security Settings',
'app.settings.menuMap.binding': 'Account Binding',
'app.settings.menuMap.notification': 'New Message Notification',
'app.settings.basic.avatar': 'Avatar',
'app.settings.basic.change-avatar': 'Change avatar',
'app.settings.basic.email': 'Email',
'app.settings.basic.email-message': 'Please input your email!',
'app.settings.basic.nickname': 'Nickname',
'app.settings.basic.nickname-message': 'Please input your Nickname!',
'app.settings.basic.profile': 'Personal profile',
'app.settings.basic.profile-message': 'Please input your personal profile!',
'app.settings.basic.profile-placeholder': 'Brief introduction to yourself',
'app.settings.basic.country': 'Country/Region',
'app.settings.basic.country-message': 'Please input your country!',
'app.settings.basic.geographic': 'Province or city',
'app.settings.basic.geographic-message': 'Please input your geographic info!',
'app.settings.basic.address': 'Street Address',
'app.settings.basic.address-message': 'Please input your address!',
'app.settings.basic.phone': 'Phone Number',
'app.settings.basic.phone-message': 'Please input your phone!',
'app.settings.basic.update': 'Update Information',
'app.settings.security.strong': 'Strong',
'app.settings.security.medium': 'Medium',
'app.settings.security.weak': 'Weak',
'app.settings.security.password': 'Account Password',
'app.settings.security.password-description': 'Current password strength',
'app.settings.security.phone': 'Security Phone',
'app.settings.security.phone-description': 'Bound phone',
'app.settings.security.question': 'Security Question',
'app.settings.security.question-description':
'The security question is not set, and the security policy can effectively protect the account security',
'app.settings.security.email': 'Backup Email',
'app.settings.security.email-description': 'Bound Email',
'app.settings.security.mfa': 'MFA Device',
'app.settings.security.mfa-description':
'Unbound MFA device, after binding, can be confirmed twice',
'app.settings.security.modify': 'Modify',
'app.settings.security.set': 'Set',
'app.settings.security.bind': 'Bind',
'app.settings.binding.taobao': 'Binding Taobao',
'app.settings.binding.taobao-description': 'Currently unbound Taobao account',
'app.settings.binding.alipay': 'Binding Alipay',
'app.settings.binding.alipay-description': 'Currently unbound Alipay account',
'app.settings.binding.dingding': 'Binding DingTalk',
'app.settings.binding.dingding-description': 'Currently unbound DingTalk account',
'app.settings.binding.bind': 'Bind',
'app.settings.notification.password': 'Account Password',
'app.settings.notification.password-description':
'Messages from other users will be notified in the form of a station letter',
'app.settings.notification.messages': 'System Messages',
'app.settings.notification.messages-description':
'System messages will be notified in the form of a station letter',
'app.settings.notification.todo': 'To-do Notification',
'app.settings.notification.todo-description':
'The to-do list will be notified in the form of a letter from the station',
'app.settings.open': 'Open',
'app.settings.close': 'Close',
};
import component from './pt-BR/component';
import globalHeader from './pt-BR/globalHeader';
import menu from './pt-BR/menu';
import pwa from './pt-BR/pwa';
import settingDrawer from './pt-BR/settingDrawer';
import settings from './pt-BR/settings';
export default {
'navBar.lang': 'Idiomas',
'layout.user.link.help': 'ajuda',
'layout.user.link.privacy': 'política de privacidade',
'layout.user.link.terms': 'termos de serviços',
'app.preview.down.block': 'Download this page to your local project',
...globalHeader,
...menu,
...settingDrawer,
...settings,
...pwa,
...component,
};
export default {
'component.tagSelect.expand': 'Expandir',
'component.tagSelect.collapse': 'Diminuir',
'component.tagSelect.all': 'Todas',
};
export default {
'component.globalHeader.search': 'Busca',
'component.globalHeader.search.example1': 'Exemplo de busca 1',
'component.globalHeader.search.example2': 'Exemplo de busca 2',
'component.globalHeader.search.example3': 'Exemplo de busca 3',
'component.globalHeader.help': 'Ajuda',
'component.globalHeader.notification': 'Notificação',
'component.globalHeader.notification.empty': 'Você visualizou todas as notificações.',
'component.globalHeader.message': 'Mensagem',
'component.globalHeader.message.empty': 'Você visualizou todas as mensagens.',
'component.globalHeader.event': 'Evento',
'component.globalHeader.event.empty': 'Você visualizou todos os eventos.',
'component.noticeIcon.clear': 'Limpar',
'component.noticeIcon.cleared': 'Limpo',
'component.noticeIcon.empty': 'Sem notificações',
'component.noticeIcon.loaded': 'Carregado',
'component.noticeIcon.view-more': 'Veja mais',
};
export default {
'menu.welcome': 'Welcome',
'menu.more-blocks': 'More Blocks',
'menu.home': 'Início',
'menu.login': 'Login',
'menu.register': 'Registro',
'menu.register.result': 'Resultado de registro',
'menu.dashboard': 'Dashboard',
'menu.dashboard.analysis': 'Análise',
'menu.dashboard.monitor': 'Monitor',
'menu.dashboard.workplace': 'Ambiente de Trabalho',
'menu.exception.403': '403',
'menu.exception.404': '404',
'menu.exception.500': '500',
'menu.form': 'Formulário',
'menu.form.basic-form': 'Formulário Básico',
'menu.form.step-form': 'Formulário Assistido',
'menu.form.step-form.info': 'Formulário Assistido(gravar informações de transferência)',
'menu.form.step-form.confirm': 'Formulário Assistido(confirmar informações de transferência)',
'menu.form.step-form.result': 'Formulário Assistido(finalizado)',
'menu.form.advanced-form': 'Formulário Avançado',
'menu.list': 'Lista',
'menu.list.table-list': 'Tabela de Busca',
'menu.list.basic-list': 'Lista Básica',
'menu.list.card-list': 'Lista de Card',
'menu.list.search-list': 'Lista de Busca',
'menu.list.search-list.articles': 'Lista de Busca(artigos)',
'menu.list.search-list.projects': 'Lista de Busca(projetos)',
'menu.list.search-list.applications': 'Lista de Busca(aplicações)',
'menu.profile': 'Perfil',
'menu.profile.basic': 'Perfil Básico',
'menu.profile.advanced': 'Perfil Avançado',
'menu.result': 'Resultado',
'menu.result.success': 'Sucesso',
'menu.result.fail': 'Falha',
'menu.exception': 'Exceção',
'menu.exception.not-permission': '403',
'menu.exception.not-find': '404',
'menu.exception.server-error': '500',
'menu.exception.trigger': 'Disparar',
'menu.account': 'Conta',
'menu.account.center': 'Central da Conta',
'menu.account.settings': 'Configurar Conta',
'menu.account.trigger': 'Disparar Erro',
'menu.account.logout': 'Sair',
'menu.editor': 'Graphic Editor',
'menu.editor.flow': 'Flow Editor',
'menu.editor.mind': 'Mind Editor',
'menu.editor.koni': 'Koni Editor',
};
export default {
'app.pwa.offline': 'Você está offline agora',
'app.pwa.serviceworker.updated': 'Novo conteúdo está disponível',
'app.pwa.serviceworker.updated.hint':
'Por favor, pressione o botão "Atualizar" para recarregar a página atual',
'app.pwa.serviceworker.updated.ok': 'Atualizar',
};
export default {
'app.setting.pagestyle': 'Configuração de estilo da página',
'app.setting.pagestyle.dark': 'Dark style',
'app.setting.pagestyle.light': 'Light style',
'app.setting.content-width': 'Largura do conteúdo',
'app.setting.content-width.fixed': 'Fixo',
'app.setting.content-width.fluid': 'Fluido',
'app.setting.themecolor': 'Cor do Tema',
'app.setting.themecolor.dust': 'Dust Red',
'app.setting.themecolor.volcano': 'Volcano',
'app.setting.themecolor.sunset': 'Sunset Orange',
'app.setting.themecolor.cyan': 'Cyan',
'app.setting.themecolor.green': 'Polar Green',
'app.setting.themecolor.daybreak': 'Daybreak Blue (default)',
'app.setting.themecolor.geekblue': 'Geek Glue',
'app.setting.themecolor.purple': 'Golden Purple',
'app.setting.navigationmode': 'Modo de Navegação',
'app.setting.sidemenu': 'Layout do Menu Lateral',
'app.setting.topmenu': 'Layout do Menu Superior',
'app.setting.fixedheader': 'Cabeçalho fixo',
'app.setting.fixedsidebar': 'Barra lateral fixa',
'app.setting.fixedsidebar.hint': 'Funciona no layout do menu lateral',
'app.setting.hideheader': 'Esconder o cabeçalho quando rolar',
'app.setting.hideheader.hint': 'Funciona quando o esconder cabeçalho está abilitado',
'app.setting.othersettings': 'Outras configurações',
'app.setting.weakmode': 'Weak Mode',
'app.setting.copy': 'Copiar Configuração',
'app.setting.copyinfo':
'copiado com sucesso,por favor trocar o defaultSettings em src/models/setting.js',
'app.setting.production.hint':
'O painel de configuração apenas é exibido no ambiente de desenvolvimento, por favor modifique manualmente o',
};
export default {
'app.settings.menuMap.basic': 'Configurações Básicas',
'app.settings.menuMap.security': 'Configurações de Segurança',
'app.settings.menuMap.binding': 'Vinculação de Conta',
'app.settings.menuMap.notification': 'Mensagens de Notificação',
'app.settings.basic.avatar': 'Avatar',
'app.settings.basic.change-avatar': 'Alterar avatar',
'app.settings.basic.email': 'Email',
'app.settings.basic.email-message': 'Por favor insira seu email!',
'app.settings.basic.nickname': 'Nome de usuário',
'app.settings.basic.nickname-message': 'Por favor insira seu nome de usuário!',
'app.settings.basic.profile': 'Perfil pessoal',
'app.settings.basic.profile-message': 'Por favor insira seu perfil pessoal!',
'app.settings.basic.profile-placeholder': 'Breve introdução sua',
'app.settings.basic.country': 'País/Região',
'app.settings.basic.country-message': 'Por favor insira país!',
'app.settings.basic.geographic': 'Província, estado ou cidade',
'app.settings.basic.geographic-message': 'Por favor insira suas informações geográficas!',
'app.settings.basic.address': 'Endereço',
'app.settings.basic.address-message': 'Por favor insira seu endereço!',
'app.settings.basic.phone': 'Número de telefone',
'app.settings.basic.phone-message': 'Por favor insira seu número de telefone!',
'app.settings.basic.update': 'Atualizar Informações',
'app.settings.security.strong': 'Forte',
'app.settings.security.medium': 'Média',
'app.settings.security.weak': 'Fraca',
'app.settings.security.password': 'Senha da Conta',
'app.settings.security.password-description': 'Força da senha',
'app.settings.security.phone': 'Telefone de Seguraça',
'app.settings.security.phone-description': 'Telefone vinculado',
'app.settings.security.question': 'Pergunta de Segurança',
'app.settings.security.question-description':
'A pergunta de segurança não está definida e a política de segurança pode proteger efetivamente a segurança da conta',
'app.settings.security.email': 'Email de Backup',
'app.settings.security.email-description': 'Email vinculado',
'app.settings.security.mfa': 'Dispositivo MFA',
'app.settings.security.mfa-description':
'O dispositivo MFA não vinculado, após a vinculação, pode ser confirmado duas vezes',
'app.settings.security.modify': 'Modificar',
'app.settings.security.set': 'Atribuir',
'app.settings.security.bind': 'Vincular',
'app.settings.binding.taobao': 'Vincular Taobao',
'app.settings.binding.taobao-description': 'Atualmente não vinculado à conta Taobao',
'app.settings.binding.alipay': 'Vincular Alipay',
'app.settings.binding.alipay-description': 'Atualmente não vinculado à conta Alipay',
'app.settings.binding.dingding': 'Vincular DingTalk',
'app.settings.binding.dingding-description': 'Atualmente não vinculado à conta DingTalk',
'app.settings.binding.bind': 'Vincular',
'app.settings.notification.password': 'Senha da Conta',
'app.settings.notification.password-description':
'Mensagens de outros usuários serão notificadas na forma de uma estação de letra',
'app.settings.notification.messages': 'Mensagens de Sistema',
'app.settings.notification.messages-description':
'Mensagens de sistema serão notificadas na forma de uma estação de letra',
'app.settings.notification.todo': 'Notificação de To-do',
'app.settings.notification.todo-description':
'A lista de to-do será notificada na forma de uma estação de letra',
'app.settings.open': 'Aberto',
'app.settings.close': 'Fechado',
};
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment