init
5
.browserslistrc
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# 支持浏览器配置
|
||||||
|
> 1%
|
||||||
|
last 2 versions
|
||||||
|
not dead
|
||||||
|
|
||||||
14
.editorconfig
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# 编辑器配置
|
||||||
|
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
indent_size = 2
|
||||||
|
indent_style = space
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
||||||
7
.eslintignore
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
src/assets
|
||||||
|
src/icons
|
||||||
|
public
|
||||||
|
dist
|
||||||
|
node_modules
|
||||||
|
vab-icon
|
||||||
|
layouts
|
||||||
123
.eslintrc.js
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
/**
|
||||||
|
* @author https://github.com/zxwk1998/vue-admin-better (不想保留author可删除)
|
||||||
|
* @description .eslintrc.js
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
root: true,
|
||||||
|
env: {
|
||||||
|
node: true,
|
||||||
|
},
|
||||||
|
extends: ['plugin:vue/recommended', 'eslint:recommended', '@vue/prettier'],
|
||||||
|
rules: {
|
||||||
|
'no-undef': 'off',
|
||||||
|
'no-console': 'off',
|
||||||
|
'no-debugger': 'off',
|
||||||
|
'prettier/prettier': 'warn',
|
||||||
|
'prefer-template': 'error',
|
||||||
|
'@typescript-eslint/no-this-alias': 'off',
|
||||||
|
'@typescript-eslint/no-explicit-any': 'off',
|
||||||
|
'@typescript-eslint/no-var-requires': 'off',
|
||||||
|
'@typescript-eslint/no-empty-function': 'off',
|
||||||
|
'@typescript-eslint/ban-ts-comment': 'off',
|
||||||
|
'vue/no-reserved-component-names': 'off',
|
||||||
|
'vue/no-v-html': 'off',
|
||||||
|
'no-unused-vars': 'off',
|
||||||
|
'vue/no-useless-template-attributes': 'off',
|
||||||
|
'use-isnan': 'off',
|
||||||
|
'vue/html-self-closing': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
html: {
|
||||||
|
void: 'any',
|
||||||
|
normal: 'any',
|
||||||
|
component: 'always',
|
||||||
|
},
|
||||||
|
svg: 'always',
|
||||||
|
math: 'always',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'vue/component-name-in-template-casing': [
|
||||||
|
'error',
|
||||||
|
'kebab-case',
|
||||||
|
{
|
||||||
|
registeredComponentsOnly: false,
|
||||||
|
ignores: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
// 多字组件名称
|
||||||
|
'vue/multi-word-component-names': 'off',
|
||||||
|
// Vue组件排序
|
||||||
|
'vue/order-in-components': [
|
||||||
|
'warn',
|
||||||
|
{
|
||||||
|
order: [
|
||||||
|
'el',
|
||||||
|
'name',
|
||||||
|
'key',
|
||||||
|
'parent',
|
||||||
|
'functional',
|
||||||
|
['delimiters', 'comments'],
|
||||||
|
['components', 'directives', 'filters'],
|
||||||
|
'extends',
|
||||||
|
'mixins',
|
||||||
|
['provide', 'inject'],
|
||||||
|
'ROUTER_GUARDS',
|
||||||
|
'layout',
|
||||||
|
'middleware',
|
||||||
|
'validate',
|
||||||
|
'scrollToTop',
|
||||||
|
'transition',
|
||||||
|
'loading',
|
||||||
|
'inheritAttrs',
|
||||||
|
'model',
|
||||||
|
['props', 'propsData'],
|
||||||
|
'emits',
|
||||||
|
'setup',
|
||||||
|
'fetch',
|
||||||
|
'asyncData',
|
||||||
|
'data',
|
||||||
|
'head',
|
||||||
|
'computed',
|
||||||
|
'watch',
|
||||||
|
'watchQuery',
|
||||||
|
'LIFECYCLE_HOOKS',
|
||||||
|
'methods',
|
||||||
|
['template', 'render'],
|
||||||
|
'renderError',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
// Vue属性排序
|
||||||
|
'vue/attributes-order': [
|
||||||
|
'warn',
|
||||||
|
{
|
||||||
|
order: [
|
||||||
|
'DEFINITION',
|
||||||
|
'LIST_RENDERING',
|
||||||
|
'CONDITIONALS',
|
||||||
|
'RENDER_MODIFIERS',
|
||||||
|
'GLOBAL',
|
||||||
|
'UNIQUE',
|
||||||
|
'TWO_WAY_BINDING',
|
||||||
|
'OTHER_DIRECTIVES',
|
||||||
|
'OTHER_ATTR',
|
||||||
|
'EVENTS',
|
||||||
|
'CONTENT',
|
||||||
|
],
|
||||||
|
alphabetical: true, //字母顺序
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
parserOptions: {
|
||||||
|
parser: 'babel-eslint',
|
||||||
|
},
|
||||||
|
overrides: [
|
||||||
|
{
|
||||||
|
files: ['**/__tests__/*.{j,t}s?(x)', '**/tests/unit/**/*.spec.{j,t}s?(x)'],
|
||||||
|
env: {
|
||||||
|
jest: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
14
.gitattributes
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# .gitattributes
|
||||||
|
*.html text eol=lf
|
||||||
|
*.css text eol=lf
|
||||||
|
*.js text eol=lf
|
||||||
|
*.scss text eol=lf
|
||||||
|
*.vue text eol=lf
|
||||||
|
*.hbs text eol=lf
|
||||||
|
*.sh text eol=lf
|
||||||
|
*.md text eol=lf
|
||||||
|
*.json text eol=lf
|
||||||
|
*.yml text eol=lf
|
||||||
|
.browserslistrc text eol=lf
|
||||||
|
.gitignore text eol=lf
|
||||||
|
*.js linguist-language=vue
|
||||||
26
.gitignore
vendored
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
# .gitignore
|
||||||
|
.DS_Store
|
||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
.env.local
|
||||||
|
.env.*.local
|
||||||
|
npm-debug.log*
|
||||||
|
yarn.lock
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
.idea
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
||||||
|
public/video
|
||||||
|
*.zip
|
||||||
|
*.7z
|
||||||
|
/src/layouts/components/layouts
|
||||||
|
/zx-templates
|
||||||
|
/package-lock.json
|
||||||
|
/src/styles/themes/green.scss
|
||||||
|
/src/styles/themes/dark.scss
|
||||||
|
/src/styles/themes/glory.scss
|
||||||
|
/.history
|
||||||
7
.stylelintrc.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
/**
|
||||||
|
* @author https://github.com/zxwk1998/vue-admin-better (不想保留author可删除)
|
||||||
|
* @description stylelint
|
||||||
|
*/
|
||||||
|
module.exports = {
|
||||||
|
extends: ['stylelint-config-recess-order', 'stylelint-config-prettier'],
|
||||||
|
}
|
||||||
54
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
{
|
||||||
|
"[vue]": {
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
|
},
|
||||||
|
"editor.quickSuggestions": {
|
||||||
|
"strings": true
|
||||||
|
},
|
||||||
|
"workbench.colorTheme": "One Monokai",
|
||||||
|
"editor.tabSize": 2,
|
||||||
|
"editor.detectIndentation": false,
|
||||||
|
"emmet.triggerExpansionOnTab": true,
|
||||||
|
"editor.formatOnSave": true,
|
||||||
|
"javascript.format.enable": true,
|
||||||
|
"git.enableSmartCommit": true,
|
||||||
|
"git.autofetch": true,
|
||||||
|
"git.confirmSync": false,
|
||||||
|
"[json]": {
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
|
},
|
||||||
|
"liveServer.settings.donotShowInfoMsg": true,
|
||||||
|
"explorer.confirmDelete": false,
|
||||||
|
"javascript.updateImportsOnFileMove.enabled": "always",
|
||||||
|
"typescript.updateImportsOnFileMove.enabled": "always",
|
||||||
|
"files.exclude": {
|
||||||
|
"**/.idea": true
|
||||||
|
},
|
||||||
|
"editor.codeActionsOnSave": {
|
||||||
|
"source.fixAll.stylelint": "explicit",
|
||||||
|
"source.fixAll.eslint": "explicit"
|
||||||
|
},
|
||||||
|
"[javascript]": {
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
|
},
|
||||||
|
"[jsonc]": {
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
|
},
|
||||||
|
"[html]": {
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
|
},
|
||||||
|
"editor.suggest.snippetsPreventQuickSuggestions": false,
|
||||||
|
"prettier.htmlWhitespaceSensitivity": "ignore",
|
||||||
|
"prettier.vueIndentScriptAndStyle": true,
|
||||||
|
"docthis.authorName": "https://vuejs-core.cn",
|
||||||
|
"docthis.includeAuthorTag": true,
|
||||||
|
"docthis.includeDescriptionTag": true,
|
||||||
|
"docthis.enableHungarianNotationEvaluation": true,
|
||||||
|
"docthis.inferTypesFromNames": true,
|
||||||
|
"vetur.format.defaultFormatter.html": "prettier",
|
||||||
|
"files.autoSave": "onFocusChange",
|
||||||
|
"path-intellisense.mappings": {
|
||||||
|
"@": "${workspaceRoot}/src"
|
||||||
|
},
|
||||||
|
"files.eol": "\n"
|
||||||
|
}
|
||||||
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2020 good luck
|
||||||
|
|
||||||
|
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.
|
||||||
203
README.en.md
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
[简体中文](./README.md) | English
|
||||||
|
|
||||||
|
<div align="center"><img width="200" src="https://gcore.jsdelivr.net/gh/zxwk1998/image/logo/vab.png"/>
|
||||||
|
<h1> vue-admin-better(element-ui) </h1>
|
||||||
|
<p>The flying snow all over the sky is a flying note, playing out expectations with blessings. May the epidemic dissipate as soon as possible, may you no longer have regrets next year, may you be warm in winter, may you not be cold in spring, and may you have lights in the dark and an umbrella in the rain.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
[](https://github.com/zxwk1998/vue-admin-better)
|
||||||
|
[](https://gitee.com/chu1204505056/vue-admin-better)
|
||||||
|
[](https://en.wikipedia.org/wiki/MIT_License)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🎉 Characteristic
|
||||||
|
|
||||||
|
- 💪 40 + high quality single page
|
||||||
|
- 💅 RBAC model + JWT permission control
|
||||||
|
- 🌍 100000 + practical application of the project
|
||||||
|
- 👏 Good type definition
|
||||||
|
- 🥳 The open source version supports free commercial use
|
||||||
|
- 🚀 Cross platform PC, mobile terminal and tablet
|
||||||
|
- 📦 Back end route dynamic rendering
|
||||||
|
|
||||||
|
## 🌐 Address
|
||||||
|
|
||||||
|
- [🎉 Vue2. X + element UI (free commercial, PC, tablet and mobile phone supported)](https://vuejs-core.cn/vue-admin-better/)
|
||||||
|
|
||||||
|
<!-- - [⚡️ Vue3. X + element plus (alpha version, free commercial, supporting PC, tablet and mobile phone)](https://vuejs-core.cn/vue-admin-better-plus/) -->
|
||||||
|
|
||||||
|
<!-- - [⚡️ Vue3. X + ant design Vue (beta version, free commercial, supporting PC, tablet and mobile phone)](https://vuejs-core.cn/vue-admin-better-antdv/) -->
|
||||||
|
|
||||||
|
- [⚡️ vue3.x + vite + vue-admin-arco](https://vuejs-core.cn/vue-admin-arco/)
|
||||||
|
|
||||||
|
- [🚀 Admin Pro demo address (vue2.x paid version, supporting PC, tablet and mobile phone)](https://vuejs-core.cn/admin-pro/)
|
||||||
|
|
||||||
|
- [🚀 Admin plus demo address (vue3.x paid version, supporting PC, tablet and mobile phone)](https://vuejs-core.cn/admin-plus/)
|
||||||
|
|
||||||
|
- [📌 Pro and plus purchase address authorization](https://vuejs-core.cn/authorization/)
|
||||||
|
|
||||||
|
- [🌐 Github Warehouse address](https://github.com/zxwk1998/vue-admin-better/)
|
||||||
|
|
||||||
|
- [🌐 Gitee Warehouse address](https://gitee.com/chu1204505056/vue-admin-better/)
|
||||||
|
|
||||||
|
- Recently, the VAB official website has been frequently attacked by DDoS. We have taken relevant preventive measures.
|
||||||
|
If the website cannot be accessed, please visit the backup address
|
||||||
|
|
||||||
|
## 📦️ Desktop applications
|
||||||
|
|
||||||
|
- [Admin Pro](https://gitee.com/chu1204505056/microsoft-store/raw/master/AdminPlus.zip)
|
||||||
|
- [Admin Plus](https://gitee.com/chu1204505056/microsoft-store/raw/master/AdminPlus.zip)
|
||||||
|
|
||||||
|
<!-- ## 🌱 Vue3.x vue3.0-antdv [Click switch branch](https://github.com/zxwk1998/vue-admin-better/tree/vue3.0-antdv)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone -b vue3.0-antdv https://github.com/zxwk1998/vue-admin-better.git
|
||||||
|
npm i --registry=http://mirrors.cloud.tencent.com/npm/
|
||||||
|
npm run serve
|
||||||
|
``` -->
|
||||||
|
|
||||||
|
## 🌱 Vue2.xmain [Click switch branch](https://github.com/zxwk1998/vue-admin-better/tree/master)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone -b master https://github.com/zxwk1998/vue-admin-better.git
|
||||||
|
npm i --registry=http://mirrors.cloud.tencent.com/npm/
|
||||||
|
npm run serve
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🍻 Front end discussion QQ group
|
||||||
|
|
||||||
|
- Let's have a cup of coffee, and then contact QQ 783963206 to invite you to the discussion group. Because of the large
|
||||||
|
number of users, if you haven't passed a friend's request, please contact Alipay on the Alipay payment page, whether
|
||||||
|
you invite or not, you can enjoy the open source code, thank you for your support and trust, and provide the
|
||||||
|
vue-admin-better basic version in the group. Automatic configuration tutorial of development tools and project
|
||||||
|
development documents.
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<!-- <td>
|
||||||
|
<img width="200px" src="https://gcore.jsdelivr.net/gh/zxwk1998/image/qq_group/hbm.jpg">
|
||||||
|
</td> -->
|
||||||
|
<td>
|
||||||
|
<img width="200px" src="https://gcore.jsdelivr.net/gh/zxwk1998/image/zfb_kf.jpg">
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<img width="200px" src="https://gcore.jsdelivr.net/gh/zxwk1998/image/qq_group/vab-2.jpg">
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<img width="200px" src="https://gcore.jsdelivr.net/gh/zxwk1998/image/qq_group/vab-3.jpg">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
## 🙈 We promise to sponsor open source projects regularly (thank giant)
|
||||||
|
|
||||||
|
<a title="vue" href="https://opencollective.com/vuejs" target="_blank">
|
||||||
|
<img width="64px" src="https://gcore.jsdelivr.net/gh/zxwk1998/image/vue.png"/>
|
||||||
|
</a>
|
||||||
|
<a title="element-plus" href="https://opencollective.com/element-plus" target="_blank">
|
||||||
|
<img width="64px" src="https://gcore.jsdelivr.net/gh/zxwk1998/image/element-plus.png"/>
|
||||||
|
</a>
|
||||||
|
<a title="ant-design-vue" href="https://opencollective.com/ant-design-vue" target="_blank">
|
||||||
|
<img width="64px" src="https://images.opencollective.com/ant-design-vue/2ec179b/logo/256.png"/>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
## 🎨 Acknowledge
|
||||||
|
|
||||||
|
| Project |
|
||||||
|
| ---------------------------------------------------------------- |
|
||||||
|
| [vue](https://github.com/vuejs/vue) |
|
||||||
|
| [element-ui](https://github.com/ElemeFE/element) |
|
||||||
|
| [element-plus](https://github.com/element-plus/element-plus) |
|
||||||
|
| [ant-design-vue](https://github.com/vueComponent/ant-design-vue) |
|
||||||
|
| [mock](https://github.com/nuysoft/Mock) |
|
||||||
|
| [axios](https://github.com/axios/axios) |
|
||||||
|
|
||||||
|
## 👷 Outstanding contributors to the framework (in no order)
|
||||||
|
|
||||||
|
<a href="https://github.com/buuing" target="_blank">
|
||||||
|
<img width="50px" style="border-radius:999px" src="https://avatars.githubusercontent.com/u/36689704?s=50"/>
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/hipi" target="_blank">
|
||||||
|
<img width="50px" style="border-radius:999px" src="https://avatars.githubusercontent.com/u/22478003?s=50"/>
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/fwfmiao" target="_blank">
|
||||||
|
<img width="50px" style="border-radius:999px" src="https://avatars.githubusercontent.com/u/29328241?s=50"/>
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/hdtopku" target="_blank">
|
||||||
|
<img width="50px" style="border-radius:999px" src="https://avatars.githubusercontent.com/u/14859466?s=50"/>
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/shaonialife" target="_blank">
|
||||||
|
<img width="50px" style="border-radius:999px" src="https://avatars.githubusercontent.com/u/16135960?s=50"/>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
## 📌 Advantages and precautions
|
||||||
|
|
||||||
|
```
|
||||||
|
Compared with other open source admin frameworks, it has the following advantages:
|
||||||
|
1. Support the front-end control routing permission intelligence and the back-end control routing permission all mode
|
||||||
|
2. It is known that the open source Vue admin framework is the first to support the automatic generation and export function of mock
|
||||||
|
3. More than 50 global fine configurations are provided
|
||||||
|
4. Support SCSS automatic sorting and eslint automatic repair
|
||||||
|
5. Axios fine encapsulation supports multiple data sources, multiple successful code arrays, and application / JSON; charset=UTF-8、application/x-www-form-urlencoded; Charset = UTF-8 multiple parameter transfer modes
|
||||||
|
6. Support login RSA encryption
|
||||||
|
7. Support packaging to automatically generate 7z compressed packages
|
||||||
|
8. Support errorlog error interception
|
||||||
|
9. Support multi theme and multi layout switching
|
||||||
|
Precautions for use:
|
||||||
|
1. The project uses lf line feed instead of CRLF line feed by default. When creating a new file, please pay attention to selecting the file line feed
|
||||||
|
2. The project uses the strictest eslint verification specification (plugin: Vue / recommended) by default. Before using it, it is recommended to configure the development tool to realize automatic repair (vscode development is recommended)
|
||||||
|
3. The project uses the MIT open source agreement with the broadest requirements, and the MIT open source agreement can be used for free
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## 💚 Suitable for people
|
||||||
|
|
||||||
|
- I am developing and want to use element UI / element plus, with 1 year of front-end development experience +.
|
||||||
|
- Familiar with vue.js technology stack and developed several practical projects with it.
|
||||||
|
- Students who are interested in principle and technology and want to improve.
|
||||||
|
|
||||||
|
## 🎉 Function map
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 🗃️ design sketch
|
||||||
|
|
||||||
|
The following is a screenshot of the pro version:
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<img src="https://gcore.jsdelivr.net/gh/zxwk1998/image/2.png">
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<img src="https://gcore.jsdelivr.net/gh/zxwk1998/image/6.png">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<img src="https://gcore.jsdelivr.net/gh/zxwk1998/image/8.png">
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<img src="https://gcore.jsdelivr.net/gh/zxwk1998/image/9.png">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<img src="https://gcore.jsdelivr.net/gh/zxwk1998/image/3.png">
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<img src="https://gcore.jsdelivr.net/gh/zxwk1998/image/5.png">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
## 📄 Commercial considerations
|
||||||
|
|
||||||
|
This project can be used for commercial purposes free of charge. Please abide by the MIT agreement and keep the author's
|
||||||
|
technical support statement. For customized source code copyright information, please contact customer service QQ 783963206.
|
||||||
|
|
||||||
|
<!-- ## 严正声明
|
||||||
|
|
||||||
|
近期发现不少游手好闲之人有组织有预谋的利用码云、知乎、掘金等网站可用国外非法网站提供的匿名手机号注册的账号 bug 冒充 vab 去攻击 vue-element-admin,iview-admin,若依,d2-admin,ant-design-vue 的行为,恶意制造对立,试图让其他开源作者卷入其中,对各位开源作者造成的影响我们深表歉意,我们欢迎 vab 的用户去体验其他更优秀的框架,vue-admin-beautiful 走到今天实属不易,被人冒充,被人发帖诋毁,被人故意发布错误言论假装发帖表扬实则为我们招骂,无意动任何人的奶酪,从 2020 年至今坚持全职维护已过一年时间,说实在的我们靠技术生存并不丢人吧,一年来感谢 vab 的用户对我们不离不弃,也希望大家越来越好,加油! -->
|
||||||
287
README.md
Normal file
@@ -0,0 +1,287 @@
|
|||||||
|
<div>
|
||||||
|
|
||||||
|
简体中文 | [English](./README.en.md)
|
||||||
|
|
||||||
|
<div align="center"><img width="200" src="https://gcore.jsdelivr.net/gh/zxwk1998/image/logo/vab.png"/>
|
||||||
|
<h1> vue-admin-better</h1>
|
||||||
|
<p>瑞雪兆丰年,红梅报新春,愿您新的一年平安喜乐,万事顺意,所得皆所愿!</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
[](https://github.com/zxwk1998/vue-admin-better)
|
||||||
|
[](https://gitee.com/chu1204505056/vue-admin-better)
|
||||||
|
[](https://en.wikipedia.org/wiki/MIT_License)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<!-- ## 🎉 全新版本
|
||||||
|
|
||||||
|
基于 vite5.x + vue3.x + arco-design2.x 全新的前端框架 vue-admin-arco, 欢迎点击查看或试用 👏🏻👏🏻👏🏻
|
||||||
|
|
||||||
|
[开源地址](https://github.com/zxwk1998/vue-admin-arco) | [演示地址](https://vuejs-core.cn/vue-admin-arco) -->
|
||||||
|
|
||||||
|
## 🎉 特性
|
||||||
|
|
||||||
|
- 💪 40+高质量单页
|
||||||
|
- 💅 RBAC 模型 + JWT 权限控制
|
||||||
|
- 🌍 10 万+ 项目实际应用
|
||||||
|
- 👏 良好的类型定义
|
||||||
|
- 🥳 开源版本支持免费商用
|
||||||
|
- 🚀 跨平台 PC、手机端、平板
|
||||||
|
- 📦️ 后端路由动态渲染
|
||||||
|
|
||||||
|
## 🌐 付费版演示地址
|
||||||
|
|
||||||
|
- [🚀 Vue Admin Pro 演示地址(vue2.x + element-ui 2.x 付费版本,支持 PC、平板、手机)](https://vuejs-core.cn/admin-pro/)
|
||||||
|
|
||||||
|
- [🚀 Vue Admin Plus 演示地址(vue3.x + element-plus 2.x 付费版本,支持 PC、平板、手机)](https://vuejs-core.cn/admin-plus/)
|
||||||
|
|
||||||
|
- [🚀 Vue Shop Vite 演示地址(vue3.x + vite 5.x + element-plus 2.x 付费版本,支持 PC、平板、手机)](https://vuejs-core.cn/shop-vite/)
|
||||||
|
|
||||||
|
- [📌 Vue Admin Pro 及 Vue Admin Plus 购买地址](https://vuejs-core.cn/authorization/)
|
||||||
|
|
||||||
|
- [📌 Vue Shop Vite 购买地址](https://vuejs-core.cn/authorization/shop-vite.html)
|
||||||
|
|
||||||
|
<!-- ## 🔊 温馨提示
|
||||||
|
|
||||||
|
近期,我们发现少数不法互联网用户通过 IDC 云服务器、代理 ip、本地计算机等方式对我们的演示地址,发起了大规模攻击,包括但不限于 DDOS 攻击、SQL 注入、大文件上传、端口扫描、目录扫描等方式,我们已第一时间通过技术手段追踪到其攻击服务器部署的网站内容,并由此推断出其所入职公司或相关联的公司,望其迷途知返,切勿再做损人不利己的事情。我们不清楚其这样做的原因,也不愿意通过以牙还牙,以眼还眼的方式,将事态扩大,为保障正常用户的访问演示地址的体验,提升访问速度,目前,演示地址已采取以下防范措施:
|
||||||
|
|
||||||
|
- 1、演示地址服务器已购买 DDOS 高防包,有效防止了大多数恶意攻击。
|
||||||
|
- 2、演示地址服务器已禁止.git、.svn、.env、.php 等后缀文件访问,单个 ip 累计访问以上文件超过 20 次,将被永久封禁,并无法再次打开演示地址。
|
||||||
|
- 3、演示地址每晚 3 点进行备份恢复、重启服务器操作,预计将有 2 到 3 分钟访问超时。
|
||||||
|
- 4、演示地址已加入恶意 ip 共享计划,对于存在恶意扫描服务器端口、服务器文件的问题 ip,我们将立即封禁,并同步至云服务器厂商恶意 ip 名单。
|
||||||
|
|
||||||
|
以上措施真实有效,正常用户切勿因好奇前去尝试 DDOS 高防包的准确性,采取以上措施,实属迫不得已,地球这么大,容得下每一个前端框架,希望大家在各自的人生里各自发光,把余下的时间多用来陪陪家人孩子。(温馨提示:如果您发现自己的 ip 被误封,可联系微信客服申请解除)。 -->
|
||||||
|
|
||||||
|
## 🌐 免费版演示地址
|
||||||
|
|
||||||
|
- [🎉 Vue Admin Better (vue2.x + element-ui 免费商用,支持 PC、平板、手机)](https://vuejs-core.cn/vue-admin-better)
|
||||||
|
|
||||||
|
<!-- - [⚡️ vue3.x + element-plus(alpha 版本,免费商用,支持 PC、平板、手机)](https://vuejs-core.cn/vue-admin-better-plus/) -->
|
||||||
|
|
||||||
|
<!-- - [⚡️ Vue Admin Ant (vue3.x + ant-design-vue 免费商用,支持 PC、平板、手机)](https://vuejs-core.cn/vue-admin-better-antdv/) -->
|
||||||
|
|
||||||
|
- [⚡️ Vue Admin Arco (vue3.x + vite5.x + arco2.x 免费商用,支持 PC)](https://vuejs-core.cn/vue-admin-arco/)
|
||||||
|
|
||||||
|
## 🌐 仓库地址
|
||||||
|
|
||||||
|
- [🌐 vue2.x github 仓库地址](https://github.com/zxwk1998/vue-admin-better/)
|
||||||
|
|
||||||
|
- [🌐 vue3.x github 仓库地址](https://github.com/zxwk1998/vue-admin-arco/)
|
||||||
|
|
||||||
|
- [🌐 vue2.x 码云仓库地址](https://gitee.com/chu1204505056/vue-admin-better/)
|
||||||
|
|
||||||
|
- [🌐 vue3.x 码云仓库地址](https://gitee.com/chu1204505056/vue-admin-arco/)
|
||||||
|
|
||||||
|
## 🍻 前端讨论 QQ 群
|
||||||
|
|
||||||
|
- 请我们喝杯咖啡,打赏后联系 QQ 783963206 邀请您进入讨论群(由于用户数较多,如果您打赏后未通过好友请求,可以尝试多加几次),不管您请还是不请,您都可以享受到开源的代码,感谢您的支持和信任,群内提供
|
||||||
|
vue-admin-better 基础版本、开发工具自动配置教程及项目开发文档。
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<img width="200px" src="https://gcore.jsdelivr.net/gh/zxwk1998/image/zfb_kf.jpg">
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<img width="200px" src="https://gcore.jsdelivr.net/gh/zxwk1998/image/qq_group/vab-2.jpg">
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<img width="200px" src="https://gcore.jsdelivr.net/gh/zxwk1998/image/qq_group/vab-3.jpg">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
## 📦️ 桌面应用程序
|
||||||
|
|
||||||
|
- [Admin Pro](https://gitee.com/chu1204505056/microsoft-store/raw/master/AdminPlus.zip)
|
||||||
|
- [Admin Plus](https://gitee.com/chu1204505056/microsoft-store/raw/master/AdminPlus.zip)
|
||||||
|
|
||||||
|
<!-- ## 🌱 vue3.x vue3.0-antdv 分支(ant-design-vue)[点击切换分支](https://github.com/zxwk1998/vue-admin-better/tree/vue3.0-antdv)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 克隆项目
|
||||||
|
git clone -b vue3.0-antdv https://github.com/zxwk1998/vue-admin-better.git
|
||||||
|
# 安装依赖
|
||||||
|
npm i --registry=http://mirrors.cloud.tencent.com/npm/
|
||||||
|
# 本地开发 启动项目
|
||||||
|
npm run serve
|
||||||
|
``` -->
|
||||||
|
|
||||||
|
## 🌱 vue3.x arco-design [点击切换仓库](https://github.com/zxwk1998/vue-admin-arco)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 克隆项目
|
||||||
|
git clonehttps://github.com/zxwk1998/vue-admin-arco.git
|
||||||
|
# 安装依赖
|
||||||
|
npm i --registry=http://mirrors.cloud.tencent.com/npm/
|
||||||
|
# 本地开发 启动项目
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🌱vue2.x master 分支(element-ui)[点击切换分支](https://github.com/zxwk1998/vue-admin-better/tree/master)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 克隆项目
|
||||||
|
git clone -b master https://github.com/zxwk1998/vue-admin-better.git
|
||||||
|
# 安装依赖
|
||||||
|
npm i --registry=http://mirrors.cloud.tencent.com/npm/
|
||||||
|
# 本地开发 启动项目
|
||||||
|
npm run serve
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔊 友情链接
|
||||||
|
|
||||||
|
- [OPSLI 基于 vue-admin-better 开源版的最佳实践](https://github.com/hiparker/opsli-boot)
|
||||||
|
|
||||||
|
- [uView uni-app 生态最优秀的 UI 框架](https://github.com/YanxinNet/uView/)
|
||||||
|
|
||||||
|
- [form-generator Element 表单设计代码生成器](https://github.com/JakHuang/form-generator/)
|
||||||
|
|
||||||
|
- [wangEditor 国产最强开源富文本编辑](https://github.com/wangeditor-team/wangEditor)
|
||||||
|
|
||||||
|
## 🙈 赞助
|
||||||
|
|
||||||
|
- 如果您觉得 vue admin better 帮到了您 ,如果情况允许,您可以选择赞助以下项目
|
||||||
|
|
||||||
|
<a title="vue" href="https://opencollective.com/vuejs" target="_blank">
|
||||||
|
<img width="64px" src="https://gcore.jsdelivr.net/gh/zxwk1998/image/vue.png"/>
|
||||||
|
</a>
|
||||||
|
<a title="element-plus" href="https://opencollective.com/element-plus" target="_blank">
|
||||||
|
<img width="64px" src="https://gcore.jsdelivr.net/gh/zxwk1998/image/element-plus.png"/>
|
||||||
|
</a>
|
||||||
|
<a title="ant-design-vue" href="https://opencollective.com/ant-design-vue" target="_blank">
|
||||||
|
<img width="64px" src="https://images.opencollective.com/ant-design-vue/2ec179b/logo/256.png"/>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
## 👷 框架杰出贡献者
|
||||||
|
|
||||||
|
<a href="https://github.com/fwfmiao" target="_blank">
|
||||||
|
<img width="50px" style="border-radius:999px" src="https://avatars.githubusercontent.com/u/29328241?s=50"/>
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/buuing" target="_blank">
|
||||||
|
<img width="50px" style="border-radius:999px" src="https://avatars.githubusercontent.com/u/36689704?s=50"/>
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/hipi" target="_blank">
|
||||||
|
<img width="50px" style="border-radius:999px" src="https://avatars.githubusercontent.com/u/22478003?s=50"/>
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/hdtopku" target="_blank">
|
||||||
|
<img width="50px" style="border-radius:999px" src="https://avatars.githubusercontent.com/u/14859466?s=50"/>
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/shaonialife" target="_blank">
|
||||||
|
<img width="50px" style="border-radius:999px" src="https://avatars.githubusercontent.com/u/16135960?s=50"/>
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/1511578084" target="_blank">
|
||||||
|
<img width="50px" style="border-radius:999px" src="https://avatars.githubusercontent.com/u/24790218?s=50"/>
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/Arooba-git" target="_blank">
|
||||||
|
<img width="50px" style="border-radius:999px" src="https://avatars.githubusercontent.com/u/56495631?s=50"/>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
## 📌 优势及注意事项
|
||||||
|
|
||||||
|
```
|
||||||
|
对比其他开源 admin 框架有如下优势:
|
||||||
|
1. 支持前端控制路由权限 intelligence、后端控制路由权限 all 模式
|
||||||
|
2. 已知开源 vue admin 框架中首家支持 mock 自动生成自动导出功能
|
||||||
|
3. 提供 50 余项全局精细化配置
|
||||||
|
4. 支持 scss 自动排序,eslint 自动修复
|
||||||
|
5. axios 精细化封装,支持多数据源、多成功 code 数组,支持 application/json;charset=UTF-8、application/x-www-form-urlencoded;charset=UTF-8 多种传参方式
|
||||||
|
6. 支持登录RSA加密
|
||||||
|
7. 支持打包自动生成7Z压缩包
|
||||||
|
8. 支持errorlog错误拦截
|
||||||
|
9. 支持多主题、多布局切换
|
||||||
|
|
||||||
|
使用注意事项:
|
||||||
|
1. 项目默认使用lf换行符而非crlf换行符,新建文件时请注意选择文件换行符
|
||||||
|
2. 项目默认使用的最严格的eslint校验规范(plugin:vue/recommended),使用之前建议配置开发工具实现自动修复(建议使用vscode开发)
|
||||||
|
3. 项目使用的是要求最宽泛的MIT开源协议,保留MIT开源协议即可免费商用
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## 💚 适合人群
|
||||||
|
|
||||||
|
- 正在以及想使用 element-ui/element-plus 开发,前端开发经验 1 年+。
|
||||||
|
- 熟悉 Vue.js 技术栈,使用它开发过几个实际项目。
|
||||||
|
- 对原理技术感兴趣,想进阶和提升的同学。
|
||||||
|
|
||||||
|
## 🎨 Star
|
||||||
|
|
||||||
|
[](https://github.com/zxwk1998/vue-admin-better/stargazers)
|
||||||
|
|
||||||
|
## ✨ Fork
|
||||||
|
|
||||||
|
[](https://github.com/zxwk1998/vue-admin-better/network/members)
|
||||||
|
|
||||||
|
## 🎉 功能地图
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 🗃️ 效果图
|
||||||
|
|
||||||
|
以下是截取的是 pro 版的效果图展示:
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<img src="https://gcore.jsdelivr.net/gh/zxwk1998/image/2.png">
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<img src="https://gcore.jsdelivr.net/gh/zxwk1998/image/6.png">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<img src="https://gcore.jsdelivr.net/gh/zxwk1998/image/8.png">
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<img src="https://gcore.jsdelivr.net/gh/zxwk1998/image/9.png">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<img src="https://gcore.jsdelivr.net/gh/zxwk1998/image/3.png">
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<img src="https://gcore.jsdelivr.net/gh/zxwk1998/image/5.png">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
以下是截取的是 shop 版的效果图展示:
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<img src="https://gcore.jsdelivr.net/gh/zxwk1998/image/16.png">
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<img src="https://gcore.jsdelivr.net/gh/zxwk1998/image/17.png">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<img src="https://gcore.jsdelivr.net/gh/zxwk1998/image/18.png">
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<img src="https://gcore.jsdelivr.net/gh/zxwk1998/image/19.png">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<img src="https://gcore.jsdelivr.net/gh/zxwk1998/image/20.png">
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<img src="https://gcore.jsdelivr.net/gh/zxwk1998/image/21.png">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
## 📄 商用注意事项
|
||||||
|
|
||||||
|
开源版本可免费用于商业用途,如果方便就留个 Star 吧
|
||||||
|
|
||||||
|
<!-- ,请遵守 MIT 协议并保留作者技术支持声明,当然如果不愿意保留可以删掉,毕竟我也拿您没办法,能帮到您也当是给自己积德了,至于[Admin](https://vuejs-core.cn/admin-plus/)、[Shop](https://vuejs-core.cn/shop-vite/) 的付费版本的相关说明如下:
|
||||||
|
本人只参与了前期小部分的开发,所以不必跟开源版做对比,同事的代码功底比我好太多,我自愧不如,关于买这件事,没有强买强卖,您愿意买就买,不愿意买就忽略。我们不高尚,写代码就是为了养家糊口,不是为了用爱发电。这几年看到那么多开源项目借鉴了我们付费版本的布局、主题配置的灵感和创意,一开始我是鄙视的,现在还好状态调整过来了,能够被借鉴,被讨论恰好说明了我们的产品有价值,为了产品卖的更好我们也必须更加用心的去维护付费版本以保持我们产品的竞争力。
|
||||||
|
当然,最后还有几句话不得不说,身处互联网由盛转衰的大变革的洪流中,能活下来就已经是千难万难了,希望所有的程序员哥哥姐姐们,早日实现自己的梦想,完成自己的心愿,也想对刚要毕业准备做一名程序员的学弟学妹们说几句,互联网行业没有你们想象的那么高大上,如果想成为一名程序员那就做好加班的准备,如果有更好的选择那就别选这个行业了。 -->
|
||||||
|
|
||||||
|
</div>
|
||||||
7
babel.config.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
/**
|
||||||
|
* @author https://github.com/zxwk1998/vue-admin-better (不想保留author可删除)
|
||||||
|
* @description babel.config
|
||||||
|
*/
|
||||||
|
module.exports = {
|
||||||
|
presets: ['@vue/cli-plugin-babel/preset'],
|
||||||
|
}
|
||||||
20
deploy.sh
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#强制推送
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -e
|
||||||
|
npm run build
|
||||||
|
cd dist
|
||||||
|
touch .nojekyll
|
||||||
|
git init
|
||||||
|
git add -A
|
||||||
|
git commit -m 'deploy'
|
||||||
|
git push -f "https://${access_token}@gitee.com/chu1204505056/vue-admin-better.git" master:gh-pages
|
||||||
|
git push -f "https://${access_token}@gitee.com/chu1204505056/vue-admin-better-element.git" master:gh-pages
|
||||||
|
start "https://gitee.com/chu1204505056/vue-admin-better/pages"
|
||||||
|
start "https://gitee.com/chu1204505056/vue-admin-better-element/pages"
|
||||||
|
git push -f "https://${access_token}@github.com/zxwk1998/vue-admin-better.git" master:gh-pages
|
||||||
|
cd -
|
||||||
|
exec /bin/bash
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
13
layouts/Permissions/index.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import permissions from './permissions'
|
||||||
|
|
||||||
|
const install = function (Vue) {
|
||||||
|
Vue.directive('permissions', permissions)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window.Vue) {
|
||||||
|
window['permissions'] = permissions
|
||||||
|
Vue.use(install)
|
||||||
|
}
|
||||||
|
|
||||||
|
permissions.install = install
|
||||||
|
export default permissions
|
||||||
13
layouts/Permissions/permissions.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import store from '@/store'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
inserted(element, binding) {
|
||||||
|
const { value } = binding
|
||||||
|
const permissions = store.getters['user/permissions']
|
||||||
|
if (value && value instanceof Array && value.length > 0) {
|
||||||
|
const hasPermission = permissions.some((role) => value.includes(role))
|
||||||
|
if (!hasPermission)
|
||||||
|
element.parentNode && element.parentNode.removeChild(element)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
65
layouts/VabColorfullIcon/index.vue
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
<template>
|
||||||
|
<!-- <img
|
||||||
|
v-if="isExternal"
|
||||||
|
:src="styleExternalIcon"
|
||||||
|
class="svg-external-icon svg-icon"
|
||||||
|
v-on="$listeners"
|
||||||
|
/> -->
|
||||||
|
<!-- <svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners">
|
||||||
|
<use :xlink:href="iconName" />
|
||||||
|
</svg> -->
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { isExternal } from '@/utils/validate'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'VabColorfulIcon',
|
||||||
|
props: {
|
||||||
|
iconClass: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
className: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
isExternal() {
|
||||||
|
return isExternal(this.iconClass)
|
||||||
|
},
|
||||||
|
iconName() {
|
||||||
|
return `#colorful-icon-${this.iconClass}`
|
||||||
|
},
|
||||||
|
svgClass() {
|
||||||
|
if (this.className) {
|
||||||
|
return 'svg-icon ' + this.className
|
||||||
|
} else {
|
||||||
|
return 'svg-icon'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
styleExternalIcon() {
|
||||||
|
return this.iconClass
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.svg-icon {
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
overflow: hidden;
|
||||||
|
vertical-align: -0.15em;
|
||||||
|
fill: currentColor;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.svg-external-icon {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
128
layouts/VabErrorLog/index.vue
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
<template>
|
||||||
|
<div v-if="errorLogs.length > 0">
|
||||||
|
<el-badge
|
||||||
|
:value="errorLogs.length"
|
||||||
|
@click.native="dialogTableVisible = true"
|
||||||
|
>
|
||||||
|
<el-button type="danger">
|
||||||
|
<vab-icon :icon="['fas', 'bug']" />
|
||||||
|
</el-button>
|
||||||
|
</el-badge>
|
||||||
|
|
||||||
|
<el-dialog
|
||||||
|
:visible.sync="dialogTableVisible"
|
||||||
|
append-to-body
|
||||||
|
title="vue-admin-better异常捕获(温馨提示:错误必须解决)"
|
||||||
|
width="70%"
|
||||||
|
>
|
||||||
|
<el-table :data="errorLogs">
|
||||||
|
<el-table-column label="报错路由">
|
||||||
|
<template slot-scope="{ row }">
|
||||||
|
<a :href="row.url" target="_blank">
|
||||||
|
<el-tag type="success">{{ row.url }}</el-tag>
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="错误信息">
|
||||||
|
<template slot-scope="{ row }">
|
||||||
|
<el-tag type="danger">{{ decodeUnicode(row.err.message) }}</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="错误详情" width="120">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-popover placement="top-start" trigger="hover">
|
||||||
|
<div style="color: red">
|
||||||
|
{{ scope.row.err.stack }}
|
||||||
|
</div>
|
||||||
|
<el-button slot="reference">查看</el-button>
|
||||||
|
</el-popover>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="操作" width="380">
|
||||||
|
<template slot-scope="{ row }">
|
||||||
|
<a
|
||||||
|
v-for="(item, index) in searchList"
|
||||||
|
:key="index"
|
||||||
|
:href="item.url + decodeUnicode(row.err.message)"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<el-button style="margin-left: 5px" type="primary">
|
||||||
|
<vab-icon :icon="['fas', 'search']" />
|
||||||
|
{{ item.title }}
|
||||||
|
</el-button>
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<span slot="footer" class="dialog-footer">
|
||||||
|
<el-button @click="dialogTableVisible = false">取 消</el-button>
|
||||||
|
<el-button icon="el-icon-delete" type="danger" @click="clearAll">
|
||||||
|
暂不显示
|
||||||
|
</el-button>
|
||||||
|
</span>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { abbreviation, title } from '@/config'
|
||||||
|
import { mapGetters } from 'vuex'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'VabErrorLog',
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
dialogTableVisible: false,
|
||||||
|
title: title,
|
||||||
|
abbreviation: abbreviation,
|
||||||
|
searchList: [
|
||||||
|
{
|
||||||
|
title: '百度搜索',
|
||||||
|
url: 'https://www.baidu.com/baidu?wd=',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '谷歌搜索',
|
||||||
|
url: 'https://www.google.com/search?q=',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Magi搜索',
|
||||||
|
url: 'https://magi.com/search?q=',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
...mapGetters({
|
||||||
|
errorLogs: 'errorLog/errorLogs',
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
clearAll() {
|
||||||
|
this.dialogTableVisible = false
|
||||||
|
this.$store.dispatch('errorLog/clearErrorLog')
|
||||||
|
},
|
||||||
|
decodeUnicode(str) {
|
||||||
|
str = str.replace(/\\/g, '%')
|
||||||
|
str = unescape(str)
|
||||||
|
str = str.replace(/%/g, '\\')
|
||||||
|
str = str.replace(/\\/g, '')
|
||||||
|
return str
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
::v-deep {
|
||||||
|
.el-badge {
|
||||||
|
.el-button {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-items: center;
|
||||||
|
height: 28px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
53
layouts/VabFullScreenBar/index.vue
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
<template>
|
||||||
|
<span :title="isFullscreen ? '退出全屏' : '进入全屏'">
|
||||||
|
<vab-icon
|
||||||
|
:icon="[
|
||||||
|
'fas',
|
||||||
|
isFullscreen ? 'compress-arrows-alt' : 'expand-arrows-alt',
|
||||||
|
]"
|
||||||
|
@click="click"
|
||||||
|
></vab-icon>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import screenfull from 'screenfull'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'VabFullScreenBar',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
isFullscreen: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.init()
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
this.destroy()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
click() {
|
||||||
|
if (!screenfull.isEnabled) {
|
||||||
|
this.$baseMessage('开启全屏失败', 'error')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
screenfull.toggle()
|
||||||
|
this.$emit('refresh')
|
||||||
|
},
|
||||||
|
change() {
|
||||||
|
this.isFullscreen = screenfull.isFullscreen
|
||||||
|
},
|
||||||
|
init() {
|
||||||
|
if (screenfull.isEnabled) {
|
||||||
|
screenfull.on('change', this.change)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
destroy() {
|
||||||
|
if (screenfull.isEnabled) {
|
||||||
|
screenfull.off('change', this.change)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
75
layouts/VabGithubCorner/index.vue
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
<template>
|
||||||
|
<a
|
||||||
|
aria-label="View source on Github"
|
||||||
|
class="github-corner"
|
||||||
|
href="https://github.com/vue-admin-better"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
class="github-color"
|
||||||
|
height="80"
|
||||||
|
viewBox="0 0 250 250"
|
||||||
|
width="80"
|
||||||
|
>
|
||||||
|
<path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z" />
|
||||||
|
<path
|
||||||
|
class="octo-arm"
|
||||||
|
d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2"
|
||||||
|
fill="currentColor"
|
||||||
|
style="transform-origin: 130px 106px"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
class="octo-body"
|
||||||
|
d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'VabGithubCorner',
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.github-corner {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: $base-z-index - 3;
|
||||||
|
|
||||||
|
.octo-arm {
|
||||||
|
animation: octocat-wave 560ms ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.octo-arm {
|
||||||
|
animation: octocat-wave 560ms ease-in-out infinite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.github-color {
|
||||||
|
color: #fff;
|
||||||
|
fill: $base-color-blue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes octocat-wave {
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
transform: rotate(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
20%,
|
||||||
|
60% {
|
||||||
|
transform: rotate(-25deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
40%,
|
||||||
|
80% {
|
||||||
|
transform: rotate(100deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
20
layouts/VabQueryForm/VabQueryFormBottomPanel.vue
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<template>
|
||||||
|
<el-col :span="24">
|
||||||
|
<div class="bottom-panel">
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'VabQueryFormBottomPanel',
|
||||||
|
props: {},
|
||||||
|
data() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
created() {},
|
||||||
|
mounted() {},
|
||||||
|
methods: {},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
25
layouts/VabQueryForm/VabQueryFormLeftPanel.vue
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<template>
|
||||||
|
<el-col :lg="span" :md="24" :sm="24" :xl="span" :xs="24">
|
||||||
|
<div class="left-panel">
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'VabQueryFormLeftPanel',
|
||||||
|
props: {
|
||||||
|
span: {
|
||||||
|
type: Number,
|
||||||
|
default: 14,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
created() {},
|
||||||
|
mounted() {},
|
||||||
|
methods: {},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
25
layouts/VabQueryForm/VabQueryFormRightPanel.vue
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<template>
|
||||||
|
<el-col :lg="span" :md="24" :sm="24" :xl="span" :xs="24">
|
||||||
|
<div class="right-panel">
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'VabQueryFormRightPanel',
|
||||||
|
props: {
|
||||||
|
span: {
|
||||||
|
type: Number,
|
||||||
|
default: 10,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
created() {},
|
||||||
|
mounted() {},
|
||||||
|
methods: {},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
20
layouts/VabQueryForm/VabQueryFormTopPanel.vue
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<template>
|
||||||
|
<el-col :span="24">
|
||||||
|
<div class="top-panel">
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'VabQueryFormTopPanel',
|
||||||
|
props: {},
|
||||||
|
data() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
created() {},
|
||||||
|
mounted() {},
|
||||||
|
methods: {},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
63
layouts/VabQueryForm/index.vue
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
<template>
|
||||||
|
<el-row :gutter="0" class="vab-query-form">
|
||||||
|
<slot></slot>
|
||||||
|
</el-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'VabQueryForm',
|
||||||
|
props: {},
|
||||||
|
data() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
created() {},
|
||||||
|
mounted() {},
|
||||||
|
methods: {},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@mixin panel {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vab-query-form {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
|
||||||
|
::v-deep {
|
||||||
|
.top-panel {
|
||||||
|
@include panel;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom-panel {
|
||||||
|
@include panel;
|
||||||
|
|
||||||
|
padding-top: 14px;
|
||||||
|
border-top: 1px solid #dcdfe6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.left-panel {
|
||||||
|
@include panel;
|
||||||
|
|
||||||
|
> .el-button,
|
||||||
|
.el-form-item {
|
||||||
|
margin: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-panel {
|
||||||
|
@include panel;
|
||||||
|
|
||||||
|
justify-content: flex-end;
|
||||||
|
|
||||||
|
.el-form-item {
|
||||||
|
margin: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
80
layouts/VabRemixIcon/index.vue
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
v-if="isExternal"
|
||||||
|
:style="styleExternalIcon"
|
||||||
|
class="svg-external-icon image-icon"
|
||||||
|
v-on="$listeners"
|
||||||
|
/>
|
||||||
|
<svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners">
|
||||||
|
<use :xlink:href="iconName" />
|
||||||
|
</svg>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { isExternal } from '@/utils/validate'
|
||||||
|
export default {
|
||||||
|
name: 'VabRemixIcon',
|
||||||
|
props: {
|
||||||
|
iconClass: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
className: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
isExternal() {
|
||||||
|
return isExternal(this.iconClass)
|
||||||
|
},
|
||||||
|
iconName() {
|
||||||
|
return `#remix-icon-${this.iconClass}`
|
||||||
|
},
|
||||||
|
svgClass() {
|
||||||
|
if (this.className) {
|
||||||
|
return 'svg-icon ' + this.className
|
||||||
|
} else {
|
||||||
|
return 'svg-icon'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
styleExternalIcon() {
|
||||||
|
return {
|
||||||
|
backgroundImage: `url(${this.iconClass})`,
|
||||||
|
backgroundSize: 'cover',
|
||||||
|
backgroundPosition: 'center',
|
||||||
|
width: '50px', // 控制大小
|
||||||
|
height: '50px',
|
||||||
|
borderRadius: '50%', // 变成圆形
|
||||||
|
overflow: 'hidden',
|
||||||
|
display: 'inline-block',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.svg-icon {
|
||||||
|
width: 1.125em;
|
||||||
|
height: 1.125em;
|
||||||
|
overflow: hidden;
|
||||||
|
fill: currentColor;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-icon {
|
||||||
|
display: inline-block;
|
||||||
|
background-size: cover !important;
|
||||||
|
background-position: center !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.svg-external-icon {
|
||||||
|
display: inline-block;
|
||||||
|
background-color: currentColor;
|
||||||
|
mask-size: cover !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
84
layouts/VabSideBar/components/VabMenuItem.vue
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
<template>
|
||||||
|
<el-menu-item :index="handlePath(routeChildren.path)" @click="handleLink">
|
||||||
|
<vab-icon
|
||||||
|
v-if="routeChildren.meta.icon"
|
||||||
|
:icon="['fas', routeChildren.meta.icon]"
|
||||||
|
class="vab-fas-icon"
|
||||||
|
/>
|
||||||
|
<span>{{ routeChildren.meta.title }}</span>
|
||||||
|
<el-tag
|
||||||
|
v-if="routeChildren.meta && routeChildren.meta.badge"
|
||||||
|
effect="dark"
|
||||||
|
type="danger"
|
||||||
|
>
|
||||||
|
{{ routeChildren.meta.badge }}
|
||||||
|
</el-tag>
|
||||||
|
</el-menu-item>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { isExternal } from '@/utils/validate'
|
||||||
|
import path from 'path'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'VabMenuItem',
|
||||||
|
props: {
|
||||||
|
routeChildren: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return null
|
||||||
|
},
|
||||||
|
},
|
||||||
|
item: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return null
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fullPath: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handlePath(routePath) {
|
||||||
|
if (isExternal(routePath)) {
|
||||||
|
return routePath
|
||||||
|
}
|
||||||
|
if (isExternal(this.fullPath)) {
|
||||||
|
return this.fullPath
|
||||||
|
}
|
||||||
|
return path.resolve(this.fullPath, routePath)
|
||||||
|
},
|
||||||
|
handleLink() {
|
||||||
|
const routePath = this.routeChildren.path
|
||||||
|
const target = this.routeChildren.meta.target
|
||||||
|
|
||||||
|
if (target === '_blank') {
|
||||||
|
if (isExternal(routePath)) {
|
||||||
|
window.open(routePath)
|
||||||
|
} else if (isExternal(this.fullPath)) {
|
||||||
|
window.open(this.fullPath)
|
||||||
|
} else if (
|
||||||
|
this.$route.path !== path.resolve(this.fullPath, routePath)
|
||||||
|
) {
|
||||||
|
let routeData = this.$router.resolve(
|
||||||
|
path.resolve(this.fullPath, routePath)
|
||||||
|
)
|
||||||
|
window.open(routeData.href)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (isExternal(routePath)) {
|
||||||
|
window.location.href = routePath
|
||||||
|
} else if (isExternal(this.fullPath)) {
|
||||||
|
window.location.href = this.fullPath
|
||||||
|
} else if (
|
||||||
|
this.$route.path !== path.resolve(this.fullPath, routePath)
|
||||||
|
) {
|
||||||
|
this.$router.push(path.resolve(this.fullPath, routePath))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
108
layouts/VabSideBar/components/VabSideBarItem.vue
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
<template>
|
||||||
|
<component
|
||||||
|
:is="menuComponent"
|
||||||
|
v-if="!item.hidden"
|
||||||
|
:full-path="fullPath"
|
||||||
|
:item="item"
|
||||||
|
:route-children="routeChildren"
|
||||||
|
>
|
||||||
|
<template v-if="item.children && item.children.length">
|
||||||
|
<vab-side-bar-item
|
||||||
|
v-for="route in item.children"
|
||||||
|
:key="route.path"
|
||||||
|
:full-path="handlePath(route.path)"
|
||||||
|
:item="route"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</component>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { isExternal } from '@/utils/validate'
|
||||||
|
import path from 'path'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'VabSideBarItem',
|
||||||
|
props: {
|
||||||
|
item: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
fullPath: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
this.onlyOneChild = null
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
menuComponent() {
|
||||||
|
if (
|
||||||
|
this.handleChildren(this.item.children, this.item) &&
|
||||||
|
(!this.routeChildren.children ||
|
||||||
|
this.routeChildren.notShowChildren) &&
|
||||||
|
!this.item.alwaysShow
|
||||||
|
) {
|
||||||
|
return 'VabMenuItem'
|
||||||
|
} else {
|
||||||
|
return 'VabSubmenu'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleChildren(children = [], parent) {
|
||||||
|
if (children === null) children = []
|
||||||
|
const showChildren = children.filter((item) => {
|
||||||
|
if (item.hidden) {
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
this.routeChildren = item
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (showChildren.length === 1) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showChildren.length === 0) {
|
||||||
|
this.routeChildren = {
|
||||||
|
...parent,
|
||||||
|
path: '',
|
||||||
|
notShowChildren: true,
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
handlePath(routePath) {
|
||||||
|
if (isExternal(routePath)) {
|
||||||
|
return routePath
|
||||||
|
}
|
||||||
|
if (isExternal(this.fullPath)) {
|
||||||
|
return this.fullPath
|
||||||
|
}
|
||||||
|
return path.resolve(this.fullPath, routePath)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.vab-nav-icon {
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep {
|
||||||
|
.el-tag {
|
||||||
|
float: right;
|
||||||
|
height: 16px;
|
||||||
|
padding-right: 4px;
|
||||||
|
padding-left: 4px;
|
||||||
|
margin-top: calc((#{$base-menu-item-height} - 16px) / 2);
|
||||||
|
line-height: 16px;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
60
layouts/VabSideBar/components/VabSubmenu.vue
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
<template>
|
||||||
|
<el-submenu
|
||||||
|
ref="subMenu"
|
||||||
|
:index="handlePath(item.path)"
|
||||||
|
:popper-append-to-body="false"
|
||||||
|
>
|
||||||
|
<template slot="title">
|
||||||
|
<vab-icon
|
||||||
|
v-if="item.meta && item.meta.icon"
|
||||||
|
:icon="['fas', item.meta.icon]"
|
||||||
|
class="vab-fas-icon"
|
||||||
|
/>
|
||||||
|
<vab-remix-icon
|
||||||
|
v-if="item.meta && item.meta.remixIcon"
|
||||||
|
:icon-class="item.meta.remixIcon"
|
||||||
|
class="vab-remix-icon"
|
||||||
|
/>
|
||||||
|
<span>{{ item.meta.title }}</span>
|
||||||
|
</template>
|
||||||
|
<slot />
|
||||||
|
</el-submenu>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { isExternal } from '@/utils/validate'
|
||||||
|
import path from 'path'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'VabSubmenu',
|
||||||
|
props: {
|
||||||
|
routeChildren: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return null
|
||||||
|
},
|
||||||
|
},
|
||||||
|
item: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return null
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fullPath: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handlePath(routePath) {
|
||||||
|
if (isExternal(routePath)) {
|
||||||
|
return routePath
|
||||||
|
}
|
||||||
|
if (isExternal(this.fullPath)) {
|
||||||
|
return this.fullPath
|
||||||
|
}
|
||||||
|
return path.resolve(this.fullPath, routePath)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
145
layouts/VabSideBar/index.vue
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
<template>
|
||||||
|
<el-scrollbar :class="{ 'is-collapse': collapse }" class="side-bar-container">
|
||||||
|
<vab-logo />
|
||||||
|
<el-menu
|
||||||
|
:active-text-color="variables['menu-color-active']"
|
||||||
|
:background-color="variables['menu-background']"
|
||||||
|
:collapse="collapse"
|
||||||
|
:collapse-transition="false"
|
||||||
|
:default-active="activeMenu"
|
||||||
|
:default-openeds="defaultOpens"
|
||||||
|
:text-color="variables['menu-color']"
|
||||||
|
:unique-opened="uniqueOpened"
|
||||||
|
mode="vertical"
|
||||||
|
>
|
||||||
|
<template v-for="route in routes">
|
||||||
|
<vab-side-bar-item
|
||||||
|
:key="route.path"
|
||||||
|
:full-path="route.path"
|
||||||
|
:item="route"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-menu>
|
||||||
|
</el-scrollbar>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import variables from '@/styles/variables.scss'
|
||||||
|
import { mapGetters } from 'vuex'
|
||||||
|
import { defaultOopeneds, uniqueOpened } from '@/config'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'VabSideBar',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
uniqueOpened,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapGetters({
|
||||||
|
collapse: 'settings/collapse',
|
||||||
|
routes: 'routes/routes',
|
||||||
|
}),
|
||||||
|
defaultOpens() {
|
||||||
|
if (this.collapse) {
|
||||||
|
}
|
||||||
|
return defaultOopeneds
|
||||||
|
},
|
||||||
|
activeMenu() {
|
||||||
|
const route = this.$route
|
||||||
|
const { meta, path } = route
|
||||||
|
if (meta.activeMenu) {
|
||||||
|
return meta.activeMenu
|
||||||
|
}
|
||||||
|
return path
|
||||||
|
},
|
||||||
|
variables() {
|
||||||
|
return variables
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@mixin active {
|
||||||
|
&:hover {
|
||||||
|
color: $base-color-white;
|
||||||
|
background-color: $base-menu-background-active !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-active {
|
||||||
|
color: $base-color-white;
|
||||||
|
background-color: $base-menu-background-active !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.side-bar-container {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: $base-z-index;
|
||||||
|
width: $base-left-menu-width;
|
||||||
|
height: 100vh;
|
||||||
|
overflow: hidden;
|
||||||
|
background: $base-menu-background;
|
||||||
|
box-shadow: 2px 0 6px rgba(0, 21, 41, 0.35);
|
||||||
|
transition: width $base-transition-time;
|
||||||
|
|
||||||
|
&.is-collapse {
|
||||||
|
width: $base-left-menu-width-min;
|
||||||
|
border-right: 0;
|
||||||
|
|
||||||
|
::v-deep {
|
||||||
|
.el-menu {
|
||||||
|
transition: width $base-transition-time;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-menu--collapse {
|
||||||
|
border-right: 0;
|
||||||
|
|
||||||
|
.el-submenu__icon-arrow {
|
||||||
|
right: 10px;
|
||||||
|
margin-top: -3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-menu-item,
|
||||||
|
.el-submenu {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep {
|
||||||
|
.el-scrollbar__wrap {
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-menu {
|
||||||
|
border: 0;
|
||||||
|
|
||||||
|
.vab-fas-icon {
|
||||||
|
padding-right: 3px;
|
||||||
|
font-size: $base-font-size-default;
|
||||||
|
display: inline-block;
|
||||||
|
width: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vab-remix-icon {
|
||||||
|
padding-right: 3px;
|
||||||
|
font-size: $base-font-size-default + 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-menu-item,
|
||||||
|
.el-submenu__title {
|
||||||
|
height: $base-menu-item-height;
|
||||||
|
line-height: $base-menu-item-height;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-menu-item {
|
||||||
|
@include active;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
293
layouts/VabTabsBar/index.vue
Normal file
@@ -0,0 +1,293 @@
|
|||||||
|
<template>
|
||||||
|
<div id="tabs-bar-container" class="tabs-bar-container">
|
||||||
|
<el-tabs
|
||||||
|
v-model="tabActive"
|
||||||
|
class="tabs-content"
|
||||||
|
type="card"
|
||||||
|
@tab-click="handleTabClick"
|
||||||
|
@tab-remove="handleTabRemove"
|
||||||
|
>
|
||||||
|
<el-tab-pane
|
||||||
|
v-for="item in visitedRoutes"
|
||||||
|
:key="item.path"
|
||||||
|
:closable="!isAffix(item)"
|
||||||
|
:label="item.meta.title"
|
||||||
|
:name="item.path"
|
||||||
|
></el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
|
||||||
|
<el-dropdown @command="handleCommand">
|
||||||
|
<span style="cursor: pointer">
|
||||||
|
更多操作
|
||||||
|
<i class="el-icon-arrow-down el-icon--right"></i>
|
||||||
|
</span>
|
||||||
|
<el-dropdown-menu slot="dropdown" class="tabs-more">
|
||||||
|
<el-dropdown-item command="closeOtherstabs">
|
||||||
|
<vab-icon :icon="['fas', 'times-circle']" />
|
||||||
|
关闭其他
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item command="closeLefttabs">
|
||||||
|
<vab-icon :icon="['fas', 'arrow-alt-circle-left']"></vab-icon>
|
||||||
|
关闭左侧
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item command="closeRighttabs">
|
||||||
|
<vab-icon :icon="['fas', 'arrow-alt-circle-right']"></vab-icon>
|
||||||
|
关闭右侧
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item command="closeAlltabs">
|
||||||
|
<vab-icon :icon="['fas', 'ban']"></vab-icon>
|
||||||
|
关闭全部
|
||||||
|
</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</el-dropdown>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import path from 'path'
|
||||||
|
import { mapGetters } from 'vuex'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'VabTabsBar',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
affixtabs: [],
|
||||||
|
tabActive: '',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
...mapGetters({
|
||||||
|
visitedRoutes: 'tabsBar/visitedRoutes',
|
||||||
|
routes: 'routes/routes',
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
$route: {
|
||||||
|
handler(route) {
|
||||||
|
this.inittabs()
|
||||||
|
this.addtabs()
|
||||||
|
let tabActive = ''
|
||||||
|
this.visitedRoutes.forEach((item, index) => {
|
||||||
|
if (item.path === this.$route.path) {
|
||||||
|
tabActive = item.path
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.tabActive = tabActive
|
||||||
|
},
|
||||||
|
immediate: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
//console.log(this.visitedRoutes);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async handleTabRemove(tabActive) {
|
||||||
|
let view
|
||||||
|
this.visitedRoutes.forEach((item, index) => {
|
||||||
|
if (tabActive == item.path) {
|
||||||
|
view = item
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const { visitedRoutes } = await this.$store.dispatch(
|
||||||
|
'tabsBar/delRoute',
|
||||||
|
view
|
||||||
|
)
|
||||||
|
if (this.isActive(view)) {
|
||||||
|
this.toLastTag(visitedRoutes, view)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleTabClick(tab) {
|
||||||
|
const route = this.visitedRoutes.filter((item, index) => {
|
||||||
|
if (tab.index == index) return item
|
||||||
|
})[0]
|
||||||
|
if (this.$route.path !== route.path) {
|
||||||
|
this.$router.push({
|
||||||
|
path: route.path,
|
||||||
|
query: route.query,
|
||||||
|
fullPath: route.fullPath,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
isActive(route) {
|
||||||
|
return route.path === this.$route.path
|
||||||
|
},
|
||||||
|
isAffix(tag) {
|
||||||
|
return tag.meta && tag.meta.affix
|
||||||
|
},
|
||||||
|
filterAffixtabs(routes, basePath = '/') {
|
||||||
|
let tabs = []
|
||||||
|
routes.forEach((route) => {
|
||||||
|
if (route.meta && route.meta.affix) {
|
||||||
|
const tagPath = path.resolve(basePath, route.path)
|
||||||
|
tabs.push({
|
||||||
|
fullPath: tagPath,
|
||||||
|
path: tagPath,
|
||||||
|
name: route.name,
|
||||||
|
meta: { ...route.meta },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (route.children) {
|
||||||
|
const temptabs = this.filterAffixtabs(route.children, route.path)
|
||||||
|
if (temptabs.length >= 1) {
|
||||||
|
tabs = [...tabs, ...temptabs]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return tabs
|
||||||
|
},
|
||||||
|
inittabs() {
|
||||||
|
const affixtabs = (this.affixtabs = this.filterAffixtabs(this.routes))
|
||||||
|
for (const tag of affixtabs) {
|
||||||
|
if (tag.name) {
|
||||||
|
this.$store.dispatch('tabsBar/addVisitedRoute', tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
addtabs() {
|
||||||
|
const { name } = this.$route
|
||||||
|
if (name) {
|
||||||
|
this.$store.dispatch('tabsBar/addVisitedRoute', this.$route)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
handleCommand(command) {
|
||||||
|
switch (command) {
|
||||||
|
case 'refreshRoute':
|
||||||
|
this.refreshRoute()
|
||||||
|
break
|
||||||
|
case 'closeOtherstabs':
|
||||||
|
this.closeOtherstabs()
|
||||||
|
break
|
||||||
|
case 'closeLefttabs':
|
||||||
|
this.closeLefttabs()
|
||||||
|
break
|
||||||
|
case 'closeRighttabs':
|
||||||
|
this.closeRighttabs()
|
||||||
|
break
|
||||||
|
case 'closeAlltabs':
|
||||||
|
this.closeAlltabs()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async refreshRoute() {
|
||||||
|
this.$baseEventBus.$emit('reloadrouter-view')
|
||||||
|
},
|
||||||
|
async closeSelectedTag(view) {
|
||||||
|
const { visitedRoutes } = await this.$store.dispatch(
|
||||||
|
'tabsBar/delRoute',
|
||||||
|
view
|
||||||
|
)
|
||||||
|
if (this.isActive(view)) {
|
||||||
|
this.toLastTag(visitedRoutes, view)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async closeOtherstabs() {
|
||||||
|
const view = await this.toThisTag()
|
||||||
|
await this.$store.dispatch('tabsBar/delOthersRoutes', view)
|
||||||
|
},
|
||||||
|
async closeLefttabs() {
|
||||||
|
const view = await this.toThisTag()
|
||||||
|
await this.$store.dispatch('tabsBar/delLeftRoutes', view)
|
||||||
|
},
|
||||||
|
async closeRighttabs() {
|
||||||
|
const view = await this.toThisTag()
|
||||||
|
await this.$store.dispatch('tabsBar/delRightRoutes', view)
|
||||||
|
},
|
||||||
|
async closeAlltabs() {
|
||||||
|
const view = await this.toThisTag()
|
||||||
|
const { visitedRoutes } = await this.$store.dispatch(
|
||||||
|
'tabsBar/delAllRoutes'
|
||||||
|
)
|
||||||
|
if (this.affixtabs.some((tag) => tag.path === view.path)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.toLastTag(visitedRoutes, view)
|
||||||
|
},
|
||||||
|
toLastTag(visitedRoutes, view) {
|
||||||
|
const latestView = visitedRoutes.slice(-1)[0]
|
||||||
|
if (latestView) {
|
||||||
|
this.$router.push(latestView)
|
||||||
|
} else {
|
||||||
|
this.$router.push('/')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async toThisTag() {
|
||||||
|
const view = this.visitedRoutes.filter((item, index) => {
|
||||||
|
if (item.path === this.$route.fullPath) {
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
})[0]
|
||||||
|
if (this.$route.path !== view.path) this.$router.push(view)
|
||||||
|
return view
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.tabs-bar-container {
|
||||||
|
position: relative;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
align-content: center;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
height: $base-tabs-bar-height;
|
||||||
|
padding-right: $base-padding;
|
||||||
|
padding-left: $base-padding;
|
||||||
|
user-select: none;
|
||||||
|
background: $base-color-white;
|
||||||
|
border-top: 1px solid #f6f6f6;
|
||||||
|
|
||||||
|
::v-deep {
|
||||||
|
.fold-unfold {
|
||||||
|
margin-right: $base-padding;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs-content {
|
||||||
|
width: calc(100% - 90px);
|
||||||
|
height: $base-tag-item-height;
|
||||||
|
|
||||||
|
::v-deep {
|
||||||
|
.el-tabs__nav-next,
|
||||||
|
.el-tabs__nav-prev {
|
||||||
|
height: $base-tag-item-height;
|
||||||
|
line-height: $base-tag-item-height;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-tabs__header {
|
||||||
|
border-bottom: 0;
|
||||||
|
|
||||||
|
.el-tabs__nav {
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-tabs__item {
|
||||||
|
box-sizing: border-box;
|
||||||
|
height: $base-tag-item-height;
|
||||||
|
margin-right: 5px;
|
||||||
|
line-height: $base-tag-item-height;
|
||||||
|
border: 1px solid $base-border-color;
|
||||||
|
border-radius: $base-border-radius;
|
||||||
|
transition: padding 0.3s cubic-bezier(0.645, 0.045, 0.355, 1) !important;
|
||||||
|
|
||||||
|
&.is-active {
|
||||||
|
border: 1px solid $base-color-blue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.more {
|
||||||
|
display: flex;
|
||||||
|
align-content: center;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
228
layouts/VabTopBar/index.vue
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
<template>
|
||||||
|
<div class="top-bar-container">
|
||||||
|
<div class="vab-main">
|
||||||
|
<el-row>
|
||||||
|
<el-col :lg="7" :md="7" :sm="7" :xl="7" :xs="7">
|
||||||
|
<vab-logo />
|
||||||
|
</el-col>
|
||||||
|
<el-col :lg="12" :md="12" :sm="12" :xl="12" :xs="12">
|
||||||
|
<el-menu
|
||||||
|
:active-text-color="variables['menu-color-active']"
|
||||||
|
:background-color="variables['menu-background']"
|
||||||
|
:default-active="activeMenu"
|
||||||
|
:text-color="variables['menu-color']"
|
||||||
|
menu-trigger="hover"
|
||||||
|
mode="horizontal"
|
||||||
|
>
|
||||||
|
<template v-for="route in routes">
|
||||||
|
<vab-side-bar-item
|
||||||
|
v-if="!route.hidden"
|
||||||
|
:key="route.path"
|
||||||
|
:full-path="route.path"
|
||||||
|
:item="route"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-menu>
|
||||||
|
</el-col>
|
||||||
|
<el-col :lg="5" :md="5" :sm="5" :xl="5" :xs="5">
|
||||||
|
<div class="right-panel">
|
||||||
|
<vab-error-log />
|
||||||
|
<vab-full-screen-bar @refresh="refreshRoute" />
|
||||||
|
<vab-theme-bar class="hidden-md-and-down" />
|
||||||
|
<vab-icon
|
||||||
|
:icon="['fas', 'redo']"
|
||||||
|
:pulse="pulse"
|
||||||
|
title="重载路由"
|
||||||
|
@click="refreshRoute"
|
||||||
|
/>
|
||||||
|
<vab-avatar />
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import variables from '@/styles/variables.scss'
|
||||||
|
import { mapGetters } from 'vuex'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'VabTopBar',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
pulse: false,
|
||||||
|
menuTrigger: 'hover',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapGetters({
|
||||||
|
routes: 'routes/routes',
|
||||||
|
visitedRoutes: 'tabsBar/visitedRoutes',
|
||||||
|
}),
|
||||||
|
activeMenu() {
|
||||||
|
const route = this.$route
|
||||||
|
const { meta, path } = route
|
||||||
|
if (meta.activeMenu) {
|
||||||
|
return meta.activeMenu
|
||||||
|
}
|
||||||
|
return path
|
||||||
|
},
|
||||||
|
variables() {
|
||||||
|
return variables
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async refreshRoute() {
|
||||||
|
this.$baseEventBus.$emit('reload-router-view')
|
||||||
|
this.pulse = true
|
||||||
|
this.timeOutID = setTimeout(() => {
|
||||||
|
this.pulse = false
|
||||||
|
}, 1000)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
beforeDestroy() {
|
||||||
|
clearTimeout(this.timeOutID);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.top-bar-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-items: flex-end;
|
||||||
|
height: $base-top-bar-height;
|
||||||
|
background: $base-menu-background;
|
||||||
|
|
||||||
|
.vab-main {
|
||||||
|
background: $base-menu-background;
|
||||||
|
|
||||||
|
::v-deep {
|
||||||
|
.el-menu {
|
||||||
|
&.el-menu--horizontal {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
height: $base-top-bar-height;
|
||||||
|
border-bottom: 0 solid transparent !important;
|
||||||
|
|
||||||
|
.el-menu-item,
|
||||||
|
.el-submenu__title {
|
||||||
|
padding: 0 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 767px) {
|
||||||
|
.el-menu-item,
|
||||||
|
.el-submenu__title {
|
||||||
|
padding: 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
li:nth-child(4),
|
||||||
|
li:nth-child(5) {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> .el-menu-item {
|
||||||
|
height: $base-top-bar-height;
|
||||||
|
line-height: $base-top-bar-height;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .el-submenu {
|
||||||
|
.el-submenu__title {
|
||||||
|
height: $base-top-bar-height;
|
||||||
|
line-height: $base-top-bar-height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 1rem;
|
||||||
|
margin-right: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--horizontal {
|
||||||
|
.el-menu {
|
||||||
|
.el-menu-item,
|
||||||
|
.el-submenu__title {
|
||||||
|
height: $base-menu-item-height;
|
||||||
|
line-height: $base-menu-item-height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-submenu,
|
||||||
|
.el-menu-item {
|
||||||
|
&.is-active {
|
||||||
|
background-color: $base-color-blue !important;
|
||||||
|
border-bottom: 0 solid transparent !important;
|
||||||
|
|
||||||
|
.el-submenu__title {
|
||||||
|
border-bottom: 0 solid transparent !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> .el-menu-item {
|
||||||
|
.el-tag {
|
||||||
|
margin-top: calc(#{$base-top-bar-height} / 2 - 7.5px);
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 1199px) {
|
||||||
|
.el-tag {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-active {
|
||||||
|
background-color: transparent !important;
|
||||||
|
border-bottom: 3px solid $base-color-blue !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-panel {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
height: $base-top-bar-height;
|
||||||
|
|
||||||
|
::v-deep {
|
||||||
|
.user-name {
|
||||||
|
color: rgba($base-color-white, 0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-name + i {
|
||||||
|
color: rgba($base-color-white, 0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
margin-right: 15px;
|
||||||
|
font-size: $base-font-size-big;
|
||||||
|
color: rgba($base-color-white, 0.9);
|
||||||
|
cursor: pointer;
|
||||||
|
fill: rgba($base-color-white, 0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
svg {
|
||||||
|
margin-right: 0;
|
||||||
|
color: rgba($base-color-white, 0.9);
|
||||||
|
cursor: pointer;
|
||||||
|
fill: rgba($base-color-white, 0.9);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-badge {
|
||||||
|
margin-right: 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
9
layouts/index.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
module.exports = {
|
||||||
|
webpackBarName: '',
|
||||||
|
webpackBanner: '',
|
||||||
|
donationConsole() {
|
||||||
|
const chalk = require('chalk')
|
||||||
|
console.log(chalk.green('项目启动成功'))
|
||||||
|
console.log('\n')
|
||||||
|
},
|
||||||
|
}
|
||||||
5
layouts/package.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"name": "layouts",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "index.js"
|
||||||
|
}
|
||||||
16
layouts/prettier.config.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
module.exports = {
|
||||||
|
printWidth: 80,
|
||||||
|
tabWidth: 2,
|
||||||
|
useTabs: false,
|
||||||
|
semi: false,
|
||||||
|
singleQuote: true,
|
||||||
|
quoteProps: 'as-needed',
|
||||||
|
jsxSingleQuote: false,
|
||||||
|
trailingComma: 'es5',
|
||||||
|
bracketSpacing: true,
|
||||||
|
jsxBracketSameLine: false,
|
||||||
|
arrowParens: 'always',
|
||||||
|
htmlWhitespaceSensitivity: 'ignore',
|
||||||
|
vueIndentScriptAndStyle: true,
|
||||||
|
endOfLine: 'lf',
|
||||||
|
}
|
||||||
321
mock/controller/colorfulIcon.js
Normal file
@@ -0,0 +1,321 @@
|
|||||||
|
const data = [
|
||||||
|
'alphabetical_sorting',
|
||||||
|
'alphabetical_sorting',
|
||||||
|
'alarm_clock',
|
||||||
|
'area_chart',
|
||||||
|
'approval',
|
||||||
|
'answers',
|
||||||
|
'approve',
|
||||||
|
'assistant',
|
||||||
|
'automotive',
|
||||||
|
'automatic',
|
||||||
|
'bad_decision',
|
||||||
|
'bar_chart',
|
||||||
|
'bearish',
|
||||||
|
'biomass',
|
||||||
|
'biohazard',
|
||||||
|
'binoculars',
|
||||||
|
'bookmark',
|
||||||
|
'briefcase',
|
||||||
|
'biotech',
|
||||||
|
'broken_link',
|
||||||
|
'business',
|
||||||
|
'bullish',
|
||||||
|
'business_contact',
|
||||||
|
'businesswoman',
|
||||||
|
'cable_release',
|
||||||
|
'calculator',
|
||||||
|
'businessman',
|
||||||
|
'calendar',
|
||||||
|
'butting_in',
|
||||||
|
'call_transfer',
|
||||||
|
'callback',
|
||||||
|
'camcorder',
|
||||||
|
'camera',
|
||||||
|
'camcorder_pro',
|
||||||
|
'cancel',
|
||||||
|
'camera_addon',
|
||||||
|
'camera_identificatio',
|
||||||
|
'capacitor',
|
||||||
|
'candle_sticks',
|
||||||
|
'checkmark',
|
||||||
|
'circuit',
|
||||||
|
'charge_battery',
|
||||||
|
'clear_filters',
|
||||||
|
'clapperboard',
|
||||||
|
'clock',
|
||||||
|
'close_up_mode',
|
||||||
|
'collaboration',
|
||||||
|
'cell_phone',
|
||||||
|
'collapse',
|
||||||
|
'collect',
|
||||||
|
'cloth',
|
||||||
|
'combo_chart',
|
||||||
|
'comments',
|
||||||
|
'conference_call',
|
||||||
|
'compact_camera',
|
||||||
|
'contacts',
|
||||||
|
'copyleft',
|
||||||
|
'copyright',
|
||||||
|
'crystal_oscillator',
|
||||||
|
'cursor',
|
||||||
|
'currency_exchange',
|
||||||
|
'customer_support',
|
||||||
|
'dam',
|
||||||
|
'data_backup',
|
||||||
|
'data_configuration',
|
||||||
|
'data_encryption',
|
||||||
|
'data_protection',
|
||||||
|
'data_recovery',
|
||||||
|
'database',
|
||||||
|
'data_sheet',
|
||||||
|
'debt',
|
||||||
|
'decision',
|
||||||
|
'delete_column',
|
||||||
|
'delete_database',
|
||||||
|
'department',
|
||||||
|
'delete_row',
|
||||||
|
'deployment',
|
||||||
|
'dislike',
|
||||||
|
'disapprove',
|
||||||
|
'disclaimer',
|
||||||
|
'display',
|
||||||
|
'document',
|
||||||
|
'do_not_insert',
|
||||||
|
'do_not_mix',
|
||||||
|
'do_not_inhale',
|
||||||
|
'donate',
|
||||||
|
'down',
|
||||||
|
'doughnut_chart',
|
||||||
|
'down_left',
|
||||||
|
'down_right',
|
||||||
|
'download',
|
||||||
|
'edit_image',
|
||||||
|
'electrical_sensor',
|
||||||
|
'electrical_threshold',
|
||||||
|
'electricity',
|
||||||
|
'electro_devices',
|
||||||
|
'electronics',
|
||||||
|
'empty_battery',
|
||||||
|
'empty_filter',
|
||||||
|
'empty_trash',
|
||||||
|
'end_call',
|
||||||
|
'engineering',
|
||||||
|
'entering_heaven_aliv',
|
||||||
|
'expand',
|
||||||
|
'export',
|
||||||
|
'expired',
|
||||||
|
'factory',
|
||||||
|
'factory_breakdown',
|
||||||
|
'external',
|
||||||
|
'faq',
|
||||||
|
'feed_in',
|
||||||
|
'file',
|
||||||
|
'feedback',
|
||||||
|
'film',
|
||||||
|
'filled_filter',
|
||||||
|
'filing_cabinet',
|
||||||
|
'film_reel',
|
||||||
|
'flash_auto',
|
||||||
|
'fine_print',
|
||||||
|
'flash_off',
|
||||||
|
'flash_on',
|
||||||
|
'flow_chart',
|
||||||
|
'folder',
|
||||||
|
'frame',
|
||||||
|
'full_battery',
|
||||||
|
'full_trash',
|
||||||
|
'gallery',
|
||||||
|
'generic_sorting_asc',
|
||||||
|
'generic_sorting_desc',
|
||||||
|
'genealogy',
|
||||||
|
'globe',
|
||||||
|
'good_decision',
|
||||||
|
'headset',
|
||||||
|
'grid',
|
||||||
|
'graduation_cap',
|
||||||
|
'heat_map',
|
||||||
|
'high_priority',
|
||||||
|
'high_battery',
|
||||||
|
'image_file',
|
||||||
|
'home',
|
||||||
|
'idea',
|
||||||
|
'import',
|
||||||
|
'in_transit',
|
||||||
|
'integrated_webcam',
|
||||||
|
'inspection',
|
||||||
|
'invite',
|
||||||
|
'internal',
|
||||||
|
'ipad',
|
||||||
|
'info',
|
||||||
|
'iphone',
|
||||||
|
'kindle',
|
||||||
|
'key',
|
||||||
|
'landscape',
|
||||||
|
'left',
|
||||||
|
'left_down',
|
||||||
|
'left_up',
|
||||||
|
'leave',
|
||||||
|
'like_placeholder',
|
||||||
|
'light_at_the_end_of_',
|
||||||
|
'library',
|
||||||
|
'line_chart',
|
||||||
|
'link',
|
||||||
|
'like',
|
||||||
|
'lock',
|
||||||
|
'list',
|
||||||
|
'lock_landscape',
|
||||||
|
'low_battery',
|
||||||
|
'lock_portrait',
|
||||||
|
'low_priority',
|
||||||
|
'make_decision',
|
||||||
|
'medium_priority',
|
||||||
|
'manager',
|
||||||
|
'menu',
|
||||||
|
'middle_battery',
|
||||||
|
'minus',
|
||||||
|
'missed_call',
|
||||||
|
'mind_map',
|
||||||
|
'mms',
|
||||||
|
'multiple_cameras',
|
||||||
|
'money_transfer',
|
||||||
|
'music',
|
||||||
|
'multiple_devices',
|
||||||
|
'multiple_smartphones',
|
||||||
|
'multiple_inputs',
|
||||||
|
'negative_dynamic',
|
||||||
|
'neutral_decision',
|
||||||
|
'night_landscape',
|
||||||
|
'news',
|
||||||
|
'neutral_trading',
|
||||||
|
'night_portrait',
|
||||||
|
'no_idea',
|
||||||
|
'next',
|
||||||
|
'no_video',
|
||||||
|
'nook',
|
||||||
|
'ok',
|
||||||
|
'org_unit',
|
||||||
|
'opened_folder',
|
||||||
|
'old_time_camera',
|
||||||
|
'online_support',
|
||||||
|
'organization',
|
||||||
|
'package',
|
||||||
|
'paid',
|
||||||
|
'parallel_tasks',
|
||||||
|
'overtime',
|
||||||
|
'panorama',
|
||||||
|
'phone',
|
||||||
|
'phone_android',
|
||||||
|
'photo_reel',
|
||||||
|
'pie_chart',
|
||||||
|
'picture',
|
||||||
|
'planner',
|
||||||
|
'plus',
|
||||||
|
'podium_with_audience',
|
||||||
|
'podium_without_speak',
|
||||||
|
'podium_with_speaker',
|
||||||
|
'previous',
|
||||||
|
'portrait_mode',
|
||||||
|
'positive_dynamic',
|
||||||
|
'privacy',
|
||||||
|
'process',
|
||||||
|
'puzzle',
|
||||||
|
'questions',
|
||||||
|
'print',
|
||||||
|
'radar_plot',
|
||||||
|
'rating',
|
||||||
|
'ratings',
|
||||||
|
'reading',
|
||||||
|
'redo',
|
||||||
|
'reading_ebook',
|
||||||
|
'refresh',
|
||||||
|
'registered_trademark',
|
||||||
|
'right',
|
||||||
|
'reuse',
|
||||||
|
'remove_image',
|
||||||
|
'right_down',
|
||||||
|
'right_up',
|
||||||
|
'rotate_to_portrait',
|
||||||
|
'rules',
|
||||||
|
'rotate_camera',
|
||||||
|
'rotate_to_landscape',
|
||||||
|
'ruler',
|
||||||
|
'scatter_plot',
|
||||||
|
'search',
|
||||||
|
'safe',
|
||||||
|
'self_service_kiosk',
|
||||||
|
'selfie',
|
||||||
|
'serial_tasks',
|
||||||
|
'sales_performance',
|
||||||
|
'settings',
|
||||||
|
'services',
|
||||||
|
'share',
|
||||||
|
'shipped',
|
||||||
|
'sim_card',
|
||||||
|
'shop',
|
||||||
|
'service_mark',
|
||||||
|
'sim_card_chip',
|
||||||
|
'signature',
|
||||||
|
'smartphone_tablet',
|
||||||
|
'sound_recording_copy',
|
||||||
|
'sms',
|
||||||
|
'speaker',
|
||||||
|
'slr_back_side',
|
||||||
|
'start',
|
||||||
|
'stack_of_photos',
|
||||||
|
'statistics',
|
||||||
|
'sports_mode',
|
||||||
|
'support',
|
||||||
|
'synchronize',
|
||||||
|
'switch_camera',
|
||||||
|
'survey',
|
||||||
|
'tablet_android',
|
||||||
|
'template',
|
||||||
|
'trademark',
|
||||||
|
'todo_list',
|
||||||
|
'touchscreen_smartpho',
|
||||||
|
'timeline',
|
||||||
|
'tree_structure',
|
||||||
|
'undo',
|
||||||
|
'up_left',
|
||||||
|
'two_smartphones',
|
||||||
|
'unlock',
|
||||||
|
'up',
|
||||||
|
'up_right',
|
||||||
|
'upload',
|
||||||
|
'video_call',
|
||||||
|
'video_file',
|
||||||
|
'view_details',
|
||||||
|
'video_projector',
|
||||||
|
'vip',
|
||||||
|
'voice_presentation',
|
||||||
|
'webcam',
|
||||||
|
'voicemail',
|
||||||
|
'workflow',
|
||||||
|
'about',
|
||||||
|
'accept_database',
|
||||||
|
'add_image',
|
||||||
|
'add_column',
|
||||||
|
'add_database',
|
||||||
|
'add_row',
|
||||||
|
]
|
||||||
|
module.exports = [
|
||||||
|
{
|
||||||
|
url: '/colorfulIcon/getList',
|
||||||
|
type: 'post',
|
||||||
|
response(config) {
|
||||||
|
const { title, pageNo = 1, pageSize = 72 } = config.body
|
||||||
|
let mockList = data.filter((item) => {
|
||||||
|
if (title && item.indexOf(title) < 0) return false
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
const pageList = mockList.filter((item, index) => index < pageSize * pageNo && index >= pageSize * (pageNo - 1))
|
||||||
|
return {
|
||||||
|
code: 200,
|
||||||
|
msg: 'success',
|
||||||
|
totalCount: mockList.length,
|
||||||
|
data: pageList,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
40
mock/controller/goodsList.js
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
const { mock } = require('mockjs')
|
||||||
|
|
||||||
|
const List = []
|
||||||
|
const count = 999
|
||||||
|
let num = 0
|
||||||
|
for (let i = 0; i < count; i++) {
|
||||||
|
List.push(
|
||||||
|
mock({
|
||||||
|
uuid: '@uuid',
|
||||||
|
image: `https://picsum.photos/300/600?random=${num++}`,
|
||||||
|
title: '@ctitle',
|
||||||
|
description: '@csentence',
|
||||||
|
link: 'https://www.baidu.com',
|
||||||
|
price: '@integer(100, 500)',
|
||||||
|
'status|1': [1, 0],
|
||||||
|
'isRecommend|1': [1, 0],
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = [
|
||||||
|
{
|
||||||
|
url: '/goodsList/getList',
|
||||||
|
type: 'post',
|
||||||
|
response(config) {
|
||||||
|
const { title = '', pageNo = 1, pageSize = 20 } = config.body
|
||||||
|
let mockList = List.filter((item) => {
|
||||||
|
if (title && item.title.indexOf(title) < 0) return false
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
const pageList = mockList.filter((item, index) => index < pageSize * pageNo && index >= pageSize * (pageNo - 1))
|
||||||
|
return {
|
||||||
|
code: 200,
|
||||||
|
msg: 'success',
|
||||||
|
totalCount: count,
|
||||||
|
data: pageList,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
982
mock/controller/icon.js
Normal file
@@ -0,0 +1,982 @@
|
|||||||
|
const data = [
|
||||||
|
'air-freshener',
|
||||||
|
'align-center',
|
||||||
|
'align-justify',
|
||||||
|
'align-left',
|
||||||
|
'align-right',
|
||||||
|
'allergies',
|
||||||
|
'ambulance',
|
||||||
|
'american-sign-language-interpreting',
|
||||||
|
'anchor',
|
||||||
|
'angle-double-down',
|
||||||
|
'angle-double-left',
|
||||||
|
'angle-double-right',
|
||||||
|
'angle-double-up',
|
||||||
|
'angle-down',
|
||||||
|
'angle-left',
|
||||||
|
'angle-right',
|
||||||
|
'angle-up',
|
||||||
|
'angry',
|
||||||
|
'ankh',
|
||||||
|
'apple-alt',
|
||||||
|
'archive',
|
||||||
|
'archway',
|
||||||
|
'arrow-alt-circle-down',
|
||||||
|
'arrow-alt-circle-left',
|
||||||
|
'arrow-alt-circle-right',
|
||||||
|
'arrow-alt-circle-up',
|
||||||
|
'arrow-circle-down',
|
||||||
|
'arrow-circle-left',
|
||||||
|
'arrow-circle-right',
|
||||||
|
'arrow-circle-up',
|
||||||
|
'arrow-down',
|
||||||
|
'arrow-left',
|
||||||
|
'arrow-right',
|
||||||
|
'arrow-up',
|
||||||
|
'arrows-alt',
|
||||||
|
'arrows-alt-h',
|
||||||
|
'arrows-alt-v',
|
||||||
|
'assistive-listening-systems',
|
||||||
|
'asterisk',
|
||||||
|
'at',
|
||||||
|
'atlas',
|
||||||
|
'atom',
|
||||||
|
'audio-description',
|
||||||
|
'award',
|
||||||
|
'baby',
|
||||||
|
'baby-carriage',
|
||||||
|
'backspace',
|
||||||
|
'backward',
|
||||||
|
'bacon',
|
||||||
|
'bahai',
|
||||||
|
'balance-scale',
|
||||||
|
'balance-scale-left',
|
||||||
|
'balance-scale-right',
|
||||||
|
'ban',
|
||||||
|
'band-aid',
|
||||||
|
'barcode',
|
||||||
|
'bars',
|
||||||
|
'baseball-ball',
|
||||||
|
'basketball-ball',
|
||||||
|
'bath',
|
||||||
|
'battery-empty',
|
||||||
|
'battery-full',
|
||||||
|
'battery-half',
|
||||||
|
'battery-quarter',
|
||||||
|
'battery-three-quarters',
|
||||||
|
'bed',
|
||||||
|
'beer',
|
||||||
|
'bell',
|
||||||
|
'bell-slash',
|
||||||
|
'bezier-curve',
|
||||||
|
'bible',
|
||||||
|
'bicycle',
|
||||||
|
'biking',
|
||||||
|
'binoculars',
|
||||||
|
'biohazard',
|
||||||
|
'birthday-cake',
|
||||||
|
'blender',
|
||||||
|
'blender-phone',
|
||||||
|
'blind',
|
||||||
|
'blog',
|
||||||
|
'bold',
|
||||||
|
'bolt',
|
||||||
|
'bomb',
|
||||||
|
'bone',
|
||||||
|
'bong',
|
||||||
|
'book',
|
||||||
|
'book-dead',
|
||||||
|
'book-medical',
|
||||||
|
'book-open',
|
||||||
|
'book-reader',
|
||||||
|
'bookmark',
|
||||||
|
'border-all',
|
||||||
|
'border-none',
|
||||||
|
'border-style',
|
||||||
|
'bowling-ball',
|
||||||
|
'box',
|
||||||
|
'box-open',
|
||||||
|
'boxes',
|
||||||
|
'braille',
|
||||||
|
'brain',
|
||||||
|
'bread-slice',
|
||||||
|
'briefcase',
|
||||||
|
'briefcase-medical',
|
||||||
|
'broadcast-tower',
|
||||||
|
'broom',
|
||||||
|
'brush',
|
||||||
|
'bug',
|
||||||
|
'building',
|
||||||
|
'bullhorn',
|
||||||
|
'bullseye',
|
||||||
|
'burn',
|
||||||
|
'bus',
|
||||||
|
'bus-alt',
|
||||||
|
'business-time',
|
||||||
|
'calculator',
|
||||||
|
'calendar',
|
||||||
|
'calendar-alt',
|
||||||
|
'calendar-check',
|
||||||
|
'calendar-day',
|
||||||
|
'calendar-minus',
|
||||||
|
'calendar-plus',
|
||||||
|
'calendar-times',
|
||||||
|
'calendar-week',
|
||||||
|
'camera',
|
||||||
|
'camera-retro',
|
||||||
|
'campground',
|
||||||
|
'candy-cane',
|
||||||
|
'cannabis',
|
||||||
|
'capsules',
|
||||||
|
'car',
|
||||||
|
'car-alt',
|
||||||
|
'car-battery',
|
||||||
|
'car-crash',
|
||||||
|
'car-side',
|
||||||
|
'caravan',
|
||||||
|
'caret-down',
|
||||||
|
'caret-left',
|
||||||
|
'caret-right',
|
||||||
|
'caret-square-down',
|
||||||
|
'caret-square-left',
|
||||||
|
'caret-square-right',
|
||||||
|
'caret-square-up',
|
||||||
|
'caret-up',
|
||||||
|
'carrot',
|
||||||
|
'cart-arrow-down',
|
||||||
|
'cart-plus',
|
||||||
|
'cash-register',
|
||||||
|
'cat',
|
||||||
|
'certificate',
|
||||||
|
'chair',
|
||||||
|
'chalkboard',
|
||||||
|
'chalkboard-teacher',
|
||||||
|
'charging-station',
|
||||||
|
'chart-area',
|
||||||
|
'chart-bar',
|
||||||
|
'chart-line',
|
||||||
|
'chart-pie',
|
||||||
|
'check',
|
||||||
|
'check-circle',
|
||||||
|
'check-double',
|
||||||
|
'check-square',
|
||||||
|
'cheese',
|
||||||
|
'chess',
|
||||||
|
'chess-bishop',
|
||||||
|
'chess-board',
|
||||||
|
'chess-king',
|
||||||
|
'chess-knight',
|
||||||
|
'chess-pawn',
|
||||||
|
'chess-queen',
|
||||||
|
'chess-rook',
|
||||||
|
'chevron-circle-down',
|
||||||
|
'chevron-circle-left',
|
||||||
|
'chevron-circle-right',
|
||||||
|
'chevron-circle-up',
|
||||||
|
'chevron-down',
|
||||||
|
'chevron-left',
|
||||||
|
'chevron-right',
|
||||||
|
'chevron-up',
|
||||||
|
'child',
|
||||||
|
'church',
|
||||||
|
'circle',
|
||||||
|
'circle-notch',
|
||||||
|
'city',
|
||||||
|
'clinic-medical',
|
||||||
|
'clipboard',
|
||||||
|
'clipboard-check',
|
||||||
|
'clipboard-list',
|
||||||
|
'clock',
|
||||||
|
'clone',
|
||||||
|
'closed-captioning',
|
||||||
|
'cloud',
|
||||||
|
'cloud-download-alt',
|
||||||
|
'cloud-meatball',
|
||||||
|
'cloud-moon',
|
||||||
|
'cloud-moon-rain',
|
||||||
|
'cloud-rain',
|
||||||
|
'cloud-showers-heavy',
|
||||||
|
'cloud-sun',
|
||||||
|
'cloud-sun-rain',
|
||||||
|
'cloud-upload-alt',
|
||||||
|
'cocktail',
|
||||||
|
'code',
|
||||||
|
'code-branch',
|
||||||
|
'coffee',
|
||||||
|
'cog',
|
||||||
|
'cogs',
|
||||||
|
'coins',
|
||||||
|
'columns',
|
||||||
|
'comment',
|
||||||
|
'comment-alt',
|
||||||
|
'comment-dollar',
|
||||||
|
'comment-dots',
|
||||||
|
'comment-medical',
|
||||||
|
'comment-slash',
|
||||||
|
'comments',
|
||||||
|
'comments-dollar',
|
||||||
|
'compact-disc',
|
||||||
|
'compass',
|
||||||
|
'compress',
|
||||||
|
'compress-alt',
|
||||||
|
'compress-arrows-alt',
|
||||||
|
'concierge-bell',
|
||||||
|
'cookie',
|
||||||
|
'cookie-bite',
|
||||||
|
'copy',
|
||||||
|
'copyright',
|
||||||
|
'couch',
|
||||||
|
'credit-card',
|
||||||
|
'crop',
|
||||||
|
'crop-alt',
|
||||||
|
'cross',
|
||||||
|
'crosshairs',
|
||||||
|
'crow',
|
||||||
|
'crown',
|
||||||
|
'crutch',
|
||||||
|
'cube',
|
||||||
|
'cubes',
|
||||||
|
'cut',
|
||||||
|
'database',
|
||||||
|
'deaf',
|
||||||
|
'democrat',
|
||||||
|
'desktop',
|
||||||
|
'dharmachakra',
|
||||||
|
'diagnoses',
|
||||||
|
'dice',
|
||||||
|
'dice-d20',
|
||||||
|
'dice-d6',
|
||||||
|
'dice-five',
|
||||||
|
'dice-four',
|
||||||
|
'dice-one',
|
||||||
|
'dice-six',
|
||||||
|
'dice-three',
|
||||||
|
'dice-two',
|
||||||
|
'digital-tachograph',
|
||||||
|
'directions',
|
||||||
|
'divide',
|
||||||
|
'dizzy',
|
||||||
|
'dna',
|
||||||
|
'dog',
|
||||||
|
'dollar-sign',
|
||||||
|
'dolly',
|
||||||
|
'dolly-flatbed',
|
||||||
|
'donate',
|
||||||
|
'door-closed',
|
||||||
|
'door-open',
|
||||||
|
'dot-circle',
|
||||||
|
'dove',
|
||||||
|
'download',
|
||||||
|
'drafting-compass',
|
||||||
|
'dragon',
|
||||||
|
'draw-polygon',
|
||||||
|
'drum',
|
||||||
|
'drum-steelpan',
|
||||||
|
'drumstick-bite',
|
||||||
|
'dumbbell',
|
||||||
|
'dumpster',
|
||||||
|
'dumpster-fire',
|
||||||
|
'dungeon',
|
||||||
|
'edit',
|
||||||
|
'egg',
|
||||||
|
'eject',
|
||||||
|
'ellipsis-h',
|
||||||
|
'ellipsis-v',
|
||||||
|
'envelope',
|
||||||
|
'envelope-open',
|
||||||
|
'envelope-open-text',
|
||||||
|
'envelope-square',
|
||||||
|
'equals',
|
||||||
|
'eraser',
|
||||||
|
'ethernet',
|
||||||
|
'euro-sign',
|
||||||
|
'exchange-alt',
|
||||||
|
'exclamation',
|
||||||
|
'exclamation-circle',
|
||||||
|
'exclamation-triangle',
|
||||||
|
'expand',
|
||||||
|
'expand-alt',
|
||||||
|
'expand-arrows-alt',
|
||||||
|
'external-link-alt',
|
||||||
|
'external-link-square-alt',
|
||||||
|
'eye',
|
||||||
|
'eye-dropper',
|
||||||
|
'eye-slash',
|
||||||
|
'fan',
|
||||||
|
'fast-backward',
|
||||||
|
'fast-forward',
|
||||||
|
'fax',
|
||||||
|
'feather',
|
||||||
|
'feather-alt',
|
||||||
|
'female',
|
||||||
|
'fighter-jet',
|
||||||
|
'file',
|
||||||
|
'file-alt',
|
||||||
|
'file-archive',
|
||||||
|
'file-audio',
|
||||||
|
'file-code',
|
||||||
|
'file-contract',
|
||||||
|
'file-csv',
|
||||||
|
'file-download',
|
||||||
|
'file-excel',
|
||||||
|
'file-export',
|
||||||
|
'file-image',
|
||||||
|
'file-import',
|
||||||
|
'file-invoice',
|
||||||
|
'file-invoice-dollar',
|
||||||
|
'file-medical',
|
||||||
|
'file-medical-alt',
|
||||||
|
'file-pdf',
|
||||||
|
'file-powerpoint',
|
||||||
|
'file-prescription',
|
||||||
|
'file-signature',
|
||||||
|
'file-upload',
|
||||||
|
'file-video',
|
||||||
|
'file-word',
|
||||||
|
'fill',
|
||||||
|
'fill-drip',
|
||||||
|
'film',
|
||||||
|
'filter',
|
||||||
|
'fingerprint',
|
||||||
|
'fire',
|
||||||
|
'fire-alt',
|
||||||
|
'fire-extinguisher',
|
||||||
|
'first-aid',
|
||||||
|
'fish',
|
||||||
|
'fist-raised',
|
||||||
|
'flag',
|
||||||
|
'flag-checkered',
|
||||||
|
'flag-usa',
|
||||||
|
'flask',
|
||||||
|
'flushed',
|
||||||
|
'folder',
|
||||||
|
'folder-minus',
|
||||||
|
'folder-open',
|
||||||
|
'folder-plus',
|
||||||
|
'font',
|
||||||
|
'football-ball',
|
||||||
|
'forward',
|
||||||
|
'frog',
|
||||||
|
'frown',
|
||||||
|
'frown-open',
|
||||||
|
'funnel-dollar',
|
||||||
|
'futbol',
|
||||||
|
'gamepad',
|
||||||
|
'gas-pump',
|
||||||
|
'gavel',
|
||||||
|
'gem',
|
||||||
|
'genderless',
|
||||||
|
'ghost',
|
||||||
|
'gift',
|
||||||
|
'gifts',
|
||||||
|
'glass-cheers',
|
||||||
|
'glass-martini',
|
||||||
|
'glass-martini-alt',
|
||||||
|
'glass-whiskey',
|
||||||
|
'glasses',
|
||||||
|
'globe',
|
||||||
|
'globe-africa',
|
||||||
|
'globe-americas',
|
||||||
|
'globe-asia',
|
||||||
|
'globe-europe',
|
||||||
|
'golf-ball',
|
||||||
|
'gopuram',
|
||||||
|
'graduation-cap',
|
||||||
|
'greater-than',
|
||||||
|
'greater-than-equal',
|
||||||
|
'grimace',
|
||||||
|
'grin',
|
||||||
|
'grin-alt',
|
||||||
|
'grin-beam',
|
||||||
|
'grin-beam-sweat',
|
||||||
|
'grin-hearts',
|
||||||
|
'grin-squint',
|
||||||
|
'grin-squint-tears',
|
||||||
|
'grin-stars',
|
||||||
|
'grin-tears',
|
||||||
|
'grin-tongue',
|
||||||
|
'grin-tongue-squint',
|
||||||
|
'grin-tongue-wink',
|
||||||
|
'grin-wink',
|
||||||
|
'grip-horizontal',
|
||||||
|
'grip-lines',
|
||||||
|
'grip-lines-vertical',
|
||||||
|
'grip-vertical',
|
||||||
|
'guitar',
|
||||||
|
'h-square',
|
||||||
|
'hamburger',
|
||||||
|
'hammer',
|
||||||
|
'hamsa',
|
||||||
|
'hand-holding',
|
||||||
|
'hand-holding-heart',
|
||||||
|
'hand-holding-usd',
|
||||||
|
'hand-lizard',
|
||||||
|
'hand-middle-finger',
|
||||||
|
'hand-paper',
|
||||||
|
'hand-peace',
|
||||||
|
'hand-point-down',
|
||||||
|
'hand-point-left',
|
||||||
|
'hand-point-right',
|
||||||
|
'hand-point-up',
|
||||||
|
'hand-pointer',
|
||||||
|
'hand-rock',
|
||||||
|
'hand-scissors',
|
||||||
|
'hand-spock',
|
||||||
|
'hands',
|
||||||
|
'hands-helping',
|
||||||
|
'handshake',
|
||||||
|
'hanukiah',
|
||||||
|
'hard-hat',
|
||||||
|
'hashtag',
|
||||||
|
'hat-cowboy',
|
||||||
|
'hat-cowboy-side',
|
||||||
|
'hat-wizard',
|
||||||
|
'hdd',
|
||||||
|
'heading',
|
||||||
|
'headphones',
|
||||||
|
'headphones-alt',
|
||||||
|
'headset',
|
||||||
|
'heart',
|
||||||
|
'heart-broken',
|
||||||
|
'heartbeat',
|
||||||
|
'helicopter',
|
||||||
|
'highlighter',
|
||||||
|
'hiking',
|
||||||
|
'hippo',
|
||||||
|
'history',
|
||||||
|
'hockey-puck',
|
||||||
|
'holly-berry',
|
||||||
|
'home',
|
||||||
|
'horse',
|
||||||
|
'horse-head',
|
||||||
|
'hospital',
|
||||||
|
'hospital-alt',
|
||||||
|
'hospital-symbol',
|
||||||
|
'hot-tub',
|
||||||
|
'hotdog',
|
||||||
|
'hotel',
|
||||||
|
'hourglass',
|
||||||
|
'hourglass-end',
|
||||||
|
'hourglass-half',
|
||||||
|
'hourglass-start',
|
||||||
|
'house-damage',
|
||||||
|
'hryvnia',
|
||||||
|
'i-cursor',
|
||||||
|
'ice-cream',
|
||||||
|
'icicles',
|
||||||
|
'icons',
|
||||||
|
'id-badge',
|
||||||
|
'id-card',
|
||||||
|
'id-card-alt',
|
||||||
|
'igloo',
|
||||||
|
'image',
|
||||||
|
'images',
|
||||||
|
'inbox',
|
||||||
|
'indent',
|
||||||
|
'industry',
|
||||||
|
'infinity',
|
||||||
|
'info',
|
||||||
|
'info-circle',
|
||||||
|
'italic',
|
||||||
|
'jedi',
|
||||||
|
'joint',
|
||||||
|
'journal-whills',
|
||||||
|
'kaaba',
|
||||||
|
'key',
|
||||||
|
'keyboard',
|
||||||
|
'khanda',
|
||||||
|
'kiss',
|
||||||
|
'kiss-beam',
|
||||||
|
'kiss-wink-heart',
|
||||||
|
'kiwi-bird',
|
||||||
|
'landmark',
|
||||||
|
'language',
|
||||||
|
'laptop',
|
||||||
|
'laptop-code',
|
||||||
|
'laptop-medical',
|
||||||
|
'laugh',
|
||||||
|
'laugh-beam',
|
||||||
|
'laugh-squint',
|
||||||
|
'laugh-wink',
|
||||||
|
'layer-group',
|
||||||
|
'leaf',
|
||||||
|
'lemon',
|
||||||
|
'less-than',
|
||||||
|
'less-than-equal',
|
||||||
|
'level-down-alt',
|
||||||
|
'level-up-alt',
|
||||||
|
'life-ring',
|
||||||
|
'lightbulb',
|
||||||
|
'link',
|
||||||
|
'lira-sign',
|
||||||
|
'list',
|
||||||
|
'list-alt',
|
||||||
|
'list-ol',
|
||||||
|
'list-ul',
|
||||||
|
'location-arrow',
|
||||||
|
'lock',
|
||||||
|
'lock-open',
|
||||||
|
'long-arrow-alt-down',
|
||||||
|
'long-arrow-alt-left',
|
||||||
|
'long-arrow-alt-right',
|
||||||
|
'long-arrow-alt-up',
|
||||||
|
'low-vision',
|
||||||
|
'luggage-cart',
|
||||||
|
'magic',
|
||||||
|
'magnet',
|
||||||
|
'mail-bulk',
|
||||||
|
'male',
|
||||||
|
'map',
|
||||||
|
'map-marked',
|
||||||
|
'map-marked-alt',
|
||||||
|
'map-marker',
|
||||||
|
'map-marker-alt',
|
||||||
|
'map-pin',
|
||||||
|
'map-signs',
|
||||||
|
'marker',
|
||||||
|
'mars',
|
||||||
|
'mars-double',
|
||||||
|
'mars-stroke',
|
||||||
|
'mars-stroke-h',
|
||||||
|
'mars-stroke-v',
|
||||||
|
'mask',
|
||||||
|
'medal',
|
||||||
|
'medkit',
|
||||||
|
'meh',
|
||||||
|
'meh-blank',
|
||||||
|
'meh-rolling-eyes',
|
||||||
|
'memory',
|
||||||
|
'menorah',
|
||||||
|
'mercury',
|
||||||
|
'meteor',
|
||||||
|
'microchip',
|
||||||
|
'microphone',
|
||||||
|
'microphone-alt',
|
||||||
|
'microphone-alt-slash',
|
||||||
|
'microphone-slash',
|
||||||
|
'microscope',
|
||||||
|
'minus',
|
||||||
|
'minus-circle',
|
||||||
|
'minus-square',
|
||||||
|
'mitten',
|
||||||
|
'mobile',
|
||||||
|
'mobile-alt',
|
||||||
|
'money-bill',
|
||||||
|
'money-bill-alt',
|
||||||
|
'money-bill-wave',
|
||||||
|
'money-bill-wave-alt',
|
||||||
|
'money-check',
|
||||||
|
'money-check-alt',
|
||||||
|
'monument',
|
||||||
|
'moon',
|
||||||
|
'mortar-pestle',
|
||||||
|
'mosque',
|
||||||
|
'motorcycle',
|
||||||
|
'mountain',
|
||||||
|
'mouse',
|
||||||
|
'mouse-pointer',
|
||||||
|
'mug-hot',
|
||||||
|
'music',
|
||||||
|
'network-wired',
|
||||||
|
'neuter',
|
||||||
|
'newspaper',
|
||||||
|
'not-equal',
|
||||||
|
'notes-medical',
|
||||||
|
'object-group',
|
||||||
|
'object-ungroup',
|
||||||
|
'oil-can',
|
||||||
|
'om',
|
||||||
|
'otter',
|
||||||
|
'outdent',
|
||||||
|
'pager',
|
||||||
|
'paint-brush',
|
||||||
|
'paint-roller',
|
||||||
|
'palette',
|
||||||
|
'pallet',
|
||||||
|
'paper-plane',
|
||||||
|
'paperclip',
|
||||||
|
'parachute-box',
|
||||||
|
'paragraph',
|
||||||
|
'parking',
|
||||||
|
'passport',
|
||||||
|
'pastafarianism',
|
||||||
|
'paste',
|
||||||
|
'pause',
|
||||||
|
'pause-circle',
|
||||||
|
'paw',
|
||||||
|
'peace',
|
||||||
|
'pen',
|
||||||
|
'pen-alt',
|
||||||
|
'pen-fancy',
|
||||||
|
'pen-nib',
|
||||||
|
'pen-square',
|
||||||
|
'pencil-alt',
|
||||||
|
'pencil-ruler',
|
||||||
|
'people-carry',
|
||||||
|
'pepper-hot',
|
||||||
|
'percent',
|
||||||
|
'percentage',
|
||||||
|
'person-booth',
|
||||||
|
'phone',
|
||||||
|
'phone-alt',
|
||||||
|
'phone-slash',
|
||||||
|
'phone-square',
|
||||||
|
'phone-square-alt',
|
||||||
|
'phone-volume',
|
||||||
|
'photo-video',
|
||||||
|
'piggy-bank',
|
||||||
|
'pills',
|
||||||
|
'pizza-slice',
|
||||||
|
'place-of-worship',
|
||||||
|
'plane',
|
||||||
|
'plane-arrival',
|
||||||
|
'plane-departure',
|
||||||
|
'play',
|
||||||
|
'play-circle',
|
||||||
|
'plug',
|
||||||
|
'plus',
|
||||||
|
'plus-circle',
|
||||||
|
'plus-square',
|
||||||
|
'podcast',
|
||||||
|
'poll',
|
||||||
|
'poll-h',
|
||||||
|
'poo',
|
||||||
|
'poo-storm',
|
||||||
|
'poop',
|
||||||
|
'portrait',
|
||||||
|
'pound-sign',
|
||||||
|
'power-off',
|
||||||
|
'pray',
|
||||||
|
'praying-hands',
|
||||||
|
'prescription',
|
||||||
|
'prescription-bottle',
|
||||||
|
'prescription-bottle-alt',
|
||||||
|
'print',
|
||||||
|
'procedures',
|
||||||
|
'project-diagram',
|
||||||
|
'puzzle-piece',
|
||||||
|
'qrcode',
|
||||||
|
'question',
|
||||||
|
'question-circle',
|
||||||
|
'quidditch',
|
||||||
|
'quote-left',
|
||||||
|
'quote-right',
|
||||||
|
'quran',
|
||||||
|
'radiation',
|
||||||
|
'radiation-alt',
|
||||||
|
'rainbow',
|
||||||
|
'random',
|
||||||
|
'receipt',
|
||||||
|
'record-vinyl',
|
||||||
|
'recycle',
|
||||||
|
'redo',
|
||||||
|
'redo-alt',
|
||||||
|
'registered',
|
||||||
|
'remove-format',
|
||||||
|
'reply',
|
||||||
|
'reply-all',
|
||||||
|
'republican',
|
||||||
|
'restroom',
|
||||||
|
'retweet',
|
||||||
|
'ribbon',
|
||||||
|
'ring',
|
||||||
|
'road',
|
||||||
|
'robot',
|
||||||
|
'rocket',
|
||||||
|
'route',
|
||||||
|
'rss',
|
||||||
|
'rss-square',
|
||||||
|
'ruble-sign',
|
||||||
|
'ruler',
|
||||||
|
'ruler-combined',
|
||||||
|
'ruler-horizontal',
|
||||||
|
'ruler-vertical',
|
||||||
|
'running',
|
||||||
|
'rupee-sign',
|
||||||
|
'sad-cry',
|
||||||
|
'sad-tear',
|
||||||
|
'satellite',
|
||||||
|
'satellite-dish',
|
||||||
|
'save',
|
||||||
|
'school',
|
||||||
|
'screwdriver',
|
||||||
|
'scroll',
|
||||||
|
'sd-card',
|
||||||
|
'search',
|
||||||
|
'search-dollar',
|
||||||
|
'search-location',
|
||||||
|
'search-minus',
|
||||||
|
'search-plus',
|
||||||
|
'seedling',
|
||||||
|
'server',
|
||||||
|
'shapes',
|
||||||
|
'share',
|
||||||
|
'share-alt',
|
||||||
|
'share-alt-square',
|
||||||
|
'share-square',
|
||||||
|
'shekel-sign',
|
||||||
|
'shield-alt',
|
||||||
|
'ship',
|
||||||
|
'shipping-fast',
|
||||||
|
'shoe-prints',
|
||||||
|
'shopping-bag',
|
||||||
|
'shopping-basket',
|
||||||
|
'shopping-cart',
|
||||||
|
'shower',
|
||||||
|
'shuttle-van',
|
||||||
|
'sign',
|
||||||
|
'sign-in-alt',
|
||||||
|
'sign-language',
|
||||||
|
'sign-out-alt',
|
||||||
|
'signal',
|
||||||
|
'signature',
|
||||||
|
'sim-card',
|
||||||
|
'sitemap',
|
||||||
|
'skating',
|
||||||
|
'skiing',
|
||||||
|
'skiing-nordic',
|
||||||
|
'skull',
|
||||||
|
'skull-crossbones',
|
||||||
|
'slash',
|
||||||
|
'sleigh',
|
||||||
|
'sliders-h',
|
||||||
|
'smile',
|
||||||
|
'smile-beam',
|
||||||
|
'smile-wink',
|
||||||
|
'smog',
|
||||||
|
'smoking',
|
||||||
|
'smoking-ban',
|
||||||
|
'sms',
|
||||||
|
'snowboarding',
|
||||||
|
'snowflake',
|
||||||
|
'snowman',
|
||||||
|
'snowplow',
|
||||||
|
'socks',
|
||||||
|
'solar-panel',
|
||||||
|
'sort',
|
||||||
|
'sort-alpha-down',
|
||||||
|
'sort-alpha-down-alt',
|
||||||
|
'sort-alpha-up',
|
||||||
|
'sort-alpha-up-alt',
|
||||||
|
'sort-amount-down',
|
||||||
|
'sort-amount-down-alt',
|
||||||
|
'sort-amount-up',
|
||||||
|
'sort-amount-up-alt',
|
||||||
|
'sort-down',
|
||||||
|
'sort-numeric-down',
|
||||||
|
'sort-numeric-down-alt',
|
||||||
|
'sort-numeric-up',
|
||||||
|
'sort-numeric-up-alt',
|
||||||
|
'sort-up',
|
||||||
|
'spa',
|
||||||
|
'space-shuttle',
|
||||||
|
'spell-check',
|
||||||
|
'spider',
|
||||||
|
'spinner',
|
||||||
|
'splotch',
|
||||||
|
'spray-can',
|
||||||
|
'square',
|
||||||
|
'square-full',
|
||||||
|
'square-root-alt',
|
||||||
|
'stamp',
|
||||||
|
'star',
|
||||||
|
'star-and-crescent',
|
||||||
|
'star-half',
|
||||||
|
'star-half-alt',
|
||||||
|
'star-of-david',
|
||||||
|
'star-of-life',
|
||||||
|
'step-backward',
|
||||||
|
'step-forward',
|
||||||
|
'stethoscope',
|
||||||
|
'sticky-note',
|
||||||
|
'stop',
|
||||||
|
'stop-circle',
|
||||||
|
'stopwatch',
|
||||||
|
'store',
|
||||||
|
'store-alt',
|
||||||
|
'stream',
|
||||||
|
'street-view',
|
||||||
|
'strikethrough',
|
||||||
|
'stroopwafel',
|
||||||
|
'subscript',
|
||||||
|
'subway',
|
||||||
|
'suitcase',
|
||||||
|
'suitcase-rolling',
|
||||||
|
'sun',
|
||||||
|
'superscript',
|
||||||
|
'surprise',
|
||||||
|
'swatchbook',
|
||||||
|
'swimmer',
|
||||||
|
'swimming-pool',
|
||||||
|
'synagogue',
|
||||||
|
'sync',
|
||||||
|
'sync-alt',
|
||||||
|
'syringe',
|
||||||
|
'table',
|
||||||
|
'table-tennis',
|
||||||
|
'tablet',
|
||||||
|
'tablet-alt',
|
||||||
|
'tablets',
|
||||||
|
'tachometer-alt',
|
||||||
|
'tag',
|
||||||
|
'tags',
|
||||||
|
'tape',
|
||||||
|
'tasks',
|
||||||
|
'taxi',
|
||||||
|
'teeth',
|
||||||
|
'teeth-open',
|
||||||
|
'temperature-high',
|
||||||
|
'temperature-low',
|
||||||
|
'tenge',
|
||||||
|
'terminal',
|
||||||
|
'text-height',
|
||||||
|
'text-width',
|
||||||
|
'th',
|
||||||
|
'th-large',
|
||||||
|
'th-list',
|
||||||
|
'theater-masks',
|
||||||
|
'thermometer',
|
||||||
|
'thermometer-empty',
|
||||||
|
'thermometer-full',
|
||||||
|
'thermometer-half',
|
||||||
|
'thermometer-quarter',
|
||||||
|
'thermometer-three-quarters',
|
||||||
|
'thumbs-down',
|
||||||
|
'thumbs-up',
|
||||||
|
'thumbtack',
|
||||||
|
'ticket-alt',
|
||||||
|
'times',
|
||||||
|
'times-circle',
|
||||||
|
'tint',
|
||||||
|
'tint-slash',
|
||||||
|
'tired',
|
||||||
|
'toggle-off',
|
||||||
|
'toggle-on',
|
||||||
|
'toilet',
|
||||||
|
'toilet-paper',
|
||||||
|
'toolbox',
|
||||||
|
'tools',
|
||||||
|
'tooth',
|
||||||
|
'torah',
|
||||||
|
'torii-gate',
|
||||||
|
'tractor',
|
||||||
|
'trademark',
|
||||||
|
'traffic-light',
|
||||||
|
'trailer',
|
||||||
|
'train',
|
||||||
|
'tram',
|
||||||
|
'transgender',
|
||||||
|
'transgender-alt',
|
||||||
|
'trash',
|
||||||
|
'trash-alt',
|
||||||
|
'trash-restore',
|
||||||
|
'trash-restore-alt',
|
||||||
|
'tree',
|
||||||
|
'trophy',
|
||||||
|
'truck',
|
||||||
|
'truck-loading',
|
||||||
|
'truck-monster',
|
||||||
|
'truck-moving',
|
||||||
|
'truck-pickup',
|
||||||
|
'tshirt',
|
||||||
|
'tty',
|
||||||
|
'tv',
|
||||||
|
'umbrella',
|
||||||
|
'umbrella-beach',
|
||||||
|
'underline',
|
||||||
|
'undo',
|
||||||
|
'undo-alt',
|
||||||
|
'universal-access',
|
||||||
|
'university',
|
||||||
|
'unlink',
|
||||||
|
'unlock',
|
||||||
|
'unlock-alt',
|
||||||
|
'upload',
|
||||||
|
'user',
|
||||||
|
'user-alt',
|
||||||
|
'user-alt-slash',
|
||||||
|
'user-astronaut',
|
||||||
|
'user-check',
|
||||||
|
'user-circle',
|
||||||
|
'user-clock',
|
||||||
|
'user-cog',
|
||||||
|
'user-edit',
|
||||||
|
'user-friends',
|
||||||
|
'user-graduate',
|
||||||
|
'user-injured',
|
||||||
|
'user-lock',
|
||||||
|
'user-md',
|
||||||
|
'user-minus',
|
||||||
|
'user-ninja',
|
||||||
|
'user-nurse',
|
||||||
|
'user-plus',
|
||||||
|
'user-secret',
|
||||||
|
'user-shield',
|
||||||
|
'user-slash',
|
||||||
|
'user-tag',
|
||||||
|
'user-tie',
|
||||||
|
'user-times',
|
||||||
|
'users',
|
||||||
|
'users-cog',
|
||||||
|
'utensil-spoon',
|
||||||
|
'utensils',
|
||||||
|
'vector-square',
|
||||||
|
'venus',
|
||||||
|
'venus-double',
|
||||||
|
'venus-mars',
|
||||||
|
'vial',
|
||||||
|
'vials',
|
||||||
|
'video',
|
||||||
|
'video-slash',
|
||||||
|
'vihara',
|
||||||
|
'voicemail',
|
||||||
|
'volleyball-ball',
|
||||||
|
'volume-down',
|
||||||
|
'volume-mute',
|
||||||
|
'volume-off',
|
||||||
|
'volume-up',
|
||||||
|
'vote-yea',
|
||||||
|
'vr-cardboard',
|
||||||
|
'walking',
|
||||||
|
'wallet',
|
||||||
|
'warehouse',
|
||||||
|
'water',
|
||||||
|
'wave-square',
|
||||||
|
'weight',
|
||||||
|
'weight-hanging',
|
||||||
|
'wheelchair',
|
||||||
|
'wifi',
|
||||||
|
'wind',
|
||||||
|
'window-close',
|
||||||
|
'window-maximize',
|
||||||
|
'window-minimize',
|
||||||
|
'window-restore',
|
||||||
|
'wine-bottle',
|
||||||
|
'wine-glass',
|
||||||
|
'wine-glass-alt',
|
||||||
|
'won-sign',
|
||||||
|
'wrench',
|
||||||
|
'x-ray',
|
||||||
|
'yen-sign',
|
||||||
|
'yin-yang',
|
||||||
|
]
|
||||||
|
module.exports = [
|
||||||
|
{
|
||||||
|
url: '/icon/getList',
|
||||||
|
type: 'post',
|
||||||
|
response(config) {
|
||||||
|
const { title, pageNo = 1, pageSize = 72 } = config.body
|
||||||
|
let mockList = data.filter((item) => {
|
||||||
|
if (title && item.indexOf(title) < 0) return false
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
const pageList = mockList.filter((item, index) => index < pageSize * pageNo && index >= pageSize * (pageNo - 1))
|
||||||
|
return {
|
||||||
|
code: 200,
|
||||||
|
msg: 'success',
|
||||||
|
totalCount: mockList.length,
|
||||||
|
data: pageList,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
51
mock/controller/menuManagement.js
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
module.exports = [
|
||||||
|
{
|
||||||
|
url: '/menuManagement/getTree',
|
||||||
|
type: 'post',
|
||||||
|
response() {
|
||||||
|
return {
|
||||||
|
code: 200,
|
||||||
|
msg: 'success',
|
||||||
|
totalCount: 999,
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
id: 'root',
|
||||||
|
label: '全部角色',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
id: '@id',
|
||||||
|
permission: 'admin',
|
||||||
|
label: 'admin角色',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '@id',
|
||||||
|
permission: 'editor',
|
||||||
|
label: 'editor角色',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: '/menuManagement/doEdit',
|
||||||
|
type: 'post',
|
||||||
|
response() {
|
||||||
|
return {
|
||||||
|
code: 200,
|
||||||
|
msg: '模拟保存成功',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: '/menuManagement/doDelete',
|
||||||
|
type: 'post',
|
||||||
|
response() {
|
||||||
|
return {
|
||||||
|
code: 200,
|
||||||
|
msg: '模拟删除成功',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
42
mock/controller/personalCenter.js
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
const { mock } = require('mockjs')
|
||||||
|
|
||||||
|
module.exports = [
|
||||||
|
{
|
||||||
|
url: '/personalCenter/getList',
|
||||||
|
type: 'post',
|
||||||
|
response(config) {
|
||||||
|
return {
|
||||||
|
code: 200,
|
||||||
|
msg: 'success',
|
||||||
|
totalCount: 999,
|
||||||
|
data: mock({
|
||||||
|
'data|10': [
|
||||||
|
{
|
||||||
|
id: '@id',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}).data,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: '/personalCenter/doEdit',
|
||||||
|
type: 'post',
|
||||||
|
response() {
|
||||||
|
return {
|
||||||
|
code: 200,
|
||||||
|
msg: '模拟保存成功',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: '/personalCenter/doDelete',
|
||||||
|
type: 'post',
|
||||||
|
response() {
|
||||||
|
return {
|
||||||
|
code: 200,
|
||||||
|
msg: '模拟删除成功',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
50
mock/controller/roleManagement.js
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
const totalCount = 2
|
||||||
|
const List = [
|
||||||
|
{
|
||||||
|
id: '@id',
|
||||||
|
permission: 'admin',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '@id',
|
||||||
|
permission: 'editor',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
module.exports = [
|
||||||
|
{
|
||||||
|
url: '/roleManagement/getList',
|
||||||
|
type: 'post',
|
||||||
|
response(config) {
|
||||||
|
const { title = '', pageNo = 1, pageSize = 20 } = config.body
|
||||||
|
let mockList = List.filter((item) => {
|
||||||
|
return !(title && item.title.indexOf(title) < 0)
|
||||||
|
})
|
||||||
|
const pageList = mockList.filter((item, index) => index < pageSize * pageNo && index >= pageSize * (pageNo - 1))
|
||||||
|
return {
|
||||||
|
code: 200,
|
||||||
|
msg: 'success',
|
||||||
|
totalCount,
|
||||||
|
data: pageList,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: '/roleManagement/doEdit',
|
||||||
|
type: 'post',
|
||||||
|
response() {
|
||||||
|
return {
|
||||||
|
code: 200,
|
||||||
|
msg: '模拟保存成功',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: '/roleManagement/doDelete',
|
||||||
|
type: 'post',
|
||||||
|
response() {
|
||||||
|
return {
|
||||||
|
code: 200,
|
||||||
|
msg: '模拟删除成功',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
256
mock/controller/router.js
Normal file
@@ -0,0 +1,256 @@
|
|||||||
|
const data = [
|
||||||
|
{
|
||||||
|
path: '/',
|
||||||
|
component: 'Layout',
|
||||||
|
redirect: 'index',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'index',
|
||||||
|
name: 'Index',
|
||||||
|
component: '@/views/index/index',
|
||||||
|
meta: {
|
||||||
|
title: '首页',
|
||||||
|
icon: 'home',
|
||||||
|
affix: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/personnelManagement',
|
||||||
|
component: 'Layout',
|
||||||
|
redirect: 'noRedirect',
|
||||||
|
name: 'PersonnelManagement',
|
||||||
|
meta: { title: '人员', icon: 'users-cog', permissions: ['admin'] },
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'userManagement',
|
||||||
|
name: 'UserManagement',
|
||||||
|
component: '@/views/personnelManagement/userManagement/index',
|
||||||
|
meta: { title: '用户管理' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'roleManagement',
|
||||||
|
name: 'RoleManagement',
|
||||||
|
component: '@/views/personnelManagement/roleManagement/index',
|
||||||
|
meta: { title: '角色管理' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'menuManagement',
|
||||||
|
name: 'MenuManagement',
|
||||||
|
component: '@/views/personnelManagement/menuManagement/index',
|
||||||
|
meta: { title: '菜单管理', badge: 'New' },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/vab',
|
||||||
|
component: 'Layout',
|
||||||
|
redirect: 'noRedirect',
|
||||||
|
name: 'Vab',
|
||||||
|
alwaysShow: true,
|
||||||
|
meta: { title: '组件', icon: 'cloud' },
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'permissions',
|
||||||
|
name: 'Permission',
|
||||||
|
component: '@/views/vab/permissions/index',
|
||||||
|
meta: {
|
||||||
|
title: '权限控制',
|
||||||
|
permissions: ['admin', 'editor'],
|
||||||
|
badge: 'New',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'icon',
|
||||||
|
component: 'EmptyLayout',
|
||||||
|
redirect: 'noRedirect',
|
||||||
|
name: 'Icon',
|
||||||
|
meta: {
|
||||||
|
title: '图标',
|
||||||
|
permissions: ['admin'],
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'awesomeIcon',
|
||||||
|
name: 'AwesomeIcon',
|
||||||
|
component: '@/views/vab/icon/index',
|
||||||
|
meta: { title: '常规图标' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'colorfulIcon',
|
||||||
|
name: 'ColorfulIcon',
|
||||||
|
component: '@/views/vab/icon/colorfulIcon',
|
||||||
|
meta: { title: '多彩图标' },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'table',
|
||||||
|
component: '@/views/vab/table/index',
|
||||||
|
name: 'Table',
|
||||||
|
meta: {
|
||||||
|
title: '表格',
|
||||||
|
permissions: ['admin'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'webSocket',
|
||||||
|
name: 'WebSocket',
|
||||||
|
component: '@/views/vab/webSocket/index',
|
||||||
|
meta: { title: 'webSocket', permissions: ['admin'] },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'form',
|
||||||
|
name: 'Form',
|
||||||
|
component: '@/views/vab/form/index',
|
||||||
|
meta: { title: '表单', permissions: ['admin'] },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'element',
|
||||||
|
name: 'Element',
|
||||||
|
component: '@/views/vab/element/index',
|
||||||
|
meta: { title: '常用组件', permissions: ['admin'] },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'tree',
|
||||||
|
name: 'Tree',
|
||||||
|
component: '@/views/vab/tree/index',
|
||||||
|
meta: { title: '树', permissions: ['admin'] },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'verify',
|
||||||
|
name: 'Verify',
|
||||||
|
component: '@/views/vab/verify/index',
|
||||||
|
meta: { title: '验证码', permissions: ['admin'] },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'menu1',
|
||||||
|
component: '@/views/vab/nested/menu1/index',
|
||||||
|
name: 'Menu1',
|
||||||
|
alwaysShow: true,
|
||||||
|
meta: {
|
||||||
|
title: '嵌套路由 1',
|
||||||
|
permissions: ['admin'],
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'menu1-1',
|
||||||
|
name: 'Menu1-1',
|
||||||
|
alwaysShow: true,
|
||||||
|
meta: { title: '嵌套路由 1-1' },
|
||||||
|
component: '@/views/vab/nested/menu1/menu1-1/index',
|
||||||
|
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'menu1-1-1',
|
||||||
|
name: 'Menu1-1-1',
|
||||||
|
meta: { title: '嵌套路由 1-1-1' },
|
||||||
|
component: '@/views/vab/nested/menu1/menu1-1/menu1-1-1/index',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'loading',
|
||||||
|
name: 'Loading',
|
||||||
|
component: '@/views/vab/loading/index',
|
||||||
|
meta: { title: 'loading', permissions: ['admin'] },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'backToTop',
|
||||||
|
name: 'BackToTop',
|
||||||
|
component: '@/views/vab/backToTop/index',
|
||||||
|
meta: { title: '返回顶部', permissions: ['admin'] },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'lodash',
|
||||||
|
name: 'Lodash',
|
||||||
|
component: '@/views/vab/lodash/index',
|
||||||
|
meta: { title: 'lodash', permissions: ['admin'] },
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
path: 'upload',
|
||||||
|
name: 'Upload',
|
||||||
|
component: '@/views/vab/upload/index',
|
||||||
|
meta: { title: '上传', permissions: ['admin'] },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'log',
|
||||||
|
name: 'Log',
|
||||||
|
component: '@/views/vab/errorLog/index',
|
||||||
|
meta: { title: '错误日志模拟', permissions: ['admin'] },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'more',
|
||||||
|
name: 'More',
|
||||||
|
component: '@/views/vab/more/index',
|
||||||
|
meta: { title: '关于', permissions: ['admin'] },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/mall',
|
||||||
|
component: 'Layout',
|
||||||
|
redirect: 'noRedirect',
|
||||||
|
name: 'Mall',
|
||||||
|
meta: {
|
||||||
|
title: '商城',
|
||||||
|
icon: 'shopping-cart',
|
||||||
|
permissions: ['admin'],
|
||||||
|
},
|
||||||
|
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'pay',
|
||||||
|
name: 'Pay',
|
||||||
|
component: '@/views/mall/pay/index',
|
||||||
|
meta: {
|
||||||
|
title: '支付',
|
||||||
|
noKeepAlive: true,
|
||||||
|
},
|
||||||
|
children: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'goodsList',
|
||||||
|
name: 'GoodsList',
|
||||||
|
component: '@/views/mall/goodsList/index',
|
||||||
|
meta: {
|
||||||
|
title: '商品列表',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/error',
|
||||||
|
component: 'EmptyLayout',
|
||||||
|
redirect: 'noRedirect',
|
||||||
|
name: 'Error',
|
||||||
|
meta: { title: '错误页', icon: 'bug' },
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '401',
|
||||||
|
name: 'Error401',
|
||||||
|
component: '@/views/401',
|
||||||
|
meta: { title: '401' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '404',
|
||||||
|
name: 'Error404',
|
||||||
|
component: '@/views/404',
|
||||||
|
meta: { title: '404' },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
module.exports = [
|
||||||
|
{
|
||||||
|
url: '/menu/navigate',
|
||||||
|
type: 'post',
|
||||||
|
response() {
|
||||||
|
return { code: 200, msg: 'success', data: data }
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
85
mock/controller/table.js
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
const { mock } = require('mockjs')
|
||||||
|
const { handleRandomImage } = require('../utils')
|
||||||
|
|
||||||
|
const List = []
|
||||||
|
const count = 999
|
||||||
|
for (let i = 0; i < count; i++) {
|
||||||
|
List.push(
|
||||||
|
mock({
|
||||||
|
uuid: '@uuid',
|
||||||
|
id: '@id',
|
||||||
|
title: '@csentence(1, 2)',
|
||||||
|
'status|1': ['published', 'draft', 'deleted'],
|
||||||
|
author: '@cname',
|
||||||
|
datetime: '@datetime',
|
||||||
|
pageViews: '@integer(300, 5000)',
|
||||||
|
img: handleRandomImage(200, 200),
|
||||||
|
smallImg: handleRandomImage(40, 40),
|
||||||
|
switch: '@boolean',
|
||||||
|
percent: '@integer(80,99)',
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = [
|
||||||
|
{
|
||||||
|
url: '/table/getList',
|
||||||
|
type: 'post',
|
||||||
|
response(config) {
|
||||||
|
if (!config.body) {
|
||||||
|
return {
|
||||||
|
code: 200,
|
||||||
|
msg: 'success',
|
||||||
|
totalCount: count,
|
||||||
|
data: mock({
|
||||||
|
'data|50': [
|
||||||
|
{
|
||||||
|
id: '@id',
|
||||||
|
title: '@csentence(1, 2)',
|
||||||
|
'status|1': ['published', 'draft', 'deleted'],
|
||||||
|
author: '@cname',
|
||||||
|
datetime: '@datetime',
|
||||||
|
pageViews: '@integer(300, 5000)',
|
||||||
|
img: handleRandomImage(200, 200),
|
||||||
|
smallImg: handleRandomImage(40, 40),
|
||||||
|
switch: '@boolean',
|
||||||
|
percent: '@integer(80,99)',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}).data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const { title = '', pageNo = 1, pageSize = 20 } = config.body
|
||||||
|
let mockList = List.filter((item) => {
|
||||||
|
return !(title && item.title.indexOf(title) < 0)
|
||||||
|
})
|
||||||
|
const pageList = mockList.filter((item, index) => index < pageSize * pageNo && index >= pageSize * (pageNo - 1))
|
||||||
|
return {
|
||||||
|
code: 200,
|
||||||
|
msg: 'success',
|
||||||
|
totalCount: count,
|
||||||
|
data: pageList,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: '/table/doEdit',
|
||||||
|
type: 'post',
|
||||||
|
response() {
|
||||||
|
return {
|
||||||
|
code: 200,
|
||||||
|
msg: '模拟保存成功',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: '/table/doDelete',
|
||||||
|
type: 'post',
|
||||||
|
response() {
|
||||||
|
return {
|
||||||
|
code: 200,
|
||||||
|
msg: '模拟删除成功',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
54
mock/controller/tree.js
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
const data = [
|
||||||
|
{
|
||||||
|
id: '1',
|
||||||
|
parentId: '0',
|
||||||
|
name: 'root',
|
||||||
|
title: 'root',
|
||||||
|
text: 'root',
|
||||||
|
value: '1',
|
||||||
|
rank: 1,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
id: '32816b88ff72423f960e7d492a386131',
|
||||||
|
parentId: '1',
|
||||||
|
name: '一级',
|
||||||
|
title: '一级',
|
||||||
|
text: '一级',
|
||||||
|
value: '32816b88ff72423f960e7d492a386131',
|
||||||
|
rank: 2,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
id: '9e11afc35d55475fb0bd3164b9684cbe',
|
||||||
|
parentId: '32816b88ff72423f960e7d492a386131',
|
||||||
|
name: '二级',
|
||||||
|
title: '二级',
|
||||||
|
text: '二级',
|
||||||
|
value: '9e11afc35d55475fb0bd3164b9684cbe',
|
||||||
|
rank: 3,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
id: '4cc1b04635e4444292526c5391699077',
|
||||||
|
parentId: '9e11afc35d55475fb0bd3164b9684cbe',
|
||||||
|
name: '三级',
|
||||||
|
title: '三级',
|
||||||
|
text: '三级',
|
||||||
|
value: '4cc1b04635e4444292526c5391699077',
|
||||||
|
rank: 4,
|
||||||
|
children: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
module.exports = [
|
||||||
|
{
|
||||||
|
url: '/tree/list',
|
||||||
|
type: 'post',
|
||||||
|
response() {
|
||||||
|
return { code: 200, msg: 'success', data }
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
98
mock/controller/user.js
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
const accessTokens = {
|
||||||
|
admin: 'admin-accessToken',
|
||||||
|
editor: 'editor-accessToken',
|
||||||
|
test: 'test-accessToken',
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = [
|
||||||
|
{
|
||||||
|
url: '/publicKey',
|
||||||
|
type: 'post',
|
||||||
|
response() {
|
||||||
|
return {
|
||||||
|
code: 200,
|
||||||
|
msg: 'success',
|
||||||
|
data: {
|
||||||
|
mockServer: true,
|
||||||
|
publicKey:
|
||||||
|
'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBT2vr+dhZElF73FJ6xiP181txKWUSNLPQQlid6DUJhGAOZblluafIdLmnUyKE8mMHhT3R+Ib3ssZcJku6Hn72yHYj/qPkCGFv0eFo7G+GJfDIUeDyalBN0QsuiE/XzPHJBuJDfRArOiWvH0BXOv5kpeXSXM8yTt5Na1jAYSiQ/wIDAQAB',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: '/login',
|
||||||
|
type: 'post',
|
||||||
|
response(config) {
|
||||||
|
const { username } = config.body
|
||||||
|
const accessToken = accessTokens[username]
|
||||||
|
if (!accessToken) {
|
||||||
|
return {
|
||||||
|
code: 500,
|
||||||
|
msg: '帐户或密码不正确。',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
code: 200,
|
||||||
|
msg: 'success',
|
||||||
|
data: { accessToken },
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: '/register',
|
||||||
|
type: 'post',
|
||||||
|
response() {
|
||||||
|
return {
|
||||||
|
code: 200,
|
||||||
|
msg: '模拟注册成功',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: '/userInfo',
|
||||||
|
type: 'post',
|
||||||
|
response(config) {
|
||||||
|
const { accessToken } = config.body
|
||||||
|
let permissions = ['admin']
|
||||||
|
let username = 'admin'
|
||||||
|
if ('admin-accessToken' === accessToken) {
|
||||||
|
permissions = ['admin']
|
||||||
|
username = 'admin'
|
||||||
|
}
|
||||||
|
if ('editor-accessToken' === accessToken) {
|
||||||
|
permissions = ['editor']
|
||||||
|
username = 'editor'
|
||||||
|
}
|
||||||
|
if ('test-accessToken' === accessToken) {
|
||||||
|
permissions = ['admin', 'editor']
|
||||||
|
username = 'test'
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
code: 200,
|
||||||
|
msg: 'success',
|
||||||
|
data: {
|
||||||
|
permissions,
|
||||||
|
username,
|
||||||
|
'avatar|1': [
|
||||||
|
'https://gcore.jsdelivr.net/gh/zxwk1998/image/avatar/avatar_1.png',
|
||||||
|
'https://gcore.jsdelivr.net/gh/zxwk1998/image/avatar/avatar_2.png',
|
||||||
|
'https://gcore.jsdelivr.net/gh/zxwk1998/image/avatar/avatar_3.png',
|
||||||
|
'https://gcore.jsdelivr.net/gh/zxwk1998/image/avatar/avatar_4.png',
|
||||||
|
'https://gcore.jsdelivr.net/gh/zxwk1998/image/avatar/avatar_5.png',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: '/logout',
|
||||||
|
type: 'post',
|
||||||
|
response() {
|
||||||
|
return {
|
||||||
|
code: 200,
|
||||||
|
msg: 'success',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
67
mock/controller/userManagement.js
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
const totalCount = 3
|
||||||
|
const List = [
|
||||||
|
{
|
||||||
|
id: '@id',
|
||||||
|
username: 'admin',
|
||||||
|
password: 'admin',
|
||||||
|
email: '@email',
|
||||||
|
permissions: ['admin'],
|
||||||
|
datatime: '@datetime',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '@id',
|
||||||
|
username: 'editor',
|
||||||
|
password: 'editor',
|
||||||
|
email: '@email',
|
||||||
|
permissions: ['editor'],
|
||||||
|
datatime: '@datetime',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '@id',
|
||||||
|
username: 'test',
|
||||||
|
password: 'test',
|
||||||
|
email: '@email',
|
||||||
|
permissions: ['admin', 'editor'],
|
||||||
|
datatime: '@datetime',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
module.exports = [
|
||||||
|
{
|
||||||
|
url: '/userManagement/getList',
|
||||||
|
type: 'post',
|
||||||
|
response(config) {
|
||||||
|
const { title = '', pageNo = 1, pageSize = 20 } = config.body
|
||||||
|
let mockList = List.filter((item) => {
|
||||||
|
if (title && item.title.indexOf(title) < 0) return false
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
const pageList = mockList.filter((item, index) => index < pageSize * pageNo && index >= pageSize * (pageNo - 1))
|
||||||
|
return {
|
||||||
|
code: 200,
|
||||||
|
msg: 'success',
|
||||||
|
totalCount,
|
||||||
|
data: pageList,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: '/userManagement/doEdit',
|
||||||
|
type: 'post',
|
||||||
|
response() {
|
||||||
|
return {
|
||||||
|
code: 200,
|
||||||
|
msg: '模拟保存成功',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: '/userManagement/doDelete',
|
||||||
|
type: 'post',
|
||||||
|
response() {
|
||||||
|
return {
|
||||||
|
code: 200,
|
||||||
|
msg: '模拟删除成功',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
98
mock/index.js
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
const chokidar = require('chokidar')
|
||||||
|
const bodyParser = require('body-parser')
|
||||||
|
const chalk = require('chalk')
|
||||||
|
const path = require('path')
|
||||||
|
const { mock } = require('mockjs')
|
||||||
|
const { baseURL } = require('../src/config')
|
||||||
|
const mockDir = path.join(process.cwd(), 'mock')
|
||||||
|
const { handleMockArray } = require('./utils')
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param app
|
||||||
|
* @returns {{mockStartIndex: number, mockRoutesLength: number}}
|
||||||
|
*/
|
||||||
|
const registerRoutes = (app) => {
|
||||||
|
let mockLastIndex
|
||||||
|
const mocks = []
|
||||||
|
const mockArray = handleMockArray()
|
||||||
|
mockArray.forEach((item) => {
|
||||||
|
const obj = require(item)
|
||||||
|
mocks.push(...obj)
|
||||||
|
})
|
||||||
|
const mocksForServer = mocks.map((route) => {
|
||||||
|
return responseFake(route.url, route.type, route.response)
|
||||||
|
})
|
||||||
|
for (const mock of mocksForServer) {
|
||||||
|
app[mock.type](mock.url, mock.response)
|
||||||
|
mockLastIndex = app._router.stack.length
|
||||||
|
}
|
||||||
|
const mockRoutesLength = Object.keys(mocksForServer).length
|
||||||
|
return {
|
||||||
|
mockRoutesLength: mockRoutesLength,
|
||||||
|
mockStartIndex: mockLastIndex - mockRoutesLength,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param url
|
||||||
|
* @param type
|
||||||
|
* @param respond
|
||||||
|
* @returns {{response(*=, *=): void, type: (*|string), url: RegExp}}
|
||||||
|
*/
|
||||||
|
const responseFake = (url, type, respond) => {
|
||||||
|
return {
|
||||||
|
url: new RegExp(`${baseURL}${url}`),
|
||||||
|
type: type || 'get',
|
||||||
|
response(req, res) {
|
||||||
|
res.status(200)
|
||||||
|
if (JSON.stringify(req.body) !== '{}') {
|
||||||
|
console.log(chalk.green(`> 请求地址:${req.path}`))
|
||||||
|
console.log(chalk.green(`> 请求参数:${JSON.stringify(req.body)}\n`))
|
||||||
|
} else {
|
||||||
|
console.log(chalk.green(`> 请求地址:${req.path}\n`))
|
||||||
|
}
|
||||||
|
res.json(mock(respond instanceof Function ? respond(req, res) : respond))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param app
|
||||||
|
*/
|
||||||
|
module.exports = (app) => {
|
||||||
|
app.use(bodyParser.json())
|
||||||
|
app.use(
|
||||||
|
bodyParser.urlencoded({
|
||||||
|
extended: true,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
const mockRoutes = registerRoutes(app)
|
||||||
|
let mockRoutesLength = mockRoutes.mockRoutesLength
|
||||||
|
let mockStartIndex = mockRoutes.mockStartIndex
|
||||||
|
chokidar
|
||||||
|
.watch(mockDir, {
|
||||||
|
ignored: /mock-server/,
|
||||||
|
ignoreInitial: true,
|
||||||
|
})
|
||||||
|
.on('all', (event) => {
|
||||||
|
if (event === 'change' || event === 'add') {
|
||||||
|
try {
|
||||||
|
app._router.stack.splice(mockStartIndex, mockRoutesLength)
|
||||||
|
|
||||||
|
Object.keys(require.cache).forEach((item) => {
|
||||||
|
if (item.includes(mockDir)) {
|
||||||
|
delete require.cache[require.resolve(item)]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const mockRoutes = registerRoutes(app)
|
||||||
|
mockRoutesLength = mockRoutes.mockRoutesLength
|
||||||
|
mockStartIndex = mockRoutes.mockStartIndex
|
||||||
|
} catch (error) {
|
||||||
|
console.log(chalk.red(error))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
44
mock/utils/index.js
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
const { Random } = require('mockjs')
|
||||||
|
const { join } = require('path')
|
||||||
|
const fs = require('fs')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author https://github.com/zxwk1998/vue-admin-better (不想保留author可删除)
|
||||||
|
* @description 随机生成图片url。
|
||||||
|
* @param width
|
||||||
|
* @param height
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function handleRandomImage(width = 50, height = 50) {
|
||||||
|
return `https://picsum.photos/${width}/${height}?random=${Random.guid()}`
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author https://github.com/zxwk1998/vue-admin-better (不想保留author可删除)
|
||||||
|
* @description 处理所有 controller 模块,npm run serve时在node环境中自动输出controller文件夹下Mock接口,请勿修改。
|
||||||
|
* @returns {[]}
|
||||||
|
*/
|
||||||
|
function handleMockArray() {
|
||||||
|
const mockArray = []
|
||||||
|
const getFiles = (jsonPath) => {
|
||||||
|
const jsonFiles = []
|
||||||
|
const findJsonFile = (path) => {
|
||||||
|
const files = fs.readdirSync(path)
|
||||||
|
files.forEach((item) => {
|
||||||
|
const fPath = join(path, item)
|
||||||
|
const stat = fs.statSync(fPath)
|
||||||
|
if (stat.isDirectory() === true) findJsonFile(item)
|
||||||
|
if (stat.isFile() === true) jsonFiles.push(item)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
findJsonFile(jsonPath)
|
||||||
|
jsonFiles.forEach((item) => mockArray.push(`./controller/${item}`))
|
||||||
|
}
|
||||||
|
getFiles('mock/controller')
|
||||||
|
return mockArray
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
handleRandomImage,
|
||||||
|
handleMockArray,
|
||||||
|
}
|
||||||
98
package.json
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
{
|
||||||
|
"name": "vue-admin-better",
|
||||||
|
"version": "2.5.6",
|
||||||
|
"author": "zxwk1998",
|
||||||
|
"participants": [],
|
||||||
|
"homepage": "https://vuejs-core.cn",
|
||||||
|
"scripts": {
|
||||||
|
"serve": "vue-cli-service serve",
|
||||||
|
"build": "vue-cli-service build",
|
||||||
|
"serve:node20": "set NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service serve",
|
||||||
|
"build:node20": "set NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service build",
|
||||||
|
"serve:mac": "export NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service serve",
|
||||||
|
"build:mac": "export NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service build",
|
||||||
|
"lint": "vue-cli-service lint --fix",
|
||||||
|
"lint:eslint": "eslint {src,mock,library}/**/*.{vue,js} --fix",
|
||||||
|
"lint:prettier": "prettier {src,mock,library}/**/*.{html,vue,css,sass,scss,js,ts,md} --write",
|
||||||
|
"clear": "rimraf node_modules&&npm install --registry=--registry=https://registry.npmmirror.com",
|
||||||
|
"update": "ncu -u --reject vue-echarts,webpack,eslint-plugin-prettier,@vue/eslint-config-prettier,prettier,layouts,sass-loader,sass,screenfull,eslint,chalk,vue,vue-template-compiler,vue-router,vuex,@vue/cli-plugin-babel,@vue/cli-plugin-eslint,@vue/cli-service,eslint-plugin-vue --registry=https://registry.npmmirror.com&&pnpm i",
|
||||||
|
"push": "start ./push.sh"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/zxwk1998/vue-admin-better.git"
|
||||||
|
},
|
||||||
|
"gitHooks": {
|
||||||
|
"pre-commit": "lint-staged"
|
||||||
|
},
|
||||||
|
"lint-staged": {
|
||||||
|
"*.{js,jsx,vue}": [
|
||||||
|
"vue-cli-service lint",
|
||||||
|
"git add"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^1.7.9",
|
||||||
|
"caniuse-lite": "^1.0.30001700",
|
||||||
|
"clipboard": "^2.0.11",
|
||||||
|
"core-js": "^3.40.0",
|
||||||
|
"dayjs": "^1.11.13",
|
||||||
|
"echarts": "5.6.0",
|
||||||
|
"element-ui": "^2.15.14",
|
||||||
|
"jsencrypt": "^3.3.2",
|
||||||
|
"layouts": "file:layouts",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
|
"mockjs": "^1.1.0",
|
||||||
|
"nprogress": "^0.2.0",
|
||||||
|
"qs": "^6.14.0",
|
||||||
|
"quill": "^2.0.3",
|
||||||
|
"screenfull": "^5.2.0",
|
||||||
|
"sortablejs": "^1.15.6",
|
||||||
|
"vab-icon": "file:vab-icon",
|
||||||
|
"vue": "~2.7.14",
|
||||||
|
"vue-echarts": "6.7.3",
|
||||||
|
"vue-quill-editor": "^3.0.6",
|
||||||
|
"vue-router": "^3.6.5",
|
||||||
|
"vue-template-compiler": "~2.7.14",
|
||||||
|
"vuex": "^3.6.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@vue/cli-plugin-babel": "^4.5.19",
|
||||||
|
"@vue/cli-plugin-eslint": "^4.5.19",
|
||||||
|
"@vue/cli-service": "^4.5.19",
|
||||||
|
"@vue/eslint-config-prettier": "^6.0.0",
|
||||||
|
"babel-eslint": "^10.1.0",
|
||||||
|
"body-parser": "^1.20.3",
|
||||||
|
"chalk": "^4.1.2",
|
||||||
|
"chokidar": "^4.0.3",
|
||||||
|
"eslint": "^6.8.0",
|
||||||
|
"eslint-plugin-prettier": "^3.4.1",
|
||||||
|
"eslint-plugin-vue": "^9.1.1",
|
||||||
|
"image-webpack-loader": "^8.1.0",
|
||||||
|
"lint-staged": "^15.4.3",
|
||||||
|
"prettier": "^2.8.8",
|
||||||
|
"sass": "~1.32.13",
|
||||||
|
"sass-loader": "^10.1.1",
|
||||||
|
"stylelint": "^16.14.1",
|
||||||
|
"stylelint-config-prettier": "^9.0.5",
|
||||||
|
"stylelint-config-recess-order": "^6.0.0",
|
||||||
|
"svg-sprite-loader": "^6.0.11",
|
||||||
|
"webpack": "4.46.0",
|
||||||
|
"webpackbar": "^7.0.0"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"vue",
|
||||||
|
"admin",
|
||||||
|
"dashboard",
|
||||||
|
"element-ui",
|
||||||
|
"vue-admin",
|
||||||
|
"element-admin",
|
||||||
|
"boilerplate",
|
||||||
|
"admin-template",
|
||||||
|
"management-system"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.9",
|
||||||
|
"npm": ">= 3.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
11987
pnpm-lock.yaml
generated
Normal file
20
prettier.config.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
/**
|
||||||
|
* @author https://vuejs-core.cn (不想保留author可删除)
|
||||||
|
* @description 代码规范
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
printWidth: 140,
|
||||||
|
tabWidth: 2,
|
||||||
|
useTabs: false,
|
||||||
|
semi: false,
|
||||||
|
singleQuote: true,
|
||||||
|
quoteProps: 'as-needed',
|
||||||
|
jsxSingleQuote: false,
|
||||||
|
trailingComma: 'es5',
|
||||||
|
bracketSpacing: true,
|
||||||
|
arrowParens: 'always',
|
||||||
|
htmlWhitespaceSensitivity: 'ignore',
|
||||||
|
vueIndentScriptAndStyle: true,
|
||||||
|
endOfLine: 'lf',
|
||||||
|
}
|
||||||
BIN
public/favicon.ico
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
public/favicon_backup.ico
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
41
public/index.html
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-cmn-Hans">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta content="IE=edge" http-equiv="X-UA-Compatible" />
|
||||||
|
<meta content="width=device-width,initial-scale=1.0" name="viewport" />
|
||||||
|
<link href="<%= BASE_URL %>favicon.ico" rel="icon" />
|
||||||
|
<title>后台管理系统</title>
|
||||||
|
<meta content="后台管理系统" name="author" />
|
||||||
|
<link href="<%= BASE_URL %>static/css/loading.css" rel="stylesheet" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="vue-admin-better">
|
||||||
|
<div class="first-loading-wrp">
|
||||||
|
<div class="loading-wrp">
|
||||||
|
<span class="dot dot-spin">
|
||||||
|
<i></i>
|
||||||
|
<i></i>
|
||||||
|
<i></i>
|
||||||
|
<i></i>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<h1><%= VUE_APP_TITLE %></h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
;/^http(s*):\/\//.test(location.href) || alert('基于vue-admin-beautiful-pro开源版开发的项目需要部署到服务器下访问')
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
if (window.location.hostname !== 'localhost') {
|
||||||
|
var _hmt = _hmt || []
|
||||||
|
;(function () {
|
||||||
|
var hm = document.createElement('script')
|
||||||
|
hm.src = 'https://hm.baidu.com/hm.js?7174bade1219f9cc272e7978f9523fc8'
|
||||||
|
var s = document.getElementsByTagName('script')[0]
|
||||||
|
s.parentNode.insertBefore(hm, s)
|
||||||
|
})()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
2
public/robots.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
User-agent: *
|
||||||
|
Allow: /
|
||||||
99
public/static/css/loading.css
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
/**
|
||||||
|
* @description 雪花屏代码,基于ant-design修改
|
||||||
|
**/
|
||||||
|
.first-loading-wrp {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 90vh;
|
||||||
|
min-height: 90vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.first-loading-wrp > h1 {
|
||||||
|
font-size: 30px;
|
||||||
|
font-weight: bolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
.first-loading-wrp .loading-wrp {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 98px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dot {
|
||||||
|
position: relative;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: inline-block;
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
font-size: 64px;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
animation: antRotate 1.2s infinite linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dot i {
|
||||||
|
position: absolute;
|
||||||
|
display: block;
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
background-color: #1890ff;
|
||||||
|
border-radius: 100%;
|
||||||
|
opacity: 0.3;
|
||||||
|
transform: scale(0.75);
|
||||||
|
transform-origin: 50% 50%;
|
||||||
|
animation: antSpinMove 1s infinite linear alternate;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dot i:nth-child(1) {
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dot i:nth-child(2) {
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
-webkit-animation-delay: 0.4s;
|
||||||
|
animation-delay: 0.4s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dot i:nth-child(3) {
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
-webkit-animation-delay: 0.8s;
|
||||||
|
animation-delay: 0.8s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dot i:nth-child(4) {
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
-webkit-animation-delay: 1.2s;
|
||||||
|
animation-delay: 1.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes antRotate {
|
||||||
|
to {
|
||||||
|
-webkit-transform: rotate(405deg);
|
||||||
|
transform: rotate(405deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes antRotate {
|
||||||
|
to {
|
||||||
|
-webkit-transform: rotate(405deg);
|
||||||
|
transform: rotate(405deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes antSpinMove {
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes antSpinMove {
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
12
push.sh
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#强制推送
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -e
|
||||||
|
git init
|
||||||
|
git add -A
|
||||||
|
git commit -m '🎉 feat: init project'
|
||||||
|
git push -f "https://${access_token}@github.com/zxwk1998/vue-admin-better.git" master
|
||||||
|
exec /bin/bash
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
12
src/App.vue
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<template>
|
||||||
|
<div id="vue-admin-better">
|
||||||
|
<router-view />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'App',
|
||||||
|
mounted() {},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
8
src/api/ad.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export function getList() {
|
||||||
|
return request({
|
||||||
|
url: 'https://api.vuejs-core.cn/getAd',
|
||||||
|
method: 'get',
|
||||||
|
})
|
||||||
|
}
|
||||||
33
src/api/appManagement.js
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export function getList(data) {
|
||||||
|
return request({
|
||||||
|
url: '/management/api/app/list',
|
||||||
|
method: 'get',
|
||||||
|
params: data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doAdd(data) {
|
||||||
|
return request({
|
||||||
|
url: '/management/api/app',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doEdit(id, data) {
|
||||||
|
return request({
|
||||||
|
url: `/management/api/app/${id}`,
|
||||||
|
method: 'put',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doDelete(data) {
|
||||||
|
return request({
|
||||||
|
url: '/management/api/app/delete',
|
||||||
|
method: 'put',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
9
src/api/colorfulIcon.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export function getIconList(data) {
|
||||||
|
return request({
|
||||||
|
url: '/colorfulIcon/getList',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
19
src/api/github.js
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import request from 'axios'
|
||||||
|
|
||||||
|
export function getRepos(params) {
|
||||||
|
return request({
|
||||||
|
url: 'https://api.github.com/repos/zxwk1998/vue-admin-better',
|
||||||
|
method: 'get',
|
||||||
|
params,
|
||||||
|
timeout: 10000,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getStargazers(params) {
|
||||||
|
return request({
|
||||||
|
url: 'https://api.github.com/repos/zxwk1998/vue-admin-better/stargazers',
|
||||||
|
method: 'get',
|
||||||
|
params,
|
||||||
|
timeout: 10000,
|
||||||
|
})
|
||||||
|
}
|
||||||
9
src/api/goodsList.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export function getList(data) {
|
||||||
|
return request({
|
||||||
|
url: '/goodsList/getList',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
9
src/api/icon.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export function getIconList(data) {
|
||||||
|
return request({
|
||||||
|
url: '/icon/getList',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
8
src/api/markdown.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import request from 'axios'
|
||||||
|
|
||||||
|
export function getList() {
|
||||||
|
return request({
|
||||||
|
url: 'https://gcore.jsdelivr.net/gh/prettier/prettier@master/docs/options.md',
|
||||||
|
method: 'get',
|
||||||
|
})
|
||||||
|
}
|
||||||
25
src/api/menuManagement.js
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export function getTree(data) {
|
||||||
|
return request({
|
||||||
|
url: '/menuManagement/getTree',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doEdit(data) {
|
||||||
|
return request({
|
||||||
|
url: '/menuManagement/doEdit',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doDelete(data) {
|
||||||
|
return request({
|
||||||
|
url: '/menuManagement/doDelete',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
33
src/api/miniAnliCategory.js
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export function getList(data) {
|
||||||
|
return request({
|
||||||
|
url: '/management/api/role/list',
|
||||||
|
method: 'get',
|
||||||
|
params: data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doAdd(data) {
|
||||||
|
return request({
|
||||||
|
url: '/management/api/role',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doEdit(id, data) {
|
||||||
|
return request({
|
||||||
|
url: `/management/api/role/${id}`,
|
||||||
|
method: 'put',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doDelete(data) {
|
||||||
|
return request({
|
||||||
|
url: '/management/api/role/delete',
|
||||||
|
method: 'put',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
8
src/api/notice.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export function getNoticeList() {
|
||||||
|
return request({
|
||||||
|
url: 'https://api.vuejs-core.cn/getNotice',
|
||||||
|
method: 'get',
|
||||||
|
})
|
||||||
|
}
|
||||||
25
src/api/personalCenter.js
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export function getList(data) {
|
||||||
|
return request({
|
||||||
|
url: '/personalCenter/getList',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doEdit(data) {
|
||||||
|
return request({
|
||||||
|
url: '/personalCenter/doEdit',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doDelete(data) {
|
||||||
|
return request({
|
||||||
|
url: '/personalCenter/doDelete',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
8
src/api/publicKey.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export function getPublicKey() {
|
||||||
|
return request({
|
||||||
|
url: '/api/auth/publicKey',
|
||||||
|
method: 'get',
|
||||||
|
})
|
||||||
|
}
|
||||||
9
src/api/remixIcon.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export function getIconList(data) {
|
||||||
|
return request({
|
||||||
|
url: '/remixIcon/getList',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
33
src/api/roleManagement.js
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export function getList(data) {
|
||||||
|
return request({
|
||||||
|
url: '/management/api/role/list',
|
||||||
|
method: 'get',
|
||||||
|
params: data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doAdd(data) {
|
||||||
|
return request({
|
||||||
|
url: '/management/api/role',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doEdit(id, data) {
|
||||||
|
return request({
|
||||||
|
url: `/management/api/role/${id}`,
|
||||||
|
method: 'put',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doDelete(data) {
|
||||||
|
return request({
|
||||||
|
url: '/management/api/role/delete',
|
||||||
|
method: 'put',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
9
src/api/router.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export function getRouterList(data) {
|
||||||
|
return request({
|
||||||
|
url: '/menu/navigate',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
25
src/api/table.js
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export function getList(data) {
|
||||||
|
return request({
|
||||||
|
url: '/table/getList',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doEdit(data) {
|
||||||
|
return request({
|
||||||
|
url: '/table/doEdit',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doDelete(data) {
|
||||||
|
return request({
|
||||||
|
url: '/table/doDelete',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
9
src/api/tree.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export function getTreeList(data) {
|
||||||
|
return request({
|
||||||
|
url: '/tree/list',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
38
src/api/user.js
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
import { encryptedData } from '@/utils/encrypt'
|
||||||
|
import { loginRSA, tokenName } from '@/config'
|
||||||
|
|
||||||
|
export async function login(data) {
|
||||||
|
if (loginRSA) {
|
||||||
|
data = await encryptedData(data)
|
||||||
|
}
|
||||||
|
return request({
|
||||||
|
url: '/api/auth/login',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getUserInfo(accessToken) {
|
||||||
|
return request({
|
||||||
|
url: '/management/api/user/current',
|
||||||
|
method: 'post',
|
||||||
|
data: {
|
||||||
|
[tokenName]: accessToken,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function logout() {
|
||||||
|
return request({
|
||||||
|
url: '/api/auth/logout',
|
||||||
|
method: 'post',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function register() {
|
||||||
|
return request({
|
||||||
|
url: '/register',
|
||||||
|
method: 'post',
|
||||||
|
})
|
||||||
|
}
|
||||||
25
src/api/userManagement.js
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export function getList(data) {
|
||||||
|
return request({
|
||||||
|
url: `/management/api/user/list`,
|
||||||
|
method: 'get',
|
||||||
|
params: data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doEdit(data) {
|
||||||
|
return request({
|
||||||
|
url: '/management/api/user/create',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doDelete(data) {
|
||||||
|
return request({
|
||||||
|
url: '/userManagement/doDelete',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
BIN
src/assets/comparison/left.jpg
Normal file
|
After Width: | Height: | Size: 73 KiB |
BIN
src/assets/comparison/right.jpg
Normal file
|
After Width: | Height: | Size: 95 KiB |
BIN
src/assets/error_images/401.png
Normal file
|
After Width: | Height: | Size: 57 KiB |
BIN
src/assets/error_images/404.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
src/assets/error_images/cloud.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
src/assets/ewm.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
src/assets/login_images/background.jpg
Normal file
|
After Width: | Height: | Size: 133 KiB |
BIN
src/assets/pro.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
src/assets/qr_logo/lqr_logo.png
Normal file
|
After Width: | Height: | Size: 8.6 KiB |
BIN
src/assets/zfb_100.jpg
Normal file
|
After Width: | Height: | Size: 102 KiB |
BIN
src/assets/zfb_699.jpg
Normal file
|
After Width: | Height: | Size: 105 KiB |
BIN
src/assets/zfb_799.jpg
Normal file
|
After Width: | Height: | Size: 102 KiB |
BIN
src/assets/zfb_kf.jpg
Normal file
|
After Width: | Height: | Size: 122 KiB |
13
src/colorfulIcon/index.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
const req = require.context('./svg', false, /\.svg$/),
|
||||||
|
requireAll = (requireContext) => {
|
||||||
|
/*let a = requireContext.keys().map(requireContext);
|
||||||
|
let arr = [];
|
||||||
|
for (let i = 0; i < a.length; i++) {
|
||||||
|
console.log();
|
||||||
|
let icon = a[i].default.id;
|
||||||
|
arr.push(icon);
|
||||||
|
}
|
||||||
|
console.log(JSON.stringify(arr));*/
|
||||||
|
return requireContext.keys().map(requireContext)
|
||||||
|
}
|
||||||
|
requireAll(req)
|
||||||
6
src/colorfulIcon/svg/alphabetical_sorting.svg
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<svg class="icon" width="128" height="128" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path
|
||||||
|
d="M358.4 853.333H245.333l-23.466 64H147.2l121.6-324.266h61.867l119.466 324.266h-68.266l-23.467-64zm-98.133-57.6h81.066l-40.533-121.6-40.533 121.6zm4.266-418.133h162.134v53.333H179.2V390.4L341.333 160H179.2v-53.333h243.2v36.266L264.533 377.6z"
|
||||||
|
fill="#2196F3"/>
|
||||||
|
<path d="M810.667 704V106.667h-85.334V704h-128L768 917.333 938.667 704z" fill="#546E7A"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 479 B |
24
src/colorfulIcon/svg/vab.svg
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<svg version="1.1" id="Layer_1"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="550px" height="400px"
|
||||||
|
xml:space="preserve">
|
||||||
|
<g id="PathID_1" transform="matrix(10.7099, 0, 0, 10.7099, 76.4, 396.15)" opacity="1">
|
||||||
|
<path style="fill: #41b882; fill-opacity: 1;"
|
||||||
|
d="M3.75 -36.65L18.4 -36.65Q22.75 -36.65 24.85 -36.25Q27 -35.9 28.7 -34.75Q30.4 -33.6 31.5 -31.7Q32.65 -29.8 32.65 -27.4Q32.65 -24.85 31.25 -22.7Q29.85 -20.55 27.5 -19.5Q30.85 -18.5 32.65 -16.15Q34.45 -13.8 34.45 -10.6Q34.45 -8.1 33.25 -5.75Q32.1 -3.4 30.1 -1.95Q28.1 -0.55 25.15 -0.25Q23.3 -0.05 16.2 0L3.75 0L3.75 -36.65M11.15 -30.55L11.15 -22.1L16 -22.1Q20.3 -22.1 21.35 -22.2Q23.25 -22.4 24.35 -23.5Q25.45 -24.6 25.45 -26.35Q25.45 -28.05 24.5 -29.1Q23.55 -30.2 21.7 -30.4Q20.6 -30.55 15.4 -30.55L11.15 -30.55M11.15 -16L11.15 -6.2L18 -6.2Q22 -6.2 23.05 -6.4Q24.7 -6.7 25.75 -7.85Q26.8 -9.05 26.8 -11Q26.8 -12.65 26 -13.8Q25.2 -14.95 23.65 -15.45Q22.15 -16 17.1 -16L11.15 -16"/>
|
||||||
|
</g>
|
||||||
|
<g id="PathID_2" transform="matrix(10.7099, 0, 0, 10.7099, 76.4, 396.15)" opacity="1">
|
||||||
|
</g>
|
||||||
|
<g id="PathID_3" transform="matrix(5.31826, 0, 0, 2.59618, 172.9, 161.55)" opacity="1">
|
||||||
|
<path style="fill: #35495e; fill-opacity: 1;"
|
||||||
|
d="M3.75 -36.65L17.25 -36.65Q21.8 -36.65 24.2 -35.95Q27.45 -35 29.75 -32.55Q32.05 -30.15 33.25 -26.6Q34.45 -23.1 34.45 -17.95Q34.45 -13.45 33.3 -10.15Q31.95 -6.15 29.4 -3.7Q27.45 -1.8 24.2 -0.75Q21.75 0 17.65 0L3.75 0L3.75 -36.65M11.15 -30.45L11.15 -6.2L16.65 -6.2Q19.75 -6.2 21.1 -6.55Q22.9 -6.95 24.1 -8Q25.3 -9.1 26.05 -11.55Q26.8 -14.05 26.8 -18.3Q26.8 -22.55 26.05 -24.8Q25.3 -27.1 23.95 -28.35Q22.6 -29.65 20.5 -30.1Q18.95 -30.45 14.45 -30.45L11.15 -30.45"/>
|
||||||
|
</g>
|
||||||
|
<g id="PathID_4" transform="matrix(5.31826, 0, 0, 2.59618, 172.9, 161.55)" opacity="1">
|
||||||
|
</g>
|
||||||
|
<g id="PathID_5" transform="matrix(5.78477, 0, 0, 3.1825, 171.7, 333.8)" opacity="1">
|
||||||
|
<path style="fill: #35495e; fill-opacity: 1;"
|
||||||
|
d="M3.75 -36.65L17.25 -36.65Q21.8 -36.65 24.2 -35.95Q27.45 -35 29.75 -32.55Q32.05 -30.15 33.25 -26.6Q34.45 -23.1 34.45 -17.95Q34.45 -13.45 33.3 -10.15Q31.95 -6.15 29.4 -3.7Q27.45 -1.8 24.2 -0.75Q21.75 0 17.65 0L3.75 0L3.75 -36.65M11.15 -30.45L11.15 -6.2L16.65 -6.2Q19.75 -6.2 21.1 -6.55Q22.9 -6.95 24.1 -8Q25.3 -9.1 26.05 -11.55Q26.8 -14.05 26.8 -18.3Q26.8 -22.55 26.05 -24.8Q25.3 -27.1 23.95 -28.35Q22.6 -29.65 20.5 -30.1Q18.95 -30.45 14.45 -30.45L11.15 -30.45"/>
|
||||||
|
</g>
|
||||||
|
<g id="PathID_6" transform="matrix(5.78477, 0, 0, 3.1825, 171.7, 333.8)" opacity="1">
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.4 KiB |
187
src/components/SelectTree/index.vue
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
<template>
|
||||||
|
<div class="select-tree-template">
|
||||||
|
<el-select
|
||||||
|
v-model="selectValue"
|
||||||
|
class="vab-tree-select"
|
||||||
|
:clearable="clearable"
|
||||||
|
:collapse-tags="selectType == 'multiple'"
|
||||||
|
:multiple="selectType == 'multiple'"
|
||||||
|
value-key="id"
|
||||||
|
@clear="clearHandle"
|
||||||
|
@remove-tag="removeTag"
|
||||||
|
>
|
||||||
|
<el-option :value="selectKey">
|
||||||
|
<el-tree
|
||||||
|
id="treeOption"
|
||||||
|
ref="treeOption"
|
||||||
|
:current-node-key="currentNodeKey"
|
||||||
|
:data="treeOptions"
|
||||||
|
:default-checked-keys="defaultSelectedKeys"
|
||||||
|
:default-expanded-keys="defaultSelectedKeys"
|
||||||
|
:highlight-current="true"
|
||||||
|
node-key="id"
|
||||||
|
:props="defaultProps"
|
||||||
|
:show-checkbox="selectType == 'multiple'"
|
||||||
|
@check="checkNode"
|
||||||
|
@node-click="nodeClick"
|
||||||
|
/>
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'SelectTreeTemplate',
|
||||||
|
props: {
|
||||||
|
/* 树形结构数据 */
|
||||||
|
treeOptions: {
|
||||||
|
type: Array,
|
||||||
|
default: () => {
|
||||||
|
return []
|
||||||
|
},
|
||||||
|
},
|
||||||
|
/* 单选/多选 */
|
||||||
|
selectType: {
|
||||||
|
type: String,
|
||||||
|
default: () => {
|
||||||
|
return 'single'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
/* 初始选中值key */
|
||||||
|
selectedKey: {
|
||||||
|
type: String,
|
||||||
|
default: () => {
|
||||||
|
return ''
|
||||||
|
},
|
||||||
|
},
|
||||||
|
/* 初始选中值name */
|
||||||
|
selectedValue: {
|
||||||
|
type: String,
|
||||||
|
default: () => {
|
||||||
|
return ''
|
||||||
|
},
|
||||||
|
},
|
||||||
|
/* 可做选择的层级 */
|
||||||
|
selectLevel: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: () => {
|
||||||
|
return ''
|
||||||
|
},
|
||||||
|
},
|
||||||
|
/* 可清空选项 */
|
||||||
|
clearable: {
|
||||||
|
type: Boolean,
|
||||||
|
default: () => {
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
defaultProps: {
|
||||||
|
children: 'children',
|
||||||
|
label: 'name',
|
||||||
|
},
|
||||||
|
defaultSelectedKeys: [], //初始选中值数组
|
||||||
|
currentNodeKey: this.selectedKey,
|
||||||
|
selectValue: this.selectType == 'multiple' ? this.selectedValue.split(',') : this.selectedValue, //下拉框选中值label
|
||||||
|
selectKey: this.selectType == 'multiple' ? this.selectedKey.split(',') : this.selectedKey, //下拉框选中值value
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.initTree()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 初始化树的值
|
||||||
|
initTree() {
|
||||||
|
const that = this
|
||||||
|
if (that.selectedKey) {
|
||||||
|
that.defaultSelectedKeys = that.selectedKey.split(',') // 设置默认展开
|
||||||
|
if (that.selectType == 'single') {
|
||||||
|
that.$refs.treeOption.setCurrentKey(that.selectedKey) // 设置默认选中
|
||||||
|
} else {
|
||||||
|
that.$refs.treeOption.setCheckedKeys(that.defaultSelectedKeys)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 清除选中
|
||||||
|
clearHandle() {
|
||||||
|
const that = this
|
||||||
|
this.selectValue = ''
|
||||||
|
this.selectKey = ''
|
||||||
|
this.defaultSelectedKeys = []
|
||||||
|
this.currentNodeKey = ''
|
||||||
|
this.clearSelected()
|
||||||
|
if (that.selectType == 'single') {
|
||||||
|
that.$refs.treeOption.setCurrentKey('') // 设置默认选中
|
||||||
|
} else {
|
||||||
|
that.$refs.treeOption.setCheckedKeys([])
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/* 清空选中样式 */
|
||||||
|
clearSelected() {
|
||||||
|
const allNode = document.querySelectorAll('#treeOption .el-tree-node')
|
||||||
|
allNode.forEach((element) => element.classList.remove('is-current'))
|
||||||
|
},
|
||||||
|
// select多选时移除某项操作
|
||||||
|
removeTag() {
|
||||||
|
this.$refs.treeOption.setCheckedKeys([])
|
||||||
|
},
|
||||||
|
// 点击叶子节点
|
||||||
|
nodeClick(data) {
|
||||||
|
if (data.rank >= this.selectLevel) {
|
||||||
|
this.selectValue = data.name
|
||||||
|
this.selectKey = data.id
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 节点选中操作
|
||||||
|
checkNode() {
|
||||||
|
const checkedNodes = this.$refs.treeOption.getCheckedNodes()
|
||||||
|
const keyArr = []
|
||||||
|
const valueArr = []
|
||||||
|
checkedNodes.forEach((item) => {
|
||||||
|
if (item.rank >= this.selectLevel) {
|
||||||
|
keyArr.push(item.id)
|
||||||
|
valueArr.push(item.name)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.selectValue = valueArr
|
||||||
|
this.selectKey = keyArr
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.el-scrollbar .el-scrollbar__view .el-select-dropdown__item {
|
||||||
|
height: auto;
|
||||||
|
max-height: 274px;
|
||||||
|
padding: 0;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-select-dropdown__item.selected {
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul li > .el-tree .el-tree-node__content {
|
||||||
|
height: auto;
|
||||||
|
padding: 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-tree-node__label {
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-tree > .is-current .el-tree-node__label {
|
||||||
|
font-weight: 700;
|
||||||
|
color: #409eff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-tree > .is-current .el-tree-node__children .el-tree-node__label {
|
||||||
|
font-weight: normal;
|
||||||
|
color: #606266;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<style lang="scss"></style>
|
||||||
120
src/components/SingleUpload/index.vue
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
<template>
|
||||||
|
<div class="single-upload">
|
||||||
|
<el-upload
|
||||||
|
:action="uploadUrl"
|
||||||
|
:before-upload="beforeUpload"
|
||||||
|
class="uploader"
|
||||||
|
:file-list="fileList"
|
||||||
|
:headers="uploadHeaders"
|
||||||
|
:on-error="handleError"
|
||||||
|
:on-success="handleSuccess"
|
||||||
|
:show-file-list="false"
|
||||||
|
>
|
||||||
|
<img v-if="fileUrl" alt="avatar" class="avatar" :src="fileUrl" />
|
||||||
|
<i v-else class="el-icon-plus uploader-icon"></i>
|
||||||
|
</el-upload>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { getAccessToken } from '@/utils/accessToken'
|
||||||
|
export default {
|
||||||
|
name: 'SingleUpload',
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
uploadUrl: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
fileUrl: this.value,
|
||||||
|
fileList: [],
|
||||||
|
token: getAccessToken() || '',
|
||||||
|
loadingInstance: null, // 存储 loading 实例
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
// 设置上传时的 headers
|
||||||
|
uploadHeaders() {
|
||||||
|
return {
|
||||||
|
Authorization: `${this.token}`,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value: {
|
||||||
|
handler(val) {
|
||||||
|
this.fileUrl = val
|
||||||
|
},
|
||||||
|
immediate: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
isImage() {
|
||||||
|
return /\.(png|jpg|jpeg|gif|webp)$/i.test(this.fileUrl)
|
||||||
|
},
|
||||||
|
handleSuccess(response) {
|
||||||
|
if (response.code === 200) {
|
||||||
|
this.fileUrl = `https://file.lihailezzc.com/${response.data.key}`
|
||||||
|
this.$message.success('上传成功!')
|
||||||
|
// this.$emit('input', this.fileUrl)
|
||||||
|
this.$emit('upload-success', this.fileUrl)
|
||||||
|
} else {
|
||||||
|
this.$message.error('上传失败,请重试!')
|
||||||
|
}
|
||||||
|
this.loadingInstance.close()
|
||||||
|
},
|
||||||
|
handleError() {
|
||||||
|
this.$message.error('上传失败,请重试!')
|
||||||
|
this.loadingInstance.close()
|
||||||
|
},
|
||||||
|
beforeUpload(file) {
|
||||||
|
const isValidSize = file.size / 1024 / 1024 < 5
|
||||||
|
if (!isValidSize) {
|
||||||
|
this.$message.error('文件大小不能超过 5MB!')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
this.loadingInstance = this.$loading({
|
||||||
|
target: this.$el, // 加载指示器的父容器
|
||||||
|
text: '上传中...',
|
||||||
|
spinner: true, // 显示加载动画
|
||||||
|
background: 'rgba(0, 0, 0, 0.5)', // 背景遮罩
|
||||||
|
})
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.single-upload {
|
||||||
|
.uploader {
|
||||||
|
border: 1px dashed #d9d9d9;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
&:hover {
|
||||||
|
border-color: #409eff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.uploader-icon {
|
||||||
|
font-size: 28px;
|
||||||
|
color: #8c939d;
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
line-height: 100px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.avatar {
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
178
src/components/VabCharge/index.vue
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
<template>
|
||||||
|
<div class="content">
|
||||||
|
<div class="g-container" :style="styleObj">
|
||||||
|
<div class="g-number">
|
||||||
|
{{ endVal }}
|
||||||
|
</div>
|
||||||
|
<div class="g-contrast">
|
||||||
|
<div class="g-circle"></div>
|
||||||
|
<ul class="g-bubbles">
|
||||||
|
<li v-for="(item, index) in 15" :key="index"></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'VabCharge',
|
||||||
|
props: {
|
||||||
|
styleObj: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
startVal: {
|
||||||
|
type: Number,
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
|
endVal: {
|
||||||
|
type: Number,
|
||||||
|
default: 100,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
decimals: 2,
|
||||||
|
prefix: '',
|
||||||
|
suffix: '%',
|
||||||
|
separator: ',',
|
||||||
|
duration: 3000,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {},
|
||||||
|
mounted() {},
|
||||||
|
methods: {},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.content {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center; /* 垂直居中 */
|
||||||
|
justify-content: center; /* 水平居中 */
|
||||||
|
width: 100%;
|
||||||
|
background: #000;
|
||||||
|
|
||||||
|
.g-number {
|
||||||
|
position: absolute;
|
||||||
|
top: 27%;
|
||||||
|
z-index: 99;
|
||||||
|
width: 300px;
|
||||||
|
font-size: 32px;
|
||||||
|
color: #fff;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.g-container {
|
||||||
|
position: relative;
|
||||||
|
width: 300px;
|
||||||
|
height: 400px;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.g-contrast {
|
||||||
|
width: 300px;
|
||||||
|
height: 400px;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: #000;
|
||||||
|
filter: contrast(15) hue-rotate(0);
|
||||||
|
animation: hueRotate 10s infinite linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
.g-circle {
|
||||||
|
position: relative;
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 300px;
|
||||||
|
height: 300px;
|
||||||
|
filter: blur(8px);
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
position: absolute;
|
||||||
|
top: 40%;
|
||||||
|
left: 50%;
|
||||||
|
width: 200px;
|
||||||
|
height: 200px;
|
||||||
|
content: '';
|
||||||
|
background-color: #00ff6f;
|
||||||
|
border-radius: 42% 38% 62% 49% / 45%;
|
||||||
|
transform: translate(-50%, -50%) rotate(0);
|
||||||
|
animation: rotate 10s infinite linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
position: absolute;
|
||||||
|
top: 40%;
|
||||||
|
left: 50%;
|
||||||
|
z-index: 99;
|
||||||
|
width: 176px;
|
||||||
|
height: 176px;
|
||||||
|
content: '';
|
||||||
|
background-color: #000;
|
||||||
|
border-radius: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.g-bubbles {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 50%;
|
||||||
|
width: 100px;
|
||||||
|
height: 40px;
|
||||||
|
background-color: #00ff6f;
|
||||||
|
filter: blur(5px);
|
||||||
|
border-radius: 100px 100px 0 0;
|
||||||
|
transform: translate(-50%, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
position: absolute;
|
||||||
|
background: #00ff6f;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@for $i from 0 through 15 {
|
||||||
|
li:nth-child(#{$i}) {
|
||||||
|
$width: 15 + random(15) + px;
|
||||||
|
|
||||||
|
top: 50%;
|
||||||
|
left: 15 + random(70) + px;
|
||||||
|
width: $width;
|
||||||
|
height: $width;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
animation: moveToTop #{random(6) + 3}s ease-in-out -#{random(5000) / 1000}s infinite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes rotate {
|
||||||
|
50% {
|
||||||
|
border-radius: 45% / 42% 38% 58% 49%;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: translate(-50%, -50%) rotate(720deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes moveToTop {
|
||||||
|
90% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
opacity: 0.1;
|
||||||
|
transform: translate(-50%, -180px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes hueRotate {
|
||||||
|
100% {
|
||||||
|
filter: contrast(15) hue-rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
305
src/components/VabProfile/index.vue
Normal file
@@ -0,0 +1,305 @@
|
|||||||
|
<template>
|
||||||
|
<div class="card" :style="styleObj">
|
||||||
|
<div class="card-borders">
|
||||||
|
<div class="border-top"></div>
|
||||||
|
<div class="border-right"></div>
|
||||||
|
<div class="border-bottom"></div>
|
||||||
|
<div class="border-left"></div>
|
||||||
|
</div>
|
||||||
|
<div class="card-content">
|
||||||
|
<el-image class="avatar" :src="avatar" />
|
||||||
|
<div class="username">
|
||||||
|
{{ username }}
|
||||||
|
</div>
|
||||||
|
<div class="social-icons">
|
||||||
|
<a v-for="(item, index) in iconArray" :key="index" class="social-icon" :href="item.url" target="_blank">
|
||||||
|
<vab-icon :icon="['fas', item.icon]" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'VabProfile',
|
||||||
|
props: {
|
||||||
|
styleObj: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
username: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
avatar: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
iconArray: {
|
||||||
|
type: Array,
|
||||||
|
default: () => {
|
||||||
|
return [
|
||||||
|
{ icon: 'bell', url: '' },
|
||||||
|
{ icon: 'bookmark', url: '' },
|
||||||
|
{ icon: 'cloud-sun', url: '' },
|
||||||
|
]
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
created() {},
|
||||||
|
mounted() {},
|
||||||
|
methods: {},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.card {
|
||||||
|
--card-bg-color: hsl(240, 31%, 25%);
|
||||||
|
--card-bg-color-transparent: hsla(240, 31%, 25%, 0.7);
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.card-borders {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.border-top {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 2px;
|
||||||
|
background: var(--card-bg-color);
|
||||||
|
transform: translateX(-100%);
|
||||||
|
animation: slide-in-horizontal 0.8s cubic-bezier(0.645, 0.045, 0.355, 1) forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
.border-right {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
width: 2px;
|
||||||
|
height: 100%;
|
||||||
|
background: var(--card-bg-color);
|
||||||
|
transform: translateY(100%);
|
||||||
|
animation: slide-in-vertical 0.8s cubic-bezier(0.645, 0.045, 0.355, 1) forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
.border-bottom {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 2px;
|
||||||
|
background: var(--card-bg-color);
|
||||||
|
transform: translateX(100%);
|
||||||
|
animation: slide-in-horizontal-reverse 0.8s cubic-bezier(0.645, 0.045, 0.355, 1) forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
.border-left {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
width: 2px;
|
||||||
|
height: 100%;
|
||||||
|
background: var(--card-bg-color);
|
||||||
|
transform: translateY(-100%);
|
||||||
|
animation: slide-in-vertical-reverse 0.8s cubic-bezier(0.645, 0.045, 0.355, 1) forwards;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
height: 100%;
|
||||||
|
padding: 40px 0 40px 0;
|
||||||
|
background: var(--card-bg-color-transparent);
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0.6);
|
||||||
|
animation: bump-in 0.5s 0.8s forwards;
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
width: 80px;
|
||||||
|
height: 80px;
|
||||||
|
border: 1px solid $base-color-white;
|
||||||
|
border-radius: 50%;
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0.6);
|
||||||
|
animation: bump-in 0.5s 1s forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
.username {
|
||||||
|
position: relative;
|
||||||
|
margin-top: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
font-size: 26px;
|
||||||
|
color: transparent;
|
||||||
|
letter-spacing: 2px;
|
||||||
|
animation: fill-text-white 1.2s 2s forwards;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
color: black;
|
||||||
|
content: '';
|
||||||
|
background: #35b9f1;
|
||||||
|
transform: scaleX(0);
|
||||||
|
transform-origin: left;
|
||||||
|
animation: slide-in-out 1.2s 1.2s cubic-bezier(0.75, 0, 0, 1) forwards;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-icons {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
.social-icon {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 2.5em;
|
||||||
|
height: 2.5em;
|
||||||
|
margin: 0 15px;
|
||||||
|
color: white;
|
||||||
|
text-decoration: none;
|
||||||
|
border-radius: 50%;
|
||||||
|
|
||||||
|
@for $i from 1 through 3 {
|
||||||
|
&:nth-child(#{$i}) {
|
||||||
|
&::before {
|
||||||
|
animation-delay: 2s + 0.1s * $i;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
animation-delay: 2.1s + 0.1s * $i;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
animation-delay: 2.2s + 0.1s * $i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before,
|
||||||
|
&::after {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
content: '';
|
||||||
|
border-radius: inherit;
|
||||||
|
transform: scale(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
background: #f7f1e3;
|
||||||
|
animation: scale-in 0.5s cubic-bezier(0.75, 0, 0, 1) forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
background: #2c3e50;
|
||||||
|
animation: scale-in 0.5s cubic-bezier(0.75, 0, 0, 1) forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
z-index: 99;
|
||||||
|
transform: scale(0);
|
||||||
|
animation: scale-in 0.5s cubic-bezier(0.75, 0, 0, 1) forwards;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes bump-in {
|
||||||
|
50% {
|
||||||
|
transform: scale(1.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slide-in-horizontal {
|
||||||
|
50% {
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
transform: translateX(100%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slide-in-horizontal-reverse {
|
||||||
|
50% {
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
transform: translateX(-100%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slide-in-vertical {
|
||||||
|
50% {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
transform: translateY(-100%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slide-in-vertical-reverse {
|
||||||
|
50% {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
transform: translateY(100%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slide-in-out {
|
||||||
|
50% {
|
||||||
|
transform: scaleX(1);
|
||||||
|
transform-origin: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
50.1% {
|
||||||
|
transform-origin: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: scaleX(0);
|
||||||
|
transform-origin: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fill-text-white {
|
||||||
|
to {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes scale-in {
|
||||||
|
to {
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
81
src/components/VabSnow/index.vue
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
<template>
|
||||||
|
<div class="content" :style="styleObj">
|
||||||
|
<div v-for="(item, index) in 200" :key="index" class="snow"></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'VabSnow',
|
||||||
|
props: {
|
||||||
|
styleObj: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
created() {},
|
||||||
|
mounted() {},
|
||||||
|
methods: {},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.content {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
background: radial-gradient(ellipse at bottom, #1b2735 0%, #090a0f 100%);
|
||||||
|
filter: drop-shadow(0 0 10px white);
|
||||||
|
}
|
||||||
|
|
||||||
|
@function random_range($min, $max) {
|
||||||
|
$rand: random();
|
||||||
|
$random_range: $min + floor($rand * (($max - $min) + 1));
|
||||||
|
|
||||||
|
@return $random_range;
|
||||||
|
}
|
||||||
|
|
||||||
|
.snow {
|
||||||
|
$total: 200;
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
background: white;
|
||||||
|
border-radius: 50%;
|
||||||
|
|
||||||
|
@for $i from 1 through $total {
|
||||||
|
$random-x: random(1000000) * 0.0001vw;
|
||||||
|
$random-offset: random_range(-100000, 100000) * 0.0001vw;
|
||||||
|
$random-x-end: $random-x + $random-offset;
|
||||||
|
$random-x-end-yoyo: $random-x + ($random-offset / 2);
|
||||||
|
$random-yoyo-time: random_range(30000, 80000) / 100000;
|
||||||
|
$random-yoyo-y: $random-yoyo-time * 100vh;
|
||||||
|
$random-scale: random(10000) * 0.0001;
|
||||||
|
$fall-duration: random_range(10, 30) * 1s;
|
||||||
|
$fall-delay: random(30) * -1s;
|
||||||
|
|
||||||
|
&:nth-child(#{$i}) {
|
||||||
|
opacity: random(10000) * 0.0001;
|
||||||
|
transform: translate($random-x, -10px) scale($random-scale);
|
||||||
|
animation: fall-#{$i} $fall-duration $fall-delay linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fall-#{$i} {
|
||||||
|
#{percentage($random-yoyo-time)} {
|
||||||
|
transform: translate($random-x-end, $random-yoyo-y) scale($random-scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
transform: translate($random-x-end-yoyo, 100vh) scale($random-scale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
217
src/components/VabUpload/index.vue
Normal file
@@ -0,0 +1,217 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog :before-close="handleClose" :close-on-click-modal="false" :title="title" :visible.sync="dialogFormVisible" width="909px">
|
||||||
|
<div class="upload">
|
||||||
|
<el-alert
|
||||||
|
:closable="false"
|
||||||
|
:title="`支持jpg、jpeg、png格式,单次可最多选择${limit}张图片,每张不可大于${size}M,如果大于${size}M会自动为您过滤`"
|
||||||
|
type="info"
|
||||||
|
/>
|
||||||
|
<br />
|
||||||
|
<el-upload
|
||||||
|
ref="upload"
|
||||||
|
accept="image/png, image/jpeg"
|
||||||
|
:action="action"
|
||||||
|
:auto-upload="false"
|
||||||
|
class="upload-content"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
:data="data"
|
||||||
|
:file-list="fileList"
|
||||||
|
:headers="headers"
|
||||||
|
:limit="limit"
|
||||||
|
list-type="picture-card"
|
||||||
|
:multiple="true"
|
||||||
|
:name="name"
|
||||||
|
:on-change="handleChange"
|
||||||
|
:on-error="handleError"
|
||||||
|
:on-exceed="handleExceed"
|
||||||
|
:on-preview="handlePreview"
|
||||||
|
:on-progress="handleProgress"
|
||||||
|
:on-remove="handleRemove"
|
||||||
|
:on-success="handleSuccess"
|
||||||
|
>
|
||||||
|
<i slot="trigger" class="el-icon-plus"></i>
|
||||||
|
<el-dialog append-to-body title="查看大图" :visible.sync="dialogVisible">
|
||||||
|
<div>
|
||||||
|
<img alt="" :src="dialogImageUrl" width="100%" />
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</el-upload>
|
||||||
|
</div>
|
||||||
|
<div slot="footer" class="dialog-footer" style="position: relative; padding-right: 15px; text-align: right">
|
||||||
|
<div v-if="show" style="position: absolute; top: 10px; left: 15px; color: #999">
|
||||||
|
正在上传中... 当前上传成功数:{{ imgSuccessNum }}张 当前上传失败数:{{ imgErrorNum }}张
|
||||||
|
</div>
|
||||||
|
<el-button type="primary" @click="handleClose">关闭</el-button>
|
||||||
|
<el-button :loading="loading" size="small" style="margin-left: 10px" type="success" @click="submitUpload">开始上传</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'VabUpload',
|
||||||
|
props: {
|
||||||
|
url: {
|
||||||
|
type: String,
|
||||||
|
default: '/upload',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
default: 'file',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
limit: {
|
||||||
|
type: Number,
|
||||||
|
default: 50,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
type: Number,
|
||||||
|
default: 1,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
show: false,
|
||||||
|
loading: false,
|
||||||
|
dialogVisible: false,
|
||||||
|
dialogImageUrl: '',
|
||||||
|
action: 'https://vab-unicloud-3a9da9.service.tcloudbase.com/upload',
|
||||||
|
headers: {},
|
||||||
|
fileList: [],
|
||||||
|
picture: 'picture',
|
||||||
|
imgNum: 0,
|
||||||
|
imgSuccessNum: 0,
|
||||||
|
imgErrorNum: 0,
|
||||||
|
typeList: null,
|
||||||
|
title: '上传',
|
||||||
|
dialogFormVisible: false,
|
||||||
|
data: {},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
percentage() {
|
||||||
|
if (this.allImgNum == 0) return 0
|
||||||
|
return this.$baseLodash.round(this.imgNum / this.allImgNum, 2) * 100
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
submitUpload() {
|
||||||
|
this.$refs.upload.submit()
|
||||||
|
},
|
||||||
|
handleProgress() {
|
||||||
|
this.loading = true
|
||||||
|
this.show = true
|
||||||
|
},
|
||||||
|
handleChange(file, fileList) {
|
||||||
|
if (file.size > 1048576 * this.size) {
|
||||||
|
fileList.map((item, index) => {
|
||||||
|
if (item === file) {
|
||||||
|
fileList.splice(index, 1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.fileList = fileList
|
||||||
|
} else {
|
||||||
|
this.allImgNum = fileList.length
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleSuccess(response, file, fileList) {
|
||||||
|
this.imgNum = this.imgNum + 1
|
||||||
|
this.imgSuccessNum = this.imgSuccessNum + 1
|
||||||
|
if (fileList.length === this.imgNum) {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.$baseMessage(`上传完成! 共上传${fileList.length}张图片`, 'success')
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
this.loading = false
|
||||||
|
this.show = false
|
||||||
|
}, 1000)
|
||||||
|
},
|
||||||
|
handleError() {
|
||||||
|
this.imgNum = this.imgNum + 1
|
||||||
|
this.imgErrorNum = this.imgErrorNum + 1
|
||||||
|
this.$baseMessage(`文件[${file.raw.name}]上传失败,文件大小为${this.$baseLodash.round(file.raw.size / 1024, 0)}KB`, 'error')
|
||||||
|
setTimeout(() => {
|
||||||
|
this.loading = false
|
||||||
|
this.show = false
|
||||||
|
}, 1000)
|
||||||
|
},
|
||||||
|
handleRemove() {
|
||||||
|
this.imgNum = this.imgNum - 1
|
||||||
|
this.allNum = this.allNum - 1
|
||||||
|
},
|
||||||
|
handlePreview(file) {
|
||||||
|
this.dialogImageUrl = file.url
|
||||||
|
this.dialogVisible = true
|
||||||
|
},
|
||||||
|
handleExceed(files, fileList) {
|
||||||
|
this.$baseMessage(
|
||||||
|
`当前限制选择 ${this.limit} 个文件,本次选择了
|
||||||
|
${files.length}
|
||||||
|
个文件`,
|
||||||
|
'error'
|
||||||
|
)
|
||||||
|
},
|
||||||
|
handleShow(data) {
|
||||||
|
this.title = '上传'
|
||||||
|
this.data = data
|
||||||
|
this.dialogFormVisible = true
|
||||||
|
},
|
||||||
|
handleClose() {
|
||||||
|
this.fileList = []
|
||||||
|
this.picture = 'picture'
|
||||||
|
this.allImgNum = 0
|
||||||
|
this.imgNum = 0
|
||||||
|
this.imgSuccessNum = 0
|
||||||
|
this.imgErrorNum = 0
|
||||||
|
/* if ("development" === process.env.NODE_ENV) {
|
||||||
|
this.api = process.env.VUE_APP_BASE_API;
|
||||||
|
} else {
|
||||||
|
this.api = `${window.location.protocol}//${window.location.host}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.action = this.api + this.url; */
|
||||||
|
this.dialogFormVisible = false
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.upload {
|
||||||
|
height: 500px;
|
||||||
|
|
||||||
|
.upload-content {
|
||||||
|
.el-upload__tip {
|
||||||
|
display: block;
|
||||||
|
height: 30px;
|
||||||
|
line-height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep {
|
||||||
|
.el-upload--picture-card {
|
||||||
|
width: 128px;
|
||||||
|
height: 128px;
|
||||||
|
margin: 3px 8px 8px 8px;
|
||||||
|
border: 2px dashed #c0ccda;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-upload-list--picture {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-upload-list--picture-card {
|
||||||
|
.el-upload-list__item {
|
||||||
|
width: 128px;
|
||||||
|
height: 128px;
|
||||||
|
margin: 3px 8px 8px 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
7
src/config/index.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
/**
|
||||||
|
* @description 3个子配置,通用配置|主题配置|网络配置导出
|
||||||
|
*/
|
||||||
|
const setting = require('./setting.config')
|
||||||
|
const theme = require('./theme.config')
|
||||||
|
const network = require('./net.config')
|
||||||
|
module.exports = Object.assign({}, setting, theme, network)
|
||||||
20
src/config/net.config.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
/**
|
||||||
|
* @description 导出默认网路配置
|
||||||
|
**/
|
||||||
|
const network = {
|
||||||
|
// 默认的接口地址 如果是开发环境和生产环境走vab-mock-server,当然你也可以选择自己配置成需要的接口地址
|
||||||
|
baseURL: process.env.NODE_ENV === 'development' ? 'http://127.0.0.1:3999' : 'http://127.0.0.1:3999',
|
||||||
|
//配后端数据的接收方式application/json;charset=UTF-8或者application/x-www-form-urlencoded;charset=UTF-8
|
||||||
|
contentType: 'application/json;charset=UTF-8',
|
||||||
|
//消息框消失时间
|
||||||
|
messageDuration: 3000,
|
||||||
|
//最长请求时间
|
||||||
|
requestTimeout: 5000,
|
||||||
|
//操作正常code,支持String、Array、int多种类型
|
||||||
|
successCode: [200, 0],
|
||||||
|
//登录失效code
|
||||||
|
invalidCode: 402,
|
||||||
|
//无权限code
|
||||||
|
noPermissionCode: 401,
|
||||||
|
}
|
||||||
|
module.exports = network
|
||||||