├── src
├── assets
│ ├── scss
│ │ ├── common
│ │ │ ├── global.scss
│ │ │ ├── transition.scss
│ │ │ └── var.scss
│ │ ├── mixins
│ │ │ ├── config.scss
│ │ │ ├── utils.scss
│ │ │ ├── function.scss
│ │ │ ├── _button.scss
│ │ │ └── mixins.scss
│ │ └── theme.scss
│ └── img
│ │ └── background.jpg
├── plugins
│ ├── index.js
│ ├── draggable.js
│ ├── store.js
│ └── element.js
├── utils
│ ├── event-bus.js
│ ├── util.js
│ ├── fetch.js
│ └── dom.js
├── constants
│ └── password.js
├── components
│ ├── multi-tab
│ │ ├── index.js
│ │ ├── __tests__
│ │ │ └── multi-tab.test.js
│ │ └── multi-tab.vue
│ └── layouts
│ │ ├── index.js
│ │ ├── route-view.js
│ │ ├── global-layout.vue
│ │ ├── menu.js
│ │ └── page-layout.vue
├── App.vue
├── store
│ ├── modules
│ │ ├── app.js
│ │ └── auth.js
│ ├── index.js
│ └── getters.js
├── views
│ ├── hello.vue
│ ├── component.vue
│ ├── page-403.vue
│ ├── page-404.vue
│ └── login.vue
├── main.js
├── api
│ └── auth.js
├── router.js
├── config
│ └── route.config.js
└── permission.js
├── .browserslistrc
├── .env
├── .env.test1
├── babel.config.js
├── public
├── favicon.ico
└── index.html
├── tests
└── unit
│ ├── .eslintrc.js
│ ├── setup.js
│ └── utils.js
├── postcss.config.js
├── .editorconfig
├── .gitignore
├── .eslintrc.js
├── vue.config.js
├── README.md
├── jest.config.js
└── package.json
/src/assets/scss/common/global.scss:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/.browserslistrc:
--------------------------------------------------------------------------------
1 | > 1%
2 | last 2 versions
3 |
--------------------------------------------------------------------------------
/src/plugins/index.js:
--------------------------------------------------------------------------------
1 | import './element'
2 | import './store'
3 |
--------------------------------------------------------------------------------
/.env:
--------------------------------------------------------------------------------
1 | VUE_APP_BASEURL=/api/
2 | VUE_APP_PROXY_TARGET=http://127.0.0.1:3000
3 |
--------------------------------------------------------------------------------
/.env.test1:
--------------------------------------------------------------------------------
1 | VUE_APP_BASEURL=/api/
2 | VUE_APP_PROXY_TARGET=http://127.0.0.1:3000
3 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/app'
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wayejs/waye-pro/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/src/utils/event-bus.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | export const EventBus = new Vue()
3 |
--------------------------------------------------------------------------------
/tests/unit/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: {
3 | jest: true
4 | }
5 | }
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | autoprefixer: {}
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/src/constants/password.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 三个姓陈的 + 一个姓林
3 | */
4 | export const PASSPORD_HASH = 'cccl'
5 |
--------------------------------------------------------------------------------
/src/components/multi-tab/index.js:
--------------------------------------------------------------------------------
1 | import MultiTab from './multi-tab.vue'
2 | export default MultiTab
3 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/assets/img/background.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wayejs/waye-pro/HEAD/src/assets/img/background.jpg
--------------------------------------------------------------------------------
/src/plugins/draggable.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import draggable from 'vuedraggable'
3 | Vue.component('draggable', draggable)
4 |
--------------------------------------------------------------------------------
/src/assets/scss/mixins/config.scss:
--------------------------------------------------------------------------------
1 | $namespace: 'ql';
2 | $element-separator: '__';
3 | $modifier-separator: '--';
4 | $state-prefix: 'is-';
5 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.{js,jsx,ts,tsx,vue}]
2 | indent_style = space
3 | indent_size = 2
4 | trim_trailing_whitespace = true
5 | insert_final_newline = true
6 |
--------------------------------------------------------------------------------
/src/components/layouts/index.js:
--------------------------------------------------------------------------------
1 | import GlobalLayout from './global-layout.vue'
2 | import RouteView from './route-view'
3 | export {
4 | GlobalLayout,
5 | RouteView
6 | }
7 |
--------------------------------------------------------------------------------
/src/plugins/store.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import VueStorage from 'vue-ls'
3 |
4 | Vue.use(VueStorage, {
5 | namespace: 'wypro__',
6 | name: 'ls',
7 | storage: 'local'
8 | })
9 |
--------------------------------------------------------------------------------
/src/store/modules/app.js:
--------------------------------------------------------------------------------
1 | const app = {
2 | state: {
3 | multiTab: true
4 | },
5 | mutations: {
6 |
7 | },
8 | actions: {
9 |
10 | }
11 | }
12 |
13 | export default app
14 |
--------------------------------------------------------------------------------
/src/views/hello.vue:
--------------------------------------------------------------------------------
1 |
2 | hello
3 |
4 |
5 |
15 |
--------------------------------------------------------------------------------
/src/views/component.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | 状态
4 |
5 |
6 |
7 |
16 |
--------------------------------------------------------------------------------
/src/assets/scss/theme.scss:
--------------------------------------------------------------------------------
1 | @import "common/var.scss";
2 |
3 | @import "common/global.scss";
4 |
5 | /* 改变 icon 字体路径变量,必需 */
6 | $--font-path: '~element-ui/lib/theme-chalk/fonts';
7 |
8 | @import "~element-ui/packages/theme-chalk/src/index";
9 | @import "~@waye/ui/packages/theme/src/index";
10 |
--------------------------------------------------------------------------------
/tests/unit/setup.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Element from 'element-ui'
3 |
4 | import clickoutside from 'element-ui/lib/utils/clickoutside'
5 |
6 | import Waye from '@waye/ui'
7 |
8 | Vue.use(Element, { size: 'medium' })
9 | Vue.use(Waye)
10 |
11 | Vue.directive('clickoutside', clickoutside)
12 |
--------------------------------------------------------------------------------
/src/views/page-403.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
16 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import './plugins'
3 | import App from './App.vue'
4 | import router from './router'
5 | import store from './store'
6 |
7 | import './permission'
8 |
9 | Vue.config.productionTip = false
10 |
11 | new Vue({
12 | router,
13 | store,
14 | render: h => h(App)
15 | }).$mount('#app')
16 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | # local env files
6 | .env.local
7 | .env.*.local
8 |
9 | # Log files
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw?
22 | .history
23 |
--------------------------------------------------------------------------------
/src/store/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuex from 'vuex'
3 |
4 | import auth from './modules/auth'
5 | import app from './modules/app'
6 | import getters from './getters'
7 | Vue.use(Vuex)
8 |
9 | const store = new Vuex.Store({
10 | modules: {
11 | app,
12 | auth
13 | },
14 | getters
15 | })
16 |
17 | export default store
18 |
--------------------------------------------------------------------------------
/src/store/getters.js:
--------------------------------------------------------------------------------
1 | const getters = {
2 | userName: state => state.auth.userName,
3 | userCode: state => state.auth.userCode,
4 | userId: state => state.auth.userId,
5 | permissions: state => state.auth.permissions,
6 | asyncRoutes: state => state.auth.asyncRoutes,
7 |
8 | multiTab: state => state.app.multiTab
9 | }
10 |
11 | export default getters
12 |
--------------------------------------------------------------------------------
/src/plugins/element.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Element from 'element-ui'
3 | import 'element-ui/lib/theme-chalk/reset.css'
4 | import '@/assets/scss/theme.scss'
5 |
6 | import clickoutside from 'element-ui/lib/utils/clickoutside'
7 |
8 | import Waye from '@waye/ui'
9 |
10 | Vue.use(Element, { size: 'medium' })
11 | Vue.use(Waye)
12 |
13 | Vue.directive('clickoutside', clickoutside)
14 |
--------------------------------------------------------------------------------
/src/components/layouts/route-view.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'QlRouteView',
3 | render () {
4 | const { $route: { meta }, $store: { getters } } = this
5 |
6 | const inKeep = (
7 |
8 |
9 |
10 | )
11 | const notKeep = (
12 |
13 | )
14 | return meta.keepAlive || getters.multiTab ? inKeep : notKeep
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | node: true
5 | },
6 | 'extends': [
7 | 'plugin:vue/essential',
8 | '@vue/standard'
9 | ],
10 | rules: {
11 | 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
12 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
13 | },
14 | parserOptions: {
15 | parser: 'babel-eslint'
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack')
2 |
3 | const plugins = [
4 | new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /zh-cn/)
5 | ]
6 |
7 | module.exports = {
8 | lintOnSave: true,
9 | configureWebpack: {
10 | plugins
11 | },
12 |
13 | devServer: {
14 | port: '9000',
15 | proxy: {
16 | '/api': {
17 | target: process.env.VUE_APP_PROXY_TARGET,
18 | ws: false,
19 | changeOrigin: true
20 | }
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/components/layouts/global-layout.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
24 |
--------------------------------------------------------------------------------
/src/api/auth.js:
--------------------------------------------------------------------------------
1 | import { post, getFileUrl, postByForm } from '../utils/fetch'
2 |
3 | export function login (params) {
4 | return post('system/mgr/login', params)
5 | }
6 |
7 | export function logout () {
8 | return post('system/mgr/logout')
9 | }
10 |
11 | /**
12 | * 获取验证码
13 | * @export
14 | * @param {any} time 时间戳
15 | */
16 | export function validCodeUrl (time) {
17 | return getFileUrl('system/kaptcha', { time })
18 | }
19 |
20 | /**
21 | * 修改密码
22 | * @param {*} params 参数
23 | */
24 | export function changePwd (params) {
25 | return postByForm('system/user/modifyPwd', params)
26 | }
27 |
--------------------------------------------------------------------------------
/src/assets/scss/common/transition.scss:
--------------------------------------------------------------------------------
1 | .fade-enter-active, .fade-leave-active {
2 | transition: opacity .5s ease;
3 | }
4 | .fade-enter, .fade-leave-active {
5 | opacity: 0
6 | }
7 | .slide-left-enter, .slide-right-leave-active {
8 | opacity: 0;
9 | -webkit-transform: translate(30px, 0);
10 | transform: translate(30px, 0);
11 | }
12 | .slide-left-leave-active, .slide-right-enter {
13 | opacity: 0;
14 | -webkit-transform: translate(-30px, 0);
15 | transform: translate(-30px, 0);
16 | }
17 | .slide-view {
18 | position: absolute;
19 | width: 100%;
20 | transition: all .5s cubic-bezier(.55,0,.1,1);
21 | }
22 |
--------------------------------------------------------------------------------
/src/components/multi-tab/__tests__/multi-tab.test.js:
--------------------------------------------------------------------------------
1 | import { shallowMount } from '@vue/test-utils'
2 | import MultiTab from '@/components/multi-tab'
3 |
4 | const $route = {
5 | fullPath: '/about',
6 | meta: {
7 | title: '关于我们'
8 | },
9 | path: '/about'
10 | }
11 | const $router = {
12 | push () {
13 |
14 | }
15 | }
16 |
17 | describe('MultiTab', () => {
18 | it('init multi-tab', async () => {
19 | const wrapper = shallowMount(MultiTab, {
20 | mocks: {
21 | $route,
22 | $router
23 | }
24 | })
25 |
26 | expect(wrapper.vm.activeRoute).toBe('/about')
27 | })
28 | })
29 |
--------------------------------------------------------------------------------
/src/router.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Router from 'vue-router'
3 |
4 | const baseRoutes = [
5 | {
6 | path: '/login',
7 | name: 'login',
8 | component: () => import(/* webpackChunkName: "login" */ '@/views/login')
9 | },
10 | {
11 | path: '/403',
12 | name: 'page403',
13 | component: () => import(/* webpackChunkName: "403" */ '@/views/page-403')
14 | }, {
15 | path: '/404',
16 | name: 'page404',
17 | component: () => import(/* webpackChunkName: "404" */ '@/views/page-404')
18 | }
19 | ]
20 |
21 | Vue.use(Router)
22 | const router = new Router({
23 | routes: baseRoutes
24 | })
25 | export default router
26 |
--------------------------------------------------------------------------------
/tests/unit/utils.js:
--------------------------------------------------------------------------------
1 | // import moment from 'moment'
2 | // import MockDate from 'mockdate'
3 | import Vue from 'vue'
4 |
5 | // export function setMockDate (dateString = '2017-09-18T03:30:07.795') {
6 | // MockDate.set(moment(dateString))
7 | // }
8 |
9 | // export function resetMockDate () {
10 | // MockDate.reset()
11 | // }
12 |
13 | export function asyncExpect (fn, timeout) {
14 | return new Promise(resolve => {
15 | if (typeof timeout === 'number') {
16 | setTimeout(() => {
17 | fn()
18 | resolve()
19 | }, timeout)
20 | } else {
21 | Vue.nextTick(() => {
22 | fn()
23 | resolve()
24 | })
25 | }
26 | })
27 | }
28 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # waye-pro
2 |
3 | > 通过 vue-cli 生成的项目脚手架
4 |
5 | ## 使用
6 |
7 | ```bash
8 | git clone https://github.com/wayejs/waye-pro.git project-xxx
9 | cd project-xxx
10 | git remote remove origin
11 | git remote add origin [新的git仓库链接]
12 | git push -u origin master
13 | yarn install
14 | ```
15 |
16 | ### Compiles and hot-reloads for development
17 | ```
18 | yarn run serve
19 | ```
20 |
21 | ### Compiles and minifies for production
22 | ```
23 | yarn run build
24 | ```
25 |
26 | ### Run your tests
27 | ```
28 | yarn run test
29 | ```
30 |
31 | ### Lints and fixes files
32 | ```
33 | yarn run lint
34 | ```
35 |
36 | ### Customize configuration
37 | See [Configuration Reference](https://cli.vuejs.org/config/).
38 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | waye-pro
10 |
11 |
12 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/views/page-404.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{timeText}}, {{userName}}
4 |
5 |
6 |
7 |
31 |
--------------------------------------------------------------------------------
/src/assets/scss/mixins/utils.scss:
--------------------------------------------------------------------------------
1 | @mixin utils-user-select($value) {
2 | -moz-user-select: $value;
3 | -webkit-user-select: $value;
4 | -ms-user-select: $value;
5 | }
6 |
7 | @mixin utils-clearfix {
8 | $selector: &;
9 |
10 | @at-root {
11 | #{$selector}::before,
12 | #{$selector}::after {
13 | display: table;
14 | content: "";
15 | }
16 | #{$selector}::after {
17 | clear: both
18 | }
19 | }
20 | }
21 |
22 | @mixin utils-vertical-center {
23 | $selector: &;
24 |
25 | @at-root {
26 | #{$selector}::after {
27 | display: inline-block;
28 | content: "";
29 | height: 100%;
30 | vertical-align: middle
31 | }
32 | }
33 | }
34 |
35 | @mixin utils-ellipsis {
36 | overflow: hidden;
37 | text-overflow: ellipsis;
38 | white-space: nowrap;
39 | }
--------------------------------------------------------------------------------
/src/config/route.config.js:
--------------------------------------------------------------------------------
1 | import { RouteView, GlobalLayout } from '@/components/layouts'
2 | const mainRouteConfig = [
3 | {
4 | name: 'dashboard',
5 | icon: 'data-montior',
6 | label: '面板',
7 | component: RouteView,
8 | children: [
9 | {
10 | name: 'hello',
11 | component: () => import('@/views/hello'),
12 | label: 'Hello'
13 | },
14 | {
15 | name: 'component',
16 | component: () => import('@/views/component'),
17 | label: '组件'
18 | }
19 | ]
20 | }
21 | ]
22 | const root = {
23 | path: '/',
24 | name: 'home',
25 | label: '首页',
26 | redirect: '/hello',
27 | component: GlobalLayout,
28 | children: mainRouteConfig
29 | }
30 |
31 | const asyncRouterConfig = [
32 | root,
33 | {
34 | path: '*',
35 | redirect: '/404',
36 | hidden: true
37 | }
38 | ]
39 |
40 | export {
41 | mainRouteConfig
42 | }
43 | export default asyncRouterConfig
44 |
--------------------------------------------------------------------------------
/src/utils/util.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 去掉重复
3 | * @param {Array} value 数组值
4 | */
5 | export function uniq (value) {
6 | let setValue = new Set(value)
7 | return Array.from(setValue)
8 | }
9 |
10 | export const getSearchParams = () => {
11 | let params = decodeURI(location.search.slice(1))
12 | let ret = {}
13 | if (params) {
14 | params = params.split('&')
15 | params.forEach(param => {
16 | let item = param.split('=')
17 | ret[item[0]] = item[1]
18 | })
19 | }
20 | return ret
21 | }
22 |
23 | /**
24 | * 分组数据
25 | * @param {*} data 数据列表
26 | * @param {*} size 每组显示的条数
27 | */
28 | export const groupBy = (data, size) => {
29 | const result = data.reduce((r, t) => {
30 | r.current.push(t)
31 | if (r.current.length === size) {
32 | r.list.push(r.current)
33 | r.current = []
34 | }
35 | return r
36 | }, { list: [], current: [] })
37 |
38 | if (result.current.length) {
39 | result.list.push(result.current)
40 | }
41 |
42 | return result.list
43 | }
44 |
45 |
46 |
--------------------------------------------------------------------------------
/src/assets/scss/mixins/function.scss:
--------------------------------------------------------------------------------
1 | @import "config";
2 |
3 | /* BEM support Func
4 | -------------------------- */
5 | @function selectorToString($selector) {
6 | $selector: inspect($selector);
7 | $selector: str-slice($selector, 2, -2);
8 | @return $selector;
9 | }
10 |
11 | @function containsModifier($selector) {
12 | $selector: selectorToString($selector);
13 |
14 | @if str-index($selector, $modifier-separator) {
15 | @return true;
16 | } @else {
17 | @return false;
18 | }
19 | }
20 |
21 | @function containWhenFlag($selector) {
22 | $selector: selectorToString($selector);
23 |
24 | @if str-index($selector, '.' + $state-prefix) {
25 | @return true
26 | } @else {
27 | @return false
28 | }
29 | }
30 |
31 | @function containPseudoClass($selector) {
32 | $selector: selectorToString($selector);
33 |
34 | @if str-index($selector, ':') {
35 | @return true
36 | } @else {
37 | @return false
38 | }
39 | }
40 |
41 | @function hitAllSpecialNestRule($selector) {
42 |
43 | @return containsModifier($selector) or containWhenFlag($selector) or containPseudoClass($selector);
44 | }
45 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | collectCoverage: process.env.COVERAGE === 'true',
3 | collectCoverageFrom: [
4 | '**/*.{js,vue}',
5 | '!**/node_modules/**',
6 | '!**/lib/**',
7 | '!**/tests/**',
8 | '!**/build/**'
9 | ],
10 | coverageReporters: ['html', 'text-summary'],
11 | moduleFileExtensions: ['js', 'jsx', 'json', 'vue'],
12 | setupFiles: ['tests/unit/setup'],
13 | transform: {
14 | '^.+\\.vue$': 'vue-jest',
15 | '.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$':
16 | 'jest-transform-stub',
17 | '^.+\\.js?$': 'babel-jest',
18 | '^.+\\.jsx?$': 'babel-jest'
19 | },
20 | moduleNameMapper: {
21 | '^@/(.*)$': '/src/$1'
22 | },
23 | snapshotSerializers: ['jest-serializer-vue'],
24 | testMatch: [
25 | '**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.test.(js|jsx|ts|tsx)'
26 | ],
27 | testPathIgnorePatterns: ['/.history/', '/node_modules/'],
28 | testURL: 'http://localhost/',
29 | transformIgnorePatterns: ['/node_modules/'],
30 | watchPlugins: [
31 | 'jest-watch-typeahead/filename',
32 | 'jest-watch-typeahead/testname'
33 | ]
34 | }
35 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "waye-pro",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "serve": "vue-cli-service serve",
7 | "build": "vue-cli-service build",
8 | "lint": "vue-cli-service lint",
9 | "test": "vue-cli-service test:unit"
10 | },
11 | "dependencies": {
12 | "@waye/ui": "^0.1.5",
13 | "axios": "^0.19.0",
14 | "core-js": "^2.6.5",
15 | "element-ui": "^2.11.1",
16 | "lodash": "^4.17.15",
17 | "md5": "^2.2.1",
18 | "moment": "^2.24.0",
19 | "nprogress": "^0.2.0",
20 | "vue": "^2.6.10",
21 | "vue-ls": "^3.2.1",
22 | "vue-router": "^3.0.3",
23 | "vuex": "^3.0.1"
24 | },
25 | "devDependencies": {
26 | "@vue/cli-plugin-babel": "^3.11.0",
27 | "@vue/cli-plugin-eslint": "^3.11.0",
28 | "@vue/cli-service": "^3.11.0",
29 | "@vue/eslint-config-standard": "^4.0.0",
30 | "@vue/cli-plugin-unit-jest": "^3.8.0",
31 | "@vue/test-utils": "^1.0.0-beta.29",
32 | "babel-cli": "^6.26.0",
33 | "babel-core": "7.0.0-bridge.0",
34 | "babel-eslint": "^10.0.1",
35 | "babel-jest": "^24.8.0",
36 | "eslint": "^5.16.0",
37 | "eslint-plugin-vue": "^5.0.0",
38 | "node-sass": "^4.9.0",
39 | "sass-loader": "^7.1.0",
40 | "vue-template-compiler": "^2.6.10"
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/components/multi-tab/multi-tab.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
11 |
12 |
13 |
14 |
60 |
61 |
82 |
--------------------------------------------------------------------------------
/src/permission.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import router from './router'
3 | import store from './store'
4 |
5 | import NProgress from 'nprogress'
6 | import 'nprogress/nprogress.css'
7 |
8 | import { SUPER_ADMIN } from './store/modules/auth'
9 | NProgress.configure({
10 | showSpinner: false
11 | })
12 |
13 | const whiteList = ['login']
14 | router.beforeEach((to, from, next) => {
15 | NProgress.start()
16 | if (whiteList.includes(to.name)) {
17 | next()
18 | } else if (Vue.ls.get('userInfo')) {
19 | if (store.getters.asyncRoutes.length === 0) {
20 | store
21 | .dispatch('genAsyncRoutes', store.getters.permissions)
22 | .then(() => {
23 | router.addRoutes(store.getters.asyncRoutes)
24 | const redirect = decodeURIComponent(from.query.redirect || to.path)
25 | if (to.path === redirect) {
26 | next({
27 | ...to,
28 | replace: true
29 | })
30 | } else {
31 | next({
32 | path: redirect
33 | })
34 | }
35 | NProgress.done()
36 | }).catch(() => {
37 | NProgress.done()
38 | })
39 | } else {
40 | next()
41 | }
42 | } else {
43 | next({
44 | path: '/login',
45 | query: {
46 | redirect: to.fullpath
47 | }
48 | })
49 | }
50 | })
51 |
52 | router.afterEach(() => {
53 | NProgress.done()
54 | })
55 |
56 | /**
57 | * 操作权限指令
58 | * 用法
59 | * - 在操作按钮组件上 使用 v-action:[actionName], 如下
60 | * 添加
61 | * 编辑
62 | * - 用户没有对应操作权限时,操作按钮会不显示
63 | * - actionName = view|add|edit|delete|import|export|disable|enable|reset, 目前只有add 和 edit
64 | */
65 | const vAction = Vue.directive('action', {
66 | bind: function (el, binding, vnode) {
67 | const actionName = binding.arg
68 | const permissions = store.getters.permissions
69 | const code = vnode.context.$route.meta.code
70 | let isAdmin = store.getters.userCode === SUPER_ADMIN
71 | let action = `${code}:${actionName}`
72 |
73 | if (!permissions.includes(action) && !isAdmin) {
74 | setTimeout(() => {
75 | if (el.parentNode == null) {
76 | el.style.display = 'none'
77 | } else {
78 | el.parentNode.removeChild(el)
79 | }
80 | }, 10)
81 | }
82 | }
83 | })
84 |
85 | export {
86 | vAction
87 | }
88 |
--------------------------------------------------------------------------------
/src/assets/scss/mixins/_button.scss:
--------------------------------------------------------------------------------
1 | @import "../common/var";
2 | @mixin button-plain($color) {
3 | color: $color;
4 | background: mix($--color-white, $color, 90%);
5 | border-color: mix($--color-white, $color, 60%);
6 |
7 | &:hover,
8 | &:focus {
9 | background: $color;
10 | border-color: $color;
11 | color: $--color-white;
12 | }
13 |
14 | &:active {
15 | background: mix($--color-black, $color, $--button-active-shade-percent);
16 | border-color: mix($--color-black, $color, $--button-active-shade-percent);
17 | color: $--color-white;
18 | outline: none;
19 | }
20 |
21 | &.is-disabled {
22 | &,
23 | &:hover,
24 | &:focus,
25 | &:active {
26 | color: mix($--color-white, $color, 40%);
27 | background-color: mix($--color-white, $color, 90%);
28 | border-color: mix($--color-white, $color, 80%);
29 | }
30 | }
31 | }
32 |
33 | @mixin button-variant($color, $background-color, $border-color) {
34 | color: $color;
35 | background-color: $background-color;
36 | border-color: $border-color;
37 |
38 | &:hover,
39 | &:focus {
40 | background: mix($--color-white, $background-color, $--button-hover-tint-percent);
41 | border-color: mix($--color-white, $border-color, $--button-hover-tint-percent);
42 | color: $color;
43 | }
44 |
45 | &:active {
46 | background: mix($--color-black, $background-color, $--button-active-shade-percent);
47 | border-color: mix($--color-black, $border-color, $--button-active-shade-percent);
48 | color: $color;
49 | outline: none;
50 | }
51 |
52 | &.is-active {
53 | background: mix($--color-black, $background-color, $--button-active-shade-percent);
54 | border-color: mix($--color-black, $border-color, $--button-active-shade-percent);
55 | color: $color;
56 | }
57 |
58 | &.is-disabled {
59 | &,
60 | &:hover,
61 | &:focus,
62 | &:active {
63 | color: $--color-white;
64 | background-color: mix($background-color, $--color-white);
65 | border-color: mix($border-color, $--color-white);
66 | }
67 | }
68 |
69 | &.is-plain {
70 | @include button-plain($background-color);
71 | }
72 | }
73 |
74 | @mixin button-size($padding-vertical, $padding-horizontal, $font-size, $border-radius) {
75 | padding: $padding-vertical $padding-horizontal;
76 | font-size: $font-size;
77 | border-radius: $border-radius;
78 | &.is-round {
79 | padding: $padding-vertical $padding-horizontal;
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/components/layouts/menu.js:
--------------------------------------------------------------------------------
1 | import { mapGetters } from 'vuex'
2 | export default {
3 | name: 'QlMenu',
4 | props: {
5 | collapse: Boolean
6 | },
7 | computed: {
8 | ...mapGetters(['asyncRoutes']),
9 |
10 | activeIndex () {
11 | return this.$route.path
12 | },
13 |
14 | menuList () {
15 | let home = this.asyncRoutes.find(item => item.name === 'home')
16 | return home ? home.children : []
17 | }
18 | },
19 | methods: {
20 | genMenus (menus) {
21 | let h = this.$createElement
22 | let elements = []
23 | menus.forEach(item => {
24 | if (item.children) {
25 | elements.push(
26 | h('el-submenu', {
27 | props: {
28 | popperClass: 'ql-layout__submenu',
29 | index: item.path
30 | },
31 | key: item.path
32 | }, [
33 | h('div', {
34 | slot: 'title'
35 | }, [
36 | h('wy-icon', {
37 | props: {
38 | name: item.icon
39 | }
40 | }),
41 | h('span', {
42 | slot: 'title'
43 | }, item.label || item.meta.title)
44 | ]),
45 | this.genMenus(item.children)
46 | ])
47 | )
48 | } else {
49 | elements.push(
50 | h('el-menu-item', {
51 | props: {
52 | index: item.path
53 | },
54 | key: item.path
55 | }, [
56 | h('wy-icon', {
57 | props: {
58 | name: item.icon
59 | }
60 | }),
61 | h('span', {
62 | slot: 'title'
63 | }, item.label || item.meta.title)
64 | ])
65 | )
66 | }
67 | })
68 | return elements
69 | }
70 | },
71 | render (h) {
72 | if (!this.menuList.length) {
73 | return h('div', {
74 | class: {
75 | 'ql-layout__aside-empty': true,
76 | 'is-collapse': this.collapse
77 | }
78 | }, '无菜单权限,请联系客服')
79 | }
80 | return h('el-menu', {
81 | class: {
82 | 'ql-layout__aside-menu': true
83 | },
84 | props: {
85 | router: true,
86 | collapse: this.collapse,
87 | defaultActive: this.activeIndex,
88 | backgroundColor: '#00142a',
89 | activeTextColor: '#409EFF',
90 | textColor: 'hsla(0, 0%, 100%, .65)',
91 | mode: 'vertical'
92 | }
93 | }, this.genMenus(this.menuList))
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/src/store/modules/auth.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import { login, logout } from '../../api/auth'
3 | import navConfig from '@/config/route.config'
4 | import cloneDeep from 'lodash/cloneDeep'
5 | let wayeUserInfo = Vue.ls.get('userInfo')
6 | let codeMap = {}
7 |
8 | export const SUPER_ADMIN = 'admin'
9 | const parseRoutes = (data, parentPath = '') => {
10 | data.forEach(item => {
11 | let name = item.name
12 | item.path = item.path || `${parentPath}/${name}`
13 |
14 | if (item.children) {
15 | let path = `${parentPath}/${name}`
16 | if (name === 'home') {
17 | path = ''
18 | }
19 | parseRoutes(item.children, path)
20 | } else {
21 | item.meta = item.meta || {}
22 | item.meta.title = item.label || ''
23 | item.meta.code = item.meta.code || item.code
24 | codeMap[item.code] = item.path
25 | }
26 | })
27 | }
28 | const filterAsyncRouter = (data, filterPaths) => {
29 | return data.filter(route => {
30 | if (hasPermission(filterPaths, route)) {
31 | if (route.children) {
32 | route.children = filterAsyncRouter(route.children, filterPaths)
33 | }
34 |
35 | return true
36 | }
37 | return false
38 | })
39 | }
40 |
41 | const hasPermission = (paths, route) => {
42 | if (route.hidden) {
43 | return true
44 | }
45 | return paths.some(path => path.indexOf(route.path) > -1)
46 | }
47 |
48 | const accessedRoutePaths = (permissions, codeMap) => {
49 | let result = []
50 | permissions.forEach(code => {
51 | if (codeMap[code]) {
52 | result.push(codeMap[code])
53 | }
54 | })
55 | return result
56 | }
57 | const user = {
58 | state: {
59 | userName: wayeUserInfo ? wayeUserInfo.userName : '',
60 | userCode: wayeUserInfo ? wayeUserInfo.userCode : '',
61 | userId: wayeUserInfo ? wayeUserInfo.userId : '',
62 | permissions: wayeUserInfo ? wayeUserInfo.permissions : [],
63 | asyncRoutes: []
64 | },
65 |
66 | mutations: {
67 | setUserName (state, name) {
68 | state.userName = name
69 | },
70 |
71 | setUserCode (state, code) {
72 | state.userCode = code
73 | },
74 |
75 | setUserId (state, id) {
76 | state.userId = id
77 | },
78 |
79 | setPermissions (state, val) {
80 | state.permissions = val
81 | },
82 | setAsyncRoutes (state, list) {
83 | state.asyncRoutes = list
84 | }
85 | },
86 |
87 | actions: {
88 | login ({ commit, dispatch }, userInfo) {
89 | return login(userInfo)
90 | .then(data => {
91 | Vue.ls.set('userInfo', data)
92 | Vue.ls.set('unloginCount', 0)
93 | Vue.ls.set('userId', data.userId)
94 |
95 | commit('setUserName', data.userName)
96 | commit('setUserCode', data.userCode)
97 | commit('setUserId', data.userId)
98 | commit('setPermissions', data.permissions)
99 |
100 | return data
101 | })
102 | },
103 |
104 | genAsyncRoutes ({ commit, state }, permissions) {
105 | return new Promise(resolve => {
106 | let routes
107 | let routeData = cloneDeep(navConfig)
108 | parseRoutes(routeData)
109 | if (state.userCode === SUPER_ADMIN) {
110 | routes = routeData
111 | } else {
112 | let filterPaths = accessedRoutePaths(permissions, codeMap)
113 | routes = filterAsyncRouter(routeData, filterPaths)
114 | }
115 | commit('setAsyncRoutes', routes)
116 | resolve()
117 | })
118 | },
119 |
120 | logout ({ commit }) {
121 | return logout().then(() => {
122 | Vue.ls.remove('userInfo')
123 | Vue.ls.remove('unloginCount')
124 | commit('setUserName', '')
125 | commit('setUserCode', '')
126 | commit('setUserId', '')
127 | commit('setPermissions', '')
128 | commit('setAsyncRoutes', [])
129 | return true
130 | })
131 | }
132 | }
133 | }
134 |
135 | export default user
136 |
--------------------------------------------------------------------------------
/src/assets/scss/mixins/mixins.scss:
--------------------------------------------------------------------------------
1 | @import "function";
2 | @import "../common/var";
3 |
4 | /* Break-points
5 | -------------------------- */
6 | @mixin res($key, $map: $--breakpoints) {
7 | // 循环断点Map,如果存在则返回
8 | @if map-has-key($map, $key) {
9 | @media only screen and #{inspect(map-get($map, $key))} {
10 | @content;
11 | }
12 | } @else {
13 | @warn "Undefeined points: `#{$map}`";
14 | }
15 | }
16 |
17 | /* Scrollbar
18 | -------------------------- */
19 | @mixin scroll-bar {
20 | $--scrollbar-thumb-background: #b4bccc;
21 | $--scrollbar-track-background: #fff;
22 |
23 | &::-webkit-scrollbar {
24 | z-index: 11;
25 | width: 6px;
26 |
27 | &:horizontal {
28 | height: 6px;
29 | }
30 |
31 | &-thumb {
32 | border-radius: 5px;
33 | width: 6px;
34 | background: $--scrollbar-thumb-background;
35 | }
36 |
37 | &-corner {
38 | background: $--scrollbar-track-background;
39 | }
40 |
41 | &-track {
42 | background: $--scrollbar-track-background;
43 |
44 | &-piece {
45 | background: $--scrollbar-track-background;
46 | width: 6px;
47 | }
48 | }
49 | }
50 | }
51 |
52 | /* Placeholder
53 | -------------------------- */
54 | @mixin placeholder {
55 | &::-webkit-input-placeholder {
56 | @content
57 | }
58 |
59 | &::-moz-placeholder {
60 | @content
61 | }
62 |
63 | &:-ms-input-placeholder {
64 | @content
65 | }
66 | }
67 |
68 | /* BEM
69 | -------------------------- */
70 | @mixin b($block) {
71 | $B: $namespace+'-'+$block !global;
72 |
73 | .#{$B} {
74 | @content;
75 | }
76 | }
77 |
78 | @mixin e($element) {
79 | $E: $element !global;
80 | $selector: &;
81 | $currentSelector: "";
82 | @each $unit in $element {
83 | $currentSelector: #{$currentSelector + "." + $B + $element-separator + $unit + ","};
84 | }
85 |
86 | @if hitAllSpecialNestRule($selector) {
87 | @at-root {
88 | #{$selector} {
89 | #{$currentSelector} {
90 | @content;
91 | }
92 | }
93 | }
94 | } @else {
95 | @at-root {
96 | #{$currentSelector} {
97 | @content;
98 | }
99 | }
100 | }
101 | }
102 |
103 | @mixin m($modifier) {
104 | $selector: &;
105 | $currentSelector: "";
106 | @each $unit in $modifier {
107 | $currentSelector: #{$currentSelector + & + $modifier-separator + $unit + ","};
108 | }
109 |
110 | @at-root {
111 | #{$currentSelector} {
112 | @content;
113 | }
114 | }
115 | }
116 |
117 | @mixin configurable-m($modifier, $E-flag: false) {
118 | $selector: &;
119 | $interpolation: '';
120 |
121 | @if $E-flag {
122 | $interpolation: $element-separator + $E-flag;
123 | }
124 |
125 | @at-root {
126 | #{$selector} {
127 | .#{$B+$interpolation+$modifier-separator+$modifier} {
128 | @content;
129 | }
130 | }
131 | }
132 | }
133 |
134 | @mixin spec-selector($specSelector: '', $element: $E, $modifier: false, $block: $B) {
135 | $modifierCombo: '';
136 |
137 | @if $modifier {
138 | $modifierCombo: $modifier-separator + $modifier;
139 | }
140 |
141 | @at-root {
142 | #{&}#{$specSelector}.#{$block+$element-separator+$element+$modifierCombo} {
143 | @content
144 | }
145 | }
146 | }
147 |
148 | @mixin meb($modifier: false, $element: $E, $block: $B) {
149 | $selector: &;
150 | $modifierCombo: '';
151 |
152 | @if $modifier {
153 | $modifierCombo: $modifier-separator + $modifier;
154 | }
155 |
156 | @at-root {
157 | #{$selector} {
158 | .#{$block+$element-separator+$element+$modifierCombo} {
159 | @content
160 | }
161 | }
162 | }
163 | }
164 |
165 | @mixin when($state) {
166 | @at-root {
167 | &.#{$state-prefix + $state} {
168 | @content;
169 | }
170 | }
171 | }
172 |
173 | @mixin extend-rule($name) {
174 | @extend #{'%shared-'+$name};
175 | }
176 |
177 | @mixin share-rule($name) {
178 | $rule-name: '%shared-'+$name;
179 |
180 | @at-root #{$rule-name} {
181 | @content
182 | }
183 | }
184 |
185 | @mixin pseudo($pseudo) {
186 | @at-root #{&}#{':#{$pseudo}'} {
187 | @content
188 | }
189 | }
190 |
191 |
--------------------------------------------------------------------------------
/src/views/login.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Waye pro
5 |
6 |
24 |
25 |
28 |
29 |
30 |
31 |
101 |
167 |
--------------------------------------------------------------------------------
/src/utils/fetch.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios'
2 | import Vue from 'vue'
3 | import qs from 'qs'
4 | import { Message } from 'element-ui'
5 | import router from '../router'
6 | import { EventBus } from './event-bus'
7 | export const BASE_URL = process.env.VUE_APP_BASEURL
8 | const MSG_UNLOGIN = '登录超时,请重新登录'
9 | const MSG_ERROR = '系统异常,请联系客服'
10 | const goLogin = message => {
11 | message = message || MSG_UNLOGIN
12 | const count = Vue.ls.get('unloginCount') || 0
13 | // 多个请求触发 401 时,只提示及跳转一次
14 | if (count >= 1 || router.currentRoute.name === 'login') {
15 | return
16 | }
17 | EventBus.$emit('ql.logout.success')
18 | Vue.ls.set('unloginCount', count + 1)
19 | Message({
20 | message,
21 | type: 'error',
22 | duration: 5 * 1000
23 | })
24 | Vue.ls.remove('userInfo')
25 | router.push({
26 | path: '/login',
27 | query: { redirect: router.currentRoute.fullPath }
28 | })
29 | }
30 |
31 | axios.defaults.baseURL = BASE_URL
32 |
33 | axios.interceptors.request.use(config => {
34 | return config
35 | })
36 |
37 | // Add a response interceptor
38 | axios.interceptors.response.use(
39 | response => {
40 | let data = response.data
41 | let showMessage = response.config.headers.showMessage
42 | const status = +data.status
43 | if (status === -100) {
44 | goLogin()
45 | } else if (status === -1) {
46 | showMessage &&
47 | Message({
48 | message: data.msg,
49 | type: 'error',
50 | duration: 3000
51 | })
52 | return Promise.reject(data.msg)
53 | } else {
54 | let serverTime = data.serverTime
55 | let now = Date.now()
56 | if (serverTime) {
57 | Vue.ls.set('timeDiff', serverTime - now)
58 | }
59 | return data.data === undefined ? data : data.data
60 | }
61 | },
62 | error => {
63 | let message = error.response.data && error.response.data.msg
64 | if (error.response && error.response.status === 401) {
65 | goLogin(message || MSG_UNLOGIN)
66 | } else {
67 | let showMessage = error.response.config.headers.showMessage
68 | showMessage &&
69 | Message({
70 | message: message || MSG_ERROR,
71 | type: 'error',
72 | duration: 5 * 1000
73 | })
74 | }
75 | console.error(error)
76 | return Promise.reject(error)
77 | }
78 | )
79 |
80 | /**
81 | * 查询
82 | * @param {*} url 接口地址
83 | * @param {*} params 参数
84 | * @param {*} showMessage 显示出错提示
85 | */
86 | export function get (url, params = {}, showMessage = true) {
87 | if (typeof params === 'boolean') {
88 | showMessage = params
89 | params = {}
90 | }
91 | return axios({
92 | url,
93 | params,
94 | headers: { showMessage },
95 | method: 'get'
96 | })
97 | }
98 |
99 | /**
100 | * post 请求
101 | * @param {*} url 接口地址
102 | * @param {*} data json 数据
103 | * @param {*} showMessage 显示出错提示
104 | */
105 | export function post (url, data = {}, showMessage = true) {
106 | return axios({
107 | url,
108 | method: 'post',
109 | data,
110 | headers: { 'Content-Type': 'application/json', showMessage }
111 | })
112 | }
113 |
114 | /**
115 | * 用 formData 方式 post
116 | * @param {*} url 接口地址
117 | * @param {*} params json 数据
118 | * @param {*} showMessage 显示出错提示
119 | */
120 | export function postByForm (url, data = {}, showMessage = true) {
121 | return axios({
122 | url,
123 | method: 'post',
124 | data: qs.stringify(data),
125 | headers: {
126 | 'Content-Type': 'application/x-www-form-urlencoded',
127 | showMessage
128 | }
129 | })
130 | }
131 |
132 | /**
133 | * 获取文件地址,如 pdf, excel, text 下载地址
134 | * @param {*} path 路径
135 | * @param {*} params 查询参数
136 | */
137 | export function getFileUrl (path, params = {}) {
138 | let queryData = []
139 | let queryString = ''
140 | Object.keys(params).forEach(key => {
141 | queryData.push(`${key}=${params[key]}`)
142 | })
143 |
144 | if (queryData.length) {
145 | queryString = `?${queryData.join('&')}`
146 | }
147 | return `${BASE_URL}${path}${queryString}`
148 | }
149 |
150 | /**
151 | * put 请求
152 | * @param {*} url 接口地址
153 | * @param {*} data json 数据
154 | */
155 | export function put (url, data = {}, byJson = true) {
156 | return axios({
157 | url,
158 | method: 'put',
159 | data: byJson ? data : qs.stringify(data),
160 | headers: {
161 | showMessage: true,
162 | 'Content-Type': byJson
163 | ? 'application/json'
164 | : 'application/x-www-form-urlencoded'
165 | }
166 | })
167 | }
168 |
169 | /**
170 | * delete 请求
171 | * @param {*} url 接口地址
172 | * @param {*} data json 数据
173 | */
174 | export function deleteData (url, data = {}) {
175 | return axios({
176 | url,
177 | method: 'delete',
178 | data,
179 | headers: { 'Content-Type': 'application/json', showMessage: true }
180 | })
181 | }
182 |
--------------------------------------------------------------------------------
/src/utils/dom.js:
--------------------------------------------------------------------------------
1 | /* istanbul ignore next */
2 | // element-ui/lib/utils/dom.js
3 | import Vue from 'vue'
4 |
5 | const isServer = Vue.prototype.$isServer
6 | const SPECIAL_CHARS_REGEXP = /([\\:\\-\\_]+(.))/g
7 | const MOZ_HACK_REGEXP = /^moz([A-Z])/
8 | const ieVersion = isServer ? 0 : Number(document.documentMode)
9 |
10 | /* istanbul ignore next */
11 | const trim = function (string) {
12 | return (string || '').replace(/^[\s\uFEFF]+|[\s\uFEFF]+$/g, '')
13 | }
14 | /* istanbul ignore next */
15 | const camelCase = function (name) {
16 | return name.replace(SPECIAL_CHARS_REGEXP, function (_, separator, letter, offset) {
17 | return offset ? letter.toUpperCase() : letter
18 | }).replace(MOZ_HACK_REGEXP, 'Moz$1')
19 | }
20 |
21 | /* istanbul ignore next */
22 | export const on = (function () {
23 | if (!isServer && document.addEventListener) {
24 | return function (element, event, handler) {
25 | if (element && event && handler) {
26 | element.addEventListener(event, handler, false)
27 | }
28 | }
29 | } else {
30 | return function (element, event, handler) {
31 | if (element && event && handler) {
32 | element.attachEvent('on' + event, handler)
33 | }
34 | }
35 | }
36 | })()
37 |
38 | /* istanbul ignore next */
39 | export const off = (function () {
40 | if (!isServer && document.removeEventListener) {
41 | return function (element, event, handler) {
42 | if (element && event) {
43 | element.removeEventListener(event, handler, false)
44 | }
45 | }
46 | } else {
47 | return function (element, event, handler) {
48 | if (element && event) {
49 | element.detachEvent('on' + event, handler)
50 | }
51 | }
52 | }
53 | })()
54 |
55 | /* istanbul ignore next */
56 | export const once = function (el, event, fn) {
57 | var listener = function () {
58 | if (fn) {
59 | fn.apply(this, arguments)
60 | }
61 | off(el, event, listener)
62 | }
63 | on(el, event, listener)
64 | }
65 |
66 | /* istanbul ignore next */
67 | export function hasClass (el, cls) {
68 | if (!el || !cls) return false
69 | if (cls.indexOf(' ') !== -1) throw new Error('className should not contain space.')
70 | if (el.classList) {
71 | return el.classList.contains(cls)
72 | } else {
73 | return (' ' + el.className + ' ').indexOf(' ' + cls + ' ') > -1
74 | }
75 | }
76 |
77 | /* istanbul ignore next */
78 | export function addClass (el, cls) {
79 | if (!el) return
80 | var curClass = el.className
81 | var classes = (cls || '').split(' ')
82 |
83 | for (var i = 0, j = classes.length; i < j; i++) {
84 | var clsName = classes[i]
85 | if (!clsName) continue
86 |
87 | if (el.classList) {
88 | el.classList.add(clsName)
89 | } else {
90 | if (!hasClass(el, clsName)) {
91 | curClass += ' ' + clsName
92 | }
93 | }
94 | }
95 | if (!el.classList) {
96 | el.className = curClass
97 | }
98 | }
99 |
100 | /* istanbul ignore next */
101 | export function removeClass (el, cls) {
102 | if (!el || !cls) return
103 | var classes = cls.split(' ')
104 | var curClass = ' ' + el.className + ' '
105 |
106 | for (var i = 0, j = classes.length; i < j; i++) {
107 | var clsName = classes[i]
108 | if (!clsName) continue
109 |
110 | if (el.classList) {
111 | el.classList.remove(clsName)
112 | } else {
113 | if (hasClass(el, clsName)) {
114 | curClass = curClass.replace(' ' + clsName + ' ', ' ')
115 | }
116 | }
117 | }
118 | if (!el.classList) {
119 | el.className = trim(curClass)
120 | }
121 | }
122 |
123 | /* istanbul ignore next */
124 | export const getStyle = ieVersion < 9 ? function (element, styleName) {
125 | if (isServer) return
126 | if (!element || !styleName) return null
127 | styleName = camelCase(styleName)
128 | if (styleName === 'float') {
129 | styleName = 'styleFloat'
130 | }
131 | try {
132 | switch (styleName) {
133 | case 'opacity':
134 | try {
135 | return element.filters.item('alpha').opacity / 100
136 | } catch (e) {
137 | return 1.0
138 | }
139 | default:
140 | return (element.style[styleName] || element.currentStyle ? element.currentStyle[styleName] : null)
141 | }
142 | } catch (e) {
143 | return element.style[styleName]
144 | }
145 | } : function (element, styleName) {
146 | if (isServer) return
147 | if (!element || !styleName) return null
148 | styleName = camelCase(styleName)
149 | if (styleName === 'float') {
150 | styleName = 'cssFloat'
151 | }
152 | try {
153 | var computed = document.defaultView.getComputedStyle(element, '')
154 | return element.style[styleName] || computed ? computed[styleName] : null
155 | } catch (e) {
156 | return element.style[styleName]
157 | }
158 | }
159 |
160 | /* istanbul ignore next */
161 | export function setStyle (element, styleName, value) {
162 | if (!element || !styleName) return
163 |
164 | if (typeof styleName === 'object') {
165 | for (var prop in styleName) {
166 | if (styleName.hasOwnProperty(prop)) {
167 | setStyle(element, prop, styleName[prop])
168 | }
169 | }
170 | } else {
171 | styleName = camelCase(styleName)
172 | if (styleName === 'opacity' && ieVersion < 9) {
173 | element.style.filter = isNaN(value) ? '' : 'alpha(opacity=' + value * 100 + ')'
174 | } else {
175 | element.style[styleName] = value
176 | }
177 | }
178 | }
179 |
--------------------------------------------------------------------------------
/src/components/layouts/page-layout.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
12 | WAYE
13 | WAYE PRO
14 |
15 |
16 |
17 |
18 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
64 |
65 |
66 |
67 |
68 |
69 |
185 |
412 |
--------------------------------------------------------------------------------
/src/assets/scss/common/var.scss:
--------------------------------------------------------------------------------
1 | /* Element Chalk Variables */
2 |
3 | /* Transition
4 | -------------------------- */
5 | $--all-transition: all .3s cubic-bezier(.645,.045,.355,1) !default;
6 | $--fade-transition: opacity 300ms cubic-bezier(0.23, 1, 0.32, 1) !default;
7 | $--fade-linear-transition: opacity 200ms linear !default;
8 | $--md-fade-transition: transform 300ms cubic-bezier(0.23, 1, 0.32, 1), opacity 300ms cubic-bezier(0.23, 1, 0.32, 1) !default;
9 | $--border-transition-base: border-color .2s cubic-bezier(.645,.045,.355,1) !default;
10 | $--color-transition-base: color .2s cubic-bezier(.645,.045,.355,1) !default;
11 |
12 | /* Colors
13 | -------------------------- */
14 | $--color-white: #fff !default;
15 | $--color-black: #000 !default;
16 |
17 | $--color-primary: #409EFF !default;
18 | $--color-primary-light-1: mix($--color-white, $--color-primary, 10%) !default; /* #53a8ff */
19 | $--color-primary-light-2: mix($--color-white, $--color-primary, 20%) !default; /* #66b1ff */
20 | $--color-primary-light-3: mix($--color-white, $--color-primary, 30%) !default; /* #79bbff */
21 | $--color-primary-light-4: mix($--color-white, $--color-primary, 40%) !default; /* #8cc5ff */
22 | $--color-primary-light-5: mix($--color-white, $--color-primary, 50%) !default; /* #a0cfff */
23 | $--color-primary-light-6: mix($--color-white, $--color-primary, 60%) !default; /* #b3d8ff */
24 | $--color-primary-light-7: mix($--color-white, $--color-primary, 70%) !default; /* #c6e2ff */
25 | $--color-primary-light-8: mix($--color-white, $--color-primary, 80%) !default; /* #d9ecff */
26 | $--color-primary-light-9: mix($--color-white, $--color-primary, 90%) !default; /* #ecf5ff */
27 |
28 | $--color-success: #4CAF50 !default;
29 | $--color-warning: #FFC107 !default;
30 | $--color-danger: #FF5252 !default;
31 | $--color-info: #909399 !default;
32 |
33 | $--color-success-light: mix($--color-white, $--color-success, 80%) !default;
34 | $--color-warning-light: mix($--color-white, $--color-warning, 80%) !default;
35 | $--color-danger-light: mix($--color-white, $--color-danger, 80%) !default;
36 | $--color-info-light: mix($--color-white, $--color-info, 80%) !default;
37 |
38 | $--color-success-lighter: mix($--color-white, $--color-success, 90%) !default;
39 | $--color-warning-lighter: mix($--color-white, $--color-warning, 90%) !default;
40 | $--color-danger-lighter: mix($--color-white, $--color-danger, 90%) !default;
41 | $--color-info-lighter: mix($--color-white, $--color-info, 90%) !default;
42 |
43 | $--color-text-primary: #303133 !default;
44 | $--color-text-regular: #606266 !default;
45 | $--color-text-secondary: #909399 !default;
46 | $--color-text-placeholder: #c0c4cc !default;
47 |
48 | /* Link
49 | -------------------------- */
50 | $--link-color: $--color-primary-light-2 !default;
51 | $--link-hover-color: $--color-primary !default;
52 |
53 | /* Background
54 | -------------------------- */
55 | $--background-color-base: #f5f7fa !default;
56 |
57 | /* Border
58 | -------------------------- */
59 | $--border-width-base: 1px !default;
60 | $--border-style-base: solid !default;
61 | $--border-color-base: #dcdfe6 !default;
62 | $--border-color-light: #e4e7ed !default;
63 | $--border-color-lighter: #ebeef5 !default;
64 | $--border-color-extra-light: #f2f6fc !default;
65 | $--border-color-hover: $--color-text-placeholder !default;
66 | $--border-base: $--border-width-base $--border-style-base $--border-color-base !default;
67 | $--border-radius-base: 4px !default;
68 | $--border-radius-small: 2px !default;
69 | $--border-radius-circle: 100% !default;
70 |
71 | /* Box-shadow
72 | -------------------------- */
73 | $--box-shadow-base: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04) !default;
74 | $--box-shadow-dark: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .12) !default;
75 | $--box-shadow-light: 0 2px 12px 0 rgba(0, 0, 0, 0.1) !default;
76 | $--box-shadow-light-1: 0 2px 1px -1px rgba(0,0,0,.2),0 1px 1px 0 rgba(0,0,0,.14),0 1px 3px 0 rgba(0,0,0,.12)!default;
77 | /* Fill
78 | -------------------------- */
79 | $--fill-base: $--color-white !default;
80 |
81 | /* Font
82 | -------------------------- */
83 | $--font-path: 'fonts' !default;
84 | $--font-size-base: 14px !default;
85 | $--font-size-small: 13px !default;
86 | $--font-size-large: 18px !default;
87 | $--font-color-disabled-base: #bbb !default;
88 | $--font-weight-primary: 500 !default;
89 | $--font-line-height-primary: 24px !default;
90 |
91 | /* Size
92 | -------------------------- */
93 | $--size-base: 14px !default;
94 |
95 | /* z-index
96 | -------------------------- */
97 | $--index-normal: 1 !default;
98 | $--index-top: 1000 !default;
99 | $--index-popper: 2000 !default;
100 |
101 | /* Disable base
102 | -------------------------- */
103 | $--disabled-fill-base: $--background-color-base !default;
104 | $--disabled-color-base: $--color-text-placeholder !default;
105 | $--disabled-border-base: $--border-color-light !default;
106 |
107 | /* Icon
108 | -------------------------- */
109 | $--icon-color: #666 !default;
110 | $--icon-color-base: $--color-info !default;
111 |
112 | /* Checkbox
113 | -------------------------- */
114 | $--checkbox-font-size: 14px !default;
115 | $--checkbox-font-weight: $--font-weight-primary !default;
116 | $--checkbox-color: $--color-text-regular !default;
117 | $--checkbox-input-height: 14px !default;
118 | $--checkbox-input-width: 14px !default;
119 | $--checkbox-input-border-radius: $--border-radius-small !default;
120 | $--checkbox-input-fill: $--color-white !default;
121 | $--checkbox-input-border: $--border-base !default;
122 | $--checkbox-input-border-color: $--border-color-base !default;
123 | $--checkbox-icon-color: $--color-white !default;
124 |
125 | $--checkbox-disabled-input-border-color: $--border-color-base !default;
126 | $--checkbox-disabled-input-fill: #edf2fc !default;
127 | $--checkbox-disabled-icon-color: $--color-text-placeholder !default;
128 |
129 | $--checkbox-disabled-checked-input-fill: $--border-color-extra-light !default;
130 | $--checkbox-disabled-checked-input-border-color: $--border-color-base !default;
131 | $--checkbox-disabled-checked-icon-color: $--color-text-placeholder !default;
132 |
133 | $--checkbox-checked-text-color: $--color-primary !default;
134 | $--checkbox-checked-input-border-color: $--color-primary !default;
135 | $--checkbox-checked-input-fill: $--color-primary !default;
136 | $--checkbox-checked-icon-color: $--fill-base !default;
137 |
138 | $--checkbox-input-border-color-hover: $--color-primary !default;
139 |
140 | $--checkbox-bordered-height: 40px !default;
141 | $--checkbox-bordered-padding: 9px 20px 9px 10px !default;
142 | $--checkbox-bordered-medium-padding: 7px 20px 7px 10px !default;
143 | $--checkbox-bordered-small-padding: 5px 15px 5px 10px !default;
144 | $--checkbox-bordered-mini-padding: 3px 15px 3px 10px !default;
145 | $--checkbox-bordered-medium-input-height: 14px !default;
146 | $--checkbox-bordered-medium-input-width: 14px !default;
147 | $--checkbox-bordered-medium-height: 36px !default;
148 | $--checkbox-bordered-small-input-height: 12px !default;
149 | $--checkbox-bordered-small-input-width: 12px !default;
150 | $--checkbox-bordered-small-height: 32px !default;
151 | $--checkbox-bordered-mini-input-height: 12px !default;
152 | $--checkbox-bordered-mini-input-width: 12px !default;
153 | $--checkbox-bordered-mini-height: 28px !default;
154 |
155 | $--checkbox-button-font-size: $--font-size-base !default;
156 | $--checkbox-button-checked-fill: $--color-primary !default;
157 | $--checkbox-button-checked-color: $--color-white !default;
158 | $--checkbox-button-checked-border-color: $--color-primary !default;
159 |
160 |
161 |
162 | /* Radio
163 | -------------------------- */
164 | $--radio-font-size: 14px !default;
165 | $--radio-font-weight: $--font-weight-primary !default;
166 | $--radio-color: $--color-text-regular !default;
167 | $--radio-input-height: 14px !default;
168 | $--radio-input-width: 14px !default;
169 | $--radio-input-border-radius: $--border-radius-circle !default;
170 | $--radio-input-fill: $--color-white !default;
171 | $--radio-input-border: $--border-base !default;
172 | $--radio-input-border-color: $--border-color-base !default;
173 | $--radio-icon-color: $--color-white !default;
174 |
175 | $--radio-disabled-input-border-color: $--disabled-border-base !default;
176 | $--radio-disabled-input-fill: $--disabled-fill-base !default;
177 | $--radio-disabled-icon-color: $--disabled-fill-base !default;
178 |
179 | $--radio-disabled-checked-input-border-color: $--disabled-border-base !default;
180 | $--radio-disabled-checked-input-fill: $--disabled-fill-base !default;
181 | $--radio-disabled-checked-icon-color: $--color-text-placeholder !default;
182 |
183 | $--radio-checked-text-color: $--color-primary !default;
184 | $--radio-checked-input-border-color: $--color-primary !default;
185 | $--radio-checked-input-fill: $--color-white !default;
186 | $--radio-checked-icon-color: $--color-primary !default;
187 |
188 | $--radio-input-border-color-hover: $--color-primary !default;
189 |
190 | $--radio-bordered-height: 40px !default;
191 | $--radio-bordered-padding: 12px 20px 0 10px !default;
192 | $--radio-bordered-medium-padding: 10px 20px 0 10px !default;
193 | $--radio-bordered-small-padding: 8px 15px 0 10px !default;
194 | $--radio-bordered-mini-padding: 6px 15px 0 10px !default;
195 | $--radio-bordered-medium-input-height: 14px !default;
196 | $--radio-bordered-medium-input-width: 14px !default;
197 | $--radio-bordered-medium-height: 36px !default;
198 | $--radio-bordered-small-input-height: 12px !default;
199 | $--radio-bordered-small-input-width: 12px !default;
200 | $--radio-bordered-small-height: 32px !default;
201 | $--radio-bordered-mini-input-height: 12px !default;
202 | $--radio-bordered-mini-input-width: 12px !default;
203 | $--radio-bordered-mini-height: 28px !default;
204 |
205 | $--radio-button-font-size: $--font-size-base !default;
206 | $--radio-button-checked-fill: $--color-primary !default;
207 | $--radio-button-checked-color: $--color-white !default;
208 | $--radio-button-checked-border-color: $--color-primary !default;
209 | $--radio-button-disabled-checked-fill: $--border-color-extra-light !default;
210 |
211 | /* Select
212 | -------------------------- */
213 | $--select-border-color-hover: $--border-color-hover !default;
214 | $--select-disabled-border: $--disabled-border-base !default;
215 | $--select-font-size: $--font-size-base !default;
216 | $--select-close-hover-color: $--color-text-secondary !default;
217 |
218 | $--select-input-color: $--color-text-placeholder !default;
219 | $--select-multiple-input-color: #666 !default;
220 | $--select-input-focus-background: $--color-primary !default;
221 | $--select-input-font-size: 14px !default;
222 |
223 | $--select-option-color: $--color-text-regular !default;
224 | $--select-option-disabled-color: $--color-text-placeholder !default;
225 | $--select-option-disabled-background: $--color-white !default;
226 | $--select-option-height: 34px !default;
227 | $--select-option-hover-background: $--background-color-base !default;
228 | $--select-option-selected: $--color-primary !default;
229 | $--select-option-selected-hover: $--background-color-base !default;
230 |
231 | $--select-group-color: $--color-info !default;
232 | $--select-group-height: 30px !default;
233 | $--select-group-font-size: 12px !default;
234 |
235 | $--select-dropdown-background: $--color-white !default;
236 | $--select-dropdown-shadow: $--box-shadow-light !default;
237 | $--select-dropdown-empty-color: #999 !default;
238 | $--select-dropdown-max-height: 274px !default;
239 | $--select-dropdown-padding: 6px 0 !default;
240 | $--select-dropdown-empty-padding: 10px 0 !default;
241 | $--select-dropdown-border: solid 1px $--border-color-light !default;
242 |
243 | /* Alert
244 | -------------------------- */
245 | $--alert-padding: 8px 16px !default;
246 | $--alert-border-radius: $--border-radius-base !default;
247 | $--alert-title-font-size: 13px !default;
248 | $--alert-description-font-size: 12px !default;
249 | $--alert-close-font-size: 12px !default;
250 | $--alert-close-customed-font-size: 13px !default;
251 |
252 | $--alert-success-color: $--color-success-lighter !default;
253 | $--alert-info-color: $--color-info-lighter !default;
254 | $--alert-warning-color: $--color-warning-lighter !default;
255 | $--alert-danger-color: $--color-danger-lighter !default;
256 |
257 | $--alert-icon-size: 16px !default;
258 | $--alert-icon-large-size: 28px !default;
259 |
260 | /* Message Box
261 | -------------------------- */
262 | $--msgbox-width: 420px !default;
263 | $--msgbox-border-radius: 4px !default;
264 | $--msgbox-font-size: $--font-size-large !default;
265 | $--msgbox-content-font-size: $--font-size-base !default;
266 | $--msgbox-content-color: $--color-text-regular !default;
267 | $--msgbox-error-font-size: 12px !default;
268 | $--msgbox-padding-primary: 15px !default;
269 |
270 | $--msgbox-success-color: $--color-success !default;
271 | $--msgbox-info-color: $--color-info !default;
272 | $--msgbox-warning-color: $--color-warning !default;
273 | $--msgbox-danger-color: $--color-danger !default;
274 |
275 | /* Message
276 | -------------------------- */
277 | $--message-shadow: $--box-shadow-base !default;
278 | $--message-min-width: 380px !default;
279 | $--message-background-color: #edf2fc !default;
280 | $--message-padding: 15px 15px 15px 20px !default;
281 | $--message-content-color: $--color-text-regular !default;
282 | $--message-close-color: $--color-text-placeholder !default;
283 | $--message-close-size: 16px !default;
284 | $--message-close-hover-color: $--color-text-secondary !default;
285 |
286 | $--message-success-color: $--color-success !default;
287 | $--message-info-color: $--color-info !default;
288 | $--message-warning-color: $--color-warning !default;
289 | $--message-danger-color: $--color-danger !default;
290 |
291 | /* Notification
292 | -------------------------- */
293 | $--notification-width: 330px !default;
294 | $--notification-padding: 14px 26px 14px 13px !default;
295 | $--notification-radius: 8px !default;
296 | $--notification-shadow: $--box-shadow-light !default;
297 | $--notification-border-color: $--border-color-lighter !default;
298 | $--notification-icon-size: 24px !default;
299 | $--notification-close-font-size: $--message-close-size !default;
300 | $--notification-group-margin: 13px !default;
301 | $--notification-font-size: $--font-size-base !default;
302 | $--notification-color: $--color-text-regular !default;
303 | $--notification-title-font-size: 16px !default;
304 | $--notification-title-color: $--color-text-primary !default;
305 |
306 | $--notification-close-color: $--color-text-secondary !default;
307 | $--notification-close-hover-color: $--color-text-regular !default;
308 |
309 | $--notification-success-color: $--color-success !default;
310 | $--notification-info-color: $--color-info !default;
311 | $--notification-warning-color: $--color-warning !default;
312 | $--notification-danger-color: $--color-danger !default;
313 |
314 | /* Input
315 | -------------------------- */
316 | $--input-font-size: $--font-size-base !default;
317 | $--input-color: $--color-text-regular !default;
318 | $--input-width: 140px !default;
319 | $--input-height: 40px !default;
320 | $--input-border: $--border-base !default;
321 | $--input-border-color: $--border-color-base !default;
322 | $--input-border-radius: $--border-radius-base !default;
323 | $--input-border-color-hover: $--border-color-hover !default;
324 | $--input-fill: $--color-white !default;
325 | $--input-fill-disabled: $--disabled-fill-base !default;
326 | $--input-color-disabled: $--font-color-disabled-base !default;
327 | $--input-icon-color: $--color-text-placeholder !default;
328 | $--input-placeholder-color: $--color-text-placeholder !default;
329 | $--input-max-width: 314px !default;
330 |
331 | $--input-hover-border: $--border-color-hover !default;
332 | $--input-clear-hover-color: $--color-text-secondary !default;
333 |
334 | $--input-focus-border: $--color-primary !default;
335 | $--input-focus-fill: $--color-white !default;
336 |
337 | $--input-disabled-fill: $--disabled-fill-base !default;
338 | $--input-disabled-border: $--disabled-border-base !default;
339 | $--input-disabled-color: $--disabled-color-base !default;
340 | $--input-disabled-placeholder-color: $--color-text-placeholder !default;
341 |
342 | $--input-medium-font-size: 14px !default;
343 | $--input-medium-height: 36px !default;
344 |
345 | $--input-small-font-size: 13px !default;
346 | $--input-small-height: 32px !default;
347 |
348 | $--input-mini-font-size: 12px !default;
349 | $--input-mini-height: 28px !default;
350 |
351 | /* Cascader
352 | -------------------------- */
353 | $--cascader-menu-fill: $--fill-base !default;
354 | $--cascader-menu-font-size: $--font-size-base !default;
355 | $--cascader-menu-radius: $--border-radius-base !default;
356 | $--cascader-menu-border: $--border-base !default;
357 | $--cascader-menu-border-color: $--border-color-base !default;
358 | $--cascader-menu-border-width: $--border-width-base !default;
359 | $--cascader-menu-color: $--color-text-regular !default;
360 | $--cascader-menu-option-color-active: $--color-text-secondary !default;
361 | $--cascader-menu-option-fill-active: rgba($--color-text-secondary, 0.12) !default;
362 | $--cascader-menu-option-color-hover: $--color-text-regular !default;
363 | $--cascader-menu-option-fill-hover: rgba($--color-text-primary, 0.06) !default;
364 | $--cascader-menu-option-color-disabled: #999 !default;
365 | $--cascader-menu-option-fill-disabled: rgba($--color-black, 0.06) !default;
366 | $--cascader-menu-option-empty-color: #666 !default;
367 | $--cascader-menu-group-color: #999 !default;
368 | $--cascader-menu-shadow: 0 1px 2px rgba($--color-black, 0.14), 0 0 3px rgba($--color-black, 0.14) !default;
369 | $--cascader-menu-option-pinyin-color: #999 !default;
370 | $--cascader-menu-submenu-shadow: 1px 1px 2px rgba($--color-black, 0.14), 1px 0 2px rgba($--color-black, 0.14) !default;
371 |
372 | /* Group
373 | -------------------------- */
374 | $--group-option-flex: 0 0 (1/5) * 100% !default;
375 | $--group-option-offset-bottom: 12px !default;
376 | $--group-option-fill-hover: rgba($--color-black, 0.06) !default;
377 | $--group-title-color: $--color-black !default;
378 | $--group-title-font-size: $--font-size-base !default;
379 | $--group-title-width: 66px !default;
380 |
381 | /* Tab
382 | -------------------------- */
383 | $--tab-font-size: $--font-size-base !default;
384 | $--tab-border-line: 1px solid #e4e4e4 !default;
385 | $--tab-header-color-active: $--color-text-secondary !default;
386 | $--tab-header-color-hover: $--color-text-regular !default;
387 | $--tab-header-color: $--color-text-regular !default;
388 | $--tab-header-fill-active: rgba($--color-black, 0.06) !default;
389 | $--tab-header-fill-hover: rgba($--color-black, 0.06) !default;
390 | $--tab-vertical-header-width: 90px !default;
391 | $--tab-vertical-header-count-color: $--color-white !default;
392 | $--tab-vertical-header-count-fill: $--color-text-secondary !default;
393 |
394 | /* Button
395 | -------------------------- */
396 | $--button-font-size: 14px !default;
397 | $--button-font-weight: $--font-weight-primary !default;
398 | $--button-border-radius: $--border-radius-base !default;
399 | $--button-padding-vertical: 12px !default;
400 | $--button-padding-horizontal: 20px !default;
401 |
402 | $--button-medium-font-size: 14px !default;
403 | $--button-medium-border-radius: $--border-radius-base !default;
404 | $--button-medium-padding-vertical: 10px !default;
405 | $--button-medium-padding-horizontal: 20px !default;
406 |
407 | $--button-small-font-size: 12px !default;
408 | $--button-small-border-radius: #{$--border-radius-base - 1} !default;
409 | $--button-small-padding-vertical: 9px !default;
410 | $--button-small-padding-horizontal: 15px !default;
411 |
412 | $--button-mini-font-size: 12px !default;
413 | $--button-mini-border-radius: #{$--border-radius-base - 1} !default;
414 | $--button-mini-padding-vertical: 7px !default;
415 | $--button-mini-padding-horizontal: 15px !default;
416 |
417 | $--button-default-color: $--color-text-regular !default;
418 | $--button-default-fill: $--color-white !default;
419 | $--button-default-border: $--border-color-base !default;
420 |
421 | $--button-disabled-color: $--color-text-placeholder !default;
422 | $--button-disabled-fill: $--color-white !default;
423 | $--button-disabled-border: $--border-color-lighter !default;
424 |
425 | $--button-primary-border: $--color-primary !default;
426 | $--button-primary-color: $--color-white !default;
427 | $--button-primary-fill: $--color-primary !default;
428 |
429 | $--button-success-border: $--color-success !default;
430 | $--button-success-color: $--color-white !default;
431 | $--button-success-fill: $--color-success !default;
432 |
433 | $--button-warning-border: $--color-warning !default;
434 | $--button-warning-color: $--color-white !default;
435 | $--button-warning-fill: $--color-warning !default;
436 |
437 | $--button-danger-border: $--color-danger !default;
438 | $--button-danger-color: $--color-white !default;
439 | $--button-danger-fill: $--color-danger !default;
440 |
441 | $--button-info-border: $--color-info !default;
442 | $--button-info-color: $--color-white !default;
443 | $--button-info-fill: $--color-info !default;
444 |
445 | $--button-hover-tint-percent: 20% !default;
446 | $--button-active-shade-percent: 10% !default;
447 |
448 |
449 | /* cascader
450 | -------------------------- */
451 | $--cascader-height: 200px !default;
452 |
453 | /* Switch
454 | -------------------------- */
455 | $--switch-on-color: $--color-primary !default;
456 | $--switch-off-color: $--border-color-base !default;
457 | $--switch-disabled-color: $--border-color-lighter !default;
458 | $--switch-disabled-text-color: $--color-text-placeholder !default;
459 |
460 | $--switch-font-size: $--font-size-base !default;
461 | $--switch-core-border-radius: 10px !default;
462 | $--switch-width: 40px !default;
463 | $--switch-height: 20px !default;
464 | $--switch-button-size: 16px !default;
465 |
466 | /* Dialog
467 | -------------------------- */
468 | $--dialog-background-color: $--color-primary-light-4 !default;
469 | $--dialog-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3) !default;
470 | $--dialog-close-hover-color: $--color-primary !default;
471 | $--dialog-title-font-size: $--font-size-large !default;
472 | $--dialog-font-size: 14px !default;
473 | $--dialog-line-height: $--font-line-height-primary !default;
474 | $--dialog-padding-primary: 20px !default;
475 |
476 | /* Table
477 | -------------------------- */
478 | $--table-border-color: $--border-color-lighter !default;
479 | $--table-border: 1px solid $--table-border-color !default;
480 | $--table-text-color: $--color-text-regular !default;
481 | $--table-header-color: $--color-white !default;
482 | $--table-row-hover-background: #f0fcff !default;
483 | $--table-current-row-background: $--color-primary-light-9 !default;
484 | $--table-header-background: #80d8ff !default;
485 | $--table-footer-background: $--color-text-placeholder !default;
486 | $--table-fixed-box-shadow: 0 0 10px rgba(0, 0, 0, .12) !default;
487 |
488 | /* Pagination
489 | -------------------------- */
490 | $--pagination-font-size: 13px !default;
491 | $--pagination-fill: $--color-white !default;
492 | $--pagination-color: $--color-text-primary !default;
493 | $--pagination-border-radius: 3px !default;
494 | $--pagination-button-color: $--color-text-primary !default;
495 | $--pagination-button-width: 35.5px !default;
496 | $--pagination-button-height: 28px !default;
497 | $--pagination-button-disabled-color: $--color-text-placeholder !default;
498 | $--pagination-button-disabled-fill: $--color-white !default;
499 | $--pagination-hover-fill: $--color-primary !default;
500 | $--pagination-hover-color: $--color-white !default;
501 |
502 | /* Popover
503 | -------------------------- */
504 | $--popover-fill: $--color-white !default;
505 | $--popover-font-size: $--font-size-base !default;
506 | $--popover-border-color: $--border-color-lighter !default;
507 | $--popover-arrow-size: 6px !default;
508 | $--popover-padding: 12px !default;
509 | $--popover-padding-large: 18px 20px !default;
510 | $--popover-title-font-size: 16px !default;
511 | $--popover-title-color: $--color-text-primary !default;
512 |
513 | /* Tooltip
514 | -------------------------- */
515 | $--tooltip-fill: $--color-text-primary !default;
516 | $--tooltip-color: $--color-white !default;
517 | $--tooltip-font-size: 12px !default;
518 | $--tooltip-border-color: $--color-text-primary !default;
519 | $--tooltip-arrow-size: 6px !default;
520 | $--tooltip-padding: 10px !default;
521 |
522 | /* Tag
523 | -------------------------- */
524 | $--tag-padding: 0 10px !default;
525 | $--tag-fill: rgba($--color-primary, 0.10) !default;
526 | $--tag-color: $--color-primary !default;
527 | $--tag-border: rgba($--color-primary, 0.20) !default;
528 | $--tag-font-size: 12px !default;
529 | $--tag-border-radius: 4px !default;
530 |
531 | $--tag-info-fill: rgba($--color-info, 0.10) !default;
532 | $--tag-info-border: rgba($--color-info, 0.20) !default;
533 | $--tag-info-color: $--color-info !default;
534 |
535 | $--tag-primary-fill: rgba($--color-primary, 0.10) !default;
536 | $--tag-primary-border: rgba($--color-primary, 0.20) !default;
537 | $--tag-primary-color: $--color-primary !default;
538 |
539 | $--tag-success-fill: rgba($--color-success, 0.10) !default;
540 | $--tag-success-border: rgba($--color-success, 0.20) !default;
541 | $--tag-success-color: $--color-success !default;
542 |
543 | $--tag-warning-fill: rgba($--color-warning, 0.10) !default;
544 | $--tag-warning-border: rgba($--color-warning, 0.20) !default;
545 | $--tag-warning-color: $--color-warning !default;
546 |
547 | $--tag-danger-fill: rgba($--color-danger, 0.10) !default;
548 | $--tag-danger-border: rgba($--color-danger, 0.20) !default;
549 | $--tag-danger-color: $--color-danger !default;
550 |
551 | /* Tree
552 | -------------------------- */
553 | $--tree-node-hover-color: $--background-color-base !default;
554 | $--tree-text-color: $--color-text-regular !default;
555 | $--tree-expand-icon-color: $--color-text-placeholder !default;
556 |
557 | /* Dropdown
558 | -------------------------- */
559 | $--dropdown-menu-box-shadow: $--box-shadow-light !default;
560 | $--dropdown-menuItem-hover-fill: $--color-primary-light-9 !default;
561 | $--dropdown-menuItem-hover-color: $--link-color !default;
562 |
563 | /* Badge
564 | -------------------------- */
565 | $--badge-fill: $--color-danger !default;
566 | $--badge-radius: 10px !default;
567 | $--badge-font-size: 12px !default;
568 | $--badge-padding: 6px !default;
569 | $--badge-size: 18px !default;
570 |
571 | /* Card
572 | --------------------------*/
573 | $--card-border-color: $--border-color-lighter !default;
574 | $--card-border-radius: 4px !default;
575 | $--card-padding: 20px !default;
576 |
577 | /* Slider
578 | --------------------------*/
579 | $--slider-main-background-color: $--color-primary !default;
580 | $--slider-runway-background-color: $--border-color-light !default;
581 | $--slider-button-hover-color: mix($--color-primary, black, 97%) !default;
582 | $--slider-stop-background-color: $--color-white !default;
583 | $--slider-disable-color: $--color-text-placeholder !default;
584 |
585 | $--slider-margin: 16px 0 !default;
586 | $--slider-border-radius: 3px !default;
587 | $--slider-height: 6px !default;
588 | $--slider-button-size: 16px !default;
589 | $--slider-button-wrapper-size: 36px !default;
590 | $--slider-button-wrapper-offset: -15px !default;
591 |
592 | /* Steps
593 | --------------------------*/
594 | $--steps-border-color: $--disabled-border-base !default;
595 | $--steps-border-radius: 4px !default;
596 | $--steps-padding: 20px !default;
597 |
598 | /* Menu
599 | --------------------------*/
600 | $--menu-item-color: $--color-text-primary !default;
601 | $--menu-item-fill: $--color-white !default;
602 | $--menu-item-hover-fill: $--color-primary-light-9 !default;
603 |
604 | /* Rate
605 | --------------------------*/
606 | $--rate-height: 20px !default;
607 | $--rate-font-size: $--font-size-base !default;
608 | $--rate-icon-size: 18px !default;
609 | $--rate-icon-margin: 6px !default;
610 | $--rate-icon-color: $--color-text-placeholder !default;
611 |
612 | /* DatePicker
613 | --------------------------*/
614 | $--datepicker-color: $--color-text-regular !default;
615 | $--datepicker-off-color: $--color-text-placeholder !default;
616 | $--datepicker-header-color: $--color-text-regular !default;
617 | $--datepicker-icon-color: $--color-text-primary !default;
618 | $--datepicker-border-color: $--disabled-border-base !default;
619 | $--datepicker-inner-border-color: #e4e4e4 !default;
620 | $--datepicker-inrange-color: $--border-color-extra-light !default;
621 | $--datepicker-inrange-hover-color: $--border-color-extra-light !default;
622 | $--datepicker-active-color: $--color-primary !default;
623 | $--datepicker-text-hover-color: $--color-primary !default;
624 | $--datepicker-cell-hover-color: #fff !default;
625 |
626 | /* Loading
627 | --------------------------*/
628 | $--loading-spinner-size: 42px !default;
629 | $--loading-fullscreen-spinner-size: 50px !default;
630 |
631 | /* Scrollbar
632 | --------------------------*/
633 | $--scrollbar-background-color: rgba($--color-text-secondary, .3) !default;
634 | $--scrollbar-hover-background-color: rgba($--color-text-secondary, .5) !default;
635 |
636 | /* Carousel
637 | --------------------------*/
638 | $--carousel-arrow-font-size: 12px !default;
639 | $--carousel-arrow-size: 36px !default;
640 | $--carousel-arrow-background: rgba(31, 45, 61, 0.11) !default;
641 | $--carousel-arrow-hover-background: rgba(31, 45, 61, 0.23) !default;
642 | $--carousel-indicator-width: 30px !default;
643 | $--carousel-indicator-height: 2px !default;
644 | $--carousel-indicator-padding-horizontal: 4px !default;
645 | $--carousel-indicator-padding-vertical: 12px !default;
646 | $--carousel-indicator-out-color: $--border-color-hover !default;
647 |
648 | /* Collapse
649 | --------------------------*/
650 | $--collapse-border-color: $--border-color-lighter !default;
651 | $--collapse-header-height: 48px !default;
652 | $--collapse-header-padding: 20px !default;
653 | $--collapse-header-fill: $--color-white !default;
654 | $--collapse-header-color: $--color-text-primary !default;
655 | $--collapse-header-size: 13px !default;
656 | $--collapse-content-fill: $--color-white !default;
657 | $--collapse-content-size: 13px !default;
658 | $--collapse-content-color: $--color-text-primary !default;
659 |
660 | /* Transfer
661 | --------------------------*/
662 | $--transfer-border-color: $--border-color-lighter !default;
663 | $--transfer-border-radius: $--border-radius-base !default;
664 | $--transfer-panel-width: 200px !default;
665 | $--transfer-panel-header-height: 40px !default;
666 | $--transfer-panel-header-background: $--background-color-base !default;
667 | $--transfer-panel-footer-height: 40px !default;
668 | $--transfer-panel-body-height: 246px !default;
669 | $--transfer-item-height: 30px !default;
670 | $--transfer-item-hover-background: $--color-text-secondary !default;
671 | $--transfer-filter-height: 32px !default;
672 |
673 | /* Header
674 | --------------------------*/
675 | $--header-padding: 0 20px !default;
676 |
677 | /* Footer
678 | --------------------------*/
679 | $--footer-padding: 0 20px !default;
680 |
681 | /* Main
682 | --------------------------*/
683 | $--main-padding: 20px !default;
684 |
685 | /* Break-point
686 | --------------------------*/
687 | $--sm: 768px !default;
688 | $--md: 992px !default;
689 | $--lg: 1200px !default;
690 | $--xl: 1920px !default;
691 |
692 | $--breakpoints: (
693 | 'xs' : (max-width: $--sm),
694 | 'sm' : (min-width: $--sm),
695 | 'md' : (min-width: $--md),
696 | 'lg' : (min-width: $--lg),
697 | 'xl' : (min-width: $--xl)
698 | );
699 |
700 | $--breakpoints-spec: (
701 | 'xs-only' : (max-width: $--sm - 1),
702 | 'sm-and-up' : (min-width: $--sm),
703 | 'sm-only': "(min-width: #{$--sm}) and (max-width: #{$--md} - 1)",
704 | 'sm-and-down': (max-width: $--md - 1),
705 | 'md-and-up' : (min-width: $--md),
706 | 'md-only': "(min-width: #{$--md}) and (max-width: #{$--lg } - 1)",
707 | 'md-and-down': (max-width: $--lg - 1),
708 | 'lg-and-up' : (min-width: $--lg),
709 | 'lg-only': "(min-width: #{$--lg}) and (max-width: #{$--xl } - 1)",
710 | 'lg-and-down': (max-width: $--xl - 1),
711 | 'xl-only' : (min-width: $--xl),
712 | );
713 | $--header-height: 60px;
714 |
--------------------------------------------------------------------------------