HaniBlindBox/honey_box/pages/infinite/bonus_house_details.vue
2026-02-05 23:44:19 +08:00

1158 lines
28 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>
<page-container title="福利屋详情" :showBack="true">
<view class="relative header-info" :class="{ 'show': headerShow }"
style="width: 686rpx; height: 152rpx; background-color: #FFFFFF; border-radius: 16rpx; margin: 0 auto;">
<image style="width: 108rpx; height: 108rpx;position: absolute; left: 24rpx; top: 22rpx;"
:src="$img1('common/logo.jpg')"></image>
<text style="font-size: 24rpx; color: #333333; position: absolute; left: 146rpx; top: 34rpx;">{{
bonusData.title }}</text>
<text style="font-size: 18rpx; color: #FF862D; position: absolute; left: 146rpx; top: 68rpx;">{{
bonusData.tips }}</text>
<text style="font-size: 16rpx; color: #999999; position: absolute; left: 146rpx; top: 102rpx;">{{
bonusData.time }}</text>
<view class="row center" style="position: absolute; left: 470rpx; top: 68rpx;">
<image style="width: 18rpx; height: 20rpx;" :src="$img1('checkin/Fire.png')" mode=""></image>
<text style="font-size: 16rpx; color: #999999; margin-left: 8rpx;">{{ bonusData.popularity }}</text>
</view>
<button open-type="share" class="button"
style="position: absolute; top: 50rpx; right: 24rpx; width: 50rpx; height: 50rpx; border: none; padding: 0; margin: 0; line-height: 1; ">
</button>
</view>
<view class="content-area" :class="{ 'show': contentShow }"
style="width: 686rpx; height: 1010rpx; background-color: #FFFFFF; border-radius: 16rpx; margin: 24rpx auto 0;">
<view class="tab">
<view class="tab-item center relative" v-for="(item, i) in tabList" :key="i"
:class="[currentTab == i ? 'act' : 'unact', { 'show': tabsShow[i] }]" @click="handleTabChange(i)">
<text>{{ item }}</text>
</view>
</view>
<!-- 赏品预览 -->
<view v-if="currentTab == 0" scroll-y="true" class="" style="width: 100%; height: 900rpx;">
<view style="height:30rpx">
<view
style="display: flex; justify-content: center; align-items: center; height:75%;margin-top: 10rpx;">
<view style="width: 280rpx; text-align: center;">
<text style="color: #333333; font-size: 24rpx;">参考价:{{ getGoodsListName }}</text>
</view>
</view>
</view>
<view class="swiper-container">
<swiper class="swiper-box" :current="currentItemId" :autoplay="false" @change="handleSwiperChange"
:indicator-dots="false" :circular="true" :interval="3000">
<swiper-item v-for="(item, index) in goodsList" :key="index" :item-id="item.index">
<view class="swiper-item-content">
<view class="item-background">
<image :src="item.imgurl_detail" class="item-image"></image>
</view>
</view>
<view class="item-bottom"></view>
</swiper-item>
</swiper>
</view>
<scroll-view scroll-y="true" style="width: 100%; height:400rpx;">
<view class="grid-container">
<view @click=" currentItemId = item.index" class="grid-item column align-center"
v-for="(item, index) in goodsList" :key="index" style="">
<image style="width: 112rpx; height: 112rpx;border-radius:25rpx;" :src="item.imgUrl">
</image>
<text style="color: #999999; font-size: 16rpx; margin-top: 16rpx;">{{ item.title }}</text>
</view>
</view>
</scroll-view>
</view>
<scroll-view v-if="currentTab == 1" scroll-y="true" style="width: 100%; height: 890rpx; padding: 24rpx;">
<view class="row align-center participant-row" :class="{ 'show': participantRowsShow[index] }"
v-for="(item, index) in participantList" :key="index" style="height: 76rpx; margin-bottom: 24rpx;">
<view class="center" style="width: 30rpx;">
<text style="color: #999999; font-size: 20rpx;">{{ index + 1 }}</text>
</view>
<image :src="item.avatar"
style="width: 76rpx; height: 76rpx; background-color: #D8D8D8; border-radius: 50%; margin-left: 24rpx;"
mode=""></image>
<view class="column" style="margin-left: 16rpx;">
<text style="color: #333333; font-size: 20rpx;">{{ item.name }}</text>
<text style="color: #999999; font-size: 16rpx; margin-top: 12rpx;">{{ item.time }}</text>
</view>
</view>
</scroll-view>
<scroll-view v-if="currentTab == 2" scroll-y="true" style="width: 100%; height: 890rpx; padding: 24rpx;">
<view class="row align-center award-row" :class="{ 'show': awardRowsShow[index] }"
v-for="(item, index) in awardRecordList" :key="index" style="height: 76rpx; margin-bottom: 24rpx;">
<view class="center" style="width: 30rpx;">
<text style="color: #999999; font-size: 20rpx;">{{ index + 1 }}</text>
</view>
<image :src="item.avatar"
style="width: 76rpx; height: 76rpx; background-color: #D8D8D8; border-radius: 50%; margin-left: 24rpx;"
mode=""></image>
<view class="column" style="margin-left: 16rpx;">
<text style="color: #333333; font-size: 20rpx;">{{ item.name }}</text>
<text style="color: #999999; font-size: 16rpx; margin-top: 12rpx;">{{ item.time }}</text>
</view>
<view class="row center" style="position: absolute; right: 56rpx;">
<image v-if="item.shang_id == 115" :src="$img1('checkin/Jackpot.png')"
style="width: 46rpx; height: 26rpx;" mode=""></image>
<text style="color: #999999; font-size: 20rpx; margin-left: 16rpx;">{{ item.award }}</text>
</view>
</view>
</scroll-view>
</view>
<view class="column align-center"
style="width: 100%; height: 198rpx; background-color: #fff; margin-top: 8rpx;">
<view class="participation-button" :class="{ 'show': buttonShow, 'pulse': buttonPulse }"
@click="handleButtonPulse">
<text class="button-text">{{ buttonText }}</text>
</view>
<text style="color: #8A8A8A; font-size: 20rpx; font-weight: 400; margin-top: 12rpx;">{{ remainingTime
}}</text>
</view>
<OrderConfirmPopupFlw v-if="orderData.goods != null" ref="buyPop" :order-data="orderData" :use-money="useMoney"
@change-pay="changePay" :use-money2="useMoney2" :use-integral="useIntegral" :is-agree="isAgree"
:send-rule-data="sendRuleData" :buy-num="1" @close="close('buyPop')" @toggle-agree="isAgree = !isAgree"
@confirm="$c.noDouble1(confirmSubmit, [1, 1], loading)">
</OrderConfirmPopupFlw>
<!-- 条件不足弹窗 -->
<uni-popup ref="condition" type="center" :animation="true" :mask-click="true">
<view class="popup-container">
<view class="popup-title">
参与提示
</view>
<view class="popup-content">
提示:需在指定时间{{ bonusData.start_time }}-{{ bonusData.end_time }}消耗达到{{ bonusData.choujiang_xianzhi
}}钻石,即可加入房间,还需{{ $c.removeTrailingZeros(remainingDiamond) }}钻石.
</view>
</view>
<view class="popup-buttons">
<view class="popup-button cancel-button" @click="$refs.condition.close()">
<text>取消</text>
</view>
<view class="popup-button confirm-button" @click="toHome()">
<text>去抽赏</text>
</view>
</view>
</uni-popup>
</page-container>
</template>
<script>
import { getWelfareHouseDetail, getWelfareParticipants, getWelfareRecords, buyWelfareHouse } from '@/common/server/welfare.js';
import { calcOrderMoney } from '@/common/server/order.js';
import OrderConfirmPopupFlw from '@/components/order-confirm-popup/order-confirm-popup-flw.vue';
import PageContainer from '@/components/page-container/page-container.vue';
export default {
components: {
OrderConfirmPopupFlw,
PageContainer
},
onShareAppMessage() {
let imageUrl = this.$config.getShareImageUrl();
return {
imageUrl: imageUrl,
title: this.bonusData.title,
path: '/pages/infinite/bonus_house_details?goods_id=' + this.goods_id
}
},
data() {
return {
currentItemId: 0,
currentTab: 0,
bonusData: {
title: "",
tips: "",
time: "",
popularity: 0, // 热度
open_time: '', //开奖时间
start_time: '', //开始时间
end_time: '', //结束时间
choujiang_xianzhi: 0 // 抽奖限制金额
},
goodsList: [],
participantList: [],
awardRecordList: [],
tabList: [
"赏品预览", "参与人数", "赏品记录"
],
goods_id: 0,
remainingTime: "0天00:00:00",
countdownTimer: null,
endTime: null,
currentServerTime: null,
buttonText: "马上参与",
user_total_consumption: 0, // 用户抽奖范围内消耗的金额
orderData: {
goods: null,
"use_integral": 0,
"use_integral_money": 0,
"money": 0,
"use_money": 0,
"score": "0.00",
"use_score": 0,
},
pageData: "",
logList: [],
sendRuleData: "",
useMoney: true,
useIntegral: false,
useMoney2: false,
isAgree: true,
loading: false,
user_count: 0, //用户已经购买的次数
// 动画状态控制变量
headerShow: false,
contentShow: false,
buttonShow: false,
tabsShow: [false, false, false],
participantRowsShow: [],
awardRowsShow: [],
// 按钮脉冲动画
buttonPulse: false
}
},
computed: {
getGoodsListName() {
if (this.goodsList.length > 0) {
return this.goodsList[this.currentItemId].title
}
return '';
},
remainingDiamond() {
let t = (this.bonusData.choujiang_xianzhi - this.user_total_consumption).toFixed(2);
return t > 0 ? t : 0;
}
},
async onLoad(options) {
console.log(options)
this.goods_id = options.goods_id
await this.load(options.goods_id)
// 添加页面加载动画
setTimeout(() => {
this.applyPageTransitions();
}, 100);
},
methods: {
handleSwiperChange(e) {
this.currentItemId = e.detail.current
},
async load(goods_id) {
// API: fuliwu_detail
const res = await getWelfareHouseDetail(goods_id);
console.log(res)
if (res.status === 1 && res.data) {
const {
goods,
goodslist,
joinCount,
currentTime,
status,
statusText,
userConsumption,
userCount
} = res.data;
this.orderData.goods = goods;
// 更新福利屋基本信息
this.bonusData = {
title: goods.title,
tips: goods.goodsDescribe,
time: goods.flwStartTime + '-' + goods.flwEndTime,
open_time: goods.openTime,
start_time: goods.flwStartTime,
end_time: goods.flwEndTime,
choujiang_xianzhi: goods.choujiangXianzhi,
popularity: joinCount || 0,
quanju_xiangou: goods.quanjuXiangou,
price: goods.price
};
if (userConsumption != null) {
this.user_total_consumption = userConsumption.totalAmount || 0;
}
if (userCount != null) {
this.user_count = userCount;
}
let index = 0;
this.goodsList.splice(0, this.goodsList.length)
// 更新赏品列表
goodslist.forEach(item => {
for (let i = 0; i < item.stock; i++) {
this.goodsList.push({
index,
imgUrl: item.imgurl,
title: item.title,
id: item.id,
stock: item.stock,
realPrice: item.price,
sortIndex: item.sort,
type: item.shangTitle,
typeColor: item.shangColor,
imgurl_detail: item.imgurlDetail
});
index++;
}
})
// 计算倒计时
this.calculateRemainingTime(goods.openTime, goods.flwStartTime, currentTime);
this.startCountdownTimer(goods.openTime, goods.flwStartTime, currentTime);
// 其他状态信息
this.activityStatus = status;
this.activityStatusText = statusText;
// 获取参与人数和赏品记录列表
if (joinCount > 0) {
await this.loadParticipants(goods_id);
await this.loadAwardRecords(goods_id);
}
}
},
changePay(e) {
this[e] = !this[e];
console.log('aaasdas');
this.confirmSubmit([0, 1]);
},
async confirmSubmit([type, num, fromNotice = false]) {
let data = {
goods_id: this.goods_id,
prize_num: 1,
num: 1,
use_money_is: this.useMoney ? 1 : 2,
use_integral_is: this.useIntegral ? 1 : 2,
coupon_id: "",
use_money2_is: this.useMoney2 ? 1 : 2
};
this.buyNum = num;
let res;
if (type == 1) {
// API: fuliwu_buy
res = await buyWelfareHouse(data);
} else {
// API: ordermoney
res = await calcOrderMoney(data);
}
if (res.status == 1) {
if (type == 0) {
this.orderData = res.data;
// 使用this.$nextTick确保视图已更新组件已挂载
this.$nextTick(() => {
if (this.$refs.buyPop) {
this.$refs.buyPop.open();
} else {
console.error('buyPop组件引用不存在');
}
});
}
if (type == 1) {
this.close("buyPop");
if (res.data.status == 1) {
const status = await this.$platform.pay({
data: res.data.res
},this);
if (status == "success") {
this.load(this.goods_id);
}
} else {
this.$c.toast({
title: res.msg,
duration: 500,
success: () => {
this.load(this.goods_id);
},
});
}
}
}
if (type == 1) {
this.close("buyPop");
}
},
calculateRemainingTime(openTime, startTime, currentTime) {
// 将时间字符串转为时间对象
const endDate = new Date(openTime.replace(/-/g, '/'));
const startDate = new Date(startTime.replace(/-/g, '/'));
const currentDate = new Date(currentTime.replace(/-/g, '/'));
// 保存结束时间和当前服务器时间,用于实时倒计时
this.endTime = endDate;
this.currentServerTime = currentDate;
// 判断当前时间与开始时间和结束时间的关系
if (currentDate > endDate) {
this.remainingTime = "活动已结束";
return;
} else if (currentDate < startDate) {
this.remainingTime = this.formatRemainingTime(startDate - currentDate, "距离开始时间:");
return;
} else if (currentDate >= startDate && currentDate <= endDate) {
this.remainingTime = this.formatRemainingTime(endDate - currentDate, "距离开奖时间:");
return;
}
},
formatRemainingTime(diffTime, prefix) {
// 转换为天、时、分、秒
const days = Math.floor(diffTime / (24 * 60 * 60 * 1000));
diffTime = diffTime % (24 * 60 * 60 * 1000);
const hours = Math.floor(diffTime / (60 * 60 * 1000));
diffTime = diffTime % (60 * 60 * 1000);
const minutes = Math.floor(diffTime / (60 * 1000));
diffTime = diffTime % (60 * 1000);
const seconds = Math.floor(diffTime / 1000);
// 格式化时间
return `${prefix}${days}天${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
},
startCountdownTimer(openTime, startTime, currentTime) {
// 清除之前可能存在的计时器
if (this.countdownTimer) {
clearInterval(this.countdownTimer);
}
// 保存结束时间和当前时间的时间差(毫秒)
const endDate = new Date(openTime.replace(/-/g, '/'));
const startDate = new Date(startTime.replace(/-/g, '/'));
const currentDate = new Date(currentTime.replace(/-/g, '/'));
const serverClientTimeDiff = currentDate.getTime() - new Date().getTime();
// 设置每秒更新一次倒计时
this.countdownTimer = setInterval(() => {
// 获取当前客户端时间并加上与服务器的时间差,以获得准确的服务器当前时间
const now = new Date();
const serverNow = new Date(now.getTime() + serverClientTimeDiff);
this.updateButtonState();
// 判断当前时间与开始时间和结束时间的关系
if (serverNow > endDate) {
clearInterval(this.countdownTimer);
this.remainingTime = "活动已结束";
return;
} else if (serverNow < startDate) {
this.remainingTime = this.formatRemainingTime(startDate - serverNow, "距离开始时间:");
return;
} else if (serverNow >= startDate && serverNow <= endDate) {
this.remainingTime = this.formatRemainingTime(endDate - serverNow, "距离开奖时间:");
return;
}
}, 1000);
},
onUnload() {
// 组件卸载时清除计时器
if (this.countdownTimer) {
clearInterval(this.countdownTimer);
this.countdownTimer = null;
}
},
async loadParticipants(goods_id) {
// 这里应该调用获取参与人数列表的接口
try {
// API: fuliwu_participants
const res = await getWelfareParticipants({ goods_id });
if (res.status === 1 && res.data && res.data.list) {
this.participantList.splice(0, this.participantList.length)
this.participantList = res.data.list.map(item => ({
avatar: item.avatar || "",
name: item.nickname || "用户",
time: item.createTime || ""
}));
}
} catch (error) {
console.error("加载参与人数列表失败", error);
}
if (this.currentTab === 1) {
setTimeout(() => {
this.animateListItems('participant-row');
}, 100);
}
},
async loadAwardRecords(goods_id) {
// 这里应该调用获取赏品记录的接口
try {
// API: fuliwu_records
const res = await getWelfareRecords({ goods_id });
if (res.status === 1 && res.data && res.data.list) {
this.awardRecordList = res.data.list.map(item => ({
avatar: item.avatar || "",
name: item.nickname || "用户",
time: item.createTime || "",
award: item.goodslistTitle || "钻石*0",
shang_id: item.shangId
}));
}
} catch (error) {
console.error("加载赏品记录失败", error);
}
if (this.currentTab === 2) {
setTimeout(() => {
this.animateListItems('award-row');
}, 100);
}
},
async handleTabChange(index) {
this.currentTab = index;
// 切换到参与人数或赏品记录时,重新加载数据
if (index === 1) {
await this.loadParticipants(this.goods_id);
} else if (index === 2) {
await this.loadAwardRecords(this.goods_id);
}
},
// 添加列表项动画方法
animateListItems(className) {
// 根据列表类型初始化动画状态数组
if (className === 'participant-row') {
this.participantRowsShow = Array(this.participantList.length).fill(false);
// 逐个显示列表项
for (let i = 0; i < this.participantList.length; i++) {
((index) => {
setTimeout(() => {
this.$set(this.participantRowsShow, index, true);
}, index * 50);
})(i);
}
} else if (className === 'award-row') {
this.awardRowsShow = Array(this.awardRecordList.length).fill(false);
// 逐个显示列表项
for (let i = 0; i < this.awardRecordList.length; i++) {
((index) => {
setTimeout(() => {
this.$set(this.awardRowsShow, index, true);
}, index * 50);
})(i);
}
}
},
updateButtonState() {
const currentDate = new Date();
const startDate = new Date(this.bonusData.start_time.replace(/-/g, '/'));
const endDate = new Date(this.bonusData.end_time.replace(/-/g, '/'));
const openDate = new Date(this.bonusData.open_time.replace(/-/g, '/'));
// console.log(currentDate,startDate);
if (currentDate < startDate) {
this.buttonText = "未开始";
} else if (currentDate >= startDate && currentDate <= endDate) {
if (this.user_count > 0 && this.user_count >= this.bonusData.quanju_xiangou) {
this.buttonText = "等待开奖中";
return;
}
this.buttonText = "马上参与";
} else if (currentDate > endDate && currentDate < openDate) {
this.buttonText = "等待开奖中";
} else if (currentDate >= openDate) {
this.buttonText = "活动已结束";
}
},
handleButtonPulse() {
// 添加动画类
this.buttonPulse = true;
setTimeout(() => {
this.buttonPulse = false;
}, 400); // 动画时长结束后移除类
// 调用原始点击处理程序
this.handleButtonClick();
},
handleButtonClick() {
if (this.buttonText === "未开始") {
uni.showToast({
title: "活动未开始",
icon: "none"
});
return;
} else if (this.buttonText === "等待开奖中") {
uni.showToast({
title: "等待开奖中",
icon: "none"
});
return;
} else if (this.buttonText === "活动已结束") {
uni.showToast({
title: "活动已结束",
icon: "none"
});
return;
}
if (this.user_count > 0 && this.user_count >= this.bonusData.quanju_xiangou) {
uni.showToast({
title: "当前活动限购" + this.bonusData.quanju_xiangou + "次",
icon: "none"
});
return;
}
//判断用户今天消费的金额是否满足参与条件
if (this.user_total_consumption < this.bonusData.choujiang_xianzhi) {
this.$refs.condition.open();
// uni.showToast({
// title: "消费金额不足",
// icon: "none"
// });
return;
}
console.log(this.user_total_consumption, this.bonusData.choujiang_xianzhi);
if (this.bonusData.price == 0) {
this.useMoney = true;
this.confirmSubmit([1, 1]);
return;
}
this.confirmSubmit([0, 1])
// if (this.$refs['buyPop']) {
// this.$refs['buyPop'].open();
// } else {
// console.error("buyPop is undefined");
// }
},
close(e) {
console.log('关闭弹窗:', e, this.$refs[e]);
if (e === 'buyPop') {
if (this.$refs[e]) {
this.$refs[e].close();
} else {
console.error('找不到buyPop组件引用');
}
} else {
if (this.$refs[e]) {
this.$refs[e].close();
} else {
console.error('找不到组件引用:', e);
}
}
if (e == "resPop") {
if (this.prizeData && this.prizeData["user_coupon"] != null) {
this.$refs["couponPop"].open(this.prizeData["user_coupon"]);
}
}
},
toHome() {
this.$customRouter.navigateTo('/pages/shouye/index', {}, 'reLaunch');
},
applyPageTransitions() {
// 头部信息
this.headerShow = true;
// 标签
setTimeout(() => { this.tabsShow[0] = true; }, 100);
setTimeout(() => { this.tabsShow[1] = true; }, 200);
setTimeout(() => { this.tabsShow[2] = true; }, 300);
// 内容区
setTimeout(() => { this.contentShow = true; }, 200);
// 按钮
setTimeout(() => { this.buttonShow = true; }, 300);
}
}
}
</script>
<style lang="scss">
.tab {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10rpx 60rpx;
position: relative;
z-index: 1;
.tab-item {
width: 155rpx;
height: 68rpx;
position: relative;
margin-right: 25rpx;
transition: all 0.3s ease;
&:active {
transform: scale(0.95);
}
&.act {
font-weight: 400;
font-size: 28rpx;
color: #333333;
&::after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 48rpx;
height: 4rpx;
background: #333333;
transition: all 0.3s cubic-bezier(0.68, -0.55, 0.27, 1.55);
animation: fadeInWidth 0.3s forwards;
}
}
&.unact {
font-weight: 400;
font-size: 28rpx;
color: #CCCCCC;
&::after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 0;
height: 4rpx;
background: #333333;
transition: all 0.3s ease;
}
}
}
}
@keyframes fadeInWidth {
from {
width: 0;
}
to {
width: 48rpx;
}
}
.grid-container {
display: grid;
grid-template-columns: repeat(4, 124rpx);
gap: 24rpx;
width: 580rpx;
margin: 10rpx auto 0;
padding-bottom: 20rpx;
}
.grid-item {
width: 142rpx;
height: 150rpx;
transition: all 0.3s ease;
padding: 8rpx;
border-radius: 12rpx;
position: relative;
&:active {
transform: translateY(-6rpx) scale(1.05);
background-color: rgba(0, 0, 0, 0.02);
}
image {
transition: all 0.25s ease;
box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.1);
}
&:active image {
box-shadow: 0 8rpx 12rpx rgba(0, 0, 0, 0.15);
}
text {
transition: color 0.25s ease;
}
&:active text {
color: #666 !important;
}
}
.button {
background-image: url($imgurl + 'checkin/ic_share.png');
background-size: 100% 100%;
transition: all 0.3s ease;
position: relative;
overflow: visible;
border: none !important;
outline: none !important;
&::after {
border: none !important;
}
&::before {
content: '';
position: absolute;
top: -5rpx;
right: -5rpx;
bottom: -5rpx;
left: -5rpx;
border-radius: 50%;
background-color: rgba(0, 0, 0, 0.05);
transform: scale(0);
opacity: 0;
transition: all 0.2s ease;
}
&:active {
transform: scale(0.9) rotate(15deg);
}
&:active::before {
transform: scale(1);
opacity: 1;
}
}
.swiper-container {
width: 544rpx;
height: 500rpx;
margin: 0 auto;
}
.swiper-box {
height: 500rpx;
}
.swiper-item-content {
display: flex;
justify-content: center;
align-items: center;
height: 75%;
margin-top: 10rpx;
}
.item-background {
background-image: url($baseurl +'flw_bj.png');
background-size: 100% 100%;
width: 280rpx;
height: 352rpx;
display: flex;
justify-content: center;
align-items: center;
z-index: 2;
}
.item-image {
width: 154rpx;
height: 166rpx;
}
.item-bottom {
background-image: url($baseurl +'flw_dibu.png');
background-size: 100% 100%;
width: 100%;
height: 122rpx;
position: relative;
top: -15%;
z-index: 1;
}
.participation-button {
display: flex;
justify-content: center;
align-items: center;
width: 340rpx;
height: 84rpx;
background-color: #D8FD24;
border-radius: 16rpx;
margin-top: 32rpx;
box-shadow: 0 4rpx 8rpx rgba(0, 0, 0, 0.1);
position: relative;
overflow: hidden;
// 页面加载动画
opacity: 0;
transform: translateY(20rpx);
transition: transform 0.5s ease, opacity 0.5s ease, background-color 0.2s ease, box-shadow 0.2s ease;
transition-delay: 0.3s;
&.show {
opacity: 1;
transform: translateY(0);
}
&.pulse {
animation: buttonPulse 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
}
.button-text {
color: #333333;
font-size: 32rpx;
font-weight: 600;
z-index: 2;
position: relative;
}
.popup-container {
width: 636rpx;
background-color: #FFFFFF;
border-radius: 16rpx;
overflow: hidden;
transform: scale(0.9);
opacity: 0;
animation: popIn 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards;
}
.popup-title {
width: 100%;
height: 80rpx;
border-radius: 24rpx 24rpx 0 0;
display: flex;
justify-content: center;
align-items: center;
font-size: 35rpx;
background-color: #f9f9f9;
position: relative;
&::after {
content: '';
position: absolute;
bottom: 0;
left: 10%;
width: 80%;
height: 1px;
background-color: #eee;
}
}
.popup-content {
padding: 24rpx;
font-size: 28rpx;
color: #666;
line-height: 1.5;
}
.popup-buttons {
display: flex;
width: 636rpx;
justify-content: space-around;
margin-top: 32rpx;
animation: slideUp 0.4s ease-out forwards;
animation-delay: 0.1s;
opacity: 0;
transform: translateY(20rpx);
}
.popup-button {
display: flex;
justify-content: center;
align-items: center;
width: 200rpx;
height: 68rpx;
border-radius: 16rpx;
font-size: 24rpx;
font-weight: 600;
transition: all 0.25s ease;
position: relative;
overflow: hidden;
&:active {
transform: scale(0.95);
}
&::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 100rpx;
height: 100rpx;
background-color: rgba(255, 255, 255, 0.3);
border-radius: 50%;
transform: translate(-50%, -50%) scale(0);
opacity: 0;
transition: all 0.3s ease-out;
}
&:active::after {
transform: translate(-50%, -50%) scale(3);
opacity: 0;
}
text {
position: relative;
z-index: 1;
font-size: 24rpx;
font-weight: 600;
}
}
.cancel-button {
background-color: #FFFFFF;
border: 1px solid #eee;
text {
color: #333333;
}
&:active {
background-color: #f5f5f5;
}
}
.confirm-button {
background-color: #CDEF27;
box-shadow: 0 4rpx 8rpx rgba(205, 239, 39, 0.3);
text {
color: #333333;
}
&:active {
background-color: #b9d721;
box-shadow: 0 2rpx 4rpx rgba(205, 239, 39, 0.2);
}
}
@keyframes popIn {
from {
transform: scale(0.9);
opacity: 0;
}
to {
transform: scale(1);
opacity: 1;
}
}
@keyframes slideUp {
from {
opacity: 0;
transform: translateY(20rpx);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.participant-row {
opacity: 0;
transform: translateX(-20rpx);
transition: all 0.4s ease;
&.show {
opacity: 1;
transform: translateX(0);
}
}
.award-row {
opacity: 0;
transform: translateX(-20rpx);
transition: all 0.4s ease;
&.show {
opacity: 1;
transform: translateX(0);
}
}
.header-info {
opacity: 0;
transform: translateY(-20rpx);
transition: all 0.5s ease;
&.show {
opacity: 1;
transform: translateY(0);
}
}
.tab-item {
opacity: 0;
transform: translateY(10rpx);
transition: all 0.4s ease;
&.show {
opacity: 1;
transform: translateY(0);
}
}
.content-area {
opacity: 0;
transform: translateY(20rpx);
transition: all 0.5s ease;
transition-delay: 0.2s;
&.show {
opacity: 1;
transform: translateY(0);
}
}
@keyframes buttonPulse {
0% {
transform: scale(1);
box-shadow: 0 4rpx 8rpx rgba(0, 0, 0, 0.1);
}
40% {
transform: scale(0.92);
box-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.05);
}
80% {
transform: scale(1.05);
box-shadow: 0 6rpx 10rpx rgba(0, 0, 0, 0.15);
background-color: #e0ff3a;
}
100% {
transform: scale(1);
box-shadow: 0 4rpx 8rpx rgba(0, 0, 0, 0.1);
}
}
</style>