feat(h5): 首页默认展示全部大类的材料种类,未选中时分组列出
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
a084f5c7e0
commit
1a0af18457
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, watch } from 'vue'
|
import { ref, onMounted, computed, watch } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import MajorCategoryCard from '@/components/MajorCategoryCard.vue'
|
import MajorCategoryCard from '@/components/MajorCategoryCard.vue'
|
||||||
import CategoryCard from '@/components/CategoryCard.vue'
|
import CategoryCard from '@/components/CategoryCard.vue'
|
||||||
|
|
@ -21,14 +21,17 @@ const majors = [
|
||||||
]
|
]
|
||||||
|
|
||||||
const selected = ref(ui.selectedMajor)
|
const selected = ref(ui.selectedMajor)
|
||||||
const categories = ref([])
|
const categoriesByMajor = ref({})
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
|
|
||||||
const loadCategories = async (major) => {
|
const loadAll = async () => {
|
||||||
if (!major) { categories.value = []; return }
|
|
||||||
loading.value = true
|
loading.value = true
|
||||||
try { categories.value = await fetchCategoriesByMajor(major) }
|
try {
|
||||||
finally { loading.value = false }
|
const results = await Promise.all(majors.map((m) => fetchCategoriesByMajor(m.value)))
|
||||||
|
const map = {}
|
||||||
|
majors.forEach((m, i) => { map[m.value] = results[i] })
|
||||||
|
categoriesByMajor.value = map
|
||||||
|
} finally { loading.value = false }
|
||||||
}
|
}
|
||||||
|
|
||||||
const onSelect = (v) => {
|
const onSelect = (v) => {
|
||||||
|
|
@ -36,13 +39,25 @@ const onSelect = (v) => {
|
||||||
ui.setMajor(selected.value)
|
ui.setMajor(selected.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(selected, loadCategories, { immediate: true })
|
const visibleGroups = computed(() => {
|
||||||
|
if (selected.value) {
|
||||||
|
return [{ major: majors.find((m) => m.value === selected.value), categories: categoriesByMajor.value[selected.value] || [] }]
|
||||||
|
}
|
||||||
|
return majors.map((m) => ({ major: m, categories: categoriesByMajor.value[m.value] || [] }))
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(selected, (v) => {
|
||||||
|
if (v && !categoriesByMajor.value[v]) {
|
||||||
|
fetchCategoriesByMajor(v).then((r) => { categoriesByMajor.value = { ...categoriesByMajor.value, [v]: r } })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
if (!auth.user) { try { await auth.loadUser() } catch {} }
|
if (!auth.user) { try { await auth.loadUser() } catch {} }
|
||||||
|
await loadAll()
|
||||||
})
|
})
|
||||||
|
|
||||||
const goCategory = (c) => router.push({ name: 'CategoryDetail', params: { major: selected.value, category: c.value } })
|
const goCategory = (major, c) => router.push({ name: 'CategoryDetail', params: { major, category: c.value } })
|
||||||
const onLogout = () => { auth.logout(); router.replace('/login') }
|
const onLogout = () => { auth.logout(); router.replace('/login') }
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
@ -59,20 +74,24 @@ const onLogout = () => { auth.logout(); router.replace('/login') }
|
||||||
@click="onSelect(m.value)" />
|
@click="onSelect(m.value)" />
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="px-4 pb-6">
|
<section class="px-4 pb-6 space-y-5">
|
||||||
<transition name="fade">
|
<div v-if="loading && !Object.keys(categoriesByMajor).length" class="grid grid-cols-2 gap-3">
|
||||||
<div v-if="selected">
|
<Skeleton v-for="n in 6" :key="n" class="h-14" />
|
||||||
<div class="text-xs text-muted mb-2">细分种类</div>
|
</div>
|
||||||
<div v-if="loading" class="grid grid-cols-2 gap-3">
|
|
||||||
<Skeleton v-for="n in 4" :key="n" class="h-14" />
|
<template v-else>
|
||||||
|
<div v-for="g in visibleGroups" :key="g.major.value">
|
||||||
|
<div class="flex items-center justify-between mb-2">
|
||||||
|
<div class="text-xs text-muted">{{ g.major.label }} · 材料种类</div>
|
||||||
|
<span class="text-[11px] text-muted tnum">{{ g.categories.length }} 类</span>
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="categories.length" class="grid grid-cols-2 gap-3">
|
<div v-if="g.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)" />
|
<CategoryCard v-for="c in g.categories" :key="c.value" :value="c.value" :count="c.count"
|
||||||
|
@click="goCategory(g.major.value, c)" />
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="py-10 text-center text-sm text-muted">该大类暂无已审核材料</div>
|
<div v-else class="py-6 text-center text-xs text-muted bg-white rounded-card">暂无已审核材料</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="py-10 text-center text-sm text-muted">点击上方分类查看细分种类</div>
|
</template>
|
||||||
</transition>
|
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue