feat(h5): 首页大类+种类浏览
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
eebd6825b9
commit
a136c3db85
|
|
@ -0,0 +1,9 @@
|
|||
<script setup>
|
||||
defineProps({ value: String, count: Number })
|
||||
</script>
|
||||
<template>
|
||||
<div class="relative px-4 py-3 rounded-card bg-white shadow-card active:bg-surface-warm cursor-pointer">
|
||||
<div class="font-medium truncate">{{ value }}</div>
|
||||
<div class="absolute top-2 right-3 text-xs text-muted tnum">{{ count }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<script setup>
|
||||
defineProps({ label: String, value: String, active: Boolean })
|
||||
</script>
|
||||
<template>
|
||||
<div class="aspect-square rounded-card shadow-card flex flex-col items-center justify-center transition active:scale-[0.98] cursor-pointer"
|
||||
:class="active ? 'bg-brand text-white' : 'bg-white text-neutral-800'">
|
||||
<div class="text-3xl font-semibold">{{ label.slice(0,1) }}</div>
|
||||
<div class="mt-2 text-sm">{{ label }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -1,2 +1,83 @@
|
|||
<script setup>defineOptions({ name: 'Home' })</script>
|
||||
<template><div class="p-4">Home 占位</div></template>
|
||||
<script setup>
|
||||
import { ref, onMounted, watch } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import MajorCategoryCard from '@/components/MajorCategoryCard.vue'
|
||||
import CategoryCard from '@/components/CategoryCard.vue'
|
||||
import Skeleton from '@/components/Skeleton.vue'
|
||||
import { useAuthStore } from '@/store/auth'
|
||||
import { useUiStore } from '@/store/ui'
|
||||
import { fetchCategoriesByMajor } from '@/api/material'
|
||||
|
||||
defineOptions({ name: 'Home' })
|
||||
const router = useRouter()
|
||||
const auth = useAuthStore()
|
||||
const ui = useUiStore()
|
||||
|
||||
const majors = [
|
||||
{ value: 'architecture', label: '建筑' },
|
||||
{ value: 'landscape', label: '景观' },
|
||||
{ value: 'equipment', label: '设备' },
|
||||
{ value: 'decoration', label: '装修' },
|
||||
]
|
||||
|
||||
const selected = ref(ui.selectedMajor)
|
||||
const categories = ref([])
|
||||
const loading = ref(false)
|
||||
|
||||
const loadCategories = async (major) => {
|
||||
if (!major) { categories.value = []; return }
|
||||
loading.value = true
|
||||
try { categories.value = await fetchCategoriesByMajor(major) }
|
||||
finally { loading.value = false }
|
||||
}
|
||||
|
||||
const onSelect = (v) => {
|
||||
selected.value = selected.value === v ? '' : v
|
||||
ui.setMajor(selected.value)
|
||||
}
|
||||
|
||||
watch(selected, loadCategories, { immediate: true })
|
||||
|
||||
onMounted(async () => {
|
||||
if (!auth.user) { try { await auth.loadUser() } catch {} }
|
||||
})
|
||||
|
||||
const goCategory = (c) => router.push({ name: 'CategoryDetail', params: { major: selected.value, category: c.value } })
|
||||
const onLogout = () => { auth.logout(); router.replace('/login') }
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="min-h-screen">
|
||||
<header class="h-12 px-4 flex items-center justify-between bg-white border-b border-line">
|
||||
<div class="text-sm text-muted">你好,<span class="text-neutral-800 font-medium">{{ auth.user?.username || '' }}</span></div>
|
||||
<button class="text-sm text-muted active:text-danger" @click="onLogout">退出</button>
|
||||
</header>
|
||||
|
||||
<section class="p-4 grid grid-cols-2 gap-3">
|
||||
<MajorCategoryCard v-for="m in majors" :key="m.value"
|
||||
:label="m.label" :value="m.value" :active="selected === m.value"
|
||||
@click="onSelect(m.value)" />
|
||||
</section>
|
||||
|
||||
<section class="px-4 pb-6">
|
||||
<transition name="fade">
|
||||
<div v-if="selected">
|
||||
<div class="text-xs text-muted mb-2">细分种类</div>
|
||||
<div v-if="loading" class="grid grid-cols-2 gap-3">
|
||||
<Skeleton v-for="n in 4" :key="n" class="h-14" />
|
||||
</div>
|
||||
<div v-else-if="categories.length" class="grid grid-cols-2 gap-3">
|
||||
<CategoryCard v-for="c in categories" :key="c.value" :value="c.value" :count="c.count" @click="goCategory(c)" />
|
||||
</div>
|
||||
<div v-else class="py-10 text-center text-sm text-muted">该大类暂无已审核材料</div>
|
||||
</div>
|
||||
<div v-else class="py-10 text-center text-sm text-muted">点击上方分类查看细分种类</div>
|
||||
</transition>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.fade-enter-active,.fade-leave-active{transition:all .2s ease}
|
||||
.fade-enter-from,.fade-leave-to{opacity:0;transform:translateY(-4px)}
|
||||
</style>
|
||||
|
|
|
|||
Loading…
Reference in New Issue