|
|
@@ -154,13 +154,9 @@
|
|
|
|
|
|
<!-- 消息状态(自己的消息) -->
|
|
|
<view v-if="msg.fromUserId === userId" class="message-status">
|
|
|
- <text v-if="msg.sendStatus === 1" class="sending">发送中...</text>
|
|
|
- <text v-else-if="msg.sendStatus === 2">已送达</text>
|
|
|
- <text v-else-if="msg.sendStatus === 3" class="read">已读</text>
|
|
|
- <view v-else-if="msg.sendStatus === 4" class="failed-group">
|
|
|
- <text class="failed">发送失败</text>
|
|
|
- <text class="retry-btn" @click.stop="retryMessage(msg)">重试</text>
|
|
|
- </view>
|
|
|
+ <text v-if="msg.sendStatus === 4" class="status-failed">发送失败</text>
|
|
|
+ <text v-else-if="msg.isPeerRead" class="status-read">已读</text>
|
|
|
+ <text v-else class="status-unread">未读</text>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
@@ -426,6 +422,15 @@ export default {
|
|
|
// 初始化在线状态监听(HTTP 轮询方式)
|
|
|
this.initOnlineStatusPolling();
|
|
|
|
|
|
+ // 等待一下确保 TIM 完全初始化后再监听已读回执
|
|
|
+ setTimeout(() => {
|
|
|
+ // 监听已读回执
|
|
|
+ this.listenMessageReadReceipt();
|
|
|
+
|
|
|
+ // 标记当前会话的消息为已读
|
|
|
+ this.markConversationRead();
|
|
|
+ }, 500);
|
|
|
+
|
|
|
// 如果有预设消息,自动发送
|
|
|
if (options.message) {
|
|
|
const message = decodeURIComponent(options.message);
|
|
|
@@ -734,7 +739,8 @@ export default {
|
|
|
});
|
|
|
}
|
|
|
|
|
|
- // 标记已读
|
|
|
+ // 标记已读(通知对方:我已阅读他发送的消息)
|
|
|
+ console.log('📖 收到新消息,标记会话已读:', this.conversationID);
|
|
|
timManager.setMessageRead(this.conversationID);
|
|
|
}
|
|
|
});
|
|
|
@@ -828,6 +834,18 @@ export default {
|
|
|
content = '[视频]';
|
|
|
}
|
|
|
|
|
|
+ // 对于自己发送的消息,isPeerRead 需要特殊处理
|
|
|
+ // 不能直接使用 timMsg.isPeerRead,因为 setMessageRead() 会影响这个值
|
|
|
+ // 只有真正收到 MESSAGE_READ_BY_PEER 事件时才应该标记为已读
|
|
|
+ let isPeerRead = false;
|
|
|
+ if (timMsg.from === this.userId) {
|
|
|
+ // 自己发送的消息,默认未读,只有收到已读回执事件时才更新
|
|
|
+ isPeerRead = false;
|
|
|
+ } else {
|
|
|
+ // 对方发送的消息,不需要 isPeerRead 字段
|
|
|
+ isPeerRead = false;
|
|
|
+ }
|
|
|
+
|
|
|
return {
|
|
|
messageId: timMsg.ID,
|
|
|
fromUserId: timMsg.from,
|
|
|
@@ -840,7 +858,8 @@ export default {
|
|
|
sendStatus: sendStatus,
|
|
|
sendTime: new Date(timMsg.time * 1000),
|
|
|
isRecalled: timMsg.isRevoked,
|
|
|
- fromUserName: timMsg.from === this.userId ? '我' : this.targetUserName
|
|
|
+ fromUserName: timMsg.from === this.userId ? '我' : this.targetUserName,
|
|
|
+ isPeerRead: isPeerRead // 对方是否已读(只对自己发送的消息有意义)
|
|
|
};
|
|
|
},
|
|
|
/**
|
|
|
@@ -884,6 +903,78 @@ export default {
|
|
|
return false;
|
|
|
}
|
|
|
},
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 监听已读回执
|
|
|
+ */
|
|
|
+ listenMessageReadReceipt() {
|
|
|
+ if (!timManager.tim || !timManager.tim.TIM) {
|
|
|
+ console.warn('⚠️ TIM 未初始化或 TIM 对象不完整,无法监听已读回执');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const TIM = timManager.tim.TIM;
|
|
|
+
|
|
|
+ // 监听消息已读回执事件
|
|
|
+ const handleMessageReadByPeer = (event) => {
|
|
|
+ console.log('📖 收到已读回执事件:', event);
|
|
|
+ console.log(' - 事件数据:', JSON.stringify(event.data));
|
|
|
+
|
|
|
+ // event.data 包含已读的消息列表
|
|
|
+ if (event.data && Array.isArray(event.data)) {
|
|
|
+ event.data.forEach(item => {
|
|
|
+ console.log(' - 处理会话:', item.conversationID, '当前会话:', this.conversationID);
|
|
|
+
|
|
|
+ // 只处理当前会话的消息
|
|
|
+ if (item.conversationID === this.conversationID) {
|
|
|
+ console.log('✅ 对方已阅读当前会话的消息');
|
|
|
+
|
|
|
+ let updatedCount = 0;
|
|
|
+
|
|
|
+ // 更新本地消息列表中所有未读消息的状态
|
|
|
+ this.messages.forEach((msg, index) => {
|
|
|
+ // 只更新自己发送的且未被标记为已读的消息
|
|
|
+ if (msg.fromUserId === this.userId && !msg.isPeerRead && msg.sendStatus !== 4) {
|
|
|
+ this.$set(this.messages[index], 'isPeerRead', true);
|
|
|
+ updatedCount++;
|
|
|
+ console.log(` - 消息 ${msg.messageId} 已标记为已读`);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ console.log(`✅ 共更新 ${updatedCount} 条消息为已读状态`);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ this.handleMessageReadByPeer = handleMessageReadByPeer;
|
|
|
+ timManager.tim.on(TIM.EVENT.MESSAGE_READ_BY_PEER, handleMessageReadByPeer);
|
|
|
+ console.log('✅ 已监听消息已读回执');
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 标记当前会话的消息为已读
|
|
|
+ * 注意:这会通知对方"我已阅读他发送的消息",触发对方的 MESSAGE_READ_BY_PEER 事件
|
|
|
+ */
|
|
|
+ async markConversationRead() {
|
|
|
+ try {
|
|
|
+ if (!timManager.tim || !this.conversationID) {
|
|
|
+ console.warn('⚠️ TIM 未初始化或会话ID为空');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log('📖 标记会话已读:', this.conversationID);
|
|
|
+
|
|
|
+ // 调用 TIM SDK 标记会话已读
|
|
|
+ // 这会通知对方:他发送给我的消息已被阅读
|
|
|
+ await timManager.tim.setMessageRead({ conversationID: this.conversationID });
|
|
|
+
|
|
|
+ console.log('✅ 会话已标记为已读,已通知对方');
|
|
|
+ } catch (error) {
|
|
|
+ console.error('❌ 标记会话已读失败:', error);
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
/**
|
|
|
* 发送文本消息
|
|
|
*/
|
|
|
@@ -2158,6 +2249,13 @@ export default {
|
|
|
timPresenceManager.offStatusChange(this.targetUserId, this.onlineStatusCallback);
|
|
|
console.log('✅ 已清理 WebSocket 监听');
|
|
|
}
|
|
|
+
|
|
|
+ // 清理已读回执监听
|
|
|
+ if (this.handleMessageReadByPeer && timManager.tim) {
|
|
|
+ const TIM = timManager.tim.TIM;
|
|
|
+ timManager.tim.off(TIM.EVENT.MESSAGE_READ_BY_PEER, this.handleMessageReadByPeer);
|
|
|
+ console.log('✅ 已清理已读回执监听');
|
|
|
+ }
|
|
|
}
|
|
|
};
|
|
|
</script>
|
|
|
@@ -2491,17 +2589,20 @@ export default {
|
|
|
|
|
|
.message-status {
|
|
|
text-align: right;
|
|
|
- font-size: 24rpx;
|
|
|
+ font-size: 22rpx;
|
|
|
+ color: #999;
|
|
|
+ margin-top: 8rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.message-status .status-unread {
|
|
|
color: #999;
|
|
|
- margin-top: 5rpx;
|
|
|
-
|
|
|
}
|
|
|
|
|
|
-.message-status .read {
|
|
|
+.message-status .status-read {
|
|
|
color: #07c160;
|
|
|
}
|
|
|
|
|
|
-.message-status .failed {
|
|
|
+.message-status .status-failed {
|
|
|
color: #fa5151;
|
|
|
}
|
|
|
|