ylj20011123 35e40eb558 update
2026-02-28 18:25:12 +08:00

394 lines
12 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">
<!-- 活动列表 -->
<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>