feat(古尔邦节): 调整页面
This commit is contained in:
parent
7186265a8b
commit
c93f91801f
@ -467,6 +467,7 @@
|
||||
"Reward": "المكافآت",
|
||||
"Ranking": "الترتيب",
|
||||
"gulben_collect_tip": "*استبدل بطاقاتك واسحب للحصول على مكافآت رائعة!",
|
||||
"gulben_barrage_get_a": "حصل على",
|
||||
"gulben_remaining_tickets": "التذاكر المتبقية: *{count}",
|
||||
"gulben_coins_cost": "{count}/عملات",
|
||||
"gulben_combine_count": "دمج * {count}",
|
||||
|
||||
@ -467,6 +467,7 @@
|
||||
"Reward": "পুরস্কার",
|
||||
"Ranking": "র্যাঙ্কিং",
|
||||
"gulben_collect_tip": "*আপনার কার্ড রিডিম করুন এবং দারুণ পুরস্কারের জন্য ড্র করুন!",
|
||||
"gulben_barrage_get_a": "পেয়েছেন",
|
||||
"gulben_remaining_tickets": "অবশিষ্ট টিকিট: *{count}",
|
||||
"gulben_coins_cost": "{count}/কয়েন",
|
||||
"gulben_combine_count": "কম্বাইন * {count}",
|
||||
|
||||
@ -467,6 +467,7 @@
|
||||
"Reward": "Reward",
|
||||
"Ranking": "Ranking",
|
||||
"gulben_collect_tip": "*Redeem Your Cards and Draw for Amazing Rewards!",
|
||||
"gulben_barrage_get_a": "Get a",
|
||||
"gulben_remaining_tickets": "Remaining Tickets: *{count}",
|
||||
"gulben_coins_cost": "{count}/coins",
|
||||
"gulben_combine_count": "Combine * {count}",
|
||||
|
||||
@ -467,6 +467,7 @@
|
||||
"Reward": "Ödül",
|
||||
"Ranking": "Sıralama",
|
||||
"gulben_collect_tip": "*Kartlarını kullan ve harika ödüller için çekiliş yap!",
|
||||
"gulben_barrage_get_a": "Kazandı",
|
||||
"gulben_remaining_tickets": "Kalan Biletler: *{count}",
|
||||
"gulben_coins_cost": "{count}/coin",
|
||||
"gulben_combine_count": "Birleştir * {count}",
|
||||
|
||||
@ -467,6 +467,7 @@
|
||||
"Reward": "奖励",
|
||||
"Ranking": "排行",
|
||||
"gulben_collect_tip": "*兑换卡片并抽取丰厚奖励!",
|
||||
"gulben_barrage_get_a": "获得",
|
||||
"gulben_remaining_tickets": "剩余票券:*{count}",
|
||||
"gulben_coins_cost": "{count}/金币",
|
||||
"gulben_combine_count": "合成 * {count}",
|
||||
|
||||
@ -189,8 +189,89 @@
|
||||
"
|
||||
>
|
||||
<template v-for="imageName in activeContainerImages" :key="imageName">
|
||||
<!-- 弹幕模块:中奖飘窗接口返回后横向展示一行 -->
|
||||
<div
|
||||
v-if="imageName === 'barrage' && barrageRenderList.length"
|
||||
style="
|
||||
width: 100vw;
|
||||
height: 8vw;
|
||||
overflow: hidden;
|
||||
margin: 0 0 4vw 0;
|
||||
padding: 0;
|
||||
direction: ltr;
|
||||
"
|
||||
>
|
||||
<div
|
||||
class="barrage-track"
|
||||
style="display: flex; align-items: center; gap: 3vw; height: 100%"
|
||||
>
|
||||
<itemCenter
|
||||
v-for="(item, index) in barrageRenderList"
|
||||
:key="`${item.account || item.nickName || index}-${item.drawTime || index}`"
|
||||
:imgUrl="imageUrl('barrageBg')"
|
||||
style="width: 45vw; height: 8vw; flex: 0 0 45vw; margin: 0; padding: 0"
|
||||
contentStyle="padding: 0 2vw; display: flex; align-items: center; justify-content: flex-start; gap: 1vw; box-sizing: border-box;"
|
||||
>
|
||||
<img
|
||||
v-smart-img.noFade
|
||||
:src="item.avatar"
|
||||
alt=""
|
||||
style="
|
||||
width: 6vw;
|
||||
height: 6vw;
|
||||
flex: 0 0 6vw;
|
||||
border-radius: 50%;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
"
|
||||
@error="handleAvatarImageError"
|
||||
/>
|
||||
<div
|
||||
style="
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
gap: 0.5vw;
|
||||
"
|
||||
>
|
||||
<div
|
||||
style="
|
||||
width: 100%;
|
||||
color: #fff;
|
||||
font-size: 1em;
|
||||
font-weight: 700;
|
||||
line-height: 1.1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
"
|
||||
>
|
||||
{{ item.nickName || item.account || '' }}
|
||||
</div>
|
||||
<div
|
||||
style="
|
||||
width: 100%;
|
||||
color: #fff;
|
||||
font-size: 1em;
|
||||
font-weight: 600;
|
||||
line-height: 1.1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
"
|
||||
>
|
||||
{{ t('gulben_barrage_get_a') }} {{ item.prizeName || '' }}
|
||||
</div>
|
||||
</div>
|
||||
</itemCenter>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- lotteryBg -->
|
||||
<itemCenter
|
||||
v-if="imageName === 'lotteryBg'"
|
||||
v-else-if="imageName === 'lotteryBg'"
|
||||
:imgUrl="imageUrl(imageName)"
|
||||
style="width: 100vw; margin: 0; padding: 0"
|
||||
contentStyle="padding: 8vw 5vw 0; align-items: stretch; justify-content: flex-start; box-sizing: border-box;"
|
||||
@ -385,6 +466,7 @@
|
||||
</div>
|
||||
</itemCenter>
|
||||
|
||||
<!-- collectGameBg -->
|
||||
<itemCenter
|
||||
v-else-if="imageName === 'collectGameBg'"
|
||||
:imgUrl="imageUrl(imageName)"
|
||||
@ -693,6 +775,7 @@
|
||||
</div>
|
||||
</itemCenter>
|
||||
|
||||
<!-- taskModule -->
|
||||
<div
|
||||
v-else-if="imageName === 'taskModule'"
|
||||
style="
|
||||
@ -1065,7 +1148,6 @@
|
||||
:name="rankingTop3[1].userName"
|
||||
:distributionValue="rankingTop3[1].amount"
|
||||
:valueIconUrl="coinIcon"
|
||||
:avatar-square="isRoomRankingSection"
|
||||
style="width: 100%"
|
||||
@click="handleRankingClick(rankingTop3[1])"
|
||||
/>
|
||||
@ -1078,7 +1160,6 @@
|
||||
:name="rankingTop3[0].userName"
|
||||
:distributionValue="rankingTop3[0].amount"
|
||||
:valueIconUrl="coinIcon"
|
||||
:avatar-square="isRoomRankingSection"
|
||||
style="width: 100%"
|
||||
@click="handleRankingClick(rankingTop3[0])"
|
||||
/>
|
||||
@ -1091,7 +1172,6 @@
|
||||
:name="rankingTop3[2].userName"
|
||||
:distributionValue="rankingTop3[2].amount"
|
||||
:valueIconUrl="coinIcon"
|
||||
:avatar-square="isRoomRankingSection"
|
||||
style="width: 100%"
|
||||
@click="handleRankingClick(rankingTop3[2])"
|
||||
/>
|
||||
@ -1586,17 +1666,37 @@
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="showRewardResultSwitcher"
|
||||
v-if="cardResultActionMode === 'rewardDraw'"
|
||||
style="
|
||||
position: relative;
|
||||
width: 100%;
|
||||
min-height: 1.2em;
|
||||
color: #fff;
|
||||
font-size: 1em;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
line-height: 1.2;
|
||||
text-align: center;
|
||||
"
|
||||
>
|
||||
{{ cardDrawResultIndex + 1 }}/{{ cardDrawResultList.length }}
|
||||
<span style="color: #fff; font-size: 1em; font-weight: 700">
|
||||
{{ currentCardDrawResultText }}
|
||||
</span>
|
||||
<span
|
||||
v-if="showRewardResultSwitcher"
|
||||
style="
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 0;
|
||||
transform: translateY(-50%);
|
||||
color: #fff;
|
||||
font-size: 1em;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
white-space: nowrap;
|
||||
"
|
||||
>
|
||||
{{ cardDrawResultIndex + 1 }}/{{ cardDrawResultList.length }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<itemCenter
|
||||
@ -1749,7 +1849,7 @@ import { preloadImages, preloadImagesIdle } from '@/utils/image/imagePreloader.j
|
||||
import { showError } from '@/utils/toast.js'
|
||||
import { viewUserInfo } from '@/utils/appBridge.js'
|
||||
import { connectToApp } from '@/utils/appConnector.js'
|
||||
import { handleRewardImageError } from '@/utils/image/imageHandler.js'
|
||||
import { handleAvatarImageError, handleRewardImageError } from '@/utils/image/imageHandler.js'
|
||||
import { formatRewardDisplay } from '@/utils/rewardFormatter.js'
|
||||
import { formatUTCCustom } from '@/utils/utcFormat.js'
|
||||
import { useDebounce } from '@/utils/useDebounce.js'
|
||||
@ -1846,38 +1946,7 @@ const cardTicketList = ref([])
|
||||
const cardRewardPrizePools = ref({})
|
||||
const cardRewardMarqueeList = ref([])
|
||||
const cardBagPools = ref({})
|
||||
const taskList = ref([
|
||||
{
|
||||
taskCode: 'GF_MIC_TIME_30',
|
||||
taskType: 1,
|
||||
taskName: 'Stay on mic',
|
||||
targetType: 'MIC_TIME',
|
||||
currentValue: 12,
|
||||
targetValue: 30,
|
||||
rewardValue: 1,
|
||||
taskStatus: 0,
|
||||
},
|
||||
{
|
||||
taskCode: 'GF_SEND_GIFT_5',
|
||||
taskType: 2,
|
||||
taskName: 'Send 5 gifts',
|
||||
targetType: 'SEND_GIFT',
|
||||
currentValue: 3,
|
||||
targetValue: 5,
|
||||
rewardValue: 2,
|
||||
taskStatus: 1,
|
||||
},
|
||||
{
|
||||
taskCode: 'GF_RECHARGE_10',
|
||||
taskType: 5,
|
||||
taskName: 'Daily total recharge amount: $10',
|
||||
targetType: 'RECHARGE_AMOUNT',
|
||||
currentValue: 10,
|
||||
targetValue: 10,
|
||||
rewardValue: 3,
|
||||
taskStatus: 2,
|
||||
},
|
||||
])
|
||||
const taskList = ref([])
|
||||
|
||||
let countdownTimer = null
|
||||
let lotteryAnimationTimer = null
|
||||
@ -2121,6 +2190,17 @@ const activeContainerImages = computed(() => {
|
||||
return activeSection.value?.containerImages || activeSection.value?.images?.container || []
|
||||
})
|
||||
|
||||
const barrageRenderList = computed(() => {
|
||||
const marqueeList = Array.isArray(cardRewardMarqueeList.value) ? cardRewardMarqueeList.value : []
|
||||
if (!marqueeList.length) {
|
||||
return []
|
||||
}
|
||||
|
||||
return marqueeList.length === 1
|
||||
? [...marqueeList, ...marqueeList, ...marqueeList, ...marqueeList]
|
||||
: [...marqueeList, ...marqueeList]
|
||||
})
|
||||
|
||||
const activeLotteryPoolMode = computed(() => {
|
||||
return lotteryPoolModes[activeLotteryPoolIndex.value] || lotteryPoolModes[0]
|
||||
})
|
||||
@ -2287,8 +2367,10 @@ const changeLotteryPoolMode = (step) => {
|
||||
activeLotteryIndex.value = 0
|
||||
}
|
||||
|
||||
// 任务目标展示:沿用 LuckyDollars Season5 的任务字段,当前先保留本地测试数据。
|
||||
// 任务目标展示:接口任务码带 CARD_ 前缀时,按后缀匹配到对应翻译。
|
||||
const showTarget = (task) => {
|
||||
const taskCode = task.taskCode || ''
|
||||
|
||||
if (task.targetType === 'MIC_TIME') {
|
||||
const timeType = task.targetValue < 60
|
||||
let currentValue = timeType ? task.currentValue : task.currentValue / 60
|
||||
@ -2305,7 +2387,7 @@ const showTarget = (task) => {
|
||||
}
|
||||
|
||||
if (task.targetType === 'SEND_GIFT') {
|
||||
if (task.taskCode === 'SP_SEND_GIFT_5') {
|
||||
if (taskCode.endsWith('SP_SEND_GIFT_5')) {
|
||||
return t('Send 5 Ramadan gifts ({currentValue}/{targetValue})', {
|
||||
currentValue: task.currentValue,
|
||||
targetValue: task.targetValue,
|
||||
@ -2314,21 +2396,21 @@ const showTarget = (task) => {
|
||||
}
|
||||
|
||||
if (task.targetType === 'SAVE_COINS') {
|
||||
if (task.taskCode === 'SP_SAVE_50000') {
|
||||
if (taskCode.endsWith('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') {
|
||||
if (taskCode.endsWith('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') {
|
||||
if (taskCode.endsWith('SP_SAVE_500000')) {
|
||||
return t('Win 500,000 coins in total across any games ({currentValue}/{targetValue})', {
|
||||
currentValue: task.currentValue,
|
||||
targetValue: task.targetValue,
|
||||
@ -2337,28 +2419,28 @@ const showTarget = (task) => {
|
||||
}
|
||||
|
||||
if (task.targetType === 'RECHARGE_AMOUNT') {
|
||||
if (task.taskCode === 'SP_RECHARGE_1') {
|
||||
if (taskCode.endsWith('SP_RECHARGE_1')) {
|
||||
return t('Daily total recharge amount: $1 ({currentValue}/{targetValue})', {
|
||||
currentValue: task.currentValue,
|
||||
targetValue: task.targetValue,
|
||||
})
|
||||
}
|
||||
|
||||
if (task.taskCode === 'SP_RECHARGE_10') {
|
||||
if (taskCode.endsWith('SP_RECHARGE_10')) {
|
||||
return t('Daily total recharge amount: $10 ({currentValue}/{targetValue})', {
|
||||
currentValue: task.currentValue,
|
||||
targetValue: task.targetValue,
|
||||
})
|
||||
}
|
||||
|
||||
if (task.taskCode === 'SP_RECHARGE_50') {
|
||||
if (taskCode.endsWith('SP_RECHARGE_50')) {
|
||||
return t('Daily total recharge amount: $50 ({currentValue}/{targetValue})', {
|
||||
currentValue: task.currentValue,
|
||||
targetValue: task.targetValue,
|
||||
})
|
||||
}
|
||||
|
||||
if (task.taskCode === 'SP_RECHARGE_100') {
|
||||
if (taskCode.endsWith('SP_RECHARGE_100')) {
|
||||
return t('Daily total recharge amount: $100 ({currentValue}/{targetValue})', {
|
||||
currentValue: task.currentValue,
|
||||
targetValue: task.targetValue,
|
||||
@ -2552,6 +2634,31 @@ const currentCardDrawResultImageUrl = computed(() => {
|
||||
)
|
||||
})
|
||||
|
||||
const currentCardDrawResult = computed(() => {
|
||||
return cardDrawResultList.value[cardDrawResultIndex.value] || null
|
||||
})
|
||||
|
||||
const currentCardDrawResultText = computed(() => {
|
||||
if (cardResultActionMode.value !== 'rewardDraw') {
|
||||
return ''
|
||||
}
|
||||
|
||||
const result = currentCardDrawResult.value
|
||||
if (!result) {
|
||||
return ''
|
||||
}
|
||||
|
||||
const days = result?.prize?.days ?? result.days
|
||||
if (days !== undefined && days !== null && days !== '') {
|
||||
return t('reward_days', { quantity: days })
|
||||
}
|
||||
|
||||
const prizeValue = result?.prize?.prizeValue ?? result.prizeValue
|
||||
return prizeValue !== undefined && prizeValue !== null && prizeValue !== ''
|
||||
? String(prizeValue)
|
||||
: ''
|
||||
})
|
||||
|
||||
const showRewardResultSwitcher = computed(() => {
|
||||
return cardResultActionMode.value === 'rewardDraw' && cardDrawResultList.value.length > 1
|
||||
})
|
||||
@ -3647,6 +3754,22 @@ onUnmounted(() => {
|
||||
}
|
||||
|
||||
/* 第四行:当前标签内容区 */
|
||||
.barrage-track {
|
||||
width: max-content;
|
||||
animation: gulben-barrage-scroll 80s linear infinite;
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
@keyframes gulben-barrage-scroll {
|
||||
0% {
|
||||
transform: translateX(100vw);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
}
|
||||
|
||||
.pool-arrow {
|
||||
width: 8vw;
|
||||
display: block;
|
||||
|
||||
@ -115,7 +115,7 @@ export const pageConfig = {
|
||||
enabled: true,
|
||||
apis: [],
|
||||
images: ['tagActiveBg', 'tagBg'],
|
||||
containerImages: ['lotteryBg', 'collectGameBg', 'taskModule'],
|
||||
containerImages: ['barrage', 'lotteryBg', 'collectGameBg', 'taskModule'],
|
||||
previewImages: [],
|
||||
remark:
|
||||
'一级标签内容区;container 大背景图使用 itemCenter 组件,宽度 100vw,从上往下排列;开发期 padding、margin、gap 先设为 0,后续再微调。',
|
||||
|
||||
@ -568,7 +568,7 @@
|
||||
"component": "itemCenter",
|
||||
"itemImage": "taskItemBg",
|
||||
"source": "任务接口和字段先参考 src/views/Activities/LuckyDollars/Season5/index.vue 的 taskList、ActTaskList、receiveTickets、showTarget",
|
||||
"data": "当前 Gulben 页面固定 activityId=1001,任务列表调用 ActTaskList('1001'),领取调用 receiveTickets({ activityId:'1001', taskCode })",
|
||||
"data": "当前 Gulben 页面固定 activityId=1001,taskList 默认空数组;任务列表调用 ActTaskList('1001'),领取调用 receiveTickets({ activityId:'1001', taskCode })",
|
||||
"wrapperStyle": "width:100vw; display:flex; flex-direction:column; gap:2vw; margin:0; padding:0 5vw; box-sizing:border-box",
|
||||
"itemStyle": "width:100%; margin:0; padding:0",
|
||||
"contentStyle": "display:flex; padding:8px; justify-content:space-between; align-items:center",
|
||||
@ -708,7 +708,7 @@
|
||||
},
|
||||
"layout": {
|
||||
"source": "展示结构复用 Personal Rank / Ranking 的排行榜部分",
|
||||
"difference": "不展示 Personal Rank 的活动礼物 giftBg 模块;头像统一 border-radius:4px;第四名以后和我的排名只展示排名、头像、名称、ID、金币数量,不展示 vip1 / userLevel1Bg / wealthLevel1Bg 三个等级图片",
|
||||
"difference": "不展示 Personal Rank 的活动礼物 giftBg 模块;前三名头像保持 border-radius:50%,第四名以后和我的排名头像使用 border-radius:4px;第四名以后和我的排名只展示排名、头像、名称、ID、金币数量,不展示 vip1 / userLevel1Bg / wealthLevel1Bg 三个等级图片",
|
||||
"myRanking": "切换到 Room Rank / Ranking 时同样固定贴底展示我的排名,样式跟列表一致,只保留名称、ID 和金币数量",
|
||||
"pagination": "使用 GET /room/contribution/total-rank?startDate=20260518&endDate=20260524&size=20;当前接口没有 current/page 参数,加载完成后 rankingHasMore=false,不再触发上拉继续请求"
|
||||
},
|
||||
@ -846,7 +846,7 @@
|
||||
"panelStyle": "min-height:86vw; padding:0; margin:0",
|
||||
"titleStyle": "",
|
||||
"childTabsStyle": "display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:2vw; margin-bottom:4vw",
|
||||
"containerImages": ["lotteryBg", "collectGameBg", "taskModule"],
|
||||
"containerImages": ["barrage", "lotteryBg", "collectGameBg", "taskModule"],
|
||||
"containerWrapperStyle": "display:flex; flex-direction:column; align-items:center; gap:0; margin:0; padding:0",
|
||||
"containerItemComponent": "itemCenter",
|
||||
"containerItemStyle": "width:100vw; margin:0; padding:0",
|
||||
@ -906,7 +906,7 @@
|
||||
"roomRankingLayout": {
|
||||
"section": "Room Rank / Ranking",
|
||||
"source": "复用 Personal Rank / Ranking 的排行榜结构和 weekly-star 上拉分页逻辑",
|
||||
"difference": "不展示活动礼物 giftBg 模块;前三名仍用 GulbenFestival 私有 TopUser 组件和 top1/top2/top3,但头像 border-radius 改为 4px;第四名以后和我的排名使用 RankingItem,只展示排名、头像、名称、ID、金币数量,不展示 vip1 / userLevel1Bg / wealthLevel1Bg 等级图",
|
||||
"difference": "不展示活动礼物 giftBg 模块;前三名仍用 GulbenFestival 私有 TopUser 组件和 top1/top2/top3,头像保持 border-radius:50%;第四名以后和我的排名使用 RankingItem,头像使用 border-radius:4px,只展示排名、头像、名称、ID、金币数量,不展示 vip1 / userLevel1Bg / wealthLevel1Bg 等级图",
|
||||
"data": "Room Rank / Ranking 固定请求 GET /room/contribution/total-rank,参数 startDate=20260518、endDate=20260524、size=20;rankList 渲染排行榜,current 渲染我的房间榜;展示账号优先取 userProfile.ownSpecialId.account,没有时取 userProfile.account;贡献值取 totalFormat;点击房间榜条目时使用 userProfile.inRoomId 调用 src/utils/appBridge.js 的 gotoRoom 方法"
|
||||
},
|
||||
"taskModuleLayout": {
|
||||
@ -917,7 +917,7 @@
|
||||
"contentStyle": "display:flex; padding:8px; justify-content:space-between; align-items:center",
|
||||
"content": "左侧展示 showTarget(task) 和 Rewards:*rewardValue;右侧根据 task.taskStatus 使用 itemCenter 展示 taskBtGo / taskBtReceive / taskBtReceived,并写入 t('task_go') / t('task_receive') / t('task_received');不展示 Season5 的任务类型图标和票券图标",
|
||||
"buttonStyle": "右侧按钮 itemCenter style=min-height:7.79vw;未完成/可领取文字 font-size:1em,已领取文字 font-size:0.9em,font-weight:600,white-space:nowrap",
|
||||
"data": "当前 Gulben 页面所有涉及 activityId 的接口调用都固定传 gulbenActivityId 的值,也就是字符串 '1001';任务列表调用 ActTaskList('1001'),领取调用 receiveTickets({ activityId:'1001', taskCode })"
|
||||
"data": "当前 Gulben 页面所有涉及 activityId 的接口调用都固定传 gulbenActivityId 的值,也就是字符串 '1001';taskList 默认空数组;任务列表调用 ActTaskList('1001'),领取调用 receiveTickets({ activityId:'1001', taskCode })"
|
||||
},
|
||||
"placeholderStyle": "min-height:58vw; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:0; margin:0; padding:0",
|
||||
"previewImageClass": "preview-image",
|
||||
@ -971,11 +971,11 @@
|
||||
- 对接抽奖区奖品池展示:`/activity/card/reward/prize/list` 返回的奖品按当前奖池 `poolType` 存储,渲染时按 `sortOrder` 升序排序并补充 `index`;奖品 itemCenter 背景继续用 `lotteryPrizeBg / lotteryPrizeActiveBg` 参与动画,内部垂直展示 `prizeImage`(宽度 60%)和奖励信息;奖励信息有 `days` 时展示 `${days} days`,没有 `days` 时展示 `prizeValue`,不展示 `prizeName`
|
||||
- 补充奖励池抽奖结果逻辑:`/activity/card/reward/draw` 接口成功后先计算中奖停点并播放 `lotteryPrizeActiveBg` 模拟转圈动画,动画结束后再展示 `resultBg` 结果弹窗;底部按钮文本为 `Confirm`,点击后关闭弹窗
|
||||
- 补充 `collectGameBg` 五层预览结构:票券数量、提示文案、当前奖池标题、当前奖池卡牌、操作按钮;支持 `gameR` / `gameSR` / `gameSSR` 本地切换
|
||||
- 补充 CollectCards 第三个任务模块 `taskModule`:任务接口和字段先参考 LuckyDollars Season5,列表项使用 `itemCenter` + `taskItemBg`,contentStyle 固定为 `display:flex; padding:8px; justify-content:space-between; align-items:center`,不引用 Season5 的任务类型图标和票券图标;右侧任务按钮也改为 `itemCenter` 背景图 + 翻译文字;Gulben 页面中任务列表和领取任务等涉及 `activityId` 的接口统一固定传 `gulbenActivityId` 的值,也就是字符串 `'1001'`
|
||||
- 补充 CollectCards 第三个任务模块 `taskModule`:任务接口和字段先参考 LuckyDollars Season5,`taskList` 默认空数组,列表项使用 `itemCenter` + `taskItemBg`,contentStyle 固定为 `display:flex; padding:8px; justify-content:space-between; align-items:center`,不引用 Season5 的任务类型图标和票券图标;右侧任务按钮也改为 `itemCenter` 背景图 + 翻译文字;Gulben 页面中任务列表和领取任务等涉及 `activityId` 的接口统一固定传 `gulbenActivityId` 的值,也就是字符串 `'1001'`
|
||||
- 补充 Personal Rank / Reward 预览结构:只展示 `RewardTop1`、`RewardTop2`、`RewardTop3` 三个 100vw 的 `itemCenter` 模块,从上往下排序;奖励数据调用 `apiGetActivityResource(rewardActivityType)`,当前 `rewardActivityType` 临时使用 `DAILY_RECHARGE_TASK2` 便于预览;接口返回 10 套奖励时只取前 3 套,每套最多 6 个奖励;如果某套只有 5 个奖励,则复制第 5 个奖励补到第 6 个位置用于预览;布局参考 DailyRecharge,左侧主奖励大图,右侧小奖励固定按 2/2/1 三行展示,第三行即使没有奖励也保留单展示位不可见占位并居中;奖励文案统一使用 `formatRewardDisplay(reward.type, reward)`
|
||||
- 补充 Personal Rank / Ranking 预览结构:活动礼物模块使用 `giftBg` 的 3 个预设空位直接展示 giftPhoto / giftCandy,不额外套参考页的 `gift` 单项背景;排行榜布局参考 LuckyDollars Season5,数据改用 `/activity/week-star/ranking` 和 `/activity/week-star/my-rank`;前三名使用 GulbenFestival 私有 `components/topUser.vue` + `top1/top2/top3`,布局为第二名/第一名/第三名左中右排列且第一名稍宽;贡献值参考 WeeklyStar 使用金币图标,前三名贡献值外观在私有组件内参考 GamesKing 的 `topUserDaily.vue` 圆角渐变底;排行榜排名和贡献值文字统一使用白色;第四名以后和我的排名使用 `RankingItem` 承载,名称下方新增 vip 等级图、userLevelBg、wealthLevelBg 等级行,vip 图片根据 `vipLevelName` 按 `VISCOUNT->vip1`、`EARL->vip2`、`MARQUIS->vip3`、`DUKEI->vip4`、`KING->vip5`、`EMPEROR->vip6` 映射展示,没有 `vipLevelName` 时不展示;userLevel 背景图根据 `charmLevel` 按 1-10/11-20/21-30/31-40/41-50 对应 `userLevel1Bg~userLevel5Bg`,wealthLevel 背景图根据 `wealthLevel` 按同样分段对应 `wealthLevel1Bg~wealthLevel5Bg`,内部居中展示对应等级文字,文字白色且 `font-size:1em`;切换到该标签时贴底展示我的排名,并通过底部 `rankingLoadmore` 上拉加载更多
|
||||
- `Personal Rank / Reward` 和 `Personal Rank / Ranking` 的活动奖励、活动礼物都来自 `/activity/king-queen/effective?templateId=2057676469390872578`;页面内必须通过共享缓存方法读取,避免进入 Reward 和 Ranking 时重复请求同一个 effective 接口。
|
||||
- 补充 Room Rank / Reward 和 Ranking:Reward 直接 100vw 展示 `ruleActivity`;Ranking 复用 Personal Rank 的排行榜展示和 weekly-star 上拉分页,但不展示活动礼物模块,头像统一 `border-radius:4px`,列表和我的排名只展示名称、ID、金币数量,不展示 `vip1`、`userLevel1Bg`、`wealthLevel1Bg` 三个等级图片
|
||||
- 补充 Room Rank / Reward 和 Ranking:Reward 直接 100vw 展示 `ruleActivity`;Ranking 复用 Personal Rank 的排行榜展示和 weekly-star 上拉分页,但不展示活动礼物模块;前三名头像保持 `border-radius:50%`,第四名以后列表和我的排名头像使用 `border-radius:4px`,列表和我的排名只展示名称、ID、金币数量,不展示 `vip1`、`userLevel1Bg`、`wealthLevel1Bg` 三个等级图片
|
||||
- 创建本地 OSS 目录 `public/oss/h5/Azizi/Activities/GulbenFestivalWebp/`
|
||||
- 添加路由 `/activities/gulben-festival`
|
||||
- 添加安全白名单和活动页权限片段
|
||||
@ -1023,13 +1023,14 @@
|
||||
- 页面初始化数据要仿照 `src/views/Activities/LuckyDollars/Season5/index.vue` 使用 `import { connectToApp } from '@/utils/appConnector.js'`。
|
||||
- `onMounted` 中不直接调用 `completePreloading()`,改为调用 `connectToAppHandler()`。
|
||||
- `connectToAppHandler()` 内通过 `connectToApp(() => { completePreloading() })` 在 APP 连接成功或浏览器环境初始化完成后再执行 `completePreloading()`;因此 `initData()`、首屏 blocking 图片预加载、后台图片预加载都在 APP header / 用户信息处理后触发。
|
||||
- Room Rank 的 UI 仍复用当前排行榜结构,不展示活动礼物模块;头像保持 `border-radius:4px`,列表和我的排名只展示名称、ID、金币数量,不展示 `vip1`、`userLevel1Bg`、`wealthLevel1Bg`。
|
||||
- Room Rank 的 UI 仍复用当前排行榜结构,不展示活动礼物模块;前三名头像保持 `border-radius:50%`,第四名以后列表和我的排名头像保持 `border-radius:4px`,列表和我的排名只展示名称、ID、金币数量,不展示 `vip1`、`userLevel1Bg`、`wealthLevel1Bg`。
|
||||
|
||||
## 本次同步:奖励池抽奖结果弹窗
|
||||
|
||||
- `/activity/card/reward/draw` 返回数据按 `body.rewards` 解析;兼容旧的 `body.results` 和直接数组返回,最终统一存入 `drawResult.results`。
|
||||
- 单抽和 5 连抽接口成功后先播放奖励池模拟转圈动画,动画结束后再展示 `resultBg` 结果弹窗。
|
||||
- 结果弹窗图片优先取 `rewards` 中第一个 `isWin === true` 的奖品;如果没有中奖标记,则退回使用第一条结果;奖励池抽奖结果图宽度为 `45vw`,抽卡/合成结果图继续使用 `28vw`。
|
||||
- 奖励池抽奖结果弹窗在奖品和底部按钮之间保留一行居中信息:有 `days` 时展示 `reward_days` 翻译文本,没有 `days` 时直接展示 `prizeValue`;5 连抽时 `1/5`、`2/5` 等页码在同一行内绝对定位贴右展示。
|
||||
- 结果弹窗底部按钮文本为 `Confirm`,点击后关闭弹窗。
|
||||
- 停点匹配优先级为 `prizeId -> prizeImage -> prizeType + prizeValue`,匹配当前奖池 `activeLotteryPrizes` 中对应奖品后,将 `lotteryPrizeActiveBg` 停在该奖品位置。
|
||||
- 匹配不到接口奖品时才使用本地 `prizeIndex` 兜底;没有任何可用停点时停在当前奖池第一个奖品,避免继续使用旧测试逻辑固定停第 4 个。
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user