250 lines
8.2 KiB
Java
250 lines
8.2 KiB
Java
package com.youlai.system.service.impl;
|
||
|
||
import cn.hutool.core.collection.CollectionUtil;
|
||
import cn.hutool.core.lang.Assert;
|
||
import cn.hutool.core.util.StrUtil;
|
||
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.youlai.system.common.constant.SystemConstants;
|
||
import com.youlai.system.common.enums.MenuTypeEnum;
|
||
import com.youlai.system.common.enums.StatusEnum;
|
||
import com.youlai.system.pojo.entity.SysDept;
|
||
import com.youlai.system.pojo.form.MenuForm;
|
||
import com.youlai.system.pojo.vo.Option;
|
||
import com.youlai.system.converter.MenuConverter;
|
||
import com.youlai.system.mapper.SysMenuMapper;
|
||
import com.youlai.system.pojo.entity.SysMenu;
|
||
import com.youlai.system.pojo.bo.RouteBO;
|
||
import com.youlai.system.pojo.query.MenuQuery;
|
||
import com.youlai.system.pojo.vo.MenuVO;
|
||
import com.youlai.system.pojo.vo.RouteVO;
|
||
import com.youlai.system.service.SysMenuService;
|
||
import lombok.RequiredArgsConstructor;
|
||
import org.springframework.cache.annotation.Cacheable;
|
||
import org.springframework.stereotype.Service;
|
||
|
||
import java.util.*;
|
||
import java.util.stream.Collectors;
|
||
|
||
/**
|
||
* 菜单业务实现类
|
||
*
|
||
* @author haoxr
|
||
* @date 2020/11/06
|
||
*/
|
||
@Service
|
||
@RequiredArgsConstructor
|
||
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements SysMenuService {
|
||
private final MenuConverter menuConverter;
|
||
|
||
/**
|
||
* 菜单列表
|
||
*/
|
||
@Override
|
||
public List<MenuVO> listMenus(MenuQuery queryParams) {
|
||
List<SysMenu> menus = this.list(new LambdaQueryWrapper<SysMenu>()
|
||
.like(StrUtil.isNotBlank(queryParams.getKeywords()), SysMenu::getName, queryParams.getKeywords())
|
||
.orderByAsc(SysMenu::getSort)
|
||
);
|
||
|
||
Set<Long> cacheMenuIds = menus.stream()
|
||
.map(menu -> menu.getId())
|
||
.collect(Collectors.toSet());
|
||
|
||
List<MenuVO> list = menus.stream().map(menu -> {
|
||
Long parentId = menu.getParentId();
|
||
// parentId不在当前菜单ID的列表,说明为顶级菜单ID,根据此ID作为递归的开始节点
|
||
if (!cacheMenuIds.contains(parentId)) {
|
||
cacheMenuIds.add(parentId);
|
||
return recurMenus(parentId, menus);
|
||
}
|
||
return new LinkedList<MenuVO>();
|
||
}).collect(ArrayList::new, ArrayList::addAll, ArrayList::addAll);
|
||
return list;
|
||
}
|
||
|
||
/**
|
||
* 保存菜单
|
||
*/
|
||
@Override
|
||
public boolean saveMenu(MenuForm menuForm) {
|
||
String path = menuForm.getPath();
|
||
|
||
MenuTypeEnum menuType = menuForm.getType(); // 菜单类型
|
||
switch (menuType) {
|
||
case CATALOG: // 目录
|
||
Assert.isTrue(path.startsWith("/"), "目录路由路径格式错误,必须以/开始");
|
||
menuForm.setComponent("Layout");
|
||
break;
|
||
case EXTLINK: // 外链
|
||
menuForm.setComponent(null);
|
||
break;
|
||
}
|
||
SysMenu entity = menuConverter.form2Entity(menuForm);
|
||
|
||
boolean result = this.saveOrUpdate(entity);
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* 菜单下拉数据
|
||
*/
|
||
@Override
|
||
public List<Option> listMenuOptions() {
|
||
List<SysMenu> menuList = this.list(new LambdaQueryWrapper<SysMenu>().orderByAsc(SysMenu::getSort));
|
||
List<Option> menus = recurMenuOptions(SystemConstants.ROOT_NODE_ID, menuList);
|
||
return menus;
|
||
}
|
||
|
||
/**
|
||
* 路由列表
|
||
*/
|
||
@Override
|
||
@Cacheable(cacheNames = "system", key = "'routes'")
|
||
public List<RouteVO> listRoutes() {
|
||
List<RouteBO> menuList = this.baseMapper.listRoutes();
|
||
List<RouteVO> routeList = recurRoutes(SystemConstants.ROOT_NODE_ID, menuList);
|
||
return routeList;
|
||
}
|
||
|
||
/**
|
||
* 递归生成菜单路由层级列表
|
||
*
|
||
* @param parentId 父级ID
|
||
* @param menuList 菜单列表
|
||
* @return
|
||
*/
|
||
private List<RouteVO> recurRoutes(Long parentId, List<RouteBO> menuList) {
|
||
List<RouteVO> list = new ArrayList<>();
|
||
Optional.ofNullable(menuList).ifPresent(menus -> menus.stream()
|
||
.filter(menu -> menu.getParentId().equals(parentId))
|
||
.forEach(menu -> {
|
||
RouteVO routeVO = new RouteVO();
|
||
MenuTypeEnum menuTypeEnum = menu.getType();
|
||
if (MenuTypeEnum.MENU.equals(menuTypeEnum)) {
|
||
routeVO.setName(menu.getPath()); // 根据name路由跳转 this.$router.push({name:xxx})
|
||
}
|
||
routeVO.setPath(menu.getPath()); // 根据path路由跳转 this.$router.push({path:xxx})
|
||
routeVO.setRedirect(menu.getRedirectUrl());
|
||
routeVO.setComponent(menu.getComponent());
|
||
|
||
RouteVO.Meta meta = new RouteVO.Meta();
|
||
meta.setTitle(menu.getName());
|
||
meta.setIcon(menu.getIcon());
|
||
meta.setRoles(menu.getRoles());
|
||
meta.setHidden(StatusEnum.DISABLE.getValue().equals(menu.getVisible()));
|
||
meta.setKeepAlive(true);
|
||
routeVO.setMeta(meta);
|
||
|
||
List<RouteVO> children = recurRoutes(menu.getId(), menuList);
|
||
routeVO.setChildren(children);
|
||
list.add(routeVO);
|
||
}));
|
||
return list;
|
||
}
|
||
|
||
|
||
/**
|
||
* 修改菜单显示状态
|
||
*
|
||
* @param menuId 菜单ID
|
||
* @param visible 是否显示(1->显示;2->隐藏)
|
||
* @return
|
||
*/
|
||
@Override
|
||
public boolean updateMenuVisible(Long menuId, Integer visible) {
|
||
boolean result = this.update(new LambdaUpdateWrapper<SysMenu>()
|
||
.eq(SysMenu::getId, menuId)
|
||
.set(SysMenu::getVisible, visible)
|
||
);
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* 获取角色权限集合
|
||
*
|
||
* @param roles
|
||
* @return
|
||
*/
|
||
@Override
|
||
public Set<String> listRolePerms(Set<String> roles) {
|
||
Set<String> perms = this.baseMapper.listRolePerms(roles);
|
||
return perms;
|
||
}
|
||
|
||
/**
|
||
* 获取菜单表单数据
|
||
*
|
||
* @param id 菜单ID
|
||
* @return
|
||
*/
|
||
@Override
|
||
public MenuForm getMenuForm(Long id) {
|
||
SysMenu entity = this.getById(id);
|
||
MenuForm menuForm = menuConverter.entity2Form(entity);
|
||
return menuForm;
|
||
}
|
||
|
||
/**
|
||
* 删除菜单
|
||
*
|
||
* @param id 菜单ID
|
||
* @return
|
||
*/
|
||
@Override
|
||
public boolean deleteMenu(Long id) {
|
||
if (id != null) {
|
||
this.remove(new LambdaQueryWrapper<SysMenu>()
|
||
.eq(SysMenu::getId, id)
|
||
.or()
|
||
.apply("CONCAT (',',tree_path,',') LIKE CONCAT('%,',{0},',%')", id));
|
||
}
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* 递归生成菜单列表
|
||
*
|
||
* @param parentId 父级ID
|
||
* @param menuList 菜单列表
|
||
* @return
|
||
*/
|
||
private List<MenuVO> recurMenus(Long parentId, List<SysMenu> menuList) {
|
||
if (CollectionUtil.isEmpty(menuList)) {
|
||
return Collections.EMPTY_LIST;
|
||
}
|
||
|
||
List<MenuVO> menus = menuList.stream()
|
||
.filter(menu -> menu.getParentId().equals(parentId))
|
||
.map(entity -> {
|
||
MenuVO menuVO = menuConverter.entity2Vo(entity);
|
||
List<MenuVO> children = recurMenus(entity.getId(), menuList);
|
||
menuVO.setChildren(children);
|
||
return menuVO;
|
||
}).collect(Collectors.toList());
|
||
return menus;
|
||
}
|
||
|
||
/**
|
||
* 递归生成菜单下拉层级列表
|
||
*
|
||
* @param parentId 父级ID
|
||
* @param menuList 菜单列表
|
||
* @return
|
||
*/
|
||
private static List<Option> recurMenuOptions(Long parentId, List<SysMenu> menuList) {
|
||
if (CollectionUtil.isEmpty(menuList)) {
|
||
return Collections.EMPTY_LIST;
|
||
}
|
||
|
||
List<Option> menus = menuList.stream()
|
||
.filter(menu -> menu.getParentId().equals(parentId))
|
||
.map(menu -> new Option(menu.getId(), menu.getName(), recurMenuOptions(menu.getId(), menuList)))
|
||
.collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
|
||
return menus;
|
||
}
|
||
|
||
|
||
}
|