需要實現的效果:
- 1、子選單如果不是全部選中,一級選單半選。
- 2、子選單全選,一級選單選中。
- 3、一級選單選擇,二級選單全選。
- 4、沒有二級選單,則只控制一級選單。
主要用到的屬性是checked和halfCheckedKeys,透過手動控制那些選單選中,那些半選中實現功能。
**頁面截圖: **
完整程式碼如下:
<template>
<div>
<a-tree v-model="checkedKeys" checkable :tree-data="menuList" @check="onCheck"></a-tree>
</div>
</template>
<script>
import { getRoleMenusById } from '@/api/role'
import { getMenusList } from '@/api/menu'
import { sortBykey, toTree } from '@/utils/common'
export default {
name: 'EditModal',
data () {
return {
checkedKeys: [],
record: {},
// 全部選單
menuList: [],
// 授權選單
menuRole: []
}
},
created () {},
mounted () {},
methods: {
sortBykey,
toTree,
/**
* 獲取使用者的授權選單
* @param {*} menuId
* @returns
*/
getUserMenus (menuId) {
return new Promise((resolve, reject) => {
getRoleMenusById(menuId).then((res) => {
resolve(res)
}).catch((err) => {
reject(err)
})
})
},
/**
* 獲取選單列表
*/
getMenusList () {
return new Promise((resolve, reject) => {
getMenusList().then((response) => {
response = response.items
response.forEach((item) => {
item.title = item.name
item.key = item.id
})
response = this.sortBykey(response, 'sort')
response = this.toTree(response)
resolve(response)
}).catch((err) => {
reject(err)
})
})
},
/**
* 選中樹狀選單
* @param {*} checkedKeys
* @param {*} info
*/
onCheck (checkedKeys, info) {
console.log(checkedKeys, info)
this.checkedKeys = this.getCheckedKeys(this.menuList, checkedKeys)
},
/**
* 篩選選中,以及半選中
* 判斷當前的節點是否選擇,如果選中,判斷主節點是否需要選中,
如果沒選中,判斷主節點是否要選中
* @param {*} menuList
* @param {*} checkedMenu
*/
getCheckedKeys (menuList, checkedMenu) {
console.log('checkedMenu', checkedMenu)
console.log('menuList', menuList)
const result = {
checked: [],
halfCheckedKeys: []
}
// 選出二級選單,那些選中
menuList.forEach((item) => {
if (item.children) {
const subAllMenu = item.children.map(item => item.key)
const isCheckedAll = this.selectedAllSubMenu(subAllMenu, checkedMenu)
if (isCheckedAll) {
// 一級選單全選
result.checked.push(item.key)
// 二級選單全選
result.checked = [...result.checked, ...subAllMenu]
} else {
// 二級選單隻選選中的
const subMenu = this.getSubMenu(item.children, checkedMenu)
result.checked = [...result.checked, ...subMenu]
if (subMenu.length) {
// 根據二級選單是否選中來半選一級選單
result.halfCheckedKeys.push(item.key)
}
}
} else {
// 一級選單選中是否選中
if (checkedMenu.indexOf(item.key) !== -1) {
result.checked.push(item.key)
}
}
})
return result
},
/**
* 檢測子選單是否都選中
* @param {*} sub
* @param {*} menu
*/
selectedAllSubMenu (sub, menu) {
for (const item of sub) {
if (!menu.includes(item)) {
// 如果sub中的某個元素不在superset中,則返回false
return false
}
}
// 如果所有元素都在menu中,則返回true
return true
},
/**
* 獲取選中的子選單
* @param {*} sub
* @param {*} menu
*/
getSubMenu (sub, menu) {
const result = []
sub.forEach(item => {
if (menu.indexOf(item.key) !== -1) {
result.push(item.key)
}
})
return result
},
/**
* 初始化
* @param {*} record
*/
async init (record) {
this.record = { ...record }
this.$nextTick(async () => {
// 全部選單
this.menuList = await this.getMenusList()
console.log('menuList', this.menuList)
// 授權選單
this.menuRole = await this.getUserMenus(this.record.menu_id)
console.log('menuRole', this.menuRole)
// 授權選單特殊處理,子選單未完全選中,父選單半選中
// this.menuRole.menu 資料為 [2,6,7,8,9,10,11,12,13,16,17,18,19,20,21,22,24]
this.checkedKeys = this.getCheckedKeys(this.menuList, this.menuRole.menu.split(',').map(Number))
})
}
}
}
</script>
完成!