index.vue 3.93 KB
<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>