AdminMenuServiceImpl.java 6.61 KB
package com.diligrp.rider.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.diligrp.rider.common.enums.AdminRoleScopeEnum;
import com.diligrp.rider.common.enums.MenuScopeEnum;
import com.diligrp.rider.common.exception.BizException;
import com.diligrp.rider.entity.SysMenu;
import com.diligrp.rider.entity.SysRole;
import com.diligrp.rider.entity.SysRoleMenu;
import com.diligrp.rider.mapper.SysMenuMapper;
import com.diligrp.rider.mapper.SysRoleMapper;
import com.diligrp.rider.mapper.SysRoleMenuMapper;
import com.diligrp.rider.service.AdminMenuService;
import com.diligrp.rider.vo.AdminMenuVO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

@Service
@RequiredArgsConstructor
public class AdminMenuServiceImpl implements AdminMenuService {

    private static final String ROLE_TYPE_ADMIN = "admin";
    private static final String ROLE_TYPE_SUBSTATION = "substation";
    private static final String ROLE_CODE_PLATFORM = "platform_admin";
    private static final String ROLE_CODE_SUBSTATION = "substation_admin";

    private final SysRoleMapper sysRoleMapper;
    private final SysMenuMapper sysMenuMapper;
    private final SysRoleMenuMapper sysRoleMenuMapper;

    @Override
    public SysRole resolveRole(Long roleId, String roleType) {
        String fallbackCode = ROLE_TYPE_ADMIN.equals(roleType) ? ROLE_CODE_PLATFORM : ROLE_CODE_SUBSTATION;
        String requiredScope = ROLE_TYPE_ADMIN.equals(roleType)
                ? AdminRoleScopeEnum.PLATFORM.name()
                : AdminRoleScopeEnum.SUBSTATION.name();

        SysRole role = null;
        if (roleId != null && roleId > 0) {
            role = sysRoleMapper.selectById(roleId);
        }
        if (role == null) {
            role = sysRoleMapper.selectOne(new LambdaQueryWrapper<SysRole>()
                    .eq(SysRole::getCode, fallbackCode)
                    .eq(SysRole::getStatus, 1)
                    .last("LIMIT 1"));
        }
        if (role == null || role.getStatus() == null || role.getStatus() != 1) {
            throw new BizException("当前账号未分配有效菜单角色");
        }
        if (!requiredScope.equals(role.getRoleScope())) {
            throw new BizException("当前账号角色归属不匹配");
        }
        return role;
    }

    @Override
    public List<AdminMenuVO> getMenus(SysRole role, String roleType) {
        List<SysRoleMenu> roleMenus = sysRoleMenuMapper.selectList(new LambdaQueryWrapper<SysRoleMenu>()
                .eq(SysRoleMenu::getRoleId, role.getId()));
        if (roleMenus.isEmpty()) {
            return List.of();
        }

        List<SysMenu> allMenus = sysMenuMapper.selectList(new LambdaQueryWrapper<SysMenu>()
                .eq(SysMenu::getStatus, 1)
                .eq(SysMenu::getVisible, 1)
                .orderByAsc(SysMenu::getListOrder)
                .orderByAsc(SysMenu::getId));
        if (allMenus.isEmpty()) {
            return List.of();
        }

        Map<Long, SysMenu> menuMap = new LinkedHashMap<>();
        for (SysMenu menu : allMenus) {
            if (isScopeAllowed(menu.getMenuScope(), roleType)) {
                menuMap.put(menu.getId(), menu);
            }
        }
        if (menuMap.isEmpty()) {
            return List.of();
        }

        Set<Long> includedIds = new LinkedHashSet<>();
        for (SysRoleMenu roleMenu : roleMenus) {
            includeWithParents(roleMenu.getMenuId(), menuMap, includedIds);
        }

        Map<Long, AdminMenuVO> voMap = new LinkedHashMap<>();
        List<AdminMenuVO> roots = new ArrayList<>();
        for (SysMenu menu : allMenus) {
            if (!includedIds.contains(menu.getId())) {
                continue;
            }
            AdminMenuVO vo = toVO(menu);
            voMap.put(menu.getId(), vo);
            Long parentId = menu.getParentId() == null ? 0L : menu.getParentId();
            if (parentId > 0 && voMap.containsKey(parentId)) {
                voMap.get(parentId).getChildren().add(vo);
            } else {
                roots.add(vo);
            }
        }
        return roots;
    }

    @Override
    public String resolveHomePath(List<AdminMenuVO> menus) {
        String homePath = findPathByCode(menus, "dashboard");
        if (homePath != null && !homePath.isBlank()) {
            return homePath;
        }
        String firstPath = findFirstPath(menus);
        return firstPath == null || firstPath.isBlank() ? "/dashboard" : firstPath;
    }

    private void includeWithParents(Long menuId, Map<Long, SysMenu> menuMap, Set<Long> includedIds) {
        SysMenu current = menuMap.get(menuId);
        while (current != null && includedIds.add(current.getId())) {
            Long parentId = current.getParentId();
            if (parentId == null || parentId < 1) {
                break;
            }
            current = menuMap.get(parentId);
        }
    }

    private boolean isScopeAllowed(String menuScope, String roleType) {
        if (MenuScopeEnum.BOTH.name().equals(menuScope)) {
            return true;
        }
        if (ROLE_TYPE_ADMIN.equals(roleType)) {
            return MenuScopeEnum.PLATFORM.name().equals(menuScope);
        }
        if (ROLE_TYPE_SUBSTATION.equals(roleType)) {
            return MenuScopeEnum.SUBSTATION.name().equals(menuScope);
        }
        return false;
    }

    private AdminMenuVO toVO(SysMenu menu) {
        AdminMenuVO vo = new AdminMenuVO();
        vo.setId(menu.getId());
        vo.setCode(menu.getCode());
        vo.setName(menu.getName());
        vo.setType(menu.getType());
        vo.setPath(menu.getPath());
        vo.setIcon(menu.getIcon());
        return vo;
    }

    private String findPathByCode(List<AdminMenuVO> menus, String code) {
        for (AdminMenuVO menu : menus) {
            if (code.equals(menu.getCode()) && menu.getPath() != null && !menu.getPath().isBlank()) {
                return menu.getPath();
            }
            String nested = findPathByCode(menu.getChildren(), code);
            if (nested != null) {
                return nested;
            }
        }
        return null;
    }

    private String findFirstPath(List<AdminMenuVO> menus) {
        for (AdminMenuVO menu : menus) {
            if (menu.getPath() != null && !menu.getPath().isBlank()) {
                return menu.getPath();
            }
            String nested = findFirstPath(menu.getChildren());
            if (nested != null) {
                return nested;
            }
        }
        return null;
    }
}