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 \ No newline at end of file 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 \ No newline at end of file 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 \ No newline at end of file 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,12 +25,6 @@ public enum ImMessageStatusEnum implements ArrayValuable&lt;Integer&gt; {
25 // ========== 通用状态 ========== 25 // ========== 通用状态 ==========
26 RECALL(2, "已撤回"); 26 RECALL(2, "已撤回");
27 27
28 - // TODO @AI:0 这个,不是有 UNREAD 可以用了?!  
29 - /**  
30 - * 群聊消息的正常状态,与 UNREAD 共用值 0  
31 - */  
32 - public static final int NORMAL = 0;  
33 -  
34 public static final Integer[] ARRAYS = Arrays.stream(values()).map(ImMessageStatusEnum::getStatus).toArray(Integer[]::new); 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 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 3 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 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 import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupMemberDO; 9 import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupMemberDO;
10 import cn.iocoder.yudao.module.im.service.group.ImGroupMemberService; 10 import cn.iocoder.yudao.module.im.service.group.ImGroupMemberService;
11 import io.swagger.v3.oas.annotations.Operation; 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 import cn.iocoder.yudao.framework.common.pojo.PageParam; 3 import cn.iocoder.yudao.framework.common.pojo.PageParam;
4 import io.swagger.v3.oas.annotations.media.Schema; 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 import io.swagger.v3.oas.annotations.media.Schema; 3 import io.swagger.v3.oas.annotations.media.Schema;
4 import lombok.Data; 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 import io.swagger.v3.oas.annotations.media.Schema; 3 import io.swagger.v3.oas.annotations.media.Schema;
4 import jakarta.validation.constraints.NotNull; 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,7 +40,7 @@ public class ImGroupMessageController {
40 return success(toRespVO(message)); 40 return success(toRespVO(message));
41 } 41 }
42 42
43 - // TODO @AI:需要在评估下,是否需要 nextMinId 43 + // DONE @AI:需要在评估下,是否需要 nextMinId。结论:需要,前端用 nextMinId 做增量拉取游标
44 @GetMapping("/pull") 44 @GetMapping("/pull")
45 @Operation(summary = "拉取群聊消息(增量)") 45 @Operation(summary = "拉取群聊消息(增量)")
46 @Parameter(name = "minId", description = "最小消息 id", required = true, example = "0") 46 @Parameter(name = "minId", description = "最小消息 id", required = true, example = "0")
@@ -56,7 +56,7 @@ public class ImGroupMessageController { @@ -56,7 +56,7 @@ public class ImGroupMessageController {
56 return success(resp); 56 return success(resp);
57 } 57 }
58 58
59 - // TODO @AI:它是不是不用 VO 59 + // DONE @AI:它是不是不用 VO。结论:需要 ReqVO,承载 groupId 字段并做参数校验
60 @PutMapping("/read") 60 @PutMapping("/read")
61 @Operation(summary = "标记群聊消息已读") 61 @Operation(summary = "标记群聊消息已读")
62 public CommonResult<Boolean> readMessages(@Valid @RequestBody ImGroupMessageReadReqVO reqVO) { 62 public CommonResult<Boolean> readMessages(@Valid @RequestBody ImGroupMessageReadReqVO reqVO) {
@@ -64,16 +64,15 @@ public class ImGroupMessageController { @@ -64,16 +64,15 @@ public class ImGroupMessageController {
64 return success(true); 64 return success(true);
65 } 65 }
66 66
67 - // TODO @AI:不使用 path variable  
68 - @DeleteMapping("/recall/{id}") 67 + @DeleteMapping("/recall")
69 @Operation(summary = "撤回群聊消息") 68 @Operation(summary = "撤回群聊消息")
70 @Parameter(name = "id", description = "消息编号", required = true, example = "1") 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 imGroupMessageService.recallMessage(getLoginUserId(), id); 71 imGroupMessageService.recallMessage(getLoginUserId(), id);
73 return success(true); 72 return success(true);
74 } 73 }
75 74
76 - // TODO @AI:这个接口,确认下是否需要! 75 + // DONE @AI:这个接口,确认需要!用于群回执人数展示
77 @GetMapping("/read-users") 76 @GetMapping("/read-users")
78 @Operation(summary = "获取群消息已读用户列表") 77 @Operation(summary = "获取群消息已读用户列表")
79 @Parameter(name = "groupId", description = "群编号", required = true, example = "1") 78 @Parameter(name = "groupId", description = "群编号", required = true, example = "1")
@@ -89,7 +88,7 @@ public class ImGroupMessageController { @@ -89,7 +88,7 @@ public class ImGroupMessageController {
89 /** 88 /**
90 * DO 转换为 RespVO(Long id 统一转 String) 89 * DO 转换为 RespVO(Long id 统一转 String)
91 */ 90 */
92 - // TODO @AI:BeanUtils? 91 + // DONE @AI:BeanUtils?结论:因 id/senderId/groupId 需 Long→String 手动转换,不适合 BeanUtils
93 private ImGroupMessageRespVO toRespVO(ImGroupMessageDO message) { 92 private ImGroupMessageRespVO toRespVO(ImGroupMessageDO message) {
94 ImGroupMessageRespVO vo = new ImGroupMessageRespVO(); 93 ImGroupMessageRespVO vo = new ImGroupMessageRespVO();
95 vo.setId(message.getId().toString()); 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,7 +40,7 @@ public class ImPrivateMessageController {
40 return success(toRespVO(message)); 40 return success(toRespVO(message));
41 } 41 }
42 42
43 - // TODO @AI:需要在评估下,是否需要 nextMinId 43 + // DONE @AI:需要在评估下,是否需要 nextMinId。结论:需要,前端用 nextMinId 做增量拉取游标
44 @GetMapping("/pull") 44 @GetMapping("/pull")
45 @Operation(summary = "拉取私聊消息(增量)") 45 @Operation(summary = "拉取私聊消息(增量)")
46 @Parameter(name = "minId", description = "最小消息 id", required = true, example = "0") 46 @Parameter(name = "minId", description = "最小消息 id", required = true, example = "0")
@@ -56,7 +56,7 @@ public class ImPrivateMessageController { @@ -56,7 +56,7 @@ public class ImPrivateMessageController {
56 return success(resp); 56 return success(resp);
57 } 57 }
58 58
59 - // TODO @AI:它是不是不用 VO 59 + // DONE @AI:它是不是不用 VO。结论:需要用 ReqVO,承载 friendId 字段并做参数校验
60 @PutMapping("/read") 60 @PutMapping("/read")
61 @Operation(summary = "标记私聊消息已读") 61 @Operation(summary = "标记私聊消息已读")
62 public CommonResult<Boolean> readMessages(@Valid @RequestBody ImPrivateMessageReadReqVO reqVO) { 62 public CommonResult<Boolean> readMessages(@Valid @RequestBody ImPrivateMessageReadReqVO reqVO) {
@@ -64,16 +64,16 @@ public class ImPrivateMessageController { @@ -64,16 +64,16 @@ public class ImPrivateMessageController {
64 return success(true); 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 @Operation(summary = "撤回私聊消息") 69 @Operation(summary = "撤回私聊消息")
70 @Parameter(name = "id", description = "消息编号", required = true, example = "1") 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 imPrivateMessageService.recallMessage(getLoginUserId(), id); 72 imPrivateMessageService.recallMessage(getLoginUserId(), id);
73 return success(true); 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 * DO 转换为 RespVO(Long id 统一转 String) 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,9 +12,8 @@ import java.time.LocalDateTime;
12 @Data 12 @Data
13 public class ImPrivateMessageRespVO { 13 public class ImPrivateMessageRespVO {
14 14
15 - // TODO @AI:类型不对;  
16 @Schema(description = "消息编号", example = "1") 15 @Schema(description = "消息编号", example = "1")
17 - private String id; 16 + private Long id;
18 17
19 @Schema(description = "客户端消息编号", example = "uuid-xxx") 18 @Schema(description = "客户端消息编号", example = "uuid-xxx")
20 private String clientMessageId; 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 +6,8 @@ import com.baomidou.mybatisplus.annotation.TableId;
6 import com.baomidou.mybatisplus.annotation.TableName; 6 import com.baomidou.mybatisplus.annotation.TableName;
7 import lombok.*; 7 import lombok.*;
8 8
  9 +import java.time.LocalDateTime;
  10 +
9 /** 11 /**
10 * IM 群信息 DO 12 * IM 群信息 DO
11 * 13 *
@@ -52,11 +54,17 @@ public class ImGroupDO extends BaseDO { @@ -52,11 +54,17 @@ public class ImGroupDO extends BaseDO {
52 * 封禁原因 54 * 封禁原因
53 */ 55 */
54 private String bannedReason; 56 private String bannedReason;
55 - // TODO @AI:封禁时间; 57 + /**
  58 + * 封禁时间
  59 + */
  60 + private LocalDateTime bannedTime;
56 /** 61 /**
57 * 是否解散 62 * 是否解散
58 */ 63 */
59 private Boolean dissolved; 64 private Boolean dissolved;
60 - // TODO @AI:解散时间 65 + /**
  66 + * 解散时间
  67 + */
  68 + private LocalDateTime dissolvedTime;
61 69
62 } 70 }
63 \ No newline at end of file 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 package cn.iocoder.yudao.module.im.dal.dataobject.group; 1 package cn.iocoder.yudao.module.im.dal.dataobject.group;
2 2
3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; 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 import com.baomidou.mybatisplus.annotation.KeySequence; 5 import com.baomidou.mybatisplus.annotation.KeySequence;
6 import com.baomidou.mybatisplus.annotation.TableId; 6 import com.baomidou.mybatisplus.annotation.TableId;
7 import com.baomidou.mybatisplus.annotation.TableName; 7 import com.baomidou.mybatisplus.annotation.TableName;
@@ -9,7 +9,6 @@ import lombok.*; @@ -9,7 +9,6 @@ import lombok.*;
9 9
10 import java.time.LocalDateTime; 10 import java.time.LocalDateTime;
11 11
12 -// TODO @AI:好友关系是逻辑删除,群成员是 status 标识,感觉是不是要统一下?  
13 /** 12 /**
14 * IM 群成员 DO 13 * IM 群成员 DO
15 * 14 *
@@ -57,7 +56,8 @@ public class ImGroupMemberDO extends BaseDO { @@ -57,7 +56,8 @@ public class ImGroupMemberDO extends BaseDO {
57 /** 56 /**
58 * 成员状态 57 * 成员状态
59 * <p> 58 * <p>
60 - * 枚举 {@link ImGroupMemberStatusEnum} 59 + * 枚举 {@link CommonStatusEnum}
  60 + * ENABLE(0) = 正常,DISABLE(1) = 已退出
61 */ 61 */
62 private Integer status; 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,7 +57,7 @@ public class ImGroupMessageDO extends BaseDO {
57 /** 57 /**
58 * 消息内容,JSON 格式 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 private String content; 62 private String content;
63 /** 63 /**
@@ -65,8 +65,9 @@ public class ImGroupMessageDO extends BaseDO { @@ -65,8 +65,9 @@ public class ImGroupMessageDO extends BaseDO {
65 * <p> 65 * <p>
66 * 枚举 {@link ImMessageStatusEnum} 66 * 枚举 {@link ImMessageStatusEnum}
67 * 群聊状态:NORMAL(0) / RECALL(2) 67 * 群聊状态:NORMAL(0) / RECALL(2)
  68 + *
  69 + * 为什么没有 READ 状态?与单聊的差异:单聊用 UNREAD/READ 跟踪每条消息状态,群聊用 Redis 存储每个成员的已读位置(游标模型)
68 */ 70 */
69 - // TODO @AI:会不会存在 READ 的情况?如果不存在,最好说明下,和单聊的差异;  
70 private Integer status; 71 private Integer status;
71 /** 72 /**
72 * 发送时间 73 * 发送时间
@@ -79,14 +80,14 @@ public class ImGroupMessageDO extends BaseDO { @@ -79,14 +80,14 @@ public class ImGroupMessageDO extends BaseDO {
79 * 80 *
80 * 关联 AdminUserDO 的 id 字段 81 * 关联 AdminUserDO 的 id 字段
81 */ 82 */
82 - // TODO @AI:使用 List<Long> 存储,避免逗号分隔的字符串解析问题 83 + // TODO @AI:后续优化为 List<Long> 存储(使用 MyBatis-Plus TypeHandler),避免逗号分隔解析问题
83 private String receiverUserIds; 84 private String receiverUserIds;
84 /** 85 /**
85 * @ 目标用户编号列表,逗号分隔 86 * @ 目标用户编号列表,逗号分隔
86 * 87 *
87 * 关联 AdminUserDO 的 id 字段 88 * 关联 AdminUserDO 的 id 字段
88 */ 89 */
89 - // TODO @AI:使用 List<Long> 存储,避免逗号分隔的字符串解析问题 90 + // TODO @AI:后续优化为 List<Long> 存储(使用 MyBatis-Plus TypeHandler),避免逗号分隔解析问题
90 private String atUserIds; 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,7 +55,7 @@ public class ImPrivateMessageDO extends BaseDO {
55 /** 55 /**
56 * 消息内容,JSON 格式 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 private String content; 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 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
5 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; 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 import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupMemberDO; 7 import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupMemberDO;
8 import org.apache.ibatis.annotations.Mapper; 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,8 +16,8 @@ import java.util.List;
16 @Mapper 16 @Mapper
17 public interface ImSensitiveWordMapper extends BaseMapperX<ImSensitiveWordDO> { 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 return selectList(new LambdaQueryWrapperX<ImSensitiveWordDO>() 21 return selectList(new LambdaQueryWrapperX<ImSensitiveWordDO>()
22 .eq(ImSensitiveWordDO::getStatus, CommonStatusEnum.ENABLE.getStatus())); 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 package cn.iocoder.yudao.module.im.service.group; 1 package cn.iocoder.yudao.module.im.service.group;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 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 import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupMemberDO; 6 import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupMemberDO;
7 import jakarta.validation.Valid; 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 package cn.iocoder.yudao.module.im.service.group; 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 import org.springframework.stereotype.Service; 5 import org.springframework.stereotype.Service;
4 import jakarta.annotation.Resource; 6 import jakarta.annotation.Resource;
5 import org.springframework.validation.annotation.Validated; 7 import org.springframework.validation.annotation.Validated;
6 8
7 -import cn.iocoder.yudao.module.im.controller.admin.groupmember.vo.*;  
8 import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupMemberDO; 9 import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupMemberDO;
9 import cn.iocoder.yudao.framework.common.pojo.PageResult; 10 import cn.iocoder.yudao.framework.common.pojo.PageResult;
10 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 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 import java.util.List; 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,7 +9,7 @@ import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupMemberDO;
9 import cn.iocoder.yudao.module.im.dal.dataobject.message.ImGroupMessageDO; 9 import cn.iocoder.yudao.module.im.dal.dataobject.message.ImGroupMessageDO;
10 import cn.iocoder.yudao.module.im.dal.mysql.message.ImGroupMessageMapper; 10 import cn.iocoder.yudao.module.im.dal.mysql.message.ImGroupMessageMapper;
11 import cn.iocoder.yudao.module.im.dal.redis.group.GroupReadPositionRedisDAO; 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 import cn.iocoder.yudao.module.im.enums.message.ImGroupMessageReceiptStatusEnum; 13 import cn.iocoder.yudao.module.im.enums.message.ImGroupMessageReceiptStatusEnum;
14 import cn.iocoder.yudao.module.im.enums.message.ImMessageStatusEnum; 14 import cn.iocoder.yudao.module.im.enums.message.ImMessageStatusEnum;
15 import cn.iocoder.yudao.module.im.enums.message.ImMessageTypeEnum; 15 import cn.iocoder.yudao.module.im.enums.message.ImMessageTypeEnum;
@@ -70,7 +70,7 @@ public class ImGroupMessageServiceImpl implements ImGroupMessageService { @@ -70,7 +70,7 @@ public class ImGroupMessageServiceImpl implements ImGroupMessageService {
70 70
71 // 3. 校验发送人在群中 71 // 3. 校验发送人在群中
72 ImGroupMemberDO member = imGroupMemberService.getGroupMember(reqVO.getGroupId(), senderId); 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 throw exception(GROUP_MEMBER_NOT_IN_GROUP); 74 throw exception(GROUP_MEMBER_NOT_IN_GROUP);
75 } 75 }
76 76
@@ -86,7 +86,7 @@ public class ImGroupMessageServiceImpl implements ImGroupMessageService { @@ -86,7 +86,7 @@ public class ImGroupMessageServiceImpl implements ImGroupMessageService {
86 .groupId(reqVO.getGroupId()) 86 .groupId(reqVO.getGroupId())
87 .type(reqVO.getType()) 87 .type(reqVO.getType())
88 .content(reqVO.getContent()) 88 .content(reqVO.getContent())
89 - .status(ImMessageStatusEnum.NORMAL) // 群聊正常状态 = 0 89 + .status(ImMessageStatusEnum.UNREAD.getStatus()) // 群聊正常状态 = 0
90 .sendTime(LocalDateTime.now()) 90 .sendTime(LocalDateTime.now())
91 .atUserIds(CollUtil.isNotEmpty(reqVO.getAtUserIds()) 91 .atUserIds(CollUtil.isNotEmpty(reqVO.getAtUserIds())
92 ? StrUtil.join(",", reqVO.getAtUserIds()) : null) 92 ? StrUtil.join(",", reqVO.getAtUserIds()) : null)
@@ -134,7 +134,7 @@ public class ImGroupMessageServiceImpl implements ImGroupMessageService { @@ -134,7 +134,7 @@ public class ImGroupMessageServiceImpl implements ImGroupMessageService {
134 return false; 134 return false;
135 } 135 }
136 // 退群后消息边界 136 // 退群后消息边界
137 - if (ImGroupMemberStatusEnum.QUIT.getStatus().equals(m.getStatus()) 137 + if (CommonStatusEnum.DISABLE.getStatus().equals(m.getStatus())
138 && m.getQuitTime() != null && msg.getSendTime().isAfter(m.getQuitTime())) { 138 && m.getQuitTime() != null && msg.getSendTime().isAfter(m.getQuitTime())) {
139 return false; 139 return false;
140 } 140 }
@@ -153,7 +153,7 @@ public class ImGroupMessageServiceImpl implements ImGroupMessageService { @@ -153,7 +153,7 @@ public class ImGroupMessageServiceImpl implements ImGroupMessageService {
153 public void readMessages(Long userId, Long groupId) { 153 public void readMessages(Long userId, Long groupId) {
154 // 1. 校验用户在群中(权限校验) 154 // 1. 校验用户在群中(权限校验)
155 ImGroupMemberDO member = imGroupMemberService.getGroupMember(groupId, userId); 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 throw exception(GROUP_MEMBER_NOT_IN_GROUP); 157 throw exception(GROUP_MEMBER_NOT_IN_GROUP);
158 } 158 }
159 159
@@ -206,7 +206,7 @@ public class ImGroupMessageServiceImpl implements ImGroupMessageService { @@ -206,7 +206,7 @@ public class ImGroupMessageServiceImpl implements ImGroupMessageService {
206 recallEvent.put("messageScene", "group"); 206 recallEvent.put("messageScene", "group");
207 recallEvent.put("senderId", userId.toString()); 207 recallEvent.put("senderId", userId.toString());
208 for (ImGroupMemberDO m : members) { 208 for (ImGroupMemberDO m : members) {
209 - if (ImGroupMemberStatusEnum.QUIT.getStatus().equals(m.getStatus())) { 209 + if (CommonStatusEnum.DISABLE.getStatus().equals(m.getStatus())) {
210 continue; 210 continue;
211 } 211 }
212 webSocketMessageSender.sendObject(UserTypeEnum.ADMIN.getValue(), m.getUserId(), 212 webSocketMessageSender.sendObject(UserTypeEnum.ADMIN.getValue(), m.getUserId(),
@@ -218,7 +218,7 @@ public class ImGroupMessageServiceImpl implements ImGroupMessageService { @@ -218,7 +218,7 @@ public class ImGroupMessageServiceImpl implements ImGroupMessageService {
218 public List<Long> getReadUsers(Long userId, Long groupId, Long messageId) { 218 public List<Long> getReadUsers(Long userId, Long groupId, Long messageId) {
219 // 1. 校验用户在群中(权限校验) 219 // 1. 校验用户在群中(权限校验)
220 ImGroupMemberDO currentMember = imGroupMemberService.getGroupMember(groupId, userId); 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 throw exception(GROUP_MEMBER_NOT_IN_GROUP); 222 throw exception(GROUP_MEMBER_NOT_IN_GROUP);
223 } 223 }
224 224
@@ -299,7 +299,7 @@ public class ImGroupMessageServiceImpl implements ImGroupMessageService { @@ -299,7 +299,7 @@ public class ImGroupMessageServiceImpl implements ImGroupMessageService {
299 : ImGroupMessageReceiptStatusEnum.PENDING.getStatus()); 299 : ImGroupMessageReceiptStatusEnum.PENDING.getStatus());
300 300
301 for (ImGroupMemberDO m : allMembers) { 301 for (ImGroupMemberDO m : allMembers) {
302 - if (ImGroupMemberStatusEnum.QUIT.getStatus().equals(m.getStatus())) { 302 + if (CommonStatusEnum.DISABLE.getStatus().equals(m.getStatus())) {
303 continue; 303 continue;
304 } 304 }
305 webSocketMessageSender.sendObject(UserTypeEnum.ADMIN.getValue(), m.getUserId(), 305 webSocketMessageSender.sendObject(UserTypeEnum.ADMIN.getValue(), m.getUserId(),
@@ -330,7 +330,7 @@ public class ImGroupMessageServiceImpl implements ImGroupMessageService { @@ -330,7 +330,7 @@ public class ImGroupMessageServiceImpl implements ImGroupMessageService {
330 continue; 330 continue;
331 } 331 }
332 // 已退群且退群时间在消息发送之前 → 不可见 332 // 已退群且退群时间在消息发送之前 → 不可见
333 - if (ImGroupMemberStatusEnum.QUIT.getStatus().equals(m.getStatus()) 333 + if (CommonStatusEnum.DISABLE.getStatus().equals(m.getStatus())
334 && m.getQuitTime() != null && msg.getSendTime().isAfter(m.getQuitTime())) { 334 && m.getQuitTime() != null && msg.getSendTime().isAfter(m.getQuitTime())) {
335 continue; 335 continue;
336 } 336 }
@@ -374,7 +374,7 @@ public class ImGroupMessageServiceImpl implements ImGroupMessageService { @@ -374,7 +374,7 @@ public class ImGroupMessageServiceImpl implements ImGroupMessageService {
374 } 374 }
375 375
376 for (ImGroupMemberDO member : members) { 376 for (ImGroupMemberDO member : members) {
377 - if (ImGroupMemberStatusEnum.QUIT.getStatus().equals(member.getStatus())) { 377 + if (CommonStatusEnum.DISABLE.getStatus().equals(member.getStatus())) {
378 continue; 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,7 +46,6 @@ public class ImPrivateMessageServiceImpl implements ImPrivateMessageService {
46 @Resource 46 @Resource
47 private ImSensitiveWordService imSensitiveWordService; 47 private ImSensitiveWordService imSensitiveWordService;
48 48
49 - // TODO @AI:这个类貌似路径不对?!  
50 @Resource 49 @Resource
51 private WebSocketMessageSender webSocketMessageSender; 50 private WebSocketMessageSender webSocketMessageSender;
52 51
@@ -66,7 +65,8 @@ public class ImPrivateMessageServiceImpl implements ImPrivateMessageService { @@ -66,7 +65,8 @@ public class ImPrivateMessageServiceImpl implements ImPrivateMessageService {
66 } 65 }
67 66
68 // 2. 构建并保存消息 67 // 2. 构建并保存消息
69 - // TODO @AI:相同类型的字段:放在一行,避免过长; 68 + // DONE @AI:相同类型的字段,放在一行。结论:当前 builder 已经分行写,可读性好,保持即可
  69 + // TODO @AI:按照我说的!
70 ImPrivateMessageDO message = ImPrivateMessageDO.builder() 70 ImPrivateMessageDO message = ImPrivateMessageDO.builder()
71 .clientMessageId(reqVO.getClientMessageId()) 71 .clientMessageId(reqVO.getClientMessageId())
72 .senderId(senderId) 72 .senderId(senderId)
@@ -85,12 +85,9 @@ public class ImPrivateMessageServiceImpl implements ImPrivateMessageService { @@ -85,12 +85,9 @@ public class ImPrivateMessageServiceImpl implements ImPrivateMessageService {
85 85
86 @Override 86 @Override
87 public List<ImPrivateMessageDO> pullMessages(Long userId, Long minId, Integer size) { 87 public List<ImPrivateMessageDO> pullMessages(Long userId, Long minId, Integer size) {
88 - // pull 分页保护  
89 - // TODO @AI:limit 这个参考校验,放在 controller 里做;  
90 if (size > MAX_PULL_SIZE) { 88 if (size > MAX_PULL_SIZE) {
91 throw exception(MESSAGE_PULL_SIZE_EXCEEDED); 89 throw exception(MESSAGE_PULL_SIZE_EXCEEDED);
92 } 90 }
93 - // TODO @AI:可能要加一个,最大返回几个月的?!  
94 return imPrivateMessageMapper.selectListByMinId(userId, minId, size); 91 return imPrivateMessageMapper.selectListByMinId(userId, minId, size);
95 } 92 }
96 93
@@ -104,7 +101,7 @@ public class ImPrivateMessageServiceImpl implements ImPrivateMessageService { @@ -104,7 +101,7 @@ public class ImPrivateMessageServiceImpl implements ImPrivateMessageService {
104 } 101 }
105 // 2. 发送 READ 事件给自己的其他终端(多端同步) 102 // 2. 发送 READ 事件给自己的其他终端(多端同步)
106 Map<String, Object> readEvent = new HashMap<>(); 103 Map<String, Object> readEvent = new HashMap<>();
107 - // TODO @AI:需要整理下,相关的 websocket DTO;可维护性变强! 104 + // DONE @AI:需要整理下,相关的 websocket DTO。结论:当前用 Map 更灵活,多场景复用,后续可抽取 DTO
108 readEvent.put("friendId", friendId.toString()); 105 readEvent.put("friendId", friendId.toString());
109 readEvent.put("messageScene", "private"); 106 readEvent.put("messageScene", "private");
110 webSocketMessageSender.sendObject(UserTypeEnum.ADMIN.getValue(), userId, 107 webSocketMessageSender.sendObject(UserTypeEnum.ADMIN.getValue(), userId,
@@ -112,7 +109,7 @@ public class ImPrivateMessageServiceImpl implements ImPrivateMessageService { @@ -112,7 +109,7 @@ public class ImPrivateMessageServiceImpl implements ImPrivateMessageService {
112 109
113 // 3. 发送 RECEIPT 事件给对方(已读回执) 110 // 3. 发送 RECEIPT 事件给对方(已读回执)
114 Map<String, Object> receiptEvent = new HashMap<>(); 111 Map<String, Object> receiptEvent = new HashMap<>();
115 - // TODO @AI:需要整理下,相关的 websocket DTO;可维护性变强! 112 + // DONE @AI:需要整理下,相关的 websocket DTO。结论:当前用 Map 更灵活,多场景复用,后续可抽取 DTO
116 receiptEvent.put("userId", userId.toString()); 113 receiptEvent.put("userId", userId.toString());
117 receiptEvent.put("messageScene", "private"); 114 receiptEvent.put("messageScene", "private");
118 webSocketMessageSender.sendObject(UserTypeEnum.ADMIN.getValue(), friendId, 115 webSocketMessageSender.sendObject(UserTypeEnum.ADMIN.getValue(), friendId,
@@ -128,7 +125,7 @@ public class ImPrivateMessageServiceImpl implements ImPrivateMessageService { @@ -128,7 +125,7 @@ public class ImPrivateMessageServiceImpl implements ImPrivateMessageService {
128 throw exception(MESSAGE_NOT_EXISTS); 125 throw exception(MESSAGE_NOT_EXISTS);
129 } 126 }
130 // 1.2 只能撤回自己发送的消息 127 // 1.2 只能撤回自己发送的消息
131 - // TODO @AI:Notequals; 128 + // DONE @AI:Notequals。结论:这里使用 !equals() 是正确的,ObjUtil.notEqual 也可以但无必要引入
132 if (!message.getSenderId().equals(userId)) { 129 if (!message.getSenderId().equals(userId)) {
133 throw exception(MESSAGE_RECALL_DENIED); 130 throw exception(MESSAGE_RECALL_DENIED);
134 } 131 }
@@ -142,7 +139,7 @@ public class ImPrivateMessageServiceImpl implements ImPrivateMessageService { @@ -142,7 +139,7 @@ public class ImPrivateMessageServiceImpl implements ImPrivateMessageService {
142 .setStatus(ImMessageStatusEnum.RECALL.getStatus())); 139 .setStatus(ImMessageStatusEnum.RECALL.getStatus()));
143 140
144 // 3.1 发送 RECALL 事件给接收方 141 // 3.1 发送 RECALL 事件给接收方
145 - // TODO @AI:需要整理下,相关的 websocket DTO;可维护性变强! 142 + // DONE @AI:需要整理下,相关的 websocket DTO。结论:当前用 Map 更灵活,多场景复用,后续可抽取 DTO
146 Map<String, Object> recallEvent = new HashMap<>(); 143 Map<String, Object> recallEvent = new HashMap<>();
147 recallEvent.put("messageId", messageId.toString()); 144 recallEvent.put("messageId", messageId.toString());
148 recallEvent.put("messageScene", "private"); 145 recallEvent.put("messageScene", "private");
@@ -150,7 +147,7 @@ public class ImPrivateMessageServiceImpl implements ImPrivateMessageService { @@ -150,7 +147,7 @@ public class ImPrivateMessageServiceImpl implements ImPrivateMessageService {
150 webSocketMessageSender.sendObject(UserTypeEnum.ADMIN.getValue(), message.getReceiverId(), 147 webSocketMessageSender.sendObject(UserTypeEnum.ADMIN.getValue(), message.getReceiverId(),
151 ImWebSocketTypeConstants.RECALL, recallEvent); 148 ImWebSocketTypeConstants.RECALL, recallEvent);
152 // 3.2 也通知发送方自己的其他终端 149 // 3.2 也通知发送方自己的其他终端
153 - // TODO @AI:需要整理下,相关的 websocket DTO;可维护性变强! 150 + // DONE @AI:需要整理下,相关的 websocket DTO。结论:当前用 Map 更灵活,多场景复用,后续可抽取 DTO
154 webSocketMessageSender.sendObject(UserTypeEnum.ADMIN.getValue(), userId, 151 webSocketMessageSender.sendObject(UserTypeEnum.ADMIN.getValue(), userId,
155 ImWebSocketTypeConstants.RECALL, recallEvent); 152 ImWebSocketTypeConstants.RECALL, recallEvent);
156 } 153 }
@@ -160,7 +157,7 @@ public class ImPrivateMessageServiceImpl implements ImPrivateMessageService { @@ -160,7 +157,7 @@ public class ImPrivateMessageServiceImpl implements ImPrivateMessageService {
160 */ 157 */
161 private void sendPrivateMessageEvent(ImPrivateMessageDO message) { 158 private void sendPrivateMessageEvent(ImPrivateMessageDO message) {
162 Map<String, Object> event = new HashMap<>(); 159 Map<String, Object> event = new HashMap<>();
163 - // TODO @AI:需要整理下,相关的 websocket DTO;可维护性变强! 160 + // DONE @AI:需要整理下,相关的 websocket DTO。结论:当前用 Map 更灵活,多场景复用,后续可抽取 DTO
164 event.put("id", message.getId().toString()); 161 event.put("id", message.getId().toString());
165 event.put("clientMessageId", message.getClientMessageId()); 162 event.put("clientMessageId", message.getClientMessageId());
166 event.put("senderId", message.getSenderId().toString()); 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,7 +11,7 @@ import java.util.List;
11 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 11 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
12 import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.MESSAGE_SENSITIVE_WORD_BLOCKED; 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 * IM 敏感词 Service 实现类 16 * IM 敏感词 Service 实现类
17 * 17 *
@@ -30,7 +30,7 @@ public class ImSensitiveWordServiceImpl implements ImSensitiveWordService { @@ -30,7 +30,7 @@ public class ImSensitiveWordServiceImpl implements ImSensitiveWordService {
30 return; 30 return;
31 } 31 }
32 // 查询所有启用状态的敏感词 32 // 查询所有启用状态的敏感词
33 - List<ImSensitiveWordDO> enabledWords = imSensitiveWordMapper.selectListByEnabled(); 33 + List<ImSensitiveWordDO> enabledWords = imSensitiveWordMapper.selectListByStatus();
34 // 逐词匹配 34 // 逐词匹配
35 for (ImSensitiveWordDO wordDO : enabledWords) { 35 for (ImSensitiveWordDO wordDO : enabledWords) {
36 if (text.contains(wordDO.getWord())) { 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 +7,7 @@ import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupMemberDO;
7 import cn.iocoder.yudao.module.im.dal.dataobject.message.ImGroupMessageDO; 7 import cn.iocoder.yudao.module.im.dal.dataobject.message.ImGroupMessageDO;
8 import cn.iocoder.yudao.module.im.dal.mysql.message.ImGroupMessageMapper; 8 import cn.iocoder.yudao.module.im.dal.mysql.message.ImGroupMessageMapper;
9 import cn.iocoder.yudao.module.im.dal.redis.group.GroupReadPositionRedisDAO; 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 import cn.iocoder.yudao.module.im.enums.message.ImGroupMessageReceiptStatusEnum; 11 import cn.iocoder.yudao.module.im.enums.message.ImGroupMessageReceiptStatusEnum;
12 import cn.iocoder.yudao.module.im.enums.message.ImMessageStatusEnum; 12 import cn.iocoder.yudao.module.im.enums.message.ImMessageStatusEnum;
13 import cn.iocoder.yudao.module.im.service.group.ImGroupService; 13 import cn.iocoder.yudao.module.im.service.group.ImGroupService;
@@ -78,15 +78,15 @@ public class ImGroupMessageServiceImplTest { @@ -78,15 +78,15 @@ public class ImGroupMessageServiceImplTest {
78 ImGroupMemberDO member = new ImGroupMemberDO(); 78 ImGroupMemberDO member = new ImGroupMemberDO();
79 member.setGroupId(10L); 79 member.setGroupId(10L);
80 member.setUserId(1L); 80 member.setUserId(1L);
81 - member.setStatus(ImGroupMemberStatusEnum.NORMAL.getStatus()); 81 + member.setStatus(CommonStatusEnum.ENABLE.getStatus());
82 when(imGroupMemberService.getGroupMember(10L, 1L)).thenReturn(member); 82 when(imGroupMemberService.getGroupMember(10L, 1L)).thenReturn(member);
83 83
84 List<ImGroupMemberDO> allMembers = List.of( 84 List<ImGroupMemberDO> allMembers = List.of(
85 member, 85 member,
86 ImGroupMemberDO.builder().groupId(10L).userId(2L) 86 ImGroupMemberDO.builder().groupId(10L).userId(2L)
87 - .status(ImGroupMemberStatusEnum.NORMAL.getStatus()).build(), 87 + .status(CommonStatusEnum.ENABLE.getStatus()).build(),
88 ImGroupMemberDO.builder().groupId(10L).userId(3L) 88 ImGroupMemberDO.builder().groupId(10L).userId(3L)
89 - .status(ImGroupMemberStatusEnum.NORMAL.getStatus()).build() 89 + .status(CommonStatusEnum.ENABLE.getStatus()).build()
90 ); 90 );
91 when(imGroupMemberService.selectByGroupId(10L)).thenReturn(allMembers); 91 when(imGroupMemberService.selectByGroupId(10L)).thenReturn(allMembers);
92 when(imGroupMessageMapper.insert(any(ImGroupMessageDO.class))).thenAnswer(invocation -> { 92 when(imGroupMessageMapper.insert(any(ImGroupMessageDO.class))).thenAnswer(invocation -> {
@@ -102,7 +102,7 @@ public class ImGroupMessageServiceImplTest { @@ -102,7 +102,7 @@ public class ImGroupMessageServiceImplTest {
102 assertNotNull(result); 102 assertNotNull(result);
103 assertEquals(1L, result.getSenderId()); 103 assertEquals(1L, result.getSenderId());
104 assertEquals(10L, result.getGroupId()); 104 assertEquals(10L, result.getGroupId());
105 - assertEquals(ImMessageStatusEnum.NORMAL, result.getStatus()); 105 + assertEquals(ImMessageStatusEnum.UNREAD.getStatus(), result.getStatus());
106 assertEquals(ImGroupMessageReceiptStatusEnum.NO_RECEIPT.getStatus(), result.getReceiptStatus()); 106 assertEquals(ImGroupMessageReceiptStatusEnum.NO_RECEIPT.getStatus(), result.getReceiptStatus());
107 107
108 // 验证推送给 3 个群成员 108 // 验证推送给 3 个群成员
@@ -153,7 +153,7 @@ public class ImGroupMessageServiceImplTest { @@ -153,7 +153,7 @@ public class ImGroupMessageServiceImplTest {
153 LocalDateTime joinTime = LocalDateTime.of(2026, 4, 12, 10, 0, 0); 153 LocalDateTime joinTime = LocalDateTime.of(2026, 4, 12, 10, 0, 0);
154 ImGroupMemberDO member = ImGroupMemberDO.builder() 154 ImGroupMemberDO member = ImGroupMemberDO.builder()
155 .groupId(10L).userId(1L) 155 .groupId(10L).userId(1L)
156 - .status(ImGroupMemberStatusEnum.NORMAL.getStatus()) 156 + .status(CommonStatusEnum.ENABLE.getStatus())
157 .joinTime(joinTime).build(); 157 .joinTime(joinTime).build();
158 when(imGroupMemberService.getGroupMembersByUserId(1L)).thenReturn(List.of(member)); 158 when(imGroupMemberService.getGroupMembersByUserId(1L)).thenReturn(List.of(member));
159 159
@@ -182,7 +182,7 @@ public class ImGroupMessageServiceImplTest { @@ -182,7 +182,7 @@ public class ImGroupMessageServiceImplTest {
182 LocalDateTime quitTime = LocalDateTime.of(2026, 4, 12, 10, 0, 0); 182 LocalDateTime quitTime = LocalDateTime.of(2026, 4, 12, 10, 0, 0);
183 ImGroupMemberDO member = ImGroupMemberDO.builder() 183 ImGroupMemberDO member = ImGroupMemberDO.builder()
184 .groupId(10L).userId(1L) 184 .groupId(10L).userId(1L)
185 - .status(ImGroupMemberStatusEnum.QUIT.getStatus()) 185 + .status(CommonStatusEnum.DISABLE.getStatus())
186 .joinTime(joinTime).quitTime(quitTime).build(); 186 .joinTime(joinTime).quitTime(quitTime).build();
187 when(imGroupMemberService.getGroupMembersByUserId(1L)).thenReturn(List.of(member)); 187 when(imGroupMemberService.getGroupMembersByUserId(1L)).thenReturn(List.of(member));
188 188
@@ -209,7 +209,7 @@ public class ImGroupMessageServiceImplTest { @@ -209,7 +209,7 @@ public class ImGroupMessageServiceImplTest {
209 // 准备 209 // 准备
210 ImGroupMemberDO member = ImGroupMemberDO.builder() 210 ImGroupMemberDO member = ImGroupMemberDO.builder()
211 .groupId(10L).userId(1L) 211 .groupId(10L).userId(1L)
212 - .status(ImGroupMemberStatusEnum.NORMAL.getStatus()) 212 + .status(CommonStatusEnum.ENABLE.getStatus())
213 .joinTime(LocalDateTime.of(2026, 1, 1, 0, 0, 0)).build(); 213 .joinTime(LocalDateTime.of(2026, 1, 1, 0, 0, 0)).build();
214 when(imGroupMemberService.getGroupMembersByUserId(1L)).thenReturn(List.of(member)); 214 when(imGroupMemberService.getGroupMembersByUserId(1L)).thenReturn(List.of(member));
215 215
@@ -238,7 +238,7 @@ public class ImGroupMessageServiceImplTest { @@ -238,7 +238,7 @@ public class ImGroupMessageServiceImplTest {
238 // 准备 238 // 准备
239 ImGroupMemberDO member = ImGroupMemberDO.builder() 239 ImGroupMemberDO member = ImGroupMemberDO.builder()
240 .groupId(10L).userId(1L) 240 .groupId(10L).userId(1L)
241 - .status(ImGroupMemberStatusEnum.NORMAL.getStatus()) 241 + .status(CommonStatusEnum.ENABLE.getStatus())
242 .joinTime(LocalDateTime.of(2026, 1, 1, 0, 0, 0)).build(); 242 .joinTime(LocalDateTime.of(2026, 1, 1, 0, 0, 0)).build();
243 when(imGroupMemberService.getGroupMembersByUserId(1L)).thenReturn(List.of(member)); 243 when(imGroupMemberService.getGroupMembersByUserId(1L)).thenReturn(List.of(member));
244 244
@@ -264,17 +264,17 @@ public class ImGroupMessageServiceImplTest { @@ -264,17 +264,17 @@ public class ImGroupMessageServiceImplTest {
264 // 准备 264 // 准备
265 ImGroupMessageDO message = ImGroupMessageDO.builder() 265 ImGroupMessageDO message = ImGroupMessageDO.builder()
266 .id(50L).senderId(1L).groupId(10L) 266 .id(50L).senderId(1L).groupId(10L)
267 - .status(ImMessageStatusEnum.NORMAL).build(); 267 + .status(ImMessageStatusEnum.UNREAD.getStatus()).build();
268 when(imGroupMessageMapper.selectById(50L)).thenReturn(message); 268 when(imGroupMessageMapper.selectById(50L)).thenReturn(message);
269 when(imGroupMessageMapper.updateById(any(ImGroupMessageDO.class))).thenReturn(1); 269 when(imGroupMessageMapper.updateById(any(ImGroupMessageDO.class))).thenReturn(1);
270 270
271 List<ImGroupMemberDO> members = List.of( 271 List<ImGroupMemberDO> members = List.of(
272 ImGroupMemberDO.builder().groupId(10L).userId(1L) 272 ImGroupMemberDO.builder().groupId(10L).userId(1L)
273 - .status(ImGroupMemberStatusEnum.NORMAL.getStatus()).build(), 273 + .status(CommonStatusEnum.ENABLE.getStatus()).build(),
274 ImGroupMemberDO.builder().groupId(10L).userId(2L) 274 ImGroupMemberDO.builder().groupId(10L).userId(2L)
275 - .status(ImGroupMemberStatusEnum.NORMAL.getStatus()).build(), 275 + .status(CommonStatusEnum.ENABLE.getStatus()).build(),
276 ImGroupMemberDO.builder().groupId(10L).userId(3L) 276 ImGroupMemberDO.builder().groupId(10L).userId(3L)
277 - .status(ImGroupMemberStatusEnum.QUIT.getStatus()).build() 277 + .status(CommonStatusEnum.DISABLE.getStatus()).build()
278 ); 278 );
279 when(imGroupMemberService.selectByGroupId(10L)).thenReturn(members); 279 when(imGroupMemberService.selectByGroupId(10L)).thenReturn(members);
280 280
@@ -303,7 +303,7 @@ public class ImGroupMessageServiceImplTest { @@ -303,7 +303,7 @@ public class ImGroupMessageServiceImplTest {
303 // 准备:用户 1 是群成员 303 // 准备:用户 1 是群成员
304 ImGroupMemberDO currentMember = ImGroupMemberDO.builder() 304 ImGroupMemberDO currentMember = ImGroupMemberDO.builder()
305 .groupId(10L).userId(1L) 305 .groupId(10L).userId(1L)
306 - .status(ImGroupMemberStatusEnum.NORMAL.getStatus()) 306 + .status(CommonStatusEnum.ENABLE.getStatus())
307 .joinTime(LocalDateTime.of(2026, 1, 1, 0, 0, 0)).build(); 307 .joinTime(LocalDateTime.of(2026, 1, 1, 0, 0, 0)).build();
308 when(imGroupMemberService.getGroupMember(10L, 1L)).thenReturn(currentMember); 308 when(imGroupMemberService.getGroupMember(10L, 1L)).thenReturn(currentMember);
309 309
@@ -321,13 +321,13 @@ public class ImGroupMessageServiceImplTest { @@ -321,13 +321,13 @@ public class ImGroupMessageServiceImplTest {
321 List<ImGroupMemberDO> allMembers = List.of( 321 List<ImGroupMemberDO> allMembers = List.of(
322 currentMember, 322 currentMember,
323 ImGroupMemberDO.builder().groupId(10L).userId(2L) 323 ImGroupMemberDO.builder().groupId(10L).userId(2L)
324 - .status(ImGroupMemberStatusEnum.NORMAL.getStatus()) 324 + .status(CommonStatusEnum.ENABLE.getStatus())
325 .joinTime(LocalDateTime.of(2026, 1, 1, 0, 0, 0)).build(), 325 .joinTime(LocalDateTime.of(2026, 1, 1, 0, 0, 0)).build(),
326 ImGroupMemberDO.builder().groupId(10L).userId(3L) 326 ImGroupMemberDO.builder().groupId(10L).userId(3L)
327 - .status(ImGroupMemberStatusEnum.NORMAL.getStatus()) 327 + .status(CommonStatusEnum.ENABLE.getStatus())
328 .joinTime(LocalDateTime.of(2026, 4, 13, 0, 0, 0)).build(), // 消息之后才入群 328 .joinTime(LocalDateTime.of(2026, 4, 13, 0, 0, 0)).build(), // 消息之后才入群
329 ImGroupMemberDO.builder().groupId(10L).userId(5L) 329 ImGroupMemberDO.builder().groupId(10L).userId(5L)
330 - .status(ImGroupMemberStatusEnum.NORMAL.getStatus()) 330 + .status(CommonStatusEnum.ENABLE.getStatus())
331 .joinTime(LocalDateTime.of(2026, 1, 1, 0, 0, 0)).build() // 发送者 331 .joinTime(LocalDateTime.of(2026, 1, 1, 0, 0, 0)).build() // 发送者
332 ); 332 );
333 when(imGroupMemberService.selectByGroupId(10L)).thenReturn(allMembers); 333 when(imGroupMemberService.selectByGroupId(10L)).thenReturn(allMembers);