ActivityCard.vue 4.04 KB
<!--
 * @Date: 2025-03-20 20:36:36
 * @LastEditors: hookehuyr hookehuyr@gmail.com
 * @LastEditTime: 2025-03-21 15:37:21
 * @FilePath: /mlaj/src/components/ui/ActivityCard.vue
 * @Description: 文件描述
-->
<template>
  <router-link :to="`/activities/${activity.id}`">
    <FrostedGlass class="flex overflow-hidden rounded-xl shadow-sm">
      <!-- Activity Image -->
      <div class="w-1/3 h-28 relative">
        <img
          :src="activity.imageUrl"
          :alt="activity.title"
          class="w-full h-full object-cover"
        />
        <div v-if="activity.isHot" class="absolute top-0 left-0 bg-red-500 text-white text-xs px-2 py-0.5">
          热门
        </div>
      </div>

      <!-- Activity Info -->
      <div class="flex-1 p-3 flex flex-col justify-between">
        <div>
          <h3 class="font-medium text-base mb-1 line-clamp-1">{{ activity.title }}</h3>

          <!-- Status Tags -->
          <div class="flex items-center space-x-2 mb-1">
            <span :class="['px-2 py-0.5 rounded-full text-xs', getStatusClass(activity.status)]">
              {{ activity.status }}
            </span>
            <span v-if="activity.isFree" class="px-2 py-0.5 rounded-full text-xs bg-green-100 text-green-600">
              免费
            </span>
          </div>
        </div>

        <!-- Location and Time -->
        <div class="text-xs text-gray-500 space-y-1">
          <div class="flex items-center">
            <svg xmlns="http://www.w3.org/2000/svg" class="h-3.5 w-3.5 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
              <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z" />
              <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 11a3 3 0 11-6 0 3 3 0 016 0z" />
            </svg>
            <span>{{ activity.location }}</span>
          </div>

          <div class="flex items-center">
            <svg xmlns="http://www.w3.org/2000/svg" class="h-3.5 w-3.5 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
              <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
            </svg>
            <span>{{ activity.period }}</span>
          </div>
        </div>

        <!-- Bottom Info Section -->
        <div class="mt-1 flex items-center justify-between">
          <div v-if="activity.price" class="flex items-baseline">
            <span class="text-red-500 font-medium">¥{{ activity.price }}</span>
            <span v-if="activity.originalPrice" class="text-xs text-gray-400 ml-1 line-through">¥{{ activity.originalPrice }}</span>
          </div>
          <div v-else></div>

          <div class="flex items-center text-xs text-gray-500">
            <svg xmlns="http://www.w3.org/2000/svg" class="h-3.5 w-3.5 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
              <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z" />
            </svg>
            <span>{{ activity.participantsCount || '15' }}/{{ activity.maxParticipants || '30' }}</span>
          </div>
        </div>
      </div>
    </FrostedGlass>
  </router-link>
</template>

<script setup>
import FrostedGlass from './FrostedGlass.vue'

defineProps({
  activity: {
    type: Object,
    required: true
  }
})

const getStatusClass = (status) => {
  switch (status) {
    case '活动中':
      return 'bg-blue-100 text-blue-600'
    case '进行中':
      return 'bg-green-100 text-green-600'
    case '即将开始':
      return 'bg-orange-100 text-orange-600'
    case '已结束':
      return 'bg-gray-100 text-gray-600'
    default:
      return 'bg-gray-100 text-gray-600'
  }
}
</script>