feat(encyclopedia): display cloud type icon images
This commit is contained in:
@@ -156,6 +156,7 @@ export function toCloudType(row: BackendCloudType): CloudType {
|
||||
id: row.id,
|
||||
name: row.name,
|
||||
genus: row.genus || '',
|
||||
icon_id: row.icon_id,
|
||||
// Compatibility value for the excluded legacy admin view. Migrated pages
|
||||
// display rarity_value directly because API.md defines no semantic mapping.
|
||||
rarity: 'common',
|
||||
|
||||
@@ -2,6 +2,7 @@ export interface CloudType {
|
||||
id: number
|
||||
name: string
|
||||
genus: string
|
||||
icon_id: string | null
|
||||
rarity: 'common' | 'uncommon' | 'rare'
|
||||
rarity_value: number
|
||||
description: string | null
|
||||
|
||||
@@ -4,7 +4,7 @@ import { NAlert, NButton, NEmpty, NSkeleton } from 'naive-ui'
|
||||
import { RouterLink, useRoute } from 'vue-router'
|
||||
import ImageDetailModal from '@/components/cloud/ImageDetailModal.vue'
|
||||
import MiniLocationMap from '@/components/cloud/MiniLocationMap.vue'
|
||||
import { apiRequest, toApiCloud } from '@/lib/api'
|
||||
import { apiRequest, imageUrl, toApiCloud } from '@/lib/api'
|
||||
import { useEncyclopediaStore } from '@/stores/encyclopedia'
|
||||
import type { ApiCloud, BackendCloudInfo } from '@/types/api'
|
||||
|
||||
@@ -20,7 +20,7 @@ const hasNextPage = ref(false)
|
||||
|
||||
const cloudTypeId = computed(() => Number(route.params.id))
|
||||
const cloudType = computed(() => encyclopediaStore.cloudTypes.find(item => item.id === cloudTypeId.value) ?? null)
|
||||
const heroImage = computed(() => gallery.value[0]?.image_url || null)
|
||||
const heroImage = computed(() => cloudType.value?.icon_id ? imageUrl(cloudType.value.icon_id, 'original') : null)
|
||||
|
||||
function formatDateTime(iso: string | null) {
|
||||
if (!iso) return '未记录拍摄时间'
|
||||
@@ -86,11 +86,15 @@ watch(() => route.params.id, () => loadPage())
|
||||
<div class="grid lg:grid-cols-[1.05fr_0.95fr]">
|
||||
<div class="relative min-h-80 bg-sky-50">
|
||||
<img v-if="heroImage" :src="heroImage" :alt="cloudType.name" class="absolute inset-0 h-full w-full object-cover" />
|
||||
<div class="absolute inset-0 bg-gradient-to-t from-slate-950/75 via-slate-950/10 to-transparent"></div>
|
||||
<div class="absolute bottom-7 left-7 right-7 text-white">
|
||||
<span class="border border-white/35 bg-slate-950/25 px-2.5 py-1 text-xs backdrop-blur">稀有度 {{ cloudType.rarity_value }}</span>
|
||||
<div v-else class="absolute inset-0 flex items-center justify-center pb-20 text-sm font-medium text-slate-500">无图片</div>
|
||||
<div v-if="heroImage" class="absolute inset-0 bg-gradient-to-t from-slate-950/75 via-slate-950/10 to-transparent"></div>
|
||||
<div class="absolute bottom-7 left-7 right-7" :class="heroImage ? 'text-white' : 'text-slate-900'">
|
||||
<span
|
||||
class="border px-2.5 py-1 text-xs"
|
||||
:class="heroImage ? 'border-white/35 bg-slate-950/25 backdrop-blur' : 'border-slate-200 bg-white'"
|
||||
>稀有度 {{ cloudType.rarity_value }}</span>
|
||||
<h1 class="mt-4 text-4xl font-bold">{{ cloudType.name }}</h1>
|
||||
<p class="mt-2 text-white/80">{{ cloudType.genus || '未提供云属名称' }}</p>
|
||||
<p class="mt-2" :class="heroImage ? 'text-white/80' : 'text-slate-600'">{{ cloudType.genus || '未提供云属名称' }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-8">
|
||||
|
||||
@@ -2,11 +2,16 @@
|
||||
import { onMounted } from 'vue'
|
||||
import { NEmpty, NSkeleton } from 'naive-ui'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { imageUrl } from '@/lib/api'
|
||||
import { useEncyclopediaStore } from '@/stores/encyclopedia'
|
||||
|
||||
const router = useRouter()
|
||||
const encyclopediaStore = useEncyclopediaStore()
|
||||
|
||||
function typeImageUrl(iconId: string | null) {
|
||||
return iconId ? imageUrl(iconId, 'preview') : ''
|
||||
}
|
||||
|
||||
onMounted(() => encyclopediaStore.fetchCloudTypes())
|
||||
</script>
|
||||
|
||||
@@ -24,10 +29,8 @@ onMounted(() => encyclopediaStore.fetchCloudTypes())
|
||||
|
||||
<div class="oc-container oc-container--content oc-page-content">
|
||||
<div v-if="encyclopediaStore.loadingCloudTypes" class="grid gap-5 md:grid-cols-2 lg:grid-cols-3">
|
||||
<div v-for="n in 6" :key="n" class="oc-panel-card border border-slate-200 bg-white p-5">
|
||||
<NSkeleton class="h-6 w-2/5" />
|
||||
<NSkeleton class="mt-3 h-4 w-1/3" />
|
||||
<NSkeleton class="mt-5 h-4 w-full" :repeat="3" />
|
||||
<div v-for="n in 6" :key="n" class="oc-panel-card overflow-hidden border border-slate-200 bg-white">
|
||||
<NSkeleton class="h-80 w-full" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -36,25 +39,48 @@ onMounted(() => encyclopediaStore.fetchCloudTypes())
|
||||
v-for="cloudType in encyclopediaStore.cloudTypes"
|
||||
:key="cloudType.id"
|
||||
type="button"
|
||||
class="oc-interactive-card oc-panel-card flex h-full flex-col border border-slate-200 bg-white p-5 text-left"
|
||||
class="oc-interactive-card oc-panel-card relative isolate min-h-80 overflow-hidden border border-slate-200 bg-sky-50 text-left"
|
||||
@click="router.push(`/encyclopedia/${cloudType.id}`)"
|
||||
>
|
||||
<div class="flex items-start justify-between gap-4">
|
||||
<div>
|
||||
<p class="oc-section-label">Cloud Genus</p>
|
||||
<h2 class="mt-2 text-xl font-bold text-slate-900">{{ cloudType.name }}</h2>
|
||||
<p class="mt-1 font-mono text-xs uppercase tracking-[0.12em] text-slate-500">
|
||||
{{ cloudType.genus || '未提供云属名称' }}
|
||||
</p>
|
||||
<img
|
||||
v-if="cloudType.icon_id"
|
||||
:src="typeImageUrl(cloudType.icon_id)"
|
||||
:alt="`${cloudType.name}介绍图`"
|
||||
class="absolute inset-0 -z-20 h-full w-full object-cover"
|
||||
/>
|
||||
<div
|
||||
v-if="cloudType.icon_id"
|
||||
class="absolute inset-0 -z-10 bg-gradient-to-t from-slate-950/90 via-slate-950/55 to-slate-950/25"
|
||||
></div>
|
||||
<div v-else class="absolute inset-0 -z-10 flex items-center justify-center text-sm font-medium text-slate-500">无图片</div>
|
||||
|
||||
<div class="flex min-h-80 flex-col p-5">
|
||||
<div class="flex items-start justify-between gap-4">
|
||||
<div>
|
||||
<p class="oc-section-label" :class="cloudType.icon_id ? 'text-white/70' : 'text-slate-500'">Cloud Genus</p>
|
||||
<h2 class="mt-2 text-xl font-bold" :class="cloudType.icon_id ? 'text-white' : 'text-slate-900'">{{ cloudType.name }}</h2>
|
||||
<p
|
||||
class="mt-1 font-mono text-xs uppercase tracking-[0.12em]"
|
||||
:class="cloudType.icon_id ? 'text-white/75' : 'text-slate-500'"
|
||||
>
|
||||
{{ cloudType.genus || '未提供云属名称' }}
|
||||
</p>
|
||||
</div>
|
||||
<span
|
||||
class="shrink-0 border px-2.5 py-1 text-xs font-medium"
|
||||
:class="cloudType.icon_id ? 'border-white/35 bg-slate-950/25 text-white backdrop-blur' : 'border-slate-200 bg-white text-slate-600'"
|
||||
>
|
||||
稀有度 {{ cloudType.rarity_value }}
|
||||
</span>
|
||||
</div>
|
||||
<span class="shrink-0 border border-slate-200 bg-slate-50 px-2.5 py-1 text-xs font-medium text-slate-600">
|
||||
稀有度 {{ cloudType.rarity_value }}
|
||||
</span>
|
||||
<p class="mt-auto line-clamp-3 pt-16 text-sm leading-6" :class="cloudType.icon_id ? 'text-white/85' : 'text-slate-600'">
|
||||
{{ cloudType.description || '暂未提供识别说明。' }}
|
||||
</p>
|
||||
<p
|
||||
class="mt-4 border-t pt-4 text-xs font-semibold"
|
||||
:class="cloudType.icon_id ? 'border-white/25 text-white' : 'border-slate-200 text-sky-700'"
|
||||
>查看类型资料与公开云图 →</p>
|
||||
</div>
|
||||
<p class="mt-5 line-clamp-3 text-sm leading-6 text-slate-600">
|
||||
{{ cloudType.description || '暂未提供识别说明。' }}
|
||||
</p>
|
||||
<p class="mt-auto border-t border-slate-200 pt-4 text-xs font-semibold text-sky-700">查看类型资料与公开云图 →</p>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user