package com.xiaopeng.account.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.DesensitizedUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
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.account.SysUser;
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.service.TokenService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.transaction.annotation.ShardingSphereTransactionType;
import org.apache.shardingsphere.transaction.core.TransactionType;
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 javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
/**
*
* 权限组设置 服务实现类
*
*
* @author mitao
* @since 2026-02-03
*/
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor_ = @Lazy)
public class SysGroupServiceImpl extends ServiceImpl implements ISysGroupService {
private final ISysGroupMenuService groupMenuService;
@Resource
private final SysMenuClient sysMenuClient;
private final ISysRoleService sysRoleService;
@Resource
private TokenService tokenService;
/**
* 新增权限组
*
* @param dto 新增权限组请求
*/
@Override
@Transactional
@ShardingSphereTransactionType(TransactionType.BASE)
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
@ShardingSphereTransactionType(TransactionType.BASE)
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 menuIds = groupMenuService.selectMenuIdsByGroupId(id);
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));
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 pageList(SysGroupPageQuery query) {
// 构建查询条件
LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
if (StringUtils.isNotBlank(query.getGroupName())) {
wrapper.like(SysGroup::getGroupName, query.getGroupName());
}
wrapper.orderByDesc(SysGroup::getCreateTime);
// 分页查询
PageInfo pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize());
PageInfo groupPage = this.page(pageInfo, wrapper);
// 转换为VO
PageInfo resultPage = new PageInfo<>(query.getPageNum(), query.getPageSize());
resultPage.setTotal(groupPage.getTotal());
List 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 queryUserPageList(GroupUserPageQuery query) {
// 校验权限组是否存在
SysGroup group = this.getById(query.getGroupId());
if (group == null) {
throw new ServiceException("权限组不存在");
}
// 分页查询
PageInfo pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize());
query.setGroupType(group.getGroupType());
Page records = baseMapper.queryUserPageList(pageInfo, query);
pageInfo.setRecords(records.getRecords());
// 手动设置分页信息(因为使用了自定义SQL)
return pageInfo;
}
/**
* 校验权限组名称唯一性
*
* @param groupName 权限组名称
* @param excludeId 排除的权限组ID(编辑时使用)
* @return true=唯一,false=不唯一
*/
@Override
public boolean checkGroupNameUnique(String groupName, Long excludeId) {
LambdaQueryWrapper 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 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());
}
}
}
/**
* 删除权限组
* @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);
}
@Override
public String getPhoneDesensitization(String phoneNumber){
boolean b = getPhoneDesensitization();
if(b){
return DesensitizedUtil.mobilePhone(phoneNumber);
}
return phoneNumber;
}
/**
* 获取登录用户的权限组,获取权限组的手机号是否脱敏的字段
* true 需要脱敏,false 否
* @return
*/
@Override
public boolean getPhoneDesensitization(){
try {
SysUser sysUser = tokenService.getLoginUser().getSysUser();
//用户查询角色 角色查询 权限组
int count = baseMapper.getPhoneDesensitization(sysUser.getId());
return count > 0;
} catch (Exception e) {
return false;
}
}
}