| <template> | |
| 	<view class="receive-gift"> | |
| 
 | |
|         <template v-if="isOpeningEnd"> | |
| 
 | |
|             <navbar title="礼品领取" leftClick @leftClick="$utils.navigateBack" /> | |
|              | |
|             <!-- 主图片展示区 --> | |
|             <view class="main-image"> | |
|                 <image :src="giftInfo.image" mode="aspectFill"></image> | |
|             </view> | |
|              | |
|             <!-- 礼品信息区域 --> | |
|             <view class="gift-info"> | |
|                 <view class="gift-name">{{giftInfo.title}}</view> | |
|                 <view class="gift-value"> | |
|                     <text>礼品价值:</text> | |
|                     <text class="price">¥{{giftInfo.price}}</text> | |
|                 </view> | |
|             </view> | |
|              | |
|             <!-- 祝福语区域 --> | |
|             <view class="blessing-area"> | |
|                 <view class="sender-info"> | |
|                     <text class="label">来自</text> | |
|                     <text class="sender">{{giftInfo.name}}</text> | |
|                     <text class="label">的祝福</text> | |
|                 </view> | |
|                 <view class="blessing-content"> | |
|                     {{ giftInfo.giveTitle }} | |
|                 </view> | |
|             </view> | |
|              | |
|             <!-- 底部区域 --> | |
|             <view class="bottom-area"> | |
|                 <!-- <view class="countdown">距离礼包失效:{{countdownText}}</view> --> | |
|                 <!-- <button class="receive-btn"  | |
|                 @click="receiveGift"  | |
|                 :disabled="giftInfo.giveStatus !== 0"> | |
|                     {{giftInfo.giveStatus === 0 ? '立即领取' : '已领取'}} | |
|                 </button> --> | |
|                  | |
|                 <button class="receive-btn" | |
| 				v-if="giftInfo.giveStatus != 1" | |
|                 @click="openAddress"> | |
|                     立即领取 | |
|                 </button> | |
|             </view> | |
|         </template> | |
|  | |
|         <!-- 礼物开启动画弹窗 --> | |
|         <uv-popup ref="giftPopup"  | |
|             mode="center"  | |
|             :round="20"  | |
|             :closeable="false"  | |
| 			:closeOnClickOverlay="false" | |
|             :maskClick="false" | |
|             :customStyle="{backgroundColor: 'transparent', padding: 0}" | |
|             overlayOpacity="0.8"> | |
|             <view class="gift-card" :class="{ 'open': isOpening }"> | |
|                 <view class="gift-icon" :class="{ 'bounce': !isOpening }"> | |
|                     <uv-icon name="gift-fill" size="120" color="#FFD700"></uv-icon> | |
|                 </view> | |
|                 <view class="gift-content"> | |
|                     <view class="gift-title" :class="{ 'fade': isOpening }"> | |
|                         {{ giftInfo.name }}送你一份礼物 | |
|                     </view> | |
|                     <view class="gift-open-btn"  | |
|                         @click="openGift" | |
|                         :class="{ 'pulse': !isOpening }"> | |
|                         <text>开</text> | |
|                         <view class="btn-sparkle"></view> | |
|                     </view> | |
|                     <view class="gift-tip" :class="{ 'fade': isOpening }"> | |
|                         {{ giftInfo.giveTitle }} | |
|                     </view> | |
|                 </view> | |
|             </view> | |
|         </uv-popup> | |
|  | |
|         <!-- 抽奖弹窗 --> | |
|         <uv-popup ref="lotteryPopup"  | |
|             mode="center"  | |
|             :round="20"  | |
|             :closeable="false"  | |
|             :maskClick="false" | |
| 			:closeOnClickOverlay="false" | |
|             :customStyle="{backgroundColor: 'transparent', padding: 0}" | |
|             overlayOpacity="0.8"> | |
|             <view class="lottery-card"> | |
|                 <view class="lottery-title">{{ giftInfo.name }}为您精选了一份抽奖礼包</view> | |
|                 <view class="gift-tip"> | |
|                         {{ giftInfo.giveTitle }} | |
|                     </view> | |
|                 <view class="lottery-content"> | |
|                     <view class="product-image"> | |
|                         <image :src="giftInfo.image" mode="aspectFill"></image> | |
|                     </view> | |
|                     <view class="product-info"> | |
|                         <view class="product-name">{{giftInfo.title}}</view> | |
|                         <view class="product-price">¥{{giftInfo.price}}</view> | |
|                     </view> | |
|                 </view> | |
| 				 | |
|                 <view class="lottery-btn" @click="startLottery" v-if="!isSpinning"> | |
|                     试试手气 | |
|                 </view> | |
| 				 | |
|                 <view class="lottery-result" v-if="showResult"> | |
|                     <text v-if="isWinner">恭喜您中奖了!</text> | |
|                     <text v-else>很遗憾,下次再来!</text> | |
|                 </view> | |
| 				 | |
| 				<view class="lottery-btn"  | |
| 				@click="openAddress"  | |
| 				v-if="isWinner && giftInfo.giveStatus != 1"> | |
| 				    立即领取 | |
| 				</view> | |
|             </view> | |
|         </uv-popup> | |
| 		 | |
| 		 | |
| 		<!-- 地址选择 --> | |
| 		<uv-popup ref="addressPopup" :round="30" style="padding-bottom: 90rpx;"> | |
| 			 | |
| 			<view class="addressPopupTitle"> | |
| 				填写地址就能收礼了 | |
| 			</view> | |
| 			 | |
| 			<!-- <view class="tabs"> | |
| 				<uv-tabs :list="tabs"  | |
| 				:activeStyle="{color : 'rgb(235, 51, 0)', fontWeight : 600}"  | |
| 				lineColor="#fff" | |
| 				:inactiveStyle="{color: 'rgba(235, 51, 0, 0.8)'}"  | |
| 				lineHeight="8rpx"  | |
| 				lineWidth="50rpx"  | |
| 				:current="addressCurrent" | |
| 				@click="clickTabs"></uv-tabs> | |
| 			</view> --> | |
| 			 | |
| 			<addressList  | |
| 			ref="addressList"  | |
| 			height="60vh"  | |
| 			v-if="addressCurrent == 1" | |
| 			@select="receiveGift" /> | |
| 			 | |
| 			<view class="redactAddressForm" | |
| 			v-else> | |
| 			 | |
| 				<redactAddressForm | |
| 				ref="redactAddressForm" | |
| 				@saveOrUpdate="receiveGift" | |
| 				/> | |
| 				 | |
| 				<view  | |
| 				@click="$refs.redactAddressForm.onSubmit"  | |
| 				class="save">确认收礼</view> | |
| 			</view> | |
| 			 | |
| 		</uv-popup> | |
| 		 | |
| 		<loginPopup ref="loginPopup" @login="getGiftInfo"/> | |
| 	</view> | |
| </template> | |
| 
 | |
