package com.xiaopeng.operation.service.impl;
|
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.xiaopeng.api.feignClient.account.SysGroupMenuClient;
|
import com.xiaopeng.api.feignClient.account.SysRoleClient;
|
import com.xiaopeng.api.feignClient.account.SysUserRoleClient;
|
import com.xiaopeng.api.feignClient.account.XpOperationsRoleClient;
|
import com.xiaopeng.api.model.account.SysRole;
|
import com.xiaopeng.api.model.account.SysUserRole;
|
import com.xiaopeng.api.model.account.XpOperationsRole;
|
import com.xiaopeng.api.model.operation.SysMenu;
|
import com.xiaopeng.common.core.domain.R;
|
import com.xiaopeng.common.security.service.TokenService;
|
import com.xiaopeng.operation.mapper.SysMenuMapper;
|
import com.xiaopeng.operation.service.ISysMenuService;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.stereotype.Service;
|
|
import java.util.*;
|
import java.util.stream.Collectors;
|
|
/**
|
* <p>
|
* 菜单权限表 服务实现类
|
* </p>
|
*
|
* @author mitao
|
* @since 2026-02-03
|
*/
|
@Slf4j
|
@Service
|
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements ISysMenuService {
|
|
@Autowired
|
private TokenService tokenService;
|
|
@Autowired
|
private SysUserRoleClient sysUserRoleClient;
|
|
@Autowired
|
private SysRoleClient sysRoleClient;
|
|
@Autowired
|
private SysGroupMenuClient sysGroupMenuClient;
|
|
@Autowired
|
private XpOperationsRoleClient xpOperationsRoleClient;
|
|
/**
|
* 根据菜单ID列表查询菜单列表
|
*
|
* @param menuIds 菜单ID列表
|
* @return 菜单列表
|
*/
|
@Override
|
public List<SysMenu> selectMenusByMenuIds(List<Long> menuIds) {
|
if (menuIds == null || menuIds.isEmpty()) {
|
return new ArrayList<>();
|
}
|
|
// 使用 MyBatis-Plus 的 listByIds 方法批量查询
|
return this.listByIds(menuIds);
|
}
|
|
@Override
|
public List<SysMenu> getMenuTree(Integer type) {
|
List<SysMenu> all = lambdaQuery().eq(SysMenu::getGroupType, type).list();
|
if (all == null || all.isEmpty()) {
|
return Collections.emptyList();
|
}
|
|
// 1) 按 parentId 分组(M/C/F 都先放进去,后面再按类型筛)
|
Map<Long, List<SysMenu>> childrenMap = all.stream()
|
.filter(Objects::nonNull)
|
.collect(Collectors.groupingBy(m -> m.getParentId() == null ? 0L : m.getParentId()));
|
|
// 2) 找到根目录:通常 parentId = 0 或 null 的目录(M)
|
List<SysMenu> roots = childrenMap.getOrDefault(0L, Collections.emptyList()).stream()
|
.filter(m -> "M".equals(m.getMenuType()))
|
.sorted(Comparator.comparing(SysMenu::getOrderNum, Comparator.nullsLast(Integer::compareTo)))
|
.collect(Collectors.toList());
|
|
// 3) 递归挂载:M 下挂 C;C 下挂 F(也允许 C 下还有 C,或 M 下还有 M,按你的数据结构来)
|
for (SysMenu root : roots) {
|
fillChildren(root, childrenMap);
|
}
|
|
return roots;
|
}
|
|
private void fillChildren(SysMenu node, Map<Long, List<SysMenu>> childrenMap) {
|
Long id = node.getId();
|
if (id == null) {
|
node.setChildren(Collections.emptyList());
|
return;
|
}
|
|
List<SysMenu> rawChildren = childrenMap.getOrDefault(id, Collections.emptyList());
|
if (rawChildren.isEmpty()) {
|
node.setChildren(Collections.emptyList());
|
return;
|
}
|
|
// 根据你的层级规则过滤子节点:
|
// - M 只能挂 M/C(看你业务,很多系统 M 下是 C)
|
// - C 只能挂 F(按钮)或(有些系统 C 下还能挂 C)
|
// - F 一般不挂任何子节点
|
String type = node.getMenuType();
|
|
List<SysMenu> children = rawChildren.stream()
|
.filter(Objects::nonNull)
|
.filter(child -> {
|
if ("M".equals(type)) {
|
return "M".equals(child.getMenuType()) || "C".equals(child.getMenuType());
|
}
|
if ("C".equals(type)) {
|
return "F".equals(child.getMenuType()); // 若允许 C 下还有 C,可改为:return "C".equals(...) || "F".equals(...)
|
}
|
return false; // F 不再往下挂
|
})
|
.sorted(Comparator.comparing(SysMenu::getOrderNum, Comparator.nullsLast(Integer::compareTo)))
|
.collect(Collectors.toList());
|
|
node.setChildren(children);
|
|
// 继续递归
|
for (SysMenu child : children) {
|
fillChildren(child, childrenMap);
|
}
|
}
|
|
@Override
|
public List<SysMenu> getPermission() {
|
try {
|
// 1. 获取当前登录用户ID
|
Long userId = tokenService.getLoginUser().getUserid();
|
if (userId == null) {
|
log.warn("获取当前登录用户ID失败");
|
return Collections.emptyList();
|
}
|
|
// 2. 查询用户角色关联
|
R<SysUserRole> userRoleResult = sysUserRoleClient.selectSysUserRoleByUserId(userId);
|
if (userRoleResult == null || userRoleResult.getCode() != 200 || userRoleResult.getData() == null) {
|
log.warn("查询用户角色关联失败, userId={}", userId);
|
return Collections.emptyList();
|
}
|
|
Long roleId = userRoleResult.getData().getRoleId();
|
if (roleId == null) {
|
log.warn("用户未关联角色, userId={}", userId);
|
return Collections.emptyList();
|
}
|
|
// 3. 查询角色信息
|
R<SysRole> roleResult = sysRoleClient.getRoleById(roleId);
|
if (roleResult == null || roleResult.getCode() != 200 || roleResult.getData() == null) {
|
log.warn("查询角色信息失败, roleId={}", roleId);
|
return Collections.emptyList();
|
}
|
|
Long groupId = roleResult.getData().getGroupId();
|
if (groupId == null) {
|
log.warn("角色未关联权限组, roleId={}", roleId);
|
return Collections.emptyList();
|
}
|
|
// 4. 查询权限组关联的菜单ID列表
|
R<List<Long>> menuIdsResult = sysGroupMenuClient.selectMenuIdsByGroupId(groupId);
|
if (menuIdsResult == null || menuIdsResult.getCode() != 200 || menuIdsResult.getData() == null) {
|
log.warn("查询权限组菜单ID列表失败, groupId={}", groupId);
|
return Collections.emptyList();
|
}
|
|
List<Long> menuIds = menuIdsResult.getData();
|
if (menuIds.isEmpty()) {
|
log.info("权限组未关联菜单, groupId={}", groupId);
|
return Collections.emptyList();
|
}
|
|
// 5. 查询菜单详情
|
List<SysMenu> menus = this.listByIds(menuIds);
|
log.info("查询用户权限菜单成功, userId={}, menuCount={}", userId, menus.size());
|
return menus;
|
|
} catch (Exception e) {
|
log.error("查询用户权限菜单异常", e);
|
return Collections.emptyList();
|
}
|
}
|
|
@Override
|
public List<SysMenu> getAppPermission() {
|
// 1. 获取当前登录用户ID
|
Long operationUserId = tokenService.getLoginOperationUser().getId();
|
if (operationUserId == null) {
|
log.warn("获取当前登录用户ID失败");
|
return Collections.emptyList();
|
}
|
|
// 2. 查询运维APP菜单(group_type=2)
|
List<SysMenu> appMenus = this.lambdaQuery()
|
.eq(SysMenu::getGroupType, 2)
|
.list();
|
if (appMenus == null || appMenus.isEmpty()) {
|
return Collections.emptyList();
|
}
|
|
// 3. 查询运维人员关联的角色(一个用户可多个角色)
|
Set<Long> roleIds = new HashSet<>();
|
try {
|
R<List<XpOperationsRole>> rolesResult = xpOperationsRoleClient.listByOperationUserId(operationUserId);
|
if (rolesResult != null && rolesResult.getData() != null) {
|
for (XpOperationsRole r : rolesResult.getData()) {
|
if (r != null && r.getRoleId() != null) {
|
roleIds.add(r.getRoleId());
|
}
|
}
|
}
|
} catch (Exception e) {
|
log.error("查询运维人员角色关联异常, operationUserId={}", operationUserId, e);
|
}
|
|
// 4. 通过 role -> groupId -> group_menu 获取允许的菜单ID集合
|
Set<Long> allowedMenuIds = new HashSet<>();
|
if (!roleIds.isEmpty()) {
|
Set<Long> groupIds = new HashSet<>();
|
for (Long roleId : roleIds) {
|
try {
|
R<SysRole> roleResult = sysRoleClient.getRoleById(roleId);
|
if (roleResult != null && roleResult.getData() != null && roleResult.getData().getGroupId() != null) {
|
groupIds.add(roleResult.getData().getGroupId());
|
}
|
} catch (Exception e) {
|
log.error("查询角色信息异常, roleId={}", roleId, e);
|
}
|
}
|
|
for (Long groupId : groupIds) {
|
try {
|
R<List<Long>> menuIdsResult = sysGroupMenuClient.selectMenuIdsByGroupId(groupId);
|
if (menuIdsResult != null && menuIdsResult.getData() != null) {
|
allowedMenuIds.addAll(menuIdsResult.getData());
|
}
|
} catch (Exception e) {
|
log.error("查询权限组菜单ID异常, groupId={}", groupId, e);
|
}
|
}
|
}
|
|
// 5. 仅保留运维APP的菜单ID,避免无关ID影响 visible
|
Set<Long> appMenuIds = appMenus.stream()
|
.filter(Objects::nonNull)
|
.map(SysMenu::getId)
|
.filter(Objects::nonNull)
|
.collect(Collectors.toSet());
|
allowedMenuIds.retainAll(appMenuIds);
|
|
// 6. 组装树形结构,并用 visible 体现权限可见性(0可见 1不可见)
|
return buildAppMenuTreeWithVisible(appMenus, allowedMenuIds);
|
}
|
|
private List<SysMenu> buildAppMenuTreeWithVisible(List<SysMenu> menus, Set<Long> allowedMenuIds) {
|
Map<Long, SysMenu> idMap = new HashMap<>();
|
for (SysMenu m : menus) {
|
if (m != null && m.getId() != null) {
|
idMap.put(m.getId(), m);
|
}
|
}
|
|
Map<Long, List<SysMenu>> childrenMap = menus.stream()
|
.filter(Objects::nonNull)
|
.filter(m -> m.getId() != null)
|
.collect(Collectors.groupingBy(m -> {
|
Long pid = m.getParentId();
|
return pid == null ? 0L : pid;
|
}));
|
|
// 根节点:parentId 为 0/null,或父节点不在当前 group_type=2 集合内
|
List<SysMenu> roots = menus.stream()
|
.filter(Objects::nonNull)
|
.filter(m -> m.getId() != null)
|
.filter(m -> {
|
Long pid = m.getParentId();
|
if (pid == null || pid == 0L) {
|
return true;
|
}
|
return !idMap.containsKey(pid);
|
})
|
.sorted(Comparator.comparing(SysMenu::getOrderNum, Comparator.nullsLast(Integer::compareTo)))
|
.collect(Collectors.toList());
|
|
for (SysMenu root : roots) {
|
fillChildrenAndVisible(root, childrenMap, allowedMenuIds, new HashSet<>());
|
}
|
return roots;
|
}
|
|
private boolean fillChildrenAndVisible(SysMenu node, Map<Long, List<SysMenu>> childrenMap, Set<Long> allowedMenuIds, Set<Long> path) {
|
Long id = node.getId();
|
if (id != null && !path.add(id)) {
|
boolean visible = allowedMenuIds.contains(id);
|
node.setChildren(Collections.emptyList());
|
node.setVisible(visible ? "0" : "1");
|
return visible;
|
}
|
List<SysMenu> children = childrenMap.getOrDefault(id == null ? 0L : id, Collections.emptyList()).stream()
|
.filter(Objects::nonNull)
|
.sorted(Comparator.comparing(SysMenu::getOrderNum, Comparator.nullsLast(Integer::compareTo)))
|
.collect(Collectors.toList());
|
|
boolean anyChildVisible = false;
|
for (SysMenu child : children) {
|
anyChildVisible |= fillChildrenAndVisible(child, childrenMap, allowedMenuIds, path);
|
}
|
node.setChildren(children);
|
|
boolean selfVisible = id != null && allowedMenuIds.contains(id);
|
boolean visible = selfVisible || anyChildVisible;
|
node.setVisible(visible ? "0" : "1");
|
if (id != null) {
|
path.remove(id);
|
}
|
return visible;
|
}
|
}
|