hookehuyr

feat(ActivityCard): 添加活动状态标签和动态样式

在ActivityCard组件中新增活动状态标签,根据活动时间动态显示不同状态(如“报名中”、“进行中”等),并为其设置相应的背景和文字颜色。同时优化了活动地点的显示逻辑,支持线上活动的显示。
<!--
* @Date: 2025-04-17 13:16:20
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-04-17 13:16:22
* @FilePath: /reading-club-app/src/components/shared/ActivityCard.vue
* @LastEditTime: 2025-04-21 10:26:22
* @FilePath: /mlaj-reading-club/src/components/shared/ActivityCard.vue
* @Description: 文件描述
-->
<template>
......@@ -16,7 +16,7 @@
:alt="activity.title"
class="absolute inset-0 h-full w-full object-cover"
/>
<div
<!-- <div
v-if="activity.tags && activity.tags.length"
class="absolute top-0 left-0 p-4 flex flex-wrap gap-2"
>
......@@ -27,6 +27,12 @@
>
{{ tag }}
</span>
</div> -->
<div class="absolute top-2 left-2">
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium"
:class="statusBadgeClass">
{{ statusText }}
</span>
</div>
</div>
......@@ -46,7 +52,7 @@
<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>
<span>{{activity.activity_type === 'online' ? '线上活动' : (activity.location ? (typeof activity.location === 'object' ? activity.location.name : activity.location) : '地点未设置')}}</span>
</div>
<div class="flex items-center justify-between">
......@@ -67,7 +73,7 @@
</template>
<script setup>
import { defineProps } from 'vue'
import { ref, computed, defineProps } from 'vue'
const props = defineProps({
activity: {
......@@ -78,7 +84,7 @@ const props = defineProps({
// 格式化日期时间
const formatDateTime = (dateTimeStr) => {
const date = new Date(dateTimeStr.replace(' ', 'T'))
const date = new Date(dateTimeStr)
return new Intl.DateTimeFormat('zh-CN', {
year: 'numeric',
month: 'long',
......@@ -87,4 +93,45 @@ const formatDateTime = (dateTimeStr) => {
minute: '2-digit'
}).format(date)
}
// Calculate if registration is still open
const now = new Date();
const registrationStart = new Date(props.activity.registration_start);
const registrationEnd = new Date(props.activity.registration_end);
const activityStart = new Date(props.activity.start_time);
const isRegistrationOpen = ref(now >= registrationStart && now <= registrationEnd);
const isUpcoming = ref(now < activityStart);
const isPast = ref(now > new Date(props.activity.end_time));
const isOngoing = ref(!isUpcoming && !isPast);
// Calculate capacity percentage
const capacityPercentage = Math.min((props.activity.participant_count / props.activity.max_participants) * 100, 100);
// Dynamically set status badge colors
const statusBadgeClass = computed(() => {
if (isPast.value) {
return 'bg-gray-100 text-gray-800';
} else if (isOngoing.value) {
return 'bg-green-100 text-green-800';
} else if (isRegistrationOpen.value) {
return 'bg-blue-100 text-blue-800';
} else if (isUpcoming.value && !isRegistrationOpen.value) {
return 'bg-yellow-100 text-yellow-800';
}
return '';
});
const statusText = computed(() => {
if (isPast.value) {
return '已结束';
} else if (isOngoing.value) {
return '进行中';
} else if (isRegistrationOpen.value) {
return '报名中';
} else if (isUpcoming.value && !isRegistrationOpen.value) {
return '即将开始';
}
return '';
});
</script>
......