| <script> | |
| 	import addressList from '../components/address/addressList.vue' | |
| 	import redactAddressForm from '../components/address/redactAddressForm.vue' | |
|     import loginPopup from '@/components/config/loginPopup.vue' | |
| 	export default { | |
| 		components : { | |
| 			addressList, | |
| 			redactAddressForm, | |
|             loginPopup, | |
| 		}, | |
| 		data() { | |
| 			return { | |
| 				giftId: '', | |
| 				giftInfo: { | |
| 				}, | |
| 				countdown: 24 * 60 * 60, // 倒计时秒数 | |
| 				countdownTimer: null, | |
| 
 | |
| 				// 领奖 | |
|                 isOpening: false, | |
|                 isOpeningEnd : false, | |
| 
 | |
|                 // 抽奖 | |
|                 isSpinning: false, | |
|                 showResult: false, | |
|                 isWinner: false, | |
| 				 | |
| 				// 地址 | |
| 				addressTotal: 0, | |
| 				tabs: [ | |
| 					{ | |
| 						name: '新地址' | |
| 					}, | |
| 					{ | |
| 						name: '现有地址' | |
| 					} | |
| 				], | |
| 				addressCurrent : 0, | |
| 			} | |
| 		}, | |
| 		computed: { | |
| 			countdownText() { | |
| 				const hours = Math.floor(this.countdown / 3600) | |
| 				const minutes = Math.floor((this.countdown % 3600) / 60) | |
| 				const seconds = this.countdown % 60 | |
| 				return `${hours}时${minutes}分${seconds}秒` | |
| 			} | |
| 		}, | |
| 		methods: { | |
|             // 打开礼物动画 | |
|             openGift() { | |
|                 this.isOpening = true | |
|                 setTimeout(() => { | |
|                     this.$refs.giftPopup.close() | |
| 					this.isOpeningEnd = true | |
|                 }, 1000) | |
|             }, | |
|             // 开始抽奖 | |
|             startLottery() { | |
|                 if (this.isSpinning) return | |
| 				uni.showLoading({ | |
| 					title: '抽奖中...', | |
| 				}) | |
|                  | |
|                 this.isSpinning = true | |
|                 this.showResult = false | |
|                  | |
|                 // 模拟抽奖过程 | |
|                 setTimeout(() => { | |
| 					 | |
| 					this.$api('getGiveShopLottery', { | |
| 						orderId : this.giftId, | |
| 					}).then(res => { | |
| 						uni.hideLoading() | |
| 						this.showResult = true | |
| 						if(res.code == 200){ | |
| 							this.isWinner = !!res.result | |
| 						} | |
| 					}) | |
| 					 | |
|                     // this.isSpinning = false | |
|                      | |
|                     // 这里可以根据实际接口返回决定是否中奖 | |
|                     // this.isWinner = Math.random() > 0.5 | |
|                      | |
|                 }, 2000) | |
|             }, | |
| 			// 获取礼品信息 | |
| 			async getGiftInfo() { | |
| 				try { | |
| 					const res = await this.$api('getOrderDetail', { | |
| 						id: this.giftId | |
| 					}) | |
| 					this.giftInfo = res.result | |
| 
 | |
|                     this.$nextTick(() => { | |
|                         // 获取信息后显示弹窗 | |
| 						if(this.giftInfo.isGive == 3){ | |
| 							this.$refs.lotteryPopup.open() | |
| 						}else{ | |
| 							this.$refs.giftPopup.open() | |
| 						} | |
|                     }) | |
|                      | |
| 					// 计算倒计时 | |
| 					// if (this.giftInfo.expireTime) { | |
| 					// 	const expireTime = new Date(this.giftInfo.expireTime).getTime() | |
| 					// 	const now = new Date().getTime() | |
| 					// 	this.countdown = Math.max(0, Math.floor((expireTime - now) / 1000)) | |
| 					// 	this.startCountdown() | |
| 					// } | |
| 				} catch (e) { | |
| 					uni.showToast({ | |
| 						title: '获取礼品信息失败', | |
| 						icon: 'none' | |
| 					}) | |
| 				} | |
| 			}, | |
| 			// 领取礼品 | |
| 			async receiveGift(address) { | |
| 				try { | |
| 					let res = await this.$api('getGiveShop', { | |
| 						orderId : this.giftId, | |
| 						address : address.address, | |
| 						addressDetails : address.addressDetails, | |
| 						name : address.name, | |
| 						phone : address.phone, | |
| 					}) | |
| 					if(res.code == 200){ | |
| 						this.$refs.addressPopup.close() | |
| 						uni.showToast({ | |
| 							title: '领取成功', | |
| 							icon: 'success' | |
| 						}) | |
| 					} | |
| 					this.giftInfo.giveStatus = 1 | |
| 				} catch (e) { | |
| 					uni.showToast({ | |
| 						title: '领取失败', | |
| 						icon: 'none' | |
| 					}) | |
| 				} | |
| 			}, | |
| 			// 开始倒计时 | |
| 			startCountdown() { | |
| 				this.countdownTimer = setInterval(() => { | |
| 					if (this.countdown > 0) { | |
| 						this.countdown-- | |
| 					} else { | |
| 						clearInterval(this.countdownTimer) | |
| 					} | |
| 				}, 1000) | |
| 			}, | |
| 			// 打开选择地址 | |
| 			openAddress() { | |
| 				this.$refs.addressPopup.open('bottom') | |
| 			}, | |
| 			// 获取地址列表 | |
| 			getAddressList() { | |
| 				// 获取地址列表 | |
| 				this.$refs.addressList.getAddressList().then(res => { | |
| 					this.addressTotal = res.total | |
| 				}) | |
| 			}, | |
| 			clickTabs({index}){ | |
| 				this.addressCurrent = index | |
| 				if(index == 1){ | |
| 					this.$nextTick(() => { | |
| 						this.getAddressList() | |
| 					}) | |
| 				} | |
| 			}, | |
| 		}, | |
| 		onLoad(options) { | |
| 			if (options.shareId) { | |
| 				uni.setStorageSync('shareId', options.shareId) | |
| 			} | |
| 			if (options.id) { | |
| 				this.giftId = options.id | |
| 				if(uni.getStorageSync('token')){ | |
| 					this.getGiftInfo() | |
| 				}else{ | |
| 					this.$refs.loginPopup.open() | |
| 				} | |
| 			} | |
| 		}, | |
| 		onShow() { | |
| 		}, | |
| 		beforeDestroy() { | |
| 			if (this.countdownTimer) { | |
| 				clearInterval(this.countdownTimer) | |
| 			} | |
| 		} | |
| 	} | |
| </script> | |
| 
 | |
