Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
水玉婷
ai-wechat
Commits
0367c92e
Commit
0367c92e
authored
Feb 09, 2026
by
水玉婷
Browse files
feat:单次连接
parent
4a8d1aff
Changes
2
Hide whitespace changes
Inline
Side-by-side
src/views/components/AiChat.vue
View file @
0367c92e
...
@@ -111,7 +111,7 @@
...
@@ -111,7 +111,7 @@
:appCode=
"props?.appCode"
:appCode=
"props?.appCode"
:apiBaseUrl=
"props?.apiBaseUrl"
:apiBaseUrl=
"props?.apiBaseUrl"
@
audio=
"handleVoiceAudio"
@
audio=
"handleVoiceAudio"
@
error=
"handleVoiceError"
class=
"voice-recognition-wrapper"
/>
@
error=
"handleVoiceError"
class=
"voice-recognition-wrapper"
/>
<textarea
ref=
"textarea"
v-model=
"messageText"
placeholder=
"输入消息..."
@
keypress=
"handleKeyPress"
<textarea
ref=
"textarea"
v-model=
"messageText"
placeholder=
"输入消息..."
@
keypress=
"handleKeyPress"
@
input=
"adjustTextareaHeight"
></textarea>
@
input=
"adjustTextareaHeight"
></textarea>
...
@@ -262,6 +262,12 @@ const handleSSEMessage = (data: SSEData, isSimulated: boolean = false) => {
...
@@ -262,6 +262,12 @@ const handleSSEMessage = (data: SSEData, isSimulated: boolean = false) => {
}
}
}
}
// 处理状态29:当前会话结束,关闭SSE连接
if
(
data
.
status
===
29
)
{
console
.
log
(
'
收到状态29,当前会话结束,关闭SSE连接
'
);
closeSSE
();
}
if
(
result
.
recordId
&&
currentAIResponse
.
value
)
{
if
(
result
.
recordId
&&
currentAIResponse
.
value
)
{
currentAIResponse
.
value
.
recordId
=
result
.
recordId
;
currentAIResponse
.
value
.
recordId
=
result
.
recordId
;
currentAIResponse
.
value
.
promptTokens
=
result
.
promptTokens
;
currentAIResponse
.
value
.
promptTokens
=
result
.
promptTokens
;
...
@@ -320,11 +326,15 @@ const handleVoiceError = (error: string) => {
...
@@ -320,11 +326,15 @@ const handleVoiceError = (error: string) => {
};
};
// 开始对话函数 - 修改为在发送消息时调用
// 开始对话函数 - 修改为在发送消息时调用
const
startConversation
=
()
=>
{
const
startConversation
=
async
():
Promise
<
void
>
=>
{
if
(
!
hasStartedConversation
.
value
)
{
if
(
!
hasStartedConversation
.
value
)
{
console
.
log
(
'
开始对话,初始化SSE连接
'
);
console
.
log
(
'
开始对话,初始化SSE连接
'
);
// 每次发送消息时重新初始化SSE连接,并等待连接建立完成
hasStartedConversation
.
value
=
true
;
hasStartedConversation
.
value
=
true
;
console
.
log
(
'
✅ SSE连接建立完成,可以发送消息
'
);
}
}
await
initSSE
();
};
};
// 定义消息类型
// 定义消息类型
...
@@ -383,7 +393,7 @@ const sendMessage = async (type: MessageType = 'text', params: MessageParams = {
...
@@ -383,7 +393,7 @@ const sendMessage = async (type: MessageType = 'text', params: MessageParams = {
}
}
// 开始对话
// 开始对话
startConversation
();
await
startConversation
();
isAIResponding
.
value
=
false
;
isAIResponding
.
value
=
false
;
isInThinkingMode
.
value
=
false
;
isInThinkingMode
.
value
=
false
;
...
@@ -686,8 +696,6 @@ defineExpose({
...
@@ -686,8 +696,6 @@ defineExpose({
// 生命周期
// 生命周期
onMounted
(()
=>
{
onMounted
(()
=>
{
console
.
log
(
'
组件挂载,初始 dialogSessionId:
'
,
props
.
dialogSessionId
);
console
.
log
(
'
组件挂载,初始 dialogSessionId:
'
,
props
.
dialogSessionId
);
initSSE
();
scrollToBottom
();
if
(
props
.
dialogSessionId
)
{
if
(
props
.
dialogSessionId
)
{
getChatRecord
(
props
.
dialogSessionId
);
getChatRecord
(
props
.
dialogSessionId
);
}
}
...
...
src/views/components/utils/sseService.ts
View file @
0367c92e
import
{
EventSourcePolyfill
}
from
'
event-source-polyfill
'
;
import
{
EventSourcePolyfill
}
from
'
event-source-polyfill
'
;
import
{
ref
,
Ref
}
from
'
vue
'
;
// SSE数据类型定义
// SSE数据类型定义
export
interface
SSEData
{
export
interface
SSEData
{
...
@@ -27,25 +26,15 @@ export interface SSEHandlers {
...
@@ -27,25 +26,15 @@ export interface SSEHandlers {
onReconnect
?:
(
newDialogSessionId
:
string
)
=>
void
;
onReconnect
?:
(
newDialogSessionId
:
string
)
=>
void
;
}
}
// SSE服务类 -
专注于SSE连接管理
// SSE服务类 -
简化的连接管理(每次发消息时建立连接)
export
class
SSEService
{
export
class
SSEService
{
private
eventSource
:
EventSourcePolyfill
|
null
=
null
;
private
eventSource
:
EventSourcePolyfill
|
null
=
null
;
private
config
:
SSEServiceConfig
;
private
config
:
SSEServiceConfig
;
private
handlers
:
SSEHandlers
;
private
handlers
:
SSEHandlers
;
private
isReconnecting
:
Ref
<
boolean
>
=
ref
(
false
);
private
timeArr
:
NodeJS
.
Timeout
[]
=
[];
// keepalive相关状态
private
hasReceivedKeepalive
:
boolean
=
false
;
// 标记是否收到过keepalive事件
// 页面刷新监听器相关
private
beforeUnloadHandler
:
(()
=>
void
)
|
null
=
null
;
private
isPageRefreshing
:
boolean
=
false
;
constructor
(
config
:
SSEServiceConfig
,
handlers
:
SSEHandlers
=
{})
{
constructor
(
config
:
SSEServiceConfig
,
handlers
:
SSEHandlers
=
{})
{
this
.
config
=
config
;
this
.
config
=
config
;
this
.
handlers
=
handlers
;
this
.
handlers
=
handlers
;
this
.
setupPageRefreshListener
();
}
}
// 初始化SSE连接
// 初始化SSE连接
...
@@ -59,12 +48,9 @@ export class SSEService {
...
@@ -59,12 +48,9 @@ export class SSEService {
'
x-app-code
'
:
this
.
config
.
appCode
||
''
,
'
x-app-code
'
:
this
.
config
.
appCode
||
''
,
},
},
withCredentials
:
true
,
withCredentials
:
true
,
connectionTimeout
:
60000
,
heartbeatTimeout
:
60000
,
});
});
this
.
eventSource
.
onopen
=
(
event
)
=>
{
this
.
eventSource
.
onopen
=
(
event
)
=>
{
// 移除这里的日志,只在外部处理器中打印
if
(
this
.
handlers
.
onOpen
)
{
if
(
this
.
handlers
.
onOpen
)
{
this
.
handlers
.
onOpen
(
event
);
this
.
handlers
.
onOpen
(
event
);
}
}
...
@@ -83,57 +69,15 @@ export class SSEService {
...
@@ -83,57 +69,15 @@ export class SSEService {
}
}
});
});
// 监听keepalive事件
this
.
eventSource
.
addEventListener
(
'
keepalive
'
,
(
event
)
=>
{
this
.
hasReceivedKeepalive
=
true
;
// 标记已收到keepalive
console
.
log
(
'
💓 收到keepalive事件,连接正常
'
);
});
this
.
eventSource
.
onerror
=
(
error
)
=>
{
this
.
eventSource
.
onerror
=
(
error
)
=>
{
console
.
error
(
'
SSE error:
'
,
error
);
console
.
error
(
'
SSE error:
'
,
error
);
// 检查是否为页面刷新导致的错误
// 简化错误处理:直接调用错误处理器并关闭连接
if
(
this
.
isPageRefreshing
)
{
console
.
log
(
'
💡 页面刷新中,忽略SSE错误
'
);
return
;
// 页面刷新时忽略所有错误
}
// 检查是否为"No activity"错误 - 使用更宽松的检测条件
const
errorString
=
String
(
error
).
toLowerCase
();
// 检测各种可能的"No activity"错误变体
const
isNoActivityError
=
errorString
.
includes
(
'
no activity
'
)
||
errorString
.
includes
(
'
no activity within
'
)
||
errorString
.
includes
(
'
milliseconds
'
)
&&
errorString
.
includes
(
'
reconnecting
'
)
||
errorString
.
includes
(
'
60000
'
)
&&
errorString
.
includes
(
'
reconnecting
'
);
// 如果是"No activity"错误且收到过keepalive,说明连接正常,忽略错误
if
(
isNoActivityError
&&
this
.
hasReceivedKeepalive
)
{
this
.
hasReceivedKeepalive
=
false
;
// 重置状态,等待下一次keepalive
return
;
// 不关闭连接,不触发重连,完全退出错误处理
}
// 如果只是"No activity"错误但没有收到keepalive,也尝试忽略(可能是误报)
if
(
isNoActivityError
)
{
return
;
// 不关闭连接,不触发重连
}
// 如果不是"No activity"错误,则执行正常的错误处理
if
(
this
.
handlers
.
onError
)
{
if
(
this
.
handlers
.
onError
)
{
this
.
handlers
.
onError
(
error
);
this
.
handlers
.
onError
(
error
);
}
}
this
.
closeSSE
();
this
.
closeSSE
();
// 添加错误重连逻辑(仅在非页面刷新状态下)
if
(
!
this
.
isReconnecting
.
value
&&
!
this
.
isPageRefreshing
)
{
setTimeout
(()
=>
{
if
(
dialogSessionId
)
{
this
.
reconnectSSE
(
dialogSessionId
);
}
},
3000
);
}
};
};
}
catch
(
err
)
{
}
catch
(
err
)
{
...
@@ -141,24 +85,11 @@ export class SSEService {
...
@@ -141,24 +85,11 @@ export class SSEService {
}
}
}
}
// 重新连接SSE
// 重新连接SSE
(简化版本,直接重新初始化连接)
public
reconnectSSE
(
newDialogSessionId
:
string
):
void
{
public
reconnectSSE
(
newDialogSessionId
:
string
):
void
{
if
(
this
.
isReconnecting
.
value
)
{
console
.
log
(
'
重新连接SSE,新的dialogSessionId:
'
,
newDialogSessionId
);
return
;
}
this
.
isReconnecting
.
value
=
true
;
console
.
log
(
'
开始重连SSE,新的dialogSessionId:
'
,
newDialogSessionId
);
this
.
closeSSE
();
this
.
closeSSE
();
this
.
initSSE
(
newDialogSessionId
);
const
reconnectTimeout
=
setTimeout
(()
=>
{
this
.
initSSE
(
newDialogSessionId
);
setTimeout
(()
=>
{
this
.
isReconnecting
.
value
=
false
;
},
2000
);
},
500
);
this
.
timeArr
.
push
(
reconnectTimeout
);
if
(
this
.
handlers
.
onReconnect
)
{
if
(
this
.
handlers
.
onReconnect
)
{
this
.
handlers
.
onReconnect
(
newDialogSessionId
);
this
.
handlers
.
onReconnect
(
newDialogSessionId
);
...
@@ -175,17 +106,6 @@ export class SSEService {
...
@@ -175,17 +106,6 @@ export class SSEService {
console
.
warn
(
'
关闭SSE连接时出错:
'
,
err
);
console
.
warn
(
'
关闭SSE连接时出错:
'
,
err
);
}
}
}
}
// 清理所有定时器
this
.
timeArr
.
forEach
(
timeout
=>
{
clearTimeout
(
timeout
);
});
this
.
timeArr
=
[];
}
// 获取重连状态
public
getIsReconnecting
():
boolean
{
return
this
.
isReconnecting
.
value
;
}
}
// 获取当前SSE连接状态
// 获取当前SSE连接状态
...
@@ -199,40 +119,6 @@ export class SSEService {
...
@@ -199,40 +119,6 @@ export class SSEService {
// 清理资源
// 清理资源
public
destroy
():
void
{
public
destroy
():
void
{
this
.
closeSSE
();
this
.
closeSSE
();
this
.
timeArr
.
forEach
((
item
)
=>
{
clearTimeout
(
item
);
});
this
.
timeArr
=
[];
this
.
removePageRefreshListener
();
}
// 设置页面刷新监听器
private
setupPageRefreshListener
():
void
{
if
(
typeof
window
!==
'
undefined
'
)
{
// 监听页面卸载事件
this
.
beforeUnloadHandler
=
()
=>
{
this
.
isPageRefreshing
=
true
;
console
.
log
(
'
💡 检测到页面刷新,主动关闭SSE连接
'
);
this
.
closeSSE
();
};
// 添加多个事件监听器,确保能捕获各种页面关闭场景
window
.
addEventListener
(
'
beforeunload
'
,
this
.
beforeUnloadHandler
);
}
}
// 移除页面刷新监听器
private
removePageRefreshListener
():
void
{
if
(
typeof
window
!==
'
undefined
'
)
{
if
(
this
.
beforeUnloadHandler
)
{
window
.
removeEventListener
(
'
beforeunload
'
,
this
.
beforeUnloadHandler
);
this
.
beforeUnloadHandler
=
null
;
}
}
}
// 检查是否正在页面刷新
public
getIsPageRefreshing
():
boolean
{
return
this
.
isPageRefreshing
;
}
}
}
}
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment