55、角色列表:渲染一级权限
通过for循环,循环了scope.row
的children
属性,这个属性里包含了所有的一级权限,每循环一次,都往第一列里放一个tag
标签,这样,经过整个for循环,所有的一级权限都会被渲染出来。
<!-- 展开列 -->
<el-table-column type="expand">
<template slot-scope="scope">
<el-row v-for="(item1,i1) in scope.row.children" :key="item1.id">
<!-- 渲染一级权限 -->
<el-col :span="5"></el-col>
<el-tag>{{item1.authName}}</el-tag>
<!-- 渲染二、三级权限 -->
<el-col :span="19"></el-col>
</el-row>
<pre>
{{scope.row}}
</pre>
</template>
</el-table-column>
接下来美化一级权限的UI结构:
给每个一级权限加上下横的表格线,值得注意的是,第一行需要加一条上顶线,用到了三元表达式。
<el-row :class="['bdbottom', i1 === 0 ? 'bdtop' : '']" v-for="(item1,i1) in scope.row.children" :key="item1.id">
<!-- 渲染一级权限 -->
<el-col :span="5"></el-col>
<el-tag>{{item1.authName}}</el-tag>
<i class="el-icon-caret-right"></i>
<!-- 渲染二、三级权限 -->
<el-col :span="19"></el-col>
</el-row>
<style lang="less" scoped>
.el-tag{
margin: 7px ;
}
.bdtop{
border-top: 1px solid #eee;
}
.bdbottom{
border-bottom: 1px solid #eee;
}
</style>
56、角色列表:渲染二级权限
<!-- 渲染二、三级权限 -->
<el-col :span="19">
<!-- 通过for循环,嵌套渲染二级权限 -->
<el-row :class="[i2 === 0 ? '' : 'bdtop']" v-for="(item2, i2) in item1.children" :key="item2.id">
<el-col>
<el-tag type="success">{{item2.authName}}</el-tag>
<i class="el-icon-caret-right"></i>
</el-col>
<el-col></el-col>
</el-row>
</el-col>
需要注意的是,在给二级权限加边框线的时候,如果给每个都加上边框线,那么二级的第一个就会和一级的第一个重合,所以二级权限也用到了三元表达式,规则和一级不同。
57、角色列表:渲染三级权限
<el-col :span="6">
<el-tag type="success">{{item2.authName}}</el-tag>
<i class="el-icon-caret-right"></i>
</el-col>
<el-col :span="18">
<el-tag type="warning" v-for="(item3, i3) in item2.children" :key="item3.id">
{{item3.authName}}
</el-tag>
</el-col>
给一级和二级列加.vcenter
类,呈现垂直居中的样式。
.vcenter{
display: flex;
align-items: center;
}
58、点击删除权限按钮弹出框
先给每个tag加closable属性,可定义这个标签是否可移除。再加一个点击事件,即关闭tag时触发的事件@close="removeRightById()
。
在methods里定义这个触发函数:
// 根据ID删除对应的权限
async removeRightById(){
// 弹框提示用户是否删除
const confirmResult= await this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).catch(err => err)
if(confirmResult !== 'confirm') {
return this.$message.info('取消了删除!');
}
console.log('确认了删除!');
}
}
59、完成删除权限功能
注意点:添加API接口路径时,用反引号。
// 根据ID删除对应的权限
async removeRightById(role,rightId){
// 弹框提示用户是否删除
const confirmResult= await this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).catch(err => err)
if(confirmResult !== 'confirm') {
return this.$message.info('取消了删除!');
}
// console.log('确认了删除!');
const {data:res} = await this.$http.delete(`roles/${role.id}/rights/${rightId}`);
if(res.meta.status !== 200) {
return this.$message.error('删除权限失败!');
}
// this.getRolesList();
role.children = res.data
}
给close事件加参数,@close="removeRightById(scope.row, item3.id
)",在scope.row
上包含了角色的id,item3.id
是对应的权限id。
为什么一点删除按钮,tag
就合上了,用户体验很不好。
因为删除完成后,会重新获取整个数据列表,页面上的table表格会被重新渲染一次,打开的状态就被立马关上了,为了防止它再次被关上,把服务器返回的data重新赋值,而不是调用getRolesList( )
函数(会发生页面的完整渲染)。
<el-tag type="warning" v-for="(item3, i3) in item2.children" :key="item3.id" closable @close="removeRightById(scope.row, item3.id)">
{{item3.authName}}
</el-tag>
再将一级和二级的删除权限功能进行完整。
60、分配权限:弹出框
1、给分配权限按钮绑定click单击事件,指定一个处理函数,只要调用这个函数就会弹出框。@click=“showSetRightDialog”
2、在methods里定义这个函数:
showSetRightDialog(){ }
3、添加对应的对话框组件:
<!-- 分配权限的对话框 -->
<el-dialog title="分配权限" :visible.sync="setRightdialogVisible" width="50%">
<span>这是一段信息</span>
<span slot="footer" class="dialog-footer">
<el-button @click="setRightdialogVisible = false">取 消</el-button>
<el-button type="primary" @click="setRightdialogVisible = false">确 定</el-button>
</span>
</el-dialog>
4、在return里定义布尔值:
// 控制分配权限对话框的显示与隐藏
setRightdialogVisible:false
5、给处理函数showSetRightDialog()重新赋值就能弹出框
showSetRightDialog(){
this.setRightdialogVisible = true;
}
接下来,在弹出框的同时,将分配权限的数据以一个树形图渲染出来,保存到data中,供页面实用。
上面第四步里,在布尔值变成到true之前,获取到所有权限的数据:
// 所有权限的数据
rightslist:[]
// 展示分配权限对话框
async showSetRightDialog(){
// 获取所有权限的数据
const {data:res} = await this.$http.get('rights/tree');
if(res.meta.status !== 200) {
return this.$message.error('获取权限数据失败!');
}
// 把获取到的权限数据保存到data中
this.rightslist = res.data;
console.log(this.rightslist);
this.setRightdialogVisible = true;
}
61、树形控件
在分配权限的对话框里加树形控件:
<el-tree :data="rightslist" :props="treeProps"></el-tree>
在return里:
// 树形控件的属性绑定对象
treeProps:{
label:'authName',
children:'children'
}
.
再对树形控件进行优化,比如提供复选框进行勾选。并且,勾选了这个节点,就是勾选了这个节点的id值,即node-key
属性。还有默认展开所有节点属性default-expand-al
。
<el-tree :data="rightslist" :props="treeProps" show-checkbox default-expand-all node-key="id"></el-tree>
node-key:每个树节点用来作为唯一标识的属性,整棵树应该是唯一的,字符串。
default-expand-all:是否默认展开所有节点,布尔值。
实现已有权限默认勾选:
default-checked-keys:默认勾选的节点的 key 的数组。
<el-tree :data="rightslist" :props="treeProps" show-checkbox default-expand-all node-key="id" :default-checked-keys="defKeys"></el-tree>
// 默认选中的节点id值数组
defKeys:[105, 116]
加载当前角色已有权限:
定义一个递归函数,将角色信息传到递归的函数中,通过递归的形式,把所有三级节点的id都保存到一个数组中,再将数组赋值给defkeys
,就能实现点击分配权限按钮时,将权限默认加载出来。
如何递归,调用node里的所有数组。
// 展示分配权限对话框
async showSetRightDialog(role){
// 获取所有权限的数据
const {data:res} = await this.$http.get('rights/tree');
if(res.meta.status !== 200) {
return this.$message.error('获取权限数据失败!');
}
// 把获取到的权限数据保存到data中
this.rightslist = res.data;
console.log(this.rightslist);
********** // 递归获取三级节点的id ******************************************************************************
//这个role在当前函数中获取不到,需要在形参里定义一个
this.getLeafKeys(role, this.defKeys);
this.setRightdialogVisible = true;
},
// 通过递归的形式,获取角色下所有三级权限的id,并保存到 defkeys 数组中
getLeafKeys(node, arr) {
// node 是用来判断是否是三级节点,即是否包含children属性,arr 数组用来保存
if(!node.children) {
// 假设是三级节点,就将 id push到数组 arr 里
return arr.push(node.id);
}
//递归开始
node.children.forEach(item =>
this.getLeafKeys(item, arr));
}
在每次关闭分配权限对话框前,清空数组里的元素:
监听“分配权限”按钮:@close="setRightDialogClosed"
。
给数组defKeys
重新赋值,就不会出现元素重叠的情况了:
// 监听分配权限对话框的关闭事件
setRightDialogClosed(){
this.defKeys = [];
}
62、调用API完成分配权限功能
getCheckedKeys
:若节点可被选择(即 show-checkbox 为 true),则返回目前被选中的节点的 key 所组成的数组。(leafOnly) 接收一个 boolean 类型的参数,若为 true 则仅返回被选中的叶子节点的 keys,默认值为 false。
getHalfCheckedKeys
:若节点可被选择(即 show-checkbox 为 true),则返回目前半选中的节点的 key 所组成的数组。
先给确定按钮绑定单击事件@click="allotRights"
,在methods里定义这个函数:
// 当前即将分配权限的角色id
roleId:''
methods:{
// 展示分配权限对话框
async showSetRightDialog(role){
this.roleId = role.id;
...
}
// 点击为角色分配权限
async allotRights(){
const keys = [
// 复习es6语法:展开运算符,把数组转化为逗号分隔的字符串
...this.$refs.treeRef.getCheckedKeys(),
...this.$refs.treeRef.getHalfCheckedKeys()
]
// console.log(keys);
//传送到服务器里进行分配
const idStr = keys.join(',');
const {data:res} = await this.$http.post(`roles/${this.roleId}/rights`, {rids: idStr})
if(res.meta.status !== 200) {
return this.$message.error('更新权限失败!');
}
this.$message.success('更新权限成功!');
this.getRolesList();
this.setRightdialogVisible = false;
}