张恒

暂时加入假登录页,404页面,还未处理数据,将路由分离,其他更改见readme

...@@ -5,6 +5,7 @@ process.env.BABEL_ENV = 'renderer' ...@@ -5,6 +5,7 @@ process.env.BABEL_ENV = 'renderer'
5 const path = require('path') 5 const path = require('path')
6 const { dependencies } = require('../package.json') 6 const { dependencies } = require('../package.json')
7 const webpack = require('webpack') 7 const webpack = require('webpack')
8 +const config = require('../config')
8 9
9 const BabiliWebpackPlugin = require('babili-webpack-plugin') 10 const BabiliWebpackPlugin = require('babili-webpack-plugin')
10 const CopyWebpackPlugin = require('copy-webpack-plugin') 11 const CopyWebpackPlugin = require('copy-webpack-plugin')
...@@ -134,6 +135,9 @@ let rendererConfig = { ...@@ -134,6 +135,9 @@ let rendererConfig = {
134 plugins: [ 135 plugins: [
135 new VueLoaderPlugin(), 136 new VueLoaderPlugin(),
136 new MiniCssExtractPlugin({ filename: 'styles.css' }), 137 new MiniCssExtractPlugin({ filename: 'styles.css' }),
138 + new webpack.DefinePlugin({
139 + 'process.env': process.env.NODE_ENV === 'production' ? config.build.env : config.dev.env
140 + }),
137 new HtmlWebpackPlugin({ 141 new HtmlWebpackPlugin({
138 filename: 'index.html', 142 filename: 'index.html',
139 template: resolve('src/index.ejs'), 143 template: resolve('src/index.ejs'),
......
1 module.exports = { 1 module.exports = {
2 NODE_ENV: '"development"', 2 NODE_ENV: '"development"',
3 - BASE_API: '""' 3 + BASE_API: '"https://easy-mock.com/mock/5950a2419adc231f356a6636/vue-admin"'
4 } 4 }
......
...@@ -58,6 +58,7 @@ ...@@ -58,6 +58,7 @@
58 "element-ui": "^2.11.1", 58 "element-ui": "^2.11.1",
59 "js-cookie": "^2.2.0", 59 "js-cookie": "^2.2.0",
60 "nedb": "^1.8.0", 60 "nedb": "^1.8.0",
61 + "nprogress": "^0.2.0",
61 "vue": "^2.6.10", 62 "vue": "^2.6.10",
62 "vue-electron": "^1.0.6", 63 "vue-electron": "^1.0.6",
63 "vue-router": "^3.0.7", 64 "vue-router": "^3.0.7",
......
1 +import request from '@/utils/request'
2 +
3 +export function login (username, password) {
4 + return request({
5 + url: '/user/login',
6 + method: 'post',
7 + data: {
8 + username,
9 + password
10 + }
11 + })
12 +}
13 +
14 +export function getInfo (token) {
15 + return request({
16 + url: '/user/info',
17 + method: 'get',
18 + params: { token }
19 + })
20 +}
21 +
22 +export function logout () {
23 + return request({
24 + url: '/user/logout',
25 + method: 'post'
26 + })
27 +}
1 +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1564902100209" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="840" xmlns:xlink="http://www.w3.org/1999/xlink" width="300" height="300"><defs><style type="text/css"></style></defs><path d="M615.6 123.6h165.5L512 589.7 242.9 123.6H63.5L512 900.4l448.5-776.9z" fill="#41B883" p-id="841"></path><path d="M781.1 123.6H615.6L512 303 408.4 123.6H242.9L512 589.7z" fill="#34495E" p-id="842"></path></svg>
...\ No newline at end of file ...\ No newline at end of file
1 <template> 1 <template>
2 - <div class="menu-wrapper"> 2 + <div v-if="!item.hidden&&item.children" class="menu-wrapper">
3 - <template v-for="item in routes" v-if="!item.hidden&&item.children">
4 <router-link 3 <router-link
5 - v-if="hasOneShowingChildren(item.children) && !item.children[0].children&&!item.alwaysShow" 4 + v-if="hasOneShowingChild(item.children) && !onlyOneChild.children&&!item.alwaysShow"
6 - :to="item.path+'/'+item.children[0].path" 5 + :to="resolvePath(onlyOneChild.path)"
7 - :key="item.children[0].name"
8 > 6 >
9 <el-menu-item 7 <el-menu-item
10 - :index="item.path+'/'+item.children[0].path" 8 + :index="resolvePath(onlyOneChild.path)"
11 :class="{'submenu-title-noDropdown':!isNest}" 9 :class="{'submenu-title-noDropdown':!isNest}"
12 > 10 >
13 <svg-icon 11 <svg-icon
14 - v-if="item.children[0].meta&&item.children[0].meta.icon" 12 + v-if="onlyOneChild.meta&&onlyOneChild.meta.icon"
15 - :icon-class="item.children[0].meta.icon" 13 + :icon-class="onlyOneChild.meta.icon"
16 ></svg-icon> 14 ></svg-icon>
17 <span 15 <span
18 - v-if="item.children[0].meta&&item.children[0].meta.title" 16 + v-if="onlyOneChild.meta&&onlyOneChild.meta.title"
19 slot="title" 17 slot="title"
20 - >{{item.children[0].meta.title}}</span> 18 + >{{onlyOneChild.meta.title}}</span>
21 </el-menu-item> 19 </el-menu-item>
22 </router-link> 20 </router-link>
23 21
24 - <el-submenu v-else :index="item.name||item.path" :key="item.name"> 22 + <el-submenu v-else :index="item.name||item.path">
25 <template slot="title"> 23 <template slot="title">
26 <svg-icon v-if="item.meta&&item.meta.icon" :icon-class="item.meta.icon"></svg-icon> 24 <svg-icon v-if="item.meta&&item.meta.icon" :icon-class="item.meta.icon"></svg-icon>
27 <span v-if="item.meta&&item.meta.title" slot="title">{{item.meta.title}}</span> 25 <span v-if="item.meta&&item.meta.title" slot="title">{{item.meta.title}}</span>
...@@ -32,63 +30,84 @@ ...@@ -32,63 +30,84 @@
32 :is-nest="true" 30 :is-nest="true"
33 class="nest-menu" 31 class="nest-menu"
34 v-if="child.children&&child.children.length>0" 32 v-if="child.children&&child.children.length>0"
35 - :routes="[child]" 33 + :item="child"
36 :key="child.path" 34 :key="child.path"
35 + :base-path="resolvePath(child.path)"
37 ></sidebar-item> 36 ></sidebar-item>
38 37
39 - <router-link v-else :to="item.path+'/'+child.path" :key="child.name"> 38 + <router-link v-else :to="resolvePath(child.path)" :key="child.name">
40 - <el-menu-item :index="item.path+'/'+child.path"> 39 + <el-menu-item :index="resolvePath(child.path)">
41 <svg-icon v-if="child.meta&&child.meta.icon" :icon-class="child.meta.icon"></svg-icon> 40 <svg-icon v-if="child.meta&&child.meta.icon" :icon-class="child.meta.icon"></svg-icon>
42 <span v-if="child.meta&&child.meta.title" slot="title">{{child.meta.title}}</span> 41 <span v-if="child.meta&&child.meta.title" slot="title">{{child.meta.title}}</span>
43 </el-menu-item> 42 </el-menu-item>
44 </router-link> 43 </router-link>
45 </template> 44 </template>
46 </el-submenu> 45 </el-submenu>
47 - </template>
48 </div> 46 </div>
49 </template> 47 </template>
50 48
51 <script> 49 <script>
50 +import path from "path";
51 +
52 export default { 52 export default {
53 name: "SidebarItem", 53 name: "SidebarItem",
54 props: { 54 props: {
55 - routes: { 55 + // route配置json
56 - type: Array 56 + item: {
57 + type: Object,
58 + required: true
57 }, 59 },
58 isNest: { 60 isNest: {
59 type: Boolean, 61 type: Boolean,
60 default: false 62 default: false
63 + },
64 + basePath: {
65 + type: String,
66 + default: ""
61 } 67 }
62 }, 68 },
69 + data() {
70 + return {
71 + onlyOneChild: null
72 + };
73 + },
63 methods: { 74 methods: {
64 - hasOneShowingChildren(children) { 75 + hasOneShowingChild(children) {
65 const showingChildren = children.filter(item => { 76 const showingChildren = children.filter(item => {
66 - return !item.hidden; 77 + if (item.hidden) {
78 + return false;
79 + } else {
80 + this.onlyOneChild = item;
81 + return true;
82 + }
67 }); 83 });
68 if (showingChildren.length === 1) { 84 if (showingChildren.length === 1) {
69 return true; 85 return true;
70 } 86 }
71 return false; 87 return false;
88 + },
89 + resolvePath(...paths) {
90 + return path.resolve(this.basePath, ...paths);
72 } 91 }
73 } 92 }
74 }; 93 };
75 </script> 94 </script>
76 <style lang="scss" scoped> 95 <style lang="scss" scoped>
77 -@import '@/styles/color.scss'; 96 +@import "@/styles/color.scss";
78 .menu-wrapper { 97 .menu-wrapper {
79 /deep/ .el-menu-item, 98 /deep/ .el-menu-item,
80 .el-submenu__title { 99 .el-submenu__title {
81 height: 46px; 100 height: 46px;
82 line-height: 46px; 101 line-height: 46px;
83 } 102 }
84 - /deep/ a{ 103 + /deep/ a {
85 background-color: #ffc248; 104 background-color: #ffc248;
86 } 105 }
87 - /deep/ .el-menu-item.is-active{ 106 + /deep/ .el-menu-item.is-active {
88 margin-left: 8px; 107 margin-left: 8px;
89 - background-color: $Theme-color!important; 108 + background-color: $Theme-color !important;
90 } 109 }
91 - /deep/ .el-menu-item{ 110 + /deep/ .el-menu-item {
92 padding: 0 20px 0 12px; 111 padding: 0 20px 0 12px;
93 } 112 }
94 } 113 }
......
...@@ -9,15 +9,8 @@ ...@@ -9,15 +9,8 @@
9 :collapse="isCollapse" 9 :collapse="isCollapse"
10 active-text-color="#ffffff" 10 active-text-color="#ffffff"
11 > 11 >
12 - <div class="title" :class="{minititle:isCollapse}"> 12 + <Logo :collapse="isCollapse" />
13 - <!-- <svg-icon icon-class="logo" icon-name></svg-icon> --> 13 + <sidebar-item v-for="route in routes" :key="route.name" :item="route" :base-path="route.path"></sidebar-item>
14 - <el-image>
15 - <div slot="error" class="image-slot">
16 - 这是logo存放位置
17 - </div>
18 - </el-image>
19 - </div>
20 - <sidebar-item :routes="routes"></sidebar-item>
21 </el-menu> 14 </el-menu>
22 </scroll-bar> 15 </scroll-bar>
23 </template> 16 </template>
...@@ -26,9 +19,10 @@ ...@@ -26,9 +19,10 @@
26 import { mapGetters } from "vuex"; 19 import { mapGetters } from "vuex";
27 import SidebarItem from "./SidebarItem"; 20 import SidebarItem from "./SidebarItem";
28 import ScrollBar from "@/components/ScrollBar"; 21 import ScrollBar from "@/components/ScrollBar";
22 +import Logo from "./logo";
29 23
30 export default { 24 export default {
31 - components: { SidebarItem, ScrollBar }, 25 + components: { SidebarItem, ScrollBar, Logo },
32 computed: { 26 computed: {
33 ...mapGetters(["sidebar"]), 27 ...mapGetters(["sidebar"]),
34 routes() { 28 routes() {
......
1 +<template>
2 + <div class="sidebar-logo-container" :class="{'collapse':collapse}">
3 + <transition name="sidebarLogoFade">
4 + <router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/">
5 + <svg-icon icon-class="logo" class-name="sidebar-logo"></svg-icon>
6 + <div class="sidebar-title">{{ title }}</div>
7 + </router-link>
8 + <router-link v-else key="expand" class="sidebar-logo-link" to="/">
9 + <svg-icon icon-class="logo" class-name="sidebar-logo"></svg-icon>
10 + <div class="sidebar-title">{{ title }}</div>
11 + </router-link>
12 + </transition>
13 + </div>
14 +</template>
15 +
16 +<script>
17 +export default {
18 + name: "SidebarLogo",
19 + props: {
20 + collapse: {
21 + type: Boolean,
22 + required: true
23 + }
24 + },
25 + data() {
26 + return {
27 + title: "logo名称",
28 + };
29 + }
30 +};
31 +</script>
32 +
33 +<style rel="stylesheet/scss" lang="scss" scoped>
34 +.sidebarLogoFade-enter-active {
35 + transition: opacity .28s;
36 +}
37 +
38 +.sidebarLogoFade-enter,
39 +.sidebarLogoFade-leave-to {
40 + opacity: 0;
41 +}
42 +
43 +.sidebar-logo-container {
44 + position: relative;
45 + width: 100%;
46 + height: 61px;
47 + line-height: 61px;
48 + text-align: center;
49 + overflow: hidden;
50 + background-color: #ffffff;
51 +
52 + & > .sidebar-logo-link {
53 + height: 100%;
54 + width: 100%;
55 +
56 + & > .sidebar-logo {
57 + width: 32px;
58 + height: 32px;
59 + vertical-align: middle;
60 + margin-right: 12px;
61 + }
62 +
63 + & > .sidebar-title {
64 + display: inline-block;
65 + margin: 0;
66 + color: #333;
67 + font-weight: 600;
68 + line-height: 50px;
69 + font-size: 14px;
70 + font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif;
71 + vertical-align: middle;
72 + }
73 + }
74 +}
75 +.collapse {
76 + .sidebar-logo {
77 + margin-right: 0px !important;
78 + }
79 +}
80 +</style>
...\ No newline at end of file ...\ No newline at end of file
...@@ -32,7 +32,7 @@ export default { ...@@ -32,7 +32,7 @@ export default {
32 classObj() { 32 classObj() {
33 return { 33 return {
34 hideSidebar: !this.sidebar.opened, 34 hideSidebar: !this.sidebar.opened,
35 - openSidebar: this.sidebar.opened, 35 + openSidebar: this.sidebar.opened
36 }; 36 };
37 } 37 }
38 } 38 }
......
...@@ -8,6 +8,7 @@ import db from './api/operationalData' ...@@ -8,6 +8,7 @@ import db from './api/operationalData'
8 // 引用element 8 // 引用element
9 import ElementUI from 'element-ui' 9 import ElementUI from 'element-ui'
10 import 'element-ui/lib/theme-chalk/index.css' 10 import 'element-ui/lib/theme-chalk/index.css'
11 +import './permission'
11 12
12 import './icons' 13 import './icons'
13 import '@/styles/index.scss' 14 import '@/styles/index.scss'
......
1 +
2 +import router from './router'
3 +import store from './store'
4 +import NProgress from 'nprogress' // Progress 进度条
5 +import 'nprogress/nprogress.css'// Progress 进度条样式
6 +// import { Message } from 'element-ui'
7 +
8 +// const whiteList = ['/login'] // 不重定向白名单
9 +router.beforeEach((to, from, next) => {
10 + NProgress.start()
11 + if (store.getters.token) {
12 + if (to.path === '/login') {
13 + next({ path: '/' })
14 + NProgress.done()
15 + } else {
16 + // if (store.getters.roles.length === 0) {
17 + // store.dispatch('GetInfo').then(res => { // 拉取用户信息
18 + // next()
19 + // }).catch((err) => {
20 + // store.dispatch('FedLogOut').then(() => {
21 + // Message.error(err || '请重新登录')
22 + // next({ path: '/' })
23 + // })
24 + // })
25 + // } else {
26 + // next()
27 + // }
28 + }
29 + } else {
30 + // if (whiteList.indexOf(to.path) !== -1) {
31 + // next()
32 + // } else {
33 + // next('/login')
34 + // NProgress.done()
35 + // }
36 + next()
37 + NProgress.done()
38 + }
39 +})
40 +
41 +router.afterEach(() => {
42 + NProgress.done() // 结束Progress
43 +})
1 +import Layout from '../layout'
2 +const Login = () => import('@/views/login')
3 +const Notfound = () => import('@/views/404')
4 +/**
5 +* hidden: true if `hidden:true` will not show in the sidebar(default is false)
6 +* alwaysShow: true if set true, will always show the root menu, whatever its child routes length
7 +* if not set alwaysShow, only more than one route under the children
8 +* it will becomes nested mode, otherwise not show the root menu
9 +* redirect: noredirect if `redirect:noredirect` will no redirct in the breadcrumb
10 +* name:'router-name' the name is used by <keep-alive> (must set!!!)
11 +* meta : {
12 + title: 'title' the name show in submenu and breadcrumb (recommend set)
13 + icon: 'svg-name' the icon show in the sidebar,
14 + }
15 +**/
16 +
17 +/**
18 + * hidden: true 如果在模板中使用该选项,则不会在侧栏显示该路由(例如:Dashboard),如果是在第一个子路由中使用,侧栏则只显示第一个子路由的名字和图标(例如: Form)
19 + * alwaysShow: true 如果设置为true它则会始终显示根菜单,无视自路由长度,没有设置的话,就会折叠起来(不清楚为什么没有作用,可能是我写错位置了?)
20 + * redirect: noredirect 若设置为noredirect则顶部面包屑不能够为其重定向.
21 + * name:'router-name' 路由名称,此项为必须填写项
22 + * meta : {
23 + title: 'title' 这里的名字决定了面包屑和侧栏的名字
24 + icon: 'svg-name' 当你在svg文件夹内加入了你的图标,那么在这里填写图标名他就会显示在侧栏
25 + }
26 + **/
27 +export default [
28 + { path: '/login', component: Login, hidden: true },
29 + { path: '/404', component: Notfound, hidden: true },
30 + {
31 + path: '/',
32 + component: Layout,
33 + redirect: '/dashboard',
34 + name: 'Dashboard',
35 + hidden: true,
36 + children: [{
37 + path: 'dashboard',
38 + component: () => import('@/components/LandingPage')
39 + }]
40 + },
41 +
42 + {
43 + path: '/form',
44 + component: Layout,
45 + children: [
46 + {
47 + path: 'index',
48 + name: 'Form',
49 + component: () => import('@/views/form/index'),
50 + meta: { title: '表单', icon: 'form' }
51 + }
52 + ]
53 + }
54 +]
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 -import Layout from '../layout' 4 +import routerMap from './constantRouterMap'
5 -Vue.use(Router)
6 -/**
7 -* hidden: true if `hidden:true` will not show in the sidebar(default is false)
8 -* alwaysShow: true if set true, will always show the root menu, whatever its child routes length
9 -* if not set alwaysShow, only more than one route under the children
10 -* it will becomes nested mode, otherwise not show the root menu
11 -* redirect: noredirect if `redirect:noredirect` will no redirct in the breadcrumb
12 -* name:'router-name' the name is used by <keep-alive> (must set!!!)
13 -* meta : {
14 - title: 'title' the name show in submenu and breadcrumb (recommend set)
15 - icon: 'svg-name' the icon show in the sidebar,
16 - }
17 -**/
18 5
19 -/** 6 +Vue.use(Router)
20 - * hidden: true 如果在模板中使用该选项,则不会在侧栏显示该路由(例如:Dashboard),如果是在第一个子路由中使用,侧栏则只显示第一个子路由的名字和图标(例如: Form)
21 - * alwaysShow: true 如果设置为true它则会始终显示根菜单,无视自路由长度,没有设置的话,就会折叠起来(不清楚为什么没有作用,可能是我写错位置了?)
22 - * redirect: noredirect 若设置为noredirect则顶部面包屑不能够为其重定向.
23 - * name:'router-name' 路由名称,此项为必须填写项
24 - * meta : {
25 - title: 'title' 这里的名字决定了面包屑和侧栏的名字
26 - icon: 'svg-name' 当你在svg文件夹内加入了你的图标,那么在这里填写图标名他就会显示在侧栏
27 - }
28 - **/
29 7
30 export default new Router({ 8 export default new Router({
31 scrollBehavior: () => ({ y: 0 }), 9 scrollBehavior: () => ({ y: 0 }),
32 - routes: [ 10 + routes: routerMap
33 - {
34 - path: '/',
35 - component: Layout,
36 - redirect: '/dashboard',
37 - name: 'Dashboard',
38 - hidden: true,
39 - children: [{
40 - path: 'dashboard',
41 - component: () => import('@/components/LandingPage')
42 - }]
43 - },
44 -
45 - {
46 - path: '/form',
47 - component: Layout,
48 - children: [
49 - {
50 - path: 'index',
51 - name: 'Form',
52 - component: () => import('@/views/form/index'),
53 - meta: { title: '表单', icon: 'form' }
54 - }
55 - ]
56 - },
57 -
58 - { path: '*', redirect: '/404', hidden: true }
59 - ]
60 }) 11 })
......
1 import Vue from 'vue' 1 import Vue from 'vue'
2 import Vuex from 'vuex' 2 import Vuex from 'vuex'
3 3
4 +// 注释这个的原因是因为会导致vuex操作失败
4 // import { createPersistedState, createSharedMutations } from 'vuex-electron' 5 // import { createPersistedState, createSharedMutations } from 'vuex-electron'
5 6
6 import modules from './modules' 7 import modules from './modules'
...@@ -10,10 +11,10 @@ Vue.use(Vuex) ...@@ -10,10 +11,10 @@ Vue.use(Vuex)
10 11
11 export default new Vuex.Store({ 12 export default new Vuex.Store({
12 modules, 13 modules,
13 - getters, 14 + getters
14 // plugins: [ 15 // plugins: [
15 // createPersistedState(), 16 // createPersistedState(),
16 // createSharedMutations() 17 // createSharedMutations()
17 // ], 18 // ],
18 - strict: process.env.NODE_ENV !== 'production' 19 + // strict: process.env.NODE_ENV !== 'production'
19 }) 20 })
......
1 -// 记录的数值
2 -const Counter = {
3 - state: {
4 -
5 - },
6 -
7 - mutations: {
8 -
9 - },
10 -
11 - actions: {
12 -
13 - }
14 -}
15 -export default Counter
...@@ -2,7 +2,11 @@ ...@@ -2,7 +2,11 @@
2 * The file enables `@/store/index.js` to import all vuex modules 2 * The file enables `@/store/index.js` to import all vuex modules
3 * in a one-shot manner. There should not be any reason to edit this file. 3 * in a one-shot manner. There should not be any reason to edit this file.
4 */ 4 */
5 - 5 +/**
6 + * 如果没什么大问题的话,这里的js会默认将你的所有模块全部自动导出,
7 + * 没有什么意外无需更改这里的代码和外部的index代码,需要如果需要将值暴露给
8 + * getter的话,还请自行手动添加,它的弊端就是不能够再这里留空文件,不然就会出现Cannot read property 'getters' of undefined的控制台报错信息
9 + */
6 const files = require.context('.', false, /\.js$/) 10 const files = require.context('.', false, /\.js$/)
7 const modules = {} 11 const modules = {}
8 12
......
1 +import Cookies from 'js-cookie'
2 +
3 +const TokenKey = 'Admin-Token'
4 +
5 +export function getToken () {
6 + return Cookies.get(TokenKey)
7 +}
8 +
9 +export function setToken (token) {
10 + return Cookies.set(TokenKey, token)
11 +}
12 +
13 +export function removeToken () {
14 + return Cookies.remove(TokenKey)
15 +}
...@@ -9,6 +9,8 @@ const serves = axios.create({ ...@@ -9,6 +9,8 @@ const serves = axios.create({
9 9
10 // 设置请求发送之前的拦截器 10 // 设置请求发送之前的拦截器
11 serves.interceptors.request.use(config => { 11 serves.interceptors.request.use(config => {
12 + console.log(config)
13 + console.log(process.env)
12 // 设置发送之前数据需要做什么处理 14 // 设置发送之前数据需要做什么处理
13 return config 15 return config
14 }, err => Promise.reject(err)) 16 }, err => Promise.reject(err))
......
1 +/**
2 + * Created by jiachenpan on 16/11/18.
3 + */
4 +
5 +export function isvalidUsername (str) {
6 + const valid_map = ['admin', 'editor']
7 + return valid_map.indexOf(str.trim()) >= 0
8 +}
9 +
10 +/* 合法uri */
11 +export function validateURL (textval) {
12 + const urlregex = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/
13 + return urlregex.test(textval)
14 +}
15 +
16 +/* 小写字母 */
17 +export function validateLowerCase (str) {
18 + const reg = /^[a-z]+$/
19 + return reg.test(str)
20 +}
21 +
22 +/* 大写字母 */
23 +export function validateUpperCase (str) {
24 + const reg = /^[A-Z]+$/
25 + return reg.test(str)
26 +}
27 +
28 +/* 大小写字母 */
29 +export function validatAlphabets (str) {
30 + const reg = /^[A-Za-z]+$/
31 + return reg.test(str)
32 +}
1 +<template>
2 + <div class="login-container">
3 + <el-form
4 + class="login-form"
5 + autocomplete="on"
6 + :model="loginForm"
7 + :rules="loginRules"
8 + ref="loginForm"
9 + label-position="left"
10 + >
11 + <h3 class="title">vue-element-admin</h3>
12 + <el-form-item prop="username">
13 + <span class="svg-container svg-container_login">
14 + <svg-icon icon-class="user" />
15 + </span>
16 + <el-input
17 + name="username"
18 + type="text"
19 + v-model="loginForm.username"
20 + autocomplete="on"
21 + placeholder="用户名"
22 + />
23 + </el-form-item>
24 + <el-form-item prop="password">
25 + <span class="svg-container">
26 + <svg-icon icon-class="password"></svg-icon>
27 + </span>
28 + <el-input
29 + name="password"
30 + :type="pwdType"
31 + @keyup.enter.native="handleLogin"
32 + v-model="loginForm.password"
33 + autocomplete="on"
34 + placeholder="密码"
35 + ></el-input>
36 + <span class="show-pwd" @click="showPwd">
37 + <svg-icon icon-class="eye" />
38 + </span>
39 + </el-form-item>
40 + <el-form-item>
41 + <el-button
42 + type="primary"
43 + style="width:100%;"
44 + :loading="loading"
45 + @click.native.prevent="handleLogin"
46 + >登录</el-button>
47 + </el-form-item>
48 + <div class="tips">
49 + <span style="margin-right:20px;">username: admin</span>
50 + <span>password: admin</span>
51 + </div>
52 + </el-form>
53 + </div>
54 +</template>
55 +
56 +<script>
57 +import { isvalidUsername } from "@/utils/validate";
58 +import { login } from "@/api/login";
59 +export default {
60 + name: "login",
61 + data() {
62 + const validateUsername = (rule, value, callback) => {
63 + if (!isvalidUsername(value)) {
64 + callback(new Error("请输入正确的用户名"));
65 + } else {
66 + callback();
67 + }
68 + };
69 + const validatePass = (rule, value, callback) => {
70 + if (value.length < 5) {
71 + callback(new Error("密码不能小于5位"));
72 + } else {
73 + callback();
74 + }
75 + };
76 + return {
77 + loginForm: {
78 + username: "admin",
79 + password: "admin"
80 + },
81 + loginRules: {
82 + username: [
83 + { required: true, trigger: "blur", validator: validateUsername }
84 + ],
85 + password: [{ required: true, trigger: "blur", validator: validatePass }]
86 + },
87 + loading: false,
88 + pwdType: "password"
89 + };
90 + },
91 + methods: {
92 + showPwd() {
93 + if (this.pwdType === "password") {
94 + this.pwdType = "";
95 + } else {
96 + this.pwdType = "password";
97 + }
98 + },
99 + handleLogin() {
100 + this.loading = true;
101 + this.$refs.loginForm.validate(valid => {
102 + if (valid) {
103 + // this.$store.dispatch('Login', this.loginForm).then(() => {
104 + this.loading = false;
105 + this.$router.push({ path: "/" });
106 + // login(this.loginForm).then(res=>console.log(res))
107 + // }).catch(() => {
108 + // this.loading = false
109 + // })
110 + } else {
111 + console.log("输入错误");
112 + return false;
113 + }
114 + });
115 + }
116 + }
117 +};
118 +</script>
119 +
120 +<style rel="stylesheet/scss" lang="scss">
121 +$bg: #2d3a4b;
122 +$light_gray: #eee;
123 +
124 +/* reset element-ui css */
125 +.login-container {
126 + left: 0px;
127 + .el-input {
128 + display: inline-block;
129 + height: 47px;
130 + width: 85%;
131 + input {
132 + background: transparent;
133 + border: 0px;
134 + -webkit-appearance: none;
135 + border-radius: 0px;
136 + padding: 12px 5px 12px 15px;
137 + color: $light_gray;
138 + height: 47px;
139 + &:-webkit-autofill {
140 + -webkit-box-shadow: 0 0 0px 1000px $bg inset !important;
141 + -webkit-text-fill-color: #fff !important;
142 + }
143 + }
144 + }
145 + .el-form-item {
146 + border: 1px solid rgba(255, 255, 255, 0.1);
147 + background: rgba(0, 0, 0, 0.1);
148 + border-radius: 5px;
149 + color: #454545;
150 + }
151 +}
152 +</style>
153 +
154 +<style rel="stylesheet/scss" lang="scss" scoped>
155 +$bg: #2d3a4b;
156 +$dark_gray: #889aa4;
157 +$light_gray: #eee;
158 +.login-container {
159 + position: fixed;
160 + height: 100%;
161 + width: 100%;
162 + background-color: $bg;
163 + .login-form {
164 + position: absolute;
165 + left: 0;
166 + right: 0;
167 + width: 520px;
168 + padding: 35px 35px 15px 35px;
169 + margin: 120px auto;
170 + }
171 + .tips {
172 + font-size: 14px;
173 + color: #fff;
174 + margin-bottom: 10px;
175 + span {
176 + &:first-of-type {
177 + margin-right: 16px;
178 + }
179 + }
180 + }
181 + .svg-container {
182 + padding: 6px 5px 6px 15px;
183 + color: $dark_gray;
184 + vertical-align: middle;
185 + width: 30px;
186 + display: inline-block;
187 + &_login {
188 + font-size: 20px;
189 + }
190 + }
191 + .title {
192 + font-size: 26px;
193 + font-weight: 400;
194 + color: $light_gray;
195 + margin: 0px auto 40px auto;
196 + text-align: center;
197 + font-weight: bold;
198 + }
199 + .show-pwd {
200 + position: absolute;
201 + right: 10px;
202 + top: 7px;
203 + font-size: 16px;
204 + color: $dark_gray;
205 + cursor: pointer;
206 + user-select: none;
207 + }
208 +}
209 +</style>