liujie
2026-02-25 a9b378f9e7b1a72f9e50227ca445d5135c71020a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
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.model.account.SysRole;
import com.xiaopeng.api.model.account.SysUserRole;
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;
 
    /**
     * 根据菜单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() {
        List<SysMenu> all = 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();
        }
    }
}