fix: 修复 chat 视图无法滚动 + SSE 事件重复消费

- scrollResultToLatest 守卫条件兼容 chat 视图
- shortNovel.js 添加 chunkProcessed 标志位避免 H5 双重消费
This commit is contained in:
2026-07-19 16:04:54 +08:00
parent e109e59f1a
commit f6ef0222b3
2 changed files with 8 additions and 3 deletions
+1 -1
View File
@@ -866,7 +866,7 @@ const keepGenerationAtBottom = () => {
} }
const scrollResultToLatest = () => { const scrollResultToLatest = () => {
if (viewState.value !== 'result') return if (viewState.value !== 'result' && viewState.value !== 'chat') return
nextTick(() => { nextTick(() => {
measureResultViewport() measureResultViewport()
pushResultScrollCommand(1000000) pushResultScrollCommand(1000000)
+7 -2
View File
@@ -14,6 +14,7 @@ import { getApiBaseUrl, getAuthHeader } from './request.js'
* @returns {Object} uni.request 任务对象(用于 abort * @returns {Object} uni.request 任务对象(用于 abort
*/ */
export const startNovelStream = ({ query, onEvent, onError }) => { export const startNovelStream = ({ query, onEvent, onError }) => {
let chunkProcessed = false
const task = uni.request({ const task = uni.request({
url: `${getApiBaseUrl()}/shortNovel/stream`, url: `${getApiBaseUrl()}/shortNovel/stream`,
method: 'POST', method: 'POST',
@@ -30,7 +31,8 @@ export const startNovelStream = ({ query, onEvent, onError }) => {
onError?.(res.data?.message || '请求失败') onError?.(res.data?.message || '请求失败')
return return
} }
if (typeof res.data === 'string' && res.data) { // 仅在 chunk 未处理时才处理完整 data(避免 H5 双重消费)
if (!chunkProcessed && typeof res.data === 'string' && res.data) {
consumeSseText(res.data, onEvent, onError) consumeSseText(res.data, onEvent, onError)
} }
}, },
@@ -40,6 +42,7 @@ export const startNovelStream = ({ query, onEvent, onError }) => {
}) })
task?.onChunkReceived?.((res) => { task?.onChunkReceived?.((res) => {
chunkProcessed = true
try { try {
const text = decodeChunk(res.data) const text = decodeChunk(res.data)
consumeSseText(text, onEvent, onError) consumeSseText(text, onEvent, onError)
@@ -62,6 +65,7 @@ export const startNovelStream = ({ query, onEvent, onError }) => {
* @returns {Object} uni.request 任务对象 * @returns {Object} uni.request 任务对象
*/ */
export const followupStream = ({ sessionId, action, payload, onEvent, onError }) => { export const followupStream = ({ sessionId, action, payload, onEvent, onError }) => {
let chunkProcessed = false
const task = uni.request({ const task = uni.request({
url: `${getApiBaseUrl()}/shortNovel/followup`, url: `${getApiBaseUrl()}/shortNovel/followup`,
method: 'POST', method: 'POST',
@@ -78,7 +82,7 @@ export const followupStream = ({ sessionId, action, payload, onEvent, onError })
onError?.(res.data?.message || '请求失败') onError?.(res.data?.message || '请求失败')
return return
} }
if (typeof res.data === 'string' && res.data) { if (!chunkProcessed && typeof res.data === 'string' && res.data) {
consumeSseText(res.data, onEvent, onError) consumeSseText(res.data, onEvent, onError)
} }
}, },
@@ -88,6 +92,7 @@ export const followupStream = ({ sessionId, action, payload, onEvent, onError })
}) })
task?.onChunkReceived?.((res) => { task?.onChunkReceived?.((res) => {
chunkProcessed = true
try { try {
const text = decodeChunk(res.data) const text = decodeChunk(res.data)
consumeSseText(text, onEvent, onError) consumeSseText(text, onEvent, onError)