vue项目创建
1.安装node
https://nodejs.org/en/
2.安装cnpm
$ npm install -g cnpm --registry=https://registry.npm.taobao.org
3.安装vue脚手架
npm install -g @vue/cli
4.创建projectname项目, 按需求选择
vue-cli 用的是 npm 源,只要设置 npm:npm config set registry https://registry.npm.taobao.org
(Babel、Router、Vuex、css Pre-processors、Linter/Formatter)
vue create projectname
↑ vue项目创建成功
vue项目初始化
import Vue from 'vue'
import axios from 'axios'
import store from '@/store'
import notification from 'ant-design-vue/es/notification'
import {
ACCESS_TOKEN } from '@/store/mutation-types'
// 创建 axios 实例
const service = axios.create({
baseURL: process.env.VUE_APP_API_BASE_URL, // api base_url
timeout: 6000 // 请求超时时间
})
const err = (error) => {
if (error.response) {
const data = error.response.data
const token = Vue.ls.get(ACCESS_TOKEN)
if (error.response.status === 403) {
notification.error({
message: 'Forbidden',
description: data.message
})
}
if (error.response.status === 401 && !(data.result && data.result.isLogin)) {
notification.error({
message: 'Unauthorized',
description: 'Authorization verification failed'
})
if (token) {
store.dispatch('Logout').then(() => {
setTimeout(() => {
window.location.reload()
}, 1500)
})
}
}
}
return Promise.reject(error)
}
// request interceptor
service.interceptors.request.use(config => {
const token = Vue.ls.get(ACCESS_TOKEN)
if (token) {
config.headers['Access-Token'] = token // 让每个请求携带自定义 token 请根据实际情况自行修改
}
return config
}, err)
// response interceptor
service.interceptors.response.use((response) => {
return response.data
}, err)
2.在utils目录里面新建permission.js文件
import Vue from 'vue'
import router from './router'
import store from './store'
import NProgress from 'nprogress' // progress bar
import '@/components/NProgress/nprogress.less' // progress bar custom style
import notification from 'ant-design-vue/es/notification'
import {
setDocumentTitle, domTitle } from '@/utils/domUtil'
import {
ACCESS_TOKEN } from '@/store/mutation-types'
NProgress.configure({
showSpinner: false }) // NProgress Configuration
const whiteList = ['login', 'register', 'registerResult'] // no redirect whitelist
const defaultRoutePath = '/dashboard/workplace'
router.beforeEach((to, from, next) => {
NProgress.start() // start progress bar
to.meta && (typeof to.meta.title !== 'undefined' && setDocumentTitle(`${
to.meta.title} - ${
domTitle}`))
if (Vue.ls.get(ACCESS_TOKEN)) {
/* has token */
if (to.path === '/user/login') {
next({
path: defaultRoutePath })
NProgress.done()
} else {
if (store.getters.roles.length === 0) {
store
.dispatch('GetInfo')
.then(res => {
const roles = res.result && res.result.role
store.dispatch('GenerateRoutes', {
roles }).then(() => {
// 根据roles权限生成可访问的路由表
// 动态添加可访问路由表
router.addRoutes(store.getters.addRouters)
// 请求带有 redirect 重定向时,登录自动重定向到该地址
const redirect = decodeURIComponent(from.query.redirect || to.path)
if (to.path === redirect) {
// hack方法 确保addRoutes已完成 ,set the replace: true so the navigation will not leave a history record
next({
...to, replace: true })
} else {
// 跳转到目的路由
next({
path: redirect })
}
})
})
.catch(() => {
notification.error({
message: '错误',
description: '请求用户信息失败,请重试'
})
store.dispatch('Logout').then(() => {
next({
path: '/user/login', query: {
redirect: to.fullPath } })
})
})
} else {
next()
}
}
} else {
if (whiteList.includes(to.name)) {
// 在免登录白名单,直接进入
next()
} else {
next({
path: '/user/login', query: {
redirect: to.fullPath } })
NProgress.done() // if current page is login will not trigger afterEach hook, so manually handle it
}
}
})
router.afterEach(() => {
NProgress.done() // finish progress bar
})
3.router目录里面的index.js 增加代码
const originalPush = Router.prototype.push
Router.prototype.push = function push (location, onResolve, onReject) {
if (onResolve || onReject) return originalPush.call(this, location, onResolve, onReject)
return originalPush.call(this, location).catch(err => err)
}
请求配置
const api = {
Login: '/auth/login',
Logout: '/auth/logout',
ForgePassword: '/auth/forge-password',
Register: '/auth/register',
twoStepCode: '/auth/2step-code',
SendSms: '/account/sms',
SendSmsErr: '/account/sms_err',
// get my info
UserInfo: '/user/info'
}
export default api
2.在api目录,新增login.js文件
import api from './index'
import {
axios } from '@/utils/request'
/**
* login func
* parameter: {
* username: '',
* password: '',
* remember_me: true,
* captcha: '12345'
* }
* @param parameter
* @returns {
*}
*/
export function login (parameter) {
return axios({
url: '/auth/login',
method: 'post',
data: parameter
})
}
export function getSmsCaptcha (parameter) {
return axios({
url: api.SendSms,
method: 'post',
data: parameter
})
}
export function getInfo () {
return axios({
url: '/user/info',
method: 'get',
headers: {
'Content-Type': 'application/json;charset=UTF-8'
}
})
}
权限控制
1.路由权限控制
import {
asyncRouterMap, constantRouterMap } from '@/config/router.config'
/**
* 过滤账户是否拥有某一个权限,并将菜单从加载列表移除
*
* @param permission
* @param route
* @returns {
boolean}
*/
function hasPermission (permission, route) {
if (route.meta && route.meta.permission) {
let flag = false
for (let i = 0, len = permission.length; i < len; i++) {
flag = route.meta.permission.includes(permission[i])
if (flag) {
return true
}
}
return false
}
return true
}
/**
* 单账户多角色时,使用该方法可过滤角色不存在的菜单
*
* @param roles
* @param route
* @returns {
*}
*/
// eslint-disable-next-line
function hasRole(roles, route) {
if (route.meta && route.meta.roles) {
return route.meta.roles.includes(roles.id)
} else {
return true
}
}
function filterAsyncRouter (routerMap, roles) {
const accessedRouters = routerMap.filter(route => {
if (hasPermission(roles.permissionList, route)) {
if (route.children && route.children.length) {
route.children = filterAsyncRouter(route.children, roles)
}
return true
}
return false
})
return accessedRouters
}
const permission = {
state: {
routers: constantRouterMap,
addRouters: []
},
mutations: {
SET_ROUTERS: (state, routers) => {
state.addRouters = routers
state.routers = constantRouterMap.concat(routers)
}
},
actions: {
GenerateRoutes ({
commit }, data) {
return new Promise(resolve => {
const {
roles } = data
console.log(roles)
const accessedRouters = filterAsyncRouter(asyncRouterMap, roles)
commit('SET_ROUTERS', accessedRouters)
resolve()
})
}
}
}
export default permission
2.按钮权限控制
import Vue from 'vue'
import store from '@/store'
/**
* Action 权限指令
* 指令用法:
* - 在需要控制 action 级别权限的组件上使用 v-action:[method] , 如下:
* <i-button v-action:add >添加用户</a-button>
* <a-button v-action:delete>删除用户</a-button>
* <a v-action:edit @click="edit(record)">修改</a>
*
* - 当前用户没有权限时,组件上使用了该指令则会被隐藏
* - 当后台权限跟 pro 提供的模式不同时,只需要针对这里的权限过滤进行修改即可
*
* @see https://github.com/sendya/ant-design-pro-vue/pull/53
*/
const action = Vue.directive('action', {
inserted: function (el, binding, vnode) {
const actionName = binding.arg
const roles = store.getters.roles
const elVal = vnode.context.$route.meta.permission
const permissionId = elVal instanceof String && [elVal] || elVal
roles.permissions.forEach(p => {
if (!permissionId.includes(p.permissionId)) {
return
}
if (p.actionList && !p.actionList.includes(actionName)) {
el.parentNode && el.parentNode.removeChild(el) || (el.style.display = 'none')
}
})
}
})
export default action
跨域配置
新建vue.config.js,然后写入如下代码:
module.exports = {
devServer: {
proxy: {
'/admin': {
target: 'http//:www.baidu.com',
ws: true,
changeOrigin: true,
"pathRewrite": {
"^/admin": "/"
}
}
}
}
}