600 lines
12 KiB
Vue
600 lines
12 KiB
Vue
<template>
|
|
<page-container title="福利屋" :showBack="true">
|
|
<banner :type-id="8" :height="328"></banner>
|
|
<view class="tab-container">
|
|
<view class="tab">
|
|
<view class="tab-item1 center" @click="$refs.rulePop.getRule(20, '规则说明')">
|
|
<text>规则说明</text>
|
|
</view>
|
|
<view class="tab-item2 center" :class="[tabCur == 1 ? 'act' : 'unact']" @click="tabChange(1)">
|
|
<text>进行中</text>
|
|
</view>
|
|
<view class="tab-item3 center" :class="[tabCur == 2 ? 'act' : 'unact']" @click="tabChange(2)">
|
|
<text>已结束</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 内容列表区域 -->
|
|
<view class="benefits-container">
|
|
<swiper class="benefits-swiper" :current="tabCur - 1" @change="handleSwiperChange">
|
|
<!-- 进行中列表 -->
|
|
<swiper-item>
|
|
<scroll-view scroll-y="true" class="benefits-scroll">
|
|
<template v-if="ongoingData.length > 0">
|
|
<view v-for="(item, index) in ongoingData" :key="index" class="benefit-item relative"
|
|
@click="goToDetail(item.id)">
|
|
<text class="benefit-title">{{ item.title }}</text>
|
|
<text class="benefit-tips">{{ item.tips }}</text>
|
|
|
|
<view class="action-btn center">
|
|
<text>马上参与</text>
|
|
</view>
|
|
<scroll-view scroll-x="true" class="goods-scroll">
|
|
<view v-for="(item1, index1) in item.GoodsList" :key="index1" class="goods-item relative">
|
|
<image class="goods-img" :src="item1.imgUrl">
|
|
</image>
|
|
<view class="goods-num center">
|
|
<text>x{{ item1.num }}</text>
|
|
</view>
|
|
</view>
|
|
</scroll-view>
|
|
<view class="divider"></view>
|
|
<view class="popularity center">
|
|
<image class="fire-icon" :src="$img1('checkin/Fire.png')"></image>
|
|
<text class="popularity-text">{{ item.Popularity }}</text>
|
|
</view>
|
|
|
|
<text class="time-text">{{ item.Time }}</text>
|
|
</view>
|
|
</template>
|
|
<template v-else>
|
|
<empty-state message="暂无进行中的活动"></empty-state>
|
|
</template>
|
|
</scroll-view>
|
|
</swiper-item>
|
|
|
|
<!-- 已结束列表 -->
|
|
<swiper-item>
|
|
<scroll-view scroll-y="true" class="benefits-scroll">
|
|
<template v-if="endedData.length > 0">
|
|
<view v-for="(item, index) in endedData" :key="index" class="benefit-item relative"
|
|
@click="goToDetail(item.id)">
|
|
<text class="benefit-title">{{ item.title }}</text>
|
|
<text class="benefit-tips">{{ item.tips }}</text>
|
|
|
|
<view class="action-btn center ended">
|
|
<text>已结束</text>
|
|
</view>
|
|
<scroll-view scroll-x="true" class="goods-scroll">
|
|
<view v-for="(item1, index1) in item.GoodsList" :key="index1" class="goods-item relative">
|
|
<image class="goods-img" :src="item1.imgUrl">
|
|
</image>
|
|
<view class="goods-num center">
|
|
<text>x{{ item1.num }}</text>
|
|
</view>
|
|
</view>
|
|
</scroll-view>
|
|
<view class="divider"></view>
|
|
<view class="popularity center">
|
|
<image class="fire-icon" :src="$img1('checkin/Fire.png')"></image>
|
|
<text class="popularity-text">{{ item.Popularity }}</text>
|
|
</view>
|
|
|
|
<text class="time-text">{{ item.Time }}</text>
|
|
</view>
|
|
</template>
|
|
<template v-else>
|
|
<empty-state message="暂无已结束的活动"></empty-state>
|
|
</template>
|
|
</scroll-view>
|
|
</swiper-item>
|
|
</swiper>
|
|
</view>
|
|
|
|
<view class="btn-group row center">
|
|
|
|
<view class="reward-record center" @click="$c.to({ url: '/pages/infinite/reward_records' })">
|
|
<text>赏品记录</text>
|
|
</view>
|
|
</view>
|
|
<rule-pop ref="rulePop"></rule-pop>
|
|
</page-container>
|
|
</template>
|
|
|
|
<script>
|
|
import { getWelfareHouseData } from '@/common/server/welfare.js';
|
|
import PageContainer from '@/components/page-container/page-container.vue'
|
|
import EmptyState from '@/components/empty-state/empty-state.vue'
|
|
|
|
export default {
|
|
components: {
|
|
PageContainer,
|
|
EmptyState
|
|
},
|
|
data() {
|
|
return {
|
|
tabCur: 1,
|
|
ongoingData: [], // 进行中数据
|
|
endedData: [], // 已结束数据
|
|
loading: false,
|
|
ongoingLoaded: false, // 进行中数据是否已加载
|
|
endedLoaded: false, // 已结束数据是否已加载
|
|
}
|
|
},
|
|
onShareAppMessage() {
|
|
let imageUrl = this.$config.getShareImageUrl();
|
|
return {
|
|
imageUrl: imageUrl,
|
|
title: this.$config.getAppSetting('share_title') || "哈尼盲盒上线,来就送!",
|
|
path: '/pages/infinite/index'
|
|
}
|
|
},
|
|
async onLoad() {
|
|
this.loadOngoingData();
|
|
},
|
|
|
|
methods: {
|
|
// 加载进行中的福利屋数据
|
|
async loadOngoingData() {
|
|
if (this.loading || this.ongoingLoaded) return;
|
|
this.loading = true;
|
|
|
|
try {
|
|
// API: fuliwu
|
|
const res = await getWelfareHouseData({ type: 1 });
|
|
|
|
if (res?.data?.data) {
|
|
this.ongoingData = this.formatBenefitsData(res.data.data);
|
|
this.ongoingLoaded = true;
|
|
}
|
|
} catch (error) {
|
|
console.error('加载进行中福利屋数据失败:', error);
|
|
} finally {
|
|
this.loading = false;
|
|
}
|
|
},
|
|
|
|
// 加载已结束的福利屋数据
|
|
async loadEndedData() {
|
|
if (this.loading || this.endedLoaded) return;
|
|
this.loading = true;
|
|
|
|
try {
|
|
// API: fuliwu
|
|
const res = await getWelfareHouseData({ type: 3 });
|
|
|
|
if (res?.data?.data) {
|
|
this.endedData = this.formatBenefitsData(res.data.data);
|
|
this.endedLoaded = true;
|
|
}
|
|
} catch (error) {
|
|
console.error('加载已结束福利屋数据失败:', error);
|
|
} finally {
|
|
this.loading = false;
|
|
}
|
|
},
|
|
|
|
// 格式化福利屋数据
|
|
formatBenefitsData(data) {
|
|
return data.map(item => {
|
|
const goodsList = [];
|
|
|
|
if (item.goodslist && item.goodslist.length) {
|
|
item.goodslist.forEach(goods => {
|
|
if (goods.stock > 0) {
|
|
goodsList.push({
|
|
imgUrl: goods.imgurl,
|
|
num: goods.stock
|
|
})
|
|
}
|
|
});
|
|
}
|
|
|
|
return {
|
|
id: item.id,
|
|
choujiangXianzhi: item.choujiangXianzhi,
|
|
title: item.title,
|
|
tips: item.goodsDescribe,
|
|
Popularity: item.joinCount || 0,
|
|
Time: `${item.flwStartTime} — ${item.flwEndTime}`,
|
|
GoodsList: goodsList
|
|
};
|
|
});
|
|
},
|
|
|
|
// 处理滑动切换
|
|
handleSwiperChange(e) {
|
|
const index = e.detail.current;
|
|
this.tabChange(index + 1);
|
|
},
|
|
|
|
// 修改标签切换方法
|
|
tabChange(i) {
|
|
if (this.tabCur === i) return;
|
|
this.tabCur = i;
|
|
|
|
if (i === 1) {
|
|
if (!this.ongoingLoaded) {
|
|
this.loadOngoingData();
|
|
}
|
|
} else {
|
|
if (!this.endedLoaded) {
|
|
this.loadEndedData();
|
|
}
|
|
}
|
|
},
|
|
|
|
// 跳转到福利屋详情
|
|
goToDetail(goodsId) {
|
|
const token = uni.getStorageSync('token');
|
|
if (!token) {
|
|
uni.showToast({
|
|
title: '请先登录',
|
|
icon: 'none',
|
|
duration: 1500
|
|
});
|
|
setTimeout(() => {
|
|
this.$c.to({ url: '/pages/user/login' });
|
|
}, 1500);
|
|
return;
|
|
}
|
|
this.$c.to({ url: '/pages/infinite/bonus_house_details?goods_id=' + goodsId });
|
|
},
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
.tab-container {
|
|
width: 100%;
|
|
margin-top: 30rpx;
|
|
}
|
|
|
|
.tab {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
|
|
.tab-item1, .tab-item2, .tab-item3 {
|
|
width: 160rpx;
|
|
height: 92rpx;
|
|
font-weight: 400;
|
|
margin-right: 30rpx;
|
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
position: relative;
|
|
overflow: hidden;
|
|
|
|
&:active {
|
|
transform: scale(0.95);
|
|
|
|
&::after {
|
|
content: '';
|
|
position: absolute;
|
|
top: 50%;
|
|
left: 50%;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: rgba(255, 255, 255, 0.2);
|
|
border-radius: 50%;
|
|
transform: translate(-50%, -50%) scale(0);
|
|
animation: ripple 0.6s ease-out;
|
|
}
|
|
}
|
|
|
|
>text {
|
|
font-weight: 600;
|
|
font-size: 24rpx;
|
|
color: #333333;
|
|
transition: all 0.3s ease;
|
|
}
|
|
}
|
|
|
|
.tab-item1 {
|
|
background: url($imgurl + "index/uncheckTab1.png") no-repeat 0 0 / 100% 100%;
|
|
|
|
&:active {
|
|
background: url($imgurl + "index/checkTab1.png") no-repeat 0 0 / 100% 100%;
|
|
}
|
|
}
|
|
|
|
.tab-item2 {
|
|
&.act {
|
|
background: url($imgurl + "index/checkTab2.png") no-repeat 0 0 / 100% 100%;
|
|
animation: tabActivate 0.3s ease-out;
|
|
}
|
|
|
|
&.unact {
|
|
background: url($imgurl + "index/uncheckTab2.png") no-repeat 0 0 / 100% 100%;
|
|
}
|
|
}
|
|
|
|
.tab-item3 {
|
|
&.act {
|
|
background: url($imgurl + "index/checkTab3.png") no-repeat 0 0 / 100% 100%;
|
|
animation: tabActivate 0.3s ease-out;
|
|
}
|
|
|
|
&.unact {
|
|
background: url($imgurl + "index/uncheckTab3.png") no-repeat 0 0 / 100% 100%;
|
|
}
|
|
}
|
|
}
|
|
|
|
@keyframes ripple {
|
|
0% {
|
|
transform: translate(-50%, -50%) scale(0);
|
|
opacity: 0.5;
|
|
}
|
|
100% {
|
|
transform: translate(-50%, -50%) scale(2);
|
|
opacity: 0;
|
|
}
|
|
}
|
|
|
|
@keyframes tabActivate {
|
|
0% {
|
|
transform: scale(0.95);
|
|
}
|
|
50% {
|
|
transform: scale(1.05);
|
|
}
|
|
100% {
|
|
transform: scale(1);
|
|
}
|
|
}
|
|
|
|
.benefits-container {
|
|
width: 672rpx;
|
|
height: 760rpx;
|
|
margin: 40rpx auto 0;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.benefits-swiper {
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
|
|
.benefits-scroll {
|
|
height: 760rpx;
|
|
}
|
|
|
|
.benefit-item {
|
|
width: 100%;
|
|
height: 274rpx;
|
|
background-color: #F8F8F8;
|
|
margin-bottom: 36rpx;
|
|
border-radius: 16rpx;
|
|
animation: slideIn 0.5s ease-out;
|
|
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
|
|
|
&:active {
|
|
transform: scale(0.98);
|
|
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
|
}
|
|
}
|
|
|
|
@keyframes slideIn {
|
|
from {
|
|
opacity: 0;
|
|
transform: translateX(30rpx);
|
|
}
|
|
to {
|
|
opacity: 1;
|
|
transform: translateX(0);
|
|
}
|
|
}
|
|
|
|
.benefit-title {
|
|
position: absolute;
|
|
left: 24rpx;
|
|
top: 28rpx;
|
|
color: #333333;
|
|
font-size: 24rpx;
|
|
}
|
|
|
|
.benefit-tips {
|
|
position: absolute;
|
|
left: 24rpx;
|
|
top: 62rpx;
|
|
color: #FF862D;
|
|
font-size: 18rpx;
|
|
}
|
|
|
|
.action-btn {
|
|
width: 128rpx;
|
|
height: 60rpx;
|
|
background-color: #D8FD24;
|
|
border-radius: 16rpx;
|
|
position: absolute;
|
|
top: 20rpx;
|
|
right: 24rpx;
|
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
|
|
&:active {
|
|
transform: scale(0.9);
|
|
background-color: darken(#D8FD24, 5%);
|
|
}
|
|
|
|
&.ended {
|
|
background-color: #333333;
|
|
transition: all 0.3s ease;
|
|
|
|
&:active {
|
|
transform: scale(0.9);
|
|
background-color: lighten(#333333, 5%);
|
|
}
|
|
|
|
text {
|
|
color: #D8FD24;
|
|
}
|
|
}
|
|
|
|
text {
|
|
font-size: 20rpx;
|
|
color: #333333;
|
|
font-weight: 600;
|
|
}
|
|
}
|
|
|
|
.goods-scroll {
|
|
height: 80rpx;
|
|
white-space: nowrap;
|
|
position: absolute;
|
|
left: 24rpx;
|
|
top: 112rpx;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.goods-item {
|
|
width: 80rpx;
|
|
height: 80rpx;
|
|
display: inline-block;
|
|
margin-right: 36rpx;
|
|
transition: transform 0.3s ease;
|
|
animation: scaleIn 0.5s ease-out;
|
|
|
|
&:active {
|
|
transform: scale(1.1);
|
|
}
|
|
}
|
|
|
|
@keyframes scaleIn {
|
|
from {
|
|
opacity: 0;
|
|
transform: scale(0.8);
|
|
}
|
|
to {
|
|
opacity: 1;
|
|
transform: scale(1);
|
|
}
|
|
}
|
|
|
|
.goods-img {
|
|
width: 100%;
|
|
height: 100%;
|
|
position: absolute;
|
|
}
|
|
|
|
.goods-num {
|
|
width: 44rpx;
|
|
height: 20rpx;
|
|
background-color: rgba(172, 172, 172, 0.60);
|
|
position: absolute;
|
|
border-radius: 10rpx;
|
|
bottom: 4rpx;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
|
|
text {
|
|
font-size: 18rpx;
|
|
color: #fff;
|
|
}
|
|
}
|
|
|
|
.divider {
|
|
width: 624rpx;
|
|
height: 2rpx;
|
|
background-color: #F3F3F3;
|
|
position: absolute;
|
|
left: 24rpx;
|
|
bottom: 54rpx;
|
|
}
|
|
|
|
.popularity {
|
|
position: absolute;
|
|
left: 24rpx;
|
|
bottom: 16rpx;
|
|
animation: slideInLeft 0.5s ease-out;
|
|
}
|
|
|
|
@keyframes slideInLeft {
|
|
from {
|
|
opacity: 0;
|
|
transform: translateX(-20rpx);
|
|
}
|
|
to {
|
|
opacity: 1;
|
|
transform: translateX(0);
|
|
}
|
|
}
|
|
|
|
.fire-icon {
|
|
width: 18rpx;
|
|
height: 20rpx;
|
|
}
|
|
|
|
.popularity-text {
|
|
font-size: 16rpx;
|
|
color: #999999;
|
|
margin-left: 8rpx;
|
|
}
|
|
|
|
.time-text {
|
|
font-size: 16rpx;
|
|
color: #999999;
|
|
position: absolute;
|
|
right: 24rpx;
|
|
bottom: 18rpx;
|
|
animation: slideInRight 0.5s ease-out;
|
|
}
|
|
|
|
@keyframes slideInRight {
|
|
from {
|
|
opacity: 0;
|
|
transform: translateX(20rpx);
|
|
}
|
|
to {
|
|
opacity: 1;
|
|
transform: translateX(0);
|
|
}
|
|
}
|
|
|
|
.btn-group {
|
|
margin-top: 40rpx;
|
|
}
|
|
|
|
.my-coupon {
|
|
width: 220rpx;
|
|
height: 72rpx;
|
|
background-color: #333333;
|
|
border-radius: 16rpx;
|
|
|
|
text {
|
|
font-size: 24rpx;
|
|
color: #D8FD24;
|
|
}
|
|
}
|
|
|
|
.reward-record {
|
|
width: 220rpx;
|
|
height: 72rpx;
|
|
background-color: #D8FD24;
|
|
border-radius: 16rpx;
|
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
animation: fadeIn 0.5s ease-out;
|
|
|
|
&:active {
|
|
transform: scale(0.95);
|
|
background-color: darken(#D8FD24, 5%);
|
|
}
|
|
|
|
text {
|
|
font-weight: 600;
|
|
font-size: 24rpx;
|
|
color: #333333;
|
|
}
|
|
}
|
|
|
|
@keyframes fadeIn {
|
|
from {
|
|
opacity: 0;
|
|
transform: translateY(20rpx);
|
|
}
|
|
to {
|
|
opacity: 1;
|
|
transform: translateY(0);
|
|
}
|
|
}
|
|
</style> |