Cómo Vue implementa el enrutamiento dinámico y los detalles del enrutamiento dinámico

Idea de diseño de permiso RBAC

Objetivo

Comprender el modelo de permisos de RBAC

fondo

Para lograr 不同的帐号登陆系统后能看到不同的页面,能执行不同的功能el objetivo, tenemos muchas soluciones, el modelo de permisos RBAC (control de acceso basado en roles), que es una solución de asignación de permisos basada en roles.

Su modo de permiso es el siguiente:

inserte la descripción de la imagen aquí

Tres puntos clave:

Usuario: la persona que utiliza el sistema

Punto de permiso: cuántas funciones hay en este sistema (ejemplo: hay 3 páginas, cada página tiene diferentes operaciones)

Rol: una colección de diferentes puntos de permiso

[Falló la transferencia de la imagen del enlace externo, el sitio de origen puede tener un mecanismo anti-leeching, se recomienda guardar la imagen y cargarla directamente (img-CxmEMg8V-1673401451130)(asset/image-20210427155035187.png)]

  1. Asignar roles a los usuarios
  2. Asignar permisos a roles

En el negocio real:

  1. Primero asigne al empleado un rol específico

  2. Luego asigne puntos de permiso específicos al rol (el botón de operación debajo de la página de salario de la página de salario)

    Los empleados tienen puntos de autoridad.

Función de asignación de empleados: componente de capa emergente

fondo

En la actualidad, ya existen algunos roles en el sistema, a continuación, vamos a asignar estos roles a diferentes empleados para que puedan hacer diferentes cosas después de ingresar al sistema.

La relación entre usuarios y roles es ** 1对多**: un usuario puede tener múltiples roles, por lo que especificará los permisos de estos múltiples roles. Por ejemplo, el presidente de la empresa puede tener las funciones de supervisor financiero y capitán de seguridad: el presidente puede leer los estados financieros y también puede verificar el seguimiento.

Objetivo

En la página de administración de empleados, cuando haga clic en Asignar rol , el componente se abrirá/cerrará en forma de una capa emergente

[Falló la transferencia de la imagen del enlace externo, el sitio de origen puede tener un mecanismo anti-leeching, se recomienda guardar la imagen y cargarla directamente (img-kH47ePb8-1673401451131)(asset/permissionUse/18.png)]

[Falló la transferencia de la imagen del enlace externo, el sitio de origen puede tener un mecanismo anti-leeching, se recomienda guardar la imagen y cargarla directamente (img-aQ1JfSXk-1673401451131)(asset/permissionUse/03.png)]

tren de pensamiento

  1. Divida las funciones específicas (las funciones del rol son más complicadas y dividir los componentes reducirá la carga de trabajo)

  2. Controla la visualización a través de la capa emergente

Nuevo componente de gestión de roles

Crea un archivo ** employees/assignRole.vue**, el contenido de la plantilla es el siguiente

<template>
  <!-- // 分配角色 -->
  <div>
    这里将来会放置多选列表

    <div style="margin-top: 20px; text-align: right">
      <el-button type="primary">确定</el-button>
      <el-button @click="closeDialog">取消</el-button>
    </div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      roleIds: []
    }
  },
  methods: {
    closeDialog() {

    }
  }
}
</script>

Registrar y usar componentes

En la página de inicio de administración de empleados employee.vue, introduzca los componentes agregados anteriormente

import AssignRole from './assignRole'

components: {
  // 省略其他....
  AssignRole // 注册组件
},
  
  // 使用
<el-dialog :visiable.sync="showDialogRole">
  <assign-role/>
</el-dialog>  

Los elementos de datos complementarios controlan la visualización y ocultación de la capa emergente

data () {
    
    
  return {
    
    
    // 省略其它
    showDialogRole: false
  }
}

Roles de asignación de empleados: interacciones básicas

Objetivo

Terminado de mostrar el efecto de cerrar la capa emergente

Efecto de interacción: capa emergente de visualización

Haga clic en el botón Asignar función , registre la identificación y muestre la capa de viñetas.

plantilla

<el-button type="text" size="small" @click="hAssignRole(scope.row)">分配角色</el-button>

el código

hEditRole({
     
     id}) {
    
    
  console.log('当前要分配角色id是', id)
  this.showRoleDialog = true
}

Efecto de interacción: cerrar capa emergente

Las siguientes operaciones harán que la ventana emergente se cierre:

  1. El usuario hizo clic en el botón cancelar.
  2. El usuario hizo clic en el botón Aceptar y la operación fue exitosa.
  3. El usuario hace clic en la X en la esquina superior derecha de la ventana emergente
<el-dialog
      title="分配角色"
      :close-on-click-modal="false"
      :close-on-press-escape="false"
      :visible.sync="showDialogRole"
    >
       <assign-role @close="showDialogRole=false" />
    </el-dialog>

Subensamblaje

<template>
  <div>
    <el-checkbox-group v-model="roleIds">
      <el-checkbox label="110">管理员</el-checkbox>
      <el-checkbox label="113">开发者</el-checkbox>
      <el-checkbox label="115">人事</el-checkbox>
    </el-checkbox-group>

    <div style="margin-top: 20px; text-align: right">
      <el-button type="primary">确定</el-button>
+      <el-button @click="closeDialog">取消</el-button>
    </div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      roleIds: []
    }
  },
  methods: {
    closeDialog() {
+      this.$emit('close')
    }
  }
}
</script>

Roles de asignación de empleados: obtenga una lista de roles y muéstrelos con el-checkbox

Componente: empleados/assignRole.vue

Objetivo

Envíe una solicitud para obtener una lista de todos los roles en este sistema y mostrarlos en el-checkbox-group

[Falló la transferencia de la imagen del enlace externo, el sitio de origen puede tener un mecanismo anti-leeching, se recomienda guardar la imagen y cargarla directamente (img-SHM57fGx-1673401451132)(asset/07-1619407883065.png)]

