| | |
| | | |
| | | import cn.hutool.core.util.ObjectUtil; |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.github.pagehelper.PageInfo; |
| | | import com.ruoyi.common.constant.HttpStatus; |
| | | import com.ruoyi.common.core.controller.BaseController; |
| | | import com.ruoyi.common.core.domain.AjaxResult; |
| | | import com.ruoyi.common.core.domain.entity.SysUser; |
| | | import com.ruoyi.common.core.page.TableDataInfo; |
| | | import com.ruoyi.common.utils.StringUtils; |
| | | import com.ruoyi.im.comm.Result; |
| | | import com.ruoyi.im.dto.RegisterDto; |
| | | import com.ruoyi.im.out.UserAccountOut; |
| | | import com.ruoyi.im.service.ImApiServcie; |
| | | import com.ruoyi.im.util.ConverterUtil; |
| | | import com.ruoyi.im.util.PhoneNumberValidatorUtil; |
| | | import com.ruoyi.im.util.SymmetricCryptoUtil; |
| | | import com.ruoyi.system.domain.UserAccount; |
| | | import com.ruoyi.system.domain.vo.UserAccountUpdateVo; |
| | | import com.ruoyi.system.domain.vo.UserAccountVo; |
| | | import com.ruoyi.system.service.UserAccountService; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.security.access.prepost.PreAuthorize; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import java.util.List; |
| | | import java.util.Objects; |
| | | import java.util.*; |
| | | import java.util.stream.Collectors; |
| | | |
| | | @RestController |
| | | @RequestMapping("/im/user") |
| | | @Slf4j |
| | | public class UserController extends BaseController { |
| | | |
| | | @Autowired |
| | | UserAccountService userAccountService; |
| | | |
| | | @Autowired |
| | | private ImApiServcie imApiServcie; |
| | | |
| | | /** |
| | | * 获取会员列表 |
| | | */ |
| | | @PreAuthorize("@ss.hasPermi('im:user:list')") |
| | | @GetMapping("/list") |
| | | public TableDataInfo list(UserAccountVo vo) |
| | | { |
| | | // 创建查询条件包装器 |
| | | LambdaQueryWrapper<UserAccount> queryWrapper = new LambdaQueryWrapper<>(); |
| | | |
| | | // 只有当 keyword 不为空时才添加 OR 条件 |
| | | if (ObjectUtil.isNotEmpty(vo.getKeywords())) { |
| | | queryWrapper.and(wrapper -> wrapper |
| | | .eq(UserAccount::getId, vo.getKeywords()) |
| | | .or() |
| | | .like(UserAccount::getPhoneNumber, vo.getKeywords()) |
| | | .or() |
| | | .like(UserAccount::getAccount, vo.getKeywords()) |
| | | .or() |
| | | .like(UserAccount::getNickname, vo.getKeywords()) |
| | | ); |
| | | } |
| | | |
| | | // 添加其他条件 |
| | | queryWrapper |
| | | .eq(ObjectUtil.isNotEmpty(vo.getAccountType()), UserAccount::getAccountType, vo.getAccountType()) |
| | | .eq(ObjectUtil.isNotEmpty(vo.getStatus()), UserAccount::getStatus, vo.getStatus()) |
| | | .eq(ObjectUtil.isNotEmpty(vo.getPosition()), UserAccount::getPosition, vo.getPosition()) |
| | | .between(ObjectUtil.isAllNotEmpty(vo.getStartTime(), vo.getEndTime()), |
| | | UserAccount::getCreateTime, vo.getStartTime(), vo.getEndTime()); |
| | | |
| | | // 默认按创建时间倒序 |
| | | queryWrapper.orderByDesc(UserAccount::getCreateTime); |
| | | startPage(); |
| | | List<UserAccount> list = userAccountService.list(new LambdaQueryWrapper<UserAccount>() |
| | | .eq(UserAccount::getId, vo.getKeyword()) |
| | | .or() |
| | | .eq(UserAccount::getPhoneNumber, vo.getKeyword()) |
| | | .or() |
| | | .eq(UserAccount::getAccount, vo.getKeyword()) |
| | | .or() |
| | | .eq(UserAccount::getNickname, vo.getKeyword()) |
| | | .eq(ObjectUtil.isNotEmpty(vo.getAccountType()),UserAccount::getAccountType,vo.getAccountType()) |
| | | .eq(ObjectUtil.isNotEmpty(vo.getStatus()),UserAccount::getStatus,vo.getStatus()) |
| | | .between(UserAccount::getCreateTime,vo.getStartTime(),vo.getEndTime()) |
| | | ); |
| | | return getDataTable(list); |
| | | List<UserAccount> list = userAccountService.list(queryWrapper); |
| | | |
| | | PageInfo<UserAccount> pageInfo = new PageInfo<>(list); |
| | | |
| | | // 转换为输出对象并递归加载下级列表(最多3级) |
| | | List<UserAccountOut> toList = convertToUserAccountOutWithSubordinates(list, 3); |
| | | |
| | | TableDataInfo rspData = new TableDataInfo(); |
| | | rspData.setCode(HttpStatus.SUCCESS); |
| | | rspData.setMsg("查询成功"); |
| | | rspData.setRows(toList); |
| | | rspData.setTotal(pageInfo.getTotal()); |
| | | return rspData; |
| | | } |
| | | |
| | | /** |
| | | * 转换用户账户列表并递归加载下级用户 |
| | | * @param userAccounts 用户账户列表 |
| | | * @param maxLevel 最大递归层级 |
| | | * @return 包含下级列表的用户输出对象列表 |
| | | */ |
| | | private List<UserAccountOut> convertToUserAccountOutWithSubordinates(List<UserAccount> userAccounts, int maxLevel) { |
| | | if (ObjectUtil.isEmpty(userAccounts) || maxLevel <= 0) { |
| | | return new ArrayList<>(); |
| | | } |
| | | |
| | | // 先转换基础信息 |
| | | List<UserAccountOut> result = ConverterUtil.convertToList(userAccounts, UserAccountOut.class); |
| | | |
| | | // 递归加载下级用户 |
| | | loadSubordinateUsersRecursive(result, maxLevel); |
| | | |
| | | return result; |
| | | } |
| | | |
| | | /** |
| | | * 递归加载多级下级用户 |
| | | * @param userAccountOuts 当前层级的用户列表 |
| | | * @param remainingLevels 剩余递归层级 |
| | | */ |
| | | private void loadSubordinateUsersRecursive(List<UserAccountOut> userAccountOuts, int remainingLevels) { |
| | | if (ObjectUtil.isEmpty(userAccountOuts) || remainingLevels <= 0) { |
| | | return; |
| | | } |
| | | |
| | | // 加载当前级别的下级用户 |
| | | loadCurrentLevelSubordinates(userAccountOuts); |
| | | |
| | | // 递归加载下级的下级 |
| | | for (UserAccountOut user : userAccountOuts) { |
| | | if (ObjectUtil.isNotEmpty(user.getSubordinateList())) { |
| | | loadSubordinateUsersRecursive(user.getSubordinateList(), remainingLevels - 1); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 加载当前层级的直接下级用户 |
| | | * @param userAccountOuts 当前层级的用户列表 |
| | | */ |
| | | private void loadCurrentLevelSubordinates(List<UserAccountOut> userAccountOuts) { |
| | | if (ObjectUtil.isEmpty(userAccountOuts)) { |
| | | return; |
| | | } |
| | | |
| | | // 收集所有用户的账号(用于查询下级) |
| | | List<String> accounts = userAccountOuts.stream() |
| | | .map(UserAccountOut::getAccount) |
| | | .filter(ObjectUtil::isNotEmpty) |
| | | .distinct() |
| | | .collect(Collectors.toList()); |
| | | |
| | | if (accounts.isEmpty()) { |
| | | // 如果没有账号,为所有用户设置空列表 |
| | | userAccountOuts.forEach(user -> user.setSubordinateList(new ArrayList<>())); |
| | | return; |
| | | } |
| | | |
| | | // 批量查询所有直接下级用户 |
| | | LambdaQueryWrapper<UserAccount> queryWrapper = new LambdaQueryWrapper<>(); |
| | | queryWrapper.in(UserAccount::getInvitationAccount, accounts); |
| | | List<UserAccount> allSubordinates = userAccountService.list(queryWrapper); |
| | | |
| | | // 转换为输出对象 |
| | | List<UserAccountOut> allSubordinateOuts = ConverterUtil.convertToList(allSubordinates, UserAccountOut.class); |
| | | |
| | | // 按邀请人账号分组 |
| | | Map<String, List<UserAccountOut>> subordinateMap = allSubordinateOuts.stream() |
| | | .filter(sub -> ObjectUtil.isNotEmpty(sub.getInvitationAccount())) |
| | | .collect(Collectors.groupingBy(UserAccountOut::getInvitationAccount)); |
| | | |
| | | // 为每个用户设置下级列表 |
| | | for (UserAccountOut user : userAccountOuts) { |
| | | if (ObjectUtil.isNotEmpty(user.getAccount())) { |
| | | List<UserAccountOut> subordinates = subordinateMap.get(user.getAccount()); |
| | | user.setSubordinateList(ObjectUtil.isNotEmpty(subordinates) ? subordinates : new ArrayList<>()); |
| | | } else { |
| | | user.setSubordinateList(new ArrayList<>()); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 获取用户的下级树形结构 |
| | | * @param userId 用户ID |
| | | * @param maxLevel 最大层级深度 |
| | | * @return 用户下级树形结构 |
| | | */ |
| | | @GetMapping("/subordinateTree/{userId}") |
| | | public AjaxResult getSubordinateTree(@PathVariable Integer userId, |
| | | @RequestParam(defaultValue = "3") int maxLevel) { |
| | | try { |
| | | UserAccount userAccount = userAccountService.getById(userId); |
| | | if (ObjectUtil.isEmpty(userAccount)) { |
| | | return AjaxResult.error("用户不存在"); |
| | | } |
| | | |
| | | // 转换当前用户 |
| | | UserAccountOut userOut = ConverterUtil.convert(userAccount, UserAccountOut.class); |
| | | |
| | | // 递归加载下级树 |
| | | List<UserAccountOut> userList = new ArrayList<>(); |
| | | userList.add(userOut); |
| | | loadSubordinateUsersRecursive(userList, maxLevel); |
| | | |
| | | return AjaxResult.success(userOut); |
| | | } catch (Exception e) { |
| | | log.error("获取用户下级树失败", e); |
| | | return AjaxResult.error("获取下级树失败"); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 获取用户的直接下级列表(不分页) |
| | | */ |
| | | @GetMapping("/directSubordinates/{userId}") |
| | | public AjaxResult getDirectSubordinates(@PathVariable Integer userId) { |
| | | try { |
| | | UserAccount userAccount = userAccountService.getById(userId); |
| | | if (ObjectUtil.isEmpty(userAccount)) { |
| | | return AjaxResult.error("用户不存在"); |
| | | } |
| | | |
| | | // 查询直接下级 |
| | | LambdaQueryWrapper<UserAccount> queryWrapper = new LambdaQueryWrapper<>(); |
| | | queryWrapper.eq(UserAccount::getInvitationAccount, userAccount.getAccount()); |
| | | List<UserAccount> subordinates = userAccountService.list(queryWrapper); |
| | | |
| | | List<UserAccountOut> result = ConverterUtil.convertToList(subordinates, UserAccountOut.class); |
| | | |
| | | return AjaxResult.success(result); |
| | | } catch (Exception e) { |
| | | log.error("获取直接下级列表失败", e); |
| | | return AjaxResult.error("获取下级列表失败"); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | /** |
| | | * 修改会员 |
| | | */ |
| | | @PreAuthorize("@ss.hasPermi('im:user:updateUserAccount')") |
| | | @GetMapping("/updateUserAccount") |
| | | // @PreAuthorize("@ss.hasPermi('im:user:updateUserAccount')") |
| | | @PostMapping("/updateUserAccount") |
| | | public AjaxResult updateUserAccount(UserAccountUpdateVo vo) { |
| | | |
| | | try { |
| | | UserAccount userAccount = userAccountService.getById(vo.getId()); |
| | | UserAccount userAccount = userAccountService.getOne(new LambdaQueryWrapper<UserAccount>() |
| | | .eq(UserAccount::getAccount,vo.getAccount()) |
| | | ); |
| | | if(ObjectUtil.isEmpty(userAccount)){ |
| | | return AjaxResult.error("会员不存在!"); |
| | | } |
| | | if(StringUtils.isNotEmpty(vo.getPhoneNumber())){ |
| | | PhoneNumberValidatorUtil.ValidationResult result = PhoneNumberValidatorUtil.validatePhoneNumber(vo.getPhoneNumber()); |
| | | if(!result.isValid()){ |
| | | return AjaxResult.error("手机号格式不正确!"); |
| | | } |
| | | } |
| | | if(StringUtils.isNotEmpty(vo.getPassword()) && StringUtils.isEmpty(vo.getOldPassword())){ |
| | | return AjaxResult.error("旧密码不能为空!"); |
| | | } |
| | | if(StringUtils.isNotEmpty(vo.getPassword())){ |
| | | String s = SymmetricCryptoUtil.decryptPassword(userAccount.getPassword()); |
| | | if(!vo.getOldPassword().equals(s)){ |
| | | return AjaxResult.error("旧密码不正确!"); |
| | | } |
| | | } |
| | | vo.setAccount(userAccount.getCloudMessageAccount()); |
| | | return imApiServcie.updateUserAccount(vo); |
| | | }catch (Exception e){ |
| | | e.printStackTrace(); |
| | | logger.error("修改会员失败!"); |
| | |
| | | return AjaxResult.success(); |
| | | } |
| | | |
| | | /** |
| | | * 创建会员 |
| | | */ |
| | | @PostMapping("/batchRegister") |
| | | public Result batchRegister(@Validated RegisterDto dto){ |
| | | try { |
| | | if(null == dto.getType()){ |
| | | return Result.error("类型不能为空"); |
| | | }else if(dto.getType() == 2){ |
| | | if(StringUtils.isEmpty(dto.getAccount())){ |
| | | return Result.error("账号不能为空"); |
| | | } |
| | | if(StringUtils.isEmpty(dto.getPassword())){ |
| | | return Result.error("密码不能为空"); |
| | | } |
| | | if(StringUtils.isEmpty(dto.getNikeName())){ |
| | | return Result.error("昵称不能为空"); |
| | | } |
| | | }else if (dto.getType() == 1){ |
| | | if(dto.getNumber() <= 0){ |
| | | return Result.error("数量不能为空"); |
| | | }else if(dto.getNumber() > 100){ |
| | | return Result.error("批量注册最多一次100"); |
| | | } |
| | | } |
| | | return imApiServcie.batchRegister(dto); |
| | | }catch (Exception e){ |
| | | e.printStackTrace(); |
| | | log.error("-----------批量注册报错------------"); |
| | | return Result.error("注册失败,请稍后再试!"); |
| | | } |
| | | } |
| | | |
| | | } |