feat(新活动): 古尔邦节

This commit is contained in:
hzj 2026-05-22 16:42:59 +08:00
parent b58317c28e
commit c3e7b1b3d7
7 changed files with 3305 additions and 0 deletions

View File

@ -110,3 +110,105 @@ export const claimDailyRechargeTask2 = async (data) => {
throw error
}
}
// 查询用户票券数量
export const apiGetCardTicketList = async (activityId) => {
try {
const response = await get(
`/activity/card/ticket/list?activityId=${encodeURIComponent(activityId)}`,
)
return response
} catch (error) {
console.error('Failed to get card ticket list:', error)
console.error('error:' + (error.response?.errorMsg || error.errorMsg || error.message || ''))
throw error
}
}
// 查询奖励池奖品列表
export const apiGetCardRewardPrizeList = async (activityId, poolType) => {
try {
const response = await get(
`/activity/card/reward/prize/list?activityId=${encodeURIComponent(activityId)}&poolType=${encodeURIComponent(poolType)}`,
)
return response
} catch (error) {
console.error('Failed to get card reward prize list:', error)
console.error('error:' + (error.response?.errorMsg || error.errorMsg || error.message || ''))
throw error
}
}
// 查询中奖飘窗列表
export const apiGetCardRewardMarquee = async (activityId) => {
try {
const response = await get(
`/activity/card/reward/marquee?activityId=${encodeURIComponent(activityId)}`,
)
return response
} catch (error) {
console.error('Failed to get card reward marquee:', error)
console.error('error:' + (error.response?.errorMsg || error.errorMsg || error.message || ''))
throw error
}
}
// 抽卡(消耗抽卡票或金币,抽 R 级卡片)
export const apiPostCardDraw = async (data) => {
try {
const response = await post('/activity/card/draw', data)
return response
} catch (error) {
console.error('Failed to draw card:', error)
console.error('error:' + (error.response?.errorMsg || error.errorMsg || error.message || ''))
throw error
}
}
// 合成卡片R×5→SRSR×3→SSR
export const apiPostCardCombine = async (data) => {
try {
const response = await post('/activity/card/combine', data)
return response
} catch (error) {
console.error('Failed to combine card:', error)
console.error('error:' + (error.response?.errorMsg || error.errorMsg || error.message || ''))
throw error
}
}
// 兑换奖励票(卡片 → STANDARD/PREMIUM/LUXURY 票)
export const apiPostCardRedeem = async (data) => {
try {
const response = await post('/activity/card/redeem', data)
return response
} catch (error) {
console.error('Failed to redeem card reward ticket:', error)
console.error('error:' + (error.response?.errorMsg || error.errorMsg || error.message || ''))
throw error
}
}
// 奖励池抽奖(消耗奖励票,抽取实际奖励)
export const apiPostCardRewardDraw = async (data) => {
try {
const response = await post('/activity/card/reward/draw', data)
return response
} catch (error) {
console.error('Failed to draw card reward:', error)
console.error('error:' + (error.response?.errorMsg || error.errorMsg || error.message || ''))
throw error
}
}
// 查询用户卡包
export const apiPostCardBagList = async (data) => {
try {
const response = await post('/activity/card/bag/list', data)
return response
} catch (error) {
console.error('Failed to get card bag list:', error)
console.error('error:' + (error.response?.errorMsg || error.errorMsg || error.message || ''))
throw error
}
}

View File

