lzj500 4 years ago
parent
commit
d5798536ac
100 changed files with 18854 additions and 0 deletions
  1. 2 0
      d2-admin/.browserslistrc
  2. 5 0
      d2-admin/.editorconfig
  3. 23 0
      d2-admin/.env
  4. 13 0
      d2-admin/.env.development
  5. 13 0
      d2-admin/.env.preview
  6. 16 0
      d2-admin/.eslintignore
  7. 28 0
      d2-admin/.eslintrc.js
  8. 11 0
      d2-admin/.github/ISSUE_TEMPLATE/bug.md
  9. 11 0
      d2-admin/.github/ISSUE_TEMPLATE/demo.md
  10. 11 0
      d2-admin/.github/ISSUE_TEMPLATE/display.md
  11. 11 0
      d2-admin/.github/ISSUE_TEMPLATE/doc.md
  12. 11 0
      d2-admin/.github/ISSUE_TEMPLATE/feature.md
  13. 11 0
      d2-admin/.github/ISSUE_TEMPLATE/other.md
  14. 11 0
      d2-admin/.github/ISSUE_TEMPLATE/question.md
  15. 11 0
      d2-admin/.github/ISSUE_TEMPLATE/update.md
  16. 113 0
      d2-admin/.github/workflows/deploy.yml
  17. 17 0
      d2-admin/.github/workflows/star.yml
  18. 21 0
      d2-admin/.gitignore
  19. 5 0
      d2-admin/.postcssrc.js
  20. 21 0
      d2-admin/LICENSE
  21. 24 0
      d2-admin/README.md
  22. 26 0
      d2-admin/README.zh.md
  23. 7 0
      d2-admin/babel.config.js
  24. 165 0
      d2-admin/d2-admin.babel
  25. 22 0
      d2-admin/dependencies-cdn.js
  26. 3 0
      d2-admin/jest.config.js
  27. 11 0
      d2-admin/jsconfig.json
  28. 15939 0
      d2-admin/package-lock.json
  29. 78 0
      d2-admin/package.json
  30. BIN
      d2-admin/public/icon.ico
  31. BIN
      d2-admin/public/image/baidu-pan-logo.png
  32. 6 0
      d2-admin/public/image/loading/loading-spin.svg
  33. BIN
      d2-admin/public/image/theme/chester/logo/all.png
  34. BIN
      d2-admin/public/image/theme/chester/logo/icon-only.png
  35. BIN
      d2-admin/public/image/theme/chester/preview@2x.png
  36. BIN
      d2-admin/public/image/theme/d2/logo/all.png
  37. BIN
      d2-admin/public/image/theme/d2/logo/icon-only.png
  38. BIN
      d2-admin/public/image/theme/d2/preview@2x.png
  39. BIN
      d2-admin/public/image/theme/element/logo/all.png
  40. BIN
      d2-admin/public/image/theme/element/logo/icon-only.png
  41. BIN
      d2-admin/public/image/theme/element/preview@2x.png
  42. BIN
      d2-admin/public/image/theme/line/bg.jpg
  43. BIN
      d2-admin/public/image/theme/line/logo/all.png
  44. BIN
      d2-admin/public/image/theme/line/logo/icon-only.png
  45. BIN
      d2-admin/public/image/theme/line/preview@2x.png
  46. BIN
      d2-admin/public/image/theme/star/bg.jpg
  47. BIN
      d2-admin/public/image/theme/star/logo/all.png
  48. BIN
      d2-admin/public/image/theme/star/logo/icon-only.png
  49. BIN
      d2-admin/public/image/theme/star/preview@2x.png
  50. BIN
      d2-admin/public/image/theme/tomorrow-night-blue/logo/all.png
  51. BIN
      d2-admin/public/image/theme/tomorrow-night-blue/logo/icon-only.png
  52. BIN
      d2-admin/public/image/theme/tomorrow-night-blue/preview@2x.png
  53. BIN
      d2-admin/public/image/theme/violet/logo/all.png
  54. BIN
      d2-admin/public/image/theme/violet/logo/icon-only.png
  55. BIN
      d2-admin/public/image/theme/violet/preview@2x.png
  56. 60 0
      d2-admin/public/index.html
  57. 28 0
      d2-admin/src/App.vue
  58. 17 0
      d2-admin/src/api/index.js
  59. 31 0
      d2-admin/src/api/modules/sys.user.api.js
  60. 102 0
      d2-admin/src/api/service.js
  61. 86 0
      d2-admin/src/api/tools.js
  62. 27 0
      d2-admin/src/assets/style/animate/vue-transition.scss
  63. 12 0
      d2-admin/src/assets/style/fixed/base.scss
  64. 31 0
      d2-admin/src/assets/style/fixed/element.scss
  65. 9 0
      d2-admin/src/assets/style/fixed/markdown.scss
  66. 8 0
      d2-admin/src/assets/style/fixed/n-progress.scss
  67. 5 0
      d2-admin/src/assets/style/fixed/tree-view.scss
  68. 9 0
      d2-admin/src/assets/style/fixed/vue-grid-layout.scss
  69. 5 0
      d2-admin/src/assets/style/fixed/vue-splitpane.scss
  70. 67 0
      d2-admin/src/assets/style/public-class.scss
  71. 44 0
      d2-admin/src/assets/style/public.scss
  72. 2 0
      d2-admin/src/assets/style/theme/chester/index.scss
  73. 64 0
      d2-admin/src/assets/style/theme/chester/setting.scss
  74. 2 0
      d2-admin/src/assets/style/theme/d2/index.scss
  75. 64 0
      d2-admin/src/assets/style/theme/d2/setting.scss
  76. 2 0
      d2-admin/src/assets/style/theme/element/index.scss
  77. 64 0
      d2-admin/src/assets/style/theme/element/setting.scss
  78. 2 0
      d2-admin/src/assets/style/theme/line/index.scss
  79. 64 0
      d2-admin/src/assets/style/theme/line/setting.scss
  80. 9 0
      d2-admin/src/assets/style/theme/register.scss
  81. 2 0
      d2-admin/src/assets/style/theme/star/index.scss
  82. 64 0
      d2-admin/src/assets/style/theme/star/setting.scss
  83. 454 0
      d2-admin/src/assets/style/theme/theme-base.scss
  84. 421 0
      d2-admin/src/assets/style/theme/theme.scss
  85. 2 0
      d2-admin/src/assets/style/theme/tomorrow-night-blue/index.scss
  86. 64 0
      d2-admin/src/assets/style/theme/tomorrow-night-blue/setting.scss
  87. 9 0
      d2-admin/src/assets/style/theme/violet/index.scss
  88. 64 0
      d2-admin/src/assets/style/theme/violet/setting.scss
  89. 23 0
      d2-admin/src/assets/style/unit/color.scss
  90. 19 0
      d2-admin/src/assets/svg-icons/icons/d2-admin-text.svg
  91. 13 0
      d2-admin/src/assets/svg-icons/icons/d2-admin.svg
  92. 7 0
      d2-admin/src/assets/svg-icons/index.js
  93. 27 0
      d2-admin/src/components/d2-container/components/d2-container-card-bs.vue
  94. 33 0
      d2-admin/src/components/d2-container/components/d2-container-card.vue
  95. 25 0
      d2-admin/src/components/d2-container/components/d2-container-full-bs.vue
  96. 31 0
      d2-admin/src/components/d2-container/components/d2-container-full.vue
  97. 26 0
      d2-admin/src/components/d2-container/components/d2-container-ghost-bs.vue
  98. 31 0
      d2-admin/src/components/d2-container/components/d2-container-ghost.vue
  99. 79 0
      d2-admin/src/components/d2-container/components/d2-source.vue
  100. 0 0
      d2-admin/src/components/d2-container/components/mixins/bs.js

+ 2 - 0
d2-admin/.browserslistrc

@@ -0,0 +1,2 @@
+> 1%
+last 2 versions

+ 5 - 0
d2-admin/.editorconfig

@@ -0,0 +1,5 @@
+[*.{js,jsx,ts,tsx,vue}]
+indent_style = space
+indent_size = 2
+trim_trailing_whitespace = true
+insert_final_newline = true

+ 23 - 0
d2-admin/.env

@@ -0,0 +1,23 @@
+# 所有环境默认
+
+# 页面 title 前缀
+VUE_APP_TITLE=D2Admin
+
+# 网络请求公用地址
+VUE_APP_API=http://local.lzj/yckj_framework/thinkphp6/public/index.php
+
+# 仓库地址
+VUE_APP_REPO=https://github.com/d2-projects/d2-admin-start-kit
+
+# 国际化配置
+VUE_APP_I18N_LOCALE=zh-chs
+VUE_APP_I18N_FALLBACK_LOCALE=en
+
+# element 颜色
+VUE_APP_ELEMENT_COLOR=#409EFF
+
+# 网络签名密钥 
+VUE_APP_API_SIGN_SECRET=32a1ff74699ff2d6ce4c497cb94cb5c8
+
+# 虚拟目录
+VUE_APP_PUBLIC_PATH="/"

+ 13 - 0
d2-admin/.env.development

@@ -0,0 +1,13 @@
+# 开发环境
+
+# 页面 title 前缀
+VUE_APP_TITLE=D2Admin dev
+
+# 网络请求公用地址
+VUE_APP_API=http://local.lzj/yckj_framework/thinkphp6/public/index.php
+
+
+
+
+
+

+ 13 - 0
d2-admin/.env.preview

@@ -0,0 +1,13 @@
+# 构建预览页面
+
+# 指定构建模式
+NODE_ENV=production
+
+# 标记当前构建方式
+VUE_APP_BUILD_MODE=PREVIEW
+
+# 显示源码按钮
+VUE_APP_SCOURCE_LINK=TRUE
+
+# 部署路径
+VUE_APP_PUBLIC_PATH=/

+ 16 - 0
d2-admin/.eslintignore

@@ -0,0 +1,16 @@
+# 忽略目录
+build/
+tests/
+node_modules/
+
+# D2CRUD 演示
+src/views/demo/d2-crud/
+
+# node 覆盖率文件
+coverage/
+
+# 忽略文件
+**/*-min.js
+**/*.min.js
+**/*.js
+**/*.vue

+ 28 - 0
d2-admin/.eslintrc.js

@@ -0,0 +1,28 @@
+module.exports = {
+  root: true,
+  env: {
+    node: true
+  },
+  'extends': [
+    'plugin:vue/essential',
+    '@vue/standard'
+  ],
+  rules: {
+    'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
+    'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
+  },
+  parserOptions: {
+    parser: 'babel-eslint'
+  },
+  overrides: [
+    {
+      files: [
+        '**/__tests__/*.{j,t}s?(x)',
+        '**/tests/unit/**/*.spec.{j,t}s?(x)'
+      ],
+      env: {
+        jest: true
+      }
+    }
+  ]
+}

+ 11 - 0
d2-admin/.github/ISSUE_TEMPLATE/bug.md

@@ -0,0 +1,11 @@
+---
+name: "👾 BUG"
+about: 代码错误
+---
+
+```
+为了统一格式,请将下面一行复制到 `Title` 栏,然后删除这部分
+👾 BUG | 你的标题
+```
+
+如果需要,在这里描述具体内容

+ 11 - 0
d2-admin/.github/ISSUE_TEMPLATE/demo.md

@@ -0,0 +1,11 @@
+---
+name: "🎮 示例相关"
+about: 增加或者完善示例
+---
+
+```
+为了统一格式,请将下面一行复制到 `Title` 栏,然后删除这部分
+🎮 示例相关 | 你的标题
+```
+
+如果需要,在这里描述具体内容

+ 11 - 0
d2-admin/.github/ISSUE_TEMPLATE/display.md

@@ -0,0 +1,11 @@
+---
+name: "🌈 显示优化"
+about: 显示方面调整
+---
+
+```
+为了统一格式,请将下面一行复制到 `Title` 栏,然后删除这部分
+🌈 显示优化 | 你的标题
+```
+
+如果需要,在这里描述具体内容

+ 11 - 0
d2-admin/.github/ISSUE_TEMPLATE/doc.md

@@ -0,0 +1,11 @@
+---
+name: "📔 文档相关"
+about: 更新或者新增文档内容
+---
+
+```
+为了统一格式,请将下面一行复制到 `Title` 栏,然后删除这部分
+📔 文档相关 | 你的标题
+```
+
+如果需要,在这里描述具体内容

+ 11 - 0
d2-admin/.github/ISSUE_TEMPLATE/feature.md

@@ -0,0 +1,11 @@
+---
+name: "🔩 功能开发"
+about: 开发新的功能
+---
+
+```
+为了统一格式,请将下面一行复制到 `Title` 栏,然后删除这部分
+🔩 功能开发 | 你的标题
+```
+
+如果需要,在这里描述具体内容

+ 11 - 0
d2-admin/.github/ISSUE_TEMPLATE/other.md

@@ -0,0 +1,11 @@
+---
+name: "🖐 其它问题"
+about: 其它类型的 issue 请使用该模板
+---
+
+```
+为了统一格式,请将下面一行复制到 `Title` 栏,然后删除这部分
+🖐 其它问题 | 你的标题
+```
+
+如果需要,在这里描述具体内容

+ 11 - 0
d2-admin/.github/ISSUE_TEMPLATE/question.md

@@ -0,0 +1,11 @@
+---
+name: "🤔 提问"
+about: 提出使用方面的问题
+---
+
+```
+为了统一格式,请将下面一行复制到 `Title` 栏,然后删除这部分
+🤔 提问 | 你的标题
+```
+
+如果需要,在这里描述具体内容

+ 11 - 0
d2-admin/.github/ISSUE_TEMPLATE/update.md

@@ -0,0 +1,11 @@
+---
+name: "⚙ 功能升级"
+about: 升级某个功能
+---
+
+```
+为了统一格式,请将下面一行复制到 `Title` 栏,然后删除这部分
+⚙ 功能升级 | 你的标题
+```
+
+如果需要,在这里描述具体内容

+ 113 - 0
d2-admin/.github/workflows/deploy.yml

