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.
1448 lines
36 KiB
1448 lines
36 KiB
<template>
|
|
<div class="wheel-container">
|
|
<!-- 顶部区域 -->
|
|
<div class="top-section">
|
|
<div class="expire-time">财富金轮到期时间:{{ expireTime }}</div>
|
|
<div class="top-right">
|
|
<div class="icon-item" @click="toggleHistory">
|
|
<img :src="historyImg" class="history-icon" alt="历史记录">
|
|
<span class="icon-text">历史记录</span>
|
|
</div>
|
|
<div class="icon-item" @click="handleRuleClick">
|
|
<img :src="ruleImg" class="rule-icon" alt="活动规则">
|
|
<span class="icon-text">活动规则</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 主标题图片 -->
|
|
<img :src="titleImg" class="title-img" alt="转动财富金轮 开启财富人生">
|
|
|
|
<!-- 转盘区域 - 完全重构 -->
|
|
<div class="wheel-section">
|
|
<div class="wheel-wrapper">
|
|
<!-- 转盘图片 -->
|
|
<img
|
|
:src="wheelImg"
|
|
class="wheel-img"
|
|
alt="财富金轮"
|
|
>
|
|
|
|
<!-- 指针系统 - 使用绝对精确的定位 -->
|
|
<div class="pointer-system">
|
|
<!-- 中心固定点 - 作为旋转参考 -->
|
|
<div class="rotation-center"></div>
|
|
|
|
<!-- 指针图片 - 使用精确的transform-origin -->
|
|
<img
|
|
src="../../assets/img/wealthGoldenWheel/pointer.png"
|
|
class="pointer-img"
|
|
:class="{ spinning: isSpinning }"
|
|
:style="{ transform: `rotate(${pointerRotation}deg)` }"
|
|
alt="指针"
|
|
>
|
|
|
|
<!-- 指针中心盖 -->
|
|
<img :src="pointerCoverImg" class="pointer-cover-img" alt="指针盖">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 剩余次数 -->
|
|
<div class="remaining-section">
|
|
<img :src="remainingBgImg" class="remaining-bg" alt="今日剩余">
|
|
<span class="remaining-text">今日剩余:{{ remainingTimes }}次</span>
|
|
</div>
|
|
|
|
<!-- 转动按钮 -->
|
|
<button
|
|
class="spin-btn"
|
|
:disabled="isSpinning || showPrizeModal || showRuleModal || isFirstVisit"
|
|
@click="handleSpin"
|
|
>
|
|
<img
|
|
:src="(remainingTimes > 0 && !showPrizeModal && !showRuleModal && !isFirstVisit) ? spinBtnImg : disabledSpinBtnImg"
|
|
alt="转动金轮"
|
|
class="spin-btn-img"
|
|
>
|
|
</button>
|
|
|
|
<!-- 中奖弹窗 -->
|
|
<div class="prize-modal" v-if="showPrizeModal">
|
|
<div class="modal-overlay" @click="closeModal"></div>
|
|
<div class="modal-content">
|
|
<img :src="modalBgImg" class="modal-bg" alt="弹窗背景">
|
|
<!-- 右上角关闭按钮 -->
|
|
<button class="close-modal" @click="closeModal">
|
|
<img :src="closeBtnImg" alt="关闭弹窗">
|
|
</button>
|
|
<div class="prize-info">
|
|
<div class="prize-title">{{ prizeMessage }}</div>
|
|
<div class="prize-amount-wrapper">
|
|
<img :src="prizeAmountImg" class="prize-amount-bg" alt="奖品数量背景">
|
|
<div class="prize-amount" :class="{ scrolling: shouldScroll }">
|
|
<span class="prize-text" v-if="shouldScroll">
|
|
{{ prizeAmount }} {{ prizeAmount }}
|
|
</span>
|
|
<span v-else>{{ prizeAmount }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 剩余次数为0时的提示弹窗 -->
|
|
<div class="no-times-modal" v-if="showNoTimesModal">
|
|
<div class="modal-overlay" @click="closeNoTimesModal"></div>
|
|
<div class="no-times-content">
|
|
<img :src="noTimesImg" class="no-times-bg" alt="今日次数已用完">
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 活动规则弹窗 -->
|
|
<div class="rule-modal" v-if="showRuleModal">
|
|
<div class="modal-overlay" @click="closeRuleModal"></div>
|
|
<div class="rule-content">
|
|
<img :src="ruleBgImg" class="rule-bg" alt="活动规则背景">
|
|
<!-- 右上角关闭按钮 -->
|
|
<button class="close-rule-btn" @click="closeRuleModal">
|
|
<img :src="closeRuleBtnImg" alt="关闭活动规则">
|
|
</button>
|
|
<div class="rule-text">
|
|
<div class="rule-line">1.在财富金轮使用期限内,每天可以转动一次</div>
|
|
<div class="rule-line">2.通过财富金轮可以获得免费Tonken和背包礼物等</div>
|
|
<div class="rule-line">3.用户通过财富金轮获得的物品以最终展示结果为准</div>
|
|
<div class="rule-line">4.Homily Link平台拥有最终解释权</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 首次访问活动规则弹窗 -->
|
|
<div class="rule-modal" v-if="isFirstVisit">
|
|
<div class="modal-overlay" @click="closeFirstVisitModal"></div>
|
|
<div class="rule-content">
|
|
<img :src="ruleBgImg" class="rule-bg" alt="活动规则背景">
|
|
<!-- 右上角关闭按钮 -->
|
|
<button class="close-rule-btn" @click="closeFirstVisitModal">
|
|
<img :src="closeRuleBtnImg" alt="关闭活动规则">
|
|
</button>
|
|
<div class="rule-text">
|
|
<div class="rule-line">1.在财富金轮使用期限内,每天可以转动一次</div>
|
|
<div class="rule-line">2.通过财富金轮可以获得免费Tonken和背包礼物等</div>
|
|
<div class="rule-line">3.用户通过财富金轮获得的物品以最终展示结果为准</div>
|
|
<div class="rule-line">4.Homily Link平台拥有最终解释权</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 右侧历史记录侧板 -->
|
|
<div class="history-record" v-if="historyRecordListVisible">
|
|
<img src="../../assets/img/wealthGoldenWheel/foldUpIcon.png"
|
|
class="fold-up" @click="toggleHistory" />
|
|
|
|
<div class="history-title">中奖记录</div>
|
|
|
|
<div style="margin-left: 45px; margin-top: 18px;">
|
|
<button v-for="item in options" :key="item.value"
|
|
:style="{
|
|
backgroundColor: selected === item.value ? '#0003bf' : '#7475b2',
|
|
borderColor: selected === item.value ? '#0003bf' : '#7475b2',
|
|
color: '#fff',
|
|
marginRight: '24px',
|
|
padding: '6px 18px',
|
|
borderRadius: '8px',
|
|
border: 'none',
|
|
cursor: 'pointer'
|
|
}"
|
|
@click="changeTypeHistoryList(item)">
|
|
{{ item.label }}
|
|
</button>
|
|
</div>
|
|
|
|
<div class="history-contents">
|
|
<!-- nowMonths(当前年) -->
|
|
<div v-if="nowMonths && nowMonths.length > 0" style="padding-left:45px;">
|
|
<div v-for="m in nowMonths" :key="m.month">
|
|
<div class="month-row" @click="toggleMonthNow(m)">
|
|
<span class="month-text">{{ m.month }}</span>
|
|
<span class="month-caret">{{ m.open ? '▼' : '▲' }}</span>
|
|
</div>
|
|
|
|
<div v-if="m.open">
|
|
<div v-if="!m.records || m.records.length === 0" class="empty-month">暂无记录</div>
|
|
<div v-for="(item, idx) in m.records" :key="item.id || idx" class="history-record-item">
|
|
<div class="left">
|
|
<div class="title" v-if="selected == 1">
|
|
<span class="circle"></span>财富金轮—{{ item.type }}
|
|
</div>
|
|
<div class="title" v-else-if="selected == 3">
|
|
<span class="circle"></span>{{ item.type }}
|
|
</div>
|
|
<div class="time">{{ item.time }}</div>
|
|
</div>
|
|
<div class="right">
|
|
<span class="token">+ {{ item.amount }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 历史年列表 -->
|
|
<div v-if="years && years.length > 0">
|
|
<div v-for="y in years" :key="y.year">
|
|
<div class="year-header" @click="toggleYear(y)" style="padding-left:14px;">
|
|
<span class="year-text">{{ y.year }}年</span>
|
|
<span class="year-caret">{{ y.expanded ? '▼' : '▲' }}</span>
|
|
</div>
|
|
<div v-if="y.expanded" class="months" style="padding-left:45px;">
|
|
<div v-for="m in y.months" :key="m.month">
|
|
<div class="month-row" @click="toggleMonth(m)">
|
|
<span class="month-text">{{ m.month }}</span>
|
|
<span class="month-caret">{{ m.open ? '▼' : '▲' }}</span>
|
|
</div>
|
|
|
|
<div v-if="m.open">
|
|
<div v-if="!m.records || m.records.length === 0" class="empty-month">暂无记录</div>
|
|
<div v-for="(item, idx) in m.records" :key="item.id || idx" class="history-record-item">
|
|
<div class="left">
|
|
<div class="title" v-if="selected == 1">
|
|
<span class="circle"></span>财富金轮—{{ item.type }}
|
|
</div>
|
|
<div class="title" v-else-if="selected == 3">
|
|
<span class="circle"></span>{{ item.type }}
|
|
</div>
|
|
<div class="time">{{ item.time }}</div>
|
|
</div>
|
|
<div class="right">
|
|
<span class="token">+ {{ item.amount }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<!-- 底部装饰 -->
|
|
<div class="history-decoration" aria-hidden="true"></div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import api from '@/utils/common.js'
|
|
import { permissionApi, lotteryApi,historyApi } from '@/api/goldenWheel'
|
|
|
|
export default {
|
|
name: 'FortuneWheel',
|
|
data() {
|
|
return {
|
|
// 图片资源
|
|
historyImg: 'https://d31zlh4on95l9h.cloudfront.net/images/aed693de6beb9faae015fd0628c4f052.png',
|
|
ruleImg: 'https://d31zlh4on95l9h.cloudfront.net/images/9a3f7680b29e31b60151cf562c0d43cb.png',
|
|
titleImg: 'https://d31zlh4on95l9h.cloudfront.net/images/a87d19806fed47b7fdf18d4b5dd70e65.png',
|
|
wheelImg: 'https://d31zlh4on95l9h.cloudfront.net/images/caaf77a490be46c56ae824d2d9aa72f4.png',
|
|
pointerCoverImg: 'https://d31zlh4on95l9h.cloudfront.net/images/19f2ea90e2560330089214e88eff04b5.png',
|
|
remainingBgImg: 'https://d31zlh4on95l9h.cloudfront.net/images/a43f0c383d55fc56b34768f039a401a8.png',
|
|
spinBtnImg: 'https://d31zlh4on95l9h.cloudfront.net/images/11b749e0fd4b08238980b74c6e80b2e6.png',
|
|
disabledSpinBtnImg: 'https://d31zlh4on95l9h.cloudfront.net/images/9b7383c1f80bb32a279791879947791a.png',
|
|
modalBgImg: 'https://d31zlh4on95l9h.cloudfront.net/images/f75ce9ca2703662fd3176dd0493f6d7b.png',
|
|
prizeAmountImg: 'https://d31zlh4on95l9h.cloudfront.net/images/878b8ea0c78bcafdaf4f6eb63a0b2eef.png',
|
|
closeBtnImg: 'https://d31zlh4on95l9h.cloudfront.net/images/453475456dad8e6832e9904c901c1274.png',
|
|
noTimesImg: 'https://d31zlh4on95l9h.cloudfront.net/images/a67e8b3de6e441af7bcb8fbbb2153ec2.png',
|
|
ruleBgImg: 'https://d31zlh4on95l9h.cloudfront.net/images/9f585ee0ab251f348a4568355ad36816.png',
|
|
closeRuleBtnImg: 'https://d31zlh4on95l9h.cloudfront.net/images/ca2ddd411ffb85968bc261382477c984.png',
|
|
|
|
// 数据
|
|
token: '',
|
|
expireTime: '',
|
|
remainingTimes: 0,
|
|
isSpinning: false,
|
|
showPrizeModal: false,
|
|
showNoTimesModal: false,
|
|
showRuleModal: false,
|
|
isFirstVisit: true,
|
|
pointerRotation: -21.5, // 指针初始旋转角度
|
|
noTimesTimer: null,
|
|
prizeMessage: '',
|
|
prizeAmount: '',
|
|
textWidth: 0,
|
|
targetPointerRotation: 0, // 指针目标旋转角度
|
|
|
|
historyRecordListVisible: false,
|
|
nowMonths: [],
|
|
years: [],
|
|
selected: 1,
|
|
options: [
|
|
{ label: 'Token', value: 1 },
|
|
{ label: '卡券', value: 3 }
|
|
],
|
|
}
|
|
},
|
|
computed: {
|
|
// 判断是否需要滚动展示
|
|
shouldScroll() {
|
|
if (!this.prizeAmount) return false;
|
|
|
|
// 判断中文字符数量
|
|
const chineseCharCount = (this.prizeAmount.match(/[\u4e00-\u9fa5]/g) || []).length;
|
|
|
|
// 判断英文字母数量
|
|
const englishCharCount = (this.prizeAmount.match(/[a-zA-Z]/g) || []).length;
|
|
|
|
// 汉字超过7个或字母超过15个时启用滚动
|
|
return chineseCharCount > 7 || englishCharCount > 15;
|
|
}
|
|
},
|
|
mounted() {
|
|
this.getTokenFromURL();
|
|
this.fetchWheelInfo();
|
|
|
|
// 预加载图片
|
|
this.preloadImages();
|
|
api.packageFun('JWsetTitle', function () {}, {
|
|
platform: 5,
|
|
title: "财富金轮"
|
|
})
|
|
},
|
|
methods: {
|
|
toggleHistory() {
|
|
this.historyRecordListVisible = !this.historyRecordListVisible
|
|
this.selected = 1
|
|
if (this.historyRecordListVisible) {
|
|
this.loadHistoryRecord()
|
|
}
|
|
},
|
|
changeTypeHistoryList(item) {
|
|
this.selected = item.value
|
|
this.loadHistoryRecord()
|
|
},
|
|
async loadHistoryRecord() {
|
|
try {
|
|
const res = await historyApi({
|
|
token: this.token,
|
|
type: this.selected
|
|
});
|
|
if (res.code === 200) {
|
|
const now_year = res.data.now_year || []
|
|
const last_year_list = res.data.last_year_list || []
|
|
|
|
this.nowMonths = (Array.isArray(now_year) ? now_year : []).map((m, idx) => ({
|
|
month: m.month,
|
|
open: idx === 0,
|
|
records: (m.list || []).map((r, ridx) => ({
|
|
id: ridx,
|
|
time: r.time,
|
|
amount: parseFloat(r.num),
|
|
type: r.name
|
|
}))
|
|
}))
|
|
|
|
this.years = (Array.isArray(last_year_list) ? last_year_list : []).map((y) => ({
|
|
year: y.year,
|
|
expanded: false,
|
|
months: (y.list || []).map((m) => ({
|
|
month: m.month,
|
|
open: false,
|
|
records: (m.list || []).map((r, ridx) => ({
|
|
id: ridx,
|
|
time: r.time,
|
|
amount: parseFloat(r.num),
|
|
type: r.name
|
|
}))
|
|
}))
|
|
}))
|
|
} else {
|
|
this.nowMonths = []
|
|
this.years = []
|
|
}
|
|
} catch (err) {
|
|
this.nowMonths = []
|
|
this.years = []
|
|
}
|
|
},
|
|
|
|
toggleMonthNow(m) {
|
|
m.open = !m.open
|
|
},
|
|
toggleYear(y) {
|
|
y.expanded = !y.expanded
|
|
},
|
|
toggleMonth(m) {
|
|
m.open = !m.open
|
|
},
|
|
// 预加载图片以提高性能
|
|
preloadImages() {
|
|
const images = [
|
|
this.historyImg, this.ruleImg, this.titleImg, this.wheelImg,
|
|
this.pointerCoverImg, this.remainingBgImg,
|
|
this.spinBtnImg, this.disabledSpinBtnImg, this.modalBgImg,
|
|
this.prizeAmountImg, this.closeBtnImg, this.noTimesImg,
|
|
this.ruleBgImg, this.closeRuleBtnImg
|
|
];
|
|
|
|
images.forEach(src => {
|
|
const img = new Image();
|
|
img.src = src;
|
|
});
|
|
},
|
|
|
|
getTokenFromURL() {
|
|
// 首先尝试从URL获取token
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|
const tokenParam = urlParams.get('token');
|
|
|
|
if (tokenParam) {
|
|
// 如果URL中有token,保存到localStorage并设置到组件
|
|
const decodedToken = decodeURIComponent(tokenParam);
|
|
localStorage.setItem('fortuneWheelToken', decodedToken);
|
|
this.token = decodedToken;
|
|
} else {
|
|
// 如果URL中没有token,尝试从localStorage获取
|
|
const storedToken = localStorage.getItem('fortuneWheelToken');
|
|
if (storedToken) {
|
|
this.token = storedToken;
|
|
} else {
|
|
console.log('URL和localStorage中都没有找到token');
|
|
// 这里可以添加处理没有token的情况,比如跳转到登录页
|
|
}
|
|
}
|
|
},
|
|
|
|
// 调用API获取财富金轮信息
|
|
fetchWheelInfo() {
|
|
if (!this.token) {
|
|
console.error('Token为空,无法调用API');
|
|
return;
|
|
}
|
|
|
|
permissionApi({ token: this.token }).then(res => {
|
|
if(res.code === 200){
|
|
this.expireTime = res.data.deadline;
|
|
this.remainingTimes = res.data.count;
|
|
} else {
|
|
console.error('API返回错误:', res.msg);
|
|
}
|
|
}).catch(error => {
|
|
console.error('API调用失败:', error);
|
|
});
|
|
},
|
|
|
|
// 调用抽奖API获取奖品信息
|
|
async fetchPrizeInfo() {
|
|
if (!this.token) {
|
|
console.error('Token为空,无法调用抽奖API');
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
// 调用抽奖API
|
|
const res = await lotteryApi({ token: this.token });
|
|
|
|
if(res.code === 200){
|
|
// 解析API返回的字符串数据
|
|
const prizeData = res.data;
|
|
|
|
// 关键修改:按照第一个空格分割字符串
|
|
const firstSpaceIndex = prizeData.indexOf(' ');
|
|
|
|
if (firstSpaceIndex !== -1) {
|
|
// 第一个空格前面的部分作为prizeMessage
|
|
this.prizeMessage = prizeData.substring(0, firstSpaceIndex);
|
|
// 第一个空格后面的部分作为prizeAmount
|
|
this.prizeAmount = prizeData.substring(firstSpaceIndex + 1);
|
|
} else {
|
|
// 如果没有空格,整个字符串作为prizeMessage,prizeAmount为空
|
|
this.prizeMessage = prizeData;
|
|
this.prizeAmount = '';
|
|
}
|
|
|
|
// 抽奖API执行完成后,查询最新的剩余次数
|
|
await this.fetchWheelInfo();
|
|
|
|
return true;
|
|
} else {
|
|
console.error('抽奖API返回错误:', res.msg);
|
|
// 设置默认值
|
|
this.prizeMessage = '抽奖失败';
|
|
this.prizeAmount = '请重试';
|
|
|
|
// 即使抽奖失败,也查询最新的剩余次数
|
|
await this.fetchWheelInfo();
|
|
|
|
return false;
|
|
}
|
|
} catch (error) {
|
|
console.error('抽奖API调用失败:', error);
|
|
// 设置默认值
|
|
this.prizeMessage = '网络错误';
|
|
this.prizeAmount = '请重试';
|
|
|
|
// 即使抽奖失败,也查询最新的剩余次数
|
|
await this.fetchWheelInfo();
|
|
|
|
return false;
|
|
}
|
|
},
|
|
|
|
// 计算随机停止位置
|
|
calculateRandomStop() {
|
|
// 转盘有8个区域,每个区域45度
|
|
const sectorDegrees = 45;
|
|
|
|
// 随机选择一个区域 (0-7)
|
|
const randomSector = Math.floor(Math.random() * 8);
|
|
|
|
// 计算目标角度:从初始位置(-21.5度)到选中区域的中心
|
|
// 每个区域中心的角度 = 区域索引 * 45度 - 22.5度
|
|
const targetAngle = randomSector * sectorDegrees - 21.5;
|
|
|
|
// 计算需要旋转的总角度(确保多转几圈)
|
|
// 从当前位置旋转到目标位置,加上多转的圈数(3-5圈)
|
|
const extraRotations = 3 + Math.floor(Math.random() * 3); // 4-5圈
|
|
const extraDegrees = extraRotations * 360;
|
|
|
|
// 计算最终旋转角度
|
|
// 从当前角度旋转到目标角度,加上额外的圈数
|
|
// 注意:需要确保旋转方向正确
|
|
let rotationNeeded = targetAngle - this.pointerRotation;
|
|
|
|
// 如果旋转角度为负,加上360度使其为正
|
|
if (rotationNeeded < 0) {
|
|
rotationNeeded += 360;
|
|
}
|
|
|
|
// 加上额外的圈数
|
|
return this.pointerRotation + rotationNeeded + extraDegrees;
|
|
},
|
|
|
|
// 处理转动
|
|
async handleSpin() {
|
|
if (this.showRuleModal || this.isFirstVisit || this.isSpinning) return;
|
|
|
|
// 先查询剩余次数
|
|
try {
|
|
if (this.remainingTimes <= 0) {
|
|
this.showNoTimesModal = true;
|
|
|
|
if (this.noTimesTimer) {
|
|
clearTimeout(this.noTimesTimer);
|
|
}
|
|
this.noTimesTimer = setTimeout(() => {
|
|
this.showNoTimesModal = false;
|
|
}, 3000);
|
|
|
|
return;
|
|
}
|
|
|
|
// 有剩余次数,开始抽奖
|
|
this.isSpinning = true;
|
|
|
|
// 计算随机停止位置
|
|
this.targetPointerRotation = this.calculateRandomStop();
|
|
|
|
// 设置CSS变量,用于动画
|
|
document.documentElement.style.setProperty('--target-pointer-rotation', `${this.targetPointerRotation}deg`);
|
|
|
|
// 开始旋转动画
|
|
this.pointerRotation = this.targetPointerRotation;
|
|
|
|
// 调用抽奖API获取奖品信息
|
|
const success = await this.fetchPrizeInfo();
|
|
|
|
setTimeout(() => {
|
|
this.isSpinning = false;
|
|
|
|
if (success) {
|
|
setTimeout(() => {
|
|
this.showPrizeModal = true;
|
|
}, 500);
|
|
}
|
|
}, 5000);
|
|
|
|
} catch (error) {
|
|
console.error('查询剩余次数失败:', error);
|
|
this.isSpinning = false;
|
|
}
|
|
},
|
|
|
|
// 处理活动规则点击
|
|
handleRuleClick() {
|
|
this.showRuleModal = true;
|
|
},
|
|
|
|
// 关闭弹窗
|
|
closeModal() {
|
|
this.showPrizeModal = false;
|
|
},
|
|
|
|
// 关闭无次数提示弹窗
|
|
closeNoTimesModal() {
|
|
this.showNoTimesModal = false;
|
|
if (this.noTimesTimer) {
|
|
clearTimeout(this.noTimesTimer);
|
|
}
|
|
},
|
|
|
|
// 关闭活动规则弹窗
|
|
closeRuleModal() {
|
|
this.showRuleModal = false;
|
|
},
|
|
|
|
// 关闭首次访问弹窗
|
|
closeFirstVisitModal() {
|
|
this.isFirstVisit = false;
|
|
},
|
|
|
|
// 跳转到历史记录页面
|
|
goToHistory() {
|
|
this.$router.push('/history');
|
|
},
|
|
|
|
// 计算文本宽度,动态设置动画
|
|
calcTextWidth() {
|
|
if (!this.shouldScroll || !this.prizeAmount) return;
|
|
|
|
// 创建临时元素,用于计算文本宽度
|
|
const tempSpan = document.createElement('span');
|
|
tempSpan.style.visibility = 'hidden';
|
|
tempSpan.style.position = 'absolute';
|
|
tempSpan.style.whiteSpace = 'nowrap';
|
|
tempSpan.style.fontSize = '25px';
|
|
tempSpan.style.fontWeight = 'bold';
|
|
tempSpan.style.fontFamily = 'inherit';
|
|
tempSpan.textContent = this.prizeAmount;
|
|
|
|
document.body.appendChild(tempSpan);
|
|
|
|
// 获取单个文本宽度
|
|
this.textWidth = tempSpan.offsetWidth;
|
|
document.body.removeChild(tempSpan);
|
|
|
|
// 移除现有的样式
|
|
const existingStyle = document.getElementById('scroll-animation-style');
|
|
if (existingStyle) {
|
|
existingStyle.remove();
|
|
}
|
|
|
|
// 动态设置滚动动画
|
|
const style = document.createElement('style');
|
|
style.id = 'scroll-animation-style';
|
|
style.textContent = `
|
|
@keyframes seamless-scroll {
|
|
0% { transform: translateX(0); }
|
|
100% { transform: translateX(-${this.textWidth + 20}px); }
|
|
}
|
|
@media (max-width: 380px) {
|
|
@keyframes seamless-scroll {
|
|
0% { transform: translateX(0); }
|
|
100% { transform: translateX(-${this.textWidth + 16}px); }
|
|
}
|
|
}
|
|
.prize-amount.scrolling .prize-text {
|
|
animation: seamless-scroll ${Math.max(5, this.textWidth / 30)}s linear infinite;
|
|
padding-right: 20px;
|
|
display: inline-block;
|
|
}
|
|
`;
|
|
|
|
document.head.appendChild(style);
|
|
}
|
|
},
|
|
watch: {
|
|
// 当奖品金额变化时,重新计算文本宽度
|
|
prizeAmount(newVal) {
|
|
if (newVal && this.shouldScroll) {
|
|
this.$nextTick(() => {
|
|
this.calcTextWidth();
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.wheel-container {
|
|
min-height: 100vh;
|
|
background-image: url('../../assets/img/wealthGoldenWheel/bg.png');
|
|
background-size: cover;
|
|
background-position: bottom center;
|
|
padding: 15px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
position: relative;
|
|
}
|
|
|
|
/* 顶部区域样式 */
|
|
.top-section {
|
|
width: 100%;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: flex-start;
|
|
margin-bottom: 15px;
|
|
}
|
|
|
|
.expire-time {
|
|
color: #fff;
|
|
font-size: 12px;
|
|
font-weight: bold;
|
|
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
|
|
margin: 11px 0 0 12px;
|
|
}
|
|
|
|
.top-right {
|
|
display: flex;
|
|
gap: 20px;
|
|
align-items: center;
|
|
}
|
|
|
|
.icon-item {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
gap: 4px;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.history-icon, .rule-icon {
|
|
width: 25px;
|
|
height: 25px;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.icon-text {
|
|
color: #fff;
|
|
font-size: 11px;
|
|
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.8);
|
|
}
|
|
|
|
/* 主标题图片样式 */
|
|
.title-img {
|
|
width: 327px;
|
|
height: 144px;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
/* 转盘区域样式 */
|
|
.wheel-section {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
margin-bottom: 15px;
|
|
position: relative;
|
|
}
|
|
|
|
.wheel-wrapper {
|
|
position: relative;
|
|
width: 333px;
|
|
height: 333px;
|
|
}
|
|
|
|
.wheel-img {
|
|
width: 100%;
|
|
height: 100%;
|
|
transform: rotate(-22.5deg);
|
|
}
|
|
|
|
/* 指针系统 - 完全重构 */
|
|
.pointer-system {
|
|
position: absolute;
|
|
top: 50%;
|
|
left: 50%;
|
|
width: 137px;
|
|
height: 137px;
|
|
transform: translate(-50%, -50%);
|
|
z-index: 2;
|
|
}
|
|
|
|
/* 中心固定点 - 用于调试和参考 */
|
|
.rotation-center {
|
|
position: absolute;
|
|
top: 50%;
|
|
left: 50%;
|
|
width: 4px;
|
|
height: 4px;
|
|
background: red;
|
|
border-radius: 50%;
|
|
transform: translate(-50%, -50%);
|
|
z-index: 4;
|
|
opacity: 0; /* 调试时可设置为1查看中心点 */
|
|
}
|
|
|
|
/* 指针底座 - 提供固定参考点 */
|
|
.pointer-base {
|
|
position: relative;
|
|
width: 137px;
|
|
height: 137px;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
transform: translateZ(0); /* 启用GPU加速 */
|
|
}
|
|
|
|
/* 指针图片 - 关键优化 */
|
|
.pointer-img {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 137px;
|
|
height: 137px;
|
|
/* 精确计算旋转中心点 */
|
|
transform-origin: 68.5px 68.5px; /* 137px / 2 = 68.5px */
|
|
transform: rotate(-21.5deg);
|
|
transition: transform 0.1s linear;
|
|
image-rendering: crisp-edges;
|
|
-webkit-font-smoothing: subpixel-antialiased;
|
|
backface-visibility: hidden;
|
|
perspective: 1000px;
|
|
will-change: transform;
|
|
}
|
|
|
|
/* 旋转动画 - 使用requestAnimationFrame优化 */
|
|
.pointer-img.spinning {
|
|
animation: smooth-spin 3s cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards;
|
|
/* 添加这些属性确保性能 */
|
|
backface-visibility: hidden;
|
|
transform: translateZ(0);
|
|
will-change: transform;
|
|
}
|
|
|
|
@keyframes smooth-spin {
|
|
0% {
|
|
transform: rotate(-21.5deg);
|
|
animation-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
|
}
|
|
100% {
|
|
transform: rotate(var(--target-pointer-rotation, 1440deg));
|
|
}
|
|
}
|
|
|
|
/* 指针盖样式 */
|
|
.pointer-cover-img {
|
|
position: absolute;
|
|
top: 50%;
|
|
left: 50%;
|
|
width: 104px;
|
|
height: 104px;
|
|
transform: translate(-50%, -50%);
|
|
z-index: 3;
|
|
pointer-events: none;
|
|
}
|
|
|
|
/* 剩余次数样式 */
|
|
.remaining-section {
|
|
position: relative;
|
|
margin-bottom: 20px;
|
|
display: flex;
|
|
justify-content: center;
|
|
margin-top: -5px;
|
|
}
|
|
|
|
.remaining-bg {
|
|
width: 104px;
|
|
height: 21.5px;
|
|
}
|
|
|
|
.remaining-text {
|
|
position: absolute;
|
|
top: 50%;
|
|
left: 50%;
|
|
transform: translate(-50%, -50%);
|
|
color: #fff;
|
|
font-size: 12px;
|
|
font-weight: bold;
|
|
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.8);
|
|
width: 100%;
|
|
text-align: center;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
/* 转动按钮样式 */
|
|
.spin-btn {
|
|
background: none;
|
|
border: none;
|
|
cursor: pointer;
|
|
transition: transform 0.2s ease;
|
|
padding: 0;
|
|
}
|
|
|
|
.spin-btn:active:not(:disabled) {
|
|
transform: scale(0.95);
|
|
}
|
|
|
|
.spin-btn:disabled {
|
|
cursor: not-allowed;
|
|
opacity: 0.7;
|
|
}
|
|
|
|
.spin-btn-img {
|
|
width: 240px;
|
|
height: 94px;
|
|
}
|
|
|
|
/* 弹窗样式 */
|
|
.prize-modal, .no-times-modal, .rule-modal {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
z-index: 1000;
|
|
}
|
|
|
|
.modal-overlay {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background-color: rgba(0, 0, 0, 0.7);
|
|
}
|
|
|
|
/* 中奖弹窗内容区域尺寸为333x377 */
|
|
.modal-content {
|
|
position: relative;
|
|
width: 333px;
|
|
height: 377px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
z-index: 1001;
|
|
animation: modal-appear 0.3s ease-out;
|
|
}
|
|
|
|
@keyframes modal-appear {
|
|
from {
|
|
opacity: 0;
|
|
transform: scale(0.8) translateY(-20px);
|
|
}
|
|
to {
|
|
opacity: 1;
|
|
transform: scale(1) translateY(0);
|
|
}
|
|
}
|
|
|
|
.modal-bg {
|
|
position: absolute;
|
|
width: 100%;
|
|
height: 100%;
|
|
z-index: -1;
|
|
}
|
|
|
|
/* 无次数提示弹窗样式 */
|
|
.no-times-content {
|
|
position: relative;
|
|
width: 333px;
|
|
height: 79px;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
z-index: 1001;
|
|
margin-top: 250px;
|
|
animation: slide-up 0.3s ease-out;
|
|
}
|
|
|
|
@keyframes slide-up {
|
|
from {
|
|
opacity: 0;
|
|
transform: translateY(20px);
|
|
}
|
|
to {
|
|
opacity: 1;
|
|
transform: translateY(0);
|
|
}
|
|
}
|
|
|
|
.no-times-bg {
|
|
position: absolute;
|
|
width: 100%;
|
|
height: 100%;
|
|
z-index: -1;
|
|
}
|
|
|
|
/* 弹窗内容样式 */
|
|
.prize-info {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
text-align: center;
|
|
z-index: 2;
|
|
margin-top: 120px;
|
|
}
|
|
|
|
.prize-title {
|
|
color: #B82525;
|
|
font-size: 25px;
|
|
font-weight: bold;
|
|
margin-bottom: 35px;
|
|
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
|
|
animation: text-pulse 2s infinite;
|
|
}
|
|
|
|
@keyframes text-pulse {
|
|
0%, 100% {
|
|
transform: scale(1);
|
|
}
|
|
50% {
|
|
transform: scale(1.05);
|
|
}
|
|
}
|
|
|
|
/* 奖品数量样式 - 优化后的样式 */
|
|
.prize-amount-wrapper {
|
|
position: relative;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
margin-top: 20px;
|
|
width: 272px;
|
|
height: 58px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.prize-amount-bg {
|
|
position: absolute;
|
|
width: 272px;
|
|
height: 58px;
|
|
z-index: 1;
|
|
}
|
|
|
|
.prize-amount {
|
|
position: absolute;
|
|
top: 50%;
|
|
left: 50%;
|
|
transform: translate(-50%, -50%);
|
|
color: #FFFFFF;
|
|
font-size: 25px;
|
|
font-weight: bold;
|
|
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.8);
|
|
width: 240px;
|
|
text-align: center;
|
|
white-space: nowrap;
|
|
z-index: 2;
|
|
overflow: hidden;
|
|
}
|
|
|
|
/* 滚动状态:限制文本显示区域,确保仅容器内文本可见 */
|
|
.prize-amount.scrolling {
|
|
width: 170px;
|
|
text-align: left;
|
|
}
|
|
|
|
|
|
/* 滚动文本容器 */
|
|
.prize-amount.scrolling .prize-text {
|
|
will-change: transform;
|
|
backface-visibility: hidden;
|
|
transform: translateZ(0);
|
|
}
|
|
|
|
/* 关闭按钮样式 - 修改位置 */
|
|
.close-modal {
|
|
position: absolute;
|
|
top: 115px;
|
|
right: 22px;
|
|
background: none;
|
|
border: none;
|
|
cursor: pointer;
|
|
z-index: 1002;
|
|
transition: transform 0.2s ease;
|
|
padding: 0;
|
|
}
|
|
|
|
.close-modal:hover {
|
|
transform: scale(1.1);
|
|
}
|
|
|
|
.close-modal img {
|
|
width: 35px;
|
|
height: 35px;
|
|
}
|
|
|
|
/* 活动规则弹窗样式 - 整体下移 */
|
|
.rule-content {
|
|
position: relative;
|
|
width: 333px;
|
|
height: 239px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
z-index: 1001;
|
|
animation: modal-appear 0.3s ease-out;
|
|
margin-top: 80px;
|
|
}
|
|
|
|
.rule-bg {
|
|
position: absolute;
|
|
width: 100%;
|
|
height: 100%;
|
|
z-index: -1;
|
|
}
|
|
|
|
/* 活动规则关闭按钮 - 修复:确保按钮层级高于背景 */
|
|
.close-rule-btn {
|
|
position: absolute;
|
|
top: 45.5px;
|
|
right: 35.5px;
|
|
background: none;
|
|
border: none;
|
|
cursor: pointer;
|
|
z-index: 1002;
|
|
transition: transform 0.2s ease;
|
|
padding: 0;
|
|
width: 30px;
|
|
height: 30px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.close-rule-btn:hover {
|
|
transform: scale(1.1);
|
|
}
|
|
|
|
.close-rule-btn img {
|
|
width: 20px;
|
|
height: 20px;
|
|
display: block;
|
|
}
|
|
|
|
/* 活动规则文本 */
|
|
.rule-text {
|
|
position: absolute;
|
|
top: 83px;
|
|
left: 27px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 9.15px;
|
|
width: calc(100% - 54px);
|
|
}
|
|
|
|
.rule-line {
|
|
color: #FFFFFF;
|
|
font-size: 12px;
|
|
line-height: 1.4;
|
|
}
|
|
|
|
/* 媒体查询 - 适配小屏幕 */
|
|
@media (max-width: 380px) {
|
|
.title-img {
|
|
width: 280px;
|
|
height: 123px;
|
|
}
|
|
|
|
.wheel-wrapper {
|
|
width: 280px;
|
|
height: 280px;
|
|
}
|
|
|
|
.pointer-container {
|
|
width: 115px;
|
|
height: 115px;
|
|
}
|
|
|
|
.pointer-system {
|
|
width: 115px;
|
|
height: 115px;
|
|
}
|
|
|
|
.pointer-system {
|
|
width: 115px;
|
|
height: 115px;
|
|
}
|
|
|
|
.pointer-cover-img {
|
|
width: 70px;
|
|
height: 70px;
|
|
}
|
|
|
|
.spin-btn-img {
|
|
width: 200px;
|
|
height: 78px;
|
|
}
|
|
|
|
.top-right {
|
|
gap: 15px;
|
|
}
|
|
|
|
.remaining-section {
|
|
margin-top: -8px;
|
|
}
|
|
|
|
/* 小屏幕适配中奖弹窗 */
|
|
.modal-content {
|
|
width: 300px;
|
|
height: 340px;
|
|
}
|
|
.prize-info {
|
|
margin-top: 100px;
|
|
}
|
|
|
|
.prize-title {
|
|
margin-bottom: 30px;
|
|
}
|
|
|
|
.prize-amount-wrapper {
|
|
margin-top: 18px;
|
|
width: 240px;
|
|
height: 51px;
|
|
}
|
|
|
|
.prize-amount-bg {
|
|
width: 240px;
|
|
height: 51px;
|
|
}
|
|
|
|
.prize-amount {
|
|
font-size: 22px;
|
|
width: 210px;
|
|
}
|
|
|
|
.prize-amount.scrolling {
|
|
width: 190px;
|
|
}
|
|
|
|
.no-times-content {
|
|
width: 280px;
|
|
height: 66px;
|
|
margin-top: 200px;
|
|
}
|
|
|
|
/* 小屏幕适配关闭按钮位置 */
|
|
.close-modal {
|
|
top: 100px;
|
|
right: 18px;
|
|
}
|
|
.close-modal img {
|
|
width: 30px;
|
|
height: 30px;
|
|
}
|
|
|
|
/* 小屏幕适配活动规则弹窗 */
|
|
.rule-content {
|
|
width: 300px;
|
|
height: 215px;
|
|
margin-top: 70px;
|
|
}
|
|
|
|
.close-rule-btn {
|
|
top: 41px;
|
|
right: 32px;
|
|
}
|
|
|
|
.rule-text {
|
|
top: 75px;
|
|
left: 24px;
|
|
width: calc(100% - 48px);
|
|
}
|
|
}
|
|
.fold-up {
|
|
width: 30px;
|
|
height: 30px;
|
|
position: absolute;
|
|
top: 20px;
|
|
left: 45px;
|
|
cursor: pointer;
|
|
z-index: 999;
|
|
}
|
|
|
|
.history-title {
|
|
padding-top: 12px;
|
|
display: flex;
|
|
justify-content: center;
|
|
width: 100%;
|
|
color: #00e5ff;
|
|
font-size: 32px;
|
|
font-weight: 700;
|
|
}
|
|
|
|
.history-record {
|
|
background: #080A6D;
|
|
position: fixed;
|
|
right: 0;
|
|
bottom: 0;
|
|
width: 90%;
|
|
height: 100vh;
|
|
display: flex;
|
|
flex-direction: column;
|
|
--bottom-cut-height: 220px;
|
|
overflow: hidden;
|
|
z-index: 2000;
|
|
box-shadow: -8px 0 24px rgba(0,0,0,0.6);
|
|
border-left: 1px solid rgba(255,255,255,0.03);
|
|
padding-bottom: 0;
|
|
}
|
|
|
|
.history-contents {
|
|
margin-top: 20px;
|
|
padding-right: 10px;
|
|
flex: 1 1 auto;
|
|
overflow-y: auto;
|
|
-webkit-overflow-scrolling: touch;
|
|
direction: rtl;
|
|
}
|
|
.history-contents > * { direction: ltr; }
|
|
.history-contents * { direction: ltr; }
|
|
|
|
.history-contents::-webkit-scrollbar {
|
|
width: 14px;
|
|
background-color: #20086d;
|
|
}
|
|
.history-contents::-webkit-scrollbar-thumb {
|
|
background-color: #4a4de6;
|
|
border-radius: 4px;
|
|
}
|
|
.history-contents::-webkit-scrollbar-thumb:hover {
|
|
background-color: #6b6ef5;
|
|
}
|
|
|
|
.history-decoration {
|
|
flex: 0 0 200px;
|
|
height: var(--bottom-cut-height);
|
|
position: relative;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
width: 100%;
|
|
pointer-events: none;
|
|
z-index: 0;
|
|
background-image: url('../../assets/img/wealthGoldenWheel/bottomDecoration.png');
|
|
background-repeat: no-repeat;
|
|
background-position: center bottom;
|
|
background-size: contain;
|
|
margin-top: 0;
|
|
}
|
|
|
|
/* 记录项样式 */
|
|
.history-record-item {
|
|
background: #0b0d99;
|
|
margin-bottom: 10px;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
width: 80%;
|
|
padding: 8px;
|
|
border-radius: 8px;
|
|
}
|
|
|
|
.history-record-item .left {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 6px;
|
|
min-width: 0;
|
|
padding: 5px;
|
|
}
|
|
|
|
.history-record-item .title {
|
|
color: #f2f5ff;
|
|
font-size: 16px;
|
|
font-weight: 700;
|
|
white-space: nowrap;
|
|
text-overflow: ellipsis;
|
|
overflow: hidden;
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.history-record-item .time {
|
|
font-size: 12px;
|
|
color: #e6ecff;
|
|
font-weight: 700;
|
|
margin-left: 28px;
|
|
}
|
|
|
|
.history-record-item .right {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: flex-end;
|
|
min-width: 72px;
|
|
padding-right: 10px;
|
|
}
|
|
|
|
.history-record-item .token {
|
|
color: #00e6ff;
|
|
font-size: 16px;
|
|
font-weight: 700;
|
|
}
|
|
.circle {
|
|
width: 10px;
|
|
height: 10px;
|
|
background-color: #fff;
|
|
margin-right: 8px;
|
|
flex-shrink: 0;
|
|
margin-left: 10px;
|
|
border-radius: 50%;
|
|
}
|
|
|
|
.month-row,
|
|
.year-header {
|
|
display: flex;
|
|
align-items: center;
|
|
padding-bottom: 12px;
|
|
cursor: pointer;
|
|
color: #ffffff;
|
|
font-weight: 700;
|
|
}
|
|
|
|
.month-text,
|
|
.year-text {
|
|
font-weight: 700;
|
|
font-size: 16px;
|
|
color: #ffffff;
|
|
}
|
|
|
|
.month-caret,
|
|
.year-caret {
|
|
margin-left: 10px;
|
|
font-size: 16px;
|
|
color: #ffffff;
|
|
}
|
|
|
|
.empty-month {
|
|
padding: 8px;
|
|
color: #cfd9ff;
|
|
background: transparent;
|
|
}
|
|
|
|
@media (max-width: 900px) {
|
|
.history-record { width: 90%; }
|
|
.history-record-item { width: calc(100% - 60px); }
|
|
}
|
|
@media (max-width: 430px) {
|
|
.history-record-item .title {
|
|
font-size: 12px;
|
|
}
|
|
|
|
.history-record-item .time {
|
|
font-size: 10px;
|
|
margin-left:10px;
|
|
}
|
|
|
|
.history-record-item .token {
|
|
font-size: 14px;
|
|
}
|
|
|
|
.history-record-item .right {
|
|
padding-right: 5px;
|
|
}
|
|
.circle {
|
|
width: 8px;
|
|
height: 8px;
|
|
margin-left: 0px;
|
|
}
|
|
.month-caret,
|
|
.year-caret {
|
|
margin-left: 5px;
|
|
}
|
|
}
|
|
|
|
</style>
|