2025-10-21 18:44:42 +08:00

396 lines
10 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="event-list-page" :style="{ paddingBottom: `${safeHeight}px` }">
<!-- 活动列表 -->
<div class="events-section">
<div class="events-list" v-if="eventsList.length > 0">
<div class="event-item" v-for="(event, index) in eventsList" :key="index" @click="goToDetail(event)">
<div class="event-cover">
<image class="cover-image" :src="event.coverImage || defaultCover" mode="aspectFill" />
<div class="event-status" :class="[
event.status === 'active' ? 'status-active' :
(event.status === 'ended' ? 'status-ended' : 'status-draft')
]">
{{ getStatusText(event.status) }}
</div>
</div>
<div class="event-content">
<div class="event-title">{{ event.eventName }}</div>
<div class="event-info">
<div class="info-item">
<span class="info-icon">📅</span>
<span class="info-text">{{ formatDateTime(event.eventTime) }}</span>
</div>
<div class="info-item">
<span class="info-icon">📍</span>
<span class="info-text">{{ event.eventLocation }}</span>
</div>
</div>
<div class="event-footer">
<div class="participation-info">
<div class="current-participants">
已报名{{ event.currentParticipants || 0 }}
</div>
<div class="max-participants">
{{ event.maxParticipants || '不限' }}
</div>
</div>
<div class="action-btn" :class="[
event.status === 'ended' ? 'action-disabled' :
(isEventFull(event) ? 'action-full' :
(hasUserRegistered(event) ? 'action-registered' : 'action-normal'))
]">
{{ getActionText(event) }}
</div>
</div>
</div>
</div>
</div>
<!-- 空状态 -->
<div class="empty-state" v-else>
<div class="empty-icon">📅</div>
<div class="empty-title">暂无活动</div>
<div class="empty-desc">敬请期待更多精彩活动</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
safeHeight: "",
eventsList: [],
defaultCover: 'https://picsum.photos/seed/event-default/400/300.jpg'
};
},
onLoad() {
let systemInfo = uni.getSystemInfoSync();
let height = systemInfo.safeAreaInsets.bottom;
this.safeHeight = Number(height);
this.loadEventsList();
},
onPullDownRefresh() {
this.loadEventsList();
},
onReachBottom() {
this.loadMoreEvents();
},
methods: {
// 加载活动列表
async loadEventsList() {
try {
// 这里调用实际接口获取活动列表
// const res = await this.$api.getEventsList({
// page: 1,
// pageSize: 10,
// status: 'active' // 只获取活动中的活动
// });
// 模拟数据
const mockData = [
{
id: 1,
eventName: "春季音乐节",
eventContent: "春暖花开,音乐与美好相遇",
eventLocation: "昆明市中心广场",
eventTime: "2024-03-15 19:00:00",
maxParticipants: 500,
currentParticipants: 280,
status: "active", // active, ended, draft
coverImage: "https://picsum.photos/seed/music-festival/400/300.jpg"
},
{
id: 2,
eventName: "亲子手工DIY活动",
eventContent: "和孩子一起创造美好回忆",
eventLocation: "青少年活动中心",
eventTime: "2024-03-20 14:00:00",
maxParticipants: 100,
currentParticipants: 65,
status: "active",
coverImage: "https://picsum.photos/seed/diy-activity/400/300.jpg"
},
{
id: 3,
eventName: "健康讲座",
eventContent: "专家分享健康养生知识",
eventLocation: "社区文化中心",
eventTime: "2024-02-28 09:00:00",
maxParticipants: 200,
currentParticipants: 200,
status: "ended",
coverImage: "https://picsum.photos/seed/health-lecture/400/300.jpg"
}
];
this.eventsList = mockData;
uni.stopPullDownRefresh();
} catch (error) {
console.error('加载活动列表失败:', error);
uni.showToast({
title: '加载失败,请重试',
icon: 'none'
});
uni.stopPullDownRefresh();
}
},
// 加载更多活动
loadMoreEvents() {
// 实现加载更多逻辑
console.log('加载更多活动');
},
// 跳转到活动详情
goToDetail(event) {
uni.navigateTo({
url: `/pages/eventRegistration/detail?id=${event.id}`
});
},
// 格式化日期时间
formatDateTime(dateTime) {
if (!dateTime) return '';
try {
const date = new Date(dateTime);
const month = date.getMonth() + 1;
const day = date.getDate();
const hours = date.getHours().toString().padStart(2, '0');
const minutes = date.getMinutes().toString().padStart(2, '0');
return `${month}${day}${hours}:${minutes}`;
} catch (error) {
return dateTime;
}
},
// 获取活动状态文本
getStatusText(status) {
const statusMap = {
'active': '报名中',
'ended': '已结束',
'draft': '筹备中'
};
return statusMap[status] || '报名中';
},
// 获取按钮文本
getActionText(event) {
if (event.status === 'ended') return '已结束';
if (this.isEventFull(event)) return '已满员';
if (this.hasUserRegistered(event)) return '已报名';
return '立即报名';
},
// 判断活动是否已满员
isEventFull(event) {
if (!event.maxParticipants) return false;
return event.currentParticipants >= event.maxParticipants;
},
// 判断用户是否已报名(实际项目中需要从接口获取)
hasUserRegistered(event) {
// 这里应该调用接口检查用户是否已报名该活动
return false;
}
}
};
</script>
<style scoped lang="less">
.event-list-page {
width: 100vw;
min-height: 100vh;
background: #f8f8f8;
overflow-y: scroll;
.events-section {
padding: 60rpx 32rpx 40rpx;
.events-list {
.event-item {
background: white;
border-radius: 24rpx;
margin-bottom: 32rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.08);
overflow: hidden;
transition: all 0.3s ease;
&:active {
transform: scale(0.98);
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.12);
}
.event-cover {
position: relative;
width: 100%;
height: 300rpx;
overflow: hidden;
.cover-image {
width: 100%;
height: 100%;
object-fit: cover;
}
.event-status {
position: absolute;
top: 20rpx;
right: 20rpx;
padding: 12rpx 24rpx;
border-radius: 20rpx;
font-size: 24rpx;
font-weight: 500;
&.status-active {
background: rgba(34, 197, 94, 0.9);
color: white;
}
&.status-ended {
background: rgba(107, 114, 128, 0.9);
color: white;
}
&.status-draft {
background: rgba(251, 146, 60, 0.9);
color: white;
}
}
}
.event-content {
padding: 16rpx 24rpx;
.event-title {
font-size: 28rpx;
font-weight: 600;
color: #1f2937;
line-height: 1.4;
margin-bottom: 24rpx;
}
.event-info {
margin-bottom: 16rpx;
.info-item {
display: flex;
align-items: center;
margin-bottom: 16rpx;
&:last-child {
margin-bottom: 0;
}
.info-icon {
font-size: 24rpx;
margin-right: 12rpx;
width: 32rpx;
text-align: center;
}
.info-text {
font-size: 24rpx;
color: #6b7280;
line-height: 1.4;
}
}
}
.event-footer {
display: flex;
justify-content: space-between;
align-items: center;
padding-top: 16rpx;
border-top: 1rpx solid #f0f0f0;
.participation-info {
.current-participants {
font-size: 24rpx;
color: #374151;
margin-bottom: 8rpx;
}
.max-participants {
font-size: 24rpx;
color: #9ca3af;
}
}
.action-btn {
padding: 16rpx 32rpx;
border-radius: 40rpx;
font-size: 24rpx;
font-weight: 500;
transition: all 0.3s ease;
&.action-normal {
background: linear-gradient(135deg, #22c55e, #16a34a);
color: white;
&:active {
opacity: 0.9;
}
}
&.action-registered {
background: #dcfce7;
color: #15803d;
border: 2rpx solid #bbf7d0;
}
&.action-full {
background: #f3f4f6;
color: #9ca3af;
border: 2rpx solid #e5e7eb;
}
&.action-disabled {
background: #f9fafb;
color: #d1d5db;
border: 2rpx solid #f3f4f6;
}
}
}
}
}
}
.empty-state {
text-align: center;
padding: 200rpx 40rpx;
.empty-icon {
font-size: 120rpx;
margin-bottom: 32rpx;
opacity: 0.3;
}
.empty-title {
font-size: 32rpx;
color: #6b7280;
margin-bottom: 16rpx;
font-weight: 500;
}
.empty-desc {
font-size: 26rpx;
color: #9ca3af;
line-height: 1.5;
}
}
}
}
.event-list-page::-webkit-scrollbar {
display: none;
}
</style>