feat(古尔邦节): 对接接口

This commit is contained in:
hzj 2026-05-23 14:36:29 +08:00
parent 2a6b330b98
commit ece1142624
8 changed files with 1506 additions and 215 deletions

View File

@ -212,3 +212,19 @@ export const apiPostCardBagList = async (data) => {
throw error throw error
} }
} }
// 查询中奖记录
export const apiPostCardRewardRecordList = async (data = {}) => {
try {
const response = await post('/activity/card/reward/record/list', {
size: 10,
current: 1,
...data,
})
return response
} catch (error) {
console.error('Failed to get card reward record list:', error)
console.error('error:' + (error.response?.errorMsg || error.errorMsg || error.message || ''))
throw error
}
}

View File

@ -4,7 +4,7 @@
<!-- 背景图 --> <!-- 背景图 -->
<img <img
v-if="shouldShowImage" v-if="shouldShowImage"
v-smart-img v-smart-img.noFade
:src="imgUrl" :src="imgUrl"
:class="flip ? 'flipImg' : ''" :class="flip ? 'flipImg' : ''"
alt="" alt=""

View File

@ -6,13 +6,14 @@ import { resolveProtectedAssetUrl } from '@/utils/protectedAssets.js'
export const smartImage = { export const smartImage = {
async mounted(el, binding) { async mounted(el, binding) {
const skipFade = binding.modifiers.noFade || binding.arg === 'noFade' || isLowEndDevice() const skipFade = binding.modifiers.noFade || binding.arg === 'noFade' || isLowEndDevice()
const keepVisible = binding.modifiers.noFade || binding.arg === 'noFade'
el.decoding = 'async' el.decoding = 'async'
const url = getValidUrl(binding.value, el) const url = getValidUrl(binding.value, el)
if (url) { if (url) {
prepareImageLoadingState(el, skipFade) prepareImageLoadingState(el, skipFade, keepVisible)
await processImage(el, url) await processImage(el, url)
el._smartImageCurrentUrl = url el._smartImageCurrentUrl = url
el._smartImageOriginalBindingValue = binding.value el._smartImageOriginalBindingValue = binding.value
@ -24,6 +25,7 @@ export const smartImage = {
async updated(el, binding) { async updated(el, binding) {
const skipFade = binding.modifiers.noFade || binding.arg === 'noFade' || isLowEndDevice() const skipFade = binding.modifiers.noFade || binding.arg === 'noFade' || isLowEndDevice()
const keepVisible = binding.modifiers.noFade || binding.arg === 'noFade'
const currentUrl = getValidUrl(binding.value, el) const currentUrl = getValidUrl(binding.value, el)
const bindingChanged = binding.value !== binding.oldValue const bindingChanged = binding.value !== binding.oldValue
const elementSrcChanged = currentUrl && currentUrl !== el._smartImageCurrentUrl const elementSrcChanged = currentUrl && currentUrl !== el._smartImageCurrentUrl
@ -33,7 +35,7 @@ export const smartImage = {
} }
if (currentUrl && currentUrl !== el._smartImageCurrentUrl) { if (currentUrl && currentUrl !== el._smartImageCurrentUrl) {
prepareImageLoadingState(el, skipFade) prepareImageLoadingState(el, skipFade, keepVisible)
await processImage(el, currentUrl) await processImage(el, currentUrl)
el._smartImageCurrentUrl = currentUrl el._smartImageCurrentUrl = currentUrl
el._smartImageOriginalBindingValue = binding.value el._smartImageOriginalBindingValue = binding.value
@ -68,7 +70,12 @@ function getValidUrl(bindingValue, el) {
return null return null
} }
function prepareImageLoadingState(el, skipFade) { function prepareImageLoadingState(el, skipFade, keepVisible = false) {
if (keepVisible) {
el.style.opacity = '1'
el.style.transition = 'none'
return
}
// 低端机也要先隐藏待处理图片,避免缓存异步完成前出现浏览器失败占位。 // 低端机也要先隐藏待处理图片,避免缓存异步完成前出现浏览器失败占位。
el.style.opacity = '0' el.style.opacity = '0'
el.style.transition = skipFade ? 'none' : 'opacity 0.3s ease-in-out' el.style.transition = skipFade ? 'none' : 'opacity 0.3s ease-in-out'

View File

@ -408,18 +408,18 @@ const router = createRouter({
}, },
// 限时活动 // 限时活动
{
path: '/activities/lucky-dollars-season5',
name: 'lucky-dollars-season5',
component: () => import('../views/Activities/LuckyDollars/Season5/index.vue'),
meta: { requiresAuth: true },
}, //2026年x月x日上午5点结束
{ {
path: '/activities/gulben-festival', path: '/activities/gulben-festival',
name: 'gulben-festival', name: 'gulben-festival',
component: () => import('../views/Activities/GulbenFestival/index.vue'), component: () => import('../views/Activities/GulbenFestival/index.vue'),
meta: { requiresAuth: true }, meta: { requiresAuth: true },
}, // 古尔邦节活动 }, // 古尔邦节活动
{
path: '/activities/lucky-dollars-season5',
name: 'lucky-dollars-season5',
component: () => import('../views/Activities/LuckyDollars/Season5/index.vue'),
meta: { requiresAuth: true },
}, //2026年x月x日上午5点结束
{ {
path: '/activities/poker-ace', path: '/activities/poker-ace',
name: 'pokerAce', name: 'pokerAce',

View File

@ -2,7 +2,7 @@
<div style="width: 100%"> <div style="width: 100%">
<div style="position: relative"> <div style="position: relative">
<img <img
v-smart-img v-smart-img.noFade
:src="BorderImgUrl" :src="BorderImgUrl"
alt="" alt=""
width="100%" width="100%"
@ -73,7 +73,7 @@
}" }"
> >
<img <img
v-smart-img v-smart-img.noFade
:src="valueIconUrl" :src="valueIconUrl"
alt="" alt=""
style="display: block; aspect-ratio: 1/1; flex: 0 0 auto" style="display: block; aspect-ratio: 1/1; flex: 0 0 auto"

View File

@ -1,4 +1,4 @@
<template> <template>
<div class="fullPage"> <div class="fullPage">
<!-- 页面同步预加载首屏关键图片加载完成前展示 loading --> <!-- 页面同步预加载首屏关键图片加载完成前展示 loading -->
<div <div
@ -118,15 +118,22 @@
> >
<itemCenter <itemCenter
class="tab-background" class="tab-background"
:imgUrl="tabButtonImage(tab.value)" :imgUrl="imageUrl('tagBg')"
contentStyle="padding: 4vw 4vw 0;" contentStyle="padding: 4vw 4vw 0;"
> >
<span style="font-weight: 700">{{ tab.label }}</span> <img
v-show="activeTopTab === tab.value"
v-smart-img.noFade
:src="imageUrl('tagActiveBg')"
class="tab-active-bg"
alt=""
/>
<span style="position: relative; z-index: 1; font-weight: 700">{{ tab.label }}</span>
</itemCenter> </itemCenter>
</button> </button>
</section> </section>
<!-- 标签内容预览区后续按模块逐步替换为真实业务内容 --> <!-- 标签内容根据当前标签逐步展示对应业务模块 -->
<section style="min-height: 86vw; padding: 0; margin: 0"> <section style="min-height: 86vw; padding: 0; margin: 0">
<div v-if="currentTopSection"> <div v-if="currentTopSection">
<!-- 二级标签个人榜和房间榜下的 Reward / Ranking --> <!-- 二级标签个人榜和房间榜下的 Reward / Ranking -->
@ -150,10 +157,19 @@
> >
<itemCenter <itemCenter
class="tab-background" class="tab-background"
:imgUrl="childTabButtonImage(tab.value)" :imgUrl="imageUrl('moduleBg')"
contentStyle="padding: 1vw 4vw 0;" contentStyle="padding: 1vw 4vw 0;"
> >
<span style="font-weight: 700">{{ tab.label }}</span> <img
v-show="activeChildTab === tab.value"
v-smart-img.noFade
:src="imageUrl('moduleActiveBg')"
class="tab-active-bg"
alt=""
/>
<span style="position: relative; z-index: 1; font-weight: 700">{{
tab.label
}}</span>
</itemCenter> </itemCenter>
</button> </button>
</div> </div>
@ -177,7 +193,36 @@
style="width: 100vw; margin: 0; padding: 0" style="width: 100vw; margin: 0; padding: 0"
contentStyle="padding: 8vw 5vw 0; align-items: stretch; justify-content: flex-start; box-sizing: border-box;" contentStyle="padding: 8vw 5vw 0; align-items: stretch; justify-content: flex-start; box-sizing: border-box;"
> >
<!-- 抽奖区域上层放左右切换按钮和奖品占位下层放抽奖按钮 --> <itemCenter
:imgUrl="imageUrl('ruleBtBg')"
style="
position: absolute;
top: 3vw;
right: 5vw;
z-index: 2;
width: 20vw;
margin: 0;
padding: 0;
direction: ltr;
"
contentStyle="padding: 4vw 3vw;"
>
<span
style="
color: #fff8d7;
font-size: 1em;
font-weight: 800;
line-height: 1;
text-align: center;
text-shadow: 0 1px 2px rgba(63, 20, 57, 0.5);
white-space: nowrap;
"
>
history
</span>
</itemCenter>
<!-- 抽奖区域上层放左右切换按钮和奖品下层放抽奖按钮 -->
<div <div
style="width: 100%; height: 100%; display: flex; flex-direction: column; gap: 0" style="width: 100%; height: 100%; display: flex; flex-direction: column; gap: 0"
> >
@ -194,7 +239,7 @@
@click="changeLotteryPoolMode(-1)" @click="changeLotteryPoolMode(-1)"
> >
<img <img
v-smart-img v-smart-img.noFade
:src="imageUrl('leftBt')" :src="imageUrl('leftBt')"
alt="" alt=""
style="width: 8vw; display: block" style="width: 8vw; display: block"
@ -226,20 +271,39 @@
<itemCenter <itemCenter
v-for="prize in row" v-for="prize in row"
:key="prize.renderKey" :key="prize.renderKey"
:imgUrl="lotteryPrizeImage(prize.index)" :imgUrl="imageUrl('lotteryPrizeBg')"
:class="['lottery-prize-item', activeLotteryPoolMode.itemClass]" :class="[
'lottery-prize-item',
activeLotteryPoolMode.itemClass,
{ 'lottery-prize-item-active': prize.index === activeLotteryIndex },
]"
contentStyle="padding: 1vw; flex-direction: column; gap: 0.5vw; align-items: center; justify-content: center; box-sizing: border-box;" contentStyle="padding: 1vw; flex-direction: column; gap: 0.5vw; align-items: center; justify-content: center; box-sizing: border-box;"
> >
<img
v-show="prize.index === activeLotteryIndex"
v-smart-img.noFade
:src="imageUrl('lotteryPrizeActiveBg')"
class="lottery-prize-active-bg"
alt=""
/>
<img <img
v-if="prize.prizeImage" v-if="prize.prizeImage"
v-smart-img v-smart-img.noFade
:src="prize.prizeImage" :src="prize.prizeImage"
alt="" alt=""
style="width: 60%; display: block; object-fit: contain" style="
position: relative;
z-index: 1;
width: 60%;
display: block;
object-fit: contain;
"
@error="handleRewardImageError" @error="handleRewardImageError"
/> />
<div <div
style=" style="
position: relative;
z-index: 1;
width: 100%; width: 100%;
color: #fff; color: #fff;
font-size: 0.7em; font-size: 0.7em;
@ -267,7 +331,7 @@
@click="changeLotteryPoolMode(1)" @click="changeLotteryPoolMode(1)"
> >
<img <img
v-smart-img v-smart-img.noFade
:src="imageUrl('leftBt')" :src="imageUrl('leftBt')"
alt="" alt=""
style="width: 8vw; display: block; transform: scaleX(-1)" style="width: 8vw; display: block; transform: scaleX(-1)"
@ -275,7 +339,7 @@
</div> </div>
</div> </div>
<!-- 抽奖区域下层单抽和5连抽按钮内部后续可替换抽奖券图标 --> <!-- 抽奖区域下层单抽和5连抽按钮内部放当前奖池票券图标 -->
<div <div
style=" style="
display: flex; display: flex;
@ -294,7 +358,7 @@
@click="handleLotteryDraw(1)" @click="handleLotteryDraw(1)"
> >
<img <img
v-smart-img v-smart-img.noFade
:src="imageUrl(activeLotteryTicketImage)" :src="imageUrl(activeLotteryTicketImage)"
alt="" alt=""
style="width: 10vw; display: block" style="width: 10vw; display: block"
@ -308,7 +372,7 @@
@click="handleLotteryDraw(5)" @click="handleLotteryDraw(5)"
> >
<img <img
v-smart-img v-smart-img.noFade
:src="imageUrl(activeLotteryTicketImage)" :src="imageUrl(activeLotteryTicketImage)"
alt="" alt=""
style="width: 10vw; display: block" style="width: 10vw; display: block"
@ -364,7 +428,7 @@
> >
<div style="width: 3vw; height: 100%"> <div style="width: 3vw; height: 100%">
<img <img
v-smart-img v-smart-img.noFade
:src="imageUrl('helpBt')" :src="imageUrl('helpBt')"
alt="" alt=""
style="width: 100%; display: block" style="width: 100%; display: block"
@ -372,7 +436,7 @@
</div> </div>
<img <img
v-smart-img v-smart-img.noFade
:src="imageUrl(ticket.image)" :src="imageUrl(ticket.image)"
alt="" alt=""
style="width: 13vw; display: block" style="width: 13vw; display: block"
@ -409,7 +473,7 @@
" "
> >
<img <img
v-smart-img v-smart-img.noFade
:src="imageUrl(activeCollectGameTitle)" :src="imageUrl(activeCollectGameTitle)"
alt="" alt=""
style="height: 6.5vw; width: auto; display: block" style="height: 6.5vw; width: auto; display: block"
@ -438,7 +502,7 @@
@click="changeCollectGameMode(-1)" @click="changeCollectGameMode(-1)"
> >
<img <img
v-smart-img v-smart-img.noFade
:src="imageUrl('leftBt')" :src="imageUrl('leftBt')"
alt="" alt=""
style="width: 8vw; display: block" style="width: 8vw; display: block"
@ -459,7 +523,7 @@
<template v-for="card in activeCollectCards" :key="card.cardTemplateId"> <template v-for="card in activeCollectCards" :key="card.cardTemplateId">
<img <img
v-if="card.isCardBack" v-if="card.isCardBack"
v-smart-img v-smart-img.noFade
:src="imageUrl('cardBackBg')" :src="imageUrl('cardBackBg')"
alt="" alt=""
style="height: 100%; width: auto; display: block" style="height: 100%; width: auto; display: block"
@ -508,7 +572,7 @@
@click="changeCollectGameMode(1)" @click="changeCollectGameMode(1)"
> >
<img <img
v-smart-img v-smart-img.noFade
:src="imageUrl('leftBt')" :src="imageUrl('leftBt')"
alt="" alt=""
style="width: 8vw; display: block; transform: scaleX(-1)" style="width: 8vw; display: block; transform: scaleX(-1)"
@ -614,7 +678,7 @@
" "
> >
<img <img
v-smart-img v-smart-img.noFade
:src="imageUrl(activeCollectTicketImage)" :src="imageUrl(activeCollectTicketImage)"
alt="" alt=""
style="width: 6vw; display: block" style="width: 6vw; display: block"
@ -657,7 +721,7 @@
<div style="font-size: 0.9em; display: flex; align-items: center; gap: 1vw"> <div style="font-size: 0.9em; display: flex; align-items: center; gap: 1vw">
<span style="color: #fff; font-size: 1em; font-weight: 590">Rewards:</span> <span style="color: #fff; font-size: 1em; font-weight: 590">Rewards:</span>
<img <img
v-smart-img v-smart-img.noFade
:src="imageUrl('Gameticket')" :src="imageUrl('Gameticket')"
:alt="t('ticket')" :alt="t('ticket')"
width="20vw" width="20vw"
@ -693,7 +757,7 @@
</div> </div>
</itemCenter> </itemCenter>
<!-- 已完成 --> <!-- 宸插畬鎴?-->
<itemCenter v-else style="" :imgUrl="imageUrl('taskBtReceived')"> <itemCenter v-else style="" :imgUrl="imageUrl('taskBtReceived')">
<div style="font-size: 0.9em; font-weight: 600; white-space: nowrap"> <div style="font-size: 0.9em; font-weight: 600; white-space: nowrap">
{{ t('task_received') }} {{ t('task_received') }}
@ -732,10 +796,18 @@
style="width: 100vw; margin: 0; padding: 0" style="width: 100vw; margin: 0; padding: 0"
contentStyle="padding: 25.5vw 9vw 5vw; align-items: flex-start; justify-content: center; box-sizing: border-box;" contentStyle="padding: 25.5vw 9vw 5vw; align-items: flex-start; justify-content: center; box-sizing: border-box;"
> >
<div style="width: 100%; display: flex; align-items: center; gap: 3.5vw"> <div
style="
width: 100%;
display: flex;
align-items: center;
gap: 3.5vw;
direction: ltr;
"
>
<!-- 左侧主奖励每套奖励的第一个奖励大图展示 --> <!-- 左侧主奖励每套奖励的第一个奖励大图展示 -->
<div <div
v-if="getRewardTopMainReward(rewardTop)" v-if="getRewardTopMainReward(rewardTop, topIndex)"
style=" style="
width: 33vw; width: 33vw;
flex: 0 0 33vw; flex: 0 0 33vw;
@ -757,14 +829,19 @@
" "
> >
<img <img
:src="getRewardTopMainReward(rewardTop).cover || ''" v-if="hasRewardCover(getRewardTopMainReward(rewardTop, topIndex))"
:src="getRewardTopMainReward(rewardTop, topIndex).cover || ''"
alt="" alt=""
style="width: 92%; display: block; object-fit: contain" style="width: 92%; display: block; object-fit: contain"
@error=" @error="
(event) => (event) =>
handleRewardImageError(event, getRewardTopMainReward(rewardTop).type) handleRewardImageError(
event,
getRewardTopMainReward(rewardTop, topIndex).type,
)
" "
/> />
<div v-else aria-hidden="true" style="width: 92%; aspect-ratio: 1/1"></div>
</div> </div>
<div <div
style=" style="
@ -775,7 +852,7 @@
text-align: center; text-align: center;
" "
> >
{{ getRewardDisplayText(getRewardTopMainReward(rewardTop)) }} {{ getRewardDisplayText(getRewardTopMainReward(rewardTop, topIndex)) }}
</div> </div>
</div> </div>
@ -784,7 +861,7 @@
style="flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1.7vw" style="flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1.7vw"
> >
<div <div
v-for="(row, rowIndex) in getRewardTopGridRows(rewardTop)" v-for="(row, rowIndex) in getRewardTopGridRows(rewardTop, topIndex)"
:key="`${topIndex}-${rowIndex}`" :key="`${topIndex}-${rowIndex}`"
style="display: flex; justify-content: center; gap: 2.7vw" style="display: flex; justify-content: center; gap: 2.7vw"
> >
@ -818,11 +895,17 @@
" "
> >
<img <img
v-if="hasRewardCover(reward)"
:src="reward.cover || ''" :src="reward.cover || ''"
alt="" alt=""
style="width: 88%; display: block; object-fit: contain" style="width: 88%; display: block; object-fit: contain"
@error="(event) => handleRewardImageError(event, reward.type)" @error="(event) => handleRewardImageError(event, reward.type)"
/> />
<div
v-else
aria-hidden="true"
style="width: 88%; aspect-ratio: 1/1"
></div>
</div> </div>
<div <div
style=" style="
@ -852,7 +935,7 @@
> >
<!-- Room Rank / Reward直接展示规则奖励图 --> <!-- Room Rank / Reward直接展示规则奖励图 -->
<img <img
v-smart-img v-smart-img.noFade
:src="imageUrl('ruleActivity')" :src="imageUrl('ruleActivity')"
alt="" alt=""
style="width: 100vw; display: block" style="width: 100vw; display: block"
@ -924,7 +1007,7 @@
" "
> >
<img <img
v-smart-img v-smart-img.noFade
:src="coinIcon" :src="coinIcon"
alt="" alt=""
style="display: block; width: 1.3em; aspect-ratio: 1/1" style="display: block; width: 1.3em; aspect-ratio: 1/1"
@ -1037,7 +1120,7 @@
style="display: flex; align-items: center; gap: 1vw; margin-top: 0.5vw" style="display: flex; align-items: center; gap: 1vw; margin-top: 0.5vw"
> >
<img <img
v-smart-img v-smart-img.noFade
:src="imageUrl('vip1')" :src="imageUrl('vip1')"
alt="" alt=""
style="width: 12vw; display: block" style="width: 12vw; display: block"
@ -1067,7 +1150,7 @@
" "
> >
<img <img
v-smart-img v-smart-img.noFade
:src="coinIcon" :src="coinIcon"
alt="" alt=""
style="display: block; width: 1.3em; aspect-ratio: 1/1" style="display: block; width: 1.3em; aspect-ratio: 1/1"
@ -1101,7 +1184,7 @@
<img <img
v-for="imageName in activePreviewImages" v-for="imageName in activePreviewImages"
:key="imageName" :key="imageName"
v-smart-img v-smart-img.noFade
:src="imageUrl(imageName)" :src="imageUrl(imageName)"
alt="" alt=""
class="preview-image" class="preview-image"
@ -1183,7 +1266,12 @@
{{ t('user_id_prefix') }} {{ myRanking.specialAccount || myRanking.account }} {{ t('user_id_prefix') }} {{ myRanking.specialAccount || myRanking.account }}
</div> </div>
<div v-else style="display: flex; align-items: center; gap: 1vw; margin-top: 0.5vw"> <div v-else style="display: flex; align-items: center; gap: 1vw; margin-top: 0.5vw">
<img v-smart-img :src="imageUrl('vip1')" alt="" style="width: 10vw; display: block" /> <img
v-smart-img.noFade
:src="imageUrl('vip1')"
alt=""
style="width: 10vw; display: block"
/>
<itemCenter <itemCenter
:imgUrl="imageUrl('userLevel1Bg')" :imgUrl="imageUrl('userLevel1Bg')"
style="width: 10vw; margin: 0; padding: 0" style="width: 10vw; margin: 0; padding: 0"
@ -1209,7 +1297,7 @@
" "
> >
<img <img
v-smart-img v-smart-img.noFade
:src="coinIcon" :src="coinIcon"
alt="" alt=""
style="display: block; width: 1.3em; aspect-ratio: 1/1" style="display: block; width: 1.3em; aspect-ratio: 1/1"
@ -1293,7 +1381,6 @@ import { connectToApp } from '@/utils/appConnector.js'
import { handleRewardImageError } from '@/utils/image/imageHandler.js' import { handleRewardImageError } from '@/utils/image/imageHandler.js'
import { formatRewardDisplay } from '@/utils/rewardFormatter.js' import { formatRewardDisplay } from '@/utils/rewardFormatter.js'
import { import {
apiGetActivityResource,
apiGetCardRewardMarquee, apiGetCardRewardMarquee,
apiGetCardRewardPrizeList, apiGetCardRewardPrizeList,
apiGetCardTicketList, apiGetCardTicketList,
@ -1302,11 +1389,10 @@ import {
apiPostCardDraw, apiPostCardDraw,
apiPostCardRedeem, apiPostCardRedeem,
apiPostCardRewardDraw, apiPostCardRewardDraw,
getRankingListAndMyRanking,
getThisWeekRewardsAndGifts,
} from '@/api/activity.js' } from '@/api/activity.js'
import { ActTaskList, activityDetail, receiveTickets } from '@/api/lottery' import { ActTaskList, activityDetail, receiveTickets } from '@/api/lottery'
import { getThisWeekRewardsAndGifts } from '@/api/topList.js'
import { getMemberProfile } from '@/api/wallet'
import { getMyWeekStarRanking, getWeekStarRanking } from '@/api/weeklyStar.js'
import { getRoomContributionTotalRank } from '@/api/ranking.js' import { getRoomContributionTotalRank } from '@/api/ranking.js'
import BackgroundLayer from '@/components/BackgroundLayer.vue' import BackgroundLayer from '@/components/BackgroundLayer.vue'
import itemCenter from '@/components/itemCenter.vue' import itemCenter from '@/components/itemCenter.vue'
@ -1319,8 +1405,8 @@ const langStore = useLangStore()
const coinIcon = new URL('../../../assets/icon/Azizi/coin.png', import.meta.url).href const coinIcon = new URL('../../../assets/icon/Azizi/coin.png', import.meta.url).href
const gulbenActivityId = '1001' const gulbenActivityId = '1001'
const kingQueenGiftTemplateId = '1966020557831610370' const templateId = ref(pageConfig.activity.templateId || '2057676469390872578')
const weeklyStarPageSize = 10 const activityType = ref(pageConfig.activity.activityType || '')
const roomRankingParams = { const roomRankingParams = {
startDate: '20260518', startDate: '20260518',
endDate: '20260524', endDate: '20260524',
@ -1358,11 +1444,8 @@ const weeklyGifts = ref([
giftCandy: 0, giftCandy: 0,
}, },
]) ])
const rankingPageNo = ref(1)
const ranking = ref([]) const ranking = ref([])
const rankingAdd = ref([])
const myRanking = ref({}) const myRanking = ref({})
const userInfo = ref({})
const rankingLoaded = ref(false) const rankingLoaded = ref(false)
const loadedRankingType = ref('') const loadedRankingType = ref('')
const rankingLoading = ref(false) const rankingLoading = ref(false)
@ -1718,23 +1801,15 @@ const cardDrawTicketCount = computed(() => getTicketRemainingCount('CARD'))
const maskLayerShow = computed(() => ruleShow.value) const maskLayerShow = computed(() => ruleShow.value)
const weeklyStarRankingType = computed(() => {
return pageConfig.activity.personalRankActivityType || 'THIS_WEEK'
})
const activeRankingLoadKey = computed(() => { const activeRankingLoadKey = computed(() => {
if (isRoomRankingSection.value) { if (isRoomRankingSection.value) {
return `room-${roomRankingParams.startDate}-${roomRankingParams.endDate}-${roomRankingParams.size}` return `room-${roomRankingParams.startDate}-${roomRankingParams.endDate}-${roomRankingParams.size}`
} }
return `personal-${weeklyStarRankingType.value}` return `personal-${activityType.value}`
}) })
const personalRewardActivityType = computed(() => { const rankingTotal = computed(() => ranking.value)
return pageConfig.activity.rewardActivityType || 'DAILY_RECHARGE_TASK2'
})
const rankingTotal = computed(() => [...ranking.value, ...rankingAdd.value])
const rankingTop3 = computed(() => { const rankingTop3 = computed(() => {
const top3 = [...rankingTotal.value] const top3 = [...rankingTotal.value]
@ -1758,35 +1833,8 @@ const isPersonalRewardSection = computed(() => {
) )
}) })
const fallbackPersonalRewardTops = computed(() => {
const rewardImages = [
'redeemR2001',
'redeemR2002',
'redeemR2003',
'redeemR2004',
'redeemR2005',
'redeemSR2011',
]
return Array.from({ length: 3 }, (_, topIndex) => ({
rule: {
id: `fallback-${topIndex}`,
},
propsGroup: {
activityRewardProps: rewardImages.map((imageName, rewardIndex) => ({
type: 'GIFT',
cover: imageUrl(imageName),
content: `${rewardIndex + 1}`,
})),
},
}))
})
const personalRewardTops = computed(() => { const personalRewardTops = computed(() => {
const rewardTops = activityRewards.value.length return activityRewards.value.slice(0, 3)
? activityRewards.value
: fallbackPersonalRewardTops.value
return rewardTops.slice(0, 3)
}) })
const changeCollectGameMode = (step) => { const changeCollectGameMode = (step) => {
@ -1821,6 +1869,68 @@ const showTarget = (task) => {
}) })
} }
if (task.targetType === 'SEND_GIFT') {
if (task.taskCode === 'SP_SEND_GIFT_5') {
return t('Send 5 Ramadan gifts ({currentValue}/{targetValue})', {
currentValue: task.currentValue,
targetValue: task.targetValue,
})
}
}
if (task.targetType === 'SAVE_COINS') {
if (task.taskCode === 'SP_SAVE_50000') {
return t('Win 50,000 coins in total across any games ({currentValue}/{targetValue})', {
currentValue: task.currentValue,
targetValue: task.targetValue,
})
}
if (task.taskCode === 'SP_SAVE_100000') {
return t('Win 100,000 coins in total across any games ({currentValue}/{targetValue})', {
currentValue: task.currentValue,
targetValue: task.targetValue,
})
}
if (task.taskCode === 'SP_SAVE_500000') {
return t('Win 500,000 coins in total across any games ({currentValue}/{targetValue})', {
currentValue: task.currentValue,
targetValue: task.targetValue,
})
}
}
if (task.targetType === 'RECHARGE_AMOUNT') {
if (task.taskCode === 'SP_RECHARGE_1') {
return t('Daily total recharge amount: $1 ({currentValue}/{targetValue})', {
currentValue: task.currentValue,
targetValue: task.targetValue,
})
}
if (task.taskCode === 'SP_RECHARGE_10') {
return t('Daily total recharge amount: $10 ({currentValue}/{targetValue})', {
currentValue: task.currentValue,
targetValue: task.targetValue,
})
}
if (task.taskCode === 'SP_RECHARGE_50') {
return t('Daily total recharge amount: $50 ({currentValue}/{targetValue})', {
currentValue: task.currentValue,
targetValue: task.targetValue,
})
}
if (task.taskCode === 'SP_RECHARGE_100') {
return t('Daily total recharge amount: $100 ({currentValue}/{targetValue})', {
currentValue: task.currentValue,
targetValue: task.targetValue,
})
}
}
return `${task.taskName}(${task.currentValue}/${task.targetValue})` return `${task.taskName}(${task.currentValue}/${task.targetValue})`
} }
@ -1931,10 +2041,7 @@ const handleCardDraw = async (drawCount = 1) => {
}) })
if (resDraw.status) { if (resDraw.status) {
await Promise.all([ await Promise.all([getCardTicketList(), getCardBagListByGrade('R')])
getCardTicketList(), // CARD
getCardBagListByGrade('R'), // R R
])
} }
} catch (error) { } catch (error) {
showError(error.errorMsg) showError(error.errorMsg)
@ -1993,8 +2100,8 @@ const handleCardRedeem = async () => {
if (resRedeem.status) { if (resRedeem.status) {
await Promise.all([ await Promise.all([
getCardTicketList(), // STANDARD / PREMIUM / LUXURY getCardTicketList(),
getCardBagListByGrade(activeCollectGameMode.value.cardGrade), // getCardBagListByGrade(activeCollectGameMode.value.cardGrade),
]) ])
} }
} catch (error) { } catch (error) {
@ -2026,7 +2133,8 @@ const receiveTaskReward = async (code) => {
taskCode: code, taskCode: code,
}) })
if (resReceive.status && resReceive.body) { if (resReceive.status && resReceive.body) {
getTaskList() getTaskList() //
getCardTicketList() //
} }
} catch (error) { } catch (error) {
showError(error.errorMsg) showError(error.errorMsg)
@ -2034,63 +2142,88 @@ const receiveTaskReward = async (code) => {
} }
const getWeeklyGifts = async () => { const getWeeklyGifts = async () => {
const resRewardsAndGifts = await getThisWeekRewardsAndGifts(kingQueenGiftTemplateId) const resRewardsAndGifts = await getThisWeekRewardsAndGifts(templateId.value)
if (resRewardsAndGifts.status && resRewardsAndGifts.body?.gifts?.length) { if (resRewardsAndGifts.status && resRewardsAndGifts.body?.gifts?.length) {
weeklyGifts.value = resRewardsAndGifts.body.gifts.slice(0, 3) weeklyGifts.value = resRewardsAndGifts.body.gifts.slice(0, 3)
} }
} }
const getPersonalRewardList = (rewardTop) => { const getPersonalRewardExtraItem = (topIndex) => {
const rewards = rewardTop?.propsGroup?.activityRewardProps if (topIndex === 0) {
return {
type: 'EXTRA_REWARD_ITEM',
quantity: 30,
cover: imageUrl('top1ExtraRewardItem'),
isExtraPreviewReward: true,
}
}
if (topIndex === 1) {
return {
type: 'EXTRA_REWARD_ITEM',
quantity: 30,
cover: imageUrl('top2ExtraRewardItem'),
isExtraPreviewReward: true,
}
}
return null
}
const getPersonalRewardList = (rewardTop, topIndex) => {
const rewards = rewardTop?.rewards || rewardTop?.propsGroup?.activityRewardProps
if (!Array.isArray(rewards)) { if (!Array.isArray(rewards)) {
return [] return []
} }
const rewardList = rewards.slice(0, 6) const rewardList = rewards.slice(0, 6)
const extraReward = getPersonalRewardExtraItem(topIndex)
if (extraReward && rewardList.length < 6) {
rewardList.push(extraReward)
}
if (rewardList.length === 5) { if (rewardList.length === 5) {
rewardList.push({ rewardList.push({
...rewardList[4], isEmptyPreviewReward: true,
isCopiedPreviewReward: true,
}) })
} }
return rewardList return rewardList
} }
const getRewardTopMainReward = (rewardTop) => { const getRewardTopMainReward = (rewardTop, topIndex) => {
return getPersonalRewardList(rewardTop)[0] || null return getPersonalRewardList(rewardTop, topIndex)[0] || null
} }
const getRewardTopGridRows = (rewardTop) => { const getRewardTopGridRows = (rewardTop, topIndex) => {
const rewards = getPersonalRewardList(rewardTop).slice(1, 6) const rewards = getPersonalRewardList(rewardTop, topIndex).slice(1, 6)
return [rewards.slice(0, 2), rewards.slice(2, 4), rewards.slice(4, 5)] return [rewards.slice(0, 2), rewards.slice(2, 4), rewards.slice(4, 5)]
} }
const getRewardDisplayText = (reward) => { const getRewardDisplayText = (reward) => {
if (!reward) { if (!reward || reward.isEmptyPreviewReward) {
return '' return ''
} }
return formatRewardDisplay(reward.type, reward) return formatRewardDisplay(reward.type, reward)
} }
const getLotteryPrizeDisplayText = (prize) => { const hasRewardCover = (reward) => {
if (!prize?.prizeType) { return Boolean(reward?.cover)
return '' }
}
return ( const getLotteryPrizeDisplayText = (prize) => {
formatRewardDisplay(prize.prizeType, { return prize?.prizeName || ''
...prize,
type: prize.prizeType,
content: prize.prizeValue,
quantity: prize.prizeValue,
}) || prize.prizeName
)
} }
const getRewardRenderKey = (reward, index) => { const getRewardRenderKey = (reward, index) => {
return [index, reward?.type || '', reward?.detailType || '', reward?.cover || ''].join('-') return [
index,
reward?.isEmptyPreviewReward ? 'empty' : '',
reward?.type || '',
reward?.detailType || '',
reward?.cover || '',
].join('-')
} }
const getPersonalRewardConfigs = async () => { const getPersonalRewardConfigs = async () => {
@ -2101,16 +2234,16 @@ const getPersonalRewardConfigs = async () => {
personalRewardLoaded.value = true personalRewardLoaded.value = true
try { try {
const res = await apiGetActivityResource(personalRewardActivityType.value) const resRewardsAndGifts = await getThisWeekRewardsAndGifts(templateId.value)
if (res.status && res.body) { if (resRewardsAndGifts.status && resRewardsAndGifts.body) {
activityRewards.value = Array.isArray(res.body) ? res.body.slice(0, 3) : [] activityRewards.value = (resRewardsAndGifts.body.butOneRewards || []).slice(0, 3)
} }
} catch (error) { } catch (error) {
showError(error.errorMsg) showError(error.errorMsg)
} }
} }
const normalizeWeeklyStarRankingItem = (item = {}, index = 0) => { const normalizePersonalRankingItem = (item = {}, index = 0) => {
return { return {
...item, ...item,
rank: item.rank || item.ranking || (index === null ? '' : index + 1), rank: item.rank || item.ranking || (index === null ? '' : index + 1),
@ -2141,35 +2274,6 @@ const normalizeRoomContributionRankingItem = (item = {}, index = 0) => {
} }
} }
const getUserInfo = async () => {
if (userInfo.value?.id) {
return userInfo.value
}
const resUserInfo = await getMemberProfile()
if (resUserInfo.status && resUserInfo.body) {
userInfo.value = resUserInfo.body
}
return userInfo.value
}
const getMyPersonalRanking = async () => {
const profile = await getUserInfo()
if (!profile?.id) {
return
}
const resMyRanking = await getMyWeekStarRanking({
type: weeklyStarRankingType.value,
userId: profile.id,
})
if (resMyRanking.status && resMyRanking.body) {
myRanking.value = normalizeWeeklyStarRankingItem(resMyRanking.body, null)
}
}
const getPersonalRanking = async () => { const getPersonalRanking = async () => {
if (rankingLoading.value || !rankingHasMore.value) { if (rankingLoading.value || !rankingHasMore.value) {
return return
@ -2178,40 +2282,21 @@ const getPersonalRanking = async () => {
rankingLoading.value = true rankingLoading.value = true
try { try {
const resRanking = await getWeekStarRanking({ const resRanking = await getRankingListAndMyRanking({
type: weeklyStarRankingType.value, activityType: activityType.value,
current: rankingPageNo.value,
size: weeklyStarPageSize,
}) })
if (resRanking.status && resRanking.body?.rankUsers) { if (resRanking.status && resRanking.body) {
const rankUsers = resRanking.body.rankUsers myRanking.value = normalizePersonalRankingItem(resRanking.body.currentUserRank || {}, null)
const records = rankUsers.records || [] ranking.value = (resRanking.body.rankingList || []).map((item, index) =>
const pageSize = Number(rankUsers.size || weeklyStarPageSize) normalizePersonalRankingItem(item, index),
const total = Number(rankUsers.total || 0)
const startIndex = (rankingPageNo.value - 1) * pageSize
const list = records.map((item, index) =>
normalizeWeeklyStarRankingItem(item, startIndex + index),
) )
rankingHasMore.value = false
if (rankingPageNo.value === 1) {
ranking.value = list
} else {
ranking.value.push(...list)
}
rankingAdd.value = []
rankingHasMore.value = records.length > 0 && rankingPageNo.value * pageSize < total
if (rankingHasMore.value) {
rankingPageNo.value += 1
}
return return
} }
ranking.value = [] ranking.value = []
rankingAdd.value = [] myRanking.value = {}
rankingHasMore.value = false rankingHasMore.value = false
} finally { } finally {
rankingLoading.value = false rankingLoading.value = false
@ -2233,7 +2318,6 @@ const getRoomContributionRanking = async () => {
ranking.value = records.map((item, index) => ranking.value = records.map((item, index) =>
normalizeRoomContributionRankingItem(item, index), normalizeRoomContributionRankingItem(item, index),
) )
rankingAdd.value = []
myRanking.value = resRanking.body.current myRanking.value = resRanking.body.current
? normalizeRoomContributionRankingItem(resRanking.body.current, null) ? normalizeRoomContributionRankingItem(resRanking.body.current, null)
: {} : {}
@ -2242,7 +2326,6 @@ const getRoomContributionRanking = async () => {
} }
ranking.value = [] ranking.value = []
rankingAdd.value = []
myRanking.value = {} myRanking.value = {}
rankingHasMore.value = false rankingHasMore.value = false
} finally { } finally {
@ -2282,16 +2365,14 @@ const loadRankingSection = async () => {
rankingLoaded.value = true rankingLoaded.value = true
loadedRankingType.value = rankingType loadedRankingType.value = rankingType
rankingPageNo.value = 1
ranking.value = [] ranking.value = []
rankingAdd.value = []
myRanking.value = {} myRanking.value = {}
rankingHasMore.value = true rankingHasMore.value = true
try { try {
const loaders = isRoomRankingSection.value const loaders = isRoomRankingSection.value
? [getRoomContributionRanking()] ? [getRoomContributionRanking()]
: [getMyPersonalRanking(), getPersonalRanking()] : [getPersonalRanking()]
if (isPersonalRankingSection.value) { if (isPersonalRankingSection.value) {
loaders.unshift(getWeeklyGifts()) loaders.unshift(getWeeklyGifts())
@ -2314,11 +2395,6 @@ const observeRankingLoadmore = async () => {
rankingObserver.observe(rankingLoadmore.value) rankingObserver.observe(rankingLoadmore.value)
} }
// 使
const lotteryPrizeImage = (index) => {
return imageUrl(index === activeLotteryIndex.value ? 'lotteryPrizeActiveBg' : 'lotteryPrizeBg')
}
const normalizeLotteryIndex = (index) => { const normalizeLotteryIndex = (index) => {
const prizeCount = activeLotteryPrizes.value.length const prizeCount = activeLotteryPrizes.value.length
if (!prizeCount) { if (!prizeCount) {
@ -2328,8 +2404,32 @@ const normalizeLotteryIndex = (index) => {
return (((Number(index) || 0) % prizeCount) + prizeCount) % prizeCount return (((Number(index) || 0) % prizeCount) + prizeCount) % prizeCount
} }
// id/name // id/name
const getLotteryResultIndex = (drawResult) => { const getLotteryResultIndex = (drawResult) => {
const rewards = Array.isArray(drawResult?.results) ? drawResult.results : []
const resultReward = rewards.find((reward) => reward?.isWin) || rewards[0] || drawResult
const prizeList = activeLotteryPrizes.value
const matchedPrizeIndex = prizeList.findIndex((prize) => {
const samePrizeId =
resultReward?.prizeId !== undefined && String(prize.id) === String(resultReward.prizeId)
const samePrizeName =
resultReward?.prizeName && prize.prizeName && prize.prizeName === resultReward.prizeName
const samePrizeImage =
resultReward?.prizeImage && prize.prizeImage && prize.prizeImage === resultReward.prizeImage
const samePrizeTypeAndValue =
resultReward?.prizeType &&
prize.prizeType &&
resultReward.prizeType === prize.prizeType &&
Number(resultReward?.prizeValue || 0) === Number(prize?.prizeValue || 0)
return samePrizeId || samePrizeName || samePrizeImage || samePrizeTypeAndValue
})
if (matchedPrizeIndex >= 0) {
return normalizeLotteryIndex(matchedPrizeIndex)
}
if (typeof drawResult?.prizeIndex === 'number') { if (typeof drawResult?.prizeIndex === 'number') {
return normalizeLotteryIndex(drawResult.prizeIndex) return normalizeLotteryIndex(drawResult.prizeIndex)
} }
@ -2351,8 +2451,11 @@ const startLotteryAnimation = (resultIndex) => {
} }
const targetIndex = normalizeLotteryIndex(resultIndex) const targetIndex = normalizeLotteryIndex(resultIndex)
const startIndex =
activeLotteryIndex.value >= 0 ? normalizeLotteryIndex(activeLotteryIndex.value) : 0
const distanceToTarget = (targetIndex - startIndex + prizeCount) % prizeCount
const minRounds = 3 const minRounds = 3
const totalSteps = prizeCount * minRounds + targetIndex + 1 const totalSteps = prizeCount * minRounds + distanceToTarget + 1
let step = 0 let step = 0
const roll = () => { const roll = () => {
@ -2363,11 +2466,11 @@ const startLotteryAnimation = (resultIndex) => {
return return
} }
activeLotteryIndex.value = step % prizeCount activeLotteryIndex.value = (startIndex + step) % prizeCount
step += 1 step += 1
const progress = step / totalSteps const progress = step / totalSteps
const delay = 70 + Math.round(progress * progress * 190) const delay = 130 + Math.round(progress * progress * 220)
lotteryAnimationTimer = window.setTimeout(roll, delay) lotteryAnimationTimer = window.setTimeout(roll, delay)
} }
@ -2389,10 +2492,22 @@ const requestLotteryDraw = async (drawCount) => {
return null return null
} }
const responseBody = resRewardDraw.body || {}
const rewards = Array.isArray(responseBody?.rewards)
? responseBody.rewards
: Array.isArray(responseBody?.results)
? responseBody.results
: Array.isArray(responseBody)
? responseBody
: responseBody
? [responseBody]
: []
return { return {
drawCount, drawCount,
prizeIndex: Math.min(3, activeLotteryPrizes.value.length - 1), batchNo: responseBody?.batchNo || '',
results: resRewardDraw.body || [], results: rewards,
raw: responseBody,
} }
} }
@ -2468,15 +2583,6 @@ const startCountdown = () => {
countdownTimer = window.setInterval(calculateCountdown, 1000) countdownTimer = window.setInterval(calculateCountdown, 1000)
} }
//
const tabButtonImage = (value) => {
return imageUrl(value === activeTopTab.value ? 'tagActiveBg' : 'tagBg')
}
const childTabButtonImage = (value) => {
return imageUrl(value === activeChildTab.value ? 'moduleActiveBg' : 'moduleBg')
}
const changeTopTab = (value) => { const changeTopTab = (value) => {
activeTopTab.value = value activeTopTab.value = value
} }
@ -2688,6 +2794,26 @@ onUnmounted(() => {
.tab-background { .tab-background {
height: 100%; height: 100%;
overflow: hidden;
contain: layout paint;
isolation: isolate;
transform: translateZ(0);
}
.tab-background :deep(.scrollY) {
z-index: 1;
overflow: hidden;
}
.tab-active-bg {
position: absolute;
inset: 0;
z-index: 0;
width: 100%;
height: 100%;
display: block;
object-fit: fill;
pointer-events: none;
} }
.image-tab span { .image-tab span {
@ -2717,7 +2843,7 @@ onUnmounted(() => {
color: #5b0000; color: #5b0000;
} }
/* 第四行:当前标签内容占位区 */ /* 第四行:当前标签内容区 */
.lottery-prize-list { .lottery-prize-list {
--lottery-prize-gap: 3vw; --lottery-prize-gap: 3vw;
} }
@ -2730,6 +2856,25 @@ onUnmounted(() => {
width: calc((100% - var(--lottery-prize-gap) * 2) / 3); width: calc((100% - var(--lottery-prize-gap) * 2) / 3);
min-width: 0; min-width: 0;
flex: 0 0 calc((100% - var(--lottery-prize-gap) * 2) / 3); flex: 0 0 calc((100% - var(--lottery-prize-gap) * 2) / 3);
overflow: hidden;
contain: layout paint;
isolation: isolate;
transform: translateZ(0);
}
.lottery-prize-item :deep(.scrollY) {
z-index: 1;
}
.lottery-prize-active-bg {
position: absolute;
inset: 0;
z-index: 0;
width: 100%;
height: 100%;
display: block;
object-fit: fill;
pointer-events: none;
} }
.lottery-prize-item-sr { .lottery-prize-item-sr {

View File

@ -6,8 +6,9 @@ export const pageConfig = {
activity: { activity: {
activityId: '1001', activityId: '1001',
templateId: '2057676469390872578',
activityCode: '', activityCode: '',
activityType: '', activityType: 19,
personalRankActivityType: 'THIS_WEEK', personalRankActivityType: 'THIS_WEEK',
roomRankActivityType: '', roomRankActivityType: '',
rewardActivityType: 'DAILY_RECHARGE_TASK2', rewardActivityType: 'DAILY_RECHARGE_TASK2',
@ -15,7 +16,27 @@ export const pageConfig = {
}, },
preload: { preload: {
blocking: ['bg', 'ruleBtBg', 'timeBg', 'tagActiveBg', 'tagBg', 'lotteryBg', 'collectGameBg'], blocking: [
'bg',
'ruleBtBg',
'timeBg',
'tagActiveBg',
'tagBg',
'moduleActiveBg',
'moduleBg',
'lotteryBg',
'collectGameBg',
'taskItemBg',
'RewardTop1',
'RewardTop2',
'RewardTop3',
'ruleActivity',
'giftBg',
'RankingItem',
'top1',
'top2',
'top3',
],
background: [ background: [
'barrageBg', 'barrageBg',
'cardBackBg', 'cardBackBg',

File diff suppressed because it is too large Load Diff