feat: 会话列表实时同步未读与最新消息
This commit is contained in:
parent
5b0a14ae57
commit
890a3cee94
11
App.vue
11
App.vue
|
|
@ -236,6 +236,17 @@ export default {
|
|||
filePath: "",
|
||||
id: Math.random().toString(36).substring(2),
|
||||
});
|
||||
|
||||
// 更新会话列表的未读数 / 文案 / 时间,保持实时展示
|
||||
if (processData.dialogueManagementId) {
|
||||
this.$store.commit("apply_RealtimeMessageToList", {
|
||||
dialogueId: processData.dialogueManagementId,
|
||||
message: processData.message,
|
||||
sendDate: processData.sendDate,
|
||||
senderId: processData.senderId,
|
||||
receiverId: processData.receiverId,
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
// 连接关闭
|
||||
|
|
|
|||
|
|
@ -63,12 +63,120 @@ export default {
|
|||
},
|
||||
computed: {
|
||||
// 补充展示字段,便于模板直接使用
|
||||
unreadMap() {
|
||||
const map = {};
|
||||
const list = this.$store?.state?.vuex_userMsgList || [];
|
||||
list.forEach((item) => {
|
||||
const id = this.getDialogueId(item);
|
||||
const count =
|
||||
item?.unReadCount ??
|
||||
item?.unreadCount ??
|
||||
item?.unread ??
|
||||
null;
|
||||
if (id && typeof count === "number") {
|
||||
map[id] = count;
|
||||
}
|
||||
});
|
||||
return map;
|
||||
},
|
||||
displayChatList() {
|
||||
return (this.chatList || []).map((item) => ({
|
||||
...item,
|
||||
displayTime: item.lastMessageTime || "",
|
||||
displayPreview: item.lastMessage || "暂无消息",
|
||||
}));
|
||||
// 合并接口首帧列表 + 实时更新列表,按 id 匹配覆盖
|
||||
const realtime = this.$store?.state?.vuex_userMsgList || [];
|
||||
const baseList = this.chatList || [];
|
||||
|
||||
const rtMap = {};
|
||||
realtime.forEach((item) => {
|
||||
const id = this.getDialogueId(item);
|
||||
if (id) rtMap[id] = item;
|
||||
});
|
||||
|
||||
const merged = baseList.map((item) => {
|
||||
const id = this.getDialogueId(item);
|
||||
const rt = id ? rtMap[id] : null;
|
||||
const source = rt || item;
|
||||
const unread =
|
||||
typeof this.unreadMap[id] === "number"
|
||||
? this.unreadMap[id]
|
||||
: source?.unReadCount ??
|
||||
source?.unreadCount ??
|
||||
source?.unread ??
|
||||
0;
|
||||
|
||||
return {
|
||||
...item,
|
||||
...rt,
|
||||
id,
|
||||
dialogueManagementId: id,
|
||||
DialogueManagementId: id,
|
||||
userId:
|
||||
source?.receiverId ||
|
||||
source?.friendId ||
|
||||
source?.userId ||
|
||||
item?.userId ||
|
||||
"",
|
||||
avatar:
|
||||
source?.receiverHeadSculptureUrl ||
|
||||
source?.avatar ||
|
||||
source?.friendAvatar ||
|
||||
"/static/avatar/default-avatar.png",
|
||||
displayTime: this.formatTime(
|
||||
source?.lastMessageTime ||
|
||||
source?.lastSendTime ||
|
||||
source?.sendDate ||
|
||||
item?.lastMessageTime ||
|
||||
""
|
||||
),
|
||||
displayPreview:
|
||||
source?.lastMessage ||
|
||||
source?.message ||
|
||||
item?.lastMessage ||
|
||||
"暂无消息",
|
||||
unreadCount: unread,
|
||||
};
|
||||
});
|
||||
|
||||
// 追加实时列表中基线不存在的会话
|
||||
realtime.forEach((item) => {
|
||||
const id = this.getDialogueId(item);
|
||||
if (!id) return;
|
||||
const exists = merged.some((row) => row.id === id);
|
||||
if (!exists) {
|
||||
const unread =
|
||||
typeof this.unreadMap[id] === "number"
|
||||
? this.unreadMap[id]
|
||||
: item?.unReadCount ??
|
||||
item?.unreadCount ??
|
||||
item?.unread ??
|
||||
0;
|
||||
merged.unshift({
|
||||
...item,
|
||||
id,
|
||||
dialogueManagementId: id,
|
||||
DialogueManagementId: id,
|
||||
userId:
|
||||
item?.receiverId ||
|
||||
item?.friendId ||
|
||||
item?.userId ||
|
||||
"",
|
||||
avatar:
|
||||
item?.receiverHeadSculptureUrl ||
|
||||
item?.avatar ||
|
||||
item?.friendAvatar ||
|
||||
"/static/avatar/default-avatar.png",
|
||||
displayTime: this.formatTime(
|
||||
item?.lastMessageTime ||
|
||||
item?.lastSendTime ||
|
||||
item?.sendDate ||
|
||||
""
|
||||
),
|
||||
displayPreview:
|
||||
item?.lastMessage || item?.message || "暂无消息",
|
||||
unreadCount: unread,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return merged;
|
||||
},
|
||||
},
|
||||
data() {
|
||||
|
|
@ -130,6 +238,8 @@ export default {
|
|||
const list = (res && res.data && res.data.item1) || [];
|
||||
|
||||
this.chatList = this.normalizeDialogueList(list);
|
||||
// 同步到全局会话列表,便于后续实时合并
|
||||
this.$store.commit("set_UserMsgList", this.chatList);
|
||||
this.totalCount = res?.data?.item2 || list.length;
|
||||
} catch (error) {
|
||||
console.error("[在线咨询] 获取会话列表失败", error);
|
||||
|
|
@ -155,9 +265,20 @@ export default {
|
|||
? item.unReadCount
|
||||
: item?.unreadCount || 0;
|
||||
|
||||
const id =
|
||||
item?.dialogueManagementId ||
|
||||
item?.DialogueManagementId ||
|
||||
item?.dialogueId ||
|
||||
item?.friendId ||
|
||||
item?.id ||
|
||||
index;
|
||||
|
||||
return {
|
||||
id: item?.dialogueManagementId || item?.dialogueId || item?.id || index,
|
||||
id,
|
||||
dialogueManagementId: id,
|
||||
DialogueManagementId: id,
|
||||
userId: item?.receiverId || item?.friendId || item?.userId || "",
|
||||
friendId: item?.receiverId || item?.friendId || item?.userId || "",
|
||||
name:
|
||||
item?.receiverName ||
|
||||
item?.friendName ||
|
||||
|
|
@ -202,6 +323,18 @@ export default {
|
|||
// 回退到字符串裁剪
|
||||
return String(timeStr).replace("T", " ").slice(5, 16);
|
||||
},
|
||||
|
||||
// 统一获取会话唯一标识
|
||||
getDialogueId(item) {
|
||||
return (
|
||||
item?.dialogueManagementId ||
|
||||
item?.DialogueManagementId ||
|
||||
item?.dialogueId ||
|
||||
item?.friendId ||
|
||||
item?.id ||
|
||||
""
|
||||
);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -186,6 +186,63 @@ const store = new Vuex.Store({
|
|||
return item;
|
||||
});
|
||||
},
|
||||
// WebSocket 实时消息:更新会话列表的未读数、文案与时间
|
||||
apply_RealtimeMessageToList(
|
||||
state,
|
||||
{ dialogueId, message, sendDate, senderId, receiverId }
|
||||
) {
|
||||
if (!dialogueId) return;
|
||||
const activeId =
|
||||
state.vuex_msgUser?.dialogueManagementId ||
|
||||
state.vuex_msgUser?.friendId ||
|
||||
state.vuex_msgUser?.id;
|
||||
const isActive = activeId && activeId === dialogueId;
|
||||
|
||||
let found = false;
|
||||
state.vuex_userMsgList = (state.vuex_userMsgList || []).map((item) => {
|
||||
const itemId =
|
||||
item?.dialogueManagementId ||
|
||||
item?.DialogueManagementId ||
|
||||
item?.friendId ||
|
||||
item?.id;
|
||||
if (itemId === dialogueId) {
|
||||
found = true;
|
||||
const currentUnread =
|
||||
Number(
|
||||
item?.unReadCount ??
|
||||
item?.unreadCount ??
|
||||
item?.unread ??
|
||||
0
|
||||
) || 0;
|
||||
const nextUnread = isActive ? 0 : currentUnread + 1;
|
||||
return {
|
||||
...item,
|
||||
lastMessage: message ?? item?.lastMessage ?? "",
|
||||
lastMessageTime: sendDate ?? item?.lastMessageTime ?? "",
|
||||
unReadCount: nextUnread,
|
||||
unreadCount: nextUnread,
|
||||
};
|
||||
}
|
||||
return item;
|
||||
});
|
||||
|
||||
// 未在列表中则插入一条最小信息的会话(保持实时感知)
|
||||
if (!found) {
|
||||
const nextUnread = isActive ? 0 : 1;
|
||||
state.vuex_userMsgList.unshift({
|
||||
id: dialogueId,
|
||||
dialogueManagementId: dialogueId,
|
||||
DialogueManagementId: dialogueId,
|
||||
friendId: receiverId || senderId || dialogueId,
|
||||
name: "",
|
||||
avatar: "",
|
||||
lastMessage: message || "",
|
||||
lastMessageTime: sendDate || "",
|
||||
unReadCount: nextUnread,
|
||||
unreadCount: nextUnread,
|
||||
});
|
||||
}
|
||||
},
|
||||
// 更新消息窗口滚动位置
|
||||
set_MsgScrollTop(state, top) {
|
||||
state.vuex_msgScrollTop = Number(top) || 0;
|
||||
|
|
|
|||
Loading…
Reference in New Issue