Browse Source

🎉🎉🎉仓库重置到2020年9月29日,Vue2.6最后一个版本,之前版本不再支持,具体请查阅文档,Vue 3.0版本即将发布请耐心等待!!!

chuzhixin 4 years ago
commit
f88c3868a7
100 changed files with 9158 additions and 0 deletions
  1. 4 0
      .browserslistrc
  2. 12 0
      .editorconfig
  3. 5 0
      .eslintignore
  4. 26 0
      .eslintrc.js
  5. 10 0
      .gitattributes
  6. 2 0
      .github/FUNDING.yml
  7. 16 0
      .github/ISSUE_TEMPLATE/---------------.md
  8. 20 0
      .gitignore
  9. 3 0
      .stylelintrc.js
  10. 52 0
      .vscode/settings.json
  11. 373 0
      LICENSE
  12. 43 0
      README-DCLOUD.md
  13. 321 0
      README.md
  14. 21 0
      SECURITY.md
  15. 3 0
      babel.config.js
  16. 17 0
      deploy.sh
  17. 70 0
      http/mock.http
  18. 373 0
      license.md
  19. 19 0
      mock/controller/ad.js
  20. 87 0
      mock/controller/blacklist.js
  21. 200 0
      mock/controller/changeLog.js
  22. 328 0
      mock/controller/colorfulIcon.js
  23. 42 0
      mock/controller/goodsDetail.js
  24. 43 0
      mock/controller/goodsList.js
  25. 989 0
      mock/controller/icon.js
  26. 51 0
      mock/controller/menuManagement.js
  27. 38 0
      mock/controller/notice.js
  28. 42 0
      mock/controller/personalCenter.js
  29. 2296 0
      mock/controller/remixIcon.js
  30. 53 0
      mock/controller/roleManagement.js
  31. 390 0
      mock/controller/router.js
  32. 88 0
      mock/controller/table.js
  33. 54 0
      mock/controller/tree.js
  34. 14 0
      mock/controller/upload.js
  35. 95 0
      mock/controller/user.js
  36. 70 0
      mock/controller/userManagement.js
  37. 16 0
      mock/index.js
  38. 94 0
      mock/mockServer.js
  39. 43 0
      mock/utils/index.js
  40. 132 0
      package.json
  41. 13 0
      plopfile.js
  42. 16 0
      prettier.config.js
  43. BIN
      public/favicon.ico
  44. BIN
      public/favicon_backup.ico
  45. 52 0
      public/index.html
  46. 96 0
      public/static/css/loading.css
  47. 11 0
      push.sh
  48. 12 0
      src/App.vue
  49. 9 0
      src/api/ad.js
  50. 9 0
      src/api/blacklist.js
  51. 9 0
      src/api/changeLog.js
  52. 9 0
      src/api/colorfulIcon.js
  53. 20 0
      src/api/github.js
  54. 9 0
      src/api/goodsDetail.js
  55. 9 0
      src/api/goodsList.js
  56. 9 0
      src/api/icon.js
  57. 8 0
      src/api/markdown.js
  58. 25 0
      src/api/menuManagement.js
  59. 8 0
      src/api/notice.js
  60. 25 0
      src/api/personalCenter.js
  61. 8 0
      src/api/publicKey.js
  62. 9 0
      src/api/remixIcon.js
  63. 25 0
      src/api/roleManagement.js
  64. 9 0
      src/api/router.js
  65. 25 0
      src/api/table.js
  66. 9 0
      src/api/tree.js
  67. 38 0
      src/api/user.js
  68. 25 0
      src/api/userManagement.js
  69. BIN
      src/assets/comparison/left.jpg
  70. BIN
      src/assets/comparison/right.jpg
  71. BIN
      src/assets/error_images/401.png
  72. BIN
      src/assets/error_images/404.png
  73. BIN
      src/assets/error_images/cloud.png
  74. BIN
      src/assets/ewm.png
  75. BIN
      src/assets/login_images/background.jpg
  76. BIN
      src/assets/pro.png
  77. BIN
      src/assets/qr_logo/lqr_logo.png
  78. 17 0
      src/colorfulIcon/index.js
  79. 1 0
      src/colorfulIcon/svg/alphabetical_sorting.svg
  80. 21 0
      src/colorfulIcon/svg/vab.svg
  81. 111 0
      src/components/JsonEditor/index.vue
  82. 201 0
      src/components/SelectTree/index.vue
  83. 191 0
      src/components/VabCharge/index.vue
  84. 92 0
      src/components/VabImage/index.vue
  85. 313 0
      src/components/VabProfile/index.vue
  86. 44 0
      src/components/VabQrCode/index.vue
  87. 82 0
      src/components/VabSnow/index.vue
  88. 95 0
      src/components/VabSticky/index.vue
  89. 267 0
      src/components/VabUpload/index.vue
  90. 85 0
      src/config/permission.js
  91. 101 0
      src/config/settings.js
  92. 53 0
      src/config/static.js
  93. 3 0
      src/layouts/EmptyLayout.vue
  94. 52 0
      src/layouts/components/Ad/index.vue
  95. 21 0
      src/layouts/components/index.js
  96. 313 0
      src/layouts/index.vue
  97. 23 0
      src/main.js
  98. 11 0
      src/plugins/echarts.js
  99. 9 0
      src/plugins/element.js
  100. 0 0
      src/plugins/index.js

+ 4 - 0
.browserslistrc

@@ -0,0 +1,4 @@
+> 1%
+last 2 versions
+not dead
+

+ 12 - 0
.editorconfig

@@ -0,0 +1,12 @@
+root = true
+
+[*]
+charset = utf-8
+end_of_line = lf
+indent_size = 2
+indent_style = space
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[*.md]
+trim_trailing_whitespace = false

+ 5 - 0
.eslintignore

@@ -0,0 +1,5 @@
+src/assets
+src/icons
+public
+dist
+node_modules

+ 26 - 0
.eslintrc.js

@@ -0,0 +1,26 @@
+module.exports = {
+  root: true,
+  env: {
+    node: true,
+  },
+  extends: ["plugin:vue/recommended", "@vue/prettier"],
+  rules: {
+    "no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
+    "no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off",
+    "vue/no-v-html": "off",
+  },
+  parserOptions: {
+    parser: "babel-eslint",
+  },
+  overrides: [
+    {
+      files: [
+        "**/__tests__/*.{j,t}s?(x)",
+        "**/tests/unit/**/*.spec.{j,t}s?(x)",
+      ],
+      env: {
+        jest: true,
+      },
+    },
+  ],
+};

+ 10 - 0
.gitattributes

@@ -0,0 +1,10 @@
+*.html text eol=lf
+*.css text eol=lf
+*.js text eol=lf
+*.scss text eol=lf
+*.vue text eol=lf
+*.hbs text eol=lf
+*.sh text eol=lf
+*.md text eol=lf
+*.json text eol=lf
+*.yml text eol=lf

+ 2 - 0
.github/FUNDING.yml

@@ -0,0 +1,2 @@
+patreon: chuzhixin
+

+ 16 - 0
.github/ISSUE_TEMPLATE/---------------.md

@@ -0,0 +1,16 @@
+---
+name: 问题提问(不按规范提问不解答)
+about: 详细描述你的问题
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+#### 出现的问题
+
+#### 操作了什么以后出现了的
+
+#### 详细的报错截图、控制台截图
+
+#### 是否已经百度过了、是否已经努力尝试解决了

+ 20 - 0
.gitignore

@@ -0,0 +1,20 @@
+.DS_Store
+node_modules
+dist
+.env.local
+.env.*.local
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+.idea
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
+public/video
+*.zip
+*.7z
+/src/layouts/components/zx-layouts
+/zx-templates
+/package-lock.json

+ 3 - 0
.stylelintrc.js

@@ -0,0 +1,3 @@
+module.exports = {
+  extends: ["stylelint-config-recess-order", "stylelint-config-prettier"],
+};

+ 52 - 0
.vscode/settings.json

@@ -0,0 +1,52 @@
+{
+  "[vue]": {
+    "editor.defaultFormatter": "esbenp.prettier-vscode"
+  },
+  "editor.quickSuggestions": {
+    "strings": true
+  },
+  "workbench.colorTheme": "One Monokai",
+  "editor.tabSize": 2,
+  "editor.detectIndentation": false,
+  "emmet.triggerExpansionOnTab": true,
+  "editor.formatOnSave": true,
+  "javascript.format.enable": true,
+  "git.enableSmartCommit": true,
+  "git.autofetch": true,
+  "git.confirmSync": false,
+  "[json]": {
+    "editor.defaultFormatter": "esbenp.prettier-vscode"
+  },
+  "liveServer.settings.donotShowInfoMsg": true,
+  "explorer.confirmDelete": false,
+  "javascript.updateImportsOnFileMove.enabled": "always",
+  "typescript.updateImportsOnFileMove.enabled": "always",
+  "files.exclude": {
+    "**/.idea": true
+  },
+  "editor.codeActionsOnSave": {
+    "source.fixAll.stylelint": true,
+    "source.fixAll.eslint": true
+  },
+  "[javascript]": {
+    "editor.defaultFormatter": "esbenp.prettier-vscode"
+  },
+  "[scss]": {
+    "editor.defaultFormatter": "esbenp.prettier-vscode"
+  },
+  "[jsonc]": {
+    "editor.defaultFormatter": "esbenp.prettier-vscode"
+  },
+  "[html]": {
+    "editor.defaultFormatter": "esbenp.prettier-vscode"
+  },
+  "editor.suggest.snippetsPreventQuickSuggestions": false,
+  "prettier.htmlWhitespaceSensitivity": "ignore",
+  "prettier.vueIndentScriptAndStyle": true,
+  "docthis.authorName": "chuzhixin 1204505056@qq.com",
+  "docthis.includeAuthorTag": true,
+  "docthis.includeDescriptionTag": true,
+  "docthis.enableHungarianNotationEvaluation": true,
+  "docthis.inferTypesFromNames": true,
+  "vetur.format.defaultFormatter.html": "prettier"
+}

+ 373 - 0
LICENSE

