feat(聊天): 实现聊天记录分页加载功能
This commit is contained in:
parent
4737ca0feb
commit
b7134046e8
|
|
@ -13,11 +13,19 @@
|
|||
class="chat-scroll"
|
||||
scroll-y
|
||||
:scroll-into-view="scrollToView"
|
||||
:scroll-top="scrollTop"
|
||||
scroll-with-animation
|
||||
:upper-threshold="20"
|
||||
@scroll="handleScroll"
|
||||
@scrolltoupper="handleScrollToUpper"
|
||||
>
|
||||
<view class="chat-content">
|
||||
<!-- 教师信息 -->
|
||||
<div class="teacher-info-card">
|
||||
<image class="teacher-avatar" :src="receiverHeadSculptureUrl"></image>
|
||||
<image
|
||||
class="teacher-avatar"
|
||||
:src="receiverHeadSculptureUrl"
|
||||
></image>
|
||||
<div class="teacher-info">
|
||||
<div class="teacher-name">{{ vuex_msgUser.name }}</div>
|
||||
|
||||
|
|
@ -84,6 +92,7 @@
|
|||
|
||||
<!-- 底部间距 滚动锚点 -->
|
||||
<view id="bottom-anchor" class="bottom-anchor"></view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
|
|
@ -155,9 +164,15 @@ export default {
|
|||
|
||||
// 滚动位置
|
||||
scrollToView: "",
|
||||
scrollTop: 0,
|
||||
currentScrollTop: 0,
|
||||
currentScrollHeight: 0,
|
||||
|
||||
PageIndex: 1,
|
||||
PageSize: 20,
|
||||
|
||||
isLoadingHistory: false,
|
||||
noMoreHistory: false,
|
||||
};
|
||||
},
|
||||
|
||||
|
|
@ -200,6 +215,7 @@ export default {
|
|||
// 监听最后一条消息的ID变化,滚动到底部
|
||||
lastMsgId(val) {
|
||||
if (!val) return;
|
||||
if (this.isLoadingHistory) return;
|
||||
this.$nextTick(() => {
|
||||
this.scrollToBottom();
|
||||
});
|
||||
|
|
@ -267,20 +283,61 @@ export default {
|
|||
|
||||
// 加载对话消息
|
||||
getMsgList() {
|
||||
this.$u.api
|
||||
.GetChatHistoryDataApi({
|
||||
"Item1.DialogueManagementId": this.vuex_msgUser.dialogueManagementId,
|
||||
return this.$store.dispatch("fetchChatRecord", {
|
||||
dialogueManagementId: this.vuex_msgUser.dialogueManagementId,
|
||||
PageIndex: this.PageIndex,
|
||||
PageSize: this.PageSize,
|
||||
});
|
||||
},
|
||||
|
||||
handleScroll(e) {
|
||||
const detail = (e && e.detail) || {};
|
||||
this.currentScrollTop = Number(detail.scrollTop) || 0;
|
||||
this.currentScrollHeight = Number(detail.scrollHeight) || 0;
|
||||
},
|
||||
|
||||
// 滚动到顶部,加载下一页历史消息
|
||||
handleScrollToUpper() {
|
||||
if (this.isLoadingHistory || this.noMoreHistory) return;
|
||||
|
||||
this.isLoadingHistory = true;
|
||||
const beforeTop = this.currentScrollTop || 0;
|
||||
const beforeHeight = this.currentScrollHeight || 0;
|
||||
this.PageIndex += 1;
|
||||
this.scrollToView = "";
|
||||
|
||||
this.$store
|
||||
.dispatch("fetchChatRecordNextPage", {
|
||||
dialogueManagementId: this.vuex_msgUser.dialogueManagementId,
|
||||
PageIndex: this.PageIndex,
|
||||
PageSize: this.PageSize,
|
||||
})
|
||||
.then((res) => {
|
||||
const msgList = res.data.item1.reverse();
|
||||
|
||||
this.$store.commit("push_MsgList", msgList);
|
||||
// // 滚动到底部
|
||||
// this.$nextTick(() => {
|
||||
// this.scrollToBottom();
|
||||
// });
|
||||
.then((list) => {
|
||||
if (!list || !list.length) {
|
||||
this.noMoreHistory = true;
|
||||
return;
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
const query = uni.createSelectorQuery().in(this);
|
||||
query
|
||||
.select(".chat-content")
|
||||
.boundingClientRect((rect) => {
|
||||
const afterHeight = Number(rect && rect.height) || 0;
|
||||
const delta = afterHeight - beforeHeight;
|
||||
if (delta > 0) {
|
||||
this.scrollTop = beforeTop + delta;
|
||||
}
|
||||
})
|
||||
.exec();
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
this.PageIndex = Math.max(1, this.PageIndex - 1);
|
||||
})
|
||||
.finally(() => {
|
||||
setTimeout(() => {
|
||||
this.isLoadingHistory = false;
|
||||
}, 50);
|
||||
});
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -146,6 +146,21 @@ const store = new Vuex.Store({
|
|||
push_MsgList(state, list) {
|
||||
state.vuex_msgList = list || [];
|
||||
},
|
||||
// 追加历史消息到头部(分页加载)
|
||||
prepend_MsgList(state, list) {
|
||||
const prev = state.vuex_msgList || [];
|
||||
const next = Array.isArray(list) ? list : [];
|
||||
const merged = [...next, ...prev];
|
||||
|
||||
const seen = new Set();
|
||||
state.vuex_msgList = merged.filter((item) => {
|
||||
const id = item && item.id;
|
||||
if (!id) return true;
|
||||
if (seen.has(id)) return false;
|
||||
seen.add(id);
|
||||
return true;
|
||||
});
|
||||
},
|
||||
// 推送一条新消息(去重)
|
||||
push_Msg(state, msg) {
|
||||
// 注:现在的消息没有id,无法去重,暂时用push_MsgList
|
||||
|
|
@ -232,17 +247,48 @@ const store = new Vuex.Store({
|
|||
// 刷新列表,清零未读
|
||||
dispatch("getUserlist");
|
||||
},
|
||||
// 获取聊天记录(私聊)
|
||||
// 获取聊天记录(私聊)——仅在进入聊天页时加载一次
|
||||
async fetchChatRecord(
|
||||
{ commit, state },
|
||||
{ userId, friendId, PageIndex = 1, PageSize = 20 }
|
||||
{ commit },
|
||||
{ dialogueManagementId, PageIndex = 1, PageSize = 20 }
|
||||
) {
|
||||
const params = { userId, friendId, PageIndex, PageSize };
|
||||
return Vue.prototype.$u.api
|
||||
.GetChatHistoryDataApi({
|
||||
"Item1.DialogueManagementId": dialogueManagementId,
|
||||
PageIndex,
|
||||
PageSize,
|
||||
})
|
||||
.then((res) => {
|
||||
const list =
|
||||
(res && res.data && Array.isArray(res.data.item1)
|
||||
? res.data.item1
|
||||
: []
|
||||
).slice().reverse();
|
||||
commit("push_MsgList", list);
|
||||
return list;
|
||||
});
|
||||
},
|
||||
|
||||
Vue.prototype.$u.api.GetChatHistoryDataApi(params).then((res) => {
|
||||
const list = res && res.data ? res.data : [];
|
||||
// 将最新消息插入到消息列表尾部(或头部)
|
||||
list.forEach((msg) => commit("push_Msg", msg));
|
||||
// 获取下一页历史消息(滚动到顶部触发)
|
||||
async fetchChatRecordNextPage(
|
||||
{ commit },
|
||||
{ dialogueManagementId, PageIndex = 1, PageSize = 20 }
|
||||
) {
|
||||
return Vue.prototype.$u.api
|
||||
.GetChatHistoryDataApi({
|
||||
"Item1.DialogueManagementId": dialogueManagementId,
|
||||
PageIndex,
|
||||
PageSize,
|
||||
})
|
||||
.then((res) => {
|
||||
const list =
|
||||
(res && res.data && Array.isArray(res.data.item1)
|
||||
? res.data.item1
|
||||
: []
|
||||
).slice().reverse();
|
||||
if (!list.length) return [];
|
||||
commit("prepend_MsgList", list);
|
||||
return list;
|
||||
});
|
||||
},
|
||||
// 设置消息置顶(服务端 + 本地)
|
||||
|
|
|
|||
Loading…
Reference in New Issue