| | |
| | | import com.ruoyi.im.dto.RegisterDto; |
| | | import com.ruoyi.im.out.UserAccountOut; |
| | | import com.ruoyi.im.service.ImApiServcie; |
| | | import com.ruoyi.im.service.UserKycService; |
| | | 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.UserKyc; |
| | | 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.util.CollectionUtils; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.PostMapping; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | 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") |
| | |
| | | @Autowired |
| | | private ImApiServcie imApiServcie; |
| | | |
| | | @Autowired |
| | | private UserKycService userKycService; |
| | | |
| | | /** |
| | | * 获取会员列表 |
| | | */ |
| | | // @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()) |
| | | ); |
| | | String keywords = vo.getKeywords().trim(); |
| | | if (StringUtils.isNotEmpty(keywords)) { |
| | | queryWrapper.and(wrapper -> wrapper |
| | | .eq(UserAccount::getInvitationCode, keywords) |
| | | .or() |
| | | // 使用右模糊匹配,可以利用索引 |
| | | .likeRight(UserAccount::getPhoneNumber, keywords) |
| | | .or() |
| | | .likeRight(UserAccount::getAccount, keywords) |
| | | .or() |
| | | .likeRight(UserAccount::getNickname, keywords) |
| | | ); |
| | | } |
| | | } |
| | | |
| | | // 添加其他条件 |
| | | 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()); |
| | | |
| | |
| | | startPage(); |
| | | List<UserAccount> list = userAccountService.list(queryWrapper); |
| | | |
| | | List<Integer> idList = list.stream() |
| | | .map(UserAccount::getId) |
| | | .collect(Collectors.toList()); |
| | | if(!CollectionUtils.isEmpty(idList)){ |
| | | List<UserKyc> kycList = userKycService.list(new LambdaQueryWrapper<UserKyc>() |
| | | .in(UserKyc::getUserId, idList) |
| | | ); |
| | | |
| | | Map<Integer, UserKyc> kycMap = kycList.stream() |
| | | .collect(Collectors.toMap(UserKyc::getUserId, kyc -> kyc)); |
| | | |
| | | list.forEach(f->{ |
| | | if(ObjectUtil.isNotEmpty(kycMap.get(f.getId()))){ |
| | | f.setName(kycMap.get(f.getId()).getName()); |
| | | f.setIdCard(kycMap.get(f.getId()).getIdCard()); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | PageInfo<UserAccount> pageInfo = new PageInfo<>(list); |
| | | |
| | | List<UserAccountOut> toList = ConverterUtil.convertToList(list, UserAccountOut.class); |
| | | // 转换为输出对象并递归加载下级列表(最多3级) |
| | | List<UserAccountOut> toList = convertToUserAccountOutWithSubordinates(list, 3); |
| | | |
| | | TableDataInfo rspData = new TableDataInfo(); |
| | | rspData.setCode(HttpStatus.SUCCESS); |
| | |
| | | } |
| | | |
| | | /** |
| | | * 转换用户账户列表并递归加载下级用户 |
| | | * @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); |
| | | } |
| | | } |
| | | } |
| | | |
| | | 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); |
| | | |
| | | // 收集所有需要设置 KYC 的用户(当前层级 + 下级) |
| | | List<UserAccountOut> allUsers = new ArrayList<>(); |
| | | allUsers.addAll(userAccountOuts); |
| | | allUsers.addAll(allSubordinateOuts); |
| | | |
| | | // 一次性设置所有用户的 KYC 信息 |
| | | setKycInfoForUsers(allUsers); |
| | | |
| | | // 按邀请人账号分组 |
| | | 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<>()); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 为用户列表设置 KYC 信息 |
| | | */ |
| | | private void setKycInfoForUsers(List<UserAccountOut> users) { |
| | | if (ObjectUtil.isEmpty(users)) { |
| | | return; |
| | | } |
| | | |
| | | // 收集用户ID |
| | | List<Integer> idList = users.stream() |
| | | .map(UserAccountOut::getId) |
| | | .filter(ObjectUtil::isNotEmpty) |
| | | .collect(Collectors.toList()); |
| | | |
| | | if (idList.isEmpty()) { |
| | | return; |
| | | } |
| | | |
| | | // 批量查询 KYC 信息 |
| | | List<UserKyc> kycList = userKycService.list(new LambdaQueryWrapper<UserKyc>() |
| | | .in(UserKyc::getUserId, idList) |
| | | ); |
| | | |
| | | // 转换为 Map |
| | | Map<Integer, UserKyc> kycMap = kycList.stream() |
| | | .collect(Collectors.toMap(UserKyc::getUserId, kyc -> kyc, (existing, replacement) -> existing)); |
| | | |
| | | // 设置 KYC 信息 |
| | | users.forEach(user -> { |
| | | if (ObjectUtil.isNotEmpty(user.getId()) && ObjectUtil.isNotEmpty(kycMap.get(user.getId()))) { |
| | | UserKyc kyc = kycMap.get(user.getId()); |
| | | user.setName(kyc.getName()); |
| | | user.setIdCard(kyc.getIdCard()); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | /** |
| | | * 获取用户的下级树形结构 |
| | | * @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')") |
| | |
| | | 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("会员不存在!"); |
| | | } |
| | | PhoneNumberValidatorUtil.ValidationResult result = PhoneNumberValidatorUtil.validatePhoneNumber(vo.getPhoneNumber()); |
| | | if(!result.isValid()){ |
| | | return AjaxResult.error("手机号格式不正确!"); |
| | | if(StringUtils.isNotEmpty(vo.getPhoneNumber())){ |
| | | PhoneNumberValidatorUtil.ValidationResult result = PhoneNumberValidatorUtil.validatePhoneNumber(vo.getPhoneNumber()); |
| | | if(!result.isValid()){ |
| | | return AjaxResult.error("手机号格式不正确!"); |
| | | } |
| | | } |
| | | vo.setAccountId(userAccount.getCloudMessageAccount()); |
| | | 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(); |
| | |
| | | if(StringUtils.isEmpty(dto.getPassword())){ |
| | | return Result.error("密码不能为空"); |
| | | } |
| | | if(StringUtils.isEmpty(dto.getNickname())){ |
| | | if(StringUtils.isEmpty(dto.getNikeName())){ |
| | | return Result.error("昵称不能为空"); |
| | | } |
| | | }else if (dto.getType() == 1){ |
| | |
| | | return Result.error("注册失败,请稍后再试!"); |
| | | } |
| | | } |
| | | |
| | | |
| | | } |