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.SysRoleMapper; import com.xiaopeng.account.mapper.SysRoleMenuMapper; import com.xiaopeng.account.model.dto.SysRoleAddDTO; import com.xiaopeng.account.model.dto.SysRoleEditDTO; import com.xiaopeng.account.model.query.SysRolePageQuery; import com.xiaopeng.account.model.vo.SysMenuVO; import com.xiaopeng.account.model.vo.SysRoleDetailVO; import com.xiaopeng.account.model.vo.SysRolePageVO; import com.xiaopeng.account.service.ISysGroupMenuService; import com.xiaopeng.account.service.ISysRoleService; import com.xiaopeng.account.service.ISysUserRoleService; import com.xiaopeng.api.feignClient.operation.SysMenuClient; 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.core.exception.ServiceException; import com.xiaopeng.common.core.utils.StringUtils; import com.xiaopeng.common.core.web.page.PageInfo; 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.util.CollectionUtils; import java.util.*; import java.util.stream.Collectors; /** *

* 角色信息表 服务实现类 *

* * @author mitao * @since 2026-02-03 */ @Slf4j @Service @RequiredArgsConstructor(onConstructor_ = @Lazy) public class SysRoleServiceImpl extends ServiceImpl implements ISysRoleService { private final ISysUserRoleService userRoleService; private final ISysGroupMenuService groupMenuService; private final SysMenuClient sysMenuClient; private final SysRoleMenuMapper sysRoleMenuMapper; /** * 根据角色ID查询权限组ID * * @param roleId 角色ID * @return 权限组ID */ @Override public Long selectGroupIdByRoleId(Long roleId) { if (roleId == null) { return null; } SysRole role = this.getById(roleId); return role != null ? role.getGroupId() : null; } /** * 根据用户ID查询角色权限 * * @param userId 用户ID * @return 角色权限集合 */ @Override public Set selectRolePermissionByUserId(Long userId) { Set roles = new HashSet<>(); if (userId == null) { return roles; } // 查询用户关联的角色 SysUserRole userRole = userRoleService.selectSysUserRoleByUserId(userId); if (userRole == null || userRole.getRoleId() == null) { return roles; } // 查询角色信息 SysRole role = this.getById(userRole.getRoleId()); if (role != null && StringUtils.isNotBlank(role.getRoleName())) { roles.add(role.getRoleName()); } return roles; } /** * 新增角色 * * @param dto 新增角色请求 */ @Override public void addRole(SysRoleAddDTO dto) { // 校验角色名称唯一性 if (!checkRoleNameUnique(dto.getRoleName(), null)) { throw new ServiceException("角色名称已存在", I18nKeyConstant.ROLE_NAME_EXISTS); } // 创建角色实体 SysRole role = new SysRole(); role.setGroupId(dto.getGroupId()); role.setRoleName(dto.getRoleName()); role.setRemarks(dto.getRemarks()); // 保存角色 this.save(role); } /** * 编辑角色 * * @param dto 编辑角色请求 */ @Override public void editRole(SysRoleEditDTO dto) { // 校验角色是否存在 SysRole existRole = this.getById(dto.getId()); if (existRole == null) { throw new ServiceException("角色不存在", I18nKeyConstant.ROlE_NOT_EXISTS); } // 校验角色名称唯一性(排除自身) if (!checkRoleNameUnique(dto.getRoleName(), dto.getId())) { throw new ServiceException("角色名称已存在", I18nKeyConstant.ROLE_NAME_EXISTS); } // 更新角色信息 existRole.setGroupId(dto.getGroupId()); existRole.setRoleName(dto.getRoleName()); existRole.setRemarks(dto.getRemarks()); this.updateById(existRole); } /** * 获取角色详情(含菜单树) * * @param id 角色ID * @return 角色详情 */ @Override public SysRoleDetailVO getRoleDetail(Long id) { // 查询角色基础信息 SysRole role = this.getById(id); if (role == null) { throw new ServiceException("角色不存在", I18nKeyConstant.ROlE_NOT_EXISTS); } SysRoleDetailVO vo = BeanUtil.toBean(role, SysRoleDetailVO.class); // 根据权限组ID获取菜单ID列表 List menuIds = groupMenuService.selectMenuIdsByGroupId(role.getGroupId()); if (CollectionUtils.isEmpty(menuIds)) { vo.setMenus(new ArrayList<>()); return vo; } // 通过Feign调用获取菜单详情 try { R> result = sysMenuClient.getMenusByMenuIds(menuIds); if (result != null && result.getData() != null) { List menus = result.getData(); // 构建菜单树 vo.setMenus(buildMenuTree(menus)); } else { vo.setMenus(new ArrayList<>()); } } catch (Exception e) { log.error("获取菜单列表失败: {}", e.getMessage()); vo.setMenus(new ArrayList<>()); } return vo; } /** * 角色分页列表 * * @param query 分页查询参数 * @return 分页结果 */ @Override public PageInfo pageList(SysRolePageQuery query) { // 构建查询条件 LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); if (StringUtils.isNotBlank(query.getRoleName())) { wrapper.like(SysRole::getRoleName, query.getRoleName()); } wrapper.orderByDesc(SysRole::getCreateTime); // 分页查询 PageInfo pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize()); PageInfo rolePage = this.page(pageInfo, wrapper); // 转换为VO PageInfo resultPage = new PageInfo<>(query.getPageNum(), query.getPageSize()); resultPage.setTotal(rolePage.getTotal()); List voList = rolePage.getRecords().stream().map(role -> { SysRolePageVO vo = new SysRolePageVO(); vo.setId(role.getId()); vo.setGroupId(role.getGroupId()); vo.setRoleName(role.getRoleName()); vo.setRemarks(role.getRemarks()); vo.setCreateTime(role.getCreateTime()); // 统计绑定用户数 Long bindCount = baseMapper.countBindUsers(role.getId()); vo.setBindCount(bindCount); return vo; }).collect(Collectors.toList()); resultPage.setRecords(voList); return resultPage; } /** * 删除角色(逻辑删除) * * @param id 角色ID */ @Override public void deleteRole(Long id) { // 校验角色是否存在 SysRole role = this.getById(id); if (role == null) { throw new ServiceException("角色不存在"); } // 检查是否有用户绑定该角色 Long bindCount = baseMapper.countBindUsers(id); if (bindCount != null && bindCount > 0) { throw new ServiceException("该角色已绑定用户,无法删除", I18nKeyConstant.ROLE_USER_BOUND); } // 逻辑删除 this.removeById(id); } /** * 校验角色名称唯一性 * * @param roleName 角色名称 * @param excludeId 排除的角色ID(编辑时使用) * @return true=唯一,false=不唯一 */ @Override public boolean checkRoleNameUnique(String roleName, Long excludeId) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(SysRole::getRoleName, roleName); if (excludeId != null) { wrapper.ne(SysRole::getId, excludeId); } return this.count(wrapper) == 0; } /** * 构建菜单树 * * @param menus 菜单列表 * @return 菜单树 */ private List buildMenuTree(List menus) { if (CollectionUtils.isEmpty(menus)) { return new ArrayList<>(); } Map menuMap = new HashMap<>(); List 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 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()); } } } @Override public Boolean checkMenuExistRole(Long menuId) { return sysRoleMenuMapper.checkMenuExistRole(menuId) > 0; } }