Browse Source

refactor(tags): streamline tag handling in post lists

- Removed redundant state for available tags and replaced it with a computed property that consolidates tags from API and post items.
- Enhanced the tag filtering UI by maintaining the existing structure while improving the logic for tag selection and clearing.
- Updated the posts page to ensure consistent tag management across user and public views.

These changes improve the efficiency of tag management and enhance the user experience in filtering posts by tags.
main
npmrun 2 weeks ago
parent
commit
f73a0d2d43
  1. 68
      app/pages/@[publicSlug]/posts/index.vue
  2. 10
      app/pages/me/posts/index.vue
  3. BIN
      packages/drizzle-pkg/db.sqlite

68
app/pages/@[publicSlug]/posts/index.vue

@ -61,7 +61,6 @@ const selectedTags = ref<string[]>(
: [],
)
const tagMode = ref<TagMode>(route.query.tagMode === 'and' ? 'and' : 'or')
const availableTags = ref<string[]>([])
const tagModeItems = [
{ label: '任一命中 (OR)', value: 'or' },
{ label: '全部命中 (AND)', value: 'and' },
@ -98,12 +97,13 @@ const { data, pending, error } = await useAsyncData(
{ watch: [slug, page, selectedTags, tagMode] },
)
watch(
() => data.value?.availableTags,
() => {
availableTags.value = data.value?.availableTags ?? []
},
)
const availableTags = computed(() => {
const byApi = data.value?.availableTags ?? []
const byItems = (data.value?.items ?? [])
.flatMap(item => item.tags ?? [])
.filter(Boolean)
return [...new Set([...byApi, ...byItems])]
})
watch(
() => [route.query.tags, route.query.tagMode] as const,
@ -166,39 +166,39 @@ usePageTitle(() => {
class="my-6"
/>
<template v-else-if="data">
<UCard class="mb-4" :ui="{ body: 'p-4 space-y-3' }">
<div class="flex items-center justify-between gap-2">
<div class="text-sm text-muted">
标签筛选
</div>
<UButton
size="xs"
color="neutral"
variant="ghost"
@click="selectedTags = []; tagMode = 'or'; updateFilterQuery(1)"
>
清空
</UButton>
</div>
<PostTagsInput
:model-value="selectedTags"
:suggestions="availableTags"
placeholder="输入标签回车筛选"
@update:model-value="(v) => { selectedTags = v; updateFilterQuery(1) }"
/>
<USelect
v-model="tagMode"
:items="tagModeItems"
class="w-full sm:w-56"
@update:model-value="() => updateFilterQuery(1)"
/>
</UCard>
<UEmpty
v-if="data.total === 0"
:title="selectedTags.length ? '没有匹配结果' : '暂无公开文章'"
:description="selectedTags.length ? '请尝试调整标签筛选条件。' : '站主尚未发布任何公开文章。'"
/>
<template v-else>
<UCard class="mb-4" :ui="{ body: 'p-4 space-y-3' }">
<div class="flex items-center justify-between gap-2">
<div class="text-sm text-muted">
标签筛选
</div>
<UButton
size="xs"
color="neutral"
variant="ghost"
@click="selectedTags = []; tagMode = 'or'; updateFilterQuery(1)"
>
清空
</UButton>
</div>
<PostTagsInput
:model-value="selectedTags"
:suggestions="availableTags"
placeholder="输入标签回车筛选"
@update:model-value="(v) => { selectedTags = v; updateFilterQuery(1) }"
/>
<USelect
v-model="tagMode"
:items="tagModeItems"
class="w-full sm:w-56"
@update:model-value="() => updateFilterQuery(1)"
/>
</UCard>
<h2 class="text-xs font-semibold uppercase tracking-wider text-muted mb-4">
文章
</h2>

10
app/pages/me/posts/index.vue

@ -25,7 +25,7 @@ const router = useRouter()
const page = ref(1)
const total = ref(0)
const pageSize = ref(20)
const availableTags = ref<string[]>([])
const availableTagsApi = ref<string[]>([])
const selectedTags = ref<string[]>([])
const tagMode = ref<TagMode>('or')
@ -58,12 +58,18 @@ async function load() {
posts.value = data.items
total.value = data.total
pageSize.value = data.pageSize
availableTags.value = data.availableTags ?? []
availableTagsApi.value = data.availableTags ?? []
} finally {
loading.value = false
}
}
const availableTags = computed(() => {
const byApi = availableTagsApi.value ?? []
const byItems = posts.value.flatMap(item => item.tags ?? []).filter(Boolean)
return [...new Set([...byApi, ...byItems])]
})
function onPageChange(nextPage: number) {
page.value = nextPage
const query = { ...route.query }

BIN
packages/drizzle-pkg/db.sqlite

Binary file not shown.
Loading…
Cancel
Save