Browse Source

Merge branch 'refactor/pro-v3'

# Conflicts:
#	src/components/Menu/SideMenu.vue
#	src/components/Other/CarbonAds.vue
Sendya 4 years ago
parent
commit
3372d24d10
100 changed files with 1420 additions and 3559 deletions
  1. 14 45
      README.md
  2. 14 42
      README.zh-CN.md
  3. 3 0
      config/plugin.config.js
  4. 115 0
      config/themePluginConfig.js
  5. 8 10
      package.json
  6. 7 5
      public/index.html
  7. 0 1
      public/loading/loading.css
  8. 0 1
      public/loading/loading.html
  9. 0 2
      public/loading/option2/html_code_segment.html
  10. 0 1
      public/loading/option2/loading.css
  11. 0 0
      public/loading/option2/loading.svg
  12. 9 5
      src/App.vue
  13. 0 12
      src/api/index.js
  14. 27 15
      src/api/login.js
  15. 15 7
      src/api/manage.js
  16. 24 0
      src/components/AvatarList/Item.jsx
  17. 0 46
      src/components/AvatarList/Item.vue
  18. 72 0
      src/components/AvatarList/List.jsx
  19. 0 99
      src/components/AvatarList/List.vue
  20. 6 1
      src/components/AvatarList/index.js
  21. 1 1
      src/components/AvatarList/index.md
  22. 0 102
      src/components/CountDown/CountDown.vue
  23. 0 3
      src/components/CountDown/index.js
  24. 0 34
      src/components/CountDown/index.md
  25. 0 153
      src/components/DescriptionList/DescriptionList.vue
  26. 0 2
      src/components/DescriptionList/index.js
  27. 1 0
      src/components/Editor/QuillEditor.vue
  28. 0 130
      src/components/Exception/ExceptionPage.vue
  29. 0 2
      src/components/Exception/index.js
  30. 0 19
      src/components/Exception/type.js
  31. 18 1
      src/components/FooterToolbar/FooterToolBar.vue
  32. 0 59
      src/components/GlobalFooter/GlobalFooter.vue
  33. 0 2
      src/components/GlobalFooter/index.js
  34. 23 0
      src/components/GlobalFooter/index.vue
  35. 80 0
      src/components/GlobalHeader/AvatarDropdown.vue
  36. 0 125
      src/components/GlobalHeader/GlobalHeader.vue
  37. 58 0
      src/components/GlobalHeader/RightContent.vue
  38. 0 2
      src/components/GlobalHeader/index.js
  39. 0 64
      src/components/Menu/SideMenu.vue
  40. 0 2
      src/components/Menu/index.js
  41. 0 177
      src/components/Menu/menu.js
  42. 0 156
      src/components/Menu/menu.render.js
  43. 1 1
      src/components/Other/CarbonAds.vue
  44. 0 202
      src/components/PageHeader/PageHeader.vue
  45. 0 2
      src/components/PageHeader/index.js
  46. 0 109
      src/components/Result/Result.vue
  47. 0 2
      src/components/Result/index.js
  48. 58 0
      src/components/SelectLang/index.jsx
  49. 31 0
      src/components/SelectLang/index.less
  50. 2 11
      src/components/SettingDrawer/SettingDrawer.vue
  51. 2 62
      src/components/SettingDrawer/settingConfig.js
  52. 4 4
      src/components/Table/index.js
  53. 0 515
      src/components/global.less
  54. 0 10
      src/components/index.js
  55. 0 45
      src/components/tools/Breadcrumb.vue
  56. 0 5
      src/components/tools/DetailList.vue
  57. 0 67
      src/components/tools/HeadInfo.vue
  58. 0 46
      src/components/tools/LangSelect.vue
  59. 0 31
      src/components/tools/Logo.vue
  60. 0 82
      src/components/tools/UserMenu.vue
  61. 0 0
      src/components/tools/index.js
  62. 10 13
      src/config/defaultSettings.js
  63. 24 36
      src/config/router.config.js
  64. 22 25
      src/core/bootstrap.js
  65. 1 1
      src/core/directives/action.js
  66. 0 99
      src/core/lazy_lib/components_use.js
  67. 96 7
      src/core/lazy_use.js
  68. 0 3
      src/core/use.js
  69. 94 0
      src/global.less
  70. 36 0
      src/layouts/BasicLayout.less
  71. 116 128
      src/layouts/BasicLayout.vue
  72. 4 173
      src/layouts/PageView.vue
  73. 6 11
      src/layouts/UserLayout.vue
  74. 59 0
      src/locales/index.js
  75. 45 0
      src/locales/lang/en-US.js
  76. 22 0
      src/locales/lang/zh-CN.js
  77. 10 4
      src/main.js
  78. 1 1
      src/mock/services/auth.js
  79. 0 10
      src/mock/services/user.js
  80. 14 9
      src/permission.js
  81. 3 3
      src/router/README.md
  82. 6 6
      src/router/generator-routers.js
  83. 0 2
      src/router/index.js
  84. 32 0
      src/store/app-mixin.js
  85. 11 0
      src/store/device-mixin.js
  86. 3 3
      src/store/getters.js
  87. 16 0
      src/store/i18n-mixin.js
  88. 65 88
      src/store/modules/app.js
  89. 3 3
      src/store/modules/user.js
  90. 18 10
      src/store/mutation-types.js
  91. 0 33
      src/utils/device.js
  92. 3 1
      src/utils/domUtil.js
  93. 0 76
      src/utils/mixin.js
  94. 20 13
      src/utils/request.js
  95. 18 0
      src/utils/screenLog.js
  96. 0 215
      src/views/Home.vue
  97. 7 6
      src/views/account/center/index.vue
  98. 40 47
      src/views/account/settings/Custom.vue
  99. 7 8
      src/views/account/settings/Index.vue
  100. 15 5
      src/views/dashboard/Analysis.vue

+ 14 - 45
README.md

@@ -1,35 +1,28 @@
 English | [简体中文](./README.zh-CN.md)
 
-<h1 align="center">Ant Design Pro Vue</h1>
+<h1 align="center">Ant Design Vue Pro</h1>
 <div align="center">
 An out-of-box UI solution for enterprise applications as a Vue boilerplate. based on  <a href="https://vuecomponent.github.io/ant-design-vue/docs/vue/introduce-cn/" target="_blank">Ant Design of Vue</a>
 </div>
 
 <div align="center">
 
