適用情況
1.element ui中tree 如果設置check-strictly 為true 則是父節點和子節點不進行關聯(即點擊選中哪個就是哪個)不方便用戶使用,如果設置為false 則父節點和子節點進行關聯,但是后端數據要求需要提供選中子節點的父節點 就需要我們講半選狀態的菜單ID getHalfCheckedKeys()和選中的ID getCheckedKeys()合並
都給后端,后端詳情返回父節點的ID,如果直接設置選中setCheckedKeys 因為父節點關聯子節點 【因此就會選中在回顯的樹呈現父節點下面的子節點都進行了選中】因此可以想辦法區別一下那個ID是半選的ID,哪些是選中的ID,進行設置,但是文檔上提供了設置全選的方法,但是沒有設置半選的方法;
2.下面是解決當前場景的方法(目前是個新增、編輯、簡單的角色,里面的權限樹,方式可以以上問題現象)
<template>
<div class="roleManagement" style="min-height:calc(100vh - 95px)">
<el-dialog :title="textMap[dialogStatus]" :visible.sync="dialogFormVisible" center width="750px">
<el-form ref="organizationData" :rules="rules" :model="organizationData">
<el-form-item label="角色名稱" prop="roleName" :label-width="formLabelWidth">
<el-input v-model="organizationData.roleName" type="text" placeholder="請輸入角色名稱" maxlength="20" />
</el-form-item>
<el-form-item label="角色描述" :label-width="formLabelWidth">
<el-input v-model="organizationData.roleDesc" type="textarea" :rows="5" maxlength="200" @input="change" />
</el-form-item>
<el-form-item label="權限" :label-width="formLabelWidth">
<!-- <el-tree
ref="tree"
style="margin-top:5px"
:data="privilegeData"
:default-checked-keys="privilegeUpData"
:default-expanded-keys="privilegeUpData"
show-checkbox
node-key="id"
default-expanded
:props="defaultProps"
@check="handleCheckChangeAuth"
/> -->
<el-tree
ref="tree"
style="margin-top:5px"
:data="privilegeData"
:default-expanded-keys="privilegeUpData"
show-checkbox
node-key="id"
default-expanded
:props="defaultProps"
:check-strictly="checkStrictly"
@check-change="handleCheckChangeAuthNode"
/>
</el-form-item>
</el-form>
<div v-if="dialogStatus ==='Details'" slot="footer" class="dialog-footer">
<el-button type="primary" @click="dialogFormVisible = false">確定</el-button>
</div>
<div v-else slot="footer" class="dialog-footer">
<el-button @click="backData()">取消</el-button>
<el-button type="primary" @click="dialogStatus === 'Create' ? createData() : updateData()">提交</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { sysMenuInfo, roleListAdd, roleDetails, roleListEdit } from '@/api/vue-roleManagement'
export default {
name: 'RoleManagement',
data() {
const tagNameReg = (rule, value, callback) => {
if (value.length === 0) {
callback(new Error('請輸入角色名稱'))
} else if (value.length > 20) {
callback(new Error('角色名稱必須要在20個字以內'))
} else {
callback()
}
}
return {
textMap: {
update: 'Edit',
create: 'Create',
detail: 'Details'
},
dialogFormVisible: false, // 新增、編輯彈出框是否展示
formLabelWidth: '120px', // 彈出框form表單寬度展示
dialogStatus: '',
readonly: false,
organizationData: {
roleName: '', // 角色名稱
roleDesc: '' // 角色描述
},
rules: {
roleName: [
{ required: true, validator: tagNameReg, trigger: 'blur' }
]
},
privilegeData: [], // 菜單權限
privilegeUpData: null,
defaultProps: {
children: 'childMenus',
label: 'menuName'
},
menuIdsObj: [], // 菜單選中的權限限制
ids: '' // 編輯ID
}
},
created() {
this.getList()
},
methods: {
/**
* 選中的節點展示
*/
handleCheckChangeAuthNode() {
this.menuIdsObj = []
// this.menuIdsObj = this.$refs.tree.getCheckedNodes() // 全選
this.menuIdsObj = this.$refs.tree.getCheckedNodes().concat(this.$refs.tree.getHalfCheckedNodes())
},
/**
* 新增事件
*/
AddEvent() {
this.dialogStatus = 'Create'
this.dialogFormVisible = true
this.resetForm('organizationData')
Object.keys(this.organizationData).forEach((key) => {
this.organizationData[key] = ''
})
// 菜單權限接口
this.privilegeData = []
this.privilegeUpData = []
this.sysMenuInfo()
},
/**
* 菜單權限展示 用於新增
*/
sysMenuInfo() {
sysMenuInfo().then((res) => {
if (res.code === 0 || res.code === '0') {
this.privilegeData = res.data
} else {
this.$message({
type: 'error',
message: res.message
})
}
}).catch((err) => {
console.log(err)
})
},
/**
* 新增保存接口
*/
createData() {
this.$refs['organizationData'].validate((valid) => {
if (valid) {
const params = {
roleName: this.organizationData.roleName, // 角色名稱
roleDesc: this.organizationData.roleDesc, // 角色描述
menuIds: [] // 選中的菜單數據
}
this.menuIdsObj.forEach(function(item) {
const obj = {
type: item.type,
parentId: item.parentId,
id: item.id
}
params.menuIds.push(obj)
})
roleListAdd(params).then((res) => {
if (res.code === '0' || res.code === 0) {
this.$message({
type: 'success',
message: '創建成功'
})
this.dialogFormVisible = false
this.pageNum = 1
this.pageSize = 10
this.getList()
} else {
this.$message({
type: 'error',
message: res.message
})
}
})
}
})
},
/**
* 點擊編輯的時間
*/
handleUpdate(row) {
this.dialogStatus = 'Edit'
this.dialogFormVisible = true
this.resetForm('organizationData')
Object.keys(this.organizationData).forEach((key) => {
this.organizationData[key] = ''
})
this.ids = row.id
this.privilegeData = [] // 菜單接口
this.privilegeUpData = []
// 調用詳情接口
this.roleDetailsList(row.id)
},
/**
* 菜單獲取接口 用於編輯接口展示
*/
getPartsysMenuInfo() {
return new Promise(function(resolve) {
sysMenuInfo().then((res) => resolve(res))
})
},
/**
* 詳情展示接口用於編輯展示
*/
getPartRoleDetails(id) {
return new Promise(function(resolve) {
roleDetails({ id: id }).then((res) => resolve(res))
})
},
roleDetailsList(id) {
if (id === '' || id === null || id === '{}' || id === undefined) {
return false
}
const _this = this
return Promise.all([this.getPartsysMenuInfo(), this.getPartRoleDetails(id)])
.then((results) => {
// 處理數據
if (results[0].code === '0' || results[0].code === 0) { // 菜單接口
_this.privilegeData = results[0].data
} else {
_this.$message({
message: results[0].message,
type: 'error'
})
_this.privilegeData = []
}
if (results[1].code === '0' || results[1].code === 0) { // 代表詳情接口
_this.organizationData.roleName = results[1].data.roleName // 角色名稱
_this.organizationData.roleDesc = results[1].data.roleDesc // 角色描述
if (results[1].data.roleMenus === null && results[1].data.roleButtons === null || results[1].data.roleMenus.length <= 0 && results[1].data.roleButtons.length <= 0) {
_this.privilegeUpData = null
} else {
const arr = []
const brr = [] // 用於渲染編輯回顯的內容
// 菜單存放的數組
results[1].data.roleMenus.forEach(function(element) {
arr.push(element.menuId)
const brrObj1 = {
type: 1,
parentId: element.parentId,
id: element.menuId
}
brr.push(brrObj1)
})
results[1].data.roleButtons.forEach(function(element) {
arr.push(element.buttonId)
const brrObj2 = {
type: 2,
parentId: element.parentId,
id: element.buttonId
}
brr.push(brrObj2)
})
_this.menuIdsObj = brr // 渲染是否選中問題 [樹]
const checkTreeNode = [] // 存放選中的節點
const parentNodes = []
_this.$nextTick(() => {
for (const item of arr) {
const node = _this.$refs.tree.getNode(item)
if (node && node.isLeaf) {
checkTreeNode.push(item)
} else if (node) {
parentNodes.push(node)
}
}
// 設置所有子節點選中,自動回填父節點
_this.$refs.tree.setCheckedKeys(checkTreeNode)
// 未回填的父節點單獨設置
for (let node of parentNodes) {
do {
// 應當有狀態的父節點在未選中時設置為半選中狀態
if (!node.checked && !node.indeterminate) {
node.indeterminate = true
}
// node.indeterminate = true 僅對一個節點進行半選中狀態設置,其父節點不能自動級聯設置,所以這里循環設置級聯父節點狀態
node = node.parent
} while (node)
}
})
_this.privilegeUpData = arr // 用於需要渲染的ID數據
}
} else {
_this.$message({
message: results[1].message,
type: 'error'
})
}
})
},
/**
* 編輯接口
*/
updateData() {
this.$refs['organizationData'].validate((valid) => {
if (valid) {
const params = {
roleName: this.organizationData.roleName, // 角色名稱
roleDesc: this.organizationData.roleDesc, // 角色描述
menuIds: [], // 選中的菜單數據
id: this.ids
}
// 處理選中需要的數據
this.menuIdsObj.forEach(function(item) {
const obj = {
type: item.type,
parentId: item.parentId,
id: item.id
}
params.menuIds.push(obj)
})
roleListEdit(params).then((res) => {
if (res.code === '0' || res.code === 0) {
this.$message({
type: 'success',
message: '編輯成功'
})
this.dialogFormVisible = false
this.pageNum = 1
this.pageSize = 10
this.getList()
} else {
this.$message({
type: 'error',
message: res.message
})
}
})
}
})
},
/**
* 點擊返回
*/
backData() {
this.dialogFormVisible = false
}
}
}
</script>
<style lang="scss" scoped>
.roleManagement {
.header_btn {
width:100%;
height:50px;
}
.loading_btnInfo{font-size:36px;color:#409EFF;margin:auto;width:36px;height:36px;display:block;margin-top:200px}
.loading_p1{width:100%;text-align:center;height:50px;line-height:50px;font-size:14px;}
.box-card {
margin:20px;
}
.box-card_serch {
margin:20px 20px 0px 20px;
}
.search-button {
border-radius: 4px;
}
/**-----------------添加成員 成員編輯權限樣式調整---------------------------; */
/deep/ .el-tree-node__content{
height:35px !important;
}
.main_app {
.main_left {
background: #FFFFFF;
border: 1px solid #DDDEE3;
border-radius: 4px;
width: 440px;
height: 430px;
float: left;
overflow-y:auto;
.div1 {
width: 440px;
height: 40px;
padding: 11px 19.9px 9px 20.5px;
color: #4A4A4A;
border-bottom: 1px solid #DDDEE3;
cursor: pointer;
}
.treeStyle {
padding: 20px;
.p1 {
font-size: 16px;
color: #2B3642;
margin-top: 15px;
margin-bottom: 15px;
img {
width: 4px;
height: 16px;
margin-right: 12px;
vertical-align: middle;
}
span {
vertical-align: middle;
}
time {
float: right;
}
}
}
}
}
}
</style>
