From c6ad3c097482dec87e01d7496b665276502783fc Mon Sep 17 00:00:00 2001 From: xiaji Date: Tue, 16 Jun 2026 07:55:09 +0800 Subject: [PATCH] =?UTF-8?q?fix(feed):=20hide=5Fread=20=E6=A8=A1=E5=BC=8F?= =?UTF-8?q?=E4=B8=8B,=E6=9C=89=E6=8F=90=E7=A4=BA=E6=9D=A1=E6=97=B6?= =?UTF-8?q?=E6=8E=A8=E8=BF=9F=E6=96=87=E7=AB=A0=20splice=20=E5=88=B0?= =?UTF-8?q?=E6=8F=90=E7=A4=BA=E6=9D=A1=E6=B6=88=E5=A4=B1=E5=90=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/views/Feed.vue | 59 ++++++++++++++++++++++++++++++------- 1 file changed, 48 insertions(+), 11 deletions(-) diff --git a/frontend/src/views/Feed.vue b/frontend/src/views/Feed.vue index 4dc5854..f545741 100644 --- a/frontend/src/views/Feed.vue +++ b/frontend/src/views/Feed.vue @@ -193,9 +193,11 @@ async function toggleRead(a: ArticleListItem) { await readsApi.mark(a.id) } - // === 关键:先 await 提示条 fetch,再 splice === - // 原因:hide_read 模式下,350ms 后 items.splice 会把 a 移除,wrapper 跟着走。 - // 如果 category-count 比 350ms 慢,wrapper 还没渲染就被切走 → 用户看不到。 + // === 关键:先 await 提示条 fetch,再决定是否 splice === + // 原因:hide_read 模式下,如果 360ms 内就把 a 从 items 移除, + // articlesWithPrompts 跟着过滤,wrapper 就被切走 → 用户看不到提示条。 + // 解决:如果 fetch 完发现有提示条 → 把 splice 推迟到 8s 提示条到期再 splice; + // 如果没有提示条 → 照旧 360ms splice。 if (!wasRead && a.category) { try { const fetchPromise = maybePromptCategoryRead(a) @@ -209,16 +211,51 @@ async function toggleRead(a: ArticleListItem) { } // hide_read 模式:卡片从列表里消失(用户预期行为) + // 但如果该文章有提示条,推迟 splice 到提示条消失后再做 if (!wasRead && hideRead.value) { - const idx = items.value.findIndex((x) => x.id === a.id) - if (idx >= 0) { - pendingRemoval.value.add(a.id) + const hasPrompt = (categoryPromptsByArticle.value.get(a.id)?.length ?? 0) > 0 + const delay = hasPrompt ? 8200 : 360 // 有提示:让提示条走完 8s;无提示:照旧 + if (hasPrompt) { + // 监听 8s 计时器到期 / dismiss / confirm + // 用 watchEffect 监听 Map 变化,提示条消失后再 splice + const stopWatch = watch( + () => categoryPromptsByArticle.value.get(a.id), + (newVal) => { + if (!newVal || newVal.length === 0) { + stopWatch() + const idx = items.value.findIndex((x) => x.id === a.id) + if (idx >= 0) { + pendingRemoval.value.add(a.id) + items.value.splice(idx, 1) + pendingRemoval.value.delete(a.id) + if (total.value > 0) total.value -= 1 + } + } + }, + { immediate: false }, + ) + // 兜底:8.2s 强制结束(防止 watch 漏掉) setTimeout(() => { - const i = items.value.findIndex((x) => x.id === a.id) - if (i >= 0) items.value.splice(i, 1) - pendingRemoval.value.delete(a.id) - if (total.value > 0) total.value -= 1 - }, 360) + stopWatch() + const idx = items.value.findIndex((x) => x.id === a.id) + if (idx >= 0) { + pendingRemoval.value.add(a.id) + items.value.splice(idx, 1) + pendingRemoval.value.delete(a.id) + if (total.value > 0) total.value -= 1 + } + }, delay) + } else { + const idx = items.value.findIndex((x) => x.id === a.id) + if (idx >= 0) { + pendingRemoval.value.add(a.id) + setTimeout(() => { + const i = items.value.findIndex((x) => x.id === a.id) + if (i >= 0) items.value.splice(i, 1) + pendingRemoval.value.delete(a.id) + if (total.value > 0) total.value -= 1 + }, delay) + } } } } catch (e: any) {