Browse Source

消息撤回优化,支持离线撤回

master
xsx 1 year ago
parent
commit
641babd2be
  1. 5
      im-platform/src/main/java/com/bx/implatform/controller/GroupMessageController.java
  2. 5
      im-platform/src/main/java/com/bx/implatform/controller/PrivateMessageController.java
  3. 2
      im-platform/src/main/java/com/bx/implatform/service/GroupMessageService.java
  4. 2
      im-platform/src/main/java/com/bx/implatform/service/PrivateMessageService.java
  5. 34
      im-platform/src/main/java/com/bx/implatform/service/impl/GroupMessageServiceImpl.java
  6. 30
      im-platform/src/main/java/com/bx/implatform/service/impl/PrivateMessageServiceImpl.java
  7. 47
      im-uniapp/App.vue
  8. 7
      im-uniapp/components/chat-message-item/chat-message-item.vue
  9. 12
      im-uniapp/main.js
  10. 9
      im-uniapp/pages/chat/chat-box.vue
  11. 38
      im-uniapp/store/chatStore.js
  12. 10
      im-web/src/components/chat/ChatBox.vue
  13. 6
      im-web/src/components/chat/ChatMessageItem.vue
  14. 40
      im-web/src/store/chatStore.js
  15. 2
      im-web/src/view/Chat.vue
  16. 44
      im-web/src/view/Home.vue

5
im-platform/src/main/java/com/bx/implatform/controller/GroupMessageController.java

