1566 lines
42 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>
<div class="fullPage">
<!-- 预加载状态 -->
<div v-show="isLoading" class="loading-container">
<div class="loading-spinner"></div>
<p>{{ $t('loading') }}...</p>
</div>
<!-- 主要内容 -->
<div
v-show="!isLoading"
style="width: 100vw; min-height: 100vh; overflow: hidden; position: relative"
>
<!-- 页面背景 -->
<BackgroundLayer
v-show="!RankingShow"
:backgroundImages="[
imageUrl('bg1'),
imageUrl('bg2'),
imageUrl('bg3'),
imageUrl('bg4'),
imageUrl('bg5'),
]"
/>
<!-- 排行榜页面背景 -->
<BackgroundLayer
v-show="RankingShow"
:backgroundImages="[imageUrl('bg1'), imageUrl('bg2-2')]"
/>
<!-- 重复的背景图层 -->
<div
v-show="RankingShow"
class="background-overlay"
:style="{ '--bg3-2-url': `url(${imageUrl('bg3-2')})` }"
></div>
<!-- 页面内容 -->
<div
style="
position: relative;
z-index: 1;
display: flex;
flex-direction: column;
align-items: center;
gap: 4vw;
"
>
<!-- 头部动画 -->
<img v-smart-img :src="webpUrl('pageTop')" alt="" width="100%" style="display: block" />
<!-- 倒计时 -->
<itemCenter
style="width: 95%; min-width: 0; margin-top: -52vw"
:imgUrl="imageUrl('TimeBg')"
contentStyle="padding:0 14.5vw 6vw 13.5vw;"
><!-- 倒计时 -->
<div class="timeBox">
<div class="timeBoxItem">
<div class="timeText" style="">{{ Days }}D</div>
</div>
<div class="timeBoxItem">
<div class="timeText" style="">{{ Hours }}</div>
</div>
<div class="timeBoxItem">
<div class="timeText" style="">{{ Minutes }}</div>
</div>
<div class="timeBoxItem">
<div class="timeText" style="">{{ Seconds }}</div>
</div>
</div>
</itemCenter>
<!-- 标签页按钮 -->
<div
style="
width: 90vw;
display: flex;
justify-content: center;
align-items: center;
gap: 10vw;
"
>
<!-- 游戏栏目按钮 -->
<div style="flex: 1; min-width: 0" @click="changeTag('gamePlay')">
<img
v-smart-img
:src="imageUrl(getImgName('TagGameBt'))"
alt=""
:class="{
'grayscale-container': !GamePlayShow,
}"
style="width: 100%; display: block; object-fit: cover"
/>
</div>
<!-- 充值栏目按钮 -->
<div style="flex: 1; min-width: 0" @click="changeTag('recharge')">
<img
v-smart-img
:src="imageUrl(getImgName('TagRechargeBt'))"
alt=""
:class="{
'grayscale-container': !RechargeShow,
}"
style="width: 100%; display: block; object-fit: cover"
/>
</div>
</div>
<!-- 游戏标签页 -->
<div
v-show="GamePlayShow"
style="display: flex; flex-direction: column; align-items: center; gap: 4vw"
>
<!-- 模块按钮 -->
<div
style="
width: 100vw;
display: flex;
justify-content: space-around;
align-items: center;
"
>
<!-- 任务模块按钮 -->
<div style="width: 30vw; min-width: 0" @click="changeModule('task')">
<img
v-smart-img
:src="imageUrl(getImgName('MTaskBt'))"
alt=""
:class="{
'grayscale-container': !TaskShow,
}"
style="width: 100%; display: block; object-fit: cover"
/>
</div>
<!-- 抽奖排名模块按钮 -->
<div style="width: 30vw; min-width: 0" @click="changeModule('lotteryRanking')">
<img
v-smart-img
:src="imageUrl(getImgName('MRankingBt'))"
alt=""
:class="{
'grayscale-container': !lotteryRankingShow,
}"
style="width: 100%; display: block; object-fit: cover"
/>
</div>
<!-- 抽奖奖励模块按钮 -->
<div style="width: 30vw; min-width: 0" @click="changeModule('lotteryReward')">
<img
v-smart-img
:src="imageUrl(getImgName('MRewardBt'))"
alt=""
:class="{
'grayscale-container': !lotteryRewardShow,
}"
style="width: 100%; display: block; object-fit: cover"
/>
</div>
</div>
<!-- 任务模块 -->
<Task v-show="TaskShow" :activity="lotteryRewards" />
<!-- 抽奖排名模块 -->
<Ranking v-show="lotteryRankingShow" rankingType="lottery" />
<!-- 抽奖奖励模块 -->
<RankingReward v-show="lotteryRewardShow" />
</div>
<!-- 充值标签页 -->
<div
v-show="RechargeShow"
style="display: flex; flex-direction: column; align-items: center; gap: 4vw"
>
<!-- 模块按钮 -->
<div
style="
width: 100vw;
display: flex;
justify-content: space-around;
align-items: center;
"
>
<!-- 任务模块按钮 -->
<div style="width: 30vw; min-width: 0" @click="changeModule('rechargeRanking')">
<img
v-smart-img
:src="imageUrl(getImgName('MRankingBt'))"
alt=""
:class="{
'grayscale-container': !rechargeRankingShow,
}"
style="width: 100%; display: block; object-fit: cover"
/>
</div>
<!-- 抽奖排名模块按钮 -->
<div style="width: 30vw; min-width: 0" @click="changeModule('rechargeReward')">
<img
v-smart-img
:src="imageUrl(getImgName('MRewardBt'))"
alt=""
:class="{
'grayscale-container': !rechargeRewardShow,
}"
style="width: 100%; display: block; object-fit: cover"
/>
</div>
</div>
<!-- 充值排名模块 -->
<Ranking v-show="rechargeRankingShow" rankingType="recharge" />
<!-- 充值奖励模块 -->
<RechargeReward v-show="rechargeRewardShow" />
</div>
</div>
<!-- 我的排名占位 -->
<div v-show="RankingShow" style="height: 35vw"></div>
<!-- 我的排名占位 -->
<div v-show="!RankingShow" style="height: 8vw"></div>
<!-- 我的排名 -->
<itemCenter
v-show="RankingShow"
style="position: fixed; bottom: 0; z-index: 2"
:imgUrl="imageUrl('myRankingBg')"
:contentStyle="`padding: 0 5vw`"
>
<!-- 基本信息 -->
<div
style="
flex: 1;
min-width: 0;
display: flex;
justify-content: space-around;
align-items: center;
gap: 8px;
"
>
<!-- 排名 -->
<itemCenter
style="width: 10vw"
:imgUrl="imageUrl('rankingNumBg')"
:contentStyle="``"
@click="viewUserInfo(listItem.userId)"
>
<div style="color: #ffe601; font-weight: 700">{{ myRanking?.rank || 999 }}</div>
</itemCenter>
<!-- 头像 -->
<itemCenter
style="width: 20vw; z-index: 1"
:imgUrl="imageUrl('userFrame')"
:contentStyle="`top:2vw`"
>
<img
v-smart-img
:src="myRanking?.userAvatar || ''"
alt=""
style="
position: relative;
z-index: -1;
display: block;
width: 13vw;
aspect-ratio: 1/1;
border-radius: 50%;
object-fit: cover;
"
@error="handleAvatarImageError"
/>
</itemCenter>
<!-- 名称id -->
<div style="flex: 1; min-width: 0; display: flex; flex-direction: column">
<!-- 名称 -->
<div
style="
color: #fff;
font-weight: 860;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
"
class="UserNickname"
>
{{ myRanking?.userName }}
</div>
<!-- ID -->
<div style="color: #fff; font-weight: 590" class="Textlittle">
{{ $t('user_id_prefix') }}
{{ myRanking?.specialAccount || myRanking?.account }}
</div>
</div>
</div>
<!-- 贡献值 -->
<div
style="
width: auto;
min-width: 0;
display: flex;
align-items: center;
"
>
<div
v-if="GamePlayShow && lotteryRankingShow"
style="display: flex; justify-content: center; align-items: center"
>
<img
v-smart-img
src="/src/assets/icon/coin.png"
alt=""
style="display: block; width: 1.5em; aspect-ratio: 1/1; object-fit: cover"
/>
<div style="color: #ffe601; font-weight: 700" class="Textlittle">
{{ myRanking?.amount || 0 }}
</div>
</div>
<div v-if="RechargeShow && rechargeRankingShow" style="color: #fff; font-weight: 700">
${{ myRanking?.amount || 0 }}
</div>
</div>
</itemCenter>
<!-- 弹窗遮罩层 -->
<maskLayer :maskLayerShow="maskLayerShow" @click="closedPopup">
<!-- 居中弹窗 -->
<div
v-show="centerPopupShow"
style="
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
"
@click="closedPopup"
>
<!-- 抽奖结果 -->
<div v-show="resultShow" style="position: relative; width: 100%" @click.stop>
<itemCenter
:imgUrl="imageUrl('resultBg')"
:contentStyle="`inset: 30vw 7vw 6vw;
flex-direction: column;
justify-content: space-between;
gap:2vw`"
>
<!-- 奖品图展示 -->
<div
style="
width: 100%;
flex: 1;
min-height: 0;
display: flex;
justify-content: space-between;
align-items: center;
"
>
<!-- 上一个奖品 -->
<div
style="
width: 8vw;
align-self: stretch;
display: flex;
justify-content: center;
align-items: center;
"
>
<img
v-smart-img
class="flipImg"
v-show="result.length > 1 && resultShowIndex > 0"
:src="imageUrl('resultBack')"
alt=""
style="display: block; width: 80%; object-fit: cover"
@click="resultShowIndex--"
/>
</div>
<!-- 奖品 -->
<img
v-smart-img
:src="result[resultShowIndex]?.prize?.prizeImage"
alt=""
style="display: block; width: 40vw"
/>
<!-- 下一个奖品 -->
<div
style="
width: 8vw;
align-self: stretch;
display: flex;
justify-content: center;
align-items: center;
"
>
<img
v-smart-img
class="flipImg"
v-show="result.length > 1 && resultShowIndex + 1 < result.length"
:src="imageUrl('resultNext')"
alt=""
style="display: block; width: 80%; object-fit: cover"
@click="resultShowIndex++"
/>
</div>
</div>
<!-- 奖品说明 -->
<div
style="
width: 100%;
height: 6vw;
text-align: center;
font-size: 0.9em;
font-weight: 590;
position: relative;
background: linear-gradient(0deg, #f3b700 0%, #ffeec6 100%);
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
"
>
{{ t('you_get') }} {{ result[resultShowIndex]?.prize?.prizeName }}
<div v-if="result.length > 1" class="resultNum">
{{ resultShowIndex + 1 }} / {{ result.length }}
</div>
</div>
<!-- 关闭弹窗按钮 -->
<div style="width: 30vw; height: 12vw" @click="closedPopup"></div>
</itemCenter>
</div>
<!-- 中奖历史 -->
<div v-show="drawRecordShow" style="position: relative; width: 95%" @click.stop>
<itemCenter :imgUrl="imageUrl('recordBg')" :contentStyle="`padding: 22vw 7vw 8vw;`">
<div
style="
width: 100%;
height: 100%;
overflow-y: auto;
display: flex;
flex-direction: column;
gap: 8px;
"
class="scrollY"
>
<div
v-for="(record, index) in myRecords"
style="
border-radius: 12px;
border: 2px solid #fff;
background: linear-gradient(
264deg,
rgba(255, 220, 220, 0.4) 10.17%,
rgba(255, 151, 151, 0.4) 60.22%,
rgba(255, 220, 220, 0.4) 103.12%
);
box-shadow:
0 36.858px 13.981px 0 rgba(255, 106, 106, 0.02),
0 20.335px 12.71px 0 rgba(255, 106, 106, 0.08),
0 8.897px 8.897px 0 rgba(255, 106, 106, 0.13),
0 2.542px 5.084px 0 rgba(255, 106, 106, 0.15);
backdrop-filter: blur(4.5px);
display: flex;
padding: 12px;
justify-content: space-between;
align-items: center;
"
>
<div style="display: flex; align-items: center; gap: 4px">
<img
v-smart-img
:src="record?.prize?.prizeImage || ''"
alt=""
style="width: 10vw; min-width: 0; object-fit: cover; display: block"
/>
<div
style="font-weight: 590; font-size: 0.9em; direction: ltr; text-align: left"
>
{{ record?.prize?.prizeName }}
</div>
</div>
<div style="font-weight: 510; font-size: 0.8em; direction: ltr; text-align: left">
{{ formatUTCCustom(record.drawTime) }}
</div>
</div>
</div>
</itemCenter>
</div>
<!-- 任务列表 -->
<itemCenter
v-show="taskListShow"
:imgUrl="imageUrl('taskListBg')"
:contentStyle="`padding: 20vw 10vw 12vw;flex-direction: column;justify-content: space-between;`"
@click.stop
>
<itemCenter
v-for="task in taskList"
:imgUrl="imageUrl('taskItemBg')"
:contentStyle="`padding: 4vw 5.5vw;justify-content: space-between;`"
@click.stop
>
<!-- 图标 -->
<div style="width: 15%">
<img
v-if="task.taskType == 2"
v-smart-img
:src="imageUrl('taskTypeGift')"
alt=""
width="100%"
style="display: block"
/>
<img
v-if="task.taskType == 4"
v-smart-img
:src="imageUrl('taskTypeGame')"
alt=""
width="100%"
style="display: block"
/>
</div>
<!-- 内容 -->
<div style="width: 60%">
<!-- 任务进度 -->
<div style="color: #fff; font-weight: 590; font-size: 0.75em">
{{ showTarget(task) }}
</div>
<!-- 任务奖励 -->
<div style="display: flex; align-items: center; gap: 1vw">
<div style="color: #fff; font-weight: 590; font-size: 0.9em">
{{ t('coins_per_get') }}
</div>
<img
v-smart-img
:src="imageUrl('ticket')"
:alt="t('ticket')"
width="15%"
style="display: block"
/>
<div style="color: #fff; font-weight: 590; font-size: 0.9em">*1</div>
</div>
</div>
<!-- 按钮 -->
<div style="width: 20%">
<!-- 前往任务 -->
<itemCenter v-if="task.taskStatus == 0" :imgUrl="imageUrl('taskBtGo')">
<div style="font-size: 1em; font-weight: 600">{{ t('task_go') }}</div>
</itemCenter>
<!-- 领取抽奖券 -->
<itemCenter
v-else-if="task.taskStatus === 1"
:imgUrl="imageUrl('taskBtReceive')"
@click="receiveTaskReward(task.taskCode)"
>
<div style="font-size: 1em; font-weight: 600">{{ t('task_receive') }}</div>
</itemCenter>
<!-- 已完成 -->
<itemCenter v-else :imgUrl="imageUrl('taskBtReceived')">
<div style="font-size: 0.9em; font-weight: 600">{{ t('task_received') }}</div>
</itemCenter>
</div>
</itemCenter>
</itemCenter>
<!-- help弹窗 -->
<img
v-smart-img
v-show="helpShow"
:src="imageUrl(getImgName('helpInfo'))"
alt=""
style="display: block; width: 100%; object-fit: cover; margin-bottom: 6vw"
@click.stop
/>
</div>
</maskLayer>
</div>
</div>
</template>
<script setup>
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useLangStore } from '@/stores/lang'
import { useI18n } from 'vue-i18n'
import { getPngUrl, getWebpUrl } from '@/config/imagePaths.js'
import { getUserId, setUserInfo } from '@/utils/userStore.js'
import { viewUserInfo } from '@/utils/appBridge.js'
import { connectToApp } from '@/utils/appConnector.js'
import { preloadImages } from '@/utils/imagePreloader.js'
import { formatUTCCustom } from '@/utils/utcFormat.js'
import { showError, showSuccess } from '@/utils/toast.js'
import { handleAvatarImageError, handleRewardImageError } from '@/utils/imageHandler.js'
import { useSpringFestival } from '@/stores/springFestival'
import { storeToRefs } from 'pinia'
import { getSelectedPayee, clearSelectedPayee } from '@/utils/payeeStore.js'
import { useThrottle, useDebounce } from '@/utils/useDebounce.js'
import { formatRewardDisplay } from '@/utils/rewardFormatter.js'
import { gotoAppPage } from '@/utils/appBridge.js'
import { getMemberProfile, getUserIdentity } from '@/api/wallet'
import {
myTickets, // 获取剩余中奖券
activityDetail, // 获取活动详情
ranklist, //获取排行榜
activityRewardConfigs, // 获取活动奖励配置列表
apigetRewardConfigs, // 获取礼物排行榜奖励列表.
winnerHistory, //获取历史中奖用户
withdrawableAmount, //获取可提现金额
} from '@/api/lottery'
import Task from './Task.vue'
import Ranking from './Ranking.vue'
import RankingReward from './RankingReward.vue'
import RechargeReward from './RechargeReward.vue'
import BackgroundLayer from '@/components/BackgroundLayer.vue'
import itemCenter from '@/components/itemCenter.vue'
import maskLayer from '@/components/MaskLayer.vue'
const { t } = useI18n()
const router = useRouter()
const route = useRoute()
const springFestivalStore = useSpringFestival()
const {
// 抽奖模块
lotteryRewards, // 抽奖奖池
tickets, // 抽奖券数量
luckyUsers, // 中奖用户列表
userInfo, // 用户信息
userIdentity, // 用户身份
currentEarnings, // 当前收益
selectedPayee, // 选择的收款人
taskList, // 任务列表
// 抽奖排名模块
lotteryPageNo, // 抽奖排名页码
lotteryRanking, // 抽奖排名
addLotteryRanking, // 补充的抽奖排名
myLotteryRanking, // 我的抽奖排名
// 排行榜奖励模块
rankingRewards, // 排名奖池
// 充值排名模块
rechargePageNo, // 充值排名页码
rechargeRanking, // 充值排名
addRechargeRanking, // 补充的充值排名
myRechargeRanking, // 我的充值排名
// 充值奖池模块
RechargeRewards, // 充值奖池
resultShow,
result, // 抽奖结果
drawRecordShow,
myRecords, // 我的抽奖记录
receiveRecordShow,
receiveRecord, // 领取抽奖券记录
taskListShow, // 任务列表展示
checkDate, // 对应周几
checkStatus, // 是否已看过
helpShow, // 帮助展示
} = storeToRefs(springFestivalStore)
const langStore = useLangStore()
// 当前语言类型
const currentLangType = computed(() => {
return langStore.selectedLang?.type || 'en'
})
const isLoading = ref(true) // 预加载状态
const timeoutId = ref(null) // 超时定时器 ID
// 获取OSS图片URL的函数
const imageUrl = (filename) => getPngUrl('Activities/SpringFestival/', filename)
const webpUrl = (filename) => getWebpUrl('Activities/SpringFestival/', filename)
// 根据语言获取图片名
const getImgName = (filename) => {
return currentLangType.value === 'ar' ? `${filename}_ar` : filename
}
// 栏目切换状态
const GamePlayShow = ref(true) // 游戏标签页展示
const RechargeShow = ref(false) // 充值标签页展示
// 模块切换状态
const TaskShow = ref(true) // 任务模块展示
const lotteryRankingShow = ref(false) // 抽奖排名模块展示
const lotteryRewardShow = ref(false) // 抽奖奖励模块展示
const rechargeRankingShow = ref(true) // 充值排名模块展示
const rechargeRewardShow = ref(false) // 充值奖励模块展示
const RankingShow = computed(() => {
return (
(GamePlayShow.value && lotteryRankingShow.value) ||
(RechargeShow.value && rechargeRankingShow.value)
)
})
// 我的排名
const myRanking = computed(() => {
if (RankingShow.value) {
if (GamePlayShow.value) {
return myLotteryRanking.value
} else {
return myRechargeRanking.value
}
}
})
// 栏目切换
const changeTag = (tag) => {
switch (tag) {
case 'gamePlay':
GamePlayShow.value = true
RechargeShow.value = false
break
case 'recharge':
GamePlayShow.value = false
RechargeShow.value = true
break
}
}
// 模块切换
const changeModule = (module) => {
switch (module) {
case 'task':
TaskShow.value = true
lotteryRankingShow.value = false
lotteryRewardShow.value = false
break
case 'lotteryRanking':
TaskShow.value = false
lotteryRankingShow.value = true
lotteryRewardShow.value = false
break
case 'lotteryReward':
TaskShow.value = false
lotteryRankingShow.value = false
lotteryRewardShow.value = true
break
case 'rechargeRanking':
rechargeRankingShow.value = true
rechargeRewardShow.value = false
break
case 'rechargeReward':
rechargeRankingShow.value = false
rechargeRewardShow.value = true
break
}
}
// 倒计时相关数据
const Days = ref(0)
const Hours = ref(0)
const Minutes = ref(0)
const Seconds = ref(0)
let countdownTimer = null
// 获取目标时间2026年3月14日上午5点北京时间
const getTargetTime = () => {
const target = new Date(2026, 2, 14, 5, 0, 0) // 月份从0开始10代表11月
return target.getTime()
}
// 计算倒计时
const calculateCountdown = () => {
const now = Date.now()
const targetTime = getTargetTime()
let diff = targetTime - now
// 如果已过期,清零并停止计时器
if (diff <= 0) {
Days.value = 0
Hours.value = '00'
Minutes.value = '00'
Seconds.value = '00'
if (countdownTimer) {
clearInterval(countdownTimer)
countdownTimer = null
}
return
}
// 计算天、小时、分钟、秒
const totalSeconds = Math.floor(diff / 1000)
Days.value = Math.floor(totalSeconds / (24 * 3600))
Hours.value = String(Math.floor((totalSeconds % (24 * 3600)) / 3600)).padStart(2, '0')
Minutes.value = String(Math.floor((totalSeconds % 3600) / 60)).padStart(2, '0')
Seconds.value = String(Math.floor(totalSeconds % 60)).padStart(2, '0')
}
// 启动倒计时
const startCountdown = () => {
calculateCountdown() // 立即执行一次
countdownTimer = setInterval(calculateCountdown, 1000)
}
const resultShowIndex = ref(0) // 抽奖结果索引
// 遮罩层
const maskLayerShow = computed(() => {
return (
resultShow.value ||
drawRecordShow.value ||
receiveRecordShow.value ||
taskListShow.value ||
helpShow.value
)
})
// 居中弹窗
const centerPopupShow = computed(() => {
return (
resultShow.value ||
drawRecordShow.value ||
receiveRecordShow.value ||
taskListShow.value ||
helpShow.value
)
})
// 检查今日是否已看过
const checkShow = () => {
const now = new Date()
const dailyDate = now.getMonth() + '-' + now.getDate()
if (dailyDate != checkDate.value) {
checkDate.value = dailyDate // 更新周几
checkStatus.value = false // 更新今日状态
showPopup('taskList')
} else if (!checkStatus.value) {
showPopup('taskList')
}
}
// 打开遮罩层
const showPopup = (type) => {
switch (type) {
case 'result':
closedPopup() // 关闭弹窗
resultShow.value = true
break
case 'drawRecord':
closedPopup() // 关闭弹窗
drawRecordShow.value = true
break
case 'receiveRecord':
closedPopup() // 关闭弹窗
receiveRecordShow.value = true
break
case 'help':
closedPopup() // 关闭弹窗
helpShow.value = true
break
case 'taskList':
closedPopup() // 关闭弹窗
taskListShow.value = true
break
default:
closedPopup() // 关闭弹窗
break
}
}
// 关闭弹窗
const closedPopup = () => {
if (taskListShow.value) {
checkStatus.value = true
}
resultShow.value = false
drawRecordShow.value = false
receiveRecordShow.value = false
taskListShow.value = false
helpShow.value = false
}
// 展示任务目标
const showTarget = (task) => {
if (task.targetType == 'SEND_GIFT') {
if (task.taskCode == 'SPINS_SEND_GIFT') {
return t('lucky_and_magical_gifts_win_gold_coins')
}
} else if (task.targetType == 'WIN_COINS') {
if (task.taskCode == 'SPINS_WIN_100000') {
return t('win_coins_in_the_game')
}
}
}
// 跳转到充值页面
const gotoRecharge = () => {
router.push('/recharge')
}
//获取奖池
const getActivityDetail = async () => {
const resDetail = await activityDetail('04877')
if (resDetail.status && resDetail.body) {
lotteryRewards.value = resDetail.body
} else {
lotteryRewards.value = {}
}
}
// 获取抽奖券
const getMyLotteryTicketCount = async () => {
try {
const response = await myTickets('2007771533988204877')
if (response.status) {
tickets.value = response.body || 0
}
} catch (error) {
showError(error.response.errorMsg)
}
}
//获取中奖用户列表
const getWinners = async () => {
const resWinners = await winnerHistory('2007771533988204877')
if (resWinners.status && resWinners.body) {
luckyUsers.value = resWinners.body
}
}
//获取任务列表
const getTaskList = async () => {
taskList.value = [
{
taskId: 1,
taskCode: 'SPINS_WIN_100000',
taskName: 'Win 100000 coins in the game',
taskType: 4,
taskDesc: '游戏内获得100000金币',
targetType: 'WIN_COINS',
targetValue: 100000,
targetUnit: 'COINS',
currentValue: 0,
progressRate: 0,
taskStatus: 0,
rewardType: 1,
rewardValue: 1,
},
{
taskId: 2,
taskCode: 'SPINS_SEND_GIFT',
taskName: 'Lucky and magical gifts win 100000 gold coins',
taskType: 2,
taskDesc: '送出幸运礼物或魔法礼物赢取100000金币',
targetType: 'SEND_GIFT',
targetValue: 100000,
targetUnit: 'COINS',
currentValue: 0,
progressRate: 0,
taskStatus: 0,
rewardType: 1,
rewardValue: 1,
},
]
}
//获取用户信息
const getUserInfo = async () => {
if (Object.keys(userInfo.value).length === 0) {
const resUserInfo = await getMemberProfile()
if (resUserInfo.status && resUserInfo.body) {
setUserInfo(resUserInfo.body, null)
userInfo.value = resUserInfo.body
}
}
const resIdentity = await getUserIdentity()
if (resIdentity.status && resIdentity.body) {
userIdentity.value = resIdentity.body
}
}
//可提现金额
const getDrawableAmount = async () => {
const resDrawableAmount = await withdrawableAmount('2007771533988204877')
if (resDrawableAmount.status && resDrawableAmount.body) {
currentEarnings.value = resDrawableAmount.body?.availableAmount || 0
}
}
// 初始化收款人信息
const initializePayee = () => {
const savedPayee = getSelectedPayee()
if (savedPayee) {
Object.assign(selectedPayee.value, savedPayee)
}
}
// 清除当前选中的收款人
const clearPayee = () => {
Object.assign(selectedPayee.value, {
id: null,
account: '',
name: '',
avatar: '',
type: '',
isHost: false,
isAgency: false,
hasSalary: false,
})
clearSelectedPayee()
}
//获取排行榜
const getRanking = async (rankingType = 'lottery') => {
if (lotteryPageNo.value == 0) {
lotteryPageNo.value = 1
}
if (rechargePageNo.value == 0) {
rechargePageNo.value = 1
}
let data = {
activityId: rankingType == 'lottery' ? '2007771533988204877' : '2007771533988204888',
pageNo: rankingType == 'lottery' ? lotteryPageNo.value : rechargePageNo.value,
pageSize: 20,
}
const resRanking = await ranklist(data)
if (resRanking.status && resRanking.body) {
if (rankingType == 'lottery') {
myLotteryRanking.value = resRanking.body?.currentUser // 我的抽奖排名
} else if (rankingType == 'recharge') {
myRechargeRanking.value = resRanking.body?.currentUser // 我的充值排名
}
if (resRanking.body.topList.length > 0) {
if (resRanking.body.topList.length == 20) {
if (rankingType == 'lottery') {
addLotteryRanking.value = []
lotteryRanking.value.push(...resRanking.body?.topList)
lotteryPageNo.value++
} else if (rankingType == 'recharge') {
addRechargeRanking.value = []
rechargeRanking.value.push(...resRanking.body?.topList)
rechargePageNo.value++
}
} else {
if (rankingType == 'lottery') {
addLotteryRanking.value = resRanking.body?.topList
} else if (rankingType == 'recharge') {
addRechargeRanking.value = resRanking.body?.topList
}
}
}
} else {
if (rankingType == 'lottery') {
myLotteryRanking.value = {}
lotteryRanking.value = []
addLotteryRanking.value = []
lotteryPageNo.value = 1
} else if (rankingType == 'recharge') {
myRechargeRanking.value = {}
rechargeRanking.value = []
addRechargeRanking.value = []
rechargePageNo.value = 1
}
}
}
//获取游戏奖励列表
const getGameReward = async () => {
let data = {
sysOrigin: 'LIKEI',
activityType: 'LUCKY_GIFT_REWARD',
}
const resActivityReward = await apigetRewardConfigs(data)
if (resActivityReward.status && resActivityReward.body) {
rankingRewards.value = resActivityReward.body.map((rewards) => {
let addReward = []
if (rewards.rule.sort == 1) {
addReward = [
{
type: 'DOLLARS',
cover: '',
content: 100,
},
{
type: 'GIFT',
cover: imageUrl('IDReward'),
content: 'ID: XXXX',
},
]
} else if (rewards.rule.sort == 2) {
addReward = [
{
type: 'DOLLARS',
cover: '',
content: 50,
},
]
} else if (rewards.rule.sort == 3) {
addReward = [
{
type: 'DOLLARS',
cover: '',
content: 30,
},
]
} else if (rewards.rule.sort == 4) {
addReward = [
{
type: 'DOLLARS',
cover: '',
content: 10,
},
]
}
rewards.propsGroup.activityRewardProps.push(...addReward) //补充奖励项
rewards = {
...rewards,
}
return rewards
})
} else {
rankingRewards.value = []
}
}
//获取充值奖励列表
const getRechargeReward = async () => {
let data = {
activityType: 'CONSUMPTION_ACTIVITY',
activityId: '2007771533988204877',
}
const resActivityReward = await activityRewardConfigs(data)
if (resActivityReward.status && resActivityReward.body) {
RechargeRewards.value = resActivityReward.body.map((rewards) => {
let jsonData = JSON.parse(rewards.jsonData)
let addReward = []
if (rewards.sort == 1) {
addReward = []
} else if (rewards.sort == 2) {
addReward = []
} else if (rewards.sort == 3) {
addReward = []
} else if (rewards.sort == 4) {
addReward = [
{
type: 'GIFT',
cover: imageUrl('reward_gift'),
content: 1,
},
]
} else if (rewards.sort == 5) {
addReward = [
{
type: 'GIFT',
cover: imageUrl('reward_gift'),
content: 1,
},
]
} else if (rewards.sort == 6) {
addReward = [
{
type: 'GIFT',
cover: imageUrl('reward_gift'),
content: 1,
},
{
type: 'PROPS',
detailType: 'AVATAR_FRAME',
cover: imageUrl('reward_frame'),
quantity: 365,
},
{
type: 'PROPS',
detailType: 'RIDE',
cover: imageUrl('reward_ride'),
quantity: 60,
},
]
}
rewards.rewardProps.push(...addReward) //补充奖励项
rewards = {
...rewards,
...jsonData,
}
return rewards
})
} else {
RechargeRewards.value = []
}
}
// 页面初始化数据
const initData = async () => {
await Promise.all([
getActivityDetail(), //获取奖池
getMyLotteryTicketCount(), //获取抽奖券
getWinners(), //获取历史中奖用户
getTaskList(), //获取任务列表
getUserInfo(), //获取用户信息
getDrawableAmount(), //获取可提现金额
initializePayee(), //获取收款人信息
getRanking('lottery'), // 获取抽奖排行榜
getRanking('recharge'), // 获取充值排行榜
getGameReward(), // 获取游戏奖励列表
getRechargeReward(), // 获取充值奖励列表
])
}
// 预加载关键图片
const preloadCriticalImages = async () => {
const criticalImages = [
// 背景
imageUrl('bg1'),
imageUrl('bg2'),
imageUrl('bg3'),
imageUrl('bg4'),
imageUrl('bg5'),
// 排行榜背景
imageUrl('bg1'),
imageUrl('bg2-2'),
// 倒计时
imageUrl('TimeBg'),
// 按钮
imageUrl(getImgName('TagGameBt')),
imageUrl(getImgName('TagRechargeBt')),
imageUrl(getImgName('MTaskBt')),
imageUrl(getImgName('MRankingBt')),
imageUrl(getImgName('MRewardBt')),
// 任务列表
imageUrl('taskListBg'),
imageUrl('taskItemBg'),
imageUrl('taskTypeGift'),
imageUrl('taskTypeGame'),
imageUrl('ticket'),
imageUrl('taskBtGo'),
imageUrl('taskBtReceive'),
imageUrl('taskBtReceived'),
]
await preloadImages(criticalImages)
}
// 完成预加载
const completePreloading = async () => {
try {
// 执行所有初始化操作
await Promise.all([
// initData(),
preloadCriticalImages(),
])
console.log('预加载完成,初始化数据成功')
} catch (error) {
console.error('预加载过程中发生错误:', error)
} finally {
// 无论成功或失败都结束加载状态
isLoading.value = false
}
}
// 预加载其他图片
const preloadOtherImages = async () => {
const criticalImages = [
// 我的排名
imageUrl('myRankingBg'),
imageUrl('rankingNumBg'),
imageUrl('userFrame'),
// 抽奖结果
imageUrl('resultBg'),
imageUrl('resultBack'),
imageUrl('resultNext'),
// 中奖历史
imageUrl('recordBg'),
// help弹窗
imageUrl(getImgName('helpInfo')),
// 抽奖组件
imageUrl('lotteryBg'),
imageUrl('historyBt'),
imageUrl('prizeActiveFrame'),
imageUrl('ticket'),
imageUrl('earningInfoBg'),
// 排行榜组件
imageUrl('top1Bg'),
imageUrl('top2Bg'),
imageUrl('top3Bg'),
imageUrl('rankingNumBg'),
imageUrl('rankingItemBg'),
// 排行榜奖励组件
imageUrl('rankingRewardTop1Bg'),
imageUrl('rankingRewardTop2Bg'),
imageUrl('rankingRewardTop3Bg'),
imageUrl('rankingRewardTop4Bg'),
// 充值奖励组件
imageUrl('receiveBt'),
imageUrl('rechargeReward100'),
imageUrl('rechargeReward500'),
imageUrl('rechargeReward1000'),
imageUrl('rechargeReward3000'),
imageUrl('rechargeReward5000'),
imageUrl('rechargeReward10000'),
]
await preloadImages(criticalImages)
}
// 使用工具函数连接APP
const connectToAppHandler = async () => {
await connectToApp(() => {
// 连接成功回调
completePreloading() // 完成预加载
})
}
// 设置超时刷新逻辑
const startTimeoutCheck = () => {
timeoutId.value = setTimeout(() => {
if (isLoading.value) {
console.warn('⏰ 预加载超时,正在刷新页面...')
window.location.reload() // 刷新页面
}
}, 20000) // 20 秒超时
}
// 清理定时器
const clearTimeoutCheck = () => {
if (timeoutId.value) {
clearTimeout(timeoutId.value)
timeoutId.value = null
}
}
// 组件挂载时检测环境
onMounted(async () => {
springFestivalStore.clear()
checkShow() // 检查是否展示每日弹窗
console.log('route.query.activeAction:', route.query.activeAction)
if (route.query.activeAction == 'TaskShow') {
changeTag('gamePlay')
changeModule('task')
} else {
changeTag('gamePlay')
changeModule('task')
}
// 启动超时检测
startTimeoutCheck()
await connectToAppHandler()
initData()
preloadOtherImages() // 预加载其他图片
startCountdown() //开启倒计时
})
onUnmounted(() => {
springFestivalStore.clear()
if (countdownTimer) {
clearInterval(countdownTimer)
countdownTimer = null
}
clearTimeoutCheck() // 清理超时检测定时器
clearPayee() // 清空收款人信息
})
</script>
<style lang="scss" scoped>
* {
color: #fff;
}
.grayscale-container {
filter: grayscale(100%) brightness(90%);
}
.fullPage {
width: 100vw;
min-height: 100vh;
background: #da4302;
position: relative;
}
.background-overlay {
position: absolute;
inset: 410vw 0 0;
background-image: var(--bg3-2-url);
background-repeat: repeat-y;
background-position: top center;
background-size: 100% auto;
z-index: 0; /* 确保在.bg之下 */
}
/* 添加加载动画样式 */
.loading-container {
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: #666;
}
.loading-spinner {
width: 32px;
height: 32px;
border: 3px solid #f3f3f3;
border-top: 3px solid #f59e0b;
border-radius: 50%;
animation: spin 1s linear infinite;
margin-bottom: 12px;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.timeBox {
width: 100%;
display: flex;
justify-content: space-between;
}
.timeBoxItem {
flex: 1;
display: flex;
justify-content: center;
}
.timeText {
color: #fff;
font-weight: 590;
font-size: 1.8em;
}
.timeGap {
width: 6px;
align-self: stretch;
display: flex;
justify-content: center;
align-items: center;
}
.scrollX::-webkit-scrollbar {
display: none;
}
.scrollY::-webkit-scrollbar {
display: none;
}
.resultNum {
position: absolute;
z-index: 9999;
inset: 0;
padding-right: 8%;
display: flex;
justify-content: flex-end;
align-items: center;
font-size: 0.8em;
font-weight: 590;
background: linear-gradient(0deg, #f3b700 0%, #ffeec6 100%);
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
@media screen and (max-width: 360px) {
* {
font-size: 10px;
}
}
@media screen and (min-width: 360px) {
* {
font-size: 12px;
}
}
@media screen and (min-width: 768px) {
* {
font-size: 24px;
}
}
@media screen and (min-width: 1024px) {
* {
font-size: 32px;
}
}
[dir='rtl'] .timeBox {
flex-direction: row-reverse;
}
[dir='rtl'] .flipImg {
transform: scaleX(-1);
}
[dir='rtl'] .resultNum {
direction: ltr;
justify-content: flex-start;
}
</style>