Commit 736a1a2f16cc1cb3139dd9d42871ce795b9c159d

Authored by YunaiV
1 parent 2ab72872

✨ feat(group): 添加用户侧群组和成员接口

新增获取当前登录用户的群列表和指定群的成员列表接口,支持聚合用户昵称和头像信息。优化群组成员查询逻辑,确保返回有效的群成员数据。

- 实现用户侧接口 `/im/group/list-my` 和 `/im/group-member/list`
- 聚合 AdminUser 的昵称和头像信息
- 过滤已封禁和解散的群组
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/friend/ImFriendController.java
... ... @@ -84,7 +84,7 @@ public class ImFriendController {
84 84 // ========== 私有方法:VO 组装 ==========
85 85  
86 86 private List<ImFriendRespVO> buildFriendRespVOList(Collection<ImFriendDO> friends) {
87   - if (CollUtil.isNotEmpty(friends)) {
  87 + if (CollUtil.isEmpty(friends)) {
88 88 return Collections.emptyList();
89 89 }
90 90 // 批量聚合 AdminUser 信息(昵称 / 头像),避免 N+1
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/ImGroupController.java
1 1 package cn.iocoder.yudao.module.im.controller.admin.group;
2 2  
3   -import org.springframework.web.bind.annotation.*;
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  6 +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
  7 +import cn.iocoder.yudao.module.im.controller.admin.group.vo.ImGroupPageReqVO;
  8 +import cn.iocoder.yudao.module.im.controller.admin.group.vo.ImGroupRespVO;
  9 +import cn.iocoder.yudao.module.im.controller.admin.group.vo.ImGroupSaveReqVO;
  10 +import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupDO;
  11 +import cn.iocoder.yudao.module.im.service.group.ImGroupService;
  12 +import io.swagger.v3.oas.annotations.Operation;
  13 +import io.swagger.v3.oas.annotations.Parameter;
  14 +import io.swagger.v3.oas.annotations.tags.Tag;
4 15 import jakarta.annotation.Resource;
5   -import org.springframework.validation.annotation.Validated;
  16 +import jakarta.validation.Valid;
6 17 import org.springframework.security.access.prepost.PreAuthorize;
7   -import io.swagger.v3.oas.annotations.tags.Tag;
8   -import io.swagger.v3.oas.annotations.Parameter;
9   -import io.swagger.v3.oas.annotations.Operation;
  18 +import org.springframework.validation.annotation.Validated;
  19 +import org.springframework.web.bind.annotation.*;
10 20  
11   -import jakarta.validation.*;
  21 +import java.util.List;
12 22  
13   -import cn.iocoder.yudao.framework.common.pojo.PageResult;
14   -import cn.iocoder.yudao.framework.common.pojo.CommonResult;
15   -import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
16 23 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
17 24  
18   -import cn.iocoder.yudao.module.im.controller.admin.group.vo.*;
19   -import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupDO;
20   -import cn.iocoder.yudao.module.im.service.group.ImGroupService;
21   -
22   -// DONE @芋艿:create/update/delete/get/page 全部保留,管理后台群管理需要
23 25 @Tag(name = "管理后台 - 群")
24 26 @RestController
25 27 @RequestMapping("/im/group")
... ... @@ -62,6 +64,7 @@ public class ImGroupController {
62 64 return success(BeanUtils.toBean(group, ImGroupRespVO.class));
63 65 }
64 66  
  67 + // TODO @AI:去掉这个接口;
65 68 @GetMapping("/page")
66 69 @Operation(summary = "获得群分页")
67 70 @PreAuthorize("@ss.hasPermission('im:group:query')")
... ... @@ -70,4 +73,26 @@ public class ImGroupController {
70 73 return success(BeanUtils.toBean(pageResult, ImGroupRespVO.class));
71 74 }
72 75  
73   -}
74 76 \ No newline at end of file
  77 + // ========== 用户侧接口(登录用户自己的群,无需后台权限) ==========
  78 +
  79 + // TODO @AI:直接 list;
  80 + @GetMapping("/list-my")
  81 + @Operation(summary = "获得当前登录用户的群列表")
  82 + public CommonResult<List<ImGroupRespVO>> getMyGroupList() {
  83 + Long userId = SecurityFrameworkUtils.getLoginUserId();
  84 + List<ImGroupDO> groups = imGroupService.getMyGroupList(userId);
  85 + return success(BeanUtils.toBean(groups, ImGroupRespVO.class));
  86 + }
  87 +
  88 + // TODO @芋艿:【对齐】/group/create、/group/modify、/group/invite、/group/quit、/group/delete/{id}
  89 + // 这些用户侧接口第一期暂未实现。需要:
  90 + // 1. createGroup(vo):需同时插入 im_group + 批量插入 im_group_member;还要给群成员推送 FRIEND_INVITE 类消息
  91 + // 2. modifyGroup(vo):允许修改 name / notice / avatar / remarkGroupName / remarkNickName
  92 + // (其中 remarkGroupName / remarkNickName 是 im_group_member 的字段,不是 im_group 的)
  93 + // 3. invite(groupId, userIds):批量插入 im_group_member 为 ENABLE;给被邀请人推送入群通知
  94 + // 4. quitGroup(groupId):校验非群主才能退,然后把自己的 im_group_member 标为 DISABLE + quitTime
  95 + // 5. removeGroupMembers(groupId, userIds):群主权限校验 + 把成员标为 DISABLE
  96 + // 以上都需要 WebSocket 推送对应事件(FRIEND_INVITE / MEMBER_QUIT / MEMBER_REMOVE 等),
  97 + // 涉及 `ImWsEventType` 扩展 + `ImWebSocketPusher` 新增事件推送方法,待统一设计后补上。
  98 +
  99 +}
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/ImGroupMemberController.java
... ... @@ -2,12 +2,15 @@ package cn.iocoder.yudao.module.im.controller.admin.group;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
5 6 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
6 7 import cn.iocoder.yudao.module.im.controller.admin.group.vo.member.ImGroupMemberPageReqVO;
7 8 import cn.iocoder.yudao.module.im.controller.admin.group.vo.member.ImGroupMemberRespVO;
8 9 import cn.iocoder.yudao.module.im.controller.admin.group.vo.member.ImGroupMemberSaveReqVO;
9 10 import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupMemberDO;
10 11 import cn.iocoder.yudao.module.im.service.group.ImGroupMemberService;
  12 +import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
  13 +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
11 14 import io.swagger.v3.oas.annotations.Operation;
12 15 import io.swagger.v3.oas.annotations.Parameter;
13 16 import io.swagger.v3.oas.annotations.tags.Tag;
... ... @@ -17,9 +20,12 @@ import org.springframework.security.access.prepost.PreAuthorize;
17 20 import org.springframework.validation.annotation.Validated;
18 21 import org.springframework.web.bind.annotation.*;
19 22  
  23 +import java.util.Collections;
  24 +import java.util.List;
  25 +import java.util.Map;
  26 +
20 27 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
21 28  
22   -// DONE @芋艿:create/update/delete/get/page 全部保留,管理后台群成员管理需要
23 29 @Tag(name = "管理后台 - 群成员")
24 30 @RestController
25 31 @RequestMapping("/im/group-member")
... ... @@ -29,6 +35,10 @@ public class ImGroupMemberController {
29 35 @Resource
30 36 private ImGroupMemberService imGroupMemberService;
31 37  
  38 + @Resource
  39 + private AdminUserApi adminUserApi;
  40 +
  41 + // TODO @AI:add 加人;
32 42 @PostMapping("/create")
33 43 @Operation(summary = "创建群成员")
34 44 @PreAuthorize("@ss.hasPermission('im:group-member:create')")
... ... @@ -36,6 +46,10 @@ public class ImGroupMemberController {
36 46 return success(imGroupMemberService.createGroupMember(createReqVO));
37 47 }
38 48  
  49 + // TODO @AI:踢人;
  50 +
  51 + // TODO @AI:退群;放在这里;避免 group 里面逻辑太多;
  52 +
39 53 @PutMapping("/update")
40 54 @Operation(summary = "更新群成员")
41 55 @PreAuthorize("@ss.hasPermission('im:group-member:update')")
... ... @@ -70,4 +84,37 @@ public class ImGroupMemberController {
70 84 return success(BeanUtils.toBean(pageResult, ImGroupMemberRespVO.class));
71 85 }
72 86  
73   -}
74 87 \ No newline at end of file
  88 + // ========== 用户侧接口(登录用户自己看群成员,无需后台权限) ==========
  89 +
  90 + @GetMapping("/list")
  91 + @Operation(summary = "获得指定群的成员列表")
  92 + @Parameter(name = "groupId", description = "群编号", required = true, example = "1024")
  93 + public CommonResult<List<ImGroupMemberRespVO>> getGroupMemberList(@RequestParam("groupId") Long groupId) {
  94 + List<ImGroupMemberDO> members = imGroupMemberService.getGroupMemberListByGroupId(groupId);
  95 + if (members.isEmpty()) {
  96 + return success(Collections.emptyList());
  97 + }
  98 + // 聚合 AdminUser 的昵称 + 头像
  99 + List<Long> userIds = CollectionUtils.convertList(members, ImGroupMemberDO::getUserId);
  100 + Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds);
  101 + return success(CollectionUtils.convertList(members, m -> {
  102 + ImGroupMemberRespVO vo = BeanUtils.toBean(m, ImGroupMemberRespVO.class);
  103 + AdminUserRespDTO user = userMap.get(m.getUserId());
  104 + if (user != null) {
  105 + vo.setNickname(user.getNickname());
  106 + vo.setAvatar(user.getAvatar());
  107 + }
  108 + // showNickname 回落:优先群内备注 displayUserName,否则用用户昵称
  109 + if (m.getDisplayUserName() != null && !m.getDisplayUserName().isEmpty()) {
  110 + vo.setShowNickname(m.getDisplayUserName());
  111 + } else if (user != null) {
  112 + vo.setShowNickname(user.getNickname());
  113 + }
  114 + return vo;
  115 + }));
  116 + }
  117 +
  118 + // TODO @芋艿:【对齐】/group/members/remove 批量踢人接口第一期未实现。
  119 + // 需要:校验群主权限、批量更新 im_group_member 为 DISABLE + 设置 quitTime、通过 WebSocket 推送给被踢成员。
  120 +
  121 +}
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupRespVO.java
... ... @@ -27,9 +27,15 @@ public class ImGroupRespVO {
27 27 @Schema(description = "是否封禁")
28 28 private Boolean banned;
29 29  
  30 + @Schema(description = "封禁时间")
  31 + private LocalDateTime bannedTime;
  32 +
30 33 @Schema(description = "是否解散")
31 34 private Boolean dissolved;
32 35  
  36 + @Schema(description = "解散时间")
  37 + private LocalDateTime dissolvedTime;
  38 +
33 39 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
34 40 private LocalDateTime createTime;
35 41  
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/member/ImGroupMemberRespVO.java
... ... @@ -39,4 +39,15 @@ public class ImGroupMemberRespVO {
39 39 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
40 40 private LocalDateTime createTime;
41 41  
  42 + // ========== 聚合字段:用户侧接口按需填充(admin CRUD 查询不填) ==========
  43 +
  44 + @Schema(description = "用户昵称(聚合自 AdminUser,用户侧接口返回)", example = "芋道")
  45 + private String nickname;
  46 +
  47 + @Schema(description = "用户头像(聚合自 AdminUser,用户侧接口返回)")
  48 + private String avatar;
  49 +
  50 + @Schema(description = "展示昵称:优先 displayUserName,回落 nickname", example = "芋道")
  51 + private String showNickname;
  52 +
42 53 }
43 54 \ No newline at end of file
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/group/ImGroupMemberMapper.java
1 1 package cn.iocoder.yudao.module.im.dal.mysql.group;
2 2  
  3 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
3 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 5 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
5 6 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
... ... @@ -7,6 +8,7 @@ import cn.iocoder.yudao.module.im.controller.admin.group.vo.member.ImGroupMember
7 8 import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupMemberDO;
8 9 import org.apache.ibatis.annotations.Mapper;
9 10  
  11 +import java.time.LocalDateTime;
10 12 import java.util.List;
11 13  
12 14 /**
... ... @@ -39,4 +41,35 @@ public interface ImGroupMemberMapper extends BaseMapperX&lt;ImGroupMemberDO&gt; {
39 41 default List<ImGroupMemberDO> selectListByUserId(Long userId) {
40 42 return selectList(new LambdaQueryWrapperX<ImGroupMemberDO>().eq(ImGroupMemberDO::getUserId, userId));
41 43 }
  44 +
  45 + // TODO @AI:selectListByXXX;enabled 传入进来
  46 + default List<ImGroupMemberDO> selectEnabledListByGroupId(Long groupId) {
  47 + return selectList(new LambdaQueryWrapperX<ImGroupMemberDO>()
  48 + .eq(ImGroupMemberDO::getGroupId, groupId)
  49 + .eq(ImGroupMemberDO::getStatus, CommonStatusEnum.ENABLE.getStatus()));
  50 + }
  51 +
  52 + // TODO @AI:selectListByXXX;enabled 传入进来
  53 + default List<ImGroupMemberDO> selectEnabledListByUserId(Long userId) {
  54 + return selectList(new LambdaQueryWrapperX<ImGroupMemberDO>()
  55 + .eq(ImGroupMemberDO::getUserId, userId)
  56 + .eq(ImGroupMemberDO::getStatus, CommonStatusEnum.ENABLE.getStatus()));
  57 + }
  58 +
  59 + /**
  60 + * 查询用户已退群的成员记录
  61 + * <p>
  62 + * 当 {@code minQuitTime} 非空时额外按 {@code quitTime ≥ minQuitTime} 过滤。
  63 + *
  64 + * @param userId 用户编号
  65 + * @param minQuitTime 最早退群时间(含),可空
  66 + * @return 已退群成员记录列表
  67 + */
  68 + default List<ImGroupMemberDO> selectQuitListByUserId(Long userId, LocalDateTime minQuitTime) {
  69 + return selectList(new LambdaQueryWrapperX<ImGroupMemberDO>()
  70 + .eq(ImGroupMemberDO::getUserId, userId)
  71 + .eq(ImGroupMemberDO::getStatus, CommonStatusEnum.DISABLE.getStatus())
  72 + .geIfPresent(ImGroupMemberDO::getQuitTime, minQuitTime));
  73 + }
  74 +
42 75 }
43 76 \ No newline at end of file
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/friend/ImFriendServiceImpl.java
... ... @@ -11,8 +11,10 @@ import cn.iocoder.yudao.module.im.service.websocket.dto.friend.FriendUpdateMessa
11 11 import cn.iocoder.yudao.module.im.service.websocket.dto.ImPrivateMessageDTO;
12 12 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
13 13 import jakarta.annotation.Resource;
  14 +import lombok.extern.slf4j.Slf4j;
