一、按钮权限
使用vue自定义事件,全局匹配权限,成功展示,失败删除按钮
1、自定义事件
//directive/hasPermission.js
import Vue from 'vue'
import store from '@/store'
// 校验用户是否拥有按钮权限
function hasPermission(el, binding) {
// 角色编码权限数组
const roles = store.getters && store.getters.roles
// 超级管理员拥有所有的按钮权限
// console.log('has', roles, this, Vue.prototype.ROOT_ROLE_CODE)
if (roles.includes(Vue.prototype.ROOT_ROLE_CODE)) {
return true
}
// console.log(vnode, el.parentNode)
//自定义指令-传过来的值,用于比较按钮权限
const { value } = binding
// getUserInfo 获取 当前角色所有按钮权限数组
const perms = store.getters && store.getters.perms
if (value && typeof value === 'string') {
const hasPermission = perms.includes(value)
// console.log('hasPermission', hasPermission);
if (!hasPermission) {
el.parentNode && el.parentNode.removeChild(el)
}
} else {
throw new Error(`按钮标识应该是字符串,错误参数:${value}`)
}
}
export default {
inserted(el, binding) {
hasPermission(el, binding)
},
update(el, binding) {
hasPermission(el, binding)
},
}
//directive/index.js
import hasPermission from './hasPermission'
const instructions = {}
instructions.install = function(Vue) {
Vue.directive('hasPermission', hasPermission)
}
export default instructions
//main.js
// 全局指令注册-按钮权限指令
import permission from './directive/index'
2、页面使用
<span v-hasPermission="'system:menu:update'">
<el-button type="text" size="medium" @click="editMenuInfo(row)"
>修改</el-button
>
<el-divider direction="vertical"></el-divider>
</span>
<!--或者-->
<el-button
v-hasPermission="'system:menu:create'"
size="small"
type="primary"
plain
icon="el-icon-circle-plus"
>添加菜单</el-button>
3、问题处理
前提:类似左侧树状图-右侧展示内容存在修改/保存按钮
1、树状图分父/子级(目前只有2级),修改权限拆分两个,使用v-show来隐藏/显示按钮,v-if会与权限冲突,导致修改按钮渲染丢失(图1,2)
2、因为匹配失败会删除该元素的父级中的第一个子级,如果存在按钮互斥(如:修改/保存)的情况,权限按钮外层需要多包裹div,或者在保存按钮同级放置一个空div(图3,4)
<div v-if="isDisabled">
<div>
<el-button
v-show="currentData.children"
v-hasPermission="'system:role:updateGroupPerm'"
size="small"
type="primary"
plain
:loading="loading"
icon="iconfont icon-bianji1 icon-margin"
@click="changeTableState"
>修改权限</el-button
>
<el-button
v-show="!currentData.children"
v-hasPermission="'system:role:updateRolePerm'"
size="small"
type="primary"
plain
:loading="loading"
icon="iconfont icon-bianji1 icon-margin"
@click="changeTableState"
>修改权限</el-button
>
</div>
</div>
<div v-else>
<!--或者-->
<div></div>
<el-button size="small" plain @click="cancel">取消</el-button>
<el-button size="small" type="primary" @click="confirm">
保存
</el-button>
</div>
<!--树状图 权限分离处理(支持表达式)-->
<el-dropdown-item
v-hasPermission="
data.children
? 'system:role:updateGroup'
: 'system:role:updateRole'
"
:command="beforeCommand('edit', data, node)"
>修改</el-dropdown-item
>
4、按钮最多四个处理
(互斥按钮,需要设置为同一个权限),否则按钮展示会丢失按钮
<el-table-column
label="操作"
align="center"
fixed="right"
:width="showList.length * 80"
>
<template slot-scope="{ row }">
<div class="split-btns">
<div
v-for="(item, i) in showList"
:key="item.key"
class="contentBox"
>
<el-button
type="text"
size="medium"
:disabled="item.isDisabled && item.isDisabled(row)"
@click="item.fn(row)"
>{{
typeof item.label === 'string'
? item.label
: item.label(row)
}}</el-button
>
<el-divider
v-if="
(i < showList.length - 1 && !moreList.length) ||
moreList.length
"
direction="vertical"
></el-divider>
</div>
<!--更多-->
<el-dropdown v-if="moreList.length" trigger="click">
<span class="el-dropdown-link">
<i class="el-icon-more menuActiveText"></i>
</span>
<el-dropdown-menu slot="dropdown">
<template v-for="item in moreList">
<el-dropdown-item
:class="{
'dropdown-item': !(
item.isDisabled && item.isDisabled(row)
),
}"
:key="item.key"
:disabled="item.isDisabled && item.isDisabled(row)"
@click.native="item.fn(row)"
>{{
typeof item.label === 'string'
? item.label
: item.label(row)
}}</el-dropdown-item
>
</template>
</el-dropdown-menu>
</el-dropdown>
</div>
</template>
</el-table-column>
import { mapGetters } from 'vuex'
data(){
return {
permissionList: [
{
label: '查看',
key: 'system:staff:detail',
fn: (row) => {
this.handleEditStaff(row, 'view')
},
},
{
label: '角色权限',
key: 'system:staff:updateRole',
fn: (row) => {
this.handleEditRole(row)
},
},
{
label: '数据权限',
key: 'system:staff:dataRole',
fn: (row) => {
this.handleEditData(row)
},
},
{
label: '修改',
key: 'system:staff:edit',
fn: (row) => {
this.handleEditStaff(row, 'edit')
},
},
{
label: (row) => {
return row.accountState === 1 ? '停用' : '启用'
},
key: 'system:staff:isEnable',
isDisabled: ({ fromType }) => {
return !fromType
},
fn: (row) => {
return row.accountState === 1
? this.handleDisable(row)
: this.handleEnable(row)
},
},
// {
// label: '删除',
// key: 'system:staff:delete',
// isDisabled: ({ fromType }) => {
// return !fromType
// },
// fn: (row) => {
// this.handleDel(row)
// },
// },
],
// 展示的四个按钮
showList: [],
// 超过四个隐藏的
moreList: [],
}
},
computed: {
// roles 角色权限 perms 按钮权限数组
...mapGetters(['perms', 'roles']),
},
created() {
this.fetchPermList()
},
methods: {
// 初始化按钮权限
fetchPermList() {
const perms = this.perms
let perms1 = []
// 如果是超级管理员角色,不校验按钮权限
if (this.roles.includes(Vue.prototype.ROOT_ROLE_CODE)) {
perms1 = this.permissionList
} else {
this.permissionList.forEach((item) => {
if (perms.includes(item.key)) {
perms1.push(item)
}
})
}
const perms2 = perms1.splice(0, 3)
this.showList = perms2
this.moreList = perms1
},
}
5、遗留问题
1、树状图如果层级不确定,处理方案后端配合简单些(未验证),纯前端不建议做拆分,否则需要大量的判断逻辑
2、按钮标识设置自动带出路由来区分页面,应该保证按钮标识的唯一性,目前后端将所有数据返回在一个数组中,会出现:在A页面路由中设置了B页面的按钮标识,会影响B页面按钮展示,数据应以页面路由为单位,而不是返回在一个大数组中,这样处理也可以减少循环
3、按钮标识配置修改,前端未及时对应修改,引发的按钮丢失的问题
持续更新中…