commit b2620a08a105836fb189ed202f52b0e50f465bcc Author: chenxiaoxi Date: Mon Apr 19 18:00:27 2021 +0800 项目初始化 diff --git a/.browserslistrc b/.browserslistrc new file mode 100644 index 000000000..ab3713ad8 --- /dev/null +++ b/.browserslistrc @@ -0,0 +1,5 @@ +# 支持浏览器配置 +> 1% +last 2 versions +not dead + diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..7b06489a1 --- /dev/null +++ b/.editorconfig @@ -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 diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 000000000..f8aa4878c --- /dev/null +++ b/.eslintignore @@ -0,0 +1,7 @@ +# .eslintignore + +src/assets +src/icons +public +dist +node_modules diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 000000000..5b96111ea --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,31 @@ +/** + + * @description .eslintrc.js + */ + +module.exports = { + root: true, + env: { + node: true, + }, + extends: ['plugin:vue/recommended', '@vue/prettier'], + rules: { + 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', + 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off', + 'vue/no-v-html': 'off', + }, + parserOptions: { + parser: 'babel-eslint', + }, + overrides: [ + { + files: [ + '**/__tests__/*.{j,t}s?(x)', + '**/tests/unit/**/*.spec.{j,t}s?(x)', + ], + env: { + jest: true, + }, + }, + ], +} diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..1fa0664d7 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,12 @@ +# .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 +*.js linguist-language=vue \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..6b55d8359 --- /dev/null +++ b/.gitignore @@ -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/zx-layouts +/zx-templates +/package-lock.json +/src/styles/themes/green.scss +/src/styles/themes/dark.scss +/src/styles/themes/glory.scss + diff --git a/.stylelintrc.js b/.stylelintrc.js new file mode 100644 index 000000000..dc4736356 --- /dev/null +++ b/.stylelintrc.js @@ -0,0 +1,7 @@ +/** + + * @description stylelint + */ +module.exports = { + extends: ['stylelint-config-recess-order', 'stylelint-config-prettier'], +} diff --git a/README.md b/README.md new file mode 100644 index 000000000..95d26e503 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +![](public/static/images/logo.png) + +### 法规智库-福田 diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 000000000..d744d8f50 --- /dev/null +++ b/babel.config.js @@ -0,0 +1,7 @@ +/** + + * @description babel.config + */ +module.exports = { + presets: ['@vue/cli-plugin-babel/preset'], +} diff --git a/package.json b/package.json new file mode 100644 index 000000000..be2a86bd6 --- /dev/null +++ b/package.json @@ -0,0 +1,96 @@ +{ + "name": "laws-system-front-FOTON", + "version": "1.0.0", + "author": "rongchuangruantong", + "participants": [], + "homepage": "http://103.249.252.28:90/LAWS/laws-system-front-FOTON.git", + "scripts": { + "serve": "vue-cli-service serve", + "build": "vue-cli-service build" + }, + "repository": { + "type": "git", + "url": "git+http://103.249.252.28:90/LAWS/laws-system-front-FOTON.git" + }, + "gitHooks": { + "pre-commit": "lint-staged" + }, + "lint-staged": { + "*.{js,jsx,vue}": [ + "vue-cli-service lint", + "git add" + ] + }, + "dependencies": { + "axios": "^0.21.1", + "clipboard": "^2.0.8", + "core-js": "^3.10.1", + "dayjs": "^1.10.4", + "echarts": "^5.1.0", + "echarts-wordcloud": "^2.0.0", + "element-ui": "^2.15.1", + "jsencrypt": "^3.1.0", + "lodash": "^4.17.21", + "maptalks": "^0.49.3", + "mapv": "^2.0.62", + "mockjs": "^1.1.0", + "nprogress": "^0.2.0", + "qs": "^6.10.1", + "screenfull": "^5.1.0", + "sortablejs": "^1.13.0", + "vab-icon": "^0.0.1", + "vue": "^2.6.12", + "vue-echarts": "5.0.0-beta.0", + "vue-router": "^3.5.1", + "vuex": "^3.6.2", + "zx-count": "^0.3.7", + "zx-layouts": "^0.6.24", + "zx-magnifie": "^0.4.0", + "zx-markdown-editor": "^0.0.2", + "zx-player": "^1.0.2", + "zx-quill": "^0.0.3", + "zx-templates": "^0.0.26", + "zx-verify": "^0.0.2" + }, + "devDependencies": { + "@vue/cli-plugin-babel": "^4.5.12", + "@vue/cli-plugin-eslint": "^4.5.12", + "@vue/cli-service": "^4.5.12", + "@vue/eslint-config-prettier": "^6.0.0", + "babel-eslint": "^10.1.0", + "body-parser": "^1.19.0", + "chalk": "^4.1.0", + "chokidar": "^3.5.1", + "eslint": "^7.24.0", + "eslint-plugin-prettier": "^3.4.0", + "eslint-plugin-vue": "^7.9.0", + "filemanager-webpack-plugin": "^4.0.0", + "image-webpack-loader": "^7.0.1", + "lint-staged": "^10.5.4", + "plop": "^2.7.4", + "prettier": "^2.2.1", + "sass": "^1.32.10", + "sass-loader": "^10.1.1", + "stylelint": "^13.12.0", + "stylelint-config-prettier": "^8.0.2", + "stylelint-config-recess-order": "^2.3.0", + "svg-sprite-loader": "^6.0.5", + "vue-template-compiler": "^2.6.12", + "webpackbar": "^4.0.0" + }, + "keywords": [ + "vue", + "admin", + "dashboard", + "element-ui", + "vue-admin", + "element-admin", + "boilerplate", + "admin-template", + "management-system" + ], + "engines": { + "node": ">=8.9", + "npm": ">= 3.0.0" + } +} diff --git a/plopfile.js b/plopfile.js new file mode 100644 index 000000000..f718b5e79 --- /dev/null +++ b/plopfile.js @@ -0,0 +1,16 @@ +/** + + * @description 代码生成机 + */ +const viewGenerator = require('zx-templates/view/prompt') +const curdGenerator = require('zx-templates/curd/prompt') +const componentGenerator = require('zx-templates/component/prompt') +const mockGenerator = require('zx-templates/mock/prompt') +const vuexGenerator = require('zx-templates/vuex/prompt') +module.exports = (plop) => { + plop.setGenerator('view', viewGenerator) + plop.setGenerator('curd', curdGenerator) + plop.setGenerator('component', componentGenerator) + plop.setGenerator('mock&api', mockGenerator) + plop.setGenerator('vuex', vuexGenerator) +} diff --git a/prettier.config.js b/prettier.config.js new file mode 100644 index 000000000..ee084387a --- /dev/null +++ b/prettier.config.js @@ -0,0 +1,21 @@ +/** + + * @description 代码规范 + */ + +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', +} diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 000000000..7c31c49f6 Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/favicon_backup.ico b/public/favicon_backup.ico new file mode 100644 index 000000000..df36fcfb7 Binary files /dev/null and b/public/favicon_backup.ico differ diff --git a/public/index.html b/public/index.html new file mode 100644 index 000000000..d765907dd --- /dev/null +++ b/public/index.html @@ -0,0 +1,41 @@ + + + + + + + + <%= VUE_APP_TITLE %> + + + + +
+
+
+ + + + + + +
+

<%= VUE_APP_TITLE %>

