From f6ef0222b3375a367e0af8cb18f5ba0020b6d04c Mon Sep 17 00:00:00 2001 From: Peanut Date: Sun, 19 Jul 2026 16:04:54 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20chat=20=E8=A7=86?= =?UTF-8?q?=E5=9B=BE=E6=97=A0=E6=B3=95=E6=BB=9A=E5=8A=A8=20+=20SSE=20?= =?UTF-8?q?=E4=BA=8B=E4=BB=B6=E9=87=8D=E5=A4=8D=E6=B6=88=E8=B4=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - scrollResultToLatest 守卫条件兼容 chat 视图 - shortNovel.js 添加 chunkProcessed 标志位避免 H5 双重消费 --- mini-program/src/pages/main/ScriptView.vue | 2 +- mini-program/src/services/shortNovel.js | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/mini-program/src/pages/main/ScriptView.vue b/mini-program/src/pages/main/ScriptView.vue index fb8a5c1..b8efc15 100644 --- a/mini-program/src/pages/main/ScriptView.vue +++ b/mini-program/src/pages/main/ScriptView.vue @@ -866,7 +866,7 @@ const keepGenerationAtBottom = () => { } const scrollResultToLatest = () => { - if (viewState.value !== 'result') return + if (viewState.value !== 'result' && viewState.value !== 'chat') return nextTick(() => { measureResultViewport() pushResultScrollCommand(1000000) diff --git a/mini-program/src/services/shortNovel.js b/mini-program/src/services/shortNovel.js index 912440c..b15024c 100644 --- a/mini-program/src/services/shortNovel.js +++ b/mini-program/src/services/shortNovel.js @@ -14,6 +14,7 @@ import { getApiBaseUrl, getAuthHeader } from './request.js' * @returns {Object} uni.request 任务对象(用于 abort) */ export const startNovelStream = ({ query, onEvent, onError }) => { + let chunkProcessed = false const task = uni.request({ url: `${getApiBaseUrl()}/shortNovel/stream`, method: 'POST', @@ -30,7 +31,8 @@ export const startNovelStream = ({ query, onEvent, onError }) => { onError?.(res.data?.message || '请求失败') return } - if (typeof res.data === 'string' && res.data) { + // 仅在 chunk 未处理时才处理完整 data(避免 H5 双重消费) + if (!chunkProcessed && typeof res.data === 'string' && res.data) { consumeSseText(res.data, onEvent, onError) } }, @@ -40,6 +42,7 @@ export const startNovelStream = ({ query, onEvent, onError }) => { }) task?.onChunkReceived?.((res) => { + chunkProcessed = true try { const text = decodeChunk(res.data) consumeSseText(text, onEvent, onError) @@ -62,6 +65,7 @@ export const startNovelStream = ({ query, onEvent, onError }) => { * @returns {Object} uni.request 任务对象 */ export const followupStream = ({ sessionId, action, payload, onEvent, onError }) => { + let chunkProcessed = false const task = uni.request({ url: `${getApiBaseUrl()}/shortNovel/followup`, method: 'POST', @@ -78,7 +82,7 @@ export const followupStream = ({ sessionId, action, payload, onEvent, onError }) onError?.(res.data?.message || '请求失败') return } - if (typeof res.data === 'string' && res.data) { + if (!chunkProcessed && typeof res.data === 'string' && res.data) { consumeSseText(res.data, onEvent, onError) } }, @@ -88,6 +92,7 @@ export const followupStream = ({ sessionId, action, payload, onEvent, onError }) }) task?.onChunkReceived?.((res) => { + chunkProcessed = true try { const text = decodeChunk(res.data) consumeSseText(text, onEvent, onError)