package com.youlai.system.service.impl; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.youlai.system.common.constant.SystemConstants; import com.youlai.system.enums.MenuTypeEnum; import com.youlai.system.enums.StatusEnum; import com.youlai.system.common.model.KeyValue; import com.youlai.system.common.model.Option; import com.youlai.system.converter.MenuConverter; import com.youlai.system.mapper.SysMenuMapper; import com.youlai.system.model.bo.RouteBO; import com.youlai.system.model.entity.GenConfig; import com.youlai.system.model.entity.SysMenu; import com.youlai.system.model.form.MenuForm; import com.youlai.system.model.query.MenuQuery; import com.youlai.system.model.vo.MenuVO; import com.youlai.system.model.vo.RouteVO; import com.youlai.system.service.SysMenuService; import com.youlai.system.service.SysRoleMenuService; import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.StringUtils; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import java.util.*; import java.util.stream.Collectors; /** * 菜单业务实现类 * * @author haoxr * @since 2020/11/06 */ @Service @RequiredArgsConstructor public class SysMenuServiceImpl extends ServiceImpl implements SysMenuService { private final MenuConverter menuConverter; private final SysRoleMenuService roleMenuService; /** * 菜单列表 * * @param queryParams {@link MenuQuery} */ @Override public List listMenus(MenuQuery queryParams) { List menus = this.list(new LambdaQueryWrapper() .like(StrUtil.isNotBlank(queryParams.getKeywords()), SysMenu::getName, queryParams.getKeywords()) .orderByAsc(SysMenu::getSort) ); // 获取所有菜单ID Set menuIds = menus.stream() .map(SysMenu::getId) .collect(Collectors.toSet()); // 获取所有父级ID Set parentIds = menus.stream() .map(SysMenu::getParentId) .collect(Collectors.toSet()); // 获取根节点ID(递归的起点),即父节点ID中不包含在部门ID中的节点,注意这里不能拿顶级菜单 O 作为根节点,因为菜单筛选的时候 O 会被过滤掉 List rootIds = parentIds.stream() .filter(id -> !menuIds.contains(id)) .toList(); // 使用递归函数来构建菜单树 return rootIds.stream() .flatMap(rootId -> buildMenuTree(rootId, menus).stream()) .collect(Collectors.toList()); } /** * 递归生成菜单列表 * * @param parentId 父级ID * @param menuList 菜单列表 * @return 菜单列表 */ private List buildMenuTree(Long parentId, List menuList) { return CollectionUtil.emptyIfNull(menuList) .stream() .filter(menu -> menu.getParentId().equals(parentId)) .map(entity -> { MenuVO menuVO = menuConverter.convertToVo(entity); List children = buildMenuTree(entity.getId(), menuList); menuVO.setChildren(children); return menuVO; }).toList(); } /** * 菜单下拉数据 * * @param onlyParent 是否只查询父级菜单 如果为true,排除按钮 */ @Override public List