-[![Backers on Open Collective](https://opencollective.com/ant-design-pro-vue/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/ant-design-pro-vue/sponsors/badge.svg)](#sponsors) [![License](https://img.shields.io/npm/l/package.json.svg?style=flat)](https://github.com/sendya/ant-design-pro-vue/blob/master/LICENSE)
-[![Release](https://img.shields.io/github/release/sendya/ant-design-pro-vue.svg?style=flat)](https://github.com/sendya/ant-design-pro-vue/releases/latest)
-[![Travis branch](https://travis-ci.org/sendya/ant-design-pro-vue.svg?branch=master)](https://travis-ci.org/sendya/ant-design-pro-vue)
+[![License](https://img.shields.io/npm/l/package.json.svg?style=flat)](https://github.com/vueComponent/ant-design-vue-pro/blob/master/LICENSE)
+[![Release](https://img.shields.io/github/release/vueComponent/ant-design-vue-pro.svg?style=flat)](https://github.com/vueComponent/ant-design-vue-pro/releases/latest)
+[![Travis branch](https://travis-ci.org/vueComponent/ant-design-vue-pro.svg?branch=master)](https://travis-ci.org/vueComponent/ant-design-vue-pro)
 
 </div>
 
-- Preview: https://preview.pro.loacg.com
-- Home Page: https://pro.loacg.com
-- Documentation: https://pro.loacg.com/docs/getting-started
-- ChangeLog: https://pro.loacg.com/docs/changelog
-- FAQ: https://pro.loacg.com/docs/faq
+- Preview: https://preview.pro.antdv.com
+- Home Page: https://pro.antdv.com
+- Documentation: https://pro.antdv.com/docs/getting-started
+- ChangeLog: https://pro.antdv.com/docs/changelog
+- FAQ: https://pro.antdv.com/docs/faq
 
 Overview
 ----
 
-![dashboard + multi-tabs](https://static-2.loacg.com/open/static/github/20190224163345.jpg)
-
-![dashboard + setting](https://static-2.loacg.com/open/static/github/20181126112124.png)
-
-![user profile](https://static-2.loacg.com/open/static/github/20180916-134251.png)
-
-![permission list](https://static-2.loacg.com/open/static/github/20180916-154937.png)
-
+![dashboard](https://static-2.loacg.com/open/static/github/SP1.png)
 
 ### Env and dependencies
 
@@ -50,8 +43,8 @@ Overview
 
 - Clone repo
 ```bash
-git clone https://github.com/sendya/ant-design-pro-vue.git
-cd ant-design-pro-vue
+git clone https://github.com/vueComponent/ant-design-vue-pro.git
+cd ant-design-vue-pro
 ```
 
 - Install dependencies
@@ -77,7 +70,7 @@ yarn run lint
 
 ### Other
 
-- **IMPORTANT : About Issue feedback !! when opening Issue read [Issue / PR Contributing](https://github.com/sendya/ant-design-pro-vue/issues/90)**
+- **IMPORTANT : About Issue feedback !! when opening Issue read [Issue / PR Contributing](https://github.com/vueComponent/ant-design-vue-pro/issues/90)**
 
 - [Vue-cli3](https://cli.vuejs.org/guide/) used by the project.
 
@@ -105,28 +98,4 @@ Modern browsers and IE10.
 ## Contributors
 
 This project exists thanks to all the people who contribute. 
-<a href="https://github.com/sendya/ant-design-pro-vue/graphs/contributors"><img src="https://opencollective.com/ant-design-pro-vue/contributors.svg?width=890&button=false" /></a>
-
-
-## Backers
-
-Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/ant-design-pro-vue#backer)]
-
-<a href="https://opencollective.com/ant-design-pro-vue#backers" target="_blank"><img src="https://opencollective.com/ant-design-pro-vue/backers.svg?width=890"></a>
-
-
-## Sponsors
-
-Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/ant-design-pro-vue#sponsor)]
-
-<a href="https://opencollective.com/ant-design-pro-vue/sponsor/0/website" target="_blank"><img src="https://opencollective.com/ant-design-pro-vue/sponsor/0/avatar.svg"></a>
-<a href="https://opencollective.com/ant-design-pro-vue/sponsor/1/website" target="_blank"><img src="https://opencollective.com/ant-design-pro-vue/sponsor/1/avatar.svg"></a>
-<a href="https://opencollective.com/ant-design-pro-vue/sponsor/2/website" target="_blank"><img src="https://opencollective.com/ant-design-pro-vue/sponsor/2/avatar.svg"></a>
-<a href="https://opencollective.com/ant-design-pro-vue/sponsor/3/website" target="_blank"><img src="https://opencollective.com/ant-design-pro-vue/sponsor/3/avatar.svg"></a>
-<a href="https://opencollective.com/ant-design-pro-vue/sponsor/4/website" target="_blank"><img src="https://opencollective.com/ant-design-pro-vue/sponsor/4/avatar.svg"></a>
-<a href="https://opencollective.com/ant-design-pro-vue/sponsor/5/website" target="_blank"><img src="https://opencollective.com/ant-design-pro-vue/sponsor/5/avatar.svg"></a>
-<a href="https://opencollective.com/ant-design-pro-vue/sponsor/6/website" target="_blank"><img src="https://opencollective.com/ant-design-pro-vue/sponsor/6/avatar.svg"></a>
-<a href="https://opencollective.com/ant-design-pro-vue/sponsor/7/website" target="_blank"><img src="https://opencollective.com/ant-design-pro-vue/sponsor/7/avatar.svg"></a>
-<a href="https://opencollective.com/ant-design-pro-vue/sponsor/8/website" target="_blank"><img src="https://opencollective.com/ant-design-pro-vue/sponsor/8/avatar.svg"></a>
-<a href="https://opencollective.com/ant-design-pro-vue/sponsor/9/website" target="_blank"><img src="https://opencollective.com/ant-design-pro-vue/sponsor/9/avatar.svg"></a>
-
+<a href="https://github.com/vueComponent/ant-design-vue-pro/graphs/contributors"><img src="https://opencollective.com/ant-design-pro-vue/contributors.svg?width=890&button=false" /></a>

+ 14 - 42
README.zh-CN.md

@@ -1,23 +1,23 @@
 [English](./README.md) | 简体中文
 
-<h1 align="center">Ant Design Pro Vue</h1>
+<h1 align="center">Ant Design Vue Pro</h1>
 <div align="center">
 An out-of-box UI solution for enterprise applications as a Vue boilerplate. based on  <a href="https://vuecomponent.github.io/ant-design-vue/docs/vue/introduce-cn/" target="_blank">Ant Design of Vue</a>
 </div>
 
 <div align="center">
 
-[![Backers on Open Collective](https://opencollective.com/ant-design-pro-vue/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/ant-design-pro-vue/sponsors/badge.svg)](#sponsors) [![License](https://img.shields.io/npm/l/package.json.svg?style=flat)](https://github.com/sendya/ant-design-pro-vue/blob/master/LICENSE)
-[![Release](https://img.shields.io/github/release/sendya/ant-design-pro-vue.svg?style=flat)](https://github.com/sendya/ant-design-pro-vue/releases/latest)
-[![Travis branch](https://travis-ci.org/sendya/ant-design-pro-vue.svg?branch=master)](https://travis-ci.org/sendya/ant-design-pro-vue)
+[![License](https://img.shields.io/npm/l/package.json.svg?style=flat)](https://github.com/vueComponent/ant-design-vue-pro/blob/master/LICENSE)
+[![Release](https://img.shields.io/github/release/vueComponent/ant-design-vue-pro.svg?style=flat)](https://github.com/vueComponent/ant-design-vue-pro/releases/latest)
+[![Travis branch](https://travis-ci.org/vueComponent/ant-design-vue-pro.svg?branch=master)](https://travis-ci.org/vueComponent/ant-design-vue-pro)
 
 </div>
 
-- 预览: https://preview.pro.loacg.com
-- 首页: https://pro.loacg.com
-- 文档: https://pro.loacg.com/docs/getting-started
-- 更新日志: https://pro.loacg.com/docs/changelog
-- 常见问题: https://pro.loacg.com/docs/faq
+- 预览: https://preview.pro.antdv.com
+- 首页: https://pro.antdv.com
+- 文档: https://pro.antdv.com/docs/getting-started
+- 更新日志: https://pro.antdv.com/docs/changelog
+- 常见问题: https://pro.antdv.com/docs/faq
 
 
 Overview
@@ -25,12 +25,7 @@ Overview
 
 基于 [Ant Design of Vue](https://vuecomponent.github.io/ant-design-vue/docs/vue/introduce-cn/) 实现的 [Ant Design Pro](https://pro.ant.design/) 
 
-![工作台-多标签模式](https://static-2.loacg.com/open/static/github/20190224163345.jpg)
-
-![工作台+设置菜单](https://static-2.loacg.com/open/static/github/20181126112124.png)
-
-![个人设置](https://static-2.loacg.com/open/static/github/20180916-134251.png)
-
+![dashboard](https://static-2.loacg.com/open/static/github/SP1.png)
 
 环境和依赖
 ----
@@ -54,8 +49,8 @@ Overview
 
 - 拉取项目代码
 ```bash
-git clone https://github.com/sendya/ant-design-pro-vue.git
-cd ant-design-pro-vue
+git clone https://github.com/vueComponent/ant-design-vue-pro.git
+cd ant-design-vue-pro
 ```
 
 - 安装依赖
@@ -83,7 +78,7 @@ yarn run lint
 其他说明
 ----
 
-- **关于 Issue 反馈 (重要!重要!重要!) 请在开 *Issue* 前,先阅读该内容:[Issue / PR 编写建议](https://github.com/sendya/ant-design-pro-vue/issues/90)** 
+- **关于 Issue 反馈 (重要!重要!重要!) 请在开 *Issue* 前,先阅读该内容:[Issue / PR 编写建议](https://github.com/vueComponent/ant-design-vue-pro/issues/90)** 
 
 - 项目使用的 [vue-cli3](https://cli.vuejs.org/guide/), 请确保你所使用的 vue-cli 是新版,并且已经学习 cli 官方文档使用教程
 
@@ -111,27 +106,4 @@ Modern browsers and IE10.
 ## Contributors
 
 This project exists thanks to all the people who contribute. 
-<a href="https://github.com/sendya/ant-design-pro-vue/graphs/contributors"><img src="https://opencollective.com/ant-design-pro-vue/contributors.svg?width=890&button=false" /></a>
-
-
-## Backers
-
-Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/ant-design-pro-vue#backer)]
-
-<a href="https://opencollective.com/ant-design-pro-vue#backers" target="_blank"><img src="https://opencollective.com/ant-design-pro-vue/backers.svg?width=890"></a>
-
-
-## Sponsors
-
-Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/ant-design-pro-vue#sponsor)]
-
-<a href="https://opencollective.com/ant-design-pro-vue/sponsor/0/website" target="_blank"><img src="https://opencollective.com/ant-design-pro-vue/sponsor/0/avatar.svg"></a>
-<a href="https://opencollective.com/ant-design-pro-vue/sponsor/1/website" target="_blank"><img src="https://opencollective.com/ant-design-pro-vue/sponsor/1/avatar.svg"></a>
-<a href="https://opencollective.com/ant-design-pro-vue/sponsor/2/website" target="_blank"><img src="https://opencollective.com/ant-design-pro-vue/sponsor/2/avatar.svg"></a>
-<a href="https://opencollective.com/ant-design-pro-vue/sponsor/3/website" target="_blank"><img src="https://opencollective.com/ant-design-pro-vue/sponsor/3/avatar.svg"></a>
-<a href="https://opencollective.com/ant-design-pro-vue/sponsor/4/website" target="_blank"><img src="https://opencollective.com/ant-design-pro-vue/sponsor/4/avatar.svg"></a>
-<a href="https://opencollective.com/ant-design-pro-vue/sponsor/5/website" target="_blank"><img src="https://opencollective.com/ant-design-pro-vue/sponsor/5/avatar.svg"></a>
-<a href="https://opencollective.com/ant-design-pro-vue/sponsor/6/website" target="_blank"><img src="https://opencollective.com/ant-design-pro-vue/sponsor/6/avatar.svg"></a>
-<a href="https://opencollective.com/ant-design-pro-vue/sponsor/7/website" target="_blank"><img src="https://opencollective.com/ant-design-pro-vue/sponsor/7/avatar.svg"></a>
-<a href="https://opencollective.com/ant-design-pro-vue/sponsor/8/website" target="_blank"><img src="https://opencollective.com/ant-design-pro-vue/sponsor/8/avatar.svg"></a>
-<a href="https://opencollective.com/ant-design-pro-vue/sponsor/9/website" target="_blank"><img src="https://opencollective.com/ant-design-pro-vue/sponsor/9/avatar.svg"></a>
+<a href="https://github.com/vueComponent/ant-design-vue-pro/graphs/contributors"><img src="https://opencollective.com/ant-design-pro-vue/contributors.svg?width=890&button=false" /></a>

+ 3 - 0
config/plugin.config.js

@@ -26,6 +26,9 @@ const themePluginOption = {
       case '.ant-steps-item-process .ant-steps-item-icon > .ant-steps-icon':
       case '.ant-steps-item-process .ant-steps-item-icon>.ant-steps-icon':
         return ':not(.ant-steps-item-process)' + selector
+      // fixed https://github.com/vueComponent/ant-design-vue-pro/issues/876
+      case '.ant-steps-item-process .ant-steps-item-icon':
+        return ':not(.ant-steps-item-custom)' + selector
       case '.ant-menu-horizontal>.ant-menu-item-active,.ant-menu-horizontal>.ant-menu-item-open,.ant-menu-horizontal>.ant-menu-item-selected,.ant-menu-horizontal>.ant-menu-item:hover,.ant-menu-horizontal>.ant-menu-submenu-active,.ant-menu-horizontal>.ant-menu-submenu-open,.ant-menu-horizontal>.ant-menu-submenu-selected,.ant-menu-horizontal>.ant-menu-submenu:hover':
       case '.ant-menu-horizontal > .ant-menu-item-active,.ant-menu-horizontal > .ant-menu-item-open,.ant-menu-horizontal > .ant-menu-item-selected,.ant-menu-horizontal > .ant-menu-item:hover,.ant-menu-horizontal > .ant-menu-submenu-active,.ant-menu-horizontal > .ant-menu-submenu-open,.ant-menu-horizontal > .ant-menu-submenu-selected,.ant-menu-horizontal > .ant-menu-submenu:hover':
         return '.ant-menu-horizontal > .ant-menu-item-active,.ant-menu-horizontal > .ant-menu-item-open,.ant-menu-horizontal > .ant-menu-item-selected,.ant-menu-horizontal:not(.ant-menu-dark) > .ant-menu-item:hover,.ant-menu-horizontal > .ant-menu-submenu-active,.ant-menu-horizontal > .ant-menu-submenu-open,.ant-menu-horizontal:not(.ant-menu-dark) > .ant-menu-submenu-selected,.ant-menu-horizontal:not(.ant-menu-dark) > .ant-menu-submenu:hover'

+ 115 - 0
config/themePluginConfig.js

@@ -0,0 +1,115 @@
+export default {
+  theme: [
+    {
+      key: 'dark',
+      fileName: 'dark.css',
+      theme: 'dark'
+    },
+    {
+      key: '#F5222D',
+      fileName: '#F5222D.css',
+      modifyVars: {
+        '@primary-color': '#F5222D'
+      }
+    },
+    {
+      key: '#FA541C',
+      fileName: '#FA541C.css',
+      modifyVars: {
+        '@primary-color': '#FA541C'
+      }
+    },
+    {
+      key: '#FAAD14',
+      fileName: '#FAAD14.css',
+      modifyVars: {
+        '@primary-color': '#FAAD14'
+      }
+    },
+    {
+      key: '#13C2C2',
+      fileName: '#13C2C2.css',
+      modifyVars: {
+        '@primary-color': '#13C2C2'
+      }
+    },
+    {
+      key: '#52C41A',
+      fileName: '#52C41A.css',
+      modifyVars: {
+        '@primary-color': '#52C41A'
+      }
+    },
+    {
+      key: '#2F54EB',
+      fileName: '#2F54EB.css',
+      modifyVars: {
+        '@primary-color': '#2F54EB'
+      }
+    },
+    {
+      key: '#722ED1',
+      fileName: '#722ED1.css',
+      modifyVars: {
+        '@primary-color': '#722ED1'
+      }
+    },
+
+    {
+      key: '#F5222D',
+      theme: 'dark',
+      fileName: 'dark-#F5222D.css',
+      modifyVars: {
+        '@primary-color': '#F5222D'
+      }
+    },
+    {
+      key: '#FA541C',
+      theme: 'dark',
+      fileName: 'dark-#FA541C.css',
+      modifyVars: {
+        '@primary-color': '#FA541C'
+      }
+    },
+    {
+      key: '#FAAD14',
+      theme: 'dark',
+      fileName: 'dark-#FAAD14.css',
+      modifyVars: {
+        '@primary-color': '#FAAD14'
+      }
+    },
+    {
+      key: '#13C2C2',
+      theme: 'dark',
+      fileName: 'dark-#13C2C2.css',
+      modifyVars: {
+        '@primary-color': '#13C2C2'
+      }
+    },
+    {
+      key: '#52C41A',
+      theme: 'dark',
+      fileName: 'dark-#52C41A.css',
+      modifyVars: {
+        '@primary-color': '#52C41A'
+      }
+    },
+    {
+      key: '#2F54EB',
+      theme: 'dark',
+      fileName: 'dark-#2F54EB.css',
+      modifyVars: {
+        '@primary-color': '#2F54EB'
+      }
+    },
+    {
+      key: '#722ED1',
+      theme: 'dark',
+      fileName: 'dark-#722ED1.css',
+      modifyVars: {
+        '@primary-color': '#722ED1'
+      }
+    }
+  ]
+}

+ 8 - 10
package.json

@@ -1,6 +1,6 @@
 {
   "name": "vue-antd-pro",
-  "version": "2.1.0",
+  "version": "3.0.0",
   "private": true,
   "scripts": {
     "serve": "vue-cli-service serve",
@@ -8,12 +8,12 @@
     "test:unit": "vue-cli-service test:unit",
     "lint": "vue-cli-service lint",
     "build:preview": "vue-cli-service build --mode preview",
-    "lint:nofix": "vue-cli-service lint --no-fix",
-    "postinstall": "opencollective-postinstall"
+    "lint:nofix": "vue-cli-service lint --no-fix"
   },
   "dependencies": {
+    "@ant-design-vue/pro-layout": "^0.3.4",
     "@antv/data-set": "^0.10.2",
-    "ant-design-vue": "1.5.0-rc.6",
+    "ant-design-vue": "^1.6.2",
     "axios": "^0.19.0",
     "core-js": "^3.1.2",
     "enquire.js": "^2.1.6",
@@ -24,11 +24,12 @@
     "mockjs2": "1.0.8",
     "moment": "^2.24.0",
     "nprogress": "^0.2.0",
+    "store": "^2.0.12",
     "viser-vue": "^2.4.6",
     "vue": "^2.6.10",
     "vue-clipboard2": "^0.2.1",
     "vue-cropper": "0.4.9",
-    "vue-ls": "^3.2.1",
+    "vue-i18n": "^8.17.4",
     "vue-quill-editor": "^3.0.6",
     "vue-router": "^3.1.2",
     "vue-svg-component-runtime": "^1.0.1",
@@ -51,16 +52,13 @@
     "eslint": "^5.16.0",
     "eslint-plugin-html": "^5.0.0",
     "eslint-plugin-vue": "^5.2.3",
+    "git-revision-webpack-plugin": "^3.0.6",
     "less": "^3.0.4",
     "less-loader": "^5.0.0",
     "opencollective": "^1.0.3",
     "opencollective-postinstall": "^2.0.2",
     "vue-svg-icon-loader": "^2.1.1",
     "vue-template-compiler": "^2.6.10",
-    "webpack-theme-color-replacer": "^1.2.17"
-  },
-  "collective": {
-    "type": "opencollective",
-    "url": "https://opencollective.com/ant-design-pro-vue"
+    "webpack-theme-color-replacer": "^1.3.12"
   }
 }

+ 7 - 5
public/index.html

@@ -6,7 +6,7 @@
     <meta name="viewport" content="width=device-width,initial-scale=1.0">
     <link rel="icon" href="<%= BASE_URL %>logo.png">
     <title>Ant Design Pro</title>
-    <style>#loading-mask{position:fixed;left:0;top:0;height:100%;width:100%;background:#fff;user-select:none;z-index:9999;overflow:hidden}.loading-wrapper{position:absolute;top:50%;left:50%;transform:translate(-50%,-100%)}.loading-dot{animation:antRotate 1.2s infinite linear;transform:rotate(45deg);position:relative;display:inline-block;font-size:64px;width:64px;height:64px;box-sizing:border-box}.loading-dot i{width:22px;height:22px;position:absolute;display:block;background-color:#1890ff;border-radius:100%;transform:scale(.75);transform-origin:50% 50%;opacity:.3;animation:antSpinMove 1s infinite linear alternate}.loading-dot i:nth-child(1){top:0;left:0}.loading-dot i:nth-child(2){top:0;right:0;-webkit-animation-delay:.4s;animation-delay:.4s}.loading-dot i:nth-child(3){right:0;bottom:0;-webkit-animation-delay:.8s;animation-delay:.8s}.loading-dot i:nth-child(4){bottom:0;left:0;-webkit-animation-delay:1.2s;animation-delay:1.2s}@keyframes antRotate{to{-webkit-transform:rotate(405deg);transform:rotate(405deg)}}@-webkit-keyframes antRotate{to{-webkit-transform:rotate(405deg);transform:rotate(405deg)}}@keyframes antSpinMove{to{opacity:1}}@-webkit-keyframes antSpinMove{to{opacity:1}}</style>
+    <style>.first-loading-wrp{display:flex;justify-content:center;align-items:center;flex-direction:column;min-height:420px;height:100%}.first-loading-wrp>h1{font-size:128px}.first-loading-wrp .loading-wrp{padding:98px;display:flex;justify-content:center;align-items:center}.dot{animation:antRotate 1.2s infinite linear;transform:rotate(45deg);position:relative;display:inline-block;font-size:32px;width:32px;height:32px;box-sizing:border-box}.dot i{width:14px;height:14px;position:absolute;display:block;background-color:#1890ff;border-radius:100%;transform:scale(.75);transform-origin:50% 50%;opacity:.3;animation:antSpinMove 1s infinite linear alternate}.dot i:nth-child(1){top:0;left:0}.dot i:nth-child(2){top:0;right:0;-webkit-animation-delay:.4s;animation-delay:.4s}.dot i:nth-child(3){right:0;bottom:0;-webkit-animation-delay:.8s;animation-delay:.8s}.dot i:nth-child(4){bottom:0;left:0;-webkit-animation-delay:1.2s;animation-delay:1.2s}@keyframes antRotate{to{-webkit-transform:rotate(405deg);transform:rotate(405deg)}}@-webkit-keyframes antRotate{to{-webkit-transform:rotate(405deg);transform:rotate(405deg)}}@keyframes antSpinMove{to{opacity:1}}@-webkit-keyframes antSpinMove{to{opacity:1}}</style>
     <!-- require cdn assets css -->
     <% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.css) { %>
     <link rel="stylesheet" href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" />
@@ -17,11 +17,13 @@
       <strong>We're sorry but vue-antd-pro doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
     </noscript>
     <div id="app">
-      <div id="loading-mask">
-          <div class="loading-wrapper">
-            <span class="loading-dot loading-dot-spin"><i></i><i></i><i></i><i></i></span>
-          </div>
+      <div class="first-loading-wrp">
+        <h1>Pro</h1>
+        <div class="loading-wrp">
+          <span class="dot dot-spin"><i></i><i></i><i></i><i></i></span>
         </div>
+        <div style="display: flex; justify-content: center; align-items: center;">Ant Design</div>
+      </div>
     </div>
     <!-- require cdn assets js -->
     <% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.js) { %>

+ 0 - 1
public/loading/loading.css

@@ -1 +0,0 @@
-#preloadingAnimation{position:fixed;left:0;top:0;height:100%;width:100%;background:#ffffff;user-select:none;z-index: 9999;overflow: hidden}.lds-roller{display:inline-block;position:relative;left:50%;top:50%;transform:translate(-50%,-50%);width:64px;height:64px;}.lds-roller div{animation:lds-roller 1.2s cubic-bezier(0.5,0,0.5,1) infinite;transform-origin:32px 32px;}.lds-roller div:after{content:" ";display:block;position:absolute;width:6px;height:6px;border-radius:50%;background:#13c2c2;margin:-3px 0 0 -3px;}.lds-roller div:nth-child(1){animation-delay:-0.036s;}.lds-roller div:nth-child(1):after{top:50px;left:50px;}.lds-roller div:nth-child(2){animation-delay:-0.072s;}.lds-roller div:nth-child(2):after{top:54px;left:45px;}.lds-roller div:nth-child(3){animation-delay:-0.108s;}.lds-roller div:nth-child(3):after{top:57px;left:39px;}.lds-roller div:nth-child(4){animation-delay:-0.144s;}.lds-roller div:nth-child(4):after{top:58px;left:32px;}.lds-roller div:nth-child(5){animation-delay:-0.18s;}.lds-roller div:nth-child(5):after{top:57px;left:25px;}.lds-roller div:nth-child(6){animation-delay:-0.216s;}.lds-roller div:nth-child(6):after{top:54px;left:19px;}.lds-roller div:nth-child(7){animation-delay:-0.252s;}.lds-roller div:nth-child(7):after{top:50px;left:14px;}.lds-roller div:nth-child(8){animation-delay:-0.288s;}.lds-roller div:nth-child(8):after{top:45px;left:10px;}#preloadingAnimation .load-tips{color: #13c2c2;font-size:2rem;position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);margin-top:80px;text-align:center;width:400px;height:64px;}  @keyframes lds-roller{0%{transform:rotate(0deg);} 100%{transform:rotate(360deg);}}

+ 0 - 1
public/loading/loading.html

@@ -1 +0,0 @@
-<div id="preloadingAnimation"><div class=lds-roller><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div></div><div class=load-tips>Loading</div></div>

File diff suppressed because it is too large
+ 0 - 2
public/loading/option2/html_code_segment.html


+ 0 - 1
public/loading/option2/loading.css

@@ -1 +0,0 @@
-.preloading-animate{background:#ffffff;width:100%;height:100%;position:fixed;left:0;top:0;z-index:299;}.preloading-animate .preloading-wrapper{position:absolute;width:5rem;height:5rem;left:50%;top:50%;transform:translate(-50%,-50%);}.preloading-animate .preloading-wrapper .preloading-balls{font-size:5rem;}

File diff suppressed because it is too large
+ 0 - 0
public/loading/option2/loading.svg


+ 9 - 5
src/App.vue

@@ -7,18 +7,22 @@
 </template>
 
 <script>
-import zhCN from 'ant-design-vue/lib/locale-provider/zh_CN'
-import { AppDeviceEnquire } from '@/utils/mixin'
+import { domTitle, setDocumentTitle } from '@/utils/domUtil'
+import { i18nRender } from '@/locales'
 
 export default {
-  mixins: [AppDeviceEnquire],
   data () {
     return {
-      locale: zhCN
     }
   },
-  mounted () {
+  computed: {
+    locale () {
+      // 只是为了切换语言时,更新标题
+      const { title } = this.$route.meta
+      title && (setDocumentTitle(`${i18nRender(title)} - ${domTitle}`))
 
+      return this.$i18n.getLocaleMessage(this.$store.getters.lang).antLocale
+    }
   }
 }
 </script>

+ 0 - 12
src/api/index.js

@@ -1,12 +0,0 @@
-const api = {
-  Login: '/auth/login',
-  Logout: '/auth/logout',
-  ForgePassword: '/auth/forge-password',
-  Register: '/auth/register',
-  twoStepCode: '/auth/2step-code',
-  SendSms: '/account/sms',
-  SendSmsErr: '/account/sms_err',
-  // get my info
-  UserInfo: '/user/info'
-}
-export default api

+ 27 - 15
src/api/login.js

@@ -1,5 +1,17 @@
-import api from './index'
-import { axios } from '@/utils/request'
+import request from '@/utils/request'
+
+const userApi = {
+  Login: '/auth/login',
+  Logout: '/auth/logout',
+  ForgePassword: '/auth/forge-password',
+  Register: '/auth/register',
+  twoStepCode: '/auth/2step-code',
+  SendSms: '/account/sms',
+  SendSmsErr: '/account/sms_err',
+  // get my info
+  UserInfo: '/user/info',
+  UserMenu: '/user/nav'
+}
 
 /**
  * login func
@@ -13,24 +25,24 @@ import { axios } from '@/utils/request'
  * @returns {*}
  */
 export function login (parameter) {
-  return axios({
-    url: '/auth/login',
+  return request({
+    url: userApi.Login,
     method: 'post',
     data: parameter
   })
 }
 
 export function getSmsCaptcha (parameter) {
-  return axios({
-    url: api.SendSms,
+  return request({
+    url: userApi.SendSms,
     method: 'post',
     data: parameter
   })
 }
 
 export function getInfo () {
-  return axios({
-    url: '/user/info',
+  return request({
+    url: userApi.UserInfo,
     method: 'get',
     headers: {
       'Content-Type': 'application/json;charset=UTF-8'
@@ -38,16 +50,16 @@ export function getInfo () {
   })
 }
 
-export function getCurrentUserNav (token) {
-  return axios({
-    url: '/user/nav',
+export function getCurrentUserNav () {
+  return request({
+    url: userApi.UserMenu,
     method: 'get'
   })
 }
 
 export function logout () {
-  return axios({
-    url: '/auth/logout',
+  return request({
+    url: userApi.Logout,
     method: 'post',
     headers: {
       'Content-Type': 'application/json;charset=UTF-8'
@@ -60,8 +72,8 @@ export function logout () {
  * @param parameter {*}
  */
 export function get2step (parameter) {
-  return axios({
-    url: api.twoStepCode,
+  return request({
+    url: userApi.twoStepCode,
     method: 'post',
     data: parameter
   })

+ 15 - 7
src/api/manage.js

@@ -1,4 +1,4 @@
-import { axios } from '@/utils/request'
+import request from '@/utils/request'
 
 const api = {
   user: '/user',
@@ -12,7 +12,7 @@ const api = {
 export default api
 
 export function getUserList (parameter) {
-  return axios({
+  return request({
     url: api.user,
     method: 'get',
     params: parameter
@@ -20,7 +20,7 @@ export function getUserList (parameter) {
 }
 
 export function getRoleList (parameter) {
-  return axios({
+  return request({
     url: api.role,
     method: 'get',
     params: parameter
@@ -28,7 +28,7 @@ export function getRoleList (parameter) {
 }
 
 export function getServiceList (parameter) {
-  return axios({
+  return request({
     url: api.service,
     method: 'get',
     params: parameter
@@ -36,7 +36,7 @@ export function getServiceList (parameter) {
 }
 
 export function getPermissions (parameter) {
-  return axios({
+  return request({
     url: api.permissionNoPager,
     method: 'get',
     params: parameter
@@ -44,7 +44,7 @@ export function getPermissions (parameter) {
 }
 
 export function getOrgTree (parameter) {
-  return axios({
+  return request({
     url: api.orgTree,
     method: 'get',
     params: parameter
@@ -54,9 +54,17 @@ export function getOrgTree (parameter) {
 // id == 0 add     post
 // id != 0 update  put
 export function saveService (parameter) {
-  return axios({
+  return request({
     url: api.service,
     method: parameter.id === 0 ? 'post' : 'put',
     data: parameter
   })
 }
+
+export function saveSub (sub) {
+  return request({
+    url: '/sub',
+    method: sub.id === 0 ? 'post' : 'put',
+    data: sub
+  })
+}

+ 24 - 0
src/components/AvatarList/Item.jsx

@@ -0,0 +1,24 @@
+import PropTypes from 'ant-design-vue/es/_util/vue-types'
+import { Tooltip, Avatar } from 'ant-design-vue'
+import { getSlotOptions } from 'ant-design-vue/lib/_util/props-util'
+import { warning } from 'ant-design-vue/lib/vc-util/warning'
+
+export const AvatarListItemProps = {
+  tips: PropTypes.string.def(null),
+  src: PropTypes.string.def('')
+}
+
+const Item = {
+  __ANT_AVATAR_CHILDREN: true,
+  name: 'AvatarListItem',
+  props: AvatarListItemProps,
+  created () {
+    warning(getSlotOptions(this.$parent).__ANT_AVATAR_LIST, 'AvatarListItem must be a subcomponent of AvatarList')
+  },
+  render () {
+    const AvatarDom = <Avatar size={this.$parent.size} src={this.src} />
+    return this.tips && <Tooltip title={this.tips}>{AvatarDom}</Tooltip> || <AvatarDom />
+  }
+}
+
+export default Item

+ 0 - 46
src/components/AvatarList/Item.vue

@@ -1,46 +0,0 @@
-<template>
-  <tooltip v-if="tips !== ''">
-    <template slot="title">{{ tips }}</template>
-    <avatar :size="avatarSize" :src="src" />
-  </tooltip>
-  <avatar v-else :size="avatarSize" :src="src" />
-</template>
-
-<script>
-import Avatar from 'ant-design-vue/es/avatar'
-import Tooltip from 'ant-design-vue/es/tooltip'
-
-export default {
-  name: 'AvatarItem',
-  components: {
-    Avatar,
-    Tooltip
-  },
-  props: {
-    tips: {
-      type: String,
-      default: '',
-      required: false
-    },
-    src: {
-      type: String,
-      default: ''
-    }
-  },
-  data () {
-    return {
-      size: this.$parent.size
-    }
-  },
-  computed: {
-    avatarSize () {
-      return this.size !== 'mini' && this.size || 20
-    }
-  },
-  watch: {
-    '$parent.size' (val) {
-      this.size = val
-    }
-  }
-}
-</script>

+ 72 - 0
src/components/AvatarList/List.jsx

@@ -0,0 +1,72 @@
+import './index.less'
+
+import PropTypes from 'ant-design-vue/es/_util/vue-types'
+import Avatar from 'ant-design-vue/es/avatar'
+import Item from './Item.jsx'
+import { filterEmpty } from '@/components/_util/util'
+
+/**
+ * size: `number`、 `large`、`small`、`default` 默认值: default
+ * maxLength: number
+ * excessItemsStyle: CSSProperties
+ */
+const AvatarListProps = {
+  prefixCls: PropTypes.string.def('ant-pro-avatar-list'),
+  size: {
+    validator: val => {
+      return typeof val === 'number' || ['small', 'large', 'default'].includes(val)
+    },
+    default: 'default'
+  },
+  maxLength: PropTypes.number.def(0),
+  excessItemsStyle: PropTypes.object.def({
+    color: '#f56a00',
+    backgroundColor: '#fde3cf'
+  })
+}
+
+const AvatarList = {
+  __ANT_AVATAR_LIST: true,
+  Item,
+  name: 'AvatarList',
+  props: AvatarListProps,
+  render (h) {
+    const { prefixCls, size } = this.$props
+    const className = {
+      [`${prefixCls}`]: true,
+      [`${size}`]: true
+    }
+    const items = filterEmpty(this.$slots.default)
+    const itemsDom = items && items.length ? <ul class={`${prefixCls}-items`}>{this.getItems(items)}</ul> : null
+
+    return (
+      <div class={className}>
+        {itemsDom}
+      </div>
+    )
+  },
+  methods: {
+    getItems (items) {
+      const className = {
+        [`${this.prefixCls}-item`]: true,
+        [`${this.size}`]: true
+      }
+      const totalSize = items.length
+
+      if (this.maxLength > 0) {
+        items = items.slice(0, this.maxLength)
+        items.push((<Avatar size={this.size} style={this.excessItemsStyle}>{`+${totalSize - this.maxLength}`}</Avatar>))
+      }
+      return items.map((item) => (
+        <li class={className}>{item}</li>
+      ))
+    }
+  }
+}
+
+AvatarList.install = function (Vue) {
+  Vue.component(AvatarList.name, AvatarList)
+  Vue.component(AvatarList.Item.name, AvatarList.Item)
+}
+
+export default AvatarList

+ 0 - 99
src/components/AvatarList/List.vue

@@ -1,99 +0,0 @@
-<!--
-<template>
-  <div :class="[prefixCls]">
-    <ul>
-      <slot></slot>
-      <template v-for="item in filterEmpty($slots.default).slice(0, 3)"></template>
-
-      <template v-if="maxLength > 0 && filterEmpty($slots.default).length > maxLength">
-        <avatar-item :size="size">
-          <avatar :size="size !== 'mini' && size || 20" :style="excessItemsStyle">{{ `+${maxLength}` }}</avatar>
-        </avatar-item>
-      </template>
-    </ul>
-  </div>
-</template>
--->
-
-<script>
-import Avatar from 'ant-design-vue/es/avatar'
-import AvatarItem from './Item'
-import { filterEmpty } from '@/components/_util/util'
-
-export default {
-  AvatarItem,
-  name: 'AvatarList',
-  components: {
-    Avatar,
-    AvatarItem
-  },
-  props: {
-    prefixCls: {
-      type: String,
-      default: 'ant-pro-avatar-list'
-    },
-    /**
-       * 头像大小 类型: large、small 、mini, default
-       * 默认值: default
-       */
-    size: {
-      type: [String, Number],
-      default: 'default'
-    },
-    /**
-       * 要显示的最大项目
-       */
-    maxLength: {
-      type: Number,
-      default: 0
-    },
-    /**
-       * 多余的项目风格
-       */
-    excessItemsStyle: {
-      type: Object,
-      default: () => {
-        return {
-          color: '#f56a00',
-          backgroundColor: '#fde3cf'
-        }
-      }
-    }
-  },
-  data () {
-    return {}
-  },
-  methods: {
-    getItems (items) {
-      const classString = {
-        [`${this.prefixCls}-item`]: true,
-        [`${this.size}`]: true
-      }
-
-      if (this.maxLength > 0) {
-        items = items.slice(0, this.maxLength)
-        items.push((<Avatar size={ this.size } style={ this.excessItemsStyle }>{`+${this.maxLength}`}</Avatar>))
-      }
-      const itemList = items.map((item) => (
-        <li class={ classString }>{ item }</li>
-      ))
-      return itemList
-    }
-  },
-  render () {
-    const { prefixCls, size } = this.$props
-    const classString = {
-      [`${prefixCls}`]: true,
-      [`${size}`]: true
-    }
-    const items = filterEmpty(this.$slots.default)
-    const itemsDom = items && items.length ? <ul class={`${prefixCls}-items`}>{ this.getItems(items) }</ul> : null
-
-    return (
-      <div class={ classString }>
-        { itemsDom }
-      </div>
-    )
-  }
-}
-</script>

+ 6 - 1
src/components/AvatarList/index.js

@@ -1,4 +1,9 @@
 import AvatarList from './List'
-import './index.less'
+import Item from './Item'
+
+export {
+  AvatarList,
+  Item as AvatarListItem
+}
 
 export default AvatarList

+ 1 - 1
src/components/AvatarList/index.md

@@ -9,7 +9,7 @@
 
 ```javascript
 import AvatarList from '@/components/AvatarList'
-const AvatarListItem = AvatarList.AvatarItem
+const AvatarListItem = AvatarList.Item
 
 export default {
     components: {

+ 0 - 102
src/components/CountDown/CountDown.vue

@@ -1,102 +0,0 @@
-<template>
-  <span>
-    {{ lastTime | format }}
-  </span>
-</template>
-
-<script>
-
-function fixedZero (val) {
-  return val * 1 < 10 ? `0${val}` : val
-}
-
-export default {
-  name: 'CountDown',
-  props: {
-    format: {
-      type: Function,
-      default: undefined
-    },
-    target: {
-      type: [Date, Number],
-      required: true
-    },
-    onEnd: {
-      type: Function,
-      default: () => ({})
-    }
-  },
-  data () {
-    return {
-      dateTime: '0',
-      originTargetTime: 0,
-      lastTime: 0,
-      timer: 0,
-      interval: 1000
-    }
-  },
-  filters: {
-    format (time) {
-      const hours = 60 * 60 * 1000
-      const minutes = 60 * 1000
-
-      const h = Math.floor(time / hours)
-      const m = Math.floor((time - h * hours) / minutes)
-      const s = Math.floor((time - h * hours - m * minutes) / 1000)
-      return `${fixedZero(h)}:${fixedZero(m)}:${fixedZero(s)}`
-    }
-  },
-  created () {
-    this.initTime()
-    this.tick()
-  },
-  methods: {
-    initTime () {
-      let lastTime = 0
-      let targetTime = 0
-      this.originTargetTime = this.target
-      try {
-        if (Object.prototype.toString.call(this.target) === '[object Date]') {
-          targetTime = this.target
-        } else {
-          targetTime = new Date(this.target).getTime()
-        }
-      } catch (e) {
-        throw new Error('invalid target prop')
-      }
-
-      lastTime = targetTime - new Date().getTime()
-
-      this.lastTime = lastTime < 0 ? 0 : lastTime
-    },
-    tick () {
-      const { onEnd } = this
-
-      this.timer = setTimeout(() => {
-        if (this.lastTime < this.interval) {
-          clearTimeout(this.timer)
-          this.lastTime = 0
-          if (typeof onEnd === 'function') {
-            onEnd()
-          }
-        } else {
-          this.lastTime -= this.interval
-          this.tick()
-        }
-      }, this.interval)
-    }
-  },
-  beforeUpdate () {
-    if (this.originTargetTime !== this.target) {
-      this.initTime()
-    }
-  },
-  beforeDestroy () {
-    clearTimeout(this.timer)
-  }
-}
-</script>
-
-<style scoped>
-
-</style>

+ 0 - 3
src/components/CountDown/index.js

@@ -1,3 +0,0 @@
-import CountDown from './CountDown'
-
-export default CountDown

+ 0 - 34
src/components/CountDown/index.md

@@ -1,34 +0,0 @@
-# CountDown 倒计时
-
-倒计时组件。
-
-
-
-引用方式:
-
-```javascript
-import CountDown from '@/components/CountDown/CountDown'
-
-export default {
-    components: {
-        CountDown
-    }
-}
-```
-
-
-
-## 代码演示  [demo](https://pro.loacg.com/test/home)
-
-```html
-<count-down :target="new Date().getTime() + 3000000" :on-end="onEndHandle" />
-```
-
-
-
-## API
-
-| 参数      | 说明                                      | 类型         | 默认值 |
-|----------|------------------------------------------|-------------|-------|
-| target | 目标时间 | Date | - |
-| onEnd |  倒计时结束回调 | funtion | -|

+ 0 - 153
src/components/DescriptionList/DescriptionList.vue

@@ -1,153 +0,0 @@
-<template>
-  <div :class="['description-list', size, layout === 'vertical' ? 'vertical': 'horizontal']">
-    <div v-if="title" class="title">{{ title }}</div>
-    <a-row>
-      <slot></slot>
-    </a-row>
-  </div>
-</template>
-
-<script>
-import { Col } from 'ant-design-vue/es/grid/'
-
-const Item = {
-  name: 'DetailListItem',
-  props: {
-    term: {
-      type: String,
-      default: '',
-      required: false
-    }
-  },
-  inject: {
-    col: {
-      type: Number
-    }
-  },
-  render () {
-    return (
-      <Col {...{ props: responsive[this.col] }}>
-        <div class="term">{this.$props.term}</div>
-        <div class="content">{this.$slots.default}</div>
-      </Col>
-    )
-  }
-}
-
-const responsive = {
-  1: { xs: 24 },
-  2: { xs: 24, sm: 12 },
-  3: { xs: 24, sm: 12, md: 8 },
-  4: { xs: 24, sm: 12, md: 6 }
-}
-
-export default {
-  name: 'DetailList',
-  Item: Item,
-  components: {
-    Col
-  },
-  props: {
-    title: {
-      type: String,
-      default: '',
-      required: false
-    },
-    col: {
-      type: Number,
-      required: false,
-      default: 3
-    },
-    size: {
-      type: String,
-      required: false,
-      default: 'large'
-    },
-    layout: {
-      type: String,
-      required: false,
-      default: 'horizontal'
-    }
-  },
-  provide () {
-    return {
-      col: this.col > 4 ? 4 : this.col
-    }
-  }
-}
-</script>
-
-<style lang="less" scoped>
-
-  .description-list {
-
-    .title {
-      color: rgba(0,0,0,.85);
-      font-size: 14px;
-      font-weight: 500;
-      margin-bottom: 16px;
-    }
-
-    /deep/ .term {
-      color: rgba(0,0,0,.85);
-      display: table-cell;
-      line-height: 20px;
-      margin-right: 8px;
-      padding-bottom: 16px;
-      white-space: nowrap;
-
-      &:not(:empty):after {
-        content: ":";
-        margin: 0 8px 0 2px;
-        position: relative;
-        top: -.5px;
-      }
-    }
-
-    /deep/ .content {
-      color: rgba(0,0,0,.65);
-      display: table-cell;
-      min-height: 22px;
-      line-height: 22px;
-      padding-bottom: 16px;
-      width: 100%;
-      &:empty {
-        content: ' ';
-        height: 38px;
-        padding-bottom: 16px;
-      }
-    }
-
-    &.small {
-
-      .title {
-        font-size: 14px;
-        color: rgba(0, 0, 0, .65);
-        font-weight: normal;
-        margin-bottom: 12px;
-      }
-      /deep/ .term, .content {
-        padding-bottom: 8px;
-      }
-    }
-
-    &.large {
-      /deep/ .term, .content {
-        padding-bottom: 16px;
-      }
-
-      .title {
-        font-size: 16px;
-      }
-    }
-
-    &.vertical {
-      .term {
-        padding-bottom: 8px;
-      }
-      /deep/ .term, .content {
-        display: block;
-      }
-    }
-  }
-</style>

+ 0 - 2
src/components/DescriptionList/index.js

@@ -1,2 +0,0 @@
-import DescriptionList from './DescriptionList'
-export default DescriptionList

+ 1 - 0
src/components/Editor/QuillEditor.vue

@@ -72,6 +72,7 @@ export default {
 
 /* 覆盖 quill 默认边框圆角为 ant 默认圆角,用于统一 ant 组件风格 */
 .ant-editor-quill {
+  line-height: initial;
   /deep/ .ql-toolbar.ql-snow {
     border-radius: @border-radius-base @border-radius-base 0 0;
   }

+ 0 - 130
src/components/Exception/ExceptionPage.vue

@@ -1,130 +0,0 @@
-<template>
-  <div class="exception">
-    <div class="imgBlock">
-      <div class="imgEle" :style="{backgroundImage: `url(${config[type].img})`}">
-      </div>
-    </div>
-    <div class="content">
-      <h1>{{ config[type].title }}</h1>
-      <div class="desc">{{ config[type].desc }}</div>
-      <div class="actions">
-        <a-button type="primary" @click="handleToHome">返回首页</a-button>
-      </div>
-    </div>
-  </div>
-</template>
-
-<script>
-import types from './type'
-
-export default {
-  name: 'Exception',
-  props: {
-    type: {
-      type: String,
-      default: '404'
-    }
-  },
-  data () {
-    return {
-      config: types
-    }
-  },
-  methods: {
-    handleToHome () {
-      this.$router.push({ name: 'dashboard' })
-    }
-  }
-}
-</script>
-<style lang="less">
-@import "~ant-design-vue/lib/style/index";
-
-.exception {
-  display: flex;
-  align-items: center;
-  height: 80%;
-  min-height: 500px;
-
-  .imgBlock {
-    flex: 0 0 62.5%;
-    width: 62.5%;
-    padding-right: 152px;
-    zoom: 1;
-    &::before,
-    &::after {
-      content: ' ';
-      display: table;
-    }
-    &::after {
-      clear: both;
-      height: 0;
-      font-size: 0;
-      visibility: hidden;
-    }
-  }
-
-  .imgEle {
-    float: right;
-    width: 100%;
-    max-width: 430px;
-    height: 360px;
-    background-repeat: no-repeat;
-    background-position: 50% 50%;
-    background-size: contain;
-  }
-
-  .content {
-    flex: auto;
-
-    h1 {
-      margin-bottom: 24px;
-      color: #434e59;
-      font-weight: 600;
-      font-size: 72px;
-      line-height: 72px;
-    }
-
-    .desc {
-      margin-bottom: 16px;
-      color: @text-color-secondary;
-      font-size: 20px;
-      line-height: 28px;
-    }
-
-    .actions {
-      button:not(:last-child) {
-        margin-right: 8px;
-      }
-    }
-  }
-}
-
-@media screen and (max-width: @screen-xl) {
-  .exception {
-    .imgBlock {
-      padding-right: 88px;
-    }
-  }
-}
-
-@media screen and (max-width: @screen-sm) {
-  .exception {
-    display: block;
-    text-align: center;
-    .imgBlock {
-      margin: 0 auto 24px;
-      padding-right: 0;
-    }
-  }
-}
-
-@media screen and (max-width: @screen-xs) {
-  .exception {
-    .imgBlock {
-      margin-bottom: -24px;
-      overflow: hidden;
-    }
-  }
-}
-</style>

+ 0 - 2
src/components/Exception/index.js

@@ -1,2 +0,0 @@
-import ExceptionPage from './ExceptionPage.vue'
-export default ExceptionPage

+ 0 - 19
src/components/Exception/type.js

@@ -1,19 +0,0 @@
-const types = {
-  403: {
-    img: 'https://gw.alipayobjects.com/zos/rmsportal/wZcnGqRDyhPOEYFcZDnb.svg',
-    title: '403',
-    desc: '抱歉,你无权访问该页面'
-  },
-  404: {
-    img: 'https://gw.alipayobjects.com/zos/rmsportal/KpnpchXsobRgLElEozzI.svg',
-    title: '404',
-    desc: '抱歉,你访问的页面不存在或仍在开发中'
-  },
-  500: {
-    img: 'https://gw.alipayobjects.com/zos/rmsportal/RVRUAYdCGeYNBWoKiIwB.svg',
-    title: '500',
-    desc: '抱歉,服务器出错了'
-  }
-}
-
-export default types

+ 18 - 1
src/components/FooterToolbar/FooterToolBar.vue

@@ -1,5 +1,5 @@
 <template>
-  <div :class="prefixCls">
+  <div :class="prefixCls" :style="{ width: barWidth, transition: '0.3s all' }">
     <div style="float: left">
       <slot name="extra">{{ extra }}</slot>
     </div>
@@ -17,10 +17,27 @@ export default {
       type: String,
       default: 'ant-pro-footer-toolbar'
     },
+    collapsed: {
+      type: Boolean,
+      default: false
+    },
+    isMobile: {
+      type: Boolean,
+      default: false
+    },
+    siderWidth: {
+      type: Number,
+      default: undefined
+    },
     extra: {
       type: [String, Object],
       default: ''
     }
+  },
+  computed: {
+    barWidth () {
+      return this.isMobile ? undefined : `calc(100% - ${this.collapsed ? 80 : this.siderWidth || 256}px)`
+    }
   }
 }
 </script>

+ 0 - 59
src/components/GlobalFooter/GlobalFooter.vue

@@ -1,59 +0,0 @@
-<template>
-  <div class="footer">
-    <div class="links">
-      <a
-        href="https://pro.loacg.com/"
-        target="_blank"
-      >Pro 首页</a>
-      <a
-        href="https://github.com/sendya/ant-design-pro-vue"
-        target="_blank"
-      >
-        <a-icon type="github" />
-      </a>
-      <a href="https://ant.design/">Ant Design</a>
-      <a href="https://vue.ant.design/">Vue Antd</a>
-    </div>
-    <div class="copyright">
-      Copyright
-      <a-icon type="copyright" /> 2018 <span>白鹭学园技术组出品</span>
-    </div>
-  </div>
-</template>
-
-<script>
-export default {
-  name: 'GlobalFooter',
-  data () {
-    return {}
-  }
-}
-</script>
-
-<style lang="less" scoped>
-.footer {
-  padding: 0 16px;
-  margin: 48px 0 24px;
-  text-align: center;
-
-  .links {
-    margin-bottom: 8px;
-
-    a {
-      color: rgba(0, 0, 0, 0.45);
-
-      &:hover {
-        color: rgba(0, 0, 0, 0.65);
-      }
-
-      &:not(:last-child) {
-        margin-right: 40px;
-      }
-    }
-  }
-  .copyright {
-    color: rgba(0, 0, 0, 0.45);
-    font-size: 14px;
-  }
-}
-</style>

+ 0 - 2
src/components/GlobalFooter/index.js

@@ -1,2 +0,0 @@
-import GlobalFooter from './GlobalFooter'
-export default GlobalFooter

+ 23 - 0
src/components/GlobalFooter/index.vue

@@ -0,0 +1,23 @@
+<template>
+  <global-footer class="footer custom-render">
+    <template v-slot:links>
+      <a href="https://www.github.com/vueComponent/pro-layout" target="_blank">Pro Layout</a>
+      <a href="https://www.github.com/vueComponent/ant-design-vue-pro" target="_blank">Github</a>
+      <a href="https://www.github.com/sendya/" target="_blank">@Sendya</a>
+    </template>
+    <template v-slot:copyright>
+      <a href="https://github.com/vueComponent" target="_blank">vueComponent</a>
+    </template>
+  </global-footer>
+</template>
+
+<script>
+import { GlobalFooter } from '@ant-design-vue/pro-layout'
+
+export default {
+  name: 'ProGlobalFooter',
+  components: {
+    GlobalFooter
+  }
+}
+</script>

+ 80 - 0
src/components/GlobalHeader/AvatarDropdown.vue

@@ -0,0 +1,80 @@
+<template>
+  <a-dropdown v-if="currentUser && currentUser.name" placement="bottomRight">
+    <span class="ant-pro-account-avatar">
+      <a-avatar size="small" src="https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png" class="antd-pro-global-header-index-avatar" />
+      <span>{{ currentUser.name }}</span>
+    </span>
+    <template v-slot:overlay>
+      <a-menu class="ant-pro-drop-down menu" :selected-keys="[]">
+        <a-menu-item v-if="menu" key="center" @click="handleToCenter">
+          <a-icon type="user" />
+          个人中心
+        </a-menu-item>
+        <a-menu-item v-if="menu" key="settings" @click="handleToSettings">
+          <a-icon type="setting" />
+          个人设置
+        </a-menu-item>
+        <a-menu-divider v-if="menu" />
+        <a-menu-item key="logout" @click="handleLogout">
+          <a-icon type="logout" />
+          退出登录
+        </a-menu-item>
+      </a-menu>
+    </template>
+  </a-dropdown>
+  <span v-else>
+    <a-spin size="small" :style="{ marginLeft: 8, marginRight: 8 }" />
+  </span>
+</template>
+
+<script>
+import { Modal } from 'ant-design-vue'
+
+export default {
+  name: 'AvatarDropdown',
+  props: {
+    currentUser: {
+      type: Object,
+      default: () => null
+    },
+    menu: {
+      type: Boolean,
+      default: true
+    }
+  },
+  methods: {
+    handleToCenter () {
+      this.$router.push({ path: '/account/center' })
+    },
+    handleToSettings () {
+      this.$router.push({ path: '/account/settings' })
+    },
+    handleLogout (e) {
+      Modal.confirm({
+        title: this.$t('layouts.usermenu.dialog.title'),
+        content: this.$t('layouts.usermenu.dialog.content'),
+        onOk: () => {
+          // return new Promise((resolve, reject) => {
+          //   setTimeout(Math.random() > 0.5 ? resolve : reject, 1500)
+          // }).catch(() => console.log('Oops errors!'))
+          return this.$store.dispatch('Logout').then(() => {
+            this.$router.push({ name: 'login' })
+          })
+        },
+        onCancel () {}
+      })
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.ant-pro-drop-down {
+  /deep/ .action {
+    margin-right: 8px;
+  }
+  /deep/ .ant-dropdown-menu-item {
+    min-width: 160px;
+  }
+}
+</style>

+ 0 - 125
src/components/GlobalHeader/GlobalHeader.vue

@@ -1,125 +0,0 @@
-<template>
-  <transition name="showHeader">
-    <div v-if="visible" class="header-animat">
-      <a-layout-header
-        v-if="visible"
-        :class="[fixedHeader && 'ant-header-fixedHeader', sidebarOpened ? 'ant-header-side-opened' : 'ant-header-side-closed', ]"
-        :style="{ padding: '0' }">
-        <div v-if="mode === 'sidemenu'" class="header">
-          <a-icon v-if="device==='mobile'" class="trigger" :type="collapsed ? 'menu-fold' : 'menu-unfold'" @click="toggle"/>
-          <a-icon v-else class="trigger" :type="collapsed ? 'menu-unfold' : 'menu-fold'" @click="toggle"/>
-          <user-menu></user-menu>
-        </div>
-        <div v-else :class="['top-nav-header-index', theme]">
-          <div class="header-index-wide">
-            <div class="header-index-left">
-              <logo class="top-nav-header" :show-title="device !== 'mobile'"/>
-              <s-menu v-if="device !== 'mobile'" mode="horizontal" :menu="menus" :theme="theme" />
-              <a-icon v-else class="trigger" :type="collapsed ? 'menu-fold' : 'menu-unfold'" @click="toggle" />
-            </div>
-            <user-menu class="header-index-right"></user-menu>
-          </div>
-        </div>
-      </a-layout-header>
-    </div>
-  </transition>
-</template>
-
-<script>
-import UserMenu from '../tools/UserMenu'
-import SMenu from '../Menu/'
-import Logo from '../tools/Logo'
-import { mixin } from '@/utils/mixin'
-
-export default {
-  name: 'GlobalHeader',
-  components: {
-    UserMenu,
-    SMenu,
-    Logo
-  },
-  mixins: [mixin],
-  props: {
-    mode: {
-      type: String,
-      // sidemenu, topmenu
-      default: 'sidemenu'
-    },
-    menus: {
-      type: Array,
-      required: true
-    },
-    theme: {
-      type: String,
-      required: false,
-      default: 'dark'
-    },
-    collapsed: {
-      type: Boolean,
-      required: false,
-      default: false
-    },
-    device: {
-      type: String,
-      required: false,
-      default: 'desktop'
-    }
-  },
-  data () {
-    return {
-      visible: true,
-      oldScrollTop: 0
-    }
-  },
-  mounted () {
-    document.addEventListener('scroll', this.handleScroll, { passive: true })
-  },
-  methods: {
-    handleScroll () {
-      if (!this.autoHideHeader) {
-        return
-      }
-
-      const scrollTop = document.body.scrollTop + document.documentElement.scrollTop
-      if (!this.ticking) {
-        this.ticking = true
-        requestAnimationFrame(() => {
-          if (this.oldScrollTop > scrollTop) {
-            this.visible = true
-          } else if (scrollTop > 300 && this.visible) {
-            this.visible = false
-          } else if (scrollTop < 300 && !this.visible) {
-            this.visible = true
-          }
-          this.oldScrollTop = scrollTop
-          this.ticking = false
-        })
-      }
-    },
-    toggle () {
-      this.$emit('toggle')
-    }
-  },
-  beforeDestroy () {
-    document.body.removeEventListener('scroll', this.handleScroll, true)
-  }
-}
-</script>
-
-<style lang="less">
-@import '../index.less';
-
-.header-animat{
-  position: relative;
-  z-index: @ant-global-header-zindex;
-}
-.showHeader-enter-active {
-  transition: all 0.25s ease;
-}
-.showHeader-leave-active {
-  transition: all 0.5s ease;
-}
-.showHeader-enter, .showHeader-leave-to {
-  opacity: 0;
-}
-</style>

+ 58 - 0
src/components/GlobalHeader/RightContent.vue

@@ -0,0 +1,58 @@
+<template>
+  <div :class="wrpCls">
+    <avatar-dropdown :menu="showMenu" :current-user="currentUser" :class="prefixCls" />
+    <select-lang :class="prefixCls" />
+  </div>
+</template>
+
+<script>
+import AvatarDropdown from './AvatarDropdown'
+import SelectLang from '@/components/SelectLang'
+
+export default {
+  name: 'RightContent',
+  components: {
+    AvatarDropdown,
+    SelectLang
+  },
+  props: {
+    prefixCls: {
+      type: String,
+      default: 'ant-pro-global-header-index-action'
+    },
+    isMobile: {
+      type: Boolean,
+      default: () => false
+    },
+    topMenu: {
+      type: Boolean,
+      required: true
+    },
+    theme: {
+      type: String,
+      required: true
+    }
+  },
+  data () {
+    return {
+      showMenu: true,
+      currentUser: {}
+    }
+  },
+  computed: {
+    wrpCls () {
+      return {
+        'ant-pro-global-header-index-right': true,
+        [`ant-pro-global-header-index-${(this.isMobile || !this.topMenu) ? 'light' : this.theme}`]: true
+      }
+    }
+  },
+  mounted () {
+    setTimeout(() => {
+      this.currentUser = {
+        name: 'Serati Ma'
+      }
+    }, 1500)
+  }
+}
+</script>

+ 0 - 2
src/components/GlobalHeader/index.js

@@ -1,2 +0,0 @@
-import GlobalHeader from './GlobalHeader'
-export default GlobalHeader

+ 0 - 64
src/components/Menu/SideMenu.vue

@@ -1,64 +0,0 @@
-<template>
-  <a-layout-sider
-    :class="['sider', isDesktop() ? null : 'shadow', theme, fixSiderbar ? 'ant-fixed-sidemenu' : null ]"
-    width="256px"
-    :collapsible="collapsible"
-    v-model="collapsed"
-    :trigger="null">
-    <logo />
-    <s-menu
-      :collapsed="collapsed"
-      :menu="menus"
-      :theme="theme"
-      :mode="mode"
-      @select="onSelect"
-      style="padding: 16px 0px;"></s-menu>
-    <!-- 广告代码 真实项目中请移除 -->
-    <ads v-if="!collapsed"/>
-  </a-layout-sider>
-
-</template>
-
-<script>
-import Logo from '@/components/tools/Logo'
-import SMenu from './index'
-import { mixin, mixinDevice } from '@/utils/mixin'
-import Ads from '@/components/Other/CarbonAds'
-
-export default {
-  name: 'SideMenu',
-  components: { Logo, SMenu, Ads },
-  mixins: [mixin, mixinDevice],
-  props: {
-    mode: {
-      type: String,
-      required: false,
-      default: 'inline'
-    },
-    theme: {
-      type: String,
-      required: false,
-      default: 'dark'
-    },
-    collapsible: {
-      type: Boolean,
-      required: false,
-      default: false
-    },
-    collapsed: {
-      type: Boolean,
-      required: false,
-      default: false
-    },
-    menus: {
-      type: Array,
-      required: true
-    }
-  },
-  methods: {
-    onSelect (obj) {
-      this.$emit('menuSelect', obj)
-    }
-  }
-}
-</script>

+ 0 - 2
src/components/Menu/index.js

@@ -1,2 +0,0 @@
-import SMenu from './menu'
-export default SMenu

+ 0 - 177
src/components/Menu/menu.js

@@ -1,177 +0,0 @@
-import Menu from 'ant-design-vue/es/menu'
-import Icon from 'ant-design-vue/es/icon'
-
-export default {
-  name: 'SMenu',
-  props: {
-    menu: {
-      type: Array,
-      required: true
-    },
-    theme: {
-      type: String,
-      required: false,
-      default: 'dark'
-    },
-    mode: {
-      type: String,
-      required: false,
-      default: 'inline'
-    },
-    collapsed: {
-      type: Boolean,
-      required: false,
-      default: false
-    }
-  },
-  data () {
-    return {
-      openKeys: [],
-      selectedKeys: [],
-      cachedOpenKeys: []
-    }
-  },
-  computed: {
-    rootSubmenuKeys: vm => {
-      const keys = []
-      vm.menu.forEach(item => keys.push(item.path))
-      return keys
-    }
-  },
-  mounted () {
-    this.updateMenu()
-  },
-  watch: {
-    collapsed (val) {
-      if (val) {
-        this.cachedOpenKeys = this.openKeys.concat()
-        this.openKeys = []
-      } else {
-        this.openKeys = this.cachedOpenKeys
-      }
-    },
-    $route: function () {
-      this.updateMenu()
-    }
-  },
-  methods: {
-    // select menu item
-    onOpenChange (openKeys) {
-      // 在水平模式下时执行,并且不再执行后续
-      if (this.mode === 'horizontal') {
-        this.openKeys = openKeys
-        return
-      }
-      // 非水平模式时
-      const latestOpenKey = openKeys.find(key => !this.openKeys.includes(key))
-      if (!this.rootSubmenuKeys.includes(latestOpenKey)) {
-        this.openKeys = openKeys
-      } else {
-        this.openKeys = latestOpenKey ? [latestOpenKey] : []
-      }
-    },
-    onSelect ({ item, key, selectedKeys }) {
-      this.selectedKeys = selectedKeys
-      this.$emit('select', { item, key, selectedKeys })
-    },
-    updateMenu () {
-      const routes = this.$route.matched.concat()
-      const { hidden } = this.$route.meta
-      if (routes.length >= 3 && hidden) {
-        routes.pop()
-        this.selectedKeys = [routes[routes.length - 1].path]
-      } else {
-        this.selectedKeys = [routes.pop().path]
-      }
-      const openKeys = []
-      if (this.mode === 'inline') {
-        routes.forEach(item => {
-          openKeys.push(item.path)
-        })
-      }
-
-      this.collapsed ? (this.cachedOpenKeys = openKeys) : (this.openKeys = openKeys)
-    },
-
-    // render
-    renderItem (menu) {
-      if (!menu.hidden) {
-        return menu.children && !menu.hideChildrenInMenu ? this.renderSubMenu(menu) : this.renderMenuItem(menu)
-      }
-      return null
-    },
-    renderMenuItem (menu) {
-      const target = menu.meta.target || null
-      const CustomTag = target && 'a' || 'router-link'
-      const props = { to: { name: menu.name } }
-      const attrs = { href: menu.path, target: menu.meta.target }
-
-      if (menu.children && menu.hideChildrenInMenu) {
-        // 把有子菜单的 并且 父菜单是要隐藏子菜单的
-        // 都给子菜单增加一个 hidden 属性
-        // 用来给刷新页面时, selectedKeys 做控制用
-        menu.children.forEach(item => {
-          item.meta = Object.assign(item.meta, { hidden: true })
-        })
-      }
-
-      return (
-        <Menu.Item {...{ key: menu.path }}>
-          <CustomTag {...{ props, attrs }}>
-            {this.renderIcon(menu.meta.icon)}
-            <span>{menu.meta.title}</span>
-          </CustomTag>
-        </Menu.Item>
-      )
-    },
-    renderSubMenu (menu) {
-      const itemArr = []
-      if (!menu.hideChildrenInMenu) {
-        menu.children.forEach(item => itemArr.push(this.renderItem(item)))
-      }
-      return (
-        <Menu.SubMenu {...{ key: menu.path }}>
-          <span slot="title">
-            {this.renderIcon(menu.meta.icon)}
-            <span>{menu.meta.title}</span>
-          </span>
-          {itemArr}
-        </Menu.SubMenu>
-      )
-    },
-    renderIcon (icon) {
-      if (icon === 'none' || icon === undefined) {
-        return null
-      }
-      const props = {}
-      typeof (icon) === 'object' ? props.component = icon : props.type = icon
-      return (
-        <Icon {... { props } }/>
-      )
-    }
-  },
-
-  render () {
-    const dynamicProps = {
-      props: {
-        mode: this.mode,
-        theme: this.theme,
-        openKeys: this.openKeys,
-        selectedKeys: this.selectedKeys
-      },
-      on: {
-        openChange: this.onOpenChange,
-        select: this.onSelect
-      }
-    }
-
-    const menuTree = this.menu.map(item => {
-      if (item.hidden) {
-        return null
-      }
-      return this.renderItem(item)
-    })
-
-    return (<Menu {...dynamicProps}>{menuTree}</Menu>)
-  }
-}

+ 0 - 156
src/components/Menu/menu.render.js

@@ -1,156 +0,0 @@
-import Menu from 'ant-design-vue/es/menu'
-import Icon from 'ant-design-vue/es/icon'
-
-const { Item, SubMenu } = Menu
-
-export default {
-  name: 'SMenu',
-  props: {
-    menu: {
-      type: Array,
-      required: true
-    },
-    theme: {
-      type: String,
-      required: false,
-      default: 'dark'
-    },
-    mode: {
-      type: String,
-      required: false,
-      default: 'inline'
-    },
-    collapsed: {
-      type: Boolean,
-      required: false,
-      default: false
-    }
-  },
-  data () {
-    return {
-      openKeys: [],
-      selectedKeys: [],
-      cachedOpenKeys: []
-    }
-  },
-  computed: {
-    rootSubmenuKeys: vm => {
-      const keys = []
-      vm.menu.forEach(item => keys.push(item.path))
-      return keys
-    }
-  },
-  created () {
-    this.updateMenu()
-  },
-  watch: {
-    collapsed (val) {
-      if (val) {
-        this.cachedOpenKeys = this.openKeys.concat()
-        this.openKeys = []
-      } else {
-        this.openKeys = this.cachedOpenKeys
-      }
-    },
-    $route: function () {
-      this.updateMenu()
-    }
-  },
-  methods: {
-    renderIcon: function (h, icon) {
-      if (icon === 'none' || icon === undefined) {
-        return null
-      }
-      const props = {}
-      typeof (icon) === 'object' ? props.component = icon : props.type = icon
-      return h(Icon, { props: { ...props } })
-    },
-    renderMenuItem: function (h, menu, pIndex, index) {
-      const target = menu.meta.target || null
-      return h(Item, { key: menu.path ? menu.path : 'item_' + pIndex + '_' + index }, [
-        h('router-link', { attrs: { to: { name: menu.name }, target: target } }, [
-          this.renderIcon(h, menu.meta.icon),
-          h('span', [menu.meta.title])
-        ])
-      ])
-    },
-    renderSubMenu: function (h, menu, pIndex, index) {
-      const this2_ = this
-      const subItem = [h('span', { slot: 'title' }, [this.renderIcon(h, menu.meta.icon), h('span', [menu.meta.title])])]
-      const itemArr = []
-      const pIndex_ = pIndex + '_' + index
-      console.log('menu', menu)
-      if (!menu.hideChildrenInMenu) {
-        menu.children.forEach(function (item, i) {
-          itemArr.push(this2_.renderItem(h, item, pIndex_, i))
-        })
-      }
-      return h(SubMenu, { key: menu.path ? menu.path : 'submenu_' + pIndex + '_' + index }, subItem.concat(itemArr))
-    },
-    renderItem: function (h, menu, pIndex, index) {
-      if (!menu.hidden) {
-        return menu.children && !menu.hideChildrenInMenu
-          ? this.renderSubMenu(h, menu, pIndex, index)
-          : this.renderMenuItem(h, menu, pIndex, index)
-      }
-    },
-    renderMenu: function (h, menuTree) {
-      const this2_ = this
-      const menuArr = []
-      menuTree.forEach(function (menu, i) {
-        if (!menu.hidden) {
-          menuArr.push(this2_.renderItem(h, menu, '0', i))
-        }
-      })
-      return menuArr
-    },
-    onOpenChange (openKeys) {
-      const latestOpenKey = openKeys.find(key => !this.openKeys.includes(key))
-      if (!this.rootSubmenuKeys.includes(latestOpenKey)) {
-        this.openKeys = openKeys
-      } else {
-        this.openKeys = latestOpenKey ? [latestOpenKey] : []
-      }
-    },
-    updateMenu () {
-      const routes = this.$route.matched.concat()
-
-      if (routes.length >= 4 && this.$route.meta.hidden) {
-        routes.pop()
-        this.selectedKeys = [routes[2].path]
-      } else {
-        this.selectedKeys = [routes.pop().path]
-      }
-
-      const openKeys = []
-      if (this.mode === 'inline') {
-        routes.forEach(item => {
-          openKeys.push(item.path)
-        })
-      }
-
-      this.collapsed ? (this.cachedOpenKeys = openKeys) : (this.openKeys = openKeys)
-    }
-  },
-  render (h) {
-    return h(
-      Menu,
-      {
-        props: {
-          theme: this.$props.theme,
-          mode: this.$props.mode,
-          openKeys: this.openKeys,
-          selectedKeys: this.selectedKeys
-        },
-        on: {
-          openChange: this.onOpenChange,
-          select: obj => {
-            this.selectedKeys = obj.selectedKeys
-            this.$emit('select', obj)
-          }
-        }
-      },
-      this.renderMenu(h, this.menu)
-    )
-  }
-}

+ 1 - 1
src/components/Other/CarbonAds.vue

@@ -57,7 +57,7 @@ export default {
   bottom: 0;
   padding: 0;
   overflow: hidden;
-  z-index: 9;
+  z-index: 100;
   background-color: #fff;
   /* border-radius: 3px; */
   font-size: 13px;

+ 0 - 202
src/components/PageHeader/PageHeader.vue

@@ -1,202 +0,0 @@
-<template>
-  <div class="page-header">
-    <div class="page-header-index-wide">
-      <s-breadcrumb />
-      <div class="detail">
-        <div class="main" v-if="!$route.meta.hiddenHeaderContent">
-          <div class="row">
-            <img v-if="logo" :src="logo" class="logo"/>
-            <h1 v-if="title" class="title">{{ title }}</h1>
-            <div class="action">
-              <slot name="action"></slot>
-            </div>
-          </div>
-          <div class="row">
-            <div v-if="avatar" class="avatar">
-              <a-avatar :src="avatar" />
-            </div>
-            <div v-if="this.$slots.content" class="headerContent">
-              <slot name="content"></slot>
-            </div>
-            <div v-if="this.$slots.extra" class="extra">
-              <slot name="extra"></slot>
-            </div>
-          </div>
-          <div>
-            <slot name="pageMenu"></slot>
-          </div>
-        </div>
-      </div>
-    </div>
-  </div>
-</template>
-
-<script>
-import Breadcrumb from '@/components/tools/Breadcrumb'
-
-export default {
-  name: 'PageHeader',
-  components: {
-    's-breadcrumb': Breadcrumb
-  },
-  props: {
-    title: {
-      type: [String, Boolean],
-      default: true,
-      required: false
-    },
-    logo: {
-      type: String,
-      default: '',
-      required: false
-    },
-    avatar: {
-      type: String,
-      default: '',
-      required: false
-    }
-  },
-  data () {
-    return {}
-  }
-}
-</script>
-
-<style lang="less" scoped>
-.page-header {
-  background: #fff;
-  padding: 16px 32px 0;
-  border-bottom: 1px solid #e8e8e8;
-
-  .breadcrumb {
-    margin-bottom: 16px;
-  }
-
-  .detail {
-    display: flex;
-    /*margin-bottom: 16px;*/
-
-    .avatar {
-      flex: 0 1 72px;
-      margin: 0 24px 8px 0;
-
-      & > span {
-        border-radius: 72px;
-        display: block;
-        width: 72px;
-        height: 72px;
-      }
-    }
-
-    .main {
-      width: 100%;
-      flex: 0 1 auto;
-
-      .row {
-        display: flex;
-        width: 100%;
-
-        .avatar {
-          margin-bottom: 16px;
-        }
-      }
-
-      .title {
-        font-size: 20px;
-        font-weight: 500;
-
-        font-size: 20px;
-        line-height: 28px;
-        font-weight: 500;
-        color: rgba(0, 0, 0, 0.85);
-        margin-bottom: 16px;
-        flex: auto;
-      }
-      .logo {
-        width: 28px;
-        height: 28px;
-        border-radius: 4px;
-        margin-right: 16px;
-      }
-      .content,
-      .headerContent {
-        flex: auto;
-        color: rgba(0, 0, 0, 0.45);
-        line-height: 22px;
-
-        .link {
-          margin-top: 16px;
-          line-height: 24px;
-
-          a {
-            font-size: 14px;
-            margin-right: 32px;
-          }
-        }
-      }
-      .extra {
-        flex: 0 1 auto;
-        margin-left: 88px;
-        min-width: 242px;
-        text-align: right;
-      }
-      .action {
-        margin-left: 56px;
-        min-width: 266px;
-        flex: 0 1 auto;
-        text-align: right;
-        &:empty {
-          display: none;
-        }
-      }
-    }
-  }
-}
-
-.mobile .page-header {
-  .main {
-    .row {
-      flex-wrap: wrap;
-
-      .avatar {
-        flex: 0 1 25%;
-        margin: 0 2% 8px 0;
-      }
-
-      .content,
-      .headerContent {
-        flex: 0 1 70%;
-
-        .link {
-          margin-top: 16px;
-          line-height: 24px;
-
-          a {
-            font-size: 14px;
-            margin-right: 10px;
-          }
-        }
-      }
-
-      .extra {
-        flex: 1 1 auto;
-        margin-left: 0;
-        min-width: 0;
-        text-align: right;
-      }
-
-      .action {
-        margin-left: unset;
-        min-width: 266px;
-        flex: 0 1 auto;
-        text-align: left;
-        margin-bottom: 12px;
-
-        &:empty {
-          display: none;
-        }
-      }
-    }
-  }
-}
-</style>

+ 0 - 2
src/components/PageHeader/index.js

@@ -1,2 +0,0 @@
-import PageHeader from './PageHeader'
-export default PageHeader

+ 0 - 109
src/components/Result/Result.vue

@@ -1,109 +0,0 @@
-<template>
-  <div class="result">
-    <div>
-      <a-icon :class="{ 'icon': true, [`${type}`]: true }" :type="localIsSuccess ? 'check-circle' : 'close-circle'"/>
-    </div>
-    <div class="title">
-      <slot name="title">
-        {{ title }}
-      </slot>
-    </div>
-    <div class="description">
-      <slot name="description">
-        {{ description }}
-      </slot>
-    </div>
-    <div class="extra" v-if="$slots.default">
-      <slot></slot>
-    </div>
-    <div class="action" v-if="$slots.action">
-      <slot name="action"></slot>
-    </div>
-  </div>
-</template>
-
-<script>
-const resultEnum = ['success', 'error']
-
-export default {
-  name: 'Result',
-  props: {
-    /** @Deprecated */
-    isSuccess: {
-      type: Boolean,
-      default: false
-    },
-    type: {
-      type: String,
-      default: resultEnum[0],
-      validator (val) {
-        return (val) => resultEnum.includes(val)
-      }
-    },
-    title: {
-      type: String,
-      default: ''
-    },
-    description: {
-      type: String,
-      default: ''
-    }
-  },
-  computed: {
-    localIsSuccess: function () {
-      return this.type === resultEnum[0]
-    }
-  }
-}
-</script>
-
-<style lang="less" scoped>
-  .result {
-    text-align: center;
-    width: 72%;
-    margin: 0 auto;
-    padding: 24px 0 8px;
-
-    .icon {
-      font-size: 72px;
-      line-height: 72px;
-      margin-bottom: 24px;
-    }
-    .success {
-      color: #52c41a;
-    }
-    .error {
-      color: red;
-    }
-    .title {
-      font-size: 24px;
-      color: rgba(0, 0, 0, .85);
-      font-weight: 500;
-      line-height: 32px;
-      margin-bottom: 16px;
-    }
-    .description {
-      font-size: 14px;
-      line-height: 22px;
-      color: rgba(0, 0, 0, 0.45);
-      margin-bottom: 24px;
-    }
-    .extra {
-      background: #fafafa;
-      padding: 24px 40px;
-      border-radius: 2px;
-      text-align: left;
-    }
-    .action {
-      margin-top: 32px;
-    }
-  }
-
-  .mobile {
-    .result {
-      width: 100%;
-      margin: 0 auto;
-      padding: unset;
-    }
-  }
-</style>

+ 0 - 2
src/components/Result/index.js

@@ -1,2 +0,0 @@
-import Result from './Result.vue'
-export default Result

+ 58 - 0
src/components/SelectLang/index.jsx

@@ -0,0 +1,58 @@
+import './index.less'
+
+import { Icon, Menu, Dropdown } from 'ant-design-vue'
+import { i18nRender } from '@/locales'
+import i18nMixin from '@/store/i18n-mixin'
+
+const locales = ['zh-CN', 'zh-TW', 'en-US', 'pt-BR']
+const languageLabels = {
+  'zh-CN': '简体中文',
+  'zh-TW': '繁体中文',
+  'en-US': 'English',
+  'pt-BR': 'Português'
+}
+// eslint-disable-next-line
+const languageIcons = {
+  'zh-CN': '🇨🇳',
+  'zh-TW': '🇭🇰',
+  'en-US': '🇺🇸',
+  'pt-BR': '🇧🇷'
+}
+
+const SelectLang = {
+  props: {
+    prefixCls: {
+      type: String,
+      default: 'ant-pro-drop-down'
+    }
+  },
+  name: 'SelectLang',
+  mixins: [i18nMixin],
+  render () {
+    const { prefixCls } = this
+    const changeLang = ({ key }) => {
+      this.setLang(key)
+    }
+    const langMenu = (
+      <Menu class={['menu', 'ant-pro-header-menu']} selectedKeys={[this.currentLang]} 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 (
+      <Dropdown overlay={langMenu} placement="bottomRight">
+        <span class={prefixCls}>
+          <Icon type="global" title={i18nRender('navBar.lang')} />
+        </span>
+      </Dropdown>
+    )
+  }
+}
+
+export default SelectLang

+ 31 - 0
src/components/SelectLang/index.less

@@ -0,0 +1,31 @@
+@import "~ant-design-vue/es/style/themes/default";
+
+@header-menu-prefix-cls: ~'@{ant-prefix}-pro-header-menu';
+@header-drop-down-prefix-cls: ~'@{ant-prefix}-pro-drop-down';
+
+.@{header-menu-prefix-cls} {
+
+  .anticon {
+    margin-right: 8px;
+  }
+  .ant-dropdown-menu-item {
+    min-width: 160px;
+  }
+}
+
+.@{header-drop-down-prefix-cls} {
+
+  line-height: @layout-header-height;
+  vertical-align: top;
+  cursor: pointer;
+
+  > i {
+    font-size: 16px !important;
+    transform: none !important;
+
+    svg {
+      position: relative;
+      top: -1px;
+    }
+  }
+}

+ 2 - 11
src/components/SettingDrawer/SettingDrawer.vue

@@ -171,18 +171,15 @@
 </template>
 
 <script>
-import { DetailList } from '@/components'
 import SettingItem from './SettingItem'
 import config from '@/config/defaultSettings'
 import { updateTheme, updateColorWeak, colorList } from './settingConfig'
-import { mixin, mixinDevice } from '@/utils/mixin'
 
 export default {
   components: {
-    DetailList,
     SettingItem
   },
-  mixins: [mixin, mixinDevice],
+  mixins: [],
   data () {
     return {
       visible: false,
@@ -230,13 +227,7 @@ export default {
   autoHideHeader: ${this.autoHideHeader}, //  auto hide header
   colorWeak: ${this.colorWeak},
   multiTab: ${this.multiTab},
-  production: process.env.NODE_ENV === 'production' && process.env.VUE_APP_PREVIEW !== 'true',
-  // vue-ls options
-  storageOptions: {
-    namespace: 'pro__',
-    name: 'ls',
-    storage: 'local',
-  }
+  production: process.env.NODE_ENV === 'production' && process.env.VUE_APP_PREVIEW !== 'true'
 }`
       this.$copyText(text).then(message => {
         console.log('copy', message)

+ 2 - 62
src/components/SettingDrawer/settingConfig.js

@@ -1,9 +1,8 @@
-import { message } from 'ant-design-vue/es'
+import message from 'ant-design-vue/es/message'
 // import defaultSettings from '../defaultSettings';
 import themeColor from './themeColor.js'
 
 // let lessNodesAppended
-
 const colorList = [
   {
     key: '薄暮', color: '#F5222D'
@@ -33,72 +32,13 @@ const colorList = [
 
 const updateTheme = newPrimaryColor => {
   const hideMessage = message.loading('正在切换主题!', 0)
-  themeColor.changeColor(newPrimaryColor).finally(t => {
+  themeColor.changeColor(newPrimaryColor).finally(() => {
     setTimeout(() => {
       hideMessage()
     }, 10)
   })
 }
 
-/*
-const updateTheme = primaryColor => {
-  // Don't compile less in production!
-  /* if (process.env.NODE_ENV === 'production') {
-    return;
-  } * /
-  // Determine if the component is remounted
-  if (!primaryColor) {
-    return
-  }
-  const hideMessage = message.loading('正在编译主题!', 0)
-  function buildIt () {
-    if (!window.less) {
-      return
-    }
-    setTimeout(() => {
-      window.less
-        .modifyVars({
-          '@primary-color': primaryColor
-        })
-        .then(() => {
-          hideMessage()
-        })
-        .catch(() => {
-          message.error('Failed to update theme')
-          hideMessage()
-        })
-    }, 200)
-  }
-  if (!lessNodesAppended) {
-    // insert less.js and color.less
-    const lessStyleNode = document.createElement('link')
-    const lessConfigNode = document.createElement('script')
-    const lessScriptNode = document.createElement('script')
-    lessStyleNode.setAttribute('rel', 'stylesheet/less')
-    lessStyleNode.setAttribute('href', '/color.less')
-    lessConfigNode.innerHTML = `
-      window.less = {
-        async: true,
-        env: 'production',
-        javascriptEnabled: true
-      };
-    `
-    lessScriptNode.src = 'https://gw.alipayobjects.com/os/lib/less.js/3.8.1/less.min.js'
-    lessScriptNode.async = true
-    lessScriptNode.onload = () => {
-      buildIt()
-      lessScriptNode.onload = null
-    }
-    document.body.appendChild(lessStyleNode)
-    document.body.appendChild(lessConfigNode)
-    document.body.appendChild(lessScriptNode)
-    lessNodesAppended = true
-  } else {
-    buildIt()
-  }
-}
-*/
-
 const updateColorWeak = colorWeak => {
   // document.body.className = colorWeak ? 'colorWeak' : '';
   const app = document.body.querySelector('#app')

+ 4 - 4
src/components/Table/index.js

@@ -85,6 +85,10 @@ export default {
           pageNo: val
         })
       })
+      // change pagination, reset total data
+      this.needTotalList = this.initTotalList(this.columns)
+      this.selectedRowKeys = []
+      this.selectedRows = []
     },
     pageNum (val) {
       Object.assign(this.localPagination, {
@@ -110,7 +114,6 @@ export default {
       pageSize: this.pageSize,
       showSizeChanger: this.showSizeChanger
     }) || false
-    console.log('this.localPagination', this.localPagination)
     this.needTotalList = this.initTotalList(this.columns)
     this.loadData()
   },
@@ -149,7 +152,6 @@ export default {
         ...filters
       }
       )
-      console.log('parameter', parameter)
       const result = this.data(parameter)
       // 对接自己的通用数据接口需要修改下方代码中的 r.pageNo, r.totalCount, r.data
       // eslint-disable-next-line
@@ -178,7 +180,6 @@ export default {
           } catch (e) {
             this.localPagination = false
           }
-          console.log('loadData -> this.localPagination', this.localPagination)
           this.localDataSource = r.data // 返回结果中的数组数据
           this.localLoading = false
         })
@@ -280,7 +281,6 @@ export default {
       if (k === 'rowSelection') {
         if (showAlert && this.rowSelection) {
           // 如果需要使用alert,则重新绑定 rowSelection 事件
-          console.log('this.rowSelection', this.rowSelection)
           props[k] = {
             ...this.rowSelection,
             selectedRows: this.selectedRows,

+ 0 - 515
src/components/global.less

@@ -1,515 +0,0 @@
-@import './index.less';
-
-body {
-
-
-}
-
-#app {
-  height: 100%;
-
-  &.colorWeak {
-    filter: invert(80%);
-  }
-  &.userLayout {
-    overflow: auto;
-  }
-}
-
-.layout.ant-layout {
-  height: auto;
-  overflow-x: hidden;
-
-  &.mobile,
-  &.tablet {
-    .ant-layout-content {
-      .content {
-        margin: 24px 0 0;
-      }
-    }
-
-    /**
-     * ant-table-wrapper
-     * 覆盖的表格手机模式样式,如果想修改在手机上表格最低宽度,可以在这里改动
-     */
-    .ant-table-wrapper {
-      .ant-table-content {
-        overflow-y: auto;
-      }
-      .ant-table-body {
-        min-width: 800px;
-      }
-    }
-    .topmenu {
-      /* 必须为 topmenu  才能启用流式布局 */
-      &.content-width-Fluid {
-        .header-index-wide {
-          margin-left: 0;
-        }
-      }
-    }
-  }
-
-  &.mobile {
-    .sidemenu {
-      .ant-header-fixedHeader {
-        &.ant-header-side-opened,
-        &.ant-header-side-closed {
-          width: 100%;
-        }
-      }
-    }
-  }
-
-  &.ant-layout-has-sider {
-    flex-direction: row;
-  }
-
-  .trigger {
-    font-size: 20px;
-    line-height: 64px;
-    padding: 0 24px;
-    cursor: pointer;
-    transition: color 0.3s;
-    &:hover {
-      background: rgba(0, 0, 0, 0.025);
-    }
-  }
-
-  .topmenu {
-    .ant-header-fixedHeader {
-      position: fixed;
-      top: 0;
-      right: 0;
-      z-index: 9;
-      width: 100%;
-      transition: width 0.2s;
-
-      &.ant-header-side-opened {
-        width: 100%;
-      }
-
-      &.ant-header-side-closed {
-        width: 100%;
-      }
-    }
-    /* 必须为 topmenu  才能启用流式布局 */
-    &.content-width-Fluid {
-      .header-index-wide {
-        max-width: unset;
-        .header-index-left {
-          flex: 1 1 1000px;
-          .logo{
-            margin-left: 25px;
-          }
-          .ant-menu.ant-menu-horizontal{
-            max-width: calc(100vw - 190px - 238px - 25px);
-            flex: 1 1 calc(100vw - 190px - 238px - 25px);
-          }
-        }
-        .header-index-right{
-          margin-right:25px;
-        }
-      }
-
-      .page-header-index-wide {
-        max-width: unset;
-      }
-    }
-  }
-
-  .sidemenu {
-    .ant-header-fixedHeader {
-      position: fixed;
-      top: 0;
-      right: 0;
-      z-index: 9;
-      width: 100%;
-      transition: width 0.2s;
-
-      &.ant-header-side-opened {
-        width: calc(100% - 256px);
-      }
-
-      &.ant-header-side-closed {
-        width: calc(100% - 80px);
-      }
-    }
-  }
-
-  .header {
-    height: 64px;
-    padding: 0 12px 0 0;
-    background: #fff;
-    box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
-    position: relative;
-  }
-
-  .header,
-  .top-nav-header-index {
-    .user-wrapper {
-      float: right;
-      height: 100%;
-
-      .action {
-        cursor: pointer;
-        padding: 0 12px;
-        display: inline-block;
-        transition: all 0.3s;
-        height: 100%;
-        color: rgba(0, 0, 0, 0.65);
-
-        &:hover {
-          background: rgba(0, 0, 0, 0.025);
-        }
-
-        .avatar {
-          margin: 20px 8px 20px 0;
-          color: #1890ff;
-          background: hsla(0, 0%, 100%, 0.85);
-          vertical-align: middle;
-        }
-
-        .icon {
-          font-size: 16px;
-          padding: 4px;
-        }
-      }
-    }
-
-    &.dark {
-      .user-wrapper {
-        .action {
-          color: rgba(255, 255, 255, 0.85);
-          a {
-            color: rgba(255, 255, 255, 0.85);
-          }
-
-          &:hover {
-            background: rgba(255, 255, 255, 0.16);
-          }
-        }
-      }
-    }
-  }
-
-  &.mobile,
-  &.tablet {
-    .top-nav-header-index {
-      .header-index-wide {
-        .header-index-left {
-          .trigger {
-            color: rgba(255, 255, 255, 0.85);
-            padding: 0 12px;
-          }
-
-          .logo.top-nav-header {
-            flex: 0 0 56px;
-            text-align: center;
-            line-height: 58px;
-            h1 {
-              display: none;
-            }
-          }
-        }
-      }
-
-      &.light {
-        .header-index-wide {
-          .header-index-left {
-            .trigger {
-              color: rgba(0, 0, 0, 0.65);
-            }
-          }
-        }
-        //
-      }
-    }
-  }
-
-  &.tablet {
-    // overflow: hidden; text-overflow:ellipsis; white-space: nowrap;
-    .top-nav-header-index {
-      .header-index-wide {
-        .header-index-left {
-          .logo > a {
-            overflow: hidden;
-            text-overflow: ellipsis;
-            white-space: nowrap;
-          }
-        }
-        .ant-menu.ant-menu-horizontal {
-          flex: 1 1 auto;
-          white-space: normal;
-        }
-      }
-    }
-  }
-
-  .top-nav-header-index {
-    box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
-    position: relative;
-    transition: background 0.3s, width 0.2s;
-
-    .header-index-wide {
-      max-width: 1200px;
-      margin: auto;
-      padding-left: 0;
-      display: flex;
-      height: 64px;
-
-      .ant-menu.ant-menu-horizontal {
-        max-width: 835px;
-        flex: 0 1 835px;
-        border: none;
-        height: 64px;
-        line-height: 64px;
-      }
-
-      .header-index-left {
-        flex: 0 1 1000px;
-        display: flex;
-
-        .logo.top-nav-header {
-          flex: 0 0 165px;
-          width: 165px;
-          height: 64px;
-          position: relative;
-          line-height: 64px;
-          transition: all 0.3s;
-          overflow: hidden;
-
-          img,
-          svg {
-            display: inline-block;
-            vertical-align: middle;
-            height: 32px;
-            width: 32px;
-          }
-
-          h1 {
-            color: #fff;
-            display: inline-block;
-            vertical-align: top;
-            font-size: 16px;
-            margin: 0 0 0 12px;
-            font-weight: 400;
-          }
-        }
-      }
-
-      .header-index-right {
-        flex: 0 0 238px;
-        align-self: flex-end;
-        height: 64px;
-        overflow: hidden;
-
-        .content-box {
-          float: right;
-          .action {
-            max-width: 140px;
-            overflow: hidden;
-            text-overflow:ellipsis;
-            white-space:nowrap;
-          }
-        }
-      }
-    }
-
-    &.light {
-      background-color: #fff;
-
-      .header-index-wide {
-        .header-index-left {
-          .logo {
-            h1 {
-              color: #002140;
-            }
-          }
-        }
-      }
-    }
-  }
-
-  // 内容区
-  .layout-content {
-    margin: 24px 24px 0px;
-    height: 100%;
-    height: 64px;
-    padding: 0 12px 0 0;
-  }
-
-  // footer
-  .ant-layout-footer {
-    padding: 0;
-  }
-}
-
-.topmenu {
-  .page-header-index-wide {
-    max-width: 1200px;
-    margin: 0 auto;
-  }
-}
-
-// drawer-sider 自定义
-.ant-drawer.drawer-sider {
-  .sider {
-    box-shadow: none;
-  }
-
-  &.dark {
-    .ant-drawer-content {
-      background-color: rgb(0, 21, 41);
-    }
-  }
-  &.light {
-    box-shadow: none;
-    .ant-drawer-content {
-      background-color: #fff;
-    }
-  }
-
-  .ant-drawer-body {
-    padding: 0;
-  }
-}
-
-// 菜单样式
-.sider {
-  box-shadow: 2px 0 6px rgba(0, 21, 41, 0.35);
-  position: relative;
-  z-index: @ant-global-sider-zindex;
-  min-height: 100vh;
-
-  .ant-layout-sider-children {
-    overflow-y: hidden;
-
-    &:hover {
-      overflow-y: auto;
-    }
-  }
-
-  &.ant-fixed-sidemenu {
-    position: fixed;
-    height: 100%;
-  }
-
-  .logo {
-    position: relative;
-    height: 64px;
-    padding-left: 24px;
-    overflow: hidden;
-    line-height: 64px;
-    background: #002140;
-    transition: all .3s;
-
-    img,
-    svg,
-    h1 {
-      display: inline-block;
-      vertical-align: middle;
-    }
-
-    img,
-    svg {
-      height: 32px;
-      width: 32px;
-    }
-
-    h1 {
-      color: #fff;
-      font-size: 20px;
-      margin: 0 0 0 12px;
-      font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif;
-      font-weight: 600;
-      vertical-align: middle;
-    }
-  }
-
-  &.light {
-    background-color: #fff;
-    box-shadow: 2px 0px 8px 0px rgba(29, 35, 41, 0.05);
-
-    .logo {
-      background: #fff;
-      box-shadow: 1px 1px 0px 0px #e8e8e8;
-
-      h1 {
-        color: unset;
-      }
-    }
-
-    .ant-menu-light {
-      border-right-color: transparent;
-    }
-  }
-}
-
-// 外置的样式控制
-.user-dropdown-menu {
-  span {
-    user-select: none;
-  }
-}
-.user-dropdown-menu-wrapper.ant-dropdown-menu {
-  padding: 4px 0;
-
-  .ant-dropdown-menu-item {
-    width: 160px;
-  }
-
-  .ant-dropdown-menu-item > .anticon:first-child,
-  .ant-dropdown-menu-item > a > .anticon:first-child,
-  .ant-dropdown-menu-submenu-title > .anticon:first-child .ant-dropdown-menu-submenu-title > a > .anticon:first-child {
-    min-width: 12px;
-    margin-right: 8px;
-  }
-}
-
-// 数据列表 样式
-.table-alert {
-  margin-bottom: 16px;
-}
-
-.table-page-search-wrapper {
-  .ant-form-inline {
-    .ant-form-item {
-      display: flex;
-      margin-bottom: 24px;
-      margin-right: 0;
-
-      .ant-form-item-control-wrapper {
-        flex: 1 1;
-        display: inline-block;
-        vertical-align: middle;
-      }
-
-      > .ant-form-item-label {
-        line-height: 32px;
-        padding-right: 8px;
-        width: auto;
-      }
-      .ant-form-item-control {
-        height: 32px;
-        line-height: 32px;
-      }
-    }
-  }
-
-  .table-page-search-submitButtons {
-    display: block;
-    margin-bottom: 24px;
-    white-space: nowrap;
-  }
-}
-
-.content {
-  .table-operator {
-    margin-bottom: 18px;
-
-    button {
-      margin-right: 8px;
-    }
-  }
-}

+ 0 - 10
src/components/index.js

@@ -13,19 +13,15 @@ import TagCloud from '@/components/Charts/TagCloud'
 
 // pro components
 import AvatarList from '@/components/AvatarList'
-import CountDown from '@/components/CountDown'
 import Ellipsis from '@/components/Ellipsis'
 import FooterToolbar from '@/components/FooterToolbar'
 import NumberInfo from '@/components/NumberInfo'
-import DescriptionList from '@/components/DescriptionList'
 import Tree from '@/components/Tree/Tree'
 import Trend from '@/components/Trend'
 import STable from '@/components/Table'
 import MultiTab from '@/components/MultiTab'
-import Result from '@/components/Result'
 import IconSelector from '@/components/IconSelector'
 import TagSelect from '@/components/TagSelect'
-import ExceptionPage from '@/components/Exception'
 import StandardFormRow from '@/components/StandardFormRow'
 import ArticleListContent from '@/components/ArticleListContent'
 
@@ -45,18 +41,12 @@ export {
   RankList,
   TransferBar,
   Trend,
-  CountDown,
   Ellipsis,
   FooterToolbar,
   NumberInfo,
-  DescriptionList,
-  // 兼容写法,请勿继续使用
-  DescriptionList as DetailList,
   Tree,
   STable,
   MultiTab,
-  Result,
-  ExceptionPage,
   IconSelector,
   TagSelect,
   StandardFormRow,

+ 0 - 45
src/components/tools/Breadcrumb.vue

@@ -1,45 +0,0 @@
-<template>
-  <a-breadcrumb class="breadcrumb">
-    <a-breadcrumb-item v-for="(item, index) in breadList" :key="item.name">
-      <router-link
-        v-if="item.name != name && index != 1"
-        :to="{ path: item.path === '' ? '/' : item.path }"
-      >{{ item.meta.title }}</router-link>
-      <span v-else>{{ item.meta.title }}</span>
-    </a-breadcrumb-item>
-  </a-breadcrumb>
-</template>
-
-<script>
-export default {
-  data () {
-    return {
-      name: '',
-      breadList: []
-    }
-  },
-  created () {
-    this.getBreadcrumb()
-  },
-  methods: {
-    getBreadcrumb () {
-      this.breadList = []
-      // this.breadList.push({name: 'index', path: '/dashboard/', meta: {title: '首页'}})
-
-      this.name = this.$route.name
-      this.$route.matched.forEach(item => {
-        // item.name !== 'index' && this.breadList.push(item)
-        this.breadList.push(item)
-      })
-    }
-  },
-  watch: {
-    $route () {
-      this.getBreadcrumb()
-    }
-  }
-}
-</script>
-
-<style scoped>
-</style>

+ 0 - 5
src/components/tools/DetailList.vue

@@ -1,5 +0,0 @@
-<script>
-/* WARNING: 兼容老引入,请勿继续使用 */
-import DescriptionList from '@/components/DescriptionList'
-export default DescriptionList
-</script>

+ 0 - 67
src/components/tools/HeadInfo.vue

@@ -1,67 +0,0 @@
-<template>
-  <div class="head-info" :class="center && 'center'">
-    <span>{{ title }}</span>
-    <p>{{ content }}</p>
-    <em v-if="bordered"/>
-  </div>
-</template>
-
-<script>
-export default {
-  name: 'HeadInfo',
-  props: {
-    title: {
-      type: String,
-      default: ''
-    },
-    content: {
-      type: String,
-      default: ''
-    },
-    bordered: {
-      type: Boolean,
-      default: false
-    },
-    center: {
-      type: Boolean,
-      default: true
-    }
-  }
-}
-</script>
-
-<style lang="less" scoped>
-  .head-info {
-    position: relative;
-    text-align: left;
-    padding: 0 32px 0 0;
-    min-width: 125px;
-
-    &.center {
-      text-align: center;
-      padding: 0 32px;
-    }
-
-    span {
-      color: rgba(0, 0, 0, .45);
-      display: inline-block;
-      font-size: 14px;
-      line-height: 22px;
-      margin-bottom: 4px;
-    }
-    p {
-      color: rgba(0, 0, 0, .85);
-      font-size: 24px;
-      line-height: 32px;
-      margin: 0;
-    }
-    em {
-      background-color: #e8e8e8;
-      position: absolute;
-      height: 56px;
-      width: 1px;
-      top: 0;
-      right: 0;
-    }
-  }
-</style>

+ 0 - 46
src/components/tools/LangSelect.vue

@@ -1,46 +0,0 @@
-<template>
-  <a-dropdown>
-    <span class="action global-lang">
-      <a-icon type="global" style="font-size: 16px"/>
-    </span>
-    <a-menu slot="overlay" style="width: 150px;" @click="SwitchLang">
-      <a-menu-item key="zh-CN">
-        <a rel="noopener noreferrer">
-          <span role="img" aria-label="简体中文">🇨🇳</span> 简体中文
-        </a>
-      </a-menu-item>
-      <a-menu-item key="zh-TW">
-        <a rel="noopener noreferrer">
-          <span role="img" aria-label="繁体中文">🇭🇰</span> 繁体中文
-        </a>
-      </a-menu-item>
-      <a-menu-item key="en-US">
-        <a rel="noopener noreferrer">
-          <span role="img" aria-label="English">🇬🇧</span> English
-        </a>
-      </a-menu-item>
-      <a-menu-item key="pt-BR">
-        <a rel="noopener noreferrer">
-          <span role="img" aria-label="Português">🇧🇷</span> Português
-        </a>
-      </a-menu-item>
-    </a-menu>
-  </a-dropdown>
-</template>
-
-<script>
-// import { mixin as langMixin } from '@/store/i18n-mixin'
-
-export default {
-  name: 'LangSelect',
-  // mixins: [langMixin],
-  data () {
-    return {}
-  },
-  methods: {
-    // SwitchLang (row) {
-    //   this.setLang(row.key)
-    // }
-  }
-}
-</script>

+ 0 - 31
src/components/tools/Logo.vue

@@ -1,31 +0,0 @@
-<template>
-  <div class="logo">
-    <router-link :to="{name:'dashboard'}">
-      <LogoSvg alt="logo" />
-      <h1 v-if="showTitle">{{ title }}</h1>
-    </router-link>
-  </div>
-</template>
-
-<script>
-import LogoSvg from '@/assets/logo.svg?inline'
-
-export default {
-  name: 'Logo',
-  components: {
-    LogoSvg
-  },
-  props: {
-    title: {
-      type: String,
-      default: 'Ant Design Pro',
-      required: false
-    },
-    showTitle: {
-      type: Boolean,
-      default: true,
-      required: false
-    }
-  }
-}
-</script>

+ 0 - 82
src/components/tools/UserMenu.vue

@@ -1,82 +0,0 @@
-<template>
-  <div class="user-wrapper">
-    <div class="content-box">
-      <a href="https://pro.loacg.com/docs/getting-started" target="_blank">
-        <span class="action">
-          <a-icon type="question-circle-o"></a-icon>
-        </span>
-      </a>
-      <notice-icon class="action"/>
-      <a-dropdown>
-        <span class="action ant-dropdown-link user-dropdown-menu">
-          <a-avatar class="avatar" size="small" :src="avatar"/>
-          <span>{{ nickname }}</span>
-        </span>
-        <a-menu slot="overlay" class="user-dropdown-menu-wrapper">
-          <a-menu-item key="0">
-            <router-link :to="{ name: 'center' }">
-              <a-icon type="user"/>
-              <span>个人中心</span>
-            </router-link>
-          </a-menu-item>
-          <a-menu-item key="1">
-            <router-link :to="{ name: 'settings' }">
-              <a-icon type="setting"/>
-              <span>账户设置</span>
-            </router-link>
-          </a-menu-item>
-          <a-menu-item key="2" disabled>
-            <a-icon type="setting"/>
-            <span>测试</span>
-          </a-menu-item>
-          <a-menu-divider/>
-          <a-menu-item key="3">
-            <a href="javascript:;" @click="handleLogout">
-              <a-icon type="logout"/>
-              <span>退出登录</span>
-            </a>
-          </a-menu-item>
-        </a-menu>
-      </a-dropdown>
-    </div>
-  </div>
-</template>
-
-<script>
-import NoticeIcon from '@/components/NoticeIcon'
-import { mapActions, mapGetters } from 'vuex'
-
-export default {
-  name: 'UserMenu',
-  components: {
-    NoticeIcon
-  },
-  computed: {
-    ...mapGetters(['nickname', 'avatar'])
-
-  },
-  methods: {
-    ...mapActions(['Logout']),
-    handleLogout () {
-      this.$confirm({
-        title: '提示',
-        content: '真的要注销登录吗 ?',
-        onOk: () => {
-          return this.Logout({}).then(() => {
-            setTimeout(() => {
-              window.location.reload()
-            }, 16)
-          }).catch(err => {
-            this.$message.error({
-              title: '错误',
-              description: err.message
-            })
-          })
-        },
-        onCancel () {
-        }
-      })
-    }
-  }
-}
-</script>

+ 0 - 0
src/components/tools/index.js


+ 10 - 13
src/config/defaultSettings.js

@@ -6,7 +6,6 @@
  * layout - 整体布局方式 ['sidemenu', 'topmenu'] 两种布局
  * fixedHeader - 固定 Header : boolean
  * fixSiderbar - 固定左侧菜单栏 : boolean
- * autoHideHeader - 向下滚动时,隐藏 Header : boolean
  * contentWidth - 内容区布局: 流式 |  固定
  *
  * storageOptions: {} - Vue-ls 插件配置项 (localStorage/sessionStorage)
@@ -14,20 +13,18 @@
  */
 
 export default {
-  primaryColor: '#52C41A', // primary color of ant design
   navTheme: 'dark', // theme for nav menu
-  layout: 'sidemenu', // nav menu position: sidemenu or topmenu
-  contentWidth: 'Fixed', // layout of content: Fluid or Fixed, only works when layout is topmenu
+  primaryColor: '#52C41A', // primary color of ant design
+  layout: 'sidemenu', // nav menu position: `sidemenu` or `topmenu`
+  contentWidth: 'Fluid', // layout of content: `Fluid` or `Fixed`, only works when layout is topmenu
   fixedHeader: false, // sticky header
   fixSiderbar: false, // sticky siderbar
-  autoHideHeader: false, //  auto hide header
   colorWeak: false,
-  multiTab: false,
-  production: process.env.NODE_ENV === 'production' && process.env.VUE_APP_PREVIEW !== 'true',
-  // vue-ls options
-  storageOptions: {
-    namespace: 'pro__', // key prefix
-    name: 'ls', // name variable Vue.[ls] or this.[$ls],
-    storage: 'local' // storage name session, local, memory
-  }
+  menu: {
+    locale: true
+  },
+  title: 'Ant Design Pro',
+  pwa: false,
+  iconfontUrl: '',
+  production: process.env.NODE_ENV === 'production' && process.env.VUE_APP_PREVIEW !== 'true'
 }

+ 24 - 36
src/config/router.config.js

@@ -1,47 +1,46 @@
 // eslint-disable-next-line
-import { UserLayout, BasicLayout, RouteView, BlankLayout, PageView } from '@/layouts'
+import { UserLayout, BasicLayout, BlankLayout } from '@/layouts'
 import { bxAnaalyse } from '@/core/icons'
 
+const RouteView = {
+  name: 'RouteView',
+  render: (h) => h('router-view')
+}
+
 export const asyncRouterMap = [
 
   {
     path: '/',
     name: 'index',
     component: BasicLayout,
-    meta: { title: '首页' },
+    meta: { title: 'menu.home' },
     redirect: '/dashboard/workplace',
     children: [
       // dashboard
       {
-        path: 'dashboard',
+        path: '/dashboard',
         name: 'dashboard',
         redirect: '/dashboard/workplace',
         component: RouteView,
-        meta: { title: '仪表盘', keepAlive: true, icon: bxAnaalyse, permission: [ 'dashboard' ] },
+        meta: { title: 'menu.dashboard', keepAlive: true, icon: bxAnaalyse, permission: [ 'dashboard' ] },
         children: [
           {
-            path: 'analysis/:pageNo([1-9]\\d*)?',
+            path: '/dashboard/analysis/:pageNo([1-9]\\d*)?',
             name: 'Analysis',
             component: () => import('@/views/dashboard/Analysis'),
-            meta: { title: '分析页', keepAlive: false, permission: [ 'dashboard' ] }
+            meta: { title: 'menu.dashboard.analysis', keepAlive: false, permission: [ 'dashboard' ] }
           },
           // 外部链接
           {
             path: 'https://www.baidu.com/',
             name: 'Monitor',
-            meta: { title: '监控页(外部)', target: '_blank' }
+            meta: { title: 'menu.dashboard.monitor', target: '_blank' }
           },
           {
-            path: 'workplace',
+            path: '/dashboard/workplace',
             name: 'Workplace',
             component: () => import('@/views/dashboard/Workplace'),
-            meta: { title: '工作台', keepAlive: true, permission: [ 'dashboard' ] }
-          },
-          {
-            path: 'test-work',
-            name: 'TestWork',
-            component: () => import('@/views/dashboard/TestWork'),
-            meta: { title: '测试功能', keepAlive: true, permission: [ 'dashboard' ] }
+            meta: { title: 'menu.dashboard.workplace', keepAlive: true, permission: [ 'dashboard' ] }
           }
         ]
       },
@@ -50,13 +49,13 @@ export const asyncRouterMap = [
       {
         path: '/form',
         redirect: '/form/base-form',
-        component: PageView,
+        component: RouteView,
         meta: { title: '表单页', icon: 'form', permission: [ 'form' ] },
         children: [
           {
             path: '/form/base-form',
             name: 'BaseForm',
-            component: () => import('@/views/form/BasicForm'),
+            component: () => import('@/views/form/basicForm'),
             meta: { title: '基础表单', keepAlive: true, permission: [ 'form' ] }
           },
           {
@@ -78,7 +77,7 @@ export const asyncRouterMap = [
       {
         path: '/list',
         name: 'list',
-        component: PageView,
+        component: RouteView,
         redirect: '/list/table-list',
         meta: { title: '列表页', icon: 'table', permission: [ 'table' ] },
         children: [
@@ -92,7 +91,7 @@ export const asyncRouterMap = [
           {
             path: '/list/basic-list',
             name: 'BasicList',
-            component: () => import('@/views/list/StandardList'),
+            component: () => import('@/views/list/BasicList'),
             meta: { title: '标准列表', keepAlive: true, permission: [ 'table' ] }
           },
           {
@@ -142,7 +141,7 @@ export const asyncRouterMap = [
           {
             path: '/profile/basic',
             name: 'ProfileBasic',
-            component: () => import('@/views/profile/basic/Index'),
+            component: () => import('@/views/profile/basic'),
             meta: { title: '基础详情页', permission: [ 'profile' ] }
           },
           {
@@ -158,7 +157,7 @@ export const asyncRouterMap = [
       {
         path: '/result',
         name: 'result',
-        component: PageView,
+        component: RouteView,
         redirect: '/result/success',
         meta: { title: '结果页', icon: 'check-circle-o', permission: [ 'result' ] },
         children: [
@@ -217,7 +216,7 @@ export const asyncRouterMap = [
           {
             path: '/account/center',
             name: 'center',
-            component: () => import('@/views/account/center/Index'),
+            component: () => import('@/views/account/center'),
             meta: { title: '个人中心', keepAlive: true, permission: [ 'user' ] }
           },
           {
@@ -261,9 +260,10 @@ export const asyncRouterMap = [
             ]
           }
         ]
-      },
+      }
 
       // other
+      /*
       {
         path: '/other',
         name: 'otherPage',
@@ -323,6 +323,7 @@ export const asyncRouterMap = [
           }
         ]
       }
+      */
     ]
   },
   {
@@ -364,19 +365,6 @@ export const constantRouterMap = [
     ]
   },
 
-  {
-    path: '/test',
-    component: BlankLayout,
-    redirect: '/test/home',
-    children: [
-      {
-        path: 'home',
-        name: 'TestHome',
-        component: () => import('@/views/Home')
-      }
-    ]
-  },
-
   {
     path: '/404',
     component: () => import(/* webpackChunkName: "fail" */ '@/views/exception/404')

+ 22 - 25
src/core/bootstrap.js

@@ -1,34 +1,31 @@
-import Vue from 'vue'
-import store from '@/store/'
+import store from '@/store'
+import storage from 'store'
 import {
   ACCESS_TOKEN,
-  DEFAULT_COLOR,
-  DEFAULT_THEME,
-  DEFAULT_LAYOUT_MODE,
-  DEFAULT_COLOR_WEAK,
-  SIDEBAR_TYPE,
-  DEFAULT_FIXED_HEADER,
-  DEFAULT_FIXED_HEADER_HIDDEN,
-  DEFAULT_FIXED_SIDEMENU,
-  DEFAULT_CONTENT_WIDTH_TYPE,
-  DEFAULT_MULTI_TAB
+  APP_LANGUAGE,
+  TOGGLE_CONTENT_WIDTH,
+  TOGGLE_FIXED_HEADER,
+  TOGGLE_FIXED_SIDEBAR, TOGGLE_HIDE_HEADER,
+  TOGGLE_LAYOUT, TOGGLE_NAV_THEME, TOGGLE_WEAK,
+  TOGGLE_COLOR, TOGGLE_MULTI_TAB
 } from '@/store/mutation-types'
-import config from '@/config/defaultSettings'
+import { printANSI } from '@/utils/screenLog'
+import defaultSettings from '@/config/defaultSettings'
 
 export default function Initializer () {
-  console.log(`API_URL: ${process.env.VUE_APP_API_BASE_URL}`)
+  printANSI() // 请自行移除该行.  please remove this line
 
-  store.commit('SET_SIDEBAR_TYPE', Vue.ls.get(SIDEBAR_TYPE, true))
-  store.commit('TOGGLE_THEME', Vue.ls.get(DEFAULT_THEME, config.navTheme))
-  store.commit('TOGGLE_LAYOUT_MODE', Vue.ls.get(DEFAULT_LAYOUT_MODE, config.layout))
-  store.commit('TOGGLE_FIXED_HEADER', Vue.ls.get(DEFAULT_FIXED_HEADER, config.fixedHeader))
-  store.commit('TOGGLE_FIXED_SIDERBAR', Vue.ls.get(DEFAULT_FIXED_SIDEMENU, config.fixSiderbar))
-  store.commit('TOGGLE_CONTENT_WIDTH', Vue.ls.get(DEFAULT_CONTENT_WIDTH_TYPE, config.contentWidth))
-  store.commit('TOGGLE_FIXED_HEADER_HIDDEN', Vue.ls.get(DEFAULT_FIXED_HEADER_HIDDEN, config.autoHideHeader))
-  store.commit('TOGGLE_WEAK', Vue.ls.get(DEFAULT_COLOR_WEAK, config.colorWeak))
-  store.commit('TOGGLE_COLOR', Vue.ls.get(DEFAULT_COLOR, config.primaryColor))
-  store.commit('TOGGLE_MULTI_TAB', Vue.ls.get(DEFAULT_MULTI_TAB, config.multiTab))
-  store.commit('SET_TOKEN', Vue.ls.get(ACCESS_TOKEN))
+  store.commit(TOGGLE_LAYOUT, storage.get(TOGGLE_LAYOUT, defaultSettings.layout))
+  store.commit(TOGGLE_FIXED_HEADER, storage.get(TOGGLE_FIXED_HEADER, defaultSettings.fixedHeader))
+  store.commit(TOGGLE_FIXED_SIDEBAR, storage.get(TOGGLE_FIXED_SIDEBAR, defaultSettings.fixSiderbar))
+  store.commit(TOGGLE_CONTENT_WIDTH, storage.get(TOGGLE_CONTENT_WIDTH, defaultSettings.contentWidth))
+  store.commit(TOGGLE_HIDE_HEADER, storage.get(TOGGLE_HIDE_HEADER, defaultSettings.autoHideHeader))
+  store.commit(TOGGLE_NAV_THEME, storage.get(TOGGLE_NAV_THEME, defaultSettings.navTheme))
+  store.commit(TOGGLE_WEAK, storage.get(TOGGLE_WEAK, defaultSettings.colorWeak))
+  store.commit(TOGGLE_COLOR, storage.get(TOGGLE_COLOR, defaultSettings.primaryColor))
+  store.commit(TOGGLE_MULTI_TAB, storage.get(TOGGLE_MULTI_TAB, defaultSettings.multiTab))
+  store.commit('SET_TOKEN', storage.get(ACCESS_TOKEN))
 
+  store.dispatch('setLang', storage.get(APP_LANGUAGE, 'en-US'))
   // last step
 }

+ 1 - 1
src/core/directives/action.js

@@ -12,7 +12,7 @@ import store from '@/store'
  *  - 当前用户没有权限时,组件上使用了该指令则会被隐藏
  *  - 当后台权限跟 pro 提供的模式不同时,只需要针对这里的权限过滤进行修改即可
  *
- *  @see https://github.com/sendya/ant-design-pro-vue/pull/53
+ *  @see https://github.com/vueComponent/ant-design-vue-pro/pull/53
  */
 const action = Vue.directive('action', {
   inserted: function (el, binding, vnode) {

+ 0 - 99
src/core/lazy_lib/components_use.js

@@ -1,99 +0,0 @@
-
-/* eslint-disable */
-/**
- * 该文件是为了按需加载,剔除掉了一些不需要的框架组件。
- * 减少了编译支持库包大小
- *
- * 当需要更多组件依赖时,在该文件加入即可
- */
-import Vue from 'vue'
-import {
-  ConfigProvider,
-  Layout,
-  Input,
-  InputNumber,
-  Button,
-  Switch,
-  Radio,
-  Checkbox,
-  Select,
-  Card,
-  Form,
-  Row,
-  Col,
-  Modal,
-  Table,
-  Tabs,
-  Icon,
-  Badge,
-  Popover,
-  Dropdown,
-  List,
-  Avatar,
-  Breadcrumb,
-  Steps,
-  Spin,
-  Menu,
-  Drawer,
-  Tooltip,
-  Alert,
-  Tag,
-  Divider,
-  DatePicker,
-  TimePicker,
-  Upload,
-  Progress,
-  Skeleton,
-  Popconfirm,
-  message,
-  notification
-} from 'ant-design-vue'
-// import VueCropper from 'vue-cropper'
-
-Vue.use(ConfigProvider)
-Vue.use(Layout)
-Vue.use(Input)
-Vue.use(InputNumber)
-Vue.use(Button)
-Vue.use(Switch)
-Vue.use(Radio)
-Vue.use(Checkbox)
-Vue.use(Select)
-Vue.use(Card)
-Vue.use(Form)
-Vue.use(Row)
-Vue.use(Col)
-Vue.use(Modal)
-Vue.use(Table)
-Vue.use(Tabs)
-Vue.use(Icon)
-Vue.use(Badge)
-Vue.use(Popover)
-Vue.use(Dropdown)
-Vue.use(List)
-Vue.use(Avatar)
-Vue.use(Breadcrumb)
-Vue.use(Steps)
-Vue.use(Spin)
-Vue.use(Menu)
-Vue.use(Drawer)
-Vue.use(Tooltip)
-Vue.use(Alert)
-Vue.use(Tag)
-Vue.use(Divider)
-Vue.use(DatePicker)
-Vue.use(TimePicker)
-Vue.use(Upload)
-Vue.use(Progress)
-Vue.use(Skeleton)
-Vue.use(Popconfirm)
-// Vue.use(VueCropper)
-Vue.use(notification)
-
-Vue.prototype.$confirm = Modal.confirm
-Vue.prototype.$message = message
-Vue.prototype.$notification = notification
-Vue.prototype.$info = Modal.info
-Vue.prototype.$success = Modal.success
-Vue.prototype.$error = Modal.error
-Vue.prototype.$warning = Modal.warning

+ 96 - 7
src/core/lazy_use.js

@@ -1,26 +1,115 @@
 import Vue from 'vue'
-import VueStorage from 'vue-ls'
-import config from '@/config/defaultSettings'
 
 // base library
-import '@/core/lazy_lib/components_use'
+import {
+  ConfigProvider,
+  Layout,
+  Input,
+  InputNumber,
+  Button,
+  Switch,
+  Radio,
+  Checkbox,
+  Select,
+  Card,
+  Form,
+  Row,
+  Col,
+  Modal,
+  Table,
+  Tabs,
+  Icon,
+  Badge,
+  Popover,
+  Dropdown,
+  List,
+  Avatar,
+  Breadcrumb,
+  Steps,
+  Spin,
+  Menu,
+  Drawer,
+  Tooltip,
+  Alert,
+  Tag,
+  Divider,
+  DatePicker,
+  TimePicker,
+  Upload,
+  Progress,
+  Skeleton,
+  Popconfirm,
+  PageHeader,
+  Result,
+  Statistic,
+  Descriptions,
+  message,
+  notification
+} from 'ant-design-vue'
 import Viser from 'viser-vue'
 
 // ext library
-import VueClipboard from 'vue-clipboard2'
 import VueCropper from 'vue-cropper'
+import Dialog from '@/components/Dialog'
 import MultiTab from '@/components/MultiTab'
 import PageLoading from '@/components/PageLoading'
 import PermissionHelper from '@/utils/helper/permission'
 import './directives/action'
 
-VueClipboard.config.autoSetContainer = true
+Vue.use(ConfigProvider)
+Vue.use(Layout)
+Vue.use(Input)
+Vue.use(InputNumber)
+Vue.use(Button)
+Vue.use(Switch)
+Vue.use(Radio)
+Vue.use(Checkbox)
+Vue.use(Select)
+Vue.use(Card)
+Vue.use(Form)
+Vue.use(Row)
+Vue.use(Col)
+Vue.use(Modal)
+Vue.use(Table)
+Vue.use(Tabs)
+Vue.use(Icon)
+Vue.use(Badge)
+Vue.use(Popover)
+Vue.use(Dropdown)
+Vue.use(List)
+Vue.use(Avatar)
+Vue.use(Breadcrumb)
+Vue.use(Steps)
+Vue.use(Spin)
+Vue.use(Menu)
+Vue.use(Drawer)
+Vue.use(Tooltip)
+Vue.use(Alert)
+Vue.use(Tag)
+Vue.use(Divider)
+Vue.use(DatePicker)
+Vue.use(TimePicker)
+Vue.use(Upload)
+Vue.use(Progress)
+Vue.use(Skeleton)
+Vue.use(Popconfirm)
+Vue.use(PageHeader)
+Vue.use(Result)
+Vue.use(Statistic)
+Vue.use(Descriptions)
+
+Vue.prototype.$confirm = Modal.confirm
+Vue.prototype.$message = message
+Vue.prototype.$notification = notification
+Vue.prototype.$info = Modal.info
+Vue.prototype.$success = Modal.success
+Vue.prototype.$error = Modal.error
+Vue.prototype.$warning = Modal.warning
 
 Vue.use(Viser)
+Vue.use(Dialog) // this.$dialog func
 Vue.use(MultiTab)
 Vue.use(PageLoading)
-Vue.use(VueStorage, config.storageOptions)
-Vue.use(VueClipboard)
 Vue.use(PermissionHelper)
 Vue.use(VueCropper)
 

+ 0 - 3
src/core/use.js

@@ -1,6 +1,4 @@
 import Vue from 'vue'
-import VueStorage from 'vue-ls'
-import config from '@/config/defaultSettings'
 
 // base library
 import Antd from 'ant-design-vue'
@@ -22,7 +20,6 @@ Vue.use(Antd)
 Vue.use(Viser)
 Vue.use(MultiTab)
 Vue.use(PageLoading)
-Vue.use(VueStorage, config.storageOptions)
 Vue.use(VueClipboard)
 Vue.use(PermissionHelper)
 Vue.use(VueCropper)

+ 94 - 0
src/global.less

@@ -0,0 +1,94 @@
+@import '~ant-design-vue/es/style/themes/default.less';
+
+html,
+body,
+#app, #root {
+  height: 100%;
+}
+
+.colorWeak {
+  filter: invert(80%);
+}
+
+.ant-layout.layout-basic {
+  height: 100vh;
+  min-height: 100vh;
+}
+
+canvas {
+  display: block;
+}
+
+body {
+  text-rendering: optimizeLegibility;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+ul,
+ol {
+  list-style: none;
+}
+
+// 数据列表 样式
+.table-alert {
+  margin-bottom: 16px;
+}
+// 数据列表 操作
+.table-operator {
+  margin-bottom: 18px;
+
+  button {
+    margin-right: 8px;
+  }
+}
+// 数据列表 搜索条件
+.table-page-search-wrapper {
+
+  .ant-form-inline {
+    .ant-form-item {
+      display: flex;
+      margin-bottom: 24px;
+      margin-right: 0;
+
+      .ant-form-item-control-wrapper {
+        flex: 1 1;
+        display: inline-block;
+        vertical-align: middle;
+      }
+
+      > .ant-form-item-label {
+        line-height: 32px;
+        padding-right: 8px;
+        width: auto;
+      }
+      .ant-form-item-control {
+        height: 32px;
+        line-height: 32px;
+      }
+    }
+  }
+
+  .table-page-search-submitButtons {
+    display: block;
+    margin-bottom: 24px;
+    white-space: nowrap;
+  }
+}
+
+@media (max-width: @screen-xs) {
+  .ant-table {
+    width: 100%;
+    overflow-x: auto;
+    &-thead > tr,
+    &-tbody > tr {
+      > th,
+      > td {
+        white-space: pre;
+        > span {
+          display: block;
+        }
+      }
+    }
+  }
+}

+ 36 - 0
src/layouts/BasicLayout.less

@@ -0,0 +1,36 @@
+@import "~ant-design-vue/es/style/themes/default.less";
+
+.ant-pro-global-header-index-right {
+  margin-right: 8px;
+
+  &.ant-pro-global-header-index-dark {
+    .ant-pro-global-header-index-action {
+      color: hsla(0, 0%, 100%, .85);
+
+      &:hover {
+        background: #1890ff;
+      }
+    }
+  }
+
+  .ant-pro-account-avatar {
+    .antd-pro-global-header-index-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);
+    }
+  }
+
+  .menu {
+    .anticon {
+      margin-right: 8px;
+    }
+
+    .ant-dropdown-menu-item {
+      min-width: 100px;
+    }
+  }
+}
+

+ 116 - 128
src/layouts/BasicLayout.vue

@@ -1,118 +1,104 @@
 <template>
-  <a-layout :class="['layout', device]">
-    <!-- SideMenu -->
-    <a-drawer
-      v-if="isMobile()"
-      placement="left"
-      :wrapClassName="`drawer-sider ${navTheme}`"
-      :closable="false"
-      :visible="collapsed"
-      @close="drawerClose"
-    >
-      <side-menu
-        mode="inline"
-        :menus="menus"
-        :theme="navTheme"
-        :collapsed="false"
-        :collapsible="true"
-        @menuSelect="menuSelect"
-      ></side-menu>
-    </a-drawer>
-
-    <side-menu
-      v-else-if="isSideMenu()"
-      mode="inline"
-      :menus="menus"
-      :theme="navTheme"
-      :collapsed="collapsed"
-      :collapsible="true"
-    ></side-menu>
-
-    <a-layout :class="[layoutMode, `content-width-${contentWidth}`]" :style="{ paddingLeft: contentPaddingLeft, minHeight: '100vh' }">
-      <!-- layout header -->
-      <global-header
-        :mode="layoutMode"
-        :menus="menus"
-        :theme="navTheme"
-        :collapsed="collapsed"
-        :device="device"
-        @toggle="toggle"
-      />
-
-      <!-- layout content -->
-      <a-layout-content :style="{ height: '100%', margin: '24px 24px 0', paddingTop: fixedHeader ? '64px' : '0' }">
-        <multi-tab v-if="multiTab"></multi-tab>
-        <transition name="page-transition">
-          <route-view />
-        </transition>
-      </a-layout-content>
-
-      <!-- layout footer -->
-      <a-layout-footer>
-        <global-footer />
-      </a-layout-footer>
-
-      <!-- Setting Drawer (show in development mode) -->
-      <setting-drawer v-if="!production"></setting-drawer>
-    </a-layout>
-  </a-layout>
+  <pro-layout
+    :title="title"
+    :menus="menus"
+    :collapsed="collapsed"
+    :mediaQuery="query"
+    :isMobile="isMobile"
+    :handleMediaQuery="handleMediaQuery"
+    :handleCollapse="handleCollapse"
+    :logo="logoRender"
+    :i18nRender="i18nRender"
+    v-bind="settings"
+  >
+    <!-- Ads begin
+      广告代码 真实项目中请移除
+      production remove this Ads
+    -->
+    <ads v-if="isProPreviewSite && !collapsed"/>
+    <!-- Ads end -->
 
+    <setting-drawer :settings="settings" @change="handleSettingChange" />
+    <template v-slot:rightContentRender>
+      <right-content :top-menu="settings.layout === 'topmenu'" :is-mobile="isMobile" :theme="settings.theme" />
+    </template>
+    <template v-slot:footerRender>
+      <global-footer />
+    </template>
+    <router-view />
+  </pro-layout>
 </template>
 
 <script>
-import { triggerWindowResizeEvent } from '@/utils/util'
-import { mapState, mapActions } from 'vuex'
-import { mixin, mixinDevice } from '@/utils/mixin'
-import config from '@/config/defaultSettings'
+import { SettingDrawer, updateTheme } from '@ant-design-vue/pro-layout'
+import { i18nRender } from '@/locales'
+import { mapState } from 'vuex'
+import { SIDEBAR_TYPE, TOGGLE_MOBILE_TYPE } from '@/store/mutation-types'
 
-import RouteView from './RouteView'
-import SideMenu from '@/components/Menu/SideMenu'
-import GlobalHeader from '@/components/GlobalHeader'
+import defaultSettings from '@/config/defaultSettings'
+import RightContent from '@/components/GlobalHeader/RightContent'
 import GlobalFooter from '@/components/GlobalFooter'
-import SettingDrawer from '@/components/SettingDrawer'
-import { convertRoutes } from '@/utils/routeConvert'
+import Ads from '@/components/Other/CarbonAds'
+import LogoSvg from '../assets/logo.svg?inline'
 
 export default {
   name: 'BasicLayout',
-  mixins: [mixin, mixinDevice],
   components: {
-    RouteView,
-    SideMenu,
-    GlobalHeader,
+    SettingDrawer,
+    RightContent,
     GlobalFooter,
-    SettingDrawer
+    Ads
   },
   data () {
     return {
-      production: config.production,
+      // preview.pro.antdv.com only use.
+      isProPreviewSite: process.env.VUE_APP_PREVIEW === 'true' && process.env.NODE_ENV !== 'development',
+      // end
+
+      // base
+      menus: [],
+      // 侧栏收起状态
       collapsed: false,
-      menus: []
+      title: defaultSettings.title,
+      settings: {
+        // 布局类型
+        layout: defaultSettings.layout, // 'sidemenu', 'topmenu'
+        // 定宽: true / 流式: false
+        contentWidth: defaultSettings.layout === 'sidemenu' ? false : defaultSettings.contentWidth === 'Fixed',
+        // 主题 'dark' | 'light'
+        theme: defaultSettings.navTheme,
+        // 主色调
+        primaryColor: defaultSettings.primaryColor,
+        fixedHeader: defaultSettings.fixedHeader,
+        fixSiderbar: defaultSettings.fixSiderbar,
+        colorWeak: defaultSettings.colorWeak,
+
+        hideHintAlert: false,
+        hideCopyButton: false
+      },
+      // 媒体查询
+      query: {},
+
+      // 是否手机模式
+      isMobile: false
     }
   },
   computed: {
     ...mapState({
       // 动态主路由
       mainMenu: state => state.permission.addRouters
-    }),
-    contentPaddingLeft () {
-      if (!this.fixSidebar || this.isMobile()) {
-        return '0'
-      }
-      if (this.sidebarOpened) {
-        return '256px'
-      }
-      return '80px'
-    }
-  },
-  watch: {
-    sidebarOpened (val) {
-      this.collapsed = !val
-    }
+    })
   },
   created () {
-    const routes = convertRoutes(this.mainMenu.find(item => item.path === '/'))
+    const routes = this.mainMenu.find(item => item.path === '/')
     this.menus = (routes && routes.children) || []
-    this.collapsed = !this.sidebarOpened
+    // 处理侧栏收起状态
+    this.$watch('collapsed', () => {
+      this.$store.commit(SIDEBAR_TYPE, this.collapsed)
+    })
+    this.$watch('isMobile', () => {
+      this.$store.commit(TOGGLE_MOBILE_TYPE, this.isMobile)
+    })
   },
   mounted () {
     const userAgent = navigator.userAgent
@@ -124,53 +110,55 @@ export default {
         }, 16)
       })
     }
+
+    // first update color
+    // TIPS: THEME COLOR HANDLER!! PLEASE CHECK THAT!!
+    if (process.env.NODE_ENV !== 'production' || process.env.VUE_APP_PREVIEW === 'true') {
+      updateTheme(this.settings.primaryColor)
+    }
   },
   methods: {
-    ...mapActions(['setSidebar']),
-    toggle () {
-      this.collapsed = !this.collapsed
-      this.setSidebar(!this.collapsed)
-      triggerWindowResizeEvent()
-    },
-    paddingCalc () {
-      let left = ''
-      if (this.sidebarOpened) {
-        left = this.isDesktop() ? '256px' : '80px'
-      } else {
-        left = (this.isMobile() && '0') || ((this.fixSidebar && '80px') || '0')
+    i18nRender,
+    handleMediaQuery (val) {
+      this.query = val
+      if (this.isMobile && !val['screen-xs']) {
+        this.isMobile = false
+        return
       }
-      return left
+      if (!this.isMobile && val['screen-xs']) {
+        this.isMobile = true
+        this.collapsed = false
+        this.settings.contentWidth = false
+        // this.settings.fixSiderbar = false
+      }
+    },
+    handleCollapse (val) {
+      this.collapsed = val
     },
-    menuSelect () {
+    handleSettingChange ({ type, value }) {
+      console.log('type', type, value)
+      type && (this.settings[type] = value)
+      switch (type) {
+        case 'contentWidth':
+          this.settings[type] = value === 'Fixed'
+          break
+        case 'layout':
+          if (value === 'sidemenu') {
+            this.settings.contentWidth = false
+          } else {
+            this.settings.fixSiderbar = false
+            this.settings.contentWidth = true
+          }
+          break
+      }
     },
-    drawerClose () {
-      this.collapsed = false
+    logoRender () {
+      return <LogoSvg />
     }
   }
 }
 </script>
 
 <style lang="less">
-/*
- * The following styles are auto-applied to elements with
- * transition="page-transition" when their visibility is toggled
- * by Vue.js.
- *
- * You can easily play with the page transition by editing
- * these styles.
- */
-
-.page-transition-enter {
-  opacity: 0;
-}
-
-.page-transition-leave-active {
-  opacity: 0;
-}
-
-.page-transition-enter .page-transition-container,
-.page-transition-leave-active .page-transition-container {
-  -webkit-transform: scale(1.1);
-  transform: scale(1.1);
-}
+@import "./BasicLayout.less";
 </style>

+ 4 - 173
src/layouts/PageView.vue

@@ -1,181 +1,12 @@
 <template>
-  <div :style="!$route.meta.hiddenHeaderContent ? 'margin: -24px -24px 0px;' : null">
-    <!-- pageHeader , route meta :true on hide -->
-    <page-header v-if="!$route.meta.hiddenHeaderContent" :title="pageTitle" :logo="logo" :avatar="avatar">
-      <slot slot="action" name="action"></slot>
-      <slot slot="content" name="headerContent"></slot>
-      <div slot="content" v-if="!this.$slots.headerContent && description">
-        <p style="font-size: 14px;color: rgba(0,0,0,.65)">{{ description }}</p>
-        <div class="link">
-          <template v-for="(link, index) in linkList">
-            <a :key="index" @click="() => { link.callback && link.callback() }">
-              <a-icon :type="link.icon" />
-              <span>{{ link.title }}</span>
-            </a>
-          </template>
-        </div>
-      </div>
-      <slot slot="extra" name="extra">
-        <div class="extra-img">
-          <img v-if="typeof extraImage !== 'undefined'" :src="extraImage"/>
-        </div>
-      </slot>
-      <div slot="pageMenu">
-        <div class="page-menu-search" v-if="search">
-          <a-input-search
-            style="width: 80%; max-width: 522px;"
-            placeholder="请输入..."
-            size="large"
-            enterButton="搜索"
-          />
-        </div>
-        <div class="page-menu-tabs" v-if="tabs && tabs.items">
-          <!-- @change="callback" :activeKey="activeKey" -->
-          <a-tabs :tabBarStyle="{margin: 0}" :activeKey="tabs.active()" @change="tabs.callback">
-            <a-tab-pane v-for="item in tabs.items" :tab="item.title" :key="item.key"></a-tab-pane>
-          </a-tabs>
-        </div>
-      </div>
-    </page-header>
-    <div class="content">
-      <div class="page-header-index-wide">
-        <slot>
-          <!-- keep-alive  -->
-          <keep-alive v-if="multiTab">
-            <router-view ref="content" />
-          </keep-alive>
-          <router-view v-else ref="content" />
-        </slot>
-      </div>
-    </div>
-  </div>
+  <page-header-wrapper>
+    <router-view />
+  </page-header-wrapper>
 </template>
 
 <script>
-import { mapState } from 'vuex'
-import PageHeader from '@/components/PageHeader'
 
 export default {
-  name: 'PageView',
-  components: {
-    PageHeader
-  },
-  props: {
-    avatar: {
-      type: String,
-      default: null
-    },
-    title: {
-      type: [String, Boolean],
-      default: true
-    },
-    logo: {
-      type: String,
-      default: null
-    },
-    directTabs: {
-      type: Object,
-      default: null
-    }
-  },
-  data () {
-    return {
-      pageTitle: null,
-      description: null,
-      linkList: [],
-      extraImage: '',
-      search: false,
-      tabs: {}
-    }
-  },
-  computed: {
-    ...mapState({
-      multiTab: state => state.app.multiTab
-    })
-  },
-  mounted () {
-    this.tabs = this.directTabs
-    this.getPageMeta()
-  },
-  updated () {
-    this.getPageMeta()
-  },
-  methods: {
-    getPageMeta () {
-      // eslint-disable-next-line
-      this.pageTitle = (typeof(this.title) === 'string' || !this.title) ? this.title : this.$route.meta.title
-
-      const content = this.$refs.content
-      if (content) {
-        if (content.pageMeta) {
-          Object.assign(this, content.pageMeta)
-        } else {
-          this.description = content.description
-          this.linkList = content.linkList
-          this.extraImage = content.extraImage
-          this.search = content.search === true
-          this.tabs = content.tabs
-        }
-      }
-    }
-  }
+  name: 'PageView'
 }
 </script>
-
-<style lang="less" scoped>
-  .content {
-    margin: 24px 24px 0;
-    .link {
-      margin-top: 16px;
-      &:not(:empty) {
-        margin-bottom: 16px;
-      }
-      a {
-        margin-right: 32px;
-        height: 24px;
-        line-height: 24px;
-        display: inline-block;
-        i {
-          font-size: 24px;
-          margin-right: 8px;
-          vertical-align: middle;
-        }
-        span {
-          height: 24px;
-          line-height: 24px;
-          display: inline-block;
-          vertical-align: middle;
-        }
-      }
-    }
-  }
-  .page-menu-search {
-    text-align: center;
-    margin-bottom: 16px;
-  }
-  .page-menu-tabs {
-    margin-top: 48px;
-  }
-
-  .extra-img {
-    margin-top: -60px;
-    text-align: center;
-    width: 195px;
-
-    img {
-      width: 100%;
-    }
-  }
-
-  .mobile {
-    .extra-img{
-      margin-top: 0;
-      text-align: center;
-      width: 96px;
-
-      img{
-        width: 100%;
-      }
-    }
-  }
-</style>

+ 6 - 11
src/layouts/UserLayout.vue

@@ -1,5 +1,5 @@
 <template>
-  <div id="userLayout" :class="['user-layout-wrapper', device]">
+  <div id="userLayout" :class="['user-layout-wrapper', isMobile && 'mobile']">
     <div class="container">
       <div class="top">
         <div class="header">
@@ -13,7 +13,7 @@
         </div>
       </div>
 
-      <route-view></route-view>
+      <router-view />
 
       <div class="footer">
         <div class="links">
@@ -22,7 +22,7 @@
           <a href="_self">条款</a>
         </div>
         <div class="copyright">
-          Copyright &copy; 2018 白鹭学园技术组出品
+          Copyright &copy; 2018 vueComponent
         </div>
       </div>
     </div>
@@ -30,16 +30,11 @@
 </template>
 
 <script>
-import RouteView from './RouteView'
-import { mixinDevice } from '@/utils/mixin'
+import { deviceMixin } from '@/store/device-mixin'
 
 export default {
   name: 'UserLayout',
-  components: { RouteView },
-  mixins: [mixinDevice],
-  data () {
-    return {}
-  },
+  mixins: [deviceMixin],
   mounted () {
     document.body.classList.add('userLayout')
   },
@@ -50,7 +45,7 @@ export default {
 </script>
 
 <style lang="less" scoped>
-  #userLayout.user-layout-wrapper {
+#userLayout.user-layout-wrapper {
     height: 100%;
 
     &.mobile {

+ 59 - 0
src/locales/index.js

@@ -0,0 +1,59 @@
+import Vue from 'vue'
+import VueI18n from 'vue-i18n'
+import storage from 'store'
+import moment from 'moment'
+
+// default lang
+import enUS from './lang/en-US'
+
+Vue.use(VueI18n)
+
+export const defaultLang = 'en-US'
+
+const messages = {
+  'en-US': {
+    ...enUS
+  }
+}
+
+const i18n = new VueI18n({
+  silentTranslationWarn: true,
+  locale: defaultLang,
+  fallbackLocale: defaultLang,
+  messages
+})
+
+const loadedLanguages = [defaultLang]
+
+function setI18nLanguage (lang) {
+  i18n.locale = lang
+  // request.headers['Accept-Language'] = lang
+  document.querySelector('html').setAttribute('lang', lang)
+  return lang
+}
+
+export function loadLanguageAsync (lang = defaultLang) {
+  return new Promise(resolve => {
+    // 缓存语言设置
+    storage.set('lang', lang)
+    if (i18n.locale !== lang) {
+      if (!loadedLanguages.includes(lang)) {
+        return import(/* webpackChunkName: "lang-[request]" */ `./lang/${lang}`).then(msg => {
+          const locale = msg.default
+          i18n.setLocaleMessage(lang, locale)
+          loadedLanguages.push(lang)
+          moment.updateLocale(locale.momentName, locale.momentLocale)
+          return setI18nLanguage(lang)
+        })
+      }
+      return resolve(setI18nLanguage(lang))
+    }
+    return resolve(lang)
+  })
+}
+
+export function i18nRender (key) {
+  return i18n.t(`${key}`)
+}
+
+export default i18n

+ 45 - 0
src/locales/lang/en-US.js

@@ -0,0 +1,45 @@
+import antdEnUS from 'ant-design-vue/es/locale-provider/en_US'
+import momentEU from 'moment/locale/eu'
+
+const components = {
+  antLocale: antdEnUS,
+  momentName: 'eu',
+  momentLocale: momentEU
+}
+
+const locale = {
+  'message': '-',
+  'menu.home': 'Home',
+  'menu.dashboard': 'Dashboard',
+  'menu.dashboard.analysis': 'Analysis',
+  'menu.dashboard.monitor': 'Monitor',
+  'menu.dashboard.workplace': 'Workplace',
+
+  'layouts.usermenu.dialog.title': 'Message',
+  'layouts.usermenu.dialog.content': 'Do you really log-out.',
+
+  'app.setting.pagestyle': 'Page style setting',
+  'app.setting.pagestyle.light': 'Light style',
+  'app.setting.pagestyle.dark': 'Dark style',
+  'app.setting.pagestyle.realdark': 'RealDark style',
+  'app.setting.themecolor': 'Theme Color',
+  'app.setting.navigationmode': 'Navigation Mode',
+  'app.setting.content-width': 'Content Width',
+  'app.setting.fixedheader': 'Fixed Header',
+  'app.setting.fixedsidebar': 'Fixed Sidebar',
+  'app.setting.sidemenu': 'Side Menu Layout',
+  'app.setting.topmenu': 'Top Menu Layout',
+  'app.setting.content-width.fixed': 'Fixed',
+  'app.setting.content-width.fluid': 'Fluid',
+  'app.setting.othersettings': 'Other Settings',
+  'app.setting.weakmode': 'Weak Mode',
+  'app.setting.copy': 'Copy Setting',
+  'app.setting.loading': 'Loading theme',
+  '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 {
+  ...components,
+  ...locale
+}

+ 22 - 0
src/locales/lang/zh-CN.js

@@ -0,0 +1,22 @@
+import antd from 'ant-design-vue/es/locale-provider/zh_CN'
+import momentCN from 'moment/locale/zh-cn'
+
+const components = {
+  antLocale: antd,
+  momentName: 'zh-cn',
+  momentLocale: momentCN
+}
+
+const locale = {
+  'message': '-',
+  'menu.home': '主页',
+  'menu.dashboard': '仪表盘',
+  'menu.dashboard.analysis': '分析页',
+  'menu.dashboard.monitor': '监控页',
+  'menu.dashboard.workplace': '工作台'
+}
+
+export default {
+  ...components,
+  ...locale
+}

+ 10 - 4
src/main.js

@@ -6,7 +6,10 @@ import Vue from 'vue'
 import App from './App.vue'
 import router from './router'
 import store from './store/'
+import i18n from './locales'
 import { VueAxios } from './utils/request'
+import ProLayout, { PageHeaderWrapper } from '@ant-design-vue/pro-layout'
+import themePluginConfig from '../config/themePluginConfig'
 
 // mock
 // WARNING: `mockjs` NOT SUPPORT `IE` PLEASE DO NOT USE IN `production` ENV.
@@ -16,18 +19,21 @@ import bootstrap from './core/bootstrap'
 import './core/lazy_use'
 import './permission' // permission control
 import './utils/filter' // global filter
-import './components/global.less'
-import { Dialog } from '@/components'
+import './global.less'
 
 Vue.config.productionTip = false
 
-// mount axios Vue.$http and this.$http
+// mount axios to `Vue.$http` and `this.$http`
 Vue.use(VueAxios)
-Vue.use(Dialog)
+Vue.component('pro-layout', ProLayout)
+Vue.component('page-header-wrapper', PageHeaderWrapper)
+
+window.umi_plugin_ant_themeVar = themePluginConfig.theme
 
 new Vue({
   router,
   store,
+  i18n,
   created: bootstrap,
   render: h => h(App)
 }).$mount('#app')

+ 1 - 1
src/mock/services/auth.js

@@ -4,7 +4,7 @@ import { builder, getBody } from '../util'
 const username = ['admin', 'super']
 // 强硬要求 ant.design 相同密码
 // '21232f297a57a5a743894a0e4a801fc3',
-const password = ['8914de686ab28dc22f30d3d8e107ff6c'] // admin, ant.design
+const password = ['8914de686ab28dc22f30d3d8e107ff6c', '21232f297a57a5a743894a0e4a801fc3'] // admin, ant.design
 
 const login = (options) => {
   const body = getBody(options)

+ 0 - 10
src/mock/services/user.js

@@ -417,16 +417,6 @@ const userNav = (options) => {
       'component': 'Analysis',
       'path': '/dashboard/analysis'
     },
-    {
-      'name': 'tests',
-      'parentId': 1,
-      'id': 8,
-      'meta': {
-        'title': '测试功能',
-        'show': true
-      },
-      'component': 'TestWork'
-    },
 
     // form
     {

+ 14 - 9
src/permission.js

@@ -1,32 +1,36 @@
-import Vue from 'vue'
 import router from './router'
 import store from './store'
-
+import storage from 'store'
 import NProgress from 'nprogress' // progress bar
 import '@/components/NProgress/nprogress.less' // progress bar custom style
 import notification from 'ant-design-vue/es/notification'
 import { setDocumentTitle, domTitle } from '@/utils/domUtil'
 import { ACCESS_TOKEN } from '@/store/mutation-types'
+import { i18nRender } from '@/locales'
 
 NProgress.configure({ showSpinner: false }) // NProgress Configuration
 
 const whiteList = ['login', 'register', 'registerResult'] // no redirect whitelist
+const loginRoutePath = '/user/login'
 const defaultRoutePath = '/dashboard/workplace'
 
 router.beforeEach((to, from, next) => {
   NProgress.start() // start progress bar
-  to.meta && (typeof to.meta.title !== 'undefined' && setDocumentTitle(`${to.meta.title} - ${domTitle}`))
-  if (Vue.ls.get(ACCESS_TOKEN)) {
-    /* has token */
-    if (to.path === '/user/login') {
+  to.meta && (typeof to.meta.title !== 'undefined' && setDocumentTitle(`${i18nRender(to.meta.title)} - ${domTitle}`))
+  /* has token */
+  if (storage.get(ACCESS_TOKEN)) {
+    if (to.path === loginRoutePath) {
       next({ path: defaultRoutePath })
       NProgress.done()
     } else {
+      // check login user.roles is null
       if (store.getters.roles.length === 0) {
+        // request login userInfo
         store
           .dispatch('GetInfo')
           .then(res => {
             const roles = res.result && res.result.role
+            // generate dynamic router
             store.dispatch('GenerateRoutes', { roles }).then(() => {
               // 根据roles权限生成可访问的路由表
               // 动态添加可访问路由表
@@ -34,7 +38,7 @@ router.beforeEach((to, from, next) => {
               // 请求带有 redirect 重定向时,登录自动重定向到该地址
               const redirect = decodeURIComponent(from.query.redirect || to.path)
               if (to.path === redirect) {
-                // hack方法 确保addRoutes已完成 ,set the replace: true so the navigation will not leave a history record
+                // set the replace: true so the navigation will not leave a history record
                 next({ ...to, replace: true })
               } else {
                 // 跳转到目的路由
@@ -47,8 +51,9 @@ router.beforeEach((to, from, next) => {
               message: '错误',
               description: '请求用户信息失败,请重试'
             })
+            // 失败时,获取用户信息失败时,调用登出,来清空历史保留信息
             store.dispatch('Logout').then(() => {
-              next({ path: '/user/login', query: { redirect: to.fullPath } })
+              next({ path: loginRoutePath, query: { redirect: to.fullPath } })
             })
           })
       } else {
@@ -60,7 +65,7 @@ router.beforeEach((to, from, next) => {
       // 在免登录白名单,直接进入
       next()
     } else {
-      next({ path: '/user/login', query: { redirect: to.fullPath } })
+      next({ path: loginRoutePath, query: { redirect: to.fullPath } })
       NProgress.done() // if current page is login will not trigger afterEach hook, so manually handle it
     }
   }

+ 3 - 3
src/router/README.md

@@ -42,7 +42,7 @@ const routerObject = {
 | keepAlive           | 缓存该路由                                                   | boolean | false  |
 | target              | 菜单链接跳转目标(参考 html a 标记)                          | string | -  |
 | hidden              | 配合`hideChildrenInMenu`使用,用于隐藏菜单时,提供递归到父菜单显示 选中菜单项_(可参考 个人页 配置方式)_ | boolean | false  |
-| hiddenHeaderContent | *特殊 隐藏 [PageHeader](https://github.com/sendya/ant-design-pro-vue/blob/master/src/components/PageHeader/PageHeader.vue#L6) 组件中的页面带的 面包屑和页面标题栏 | boolean | false  |
+| hiddenHeaderContent | *特殊 隐藏 [PageHeader](https://github.com/vueComponent/ant-design-vue-pro/blob/master/src/components/PageHeader/PageHeader.vue#L6) 组件中的页面带的 面包屑和页面标题栏 | boolean | false  |
 | permission          | 与项目提供的权限拦截匹配的权限,如果不匹配,则会被禁止访问该路由页面 | array   | []     |
 
 > 路由自定义 `Icon` 请引入自定义 `svg` Icon 文件,然后传递给路由的 `meta.icon` 参数即可
@@ -123,7 +123,7 @@ const asyncRouterMap = [
 > 1. 请注意 `component: () => import('..') ` 方式引入路由的页面组件为 懒加载模式。具体可以看 [Vue 官方文档](https://router.vuejs.org/zh/guide/advanced/lazy-loading.html)
 > 2. 增加新的路由应该增加在 '/' (index) 路由的 `children` 内
 > 3. 子路由的父级路由必须有 `router-view` 才能让子路由渲染出来,请仔细查阅 vue-router 文档
-> 4. `permission` 可以进行自定义修改,只需要对这个模块进行自定义修改即可 [src/store/modules/permission.js#L10](https://github.com/sendya/ant-design-pro-vue/blob/master/src/store/modules/permission.js#L10)
+> 4. `permission` 可以进行自定义修改,只需要对这个模块进行自定义修改即可 [src/store/modules/permission.js#L10](https://github.com/vueComponent/ant-design-vue-pro/blob/master/src/store/modules/permission.js#L10)
 
 
 附权限路由结构:
@@ -131,4 +131,4 @@ const asyncRouterMap = [
 ![权限结构](https://static-2.loacg.com/open/static/github/permissions.png)
 
 
-第二种前端路由由后端动态生成的设计,可以前往官网文档 https://pro.loacg.com/docs/authority-management 参考
+第二种前端路由由后端动态生成的设计,可以前往官网文档 https://pro.antdv.com/docs/authority-management 参考

+ 6 - 6
src/router/generator-routers.js

@@ -19,19 +19,19 @@ const constantRouterComponents = {
   'Analysis': () => import('@/views/dashboard/Analysis'),
 
   // form
-  'BasicForm': () => import('@/views/form/BasicForm'),
+  'BasicForm': () => import('@/views/form/basicForm'),
   'StepForm': () => import('@/views/form/stepForm/StepForm'),
   'AdvanceForm': () => import('@/views/form/advancedForm/AdvancedForm'),
 
   // list
   'TableList': () => import('@/views/list/TableList'),
-  'StandardList': () => import('@/views/list/StandardList'),
+  'StandardList': () => import('@/views/list/BasicList'),
   'CardList': () => import('@/views/list/CardList'),
   'SearchLayout': () => import('@/views/list/search/SearchLayout'),
   'SearchArticles': () => import('@/views/list/search/Article'),
   'SearchProjects': () => import('@/views/list/search/Projects'),
   'SearchApplications': () => import('@/views/list/search/Applications'),
-  'ProfileBasic': () => import('@/views/profile/basic/Index'),
+  'ProfileBasic': () => import('@/views/profile/basic'),
   'ProfileAdvanced': () => import('@/views/profile/advanced/Advanced'),
 
   // result
@@ -44,15 +44,15 @@ const constantRouterComponents = {
   'Exception500': () => import(/* webpackChunkName: "fail" */ '@/views/exception/500'),
 
   // account
-  'AccountCenter': () => import('@/views/account/center/Index'),
+  'AccountCenter': () => import('@/views/account/center'),
   'AccountSettings': () => import('@/views/account/settings/Index'),
   'BaseSettings': () => import('@/views/account/settings/BaseSetting'),
   'SecuritySettings': () => import('@/views/account/settings/Security'),
   'CustomSettings': () => import('@/views/account/settings/Custom'),
   'BindingSettings': () => import('@/views/account/settings/Binding'),
-  'NotificationSettings': () => import('@/views/account/settings/Notification'),
+  'NotificationSettings': () => import('@/views/account/settings/Notification')
 
-  'TestWork': () => import(/* webpackChunkName: "TestWork" */ '@/views/dashboard/TestWork')
+  // 'TestWork': () => import(/* webpackChunkName: "TestWork" */ '@/views/dashboard/TestWork')
 }
 
 // 前端未找到页面路由(固定不用改)

+ 0 - 2
src/router/index.js

@@ -13,7 +13,5 @@ Vue.use(Router)
 
 export default new Router({
   mode: 'history',
-  base: process.env.BASE_URL,
-  scrollBehavior: () => ({ y: 0 }),
   routes: constantRouterMap
 })

+ 32 - 0
src/store/app-mixin.js

@@ -0,0 +1,32 @@
+import { mapState } from 'vuex'
+
+const baseMixin = {
+  computed: {
+    ...mapState({
+      layout: state => state.app.layout,
+      navTheme: state => state.app.theme,
+      primaryColor: state => state.app.color,
+      colorWeak: state => state.app.weak,
+      fixedHeader: state => state.app.fixedHeader,
+      fixedSidebar: state => state.app.fixedSidebar,
+      contentWidth: state => state.app.contentWidth,
+      autoHideHeader: state => state.app.autoHideHeader,
+
+      isMobile: state => state.app.isMobile,
+      sideCollapsed: state => state.app.sideCollapsed,
+      multiTab: state => state.app.multiTab
+    }),
+    isTopMenu () {
+      return this.layout === 'topmenu'
+    }
+  },
+  methods: {
+    isSideMenu () {
+      return !this.isTopMenu
+    }
+  }
+}
+
+export {
+  baseMixin
+}

+ 11 - 0
src/store/device-mixin.js

@@ -0,0 +1,11 @@
+import { mapState } from 'vuex'
+
+const deviceMixin = {
+  computed: {
+    ...mapState({
+      isMobile: state => state.app.isMobile
+    })
+  }
+}
+
+export { deviceMixin }

+ 3 - 3
src/store/getters.js

@@ -1,5 +1,6 @@
 const getters = {
-  device: state => state.app.device,
+  isMobile: state => state.app.isMobile,
+  lang: state => state.app.lang,
   theme: state => state.app.theme,
   color: state => state.app.color,
   token: state => state.user.token,
@@ -9,8 +10,7 @@ const getters = {
   roles: state => state.user.roles,
   userInfo: state => state.user.info,
   addRouters: state => state.permission.addRouters,
-  multiTab: state => state.app.multiTab,
-  lang: state => state.i18n.lang
+  multiTab: state => state.app.multiTab
 }
 
 export default getters

+ 16 - 0
src/store/i18n-mixin.js

@@ -0,0 +1,16 @@
+import { mapState } from 'vuex'
+
+const i18nMixin = {
+  computed: {
+    ...mapState({
+      currentLang: state => state.app.lang
+    })
+  },
+  methods: {
+    setLang (lang) {
+      this.$store.dispatch('setLang', lang)
+    }
+  }
+}
+
+export default i18nMixin

+ 65 - 88
src/store/modules/app.js

@@ -1,120 +1,97 @@
-import Vue from 'vue'
+import storage from 'store'
 import {
   SIDEBAR_TYPE,
-  DEFAULT_THEME,
-  DEFAULT_LAYOUT_MODE,
-  DEFAULT_COLOR,
-  DEFAULT_COLOR_WEAK,
-  DEFAULT_FIXED_HEADER,
-  DEFAULT_FIXED_SIDEMENU,
-  DEFAULT_FIXED_HEADER_HIDDEN,
-  DEFAULT_CONTENT_WIDTH_TYPE,
-  DEFAULT_MULTI_TAB
+  TOGGLE_MOBILE_TYPE,
+  TOGGLE_NAV_THEME,
+  TOGGLE_LAYOUT,
+  TOGGLE_FIXED_HEADER,
+  TOGGLE_FIXED_SIDEBAR,
+  TOGGLE_CONTENT_WIDTH,
+  TOGGLE_HIDE_HEADER,
+  TOGGLE_COLOR,
+  TOGGLE_WEAK,
+  TOGGLE_MULTI_TAB,
+  // i18n
+  APP_LANGUAGE
 } from '@/store/mutation-types'
+import { loadLanguageAsync } from '@/locales'
 
 const app = {
   state: {
-    sidebar: true,
-    device: 'desktop',
-    theme: '',
+    sideCollapsed: false,
+    isMobile: false,
+    theme: 'dark',
     layout: '',
     contentWidth: '',
     fixedHeader: false,
-    fixSiderbar: false,
+    fixedSidebar: false,
     autoHideHeader: false,
-    color: null,
+    color: '',
     weak: false,
-    multiTab: true
+    multiTab: true,
+    lang: 'en-US',
+    _antLocale: {}
   },
   mutations: {
-    SET_SIDEBAR_TYPE: (state, type) => {
-      state.sidebar = type
-      Vue.ls.set(SIDEBAR_TYPE, type)
+    [SIDEBAR_TYPE]: (state, type) => {
+      state.sideCollapsed = type
+      storage.set(SIDEBAR_TYPE, type)
     },
-    CLOSE_SIDEBAR: (state) => {
-      Vue.ls.set(SIDEBAR_TYPE, true)
-      state.sidebar = false
+    [TOGGLE_MOBILE_TYPE]: (state, isMobile) => {
+      state.isMobile = isMobile
     },
-    TOGGLE_DEVICE: (state, device) => {
-      state.device = device
-    },
-    TOGGLE_THEME: (state, theme) => {
-      // setStore('_DEFAULT_THEME', theme)
-      Vue.ls.set(DEFAULT_THEME, theme)
+    [TOGGLE_NAV_THEME]: (state, theme) => {
       state.theme = theme
+      storage.set(TOGGLE_NAV_THEME, theme)
     },
-    TOGGLE_LAYOUT_MODE: (state, layout) => {
-      Vue.ls.set(DEFAULT_LAYOUT_MODE, layout)
-      state.layout = layout
-    },
-    TOGGLE_FIXED_HEADER: (state, fixed) => {
-      Vue.ls.set(DEFAULT_FIXED_HEADER, fixed)
-      state.fixedHeader = fixed
+    [TOGGLE_LAYOUT]: (state, mode) => {
+      state.layout = mode
+      storage.set(TOGGLE_LAYOUT, mode)
     },
-    TOGGLE_FIXED_SIDERBAR: (state, fixed) => {
-      Vue.ls.set(DEFAULT_FIXED_SIDEMENU, fixed)
-      state.fixSiderbar = fixed
+    [TOGGLE_FIXED_HEADER]: (state, mode) => {
+      state.fixedHeader = mode
+      storage.set(TOGGLE_FIXED_HEADER, mode)
     },
-    TOGGLE_FIXED_HEADER_HIDDEN: (state, show) => {
-      Vue.ls.set(DEFAULT_FIXED_HEADER_HIDDEN, show)
-      state.autoHideHeader = show
+    [TOGGLE_FIXED_SIDEBAR]: (state, mode) => {
+      state.fixedSidebar = mode
+      storage.set(TOGGLE_FIXED_SIDEBAR, mode)
     },
-    TOGGLE_CONTENT_WIDTH: (state, type) => {
-      Vue.ls.set(DEFAULT_CONTENT_WIDTH_TYPE, type)
+    [TOGGLE_CONTENT_WIDTH]: (state, type) => {
       state.contentWidth = type
+      storage.set(TOGGLE_CONTENT_WIDTH, type)
     },
-    TOGGLE_COLOR: (state, color) => {
-      Vue.ls.set(DEFAULT_COLOR, color)
+    [TOGGLE_HIDE_HEADER]: (state, type) => {
+      state.autoHideHeader = type
+      storage.set(TOGGLE_HIDE_HEADER, type)
+    },
+    [TOGGLE_COLOR]: (state, color) => {
       state.color = color
+      storage.set(TOGGLE_COLOR, color)
+    },
+    [TOGGLE_WEAK]: (state, mode) => {
+      state.weak = mode
+      storage.set(TOGGLE_WEAK, mode)
     },
-    TOGGLE_WEAK: (state, flag) => {
-      Vue.ls.set(DEFAULT_COLOR_WEAK, flag)
-      state.weak = flag
+    [APP_LANGUAGE]: (state, lang, antd = {}) => {
+      state.lang = lang
+      state._antLocale = antd
+      storage.set(APP_LANGUAGE, lang)
     },
-    TOGGLE_MULTI_TAB: (state, bool) => {
-      Vue.ls.set(DEFAULT_MULTI_TAB, bool)
+    [TOGGLE_MULTI_TAB]: (state, bool) => {
+      storage.set(TOGGLE_MULTI_TAB, bool)
       state.multiTab = bool
     }
   },
   actions: {
-    setSidebar ({ commit }, type) {
-      commit('SET_SIDEBAR_TYPE', type)
-    },
-    CloseSidebar ({ commit }) {
-      commit('CLOSE_SIDEBAR')
-    },
-    ToggleDevice ({ commit }, device) {
-      commit('TOGGLE_DEVICE', device)
-    },
-    ToggleTheme ({ commit }, theme) {
-      commit('TOGGLE_THEME', theme)
-    },
-    ToggleLayoutMode ({ commit }, mode) {
-      commit('TOGGLE_LAYOUT_MODE', mode)
-    },
-    ToggleFixedHeader ({ commit }, fixedHeader) {
-      if (!fixedHeader) {
-        commit('TOGGLE_FIXED_HEADER_HIDDEN', false)
-      }
-      commit('TOGGLE_FIXED_HEADER', fixedHeader)
-    },
-    ToggleFixSiderbar ({ commit }, fixSiderbar) {
-      commit('TOGGLE_FIXED_SIDERBAR', fixSiderbar)
-    },
-    ToggleFixedHeaderHidden ({ commit }, show) {
-      commit('TOGGLE_FIXED_HEADER_HIDDEN', show)
-    },
-    ToggleContentWidth ({ commit }, type) {
-      commit('TOGGLE_CONTENT_WIDTH', type)
-    },
-    ToggleColor ({ commit }, color) {
-      commit('TOGGLE_COLOR', color)
-    },
-    ToggleWeak ({ commit }, weakFlag) {
-      commit('TOGGLE_WEAK', weakFlag)
-    },
-    ToggleMultiTab ({ commit }, bool) {
-      commit('TOGGLE_MULTI_TAB', bool)
+    setLang ({ commit }, lang) {
+      return new Promise((resolve, reject) => {
+        commit(APP_LANGUAGE, lang)
+        loadLanguageAsync(lang).then(() => {
+          resolve()
+        }).catch((e) => {
+          reject(e)
+        })
+      })
     }
   }
 }

+ 3 - 3
src/store/modules/user.js

@@ -1,4 +1,4 @@
-import Vue from 'vue'
+import storage from 'store'
 import { login, getInfo, logout } from '@/api/login'
 import { ACCESS_TOKEN } from '@/store/mutation-types'
 import { welcome } from '@/utils/util'
@@ -38,7 +38,7 @@ const user = {
       return new Promise((resolve, reject) => {
         login(userInfo).then(response => {
           const result = response.result
-          Vue.ls.set(ACCESS_TOKEN, result.token, 7 * 24 * 60 * 60 * 1000)
+          storage.set(ACCESS_TOKEN, result.token, 7 * 24 * 60 * 60 * 1000)
           commit('SET_TOKEN', result.token)
           resolve()
         }).catch(error => {
@@ -89,7 +89,7 @@ const user = {
         }).finally(() => {
           commit('SET_TOKEN', '')
           commit('SET_ROLES', [])
-          Vue.ls.remove(ACCESS_TOKEN)
+          storage.remove(ACCESS_TOKEN)
         })
       })
     }

+ 18 - 10
src/store/mutation-types.js

@@ -1,16 +1,24 @@
 export const ACCESS_TOKEN = 'Access-Token'
-export const SIDEBAR_TYPE = 'SIDEBAR_TYPE'
-export const DEFAULT_THEME = 'DEFAULT_THEME'
-export const DEFAULT_LAYOUT_MODE = 'DEFAULT_LAYOUT_MODE'
-export const DEFAULT_COLOR = 'DEFAULT_COLOR'
-export const DEFAULT_COLOR_WEAK = 'DEFAULT_COLOR_WEAK'
-export const DEFAULT_FIXED_HEADER = 'DEFAULT_FIXED_HEADER'
-export const DEFAULT_FIXED_SIDEMENU = 'DEFAULT_FIXED_SIDEMENU'
-export const DEFAULT_FIXED_HEADER_HIDDEN = 'DEFAULT_FIXED_HEADER_HIDDEN'
-export const DEFAULT_CONTENT_WIDTH_TYPE = 'DEFAULT_CONTENT_WIDTH_TYPE'
-export const DEFAULT_MULTI_TAB = 'DEFAULT_MULTI_TAB'
+
+export const SIDEBAR_TYPE = 'sidebar_type'
+export const TOGGLE_MOBILE_TYPE = 'is_mobile'
+export const TOGGLE_NAV_THEME = 'nav_theme'
+export const TOGGLE_LAYOUT = 'layout'
+export const TOGGLE_FIXED_HEADER = 'fixed_header'
+export const TOGGLE_FIXED_SIDEBAR = 'fixed_sidebar'
+export const TOGGLE_CONTENT_WIDTH = 'content_width'
+export const TOGGLE_HIDE_HEADER = 'auto_hide_header'
+export const TOGGLE_COLOR = 'color'
+export const TOGGLE_WEAK = 'weak'
+export const TOGGLE_MULTI_TAB = 'multi_tab'
+export const APP_LANGUAGE = 'app_language'
 
 export const CONTENT_WIDTH_TYPE = {
   Fluid: 'Fluid',
   Fixed: 'Fixed'
 }
+
+export const NAV_THEME = {
+  LIGHT: 'light',
+  DARK: 'dark'
+}

+ 0 - 33
src/utils/device.js

@@ -1,33 +0,0 @@
-import enquireJs from 'enquire.js'
-
-export const DEVICE_TYPE = {
-  DESKTOP: 'desktop',
-  TABLET: 'tablet',
-  MOBILE: 'mobile'
-}
-
-export const deviceEnquire = function (callback) {
-  const matchDesktop = {
-    match: () => {
-      callback && callback(DEVICE_TYPE.DESKTOP)
-    }
-  }
-
-  const matchLablet = {
-    match: () => {
-      callback && callback(DEVICE_TYPE.TABLET)
-    }
-  }
-
-  const matchMobile = {
-    match: () => {
-      callback && callback(DEVICE_TYPE.MOBILE)
-    }
-  }
-
-  // screen and (max-width: 1087.99px)
-  enquireJs
-    .register('screen and (max-width: 576px)', matchMobile)
-    .register('screen and (min-width: 576px) and (max-width: 1199px)', matchLablet)
-    .register('screen and (min-width: 1200px)', matchDesktop)
-}

+ 3 - 1
src/utils/domUtil.js

@@ -1,3 +1,5 @@
+import config from '@/config/defaultSettings'
+
 export const setDocumentTitle = function (title) {
   document.title = title
   const ua = navigator.userAgent
@@ -16,4 +18,4 @@ export const setDocumentTitle = function (title) {
   }
 }
 
-export const domTitle = 'Ant Design Pro'
+export const domTitle = config.title

+ 0 - 76
src/utils/mixin.js

@@ -1,76 +0,0 @@
-// import Vue from 'vue'
-import { deviceEnquire, DEVICE_TYPE } from '@/utils/device'
-import { mapState } from 'vuex'
-
-// const mixinsComputed = Vue.config.optionMergeStrategies.computed
-// const mixinsMethods = Vue.config.optionMergeStrategies.methods
-
-const mixin = {
-  computed: {
-    ...mapState({
-      layoutMode: state => state.app.layout,
-      navTheme: state => state.app.theme,
-      primaryColor: state => state.app.color,
-      colorWeak: state => state.app.weak,
-      fixedHeader: state => state.app.fixedHeader,
-      fixSiderbar: state => state.app.fixSiderbar,
-      fixSidebar: state => state.app.fixSiderbar,
-      contentWidth: state => state.app.contentWidth,
-      autoHideHeader: state => state.app.autoHideHeader,
-      sidebarOpened: state => state.app.sidebar,
-      multiTab: state => state.app.multiTab
-    })
-  },
-  methods: {
-    isTopMenu () {
-      return this.layoutMode === 'topmenu'
-    },
-    isSideMenu () {
-      return !this.isTopMenu()
-    }
-  }
-}
-
-const mixinDevice = {
-  computed: {
-    ...mapState({
-      device: state => state.app.device
-    })
-  },
-  methods: {
-    isMobile () {
-      return this.device === DEVICE_TYPE.MOBILE
-    },
-    isDesktop () {
-      return this.device === DEVICE_TYPE.DESKTOP
-    },
-    isTablet () {
-      return this.device === DEVICE_TYPE.TABLET
-    }
-  }
-}
-
-const AppDeviceEnquire = {
-  mounted () {
-    const { $store } = this
-    deviceEnquire(deviceType => {
-      switch (deviceType) {
-        case DEVICE_TYPE.DESKTOP:
-          $store.commit('TOGGLE_DEVICE', 'desktop')
-          $store.dispatch('setSidebar', true)
-          break
-        case DEVICE_TYPE.TABLET:
-          $store.commit('TOGGLE_DEVICE', 'tablet')
-          $store.dispatch('setSidebar', false)
-          break
-        case DEVICE_TYPE.MOBILE:
-        default:
-          $store.commit('TOGGLE_DEVICE', 'mobile')
-          $store.dispatch('setSidebar', true)
-          break
-      }
-    })
-  }
-}
-
-export { mixin, AppDeviceEnquire, mixinDevice }

+ 20 - 13
src/utils/request.js

@@ -1,20 +1,23 @@
-import Vue from 'vue'
 import axios from 'axios'
 import store from '@/store'
+import storage from 'store'
 import notification from 'ant-design-vue/es/notification'
 import { VueAxios } from './axios'
 import { ACCESS_TOKEN } from '@/store/mutation-types'
 
 // 创建 axios 实例
-const service = axios.create({
-  baseURL: process.env.VUE_APP_API_BASE_URL, // api base_url
+const request = axios.create({
+  // API 请求的默认前缀
+  baseURL: process.env.VUE_APP_API_BASE_URL,
   timeout: 6000 // 请求超时时间
 })
 
-const err = (error) => {
+// 异常拦截处理器
+const errorHandler = (error) => {
   if (error.response) {
     const data = error.response.data
-    const token = Vue.ls.get(ACCESS_TOKEN)
+    // 从 localstorage 获取 token
+    const token = storage.get(ACCESS_TOKEN)
     if (error.response.status === 403) {
       notification.error({
         message: 'Forbidden',
@@ -39,27 +42,31 @@ const err = (error) => {
 }
 
 // request interceptor
-service.interceptors.request.use(config => {
-  const token = Vue.ls.get(ACCESS_TOKEN)
+request.interceptors.request.use(config => {
+  const token = storage.get(ACCESS_TOKEN)
+  // 如果 token 存在
+  // 让每个请求携带自定义 token 请根据实际情况自行修改
   if (token) {
-    config.headers['Access-Token'] = token // 让每个请求携带自定义 token 请根据实际情况自行修改
+    config.headers['Access-Token'] = token
   }
   return config
-}, err)
+}, errorHandler)
 
 // response interceptor
-service.interceptors.response.use((response) => {
+request.interceptors.response.use((response) => {
   return response.data
-}, err)
+}, errorHandler)
 
 const installer = {
   vm: {},
   install (Vue) {
-    Vue.use(VueAxios, service)
+    Vue.use(VueAxios, request)
   }
 }
 
+export default request
+
 export {
   installer as VueAxios,
-  service as axios
+  request as axios
 }

+ 18 - 0
src/utils/screenLog.js

@@ -0,0 +1,18 @@
+/* eslint-disable */
+export const printANSI = () => {
+  // console.clear()
+  console.log('[antd pro] created()')
+  // ASCII - ANSI Shadow
+  let text = `
+ █████╗ ███╗   ██╗████████╗██████╗     ██████╗ ██████╗  ██████╗ 
+██╔══██╗████╗  ██║╚══██╔══╝██╔══██╗    ██╔══██╗██╔══██╗██╔═══██╗
+███████║██╔██╗ ██║   ██║   ██║  ██║    ██████╔╝██████╔╝██║   ██║
+██╔══██║██║╚██╗██║   ██║   ██║  ██║    ██╔═══╝ ██╔══██╗██║   ██║
+██║  ██║██║ ╚████║   ██║   ██████╔╝    ██║     ██║  ██║╚██████╔╝
+╚═╝  ╚═╝╚═╝  ╚═══╝   ╚═╝   ╚═════╝     ╚═╝     ╚═╝  ╚═╝ ╚═════╝ 
+\t\t\t\t\tPublished ${APP_VERSION}-${GIT_HASH} @ antdv.com
+\t\t\t\t\tBuild date: ${BUILD_DATE}`
+  console.log(`%c${text}`, 'color: #fc4d50')
+  console.log('%c感谢使用 antd pro!', 'color: #000; font-size: 14px;    font-family: Hiragino Sans GB,Microsoft YaHei,\\\\5FAE\\8F6F\\96C5\\9ED1,Droid Sans Fallback,Source Sans,Wenquanyi Micro Hei,WenQuanYi Micro Hei Mono,WenQuanYi Zen Hei,Apple LiGothic Medium,SimHei,ST Heiti,WenQuanYi Zen Hei Sharp,sans-serif;')
+  console.log('%cThanks for using antd pro!', 'color: #fff; font-size: 14px; font-weight: 300; text-shadow:#000 1px 0 0,#000 0 1px 0,#000 -1px 0 0,#000 0 -1px 0;')
+}

+ 0 - 215
src/views/Home.vue

@@ -1,215 +0,0 @@
-<template>
-  <div class="home">
-    <div class="banner">
-      <img alt="Vue logo" style="width: 64px; height: 64px" src="../assets/logo.png">
-      <h3 style="margin-top: 1rem">Welcome to Your Vue.js App</h3>
-    </div>
-
-    <br/>
-
-    <h2># Trend 组件 </h2>
-
-    <a-divider> 正常 </a-divider>
-
-    <a-card>
-
-      <trend flag="up" style="margin-right: 16px;">
-        <span slot="term">工资</span>
-        5%
-      </trend>
-      <trend flag="up" style="margin-right: 16px;">
-        <span slot="term">工作量</span>
-        50%
-      </trend>
-      <trend flag="down">
-        <span slot="term">身体状态</span>
-        50%
-      </trend>
-
-    </a-card>
-
-    <a-divider> 颜色反转 </a-divider>
-
-    <a-card style="margin-bottom: 3rem">
-
-      <trend flag="up" :reverse-color="true" style="margin-right: 16px;">
-        <span slot="term">工资</span>
-        5%
-      </trend>
-      <trend flag="down" :reverse-color="true" style="margin-right: 16px;">
-        <span slot="term">工作量</span>
-        50%
-      </trend>
-
-    </a-card>
-
-    <h2># AvatarList 组件 </h2>
-
-    <a-divider> AvatarList </a-divider>
-    <a-card style="margin-bottom: 3rem">
-      <avatar-list :max-length="3">
-        <avatar-list-item tips="Jake" src="https://gw.alipayobjects.com/zos/rmsportal/zOsKZmFRdUtvpqCImOVY.png" />
-        <avatar-list-item tips="Andy" src="https://gw.alipayobjects.com/zos/rmsportal/sfjbOqnsXXJgNCjCzDBL.png" />
-        <avatar-list-item tips="Niko" src="https://gw.alipayobjects.com/zos/rmsportal/kZzEzemZyKLKFsojXItE.png" />
-        <avatar-list-item tips="Niko" src="https://gw.alipayobjects.com/zos/rmsportal/kZzEzemZyKLKFsojXItE.png" />
-        <avatar-list-item tips="Niko" src="https://gw.alipayobjects.com/zos/rmsportal/kZzEzemZyKLKFsojXItE.png" />
-        <avatar-list-item tips="Niko" src="https://gw.alipayobjects.com/zos/rmsportal/kZzEzemZyKLKFsojXItE.png" />
-        <avatar-list-item tips="Niko" src="https://gw.alipayobjects.com/zos/rmsportal/kZzEzemZyKLKFsojXItE.png" />
-
-      </avatar-list>
-
-      <a-divider type="vertical" style="margin: 0 16px" />
-
-      <avatar-list size="mini">
-        <avatar-list-item tips="Jake" src="https://gw.alipayobjects.com/zos/rmsportal/zOsKZmFRdUtvpqCImOVY.png" />
-        <avatar-list-item tips="Andy" src="https://gw.alipayobjects.com/zos/rmsportal/sfjbOqnsXXJgNCjCzDBL.png" />
-        <avatar-list-item tips="Niko" src="https://gw.alipayobjects.com/zos/rmsportal/kZzEzemZyKLKFsojXItE.png" />
-      </avatar-list>
-    </a-card>
-
-    <h2># CountDown 组件 </h2>
-
-    <a-divider> CountDown </a-divider>
-    <a-card style="margin-bottom: 3rem">
-      <count-down
-        style="font-size: 2rem"
-        :target="new Date().getTime() + 3000000"
-        :on-end="onEndHandle">
-      </count-down>
-
-      <a-divider type="vertical" style="margin: 0 16px" />
-
-      <count-down
-        style="font-size: 2rem"
-        :target="new Date().getTime() + 10000"
-        :on-end="onEndHandle2">
-      </count-down>
-    </a-card>
-
-    <h2># Ellipsis 组件 </h2>
-
-    <a-divider> Ellipsis </a-divider>
-    <a-card style="margin-bottom: 3rem">
-      <ellipsis :length="100" tooltip>
-        There were injuries alleged in three cases in 2015, and a
-        fourth incident in September, according to the safety recall report. After meeting with US regulators in October, the firm decided to issue a voluntary recall.
-      </ellipsis>
-    </a-card>
-
-    <h2># NumberInfo 组件 </h2>
-
-    <a-divider> NumberInfo </a-divider>
-    <a-card style="margin-bottom: 3rem">
-      <number-info
-        :sub-title="() => { return 'Visits this week' }"
-        :total="12321"
-        status="up"
-        :sub-total="17.1"></number-info>
-    </a-card>
-
-    <h2># TagSelect 组件 </h2>
-
-    <a-divider> TagSelect </a-divider>
-    <a-card style="margin-bottom: 3rem">
-      <tag-select>
-        <tag-select-option value="cat1">类目1</tag-select-option>
-        <tag-select-option value="cat2">类目2</tag-select-option>
-        <tag-select-option value="cat3">类目3</tag-select-option>
-        <tag-select-option value="cat4">类目4</tag-select-option>
-        <tag-select-option value="cat5">类目5</tag-select-option>
-        <tag-select-option value="cat6">类目6</tag-select-option>
-        <tag-select-option value="cat7">类目7</tag-select-option>
-      </tag-select>
-    </a-card>
-
-    <h2># DescriptionList 组件 </h2>
-
-    <a-divider> DescriptionList </a-divider>
-    <a-card style="margin-bottom: 3rem">
-      <description-list title="组名称" size="small">
-        <description-list-item term="负责人">林东东</description-list-item>
-        <description-list-item term="角色码">1234567</description-list-item>
-        <description-list-item term="所属部门">XX公司-YY部</description-list-item>
-        <description-list-item term="过期时间">2018-08-08</description-list-item>
-        <description-list-item term="描述">这段描述很长很长很长很长很长很长很长很长很长很长很长很长很长很长...</description-list-item>
-      </description-list>
-    </a-card>
-
-    <a-divider> TagCloud </a-divider>
-    <a-card style="margin-bottom: 3rem">
-      <tag-cloud :tag-list="tagCloudData"></tag-cloud>
-    </a-card>
-  </div>
-</template>
-
-<script>
-// @ is an alias to /src
-
-import Trend from '@/components/Trend'
-import AvatarList from '@/components/AvatarList'
-import CountDown from '@/components/CountDown/CountDown'
-import Ellipsis from '@/components/Ellipsis'
-import NumberInfo from '@/components/NumberInfo'
-import TagSelect from '@/components/TagSelect'
-import { DescriptionList, TagCloud } from '@/components/'
-
-const AvatarListItem = AvatarList.AvatarItem
-const TagSelectOption = TagSelect.Option
-
-const DescriptionListItem = DescriptionList.Item
-
-export default {
-  name: 'Home',
-  components: {
-    NumberInfo,
-    Ellipsis,
-    CountDown,
-    Trend,
-    AvatarList,
-    AvatarListItem,
-    TagSelect,
-    TagSelectOption,
-    TagCloud,
-    DescriptionList,
-    DescriptionListItem
-  },
-  data () {
-    return {
-      targetTime: new Date().getTime() + 3900000,
-      tagCloudData: []
-    }
-  },
-  created () {
-    this.getTagCloudData()
-  },
-  methods: {
-    onEndHandle () {
-      this.$message.success('CountDown callback!!!')
-    },
-    onEndHandle2 () {
-      this.$notification.open({
-        message: 'Notification Title',
-        description: 'This is the content of the notification. This is the content of the notification. This is the content of the notification.'
-      })
-    },
-    getTagCloudData () {
-      this.$http.get('/data/antv/tag-cloud').then(res => {
-        this.tagCloudData = res.result
-      })
-    }
-  }
-}
-</script>
-
-<style scoped>
-  .home {
-    width: 900px;
-    margin: 0 auto;
-    padding: 25px 0;
-  }
-  .home > .banner {
-    text-align: center;
-    padding: 25px 0;
-    margin: 25px 0;
-  }
-</style>

+ 7 - 6
src/views/account/center/Index.vue → src/views/account/center/index.vue

@@ -5,9 +5,9 @@
         <a-card :bordered="false">
           <div class="account-center-avatarHolder">
             <div class="avatar">
-              <img :src="avatar()">
+              <img :src="avatar">
             </div>
-            <div class="username">{{ nickname() }}</div>
+            <div class="username">{{ nickname }}</div>
             <div class="bio">海纳百川,有容乃大</div>
           </div>
           <div class="account-center-detail">
@@ -33,14 +33,14 @@
                   <a-tag
                     :key="tag"
                     :closable="index !== 0"
-                    :afterClose="() => handleTagClose(tag)"
+                    :close="() => handleTagClose(tag)"
                   >{{ `${tag.slice(0, 20)}...` }}</a-tag>
                 </a-tooltip>
                 <a-tag
                   v-else
                   :key="tag"
                   :closable="index !== 0"
-                  :afterClose="() => handleTagClose(tag)"
+                  :close="() => handleTagClose(tag)"
                 >{{ tag }}</a-tag>
               </template>
               <a-input
@@ -136,12 +136,13 @@ export default {
       noTitleKey: 'app'
     }
   },
+  computed: {
+    ...mapGetters(['nickname', 'avatar'])
+  },
   mounted () {
     this.getTeams()
   },
   methods: {
-    ...mapGetters(['nickname', 'avatar']),
-
     getTeams () {
       this.$http.get('/workplace/teams').then(res => {
         this.teams = res.result

+ 40 - 47
src/views/account/settings/Custom.vue

@@ -1,30 +1,52 @@
+<template>
+  <a-list itemLayout="horizontal">
+    <a-list-item>
+      <a-list-item-meta>
+        <template v-slot:title>
+          <a>风格配色</a>
+        </template>
+        <template v-slot:description>
+          <span>
+            整体风格配色设置
+          </span>
+        </template>
+      </a-list-item-meta>
+      <template v-slot:actions>
+        <a-switch checkedChildren="暗色" unCheckedChildren="白色" :defaultChecked="navTheme === 'dark' && true || false" @change="onChange" />
+      </template>
+    </a-list-item>
+    <a-list-item>
+      <a-list-item-meta>
+        <template v-slot:title>
+          <a>主题色</a>
+        </template>
+        <template v-slot:description>
+          <span>
+            页面风格配色: <a>{{ colorFilter(primaryColor) }}</a>
+          </span>
+        </template>
+      </a-list-item-meta>
+    </a-list-item>
+  </a-list>
+</template>
 <script>
 import { colorList } from '@/components/SettingDrawer/settingConfig'
-import ASwitch from 'ant-design-vue/es/switch'
-import AList from 'ant-design-vue/es/list'
-import AListItem from 'ant-design-vue/es/list/Item'
-import { mixin } from '@/utils/mixin'
+import { baseMixin } from '@/store/app-mixin'
+import { NAV_THEME, TOGGLE_NAV_THEME } from '@/store/mutation-types'
 
-const Meta = AListItem.Meta
+const themeMap = {
+  'dark': '暗色',
+  'light': '白色'
+}
 
 export default {
-  components: {
-    AListItem,
-    AList,
-    ASwitch,
-    Meta
-  },
-  mixins: [mixin],
+  mixins: [baseMixin],
   data () {
     return {
     }
   },
   filters: {
     themeFilter (theme) {
-      const themeMap = {
-        'dark': '暗色',
-        'light': '白色'
-      }
       return themeMap[theme]
     }
   },
@@ -36,40 +58,11 @@ export default {
 
     onChange (checked) {
       if (checked) {
-        this.$store.dispatch('ToggleTheme', 'dark')
+        this.$store.commit(TOGGLE_NAV_THEME, NAV_THEME.DARK)
       } else {
-        this.$store.dispatch('ToggleTheme', 'light')
+        this.$store.commit(TOGGLE_NAV_THEME, NAV_THEME.LIGHT)
       }
     }
-  },
-  render () {
-    return (
-      <AList itemLayout="horizontal">
-        <AListItem>
-          <Meta>
-            <a slot="title">风格配色</a>
-            <span slot="description">
-                整体风格配色设置
-            </span>
-          </Meta>
-          <div slot="actions">
-            <ASwitch checkedChildren="暗色" unCheckedChildren="白色" defaultChecked={this.navTheme === 'dark' && true || false} onChange={this.onChange} />
-          </div>
-        </AListItem>
-        <AListItem>
-          <Meta>
-            <a slot="title">主题色</a>
-            <span slot="description">
-                页面风格配色: <a domPropsInnerHTML={ this.colorFilter(this.primaryColor) }/>
-            </span>
-          </Meta>
-        </AListItem>
-      </AList>
-    )
   }
 }
 </script>
-
-<style scoped>
-
-</style>

+ 7 - 8
src/views/account/settings/Index.vue

@@ -1,11 +1,11 @@
 <template>
   <div class="page-header-index-wide">
     <a-card :bordered="false" :bodyStyle="{ padding: '16px 0', height: '100%' }" :style="{ height: '100%' }">
-      <div class="account-settings-info-main" :class="device">
+      <div class="account-settings-info-main" :class="{ 'mobile': isMobile }">
         <div class="account-settings-info-left">
           <a-menu
-            :mode="device == 'mobile' ? 'horizontal' : 'inline'"
-            :style="{ border: '0', width: device == 'mobile' ? '560px' : 'auto'}"
+            :mode="isMobile ? 'horizontal' : 'inline'"
+            :style="{ border: '0', width: isMobile ? '560px' : 'auto'}"
             :selectedKeys="selectedKeys"
             type="inner"
             @openChange="onOpenChange"
@@ -49,15 +49,14 @@
 </template>
 
 <script>
-import { PageView, RouteView } from '@/layouts'
-import { mixinDevice } from '@/utils/mixin.js'
+import { RouteView } from '@/layouts'
+import { baseMixin } from '@/store/app-mixin'
 
 export default {
   components: {
-    RouteView,
-    PageView
+    RouteView
   },
-  mixins: [mixinDevice],
+  mixins: [baseMixin],
   data () {
     return {
       // horizontal  inline

+ 15 - 5
src/views/dashboard/Analysis.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="page-header-index-wide">
+  <div>
     <a-row :gutter="24">
       <a-col :sm="24" :md="12" :xl="6" :style="{ marginBottom: '24px' }">
         <chart-card :loading="loading" title="总销售额" total="¥126,560">
@@ -99,7 +99,7 @@
       </div>
     </a-card>
 
-    <div class="antd-pro-pages-dashboard-analysis-twoColLayout" :class="isDesktop() ? 'desktop' : ''">
+    <div class="antd-pro-pages-dashboard-analysis-twoColLayout" :class="!isMobile && 'desktop'">
       <a-row :gutter="24" type="flex" :style="{ marginTop: '24px' }">
         <a-col :xl="12" :lg="24" :md="24" :sm="24" :xs="24">
           <a-card :loading="loading" :bordered="false" title="线上热门搜索" :style="{ height: '100%' }">
@@ -213,8 +213,18 @@
 
 <script>
 import moment from 'moment'
-import { ChartCard, MiniArea, MiniBar, MiniProgress, RankList, Bar, Trend, NumberInfo, MiniSmoothArea } from '@/components'
-import { mixinDevice } from '@/utils/mixin'
+import {
+  ChartCard,
+  MiniArea,
+  MiniBar,
+  MiniProgress,
+  RankList,
+  Bar,
+  Trend,
+  NumberInfo,
+  MiniSmoothArea
+} from '@/components'
+import { baseMixin } from '@/store/app-mixin'
 
 const barData = []
 const barData2 = []
@@ -317,7 +327,7 @@ const pieData = dv.rows
 
 export default {
   name: 'Analysis',
-  mixins: [mixinDevice],
+  mixins: [baseMixin],
   components: {
     ChartCard,
     MiniArea,

Some files were not shown because too many files changed in this diff