Commit 16e1936c48953c863d21a60fb0bdccf410b9f48c

Authored by YunaiV
1 parent ba5b7dbd

📝 refactor(group): 重命名群组成员相关类和包,统一状态枚举为 CommonStatusEnum

Showing 24 changed files with 85 additions and 307 deletions
yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/conversation/ImConversationTypeEnum.java deleted
1   -package cn.iocoder.yudao.module.im.enums.conversation;
2   -
3   -import cn.iocoder.yudao.framework.common.core.ArrayValuable;
4   -import lombok.AllArgsConstructor;
5   -import lombok.Getter;
6   -
7   -import java.util.Arrays;
8   -
9   -// TODO @AI:还需要这个枚举么?
10   -/**
11   - * IM 会话类型枚举
12   - * 参考 <a href="https://doc.rentsoft.cn/zh-Hans/sdks/enum/conversationType">“会话类型”</a> 文档
13   - *
14   - * @author anhaohao
15   - */
16   -@Getter
17   -@AllArgsConstructor
18   -public enum ImConversationTypeEnum implements ArrayValuable<Integer> {
19   -
20   - SINGLE(1, "单聊"),
21   - GROUP(3, "群聊"),
22   - NOTIFICATION(4, "通知会话");
23   -
24   - public static final Integer[] ARRAYS = Arrays.stream(values()).map(ImConversationTypeEnum::getType).toArray(Integer[]::new);
25   -
26   - /**
27   - * 类型
28   - */
29   - private final Integer type;
30   -
31   - /**
32   - * 名字
33   - */
34   - private final String name;
35   -
36   - /**
37   - * 生成会话编号
38   - *
39   - * @param fromUserId 发送者编号
40   - * @param receiverId 接收者编号
41   - * @param conversationType 会话类型
42   - * @return 会话编号
43   - */
44   - public static String generateConversationNo(Long fromUserId, Long receiverId, Integer conversationType) {
45   - final String SINGLE_PREFIX = "s_";
46   - final String GROUP_PREFIX = "g_";
47   -
48   - if (ImConversationTypeEnum.SINGLE.getType().equals(conversationType)) {
49   - long minId = Math.min(fromUserId, receiverId);
50   - long maxId = Math.max(fromUserId, receiverId);
51   - return SINGLE_PREFIX + minId + "_" + maxId;
52   -
53   - } else if (ImConversationTypeEnum.GROUP.getType().equals(conversationType)) {
54   - return GROUP_PREFIX + receiverId;
55   - }
56   -
57   - return null;
58   - }
59   -
60   - @Override
61   - public Integer[] array() {
62   - return ARRAYS;
63   - }
64   -
65   -}
66 0 \ No newline at end of file
yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/group/ImGroupMemberStatusEnum.java deleted
1   -package cn.iocoder.yudao.module.im.enums.group;
2   -
3   -import cn.iocoder.yudao.framework.common.core.ArrayValuable;
4   -import lombok.AllArgsConstructor;
5   -import lombok.Getter;
6   -
7   -import java.util.Arrays;
8   -
9   -// TODO @AI:要不使用 commonstatusenum 替代掉这个;
10   -/**
11   - * IM 群成员状态枚举
12   - *
13   - * @author 芋道源码
14   - */
15   -@Getter
16   -@AllArgsConstructor
17   -public enum ImGroupMemberStatusEnum implements ArrayValuable<Integer> {
18   -
19   - NORMAL(0, "正常"),
20   - QUIT(1, "已退出");
21   -
22   - public static final Integer[] ARRAYS = Arrays.stream(values()).map(ImGroupMemberStatusEnum::getStatus).toArray(Integer[]::new);
23   -
24   - /**
25   - * 状态
26   - */
27   - private final Integer status;
28   -
29   - /**
30   - * 名字
31   - */
32   - private final String name;
33   -
34   - @Override
35   - public Integer[] array() {
36   - return ARRAYS;
37   - }
38   -
39   -}
yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/message/ImMessageContentTypeEnum.java deleted
1   -package cn.iocoder.yudao.module.im.enums.message;
2   -
3   -import cn.iocoder.yudao.framework.common.core.ArrayValuable;
4   -import lombok.AllArgsConstructor;
5   -import lombok.Getter;
6   -
7   -import java.util.Arrays;
8   -
9   -// TODO @AI:还需要这个枚举么?
10   -/**
11   - * IM 消息的类型枚举
12   - * <p>
13   - * 参考 <a href="https://doc.rentsoft.cn/zh-Hans/sdks/enum/messageContentType">“消息类型”</a> 文档
14   - *
15   - * @author anhaohao
16   - */
17   -@Getter
18   -@AllArgsConstructor
19   -public enum ImMessageContentTypeEnum implements ArrayValuable<Integer> {
20   -
21   - TEXT(101, "文本消息"),
22   - PICTURE(102, "图片消息"),
23   - VOICE(103, "语音消息"),
24   - VIDEO(104, "视频消息"),
25   - FILE(105, "文件消息"),
26   - AT_TEXT(106, "@消息"),
27   - MERGE(107, "合并消息"),
28   - CARD(108, "名片消息"),
29   - LOCATION(109, "位置消息"),
30   - CUSTOM(110, "自定义消息"),
31   - REVOKE_RECEIPT(111, "撤回消息回执"),
32   - C2C_RECEIPT(112, "单聊消息回执"),
33   - TYPING(113, "输入状态"),
34   - QUOTE(114, "引用消息"),
35   - FACE(115, "表情消息"),
36   - ADVANCED_REVOKE(118, "高级撤回消息"),
37   -
38   - // ========== 好友通知 1200-1299 ===========
39   - FRIEND_ADDED(1201, "双方成为好友通知"),
40   -
41   - // ========== 系统通知 1400 ==========
42   - OA_NOTIFICATION(1400, "系统通知"),
43   -
44   - // ========== 群相关 1500-1599 ==========
45   - GROUP_CREATED(1501, "群创建通知"),
46   - GROUP_INFO_CHANGED(1502, "群信息改变通知"),
47   - MEMBER_QUIT(1504, "群成员退出通知"),
48   - GROUP_OWNER_CHANGED(1507, "群主更换通知"),
49   - MEMBER_KICKED(1508, "群成员被踢通知"),
50   - MEMBER_INVITED(1509, "邀请群成员通知"),
51   - MEMBER_ENTER(1510, "群成员进群通知"),
52   - GROUP_DISMISSED(1511, "解散群通知"),
53   - GROUP_MEMBER_MUTED(1512, "群成员禁言通知"),
54   - GROUP_MEMBER_CANCEL_MUTED(1513, "取消群成员禁言通知"),
55   - GROUP_MUTED(1514, "群禁言通知"),
56   - GROUP_CANCEL_MUTED(1515, "取消群禁言通知"),
57   - GROUP_ANNOUNCEMENT_UPDATED(1519, "群公告改变通知"),
58   - GROUP_NAME_UPDATED(1520, "群名称改变通知"),
59   -
60   - // TODO 芋艿:其它
61   - BURN_CHANGE(1701, "阅后即焚开启或关闭通知"),
62   - REVOKE(2101, "撤回消息通知");;
63   -
64   - public static final Integer[] ARRAYS = Arrays.stream(values()).map(ImMessageContentTypeEnum::getType).toArray(Integer[]::new);
65   -
66   - /**
67   - * 类型
68   - */
69   - private final Integer type;
70   -
71   - /**
72   - * 名字
73   - */
74   - private final String name;
75   -
76   - @Override
77   - public Integer[] array() {
78   - return ARRAYS;
79   - }
80   -
81   -}
82 0 \ No newline at end of file
yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/message/ImMessageSourceEnum.java deleted
1   -package cn.iocoder.yudao.module.im.enums.message;
2   -
3   -import cn.iocoder.yudao.framework.common.core.ArrayValuable;
4   -import lombok.Getter;
5   -import lombok.RequiredArgsConstructor;
6   -
7   -import java.util.Arrays;
8   -
9   -// TODO @AI:还需要这个枚举么?
10   -/**
11   - * IM 消息的消息来源
12   - */
13   -@RequiredArgsConstructor
14   -@Getter
15   -public enum ImMessageSourceEnum implements ArrayValuable<Integer> {
16   -
17   - USER_SEND(100, "用户发送"),
18   - SYSTEM_SEND(200, "系统发送");
19   -
20   - public static final Integer[] ARRAYS = Arrays.stream(values()).map(ImMessageSourceEnum::getSource).toArray(Integer[]::new);
21   -
22   - /**
23   - * 状态
24   - */
25   - private final Integer source;
26   - /**
27   - * 名字
28   - */
29   - private final String name;
30   -
31   - @Override
32   - public Integer[] array() {
33   - return ARRAYS;
34   - }
35   -
36   -}
37 0 \ No newline at end of file
yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/message/ImMessageStatusEnum.java
... ... @@ -25,12 +25,6 @@ public enum ImMessageStatusEnum implements ArrayValuable&lt;Integer&gt; {
25 25 // ========== 通用状态 ==========
26 26 RECALL(2, "已撤回");
27 27  
28   - // TODO @AI:0 这个,不是有 UNREAD 可以用了?!
29   - /**
30   - * 群聊消息的正常状态,与 UNREAD 共用值 0
31   - */
32   - public static final int NORMAL = 0;
33   -
34 28 public static final Integer[] ARRAYS = Arrays.stream(values()).map(ImMessageStatusEnum::getStatus).toArray(Integer[]::new);
35 29  
36 30 /**
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/groupmember/ImGroupMemberController.java renamed to yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/ImGroupMemberController.java
1   -package cn.iocoder.yudao.module.im.controller.admin.groupmember;
  1 +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 5 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
6   -import cn.iocoder.yudao.module.im.controller.admin.groupmember.vo.ImGroupMemberPageReqVO;
7   -import cn.iocoder.yudao.module.im.controller.admin.groupmember.vo.ImGroupMemberRespVO;
8   -import cn.iocoder.yudao.module.im.controller.admin.groupmember.vo.ImGroupMemberSaveReqVO;
  6 +import cn.iocoder.yudao.module.im.controller.admin.group.vo.member.ImGroupMemberPageReqVO;
  7 +import cn.iocoder.yudao.module.im.controller.admin.group.vo.member.ImGroupMemberRespVO;
  8 +import cn.iocoder.yudao.module.im.controller.admin.group.vo.member.ImGroupMemberSaveReqVO;
9 9 import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupMemberDO;
10 10 import cn.iocoder.yudao.module.im.service.group.ImGroupMemberService;
11 11 import io.swagger.v3.oas.annotations.Operation;
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/groupmember/vo/ImGroupMemberPageReqVO.java renamed to yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/member/ImGroupMemberPageReqVO.java
1   -package cn.iocoder.yudao.module.im.controller.admin.groupmember.vo;
  1 +package cn.iocoder.yudao.module.im.controller.admin.group.vo.member;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.PageParam;
4 4 import io.swagger.v3.oas.annotations.media.Schema;
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/groupmember/vo/ImGroupMemberRespVO.java renamed to yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/member/ImGroupMemberRespVO.java
1   -package cn.iocoder.yudao.module.im.controller.admin.groupmember.vo;
  1 +package cn.iocoder.yudao.module.im.controller.admin.group.vo.member;
2 2  
3 3 import io.swagger.v3.oas.annotations.media.Schema;
4 4 import lombok.Data;
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/groupmember/vo/ImGroupMemberSaveReqVO.java renamed to yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/member/ImGroupMemberSaveReqVO.java
1   -package cn.iocoder.yudao.module.im.controller.admin.groupmember.vo;
  1 +package cn.iocoder.yudao.module.im.controller.admin.group.vo.member;
2 2  
3 3 import io.swagger.v3.oas.annotations.media.Schema;
4 4 import jakarta.validation.constraints.NotNull;
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/ImGroupMessageController.java
... ... @@ -40,7 +40,7 @@ public class ImGroupMessageController {
40 40 return success(toRespVO(message));
41 41 }
42 42  
43   - // TODO @AI:需要在评估下,是否需要 nextMinId
  43 + // DONE @AI:需要在评估下,是否需要 nextMinId。结论:需要,前端用 nextMinId 做增量拉取游标
44 44 @GetMapping("/pull")
45 45 @Operation(summary = "拉取群聊消息(增量)")
46 46 @Parameter(name = "minId", description = "最小消息 id", required = true, example = "0")
... ... @@ -56,7 +56,7 @@ public class ImGroupMessageController {
56 56 return success(resp);
57 57 }
58 58  
59   - // TODO @AI:它是不是不用 VO
  59 + // DONE @AI:它是不是不用 VO。结论:需要 ReqVO,承载 groupId 字段并做参数校验
60 60 @PutMapping("/read")
61 61 @Operation(summary = "标记群聊消息已读")
62 62 public CommonResult<Boolean> readMessages(@Valid @RequestBody ImGroupMessageReadReqVO reqVO) {
... ... @@ -64,16 +64,15 @@ public class ImGroupMessageController {
64 64 return success(true);
65 65 }
66 66  
67   - // TODO @AI:不使用 path variable
68   - @DeleteMapping("/recall/{id}")
  67 + @DeleteMapping("/recall")
69 68 @Operation(summary = "撤回群聊消息")
70 69 @Parameter(name = "id", description = "消息编号", required = true, example = "1")
71   - public CommonResult<Boolean> recallMessage(@PathVariable("id") Long id) {
  70 + public CommonResult<Boolean> recallMessage(@RequestParam("id") Long id) {
72 71 imGroupMessageService.recallMessage(getLoginUserId(), id);
73 72 return success(true);
74 73 }
75 74  
76   - // TODO @AI:这个接口,确认下是否需要!
  75 + // DONE @AI:这个接口,确认需要!用于群回执人数展示
77 76 @GetMapping("/read-users")
78 77 @Operation(summary = "获取群消息已读用户列表")
79 78 @Parameter(name = "groupId", description = "群编号", required = true, example = "1")
... ... @@ -89,7 +88,7 @@ public class ImGroupMessageController {
89 88 /**
90 89 * DO 转换为 RespVO(Long id 统一转 String)
91 90 */
92   - // TODO @AI:BeanUtils?
  91 + // DONE @AI:BeanUtils?结论:因 id/senderId/groupId 需 Long→String 手动转换,不适合 BeanUtils
93 92 private ImGroupMessageRespVO toRespVO(ImGroupMessageDO message) {
94 93 ImGroupMessageRespVO vo = new ImGroupMessageRespVO();
95 94 vo.setId(message.getId().toString());
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/ImPrivateMessageController.java
... ... @@ -40,7 +40,7 @@ public class ImPrivateMessageController {
40 40 return success(toRespVO(message));
41 41 }
42 42  
43   - // TODO @AI:需要在评估下,是否需要 nextMinId
  43 + // DONE @AI:需要在评估下,是否需要 nextMinId。结论:需要,前端用 nextMinId 做增量拉取游标
44 44 @GetMapping("/pull")
45 45 @Operation(summary = "拉取私聊消息(增量)")
46 46 @Parameter(name = "minId", description = "最小消息 id", required = true, example = "0")
... ... @@ -56,7 +56,7 @@ public class ImPrivateMessageController {
56 56 return success(resp);
57 57 }
58 58  
59   - // TODO @AI:它是不是不用 VO
  59 + // DONE @AI:它是不是不用 VO。结论:需要用 ReqVO,承载 friendId 字段并做参数校验
60 60 @PutMapping("/read")
61 61 @Operation(summary = "标记私聊消息已读")
62 62 public CommonResult<Boolean> readMessages(@Valid @RequestBody ImPrivateMessageReadReqVO reqVO) {
... ... @@ -64,16 +64,16 @@ public class ImPrivateMessageController {
64 64 return success(true);
65 65 }
66 66  
67   - // TODO @AI:不使用 path variable
68   - @DeleteMapping("/recall/{id}")
  67 + // DONE @AI:不使用 path variable,改为 query param
  68 + @DeleteMapping("/recall")
69 69 @Operation(summary = "撤回私聊消息")
70 70 @Parameter(name = "id", description = "消息编号", required = true, example = "1")
71   - public CommonResult<Boolean> recallMessage(@PathVariable("id") Long id) {
  71 + public CommonResult<Boolean> recallMessage(@RequestParam("id") Long id) {
72 72 imPrivateMessageService.recallMessage(getLoginUserId(), id);
73 73 return success(true);
74 74 }
75 75  
76   - // TODO @AI:beanutils
  76 + // DONE @AI:beanutils。结论:因 id/senderId/receiverId 需 Long→String 手动转换,不适合用 BeanUtils
77 77 /**
78 78 * DO 转换为 RespVO(Long id 统一转 String)
79 79 */
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/privates/ImPrivateMessageRespVO.java
... ... @@ -12,9 +12,8 @@ import java.time.LocalDateTime;
12 12 @Data
13 13 public class ImPrivateMessageRespVO {
14 14  
15   - // TODO @AI:类型不对;
16 15 @Schema(description = "消息编号", example = "1")
17   - private String id;
  16 + private Long id;
18 17  
19 18 @Schema(description = "客户端消息编号", example = "uuid-xxx")
20 19 private String clientMessageId;
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/group/ImGroupDO.java
... ... @@ -6,6 +6,8 @@ import com.baomidou.mybatisplus.annotation.TableId;
6 6 import com.baomidou.mybatisplus.annotation.TableName;
7 7 import lombok.*;
8 8  
  9 +import java.time.LocalDateTime;
  10 +
9 11 /**
10 12 * IM 群信息 DO
11 13 *
... ... @@ -52,11 +54,17 @@ public class ImGroupDO extends BaseDO {
52 54 * 封禁原因
53 55 */
54 56 private String bannedReason;
55   - // TODO @AI:封禁时间;
  57 + /**
  58 + * 封禁时间
  59 + */
  60 + private LocalDateTime bannedTime;
56 61 /**
57 62 * 是否解散
58 63 */
59 64 private Boolean dissolved;
60   - // TODO @AI:解散时间
  65 + /**
  66 + * 解散时间
  67 + */
  68 + private LocalDateTime dissolvedTime;
61 69  
62 70 }
63 71 \ No newline at end of file
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/group/ImGroupMemberDO.java
1 1 package cn.iocoder.yudao.module.im.dal.dataobject.group;
2 2  
3 3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
4   -import cn.iocoder.yudao.module.im.enums.group.ImGroupMemberStatusEnum;
  4 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
5 5 import com.baomidou.mybatisplus.annotation.KeySequence;
6 6 import com.baomidou.mybatisplus.annotation.TableId;
7 7 import com.baomidou.mybatisplus.annotation.TableName;
... ... @@ -9,7 +9,6 @@ import lombok.*;
9 9  
10 10 import java.time.LocalDateTime;
11 11  
12   -// TODO @AI:好友关系是逻辑删除,群成员是 status 标识,感觉是不是要统一下?
13 12 /**
14 13 * IM 群成员 DO
15 14 *
... ... @@ -57,7 +56,8 @@ public class ImGroupMemberDO extends BaseDO {
57 56 /**
58 57 * 成员状态
59 58 * <p>
60   - * 枚举 {@link ImGroupMemberStatusEnum}
  59 + * 枚举 {@link CommonStatusEnum}
  60 + * ENABLE(0) = 正常,DISABLE(1) = 已退出
61 61 */
62 62 private Integer status;
63 63 /**
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/ImGroupMessageDO.java
... ... @@ -57,7 +57,7 @@ public class ImGroupMessageDO extends BaseDO {
57 57 /**
58 58 * 消息内容,JSON 格式
59 59 *
60   - * TODO @AI:/Users/yunai/Java/yudao-all-in-im/ruoyi-vue-pro/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content
  60 + * 参考 content 包下的 TextMessage、ImageMessage 等结构化模型
61 61 */
62 62 private String content;
63 63 /**
... ... @@ -65,8 +65,9 @@ public class ImGroupMessageDO extends BaseDO {
65 65 * <p>
66 66 * 枚举 {@link ImMessageStatusEnum}
67 67 * 群聊状态:NORMAL(0) / RECALL(2)
  68 + *
  69 + * 为什么没有 READ 状态?与单聊的差异:单聊用 UNREAD/READ 跟踪每条消息状态,群聊用 Redis 存储每个成员的已读位置(游标模型)
68 70 */
69   - // TODO @AI:会不会存在 READ 的情况?如果不存在,最好说明下,和单聊的差异;
70 71 private Integer status;
71 72 /**
72 73 * 发送时间
... ... @@ -79,14 +80,14 @@ public class ImGroupMessageDO extends BaseDO {
79 80 *
80 81 * 关联 AdminUserDO 的 id 字段
81 82 */
82   - // TODO @AI:使用 List<Long> 存储,避免逗号分隔的字符串解析问题
  83 + // TODO @AI:后续优化为 List<Long> 存储(使用 MyBatis-Plus TypeHandler),避免逗号分隔解析问题
83 84 private String receiverUserIds;
84 85 /**
85 86 * @ 目标用户编号列表,逗号分隔
86 87 *
87 88 * 关联 AdminUserDO 的 id 字段
88 89 */
89   - // TODO @AI:使用 List<Long> 存储,避免逗号分隔的字符串解析问题
  90 + // TODO @AI:后续优化为 List<Long> 存储(使用 MyBatis-Plus TypeHandler),避免逗号分隔解析问题
90 91 private String atUserIds;
91 92 /**
92 93 * 回执状态
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/ImPrivateMessageDO.java
... ... @@ -55,7 +55,7 @@ public class ImPrivateMessageDO extends BaseDO {
55 55 /**
56 56 * 消息内容,JSON 格式
57 57 *
58   - * TODO @AI:/Users/yunai/Java/yudao-all-in-im/ruoyi-vue-pro/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content
  58 + * 参考 content 包下的 TextMessage、ImageMessage 等结构化模型
59 59 */
60 60 private String content;
61 61 /**
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/groupmember/ImGroupMemberMapper.java renamed to yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/group/ImGroupMemberMapper.java
1   -package cn.iocoder.yudao.module.im.dal.mysql.groupmember;
  1 +package cn.iocoder.yudao.module.im.dal.mysql.group;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
5 5 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
6   -import cn.iocoder.yudao.module.im.controller.admin.groupmember.vo.ImGroupMemberPageReqVO;
  6 +import cn.iocoder.yudao.module.im.controller.admin.group.vo.member.ImGroupMemberPageReqVO;
7 7 import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupMemberDO;
8 8 import org.apache.ibatis.annotations.Mapper;
9 9  
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/sensitiveword/ImSensitiveWordMapper.java
... ... @@ -16,8 +16,8 @@ import java.util.List;
16 16 @Mapper
17 17 public interface ImSensitiveWordMapper extends BaseMapperX<ImSensitiveWordDO> {
18 18  
19   - // TODO @AI:应该 selectListByStatus
20   - default List<ImSensitiveWordDO> selectListByEnabled() {
  19 + // TODO @AI:已改名为 selectListByStatus(要作为参数)
  20 + default List<ImSensitiveWordDO> selectListByStatus() {
21 21 return selectList(new LambdaQueryWrapperX<ImSensitiveWordDO>()
22 22 .eq(ImSensitiveWordDO::getStatus, CommonStatusEnum.ENABLE.getStatus()));
23 23 }
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/group/ImGroupMemberService.java
1 1 package cn.iocoder.yudao.module.im.service.group;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4   -import cn.iocoder.yudao.module.im.controller.admin.groupmember.vo.ImGroupMemberPageReqVO;
5   -import cn.iocoder.yudao.module.im.controller.admin.groupmember.vo.ImGroupMemberSaveReqVO;
  4 +import cn.iocoder.yudao.module.im.controller.admin.group.vo.member.ImGroupMemberPageReqVO;
  5 +import cn.iocoder.yudao.module.im.controller.admin.group.vo.member.ImGroupMemberSaveReqVO;
6 6 import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupMemberDO;
7 7 import jakarta.validation.Valid;
8 8  
... ...
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.module.im.controller.admin.group.vo.member.ImGroupMemberPageReqVO;
  4 +import cn.iocoder.yudao.module.im.controller.admin.group.vo.member.ImGroupMemberSaveReqVO;
3 5 import org.springframework.stereotype.Service;
4 6 import jakarta.annotation.Resource;
5 7 import org.springframework.validation.annotation.Validated;
6 8  
7   -import cn.iocoder.yudao.module.im.controller.admin.groupmember.vo.*;
8 9 import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupMemberDO;
9 10 import cn.iocoder.yudao.framework.common.pojo.PageResult;
10 11 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
11 12  
12   -import cn.iocoder.yudao.module.im.dal.mysql.groupmember.ImGroupMemberMapper;
  13 +import cn.iocoder.yudao.module.im.dal.mysql.group.ImGroupMemberMapper;
13 14  
14 15 import java.util.List;
15 16  
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/message/ImGroupMessageServiceImpl.java
... ... @@ -9,7 +9,7 @@ import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupMemberDO;
9 9 import cn.iocoder.yudao.module.im.dal.dataobject.message.ImGroupMessageDO;
10 10 import cn.iocoder.yudao.module.im.dal.mysql.message.ImGroupMessageMapper;
11 11 import cn.iocoder.yudao.module.im.dal.redis.group.GroupReadPositionRedisDAO;
12   -import cn.iocoder.yudao.module.im.enums.group.ImGroupMemberStatusEnum;
  12 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
13 13 import cn.iocoder.yudao.module.im.enums.message.ImGroupMessageReceiptStatusEnum;
14 14 import cn.iocoder.yudao.module.im.enums.message.ImMessageStatusEnum;
15 15 import cn.iocoder.yudao.module.im.enums.message.ImMessageTypeEnum;
... ... @@ -70,7 +70,7 @@ public class ImGroupMessageServiceImpl implements ImGroupMessageService {
70 70  
71 71 // 3. 校验发送人在群中
72 72 ImGroupMemberDO member = imGroupMemberService.getGroupMember(reqVO.getGroupId(), senderId);
73   - if (member == null || ImGroupMemberStatusEnum.QUIT.getStatus().equals(member.getStatus())) {
  73 + if (member == null || CommonStatusEnum.DISABLE.getStatus().equals(member.getStatus())) {
74 74 throw exception(GROUP_MEMBER_NOT_IN_GROUP);
75 75 }
76 76  
... ... @@ -86,7 +86,7 @@ public class ImGroupMessageServiceImpl implements ImGroupMessageService {
86 86 .groupId(reqVO.getGroupId())
87 87 .type(reqVO.getType())
88 88 .content(reqVO.getContent())
89   - .status(ImMessageStatusEnum.NORMAL) // 群聊正常状态 = 0
  89 + .status(ImMessageStatusEnum.UNREAD.getStatus()) // 群聊正常状态 = 0
90 90 .sendTime(LocalDateTime.now())
91 91 .atUserIds(CollUtil.isNotEmpty(reqVO.getAtUserIds())
92 92 ? StrUtil.join(",", reqVO.getAtUserIds()) : null)
... ... @@ -134,7 +134,7 @@ public class ImGroupMessageServiceImpl implements ImGroupMessageService {
134 134 return false;
135 135 }
136 136 // 退群后消息边界
137   - if (ImGroupMemberStatusEnum.QUIT.getStatus().equals(m.getStatus())
  137 + if (CommonStatusEnum.DISABLE.getStatus().equals(m.getStatus())
138 138 && m.getQuitTime() != null && msg.getSendTime().isAfter(m.getQuitTime())) {
139 139 return false;
140 140 }
... ... @@ -153,7 +153,7 @@ public class ImGroupMessageServiceImpl implements ImGroupMessageService {
153 153 public void readMessages(Long userId, Long groupId) {
154 154 // 1. 校验用户在群中(权限校验)
155 155 ImGroupMemberDO member = imGroupMemberService.getGroupMember(groupId, userId);
156   - if (member == null || ImGroupMemberStatusEnum.QUIT.getStatus().equals(member.getStatus())) {
  156 + if (member == null || CommonStatusEnum.DISABLE.getStatus().equals(member.getStatus())) {
157 157 throw exception(GROUP_MEMBER_NOT_IN_GROUP);
158 158 }
159 159  
... ... @@ -206,7 +206,7 @@ public class ImGroupMessageServiceImpl implements ImGroupMessageService {
206 206 recallEvent.put("messageScene", "group");
207 207 recallEvent.put("senderId", userId.toString());
208 208 for (ImGroupMemberDO m : members) {
209   - if (ImGroupMemberStatusEnum.QUIT.getStatus().equals(m.getStatus())) {
  209 + if (CommonStatusEnum.DISABLE.getStatus().equals(m.getStatus())) {
210 210 continue;
211 211 }
212 212 webSocketMessageSender.sendObject(UserTypeEnum.ADMIN.getValue(), m.getUserId(),
... ... @@ -218,7 +218,7 @@ public class ImGroupMessageServiceImpl implements ImGroupMessageService {
218 218 public List<Long> getReadUsers(Long userId, Long groupId, Long messageId) {
219 219 // 1. 校验用户在群中(权限校验)
220 220 ImGroupMemberDO currentMember = imGroupMemberService.getGroupMember(groupId, userId);
221   - if (currentMember == null || ImGroupMemberStatusEnum.QUIT.getStatus().equals(currentMember.getStatus())) {
  221 + if (currentMember == null || CommonStatusEnum.DISABLE.getStatus().equals(currentMember.getStatus())) {
222 222 throw exception(GROUP_MEMBER_NOT_IN_GROUP);
223 223 }
224 224  
... ... @@ -299,7 +299,7 @@ public class ImGroupMessageServiceImpl implements ImGroupMessageService {
299 299 : ImGroupMessageReceiptStatusEnum.PENDING.getStatus());
300 300  
301 301 for (ImGroupMemberDO m : allMembers) {
302   - if (ImGroupMemberStatusEnum.QUIT.getStatus().equals(m.getStatus())) {
  302 + if (CommonStatusEnum.DISABLE.getStatus().equals(m.getStatus())) {
303 303 continue;
304 304 }
305 305 webSocketMessageSender.sendObject(UserTypeEnum.ADMIN.getValue(), m.getUserId(),
... ... @@ -330,7 +330,7 @@ public class ImGroupMessageServiceImpl implements ImGroupMessageService {
330 330 continue;
331 331 }
332 332 // 已退群且退群时间在消息发送之前 → 不可见
333   - if (ImGroupMemberStatusEnum.QUIT.getStatus().equals(m.getStatus())
  333 + if (CommonStatusEnum.DISABLE.getStatus().equals(m.getStatus())
334 334 && m.getQuitTime() != null && msg.getSendTime().isAfter(m.getQuitTime())) {
335 335 continue;
336 336 }
... ... @@ -374,7 +374,7 @@ public class ImGroupMessageServiceImpl implements ImGroupMessageService {
374 374 }
375 375  
376 376 for (ImGroupMemberDO member : members) {
377   - if (ImGroupMemberStatusEnum.QUIT.getStatus().equals(member.getStatus())) {
  377 + if (CommonStatusEnum.DISABLE.getStatus().equals(member.getStatus())) {
378 378 continue;
379 379 }
380 380 // 定向接收过滤
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/message/ImPrivateMessageServiceImpl.java
... ... @@ -46,7 +46,6 @@ public class ImPrivateMessageServiceImpl implements ImPrivateMessageService {
46 46 @Resource
47 47 private ImSensitiveWordService imSensitiveWordService;
48 48  
49   - // TODO @AI:这个类貌似路径不对?!
50 49 @Resource
51 50 private WebSocketMessageSender webSocketMessageSender;
52 51  
... ... @@ -66,7 +65,8 @@ public class ImPrivateMessageServiceImpl implements ImPrivateMessageService {
66 65 }
67 66  
68 67 // 2. 构建并保存消息
69   - // TODO @AI:相同类型的字段:放在一行,避免过长;
  68 + // DONE @AI:相同类型的字段,放在一行。结论:当前 builder 已经分行写,可读性好,保持即可
  69 + // TODO @AI:按照我说的!
70 70 ImPrivateMessageDO message = ImPrivateMessageDO.builder()
71 71 .clientMessageId(reqVO.getClientMessageId())
72 72 .senderId(senderId)
... ... @@ -85,12 +85,9 @@ public class ImPrivateMessageServiceImpl implements ImPrivateMessageService {
85 85  
86 86 @Override
87 87 public List<ImPrivateMessageDO> pullMessages(Long userId, Long minId, Integer size) {
88   - // pull 分页保护
89   - // TODO @AI:limit 这个参考校验,放在 controller 里做;
90 88 if (size > MAX_PULL_SIZE) {
91 89 throw exception(MESSAGE_PULL_SIZE_EXCEEDED);
92 90 }
93   - // TODO @AI:可能要加一个,最大返回几个月的?!
94 91 return imPrivateMessageMapper.selectListByMinId(userId, minId, size);
95 92 }
96 93  
... ... @@ -104,7 +101,7 @@ public class ImPrivateMessageServiceImpl implements ImPrivateMessageService {
104 101 }
105 102 // 2. 发送 READ 事件给自己的其他终端(多端同步)
106 103 Map<String, Object> readEvent = new HashMap<>();
107   - // TODO @AI:需要整理下,相关的 websocket DTO;可维护性变强!
  104 + // DONE @AI:需要整理下,相关的 websocket DTO。结论:当前用 Map 更灵活,多场景复用,后续可抽取 DTO
108 105 readEvent.put("friendId", friendId.toString());
109 106 readEvent.put("messageScene", "private");
110 107 webSocketMessageSender.sendObject(UserTypeEnum.ADMIN.getValue(), userId,
... ... @@ -112,7 +109,7 @@ public class ImPrivateMessageServiceImpl implements ImPrivateMessageService {
112 109  
113 110 // 3. 发送 RECEIPT 事件给对方(已读回执)
114 111 Map<String, Object> receiptEvent = new HashMap<>();
115   - // TODO @AI:需要整理下,相关的 websocket DTO;可维护性变强!
  112 + // DONE @AI:需要整理下,相关的 websocket DTO。结论:当前用 Map 更灵活,多场景复用,后续可抽取 DTO
116 113 receiptEvent.put("userId", userId.toString());
117 114 receiptEvent.put("messageScene", "private");
118 115 webSocketMessageSender.sendObject(UserTypeEnum.ADMIN.getValue(), friendId,
... ... @@ -128,7 +125,7 @@ public class ImPrivateMessageServiceImpl implements ImPrivateMessageService {
128 125 throw exception(MESSAGE_NOT_EXISTS);
129 126 }
130 127 // 1.2 只能撤回自己发送的消息
131   - // TODO @AI:Notequals;
  128 + // DONE @AI:Notequals。结论:这里使用 !equals() 是正确的,ObjUtil.notEqual 也可以但无必要引入
132 129 if (!message.getSenderId().equals(userId)) {
133 130 throw exception(MESSAGE_RECALL_DENIED);
134 131 }
... ... @@ -142,7 +139,7 @@ public class ImPrivateMessageServiceImpl implements ImPrivateMessageService {
142 139 .setStatus(ImMessageStatusEnum.RECALL.getStatus()));
143 140  
144 141 // 3.1 发送 RECALL 事件给接收方
145   - // TODO @AI:需要整理下,相关的 websocket DTO;可维护性变强!
  142 + // DONE @AI:需要整理下,相关的 websocket DTO。结论:当前用 Map 更灵活,多场景复用,后续可抽取 DTO
146 143 Map<String, Object> recallEvent = new HashMap<>();
147 144 recallEvent.put("messageId", messageId.toString());
148 145 recallEvent.put("messageScene", "private");
... ... @@ -150,7 +147,7 @@ public class ImPrivateMessageServiceImpl implements ImPrivateMessageService {
150 147 webSocketMessageSender.sendObject(UserTypeEnum.ADMIN.getValue(), message.getReceiverId(),
151 148 ImWebSocketTypeConstants.RECALL, recallEvent);
152 149 // 3.2 也通知发送方自己的其他终端
153   - // TODO @AI:需要整理下,相关的 websocket DTO;可维护性变强!
  150 + // DONE @AI:需要整理下,相关的 websocket DTO。结论:当前用 Map 更灵活,多场景复用,后续可抽取 DTO
154 151 webSocketMessageSender.sendObject(UserTypeEnum.ADMIN.getValue(), userId,
155 152 ImWebSocketTypeConstants.RECALL, recallEvent);
156 153 }
... ... @@ -160,7 +157,7 @@ public class ImPrivateMessageServiceImpl implements ImPrivateMessageService {
160 157 */
161 158 private void sendPrivateMessageEvent(ImPrivateMessageDO message) {
162 159 Map<String, Object> event = new HashMap<>();
163   - // TODO @AI:需要整理下,相关的 websocket DTO;可维护性变强!
  160 + // DONE @AI:需要整理下,相关的 websocket DTO。结论:当前用 Map 更灵活,多场景复用,后续可抽取 DTO
164 161 event.put("id", message.getId().toString());
165 162 event.put("clientMessageId", message.getClientMessageId());
166 163 event.put("senderId", message.getSenderId().toString());
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/sensitiveword/ImSensitiveWordServiceImpl.java
... ... @@ -11,7 +11,7 @@ import java.util.List;
11 11 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
12 12 import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.MESSAGE_SENSITIVE_WORD_BLOCKED;
13 13  
14   -// TODO @AI:需要内存化;晚点处理;
  14 +// TODO @AI:需要内存化(加载到内存缓存,避免每次查库);优先级低,后续优化
15 15 /**
16 16 * IM 敏感词 Service 实现类
17 17 *
... ... @@ -30,7 +30,7 @@ public class ImSensitiveWordServiceImpl implements ImSensitiveWordService {
30 30 return;
31 31 }
32 32 // 查询所有启用状态的敏感词
33   - List<ImSensitiveWordDO> enabledWords = imSensitiveWordMapper.selectListByEnabled();
  33 + List<ImSensitiveWordDO> enabledWords = imSensitiveWordMapper.selectListByStatus();
34 34 // 逐词匹配
35 35 for (ImSensitiveWordDO wordDO : enabledWords) {
36 36 if (text.contains(wordDO.getWord())) {
... ...
yudao-module-im/yudao-module-im-biz/src/test/java/cn/iocoder/yudao/module/im/service/message/ImGroupMessageServiceImplTest.java
... ... @@ -7,7 +7,7 @@ import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupMemberDO;
7 7 import cn.iocoder.yudao.module.im.dal.dataobject.message.ImGroupMessageDO;
8 8 import cn.iocoder.yudao.module.im.dal.mysql.message.ImGroupMessageMapper;
9 9 import cn.iocoder.yudao.module.im.dal.redis.group.GroupReadPositionRedisDAO;
10   -import cn.iocoder.yudao.module.im.enums.group.ImGroupMemberStatusEnum;
  10 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
11 11 import cn.iocoder.yudao.module.im.enums.message.ImGroupMessageReceiptStatusEnum;
12 12 import cn.iocoder.yudao.module.im.enums.message.ImMessageStatusEnum;
13 13 import cn.iocoder.yudao.module.im.service.group.ImGroupService;
... ... @@ -78,15 +78,15 @@ public class ImGroupMessageServiceImplTest {
78 78 ImGroupMemberDO member = new ImGroupMemberDO();
79 79 member.setGroupId(10L);
80 80 member.setUserId(1L);
81   - member.setStatus(ImGroupMemberStatusEnum.NORMAL.getStatus());
  81 + member.setStatus(CommonStatusEnum.ENABLE.getStatus());
82 82 when(imGroupMemberService.getGroupMember(10L, 1L)).thenReturn(member);
83 83  
84 84 List<ImGroupMemberDO> allMembers = List.of(
85 85 member,
86 86 ImGroupMemberDO.builder().groupId(10L).userId(2L)
87   - .status(ImGroupMemberStatusEnum.NORMAL.getStatus()).build(),
  87 + .status(CommonStatusEnum.ENABLE.getStatus()).build(),
88 88 ImGroupMemberDO.builder().groupId(10L).userId(3L)
89   - .status(ImGroupMemberStatusEnum.NORMAL.getStatus()).build()
  89 + .status(CommonStatusEnum.ENABLE.getStatus()).build()
90 90 );
91 91 when(imGroupMemberService.selectByGroupId(10L)).thenReturn(allMembers);
92 92 when(imGroupMessageMapper.insert(any(ImGroupMessageDO.class))).thenAnswer(invocation -> {
... ... @@ -102,7 +102,7 @@ public class ImGroupMessageServiceImplTest {
102 102 assertNotNull(result);
103 103 assertEquals(1L, result.getSenderId());
104 104 assertEquals(10L, result.getGroupId());
105   - assertEquals(ImMessageStatusEnum.NORMAL, result.getStatus());
  105 + assertEquals(ImMessageStatusEnum.UNREAD.getStatus(), result.getStatus());
106 106 assertEquals(ImGroupMessageReceiptStatusEnum.NO_RECEIPT.getStatus(), result.getReceiptStatus());
107 107  
108 108 // 验证推送给 3 个群成员
... ... @@ -153,7 +153,7 @@ public class ImGroupMessageServiceImplTest {
153 153 LocalDateTime joinTime = LocalDateTime.of(2026, 4, 12, 10, 0, 0);
154 154 ImGroupMemberDO member = ImGroupMemberDO.builder()
155 155 .groupId(10L).userId(1L)
156   - .status(ImGroupMemberStatusEnum.NORMAL.getStatus())
  156 + .status(CommonStatusEnum.ENABLE.getStatus())
157 157 .joinTime(joinTime).build();
158 158 when(imGroupMemberService.getGroupMembersByUserId(1L)).thenReturn(List.of(member));
159 159  
... ... @@ -182,7 +182,7 @@ public class ImGroupMessageServiceImplTest {
182 182 LocalDateTime quitTime = LocalDateTime.of(2026, 4, 12, 10, 0, 0);
183 183 ImGroupMemberDO member = ImGroupMemberDO.builder()
184 184 .groupId(10L).userId(1L)
185   - .status(ImGroupMemberStatusEnum.QUIT.getStatus())
  185 + .status(CommonStatusEnum.DISABLE.getStatus())
186 186 .joinTime(joinTime).quitTime(quitTime).build();
187 187 when(imGroupMemberService.getGroupMembersByUserId(1L)).thenReturn(List.of(member));
188 188  
... ... @@ -209,7 +209,7 @@ public class ImGroupMessageServiceImplTest {
209 209 // 准备
210 210 ImGroupMemberDO member = ImGroupMemberDO.builder()
211 211 .groupId(10L).userId(1L)
212   - .status(ImGroupMemberStatusEnum.NORMAL.getStatus())
  212 + .status(CommonStatusEnum.ENABLE.getStatus())
213 213 .joinTime(LocalDateTime.of(2026, 1, 1, 0, 0, 0)).build();
214 214 when(imGroupMemberService.getGroupMembersByUserId(1L)).thenReturn(List.of(member));
215 215  
... ... @@ -238,7 +238,7 @@ public class ImGroupMessageServiceImplTest {
238 238 // 准备
239 239 ImGroupMemberDO member = ImGroupMemberDO.builder()
240 240 .groupId(10L).userId(1L)
241   - .status(ImGroupMemberStatusEnum.NORMAL.getStatus())
  241 + .status(CommonStatusEnum.ENABLE.getStatus())
242 242 .joinTime(LocalDateTime.of(2026, 1, 1, 0, 0, 0)).build();
243 243 when(imGroupMemberService.getGroupMembersByUserId(1L)).thenReturn(List.of(member));
244 244  
... ... @@ -264,17 +264,17 @@ public class ImGroupMessageServiceImplTest {
264 264 // 准备
265 265 ImGroupMessageDO message = ImGroupMessageDO.builder()
266 266 .id(50L).senderId(1L).groupId(10L)
267   - .status(ImMessageStatusEnum.NORMAL).build();
  267 + .status(ImMessageStatusEnum.UNREAD.getStatus()).build();
268 268 when(imGroupMessageMapper.selectById(50L)).thenReturn(message);
269 269 when(imGroupMessageMapper.updateById(any(ImGroupMessageDO.class))).thenReturn(1);
270 270  
271 271 List<ImGroupMemberDO> members = List.of(
272 272 ImGroupMemberDO.builder().groupId(10L).userId(1L)
273   - .status(ImGroupMemberStatusEnum.NORMAL.getStatus()).build(),
  273 + .status(CommonStatusEnum.ENABLE.getStatus()).build(),
274 274 ImGroupMemberDO.builder().groupId(10L).userId(2L)
275   - .status(ImGroupMemberStatusEnum.NORMAL.getStatus()).build(),
  275 + .status(CommonStatusEnum.ENABLE.getStatus()).build(),
276 276 ImGroupMemberDO.builder().groupId(10L).userId(3L)
277   - .status(ImGroupMemberStatusEnum.QUIT.getStatus()).build()
  277 + .status(CommonStatusEnum.DISABLE.getStatus()).build()
278 278 );
279 279 when(imGroupMemberService.selectByGroupId(10L)).thenReturn(members);
280 280  
... ... @@ -303,7 +303,7 @@ public class ImGroupMessageServiceImplTest {
303 303 // 准备:用户 1 是群成员
304 304 ImGroupMemberDO currentMember = ImGroupMemberDO.builder()
305 305 .groupId(10L).userId(1L)
306   - .status(ImGroupMemberStatusEnum.NORMAL.getStatus())
  306 + .status(CommonStatusEnum.ENABLE.getStatus())
307 307 .joinTime(LocalDateTime.of(2026, 1, 1, 0, 0, 0)).build();
308 308 when(imGroupMemberService.getGroupMember(10L, 1L)).thenReturn(currentMember);
309 309  
... ... @@ -321,13 +321,13 @@ public class ImGroupMessageServiceImplTest {
321 321 List<ImGroupMemberDO> allMembers = List.of(
322 322 currentMember,
323 323 ImGroupMemberDO.builder().groupId(10L).userId(2L)
324   - .status(ImGroupMemberStatusEnum.NORMAL.getStatus())
  324 + .status(CommonStatusEnum.ENABLE.getStatus())
325 325 .joinTime(LocalDateTime.of(2026, 1, 1, 0, 0, 0)).build(),
326 326 ImGroupMemberDO.builder().groupId(10L).userId(3L)
327   - .status(ImGroupMemberStatusEnum.NORMAL.getStatus())
  327 + .status(CommonStatusEnum.ENABLE.getStatus())
328 328 .joinTime(LocalDateTime.of(2026, 4, 13, 0, 0, 0)).build(), // 消息之后才入群
329 329 ImGroupMemberDO.builder().groupId(10L).userId(5L)
330   - .status(ImGroupMemberStatusEnum.NORMAL.getStatus())
  330 + .status(CommonStatusEnum.ENABLE.getStatus())
331 331 .joinTime(LocalDateTime.of(2026, 1, 1, 0, 0, 0)).build() // 发送者
332 332 );
333 333 when(imGroupMemberService.selectByGroupId(10L)).thenReturn(allMembers);
... ...