權(quán)限管理實(shí)現(xiàn)
1.角色列表頁(yè)
1.1 完成roles組件靜態(tài)布局
Elemenet組件 Table 表格 展開(kāi)行:
通過(guò)設(shè)置 type="expand" 和 Scoped slot 可以開(kāi)啟展開(kāi)行功能,el-table-column 的模板會(huì)被渲染成為展開(kāi)行的內(nèi)容智政,展開(kāi)行可訪(fǎng)問(wèn)的屬性與使用自定義列模板時(shí)的 Scoped slot 相同。
傳送門(mén)http://element-cn.eleme.io/#/zh-CN/component/table
Elemenet組件 Tag 標(biāo)簽 可移除標(biāo)簽 :
傳送們http://element-cn.eleme.io/#/zh-CN/component/tag
//直接復(fù)制user組件皱蹦,重命名roles.vue,設(shè)置router.js眷蜈,roles.vue組件demo
<template>
<div id="user">
<!-- 頂級(jí)面包屑 -->
<el-row>
<el-col :span="24">
<breadcrumb :level2="level2" :level3="level3"></breadcrumb>
</el-col>
</el-row>
<!-- 操縱框 -->
<el-row class="operate">
<el-col :span="24">
<el-button type="primary" plain @click="visible=true">添加角色</el-button>
</el-col>
</el-row>
<!-- 用戶(hù)數(shù)據(jù) -->
<el-row>
<el-col :sapn="24">
<el-table :data="userList" style="width: 100%" border>
<!-- 展開(kāi)的table -->
<el-table-column type="expand">
<!-- 模板 -->
<template slot-scope="props">
<!-- {{props.row.children}} -->
<!-- 生成tag標(biāo)簽 -->
<!-- <el-tag closable>測(cè)試</el-tag> -->
<!-- 生成最左邊的一級(jí)菜單 -->
<el-row v-for="item in props.row.children" :key="item.id">
<el-col :span="4">
<el-tag closable>{{item.authName}}</el-tag>
<!-- 小箭頭 -->
<i class="el-icon-arrow-right"></i>
</el-col>
<el-col :span="20">
<!-- 二級(jí)菜單 需要當(dāng)度占一行 用row嵌套即可-->
<el-row v-for="level2 in item.children" :key="level2.id">
<el-col :span="4">
<el-tag closable type="success">{{level2.authName}}</el-tag>
<!-- 小箭頭 -->
<i class="el-icon-arrow-right"></i>
</el-col>
<el-col :span="20">
<el-tag closable v-for="level3 in level2.children" :key="level3.id" type="warning">{{level3.authName}}</el-tag>
<!-- 小箭頭 -->
<i class="el-icon-arrow-right"></i>
</el-col>
</el-row>
</el-col>
</el-row>
<el-row v-if="props.row.children.length==0">
<el-col :span="24">沒(méi)有分配權(quán)限</el-col>
</el-row>
</template>
</el-table-column>
<!-- 返回的數(shù)據(jù)沒(méi)有對(duì)應(yīng)的屬性名沪哺,把prop刪掉 -->
<!-- 增加type="index",會(huì)設(shè)置排序 -->
<el-table-column label="#" width="30" type="index"></el-table-column>
<el-table-column prop="roleName" label="角色名稱(chēng)" width="180"></el-table-column>
<el-table-column prop="roleDesc" label="角色描述" width="300"></el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button type="primary" plain size="mini" icon="el-icon-edit"></el-button>
<el-button type="danger" plain size="mini" icon="el-icon-check"></el-button>
<el-button type="warning" plain size="mini" icon="el-icon-delete"></el-button>
</template>
</el-table-column>
</el-table>
</el-col>
</el-row>
</div>
</template>
<script>
export default {
//寫(xiě)了name方便在Vue Devtools谷歌插件應(yīng)用內(nèi)找到對(duì)應(yīng)的組件
name: "user",
data() {
return {
level2: "權(quán)限管理",
level3: "角色列表",
//用戶(hù)的數(shù)據(jù)
userList: []
};
},
methods: {},
//生命周期函數(shù)酌儒,回調(diào)函數(shù)
async created() {
let res = await this.$axios.get("roles");
console.log(res);
this.userList = res.data.data;
}
};
</script>
<style lang="scss">
#user {
.operate {
background-color: #e8edf3;
}
.el-dialog {
width: 30%;
}
}
</style>
1.2 完成roles組件動(dòng)態(tài)交互
Ⅰ. 添加角色:同user組件類(lèi)似(完整代碼在頁(yè)面底部)
代碼邏輯同user組件差不多辜妓,由于顯示狀態(tài)碼201之前沒(méi)在axios攔截器上設(shè)置,所以修改vue-axios.js
//原先的代碼
<script>
if(response.data.meta.status===200){
//成功,提示返回的信息
Vue.prototype.$message.success(response.data.meta.msg);
}else if(response.data.meta.status===400){
//失敗,提示返回的信息
Vue.prototype.$message.error(response.data.meta.msg);
}
</script>
//修改后代碼
<script>
//if(response.data.meta.status===200){
//便捷寫(xiě)法忌怎,indexOf判斷響應(yīng)的狀態(tài)碼是否存在
if([200,201].indexOf(response.data.meta.status)){
//成功,提示返回的信息
Vue.prototype.$message.success(response.data.meta.msg);
}else if(response.data.meta.status===400){
//失敗,提示返回的信息
Vue.prototype.$message.error(response.data.meta.msg);
}
</script>
Ⅱ. 刪除角色:同user組件類(lèi)似(完整代碼在頁(yè)面底部)
Ⅲ. 編輯角色:同user組件類(lèi)似(完整代碼在頁(yè)面底部)
Ⅳ. 權(quán)限分配:
Elemenet組件 Tree 樹(shù)形控件 默認(rèn)展開(kāi)和默認(rèn)選中:
傳送門(mén)http://element-cn.eleme.io/#/zh-CN/component/tree
常用 | 作用 |
---|---|
1.default-expand-all | 是否默認(rèn)展開(kāi)所有節(jié)點(diǎn)籍滴,默認(rèn)為false |
2.default-checked-keys | 默認(rèn)勾選的節(jié)點(diǎn)的 key 的數(shù)組 |
3.node-key | 每個(gè)樹(shù)節(jié)點(diǎn)用來(lái)作為唯一標(biāo)識(shí)的屬性,整棵樹(shù)應(yīng)該是唯一的 |
4.ref="tree" | 獲取和設(shè)置選中節(jié)點(diǎn) |
Ⅴ. 刪除單個(gè) Tag 標(biāo)簽 權(quán)限
Elemenet組件 Tag 標(biāo)簽 事件 close榴啸,表示關(guān)閉 Tag 時(shí)觸發(fā)的事件
@close="delCurrentTag(當(dāng)前角色,當(dāng)前權(quán)限)"
VI. 子組件修改權(quán)限后孽惰,父組件菜單欄不同步更新
解決方法 | 局限性 |
---|---|
1.window.location.reload() | 畫(huà)面閃爍效果不好 |
2.$emit子組件向父組件通信 | 代碼比方法1多,效果好插掂,詳情看Vue 后臺(tái)管理項(xiàng)目11-Vue中的通信傳值
|
//完整roles組件代碼
<template>
<div id="roles">
<!-- 頂級(jí)面包屑 -->
<el-row>
<el-col :span="24">
<breadcrumb :level2="level2" :level3="level3"></breadcrumb>
</el-col>
</el-row>
<!-- 操縱框 -->
<el-row class="operate">
<el-col :span="24">
<el-button type="primary" plain @click="addVistable=true">添加角色</el-button>
</el-col>
</el-row>
<!-- 用戶(hù)數(shù)據(jù) -->
<el-row>
<el-col :sapn="24">
<el-table :data="rolesList" style="width: 100%" border>
<!-- 展開(kāi)的table -->
<el-table-column type="expand">
<!-- 模板 -->
<template slot-scope="props">
<!-- {{props.row.children}} -->
<!-- 生成tag標(biāo)簽 -->
<!-- <el-tag closable>測(cè)試</el-tag> -->
<!-- 生成最左邊的一級(jí)菜單 -->
<el-row v-for="item in props.row.children" :key="item.id">
<el-col :span="4">
<el-tag closable @close="delCurrentTag(props.row,item)">{{item.authName}}</el-tag>
<!-- 小箭頭 -->
<i class="el-icon-arrow-right"></i>
</el-col>
<el-col :span="20">
<!-- 二級(jí)菜單 需要當(dāng)度占一行 用row嵌套即可-->
<el-row v-for="level2 in item.children" :key="level2.id">
<el-col :span="4">
<el-tag closable @close="delCurrentTag(props.row,level2)" type="success">{{level2.authName}}</el-tag>
<!-- 小箭頭 -->
<i class="el-icon-arrow-right"></i>
</el-col>
<el-col :span="20">
<el-tag closable @close="delCurrentTag(props.row,level3)" v-for="level3 in level2.children" :key="level3.id" type="warning">{{level3.authName}}</el-tag>
<!-- 小箭頭 -->
<i class="el-icon-arrow-right"></i>
</el-col>
</el-row>
</el-col>
</el-row>
<el-row v-if="props.row.children.length==0">
<el-col :span="24">沒(méi)有分配權(quán)限</el-col>
</el-row>
</template>
</el-table-column>
<!-- 返回的數(shù)據(jù)沒(méi)有對(duì)應(yīng)的屬性名灰瞻,把prop刪掉 -->
<!-- 增加type="index"腥例,會(huì)設(shè)置排序 -->
<el-table-column label="#" width="40" type="index"></el-table-column>
<el-table-column prop="roleName" label="角色名稱(chēng)" width="180"></el-table-column>
<el-table-column prop="roleDesc" label="角色描述" width="300"></el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button type="primary" @click="showEditDialog(scope.row)" plain size="mini" icon="el-icon-edit"></el-button>
<el-button type="danger" @click="delOne(scope.row)" plain size="mini" icon="el-icon-delete"></el-button>
<el-button type="warning" plain size="mini" icon="el-icon-check" @click="showRolesDialog(scope.row)"></el-button>
</template>
</el-table-column>
</el-table>
</el-col>
</el-row>
<!-- 添加角色的對(duì)話(huà)框 -->
<el-dialog title="添加角色" :visible.sync="addVistable">
<!-- label-position控制label名的顯示位置辅甥,注意要設(shè)置label-width才能生效 -->
<!-- 表單數(shù)據(jù)驗(yàn)證要加form上添加:rules="rules"屬性 -->
<!-- 表單提交驗(yàn)證要加ref="userForm"屬性,并將userForm傳給提交按鈕 -->
<el-form :model="addForm" :rules="rules" ref="addForm" label-position="left" label-width="80px">
<el-form-item label="角色名稱(chēng)" prop="roleName">
<el-input v-model="addForm.roleName" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="角色描述" prop="roleDesc">
<el-input v-model="addForm.roleDesc" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="addVistable = false">取 消</el-button>
<!-- 記住這邊的userForm要加單引號(hào) -->
<el-button type="primary" @click="submitForm('addForm')">確 定</el-button>
</div>
</el-dialog>
<!-- 編輯角色的對(duì)話(huà)框 -->
<el-dialog title="編輯角色" :visible.sync="editVistable">
<!-- 這里不能用addForm,因?yàn)閍ddForm默認(rèn)是空燎竖,而編輯點(diǎn)誰(shuí)就有 -->
<el-form :model="editForm" :rules="rules" ref="editForm" label-position="left" label-width="80px">
<el-form-item label="角色名稱(chēng)" prop="roleName">
<el-input v-model="editForm.roleName" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="角色描述" prop="roleDesc">
<el-input v-model="editForm.roleDesc" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="editVistable = false">取 消</el-button>
<!-- 記住這邊的userForm要加單引號(hào) -->
<el-button type="primary" @click="submitEdit('editForm')">確 定</el-button>
</div>
</el-dialog>
<!-- 權(quán)限分配對(duì)話(huà)框 -->
<el-dialog title="分配權(quán)限" :visible.sync="roleVistable">
<!-- label-position控制label名的顯示位置璃弄,注意要設(shè)置label-width才能生效 -->
<!-- 表單數(shù)據(jù)驗(yàn)證要加form上添加:rules="rules"屬性 -->
<!-- 表單提交驗(yàn)證要加ref="userForm"屬性,并將userForm傳給提交按鈕 -->
<el-row>
<el-col :span="24">
<!-- 樹(shù)形結(jié)構(gòu) -->
<el-tree
:data="totalRoles"
show-checkbox
node-key="id"
:default-checked-keys="checkedKeys"
:props="defaultProps"
default-expand-all
ref="tree">
</el-tree>
</el-col>
</el-row>
<div slot="footer" class="dialog-footer">
<el-button @click="roleVistable = false">取 消</el-button>
<!-- 這里不是獲取from了而是要獲取樹(shù)形結(jié)構(gòu)的數(shù)據(jù) -->
<el-button type="primary" @click="submitRoles">確 定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
export default {
//寫(xiě)了name方便在Vue Devtools谷歌插件應(yīng)用內(nèi)找到對(duì)應(yīng)的組件
name: "roles",
data() {
return {
level2: "權(quán)限管理",
level3: "角色列表",
//角色的數(shù)據(jù)
rolesList: [],
//新增框顯示標(biāo)記
addVistable:false,
//新增的數(shù)據(jù)
addForm: {
roleName:"",
roleDesc:""
},
//編輯的數(shù)據(jù)
editForm: {
roleName:"",
roleDesc:""
},
//編輯框顯示標(biāo)記
editVistable:false,
//權(quán)限框顯示標(biāo)記
roleVistable:false,
//所有的權(quán)限數(shù)據(jù)
totalRoles:[],
//提交權(quán)限分配需要,共享角色數(shù)據(jù)
selectRole:{},
//權(quán)限tree的對(duì)應(yīng)關(guān)系
defaultProps:{
label:'authName'
},
//默認(rèn)選中的字段
checkedKeys:[],
//表單驗(yàn)證規(guī)則
rules: {
roleName:[
{required:true,message:"請(qǐng)輸入角色名",trigger:"blur"},
{min:3,max:32,message:"長(zhǎng)度在3到32個(gè)字符",trigger:"blur"}
],
roleDesc:[
{required:true,message:"請(qǐng)輸入角色描述",trigger:"blur"},
{min:3,max:32,message:"長(zhǎng)度在3到32個(gè)字符",trigger:"blur"}
]
}
};
},
methods: {
//獲取roles數(shù)據(jù)的方法
async getRoles() {
//依次往下執(zhí)行
let res = await this.$axios.get("roles");
this.rolesList = res.data.data;
},
submitForm(addForm){
this.addVistable = true;
//直接獲取表單驗(yàn)證
this.$refs[addForm].validate(async valid=>{
if(valid){
//提交數(shù)據(jù)
let res = await this.$axios.post('roles',this.addForm)
//關(guān)閉對(duì)話(huà)框
this.addVistable = false;
if(res.data.meta.status == 201) {
//成功重新獲取數(shù)據(jù)
this.getRoles()
}else{
//提示失敗构回,axios攔截器有了
}
}else {
this.$message.error('請(qǐng)檢查數(shù)據(jù)');
return false;
}
})
},
delOne(data){
console.log(data);
let id = data.id;
//提示用戶(hù)
this.$confirm('此操作將永久刪除這類(lèi)角色夏块,是否繼續(xù)?',"提示",{
confirmButtonText:"確定",
cancelButtonText:"取消",
type:"danger"
})
.then(async()=>{
//確定
let res = await this.$axios.delete(`roles/${id}`);
//console.log(res);
//重新獲取用戶(hù)數(shù)據(jù)即可
this.getRoles();
})
.catch(()=>{
//取消
})
},
//顯示編輯框
showEditDialog(data){
this.editVistable = true;
this.editForm = data;
},
//保存編輯結(jié)果
submitEdit(formName){
this.$refs[formName].validate(async valid => {
if (valid) {
//驗(yàn)證成功
//調(diào)用接口
let res = await this.$axios.put(`roles/${this.editForm.id}`,this.editForm);
console.log(res);
if(res.data.meta.status===200){
//201表示成功請(qǐng)求并創(chuàng)建了新的資源纤掸,可以繼續(xù)執(zhí)行下一步
//關(guān)閉彈框
this.editVistable=false;
//重新獲取數(shù)據(jù)
this.getRoles();
}
} else {
//驗(yàn)證失敗
this.$message.error('請(qǐng)檢查數(shù)據(jù)')
return false;
}
});
},
//顯示權(quán)限框
async showRolesDialog(data){
//提交權(quán)限分配需要:保存正在編輯權(quán)限的角色數(shù)據(jù)
this.selectRole = data;
//顯示對(duì)話(huà)框
this.roleVistable = true;
//獲取所有權(quán)限列表
let res = await this.$axios.get('rights/tree');
console.log(res);
//保存數(shù)據(jù)到data中
this.totalRoles = res.data.data;
// 每次調(diào)用前先將this.checkedKeys變?yōu)榭諗?shù)組脐供,避免被之前的權(quán)限覆蓋
this.checkedKeys = []
//利用遞歸獲取所有的權(quán)限id
let findChild = (father)=>{
//找后代
if(father.children){
// console.log('有兒子');
father.children.forEach(v=>{
// this.checkedKeys.push(v.id)
//每一個(gè)兒子都可能有后代
findChild(v);
})
}else{
//沒(méi)有后代
// console.log('沒(méi)有后代了');
//因?yàn)閠ree這個(gè)組件的問(wèn)題,如果父id設(shè)置選中借跪,會(huì)默認(rèn)選中它的所有子節(jié)點(diǎn)
//只需要添加最底層的即可
this.checkedKeys.push(father.id)
}
}
//調(diào)用遞歸
// console.log(data);
findChild(data)
},
//提交權(quán)限分配
async submitRoles(){
//獲取選中的權(quán)限對(duì)象數(shù)據(jù)
// console.log(this.$refs.tree.getCheckedNodes());
//獲取半選中的節(jié)點(diǎn)對(duì)象數(shù)據(jù)
// console.log(this.$refs.tree.getHalfCheckedNodes());
//獲取半選中的權(quán)限ID
// console.log(this.$refs.tree.getHalfCheckedKeys());
//獲取選中的權(quán)限ID
// console.log(this.$refs.tree.getCheckedKeys());
//選中的key
let checkedKeys = this.$refs.tree.getCheckedKeys();
//半選中的key政己,父節(jié)點(diǎn)的id也要獲取
let halfCheckedKeys = this.$refs.tree.getHalfCheckedKeys();
//兩個(gè)數(shù)組→id1,id2,id3的字符串
//concat數(shù)組拼接方法
//用join將數(shù)組轉(zhuǎn)換成分隔符隔開(kāi)的字符串
let totalKeys = checkedKeys.concat(halfCheckedKeys);
let rids = totalKeys.join(',')
console.log(rids);
console.log(this.selectRole);
let res = await this.$axios.post(`roles/${this.selectRole.id}/rights`,{
rids
})
console.log(res);
//隱藏權(quán)限框
this.roleVistable = false;
//重新獲取角色數(shù)據(jù)即可
this.getRoles();
},
//刪除角色的指定權(quán)限
async delCurrentTag(role,right){
// console.log(role);
// console.log(right);
let res = await this.$axios.delete(`roles/${role.id}/rights/${right.id}`);
console.log(res);
//這邊全部重新獲取頁(yè)面數(shù)據(jù),會(huì)折疊起來(lái)掏愁,用戶(hù)體驗(yàn)不好
// this.getRoles();
//可以直接把服務(wù)器返回的權(quán)限賦值給當(dāng)前角色
role.children = res.data.data;
}
},
//生命周期函數(shù)歇由,回調(diào)函數(shù)
async created() {
this.getRoles()
}
};
</script>
<style lang="scss">
#roles {
.operate {
background-color: #e8edf3;
}
.el-dialog {
width: 30%;
}
}
</style>
2.權(quán)限列表頁(yè)
直接參照之前的頁(yè)面寫(xiě)卵牍,沒(méi)什么交互,效果如下:
<template>
<div id="user">
<!-- 頂級(jí)面包屑 -->
<el-row>
<el-col :span="24">
<breadcrumb :level2="level2" :level3="level3"></breadcrumb>
</el-col>
</el-row>
<!-- 用戶(hù)數(shù)據(jù) -->
<el-row>
<el-col :sapn="24">
<el-table :data="rightList" style="width: 100%" border>
<!-- 返回的數(shù)據(jù)沒(méi)有對(duì)應(yīng)的屬性名沦泌,把prop刪掉 -->
<!-- 增加type="index"糊昙,會(huì)設(shè)置排序 -->
<el-table-column label="#" width="40" type="index"></el-table-column>
<el-table-column prop="authName" label="權(quán)限名稱(chēng)" width="180"></el-table-column>
<el-table-column prop="path" label="路徑" width="200"></el-table-column>
<el-table-column prop="level" label="層級(jí)" width="80">
<template slot-scope="scope">
<span v-if="scope.row.level==='0'">一級(jí)</span>
<span v-if="scope.row.level==='1'">二級(jí)</span>
<span v-if="scope.row.level==='2'">三級(jí)</span>
</template>
</el-table-column>
</el-table>
</el-col>
</el-row>
</div>
</template>
<script>
export default {
//寫(xiě)了name方便在Vue Devtools谷歌插件應(yīng)用內(nèi)找到對(duì)應(yīng)的組件
name: "user",
data() {
return {
level2: "權(quán)限管理",
level3: "權(quán)限列表",
//權(quán)限的數(shù)據(jù)
rightList: []
}
},
methods: {
},
//生命周期函數(shù),回調(diào)函數(shù)
async created() {
//get請(qǐng)求需要通過(guò)params屬性來(lái)傳對(duì)象
let res = await this.$axios.get("rights/list");
console.log(res);
this.rightList = res.data.data
}
};
</script>
<style lang="scss">
#user {
.operate {
background-color: #e8edf3;
}
.el-dialog {
width:30%;
}
}
</style>
PS:有讀者問(wèn)我要這階段寫(xiě)的源碼谢谦,這里共享下百度云地址
鏈接:https://pan.baidu.com/s/1hJAZU28I2PFjueBfzd7M6g
提取碼:4zn9
本文同步發(fā)表在我的個(gè)人博客:https://www.lubaojun.com/