With Vue-cli3 + element + mockjs rights management system to achieve the background and top-level menu bar display

I realized recently completed a back-end management system permissions feature, but think of all the menus are left-back system, limit the expansion of the menu, so I Improved display of three menus.

Achieve competence functions

Permissions route ideas: roles according to the routing information of the user login information roles in comparison filter configured to generate a routing table access, and access can dynamically add routing table router.addRoutes (store.getters.addRouters), in order to achieve show top and left side of the menu bar.

Implementation steps:

1. Set the default information to the respective roles of the menu

In the router / index.js in a corresponding menu setting information of default roles; as follows: for "permissions" permission set for menu: meta: {roles: [ 'admin', 'editor']}, and different roles can see; to its sub-menu "page permissions", set permissions: meta: {roles: [ 'admin']}, and said that only "admin" can see the menu; to its sub-menu "button authority "set permissions: meta: {roles: [ 'editor']}, and represents only the" Editor "can see the menu.

2. filtering and routing by intercepting authority router.beforeEach ();

code show as below:

// permission judge function
function hasPermission(roles, permissionRoles) {
  if (roles.indexOf('admin') >= 0) return true // admin permission passed directly
  if (!permissionRoles) return true
  return roles.some(role => permissionRoles.indexOf(role) >= 0)
}
const whiteList = ['/login'] // 不重定向白名单

router.beforeEach((to, from, next) => {
  NProgress.start()
   // 设置浏览器头部标题
   const browserHeaderTitle = to.meta.title
   store.commit('SET_BROWSERHEADERTITLE', {
     browserHeaderTitle: browserHeaderTitle
   })
  // 点击登录时,拿到了token并存入了vuex;
  if (getToken()) {
    /* has token*/
    if (store.getters.isLock && to.path !== '/lock') {
      next({
        path: '/lock'
      })
      NProgress.done()
    } else if (to.path === '/login') {
      next({ path: '/' })  // 会匹配到path:'',后面的path:'*'还没有生成;
      NProgress.done() 
    } else {
      if (store.getters.roles.length === 0) {
        store.dispatch('GetInfo').then(res => { // 拉取用户信息
          const roles = res.roles
          store.dispatch('GenerateRoutes', { roles }).then(() => { // 根据roles权限生成可访问的路由表
            router.addRoutes(store.getters.addRouters) // 动态添加可访问权限路由表
            next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
          })
        }).catch((err) => {
          store.dispatch('FedLogOut').then(() => {
            Message.error(err || 'Verification failed, please login again')
            next({ path: '/' })
          })
        })
      } else {
        // 没有动态改变权限的需求可直接next() 删除下方权限判断 ↓
        if (hasPermission(store.getters.roles, to.meta.roles)) {
          next()//
        } else {
          next({ path: '/401', replace: true, query: { noGoBack: true }})
        }
      }
    }
  } else {
    if (whiteList.indexOf(to.path) !== -1) {
      next()
    } else {
      // 点击退出时,会定位到这里
      next('/login')
      NProgress.done()
    }
  }
})

router.afterEach(() => {
  NProgress.done() // 结束Progress
  setTimeout(() => {
    const browserHeaderTitle = store.getters.browserHeaderTitle
    setTitle(browserHeaderTitle)
  }, 0)
})
复制代码

Business logic analysis after the user clicks the Login:

1, the transfer of logged user interfaces, token acquired, goto route;

2, the navigation route by hook router.beforeEach ((to, from, next) => {}) to determine the next jump logic function, as follows:

2.1、用户已经登录成功并返回token值;

 2.1.1、lock 锁屏场景;
 
 2.1.2、用户重新定位到登录页面;
 
  2.1.3、根据用户是否有roles信息,进行不同的业务逻辑,如下:
  
    (1)、初始情况下,用户roles信息为空;
        通过store.dispatch('GetInfo')调取接口,获取用户信息;
        获取到roles信息后,将roles,name,avatar保存到vuex;
        同时,通过store.dispatch('GenerateRoutes', { roles })去重新过滤和生成路由,并将重新生成之后的权限路由'routes'保存到vuex;
        最后,通过router.addRoutes()合并路由表;   
        如果在获取用户信息接口时,出现错误,则调取store.dispatch('FedLogOut')接口,返回到login页面;
        用户FedLogOut之后,需要情况vuex和localStorage中的token信息;
         
   (2)、用户已经拥有roles信息;
        点击页面路由,通过roles权限判断 hasPermission();
        如果用户有该路由权限,直接跳转对应的页面;如果没有权限,则跳转至401提示页面;

2.2、用户没有获取到token值;

  2.2.1、如果设置了白名单用户,则直接跳转到相应的页面;反之,则跳转至登录页面;
复制代码

