fix(feed): 把 wrapper 嵌入 NCard 内部底部,真正紧贴对应卡片
This commit is contained in:
@@ -44,17 +44,12 @@ let categoryPromptTimer: number | null = null
|
||||
// - items 没这条 → 不渲染(孤儿)
|
||||
// - items 有 + Map 也有 → 渲染
|
||||
// - items 有 + Map 没 → 不渲染(用户已 dismiss/确认/超时)
|
||||
const articlesWithPrompts = computed(() => {
|
||||
const r = items.value.filter((a) => (categoryPromptsByArticle.value.get(a.id)?.length ?? 0) > 0)
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('[AWP] resultLen=', r.length, 'itemsLen=', items.value.length, 'mapSize=', categoryPromptsByArticle.value.size)
|
||||
return r
|
||||
})
|
||||
const articlesWithPrompts = computed(() =>
|
||||
items.value.filter((a) => (categoryPromptsByArticle.value.get(a.id)?.length ?? 0) > 0)
|
||||
)
|
||||
|
||||
// 移除某篇文章的所有提示条(8 秒超时 / 确认后 / 过滤变化)
|
||||
function clearPromptsForArticle(articleId: number) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('[CLEAR_ONE]', articleId, 'stack:', new Error().stack?.split('\n').slice(2, 5).join(' | '))
|
||||
if (categoryPromptsByArticle.value.has(articleId)) {
|
||||
const next = new Map(categoryPromptsByArticle.value)
|
||||
next.delete(articleId)
|
||||
@@ -64,8 +59,6 @@ function clearPromptsForArticle(articleId: number) {
|
||||
|
||||
// 全清
|
||||
function clearAllPrompts() {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('[CLEAR_ALL] size=', categoryPromptsByArticle.value.size, 'stack:', new Error().stack?.split('\n').slice(2, 5).join(' | '))
|
||||
if (categoryPromptsByArticle.value.size > 0) {
|
||||
categoryPromptsByArticle.value = new Map()
|
||||
}
|
||||
@@ -693,58 +686,57 @@ onMounted(async () => {
|
||||
{{ a.is_read ? '已读' : '标为已读' }}
|
||||
</NButton>
|
||||
</div>
|
||||
<!--
|
||||
分类提示条(per-article,紧贴卡片底部):
|
||||
- 嵌在 NCard 内部,确保 DOM 位置紧贴对应卡片
|
||||
- 只有当该 article 在 categoryPromptsByArticle Map 里有值时才渲染
|
||||
- 8s 后 Map 删掉 → wrapper 走 leave 动画
|
||||
- 内部 NAlert v-for 用 ${a.id}-${category} 作为 key,确保多个 category 时各自独立
|
||||
-->
|
||||
<div
|
||||
v-if="(categoryPromptsByArticle.get(a.id)?.length ?? 0) > 0"
|
||||
:key="`prompt-wrapper-${a.id}`"
|
||||
class="feed-category-prompt-wrapper"
|
||||
>
|
||||
<!-- 标题行:标记已读的确认 + 1~2 条分类提示的容器 -->
|
||||
<div class="feed-category-prompt-header">
|
||||
<NSpace align="center" :size="8" :wrap="true">
|
||||
<NTag type="success" size="small" round :bordered="false">✓ 已将《{{ a.title_zh || a.title }}》标记为已读</NTag>
|
||||
</NSpace>
|
||||
</div>
|
||||
<NAlert
|
||||
v-for="p in (categoryPromptsByArticle.get(a.id) || [])"
|
||||
:key="`${a.id}-${p.category}`"
|
||||
type="success"
|
||||
:show-icon="false"
|
||||
closable
|
||||
@close="dismissPrompt(a.id, p.category)"
|
||||
class="feed-category-prompt"
|
||||
>
|
||||
<template #header>
|
||||
<NSpace align="center" :size="8" :wrap="true">
|
||||
<NText>「{{ p.category }}」分类下还有 {{ p.unreadCount }} 条 24 小时未读</NText>
|
||||
</NSpace>
|
||||
</template>
|
||||
<NSpace :size="8" style="margin-top: 8px">
|
||||
<NButton
|
||||
type="primary"
|
||||
size="small"
|
||||
round
|
||||
:loading="pendingCategory === p.category"
|
||||
:disabled="pendingCategory !== null"
|
||||
@click="confirmMarkCategory(a.id, p.category)"
|
||||
>
|
||||
全部已读
|
||||
</NButton>
|
||||
<NButton size="small" round @click="dismissPrompt(a.id, p.category)">
|
||||
稍后再说
|
||||
</NButton>
|
||||
</NSpace>
|
||||
</NAlert>
|
||||
</div>
|
||||
</NSpace>
|
||||
</NCard>
|
||||
<!--
|
||||
该文章对应的分类提示条(per-article 挂载,卡片**下方**):
|
||||
- 用 articlesWithPrompts(过滤后只有有提示条的 article)做 v-for
|
||||
- 跟 NCard 在同一个 TransitionGroup,但 hide_read 模式不再 splice 移除文章,
|
||||
所以 NCard 不会触发 leave 动画,wrapper 不会被卷走
|
||||
- 8s 后 Map 删掉 → wrapper 走自己的 leave 动画(只影响 wrapper,不影响 NCard)
|
||||
- 内部 NAlert v-for 用 ${a.id}-${category} 作为 key,确保多个 category 时各自独立
|
||||
-->
|
||||
<div
|
||||
v-for="a in articlesWithPrompts"
|
||||
:key="`prompt-wrapper-${a.id}`"
|
||||
class="feed-category-prompt-wrapper"
|
||||
>
|
||||
<!-- 标题行:标记已读的确认 + 1~2 条分类提示的容器 -->
|
||||
<div class="feed-category-prompt-header">
|
||||
<NSpace align="center" :size="8" :wrap="true">
|
||||
<NTag type="success" size="small" round :bordered="false">✓ 已将《{{ a.title_zh || a.title }}》标记为已读</NTag>
|
||||
</NSpace>
|
||||
</div>
|
||||
<NAlert
|
||||
v-for="p in (categoryPromptsByArticle.get(a.id) || [])"
|
||||
:key="`${a.id}-${p.category}`"
|
||||
type="success"
|
||||
:show-icon="false"
|
||||
closable
|
||||
@close="dismissPrompt(a.id, p.category)"
|
||||
class="feed-category-prompt"
|
||||
>
|
||||
<template #header>
|
||||
<NSpace align="center" :size="8" :wrap="true">
|
||||
<NText>「{{ p.category }}」分类下还有 {{ p.unreadCount }} 条 24 小时未读</NText>
|
||||
</NSpace>
|
||||
</template>
|
||||
<NSpace :size="8" style="margin-top: 8px">
|
||||
<NButton
|
||||
type="primary"
|
||||
size="small"
|
||||
round
|
||||
:loading="pendingCategory === p.category"
|
||||
:disabled="pendingCategory !== null"
|
||||
@click="confirmMarkCategory(a.id, p.category)"
|
||||
>
|
||||
全部已读
|
||||
</NButton>
|
||||
<NButton size="small" round @click="dismissPrompt(a.id, p.category)">
|
||||
稍后再说
|
||||
</NButton>
|
||||
</NSpace>
|
||||
</NAlert>
|
||||
</div>
|
||||
</TransitionGroup>
|
||||
|
||||
<!-- 页码分页 -->
|
||||
|
||||
Reference in New Issue
Block a user