2 changed files with 148 additions and 9 deletions
@ -0,0 +1,113 @@ |
|||
<script setup lang="ts"> |
|||
import { ref, onMounted } from 'vue' |
|||
import { useRouter } from 'vue-router' |
|||
import { tagApi } from '@/api/client' |
|||
import type { Tag } from '@/generated/api' |
|||
|
|||
const router = useRouter() |
|||
const tags = ref<Tag[]>([]) |
|||
const loading = ref(false) |
|||
const error = ref<string | null>(null) |
|||
|
|||
function sizeClass(count: number): string { |
|||
if (count >= 5) return 'tag-lg' |
|||
if (count >= 2) return 'tag-md' |
|||
return 'tag-sm' |
|||
} |
|||
|
|||
function goToTag(tag: Tag) { |
|||
router.push({ name: 'Home', query: { tag: tag.slug } }) |
|||
} |
|||
|
|||
async function load() { |
|||
loading.value = true |
|||
error.value = null |
|||
try { |
|||
const resp = await tagApi.apiTagsGet() |
|||
tags.value = resp.data.data ?? [] |
|||
} catch (e) { |
|||
console.error(e) |
|||
error.value = '标签加载失败' |
|||
} finally { |
|||
loading.value = false |
|||
} |
|||
} |
|||
|
|||
onMounted(load) |
|||
</script> |
|||
|
|||
<template> |
|||
<div class="tag-cloud"> |
|||
<h3 class="tag-cloud-title">标签云</h3> |
|||
<p v-if="error" class="error-text">{{ error }}</p> |
|||
<p v-else-if="loading" class="hint-text">加载中...</p> |
|||
<p v-else-if="tags.length === 0" class="hint-text">暂无标签</p> |
|||
<div v-else class="tag-cloud-items"> |
|||
<button |
|||
v-for="tag in tags" |
|||
:key="tag.id" |
|||
class="tag-item" |
|||
:class="sizeClass(tag.articleCount)" |
|||
@click="goToTag(tag)" |
|||
> |
|||
{{ tag.name }} |
|||
</button> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<style scoped> |
|||
.tag-cloud { |
|||
background: #fff; |
|||
border: 1px solid #e5e5ea; |
|||
border-radius: 8px; |
|||
padding: 16px; |
|||
} |
|||
|
|||
.tag-cloud-title { |
|||
margin: 0 0 12px; |
|||
font-size: 16px; |
|||
} |
|||
|
|||
.tag-cloud-items { |
|||
display: flex; |
|||
flex-wrap: wrap; |
|||
gap: 8px; |
|||
} |
|||
|
|||
.tag-item { |
|||
border: none; |
|||
background: #eef3ff; |
|||
color: #3b5bdb; |
|||
border-radius: 12px; |
|||
cursor: pointer; |
|||
font-size: 13px; |
|||
padding: 4px 12px; |
|||
} |
|||
|
|||
.tag-item:hover { |
|||
background: #dbe4ff; |
|||
} |
|||
|
|||
.tag-lg { |
|||
font-size: 17px; |
|||
padding: 6px 16px; |
|||
} |
|||
|
|||
.tag-md { |
|||
font-size: 14px; |
|||
padding: 5px 14px; |
|||
} |
|||
|
|||
.tag-sm { |
|||
font-size: 12px; |
|||
} |
|||
|
|||
.error-text { |
|||
color: #d33c3c; |
|||
} |
|||
|
|||
.hint-text { |
|||
color: #8a93a3; |
|||
} |
|||
</style> |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue