liujie
2026-03-10 086c8c208e6af4d593a80d8e6ea85013d8dd14cc
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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
package com.xiaopeng.account.service.impl;
 
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xiaopeng.account.constant.I18nKeyConstant;
import com.xiaopeng.account.mapper.SysGroupMapper;
import com.xiaopeng.account.model.dto.SysGroupAddDTO;
import com.xiaopeng.account.model.dto.SysGroupEditDTO;
import com.xiaopeng.account.model.query.GroupUserPageQuery;
import com.xiaopeng.account.model.query.SysGroupPageQuery;
import com.xiaopeng.account.model.vo.GroupUserVO;
import com.xiaopeng.account.model.vo.SysGroupDetailVO;
import com.xiaopeng.account.model.vo.SysGroupPageVO;
import com.xiaopeng.account.model.vo.SysMenuVO;
import com.xiaopeng.account.service.ISysGroupMenuService;
import com.xiaopeng.account.service.ISysGroupService;
import com.xiaopeng.account.service.ISysRoleService;
import com.xiaopeng.api.feignClient.operation.SysMenuClient;
import com.xiaopeng.api.model.account.SysGroup;
import com.xiaopeng.api.model.account.SysRole;
import com.xiaopeng.api.model.operation.SysMenu;
import com.xiaopeng.common.core.domain.R;
import com.xiaopeng.common.core.exception.ServiceException;
import com.xiaopeng.common.core.utils.StringUtils;
import com.xiaopeng.common.core.web.page.PageInfo;
import com.xiaopeng.common.security.utils.SecurityUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
 
import java.util.*;
import java.util.stream.Collectors;
 
/**
 * <p>
 * 权限组设置 服务实现类
 * </p>
 *
 * @author mitao
 * @since 2026-02-03
 */
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor_ = @Lazy)
public class SysGroupServiceImpl extends ServiceImpl<SysGroupMapper, SysGroup> implements ISysGroupService {
 
    private final ISysGroupMenuService groupMenuService;
 
    private final SysMenuClient sysMenuClient;
    private final ISysRoleService sysRoleService;
 
    /**
     * 新增权限组
     *
     * @param dto 新增权限组请求
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addGroup(SysGroupAddDTO dto) {
        // 校验组名唯一性
        if (!checkGroupNameUnique(dto.getGroupName(), null)) {
            throw new ServiceException("权限组名称已存在", I18nKeyConstant.GROUP_NAME_EXISTS);
        }
 
        // 创建权限组实体
        SysGroup group = BeanUtil.copyProperties(dto, SysGroup.class);
        // 保存权限组
        this.save(group);
 
        // 保存菜单关联
        groupMenuService.saveGroupMenus(group.getId(), dto.getMenuIds());
    }
 
    /**
     * 编辑权限组
     *
     * @param dto 编辑权限组请求
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void editGroup(SysGroupEditDTO dto) {
        // 校验权限组是否存在
        SysGroup existGroup = this.getById(dto.getId());
        if (existGroup == null) {
            throw new ServiceException("权限组不存在", I18nKeyConstant.GROUP_NOT_EXISTS);
        }
 
        // 校验组名唯一性(排除自身)
        if (!checkGroupNameUnique(dto.getGroupName(), dto.getId())) {
            throw new ServiceException("权限组名称已存在", I18nKeyConstant.GROUP_NAME_EXISTS);
        }
 
        // 更新权限组信息
        existGroup.setGroupName(dto.getGroupName());
        existGroup.setRemarks(dto.getRemarks());
        existGroup.setGroupType(dto.getGroupType());
        this.updateById(existGroup);
 
        // 删除旧的菜单关联
        groupMenuService.deleteByGroupId(dto.getId());
 
        // 保存新的菜单关联
        groupMenuService.saveGroupMenus(dto.getId(), dto.getMenuIds());
    }
 
    /**
     * 获取权限组详情(含菜单树)
     *
     * @param id 权限组ID
     * @return 权限组详情
     */
    @Override
    public SysGroupDetailVO getGroupDetail(Long id) {
        // 查询权限组基础信息
        SysGroup group = this.getById(id);
        if (group == null) {
            throw new ServiceException("权限组不存在", I18nKeyConstant.GROUP_NOT_EXISTS);
        }
 
        SysGroupDetailVO vo = BeanUtil.toBean(group, SysGroupDetailVO.class);
 
        // 根据权限组ID获取菜单ID列表
        List<Long> menuIds = groupMenuService.selectMenuIdsByGroupId(id);
        if (CollectionUtils.isEmpty(menuIds)) {
            vo.setMenus(new ArrayList<>());
            return vo;
        }
 
        // 通过Feign调用获取菜单详情
        try {
            R<List<SysMenu>> result = sysMenuClient.getMenusByMenuIds(menuIds);
            if (result != null && result.getData() != null) {
                List<SysMenu> menus = result.getData();
                // 构建菜单树
                vo.setMenus(buildMenuTree(menus));
                vo.setMenuIds(menus.stream().map(SysMenu::getId).collect(Collectors.toList()));
            } else {
                vo.setMenus(new ArrayList<>());
                vo.setMenuIds(new ArrayList<>());
            }
        } catch (Exception e) {
            log.error("获取菜单列表失败: {}", e.getMessage());
            vo.setMenus(new ArrayList<>());
        }
 
        return vo;
    }
 
