From 729fab4ef151e137212d1101dffa7e755e45e026 Mon Sep 17 00:00:00 2001 From: xsx <825657193@qq.com> Date: Tue, 1 Apr 2025 19:02:43 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A5=BD=E5=8F=8B=E4=BC=98=E5=8C=96(=E6=94=B9?= =?UTF-8?q?=E4=B8=BA=E9=80=BB=E8=BE=91=E5=88=A0=E9=99=A4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/bx/imcommon/enums/IMTerminalType.java | 6 +- .../implatform/config/MinIoClientConfig.java | 1 - .../controller/FriendController.java | 21 +- .../controller/LoginController.java | 1 - .../controller/WebrtcPrivateController.java | 1 - .../java/com/bx/implatform/entity/Friend.java | 5 + .../com/bx/implatform/enums/MessageType.java | 2 + .../listener/PrivateMessageListener.java | 3 +- .../bx/implatform/service/FriendService.java | 32 ++- .../service/SensitiveWordService.java | 7 - .../service/impl/FriendServiceImpl.java | 217 +++++++++++++----- .../service/impl/GroupMessageServiceImpl.java | 2 - .../service/impl/GroupServiceImpl.java | 8 +- .../impl/PrivateMessageServiceImpl.java | 30 +-- .../consumer/GroupBannedConsumerTask.java | 1 - .../task/consumer/GroupUnbanConsumerTask.java | 1 - .../java/com/bx/implatform/vo/FriendVO.java | 3 + .../src/main/resources/application-dev.yml | 1 - .../src/main/resources/application-dev.yml | 4 +- im-uniapp/App.vue | 33 +-- im-uniapp/common/enums.js | 2 + im-uniapp/pages/chat/chat-box.vue | 35 ++- im-uniapp/pages/common/user-info.vue | 32 ++- im-uniapp/pages/friend/friend-add.vue | 7 +- im-uniapp/pages/friend/friend.vue | 9 +- im-uniapp/pages/group/group-info.vue | 3 +- im-uniapp/pages/group/group-invite.vue | 8 +- im-uniapp/store/chatStore.js | 21 +- im-uniapp/store/friendStore.js | 29 ++- im-web/src/api/enums.js | 2 + im-web/src/components/chat/ChatBox.vue | 36 ++- im-web/src/components/common/UserInfo.vue | 9 +- im-web/src/components/friend/AddFriend.vue | 9 +- .../src/components/group/AddGroupMember.vue | 4 +- im-web/src/store/chatStore.js | 20 +- im-web/src/store/friendStore.js | 41 +++- im-web/src/view/Friend.vue | 56 +++-- im-web/src/view/Home.vue | 38 +-- 38 files changed, 453 insertions(+), 287 deletions(-) diff --git a/im-common/src/main/java/com/bx/imcommon/enums/IMTerminalType.java b/im-common/src/main/java/com/bx/imcommon/enums/IMTerminalType.java index 3fd3107..d5f5fac 100644 --- a/im-common/src/main/java/com/bx/imcommon/enums/IMTerminalType.java +++ b/im-common/src/main/java/com/bx/imcommon/enums/IMTerminalType.java @@ -20,7 +20,11 @@ public enum IMTerminalType { /** * pc */ - PC(2, "pc"); + PC(2, "pc"), + /** + * 未知 + */ + UNKNOW(-1, "未知"); private final Integer code; diff --git a/im-platform/src/main/java/com/bx/implatform/config/MinIoClientConfig.java b/im-platform/src/main/java/com/bx/implatform/config/MinIoClientConfig.java index 16017b2..ca661b8 100644 --- a/im-platform/src/main/java/com/bx/implatform/config/MinIoClientConfig.java +++ b/im-platform/src/main/java/com/bx/implatform/config/MinIoClientConfig.java @@ -2,7 +2,6 @@ package com.bx.implatform.config; import com.bx.implatform.config.props.MinioProperties; import io.minio.MinioClient; -import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/im-platform/src/main/java/com/bx/implatform/controller/FriendController.java b/im-platform/src/main/java/com/bx/implatform/controller/FriendController.java index c16f692..1d3236a 100644 --- a/im-platform/src/main/java/com/bx/implatform/controller/FriendController.java +++ b/im-platform/src/main/java/com/bx/implatform/controller/FriendController.java @@ -1,11 +1,9 @@ package com.bx.implatform.controller; import com.bx.implatform.annotation.RepeatSubmit; -import com.bx.implatform.entity.Friend; import com.bx.implatform.result.Result; import com.bx.implatform.result.ResultUtils; import com.bx.implatform.service.FriendService; -import com.bx.implatform.session.SessionContext; import com.bx.implatform.vo.FriendVO; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -15,7 +13,6 @@ import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; import java.util.List; -import java.util.stream.Collectors; @Tag(name = "好友") @RestController @@ -28,15 +25,7 @@ public class FriendController { @GetMapping("/list") @Operation(summary = "好友列表", description = "获取好友列表") public Result> findFriends() { - List friends = friendService.findFriendByUserId(SessionContext.getSession().getUserId()); - List vos = friends.stream().map(f -> { - FriendVO vo = new FriendVO(); - vo.setId(f.getFriendId()); - vo.setHeadImage(f.getFriendHeadImage()); - vo.setNickName(f.getFriendNickName()); - return vo; - }).collect(Collectors.toList()); - return ResultUtils.success(vos); + return ResultUtils.success(friendService.findFriends()); } @@ -62,13 +51,5 @@ public class FriendController { return ResultUtils.success(); } - @PutMapping("/update") - @Operation(summary = "更新好友信息", description = "更新好友头像或昵称") - public Result modifyFriend(@Valid @RequestBody FriendVO vo) { - friendService.update(vo); - return ResultUtils.success(); - } - - } diff --git a/im-platform/src/main/java/com/bx/implatform/controller/LoginController.java b/im-platform/src/main/java/com/bx/implatform/controller/LoginController.java index 0f6e242..36a7a43 100644 --- a/im-platform/src/main/java/com/bx/implatform/controller/LoginController.java +++ b/im-platform/src/main/java/com/bx/implatform/controller/LoginController.java @@ -1,6 +1,5 @@ package com.bx.implatform.controller; -import com.bx.implatform.annotation.RepeatSubmit; import com.bx.implatform.dto.LoginDTO; import com.bx.implatform.dto.ModifyPwdDTO; import com.bx.implatform.dto.RegisterDTO; diff --git a/im-platform/src/main/java/com/bx/implatform/controller/WebrtcPrivateController.java b/im-platform/src/main/java/com/bx/implatform/controller/WebrtcPrivateController.java index 7911999..2ce13b4 100644 --- a/im-platform/src/main/java/com/bx/implatform/controller/WebrtcPrivateController.java +++ b/im-platform/src/main/java/com/bx/implatform/controller/WebrtcPrivateController.java @@ -1,6 +1,5 @@ package com.bx.implatform.controller; -import com.bx.implatform.annotation.OnlineCheck; import com.bx.implatform.result.Result; import com.bx.implatform.result.ResultUtils; import com.bx.implatform.service.WebrtcPrivateService; diff --git a/im-platform/src/main/java/com/bx/implatform/entity/Friend.java b/im-platform/src/main/java/com/bx/implatform/entity/Friend.java index f869b81..c7451f9 100644 --- a/im-platform/src/main/java/com/bx/implatform/entity/Friend.java +++ b/im-platform/src/main/java/com/bx/implatform/entity/Friend.java @@ -45,6 +45,11 @@ public class Friend{ */ private String friendHeadImage; + /** + * 是否已删除 + */ + private Boolean deleted; + /** * 创建时间 */ diff --git a/im-platform/src/main/java/com/bx/implatform/enums/MessageType.java b/im-platform/src/main/java/com/bx/implatform/enums/MessageType.java index 7a69c2c..3b5d40b 100644 --- a/im-platform/src/main/java/com/bx/implatform/enums/MessageType.java +++ b/im-platform/src/main/java/com/bx/implatform/enums/MessageType.java @@ -33,6 +33,8 @@ public enum MessageType { USER_BANNED(50,"用户封禁"), GROUP_BANNED(51,"群聊封禁"), GROUP_UNBAN(52,"群聊解封"), + FRIEND_NEW(80, "新增好友"), + FRIEND_DEL(81, "删除好友"), RTC_CALL_VOICE(100, "语音呼叫"), RTC_CALL_VIDEO(101, "视频呼叫"), RTC_ACCEPT(102, "接受"), diff --git a/im-platform/src/main/java/com/bx/implatform/listener/PrivateMessageListener.java b/im-platform/src/main/java/com/bx/implatform/listener/PrivateMessageListener.java index 6417274..b59db7a 100644 --- a/im-platform/src/main/java/com/bx/implatform/listener/PrivateMessageListener.java +++ b/im-platform/src/main/java/com/bx/implatform/listener/PrivateMessageListener.java @@ -17,6 +17,7 @@ import org.springframework.context.annotation.Lazy; import java.util.HashSet; import java.util.List; +import java.util.Objects; import java.util.Set; @Slf4j @@ -31,7 +32,7 @@ public class PrivateMessageListener implements MessageListener for(IMSendResult result : results){ PrivateMessageVO messageInfo = result.getData(); // 更新消息状态,这里只处理成功消息,失败的消息继续保持未读状态 - if (result.getCode().equals(IMSendCode.SUCCESS.code())) { + if (result.getCode().equals(IMSendCode.SUCCESS.code()) && !Objects.isNull(messageInfo.getId())) { messageIds.add(messageInfo.getId()); log.info("消息送达,消息id:{},发送者:{},接收者:{},终端:{}", messageInfo.getId(), result.getSender().getId(), result.getReceiver().getId(), result.getReceiver().getTerminal()); } diff --git a/im-platform/src/main/java/com/bx/implatform/service/FriendService.java b/im-platform/src/main/java/com/bx/implatform/service/FriendService.java index 4fdf32f..70088a4 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/FriendService.java +++ b/im-platform/src/main/java/com/bx/implatform/service/FriendService.java @@ -17,14 +17,27 @@ public interface FriendService extends IService { */ Boolean isFriend(Long userId1, Long userId2); + /** + * 查询用户的所有好友,包括已删除的 + * + * @return 好友列表 + */ + List findAllFriends(); /** * 查询用户的所有好友 * - * @param userId 用户id + * @param friendIds 好友id + * @return 好友列表 + */ + List findByFriendIds(List friendIds); + + /** + * 查询当前用户的所有好友 + * * @return 好友列表 */ - List findFriendByUserId(Long userId); + List findFriends(); /** * 添加好友,互相建立好友关系 @@ -41,17 +54,20 @@ public interface FriendService extends IService { void delFriend(Long friendId); /** - * 更新好友信息,主要是头像和昵称 + * 查询指定的某个好友信息 * - * @param vo 好友vo + * @param friendId 好友的用户id + * @return 好友信息 */ - void update(FriendVO vo); + FriendVO findFriend(Long friendId); /** - * 查询指定的某个好友信息 + * 绑定好友关系 * + * @param userId 好友的id * @param friendId 好友的用户id * @return 好友信息 */ - FriendVO findFriend(Long friendId); -} + void bindFriend(Long userId, Long friendId); + +} \ No newline at end of file diff --git a/im-platform/src/main/java/com/bx/implatform/service/SensitiveWordService.java b/im-platform/src/main/java/com/bx/implatform/service/SensitiveWordService.java index f6a4b86..2a4f099 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/SensitiveWordService.java +++ b/im-platform/src/main/java/com/bx/implatform/service/SensitiveWordService.java @@ -1,14 +1,7 @@ package com.bx.implatform.service; import com.baomidou.mybatisplus.extension.service.IService; -import com.bx.implatform.dto.LoginDTO; -import com.bx.implatform.dto.ModifyPwdDTO; -import com.bx.implatform.dto.RegisterDTO; import com.bx.implatform.entity.SensitiveWord; -import com.bx.implatform.entity.User; -import com.bx.implatform.vo.LoginVO; -import com.bx.implatform.vo.OnlineTerminalVO; -import com.bx.implatform.vo.UserVO; import java.util.List; diff --git a/im-platform/src/main/java/com/bx/implatform/service/impl/FriendServiceImpl.java b/im-platform/src/main/java/com/bx/implatform/service/impl/FriendServiceImpl.java index c67a0d0..a302596 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/impl/FriendServiceImpl.java +++ b/im-platform/src/main/java/com/bx/implatform/service/impl/FriendServiceImpl.java @@ -1,19 +1,31 @@ package com.bx.implatform.service.impl; +import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.bx.imclient.IMClient; +import com.bx.imcommon.enums.IMTerminalType; +import com.bx.imcommon.model.IMPrivateMessage; +import com.bx.imcommon.model.IMUserInfo; import com.bx.implatform.contant.RedisKey; import com.bx.implatform.entity.Friend; +import com.bx.implatform.entity.PrivateMessage; import com.bx.implatform.entity.User; +import com.bx.implatform.enums.MessageStatus; +import com.bx.implatform.enums.MessageType; import com.bx.implatform.exception.GlobalException; import com.bx.implatform.mapper.FriendMapper; +import com.bx.implatform.mapper.PrivateMessageMapper; import com.bx.implatform.mapper.UserMapper; import com.bx.implatform.service.FriendService; import com.bx.implatform.session.SessionContext; import com.bx.implatform.session.UserSession; +import com.bx.implatform.util.BeanUtils; import com.bx.implatform.vo.FriendVO; +import com.bx.implatform.vo.PrivateMessageVO; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.aop.framework.AopContext; @@ -23,8 +35,10 @@ import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.Date; import java.util.List; import java.util.Objects; +import java.util.stream.Collectors; @Slf4j @Service @@ -32,15 +46,33 @@ import java.util.Objects; @CacheConfig(cacheNames = RedisKey.IM_CACHE_FRIEND) public class FriendServiceImpl extends ServiceImpl implements FriendService { + private final PrivateMessageMapper privateMessageMapper; private final UserMapper userMapper; + private final IMClient imClient; @Override - public List findFriendByUserId(Long userId) { - LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(); - queryWrapper.eq(Friend::getUserId, userId); - return this.list(queryWrapper); + public List findAllFriends() { + Long userId = SessionContext.getSession().getUserId(); + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.eq(Friend::getUserId, userId); + return this.list(wrapper); } + @Override + public List findByFriendIds(List friendIds) { + Long userId = SessionContext.getSession().getUserId(); + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.eq(Friend::getUserId, userId); + wrapper.in(Friend::getFriendId, friendIds); + wrapper.eq(Friend::getDeleted,false); + return this.list(wrapper); + } + + @Override + public List findFriends() { + List friends = this.findAllFriends(); + return friends.stream().map(this::conver).collect(Collectors.toList()); + } @Transactional(rollbackFor = Exception.class) @Override @@ -50,53 +82,37 @@ public class FriendServiceImpl extends ServiceImpl impleme throw new GlobalException("不允许添加自己为好友"); } // 互相绑定好友关系 - FriendServiceImpl proxy = (FriendServiceImpl) AopContext.currentProxy(); + FriendServiceImpl proxy = (FriendServiceImpl)AopContext.currentProxy(); proxy.bindFriend(userId, friendId); proxy.bindFriend(friendId, userId); + // 推送添加好友提示 + sendAddTipMessage(friendId); log.info("添加好友,用户id:{},好友id:{}", userId, friendId); } - @Transactional(rollbackFor = Exception.class) @Override public void delFriend(Long friendId) { - long userId = SessionContext.getSession().getUserId(); + Long userId = SessionContext.getSession().getUserId(); // 互相解除好友关系,走代理清理缓存 - FriendServiceImpl proxy = (FriendServiceImpl) AopContext.currentProxy(); + FriendServiceImpl proxy = (FriendServiceImpl)AopContext.currentProxy(); proxy.unbindFriend(userId, friendId); proxy.unbindFriend(friendId, userId); + // 推送解除好友提示 + sendDelTipMessage(friendId); log.info("删除好友,用户id:{},好友id:{}", userId, friendId); } - @Cacheable(key = "#userId1+':'+#userId2") @Override public Boolean isFriend(Long userId1, Long userId2) { - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.lambda() - .eq(Friend::getUserId, userId1) - .eq(Friend::getFriendId, userId2); - return this.count(queryWrapper) > 0; + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.eq(Friend::getUserId, userId1); + wrapper.eq(Friend::getFriendId, userId2); + wrapper.eq(Friend::getDeleted,false); + return this.exists(wrapper); } - - @Override - public void update(FriendVO vo) { - long userId = SessionContext.getSession().getUserId(); - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.lambda() - .eq(Friend::getUserId, userId) - .eq(Friend::getFriendId, vo.getId()); - Friend f = this.getOne(queryWrapper); - if (Objects.isNull(f)) { - throw new GlobalException("对方不是您的好友"); - } - f.setFriendHeadImage(vo.getHeadImage()); - f.setFriendNickName(vo.getNickName()); - this.updateById(f); - } - - /** * 单向绑定好友关系 * @@ -105,22 +121,23 @@ public class FriendServiceImpl extends ServiceImpl impleme */ @CacheEvict(key = "#userId+':'+#friendId") public void bindFriend(Long userId, Long friendId) { - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.lambda() - .eq(Friend::getUserId, userId) - .eq(Friend::getFriendId, friendId); - if (this.count(queryWrapper) == 0) { - Friend friend = new Friend(); - friend.setUserId(userId); - friend.setFriendId(friendId); - User friendInfo = userMapper.selectById(friendId); - friend.setFriendHeadImage(friendInfo.getHeadImage()); - friend.setFriendNickName(friendInfo.getNickName()); - this.save(friend); + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.lambda().eq(Friend::getUserId, userId).eq(Friend::getFriendId, friendId); + Friend friend = this.getOne(wrapper); + if (Objects.isNull(friend)) { + friend = new Friend(); } + friend.setUserId(userId); + friend.setFriendId(friendId); + User friendInfo = userMapper.selectById(friendId); + friend.setFriendHeadImage(friendInfo.getHeadImage()); + friend.setFriendNickName(friendInfo.getNickName()); + friend.setDeleted(false); + this.saveOrUpdate(friend); + // 推送好友变化信息s + sendAddFriendMessage(userId, friendId, friend); } - /** * 单向解除好友关系 * @@ -129,30 +146,112 @@ public class FriendServiceImpl extends ServiceImpl impleme */ @CacheEvict(key = "#userId+':'+#friendId") public void unbindFriend(Long userId, Long friendId) { - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.lambda() - .eq(Friend::getUserId, userId) - .eq(Friend::getFriendId, friendId); - List friends = this.list(queryWrapper); - friends.forEach(friend -> this.removeById(friend.getId())); + // 逻辑删除 + LambdaUpdateWrapper wrapper = Wrappers.lambdaUpdate(); + wrapper.eq(Friend::getUserId, userId); + wrapper.eq(Friend::getFriendId, friendId); + wrapper.set(Friend::getDeleted,true); + this.update(wrapper); + // 推送好友变化信息 + sendDelFriendMessage(userId, friendId); } - @Override public FriendVO findFriend(Long friendId) { UserSession session = SessionContext.getSession(); - QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.lambda() - .eq(Friend::getUserId, session.getUserId()) - .eq(Friend::getFriendId, friendId); + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.eq(Friend::getUserId, session.getUserId()); + wrapper.eq(Friend::getFriendId, friendId); Friend friend = this.getOne(wrapper); if (Objects.isNull(friend)) { throw new GlobalException("对方不是您的好友"); } + return conver(friend); + } + + private FriendVO conver(Friend f) { FriendVO vo = new FriendVO(); - vo.setId(friend.getFriendId()); - vo.setHeadImage(friend.getFriendHeadImage()); - vo.setNickName(friend.getFriendNickName()); + vo.setId(f.getFriendId()); + vo.setHeadImage(f.getFriendHeadImage()); + vo.setNickName(f.getFriendNickName()); + vo.setDeleted(f.getDeleted()); return vo; } + + void sendAddFriendMessage(Long userId, Long friendId, Friend friend) { + // 推送好友状态信息 + PrivateMessageVO msgInfo = new PrivateMessageVO(); + msgInfo.setSendId(friendId); + msgInfo.setRecvId(userId); + msgInfo.setSendTime(new Date()); + msgInfo.setType(MessageType.FRIEND_NEW.code()); + FriendVO vo = conver(friend); + msgInfo.setContent(JSON.toJSONString(vo)); + IMPrivateMessage sendMessage = new IMPrivateMessage<>(); + sendMessage.setSender(new IMUserInfo(friendId, IMTerminalType.UNKNOW.code())); + sendMessage.setRecvId(userId); + sendMessage.setData(msgInfo); + sendMessage.setSendToSelf(false); + sendMessage.setSendResult(false); + imClient.sendPrivateMessage(sendMessage); + } + + void sendDelFriendMessage(Long userId, Long friendId) { + // 推送好友状态信息 + PrivateMessageVO msgInfo = new PrivateMessageVO(); + msgInfo.setSendId(friendId); + msgInfo.setRecvId(userId); + msgInfo.setSendTime(new Date()); + msgInfo.setType(MessageType.FRIEND_DEL.code()); + IMPrivateMessage sendMessage = new IMPrivateMessage<>(); + sendMessage.setSender(new IMUserInfo(friendId, IMTerminalType.UNKNOW.code())); + sendMessage.setRecvId(userId); + sendMessage.setData(msgInfo); + sendMessage.setSendToSelf(false); + sendMessage.setSendResult(false); + imClient.sendPrivateMessage(sendMessage); + } + + void sendAddTipMessage(Long friendId) { + UserSession session = SessionContext.getSession(); + PrivateMessage msg = new PrivateMessage(); + msg.setSendId(session.getUserId()); + msg.setRecvId(friendId); + msg.setContent("你们已成为好友,现在可以开始聊天了"); + msg.setSendTime(new Date()); + msg.setStatus(MessageStatus.UNSEND.code()); + msg.setType(MessageType.TIP_TEXT.code()); + privateMessageMapper.insert(msg); + // 推给对方 + PrivateMessageVO messageInfo = BeanUtils.copyProperties(msg, PrivateMessageVO.class); + IMPrivateMessage sendMessage = new IMPrivateMessage<>(); + sendMessage.setSender(new IMUserInfo(session.getUserId(), session.getTerminal())); + sendMessage.setRecvId(friendId); + sendMessage.setSendToSelf(false); + sendMessage.setData(messageInfo); + imClient.sendPrivateMessage(sendMessage); + // 推给自己 + sendMessage.setRecvId(session.getUserId()); + imClient.sendPrivateMessage(sendMessage); + } + + void sendDelTipMessage(Long friendId){ + UserSession session = SessionContext.getSession(); + // 推送好友状态信息 + PrivateMessage msg = new PrivateMessage(); + msg.setSendId(session.getUserId()); + msg.setRecvId(friendId); + msg.setSendTime(new Date()); + msg.setType(MessageType.TIP_TEXT.code()); + msg.setStatus(MessageStatus.UNSEND.code()); + msg.setContent("你们的好友关系已被解除"); + privateMessageMapper.insert(msg); + // 推送 + PrivateMessageVO messageInfo = BeanUtils.copyProperties(msg, PrivateMessageVO.class); + IMPrivateMessage sendMessage = new IMPrivateMessage<>(); + sendMessage.setSender(new IMUserInfo(friendId, IMTerminalType.UNKNOW.code())); + sendMessage.setRecvId(friendId); + sendMessage.setData(messageInfo); + imClient.sendPrivateMessage(sendMessage); + } } diff --git a/im-platform/src/main/java/com/bx/implatform/service/impl/GroupMessageServiceImpl.java b/im-platform/src/main/java/com/bx/implatform/service/impl/GroupMessageServiceImpl.java index 244c062..15e800a 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/impl/GroupMessageServiceImpl.java +++ b/im-platform/src/main/java/com/bx/implatform/service/impl/GroupMessageServiceImpl.java @@ -31,10 +31,8 @@ import com.bx.implatform.session.UserSession; import com.bx.implatform.util.BeanUtils; import com.bx.implatform.util.SensitiveFilterUtil; import com.bx.implatform.vo.GroupMessageVO; -import com.google.common.base.Splitter; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.time.DateUtils; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; diff --git a/im-platform/src/main/java/com/bx/implatform/service/impl/GroupServiceImpl.java b/im-platform/src/main/java/com/bx/implatform/service/impl/GroupServiceImpl.java index 1389b89..dc289c8 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/impl/GroupServiceImpl.java +++ b/im-platform/src/main/java/com/bx/implatform/service/impl/GroupServiceImpl.java @@ -227,14 +227,12 @@ public class GroupServiceImpl extends ServiceImpl implements throw new GlobalException("群聊人数不能大于" + Constant.MAX_GROUP_MEMBER + "人"); } // 找出好友信息 - List friends = friendsService.findFriendByUserId(session.getUserId()); - List friendsList = vo.getFriendIds().stream() - .map(id -> friends.stream().filter(f -> f.getFriendId().equals(id)).findFirst().get()).toList(); - if (friendsList.size() != vo.getFriendIds().size()) { + List friends = friendsService.findByFriendIds(vo.getFriendIds()); + if (vo.getFriendIds().size() != friends.size()) { throw new GlobalException("部分用户不是您的好友,邀请失败"); } // 批量保存成员数据 - List groupMembers = friendsList.stream().map(f -> { + List groupMembers = friends.stream().map(f -> { Optional optional = members.stream().filter(m -> m.getUserId().equals(f.getFriendId())).findFirst(); GroupMember groupMember = optional.orElseGet(GroupMember::new); diff --git a/im-platform/src/main/java/com/bx/implatform/service/impl/PrivateMessageServiceImpl.java b/im-platform/src/main/java/com/bx/implatform/service/impl/PrivateMessageServiceImpl.java index 7e357c2..ef5222c 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/impl/PrivateMessageServiceImpl.java +++ b/im-platform/src/main/java/com/bx/implatform/service/impl/PrivateMessageServiceImpl.java @@ -1,6 +1,5 @@ package com.bx.implatform.service.impl; -import cn.hutool.core.collection.CollectionUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; @@ -12,7 +11,6 @@ import com.bx.imcommon.enums.IMTerminalType; import com.bx.imcommon.model.IMPrivateMessage; import com.bx.imcommon.model.IMUserInfo; import com.bx.implatform.dto.PrivateMessageDTO; -import com.bx.implatform.entity.Friend; import com.bx.implatform.entity.PrivateMessage; import com.bx.implatform.enums.MessageStatus; import com.bx.implatform.enums.MessageType; @@ -31,7 +29,9 @@ import org.apache.commons.lang3.time.DateUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.*; +import java.util.Date; +import java.util.List; +import java.util.Objects; import java.util.stream.Collectors; @Slf4j @@ -135,29 +135,19 @@ public class PrivateMessageServiceImpl extends ServiceImpl friends = friendService.findFriendByUserId(session.getUserId()); - if (friends.isEmpty()) { - // 关闭加载中标志 - this.sendLoadingMessage(false); - return; - } // 开启加载中标志 this.sendLoadingMessage(true); - List friendIds = friends.stream().map(Friend::getFriendId).collect(Collectors.toList()); // 获取当前用户的消息 - LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(); + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); // 只能拉取最近3个月的消息,移动端只拉取一个月消息 int months = session.getTerminal().equals(IMTerminalType.APP.code()) ? 1 : 3; Date minDate = DateUtils.addMonths(new Date(), -months); - queryWrapper.gt(PrivateMessage::getId, minId).ge(PrivateMessage::getSendTime, minDate).and(wrap -> wrap.and( - wp -> wp.eq(PrivateMessage::getSendId, session.getUserId()).in(PrivateMessage::getRecvId, friendIds)) - .or(wp -> wp.eq(PrivateMessage::getRecvId, session.getUserId()).in(PrivateMessage::getSendId, friendIds))) - .orderByAsc(PrivateMessage::getId); - List messages = this.list(queryWrapper); + wrapper.gt(PrivateMessage::getId, minId); + wrapper.ge(PrivateMessage::getSendTime, minDate); + wrapper.and(wp -> wp.eq(PrivateMessage::getSendId, session.getUserId()).or() + .eq(PrivateMessage::getRecvId, session.getUserId())); + wrapper.orderByAsc(PrivateMessage::getId); + List messages = this.list(wrapper); // 推送消息 for (PrivateMessage m : messages) { PrivateMessageVO vo = BeanUtils.copyProperties(m, PrivateMessageVO.class); diff --git a/im-platform/src/main/java/com/bx/implatform/task/consumer/GroupBannedConsumerTask.java b/im-platform/src/main/java/com/bx/implatform/task/consumer/GroupBannedConsumerTask.java index 1fc7f57..27c8853 100644 --- a/im-platform/src/main/java/com/bx/implatform/task/consumer/GroupBannedConsumerTask.java +++ b/im-platform/src/main/java/com/bx/implatform/task/consumer/GroupBannedConsumerTask.java @@ -61,7 +61,6 @@ public class GroupBannedConsumerTask extends RedisMQConsumer { IMGroupMessage sendMessage = new IMGroupMessage<>(); sendMessage.setSender(new IMUserInfo(Constant.SYS_USER_ID, IMTerminalType.PC.code())); sendMessage.setRecvIds(userIds); - sendMessage.setSendResult(true); sendMessage.setSendToSelf(false); sendMessage.setData(msgInfo); imClient.sendGroupMessage(sendMessage); diff --git a/im-platform/src/main/java/com/bx/implatform/task/consumer/GroupUnbanConsumerTask.java b/im-platform/src/main/java/com/bx/implatform/task/consumer/GroupUnbanConsumerTask.java index e2c99c2..67b3993 100644 --- a/im-platform/src/main/java/com/bx/implatform/task/consumer/GroupUnbanConsumerTask.java +++ b/im-platform/src/main/java/com/bx/implatform/task/consumer/GroupUnbanConsumerTask.java @@ -60,7 +60,6 @@ public class GroupUnbanConsumerTask extends RedisMQConsumer { IMGroupMessage sendMessage = new IMGroupMessage<>(); sendMessage.setSender(new IMUserInfo(Constant.SYS_USER_ID, IMTerminalType.PC.code())); sendMessage.setRecvIds(userIds); - sendMessage.setSendResult(true); sendMessage.setSendToSelf(false); sendMessage.setData(msgInfo); imClient.sendGroupMessage(sendMessage); diff --git a/im-platform/src/main/java/com/bx/implatform/vo/FriendVO.java b/im-platform/src/main/java/com/bx/implatform/vo/FriendVO.java index 7b40fb4..e36e6e3 100644 --- a/im-platform/src/main/java/com/bx/implatform/vo/FriendVO.java +++ b/im-platform/src/main/java/com/bx/implatform/vo/FriendVO.java @@ -19,4 +19,7 @@ public class FriendVO { @Schema(description = "好友头像") private String headImage; + + @Schema(description = "是否已删除") + private Boolean deleted; } diff --git a/im-platform/src/main/resources/application-dev.yml b/im-platform/src/main/resources/application-dev.yml index 618bcbb..aff630b 100644 --- a/im-platform/src/main/resources/application-dev.yml +++ b/im-platform/src/main/resources/application-dev.yml @@ -8,7 +8,6 @@ spring: redis: host: localhost port: 6379 - database: 1 minio: endpoint: http://127.0.0.1:9000 #内网地址 diff --git a/im-server/src/main/resources/application-dev.yml b/im-server/src/main/resources/application-dev.yml index 305d30c..a06ec18 100644 --- a/im-server/src/main/resources/application-dev.yml +++ b/im-server/src/main/resources/application-dev.yml @@ -2,6 +2,4 @@ spring: data: redis: host: 127.0.0.1 - port: 6379 - database: 1 - + port: 6379 \ No newline at end of file diff --git a/im-uniapp/App.vue b/im-uniapp/App.vue index 649eaef..601145b 100644 --- a/im-uniapp/App.vue +++ b/im-uniapp/App.vue @@ -138,10 +138,19 @@ export default { this.chatStore.recallMessage(msg, chatInfo); return; } + // 新增好友 + if (msg.type == this.$enums.MESSAGE_TYPE.FRIEND_NEW) { + this.friendStore.addFriend(JSON.parse(msg.content)); + return; + } + // 删除好友 + if (msg.type == this.$enums.MESSAGE_TYPE.FRIEND_DEL) { + this.friendStore.removeFriend(friendId); + return; + } // 消息插入 - this.loadFriendInfo(friendId, (friend) => { - this.insertPrivateMessage(friend, msg); - }) + let friend = this.loadFriendInfo(friendId); + this.insertPrivateMessage(friend, msg); }, insertPrivateMessage(friend, msg) { // 单人视频信令 @@ -280,17 +289,15 @@ export default { }, loadFriendInfo(id, callback) { let friend = this.friendStore.findFriend(id); - if (friend) { - callback(friend); - } else { - http({ - url: `/friend/find/${id}`, - method: 'GET' - }).then((friend) => { - this.friendStore.addFriend(friend); - callback(friend) - }) + if (!friend) { + console.log("未知用户:", id) + friend = { + id: id, + showNickName: "未知用户", + headImage: "" + } } + return friend; }, loadGroupInfo(id, callback) { let group = this.groupStore.findGroup(id); diff --git a/im-uniapp/common/enums.js b/im-uniapp/common/enums.js index 08510be..d377bb1 100644 --- a/im-uniapp/common/enums.js +++ b/im-uniapp/common/enums.js @@ -14,6 +14,8 @@ const MESSAGE_TYPE = { ACT_RT_VOICE: 40, ACT_RT_VIDEO: 41, USER_BANNED: 50, + FRIEND_NEW: 80, + FRIEND_DEL: 81, RTC_CALL_VOICE: 100, RTC_CALL_VIDEO: 101, RTC_ACCEPT: 102, diff --git a/im-uniapp/pages/chat/chat-box.vue b/im-uniapp/pages/chat/chat-box.vue index 0e69592..5b84715 100644 --- a/im-uniapp/pages/chat/chat-box.vue +++ b/im-uniapp/pages/chat/chat-box.vue @@ -119,7 +119,7 @@ export default { data() { return { chat: {}, - friend: {}, + userInfo: {}, group: {}, groupMembers: [], isReceipt: false, // 是否回执消息 @@ -578,7 +578,7 @@ export default { }) } else { uni.navigateTo({ - url: "/pages/common/user-info?id=" + this.friend.id + url: "/pages/common/user-info?id=" + this.userInfo.id }) } }, @@ -657,15 +657,29 @@ export default { this.groupMembers = groupMembers; }); }, + updateFriendInfo() { + if (this.isFriend) { + // store的数据不能直接修改,深拷贝一份store的数据 + let friend = JSON.parse(JSON.stringify(this.friend)); + friend.headImage = this.userInfo.headImageThumb; + friend.nickName = this.userInfo.nickName; + friend.showNickName = friend.remarkNickName ? friend.remarkNickName : friend.nickName; + // 更新好友列表中的昵称和头像 + this.friendStore.updateFriend(friend); + // 更新会话中的头像和昵称 + this.chatStore.updateChatFromFriend(friend); + } else { + this.chatStore.updateChatFromUser(this.userInfo); + } + }, loadFriend(friendId) { - // 获取对方最新信息 + // 获取好友用户信息 this.$http({ url: `/user/find/${friendId}`, method: 'GET' - }).then((friend) => { - this.friend = friend; - this.chatStore.updateChatFromFriend(friend); - this.friendStore.updateFriend(friend); + }).then((userInfo) => { + this.userInfo = userInfo; + this.updateFriendInfo(); }) }, rpxTopx(rpx) { @@ -807,7 +821,7 @@ export default { } if (this.chat.type == "PRIVATE") { msgInfo.recvId = this.mine.id - msgInfo.content = "该用户已被管理员封禁,原因:" + this.friend.reason + msgInfo.content = "该用户已被管理员封禁,原因:" + this.userInfo.reason } else { msgInfo.groupId = this.group.id; msgInfo.content = "本群聊已被管理员封禁,原因:" + this.group.reason @@ -823,6 +837,9 @@ export default { mine() { return this.userStore.userInfo; }, + friend() { + return this.friendStore.findFriend(this.userInfo.id); + }, title() { if (!this.chat) { return ""; @@ -850,7 +867,7 @@ export default { return this.chat.unreadCount; }, isBanned() { - return (this.chat.type == "PRIVATE" && this.friend.isBanned) || + return (this.chat.type == "PRIVATE" && this.userInfo.isBanned) || (this.chat.type == "GROUP" && this.group.isBanned) }, atUserItems() { diff --git a/im-uniapp/pages/common/user-info.vue b/im-uniapp/pages/common/user-info.vue index b0ea1aa..cb34f8f 100644 --- a/im-uniapp/pages/common/user-info.vue +++ b/im-uniapp/pages/common/user-info.vue @@ -82,7 +82,8 @@ export default { id: this.userInfo.id, nickName: this.userInfo.nickName, headImage: this.userInfo.headImageThumb, - online: this.userInfo.online + online: this.userInfo.online, + deleted: false } this.friendStore.addFriend(friend); uni.showToast({ @@ -113,20 +114,17 @@ export default { }) }, updateFriendInfo() { - // store的数据不能直接修改,深拷贝一份store的数据 - let friend = JSON.parse(JSON.stringify(this.friendInfo)); - friend.headImage = this.userInfo.headImageThumb; - friend.nickName = this.userInfo.nickName; - this.$http({ - url: "/friend/update", - method: "PUT", - data: friend - }).then(() => { + if (this.isFriend) { + // store的数据不能直接修改,深拷贝一份store的数据 + let friend = JSON.parse(JSON.stringify(this.friendInfo)); + friend.headImage = this.userInfo.headImageThumb; + friend.nickName = this.userInfo.nickName; + // 更新好友列表中的昵称和头像 this.friendStore.updateFriend(friend); // 更新会话中的头像和昵称 this.chatStore.updateChatFromFriend(this.userInfo); - }) + } }, loadUserInfo(id) { this.$http({ @@ -135,21 +133,17 @@ export default { }).then((user) => { this.userInfo = user; // 如果发现好友的头像和昵称改了,进行更新 - if (this.isFriend && (this.userInfo.headImageThumb != this.friendInfo.headImage || - this.userInfo.nickName != this.friendInfo.nickName)) { - this.updateFriendInfo() - } + this.updateFriendInfo() + }) } }, computed: { isFriend() { - return !!this.friendInfo; + return this.friendStore.isFriend(this.userInfo.id); }, friendInfo() { - let friends = this.friendStore.friends; - let friend = friends.find((f) => f.id == this.userInfo.id); - return friend; + return this.friendStore.findFriend(this.userInfo.id); } }, onLoad(options) { diff --git a/im-uniapp/pages/friend/friend-add.vue b/im-uniapp/pages/friend/friend-add.vue index ea21de4..72b45e0 100644 --- a/im-uniapp/pages/friend/friend-add.vue +++ b/im-uniapp/pages/friend/friend-add.vue @@ -61,7 +61,8 @@ export default { id: user.id, nickName: user.nickName, headImage: user.headImage, - online: user.online + online: user.online, + delete: false } this.friendStore.addFriend(friend); uni.showToast({ @@ -76,9 +77,7 @@ export default { }) }, isFriend(userId) { - let friends = this.friendStore.friends; - let friend = friends.find((f) => f.id == userId); - return !!friend; + return this.friendStore.isFriend(userId); } } } diff --git a/im-uniapp/pages/friend/friend.vue b/im-uniapp/pages/friend/friend.vue index 736674a..6a7e020 100644 --- a/im-uniapp/pages/friend/friend.vue +++ b/im-uniapp/pages/friend/friend.vue @@ -8,7 +8,7 @@ placeholder="点击搜索好友"> - + 温馨提示:您现在还没有任何好友,快点击右上方'+'按钮添加好友吧~ @@ -56,14 +56,11 @@ export default { } }, computed: { - friends() { - return this.friendStore.friends; - }, friendGroupMap() { // 按首字母分组 let groupMap = new Map(); - this.friends.forEach((f) => { - if (this.searchText && !f.nickName.includes(this.searchText)) { + this.friendStore.friends.forEach((f) => { + if (f.deleted || (this.searchText && !f.nickName.includes(this.searchText))) { return; } let letter = this.firstLetter(f.nickName).toUpperCase(); diff --git a/im-uniapp/pages/group/group-info.vue b/im-uniapp/pages/group/group-info.vue index b4aff2a..c487ebc 100644 --- a/im-uniapp/pages/group/group-info.vue +++ b/im-uniapp/pages/group/group-info.vue @@ -113,8 +113,7 @@ export default { url: "/pages/group/group" }); this.groupStore.removeGroup(this.groupId); - this.chatStore.removeGroupChat(this - .groupId); + this.chatStore.removeGroupChat(this.groupId); }, 100) } }) diff --git a/im-uniapp/pages/group/group-invite.vue b/im-uniapp/pages/group/group-invite.vue index a5a6db3..2ffbe67 100644 --- a/im-uniapp/pages/group/group-invite.vue +++ b/im-uniapp/pages/group/group-invite.vue @@ -8,9 +8,9 @@ - - + @@ -79,7 +79,7 @@ export default { initFriendItems() { this.friendItems = []; let friends = this.friendStore.friends; - friends.forEach((f => { + friends.filter(f => !f.deleted).forEach((f => { let item = { id: f.id, headImage: f.headImage, diff --git a/im-uniapp/store/chatStore.js b/im-uniapp/store/chatStore.js index bef4ac4..7ca83e6 100644 --- a/im-uniapp/store/chatStore.js +++ b/im-uniapp/store/chatStore.js @@ -180,7 +180,7 @@ export default defineStore('chatStore', { chat.sendNickName = msgInfo.sendNickName; // 未读加1 if (!msgInfo.selfSend && msgInfo.status != MESSAGE_STATUS.READED && - msgInfo.type != MESSAGE_TYPE.TIP_TEXT) { + msgInfo.status != MESSAGE_STATUS.RECALL && msgInfo.type != MESSAGE_TYPE.TIP_TEXT) { chat.unreadCount++; } // 是否有人@我 @@ -270,7 +270,9 @@ export default defineStore('chatStore', { chat.lastContent = m.content; chat.lastSendTime = msgInfo.sendTime; chat.sendNickName = ''; - chat.unreadCount++; + if (!msgInfo.selfSend && msgInfo.status != MESSAGE_STATUS.READED) { + chat.unreadCount++; + } } // 被引用的消息也要撤回 if (m.quoteMessage && m.quoteMessage.id == msgInfo.id) { @@ -284,15 +286,26 @@ export default defineStore('chatStore', { }, updateChatFromFriend(friend) { let chat = this.findChatByFriend(friend.id) - if (chat && (chat.headImage != friend.headImageThumb || + if (chat && (chat.headImage != friend.headImage || chat.showName != friend.nickName)) { // 更新会话中的群名和头像 - chat.headImage = friend.headImageThumb; + chat.headImage = friend.headImage; chat.showName = friend.nickName; chat.stored = false; this.saveToStorage(); } }, + updateChatFromUser(user) { + let chat = this.findChatByFriend(user.id); + // 更新会话中的昵称和头像 + if (chat && (chat.headImage != user.headImageThumb || + chat.showName != user.nickName)) { + chat.headImage = user.headImageThumb; + chat.showName = user.nickName; + chat.stored = false; + this.saveToStorage(); + } + }, updateChatFromGroup(group) { let chat = this.findChatByGroup(group.id); if (chat && (chat.headImage != group.headImageThumb || diff --git a/im-uniapp/store/friendStore.js b/im-uniapp/store/friendStore.js index 939f2d2..0b9f4b4 100644 --- a/im-uniapp/store/friendStore.js +++ b/im-uniapp/store/friendStore.js @@ -29,12 +29,16 @@ export default defineStore('friendStore', { removeFriend(id) { this.friends.forEach((f, idx) => { if (f.id == id) { - this.friends.splice(idx, 1) + this.friends[idx].deleted = true; } }) }, addFriend(friend) { - this.friends.push(friend); + if (this.friends.find((f) => f.id == friend.id)) { + this.updateFriend(friend) + } else { + this.friends.unshift(friend); + } }, setOnlineStatus(onlineTerminals) { this.friends.forEach((f) => { @@ -51,16 +55,16 @@ export default defineStore('friendStore', { }); }, refreshOnlineStatus() { - if (this.friends.length > 0) { - let userIds = []; - this.friends.forEach(f => userIds.push(f.id)); - http({ - url: '/user/terminal/online?userIds=' + userIds.join(','), - method: 'GET' - }).then((onlineTerminals) => { - this.setOnlineStatus(onlineTerminals); - }) + let userIds = this.friends.filter((f) => !f.deleted).map((f) => f.id); + if (userIds.length == 0) { + return; } + http({ + url: '/user/terminal/online?userIds=' + userIds.join(','), + method: 'GET' + }).then((onlineTerminals) => { + this.setOnlineStatus(onlineTerminals); + }) // 30s后重新拉取 clearTimeout(this.timer); this.timer = setTimeout(() => { @@ -88,6 +92,9 @@ export default defineStore('friendStore', { } }, getters: { + isFriend: (state) => (userId) => { + return state.friends.filter((f) => !f.deleted).some((f) => f.id == userId); + }, findFriend: (state) => (id) => { return state.friends.find((f) => f.id == id); } diff --git a/im-web/src/api/enums.js b/im-web/src/api/enums.js index efdaa01..37a9cd9 100644 --- a/im-web/src/api/enums.js +++ b/im-web/src/api/enums.js @@ -13,6 +13,8 @@ const MESSAGE_TYPE = { ACT_RT_VOICE: 40, ACT_RT_VIDEO: 41, USER_BANNED: 50, + FRIEND_NEW: 80, + FRIEND_DEL: 81, RTC_CALL_VOICE: 100, RTC_CALL_VIDEO: 101, RTC_ACCEPT: 102, diff --git a/im-web/src/components/chat/ChatBox.vue b/im-web/src/components/chat/ChatBox.vue index 0bbad5e..28afab4 100644 --- a/im-web/src/components/chat/ChatBox.vue +++ b/im-web/src/components/chat/ChatBox.vue @@ -117,7 +117,7 @@ export default { }, data() { return { - friend: {}, + userInfo: {}, group: {}, groupMembers: [], sendImageUrl: "", @@ -540,15 +540,27 @@ export default { this.groupMembers = groupMembers; }); }, + updateFriendInfo() { + if (this.isFriend) { + // store的数据不能直接修改,深拷贝一份store的数据 + let friend = JSON.parse(JSON.stringify(this.friend)); + friend.headImage = this.userInfo.headImageThumb; + friend.nickName = this.userInfo.nickName; + friend.showNickName = friend.remarkNickName ? friend.remarkNickName : friend.nickName; + this.$store.commit("updateChatFromFriend", friend); + this.$store.commit("updateFriend", friend); + }else { + this.$store.commit("updateChatFromUser", this.userInfo); + } + }, loadFriend(friendId) { - // 获取对方最新信息 + // 获取好友信息 this.$http({ url: `/user/find/${friendId}`, - method: 'get' - }).then((friend) => { - this.friend = friend; - this.$store.commit("updateChatFromFriend", friend); - this.$store.commit("updateFriend", friend); + method: 'GET' + }).then((userInfo) => { + this.userInfo = userInfo; + this.updateFriendInfo(); }) }, showName(msgInfo) { @@ -624,7 +636,7 @@ export default { } if (this.chat.type == "PRIVATE") { msgInfo.recvId = this.mine.id - msgInfo.content = "该用户已被管理员封禁,原因:" + this.friend.reason + msgInfo.content = "该用户已被管理员封禁,原因:" + this.userInfo.reason } else { msgInfo.groupId = this.group.id; msgInfo.content = "本群聊已被管理员封禁,原因:" + this.group.reason @@ -640,6 +652,12 @@ export default { mine() { return this.$store.state.userStore.userInfo; }, + isFriend() { + return this.$store.getters.isFriend(this.userInfo.id); + }, + friend() { + return this.$store.getters.findFriend(this.userInfo.id) + }, title() { let title = this.chat.showName; if (this.chat.type == "GROUP") { @@ -661,7 +679,7 @@ export default { return this.chat.messages.length; }, isBanned() { - return (this.chat.type == "PRIVATE" && this.friend.isBanned) || + return (this.chat.type == "PRIVATE" && this.userInfo.isBanned) || (this.chat.type == "GROUP" && this.group.isBanned) } }, diff --git a/im-web/src/components/common/UserInfo.vue b/im-web/src/components/common/UserInfo.vue index 16d5eb5..38d6ac6 100644 --- a/im-web/src/components/common/UserInfo.vue +++ b/im-web/src/components/common/UserInfo.vue @@ -68,13 +68,14 @@ export default { params: { friendId: this.user.id } - }).then((data) => { + }).then(() => { this.$message.success("添加成功,对方已成为您的好友"); let friend = { id: this.user.id, nickName: this.user.nickName, headImage: this.user.headImageThumb, - online: this.user.online + online: this.user.online, + deleted: false } this.$store.commit("addFriend", friend); }) @@ -87,9 +88,7 @@ export default { }, computed: { isFriend() { - let friends = this.$store.state.friendStore.friends; - let friend = friends.find((f) => f.id == this.user.id); - return friend != undefined; + return this.$store.getters.isFriend(this.user.id); } } } diff --git a/im-web/src/components/friend/AddFriend.vue b/im-web/src/components/friend/AddFriend.vue index 34f5c35..9400a2a 100644 --- a/im-web/src/components/friend/AddFriend.vue +++ b/im-web/src/components/friend/AddFriend.vue @@ -74,21 +74,20 @@ export default { params: { friendId: user.id } - }).then((data) => { + }).then(() => { this.$message.success("添加成功,对方已成为您的好友"); let friend = { id: user.id, nickName: user.nickName, headImage: user.headImage, - online: user.online + online: user.online, + deleted: false } this.$store.commit("addFriend", friend); }) }, isFriend(userId) { - let friends = this.$store.state.friendStore.friends; - let friend = friends.find((f) => f.id == userId); - return friend != undefined; + return this.$store.getters.isFriend(userId); } } } diff --git a/im-web/src/components/group/AddGroupMember.vue b/im-web/src/components/group/AddGroupMember.vue index 068fbb0..84f8a31 100644 --- a/im-web/src/components/group/AddGroupMember.vue +++ b/im-web/src/components/group/AddGroupMember.vue @@ -55,7 +55,6 @@ export default { this.$emit("close"); }, onOk() { - let inviteVO = { groupId: this.groupId, friendIds: [] @@ -107,6 +106,9 @@ export default { if (newData) { this.friends = []; this.$store.state.friendStore.friends.forEach((f) => { + if (f.deleted) { + return; + } let friend = JSON.parse(JSON.stringify(f)) let m = this.members.filter((m) => !m.quit) .find((m) => m.userId == f.id); diff --git a/im-web/src/store/chatStore.js b/im-web/src/store/chatStore.js index 161c025..00e990a 100644 --- a/im-web/src/store/chatStore.js +++ b/im-web/src/store/chatStore.js @@ -175,7 +175,7 @@ export default { chat.sendNickName = msgInfo.sendNickName; // 未读加1 if (!msgInfo.selfSend && msgInfo.status != MESSAGE_STATUS.READED && - msgInfo.type != MESSAGE_TYPE.TIP_TEXT) { + msgInfo.status != MESSAGE_STATUS.RECALL && msgInfo.type != MESSAGE_TYPE.TIP_TEXT) { chat.unreadCount++; } // 是否有人@我 @@ -258,7 +258,7 @@ export default { chat.lastContent = m.content; chat.lastSendTime = msgInfo.sendTime; chat.sendNickName = ''; - if(!msgInfo.selfSend){ + if (!msgInfo.selfSend && msgInfo.status != MESSAGE_STATUS.READED) { chat.unreadCount++; } } @@ -275,14 +275,25 @@ export default { updateChatFromFriend(state, friend) { let chat = this.getters.findChatByFriend(friend.id); // 更新会话中的群名和头像 - if (chat && (chat.headImage != friend.headImageThumb || + if (chat && (chat.headImage != friend.headImage || chat.showName != friend.nickName)) { - chat.headImage = friend.headImageThumb; + chat.headImage = friend.headImage; chat.showName = friend.nickName; chat.stored = false; this.commit("saveToStorage") } }, + updateChatFromUser(user) { + let chat = this.getters.findChatByFriend(user.id); + // 更新会话中的昵称和头像 + if (chat && (chat.headImage != user.headImageThumb || + chat.showName != user.nickName)) { + chat.headImage = user.headImageThumb; + chat.showName = user.nickName; + chat.stored = false; + this.saveToStorage(); + } + }, updateChatFromGroup(state, group) { let chat = this.getters.findChatByGroup(group.id); if (chat && (chat.headImage != group.headImageThumb || @@ -333,7 +344,6 @@ export default { // 只存储有改动的会话 let chatKey = `${key}-${chat.type}-${chat.targetId}` if (!chat.stored) { - console.log(chatKey) if (chat.delete) { localForage.removeItem(chatKey); } else { diff --git a/im-web/src/store/friendStore.js b/im-web/src/store/friendStore.js index dee3ae4..0ae893f 100644 --- a/im-web/src/store/friendStore.js +++ b/im-web/src/store/friendStore.js @@ -28,23 +28,35 @@ export default { }) }, activeFriend(state, idx) { - state.activeFriend = state.friends[idx]; - }, - removeFriend(state, idx) { - if (state.friends[idx] == state.activeFriend) { + if (idx < 0) { state.activeFriend = null; + } else { + state.activeFriend = state.friends[idx]; + } + }, + removeFriend(state, id) { + for (let idx in state.friends) { + if (id && state.friends[idx].id == id) { + state.friends[idx].deleted = true; + if (state.friends[idx] == state.activeFriend) { + state.activeFriend = null; + } + return; + } } - state.friends.splice(idx, 1); }, addFriend(state, friend) { - state.friends.push(friend); + if (state.friends.find((f) => f.id == friend.id)) { + this.commit("updateFriend", friend) + } else { + state.friends.unshift(friend); + } }, refreshOnlineStatus(state) { - let userIds = []; - if (state.friends.length == 0) { + let userIds = state.friends.filter((f) => !f.deleted).map((f) => f.id); + if (userIds.length == 0) { return; } - state.friends.forEach((f) => { userIds.push(f.id) }); http({ url: '/user/terminal/online', method: 'get', @@ -52,7 +64,6 @@ export default { }).then((onlineTerminals) => { this.commit("setOnlineStatus", onlineTerminals); }) - // 30s后重新拉取 state.timer && clearTimeout(state.timer); state.timer = setTimeout(() => { @@ -100,10 +111,18 @@ export default { context.commit("setFriends", friends); context.commit("refreshOnlineStatus"); resolve() - }).catch((res) => { + }).catch(() => { reject(); }) }); } + }, + getters: { + isFriend: (state) => (userId) => { + return state.friends.filter((f)=>!f.deleted).some((f)=>f.id == userId); + }, + findFriend: (state) => (userId) => { + return state.friends.find((f)=>f.id == userId); + } } } diff --git a/im-web/src/view/Friend.vue b/im-web/src/view/Friend.vue index 6d35f38..7ff119a 100644 --- a/im-web/src/view/Friend.vue +++ b/im-web/src/view/Friend.vue @@ -11,9 +11,9 @@
- + @delete="onDelItem(friend)" @click.native="onActiveItem(friend, index)">
@@ -72,7 +72,8 @@ export default { searchText: "", showAddFriend: false, activeIdx: -1, - userInfo: {} + userInfo: {}, + friend: {} } }, methods: { @@ -85,9 +86,10 @@ export default { onActiveItem(friend, idx) { this.$store.commit("activeFriend", idx); this.activeIdx = idx - this.loadUserInfo(friend, idx); + this.friend = friend; + this.loadUserInfo(friend.id); }, - onDelItem(friend, idx) { + onDelItem(friend) { this.$confirm(`确认删除'${friend.nickName}',并清空聊天记录吗?`, '确认解除?', { confirmButtonText: '确定', cancelButtonText: '取消', @@ -96,9 +98,9 @@ export default { this.$http({ url: `/friend/delete/${friend.id}`, method: 'delete' - }).then((data) => { + }).then(() => { this.$message.success("删除好友成功"); - this.$store.commit("removeFriend", idx); + this.$store.commit("removeFriend", friend.id); this.$store.commit("removePrivateChat", friend.id); }) }) @@ -110,7 +112,7 @@ export default { params: { friendId: user.id } - }).then((data) => { + }).then(() => { this.$message.success("添加成功,对方已成为您的好友"); let friend = { id: user.id, @@ -128,6 +130,7 @@ export default { showName: user.nickName, headImage: user.headImageThumb, }; + console.log("chat:",chat) this.$store.commit("openChat", chat); this.$store.commit("activeChat", 0); this.$router.push("/home/chat"); @@ -137,31 +140,24 @@ export default { this.$store.commit('showFullImageBox', this.userInfo.headImage); } }, - updateFriendInfo(friend, user, index) { - // store的数据不能直接修改,深拷贝一份store的数据 - friend = JSON.parse(JSON.stringify(friend)); - friend.headImage = user.headImageThumb; - friend.nickName = user.nickName; - this.$http({ - url: "/friend/update", - method: "put", - data: friend - }).then(() => { + updateFriendInfo() { + if (this.isFriend) { + // store的数据不能直接修改,深拷贝一份store的数据 + let friend = JSON.parse(JSON.stringify(this.friend)); + friend.headImage = this.userInfo.headImageThumb; + friend.nickName = this.userInfo.nickName; + this.$store.commit("updateChatFromFriend", friend); this.$store.commit("updateFriend", friend); - this.$store.commit("updateChatFromFriend", user); - }) + } }, - loadUserInfo(friend, index) { + loadUserInfo(id) { + // 获取好友用户信息 this.$http({ - url: `/user/find/${friend.id}`, - method: 'get' - }).then((user) => { - this.userInfo = user; - // 如果发现好友的头像和昵称改了,进行更新 - if (user.headImageThumb != friend.headImage || - user.nickName != friend.nickName) { - this.updateFriendInfo(friend, user, index) - } + url: `/user/find/${id}`, + method: 'GET' + }).then((userInfo) => { + this.userInfo = userInfo; + this.updateFriendInfo(); }) } }, diff --git a/im-web/src/view/Home.vue b/im-web/src/view/Home.vue index 9f28b13..4fa7333 100644 --- a/im-web/src/view/Home.vue +++ b/im-web/src/view/Home.vue @@ -189,18 +189,27 @@ export default { this.$store.commit("recallMessage", [msg, chatInfo]) return; } + // 新增好友 + if (msg.type == this.$enums.MESSAGE_TYPE.FRIEND_NEW) { + this.$store.commit("addFriend", JSON.parse(msg.content)); + return; + } + // 删除好友 + if (msg.type == this.$enums.MESSAGE_TYPE.FRIEND_DEL) { + this.$store.commit("removeFriend", friendId); + return; + } // 单人webrtc 信令 if (this.$msgType.isRtcPrivate(msg.type)) { this.$refs.rtcPrivateVideo.onRTCMessage(msg) return; } // 好友id - this.loadFriendInfo(friendId).then((friend) => { - this.insertPrivateMessage(friend, msg); - }) + let friend = this.loadFriendInfo(friendId); + this.insertPrivateMessage(friend, msg); + }, insertPrivateMessage(friend, msg) { - let chatInfo = { type: 'PRIVATE', targetId: friend.id, @@ -322,20 +331,15 @@ export default { this.showSettingDialog = false; }, loadFriendInfo(id) { - return new Promise((resolve, reject) => { - let friend = this.$store.state.friendStore.friends.find((f) => f.id == id); - if (friend) { - resolve(friend); - } else { - this.$http({ - url: `/friend/find/${id}`, - method: 'get' - }).then((friend) => { - this.$store.commit("addFriend", friend); - resolve(friend) - }) + let friend = this.$store.state.friendStore.friends.find((f) => f.id == id); + if (!friend) { + friend = { + id: id, + showNickName: "未知用户", + headImage: "" } - }); + } + return friend; }, loadGroupInfo(id) { return new Promise((resolve, reject) => {