14 15 import org.springframework.cache.annotation.CacheEvict;
15 16 import org.springframework.cache.annotation.Cacheable;
  17 +import org.springframework.dao.DuplicateKeyException;
16 18 import org.springframework.stereotype.Service;
17 19 import org.springframework.transaction.annotation.Transactional;
18 20 import org.springframework.validation.annotation.Validated;
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/group/ImGroupMemberService.java
... ... @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.im.controller.admin.group.vo.member.ImGroupMember
6 6 import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupMemberDO;
7 7 import jakarta.validation.Valid;
8 8  
  9 +import java.time.LocalDateTime;
9 10 import java.util.List;
10 11  
11 12 /**
... ... @@ -54,12 +55,12 @@ public interface ImGroupMemberService {
54 55 PageResult<ImGroupMemberDO> getGroupMemberPage(ImGroupMemberPageReqVO pageReqVO);
55 56  
56 57 /**
57   - * 根据群组id查询群成员
  58 + * 根据群组 id 查询群成员(包含所有状态)
58 59 *
59 60 * @param groupId 群组id
60 61 * @return 群成员列表
61 62 */
62   - List<ImGroupMemberDO> selectByGroupId(Long groupId);
  63 + List<ImGroupMemberDO> getGroupMemberListByGroupId(Long groupId);
