- <template>
 -     <view class="page">
 - 
 -         <navbar leftClick 
 -         color="#fff"
 -         bgColor="#667eea"
 -         @leftClick="$utils.navigateBack" />
 -         <view class="turntable-container">
 - 
 -             <!-- 头部标题 -->
 -             <view class="header">
 -                 <text class="title">幸运大转盘</text>
 -                 <text class="subtitle">转一转,好运来!</text>
 -             </view>
 - 
 -             <!-- 积分余额显示 -->
 -             <!-- 注释积分显示区域 -->
 -             <!-- <view class="points-display">
 -                 <view class="points-info">
 -                     <text class="points-label">当前积分:</text>
 -                     <text class="points-value">{{ userPoints }}</text>
 -                 </view>
 -                 <view class="cost-info">
 -                     <text class="cost-label">每次消耗:</text>
 -                     <text class="cost-value">{{ drawCost }}积分</text>
 -                 </view>
 -             </view> -->
 - 
 -             <!-- 转盘区域 -->
 -             <view class="turntable-wrapper" v-if="prizes.length > 0">
 -                 <view class="turntable" :class="{ 'spinning': isSpinning }" :style="{ transform: `rotate(${rotateAngle}deg)` }">
 -                     <!-- 使用纯CSS创建转盘 -->
 -                     <view class="wheel-bg">
 -                         <!-- 8个扇形区域 -->
 -                         <view 
 -                             v-for="(prize, index) in prizes" 
 -                             :key="index"
 -                             class="wheel-sector"
 -                             :style="{ 
 -                                 backgroundColor: sectorColors[index % sectorColors.length],
 -                                 transform: `rotate(${index * sectorAngle}deg)`
 -                             }"
 -                         >
 -                         </view>
 -                     </view>
 -                     
 -                     <!-- 奖品文字覆盖层 -->
 -                     <view class="prizes-overlay">
 -                         <view 
 -                             v-for="(prize, index) in prizes" 
 -                             :key="index"
 -                             class="prize-item"
 -                             :style="prizeStyles[index]"
 -                         >
 -                             <view class="prize-content">
 -                                 <text class="prize-icon">{{ getIcon(prize.type) }}</text>
 -                                 <text class="prize-name">{{ prize.title }}</text>
 -                                 <text class="prize-value" v-if="prize.price">¥{{ prize.price }}</text>
 -                             </view>
 -                         </view>
 -                     </view>
 -                 </view>
 - 
 -                 <!-- 中心指针 -->
 -                 <view class="pointer">
 -                     <view class="pointer-triangle"></view>
 -                 </view>
 - 
 -                 <!-- 中心按钮 -->
 -                 <view class="center-button" @click="startSpin" :class="{ disabled: isSpinning || userPoints < drawCost || isWatchingAd }">
 -                     <text class="button-text">{{ getButtonText() }}</text>
 -                 </view>
 -             </view>
 - 
 -             <!-- 加载中状态 -->
 -             <view v-else class="loading-wrapper">
 -                 <uv-loading-icon mode="spinner" color="#fff" size="60"></uv-loading-icon>
 -                 <text class="loading-text">加载中...</text>
 -             </view>
 - 
 -             <!-- 抽奖结果弹窗 -->
 -             <view class="result-modal" v-if="showResult" @click="closeResult">
 -                 <view class="modal-content" @click.stop>
 -                     <text class="result-title">🎉 恭喜您 🎉</text>
 -                     <view class="result-prize">
 -                         <!-- <text class="result-icon">{{ getIcon(currentPrize.type) }}</text> -->
 - 
 -                         <image :src="currentPrize.img" mode="widthFix" style="width: 100%;"></image>
 - 
 -                         <text class="result-name">{{ currentPrize.title }}</text>
 -                         <text class="result-value" v-if="currentPrize.price">¥{{ currentPrize.price }}</text>
 -                     </view>
 -                     <view class="points-change">
 -                         <text class="change-text">{{ getPointsChangeText() }}</text>
 -                     </view>
 -                     <view class="result-actions">
 -                         <button class="confirm-btn" @click="closeResult">确定</button>
 -                     </view>
 -                 </view>
 -             </view>
 - 
 -             <!-- 积分提示 -->
 -             <!-- 注释积分提示信息 -->
 -             <!-- <view class="spin-info">
 -                 <text>观看完整视频广告后消耗{{ drawCost }}积分即可抽奖,快来试试手气吧!</text>
 -             </view> -->
 -             <view class="spin-info">
 -                 <text>观看完整视频广告即可免费抽奖,快来试试手气吧!</text>
 -             </view>
 -         </view>
 -     </view>
 - </template>
 - 
 - <script>
 - 	import { mapState } from 'vuex'
 - 	import rewardedVideoAdMixin from '@/mixins/rewardedVideoAd.js'
 - 	export default {
 - 		mixins: [rewardedVideoAdMixin],
 - 		computed: {
 - 			...mapState(['userInfo']),
 - 			// 获取用户当前积分
 - 			userPoints() {
 - 				return this.userInfo?.integerPrice || 0
 - 			}
 - 		},
 - 		data() {
 - 			return {
 - 				// 奖品配置(从接口获取)
 - 				prizes: [],
 - 				sectorColors: [
 - 					'#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4',
 - 					'#FFEAA7', '#DDA0DD', '#98D8C8', '#F7DC6F'
 - 				],
 - 				isSpinning: false, // 是否正在旋转
 - 				rotateAngle: 0, // 旋转角度
 - 				totalSpinRounds: 0, // 总旋转圈数
 - 				currentAngle: 0, // 当前角度(0-360度)
 - 				showResult: false, // 显示结果弹窗
 - 				currentPrize: null, // 当前中奖奖品
 - 				sectorAngle: 0, // 每个扇形的角度
 - 				drawCost: 5, // 抽奖消耗积分
 - 				pointsChange: null, // 积分变化
 - 				// 预计算奖品位置样式
 - 				prizeStyles: []
 - 				// 视频广告相关数据已移至混入中
 - 			}
 - 		},
 - 		onLoad() {
 - 			this.getLuckDrawList()
 - 			// initRewardedVideoAd() 已在混入的mounted中处理
 - 
 -             this.rewardedRecordConfig.type = 10 // 10抽奖
 - 		},
 - 		onShow() {
 - 			// 刷新用户信息以获取最新积分
 - 			if (uni.getStorageSync('token')) {
 - 				this.$store.commit('getUserInfo')
 - 			}
 - 		},
 - 		methods: {
 - 			// 广告观看完成回调
 - 			onAdWatchComplete() {
 - 				console.log('用户看完广告,开始抽奖')
 - 				this.performDraw()
 - 			},
 - 
 - 			// 广告观看取消回调
 - 			onAdWatchCancel() {
 - 				uni.showToast({
 - 					title: '请观看完整广告才能抽奖',
 - 					icon: 'none'
 - 				})
 - 			},
 - 
 - 			// 获取抽奖列表
 - 			getLuckDrawList() {
 - 				this.$api('getLuckDrawList', {}, res => {
 - 					if (res.code == 200) {
 - 						this.prizes = res.result || []
 - 						
 - 						// 计算每个扇形的角度
 - 						if (this.prizes.length > 0) {
 - 							this.sectorAngle = 360 / this.prizes.length
 - 							this.calculatePrizeStyles()
 - 						}
 - 					} else {
 - 						uni.showToast({
 - 							title: res.message || '获取抽奖信息失败',
 - 							icon: 'none'
 - 						})
 - 					}
 - 				})
 - 			},
 - 
 - 			// 获取按钮文字
 - 			getButtonText() {
 - 				if (this.isWatchingAd) {
 - 					return '观看广告中...'
 - 				}
 - 				if (this.isSpinning) {
 - 					return '抽奖中...'
 - 				}
 - 				// 注释积分不足检查
 - 				// if (this.userPoints < this.drawCost) {
 - 				// 	return '积分不足'
 - 				// }
 - 				return '观看广告抽奖'
 - 			},
 - 
 - 			// 根据奖品类型获取图标
 - 			getIcon(type) {
 - 				const iconMap = {
 - 					'0': '💰',
 - 					'points': '⭐',
 - 					'gift': '🎁',
 - 					'coupon': '🎫',
 - 					'thanks': '🤝'
 - 				}
 - 				return iconMap[type] || '🎁'
 - 			},
 - 
 - 			// 计算奖品位置样式
 - 			calculatePrizeStyles() {
 - 				this.prizeStyles = this.prizes.map((prize, index) => {
 - 					// 计算奖品在圆形中的位置
 - 					const angle = (index * this.sectorAngle + this.sectorAngle / 2) * Math.PI / 180; // 转换为弧度
 - 					const radius = 150; // 奖品距离中心的距离
 - 					const x = Math.cos(angle - Math.PI/2) * radius; // 减去90度,因为我们希望0度在顶部
 - 					const y = Math.sin(angle - Math.PI/2) * radius;
 - 					
 - 					return `left: calc(50% + ${x}rpx); top: calc(50% + ${y}rpx); transform: translate(-50%, -50%);`
 - 				})
 - 			},
 - 
 - 			// 开始抽奖
 - 			startSpin() {
 - 				// 检查是否可以抽奖
 - 				if (this.isSpinning || this.isWatchingAd) {
 - 					return
 - 				}
 - 
 - 				// 注释积分检查逻辑
 - 				// // 检查积分是否足够
 - 				// if (this.userPoints < this.drawCost) {
 - 				// 	uni.showModal({
 - 				// 		title: '积分不足',
 - 				// 		content: `抽奖需要消耗${this.drawCost}积分,您当前积分为${this.userPoints}`,
 - 				// 		showCancel: true,
 - 				// 		cancelText: '取消',
 - 				// 		confirmText: '去赚积分',
 - 				// 		success: (res) => {
 - 				// 			if (res.confirm) {
 - 				// 				// 跳转到积分获取页面或任务页面
 - 				// 				uni.navigateBack()
 - 				// 			}
 - 				// 		}
 - 				// 	})
 - 				// 	return
 - 				// }
 - 
 - 				// 先播放广告,再进行抽奖
 - 				this.showRewardedVideoAd({
 - 					onSuccess: this.onAdWatchComplete,
 - 					onCancel: this.onAdWatchCancel,
 - 					fallbackTitle: '广告加载失败',
 - 					fallbackContent: '无法加载广告,是否直接抽奖?'
 - 				})
 - 			},
 - 
 - 			// 执行抽奖(观看广告后调用)
 - 			performDraw() {
 - 				this.isSpinning = true
 - 
 - 				// 调用抽奖接口
 - 				this.$api('luckDraw', {}, res => {
 - 					if (res.code == 200) {
 - 						const result = res.result
 - 						this.currentPrize = result.gift
 - 						this.pointsChange = result.remainingIntegral || null
 - 						
 - 						// 更新用户信息(积分变化)
 - 						this.$store.commit('getUserInfo')
 - 						
 - 						// 找到中奖奖品的索引
 - 						const prizeIndex = this.prizes.findIndex(prize => prize.id == result.gift.id)
 - 						
 - 						if (prizeIndex !== -1) {
 - 							// 计算目标角度
 - 							// 奖品在扇形中心的角度
 - 							const prizeAngle = prizeIndex * this.sectorAngle + this.sectorAngle / 2
 - 							// 要让奖品转到指针位置(0度),目标角度就是负的奖品角度
 - 							let targetAngle = -prizeAngle
 - 							
 - 							// 确保目标角度为正值(0-360度范围内)
 - 							if (targetAngle < 0) {
 - 								targetAngle += 360
 - 							}
 - 							
 - 							// 增加旋转圈数
 - 							const spinRounds = 5 // 转5圈
 - 							this.totalSpinRounds += spinRounds
 - 							this.currentAngle = targetAngle
 - 							
 - 							// 计算最终的旋转角度 = 总圈数 * 360 + 当前角度
 - 							this.rotateAngle = this.totalSpinRounds * 360 + this.currentAngle
 - 
 - 							// 动画结束后显示结果
 - 							setTimeout(() => {
 - 								this.isSpinning = false
 - 								this.showResult = true
 - 								this.handlePrizeResult()
 - 							}, 3000)
 - 						} else {
 - 							this.isSpinning = false
 - 							uni.showToast({
 - 								title: '抽奖异常,请重试',
 - 								icon: 'none'
 - 							})
 - 						}
 - 					} else {
 - 						this.isSpinning = false
 - 						uni.showToast({
 - 							title: res.message || '抽奖失败,请重试',
 - 							icon: 'none'
 - 						})
 - 					}
 - 				})
 - 			},
 - 
 - 			// 处理中奖结果
 - 			handlePrizeResult() {
 - 				if (this.currentPrize) {
 - 					console.log(`中奖信息:`, this.currentPrize)
 - 					// 根据奖品类型显示不同提示
 - 					if (this.currentPrize.type === 'money') {
 - 						console.log(`获得现金奖励: ${this.currentPrize.prizeValue}`)
 - 					} else if (this.currentPrize.type === 'points') {
 - 						console.log(`获得积分奖励: ${this.currentPrize.prizeValue}`)
 - 					} else if (this.currentPrize.type === 'gift') {
 - 						console.log(`获得礼品: ${this.currentPrize.prizeName}`)
 - 					}
 - 				}
 - 			},
 - 
 - 			// 关闭结果弹窗
 - 			closeResult() {
 - 				this.showResult = false
 - 				this.pointsChange = null
 - 				// 刷新抽奖信息
 - 				this.getLuckDrawList()
 - 			},
 - 			
 - 			// 积分变化提示文字
 - 			getPointsChangeText() {
 - 				// 注释积分消耗提示
 - 				// let text = `消耗 ${this.drawCost} 积分`
 - 				let text = `恭喜您获得奖品!`
 - 				
 - 				if (this.currentPrize && this.currentPrize.type === 'points') {
 - 					const gained = parseInt(this.currentPrize.prizeValue)
 - 					// 注释积分计算逻辑
 - 					// const net = gained - this.drawCost
 - 					// if (net > 0) {
 - 					// 	text += `,获得 ${gained} 积分,净收益 +${net} 积分`
 - 					// } else if (net < 0) {
 - 					// 	text += `,获得 ${gained} 积分,净损失 ${Math.abs(net)} 积分`
 - 					// } else {
 - 					// 	text += `,获得 ${gained} 积分,收支平衡`
 - 					// }
 - 					text = `获得 ${gained} 积分奖励!`
 - 				}
 - 				
 - 				return text
 - 			}
 - 		}
 - 	}
 - </script>
 - 
 - <style scoped lang="scss">
 - 	.turntable-container {
 - 		min-height: 100vh;
 - 		background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
 - 		padding: 40rpx;
 - 		display: flex;
 - 		flex-direction: column;
 - 		align-items: center;
 - 	}
 - 
 - 	.header {
 - 		text-align: center;
 - 		margin-bottom: 40rpx;
 - 		color: white;
 - 
 - 		.title {
 - 			font-size: 48rpx;
 - 			font-weight: bold;
 - 			display: block;
 - 			margin-bottom: 20rpx;
 - 		}
 - 
 - 		.subtitle {
 - 			font-size: 28rpx;
 - 			opacity: 0.9;
 - 		}
 - 	}
 - 
 - 	.points-display {
 - 		background: rgba(255, 255, 255, 0.2);
 - 		border-radius: 20rpx;
 - 		padding: 30rpx;
 - 		margin-bottom: 40rpx;
 - 		backdrop-filter: blur(10rpx);
 - 		display: flex;
 - 		justify-content: space-between;
 - 		align-items: center;
 - 		width: 100%;
 - 		max-width: 600rpx;
 - 
 - 		.points-info, .cost-info {
 - 			display: flex;
 - 			align-items: center;
 - 			color: white;
 - 			
 - 			.points-label, .cost-label {
 - 				font-size: 28rpx;
 - 				margin-right: 10rpx;
 - 			}
 - 			
 - 			.points-value {
 - 				font-size: 32rpx;
 - 				font-weight: bold;
 - 				color: #FFD700;
 - 			}
 - 			
 - 			.cost-value {
 - 				font-size: 28rpx;
 - 				font-weight: bold;
 - 				color: #FF6B6B;
 - 			}
 - 		}
 - 	}
 - 
 - 	.turntable-wrapper {
 - 		position: relative;
 - 		width: 600rpx;
 - 		height: 600rpx;
 - 		margin-bottom: 60rpx;
 - 	}
 - 
 - 	.loading-wrapper {
 - 		display: flex;
 - 		flex-direction: column;
 - 		align-items: center;
 - 		justify-content: center;
 - 		height: 600rpx;
 - 		
 - 		.loading-text {
 - 			color: white;
 - 			font-size: 28rpx;
 - 			margin-top: 20rpx;
 - 		}
 - 	}
 - 
 - 	.turntable {
 - 		width: 100%;
 - 		height: 100%;
 - 		border-radius: 50%;
 - 		position: relative;
 - 		transition: transform 3s cubic-bezier(0.23, 1, 0.32, 1);
 - 		box-shadow: 0 0 40rpx rgba(0, 0, 0, 0.3);
 - 		overflow: hidden;
 - 
 - 		&.spinning {
 - 			transition-duration: 3s;
 - 		}
 - 	}
 - 
 - 	.wheel-bg {
 - 		position: absolute;
 - 		width: 100%;
 - 		height: 100%;
 - 		border-radius: 50%;
 - 		overflow: hidden;
 - 	}
 - 
 - 	.wheel-sector {
 - 		position: absolute;
 - 		width: 50%;
 - 		height: 50%;
 - 		top: 0%;
 - 		left: 50%;
 - 		transform-origin: 0% 100%;
 - 		
 - 		&::before {
 - 			content: '';
 - 			position: absolute;
 - 			top: 0;
 - 			left: 0;
 - 			width: 100%;
 - 			height: 100%;
 - 			background: inherit;
 - 			clip-path: polygon(0% 100%, 50% 0%, 100% 100%);
 - 		}
 - 		
 - 		// 添加边框线
 - 		&::after {
 - 			content: '';
 - 			position: absolute;
 - 			top: 0;
 - 			left: 0;
 - 			width: 100%;
 - 			height: 100%;
 - 			border-right: 2rpx solid rgba(255,255,255,0.3);
 - 			transform-origin: 0% 100%;
 - 		}
 - 	}
 - 
 - 	.prizes-overlay {
 - 		position: absolute;
 - 		width: 100%;
 - 		height: 100%;
 - 		top: 0;
 - 		left: 0;
 - 		z-index: 990;
 - 	}
 - 
 - 	.prize-item {
 - 		position: absolute;
 - 		width: 120rpx;
 - 		height: 80rpx;
 - 		z-index: 10;
 - 	}
 - 
 - 	.prize-content {
 - 		width: 100%;
 - 		height: 100%;
 - 		display: flex;
 - 		flex-direction: column;
 - 		align-items: center;
 - 		justify-content: center;
 - 		text-align: center;
 - 		color: white;
 - 		text-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.8);
 - 
 - 		.prize-icon {
 - 			font-size: 32rpx;
 - 			display: block;
 - 			margin-bottom: 4rpx;
 - 		}
 - 
 - 		.prize-name {
 - 			font-size: 18rpx;
 - 			display: block;
 - 			font-weight: bold;
 - 			margin-bottom: 2rpx;
 - 			line-height: 1.2;
 - 		}
 - 
 - 		.prize-value {
 - 			font-size: 20rpx;
 - 			display: block;
 - 			font-weight: bold;
 - 			line-height: 1.2;
 - 		}
 - 	}
 - 
 - 	.pointer {
 - 		position: absolute;
 - 		top: -20rpx;
 - 		left: 50%;
 - 		transform: translateX(-50%);
 - 		z-index: 100;
 - 
 - 		.pointer-triangle {
 - 			width: 0;
 - 			height: 0;
 - 			border-left: 20rpx solid transparent;
 - 			border-right: 20rpx solid transparent;
 - 			border-top: 60rpx solid #FF4757;
 - 			filter: drop-shadow(0 4rpx 8rpx rgba(0, 0, 0, 0.3));
 - 		}
 - 	}
 - 
 - 	.center-button {
 - 		position: absolute;
 - 		top: 50%;
 - 		left: 50%;
 - 		transform: translate(-50%, -50%);
 - 		width: 160rpx;
 - 		height: 160rpx;
 - 		border-radius: 50%;
 - 		background: linear-gradient(145deg, #FF6B6B, #FF4757);
 - 		display: flex;
 - 		align-items: center;
 - 		justify-content: center;
 - 		box-shadow: 0 8rpx 20rpx rgba(255, 71, 87, 0.4);
 - 		z-index: 50;
 - 		transition: transform 0.2s;
 - 
 - 		&:active:not(.disabled) {
 - 			transform: translate(-50%, -50%) scale(0.95);
 - 		}
 - 
 - 		&.disabled {
 - 			opacity: 0.6;
 - 			cursor: not-allowed;
 - 			background: linear-gradient(145deg, #999, #777);
 - 		}
 - 
 - 		.button-text {
 - 			color: white;
 - 			font-size: 24rpx;
 - 			font-weight: bold;
 - 			text-align: center;
 - 		}
 - 	}
 - 
 - 	.result-modal {
 - 		position: fixed;
 - 		top: 0;
 - 		left: 0;
 - 		width: 100vw;
 - 		height: 100vh;
 - 		background: rgba(0, 0, 0, 0.7);
 - 		display: flex;
 - 		align-items: center;
 - 		justify-content: center;
 - 		z-index: 1000;
 - 
 - 		.modal-content {
 - 			background: white;
 - 			border-radius: 20rpx;
 - 			padding: 60rpx 40rpx;
 - 			text-align: center;
 - 			box-shadow: 0 20rpx 40rpx rgba(0, 0, 0, 0.3);
 - 			min-width: 500rpx;
 - 
 - 			.result-title {
 - 				font-size: 36rpx;
 - 				font-weight: bold;
 - 				color: #FF6B6B;
 - 				margin-bottom: 40rpx;
 - 			}
 - 
 - 			.result-prize {
 - 				margin-bottom: 30rpx;
 - 
 - 				.result-icon {
 - 					font-size: 60rpx;
 - 					display: block;
 - 					margin-bottom: 20rpx;
 - 				}
 - 
 - 				.result-name {
 - 					font-size: 32rpx;
 - 					color: #333;
 - 					display: block;
 - 					margin-bottom: 10rpx;
 - 				}
 - 
 - 				.result-value {
 - 					font-size: 36rpx;
 - 					color: #FF6B6B;
 - 					font-weight: bold;
 - 				}
 - 			}
 - 
 - 			.points-change {
 - 				margin-bottom: 40rpx;
 - 				padding: 20rpx;
 - 				background: #f5f5f5;
 - 				border-radius: 10rpx;
 - 				
 - 				.change-text {
 - 					font-size: 24rpx;
 - 					color: #666;
 - 					line-height: 1.4;
 - 				}
 - 			}
 - 
 - 			.confirm-btn {
 - 				background: linear-gradient(45deg, #FF6B6B, #FF4757);
 - 				color: white;
 - 				border: none;
 - 				border-radius: 40rpx;
 - 				padding: 20rpx 60rpx;
 - 				font-size: 28rpx;
 - 				font-weight: bold;
 - 			}
 - 		}
 - 	}
 - 
 - 	.spin-info {
 - 		text-align: center;
 - 		color: white;
 - 		font-size: 28rpx;
 - 		background: rgba(255, 255, 255, 0.2);
 - 		padding: 20rpx 40rpx;
 - 		border-radius: 40rpx;
 - 		backdrop-filter: blur(10rpx);
 - 	}
 - </style>
 
 
  |