SysMenuServiceImpl.java 8.7 KB
Newer Older
H
haoxr 已提交
1
package com.youlai.system.service.impl;
H
hxrui 已提交
2

3
import cn.hutool.core.collection.CollectionUtil;
4
import cn.hutool.core.util.NumberUtil;
5
import cn.hutool.core.util.StrUtil;
H
hxrui 已提交
6
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
7
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
H
hxrui 已提交
8
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
9
import com.youlai.common.constant.SystemConstants;
10
import com.youlai.common.enums.MenuTypeEnum;
11 12 13
import com.youlai.common.enums.StatusEnum;
import com.youlai.system.converter.MenuConverter;
import com.youlai.system.mapper.SysMenuMapper;
14 15 16 17 18 19 20
import com.youlai.system.model.bo.RouteBO;
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.common.web.model.Option;
import com.youlai.system.model.vo.RouteVO;
H
haoxr 已提交
21
import com.youlai.system.service.SysMenuService;
22
import lombok.RequiredArgsConstructor;
23
import org.apache.commons.lang3.StringUtils;
24
import org.springframework.cache.annotation.Cacheable;
H
hxrui 已提交
25 26
import org.springframework.stereotype.Service;

27 28 29
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
30
import java.util.stream.Collectors;
H
hxrui 已提交
31 32

/**
郝先瑞 已提交
33
 * 菜单业务实现类
34
 *
郝先瑞 已提交
35
 * @author haoxr
36
 * @since 2020/11/06
H
hxrui 已提交
37 38
 */