@@ -0,0 +1,113 @@
+name: Deploy preview
+
+on:
+  push:
+    branches:
+      - master
+
+jobs:
+
+  cdn:
+    name: CDN
+    if: "! contains(github.event.head_commit.message, '[skip ci]')"
+    runs-on: ubuntu-latest
+    steps:
+    - uses: actions/checkout@v1
+    - uses: bahmutov/npm-install@v1
+    - name: Set vue cli env
+      shell: bash
+      run: |
+        echo -e "\
+        VUE_APP_PUBLIC_PATH=/d2-admin-start-kit/preview/\
+        " > .env.preview.local
+        cat .env.preview.local | while read line
+        do
+          echo $line
+        done
+    - name: Build
+      run: yarn build:preview --report
+    - name: Setup qshell
+      uses: foxundermoon/setup-qshell@v1
+      env:
+        ACTIONS_ALLOW_UNSECURE_COMMANDS: 'true'
+      with:
+        qshell-version: '2.4.0'
+    - name: Test qshell
+      run: qshell version
+    - name: Login
+      run: qshell account ${{ secrets.AK }} ${{ secrets.SK }} GITHUB_ACTION
+    - name: CDN upload
+      run: |
+        qshell qupload2 \
+        --src-dir=$GITHUB_WORKSPACE/dist \
+        --bucket=d2-cdn \
+        --key-prefix=${GITHUB_REPOSITORY//*\//}/preview/ \
+        --overwrite=true \
+        --check-exists=true \
+        --check-hash=true \
+        --check-size=true \
+        --rescan-local=true \
+        --thread-count=32
+    - name: CDN refresh
+      run: |
+        echo "https://cdn.d2.pub/${GITHUB_REPOSITORY//*\//}/preview/" > cdnrefresh.txt
+        qshell cdnrefresh --dirs -i ./cdnrefresh.txt
+  
+  ftp:
+    name: FTP
+    if: "! contains(github.event.head_commit.message, '[skip ci]')"
+    runs-on: ubuntu-latest
+    steps:
+    - uses: actions/checkout@v1
+    - uses: bahmutov/npm-install@v1
+    - name: Set vue cli env
+      shell: bash
+      run: |
+        echo -e "\
+        VUE_APP_PUBLIC_PATH=/d2-admin-start-kit/preview/\
+        " > .env.preview.local
+        cat .env.preview.local | while read line
+        do
+          echo $line
+        done
+    - name: Build
+      run: yarn build:preview --report
+    - name: Deploy
+      uses: SamKirkland/FTP-Deploy-Action@2.0.0
+      env:
+        FTP_SERVER: ${{ secrets.FTP_SERVER }}
+        FTP_USERNAME: ${{ secrets.FTP_USERNAME }}
+        FTP_PASSWORD: ${{ secrets.FTP_PASSWORD }}
+        METHOD: sftp
+        PORT: ${{ secrets.FTP_PORT }}
+        LOCAL_DIR: dist
+        REMOTE_DIR: /www/d2-admin-start-kit/preview
+        ARGS: --delete --verbose --parallel=100
+  
+  gh-pages:
+    name: Github Pages
+    if: "! contains(github.event.head_commit.message, '[skip ci]')"
+    runs-on: ubuntu-latest
+    steps:
+    - uses: actions/checkout@v1
+    - uses: bahmutov/npm-install@v1
+    - name: Set vue cli env
+      shell: bash
+      run: |
+        echo -e "\
+        VUE_APP_PUBLIC_PATH=/d2-admin-start-kit/\
+        " > .env.preview.local
+        cat .env.preview.local | while read line
+        do
+          echo $line
+        done
+    - name: Build
+      run: yarn build:preview --report
+    - name: Deploy
+      uses: peaceiris/actions-gh-pages@v2
+      env:
+        PERSONAL_TOKEN: ${{ secrets.ACCESS_TOKEN }}
+        PUBLISH_BRANCH: gh-pages
+        PUBLISH_DIR: ./dist
+      with:
+        forceOrphan: true

+ 17 - 0
d2-admin/.github/workflows/star.yml

@@ -0,0 +1,17 @@
+name: Star notice
+
+on:
+  watch:
+    types: [started]
+
+jobs:
+  bark:
+
+    runs-on: ubuntu-latest
+
+    steps:
+    - name: send bark message
+      run: |
+        repo=${GITHUB_REPOSITORY//\//:}
+        actor=$GITHUB_ACTOR
+        curl https://api.day.app/rwVK7e3nsZtopouwhRpVvM/$actor%20star%20了你的仓库/$repo

+ 21 - 0
d2-admin/.gitignore

@@ -0,0 +1,21 @@
+.DS_Store
+node_modules
+/dist
+
+# local env files
+.env.local
+.env.*.local
+
+# Log files
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?

+ 5 - 0
d2-admin/.postcssrc.js

@@ -0,0 +1,5 @@
+module.exports = {
+  plugins: {
+    autoprefixer: {}
+  }
+}

+ 21 - 0
d2-admin/LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018 李杨
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 24 - 0
d2-admin/README.md

@@ -0,0 +1,24 @@
+[D2Admin](https://github.com/d2-projects/d2-admin) is a fully open source and free enterprise back-end product front-end integration solution, using the latest front-end technology stack, javascript files loading of local first screen less than 60kb, has prepared most of the project preparations, and with a lot of sample code to help the management system agile development.
+
+[中文](https://github.com/d2-projects/d2-admin-start-kit/blob/master/README.zh.md) | **English**
+
+## Preview
+
+![Deploy preview](https://github.com/d2-projects/d2-admin-start-kit/workflows/Deploy%20preview/badge.svg)
+[![Netlify Status](https://api.netlify.com/api/v1/badges/08ff8c93-f0a8-497a-a081-440b31fb3aa4/deploy-status)](https://app.netlify.com/sites/d2-admin-start-kit/deploys)
+
+The following access addresses are built and deployed by the latest master branch code at the same time. The access effect is completely consistent. Please select the appropriate access link according to your own network situation.
+
+| server | link | server |
+| --- | --- | --- |
+| d2.pub | [d2.pub/d2-admin-start-kit/preview](https://d2.pub/d2-admin-start-kit/preview) | China server |
+| cdn.d2.pub | [cdn.d2.pub/d2-admin-start-kit/preview](https://cdn.d2.pub/d2-admin-start-kit/preview) | qiniu CDN |
+| github | [d2-projects.github.io/d2-admin-start-kit](https://d2-projects.github.io/d2-admin-start-kit) | GitHub pages |
+| netlify | [d2-admin-start-kit.netlify.com](https://d2-admin-start-kit.netlify.com) | Netlify CDN |
+
+## Other synchronous repositories
+
+| type | link |
+| --- | --- |
+| gitee | [https://gitee.com/d2-projects/d2-admin](https://gitee.com/d2-projects/d2-admin) |
+| coding | [https://d2-projects.coding.net/p/d2-projects/d/d2-admin/git](https://d2-projects.coding.net/p/d2-projects/d/d2-admin/git) |

+ 26 - 0
d2-admin/README.zh.md

@@ -0,0 +1,26 @@
+[D2Admin](https://github.com/d2-projects/d2-admin) 是一个完全 **开源免费** 的企业中后台产品前端集成方案,使用最新的前端技术栈,小于 60kb 的本地首屏 js 加载,已经做好大部分项目前期准备工作,并且带有大量示例代码,助力管理系统敏捷开发。
+
+**中文** | [English](https://github.com/d2-projects/d2-admin-start-kit)
+
+## 预览
+
+![Deploy preview](https://github.com/d2-projects/d2-admin-start-kit/workflows/Deploy%20preview/badge.svg)
+[![Netlify Status](https://api.netlify.com/api/v1/badges/08ff8c93-f0a8-497a-a081-440b31fb3aa4/deploy-status)](https://app.netlify.com/sites/d2-admin-start-kit/deploys)
+
+下列访问地址均由最新的 master 分支代码同时构建部署,访问效果完全一致,请根据自身网络情况选择合适的访问链接。
+
+| 位置 | 链接 | 部署位置 |
+| --- | --- | --- |
+| d2.pub | [preview](https://d2.pub/d2-admin-start-kit/preview) | 中国服务器 |
+| cdn.d2.pub | [preview](https://cdn.d2.pub/d2-admin-start-kit/preview) | 七牛云 CDN |
+| github | [preview](https://d2-projects.github.io/d2-admin-start-kit) | GitHub pages |
+| netlify | [preview](https://d2-admin-start-kit.netlify.com) | Netlify CDN |
+
+## 其它同步仓库
+
+| 位置 | 链接 |
+| --- | --- |
+| 码云 | [https://gitee.com/d2-projects/d2-admin-start-kit](https://gitee.com/d2-projects/d2-admin-start-kit) |
+| coding | [https://d2-projects.coding.net/p/d2-projects/d/d2-admin-start-kit/git](https://d2-projects.coding.net/p/d2-projects/d/d2-admin-start-kit/git) |
+
+> 如果您在 github 仓库下载很慢,可以尝试使用我们的码云仓库克隆代码

+ 7 - 0
d2-admin/babel.config.js

@@ -0,0 +1,7 @@
+module.exports = {
+  presets: [
+    '@vue/cli-plugin-babel/preset'
+  ],
+  // 允许两种编码引入方式共存,也就是 common 规范与 es6 规范的共存处理
+  sourceType: 'unambiguous'
+}

+ 165 - 0
d2-admin/d2-admin.babel

@@ -0,0 +1,165 @@
+<babeledit_project version="1.2">
+    <!--
+
+    BabelEdit project file
+    https://www.codeandweb.com/babeledit
+
+    This file contains meta data for all translations, but not the translation texts itself.
+    They are stored in framework-specific message files (.json / .vue / .yaml / .properties)
+
+    -->
+    <preset_collections/>
+    <framework>vue-json</framework>
+    <filename>d2-admin.babel</filename>
+    <source_root_dir></source_root_dir>
+    <folder_node>
+        <name></name>
+        <children>
+            <concept_node>
+                <name>_element</name>
+                <definition_loaded>false</definition_loaded>
+                <description></description>
+                <comment></comment>
+                <default_text></default_text>
+                <translations>
+                    <translation>
+                        <language>en-US</language>
+                        <approved>false</approved>
+                    </translation>
+                    <translation>
+                        <language>ja-JP</language>
+                        <approved>false</approved>
+                    </translation>
+                    <translation>
+                        <language>zh-CHS</language>
+                        <approved>false</approved>
+                    </translation>
+                    <translation>
+                        <language>zh-CHT</language>
+                        <approved>false</approved>
+                    </translation>
+                </translations>
+            </concept_node>
+            <concept_node>
+                <name>_name</name>
+                <definition_loaded>false</definition_loaded>
+                <description></description>
+                <comment></comment>
+                <default_text></default_text>
+                <translations>
+                    <translation>
+                        <language>en-US</language>
+                        <approved>false</approved>
+                    </translation>
+                    <translation>
+                        <language>ja-JP</language>
+                        <approved>false</approved>
+                    </translation>
+                    <translation>
+                        <language>zh-CHS</language>
+                        <approved>false</approved>
+                    </translation>
+                    <translation>
+                        <language>zh-CHT</language>
+                        <approved>false</approved>
+                    </translation>
+                </translations>
+            </concept_node>
+            <folder_node>
+                <name>page</name>
+                <children>
+                    <folder_node>
+                        <name>demo</name>
+                        <children>
+                            <folder_node>
+                                <name>playground</name>
+                                <children>
+                                    <folder_node>
+                                        <name>locales</name>
+                                        <children>
+                                            <concept_node>
+                                                <name>text</name>
+                                                <definition_loaded>false</definition_loaded>
+                                                <description></description>
+                                                <comment></comment>
+                                                <default_text></default_text>
+                                                <translations>
+                                                    <translation>
+                                                        <language>en-US</language>
+                                                        <approved>false</approved>
+                                                    </translation>
+                                                    <translation>
+                                                        <language>ja-JP</language>
+                                                        <approved>false</approved>
+                                                    </translation>
+                                                    <translation>
+                                                        <language>zh-CHS</language>
+                                                        <approved>false</approved>
+                                                    </translation>
+                                                    <translation>
+                                                        <language>zh-CHT</language>
+                                                        <approved>false</approved>
+                                                    </translation>
+                                                </translations>
+                                            </concept_node>
+                                        </children>
+                                    </folder_node>
+                                </children>
+                            </folder_node>
+                        </children>
+                    </folder_node>
+                </children>
+            </folder_node>
+        </children>
+    </folder_node>
+    <isTemplateProject>false</isTemplateProject>
+    <languages>
+        <language>
+            <code>en-US</code>
+            <source_id></source_id>
+            <source_file>src/locales/en.json</source_file>
+        </language>
+        <language>
+            <code>ja-JP</code>
+            <source_id></source_id>
+            <source_file>src/locales/ja.json</source_file>
+        </language>
+        <language>
+            <code>zh-CHS</code>
+            <source_id></source_id>
+            <source_file>src/locales/zh-chs.json</source_file>
+        </language>
+        <language>
+            <code>zh-CHT</code>
+            <source_id></source_id>
+            <source_file>src/locales/zh-cht.json</source_file>
+        </language>
+    </languages>
+    <translation_files>
+        <translation_file>
+            <file>src/locales/en.json</file>
+        </translation_file>
+        <translation_file>
+            <file>src/locales/ja.json</file>
+        </translation_file>
+        <translation_file>
+            <file>src/locales/zh-chs.json</file>
+        </translation_file>
+        <translation_file>
+            <file>src/locales/zh-cht.json</file>
+        </translation_file>
+    </translation_files>
+    <editor_configuration>
+        <save_empty_translations>true</save_empty_translations>
+        <copy_templates>
+            <copy_template>$t('%1')</copy_template>
+            <copy_template>{{ $t('%1') }}</copy_template>
+            <copy_template>this.$t('%1')</copy_template>
+        </copy_templates>
+    </editor_configuration>
+    <primary_language>zh-CHS</primary_language>
+    <configuration>
+        <indent>tab</indent>
+        <format>namespaced-json</format>
+    </configuration>
+</babeledit_project>

+ 22 - 0
d2-admin/dependencies-cdn.js

@@ -0,0 +1,22 @@
+module.exports = [
+  { name: 'vue', library: 'Vue', js: 'https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.min.js', css: '' },
+  { name: 'vue-i18n', library: 'VueI18n', js: 'https://cdn.jsdelivr.net/npm/vue-i18n@8.15.1/dist/vue-i18n.min.js', css: '' },
+  { name: 'vue-router', library: 'VueRouter', js: 'https://cdn.jsdelivr.net/npm/vue-router@3.1.3/dist/vue-router.min.js', css: '' },
+  { name: 'vuex', library: 'Vuex', js: 'https://cdn.jsdelivr.net/npm/vuex@3.1.2/dist/vuex.min.js', css: '' },
+  { name: 'axios', library: 'axios', js: 'https://cdn.jsdelivr.net/npm/axios@0.19.0/dist/axios.min.js', css: '' },
+  { name: 'better-scroll', library: 'BScroll', js: 'https://cdn.jsdelivr.net/npm/better-scroll@1.15.2/dist/bscroll.min.js', css: '' },
+  { name: 'axios-mock-adapter', library: 'AxiosMockAdapter', js: 'https://cdn.jsdelivr.net/npm/axios-mock-adapter@1.18.1/dist/axios-mock-adapter.min.js', css: '' },
+  { name: 'element-ui', library: 'ELEMENT', js: 'https://cdn.jsdelivr.net/npm/element-ui@2.13.1/lib/index.js', css: 'https://cdn.jsdelivr.net/npm/element-ui@2.13.0/lib/theme-chalk/index.css' },
+  { name: 'lodash', library: '_', js: 'https://cdn.jsdelivr.net/npm/lodash@4.17.15/lodash.min.js', css: '' },
+  { name: 'ua-parser-js', library: 'UAParser', js: 'https://cdn.jsdelivr.net/npm/ua-parser-js@0.7.20/dist/ua-parser.min.js', css: '' },
+  { name: 'js-cookie', library: 'Cookies', js: 'https://cdn.jsdelivr.net/npm/js-cookie@2.2.1/src/js.cookie.min.js', css: '' },
+  { name: 'nprogress', library: 'NProgress', js: 'https://cdn.jsdelivr.net/npm/nprogress@0.2.0/nprogress.min.js', css: 'https://cdn.jsdelivr.net/npm/nprogress@0.2.0/nprogress.css' },
+  { name: 'dayjs', library: 'dayjs', js: 'https://cdn.jsdelivr.net/npm/dayjs@1.8.17/dayjs.min.js', css: '' },
+  { name: 'fuse.js', library: 'Fuse', js: 'https://cdn.jsdelivr.net/npm/fuse.js@5.2.3/dist/fuse.min.js', css: '' },
+  { name: 'hotkeys-js', library: 'hotkeys', js: 'https://cdn.jsdelivr.net/npm/hotkeys-js@3.7.3/dist/hotkeys.min.js', css: '' },
+  { name: 'qs', library: 'Qs', js: 'https://cdn.jsdelivr.net/npm/qs@6.9.1/dist/qs.js', css: '' },
+  { name: 'lowdb', library: 'low', js: 'https://cdn.jsdelivr.net/npm/lowdb@1.0.0/dist/low.min.js', css: '' },
+  { name: 'lowdb/adapters/LocalStorage', library: 'LocalStorage', js: 'https://cdn.jsdelivr.net/npm/lowdb@1.0.0/dist/LocalStorage.min.js', css: '' },
+  { name: 'screenfull', library: 'screenfull', js: 'https://cdn.jsdelivr.net/npm/screenfull@5.0.2/dist/screenfull.min.js', css: '' },
+  { name: 'sortablejs', library: 'Sortable', js: 'https://cdn.jsdelivr.net/npm/sortablejs@1.10.1/Sortable.min.js', css: '' }
+]

+ 3 - 0
d2-admin/jest.config.js

@@ -0,0 +1,3 @@
+module.exports = {
+  preset: '@vue/cli-plugin-unit-jest'
+}

+ 11 - 0
d2-admin/jsconfig.json

@@ -0,0 +1,11 @@
+{
+  "compilerOptions": {
+    "target": "es2017",
+    "allowSyntheticDefaultImports": false,
+    "baseUrl": "./",
+    "paths": {
+      "@/*": ["src/*"]
+    }
+  },
+  "exclude": ["node_modules", "dist"]
+}

File diff suppressed because it is too large
+ 15939 - 0
d2-admin/package-lock.json


+ 78 - 0
d2-admin/package.json

@@ -0,0 +1,78 @@
+{
+  "name": "d2-admin",
+  "version": "1.20.1",
+  "scripts": {
+    "serve": "vue-cli-service serve --open",
+    "start": "npm run serve",
+    "dev": "npm run serve",
+    "build": "vue-cli-service build",
+    "build:preview": "NODE_OPTIONS=--max_old_space_size=4096 vue-cli-service build --mode preview",
+    "lint": "vue-cli-service lint --fix",
+    "test:unit": "vue-cli-service test:unit"
+  },
+  "dependencies": {
+    "await-to-js": "^3.0.0",
+    "axios": "^0.19.2",
+    "axios-mock-adapter": "^1.18.1",
+    "better-scroll": "^1.15.2",
+    "core-js": "^3.4.3",
+    "dayjs": "^1.8.17",
+    "element-ui": "^2.13.1",
+    "faker": "^4.1.0",
+    "flex.css": "^1.1.7",
+    "fuse.js": "^5.2.3",
+    "hotkeys-js": "^3.7.3",
+    "js-cookie": "^2.2.1",
+    "js-md5": "^0.7.3",
+    "lodash": "^4.17.19",
+    "lowdb": "^1.0.0",
+    "nprogress": "^0.2.0",
+    "screenfull": "^5.0.2",
+    "sortablejs": "^1.10.1",
+    "ua-parser-js": "^0.7.20",
+    "vue": "^2.6.11",
+    "vue-axios": "^3.2.4",
+    "vue-i18n": "^8.15.1",
+    "vue-layer": "^1.2.5",
+    "vue-router": "^3.1.3",
+    "vuex": "^3.1.2"
+  },
+  "devDependencies": {
+    "@d2-projects/vue-filename-injector": "^1.1.0",
+    "@kazupon/vue-i18n-loader": "^0.5.0",
+    "@vue/cli-plugin-babel": "^4.1.0",
+    "@vue/cli-plugin-eslint": "^4.1.0",
+    "@vue/cli-plugin-router": "^4.1.0",
+    "@vue/cli-plugin-unit-jest": "^4.1.0",
+    "@vue/cli-plugin-vuex": "^4.1.0",
+    "@vue/cli-service": "^4.1.0",
+    "@vue/eslint-config-standard": "^5.1.2",
+    "@vue/test-utils": "^1.0.2",
+    "babel-eslint": "^10.0.3",
+    "compression-webpack-plugin": "^3.0.1",
+    "cz-conventional-changelog": "^3.2.0",
+    "eslint": "^6.8.0",
+    "eslint-plugin-import": "^2.20.2",
+    "eslint-plugin-node": "^11.1.0",
+    "eslint-plugin-promise": "^4.2.1",
+    "eslint-plugin-standard": "^4.0.1",
+    "eslint-plugin-vue": "^6.2.2",
+    "sass": "^1.23.7",
+    "sass-loader": "^8.0.0",
+    "svg-sprite-loader": "^4.1.6",
+    "text-loader": "^0.0.1",
+    "vue-cli-plugin-i18n": "^1.0.1",
+    "vue-template-compiler": "^2.6.10",
+    "webpack-bundle-analyzer": "^3.6.0",
+    "webpack-theme-color-replacer": "^1.3.3"
+  },
+  "config": {
+    "commitizen": {
+      "path": "./node_modules/cz-conventional-changelog"
+    }
+  },
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/d2-projects/d2-admin.git"
+  }
+}

BIN
d2-admin/public/icon.ico


BIN
d2-admin/public/image/baidu-pan-logo.png


+ 6 - 0
d2-admin/public/image/loading/loading-spin.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32" height="32" fill="white">
+  <path opacity=".25" d="M16 0 A16 16 0 0 0 16 32 A16 16 0 0 0 16 0 M16 4 A12 12 0 0 1 16 28 A12 12 0 0 1 16 4"/>
+  <path d="M16 0 A16 16 0 0 1 32 16 L28 16 A12 12 0 0 0 16 4z">
+    <animateTransform attributeName="transform" type="rotate" from="0 16 16" to="360 16 16" dur="0.8s" repeatCount="indefinite" />
+  </path>
+</svg>

BIN
d2-admin/public/image/theme/chester/logo/all.png


BIN
d2-admin/public/image/theme/chester/logo/icon-only.png


BIN
d2-admin/public/image/theme/chester/preview@2x.png


BIN
d2-admin/public/image/theme/d2/logo/all.png


BIN
d2-admin/public/image/theme/d2/logo/icon-only.png


BIN
d2-admin/public/image/theme/d2/preview@2x.png


BIN
d2-admin/public/image/theme/element/logo/all.png


BIN
d2-admin/public/image/theme/element/logo/icon-only.png


BIN
d2-admin/public/image/theme/element/preview@2x.png


BIN
d2-admin/public/image/theme/line/bg.jpg


BIN
d2-admin/public/image/theme/line/logo/all.png


BIN
d2-admin/public/image/theme/line/logo/icon-only.png


BIN
d2-admin/public/image/theme/line/preview@2x.png


BIN
d2-admin/public/image/theme/star/bg.jpg


BIN
d2-admin/public/image/theme/star/logo/all.png


BIN
d2-admin/public/image/theme/star/logo/icon-only.png


BIN
d2-admin/public/image/theme/star/preview@2x.png


BIN
d2-admin/public/image/theme/tomorrow-night-blue/logo/all.png


BIN
d2-admin/public/image/theme/tomorrow-night-blue/logo/icon-only.png


BIN
d2-admin/public/image/theme/tomorrow-night-blue/preview@2x.png


BIN
d2-admin/public/image/theme/violet/logo/all.png


BIN
d2-admin/public/image/theme/violet/logo/icon-only.png


BIN
d2-admin/public/image/theme/violet/preview@2x.png


+ 60 - 0
d2-admin/public/index.html

@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<html>
+  <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 %>icon.ico">
+    <!-- 使用 CDN 加速的 CSS 文件,配置在 vue.config.js 下 -->
+    <% for (var i in htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.css) { %>
+    <link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="preload" as="style">
+    <link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="stylesheet">
+    <% } %>
+    <!-- 使用 CDN 加速的 JS 文件,配置在 vue.config.js 下 -->
+    <% for (var i in htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.js) { %>
+    <link href="<%= htmlWebpackPlugin.options.cdn.js[i] %>" rel="preload" as="script">
+    <% } %>
+    <title><%= VUE_APP_TITLE %></title>
+    <style>
+      html, body, #app { height: 100%; margin: 0px; padding: 0px; width: 100%; }
+      .d2-home { background-color: #303133; height: 100%; display: flex; flex-direction: column; }
+      .d2-home__main { user-select: none; width: 100%; flex-grow: 1; display: flex; justify-content: center; align-items: center; flex-direction: column; }
+      .d2-home__footer { width: 100%; flex-grow: 0; text-align: center; padding: 1em 0; }
+      .d2-home__footer > a { font-size: 12px; color: #ABABAB; text-decoration: none; }
+      .d2-home__loading { height: 32px; width: 32px; margin-bottom: 20px; }
+    </style>
+    <script>
+      var _hmt = _hmt || [];
+      var hmid = "bc38887aa5588add05a38704342ad7e8";
+      (function() { var hm = document.createElement("script"); hm.src = "https://hm.baidu.com/hm.js?" + hmid; var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(hm, s);})();
+    </script>
+  </head>
+  <body>
+    <noscript>
+      <strong>
+        Sorry, D2Admin will not work properly without JavaScript support. Enable JavaScript for browsers and continue.
+      </strong>
+    </noscript>
+    <div id="app">
+      <div class="d2-home">
+        <div class="d2-home__main">
+          <img
+            class="d2-home__loading"
+            src="./image/loading/loading-spin.svg"
+            alt="loading">
+        </div>
+        <div class="d2-home__footer">
+          <a
+            href="https://github.com/d2-projects/d2-admin"
+            target="_blank">
+            https://github.com/d2-projects/d2-admin
+          </a>
+        </div>
+      </div>
+    </div>
+    <!-- 使用 CDN 加速的 JS 文件,配置在 vue.config.js 下 -->
+    <% for (var i in htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.js) { %>
+    <script src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script>
+    <% } %>
+  </body>
+</html>

+ 28 - 0
d2-admin/src/App.vue

@@ -0,0 +1,28 @@
+<template>
+  <div id="app">
+    <router-view/>
+  </div>
+</template>
+
+<script>
+import util from '@/libs/util'
+export default {
+  name: 'app',
+  watch: {
+    '$i18n.locale': 'i18nHandle'
+  },
+  created () {
+    this.i18nHandle(this.$i18n.locale)
+  },
+  methods: {
+    i18nHandle (val, oldVal) {
+      util.cookies.set('lang', val)
+      document.querySelector('html').setAttribute('lang', val)
+    }
+  }
+}
+</script>
+
+<style lang="scss">
+@import '~@/assets/style/public-class.scss';
+</style>

+ 17 - 0
d2-admin/src/api/index.js

@@ -0,0 +1,17 @@
+import { assign, map } from 'lodash'
+import faker from 'faker/locale/zh_CN'
+import { service, request, serviceForMock, requestForMock, mock } from './service'
+import * as tools from './tools'
+
+const files = require.context('./modules', true, /\.api\.js$/)
+const generators = files.keys().map(key => files(key).default)
+
+export default assign({}, ...map(generators, generator => generator({
+  service,
+  request,
+  serviceForMock,
+  requestForMock,
+  mock,
+  faker,
+  tools
+})))

+ 31 - 0
d2-admin/src/api/modules/sys.user.api.js

@@ -0,0 +1,31 @@
+import { find, assign } from 'lodash'
+
+const users = [
+  { username: 'admin', password: 'admin', uuid: 'admin-uuid', name: 'Admin' },
+  { username: 'editor', password: 'editor', uuid: 'editor-uuid', name: 'Editor' },
+  { username: 'user1', password: 'user1', uuid: 'user1-uuid', name: 'User1' }
+]
+
+export default ({ service, request, serviceForMock, requestForMock, mock, faker, tools }) => ({
+  /**
+   * @description 登录
+   * @param {Object} data 登录携带的信息
+   */
+  SYS_USER_LOGIN (data = {}) {
+    // 模拟数据
+    mock
+      .onAny('/login')
+      .reply(config => {
+        const user = find(users, tools.parse(config.data))
+        return user
+          ? tools.responseSuccess(assign({}, user, { token: faker.random.uuid() }))
+          : tools.responseError({}, '账号或密码不正确')
+      })
+    // 接口请求
+    return requestForMock({
+      url: '/login',
+      method: 'post',
+      data
+    })
+  }
+})

+ 102 - 0
d2-admin/src/api/service.js

@@ -0,0 +1,102 @@
+import axios from 'axios'
+import Adapter from 'axios-mock-adapter'
+import { get } from 'lodash'
+import util from '@/libs/util'
+import { errorLog, errorCreate } from './tools'
+
+/**
+ * @description 创建请求实例
+ */
+function createService () {
+  // 创建一个 axios 实例
+  const service = axios.create()
+  // 请求拦截
+  service.interceptors.request.use(
+    config => config,
+    error => {
+      // 发送失败
+      console.log(error)
+      return Promise.reject(error)
+    }
+  )
+  // 响应拦截
+  service.interceptors.response.use(
+    response => {
+      // dataAxios 是 axios 返回数据中的 data
+      const dataAxios = response.data
+      // 这个状态码是和后端约定的
+      const { code } = dataAxios
+      // 根据 code 进行判断
+      if (code === undefined) {
+        // 如果没有 code 代表这不是项目后端开发的接口 比如可能是 D2Admin 请求最新版本
+        return dataAxios
+      } else {
+        // 有 code 代表这是一个后端接口 可以进行进一步的判断
+        switch (code) {
+          case 0:
+            // [ 示例 ] code === 0 代表没有错误
+            return dataAxios.data
+          case 'xxx':
+            // [ 示例 ] 其它和后台约定的 code
+            errorCreate(`[ code: xxx ] ${dataAxios.msg}: ${response.config.url}`)
+            break
+          default:
+            // 不是正确的 code
+            errorCreate(`${dataAxios.msg}: ${response.config.url}`)
+            break
+        }
+      }
+    },
+    error => {
+      const status = get(error, 'response.status')
+      switch (status) {
+        case 400: error.message = '请求错误'; break
+        case 401: error.message = '未授权,请登录'; break
+        case 403: error.message = '拒绝访问'; break
+        case 404: error.message = `请求地址出错: ${error.response.config.url}`; break
+        case 408: error.message = '请求超时'; break
+        case 500: error.message = '服务器内部错误'; break
+        case 501: error.message = '服务未实现'; break
+        case 502: error.message = '网关错误'; break
+        case 503: error.message = '服务不可用'; break
+        case 504: error.message = '网关超时'; break
+        case 505: error.message = 'HTTP版本不受支持'; break
+        default: break
+      }
+      errorLog(error)
+      return Promise.reject(error)
+    }
+  )
+  return service
+}
+
+/**
+ * @description 创建请求方法
+ * @param {Object} service axios 实例
+ */
+function createRequestFunction (service) {
+  return function (config) {
+    const token = util.cookies.get('token')
+    const configDefault = {
+      headers: {
+        Authorization: token,
+        'Content-Type': get(config, 'headers.Content-Type', 'application/json')
+      },
+      timeout: 5000,
+      baseURL: process.env.VUE_APP_API,
+      data: {}
+    }
+    return service(Object.assign(configDefault, config))
+  }
+}
+
+// 用于真实网络请求的实例和请求方法
+export const service = createService()
+export const request = createRequestFunction(service)
+
+// 用于模拟网络请求的实例和请求方法
+export const serviceForMock = createService()
+export const requestForMock = createRequestFunction(serviceForMock)
+
+// 网络请求数据模拟工具
+export const mock = new Adapter(serviceForMock)

+ 86 - 0
d2-admin/src/api/tools.js

@@ -0,0 +1,86 @@
+import { Message } from 'element-ui'
+import store from '@/store'
+import util from '@/libs/util'
+
+/**
+ * @description 安全地解析 json 字符串
+ * @param {String} jsonString 需要解析的 json 字符串
+ * @param {String} defaultValue 默认值
+ */
+export function parse (jsonString = '{}', defaultValue = {}) {
+  let result = defaultValue
+  try {
+    result = JSON.parse(jsonString)
+  } catch (error) {
+    console.log(error)
+  }
+  return result
+}
+
+/**
+ * @description 接口请求返回
+ * @param {Any} data 返回值
+ * @param {String} msg 状态信息
+ * @param {Number} code 状态码
+ */
+export function response (data = {}, msg = '', code = 0) {
+  return [
+    200,
+    { code, msg, data }
+  ]
+}
+
+/**
+ * @description 接口请求返回 正确返回
+ * @param {Any} data 返回值
+ * @param {String} msg 状态信息
+ */
+export function responseSuccess (data = {}, msg = '成功') {
+  return response(data, msg)
+}
+
+/**
+ * @description 接口请求返回 错误返回
+ * @param {Any} data 返回值
+ * @param {String} msg 状态信息
+ * @param {Number} code 状态码
+ */
+export function responseError (data = {}, msg = '请求失败', code = 500) {
+  return response(data, msg, code)
+}
+
+/**
+ * @description 记录和显示错误
+ * @param {Error} error 错误对象
+ */
+export function errorLog (error) {
+  // 添加到日志
+  store.dispatch('d2admin/log/push', {
+    message: '数据请求异常',
+    type: 'danger',
+    meta: {
+      error
+    }
+  })
+  // 打印到控制台
+  if (process.env.NODE_ENV === 'development') {
+    util.log.danger('>>>>>> Error >>>>>>')
+    console.log(error)
+  }
+  // 显示提示
+  Message({
+    message: error.message,
+    type: 'error',
+    duration: 5 * 1000
+  })
+}
+
+/**
+ * @description 创建一个错误
+ * @param {String} msg 错误信息
+ */
+export function errorCreate (msg) {
+  const error = new Error(msg)
+  errorLog(error)
+  throw error
+}

+ 27 - 0
d2-admin/src/assets/style/animate/vue-transition.scss

@@ -0,0 +1,27 @@
+// 过渡动画 横向渐变
+.fade-transverse-leave-active,
+.fade-transverse-enter-active {
+  transition: all .5s;
+}
+.fade-transverse-enter {
+  opacity: 0;
+  transform: translateX(-30px);
+}
+.fade-transverse-leave-to {
+  opacity: 0;
+  transform: translateX(30px);
+}
+
+// 过渡动画 缩放渐变
+.fade-scale-leave-active,
+.fade-scale-enter-active {
+  transition: all .3s;
+}
+.fade-scale-enter {
+  opacity: 0;
+  transform: scale(1.2);
+}
+.fade-scale-leave-to {
+  opacity: 0;
+  transform: scale(0.8);
+}

+ 12 - 0
d2-admin/src/assets/style/fixed/base.scss

@@ -0,0 +1,12 @@
+// 优化显示
+html, body {
+  margin: 0px;
+  height: 100%;
+  font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial, sans-serif;
+  #app {
+    @extend %full;
+    a {
+      text-decoration: none;
+    }
+  }
+}

+ 31 - 0
d2-admin/src/assets/style/fixed/element.scss

@@ -0,0 +1,31 @@
+// element 样式补丁
+.el-card {
+  &.is-always-shadow {
+    box-shadow: 0 0 8px 0 rgba(232,237,250,.6), 0 2px 4px 0 rgba(232,237,250,.5);
+  }
+  &.is-hover-shadow {
+    &:hover {
+      box-shadow: 0 0 8px 0 rgba(232,237,250,.6), 0 2px 4px 0 rgba(232,237,250,.5);
+    }
+  }
+}
+
+.el-menu--horizontal {
+  border-bottom: none !important;
+}
+
+.el-tabs__item:focus.is-active.is-focus:not(:active) {
+  box-shadow: none !important;
+}
+
+// 修复IE宽度不能撑满
+.el-table__body,
+.el-table__header {
+  width: 100% !important;
+}
+
+// Chrome下表格头部错位修复
+.el-table th.gutter,
+.el-table colgroup.gutter {
+  display: table-cell !important;
+}

+ 9 - 0
d2-admin/src/assets/style/fixed/markdown.scss

@@ -0,0 +1,9 @@
+// markdown 样式补丁
+.markdown-body {
+  ul {
+    list-style: disc;
+  }
+  h1, h2 {
+    border-bottom: none;
+  }
+}

+ 8 - 0
d2-admin/src/assets/style/fixed/n-progress.scss

@@ -0,0 +1,8 @@
+#nprogress {
+  .bar {
+    background: $color-primary !important;
+  }
+  .peg {
+    box-shadow: 0 0 10px $color-primary, 0 0 5px $color-primary !important;
+  }
+}

+ 5 - 0
d2-admin/src/assets/style/fixed/tree-view.scss

@@ -0,0 +1,5 @@
+.tree-view-wrapper.tree-view-small {
+  .tree-view-item {
+    font-size: 10px;
+  }
+}

+ 9 - 0
d2-admin/src/assets/style/fixed/vue-grid-layout.scss

@@ -0,0 +1,9 @@
+// vue-splitpane 样式补丁
+.vue-grid-item {
+  &.vue-grid-placeholder {
+    border: 1px solid $color-border-1;
+    background-color: rgba(#FFF, .3);
+    opacity: 1;
+    border-radius: 4px;
+  }
+}

+ 5 - 0
d2-admin/src/assets/style/fixed/vue-splitpane.scss

@@ -0,0 +1,5 @@
+// vue-splitpane 样式补丁
+.splitter-pane-resizer {
+  background-color: $color-border-1 !important;
+  opacity: 1 !important;
+}

+ 67 - 0
d2-admin/src/assets/style/public-class.scss

@@ -0,0 +1,67 @@
+@import 'public';
+
+// 补丁 base
+@import '~@/assets/style/fixed/base.scss';
+// 补丁 element
+@import '~@/assets/style/fixed/element.scss';
+// 补丁 markdown
+@import '~@/assets/style/fixed/markdown.scss';
+// 补丁 n-progress
+@import '~@/assets/style/fixed/n-progress.scss';
+// 补丁 vue-splitpane
+@import '~@/assets/style/fixed/vue-splitpane.scss';
+// 补丁 vue-grid-layout
+@import '~@/assets/style/fixed/vue-grid-layout.scss';
+// 补丁 tree-view
+@import '~@/assets/style/fixed/tree-view.scss';
+
+// 动画
+@import '~@/assets/style/animate/vue-transition.scss';
+
+// 在这里写公用的class
+// 注意 这个文件里只写class
+// mixin等内容请在 public.scss 里书写
+
+// 文字相关
+.#{$prefix}-text-center {
+  text-align: center;
+}
+
+// 浮动相关
+.#{$prefix}-fl {
+  float: left;
+}
+.#{$prefix}-fr {
+  float: right;
+}
+
+// 边距相关
+$sizes: (0, 5, 10, 15, 20);
+
+@for $index from 1 to 6 {
+  .#{$prefix}-m-#{nth($sizes, $index)} { margin: #{nth($sizes, $index)}px !important; }
+  .#{$prefix}-mt-#{nth($sizes, $index)} { margin-top: #{nth($sizes, $index)}px !important; }
+  .#{$prefix}-mr-#{nth($sizes, $index)} { margin-right: #{nth($sizes, $index)}px !important; }
+  .#{$prefix}-mb-#{nth($sizes, $index)} { margin-bottom: #{nth($sizes, $index)}px !important; }
+  .#{$prefix}-ml-#{nth($sizes, $index)} { margin-left: #{nth($sizes, $index)}px !important; }
+
+  .#{$prefix}-p-#{nth($sizes, $index)} { padding: #{nth($sizes, $index)}px !important; }
+  .#{$prefix}-pt-#{nth($sizes, $index)} { padding-top: #{nth($sizes, $index)}px !important; }
+  .#{$prefix}-pr-#{nth($sizes, $index)} { padding-right: #{nth($sizes, $index)}px !important; }
+  .#{$prefix}-pb-#{nth($sizes, $index)} { padding-bottom: #{nth($sizes, $index)}px !important; }
+  .#{$prefix}-pl-#{nth($sizes, $index)} { padding-left: #{nth($sizes, $index)}px !important; }
+}
+
+// 快速使用
+
+.#{$prefix}-m { margin: 20px !important; }
+.#{$prefix}-mt { margin-top: 20px !important; }
+.#{$prefix}-mr { margin-right: 20px !important; }
+.#{$prefix}-mb { margin-bottom: 20px !important; }
+.#{$prefix}-ml { margin-left: 20px !important; }
+
+.#{$prefix}-p { padding: 20px !important; }
+.#{$prefix}-pt { padding-top: 20px !important; }
+.#{$prefix}-pr { padding-right: 20px !important; }
+.#{$prefix}-pb { padding-bottom: 20px !important; }
+.#{$prefix}-pl { padding-left: 20px !important; }

+ 44 - 0
d2-admin/src/assets/style/public.scss

@@ -0,0 +1,44 @@
+@import '~@/assets/style/unit/color.scss';
+
+// 工具类名统一前缀
+$prefix: d2;
+
+// 禁止用户选中 鼠标变为手形
+%unable-select {
+  user-select: none;
+  cursor: pointer;
+}
+
+// 填满父元素
+// 组要父元素 position: relative | absolute;
+%full {
+  position: absolute;
+  top: 0px;
+  right: 0px;
+  bottom: 0px;
+  left: 0px;
+}
+
+// flex 垂直水平居中
+%flex-center-row {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  flex-direction: row;
+}
+%flex-center-col {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  flex-direction: column;
+}
+
+// 将元素模拟成卡片外观
+%card {
+  border: 1px solid #dddee1;
+  border-color: #e9eaec;
+  background: #fff;
+  border-radius: 4px;
+  font-size: 14px;
+  position: relative;
+}

+ 2 - 0
d2-admin/src/assets/style/theme/chester/index.scss

@@ -0,0 +1,2 @@
+@import './setting.scss';
+@import '../theme.scss';

+ 64 - 0
d2-admin/src/assets/style/theme/chester/setting.scss

@@ -0,0 +1,64 @@
+// 主题名称
+$theme-name: 'chester';
+// 主题背景颜色
+$theme-bg-color: #2C3643;
+// 主题背景图片遮罩
+$theme-bg-mask: rgba(#000, 0);
+
+// 消息提示
+$theme-message-info-background-color: #FFFFFF;
+$theme-message-info-text-color: #222A34;
+$theme-message-info-border-color: #222A34;
+
+// container组件
+$theme-container-background-color: rgba(#FFF, 1);
+$theme-container-header-footer-background-color: #FFF;
+$theme-container-border-inner: 1px solid #CFD7E5;
+$theme-container-border-outer: 1px solid #2A2D2E;
+
+$theme-multiple-page-control-color: #CCCCCC;
+$theme-multiple-page-control-color-active: #242D38;
+$theme-multiple-page-control-nav-prev-color: #CCCCCC;
+$theme-multiple-page-control-nav-next-color: #CCCCCC;
+$theme-multiple-page-control-border-color: #2A2D2E;
+$theme-multiple-page-control-border-color-active: #FFFFFF;
+$theme-multiple-page-control-background-color: #242D38;
+$theme-multiple-page-control-background-color-active: #FFFFFF;
+
+// 顶栏和侧边栏中展开的菜单 hover 状态下
+$theme-menu-item-color-hover: #CCCCCC;
+$theme-menu-item-background-color-hover: #2A2D2E;
+
+// 顶栏上的文字颜色
+$theme-header-item-color: #CCCCCC;
+$theme-header-item-background-color: transparent;
+// 顶栏上的项目在 hover 时
+$theme-header-item-color-hover: #CCCCCC;
+$theme-header-item-background-color-hover: #2A2D2E;
+// 顶栏上的项目在 focus 时
+$theme-header-item-color-focus: #CCCCCC;
+$theme-header-item-background-color-focus: #222A34;
+// 顶栏上的项目在 active 时
+$theme-header-item-color-active: #FFFFFF;
+$theme-header-item-background-color-active: #222A34;
+
+// 侧边栏上的文字颜色
+$theme-aside-item-color: #CCCCCC;
+$theme-aside-item-background-color: transparent;
+// 侧边栏上的项目在 hover 时
+$theme-aside-item-color-hover: #CCCCCC;
+$theme-aside-item-background-color-hover: #2A2D2E;
+// 侧边栏上的项目在 focus 时
+$theme-aside-item-color-focus: #CCCCCC;
+$theme-aside-item-background-color-focus: #222A34;
+// 侧边栏上的项目在 active 时
+$theme-aside-item-color-active: #FFFFFF;
+$theme-aside-item-background-color-active: #222A34;
+
+// 侧边栏菜单为空的时候显示的元素
+$theme-aside-menu-empty-icon-color: #CCCCCC;
+$theme-aside-menu-empty-text-color: #CCCCCC;
+$theme-aside-menu-empty-background-color: #242D38;
+$theme-aside-menu-empty-icon-color-hover: #FFFFFF;
+$theme-aside-menu-empty-text-color-hover: #FFFFFF;
+$theme-aside-menu-empty-background-color-hover: #242D38;

+ 2 - 0
d2-admin/src/assets/style/theme/d2/index.scss

@@ -0,0 +1,2 @@
+@import './setting.scss';
+@import '../theme.scss';

+ 64 - 0
d2-admin/src/assets/style/theme/d2/setting.scss

@@ -0,0 +1,64 @@
+// 主题名称
+$theme-name: 'd2';
+// 主题背景颜色
+$theme-bg-color: #ebf1f6;
+// 主题背景图片遮罩
+$theme-bg-mask: rgba(#000, 0);
+
+// 消息提示
+$theme-message-info-background-color: $color-bg;
+$theme-message-info-text-color: $color-text-normal;
+$theme-message-info-border-color: $color-border-1;
+
+// container组件
+$theme-container-background-color: rgba(#FFF, 1);
+$theme-container-header-footer-background-color: #FFF;
+$theme-container-border-inner: 1px solid #cfd7e5;
+$theme-container-border-outer: 1px solid #cfd7e5;
+
+$theme-multiple-page-control-color: $color-text-normal;
+$theme-multiple-page-control-color-active: #2f74ff;
+$theme-multiple-page-control-nav-prev-color: #cfd7e5;
+$theme-multiple-page-control-nav-next-color: #cfd7e5;
+$theme-multiple-page-control-border-color: #cfd7e5;
+$theme-multiple-page-control-border-color-active: #FFF;
+$theme-multiple-page-control-background-color: rgba(#000, .03);
+$theme-multiple-page-control-background-color-active: #FFF;
+
+// 顶栏和侧边栏中展开的菜单 hover 状态下
+$theme-menu-item-color-hover: #293849;
+$theme-menu-item-background-color-hover: #ecf5ff;
+
+// 顶栏上的文字颜色
+$theme-header-item-color: $color-text-normal;
+$theme-header-item-background-color: transparent;
+// 顶栏上的项目在 hover 时
+$theme-header-item-color-hover: #2f74ff;
+$theme-header-item-background-color-hover: rgba(#FFF, .5);
+// 顶栏上的项目在 focus 时
+$theme-header-item-color-focus: #2f74ff;
+$theme-header-item-background-color-focus: rgba(#FFF, .5);
+// 顶栏上的项目在 active 时
+$theme-header-item-color-active: #2f74ff;
+$theme-header-item-background-color-active: rgba(#FFF, .5);
+
+// 侧边栏上的文字颜色
+$theme-aside-item-color: $color-text-normal;
+$theme-aside-item-background-color: transparent;
+// 侧边栏上的项目在 hover 时
+$theme-aside-item-color-hover: #2f74ff;
+$theme-aside-item-background-color-hover: rgba(#FFF, .5);
+// 侧边栏上的项目在 focus 时
+$theme-aside-item-color-focus: #2f74ff;
+$theme-aside-item-background-color-focus: rgba(#FFF, .5);
+// 侧边栏上的项目在 active 时
+$theme-aside-item-color-active: #2f74ff;
+$theme-aside-item-background-color-active: rgba(#FFF, .5);
+
+// 侧边栏菜单为空的时候显示的元素
+$theme-aside-menu-empty-icon-color: $color-text-normal;
+$theme-aside-menu-empty-text-color: $color-text-normal;
+$theme-aside-menu-empty-background-color: rgba(#000, .03);
+$theme-aside-menu-empty-icon-color-hover: $color-text-main;
+$theme-aside-menu-empty-text-color-hover: $color-text-main;
+$theme-aside-menu-empty-background-color-hover: rgba(#000, .05);

+ 2 - 0
d2-admin/src/assets/style/theme/element/index.scss

@@ -0,0 +1,2 @@
+@import './setting.scss';
+@import '../theme.scss';

+ 64 - 0
d2-admin/src/assets/style/theme/element/setting.scss

@@ -0,0 +1,64 @@
+// 主题名称
+$theme-name: 'element';
+// 主题背景颜色
+$theme-bg-color: #314255;
+// 主题背景图片遮罩
+$theme-bg-mask: rgba(#000, 0);
+
+// 消息提示
+$theme-message-info-background-color: #FFFFFF;
+$theme-message-info-text-color: #202D3D;
+$theme-message-info-border-color: #202D3D;
+
+// container组件
+$theme-container-background-color: rgba(#FFF, 1);
+$theme-container-header-footer-background-color: #FFF;
+$theme-container-border-inner: 1px solid #CFD7E5;
+$theme-container-border-outer: 1px solid #011527;
+
+$theme-multiple-page-control-color: #BFCBD9;
+$theme-multiple-page-control-color-active: #46A0FC;
+$theme-multiple-page-control-nav-prev-color: #BFCBD9;
+$theme-multiple-page-control-nav-next-color: #BFCBD9;
+$theme-multiple-page-control-border-color: #011527;
+$theme-multiple-page-control-border-color-active: #FFFFFF;
+$theme-multiple-page-control-background-color: #212D3D;
+$theme-multiple-page-control-background-color-active: #FFFFFF;
+
+// 顶栏和侧边栏中展开的菜单 hover 状态下
+$theme-menu-item-color-hover: #BFCBD9;
+$theme-menu-item-background-color-hover: #011527;
+
+// 顶栏上的文字颜色
+$theme-header-item-color: #BFCBD9;
+$theme-header-item-background-color: transparent;
+// 顶栏上的项目在 hover 时
+$theme-header-item-color-hover: #BFCBD9;
+$theme-header-item-background-color-hover: #011527;
+// 顶栏上的项目在 focus 时
+$theme-header-item-color-focus: #BFCBD9;
+$theme-header-item-background-color-focus: #202D3D;
+// 顶栏上的项目在 active 时
+$theme-header-item-color-active: #46A0FC;
+$theme-header-item-background-color-active: #202D3D;
+
+// 侧边栏上的文字颜色
+$theme-aside-item-color: #BFCBD9;
+$theme-aside-item-background-color: transparent;
+// 侧边栏上的项目在 hover 时
+$theme-aside-item-color-hover: #BFCBD9;
+$theme-aside-item-background-color-hover: #011527;
+// 侧边栏上的项目在 focus 时
+$theme-aside-item-color-focus: #BFCBD9;
+$theme-aside-item-background-color-focus: #202D3D;
+// 侧边栏上的项目在 active 时
+$theme-aside-item-color-active: #46A0FC;
+$theme-aside-item-background-color-active: #202D3D;
+
+// 侧边栏菜单为空的时候显示的元素
+$theme-aside-menu-empty-icon-color: #BFCBD9;
+$theme-aside-menu-empty-text-color: #BFCBD9;
+$theme-aside-menu-empty-background-color: #202D3D;
+$theme-aside-menu-empty-icon-color-hover: #46A0FC;
+$theme-aside-menu-empty-text-color-hover: #46A0FC;
+$theme-aside-menu-empty-background-color-hover: #202D3D;

+ 2 - 0
d2-admin/src/assets/style/theme/line/index.scss

@@ -0,0 +1,2 @@
+@import './setting.scss';
+@import '../theme.scss';

+ 64 - 0
d2-admin/src/assets/style/theme/line/setting.scss

@@ -0,0 +1,64 @@
+// 主题名称
+$theme-name: 'line';
+// 主题背景颜色
+$theme-bg-color: #f8f8f9;
+// 主题背景图片遮罩
+$theme-bg-mask: rgba(#000, 0);
+
+// 消息提示
+$theme-message-info-background-color: $color-bg;
+$theme-message-info-text-color: $color-text-normal;
+$theme-message-info-border-color: $color-border-1;
+
+// container组件
+$theme-container-background-color: rgba(#FFF, .8);
+$theme-container-header-footer-background-color: #FFF;
+$theme-container-border-inner: 1px solid $color-border-2;
+$theme-container-border-outer: 1px solid #cfd7e5;
+
+$theme-multiple-page-control-color: #FFF;
+$theme-multiple-page-control-color-active: $color-text-normal;
+$theme-multiple-page-control-nav-prev-color: #cfd7e5;
+$theme-multiple-page-control-nav-next-color: #cfd7e5;
+$theme-multiple-page-control-border-color: #cfd7e5;
+$theme-multiple-page-control-border-color-active: #FFF;
+$theme-multiple-page-control-background-color: #cfd7e5;
+$theme-multiple-page-control-background-color-active: #FFF;
+
+// 顶栏和侧边栏中展开的菜单 hover 状态下
+$theme-menu-item-color-hover: #293849;
+$theme-menu-item-background-color-hover: #EFEFEF;
+
+// 顶栏上的文字颜色
+$theme-header-item-color: $color-text-normal;
+$theme-header-item-background-color: transparent;
+// 顶栏上的项目在 hover 时
+$theme-header-item-color-hover: $color-text-main;
+$theme-header-item-background-color-hover: rgba(#000, .02);
+// 顶栏上的项目在 focus 时
+$theme-header-item-color-focus: $color-text-main;
+$theme-header-item-background-color-focus: rgba(#000, .02);
+// 顶栏上的项目在 active 时
+$theme-header-item-color-active: $color-text-main;
+$theme-header-item-background-color-active: rgba(#000, .03);
+
+// 侧边栏上的文字颜色
+$theme-aside-item-color: $color-text-normal;
+$theme-aside-item-background-color: transparent;
+// 侧边栏上的项目在 hover 时
+$theme-aside-item-color-hover: $color-text-main;
+$theme-aside-item-background-color-hover: rgba(#000, .02);
+// 侧边栏上的项目在 focus 时
+$theme-aside-item-color-focus: $color-text-main;
+$theme-aside-item-background-color-focus: rgba(#000, .02);
+// 侧边栏上的项目在 active 时
+$theme-aside-item-color-active: $color-text-main;
+$theme-aside-item-background-color-active: rgba(#000, .03);
+
+// 侧边栏菜单为空的时候显示的元素
+$theme-aside-menu-empty-icon-color: $color-text-normal;
+$theme-aside-menu-empty-text-color: $color-text-normal;
+$theme-aside-menu-empty-background-color: rgba(#000, .03);
+$theme-aside-menu-empty-icon-color-hover: $color-text-main;
+$theme-aside-menu-empty-text-color-hover: $color-text-main;
+$theme-aside-menu-empty-background-color-hover: rgba(#000, .05);

+ 9 - 0
d2-admin/src/assets/style/theme/register.scss

@@ -0,0 +1,9 @@
+@import '~@/assets/style/theme/theme-base.scss';
+
+@import '~@/assets/style/theme/d2/index.scss';
+@import '~@/assets/style/theme/chester/index.scss';
+@import '~@/assets/style/theme/element/index.scss';
+@import '~@/assets/style/theme/line/index.scss';
+@import '~@/assets/style/theme/star/index.scss';
+@import '~@/assets/style/theme/tomorrow-night-blue/index.scss';
+@import '~@/assets/style/theme/violet/index.scss';

+ 2 - 0
d2-admin/src/assets/style/theme/star/index.scss

@@ -0,0 +1,2 @@
+@import './setting.scss';
+@import '../theme.scss';

+ 64 - 0
d2-admin/src/assets/style/theme/star/setting.scss

@@ -0,0 +1,64 @@
+// 主题名称
+$theme-name: 'star';
+// 主题背景颜色
+$theme-bg-color: #EFF4F8;
+// 主题背景图片遮罩
+$theme-bg-mask: rgba(#000, .3);
+
+// 消息提示
+$theme-message-info-background-color: $color-bg;
+$theme-message-info-text-color: $color-text-normal;
+$theme-message-info-border-color: $color-border-1;
+
+// container组件
+$theme-container-background-color: rgba(#FFF, .9);
+$theme-container-header-footer-background-color: #FFF;
+$theme-container-border-inner: 1px solid $color-border-1;
+$theme-container-border-outer: 1px solid #114450;
+
+$theme-multiple-page-control-color: #FFF;
+$theme-multiple-page-control-color-active: $color-text-normal;
+$theme-multiple-page-control-nav-prev-color: #FFF;
+$theme-multiple-page-control-nav-next-color: #FFF;
+$theme-multiple-page-control-border-color: #114450;
+$theme-multiple-page-control-border-color-active: #FFF;
+$theme-multiple-page-control-background-color: rgba(#FFF, .5);
+$theme-multiple-page-control-background-color-active: #FFF;
+
+// 顶栏和侧边栏中展开的菜单 hover 状态下
+$theme-menu-item-color-hover: #293849;
+$theme-menu-item-background-color-hover: #ecf5ff;
+
+// 顶栏上的文字颜色
+$theme-header-item-color: #FFF;
+$theme-header-item-background-color: transparent;
+// 顶栏上的项目在 hover 时
+$theme-header-item-color-hover: #FFF;
+$theme-header-item-background-color-hover: rgba(#000, .2);
+// 顶栏上的项目在 focus 时
+$theme-header-item-color-focus: #FFF;
+$theme-header-item-background-color-focus: rgba(#000, .2);
+// 顶栏上的项目在 active 时
+$theme-header-item-color-active: #FFF;
+$theme-header-item-background-color-active: rgba(#000, .3);
+
+// 侧边栏上的文字颜色
+$theme-aside-item-color: #FFF;
+$theme-aside-item-background-color: transparent;
+// 侧边栏上的项目在 hover 时
+$theme-aside-item-color-hover: #FFF;
+$theme-aside-item-background-color-hover: rgba(#000, .2);
+// 侧边栏上的项目在 focus 时
+$theme-aside-item-color-focus: #FFF;
+$theme-aside-item-background-color-focus: rgba(#000, .2);
+// 侧边栏上的项目在 active 时
+$theme-aside-item-color-active: #FFF;
+$theme-aside-item-background-color-active: rgba(#000, .3);
+
+// 侧边栏菜单为空的时候显示的元素
+$theme-aside-menu-empty-icon-color: #FFF;
+$theme-aside-menu-empty-text-color: #FFF;
+$theme-aside-menu-empty-background-color: rgba(#FFF, .2);
+$theme-aside-menu-empty-icon-color-hover: #FFF;
+$theme-aside-menu-empty-text-color-hover: #FFF;
+$theme-aside-menu-empty-background-color-hover: rgba(#FFF, .3);

+ 454 - 0
d2-admin/src/assets/style/theme/theme-base.scss

@@ -0,0 +1,454 @@
+// 减小弹出菜单的项目高度
+.el-menu--popup {
+  .el-menu-item {
+    height: 36px;
+    line-height: 36px;
+  }
+  .el-submenu__title {
+    height: 36px;
+    line-height: 36px;
+  }
+}
+
+// 整体框架结构
+.d2-layout-header-aside-group {
+  height: 100%;
+  width: 100%;
+  min-width: 900px;
+  background-size: cover;
+  background-position: center;
+  overflow: hidden;
+  position: relative;
+  // 背景上面的半透明遮罩
+  .d2-layout-header-aside-mask {
+    @extend %full;
+  }
+  // 内容层
+  .d2-layout-header-aside-content {
+    @extend %full;
+    .d2-theme-header {
+      height: 60px;
+      .d2-theme-header-menu {
+        overflow: hidden;
+        &.is-scrollable {
+          position: relative;
+          padding: 0 20px;
+          .d2-theme-header-menu__prev, .d2-theme-header-menu__next {
+            display: -webkit-box;
+            display: -ms-flexbox;
+            display: flex;
+          }
+        }
+        .d2-theme-header-menu__content {
+          overflow: hidden;
+          .d2-theme-header-menu__scroll {
+            white-space: nowrap;
+            position: relative;
+            -webkit-transition: -webkit-transform .3s;
+            transition: -webkit-transform .3s;
+            transition: transform .3s;
+            transition: transform .3s, -webkit-transform .3s;
+            transition: transform .3s,-webkit-transform .3s;
+            float: left;
+          }
+        }
+        .d2-theme-header-menu__prev, .d2-theme-header-menu__next {
+          height: 60px;
+          position: absolute;
+          top: 0;
+          font-size: 20px;
+          cursor: pointer;
+          display: none;
+        }
+        .d2-theme-header-menu__prev {
+          left: 0;
+          border-top-left-radius: 2px;
+          border-bottom-left-radius: 2px;
+        }
+        .d2-theme-header-menu__next {
+          right: 0;
+          border-top-right-radius: 2px;
+          border-bottom-right-radius: 2px;
+        }
+      }
+    }
+    .d2-theme-container {
+      .d2-theme-container-aside {
+        position: relative;
+        .d2-layout-header-aside-menu-side {
+          @extend %full;
+          overflow: hidden;
+        }
+      }
+      .d2-theme-container-transition {
+        transition: width .3s;
+      }
+      .d2-theme-container-main {
+        padding: 0px;
+        position: relative;
+        overflow: hidden;
+        .d2-theme-container-main-layer {
+          position: absolute;
+          top: 0px;
+          bottom: 0px;
+          left: 0px;
+          right: 0px;
+        }
+        .d2-theme-container-main-body {
+          position: relative;
+        }
+      }
+    }
+  }
+}
+
+// 主题公用
+.d2-layout-header-aside-group {
+  &.grayMode {
+    -webkit-filter: grayscale(100%);
+    -moz-filter: grayscale(100%);
+    -ms-filter: grayscale(100%);
+    -o-filter: grayscale(100%);
+    filter: grayscale(100%);
+    filter: gray;
+  }
+  // 主体
+  .d2-layout-header-aside-content {
+    // [布局] 顶栏
+    .d2-theme-header {
+      // logo区域
+      .logo-group {
+        float: left;
+        text-align: center;
+        img {
+          height: 60px;
+        }
+      }
+      .logo-transition {
+        transition: width .3s;
+      }
+      // 折叠侧边栏切换按钮
+      .toggle-aside-btn {
+        float: left;
+        height: 60px;
+        width: 60px;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        @extend %unable-select;
+        i {
+          font-size: 20px;
+          margin-top: 4px;
+        }
+      }
+      // [菜单] 顶栏
+      .el-menu {
+        float: left;
+        border-bottom: none;
+        background-color: transparent;
+        %header-menu-item {
+          @extend %unable-select;
+          i.fa {
+            font-size: 16px;
+            margin-right: 4px;
+          }
+        }
+        .el-menu-item {
+          @extend %header-menu-item;
+          border-bottom: none;
+        }
+        .el-submenu {
+          @extend %header-menu-item;
+          .el-submenu__title {
+            border-bottom: none;
+          }
+        }
+      }
+      // 顶栏右侧的按钮
+      .d2-header-right {
+        float: right;
+        height: 60px;
+        display: flex;
+        align-items: center;
+        .btn-text {
+          padding: 14px 12px;
+          border-radius: 4px;
+          margin: 0px !important;
+          &.el-color-picker.el-color-picker--mini {
+            padding: 9px 6px;
+          }
+        }
+        .el-dropdown {
+          @extend %unable-select;
+        }
+      }
+    }
+    // [布局] 顶栏下面
+    .d2-theme-container {
+      // 侧边栏
+      .d2-theme-container-aside {
+        %d2-theme-container-aside-menu-icon {
+          width: 20px;
+          text-align: center;
+          font-size: 16px;
+        }
+        // [菜单] 正常状态
+        .el-menu {
+          @extend %unable-select;
+          background-color: transparent;
+          border-right: none;
+          .el-menu-item {
+            i {
+              @extend %d2-theme-container-aside-menu-icon;
+            }
+          }
+        }
+        .el-submenu {
+          @extend %unable-select;
+          .el-submenu__title {
+            i {
+              @extend %d2-theme-container-aside-menu-icon;
+            }
+            .el-submenu__icon-arrow {
+              margin-top: -10px;
+            }
+          }
+        }
+        // 菜单为空的时候显示的信息
+        .d2-layout-header-aside-menu-empty {
+          height: 160px;
+          margin: 10px;
+          margin-top: 0px;
+          border-radius: 4px;
+          @extend %unable-select;
+          i {
+            font-size: 30px;
+            margin-bottom: 10px;
+          }
+          span {
+            font-size: 14px;
+          }
+        }
+        // [菜单] 折叠状态
+        .el-menu--collapse {
+          background-color: transparent;
+          .el-submenu__title {
+            text-align: center;
+          }
+        }
+      }
+      // 右下 主体
+      .d2-theme-container-main {
+        // 主体部分分为多页面控制器 和主体
+        .d2-theme-container-main-header {
+          height: 41px;
+          // 多页面控制器
+          .d2-multiple-page-control-group {
+            padding-right: 20px;
+            .d2-multiple-page-control-content {
+              overflow: auto;
+              position: relative;
+              .d2-multiple-page-control-content-inner {
+                .d2-multiple-page-control {
+                  .el-tabs__header.is-top {
+                    margin: 0px;
+                  }
+                  .el-tabs__nav {
+                    overflow: hidden;
+                  }
+                }
+              }
+            }
+            .d2-multiple-page-control-btn {
+              position: relative;
+              bottom: -1px;
+              .el-dropdown {
+                .el-button-group {
+                  .el-button:first-child {
+                    border-bottom-left-radius: 0px;
+                  }
+                  .el-button:last-child {
+                    border-bottom-right-radius: 0px;
+                  }
+                }
+              }
+            }
+          }
+        }
+        // 主体
+        .d2-theme-container-main-body {
+          // 布局组件
+          .container-component {
+            @extend %full;
+            overflow: hidden;
+            // 填充式布局组件
+            .d2-container-full {
+              position: absolute;
+              top: 0px;
+              right: 20px;
+              bottom: 0px;
+              left: 0px;
+              display: flex;
+              flex-direction: column;
+              overflow: hidden;
+              .d2-container-full__header {
+                padding: 20px;
+              }
+              .d2-container-full__body {
+                flex-grow: 1;
+                height: 100%;
+                padding: 20px 20px;
+                overflow: auto;
+                position: relative;
+              }
+              .d2-container-full__footer {
+                padding: 20px;
+              }
+            }
+            // 填充式布局组件 - 滚动优化
+            .d2-container-full-bs {
+              position: absolute;
+              top: 0px;
+              right: 20px;
+              bottom: 0px;
+              left: 0px;
+              display: flex;
+              flex-direction: column;
+              overflow: hidden;
+              .d2-container-full-bs__header {
+                padding: 20px;
+              }
+              .d2-container-full-bs__body {
+                flex-grow: 1;
+                overflow: hidden;
+                position: relative;
+                .d2-container-full-bs__body-wrapper-inner {
+                  padding: 20px;
+                  position: relative;
+                }
+              }
+              .d2-container-full-bs__footer {
+                padding: 20px;
+              }
+            }
+            // 隐形布局组件
+            .d2-container-ghost {
+              position: absolute;
+              top: 0px;
+              right: 20px;
+              bottom: 0px;
+              left: 0px;
+              display: flex;
+              flex-direction: column;
+              overflow: hidden;
+              .d2-container-ghost__header {
+                padding: 20px;
+                border-bottom-left-radius: 4px;
+                border-bottom-right-radius: 4px;
+              }
+              .d2-container-ghost__body {
+                flex-grow: 1;
+                overflow: auto;
+                position: relative;
+              }
+              .d2-container-ghost__footer {
+                padding: 20px;
+                border-top-left-radius: 4px;
+                border-top-right-radius: 4px;
+              }
+            }
+            // 隐形布局组件 - 滚动优化
+            .d2-container-ghost-bs {
+              position: absolute;
+              top: 0px;
+              right: 20px;
+              bottom: 0px;
+              left: 0px;
+              display: flex;
+              flex-direction: column;
+              overflow: hidden;
+              .d2-container-ghost-bs__header {
+                padding: 20px;
+                border-bottom-left-radius: 4px;
+                border-bottom-right-radius: 4px;
+              }
+              .d2-container-ghost-bs__body {
+                flex-grow: 1;
+                overflow: hidden;
+                position: relative;
+              }
+              .d2-container-ghost-bs__footer {
+                padding: 20px;
+                border-top-left-radius: 4px;
+                border-top-right-radius: 4px;
+              }
+            }
+            // 卡片式布局组件
+            .d2-container-card {
+              position: absolute;
+              top: 0px;
+              right: 20px;
+              bottom: 0px;
+              left: 0px;
+              display: flex;
+              flex-direction: column;
+              overflow: hidden;
+              .d2-container-card__header {
+                padding: 20px;
+              }
+              .d2-container-card__body {
+                flex-grow: 1;
+                overflow: auto;
+                .d2-container-card__body-card {
+                  position: relative;
+                  margin-bottom: 20px;
+                  padding: 20px;
+                  border-bottom-left-radius: 4px;
+                  border-bottom-right-radius: 4px;
+                }
+              }
+              .d2-container-card__footer {
+                padding: 20px;
+                border-top-left-radius: 4px;
+                border-top-right-radius: 4px;
+              }
+            }
+            // 卡片式布局组件 - 滚动优化
+            .d2-container-card-bs {
+              position: absolute;
+              top: 0px;
+              right: 20px;
+              bottom: 0px;
+              left: 0px;
+              display: flex;
+              flex-direction: column;
+              overflow: hidden;
+              .d2-container-card-bs__header {
+                padding: 20px;
+              }
+              .d2-container-card-bs__body {
+                position: relative;
+                flex-grow: 1;
+                overflow: hidden;
+                .d2-container-card-bs__body-wrapper-inner {
+                  padding-bottom: 20px;
+                }
+                .d2-container-card-bs__body-card {
+                  position: relative;
+                  padding: 20px;
+                  border-bottom-left-radius: 4px;
+                  border-bottom-right-radius: 4px;
+                }
+              }
+              .d2-container-card-bs__footer {
+                padding: 20px;
+                border-top-left-radius: 4px;
+                border-top-right-radius: 4px;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}

+ 421 - 0
d2-admin/src/assets/style/theme/theme.scss

@@ -0,0 +1,421 @@
+// 每个主题特有的设置
+.theme-#{$theme-name} {
+
+  .el-message {
+    &.el-message--info {
+      background-color: $theme-message-info-background-color;
+      color: $theme-message-info-text-color;
+      border-color: $theme-message-info-border-color;
+    }
+  }
+
+  .el-card {
+    &.d2-card {
+      border: $theme-container-border-outer;
+      .el-card__header {
+        border-bottom: $theme-container-border-outer;
+      }
+    }
+  }
+
+  // 背景图片和遮罩
+  .d2-layout-header-aside-group {
+    background-color: $theme-bg-color;
+    .d2-layout-header-aside-mask {
+      background: $theme-bg-mask;
+    }
+  }
+
+  // 菜单项目
+  @mixin theme-menu-hover-style {
+    color: $theme-menu-item-color-hover;
+    i.fa {
+      color: $theme-menu-item-color-hover;
+    }
+    background: $theme-menu-item-background-color-hover;
+  }
+  %el-menu-icon {
+    i {
+      display: inline-block;
+      width: 14px;
+      text-align: center;
+      margin-right: 5px;
+    }
+    svg {
+      margin: 0px;
+      height: 14px;
+      width: 14px;
+      margin-right: 5px;
+    }
+  }
+  .el-submenu__title {
+    @extend %unable-select;
+    @extend %el-menu-icon;
+  }
+  .el-menu-item {
+    @extend %unable-select;
+    @extend %el-menu-icon;
+  }
+  .el-submenu__title:hover {
+    @include theme-menu-hover-style;
+  }
+  .el-menu-item:hover {
+    @include theme-menu-hover-style;
+  }
+  .el-menu--horizontal .el-menu-item:not(.is-disabled):hover {
+    @include theme-menu-hover-style;
+  }
+  .el-menu--horizontal .el-menu .el-submenu__title:hover {
+    @include theme-menu-hover-style;
+  }
+  
+  // 顶栏
+  .d2-theme-header {
+    // 顶栏菜单空间不足时显示的滚动控件
+    .d2-theme-header-menu {
+      .d2-theme-header-menu__prev, .d2-theme-header-menu__next {
+        color: $theme-header-item-color;
+        background: $theme-header-item-background-color;
+        &:hover {
+          color: $theme-header-item-color-hover;
+          background: $theme-header-item-background-color-hover;
+        }
+      }
+    }
+    // 切换按钮
+    .toggle-aside-btn {
+      i {
+        color: $theme-header-item-color;
+        background: $theme-header-item-background-color;
+        &:hover {
+          color: $theme-header-item-color-hover;
+        }
+      }
+    }
+    // 顶栏菜单
+    .el-menu {
+      .el-menu-item {
+        transition: border-top-color 0s;
+        color: $theme-header-item-color;
+        background: $theme-header-item-background-color;
+        i.fa { color: inherit; }
+        &:hover {
+          color: $theme-header-item-color-hover;
+          background: $theme-header-item-background-color-hover;
+          i.fa { color: inherit; }
+        }
+        &:focus {
+          color: $theme-header-item-color-focus;
+          background: $theme-header-item-background-color-focus;
+          i.fa { color: inherit; }
+        }
+        &.is-active {
+          color: $theme-header-item-color-active;
+          background: $theme-header-item-background-color-active;
+          i.fa { color: inherit; }
+        }
+      }
+      .el-submenu {
+        &.is-active {
+          .el-submenu__title {
+            color: $theme-header-item-color-active;
+            background: $theme-header-item-background-color-active;
+            i.fa { color: inherit; }
+          }
+        }
+        .el-submenu__title {
+          transition: border-top-color 0s;
+          color: $theme-header-item-color;
+          background: $theme-header-item-background-color;
+          i.fa { color: inherit; }
+          .el-submenu__icon-arrow {
+            color: $theme-header-item-color;
+          }
+          &:hover {
+            color: $theme-header-item-color-hover;
+            background: $theme-header-item-background-color-hover;
+            i.fa { color: inherit; }
+            .el-submenu__icon-arrow {
+              color: $theme-header-item-color-hover;
+            }
+          }
+          &:focus {
+            color: $theme-header-item-color-focus;
+            background: $theme-header-item-background-color-focus;
+            i.fa { color: inherit; }
+            .el-submenu__icon-arrow {
+              color: $theme-header-item-color-focus;
+            }
+          }
+        }
+      }
+    }
+    // 顶栏右侧
+    .d2-header-right {
+      .btn-text {
+        color: $theme-header-item-color;
+        &.can-hover {
+          &:hover {
+            color: $theme-header-item-color-hover;
+            background: $theme-header-item-background-color-hover;
+          }
+        }
+      }
+    }
+  }
+  // [布局] 顶栏下面
+  .d2-theme-container {
+    // 侧边栏
+    .d2-theme-container-aside {
+      // 菜单为空的时候显示的信息
+      .d2-layout-header-aside-menu-empty {
+        background: $theme-aside-menu-empty-background-color;
+        i {
+          color: $theme-aside-menu-empty-icon-color;
+        }
+        span {
+          color: $theme-aside-menu-empty-text-color;
+        }
+        &:hover {
+          background: $theme-aside-menu-empty-background-color-hover;
+          i {
+            color: $theme-aside-menu-empty-icon-color-hover;
+          }
+          span {
+            color: $theme-aside-menu-empty-text-color-hover;
+          }
+        }
+      }
+      // [菜单] 正常状态
+      .el-menu {
+        .el-menu-item {
+          color: $theme-aside-item-color;
+          background: $theme-aside-item-background-color;
+          i {
+            color: $theme-aside-item-color;
+          }
+          &:hover {
+            color: $theme-aside-item-color-hover;
+            fill: $theme-aside-item-color-hover;
+            background: $theme-aside-item-background-color-hover;
+            i {
+              color: $theme-aside-item-color-hover;
+            }
+          }
+          &:focus {
+            color: $theme-aside-item-color-focus;
+            fill: $theme-aside-item-color-focus;
+            background: $theme-aside-item-background-color-focus;
+            i {
+              color: $theme-aside-item-color-focus;
+            }
+          }
+          &.is-active {
+            color: $theme-aside-item-color-active;
+            fill: $theme-aside-item-color-active;
+            background: $theme-aside-item-background-color-active;
+            i {
+              color: $theme-aside-item-color-active;
+            }
+          }
+        }
+      }
+      .el-submenu {
+        .el-submenu__title {
+          color: $theme-aside-item-color;
+          background: $theme-aside-item-background-color;
+          i {
+            color: $theme-aside-item-color;
+          }
+          .el-submenu__icon-arrow {
+            color: $theme-aside-item-color;
+          }
+          &:hover {
+            color: $theme-aside-item-color-hover;
+            background: $theme-aside-item-background-color-hover;
+            i {
+              color: $theme-aside-item-color-hover;
+            }
+            .el-submenu__icon-arrow {
+              color: $theme-aside-item-color-hover;
+            }
+          }
+        }
+      }
+    }
+    .d2-theme-container-main {
+      // 主体部分分为多页面控制器 和主体
+      .d2-theme-container-main-header {
+        // 多页面控制器
+        .d2-multiple-page-control {
+          .el-tabs__header.is-top {
+            border-bottom-color: $theme-multiple-page-control-border-color;
+          }
+          .el-tabs__nav {
+            border-color: $theme-multiple-page-control-border-color;
+            .el-tabs__item {
+              @extend %unable-select;
+              color: $theme-multiple-page-control-color;
+              background-color: $theme-multiple-page-control-background-color;
+              border-left-color: $theme-multiple-page-control-border-color;
+              &:first-child {
+                border-left: none;
+                &:hover {
+                  padding: 0px 20px;
+                }
+              }
+            }
+            .el-tabs__item.is-active {
+              color: $theme-multiple-page-control-color-active;
+              background-color: $theme-multiple-page-control-background-color-active;
+              border-bottom-color: $theme-multiple-page-control-border-color-active;
+            }
+          }
+          %el-tabs__nav {
+            font-size: 20px;
+          }
+          .el-tabs__nav-prev {
+            @extend %el-tabs__nav;
+            color: $theme-multiple-page-control-nav-prev-color;
+          }
+          .el-tabs__nav-next {
+            @extend %el-tabs__nav;
+            color: $theme-multiple-page-control-nav-next-color;
+          }
+        }
+        // 多页控制器的关闭控制
+        .d2-multiple-page-control-btn {
+          .el-dropdown {
+            .el-button-group {
+              .el-button {
+                border-color: $theme-multiple-page-control-border-color;
+              }
+            }
+          }
+        }
+      }
+      // 主体
+      .d2-theme-container-main-body {
+        // 布局组件
+        .container-component {
+          // [组件]
+          // d2-container-full 填充型
+          .d2-container-full {
+            border: $theme-container-border-outer;
+            border-top: none;
+            border-bottom: none;
+            .d2-container-full__header {
+              border-bottom: $theme-container-border-inner;
+              background: $theme-container-header-footer-background-color;
+            }
+            .d2-container-full__body {
+              background: $theme-container-background-color;
+            }
+            .d2-container-full__footer {
+              border-top: $theme-container-border-inner;
+              background: $theme-container-header-footer-background-color;
+            }
+          }
+          // [组件]
+          // d2-container-full-bs 填充型 滚动优化
+          .d2-container-full-bs {
+            border: $theme-container-border-outer;
+            border-top: none;
+            border-bottom: none;
+            .d2-container-full-bs__header {
+              border-bottom: $theme-container-border-inner;
+              background: $theme-container-header-footer-background-color;
+            }
+            .d2-container-full-bs__body {
+              background: $theme-container-background-color;
+            }
+            .d2-container-full-bs__footer {
+              border-top: $theme-container-border-inner;
+              background: $theme-container-header-footer-background-color;
+            }
+          }
+          // [组件]
+          // d2-container-ghost 隐形布局组件
+          .d2-container-ghost {
+            .d2-container-ghost__header {
+              border-bottom: $theme-container-border-outer;
+              border-left: $theme-container-border-outer;
+              border-right: $theme-container-border-outer;
+              background: $theme-container-header-footer-background-color;
+            }
+            .d2-container-ghost__footer {
+              border-top: $theme-container-border-outer;
+              border-left: $theme-container-border-outer;
+              border-right: $theme-container-border-outer;
+              background: $theme-container-header-footer-background-color;
+            }
+          }
+          // [组件]
+          // d2-container-ghost-bs 隐形布局组件 滚动优化
+          .d2-container-ghost-bs {
+            .d2-container-ghost-bs__header {
+              border-bottom: $theme-container-border-outer;
+              border-left: $theme-container-border-outer;
+              border-right: $theme-container-border-outer;
+              background: $theme-container-header-footer-background-color;
+            }
+            .d2-container-ghost-bs__footer {
+              border-top: $theme-container-border-outer;
+              border-left: $theme-container-border-outer;
+              border-right: $theme-container-border-outer;
+              background: $theme-container-header-footer-background-color;
+            }
+          }
+          // [组件]
+          // d2-container-card 卡片型
+          .d2-container-card {
+            .d2-container-card__header {
+              border-bottom: $theme-container-border-inner;
+              border-left: $theme-container-border-outer;
+              border-right: $theme-container-border-outer;
+              background: $theme-container-header-footer-background-color;
+            }
+            .d2-container-card__body {
+              .d2-container-card__body-card {
+                background: $theme-container-background-color;
+                border-left: $theme-container-border-outer;
+                border-right: $theme-container-border-outer;
+                border-bottom: $theme-container-border-outer;
+              }
+            }
+            .d2-container-card__footer {
+              border-top: $theme-container-border-outer;
+              border-left: $theme-container-border-outer;
+              border-right: $theme-container-border-outer;
+              background: $theme-container-header-footer-background-color;
+            }
+          }
+          // [组件]
+          // d2-container-card-bs 卡片型 滚动优化
+          .d2-container-card-bs {
+            .d2-container-card-bs__header {
+              border-bottom: $theme-container-border-inner;
+              border-left: $theme-container-border-outer;
+              border-right: $theme-container-border-outer;
+              background: $theme-container-header-footer-background-color;
+            }
+            .d2-container-card-bs__body {
+              .d2-container-card-bs__body-card {
+                background: $theme-container-background-color;
+                border-left: $theme-container-border-outer;
+                border-right: $theme-container-border-outer;
+                border-bottom: $theme-container-border-outer;
+              }
+            }
+            .d2-container-card-bs__footer {
+              border-top: $theme-container-border-outer;
+              border-left: $theme-container-border-outer;
+              border-right: $theme-container-border-outer;
+              background: $theme-container-header-footer-background-color;
+            }
+          }
+        }
+      }
+    }
+  }
+}

+ 2 - 0
d2-admin/src/assets/style/theme/tomorrow-night-blue/index.scss

@@ -0,0 +1,2 @@
+@import './setting.scss';
+@import '../theme.scss';

+ 64 - 0
d2-admin/src/assets/style/theme/tomorrow-night-blue/setting.scss

@@ -0,0 +1,64 @@
+// 主题名称
+$theme-name: 'tomorrow-night-blue';
+// 主题背景颜色
+$theme-bg-color: #002253;
+// 主题背景图片遮罩
+$theme-bg-mask: rgba(#000, 0);
+
+// 消息提示
+$theme-message-info-background-color: $color-bg;
+$theme-message-info-text-color: $color-text-normal;
+$theme-message-info-border-color: $color-border-1;
+
+// container组件
+$theme-container-background-color: rgba(#FFF, 1);
+$theme-container-header-footer-background-color: #FFF;
+$theme-container-border-inner: 1px solid $color-border-1;
+$theme-container-border-outer: 1px solid #002253;
+
+$theme-multiple-page-control-color: #FFF;
+$theme-multiple-page-control-color-active: $color-text-normal;
+$theme-multiple-page-control-nav-prev-color: #FFF;
+$theme-multiple-page-control-nav-next-color: #FFF;
+$theme-multiple-page-control-border-color: #002253;
+$theme-multiple-page-control-border-color-active: #FFF;
+$theme-multiple-page-control-background-color: rgba(#FFF, .2);
+$theme-multiple-page-control-background-color-active: #FFF;
+
+// 顶栏和侧边栏中展开的菜单 hover 状态下
+$theme-menu-item-color-hover: #293849;
+$theme-menu-item-background-color-hover: #ecf5ff;
+
+// 顶栏上的文字颜色
+$theme-header-item-color: #FF929A;
+$theme-header-item-background-color: transparent;
+// 顶栏上的项目在 hover 时
+$theme-header-item-color-hover: #FFEBA4;
+$theme-header-item-background-color-hover: rgba(#FFF, .05);
+// 顶栏上的项目在 focus 时
+$theme-header-item-color-focus: #FFB870;
+$theme-header-item-background-color-focus: rgba(#FFF, .05);
+// 顶栏上的项目在 active 时
+$theme-header-item-color-active: #FFB870;
+$theme-header-item-background-color-active: rgba(#FFF, .05);
+
+// 侧边栏上的文字颜色
+$theme-aside-item-color: #FF929A;
+$theme-aside-item-background-color: transparent;
+// 侧边栏上的项目在 hover 时
+$theme-aside-item-color-hover: #FFEBA4;
+$theme-aside-item-background-color-hover: rgba(#FFF, .05);
+// 侧边栏上的项目在 focus 时
+$theme-aside-item-color-focus: #FFB870;
+$theme-aside-item-background-color-focus: rgba(#FFF, .05);
+// 侧边栏上的项目在 active 时
+$theme-aside-item-color-active: #FFB870;
+$theme-aside-item-background-color-active: rgba(#FFF, .05);
+
+// 侧边栏菜单为空的时候显示的元素
+$theme-aside-menu-empty-icon-color: #FFB870;
+$theme-aside-menu-empty-text-color: #FFB870;
+$theme-aside-menu-empty-background-color: rgba(#FFF, .1);
+$theme-aside-menu-empty-icon-color-hover: #FFEBA4;
+$theme-aside-menu-empty-text-color-hover: #FFEBA4;
+$theme-aside-menu-empty-background-color-hover: rgba(#FFF, .2);

+ 9 - 0
d2-admin/src/assets/style/theme/violet/index.scss

@@ -0,0 +1,9 @@
+@import './setting.scss';
+@import '../theme.scss';
+
+.theme-#{$theme-name} {
+  .d2-layout-header-aside-group {
+    background: #bc00e3;
+    background: linear-gradient(120deg, #bc00e3 0%, #4EFFFB 100%);
+  }
+}

+ 64 - 0
d2-admin/src/assets/style/theme/violet/setting.scss

@@ -0,0 +1,64 @@
+// 主题名称
+$theme-name: 'violet';
+// 主题背景颜色
+$theme-bg-color: #000;
+// 主题背景图片遮罩
+$theme-bg-mask: rgba(#000, 0);
+
+// 消息提示
+$theme-message-info-background-color: $color-bg;
+$theme-message-info-text-color: $color-text-normal;
+$theme-message-info-border-color: $color-border-1;
+
+// container组件
+$theme-container-background-color: #FFF;
+$theme-container-header-footer-background-color: #FFF;
+$theme-container-border-inner: 1px solid $color-border-2;
+$theme-container-border-outer: 1px solid #8C40E2;
+
+$theme-multiple-page-control-color: #FFF;
+$theme-multiple-page-control-color-active: $color-text-normal;
+$theme-multiple-page-control-nav-prev-color: #FFF;
+$theme-multiple-page-control-nav-next-color: #FFF;
+$theme-multiple-page-control-border-color: #8C40E2;
+$theme-multiple-page-control-border-color-active: #FFF;
+$theme-multiple-page-control-background-color: rgba(#FFF, .3);
+$theme-multiple-page-control-background-color-active: #FFF;
+
+// 顶栏和侧边栏中展开的菜单 hover 状态下
+$theme-menu-item-color-hover: #293849;
+$theme-menu-item-background-color-hover: #ecf5ff;
+
+// 顶栏上的文字颜色
+$theme-header-item-color: #FFF;
+$theme-header-item-background-color: transparent;
+// 顶栏上的项目在 hover 时
+$theme-header-item-color-hover: #FFF;
+$theme-header-item-background-color-hover: linear-gradient(-180deg, rgba(255,255,255,0.18) 0%, rgba(255,255,255,0.12) 100%);
+// 顶栏上的项目在 focus 时
+$theme-header-item-color-focus: #FFF;
+$theme-header-item-background-color-focus: linear-gradient(-180deg, rgba(255,255,255,0.18) 0%, rgba(255,255,255,0.12) 100%);
+// 顶栏上的项目在 active 时
+$theme-header-item-color-active: #FFF;
+$theme-header-item-background-color-active: linear-gradient(-180deg, rgba(255,255,255,0.18) 0%, rgba(255,255,255,0.12) 100%);
+
+// 侧边栏上的文字颜色
+$theme-aside-item-color: #FFF;
+$theme-aside-item-background-color: transparent;
+// 侧边栏上的项目在 hover 时
+$theme-aside-item-color-hover: #FFF;
+$theme-aside-item-background-color-hover: linear-gradient(90deg, rgba(255,255,255,0.28) 0%, rgba(255,255,255,0.00) 100%);
+// 侧边栏上的项目在 focus 时
+$theme-aside-item-color-focus: #FFF;
+$theme-aside-item-background-color-focus: linear-gradient(90deg, rgba(255,255,255,0.28) 0%, rgba(255,255,255,0.00) 100%);
+// 侧边栏上的项目在 active 时
+$theme-aside-item-color-active: #FFF;
+$theme-aside-item-background-color-active: linear-gradient(90deg, rgba(255,255,255,0.28) 0%, rgba(255,255,255,0.00) 100%);
+
+// 侧边栏菜单为空的时候显示的元素
+$theme-aside-menu-empty-icon-color: #FFF;
+$theme-aside-menu-empty-text-color: #FFF;
+$theme-aside-menu-empty-background-color: rgba(#000, .1);
+$theme-aside-menu-empty-icon-color-hover: #FFF;
+$theme-aside-menu-empty-text-color-hover: #FFF;
+$theme-aside-menu-empty-background-color-hover: rgba(#000, .15);

+ 23 - 0
d2-admin/src/assets/style/unit/color.scss

@@ -0,0 +1,23 @@
+// 主色
+$color-primary: #409EFF;
+
+// 辅助色
+$color-info: #909399;
+$color-success: #67C23A;
+$color-warning: #E6A23C;
+$color-danger: #F56C6C;
+
+// 文字
+$color-text-main: #303133;
+$color-text-normal: #606266;
+$color-text-sub: #909399;
+$color-text-placehoder: #C0C4CC;
+
+// 边框
+$color-border-1: #DCDFE6;
+$color-border-2: #E4E7ED;
+$color-border-3: #EBEEF5;
+$color-border-4: #F2F6FC;
+
+// 背景
+$color-bg: #f8f8f9;

File diff suppressed because it is too large
+ 19 - 0
d2-admin/src/assets/svg-icons/icons/d2-admin-text.svg


File diff suppressed because it is too large
+ 13 - 0
d2-admin/src/assets/svg-icons/icons/d2-admin.svg


+ 7 - 0
d2-admin/src/assets/svg-icons/index.js

@@ -0,0 +1,7 @@
+import Vue from 'vue'
+
+const requireAll = requireContext => requireContext.keys().map(requireContext)
+const req = require.context('./icons', false, /\.svg$/)
+const iconMap = requireAll(req)
+
+Vue.prototype.$IconSvg = iconMap.map(e => e.default.id.slice(3))

+ 27 - 0
d2-admin/src/components/d2-container/components/d2-container-card-bs.vue

@@ -0,0 +1,27 @@
+<template>
+  <div class="d2-container-card-bs">
+    <div v-if="$slots.header" class="d2-container-card-bs__header" ref="header">
+      <slot name="header"/>
+    </div>
+    <div class="d2-container-card-bs__body" ref="wrapper">
+      <div class="d2-container-card-bs__body-wrapper-inner">
+        <div class="d2-container-card-bs__body-card">
+          <slot/>
+        </div>
+      </div>
+    </div>
+    <div v-if="$slots.footer" class="d2-container-card-bs__footer" ref="footer">
+      <slot name="footer"/>
+    </div>
+  </div>
+</template>
+
+<script>
+import bs from './mixins/bs'
+export default {
+  name: 'd2-container-card-bs',
+  mixins: [
+    bs
+  ]
+}
+</script>

+ 33 - 0
d2-admin/src/components/d2-container/components/d2-container-card.vue

@@ -0,0 +1,33 @@
+<template>
+  <div class="d2-container-card">
+    <div v-if="$slots.header" class="d2-container-card__header" ref="header">
+      <slot name="header"/>
+    </div>
+    <div class="d2-container-card__body" ref="body">
+      <div class="d2-container-card__body-card">
+        <slot/>
+      </div>
+    </div>
+    <div v-if="$slots.footer" class="d2-container-card__footer" ref="footer">
+      <slot name="footer"/>
+    </div>
+  </div>
+</template>
+
+<script>
+import scroll from './mixins/normal'
+export default {
+  name: 'd2-container-card',
+  mixins: [
+    scroll
+  ],
+  mounted () {
+    // 增加滚动事件监听
+    this.addScrollListener()
+  },
+  beforeDestroy () {
+    // 移除滚动事件监听
+    this.removeScrollListener()
+  }
+}
+</script>

+ 25 - 0
d2-admin/src/components/d2-container/components/d2-container-full-bs.vue

@@ -0,0 +1,25 @@
+<template>
+  <div class="d2-container-full-bs">
+    <div v-if="$slots.header" class="d2-container-full-bs__header" ref="header">
+      <slot name="header"/>
+    </div>
+    <div class="d2-container-full-bs__body" ref="wrapper">
+      <div class="d2-container-full-bs__body-wrapper-inner">
+        <slot/>
+      </div>
+    </div>
+    <div v-if="$slots.footer" class="d2-container-full-bs__footer" ref="footer">
+      <slot name="footer"/>
+    </div>
+  </div>
+</template>
+
+<script>
+import bs from './mixins/bs'
+export default {
+  name: 'd2-container-card-bs',
+  mixins: [
+    bs
+  ]
+}
+</script>

+ 31 - 0
d2-admin/src/components/d2-container/components/d2-container-full.vue

@@ -0,0 +1,31 @@
+<template>
+  <div class="d2-container-full">
+    <div v-if="$slots.header" class="d2-container-full__header" ref="header">
+      <slot name="header"/>
+    </div>
+    <div class="d2-container-full__body" ref="body">
+      <slot/>
+    </div>
+    <div v-if="$slots.footer" class="d2-container-full__footer" ref="footer">
+      <slot name="footer"/>
+    </div>
+  </div>
+</template>
+
+<script>
+import scroll from './mixins/normal'
+export default {
+  name: 'd2-container-full',
+  mixins: [
+    scroll
+  ],
+  mounted () {
+    // 增加滚动事件监听
+    this.addScrollListener()
+  },
+  beforeDestroy () {
+    // 移除滚动事件监听
+    this.removeScrollListener()
+  }
+}
+</script>

+ 26 - 0
d2-admin/src/components/d2-container/components/d2-container-ghost-bs.vue

@@ -0,0 +1,26 @@
+<template>
+  <div class="d2-container-ghost-bs">
+    <div v-if="$slots.header" class="d2-container-ghost-bs__header" ref="header">
+      <slot name="header"/>
+    </div>
+    <div class="d2-container-ghost-bs__body" ref="wrapper">
+      <!-- https://github.com/d2-projects/d2-admin/issues/181 -->
+      <div>
+        <slot/>
+      </div>
+    </div>
+    <div v-if="$slots.footer" class="d2-container-ghost-bs__footer" ref="footer">
+      <slot name="footer"/>
+    </div>
+  </div>
+</template>
+
+<script>
+import bs from './mixins/bs'
+export default {
+  name: 'd2-container-card-bs',
+  mixins: [
+    bs
+  ]
+}
+</script>

+ 31 - 0
d2-admin/src/components/d2-container/components/d2-container-ghost.vue

@@ -0,0 +1,31 @@
+<template>
+  <div class="d2-container-ghost">
+    <div v-if="$slots.header" class="d2-container-ghost__header" ref="header">
+      <slot name="header"/>
+    </div>
+    <div class="d2-container-ghost__body" ref="body">
+      <slot/>
+    </div>
+    <div v-if="$slots.footer" class="d2-container-ghost__footer" ref="footer">
+      <slot name="footer"/>
+    </div>
+  </div>
+</template>
+
+<script>
+import scroll from './mixins/normal'
+export default {
+  name: 'd2-container-ghost',
+  mixins: [
+    scroll
+  ],
+  mounted () {
+    // 增加滚动事件监听
+    this.addScrollListener()
+  },
+  beforeDestroy () {
+    // 移除滚动事件监听
+    this.removeScrollListener()
+  }
+}
+</script>

+ 79 - 0
d2-admin/src/components/d2-container/components/d2-source.vue

@@ -0,0 +1,79 @@
+<template>
+  <div
+    v-if="show"
+    class="d2-source"
+    :class="{ 'd2-source--active': isActive }"
+    @click="handleClick">
+    <d2-icon name="code"/> 本页源码
+  </div>
+</template>
+
+<script>
+import { last, get } from 'lodash'
+export default {
+  data () {
+    return {
+      isActive: false,
+      path: ''
+    }
+  },
+  computed: {
+    show () {
+      return process.env.VUE_APP_SCOURCE_LINK === 'TRUE'
+    }
+  },
+  watch: {
+    $route: {
+      handler (to) {
+        this.path = get(last(to.matched), 'components.default.__source')
+      },
+      immediate: true
+    }
+  },
+  mounted () {
+    // 一秒后显示按钮
+    setTimeout(() => {
+      this.isActive = true
+    }, 500)
+  },
+  methods: {
+    // 点击按钮的时候跳转到源代码
+    handleClick () {
+      this.$open(`${process.env.VUE_APP_REPO}/blob/master/${this.path}`)
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.d2-source {
+  $borderRadius: 4px;
+  $paddingLR: 15px;
+  $paddingTB: 7px;
+  $fontSize: 12px;
+  $rightOuter: $paddingLR / 2;
+  opacity: 0;
+  position: fixed;
+  z-index: 9999;
+  right: - $borderRadius - $rightOuter;
+  bottom: 20px;
+  font-size: $fontSize;
+  line-height: $fontSize;
+  font-weight: bold;
+  border-radius: $borderRadius;
+  padding: $paddingTB $paddingLR;
+  padding-right: $borderRadius + $paddingLR;
+  background-color: rgba(#000, .7);
+  border: 1px solid #000;
+  color: #FFF;
+  transition: all .3s;
+  @extend %unable-select;
+  &.d2-source--active {
+    opacity: 1;
+  }
+  &:hover {
+    right: - $borderRadius;
+    background-color: rgba(#000, .9);
+  }
+}
+</style>

+ 0 - 0
d2-admin/src/components/d2-container/components/mixins/bs.js


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