diff --git a/framework/pom.xml b/framework/pom.xml
index 2b359058..8dcc90f7 100644
--- a/framework/pom.xml
+++ b/framework/pom.xml
@@ -15,6 +15,11 @@
jar
+
+ com.belerweb
+ pinyin4j
+ 2.5.1
+
com.qiniu
qiniu-java-sdk
diff --git a/framework/src/main/java/cn/lili/common/exception/ServiceException.java b/framework/src/main/java/cn/lili/common/exception/ServiceException.java
index feb98e6d..754aec2a 100644
--- a/framework/src/main/java/cn/lili/common/exception/ServiceException.java
+++ b/framework/src/main/java/cn/lili/common/exception/ServiceException.java
@@ -15,12 +15,11 @@ public class ServiceException extends RuntimeException {
private static final long serialVersionUID = 3447728300174142127L;
- public static final String DEFAULT_MESSAGE = "网络错误,请稍后重试!";
/**
* 异常消息
*/
- private String msg = DEFAULT_MESSAGE;
+ private String msg = ResultCode.ERROR.message();
/**
* 错误码
diff --git a/framework/src/main/java/cn/lili/controller/im/ImGroupController.java b/framework/src/main/java/cn/lili/controller/im/ImGroupController.java
new file mode 100644
index 00000000..0519ecba
--- /dev/null
+++ b/framework/src/main/java/cn/lili/controller/im/ImGroupController.java
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/framework/src/main/java/cn/lili/modules/im/entity/dos/Friend.java b/framework/src/main/java/cn/lili/modules/im/entity/dos/Friend.java
new file mode 100644
index 00000000..19b45a63
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/im/entity/dos/Friend.java
@@ -0,0 +1,39 @@
+package cn.lili.modules.im.entity.dos;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.Data;
+import java.util.Date;
+
+@Data
+@TableName("li_friend")
+public class Friend {
+
+ @TableId(type = IdType.ASSIGN_ID)
+ private String id;
+
+ // 用户ID
+ private String userId;
+
+ // 好友ID
+ private String friendId;
+
+ // 好友昵称
+ private String nickname;
+
+ // 好友头像
+ private String avatar;
+
+ // 好友备注
+ private String remark;
+
+ // 关系状态 (0:待确认 1:已确认 2:已拒绝 3:已解除)
+ private Integer status;
+
+ // 创建时间
+ private Date createTime;
+
+ // 更新时间
+ private Date updateTime;
+}
\ No newline at end of file
diff --git a/framework/src/main/java/cn/lili/modules/im/entity/dos/ImGroup.java b/framework/src/main/java/cn/lili/modules/im/entity/dos/ImGroup.java
new file mode 100644
index 00000000..1387afef
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/im/entity/dos/ImGroup.java
@@ -0,0 +1,32 @@
+package cn.lili.modules.im.entity.dos;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.Data;
+import java.util.Date;
+
+@Data
+@TableName("li_im_group")
+public class ImGroup {
+ @TableId(type = IdType.ASSIGN_ID)
+ private String id;
+
+ // 群名称
+ private String name;
+
+ // 群头像
+ private String avatar;
+
+ // 群公告
+ private String notice;
+
+ // 群主ID
+ private String ownerId;
+
+ // 创建时间
+ private Date createTime;
+
+ // 更新时间
+ private Date updateTime;
+}
\ No newline at end of file
diff --git a/framework/src/main/java/cn/lili/modules/im/entity/dos/ImGroupMember.java b/framework/src/main/java/cn/lili/modules/im/entity/dos/ImGroupMember.java
new file mode 100644
index 00000000..44151239
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/im/entity/dos/ImGroupMember.java
@@ -0,0 +1,38 @@
+package cn.lili.modules.im.entity.dos;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.Data;
+import java.util.Date;
+
+@Data
+@TableName("li_im_group_member")
+public class ImGroupMember {
+ @TableId(type = IdType.ASSIGN_ID)
+ private String id;
+
+ // 群ID
+ private String groupId;
+
+ // 成员ID
+ private String memberId;
+
+ // 成员昵称
+ private String nickname;
+
+ // 成员角色(0:普通成员 1:管理员 2:群主)
+ private Integer role;
+
+ // 是否被禁言(0:否 1:是)
+ private Integer isMuted;
+
+ // 禁言结束时间
+ private Date muteEndTime;
+
+ // 加入时间
+ private Date joinTime;
+
+ // 更新时间
+ private Date updateTime;
+}
\ 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
new file mode 100644
index 00000000..fe2a1635
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/im/entity/vo/FriendVO.java
@@ -0,0 +1,21 @@
+package cn.lili.modules.im.entity.vo;
+
+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
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
new file mode 100644
index 00000000..2268608b
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/im/mapper/FriendMapper.java
@@ -0,0 +1,10 @@
+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;
+
+@Mapper
+public interface FriendMapper extends BaseMapper {
+}
diff --git a/framework/src/main/java/cn/lili/modules/im/mapper/ImGroupMapper.java b/framework/src/main/java/cn/lili/modules/im/mapper/ImGroupMapper.java
new file mode 100644
index 00000000..c6591941
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/im/mapper/ImGroupMapper.java
@@ -0,0 +1,7 @@
+package cn.lili.modules.im.mapper;
+
+import cn.lili.modules.im.entity.dos.ImGroup;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+public interface ImGroupMapper 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
new file mode 100644
index 00000000..0c9b8d04
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/im/mapper/ImGroupMemberMapper.java
@@ -0,0 +1,8 @@
+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;
+
+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
new file mode 100644
index 00000000..542009c5
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/im/service/FriendService.java
@@ -0,0 +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 com.baomidou.mybatisplus.extension.service.IService;
+
+import java.util.List;
+
+
+
+public interface FriendService extends IService {
+
+
+
+ /**
+
+ * 获取互相关注的好友列表(包含详细信息)
+
+ * @param userId 用户ID
+
+ * @return 好友列表
+
+ */
+
+ List getMutualFriends(String userId);
+
+
+
+ /**
+
+ * 获取好友详细信息
+
+ * @param friendId 好友ID
+
+ * @return 好友详细信息
+
+ */
+
+ FriendVO getFriendDetails(String friendId);
+
+
+
+ /**
+
+ * 解除好友关系
+
+ * @param userId 用户ID
+
+ * @param friendId 好友ID
+
+ */
+
+ void removeFriend(String userId, String friendId);
+
+
+
+ /**
+
+ * 添加好友
+
+ * @param userId 用户ID
+
+ * @param friendId 好友ID
+
+ */
+
+ void addFriend(String userId, String friendId);
+
+
+
+ /**
+
+ * 更新好友备注
+
+ * @param userId 用户ID
+
+ * @param friendId 好友ID
+
+ * @param remark 备注
+
+ */
+
+ void updateRemark(String userId, String friendId, String remark);
+
+}
\ 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
new file mode 100644
index 00000000..23a4454b
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/im/service/ImGroupService.java
@@ -0,0 +1,58 @@
+package cn.lili.modules.im.service;
+
+import cn.lili.modules.im.entity.dos.ImGroup;
+import com.baomidou.mybatisplus.extension.service.IService;
+import java.util.List;
+
+public interface ImGroupService extends IService {
+
+ /**
+ * 创建群聊
+ * @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
+ */
+ void unmuteMember(String groupId, String memberId);
+}
\ 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
new file mode 100644
index 00000000..540e79d2
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/im/serviceimpl/FriendServiceImpl.java
@@ -0,0 +1,344 @@
+package cn.lili.modules.im.serviceimpl;
+import cn.lili.common.security.context.UserContext;
+import cn.lili.common.security.enums.UserEnums;
+import cn.lili.common.exception.ServiceException;
+import cn.lili.common.utils.StringUtils;
+import cn.lili.modules.im.entity.dos.Friend;
+import cn.lili.modules.im.entity.vo.FriendVO;
+import cn.lili.modules.im.mapper.FriendMapper;
+import cn.lili.modules.im.service.FriendService;
+
+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.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.Date;
+import java.util.List;
+import java.util.ArrayList;
+
+import static cn.hutool.extra.pinyin.PinyinUtil.getFirstLetter;
+
+@Slf4j
+@Service
+public class FriendServiceImpl extends ServiceImpl implements FriendService {
+ @Autowired
+ private MemberMapper memberMapper;
+
+ @Override
+ public List getMutualFriends(String userId) {
+ // 获取好友关系列表
+ LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
+ queryWrapper.eq(Friend::getUserId, userId)
+ .eq(Friend::getStatus, 1); // 已确认的好友关系
+ List friends = this.list(queryWrapper);
+
+
+ // 转换为 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);
+ }
+ // 按照昵称首字母排序
+ Collections.sort(friendVOs, (a, b) -> {
+ String letterA = a.getFirstLetter() != null ? a.getFirstLetter() : "#";
+ String letterB = b.getFirstLetter() != null ? b.getFirstLetter() : "#";
+ return letterA.compareTo(letterB);
+ });
+
+
+ return friendVOs;
+ }
+ /**
+ * 获取字符串的首字母
+ * @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();
+
+ // 查询好友关系
+ 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("解除好友关系失败");
+
+ }
+
+ }
+
+
+
+ @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("好友关系不存在");
+
+ }
+
+
+
+ friend.setRemark(remark);
+
+ friend.setUpdateTime(new Date());
+
+
+
+ if (!this.updateById(friend)) {
+
+ throw new ServiceException("更新好友备注失败");
+
+ }
+
+ }
+
+
+
+ /**
+
+ * 检查是否已经是好友关系
+
+ */
+
+ 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;
+
+ }
+
+
+
+
+
+}
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
new file mode 100644
index 00000000..9a0a1e87
--- /dev/null
+++ b/framework/src/main/java/cn/lili/modules/im/serviceimpl/ImGroupServiceImpl.java
@@ -0,0 +1,218 @@
+package cn.lili.modules.im.serviceimpl;
+
+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.mapper.ImGroupMapper;
+import cn.lili.modules.im.mapper.ImGroupMemberMapper;
+import cn.lili.modules.im.service.ImGroupService;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Date;
+import java.util.List;
+
+@Service
+@RequiredArgsConstructor
+public class ImGroupServiceImpl extends ServiceImpl implements ImGroupService {
+
+ private final ImGroupMemberMapper groupMemberMapper;
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public ImGroup createGroup(String groupName, List memberIds) {
+ String currentUserId = UserContext.getCurrentUser().getId();
+
+ // 创建群组
+ ImGroup group = new ImGroup();
+ group.setName(groupName);
+ group.setOwnerId(currentUserId);
+ group.setCreateTime(new Date());
+ group.setUpdateTime(new Date());
+
+ if (!this.save(group)) {
+ throw new ServiceException("创建群聊失败");
+ }
+
+ // 添加群主为成员
+ addGroupMember(group.getId(), currentUserId, 2);
+
+ // 添加其他成员
+ if (memberIds != null && !memberIds.isEmpty()) {
+ for (String memberId : memberIds) {
+ addGroupMember(group.getId(), memberId, 0);
+ }
+ }
+
+ return group;
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void dismissGroup(String groupId) {
+ String currentUserId = UserContext.getCurrentUser().getId();
+
+ // 检查是否是群主
+ ImGroupMember owner = getGroupMember(groupId, currentUserId);
+ if (owner == null || owner.getRole() != 2) {
+ throw new ServiceException("只有群主能解散群聊");
+ }
+
+ // 删除群成员
+ LambdaQueryWrapper memberWrapper = new LambdaQueryWrapper<>();
+ memberWrapper.eq(ImGroupMember::getGroupId, groupId);
+ groupMemberMapper.delete(memberWrapper);
+
+ // 删除群组
+ this.removeById(groupId);
+ }
+
+ @Override
+ @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) {
+ addGroupMember(groupId, memberId, 0);
+ }
+ }
+ }
+
+ @Override
+ @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);
+ }
+
+ @Override
+ @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);
+ }
+
+ @Override
+ @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));
+ member.setUpdateTime(new Date());
+ groupMemberMapper.updateById(member);
+ }
+
+ @Override
+ @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);
+ member.setUpdateTime(new Date());
+ groupMemberMapper.updateById(member);
+ }
+
+ /**
+ * 添加群成员
+ */
+ private void addGroupMember(String groupId, String memberId, Integer role) {
+ ImGroupMember member = new ImGroupMember();
+ member.setGroupId(groupId);
+ member.setMemberId(memberId);
+ member.setRole(role);
+ member.setIsMuted(0);
+ member.setJoinTime(new Date());
+ member.setUpdateTime(new Date());
+ groupMemberMapper.insert(member);
+ }
+
+ /**
+ * 获取群成员信息
+ */
+ private ImGroupMember getGroupMember(String groupId, String memberId) {
+ LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
+ queryWrapper.eq(ImGroupMember::getGroupId, groupId)
+ .eq(ImGroupMember::getMemberId, memberId);
+ return groupMemberMapper.selectOne(queryWrapper);
+ }
+}
\ No newline at end of file
diff --git a/framework/src/main/java/cn/lili/modules/member/mapper/MemberMapper.java b/framework/src/main/java/cn/lili/modules/member/mapper/MemberMapper.java
index 32f09fa9..74031963 100644
--- a/framework/src/main/java/cn/lili/modules/member/mapper/MemberMapper.java
+++ b/framework/src/main/java/cn/lili/modules/member/mapper/MemberMapper.java
@@ -9,6 +9,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
+import org.mapstruct.Mapper;
import java.util.List;
@@ -17,7 +18,9 @@ import java.util.List;
*
* @author Bulbasaur
* @since 2020-02-25 14:10:16
+ * @
*/
+@Mapper
public interface MemberMapper extends BaseMapper {
/**
diff --git a/im-api/src/main/java/cn/lili/controller/im/FriendController.java b/im-api/src/main/java/cn/lili/controller/im/FriendController.java
new file mode 100644
index 00000000..a318ae17
--- /dev/null
+++ b/im-api/src/main/java/cn/lili/controller/im/FriendController.java
@@ -0,0 +1,100 @@
+package cn.lili.controller.im;
+
+import cn.lili.common.enums.ResultCode;
+import cn.lili.common.enums.ResultUtil;
+import cn.lili.common.exception.ServiceException;
+import cn.lili.common.security.AuthUser;
+import cn.lili.common.security.context.UserContext;
+import cn.lili.common.vo.ResultMessage;
+import cn.lili.modules.im.entity.dos.Friend;
+import cn.lili.modules.im.entity.vo.FriendVO;
+import cn.lili.modules.im.service.FriendService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.List;
+
+
+
+/**
+
+ * @author Chopper
+
+ */
+
+@RestController
+
+@Api(tags = "好友管理接口")
+
+@RequestMapping("/im/friend")
+
+@RequiredArgsConstructor(onConstructor = @__(@Autowired))
+
+public class FriendController {
+
+
+
+ private final FriendService friendService;
+
+
+ @GetMapping("/mutual")
+ @ApiOperation(value = "查看所有互相关注好友")
+ public ResultMessage> getMutualFriends() {
+ AuthUser currentUser = UserContext.getCurrentUser();
+ if (currentUser == null) {
+ throw new ServiceException(ResultCode.USER_NOT_LOGIN);
+ }
+ List friends = friendService.getMutualFriends(currentUser.getId());
+ return ResultUtil.data(friends);
+ }
+
+ @GetMapping("/{friendId}")
+ @ApiOperation(value = "查看好友资料")
+ public ResultMessage getFriendDetails(@PathVariable String friendId) {
+ AuthUser currentUser = UserContext.getCurrentUser();
+ if (currentUser == null) {
+ throw new ServiceException(ResultCode.USER_NOT_LOGIN);
+ }
+ FriendVO friend = friendService.getFriendDetails(friendId);
+ return ResultUtil.data(friend);
+ }
+
+ @DeleteMapping("/{friendId}")
+ @ApiOperation(value = "解除好友关系")
+ public ResultMessage