vue电商项目004:权限管理模块
在完成用户列表功能后大家记得把项目提交到本地和云端,并且创建一个rights子分支
1.权限列表
1.1添加对应的路由规则
import Rights from '../components/power/Rights.vue'
......
path: '/home', component: Home, redirect: '/welcome', children: [
{ path: "/welcome", component: Welcome },
{ path: "/users", component: Users },
{ path: "/rights", component: Rights }
]
......
在components新建一个power文件夹然后再文件夹下新建一个Rights.vue组件
1.2添加面包屑导航
因为所有的面包屑导航都差不多,只要适当的修改其中的内容即可,我们可以复制Users.vue中的面包屑导航然后适当的修改就可以了
<!-- 面包屑导航区域 -->
<el-breadcrumb separator-class="el-icon-arrow-right">
<el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>权限管理</el-breadcrumb-item>
<el-breadcrumb-item>权限列表</el-breadcrumb-item>
</el-breadcrumb>
1.3添加卡片视图区域
所谓的卡片视图区域其实就是显示数据的地方,在Users.vue中我们也用到了el-table一系列的组件
<el-card>
<el-table :data="RightsList" border stripe>
<el-table-column label="#" type="index"></el-table-column>
<el-table-column label="权限名称" prop="authName"></el-table-column>
<el-table-column label="路径" prop="path"></el-table-column>
<el-table-column label="权限等级" prop="level">
<template slot-scope="scope">
<el-tag v-if="scope.row.level==='0'">一级</el-tag>
<el-tag type="success" v-else-if="scope.row.level==='1'">二级</el-tag>
<el-tag type="warning" v-else>三级</el-tag>
</template>
</el-table-column>
</el-table>
</el-card>
1.4 定义权限列表并且获取所有的权限信息
功能的实现比较简单就是获取到数据并且展示在页面上就OK了
data(){
return{
//所有的权限列表
RightsList:[]
}
},
created(){
//获取所有的权限
this.getRightsList()
},
methods:{
//获取权限列表
async getRightsList(){
const {data:res}=await this.$http.get('rights/list')
if(res.meta.status!==200){
return this.$message.error('获取权限列表失败')
}
console.log(res.data)
this.RightsList=res.data
}
}
1.5tag组件的使用
在权限列表功能的完成过程中我们又使用了一个一个新的组件tag,大家也需要进行注册然后再进行使用
使用作用域插槽并且使用v-if和v-else渲染不同的权限等级
1.6效果图和完成的代码
效果图:
完整的代码:
<template>
<div>
<!-- 面包屑导航区域 -->
<el-breadcrumb separator-class="el-icon-arrow-right">
<el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>权限管理</el-breadcrumb-item>
<el-breadcrumb-item>权限列表</el-breadcrumb-item>
</el-breadcrumb>
<!-- 卡片视图区 -->
<el-card>
<el-table :data="RightsList" border stripe>
<el-table-column label="#" type="index"></el-table-column>
<el-table-column label="权限名称" prop="authName"></el-table-column>
<el-table-column label="路径" prop="path"></el-table-column>
<el-table-column label="权限等级" prop="level">
<template slot-scope="scope">
<el-tag v-if="scope.row.level==='0'">一级</el-tag>
<el-tag type="success" v-else-if="scope.row.level==='1'">二级</el-tag>
<el-tag type="warning" v-else>三级</el-tag>
</template>
</el-table-column>
</el-table>
</el-card>
</div>
</template>
<script>
export default{
data(){
return{
//所有的权限列表
RightsList:[]
}
},
created(){
//获取所有的权限
this.getRightsList()
},
methods:{
//获取权限列表
async getRightsList(){
const {data:res}=await this.$http.get('rights/list')
if(res.meta.status!==200){
return this.$message.error('获取权限列表失败')
}
console.log(res.data)
this.RightsList=res.data
}
}
}
</script>
<style lang="less" scoped>
</style>
2.角色列表
2.1新建角色列表组价和添加路由
在power文件夹下新建一个Roles.vue子组件,然后添加对应的路由规则
大家完善一下即可
2.2添加面包屑导航
一样的套路再来一遍,啊哈哈
<!-- 面包屑导航 -->
<el-breadcrumb separator-class="el-icon-arrow-right">
<el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>权限管理</el-breadcrumb-item>
<el-breadcrumb-item>角色列表</el-breadcrumb-item>
</el-breadcrumb>
2.3卡片视图(显示数据)
- 在data中添加一个rightsList数据,在methods中提供一个getRightsList方法发送请求获取权限列表数据,在created中调用这个方法获取数据,同时在页面上写出卡片的视图区域
export default {
data(){
return {
roleList:[]
}
},created(){
this.getRoleList();
},methods:{
async getRoleList(){
const {data:res} = await this.$http.get('roles')
//如果返回状态为异常状态则报错并返回
// if (res.meta.status !== 200)
// return this.$message.error('获取角色列表失败')
// //如果返回状态正常,将请求的数据保存在data中
// this.roleList = res.data
console.log(res.data)
this.roleList = res.data;
}
}
- 卡片视图的区域
<!-- 卡片视图区 -->
<el-card>
<!-- 添加角色按钮区 -->
<el-row>
<el-col>
<el-button type="primary" @click="addDialogVisible=true">添加角色</el-button>
</el-col>
</el-row>
<!-- 角色列表区 -->
<!-- row-key="id" 是2019年3月提供的新特性,
if there's nested data, rowKey is required.
如果这是一个嵌套的数据,rowkey 是必须添加的属性 -->
<el-table row-key="id" :data="roleList" border stripe>
<el-table-column type="expand">
</el-table-column>
<el-table-column label="#" type="index"></el-table-column>
<el-table-column label="角色名称" prop="roleName"></el-table-column>
<el-table-column label="角色描述" prop="roleDesc"></el-table-column>
<el-table-column label="操作">
<template slot-scope="scope" width="300px">
<el-button size="mini" type="primary" icon="el-icon-edit" @click="showEditDialog(scope.row.id)">编辑</el-button>
<el-button size="mini" type="danger" icon="el-icon-delete" @click="removeRoleById(scope.row.id)">删除</el-button>
<el-button size="mini" type="warning" icon="el-icon-setting" @click="showSetRightDialog(scope.row)">分配权限</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
2.4添加角色、删除角色、编辑角色
因为这三个功能的实现已经在前面实现过,这些代码我就不一一写了,最后会给出全部的代码,里面有注释,大家可以自己看看
2.5生成权限列表
使用三重嵌套for循环生成权限下拉列表
<el-table-column type="expand">
<template slot-scope="scope">
<el-row :class="['bdbottom',i1===0?'bdtop':'','vcenter']" v-for="(item1,i1) in scope.row.children" :key="item1.id">
<!-- 渲染一级权限 -->
<el-col :span="5">
<el-tag closable @close="removeRightById(scope.row,item1.id)">{{item1.authName}}</el-tag>
<i class="el-icon-caret-right"></i>
</el-col>
<!-- 渲染二级和三级权限 -->
<el-col :span="19">
<el-row :class="[i2===0?'':'bdtop','vcenter']" v-for="(item2,i2) in item1.children" :key="item2.id">
<el-col :span="6">
<el-tag type="success" closable @close="removeRightById(scope.row,item2.id)">{{item2.authName}}</el-tag>
<i class="el-icon-caret-right"></i>
</el-col>
<el-col :span="18">
<el-tag type="warning" v-for="item3 in item2.children" :key="item3.id" closable @close="removeRightById(scope.row,item3.id)">{{item3.authName}}</el-tag>
</el-col>
</el-row>
</el-col>
</el-row>
</template>
</el-table-column>
注意: row-key=“id” 是2019年3月提供的新特性,if there’s nested data, rowKey is required.如果这是一个嵌套的数据,rowkey 是必须添加的属性,在el-table中必须添加row-key="id"的属性
下拉列表的样式
通过设置global.css中的#app样式min-width:1366px 解决三级权限换行的问题
,通过给一级权限el-row添加display:flex,align-items:center的方式解决一级权限垂直居中的问题,二级权限也类似添加,因为需要给多个内容添加,可以将这个样式设置为一个.vcenter{display:flex;align-items:center}
在Roles.vue中添加的样式
.el-tag {
margin: 7px;
}
.bdtop {
border-top: 1px solid #eee;
}
.bdbottom {
border-bottom: 1px solid #eee;
}
.vcenter {
display: flex;
align-items: center;
}
2.6.添加权限删除功能
给每一个权限的el-tag添加closable属性,是的权限右侧出现“X”图标
再给el-tag添加绑定close事件处理函数removeRightById(scope.row,item1.id)
removeRightById(scope.row,item2.id)
removeRightById(scope.row,item3.id)
//根据Id删除对应的权限
async removeRightById(role,rightId){
//弹框提示用户是否删除
const confirmRes=await this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
//如果用户点击确认,则confirmResult 为'confirm'
//如果用户点击取消, 则confirmResult获取的就是catch的错误消息'cancel'
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).catch(err => err)
if(confirmRes!=='confirm'){
return this.$message.info('取消了删除!')
}
//用户点击了确定表示真的要删除
//当发送delete请求之后,返回的数据就是最新的角色权限信息
const {data:res}=await this.$http.delete(`roles/${role.id}/rights/${rightId}`)
if(res.meta.status!==200){
return this.$message.error('删除权限失败!')
}
//无需再重新加载所有权限
//只需要对现有的角色权限进行更新即可
role.children=res.data
this.$message.success('删除权限成功!')
}
2.7完成权限分配功能
先给分配权限按钮添加事件
< el-button size=“mini” type=“warning” icon=“el-icon-setting” @click=“showSetRightDialog”>分配权限< /el-button>
在showSetRightDialog函数中请求权限树数据并显示对话框
//分配权限的对话框
async showSetRightDialog(role){
this.roleId=role.id
//获取所有权限的数据
const {data:res}=await this.$http.get('rights/tree')
if(res.meta.status!==200){
return this.$message.error('获取权限数据失败!')
}
//把获取到的权限数据保存到rightsList中
this.rightsList=res.data
this.getLeafKeys(role,this.defKeys)
this.SetRightDialogVisible=true
}
添加分配权限对话框,并添加绑定数据setRightDialogVisible
2.8使用属性结构完成分配权限的功能
在element.js中引入Tree,注册Tree
分配权限的对话框
<!-- 分配权限的对话框 -->
<el-dialog
title="分配权限"
:visible.sync="SetRightDialogVisible"
width="50%" @close="setRightDialogClosed">
<!-- 树形控件 -->
<!-- 树形组件
show-checkbox:显示复选框
node-key:设置选中节点对应的值
default-expand-all:是否默认展开所有节点
:default-checked-keys 设置默认选中项的数组
ref:设置引用 -->
<el-tree :data="rightsList" :props="treeProps" show-checkbox node-key="id" default-expand-all :default-checked-keys="defKeys" ref="treeRef"></el-tree>
<!-- 底部区域 -->
<span slot="footer" class="dialog-footer">
<el-button @click="SetRightDialogVisible = false">取 消</el-button>
<el-button type="primary" @click="allotRights" >确 定</el-button>
</span>
</el-dialog>
分配权限涉及到的函数
//分配权限的对话框
async showSetRightDialog(role){
this.roleId=role.id
//获取所有权限的数据
const {data:res}=await this.$http.get('rights/tree')
if(res.meta.status!==200){
return this.$message.error('获取权限数据失败!')
}
//把获取到的权限数据保存到rightsList中
this.rightsList=res.data
this.getLeafKeys(role,this.defKeys)
this.SetRightDialogVisible=true
},
//通过递归的形式,获取角色下所有三级权限的id,并保存到defKeys数组中
getLeafKeys(node,arr){
//该函数会获取到当前角色的所有三级权限id并添加到defKeys中
//如果当前节点不包含children属性,则表示node为三级权限
if(!node.children){
return arr.push(node.id)
}
node.children.forEach(item=>this.getLeafKeys(item,arr))
},
//监听分配权限对话框的关闭事件
setRightDialogClosed(){
this.defKeys=[]
},
//点击为角色分配权限
async allotRights(){
//获取所有选中及半选的内容
const keys=[
...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.getRoleList()
this.SetRightDialogVisible=false
}
}
2.9Roles.vue完整的代码
<template>
<div>
<!-- 面包屑导航 -->
<el-breadcrumb separator-class="el-icon-arrow-right">
<el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>权限管理</el-breadcrumb-item>
<el-breadcrumb-item>角色列表</el-breadcrumb-item>
</el-breadcrumb>
<!-- 卡片视图区 -->
<el-card>
<!-- 添加角色按钮区 -->
<el-row>
<el-col>
<el-button type="primary" @click="addDialogVisible=true">添加角色</el-button>
</el-col>
</el-row>
<!-- 角色列表区 -->
<!-- row-key="id" 是2019年3月提供的新特性,
if there's nested data, rowKey is required.
如果这是一个嵌套的数据,rowkey 是必须添加的属性 -->
<el-table row-key="id" :data="roleList" border stripe>
<el-table-column type="expand">
<template slot-scope="scope">
<el-row :class="['bdbottom',i1===0?'bdtop':'','vcenter']" v-for="(item1,i1) in scope.row.children" :key="item1.id">
<!-- 渲染一级权限 -->
<el-col :span="5">
<el-tag closable @close="removeRightById(scope.row,item1.id)">{{item1.authName}}</el-tag>
<i class="el-icon-caret-right"></i>
</el-col>
<!-- 渲染二级和三级权限 -->
<el-col :span="19">
<el-row :class="[i2===0?'':'bdtop','vcenter']" v-for="(item2,i2) in item1.children" :key="item2.id">
<el-col :span="6">
<el-tag type="success" closable @close="removeRightById(scope.row,item2.id)">{{item2.authName}}</el-tag>
<i class="el-icon-caret-right"></i>
</el-col>
<el-col :span="18">
<el-tag type="warning" v-for="item3 in item2.children" :key="item3.id" closable @close="removeRightById(scope.row,item3.id)">{{item3.authName}}</el-tag>
</el-col>
</el-row>
</el-col>
</el-row>
<!-- <pre>
{{scope.row}}
</pre> -->
</template>
</el-table-column>
<el-table-column label="#" type="index"></el-table-column>
<el-table-column label="角色名称" prop="roleName"></el-table-column>
<el-table-column label="角色描述" prop="roleDesc"></el-table-column>
<el-table-column label="操作">
<template slot-scope="scope" width="300px">
<el-button size="mini" type="primary" icon="el-icon-edit" @click="showEditDialog(scope.row.id)">编辑</el-button>
<el-button size="mini" type="danger" icon="el-icon-delete" @click="removeRoleById(scope.row.id)">删除</el-button>
<el-button size="mini" type="warning" icon="el-icon-setting" @click="showSetRightDialog(scope.row)">分配权限</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
<!-- 分配权限的对话框 -->
<el-dialog
title="分配权限"
:visible.sync="SetRightDialogVisible"
width="50%" @close="setRightDialogClosed">
<!-- 树形控件 -->
<el-tree :data="rightsList" :props="treeProps" show-checkbox node-key="id" default-expand-all :default-checked-keys="defKeys" ref="treeRef"></el-tree>
<!-- 底部区域 -->
<span slot="footer" class="dialog-footer">
<el-button @click="SetRightDialogVisible = false">取 消</el-button>
<el-button type="primary" @click="allotRights" >确 定</el-button>
</span>
</el-dialog>
<!-- 添加角色的对话框 -->
<el-dialog title="添加角色" :visible.sync="addDialogVisible" width="50%" @close="addDialogClosed">
<!-- 内容主体区域 -->
<el-form :model="roleForm" :rules="roleFormRules" ref="roleFormRef" label-width="80px">
<el-form-item label="角色名称" prop="roleName">
<el-input v-model="roleForm.roleName"></el-input>
</el-form-item>
<el-form-item label="角色描述" prop="roleDesc">
<el-input v-model="roleForm.roleDesc"></el-input>
</el-form-item>
</el-form>
<!-- 底部区域 -->
<span slot="footer" class="dialog-footer">
<el-button @click="addDialogVisible = false">取 消</el-button>
<el-button type="primary" @click="addRole">确 定</el-button>
</span>
</el-dialog>
<!-- 修改角色界面 -->
<el-dialog title="编辑角色" :visible.sync="editDialogVisible" width="50%" @click="editDialogClosed">
<!-- 内容主体区域 -->
<el-form :model="editForm" :rules="editFormRules" ref="editFormRef" label-width="70px">
<el-form-item label="角色名称" prop="roleName">
<el-input v-model="editForm.roleName"></el-input>
</el-form-item>
<el-form-item label="角色描述" prop="roleDesc">
<el-input v-model="editForm.roleDesc"></el-input>
</el-form-item>
</el-form>
<!-- 页脚区域 -->
<span slot="footer" class="dialog-footer">
<el-button @click="editDialogVisible=flase">取 消</el-button>
<el-button type="primary" @click="editRoleInfo">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
export default {
data() {
return {
//所有角色列表数据
roleList: [],
//查询到的角色信息对象
editForm: {},
//控制编辑角色对话框的显示与隐藏
editDialogVisible: false,
//控制添加角色对话框的显示与隐藏
addDialogVisible: false,
//添加角色的表单数据
roleForm: {
roleName: '',
roleDesc: ''
},
//添加角色列表的的规则
roleFormRules: {
roleName: [{
required: true,
message: '请输入角色名称',
trigger: 'blur'
}]
},
//修改角色列表的的规则
editFormRules: {
roleName: [{
required: true,
message: '请输入角色名称',
trigger: 'blur'
}]
},
//控制分配权限对话框的显示与隐藏
SetRightDialogVisible:false,
// 所有权限的数据
rightsList:[],
// 树形控件的属性绑定对象
treeProps:{
label:'authName',
children:'children'
},
//默认选中的节点id值数组
defKeys:[],
// 当前即将分配权限的id
roleId:''
}
},
created() {
this.getRoleList()
},
methods: {
//获取所有的角色的列表
async getRoleList() {
const {
data: res
} = await this.$http.get('roles')
if (res.meta.status !== 200) {
return this.$message.error('获取角色列表失败')
}
this.roleList = res.data
},
//添加关闭重置
addDialogClosed() {
this.$refs.roleFormRef.resetFields()
},
//编辑角色信息重置
editDialogClosed() {
this.$refs.editFormRef.resetFields()
},
//添加角色
addRole() {
this.$refs.roleFormRef.validate(async valid => {
if (!valid) return
//可以发起添加用户的网络请求
const {
data: res
} = await this.$http.post('roles', this.roleForm)
if (res.meta.status !== 201) {
return this.$message.error('添加角色失败!')
}
this.$message.success('添加角色成功!')
//隐藏添加用户对话框
this.addDialogVisible = false
this.getRoleList()
})
},
//提交编辑后的角色信息
editRoleInfo() {
this.$refs.editFormRef.validate(async valid => {
if (!valid) return
//可以发起修改用户的网络请求
const {
data: res
} = await this.$http.put('roles/' + this.editForm.roleId, {
roleName: this.editForm.roleName,
roleDesc: this.editForm.roleDesc
})
if (res.meta.status !== 200) {
return this.$message.error('更新角色信息失败!')
}
//隐藏修改用户对话框
this.editDialogVisible = false
// 刷新列表列表
this.getRoleList()
// 提示用户信息修改成功
this.$message.success('更新角色信息成功!')
})
},
// 根据id删除对应的角色信息
async showEditDialog(id) {
const {
data: res
} = await this.$http.get('roles/' + id)
if (res.meta.status !== 200)
return this.$message.error('查询角色信息失败!')
this.editForm = res.data
this.editDialogVisible = true
console.log(this.editForm)
},
async removeRoleById(id) {
//弹框询问角色是否删除数据
const confirmRes = await this.$confirm('此操作将永久删除该角色, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).catch(err => err)
//console.log(confirmRes)
//如果角色确认删除,则返回值为字符串confirm
//如果角色取消删除,则返回值为字符串cancel
if (confirmRes !== 'confirm') {
return this.$message.info('已取消了删除!')
}
const {
data: res
} = await this.$http.delete('roles/' + id)
if (res.meta.status !== 200) {
return this.$message.error('删除角色失败!')
}
// 刷新列表列表
this.getRoleList()
// 提示用户信息修改成功
this.$message.success('删除角色信息成功!')
},
//根据Id删除对应的权限
async removeRightById(role,rightId){
//弹框提示用户是否删除
const confirmRes=await this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).catch(err => err)
if(confirmRes!=='confirm'){
return this.$message.info('取消了删除!')
}
const {data:res}=await this.$http.delete(`roles/${role.id}/rights/${rightId}`)
if(res.meta.status!==200){
return this.$message.error('删除权限失败!')
}
role.children=res.data
this.$message.success('删除权限成功!')
},
//分配权限的对话框
async showSetRightDialog(role){
this.roleId=role.id
//获取所有权限的数据
const {data:res}=await this.$http.get('rights/tree')
if(res.meta.status!==200){
return this.$message.error('获取权限数据失败!')
}
//把获取到的权限数据保存到rightsList中
this.rightsList=res.data
this.getLeafKeys(role,this.defKeys)
this.SetRightDialogVisible=true
},
//通过递归的形式,获取角色下所有三级权限的id,并保存到defKeys数组中
getLeafKeys(node,arr){
if(!node.children){
return arr.push(node.id)
}
node.children.forEach(item=>this.getLeafKeys(item,arr))
},
//监听分配权限对话框的关闭事件
setRightDialogClosed(){
this.defKeys=[]
},
//点击为角色分配权限
async allotRights(){
const keys=[
...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.getRoleList()
this.SetRightDialogVisible=false
}
}
}
</script>
<style lang="less" scoped>
.el-tag {
margin: 7px;
}
.bdtop {
border-top: 1px solid #eee;
}
.bdbottom {
border-bottom: 1px solid #eee;
}
.vcenter {
display: flex;
align-items: center;
}
</style>
2.10效果图
大家如果需要数据库和后端的接口以及有任何问题和建议欢迎大家留言,会持续更新,谢谢支持!!