@@ -0,0 +1,373 @@
+Mozilla Public License Version 2.0
+==================================
+
+1. Definitions
+--------------
+
+1.1. "Contributor"
+    means each individual or legal entity that creates, contributes to
+    the creation of, or owns Covered Software.
+
+1.2. "Contributor Version"
+    means the combination of the Contributions of others (if any) used
+    by a Contributor and that particular Contributor's Contribution.
+
+1.3. "Contribution"
+    means Covered Software of a particular Contributor.
+
+1.4. "Covered Software"
+    means Source Code Form to which the initial Contributor has attached
+    the notice in Exhibit A, the Executable Form of such Source Code
+    Form, and Modifications of such Source Code Form, in each case
+    including portions thereof.
+
+1.5. "Incompatible With Secondary Licenses"
+    means
+
+    (a) that the initial Contributor has attached the notice described
+        in Exhibit B to the Covered Software; or
+
+    (b) that the Covered Software was made available under the terms of
+        version 1.1 or earlier of the License, but not also under the
+        terms of a Secondary License.
+
+1.6. "Executable Form"
+    means any form of the work other than Source Code Form.
+
+1.7. "Larger Work"
+    means a work that combines Covered Software with other material, in
+    a separate file or files, that is not Covered Software.
+
+1.8. "License"
+    means this document.
+
+1.9. "Licensable"
+    means having the right to grant, to the maximum extent possible,
+    whether at the time of the initial grant or subsequently, any and
+    all of the rights conveyed by this License.
+
+1.10. "Modifications"
+    means any of the following:
+
+    (a) any file in Source Code Form that results from an addition to,
+        deletion from, or modification of the contents of Covered
+        Software; or
+
+    (b) any new file in Source Code Form that contains any Covered
+        Software.
+
+1.11. "Patent Claims" of a Contributor
+    means any patent claim(s), including without limitation, method,
+    process, and apparatus claims, in any patent Licensable by such
+    Contributor that would be infringed, but for the grant of the
+    License, by the making, using, selling, offering for sale, having
+    made, import, or transfer of either its Contributions or its
+    Contributor Version.
+
+1.12. "Secondary License"
+    means either the GNU General Public License, Version 2.0, the GNU
+    Lesser General Public License, Version 2.1, the GNU Affero General
+    Public License, Version 3.0, or any later versions of those
+    licenses.
+
+1.13. "Source Code Form"
+    means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your")
+    means an individual or a legal entity exercising rights under this
+    License. For legal entities, "You" includes any entity that
+    controls, is controlled by, or is under common control with You. For
+    purposes of this definition, "control" means (a) the power, direct
+    or indirect, to cause the direction or management of such entity,
+    whether by contract or otherwise, or (b) ownership of more than
+    fifty percent (50%) of the outstanding shares or beneficial
+    ownership of such entity.
+
+2. License Grants and Conditions
+--------------------------------
+
+2.1. Grants
+
+Each Contributor hereby grants You a world-wide, royalty-free,
+non-exclusive license:
+
+(a) under intellectual property rights (other than patent or trademark)
+    Licensable by such Contributor to use, reproduce, make available,
+    modify, display, perform, distribute, and otherwise exploit its
+    Contributions, either on an unmodified basis, with Modifications, or
+    as part of a Larger Work; and
+
+(b) under Patent Claims of such Contributor to make, use, sell, offer
+    for sale, have made, import, and otherwise transfer either its
+    Contributions or its Contributor Version.
+
+2.2. Effective Date
+
+The licenses granted in Section 2.1 with respect to any Contribution
+become effective for each Contribution on the date the Contributor first
+distributes such Contribution.
+
+2.3. Limitations on Grant Scope
+
+The licenses granted in this Section 2 are the only rights granted under
+this License. No additional rights or licenses will be implied from the
+distribution or licensing of Covered Software under this License.
+Notwithstanding Section 2.1(b) above, no patent license is granted by a
+Contributor:
+
+(a) for any code that a Contributor has removed from Covered Software;
+    or
+
+(b) for infringements caused by: (i) Your and any other third party's
+    modifications of Covered Software, or (ii) the combination of its
+    Contributions with other software (except as part of its Contributor
+    Version); or
+
+(c) under Patent Claims infringed by Covered Software in the absence of
+    its Contributions.
+
+This License does not grant any rights in the trademarks, service marks,
+or logos of any Contributor (except as may be necessary to comply with
+the notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+No Contributor makes additional grants as a result of Your choice to
+distribute the Covered Software under a subsequent version of this
+License (see Section 10.2) or under the terms of a Secondary License (if
+permitted under the terms of Section 3.3).
+
+2.5. Representation
+
+Each Contributor represents that the Contributor believes its
+Contributions are its original creation(s) or it has sufficient rights
+to grant the rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+This License is not intended to limit any rights You have under
+applicable copyright doctrines of fair use, fair dealing, or other
+equivalents.
+
+2.7. Conditions
+
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
+in Section 2.1.
+
+3. Responsibilities
+-------------------
+
+3.1. Distribution of Source Form
+
+All distribution of Covered Software in Source Code Form, including any
+Modifications that You create or to which You contribute, must be under
+the terms of this License. You must inform recipients that the Source
+Code Form of the Covered Software is governed by the terms of this
+License, and how they can obtain a copy of this License. You may not
+attempt to alter or restrict the recipients' rights in the Source Code
+Form.
+
+3.2. Distribution of Executable Form
+
+If You distribute Covered Software in Executable Form then:
+
+(a) such Covered Software must also be made available in Source Code
+    Form, as described in Section 3.1, and You must inform recipients of
+    the Executable Form how they can obtain a copy of such Source Code
+    Form by reasonable means in a timely manner, at a charge no more
+    than the cost of distribution to the recipient; and
+
+(b) You may distribute such Executable Form under the terms of this
+    License, or sublicense it under different terms, provided that the
+    license for the Executable Form does not attempt to limit or alter
+    the recipients' rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+You may create and distribute a Larger Work under terms of Your choice,
+provided that You also comply with the requirements of this License for
+the Covered Software. If the Larger Work is a combination of Covered
+Software with a work governed by one or more Secondary Licenses, and the
+Covered Software is not Incompatible With Secondary Licenses, this
+License permits You to additionally distribute such Covered Software
+under the terms of such Secondary License(s), so that the recipient of
+the Larger Work may, at their option, further distribute the Covered
+Software under the terms of either this License or such Secondary
+License(s).
+
+3.4. Notices
+
+You may not remove or alter the substance of any license notices
+(including copyright notices, patent notices, disclaimers of warranty,
+or limitations of liability) contained within the Source Code Form of
+the Covered Software, except that You may alter any license notices to
+the extent required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+You may choose to offer, and to charge a fee for, warranty, support,
+indemnity or liability obligations to one or more recipients of Covered
+Software. However, You may do so only on Your own behalf, and not on
+behalf of any Contributor. You must make it absolutely clear that any
+such warranty, support, indemnity, or liability obligation is offered by
+You alone, and You hereby agree to indemnify every Contributor for any
+liability incurred by such Contributor as a result of warranty, support,
+indemnity or liability terms You offer. You may include additional
+disclaimers of warranty and limitations of liability specific to any
+jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+---------------------------------------------------
+
+If it is impossible for You to comply with any of the terms of this
+License with respect to some or all of the Covered Software due to
+statute, judicial order, or regulation then You must: (a) comply with
+the terms of this License to the maximum extent possible; and (b)
+describe the limitations and the code they affect. Such description must
+be placed in a text file included with all distributions of the Covered
+Software under this License. Except to the extent prohibited by statute
+or regulation, such description must be sufficiently detailed for a
+recipient of ordinary skill to be able to understand it.
+
+5. Termination
+--------------
+
+5.1. The rights granted under this License will terminate automatically
+if You fail to comply with any of its terms. However, if You become
+compliant, then the rights granted under this License from a particular
+Contributor are reinstated (a) provisionally, unless and until such
+Contributor explicitly and finally terminates Your grants, and (b) on an
+ongoing basis, if such Contributor fails to notify You of the
+non-compliance by some reasonable means prior to 60 days after You have
+come back into compliance. Moreover, Your grants from a particular
+Contributor are reinstated on an ongoing basis if such Contributor
+notifies You of the non-compliance by some reasonable means, this is the
+first time You have received notice of non-compliance with this License
+from such Contributor, and You become compliant prior to 30 days after
+Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+infringement claim (excluding declaratory judgment actions,
+counter-claims, and cross-claims) alleging that a Contributor Version
+directly or indirectly infringes any patent, then the rights granted to
+You by any and all Contributors for the Covered Software under Section
+2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all
+end user license agreements (excluding distributors and resellers) which
+have been validly granted by You or Your distributors under this License
+prior to termination shall survive termination.
+
+************************************************************************
+*                                                                      *
+*  6. Disclaimer of Warranty                                           *
+*  -------------------------                                           *
+*                                                                      *
+*  Covered Software is provided under this License on an "as is"       *
+*  basis, without warranty of any kind, either expressed, implied, or  *
+*  statutory, including, without limitation, warranties that the       *
+*  Covered Software is free of defects, merchantable, fit for a        *
+*  particular purpose or non-infringing. The entire risk as to the     *
+*  quality and performance of the Covered Software is with You.        *
+*  Should any Covered Software prove defective in any respect, You     *
+*  (not any Contributor) assume the cost of any necessary servicing,   *
+*  repair, or correction. This disclaimer of warranty constitutes an   *
+*  essential part of this License. No use of any Covered Software is   *
+*  authorized under this License except under this disclaimer.         *
+*                                                                      *
+************************************************************************
+
+************************************************************************
+*                                                                      *
+*  7. Limitation of Liability                                          *
+*  --------------------------                                          *
+*                                                                      *
+*  Under no circumstances and under no legal theory, whether tort      *
+*  (including negligence), contract, or otherwise, shall any           *
+*  Contributor, or anyone who distributes Covered Software as          *
+*  permitted above, be liable to You for any direct, indirect,         *
+*  special, incidental, or consequential damages of any character      *
+*  including, without limitation, damages for lost profits, loss of    *
+*  goodwill, work stoppage, computer failure or malfunction, or any    *
+*  and all other commercial damages or losses, even if such party      *
+*  shall have been informed of the possibility of such damages. This   *
+*  limitation of liability shall not apply to liability for death or   *
+*  personal injury resulting from such party's negligence to the       *
+*  extent applicable law prohibits such limitation. Some               *
+*  jurisdictions do not allow the exclusion or limitation of           *
+*  incidental or consequential damages, so this exclusion and          *
+*  limitation may not apply to You.                                    *
+*                                                                      *
+************************************************************************
+
+8. Litigation
+-------------
+
+Any litigation relating to this License may be brought only in the
+courts of a jurisdiction where the defendant maintains its principal
+place of business and such litigation shall be governed by laws of that
+jurisdiction, without reference to its conflict-of-law provisions.
+Nothing in this Section shall prevent a party's ability to bring
+cross-claims or counter-claims.
+
+9. Miscellaneous
+----------------
+
+This License represents the complete agreement concerning the subject
+matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent
+necessary to make it enforceable. Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+shall not be used to construe this License against a Contributor.
+
+10. Versions of the License
+---------------------------
+
+10.1. New Versions
+
+Mozilla Foundation is the license steward. Except as provided in Section
+10.3, no one other than the license steward has the right to modify or
+publish new versions of this License. Each version will be given a
+distinguishing version number.
+
+10.2. Effect of New Versions
+
+You may distribute the Covered Software under the terms of the version
+of the License under which You originally received the Covered Software,
+or under the terms of any subsequent version published by the license
+steward.
+
+10.3. Modified Versions
+
+If you create software not governed by this License, and you want to
+create a new license for such software, you may create and use a
+modified version of this License if you rename the license and remove
+any references to the name of the license steward (except to note that
+such modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary
+Licenses
+
+If You choose to distribute Source Code Form that is Incompatible With
+Secondary Licenses under the terms of this version of the License, the
+notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+-------------------------------------------
+
+  This Source Code Form is subject to the terms of the Mozilla Public
+  License, v. 2.0. If a copy of the MPL was not distributed with this
+  file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular
+file, then You may include the notice in a location (such as a LICENSE
+file in a relevant directory) where a recipient would be likely to look
+for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+---------------------------------------------------------
+
+  This Source Code Form is "Incompatible With Secondary Licenses", as
+  defined by the Mozilla Public License, v. 2.0.

+ 43 - 0
README-DCLOUD.md

@@ -0,0 +1,43 @@
+<div align="center"><img width="200" src="https://gitee.com/chu1204505056/vue-admin-beautiful/raw/master/src/colorfulIcon/svg/vab.svg"/>
+<h1> vue-admin-beautiful </h1>
+<h3>一款基于 vue+element-ui 的绝佳的通用型、中后台前端框架</h3>
+<h3>An excellent general-purpose, middle and background front-end framework based on Vue + element UI</h3>
+</div>
+
+[![](https://img.shields.io/github/stars/chuzhixin/vue-admin-beautiful?style=flat-square&label=Stars&logo=github)
+](https://github.com/chuzhixin/vue-admin-beautiful)
+
+## 演示地址
+
+### - [🚀 演示地址:vue-admin-beautiful (横向纵向布局无缝切换)](https://chu1204505056.gitee.io/vue-admin-beautiful/?hmsr=%E6%8F%92%E4%BB%B6%E5%B8%82%E5%9C%BA&hmpl=&hmcu=&hmkw=&hmci=)
+
+### - [🚀 vue-admin-beautiful-pro 版演示地址](https://chu1204505056.gitee.io/vue-admin-beautiful-pro/?hmsr=%E6%8F%92%E4%BB%B6%E5%B8%82%E5%9C%BA&hmpl=&hmcu=&hmkw=&hmci=)
+
+### - [🚀 vue-admin-beautiful-mini vue3.0 预览版地址](https://chu1204505056.gitee.io/vue-admin-beautiful-mini/?hmsr=%E6%8F%92%E4%BB%B6%E5%B8%82%E5%9C%BA&hmpl=&hmcu=&hmkw=&hmci=)
+
+## vue-admin-beautiful 前端讨论群-1 972435319
+
+不管您加或者不加,您都可以享受到开源的代码,感谢您的支持和信任,群内提供 vue-admin-beautiful-template 基础版本和详细的基础使用文档适合框架快速入门
+
+![img](https://chu1204505056.gitee.io/vabBooks/img/ewm.png)
+
+## 安装
+
+```bash
+# 克隆项目
+git clone https://github.com/chuzhixin/vue-admin-beautiful.git
+# 进入项目目录
+npm vue-admin-beautiful
+# 安装依赖
+npm i
+# 本地开发 启动项目
+cnpm run serve
+```
+
+#### github 标星增长量统计
+
+[![Stargazers over time](https://starcharts.herokuapp.com/chuzhixin/vue-admin-beautiful.svg)](https://github.com/chuzhixin/vue-admin-beautiful)
+
+#### 开发者评级
+
+[![chuzhixin's github stats](https://github-readme-stats.vercel.app/api?username=chuzhixin)](https://github.com/chuzhixin/vue-admin-beautiful)

File diff suppressed because it is too large
+ 321 - 0
README.md


+ 21 - 0
SECURITY.md

@@ -0,0 +1,21 @@
+# Security Policy
+
+## Supported Versions
+
+Use this section to tell people about which versions of your project are
+currently being supported with security updates.
+
+| Version | Supported          |
+| ------- | ------------------ |
+| 5.1.x   | :white_check_mark: |
+| 5.0.x   | :x:                |
+| 4.0.x   | :white_check_mark: |
+| < 4.0   | :x:                |
+
+## Reporting a Vulnerability
+
+Use this section to tell people how to report a vulnerability.
+
+Tell them where to go, how often they can expect to get an update on a
+reported vulnerability, what to expect if the vulnerability is accepted or
+declined, etc.

+ 3 - 0
babel.config.js

@@ -0,0 +1,3 @@
+module.exports = {
+  presets: ["@vue/cli-plugin-babel/preset"],
+};

+ 17 - 0
deploy.sh

@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+set -e
+npm run build
+cd dist
+touch .nojekyll
+git init
+git add -A
+git commit -m '🎉🎉🎉仓库重置到2020年9月29日,Vue2.6最后一个版本,之前版本不再支持,具体请查阅文档,Vue 3.0版本请耐心等待!!!'
+git push -f "https://${access_token}@gitee.com/chu1204505056/vue-admin-beautiful.git" master:gh-pages
+start "https://gitee.com/chu1204505056/vue-admin-beautiful/pages"
+git push -f "https://${access_token}@github.com/chuzhixin/vue-admin-beautiful.git" master:gh-pages
+cd -
+exec /bin/bash
+
+
+
+

+ 70 - 0
http/mock.http

@@ -0,0 +1,70 @@
+
+###/changeLog/getList###mockServer
+POST http://localhost:80/mock-server/changeLog/getList
+Content-Type: application/x-www-form-urlencoded
+###
+mockServer
+###/colorfulIcon/list###
+POST http://localhost:80/mock-server/colorfulIcon/list
+Content-Type: application/x-www-form-urlencoded
+###mockServer
+
+###/menu/navigate###
+POST http://localhost:80/mock-server/menu/navigate
+Content-Type: application/x-www-form-urlenmockServer
+###
+
+###/icon/list###
+POST http://localhost:80/mock-server/icon/mockServer
+Content-Type: application/x-www-form-urlencoded
+###
+
+###/face/list###mockServer
+POST http://localhost:80/mock-server/face/list
+Content-Type: application/x-www-form-urlencoded
+###
+mockServer
+###/table/list###
+POST http://localhost:80/mock-server/table/list
+Content-Type: application/x-www-form-urlencoded
+###mockServer
+
+###/remixicon/getList###
+POST http://localhost:80/mock-server/remixicon/getList
+Content-Type: application/x-www-form-urlenmockServer
+###
+
+###/publicKey###
+POST http://localhost:80/mock-server/pumockServer
+Content-Type: application/x-www-form-urlencoded
+###
+
+###/tree/list###mockServer
+POST http://localhost:80/mock-server/tree/list
+Content-Type: application/x-www-form-urlencoded
+###
+mockServer
+###/upload###
+POST http://localhost:80/mock-server/upload
+Content-Type: application/x-www-form-urlencoded
+###mockServer
+
+###/login###
+POST http://localhost:80/mock-server/login
+Content-Type: application/x-www-form-urlenmockServer
+###
+
+###/waterfall/list###
+POST http://localhost:80/mock-server/waterfall/list
+Content-Type: application/x-www-form-urlencoded
+###
+
+###/logout###
+POST http://localhost:80/mock-server/logout
+Content-Type: application/x-www-form-urlencoded
+###
+
+###/userInfo###
+POST http://localhost:80/mock-server/userInfo
+Content-Type: application/x-www-form-urlencoded
+###

+ 373 - 0
license.md

@@ -0,0 +1,373 @@
+Mozilla Public License Version 2.0
+==================================
+
+1. Definitions
+--------------
+
+1.1. "Contributor"
+    means each individual or legal entity that creates, contributes to
+    the creation of, or owns Covered Software.
+
+1.2. "Contributor Version"
+    means the combination of the Contributions of others (if any) used
+    by a Contributor and that particular Contributor's Contribution.
+
+1.3. "Contribution"
+    means Covered Software of a particular Contributor.
+
+1.4. "Covered Software"
+    means Source Code Form to which the initial Contributor has attached
+    the notice in Exhibit A, the Executable Form of such Source Code
+    Form, and Modifications of such Source Code Form, in each case
+    including portions thereof.
+
+1.5. "Incompatible With Secondary Licenses"
+    means
+
+    (a) that the initial Contributor has attached the notice described
+        in Exhibit B to the Covered Software; or
+
+    (b) that the Covered Software was made available under the terms of
+        version 1.1 or earlier of the License, but not also under the
+        terms of a Secondary License.
+
+1.6. "Executable Form"
+    means any form of the work other than Source Code Form.
+
+1.7. "Larger Work"
+    means a work that combines Covered Software with other material, in
+    a separate file or files, that is not Covered Software.
+
+1.8. "License"
+    means this document.
+
+1.9. "Licensable"
+    means having the right to grant, to the maximum extent possible,
+    whether at the time of the initial grant or subsequently, any and
+    all of the rights conveyed by this License.
+
+1.10. "Modifications"
+    means any of the following:
+
+    (a) any file in Source Code Form that results from an addition to,
+        deletion from, or modification of the contents of Covered
+        Software; or
+
+    (b) any new file in Source Code Form that contains any Covered
+        Software.
+
+1.11. "Patent Claims" of a Contributor
+    means any patent claim(s), including without limitation, method,
+    process, and apparatus claims, in any patent Licensable by such
+    Contributor that would be infringed, but for the grant of the
+    License, by the making, using, selling, offering for sale, having
+    made, import, or transfer of either its Contributions or its
+    Contributor Version.
+
+1.12. "Secondary License"
+    means either the GNU General Public License, Version 2.0, the GNU
+    Lesser General Public License, Version 2.1, the GNU Affero General
+    Public License, Version 3.0, or any later versions of those
+    licenses.
+
+1.13. "Source Code Form"
+    means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your")
+    means an individual or a legal entity exercising rights under this
+    License. For legal entities, "You" includes any entity that
+    controls, is controlled by, or is under common control with You. For
+    purposes of this definition, "control" means (a) the power, direct
+    or indirect, to cause the direction or management of such entity,
+    whether by contract or otherwise, or (b) ownership of more than
+    fifty percent (50%) of the outstanding shares or beneficial
+    ownership of such entity.
+
+2. License Grants and Conditions
+--------------------------------
+
+2.1. Grants
+
+Each Contributor hereby grants You a world-wide, royalty-free,
+non-exclusive license:
+
+(a) under intellectual property rights (other than patent or trademark)
+    Licensable by such Contributor to use, reproduce, make available,
+    modify, display, perform, distribute, and otherwise exploit its
+    Contributions, either on an unmodified basis, with Modifications, or
+    as part of a Larger Work; and
+
+(b) under Patent Claims of such Contributor to make, use, sell, offer
+    for sale, have made, import, and otherwise transfer either its
+    Contributions or its Contributor Version.
+
+2.2. Effective Date
+
+The licenses granted in Section 2.1 with respect to any Contribution
+become effective for each Contribution on the date the Contributor first
+distributes such Contribution.
+
+2.3. Limitations on Grant Scope
+
+The licenses granted in this Section 2 are the only rights granted under
+this License. No additional rights or licenses will be implied from the
+distribution or licensing of Covered Software under this License.
+Notwithstanding Section 2.1(b) above, no patent license is granted by a
+Contributor:
+
+(a) for any code that a Contributor has removed from Covered Software;
+    or
+
+(b) for infringements caused by: (i) Your and any other third party's
+    modifications of Covered Software, or (ii) the combination of its
+    Contributions with other software (except as part of its Contributor
+    Version); or
+
+(c) under Patent Claims infringed by Covered Software in the absence of
+    its Contributions.
+
+This License does not grant any rights in the trademarks, service marks,
+or logos of any Contributor (except as may be necessary to comply with
+the notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+No Contributor makes additional grants as a result of Your choice to
+distribute the Covered Software under a subsequent version of this
+License (see Section 10.2) or under the terms of a Secondary License (if
+permitted under the terms of Section 3.3).
+
+2.5. Representation
+
+Each Contributor represents that the Contributor believes its
+Contributions are its original creation(s) or it has sufficient rights
+to grant the rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+This License is not intended to limit any rights You have under
+applicable copyright doctrines of fair use, fair dealing, or other
+equivalents.
+
+2.7. Conditions
+
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
+in Section 2.1.
+
+3. Responsibilities
+-------------------
+
+3.1. Distribution of Source Form
+
+All distribution of Covered Software in Source Code Form, including any
+Modifications that You create or to which You contribute, must be under
+the terms of this License. You must inform recipients that the Source
+Code Form of the Covered Software is governed by the terms of this
+License, and how they can obtain a copy of this License. You may not
+attempt to alter or restrict the recipients' rights in the Source Code
+Form.
+
+3.2. Distribution of Executable Form
+
+If You distribute Covered Software in Executable Form then:
+
+(a) such Covered Software must also be made available in Source Code
+    Form, as described in Section 3.1, and You must inform recipients of
+    the Executable Form how they can obtain a copy of such Source Code
+    Form by reasonable means in a timely manner, at a charge no more
+    than the cost of distribution to the recipient; and
+
+(b) You may distribute such Executable Form under the terms of this
+    License, or sublicense it under different terms, provided that the
+    license for the Executable Form does not attempt to limit or alter
+    the recipients' rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+You may create and distribute a Larger Work under terms of Your choice,
+provided that You also comply with the requirements of this License for
+the Covered Software. If the Larger Work is a combination of Covered
+Software with a work governed by one or more Secondary Licenses, and the
+Covered Software is not Incompatible With Secondary Licenses, this
+License permits You to additionally distribute such Covered Software
+under the terms of such Secondary License(s), so that the recipient of
+the Larger Work may, at their option, further distribute the Covered
+Software under the terms of either this License or such Secondary
+License(s).
+
+3.4. Notices
+
+You may not remove or alter the substance of any license notices
+(including copyright notices, patent notices, disclaimers of warranty,
+or limitations of liability) contained within the Source Code Form of
+the Covered Software, except that You may alter any license notices to
+the extent required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+You may choose to offer, and to charge a fee for, warranty, support,
+indemnity or liability obligations to one or more recipients of Covered
+Software. However, You may do so only on Your own behalf, and not on
+behalf of any Contributor. You must make it absolutely clear that any
+such warranty, support, indemnity, or liability obligation is offered by
+You alone, and You hereby agree to indemnify every Contributor for any
+liability incurred by such Contributor as a result of warranty, support,
+indemnity or liability terms You offer. You may include additional
+disclaimers of warranty and limitations of liability specific to any
+jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+---------------------------------------------------
+
+If it is impossible for You to comply with any of the terms of this
+License with respect to some or all of the Covered Software due to
+statute, judicial order, or regulation then You must: (a) comply with
+the terms of this License to the maximum extent possible; and (b)
+describe the limitations and the code they affect. Such description must
+be placed in a text file included with all distributions of the Covered
+Software under this License. Except to the extent prohibited by statute
+or regulation, such description must be sufficiently detailed for a
+recipient of ordinary skill to be able to understand it.
+
+5. Termination
+--------------
+
+5.1. The rights granted under this License will terminate automatically
+if You fail to comply with any of its terms. However, if You become
+compliant, then the rights granted under this License from a particular
+Contributor are reinstated (a) provisionally, unless and until such
+Contributor explicitly and finally terminates Your grants, and (b) on an
+ongoing basis, if such Contributor fails to notify You of the
+non-compliance by some reasonable means prior to 60 days after You have
+come back into compliance. Moreover, Your grants from a particular
+Contributor are reinstated on an ongoing basis if such Contributor
+notifies You of the non-compliance by some reasonable means, this is the
+first time You have received notice of non-compliance with this License
+from such Contributor, and You become compliant prior to 30 days after
+Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+infringement claim (excluding declaratory judgment actions,
+counter-claims, and cross-claims) alleging that a Contributor Version
+directly or indirectly infringes any patent, then the rights granted to
+You by any and all Contributors for the Covered Software under Section
+2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all
+end user license agreements (excluding distributors and resellers) which
+have been validly granted by You or Your distributors under this License
+prior to termination shall survive termination.
+
+************************************************************************
+*                                                                      *
+*  6. Disclaimer of Warranty                                           *
+*  -------------------------                                           *
+*                                                                      *
+*  Covered Software is provided under this License on an "as is"       *
+*  basis, without warranty of any kind, either expressed, implied, or  *
+*  statutory, including, without limitation, warranties that the       *
+*  Covered Software is free of defects, merchantable, fit for a        *
+*  particular purpose or non-infringing. The entire risk as to the     *
+*  quality and performance of the Covered Software is with You.        *
+*  Should any Covered Software prove defective in any respect, You     *
+*  (not any Contributor) assume the cost of any necessary servicing,   *
+*  repair, or correction. This disclaimer of warranty constitutes an   *
+*  essential part of this License. No use of any Covered Software is   *
+*  authorized under this License except under this disclaimer.         *
+*                                                                      *
+************************************************************************
+
+************************************************************************
+*                                                                      *
+*  7. Limitation of Liability                                          *
+*  --------------------------                                          *
+*                                                                      *
+*  Under no circumstances and under no legal theory, whether tort      *
+*  (including negligence), contract, or otherwise, shall any           *
+*  Contributor, or anyone who distributes Covered Software as          *
+*  permitted above, be liable to You for any direct, indirect,         *
+*  special, incidental, or consequential damages of any character      *
+*  including, without limitation, damages for lost profits, loss of    *
+*  goodwill, work stoppage, computer failure or malfunction, or any    *
+*  and all other commercial damages or losses, even if such party      *
+*  shall have been informed of the possibility of such damages. This   *
+*  limitation of liability shall not apply to liability for death or   *
+*  personal injury resulting from such party's negligence to the       *
+*  extent applicable law prohibits such limitation. Some               *
+*  jurisdictions do not allow the exclusion or limitation of           *
+*  incidental or consequential damages, so this exclusion and          *
+*  limitation may not apply to You.                                    *
+*                                                                      *
+************************************************************************
+
+8. Litigation
+-------------
+
+Any litigation relating to this License may be brought only in the
+courts of a jurisdiction where the defendant maintains its principal
+place of business and such litigation shall be governed by laws of that
+jurisdiction, without reference to its conflict-of-law provisions.
+Nothing in this Section shall prevent a party's ability to bring
+cross-claims or counter-claims.
+
+9. Miscellaneous
+----------------
+
+This License represents the complete agreement concerning the subject
+matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent
+necessary to make it enforceable. Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+shall not be used to construe this License against a Contributor.
+
+10. Versions of the License
+---------------------------
+
+10.1. New Versions
+
+Mozilla Foundation is the license steward. Except as provided in Section
+10.3, no one other than the license steward has the right to modify or
+publish new versions of this License. Each version will be given a
+distinguishing version number.
+
+10.2. Effect of New Versions
+
+You may distribute the Covered Software under the terms of the version
+of the License under which You originally received the Covered Software,
+or under the terms of any subsequent version published by the license
+steward.
+
+10.3. Modified Versions
+
+If you create software not governed by this License, and you want to
+create a new license for such software, you may create and use a
+modified version of this License if you rename the license and remove
+any references to the name of the license steward (except to note that
+such modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary
+Licenses
+
+If You choose to distribute Source Code Form that is Incompatible With
+Secondary Licenses under the terms of this version of the License, the
+notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+-------------------------------------------
+
+  This Source Code Form is subject to the terms of the Mozilla Public
+  License, v. 2.0. If a copy of the MPL was not distributed with this
+  file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular
+file, then You may include the notice in a location (such as a LICENSE
+file in a relevant directory) where a recipient would be likely to look
+for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+---------------------------------------------------------
+
+  This Source Code Form is "Incompatible With Secondary Licenses", as
+  defined by the Mozilla Public License, v. 2.0.

+ 19 - 0
mock/controller/ad.js

@@ -0,0 +1,19 @@
+const data = [
+  {
+    title: "vue-admin-beautiful-pro beta版本已发布,点我提前体验",
+    url: "https://chu1204505056.gitee.io/vue-admin-beautiful-pro/#/index",
+  },
+];
+module.exports = [
+  {
+    url: "/ad/getList",
+    type: "get",
+    response() {
+      return {
+        code: 200,
+        msg: "success",
+        data,
+      };
+    },
+  },
+];

+ 87 - 0
mock/controller/blacklist.js

@@ -0,0 +1,87 @@
+const data = [
+  {
+    name: "奉/fendou飘逸的梦",
+    qq: "812770127",
+    excuse: "上来就开骂,不可原谅",
+  },
+  {
+    name: "江荻",
+    qq: "2324945654",
+    excuse: "上来就开骂,不可原谅",
+  },
+  {
+    name: "Diamond",
+    qq: "494904935",
+    excuse: "跟我道歉可以选择原谅",
+  },
+  {
+    name: "Mr、无涯",
+    qq: "2198457489",
+    excuse: "已原谅",
+  },
+  {
+    name: "玩世不恭丶江小白",
+    qq: "1779263221",
+    excuse: "睁眼说瞎话",
+  },
+  {
+    name: "福州客家网络科技有限公司(潘芳林等兄弟二人)",
+    qq: "1409198410、1778486252",
+    excuse:
+      "剽窃、破解框架授权并发布到网上还伪装成善人,公开道歉并尊重我的劳动成果可以选择原谅",
+  },
+  {
+    name: "willina",
+    qq: "405522648",
+    excuse:
+      "上来就开骂道:You and your git submit are just a rubbish,不可原谅",
+  },
+  {
+    name: "7(赵海鹏)",
+    qq: "252334666",
+    excuse: "欺骗两个善良的小姑娘,做完项目不付70%的尾款,强烈抵制",
+  },
+  {
+    name: "生活,一半记忆.一半继续",
+    qq: "252667193",
+    excuse: "30多岁,不学无术,造谣抹黑,不可原谅",
+  },
+  {
+    name: "AIRLOO",
+    qq: "5971794",
+    excuse: "已原谅",
+  },
+  {
+    name: "master Z",
+    qq: "1832819123",
+    excuse: "不尊重别人的劳动成果,认为开源就得无偿替他服务,不可原谅",
+  },
+  {
+    name: "想象中。。。",
+    qq: "329492979",
+    excuse: "不尊重别人的劳动成果,认为开源就得无偿替他服务,不可原谅",
+  },
+  {
+    name: "苏潍—菏泽微智科技",
+    qq: "328580081",
+    excuse: "无言以对",
+  },
+  {
+    name: "罗阳",
+    qq: "1320168680",
+    excuse: "不尊重别人的劳动成果,认为开源就得无偿替他服务,不可原谅",
+  },
+];
+module.exports = [
+  {
+    url: "/blacklist/getList",
+    type: "post",
+    response() {
+      return {
+        code: 200,
+        msg: "success",
+        data,
+      };
+    },
+  },
+];

+ 200 - 0
mock/controller/changeLog.js

@@ -0,0 +1,200 @@
+const data = [
+  {
+    content: "在github上获得了第一个star,感恩一位名叫Bequiet2014的github用户",
+    timestamp: "2020-03-23",
+  },
+  {
+    content: "增加更换主题功能",
+    timestamp: "2020-04-10",
+  },
+  {
+    content: "大幅精简代码",
+    timestamp: "2020-04-14",
+  },
+  {
+    content: "修复群友反馈的bug",
+    timestamp: "2020-04-16",
+  },
+  {
+    content: "剔除maptalks",
+    timestamp: "2020-04-17",
+  },
+  {
+    content:
+      "换行符统一修改为lf 支持苹果 linux windows协同开发 强制开启最严格eslint规则 不要哭 严格是有好处的",
+    timestamp: "2020-04-17",
+  },
+  {
+    content: "彻底完成手机端适配,记录这一天熬夜到了晚上三点",
+    timestamp: "2020-04-18",
+  },
+  {
+    content:
+      "删除babel-polyfill 提高打包速度 减少压缩体积(放弃ie是这个项目做出的最伟大的决定)",
+    timestamp: "2020-04-18",
+  },
+  {
+    content: "源码精简至800k",
+    timestamp: "2020-04-19",
+  },
+  {
+    content: "添加视频播放器组件",
+    timestamp: "2020-04-20",
+  },
+  {
+    content: "修复路由懒加载 完善主题配色",
+    timestamp: "2020-04-22",
+  },
+  {
+    content: "修复全局axios拦截 加快动画展示效果 修改登录页样式",
+    timestamp: "2020-04-24",
+  },
+  {
+    content: "简化权限与登录逻辑 更新mockServer",
+    timestamp: "2020-04-25",
+  },
+  {
+    content: "优化登录退出逻辑 代码更清晰 退出不再重载网页 改为重载路由形式",
+    timestamp: "2020-04-26",
+  },
+  {
+    content: "无端的指责只会让我更加努力 修复sidebar 简化permission",
+    timestamp: "2020-04-28",
+  },
+  {
+    content: "又是一个深夜 实现了表格增删改查的一键生成",
+    timestamp: "2020-04-30",
+  },
+  {
+    content: "大幅优化tagsview标签动画",
+    timestamp: "2020-05-02",
+  },
+  {
+    content: "三种图标组件实现mock模拟分页",
+    timestamp: "2020-05-03",
+  },
+  {
+    content: "添加了markdown编辑器组件",
+    timestamp: "2020-05-04",
+  },
+  {
+    content: "添加stylelint-plus自动规整排序样式",
+    timestamp: "2020-05-06",
+  },
+  {
+    content: "添加商城模板",
+    timestamp: "2020-05-12",
+  },
+  {
+    content: "github标星超过1000 感恩",
+    timestamp: "2020-05-13",
+  },
+  {
+    content: "添加验证码组件",
+    timestamp: "2020-05-14",
+  },
+  {
+    content: "修复横向菜单bug",
+    timestamp: "2020-05-16",
+  },
+  {
+    content: "又被人骂了 挺好的 让我下定决心重写了tagsBar",
+    timestamp: "2020-05-20",
+  },
+  {
+    content: "仿ant-design 添加雪花屏",
+    timestamp: "2020-05-26",
+  },
+  {
+    content: "添加人员管理模块",
+    timestamp: "2020-06-02",
+  },
+  {
+    content: "github标星超过2000 感恩",
+    timestamp: "2020-06-03",
+  },
+  {
+    content: "添加炫酷地图组件",
+    timestamp: "2020-06-11",
+  },
+  {
+    content: "抽离更多公共配置,框架使用更顺手",
+    timestamp: "2020-06-19",
+  },
+  {
+    content: "彻底完成了tagsbar多标签页的重构",
+    timestamp: "2020-06-22",
+  },
+  {
+    content: "感恩github标星过3.0K 祝大家端午节快乐",
+    timestamp: "2020-06-25",
+  },
+  {
+    content: "彻底重构了SideBar与TopBar 大幅精简dom渲染逻辑 全球首发",
+    timestamp: "2020-06-25",
+  },
+  {
+    content: "添加菜单管理",
+    timestamp: "2020-07-7",
+  },
+  {
+    content: "首次采用sass-loader 9.0写法,感谢github用户 shaonialife",
+    timestamp: "2020-07-7",
+  },
+  {
+    content: "添加vue-amap组件",
+    timestamp: "2020-07-11",
+  },
+  {
+    content: "修改zx-layouts引入方式",
+    timestamp: "2020-07-15",
+  },
+  {
+    content:
+      "记录这一天vue-admin-beautiful在插件市场、百度已花费超过1万元广告费用,希望一切都值得",
+    timestamp: "2020-07-18",
+  },
+  {
+    content: "主题配置添加海洋之心、绿荫草场、荣耀典藏、暗黑之子模式",
+    timestamp: "2020-07-18",
+  },
+  {
+    content: "全局axios请求全面支持Status Code拦截处理",
+    timestamp: "2020-07-29",
+  },
+  {
+    content: "重构全局loadding加载代码",
+    timestamp: "2020-07-31",
+  },
+  {
+    content: "升级stylelint自动排序功能",
+    timestamp: "2020-08-25",
+  },
+  {
+    content: "修复视频播放器组件重载路由失效的bug",
+    timestamp: "2020-09-03",
+  },
+  {
+    content: "修复极个别情况image-loader打包报错",
+    timestamp: "2020-09-18",
+  },
+  {
+    content: "全网首个基于vue3.0开发的admin框架已发布,具体请访问github",
+    timestamp: "2020-09-22",
+  },
+];
+
+module.exports = [
+  {
+    url: "/changeLog/getList",
+    type: "post",
+    response() {
+      return {
+        code: 200,
+        msg: "success",
+        totalCount: 999,
+        data: data,
+      };
+    },
+  },
+];

+ 328 - 0
mock/controller/colorfulIcon.js

@@ -0,0 +1,328 @@
+const data = [
+  "alphabetical_sorting",
+  "advance",
+  "address_book",
+  "alphabetical_sorting",
+  "advertising",
+  "alarm_clock",
+  "area_chart",
+  "approval",
+  "answers",
+  "approve",
+  "assistant",
+  "audio_file",
+  "automotive",
+  "automatic",
+  "bad_decision",
+  "bar_chart",
+  "bearish",
+  "biomass",
+  "biohazard",
+  "binoculars",
+  "bookmark",
+  "briefcase",
+  "biotech",
+  "broken_link",
+  "business",
+  "bullish",
+  "business_contact",
+  "businesswoman",
+  "cable_release",
+  "calculator",
+  "businessman",
+  "calendar",
+  "butting_in",
+  "call_transfer",
+  "callback",
+  "camcorder",
+  "camera",
+  "camcorder_pro",
+  "cancel",
+  "camera_addon",
+  "camera_identificatio",
+  "capacitor",
+  "candle_sticks",
+  "checkmark",
+  "circuit",
+  "charge_battery",
+  "clear_filters",
+  "clapperboard",
+  "clock",
+  "close_up_mode",
+  "collaboration",
+  "cell_phone",
+  "collapse",
+  "collect",
+  "cloth",
+  "combo_chart",
+  "comments",
+  "conference_call",
+  "compact_camera",
+  "contacts",
+  "copyleft",
+  "copyright",
+  "crystal_oscillator",
+  "cursor",
+  "currency_exchange",
+  "customer_support",
+  "dam",
+  "data_backup",
+  "data_configuration",
+  "data_encryption",
+  "data_protection",
+  "data_recovery",
+  "database",
+  "data_sheet",
+  "debt",
+  "decision",
+  "delete_column",
+  "delete_database",
+  "department",
+  "delete_row",
+  "deployment",
+  "dislike",
+  "disapprove",
+  "disclaimer",
+  "display",
+  "document",
+  "do_not_insert",
+  "do_not_mix",
+  "do_not_inhale",
+  "donate",
+  "down",
+  "doughnut_chart",
+  "down_left",
+  "down_right",
+  "download",
+  "edit_image",
+  "electrical_sensor",
+  "electrical_threshold",
+  "electricity",
+  "electro_devices",
+  "electronics",
+  "empty_battery",
+  "empty_filter",
+  "empty_trash",
+  "end_call",
+  "engineering",
+  "entering_heaven_aliv",
+  "expand",
+  "export",
+  "expired",
+  "factory",
+  "factory_breakdown",
+  "external",
+  "faq",
+  "feed_in",
+  "file",
+  "feedback",
+  "film",
+  "filled_filter",
+  "filing_cabinet",
+  "film_reel",
+  "flash_auto",
+  "fine_print",
+  "flash_off",
+  "flash_on",
+  "flow_chart",
+  "folder",
+  "frame",
+  "full_battery",
+  "full_trash",
+  "gallery",
+  "generic_sorting_asc",
+  "generic_sorting_desc",
+  "genealogy",
+  "globe",
+  "good_decision",
+  "headset",
+  "grid",
+  "graduation_cap",
+  "heat_map",
+  "high_priority",
+  "high_battery",
+  "image_file",
+  "home",
+  "idea",
+  "import",
+  "in_transit",
+  "integrated_webcam",
+  "inspection",
+  "invite",
+  "internal",
+  "ipad",
+  "info",
+  "iphone",
+  "kindle",
+  "key",
+  "landscape",
+  "left",
+  "left_down",
+  "left_up",
+  "leave",
+  "like_placeholder",
+  "light_at_the_end_of_",
+  "library",
+  "line_chart",
+  "link",
+  "like",
+  "lock",
+  "list",
+  "lock_landscape",
+  "low_battery",
+  "lock_portrait",
+  "low_priority",
+  "make_decision",
+  "medium_priority",
+  "manager",
+  "menu",
+  "middle_battery",
+  "minus",
+  "missed_call",
+  "mind_map",
+  "mms",
+  "multiple_cameras",
+  "money_transfer",
+  "music",
+  "multiple_devices",
+  "multiple_smartphones",
+  "multiple_inputs",
+  "negative_dynamic",
+  "neutral_decision",
+  "night_landscape",
+  "news",
+  "neutral_trading",
+  "night_portrait",
+  "no_idea",
+  "next",
+  "no_video",
+  "nook",
+  "ok",
+  "org_unit",
+  "opened_folder",
+  "old_time_camera",
+  "online_support",
+  "organization",
+  "package",
+  "paid",
+  "parallel_tasks",
+  "overtime",
+  "panorama",
+  "phone",
+  "phone_android",
+  "photo_reel",
+  "pie_chart",
+  "picture",
+  "planner",
+  "plus",
+  "podium_with_audience",
+  "podium_without_speak",
+  "podium_with_speaker",
+  "previous",
+  "portrait_mode",
+  "positive_dynamic",
+  "privacy",
+  "process",
+  "puzzle",
+  "questions",
+  "print",
+  "radar_plot",
+  "rating",
+  "ratings",
+  "reading",
+  "redo",
+  "reading_ebook",
+  "refresh",
+  "registered_trademark",
+  "right",
+  "reuse",
+  "remove_image",
+  "right_down",
+  "right_up",
+  "rotate_to_portrait",
+  "rules",
+  "rotate_camera",
+  "rotate_to_landscape",
+  "ruler",
+  "scatter_plot",
+  "search",
+  "safe",
+  "self_service_kiosk",
+  "selfie",
+  "serial_tasks",
+  "sales_performance",
+  "settings",
+  "services",
+  "share",
+  "shipped",
+  "sim_card",
+  "shop",
+  "service_mark",
+  "sim_card_chip",
+  "signature",
+  "smartphone_tablet",
+  "sound_recording_copy",
+  "sms",
+  "speaker",
+  "slr_back_side",
+  "start",
+  "stack_of_photos",
+  "statistics",
+  "sports_mode",
+  "support",
+  "synchronize",
+  "switch_camera",
+  "survey",
+  "tablet_android",
+  "template",
+  "trademark",
+  "todo_list",
+  "touchscreen_smartpho",
+  "timeline",
+  "tree_structure",
+  "undo",
+  "up_left",
+  "two_smartphones",
+  "unlock",
+  "up",
+  "up_right",
+  "upload",
+  "video_call",
+  "video_file",
+  "view_details",
+  "video_projector",
+  "vip",
+  "voice_presentation",
+  "webcam",
+  "voicemail",
+  "workflow",
+  "about",
+  "accept_database",
+  "add_image",
+  "add_column",
+  "add_database",
+  "add_row",
+];
+module.exports = [
+  {
+    url: "/colorfulIcon/getList",
+    type: "post",
+    response(config) {
+      const { title, pageNo = 1, pageSize = 72 } = config.body;
+      let mockList = data.filter((item) => {
+        if (title && item.indexOf(title) < 0) return false;
+        return true;
+      });
+      const pageList = mockList.filter(
+        (item, index) =>
+          index < pageSize * pageNo && index >= pageSize * (pageNo - 1)
+      );
+      return {
+        code: 200,
+        msg: "success",
+        totalCount: mockList.length,
+        data: pageList,
+      };
+    },
+  },
+];

+ 42 - 0
mock/controller/goodsDetail.js

@@ -0,0 +1,42 @@
+const { mock } = require("mockjs");
+
+module.exports = [
+  {
+    url: "/goodsDetail/getList",
+    type: "post",
+    response(config) {
+      return {
+        code: 200,
+        msg: "success",
+        totalCount: 999,
+        data: mock({
+          "data|10": [
+            {
+              id: "@id",
+            },
+          ],
+        }).data,
+      };
+    },
+  },
+  {
+    url: "/goodsDetail/doEdit",
+    type: "post",
+    response(config) {
+      return {
+        code: 200,
+        msg: "模拟保存成功",
+      };
+    },
+  },
+  {
+    url: "/goodsDetail/doDelete",
+    type: "post",
+    response(config) {
+      return {
+        code: 200,
+        msg: "模拟删除成功",
+      };
+    },
+  },
+];

+ 43 - 0
mock/controller/goodsList.js

@@ -0,0 +1,43 @@
+const { mock } = require("mockjs");
+
+const List = [];
+const count = 999;
+let num = 0;
+for (let i = 0; i < count; i++) {
+  List.push(
+    mock({
+      uuid: "@uuid",
+      image: `https://picsum.photos/300/600?random=${num++}`,
+      title: "@ctitle",
+      description: "@csentence",
+      link: "https://www.baidu.com",
+      price: "@integer(100, 500)",
+      "status|1": [1, 0],
+      "isRecommend|1": [1, 0],
+    })
+  );
+}
+
+module.exports = [
+  {
+    url: "/goodsList/getList",
+    type: "post",
+    response(config) {
+      const { title = "", pageNo = 1, pageSize = 20 } = config.body;
+      let mockList = List.filter((item) => {
+        if (title && item.title.indexOf(title) < 0) return false;
+        return true;
+      });
+      const pageList = mockList.filter(
+        (item, index) =>
+          index < pageSize * pageNo && index >= pageSize * (pageNo - 1)
+      );
+      return {
+        code: 200,
+        msg: "success",
+        totalCount: count,
+        data: pageList,
+      };
+    },
+  },
+];

+ 989 - 0
mock/controller/icon.js

@@ -0,0 +1,989 @@
+const data = [
+  "ad",
+  "address-book",
+  "address-card",
+  "adjust",
+  "air-freshener",
+  "align-center",
+  "align-justify",
+  "align-left",
+  "align-right",
+  "allergies",
+  "ambulance",
+  "american-sign-language-interpreting",
+  "anchor",
+  "angle-double-down",
+  "angle-double-left",
+  "angle-double-right",
+  "angle-double-up",
+  "angle-down",
+  "angle-left",
+  "angle-right",
+  "angle-up",
+  "angry",
+  "ankh",
+  "apple-alt",
+  "archive",
+  "archway",
+  "arrow-alt-circle-down",
+  "arrow-alt-circle-left",
+  "arrow-alt-circle-right",
+  "arrow-alt-circle-up",
+  "arrow-circle-down",
+  "arrow-circle-left",
+  "arrow-circle-right",
+  "arrow-circle-up",
+  "arrow-down",
+  "arrow-left",
+  "arrow-right",
+  "arrow-up",
+  "arrows-alt",
+  "arrows-alt-h",
+  "arrows-alt-v",
+  "assistive-listening-systems",
+  "asterisk",
+  "at",
+  "atlas",
+  "atom",
+  "audio-description",
+  "award",
+  "baby",
+  "baby-carriage",
+  "backspace",
+  "backward",
+  "bacon",
+  "bahai",
+  "balance-scale",
+  "balance-scale-left",
+  "balance-scale-right",
+  "ban",
+  "band-aid",
+  "barcode",
+  "bars",
+  "baseball-ball",
+  "basketball-ball",
+  "bath",
+  "battery-empty",
+  "battery-full",
+  "battery-half",
+  "battery-quarter",
+  "battery-three-quarters",
+  "bed",
+  "beer",
+  "bell",
+  "bell-slash",
+  "bezier-curve",
+  "bible",
+  "bicycle",
+  "biking",
+  "binoculars",
+  "biohazard",
+  "birthday-cake",
+  "blender",
+  "blender-phone",
+  "blind",
+  "blog",
+  "bold",
+  "bolt",
+  "bomb",
+  "bone",
+  "bong",
+  "book",
+  "book-dead",
+  "book-medical",
+  "book-open",
+  "book-reader",
+  "bookmark",
+  "border-all",
+  "border-none",
+  "border-style",
+  "bowling-ball",
+  "box",
+  "box-open",
+  "boxes",
+  "braille",
+  "brain",
+  "bread-slice",
+  "briefcase",
+  "briefcase-medical",
+  "broadcast-tower",
+  "broom",
+  "brush",
+  "bug",
+  "building",
+  "bullhorn",
+  "bullseye",
+  "burn",
+  "bus",
+  "bus-alt",
+  "business-time",
+  "calculator",
+  "calendar",
+  "calendar-alt",
+  "calendar-check",
+  "calendar-day",
+  "calendar-minus",
+  "calendar-plus",
+  "calendar-times",
+  "calendar-week",
+  "camera",
+  "camera-retro",
+  "campground",
+  "candy-cane",
+  "cannabis",
+  "capsules",
+  "car",
+  "car-alt",
+  "car-battery",
+  "car-crash",
+  "car-side",
+  "caravan",
+  "caret-down",
+  "caret-left",
+  "caret-right",
+  "caret-square-down",
+  "caret-square-left",
+  "caret-square-right",
+  "caret-square-up",
+  "caret-up",
+  "carrot",
+  "cart-arrow-down",
+  "cart-plus",
+  "cash-register",
+  "cat",
+  "certificate",
+  "chair",
+  "chalkboard",
+  "chalkboard-teacher",
+  "charging-station",
+  "chart-area",
+  "chart-bar",
+  "chart-line",
+  "chart-pie",
+  "check",
+  "check-circle",
+  "check-double",
+  "check-square",
+  "cheese",
+  "chess",
+  "chess-bishop",
+  "chess-board",
+  "chess-king",
+  "chess-knight",
+  "chess-pawn",
+  "chess-queen",
+  "chess-rook",
+  "chevron-circle-down",
+  "chevron-circle-left",
+  "chevron-circle-right",
+  "chevron-circle-up",
+  "chevron-down",
+  "chevron-left",
+  "chevron-right",
+  "chevron-up",
+  "child",
+  "church",
+  "circle",
+  "circle-notch",
+  "city",
+  "clinic-medical",
+  "clipboard",
+  "clipboard-check",
+  "clipboard-list",
+  "clock",
+  "clone",
+  "closed-captioning",
+  "cloud",
+  "cloud-download-alt",
+  "cloud-meatball",
+  "cloud-moon",
+  "cloud-moon-rain",
+  "cloud-rain",
+  "cloud-showers-heavy",
+  "cloud-sun",
+  "cloud-sun-rain",
+  "cloud-upload-alt",
+  "cocktail",
+  "code",
+  "code-branch",
+  "coffee",
+  "cog",
+  "cogs",
+  "coins",
+  "columns",
+  "comment",
+  "comment-alt",
+  "comment-dollar",
+  "comment-dots",
+  "comment-medical",
+  "comment-slash",
+  "comments",
+  "comments-dollar",
+  "compact-disc",
+  "compass",
+  "compress",
+  "compress-alt",
+  "compress-arrows-alt",
+  "concierge-bell",
+  "cookie",
+  "cookie-bite",
+  "copy",
+  "copyright",
+  "couch",
+  "credit-card",
+  "crop",
+  "crop-alt",
+  "cross",
+  "crosshairs",
+  "crow",
+  "crown",
+  "crutch",
+  "cube",
+  "cubes",
+  "cut",
+  "database",
+  "deaf",
+  "democrat",
+  "desktop",
+  "dharmachakra",
+  "diagnoses",
+  "dice",
+  "dice-d20",
+  "dice-d6",
+  "dice-five",
+  "dice-four",
+  "dice-one",
+  "dice-six",
+  "dice-three",
+  "dice-two",
+  "digital-tachograph",
+  "directions",
+  "divide",
+  "dizzy",
+  "dna",
+  "dog",
+  "dollar-sign",
+  "dolly",
+  "dolly-flatbed",
+  "donate",
+  "door-closed",
+  "door-open",
+  "dot-circle",
+  "dove",
+  "download",
+  "drafting-compass",
+  "dragon",
+  "draw-polygon",
+  "drum",
+  "drum-steelpan",
+  "drumstick-bite",
+  "dumbbell",
+  "dumpster",
+  "dumpster-fire",
+  "dungeon",
+  "edit",
+  "egg",
+  "eject",
+  "ellipsis-h",
+  "ellipsis-v",
+  "envelope",
+  "envelope-open",
+  "envelope-open-text",
+  "envelope-square",
+  "equals",
+  "eraser",
+  "ethernet",
+  "euro-sign",
+  "exchange-alt",
+  "exclamation",
+  "exclamation-circle",
+  "exclamation-triangle",
+  "expand",
+  "expand-alt",
+  "expand-arrows-alt",
+  "external-link-alt",
+  "external-link-square-alt",
+  "eye",
+  "eye-dropper",
+  "eye-slash",
+  "fan",
+  "fast-backward",
+  "fast-forward",
+  "fax",
+  "feather",
+  "feather-alt",
+  "female",
+  "fighter-jet",
+  "file",
+  "file-alt",
+  "file-archive",
+  "file-audio",
+  "file-code",
+  "file-contract",
+  "file-csv",
+  "file-download",
+  "file-excel",
+  "file-export",
+  "file-image",
+  "file-import",
+  "file-invoice",
+  "file-invoice-dollar",
+  "file-medical",
+  "file-medical-alt",
+  "file-pdf",
+  "file-powerpoint",
+  "file-prescription",
+  "file-signature",
+  "file-upload",
+  "file-video",
+  "file-word",
+  "fill",
+  "fill-drip",
+  "film",
+  "filter",
+  "fingerprint",
+  "fire",
+  "fire-alt",
+  "fire-extinguisher",
+  "first-aid",
+  "fish",
+  "fist-raised",
+  "flag",
+  "flag-checkered",
+  "flag-usa",
+  "flask",
+  "flushed",
+  "folder",
+  "folder-minus",
+  "folder-open",
+  "folder-plus",
+  "font",
+  "football-ball",
+  "forward",
+  "frog",
+  "frown",
+  "frown-open",
+  "funnel-dollar",
+  "futbol",
+  "gamepad",
+  "gas-pump",
+  "gavel",
+  "gem",
+  "genderless",
+  "ghost",
+  "gift",
+  "gifts",
+  "glass-cheers",
+  "glass-martini",
+  "glass-martini-alt",
+  "glass-whiskey",
+  "glasses",
+  "globe",
+  "globe-africa",
+  "globe-americas",
+  "globe-asia",
+  "globe-europe",
+  "golf-ball",
+  "gopuram",
+  "graduation-cap",
+  "greater-than",
+  "greater-than-equal",
+  "grimace",
+  "grin",
+  "grin-alt",
+  "grin-beam",
+  "grin-beam-sweat",
+  "grin-hearts",
+  "grin-squint",
+  "grin-squint-tears",
+  "grin-stars",
+  "grin-tears",
+  "grin-tongue",
+  "grin-tongue-squint",
+  "grin-tongue-wink",
+  "grin-wink",
+  "grip-horizontal",
+  "grip-lines",
+  "grip-lines-vertical",
+  "grip-vertical",
+  "guitar",
+  "h-square",
+  "hamburger",
+  "hammer",
+  "hamsa",
+  "hand-holding",
+  "hand-holding-heart",
+  "hand-holding-usd",
+  "hand-lizard",
+  "hand-middle-finger",
+  "hand-paper",
+  "hand-peace",
+  "hand-point-down",
+  "hand-point-left",
+  "hand-point-right",
+  "hand-point-up",
+  "hand-pointer",
+  "hand-rock",
+  "hand-scissors",
+  "hand-spock",
+  "hands",
+  "hands-helping",
+  "handshake",
+  "hanukiah",
+  "hard-hat",
+  "hashtag",
+  "hat-cowboy",
+  "hat-cowboy-side",
+  "hat-wizard",
+  "hdd",
+  "heading",
+  "headphones",
+  "headphones-alt",
+  "headset",
+  "heart",
+  "heart-broken",
+  "heartbeat",
+  "helicopter",
+  "highlighter",
+  "hiking",
+  "hippo",
+  "history",
+  "hockey-puck",
+  "holly-berry",
+  "home",
+  "horse",
+  "horse-head",
+  "hospital",
+  "hospital-alt",
+  "hospital-symbol",
+  "hot-tub",
+  "hotdog",
+  "hotel",
+  "hourglass",
+  "hourglass-end",
+  "hourglass-half",
+  "hourglass-start",
+  "house-damage",
+  "hryvnia",
+  "i-cursor",
+  "ice-cream",
+  "icicles",
+  "icons",
+  "id-badge",
+  "id-card",
+  "id-card-alt",
+  "igloo",
+  "image",
+  "images",
+  "inbox",
+  "indent",
+  "industry",
+  "infinity",
+  "info",
+  "info-circle",
+  "italic",
+  "jedi",
+  "joint",
+  "journal-whills",
+  "kaaba",
+  "key",
+  "keyboard",
+  "khanda",
+  "kiss",
+  "kiss-beam",
+  "kiss-wink-heart",
+  "kiwi-bird",
+  "landmark",
+  "language",
+  "laptop",
+  "laptop-code",
+  "laptop-medical",
+  "laugh",
+  "laugh-beam",
+  "laugh-squint",
+  "laugh-wink",
+  "layer-group",
+  "leaf",
+  "lemon",
+  "less-than",
+  "less-than-equal",
+  "level-down-alt",
+  "level-up-alt",
+  "life-ring",
+  "lightbulb",
+  "link",
+  "lira-sign",
+  "list",
+  "list-alt",
+  "list-ol",
+  "list-ul",
+  "location-arrow",
+  "lock",
+  "lock-open",
+  "long-arrow-alt-down",
+  "long-arrow-alt-left",
+  "long-arrow-alt-right",
+  "long-arrow-alt-up",
+  "low-vision",
+  "luggage-cart",
+  "magic",
+  "magnet",
+  "mail-bulk",
+  "male",
+  "map",
+  "map-marked",
+  "map-marked-alt",
+  "map-marker",
+  "map-marker-alt",
+  "map-pin",
+  "map-signs",
+  "marker",
+  "mars",
+  "mars-double",
+  "mars-stroke",
+  "mars-stroke-h",
+  "mars-stroke-v",
+  "mask",
+  "medal",
+  "medkit",
+  "meh",
+  "meh-blank",
+  "meh-rolling-eyes",
+  "memory",
+  "menorah",
+  "mercury",
+  "meteor",
+  "microchip",
+  "microphone",
+  "microphone-alt",
+  "microphone-alt-slash",
+  "microphone-slash",
+  "microscope",
+  "minus",
+  "minus-circle",
+  "minus-square",
+  "mitten",
+  "mobile",
+  "mobile-alt",
+  "money-bill",
+  "money-bill-alt",
+  "money-bill-wave",
+  "money-bill-wave-alt",
+  "money-check",
+  "money-check-alt",
+  "monument",
+  "moon",
+  "mortar-pestle",
+  "mosque",
+  "motorcycle",
+  "mountain",
+  "mouse",
+  "mouse-pointer",
+  "mug-hot",
+  "music",
+  "network-wired",
+  "neuter",
+  "newspaper",
+  "not-equal",
+  "notes-medical",
+  "object-group",
+  "object-ungroup",
+  "oil-can",
+  "om",
+  "otter",
+  "outdent",
+  "pager",
+  "paint-brush",
+  "paint-roller",
+  "palette",
+  "pallet",
+  "paper-plane",
+  "paperclip",
+  "parachute-box",
+  "paragraph",
+  "parking",
+  "passport",
+  "pastafarianism",
+  "paste",
+  "pause",
+  "pause-circle",
+  "paw",
+  "peace",
+  "pen",
+  "pen-alt",
+  "pen-fancy",
+  "pen-nib",
+  "pen-square",
+  "pencil-alt",
+  "pencil-ruler",
+  "people-carry",
+  "pepper-hot",
+  "percent",
+  "percentage",
+  "person-booth",
+  "phone",
+  "phone-alt",
+  "phone-slash",
+  "phone-square",
+  "phone-square-alt",
+  "phone-volume",
+  "photo-video",
+  "piggy-bank",
+  "pills",
+  "pizza-slice",
+  "place-of-worship",
+  "plane",
+  "plane-arrival",
+  "plane-departure",
+  "play",
+  "play-circle",
+  "plug",
+  "plus",
+  "plus-circle",
+  "plus-square",
+  "podcast",
+  "poll",
+  "poll-h",
+  "poo",
+  "poo-storm",
+  "poop",
+  "portrait",
+  "pound-sign",
+  "power-off",
+  "pray",
+  "praying-hands",
+  "prescription",
+  "prescription-bottle",
+  "prescription-bottle-alt",
+  "print",
+  "procedures",
+  "project-diagram",
+  "puzzle-piece",
+  "qrcode",
+  "question",
+  "question-circle",
+  "quidditch",
+  "quote-left",
+  "quote-right",
+  "quran",
+  "radiation",
+  "radiation-alt",
+  "rainbow",
+  "random",
+  "receipt",
+  "record-vinyl",
+  "recycle",
+  "redo",
+  "redo-alt",
+  "registered",
+  "remove-format",
+  "reply",
+  "reply-all",
+  "republican",
+  "restroom",
+  "retweet",
+  "ribbon",
+  "ring",
+  "road",
+  "robot",
+  "rocket",
+  "route",
+  "rss",
+  "rss-square",
+  "ruble-sign",
+  "ruler",
+  "ruler-combined",
+  "ruler-horizontal",
+  "ruler-vertical",
+  "running",
+  "rupee-sign",
+  "sad-cry",
+  "sad-tear",
+  "satellite",
+  "satellite-dish",
+  "save",
+  "school",
+  "screwdriver",
+  "scroll",
+  "sd-card",
+  "search",
+  "search-dollar",
+  "search-location",
+  "search-minus",
+  "search-plus",
+  "seedling",
+  "server",
+  "shapes",
+  "share",
+  "share-alt",
+  "share-alt-square",
+  "share-square",
+  "shekel-sign",
+  "shield-alt",
+  "ship",
+  "shipping-fast",
+  "shoe-prints",
+  "shopping-bag",
+  "shopping-basket",
+  "shopping-cart",
+  "shower",
+  "shuttle-van",
+  "sign",
+  "sign-in-alt",
+  "sign-language",
+  "sign-out-alt",
+  "signal",
+  "signature",
+  "sim-card",
+  "sitemap",
+  "skating",
+  "skiing",
+  "skiing-nordic",
+  "skull",
+  "skull-crossbones",
+  "slash",
+  "sleigh",
+  "sliders-h",
+  "smile",
+  "smile-beam",
+  "smile-wink",
+  "smog",
+  "smoking",
+  "smoking-ban",
+  "sms",
+  "snowboarding",
+  "snowflake",
+  "snowman",
+  "snowplow",
+  "socks",
+  "solar-panel",
+  "sort",
+  "sort-alpha-down",
+  "sort-alpha-down-alt",
+  "sort-alpha-up",
+  "sort-alpha-up-alt",
+  "sort-amount-down",
+  "sort-amount-down-alt",
+  "sort-amount-up",
+  "sort-amount-up-alt",
+  "sort-down",
+  "sort-numeric-down",
+  "sort-numeric-down-alt",
+  "sort-numeric-up",
+  "sort-numeric-up-alt",
+  "sort-up",
+  "spa",
+  "space-shuttle",
+  "spell-check",
+  "spider",
+  "spinner",
+  "splotch",
+  "spray-can",
+  "square",
+  "square-full",
+  "square-root-alt",
+  "stamp",
+  "star",
+  "star-and-crescent",
+  "star-half",
+  "star-half-alt",
+  "star-of-david",
+  "star-of-life",
+  "step-backward",
+  "step-forward",
+  "stethoscope",
+  "sticky-note",
+  "stop",
+  "stop-circle",
+  "stopwatch",
+  "store",
+  "store-alt",
+  "stream",
+  "street-view",
+  "strikethrough",
+  "stroopwafel",
+  "subscript",
+  "subway",
+  "suitcase",
+  "suitcase-rolling",
+  "sun",
+  "superscript",
+  "surprise",
+  "swatchbook",
+  "swimmer",
+  "swimming-pool",
+  "synagogue",
+  "sync",
+  "sync-alt",
+  "syringe",
+  "table",
+  "table-tennis",
+  "tablet",
+  "tablet-alt",
+  "tablets",
+  "tachometer-alt",
+  "tag",
+  "tags",
+  "tape",
+  "tasks",
+  "taxi",
+  "teeth",
+  "teeth-open",
+  "temperature-high",
+  "temperature-low",
+  "tenge",
+  "terminal",
+  "text-height",
+  "text-width",
+  "th",
+  "th-large",
+  "th-list",
+  "theater-masks",
+  "thermometer",
+  "thermometer-empty",
+  "thermometer-full",
+  "thermometer-half",
+  "thermometer-quarter",
+  "thermometer-three-quarters",
+  "thumbs-down",
+  "thumbs-up",
+  "thumbtack",
+  "ticket-alt",
+  "times",
+  "times-circle",
+  "tint",
+  "tint-slash",
+  "tired",
+  "toggle-off",
+  "toggle-on",
+  "toilet",
+  "toilet-paper",
+  "toolbox",
+  "tools",
+  "tooth",
+  "torah",
+  "torii-gate",
+  "tractor",
+  "trademark",
+  "traffic-light",
+  "trailer",
+  "train",
+  "tram",
+  "transgender",
+  "transgender-alt",
+  "trash",
+  "trash-alt",
+  "trash-restore",
+  "trash-restore-alt",
+  "tree",
+  "trophy",
+  "truck",
+  "truck-loading",
+  "truck-monster",
+  "truck-moving",
+  "truck-pickup",
+  "tshirt",
+  "tty",
+  "tv",
+  "umbrella",
+  "umbrella-beach",
+  "underline",
+  "undo",
+  "undo-alt",
+  "universal-access",
+  "university",
+  "unlink",
+  "unlock",
+  "unlock-alt",
+  "upload",
+  "user",
+  "user-alt",
+  "user-alt-slash",
+  "user-astronaut",
+  "user-check",
+  "user-circle",
+  "user-clock",
+  "user-cog",
+  "user-edit",
+  "user-friends",
+  "user-graduate",
+  "user-injured",
+  "user-lock",
+  "user-md",
+  "user-minus",
+  "user-ninja",
+  "user-nurse",
+  "user-plus",
+  "user-secret",
+  "user-shield",
+  "user-slash",
+  "user-tag",
+  "user-tie",
+  "user-times",
+  "users",
+  "users-cog",
+  "utensil-spoon",
+  "utensils",
+  "vector-square",
+  "venus",
+  "venus-double",
+  "venus-mars",
+  "vial",
+  "vials",
+  "video",
+  "video-slash",
+  "vihara",
+  "voicemail",
+  "volleyball-ball",
+  "volume-down",
+  "volume-mute",
+  "volume-off",
+  "volume-up",
+  "vote-yea",
+  "vr-cardboard",
+  "walking",
+  "wallet",
+  "warehouse",
+  "water",
+  "wave-square",
+  "weight",
+  "weight-hanging",
+  "wheelchair",
+  "wifi",
+  "wind",
+  "window-close",
+  "window-maximize",
+  "window-minimize",
+  "window-restore",
+  "wine-bottle",
+  "wine-glass",
+  "wine-glass-alt",
+  "won-sign",
+  "wrench",
+  "x-ray",
+  "yen-sign",
+  "yin-yang",
+];
+module.exports = [
+  {
+    url: "/icon/getList",
+    type: "post",
+    response(config) {
+      const { title, pageNo = 1, pageSize = 72 } = config.body;
+      let mockList = data.filter((item) => {
+        if (title && item.indexOf(title) < 0) return false;
+        return true;
+      });
+      const pageList = mockList.filter(
+        (item, index) =>
+          index < pageSize * pageNo && index >= pageSize * (pageNo - 1)
+      );
+      return {
+        code: 200,
+        msg: "success",
+        totalCount: mockList.length,
+        data: pageList,
+      };
+    },
+  },
+];

+ 51 - 0
mock/controller/menuManagement.js

@@ -0,0 +1,51 @@
+module.exports = [
+  {
+    url: "/menuManagement/getTree",
+    type: "post",
+    response(config) {
+      return {
+        code: 200,
+        msg: "success",
+        totalCount: 999,
+        data: [
+          {
+            id: "root",
+            label: "全部角色",
+            children: [
+              {
+                id: "@id",
+                permission: "admin",
+                label: "admin角色",
+              },
+              {
+                id: "@id",
+                permission: "editor",
+                label: "editor角色",
+              },
+            ],
+          },
+        ],
+      };
+    },
+  },
+  {
+    url: "/menuManagement/doEdit",
+    type: "post",
+    response(config) {
+      return {
+        code: 200,
+        msg: "模拟保存成功",
+      };
+    },
+  },
+  {
+    url: "/menuManagement/doDelete",
+    type: "post",
+    response(config) {
+      return {
+        code: 200,
+        msg: "模拟删除成功",
+      };
+    },
+  },
+];

File diff suppressed because it is too large
+ 38 - 0
mock/controller/notice.js


+ 42 - 0
mock/controller/personalCenter.js

@@ -0,0 +1,42 @@
+const { mock } = require("mockjs");
+
+module.exports = [
+  {
+    url: "/personalCenter/getList",
+    type: "post",
+    response(config) {
+      return {
+        code: 200,
+        msg: "success",
+        totalCount: 999,
+        data: mock({
+          "data|10": [
+            {
+              id: "@id",
+            },
+          ],
+        }).data,
+      };
+    },
+  },
+  {
+    url: "/personalCenter/doEdit",
+    type: "post",
+    response(config) {
+      return {
+        code: 200,
+        msg: "模拟保存成功",
+      };
+    },
+  },
+  {
+    url: "/personalCenter/doDelete",
+    type: "post",
+    response(config) {
+      return {
+        code: 200,
+        msg: "模拟删除成功",
+      };
+    },
+  },
+];

File diff suppressed because it is too large
+ 2296 - 0
mock/controller/remixIcon.js


+ 53 - 0
mock/controller/roleManagement.js

@@ -0,0 +1,53 @@
+const totalCount = 2;
+const List = [
+  {
+    id: "@id",
+    permission: "admin",
+  },
+  {
+    id: "@id",
+    permission: "editor",
+  },
+];
+module.exports = [
+  {
+    url: "/roleManagement/getList",
+    type: "post",
+    response(config) {
+      const { title = "", pageNo = 1, pageSize = 20 } = config.body;
+      let mockList = List.filter((item) => {
+        return !(title && item.title.indexOf(title) < 0);
+      });
+      const pageList = mockList.filter(
+        (item, index) =>
+          index < pageSize * pageNo && index >= pageSize * (pageNo - 1)
+      );
+      return {
+        code: 200,
+        msg: "success",
+        totalCount,
+        data: pageList,
+      };
+    },
+  },
+  {
+    url: "/roleManagement/doEdit",
+    type: "post",
+    response() {
+      return {
+        code: 200,
+        msg: "模拟保存成功",
+      };
+    },
+  },
+  {
+    url: "/roleManagement/doDelete",
+    type: "post",
+    response() {
+      return {
+        code: 200,
+        msg: "模拟删除成功",
+      };
+    },
+  },
+];

+ 390 - 0
mock/controller/router.js

@@ -0,0 +1,390 @@
+const data = [
+  {
+    path: "/",
+    component: "Layout",
+    redirect: "index",
+    children: [
+      {
+        path: "index",
+        name: "Index",
+        component: "views/index/index",
+        meta: {
+          title: "首页",
+          icon: "home",
+          affix: true,
+        },
+      },
+    ],
+  },
+  {
+    path: "/personalCenter",
+    component: "Layout",
+    hidden: true,
+    redirect: "personalCenter",
+    children: [
+      {
+        path: "personalCenter",
+        name: "PersonalCenter",
+        component: "views/personalCenter/index",
+        meta: {
+          title: "个人中心",
+        },
+      },
+    ],
+  },
+  {
+    path: "/personnelManagement",
+    component: "Layout",
+    redirect: "noRedirect",
+    name: "PersonnelManagement",
+    meta: { title: "人员", icon: "users-cog", permissions: ["admin"] },
+    children: [
+      {
+        path: "userManagement",
+        name: "UserManagement",
+        component: "views/personnelManagement/userManagement/index",
+        meta: { title: "用户管理" },
+      },
+      {
+        path: "roleManagement",
+        name: "RoleManagement",
+        component: "views/personnelManagement/roleManagement/index",
+        meta: { title: "角色管理" },
+      },
+      {
+        path: "menuManagement",
+        name: "MenuManagement",
+        component: "views/personnelManagement/menuManagement/index",
+        meta: { title: "菜单管理", badge: "New" },
+      },
+    ],
+  },
+  {
+    path: "/vab",
+    component: "Layout",
+    redirect: "noRedirect",
+    name: "Vab",
+    alwaysShow: true,
+    meta: { title: "组件", icon: "cloud" },
+    children: [
+      {
+        path: "permissions",
+        name: "Permission",
+        component: "views/vab/permissions/index",
+        meta: {
+          title: "权限控制",
+          permissions: ["admin", "editor"],
+          badge: "New",
+        },
+      },
+      {
+        path: "icon",
+        component: "EmptyLayout",
+        redirect: "noRedirect",
+        name: "Icon",
+        meta: {
+          title: "图标",
+          permissions: ["admin"],
+        },
+        children: [
+          {
+            path: "awesomeIcon",
+            name: "AwesomeIcon",
+            component: "views/vab/icon/index",
+            meta: { title: "常规图标" },
+          },
+          {
+            path: "remixIcon",
+            name: "RemixIcon",
+            component: "views/vab/icon/remixIcon",
+            meta: { title: "小清新图标" },
+          },
+          {
+            path: "colorfulIcon",
+            name: "ColorfulIcon",
+            component: "views/vab/icon/colorfulIcon",
+            meta: { title: "多彩图标" },
+          },
+        ],
+      },
+      {
+        path: "table",
+        component: "EmptyLayout",
+        redirect: "noRedirect",
+        name: "Table",
+        meta: {
+          title: "表格",
+          permissions: ["admin"],
+        },
+        children: [
+          {
+            path: "comprehensiveTable",
+            name: "ComprehensiveTable",
+            component: "views/vab/table/index",
+            meta: { title: "综合表格" },
+          },
+          {
+            path: "inlineEditTable",
+            name: "InlineEditTable",
+            component: "views/vab/table/inlineEditTable",
+            meta: { title: "行内编辑" },
+          },
+        ],
+      },
+      {
+        path: "map",
+        name: "Map",
+        component: "views/vab/map/index",
+        meta: { title: "地图", permissions: ["admin"], badge: "Pro" },
+      },
+      {
+        path: "webSocket",
+        name: "WebSocket",
+        component: "views/vab/webSocket/index",
+        meta: { title: "webSocket", permissions: ["admin"] },
+      },
+      {
+        path: "form",
+        name: "Form",
+        component: "views/vab/form/index",
+        meta: { title: "表单", permissions: ["admin"] },
+      },
+      {
+        path: "element",
+        name: "Element",
+        component: "views/vab/element/index",
+        meta: { title: "常用组件", permissions: ["admin"] },
+      },
+      {
+        path: "tree",
+        name: "Tree",
+        component: "views/vab/tree/index",
+        meta: { title: "树", permissions: ["admin"] },
+      },
+      {
+        path: "card",
+        name: "Card",
+        component: "views/vab/card/index",
+        meta: { title: "卡片", permissions: ["admin"] },
+      },
+
+      {
+        path: "betterScroll",
+        name: "BetterScroll",
+        component: "views/vab/betterScroll/index",
+        meta: {
+          title: "滚动侦测",
+          permissions: ["admin"],
+        },
+      },
+      {
+        path: "verify",
+        name: "Verify",
+        component: "views/vab/verify/index",
+        meta: { title: "验证码", permissions: ["admin"] },
+      },
+      {
+        path: "menu1",
+        component: "views/vab/nested/menu1/index",
+        name: "Menu1",
+        alwaysShow: true,
+        meta: {
+          title: "嵌套路由 1",
+          permissions: ["admin"],
+        },
+        children: [
+          {
+            path: "menu1-1",
+            name: "Menu1-1",
+            alwaysShow: true,
+            meta: { title: "嵌套路由 1-1" },
+            component: "views/vab/nested/menu1/menu1-1/index",
+
+            children: [
+              {
+                path: "menu1-1-1",
+                name: "Menu1-1-1",
+                meta: { title: "嵌套路由 1-1-1" },
+                component: "views/vab/nested/menu1/menu1-1/menu1-1-1/index",
+              },
+            ],
+          },
+        ],
+      },
+      {
+        path: "magnifier",
+        name: "Magnifier",
+        component: "views/vab/magnifier/index",
+        meta: { title: "放大镜", permissions: ["admin"] },
+      },
+      {
+        path: "echarts",
+        name: "Echarts",
+        component: "views/vab/echarts/index",
+        meta: { title: "图表", permissions: ["admin"] },
+      },
+
+      {
+        path: "loading",
+        name: "Loading",
+        component: "views/vab/loading/index",
+        meta: { title: "loading", permissions: ["admin"] },
+      },
+      {
+        path: "player",
+        name: "Player",
+        component: "views/vab/player/index",
+        meta: { title: "视频播放器", permissions: ["admin"] },
+      },
+      {
+        path: "markdownEditor",
+        name: "MarkdownEditor",
+        component: "views/vab/markdownEditor/index",
+        meta: { title: "markdown编辑器", permissions: ["admin"] },
+      },
+      {
+        path: "editor",
+        name: "Editor",
+        component: "views/vab/editor/index",
+        meta: { title: "富文本编辑器", permissions: ["admin"], badge: "New" },
+      },
+      {
+        path: "qrCode",
+        name: "QrCode",
+        component: "views/vab/qrCode/index",
+        meta: { title: "二维码", permissions: ["admin"] },
+      },
+      {
+        path: "backToTop",
+        name: "BackToTop",
+        component: "views/vab/backToTop/index",
+        meta: { title: "返回顶部", permissions: ["admin"] },
+      },
+      {
+        path: "lodash",
+        name: "Lodash",
+        component: "views/vab/lodash/index",
+        meta: { title: "lodash", permissions: ["admin"] },
+      },
+      {
+        path: "imgComparison",
+        name: "ImgComparison",
+        component: "views/vab/imgComparison/index",
+        meta: { title: "图像拖拽比对", permissions: ["admin"] },
+      },
+      {
+        path: "codeGenerator",
+        name: "CodeGenerator",
+        component: "views/vab/codeGenerator/index",
+        meta: { title: "代码生成机", permissions: ["admin"] },
+      },
+      {
+        path: "markdown",
+        name: "Markdown",
+        component: "views/vab/markdown/index",
+        meta: { title: "markdown阅读器", permissions: ["admin"] },
+      },
+      {
+        path: "smallComponents",
+        name: "SmallComponents",
+        component: "views/vab/smallComponents/index",
+        meta: { title: "小组件", permissions: ["admin"] },
+      },
+
+      {
+        path: "upload",
+        name: "Upload",
+        component: "views/vab/upload/index",
+        meta: { title: "上传", permissions: ["admin"] },
+      },
+      {
+        path: "sticky",
+        name: "Sticky",
+        component: "views/vab/sticky/index",
+        meta: { title: "sticky吸附", permissions: ["admin"] },
+      },
+      {
+        path: "log",
+        name: "Log",
+        component: "views/vab/errorLog/index",
+        meta: { title: "错误日志模拟", permissions: ["admin"] },
+      },
+      {
+        path: "more",
+        name: "More",
+        component: "views/vab/more/index",
+        meta: { title: "更多组件", permissions: ["admin"] },
+      },
+    ],
+  },
+  {
+    path: "/mall",
+    component: "Layout",
+    redirect: "noRedirect",
+    name: "Mall",
+    meta: {
+      title: "商城",
+      icon: "shopping-cart",
+      permissions: ["admin"],
+    },
+
+    children: [
+      {
+        path: "pay",
+        name: "Pay",
+        component: "views/mall/pay/index",
+        meta: {
+          title: "支付",
+          noKeepAlive: true,
+        },
+        children: null,
+      },
+      {
+        path: "goodsList",
+        name: "GoodsList",
+        component: "views/mall/goodsList/index",
+        meta: {
+          title: "商品列表",
+        },
+      },
+      {
+        path: "goodsDetail",
+        name: "GoodsDetail",
+        component: "views/mall/goodsDetail/index",
+        meta: {
+          title: "商品详情",
+        },
+      },
+    ],
+  },
+  {
+    path: "/error",
+    component: "EmptyLayout",
+    redirect: "noRedirect",
+    name: "Error",
+    meta: { title: "错误页", icon: "bug" },
+    children: [
+      {
+        path: "401",
+        name: "Error401",
+        component: "views/401",
+        meta: { title: "401" },
+      },
+      {
+        path: "404",
+        name: "Error404",
+        component: "views/404",
+        meta: { title: "404" },
+      },
+    ],
+  },
+];
+module.exports = [
+  {
+    url: "/menu/navigate",
+    type: "post",
+    response() {
+      return { code: 200, msg: "success", data: data };
+    },
+  },
+];

+ 88 - 0
mock/controller/table.js

@@ -0,0 +1,88 @@
+const { mock } = require("mockjs");
+const { handleRandomImage } = require("../utils");
+
+const List = [];
+const count = 999;
+for (let i = 0; i < count; i++) {
+  List.push(
+    mock({
+      uuid: "@uuid",
+      id: "@id",
+      title: "@csentence(1, 2)",
+      "status|1": ["published", "draft", "deleted"],
+      author: "@cname",
+      datetime: "@datetime",
+      pageViews: "@integer(300, 5000)",
+      img: handleRandomImage(200, 200),
+      smallImg: handleRandomImage(40, 40),
+      switch: "@boolean",
+      percent: "@integer(80,99)",
+    })
+  );
+}
+
+module.exports = [
+  {
+    url: "/table/getList",
+    type: "post",
+    response(config) {
+      if (!config.body) {
+        return {
+          code: 200,
+          msg: "success",
+          totalCount: count,
+          data: mock({
+            "data|50": [
+              {
+                id: "@id",
+                title: "@csentence(1, 2)",
+                "status|1": ["published", "draft", "deleted"],
+                author: "@cname",
+                datetime: "@datetime",
+                pageViews: "@integer(300, 5000)",
+                img: handleRandomImage(200, 200),
+                smallImg: handleRandomImage(40, 40),
+                switch: "@boolean",
+                percent: "@integer(80,99)",
+              },
+            ],
+          }).data,
+        };
+      }
+      const { title = "", pageNo = 1, pageSize = 20 } = config.body;
+      let mockList = List.filter((item) => {
+        return !(title && item.title.indexOf(title) < 0);
+      });
+      const pageList = mockList.filter(
+        (item, index) =>
+          index < pageSize * pageNo && index >= pageSize * (pageNo - 1)
+      );
+      return {
+        code: 200,
+        msg: "success",
+        totalCount: count,
+        data: pageList,
+      };
+    },
+  },
+  {
+    url: "/table/doEdit",
+    type: "post",
+    response() {
+      return {
+        code: 200,
+        msg: "模拟保存成功",
+      };
+    },
+  },
+  {
+    url: "/table/doDelete",
+    type: "post",
+    response() {
+      return {
+        code: 200,
+        msg: "模拟删除成功",
+      };
+    },
+  },
+];

+ 54 - 0
mock/controller/tree.js

@@ -0,0 +1,54 @@
+const data = [
+  {
+    id: "1",
+    parentId: "0",
+    name: "vue-admin-beautiful科技有限公司",
+    title: "vue-admin-beautiful科技有限公司",
+    text: "vue-admin-beautiful科技有限公司",
+    value: "1",
+    rank: 1,
+    children: [
+      {
+        id: "32816b88ff72423f960e7d492a386131",
+        parentId: "1",
+        name: "1103工作室",
+        title: "1103工作室",
+        text: "1103工作室",
+        value: "32816b88ff72423f960e7d492a386131",
+        rank: 2,
+        children: [
+          {
+            id: "9e11afc35d55475fb0bd3164b9684cbe",
+            parentId: "32816b88ff72423f960e7d492a386131",
+            name: "前端牛逼plus小组",
+            title: "前端牛逼plus小组",
+            text: "前端牛逼plus小组",
+            value: "9e11afc35d55475fb0bd3164b9684cbe",
+            rank: 3,
+            children: [
+              {
+                id: "4cc1b04635e4444292526c5391699077",
+                parentId: "9e11afc35d55475fb0bd3164b9684cbe",
+                name: "组员chuzhixin",
+                title: "组员chuzhixin",
+                text: "组员chuzhixin",
+                value: "4cc1b04635e4444292526c5391699077",
+                rank: 4,
+                children: [],
+              },
+            ],
+          },
+        ],
+      },
+    ],
+  },
+];
+module.exports = [
+  {
+    url: "/tree/list",
+    type: "post",
+    response() {
+      return { code: 200, msg: "success", data };
+    },
+  },
+];

+ 14 - 0
mock/controller/upload.js

@@ -0,0 +1,14 @@
+const data = [];
+module.exports = [
+  {
+    url: "/upload",
+    type: "post",
+    response(config) {
+      return {
+        code: 200,
+        msg: "success",
+        data: data,
+      };
+    },
+  },
+];

+ 95 - 0
mock/controller/user.js

@@ -0,0 +1,95 @@
+const accessTokens = {
+  admin: "admin-accessToken",
+  editor: "editor-accessToken",
+  test: "test-accessToken",
+};
+
+module.exports = [
+  {
+    url: "/publicKey",
+    type: "post",
+    response() {
+      return {
+        code: 200,
+        msg: "success",
+        data: {
+          mockServer: true,
+          publicKey:
+            "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBT2vr+dhZElF73FJ6xiP181txKWUSNLPQQlid6DUJhGAOZblluafIdLmnUyKE8mMHhT3R+Ib3ssZcJku6Hn72yHYj/qPkCGFv0eFo7G+GJfDIUeDyalBN0QsuiE/XzPHJBuJDfRArOiWvH0BXOv5kpeXSXM8yTt5Na1jAYSiQ/wIDAQAB",
+        },
+      };
+    },
+  },
+  {
+    url: "/login",
+    type: "post",
+    response(config) {
+      const { username } = config.body;
+      const accessToken = accessTokens[username];
+      if (!accessToken) {
+        return {
+          code: 500,
+          msg: "帐户或密码不正确。",
+        };
+      }
+      return {
+        code: 200,
+        msg: "success",
+        data: { accessToken },
+      };
+    },
+  },
+  {
+    url: "/register",
+    type: "post",
+    response() {
+      return {
+        code: 200,
+        msg: "模拟注册成功",
+      };
+    },
+  },
+  {
+    url: "/userInfo",
+    type: "post",
+    response(config) {
+      const { accessToken } = config.body;
+      let permissions = ["admin"];
+      let username = "admin";
+      if ("admin-accessToken" === accessToken) {
+        permissions = ["admin"];
+        username = "admin";
+      }
+      if ("editor-accessToken" === accessToken) {
+        permissions = ["editor"];
+        username = "editor";
+      }
+      if ("test-accessToken" === accessToken) {
+        permissions = ["admin", "editor"];
+        username = "test";
+      }
+      return {
+        code: 200,
+        msg: "success",
+        data: {
+          permissions,
+          username,
+          "avatar|1": [
+            "https://i.gtimg.cn/club/item/face/img/2/15922_100.gif",
+            "https://i.gtimg.cn/club/item/face/img/8/15918_100.gif",
+          ],
+        },
+      };
+    },
+  },
+  {
+    url: "/logout",
+    type: "post",
+    response() {
+      return {
+        code: 200,
+        msg: "success",
+      };
+    },
+  },
+];

+ 70 - 0
mock/controller/userManagement.js

@@ -0,0 +1,70 @@
+const totalCount = 3;
+const List = [
+  {
+    id: "@id",
+    username: "admin",
+    password: "admin",
+    email: "@email",
+    permissions: ["admin"],
+    datatime: "@datetime",
+  },
+  {
+    id: "@id",
+    username: "editor",
+    password: "editor",
+    email: "@email",
+    permissions: ["editor"],
+    datatime: "@datetime",
+  },
+  {
+    id: "@id",
+    username: "test",
+    password: "test",
+    email: "@email",
+    permissions: ["admin", "editor"],
+    datatime: "@datetime",
+  },
+];
+module.exports = [
+  {
+    url: "/userManagement/getList",
+    type: "post",
+    response(config) {
+      const { title = "", pageNo = 1, pageSize = 20 } = config.body;
+      let mockList = List.filter((item) => {
+        if (title && item.title.indexOf(title) < 0) return false;
+        return true;
+      });
+      const pageList = mockList.filter(
+        (item, index) =>
+          index < pageSize * pageNo && index >= pageSize * (pageNo - 1)
+      );
+      return {
+        code: 200,
+        msg: "success",
+        totalCount,
+        data: pageList,
+      };
+    },
+  },
+  {
+    url: "/userManagement/doEdit",
+    type: "post",
+    response() {
+      return {
+        code: 200,
+        msg: "模拟保存成功",
+      };
+    },
+  },
+  {
+    url: "/userManagement/doDelete",
+    type: "post",
+    response() {
+      return {
+        code: 200,
+        msg: "模拟删除成功",
+      };
+    },
+  },
+];

+ 16 - 0
mock/index.js

@@ -0,0 +1,16 @@
+/**
+ * @copyright chuzhixin 1204505056@qq.com
+ * @description 导入所有 controller 模块,npm run serve时在node环境中自动输出controller文件夹下Mock接口,请勿修改。
+ */
+
+const { handleMockArray } = require("./utils");
+
+const mocks = [];
+const mockArray = handleMockArray();
+mockArray.forEach((item) => {
+  const obj = require(item);
+  mocks.push(...obj);
+});
+module.exports = {
+  mocks,
+};

+ 94 - 0
mock/mockServer.js

@@ -0,0 +1,94 @@
+const chokidar = require("chokidar");
+const bodyParser = require("body-parser");
+const chalk = require("chalk");
+const path = require("path");
+const Mock = require("mockjs");
+const { baseURL } = require("../src/config/settings");
+const mockDir = path.join(process.cwd(), "mock");
+
+/**
+ *
+ * @param app
+ * @returns {{mockStartIndex: number, mockRoutesLength: number}}
+ */
+const registerRoutes = (app) => {
+  let mockLastIndex;
+  const { mocks } = require("./index.js");
+  const mocksForServer = mocks.map((route) => {
+    return responseFake(route.url, route.type, route.response);
+  });
+  for (const mock of mocksForServer) {
+    app[mock.type](mock.url, mock.response);
+    mockLastIndex = app._router.stack.length;
+  }
+  const mockRoutesLength = Object.keys(mocksForServer).length;
+  return {
+    mockRoutesLength: mockRoutesLength,
+    mockStartIndex: mockLastIndex - mockRoutesLength,
+  };
+};
+
+/**
+ *
+ * @param url
+ * @param type
+ * @param respond
+ * @returns {{response(*=, *=): void, type: (*|string), url: RegExp}}
+ */
+const responseFake = (url, type, respond) => {
+  return {
+    url: new RegExp(`${baseURL}${url}`),
+    type: type || "get",
+    response(req, res) {
+      res.status(200);
+      if (JSON.stringify(req.body) !== "{}") {
+        console.log(chalk.green(`> 请求地址:${req.path}`));
+        console.log(chalk.green(`> 请求参数:${JSON.stringify(req.body)}\n`));
+      } else {
+        console.log(chalk.green(`> 请求地址:${req.path}\n`));
+      }
+      res.json(
+        Mock.mock(respond instanceof Function ? respond(req, res) : respond)
+      );
+    },
+  };
+};
+/**
+ *
+ * @param app
+ */
+module.exports = (app) => {
+  app.use(bodyParser.json());
+  app.use(
+    bodyParser.urlencoded({
+      extended: true,
+    })
+  );
+
+  const mockRoutes = registerRoutes(app);
+  let mockRoutesLength = mockRoutes.mockRoutesLength;
+  let mockStartIndex = mockRoutes.mockStartIndex;
+  chokidar
+    .watch(mockDir, {
+      ignored: /mock-server/,
+      ignoreInitial: true,
+    })
+    .on("all", (event) => {
+      if (event === "change" || event === "add") {
+        try {
+          app._router.stack.splice(mockStartIndex, mockRoutesLength);
+
+          Object.keys(require.cache).forEach((item) => {
+            if (item.includes(mockDir)) {
+              delete require.cache[require.resolve(item)];
+            }
+          });
+          const mockRoutes = registerRoutes(app);
+          mockRoutesLength = mockRoutes.mockRoutesLength;
+          mockStartIndex = mockRoutes.mockStartIndex;
+        } catch (error) {
+          console.log(chalk.red(error));
+        }
+      }
+    });
+};

+ 43 - 0
mock/utils/index.js

@@ -0,0 +1,43 @@
+const { Random } = require("mockjs");
+const { join } = require("path");
+const fs = require("fs");
+
+/**
+ * @copyright chuzhixin 1204505056@qq.com
+ * @description 随机生成图片url。
+ * @param width
+ * @param height
+ * @returns {string}
+ */
+function handleRandomImage(width = 50, height = 50) {
+  return `https://picsum.photos/${width}/${height}?random=${Random.guid()}`;
+}
+
+/**
+ * @copyright chuzhixin 1204505056@qq.com
+ * @description 处理所有 controller 模块,npm run serve时在node环境中自动输出controller文件夹下Mock接口,请勿修改。
+ * @returns {[]}
+ */
+function handleMockArray() {
+  const mockArray = [];
+  const getFiles = (jsonPath) => {
+    const jsonFiles = [];
+    const findJsonFile = (path) => {
+      const files = fs.readdirSync(path);
+      files.forEach((item) => {
+        const fPath = join(path, item);
+        const stat = fs.statSync(fPath);
+        if (stat.isDirectory() === true) findJsonFile(item);
+        if (stat.isFile() === true) jsonFiles.push(item);
+      });
+    };
+    findJsonFile(jsonPath);
+    jsonFiles.forEach((item) => mockArray.push(`./controller/${item}`));
+  };
+  getFiles("mock/controller");
+  return mockArray;
+}
+module.exports = {
+  handleRandomImage,
+  handleMockArray,
+};

+ 132 - 0
package.json

@@ -0,0 +1,132 @@
+{
+  "name": "vue-admin-beautiful",
+  "version": "1.0.0",
+  "author": "chuzhixin 1204505056@qq.com",
+  "participants": [],
+  "homepage": "https://chu1204505056.gitee.io/vue-admin-beautiful",
+  "publishConfig": {
+    "registry": "https://npm.pkg.github.com/"
+  },
+  "scripts": {
+    "serve": "vue-cli-service serve",
+    "build": "vue-cli-service build",
+    "build:report": "vue-cli-service build --report",
+    "globle": "npm install -g cnpm --registry=https://registry.npm.taobao.org&&cnpm i rimraf npm-check-updates nrm -g&&rimraf node_modules&&cnpm i",
+    "lint": "vue-cli-service lint --fix",
+    "lint:style": "stylelint-config-prettier-check",
+    "inspect": "vue-cli-service inspect",
+    "template": "plop",
+    "clear": "rimraf node_modules&&cnpm i&&increase-memory-limit",
+    "use:npm": "nrm use npm",
+    "use:taobao": "nrm use taobao",
+    "update": "ncu -u --concurrency 10 --timeout 80000&&cnpm i",
+    "update:globle": "ncu -g --concurrency 10 --timeout 80000",
+    "svgo": "svgo -f src/remixIcon/svg --config=svgo.yml",
+    "push": "start ./push.sh",
+    "deploy": "start ./deploy.sh",
+    "increase-memory-limit": "increase-memory-limit"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/chuzhixin/vue-admin-beautiful.git"
+  },
+  "husky": {
+    "hooks": {
+      "pre-commit": "lint-staged"
+    }
+  },
+  "lint-staged": {
+    "src/**/*.{js,vue}": [
+      "eslint --fix",
+      "git add"
+    ]
+  },
+  "dependencies": {
+    "axios": "^0.20.0",
+    "better-scroll": "^2.0.4",
+    "clipboard": "^2.0.6",
+    "codemirror": "^5.58.1",
+    "core-js": "^3.6.5",
+    "dayjs": "^1.9.0",
+    "echarts": "^4.9.0",
+    "echarts-wordcloud": "^1.1.3",
+    "element-ui": "^2.13.2",
+    "file-saver": "^2.0.2",
+    "js-cookie": "^2.2.1",
+    "jsencrypt": "^3.0.0-rc.1",
+    "jsonlint": "^1.6.3",
+    "lodash": "^4.17.20",
+    "maptalks": "^0.49.1",
+    "mapv": "^2.0.57",
+    "nprogress": "^0.2.0",
+    "qs": "^6.9.4",
+    "screenfull": "^5.0.2",
+    "vue": "^2.6.12",
+    "vue-amap": "^0.5.10",
+    "vue-echarts": "^5.0.0-beta.0",
+    "vue-qart": "^2.2.0",
+    "vue-router": "^3.4.5",
+    "vuedraggable": "^2.24.1",
+    "vuex": "^3.5.1",
+    "zx-comparison": "^1.0.3",
+    "zx-count": "^0.3.7",
+    "zx-icon": "^1.1.9",
+    "zx-keel": "^0.9.4",
+    "zx-layouts": "^0.6.13",
+    "zx-magnifie": "^0.4.0",
+    "zx-markdown-editor": "^0.0.2",
+    "zx-player": "^1.0.1",
+    "zx-quill": "^0.0.2",
+    "zx-templates": "^0.0.22",
+    "zx-verify": "^0.0.2"
+  },
+  "devDependencies": {
+    "@babel/register": "^7.11.5",
+    "@vue/cli-plugin-babel": "^4.5.6",
+    "@vue/cli-plugin-eslint": "^4.5.6",
+    "@vue/cli-plugin-router": "^4.5.6",
+    "@vue/cli-plugin-vuex": "^4.5.6",
+    "@vue/cli-service": "^4.5.6",
+    "@vue/eslint-config-prettier": "^6.0.0",
+    "autoprefixer": "^10.0.1",
+    "babel-eslint": "^10.1.0",
+    "babel-plugin-dynamic-import-node": "^2.3.3",
+    "compression-webpack-plugin": "^6.0.2",
+    "eslint": "^7.10.0",
+    "eslint-plugin-prettier": "^3.1.4",
+    "eslint-plugin-vue": "^6.2.2",
+    "filemanager-webpack-plugin": "^2.0.5",
+    "husky": "^4.3.0",
+    "image-webpack-loader": "^7.0.1",
+    "increase-memory-limit": "^1.0.7",
+    "lint-staged": "^10.4.0",
+    "mockjs": "^1.1.0",
+    "plop": "^2.7.4",
+    "prettier": "^2.1.2",
+    "sass": "^1.26.11",
+    "sass-loader": "^10.0.2",
+    "script-loader": "^0.7.2",
+    "stylelint": "^13.7.2",
+    "stylelint-config-prettier": "^8.0.2",
+    "stylelint-config-recess-order": "^2.1.0",
+    "svg-sprite-loader": "^5.0.0",
+    "svgo": "^1.3.2",
+    "vue-template-compiler": "^2.6.12",
+    "webpackbar": "^4.0.0"
+  },
+  "keywords": [
+    "vue",
+    "admin",
+    "dashboard",
+    "element-ui",
+    "vue-admin",
+    "element-admin",
+    "boilerplate",
+    "admin-template",
+    "management-system"
+  ],
+  "engines": {
+    "node": ">=8.9",
+    "npm": ">= 3.0.0"
+  }
+}

+ 13 - 0
plopfile.js

@@ -0,0 +1,13 @@
+const viewGenerator = require("zx-templates/view/prompt");
+const curdGenerator = require("zx-templates/curd/prompt");
+const componentGenerator = require("zx-templates/component/prompt");
+const mockGenerator = require("zx-templates/mock/prompt");
+const vuexGenerator = require("zx-templates/vuex/prompt");
+
+module.exports = (plop) => {
+  plop.setGenerator("view", viewGenerator);
+  plop.setGenerator("curd", curdGenerator);
+  plop.setGenerator("component", componentGenerator);
+  plop.setGenerator("mock&api", mockGenerator);
+  plop.setGenerator("vuex", vuexGenerator);
+};

+ 16 - 0
prettier.config.js

@@ -0,0 +1,16 @@
+module.exports = {
+  printWidth: 80,
+  tabWidth: 2,
+  useTabs: false,
+  semi: true,
+  singleQuote: false,
+  quoteProps: "as-needed",
+  jsxSingleQuote: false,
+  trailingComma: "es5",
+  bracketSpacing: true,
+  jsxBracketSameLine: false,
+  arrowParens: "always",
+  htmlWhitespaceSensitivity: "ignore",
+  vueIndentScriptAndStyle: true,
+  endOfLine: "lf",
+};

BIN
public/favicon.ico


BIN
public/favicon_backup.ico


+ 52 - 0
public/index.html

@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<html lang="zh-cmn-Hans">
+  <head>
+    <meta charset="utf-8" />
+    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
+    <meta name="viewport" content="width=device-width,initial-scale=1.0" />
+    <link rel="icon" href="<%= BASE_URL %>favicon.ico" />
+    <title><%= VUE_APP_TITLE %></title>
+    <meta
+      name="keywords"
+      content="vab,vab官网,后台管理框架,vue后台管理框架,vue-admin-beautiful,vue-admin-beautiful官网,vue-admin-beautiful文档,vue-element-admin,vue-element-admin官网,vue-element-admin文档,vue-admin,vue-admin官网,vue-admin文档"
+    />
+    <meta
+      name="description"
+      content="<%= VUE_APP_TITLE %>官网与文档基于vue-admin-beautiful构建,简称vab(是一款超棒的vue+element中后台前端快速开发框架),QQ群972435319,作者:<%= VUE_APP_AUTHOR %>"
+    />
+    <meta name="author" content="<%= VUE_APP_AUTHOR %>" />
+    <link rel="stylesheet" href="<%= BASE_URL %>static/css/loading.css" />
+    <script>
+      var _hmt = _hmt || [];
+      (function () {
+        var hm = document.createElement("script");
+        hm.src = "https://hm.baidu.com/hm.js?7174bade1219f9cc272e7978f9523fc8";
+        var s = document.getElementsByTagName("script")[0];
+        s.parentNode.insertBefore(hm, s);
+      })();
+    </script>
+  </head>
+  <body>
+    <noscript>
+      非常抱歉鉴于安全考量,您无法查看<%= VUE_APP_TITLE %>
+      源代码,该系统基于vue-admin-beautiful开发
+    </noscript>
+    <div id="vue-admin-beautiful">
+      <div class="first-loading-wrp">
+        <div class="loading-wrp">
+          <span class="dot dot-spin">
+            <i></i>
+            <i></i>
+            <i></i>
+            <i></i>
+          </span>
+        </div>
+        <h1><%= VUE_APP_TITLE %></h1>
+      </div>
+    </div>
+    <script>
+      /^http(s*):\/\//.test(location.href) ||
+        alert("基于vue-admin-beautiful开发的项目需要部署到服务器下访问");
+    </script>
+  </body>
+</html>

+ 96 - 0
public/static/css/loading.css

@@ -0,0 +1,96 @@
+.first-loading-wrp {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  height: 90vh;
+  min-height: 90vh;
+}
+
+.first-loading-wrp > h1 {
+  font-size: 30px;
+  font-weight: bolder;
+}
+
+.first-loading-wrp .loading-wrp {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 98px;
+}
+
+.dot {
+  position: relative;
+  box-sizing: border-box;
+  display: inline-block;
+  width: 64px;
+  height: 64px;
+  font-size: 64px;
+  transform: rotate(45deg);
+  animation: antRotate 1.2s infinite linear;
+}
+
+.dot i {
+  position: absolute;
+  display: block;
+  width: 28px;
+  height: 28px;
+  background-color: #1890ff;
+  border-radius: 100%;
+  opacity: 0.3;
+  transform: scale(0.75);
+  transform-origin: 50% 50%;
+  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: 0.4s;
+  animation-delay: 0.4s;
+}
+
+.dot i:nth-child(3) {
+  right: 0;
+  bottom: 0;
+  -webkit-animation-delay: 0.8s;
+  animation-delay: 0.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;
+  }
+}

+ 11 - 0
push.sh

@@ -0,0 +1,11 @@
+#!/usr/bin/env bash
+set -e
+git init
+git add -A
+git commit -m '🎉🎉🎉仓库重置到2020年9月29日,Vue2.6最后一个版本,之前版本不再支持,具体请查阅文档,Vue 3.0版本即将发布请耐心等待!!!'
+git push -f "https://${access_token}@github.com/chuzhixin/vue-admin-beautiful.git" master
+exec /bin/bash
+
+
+
+

+ 12 - 0
src/App.vue

@@ -0,0 +1,12 @@
+<template>
+  <div id="vue-admin-beautiful">
+    <router-view />
+  </div>
+</template>
+
+<script>
+  export default {
+    name: "App",
+    mounted() {},
+  };
+</script>

+ 9 - 0
src/api/ad.js

@@ -0,0 +1,9 @@
+import request from "@/utils/request";
+
+export function getList(data) {
+  return request({
+    url: "/ad/getList",
+    method: "get",
+    data,
+  });
+}

+ 9 - 0
src/api/blacklist.js

@@ -0,0 +1,9 @@
+import request from "@/utils/request";
+
+export function getList(data) {
+  return request({
+    url: "/blacklist/getList",
+    method: "post",
+    data,
+  });
+}

+ 9 - 0
src/api/changeLog.js

@@ -0,0 +1,9 @@
+import request from "@/utils/request";
+
+export function getList(data) {
+  return request({
+    url: "/changeLog/getList",
+    method: "post",
+    data,
+  });
+}

+ 9 - 0
src/api/colorfulIcon.js

@@ -0,0 +1,9 @@
+import request from "@/utils/request";
+
+export function getIconList(data) {
+  return request({
+    url: "/colorfulIcon/getList",
+    method: "post",
+    data,
+  });
+}

+ 20 - 0
src/api/github.js

@@ -0,0 +1,20 @@
+import request from "axios";
+
+export function getRepos(params) {
+  return request({
+    url: "https://api.github.com/repos/chuzhixin/vue-admin-beautiful",
+    method: "get",
+    params,
+    timeout: 10000,
+  });
+}
+
+export function getStargazers(params) {
+  return request({
+    url:
+      "https://api.github.com/repos/chuzhixin/vue-admin-beautiful/stargazers",
+    method: "get",
+    params,
+    timeout: 10000,
+  });
+}

+ 9 - 0
src/api/goodsDetail.js

@@ -0,0 +1,9 @@
+import request from "@/utils/request";
+
+export function getList(data) {
+  return request({
+    url: "/goodsDetail/getList",
+    method: "post",
+    data,
+  });
+}

+ 9 - 0
src/api/goodsList.js

@@ -0,0 +1,9 @@
+import request from "@/utils/request";
+
+export function getList(data) {
+  return request({
+    url: "/goodsList/getList",
+    method: "post",
+    data,
+  });
+}

+ 9 - 0
src/api/icon.js

@@ -0,0 +1,9 @@
+import request from "@/utils/request";
+
+export function getIconList(data) {
+  return request({
+    url: "/icon/getList",
+    method: "post",
+    data,
+  });
+}

+ 8 - 0
src/api/markdown.js

@@ -0,0 +1,8 @@
+import request from "axios";
+
+export function getList() {
+  return request({
+    url: "https://cdn.jsdelivr.net/gh/prettier/prettier@master/docs/options.md",
+    method: "get",
+  });
+}

+ 25 - 0
src/api/menuManagement.js

@@ -0,0 +1,25 @@
+import request from "@/utils/request";
+
+export function getTree(data) {
+  return request({
+    url: "/menuManagement/getTree",
+    method: "post",
+    data,
+  });
+}
+
+export function doEdit(data) {
+  return request({
+    url: "/menuManagement/doEdit",
+    method: "post",
+    data,
+  });
+}
+
+export function doDelete(data) {
+  return request({
+    url: "/menuManagement/doDelete",
+    method: "post",
+    data,
+  });
+}

+ 8 - 0
src/api/notice.js

@@ -0,0 +1,8 @@
+import request from "@/utils/request";
+
+export function getNoticeList() {
+  return request({
+    url: "/notice/getList",
+    method: "post",
+  });
+}

+ 25 - 0
src/api/personalCenter.js

@@ -0,0 +1,25 @@
+import request from "@/utils/request";
+
+export function getList(data) {
+  return request({
+    url: "/personalCenter/getList",
+    method: "post",
+    data,
+  });
+}
+
+export function doEdit(data) {
+  return request({
+    url: "/personalCenter/doEdit",
+    method: "post",
+    data,
+  });
+}
+
+export function doDelete(data) {
+  return request({
+    url: "/personalCenter/doDelete",
+    method: "post",
+    data,
+  });
+}

+ 8 - 0
src/api/publicKey.js

@@ -0,0 +1,8 @@
+import request from "@/utils/request";
+
+export function getPublicKey() {
+  return request({
+    url: "/publicKey",
+    method: "post",
+  });
+}

+ 9 - 0
src/api/remixIcon.js

@@ -0,0 +1,9 @@
+import request from "@/utils/request";
+
+export function getIconList(data) {
+  return request({
+    url: "/remixIcon/getList",
+    method: "post",
+    data,
+  });
+}

+ 25 - 0
src/api/roleManagement.js

@@ -0,0 +1,25 @@
+import request from "@/utils/request";
+
+export function getList(data) {
+  return request({
+    url: "/roleManagement/getList",
+    method: "post",
+    data,
+  });
+}
+
+export function doEdit(data) {
+  return request({
+    url: "/roleManagement/doEdit",
+    method: "post",
+    data,
+  });
+}
+
+export function doDelete(data) {
+  return request({
+    url: "/roleManagement/doDelete",
+    method: "post",
+    data,
+  });
+}

+ 9 - 0
src/api/router.js

@@ -0,0 +1,9 @@
+import request from "@/utils/request";
+
+export function getRouterList(data) {
+  return request({
+    url: "/menu/navigate",
+    method: "post",
+    data,
+  });
+}

+ 25 - 0
src/api/table.js

@@ -0,0 +1,25 @@
+import request from "@/utils/request";
+
+export function getList(data) {
+  return request({
+    url: "/table/getList",
+    method: "post",
+    data,
+  });
+}
+
+export function doEdit(data) {
+  return request({
+    url: "/table/doEdit",
+    method: "post",
+    data,
+  });
+}
+
+export function doDelete(data) {
+  return request({
+    url: "/table/doDelete",
+    method: "post",
+    data,
+  });
+}

+ 9 - 0
src/api/tree.js

@@ -0,0 +1,9 @@
+import request from "@/utils/request";
+
+export function getTreeList(data) {
+  return request({
+    url: "/tree/list",
+    method: "post",
+    data,
+  });
+}

+ 38 - 0
src/api/user.js

@@ -0,0 +1,38 @@
+import request from "@/utils/request";
+import { encryptedData } from "@/utils/encrypt";
+import { loginRSA, tokenName } from "@/config/settings";
+
+export async function login(data) {
+  if (loginRSA) {
+    data = await encryptedData(data);
+  }
+  return request({
+    url: "/login",
+    method: "post",
+    data,
+  });
+}
+
+export function getUserInfo(accessToken) {
+  return request({
+    url: "/userInfo",
+    method: "post",
+    data: {
+      [tokenName]: accessToken,
+    },
+  });
+}
+
+export function logout() {
+  return request({
+    url: "/logout",
+    method: "post",
+  });
+}
+
+export function register() {
+  return request({
+    url: "/register",
+    method: "post",
+  });
+}

+ 25 - 0
src/api/userManagement.js

@@ -0,0 +1,25 @@
+import request from "@/utils/request";
+
+export function getList(data) {
+  return request({
+    url: "/userManagement/getList",
+    method: "post",
+    data,
+  });
+}
+
+export function doEdit(data) {
+  return request({
+    url: "/userManagement/doEdit",
+    method: "post",
+    data,
+  });
+}
+
+export function doDelete(data) {
+  return request({
+    url: "/userManagement/doDelete",
+    method: "post",
+    data,
+  });
+}

BIN
src/assets/comparison/left.jpg


BIN
src/assets/comparison/right.jpg


BIN
src/assets/error_images/401.png


BIN
src/assets/error_images/404.png


BIN
src/assets/error_images/cloud.png


BIN
src/assets/ewm.png


BIN
src/assets/login_images/background.jpg


BIN
src/assets/pro.png


BIN
src/assets/qr_logo/lqr_logo.png


+ 17 - 0
src/colorfulIcon/index.js

@@ -0,0 +1,17 @@
+import Vue from "vue";
+import { ColorfullIcon } from "@/layouts/components";
+
+Vue.component("vab-colorful-icon", ColorfullIcon);
+const req = require.context("./svg", false, /\.svg$/),
+  requireAll = (requireContext) => {
+    /*let a = requireContext.keys().map(requireContext);
+    let arr = [];
+    for (let i = 0; i < a.length; i++) {
+      console.log();
+      let icon = a[i].default.id;
+      arr.push(icon);
+    }
+    console.log(JSON.stringify(arr));*/
+    return requireContext.keys().map(requireContext);
+  };
+requireAll(req);

+ 1 - 0
src/colorfulIcon/svg/alphabetical_sorting.svg

@@ -0,0 +1 @@
+<svg class="icon" width="128" height="128" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg"><path d="M358.4 853.333H245.333l-23.466 64H147.2l121.6-324.266h61.867l119.466 324.266h-68.266l-23.467-64zm-98.133-57.6h81.066l-40.533-121.6-40.533 121.6zm4.266-418.133h162.134v53.333H179.2V390.4L341.333 160H179.2v-53.333h243.2v36.266L264.533 377.6z" fill="#2196F3"/><path d="M810.667 704V106.667h-85.334V704h-128L768 917.333 938.667 704z" fill="#546E7A"/></svg>

File diff suppressed because it is too large
+ 21 - 0
src/colorfulIcon/svg/vab.svg


+ 111 - 0
src/components/JsonEditor/index.vue

@@ -0,0 +1,111 @@
+<template>
+  <div class="json-editor">
+    <label>
+      <textarea ref="textarea" />
+    </label>
+  </div>
+</template>
+
+<script>
+  import CodeMirror from "codemirror";
+  import "codemirror/addon/lint/lint.css";
+  import "codemirror/lib/codemirror.css";
+  import "codemirror/theme/rubyblue.css";
+  import "codemirror/mode/javascript/javascript";
+  import "codemirror/addon/lint/lint";
+  import "codemirror/addon/lint/json-lint";
+
+  require("script-loader!jsonlint");
+
+  export default {
+    name: "JsonEditor",
+    props: {
+      value: {
+        type: [Array, Object],
+        default: () => {
+          return null;
+        },
+      },
+    },
+    data() {
+      return {
+        jsonEditor: false,
+      };
+    },
+    watch: {
+      value(value) {
+        const editorValue = this.jsonEditor.getValue();
+
+        if (editorValue) {
+          this.$emit("change", editorValue);
+        } else {
+          this.$baseMessage("JSON不能为空,否则无法生成表格", "error");
+        }
+        if (value !== editorValue) {
+          this.jsonEditor.setValue(JSON.stringify(this.value, null, 2));
+        }
+      },
+    },
+    mounted() {
+      this.jsonEditor = CodeMirror.fromTextArea(this.$refs.textarea, {
+        lineNumbers: true,
+        mode: "application/json",
+        gutters: ["CodeMirror-lint-markers"],
+        theme: "rubyblue",
+        lint: true,
+      });
+
+      this.jsonEditor.setValue(JSON.stringify(this.value, null, 2));
+      this.jsonEditor.on("change", (cm) => {
+        if (this.isJsonString(cm.getValue())) {
+          this.$emit("change", cm.getValue());
+        }
+      });
+    },
+    methods: {
+      getValue() {
+        return this.jsonEditor.getValue();
+      },
+      isJsonString(str) {
+        try {
+          if (typeof JSON.parse(str) == "object") {
+            return true;
+          }
+        } catch (e) {}
+        return false;
+      },
+    },
+  };
+</script>
+
+<style scoped>
+  .json-editor {
+    position: relative;
+    height: 100%;
+  }
+
+  .json-editor >>> .CodeMirror {
+    height: auto;
+    min-height: calc(100vh - 220px);
+  }
+
+  .json-editor >>> .CodeMirror-scroll {
+    min-height: calc(100vh - 220px);
+  }
+
+  .json-editor >>> .cm-s-rubyblue span.cm-string {
+    color: #f08047;
+  }
+
+  .json-editor >>> .cm-s-rubyblue .CodeMirror-gutters {
+    padding-right: 10px;
+
+    /* background: transparent; */
+    border-right: 1px solid #fff;
+  }
+
+  .json-editor >>> .cm-s-rubyblue.CodeMirror {
+    /* background: #08233e; */
+    color: white;
+  }
+</style>

+ 201 - 0
src/components/SelectTree/index.vue

@@ -0,0 +1,201 @@
+<template>
+  <div class="select-tree-template">
+    <el-select
+      v-model="selectValue"
+      :clearable="clearable"
+      :collapse-tags="selectType == 'multiple'"
+      :multiple="selectType == 'multiple'"
+      class="vab-tree-select"
+      value-key="id"
+      @clear="clearHandle"
+      @remove-tag="removeTag"
+    >
+      <el-option :value="selectKey">
+        <el-tree
+          id="treeOption"
+          ref="treeOption"
+          :current-node-key="currentNodeKey"
+          :data="treeOptions"
+          :default-checked-keys="defaultSelectedKeys"
+          :default-expanded-keys="defaultSelectedKeys"
+          :highlight-current="true"
+          :props="defaultProps"
+          :show-checkbox="selectType == 'multiple'"
+          node-key="id"
+          @check="checkNode"
+          @node-click="nodeClick"
+        ></el-tree>
+      </el-option>
+    </el-select>
+  </div>
+</template>
+
+<script>
+  export default {
+    name: "SelectTreeTemplate",
+    props: {
+      /* 树形结构数据 */
+      treeOptions: {
+        type: Array,
+        default: () => {
+          return [];
+        },
+      },
+      /* 单选/多选 */
+      selectType: {
+        type: String,
+        default: () => {
+          return "single";
+        },
+      },
+      /* 初始选中值key */
+      selectedKey: {
+        type: String,
+        default: () => {
+          return "";
+        },
+      },
+      /* 初始选中值name */
+      selectedValue: {
+        type: String,
+        default: () => {
+          return "";
+        },
+      },
+      /* 可做选择的层级 */
+      selectLevel: {
+        type: [String, Number],
+        default: () => {
+          return "";
+        },
+      },
+      /* 可清空选项 */
+      clearable: {
+        type: Boolean,
+        default: () => {
+          return true;
+        },
+      },
+    },
+    data() {
+      return {
+        defaultProps: {
+          children: "children",
+          label: "name",
+        },
+        defaultSelectedKeys: [], //初始选中值数组
+        currentNodeKey: this.selectedKey,
+        selectValue:
+          this.selectType == "multiple"
+            ? this.selectedValue.split(",")
+            : this.selectedValue, //下拉框选中值label
+        selectKey:
+          this.selectType == "multiple"
+            ? this.selectedKey.split(",")
+            : this.selectedKey, //下拉框选中值value
+      };
+    },
+    mounted() {
+      const that = this;
+      this.initTree();
+    },
+    methods: {
+      // 初始化树的值
+      initTree() {
+        const that = this;
+        if (that.selectedKey) {
+          that.defaultSelectedKeys = that.selectedKey.split(","); // 设置默认展开
+          if (that.selectType == "single") {
+            that.$refs.treeOption.setCurrentKey(that.selectedKey); // 设置默认选中
+          } else {
+            that.$refs.treeOption.setCheckedKeys(that.defaultSelectedKeys);
+          }
+        }
+      },
+      // 清除选中
+      clearHandle() {
+        const that = this;
+        this.selectValue = "";
+        this.selectKey = "";
+        this.defaultSelectedKeys = [];
+        this.currentNodeKey = "";
+        this.clearSelected();
+        if (that.selectType == "single") {
+          that.$refs.treeOption.setCurrentKey(""); // 设置默认选中
+        } else {
+          that.$refs.treeOption.setCheckedKeys([]);
+        }
+      },
+      /* 清空选中样式 */
+      clearSelected() {
+        const allNode = document.querySelectorAll("#treeOption .el-tree-node");
+        allNode.forEach((element) => element.classList.remove("is-current"));
+      },
+      // select多选时移除某项操作
+      removeTag(val) {
+        this.$refs.treeOption.setCheckedKeys([]);
+      },
+      // 点击叶子节点
+      nodeClick(data, node, el) {
+        if (data.rank >= this.selectLevel) {
+          this.selectValue = data.name;
+          this.selectKey = data.id;
+        }
+      },
+      // 节点选中操作
+      checkNode(data, node, el) {
+        const checkedNodes = this.$refs.treeOption.getCheckedNodes();
+        const keyArr = [];
+        const valueArr = [];
+        checkedNodes.forEach((item) => {
+          if (item.rank >= this.selectLevel) {
+            keyArr.push(item.id);
+            valueArr.push(item.name);
+          }
+        });
+        this.selectValue = valueArr;
+        this.selectKey = keyArr;
+      },
+    },
+  };
+</script>
+
+<style lang="scss" scoped>
+  .el-scrollbar .el-scrollbar__view .el-select-dropdown__item {
+    height: auto;
+    max-height: 274px;
+    padding: 0;
+    overflow-y: auto;
+  }
+
+  .el-select-dropdown__item.selected {
+    font-weight: normal;
+  }
+
+  ul li > .el-tree .el-tree-node__content {
+    height: auto;
+    padding: 0 20px;
+  }
+
+  .el-tree-node__label {
+    font-weight: normal;
+  }
+
+  .el-tree > .is-current .el-tree-node__label {
+    font-weight: 700;
+    color: #409eff;
+  }
+
+  .el-tree > .is-current .el-tree-node__children .el-tree-node__label {
+    font-weight: normal;
+    color: #606266;
+  }
+</style>
+<style lang="scss">
+  /* .vab-tree-select{
+      .el-tag__close.el-icon-close{
+        width:0;
+        overflow:hidden;
+      }
+    } */
+</style>

+ 191 - 0
src/components/VabCharge/index.vue

@@ -0,0 +1,191 @@
+<template>
+  <div class="content">
+    <div class="g-container" :style="styleObj">
+      <div class="g-number">
+        <vab-count
+          :start-val="startVal"
+          :end-val="endVal"
+          :duration="duration"
+          :separator="separator"
+          :prefix="prefix"
+          :suffix="suffix"
+          :decimals="decimals"
+        />
+      </div>
+      <div class="g-contrast">
+        <div class="g-circle"></div>
+        <ul class="g-bubbles">
+          <li v-for="(item, index) in 15" :key="index"></li>
+        </ul>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+  export default {
+    name: "VabCharge",
+    props: {
+      styleObj: {
+        type: Object,
+        default: () => {
+          return {};
+        },
+      },
+      startVal: {
+        type: Number,
+        default: 0,
+      },
+      endVal: {
+        type: Number,
+        default: 100,
+      },
+    },
+    data() {
+      return {
+        decimals: 2,
+        prefix: "",
+        suffix: "%",
+        separator: ",",
+        duration: 3000,
+      };
+    },
+    created() {},
+    mounted() {},
+    methods: {},
+  };
+</script>
+
+<style lang="scss" scoped>
+  .content {
+    position: relative;
+    display: flex;
+    align-items: center; /* 垂直居中 */
+    justify-content: center; /* 水平居中 */
+    width: 100%;
+    background: #000;
+
+    .g-number {
+      position: absolute;
+      top: 27%;
+      z-index: 99;
+      width: 300px;
+      font-size: 32px;
+      color: #fff;
+      text-align: center;
+    }
+
+    .g-container {
+      position: relative;
+      width: 300px;
+      height: 400px;
+      margin: auto;
+    }
+
+    .g-contrast {
+      width: 300px;
+      height: 400px;
+      overflow: hidden;
+      background-color: #000;
+      filter: contrast(15) hue-rotate(0);
+      animation: hueRotate 10s infinite linear;
+    }
+
+    .g-circle {
+      position: relative;
+      box-sizing: border-box;
+      width: 300px;
+      height: 300px;
+      filter: blur(8px);
+
+      &::after {
+        position: absolute;
+        top: 40%;
+        left: 50%;
+        width: 200px;
+        height: 200px;
+        content: "";
+        background-color: #00ff6f;
+        border-radius: 42% 38% 62% 49% / 45%;
+        transform: translate(-50%, -50%) rotate(0);
+        animation: rotate 10s infinite linear;
+      }
+
+      &::before {
+        position: absolute;
+        top: 40%;
+        left: 50%;
+        z-index: 99;
+        width: 176px;
+        height: 176px;
+        content: "";
+        background-color: #000;
+        border-radius: 50%;
+        transform: translate(-50%, -50%);
+      }
+    }
+
+    .g-bubbles {
+      position: absolute;
+      bottom: 0;
+      left: 50%;
+      width: 100px;
+      height: 40px;
+      background-color: #00ff6f;
+      filter: blur(5px);
+      border-radius: 100px 100px 0 0;
+      transform: translate(-50%, 0);
+    }
+
+    li {
+      position: absolute;
+      background: #00ff6f;
+      border-radius: 50%;
+    }
+
+    @for $i from 0 through 15 {
+      li:nth-child(#{$i}) {
+        $width: 15 + random(15) + px;
+
+        top: 50%;
+        left: 15 + random(70) + px;
+        width: $width;
+        height: $width;
+        transform: translate(-50%, -50%);
+        animation: moveToTop
+          #{random(6) +
+          3}s
+          ease-in-out -#{random(5000) /
+          1000}s
+          infinite;
+      }
+    }
+
+    @keyframes rotate {
+      50% {
+        border-radius: 45% / 42% 38% 58% 49%;
+      }
+
+      100% {
+        transform: translate(-50%, -50%) rotate(720deg);
+      }
+    }
+
+    @keyframes moveToTop {
+      90% {
+        opacity: 1;
+      }
+
+      100% {
+        opacity: 0.1;
+        transform: translate(-50%, -180px);
+      }
+    }
+
+    @keyframes hueRotate {
+      100% {
+        filter: contrast(15) hue-rotate(360deg);
+      }
+    }
+  }
+</style>

+ 92 - 0
src/components/VabImage/index.vue

@@ -0,0 +1,92 @@
+<template>
+  <div class="vab-image__outter">
+    <el-image
+      :src="bigSrc"
+      fit="cover"
+      style="width: 100%; height: 100%"
+      @click="clickBig"
+    ></el-image>
+    <el-image
+      :src="smallSrc"
+      class="vab-image__outter__small"
+      fit="cover"
+      @click="clickSmall"
+    ></el-image>
+    <span class="vab-image__outter__percent">{{ percent }}%</span>
+  </div>
+</template>
+
+<script>
+  export default {
+    name: "VabImage",
+    components: {},
+    props: {
+      bigSrc: {
+        type: String,
+        default: "",
+      },
+      smallSrc: {
+        type: String,
+        default: "",
+      },
+      percent: {
+        type: Number,
+        default: 97,
+      },
+    },
+    data() {
+      return {};
+    },
+    created() {},
+    mounted() {},
+    methods: {
+      clickBig() {
+        this.$emit("clickBig");
+      },
+      clickSmall() {
+        this.$emit("clickSmall");
+      },
+    },
+  };
+</script>
+
+<style lang="scss" scoped>
+  .vab-image {
+    &__outter {
+      position: relative;
+      width: 100%;
+      height: 100%;
+
+      ::v-deep {
+        img {
+          border-radius: $base-border-radius;
+        }
+      }
+
+      &__small {
+        position: absolute;
+        top: 0;
+        right: 0;
+        width: 80px;
+        height: 100px;
+        border-bottom: 1px solid $base-color-white;
+        border-left: 1px solid $base-color-white;
+        border-radius: $base-border-radius;
+      }
+
+      &__percent {
+        position: absolute;
+        right: 0;
+        bottom: 0;
+        display: inline-block;
+        min-width: 50px;
+        height: 25px;
+        line-height: 25px;
+        color: $base-color-white;
+        text-align: center;
+        background-color: $base-color-red;
+        border-radius: $base-border-radius;
+      }
+    }
+  }
+</style>

+ 313 - 0
src/components/VabProfile/index.vue

@@ -0,0 +1,313 @@
+<template>
+  <div class="card" :style="styleObj">
+    <div class="card-borders">
+      <div class="border-top"></div>
+      <div class="border-right"></div>
+      <div class="border-bottom"></div>
+      <div class="border-left"></div>
+    </div>
+    <div class="card-content">
+      <el-image :src="avatar" class="avatar"></el-image>
+      <div class="username">{{ username }}</div>
+      <div class="social-icons">
+        <a
+          v-for="(item, index) in iconArray"
+          :key="index"
+          class="social-icon"
+          :href="item.url"
+          target="_blank"
+        >
+          <vab-icon :icon="['fas', item.icon]" />
+        </a>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+  export default {
+    name: "VabProfile",
+    props: {
+      styleObj: {
+        type: Object,
+        default: () => {
+          return {};
+        },
+      },
+      username: {
+        type: String,
+        default: "",
+      },
+      avatar: {
+        type: String,
+        default: "",
+      },
+      iconArray: {
+        type: Array,
+        default: () => {
+          return [
+            { icon: "bell", url: "" },
+            { icon: "bookmark", url: "" },
+            { icon: "cloud-sun", url: "" },
+          ];
+        },
+      },
+    },
+    data() {
+      return {};
+    },
+    created() {},
+    mounted() {},
+    methods: {},
+  };
+</script>
+
+<style lang="scss" scoped>
+  .card {
+    --card-bg-color: hsl(240, 31%, 25%);
+    --card-bg-color-transparent: hsla(240, 31%, 25%, 0.7);
+
+    position: relative;
+    width: 100%;
+    height: 100%;
+
+    .card-borders {
+      position: absolute;
+      top: 0;
+      left: 0;
+      width: 100%;
+      height: 100%;
+      overflow: hidden;
+
+      .border-top {
+        position: absolute;
+        top: 0;
+        width: 100%;
+        height: 2px;
+        background: var(--card-bg-color);
+        transform: translateX(-100%);
+        animation: slide-in-horizontal 0.8s cubic-bezier(0.645, 0.045, 0.355, 1)
+          forwards;
+      }
+
+      .border-right {
+        position: absolute;
+        right: 0;
+        width: 2px;
+        height: 100%;
+        background: var(--card-bg-color);
+        transform: translateY(100%);
+        animation: slide-in-vertical 0.8s cubic-bezier(0.645, 0.045, 0.355, 1)
+          forwards;
+      }
+
+      .border-bottom {
+        position: absolute;
+        bottom: 0;
+        width: 100%;
+        height: 2px;
+        background: var(--card-bg-color);
+        transform: translateX(100%);
+        animation: slide-in-horizontal-reverse 0.8s
+          cubic-bezier(0.645, 0.045, 0.355, 1) forwards;
+      }
+
+      .border-left {
+        position: absolute;
+        top: 0;
+        width: 2px;
+        height: 100%;
+        background: var(--card-bg-color);
+        transform: translateY(-100%);
+        animation: slide-in-vertical-reverse 0.8s
+          cubic-bezier(0.645, 0.045, 0.355, 1) forwards;
+      }
+    }
+
+    .card-content {
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+      height: 100%;
+      padding: 40px 0 40px 0;
+      background: var(--card-bg-color-transparent);
+      opacity: 0;
+      transform: scale(0.6);
+      animation: bump-in 0.5s 0.8s forwards;
+
+      .avatar {
+        width: 80px;
+        height: 80px;
+        border: 1px solid $base-color-white;
+        border-radius: 50%;
+        opacity: 0;
+        transform: scale(0.6);
+        animation: bump-in 0.5s 1s forwards;
+      }
+
+      .username {
+        position: relative;
+        margin-top: 20px;
+        margin-bottom: 20px;
+        font-size: 26px;
+        color: transparent;
+        letter-spacing: 2px;
+        animation: fill-text-white 1.2s 2s forwards;
+
+        &::before {
+          position: absolute;
+          top: 0;
+          left: 0;
+          width: 100%;
+          height: 100%;
+          color: black;
+          content: "";
+          background: #35b9f1;
+          transform: scaleX(0);
+          transform-origin: left;
+          animation: slide-in-out 1.2s 1.2s cubic-bezier(0.75, 0, 0, 1) forwards;
+        }
+      }
+
+      .social-icons {
+        display: flex;
+
+        .social-icon {
+          position: relative;
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          width: 2.5em;
+          height: 2.5em;
+          margin: 0 15px;
+          color: white;
+          text-decoration: none;
+          border-radius: 50%;
+
+          @for $i from 1 through 3 {
+            &:nth-child(#{$i}) {
+              &::before {
+                animation-delay: 2s + 0.1s * $i;
+              }
+
+              &::after {
+                animation-delay: 2.1s + 0.1s * $i;
+              }
+
+              svg {
+                animation-delay: 2.2s + 0.1s * $i;
+              }
+            }
+          }
+
+          &::before,
+          &::after {
+            position: absolute;
+            top: 0;
+            left: 0;
+            width: 100%;
+            height: 100%;
+            content: "";
+            border-radius: inherit;
+            transform: scale(0);
+          }
+
+          &::before {
+            background: #f7f1e3;
+            animation: scale-in 0.5s cubic-bezier(0.75, 0, 0, 1) forwards;
+          }
+
+          &::after {
+            background: #2c3e50;
+            animation: scale-in 0.5s cubic-bezier(0.75, 0, 0, 1) forwards;
+          }
+
+          svg {
+            z-index: 99;
+            transform: scale(0);
+            animation: scale-in 0.5s cubic-bezier(0.75, 0, 0, 1) forwards;
+          }
+        }
+      }
+    }
+  }
+
+  @keyframes bump-in {
+    50% {
+      transform: scale(1.05);
+    }
+
+    to {
+      opacity: 1;
+      transform: scale(1);
+    }
+  }
+
+  @keyframes slide-in-horizontal {
+    50% {
+      transform: translateX(0);
+    }
+
+    to {
+      transform: translateX(100%);
+    }
+  }
+
+  @keyframes slide-in-horizontal-reverse {
+    50% {
+      transform: translateX(0);
+    }
+
+    to {
+      transform: translateX(-100%);
+    }
+  }
+
+  @keyframes slide-in-vertical {
+    50% {
+      transform: translateY(0);
+    }
+
+    to {
+      transform: translateY(-100%);
+    }
+  }
+
+  @keyframes slide-in-vertical-reverse {
+    50% {
+      transform: translateY(0);
+    }
+
+    to {
+      transform: translateY(100%);
+    }
+  }
+
+  @keyframes slide-in-out {
+    50% {
+      transform: scaleX(1);
+      transform-origin: left;
+    }
+
+    50.1% {
+      transform-origin: right;
+    }
+
+    100% {
+      transform: scaleX(0);
+      transform-origin: right;
+    }
+  }
+
+  @keyframes fill-text-white {
+    to {
+      color: white;
+    }
+  }
+
+  @keyframes scale-in {
+    to {
+      transform: scale(1);
+    }
+  }
+</style>

+ 44 - 0
src/components/VabQrCode/index.vue

@@ -0,0 +1,44 @@
+<template>
+  <div class="app-container">
+    <vue-q-art :config="config"></vue-q-art>
+  </div>
+</template>
+
+<script>
+  import VueQArt from "vue-qart";
+  import qrImg from "@/assets/qr_logo/lqr_logo.png";
+
+  export default {
+    name: "VabQrCode",
+    components: {
+      VueQArt,
+    },
+    props: {
+      imagePath: {
+        type: String,
+        default: qrImg,
+      },
+      url: {
+        type: String,
+        default: "http://www.boyunvision.com/",
+      },
+      size: {
+        type: Number,
+        default: 500,
+      },
+    },
+    data() {
+      return {
+        config: {
+          value: this.url,
+          imagePath: this.imagePath,
+          filter: "color",
+          size: this.size,
+        },
+      };
+    },
+    created() {},
+    mounted() {},
+    methods: {},
+  };
+</script>

+ 82 - 0
src/components/VabSnow/index.vue

@@ -0,0 +1,82 @@
+<template>
+  <div class="content" :style="styleObj">
+    <div v-for="(item, index) in 200" :key="index" class="snow"></div>
+  </div>
+</template>
+
+<script>
+  export default {
+    name: "VabSnow",
+    props: {
+      styleObj: {
+        type: Object,
+        default: () => {
+          return {};
+        },
+      },
+    },
+    data() {
+      return {};
+    },
+    created() {},
+    mounted() {},
+    methods: {},
+  };
+</script>
+
+<style lang="scss" scoped>
+  .content {
+    position: relative;
+    width: 100%;
+    height: 100%;
+    overflow: hidden;
+    background: radial-gradient(ellipse at bottom, #1b2735 0%, #090a0f 100%);
+    filter: drop-shadow(0 0 10px white);
+  }
+
+  @function random_range($min, $max) {
+    $rand: random();
+    $random_range: $min + floor($rand * (($max - $min) + 1));
+
+    @return $random_range;
+  }
+
+  .snow {
+    $total: 200;
+
+    position: absolute;
+    width: 10px;
+    height: 10px;
+    background: white;
+    border-radius: 50%;
+
+    @for $i from 1 through $total {
+      $random-x: random(1000000) * 0.0001vw;
+      $random-offset: random_range(-100000, 100000) * 0.0001vw;
+      $random-x-end: $random-x + $random-offset;
+      $random-x-end-yoyo: $random-x + ($random-offset / 2);
+      $random-yoyo-time: random_range(30000, 80000) / 100000;
+      $random-yoyo-y: $random-yoyo-time * 100vh;
+      $random-scale: random(10000) * 0.0001;
+      $fall-duration: random_range(10, 30) * 1s;
+      $fall-delay: random(30) * -1s;
+
+      &:nth-child(#{$i}) {
+        opacity: random(10000) * 0.0001;
+        transform: translate($random-x, -10px) scale($random-scale);
+        animation: fall-#{$i} $fall-duration $fall-delay linear infinite;
+      }
+
+      @keyframes fall-#{$i} {
+        #{percentage($random-yoyo-time)} {
+          transform: translate($random-x-end, $random-yoyo-y)
+            scale($random-scale);
+        }
+
+        to {
+          transform: translate($random-x-end-yoyo, 100vh) scale($random-scale);
+        }
+      }
+    }
+  }
+</style>

+ 95 - 0
src/components/VabSticky/index.vue

@@ -0,0 +1,95 @@
+<template>
+  <div :style="{ height: height + 'px', zIndex: zIndex }">
+    <div
+      :class="className"
+      :style="{
+        top: isSticky ? stickyTop + 'px' : '',
+        zIndex: zIndex,
+        position: position,
+        width: width,
+        height: height + 'px',
+      }"
+    >
+      <slot></slot>
+    </div>
+  </div>
+</template>
+
+<script>
+  export default {
+    name: "VabSticky",
+    props: {
+      stickyTop: {
+        type: Number,
+        default: 0,
+      },
+      zIndex: {
+        type: Number,
+        default: 1,
+      },
+      className: {
+        type: String,
+        default: "",
+      },
+    },
+    data() {
+      return {
+        active: false,
+        position: "",
+        width: undefined,
+        height: undefined,
+        isSticky: false,
+      };
+    },
+    mounted() {
+      this.height = this.$el.getBoundingClientRect().height;
+      window.addEventListener("scroll", this.handleScroll);
+      window.addEventListener("resize", this.handleResize);
+    },
+    activated() {
+      this.handleScroll();
+    },
+    destroyed() {
+      window.removeEventListener("scroll", this.handleScroll);
+      window.removeEventListener("resize", this.handleResize);
+    },
+    methods: {
+      sticky() {
+        if (this.active) {
+          return;
+        }
+        this.position = "fixed";
+        this.active = true;
+        this.width = this.width + "px";
+        this.isSticky = true;
+      },
+      handleReset() {
+        if (!this.active) {
+          return;
+        }
+        this.reset();
+      },
+      reset() {
+        this.position = "";
+        this.width = "auto";
+        this.active = false;
+        this.isSticky = false;
+      },
+      handleScroll() {
+        const width = this.$el.getBoundingClientRect().width;
+        this.width = width || "auto";
+        const offsetTop = this.$el.getBoundingClientRect().top;
+        if (offsetTop < this.stickyTop) {
+          this.sticky();
+          return;
+        }
+        this.handleReset();
+      },
+      handleResize() {
+        if (this.isSticky) {
+          this.width = this.$el.getBoundingClientRect().width + "px";
+        }
+      },
+    },
+  };
+</script>

+ 267 - 0
src/components/VabUpload/index.vue

@@ -0,0 +1,267 @@
+<template>
+  <el-dialog
+    :title="title"
+    :visible.sync="dialogFormVisible"
+    width="909px"
+    :before-close="handleClose"
+    :close-on-click-modal="false"
+  >
+    <div class="upload">
+      <el-alert
+        :closable="false"
+        :title="`支持jpg、jpeg、png格式,单次可最多选择${limit}张图片,每张不可大于${size}M,如果大于${size}M会自动为您过滤`"
+        type="info"
+      ></el-alert>
+      <br />
+      <el-upload
+        ref="upload"
+        class="upload-content"
+        :name="name"
+        :data="data"
+        :action="action"
+        :headers="headers"
+        :on-change="handleChange"
+        :on-preview="handlePreview"
+        :on-remove="handleRemove"
+        :on-exceed="handleExceed"
+        :on-success="handleSuccess"
+        :on-progress="handleProgress"
+        :on-error="handleError"
+        :file-list="fileList"
+        :multiple="true"
+        :auto-upload="false"
+        accept="image/png, image/jpeg"
+        :limit="limit"
+        list-type="picture-card"
+        :close-on-click-modal="false"
+      >
+        <i slot="trigger" class="el-icon-plus"></i>
+        <el-dialog
+          title="查看大图"
+          append-to-body
+          :visible.sync="dialogVisible"
+        >
+          <div style="padding-bottom: 20px !important">
+            <img width="100%" :src="dialogImageUrl" alt="" />
+          </div>
+        </el-dialog>
+      </el-upload>
+    </div>
+    <div
+      slot="footer"
+      class="dialog-footer"
+      style="position: relative; padding-right: 15px; text-align: right"
+    >
+      <div
+        v-if="show"
+        style="position: absolute; top: 10px; left: 15px; color: #999"
+      >
+        正在上传中... 当前上传成功数:{{ imgSuccessNum }}张 当前上传失败数:{{
+          imgErrorNum
+        }}张
+      </div>
+      <el-button type="primary" @click="handleClose">关闭</el-button>
+      <el-button
+        style="margin-left: 10px"
+        size="small"
+        type="success"
+        :loading="loading"
+        @click="submitUpload"
+      >
+        开始上传
+      </el-button>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+  import { tokenName } from "@/config/settings";
+
+  export default {
+    name: "VabUpload",
+    props: {
+      url: {
+        type: String,
+        default: "/upload",
+        required: true,
+      },
+      name: {
+        type: String,
+        default: "file",
+        required: true,
+      },
+      limit: {
+        type: Number,
+        default: 50,
+        required: true,
+      },
+      size: {
+        type: Number,
+        default: 1,
+        required: true,
+      },
+    },
+    data() {
+      return {
+        show: false,
+        loading: false,
+        dialogVisible: false,
+        dialogImageUrl: "",
+        action: "",
+        headers: {},
+        fileList: [],
+        picture: "picture",
+        imgNum: 0,
+        imgSuccessNum: 0,
+        imgErrorNum: 0,
+        typeList: null,
+        title: "上传",
+        dialogFormVisible: false,
+        data: {},
+      };
+    },
+    computed: {
+      percentage() {
+        if (this.allImgNum == 0) return 0;
+        return this.$baseLodash.round(this.imgNum / this.allImgNum, 2) * 100;
+      },
+    },
+    created() {
+      if ("development" === process.env.NODE_ENV) {
+        this.api = process.env.VUE_APP_BASE_API;
+      } else {
+        this.api = `${window.location.protocol}//${window.location.host}`;
+      }
+
+      this.action = this.api + this.url;
+      this.headers[tokenName] = this.$baseAccessToken();
+    },
+    methods: {
+      submitUpload() {
+        this.$refs.upload.submit();
+      },
+      handleProgress(event, file, fileList) {
+        this.loading = true;
+        this.show = true;
+      },
+      handleChange(file, fileList) {
+        if (file.size > 1048576 * this.size) {
+          fileList.map((item, index) => {
+            if (item === file) {
+              fileList.splice(index, 1);
+            }
+          });
+          this.fileList = fileList;
+        } else {
+          this.allImgNum = fileList.length;
+        }
+      },
+      handleSuccess(response, file, fileList) {
+        this.imgNum = this.imgNum + 1;
+        this.imgSuccessNum = this.imgSuccessNum + 1;
+        if (fileList.length === this.imgNum) {
+          setTimeout(() => {
+            this.$emit("fetchDatas");
+            this.$baseMessage(
+              `上传完成! 共上传${fileList.length}张图片`,
+              "success"
+            );
+          }, 1000);
+        }
+
+        setTimeout(() => {
+          this.loading = false;
+          this.show = false;
+        }, 1000);
+      },
+      handleError(err, file, fileList) {
+        this.imgNum = this.imgNum + 1;
+        this.imgErrorNum = this.imgErrorNum + 1;
+        this.$baseMessage(
+          `文件[${file.raw.name}]上传失败,文件大小为${this.$baseLodash.round(
+            file.raw.size / 1024,
+            0
+          )}KB`,
+          "error"
+        );
+        setTimeout(() => {
+          this.loading = false;
+          this.show = false;
+        }, 1000);
+      },
+      handleRemove(file, fileList) {
+        this.imgNum = this.imgNum - 1;
+        this.allNum = this.allNum - 1;
+      },
+      handlePreview(file) {
+        this.dialogImageUrl = file.url;
+        this.dialogVisible = true;
+      },
+      handleExceed(files, fileList) {
+        this.$baseMessage(
+          `当前限制选择 ${this.limit} 个文件,本次选择了
+             ${files.length}
+             个文件`,
+          "error"
+        );
+      },
+      handleShow(data) {
+        this.title = "上传";
+        this.data = data;
+        this.dialogFormVisible = true;
+      },
+      handleClose() {
+        this.fileList = [];
+        this.picture = "picture";
+        this.allImgNum = 0;
+        this.imgNum = 0;
+        this.imgSuccessNum = 0;
+        this.imgErrorNum = 0;
+        if ("development" === process.env.NODE_ENV) {
+          this.api = process.env.VUE_APP_BASE_API;
+        } else {
+          this.api = `${window.location.protocol}//${window.location.host}`;
+        }
+
+        this.action = this.api + this.url;
+        this.headers[tokenName] = this.$baseAccessToken();
+        this.dialogFormVisible = false;
+      },
+    },
+  };
+</script>
+
+<style lang="scss" scoped>
+  .upload {
+    height: 600px;
+
+    .upload-content {
+      .el-upload__tip {
+        display: block;
+        height: 30px;
+        line-height: 30px;
+      }
+
+      ::v-deep {
+        .el-upload--picture-card {
+          width: 128px;
+          height: 128px;
+          margin: 3px 8px 8px 8px;
+          border: 2px dashed #c0ccda;
+        }
+
+        .el-upload-list--picture {
+          margin-bottom: 20px;
+        }
+
+        .el-upload-list--picture-card {
+          .el-upload-list__item {
+            width: 128px;
+            height: 128px;
+            margin: 3px 8px 8px 8px;
+          }
+        }
+      }
+    }
+  }
+</style>

+ 85 - 0
src/config/permission.js

@@ -0,0 +1,85 @@
+/**
+ * @copyright chuzhixin 1204505056@qq.com
+ * @description 路由守卫,目前两种模式:all模式与intelligence模式
+ */
+import router from "@/router";
+import store from "@/store";
+import VabProgress from "nprogress";
+import "nprogress/nprogress.css";
+import getPageTitle from "@/utils/pageTitle";
+import {
+  authentication,
+  loginInterception,
+  progressBar,
+  recordRoute,
+  routesWhiteList,
+} from "./settings";
+
+VabProgress.configure({
+  easing: "ease",
+  speed: 500,
+  trickleSpeed: 200,
+  showSpinner: false,
+});
+router.beforeResolve(async (to, from, next) => {
+  if (progressBar) VabProgress.start();
+  let hasToken = store.getters["user/accessToken"];
+
+  if (!loginInterception) hasToken = true;
+
+  if (hasToken) {
+    if (to.path === "/login") {
+      next({ path: "/" });
+      if (progressBar) VabProgress.done();
+    } else {
+      const hasPermissions =
+        store.getters["user/permissions"] &&
+        store.getters["user/permissions"].length > 0;
+      if (hasPermissions) {
+        next();
+      } else {
+        try {
+          let permissions;
+          if (!loginInterception) {
+            //settings.js loginInterception为false时,创建虚拟权限
+            await store.dispatch("user/setPermissions", ["admin"]);
+            permissions = ["admin"];
+          } else {
+            permissions = await store.dispatch("user/getUserInfo");
+          }
+
+          let accessRoutes = [];
+          if (authentication === "intelligence") {
+            accessRoutes = await store.dispatch(
+              "routes/setRoutes",
+              permissions
+            );
+          } else if (authentication === "all") {
+            accessRoutes = await store.dispatch("routes/setAllRoutes");
+          }
+          router.addRoutes(accessRoutes);
+          next({ ...to, replace: true });
+        } catch {
+          await store.dispatch("user/resetAccessToken");
+          if (progressBar) VabProgress.done();
+        }
+      }
+    }
+  } else {
+    if (routesWhiteList.indexOf(to.path) !== -1) {
+      next();
+    } else {
+      if (recordRoute) {
+        next(`/login?redirect=${to.path}`);
+      } else {
+        next("/login");
+      }
+
+      if (progressBar) VabProgress.done();
+    }
+  }
+  document.title = getPageTitle(to.meta.title);
+});
+router.afterEach(() => {
+  if (progressBar) VabProgress.done();
+});

+ 101 - 0
src/config/settings.js

@@ -0,0 +1,101 @@
+/**
+ * @copyright chuzhixin 1204505056@qq.com
+ * @description 全局变量配置
+ */
+module.exports = {
+  // 开发以及部署时的URL
+  publicPath: "",
+  // 生产环境构建文件的目录名
+  outputDir: "dist",
+  // 放置生成的静态资源 (js、css、img、fonts) 的 (相对于 outputDir 的) 目录。
+  assetsDir: "static",
+  // 开发环境每次保存时是否输出为eslint编译警告
+  lintOnSave: true,
+  // 进行编译的依赖
+  transpileDependencies: ["vue-echarts", "resize-detector", "zx-layouts"],
+  // 默认的接口地址 如果是开发环境和生产环境走vab-mock-server,当然你也可以选择自己配置成需要的接口地址
+  baseURL:
+    process.env.NODE_ENV === "development"
+      ? "vab-mock-server"
+      : "vab-mock-server",
+  //标题 (包括初次加载雪花屏的标题 页面的标题 浏览器的标题)
+  title: "vue-admin-beautiful",
+  //简写
+  abbreviation: "vab",
+  //开发环境端口号
+  devPort: "80",
+  //版本号
+  version: process.env.VUE_APP_VERSION,
+  //烦请保留package.json作者信息 保留版权可免费商用 如需去除并自定义为自己企业的版权请联系群主QQ 1204505056 需支付299元 恶意修改发生纠纷及出现任何问题 由修改人自行承担
+  copyright: process.env.VUE_APP_AUTHOR,
+  //是否显示页面底部版权信息,建议您显示,当然您也可以选择不显示,不管您是付费用户还是未付费用户您都有选择显示或者不显示的权利
+  footerCopyright: process.env.NODE_ENV !== "development",
+  //是否显示右上角github图标
+  githubCorner: process.env.NODE_ENV !== "development",
+  //是否显示顶部进度条
+  progressBar: true,
+  //缓存路由的最大数量
+  keepAliveMaxNum: 99,
+  // 路由模式,可选值为 history 或 hash
+  routerMode: "hash",
+  //不经过token校验的路由
+  routesWhiteList: ["/login", "/register", "/404", "/401"],
+  //加载时显示文字
+  loadingText: "正在加载中...",
+  //token名称
+  tokenName: "accessToken",
+  //token在localStorage、sessionStorage、cookie存储的key的名称
+  tokenTableName: "vue-admin-beautiful",
+  //token存储位置localStorage sessionStorage cookie
+  storage: "localStorage",
+  //token失效回退到登录页时是否记录本次的路由
+  recordRoute: true,
+  //是否显示logo,不显示时设置false,显示时请填写remixIcon图标名称,暂时只支持设置remixIcon
+  logo: "vuejs-fill",
+  //是否国定头部 固定fixed 不固定noFixed
+  header: "fixed",
+  //横纵布局 horizontal vertical
+  layout: "vertical",
+  //是否开启主题配置按钮
+  themeBar: true,
+  //是否显示多标签页
+  tagsBar: true,
+  //是否显示骨架屏
+  skeleton: false,
+  //配后端数据的接收方式application/json;charset=UTF-8或者application/x-www-form-urlencoded;charset=UTF-8
+  contentType: "application/json;charset=UTF-8",
+  //消息框消失时间
+  messageDuration: 3000,
+  //最长请求时间
+  requestTimeout: 5000,
+  //操作正常code,支持String、Array、int多种类型
+  successCode: [200, 0],
+  //登录失效code
+  invalidCode: 402,
+  //无权限code
+  noPermissionCode: 401,
+  //是否显示在页面高亮错误
+  errorLog: ["development", "test", "production"],
+  //是否开启登录拦截
+  loginInterception: true,
+  //是否开启登录RSA加密
+  loginRSA: true,
+  //是否依据mock数据生成webstorm HTTP Request请求文件
+  httpRequestFile: false,
+  //intelligence和all两种方式,前者后端权限只控制permissions不控制view文件的import(前后端配合,减轻后端工作量),all方式完全交给后端前端只负责加载
+  authentication: "intelligence",
+  //vertical布局时是否只保持一个子菜单的展开
+  uniqueOpened: true,
+  //vertical布局时默认展开的菜单path,使用逗号隔开建议只展开一个
+  defaultOopeneds: ["/vab"],
+  //需要加loading层的请求,防止重复提交
+  debounce: ["doEdit"],
+  //需要自动注入并加载的模块
+  providePlugin: { maptalks: "maptalks", "window.maptalks": "maptalks" },
+  //npm run build时是否自动生成7z压缩包
+  build7z: false,
+  //代码生成机生成在view下的文件夹名称
+  templateFolder: "project",
+  //是否显示终端donation打印
+  donation: true,
+};

+ 53 - 0
src/config/static.js

@@ -0,0 +1,53 @@
+/**
+ * @copyright chuzhixin 1204505056@qq.com
+ * @description 导入所有 controller 模块,浏览器环境中自动输出controller文件夹下Mock接口,请勿修改。
+ */
+import Mock from "mockjs";
+import { paramObj } from "@/utils";
+
+const mocks = [];
+const files = require.context("../../mock/controller", false, /\.js$/);
+
+files.keys().forEach((key) => {
+  const obj = files(key);
+  mocks.push(...obj);
+});
+
+export function mockXHR() {
+  Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send;
+  Mock.XHR.prototype.send = function () {
+    if (this.custom.xhr) {
+      this.custom.xhr.withCredentials = this.withCredentials || false;
+
+      if (this.responseType) {
+        this.custom.xhr.responseType = this.responseType;
+      }
+    }
+    this.proxy_send(...arguments);
+  };
+
+  function XHR2ExpressReqWrap(respond) {
+    return function (options) {
+      let result = null;
+      if (respond instanceof Function) {
+        const { body, type, url } = options;
+        result = respond({
+          method: type,
+          body: JSON.parse(body),
+          query: paramObj(url),
+        });
+      } else {
+        result = respond;
+      }
+      return Mock.mock(result);
+    };
+  }
+
+  for (const i of mocks) {
+    Mock.mock(
+      new RegExp(i.url),
+      i.type || "get",
+      XHR2ExpressReqWrap(i.response)
+    );
+  }
+}

+ 3 - 0
src/layouts/EmptyLayout.vue

@@ -0,0 +1,3 @@
+<template>
+  <router-view />
+</template>

+ 52 - 0
src/layouts/components/Ad/index.vue

@@ -0,0 +1,52 @@
+<template>
+  <div class="vab-ad">
+    <el-carousel
+      v-if="adList"
+      height="30px"
+      direction="vertical"
+      :autoplay="true"
+      :interval="3000"
+      indicator-position="none"
+    >
+      <el-carousel-item v-for="(item, index) in adList" :key="index">
+        <el-tag type="warning">Ad</el-tag>
+        <a target="_blank" :href="item.url">{{ item.title }}</a>
+      </el-carousel-item>
+    </el-carousel>
+  </div>
+</template>
+<script>
+  import { getList } from "@/api/ad";
+  export default {
+    data() {
+      return {
+        nodeEnv: process.env.NODE_ENV,
+        adList: [],
+      };
+    },
+    created() {
+      this.fetchData();
+    },
+    methods: {
+      async fetchData() {
+        const { data } = await getList();
+        this.adList = data;
+      },
+    },
+  };
+</script>
+<style lang="scss" scoped>
+  .vab-ad {
+    height: 30px;
+    padding-right: $base-padding;
+    padding-left: $base-padding;
+    line-height: 30px;
+    cursor: pointer;
+    background: #eef1f6;
+    box-shadow: 0 -1px 2px rgba(0, 21, 41, 0.08) inset;
+
+    a {
+      color: #999;
+    }
+  }
+</style>

+ 21 - 0
src/layouts/components/index.js

@@ -0,0 +1,21 @@
+/**
+ * @copyright chuzhixin 1204505056@qq.com
+ * @description 公共布局导出,已封装成npm,便于此后在线升级,当然也存在一定的弊端,给开发者自定义增加了一定的困难,如果您一定要进行高度自定义,请仔细阅读VIP群文档,layouts本地化篇
+ */
+export { default as ColorfullIcon } from "zx-layouts/ColorfullIcon";
+export { default as RemixIcon } from "zx-layouts/RemixIcon";
+export { default as VabDrag } from "zx-layouts/Drag";
+export { default as VabPermissions } from "zx-layouts/Permissions";
+export { default as VabQueryForm } from "zx-layouts/VabQueryForm/export";
+export { default as Logo } from "zx-layouts/Logo";
+export { default as Avatar } from "zx-layouts/Avatar";
+export { default as Ad } from "./Ad";
+export { default as AppMain } from "zx-layouts/AppMain";
+export { default as TagsBar } from "zx-layouts/TagsBar";
+export { default as SideBar } from "zx-layouts/SideBar";
+export { default as Breadcrumb } from "zx-layouts/Breadcrumb";
+export { default as FullScreenBar } from "zx-layouts/FullScreenBar";
+export { default as ErrorLog } from "zx-layouts/ErrorLog";
+export { default as ThemeBar } from "zx-layouts/ThemeBar";
+export { default as TopBar } from "zx-layouts/TopBar";
+export { default as NavBar } from "zx-layouts/NavBar";

+ 313 - 0
src/layouts/index.vue

@@ -0,0 +1,313 @@
+<template>
+  <div class="vue-admin-beautiful-wrapper" :class="classObj">
+    <div
+      v-if="'horizontal' === layout"
+      class="layout-container-horizontal"
+      :class="{
+        fixed: header === 'fixed',
+        'no-tags-bar': tagsBar === 'false' || tagsBar === false,
+      }"
+    >
+      <div :class="header === 'fixed' ? 'fixed-header' : ''">
+        <top-bar></top-bar>
+        <div
+          v-if="tagsBar === 'true' || tagsBar === true"
+          :class="{ 'tag-view-show': tagsBar }"
+        >
+          <div class="vab-main">
+            <tags-bar></tags-bar>
+          </div>
+        </div>
+      </div>
+      <div class="vab-main main-padding">
+        <ad></ad>
+        <app-main></app-main>
+      </div>
+    </div>
+    <div
+      v-else
+      class="layout-container-vertical"
+      :class="{
+        fixed: header === 'fixed',
+        'no-tags-bar': tagsBar === 'false' || tagsBar === false,
+      }"
+    >
+      <div
+        v-if="device === 'mobile' && collapse === false"
+        class="mask"
+        @click="handleFoldSideBar"
+      />
+      <side-bar></side-bar>
+      <div class="vab-main" :class="collapse ? 'is-collapse-main' : ''">
+        <div :class="header === 'fixed' ? 'fixed-header' : ''">
+          <nav-bar></nav-bar>
+          <tags-bar v-if="tagsBar === 'true' || tagsBar === true" />
+        </div>
+        <ad></ad>
+        <app-main></app-main>
+      </div>
+    </div>
+    <el-backtop></el-backtop>
+  </div>
+</template>
+
+<script>
+  import { Ad, AppMain, NavBar, SideBar, TagsBar, TopBar } from "./components";
+  import { mapActions, mapGetters } from "vuex";
+  import { tokenName } from "@/config/settings";
+  export default {
+    name: "Layout",
+    components: {
+      Ad,
+      TopBar,
+      NavBar,
+      SideBar,
+      AppMain,
+      TagsBar,
+    },
+    data() {
+      return { oldLayout: "" };
+    },
+    computed: {
+      ...mapGetters({
+        layout: "settings/layout",
+        tagsBar: "settings/tagsBar",
+        collapse: "settings/collapse",
+        header: "settings/header",
+        device: "settings/device",
+      }),
+      classObj() {
+        return {
+          mobile: this.device === "mobile",
+        };
+      },
+    },
+    beforeMount() {
+      window.addEventListener("resize", this.handleResize);
+    },
+    beforeDestroy() {
+      window.removeEventListener("resize", this.handleResize);
+    },
+    mounted() {
+      this.oldLayout = this.layout;
+      const userAgent = navigator.userAgent;
+      if (userAgent.includes("Juejin")) {
+        this.$baseAlert(
+          "vue-admin-beautiful不支持在掘金内置浏览器演示,请手动复制以下地址到浏览器中查看http://mpfhrd48.sanxing.uz7.cn/vue-admin-beautiful"
+        );
+      }
+      const isMobile = this.handleIsMobile();
+      if (isMobile) {
+        if (isMobile) {
+          //横向布局时如果是手机端访问那么改成纵向版
+          this.$store.dispatch("settings/changeLayout", "vertical");
+        } else {
+          this.$store.dispatch("settings/changeLayout", this.oldLayout);
+        }
+        this.$store.dispatch("settings/toggleDevice", "mobile");
+        setTimeout(() => {
+          this.$store.dispatch("settings/foldSideBar");
+        }, 2000);
+      } else {
+        this.$store.dispatch("settings/openSideBar");
+      }
+      this.$nextTick(() => {
+        window.addEventListener(
+          "storage",
+          (e) => {
+            if (e.key === tokenName || e.key === null) window.location.reload();
+            if (e.key === tokenName && e.value === null)
+              window.location.reload();
+          },
+          false
+        );
+      });
+    },
+    methods: {
+      ...mapActions({
+        handleFoldSideBar: "settings/foldSideBar",
+      }),
+      handleIsMobile() {
+        return document.body.getBoundingClientRect().width - 1 < 992;
+      },
+      handleResize() {
+        if (!document.hidden) {
+          const isMobile = this.handleIsMobile();
+          if (isMobile) {
+            //横向布局时如果是手机端访问那么改成纵向版
+            this.$store.dispatch("settings/changeLayout", "vertical");
+          } else {
+            this.$store.dispatch("settings/changeLayout", this.oldLayout);
+          }
+
+          this.$store.dispatch(
+            "settings/toggleDevice",
+            isMobile ? "mobile" : "desktop"
+          );
+        }
+      },
+    },
+  };
+</script>
+
+<style lang="scss" scoped>
+  @mixin fix-header {
+    position: fixed;
+    top: 0;
+    right: 0;
+    left: 0;
+    z-index: $base-z-index - 2;
+    width: 100%;
+    overflow: hidden;
+  }
+
+  .vue-admin-beautiful-wrapper {
+    position: relative;
+    width: 100%;
+    height: 100%;
+
+    .layout-container-horizontal {
+      position: relative;
+
+      &.fixed {
+        padding-top: calc(#{$base-top-bar-height} + #{$base-tags-bar-height});
+      }
+
+      &.fixed.no-tags-bar {
+        padding-top: $base-top-bar-height;
+      }
+
+      ::v-deep {
+        .vab-main {
+          width: 88%;
+          margin: auto;
+        }
+
+        .fixed-header {
+          @include fix-header;
+        }
+
+        .tag-view-show {
+          background: $base-color-white;
+          box-shadow: $base-box-shadow;
+        }
+
+        .nav-bar-container {
+          .fold-unfold {
+            display: none;
+          }
+        }
+
+        .main-padding {
+          .app-main-container {
+            margin-top: $base-padding;
+            margin-bottom: $base-padding;
+            background: $base-color-white;
+          }
+        }
+      }
+    }
+
+    .layout-container-vertical {
+      position: relative;
+
+      .mask {
+        position: fixed;
+        top: 0;
+        right: 0;
+        bottom: 0;
+        left: 0;
+        z-index: $base-z-index - 1;
+        width: 100%;
+        height: 100vh;
+        overflow: hidden;
+        background: #000;
+        opacity: 0.5;
+      }
+
+      &.fixed {
+        padding-top: calc(#{$base-nav-bar-height} + #{$base-tags-bar-height});
+      }
+
+      &.fixed.no-tags-bar {
+        padding-top: $base-nav-bar-height;
+      }
+
+      .vab-main {
+        position: relative;
+        min-height: 100%;
+        margin-left: $base-left-menu-width;
+        background: #f6f8f9;
+        transition: $base-transition;
+
+        ::v-deep {
+          .fixed-header {
+            @include fix-header;
+
+            left: $base-left-menu-width;
+            width: $base-right-content-width;
+            box-shadow: $base-box-shadow;
+            transition: $base-transition;
+          }
+
+          .nav-bar-container {
+            position: relative;
+            box-sizing: border-box;
+          }
+
+          .tags-bar-container {
+            box-sizing: border-box;
+          }
+
+          .app-main-container {
+            width: calc(100% - #{$base-padding} - #{$base-padding});
+            margin: $base-padding auto;
+            background: $base-color-white;
+            border-radius: $base-border-radius;
+          }
+        }
+
+        &.is-collapse-main {
+          margin-left: $base-left-menu-width-min;
+
+          ::v-deep {
+            .fixed-header {
+              left: $base-left-menu-width-min;
+              width: calc(100% - 65px);
+            }
+          }
+        }
+      }
+    }
+
+    /* 手机端开始 */
+    &.mobile {
+      ::v-deep {
+        .el-pager,
+        .el-pagination__jump {
+          display: none;
+        }
+
+        .layout-container-vertical {
+          .el-scrollbar.side-bar-container.is-collapse {
+            width: 0;
+          }
+
+          .vab-main {
+            width: 100%;
+            margin-left: 0;
+          }
+        }
+
+        .vab-main {
+          .fixed-header {
+            left: 0 !important;
+            width: 100% !important;
+          }
+        }
+      }
+    }
+
+    /* 手机端结束 */
+  }
+</style>

+ 23 - 0
src/main.js

@@ -0,0 +1,23 @@
+import Vue from "vue";
+import App from "./App";
+import store from "./store";
+import router from "./router";
+import "./plugins";
+/**
+ * @copyright chuzhixin 1204505056@qq.com
+ * @description 生产环境默认都使用mock,如果正式用于生产环境时,记得去掉
+ */
+
+if (process.env.NODE_ENV === "production") {
+  const { mockXHR } = require("@/config/static");
+  mockXHR();
+}
+
+Vue.config.productionTip = false;
+
+new Vue({
+  el: "#vue-admin-beautiful",
+  router,
+  store,
+  render: (h) => h(App),
+});

+ 11 - 0
src/plugins/echarts.js

@@ -0,0 +1,11 @@
+import "echarts";
+import "echarts/map/js/china";
+import "echarts/map/js/world";
+
+import "echarts-wordcloud";
+
+import VabChart from "vue-echarts";
+import theme from "./vab-echarts-theme.json";
+
+VabChart.registerTheme("vab-echarts-theme", theme);
+export default VabChart;

+ 9 - 0
src/plugins/element.js

@@ -0,0 +1,9 @@
+import Vue from "vue";
+import ElementUI from "element-ui";
+import "element-ui/lib/theme-chalk/display.css";
+
+import "@/styles/element-variables.scss";
+
+Vue.use(ElementUI, {
+  size: "small",
+});

+ 0 - 0
src/plugins/index.js


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