| <style lang="scss" scoped> | |
| .receive-gift { | |
| 	min-height: 100vh; | |
| 	background: #fff; | |
| 	 | |
| 	.main-image { | |
| 		width: 100%; | |
| 		height: 400rpx; | |
| 		 | |
| 		image { | |
| 			width: 100%; | |
| 			height: 100%; | |
| 		} | |
| 	} | |
| 	 | |
| 	.gift-info { | |
| 		padding: 30rpx; | |
| 		 | |
| 		.gift-name { | |
| 			font-size: 36rpx; | |
| 			font-weight: 600; | |
| 			color: #333; | |
| 			margin-bottom: 20rpx; | |
| 		} | |
| 		 | |
| 		.gift-value { | |
| 			font-size: 28rpx; | |
| 			color: #666; | |
| 			 | |
| 			.price { | |
| 				color: #E3441A; | |
| 				font-weight: 600; | |
| 				margin-left: 10rpx; | |
| 			} | |
| 		} | |
| 	} | |
| 	 | |
| 	.blessing-area { | |
| 		padding: 30rpx; | |
| 		background: #FFF5F5; | |
| 		margin: 30rpx; | |
| 		border-radius: 12rpx; | |
| 		 | |
| 		.sender-info { | |
| 			text-align: center; | |
| 			margin-bottom: 20rpx; | |
| 			 | |
| 			.label { | |
| 				color: #666; | |
| 				font-size: 28rpx; | |
| 			} | |
| 			 | |
| 			.sender { | |
| 				color: #333; | |
| 				font-size: 32rpx; | |
| 				font-weight: 600; | |
| 				margin: 0 10rpx; | |
| 			} | |
| 		} | |
| 		 | |
| 		.blessing-content { | |
| 			color: #333; | |
| 			font-size: 30rpx; | |
| 			line-height: 1.6; | |
| 			text-align: center; | |
| 		} | |
| 	} | |
| 	 | |
| 	.bottom-area { | |
| 		position: fixed; | |
| 		left: 0; | |
| 		bottom: 0; | |
| 		width: 100%; | |
| 		box-sizing: border-box; | |
| 		padding: 20rpx 30rpx calc(30rpx + env(safe-area-inset-bottom)) 30rpx; | |
| 		background: #fff; | |
| 		box-shadow: 0 -2rpx 10rpx rgba(0,0,0,0.05); | |
| 		z-index: 10; | |
| 		 | |
| 		.countdown { | |
| 			text-align: center; | |
| 			font-size: 28rpx; | |
| 			color: #666; | |
| 			margin-bottom: 20rpx; | |
| 			font-weight: 500; | |
| 		} | |
| 		 | |
| 		.receive-btn { | |
| 			width: 100%; | |
| 			height: 88rpx; | |
| 			line-height: 88rpx; | |
| 			background: linear-gradient(to right, #FF4B4B, #E3441A); | |
| 			color: #fff; | |
| 			border-radius: 44rpx; | |
| 			font-size: 32rpx; | |
| 			font-weight: 500; | |
| 			 | |
| 			&[disabled] { | |
| 				background: #ccc; | |
| 				opacity: 0.8; | |
| 			} | |
| 		} | |
| 	} | |
| } | |
| 
 | |
| .addressPopupTitle{ | |
|     padding: 40rpx; | |
| 	font-size: 32rpx; | |
| 	font-weight: 900; | |
| 	text-align: center; | |
| } | |
| .redactAddressForm{ | |
| 	padding: 0 40rpx; | |
| 	padding-bottom: 40rpx; | |
| 	.save { | |
| 		display: flex; | |
| 		align-items: center; | |
| 		justify-content: center; | |
| 		width: 90%; | |
| 		height: 80rpx; | |
| 		border-radius: 40rpx; | |
| 		color: white; | |
| 		font-size: 28rpx; | |
| 		margin: 0rpx auto; | |
| 		background: $uni-color; | |
| 		margin-top: 150rpx; | |
| 	} | |
| } | |
| 
 | |
| // 普通礼包开启动画 | |
| .gift-card { | |
|     position: relative; | |
|     background: $uni-color; | |
|     border-radius: 20rpx; | |
|     padding: 60rpx 40rpx; | |
|     width: 600rpx; | |
|     transform-origin: center; | |
|     transition: all 0.8s cubic-bezier(0.68, -0.55, 0.265, 1.55); | |
|      | |
|     .gift-icon { | |
|         position: absolute; | |
|         top: -60rpx; | |
|         left: 50%; | |
|         transform: translateX(-50%); | |
|         width: 120rpx; | |
|         height: 120rpx; | |
|         display: flex; | |
|         align-items: center; | |
|         justify-content: center; | |
|         transition: all 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55); | |
|         transform-origin: center bottom; | |
|         animation: giftBounce 2s infinite; | |
|     } | |
|      | |
|     .gift-content { | |
|         margin-top: 60rpx; | |
|         transform-origin: center; | |
|         transition: all 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55); | |
|         color: #fff; | |
| 		text-align: center; | |
|          | |
|         .gift-open-btn { | |
|             position: relative; | |
|             width: 120rpx; | |
|             height: 120rpx; | |
|             border-radius: 50%; | |
|             background: linear-gradient(135deg, #FF4B4B, #E3441A); | |
|             margin: 40rpx auto; | |
|             display: flex; | |
|             align-items: center; | |
|             justify-content: center; | |
|             cursor: pointer; | |
|             overflow: hidden; | |
|             box-shadow: 0 6rpx 20rpx rgba(227, 68, 26, 0.3); | |
|              | |
|             text { | |
|                 color: #fff; | |
|                 font-size: 36rpx; | |
|                 font-weight: bold; | |
|                 z-index: 1; | |
|             } | |
|              | |
|             .btn-sparkle { | |
|                 position: absolute; | |
|                 top: -50%; | |
|                 left: -50%; | |
|                 width: 200%; | |
|                 height: 200%; | |
|                 background: linear-gradient(90deg,  | |
|                     rgba(255,255,255,0) 0%, | |
|                     rgba(255,255,255,0.2) 50%, | |
|                     rgba(255,255,255,0) 100%); | |
|                 transform: rotate(45deg); | |
|                 animation: sparkle 2s infinite; | |
|             } | |
|              | |
|             &.pulse { | |
|                 animation: pulse 2s infinite; | |
|             } | |
|         } | |
| 		.gift-title{ | |
| 			color: #fff; | |
| 			font-size: 32rpx; | |
| 			font-weight: bold; | |
| 			margin-bottom: 20rpx; | |
| 		} | |
|          | |
|         .gift-title, .gift-tip { | |
|             transition: all 0.5s ease; | |
|              | |
|             &.fade { | |
|                 opacity: 0; | |
|                 transform: translateY(-20rpx); | |
|             } | |
|         } | |
|          | |
|         .gift-icon { | |
|             &.bounce { | |
|                 animation: giftBounce 2s infinite; | |
|             } | |
|         } | |
|     } | |
|      | |
|     &.open { | |
|         transform: perspective(1000px) rotateY(720deg) scale(0.5); | |
|         opacity: 0; | |
|          | |
|         .gift-icon { | |
|             transform: translateX(-50%) translateY(-200%) scale(1.5) rotate(720deg); | |
|             opacity: 0; | |
|         } | |
|          | |
|         .gift-content { | |
|             transform: scale(0) rotate(-720deg); | |
|             opacity: 0; | |
|         } | |
|     } | |
| } | |
| 
 | |