+
+
+ + + diff --git a/public/static/css/loading.css b/public/static/css/loading.css new file mode 100644 index 000000000..b8624b061 --- /dev/null +++ b/public/static/css/loading.css @@ -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; + } +} diff --git a/public/static/images/logo.png b/public/static/images/logo.png new file mode 100644 index 000000000..a038d31fa Binary files /dev/null and b/public/static/images/logo.png differ diff --git a/src/App.vue b/src/App.vue new file mode 100644 index 000000000..94f824e74 --- /dev/null +++ b/src/App.vue @@ -0,0 +1,12 @@ + + + diff --git a/src/api/ad.js b/src/api/ad.js new file mode 100644 index 000000000..065e6a903 --- /dev/null +++ b/src/api/ad.js @@ -0,0 +1,9 @@ +import request from '@/utils/request' + +export function getList(data) { + return request({ + url: '/ad/getList', + method: 'get', + data, + }) +} diff --git a/src/api/changeLog.js b/src/api/changeLog.js new file mode 100644 index 000000000..bf7464b85 --- /dev/null +++ b/src/api/changeLog.js @@ -0,0 +1,9 @@ +import request from '@/utils/request' + +export function getList(data) { + return request({ + url: '/changeLog/getList', + method: 'post', + data, + }) +} diff --git a/src/api/colorfulIcon.js b/src/api/colorfulIcon.js new file mode 100644 index 000000000..c2b6d5bb6 --- /dev/null +++ b/src/api/colorfulIcon.js @@ -0,0 +1,9 @@ +import request from '@/utils/request' + +export function getIconList(data) { + return request({ + url: '/colorfulIcon/getList', + method: 'post', + data, + }) +} diff --git a/src/api/github.js b/src/api/github.js new file mode 100644 index 000000000..2d218dc1d --- /dev/null +++ b/src/api/github.js @@ -0,0 +1,20 @@ +import request from 'axios' + +export function getRepos(params) { + return request({ + url: 'https://api.github.com/repos/chuzhixin/vue-admin-beautiful', + method: 'get', + params, + timeout: 10000, + }) +} + +export function getStargazers(params) { + return request({ + url: + 'https://api.github.com/repos/chuzhixin/vue-admin-beautiful/stargazers', + method: 'get', + params, + timeout: 10000, + }) +} diff --git a/src/api/goodsList.js b/src/api/goodsList.js new file mode 100644 index 000000000..3a40f8fd2 --- /dev/null +++ b/src/api/goodsList.js @@ -0,0 +1,9 @@ +import request from '@/utils/request' + +export function getList(data) { + return request({ + url: '/goodsList/getList', + method: 'post', + data, + }) +} diff --git a/src/api/icon.js b/src/api/icon.js new file mode 100644 index 000000000..fe1d1863e --- /dev/null +++ b/src/api/icon.js @@ -0,0 +1,9 @@ +import request from '@/utils/request' + +export function getIconList(data) { + return request({ + url: '/icon/getList', + method: 'post', + data, + }) +} diff --git a/src/api/markdown.js b/src/api/markdown.js new file mode 100644 index 000000000..e6bb01c81 --- /dev/null +++ b/src/api/markdown.js @@ -0,0 +1,8 @@ +import request from 'axios' + +export function getList() { + return request({ + url: 'https://cdn.jsdelivr.net/gh/prettier/prettier@master/docs/options.md', + method: 'get', + }) +} diff --git a/src/api/menuManagement.js b/src/api/menuManagement.js new file mode 100644 index 000000000..32b22d3b6 --- /dev/null +++ b/src/api/menuManagement.js @@ -0,0 +1,25 @@ +import request from '@/utils/request' + +export function getTree(data) { + return request({ + url: '/menuManagement/getTree', + method: 'post', + data, + }) +} + +export function doEdit(data) { + return request({ + url: '/menuManagement/doEdit', + method: 'post', + data, + }) +} + +export function doDelete(data) { + return request({ + url: '/menuManagement/doDelete', + method: 'post', + data, + }) +} diff --git a/src/api/notice.js b/src/api/notice.js new file mode 100644 index 000000000..ced1de3b4 --- /dev/null +++ b/src/api/notice.js @@ -0,0 +1,8 @@ +import request from '@/utils/request' + +export function getNoticeList() { + return request({ + url: '/notice/getList', + method: 'post', + }) +} diff --git a/src/api/personalCenter.js b/src/api/personalCenter.js new file mode 100644 index 000000000..804c679be --- /dev/null +++ b/src/api/personalCenter.js @@ -0,0 +1,25 @@ +import request from '@/utils/request' + +export function getList(data) { + return request({ + url: '/personalCenter/getList', + method: 'post', + data, + }) +} + +export function doEdit(data) { + return request({ + url: '/personalCenter/doEdit', + method: 'post', + data, + }) +} + +export function doDelete(data) { + return request({ + url: '/personalCenter/doDelete', + method: 'post', + data, + }) +} diff --git a/src/api/publicKey.js b/src/api/publicKey.js new file mode 100644 index 000000000..8b641fb8f --- /dev/null +++ b/src/api/publicKey.js @@ -0,0 +1,8 @@ +import request from '@/utils/request' + +export function getPublicKey() { + return request({ + url: '/publicKey', + method: 'post', + }) +} diff --git a/src/api/remixIcon.js b/src/api/remixIcon.js new file mode 100644 index 000000000..c62ea704f --- /dev/null +++ b/src/api/remixIcon.js @@ -0,0 +1,9 @@ +import request from '@/utils/request' + +export function getIconList(data) { + return request({ + url: '/remixIcon/getList', + method: 'post', + data, + }) +} diff --git a/src/api/roleManagement.js b/src/api/roleManagement.js new file mode 100644 index 000000000..4aac23ed7 --- /dev/null +++ b/src/api/roleManagement.js @@ -0,0 +1,25 @@ +import request from '@/utils/request' + +export function getList(data) { + return request({ + url: '/roleManagement/getList', + method: 'post', + data, + }) +} + +export function doEdit(data) { + return request({ + url: '/roleManagement/doEdit', + method: 'post', + data, + }) +} + +export function doDelete(data) { + return request({ + url: '/roleManagement/doDelete', + method: 'post', + data, + }) +} diff --git a/src/api/router.js b/src/api/router.js new file mode 100644 index 000000000..4d34d4894 --- /dev/null +++ b/src/api/router.js @@ -0,0 +1,9 @@ +import request from '@/utils/request' + +export function getRouterList(data) { + return request({ + url: '/menu/navigate', + method: 'post', + data, + }) +} diff --git a/src/api/table.js b/src/api/table.js new file mode 100644 index 000000000..0c1effc31 --- /dev/null +++ b/src/api/table.js @@ -0,0 +1,25 @@ +import request from '@/utils/request' + +export function getList(data) { + return request({ + url: '/table/getList', + method: 'post', + data, + }) +} + +export function doEdit(data) { + return request({ + url: '/table/doEdit', + method: 'post', + data, + }) +} + +export function doDelete(data) { + return request({ + url: '/table/doDelete', + method: 'post', + data, + }) +} diff --git a/src/api/tree.js b/src/api/tree.js new file mode 100644 index 000000000..e29ad3895 --- /dev/null +++ b/src/api/tree.js @@ -0,0 +1,9 @@ +import request from '@/utils/request' + +export function getTreeList(data) { + return request({ + url: '/tree/list', + method: 'post', + data, + }) +} diff --git a/src/api/user.js b/src/api/user.js new file mode 100644 index 000000000..e99e29f15 --- /dev/null +++ b/src/api/user.js @@ -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: '/login', + method: 'post', + data, + }) +} + +export function getUserInfo(accessToken) { + return request({ + url: '/userInfo', + method: 'post', + data: { + [tokenName]: accessToken, + }, + }) +} + +export function logout() { + return request({ + url: '/logout', + method: 'post', + }) +} + +export function register() { + return request({ + url: '/register', + method: 'post', + }) +} diff --git a/src/api/userManagement.js b/src/api/userManagement.js new file mode 100644 index 000000000..9eaca6ed0 --- /dev/null +++ b/src/api/userManagement.js @@ -0,0 +1,25 @@ +import request from '@/utils/request' + +export function getList(data) { + return request({ + url: '/userManagement/getList', + method: 'post', + data, + }) +} + +export function doEdit(data) { + return request({ + url: '/userManagement/doEdit', + method: 'post', + data, + }) +} + +export function doDelete(data) { + return request({ + url: '/userManagement/doDelete', + method: 'post', + data, + }) +} diff --git a/src/assets/comparison/left.jpg b/src/assets/comparison/left.jpg new file mode 100644 index 000000000..f5133cf11 Binary files /dev/null and b/src/assets/comparison/left.jpg differ diff --git a/src/assets/comparison/right.jpg b/src/assets/comparison/right.jpg new file mode 100644 index 000000000..625a53f24 Binary files /dev/null and b/src/assets/comparison/right.jpg differ diff --git a/src/assets/error_images/401.png b/src/assets/error_images/401.png new file mode 100644 index 000000000..90bbf6e33 Binary files /dev/null and b/src/assets/error_images/401.png differ diff --git a/src/assets/error_images/404.png b/src/assets/error_images/404.png new file mode 100644 index 000000000..14fa72555 Binary files /dev/null and b/src/assets/error_images/404.png differ diff --git a/src/assets/error_images/cloud.png b/src/assets/error_images/cloud.png new file mode 100644 index 000000000..247c06b41 Binary files /dev/null and b/src/assets/error_images/cloud.png differ diff --git a/src/assets/ewm.png b/src/assets/ewm.png new file mode 100644 index 000000000..a97a6ad46 Binary files /dev/null and b/src/assets/ewm.png differ diff --git a/src/assets/login_images/background.jpg b/src/assets/login_images/background.jpg new file mode 100644 index 000000000..87ac4969b Binary files /dev/null and b/src/assets/login_images/background.jpg differ diff --git a/src/assets/pro.png b/src/assets/pro.png new file mode 100644 index 000000000..09bcef5b3 Binary files /dev/null and b/src/assets/pro.png differ diff --git a/src/assets/qr_logo/lqr_logo.png b/src/assets/qr_logo/lqr_logo.png new file mode 100644 index 000000000..f81db4620 Binary files /dev/null and b/src/assets/qr_logo/lqr_logo.png differ diff --git a/src/assets/zfb_699.jpg b/src/assets/zfb_699.jpg new file mode 100644 index 000000000..4760e7c35 Binary files /dev/null and b/src/assets/zfb_699.jpg differ diff --git a/src/assets/zfb_799.jpg b/src/assets/zfb_799.jpg new file mode 100644 index 000000000..ff1060437 Binary files /dev/null and b/src/assets/zfb_799.jpg differ diff --git a/src/colorfulIcon/index.js b/src/colorfulIcon/index.js new file mode 100644 index 000000000..2dd876e1f --- /dev/null +++ b/src/colorfulIcon/index.js @@ -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) diff --git a/src/colorfulIcon/svg/alphabetical_sorting.svg b/src/colorfulIcon/svg/alphabetical_sorting.svg new file mode 100644 index 000000000..3cfa035b0 --- /dev/null +++ b/src/colorfulIcon/svg/alphabetical_sorting.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/colorfulIcon/svg/vab.svg b/src/colorfulIcon/svg/vab.svg new file mode 100644 index 000000000..5c46271c7 --- /dev/null +++ b/src/colorfulIcon/svg/vab.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/components/SelectTree/index.vue b/src/components/SelectTree/index.vue new file mode 100644 index 000000000..bacc7dd83 --- /dev/null +++ b/src/components/SelectTree/index.vue @@ -0,0 +1,201 @@ + + + + + + diff --git a/src/components/VabCharge/index.vue b/src/components/VabCharge/index.vue new file mode 100644 index 000000000..609da971c --- /dev/null +++ b/src/components/VabCharge/index.vue @@ -0,0 +1,191 @@ + + + + + diff --git a/src/components/VabProfile/index.vue b/src/components/VabProfile/index.vue new file mode 100644 index 000000000..7f291dd17 --- /dev/null +++ b/src/components/VabProfile/index.vue @@ -0,0 +1,313 @@ + + + + + diff --git a/src/components/VabSnow/index.vue b/src/components/VabSnow/index.vue new file mode 100644 index 000000000..5131d525b --- /dev/null +++ b/src/components/VabSnow/index.vue @@ -0,0 +1,82 @@ + + + + + diff --git a/src/components/VabUpload/index.vue b/src/components/VabUpload/index.vue new file mode 100644 index 000000000..31d83a505 --- /dev/null +++ b/src/components/VabUpload/index.vue @@ -0,0 +1,255 @@ + + + + + diff --git a/src/config/index.js b/src/config/index.js new file mode 100644 index 000000000..86e58d6d9 --- /dev/null +++ b/src/config/index.js @@ -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) diff --git a/src/config/net.config.js b/src/config/net.config.js new file mode 100644 index 000000000..335b8bf8d --- /dev/null +++ b/src/config/net.config.js @@ -0,0 +1,18 @@ +/** + * @description 导出默认网路配置 + **/ +const network = { + //配后端数据的接收方式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 diff --git a/src/config/permission.js b/src/config/permission.js new file mode 100644 index 000000000..82302e899 --- /dev/null +++ b/src/config/permission.js @@ -0,0 +1,78 @@ +import router from '@/router' +import store from '@/store' +import VabProgress from 'nprogress' +import 'nprogress/nprogress.css' +import getPageTitle from '@/utils/pageTitle' +import { + authentication, + loginInterception, + progressBar, + recordRoute, + routesWhiteList, +} from '@/config' + +VabProgress.configure({ + easing: 'ease', + speed: 500, + trickleSpeed: 200, + showSpinner: false, +}) +router.beforeResolve(async (to, from, next) => { + if (progressBar) VabProgress.start() + let hasToken = store.getters['user/accessToken'] + + if (!loginInterception) hasToken = true + + if (hasToken) { + if (to.path === '/login') { + next({ path: '/' }) + if (progressBar) VabProgress.done() + } else { + const hasPermissions = + store.getters['user/permissions'] && + store.getters['user/permissions'].length > 0 + if (hasPermissions) { + next() + } else { + try { + let permissions + if (!loginInterception) { + //settings.js loginInterception为false时,创建虚拟权限 + await store.dispatch('user/setPermissions', ['admin']) + permissions = ['admin'] + } else { + permissions = await store.dispatch('user/getUserInfo') + } + + let accessRoutes = [] + if (authentication === 'intelligence') { + accessRoutes = await store.dispatch('routes/setRoutes', permissions) + } else if (authentication === 'all') { + accessRoutes = await store.dispatch('routes/setAllRoutes') + } + router.addRoute(accessRoutes) + next({ ...to, replace: true }) + } catch { + await store.dispatch('user/resetAccessToken') + if (progressBar) VabProgress.done() + } + } + } + } else { + if (routesWhiteList.indexOf(to.path) !== -1) { + next() + } else { + if (recordRoute) { + next(`/login?redirect=${to.path}`) + } else { + next('/login') + } + + if (progressBar) VabProgress.done() + } + } + document.title = getPageTitle(to.meta.title) +}) +router.afterEach(() => { + if (progressBar) VabProgress.done() +}) diff --git a/src/config/setting.config.js b/src/config/setting.config.js new file mode 100644 index 000000000..db1bb50ca --- /dev/null +++ b/src/config/setting.config.js @@ -0,0 +1,75 @@ +/** + * @description 导出默认通用配置 + */ +const setting = { + // 开发以及部署时的URL + publicPath: '', + // 生产环境构建文件的目录名 + outputDir: 'dist', + // 放置生成的静态资源 (js、css、img、fonts) 的 (相对于 outputDir 的) 目录。 + assetsDir: 'static', + // 开发环境每次保存时是否输出为eslint编译警告 + lintOnSave: true, + // 进行编译的依赖 + transpileDependencies: [], + // 默认的接口地址 如果是开发环境和生产环境走vab-mock-server,当然你也可以选择自己配置成需要的接口地址 + baseURL: + process.env.NODE_ENV === 'development' + ? 'vab-mock-server' + : 'vab-mock-server', + //标题 (包括初次加载雪花屏的标题 页面的标题 浏览器的标题) + title: 'vue-admin-beautiful-pro', + //简写 + abbreviation: 'vab', + //开发环境端口号 + devPort: '80', + //版本号 + version: process.env.VUE_APP_VERSION, + //这一项非常重要!请务必保留MIT协议下package.json及copyright作者信息 即可免费商用,不遵守此项约定你将无法使用该框架,如需自定义版权信息请联系QQ1204505056 + copyright: 'vab', + //是否显示页面底部自定义版权信息 + footerCopyright: true, + //是否显示顶部进度条 + progressBar: true, + //缓存路由的最大数量 + keepAliveMaxNum: 99, + // 路由模式,可选值为 history 或 hash + routerMode: 'hash', + //不经过token校验的路由 + routesWhiteList: ['/login', '/register', '/404', '/401'], + //加载时显示文字 + loadingText: '正在加载中...', + //token名称 + tokenName: 'accessToken', + //token在localStorage、sessionStorage存储的key的名称 + tokenTableName: 'vue-admin-beautiful-2021', + //token存储位置localStorage sessionStorage + storage: 'localStorage', + //token失效回退到登录页时是否记录本次的路由 + recordRoute: true, + //是否显示logo,不显示时设置false,显示时请填写remixIcon图标名称,暂时只支持设置remixIcon + logo: 'vuejs-fill', + //是否显示在页面高亮错误 + errorLog: ['development', 'production'], + //是否开启登录拦截 + loginInterception: true, + //是否开启登录RSA加密 + loginRSA: true, + //intelligence和all两种方式,前者后端权限只控制permissions不控制view文件的import(前后端配合,减轻后端工作量),all方式完全交给后端前端只负责加载 + authentication: 'intelligence', + //vertical布局时是否只保持一个子菜单的展开 + uniqueOpened: true, + //vertical布局时默认展开的菜单path,使用逗号隔开建议只展开一个 + defaultOopeneds: ['/vab'], + //需要加loading层的请求,防止重复提交 + debounce: ['doEdit'], + //需要自动注入并加载的模块 + providePlugin: { maptalks: 'maptalks', 'window.maptalks': 'maptalks' }, + //npm run build时是否自动生成7z压缩包 + build7z: false, + //代码生成机生成在view下的文件夹名称 + templateFolder: 'project', + //是否显示终端donation打印 + donation: true, +} +module.exports = setting diff --git a/src/config/settings.js b/src/config/settings.js new file mode 100644 index 000000000..c070a6691 --- /dev/null +++ b/src/config/settings.js @@ -0,0 +1,6 @@ +/** + * @description 3个子配置,通用配置|主题配置|网络配置 + */ +//默认配置 +const { setting, theme, network } = require('./') +module.exports = Object.assign({}, setting, theme, network) diff --git a/src/config/theme.config.js b/src/config/theme.config.js new file mode 100644 index 000000000..b6a69d235 --- /dev/null +++ b/src/config/theme.config.js @@ -0,0 +1,14 @@ +/** + * @description 导出默认主题配置 + */ +const theme = { + //是否国定头部 固定fixed 不固定noFixed + header: 'fixed', + //横纵布局 horizontal vertical + layout: 'vertical', + //是否开启主题配置按钮 + themeBar: true, + //是否显示多标签页 + tabsBar: true, +} +module.exports = theme diff --git a/src/layouts/EmptyLayout.vue b/src/layouts/EmptyLayout.vue new file mode 100644 index 000000000..98240aef8 --- /dev/null +++ b/src/layouts/EmptyLayout.vue @@ -0,0 +1,3 @@ + diff --git a/src/layouts/components/VabAd/index.vue b/src/layouts/components/VabAd/index.vue new file mode 100644 index 000000000..1184f6559 --- /dev/null +++ b/src/layouts/components/VabAd/index.vue @@ -0,0 +1,52 @@ + + + diff --git a/src/layouts/components/VabAppMain/index.vue b/src/layouts/components/VabAppMain/index.vue new file mode 100644 index 000000000..31a34b88c --- /dev/null +++ b/src/layouts/components/VabAppMain/index.vue @@ -0,0 +1,98 @@ + + + + + diff --git a/src/layouts/components/VabAvatar/index.vue b/src/layouts/components/VabAvatar/index.vue new file mode 100644 index 000000000..67dc68bb6 --- /dev/null +++ b/src/layouts/components/VabAvatar/index.vue @@ -0,0 +1,105 @@ + + + + diff --git a/src/layouts/components/VabBreadcrumb/index.vue b/src/layouts/components/VabBreadcrumb/index.vue new file mode 100644 index 000000000..0259bccba --- /dev/null +++ b/src/layouts/components/VabBreadcrumb/index.vue @@ -0,0 +1,63 @@ + + + + + diff --git a/src/layouts/components/VabLogo/index.vue b/src/layouts/components/VabLogo/index.vue new file mode 100644 index 000000000..c07c1b258 --- /dev/null +++ b/src/layouts/components/VabLogo/index.vue @@ -0,0 +1,92 @@ + + + diff --git a/src/layouts/components/VabNavBar/index.vue b/src/layouts/components/VabNavBar/index.vue new file mode 100644 index 000000000..9a2a63404 --- /dev/null +++ b/src/layouts/components/VabNavBar/index.vue @@ -0,0 +1,136 @@ + + + + + diff --git a/src/layouts/components/VabThemeBar/index.vue b/src/layouts/components/VabThemeBar/index.vue new file mode 100644 index 000000000..bd09aba24 --- /dev/null +++ b/src/layouts/components/VabThemeBar/index.vue @@ -0,0 +1,259 @@ + + + + + + diff --git a/src/layouts/export.js b/src/layouts/export.js new file mode 100644 index 000000000..3a4b71f7a --- /dev/null +++ b/src/layouts/export.js @@ -0,0 +1,25 @@ +/** + + * @description 公共布局及样式自动引入 + */ + +import Vue from 'vue' + +const requireComponents = require.context('./components', true, /\.vue$/) +requireComponents.keys().forEach((fileName) => { + const componentConfig = requireComponents(fileName) + const componentName = componentConfig.default.name + Vue.component(componentName, componentConfig.default || componentConfig) +}) + +const requireZxLayouts = require.context('zx-layouts', true, /\.vue$/) +requireZxLayouts.keys().forEach((fileName) => { + const componentConfig = requireZxLayouts(fileName) + const componentName = componentConfig.default.name + Vue.component(componentName, componentConfig.default || componentConfig) +}) + +const requireThemes = require.context('@/styles/themes', true, /\.scss$/) +requireThemes.keys().forEach((fileName) => { + require(`@/styles/themes/${fileName.slice(2)}`) +}) diff --git a/src/layouts/index.vue b/src/layouts/index.vue new file mode 100644 index 000000000..ef5c93215 --- /dev/null +++ b/src/layouts/index.vue @@ -0,0 +1,304 @@ + + + + + diff --git a/src/main.js b/src/main.js new file mode 100644 index 000000000..945e63cbe --- /dev/null +++ b/src/main.js @@ -0,0 +1,20 @@ +import Vue from 'vue' +import App from './App' +import store from './store' +import router from './router' +import './plugins' +import '@/layouts/export' + +if (process.env.NODE_ENV === 'production') { + const { mockXHR } = require('@/utils/static') + mockXHR() +} + +Vue.config.productionTip = false + +new Vue({ + el: '#vue-admin-beautiful', + router, + store, + render: (h) => h(App), +}) diff --git a/src/plugins/echarts.js b/src/plugins/echarts.js new file mode 100644 index 000000000..f600f836c --- /dev/null +++ b/src/plugins/echarts.js @@ -0,0 +1,4 @@ +import 'echarts' +import VabChart from 'vue-echarts' + +export default VabChart diff --git a/src/plugins/element.js b/src/plugins/element.js new file mode 100644 index 000000000..3b91ff0ac --- /dev/null +++ b/src/plugins/element.js @@ -0,0 +1,9 @@ +import Vue from 'vue' +import ElementUI from 'element-ui' +import 'element-ui/lib/theme-chalk/display.css' + +import '@/styles/element-variables.scss' + +Vue.use(ElementUI, { + size: 'small', +}) diff --git a/src/plugins/index.js b/src/plugins/index.js new file mode 100644 index 000000000..2d4322a6f --- /dev/null +++ b/src/plugins/index.js @@ -0,0 +1,17 @@ +/* 公共引入,勿随意修改,修改时需经过确认 */ +import Vue from 'vue' +import './element' +import './support' +import '@/styles/vab.scss' +import '@/remixIcon' +import '@/colorfulIcon' +import '@/config/permission' +import '@/utils/errorLog' +import './vabIcon' +import VabPermissions from 'zx-layouts/Permissions' +import Vab from '@/utils/vab' +import VabCount from 'zx-count' + +Vue.use(Vab) +Vue.use(VabPermissions) +Vue.use(VabCount) diff --git a/src/plugins/support.js b/src/plugins/support.js new file mode 100644 index 000000000..391064970 --- /dev/null +++ b/src/plugins/support.js @@ -0,0 +1,20 @@ +import { MessageBox } from 'element-ui' +import { donation } from '@/config' +import { dependencies, repository } from '../../package.json' + +if (!!window.ActiveXObject || 'ActiveXObject' in window) { + MessageBox({ + title: '温馨提示', + message: + '自2015年3月起,微软已宣布弃用IE,且不再对IE提供任何更新维护,请点击此处访问微软官网更新浏览器,如果您使用的是双核浏览器,请您切换浏览器内核为极速模式', + type: 'warning', + showClose: false, + showConfirmButton: false, + closeOnClickModal: false, + closeOnPressEscape: false, + closeOnHashChange: false, + dangerouslyUseHTMLString: true, + }) +} +if (!dependencies['vab-icon'] || !dependencies['zx-layouts']) + document.body.innerHTML = '' diff --git a/src/plugins/vabIcon.js b/src/plugins/vabIcon.js new file mode 100644 index 000000000..634bca731 --- /dev/null +++ b/src/plugins/vabIcon.js @@ -0,0 +1,4 @@ +import Vue from 'vue' +import VabIcon from 'vab-icon' + +Vue.component('VabIcon', VabIcon) diff --git a/src/plugins/vabMagnifier.js b/src/plugins/vabMagnifier.js new file mode 100644 index 000000000..748fda247 --- /dev/null +++ b/src/plugins/vabMagnifier.js @@ -0,0 +1,3 @@ +import VabMagnifier from 'zx-magnifie' + +export default VabMagnifier diff --git a/src/plugins/vabMarkdownEditor.js b/src/plugins/vabMarkdownEditor.js new file mode 100644 index 000000000..03686b69c --- /dev/null +++ b/src/plugins/vabMarkdownEditor.js @@ -0,0 +1,5 @@ +import ZxMarkdownEditor from 'zx-markdown-editor' +import 'zx-markdown-editor/dist/zx-markdown-editor.css' + +const VabMarkdownEditor = ZxMarkdownEditor +export default VabMarkdownEditor diff --git a/src/plugins/vabPlayer.js b/src/plugins/vabPlayer.js new file mode 100644 index 000000000..69bf8a798 --- /dev/null +++ b/src/plugins/vabPlayer.js @@ -0,0 +1,3 @@ +import { VabPlayerMp4, VabPlayerHls, VabPlayerFlv } from 'zx-player' + +export { VabPlayerMp4, VabPlayerHls, VabPlayerFlv } diff --git a/src/plugins/vabQuill.js b/src/plugins/vabQuill.js new file mode 100644 index 000000000..eae4bbf4c --- /dev/null +++ b/src/plugins/vabQuill.js @@ -0,0 +1,4 @@ +import 'zx-quill/dist/zx-quill.css' +import VabQuill from 'zx-quill' + +export default VabQuill diff --git a/src/plugins/vabVerify.js b/src/plugins/vabVerify.js new file mode 100644 index 000000000..e98ae43e2 --- /dev/null +++ b/src/plugins/vabVerify.js @@ -0,0 +1,4 @@ +import VabVerify from 'zx-verify' +import 'zx-verify/dist/zx-verify.css' + +export default VabVerify diff --git a/src/remixIcon/index.js b/src/remixIcon/index.js new file mode 100644 index 000000000..2dd876e1f --- /dev/null +++ b/src/remixIcon/index.js @@ -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) diff --git a/src/remixIcon/svg/qq-fill.svg b/src/remixIcon/svg/qq-fill.svg new file mode 100644 index 000000000..1f446b117 --- /dev/null +++ b/src/remixIcon/svg/qq-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/remixIcon/svg/vuejs-fill.svg b/src/remixIcon/svg/vuejs-fill.svg new file mode 100644 index 000000000..1b1a1371b --- /dev/null +++ b/src/remixIcon/svg/vuejs-fill.svg @@ -0,0 +1 @@ + diff --git a/src/router/index.js b/src/router/index.js new file mode 100644 index 000000000..d3add9e70 --- /dev/null +++ b/src/router/index.js @@ -0,0 +1,382 @@ +/** + * @description router全局配置 + */ + +import Vue from 'vue' +import VueRouter from 'vue-router' +import Layout from '@/layouts' +import EmptyLayout from '@/layouts/EmptyLayout' +import { publicPath, routerMode } from '@/config' + +Vue.use(VueRouter) +export const constantRoutes = [ + { + path: '/login', + component: () => import('@/views/login/index'), + hidden: true, + }, + { + path: '/register', + component: () => import('@/views/register/index'), + hidden: true, + }, + { + path: '/401', + name: '401', + component: () => import('@/views/401'), + hidden: true, + }, + { + path: '/404', + name: '404', + component: () => import('@/views/404'), + hidden: true, + }, +] + +export const asyncRoutes = [ + { + path: '/', + component: Layout, + redirect: 'index', + children: [ + { + path: 'index', + name: 'Index', + component: () => import('@/views/index/index'), + meta: { + title: '首页', + icon: 'home', + affix: true, + }, + }, + ], + }, + + { + path: '/vab', + component: Layout, + redirect: 'noRedirect', + name: 'Vab', + alwaysShow: true, + meta: { title: '组件', icon: 'box-open' }, + children: [ + { + path: 'permissions', + name: 'Permission', + component: () => import('@/views/vab/permissions/index'), + meta: { + title: '角色权限', + permissions: ['admin', 'editor'], + }, + }, + { + path: 'icon', + component: EmptyLayout, + redirect: 'noRedirect', + name: 'Icon', + meta: { + title: '图标', + permissions: ['admin'], + }, + children: [ + { + path: 'awesomeIcon', + name: 'AwesomeIcon', + component: () => import('@/views/vab/icon/index'), + meta: { title: '常规图标' }, + }, + { + path: 'remixIcon', + name: 'RemixIcon', + component: () => import('@/views/vab/icon/remixIcon'), + meta: { title: '小清新图标' }, + }, + { + path: 'colorfulIcon', + name: 'ColorfulIcon', + component: () => import('@/views/vab/icon/colorfulIcon'), + meta: { title: '多彩图标' }, + }, + ], + }, + { + path: 'table', + component: () => import('@/views/vab/table/index'), + name: 'Table', + meta: { + title: '表格', + permissions: ['admin'], + }, + }, + { + path: 'map', + component: () => import('@/views/vab/map/index'), + name: 'Map', + meta: { + title: '地图', + permissions: ['admin'], + }, + }, + + { + path: 'webSocket', + name: 'WebSocket', + component: () => import('@/views/vab/webSocket/index'), + meta: { title: 'webSocket', permissions: ['admin'] }, + }, + { + path: 'form', + name: 'Form', + component: () => import('@/views/vab/form/index'), + meta: { title: '表单', permissions: ['admin'] }, + }, + { + path: 'element', + name: 'Element', + component: () => import('@/views/vab/element/index'), + meta: { title: '常用组件', permissions: ['admin'] }, + }, + { + path: 'tree', + name: 'Tree', + component: () => import('@/views/vab/tree/index'), + meta: { title: '树', permissions: ['admin'] }, + }, + { + path: 'verify', + name: 'Verify', + component: () => import('@/views/vab/verify/index'), + meta: { title: '验证码', permissions: ['admin'] }, + }, + { + path: 'menu1', + component: () => import('@/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: () => import('@/views/vab/nested/menu1/menu1-1/index'), + + children: [ + { + path: 'menu1-1-1', + name: 'Menu1-1-1', + meta: { title: '嵌套路由 1-1-1' }, + component: () => + import('@/views/vab/nested/menu1/menu1-1/menu1-1-1/index'), + }, + ], + }, + ], + }, + { + path: 'magnifier', + name: 'Magnifier', + component: () => import('@/views/vab/magnifier/index'), + meta: { title: '放大镜', permissions: ['admin'] }, + }, + { + path: 'loading', + name: 'Loading', + component: () => import('@/views/vab/loading/index'), + meta: { title: 'loading', permissions: ['admin'] }, + }, + { + path: 'player', + name: 'Player', + component: () => import('@/views/vab/player/index'), + meta: { title: '视频播放器', permissions: ['admin'] }, + }, + { + path: 'markdownEditor', + name: 'MarkdownEditor', + component: () => import('@/views/vab/markdownEditor/index'), + meta: { title: 'markdown编辑器', permissions: ['admin'] }, + }, + { + path: 'editor', + name: 'Editor', + component: () => import('@/views/vab/editor/index'), + meta: { + title: '富文本编辑器', + permissions: ['admin'], + badge: 'New', + }, + }, + { + path: 'backToTop', + name: 'BackToTop', + component: () => import('@/views/vab/backToTop/index'), + meta: { title: '返回顶部', permissions: ['admin'] }, + }, + { + path: 'lodash', + name: 'Lodash', + component: () => import('@/views/vab/lodash/index'), + meta: { title: 'lodash', permissions: ['admin'] }, + }, + { + path: 'smallComponents', + name: 'SmallComponents', + component: () => import('@/views/vab/smallComponents/index'), + meta: { title: '小组件', permissions: ['admin'] }, + }, + + { + path: 'upload', + name: 'Upload', + component: () => import('@/views/vab/upload/index'), + meta: { title: '上传', permissions: ['admin'] }, + }, + { + path: 'log', + name: 'Log', + component: () => import('@/views/vab/errorLog/index'), + meta: { title: '错误日志模拟', permissions: ['admin'] }, + }, + { + path: + 'https://github.com/chuzhixin/vue-admin-beautiful?utm_source=gold_browser_extension', + name: 'ExternalLink', + meta: { + title: '外链', + target: '_blank', + permissions: ['admin', 'editor'], + badge: 'New', + }, + }, + { + path: 'more', + name: 'More', + component: () => import('@/views/vab/more/index'), + meta: { title: '关于', permissions: ['admin'] }, + }, + ], + }, + { + path: '/personnelManagement', + component: Layout, + redirect: 'noRedirect', + name: 'PersonnelManagement', + meta: { title: '配置', icon: 'users-cog', permissions: ['admin'] }, + children: [ + { + path: 'userManagement', + name: 'UserManagement', + component: () => + import('@/views/personnelManagement/userManagement/index'), + meta: { title: '用户管理' }, + }, + { + path: 'roleManagement', + name: 'RoleManagement', + component: () => + import('@/views/personnelManagement/roleManagement/index'), + meta: { title: '角色管理' }, + }, + { + path: 'menuManagement', + name: 'MenuManagement', + component: () => + import('@/views/personnelManagement/menuManagement/index'), + meta: { title: '菜单管理', badge: 'New' }, + }, + ], + }, + { + path: '/mall', + component: Layout, + redirect: 'noRedirect', + name: 'Mall', + meta: { + title: '商城', + icon: 'shopping-cart', + permissions: ['admin'], + }, + + children: [ + { + path: 'pay', + name: 'Pay', + component: () => import('@/views/mall/pay/index'), + meta: { + title: '支付', + noKeepAlive: true, + }, + children: null, + }, + { + path: 'goodsList', + name: 'GoodsList', + component: () => import('@/views/mall/goodsList/index'), + meta: { + title: '商品列表', + }, + }, + ], + }, + { + path: '/error', + component: EmptyLayout, + redirect: 'noRedirect', + name: 'Error', + meta: { title: '错误页', icon: 'bug' }, + children: [ + { + path: '401', + name: 'Error401', + component: () => import('@/views/401'), + meta: { title: '401' }, + }, + { + path: '404', + name: 'Error404', + component: () => import('@/views/404'), + meta: { title: '404' }, + }, + ], + }, + { + path: '*', + redirect: '/404', + hidden: true, + }, +] + +const router = new VueRouter({ + base: publicPath, + mode: routerMode, + scrollBehavior: () => ({ + y: 0, + }), + routes: constantRoutes, +}) +//注释的地方是允许路由重复点击,如果你觉得框架路由跳转规范太过严格可选择放开 +const originalPush = VueRouter.prototype.push +VueRouter.prototype.push = function push(location, onResolve, onReject) { + if (onResolve || onReject) + return originalPush.call(this, location, onResolve, onReject) + return originalPush.call(this, location).catch((err) => err) +} + +export function resetRouter() { + router.matcher = new VueRouter({ + base: publicPath, + mode: routerMode, + scrollBehavior: () => ({ + y: 0, + }), + routes: constantRoutes, + }).matcher +} + +export default router diff --git a/src/store/index.js b/src/store/index.js new file mode 100644 index 000000000..157a2d5df --- /dev/null +++ b/src/store/index.js @@ -0,0 +1,21 @@ +/** + * @description 导入所有 vuex 模块,自动加入namespaced:true,用于解决vuex命名冲突,请勿修改。 + */ + +import Vue from 'vue' +import Vuex from 'vuex' + +Vue.use(Vuex) +const files = require.context('./modules', false, /\.js$/) +const modules = {} + +files.keys().forEach((key) => { + modules[key.replace(/(\.\/|\.js)/g, '')] = files(key).default +}) +Object.keys(modules).forEach((key) => { + modules[key]['namespaced'] = true +}) +const store = new Vuex.Store({ + modules, +}) +export default store diff --git a/src/store/modules/errorLog.js b/src/store/modules/errorLog.js new file mode 100644 index 000000000..d06be28a4 --- /dev/null +++ b/src/store/modules/errorLog.js @@ -0,0 +1,28 @@ +/** + + * @description 异常捕获的状态拦截,请勿修改 + */ + +const state = () => ({ + errorLogs: [], +}) +const getters = { + errorLogs: (state) => state.errorLogs, +} +const mutations = { + addErrorLog(state, errorLog) { + state.errorLogs.push(errorLog) + }, + clearErrorLog: (state) => { + state.errorLogs.splice(0) + }, +} +const actions = { + addErrorLog({ commit }, errorLog) { + commit('addErrorLog', errorLog) + }, + clearErrorLog({ commit }) { + commit('clearErrorLog') + }, +} +export default { state, getters, mutations, actions } diff --git a/src/store/modules/routes.js b/src/store/modules/routes.js new file mode 100644 index 000000000..c2b9b3192 --- /dev/null +++ b/src/store/modules/routes.js @@ -0,0 +1,50 @@ +/** + + * @description 路由拦截状态管理,目前两种模式:all模式与intelligence模式,其中partialRoutes是菜单暂未使用 + */ +import { asyncRoutes, constantRoutes } from '@/router' +import { getRouterList } from '@/api/router' +import { convertRouter, filterAsyncRoutes } from '@/utils/handleRoutes' + +const state = () => ({ + routes: [], + partialRoutes: [], +}) +const getters = { + routes: (state) => state.routes, + partialRoutes: (state) => state.partialRoutes, +} +const mutations = { + setRoutes(state, routes) { + state.routes = constantRoutes.concat(routes) + }, + setAllRoutes(state, routes) { + state.routes = constantRoutes.concat(routes) + }, + setPartialRoutes(state, routes) { + state.partialRoutes = constantRoutes.concat(routes) + }, +} +const actions = { + async setRoutes({ commit }, permissions) { + //开源版只过滤动态路由permissions,admin不再默认拥有全部权限 + const finallyAsyncRoutes = await filterAsyncRoutes( + [...asyncRoutes], + permissions + ) + commit('setRoutes', finallyAsyncRoutes) + return finallyAsyncRoutes + }, + async setAllRoutes({ commit }) { + let { data } = await getRouterList() + data.push({ path: '*', redirect: '/404', hidden: true }) + let accessRoutes = convertRouter(data) + commit('setAllRoutes', accessRoutes) + return accessRoutes + }, + setPartialRoutes({ commit }, accessRoutes) { + commit('setPartialRoutes', accessRoutes) + return accessRoutes + }, +} +export default { state, getters, mutations, actions } diff --git a/src/store/modules/settings.js b/src/store/modules/settings.js new file mode 100644 index 000000000..a0573430b --- /dev/null +++ b/src/store/modules/settings.js @@ -0,0 +1,75 @@ +/** + + * @description 所有全局配置的状态管理,如无必要请勿修改 + */ + +import defaultSettings from '@/config' + +const { tabsBar, logo, layout, header, themeBar } = defaultSettings +const theme = + JSON.parse(localStorage.getItem('vue-admin-beautiful-theme')) || '' +const state = () => ({ + tabsBar: theme.tabsBar || tabsBar, + logo, + collapse: false, + layout: theme.layout || layout, + header: theme.header || header, + device: 'desktop', + themeBar, +}) +const getters = { + collapse: (state) => state.collapse, + device: (state) => state.device, + header: (state) => state.header, + layout: (state) => state.layout, + logo: (state) => state.logo, + tabsBar: (state) => state.tabsBar, + themeBar: (state) => state.themeBar, +} +const mutations = { + changeLayout: (state, layout) => { + if (layout) state.layout = layout + }, + changeHeader: (state, header) => { + if (header) state.header = header + }, + changeTabsBar: (state, tabsBar) => { + if (tabsBar) state.tabsBar = tabsBar + }, + changeCollapse: (state) => { + state.collapse = !state.collapse + }, + foldSideBar: (state) => { + state.collapse = true + }, + openSideBar: (state) => { + state.collapse = false + }, + toggleDevice: (state, device) => { + state.device = device + }, +} +const actions = { + changeLayout({ commit }, layout) { + commit('changeLayout', layout) + }, + changeHeader({ commit }, header) { + commit('changeHeader', header) + }, + changeTabsBar({ commit }, tabsBar) { + commit('changeTabsBar', tabsBar) + }, + changeCollapse({ commit }) { + commit('changeCollapse') + }, + foldSideBar({ commit }) { + commit('foldSideBar') + }, + openSideBar({ commit }) { + commit('openSideBar') + }, + toggleDevice({ commit }, device) { + commit('toggleDevice', device) + }, +} +export default { state, getters, mutations, actions } diff --git a/src/store/modules/table.js b/src/store/modules/table.js new file mode 100644 index 000000000..70898a0e2 --- /dev/null +++ b/src/store/modules/table.js @@ -0,0 +1,23 @@ +/** + + * @description 代码生成机状态管理 + */ + +const state = () => ({ + srcCode: '', +}) +const getters = { + srcTableCode: (state) => state.srcCode, +} + +const mutations = { + setTableCode(state, srcCode) { + state.srcCode = srcCode + }, +} +const actions = { + setTableCode({ commit }, srcCode) { + commit('setTableCode', srcCode) + }, +} +export default { state, getters, mutations, actions } diff --git a/src/store/modules/tabsBar.js b/src/store/modules/tabsBar.js new file mode 100644 index 000000000..b9c9e8c65 --- /dev/null +++ b/src/store/modules/tabsBar.js @@ -0,0 +1,112 @@ +/** + + * @description tabsBar多标签页逻辑,前期借鉴了很多开源项目发现都有个共同的特点很繁琐并不符合框架设计的初衷,后来在github用户hipi的启发下完成了重构,请勿修改 + */ + +const state = () => ({ + visitedRoutes: [], +}) +const getters = { + visitedRoutes: (state) => state.visitedRoutes, +} +const mutations = { + addVisitedRoute(state, route) { + let target = state.visitedRoutes.find((item) => item.path === route.path) + if (target) { + if (route.fullPath !== target.fullPath) Object.assign(target, route) + return + } + state.visitedRoutes.push(Object.assign({}, route)) + }, + delVisitedRoute(state, route) { + state.visitedRoutes.forEach((item, index) => { + if (item.path === route.path) state.visitedRoutes.splice(index, 1) + }) + }, + delOthersVisitedRoute(state, route) { + state.visitedRoutes = state.visitedRoutes.filter( + (item) => item.meta.affix || item.path === route.path + ) + }, + delLeftVisitedRoute(state, route) { + let index = state.visitedRoutes.length + state.visitedRoutes = state.visitedRoutes.filter((item) => { + if (item.name === route.name) index = state.visitedRoutes.indexOf(item) + return item.meta.affix || index <= state.visitedRoutes.indexOf(item) + }) + }, + delRightVisitedRoute(state, route) { + let index = state.visitedRoutes.length + state.visitedRoutes = state.visitedRoutes.filter((item) => { + if (item.name === route.name) index = state.visitedRoutes.indexOf(item) + return item.meta.affix || index >= state.visitedRoutes.indexOf(item) + }) + }, + delAllVisitedRoutes(state) { + state.visitedRoutes = state.visitedRoutes.filter((item) => item.meta.affix) + }, + updateVisitedRoute(state, route) { + state.visitedRoutes.forEach((item) => { + if (item.path === route.path) item = Object.assign(item, route) + }) + }, +} +const actions = { + addVisitedRoute({ commit }, route) { + commit('addVisitedRoute', route) + }, + async delRoute({ dispatch, state }, route) { + await dispatch('delVisitedRoute', route) + return { + visitedRoutes: [...state.visitedRoutes], + } + }, + delVisitedRoute({ commit, state }, route) { + commit('delVisitedRoute', route) + return [...state.visitedRoutes] + }, + async delOthersRoutes({ dispatch, state }, route) { + await dispatch('delOthersVisitedRoute', route) + return { + visitedRoutes: [...state.visitedRoutes], + } + }, + async delLeftRoutes({ dispatch, state }, route) { + await dispatch('delLeftVisitedRoute', route) + return { + visitedRoutes: [...state.visitedRoutes], + } + }, + async delRightRoutes({ dispatch, state }, route) { + await dispatch('delRightVisitedRoute', route) + return { + visitedRoutes: [...state.visitedRoutes], + } + }, + delOthersVisitedRoute({ commit, state }, route) { + commit('delOthersVisitedRoute', route) + return [...state.visitedRoutes] + }, + delLeftVisitedRoute({ commit, state }, route) { + commit('delLeftVisitedRoute', route) + return [...state.visitedRoutes] + }, + delRightVisitedRoute({ commit, state }, route) { + commit('delRightVisitedRoute', route) + return [...state.visitedRoutes] + }, + async delAllRoutes({ dispatch, state }, route) { + await dispatch('delAllVisitedRoutes', route) + return { + visitedRoutes: [...state.visitedRoutes], + } + }, + delAllVisitedRoutes({ commit, state }) { + commit('delAllVisitedRoutes') + return [...state.visitedRoutes] + }, + updateVisitedRoute({ commit }, route) { + commit('updateVisitedRoute', route) + }, +} +export default { state, getters, mutations, actions } diff --git a/src/store/modules/user.js b/src/store/modules/user.js new file mode 100644 index 000000000..e810b4e36 --- /dev/null +++ b/src/store/modules/user.js @@ -0,0 +1,99 @@ +/** + + * @description 登录、获取用户信息、退出登录、清除accessToken逻辑,不建议修改 + */ + +import Vue from 'vue' +import { getUserInfo, login, logout } from '@/api/user' +import { + getAccessToken, + removeAccessToken, + setAccessToken, +} from '@/utils/accessToken' +import { resetRouter } from '@/router' +import { title, tokenName } from '@/config' + +const state = () => ({ + accessToken: getAccessToken(), + username: '', + avatar: '', + permissions: [], +}) +const getters = { + accessToken: (state) => state.accessToken, + username: (state) => state.username, + avatar: (state) => state.avatar, + permissions: (state) => state.permissions, +} +const mutations = { + setAccessToken(state, accessToken) { + state.accessToken = accessToken + setAccessToken(accessToken) + }, + setUsername(state, username) { + state.username = username + }, + setAvatar(state, avatar) { + state.avatar = avatar + }, + setPermissions(state, permissions) { + state.permissions = permissions + }, +} +const actions = { + setPermissions({ commit }, permissions) { + commit('setPermissions', permissions) + }, + async login({ commit }, userInfo) { + const { data } = await login(userInfo) + const accessToken = data[tokenName] + if (accessToken) { + commit('setAccessToken', accessToken) + const hour = new Date().getHours() + const thisTime = + hour < 8 + ? '早上好' + : hour <= 11 + ? '上午好' + : hour <= 13 + ? '中午好' + : hour < 18 + ? '下午好' + : '晚上好' + Vue.prototype.$baseNotify(`欢迎登录${title}`, `${thisTime}!`) + } else { + Vue.prototype.$baseMessage( + `登录接口异常,未正确返回${tokenName}...`, + 'error' + ) + } + }, + async getUserInfo({ commit, state }) { + const { data } = await getUserInfo(state.accessToken) + if (!data) { + Vue.prototype.$baseMessage('验证失败,请重新登录...', 'error') + return false + } + let { permissions, username, avatar } = data + if (permissions && username && Array.isArray(permissions)) { + commit('setPermissions', permissions) + commit('setUsername', username) + commit('setAvatar', avatar) + return permissions + } else { + Vue.prototype.$baseMessage('用户信息接口异常', 'error') + return false + } + }, + async logout({ dispatch }) { + await logout(state.accessToken) + await dispatch('resetAccessToken') + await resetRouter() + }, + resetAccessToken({ commit }) { + commit('setPermissions', []) + commit('setAccessToken', '') + removeAccessToken() + }, +} +export default { state, getters, mutations, actions } diff --git a/src/styles/element-variables.scss b/src/styles/element-variables.scss new file mode 100644 index 000000000..8da98a7ff --- /dev/null +++ b/src/styles/element-variables.scss @@ -0,0 +1,1037 @@ +@charset "utf-8"; + +/* Transition +-------------------------- */ +$--all-transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1); +$--fade-transition: opacity 300ms cubic-bezier(0.23, 1, 0.32, 1); +$--fade-linear-transition: opacity 200ms linear; +$--md-fade-transition: transform 300ms cubic-bezier(0.23, 1, 0.32, 1), + opacity 300ms cubic-bezier(0.23, 1, 0.32, 1); +$--border-transition-base: border-color 0.2s + cubic-bezier(0.645, 0.045, 0.355, 1); +$--color-transition-base: color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1); + +/* Color +-------------------------- */ +/// color|1|Brand Color|0 +$--color-primary: $base-color-blue; +/// color|1|Background Color|4 +$--color-white: #fff; +/// color|1|Background Color|4 +$--color-black: #000; +$--color-primary-light-1: mix($--color-white, $--color-primary, 10%); + +/* 53a8ff */ +$--color-primary-light-2: mix($--color-white, $--color-primary, 20%); + +/* 66b1ff */ +$--color-primary-light-3: mix($--color-white, $--color-primary, 30%); + +/* 79bbff */ +$--color-primary-light-4: mix($--color-white, $--color-primary, 40%); + +/* 8cc5ff */ +$--color-primary-light-5: mix($--color-white, $--color-primary, 50%); + +/* a0cfff */ +$--color-primary-light-6: mix($--color-white, $--color-primary, 60%); + +/* b3d8ff */ +$--color-primary-light-7: mix($--color-white, $--color-primary, 70%); + +/* c6e2ff */ +$--color-primary-light-8: mix($--color-white, $--color-primary, 80%); + +/* d9ecff */ +$--color-primary-light-9: mix($--color-white, $--color-primary, 90%); + +/* ecf5ff */ +/// color|1|Functional Color|1 +$--color-success: $base-color-green; +/// color|1|Functional Color|1 +$--color-warning: $base-color-yellow; +/// color|1|Functional Color|1 +$--color-danger: $base-color-red; +/// color|1|Functional Color|1 +$--color-info: #909399; + +$--color-success-light: mix($--color-white, $--color-success, 80%); +$--color-warning-light: mix($--color-white, $--color-warning, 80%); +$--color-danger-light: mix($--color-white, $--color-danger, 80%); +$--color-info-light: mix($--color-white, $--color-info, 80%); + +$--color-success-lighter: mix($--color-white, $--color-success, 90%); +$--color-warning-lighter: mix($--color-white, $--color-warning, 90%); +$--color-danger-lighter: mix($--color-white, $--color-danger, 90%); +$--color-info-lighter: mix($--color-white, $--color-info, 90%); +/// color|1|Font Color|2 +$--color-text-primary: #303133; +/// color|1|Font Color|2 +$--color-text-regular: #606266; +/// color|1|Font Color|2 +$--color-text-secondary: #909399; +/// color|1|Font Color|2 +$--color-text-placeholder: #c0c4cc; +/// color|1|Border Color|3 +$--border-color-base: #dcdfe6; +/// color|1|Border Color|3 +$--border-color-light: #e4e7ed; +/// color|1|Border Color|3 +$--border-color-lighter: #ebeef5; +/// color|1|Border Color|3 +$--border-color-extra-light: #f2f6fc; + +// Background +/// color|1|Background Color|4 +$--background-color-base: #f5f7fa; + +/* Link +-------------------------- */ +$--link-color: $--color-primary-light-2; +$--link-hover-color: $--color-primary; + +/* Border +-------------------------- */ +$--border-width-base: 1px; +$--border-style-base: solid; +$--border-color-hover: $--color-text-placeholder; +$--border-base: $--border-width-base $--border-style-base $--border-color-base; +/// borderRadius|1|Radius|0 +$--border-radius-base: $base-border-radius; +/// borderRadius|1|Radius|0 +$--border-radius-small: $base-border-radius; +/// borderRadius|1|Radius|0 +$--border-radius-circle: 100%; +/// borderRadius|1|Radius|0 +$--border-radius-zero: 0; + +// Box-shadow +/// boxShadow|1|Shadow|1 +$--box-shadow-base: 0 2px 4px rgba(0, 0, 0, 0.12), 0 0 6px rgba(0, 0, 0, 0.04); +// boxShadow|1|Shadow|1 +$--box-shadow-dark: 0 2px 4px rgba(0, 0, 0, 0.12), 0 0 6px rgba(0, 0, 0, 0.12); +/// boxShadow|1|Shadow|1 +$--box-shadow-light: 0 2px 12px 0 rgba(0, 0, 0, 0.1); + +/* Fill +-------------------------- */ +$--fill-base: $--color-white; + +/* Typography +-------------------------- */ +$--font-path: "~element-ui/lib/theme-chalk/fonts"; +$--font-display: "auto"; +/// fontSize|1|Font Size|0 +$--font-size-extra-large: 20px; +/// fontSize|1|Font Size|0 +$--font-size-large: 18px; +/// fontSize|1|Font Size|0 +$--font-size-medium: 16px; +/// fontSize|1|Font Size|0 +$--font-size-base: 14px; +/// fontSize|1|Font Size|0 +$--font-size-small: 13px; +/// fontSize|1|Font Size|0 +$--font-size-extra-small: 12px; +/// fontWeight|1|Font Weight|1 +$--font-weight-primary: 500; +/// fontWeight|1|Font Weight|1 +$--font-weight-secondary: 100; +/// fontLineHeight|1|Line Height|2 +$--font-line-height-primary: 24px; +/// fontLineHeight|1|Line Height|2 +$--font-line-height-secondary: 16px; +$--font-color-disabled-base: #bbb; + +/* Size +-------------------------- */ +$--size-base: 14px; + +/* z-index +-------------------------- */ +$--index-normal: 1; +$--index-top: 1000; +$--index-popper: 2000; + +/* Disable base +-------------------------- */ +$--disabled-fill-base: $--background-color-base; +$--disabled-color-base: $--color-text-placeholder; +$--disabled-border-base: $--border-color-light; + +/* Icon +-------------------------- */ +$--icon-color: #666; +$--icon-color-base: $--color-info; + +/* Checkbox +-------------------------- */ +/// fontSize||Font|1 +$--checkbox-font-size: 14px; +/// fontWeight||Font|1 +$--checkbox-font-weight: $--font-weight-primary; +/// color||Color|0 +$--checkbox-font-color: $--color-text-regular; +$--checkbox-input-height: 14px; +$--checkbox-input-width: 14px; +/// borderRadius||Border|2 +$--checkbox-border-radius: $--border-radius-small; +/// color||Color|0 +$--checkbox-background-color: $--color-white; +$--checkbox-input-border: $--border-base; + +/// color||Color|0 +$--checkbox-disabled-border-color: $--border-color-base; +$--checkbox-disabled-input-fill: #edf2fc; +$--checkbox-disabled-icon-color: $--color-text-placeholder; + +$--checkbox-disabled-checked-input-fill: $--border-color-extra-light; +$--checkbox-disabled-checked-input-border-color: $--border-color-base; +$--checkbox-disabled-checked-icon-color: $--color-text-placeholder; + +/// color||Color|0 +$--checkbox-checked-font-color: $--color-primary; +$--checkbox-checked-input-border-color: $--color-primary; +/// color||Color|0 +$--checkbox-checked-background-color: $--color-primary; +$--checkbox-checked-icon-color: $--fill-base; + +$--checkbox-input-border-color-hover: $--color-primary; +/// height||Other|4 +$--checkbox-bordered-height: 40px; +/// padding||Spacing|3 +$--checkbox-bordered-padding: 9px 20px 9px 10px; +/// padding||Spacing|3 +$--checkbox-bordered-medium-padding: 7px 20px 7px 10px; +/// padding||Spacing|3 +$--checkbox-bordered-small-padding: 5px 15px 5px 10px; +/// padding||Spacing|3 +$--checkbox-bordered-mini-padding: 3px 15px 3px 10px; +$--checkbox-bordered-medium-input-height: 14px; +$--checkbox-bordered-medium-input-width: 14px; +/// height||Other|4 +$--checkbox-bordered-medium-height: 36px; +$--checkbox-bordered-small-input-height: 12px; +$--checkbox-bordered-small-input-width: 12px; +/// height||Other|4 +$--checkbox-bordered-small-height: 32px; +$--checkbox-bordered-mini-input-height: 12px; +$--checkbox-bordered-mini-input-width: 12px; +/// height||Other|4 +$--checkbox-bordered-mini-height: 28px; + +/// color||Color|0 +$--checkbox-button-checked-background-color: $--color-primary; +/// color||Color|0 +$--checkbox-button-checked-font-color: $--color-white; +/// color||Color|0 +$--checkbox-button-checked-border-color: $--color-primary; + +/* Radio +-------------------------- */ +/// fontSize||Font|1 +$--radio-font-size: $--font-size-base; +/// fontWeight||Font|1 +$--radio-font-weight: $--font-weight-primary; +/// color||Color|0 +$--radio-font-color: $--color-text-regular; +$--radio-input-height: 14px; +$--radio-input-width: 14px; +/// borderRadius||Border|2 +$--radio-input-border-radius: $--border-radius-circle; +/// color||Color|0 +$--radio-input-background-color: $--color-white; +$--radio-input-border: $--border-base; +/// color||Color|0 +$--radio-input-border-color: $--border-color-base; +/// color||Color|0 +$--radio-icon-color: $--color-white; + +$--radio-disabled-input-border-color: $--disabled-border-base; +$--radio-disabled-input-fill: $--disabled-fill-base; +$--radio-disabled-icon-color: $--disabled-fill-base; + +$--radio-disabled-checked-input-border-color: $--disabled-border-base; +$--radio-disabled-checked-input-fill: $--disabled-fill-base; +$--radio-disabled-checked-icon-color: $--color-text-placeholder; + +/// color||Color|0 +$--radio-checked-font-color: $--color-primary; +/// color||Color|0 +$--radio-checked-input-border-color: $--color-primary; +/// color||Color|0 +$--radio-checked-input-background-color: $--color-white; +/// color||Color|0 +$--radio-checked-icon-color: $--color-primary; + +$--radio-input-border-color-hover: $--color-primary; + +$--radio-bordered-height: 40px; +$--radio-bordered-padding: 12px 20px 0 10px; +$--radio-bordered-medium-padding: 10px 20px 0 10px; +$--radio-bordered-small-padding: 8px 15px 0 10px; +$--radio-bordered-mini-padding: 6px 15px 0 10px; +$--radio-bordered-medium-input-height: 14px; +$--radio-bordered-medium-input-width: 14px; +$--radio-bordered-medium-height: 36px; +$--radio-bordered-small-input-height: 12px; +$--radio-bordered-small-input-width: 12px; +$--radio-bordered-small-height: 32px; +$--radio-bordered-mini-input-height: 12px; +$--radio-bordered-mini-input-width: 12px; +$--radio-bordered-mini-height: 28px; + +/// fontSize||Font|1 +$--radio-button-font-size: $--font-size-base; +/// color||Color|0 +$--radio-button-checked-background-color: $--color-primary; +/// color||Color|0 +$--radio-button-checked-font-color: $--color-white; +/// color||Color|0 +$--radio-button-checked-border-color: $--color-primary; +$--radio-button-disabled-checked-fill: $--border-color-extra-light; + +/* Select +-------------------------- */ +$--select-border-color-hover: $--border-color-hover; +$--select-disabled-border: $--disabled-border-base; +/// fontSize||Font|1 +$--select-font-size: $--font-size-base; +$--select-close-hover-color: $--color-text-secondary; + +$--select-input-color: $--color-text-placeholder; +$--select-multiple-input-color: #666; +/// color||Color|0 +$--select-input-focus-border-color: $--color-primary; +/// fontSize||Font|1 +$--select-input-font-size: 14px; + +$--select-option-color: $--color-text-regular; +$--select-option-disabled-color: $--color-text-placeholder; +$--select-option-disabled-background: $--color-white; +/// height||Other|4 +$--select-option-height: 34px; +$--select-option-hover-background: $--background-color-base; +/// color||Color|0 +$--select-option-selected-font-color: $--color-primary; +$--select-option-selected-hover: $--background-color-base; + +$--select-group-color: $--color-info; +$--select-group-height: 30px; +$--select-group-font-size: 12px; + +$--select-dropdown-background: $--color-white; +$--select-dropdown-shadow: $--box-shadow-light; +$--select-dropdown-empty-color: #999; +/// height||Other|4 +$--select-dropdown-max-height: 274px; +$--select-dropdown-padding: 6px 0; +$--select-dropdown-empty-padding: 10px 0; +$--select-dropdown-border: solid 1px $--border-color-light; + +/* Alert +-------------------------- */ +$--alert-padding: 8px 16px; +/// borderRadius||Border|2 +$--alert-border-radius: $--border-radius-base; +/// fontSize||Font|1 +$--alert-title-font-size: 13px; +/// fontSize||Font|1 +$--alert-description-font-size: 12px; +/// fontSize||Font|1 +$--alert-close-font-size: 12px; +/// fontSize||Font|1 +$--alert-close-customed-font-size: 13px; + +$--alert-success-color: $--color-success-lighter; +$--alert-info-color: $--color-info-lighter; +$--alert-warning-color: $--color-warning-lighter; +$--alert-danger-color: $--color-danger-lighter; + +/// height||Other|4 +$--alert-icon-size: 16px; +/// height||Other|4 +$--alert-icon-large-size: 28px; + +/* MessageBox +-------------------------- */ +/// color||Color|0 +$--messagebox-title-color: $--color-text-primary; +$--msgbox-width: 420px; +$--msgbox-border-radius: $--border-radius-base; +/// fontSize||Font|1 +$--messagebox-font-size: $--font-size-large; +/// fontSize||Font|1 +$--messagebox-content-font-size: $--font-size-base; +/// color||Color|0 +$--messagebox-content-color: $--color-text-regular; +/// fontSize||Font|1 +$--messagebox-error-font-size: 12px; +$--msgbox-padding-primary: 15px; +/// color||Color|0 +$--messagebox-success-color: $--color-success; +/// color||Color|0 +$--messagebox-info-color: $--color-info; +/// color||Color|0 +$--messagebox-warning-color: $--color-warning; +/// color||Color|0 +$--messagebox-danger-color: $--color-danger; + +/* Message +-------------------------- */ +$--message-shadow: $--box-shadow-base; +$--message-min-width: 380px; +$--message-background-color: #edf2fc; +$--message-padding: 15px 15px 15px 20px; +/// color||Color|0 +$--message-close-icon-color: $--color-text-placeholder; +/// height||Other|4 +$--message-close-size: 16px; +/// color||Color|0 +$--message-close-hover-color: $--color-text-secondary; + +/// color||Color|0 +$--message-success-font-color: $--color-success; +/// color||Color|0 +$--message-info-font-color: $--color-info; +/// color||Color|0 +$--message-warning-font-color: $--color-warning; +/// color||Color|0 +$--message-danger-font-color: $--color-danger; + +/* Notification +-------------------------- */ +$--notification-width: 330px; +/// padding||Spacing|3 +$--notification-padding: 14px 26px 14px 13px; +$--notification-radius: 8px; +$--notification-shadow: $--box-shadow-light; +/// color||Color|0 +$--notification-border-color: $--border-color-lighter; +$--notification-icon-size: 24px; +$--notification-close-font-size: $--message-close-size; +$--notification-group-margin-left: 13px; +$--notification-group-margin-right: 8px; +/// fontSize||Font|1 +$--notification-content-font-size: $--font-size-base; +/// color||Color|0 +$--notification-content-color: $--color-text-regular; +/// fontSize||Font|1 +$--notification-title-font-size: 16px; +/// color||Color|0 +$--notification-title-color: $--color-text-primary; + +/// color||Color|0 +$--notification-close-color: $--color-text-secondary; +/// color||Color|0 +$--notification-close-hover-color: $--color-text-regular; + +/// color||Color|0 +$--notification-success-icon-color: $--color-success; +/// color||Color|0 +$--notification-info-icon-color: $--color-info; +/// color||Color|0 +$--notification-warning-icon-color: $--color-warning; +/// color||Color|0 +$--notification-danger-icon-color: $--color-danger; + +/* Input +-------------------------- */ +$--input-font-size: $--font-size-base; +/// color||Color|0 +$--input-font-color: $--color-text-regular; +/// height||Other|4 +$--input-width: 140px; +/// height||Other|4 +$--input-height: 40px; +$--input-border: $--border-base; +$--input-border-color: $--border-color-base; +/// borderRadius||Border|2 +$--input-border-radius: $--border-radius-base; +$--input-border-color-hover: $--border-color-hover; +/// color||Color|0 +$--input-background-color: $--color-white; +$--input-fill-disabled: $--disabled-fill-base; +$--input-color-disabled: $--font-color-disabled-base; +/// color||Color|0 +$--input-icon-color: $--color-text-placeholder; +/// color||Color|0 +$--input-placeholder-color: $--color-text-placeholder; +$--input-max-width: 314px; + +$--input-hover-border: $--border-color-hover; +$--input-clear-hover-color: $--color-text-secondary; + +$--input-focus-border: $--color-primary; +$--input-focus-fill: $--color-white; + +$--input-disabled-fill: $--disabled-fill-base; +$--input-disabled-border: $--disabled-border-base; +$--input-disabled-color: $--disabled-color-base; +$--input-disabled-placeholder-color: $--color-text-placeholder; + +/// fontSize||Font|1 +$--input-medium-font-size: 14px; +/// height||Other|4 +$--input-medium-height: 36px; +/// fontSize||Font|1 +$--input-small-font-size: 13px; +/// height||Other|4 +$--input-small-height: 32px; +/// fontSize||Font|1 +$--input-mini-font-size: 12px; +/// height||Other|4 +$--input-mini-height: 28px; + +/* Cascader +-------------------------- */ +/// color||Color|0 +$--cascader-menu-font-color: $--color-text-regular; +/// color||Color|0 +$--cascader-menu-selected-font-color: $--color-primary; +$--cascader-menu-fill: $--fill-base; +$--cascader-menu-font-size: $--font-size-base; +$--cascader-menu-radius: $--border-radius-base; +$--cascader-menu-border: solid 1px $--border-color-light; +$--cascader-menu-shadow: $--box-shadow-light; +$--cascader-node-background-hover: $--background-color-base; +$--cascader-node-color-disabled: $--color-text-placeholder; +$--cascader-color-empty: $--color-text-placeholder; +$--cascader-tag-background: #f0f2f5; + +/* Group +-------------------------- */ +$--group-option-flex: 0 0 (1/5) * 100%; +$--group-option-offset-bottom: 12px; +$--group-option-fill-hover: rgba($--color-black, 0.06); +$--group-title-color: $--color-black; +$--group-title-font-size: $--font-size-base; +$--group-title-width: 66px; + +/* Tab +-------------------------- */ +$--tab-font-size: $--font-size-base; +$--tab-border-line: 1px solid #e4e4e4; +$--tab-header-color-active: $--color-text-secondary; +$--tab-header-color-hover: $--color-text-regular; +$--tab-header-color: $--color-text-regular; +$--tab-header-fill-active: rgba($--color-black, 0.06); +$--tab-header-fill-hover: rgba($--color-black, 0.06); +$--tab-vertical-header-width: 90px; +$--tab-vertical-header-count-color: $--color-white; +$--tab-vertical-header-count-fill: $--color-text-secondary; + +/* Button +-------------------------- */ +/// fontSize||Font|1 +$--button-font-size: $--font-size-base; +/// fontWeight||Font|1 +$--button-font-weight: $--font-weight-primary; +/// borderRadius||Border|2 +$--button-border-radius: $--border-radius-base; +/// padding||Spacing|3 +$--button-padding-vertical: 12px; +/// padding||Spacing|3 +$--button-padding-horizontal: 20px; + +/// fontSize||Font|1 +$--button-medium-font-size: $--font-size-base; +/// borderRadius||Border|2 +$--button-medium-border-radius: $--border-radius-base; +/// padding||Spacing|3 +$--button-medium-padding-vertical: 10px; +/// padding||Spacing|3 +$--button-medium-padding-horizontal: 20px; + +/// fontSize||Font|1 +$--button-small-font-size: 12px; +$--button-small-border-radius: $--border-radius-base; +/// padding||Spacing|3 +$--button-small-padding-vertical: 9px; +/// padding||Spacing|3 +$--button-small-padding-horizontal: 15px; +/// fontSize||Font|1 +$--button-mini-font-size: 12px; +$--button-mini-border-radius: $--border-radius-base; +/// padding||Spacing|3 +$--button-mini-padding-vertical: 7px; +/// padding||Spacing|3 +$--button-mini-padding-horizontal: 15px; + +/// color||Color|0 +$--button-default-font-color: $--color-text-regular; +/// color||Color|0 +$--button-default-background-color: $--color-white; +/// color||Color|0 +$--button-default-border-color: $--border-color-base; + +/// color||Color|0 +$--button-disabled-font-color: $--color-text-placeholder; +/// color||Color|0 +$--button-disabled-background-color: $--color-white; +/// color||Color|0 +$--button-disabled-border-color: $--border-color-lighter; + +/// color||Color|0 +$--button-primary-border-color: $--color-primary; +/// color||Color|0 +$--button-primary-font-color: $--color-white; +/// color||Color|0 +$--button-primary-background-color: $--color-primary; +/// color||Color|0 +$--button-success-border-color: $--color-success; +/// color||Color|0 +$--button-success-font-color: $--color-white; +/// color||Color|0 +$--button-success-background-color: $--color-success; +/// color||Color|0 +$--button-warning-border-color: $--color-warning; +/// color||Color|0 +$--button-warning-font-color: $--color-white; +/// color||Color|0 +$--button-warning-background-color: $--color-warning; +/// color||Color|0 +$--button-danger-border-color: $--color-danger; +/// color||Color|0 +$--button-danger-font-color: $--color-white; +/// color||Color|0 +$--button-danger-background-color: $--color-danger; +/// color||Color|0 +$--button-info-border-color: $--color-info; +/// color||Color|0 +$--button-info-font-color: $--color-white; +/// color||Color|0 +$--button-info-background-color: $--color-info; + +$--button-hover-tint-percent: 20%; +$--button-active-shade-percent: 10%; + +/* cascader +-------------------------- */ +$--cascader-height: 200px; + +/* Switch +-------------------------- */ +/// color||Color|0 +$--switch-on-color: $--color-primary; +/// color||Color|0 +$--switch-off-color: $--border-color-base; +/// fontSize||Font|1 +$--switch-font-size: $--font-size-base; +$--switch-core-border-radius: 10px; +// height||Other|4 TODO: width 代码写死的40px 所以下面这三个属性都没意义 +$--switch-width: 40px; +// height||Other|4 +$--switch-height: 20px; +// height||Other|4 +$--switch-button-size: 16px; + +/* Dialog +-------------------------- */ +$--dialog-background-color: $--color-white; +$--dialog-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); +/// fontSize||Font|1 +$--dialog-title-font-size: $--font-size-large; +/// fontSize||Font|1 +$--dialog-content-font-size: 14px; +/// fontLineHeight||LineHeight|2 +$--dialog-font-line-height: $--font-line-height-primary; +/// padding||Spacing|3 +$--dialog-padding-primary: 20px; + +/* Table +-------------------------- */ +/// color||Color|0 +$--table-border-color: $--border-color-lighter; +$--table-border: 1px solid $--table-border-color; +/// color||Color|0 +$--table-font-color: $--color-text-regular; +/// color||Color|0 +$--table-header-font-color: $--color-text-secondary; +/// color||Color|0 +$--table-row-hover-background-color: $--background-color-base; +$--table-current-row-background-color: $--color-primary-light-9; +/// color||Color|0 +$--table-header-background-color: $--color-white; +$--table-fixed-box-shadow: 0 0 10px rgba(0, 0, 0, 0.12); + +/* Pagination +-------------------------- */ +/// fontSize||Font|1 +$--pagination-font-size: 13px; +/// color||Color|0 +$--pagination-background-color: $--color-white; +/// color||Color|0 +$--pagination-font-color: $--color-text-primary; +$--pagination-border-radius: $--border-radius-base; +/// color||Color|0 +$--pagination-button-color: $--color-text-primary; +/// height||Other|4 +$--pagination-button-width: 35.5px; +/// height||Other|4 +$--pagination-button-height: 28px; +/// color||Color|0 +$--pagination-button-disabled-color: $--color-text-placeholder; +/// color||Color|0 +$--pagination-button-disabled-background-color: $--color-white; +/// color||Color|0 +$--pagination-hover-color: $--color-primary; + +/* Popup +-------------------------- */ +/// color||Color|0 +$--popup-modal-background-color: $--color-black; +/// opacity||Other|1 +$--popup-modal-opacity: 0.5; + +/* Popover +-------------------------- */ +/// color||Color|0 +$--popover-background-color: $--color-white; +/// fontSize||Font|1 +$--popover-font-size: $--font-size-base; +/// color||Color|0 +$--popover-border-color: $--border-color-lighter; +$--popover-arrow-size: 6px; +/// padding||Spacing|3 +$--popover-padding: 12px; +$--popover-padding-large: 18px 20px; +/// fontSize||Font|1 +$--popover-title-font-size: 16px; +/// color||Color|0 +$--popover-title-font-color: $--color-text-primary; + +/* Tooltip +-------------------------- */ +/// color|1|Color|0 +$--tooltip-fill: $--color-text-primary; +/// color|1|Color|0 +$--tooltip-color: $--color-white; +/// fontSize||Font|1 +$--tooltip-font-size: 12px; +/// color||Color|0 +$--tooltip-border-color: $--color-text-primary; +$--tooltip-arrow-size: 6px; +/// padding||Spacing|3 +$--tooltip-padding: 10px; + +/* Tag +-------------------------- */ +/// color||Color|0 +$--tag-info-color: $--color-info; +/// color||Color|0 +$--tag-primary-color: $--color-primary; +/// color||Color|0 +$--tag-success-color: $--color-success; +/// color||Color|0 +$--tag-warning-color: $--color-warning; +/// color||Color|0 +$--tag-danger-color: $--color-danger; +/// fontSize||Font|1 +$--tag-font-size: 12px; +$--tag-border-radius: $--border-radius-base; +$--tag-padding: 0 10px; + +/* Tree +-------------------------- */ +/// color||Color|0 +$--tree-node-hover-background-color: $--background-color-base; +/// color||Color|0 +$--tree-font-color: $--color-text-regular; +/// color||Color|0 +$--tree-expand-icon-color: $--color-text-placeholder; + +/* Dropdown +-------------------------- */ +$--dropdown-menu-box-shadow: $--box-shadow-light; +$--dropdown-menuItem-hover-fill: $--color-primary-light-9; +$--dropdown-menuItem-hover-color: $--link-color; + +/* Badge +-------------------------- */ +/// color||Color|0 +$--badge-background-color: $--color-danger; +$--badge-radius: 10px; +/// fontSize||Font|1 +$--badge-font-size: 12px; +/// padding||Spacing|3 +$--badge-padding: 6px; +/// height||Other|4 +$--badge-size: 18px; + +/* Card +-------------------------- */ +/// color||Color|0 +$--card-border-color: $--border-color-lighter; +$--card-border-radius: $--border-radius-base; +/// padding||Spacing|3 +$--card-padding: 20px; + +/* Slider +-------------------------- */ +/// color||Color|0 +$--slider-main-background-color: $--color-primary; +/// color||Color|0 +$--slider-runway-background-color: $--border-color-light; +$--slider-button-hover-color: mix($--color-primary, black, 97%); +$--slider-stop-background-color: $--color-white; +$--slider-disable-color: $--color-text-placeholder; +$--slider-margin: 16px 0; +$--slider-border-radius: $--border-radius-base; +/// height|1|Other|4 +$--slider-height: 6px; +/// height||Other|4 +$--slider-button-size: 16px; +$--slider-button-wrapper-size: 36px; +$--slider-button-wrapper-offset: -15px; + +/* Steps +-------------------------- */ +$--steps-border-color: $--disabled-border-base; +$--steps-border-radius: $--border-radius-base; +$--steps-padding: 20px; + +/* Menu +-------------------------- */ +/// fontSize||Font|1 +$--menu-item-font-size: $--font-size-base; +/// color||Color|0 +$--menu-item-font-color: $--color-text-primary; +/// color||Color|0 +$--menu-background-color: $--color-white; +$--menu-item-hover-fill: $--color-primary-light-9; + +/* Rate +-------------------------- */ +$--rate-height: 20px; +/// fontSize||Font|1 +$--rate-font-size: $--font-size-base; +/// height||Other|3 +$--rate-icon-size: 18px; +/// margin||Spacing|2 +$--rate-icon-margin: 6px; +$--rate-icon-color: $--color-text-placeholder; + +/* DatePicker +-------------------------- */ +$--datepicker-font-color: $--color-text-regular; +/// color|1|Color|0 +$--datepicker-off-font-color: $--color-text-placeholder; +/// color||Color|0 +$--datepicker-header-font-color: $--color-text-regular; +$--datepicker-icon-color: $--color-text-primary; +$--datepicker-border-color: $--disabled-border-base; +$--datepicker-inner-border-color: #e4e4e4; +/// color||Color|0 +$--datepicker-inrange-background-color: $--border-color-extra-light; +/// color||Color|0 +$--datepicker-inrange-hover-background-color: $--border-color-extra-light; +/// color||Color|0 +$--datepicker-active-color: $--color-primary; +/// color||Color|0 +$--datepicker-hover-font-color: $--color-primary; +$--datepicker-cell-hover-color: #fff; + +/* Loading +-------------------------- */ +/// height||Other|4 +$--loading-spinner-size: 42px; +/// height||Other|4 +$--loading-fullscreen-spinner-size: 50px; + +/* Scrollbar +-------------------------- */ +$--scrollbar-background-color: rgba($--color-text-secondary, 0.3); +$--scrollbar-hover-background-color: rgba($--color-text-secondary, 0.5); + +/* Carousel +-------------------------- */ +/// fontSize||Font|1 +$--carousel-arrow-font-size: 12px; +$--carousel-arrow-size: 36px; +$--carousel-arrow-background: rgba(31, 45, 61, 0.11); +$--carousel-arrow-hover-background: rgba(31, 45, 61, 0.23); +/// width||Other|4 +$--carousel-indicator-width: 30px; +/// height||Other|4 +$--carousel-indicator-height: 2px; +$--carousel-indicator-padding-horizontal: 4px; +$--carousel-indicator-padding-vertical: 12px; +$--carousel-indicator-out-color: $--border-color-hover; + +/* Collapse +-------------------------- */ +/// color||Color|0 +$--collapse-border-color: $--border-color-lighter; +/// height||Other|4 +$--collapse-header-height: 48px; +/// color||Color|0 +$--collapse-header-background-color: $--color-white; +/// color||Color|0 +$--collapse-header-font-color: $--color-text-primary; +/// fontSize||Font|1 +$--collapse-header-font-size: 13px; +/// color||Color|0 +$--collapse-content-background-color: $--color-white; +/// fontSize||Font|1 +$--collapse-content-font-size: 13px; +/// color||Color|0 +$--collapse-content-font-color: $--color-text-primary; + +/* Transfer +-------------------------- */ +$--transfer-border-color: $--border-color-lighter; +$--transfer-border-radius: $--border-radius-base; +/// height||Other|4 +$--transfer-panel-width: 200px; +/// height||Other|4 +$--transfer-panel-header-height: 40px; +/// color||Color|0 +$--transfer-panel-header-background-color: $--background-color-base; +/// height||Other|4 +$--transfer-panel-footer-height: 40px; +/// height||Other|4 +$--transfer-panel-body-height: 246px; +/// height||Other|4 +$--transfer-item-height: 30px; +/// height||Other|4 +$--transfer-filter-height: 32px; + +/* Header + -------------------------- */ +$--header-padding: 0 20px; + +/* Footer +-------------------------- */ +$--footer-padding: 0 20px; + +/* Main +-------------------------- */ +$--main-padding: 20px; + +/* Timeline +-------------------------- */ +$--timeline-node-size-normal: 12px; +$--timeline-node-size-large: 14px; +$--timeline-node-color: $--border-color-light; + +/* Backtop +-------------------------- */ +/// color||Color|0 +$--backtop-background-color: $--color-white; +/// color||Color|0 +$--backtop-font-color: $--color-primary; +/// color||Color|0 +$--backtop-hover-background-color: $--border-color-extra-light; + +/* Link +-------------------------- */ +/// fontSize||Font|1 +$--link-font-size: $--font-size-base; +/// fontWeight||Font|1 +$--link-font-weight: $--font-weight-primary; +/// color||Color|0 +$--link-default-font-color: $--color-text-regular; +/// color||Color|0 +$--link-default-active-color: $--color-primary; +/// color||Color|0 +$--link-disabled-font-color: $--color-text-placeholder; +/// color||Color|0 +$--link-primary-font-color: $--color-primary; +/// color||Color|0 +$--link-success-font-color: $--color-success; +/// color||Color|0 +$--link-warning-font-color: $--color-warning; +/// color||Color|0 +$--link-danger-font-color: $--color-danger; +/// color||Color|0 +$--link-info-font-color: $--color-info; + +/* Calendar +-------------------------- */ +/// border||Other|4 +$--calendar-border: $--table-border; +/// color||Other|4 +$--calendar-selected-background-color: #f2f8fe; +$--calendar-cell-width: 85px; + +/* Form +-------------------------- */ +/// fontSize||Font|1 +$--form-label-font-size: $--font-size-base; + +/* Avatar +-------------------------- */ +/// color||Color|0 +$--avatar-font-color: #fff; +/// color||Color|0 +$--avatar-background-color: #c0c4cc; +/// fontSize||Font Size|1 +$--avatar-text-font-size: 14px; +/// fontSize||Font Size|1 +$--avatar-icon-font-size: 18px; +/// borderRadius||Border|2 +$--avatar-border-radius: $--border-radius-base; +/// size|1|Avatar Size|3 +$--avatar-large-size: 40px; +/// size|1|Avatar Size|3 +$--avatar-medium-size: 36px; +/// size|1|Avatar Size|3 +$--avatar-small-size: 28px; + +/* Break-point +-------------------------- */ +$--sm: 768px; +$--md: 992px; +$--lg: 1200px; +$--xl: 1920px; + +$--breakpoints: ( + "xs": ( + max-width: $--sm - 1, + ), + "sm": ( + min-width: $--sm, + ), + "md": ( + min-width: $--md, + ), + "lg": ( + min-width: $--lg, + ), + "xl": ( + min-width: $--xl, + ), +); + +$--breakpoints-spec: ( + "xs-only": ( + max-width: $--sm - 1, + ), + "sm-and-up": ( + min-width: $--sm, + ), + "sm-only": "(min-width: #{$--sm}) and (max-width: #{$--md - 1})", + "sm-and-down": ( + max-width: $--md - 1, + ), + "md-and-up": ( + min-width: $--md, + ), + "md-only": "(min-width: #{$--md}) and (max-width: #{$--lg - 1})", + "md-and-down": ( + max-width: $--lg - 1, + ), + "lg-and-up": ( + min-width: $--lg, + ), + "lg-only": "(min-width: #{$--lg}) and (max-width: #{$--xl - 1})", + "lg-and-down": ( + max-width: $--xl - 1, + ), + "xl-only": ( + min-width: $--xl, + ), +); + +@import "~element-ui/packages/theme-chalk/src/index"; diff --git a/src/styles/loading.scss b/src/styles/loading.scss new file mode 100644 index 000000000..bb8515070 --- /dev/null +++ b/src/styles/loading.scss @@ -0,0 +1,346 @@ +/** + + * @description 全局加载动画 + */ + +@charset "utf-8"; + +@import "./spinner/dots.css"; +@import "./spinner/gauge.css"; +@import "./spinner/inner-circles.css"; +@import "./spinner/plus.css"; + +$base-loading: ".vab-loading-type"; + +/* 自定义loading开始 */ +#{$base-loading}1 { + display: flex; + width: 36px; + height: 36px; + margin: 0 auto 15px; + border: 3px solid transparent; + border-top-color: $base-color-blue; + border-bottom-color: $base-color-blue; + border-radius: 50%; + animation: vabLoading1-0 0.8s linear infinite; +} + +#{$base-loading}1::before { + display: block; + width: 8px; + height: 8px; + margin: auto; + content: ""; + border: 3px solid $base-color-blue; + border-radius: 50%; + animation: vabLoading1 0.5s alternate ease-in infinite; +} + +@keyframes vabLoading1-0 { + to { + transform: rotate(360deg); + } +} + +@keyframes vabLoading1 { + from { + transform: scale(0.5); + } + + to { + transform: scale(1.2); + } +} + +#{$base-loading}2 { + width: 20px; + height: 20px; + margin-top: -40px; + margin-left: -10px; + animation: vabLoading2 1s linear reverse infinite; +} + +#{$base-loading}2::before { + display: block; + width: 36px; + height: 36px; + margin-top: -17px; + margin-left: -18px; + content: ""; + animation: vabLoading2 0.4s linear infinite; +} + +#{$base-loading}2::after { + display: block; + width: 8px; + height: 8px; + margin-top: -3px; + margin-left: -4px; + content: ""; + animation: vabLoading2 0.4s linear infinite; +} + +#{$base-loading}2::before, +#{$base-loading}2, +#{$base-loading}2::after { + position: absolute; + top: 40%; + left: 50%; + border: 3px solid transparent; + border-top-color: $base-color-blue; + border-right-color: $base-color-blue; + border-radius: 50%; +} + +@keyframes vabLoading2 { + to { + transform: rotate(360deg); + } +} + +#{$base-loading}3 { + display: inline-block; + width: 2.5em; + height: 3em; + margin-bottom: 15px; + border: 3px solid transparent; + border-top-color: $base-color-blue; + border-bottom-color: $base-color-blue; + border-radius: 50%; + animation: vabLoading3 2s ease infinite; +} + +@keyframes vabLoading3 { + 50% { + border-width: 8px; + transform: rotate(360deg) scale(0.4, 0.33); + } + + 100% { + border-width: 3px; + transform: rotate(720deg) scale(1, 1); + } +} + +#{$base-loading}4 { + display: inline-block; + width: 30px; + height: 30px; + margin: 0 auto 10px; + border: 8px solid transparent; + border-bottom-color: $base-color-blue; + border-left-color: $base-color-blue; + border-radius: 50%; + animation: vabLoading4 1s linear infinite normal; +} + +#{$base-loading}4::after { + display: block; + width: 15px; + height: 15px; + margin: 0; + content: " "; + border: 6px solid $base-color-blue; + border-bottom-color: transparent; + border-left-color: transparent; + border-radius: 50%; +} + +@keyframes vabLoading4 { + 0% { + opacity: 0.2; + transform: rotate(0deg); + } + + 50% { + opacity: 1; + transform: rotate(180deg); + } + + 100% { + opacity: 0.2; + transform: rotate(360deg); + } +} + +#{$base-loading}5 { + display: block; + width: 0; + height: 0; + margin: 0 auto 15px; + border: solid 1.5em $base-color-blue; + border-right: solid 1.5em transparent; + border-left: solid 1.5em transparent; + border-radius: 100%; + animation: vabLoading5 1s linear infinite; +} + +@keyframes vabLoading5 { + 0% { + transform: rotate(0deg); + } + + 50% { + transform: rotate(60deg); + } + + 100% { + transform: rotate(360deg); + } +} + +#{$base-loading}6 { + display: block; + width: 0; + height: 0; + margin: 0 auto 25px auto; + perspective: 200px; +} + +#{$base-loading}6::before, +#{$base-loading}6::after { + position: absolute; + width: 20px; + height: 20px; + content: ""; + background: rgba(0, 0, 0, 0); + animation: vabLoading6 0.5s infinite alternate; +} + +#{$base-loading}6::before { + left: 0; +} + +#{$base-loading}6::after { + right: 0; + animation-delay: 0.15s; +} + +@keyframes vabLoading6 { + 0% { + box-shadow: 0 0 0 rgba(0, 0, 0, 0); + transform: scale(1) translateY(0) rotateX(0deg); + } + + 100% { + background: $base-color-blue; + box-shadow: 0 25px 40px rgba($base-color-blue, 0.5); + transform: scale(1.2) translateY(-25px) rotateX(45deg); + } +} + +#{$base-loading}7 { + display: block; + width: 25px; + height: 25px; + margin: 0 auto 15px auto; + border: 2px solid $base-color-blue; + border-top-color: rgba($base-color-blue, 0.2); + border-right-color: rgba($base-color-blue, 0.2); + border-bottom-color: rgba($base-color-blue, 0.2); + border-radius: 100%; + animation: vabLoading7 infinite 0.75s linear; +} + +@keyframes vabLoading7 { + 0% { + transform: rotate(0); + } + + 100% { + transform: rotate(360deg); + } +} + +#{$base-loading}8 { + position: relative; + box-sizing: border-box; + display: block; + width: 20px; + height: 20px; + margin: 0 auto 15px auto; + background-color: $base-color-blue; + border-radius: 50%; + box-shadow: 30px 0 0 0 $base-color-blue; + transform: translateX(-15px); +} + +#{$base-loading}8::after { + position: absolute; + top: 8px; + left: 9px; + width: 10px; + height: 10px; + content: ""; + background-color: $base-color-white; + border-radius: 50%; + box-shadow: 30px 0 0 0 $base-color-white; + animation: vabLoading8 2s ease-in-out infinite alternate; +} + +@keyframes vabLoading8 { + 0% { + left: 9px; + } + + 100% { + left: 1px; + } +} + +#{$base-loading}9 { + position: relative; + box-sizing: border-box; + display: block; + width: 20px; + height: 20px; + margin: 0 auto 15px auto; + border: 1px $base-color-blue solid; + animation: vabLoading9 5s linear infinite; +} + +#{$base-loading}9::after { + position: absolute; + top: -8px; + left: 0; + width: 4px; + height: 4px; + content: ""; + background-color: $base-color-blue; + animation: vabLoading9_check 1s ease-in-out infinite; +} + +@keyframes vabLoading9_check { + 25% { + top: -8px; + left: 22px; + } + + 50% { + top: 22px; + left: 22px; + } + + 75% { + top: 22px; + left: -9px; + } + + 100% { + top: -7px; + left: -9px; + } +} + +@keyframes vabLoading9 { + 0% { + box-shadow: inset 0 0 0 0 rgba($base-color-blue, 0.5); + opacity: 0.5; + } + + 100% { + box-shadow: inset 0 -20px 0 0 $base-color-blue; + } +} + +/* 自定义loading结束 */ diff --git a/src/styles/normalize.scss b/src/styles/normalize.scss new file mode 100644 index 000000000..fe27fe8e8 --- /dev/null +++ b/src/styles/normalize.scss @@ -0,0 +1,353 @@ +@charset "utf-8"; + +/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ + +/* Document + ========================================================================== */ + +/** + * 1. Correct the line height in all browsers. + * 2. Prevent adjustments of font size after orientation changes in iOS. + */ + +html { + line-height: 1.15; /* 1 */ + -webkit-text-size-adjust: 100%; /* 2 */ +} + +/* Sections + ========================================================================== */ + +/** + * Remove the margin in all browsers. + */ + +body { + margin: 0; +} + +/** + * Render the `main` element consistently in IE. + */ + +main { + display: block; +} + +/** + * Correct the font size and margin on `h1` elements within `section` and + * `article` contexts in Chrome, Firefox, and Safari. + */ + +h1 { + margin: 0.67em 0; + font-size: 2em; +} + +/* Grouping content + ========================================================================== */ + +/** + * 1. Add the correct box sizing in Firefox. + * 2. Show the overflow in Edge and IE. + */ + +hr { + box-sizing: content-box; /* 1 */ + height: 0; /* 1 */ + overflow: visible; /* 2 */ +} + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + +pre { + font-family: monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/* Text-level semantics + ========================================================================== */ + +/** + * Remove the gray background on active links in IE 10. + */ + +a { + background-color: transparent; +} + +/** + * 1. Remove the bottom border in Chrome 57- + * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. + */ + +abbr[title] { + text-decoration: underline; /* 2 */ + text-decoration: underline dotted; /* 2 */ + border-bottom: none; /* 1 */ +} + +/** + * Add the correct font weight in Chrome, Edge, and Safari. + */ + +b, +strong { + font-weight: bolder; +} + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + +code, +kbd, +samp { + font-family: monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/** + * Add the correct font size in all browsers. + */ + +small { + font-size: 80%; +} + +/** + * Prevent `sub` and `sup` elements from affecting the line height in + * all browsers. + */ + +sub, +sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* Embedded content + ========================================================================== */ + +/** + * Remove the border on images inside links in IE 10. + */ + +img { + border-style: none; +} + +/* Forms + ========================================================================== */ + +/** + * 1. Change the font styles in all browsers. + * 2. Remove the margin in Firefox and Safari. + */ + +button, +input, +optgroup, +select, +textarea { + margin: 0; /* 2 */ + font-family: inherit; /* 1 */ + font-size: 100%; /* 1 */ + line-height: 1.15; /* 1 */ +} + +/** + * Show the overflow in IE. + * 1. Show the overflow in Edge. + */ + +button, +input { + /* 1 */ + overflow: visible; +} + +/** + * Remove the inheritance of text transform in Edge, Firefox, and IE. + * 1. Remove the inheritance of text transform in Firefox. + */ + +button, +select { + /* 1 */ + text-transform: none; +} + +/** + * Correct the inability to style clickable types in iOS and Safari. + */ + +button, +[type="button"], +[type="reset"], +[type="submit"] { + -webkit-appearance: button; +} + +/** + * Remove the inner border and padding in Firefox. + */ + +button::-moz-focus-inner, +[type="button"]::-moz-focus-inner, +[type="reset"]::-moz-focus-inner, +[type="submit"]::-moz-focus-inner { + padding: 0; + border-style: none; +} + +/** + * Restore the focus styles unset by the previous rule. + */ + +button:-moz-focusring, +[type="button"]:-moz-focusring, +[type="reset"]:-moz-focusring, +[type="submit"]:-moz-focusring { + outline: 1px dotted ButtonText; +} + +/** + * Correct the padding in Firefox. + */ + +fieldset { + padding: 0.35em 0.75em 0.625em; +} + +/** + * 1. Correct the text wrapping in Edge and IE. + * 2. Correct the color inheritance from `fieldset` elements in IE. + * 3. Remove the padding so developers are not caught out when they zero out + * `fieldset` elements in all browsers. + */ + +legend { + box-sizing: border-box; /* 1 */ + display: table; /* 1 */ + max-width: 100%; /* 1 */ + padding: 0; /* 3 */ + color: inherit; /* 2 */ + white-space: normal; /* 1 */ +} + +/** + * Add the correct vertical alignment in Chrome, Firefox, and Opera. + */ + +progress { + vertical-align: baseline; +} + +/** + * Remove the default vertical scrollbar in IE 10+. + */ + +textarea { + overflow: auto; +} + +/** + * 1. Add the correct box sizing in IE 10. + * 2. Remove the padding in IE 10. + */ + +[type="checkbox"], +[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Correct the cursor style of increment and decrement buttons in Chrome. + */ + +[type="number"]::-webkit-inner-spin-button, +[type="number"]::-webkit-outer-spin-button { + height: auto; +} + +/** + * 1. Correct the odd appearance in Chrome and Safari. + * 2. Correct the outline style in Safari. + */ + +[type="search"] { + -webkit-appearance: textfield; /* 1 */ + outline-offset: -2px; /* 2 */ +} + +/** + * Remove the inner padding in Chrome and Safari on macOS. + */ + +[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** + * 1. Correct the inability to style clickable types in iOS and Safari. + * 2. Change font properties to `inherit` in Safari. + */ + +::-webkit-file-upload-button { + -webkit-appearance: button; /* 1 */ + font: inherit; /* 2 */ +} + +/* Interactive + ========================================================================== */ + +/* + * Add the correct display in Edge, IE 10+, and Firefox. + */ + +details { + display: block; +} + +/* + * Add the correct display in all browsers. + */ + +summary { + display: list-item; +} + +/* Misc + ========================================================================== */ + +/** + * Add the correct display in IE 10+. + */ + +template { + display: none; +} + +/** + * Add the correct display in IE 10. + */ + +[hidden] { + display: none; +} diff --git a/src/styles/spinner/dots.css b/src/styles/spinner/dots.css new file mode 100644 index 000000000..33bef9507 --- /dev/null +++ b/src/styles/spinner/dots.css @@ -0,0 +1,110 @@ +.dots-loader:not(:required) { + position: relative; + display: inline-block; + width: 7px; + height: 7px; + margin-bottom: 30px; + overflow: hidden; + text-indent: -9999px; + background: transparent; + border-radius: 100%; + box-shadow: #f86 -14px -14px 0 7px, + #fc6 14px -14px 0 7px, + #6d7 14px 14px 0 7px, + #4ae -14px 14px 0 7px; + transform-origin: 50% 50%; + animation: dots-loader 5s infinite ease-in-out; +} + +@keyframes dots-loader { + 0% { + box-shadow: #f86 -14px -14px 0 7px, + #fc6 14px -14px 0 7px, + #6d7 14px 14px 0 7px, + #4ae -14px 14px 0 7px; + } + + 8.33% { + box-shadow: #f86 14px -14px 0 7px, + #fc6 14px -14px 0 7px, + #6d7 14px 14px 0 7px, + #4ae -14px 14px 0 7px; + } + + 16.67% { + box-shadow: #f86 14px 14px 0 7px, + #fc6 14px 14px 0 7px, + #6d7 14px 14px 0 7px, + #4ae -14px 14px 0 7px; + } + + 25% { + box-shadow: #f86 -14px 14px 0 7px, + #fc6 -14px 14px 0 7px, + #6d7 -14px 14px 0 7px, + #4ae -14px 14px 0 7px; + } + + 33.33% { + box-shadow: #f86 -14px -14px 0 7px, + #fc6 -14px 14px 0 7px, + #6d7 -14px -14px 0 7px, + #4ae -14px -14px 0 7px; + } + + 41.67% { + box-shadow: #f86 14px -14px 0 7px, + #fc6 -14px 14px 0 7px, + #6d7 -14px -14px 0 7px, + #4ae 14px -14px 0 7px; + } + + 50% { + box-shadow: #f86 14px 14px 0 7px, + #fc6 -14px 14px 0 7px, + #6d7 -14px -14px 0 7px, + #4ae 14px -14px 0 7px; + } + + 58.33% { + box-shadow: #f86 -14px 14px 0 7px, + #fc6 -14px 14px 0 7px, + #6d7 -14px -14px 0 7px, + #4ae 14px -14px 0 7px; + } + + 66.67% { + box-shadow: #f86 -14px -14px 0 7px, + #fc6 -14px -14px 0 7px, + #6d7 -14px -14px 0 7px, + #4ae 14px -14px 0 7px; + } + + 75% { + box-shadow: #f86 14px -14px 0 7px, + #fc6 14px -14px 0 7px, + #6d7 14px -14px 0 7px, + #4ae 14px -14px 0 7px; + } + + 83.33% { + box-shadow: #f86 14px 14px 0 7px, + #fc6 14px -14px 0 7px, + #6d7 14px 14px 0 7px, + #4ae 14px 14px 0 7px; + } + + 91.67% { + box-shadow: #f86 -14px 14px 0 7px, + #fc6 14px -14px 0 7px, + #6d7 14px 14px 0 7px, + #4ae -14px 14px 0 7px; + } + + 100% { + box-shadow: #f86 -14px -14px 0 7px, + #fc6 14px -14px 0 7px, + #6d7 14px 14px 0 7px, + #4ae -14px 14px 0 7px; + } +} diff --git a/src/styles/spinner/gauge.css b/src/styles/spinner/gauge.css new file mode 100644 index 000000000..1b82a280d --- /dev/null +++ b/src/styles/spinner/gauge.css @@ -0,0 +1,104 @@ +.gauge-loader:not(:required) { + position: relative; + display: inline-block; + width: 64px; + height: 32px; + margin-bottom: 10px; + overflow: hidden; + text-indent: -9999px; + background: #6ca; + border-top-left-radius: 32px; + border-top-right-radius: 32px; +} + +.gauge-loader:not(:required)::before { + position: absolute; + top: 5px; + left: 30px; + width: 4px; + height: 27px; + content: ""; + background: white; + border-radius: 2px; + transform-origin: 50% 100%; + animation: gauge-loader 4000ms infinite ease; +} + +.gauge-loader:not(:required)::after { + position: absolute; + top: 26px; + left: 26px; + width: 13px; + height: 13px; + content: ""; + background: white; + -moz-border-radius: 8px; + -webkit-border-radius: 8px; + border-radius: 8px; +} + +@keyframes gauge-loader { + 0% { + transform: rotate(-50deg); + } + + 10% { + transform: rotate(20deg); + } + + 20% { + transform: rotate(60deg); + } + + 24% { + transform: rotate(60deg); + } + + 40% { + transform: rotate(-20deg); + } + + 54% { + transform: rotate(70deg); + } + + 56% { + transform: rotate(78deg); + } + + 58% { + transform: rotate(73deg); + } + + 60% { + transform: rotate(75deg); + } + + 62% { + transform: rotate(70deg); + } + + 70% { + transform: rotate(-20deg); + } + + 80% { + transform: rotate(20deg); + } + + 83% { + transform: rotate(25deg); + } + + 86% { + transform: rotate(20deg); + } + + 89% { + transform: rotate(25deg); + } + + 100% { + transform: rotate(-50deg); + } +} diff --git a/src/styles/spinner/inner-circles.css b/src/styles/spinner/inner-circles.css new file mode 100644 index 000000000..0144da20c --- /dev/null +++ b/src/styles/spinner/inner-circles.css @@ -0,0 +1,51 @@ +.inner-circles-loader:not(:required) { + position: relative; + display: inline-block; + width: 50px; + height: 50px; + margin-bottom: 10px; + overflow: hidden; + text-indent: -9999px; + background: rgba(25, 165, 152, 0.5); + border-radius: 50%; + transform: translate3d(0, 0, 0); +} + +.inner-circles-loader:not(:required)::before, +.inner-circles-loader:not(:required)::after { + position: absolute; + top: 0; + display: inline-block; + width: 50px; + height: 50px; + content: ""; + border-radius: 50%; +} + +.inner-circles-loader:not(:required)::before { + left: 0; + background: #c7efcf; + transform-origin: 0 50%; + animation: inner-circles-loader 3s infinite; +} + +.inner-circles-loader:not(:required)::after { + right: 0; + background: #eef5db; + transform-origin: 100% 50%; + animation: inner-circles-loader 3s 0.2s reverse infinite; +} + +@keyframes inner-circles-loader { + 0% { + transform: rotate(0deg); + } + + 50% { + transform: rotate(360deg); + } + + 100% { + transform: rotate(0deg); + } +} diff --git a/src/styles/spinner/plus.css b/src/styles/spinner/plus.css new file mode 100644 index 000000000..af4516f35 --- /dev/null +++ b/src/styles/spinner/plus.css @@ -0,0 +1,341 @@ +.plus-loader:not(:required) { + position: relative; + display: inline-block; + width: 48px; + height: 48px; + margin-bottom: 10px; + overflow: hidden; + text-indent: -9999px; + background: #f86; + -moz-border-radius: 24px; + -webkit-border-radius: 24px; + border-radius: 24px; + -moz-transform: rotateZ(90deg); + -ms-transform: rotateZ(90deg); + -webkit-transform: rotateZ(90deg); + transform: rotateZ(90deg); + -moz-transform-origin: 50% 50%; + -ms-transform-origin: 50% 50%; + -webkit-transform-origin: 50% 50%; + transform-origin: 50% 50%; + -moz-animation: plus-loader-background 3s infinite ease-in-out; + -webkit-animation: plus-loader-background 3s infinite ease-in-out; + animation: plus-loader-background 3s infinite ease-in-out; +} + +.plus-loader:not(:required)::after { + position: absolute; + top: 0; + right: 50%; + width: 50%; + height: 100%; + content: ""; + background: #f86; + -moz-border-radius: 24px 0 0 24px; + -webkit-border-radius: 24px; + border-radius: 24px 0 0 24px; + -moz-transform-origin: 100% 50%; + -ms-transform-origin: 100% 50%; + -webkit-transform-origin: 100% 50%; + transform-origin: 100% 50%; + -moz-animation: plus-loader-top 3s infinite linear; + -webkit-animation: plus-loader-top 3s infinite linear; + animation: plus-loader-top 3s infinite linear; +} + +.plus-loader:not(:required)::before { + position: absolute; + top: 0; + right: 50%; + width: 50%; + height: 100%; + content: ""; + background: #fc6; + -moz-border-radius: 24px 0 0 24px; + -webkit-border-radius: 24px; + border-radius: 24px 0 0 24px; + -moz-transform-origin: 100% 50%; + -ms-transform-origin: 100% 50%; + -webkit-transform-origin: 100% 50%; + transform-origin: 100% 50%; + -moz-animation: plus-loader-bottom 3s infinite linear; + -webkit-animation: plus-loader-bottom 3s infinite linear; + animation: plus-loader-bottom 3s infinite linear; +} + +@keyframes plus-loader-top { + 2.5% { + background: #f86; + -moz-transform: rotateY(0deg); + -ms-transform: rotateY(0deg); + -webkit-transform: rotateY(0deg); + transform: rotateY(0deg); + -moz-animation-timing-function: ease-in; + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + } + + 13.75% { + background: #ff430d; + -moz-transform: rotateY(90deg); + -ms-transform: rotateY(90deg); + -webkit-transform: rotateY(90deg); + transform: rotateY(90deg); + -moz-animation-timing-function: step-start; + -webkit-animation-timing-function: step-start; + animation-timing-function: step-start; + } + + 13.76% { + background: #ffae0d; + -moz-transform: rotateY(90deg); + -ms-transform: rotateY(90deg); + -webkit-transform: rotateY(90deg); + transform: rotateY(90deg); + -moz-animation-timing-function: ease-out; + -webkit-animation-timing-function: ease-out; + animation-timing-function: ease-out; + } + + 25% { + background: #fc6; + -moz-transform: rotateY(180deg); + -ms-transform: rotateY(180deg); + -webkit-transform: rotateY(180deg); + transform: rotateY(180deg); + } + + 27.5% { + background: #fc6; + -moz-transform: rotateY(180deg); + -ms-transform: rotateY(180deg); + -webkit-transform: rotateY(180deg); + transform: rotateY(180deg); + -moz-animation-timing-function: ease-in; + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + } + + 41.25% { + background: #ffae0d; + -moz-transform: rotateY(90deg); + -ms-transform: rotateY(90deg); + -webkit-transform: rotateY(90deg); + transform: rotateY(90deg); + -moz-animation-timing-function: step-start; + -webkit-animation-timing-function: step-start; + animation-timing-function: step-start; + } + + 41.26% { + background: #2cc642; + -moz-transform: rotateY(90deg); + -ms-transform: rotateY(90deg); + -webkit-transform: rotateY(90deg); + transform: rotateY(90deg); + -moz-animation-timing-function: ease-out; + -webkit-animation-timing-function: ease-out; + animation-timing-function: ease-out; + } + + 50% { + background: #6d7; + -moz-transform: rotateY(0deg); + -ms-transform: rotateY(0deg); + -webkit-transform: rotateY(0deg); + transform: rotateY(0deg); + } + + 52.5% { + background: #6d7; + -moz-transform: rotateY(0deg); + -ms-transform: rotateY(0deg); + -webkit-transform: rotateY(0deg); + transform: rotateY(0deg); + -moz-animation-timing-function: ease-in; + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + } + + 63.75% { + background: #2cc642; + -moz-transform: rotateY(90deg); + -ms-transform: rotateY(90deg); + -webkit-transform: rotateY(90deg); + transform: rotateY(90deg); + -moz-animation-timing-function: step-start; + -webkit-animation-timing-function: step-start; + animation-timing-function: step-start; + } + + 63.76% { + background: #1386d2; + -moz-transform: rotateY(90deg); + -ms-transform: rotateY(90deg); + -webkit-transform: rotateY(90deg); + transform: rotateY(90deg); + -moz-animation-timing-function: ease-out; + -webkit-animation-timing-function: ease-out; + animation-timing-function: ease-out; + } + + 75% { + background: #4ae; + -moz-transform: rotateY(180deg); + -ms-transform: rotateY(180deg); + -webkit-transform: rotateY(180deg); + transform: rotateY(180deg); + } + + 77.5% { + background: #4ae; + -moz-transform: rotateY(180deg); + -ms-transform: rotateY(180deg); + -webkit-transform: rotateY(180deg); + transform: rotateY(180deg); + -moz-animation-timing-function: ease-in; + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + } + + 91.25% { + background: #1386d2; + -moz-transform: rotateY(90deg); + -ms-transform: rotateY(90deg); + -webkit-transform: rotateY(90deg); + transform: rotateY(90deg); + -moz-animation-timing-function: step-start; + -webkit-animation-timing-function: step-start; + animation-timing-function: step-start; + } + + 91.26% { + background: #ff430d; + -moz-transform: rotateY(90deg); + -ms-transform: rotateY(90deg); + -webkit-transform: rotateY(90deg); + transform: rotateY(90deg); + -moz-animation-timing-function: ease-in; + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + } + + 100% { + background: #f86; + -moz-transform: rotateY(0deg); + -ms-transform: rotateY(0deg); + -webkit-transform: rotateY(0deg); + transform: rotateY(0deg); + -moz-animation-timing-function: step-start; + -webkit-animation-timing-function: step-start; + animation-timing-function: step-start; + } +} + +@keyframes plus-loader-bottom { + 0% { + background: #fc6; + -moz-animation-timing-function: step-start; + -webkit-animation-timing-function: step-start; + animation-timing-function: step-start; + } + + 50% { + background: #fc6; + -moz-animation-timing-function: step-start; + -webkit-animation-timing-function: step-start; + animation-timing-function: step-start; + } + + 75% { + background: #4ae; + -moz-animation-timing-function: step-start; + -webkit-animation-timing-function: step-start; + animation-timing-function: step-start; + } + + 100% { + background: #4ae; + -moz-animation-timing-function: step-start; + -webkit-animation-timing-function: step-start; + animation-timing-function: step-start; + } +} + +@keyframes plus-loader-background { + 0% { + background: #f86; + -moz-transform: rotateZ(180deg); + -ms-transform: rotateZ(180deg); + -webkit-transform: rotateZ(180deg); + transform: rotateZ(180deg); + } + + 25% { + background: #f86; + -moz-transform: rotateZ(180deg); + -ms-transform: rotateZ(180deg); + -webkit-transform: rotateZ(180deg); + transform: rotateZ(180deg); + -moz-animation-timing-function: step-start; + -webkit-animation-timing-function: step-start; + animation-timing-function: step-start; + } + + 27.5% { + background: #6d7; + -moz-transform: rotateZ(90deg); + -ms-transform: rotateZ(90deg); + -webkit-transform: rotateZ(90deg); + transform: rotateZ(90deg); + } + + 50% { + background: #6d7; + -moz-transform: rotateZ(90deg); + -ms-transform: rotateZ(90deg); + -webkit-transform: rotateZ(90deg); + transform: rotateZ(90deg); + -moz-animation-timing-function: step-start; + -webkit-animation-timing-function: step-start; + animation-timing-function: step-start; + } + + 52.5% { + background: #6d7; + -moz-transform: rotateZ(0deg); + -ms-transform: rotateZ(0deg); + -webkit-transform: rotateZ(0deg); + transform: rotateZ(0deg); + } + + 75% { + background: #6d7; + -moz-transform: rotateZ(0deg); + -ms-transform: rotateZ(0deg); + -webkit-transform: rotateZ(0deg); + transform: rotateZ(0deg); + -moz-animation-timing-function: step-start; + -webkit-animation-timing-function: step-start; + animation-timing-function: step-start; + } + + 77.5% { + background: #f86; + -moz-transform: rotateZ(270deg); + -ms-transform: rotateZ(270deg); + -webkit-transform: rotateZ(270deg); + transform: rotateZ(270deg); + } + + 100% { + background: #f86; + -moz-transform: rotateZ(270deg); + -ms-transform: rotateZ(270deg); + -webkit-transform: rotateZ(270deg); + transform: rotateZ(270deg); + -moz-animation-timing-function: step-start; + -webkit-animation-timing-function: step-start; + animation-timing-function: step-start; + } +} diff --git a/src/styles/themes/default.scss b/src/styles/themes/default.scss new file mode 100644 index 000000000..7061af3cc --- /dev/null +++ b/src/styles/themes/default.scss @@ -0,0 +1 @@ +/* 绿荫草场主题、荣耀典藏主题、暗黑之子主题加QQ讨论群972435319、1139183756后私聊群主获取,获取后将主题放到themes文件夹根目录即可 */ diff --git a/src/styles/transition.scss b/src/styles/transition.scss new file mode 100644 index 000000000..1ab389655 --- /dev/null +++ b/src/styles/transition.scss @@ -0,0 +1,19 @@ +/** + + * @description vue过渡动画 + */ + +@charset "utf-8"; + +.fade-transform-leave-active, +.fade-transform-enter-active { + transition: $base-transition; +} + +.fade-transform-enter { + opacity: 0; +} + +.fade-transform-leave-to { + opacity: 0; +} diff --git a/src/styles/vab.scss b/src/styles/vab.scss new file mode 100644 index 000000000..743afb148 --- /dev/null +++ b/src/styles/vab.scss @@ -0,0 +1,295 @@ +/** + + * @description 全局样式 + */ + +@charset "utf-8"; + +@import './normalize.scss'; +@import './transition.scss'; +@import './loading.scss'; +$base: '.vab'; + +@mixin scrollbar { + max-height: 88vh; + margin-bottom: 0.5vh; + overflow-y: auto; + + &::-webkit-scrollbar { + width: 0; + height: 0; + background: transparent; + } + + &::-webkit-scrollbar-thumb { + background-color: rgba(144, 147, 153, 0.3); + border-radius: 10px; + } + + &::-webkit-scrollbar-thumb:hover { + background-color: rgba(144, 147, 153, 0.3); + } +} + +@mixin base-scrollbar { + &::-webkit-scrollbar { + width: 13px; + height: 13px; + } + + &::-webkit-scrollbar-thumb { + background-color: rgba(0, 0, 0, 0.4); + background-clip: padding-box; + border: 3px solid transparent; + border-radius: 7px; + } + + &::-webkit-scrollbar-thumb:hover { + background-color: rgba(0, 0, 0, 0.5); + } + + &::-webkit-scrollbar-track { + background-color: transparent; + } + + &::-webkit-scrollbar-track:hover { + background-color: #f8fafc; + } +} + +img { + object-fit: cover; +} + +a { + color: $base-color-blue; + text-decoration: none; + cursor: pointer; +} + +* { + transition: $base-transition; +} +svg { + transition: none; + * { + transition: none; + } +} + +html { + body { + position: relative; + height: 100vh; + padding: 0; + margin: 0; + font-family: Avenir, Helvetica, Arial, sans-serif; + font-size: $base-font-size-default; + color: #2c3e50; + background: #f6f8f9; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + + @include base-scrollbar; + + div { + @include base-scrollbar; + } + + svg, + i { + &:hover { + opacity: 0.8; + } + } + + .v-modal { + backdrop-filter: blur(10px); + } + + /* el-tag开始 */ + .el-tag + .el-tag { + margin-left: 10px; + } + + /* el-tag结束 */ + + /* markdown编辑器开始 */ + .editor-toolbar { + .no-mobile, + .fa-question-circle { + display: none; + } + } + + /* markdown编辑器结束 */ + + /* 间隔线开始 */ + .el-divider--horizontal { + margin: 10px 0 25px 0; + + .el-divider__text { + display: -webkit-box; + overflow: hidden; + text-overflow: ellipsis; + -webkit-line-clamp: 1; + -webkit-box-orient: vertical; + } + } + + /* 间隔线结束 */ + + /* 大图展示开始 */ + .el-image-viewer { + &__close { + .el-icon-circle-close { + color: $base-color-white; + } + } + } + + /* 大图展示结束 */ + + .vue-admin-beautiful-wrapper { + .app-main-container { + @include base-scrollbar; + + > [class*='-container'] { + * { + transition: none; + } + padding: $base-padding; + background: $base-color-white; + } + } + } + + /* 进度条开始 */ + #nprogress { + position: fixed; + z-index: $base-z-index; + + .bar { + background: $base-color-blue !important; + } + + .peg { + box-shadow: 0 0 10px $base-color-blue, 0 0 5px $base-color-blue !important; + } + } + + /* 进度条结束 */ + + /* 表格开始 */ + + .el-table { + .el-table__body-wrapper { + @include base-scrollbar; + } + + th { + background: #f5f7fa; + } + + td, + th { + position: relative; + box-sizing: border-box; + padding: 7.5px 0; + + .cell { + font-size: $base-font-size-default; + font-weight: normal; + color: #606266; + + .el-image { + width: 50px; + height: 50px; + border-radius: $base-border-radius; + } + } + } + } + + /* 表格结束 */ + + /* 分页开始 */ + .el-pagination { + padding: 2px 5px; + margin: 15px 0 0 0; + font-weight: normal; + color: $base-color-black; + text-align: center; + } + + /* 分页结束 */ + + /* 菜单开始 */ + .el-menu.el-menu--popup.el-menu--popup-right-start { + @include scrollbar; + } + + .el-menu.el-menu--popup.el-menu--popup-bottom-start { + @include scrollbar; + } + + .el-submenu__title i { + color: $base-color-white; + } + + /* 菜单结束 */ + + /* 弹窗开始 */ + + .el-dialog, + .el-message-box { + &__body { + border-top: 1px solid $base-border-color; + + .el-form { + padding-right: 30px; + } + } + + &__footer { + padding: $base-padding; + text-align: right; + border-top: 1px solid $base-border-color; + } + + &__content { + padding: 20px 20px 20px 20px; + } + } + + /* 弹窗结束 */ + + /* 卡片开始 */ + .el-card { + margin-bottom: 15px; + + &__body { + padding: $base-padding; + } + } + + /* 卡片结束 */ + + /* 下拉树样式-----------开始 */ + .select-tree-popper { + .el-scrollbar { + .el-scrollbar__view { + .el-select-dropdown__item { + height: auto; + max-height: 274px; + padding: 0; + overflow-y: auto; + line-height: 26px; + } + } + } + } + + /* 下拉树样式-----------结束 */ + } +} diff --git a/src/styles/variables.scss b/src/styles/variables.scss new file mode 100644 index 000000000..56b9ab10f --- /dev/null +++ b/src/styles/variables.scss @@ -0,0 +1,83 @@ +/** + + * @description 全局主题变量配置 + */ +/* stylelint-disable */ +@charset "utf-8"; +//框架默认主题色 +$base-color-default: #41b584; +//默认层级 +$base-z-index: 999; +//横向布局纵向布局时菜单背景色 +$base-menu-background: #2f3447; +//菜单文字颜色 +$base-menu-color: hsla(0, 0%, 100%, 0.95); +//菜单选中文字颜色 +$base-menu-color-active: hsla(0, 0%, 100%, 0.95); +//菜单选中背景色 +$base-menu-background-active: $base-color-default; +//标题颜色 +$base-title-color: #fff; +//字体大小配置 +$base-font-size-small: 12px; +$base-font-size-default: 14px; +$base-font-size-big: 16px; +$base-font-size-bigger: 18px; +$base-font-size-max: 22px; +$base-font-color: #606266; +$base-color-blue: $base-color-default; +$base-color-green: #47ba80; +$base-color-white: #fff; +$base-color-black: #000; +$base-color-yellow: #fac858; +$base-color-orange: #ff6700; +$base-color-red: #f34d37; +$base-color-gray: rgba(0, 0, 0, 0.65); +$base-main-width: 1279px; +$base-border-radius: 2px; +$base-border-color: #dcdfe6; +//输入框高度 +$base-input-height: 32px; +//默认paddiing +$base-padding: 20px; +//默认阴影 +$base-box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08); +//横向布局时top-bar、logo、一级菜单的高度 +$base-top-bar-height: 65px; +//纵向布局时logo的高度 +$base-logo-height: 75px; +//顶部nav-bar的高度 +$base-nav-bar-height: 60px; +//顶部多标签页tabs-bar的高度 +$base-tabs-bar-height: 55px; +//顶部多标签页tabs-bar中每一个item的高度 +$base-tag-item-height: 34px; +//菜单li标签的高度 +$base-menu-item-height: 50px; +//app-main的高度 +$base-app-main-height: calc( + 100vh - #{$base-nav-bar-height} - #{$base-tabs-bar-height} - #{$base-padding} - + #{$base-padding} - 55px - 55px +); +//纵向布局时左侧导航未折叠时的宽度 +$base-left-menu-width: 256px; +//纵向布局时左侧导航未折叠时右侧内容的宽度 +$base-right-content-width: calc(100% - #{$base-left-menu-width}); +//纵向布局时左侧导航已折叠时的宽度 +$base-left-menu-width-min: 65px; +//纵向布局时左侧导航已折叠时右侧内容的宽度 +$base-right-content-width-min: calc(100% - #{$base-left-menu-width-min}); +//默认动画 +$base-transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1), border 0s, + background 0s, color 0s, font-size 0s; +//默认动画长 +$base-transition-time: 0.3s; + +:export { + //菜单文字颜色变量导出 + menu-color: $base-menu-color; + //菜单选中文字颜色变量导出 + menu-color-active: $base-menu-color-active; + //菜单背景色变量导出 + menu-background: $base-menu-background; +} diff --git a/src/utils/accessToken.js b/src/utils/accessToken.js new file mode 100644 index 000000000..c7fd2b3e6 --- /dev/null +++ b/src/utils/accessToken.js @@ -0,0 +1,59 @@ +import { storage, tokenTableName } from '@/config' + +/** + + * @description 获取accessToken + * @returns {string|ActiveX.IXMLDOMNode|Promise|any|IDBRequest|MediaKeyStatus|FormDataEntryValue|Function|Promise} + */ +export function getAccessToken() { + if (storage) { + if ('localStorage' === storage) { + return localStorage.getItem(tokenTableName) + } else if ('sessionStorage' === storage) { + return sessionStorage.getItem(tokenTableName) + } else { + return localStorage.getItem(tokenTableName) + } + } else { + return localStorage.getItem(tokenTableName) + } +} + +/** + + * @description 存储accessToken + * @param accessToken + * @returns {void|*} + */ +export function setAccessToken(accessToken) { + if (storage) { + if ('localStorage' === storage) { + return localStorage.setItem(tokenTableName, accessToken) + } else if ('sessionStorage' === storage) { + return sessionStorage.setItem(tokenTableName, accessToken) + } else { + return localStorage.setItem(tokenTableName, accessToken) + } + } else { + return localStorage.setItem(tokenTableName, accessToken) + } +} + +/** + + * @description 移除accessToken + * @returns {void|Promise} + */ +export function removeAccessToken() { + if (storage) { + if ('localStorage' === storage) { + return localStorage.removeItem(tokenTableName) + } else if ('sessionStorage' === storage) { + return sessionStorage.clear() + } else { + return localStorage.removeItem(tokenTableName) + } + } else { + return localStorage.removeItem(tokenTableName) + } +} diff --git a/src/utils/clipboard.js b/src/utils/clipboard.js new file mode 100644 index 000000000..a853d9969 --- /dev/null +++ b/src/utils/clipboard.js @@ -0,0 +1,31 @@ +import Vue from 'vue' +import Clipboard from 'clipboard' + +function clipboardSuccess() { + Vue.prototype.$baseMessage('复制成功', 'success') +} + +function clipboardError() { + Vue.prototype.$baseMessage('复制失败', 'error') +} + +/** + + * @description 复制数据 + * @param text + * @param event + */ +export default function handleClipboard(text, event) { + const clipboard = new Clipboard(event.target, { + text: () => text, + }) + clipboard.on('success', () => { + clipboardSuccess() + clipboard.destroy() + }) + clipboard.on('error', () => { + clipboardError() + clipboard.destroy() + }) + clipboard.onClick(event) +} diff --git a/src/utils/encrypt.js b/src/utils/encrypt.js new file mode 100644 index 000000000..de651b90e --- /dev/null +++ b/src/utils/encrypt.js @@ -0,0 +1,46 @@ +import JSEncrypt from 'jsencrypt' +import { getPublicKey } from '@/api/publicKey' + +const privateKey = + 'MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMFPa+v52FkSUXvcUnrGI/XzW3EpZRI0s9BCWJ3oNQmEYA5luWW5p8h0uadTIoTyYweFPdH4hveyxlwmS7oefvbIdiP+o+QIYW/R4Wjsb4Yl8MhR4PJqUE3RCy6IT9fM8ckG4kN9ECs6Ja8fQFc6/mSl5dJczzJO3k1rWMBhKJD/AgMBAAECgYEAucMakH9dWeryhrYoRHcXo4giPVJsH9ypVt4KzmOQY/7jV7KFQK3x//27UoHfUCak51sxFw9ek7UmTPM4HjikA9LkYeE7S381b4QRvFuf3L6IbMP3ywJnJ8pPr2l5SqQ00W+oKv+w/VmEsyUHr+k4Z+4ik+FheTkVWp566WbqFsECQQDjYaMcaKw3j2Zecl8T6eUe7fdaRMIzp/gcpPMfT/9rDzIQk+7ORvm1NI9AUmFv/FAlfpuAMrdL2n7p9uznWb7RAkEA2aP934kbXg5bdV0R313MrL+7WTK/qdcYxATUbMsMuWWQBoS5irrt80WCZbG48hpocJavLNjbtrjmUX3CuJBmzwJAOJg8uP10n/+ZQzjEYXh+BszEHDuw+pp8LuT/fnOy5zrJA0dO0RjpXijO3vuiNPVgHXT9z1LQPJkNrb5ACPVVgQJBALPeb4uV0bNrJDUb5RB4ghZnIxv18CcaqNIft7vuGCcFBAIPIRTBprR+RuVq+xHDt3sNXdsvom4h49+Hky1b0ksCQBBwUtVaqH6ztCtwUF1j2c/Zcrt5P/uN7IHAd44K0gIJc1+Csr3qPG+G2yoqRM8KVqLI8Z2ZYn9c+AvEE+L9OQY=' + +/** + + * @description RSA加密 + * @param data + * @returns {Promise<{param: PromiseLike}|*>} + */ +export async function encryptedData(data) { + let publicKey = '' + const res = await getPublicKey() + publicKey = res.data.publicKey + if (res.data.mockServer) { + publicKey = '' + } + if (publicKey == '') { + return data + } + const encrypt = new JSEncrypt() + encrypt.setPublicKey( + `-----BEGIN PUBLIC KEY-----${publicKey}-----END PUBLIC KEY-----` + ) + data = encrypt.encrypt(JSON.stringify(data)) + return { + param: data, + } +} + +/** + + * @description RSA解密 + * @param data + * @returns {PromiseLike} + */ +export function decryptedData(data) { + const decrypt = new JSEncrypt() + decrypt.setPrivateKey( + `-----BEGIN RSA PRIVATE KEY-----${privateKey}-----END RSA PRIVATE KEY-----` + ) + data = decrypt.decrypt(JSON.stringify(data)) + return data +} diff --git a/src/utils/errorLog.js b/src/utils/errorLog.js new file mode 100644 index 000000000..07a836c31 --- /dev/null +++ b/src/utils/errorLog.js @@ -0,0 +1,25 @@ +import Vue from 'vue' +import store from '@/store' +import { isArray, isString } from '@/utils/validate' +import { errorLog } from '@/config' + +const needErrorLog = errorLog +const checkNeed = () => { + const env = process.env.NODE_ENV + if (isString(needErrorLog)) { + return env === needErrorLog + } + if (isArray(needErrorLog)) { + return needErrorLog.includes(env) + } + return false +} +if (checkNeed()) { + Vue.config.errorHandler = (err, vm, info) => { + console.error('vue-admin-beautiful错误拦截:', err, vm, info) + const url = window.location.href + Vue.nextTick(() => { + store.dispatch('errorLog/addErrorLog', { err, vm, info, url }) + }) + } +} diff --git a/src/utils/handleRoutes.js b/src/utils/handleRoutes.js new file mode 100644 index 000000000..7058f2ef5 --- /dev/null +++ b/src/utils/handleRoutes.js @@ -0,0 +1,63 @@ +/** + + * @description all模式渲染后端返回路由 + * @param constantRoutes + * @returns {*} + */ +export function convertRouter(asyncRoutes) { + return asyncRoutes.map((route) => { + if (route.component) { + if (route.component === 'Layout') { + route.component = (resolve) => require(['@/layouts'], resolve) + } else if (route.component === 'EmptyLayout') { + route.component = (resolve) => + require(['@/layouts/EmptyLayout'], resolve) + } else { + const index = route.component.indexOf('views') + const path = + index > 0 ? route.component.slice(index) : `views/${route.component}` + route.component = (resolve) => require([`@/${path}`], resolve) + } + } + if (route.children && route.children.length) + route.children = convertRouter(route.children) + if (route.children && route.children.length === 0) delete route.children + return route + }) +} + +/** + + * @description 判断当前路由是否包含权限 + * @param permissions + * @param route + * @returns {boolean|*} + */ +function hasPermission(permissions, route) { + if (route.meta && route.meta.permissions) { + return permissions.some((role) => route.meta.permissions.includes(role)) + } else { + return true + } +} + +/** + + * @description intelligence模式根据permissions数组拦截路由 + * @param routes + * @param permissions + * @returns {[]} + */ +export function filterAsyncRoutes(routes, permissions) { + const finallyRoutes = [] + routes.forEach((route) => { + const item = { ...route } + if (hasPermission(permissions, item)) { + if (item.children) { + item.children = filterAsyncRoutes(item.children, permissions) + } + finallyRoutes.push(item) + } + }) + return finallyRoutes +} diff --git a/src/utils/index.js b/src/utils/index.js new file mode 100644 index 000000000..e9afbd571 --- /dev/null +++ b/src/utils/index.js @@ -0,0 +1,266 @@ +/** + + * @description 格式化时间 + * @param time + * @param cFormat + * @returns {string|null} + */ +export function parseTime(time, cFormat) { + if (arguments.length === 0) { + return null + } + const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}' + let date + if (typeof time === 'object') { + date = time + } else { + if (typeof time === 'string' && /^[0-9]+$/.test(time)) { + time = parseInt(time) + } + if (typeof time === 'number' && time.toString().length === 10) { + time = time * 1000 + } + date = new Date(time) + } + const formatObj = { + y: date.getFullYear(), + m: date.getMonth() + 1, + d: date.getDate(), + h: date.getHours(), + i: date.getMinutes(), + s: date.getSeconds(), + a: date.getDay(), + } + const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => { + let value = formatObj[key] + if (key === 'a') { + return ['日', '一', '二', '三', '四', '五', '六'][value] + } + if (result.length > 0 && value < 10) { + value = '0' + value + } + return value || 0 + }) + return time_str +} + +/** + + * @description 格式化时间 + * @param time + * @param option + * @returns {string} + */ +export function formatTime(time, option) { + if (('' + time).length === 10) { + time = parseInt(time) * 1000 + } else { + time = +time + } + const d = new Date(time) + const now = Date.now() + + const diff = (now - d) / 1000 + + if (diff < 30) { + return '刚刚' + } else if (diff < 3600) { + // less 1 hour + return Math.ceil(diff / 60) + '分钟前' + } else if (diff < 3600 * 24) { + return Math.ceil(diff / 3600) + '小时前' + } else if (diff < 3600 * 24 * 2) { + return '1天前' + } + if (option) { + return parseTime(time, option) + } else { + return ( + d.getMonth() + + 1 + + '月' + + d.getDate() + + '日' + + d.getHours() + + '时' + + d.getMinutes() + + '分' + ) + } +} + +/** + + * @description 将url请求参数转为json格式 + * @param url + * @returns {{}|any} + */ +export function paramObj(url) { + const search = url.split('?')[1] + if (!search) { + return {} + } + return JSON.parse( + '{"' + + decodeURIComponent(search) + .replace(/"/g, '\\"') + .replace(/&/g, '","') + .replace(/=/g, '":"') + .replace(/\+/g, ' ') + + '"}' + ) +} + +/** + + * @description 父子关系的数组转换成树形结构数据 + * @param data + * @returns {*} + */ +export function translateDataToTree(data) { + const parent = data.filter( + (value) => value.parentId === 'undefined' || value.parentId == null + ) + const children = data.filter( + (value) => value.parentId !== 'undefined' && value.parentId != null + ) + const translator = (parent, children) => { + parent.forEach((parent) => { + children.forEach((current, index) => { + if (current.parentId === parent.id) { + const temp = JSON.parse(JSON.stringify(children)) + temp.splice(index, 1) + translator([current], temp) + typeof parent.children !== 'undefined' + ? parent.children.push(current) + : (parent.children = [current]) + } + }) + }) + } + translator(parent, children) + return parent +} + +/** + + * @description 树形结构数据转换成父子关系的数组 + * @param data + * @returns {[]} + */ +export function translateTreeToData(data) { + const result = [] + data.forEach((item) => { + const loop = (data) => { + result.push({ + id: data.id, + name: data.name, + parentId: data.parentId, + }) + const child = data.children + if (child) { + for (let i = 0; i < child.length; i++) { + loop(child[i]) + } + } + } + loop(item) + }) + return result +} + +/** + + * @description 10位时间戳转换 + * @param time + * @returns {string} + */ +export function tenBitTimestamp(time) { + const date = new Date(time * 1000) + const y = date.getFullYear() + let m = date.getMonth() + 1 + m = m < 10 ? '' + m : m + let d = date.getDate() + d = d < 10 ? '' + d : d + let h = date.getHours() + h = h < 10 ? '0' + h : h + let minute = date.getMinutes() + let second = date.getSeconds() + minute = minute < 10 ? '0' + minute : minute + second = second < 10 ? '0' + second : second + return y + '年' + m + '月' + d + '日 ' + h + ':' + minute + ':' + second //组合 +} + +/** + + * @description 13位时间戳转换 + * @param time + * @returns {string} + */ +export function thirteenBitTimestamp(time) { + const date = new Date(time / 1) + const y = date.getFullYear() + let m = date.getMonth() + 1 + m = m < 10 ? '' + m : m + let d = date.getDate() + d = d < 10 ? '' + d : d + let h = date.getHours() + h = h < 10 ? '0' + h : h + let minute = date.getMinutes() + let second = date.getSeconds() + minute = minute < 10 ? '0' + minute : minute + second = second < 10 ? '0' + second : second + return y + '年' + m + '月' + d + '日 ' + h + ':' + minute + ':' + second //组合 +} + +/** + + * @description 获取随机id + * @param length + * @returns {string} + */ +export function uuid(length = 32) { + const num = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890' + let str = '' + for (let i = 0; i < length; i++) { + str += num.charAt(Math.floor(Math.random() * num.length)) + } + return str +} + +/** + + * @description m到n的随机数 + * @param m + * @param n + * @returns {number} + */ +export function random(m, n) { + return Math.floor(Math.random() * (m - n) + n) +} + +/** + + * @description addEventListener + * @type {function(...[*]=)} + */ +export const on = (function () { + return function (element, event, handler, useCapture = false) { + if (element && event && handler) { + element.addEventListener(event, handler, useCapture) + } + } +})() + +/** + + * @description removeEventListener + * @type {function(...[*]=)} + */ +export const off = (function () { + return function (element, event, handler, useCapture = false) { + if (element && event) { + element.removeEventListener(event, handler, useCapture) + } + } +})() diff --git a/src/utils/pageTitle.js b/src/utils/pageTitle.js new file mode 100644 index 000000000..e09567da0 --- /dev/null +++ b/src/utils/pageTitle.js @@ -0,0 +1,14 @@ +import { title } from '@/config' + +/** + + * @description 设置标题 + * @param pageTitle + * @returns {string} + */ +export default function getPageTitle(pageTitle) { + if (pageTitle) { + return `${pageTitle}-${title}` + } + return `${title}` +} diff --git a/src/utils/permission.js b/src/utils/permission.js new file mode 100644 index 000000000..ed33463cc --- /dev/null +++ b/src/utils/permission.js @@ -0,0 +1,20 @@ +import store from '@/store' + +/** + + * @description 检查权限 + * @param value + * @returns {boolean} + */ +export default function checkPermission(value) { + if (value && value instanceof Array && value.length > 0) { + const permissions = store.getters['user/permissions'] + const permissionPermissions = value + + return permissions.some((role) => { + return permissionPermissions.includes(role) + }) + } else { + return false + } +} diff --git a/src/utils/request.js b/src/utils/request.js new file mode 100644 index 000000000..53a2cad7a --- /dev/null +++ b/src/utils/request.js @@ -0,0 +1,125 @@ +import Vue from 'vue' +import axios from 'axios' +import { + baseURL, + contentType, + debounce, + invalidCode, + noPermissionCode, + requestTimeout, + successCode, + tokenName, + loginInterception, +} from '@/config' +import store from '@/store' +import qs from 'qs' +import router from '@/router' +import { isArray } from '@/utils/validate' + +let loadingInstance + +/** + + * @description 处理code异常 + * @param {*} code + * @param {*} msg + */ +const handleCode = (code, msg) => { + switch (code) { + case invalidCode: + Vue.prototype.$baseMessage(msg || `后端接口${code}异常`, 'error') + store.dispatch('user/resetAccessToken').catch(() => {}) + if (loginInterception) { + location.reload() + } + break + case noPermissionCode: + router.push({ path: '/401' }).catch(() => {}) + break + default: + Vue.prototype.$baseMessage(msg || `后端接口${code}异常`, 'error') + break + } +} + +const instance = axios.create({ + baseURL, + timeout: requestTimeout, + headers: { + 'Content-Type': contentType, + }, +}) + +instance.interceptors.request.use( + (config) => { + if (store.getters['user/accessToken']) { + config.headers[tokenName] = store.getters['user/accessToken'] + } + //这里会过滤所有为空、0、false的key,如果不需要请自行注释 + if (config.data) + config.data = Vue.prototype.$baseLodash.pickBy( + config.data, + Vue.prototype.$baseLodash.identity + ) + if ( + config.data && + config.headers['Content-Type'] === + 'application/x-www-form-urlencoded;charset=UTF-8' + ) + config.data = qs.stringify(config.data) + if (debounce.some((item) => config.url.includes(item))) + loadingInstance = Vue.prototype.$baseLoading() + return config + }, + (error) => { + return Promise.reject(error) + } +) + +instance.interceptors.response.use( + (response) => { + if (loadingInstance) loadingInstance.close() + + const { data, config } = response + const { code, msg } = data + // 操作正常Code数组 + const codeVerificationArray = isArray(successCode) + ? [...successCode] + : [...[successCode]] + // 是否操作正常 + if (codeVerificationArray.includes(code)) { + return data + } else { + handleCode(code, msg) + return Promise.reject( + 'vue-admin-beautiful请求异常拦截:' + + JSON.stringify({ url: config.url, code, msg }) || 'Error' + ) + } + }, + (error) => { + if (loadingInstance) loadingInstance.close() + const { response, message } = error + if (error.response && error.response.data) { + const { status, data } = response + handleCode(status, data.msg || message) + return Promise.reject(error) + } else { + let { message } = error + if (message === 'Network Error') { + message = '后端接口连接异常' + } + if (message.includes('timeout')) { + message = '后端接口请求超时' + } + if (message.includes('Request failed with status code')) { + const code = message.substr(message.length - 3) + message = '后端接口' + code + '异常' + } + Vue.prototype.$baseMessage(message || `后端接口未知异常`, 'error') + return Promise.reject(error) + } + } +) + +export default instance diff --git a/src/utils/vab.js b/src/utils/vab.js new file mode 100644 index 000000000..e594e9ade --- /dev/null +++ b/src/utils/vab.js @@ -0,0 +1,180 @@ +import { loadingText, messageDuration, title } from '@/config' +import * as lodash from 'lodash' +import { Loading, Message, MessageBox, Notification } from 'element-ui' +import store from '@/store' +import { getAccessToken } from '@/utils/accessToken' + +const accessToken = store.getters['user/accessToken'] +const layout = store.getters['settings/layout'] + +const install = (Vue, opts = {}) => { + /* 全局accessToken */ + Vue.prototype.$baseAccessToken = () => { + return accessToken || getAccessToken() + } + /* 全局标题 */ + Vue.prototype.$baseTitle = (() => { + return title + })() + /* 全局加载层 */ + Vue.prototype.$baseLoading = (index, text) => { + let loading + if (!index) { + loading = Loading.service({ + lock: true, + text: text || loadingText, + background: 'hsla(0,0%,100%,.8)', + }) + } else { + loading = Loading.service({ + lock: true, + text: text || loadingText, + spinner: 'vab-loading-type' + index, + background: 'hsla(0,0%,100%,.8)', + }) + } + return loading + } + /* 全局多彩加载层 */ + Vue.prototype.$baseColorfullLoading = (index, text) => { + let loading + if (!index) { + loading = Loading.service({ + lock: true, + text: text || loadingText, + spinner: 'dots-loader', + background: 'hsla(0,0%,100%,.8)', + }) + } else { + switch (index) { + case 1: + index = 'dots' + break + case 2: + index = 'gauge' + break + case 3: + index = 'inner-circles' + break + case 4: + index = 'plus' + break + } + loading = Loading.service({ + lock: true, + text: text || loadingText, + spinner: index + '-loader', + background: 'hsla(0,0%,100%,.8)', + }) + } + return loading + } + /* 全局Message */ + Vue.prototype.$baseMessage = (message, type) => { + Message({ + offset: 60, + showClose: true, + message: message, + type: type, + dangerouslyUseHTMLString: true, + duration: messageDuration, + }) + } + + /* 全局Alert */ + Vue.prototype.$baseAlert = (content, title, callback) => { + MessageBox.alert(content, title || '温馨提示', { + confirmButtonText: '确定', + dangerouslyUseHTMLString: true, + callback: (action) => { + if (callback) { + callback() + } + }, + }) + } + + /* 全局Confirm */ + Vue.prototype.$baseConfirm = (content, title, callback1, callback2) => { + MessageBox.confirm(content, title || '温馨提示', { + confirmButtonText: '确定', + cancelButtonText: '取消', + closeOnClickModal: false, + type: 'warning', + }) + .then(() => { + if (callback1) { + callback1() + } + }) + .catch(() => { + if (callback2) { + callback2() + } + }) + } + + /* 全局Notification */ + Vue.prototype.$baseNotify = (message, title, type, position) => { + Notification({ + title: title, + message: message, + position: position || 'top-right', + type: type || 'success', + duration: messageDuration, + }) + } + + /* 全局TableHeight */ + Vue.prototype.$baseTableHeight = (formType) => { + let height = window.innerHeight + let paddingHeight = 400 + const formHeight = 50 + + if (layout === 'vertical') { + paddingHeight = 365 + } + + if ('number' == typeof formType) { + height = height - paddingHeight - formHeight * formType + } else { + height = height - paddingHeight + } + return height + } + + /* 全局map图层 */ + Vue.prototype.$baseMap = () => { + return new maptalks.Map('map', { + center: [116.41348403785, 39.910843952376], + zoom: 12, + minZoom: 1, + maxZoom: 19, + spatialReference: { + projection: 'baidu', + }, + attribution: { + content: '© vue-admin-beautiful', + }, + baseLayer: new maptalks.TileLayer('base', { + cssFilter: 'sepia(100%) invert(90%)', + urlTemplate: + 'http://online{s}.map.bdimg.com/onlinelabel/?qt=tile&x={x}&y={y}&z={z}&styles=pl&scaler=1&p=1', + subdomains: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + attribution: + '© Baidu', + }), + }) + } + + /* 全局lodash */ + Vue.prototype.$baseLodash = lodash + /* 全局事件总线 */ + Vue.prototype.$baseEventBus = new Vue() +} + +if (typeof window !== 'undefined' && window.Vue) { + install(window.Vue) +} + +export default install diff --git a/src/utils/validate.js b/src/utils/validate.js new file mode 100644 index 000000000..f14dccbb7 --- /dev/null +++ b/src/utils/validate.js @@ -0,0 +1,212 @@ +/** + + * @description 判读是否为外链 + * @param path + * @returns {boolean} + */ +export function isExternal(path) { + return /^(https?:|mailto:|tel:)/.test(path) +} + +/** + + * @description 校验密码是否小于6位 + * @param str + * @returns {boolean} + */ +export function isPassword(str) { + return str.length >= 6 +} + +/** + + * @description 判断是否为数字 + * @param value + * @returns {boolean} + */ +export function isNumber(value) { + const reg = /^[0-9]*$/ + return reg.test(value) +} + +/** + + * @description 判断是否是名称 + * @param value + * @returns {boolean} + */ +export function isName(value) { + const reg = /^[\u4e00-\u9fa5a-zA-Z0-9]+$/ + return reg.test(value) +} + +/** + + * @description 判断是否为IP + * @param ip + * @returns {boolean} + */ +export function isIP(ip) { + const reg = /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/ + return reg.test(ip) +} + +/** + + * @description 判断是否是传统网站 + * @param url + * @returns {boolean} + */ +export function isUrl(url) { + const reg = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/ + return reg.test(url) +} + +/** + + * @description 判断是否是小写字母 + * @param str + * @returns {boolean} + */ +export function isLowerCase(str) { + const reg = /^[a-z]+$/ + return reg.test(str) +} + +/** + + * @description 判断是否是大写字母 + * @param str + * @returns {boolean} + */ +export function isUpperCase(str) { + const reg = /^[A-Z]+$/ + return reg.test(str) +} + +/** + + * @description 判断是否是大写字母开头 + * @param str + * @returns {boolean} + */ +export function isAlphabets(str) { + const reg = /^[A-Za-z]+$/ + return reg.test(str) +} + +/** + + * @description 判断是否是字符串 + * @param str + * @returns {boolean} + */ +export function isString(str) { + return typeof str === 'string' || str instanceof String +} + +/** + + * @description 判断是否是数组 + * @param arg + * @returns {arg is any[]|boolean} + */ +export function isArray(arg) { + if (typeof Array.isArray === 'undefined') { + return Object.prototype.toString.call(arg) === '[object Array]' + } + return Array.isArray(arg) +} + +/** + + * @description 判断是否是端口号 + * @param str + * @returns {boolean} + */ +export function isPort(str) { + const reg = /^([0-9]|[1-9]\d|[1-9]\d{2}|[1-9]\d{3}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6553[0-5])$/ + return reg.test(str) +} + +/** + + * @description 判断是否是手机号 + * @param str + * @returns {boolean} + */ +export function isPhone(str) { + const reg = /^1\d{10}$/ + return reg.test(str) +} + +/** + + * @description 判断是否是身份证号(第二代) + * @param str + * @returns {boolean} + */ +export function isIdCard(str) { + const reg = /^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/ + return reg.test(str) +} + +/** + + * @description 判断是否是邮箱 + * @param str + * @returns {boolean} + */ +export function isEmail(str) { + const reg = /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/ + return reg.test(str) +} + +/** + + * @description 判断是否中文 + * @param str + * @returns {boolean} + */ +export function isChina(str) { + const reg = /^[\u4E00-\u9FA5]{2,4}$/ + return reg.test(str) +} + +/** + + * @description 判断是否为空 + * @param str + * @returns {boolean} + */ +export function isBlank(str) { + return ( + str == null || + false || + str === '' || + str.trim() === '' || + str.toLocaleLowerCase().trim() === 'null' + ) +} + +/** + + * @description 判断是否为固话 + * @param str + * @returns {boolean} + */ +export function isTel(str) { + const reg = /^(400|800)([0-9\\-]{7,10})|(([0-9]{4}|[0-9]{3})(-| )?)?([0-9]{7,8})((-| |转)*([0-9]{1,4}))?$/ + return reg.test(str) +} + +/** + + * @description 判断是否为数字且最多两位小数 + * @param str + * @returns {boolean} + */ +export function isNum(str) { + const reg = /^\d+(\.\d{1,2})?$/ + return reg.test(str) +} diff --git a/src/views/401.vue b/src/views/401.vue new file mode 100644 index 000000000..b09711a2e --- /dev/null +++ b/src/views/401.vue @@ -0,0 +1,296 @@ + + + + + diff --git a/src/views/404.vue b/src/views/404.vue new file mode 100644 index 000000000..9c261b691 --- /dev/null +++ b/src/views/404.vue @@ -0,0 +1,296 @@ + + + + + diff --git a/src/views/index/components/Plan.vue b/src/views/index/components/Plan.vue new file mode 100644 index 000000000..02ef9ae04 --- /dev/null +++ b/src/views/index/components/Plan.vue @@ -0,0 +1,87 @@ + + diff --git a/src/views/index/components/VersionInformation.vue b/src/views/index/components/VersionInformation.vue new file mode 100644 index 000000000..1df8fcf53 --- /dev/null +++ b/src/views/index/components/VersionInformation.vue @@ -0,0 +1,149 @@ + + + + + diff --git a/src/views/index/index.vue b/src/views/index/index.vue new file mode 100644 index 000000000..468d62bcb --- /dev/null +++ b/src/views/index/index.vue @@ -0,0 +1,699 @@ + + + + diff --git a/src/views/login/index.vue b/src/views/login/index.vue new file mode 100644 index 000000000..dd9976441 --- /dev/null +++ b/src/views/login/index.vue @@ -0,0 +1,327 @@ + + + + + diff --git a/src/views/mall/goodsList/index.vue b/src/views/mall/goodsList/index.vue new file mode 100644 index 000000000..824c62ba7 --- /dev/null +++ b/src/views/mall/goodsList/index.vue @@ -0,0 +1,163 @@ + + + + diff --git a/src/views/mall/pay/components/Step1.vue b/src/views/mall/pay/components/Step1.vue new file mode 100644 index 000000000..202e906f9 --- /dev/null +++ b/src/views/mall/pay/components/Step1.vue @@ -0,0 +1,70 @@ + + + diff --git a/src/views/mall/pay/components/Step2.vue b/src/views/mall/pay/components/Step2.vue new file mode 100644 index 000000000..c64e5ddee --- /dev/null +++ b/src/views/mall/pay/components/Step2.vue @@ -0,0 +1,84 @@ + + + diff --git a/src/views/mall/pay/components/Step3.vue b/src/views/mall/pay/components/Step3.vue new file mode 100644 index 000000000..a504a1944 --- /dev/null +++ b/src/views/mall/pay/components/Step3.vue @@ -0,0 +1,101 @@ + + + diff --git a/src/views/mall/pay/index.vue b/src/views/mall/pay/index.vue new file mode 100644 index 000000000..e0543288c --- /dev/null +++ b/src/views/mall/pay/index.vue @@ -0,0 +1,60 @@ + + + + diff --git a/src/views/personalCenter/index.vue b/src/views/personalCenter/index.vue new file mode 100644 index 000000000..42b0fa291 --- /dev/null +++ b/src/views/personalCenter/index.vue @@ -0,0 +1,23 @@ + + + diff --git a/src/views/personnelManagement/menuManagement/components/MenuManagementEdit.vue b/src/views/personnelManagement/menuManagement/components/MenuManagementEdit.vue new file mode 100644 index 000000000..df23fdff5 --- /dev/null +++ b/src/views/personnelManagement/menuManagement/components/MenuManagementEdit.vue @@ -0,0 +1,71 @@ + + + diff --git a/src/views/personnelManagement/menuManagement/index.vue b/src/views/personnelManagement/menuManagement/index.vue new file mode 100644 index 000000000..260ebc7a8 --- /dev/null +++ b/src/views/personnelManagement/menuManagement/index.vue @@ -0,0 +1,173 @@ + + + diff --git a/src/views/personnelManagement/roleManagement/components/RoleManagementEdit.vue b/src/views/personnelManagement/roleManagement/components/RoleManagementEdit.vue new file mode 100644 index 000000000..dc3a9fdab --- /dev/null +++ b/src/views/personnelManagement/roleManagement/components/RoleManagementEdit.vue @@ -0,0 +1,69 @@ + + + diff --git a/src/views/personnelManagement/roleManagement/index.vue b/src/views/personnelManagement/roleManagement/index.vue new file mode 100644 index 000000000..5fcf65896 --- /dev/null +++ b/src/views/personnelManagement/roleManagement/index.vue @@ -0,0 +1,150 @@ + + + diff --git a/src/views/personnelManagement/userManagement/components/UserManagementEdit.vue b/src/views/personnelManagement/userManagement/components/UserManagementEdit.vue new file mode 100644 index 000000000..fe4487260 --- /dev/null +++ b/src/views/personnelManagement/userManagement/components/UserManagementEdit.vue @@ -0,0 +1,95 @@ + + + diff --git a/src/views/personnelManagement/userManagement/index.vue b/src/views/personnelManagement/userManagement/index.vue new file mode 100644 index 000000000..e44e687f4 --- /dev/null +++ b/src/views/personnelManagement/userManagement/index.vue @@ -0,0 +1,166 @@ + + + diff --git a/src/views/register/index.vue b/src/views/register/index.vue new file mode 100644 index 000000000..7cb514fe4 --- /dev/null +++ b/src/views/register/index.vue @@ -0,0 +1,377 @@ + + + diff --git a/src/views/test/index.vue b/src/views/test/index.vue new file mode 100644 index 000000000..cd3fc662d --- /dev/null +++ b/src/views/test/index.vue @@ -0,0 +1,16 @@ + + diff --git a/src/views/vab/backToTop/index.vue b/src/views/vab/backToTop/index.vue new file mode 100644 index 000000000..49c101ac7 --- /dev/null +++ b/src/views/vab/backToTop/index.vue @@ -0,0 +1,22 @@ + + + + diff --git a/src/views/vab/editor/index.vue b/src/views/vab/editor/index.vue new file mode 100644 index 000000000..7e931a057 --- /dev/null +++ b/src/views/vab/editor/index.vue @@ -0,0 +1,156 @@ + + + + diff --git a/src/views/vab/element/index.vue b/src/views/vab/element/index.vue new file mode 100644 index 000000000..5d44c4596 --- /dev/null +++ b/src/views/vab/element/index.vue @@ -0,0 +1,254 @@ + + + + + diff --git a/src/views/vab/errorLog/components/ErrorTest.vue b/src/views/vab/errorLog/components/ErrorTest.vue new file mode 100644 index 000000000..a64210faa --- /dev/null +++ b/src/views/vab/errorLog/components/ErrorTest.vue @@ -0,0 +1,13 @@ + + + diff --git a/src/views/vab/errorLog/index.vue b/src/views/vab/errorLog/index.vue new file mode 100644 index 000000000..09593e740 --- /dev/null +++ b/src/views/vab/errorLog/index.vue @@ -0,0 +1,28 @@ + + + diff --git a/src/views/vab/form/index.vue b/src/views/vab/form/index.vue new file mode 100644 index 000000000..64d96d3cf --- /dev/null +++ b/src/views/vab/form/index.vue @@ -0,0 +1,111 @@ + + + diff --git a/src/views/vab/icon/colorfulIcon.vue b/src/views/vab/icon/colorfulIcon.vue new file mode 100644 index 000000000..d1890b98c --- /dev/null +++ b/src/views/vab/icon/colorfulIcon.vue @@ -0,0 +1,155 @@ + + + + + diff --git a/src/views/vab/icon/index.vue b/src/views/vab/icon/index.vue new file mode 100644 index 000000000..aad8cca14 --- /dev/null +++ b/src/views/vab/icon/index.vue @@ -0,0 +1,140 @@ + + + + + diff --git a/src/views/vab/icon/remixIcon.vue b/src/views/vab/icon/remixIcon.vue new file mode 100644 index 000000000..e8e376892 --- /dev/null +++ b/src/views/vab/icon/remixIcon.vue @@ -0,0 +1,153 @@ + + + + + diff --git a/src/views/vab/loading/index.vue b/src/views/vab/loading/index.vue new file mode 100644 index 000000000..94ce9f781 --- /dev/null +++ b/src/views/vab/loading/index.vue @@ -0,0 +1,71 @@ + + + + + diff --git a/src/views/vab/lodash/index.vue b/src/views/vab/lodash/index.vue new file mode 100644 index 000000000..8d326b594 --- /dev/null +++ b/src/views/vab/lodash/index.vue @@ -0,0 +1,211 @@ + + + + diff --git a/src/views/vab/magnifier/index.vue b/src/views/vab/magnifier/index.vue new file mode 100644 index 000000000..460dce4d9 --- /dev/null +++ b/src/views/vab/magnifier/index.vue @@ -0,0 +1,35 @@ + + + diff --git a/src/views/vab/map/index.vue b/src/views/vab/map/index.vue new file mode 100644 index 000000000..c86897780 --- /dev/null +++ b/src/views/vab/map/index.vue @@ -0,0 +1,115 @@ + + + + diff --git a/src/views/vab/markdownEditor/index.vue b/src/views/vab/markdownEditor/index.vue new file mode 100644 index 000000000..48989a15e --- /dev/null +++ b/src/views/vab/markdownEditor/index.vue @@ -0,0 +1,51 @@ + + + diff --git a/src/views/vab/more/index.vue b/src/views/vab/more/index.vue new file mode 100644 index 000000000..1c05e9dc0 --- /dev/null +++ b/src/views/vab/more/index.vue @@ -0,0 +1,119 @@ + + + + diff --git a/src/views/vab/nested/menu1/index.vue b/src/views/vab/nested/menu1/index.vue new file mode 100644 index 000000000..43702fcc9 --- /dev/null +++ b/src/views/vab/nested/menu1/index.vue @@ -0,0 +1,7 @@ + diff --git a/src/views/vab/nested/menu1/menu1-1/index.vue b/src/views/vab/nested/menu1/menu1-1/index.vue new file mode 100644 index 000000000..2560d5dad --- /dev/null +++ b/src/views/vab/nested/menu1/menu1-1/index.vue @@ -0,0 +1,13 @@ + + diff --git a/src/views/vab/nested/menu1/menu1-1/menu1-1-1/index.vue b/src/views/vab/nested/menu1/menu1-1/menu1-1-1/index.vue new file mode 100644 index 000000000..bcff7d3dc --- /dev/null +++ b/src/views/vab/nested/menu1/menu1-1/menu1-1-1/index.vue @@ -0,0 +1,15 @@ + + diff --git a/src/views/vab/permissions/index.vue b/src/views/vab/permissions/index.vue new file mode 100644 index 000000000..011a65548 --- /dev/null +++ b/src/views/vab/permissions/index.vue @@ -0,0 +1,156 @@ + + + diff --git a/src/views/vab/player/index.vue b/src/views/vab/player/index.vue new file mode 100644 index 000000000..504e10dd5 --- /dev/null +++ b/src/views/vab/player/index.vue @@ -0,0 +1,73 @@ + + + diff --git a/src/views/vab/smallComponents/index.vue b/src/views/vab/smallComponents/index.vue new file mode 100644 index 000000000..95c7328d7 --- /dev/null +++ b/src/views/vab/smallComponents/index.vue @@ -0,0 +1,110 @@ + + + + diff --git a/src/views/vab/table/components/TableEdit.vue b/src/views/vab/table/components/TableEdit.vue new file mode 100644 index 000000000..3e8d877e1 --- /dev/null +++ b/src/views/vab/table/components/TableEdit.vue @@ -0,0 +1,75 @@ + + + diff --git a/src/views/vab/table/index.vue b/src/views/vab/table/index.vue new file mode 100644 index 000000000..f9186c6ee --- /dev/null +++ b/src/views/vab/table/index.vue @@ -0,0 +1,263 @@ + + + diff --git a/src/views/vab/tree/index.vue b/src/views/vab/tree/index.vue new file mode 100644 index 000000000..565e5aecf --- /dev/null +++ b/src/views/vab/tree/index.vue @@ -0,0 +1,478 @@ + + + diff --git a/src/views/vab/upload/index.vue b/src/views/vab/upload/index.vue new file mode 100644 index 000000000..910718325 --- /dev/null +++ b/src/views/vab/upload/index.vue @@ -0,0 +1,34 @@ + + + diff --git a/src/views/vab/verify/index.vue b/src/views/vab/verify/index.vue new file mode 100644 index 000000000..899d7e3d5 --- /dev/null +++ b/src/views/vab/verify/index.vue @@ -0,0 +1,35 @@ + + + diff --git a/src/views/vab/webSocket/index.vue b/src/views/vab/webSocket/index.vue new file mode 100644 index 000000000..84b867d21 --- /dev/null +++ b/src/views/vab/webSocket/index.vue @@ -0,0 +1,87 @@ + + + diff --git a/vue.config.js b/vue.config.js new file mode 100644 index 000000000..9d3a6c98b --- /dev/null +++ b/vue.config.js @@ -0,0 +1,183 @@ +/** + + * @description cli配置 + */ + +const path = require('path') +const { + publicPath, + assetsDir, + outputDir, + lintOnSave, + transpileDependencies, + title, + abbreviation, + devPort, + providePlugin, + build7z, + donation, +} = require('./src/config') +const { webpackBarName, webpackBanner, donationConsole } = require('zx-layouts') + +if (donation) donationConsole() +const { version, author } = require('./package.json') +const Webpack = require('webpack') +const WebpackBar = require('webpackbar') +const FileManagerPlugin = require('filemanager-webpack-plugin') +const dayjs = require('dayjs') +const date = dayjs().format('YYYY_M_D') +const time = dayjs().format('YYYY-M-D HH:mm:ss') +process.env.VUE_APP_TITLE = title || 'vue-admin-beautiful' +process.env.VUE_APP_AUTHOR = author || 'chuzhixin 1204505056@qq.com' +process.env.VUE_APP_UPDATE_TIME = time +process.env.VUE_APP_VERSION = version + +const resolve = (dir) => path.join(__dirname, dir) + +module.exports = { + publicPath, + assetsDir, + outputDir, + lintOnSave, + transpileDependencies, + devServer: { + hot: true, + port: devPort, + open: true, + noInfo: false, + overlay: { + warnings: true, + errors: true, + }, + }, + configureWebpack() { + return { + resolve: { + alias: { + '@': resolve('src'), + }, + }, + plugins: [ + new Webpack.ProvidePlugin(providePlugin), + new WebpackBar({ + name: webpackBarName, + }), + ], + } + }, + chainWebpack(config) { + config.plugins.delete('preload') + config.plugins.delete('prefetch') + config.module + .rule('svg') + .exclude.add(resolve('src/remixIcon')) + .add(resolve('src/colorfulIcon')) + .end() + + config.module + .rule('remixIcon') + .test(/\.svg$/) + .include.add(resolve('src/remixIcon')) + .end() + .use('svg-sprite-loader') + .loader('svg-sprite-loader') + .options({ symbolId: 'remix-icon-[name]' }) + .end() + + config.module + .rule('colorfulIcon') + .test(/\.svg$/) + .include.add(resolve('src/colorfulIcon')) + .end() + .use('svg-sprite-loader') + .loader('svg-sprite-loader') + .options({ symbolId: 'colorful-icon-[name]' }) + .end() + + /* config.when(process.env.NODE_ENV === "development", (config) => { + config.devtool("source-map"); + }); */ + config.when(process.env.NODE_ENV !== 'development', (config) => { + config.performance.set('hints', false) + config.devtool('none') + config.optimization.splitChunks({ + chunks: 'all', + cacheGroups: { + libs: { + name: 'chunk-libs', + test: /[\\/]node_modules[\\/]/, + priority: 10, + chunks: 'initial', + }, + elementUI: { + name: 'chunk-elementUI', + priority: 20, + test: /[\\/]node_modules[\\/]_?element-ui(.*)/, + }, + fortawesome: { + name: 'chunk-fortawesome', + priority: 20, + test: /[\\/]node_modules[\\/]_?@fortawesome(.*)/, + }, + }, + }) + config + .plugin('banner') + .use(Webpack.BannerPlugin, [`${webpackBanner}${time}`]) + .end() + config.module + .rule('images') + .use('image-webpack-loader') + .loader('image-webpack-loader') + .options({ + bypassOnDebug: true, + }) + .end() + }) + + if (build7z) { + config.when(process.env.NODE_ENV === 'production', (config) => { + config + .plugin('fileManager') + .use(FileManagerPlugin, [ + { + onEnd: { + delete: [`./${outputDir}/video`, `./${outputDir}/data`], + archive: [ + { + source: `./${outputDir}`, + destination: `./${outputDir}/${abbreviation}_${outputDir}_${date}.7z`, + }, + ], + }, + }, + ]) + .end() + }) + } + }, + runtimeCompiler: true, + productionSourceMap: false, + css: { + requireModuleExtension: true, + sourceMap: true, + loaderOptions: { + scss: { + /*sass-loader 8.0语法 */ + //prependData: '@import "~@/styles/variables.scss";', + + /*sass-loader 9.0写法,感谢github用户 shaonialife*/ + additionalData(content, loaderContext) { + const { resourcePath, rootContext } = loaderContext + const relativePath = path.relative(rootContext, resourcePath) + if ( + relativePath.replace(/\\/g, '/') !== 'src/styles/variables.scss' + ) { + return '@import "~@/styles/variables.scss";' + content + } + return content + }, + }, + }, + }, +} diff --git a/webstorm.config.js b/webstorm.config.js new file mode 100644 index 000000000..22d53e99a --- /dev/null +++ b/webstorm.config.js @@ -0,0 +1,6 @@ +/** + + * @description webstorm.config + */ +const webpackConfig = require('@vue/cli-service/webpack.config.js') +module.exports = webpackConfig