tren de pensamiento

  1. Prepara plantillas estáticas y aprende el-checkbox-group
  2. Preparar la interfaz api
  3. Envíe una solicitud para obtener los datos de back-end y luego renderice

Aprenda el cuadro de selección múltiple el-checkbox-group

plantilla

<el-checkbox-group v-model="roleIds">
  <el-checkbox label="110">管理员</el-checkbox>
  <el-checkbox label="113">开发者</el-checkbox>
  <el-checkbox label="115">人事</el-checkbox>
</el-checkbox-group>

Para el grupo de casillas de verificación el utilizado para representar opciones múltiples:

  • El valor de v-model es una matriz (indica selección múltiple)
  • El atributo de etiqueta de su elemento secundario el-checkbox determina el valor después de seleccionar este elemento

datos

data () {
    
    
  return {
    
    
    roleIds: [] // 保存当前选中的权限列表
  }
}

Prepare la API para obtener la lista de roles.

El objetivo es: conseguir todos los personajes. Sin embargo, el backend no proporciona una interfaz preparada para obtener directamente todos los roles.

Nota: No tenemos una lista de roles dedicados a la función actual, podemos usar temporalmente pageSize como 100 (equivalente a tomar la primera página, 100 elementos por página) para obtener datos. en el archivo src\api\setting.js,


/**
 * 获取所有角色信息
 * @param {*} params  {page, pagesize}
 * @returns
 */
export function getRoles(params) {
    
    
  return request({
    
    
    url: '/sys/role',
    method: 'GET',
    params: params
  })
}

Llamado en el componente empresarial

en src\views\employees\assignRole.vue_

<script>
import {
    
     getRoles } from '@/api/setting'
export default {
    
    
  data() {
    
    
    return {
    
    
      roleIds: [],
+     list: []
    }
  },
  created() {
    
    
    this.loadRoles()
  },
  methods: {
    
    
    async loadRoles() {
    
    
      const {
    
     data } = await getRoles({
    
     page: 1, pagesize: 100 })
+     this.list = data.rows
    },
    closeDialog() {
    
    
      this.$emit('close')
    }
  }
}
</script>

Representar los datos en la plantilla

<el-checkbox-group v-model="roleIds">
  <!-- 注意:label决定当前选中的值 -->
  <el-checkbox v-for="item in list" :key="item.id" :label="item.id">
    {
   
   { item.name }}
  </el-checkbox>
</el-checkbox-group>

Nota: la etiqueta determina el valor seleccionado actualmente

resumen

Roles de asignación de empleados: obtener datos y reponer

Objetivo

​ Si el usuario actual ya ha configurado algunos datos de roles, los datos de roles configurados deben mostrarse primero: ¡algunas casillas de verificación están seleccionadas!

[Falló la transferencia de la imagen del enlace externo, el sitio de origen puede tener un mecanismo anti-leeching, se recomienda guardar la imagen y cargarla directamente (img-YLTZ10fZ-1673401451132)(asset/08-1619407893456.png)]

tren de pensamiento

Pase la identificación de usuario en el componente principal

Después de abrir la capa emergente, obtenga la información del rol actual de acuerdo con la identificación del usuario y luego haga eco

padre a hijo - padre

definir elementos de datos

data() {
    
    
    return {
    
    
      // 省略其他 ...
      curEmployeId: '', // 当前的员工编号
    }
}

Al hacer clic en asignar un rol, asígnele un valor

// 用户点击分配角色
hAssignRole(id) {
    
    
  this.showDialogRole = true

  this.curEmployeId = id
}

plantilla

Pasar accesorios a componentes secundarios

<el-dialog :visible.sync="showDialogRole" title="权限">
  <assign-role
+        :employee-id="curEmployeId"
        @close="showDialogRole=false"
      />
</el-dialog>

padre a hijo - hijo a recibir

