diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index e6c87e9a789df3daf425268c58e92c186767d2a0..0000000000000000000000000000000000000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,25 +0,0 @@ -version: 2 -jobs: - build: - docker: - - image: circleci/node:latest - steps: - - checkout - - run: npm install - - run: npm run lint - - run: npm run build - test: - docker: - - image: circleci/node:latest-browsers - steps: - - checkout - - run: npm install - - run: - command: npm run test:all - no_output_timeout: 30m -workflows: - version: 2 - build_and_test: - jobs: - - build - - test diff --git a/.eslintrc.js b/.eslintrc.js index 02f5cb1252fd2075644a8272aa21867ecf563ddd..10309cef189855ac5cc6c46feabf83e56731e2f6 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -24,7 +24,7 @@ module.exports = { 2, { optionalDependencies: true, - devDependencies: ['**/tests/**.js', '/mock/**.js', '**/**.test.js'], + devDependencies: ['**/tests/**.js', '/mock/**/**.js', '**/**.test.js'], }, ], 'jsx-a11y/no-noninteractive-element-interactions': 0, diff --git a/.prettierignore b/.prettierignore index 2098c78c895e444136787bb101b9e2af2e519cae..6ce5e0186c7069221cdc1a321f1683d9c38d7c97 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,7 +1,5 @@ **/*.md **/*.svg -**/*.ejs -**/*.html package.json .umi .umi-production diff --git a/.stylelintrc.json b/.stylelintrc.json index b533bdd6333631833c1beb472a44bab53e1a1565..215bf08119eadd5005ddbef70291a652520e697b 100644 --- a/.stylelintrc.json +++ b/.stylelintrc.json @@ -1,9 +1,13 @@ { - "extends": ["stylelint-config-standard", "stylelint-config-prettier"], + "extends": [ + "stylelint-config-standard", + "stylelint-config-css-modules", + "stylelint-config-rational-order", + "stylelint-config-prettier" + ], + "plugins": ["stylelint-order", "stylelint-declaration-block-no-ignored-properties"], "rules": { - "declaration-empty-line-before": null, "no-descending-specificity": null, - "selector-pseudo-class-no-unknown": null, - "selector-pseudo-element-colon-notation": null + "plugin/declaration-block-no-ignored-properties": true } } diff --git a/README.md b/README.md index 21268cc68e2c4695536357999c24702eabe92fc1..ce0725dfd5b671fde4dcc894108b4f8a997fe027 100644 --- a/README.md +++ b/README.md @@ -6,13 +6,12 @@ English | [简体中文](./README.zh-CN.md) | [Русский](./README.ru-RU.md An out-of-box UI solution for enterprise applications as a React boilerplate. -[![CircleCI Status](https://circleci.com/gh/ant-design/ant-design-pro.svg?style=svg)](https://circleci.com/gh/ant-design/ant-design-pro/) -[![Build status](https://ci.appveyor.com/api/projects/status/67fxu2by3ibvqtat/branch/master?svg=true)](https://ci.appveyor.com/project/afc163/ant-design-pro/branch/master) +[![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)](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)(🇨🇳) - +[![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) ![](https://user-images.githubusercontent.com/8186664/44953195-581e3d80-aec4-11e8-8dcb-54b9db38ec11.png) diff --git a/README.ru-RU.md b/README.ru-RU.md index c20880ee8104c76327f9aaff48f5ebb1fb224942..22d16c9ac83c9b8f56dbc9f409753ff589b7c00c 100644 --- a/README.ru-RU.md +++ b/README.ru-RU.md @@ -6,11 +6,12 @@ UI-решение "из коробки" для корпоративных приложений как React boilerplate -[![CircleCI Status](https://circleci.com/gh/ant-design/ant-design-pro.svg?style=svg)](https://circleci.com/gh/ant-design/ant-design-pro/) -[![Build status](https://ci.appveyor.com/api/projects/status/67fxu2by3ibvqtat/branch/master?svg=true)](https://ci.appveyor.com/project/afc163/ant-design-pro/branch/master) +[![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://badges.gitter.im/ant-design/ant-design-pro.svg)](https://gitter.im/ant-design/ant-design-pro?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) +[![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) ![](https://user-images.githubusercontent.com/8186664/44953195-581e3d80-aec4-11e8-8dcb-54b9db38ec11.png) diff --git a/README.zh-CN.md b/README.zh-CN.md index e1682437558d7af9a73d8fd8ce4de4eec4bce434..6b150506179b433d3dbf5c4ad5ced0c00c86dcb9 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -6,11 +6,11 @@ 开箱即用的中台前端/设计解决方案。 -[![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) +[![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://badges.gitter.im/ant-design/ant-design-pro.svg)](https://gitter.im/ant-design/ant-design-pro?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) +[![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) ![](https://user-images.githubusercontent.com/8186664/44953195-581e3d80-aec4-11e8-8dcb-54b9db38ec11.png) @@ -84,8 +84,8 @@ $ npm start # 访问 http://localhost:8000 ```bash # preview -$ docker pull chenshuai2144/ant-design-pro -$ docker run -p 80:80 chenshuai2144/ant-design-pro +$ docker pull antdesign/ant-design-pro +$ docker run -p 80:80 antdesign/ant-design-pro # open http://localhost # dev diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index f2ffbbd45be5d8715f1d7d67d1100e8702557d93..0000000000000000000000000000000000000000 --- a/appveyor.yml +++ /dev/null @@ -1,26 +0,0 @@ -# Test against the latest version of this Node.js version -environment: - nodejs_version: '10' - -# this is how to allow failing jobs in the matrix -matrix: - fast_finish: true # set this flag to immediately finish build once one of the jobs fails. - -# Install scripts. (runs after repo cloning) -install: - # Get the latest stable version of Node.js or io.js - - ps: Install-Product node $env:nodejs_version - # install modules - - npm install - # Output useful info for debugging. - - node --version - - npm --version - -# Post-install test scripts. -test_script: - - npm run lint - - npm run test:all - - npm run build - -# Don't actually build. -build: off diff --git a/azure-pipelines.yml b/azure-pipelines.yml new file mode 100644 index 0000000000000000000000000000000000000000..9c4c97e1ad91a23e84b499ffdae0eac65a9cb579 --- /dev/null +++ b/azure-pipelines.yml @@ -0,0 +1,74 @@ +# 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 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 diff --git a/config/config.js b/config/config.js index fafb1484874e3e306cc23e6988fab48c75f03401..a86d1efd421deec9179335ae8e20760aac646403 100644 --- a/config/config.js +++ b/config/config.js @@ -4,6 +4,9 @@ import webpackPlugin from './plugin.config'; import defaultSettings from '../src/defaultSettings'; import slash from 'slash2'; +const { pwa, primaryColor } = defaultSettings; +const { NODE_ENV, APP_TYPE, TEST } = process.env; + const plugins = [ [ 'umi-plugin-react', @@ -20,6 +23,7 @@ const plugins = [ dynamicImport: { loadingComponent: './components/PageLoading/index', webpackChunkName: true, + level: 3, }, pwa: { workboxPluginMode: 'InjectManifest', @@ -51,7 +55,7 @@ const plugins = [ // 针对 preview.pro.ant.design 的 GA 统计代码 // 业务上不需要这个 -if (process.env.APP_TYPE === 'site') { +if (APP_TYPE === 'site') { plugins.push([ 'umi-plugin-ga', { @@ -64,7 +68,7 @@ export default { // add for transfer to umi plugins, define: { - APP_TYPE: process.env.APP_TYPE || '', + APP_TYPE: APP_TYPE || '', }, treeShaking: true, targets: { @@ -96,10 +100,11 @@ export default { // Theme for antd // https://ant.design/docs/react/customize-theme-cn theme: { - 'primary-color': defaultSettings.primaryColor, + 'primary-color': primaryColor, }, externals: { '@antv/data-set': 'DataSet', + bizcharts: 'BizCharts', }, // proxy: { // '/server/api/': { diff --git a/functions/package.json b/functions/package.json index dd7281977e6816559ab0d5142b98a57358248d96..fe77db2ab178ceec526d78d077834a401b7970a0 100644 --- a/functions/package.json +++ b/functions/package.json @@ -17,7 +17,7 @@ "firebase-functions": "^2.1.0", "mockjs": "^1.0.1-beta3", "moment": "^2.22.2", - "path-to-regexp": "^2.2.1" + "path-to-regexp": "^3.0.0" }, "private": true } diff --git a/jest-puppeteer.config.js b/jest-puppeteer.config.js index d720fc2bf05ea1918ce0708be1ce18ebf4be5ff4..cded345494729be647ba25d868f38e33ad5eaa01 100644 --- a/jest-puppeteer.config.js +++ b/jest-puppeteer.config.js @@ -1,15 +1,6 @@ // ps https://github.com/GoogleChrome/puppeteer/issues/3120 module.exports = { launch: { - headless: true, - args: [ - '--disable-gpu', - '--disable-dev-shm-usage', - '--disable-setuid-sandbox', - '--no-first-run', - '--no-sandbox', - '--no-zygote', - '--single-process', - ], + args: ['--disable-gpu', '--disable-dev-shm-usage', '--no-first-run', '--no-zygote'], }, }; diff --git a/mock/notices.js b/mock/notices.js index e07565dfe603c73b348c908a201d20422da3bf52..505088e0da17ba556961e2d1f3ed1159d561cae2 100644 --- a/mock/notices.js +++ b/mock/notices.js @@ -1,114 +1,101 @@ -const fakeNotices = [ - { - 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', - }, -]; - -const getNotices = (req, res) => { - if (req.query && req.query.type) { - const startFrom = parseInt(req.query.lastItemId, 10) + 1; - const result = fakeNotices - .filter(({ type }) => type === req.query.type) - .map((notice, index) => ({ - ...notice, - id: `0000000${startFrom + index}`, - })); - return res.json(startFrom > 24 ? result.concat(null) : result); - } - return res.json(fakeNotices); -}; +const getNotices = (req, res) => + res.json([ + { + id: '000000001', + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png', + title: '你收到了 14 份新周报', + datetime: '2017-08-09', + type: 'notification', + }, + { + id: '000000002', + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/OKJXDXrmkNshAMvwtvhu.png', + title: '你推荐的 曲妮妮 已通过第三轮面试', + datetime: '2017-08-08', + type: 'notification', + }, + { + id: '000000003', + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/kISTdvpyTAhtGxpovNWd.png', + title: '这种模板可以区分多种通知类型', + datetime: '2017-08-07', + read: true, + type: 'notification', + }, + { + id: '000000004', + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png', + title: '左侧图标用于区分不同的类型', + datetime: '2017-08-07', + type: 'notification', + }, + { + id: '000000005', + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png', + title: '内容不要超过两行字,超出时自动截断', + datetime: '2017-08-07', + type: 'notification', + }, + { + id: '000000006', + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg', + title: '曲丽丽 评论了你', + description: '描述信息描述信息描述信息', + datetime: '2017-08-07', + type: 'message', + 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, diff --git a/mock/user.js b/mock/user.js index dd3f240282f8cb93e2ae3da04960124c6e81182e..2fb6c60a1e8d2c95a20ab9d28bf48e694fe49630 100644 --- a/mock/user.js +++ b/mock/user.js @@ -3,7 +3,7 @@ export default { // 支持值为 Object 和 Array 'GET /api/currentUser': { name: 'Serati Ma', - avatar: 'https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png', + avatar: 'https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png', userid: '00000001', email: 'antdesign@alipay.com', signature: '海纳百川,有容乃大', diff --git a/package.json b/package.json index 850c474544ddafe1157ef7968be5c5956926f8df..551ef36fecb866990eb987b5138e5f4d59feb910 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ant-design-pro", - "version": "2.2.0", + "version": "2.2.1", "description": "An out-of-box UI solution for enterprise applications", "private": true, "scripts": { @@ -11,10 +11,10 @@ "dev:no-mock": "cross-env MOCK=none umi dev", "build": "umi build", "analyze": "cross-env ANALYZE=1 umi build", - "lint:style": "stylelint \"src/**/*.less\" --syntax less", + "lint:style": "stylelint 'src/**/*.less' --syntax less", "lint:prettier": "check-prettier lint", "lint": "eslint --ext .js src mock tests && npm run lint:style && npm run lint:prettier", - "lint:fix": "eslint --fix --ext .js src mock tests && npm run lint:style", + "lint:fix": "eslint --fix --ext .js src mock tests && stylelint --fix 'src/**/*.less' --syntax less", "lint-staged": "lint-staged", "lint-staged:js": "eslint --ext .js", "test": "umi test", @@ -50,46 +50,51 @@ "umi-request": "^1.0.0" }, "devDependencies": { - "@types/react": "^16.7.7", - "@types/react-dom": "^16.0.10", + "@types/react": "^16.8.1", + "@types/react-dom": "^16.0.11", "antd-pro-merge-less": "^1.0.0", - "antd-theme-webpack-plugin": "^1.1.8", + "antd-theme-webpack-plugin": "^1.2.0", "babel-eslint": "^10.0.1", + "chalk": "^2.4.2", "check-prettier": "^1.0.1", - "cross-env": "^5.1.1", + "cross-env": "^5.2.0", "cross-port-killer": "^1.0.1", - "enzyme": "3.7.0", - "eslint": "^5.4.0", - "eslint-config-airbnb": "^17.0.0", - "eslint-config-prettier": "^3.0.1", + "enzyme": "^3.9.0", + "eslint": "^5.13.0", + "eslint-config-airbnb": "^17.1.0", + "eslint-config-prettier": "^4.0.0", "eslint-plugin-babel": "^5.3.0", - "eslint-plugin-compat": "^2.6.2", - "eslint-plugin-import": "^2.14.0", - "eslint-plugin-jsx-a11y": "^6.1.2", - "eslint-plugin-markdown": "^1.0.0-beta.6", - "eslint-plugin-react": "^7.11.1", - "husky": "^1.2.0", - "jest-puppeteer": "^3.5.1", + "eslint-plugin-compat": "^2.6.3", + "eslint-plugin-import": "^2.16.0", + "eslint-plugin-jsx-a11y": "^6.2.0", + "eslint-plugin-markdown": "^1.0.0", + "eslint-plugin-react": "^7.12.4", + "gh-pages": "^2.0.1", + "husky": "^1.3.1", + "jest-puppeteer": "^4.0.0", "less": "^3.9.0", - "lint-staged": "^8.1.0", + "lint-staged": "^8.1.1", "merge-umi-mock-data": "^1.0.4", "mockjs": "^1.0.1-beta3", - "prettier": "1.15.2", - "pro-download": "^1.0.1", + "prettier": "^1.16.4", "slash2": "^2.0.0", - "stylelint": "^9.8.0", - "stylelint-config-prettier": "^4.0.0", - "stylelint-config-standard": "^18.0.0", - "tslint": "^5.10.0", - "tslint-config-prettier": "^1.10.0", + "stylelint": "^9.10.1", + "stylelint-config-css-modules": "^1.3.0", + "stylelint-config-prettier": "^5.0.0", + "stylelint-config-rational-order": "^0.0.4", + "stylelint-config-standard": "^18.2.0", + "stylelint-declaration-block-no-ignored-properties": "^1.1.0", + "stylelint-order": "^2.0.0", + "tslint": "^5.12.1", + "tslint-config-prettier": "^1.17.0", "tslint-react": "^3.6.0", - "umi": "^2.4.2", + "umi": "^2.4.4", "umi-plugin-ga": "^1.1.3", "umi-plugin-react": "^1.3.4", "umi-plugin-pro-block": "^1.2.0" }, "optionalDependencies": { - "puppeteer": "^1.10.0" + "puppeteer": "^1.12.1" }, "lint-staged": { "**/*.{js,ts,tsx,json,jsx,less}": [ diff --git a/src/app.js b/src/app.js index 7de5a69e1330e9ff0738ddd1ce378cc661e04619..0f35ff9af6376bcc3c3606f219ae6bcd1af6b769 100644 --- a/src/app.js +++ b/src/app.js @@ -8,11 +8,12 @@ export const dva = { }, }; -let authRoutes = null; +let authRoutes = {}; function ergodicRoutes(routes, authKey, authority) { routes.forEach(element => { if (element.path === authKey) { + if (!element.authority) element.authority = []; // eslint-disable-line Object.assign(element.authority, authority || []); } else if (element.routes) { ergodicRoutes(element.routes, authKey, authority); @@ -31,8 +32,13 @@ export function patchRoutes(routes) { export function render(oldRender) { fetch('/api/auth_routes') .then(res => res.json()) - .then(ret => { - authRoutes = ret; - oldRender(); - }); + .then( + ret => { + authRoutes = ret; + oldRender(); + }, + () => { + oldRender(); + } + ); } diff --git a/src/components/GlobalHeader/RightContent.js b/src/components/GlobalHeader/RightContent.js index 8463ec13c16766be8b4586f2955d474181fa9fa4..dc63084c05b8ff31ce147fd0686104dc705678f4 100644 --- a/src/components/GlobalHeader/RightContent.js +++ b/src/components/GlobalHeader/RightContent.js @@ -1,6 +1,6 @@ import React, { PureComponent } from 'react'; import { FormattedMessage, formatMessage } from 'umi/locale'; -import { Spin, Tag, Menu, Icon, Avatar, Tooltip } from 'antd'; +import { Spin, Tag, Menu, Icon, Avatar, Tooltip, message } from 'antd'; import moment from 'moment'; import groupBy from 'lodash/groupBy'; import { NoticeIcon } from 'ant-design-pro'; @@ -63,30 +63,13 @@ export default class GlobalHeaderRight extends PureComponent { }); }; - fetchMoreNotices = tabProps => { - const { list, name } = tabProps; - const { dispatch, notices = [] } = this.props; - const lastItemId = notices[notices.length - 1].id; - dispatch({ - type: 'global/fetchMoreNotices', - payload: { - lastItemId, - type: name, - offset: list.length, - }, - }); - }; - render() { const { currentUser, - fetchingMoreNotices, fetchingNotices, - loadedAllNotices, onNoticeVisibleChange, onMenuClick, onNoticeClear, - skeletonCount, theme, } = this.props; const menu = ( @@ -110,11 +93,6 @@ export default class GlobalHeaderRight extends PureComponent { ); - const loadMoreProps = { - skeletonCount, - loadedAll: loadedAllNotices, - loading: fetchingMoreNotices, - }; const noticeData = this.getNoticeData(); const unreadMsg = this.getUnreadData(noticeData); let className = styles.right; @@ -155,44 +133,43 @@ export default class GlobalHeaderRight extends PureComponent { console.log(item, tabProps); // eslint-disable-line this.changeReadState(item, tabProps); }} + loading={fetchingNotices} locale={{ emptyText: formatMessage({ id: 'component.noticeIcon.empty' }), clear: formatMessage({ id: 'component.noticeIcon.clear' }), - loadedAll: formatMessage({ id: 'component.noticeIcon.loaded' }), - loadMore: formatMessage({ id: 'component.noticeIcon.loading-more' }), + viewMore: formatMessage({ id: 'component.noticeIcon.view-more' }), + notification: formatMessage({ id: 'component.globalHeader.notification' }), + message: formatMessage({ id: 'component.globalHeader.message' }), + event: formatMessage({ id: 'component.globalHeader.event' }), }} onClear={onNoticeClear} - onLoadMore={this.fetchMoreNotices} onPopupVisibleChange={onNoticeVisibleChange} - loading={fetchingNotices} + onViewMore={() => message.info('Click on view more')} clearClose > {currentUser.name ? ( diff --git a/src/components/GlobalHeader/index.less b/src/components/GlobalHeader/index.less index 83a4151ed6164be0a1fb5f7ecdc741e6899c23ec..e66510b90f73693c5575d8bf518cc13be5b9d880 100644 --- a/src/components/GlobalHeader/index.less +++ b/src/components/GlobalHeader/index.less @@ -3,21 +3,21 @@ @pro-header-hover-bg: rgba(0, 0, 0, 0.025); .header { + position: relative; height: @layout-header-height; padding: 0; background: #fff; box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08); - position: relative; } .logo { + display: inline-block; height: @layout-header-height; + padding: 0 0 0 24px; + font-size: 20px; line-height: @layout-header-height; vertical-align: top; - display: inline-block; - padding: 0 0 0 24px; cursor: pointer; - font-size: 20px; img { display: inline-block; vertical-align: middle; @@ -34,11 +34,11 @@ } .trigger { - font-size: 20px; height: @layout-header-height; + padding: ~'calc((@{layout-header-height} - 20px) / 2)' 24px; + font-size: 20px; cursor: pointer; transition: all 0.3s, padding 0s; - padding: ~'calc((@{layout-header-height} - 20px) / 2)' 24px; &:hover { background: @pro-header-hover-bg; } @@ -49,14 +49,14 @@ height: 100%; overflow: hidden; .action { - cursor: pointer; - padding: 0 12px; display: inline-block; - transition: all 0.3s; height: 100%; + padding: 0 12px; + cursor: pointer; + transition: all 0.3s; > i { - vertical-align: middle; color: @text-color; + vertical-align: middle; } &:hover { background: @pro-header-hover-bg; @@ -76,8 +76,8 @@ margin: ~'calc((@{layout-header-height} - 24px) / 2)' 0; margin-right: 8px; color: @primary-color; - background: rgba(255, 255, 255, 0.85); vertical-align: top; + background: rgba(255, 255, 255, 0.85); } } } @@ -111,14 +111,14 @@ padding: 22px 12px; } .logo { - padding-left: 12px; - padding-right: 12px; position: relative; + padding-right: 12px; + padding-left: 12px; } .right { position: absolute; - right: 12px; top: 0; + right: 12px; background: #fff; .account { .avatar { diff --git a/src/components/HeaderDropdown/index.d.ts b/src/components/HeaderDropdown/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..e9dac7e532570e2f85a6a220d5d4ff9b97194927 --- /dev/null +++ b/src/components/HeaderDropdown/index.d.ts @@ -0,0 +1,2 @@ +import * as React from 'react'; +export default class HeaderDropdown extends React.Component {} diff --git a/src/components/HeaderDropdown/index.less b/src/components/HeaderDropdown/index.less index 6494de0a6a23f993875c16439e73ef8d3f121922..ef0c75913e821d8f9f54cba72a42b872bdd70c5c 100644 --- a/src/components/HeaderDropdown/index.less +++ b/src/components/HeaderDropdown/index.less @@ -2,8 +2,8 @@ .container > * { background-color: #fff; - box-shadow: @shadow-1-down; border-radius: 4px; + box-shadow: @shadow-1-down; } @media screen and (max-width: @screen-xs) { diff --git a/src/components/HeaderSearch/index.en-US.md b/src/components/HeaderSearch/index.en-US.md index 6f4d06b4e10f43f16e2b997629a8ecd79ca50a3c..9f2b5e8a46078d20bd1efea91efcca4d76f09e5e 100644 --- a/src/components/HeaderSearch/index.en-US.md +++ b/src/components/HeaderSearch/index.en-US.md @@ -1,8 +1,6 @@ --- -title: - en-US: HeaderSearch - zh-CN: HeaderSearch -subtitle: Top search box +title: HeaderSearch +subtitle: cols: 1 order: 8 --- @@ -21,4 +19,4 @@ onSelect | Called when a option is selected. param is option's value and option onPressEnter | Callback when pressing Enter | function(value) | - onVisibleChange | Show or hide the callback of the text box | function(value) |- defaultOpen | The input box is displayed for the first time. | boolean | false -open | The input box is displayed | booelan |false \ No newline at end of file +open | The input box is displayed | boolean |false \ No newline at end of file diff --git a/src/components/HeaderSearch/index.less b/src/components/HeaderSearch/index.less index e97386d82d6dc3fe3bfee8d30d0dd38b6174b984..88fadecdcc2cb137266c6a1e6ea388f07e597d84 100644 --- a/src/components/HeaderSearch/index.less +++ b/src/components/HeaderSearch/index.less @@ -2,21 +2,21 @@ .headerSearch { :global(.anticon-search) { - cursor: pointer; font-size: 16px; + cursor: pointer; } .input { - transition: width 0.3s, margin-left 0.3s; width: 0; background: transparent; border-radius: 0; + transition: width 0.3s, margin-left 0.3s; :global(.ant-select-selection) { background: transparent; } input { - border: 0; - padding-left: 0; padding-right: 0; + padding-left: 0; + border: 0; box-shadow: none !important; } &, diff --git a/src/components/HeaderSearch/index.zh-CN.md b/src/components/HeaderSearch/index.zh-CN.md index 9c108c2bc14594ea082fe93af37836e610862f63..83e74887f48f92ed380b274cec6c89d883962153 100644 --- a/src/components/HeaderSearch/index.zh-CN.md +++ b/src/components/HeaderSearch/index.zh-CN.md @@ -1,7 +1,5 @@ --- -title: - en-US: HeaderSearch - zh-CN: HeaderSearch +title: HeaderSearch subtitle: 顶部搜索框 cols: 1 order: 8 @@ -21,4 +19,4 @@ onSelect | 被选中时调用,参数为选中项的 value 值 | function(value onPressEnter | 按下回车时的回调 | function(value) | - onVisibleChange | 显示或隐藏文本框的回调 | function(value) |- defaultOpen | 输入框首次显示是否显示 | boolean | false -open | 控制输入框是否显示 | booelan |false \ No newline at end of file +open | 控制输入框是否显示 | boolean |false \ No newline at end of file diff --git a/src/components/IconFont/index.js b/src/components/IconFont/index.js new file mode 100644 index 0000000000000000000000000000000000000000..0b99dec3a7996eca278585cc961e0683b5d1cbcd --- /dev/null +++ b/src/components/IconFont/index.js @@ -0,0 +1,7 @@ +import { Icon } from 'antd'; +import { iconfontUrl as scriptUrl } from '../../defaultSettings'; + +// 使用: +// import IconFont from '@/components/IconFont'; +// +export default Icon.createFromIconfontCN({ scriptUrl }); diff --git a/src/components/SelectLang/index.less b/src/components/SelectLang/index.less index 971ef2aa98be7393a749381e64976df111ffd306..9f41ade9ac975d07cfd9a788ddbdd8f943c8e809 100644 --- a/src/components/SelectLang/index.less +++ b/src/components/SelectLang/index.less @@ -10,11 +10,11 @@ } .dropDown { - cursor: pointer; - vertical-align: top; line-height: @layout-header-height; + vertical-align: top; + cursor: pointer; > i { - font-size: 14px !important; + font-size: 16px !important; transform: none !important; svg { position: relative; diff --git a/src/components/SettingDrawer/ThemeColor.less b/src/components/SettingDrawer/ThemeColor.less index 4983eb9c67d207cfa4f9470a5a82068eb9c20c71..52e63beacaa7495c2aa7f22dd9012618d962baa7 100644 --- a/src/components/SettingDrawer/ThemeColor.less +++ b/src/components/SettingDrawer/ThemeColor.less @@ -1,21 +1,21 @@ .themeColor { - overflow: hidden; margin-top: 24px; + overflow: hidden; .title { - font-size: 14px; + margin-bottom: 12px; color: rgba(0, 0, 0, 0.65); + font-size: 14px; line-height: 22px; - margin-bottom: 12px; } .colorBlock { + float: left; width: 20px; height: 20px; - border-radius: 2px; - float: left; - cursor: pointer; margin-right: 8px; - text-align: center; color: #fff; font-weight: bold; + text-align: center; + border-radius: 2px; + cursor: pointer; } } diff --git a/src/components/SettingDrawer/index.js b/src/components/SettingDrawer/index.js index 4b279f593ec8cf032d00bb6783b01b001a4b016d..cdb28aa3c8f29fca78d2bf9dc296d711794ca3be 100644 --- a/src/components/SettingDrawer/index.js +++ b/src/components/SettingDrawer/index.js @@ -137,7 +137,7 @@ class SettingDrawer extends PureComponent { onClose={this.togglerContent} placement="right" handler={ -
+
} - onHandleClick={this.togglerContent} style={{ zIndex: 999, }} diff --git a/src/components/SettingDrawer/index.less b/src/components/SettingDrawer/index.less index af4109be3a3293a4cbdee09eda6a7355d20d62a2..4ee941c0e6caf5ce03f59852341041a44c5fc2be 100644 --- a/src/components/SettingDrawer/index.less +++ b/src/components/SettingDrawer/index.less @@ -1,16 +1,16 @@ @import '~antd/lib/style/themes/default.less'; .content { + position: relative; min-height: 100%; background: #fff; - position: relative; } .blockChecbox { display: flex; .item { - margin-right: 16px; position: relative; + margin-right: 16px; // box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.1); border-radius: @border-radius-base; cursor: pointer; @@ -23,52 +23,52 @@ top: 0; right: 0; width: 100%; + height: 100%; padding-top: 15px; padding-left: 24px; - height: 100%; color: @primary-color; - font-size: 14px; font-weight: bold; + font-size: 14px; } } .color_block { + display: inline-block; width: 38px; height: 22px; margin: 4px; - border-radius: 4px; - cursor: pointer; margin-right: 12px; - display: inline-block; vertical-align: middle; + border-radius: 4px; + cursor: pointer; } .title { - font-size: 14px; + margin-bottom: 12px; color: @heading-color; + font-size: 14px; line-height: 22px; - margin-bottom: 12px; } .handle { position: absolute; top: 240px; - background: @primary-color; - width: 48px; - height: 48px; right: 300px; + z-index: 0; display: flex; justify-content: center; align-items: center; - cursor: pointer; - pointer-events: auto; - z-index: 0; - text-align: center; + width: 48px; + height: 48px; font-size: 16px; + text-align: center; + background: @primary-color; border-radius: 4px 0 0 4px; + cursor: pointer; + pointer-events: auto; } .productionHint { - font-size: 12px; margin-top: 16px; + font-size: 12px; } diff --git a/src/components/SiderMenu/BaseMenu.js b/src/components/SiderMenu/BaseMenu.js index 2ad6113465994fe177114a41c3efd8dab45734ad..9ab66ec3c03111edb1920d7d61e14dfef92838a2 100644 --- a/src/components/SiderMenu/BaseMenu.js +++ b/src/components/SiderMenu/BaseMenu.js @@ -6,18 +6,23 @@ import { urlToList } from '../_utils/pathTools'; import { getMenuMatches } from './SiderMenuUtils'; import { isUrl } from '@/utils/utils'; import styles from './index.less'; +import IconFont from '@/components/IconFont'; const { SubMenu } = Menu; // Allow menu.js config icon as string or ReactNode // icon: 'setting', +// icon: 'icon-geren' #For Iconfont , // icon: 'http://demo.com/icon.png', // icon: , const getIcon = icon => { - if (typeof icon === 'string' && isUrl(icon)) { - return icon; - } if (typeof icon === 'string') { + if (isUrl(icon)) { + return icon} />; + } + if (icon.startsWith('icon-')) { + return ; + } return ; } return icon; @@ -28,13 +33,13 @@ export default class BaseMenu extends PureComponent { * 获得菜单子节点 * @memberof SiderMenu */ - getNavMenuItems = (menusData, parent) => { + getNavMenuItems = menusData => { if (!menusData) { return []; } return menusData .filter(item => item.name && !item.hideInMenu) - .map(item => this.getSubMenuOrItem(item, parent)) + .map(item => this.getSubMenuOrItem(item)) .filter(item => item); }; diff --git a/src/components/SiderMenu/SiderMenu.js b/src/components/SiderMenu/SiderMenu.js index e1b49d0037e20972f044e2691e00869fd01a0ed1..da9520faa8af841447db173ef98c2f9c544d2f4a 100644 --- a/src/components/SiderMenu/SiderMenu.js +++ b/src/components/SiderMenu/SiderMenu.js @@ -5,10 +5,13 @@ import Link from 'umi/link'; import styles from './index.less'; import PageLoading from '../PageLoading'; import { getDefaultCollapsedSubMenus } from './SiderMenuUtils'; +import { title } from '../../defaultSettings'; const BaseMenu = React.lazy(() => import('./BaseMenu')); const { Sider } = Layout; +let firstMount = true; + export default class SiderMenu extends PureComponent { constructor(props) { super(props); @@ -17,11 +20,16 @@ export default class SiderMenu extends PureComponent { }; } + componentDidMount() { + firstMount = false; + } + static getDerivedStateFromProps(props, state) { - const { pathname } = state; - if (props.location.pathname !== pathname) { + const { pathname, flatMenuKeysLen } = state; + if (props.location.pathname !== pathname || props.flatMenuKeys.length !== flatMenuKeysLen) { return { pathname: props.location.pathname, + flatMenuKeysLen: props.flatMenuKeys.length, openKeys: getDefaultCollapsedSubMenus(props), }; } @@ -46,12 +54,12 @@ export default class SiderMenu extends PureComponent { }; render() { - const { logo, collapsed, onCollapse, fixSiderbar, theme } = this.props; + const { logo, collapsed, onCollapse, fixSiderbar, theme, isMobile } = this.props; const { openKeys } = this.state; const defaultProps = collapsed ? {} : { openKeys }; const siderClassName = classNames(styles.sider, { - [styles.fixSiderbar]: fixSiderbar, + [styles.fixSiderBar]: fixSiderbar, [styles.light]: theme === 'light', }); return ( @@ -60,7 +68,11 @@ export default class SiderMenu extends PureComponent { collapsible collapsed={collapsed} breakpoint="lg" - onCollapse={onCollapse} + onCollapse={collapse => { + if (firstMount || !isMobile) { + onCollapse(collapse); + } + }} width={256} theme={theme} className={siderClassName} @@ -68,7 +80,7 @@ export default class SiderMenu extends PureComponent { }> diff --git a/src/components/SiderMenu/SiderMenuUtils.js b/src/components/SiderMenu/SiderMenuUtils.js index 6722ed7a8544c6e19e46f157cf7a14aca27feb3b..6e04ec134d76020bc902437632f136fa99a65098 100644 --- a/src/components/SiderMenu/SiderMenuUtils.js +++ b/src/components/SiderMenu/SiderMenuUtils.js @@ -35,5 +35,6 @@ export const getDefaultCollapsedSubMenus = props => { } = props; return urlToList(pathname) .map(item => getMenuMatches(flatMenuKeys, item)[0]) - .filter(item => item); + .filter(item => item) + .reduce((acc, curr) => [...acc, curr], ['/']); }; diff --git a/src/components/SiderMenu/index.less b/src/components/SiderMenu/index.less index 9ae37db198bbb263e206bddbaf5f9e189b07fd9f..88722c87e9b4ce466ade464dfe76aa2597cf8c18 100644 --- a/src/components/SiderMenu/index.less +++ b/src/components/SiderMenu/index.less @@ -3,46 +3,55 @@ @nav-header-height: @layout-header-height; .logo { - height: @nav-header-height; position: relative; - line-height: @nav-header-height; + height: @nav-header-height; padding-left: (@menu-collapsed-width - 32px) / 2; - transition: all 0.3s; - background: #002140; overflow: hidden; + line-height: @nav-header-height; + background: #002140; + transition: all 0.3s; img { display: inline-block; - vertical-align: middle; height: 32px; + vertical-align: middle; } h1 { - color: white; display: inline-block; - vertical-align: middle; - font-size: 20px; margin: 0 0 0 12px; - font-family: Avenir, 'Helvetica Neue', Arial, Helvetica, sans-serif; + color: white; font-weight: 600; + font-size: 20px; + font-family: Avenir, 'Helvetica Neue', Arial, Helvetica, sans-serif; + vertical-align: middle; } } - .sider { - min-height: 100vh; - box-shadow: 2px 0 6px rgba(0, 21, 41, 0.35); position: relative; z-index: 10; - &.fixSiderbar { + min-height: 100vh; + box-shadow: 2px 0 6px rgba(0, 21, 41, 0.35); + &.fixSiderBar { position: fixed; top: 0; left: 0; - :global(.ant-menu-root) { - overflow-y: auto; - height: ~'calc(100vh - @{nav-header-height})'; + box-shadow: 2px 0 8px 0 rgba(29, 35, 41, 0.05); + :global { + .ant-menu-root { + height: ~'calc(100vh - @{nav-header-height})'; + overflow-y: auto; + } + .ant-menu-inline { + border-right: 0; + .ant-menu-item, + .ant-menu-submenu-title { + width: 100%; + } + } } } &.light { - box-shadow: 2px 0 8px 0 rgba(29, 35, 41, 0.05); background-color: white; + box-shadow: 2px 0 8px 0 rgba(29, 35, 41, 0.05); .logo { background: white; box-shadow: 1px 1px 0 0 @border-color-split; @@ -58,7 +67,7 @@ .icon { width: 14px; - margin-right: 10px; + vertical-align: baseline; } :global { @@ -78,15 +87,15 @@ .sider-menu-item-img + span, & > .ant-menu-submenu > .ant-menu-submenu-title .sider-menu-item-img + span { - max-width: 0; display: inline-block; + max-width: 0; opacity: 0; } } .ant-menu-item .sider-menu-item-img + span, .ant-menu-submenu-title .sider-menu-item-img + span { - transition: opacity 0.3s @ease-in-out, width 0.3s @ease-in-out; opacity: 1; + transition: opacity 0.3s @ease-in-out, width 0.3s @ease-in-out; } .ant-drawer-left { .ant-drawer-body { diff --git a/src/components/TopNavHeader/index.js b/src/components/TopNavHeader/index.js index eca4dbe4b993b21de576c903c4fafe1fda856a9d..2d0e06561e0ef053594f157cd428b68874cc951d 100644 --- a/src/components/TopNavHeader/index.js +++ b/src/components/TopNavHeader/index.js @@ -4,6 +4,7 @@ import RightContent from '../GlobalHeader/RightContent'; import BaseMenu from '../SiderMenu/BaseMenu'; import { getFlatMenuKeys } from '../SiderMenu/SiderMenuUtils'; import styles from './index.less'; +import { title } from '../../defaultSettings'; export default class TopNavHeader extends PureComponent { state = { @@ -32,7 +33,7 @@ export default class TopNavHeader extends PureComponent {
{ - message.warning(formatMessage({ id: 'app.pwa.offline' })); -}); +window.React = React; -// Pop up a prompt on the page asking the user if they want to use the latest version -window.addEventListener('sw.updated', e => { - 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 Promise.resolve(); - } - // Send skip-waiting event to waiting SW with MessageChannel - await new Promise((resolve, reject) => { - const channel = new MessageChannel(); - channel.port1.onmessage = event => { - if (event.data.error) { - reject(event.data.error); - } else { - resolve(event.data); - } - }; - worker.postMessage({ type: 'skip-waiting' }, [channel.port2]); +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', e => { + 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 Promise.resolve(); + } + // Send skip-waiting event to waiting SW with MessageChannel + await new Promise((resolve, reject) => { + const channel = new MessageChannel(); + channel.port1.onmessage = event => { + if (event.data.error) { + reject(event.data.error); + } else { + resolve(event.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 = ( + + ); + notification.open({ + message: formatMessage({ id: 'app.pwa.serviceworker.updated' }), + description: formatMessage({ id: 'app.pwa.serviceworker.updated.hint' }), + btn, + key, + onClose: async () => {}, }); - // 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 = ( - - ); - notification.open({ - message: formatMessage({ id: 'app.pwa.serviceworker.updated' }), - description: formatMessage({ id: 'app.pwa.serviceworker.updated.hint' }), - btn, - key, - onClose: async () => {}, }); -}); +} diff --git a/src/global.less b/src/global.less index fccd7e835aa07b44811beb7ce65a16bee02dce15..1450ba46b17daf355a169563d975693f17170ff0 100644 --- a/src/global.less +++ b/src/global.less @@ -1,3 +1,5 @@ +@import '~antd/lib/style/themes/default.less'; + html, body, #root { @@ -31,3 +33,20 @@ 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; + } + } + } + } +} diff --git a/src/layouts/BasicLayout.js b/src/layouts/BasicLayout.js index cb97621204d2b3af43dbbed007ae41457f487b45..06cc41fce542df11b491a8f244f559a8936f7b1e 100644 --- a/src/layouts/BasicLayout.js +++ b/src/layouts/BasicLayout.js @@ -1,22 +1,17 @@ import React, { Suspense } from 'react'; import { Layout } from 'antd'; import DocumentTitle from 'react-document-title'; -import isEqual from 'lodash/isEqual'; -import memoizeOne from 'memoize-one'; import { connect } from 'dva'; import { ContainerQuery } from 'react-container-query'; import classNames from 'classnames'; -import pathToRegexp from 'path-to-regexp'; import Media from 'react-media'; -import { formatMessage } from 'umi/locale'; -import Authorized from '@/utils/Authorized'; import logo from '../assets/logo.svg'; import Footer from './Footer'; import Header from './Header'; import Context from './MenuContext'; import PageLoading from '@/components/PageLoading'; import SiderMenu from '@/components/SiderMenu'; -import { title } from '../defaultSettings'; +import getPageTitle from '@/utils/getPageTitle'; import styles from './BasicLayout.less'; // lazy load SettingDrawer @@ -49,13 +44,7 @@ const query = { }, }; -class BasicLayout extends React.PureComponent { - constructor(props) { - super(props); - this.getPageTitle = memoizeOne(this.getPageTitle); - this.matchParamsPath = memoizeOne(this.matchParamsPath, isEqual); - } - +class BasicLayout extends React.Component { componentDidMount() { const { dispatch, @@ -73,15 +62,6 @@ class BasicLayout extends React.PureComponent { }); } - componentDidUpdate(preProps) { - // After changing to phone mode, - // if collapsed is true, you need to click twice to display - const { collapsed, isMobile } = this.props; - if (isMobile && !preProps.isMobile && !collapsed) { - this.handleMenuCollapse(false); - } - } - getContext() { const { location, breadcrumbNameMap } = this.props; return { @@ -90,41 +70,6 @@ class BasicLayout extends React.PureComponent { }; } - matchParamsPath = (pathname, breadcrumbNameMap) => { - const pathKey = Object.keys(breadcrumbNameMap).find(key => pathToRegexp(key).test(pathname)); - return breadcrumbNameMap[pathKey]; - }; - - getRouterAuthority = (pathname, routeData) => { - let routeAuthority = ['noAuthority']; - const getAuthority = (key, routes) => { - routes.forEach(route => { - if (route.path && pathToRegexp(route.path).test(key)) { - routeAuthority = route.authority; - } else if (route.routes) { - routeAuthority = getAuthority(key, route.routes); - } - return route; - }); - return routeAuthority; - }; - return getAuthority(pathname, routeData); - }; - - getPageTitle = (pathname, breadcrumbNameMap) => { - const currRouterData = this.matchParamsPath(pathname, breadcrumbNameMap); - - if (!currRouterData) { - return title; - } - const pageName = formatMessage({ - id: currRouterData.locale || currRouterData.name, - defaultMessage: currRouterData.name, - }); - - return `${pageName} - ${title}`; - }; - getLayoutStyle = () => { const { fixSiderbar, isMobile, collapsed, layout } = this.props; if (fixSiderbar && layout !== 'topmenu' && !isMobile) { @@ -161,12 +106,10 @@ class BasicLayout extends React.PureComponent { isMobile, menuData, breadcrumbNameMap, - route: { routes }, fixedHeader, } = this.props; const isTop = PropsLayout === 'topmenu'; - const routerConfig = this.getRouterAuthority(pathname, routes); const contentStyle = !fixedHeader ? { paddingTop: 0 } : {}; const layout = ( @@ -194,9 +137,7 @@ class BasicLayout extends React.PureComponent { {...this.props} /> - Exception403

}> - {children} -
+ {children}