@ -19,6 +19,7 @@ export const PUBLIC_PATHS = Object.freeze([
'/login-reward',
'/activities/poker-ace',
'/daily-recharge',
'/activities/gulben-festival',
'/activities/lucky-dollars-season5',
'/activities/lucky-dollars-season4',
'/activities/lesser-bairam',

View File

@ -414,6 +414,12 @@ const router = createRouter({
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/poker-ace',
name: 'pokerAce',

View File

@ -63,6 +63,7 @@ const ACTIVITIES = [
'/activities/poker-ace', // 扑克王牌排行榜
'/daily-recharge', // 每日充值页面
'/activities/lucky-dollars-season5', // 幸运美金活动
'/activities/gulben-festival', // 古尔邦节活动
'/activities/lucky-dollars-season4', // 幸运美金活动
'/activities/lesser-bairam', // 开斋节打榜
'/activities/lucky-dollars-season3', // 斋月打榜

View File

@ -0,0 +1,333 @@
<template>
<div style="width: 100%">
<div style="position: relative">
<img
v-smart-img
:src="BorderImgUrl"
alt=""
width="100%"
style="display: block; position: relative; z-index: 2"
/>
<!-- 头像 -->
<div
style="
position: absolute;
top: 0;
left: 0;
right: 0;
z-index: 1;
display: flex;
justify-content: center;
align-items: center;
"
:style="{ height: avatarContainerHeight }"
>
<div :style="{ width: avatarWidth }">
<img
:src="avatarUrl || ''"
alt=""
width="100%"
class="top-avatar"
:class="{ 'top-avatar-square': avatarSquare }"
style="display: block; aspect-ratio: 1/1; object-fit: cover"
@error="handleAvatarImageError"
/>
</div>
</div>
<!-- 用户名和贡献值 -->
<div
style="
position: absolute;
bottom: 0;
left: 0;
right: 0;
z-index: 3;
display: flex;
flex-direction: column;
align-items: center;
gap: 2px;
"
:style="{ height: bottomSectionHeight }"
>
<div
style="display: flex; justify-content: center; align-items: center"
:style="{
width: nameValueWidth,
height: nameValueHeight,
}"
>
<div style="font-weight: 700" class="showText" :class="isTopOne ? 'top1Text' : 'text'">
{{ name }}
</div>
</div>
<!-- 贡献值参考 GamesKing topUserDaily 的金币样式 -->
<div
class="distribution-value-pill"
:class="distributionValueClass"
style="padding: 1px 2px; display: flex; justify-content: center; align-items: center"
:style="{
width: distributionValueWidth,
height: distributionValueHeight,
}"
>
<img
v-smart-img
:src="valueIconUrl"
alt=""
style="display: block; aspect-ratio: 1/1; flex: 0 0 auto"
:style="{ width: coinWidth }"
/>
<div style="font-weight: 590" class="showText" :class="isTopOne ? 'top1Text' : 'text'">
{{ distributionValue }}
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { handleAvatarImageError } from '@/utils/image/imageHandler.js'
import { computed } from 'vue'
const props = defineProps({
ranking: {
type: String,
default: '',
},
avatarUrl: {
type: String,
default: '',
},
BorderImgUrl: {
type: String,
required: true,
},
name: {
type: String,
default: '',
},
distributionValue: {
type: [String, Number],
default: '',
},
valueIconUrl: {
type: String,
required: true,
},
avatarSquare: {
type: Boolean,
default: false,
},
})
//
const isTopOne = computed(() => {
return props.ranking === '1'
})
const distributionValueClass = computed(() => {
switch (props.ranking) {
case '1':
return 'distribution-value-pill-top1'
case '2':
return 'distribution-value-pill-top2'
case '3':
return 'distribution-value-pill-top3'
default:
return ''
}
})
//
const avatarContainerHeight = computed(() => {
switch (props.ranking) {
case '1':
return '70%'
case '2':
return '60%'
case '3':
return '60%'
default:
return '60%'
}
})
//
const avatarWidth = computed(() => {
switch (props.ranking) {
case '1':
return '55%'
case '2':
return '73%'
case '3':
return '73%'
default:
return '77%'
}
})
//
const bottomSectionHeight = computed(() => {
switch (props.ranking) {
case '1':
return '38%'
case '2':
return '45%'
case '3':
return '45%'
default:
return '39%'
}
})
//
const nameValueWidth = computed(() => {
switch (props.ranking) {
case '1':
return '60%'
case '2':
return '60%'
case '3':
return '60%'
default:
return '60%'
}
})
//
const nameValueHeight = computed(() => {
switch (props.ranking) {
case '1':
return '17%'
case '2':
return '17%'
case '3':
return '17%'
default:
return '17%'
}
})
//
const distributionValueWidth = computed(() => {
switch (props.ranking) {
case '1':
return '60%'
case '2':
return '60%'
case '3':
return '60%'
default:
return '40%'
}
})
//
const distributionValueHeight = computed(() => {
switch (props.ranking) {
case '1':
return '15%'
case '2':
return '15%'
case '3':
return '15%'
default:
return '20%'
}
})
//
const coinWidth = computed(() => {
switch (props.ranking) {
case '1':
return '1em'
case '2':
return '0.9em'
case '3':
return '0.9em'
default:
return '0.9em'
}
})
</script>
<style lang="scss" scoped>
* {
color: black;
}
.showText {
color: #fff;
text-align: center;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.top1Text {
font-size: 1em;
}
.text {
font-size: 0.7em;
}
.top-avatar {
border-radius: 50%;
}
.top-avatar-square {
border-radius: 4px;
}
.distribution-value-pill {
border-radius: 40px;
border: 0.64px solid #ffdf36;
box-shadow: 0 0 2.558px 0 rgba(0, 0, 0, 0.4) inset;
}
.distribution-value-pill-top1 {
background: linear-gradient(270deg, #063a16 0%, #49d890 47.45%, #063a2c 100%);
}
.distribution-value-pill-top2 {
background: linear-gradient(270deg, #a3fdf9 0%, #1d7bbd 50%, #a3fdf9 100%);
}
.distribution-value-pill-top3 {
background: linear-gradient(270deg, #f5eae4 0%, #f9c29e 50%, #f5eae4 100%);
}
@media screen and (max-width: 360px) {
* {
font-size: 10px;
}
}
@media screen and (min-width: 360px) {
* {
font-size: 16px;
}
}
@media screen and (min-width: 768px) {
* {
font-size: 24px;
}
}
@media screen and (min-width: 1024px) {
* {
font-size: 32px;
}
}
</style>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,208 @@
export const pageConfig = {
name: 'Gulben Festival',
routePath: '/activities/gulben-festival',
routeName: 'gulben-festival',
assetPath: 'Activities/GulbenFestival/',
activity: {
activityId: '1001',
activityCode: '',
activityType: '',
personalRankActivityType: 'THIS_WEEK',
roomRankActivityType: '',
rewardActivityType: 'DAILY_RECHARGE_TASK2',
periodText: '',
},
preload: {
blocking: ['bg', 'ruleBtBg', 'timeBg', 'tagActiveBg', 'tagBg', 'lotteryBg', 'collectGameBg'],
background: [
'barrageBg',
'cardBackBg',
'draw5BtBg',
'draw1Bt',
'GameDrawBtBg',
'Gameticket',
'gameTitleR',
'gameTitleSR',
'gameTitleSSR',
'giftBg',
'leftBt',
'lotteryPrizeActiveBg',
'lotteryPrizeBg',
'moduleActiveBg',
'moduleBg',
'redeemRGift',
'redeemRGoat',
'redeemRLamp',
'redeemRLight',
'redeemRMoon',
'redeemR2001',
'redeemR2002',
'redeemR2003',
'redeemR2004',
'redeemR2005',
'redeemSR2011',
'redeemSR2012',
'redeemSR2013',
'redeemSRLamb',
'redeemSRScroll',
'redeemSRTurkey',
'redeemSSR2021',
'redeemSSR2022',
'redeemSSRGoat',
'redeemSSRLamb',
'ruleActivity',
'ruleInfoBg',
'taskBtGo',
'taskBtReceive',
'taskBtReceived',
'taskItemBg',
'ticketHandleBtBg',
'ticketR',
'ticketSR',
'ticketSSR',
'RankingItem',
'RewardTop1',
'RewardTop2',
'RewardTop3',
'top1',
'top2',
'top3',
'vip1',
'userLevel1Bg',
'wealthLevel1Bg',
],
},
modules: {
tabs: {
enabled: true,
defaultValue: 'CollectCards toWin Prizes',
items: ['CollectCards toWin Prizes', 'Personal Rank', 'Room Rank'],
},
sections: [
{
name: 'collectCards',
label: 'CollectCards toWin Prizes',
enabled: true,
apis: [],
images: ['tagActiveBg', 'tagBg'],
containerImages: ['lotteryBg', 'collectGameBg', 'taskModule'],
previewImages: [],
remark:
'一级标签内容区container 大背景图使用 itemCenter 组件,宽度 100vw从上往下排列开发期 padding、margin、gap 先设为 0后续再微调。',
children: {},
},
{
name: 'personalRank',
label: 'Personal Rank',
enabled: true,
apis: [],
images: ['tagActiveBg', 'tagBg'],
remark:
'一级标签内容区;图片为背景图,使用 itemCenter 组件居中换行展示英文标题文本,开发期间不加翻译',
children: {
tabs: {
enabled: true,
defaultValue: 'Reward',
items: ['Reward', 'Ranking'],
},
sections: [
{
name: 'Reward',
enabled: true,
apis: [],
images: ['moduleActiveBg', 'moduleBg'],
previewImages: ['RewardTop1', 'RewardTop2', 'RewardTop3'],
remark:
'二级奖励标签内容区;图片为背景图,使用 itemCenter 组件居中换行展示英文标题文本,开发期间不加翻译',
children: {},
},
{
name: 'Ranking',
enabled: true,
apis: [],
images: ['moduleActiveBg', 'moduleBg'],
previewImages: ['top1', 'top2', 'top3'],
remark:
'二级排行榜标签内容区;图片为背景图,使用 itemCenter 组件居中换行展示英文标题文本,开发期间不加翻译',
children: {},
},
],
},
},
{
name: 'roomRank',
label: 'Room Rank',
enabled: true,
apis: [],
images: ['tagActiveBg', 'tagBg'],
remark:
'一级标签内容区;图片为背景图,使用 itemCenter 组件居中换行展示英文标题文本,开发期间不加翻译',
children: {
tabs: {
enabled: true,
defaultValue: 'Reward',
items: ['Reward', 'Ranking'],
},
sections: [
{
name: 'Reward',
enabled: true,
apis: [],
images: ['moduleActiveBg', 'moduleBg'],
previewImages: ['ruleActivity'],
remark:
'Room Rank / Reward 内容区;直接 100vw 展示 ruleActivity',
children: {},
},
{
name: 'Ranking',
enabled: true,
apis: [],
images: ['moduleActiveBg', 'moduleBg'],
previewImages: ['top1', 'top2', 'top3'],
remark:
'二级排行榜标签内容区;图片为背景图,使用 itemCenter 组件居中换行展示英文标题文本,开发期间不加翻译',
children: {},
},
],
},
},
],
popups: [
{
name: 'rule',
triggerImage: 'ruleBtBg',
component: 'MaskLayer',
backgroundImage: 'ruleInfoBg',
contentComponent: 'itemCenter',
closeRule: 'click mask to close, click popup content stop propagation',
textStyle: {
color: '#FFF',
fontSize: '1em',
fontWeight: 600,
},
},
],
features: [
{
name: 'countdown',
enabled: '',
deadline: '',
images: ['timeBg'],
fields: {
endTime: '2026-06-01 05:00:00',
remainingText: '',
},
remark:
'倒计时方法参考 LuckyDollars Season5Days/Hours/Minutes/Seconds 四个 ref + calculateCountdown/startCountdown目标时间直接在 getTargetTime 中使用 new Date(2026, 5, 1, 5, 0, 0),不解析中文;时分秒的中间用英文冒号:',
},
],
},
images: {
localized: {},
},
}