增强消息视图的SSE连接管理

This commit is contained in:
jxxghp
2025-08-21 09:22:57 +08:00
parent eafe63c886
commit c330aee560
3 changed files with 57 additions and 10 deletions
+17
View File
@@ -50,6 +50,9 @@ const sendButtonDisabled = ref(false)
// 消息对话框引用 // 消息对话框引用
const messageDialogRef = ref<any>(null) const messageDialogRef = ref<any>(null)
// 消息视图引用
const messageViewRef = ref<any>(null)
// 滚动容器引用 // 滚动容器引用
const messageContentRef = ref<any>() const messageContentRef = ref<any>()
@@ -115,6 +118,12 @@ async function openMessageDialog() {
setTimeout(() => { setTimeout(() => {
forceScrollToEnd() forceScrollToEnd()
}, 600) }, 600)
// 等待对话框打开后恢复SSE连接
nextTick(() => {
if (messageViewRef.value && typeof messageViewRef.value.resumeSSE === 'function') {
messageViewRef.value.resumeSSE()
}
})
} }
// 智能滚动到底部(只有用户在底部附近时才滚动) // 智能滚动到底部(只有用户在底部附近时才滚动)
@@ -184,6 +193,14 @@ defineExpose({
openMessageDialog: openMessageDialogFromExternal, openMessageDialog: openMessageDialogFromExternal,
}) })
// 监听消息对话框状态变化
watch(messageDialog, newValue => {
if (!newValue && messageViewRef.value && typeof messageViewRef.value.pauseSSE === 'function') {
// 对话框关闭时暂停SSE连接
messageViewRef.value.pauseSSE()
}
})
onMounted(() => { onMounted(() => {
const shortcut = getQueryValue('shortcut') const shortcut = getQueryValue('shortcut')
if (shortcut) { if (shortcut) {
+10 -5
View File
@@ -69,8 +69,8 @@ export class SSEManager {
this.backgroundCloseTimer = null this.backgroundCloseTimer = null
} }
// 立即重新建立连接 // 只有在有活跃监听器时才重新建立连接
if (!this.eventSource || this.eventSource.readyState === EventSource.CLOSED) { if (this.listeners.size > 0 && (!this.eventSource || this.eventSource.readyState === EventSource.CLOSED)) {
this.reconnectSSE() this.reconnectSSE()
} }
} }
@@ -84,6 +84,11 @@ export class SSEManager {
return return
} }
// 如果没有活跃的监听器,不进行重连
if (this.listeners.size === 0) {
return
}
this.isConnecting = true this.isConnecting = true
this.reconnectAttempts = attemptCount this.reconnectAttempts = attemptCount
@@ -105,7 +110,7 @@ export class SSEManager {
} }
this.reconnectTimer = window.setTimeout(() => { this.reconnectTimer = window.setTimeout(() => {
if (!this.isBackground) { if (!this.isBackground && this.listeners.size > 0) {
this.reconnectSSE(this.reconnectAttempts + 1) this.reconnectSSE(this.reconnectAttempts + 1)
} }
}, this.options.reconnectDelay) }, this.options.reconnectDelay)
@@ -131,7 +136,7 @@ export class SSEManager {
} }
this.reconnectTimer = window.setTimeout(() => { this.reconnectTimer = window.setTimeout(() => {
if (!this.isBackground) { if (!this.isBackground && this.listeners.size > 0) {
this.reconnectSSE(this.reconnectAttempts + 1) this.reconnectSSE(this.reconnectAttempts + 1)
} }
}, this.options.reconnectDelay) }, this.options.reconnectDelay)
@@ -205,7 +210,7 @@ export class SSEManager {
*/ */
forceReconnect() { forceReconnect() {
this.close() this.close()
if (!this.isBackground) { if (!this.isBackground && this.listeners.size > 0) {
this.reconnectSSE() this.reconnectSSE()
} }
} }
+30 -5
View File
@@ -45,11 +45,16 @@ function handleSSEMessage(event: MessageEvent) {
} }
// 使用优化的SSE连接 // 使用优化的SSE连接
useSSE(`${import.meta.env.VITE_API_BASE_URL}system/message?role=user`, handleSSEMessage, 'message-view', { const { manager, isConnected } = useSSE(
backgroundCloseDelay: 5000, `${import.meta.env.VITE_API_BASE_URL}system/message?role=user`,
reconnectDelay: 3000, handleSSEMessage,
maxReconnectAttempts: 3, 'message-view',
}) {
backgroundCloseDelay: 5000,
reconnectDelay: 3000,
maxReconnectAttempts: 3,
},
)
// 调用API加载存量消息 // 调用API加载存量消息
async function loadMessages({ done }: { done: any }) { async function loadMessages({ done }: { done: any }) {
@@ -145,6 +150,26 @@ function handleImageLoad() {
emit('scroll') emit('scroll')
} }
// 暂停SSE连接
function pauseSSE() {
if (manager) {
manager.removeMessageListener('message-view')
}
}
// 恢复SSE连接
function resumeSSE() {
if (manager) {
manager.addMessageListener('message-view', handleSSEMessage)
}
}
// 暴露方法给父组件
defineExpose({
pauseSSE,
resumeSSE,
})
onMounted(() => { onMounted(() => {
// 组件挂载后触发一次滚动事件 // 组件挂载后触发一次滚动事件
nextTick(() => { nextTick(() => {