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

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

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

43
    private final MenuConverter menuConverter;
44

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

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

61 62 63 64 65 66 67 68 69 70
        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)); // 递归
        }
71
        return list;
72 73
    }

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

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

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

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

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

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

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

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


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

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

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 210
    /**
     * 获取菜单表单数据
     *
     * @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;
    }

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

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

245

246
    /**
247
     * 部门路径生成
248
     *
249 250
     * @param parentId 父ID
     * @return 父节点路径以英文逗号(, )分割,eg: 1,2,3
251
     */
252 253 254 255 256 257 258 259 260
    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();
            }
261
        }
262
        return treePath;
263 264
    }

郝先瑞 已提交
265

H
hxrui 已提交
266
}