使用若依框架时发现了该bug,在菜单回显的时候,子节点没有全部选中,父节点也被默认全选了
/** 打开弹窗 */
const open = async (row: RoleApi.RoleVO) => {
dialogVisible.value = true
resetForm()
// 加载 Menu 列表。注意,必须放在前面,不然下面 setChecked 没数据节点
menuOptions.value = handleTree(await MenuApi.getSimpleMenusList())
// 设置数据
formData.id = row.id
formData.name = row.name
formData.code = row.code
formLoading.value = true
try {
formData.value.menuIds = await PermissionApi.getRoleMenuList(row.id)
// 设置选中
formData.value.menuIds.forEach((menuId: number) => {
treeRef.value.setChecked(menuId, true, false)
})
} finally {
formLoading.value = false
}
}

因为在保存时,会将父节点id子节点id一起保存,导致回显 都被默认选中了,
解决方案:
在加载时,从回显数据区去掉没有全选的父节点id,菜单并且存在多层级的情况,孙节点没有全部选中,则子节点、父节点都需要剔除;
/**
* 清洗选中 ID,移除不合法的父节点
* @param {Array} tree - 树结构
* @param {Array} selected - 后端返回的一维 ID 列表
*/
function cleanSelected(tree, selected) {
const selectedSet = new Set(selected);
const validSet = new Set();
function dfs(node) {
const hasChildren = node.children && node.children.length > 0;
if (!hasChildren) {
// 叶子节点
if (selectedSet.has(node.id)) validSet.add(node.id);
return { selected: selectedSet.has(node.id), allSelected: selectedSet.has(node.id) };
}
let childSelected = false;
let childAllSelected = true;
for (const child of node.children) {
const res = dfs(child);
childSelected = childSelected || res.selected;
childAllSelected = childAllSelected && res.allSelected;
}
const selfSelected = selectedSet.has(node.id);
// 情况 1:父节点选中但子节点没有全选 → 父节点无效
if (selfSelected && !childAllSelected) {
// 不加入 validSet
return { selected: true, allSelected: false };
}
// 情况 2:父节点选中并且子节点全部选中 → 保留父节点,移除子节点
if (selfSelected && childAllSelected) {
validSet.add(node.id);
// 删除所有子节点
node.children.forEach(c => validSet.delete(c.id));
return { selected: true, allSelected: true };
}
// 情况 3:父节点未选中,但子节点选中了 → 保留子节点
return { selected: childSelected, allSelected: false };
}
tree.forEach(root => dfs(root));
return [...validSet];
}
/** 打开弹窗 */
const open = async (row: RoleApi.RoleVO) => {
dialogVisible.value = true
resetForm()
// 加载 Menu 列表。注意,必须放在前面,不然下面 setChecked 没数据节点
menuOptions.value = handleTree(await MenuApi.getSimpleMenusList())
// 设置数据
formData.id = row.id
formData.name = row.name
formData.code = row.code
formLoading.value = true
try {
formData.menuIds = await PermissionApi.getRoleMenuList(row.id)
// 设置选中
// 去掉所有半选节点ID
const cleanMenuIds = cleanSelected(menuOptions.value, formData.menuIds)
treeRef.value.setCheckedKeys(cleanMenuIds, false) // setCheckedNodes()
} finally {
formLoading.value = false
}
}
5026

被折叠的 条评论
为什么被折叠?