<script>
 import {
      
       getUserDetailById } from '@/api/user'
 export default {
      
      
    props: {
      
      
       // 用户的id 用来查询当前用户的角色信息
        employeeId: {
      
      
      		type: String,
      		required: true
    		}
    },
  	created() {
      
      
    	this.loadRoles()
  	},

  methods: {
      
      
    async loadRoles() {
      
      
      const res = await getRoles({
      
       page: 1, pagesize: 100 })
      // 保存所有的角色
      this.list = res.data.rows
      // console.log('loadRoles...........', res)
      const info = await getUserDetailById(this.employeeId)
      console.log('getUserDetailById...........', info)
      // 保存这个员工当前的已经有的角色
      this.roleIds = info.data.roleIds
    },
 }
</script>

Problema de reposición de roles de asignación de empleados: creado solo se ejecuta una vez

razón

Dado que el subcomponente está anidado en el cuadro de diálogo, solo se creará una vez: la creación se ejecuta solo una vez, y las operaciones posteriores de visualización y ocultación no harán que se reconstruya el componente, por lo que: el contenido abierto más tarde es el mismo que la primera vez .

resolver

Solución 1: cuando la capa emergente esté oculta, destruya el subcomponente.

<el-dialog
      title="分配角色"
      :close-on-click-modal="false"
      :close-on-press-escape="false"
      :visible.sync="showDialogRole"
    >
      <assign-role
+       v-if="showDialogRole"
        :employee-id="curEmployeId"
        @close="showDialogRole=false"
      />
    </el-dialog>

Ventajas: Simple; Desventajas: La destrucción de componentes tiene ciertos problemas de rendimiento

Opción II:

Idea: cuando haga clic para asignar un rol en el componente principal, llame directamente al método en el componente secundario para obtener los datos

Agregar una referencia al componente secundario

<assign-role
        ref="assignRole"
        :employee-id="curEmployeId"
        @close="showDialogRole=false"
      />
// 用户点击分配角色
hAssignRole(id) {
    
    
  this.showDialogRole = true

  this.curEmployeId = id
  console.log('父组件', this.curEmployeId)
  // this.$nextTick
  // 直接找到子组件,调用方法去获取最新的数据
  this.$nextTick(() => {
    
    
    this.$refs.assignRole.loadRoles()
    // console.log('子组件中的props', this.$refs.assignRole.employeeId)
  })
}

Eliminar creado en el precio del subgrupo

// created() {
  //   // 组件创建时执行一次
  //   this.loadRoles()
  // },

Función de asignación de empleados - Guardar

Objetivo

Guardar las funciones específicas del rol asignado modificado del usuario

tren de pensamiento

Interfaz de encapsulación -> interfaz de llamada

Asignar interfaz de rol

En el api/employees.jsarchivo ** **, agregue un método llamado AssignRoles

/**
 * @description: 为用户分配角色
 * @param {*} data { id:当前用户id, roleIds:选中的角色id组成的数组 }
 * @return {*}
 */
export function assignRoles(data) {
    
    
  return request({
    
    
    url: '/sys/user/assignRoles',
    data,
    method: 'put'
  })
}

Confirmar el guardado en el código de negocio

Importar la API definida anteriormente

import {
    
     assignRoles } from '@/api/employees'

Agregar un evento de clic al botón

<template>
  <el-button type="primary" size="small" @click="hSave">确定</el-button>
</template>

Devoluciones de llamada adicionales guardadas

// 保存当前角色信息
async hSubmit() {
    
    
  const res = await assignRoles({
    
     id: this.employeeId, roleIds: this.roleIds })
  console.log('保存角色', res)
  this.$emit('update-close')
}

En el componente principal, escucha el evento.

<assign-role
        ref="assignRole"
        :employee-id="curEmployeId"
        @update-close="hUpdateClose"
        @close="showDialogRole=false"
      />

hActualizarCerrar:

// 用户分配角色成功
    hUpdateClose() {
    
    
      this.showDialogRole = false
      this.loadEmployeeList()
    }

Permisos de asignación de funciones: descripción general

Por qué asignar permisos a roles

Cuál es el rol del usuario, tiene ciertas funciones

En el código anterior, se ha agregado un rol al usuario, por lo que lo que el empleado puede hacer depende de las funciones específicas que se llevan a cabo en el rol.

imagen-20210428094452560

Hay muchas funciones de gestión de derechos que requieren componentes de empaquetado.

Permisos de asignación de roles: componentes Bombshell e interacciones básicas

Objetivo

En el módulo de gestión de roles (views/settings/settings.vue), implemente subcomponentes

[Falló la transferencia de la imagen del enlace externo, el sitio de origen puede tener un mecanismo anti-leeching, se recomienda guardar la imagen y cargarla directamente (img-0zTwqJw2-1673401451132)(activo/asignar permisos.gif)]

tren de pensamiento

Preparar ventana emergente -> registrar evento -> proporcionar método de datos

Complete el negocio de asignar puntos de autoridad a roles

Encapsular subcomponentes

Primero encapsule un componente de AssignPermission.vue en la configuración para la copia de seguridad.

|--settings
|---------settings.vue # 角色管理主页
|---------assignPermission.vue  #给角色分配权限

Será referenciado y utilizado en settings.vue.

Agregue una capa emergente en el componente principal e introduzca el componente secundario

Introducir subcomponentes en settings.vue

import assignPermission from './assignPermission'

registro

components: {
    
    
    assignPermission
  },

Agregue el componente el-dialog a la plantilla e impórtelo

<!-- 分配权限的弹层 -->
<el-dialog 
    title="分配权限(一级为路由页面查看权限-二级为按钮操作权限)" :visible.sync="showDialogAssign">
  <assign-permission />
</el-dialog>

Dato suplementario

return {
    
    
  //... 省略其它
  showDialogAssign: false, // 分配权限对话框
}

Interacción: muestra la capa emergente

Mostrar ventana emergente. Agregar un evento de clic al botón

<el-button size="small" type="success" @click="hAssign">
    分配权限
</el-button>

Establezca showDialogAssign en verdadero en la devolución de llamada

methods:{
    
    
  hAssign() {
    
    
    this.showDialogAssign = true
  } 
}

Capa emergente de ocultación de interacción

Evento personalizado: niño a padre

<el-dialog
      title="分配权限(一级为路由页面查看权限-二级为按钮操作权限)"
      :visible.sync="showDialogAssign"
    >
      <assign-permission
+        @close="showDialogAssign=false"
      />
    </el-dialog>

en el componente hijo

methods: {
    
    
    hCancel() {
    
    
    // 通过父组件去关闭弹层
      this.$emit('close')
    }
  }

Permisos de asignación de roles: obtenga datos y visualización de puntos de permiso

Objetivo

En el componente AssignPermission.vue, todos los datos de puntos de permiso en el sistema actual se obtienen y se muestran en una estructura de árbol. El efecto objetivo es el siguiente:

[Falló la transferencia de la imagen del enlace externo, el sitio de origen puede tener un mecanismo de enlace antirrobo, se recomienda guardar la imagen y cargarla directamente (img-oYbV8FQO-1673401451133)(activo/imagen-20210428100556359.png)]

tren de pensamiento

  1. Preparar la interfaz del punto de permiso

  2. Después de que se muestre la ventana emergente:

    1. Llame a la API para enviar una solicitud para obtener datos;
    2. Conversión de formato de datos (matriz a árbol)
    3. Enlace de plantilla (mostrar datos en el-tree)

preparar API

Prepare la API en src\api\permission.js (esta API se ha utilizado en la página del punto de permiso)

import request from '@/utils/request'

// 获取权限点列表
export function getPermissionList(params) {
    
    
  return request({
    
    
    url: '/sys/permission',
    params
  })
}

Preparar elementos de datos

permissionData: [] // 存储权限数据

Enviar una solicitud para obtener datos

método de importación

import {
    
     getPermissionList } from '@/api/permission'
import {
    
     tranListToTreeData } from '@/utils/index'

Llamado en creado

created() {
  this.loadPermissionList()
},
  async loadPermissionList() {
    // 发送请求, 获取权限列表
    const { data } = await getPermissionList()
    console.log('权限列表的数据是', data)
    this.permissionData = tranListToTreeData(data)
  }

Mostrar datos en el-tree

<!-- 权限点数据展示 -->
<el-tree
    :data="permissionData"
    :props="{ label: 'name' }"
/>

Nota: accesorios

Permisos de asignación de funciones: configuración de las propiedades de el-tree

Objetivo

Otras configuraciones para el-tree:

  1. Mostrar cuadro de selección
  2. Expandir todo por defecto
  3. Asociación estrecha de padres e hijos
imagen-20210524231614693

configuración de atributos

https://element.eleme.io/#/zh-CN/component/tree

  1. mostrar casilla de verificación mostrar casilla de verificación
  2. default-expand-all Expandir por defecto
  3. check-strictly set verdadero, puede cerrar la asociación padre-hijo
<!-- 权限点数据展示 -->
      <el-tree
        :data="permissionData"
        :props="{ label: 'name' }"
        default-expand-all
        :show-checkbox="true"
        :check-strictly="true"
      />

El método de escritura por defecto-expandir-todo es equivalente a:default-expand-all="true"

Efecto

Permisos de asignación de funciones - Reposición de datos

Objetivo

El usuario actual puede tener algunos permisos existentes, que deben repetirse

tren de pensamiento

  1. preparar API
  2. Reúna los parámetros actuales y llame a la API para obtener los datos;
  3. Mostrar el relleno de datos en el árbol

preparar API

Archivo: en src\api\settings.js, agregue un método getRoleDetail

/**
 * @description: 获取角色详情
 * @param {*} id 角色id
 * @return {*}
 */
export function getRoleDetail(id) {
    
    
  return request({
    
    
    url: `/sys/role/${
      
      id}`
  })
}

Pasar id de padre a hijo

En el componente principal setting.vue, defina el elemento de datos:

data () {
    
    
  return {
    
    
  	// 省略其他...
  	roleId: ''
	}
}

Guarde el roleId cuando haga clic para asignar permisos

<el-button size="mini" type="success" @click="hAssign(scope.row.id)">分配权限</el-button>

La devolución de llamada correspondiente es:

hAssign(id) {
    
    
   // 记下来id
   this.roleId = id
   this.showDialogAssign = true
},

Recibir roleId en subclase

En AssignPerimission.vue, los accesorios de definición complementarios reciben el valor roleId

props: {
    
    
  roleId: {
    
    
    type: String,
    required: true
  }
}

Llamar api para obtener datos

Introducir la api previamente encapsulada

import {
    
     
  assignPerm, 
+ getRoleDetail 
} from '@/api/setting'
created() {
    
    
    // 调用接口,获取所有的权限点数据
    this.loadPermissionList()

    // 调用接口,获取当前这个角色已经具备的权限
+   this.loadPermissionByRoleId()
  },
    
async loadPermissionByRoleId() {
    
    
      // 根据roleId获取当前这个角色已经具备的权限
      const res = await getRoleDetail(this.roleId)
+      console.log('获取当前角色的已有的权限点数据', res.data.permIds)
      // 回填到树上
      this.$refs.tree.setCheckedKeys(res.data.permIds)
    },
    async loadPermissionList() {
    
    
      const res = await getPermissionList()
      console.log('获取所有的权限点数据', res)
      // 转成树状结构
      this.permissionData = tranListToTreeData(res.data)
    },

Rellenar datos en el-tree

Se han obtenido los datos, ¿cómo llenarlos en el árbol, de modo que se seleccionen algunas casillas de verificación?

Ejemplo: setCheckedKeys + clave de nodo

Sitio web oficial: https://element.eleme.io/#/zh-CN/component/tree#fang-fa

  1. Agregar clave de nodo de atributo al árbol
<!-- 权限点数据展示 -->
    <el-tree
      ref="refTree"
      :data="permissionData"
      :props="{ label: 'name' }"
      :default-expand-all="true"
      :show-checkbox="true"
      :check-strictly="true"
      node-key="id"
    />
  1. llamar a setCheckedKeys
// 获取角色现有的权限
    async loadRoleDetail() {
      const res = await getRoleDetail(this.roleId)
      console.log('获取角色现有的权限', res.data.permIds)

      // 回填
      this.$refs.refTree.setCheckedKeys(res.data.permIds)
    },

resumen

  1. En el componente el-tree, haga eco de los datos en el componente el-tree a través del método setCheckedKeys

Permisos de asignación de roles: problema de reposición de datos: lo creado solo se ejecuta una vez

razón

Dado que el subcomponente está anidado en el cuadro de diálogo, solo se creará una vez: la creación se ejecuta solo una vez, y las operaciones posteriores de visualización y ocultación no harán que se reconstruya el componente, por lo que: el contenido abierto más tarde es el mismo que la primera vez .

resolver

Solución 1: cuando la capa emergente esté oculta, destruya el subcomponente.

<el-dialog
      title="分配角色"
      :visible.sync="showDialogRole"
      :close-on-click-modal="false"
      :close-on-press-escape="false"
    >
      <子组件
+       v-if="showDialogAssign"
      />
    </el-dialog>

Ventajas: simple, se obtienen los últimos datos;

Desventajas: La destrucción de componentes tiene ciertos problemas de rendimiento,

Solución 2: haga referencia a los subcomponentes a través de referencias y llame directamente a sus métodos para enviar solicitudes

[Falló la transferencia de la imagen del enlace externo, el sitio de origen puede tener un mecanismo anti-leeching, se recomienda guardar la imagen y cargarla directamente (img-JrmAm932-1673401451133)(asset/image-20210428105921353.png)]

// 用户点击了权限分配
    hAssign(id) {
    
    
      // alert(id)
      // 1. 保存角色编号
      //    它会影响子组件中的props,但是,这个传递的过程是异步的
      this.roleId = id
      // 2. 弹层
      this.showDialogAssign = true
      // 3. 手动调用子组件的loadPermissionByRoleId, 去根据最新的roleId获取权限信息
      this.$nextTick(() => {
    
    
        this.$refs.permission.loadPermissionByRoleId()
      })
      }
    }

