data() {
return {
visible: false,
menuList: [],
defaultProps: {
children: 'children',
label: 'name'
},
checkedKeys: [], // 已配置的菜单
checkedMenuIds: [],
roleId: "",
boolChecked: false, // 用于判断是否点过菜单选项,确认是否调用过check方法
}
},
第一步 获取树形结构menuList,根据自己字段配置defaultProps, node-key
第二步 配置默认选中,即checkedKeys,
问题:若选中项有(系统管理,角色管理,菜单管理)这个数组,父节点选中,则子节点会全部选中,就会出现用户管理也被选中了(意思就是在设置默认选中的时候只设置叶子节点)
解决:后端封装数据,若父节点有子节点,把子节点挂在父节点上。返回的List不是树形结构,但是List里每个节点都是树形结构。前端只需要把List里的每个元素的叶子节点放进checkedKeys就好了。 我之前已经写好了方法,直接调用就好,主要是方便,可根据自己需要调整。( 代码里需要的类和方法放在了最后)
// 这里返回的不是树形结果,只是把父节点的子节点set进去 原因 element-ui el-tree 在setCheckedKeys会把所有子节点都选中
@Override
public List<MenuVo> getRoleMenuList(Long roleId) {
List<MenuVo> menuList = menuMapper.getRoleMenuList(roleId);
if (menuList == null || menuList.size() == 0) {
return null;
}
// 构建children
List<MenuVo> menuVoList = new ArrayList<>();
// 先找到所有的一级菜单
for (MenuVo menu : menuList) {
// 一级菜单没有parentId
if (menu.getParentId() == null || menu.getParentId() == 0) {
menuVoList.add(menu);
}
}
// 为一级菜单设置子菜单,getChild是递归调用的
for (MenuVo menu : menuVoList) {
menu.setChildren(getChild(menu.getId(), menuList));
}
// 注意这里返回menuList,而不是menuVoList
return menuList;
}
let list = res.data;
if(list) {
list.forEach(item => {
if (item.children === null) {
this.checkedKeys.push(item.id);
}
})
}
this.$refs.tree.setCheckedKeys(this.checkedKeys);
第三步 保存选项,我的实现方式如下, 使用@check=“check”
把所有选中的选项id 传个后端来处理,后端根据角色已有的菜单,判断出哪些是新增的菜单,哪些是删除的菜单
check(menuData, checkedData) {
this.boolChecked = true;
this.checkedMenuIds = checkedData.checkedKeys.concat(checkedData.halfCheckedKeys);
},
saveRoleMenu() {
if (!this.boolChecked) {
this.visible = false;
return;
}
let param = {
menuIds: this.checkedMenuIds.join(","),
roleId: this.roleId
}
this.$api.sys.saveRoleMenu(param).then(res => {
if (res.code === 0) {
this.$message({
type: "success",
message: "保存成功!"
});
this.roleId = "";
this.checkedMenuIds = [];
this.visible = false;
} else {
this.$message.error({
message: res.message
});
}
});
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean saveRoleMenu(List<Long> menuIds, Long roleId, Long userId) {
// 原有的菜单列表
List<MenuVo> list = menuMapper.getRoleMenuList(roleId);
// 原有的菜单
List<Long> menuArr = new ArrayList<>();
// 新增的菜单
List<SysRoleMenu> addRoleMenuList = new ArrayList<>();
SysRoleMenu roleMenu;
// 删除的菜单
List<Long> removeArr = new ArrayList<>();
for (MenuVo menu : list) {
menuArr.add(menu.getId());
}
for (Long menuId : menuIds) {
if (!menuArr.contains(menuId)) {
roleMenu = new SysRoleMenu();
roleMenu.setCreateUser(userId);
roleMenu.setMenuId(menuId);
roleMenu.setRoleId(roleId);
addRoleMenuList.add(roleMenu);
}
}
for (Long menuId : menuArr) {
if (!menuIds.contains(menuId)) {
removeArr.add(menuId);
}
}
try {
if(removeArr.size() > 0) {
roleMenuMapper.deleteBatchRoleMenu(removeArr, roleId, userId);
}
if (addRoleMenuList.size() > 0) {
roleMenuMapper.batchInsert(addRoleMenuList);
}
return true;
} catch (Exception e) {
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
logger.error("角色授权失败", e);
return false;
}
}
@Data
public class MenuVo {
private Long id;
private Long parentId;
private String name;
private String url;
private String icon;
private Integer level;
private List<MenuVo> children;
}
private List<MenuVo> getChild(Long menuId, List<MenuVo> rootMenu) {
// 子菜单
List<MenuVo> childList = new ArrayList<>();
for (MenuVo menuVo : rootMenu) {
// 遍历所有节点,将父菜单id与传过来的id比较
if (menuVo.getParentId() != null) {
if (menuVo.getParentId().equals(menuId)) {
childList.add(menuVo);
}
}
}
// 把子菜单的子菜单再循环一遍
for (MenuVo menuVo : childList) {
// 没有url子菜单还有子菜单
// 递归
menuVo.setChildren(getChild(menuVo.getId(), rootMenu));
} // 递归退出条件
if (childList.size() == 0) {
return null;
}
return childList;
}