珠宝小程序前端代码
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

713 lines
17 KiB

<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>