Permisos de asignación de funciones - Guardar configuración

Objetivo

Completar la función de asignación de permisos

tren de pensamiento

Prepare api, llame cuando haga clic en guardar

preparar API

En el archivo src\api\settings.js, agregue una API para asignar permisos

/**
 * 给角色分配权限
 * @param {*} data {id:角色id, permIds:[] 所有选中的节点的id组成的数组}
 * @returns
 */
export function assignPerm(data) {
    
    
  return request({
    
    
    url: '/sys/role/assignPrem',
    method: 'put',
    data
  })
}

Llame a api para asignar permisos-análisis

Simplemente llame a la API definida anteriormente y pase los parámetros relevantes.

Hay dos parámetros aquí:

  1. ¿Cuál es el ID de rol actual?在点击分配权限时,可以从表格中获取, 父传子
  2. ¿Cuál es el ID de la lista de permisos correspondiente?通过el-tree组件的getCheckedKeys来获取用户选中的id列表

Llame a api para asignar permisos - realización de funciones

async hSave() {
    
    
      const permIds = this.$refs.tree.getCheckedKeys()
      // console.log('当前选中的节点数组是', permIds)
      const res = await assignPerm({
    
    
        id: this.roleId,
        permIds
      })
      console.log('保存角色的权限点的结果是', res)

      // 提示
      this.$message.success('保存角色的权限成功')
      // 关闭弹层
      this.hCancel()
    },
    hCancel() {
    
    
      // 通过父组件去关闭弹层
      this.$emit('close-dialog')

      // 清空当前的选择
      this.$refs.tree.setCheckedKeys([])
    }

