| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 |
- <template>
- <div class="home-page with-bottom-nav">
- <div class="hero-section">
- <h1 class="hero-title">许愿树 ✨</h1>
- <p class="hero-sub">找到你身边的许愿树,记录美好心愿</p>
- <div class="location-bar">
- <van-icon name="location-o" />
- <span v-if="locating">正在获取位置...</span>
- <span v-else-if="locationStore.located">
- 已定位 · 附近 {{ nearby.length }} 棵许愿树
- </span>
- <span v-else>定位失败,显示全部许愿树</span>
- </div>
- </div>
- <van-pull-refresh v-if="!locating" v-model="refreshing" @refresh="onRefresh">
- <van-list
- v-model:loading="loading"
- :finished="finished"
- finished-text="已经找到所有许愿树啦 ✨"
- @load="loadTrees"
- >
- <tree-card
- v-for="tree in nearby"
- :key="tree.id"
- :tree="tree"
- @click="goTree(tree.id)"
- />
- </van-list>
- </van-pull-refresh>
- <div class="empty-hint" v-if="!loading && nearby.length === 0">
- <van-empty description="附近暂无许愿树" />
- </div>
- </div>
- </template>
- <script setup lang="ts">
- import {onMounted, onUnmounted, ref} from 'vue'
- import {useRouter} from 'vue-router'
- import {useLocationStore} from '@/stores/location'
- import {fetchNearbyTrees} from '@/api/tree'
- import TreeCard from '@/components/TreeCard.vue'
- const router = useRouter()
- const locationStore = useLocationStore()
- const nearby = ref<any[]>([])
- const loading = ref(false)
- const finished = ref(false)
- const refreshing = ref(false)
- const locating = ref(true)
- async function loadTrees() {
- loading.value = true
- try {
- const result = await fetchNearbyTrees(
- locationStore.lng || 116.4074,
- locationStore.lat || 39.9042,
- 50000
- )
- nearby.value = result
- finished.value = true
- } catch {
- finished.value = true // 请求失败后停止,不再重试
- } finally {
- loading.value = false
- refreshing.value = false
- }
- }
- async function onRefresh() {
- refreshing.value = true
- await locationStore.refreshLocation()
- finished.value = false
- await loadTrees()
- }
- function goTree(id: number) {
- router.push(`/tree/${id}`)
- }
- /*const goTrees = (id: number) => {
- return router.push(`/tree/${id}`)
- }*/
- onMounted(async () => {
- locationStore.startWatch(5000)
- // 等待首次定位
- if (!locationStore.located) {
- await new Promise<void>((resolve) => {
- const check = setInterval(() => {
- if (locationStore.located) {
- clearInterval(check)
- resolve()
- }
- }, 200)
- })
- }
- locating.value = false
- })
- onUnmounted(() => {
- locationStore.stopWatch()
- })
- </script>
- <style scoped>
- .home-page {
- min-height: 100vh;
- background: #f7f8fa;
- }
- .hero-section {
- background: linear-gradient(135deg, #07c160, #05a650);
- padding: 30px 20px 20px;
- color: #fff;
- text-align: center;
- }
- .hero-title {
- font-size: 28px;
- font-weight: 700;
- margin-bottom: 6px;
- }
- .hero-sub {
- font-size: 14px;
- opacity: 0.85;
- margin-bottom: 16px;
- }
- .location-bar {
- display: inline-flex;
- align-items: center;
- gap: 6px;
- background: rgba(255,255,255,0.2);
- border-radius: 20px;
- padding: 6px 16px;
- font-size: 12px;
- }
- .empty-hint {
- padding-top: 60px;
- }
- </style>
|