后台管理系统 一 登录模块
目录
[TOC]
项目地址
模板介绍
GitHub - PanJiaChen/vue-admin-template: a vue2.0 minimal admin template
项目目录
build:inde.jswebpack配置文件【很少修改这个文件】
mock: 数据文件夹【模拟一些假的数据】
node-modules: 项目依赖
public: icon图标 静态页面 静态资源 webpack不会编译这个文件夹
src程序源码
api: 涉及请求相关的
assets:放置静态资源(一般是共享的)webpack会进行编译
component:非路由组件,全局组组件
icons: svg矢量图
layout:组件与混入
router:路由相关
store vuex
style:样式
utils: 公共类库 axios的二次封装
views: 路由文件夹
app:根组件
main 入口文件
permission:导航守卫
settings:项目配置项
环境变量
设置webpack配置文件 运行时可以检测环境(webpack对外暴露了 process可以拿到 env为环境变量。设置的值必须VUE_APP开头)
# just a flag
ENV = 'development'
# base api
VUE_APP_BASE_API = '/dev-api'
分环境加网络请求前缀
// create an axios instance
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
// withCredentials: true, // send cookies when cross-domain requests
timeout: 5000 // request timeout
})
- .env.development 开发
- .env.production 生产
- .env.staging 测试
- process.env读取环境变量
- 设置文件时值必须以VUE_APP开头
登录业务
完成静态组件
handleLogin() {
//验证用户名和密码的规则
this.$refs.loginForm.validate((valid) => {
// 符合派发登录接口携带数据
if (valid) {
this.loading = true;
this.$store
.dispatch("user/login", this.loginForm)
.then(() => {
this.$router.push({ path: this.redirect || "/" });
this.loading = false;
})
.catch(() => {
this.loading = false;
});
} else {
console.log("error submit!!");
return false;
}
});
},
vuex
const getDefaultState = () => {
return {
token: getToken(),
name: '',
avatar: ''
}
}
const state = getDefaultState()
const mutations = {
RESET_STATE: (state) => {
Object.assign(state, getDefaultState())
},
SET_TOKEN: (state, token) => {
state.token = token
},
}
const actions = {
// user login
async login({ commit }, userInfo) {
const { username, password } = userInfo
let result = await login({ username: username.trim(), password: password })
if (result.code == 20000) {
commit('SET_TOKEN', result.data.token)
setToken(result.data.token)
return 'ok'
} else {
return Promise.reject(new Error('false'))
}
// return new Promise((resolve, reject) => {
// login({ username: username.trim(), password: password }).then(response => {
// const { data } = response
// commit('SET_TOKEN', data.token)
// setToken(data.token)
// resolve()
// }).catch(error => {
// reject(error)
// })
// })
},
}
export default {
namespaced: true,
state,
mutations,
actions
}
'js-cookie'第三方库
下载cookie
npm install js-cookie
当前页面引用cookie
import Cookies from "js-cookie";
cookie在当前的使用
// 写入cookie
Cookies.set('name', 'value')
// 读取
Cookies.get('name') // => 'value'
Cookies.get('nothing') // => undefined
// 读取所有可见的cookie
Cookies.get()
// 删除某项cookie值
Cookies.remove('name')
// 删除存了指定页面path的cookie
Cookies.remove('name', { path: '' });
cookie设置过期时间
Cookies.set('key', 'value', { expires: 27 });//创建有效期为27天的cookie
Cookies.set('key', 'value', { expires: 17, path: '' }); //可以通过配置path,为当前页创建有效期7天的cookie
业务需要在前端进行数据的缓存,到期就删除再进行获取新数据。
前端设置数据定时失效的可以有下面2种方法:
1、当数据较大时,可以利用localstorage,存数据时候写入一个时间,获取的时候再与当前时间进行比较
2、如果数据不超过cookie的限制大小,可以利用cookie比较方便,直接设置有效期即可
利用localstorage实现:步骤
1.存储数据时加上时间戳
在项目开发中,我们可以写一个公用的方法来进行存储的时候加上时间戳
//export抛出
export function setLocalStorageAndTime (key, value) {
window.localStorage.setItem(key, JSON.stringify({ data: value, time: new Date().getTime() }))
}
存储、
// 有数据再进行存储
setLocalStorageAndTime('XXX', {name: 'XXX'})
读取、
// 判断是否返回为null或者失效
getLocalStorageAndTime('XXX', 86400000)
获取数据时与当前时间进行比较、
export function getLocalStorageAndTime (key, exp = 86400000) {
// 获取数据
let data = window.localStorage.getItem(key)
if (!data) return null
let dataObj = JSON.parse(data)
// 与过期时间比较
if (new Date().getTime() - dataObj.time > exp) {
// 过期删除返回null
removeLocalStorage(key)
console.log('信息已过期')
return null
} else {
return dataObj.data
}
}
利用cookie实现
Cookies.set('name', 'value', { expires: 7 }); // 7 天后失效
//官方文档只要设置天数,没有时分秒,这样我们想设置更小单位的时候无法下手,其实也可以设置时间戳来处理时间的,下面这种方式可以设置任意单位的有效期:
let seconds = 10;
let expires = new Date(new Date() * 1 + seconds * 1000);
Cookies.set('username', 'tanggaowei', { expires: expires }); // 10 秒后失效
import Cookies from 'js-cookie'
/*
* 设置cookies
* */
export function getCookies (key) {
return Cookies.get(key)
}
/*
* 设置Cookies
* */
export function setCookies (key, value, expiresTime) {
let seconds = expiresTime
let expires = new Date(new Date() * 1 + seconds * 1000)
return Cookies.set(key, value, { expires: expires })
}
/*
* 移除Cookies
* */
export function removeCookies (key) {
return Cookies.remove(key)
}
代码
import Cookies from 'js-cookie'
const TokenKey = 'vue_admin_template_token'
export function getToken() {
return Cookies.get(TokenKey)
}
export function setToken(token) {
return Cookies.set(TokenKey, token)
}
export function removeToken() {
return Cookies.remove(TokenKey)
}
书写api
import request from '@/utils/request'
export function login(data) {
return request({
url: '/admin/acl/index/login',
method: 'post',
data
})
}
export function getInfo(token) {
return request({
url: '/admin/acl/index/info',
method: 'get',
params: { token }
})
}
export function logout() {
return request({
url: '/admin/acl/index/logout',
method: 'post'
})
}
axios的二次封装
import axios from 'axios'
import { MessageBox, Message } from 'element-ui'
import store from '@/store'
import { getToken } from '@/utils/auth'
// create an axios instance
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
// withCredentials: true, // send cookies when cross-domain requests
timeout: 5000 // request timeout
})
// 请求拦截器,携带的token字段
service.interceptors.request.use(
config => {
// do something before request is sent
if (store.getters.token) {
// let each request carry token
// ['X-Token'] is a custom headers key
// please modify it according to the actual situation
config.headers['token'] = getToken()
}
return config
},
error => {
// do something with request error
console.log(error) // for debug
return Promise.reject(error)
}
)
//响应拦截器
service.interceptors.response.use(
/**
* If you want to get http information such as headers or status
* Please return response => response
*/
/**
* Determine the request status by custom code
* Here is just an example
* You can also judge the status by HTTP Status Code
*/
response => {
const res = response.data
// 服务器响应失败
if (res.code !== 20000 && res.code !== 200) {
Message({
message: res.message || 'Error',
type: 'error',
duration: 5 * 1000
})
// 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;
if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
// to re-login
MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', {
confirmButtonText: 'Re-Login',
cancelButtonText: 'Cancel',
type: 'warning'
}).then(() => {
store.dispatch('user/resetToken').then(() => {
location.reload()
})
})
}
return Promise.reject(new Error(res.message || 'Error'))
} else {
// 成功
return res
}
},
error => {
console.log('err' + error) // for debug
Message({
message: error.message,
type: 'error',
duration: 5 * 1000
})
return Promise.reject(error)
}
)
export default service
解决代理跨域问题
在vue.config.js中 配置devServer
devServer: {
port: port,
open: true,
overlay: {
warnings: false,
errors: true
},
//配置代理
proxy: {
"/dev-api": {
target: "http://gmall-h5-api.atguigu.cn",
pathRewrite: { "^/dev-api": "" }
}
}
},
退出登录
组件中派发任务
async logout() {
await this.$store.dispatch("user/logout");
this.$router.push(`/login?redirect=${this.$route.fullPath}`);
},
},
vuex清除token
const getDefaultState = () => {
return {
token: getToken(),
name: '',
avatar: ''
}
}
const state = getDefaultState()
const mutations = {
RESET_STATE: (state) => {
Object.assign(state, getDefaultState())
},
}
logout({ commit, state }) {
return new Promise((resolve, reject) => {
logout(state.token).then(() => {
removeToken() // must remove token first
resetRouter()
commit('RESET_STATE')
resolve()
}).catch(error => {
reject(error)
})
})
},