Finalmente, cuando se cierre la capa emergente, borre los datos seleccionados por el usuario en el árbol

resumen

  • el-tree obtiene las claves del nodo actualmente seleccionado: getCheckedKeys
  • Para los componentes de el-tree, borre la selección actual: this.$refs.tree.setCheckedKeys([])

Conocer los datos de permisos del usuario

Hasta ahora, hemos implementado todos los aspectos de la idea de diseño de permisos RBAC. Hemos asignado funciones a los empleados y asignado puntos de permiso a las funciones. Los empleados ahora tienen los puntos de permiso correspondientes. A continuación, podemos usar estos puntos de permiso para el control de autoridad real, en el proyecto de recursos humanos, hay dos lugares para el control de autoridad:

  1. Control de permisos del menú izquierdo (después de que diferentes usuarios ingresan al sistema, los menús que ven son diferentes)
  2. Control de permisos del botón de operación (botones en la página, diferentes personas tienen diferentes permisos)

donde estan los datos del permiso

Cree nuevos datos de empleado en la administración de empleados y luego use la nueva cuenta de empleado para iniciar sesión (la contraseña es 123456) y vea los datos devueltos de la interfaz de información personal (/api/sys/profile), como se muestra en la figura a continuación, no hay permisos configurados El estado de devolución del , puede ver que los menús y los puntos debajo de los roles están vacíos, y los empleados no tienen permisos en este momento

[Falló la transferencia de la imagen del enlace externo, el sitio de origen puede tener un mecanismo anti-leeching, se recomienda guardar la imagen y cargarla directamente (img-WN9TIr43-1673401451134)(asset/permissionUse/13.png)]

Cómo modificar los datos de permisos

Inicie sesión con una cuenta de administrador y luego asigne dos permisos de menú y un permiso de botón de operación al nuevo empleado recién creado, y luego vuelva a iniciar sesión en la cuenta del empleado para ver información personal y devolver datos

Pasos:

  1. Gestión de puntos de permiso > Agregar puntos de permiso de operación de botón en la gestión de empleados导入,导出

  2. Gestión de roles > Director de personal de nuevo rol > Asignar permisos a roles (administración de empleados, importación, exportación)

  3. Gestión de empleados > Asignar el rol de director de recursos humanos a los empleados

  4. Vuelva a iniciar sesión en la nueva cuenta de empleado, verifique los datos de permiso y observe los elementos data.roles.menus, puntos

Solicitud de permisos-menú izquierdo generado dinámicamente-análisis general

analizar

El inicio de sesión es exitoso, ingrese al protector de navegación:

  • Obtener información de permiso personal
  • Generar rutas dinámicas accesibles

[Falló la transferencia de la imagen del enlace externo, el sitio de origen puede tener un mecanismo anti-leeching, se recomienda guardar la imagen y subirla directamente (img-wMfe8si3-1673401451134)(asset/image-20210428122059657.png)]

ejemplo

[Error en la transferencia de la imagen del enlace externo, el sitio de origen puede tener un mecanismo anti-leeching, se recomienda guardar la imagen y cargarla directamente (img-L1oHNZ59-1673401451134)(asset/permissionUse/17.png)]

Solicitud de permisos - generar menú izquierdo dinámicamente - método addRoutes

Objetivo

Aprenda addRoutes en el objeto vue-router y utilícelo para agregar dinámicamente configuraciones de enrutamiento

tren de pensamiento

Las páginas (configuración de enrutamiento) a las que pueden acceder los usuarios deben ser dinámicas , por lo que primero debe dominar una API que pueda agregar dinámicamente direcciones de enrutamiento

Uso básico de addRoutes

Formato

router.addRoutes([路由配置对象])
或者:
this.$router.addRoutes([路由配置对象])

Rol: agregar dinámicamente la configuración de enrutamiento

