本网站的架构(四)vue实现后台管理

 0 0条评论

网站的后台管理系统,使用的是vue框架,不过当时使用的还是vue2.0,并未使用3.0。服务端的API上一节已经讲过,使用node开发的。

UI使用的element框架,也是非常简单友好的一套vue的UI框架,基本上也不用再自己设置什么样式了。

一,封装axios

数据通讯必须使用ajax实现,自然要使用到axios框架,对于常用的第三方框架,通常都要自己再封装一层

1,万一以后项目更改或者框架不稳定了,可以直接修改自己的封装层即可

2,自己封装的代码里,可以增加拦截器、验证等功能。

我这里主要是每次发出请求时,都需要从本地调用token,然后放入header发送给服务端,如果token错误,服务端则会给出相应的错误代码,如果没有错误,则继续执行ajax请求,代码如下:

import axios from 'axios'
import qs from 'qs'
import Vue from 'vue'
import Router from '../router'
import clear from 'utils/clear'
const ajax = axios.create({
  baseURL: 'https://api.shuanghei.com',
  timeout: 5000,
  withCredentials: false,
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded'
  }
})
ajax.defaults.transformRequest = (data) =>
  qs.stringify(data) 
  // , { arrayFormat: 'brackets' }, { indices: false } 暂时不需要
ajax.interceptors.request.use(
  (config) => {
    const token = window.localStorage.getItem('access_token')
    config.headers.authorization = token // 请求时添加coken
    return config
  },
  (err) => {
    return Promise.reject(err)
  }
)

ajax.interceptors.response.use(
  (res) => {
    return res.data
  },
  (err) => {
    // 这里可以预处理错误
    if (err.response.status === 401) {
      const { code } = err.response.data
      if (code === 10007) {
        // 此code是服务端 返回得错误编号,固定死
        clear()
        Router.push('/login')
        Vue.prototype.$message.error('帐号已在别处登录')
        return
      }
      if (code === 10006) {
        clear()
        Router.push('/login')
        Vue.prototype.$message.error('帐号已被管理员强制下线')
        return
      }
      if (code === 10003) {
        clear()
        Router.push('/login')
        Vue.prototype.$message.error('已超时,请重新登录')
        return
      }
    }
    return Promise.reject(err.response.data)
  }
)
export default ajax

二,自定义组件

项目中很多组件都需要重用,比如左边的树形菜单、面包屑导航、table的某些列等,这里就说说列吧。


绝大部分页面,都会有以上这些列,我本来是想把这几个列合成一个完成的自定义组件的,后来发现element2.0下,会出现排列错乱的问题,不知道现在3.0解决了没,那么我就把每一个列创建一个自定义组件,如下图:


我们就以createuser列为例吧,CreateUser.vue代码如下:

<template>
  <el-table-column prop="createUser"
                   label="创建人"
                   :width="width">
  </el-table-column>
</template>
<script>
export default {
  props: {
    width: {
      type: String,
      default: '100'
    }
  }
}
</script>

index.js代码如下,进行组件的安装:

import Component from './CreateUser'
export default {
  install: function (Vue) {
    Vue.component('col-createuser', Component)
  }
}

三,权限控制

这一块还是比较麻烦的,分三块

1,左侧菜单栏,是否显示相对应的链接

2,用户直接输入url,要在页面当前判断是否有权限进入

3,页面中的增删改button的判断,是否显示

用户在登陆的时候,如果登陆成功,则会从服务端返回相对应的权限列表,加密后保存到本地储存,代码如下:

.then((res) => {
    window.sessionStorage.setItem('apiid', res.data._id) // 只保留session
    window.sessionStorage.setItem('apikey', encrypt(res.data.apikey))
    window.sessionStorage.setItem('username', this.loginForm.name)
    window.sessionStorage.setItem('menuList', encrypt(res.data.menuList)) // 菜单
    window.sessionStorage.setItem('routerList', encrypt(res.data.routerList))// 每个路由的增删改
    window.sessionStorage.setItem('UIrouter', encrypt(res.data.UIrouter))// 是否有路由的入口
    window.sessionStorage.setItem('RoleList', encrypt(res.data.rolenameList))// 用户角色
    this.$router.push('/welcome')
          })

左侧菜单栏,则根据res.data.menuList来加载。

每个页面的路由控制,我会在router.beforeEach里判断,核心代码如下:

router.beforeEach((to, from, next) => {
  document.title = to.meta.title
  if (to.path === '/login') {
    return next()
  } else {
    if (
      !window.sessionStorage.getItem('apiid') ||
      !window.sessionStorage.getItem('apikey')
    ) {
      clear()
      return next('/login') 
      // 如果本地没有存储apikey,那就要用户强制登录,页面只要关闭就要重新登录
    }
  }
  if (!window.localStorage.getItem('access_token')) {
    refreshToken(next)
  } else {
    const createtime = Number.parseInt(
      window.localStorage.getItem('createtime')
    )
    const expiresIn = Number.parseInt(window.localStorage.getItem('expiresIn'))
    const currtime = Math.floor(Date.now() / 1000)
    if (expiresIn + createtime < currtime + expiresIn / 2) {
      // 如果超过一半时间
      refreshToken(next)
    } else {
      const UIrouter = JSON.parse(
        decrypt(window.sessionStorage.getItem('UIrouter'))
      ) // 判断用户是有此路由的权限,避免用户直接输入浏览器访问
      if (to.path.toLowerCase() === '/welcome' || UIrouter.includes(to.path)) {
        next()
      } else {
        Vue.prototype.$message.warning('非法进入')
        clear()
        next('/login')
      }
    }
  }
})

最后,页面中,button是否显示,我使用了一个mixins,代码如下:

import { decrypt } from 'utils/crypto'

export default {
  computed: {
    isDisable () {
      return function (model, method) {
        const item = JSON.parse(
          decrypt(window.sessionStorage.getItem('routerList'))
        ).find((n) => {
          return n.model === model
        })
        if (item) {
          return !item.methods.includes(method)
        }
        return true
      }
    }
  }
}

本文作者:双黑

版权声明:本站文章欢迎链接分享,禁止全文转载!

游客