@Service
39
@RequiredArgsConstructor
郝先瑞 已提交
40
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements SysMenuService {
41

42
    private final MenuConverter menuConverter;
43

44
    /**
45 46 47
     * 菜单列表
     *
     * @param queryParams {@link MenuQuery}
48
     */
H
hxrui 已提交
49
    @Override
50
    public List<MenuVO> listMenus(MenuQuery queryParams) {
郝先瑞 已提交
51
        List<SysMenu> menus = this.list(new LambdaQueryWrapper<SysMenu>()
52
                .like(StrUtil.isNotBlank(queryParams.getKeywords()), SysMenu::getName, queryParams.getKeywords())
郝先瑞 已提交
53
                .orderByAsc(SysMenu::getSort)
54
        );
H
hxrui 已提交
55

56 57 58
        Set<Long> parentIds = menus.stream()
                .map(SysMenu::getParentId)
                .collect(Collectors.toSet());
H
hxrui 已提交
59

60 61 62 63 64 65 66 67 68 69
        Set<Long> menuIds = menus.stream()
                .map(SysMenu::getId)
                .collect(Collectors.toSet());

        List<Long> rootIds = CollectionUtil.subtractToList(parentIds, menuIds); // 求差集,得到 parentIds 中 menuIds 没有的元素

        List<MenuVO> list = new ArrayList<>();
        for (Long rootId : rootIds) {
            list.addAll(recurMenus(rootId, menus)); // 递归
        }
70
        return list;
71 72
    }

H
hxrui 已提交
73
    /**
74
     * 保存菜单
75 76
     */
    @Override
77 78
    public boolean saveMenu(MenuForm menuForm) {
        String path = menuForm.getPath();
79

80
        MenuTypeEnum menuType = menuForm.getType();  // 菜单类型
81
        switch (menuType) {
82 83 84 85 86 87 88 89
            case CATALOG -> { // 目录
                if (NumberUtil.equals(menuForm.getParentId(), 0) && !path.startsWith("/")) {
                    menuForm.setPath("/" + path); // 一级目录需以 / 开头
                }
                menuForm.setComponent("Layout");
            }
            case EXTLINK -> // 外链
                    menuForm.setComponent(null);
90
        }
91
        SysMenu entity = menuConverter.form2Entity(menuForm);
92

93 94 95
        String treePath = generateMenuTreePath(menuForm.getParentId());
        entity.setTreePath(treePath);
        return this.saveOrUpdate(entity);
96 97
    }

98 99 100 101
    /**
     * 菜单下拉数据
     */
    @Override
102
    public List<Option> listMenuOptions() {
103
        List<SysMenu> menuList = this.list(new LambdaQueryWrapper<SysMenu>().orderByAsc(SysMenu::getSort));
104
        return recurMenuOptions(SystemConstants.ROOT_NODE_ID, menuList);
105
    }
106

有来技术 已提交
107
    /**
108
     * 路由列表
有来技术 已提交
109 110
     */
    @Override
111
    //@Cacheable(cacheNames = "system", key = "'routes'")
112
    public List<RouteVO> listRoutes() {
113
        List<RouteBO> menuList = this.baseMapper.listRoutes();
114
        return recurRoutes(SystemConstants.ROOT_NODE_ID, menuList);
有来技术 已提交
115 116 117 118 119 120 121 122 123
    }

    /**
     * 递归生成菜单路由层级列表
     *
     * @param parentId 父级ID
     * @param menuList 菜单列表
     * @return
     */
124
    private List<RouteVO> recurRoutes(Long parentId, List<RouteBO> menuList) {
125
        return CollectionUtil.emptyIfNull(menuList).stream()
126
                .filter(menu -> menu.getParentId().equals(parentId))
127
                .map(menu -> {
郝先瑞 已提交
128
                    RouteVO routeVO = new RouteVO();
129 130
                    MenuTypeEnum menuTypeEnum = menu.getType();
                    if (MenuTypeEnum.MENU.equals(menuTypeEnum)) {
131 132
                        String routeName = StringUtils.capitalize(StrUtil.toCamelCase(menu.getPath(), '-')); // 路由 name 需要驼峰,首字母大写
                        routeVO.setName(routeName); //  根据name路由跳转 this.$router.push({name:xxx})
133
                    }
134
                    routeVO.setPath(menu.getPath()); // 根据path路由跳转 this.$router.push({path:xxx})
135
                    routeVO.setRedirect(menu.getRedirectUrl());
郝先瑞 已提交
136
                    routeVO.setComponent(menu.getComponent());
有来技术 已提交
137

郝先瑞 已提交
138
                    RouteVO.Meta meta = new RouteVO.Meta();
有来技术 已提交
139 140 141
                    meta.setTitle(menu.getName());
                    meta.setIcon(menu.getIcon());
                    meta.setRoles(menu.getRoles());
142
                    meta.setHidden(StatusEnum.DISABLE.getValue().equals(menu.getVisible()));
143
                    meta.setKeepAlive(true);
郝先瑞 已提交
144
                    routeVO.setMeta(meta);
145

146
                    List<RouteVO> children = recurRoutes(menu.getId(), menuList);
郝先瑞 已提交
147
                    routeVO.setChildren(children);
148 149
                    return routeVO;
                }).toList();
有来技术 已提交
150
    }
郝先瑞 已提交
151 152


153 154 155 156 157 158 159 160 161
    /**
     * 修改菜单显示状态
     *
     * @param menuId  菜单ID
     * @param visible 是否显示(1->显示;2->隐藏)
     * @return
     */
    @Override
    public boolean updateMenuVisible(Long menuId, Integer visible) {
162
        return this.update(new LambdaUpdateWrapper<SysMenu>()
163 164 165 166 167
                .eq(SysMenu::getId, menuId)
                .set(SysMenu::getVisible, visible)
        );
    }

168 169 170 171 172 173
    /**
     * 获取角色权限集合
     *
     * @param roles
     * @return
     */
174 175 176 177 178 179
    @Override
    public Set<String> listRolePerms(Set<String> roles) {
        Set<String> perms = this.baseMapper.listRolePerms(roles);
        return perms;
    }

180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
    /**
     * 获取菜单表单数据
     *
     * @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;
    }

郝先瑞 已提交
210
    /**
211
     * 递归生成菜单列表
郝先瑞 已提交
212 213 214 215 216
     *
     * @param parentId 父级ID
     * @param menuList 菜单列表
     * @return
     */
217
    private List<MenuVO> recurMenus(Long parentId, List<SysMenu> menuList) {
218 219
        return CollectionUtil.emptyIfNull(menuList)
                .stream()
郝先瑞 已提交
220
                .filter(menu -> menu.getParentId().equals(parentId))
221
                .map(entity -> {
222
                    MenuVO menuVO = menuConverter.entity2Vo(entity);
223
                    List<MenuVO> children = recurMenus(entity.getId(), menuList);
224 225
                    menuVO.setChildren(children);
                    return menuVO;
226
                }).toList();
郝先瑞 已提交
227 228 229 230 231 232 233 234 235
    }

    /**
     * 递归生成菜单下拉层级列表
     *
     * @param parentId 父级ID
     * @param menuList 菜单列表
     * @return
     */
236
    private static List<Option> recurMenuOptions(Long parentId, List<SysMenu> menuList) {
237
        List<Option> menus = CollectionUtil.emptyIfNull(menuList).stream()
郝先瑞 已提交
238
                .filter(menu -> menu.getParentId().equals(parentId))
239
                .map(menu -> new Option(menu.getId(), menu.getName(), recurMenuOptions(menu.getId(), menuList)))
郝先瑞 已提交
240 241 242 243
                .collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
        return menus;
    }

244

245
    /**
246
     * 部门路径生成
247
     *
248 249
     * @param parentId 父ID
     * @return 父节点路径以英文逗号(, )分割,eg: 1,2,3
250
     */
251 252 253 254 255 256 257 258 259
    private String generateMenuTreePath(Long parentId) {
        String treePath = null;
        if (SystemConstants.ROOT_NODE_ID.equals(parentId)) {
            treePath = String.valueOf(parentId);
        } else {
            SysMenu parent = this.getById(parentId);
            if (parent != null) {
                treePath = parent.getTreePath() + "," + parent.getId();
            }
260
        }
261
        return treePath;
262 263
    }

郝先瑞 已提交
264

H
hxrui 已提交
265
}