index.vue
3.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
<template>
<view class="min-h-screen flex flex-col bg-white">
<AppHeader title="城市漫步" :showBack="false" />
<!-- Map container -->
<view class="flex-1 relative">
<Map
class="w-full h-full"
:longitude="121.47"
:latitude="31.23"
:scale="15"
:markers="markers"
@markertap="onMarkerTap"
/>
</view>
<!-- Check-in point detail modal -->
<view v-if="showModal && selectedPoint" class="fixed inset-0 bg-black bg-opacity-50 flex items-end justify-center z-20">
<view class="bg-white rounded-t-2xl w-full max-h-[80%] overflow-y-auto">
<view class="relative h-64 overflow-hidden">
<image :src="selectedPoint.image" :alt="selectedPoint.name" class="w-full h-full object-cover" />
<button class="absolute top-4 right-4 bg-white rounded-full p-2" @click="showModal = false">
<Failure size="24" />
</button>
</view>
<view class="p-4">
<h2 class="text-2xl font-bold mb-2">{{ selectedPoint.name }}</h2>
<p class="text-gray-600 mb-6">{{ selectedPoint.description }}</p>
<button @click="handleCheckIn" :disabled="selectedPoint.isCheckedIn" :class="['w-full py-3 rounded-full text-white font-medium', selectedPoint.isCheckedIn ? 'bg-gray-400' : 'bg-blue-500']">
{{ selectedPoint.isCheckedIn ? '已打卡' : '打卡' }}
</button>
</view>
</view>
</view>
<!-- Check-in success message -->
<view v-if="showSuccess" class="fixed inset-0 flex items-center justify-center z-30 pointer-events-none">
<view class="bg-black bg-opacity-70 text-white px-6 py-4 rounded-lg flex items-center">
<Check size="24" class="text-green-400 mr-2" />
<span>打卡成功!</span>
</view>
</view>
<BottomNav />
</view>
</template>
<script setup>
import { ref, computed } from 'vue';
import AppHeader from '../../components/AppHeader.vue';
import BottomNav from '../../components/BottomNav.vue';
import { Failure, Check } from '@nutui/icons-vue-taro';
const selectedPoint = ref(null);
const showModal = ref(false);
const showSuccess = ref(false);
const checkInPoints = ref([
{
id: 'yuyuan',
name: '豫园',
description: '豫园始建于1559年,是明代著名的私家园林,现为国家重点文物保护单位。园内亭台楼阁布局精巧,景色优美,是上海著名的旅游景点。',
latitude: 31.2271,
longitude: 121.4875,
iconPath: '/static/images/activities/marker.png',
width: 30,
height: 30,
image: "/static/images/activities/citywalk2_1.png",
isCheckedIn: false
},
{
id: 'jiuquqiao',
name: '九曲桥',
description: '豫园九曲桥位于上海城隍庙豫园内,是上海的标志性建筑之一。桥因始建于明代嘉靖、万历年间,九曲桥与荷花池在那时就已存在,最初为木桥。清朝隆年间进行过修建,上世纪20年代因火灾改建为水泥桥,解放后又恢复了石桥形式。',
latitude: 31.2275,
longitude: 121.4895,
iconPath: '/static/images/activities/marker.png',
width: 30,
height: 30,
image: "/static/images/activities/citywalk2_1.png",
isCheckedIn: false
}
]);
const markers = computed(() => checkInPoints.value.map(p => ({
id: p.id,
latitude: p.latitude,
longitude: p.longitude,
iconPath: p.iconPath,
width: p.width,
height: p.height,
})));
const onMarkerTap = (e) => {
const point = checkInPoints.value.find(p => p.id === e.detail.markerId);
if (point) {
selectedPoint.value = point;
showModal.value = true;
}
};
const handleCheckIn = () => {
if (selectedPoint.value) {
const index = checkInPoints.value.findIndex(p => p.id === selectedPoint.value.id);
if (index !== -1) {
checkInPoints.value[index].isCheckedIn = true;
}
showModal.value = false;
showSuccess.value = true;
setTimeout(() => {
showSuccess.value = false;
}, 2000);
}
};
</script>