Commit a795fa7b14f6cb93eb6b5c2a8da425ed8ca6625d
1 parent
cf56a6c30f
Exists in
master
auto commit the code by alias command
Showing
13 changed files
with
59 additions
and
24 deletions
Show diff stats
.gitignore
1 | .DS_Store | 1 | .DS_Store |
2 | node_modules/ | 2 | node_modules/ |
3 | dist/ | 3 | dist/ |
4 | npm-debug.log* | 4 | npm-debug.log* |
5 | yarn-debug.log* | 5 | yarn-debug.log* |
6 | yarn-error.log* | 6 | yarn-error.log* |
7 | package-lock.json | 7 | package-lock.json |
8 | tests/**/coverage/ | 8 | tests/**/coverage/ |
9 | 9 | ||
10 | # Editor directories and files | 10 | # Editor directories and files |
11 | .idea | 11 | .idea |
12 | .vscode | 12 | .vscode |
13 | *.suo | 13 | *.suo |
14 | *.ntvs* | 14 | *.ntvs* |
15 | *.njsproj | 15 | *.njsproj |
16 | *.sln | 16 | *.sln |
17 | yarn.lock |
package.json
1 | { | 1 | { |
2 | "name": "vue-admin-template", | 2 | "name": "yp-plan", |
3 | "version": "4.2.1", | 3 | "version": "4.2.1", |
4 | "description": "A vue admin template with Element UI & axios & iconfont & permission control & lint", | 4 | "description": "A vue admin template with Element UI & axios & iconfont & permission control & lint", |
5 | "author": "Pan <panfree23@gmail.com>", | 5 | "author": "XYT==admin@xiuyetang.com", |
6 | "license": "MIT", | 6 | "license": "MIT", |
7 | "scripts": { | 7 | "scripts": { |
8 | "dev": "vue-cli-service serve", | 8 | "dev": "vue-cli-service serve", |
9 | "build:prod": "vue-cli-service build", | 9 | "build:prod": "vue-cli-service build", |
10 | "build:stage": "vue-cli-service build --mode staging", | 10 | "build:stage": "vue-cli-service build --mode staging", |
11 | "preview": "node build/index.js --preview", | 11 | "preview": "node build/index.js --preview", |
12 | "lint": "eslint --ext .js,.vue src", | 12 | "lint": "eslint --ext .js,.vue src", |
13 | "test:unit": "jest --clearCache && vue-cli-service test:unit", | 13 | "test:unit": "jest --clearCache && vue-cli-service test:unit", |
14 | "test:ci": "npm run lint && npm run test:unit", | 14 | "test:ci": "npm run lint && npm run test:unit", |
15 | "svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml" | 15 | "svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml" |
16 | }, | 16 | }, |
17 | "dependencies": { | 17 | "dependencies": { |
18 | "axios": "0.18.1", | 18 | "axios": "0.18.1", |
19 | "echarts": "^4.7.0", | ||
19 | "element-ui": "2.13.0", | 20 | "element-ui": "2.13.0", |
20 | "js-cookie": "2.2.0", | 21 | "js-cookie": "2.2.0", |
21 | "normalize.css": "7.0.0", | 22 | "normalize.css": "7.0.0", |
22 | "nprogress": "0.2.0", | 23 | "nprogress": "0.2.0", |
23 | "path-to-regexp": "2.4.0", | 24 | "path-to-regexp": "2.4.0", |
25 | "plop": "^2.6.0", | ||
24 | "vue": "2.6.10", | 26 | "vue": "2.6.10", |
25 | "vue-router": "3.0.6", | 27 | "vue-router": "3.0.6", |
26 | "vuex": "3.1.0" | 28 | "vuex": "3.1.0" |
27 | }, | 29 | }, |
28 | "devDependencies": { | 30 | "devDependencies": { |
29 | "@babel/core": "7.0.0", | 31 | "@babel/core": "7.0.0", |
30 | "@babel/register": "7.0.0", | 32 | "@babel/register": "7.0.0", |
31 | "@vue/cli-plugin-babel": "3.6.0", | 33 | "@vue/cli-plugin-babel": "3.6.0", |
32 | "@vue/cli-plugin-eslint": "^3.9.1", | 34 | "@vue/cli-plugin-eslint": "^3.9.1", |
33 | "@vue/cli-plugin-unit-jest": "3.6.3", | 35 | "@vue/cli-plugin-unit-jest": "3.6.3", |
34 | "@vue/cli-service": "3.6.0", | 36 | "@vue/cli-service": "3.6.0", |
35 | "@vue/test-utils": "1.0.0-beta.29", | 37 | "@vue/test-utils": "1.0.0-beta.29", |
36 | "autoprefixer": "^9.5.1", | 38 | "autoprefixer": "^9.5.1", |
37 | "babel-core": "7.0.0-bridge.0", | 39 | "babel-core": "7.0.0-bridge.0", |
38 | "babel-eslint": "10.0.1", | 40 | "babel-eslint": "10.0.1", |
39 | "babel-jest": "23.6.0", | 41 | "babel-jest": "23.6.0", |
40 | "chalk": "2.4.2", | 42 | "chalk": "2.4.2", |
41 | "connect": "3.6.6", | 43 | "connect": "3.6.6", |
42 | "eslint": "5.15.3", | 44 | "eslint": "5.15.3", |
43 | "eslint-plugin-vue": "5.2.2", | 45 | "eslint-plugin-vue": "5.2.2", |
44 | "html-webpack-plugin": "3.2.0", | 46 | "html-webpack-plugin": "3.2.0", |
45 | "mockjs": "1.0.1-beta3", | 47 | "mockjs": "1.0.1-beta3", |
46 | "node-sass": "^4.9.0", | 48 | "node-sass": "^4.9.0", |
47 | "runjs": "^4.3.2", | 49 | "runjs": "^4.3.2", |
48 | "sass-loader": "^7.1.0", | 50 | "sass-loader": "^7.1.0", |
49 | "script-ext-html-webpack-plugin": "2.1.3", | 51 | "script-ext-html-webpack-plugin": "2.1.3", |
50 | "script-loader": "0.7.2", | 52 | "script-loader": "0.7.2", |
51 | "serve-static": "^1.13.2", | 53 | "serve-static": "^1.13.2", |
52 | "svg-sprite-loader": "4.1.3", | 54 | "svg-sprite-loader": "4.1.3", |
53 | "svgo": "1.2.2", | 55 | "svgo": "1.2.2", |
54 | "vue-template-compiler": "2.6.10" | 56 | "vue-template-compiler": "2.6.10" |
55 | }, | 57 | }, |
56 | "engines": { | 58 | "engines": { |
57 | "node": ">=8.9", | 59 | "node": ">=8.9", |
58 | "npm": ">= 3.0.0" | 60 | "npm": ">= 3.0.0" |
59 | }, | 61 | }, |
60 | "browserslist": [ | 62 | "browserslist": [ |
61 | "> 1%", | 63 | "> 1%", |
62 | "last 2 versions" | 64 | "last 2 versions" |
63 | ] | 65 | ] |
64 | } | 66 | } |
65 | 67 |
src/App.vue
1 | <template> | 1 | <template> |
2 | <div id="app"> | 2 | <div id="app"> |
3 | <router-view /> | 3 | <router-view /> |
4 | </div> | 4 | </div> |
5 | |||
5 | </template> | 6 | </template> |
6 | 7 | ||
7 | <script> | 8 | <script> |
8 | export default { | 9 | export default { |
9 | name: 'App' | 10 | name: 'App' |
10 | } | 11 | } |
11 | </script> | 12 | </script> |
12 | 13 |
src/api/user.js
1 | import request from '@/utils/request' | 1 | import request from '@/utils/request' |
2 | 2 | ||
3 | export function login(data) { | 3 | export function login(data) { |
4 | console.log('login....', data) | ||
4 | return request({ | 5 | return request({ |
5 | url: '/vue-admin-template/user/login', | 6 | url: '/vue-admin-template/user/login', |
6 | method: 'post', | 7 | method: 'post', |
7 | data | 8 | data |
8 | }) | 9 | }) |
9 | } | 10 | } |
10 | 11 | ||
11 | export function getInfo(token) { | 12 | export function getInfo(token) { |
13 | console.log('getInfo....', token) | ||
12 | return request({ | 14 | return request({ |
13 | url: '/vue-admin-template/user/info', | 15 | url: '/vue-admin-template/user/info', |
14 | method: 'get', | 16 | method: 'get', |
15 | params: { token } | 17 | params: { token } |
16 | }) | 18 | }) |
17 | } | 19 | } |
18 | 20 | ||
19 | export function logout() { | 21 | export function logout() { |
22 | console.log('logout....') | ||
20 | return request({ | 23 | return request({ |
21 | url: '/vue-admin-template/user/logout', | 24 | url: '/vue-admin-template/user/logout', |
22 | method: 'post' | 25 | method: 'post' |
23 | }) | 26 | }) |
24 | } | 27 | } |
25 | 28 |
src/layout/components/AppMain.vue
1 | <template> | 1 | <template> |
2 | <section class="app-main"> | 2 | <section class="app-main"> |
3 | <transition name="fade-transform" mode="out-in"> | 3 | <transition name="fade-transform" mode="out-in"> |
4 | <router-view :key="key" /> | 4 | <router-view :key="key" /> |
5 | </transition> | 5 | </transition> |
6 | </section> | 6 | </section> |
7 | </template> | 7 | </template> |
8 | 8 | ||
9 | <script> | 9 | <script> |
10 | export default { | 10 | export default { |
11 | name: 'AppMain', | 11 | name: 'AppMain', |
12 | computed: { | 12 | computed: { |
13 | // key() { | ||
14 | // return this.$route.name !== undefined? this.$route.name + +new Date(): this.$route + +new Date() | ||
15 | // } | ||
13 | key() { | 16 | key() { |
14 | return this.$route.path | 17 | return this.$route.path |
15 | } | 18 | } |
16 | } | 19 | } |
17 | } | 20 | } |
18 | </script> | 21 | </script> |
19 | 22 | ||
20 | <style scoped> | 23 | <style scoped> |
21 | .app-main { | 24 | .app-main { |
22 | /*50 = navbar */ | 25 | /*50 = navbar */ |
23 | min-height: calc(100vh - 50px); | 26 | min-height: calc(100vh - 50px); |
24 | width: 100%; | 27 | width: 100%; |
25 | position: relative; | 28 | position: relative; |
26 | overflow: hidden; | 29 | overflow: hidden; |
27 | } | 30 | } |
28 | .fixed-header+.app-main { | 31 | .fixed-header+.app-main { |
29 | padding-top: 50px; | 32 | padding-top: 50px; |
30 | } | 33 | } |
31 | </style> | 34 | </style> |
32 | 35 | ||
33 | <style lang="scss"> | 36 | <style lang="scss"> |
34 | // fix css style bug in open el-dialog | 37 | // fix css style bug in open el-dialog |
35 | .el-popup-parent--hidden { | 38 | .el-popup-parent--hidden { |
36 | .fixed-header { | 39 | .fixed-header { |
37 | padding-right: 15px; | 40 | padding-right: 15px; |
38 | } | 41 | } |
39 | } | 42 | } |
40 | </style> | 43 | </style> |
41 | 44 |
src/layout/components/Navbar.vue
1 | <template> | 1 | <template> |
2 | <div class="navbar"> | 2 | <div class="navbar"> |
3 | <hamburger :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" /> | 3 | <hamburger :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" /> |
4 | 4 | ||
5 | <breadcrumb class="breadcrumb-container" /> | 5 | <breadcrumb class="breadcrumb-container" /> |
6 | 6 | ||
7 | <div class="right-menu"> | 7 | <div class="right-menu"> |
8 | 语言设置 | ||
8 | <el-dropdown class="avatar-container" trigger="click"> | 9 | <el-dropdown class="avatar-container" trigger="click"> |
9 | <div class="avatar-wrapper"> | 10 | <div class="avatar-wrapper"> |
10 | <img :src="avatar+'?imageView2/1/w/80/h/80'" class="user-avatar"> | 11 | <img :src="avatar+'?imageView2/1/w/80/h/80'" class="user-avatar"> |
11 | <i class="el-icon-caret-bottom" /> | 12 | <i class="el-icon-caret-bottom" /> |
12 | </div> | 13 | </div> |
13 | <el-dropdown-menu slot="dropdown" class="user-dropdown"> | 14 | <el-dropdown-menu slot="dropdown" class="user-dropdown"> |
14 | <router-link to="/"> | 15 | <router-link to="/"> |
15 | <el-dropdown-item> | 16 | <el-dropdown-item> |
16 | Home | 17 | Home |
17 | </el-dropdown-item> | 18 | </el-dropdown-item> |
18 | </router-link> | 19 | </router-link> |
19 | <a target="_blank" href="https://github.com/PanJiaChen/vue-admin-template/"> | 20 | <router-link to="/seting"> |
21 | <el-dropdown-item> | ||
22 | 个人设置 | ||
23 | </el-dropdown-item> | ||
24 | </router-link> | ||
25 | <!-- <a target="_blank" href="https://github.com/PanJiaChen/vue-admin-template/"> | ||
20 | <el-dropdown-item>Github</el-dropdown-item> | 26 | <el-dropdown-item>Github</el-dropdown-item> |
21 | </a> | 27 | </a> --> |
22 | <a target="_blank" href="https://panjiachen.github.io/vue-element-admin-site/#/"> | 28 | <!-- <a target="_blank" href="https://panjiachen.github.io/vue-element-admin-site/#/"> |
23 | <el-dropdown-item>Docs</el-dropdown-item> | 29 | <el-dropdown-item>Docs</el-dropdown-item> |
24 | </a> | 30 | </a> --> |
25 | <el-dropdown-item divided @click.native="logout"> | 31 | <el-dropdown-item divided @click.native="logout"> |
26 | <span style="display:block;">Log Out</span> | 32 | <span style="display:block;">退出系统</span> |
27 | </el-dropdown-item> | 33 | </el-dropdown-item> |
28 | </el-dropdown-menu> | 34 | </el-dropdown-menu> |
29 | </el-dropdown> | 35 | </el-dropdown> |
30 | </div> | 36 | </div> |
31 | </div> | 37 | </div> |
32 | </template> | 38 | </template> |
33 | 39 | ||
34 | <script> | 40 | <script> |
35 | import { mapGetters } from 'vuex' | 41 | import { mapGetters } from 'vuex' |
36 | import Breadcrumb from '@/components/Breadcrumb' | 42 | import Breadcrumb from '@/components/Breadcrumb' |
37 | import Hamburger from '@/components/Hamburger' | 43 | import Hamburger from '@/components/Hamburger' |
38 | 44 | ||
39 | export default { | 45 | export default { |
40 | components: { | 46 | components: { |
41 | Breadcrumb, | 47 | Breadcrumb, |
42 | Hamburger | 48 | Hamburger |
43 | }, | 49 | }, |
44 | computed: { | 50 | computed: { |
45 | ...mapGetters([ | 51 | ...mapGetters([ |
46 | 'sidebar', | 52 | 'sidebar', |
47 | 'avatar' | 53 | 'avatar' |
48 | ]) | 54 | ]) |
49 | }, | 55 | }, |
50 | methods: { | 56 | methods: { |
51 | toggleSideBar() { | 57 | toggleSideBar() { |
52 | this.$store.dispatch('app/toggleSideBar') | 58 | this.$store.dispatch('app/toggleSideBar') |
53 | }, | 59 | }, |
54 | async logout() { | 60 | async logout() { |
55 | await this.$store.dispatch('user/logout') | 61 | await this.$store.dispatch('user/logout') |
56 | this.$router.push(`/login?redirect=${this.$route.fullPath}`) | 62 | this.$router.push(`/login?redirect=${this.$route.fullPath}`) |
57 | } | 63 | } |
58 | } | 64 | } |
59 | } | 65 | } |
60 | </script> | 66 | </script> |
61 | 67 | ||
62 | <style lang="scss" scoped> | 68 | <style lang="scss" scoped> |
63 | .navbar { | 69 | .navbar { |
64 | height: 50px; | 70 | height: 50px; |
65 | overflow: hidden; | 71 | overflow: hidden; |
66 | position: relative; | 72 | position: relative; |
67 | background: #fff; | 73 | background: #fff; |
68 | box-shadow: 0 1px 4px rgba(0,21,41,.08); | 74 | box-shadow: 0 1px 4px rgba(0,21,41,.08); |
69 | 75 | ||
70 | .hamburger-container { | 76 | .hamburger-container { |
71 | line-height: 46px; | 77 | line-height: 46px; |
72 | height: 100%; | 78 | height: 100%; |
73 | float: left; | 79 | float: left; |
74 | cursor: pointer; | 80 | cursor: pointer; |
75 | transition: background .3s; | 81 | transition: background .3s; |
76 | -webkit-tap-highlight-color:transparent; | 82 | -webkit-tap-highlight-color:transparent; |
77 | 83 | ||
78 | &:hover { | 84 | &:hover { |
79 | background: rgba(0, 0, 0, .025) | 85 | background: rgba(0, 0, 0, .025) |
80 | } | 86 | } |
81 | } | 87 | } |
82 | 88 | ||
83 | .breadcrumb-container { | 89 | .breadcrumb-container { |
84 | float: left; | 90 | float: left; |
85 | } | 91 | } |
86 | 92 | ||
87 | .right-menu { | 93 | .right-menu { |
88 | float: right; | 94 | float: right; |
89 | height: 100%; | 95 | height: 100%; |
90 | line-height: 50px; | 96 | line-height: 50px; |
91 | 97 | ||
92 | &:focus { | 98 | &:focus { |
93 | outline: none; | 99 | outline: none; |
94 | } | 100 | } |
95 | 101 | ||
96 | .right-menu-item { | 102 | .right-menu-item { |
97 | display: inline-block; | 103 | display: inline-block; |
98 | padding: 0 8px; | 104 | padding: 0 8px; |
99 | height: 100%; | 105 | height: 100%; |
100 | font-size: 18px; | 106 | font-size: 18px; |
101 | color: #5a5e66; | 107 | color: #5a5e66; |
102 | vertical-align: text-bottom; | 108 | vertical-align: text-bottom; |
103 | 109 | ||
104 | &.hover-effect { | 110 | &.hover-effect { |
105 | cursor: pointer; | 111 | cursor: pointer; |
106 | transition: background .3s; | 112 | transition: background .3s; |
107 | 113 | ||
108 | &:hover { | 114 | &:hover { |
109 | background: rgba(0, 0, 0, .025) | 115 | background: rgba(0, 0, 0, .025) |
110 | } | 116 | } |
111 | } | 117 | } |
112 | } | 118 | } |
113 | 119 | ||
114 | .avatar-container { | 120 | .avatar-container { |
115 | margin-right: 30px; | 121 | margin-right: 30px; |
116 | 122 | ||
117 | .avatar-wrapper { | 123 | .avatar-wrapper { |
118 | margin-top: 5px; | 124 | margin-top: 5px; |
119 | position: relative; | 125 | position: relative; |
120 | 126 | ||
121 | .user-avatar { | 127 | .user-avatar { |
122 | cursor: pointer; | 128 | cursor: pointer; |
123 | width: 40px; | 129 | width: 40px; |
124 | height: 40px; | 130 | height: 40px; |
125 | border-radius: 10px; | 131 | border-radius: 10px; |
126 | } | 132 | } |
127 | 133 | ||
128 | .el-icon-caret-bottom { | 134 | .el-icon-caret-bottom { |
129 | cursor: pointer; | 135 | cursor: pointer; |
130 | position: absolute; | 136 | position: absolute; |
131 | right: -20px; | 137 | right: -20px; |
132 | top: 25px; | 138 | top: 25px; |
133 | font-size: 12px; | 139 | font-size: 12px; |
134 | } | 140 | } |
135 | } | 141 | } |
136 | } | 142 | } |
137 | } | 143 | } |
138 | } | 144 | } |
139 | </style> | 145 | </style> |
140 | 146 |
src/layout/components/Sidebar/Logo.vue
1 | <template> | 1 | <template> |
2 | <div class="sidebar-logo-container" :class="{'collapse':collapse}"> | 2 | <div class="sidebar-logo-container" :class="{'collapse':collapse}"> |
3 | <transition name="sidebarLogoFade"> | 3 | <transition name="sidebarLogoFade"> |
4 | <router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/"> | 4 | <router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/"> |
5 | <img v-if="logo" :src="logo" class="sidebar-logo"> | 5 | <img v-if="logo" :src="logo" class="sidebar-logo"> |
6 | <h1 v-else class="sidebar-title">{{ title }} </h1> | 6 | <h1 v-else class="sidebar-title">{{ title }} </h1> |
7 | </router-link> | 7 | </router-link> |
8 | <router-link v-else key="expand" class="sidebar-logo-link" to="/"> | 8 | <router-link v-else key="expand" class="sidebar-logo-link" to="/"> |
9 | <img v-if="logo" :src="logo" class="sidebar-logo"> | 9 | <img v-if="logo" :src="logo" class="sidebar-logo"> |
10 | <h1 class="sidebar-title">{{ title }} </h1> | 10 | <h1 class="sidebar-title">{{ title }} </h1> |
11 | </router-link> | 11 | </router-link> |
12 | </transition> | 12 | </transition> |
13 | </div> | 13 | </div> |
14 | </template> | 14 | </template> |
15 | 15 | ||
16 | <script> | 16 | <script> |
17 | export default { | 17 | export default { |
18 | name: 'SidebarLogo', | 18 | name: 'SidebarLogo', |
19 | props: { | 19 | props: { |
20 | collapse: { | 20 | collapse: { |
21 | type: Boolean, | 21 | type: Boolean, |
22 | required: true | 22 | required: true |
23 | } | 23 | } |
24 | }, | 24 | }, |
25 | data() { | 25 | data() { |
26 | return { | 26 | return { |
27 | title: 'Vue Admin Template', | 27 | title: '鱼皮出海', |
28 | logo: 'https://wpimg.wallstcn.com/69a1c46c-eb1c-4b46-8bd4-e9e686ef5251.png' | 28 | logo: 'https://wpimg.wallstcn.com/69a1c46c-eb1c-4b46-8bd4-e9e686ef5251.png' |
29 | } | 29 | } |
30 | } | 30 | } |
31 | } | 31 | } |
32 | </script> | 32 | </script> |
33 | 33 | ||
34 | <style lang="scss" scoped> | 34 | <style lang="scss" scoped> |
35 | .sidebarLogoFade-enter-active { | 35 | .sidebarLogoFade-enter-active { |
36 | transition: opacity 1.5s; | 36 | transition: opacity 1.5s; |
37 | } | 37 | } |
38 | 38 | ||
39 | .sidebarLogoFade-enter, | 39 | .sidebarLogoFade-enter, |
40 | .sidebarLogoFade-leave-to { | 40 | .sidebarLogoFade-leave-to { |
41 | opacity: 0; | 41 | opacity: 0; |
42 | } | 42 | } |
43 | 43 | ||
44 | .sidebar-logo-container { | 44 | .sidebar-logo-container { |
45 | position: relative; | 45 | position: relative; |
46 | width: 100%; | 46 | width: 100%; |
47 | height: 50px; | 47 | height: 50px; |
48 | line-height: 50px; | 48 | line-height: 50px; |
49 | background: #2b2f3a; | 49 | background: #2b2f3a; |
50 | text-align: center; | 50 | text-align: center; |
51 | overflow: hidden; | 51 | overflow: hidden; |
52 | 52 | ||
53 | & .sidebar-logo-link { | 53 | & .sidebar-logo-link { |
54 | height: 100%; | 54 | height: 100%; |
55 | width: 100%; | 55 | width: 100%; |
56 | 56 | ||
57 | & .sidebar-logo { | 57 | & .sidebar-logo { |
58 | width: 32px; | 58 | width: 32px; |
59 | height: 32px; | 59 | height: 32px; |
60 | vertical-align: middle; | 60 | vertical-align: middle; |
61 | margin-right: 12px; | 61 | margin-right: 12px; |
62 | } | 62 | } |
63 | 63 | ||
64 | & .sidebar-title { | 64 | & .sidebar-title { |
65 | display: inline-block; | 65 | display: inline-block; |
66 | margin: 0; | 66 | margin: 0; |
67 | color: #fff; | 67 | color: #fff; |
68 | font-weight: 600; | 68 | font-weight: 600; |
69 | line-height: 50px; | 69 | line-height: 50px; |
70 | font-size: 14px; | 70 | font-size: 14px; |
71 | font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif; | 71 | font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif; |
72 | vertical-align: middle; | 72 | vertical-align: middle; |
73 | } | 73 | } |
74 | } | 74 | } |
75 | 75 | ||
76 | &.collapse { | 76 | &.collapse { |
77 | .sidebar-logo { | 77 | .sidebar-logo { |
78 | margin-right: 0px; | 78 | margin-right: 0px; |
79 | } | 79 | } |
80 | } | 80 | } |
81 | } | 81 | } |
82 | </style> | 82 | </style> |
83 | 83 |
src/main.js
1 | import Vue from 'vue' | 1 | import Vue from 'vue' |
2 | 2 | ||
3 | import 'normalize.css/normalize.css' // A modern alternative to CSS resets | 3 | import 'normalize.css/normalize.css' // A modern alternative to CSS resets |
4 | 4 | ||
5 | import ElementUI from 'element-ui' | 5 | import ElementUI from 'element-ui' |
6 | import 'element-ui/lib/theme-chalk/index.css' | 6 | import 'element-ui/lib/theme-chalk/index.css' |
7 | import locale from 'element-ui/lib/locale/lang/en' // lang i18n | 7 | import locale from 'element-ui/lib/locale/lang/en' // lang i18n |
8 | // import local_zh from 'element-ui/lib/locale/lang/zh-CN' // 在node_module里面 | ||
8 | 9 | ||
9 | import '@/styles/index.scss' // global css | 10 | import '@/styles/index.scss' // global css |
10 | 11 | ||
11 | import App from './App' | 12 | import App from './App' |
12 | import store from './store' | 13 | import store from './store' |
13 | import router from './router' | 14 | import router from './router' |
14 | 15 | ||
15 | import '@/icons' // icon | 16 | import '@/icons' // icon |
16 | import '@/permission' // permission control | 17 | import '@/permission' // permission control |
17 | 18 | ||
18 | /** | 19 | /** |
19 | * If you don't want to use mock-server | 20 | * If you don't want to use mock-server |
20 | * you want to use MockJs for mock api | 21 | * you want to use MockJs for mock api |
21 | * you can execute: mockXHR() | 22 | * you can execute: mockXHR() |
22 | * | 23 | * |
23 | * Currently MockJs will be used in the production environment, | 24 | * Currently MockJs will be used in the production environment, |
24 | * please remove it before going online ! ! ! | 25 | * please remove it before going online ! ! ! |
25 | */ | 26 | */ |
26 | if (process.env.NODE_ENV === 'production') { | 27 | if (process.env.NODE_ENV === 'production') { |
27 | const { mockXHR } = require('../mock') | 28 | const { mockXHR } = require('../mock') |
28 | mockXHR() | 29 | mockXHR() |
29 | } | 30 | } |
30 | 31 | ||
31 | // set ElementUI lang to EN | 32 | // set ElementUI lang to EN |
32 | Vue.use(ElementUI, { locale }) | 33 | Vue.use(ElementUI, { locale }) |
33 | // 如果想要中文版 element-ui,按如下方式声明 | 34 | // 如果想要中文版 element-ui,按如下方式声明 |
34 | // Vue.use(ElementUI) | 35 | // Vue.use(ElementUI, {local_zh}) |
35 | 36 | ||
36 | Vue.config.productionTip = false | 37 | Vue.config.productionTip = false |
37 | 38 | ||
38 | new Vue({ | 39 | new Vue({ |
39 | el: '#app', | 40 | el: '#app', |
40 | router, | 41 | router, |
41 | store, | 42 | store, |
42 | render: h => h(App) | 43 | render: h => h(App) |
43 | }) | 44 | }) |
44 | 45 |
src/router/index.js
1 | import Vue from 'vue' | 1 | import Vue from 'vue' |
2 | import Router from 'vue-router' | 2 | import Router from 'vue-router' |
3 | 3 | ||
4 | Vue.use(Router) | 4 | Vue.use(Router) |
5 | 5 | ||
6 | /* Layout */ | 6 | /* Layout */ |
7 | import Layout from '@/layout' | 7 | import Layout from '@/layout' |
8 | 8 | ||
9 | /** | 9 | /** |
10 | * Note: sub-menu only appear when route children.length >= 1 | 10 | * Note: sub-menu only appear when route children.length >= 1 |
11 | * Detail see: https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html | 11 | * Detail see: https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html |
12 | * | 12 | * |
13 | * hidden: true if set true, item will not show in the sidebar(default is false) | 13 | * hidden: true if set true, item will not show in the sidebar(default is false) |
14 | * alwaysShow: true if set true, will always show the root menu | 14 | * alwaysShow: true if set true, will always show the root menu |
15 | * if not set alwaysShow, when item has more than one children route, | 15 | * if not set alwaysShow, when item has more than one children route, |
16 | * it will becomes nested mode, otherwise not show the root menu | 16 | * it will becomes nested mode, otherwise not show the root menu |
17 | * redirect: noRedirect if set noRedirect will no redirect in the breadcrumb | 17 | * redirect: noRedirect if set noRedirect will no redirect in the breadcrumb |
18 | * name:'router-name' the name is used by <keep-alive> (must set!!!) | 18 | * name:'router-name' the name is used by <keep-alive> (must set!!!) |
19 | * meta : { | 19 | * meta : { |
20 | roles: ['admin','editor'] control the page roles (you can set multiple roles) | 20 | roles: ['admin','editor'] control the page roles (you can set multiple roles) |
21 | title: 'title' the name show in sidebar and breadcrumb (recommend set) | 21 | title: 'title' the name show in sidebar and breadcrumb (recommend set) |
22 | icon: 'svg-name' the icon show in the sidebar | 22 | icon: 'svg-name' the icon show in the sidebar |
23 | breadcrumb: false if set false, the item will hidden in breadcrumb(default is true) | 23 | breadcrumb: false if set false, the item will hidden in breadcrumb(default is true) |
24 | activeMenu: '/example/list' if set path, the sidebar will highlight the path you set | 24 | activeMenu: '/example/list' if set path, the sidebar will highlight the path you set |
25 | } | 25 | } |
26 | */ | 26 | */ |
27 | 27 | ||
28 | /** | 28 | /** |
29 | * constantRoutes | 29 | * constantRoutes |
30 | * a base page that does not have permission requirements | 30 | * a base page that does not have permission requirements |
31 | * all roles can be accessed | 31 | * all roles can be accessed |
32 | */ | 32 | */ |
33 | export const constantRoutes = [ | 33 | export const constantRoutes = [ |
34 | { | 34 | { |
35 | path: '/login', | 35 | path: '/login', |
36 | component: () => import('@/views/login/index'), | 36 | component: () => import('@/views/login/index'), |
37 | hidden: true | 37 | hidden: true |
38 | }, | 38 | }, |
39 | 39 | ||
40 | { | 40 | { |
41 | path: '/404', | 41 | path: '/404', |
42 | component: () => import('@/views/404'), | 42 | component: () => import('@/views/404'), |
43 | hidden: true | 43 | hidden: true |
44 | }, | 44 | }, |
45 | 45 | ||
46 | { | 46 | { |
47 | path: '/', | 47 | path: '/', |
48 | component: Layout, | 48 | component: Layout, |
49 | redirect: '/dashboard', | 49 | redirect: '/dashboard', |
50 | children: [{ | 50 | children: [{ |
51 | path: 'dashboard', | 51 | path: 'dashboard', |
52 | name: 'Dashboard', | 52 | name: 'Dashboard', |
53 | component: () => import('@/views/dashboard/index'), | 53 | component: () => import('@/views/dashboard/index'), |
54 | meta: { title: 'Dashboard', icon: 'dashboard' } | 54 | meta: { title: '标题-------dashboard', icon: 'dashboard' } |
55 | }] | 55 | }] |
56 | }, | 56 | }, |
57 | 57 | ||
58 | { | 58 | { |
59 | path: '/example', | 59 | path: '/example', |
60 | component: Layout, | 60 | component: Layout, |
61 | redirect: '/example/table', | 61 | redirect: '/example/table', |
62 | name: 'Example', | 62 | name: 'Example', |
63 | meta: { title: 'Example', icon: 'example' }, | 63 | meta: { title: 'Example', icon: 'example' }, |
64 | children: [ | 64 | children: [ |
65 | { | 65 | { |
66 | path: 'table', | 66 | path: 'table', |
67 | name: 'Table', | 67 | name: 'Table', |
68 | component: () => import('@/views/table/index'), | 68 | component: () => import('@/views/table/index'), |
69 | meta: { title: 'Table', icon: 'table' } | 69 | meta: { title: 'Table', icon: 'table' } |
70 | }, | 70 | }, |
71 | { | 71 | { |
72 | path: 'tree', | 72 | path: 'tree', |
73 | name: 'Tree', | 73 | name: 'Tree', |
74 | component: () => import('@/views/tree/index'), | 74 | component: () => import('@/views/tree/index'), |
75 | meta: { title: 'Tree', icon: 'tree' } | 75 | meta: { title: 'Tree', icon: 'tree' } |
76 | } | 76 | } |
77 | ] | 77 | ] |
78 | }, | 78 | }, |
79 | 79 | ||
80 | { | 80 | { |
81 | path: '/form', | 81 | path: '/form', |
82 | component: Layout, | 82 | component: Layout, |
83 | children: [ | 83 | children: [ |
84 | { | 84 | { |
85 | path: 'index', | 85 | path: 'index', |
86 | name: 'Form', | 86 | name: 'Form', |
87 | component: () => import('@/views/form/index'), | 87 | component: () => import('@/views/form/index'), |
88 | meta: { title: 'Form', icon: 'form' } | 88 | meta: { title: 'Form', icon: 'form' } |
89 | } | 89 | } |
90 | ] | 90 | ] |
91 | } | 91 | } |
92 | ] | 92 | ] |
93 | 93 | ||
94 | /** | 94 | /** |
95 | * asyncRoutes | 95 | * asyncRoutes |
96 | * the routes that need to be dynamically loaded based on user roles | 96 | * the routes that need to be dynamically loaded based on user roles |
97 | */ | 97 | */ |
98 | export const asyncRoutes = [ | 98 | export const asyncRoutes = [ |
99 | { | 99 | { |
100 | path: '/nested', | 100 | path: '/nested', |
101 | component: Layout, | 101 | component: Layout, |
102 | redirect: '/nested/menu1', | 102 | redirect: '/nested/menu1', |
103 | name: 'Nested', | 103 | name: 'Nested', |
104 | meta: { | 104 | meta: { |
105 | title: 'Nested', | 105 | title: 'Nested', |
106 | icon: 'nested' | 106 | icon: 'nested' |
107 | }, | 107 | }, |
108 | children: [ | 108 | children: [ |
109 | { | 109 | { |
110 | path: 'menu1', | 110 | path: 'menu1', |
111 | component: () => import('@/views/nested/menu1/index'), // Parent router-view | 111 | component: () => import('@/views/nested/menu1/index'), // Parent router-view |
112 | name: 'Menu1', | 112 | name: 'Menu1', |
113 | meta: { title: 'Menu1' }, | 113 | meta: { title: 'Menu1' }, |
114 | children: [ | 114 | children: [ |
115 | { | 115 | { |
116 | path: 'menu1-1', | 116 | path: 'menu1-1', |
117 | component: () => import('@/views/nested/menu1/menu1-1'), | 117 | component: () => import('@/views/nested/menu1/menu1-1'), |
118 | name: 'Menu1-1', | 118 | name: 'Menu1-1', |
119 | meta: { title: 'Menu1-1' } | 119 | meta: { title: 'Menu1-1' } |
120 | }, | 120 | }, |
121 | { | 121 | { |
122 | path: 'menu1-2', | 122 | path: 'menu1-2', |
123 | component: () => import('@/views/nested/menu1/menu1-2'), | 123 | component: () => import('@/views/nested/menu1/menu1-2'), |
124 | name: 'Menu1-2', | 124 | name: 'Menu1-2', |
125 | meta: { title: 'Menu1-2' }, | 125 | meta: { title: 'Menu1-2' }, |
126 | children: [ | 126 | children: [ |
127 | { | 127 | { |
128 | path: 'menu1-2-1', | 128 | path: 'menu1-2-1', |
129 | component: () => import('@/views/nested/menu1/menu1-2/menu1-2-1'), | 129 | component: () => import('@/views/nested/menu1/menu1-2/menu1-2-1'), |
130 | name: 'Menu1-2-1', | 130 | name: 'Menu1-2-1', |
131 | meta: { title: 'Menu1-2-1' } | 131 | meta: { title: 'Menu1-2-1' } |
132 | }, | 132 | }, |
133 | { | 133 | { |
134 | path: 'menu1-2-2', | 134 | path: 'menu1-2-2', |
135 | component: () => import('@/views/nested/menu1/menu1-2/menu1-2-2'), | 135 | component: () => import('@/views/nested/menu1/menu1-2/menu1-2-2'), |
136 | name: 'Menu1-2-2', | 136 | name: 'Menu1-2-2', |
137 | meta: { title: 'Menu1-2-2' } | 137 | meta: { title: 'Menu1-2-2' } |
138 | } | 138 | } |
139 | ] | 139 | ] |
140 | }, | 140 | }, |
141 | { | 141 | { |
142 | path: 'menu1-3', | 142 | path: 'menu1-3', |
143 | component: () => import('@/views/nested/menu1/menu1-3'), | 143 | component: () => import('@/views/nested/menu1/menu1-3'), |
144 | name: 'Menu1-3', | 144 | name: 'Menu1-3', |
145 | meta: { title: 'Menu1-3' } | 145 | meta: { title: 'Menu1-3' } |
146 | } | 146 | } |
147 | ] | 147 | ] |
148 | }, | 148 | }, |
149 | { | 149 | { |
150 | path: 'menu2', | 150 | path: 'menu2', |
151 | component: () => import('@/views/nested/menu2/index'), | 151 | component: () => import('@/views/nested/menu2/index'), |
152 | meta: { title: 'menu2' } | 152 | meta: { title: 'menu2' } |
153 | } | 153 | } |
154 | ] | 154 | ] |
155 | }, | 155 | }, |
156 | 156 | ||
157 | { | 157 | { |
158 | path: 'external-link', | 158 | path: 'external-link', |
159 | component: Layout, | 159 | component: Layout, |
160 | children: [ | 160 | children: [ |
161 | { | 161 | { |
162 | path: 'https://panjiachen.github.io/vue-element-admin-site/#/', | 162 | path: 'https://panjiachen.github.io/vue-element-admin-site/#/', |
163 | meta: { title: 'External Link', icon: 'link' } | 163 | meta: { title: 'External Link', icon: 'link' } |
164 | } | 164 | } |
165 | ] | 165 | ] |
166 | }, | 166 | }, |
167 | |||
168 | // 404 page must be placed at the end !!! | 167 | // 404 page must be placed at the end !!! |
169 | { path: '*', redirect: '/404', hidden: true } | 168 | { |
169 | path: '*', | ||
170 | redirect: '/404' | ||
171 | } | ||
170 | ] | 172 | ] |
171 | 173 | ||
172 | const createRouter = () => new Router({ | 174 | const createRouter = () => new Router({ |
173 | // mode: 'history', // require service support | 175 | // mode: 'history', // require service support |
174 | scrollBehavior: () => ({ y: 0 }), | 176 | scrollBehavior: () => ({ y: 0 }), |
175 | routes: constantRoutes | 177 | routes: constantRoutes |
176 | }) | 178 | }) |
177 | 179 | ||
178 | const router = createRouter() | 180 | const router = createRouter() |
179 | 181 | ||
180 | // Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465 | 182 | // Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465 |
181 | export function resetRouter() { | 183 | export function resetRouter() { |
182 | const newRouter = createRouter() | 184 | const newRouter = createRouter() |
183 | router.matcher = newRouter.matcher // reset router | 185 | router.matcher = newRouter.matcher // reset router |
184 | } | 186 | } |
185 | 187 | ||
186 | export default router | 188 | export default router |
src/settings.js
1 | module.exports = { | 1 | module.exports = { |
2 | 2 | ||
3 | title: 'Vue Admin Template', | 3 | title: '鱼皮出海', |
4 | 4 | ||
5 | /** | 5 | /** |
6 | * @type {boolean} true | false | 6 | * @type {boolean} true | false |
7 | * @description Whether fix the header | 7 | * @description Whether fix the header |
8 | */ | 8 | */ |
9 | fixedHeader: false, | 9 | fixedHeader: true, |
10 | 10 | ||
11 | /** | 11 | /** |
12 | * @type {boolean} true | false | 12 | * @type {boolean} true | false |
13 | * @description Whether show the logo in sidebar | 13 | * @description Whether show the logo in sidebar |
14 | */ | 14 | */ |
15 | sidebarLogo: false | 15 | sidebarLogo:true |
16 | } | 16 | } |
17 | 17 |
src/utils/request.js
1 | import axios from 'axios' | 1 | import axios from 'axios' |
2 | import { MessageBox, Message } from 'element-ui' | 2 | import { MessageBox, Message } from 'element-ui' |
3 | import store from '@/store' | 3 | import store from '@/store' |
4 | import { getToken } from '@/utils/auth' | 4 | import { getToken } from '@/utils/auth' |
5 | 5 | ||
6 | // create an axios instance | 6 | // create an axios instance |
7 | // 创建axios实例 | ||
7 | const service = axios.create({ | 8 | const service = axios.create({ |
8 | baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url | 9 | baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url |
9 | // withCredentials: true, // send cookies when cross-domain requests | 10 | // withCredentials: true, // send cookies when cross-domain requests |
10 | timeout: 5000 // request timeout | 11 | timeout: 5000 // request timeout |
11 | }) | 12 | }) |
12 | 13 | ||
13 | // request interceptor | 14 | // request interceptor |
15 | // request拦截器 | ||
14 | service.interceptors.request.use( | 16 | service.interceptors.request.use( |
15 | config => { | 17 | config => { |
16 | // do something before request is sent | 18 | // do something before request is sent |
17 | 19 | console.log('do something before request is sent') | |
18 | if (store.getters.token) { | 20 | if (store.getters.token) { |
21 | console.log('[X-Token] is a custom headers key') | ||
19 | // let each request carry token | 22 | // let each request carry token |
20 | // ['X-Token'] is a custom headers key | 23 | // ['X-Token'] is a custom headers key |
21 | // please modify it according to the actual situation | 24 | // please modify it according to the actual situation |
22 | config.headers['X-Token'] = getToken() | 25 | config.headers['X-Token'] = getToken() |
23 | } | 26 | } |
24 | return config | 27 | return config |
25 | }, | 28 | }, |
26 | error => { | 29 | error => { |
30 | console.log('do something with request error') | ||
27 | // do something with request error | 31 | // do something with request error |
28 | console.log(error) // for debug | 32 | console.log(error) // for debug |
29 | return Promise.reject(error) | 33 | return Promise.reject(error) |
30 | } | 34 | } |
31 | ) | 35 | ) |
32 | 36 | ||
33 | // response interceptor | 37 | // response interceptor |
38 | // respone拦截器 | ||
34 | service.interceptors.response.use( | 39 | service.interceptors.response.use( |
35 | /** | 40 | /** |
36 | * If you want to get http information such as headers or status | 41 | * If you want to get http information such as headers or status |
37 | * Please return response => response | 42 | * Please return response => response |
38 | */ | 43 | */ |
39 | 44 | ||
40 | /** | 45 | /** |
41 | * Determine the request status by custom code | 46 | * Determine the request status by custom code |
42 | * Here is just an example | 47 | * Here is just an example |
43 | * You can also judge the status by HTTP Status Code | 48 | * You can also judge the status by HTTP Status Code |
44 | */ | 49 | */ |
45 | response => { | 50 | response => { |
46 | const res = response.data | 51 | const res = response.data |
47 | 52 | /** | |
53 | * 下面的注释为通过response自定义code来标示请求状态,当code返回如下情况为权限有问题,登出并返回到登录页 | ||
54 | * 如通过xmlhttprequest 状态码标识 逻辑可写在下面error中 | ||
55 | */ | ||
56 | console.log('if the custom code is not 20000, it is judged as an error.') | ||
48 | // if the custom code is not 20000, it is judged as an error. | 57 | // if the custom code is not 20000, it is judged as an error. |
49 | if (res.code !== 20000) { | 58 | if (res.code !== 20000) { |
50 | Message({ | 59 | Message({ |
51 | message: res.message || 'Error', | 60 | message: res.message || 'Error', |
52 | type: 'error', | 61 | type: 'error', |
53 | duration: 5 * 1000 | 62 | duration: 5 * 1000 |
54 | }) | 63 | }) |
55 | 64 | ||
56 | // 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired; | 65 | // 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired; |
66 | // 50008:非法的token; 50012:其他客户端登录了; 50014:Token 过期了; | ||
57 | if (res.code === 50008 || res.code === 50012 || res.code === 50014) { | 67 | if (res.code === 50008 || res.code === 50012 || res.code === 50014) { |
58 | // to re-login | 68 | // to re-login |
59 | MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', { | 69 | // MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', { |
60 | confirmButtonText: 'Re-Login', | 70 | MessageBox.confirm('你已被登出,可以取消继续留在该页面,或者重新登录', '确定登出', { |
61 | cancelButtonText: 'Cancel', | 71 | // confirmButtonText: 'Re-Login', |
72 | confirmButtonText: '重新登录', | ||
73 | // cancelButtonText: 'Cancel', | ||
74 | cancelButtonText: '取消', | ||
62 | type: 'warning' | 75 | type: 'warning' |
63 | }).then(() => { | 76 | }).then(() => { |
64 | store.dispatch('user/resetToken').then(() => { | 77 | store.dispatch('user/resetToken').then(() => { |
65 | location.reload() | 78 | location.reload()// 为了重新实例化vue-router对象 避免bug |
66 | }) | 79 | }) |
67 | }) | 80 | }) |
68 | } | 81 | } |
69 | return Promise.reject(new Error(res.message || 'Error')) | 82 | return Promise.reject(new Error(res.message || 'Error')) |
70 | } else { | 83 | } else { |
71 | return res | 84 | return res |
72 | } | 85 | } |
73 | }, | 86 | }, |
74 | error => { | 87 | error => { |
75 | console.log('err' + error) // for debug | 88 | console.log('err' + error) // for debug |
76 | Message({ | 89 | Message({ |
77 | message: error.message, | 90 | message: error.message, |
78 | type: 'error', | 91 | type: 'error', |
79 | duration: 5 * 1000 | 92 | duration: 5 * 1000 |
80 | }) | 93 | }) |
81 | return Promise.reject(error) | 94 | return Promise.reject(error) |
82 | } | 95 | } |
83 | ) | 96 | ) |
84 | 97 | ||
85 | export default service | 98 | export default service |
86 | 99 |
src/views/dashboard/index.vue
1 | <template> | 1 | <template> |
2 | <div class="dashboard-container"> | 2 | <div class="dashboard-container"> |
3 | <div class="dashboard-text">name: {{ name }}</div> | 3 | <div class="dashboard-text">用户名: {{ name }}</div> |
4 | <div class="dashboard-text">roles: <span v-for="role in roles" :key="role">{{ role }}</span></div> | 4 | <div class="dashboard-text">角色: <span v-for="role in roles" :key="role">{{ role }}</span></div> |
5 | </div> | 5 | </div> |
6 | </template> | 6 | </template> |
7 | 7 | ||
8 | |||
9 | |||
8 | <script> | 10 | <script> |
9 | import { mapGetters } from 'vuex' | 11 | import { mapGetters } from 'vuex' |
12 | import ElementUI from 'element-ui' | ||
10 | 13 | ||
11 | export default { | 14 | export default { |
12 | name: 'Dashboard', | 15 | name: 'Dashboard', |
13 | computed: { | 16 | computed: { |
14 | ...mapGetters([ | 17 | ...mapGetters([ |
15 | 'name', | 18 | 'name', |
16 | 'roles' | 19 | 'roles' |
17 | ]) | 20 | ]) |
18 | } | 21 | } |
19 | } | 22 | } |
20 | </script> | 23 | </script> |
21 | 24 | ||
22 | <style lang="scss" scoped> | 25 | <style lang="scss" scoped> |
23 | .dashboard { | 26 | .dashboard { |
24 | &-container { | 27 | &-container { |
25 | margin: 30px; | 28 | margin: 30px; |
26 | } | 29 | } |
27 | &-text { | 30 | &-text { |
28 | font-size: 30px; | 31 | font-size: 30px; |
29 | line-height: 46px; | 32 | line-height: 46px; |
30 | } | 33 | } |
31 | } | 34 | } |
32 | </style> | 35 | </style> |
33 | 36 |
src/views/login/index.vue
1 | <template> | 1 | <template> |
2 | <div class="login-container"> | 2 | <div class="login-container"> |
3 | <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" auto-complete="on" label-position="left"> | 3 | <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" auto-complete="on" label-position="left"> |
4 | 4 | ||
5 | <div class="title-container"> | 5 | <div class="title-container"> |
6 | <h3 class="title">Login Form</h3> | 6 | <h3 class="title">Login Form</h3> |
7 | </div> | 7 | </div> |
8 | 8 | ||
9 | <el-form-item prop="username"> | 9 | <el-form-item prop="username"> |
10 | <span class="svg-container"> | 10 | <span class="svg-container"> |
11 | <svg-icon icon-class="user" /> | 11 | <svg-icon icon-class="user" /> |
12 | </span> | 12 | </span> |
13 | <el-input | 13 | <el-input |
14 | ref="username" | 14 | ref="username" |
15 | v-model="loginForm.username" | 15 | v-model="loginForm.username" |
16 | placeholder="Username" | 16 | placeholder="Username" |
17 | name="username" | 17 | name="username" |
18 | type="text" | 18 | type="text" |
19 | tabindex="1" | 19 | tabindex="1" |
20 | auto-complete="on" | 20 | auto-complete="on" |
21 | /> | 21 | /> |
22 | </el-form-item> | 22 | </el-form-item> |
23 | 23 | ||
24 | <el-form-item prop="password"> | 24 | <el-form-item prop="password"> |
25 | <span class="svg-container"> | 25 | <span class="svg-container"> |
26 | <svg-icon icon-class="password" /> | 26 | <svg-icon icon-class="password" /> |
27 | </span> | 27 | </span> |
28 | <el-input | 28 | <el-input |
29 | :key="passwordType" | 29 | :key="passwordType" |
30 | ref="password" | 30 | ref="password" |
31 | v-model="loginForm.password" | 31 | v-model="loginForm.password" |
32 | :type="passwordType" | 32 | :type="passwordType" |
33 | placeholder="Password" | 33 | placeholder="Password" |
34 | name="password" | 34 | name="password" |
35 | tabindex="2" | 35 | tabindex="2" |
36 | auto-complete="on" | 36 | auto-complete="on" |
37 | @keyup.enter.native="handleLogin" | 37 | @keyup.enter.native="handleLogin" |
38 | /> | 38 | /> |
39 | <span class="show-pwd" @click="showPwd"> | 39 | <span class="show-pwd" @click="showPwd"> |
40 | <svg-icon :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" /> | 40 | <svg-icon :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" /> |
41 | </span> | 41 | </span> |
42 | </el-form-item> | 42 | </el-form-item> |
43 | 43 | <!-- <el-button :loading="loading" type="primary" style="width:100%;margin-bottom:30px;" @click.native.prevent="handleLogin">reg</el-button> --> | |
44 | <el-button :loading="loading" type="primary" style="width:100%;margin-bottom:30px;" @click.native.prevent="handleLogin">Login</el-button> | 44 | <el-button :loading="loading" type="primary" style="width:100%;margin-bottom:30px;" @click.native.prevent="handleLogin">Login</el-button> |
45 | 45 | ||
46 | <div class="tips"> | 46 | <div class="tips"> |
47 | <span style="margin-right:20px;">username: admin</span> | 47 | <span style="margin-right:20px;">username: admin</span> |
48 | <span> password: any</span> | 48 | <span> password: any</span> |
49 | </div> | 49 | </div> |
50 | 50 | ||
51 | </el-form> | 51 | </el-form> |
52 | </div> | 52 | </div> |
53 | </template> | 53 | </template> |
54 | 54 | ||
55 | <script> | 55 | <script> |
56 | import { validUsername } from '@/utils/validate' | 56 | import { validUsername } from '@/utils/validate' |
57 | 57 | ||
58 | export default { | 58 | export default { |
59 | name: 'Login', | 59 | name: 'Login', |
60 | data() { | 60 | data() { |
61 | const validateUsername = (rule, value, callback) => { | 61 | const validateUsername = (rule, value, callback) => { |
62 | if (!validUsername(value)) { | 62 | if (!validUsername(value)) { |
63 | callback(new Error('Please enter the correct user name')) | 63 | callback(new Error('Please enter the correct user name')) |
64 | } else { | 64 | } else { |
65 | callback() | 65 | callback() |
66 | } | 66 | } |
67 | } | 67 | } |
68 | const validatePassword = (rule, value, callback) => { | 68 | const validatePassword = (rule, value, callback) => { |
69 | if (value.length < 6) { | 69 | if (value.length < 6) { |
70 | callback(new Error('The password can not be less than 6 digits')) | 70 | callback(new Error('The password can not be less than 6 digits')) |
71 | } else { | 71 | } else { |
72 | callback() | 72 | callback() |
73 | } | 73 | } |
74 | } | 74 | } |
75 | return { | 75 | return { |
76 | loginForm: { | 76 | loginForm: { |
77 | username: 'admin', | 77 | username: 'admin', |
78 | password: '111111' | 78 | password: '111111' |
79 | }, | 79 | }, |
80 | loginRules: { | 80 | loginRules: { |
81 | username: [{ required: true, trigger: 'blur', validator: validateUsername }], | 81 | username: [{ required: true, trigger: 'blur', validator: validateUsername }], |
82 | password: [{ required: true, trigger: 'blur', validator: validatePassword }] | 82 | password: [{ required: true, trigger: 'blur', validator: validatePassword }] |
83 | }, | 83 | }, |
84 | loading: false, | 84 | loading: false, |
85 | passwordType: 'password', | 85 | passwordType: 'password', |
86 | redirect: undefined | 86 | redirect: undefined |
87 | } | 87 | } |
88 | }, | 88 | }, |
89 | watch: { | 89 | watch: { |
90 | $route: { | 90 | $route: { |
91 | handler: function(route) { | 91 | handler: function(route) { |
92 | this.redirect = route.query && route.query.redirect | 92 | this.redirect = route.query && route.query.redirect |
93 | }, | 93 | }, |
94 | immediate: true | 94 | immediate: true |
95 | } | 95 | } |
96 | }, | 96 | }, |
97 | methods: { | 97 | methods: { |
98 | showPwd() { | 98 | showPwd() { |
99 | if (this.passwordType === 'password') { | 99 | if (this.passwordType === 'password') { |
100 | this.passwordType = '' | 100 | this.passwordType = '' |
101 | } else { | 101 | } else { |
102 | this.passwordType = 'password' | 102 | this.passwordType = 'password' |
103 | } | 103 | } |
104 | this.$nextTick(() => { | 104 | this.$nextTick(() => { |
105 | this.$refs.password.focus() | 105 | this.$refs.password.focus() |
106 | }) | 106 | }) |
107 | }, | 107 | }, |
108 | handleLogin() { | 108 | handleLogin() { |
109 | this.$refs.loginForm.validate(valid => { | 109 | this.$refs.loginForm.validate(valid => { |
110 | if (valid) { | 110 | if (valid) { |
111 | this.loading = true | 111 | this.loading = true |
112 | this.$store.dispatch('user/login', this.loginForm).then(() => { | 112 | this.$store.dispatch('user/login', this.loginForm).then(() => { |
113 | this.$router.push({ path: this.redirect || '/' }) | 113 | this.$router.push({ path: this.redirect || '/' }) |
114 | this.loading = false | 114 | this.loading = false |
115 | }).catch(() => { | 115 | }).catch(() => { |
116 | this.loading = false | 116 | this.loading = false |
117 | }) | 117 | }) |
118 | } else { | 118 | } else { |
119 | console.log('error submit!!') | 119 | console.log('error submit!!') |
120 | return false | 120 | return false |
121 | } | 121 | } |
122 | }) | 122 | }) |
123 | } | 123 | } |
124 | } | 124 | } |
125 | } | 125 | } |
126 | </script> | 126 | </script> |
127 | 127 | ||
128 | <style lang="scss"> | 128 | <style lang="scss"> |
129 | /* 修复input 背景不协调 和光标变色 */ | 129 | /* 修复input 背景不协调 和光标变色 */ |
130 | /* Detail see https://github.com/PanJiaChen/vue-element-admin/pull/927 */ | 130 | /* Detail see https://github.com/PanJiaChen/vue-element-admin/pull/927 */ |
131 | 131 | ||
132 | $bg:#283443; | 132 | $bg:#283443; |
133 | $light_gray:#fff; | 133 | $light_gray:#fff; |
134 | $cursor: #fff; | 134 | $cursor: #fff; |
135 | 135 | ||
136 | @supports (-webkit-mask: none) and (not (cater-color: $cursor)) { | 136 | @supports (-webkit-mask: none) and (not (cater-color: $cursor)) { |
137 | .login-container .el-input input { | 137 | .login-container .el-input input { |
138 | color: $cursor; | 138 | color: $cursor; |
139 | } | 139 | } |
140 | } | 140 | } |
141 | 141 | ||
142 | /* reset element-ui css */ | 142 | /* reset element-ui css */ |
143 | .login-container { | 143 | .login-container { |
144 | .el-input { | 144 | .el-input { |
145 | display: inline-block; | 145 | display: inline-block; |
146 | height: 47px; | 146 | height: 47px; |
147 | width: 85%; | 147 | width: 85%; |
148 | 148 | ||
149 | input { | 149 | input { |
150 | background: transparent; | 150 | background: transparent; |
151 | border: 0px; | 151 | border: 0px; |
152 | -webkit-appearance: none; | 152 | -webkit-appearance: none; |
153 | border-radius: 0px; | 153 | border-radius: 0px; |
154 | padding: 12px 5px 12px 15px; | 154 | padding: 12px 5px 12px 15px; |
155 | color: $light_gray; | 155 | color: $light_gray; |
156 | height: 47px; | 156 | height: 47px; |
157 | caret-color: $cursor; | 157 | caret-color: $cursor; |
158 | 158 | ||
159 | &:-webkit-autofill { | 159 | &:-webkit-autofill { |
160 | box-shadow: 0 0 0px 1000px $bg inset !important; | 160 | box-shadow: 0 0 0px 1000px $bg inset !important; |
161 | -webkit-text-fill-color: $cursor !important; | 161 | -webkit-text-fill-color: $cursor !important; |
162 | } | 162 | } |
163 | } | 163 | } |
164 | } | 164 | } |
165 | 165 | ||
166 | .el-form-item { | 166 | .el-form-item { |
167 | border: 1px solid rgba(255, 255, 255, 0.1); | 167 | border: 1px solid rgba(255, 255, 255, 0.1); |
168 | background: rgba(0, 0, 0, 0.1); | 168 | background: rgba(0, 0, 0, 0.1); |
169 | border-radius: 5px; | 169 | border-radius: 5px; |
170 | color: #454545; | 170 | color: #454545; |
171 | } | 171 | } |
172 | } | 172 | } |
173 | </style> | 173 | </style> |
174 | 174 | ||
175 | <style lang="scss" scoped> | 175 | <style lang="scss" scoped> |
176 | $bg:#2d3a4b; | 176 | $bg:#2d3a4b; |
177 | $dark_gray:#889aa4; | 177 | $dark_gray:#889aa4; |
178 | $light_gray:#eee; | 178 | $light_gray:#eee; |
179 | 179 | ||
180 | .login-container { | 180 | .login-container { |
181 | min-height: 100%; | 181 | min-height: 100%; |
182 | width: 100%; | 182 | width: 100%; |
183 | background-color: $bg; | 183 | background-color: $bg; |
184 | overflow: hidden; | 184 | overflow: hidden; |
185 | 185 | ||
186 | .login-form { | 186 | .login-form { |
187 | position: relative; | 187 | position: relative; |
188 | width: 520px; | 188 | width: 520px; |
189 | max-width: 100%; | 189 | max-width: 100%; |
190 | padding: 160px 35px 0; | 190 | padding: 160px 35px 0; |
191 | margin: 0 auto; | 191 | margin: 0 auto; |
192 | overflow: hidden; | 192 | overflow: hidden; |
193 | } | 193 | } |
194 | 194 | ||
195 | .tips { | 195 | .tips { |
196 | font-size: 14px; | 196 | font-size: 14px; |
197 | color: #fff; | 197 | color: #fff; |
198 | margin-bottom: 10px; | 198 | margin-bottom: 10px; |
199 | 199 | ||
200 | span { | 200 | span { |
201 | &:first-of-type { | 201 | &:first-of-type { |
202 | margin-right: 16px; | 202 | margin-right: 16px; |
203 | } | 203 | } |
204 | } | 204 | } |
205 | } | 205 | } |
206 | 206 | ||
207 | .svg-container { | 207 | .svg-container { |
208 | padding: 6px 5px 6px 15px; | 208 | padding: 6px 5px 6px 15px; |
209 | color: $dark_gray; | 209 | color: $dark_gray; |
210 | vertical-align: middle; | 210 | vertical-align: middle; |
211 | width: 30px; | 211 | width: 30px; |
212 | display: inline-block; | 212 | display: inline-block; |
213 | } | 213 | } |
214 | 214 | ||
215 | .title-container { | 215 | .title-container { |
216 | position: relative; | 216 | position: relative; |
217 | 217 | ||
218 | .title { | 218 | .title { |
219 | font-size: 26px; | 219 | font-size: 26px; |
220 | color: $light_gray; | 220 | color: $light_gray; |
221 | margin: 0px auto 40px auto; | 221 | margin: 0px auto 40px auto; |
222 | text-align: center; | 222 | text-align: center; |
223 | font-weight: bold; | 223 | font-weight: bold; |
224 | } | 224 | } |
225 | } | 225 | } |
226 | 226 | ||
227 | .show-pwd { | 227 | .show-pwd { |
228 | position: absolute; | 228 | position: absolute; |
229 | right: 10px; | 229 | right: 10px; |
230 | top: 7px; | 230 | top: 7px; |
231 | font-size: 16px; | 231 | font-size: 16px; |
232 | color: $dark_gray; | 232 | color: $dark_gray; |
233 | cursor: pointer; | 233 | cursor: pointer; |
234 | user-select: none; | 234 | user-select: none; |
235 | } | 235 | } |
236 | } | 236 | } |
237 | </style> | 237 | </style> |
238 | 238 |