396 lines
10 KiB
Vue
396 lines
10 KiB
Vue
<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> |