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
}
}
// 查询中奖记录
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
v-if="shouldShowImage"
v-smart-img
v-smart-img.noFade
:src="imgUrl"
:class="flip ? 'flipImg' : ''"
alt=""

View File

@ -6,13 +6,14 @@ import { resolveProtectedAssetUrl } from '@/utils/protectedAssets.js'
export const smartImage = {
async mounted(el, binding) {
const skipFade = binding.modifiers.noFade || binding.arg === 'noFade' || isLowEndDevice()
const keepVisible = binding.modifiers.noFade || binding.arg === 'noFade'
el.decoding = 'async'
const url = getValidUrl(binding.value, el)
if (url) {
prepareImageLoadingState(el, skipFade)
prepareImageLoadingState(el, skipFade, keepVisible)
await processImage(el, url)
el._smartImageCurrentUrl = url
el._smartImageOriginalBindingValue = binding.value
@ -24,6 +25,7 @@ export const smartImage = {
async updated(el, binding) {
const skipFade = binding.modifiers.noFade || binding.arg === 'noFade' || isLowEndDevice()
const keepVisible = binding.modifiers.noFade || binding.arg === 'noFade'
const currentUrl = getValidUrl(binding.value, el)
const bindingChanged = binding.value !== binding.oldValue
const elementSrcChanged = currentUrl && currentUrl !== el._smartImageCurrentUrl
@ -33,7 +35,7 @@ export const smartImage = {
}
if (currentUrl && currentUrl !== el._smartImageCurrentUrl) {
prepareImageLoadingState(el, skipFade)
prepareImageLoadingState(el, skipFade, keepVisible)
await processImage(el, currentUrl)
el._smartImageCurrentUrl = currentUrl
el._smartImageOriginalBindingValue = binding.value
@ -68,7 +70,12 @@ function getValidUrl(bindingValue, el) {
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.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',
name: 'gulben-festival',
component: () => import('../views/Activities/GulbenFestival/index.vue'),
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',
name: 'pokerAce',

View File

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

View File

@ -1,4 +1,4 @@
<template>
<template>
<div class="fullPage">
<!-- 页面同步预加载首屏关键图片加载完成前展示 loading -->
<div
@ -118,15 +118,22 @@
>
<itemCenter
class="tab-background"
:imgUrl="tabButtonImage(tab.value)"
:imgUrl="imageUrl('tagBg')"
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>
</button>
</section>
<!-- 标签内容预览区后续按模块逐步替换为真实业务内容 -->
<!-- 标签内容根据当前标签逐步展示对应业务模块 -->
<section style="min-height: 86vw; padding: 0; margin: 0">
<div v-if="currentTopSection">
<!-- 二级标签个人榜和房间榜下的 Reward / Ranking -->
@ -150,10 +157,19 @@
>
<itemCenter
class="tab-background"
:imgUrl="childTabButtonImage(tab.value)"
:imgUrl="imageUrl('moduleBg')"
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>
</button>
</div>
@ -177,7 +193,36 @@
style="width: 100vw; margin: 0; padding: 0"
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
style="width: 100%; height: 100%; display: flex; flex-direction: column; gap: 0"
>
@ -194,7 +239,7 @@
@click="changeLotteryPoolMode(-1)"
>
<img
v-smart-img
v-smart-img.noFade
:src="imageUrl('leftBt')"
alt=""
style="width: 8vw; display: block"
@ -226,20 +271,39 @@
<itemCenter
v-for="prize in row"
:key="prize.renderKey"
:imgUrl="lotteryPrizeImage(prize.index)"
:class="['lottery-prize-item', activeLotteryPoolMode.itemClass]"
:imgUrl="imageUrl('lotteryPrizeBg')"
: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;"
>
<img
v-show="prize.index === activeLotteryIndex"
v-smart-img.noFade
:src="imageUrl('lotteryPrizeActiveBg')"
class="lottery-prize-active-bg"
alt=""
/>
<img
v-if="prize.prizeImage"
v-smart-img
v-smart-img.noFade
:src="prize.prizeImage"
alt=""
style="width: 60%; display: block; object-fit: contain"
style="
position: relative;
z-index: 1;
width: 60%;
display: block;
object-fit: contain;
"
@error="handleRewardImageError"
/>
<div
style="
position: relative;
z-index: 1;
width: 100%;
color: #fff;
font-size: 0.7em;
@ -267,7 +331,7 @@
@click="changeLotteryPoolMode(1)"
>
<img
v-smart-img
v-smart-img.noFade
:src="imageUrl('leftBt')"
alt=""
style="width: 8vw; display: block; transform: scaleX(-1)"
@ -275,7 +339,7 @@
</div>
</div>
<!-- 抽奖区域下层单抽和5连抽按钮内部后续可替换抽奖券图标 -->
<!-- 抽奖区域下层单抽和5连抽按钮内部放当前奖池票券图标 -->
<div
style="
display: flex;
@ -294,7 +358,7 @@
@click="handleLotteryDraw(1)"
>
<img
v-smart-img
v-smart-img.noFade
:src="imageUrl(activeLotteryTicketImage)"
alt=""
style="width: 10vw; display: block"
@ -308,7 +372,7 @@
@click="handleLotteryDraw(5)"
>
<img
v-smart-img
v-smart-img.noFade
:src="imageUrl(activeLotteryTicketImage)"
alt=""
style="width: 10vw; display: block"
@ -364,7 +428,7 @@
>
<div style="width: 3vw; height: 100%">
<img
v-smart-img
v-smart-img.noFade
:src="imageUrl('helpBt')"
alt=""
style="width: 100%; display: block"
@ -372,7 +436,7 @@
</div>
<img
v-smart-img
v-smart-img.noFade
:src="imageUrl(ticket.image)"
alt=""
style="width: 13vw; display: block"
@ -409,7 +473,7 @@
"
>
<img
v-smart-img
v-smart-img.noFade
:src="imageUrl(activeCollectGameTitle)"
alt=""
style="height: 6.5vw; width: auto; display: block"
@ -438,7 +502,7 @@
@click="changeCollectGameMode(-1)"
>
<img
v-smart-img
v-smart-img.noFade
:src="imageUrl('leftBt')"
alt=""
style="width: 8vw; display: block"
@ -459,7 +523,7 @@
<template v-for="card in activeCollectCards" :key="card.cardTemplateId">
<img
v-if="card.isCardBack"
v-smart-img
v-smart-img.noFade
:src="imageUrl('cardBackBg')"
alt=""
style="height: 100%; width: auto; display: block"
@ -508,7 +572,7 @@
@click="changeCollectGameMode(1)"
>
<img
v-smart-img
v-smart-img.noFade
:src="imageUrl('leftBt')"
alt=""
style="width: 8vw; display: block; transform: scaleX(-1)"
@ -614,7 +678,7 @@
"
>
<img
v-smart-img
v-smart-img.noFade
:src="imageUrl(activeCollectTicketImage)"
alt=""
style="width: 6vw; display: block"
@ -657,7 +721,7 @@
<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>
<img
v-smart-img
v-smart-img.noFade
:src="imageUrl('Gameticket')"
:alt="t('ticket')"
width="20vw"
@ -693,7 +757,7 @@
</div>
</itemCenter>
<!-- 已完成 -->
<!-- 宸插畬鎴?-->
<itemCenter v-else style="" :imgUrl="imageUrl('taskBtReceived')">
<div style="font-size: 0.9em; font-weight: 600; white-space: nowrap">
{{ t('task_received') }}
@ -732,10 +796,18 @@
style="width: 100vw; margin: 0; padding: 0"
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
v-if="getRewardTopMainReward(rewardTop)"
v-if="getRewardTopMainReward(rewardTop, topIndex)"
style="
width: 33vw;
flex: 0 0 33vw;
@ -757,14 +829,19 @@
"
>
<img
:src="getRewardTopMainReward(rewardTop).cover || ''"
v-if="hasRewardCover(getRewardTopMainReward(rewardTop, topIndex))"
:src="getRewardTopMainReward(rewardTop, topIndex).cover || ''"
alt=""
style="width: 92%; display: block; object-fit: contain"
@error="
(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
style="
@ -775,7 +852,7 @@
text-align: center;
"
>
{{ getRewardDisplayText(getRewardTopMainReward(rewardTop)) }}
{{ getRewardDisplayText(getRewardTopMainReward(rewardTop, topIndex)) }}
</div>
</div>
@ -784,7 +861,7 @@
style="flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1.7vw"
>
<div
v-for="(row, rowIndex) in getRewardTopGridRows(rewardTop)"
v-for="(row, rowIndex) in getRewardTopGridRows(rewardTop, topIndex)"
:key="`${topIndex}-${rowIndex}`"
style="display: flex; justify-content: center; gap: 2.7vw"
>
@ -818,11 +895,17 @@
"
>
<img
v-if="hasRewardCover(reward)"
:src="reward.cover || ''"
alt=""
style="width: 88%; display: block; object-fit: contain"
@error="(event) => handleRewardImageError(event, reward.type)"
/>
<div
v-else
aria-hidden="true"
style="width: 88%; aspect-ratio: 1/1"
></div>
</div>
<div
style="
@ -852,7 +935,7 @@
>
<!-- Room Rank / Reward直接展示规则奖励图 -->
<img
v-smart-img
v-smart-img.noFade
:src="imageUrl('ruleActivity')"
alt=""
style="width: 100vw; display: block"
@ -924,7 +1007,7 @@
"
>
<img
v-smart-img
v-smart-img.noFade
:src="coinIcon"
alt=""
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"
>
<img
v-smart-img
v-smart-img.noFade
:src="imageUrl('vip1')"
alt=""
style="width: 12vw; display: block"
@ -1067,7 +1150,7 @@
"
>
<img
v-smart-img
v-smart-img.noFade
:src="coinIcon"
alt=""
style="display: block; width: 1.3em; aspect-ratio: 1/1"
@ -1101,7 +1184,7 @@
<img
v-for="imageName in activePreviewImages"
:key="imageName"
v-smart-img
v-smart-img.noFade
:src="imageUrl(imageName)"
alt=""
class="preview-image"
@ -1183,7 +1266,12 @@
{{ t('user_id_prefix') }} {{ myRanking.specialAccount || myRanking.account }}
</div>
<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
:imgUrl="imageUrl('userLevel1Bg')"
style="width: 10vw; margin: 0; padding: 0"
@ -1209,7 +1297,7 @@
"
>
<img
v-smart-img
v-smart-img.noFade
:src="coinIcon"
alt=""
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 { formatRewardDisplay } from '@/utils/rewardFormatter.js'
import {
apiGetActivityResource,
apiGetCardRewardMarquee,
apiGetCardRewardPrizeList,
apiGetCardTicketList,
@ -1302,11 +1389,10 @@ import {
apiPostCardDraw,
apiPostCardRedeem,
apiPostCardRewardDraw,
getRankingListAndMyRanking,
getThisWeekRewardsAndGifts,
} from '@/api/activity.js'
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 BackgroundLayer from '@/components/BackgroundLayer.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 gulbenActivityId = '1001'
const kingQueenGiftTemplateId = '1966020557831610370'
const weeklyStarPageSize = 10
const templateId = ref(pageConfig.activity.templateId || '2057676469390872578')
const activityType = ref(pageConfig.activity.activityType || '')
const roomRankingParams = {
startDate: '20260518',
endDate: '20260524',
@ -1358,11 +1444,8 @@ const weeklyGifts = ref([
giftCandy: 0,
},
])
const rankingPageNo = ref(1)
const ranking = ref([])
const rankingAdd = ref([])
const myRanking = ref({})
const userInfo = ref({})
const rankingLoaded = ref(false)
const loadedRankingType = ref('')
const rankingLoading = ref(false)
@ -1718,23 +1801,15 @@ const cardDrawTicketCount = computed(() => getTicketRemainingCount('CARD'))
const maskLayerShow = computed(() => ruleShow.value)
const weeklyStarRankingType = computed(() => {
return pageConfig.activity.personalRankActivityType || 'THIS_WEEK'
})
const activeRankingLoadKey = computed(() => {
if (isRoomRankingSection.value) {
return `room-${roomRankingParams.startDate}-${roomRankingParams.endDate}-${roomRankingParams.size}`
}
return `personal-${weeklyStarRankingType.value}`
return `personal-${activityType.value}`
})
const personalRewardActivityType = computed(() => {
return pageConfig.activity.rewardActivityType || 'DAILY_RECHARGE_TASK2'
})
const rankingTotal = computed(() => [...ranking.value, ...rankingAdd.value])
const rankingTotal = computed(() => ranking.value)
const rankingTop3 = computed(() => {
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 rewardTops = activityRewards.value.length
? activityRewards.value
: fallbackPersonalRewardTops.value
return rewardTops.slice(0, 3)
return activityRewards.value.slice(0, 3)
})
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})`
}
@ -1931,10 +2041,7 @@ const handleCardDraw = async (drawCount = 1) => {
})
if (resDraw.status) {
await Promise.all([
getCardTicketList(), // CARD
getCardBagListByGrade('R'), // R R
])
await Promise.all([getCardTicketList(), getCardBagListByGrade('R')])
}
} catch (error) {
showError(error.errorMsg)
@ -1993,8 +2100,8 @@ const handleCardRedeem = async () => {
if (resRedeem.status) {
await Promise.all([
getCardTicketList(), // STANDARD / PREMIUM / LUXURY
getCardBagListByGrade(activeCollectGameMode.value.cardGrade), //
getCardTicketList(),
getCardBagListByGrade(activeCollectGameMode.value.cardGrade),
])
}
} catch (error) {
@ -2026,7 +2133,8 @@ const receiveTaskReward = async (code) => {
taskCode: code,
})
if (resReceive.status && resReceive.body) {
getTaskList()
getTaskList() //
getCardTicketList() //
}
} catch (error) {
showError(error.errorMsg)
@ -2034,63 +2142,88 @@ const receiveTaskReward = async (code) => {
}
const getWeeklyGifts = async () => {
const resRewardsAndGifts = await getThisWeekRewardsAndGifts(kingQueenGiftTemplateId)
const resRewardsAndGifts = await getThisWeekRewardsAndGifts(templateId.value)
if (resRewardsAndGifts.status && resRewardsAndGifts.body?.gifts?.length) {
weeklyGifts.value = resRewardsAndGifts.body.gifts.slice(0, 3)
}
}
const getPersonalRewardList = (rewardTop) => {
const rewards = rewardTop?.propsGroup?.activityRewardProps
const getPersonalRewardExtraItem = (topIndex) => {
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)) {
return []
}
const rewardList = rewards.slice(0, 6)
const extraReward = getPersonalRewardExtraItem(topIndex)
if (extraReward && rewardList.length < 6) {
rewardList.push(extraReward)
}
if (rewardList.length === 5) {
rewardList.push({
...rewardList[4],
isCopiedPreviewReward: true,
isEmptyPreviewReward: true,
})
}
return rewardList
}
const getRewardTopMainReward = (rewardTop) => {
return getPersonalRewardList(rewardTop)[0] || null
const getRewardTopMainReward = (rewardTop, topIndex) => {
return getPersonalRewardList(rewardTop, topIndex)[0] || null
}
const getRewardTopGridRows = (rewardTop) => {
const rewards = getPersonalRewardList(rewardTop).slice(1, 6)
const getRewardTopGridRows = (rewardTop, topIndex) => {
const rewards = getPersonalRewardList(rewardTop, topIndex).slice(1, 6)
return [rewards.slice(0, 2), rewards.slice(2, 4), rewards.slice(4, 5)]
}
const getRewardDisplayText = (reward) => {
if (!reward) {
if (!reward || reward.isEmptyPreviewReward) {
return ''
}
return formatRewardDisplay(reward.type, reward)
}
const getLotteryPrizeDisplayText = (prize) => {
if (!prize?.prizeType) {
return ''
}
const hasRewardCover = (reward) => {
return Boolean(reward?.cover)
}
return (
formatRewardDisplay(prize.prizeType, {
...prize,
type: prize.prizeType,
content: prize.prizeValue,
quantity: prize.prizeValue,
}) || prize.prizeName
)
const getLotteryPrizeDisplayText = (prize) => {
return prize?.prizeName || ''
}
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 () => {
@ -2101,16 +2234,16 @@ const getPersonalRewardConfigs = async () => {
personalRewardLoaded.value = true
try {
const res = await apiGetActivityResource(personalRewardActivityType.value)
if (res.status && res.body) {
activityRewards.value = Array.isArray(res.body) ? res.body.slice(0, 3) : []
const resRewardsAndGifts = await getThisWeekRewardsAndGifts(templateId.value)
if (resRewardsAndGifts.status && resRewardsAndGifts.body) {
activityRewards.value = (resRewardsAndGifts.body.butOneRewards || []).slice(0, 3)
}
} catch (error) {
showError(error.errorMsg)
}
}
const normalizeWeeklyStarRankingItem = (item = {}, index = 0) => {
const normalizePersonalRankingItem = (item = {}, index = 0) => {
return {
...item,
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 () => {
if (rankingLoading.value || !rankingHasMore.value) {
return
@ -2178,40 +2282,21 @@ const getPersonalRanking = async () => {
rankingLoading.value = true
try {
const resRanking = await getWeekStarRanking({
type: weeklyStarRankingType.value,
current: rankingPageNo.value,
size: weeklyStarPageSize,
const resRanking = await getRankingListAndMyRanking({
activityType: activityType.value,
})
if (resRanking.status && resRanking.body?.rankUsers) {
const rankUsers = resRanking.body.rankUsers
const records = rankUsers.records || []
const pageSize = Number(rankUsers.size || weeklyStarPageSize)
const total = Number(rankUsers.total || 0)
const startIndex = (rankingPageNo.value - 1) * pageSize
const list = records.map((item, index) =>
normalizeWeeklyStarRankingItem(item, startIndex + index),
if (resRanking.status && resRanking.body) {
myRanking.value = normalizePersonalRankingItem(resRanking.body.currentUserRank || {}, null)
ranking.value = (resRanking.body.rankingList || []).map((item, index) =>
normalizePersonalRankingItem(item, index),
)
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
}
rankingHasMore.value = false
return
}
ranking.value = []
rankingAdd.value = []
myRanking.value = {}
rankingHasMore.value = false
} finally {
rankingLoading.value = false
@ -2233,7 +2318,6 @@ const getRoomContributionRanking = async () => {
ranking.value = records.map((item, index) =>
normalizeRoomContributionRankingItem(item, index),
)
rankingAdd.value = []
myRanking.value = resRanking.body.current
? normalizeRoomContributionRankingItem(resRanking.body.current, null)
: {}
@ -2242,7 +2326,6 @@ const getRoomContributionRanking = async () => {
}
ranking.value = []
rankingAdd.value = []
myRanking.value = {}
rankingHasMore.value = false
} finally {
@ -2282,16 +2365,14 @@ const loadRankingSection = async () => {
rankingLoaded.value = true
loadedRankingType.value = rankingType
rankingPageNo.value = 1
ranking.value = []
rankingAdd.value = []
myRanking.value = {}
rankingHasMore.value = true
try {
const loaders = isRoomRankingSection.value
? [getRoomContributionRanking()]
: [getMyPersonalRanking(), getPersonalRanking()]
: [getPersonalRanking()]
if (isPersonalRankingSection.value) {
loaders.unshift(getWeeklyGifts())
@ -2314,11 +2395,6 @@ const observeRankingLoadmore = async () => {
rankingObserver.observe(rankingLoadmore.value)
}
// 使
const lotteryPrizeImage = (index) => {
return imageUrl(index === activeLotteryIndex.value ? 'lotteryPrizeActiveBg' : 'lotteryPrizeBg')
}
const normalizeLotteryIndex = (index) => {
const prizeCount = activeLotteryPrizes.value.length
if (!prizeCount) {
@ -2328,8 +2404,32 @@ const normalizeLotteryIndex = (index) => {
return (((Number(index) || 0) % prizeCount) + prizeCount) % prizeCount
}
// id/name
// id/name
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') {
return normalizeLotteryIndex(drawResult.prizeIndex)
}
@ -2351,8 +2451,11 @@ const startLotteryAnimation = (resultIndex) => {
}
const targetIndex = normalizeLotteryIndex(resultIndex)
const startIndex =
activeLotteryIndex.value >= 0 ? normalizeLotteryIndex(activeLotteryIndex.value) : 0
const distanceToTarget = (targetIndex - startIndex + prizeCount) % prizeCount
const minRounds = 3
const totalSteps = prizeCount * minRounds + targetIndex + 1
const totalSteps = prizeCount * minRounds + distanceToTarget + 1
let step = 0
const roll = () => {
@ -2363,11 +2466,11 @@ const startLotteryAnimation = (resultIndex) => {
return
}
activeLotteryIndex.value = step % prizeCount
activeLotteryIndex.value = (startIndex + step) % prizeCount
step += 1
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)
}
@ -2389,10 +2492,22 @@ const requestLotteryDraw = async (drawCount) => {
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 {
drawCount,
prizeIndex: Math.min(3, activeLotteryPrizes.value.length - 1),
results: resRewardDraw.body || [],
batchNo: responseBody?.batchNo || '',
results: rewards,
raw: responseBody,
}
}
@ -2468,15 +2583,6 @@ const startCountdown = () => {
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) => {
activeTopTab.value = value
}
@ -2688,6 +2794,26 @@ onUnmounted(() => {
.tab-background {
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 {
@ -2717,7 +2843,7 @@ onUnmounted(() => {
color: #5b0000;
}
/* 第四行:当前标签内容占位区 */
/* 第四行:当前标签内容区 */
.lottery-prize-list {
--lottery-prize-gap: 3vw;
}
@ -2730,6 +2856,25 @@ onUnmounted(() => {
width: calc((100% - var(--lottery-prize-gap) * 2) / 3);
min-width: 0;
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 {

View File

@ -6,8 +6,9 @@ export const pageConfig = {
activity: {
activityId: '1001',
templateId: '2057676469390872578',
activityCode: '',
activityType: '',
activityType: 19,
personalRankActivityType: 'THIS_WEEK',
roomRankActivityType: '',
rewardActivityType: 'DAILY_RECHARGE_TASK2',
@ -15,7 +16,27 @@ export const pageConfig = {
},
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: [
'barrageBg',
'cardBackBg',

File diff suppressed because it is too large Load Diff