lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(ImMessage::getTalkId, talkId);
- if (CharSequenceUtil.isNotEmpty(lastMessageId)) {
- lambdaQueryWrapper.lt(ImMessage::getId, lastMessageId);
+ if (CharSequenceUtil.isNotEmpty(earliestMsgId)) {
+ lambdaQueryWrapper.ge(ImMessage::getId, earliestMsgId);
+ }
+ if (CharSequenceUtil.isNotEmpty(latestMsgId)) {
+ lambdaQueryWrapper.le(ImMessage::getId, latestMsgId);
}
lambdaQueryWrapper.orderByDesc(ImMessage::getCreateTime);
// lambdaQueryWrapper.last("limit " + num);
diff --git a/framework/src/main/java/cn/lili/modules/im/entity/enums/MessageStatusEnum.java b/framework/src/main/java/cn/lili/modules/im/entity/enums/MessageStatusEnum.java
index 687c814c..b727f9ff 100644
--- a/framework/src/main/java/cn/lili/modules/im/entity/enums/MessageStatusEnum.java
+++ b/framework/src/main/java/cn/lili/modules/im/entity/enums/MessageStatusEnum.java
@@ -1,31 +1,53 @@
package cn.lili.modules.im.entity.enums;
/**
- * 消息的类型
- *
- * @author liushuai(liushuai711 @ gmail.com)
- * @version v4.0
- * @Description:
- * @since 2022/2/10 16:36
+ * 消息状态枚举
*/
public enum MessageStatusEnum {
- //socket刚打开时发送的消息,这个一般是是刚打开socket链接,进行登录,传入token用
- CONNECT,
- //心跳类型的消息,此种类型的消息只有 type 、 text 两种属性
- HEARTBEAT,
- //用户打开一个对话框,准备跟某人聊天时
- OPEN,
- //客服进行自动回复。客户端发起这种类型请求,则是在拉取对方是否有自动回复,如果有,服务端就会给客户端发送过自动回复的信息
- AUTO_REPLY,
- //正常收发消息沟通,文字、表情等沟通
- MSG,
- //扩展。比如发送商品、发送订单
- EXTEND,
- //系统提示,如提示 对方已离线
- SYSTEM,
- //服务端发送到客户端,用于设置客户端的用户信息。会吧 com.xnx3.yunkefu.core.vo.bean.User 传过去
- SET_USER,
- //结束服务
- CLOSE_SERVICE;
+
+ NORMAL(0, "正常"),
+ DELETED(1, "已删除"),
+ RECALLED(2, "已撤回"),
+
+ // WebSocket相关状态
+ CONNECT(100, "连接"),
+ HEARTBEAT(101, "心跳"),
+ OPEN(102, "打开对话"),
+ AUTO_REPLY(103, "自动回复"),
+ MSG(104, "普通消息"),
+ EXTEND(105, "扩展消息"),
+ SYSTEM(106, "系统消息"),
+ SET_USER(107, "设置用户"),
+ CLOSE_SERVICE(108, "结束服务");
+ private final Integer status;
+ private final String description;
+
+ MessageStatusEnum(Integer status, String description) {
+ this.status = status;
+ this.description = description;
+ }
+
+ public Integer getStatus() {
+ return status;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * 根据状态码获取枚举
+ */
+ public static MessageStatusEnum getByStatus(Integer status) {
+ if (status == null) {
+ return null;
+ }
+ for (MessageStatusEnum statusEnum : values()) {
+ if (statusEnum.getStatus().equals(status)) {
+ return statusEnum;
+ }
+ }
+ return null;
+ }
}
diff --git a/framework/src/main/java/cn/lili/modules/im/entity/enums/MessageTypeEnum.java b/framework/src/main/java/cn/lili/modules/im/entity/enums/MessageTypeEnum.java
index 6b06d3b7..0ab162d9 100644
--- a/framework/src/main/java/cn/lili/modules/im/entity/enums/MessageTypeEnum.java
+++ b/framework/src/main/java/cn/lili/modules/im/entity/enums/MessageTypeEnum.java
@@ -1,23 +1,45 @@
package cn.lili.modules.im.entity.enums;
/**
- * 消息类型
- *
- * @author liushuai
+ * 消息类型枚举
*/
public enum MessageTypeEnum {
- /**
- * 消息类型枚举
- *
- * 普通消息
- * 图片
- * 语音
- * 视频
- */
- MESSAGE,
- PICTURE,
- VOICE,
- GOODS,
- ORDER,
- VIDEO
+ MESSAGE("message", "普通消息"),
+ TEXT("TEXT", "文本消息"),
+ IMAGE("IMAGE", "图片消息"),
+ FILE("FILE", "文件消息"),
+ VOICE("VOICE", "语音消息"),
+ VIDEO("VIDEO", "视频消息"),
+ SYSTEM("SYSTEM", "系统消息"),
+ GROUP("GROUP", "群聊消息"),
+ LOCATION("LOCATION", "位置消息");
+
+ private final String type;
+ private final String description;
+
+ MessageTypeEnum(String type, String description) {
+ this.type = type;
+ this.description = description;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public static MessageTypeEnum fromType(String type) {
+ if (type == null) {
+ return null;
+ }
+
+ for (MessageTypeEnum typeEnum : MessageTypeEnum.values()) {
+ if (typeEnum.getType().equalsIgnoreCase(type)) {
+ return typeEnum;
+ }
+ }
+ return null;
+ }
}
diff --git a/framework/src/main/java/cn/lili/modules/im/entity/enums/OperationType.java b/framework/src/main/java/cn/lili/modules/im/entity/enums/OperationType.java
index 5909222e..9d8c37bc 100644
--- a/framework/src/main/java/cn/lili/modules/im/entity/enums/OperationType.java
+++ b/framework/src/main/java/cn/lili/modules/im/entity/enums/OperationType.java
@@ -21,6 +21,5 @@ public enum OperationType {
MESSAGE,
HISTORY,
READ,
- UNREAD,
-
+ UNREAD
}
diff --git a/framework/src/main/java/cn/lili/modules/im/entity/vo/FriendRequestVO.java b/framework/src/main/java/cn/lili/modules/im/entity/vo/FriendRequestVO.java
new file mode 100644
index 00000000..631b6ab5
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/im/entity/vo/FriendRequestVO.java
@@ -0,0 +1,35 @@
+package cn.lili.modules.im.entity.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import java.util.Date;
+
+@Data
+@ApiModel(value = "好友申请VO")
+public class FriendRequestVO {
+
+ @ApiModelProperty(value = "申请ID")
+ private String id;
+
+ @ApiModelProperty(value = "申请者ID")
+ private String userId;
+
+ @ApiModelProperty(value = "申请者昵称")
+ private String nickname;
+
+ @ApiModelProperty(value = "申请者头像")
+ private String avatar;
+
+ @ApiModelProperty(value = "申请者手机号")
+ private String mobile;
+
+ @ApiModelProperty(value = "备注")
+ private String remark;
+
+ @ApiModelProperty(value = "状态(0:待处理 1:已接受 2:已拒绝)")
+ private Integer status;
+
+ @ApiModelProperty(value = "申请时间")
+ private Date createTime;
+}
\ No newline at end of file
diff --git a/framework/src/main/java/cn/lili/modules/im/entity/vo/FriendVO.java b/framework/src/main/java/cn/lili/modules/im/entity/vo/FriendVO.java
index fe2a1635..3191e93f 100644
--- a/framework/src/main/java/cn/lili/modules/im/entity/vo/FriendVO.java
+++ b/framework/src/main/java/cn/lili/modules/im/entity/vo/FriendVO.java
@@ -4,18 +4,64 @@ import cn.lili.modules.im.entity.dos.Friend;
import lombok.Data;
import java.util.Date;
-@Data
-public class FriendVO extends Friend {
- // 从 li_member 表获取的字段
- private String username;
- private String nickname;
- private String face; // 头像
- private String mobile;
- private String email;
- private String region;
- private String gender;
- private Date birthday;
- // 昵称首字母(用于排序)
- private String firstLetter;
-}
\ No newline at end of file
+import cn.lili.modules.im.entity.dos.Friend;
+
+import lombok.Data;
+
+import java.util.Date;
+
+import java.io.Serializable;
+
+import io.swagger.annotations.ApiModel;
+
+import io.swagger.annotations.ApiModelProperty;
+
+
+
+@Data
+
+@ApiModel(value = "好友VO")
+
+public class FriendVO implements Serializable {
+
+
+
+ private static final long serialVersionUID = 1L;
+
+
+
+ @ApiModelProperty(value = "用户ID")
+ private String id;
+
+ @ApiModelProperty(value = "关系ID")
+ private String friendId;
+ private String talkId;
+
+ @ApiModelProperty(value = "昵称")
+ private String nickname;
+
+ @ApiModelProperty(value = "头像")
+ private String avatar;
+
+ @ApiModelProperty(value = "地区")
+ private String region;
+
+ @ApiModelProperty(value = "手机号")
+ private String mobile;
+
+ @ApiModelProperty(value = "备注")
+ private String remark;
+
+ @ApiModelProperty(value = "是否是店铺 0:否 1:是")
+ private Integer storeFlag;
+
+ @ApiModelProperty(value = "是否互相关注")
+ private Integer isMutual;
+
+ @ApiModelProperty(value = "关注时间")
+ private Date createTime;
+
+
+}
+
diff --git a/framework/src/main/java/cn/lili/modules/im/entity/vo/ImGroupMemberVO.java b/framework/src/main/java/cn/lili/modules/im/entity/vo/ImGroupMemberVO.java
new file mode 100644
index 00000000..b81004de
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/im/entity/vo/ImGroupMemberVO.java
@@ -0,0 +1,33 @@
+package cn.lili.modules.im.entity.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+@ApiModel(value = "群成员信息")
+public class ImGroupMemberVO {
+ @ApiModelProperty(value = "成员ID")
+ private String memberId;
+
+ @ApiModelProperty(value = "成员昵称")
+ private String nickname;
+
+ @ApiModelProperty(value = "成员头像")
+ private String avatar;
+
+ @ApiModelProperty(value = "角色(0:普通成员 1:管理员 2:群主)")
+ private Integer role;
+
+ @ApiModelProperty(value = "是否被禁言")
+ private Integer isMuted;
+
+ @ApiModelProperty(value = "禁言结束时间")
+ private Date muteEndTime;
+
+ @ApiModelProperty(value = "加入时间")
+ private Date joinTime;
+ private String displayName;
+}
\ No newline at end of file
diff --git a/framework/src/main/java/cn/lili/modules/im/entity/vo/ImGroupVO.java b/framework/src/main/java/cn/lili/modules/im/entity/vo/ImGroupVO.java
new file mode 100644
index 00000000..f8e5ebf8
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/im/entity/vo/ImGroupVO.java
@@ -0,0 +1,39 @@
+package cn.lili.modules.im.entity.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+@ApiModel(value = "群聊信息")
+public class ImGroupVO {
+ @ApiModelProperty(value = "群ID")
+ private String id;
+
+ @ApiModelProperty(value = "群名称")
+ private String name;
+
+ @ApiModelProperty(value = "群头像")
+ private String avatar;
+
+ @ApiModelProperty(value = "群公告")
+ private String notice;
+
+ @ApiModelProperty(value = "群主ID")
+ private String ownerId;
+
+ @ApiModelProperty(value = "成员数量")
+ private Integer memberCount;
+
+ @ApiModelProperty(value = "创建时间")
+ private Date createTime;
+ private Integer role;
+ private String displayName;
+ @ApiModelProperty(value = "最后一条消息")
+ private ImMessageVO lastMessage;
+
+ @ApiModelProperty(value = "未读消息数")
+ private Integer unreadCount;
+}
\ No newline at end of file
diff --git a/framework/src/main/java/cn/lili/modules/im/entity/vo/ImMessageVO.java b/framework/src/main/java/cn/lili/modules/im/entity/vo/ImMessageVO.java
new file mode 100644
index 00000000..e767a976
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/im/entity/vo/ImMessageVO.java
@@ -0,0 +1,78 @@
+package cn.lili.modules.im.entity.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import java.util.Date;
+
+@Data
+@ApiModel(value = "即时通讯消息VO")
+public class ImMessageVO {
+
+ @ApiModelProperty(value = "消息ID")
+ private String id;
+
+ @ApiModelProperty(value = "会话ID")
+ private String talkId;
+
+ @ApiModelProperty(value = "发送者ID")
+ private String fromUser;
+
+ @ApiModelProperty(value = "发送者昵称")
+ private String fromName;
+
+ @ApiModelProperty(value = "发送者头像")
+ private String fromAvatar;
+
+ @ApiModelProperty(value = "接收者ID")
+ private String toUser;
+
+ @ApiModelProperty(value = "消息内容")
+ private String text;
+
+ @ApiModelProperty(value = "消息类型")
+ private String type;
+
+ @ApiModelProperty(value = "聊天类型(单聊/群聊)")
+ private String messageType;
+
+ @ApiModelProperty(value = "消息状态")
+ private Integer status;
+
+ @ApiModelProperty(value = "是否已读")
+ private Boolean isRead;
+
+ @ApiModelProperty(value = "创建时间")
+ private Date createTime;
+
+ // 扩展字段
+ @ApiModelProperty(value = "文件名")
+ private String fileName;
+
+ @ApiModelProperty(value = "文件大小")
+ private Long fileSize;
+
+ @ApiModelProperty(value = "文件URL")
+ private String fileUrl;
+
+ @ApiModelProperty(value = "图片URL")
+ private String imageUrl;
+
+ @ApiModelProperty(value = "图片宽度")
+ private Integer imageWidth;
+
+ @ApiModelProperty(value = "图片高度")
+ private Integer imageHeight;
+
+ @ApiModelProperty(value = "缩略图URL")
+ private String thumbnailUrl;
+
+ @ApiModelProperty(value = "语音URL")
+ private String voiceUrl;
+
+ @ApiModelProperty(value = "语音时长")
+ private Integer duration;
+
+ @ApiModelProperty(value = "额外信息")
+ private String extra;
+}
\ No newline at end of file
diff --git a/framework/src/main/java/cn/lili/modules/im/entity/vo/ImTalkVO.java b/framework/src/main/java/cn/lili/modules/im/entity/vo/ImTalkVO.java
index 6d80a8be..a78ce2d3 100644
--- a/framework/src/main/java/cn/lili/modules/im/entity/vo/ImTalkVO.java
+++ b/framework/src/main/java/cn/lili/modules/im/entity/vo/ImTalkVO.java
@@ -53,6 +53,8 @@ public class ImTalkVO extends BaseTenantEntity {
@ApiModelProperty(value = "未读数量")
private Long unread;
+ @ApiModelProperty(value = "是否关注")
+ private Integer isMutual;
public ImTalkVO() {
@@ -66,6 +68,7 @@ public class ImTalkVO extends BaseTenantEntity {
name = imTalk.getName1();
face = imTalk.getFace1();
storeFlag = imTalk.getStoreFlag1();
+ isMutual=imTalk.getIsMutual();
} else {
userId = imTalk.getUserId2();
top = imTalk.getTop2();
@@ -73,6 +76,7 @@ public class ImTalkVO extends BaseTenantEntity {
name = imTalk.getName2();
face = imTalk.getFace2();
storeFlag = imTalk.getStoreFlag2();
+ isMutual=imTalk.getIsMutual();
}
lastTalkMessage = imTalk.getLastTalkMessage();
lastTalkTime = imTalk.getLastTalkTime();
diff --git a/framework/src/main/java/cn/lili/modules/im/entity/vo/MessageOperation.java b/framework/src/main/java/cn/lili/modules/im/entity/vo/MessageOperation.java
index b4360bc6..e3dcb51b 100644
--- a/framework/src/main/java/cn/lili/modules/im/entity/vo/MessageOperation.java
+++ b/framework/src/main/java/cn/lili/modules/im/entity/vo/MessageOperation.java
@@ -41,13 +41,13 @@ public class MessageOperation {
public void setOperationType(String operationType) {
if (!StringUtils.isEmpty(operationType)) {
- this.operationType = OperationType.valueOf(operationType);
+ this.operationType = OperationType.valueOf(operationType.toUpperCase());
}
}
public void setMessageType(String messageType) {
if (!StringUtils.isEmpty(messageType)) {
- this.messageType = MessageTypeEnum.valueOf(messageType);
+ this.messageType = MessageTypeEnum.valueOf(messageType.toUpperCase());
}
}
}
diff --git a/framework/src/main/java/cn/lili/modules/im/mapper/FriendMapper.java b/framework/src/main/java/cn/lili/modules/im/mapper/FriendMapper.java
index 2268608b..25c50d6e 100644
--- a/framework/src/main/java/cn/lili/modules/im/mapper/FriendMapper.java
+++ b/framework/src/main/java/cn/lili/modules/im/mapper/FriendMapper.java
@@ -2,9 +2,15 @@ package cn.lili.modules.im.mapper;
import cn.lili.modules.im.entity.dos.Friend;
+
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import org.mapstruct.Mapper;
+
+import org.apache.ibatis.annotations.Mapper;
+
+
@Mapper
+
public interface FriendMapper extends BaseMapper {
+
}
diff --git a/framework/src/main/java/cn/lili/modules/im/mapper/ImGroupMemberMapper.java b/framework/src/main/java/cn/lili/modules/im/mapper/ImGroupMemberMapper.java
index 0c9b8d04..a9a889c6 100644
--- a/framework/src/main/java/cn/lili/modules/im/mapper/ImGroupMemberMapper.java
+++ b/framework/src/main/java/cn/lili/modules/im/mapper/ImGroupMemberMapper.java
@@ -1,8 +1,13 @@
package cn.lili.modules.im.mapper;
import cn.lili.modules.im.entity.dos.ImGroupMember;
-import cn.lili.modules.im.entity.dos.ImMessage;
+
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+
+@Mapper
public interface ImGroupMemberMapper extends BaseMapper {
+
}
diff --git a/framework/src/main/java/cn/lili/modules/im/service/FriendService.java b/framework/src/main/java/cn/lili/modules/im/service/FriendService.java
index 542009c5..4130bd9a 100644
--- a/framework/src/main/java/cn/lili/modules/im/service/FriendService.java
+++ b/framework/src/main/java/cn/lili/modules/im/service/FriendService.java
@@ -1,88 +1,88 @@
package cn.lili.modules.im.service;
-
import cn.lili.modules.im.entity.dos.Friend;
-
import cn.lili.modules.im.entity.vo.FriendVO;
-
+import cn.lili.modules.im.entity.vo.FriendRequestVO;
import com.baomidou.mybatisplus.extension.service.IService;
-
import java.util.List;
-
-
+/**
+ * 好友关系业务层
+ *
+ * @author Chopper
+ */
public interface FriendService extends IService {
-
-
-
+
/**
-
- * 获取互相关注的好友列表(包含详细信息)
-
+ * 获取关注列表
* @param userId 用户ID
-
- * @return 好友列表
-
+ * @return 关注的用户列表
*/
-
List getMutualFriends(String userId);
-
-
-
+
/**
-
- * 获取好友详细信息
-
- * @param friendId 好友ID
-
- * @return 好友详细信息
-
+ * 获取用户详细信息
+ * @param friendId 用户ID
+ * @return 用户详细信息
*/
-
FriendVO getFriendDetails(String friendId);
-
-
-
+
/**
-
- * 解除好友关系
-
- * @param userId 用户ID
-
- * @param friendId 好友ID
-
+ * 取消关注
+ * @param userId 当前用户ID
+ * @param friendId 要取消关注的用户ID
*/
-
void removeFriend(String userId, String friendId);
-
-
-
+
/**
-
- * 添加好友
-
- * @param userId 用户ID
-
- * @param friendId 好友ID
-
+ * 关注用户
+ * @param userId 当前用户ID
+ * @param friendId 要关注的用户ID
*/
-
void addFriend(String userId, String friendId);
-
-
-
+
/**
-
- * 更新好友备注
-
- * @param userId 用户ID
-
- * @param friendId 好友ID
-
+ * 通过手机号关注用户
+ * @param mobile 手机号
+ * @param remark 备注
+ */
+ void addFriendByMobile(String mobile, String remark);
+
+ /**
+ * 更新备注
+ * @param userId 当前用户ID
+ * @param friendId 关注的用户ID
* @param remark 备注
-
*/
-
void updateRemark(String userId, String friendId, String remark);
-
+//
+// /**
+// * 获取好友申请列表
+// * @param userId 用户ID
+// * @return 申请列表
+// */
+// List getFriendRequests(String userId);
+//
+// /**
+// * 接受好友申请
+// * @param requestId 申请ID
+// * @param userId 当前用户ID
+// */
+// void acceptFriendRequest(String requestId, String userId);
+//
+// /**
+// * 拒绝好友申请
+// * @param requestId 申请ID
+// * @param userId 当前用户ID
+// */
+// void rejectFriendRequest(String requestId, String userId);
+
+ /**
+ * 搜索用户
+ * @param keyword 搜索关键词(用户名/手机号)
+ * @param onlyStore 是否只搜索店铺
+ * @param currentUserId 当前用户ID
+ * @return 用户列表
+ */
+ List searchUsers(String keyword, Boolean onlyStore, String currentUserId);
}
\ No newline at end of file
diff --git a/framework/src/main/java/cn/lili/modules/im/service/ImGroupService.java b/framework/src/main/java/cn/lili/modules/im/service/ImGroupService.java
index 23a4454b..8c8de02f 100644
--- a/framework/src/main/java/cn/lili/modules/im/service/ImGroupService.java
+++ b/framework/src/main/java/cn/lili/modules/im/service/ImGroupService.java
@@ -1,58 +1,154 @@
package cn.lili.modules.im.service;
import cn.lili.modules.im.entity.dos.ImGroup;
+
+import cn.lili.modules.im.entity.vo.FriendVO;
+import cn.lili.modules.im.entity.vo.ImGroupMemberVO;
+import cn.lili.modules.im.entity.vo.ImGroupVO;
import com.baomidou.mybatisplus.extension.service.IService;
+
import java.util.List;
+
+
public interface ImGroupService extends IService {
+
/**
- * 创建群聊
- * @param groupName 群名称
- * @param memberIds 邀请的成员ID列表
- * @return 群聊信息
+ * 获取用户加入的群聊列表
+ * @param userId 用户ID
+ * @return 群聊列表
*/
+ List getUserGroups(String userId);
+
+ /**
+ * 获取群聊详情
+ * @param groupId 群ID
+ * @return 群聊详情
+ */
+ ImGroupVO getGroupDetail(String groupId);
+
+ /**
+ * 获取群成员列表
+ * @param groupId 群ID
+ * @return 群成员列表
+ */
+ List getGroupMembers(String groupId);
+
+ /**
+ * 退出群聊
+ * @param groupId 群ID
+ * @param userId 用户ID
+ */
+ void quitGroup(String groupId, String userId);
+
+ /**
+ * 修改群信息
+ * @param groupId 群ID
+ * @param groupName 群名称
+ * @param notice 群公告
+ * @param avatar 群头像
+ */
+ void updateGroupInfo(String groupId, String groupName, String notice, String avatar);
+
+
+
+ /**
+
+ * 创建群聊
+
+ * @param groupName 群名称
+
+ * @param memberIds 邀请的成员ID列表
+
+ * @return 群聊信息
+
+ */
+
ImGroup createGroup(String groupName, List memberIds);
+
+
/**
+
* 解散群聊
+
* @param groupId 群ID
+
*/
+
void dismissGroup(String groupId);
+
+
/**
+
* 邀请成员
+
* @param groupId 群ID
+
* @param memberIds 成员ID列表
+
*/
+
void inviteMembers(String groupId, List memberIds);
+
+
/**
+
* 设置管理员
+
* @param groupId 群ID
+
* @param memberId 成员ID
+
*/
+
void setAdmin(String groupId, String memberId);
+
+
/**
+
* 取消管理员
+
* @param groupId 群ID
+
* @param memberId 成员ID
+
*/
+
void removeAdmin(String groupId, String memberId);
- /**
- * 禁言成员
- * @param groupId 群ID
- * @param memberId 成员ID
- * @param duration 禁言时长(分钟)
- */
- void muteMember(String groupId, String memberId, Integer duration);
+
/**
- * 解除成员禁言
+
+ * 禁言成员
+
* @param groupId 群ID
+
* @param memberId 成员ID
+
+ * @param duration 禁言时长(分钟)
+
*/
+
+ void muteMember(String groupId, String memberId, Integer duration);
+
+
+
+ /**
+
+ * 解除成员禁言
+
+ * @param groupId 群ID
+
+ * @param memberId 成员ID
+
+ */
+
void unmuteMember(String groupId, String memberId);
+
}
\ No newline at end of file
diff --git a/framework/src/main/java/cn/lili/modules/im/service/ImMessageService.java b/framework/src/main/java/cn/lili/modules/im/service/ImMessageService.java
index 823369c0..9fb9f43a 100644
--- a/framework/src/main/java/cn/lili/modules/im/service/ImMessageService.java
+++ b/framework/src/main/java/cn/lili/modules/im/service/ImMessageService.java
@@ -1,7 +1,10 @@
package cn.lili.modules.im.service;
+import cn.lili.common.vo.PageVO;
+import cn.lili.common.vo.ResultPageVO;
import cn.lili.modules.im.entity.dos.ImMessage;
import cn.lili.modules.im.entity.dto.MessageQueryParams;
+import cn.lili.modules.im.entity.vo.ImMessageVO;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
@@ -13,6 +16,33 @@ import java.util.List;
*/
public interface ImMessageService extends IService {
+ /**
+ * 获取历史消息
+ * @param talkId 对话ID
+ * @param earliestMsgId 最早消息ID
+ * @param pageSize 每页大小
+ * @return 消息列表
+ */
+ List getHistoryMessages(String talkId, String earliestMsgId, Integer pageSize);
+
+ /**
+ * 获取最近消息
+ * @param talkId 对话ID
+ * @param latestMsgId 最新消息ID
+ * @param pageSize 每页大小
+ * @return 消息列表
+ */
+ List getRecentMessages(String talkId, String latestMsgId, Integer pageSize);
+
+ /**
+ * 发送消息
+ * @param toId 接收者ID
+ * @param content 消息内容
+ * @param type 消息类型
+ * @return 消息对象
+ */
+ ImMessageVO sendMessage(String toId, String content, String type);
+
/**
* 阅读消息
*
@@ -63,4 +93,60 @@ public interface ImMessageService extends IService {
* 清空所有未读消息
*/
void cleanUnreadMessage();
+
+ /**
+ * 获取群聊消息历史
+ * @param groupId 群ID
+ * @param pageNumber 页码
+ * @param pageSize 每页大小
+ * @return 消息列表
+ */
+ ResultPageVO getGroupMessages(String groupId, Integer pageNumber, Integer pageSize);
+
+ /**
+ * 发送群聊消息
+ * @param groupId 群ID
+ * @param content 消息内容
+ * @param type 消息类型
+ * @return 消息对象
+ */
+ ImMessageVO sendGroupMessage(String groupId, String content, String type);
+
+ /**
+ * 撤回消息
+ * @param messageId 消息ID
+ */
+ void recallMessage(String messageId);
+
+ /**
+ * 加载历史消息
+ * @param talkId 会话ID
+ * @param earliestMsgId 最早消息ID
+ * @param size 每页大小
+ * @return 消息列表
+ */
+ List loadHistoryMessages(String talkId, String earliestMsgId, Integer size);
+
+ /**
+ * 加载最新消息
+ * @param talkId 会话ID
+ * @param size 每页大小
+ * @return 消息列表
+ */
+ List loadLatestMessages(String talkId, Integer size);
+
+ /**
+ * 获取新消息
+ * @param talkId 会话ID
+ * @param latestMsgId 最新消息ID
+ * @return 新消息列表
+ */
+ List getNewerMessages(String talkId, String latestMsgId);
+
+ /**
+ * 标记消息已读
+ * @param messages 消息列表
+ * @param userId 用户ID
+ */
+ void readMessages(List messages, String userId);
}
\ No newline at end of file
diff --git a/framework/src/main/java/cn/lili/modules/im/service/MessageSender.java b/framework/src/main/java/cn/lili/modules/im/service/MessageSender.java
new file mode 100644
index 00000000..6be477b1
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/im/service/MessageSender.java
@@ -0,0 +1,7 @@
+package cn.lili.modules.im.service;
+
+import cn.lili.modules.im.entity.vo.MessageVO;
+
+public interface MessageSender {
+ void sendMessage(String sessionId, MessageVO message);
+}
\ No newline at end of file
diff --git a/framework/src/main/java/cn/lili/modules/im/serviceimpl/FriendServiceImpl.java b/framework/src/main/java/cn/lili/modules/im/serviceimpl/FriendServiceImpl.java
index 540e79d2..154a163b 100644
--- a/framework/src/main/java/cn/lili/modules/im/serviceimpl/FriendServiceImpl.java
+++ b/framework/src/main/java/cn/lili/modules/im/serviceimpl/FriendServiceImpl.java
@@ -1,344 +1,404 @@
package cn.lili.modules.im.serviceimpl;
-import cn.lili.common.security.context.UserContext;
-import cn.lili.common.security.enums.UserEnums;
+
+import cn.lili.common.enums.ResultCode;
import cn.lili.common.exception.ServiceException;
-import cn.lili.common.utils.StringUtils;
+import cn.lili.common.security.AuthUser;
+import cn.lili.common.security.context.UserContext;
import cn.lili.modules.im.entity.dos.Friend;
+import cn.lili.modules.im.entity.dos.ImTalk;
import cn.lili.modules.im.entity.vo.FriendVO;
+import cn.lili.modules.im.entity.vo.FriendRequestVO;
import cn.lili.modules.im.mapper.FriendMapper;
import cn.lili.modules.im.service.FriendService;
-
+import cn.lili.modules.im.service.ImTalkService;
import cn.lili.modules.member.entity.dos.Member;
-import cn.lili.modules.member.mapper.MemberMapper;
+import cn.lili.modules.member.service.MemberService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
-import net.sourceforge.pinyin4j.PinyinHelper;
-import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
-import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
-import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
-import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
-import org.springframework.beans.BeanUtils;
-import java.util.Collections;
+import java.util.ArrayList;
import java.util.Date;
import java.util.List;
-import java.util.ArrayList;
-
-import static cn.hutool.extra.pinyin.PinyinUtil.getFirstLetter;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+/**
+ * 好友业务层实现
+ *
+ * @author Chopper
+ */
@Slf4j
@Service
+@Transactional(rollbackFor = Exception.class)
+@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class FriendServiceImpl extends ServiceImpl implements FriendService {
- @Autowired
- private MemberMapper memberMapper;
+ private final ImTalkService imTalkService;
+ private final MemberService memberService;
+ private final FriendMapper friendMapper;
@Override
public List getMutualFriends(String userId) {
- // 获取好友关系列表
+ // 验证用户登录状态
+ AuthUser currentUser = UserContext.getCurrentUser();
+ if (currentUser == null) {
+ throw new ServiceException(ResultCode.USER_NOT_LOGIN);
+ }
+
+ // 获取当前用户的ID
+ String currentUserId = currentUser.getId();
+
+ // 构建查询条件
+ LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
+ queryWrapper.eq(Friend::getUserId, currentUserId) // 查询当前用户的关注列表
+ .eq(Friend::getStatus, 1); // 只查询状态为1的记录
+
+ // 查询关注列表
+ List friends = this.list(queryWrapper);
+ if (friends.isEmpty()) {
+ return new ArrayList<>(); // 如果没有找到,返回空列表
+ }
+
+ // 收集所有关注的用户ID
+ List friendIds = friends.stream()
+ .map(Friend::getFriendId) // 获取 friendId
+ .collect(Collectors.toList());
+
+ // 检查 friendIds 是否为空
+ if (friendIds.isEmpty()) {
+ log.warn("No friend IDs found for user: {}", currentUserId);
+ return new ArrayList<>(); // 或者抛出异常
+ }
+
+ // 批量查询用户信息
+ List members = memberService.listByIds(friendIds);
+ Map memberMap = members.stream()
+ .collect(Collectors.toMap(Member::getId, member -> member));
+
+ // 组装VO对象
+ return friends.stream().map(friend -> {
+ Member member = memberMap.get(friend.getFriendId());
+ if (member != null) {
+ FriendVO vo = new FriendVO();
+ vo.setId(member.getId().toString()); // 设置为用户的 ID
+ vo.setFriendId(friend.getFriendId()); // 设置为 Friend 的 ID
+ vo.setNickname(member.getNickName());
+ vo.setAvatar(member.getFace());
+ // 其他字段设置...
+ return vo;
+ }
+ return null;
+ })
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ }
+
+ // 假设这个方法用于从 ImTalk 表中获取 talkId
+ private String getTalkId(String userId1, String userId2) {
+ LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
+ queryWrapper
+ .or().eq(ImTalk::getUserId1, userId1).eq(ImTalk::getUserId2, userId2)
+ .or().eq(ImTalk::getUserId1, userId2).eq(ImTalk::getUserId2, userId1);
+
+ ImTalk imTalk = imTalkService.getOne(queryWrapper);
+ return imTalk != null ? imTalk.getId() : null; // 返回 talkId
+ }
+ @Override
+ public void addFriend(String userId, String friendId) {
+ // 验证用户登录状态
+ AuthUser currentUser = UserContext.getCurrentUser();
+ if (currentUser == null) {
+ throw new ServiceException(ResultCode.USER_NOT_LOGIN);
+ }
+
+ // 检查是否已经关注
LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Friend::getUserId, userId)
- .eq(Friend::getStatus, 1); // 已确认的好友关系
- List friends = this.list(queryWrapper);
+ .eq(Friend::getFriendId, friendId);
-
- // 转换为 FriendVO 列表
- List friendVOs = new ArrayList<>();
- for (Friend friend : friends) {
- FriendVO friendVO = new FriendVO();
- BeanUtils.copyProperties(friend, friendVO);
-
- // 查询好友的详细信息
- Member member = memberMapper.selectById(friend.getFriendId());
- if (member != null) {
- // 复制会员信息到 VO
- friendVO.setUsername(member.getUsername());
- friendVO.setNickname(member.getNickName());
- friendVO.setFace(member.getFace());
- friendVO.setMobile(member.getMobile());
- friendVO.setEmail(member.getRegion());
- friendVO.setGender(member.getGradeId());
- friendVO.setBirthday(member.getBirthday());
- // 设置昵称首字母
- String firstLetter = getFirstLetter(member.getNickName());
- friendVO.setFirstLetter(firstLetter);
- }
-
- friendVOs.add(friendVO);
+ // 如果已经关注,抛出异常
+ if (this.count(queryWrapper) > 0) {
+ throw new ServiceException("您已经关注过该用户");
}
- // 按照昵称首字母排序
- Collections.sort(friendVOs, (a, b) -> {
- String letterA = a.getFirstLetter() != null ? a.getFirstLetter() : "#";
- String letterB = b.getFirstLetter() != null ? b.getFirstLetter() : "#";
- return letterA.compareTo(letterB);
- });
+ // 创建新的关注关系
+ Friend friend = new Friend();
+ friend.setUserId(userId);
+ friend.setFriendId(friendId);
+ friend.setStatus(1); // 设置为已关注状态
+ friend.setIsMutual(1);
+ friend.setCreateTime(new Date());
+// friend.setUpdateTime(new Date());
- return friendVOs;
+ // 检查对方是否也关注了当前用户
+ Integer mutualStatus = isFollowing(friendId, userId); // 检查 friendId 是否关注了 userId
+
+ // 设置互相关注状态
+ if (mutualStatus == 1) {
+ friend.setIsMutual(2); // 设置为互相关注
+ } else {
+ friend.setIsMutual(1); // 设置为单向关注
+ }
+
+ // 保存关注关系
+ this.save(friend);
}
- /**
- * 获取字符串的首字母
- * @param str 字符串
- * @return 首字母(大写)
- */
- private String getFirstLetter(String str) {
- if (StringUtils.isEmpty(str)) {
- return "#";
- }
-
- try {
- // 创建 HanyuPinyinOutputFormat 对象
- HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
- // 设置拼音小写
- format.setCaseType(HanyuPinyinCaseType.LOWERCASE);
- // 设置声调不输出
- format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
-
- // 取第一个字符
- char firstChar = str.charAt(0);
- // 判断是否为汉字
- if (Character.toString(firstChar).matches("[\\u4E00-\\u9FA5]+")) {
- // 如果是汉字,转换为拼音
- String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(firstChar, format);
- if (pinyinArray != null && pinyinArray.length > 0) {
- return pinyinArray[0].substring(0, 1).toUpperCase();
- }
- } else if (Character.toString(firstChar).matches("[a-zA-Z]")) {
- // 如果是字母,直接返回大写
- return String.valueOf(firstChar).toUpperCase();
- }
-
- // 其他情况返回 #
- return "#";
- } catch (BadHanyuPinyinOutputFormatCombination e) {
- log.error("获取拼音首字母失败", e);
- return "#";
- }
- }
-
@Override
public FriendVO getFriendDetails(String friendId) {
- String userId = UserContext.getCurrentUser().getId();
+ // 验证用户登录状态
+ AuthUser currentUser = UserContext.getCurrentUser();
+ if (currentUser == null) {
+ throw new ServiceException(ResultCode.USER_NOT_LOGIN);
+ }
- // 查询好友关系
+ // 获取好友信息
+ Member member = memberService.getById(friendId);
+ if (member == null) {
+ throw new ServiceException("用户不存在");
+ }
+
+ // 转换为VO
+ FriendVO vo = new FriendVO();
+ vo.setId(member.getId().toString());
+ vo.setNickname(member.getNickName());
+ vo.setAvatar(member.getFace());
+ vo.setRegion(member.getRegion());
+ vo.setMobile(member.getMobile());
+
+ // 设置默认值
+ vo.setRemark(""); // 或者设置为 null
+ vo.setStoreFlag(member.getHaveStore() ? 1 : 0); // 假设你有这个字段
+ vo.setCreateTime(new Date()); // 或者设置为 null
+
+ // 获取当前用户ID
+ String currentUserId = currentUser.getId();
+
+ // 查询Friend表以获取isMutual值
+ LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
+ queryWrapper.eq(Friend::getUserId, currentUserId)
+ .eq(Friend::getFriendId, friendId);
+
+ Friend friendRelation = this.getOne(queryWrapper);
+ if (friendRelation != null) {
+ vo.setIsMutual(friendRelation.getIsMutual()); // 设置isMutual值
+ vo.setFriendId(friendRelation.getFriendId());
+ } else {
+ vo.setIsMutual(0); // 如果没有找到关系,设置为未关注
+ }
+
+ return vo;
+ }
+
+ @Override
+ public void removeFriend(String userId, String friendId) {
+ // 验证用户登录状态
+ AuthUser currentUser = UserContext.getCurrentUser();
+ if (currentUser == null) {
+ throw new ServiceException(ResultCode.USER_NOT_LOGIN);
+ }
+
+ // 验证操作权限
+ if (!currentUser.getId().equals(userId)) {
+ throw new ServiceException(ResultCode.USER_AUTHORITY_ERROR);
+ }
+
+ // 取消关注
LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Friend::getUserId, userId)
.eq(Friend::getFriendId, friendId);
- Friend friend = this.getOne(queryWrapper);
-
- if (friend == null) {
- throw new ServiceException("好友关系不存在");
- }
-
- // 转换为 VO 并查询详细信息
- FriendVO friendVO = new FriendVO();
- BeanUtils.copyProperties(friend, friendVO);
-
- // 查询好友的详细信息
- Member member = memberMapper.selectById(friendId);
- if (member != null) {
- // 复制会员信息到 VO
- friendVO.setUsername(member.getUsername());
- friendVO.setNickname(member.getNickName());
- friendVO.setFace(member.getFace());
- friendVO.setMobile(member.getMobile());
- friendVO.setEmail(member.getRegion());
- friendVO.setGender(member.getGradeId());
- friendVO.setBirthday(member.getBirthday());
- }
-
- return friendVO;
- }
-
-
-
- @Override
-
- @Transactional(rollbackFor = Exception.class)
-
- public void removeFriend(String userId, String friendId) {
-
- // 删除双向的好友关系
-
- LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
-
- queryWrapper.and(wrapper -> wrapper
-
- .or(w -> w.eq(Friend::getUserId, userId).eq(Friend::getFriendId, friendId))
-
- .or(w -> w.eq(Friend::getUserId, friendId).eq(Friend::getFriendId, userId))
-
- );
-
-
if (!this.remove(queryWrapper)) {
-
- throw new ServiceException("解除好友关系失败");
-
+ throw new ServiceException("取消关注失败");
}
-
}
-
-
@Override
-
- @Transactional(rollbackFor = Exception.class)
-
- public void addFriend(String userId, String friendId) {
-
- // 检查用户ID是否存在
-
- if (!isUserExists(userId)) {
-
- throw new ServiceException("用户ID不存在");
-
- }
-
-
-
- // 检查好友ID是否存在
-
- if (!isUserExists(friendId)) {
-
- throw new ServiceException("好友ID不存在");
-
- }
-
-
-
- // 检查是否已经是好友
-
- if (checkFriendship(userId, friendId)) {
-
- throw new ServiceException("已经是好友关系");
-
- }
-
-
-
- // 创建好友关系
-
- Friend friend = new Friend();
-
- friend.setUserId(userId);
-
- friend.setFriendId(friendId);
-
- friend.setStatus(1);
-
- friend.setCreateTime(new Date());
-
- friend.setUpdateTime(new Date());
-
-
-
- // 保存双向好友关系
-
- if (!this.save(friend)) {
-
- throw new ServiceException("添加好友失败");
-
- }
-
-
-
- // 创建反向好友关系
-
- Friend reverseFriend = new Friend();
-
- reverseFriend.setUserId(friendId);
-
- reverseFriend.setFriendId(userId);
-
- reverseFriend.setStatus(1);
-
- reverseFriend.setCreateTime(new Date());
-
- reverseFriend.setUpdateTime(new Date());
-
-
-
- if (!this.save(reverseFriend)) {
-
- throw new ServiceException("添加好友失败");
-
- }
-
- }
-
- private boolean isUserExists(String userId) {
-
- return memberMapper.selectById(userId) != null;
-
- }
-
-
-
- @Override
-
public void updateRemark(String userId, String friendId, String remark) {
-
- LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
-
- queryWrapper.eq(Friend::getUserId, userId)
-
- .eq(Friend::getFriendId, friendId);
-
-
-
- Friend friend = this.getOne(queryWrapper);
-
- if (friend == null) {
-
- throw new ServiceException("好友关系不存在");
-
+ // 验证用户登录状态
+ AuthUser currentUser = UserContext.getCurrentUser();
+ if (currentUser == null) {
+ throw new ServiceException(ResultCode.USER_NOT_LOGIN);
}
-
-
- friend.setRemark(remark);
-
- friend.setUpdateTime(new Date());
-
-
-
- if (!this.updateById(friend)) {
-
- throw new ServiceException("更新好友备注失败");
-
+ // 验证操作权限
+ if (!currentUser.getId().equals(userId)) {
+ throw new ServiceException(ResultCode.USER_AUTHORITY_ERROR);
}
- }
-
-
-
- /**
-
- * 检查是否已经是好友关系
-
- */
-
- private boolean checkFriendship(String userId, String friendId) {
-
+ // 更新备注
LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
-
queryWrapper.eq(Friend::getUserId, userId)
-
.eq(Friend::getFriendId, friendId)
-
.eq(Friend::getStatus, 1);
- return this.count(queryWrapper) > 0;
+ Friend friend = this.getOne(queryWrapper);
+ if (friend == null) {
+ throw new ServiceException("未关注该用户");
+ }
+ friend.setRemark(remark);
+ friend.setUpdateTime(new Date());
+
+ if (!this.updateById(friend)) {
+ throw new ServiceException("更新备注失败");
+ }
}
+ @Override
+ public void addFriendByMobile(String mobile, String remark) {
+ // 查找目标用户
+ Member targetMember = memberService.findByMobile(mobile);
+ if (targetMember == null) {
+ throw new ServiceException("该手机号未注册");
+ }
+ String currentUserId = UserContext.getCurrentUser().getId();
+ String targetUserId = targetMember.getId().toString();
+ // 不能关注自己
+ if (currentUserId.equals(targetUserId)) {
+ throw new ServiceException("不能关注自己");
+ }
+ // 检查是否已经关注
+ if (isFollowing(currentUserId, targetUserId) > 0) {
+ throw new ServiceException("已经关注该用户");
+ }
-}
+ // 创建关注关系
+ Friend friend = new Friend();
+ friend.setUserId(currentUserId);
+ friend.setFriendId(targetUserId);
+ friend.setRemark(remark);
+ friend.setStatus(1);
+ friend.setIsMutual(1); // 直接设置为已关注状态
+ friend.setStoreFlag(targetMember.getHaveStore() ? 1 : 0); // 设置是否是店铺
+ friend.setCreateTime(new Date());
+// friend.setUpdateTime(new Date());
+
+ // 检查对方是否也关注了当前用户
+ Integer mutualStatus = isFollowing(targetUserId, currentUserId);
+
+ // 设置互相关注状态
+ if (mutualStatus == 1) {
+ friend.setIsMutual(2); // 设置为互相关注
+ } else {
+ friend.setIsMutual(1); // 设置为单向关注
+ }
+
+ // 保存关注关系
+ this.save(friend);
+ }
+
+ /**
+ * 检查是否是好友关系(互相关注)
+ */
+ private Integer isFriend(String userId, String friendId) {
+ // 检查是否互相关注
+ Integer isUserFollowingFriend = isFollowing(userId, friendId);
+ Integer isFriendFollowingUser = isFollowing(friendId, userId);
+
+ // 如果双方都关注,返回 2;如果只有一个方向关注,返回 1;否则返回 0
+ if (isUserFollowingFriend == 1 && isFriendFollowingUser == 1) {
+ return 2; // 互相关注
+ } else if (isUserFollowingFriend == 1 || isFriendFollowingUser == 1) {
+ return 1; // 单向关注
+ }
+ return 0; // 未关注
+ }
+ /**
+ * 检查是否已关注
+ */
+ public Integer isFollowing(String currentUserId, String targetUserId) {
+ // 查询当前用户是否关注目标用户
+ Long count = friendMapper.selectCount(new LambdaQueryWrapper()
+ .eq(Friend::getUserId, currentUserId)
+ .eq(Friend::getFriendId, targetUserId)
+ .eq(Friend::getIsMutual, 1)); // 确保状态为已关注
+
+ if (count > 0) {
+ // 查询目标用户是否也关注当前用户
+ Long mutualCount = friendMapper.selectCount(new LambdaQueryWrapper()
+ .eq(Friend::getUserId, targetUserId)
+ .eq(Friend::getFriendId, currentUserId)
+ .eq(Friend::getIsMutual, 1)); // 确保状态为已关注
+
+ return mutualCount > 0 ? 2 : 1; // 2 表示互相关注,1 表示单向关注
+ }
+
+ return 0; // 未关注
+ }
+
+ @Override
+ public List searchUsers(String keyword, Boolean onlyStore, String currentUserId) {
+ // 构建查询条件
+ LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
+ queryWrapper.and(wrapper -> wrapper
+ .like(Member::getNickName, keyword)
+ .or()
+ .like(Member::getMobile, keyword)
+ )
+ .ne(Member::getId, currentUserId); // 排除自己
+
+ if (Boolean.TRUE.equals(onlyStore)) {
+ queryWrapper.eq(Member::getHaveStore, true);
+ }
+
+ // 限制返回数量
+ queryWrapper.last("LIMIT 20");
+
+ // 查询用户
+ List members = memberService.list(queryWrapper);
+ if (members.isEmpty()) {
+ return new ArrayList<>();
+ }
+
+ // 获取已关注的用户ID
+ List memberIds = members.stream()
+ .map(member -> member.getId().toString())
+ .distinct() // 确保唯一
+ .collect(Collectors.toList());
+
+ // 查询当前用户与这些用户的关注关系
+ LambdaQueryWrapper friendWrapper = new LambdaQueryWrapper<>();
+ friendWrapper.eq(Friend::getUserId, currentUserId)
+ .in(Friend::getFriendId, memberIds)
+ .eq(Friend::getStatus, 1);
+ List friends = this.list(friendWrapper);
+
+ // 构建已关注用户的Map
+ Map friendMap = friends.stream()
+ .collect(Collectors.toMap(Friend::getFriendId, friend -> friend, (existing, replacement) -> existing)); // 处理重复键
+
+ // 转换为VO对象
+ return members.stream().map(member -> {
+ FriendVO vo = new FriendVO();
+ vo.setId(member.getId().toString());
+ vo.setNickname(member.getNickName());
+ vo.setAvatar(member.getFace());
+ vo.setRegion(member.getRegion());
+ vo.setMobile(member.getMobile());
+ vo.setStoreFlag(member.getHaveStore() ? 1 : 0);
+
+ // 设置是否互相关注
+ Friend friend = friendMap.get(member.getId().toString());
+ if (friend != null) {
+ vo.setFriendId(friend.getId());
+ vo.setRemark(friend.getRemark());
+ vo.setCreateTime(friend.getCreateTime());
+ // 检查是否互相关注
+ vo.setIsMutual(friend.getIsMutual() != null ? friend.getIsMutual() : 0);
+ } else {
+ vo.setIsMutual(0); // 如果没有找到对应的 Friend 记录,设置为 0
+ }
+
+ return vo;
+ }).distinct() // 确保返回的 VO 对象唯一
+ .collect(Collectors.toList());
+ }
+}
\ No newline at end of file
diff --git a/framework/src/main/java/cn/lili/modules/im/serviceimpl/ImGroupServiceImpl.java b/framework/src/main/java/cn/lili/modules/im/serviceimpl/ImGroupServiceImpl.java
index 9a0a1e87..29add1d0 100644
--- a/framework/src/main/java/cn/lili/modules/im/serviceimpl/ImGroupServiceImpl.java
+++ b/framework/src/main/java/cn/lili/modules/im/serviceimpl/ImGroupServiceImpl.java
@@ -1,50 +1,216 @@
package cn.lili.modules.im.serviceimpl;
+import cn.lili.common.enums.ResultCode;
+import cn.lili.common.security.AuthUser;
import cn.lili.common.security.context.UserContext;
import cn.lili.common.exception.ServiceException;
import cn.lili.modules.im.entity.dos.ImGroup;
import cn.lili.modules.im.entity.dos.ImGroupMember;
+import cn.lili.modules.im.entity.vo.ImGroupMemberVO;
+import cn.lili.modules.im.entity.vo.ImGroupVO;
import cn.lili.modules.im.mapper.ImGroupMapper;
import cn.lili.modules.im.mapper.ImGroupMemberMapper;
import cn.lili.modules.im.service.ImGroupService;
+import cn.lili.modules.im.service.FriendService;
+import cn.lili.modules.im.entity.vo.FriendVO;
+import cn.lili.modules.member.entity.dos.Member;
+import cn.lili.modules.member.mapper.MemberMapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.List;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.stream.Collectors;
@Service
-@RequiredArgsConstructor
+@Transactional(rollbackFor = Exception.class)
+@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class ImGroupServiceImpl extends ServiceImpl implements ImGroupService {
private final ImGroupMemberMapper groupMemberMapper;
+ private final MemberMapper memberMapper;
+ private final FriendService friendService;
@Override
- @Transactional(rollbackFor = Exception.class)
- public ImGroup createGroup(String groupName, List memberIds) {
+ public List getUserGroups(String userId) {
+ // 查询用户加入的群组
+ LambdaQueryWrapper memberQuery = new LambdaQueryWrapper<>();
+ memberQuery.eq(ImGroupMember::getMemberId, userId);
+ List groupMembers = groupMemberMapper.selectList(memberQuery);
+
+ if (groupMembers.isEmpty()) {
+ return new ArrayList<>();
+ }
+
+ // 获取群组ID列表
+ List groupIds = groupMembers.stream()
+ .map(ImGroupMember::getGroupId)
+ .collect(Collectors.toList());
+
+ // 批量查询群组信息
+ List groups = this.listByIds(groupIds);
+
+ // 转换为VO对象
+ return groups.stream().map(group -> {
+ ImGroupVO vo = new ImGroupVO();
+ BeanUtils.copyProperties(group, vo);
+
+ // 设置成员数量
+ vo.setMemberCount(getGroupMemberCount(group.getId()));
+
+ // TODO: 设置最后一条消息和未读数
+
+ return vo;
+ }).collect(Collectors.toList());
+ }
+
+ @Override
+ public ImGroupVO getGroupDetail(String groupId) {
+ // 获取群组基本信息
+ ImGroup group = this.getById(groupId);
+ if (group == null) {
+ throw new ServiceException("群组不存在");
+ }
+
+ // 转换为VO
+ ImGroupVO vo = new ImGroupVO();
+ BeanUtils.copyProperties(group, vo);
+
+ // 设置成员数量
+ vo.setMemberCount(getGroupMemberCount(groupId));
+
+ // TODO: 设置最后一条消息和未读数
+
+ return vo;
+ }
+
+ @Override
+ public List getGroupMembers(String groupId) {
+ // 查询群成员
+ LambdaQueryWrapper memberQuery = new LambdaQueryWrapper<>();
+ memberQuery.eq(ImGroupMember::getGroupId, groupId)
+ .orderByDesc(ImGroupMember::getRole)
+ .orderByAsc(ImGroupMember::getJoinTime);
+
+ List members = groupMemberMapper.selectList(memberQuery);
+
+ if (members.isEmpty()) {
+ return new ArrayList<>();
+ }
+
+ // 获取成员用户信息
+ List memberIds = members.stream()
+ .map(ImGroupMember::getMemberId)
+ .collect(Collectors.toList());
+
+ List users = memberMapper.selectBatchIds(memberIds);
+ Map userMap = users.stream()
+ .collect(Collectors.toMap(member -> member.getId().toString(), member -> member));
+
+ // 转换为VO
+ return members.stream().map(member -> {
+ ImGroupMemberVO vo = new ImGroupMemberVO();
+ BeanUtils.copyProperties(member, vo);
+
+ Member user = userMap.get(member.getMemberId());
+ if (user != null) {
+ vo.setNickname(user.getNickName());
+ vo.setAvatar(user.getFace());
+ }
+
+ return vo;
+ }).collect(Collectors.toList());
+ }
+
+ @Override
+ public void quitGroup(String groupId, String userId) {
+ // 验证群组是否存在
+ ImGroup group = this.getById(groupId);
+ if (group == null) {
+ throw new ServiceException("群组不存在");
+ }
+
+ // 群主不能退群
+ if (group.getOwnerId().equals(userId)) {
+ throw new ServiceException("群主不能退群");
+ }
+
+ // 删除群成员记录
+ LambdaQueryWrapper memberQuery = new LambdaQueryWrapper<>();
+ memberQuery.eq(ImGroupMember::getGroupId, groupId)
+ .eq(ImGroupMember::getMemberId, userId);
+
+ groupMemberMapper.delete(memberQuery);
+ }
+
+ @Override
+ public void updateGroupInfo(String groupId, String groupName, String notice, String avatar) {
+ // 验证群组是否存在
+ ImGroup group = this.getById(groupId);
+ if (group == null) {
+ throw new ServiceException("群组不存在");
+ }
+
+ // 验证操作权限
String currentUserId = UserContext.getCurrentUser().getId();
+ LambdaQueryWrapper memberQuery = new LambdaQueryWrapper<>();
+ memberQuery.eq(ImGroupMember::getGroupId, groupId)
+ .eq(ImGroupMember::getMemberId, currentUserId)
+ .ge(ImGroupMember::getRole, 1); // 管理员及以上权限
+
+ if (groupMemberMapper.selectCount(memberQuery) == 0) {
+ throw new ServiceException("没有权限修改群信息");
+ }
+
+ // 更新群信息
+ ImGroup updateGroup = new ImGroup();
+ updateGroup.setId(groupId);
+ if (groupName != null) {
+ updateGroup.setName(groupName);
+ }
+ if (notice != null) {
+ updateGroup.setNotice(notice);
+ }
+ if (avatar != null) {
+ updateGroup.setAvatar(avatar);
+ }
+ updateGroup.setUpdateTime(new Date());
+
+ this.updateById(updateGroup);
+ }
+
+ @Override
+ public ImGroup createGroup(String groupName, List memberIds) {
+ AuthUser currentUser = UserContext.getCurrentUser();
+ if (currentUser == null) {
+ throw new ServiceException(ResultCode.USER_NOT_LOGIN);
+ }
// 创建群组
ImGroup group = new ImGroup();
group.setName(groupName);
- group.setOwnerId(currentUserId);
+ group.setOwnerId(currentUser.getId());
group.setCreateTime(new Date());
group.setUpdateTime(new Date());
-
+
if (!this.save(group)) {
- throw new ServiceException("创建群聊失败");
+ throw new ServiceException("创建群组失败");
}
- // 添加群主为成员
- addGroupMember(group.getId(), currentUserId, 2);
+ // 添加群主为群成员
+ addGroupMember(group.getId(), currentUser.getId(), 2); // 2表示群主
- // 添加其他成员
+ // 添加初始成员
if (memberIds != null && !memberIds.isEmpty()) {
for (String memberId : memberIds) {
- addGroupMember(group.getId(), memberId, 0);
+ addGroupMember(group.getId(), memberId, 0); // 0表示普通成员
}
}
@@ -52,20 +218,23 @@ public class ImGroupServiceImpl extends ServiceImpl impl
}
@Override
- @Transactional(rollbackFor = Exception.class)
public void dismissGroup(String groupId) {
- String currentUserId = UserContext.getCurrentUser().getId();
+ // 验证群组是否存在
+ ImGroup group = this.getById(groupId);
+ if (group == null) {
+ throw new ServiceException("群组不存在");
+ }
- // 检查是否是群主
- ImGroupMember owner = getGroupMember(groupId, currentUserId);
- if (owner == null || owner.getRole() != 2) {
- throw new ServiceException("只有群主能解散群聊");
+ // 验证是否是群主
+ String currentUserId = UserContext.getCurrentUser().getId();
+ if (!group.getOwnerId().equals(currentUserId)) {
+ throw new ServiceException("只有群主能解散群组");
}
// 删除群成员
- LambdaQueryWrapper memberWrapper = new LambdaQueryWrapper<>();
- memberWrapper.eq(ImGroupMember::getGroupId, groupId);
- groupMemberMapper.delete(memberWrapper);
+ LambdaQueryWrapper memberQuery = new LambdaQueryWrapper<>();
+ memberQuery.eq(ImGroupMember::getGroupId, groupId);
+ groupMemberMapper.delete(memberQuery);
// 删除群组
this.removeById(groupId);
@@ -75,13 +244,13 @@ public class ImGroupServiceImpl extends ServiceImpl impl
@Transactional(rollbackFor = Exception.class)
public void inviteMembers(String groupId, List memberIds) {
String currentUserId = UserContext.getCurrentUser().getId();
-
+
// 检查权限
ImGroupMember operator = getGroupMember(groupId, currentUserId);
if (operator == null || operator.getRole() < 1) {
throw new ServiceException("没有邀请权限");
}
-
+
// 添加成员
for (String memberId : memberIds) {
if (getGroupMember(groupId, memberId) == null) {
@@ -94,19 +263,19 @@ public class ImGroupServiceImpl extends ServiceImpl impl
@Transactional(rollbackFor = Exception.class)
public void setAdmin(String groupId, String memberId) {
String currentUserId = UserContext.getCurrentUser().getId();
-
+
// 检查是否是群主
ImGroupMember owner = getGroupMember(groupId, currentUserId);
if (owner == null || owner.getRole() != 2) {
throw new ServiceException("只有群主能设置管理员");
}
-
+
// 设置管理员
ImGroupMember member = getGroupMember(groupId, memberId);
if (member == null) {
throw new ServiceException("该成员不在群中");
}
-
+
member.setRole(1);
member.setUpdateTime(new Date());
groupMemberMapper.updateById(member);
@@ -116,19 +285,19 @@ public class ImGroupServiceImpl extends ServiceImpl impl
@Transactional(rollbackFor = Exception.class)
public void removeAdmin(String groupId, String memberId) {
String currentUserId = UserContext.getCurrentUser().getId();
-
+
// 检查是否是群主
ImGroupMember owner = getGroupMember(groupId, currentUserId);
if (owner == null || owner.getRole() != 2) {
throw new ServiceException("只有群主能取消管理员");
}
-
+
// 取消管理员
ImGroupMember member = getGroupMember(groupId, memberId);
if (member == null) {
throw new ServiceException("该成员不在群中");
}
-
+
member.setRole(0);
member.setUpdateTime(new Date());
groupMemberMapper.updateById(member);
@@ -138,24 +307,24 @@ public class ImGroupServiceImpl extends ServiceImpl impl
@Transactional(rollbackFor = Exception.class)
public void muteMember(String groupId, String memberId, Integer duration) {
String currentUserId = UserContext.getCurrentUser().getId();
-
+
// 检查操作权限
ImGroupMember operator = getGroupMember(groupId, currentUserId);
if (operator == null || operator.getRole() < 1) {
throw new ServiceException("没有禁言权限");
}
-
+
// 检查被禁言成员
ImGroupMember member = getGroupMember(groupId, memberId);
if (member == null) {
throw new ServiceException("该成员不在群中");
}
-
+
// 管理员不能禁言群主和其他管理员
if (operator.getRole() == 1 && member.getRole() > 0) {
throw new ServiceException("没有权限禁言该成员");
}
-
+
// 设置禁言
member.setIsMuted(1);
member.setMuteEndTime(new Date(System.currentTimeMillis() + duration * 60 * 1000));
@@ -167,24 +336,24 @@ public class ImGroupServiceImpl extends ServiceImpl impl
@Transactional(rollbackFor = Exception.class)
public void unmuteMember(String groupId, String memberId) {
String currentUserId = UserContext.getCurrentUser().getId();
-
+
// 检查操作权限
ImGroupMember operator = getGroupMember(groupId, currentUserId);
if (operator == null || operator.getRole() < 1) {
throw new ServiceException("没有解除禁言权限");
}
-
+
// 检查被解除禁言成员
ImGroupMember member = getGroupMember(groupId, memberId);
if (member == null) {
throw new ServiceException("该成员不在群中");
}
-
+
// 管理员不能解除群主和其他管理员的禁言
if (operator.getRole() == 1 && member.getRole() > 0) {
throw new ServiceException("没有权限解除该成员的禁言");
}
-
+
// 解除禁言
member.setIsMuted(0);
member.setMuteEndTime(null);
@@ -192,6 +361,15 @@ public class ImGroupServiceImpl extends ServiceImpl impl
groupMemberMapper.updateById(member);
}
+ /**
+ * 获取群成员数量
+ */
+ private Integer getGroupMemberCount(String groupId) {
+ LambdaQueryWrapper countQuery = new LambdaQueryWrapper<>();
+ countQuery.eq(ImGroupMember::getGroupId, groupId);
+ return Math.toIntExact(groupMemberMapper.selectCount(countQuery));
+ }
+
/**
* 添加群成员
*/
@@ -200,9 +378,9 @@ public class ImGroupServiceImpl extends ServiceImpl impl
member.setGroupId(groupId);
member.setMemberId(memberId);
member.setRole(role);
- member.setIsMuted(0);
member.setJoinTime(new Date());
- member.setUpdateTime(new Date());
+ member.setIsMuted(0);
+
groupMemberMapper.insert(member);
}
@@ -212,7 +390,16 @@ public class ImGroupServiceImpl extends ServiceImpl impl
private ImGroupMember getGroupMember(String groupId, String memberId) {
LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(ImGroupMember::getGroupId, groupId)
- .eq(ImGroupMember::getMemberId, memberId);
+ .eq(ImGroupMember::getMemberId, memberId);
return groupMemberMapper.selectOne(queryWrapper);
}
-}
\ No newline at end of file
+
+ /**
+ * 检查是否是好友关系
+ */
+ private boolean isFriend(String userId, String friendId) {
+ List friends = friendService.getMutualFriends(userId);
+ return friends.stream()
+ .anyMatch(friend -> friend.getFriendId().equals(friendId));
+ }
+}
\ No newline at end of file
diff --git a/framework/src/main/java/cn/lili/modules/im/serviceimpl/ImMessageServiceImpl.java b/framework/src/main/java/cn/lili/modules/im/serviceimpl/ImMessageServiceImpl.java
index 6e75529d..758d31d3 100644
--- a/framework/src/main/java/cn/lili/modules/im/serviceimpl/ImMessageServiceImpl.java
+++ b/framework/src/main/java/cn/lili/modules/im/serviceimpl/ImMessageServiceImpl.java
@@ -6,10 +6,12 @@ import cn.lili.common.security.AuthUser;
import cn.lili.common.security.context.UserContext;
import cn.lili.common.security.enums.UserEnums;
import cn.lili.modules.im.entity.dos.ImMessage;
+import cn.lili.modules.im.entity.dos.ImTalk;
import cn.lili.modules.im.entity.dto.MessageQueryParams;
import cn.lili.modules.im.mapper.ImMessageMapper;
import cn.lili.modules.im.service.ImMessageService;
import cn.lili.modules.im.service.ImTalkService;
+import cn.lili.modules.im.websocket.WebSocketServer;
import cn.lili.mybatis.util.PageUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
@@ -19,9 +21,14 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Objects;
+import java.util.*;
+import java.util.stream.Collectors;
+
+import cn.lili.modules.im.entity.vo.ImMessageVO;
+import cn.lili.modules.im.entity.dos.ImGroup;
+import cn.lili.modules.im.mapper.ImGroupMapper;
+import cn.lili.modules.im.entity.vo.MessageOperation;
+import cn.lili.common.vo.ResultPageVO;
/**
* Im消息 业务实现
@@ -33,8 +40,26 @@ import java.util.Objects;
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class ImMessageServiceImpl extends ServiceImpl implements ImMessageService {
+// @Autowired
+// private final WebSocketServer imTalkService;
+
@Autowired
- private ImTalkService imTalkService;
+ private ImGroupMapper imGroupMapper;
+
+ @Override
+ public List getHistoryMessages(String talkId, String earliestMsgId, Integer pageSize) {
+ return null;
+ }
+
+ @Override
+ public List getRecentMessages(String talkId, String latestMsgId, Integer pageSize) {
+ return null;
+ }
+
+ @Override
+ public ImMessageVO sendMessage(String toId, String content, String type) {
+ return null;
+ }
@Override
public void read(String talkId, String accessToken) {
@@ -43,6 +68,7 @@ public class ImMessageServiceImpl extends ServiceImpl queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(ImMessage::getToUser, userId);
- queryWrapper.eq(ImMessage::getIsRead, false);
+// queryWrapper.eq(ImMessage::getIsRead, false);
return this.list(queryWrapper);
}
@@ -77,12 +103,23 @@ public class ImMessageServiceImpl extends ServiceImpl getList(MessageQueryParams messageQueryParams) {
- List messageList = this.page(PageUtil.initPage(messageQueryParams), messageQueryParams.initQueryWrapper()).getRecords();
+ // 使用 LambdaQueryWrapper 创建查询条件
+ LambdaQueryWrapper queryWrapper = messageQueryParams.initQueryWrapper();
+
+ // 关联查询,假设 ImTalkMapper 是你的 Mapper 类
+ queryWrapper.eq(ImMessage::getTalkId, messageQueryParams.getTalkId());
+
+ // 执行分页查询
+ List messageList = this.page(PageUtil.initPage(messageQueryParams), queryWrapper).getRecords();
+
+ // 对消息列表进行排序和已读处理
ListSort(messageList);
readMessage(messageList);
+
return messageList;
}
+
@Override
public Long unreadMessageCount() {
AuthUser currentUser = UserContext.getCurrentUser();
@@ -101,6 +138,63 @@ public class ImMessageServiceImpl extends ServiceImpl().eq(ImMessage::getToUser,currentUser.getId()).set(ImMessage::getIsRead,true));
}
+ @Override
+ public ResultPageVO getGroupMessages(String groupId, Integer pageNumber, Integer pageSize) {
+ List messages = this.getMessagesByGroupId(groupId, pageNumber, pageSize);
+
+ List messageVOs = messages.stream()
+ .map(message -> new ImMessageVO())
+ .collect(Collectors.toList());
+
+ Long total = this.count(new LambdaQueryWrapper().eq(ImMessage::getGroupId, groupId));
+
+ return new ResultPageVO<>(total, (long) Math.ceil((double) total / pageSize), (long) pageNumber, (long) pageSize, messageVOs);
+ }
+
+ @Override
+ public ImMessageVO sendGroupMessage(String groupId, String content, String type) {
+ ImMessage imMessage = new ImMessage();
+ imMessage.setText(content);
+ imMessage.setType(type);
+ imMessage.setGroupId(groupId);
+ imMessage.setCreateTime(new Date());
+
+ this.save(imMessage);
+
+ return new ImMessageVO();
+ }
+
+ @Override
+ public void recallMessage(String messageId) {
+
+ }
+
+ @Override
+ public List loadHistoryMessages(String talkId, String earliestMsgId, Integer size) {
+ return null;
+ }
+
+ @Override
+ public List loadLatestMessages(String talkId, Integer size) {
+ return null;
+ }
+
+ @Override
+ public List getNewerMessages(String talkId, String latestMsgId) {
+ return null;
+ }
+
+ @Override
+ public void readMessages(List messages, String userId) {
+
+ }
+
+ private List getMessagesByGroupId(String groupId, Integer pageNumber, Integer pageSize) {
+ return this.list(new LambdaQueryWrapper().eq(ImMessage::getGroupId, groupId)
+ .orderByDesc(ImMessage::getCreateTime)
+ .last("LIMIT " + (pageNumber - 1) * pageSize + ", " + pageSize));
+ }
+
/**
* 根据时间倒叙
*
@@ -144,6 +238,7 @@ public class ImMessageServiceImpl extends ServiceImpl implements ImTalkService {
+ private final ImMessageService imMessageService;
+ @Autowired
+ public ImTalkServiceImpl(@Lazy ImMessageService imMessageService) {
+ this.imMessageService = imMessageService;
+ }
+@Autowired
+FriendMapper friendMapper;
@Autowired
private MemberService memberService;
@Autowired
private StoreService storeService;
- @Autowired
- private ImMessageService imMessageService;
-
public ImTalk getTalkByUser(String userId) {
LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
AuthUser currentUser = Objects.requireNonNull(UserContext.getCurrentUser());
@@ -180,14 +192,52 @@ public class ImTalkServiceImpl extends ServiceImpl impleme
if (authUser == null) {
throw new ServiceException(ResultCode.USER_NOT_LOGIN);
}
+
LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.and(wq -> wq.eq(ImTalk::getUserId1, authUser.getId()).or().eq(ImTalk::getUserId2, authUser.getId()));
+
if (CharSequenceUtil.isNotEmpty(imTalkQueryParams.getUserName())) {
- queryWrapper.and(wq -> wq.ne(ImTalk::getUserId1, authUser.getId()).like(ImTalk::getName1, imTalkQueryParams.getUserName()).or().ne(ImTalk::getUserId2, authUser.getId()).like(ImTalk::getName2, imTalkQueryParams.getUserName()));
+ queryWrapper.and(wq -> wq.ne(ImTalk::getUserId1, authUser.getId())
+ .like(ImTalk::getName1, imTalkQueryParams.getUserName())
+ .or()
+ .ne(ImTalk::getUserId2, authUser.getId())
+ .like(ImTalk::getName2, imTalkQueryParams.getUserName()));
}
+
queryWrapper.orderByDesc(ImTalk::getLastTalkTime);
List imTalks = this.list(queryWrapper);
- List imTalkVOList = imTalks.stream().map(imTalk -> new ImTalkVO(imTalk, authUser.getId())).collect(Collectors.toList());
+
+ // 获取好友关系
+ List friendIds = imTalks.stream()
+ .flatMap(imTalk -> Stream.of(imTalk.getUserId1(), imTalk.getUserId2()))
+ .distinct()
+ .collect(Collectors.toList());
+
+ // 查询好友关系
+ List friends = friendMapper.selectList(new LambdaQueryWrapper()
+ .in(Friend::getFriendId, friendIds)
+ .eq(Friend::getUserId, authUser.getId())
+ .eq(Friend::getStatus, 1)); // 只查询状态为1的记录
+
+ // 创建一个 Set 来存储已关注的用户 ID
+ Set mutualFriends = friends.stream()
+ .map(Friend::getFriendId)
+ .collect(Collectors.toSet());
+
+ // 更新 isMutual 字段
+ for (ImTalk imTalk : imTalks) {
+ if (mutualFriends.contains(imTalk.getUserId1()) || mutualFriends.contains(imTalk.getUserId2())) {
+ imTalk.setIsMutual(1); // 设置为单向关注
+ } else {
+ imTalk.setIsMutual(0); // 设置为未关注
+ }
+ }
+
+ // 将更新后的 imTalk 转换为 VO 对象
+ List imTalkVOList = imTalks.stream()
+ .map(imTalk -> new ImTalkVO(imTalk, authUser.getId()))
+ .collect(Collectors.toList());
+
getUnread(imTalkVOList);
return imTalkVOList;
}
diff --git a/im-api/src/main/java/cn/lili/controller/im/WebSocketServer.java b/framework/src/main/java/cn/lili/modules/im/websocket/WebSocketServer.java
similarity index 62%
rename from im-api/src/main/java/cn/lili/controller/im/WebSocketServer.java
rename to framework/src/main/java/cn/lili/modules/im/websocket/WebSocketServer.java
index 509b2706..70a5b48c 100644
--- a/im-api/src/main/java/cn/lili/controller/im/WebSocketServer.java
+++ b/framework/src/main/java/cn/lili/modules/im/websocket/WebSocketServer.java
@@ -1,7 +1,8 @@
-package cn.lili.controller.im;
+package cn.lili.modules.im.websocket;
import cn.hutool.json.JSONUtil;
import cn.lili.cache.Cache;
+import cn.lili.common.exception.ServiceException;
import cn.lili.common.security.AuthUser;
import cn.lili.common.security.context.UserContext;
import cn.lili.common.security.enums.UserEnums;
@@ -13,8 +14,11 @@ import cn.lili.modules.im.entity.vo.MessageOperation;
import cn.lili.modules.im.entity.vo.MessageVO;
import cn.lili.modules.im.service.ImMessageService;
import cn.lili.modules.im.service.ImTalkService;
+import cn.lili.modules.member.entity.dos.Member;
+import cn.lili.modules.member.service.MemberService;
import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
@@ -40,6 +44,7 @@ import org.springframework.stereotype.Component;
@Slf4j
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class WebSocketServer {
+ private final MemberService memberService;
/**
* 在线人数 PS 注意,只能单节点,如果多节点部署需要自行寻找方案
*/
@@ -107,21 +112,36 @@ public class WebSocketServer {
* @param messageOperation
*/
private void operation(String accessToken, MessageOperation messageOperation) {
-
AuthUser authUser = UserContext.getAuthUser(accessToken);
+
switch (messageOperation.getOperationType()) {
case PING:
break;
case MESSAGE:
- //保存消息
+ // 获取或创建聊天记录
+ ImTalk imTalk = getOrCreateTalk(authUser.getId(), messageOperation.getTo());
+
+ // 如果 imTalk 为 null,说明创建失败,记录日志并返回
+ if (imTalk == null) {
+ log.warn("Failed to create ImTalk for users: {} and {}", authUser.getId(), messageOperation.getTo());
+ return; // 或者抛出异常
+ }
+
+ // 保存消息
ImMessage imMessage = new ImMessage(messageOperation);
+ imMessage.setCreateBy(authUser.getNickName());
+ imMessage.setTalkId(imTalk.getId()); // 设置 talk_id 为 imTalk 的 id
imMessageService.save(imMessage);
- //修改最后消息信息
- imTalkService.update(new LambdaUpdateWrapper().eq(ImTalk::getId, messageOperation.getTalkId())
- .set(ImTalk::getLastTalkMessage, messageOperation.getContext())
- .set(ImTalk::getLastTalkTime, imMessage.getCreateTime())
- .set(ImTalk::getLastMessageType, imMessage.getMessageType()));
- //发送消息
+ log.info("Message saved: {}", imMessage);
+
+ // 更新最后消息信息
+ imTalkService.update(new LambdaUpdateWrapper()
+ .eq(ImTalk::getId, imTalk.getId())
+ .set(ImTalk::getLastTalkMessage, messageOperation.getContext())
+ .set(ImTalk::getLastTalkTime, imMessage.getCreateTime())
+ .set(ImTalk::getLastMessageType, imMessage.getMessageType()));
+
+ // 发送消息
sendMessage(messageOperation.getTo(), new MessageVO(MessageResultType.MESSAGE, imMessage));
break;
case READ:
@@ -131,17 +151,55 @@ public class WebSocketServer {
break;
case UNREAD:
sendMessage(authUser.getId(),
- new MessageVO(MessageResultType.UN_READ, imMessageService.unReadMessages(accessToken)));
+ new MessageVO(MessageResultType.UN_READ, imMessageService.unReadMessages(accessToken)));
break;
case HISTORY:
sendMessage(authUser.getId(), new MessageVO(MessageResultType.HISTORY,
- imMessageService.historyMessage(accessToken, messageOperation.getTo())));
+ imMessageService.historyMessage(accessToken, messageOperation.getTo())));
break;
default:
break;
}
}
+ // 获取或创建聊天记录
+ public ImTalk getOrCreateTalk(String userId1, String userId2) {
+ // 查询现有的聊天记录
+ LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
+ queryWrapper
+ .or().eq(ImTalk::getUserId1, userId1).eq(ImTalk::getUserId2, userId2)
+ .or().eq(ImTalk::getUserId1, userId2).eq(ImTalk::getUserId2, userId1);
+ ImTalk imTalk = imTalkService.getOne(queryWrapper);
+ if (imTalk != null) {
+ log.info("Found existing talk: {}", imTalk);
+ return imTalk;
+ }
+
+ // 如果没有找到,创建新的聊天记录
+ log.info("Creating new talk between {} and {}", userId1, userId2);
+
+ // 获取用户信息
+ Member member1 = memberService.getById(userId1);
+ Member member2 = memberService.getById(userId2);
+
+ // 检查用户是否存在
+ if (member1 == null || member2 == null) {
+ log.warn("One of the members does not exist: member1={}, member2={}", member1, member2);
+ throw new ServiceException("One of the users does not exist."); // 或者根据需要处理
+ }
+
+ String face1 = member1.getFace() != null ? member1.getFace() : ""; // 获取头像
+ String face2 = member2.getFace() != null ? member2.getFace() : ""; // 获取头像
+ String name1 = member1.getNickName() != null ? member1.getNickName() : ""; // 获取昵称
+ String name2 = member2.getNickName() != null ? member2.getNickName() : ""; // 获取昵称
+
+ // 创建新的聊天记录
+ imTalk = new ImTalk(userId1, userId2, face1, face2, name1, name2);
+ imTalkService.save(imTalk);
+ log.info("New talk created: {}", imTalk);
+
+ return imTalk;
+ }
/**
* 发送消息
*
diff --git a/framework/src/main/java/cn/lili/modules/member/entity/dos/Member.java b/framework/src/main/java/cn/lili/modules/member/entity/dos/Member.java
index 8027050a..6763f87a 100644
--- a/framework/src/main/java/cn/lili/modules/member/entity/dos/Member.java
+++ b/framework/src/main/java/cn/lili/modules/member/entity/dos/Member.java
@@ -6,6 +6,8 @@ import cn.lili.common.security.sensitive.enums.SensitiveStrategy;
import cn.lili.common.utils.CommonUtil;
import cn.lili.mybatis.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@@ -31,6 +33,24 @@ public class Member extends BaseEntity {
private static final long serialVersionUID = 1L;
+ @TableId(type = IdType.AUTO)
+ private String id;
+
+ // 创建者
+ private String createBy;
+
+ // 创建时间
+ private Date createTime;
+
+ // 删除标志 true/false
+ private Boolean deleteFlag;
+
+ // 更新者
+ private String updateBy;
+
+ // 更新时间
+ private Date updateTime;
+
@ApiModelProperty(value = "会员用户名")
private String username;
@@ -97,13 +117,13 @@ public class Member extends BaseEntity {
@ApiModelProperty(value = "经验值数量")
private Long experience;
-
public Member(String username, String password, String mobile) {
this.username = username;
this.password = password;
this.mobile = mobile;
this.nickName = CommonUtil.getSpecialStr("用户");
this.disabled = true;
+ this.deleteFlag=false;
this.haveStore = false;
this.sex = 0;
this.point = 0L;
@@ -115,6 +135,7 @@ public class Member extends BaseEntity {
this.username = username;
this.password = password;
this.mobile = mobile;
+ this.deleteFlag=false;
this.nickName = nickName;
this.disabled = true;
this.haveStore = false;
diff --git a/im-api/pom.xml b/im-api/pom.xml
index 8f6efc47..7f823cf4 100644
--- a/im-api/pom.xml
+++ b/im-api/pom.xml
@@ -19,11 +19,6 @@
framework
${revision}