394 lines
12 KiB
Vue
394 lines
12 KiB
Vue
<template>
|
||
<div class="event-list-page">
|
||
<!-- 活动列表 -->
|
||
<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">
|
||
<swiper>
|
||
<swiper-item v-for="(item, imgIndex) in event.ImageList" :key="imgIndex">
|
||
<image class="cover-image" :src="item.ImageUrl" mode="aspectFill" />
|
||
</swiper-item>
|
||
</swiper>
|
||
|
||
<div class="event-status" :class="event._activityStatus.cssClass">
|
||
{{ event._activityStatus.text }}
|
||
</div>
|
||
</div>
|
||
|
||
<div class="event-content">
|
||
<div class="event-title">{{ event.ACTIVITY_NAME }}</div>
|
||
|
||
<div class="event-info">
|
||
<div class="info-item">
|
||
<span class="info-icon">📅</span>
|
||
<span class="info-text">{{ event.ACTIVITY_STARTDATE ? event.ACTIVITY_STARTDATE : ""
|
||
}}{{ event.ACTIVITY_ENDDATE ? `-` + event.ACTIVITY_ENDDATE : "" }}</span>
|
||
</div>
|
||
<div class="info-item">
|
||
<span class="info-icon">📝</span>
|
||
<span class="info-text">报名:{{ event.SIGNUP_STARTDATE ? event.SIGNUP_STARTDATE : ""
|
||
}}{{ event.SIGNUP_ENDDATE ? `-` + event.SIGNUP_ENDDATE : "" }}</span>
|
||
</div>
|
||
<div class="info-item">
|
||
<span class="info-icon">📍</span>
|
||
<span class="info-text">{{ event.ACTIVITY_LOCATION }}</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="event-footer" v-if="Number(event.ACTIVITY_TYPE) === 1000">
|
||
<div class="participation-info">
|
||
<div class="current-participants">
|
||
已报名:{{ event.currentParticipants || 0 }}人
|
||
</div>
|
||
<div class="max-participants">
|
||
限:{{ event.MAXIMUM_CAPACITY ? event.MAXIMUM_CAPACITY : '不限' }}人
|
||
</div>
|
||
</div>
|
||
<div :class="['action-btn', event._signupStatus.btnClass]">{{ event._signupStatus.text || '立即报名' }}</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 {
|
||
eventsList: [],
|
||
};
|
||
},
|
||
onLoad() {
|
||
this.loadEventsList();
|
||
},
|
||
onPullDownRefresh() {
|
||
this.loadEventsList();
|
||
},
|
||
methods: {
|
||
// 加载活动列表
|
||
async loadEventsList() {
|
||
const req = {
|
||
SearchParameter: {
|
||
// ACTIVITY_ENDDATE_Start: params.ACTIVITY_ENDDATE_Start,
|
||
// ACTIVITY_STARTDATE_End: params.ACTIVITY_STARTDATE_End,
|
||
// SERVERPART_IDS: params?.SERVERPART_IDS,
|
||
PROVINCE_CODE: "530000",
|
||
ACTIVITY_STATES: 1
|
||
},
|
||
PageIndex: 1,
|
||
PageSize: 999999,
|
||
type: 'encryption'
|
||
}
|
||
|
||
uni.showLoading({
|
||
title: '加载中...',
|
||
mask: true
|
||
});
|
||
|
||
const data = await this.$api.$posMemberPost("/Member/GetACTIVITYList", req)
|
||
|
||
uni.hideLoading();
|
||
let list = data.Result_Data.List
|
||
const nowTime = new Date().getTime();
|
||
this.eventsList = list.map(item => {
|
||
// 1. 活动状态 (针对活动本身的执行时间)
|
||
let activityStatus = { text: '进行中', cssClass: 'status-active' };
|
||
const actStart = item.ACTIVITY_STARTDATE ? new Date(item.ACTIVITY_STARTDATE.replace(/-/g, '/')).getTime() : 0;
|
||
const actEnd = item.ACTIVITY_ENDDATE ? new Date(item.ACTIVITY_ENDDATE.replace(/-/g, '/')).getTime() : 0;
|
||
|
||
if (actEnd > 0 && actEnd < nowTime) {
|
||
activityStatus = { text: '已结束', cssClass: 'status-ended' };
|
||
} else if (actStart > 0 && actStart > nowTime) {
|
||
activityStatus = { text: '未开始', cssClass: 'status-unstarted' };
|
||
} else {
|
||
activityStatus = { text: '进行中', cssClass: 'status-active' };
|
||
}
|
||
|
||
// 2. 报名状态 (针对报名操作的时间和名额)
|
||
let signupStatus = { text: '立即报名', btnClass: 'action-normal' };
|
||
const signStart = item.SIGNUP_STARTDATE ? new Date(item.SIGNUP_STARTDATE.replace(/-/g, '/')).getTime() : 0;
|
||
const signEnd = item.SIGNUP_ENDDATE ? new Date(item.SIGNUP_ENDDATE.replace(/-/g, '/')).getTime() : 0;
|
||
const isFull = item.MAXIMUM_CAPACITY && Number(item.currentParticipants || 0) >= Number(item.MAXIMUM_CAPACITY);
|
||
|
||
if (signEnd > 0 && signEnd < nowTime) {
|
||
signupStatus = { text: '报名已截止', btnClass: 'action-disabled' };
|
||
} else if (signStart > 0 && signStart > nowTime) {
|
||
signupStatus = { text: '报名未开始', btnClass: 'action-disabled' };
|
||
} else if (isFull) {
|
||
signupStatus = { text: '已满额', btnClass: 'action-full' };
|
||
} else {
|
||
signupStatus = { text: '立即报名', btnClass: 'action-normal' };
|
||
}
|
||
|
||
return { ...item, _activityStatus: activityStatus, _signupStatus: signupStatus };
|
||
});
|
||
console.log('活动列表sda', this.eventsList);
|
||
},
|
||
|
||
// 跳转到活动详情
|
||
goToDetail(event) {
|
||
if (Number(event.ACTIVITY_TYPE) === 1000 || Number(event.ACTIVITY_TYPE) === 3000) {
|
||
uni.navigateTo({
|
||
url: `/pages/eventRegistration/detail?id=${event.ACTIVITY_ID}`
|
||
});
|
||
} else {
|
||
let currentService = uni.getStorageSync("currentService");
|
||
uni.navigateTo({
|
||
url: `/pages/shopMallPage/shopType/index?selectIndex=3&comeForm=serviceDetail&comeService=${this.processString(currentService.SERVERPART_NAME)}`,
|
||
});
|
||
}
|
||
},
|
||
processString(inputString) {
|
||
// 定义要检查的关键字
|
||
const keywords = ['服务区', '停车区', '加水站', '加油站', '观景台', '休息区'];
|
||
|
||
// 遍历关键字,检查是否包含在字符串中
|
||
for (let keyword of keywords) {
|
||
const index = inputString.indexOf(keyword);
|
||
if (index !== -1) {
|
||
// 截取关键字之前的部分
|
||
return inputString.substring(0, index);
|
||
}
|
||
}
|
||
|
||
// 如果没有找到任何关键字,返回原始字符串
|
||
return inputString;
|
||
},
|
||
// 获取活动状态文本
|
||
getStatusText(status) {
|
||
const start = status.SIGNUP_STARTDATE || status.ACTIVITY_STARTDATE;
|
||
const end = status.SIGNUP_ENDDATE || status.ACTIVITY_ENDDATE;
|
||
const now = new Date().getTime();
|
||
const startTime = start ? new Date(start.replace(/-/g, '/')).getTime() : 0;
|
||
const endTime = end ? new Date(end.replace(/-/g, '/')).getTime() : 0;
|
||
|
||
if (endTime > 0 && endTime < now) {
|
||
return '已结束报名'
|
||
} else if (startTime > 0 && startTime > now) {
|
||
return '未开始'
|
||
} else {
|
||
return '报名中'
|
||
}
|
||
}
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<style scoped lang="less">
|
||
.event-list-page {
|
||
width: 100vw;
|
||
min-height: 100vh;
|
||
background: #f8f8f8;
|
||
overflow-y: auto;
|
||
|
||
.events-section {
|
||
width: 100%;
|
||
box-sizing: border-box;
|
||
padding: 32rpx;
|
||
|
||
.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: 10rpx 24rpx;
|
||
border-radius: 20rpx;
|
||
font-size: 22rpx;
|
||
font-weight: 600;
|
||
letter-spacing: 2rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
|
||
&.status-active {
|
||
background: linear-gradient(135deg, #22c55e 0%, #16a34a 100%);
|
||
color: white;
|
||
}
|
||
|
||
&.status-ended,
|
||
&.status-unstarted {
|
||
background: linear-gradient(135deg, #9ca3af 0%, #6b7280 100%);
|
||
color: white;
|
||
}
|
||
|
||
&.status-full {
|
||
background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);
|
||
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;
|
||
border: none;
|
||
|
||
&:active {
|
||
opacity: 0.9;
|
||
}
|
||
}
|
||
|
||
&.action-full {
|
||
background: linear-gradient(135deg, #ef4444, #dc2626);
|
||
color: white;
|
||
border: none;
|
||
}
|
||
|
||
&.action-disabled {
|
||
background: linear-gradient(135deg, #9ca3af, #6b7280);
|
||
color: white;
|
||
border: none;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.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;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
@keyframes breathing {
|
||
0% {
|
||
opacity: 0.9;
|
||
transform: scale(1);
|
||
}
|
||
|
||
50% {
|
||
opacity: 1;
|
||
transform: scale(1.05);
|
||
}
|
||
|
||
100% {
|
||
opacity: 0.9;
|
||
transform: scale(1);
|
||
}
|
||
}
|
||
|
||
.event-list-page::-webkit-scrollbar {
|
||
display: none;
|
||
}
|
||
</style> |