63 64  
64 65 /**
65 66 * 根据群编号和用户编号查询群成员
... ... @@ -76,5 +77,39 @@ public interface ImGroupMemberService {
76 77 * @param userId 用户编号
77 78 * @return 群成员记录列表
78 79 */
79   - List<ImGroupMemberDO> getGroupMembersByUserId(Long userId);
  80 + List<ImGroupMemberDO> getGroupMemberListByUserId(Long userId);
  81 +
  82 + /**
  83 + * 根据群编号查询有效成员列表(仅 ENABLE 状态)
  84 + *
  85 + * @param groupId 群编号
  86 + * @return 有效群成员列表
  87 + */
  88 + List<ImGroupMemberDO> getActiveGroupMemberListByGroupId(Long groupId);
  89 +
  90 + /**
  91 + * 查询用户所在的所有群的有效成员记录(仅 ENABLE 状态)
  92 + *
  93 + * @param userId 用户编号
  94 + * @return 有效群成员记录列表
  95 + */
  96 + List<ImGroupMemberDO> getActiveGroupMemberListByUserId(Long userId);
  97 +
  98 + /**
  99 + * 查询用户已退群的群成员记录(DISABLE 状态)
  100 + *
  101 + * @param userId 用户编号,必传
  102 + * @param minQuitTime 最早退群时间(含),可空
  103 + * @return 已退群成员记录列表
  104 + */
  105 + List<ImGroupMemberDO> getQuitGroupMemberListByUserId(Long userId, LocalDateTime minQuitTime);
  106 +
  107 + /**
  108 + * 校验用户是否为群的有效成员
  109 + *
  110 + * @param groupId 群编号
  111 + * @param userId 用户编号
  112 + * @return 群成员记录
  113 + */
  114 + ImGroupMemberDO validateMemberInGroup(Long groupId, Long userId);
