feat(新限时活动页面): 登录奖励领取页
This commit is contained in:
parent
4f23412f76
commit
dc485a8c7b
37
src/api/task.js
Normal file
37
src/api/task.js
Normal file
@ -0,0 +1,37 @@
|
||||
import { get, post } from '../utils/http.js'
|
||||
|
||||
// 每日签到奖励列表.
|
||||
export const apiGetLoginRewards = async (activityType) => {
|
||||
try {
|
||||
const response = await get(`/task/check/in/list/award?activityType=${activityType}`)
|
||||
return response
|
||||
} catch (error) {
|
||||
console.error('Failed to get login rewards:', error)
|
||||
console.error('error:' + error.response.errorMsg)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
// 今天是否已签到.
|
||||
export const apiGetTodayLoginStatus = async (dailyKey) => {
|
||||
try {
|
||||
const response = await get(`/task/check/in/today?dailyKey=${dailyKey}`)
|
||||
return response
|
||||
} catch (error) {
|
||||
console.error('Failed to get today login info:', error)
|
||||
console.error('error:' + error.response.errorMsg)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
// 打卡-领取奖励.
|
||||
export const postReceiveLoginReward = async (data) => {
|
||||
try {
|
||||
const response = await post(`/task/check/in/receive`, data)
|
||||
return response
|
||||
} catch (error) {
|
||||
console.error('Failed to post receive login reward:', error)
|
||||
console.error('error:' + error.response.errorMsg)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
@ -371,6 +371,12 @@ const router = createRouter({
|
||||
},
|
||||
|
||||
// 限时活动
|
||||
{
|
||||
path: '/login-reward',
|
||||
name: 'login-reward',
|
||||
component: () => import('../views/Activities/LoginReward/index.vue'),
|
||||
meta: { requiresAuth: true },
|
||||
}, //2026年xxxxxx结束
|
||||
{
|
||||
path: '/lucky-dollars-season3',
|
||||
name: 'lucky-dollars-season3',
|
||||
|
||||
@ -58,9 +58,10 @@ const ACTIVITIES = [
|
||||
INVITATION_PAGES.INVITE_USER, //邀请新用户(邀请码)
|
||||
'/recharge-reward', //充值奖励
|
||||
|
||||
'/lucky-dollars-season3', //水果游戏打榜
|
||||
'/jack-pot', //水果游戏打榜
|
||||
'/new-year', //新年抽奖
|
||||
'/login-reward', // 登录奖励
|
||||
'/lucky-dollars-season3', // 水果游戏打榜
|
||||
'/jack-pot', // 水果游戏打榜
|
||||
'/new-year', // 新年抽奖
|
||||
]
|
||||
|
||||
// 🎯 核心改变:基于身份的权限配置
|
||||
|
||||
@ -409,6 +409,7 @@ class RouteGuard {
|
||||
'/invitation-to-register', //邀请新用户注册页面
|
||||
'/recharge-reward', //充值奖励
|
||||
|
||||
'/login-reward', // 登录奖励
|
||||
'/lucky-dollars-season3', //水果游戏打榜
|
||||
'/jack-pot', //水果游戏打榜
|
||||
'/new-year', //新年抽奖
|
||||
|
||||
359
src/views/Activities/LoginReward/index.vue
Normal file
359
src/views/Activities/LoginReward/index.vue
Normal file
@ -0,0 +1,359 @@
|
||||
<template>
|
||||
<div class="fullPage">
|
||||
<!-- 预加载状态 -->
|
||||
<div v-if="isLoading" class="loading-container">
|
||||
<div class="loading-spinner"></div>
|
||||
<p>{{ t('loading') }}...</p>
|
||||
</div>
|
||||
|
||||
<!-- 主要内容 -->
|
||||
<div
|
||||
v-show="!isLoading"
|
||||
style="width: 100vw; min-height: 100vh; overflow: hidden; position: relative"
|
||||
>
|
||||
<!-- 页面背景 -->
|
||||
<BackgroundLayer :backgroundImages="[imageUrl('bg1'), imageUrl('bg2'), imageUrl('bg3')]" />
|
||||
<!-- 重复的背景图层 -->
|
||||
<!-- <div class="background-overlay" :style="{ '--bg2-url': `url(${imageUrl('bg3')})` }"></div> -->
|
||||
|
||||
<!-- 页面内容 -->
|
||||
<div style="position: relative; z-index: 2; margin: 85vw 0 10vw">
|
||||
<!-- 登录奖励池 -->
|
||||
<itemCenter
|
||||
style=""
|
||||
:imgUrl="imageUrl('rewards')"
|
||||
:contentStyle="`
|
||||
padding: 21.5vw 6.5vw 12vw;
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
grid-template-rows: repeat(3, 1fr);
|
||||
gap: 10.5vw 2.5vw;
|
||||
|
||||
direction: ltr;
|
||||
`"
|
||||
>
|
||||
<div
|
||||
v-for="(reward, index) in rewardInfo?.propsGroup?.activityRewardProps"
|
||||
:key="index"
|
||||
style="align-self: stretch; position: relative"
|
||||
:style="[getGridPosition(index)]"
|
||||
@click="receiveTaskReward()"
|
||||
>
|
||||
<div
|
||||
style="position: absolute; inset: 0; z-index: 2"
|
||||
v-if="reward.sort > currentDayIndex || todayReceived"
|
||||
@click.stop
|
||||
>
|
||||
<img
|
||||
v-smart-img
|
||||
:src="showImgUrl(currentDayIndex, reward)"
|
||||
alt=""
|
||||
style="width: 100%; height: 100%; display: block; object-fit: cover"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</itemCenter>
|
||||
|
||||
<!-- 规则 -->
|
||||
<img
|
||||
v-smart-img
|
||||
:src="imageUrl(getImgName('ruleInfo'))"
|
||||
alt=""
|
||||
style="width: 100%; display: block; object-fit: cover"
|
||||
/>
|
||||
</div>
|
||||
<!-- 弹窗遮罩层 -->
|
||||
<maskLayer :maskLayerShow="maskLayerShow" @click="closedPopup">
|
||||
<!-- 居中弹窗 -->
|
||||
<div
|
||||
style="
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
"
|
||||
@click="closedPopup"
|
||||
></div>
|
||||
</maskLayer>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
||||
import { connectToApp } from '@/utils/appConnector.js'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { setDocumentDirection } from '@/locales/i18n'
|
||||
import { viewUserInfo } from '@/utils/appBridge.js'
|
||||
import { useLangStore } from '@/stores/lang'
|
||||
import { getPngUrl } from '@/config/imagePaths.js'
|
||||
import { preloadImages } from '@/utils/imagePreloader.js'
|
||||
import { showError, showSuccess } from '@/utils/toast.js'
|
||||
import { handleAvatarImageError, handleRewardImageError } from '@/utils/imageHandler.js'
|
||||
import { formatRewardDisplay } from '@/utils/rewardFormatter.js'
|
||||
|
||||
import { apiGetLoginRewards, apiGetTodayLoginStatus, postReceiveLoginReward } from '@/api/task.js'
|
||||
|
||||
import BackgroundLayer from '@/components/BackgroundLayer.vue'
|
||||
import itemCenter from '@/components/itemCenter.vue'
|
||||
import maskLayer from '@/components/MaskLayer.vue'
|
||||
|
||||
// 预加载状态
|
||||
const isLoading = ref(true)
|
||||
|
||||
const { t, locale } = useI18n()
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
|
||||
const langStore = useLangStore()
|
||||
// 当前语言类型
|
||||
const currentLangType = computed(() => {
|
||||
return langStore.selectedLang?.type || 'en'
|
||||
})
|
||||
|
||||
// 获取OSS图片URL的函数
|
||||
const imageUrl = (filename) => getPngUrl('Activities/LoginReward/', filename)
|
||||
|
||||
// 根据语言获取图片名
|
||||
const getImgName = (filename) => {
|
||||
return currentLangType.value === 'ar' ? `${filename}_ar` : filename
|
||||
}
|
||||
|
||||
const rewardInfo = ref({}) // 奖池列表
|
||||
const currentDayIndex = ref(0) // 当前签到天数
|
||||
const todayReceived = ref(false) // 今日是否已领取
|
||||
|
||||
// 展示不同图片
|
||||
const showImgUrl = (currentDayIndex, reward) => {
|
||||
// 未领取状态
|
||||
if (reward.sort > currentDayIndex) {
|
||||
if (reward.sort < 7) {
|
||||
console.log(`imageUrl('itemLock')`, imageUrl('itemLock'))
|
||||
|
||||
return imageUrl('itemLock')
|
||||
} else {
|
||||
return imageUrl('itemBigLock')
|
||||
}
|
||||
}
|
||||
|
||||
// 已领取状态
|
||||
else if (todayReceived.value) {
|
||||
if (reward.sort < 7) {
|
||||
return imageUrl(getImgName('itemReceived'))
|
||||
} else {
|
||||
return imageUrl(getImgName('itemBigReceived'))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 弹窗展示
|
||||
const helpShow = ref(false) // 帮助
|
||||
const maskLayerShow = computed(() => {
|
||||
return helpShow.value
|
||||
})
|
||||
|
||||
// 打开弹窗
|
||||
const openPopup = (type) => {
|
||||
closedPopup(false) //先关闭其他弹窗,不清除抽奖结果
|
||||
switch (type) {
|
||||
case 'help':
|
||||
helpShow.value = true
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭弹窗
|
||||
const closedPopup = (clear = true) => {
|
||||
helpShow.value = false
|
||||
// 清空数据
|
||||
if (clear) {
|
||||
}
|
||||
}
|
||||
|
||||
//奖池布局
|
||||
const getGridPosition = (index) => {
|
||||
//顺时针位置
|
||||
const positions = [
|
||||
{ gridArea: '1/1' }, //上左
|
||||
{ gridArea: '1/2' }, //上中
|
||||
{ gridArea: '1/3' }, //上右
|
||||
{ gridArea: '2/1' }, //中左
|
||||
{ gridArea: '2/2' }, //中中
|
||||
{ gridArea: '2/3' }, //中右
|
||||
{ gridRow: '3', gridColumn: '1 / -1' }, //下整行
|
||||
]
|
||||
return positions[index]
|
||||
}
|
||||
|
||||
// 每日签到奖励列表
|
||||
const getLoginRewards = async () => {
|
||||
const resLoginRewards = await apiGetLoginRewards('DAILY_REGISTER_AZIZI')
|
||||
if (resLoginRewards.status && resLoginRewards.body) {
|
||||
rewardInfo.value = resLoginRewards.body?.rewards?.[0] || {}
|
||||
currentDayIndex.value = resLoginRewards.body?.days || 0
|
||||
|
||||
getTodayLoginStatus() // 今日是否已签到
|
||||
}
|
||||
}
|
||||
|
||||
// 今天是否已签到
|
||||
const getTodayLoginStatus = async () => {
|
||||
const resTodayLoginStatus = await apiGetTodayLoginStatus(currentDayIndex.value)
|
||||
if (resTodayLoginStatus.status && resTodayLoginStatus.body) {
|
||||
todayReceived.value = resTodayLoginStatus.body
|
||||
}
|
||||
}
|
||||
|
||||
// 领取任务奖励
|
||||
const receiveTaskReward = async () => {
|
||||
let data = {
|
||||
id: rewardInfo.value.rule.id,
|
||||
resourceGroupId: rewardInfo.value.rule.resourceGroupId,
|
||||
dailyKey: currentDayIndex.value,
|
||||
}
|
||||
try {
|
||||
const resReceive = await postReceiveLoginReward(data)
|
||||
if (resReceive.status && resReceive.body) {
|
||||
getLoginRewards() // 每日签到奖励列表
|
||||
}
|
||||
} catch (error) {
|
||||
showError(error.errorMsg)
|
||||
}
|
||||
}
|
||||
|
||||
// 刷新页面数据
|
||||
const initData = async () => {
|
||||
await Promise.all([
|
||||
getLoginRewards(), // 每日签到奖励列表
|
||||
])
|
||||
}
|
||||
|
||||
// 预加载关键图片
|
||||
const preloadCriticalImages = async () => {
|
||||
const criticalImages = []
|
||||
|
||||
await preloadImages(criticalImages)
|
||||
}
|
||||
|
||||
// 完成预加载
|
||||
const completePreloading = async () => {
|
||||
try {
|
||||
// 执行所有初始化操作
|
||||
await Promise.all([initData(), preloadCriticalImages()])
|
||||
} catch (error) {
|
||||
console.error('预加载过程中发生错误:', error)
|
||||
} finally {
|
||||
// 无论成功或失败都结束加载状态
|
||||
isLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 使用工具函数连接APP
|
||||
const connectToAppHandler = async () => {
|
||||
await connectToApp(() => {
|
||||
// 连接成功回调
|
||||
completePreloading() // 完成预加载
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
connectToAppHandler()
|
||||
})
|
||||
|
||||
onUnmounted(() => {})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
* {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.fullPage {
|
||||
position: relative;
|
||||
background: #142c24;
|
||||
}
|
||||
|
||||
.bg {
|
||||
width: 100vw;
|
||||
min-height: 100vh;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.background-overlay {
|
||||
position: absolute;
|
||||
inset: 236vw 0 0;
|
||||
background-image: var(--bg2-url);
|
||||
background-repeat: repeat-y;
|
||||
background-position: top center;
|
||||
background-size: 100% auto;
|
||||
z-index: 0; /* 确保在.bg之下 */
|
||||
}
|
||||
|
||||
/* 添加加载动画样式 */
|
||||
.loading-container {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.loading-spinner {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border: 3px solid #f3f3f3;
|
||||
border-top: 3px solid #f59e0b;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.scrollY::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
[dir='rtl'] .flipImg {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
@media screen and (max-width: 360px) {
|
||||
* {
|
||||
font-size: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 360px) {
|
||||
* {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
* {
|
||||
font-size: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1024px) {
|
||||
* {
|
||||
font-size: 32px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Loading…
x
Reference in New Issue
Block a user