ejemplo

// 按钮
<button @click="hAddRoute">addRoute</button>

// 回调
hAddRoute() {
	this.$router.addRoutes([{
		path: '/abc',
		component: () => import('@/views/abc'),
		}])
},

Efecto

Después de hacer clic en el botón, puede acceder a /abc en la dirección.

código de actualización

  1. Elimine la parte del enrutamiento dinámico en la configuración de enrutamiento en router/index.js

    const createRouter = () => new Router({
          
          
      // mode: 'history', // require service support
      scrollBehavior: () => ({
          
           y: 0 }),
      // routes: constantRoutes
      // 合并动态和静态的路由  , ...asyncRoutes
    - routes: [...constantRoutes, ...asyncRoutes]
    + routes: [...constantRoutes]
    })
    
  2. Introducido en allow.js y agregado dinámicamente usando addRoutes

Transforme la tabla de enrutamiento dinámico que se escribió directamente de forma estática en el enrutador al addRoutesformulario agregado por la llamada al método

// 引入所有的动态路由表(未经过筛选)
+ import router, {
    
     asyncRoutes } from '@/router'

const whiteList = ['/login', '/404']
router.beforeEach(async(to, from, next) => {
    
    
  // 开启进度条
  NProgress.start()
  // 获取本地token 全局getter
  const token = store.getters.token
  if (token) {
    
    
    // 有token
    if (to.path === '/login') {
    
    
      next('/')
    } else {
    
    
      if (!store.getters.userId) {
    
    
        await store.dispatch('user/getUserInfo')
        // 改写成动态添加的方式
+       router.addRoutes(asyncRoutes)
      }
      next()
    }
  } else {
    
    
    // 没有token
    if (whiteList.includes(to.path)) {
    
    
      next()
    } else {
    
    
      next('/login')
    }
  }
  // 结束进度条
  NProgress.done()
})

Efecto de aceptación

  1. Solo queda la página de inicio estática en el menú de la izquierda (que se resolverá más adelante)

  2. La introducción manual de una determinada dirección de enrutamiento dinámico en el navegador aún está disponible, lo que demuestra que en realidad hemos agregado enrutamiento dinámico a nuestro sistema de enrutamiento.

Solicitud de permiso - generar dinámicamente menú izquierdo - reescribir menú guardar ubicación

análisis del problema

Los datos utilizados por la representación del menú actual (src\layout\components\Sidebar\index.vue): this.$router.options.routesestos datos son fijos y la tabla de enrutamiento que agregamos a través de addRoutes solo existe en la memoria y no cambiaráthis.$router.options.routes

Si queremos que los datos de enrutamiento se reflejen en el menú inmediatamente después de llamar al método addRoutes, debemos pensar en un método adicional. Piénselo. En el desarrollo de Vue, ¿qué tecnología puede garantizar que las funciones receptivas también se puedan modificar dinámicamente? vuex!

Objetivo

guardar datos de menú en vuex

[Falló la transferencia de la imagen del enlace externo, el sitio de origen puede tener un mecanismo de enlace antirrobo, se recomienda guardar la imagen y cargarla directamente (img-4Q4i5Ywp-1673401451134)(activo/imagen-20210428122540218.png)]

Definir los datos del menú de gestión de vuex

  1. Módulos complementarios. src/store/modulesAgregue el módulo menu.js a continuación
    • Definir datos menuList
    • Método para modificar datos setMenuList
// 导入静态路由
import {
    
     constantRoutes } from '@/router'
export default {
    
    
  namespaced: true,
  state: {
    
    
    // 先以静态路由作为菜单数据的初始值
    menuList: [...constantRoutes]
  },
  mutations: {
    
    
    setMenuList(state, asyncRoutes) {
    
    
      // 将动态路由和静态路由组合起来
      state.menuList = [...constantRoutes, ...asyncRoutes]
    }
  }
}

Por supuesto, registre este módulo en src/store/index.js

+ import menu from './modules/menu'

Vue.use(Vuex)

const store = new Vuex.Store({
    
    
  modules: {
    
    
    app,
    settings,
    user,
+   menu
  },
  getters
})

2. Envíe setMenuList para generar datos de menú completos

Modifique el código en src/permission.js

if (!store.getters.userId) {
    
    
        await store.dispatch('user/getUserInfo')

        // 动态添加可以访问的路由设置
        router.addRoutes(asyncRoutes)

        // 根据用户实际能访问几个页面来决定从整体8个路由设置
        // 中,过滤中出来几个,然后保存到vuex中
        store.commit('menu/setMenuList', asyncRoutes)
      }

3. La parte de generación del menú se reescribe para usar los datos en vuex

En el archivo src\layout\components\Sidebar\index.vue, modifique

routes() {
    
    
  // 拿到的是一个完整的包含了静态路由和动态路由的数据结构
  // return this.$router.options.routes
  return this.$store.state.menu.menuList
}

resumen

[Falló la transferencia de la imagen del enlace externo, el sitio de origen puede tener un mecanismo de enlace antirrobo, se recomienda guardar la imagen y cargarla directamente (img-FQFaCeh7-1673401451135)(activo/imagen-20210525124226388.png)]

Solicitud de permisos: use datos de permisos para filtrar

Objetivo

En el paso anterior conseguimos:

  • El enrutamiento dinámico se agrega dinámicamente al sistema de enrutamiento a través de addRoutes
  • Guarda la ruta dinámica en el menú de vuex

Sin embargo, no coincidimos con los datos de permisos. Luego, filtramos el menú dinámico a través de los datos de permisos devueltos por la interfaz para asegurarnos de que el menú completo esté relacionado con el permiso del usuario.

filtrar ideas

[Error en la transferencia de la imagen del enlace externo, el sitio de origen puede tener un mecanismo de enlace antirrobo, se recomienda guardar la imagen y cargarla directamente (img-JQ1M2Yrk-1673401451135)(activo/imagen-20210525000107003.png)]

