406 lines
10 KiB
Vue
406 lines
10 KiB
Vue
<template>
|
|
<div style="width: 100%; position: relative">
|
|
<itemCenter
|
|
:imgUrl="imageUrl('rewardBg')"
|
|
:flip="true"
|
|
:contentStyle="`inset: 4vw 6vw 10vw;`"
|
|
:class="{
|
|
'grayscale-container':
|
|
rewards.dayIndex > currentDayIndex ||
|
|
(rewards.dayIndex < currentDayIndex && !rewards.isSigned),
|
|
}"
|
|
>
|
|
<!-- 奖品展示 -->
|
|
<div style="width: 100%; height: 100%" :style="layerStyle">
|
|
<!-- 奖品项 -->
|
|
<itemCenter
|
|
v-for="(goods, index) in dailyConfigs"
|
|
:imgUrl="imageUrl('rewardGoodsBg')"
|
|
:flip="true"
|
|
:contentStyle="`flex-direction: column;justify-content: space-between;align-items: center;`"
|
|
:style="getGridPosition(index)"
|
|
>
|
|
<div
|
|
style="
|
|
width: 100%;
|
|
min-width: 0;
|
|
aspect-ratio: 1/0.95;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
"
|
|
>
|
|
<img
|
|
v-smart-img
|
|
:src="goods.cover"
|
|
alt=""
|
|
style="width: 50%; display: block; object-fit: cover"
|
|
/>
|
|
</div>
|
|
|
|
<div
|
|
style="margin-top: -0.5vw; display: flex; justify-content: center; align-items: center"
|
|
>
|
|
<div style="font-size: 0.5em; font-weight: 600; color: #ff3b76">
|
|
{{ formatRewardDisplay(goods.type, goods) }}
|
|
</div>
|
|
</div>
|
|
</itemCenter>
|
|
</div>
|
|
|
|
<!-- 领取条件 -->
|
|
<div
|
|
style="position: absolute; bottom: -10vw; width: 60%; height: 10vw"
|
|
@click="postSignIn(rewards)"
|
|
>
|
|
<div
|
|
v-if="rewards.isSigned"
|
|
style="
|
|
margin-left: 1vw;
|
|
width: 100%;
|
|
height: 100%;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
color: #ff79a1;
|
|
font-size: 0.7em;
|
|
font-weight: 600;
|
|
"
|
|
>
|
|
{{ t('sign_in_received') }}
|
|
</div>
|
|
<div
|
|
v-else
|
|
style="
|
|
width: 100%;
|
|
height: 100%;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
"
|
|
>
|
|
<img
|
|
v-smart-img
|
|
v-if="rewards.isPaid"
|
|
src="/src/assets/icon/coin.png"
|
|
alt=""
|
|
style="width: 1.3em; min-width: 0; display: block; object-fit: cover"
|
|
/>
|
|
<div style="font-size: 0.8em; color: #ff79a1; font-weight: 600">
|
|
{{ rewards.isPaid ? rewards.paidCost : t('sign_in_free') }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</itemCenter>
|
|
|
|
<!-- 补签 -->
|
|
<div
|
|
v-if="rewards.dayIndex < currentDayIndex && !rewards.isSigned"
|
|
style="
|
|
position: absolute;
|
|
inset: 0;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
"
|
|
@click="postSignInSupplement(rewards.dayIndex)"
|
|
>
|
|
<itemCenter
|
|
style="width: 80%"
|
|
:imgUrl="imageUrl('makeUpBtBg')"
|
|
:contentStyle="`inset: 0;flex-direction: column;`"
|
|
>
|
|
<div style="color: #ff79a1; font-weight: 600">{{ t('sign_in_make_up') }}</div>
|
|
<div style="display: flex; justify-content: center; align-items: center">
|
|
<img
|
|
v-smart-img
|
|
src="/src/assets/icon/coin.png"
|
|
alt=""
|
|
style="width: 1.3em; min-width: 0; display: block; object-fit: cover"
|
|
/>
|
|
<div style="color: #ff79a1; font-weight: 600">*{{ rewards.paidCost + 500 }}</div>
|
|
</div>
|
|
</itemCenter>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
|
import { handleAvatarImageError } from '@/utils/imageHandler.js'
|
|
import { useRoute, useRouter } from 'vue-router'
|
|
import { useLangStore } from '@/stores/lang'
|
|
import { useI18n } from 'vue-i18n'
|
|
import { getPngUrl } from '@/config/imagePaths.js'
|
|
import { useCoupleStore } from '@/stores/couple'
|
|
import { showError, showSuccess } from '@/utils/toast.js'
|
|
import { storeToRefs } from 'pinia'
|
|
import { formatRewardDisplay } from '@/utils/rewardFormatter.js'
|
|
|
|
import {
|
|
apiGetMyLotteryTicketCount, // 获取我的剩余抽奖券数量
|
|
apiGetUserFragmentBackpack, // 获取用户碎片背包
|
|
apiGetMySignInStatus, // 获取我的签到状态
|
|
apiPostMySignIn, // 执行签到
|
|
apiPostMySignInSupplement, // 补签
|
|
} from '@/api/couple.js'
|
|
|
|
import itemCenter from '@/components/itemCenter.vue'
|
|
|
|
const { t } = useI18n()
|
|
const router = useRouter()
|
|
const route = useRoute()
|
|
const coupleStore = useCoupleStore()
|
|
const {
|
|
crystal, //水晶数量
|
|
debris, //碎片数量
|
|
|
|
TipsShow, // 提示弹窗
|
|
needCheckInTipsShow, // 需要补签提示
|
|
signInSuccessShow, // 签到成功提示
|
|
|
|
signInInfo, // 签到奖池列表
|
|
} = storeToRefs(coupleStore)
|
|
|
|
const langStore = useLangStore()
|
|
// 当前语言类型
|
|
const currentLangType = computed(() => {
|
|
return langStore.selectedLang?.type || 'en'
|
|
})
|
|
|
|
const isLoading = ref(true) // 预加载状态
|
|
|
|
// 获取OSS图片URL的函数
|
|
const imageUrl = (filename) => getPngUrl('Ranking/Couple/', filename)
|
|
|
|
// 根据语言获取图片名
|
|
const getImgName = (filename) => {
|
|
return currentLangType.value === 'ar' ? `${filename}_ar` : filename
|
|
}
|
|
|
|
// 接收数据
|
|
const props = defineProps({
|
|
// 奖励配置
|
|
rewards: {
|
|
type: Object,
|
|
default: () => ({}),
|
|
},
|
|
|
|
// 当前签到天数
|
|
currentDayIndex: {
|
|
type: Number,
|
|
default: 0,
|
|
},
|
|
})
|
|
|
|
// 补充水晶后的每日奖励配置
|
|
const dailyConfigs = computed(() => {
|
|
let configs = props.rewards?.addActivityPropsGroup?.activityRewardProps
|
|
if (props.rewards?.lotteryTicketCount > 0) {
|
|
return [
|
|
...configs,
|
|
{
|
|
type: 'TICKET',
|
|
cover: imageUrl('crystal'),
|
|
content: props.rewards.lotteryTicketCount,
|
|
},
|
|
]
|
|
} else {
|
|
return configs
|
|
}
|
|
})
|
|
|
|
// 整体布局
|
|
const layerStyle = computed(() => {
|
|
let length = dailyConfigs.value.length
|
|
|
|
switch (length) {
|
|
case 1:
|
|
return `display:flex;justify-content:center;align-items:center;width: 18vw;`
|
|
case 2:
|
|
return `display: grid;grid-template-columns: repeat(2, 1fr);grid-template-rows: repeat(2, 1fr);`
|
|
case 3:
|
|
return `display: grid;grid-template-columns: repeat(2, 1fr);grid-template-rows: repeat(2, 1fr);`
|
|
case 4:
|
|
return `display: grid;grid-template-columns: repeat(2, 1fr);grid-template-rows: repeat(2, 1fr);`
|
|
default:
|
|
return `display: grid;grid-template-columns: repeat(2, 1fr);grid-template-rows: repeat(2, 1fr);`
|
|
}
|
|
})
|
|
|
|
// 每日奖品布局
|
|
const getGridPosition = (index) => {
|
|
let length = dailyConfigs.value.length
|
|
|
|
let gridPosition = []
|
|
switch (length) {
|
|
case 1:
|
|
gridPosition = []
|
|
break
|
|
case 2:
|
|
gridPosition = [
|
|
{ gridArea: '1/1', position: 'relative', top: '2vw' }, //1左
|
|
{ gridArea: '2/2' }, //2右
|
|
]
|
|
break
|
|
case 3:
|
|
gridPosition = [
|
|
{ gridArea: '1/1', position: 'relative', left: '2vw' }, //1左
|
|
{ gridArea: '2/1', position: 'relative' }, //2左
|
|
{ gridArea: '2/2', position: 'relative', left: '2vw', bottom: '2vw' }, //2右
|
|
]
|
|
break
|
|
case 4:
|
|
gridPosition = [
|
|
{ gridArea: '1/1' }, //1左
|
|
{ gridArea: '1/2' }, //1右
|
|
{ gridArea: '2/1' }, //2左
|
|
{ gridArea: '2/2' }, //2右
|
|
]
|
|
break
|
|
|
|
default:
|
|
gridPosition = []
|
|
break
|
|
}
|
|
|
|
return gridPosition[index]
|
|
}
|
|
|
|
// 获取签到状态
|
|
const getSignInStatus = async () => {
|
|
try {
|
|
const response = await apiGetMySignInStatus()
|
|
if (response.status) {
|
|
signInInfo.value = response.body || {}
|
|
}
|
|
} catch (error) {
|
|
showError(error.response.errorMsg)
|
|
}
|
|
}
|
|
|
|
// 获取抽奖券
|
|
const getMyLotteryTicketCount = async () => {
|
|
try {
|
|
const response = await apiGetMyLotteryTicketCount('2004471533988167125')
|
|
if (response.status) {
|
|
crystal.value = response.body || 0
|
|
}
|
|
} catch (error) {
|
|
showError(error.response.errorMsg)
|
|
}
|
|
}
|
|
|
|
// 获取用户碎片背包
|
|
const getUserFragmentBackpack = async () => {
|
|
try {
|
|
let response = await apiGetUserFragmentBackpack({
|
|
userId: getUserId(),
|
|
fragmentsIds: ['2011710323414081538'],
|
|
})
|
|
if (response.status) {
|
|
debris.value = response.body?.[0]?.quantity || 0
|
|
}
|
|
} catch (error) {
|
|
showError(error.response.errorMsg)
|
|
}
|
|
}
|
|
|
|
// 更新数据
|
|
const updateNumbers = () => {
|
|
getSignInStatus() // 获取签到状态
|
|
getMyLotteryTicketCount() // 获取抽奖券数量
|
|
getUserFragmentBackpack() // 获取碎片数量
|
|
}
|
|
|
|
// 执行签到
|
|
const postSignIn = async (rewards) => {
|
|
if (rewards.isSigned) return // 已签到,直接返回
|
|
try {
|
|
const response = await apiPostMySignIn({ dayIndex: rewards.dayIndex })
|
|
if (response.status) {
|
|
signInSuccessShow.value = true // 签到成功提示
|
|
updateNumbers() // 更新数据
|
|
}
|
|
} catch (error) {
|
|
if (error.response.errorCode == 500) {
|
|
TipsShow.value = true // 余额不足提示
|
|
} else if (error.response.errorCode == 3287) {
|
|
needCheckInTipsShow.value = true // 需要补签提示
|
|
} else {
|
|
showError(error.response.errorMsg)
|
|
}
|
|
}
|
|
}
|
|
|
|
// 补签
|
|
const postSignInSupplement = async (dayIndex) => {
|
|
try {
|
|
const response = await apiPostMySignInSupplement({ dayIndex })
|
|
if (response.status) {
|
|
signInSuccessShow.value = true // 签到成功提示
|
|
updateNumbers() // 更新数据
|
|
}
|
|
} catch (error) {
|
|
if (error.response.errorCode == 500) {
|
|
TipsShow.value = true // 余额不足提示
|
|
} else if (error.response.errorCode == 3283) {
|
|
needCheckInTipsShow.value = true // 需要补签提示
|
|
} else {
|
|
showError(error.response.errorMsg)
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
* {
|
|
color: black;
|
|
}
|
|
|
|
.grayscale-container {
|
|
filter: grayscale(100%) brightness(90%);
|
|
pointer-events: none;
|
|
}
|
|
|
|
.showText {
|
|
color: #fff;
|
|
text-align: center;
|
|
overflow: hidden;
|
|
white-space: nowrap;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
.top1Text {
|
|
font-size: 0.75em;
|
|
}
|
|
|
|
.text {
|
|
font-size: 0.6em;
|
|
}
|
|
|
|
@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>
|