80 115 }
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/group/ImGroupMemberServiceImpl.java
1 1 package cn.iocoder.yudao.module.im.service.group;
2 2  
  3 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
3 4 import cn.iocoder.yudao.module.im.controller.admin.group.vo.member.ImGroupMemberPageReqVO;
4 5 import cn.iocoder.yudao.module.im.controller.admin.group.vo.member.ImGroupMemberSaveReqVO;
5 6 import org.springframework.stereotype.Service;
... ... @@ -12,6 +13,7 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
12 13  
13 14 import cn.iocoder.yudao.module.im.dal.mysql.group.ImGroupMemberMapper;
14 15  
  16 +import java.time.LocalDateTime;
15 17 import java.util.List;
16 18  
17 19 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
... ... @@ -72,7 +74,7 @@ public class ImGroupMemberServiceImpl implements ImGroupMemberService {
72 74 }
73 75  
74 76 @Override
75   - public List<ImGroupMemberDO> selectByGroupId(Long groupId) {
  77 + public List<ImGroupMemberDO> getGroupMemberListByGroupId(Long groupId) {
76 78 return imGroupMemberMapper.selectListByGroupId(groupId);
77 79 }
78 80  
... ... @@ -82,8 +84,32 @@ public class ImGroupMemberServiceImpl implements ImGroupMemberService {
82 84 }
83 85  
84 86 @Override
85   - public List<ImGroupMemberDO> getGroupMembersByUserId(Long userId) {
  87 + public List<ImGroupMemberDO> getGroupMemberListByUserId(Long userId) {
86 88 return imGroupMemberMapper.selectListByUserId(userId);
87 89 }
88 90  
  91 + @Override
  92 + public List<ImGroupMemberDO> getActiveGroupMemberListByGroupId(Long groupId) {
  93 + return imGroupMemberMapper.selectEnabledListByGroupId(groupId);
  94 + }
  95 +
  96 + @Override
  97 + public List<ImGroupMemberDO> getActiveGroupMemberListByUserId(Long userId) {
  98 + return imGroupMemberMapper.selectEnabledListByUserId(userId);
  99 + }
  100 +
  101 + @Override
  102 + public List<ImGroupMemberDO> getQuitGroupMemberListByUserId(Long userId, LocalDateTime minQuitTime) {
  103 + return imGroupMemberMapper.selectQuitListByUserId(userId, minQuitTime);
  104 + }
  105 +
  106 + @Override
  107 + public ImGroupMemberDO validateMemberInGroup(Long groupId, Long userId) {
  108 + ImGroupMemberDO member = imGroupMemberMapper.selectByGroupIdAndUserId(groupId, userId);
  109 + if (member == null || CommonStatusEnum.DISABLE.getStatus().equals(member.getStatus())) {
  110 + throw exception(GROUP_MEMBER_NOT_IN_GROUP);
  111 + }
  112 + return member;
  113 + }
  114 +
89 115 }
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/group/ImGroupService.java
... ... @@ -5,6 +5,8 @@ import cn.iocoder.yudao.module.im.controller.admin.group.vo.*;
5 5 import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupDO;
6 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
7 7  
  8 +import java.util.List;
  9 +
8 10 /**
9 11 * 群 Service 接口
10 12 *
... ... @@ -58,4 +60,14 @@ public interface ImGroupService {
58 60 */
59 61 ImGroupDO validateGroupExists(Long groupId);
60 62  
61   -}
62 63 \ No newline at end of file
  64 + /**
  65 + * 获取指定用户加入的所有"有效"群(未退群且未封禁/解散)
  66 + * <p>
  67 + * 返回当前登录用户在群内身份仍有效的所有群。
  68 + *
  69 + * @param userId 用户编号
  70 + * @return 群列表
  71 + */
  72 + List<ImGroupDO> getMyGroupList(Long userId);
  73 +
  74 +}
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/group/ImGroupServiceImpl.java
1 1 package cn.iocoder.yudao.module.im.service.group;
2 2  
  3 +import cn.hutool.core.collection.CollUtil;
