package com.xiaopeng.account.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
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.mapper.XpOperationsRoleMapper;
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.ISysGroupService;
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.SysGroup;
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.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.beans.factory.annotation.Autowired;
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;
private final XpOperationsRoleMapper xpOperationsRoleMapper;
@Lazy
@Autowired
private ISysGroupService sysGroupService;
/**
* 根据角色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);
//查询关联权限组
if (Objects.nonNull(vo.getGroupId())) {
SysGroup sysGroup = sysGroupService.getById(vo.getGroupId());
vo.setGroupName(sysGroup != null ? sysGroup.getGroupName() : null);
}
// 根据权限组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())) {
// 转义 LIKE 特殊字符:% _ \
String roleName = StringUtils.escapeLike(query.getRoleName());
wrapper.like(SysRole::getRoleName, roleName);
}
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;
}
@Override
public Set selectRolePermissionByOperationUserId(Long userId) {
Set roles = new HashSet<>();
if (userId == null) {
return roles;
}
// 查询用户关联的角色
List xpOperationsRoles = xpOperationsRoleMapper.selectSysUserRoleByOperationUserId(userId);
if (CollectionUtils.isEmpty(xpOperationsRoles)) {
return roles;
}
// 查询角色信息
List roleIds = xpOperationsRoles.stream().map(XpOperationsRole::getRoleId).collect(Collectors.toList());
List roleList= this.list(Wrappers.lambdaQuery(SysRole.class)
.in(SysRole::getId, roleIds));
if (!CollectionUtils.isEmpty(roleList)) {
roleList.forEach(role -> {
if (role != null) {
roles.add(role.getRoleName());
}
});
}
return roles;
}
}