diff --git a/src/js/websocket/constructor.js b/src/js/websocket/constructor.js index 629f62d..14c7c94 100644 --- a/src/js/websocket/constructor.js +++ b/src/js/websocket/constructor.js @@ -54,6 +54,29 @@ export const helloConstructor = () => { return data } +export const chatReadConstructor = (toId, content) => { + const header = Header.create({ + magic: proto.magic, + version: proto.version, + msgType: MsgType.CHAT_READ, + isExtension: false + }) + + const userData = userStore() + const body = Body.create({ + fromId: userData.user.account, + fromClient: userData.clientId, + toId: toId, + content: content, + tempMsgId: uuidv4() + }) + const chatMsg = Msg.create({ header: header, body: body }) + const payload = Msg.encode(chatMsg).finish() + const data = encodePayload(payload) + + return data +} + /** * 发送前对长度编码,配合服务端解决半包黏包问题 * @param {*} payload diff --git a/src/js/websocket/wsConnect.js b/src/js/websocket/wsConnect.js index d95ddf8..8db0866 100644 --- a/src/js/websocket/wsConnect.js +++ b/src/js/websocket/wsConnect.js @@ -2,7 +2,12 @@ import { Msg, MsgType } from '@/proto/msg' import { userStore, messageStore } from '@/stores' import { v4 as uuidv4 } from 'uuid' import { generateSign, combineId } from '@/utils/common' -import { chatConstructor, heartBeatConstructor, helloConstructor } from './constructor' +import { + chatConstructor, + heartBeatConstructor, + helloConstructor, + chatReadConstructor +} from './constructor' import { msgChatCreateSessionService } from '@/api/message' class WsConnect { @@ -132,7 +137,8 @@ class WsConnect { dataConstructor = { [MsgType.HELLO]: helloConstructor, [MsgType.HEART_BEAT]: heartBeatConstructor, - [MsgType.CHAT]: chatConstructor + [MsgType.CHAT]: chatConstructor, + [MsgType.CHAT_READ]: chatReadConstructor } /** diff --git a/src/proto/msg.js b/src/proto/msg.js index f0d2d46..3e264b0 100644 --- a/src/proto/msg.js +++ b/src/proto/msg.js @@ -286,9 +286,10 @@ export const Msg = ($root.Msg = (() => { * @property {number} HEART_BEAT=1 HEART_BEAT value * @property {number} CHAT=2 CHAT value * @property {number} GROUP_CHAT=3 GROUP_CHAT value - * @property {number} READ=4 READ value - * @property {number} DELIVERED=5 DELIVERED value - * @property {number} SENDER_SYNC=6 SENDER_SYNC value + * @property {number} CHAT_READ=4 CHAT_READ value + * @property {number} GROUP_CHAT_READ=5 GROUP_CHAT_READ value + * @property {number} DELIVERED=6 DELIVERED value + * @property {number} SENDER_SYNC=7 SENDER_SYNC value * @property {number} CLOSE_BY_READ_IDLE=10 CLOSE_BY_READ_IDLE value * @property {number} CLOSE_BY_ERROR_MAGIC=11 CLOSE_BY_ERROR_MAGIC value * @property {number} DEFAULT=99 DEFAULT value @@ -300,9 +301,10 @@ export const MsgType = ($root.MsgType = (() => { values[(valuesById[1] = 'HEART_BEAT')] = 1 values[(valuesById[2] = 'CHAT')] = 2 values[(valuesById[3] = 'GROUP_CHAT')] = 3 - values[(valuesById[4] = 'READ')] = 4 - values[(valuesById[5] = 'DELIVERED')] = 5 - values[(valuesById[6] = 'SENDER_SYNC')] = 6 + values[(valuesById[4] = 'CHAT_READ')] = 4 + values[(valuesById[5] = 'GROUP_CHAT_READ')] = 5 + values[(valuesById[6] = 'DELIVERED')] = 6 + values[(valuesById[7] = 'SENDER_SYNC')] = 7 values[(valuesById[10] = 'CLOSE_BY_READ_IDLE')] = 10 values[(valuesById[11] = 'CLOSE_BY_ERROR_MAGIC')] = 11 values[(valuesById[99] = 'DEFAULT')] = 99 @@ -495,6 +497,7 @@ export const Header = ($root.Header = (() => { case 4: case 5: case 6: + case 7: case 10: case 11: case 99: @@ -541,18 +544,22 @@ export const Header = ($root.Header = (() => { case 3: message.msgType = 3 break - case 'READ': + case 'CHAT_READ': case 4: message.msgType = 4 break - case 'DELIVERED': + case 'GROUP_CHAT_READ': case 5: message.msgType = 5 break - case 'SENDER_SYNC': + case 'DELIVERED': case 6: message.msgType = 6 break + case 'SENDER_SYNC': + case 7: + message.msgType = 7 + break case 'CLOSE_BY_READ_IDLE': case 10: message.msgType = 10 diff --git a/src/proto/msg.proto b/src/proto/msg.proto index 1843f77..d8916c8 100644 --- a/src/proto/msg.proto +++ b/src/proto/msg.proto @@ -11,9 +11,10 @@ enum MsgType { HEART_BEAT = 1; //心跳 CHAT = 2; //单聊 GROUP_CHAT = 3; //群聊 - READ = 4; // 已读 - DELIVERED = 5; //已发送 - SENDER_SYNC = 6; //发送端多设备之间同步的消息 + CHAT_READ = 4; // 单聊已读 + GROUP_CHAT_READ = 5; // 群聊已读 + DELIVERED = 6; //已发送 + SENDER_SYNC = 7; //发送端多设备之间同步的消息 CLOSE_BY_READ_IDLE = 10; //超时关闭 CLOSE_BY_ERROR_MAGIC = 11; //magic不对关闭 diff --git a/src/stores/message.js b/src/stores/message.js index 59a9f7d..7afa95a 100644 --- a/src/stores/message.js +++ b/src/stores/message.js @@ -48,6 +48,8 @@ export const messageStore = defineStore('anyim-message', () => { if ('top' in obj) mySession.top = obj.top if ('muted' in obj) mySession.muted = obj.muted if ('draft' in obj) mySession.draft = obj.draft + if ('readMsgId' in obj) mySession.readMsgId = obj.readMsgId + if ('readTime' in obj) mySession.readTime = obj.readTime } /** diff --git a/src/views/message/MessageLayout.vue b/src/views/message/MessageLayout.vue index a9e33fa..afedf52 100644 --- a/src/views/message/MessageLayout.vue +++ b/src/views/message/MessageLayout.vue @@ -180,6 +180,11 @@ const onInputBoxDragUpdate = ({ height }) => { }) } +/** + * 通过REST接口主动拉取消息 + * @param mode 0:拉取最近N条;1:按refMsgId向上拉取N条(上滑加载更多消息) + * @param ref mode=1时要携带,标记更新的msgId位置 + */ const pullMsg = async (mode = 0, ref = -1) => { if (hasNoMoreMsg.value) { return @@ -204,7 +209,7 @@ const pullMsg = async (mode = 0, ref = -1) => { lastMsgContent: res.data.data.msgList[msgCount - 1].content, lastMsgTime: res.data.data.msgList[msgCount - 1].msgTime }) - if (mode === 0) msgListReachBottom() + if (mode === 0) msgListReachBottom(false) } else { if (mode === 1) { @@ -221,18 +226,22 @@ const handleIsChoosed = (exportSession) => { sessionId.value = exportSession.sessionId reset() } - else { - // TODO 这个是为了临时消除接收端当前session下出现的未读图标,后面要通过""已读消息"来消除的 - messageData.updateSession({ - sessionId: sessionId.value, - unreadCount: 0 - }) - } - - // 如果切换到的session,在之前都没有pull过消息,则需要pull一次(mode=0方式),且lastMsgId有值才pull + // 如果切换到的session在之前都没有pull过消息,则需要pull一次(mode=0),且lastMsgId有值才pull if (!msgRecords.value && choosedSession.value.lastMsgId) { pullMsg() } + // 给这个session的对方回已读消息 + if (choosedSession.value.readMsgId < choosedSession.value.lastMsgId) { + const content = choosedSession.value.lastMsgId.toString() + wsConnect.sendMsg(showId.value, MsgType.CHAT_READ, content + '', () => {}) + // 更新本地缓存的已读位置 + messageData.updateSession({ + sessionId: sessionId.value, + readMsgId: content, + readTime: new Date(), + unreadCount: 0 + }) + } } const handleSwitchTag = (obj) => {