diff --git a/frontend/src/views/Feed.vue b/frontend/src/views/Feed.vue index f545741..627df45 100644 --- a/frontend/src/views/Feed.vue +++ b/frontend/src/views/Feed.vue @@ -210,54 +210,11 @@ async function toggleRead(a: ArticleListItem) { } } - // hide_read 模式:卡片从列表里消失(用户预期行为) - // 但如果该文章有提示条,推迟 splice 到提示条消失后再做 - if (!wasRead && hideRead.value) { - 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(() => { - 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) - } - } - } + // hide_read 模式:卡片**保留在列表里**(视觉降级为 opacity 0.7) + // 不再 splice 移除文章 — 否则会触发 NCard 的 leave 动画, + // 进而影响 wrapper 显示,导致分类提示条看不见 + // 用户主动刷新 / 切页时 hideRead=true 的过滤会自然把已读过滤掉 + // (hide_read 模式的"splice"逻辑废弃,保留 is_read 状态以驱动 article-card-read 样式) } catch (e: any) { // 失败回滚 a.is_read = wasRead @@ -319,21 +276,9 @@ async function confirmMarkCategory(articleId: number, category: string) { for (const item of items.value) { if (ids.has(item.id)) item.is_read = true } - // 走 hide_read 模式下的滑出(累计 delay,逐个错开,避免 30 个 setTimeout 同时触发视觉抖) - let i = 0 - for (const id of resp.article_ids) { - const idx = items.value.findIndex((x) => x.id === id) - if (idx < 0) continue - pendingRemoval.value.add(id) - const delay = 360 + i * 20 - i++ - setTimeout(() => { - const k = items.value.findIndex((x) => x.id === id) - if (k >= 0) items.value.splice(k, 1) - pendingRemoval.value.delete(id) - if (total.value > 0) total.value -= 1 - }, delay) - } + // 走 hide_read 模式下的滑出 — 已废弃,改成已读卡片视觉降级 + // 原因:批量 splice 触发的 NCard leave 动画会带歪提示条 wrapper + // 用户主动刷新 / 切页时,hideRead=true 的过滤会自然把已读过滤掉 // 关闭该 article 的整组提示(不只关 category — 既然"全部已读"了,这一片都不需要了) clearPromptsForArticle(articleId) message.success(`已将 ${resp.marked} 条「${category}」标记为已读`) @@ -746,9 +691,9 @@ onMounted(async () => {