3 4 import org.springframework.stereotype.Service;
4 5 import jakarta.annotation.Resource;
5 6 import org.springframework.validation.annotation.Validated;
... ... @@ -22,6 +23,7 @@ import java.util.Set;
22 23 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
23 24 import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.*;
24 25  
  26 +// TODO @芋艿:群主的调整,暂时不考虑。后续在弄;
25 27 /**
26 28 * 群 Service 实现类
27 29 *
... ... @@ -37,32 +39,53 @@ public class ImGroupServiceImpl implements ImGroupService {
37 39 @Resource
38 40 private ImGroupMemberMapper imGroupMemberMapper;
39 41  
  42 + // TODO @AI:返回对象;
  43 + // TODO @AI:要不要拆分 VO;ImGroupCreateReqVO(name)
40 44 @Override
41 45 public Long createGroup(ImGroupSaveReqVO createReqVO) {
42 46 // 插入
43 47 ImGroupDO group = BeanUtils.toBean(createReqVO, ImGroupDO.class);
44 48 imGroupMapper.insert(group);
45   - // 返回
  49 +
  50 + // TODO @AI:群主 GroupMember;
  51 +
  52 + // TODO 多终端推送消息(group message)
46 53 return group.getId();
47 54 }
48 55  
  56 + // TODO @AI:要不要拆分 VO;ImGroupUpdateReqVO(name、avatar、notice);我在本群的昵称/群名备注;
  57 + // TODO 1. 需要校验群主:name、avatar、notice;如果修改群信息,是不是要群发消息?(群信息变更消息);
  58 + // TODO 2. 需要校验群成员:我在本群的昵称/群名备注
  59 + // TODO @AI:返回 返回对象;
49 60 @Override
50 61 public void updateGroup(ImGroupSaveReqVO updateReqVO) {
51 62 // 校验存在
52 63 validateGroupExists(updateReqVO.getId());
  64 +
53 65 // 更新
54 66 ImGroupDO updateObj = BeanUtils.toBean(updateReqVO, ImGroupDO.class);
55 67 imGroupMapper.updateById(updateObj);
56 68 }
57 69  
  70 + // TODO @AI:dissolve 解散群;
58 71 @Override
59 72 public void deleteGroup(Long id) {
60 73 // 校验存在
61 74 validateGroupExists(id);
  75 + // TODO @AI:群主才可以;
  76 +
  77 + // TODO @AI:清理已读缓存;
  78 +
  79 + // TODO @AI:推送群解散的提示;
  80 +
  81 + // TODO @AI:推送群信息变化;
  82 +
62 83 // 删除
63 84 imGroupMapper.deleteById(id);
64 85 }
65 86  
  87 + // TODO @AI:quit 退群;
  88 +
66 89 @Override
67 90 public ImGroupDO validateGroupExists(Long id) {
68 91 ImGroupDO group = imGroupMapper.selectById(id);
... ... @@ -78,6 +101,10 @@ public class ImGroupServiceImpl implements ImGroupService {
78 101 return group;
79 102 }
80 103  
  104 + // TODO @AI:add 加群;
  105 +
  106 + // TODO @AI:remove 踢人;
  107 +
81 108 @Override
82 109 public ImGroupDO getGroup(Long id) {
83 110 return imGroupMapper.selectById(id);
... ... @@ -92,14 +119,15 @@ public class ImGroupServiceImpl implements ImGroupService {
92 119 public List<ImGroupDO> getMyGroupList(Long userId) {
93 120 // 1. 查用户所在的、仍有效的群成员记录(仅 ENABLE 状态)
94 121 List<ImGroupMemberDO> members = imGroupMemberMapper.selectEnabledListByUserId(userId);
95   - if (members.isEmpty()) {
  122 + if (CollUtil.isNotEmpty(members)) {
96 123 return Collections.emptyList();
97 124 }
98 125 Set<Long> groupIds = CollectionUtils.convertSet(members, ImGroupMemberDO::getGroupId);
99   - if (groupIds.isEmpty()) {
  126 + if (CollUtil.isEmpty(groupIds)) {
100 127 return Collections.emptyList();
101 128 }
102 129 // 2. 查群并过滤掉已封禁/解散的
  130 + // TODO @AI:查询的时候,就过滤掉!不要内存过滤;
103 131 List<ImGroupDO> groups = imGroupMapper.selectByIds(groupIds);
104 132 groups.removeIf(g -> Boolean.TRUE.equals(g.getBanned()) || Boolean.TRUE.equals(g.getDissolved()));
105 133 return groups;
... ...