This commit is contained in:
JiXinHui 2025-12-17 15:32:39 +08:00
commit e20570faa0
2 changed files with 180 additions and 77 deletions

View File

@ -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);
});
},

View File

@ -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;
});
},
// 设置消息置顶(服务端 + 本地)