El filtrado usa el nombre como identificador y verifica si el nombre de la ruta es consistente con el subíndice

[Falló la transferencia de la imagen del enlace externo, el sitio de origen puede tener un mecanismo anti-leeching, se recomienda guardar la imagen y cargarla directamente (img-c8GBacDW-1673401451135)(asset/image-20210428153438963.png)]

La convención de interfaz del backend es la siguiente:

  • Nombre de página: ID de empleado: empleados
  • Nombre de la página: ID de permiso: permisos
  • Nombre de página: Identificador de estructura organizativa: departamentos
  • Nombre de la página: Ajustes ID: ajustes
  • Nombre de página: Id. de salario: salarios
  • Nombre de la página: Id. de aprobación: aprobaciones
  • Nombre de página: Asistencia Logo: asistencias
  • Nombre de la página: Seguro Social Logo: social_securitys

Devolver elementos de menú de acciones

Las páginas a las que el usuario puede acceder se obtienen a través de acciones, y solo necesita regresar de la acción.

Modificar store/modules/user.jsy complementar la declaración de devolución.

// 用来获取用户信息的action
    async getUserInfo(context) {
    
    
      // 1. ajax获取基本信息,包含用户id
      const rs = await getUserInfoApi()
      console.log('用来获取用户信息的,', rs)
      // 2. 根据用户id(rs.data.userId)再发请求,获取详情(包含头像)
      const info = await getUserDetailById(rs.data.userId)
      console.log('获取详情', info.data)
      // 把上边获取的两份合并在一起,保存到vuex中
      context.commit('setUserInfo', {
    
     ...info.data, ...rs.data })
+     return rs.data.roles.menus
    },

Obtenga el valor de retorno de la acción en allow.js y filtre

en src/permission.js_

if (!store.getters.userId) {
    
    
        // 有token,要去的不是login,就直接放行
        // 进一步获取用户信息
        // 发ajax---派发action来做
        const menus = await store.dispatch('user/getUserInfo')
        console.log('当前用户能访问的页面', menus)
        console.log('当前系统功能中提供的所有的动态路由页面是', asyncRoutes)
        // 根据本用户实际的权限menus去 asyncRoutes 中做过滤,选出本用户能访问的页面

        const filterRoutes = asyncRoutes.filter(route => {
    
    
          const routeName = route.children[0].name
          return menus.includes(routeName)
        })

        // 一定要在进入主页之前去获取用户信息

        // addRoutes用来动态添加路由配置
        // 只有在这里设置了补充了路由配置,才可能去访问页面
        // 它们不会出现左侧
        router.addRoutes(filterRoutes)

        // 把它们保存在vuex中,在src\layout\components\Sidebar\index.vue
        // 生成左侧菜单时,也应该去vuex中拿
        store.commit('menu/setMenuList', filterRoutes)
      }

Efecto

[Falló la transferencia de la imagen del enlace externo, el sitio de origen puede tener un mecanismo anti-leeching, se recomienda guardar la imagen y cargarla directamente (img-EgzHy9V4-1673401451135)(asset/permissionUse/15.png)]

resumen

  • Obtener el valor de retorno de las acciones
  • asyncRoutes.filter
imagen-20210525002110439

Corrección de errores al actualizar la página

pregunta

Si refrescamos el navegador, encontraremos que hemos saltado a la página 404

Para la ruta agregada por addRoute, la pantalla será blanca al actualizar

razón

Ahora la página 404 en nuestra configuración de enrutamiento está en el medio en lugar de al final de todas las rutas.

resolver

Simplemente cambie la página 404 al final de la configuración de enrutamiento

el código

  1. path:'*'Eliminar este elemento de las rutas estáticas en rutas/index.js

  2. Agregado al final en allow.js

// if(没有userInfo) {
    
    
if (!store.getters.userId) {
    
    
  // 有token,要去的不是login,就直接放行
  // 进一步获取用户信息
  // 发ajax---派发action来做
  const menus = await store.dispatch('user/getUserInfo')
  console.log('当前用户能访问的页面', menus)
  console.log('当前系统功能中提供的所有的动态路由页面是', asyncRoutes)
  // 根据本用户实际的权限menus去 asyncRoutes 中做过滤,选出本用户能访问的页面

  const filterRoutes = asyncRoutes.filter(route => {
    
    
    const routeName = route.children[0].name
    return menus.includes(routeName)
  })

  // 一定要在进入主页之前去获取用户信息

  // 把404加到最后一条
  filterRoutes.push( // 404 page must be placed at the end !!!
    {
    
     path: '*', redirect: '/404', hidden: true })

  // addRoutes用来动态添加路由配置
  // 只有在这里设置了补充了路由配置,才可能去访问页面
  // 它们不会出现左侧
  router.addRoutes(filterRoutes)

  // 把它们保存在vuex中,在src\layout\components\Sidebar\index.vue
  // 生成左侧菜单时,也应该去vuex中拿
  store.commit('menu/setMenuList', filterRoutes)

  // 解决刷新出现的白屏bug
  next({
    
    
    ...to, // next({ ...to })的目的,是保证路由添加完了再进入页面 (可以理解为重进一次)
    replace: true // 重进一次, 不保留重复历史
  })
} else {
    
    
  next()
}

Restablecer rutas al cerrar la sesión

pregunta

Después de salir, inicie sesión nuevamente y descubra que el menú es anormal (la consola tiene una salida que dice que la ruta se repite);

[Falló la transferencia de la imagen del enlace externo, el sitio de origen puede tener un mecanismo anti-leeching, se recomienda guardar la imagen y subirla directamente (img-xfeMibRM-1673401451136)(asset/image-20210525161618731.png)]

razón

La configuración de enrutamiento se router.addRoutes(filterRoutes)agrega a través de , y cuando cierra la sesión, no se borra, y vuelve a iniciar sesión y la agrega nuevamente, por lo que hay duplicación.