    /**
     * 权限组分页列表
     *
     * @param query 分页查询参数
     * @return 分页结果
     */
    @Override
    public PageInfo<SysGroupPageVO> pageList(SysGroupPageQuery query) {
        // 构建查询条件
        LambdaQueryWrapper<SysGroup> wrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isNotBlank(query.getGroupName())) {
            wrapper.like(SysGroup::getGroupName, query.getGroupName());
        }
        wrapper.orderByDesc(SysGroup::getCreateTime);
 
        // 分页查询
        PageInfo<SysGroup> pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize());
        PageInfo<SysGroup> groupPage = this.page(pageInfo, wrapper);
 
        // 转换为VO
        PageInfo<SysGroupPageVO> resultPage = new PageInfo<>(query.getPageNum(), query.getPageSize());
        resultPage.setTotal(groupPage.getTotal());
 
        List<SysGroupPageVO> voList = groupPage.getRecords().stream().map(group -> {
            SysGroupPageVO vo = BeanUtil.copyProperties(group, SysGroupPageVO.class);
            // 统计绑定用户数
            Long bindCount = baseMapper.countBindUsers(group.getId());
            vo.setBindCount(bindCount != null ? bindCount : 0L);
            return vo;
        }).collect(Collectors.toList());
 
        resultPage.setRecords(voList);
        return resultPage;
    }
 
    /**
     * 查询权限组绑定用户分页列表
     *
     * @param query 分页查询参数
     * @return 分页结果
     */
    @Override
    public PageInfo<GroupUserVO> queryUserPageList(GroupUserPageQuery query) {
        // 校验权限组是否存在
        SysGroup group = this.getById(query.getGroupId());
        if (group == null) {
            throw new ServiceException("权限组不存在");
        }
 
        // 分页查询
        PageInfo<GroupUserVO> pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize());
        query.setGroupType(group.getGroupType());
        PageInfo<GroupUserVO> records = baseMapper.queryUserPageList(pageInfo, query);
 
        // 手动设置分页信息(因为使用了自定义SQL)
        return pageInfo;
    }
 
    /**
     * 校验权限组名称唯一性
     *
     * @param groupName 权限组名称
     * @param excludeId 排除的权限组ID(编辑时使用)
     * @return true=唯一,false=不唯一
     */
    @Override
    public boolean checkGroupNameUnique(String groupName, Long excludeId) {
        LambdaQueryWrapper<SysGroup> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysGroup::getGroupName, groupName);
        if (excludeId != null) {
            wrapper.ne(SysGroup::getId, excludeId);
        }
        return this.count(wrapper) == 0;
    }
 
    /**
     * 构建菜单树
     *
     * @param menus 菜单列表
     * @return 菜单树
     */
    private List<SysMenuVO> buildMenuTree(List<SysMenu> menus) {
        if (CollectionUtils.isEmpty(menus)) {
            return new ArrayList<>();
        }
 
        Map<Long, SysMenuVO> menuMap = new HashMap<>();
        List<SysMenuVO> rootMenus = new ArrayList<>();
 
        // 转换为VO并建立映射
        for (SysMenu menu : menus) {
            SysMenuVO vo = convertToMenuVO(menu);
            vo.setChildren(new ArrayList<>());
            menuMap.put(vo.getId(), vo);
        }
 
        // 构建树结构
        for (SysMenuVO vo : menuMap.values()) {
            if (vo.getParentId() == null || vo.getParentId() == 0) {
                rootMenus.add(vo);
            } else {
                SysMenuVO parent = menuMap.get(vo.getParentId());
                if (parent != null) {
                    parent.getChildren().add(vo);
                } else {
                    // 父节点不在列表中,作为根节点处理
                    rootMenus.add(vo);
                }
            }
        }
 
        // 按orderNum排序
        sortMenuTree(rootMenus);
 
        return rootMenus;
    }
 
    /**
     * 转换为菜单VO
     *
     * @param menu 菜单实体
     * @return 菜单VO
     */
    private SysMenuVO convertToMenuVO(SysMenu menu) {
        SysMenuVO vo = new SysMenuVO();
        BeanUtils.copyProperties(menu, vo);
        return vo;
    }
 
    /**
     * 递归排序菜单树
     *
     * @param menus 菜单列表
     */
    private void sortMenuTree(List<SysMenuVO> menus) {
        if (CollectionUtils.isEmpty(menus)) {
            return;
        }
        menus.sort(Comparator.comparing(SysMenuVO::getOrderNum, Comparator.nullsLast(Comparator.naturalOrder())));
        for (SysMenuVO menu : menus) {
            if (!CollectionUtils.isEmpty(menu.getChildren())) {
                sortMenuTree(menu.getChildren());
            }
        }
    }
 
    /**
     * 删除权限组
     * @param id
     */
    @Override
    public void deleteById(Long id) {
        Long count = sysRoleService.lambdaQuery().eq(SysRole::getGroupId, id).count();
        if (count > 0) {
            throw new ServiceException("删除失败,该权限组已关联角色", I18nKeyConstant.SYS_GROUP_DELETE_FAIL);
        }
        removeById(id);
    }
}