3. The navigation route through the hook function router.afterEach (), do finishing work

as follows:

3.1、NProgress.done() // 结束Progress
3.2、获取到title并设置title;
复制代码

Details, please consult the src / permission.js

4. rights demonstration shows

Test account:

. (1) username: admin, password: 123456; admin has the highest authority, can view all of the pages and buttons;

. (2) username: editor, password: 123456; editor only given the authority pages and buttons can be seen;

Three navigation menu bar at the top shows

As shown, after the completion of the general background system has secondary navigation menu function, I find that a lot of back-end management system has three navigation menu, but if you regard the three-level menu stepped into the left-hand menu to do the arrangement will look more compact, so I think put all three into the top of the menu is a good choice.

1. Development needs:

Click on the left menu, find the menu (top menu bar) emissions to their corresponding top navigation bar;

2. The development steps:

1. Define the top navigation component topMenu.vue;

Performed by element-ui, NavMenu navigation menu display the top menu, note the difference between the top bar and the side bar provided; while being in reference to the head assembly headNav.vue;

2. Define the top bar routing data router / topRouter.js;

Format is as follows:

export const topRouterMap = [
    {
        'parentName':'infoShow',
        'topmenulist':[
            {
                path: 'infoShow1',
                name: 'infoShow1',
                meta: {
                    title: '个人信息子菜单1',
                    icon: 'fa-asterisk',
                    routerType: 'topmenu'
                },
                component: () => import('@/page/fundList/moneyData')
            }
        ]
    },
    {
        'parentName':'chinaTabsList',
        'topmenulist':[
            {
                path:'chinaTabsList1',
                name:'chinaTabsList1',
                meta:{
                    title:'区域投资子菜单1',
                    icon:'fa-asterisk',
                    routerType:'topmenu'
                },
                component: () => import('@/page/fundList/moneyData')
            }
        ]
    }
]
复制代码

Routing is defined as the total number of groups topRouterMap; to establish contact with the left side of the route by parentName; represents a value of the top field route by topmenulist; meta.routerType by value "topmenu" or "leftmenu" is a top field to distinguish between routes, or left route side;

3. Prepare headNav.vue rendering data;