@ -30,9 +30,8 @@ public class GroupMessageController {
@DeleteMapping("/recall/{id}") @DeleteMapping("/recall/{id}")
@Operation(summary = "撤回消息", description = "撤回群聊消息") @Operation(summary = "撤回消息", description = "撤回群聊消息")
public Result<Long> recallMessage(@NotNull(message = "消息id不能为空") @PathVariable Long id) { public Result<GroupMessageVO> recallMessage(@NotNull(message = "消息id不能为空") @PathVariable Long id) {
groupMessageService.recallMessage(id); return ResultUtils.success(groupMessageService.recallMessage(id));
return ResultUtils.success();
} }
@GetMapping("/pullOfflineMessage") @GetMapping("/pullOfflineMessage")

5
im-platform/src/main/java/com/bx/implatform/controller/PrivateMessageController.java

@ -30,9 +30,8 @@ public class PrivateMessageController {
@DeleteMapping("/recall/{id}") @DeleteMapping("/recall/{id}")
@Operation(summary = "撤回消息", description = "撤回私聊消息") @Operation(summary = "撤回消息", description = "撤回私聊消息")
public Result<Long> recallMessage(@NotNull(message = "消息id不能为空") @PathVariable Long id) { public Result<PrivateMessageVO> recallMessage(@NotNull(message = "消息id不能为空") @PathVariable Long id) {
privateMessageService.recallMessage(id); return ResultUtils.success( privateMessageService.recallMessage(id));
return ResultUtils.success();
} }
@GetMapping("/pullOfflineMessage") @GetMapping("/pullOfflineMessage")

2
im-platform/src/main/java/com/bx/implatform/service/GroupMessageService.java

@ -22,7 +22,7 @@ public interface GroupMessageService extends IService<GroupMessage> {
* *
* @param id 消息id * @param id 消息id
*/ */
void recallMessage(Long id); GroupMessageVO recallMessage(Long id);
/** /**
* 拉取离线消息只能拉取最近1个月的消息最多拉取1000条 * 拉取离线消息只能拉取最近1个月的消息最多拉取1000条

2
im-platform/src/main/java/com/bx/implatform/service/PrivateMessageService.java

@ -23,7 +23,7 @@ public interface PrivateMessageService extends IService<PrivateMessage> {
* *
* @param id 消息id * @param id 消息id
*/ */
void recallMessage(Long id); PrivateMessageVO recallMessage(Long id);
/** /**
* 拉取历史聊天记录 * 拉取历史聊天记录

34
im-platform/src/main/java/com/bx/implatform/service/impl/GroupMessageServiceImpl.java

@ -38,6 +38,7 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils; import org.apache.commons.lang3.time.DateUtils;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*; import java.util.*;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
@ -92,8 +93,9 @@ public class GroupMessageServiceImpl extends ServiceImpl<GroupMessageMapper, Gro
return msgInfo; return msgInfo;
} }
@Transactional
@Override @Override
public void recallMessage(Long id) { public GroupMessageVO recallMessage(Long id) {
UserSession session = SessionContext.getSession(); UserSession session = SessionContext.getSession();
GroupMessage msg = this.getById(id); GroupMessage msg = this.getById(id);
if (Objects.isNull(msg)) { if (Objects.isNull(msg)) {
@ -113,31 +115,26 @@ public class GroupMessageServiceImpl extends ServiceImpl<GroupMessageMapper, Gro
// 修改数据库 // 修改数据库
msg.setStatus(MessageStatus.RECALL.code()); msg.setStatus(MessageStatus.RECALL.code());
this.updateById(msg); this.updateById(msg);
// 生成一条撤回消息
GroupMessage recallMsg = new GroupMessage();
recallMsg.setStatus(MessageStatus.UNSEND.code());
recallMsg.setType(MessageType.RECALL.code());
recallMsg.setGroupId(msg.getGroupId());
recallMsg.setSendId(session.getUserId());
recallMsg.setSendNickName(member.getShowNickName());
recallMsg.setContent(id.toString());
recallMsg.setSendTime(new Date());
this.save(recallMsg);
// 群发 // 群发
List<Long> userIds = groupMemberService.findUserIdsByGroupId(msg.getGroupId()); List<Long> userIds = groupMemberService.findUserIdsByGroupId(msg.getGroupId());
// 不用发给自己 GroupMessageVO msgInfo = BeanUtils.copyProperties(recallMsg, GroupMessageVO.class);
userIds = userIds.stream().filter(uid -> !session.getUserId().equals(uid)).collect(Collectors.toList());
GroupMessageVO msgInfo = BeanUtils.copyProperties(msg, GroupMessageVO.class);
msgInfo.setType(MessageType.RECALL.code());
String content = String.format("'%s'撤回了一条消息", member.getShowNickName());
msgInfo.setContent(content);
msgInfo.setSendTime(new Date());
IMGroupMessage<GroupMessageVO> sendMessage = new IMGroupMessage<>(); IMGroupMessage<GroupMessageVO> sendMessage = new IMGroupMessage<>();
sendMessage.setSender(new IMUserInfo(session.getUserId(), session.getTerminal())); sendMessage.setSender(new IMUserInfo(session.getUserId(), session.getTerminal()));
sendMessage.setRecvIds(userIds); sendMessage.setRecvIds(userIds);
sendMessage.setData(msgInfo); sendMessage.setData(msgInfo);
sendMessage.setSendResult(false);
sendMessage.setSendToSelf(false);
imClient.sendGroupMessage(sendMessage);
// 推给自己其他终端
msgInfo.setContent("你撤回了一条消息");
sendMessage.setSendToSelf(true);
sendMessage.setRecvIds(Collections.emptyList());
sendMessage.setRecvTerminals(Collections.emptyList());
imClient.sendGroupMessage(sendMessage); imClient.sendGroupMessage(sendMessage);
log.info("撤回群聊消息,发送id:{},群聊id:{},内容:{}", session.getUserId(), msg.getGroupId(), msg.getContent()); log.info("撤回群聊消息,发送id:{},群聊id:{},内容:{}", session.getUserId(), msg.getGroupId(), msg.getContent());
return msgInfo;
} }
@ -165,7 +162,6 @@ public class GroupMessageServiceImpl extends ServiceImpl<GroupMessageMapper, Gro
wrapper.gt(GroupMessage::getId, minId) wrapper.gt(GroupMessage::getId, minId)
.gt(GroupMessage::getSendTime, minDate) .gt(GroupMessage::getSendTime, minDate)
.in(GroupMessage::getGroupId, groupIds) .in(GroupMessage::getGroupId, groupIds)
.ne(GroupMessage::getStatus, MessageStatus.RECALL.code())
.orderByAsc(GroupMessage::getId); .orderByAsc(GroupMessage::getId);
List<GroupMessage> messages = this.list(wrapper); List<GroupMessage> messages = this.list(wrapper);
// 通过群聊对消息进行分组 // 通过群聊对消息进行分组

30
im-platform/src/main/java/com/bx/implatform/service/impl/PrivateMessageServiceImpl.java

@ -74,8 +74,9 @@ public class PrivateMessageServiceImpl extends ServiceImpl<PrivateMessageMapper,
return msgInfo; return msgInfo;
} }
@Transactional
@Override @Override
public void recallMessage(Long id) { public PrivateMessageVO recallMessage(Long id) {
UserSession session = SessionContext.getSession(); UserSession session = SessionContext.getSession();
PrivateMessage msg = this.getById(id); PrivateMessage msg = this.getById(id);
if (Objects.isNull(msg)) { if (Objects.isNull(msg)) {
@ -90,26 +91,24 @@ public class PrivateMessageServiceImpl extends ServiceImpl<PrivateMessageMapper,
// 修改消息状态 // 修改消息状态
msg.setStatus(MessageStatus.RECALL.code()); msg.setStatus(MessageStatus.RECALL.code());
this.updateById(msg); this.updateById(msg);
// 生成一条撤回消息
PrivateMessage recallMsg = new PrivateMessage();
recallMsg.setSendId(session.getUserId());
recallMsg.setStatus(MessageStatus.UNSEND.code());
recallMsg.setSendTime(new Date());
recallMsg.setRecvId(msg.getRecvId());
recallMsg.setType(MessageType.RECALL.code());
recallMsg.setContent(id.toString());
this.save(recallMsg);
// 推送消息 // 推送消息
PrivateMessageVO msgInfo = BeanUtils.copyProperties(msg, PrivateMessageVO.class); PrivateMessageVO msgInfo = BeanUtils.copyProperties(recallMsg, PrivateMessageVO.class);
msgInfo.setType(MessageType.RECALL.code());
msgInfo.setSendTime(new Date());
msgInfo.setContent("对方撤回了一条消息");
IMPrivateMessage<PrivateMessageVO> sendMessage = new IMPrivateMessage<>(); IMPrivateMessage<PrivateMessageVO> sendMessage = new IMPrivateMessage<>();
sendMessage.setSender(new IMUserInfo(session.getUserId(), session.getTerminal())); sendMessage.setSender(new IMUserInfo(session.getUserId(), session.getTerminal()));
sendMessage.setRecvId(msgInfo.getRecvId()); sendMessage.setRecvId(msgInfo.getRecvId());
sendMessage.setSendToSelf(false);
sendMessage.setData(msgInfo); sendMessage.setData(msgInfo);
sendMessage.setSendResult(false);
imClient.sendPrivateMessage(sendMessage);
// 推给自己其他终端
msgInfo.setContent("你撤回了一条消息");
sendMessage.setSendToSelf(true);
sendMessage.setRecvTerminals(Collections.emptyList());
imClient.sendPrivateMessage(sendMessage); imClient.sendPrivateMessage(sendMessage);
log.info("撤回私聊消息,发送id:{},接收id:{},内容:{}", msg.getSendId(), msg.getRecvId(), msg.getContent()); log.info("撤回私聊消息,发送id:{},接收id:{},内容:{}", msg.getSendId(), msg.getRecvId(), msg.getContent());
return msgInfo;
} }
@Override @Override
@ -154,8 +153,7 @@ public class PrivateMessageServiceImpl extends ServiceImpl<PrivateMessageMapper,
// 只能拉取最近3个月的消息,移动端只拉取一个月消息 // 只能拉取最近3个月的消息,移动端只拉取一个月消息
int months = session.getTerminal().equals(IMTerminalType.APP.code()) ? 1 : 3; int months = session.getTerminal().equals(IMTerminalType.APP.code()) ? 1 : 3;
Date minDate = DateUtils.addMonths(new Date(), -months); Date minDate = DateUtils.addMonths(new Date(), -months);
queryWrapper.gt(PrivateMessage::getId, minId).ge(PrivateMessage::getSendTime, minDate) queryWrapper.gt(PrivateMessage::getId, minId).ge(PrivateMessage::getSendTime, minDate).and(wrap -> wrap.and(
.ne(PrivateMessage::getStatus, MessageStatus.RECALL.code()).and(wrap -> wrap.and(
wp -> wp.eq(PrivateMessage::getSendId, session.getUserId()).in(PrivateMessage::getRecvId, friendIds)) wp -> wp.eq(PrivateMessage::getSendId, session.getUserId()).in(PrivateMessage::getRecvId, friendIds))
.or(wp -> wp.eq(PrivateMessage::getRecvId, session.getUserId()).in(PrivateMessage::getSendId, friendIds))) .or(wp -> wp.eq(PrivateMessage::getRecvId, session.getUserId()).in(PrivateMessage::getSendId, friendIds)))
.orderByAsc(PrivateMessage::getId); .orderByAsc(PrivateMessage::getId);

47
im-uniapp/App.vue

@ -107,6 +107,15 @@ export default {
}) })
}, },
handlePrivateMessage(msg) { handlePrivateMessage(msg) {
//
msg.selfSend = msg.sendId == this.userStore.userInfo.id;
// id
let friendId = msg.selfSend ? msg.recvId : msg.sendId;
//
let chatInfo = {
type: 'PRIVATE',
targetId: friendId
}
// //
if (msg.type == enums.MESSAGE_TYPE.LOADING) { if (msg.type == enums.MESSAGE_TYPE.LOADING) {
this.chatStore.setLoadingPrivateMsg(JSON.parse(msg.content)) this.chatStore.setLoadingPrivateMsg(JSON.parse(msg.content))
@ -114,10 +123,7 @@ export default {
} }
// //
if (msg.type == enums.MESSAGE_TYPE.READED) { if (msg.type == enums.MESSAGE_TYPE.READED) {
this.chatStore.resetUnreadCount({ this.chatStore.resetUnreadCount(chatInfo);
type: 'PRIVATE',
targetId: msg.recvId
})
return; return;
} }
// , // ,
@ -127,10 +133,12 @@ export default {
}) })
return; return;
} }
// //
msg.selfSend = msg.sendId == this.userStore.userInfo.id; if (msg.type == enums.MESSAGE_TYPE.RECALL) {
// id this.chatStore.recallMessage(msg, chatInfo);
let friendId = msg.selfSend ? msg.recvId : msg.sendId; return;
}
//
this.loadFriendInfo(friendId, (friend) => { this.loadFriendInfo(friendId, (friend) => {
this.insertPrivateMessage(friend, msg); this.insertPrivateMessage(friend, msg);
}) })
@ -177,6 +185,12 @@ export default {
}, },
handleGroupMessage(msg) { handleGroupMessage(msg) {
//
msg.selfSend = msg.sendId == this.userStore.userInfo.id;
let chatInfo = {
type: 'GROUP',
targetId: msg.groupId
}
// //
if (msg.type == enums.MESSAGE_TYPE.LOADING) { if (msg.type == enums.MESSAGE_TYPE.LOADING) {
this.chatStore.setLoadingGroupMsg(JSON.parse(msg.content)) this.chatStore.setLoadingGroupMsg(JSON.parse(msg.content))
@ -185,19 +199,11 @@ export default {
// //
if (msg.type == enums.MESSAGE_TYPE.READED) { if (msg.type == enums.MESSAGE_TYPE.READED) {
// //
let chatInfo = {
type: 'GROUP',
targetId: msg.groupId
}
this.chatStore.resetUnreadCount(chatInfo) this.chatStore.resetUnreadCount(chatInfo)
return; return;
} }
// //
if (msg.type == enums.MESSAGE_TYPE.RECEIPT) { if (msg.type == enums.MESSAGE_TYPE.RECEIPT) {
let chatInfo = {
type: 'GROUP',
targetId: msg.groupId
}
// //
let msgInfo = { let msgInfo = {
id: msg.id, id: msg.id,
@ -205,11 +211,14 @@ export default {
readedCount: msg.readedCount, readedCount: msg.readedCount,
receiptOk: msg.receiptOk receiptOk: msg.receiptOk
}; };
this.chatStore.updateMessage(msgInfo,chatInfo) this.chatStore.updateMessage(msgInfo, chatInfo)
return;
}
//
if (msg.type == this.$enums.MESSAGE_TYPE.RECALL) {
this.chatStore.recallMessage(msg, chatInfo)
return; return;
} }
//
msg.selfSend = msg.sendId == this.userStore.userInfo.id;
this.loadGroupInfo(msg.groupId, (group) => { this.loadGroupInfo(msg.groupId, (group) => {
// //
this.insertGroupMessage(group, msg); this.insertGroupMessage(group, msg);

7
im-uniapp/components/chat-message-item/chat-message-item.vue

@ -1,13 +1,12 @@
<template> <template>
<view class="chat-msg-item"> <view class="chat-msg-item">
<view class="chat-msg-tip" <view class="chat-msg-tip" v-if="msgInfo.type == $enums.MESSAGE_TYPE.TIP_TEXT">
v-if="msgInfo.type == $enums.MESSAGE_TYPE.RECALL || msgInfo.type == $enums.MESSAGE_TYPE.TIP_TEXT">
{{ msgInfo.content }} {{ msgInfo.content }}
</view> </view>
<view class="chat-msg-tip" v-if="msgInfo.type == $enums.MESSAGE_TYPE.TIP_TIME"> <view class="chat-msg-tip" v-else-if="msgInfo.type == $enums.MESSAGE_TYPE.TIP_TIME">
{{ $date.toTimeText(msgInfo.sendTime) }} {{ $date.toTimeText(msgInfo.sendTime) }}
</view> </view>
<view class="chat-msg-normal" v-if="isNormal" :class="{ 'chat-msg-mine': msgInfo.selfSend }"> <view class="chat-msg-normal" v-else-if="isNormal" :class="{ 'chat-msg-mine': msgInfo.selfSend }">
<head-image class="avatar" @longpress.prevent="$emit('longPressHead')" :id="msgInfo.sendId" :url="headImage" <head-image class="avatar" @longpress.prevent="$emit('longPressHead')" :id="msgInfo.sendId" :url="headImage"
:name="showName" size="small"></head-image> :name="showName" size="small"></head-image>
<view class="chat-msg-content"> <view class="chat-msg-content">

12
im-uniapp/main.js

@ -19,17 +19,15 @@ import arrowBar from '@/components/bar/arrow-bar'
import btnBar from '@/components/bar/btn-bar' import btnBar from '@/components/bar/btn-bar'
import switchBar from '@/components/bar/switch-bar' import switchBar from '@/components/bar/switch-bar'
// #ifdef H5 // #ifdef H5
// import VConsole from 'vconsole' import * as recorder from './common/recorder-h5';
// new VConsole();
// #endif
// #ifdef H5
import ImageResize from "quill-image-resize-mp"; import ImageResize from "quill-image-resize-mp";
import Quill from "quill"; import Quill from "quill";
// 以下组件用于兼容部分手机聊天边框无法输入的问题
window.Quill = Quill; window.Quill = Quill;
window.ImageResize = { default: ImageResize }; window.ImageResize = { default: ImageResize };
// #endif // 调试器
// #ifdef H5 // import VConsole from 'vconsole'
import * as recorder from './common/recorder-h5'; // new VConsole();
// #endif // #endif
// #ifndef H5 // #ifndef H5
import * as recorder from './common/recorder-app'; import * as recorder from './common/recorder-app';

9
im-uniapp/pages/chat/chat-box.vue

@ -519,12 +519,9 @@ export default {
this.$http({ this.$http({
url: url, url: url,
method: 'DELETE' method: 'DELETE'
}).then(() => { }).then((m) => {
msgInfo = JSON.parse(JSON.stringify(msgInfo)); m.selfSend = true;
msgInfo.type = this.$enums.MESSAGE_TYPE.RECALL; this.chatStore.recallMessage(m, this.chat);
msgInfo.content = '你撤回了一条消息';
msgInfo.status = this.$enums.MESSAGE_STATUS.RECALL;
this.chatStore.insertMessage(msgInfo, this.chat);
}) })
} }
} }

38
im-uniapp/store/chatStore.js

@ -156,10 +156,6 @@ export default defineStore('chatStore', {
let message = this.findMessage(chat, msgInfo); let message = this.findMessage(chat, msgInfo);
if (message) { if (message) {
Object.assign(message, msgInfo); Object.assign(message, msgInfo);
// 撤回消息需要显示
if (msgInfo.type == MESSAGE_TYPE.RECALL) {
chat.lastContent = msgInfo.content;
}
chat.stored = false; chat.stored = false;
this.saveToStorage(); this.saveToStorage();
return; return;
@ -248,9 +244,8 @@ export default defineStore('chatStore', {
chat.messages.splice(idx, 1); chat.messages.splice(idx, 1);
break; break;
} }
// 正在发送中的消息可能没有id,根据发送时间删除 // 正在发送中的消息可能没有id,只有临时id
if (msgInfo.selfSend && chat.messages[idx].selfSend && if (chat.messages[idx].tmpId && chat.messages[idx].tmpId == msgInfo.tmpId) {
chat.messages[idx].sendTime == msgInfo.sendTime) {
chat.messages.splice(idx, 1); chat.messages.splice(idx, 1);
break; break;
} }
@ -258,6 +253,35 @@ export default defineStore('chatStore', {
chat.stored = false; chat.stored = false;
this.saveToStorage(); this.saveToStorage();
}, },
recallMessage(msgInfo, chatInfo) {
let chat = this.findChat(chatInfo);
if (!chat) return;
// 要撤回的消息id
let id = msgInfo.content;
let name = msgInfo.selfSend ? '你' : chat.type == 'PRIVATE' ? '对方' : msgInfo.sendNickName;
for (let idx in chat.messages) {
let m = chat.messages[idx];
if (m.id && m.id == id) {
// 改造成一条提示消息
m.status = MESSAGE_STATUS.RECALL;
m.content = name + "撤回了一条消息";
m.type = MESSAGE_TYPE.TIP_TEXT
// 会话列表
chat.lastContent = m.content;
chat.lastSendTime = msgInfo.sendTime;
chat.sendNickName = '';
chat.unreadCount++;
}
// 被引用的消息也要撤回
if (m.quoteMessage && m.quoteMessage.id == msgInfo.id) {
m.quoteMessage.content = "引用内容已撤回";
m.quoteMessage.status = MESSAGE_STATUS.RECALL;
m.quoteMessage.type = MESSAGE_TYPE.TIP_TEXT
}
}
chat.stored = false;
this.saveToStorage();
},
updateChatFromFriend(friend) { updateChatFromFriend(friend) {
let chat = this.findChatByFriend(friend.id) let chat = this.findChatByFriend(friend.id)
if (chat && (chat.headImage != friend.headImageThumb || if (chat && (chat.headImage != friend.headImageThumb ||

10
im-web/src/components/chat/ChatBox.vue

@ -490,13 +490,10 @@ export default {
this.$http({ this.$http({
url: url, url: url,
method: 'delete' method: 'delete'
}).then(() => { }).then((m) => {
this.$message.success("消息已撤回"); this.$message.success("消息已撤回");
msgInfo = JSON.parse(JSON.stringify(msgInfo)); m.selfSend = true;
msgInfo.type = 10; this.$store.commit("recallMessage", [m, this.chat]);
msgInfo.content = '你撤回了一条消息';
msgInfo.status = this.$enums.MESSAGE_STATUS.RECALL;
this.$store.commit("insertMessage", [msgInfo, this.chat]);
}) })
}); });
}, },
@ -572,7 +569,6 @@ export default {
} }
}, },
resetEditor() { resetEditor() {
this.$nextTick(() => { this.$nextTick(() => {
this.$refs.chatInputEditor.clear(); this.$refs.chatInputEditor.clear();
this.$refs.chatInputEditor.focus(); this.$refs.chatInputEditor.focus();

6
im-web/src/components/chat/ChatMessageItem.vue

@ -1,13 +1,13 @@
<template> <template>
<div class="chat-msg-item"> <div class="chat-msg-item">
<div class="chat-msg-tip" <div class="chat-msg-tip"
v-if="msgInfo.type == $enums.MESSAGE_TYPE.RECALL || msgInfo.type == $enums.MESSAGE_TYPE.TIP_TEXT"> v-if="msgInfo.type == $enums.MESSAGE_TYPE.TIP_TEXT">
{{ msgInfo.content }} {{ msgInfo.content }}
</div> </div>
<div class="chat-msg-tip" v-if="msgInfo.type == $enums.MESSAGE_TYPE.TIP_TIME"> <div class="chat-msg-tip" v-else-if="msgInfo.type == $enums.MESSAGE_TYPE.TIP_TIME">
{{ $date.toTimeText(msgInfo.sendTime) }} {{ $date.toTimeText(msgInfo.sendTime) }}
</div> </div>
<div class="chat-msg-normal" v-if="isNormal" :class="{ 'chat-msg-mine': mine }"> <div class="chat-msg-normal" v-else-if="isNormal" :class="{ 'chat-msg-mine': mine }">
<div class="head-image"> <div class="head-image">
<head-image :name="showName" :size="38" :url="headImage" :id="msgInfo.sendId"></head-image> <head-image :name="showName" :size="38" :url="headImage" :id="msgInfo.sendId"></head-image>
</div> </div>

40
im-web/src/store/chatStore.js

@ -151,10 +151,6 @@ export default {
let message = this.getters.findMessage(chat, msgInfo); let message = this.getters.findMessage(chat, msgInfo);
if (message) { if (message) {
Object.assign(message, msgInfo); Object.assign(message, msgInfo);
// 撤回消息需要显示
if (msgInfo.type == MESSAGE_TYPE.RECALL) {
chat.lastContent = msgInfo.content;
}
chat.stored = false; chat.stored = false;
this.commit("saveToStorage"); this.commit("saveToStorage");
return; return;
@ -236,9 +232,8 @@ export default {
chat.messages.splice(idx, 1); chat.messages.splice(idx, 1);
break; break;
} }
// 正在发送中的消息可能没有id,根据发送时间删除 // 正在发送中的消息可能没有id,只有临时id
if (msgInfo.selfSend && chat.messages[idx].selfSend && if (chat.messages[idx].tmpId && chat.messages[idx].tmpId == msgInfo.tmpId) {
chat.messages[idx].sendTime == msgInfo.sendTime) {
chat.messages.splice(idx, 1); chat.messages.splice(idx, 1);
break; break;
} }
@ -246,6 +241,37 @@ export default {
chat.stored = false; chat.stored = false;
this.commit("saveToStorage"); this.commit("saveToStorage");
}, },
recallMessage(state, [msgInfo, chatInfo]) {
let chat = this.getters.findChat(chatInfo);
if (!chat) return;
// 要撤回的消息id
let id = msgInfo.content;
let name = msgInfo.selfSend ? '你' : chat.type == 'PRIVATE' ? '对方' : msgInfo.sendNickName;
for (let idx in chat.messages) {
let m = chat.messages[idx];
if (m.id && m.id == id) {
// 改造成一条提示消息
m.status = MESSAGE_STATUS.RECALL;
m.content = name + "撤回了一条消息";
m.type = MESSAGE_TYPE.TIP_TEXT
// 会话列表
chat.lastContent = m.content;
chat.lastSendTime = msgInfo.sendTime;
chat.sendNickName = '';
if(!msgInfo.selfSend){
chat.unreadCount++;
}
}
// 被引用的消息也要撤回
if (m.quoteMessage && m.quoteMessage.id == msgInfo.id) {
m.quoteMessage.content = "引用内容已撤回";
m.quoteMessage.status = MESSAGE_STATUS.RECALL;
m.quoteMessage.type = MESSAGE_TYPE.TIP_TEXT
}
}
chat.stored = false;
this.commit("saveToStorage");
},
updateChatFromFriend(state, friend) { updateChatFromFriend(state, friend) {
let chat = this.getters.findChatByFriend(friend.id); let chat = this.getters.findChatByFriend(friend.id);
// 更新会话中的群名和头像 // 更新会话中的群名和头像

2
im-web/src/view/Chat.vue

@ -11,7 +11,7 @@
</div> </div>
<el-scrollbar class="chat-list-items" v-else> <el-scrollbar class="chat-list-items" v-else>
<div v-for="(chat, index) in chatStore.chats" :key="index"> <div v-for="(chat, index) in chatStore.chats" :key="index">
<chat-item v-show="!chat.delete && chat.showName.includes(searchText)" :chat="chat" :index="index" <chat-item v-show="!chat.delete && chat.showName && chat.showName.includes(searchText)" :chat="chat" :index="index"
@click.native="onActiveItem(index)" @delete="onDelItem(index)" @top="onTop(index)" @click.native="onActiveItem(index)" @delete="onDelItem(index)" @top="onTop(index)"
:active="chat === chatStore.activeChat"></chat-item> :active="chat === chatStore.activeChat"></chat-item>
</div> </div>

44
im-web/src/view/Home.vue

@ -6,7 +6,8 @@
<div class="top"> <div class="top">
<div class="user-head-image"> <div class="user-head-image">
<head-image :name="$store.state.userStore.userInfo.nickName" :size="38" <head-image :name="$store.state.userStore.userInfo.nickName" :size="38"
:url="$store.state.userStore.userInfo.headImageThumb" @click.native="showSettingDialog = true"> :url="$store.state.userStore.userInfo.headImageThumb"
@click.native="showSettingDialog = true">
</head-image> </head-image>
</div> </div>
@ -157,6 +158,15 @@ export default {
}) })
}, },
handlePrivateMessage(msg) { handlePrivateMessage(msg) {
//
msg.selfSend = msg.sendId == this.$store.state.userStore.userInfo.id;
// id
let friendId = msg.selfSend ? msg.recvId : msg.sendId;
//
let chatInfo = {
type: 'PRIVATE',
targetId: friendId
}
// //
if (msg.type == this.$enums.MESSAGE_TYPE.LOADING) { if (msg.type == this.$enums.MESSAGE_TYPE.LOADING) {
this.$store.commit("loadingPrivateMsg", JSON.parse(msg.content)) this.$store.commit("loadingPrivateMsg", JSON.parse(msg.content))
@ -164,10 +174,7 @@ export default {
} }
// //
if (msg.type == this.$enums.MESSAGE_TYPE.READED) { if (msg.type == this.$enums.MESSAGE_TYPE.READED) {
this.$store.commit("resetUnreadCount", { this.$store.commit("resetUnreadCount", chatInfo)
type: 'PRIVATE',
targetId: msg.recvId
})
return; return;
} }
// , // ,
@ -177,15 +184,17 @@ export default {
}) })
return; return;
} }
// //
msg.selfSend = msg.sendId == this.$store.state.userStore.userInfo.id; if (msg.type == this.$enums.MESSAGE_TYPE.RECALL) {
this.$store.commit("recallMessage", [msg, chatInfo])
return;
}
// webrtc // webrtc
if (this.$msgType.isRtcPrivate(msg.type)) { if (this.$msgType.isRtcPrivate(msg.type)) {
this.$refs.rtcPrivateVideo.onRTCMessage(msg) this.$refs.rtcPrivateVideo.onRTCMessage(msg)
return; return;
} }
// id // id
let friendId = msg.selfSend ? msg.recvId : msg.sendId;
this.loadFriendInfo(friendId).then((friend) => { this.loadFriendInfo(friendId).then((friend) => {
this.insertPrivateMessage(friend, msg); this.insertPrivateMessage(friend, msg);
}) })
@ -209,6 +218,12 @@ export default {
} }
}, },
handleGroupMessage(msg) { handleGroupMessage(msg) {
//
msg.selfSend = msg.sendId == this.$store.state.userStore.userInfo.id;
let chatInfo = {
type: 'GROUP',
targetId: msg.groupId
}
// //
if (msg.type == this.$enums.MESSAGE_TYPE.LOADING) { if (msg.type == this.$enums.MESSAGE_TYPE.LOADING) {
this.$store.commit("loadingGroupMsg", JSON.parse(msg.content)) this.$store.commit("loadingGroupMsg", JSON.parse(msg.content))
@ -217,10 +232,6 @@ export default {
// //
if (msg.type == this.$enums.MESSAGE_TYPE.READED) { if (msg.type == this.$enums.MESSAGE_TYPE.READED) {
// //
let chatInfo = {
type: 'GROUP',
targetId: msg.groupId
}
this.$store.commit("resetUnreadCount", chatInfo) this.$store.commit("resetUnreadCount", chatInfo)
return; return;
} }
@ -233,11 +244,14 @@ export default {
readedCount: msg.readedCount, readedCount: msg.readedCount,
receiptOk: msg.receiptOk receiptOk: msg.receiptOk
}; };
this.$store.commit("updateMessage", msgInfo) this.$store.commit("updateMessage", [msgInfo, chatInfo])
return;
}
//
if (msg.type == this.$enums.MESSAGE_TYPE.RECALL) {
this.$store.commit("recallMessage", [msg, chatInfo])
return; return;
} }
//
msg.selfSend = msg.sendId == this.$store.state.userStore.userInfo.id;
// //
if (this.$msgType.isRtcGroup(msg.type)) { if (this.$msgType.isRtcGroup(msg.type)) {
this.$nextTick(() => { this.$nextTick(() => {

Loading…
Cancel
Save