Es necesario restablecer la autoridad de enrutamiento (restaurar el valor predeterminado) y agregarla nuevamente después de iniciar sesión en el futuro; de lo contrario, se agregará repetidamente

resolver

Nuestros router/index.jsarchivos **, encontraron un método de ruta de reinicio

// 重置路由
export function resetRouter() {
    
    
  const newRouter = createRouter()
  router.matcher = newRouter.matcher // 重新设置路由的可匹配路径
}

Este método es para volver a crear una instancia de la ruta, lo que equivale a cambiar una nueva ruta. El ** anterior ya 加的路由no existe. Debe llamarlo cuando cierre la sesión**

store/modules/user.js

import {
    
     resetRouter } from '@/router'
// 退出的action操作
logout(context) {
    
    
  // 1. 移除vuex个人信息
  context.commit('removeUserInfo')
  // 2. 移除token信息
  context.commit('removeToken')
  // 3. 重置路由
  resetRouter()
  // 4. 重置 vuex 中的路由信息 只保留每个用户都一样的静态路由数据
  //    在moudules中的一个module中去调用另一个modules中的mutation要加{root:true}
  // context.commit('setMenuList', [], { root: true })
}

Solicitud de permisos - Control de nivel de botones - Análisis

Objetivo

Tanto el empleado A como el empleado B pueden acceder a la misma página (tome la gestión de empleados como ejemplo), pero el empleado A puede exportar Excel, pero el empleado B no puede exportar Excel.

tren de pensamiento

Una vez que el usuario inicia sesión correctamente, los permisos de nivel de botón a los que el usuario puede acceder se almacenan en la matriz de puntos. Y estos datos se almacenan en vuex, por lo que se puede acceder a ellos en cualquier parte del proyecto.

  • Si el logotipo de un botón aparece en puntos, se puede mostrar

Solicitud de permiso - Control de nivel de botones - Instrucciones personalizadas

Directivas: v-for, v-if…

Instrucciones definidas por el usuario: instrucciones autodefinidas, porque las instrucciones en sí mismas no son suficientes, por lo que debemos definirlas nosotros mismos.

Úselo para el control de permisos a nivel de botón

Revisar directivas personalizadas

formato de registro

// 注册一个全局自定义指令 `v-focus`
Vue.directive('focus', {
    
    
  // 当被绑定的元素插入到 DOM 中时inserted会自动执行
  inserted: function(el, binding) {
    
    
    // v-focus="'abc'"  ===> binding.value = 'abc'
    console.log('focus.... binding', binding.value)
    // 聚焦元素
    el.focus()
  }
})

formato de uso

<input v-foucs="'xxxx'" />

Resolver la verificación de permisos a nivel de botón

En main.js, defina la directiva global

// 注册一个全局自定义指令 `v-allow`
Vue.directive('allow', {
    
    
  inserted: function(el, binding) {
    
    
    // 从vuex中取出points,
    const points = store.state.user.userInfo.roles.points
    // 如果points有binding.value则显示
    if (points.includes(binding.value)) {
    
    
      // console.log('判断这个元素是否会显示', el, binding.value)
    } else {
    
    
      el.parentNode.removeChild(el)
      // el.style.display = 'none'
    }
  }
})

usar

<el-button
+           v-allow="'import_employee'"
            type="warning"
            size="small"
            @click="$router.push('/import')"
          >导入excel</el-button>

Aquí el : 'import_employee'es del identificador

[Falló la transferencia de la imagen del enlace externo, el sitio de origen puede tener un mecanismo anti-leeching, se recomienda guardar la imagen y subirla directamente (img-OHL0NZor-1673401451136)(asset/image-20210428165654008.png)]

Resumen de los puntos clave del proceso de control de autoridad

Escena de negocios

Hay diferentes departamentos funcionales en la empresa, todos los cuales usan el mismo sistema, y ​​las cosas que las personas de diferentes departamentos necesitan para operar en el sistema son diferentes.

Es necesario configurar diferentes permisos según los diferentes roles de los empleados

Idea de diseño de permiso RBAC

[Falló la transferencia de la imagen del enlace externo, el sitio de origen puede tener un mecanismo anti-leeching, se recomienda guardar la imagen y cargarla directamente (img-Zjgpc0W3-1673401451136)(asset/image-20210427155035187.png)]

Una idea de diseño basada en roles

  1. Configurar roles para empleados (un empleado puede tener múltiples roles)
  2. Configurar puntos de permiso para roles (un rol puede tener múltiples puntos de permiso)

Siempre que los empleados tengan un rol, automáticamente tienen todos los puntos de autoridad vinculados al rol.

3. Módulos comerciales correspondientes basados ​​en ideas de diseño de autoridad

  1. gestión de empleados
  2. gestión de roles
  3. Gestión de puntos de permiso

Los empleados obtienen datos de permisos

​ La interfaz de información del empleado contiene todos los datos de permiso del empleado actual

userInfo:{
  roles: {
    menus: [],  // 菜单权限数据
    points: [] // 按钮权限数据
  }
}

Usar datos de permisos para realizar un procesamiento de permisos específico

  1. Control de permisos de menú

    Iniciar sesión > datos de permisos del menú > coincidir con todos los datos de enrutamiento dinámico local > obtener datos de enrutamiento dinámico filtrados de acuerdo con los permisos

    1. Agregar al sistema de enrutamiento (el componente addRoutes se puede representar de acuerdo con la ID de la ruta )
    2. Agregado a la representación del menú izquierdo (administración de vuex + v-for transversal)
  2. Control de permisos de botones

    Iniciar sesión > Datos de permiso del botón > Usar el ID de permiso independiente del botón para buscar en los datos de permiso

    directiva personalizada

Supongo que te gusta

Origin blog.csdn.net/weixin_45357661/article/details/128639638
Recomendado
Clasificación