Ideas: Click the menu on the left, corresponding to the top of the menu to be displayed. Because the left menu to establish contact and the top menu. We know that navigation menu when a user logs will be filtered according to the permissions of the user role information; after that, prior to filtration rights routing data, we can) all three menus to filter by adding addTopRouter (, the addition is complete, continue role filter can not have the authority to ensure that the top menu is also filtered out.

// 通过循环过滤,生成新的二级菜单
function addTopRouter(){
  asyncRouterMap.forEach( (item) => {
    if(item.children && item.children.length >= 1){
      item.children.forEach((sitem) => {
       topRouterMap.forEach((citem) => {
          if(sitem.name === citem.parentName){
              let newChildren = item.children.concat(citem.topmenulist);
              item.children = newChildren;
          }
       })
      })
    }
  })
  return asyncRouterMap;
}
复制代码
4. From the navigation route and displays the corresponding filtered data;

In topMenu.vue component, the user or the default come left menu trigger setLeftInnerMenu () function, as follows:

 setLeftInnerMenu(){
    if(this.$route.meta.routerType == 'leftmenu'){ // 点击的为 左侧的2级菜单
        this.$store.dispatch(''ClickLeftInnerMenu,
            {'name':this.$route.name}
        );
    }else{ // 点击顶部的菜单
        this.$store.dispatch('ClickTopMenu',
            {'title':this.$route.meta.title}
        );
    }
}
复制代码

By this route the this route.meta.routerType value judgment, the menu the user is still left click on the top menu.  If you click on the top menu through this.Store trigger asynchronous operation 'ClickLeftInnerMenu' passing the parameter 'name', vuex in = filterTopRouters (state.routers, data) by filtering the current routing information state.topRouters; code as follows:

// 获取到当前路由对应顶部子菜单
 function filterTopRouters(data){
    let topRouters = topRouterMap.find((item)=>{
       return item.parentName === data.name
    })
    if(!mutils.isEmpty(topRouters)){
       return topRouters.topmenulist;
    }
}
复制代码

topMenu.vue by computed: the corresponding routing data for display to the top {... mapGetters ([ 'topRouters'])}. Each time a user clicks on the left menu, top routes have been reassigned and rendering to ensure the accuracy of the data.

The top menu perfect;

When the data is top of the menu is too large, we need to set the horizontal scroll bar and set the scroll bar style. Figure:

Detailed mock data

Use easy-mock

1. the Easy Mock description:
  • Easy Mock is a visual, and can quickly generate analog data persistence services,
  • Easy Mock support Swagger create a project to save manually create interfaces based on time;
  • Simply put: Easy Mock is to create a mock online service platform, to help you save your configuration, installation, from services, maintenance, people do not cooperate Mock data exchange and a series of complex operation, it can do in one second in time for everything you want.

Detailed usage, contains an introduction and use of new projects, basic syntax, data placeholders, Swagger, etc., please refer to the detailed documentation

2.easy-mock, this project uses:
1. According to official documents, creating a personal project vue-touzi-admin;

According to project needs, has created an interface: the user logs Interface: "/ user / login"; obtaining user interface information: "/ user / info"; user logs off Interface: "/ user / logout"; get a list of all user interfaces: "/ user / getUserList"; FIG:

The login interface logic easy-mock end prepared as follows:

{
  code: function({
    _req
  }) {
    if (_req.body.username === "admin" || _req.body.username === "editor" && _req.body.password === "123456") {
      return 200
    } else {
      return -1
    }
  },
  message: function({
    _req
  }) {
    if (_req.body.username !== "admin" || _req.body.username !== "editor") {
      return "账号或密码有误!"
    }
  },
  data: function({
    _req
  }) {
    if (_req.body.username == "admin" && _req.body.password === "123456") {
      return {
        code: 0,
        roles: ['admin'],
        token: 'admin',
        introduction: '我是超级管理员',
        name: 'Super Admin'
      }
    } else if (_req.body.username === 'editor' && _req.body.password === "123456") {
      return {
        code: 0,
        roles: ['editor'],
        token: 'editor',
        introduction: '我是编辑',
        name: 'Normal Editor'
      }
    } else {
      return "账号或密码有误!"
    }
  }
}
复制代码
2. The development and production environments address configuration;

Development Environment: NODE_ENV = development; production environment, NODE_ENV = production; follows:

NODE_ENV = development
VUE_APP_URL = "https://easy-mock.com/mock/5cd03667adb0973be6a3d8d1/api"
复制代码
3. Examples of interface package;

as follows:

import request from '@/utils/axios'
import baseUrl  from '@/utils/env'
export function login(username, password) {
  return request({
    url: baseUrl.app_url+'/user/login',
    method: 'post',
    data: {
      username,
      password
    }
  })
}
复制代码

mockjs use

1. Background:

In using easy-mock analog data, it was found that the fixed form data can not be achieved CRUD etc., thereby selecting the use mockjs;

2. Introduction and functions:

Mock.js is a simulation data generator designed to help front-end siege division independent of the back-end development, help write unit tests. Analog functions provides the following:

1. According to the data template to generate analog data, provided by the method mockjs, you can easily create a lot of random text, numbers, Boolean, date, email, links, images, colors and so on.

2. Analog Ajax request, generate and return the analog data, mockjs can be powerful ajax interception. Can determine the type of request, access to the url, request parameters, etc. Then you can return to mock the false data, or your own programmed json file. powerful approachable.

3. Generate simulated data based on HTML templates

3.mockjs used in this project:
1. Install mockjs
npm install mockjs --save-dev
复制代码
2. Create mock folder structure and define the relevant functional modules;

Figure:

mockjs / index.js, responsible for defining the relevant mock interfaces, as follows:
import Mock from 'mockjs'

import tableAPI from './money'

// 设置全局延时 没有延时的话有时候会检测不到数据变化 建议保留
Mock.setup({
    timeout: '300-600'
})

// 资金相关
Mock.mock(/\/money\/get/, 'get', tableAPI.getMoneyList)
Mock.mock(/\/money\/remove/, 'get', tableAPI.deleteMoney)
Mock.mock(/\/money\/batchremove/, 'get', tableAPI.batchremoveMoney)
Mock.mock(/\/money\/add/, 'get', tableAPI.createMoney)
Mock.mock(/\/money\/edit/, 'get', tableAPI.updateMoney)
复制代码

mockjs / money.js , defines related functions, analog data, business logic, such as deletions of financial data flow change search and the like; refer to the rule data generated mockjs network official document , there is described in detail above syntax;

3. main.js incorporated in the definition of a good mockjs;

as follows:

import './mockjs'  //引用mock
复制代码
4.mockjs, api interface package;

src / api / money.js in a unified interface to the package, the function call corresponding to the page, corresponding to the acquired analog data. code show as below:

import request from '@/utils/axios'

export function getMoneyIncomePay(params) {
  return request({
    url: '/money/get',
    method: 'get',
    params: params
  })
}

export function addMoney(params) {
  return request({
    url: '/money/add',
    method: 'get',
    params: params
  })
}
复制代码
5. The assembly, interface calls, data acquisition, to render the page;

vue-cli3.0 upgrade record

Since the early use vue-cli2.0 project to build the project, the need for cumbersome webpack configuration; vue-cli 3.0 integrates webpack configurations, and on performance optimization done a lot. Because this project uses vue-cli3.0 to build and upgrade. A note will now be summarized as follows, detailed documentation, please refer to the official website .

1.vue-cli3.0 use the premise of introduction

Vue CLI package name changed to @ vue / cli a vue-cli. If you have already installed an older version of the global vue-cli (1.x or 2.x), you need to uninstall it by npm uninstall vue-cli -g, or yarn global remove vue-cli. Vue CLI requires Node.js version 8.9 or later (recommended 8.11.0+). You can use nvm nvm-windows or Node manage multiple versions on the same computer.

Installation and use 2.vue-cli3.0

1.vue-cli3.x installation
npm install -g @vue/cli
# OR
yarn global add @vue/cli
复制代码

If you want to also retain vue-cli2.x grammar or use templates 2.x, it is recommended to install cli-init

npm install -g @vue/cli-init
# OR
yarn global add @vue/cli-init
复制代码
2. Create a project using vue-cli3.x

vue create 项目名称; Mounting step to select the relevant configuration information, until completion.

3. New projects require environmental variables and configuration mode

New files in the root directory and .env.development .env.production, development environment and respectively generating environment configuration; primarily used to define an environment variable, or by npm run serve npm run build integrated into different environments, for the interface transfer. code show as below:

.env.development

NODE_ENV = development
VUE_APP_URL = "https://easy-mock.com/mock/5cd03667adb0973be6a3d8d1/api"
复制代码

.env.production

NODE_ENV = production
VUE_APP_URL = "https://easy-mock.com/mock/5cd03667adb0973be6a3d8d1/api"
复制代码

Use, as in the present project, arranged in utils / env.js code is as follows:

// development和production环境是不同的
let app_url = process.env.VUE_APP_URL  
export default {
    app_url
}
复制代码

Since we are using easy-mock simulation data, there is no cross-domain problem, so no need to configure devServer.proxy, can be used directly. Api in use as follows:

import request from '@/utils/axios'
import baseUrl  from '@/utils/env'
export function login(username, password) {
  return request({
    url: baseUrl.app_url+'/user/login',
    method: 'post',
    data: {
      username,
      password
    }
  })
}
复制代码
4. Detailed Configuration compiler package vue.config.js

The use vue-cli3.x generation program, has been integrated into the configuration WebPACK node_module, if desired for WebPACK such as the detailed configuration of the required item in the new file vue.config.js root specific configuration can reference document , the following It is a basic configuration.

const TerserPlugin = require('terser-webpack-plugin')  // 用于在生成环境剔除debuger和console
const path = require('path');
const resolve = dir => {
  return path.join(__dirname, dir);
};

const env = process.env.NODE_ENV
let target = process.env.VUE_APP_URL  // development和production环境是不同的

module.exports = {
  publicPath: '/',
  outputDir: './dist',
  lintOnSave: false, // 关闭eslint
  // 打包时不生成.map文件
  productionSourceMap: false,
  devServer: {
    open: true,
    host: '0.0.0.0',
    port: 8808
    // 由于本项目数据通过easy-mock和mockjs模拟,不存在跨域问题,无需配置代理;
    // proxy: { 
    //   '/v2': {
    //       target: target,
    //       changeOrigin: true
    //   }
    // }
  },
   // webpack相关配置
  chainWebpack: (config) => {
    config.entry.app = ['./src/main.js'];
    config.resolve.alias
      .set('@', resolve('src'))
      .set('cps', resolve('src/components'))
  },
  configureWebpack:config => {
    // 为生产环境修改配置...
    if (process.env.NODE_ENV === 'production') {
      new TerserPlugin({
        cache: true,
        parallel: true,
        sourceMap: true, // Must be set to true if using source-maps in production
        terserOptions: {
          compress: {
            drop_console: true,
            drop_debugger: true
          }
        }
      })
    } else {
      // 为开发环境修改配置...

    }
  },
   // 第三方插件配置
  pluginOptions: {

  }
}

复制代码

Good project configuration is complete, install all the dependencies. The implementation of the development environment package command: npm run serve, you can run the project; execution environment generation packaging commands: npm run build, you can generate a production environment file.

Technical Q & A

project instruction:

Little love ADMIN is completely free open source management system integration solutions can be applied directly related to the back-end management system templates; many places are the focus of a detailed notes and explanations. If you like the same front-end development, welcome to join our discussion / study group within the group can be Q & A, share learning materials; welcome to join the Q qq group: 602 515 030

Reproduced in: https: //juejin.im/post/5d0b4d28f265da1baf7cf293

Guess you like

Origin blog.csdn.net/weixin_34258782/article/details/93169762