vue_zhongyou 1.0.25 → 1.0.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
package//345/212/237/350/203/275/344/273/243/347/240/201/AI/345/257/271/350/257/235/aiChatPage.vue
CHANGED
|
@@ -166,6 +166,15 @@ const inputComRef = ref(null)
|
|
|
166
166
|
const abortControllerRef = ref(null)
|
|
167
167
|
// 当前正在接收流式响应的消息索引
|
|
168
168
|
const streamingMessageIndex = ref(-1)
|
|
169
|
+
// SSE重连相关
|
|
170
|
+
const reconnectAttempts = ref(0)
|
|
171
|
+
const maxReconnectAttempts = ref(3)
|
|
172
|
+
const reconnectDelay = ref(1000) // 初始重连延迟1秒
|
|
173
|
+
const reconnectTimerRef = ref(null)
|
|
174
|
+
// 当前请求体,用于重连时重新发送
|
|
175
|
+
const currentRequestBody = ref(null)
|
|
176
|
+
// 当前用户输入,用于重连时重新发送
|
|
177
|
+
const currentUserInput = ref('')
|
|
169
178
|
|
|
170
179
|
|
|
171
180
|
// 判断消息类型
|
|
@@ -260,10 +269,21 @@ const sendMessage = async () => {
|
|
|
260
269
|
const text = inputComRef.value.inputText.trim()
|
|
261
270
|
if (!text || isLoading.value) return
|
|
262
271
|
|
|
263
|
-
//
|
|
272
|
+
// 取消之前的请求和重连定时器
|
|
264
273
|
if (abortControllerRef.value) {
|
|
265
274
|
abortControllerRef.value.abort()
|
|
266
275
|
}
|
|
276
|
+
if (reconnectTimerRef.value) {
|
|
277
|
+
clearTimeout(reconnectTimerRef.value)
|
|
278
|
+
reconnectTimerRef.value = null
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// 重置重连计数器和延迟
|
|
282
|
+
reconnectAttempts.value = 0
|
|
283
|
+
reconnectDelay.value = 1000
|
|
284
|
+
|
|
285
|
+
// 保存当前请求信息,用于重连
|
|
286
|
+
currentUserInput.value = text
|
|
267
287
|
|
|
268
288
|
// 添加用户消息
|
|
269
289
|
addMessage('user', text)
|
|
@@ -291,7 +311,16 @@ const sendMessage = async () => {
|
|
|
291
311
|
}
|
|
292
312
|
}
|
|
293
313
|
}
|
|
314
|
+
|
|
315
|
+
// 保存请求体,用于重连
|
|
316
|
+
currentRequestBody.value = requestBody
|
|
317
|
+
|
|
318
|
+
// 执行SSE请求
|
|
319
|
+
await executeSSERequest(requestBody, text)
|
|
320
|
+
}
|
|
294
321
|
|
|
322
|
+
// 执行SSE请求
|
|
323
|
+
const executeSSERequest = async (requestBody, userText) => {
|
|
295
324
|
// 创建新的AbortController
|
|
296
325
|
abortControllerRef.value = new AbortController()
|
|
297
326
|
|
|
@@ -308,7 +337,7 @@ const sendMessage = async () => {
|
|
|
308
337
|
'Cache-Control': 'no-cache'
|
|
309
338
|
},
|
|
310
339
|
body: JSON.stringify({
|
|
311
|
-
message:
|
|
340
|
+
message: userText
|
|
312
341
|
}),
|
|
313
342
|
signal: abortControllerRef.value.signal
|
|
314
343
|
})
|
|
@@ -322,11 +351,16 @@ const sendMessage = async () => {
|
|
|
322
351
|
const decoder = new TextDecoder()
|
|
323
352
|
let buffer = ''
|
|
324
353
|
|
|
354
|
+
// 重置重连计数器(连接成功)
|
|
355
|
+
reconnectAttempts.value = 0
|
|
356
|
+
|
|
325
357
|
while (true) {
|
|
326
358
|
const { done, value } = await reader.read()
|
|
359
|
+
console.log(done, value);
|
|
327
360
|
|
|
328
361
|
if (done) {
|
|
329
362
|
console.log('SSE流读取完成')
|
|
363
|
+
// 流正常结束,不需要重连
|
|
330
364
|
break
|
|
331
365
|
}
|
|
332
366
|
|
|
@@ -380,9 +414,44 @@ const sendMessage = async () => {
|
|
|
380
414
|
console.log('请求已取消')
|
|
381
415
|
} else {
|
|
382
416
|
console.error('SSE请求失败:', error)
|
|
417
|
+
// 处理SSE错误并重试
|
|
383
418
|
handleSSEError('连接失败,请重试')
|
|
419
|
+
// 尝试重连
|
|
420
|
+
attemptReconnect()
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// 尝试重新连接
|
|
426
|
+
const attemptReconnect = () => {
|
|
427
|
+
// 检查是否达到最大重试次数
|
|
428
|
+
if (reconnectAttempts.value >= maxReconnectAttempts.value) {
|
|
429
|
+
console.error('已达到最大重连次数,停止重连')
|
|
430
|
+
// 更新消息状态
|
|
431
|
+
const messageIndex = streamingMessageIndex.value
|
|
432
|
+
if (messageIndex !== -1 && messages.value[messageIndex]) {
|
|
433
|
+
messages.value[messageIndex].loading = false
|
|
434
|
+
messages.value[messageIndex].content = '连接已断开,建议重试'
|
|
384
435
|
}
|
|
436
|
+
isLoading.value = false
|
|
437
|
+
return
|
|
385
438
|
}
|
|
439
|
+
|
|
440
|
+
// 增加重连计数器
|
|
441
|
+
reconnectAttempts.value++
|
|
442
|
+
|
|
443
|
+
// 指数退避策略,每次重连延迟翻倍
|
|
444
|
+
const delay = reconnectDelay.value * Math.pow(2, reconnectAttempts.value - 1)
|
|
445
|
+
|
|
446
|
+
console.log(`SSE连接失败,${delay}ms后尝试第${reconnectAttempts.value}次重连...`)
|
|
447
|
+
|
|
448
|
+
// 设置重连定时器
|
|
449
|
+
reconnectTimerRef.value = setTimeout(async () => {
|
|
450
|
+
console.log(`尝试第${reconnectAttempts.value}次重连...`)
|
|
451
|
+
|
|
452
|
+
// 重新执行SSE请求
|
|
453
|
+
await executeSSERequest(currentRequestBody.value, currentUserInput.value)
|
|
454
|
+
}, delay)
|
|
386
455
|
}
|
|
387
456
|
|
|
388
457
|
// 处理SSE消息
|
|
@@ -463,6 +532,11 @@ onUnmounted(() => {
|
|
|
463
532
|
abortControllerRef.value.abort()
|
|
464
533
|
abortControllerRef.value = null
|
|
465
534
|
}
|
|
535
|
+
// 清理重连定时器
|
|
536
|
+
if (reconnectTimerRef.value) {
|
|
537
|
+
clearTimeout(reconnectTimerRef.value)
|
|
538
|
+
reconnectTimerRef.value = null
|
|
539
|
+
}
|
|
466
540
|
})
|
|
467
541
|
|
|
468
542
|
// 格式化消息内容(支持Markdown)
|
|
@@ -708,6 +782,7 @@ const handleLoadMore = (message) => {
|
|
|
708
782
|
// max-width: 75%;
|
|
709
783
|
flex: 1;
|
|
710
784
|
gap: 6px;
|
|
785
|
+
overflow: hidden;
|
|
711
786
|
}
|
|
712
787
|
|
|
713
788
|
.message-bubble {
|
|
@@ -715,11 +790,15 @@ const handleLoadMore = (message) => {
|
|
|
715
790
|
word-wrap: break-word;
|
|
716
791
|
word-break: break-word;
|
|
717
792
|
line-height: 1.5;
|
|
793
|
+
max-width: 100%;
|
|
794
|
+
box-sizing: border-box;
|
|
795
|
+
overflow: hidden;
|
|
718
796
|
}
|
|
719
797
|
|
|
720
798
|
.message-text {
|
|
721
799
|
font-size: 15px;
|
|
722
800
|
white-space: pre-wrap;
|
|
801
|
+
overflow: hidden;
|
|
723
802
|
|
|
724
803
|
// Markdown样式隔离 - 使用深度选择器控制所有Markdown元素
|
|
725
804
|
:deep(*) {
|
|
@@ -804,6 +883,8 @@ const handleLoadMore = (message) => {
|
|
|
804
883
|
border-radius: 3px;
|
|
805
884
|
font-size: 0.9em;
|
|
806
885
|
color: #e83e8c;
|
|
886
|
+
word-break: break-all;
|
|
887
|
+
word-wrap: break-word;
|
|
807
888
|
}
|
|
808
889
|
|
|
809
890
|
:deep(pre) {
|
|
@@ -813,8 +894,13 @@ const handleLoadMore = (message) => {
|
|
|
813
894
|
padding: 12px;
|
|
814
895
|
margin: 0.5em 0;
|
|
815
896
|
overflow-x: auto;
|
|
816
|
-
|
|
897
|
+
overflow-y: hidden;
|
|
898
|
+
font-size: 0.85em;
|
|
817
899
|
line-height: 1.5;
|
|
900
|
+
max-width: 100%;
|
|
901
|
+
box-sizing: border-box;
|
|
902
|
+
-webkit-overflow-scrolling: touch;
|
|
903
|
+
word-break: break-all;
|
|
818
904
|
}
|
|
819
905
|
|
|
820
906
|
:deep(pre code) {
|
|
@@ -823,6 +909,10 @@ const handleLoadMore = (message) => {
|
|
|
823
909
|
border-radius: 0;
|
|
824
910
|
font-size: inherit;
|
|
825
911
|
color: inherit;
|
|
912
|
+
word-break: break-all;
|
|
913
|
+
word-wrap: break-word;
|
|
914
|
+
white-space: pre-wrap;
|
|
915
|
+
overflow-wrap: anywhere;
|
|
826
916
|
}
|
|
827
917
|
|
|
828
918
|
// 引用样式
|
|
@@ -840,12 +930,17 @@ const handleLoadMore = (message) => {
|
|
|
840
930
|
width: 100%;
|
|
841
931
|
margin: 0.5em 0;
|
|
842
932
|
font-size: 0.95em;
|
|
933
|
+
display: block;
|
|
934
|
+
overflow-x: auto;
|
|
935
|
+
-webkit-overflow-scrolling: touch;
|
|
843
936
|
}
|
|
844
937
|
|
|
845
938
|
:deep(table th), :deep(table td) {
|
|
846
939
|
border: 1px solid #dfe2e5;
|
|
847
940
|
padding: 6px 12px;
|
|
848
941
|
text-align: left;
|
|
942
|
+
white-space: nowrap;
|
|
943
|
+
min-width: 80px;
|
|
849
944
|
}
|
|
850
945
|
|
|
851
946
|
:deep(table th) {
|
|
@@ -863,6 +958,7 @@ const handleLoadMore = (message) => {
|
|
|
863
958
|
text-decoration: none;
|
|
864
959
|
border-bottom: 1px solid transparent;
|
|
865
960
|
transition: border-bottom-color 0.2s;
|
|
961
|
+
word-break: break-all;
|
|
866
962
|
}
|
|
867
963
|
|
|
868
964
|
:deep(a:hover) {
|