| @keyframes sparkle { | |
|     0% { | |
|         transform: rotate(45deg) translateX(-100%); | |
|     } | |
|     50% { | |
|         transform: rotate(45deg) translateX(100%); | |
|     } | |
|     100% { | |
|         transform: rotate(45deg) translateX(100%); | |
|     } | |
| } | |
| 
 | |
| @keyframes pulse { | |
|     0% { | |
|         transform: scale(1); | |
|     } | |
|     50% { | |
|         transform: scale(1.05); | |
|     } | |
|     100% { | |
|         transform: scale(1); | |
|     } | |
| } | |
| 
 | |
| // 修改原有的giftBounce动画 | |
| @keyframes giftBounce { | |
|     0%, 100% { | |
|         transform: translateX(-50%) translateY(0) rotate(0deg); | |
|     } | |
|     25% { | |
|         transform: translateX(-50%) translateY(-15rpx) rotate(-5deg); | |
|     } | |
|     75% { | |
|         transform: translateX(-50%) translateY(-15rpx) rotate(5deg); | |
|     } | |
| } | |
| 
 | |
| // 抽奖动画 | |
| .lottery-card { | |
|     width: 600rpx; | |
|     background: linear-gradient(135deg, #FF6B6B, #E3441A); | |
|     border-radius: 20rpx; | |
|     padding: 40rpx; | |
|     text-align: center; | |
|      | |
|     .lottery-title { | |
|         color: #fff; | |
|         font-size: 32rpx; | |
|         font-weight: bold; | |
|         margin-bottom: 20rpx; | |
|     } | |
|     .gift-tip{ | |
|         color: #fff; | |
|         font-size: 28rpx; | |
|         margin-bottom: 40rpx; | |
|     } | |
|      | |
|     .lottery-content { | |
|         background: #fff; | |
|         border-radius: 16rpx; | |
|         padding: 30rpx; | |
|         margin: 0 auto 30rpx; | |
|          | |
|         .product-image { | |
|             width: 300rpx; | |
|             height: 300rpx; | |
|             margin: 0 auto 20rpx; | |
|             border-radius: 8rpx; | |
|             overflow: hidden; | |
|              | |
|             image { | |
|                 width: 100%; | |
|                 height: 100%; | |
|             } | |
|         } | |
|          | |
|         .product-info { | |
|             text-align: center; | |
|              | |
|             .product-name { | |
|                 font-size: 28rpx; | |
|                 color: #333; | |
|                 margin-bottom: 10rpx; | |
|             } | |
|              | |
|             .product-price { | |
|                 font-size: 36rpx; | |
|                 color: #E3441A; | |
|                 font-weight: bold; | |
|             } | |
|         } | |
|     } | |
|      | |
|     .lottery-btn { | |
|         margin-top: 40rpx; | |
|         background: #FFD700; | |
|         color: #E3441A; | |
|         padding: 20rpx 60rpx; | |
|         border-radius: 40rpx; | |
|         display: inline-block; | |
|         font-weight: bold; | |
|         box-shadow: 0 6rpx 20rpx rgba(255, 215, 0, 0.3); | |
|     } | |
|      | |
|     .lottery-result { | |
|         margin-top: 30rpx; | |
|         color: #fff; | |
|         font-size: 32rpx; | |
|         font-weight: bold; | |
|         animation: fadeIn 0.5s ease; | |
|     } | |
| } | |
| </style> |