修复聊天信息聚合问题

This commit is contained in:
2026-06-06 13:09:19 +08:00
parent 2faac32d87
commit 1b5cf41576
2 changed files with 42 additions and 13 deletions
+20 -8
View File
@@ -26,6 +26,7 @@ const menuX = ref(0)
const menuY = ref(0) const menuY = ref(0)
const topThreshold = 8 const topThreshold = 8
const bottomThreshold = 40 const bottomThreshold = 40
const scrollOverflowAllowance = 1
const groupedMessages = computed<GroupedTextMessage[]>(() => { const groupedMessages = computed<GroupedTextMessage[]>(() => {
const groups = new Map<string, GroupedTextMessage>() const groups = new Map<string, GroupedTextMessage>()
@@ -102,25 +103,29 @@ function handleKeydown(event: KeyboardEvent) {
} }
} }
function handleScroll() { function loadOlderFromCurrentScroll(el: HTMLElement) {
closeMessageMenu()
const el = panelRef.value
if ( if (
!el ||
props.loadingOlder || props.loadingOlder ||
!props.hasMoreMessages || !props.hasMoreMessages ||
props.messages.length === 0 || groupedMessages.value.length === 0 ||
restoreScrollHeight != null restoreScrollHeight != null
) { ) {
return return
} }
if (el.scrollTop <= topThreshold) {
restoreScrollHeight = el.scrollHeight restoreScrollHeight = el.scrollHeight
restoreScrollTop = el.scrollTop restoreScrollTop = el.scrollTop
restoreMessageCount = props.messages.length restoreMessageCount = groupedMessages.value.length
emit('load-older') emit('load-older')
} }
function handleScroll() {
closeMessageMenu()
const el = panelRef.value
if (!el || el.scrollTop > topThreshold) {
return
}
loadOlderFromCurrentScroll(el)
} }
onBeforeUpdate(() => { onBeforeUpdate(() => {
@@ -138,6 +143,9 @@ onMounted(async () => {
if (el) { if (el) {
el.scrollTop = el.scrollHeight el.scrollTop = el.scrollHeight
didInitialScroll = true didInitialScroll = true
if (el.scrollHeight <= el.clientHeight + scrollOverflowAllowance) {
loadOlderFromCurrentScroll(el)
}
} }
}) })
@@ -153,7 +161,7 @@ onUpdated(() => {
} }
if (restoreScrollHeight != null) { if (restoreScrollHeight != null) {
if (props.messages.length > restoreMessageCount) { if (groupedMessages.value.length > restoreMessageCount) {
el.scrollTop = el.scrollHeight - restoreScrollHeight + restoreScrollTop el.scrollTop = el.scrollHeight - restoreScrollHeight + restoreScrollTop
clearRestoreState() clearRestoreState()
return return
@@ -167,6 +175,10 @@ onUpdated(() => {
el.scrollTop = el.scrollHeight el.scrollTop = el.scrollHeight
didInitialScroll = true didInitialScroll = true
} }
if (el.scrollHeight <= el.clientHeight + scrollOverflowAllowance) {
loadOlderFromCurrentScroll(el)
}
}) })
</script> </script>
@@ -24,6 +24,7 @@ const chatHasMore = ref(true)
const error = ref('') const error = ref('')
const chatPageSize = 20 const chatPageSize = 20
const chatHistoryRef = ref<HTMLElement | null>(null) const chatHistoryRef = ref<HTMLElement | null>(null)
const scrollOverflowAllowance = 1
type GroupedTextMessage = TextMessage & { mergedCount: number; mergedMessages: TextMessage[] } type GroupedTextMessage = TextMessage & { mergedCount: number; mergedMessages: TextMessage[] }
type PendingDeleteAction = type PendingDeleteAction =
| { kind: 'delete-message'; message: GroupedTextMessage } | { kind: 'delete-message'; message: GroupedTextMessage }
@@ -186,24 +187,30 @@ async function loadInitialMessages() {
const el = chatHistoryRef.value const el = chatHistoryRef.value
if (el) { if (el) {
el.scrollTop = el.scrollHeight el.scrollTop = el.scrollHeight
await loadMoreUntilScrollable(el)
} }
} }
async function loadOlderMessages() { async function loadOlderMessages() {
const el = chatHistoryRef.value
await loadOlderMessagesFromCurrentScroll(el)
}
async function loadOlderMessagesFromCurrentScroll(el: HTMLElement | null) {
if (chatLoadingOlder.value || !chatHasMore.value) { if (chatLoadingOlder.value || !chatHasMore.value) {
return return
} }
const el = chatHistoryRef.value
const previousScrollHeight = el?.scrollHeight ?? 0 const previousScrollHeight = el?.scrollHeight ?? 0
const previousScrollTop = el?.scrollTop ?? 0 const previousScrollTop = el?.scrollTop ?? 0
const previousGroupedMessageCount = groupedMessages.value.length
chatLoadingOlder.value = true chatLoadingOlder.value = true
try { try {
const response = await getTextMessages(chatPageSize, messages.value.length, props.nodeId) const response = await getTextMessages(chatPageSize, messages.value.length, props.nodeId)
messages.value = mergeMessages(messages.value, toChronological(response.items)) messages.value = mergeMessages(messages.value, toChronological(response.items))
chatHasMore.value = response.items.length === chatPageSize chatHasMore.value = response.items.length === chatPageSize
await nextTick() await nextTick()
if (el) { if (el && groupedMessages.value.length > previousGroupedMessageCount) {
el.scrollTop = el.scrollHeight - previousScrollHeight + previousScrollTop el.scrollTop = el.scrollHeight - previousScrollHeight + previousScrollTop
} }
} catch (err) { } catch (err) {
@@ -213,6 +220,16 @@ async function loadOlderMessages() {
} }
} }
async function loadMoreUntilScrollable(el: HTMLElement) {
while (chatHasMore.value && el.scrollHeight <= el.clientHeight + scrollOverflowAllowance) {
const previousGroupedMessageCount = groupedMessages.value.length
await loadOlderMessagesFromCurrentScroll(el)
if (groupedMessages.value.length <= previousGroupedMessageCount) {
break
}
}
}
function closeMessageMenu() { function closeMessageMenu() {
menuMessage.value = null menuMessage.value = null
} }