aslan-h5/src/views/Invitation/InvitationToRegister.vue

657 lines
19 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="fullPage">
<div style="position: absolute; top: 0; left: 0; width: 100%">
<GeneralHeader title="Invitation to register" :showHelp="true" @help="helpInfoShow = true" />
</div>
<!-- 确认邀请码 -->
<div style="padding: 87% 0 5%">
<img
v-if="showBindingBt"
:src="images.enterCode"
alt=""
width="40%"
@click="enterCodeShow = true"
style="display: block"
/>
<img
v-else-if="myInviter.inviterInfo?.userId"
:src="images.privateChat"
alt=""
width="40%"
@click="gotoPrivateChat(myInviter.inviterInfo?.userId)"
style="display: block"
/>
</div>
<!-- 主体内容 -->
<div
style="padding: 0 3%; display: flex; flex-direction: column; gap: 12px; padding-bottom: 30px"
>
<!-- 倒计时 -->
<!-- <div style="position: relative">
<img :src="images.countdownBg" alt="" width="100%" style="display: block" />
<div
style="
position: absolute;
inset: 0;
display: flex;
justify-content: center;
align-items: center;
font-size: 1.2em;
font-weight: 700;
letter-spacing: 2px;
"
>
29D 2323:23
</div>
</div> -->
<!-- 我的邀请码 -->
<div
style="
width: 100%;
border-radius: 8px;
background: rgba(194, 174, 232, 0.2);
backdrop-filter: blur(32px);
padding: 12px;
display: flex;
flex-direction: column;
gap: 4px;
"
@click.stop
>
<div style="font-weight: 590">My invitation code:</div>
<div
style="
border-radius: 8px;
background: rgba(255, 255, 255, 0.2);
padding: 12px;
display: flex;
justify-content: center;
align-items: center;
gap: 4px;
"
>
<div style="font-weight: 590">{{ myInviteInfo.inviteCode || '' }}</div>
<img
src="../../assets/icon/copy.png"
alt=""
width="24px"
@click="copyCode(myInviteInfo.inviteCode || '')"
/>
</div>
<div style="font-weight: 510; font-size: 0.7em">
*Copy your invitation code and send it to your new friends.
</div>
</div>
<!-- 模块切换按钮 -->
<div>
<div
v-if="showModule == 'list'"
style="display: flex; justify-content: space-around; align-items: center"
>
<img :src="images.listBtActive" alt="" width="40%" style="display: block" />
<img
:src="images.rewardBt"
alt=""
width="40%"
style="display: block"
@click="showModule = 'reward'"
/>
</div>
<div v-else style="display: flex; justify-content: space-around; align-items: center">
<img
:src="images.listBt"
alt=""
width="40%"
style="display: block"
@click="showModule = 'list'"
/>
<img :src="images.rewardBtActive" alt="" width="40%" style="display: block" />
</div>
</div>
<!-- 邀请列表模块 -->
<div v-if="showModule == 'list'" style="display: flex; flex-direction: column; gap: 12px">
<!-- 收入展示 -->
<div style="display: flex; justify-content: space-around; align-items: center">
<div style="position: relative; width: 47%">
<img :src="images.totalIncome" alt="" width="100%" style="display: block" />
<div
style="
position: absolute;
top: 40%;
width: 100%;
height: 60%;
display: flex;
justify-content: center;
align-items: center;
"
>
<img src="/src/assets/icon/coin.png" alt="" width="10%" style="display: block" />
<div style="font-weight: 590">{{ myInviteIncome.totalIncome || 0 }}</div>
</div>
</div>
<div style="position: relative; width: 47%">
<img :src="images.todayIncome" alt="" width="100%" style="display: block" />
<div
style="
position: absolute;
top: 40%;
width: 100%;
height: 60%;
display: flex;
justify-content: center;
align-items: center;
"
>
<img src="/src/assets/icon/coin.png" alt="" width="10%" style="display: block" />
<div style="font-weight: 590">{{ myInviteIncome.todayIncome || 0 }}</div>
</div>
</div>
</div>
<!-- 邀请人数 -->
<div
style="
border-radius: 8px;
background: rgba(194, 174, 232, 0.2);
backdrop-filter: blur(32px);
padding: 12px;
display: flex;
align-items: center;
gap: 4px;
"
>
<div
style="
width: 3px;
height: 12px;
flex-shrink: 0;
background: radial-gradient(323.25% 50.32% at 50% 50%, #d58ef4 0%, #7a5aff 100%);
"
></div>
<div style="font-weight: 590">
Number of valid users invited: {{ myInviteIncome.validInviteCount || 0 }}
</div>
</div>
<!-- 列表 -->
<div
style="
border-radius: 8px;
background: rgba(194, 174, 232, 0.2);
backdrop-filter: blur(32px);
padding: 8px;
display: flex;
flex-direction: column;
gap: 4px;
"
>
<!-- 头部 -->
<div style="width: 100%; display: flex; align-items: center">
<div style="flex: 1; font-weight: 590; font-size: 0.85em">Users</div>
<div
style="
flex: 1;
font-weight: 590;
display: flex;
justify-content: space-between;
align-items: center;
"
>
<div
style="
width: 1px;
height: 16px;
background: linear-gradient(
rgba(217, 217, 217, 0) 0%,
#d9d9d9 50%,
rgba(217, 217, 217, 0) 100%
);
"
></div>
<div style="font-weight: 590; font-size: 0.82em">Remaining time</div>
<div
style="
width: 1px;
height: 16px;
background: linear-gradient(
rgba(217, 217, 217, 0) 0%,
#d9d9d9 50%,
rgba(217, 217, 217, 0) 100%
);
"
></div>
</div>
<div style="flex: 1; font-weight: 590; text-align: end; font-size: 0.82em">
Prowide income
</div>
</div>
<!-- 列表项 -->
<div
v-for="user in myInviteUsers"
style="width: 100%; display: flex; align-items: center"
>
<div style="flex: 1; font-weight: 590; font-size: 0.7em">
ID:{{ user.invitedUserAccount || '-' }}
</div>
<div
style="
flex: 1;
font-weight: 590;
display: flex;
justify-content: space-between;
align-items: center;
"
>
<div
style="
width: 1px;
height: 16px;
background: linear-gradient(
rgba(217, 217, 217, 0) 0%,
#d9d9d9 50%,
rgba(217, 217, 217, 0) 100%
);
"
></div>
<div style="font-weight: 590; font-size: 0.7em">{{ user.remainingDays || 0 }}Day</div>
<div
style="
width: 1px;
height: 16px;
background: linear-gradient(
rgba(217, 217, 217, 0) 0%,
#d9d9d9 50%,
rgba(217, 217, 217, 0) 100%
);
"
></div>
</div>
<div
style="
flex: 1;
display: flex;
justify-content: flex-end;
align-items: center;
gap: 4px;
"
>
<img src="../../assets/icon/coin.png" alt="" width="15%" />
<div style="color: #ffb627; font-size: 0.8em; font-weight: 590">
{{ user.provideIncome || 0 }}
</div>
</div>
</div>
</div>
</div>
<!-- 奖励说明模块 -->
<div v-if="showModule == 'reward'" style="display: flex; flex-direction: column; gap: 12px">
<div style="position: relative" v-for="poolItem in inviteAwardPool">
<img
:src="images[`reward${poolItem.quantity}people`]"
alt=""
width="100%"
style="display: block"
/>
<div
style="
position: absolute;
inset: 12% 0 0;
display: flex;
flex-direction: column;
justify-content: space-around;
"
>
<div style="display: flex; justify-content: space-around">
<div
style="width: 45%; position: relative"
v-for="(award, index) in poolItem.activityRewardPropsList"
>
<img :src="images.rewardItemBg" alt="" width="100%" />
<div
style="
position: absolute;
inset: 0;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
"
>
<img :src="award.cover" alt="" width="50%" />
<div>{{ showAwardText(award) }}</div>
</div>
</div>
</div>
<div style="display: flex; justify-content: center">
<img
v-if="poolItem.state == '1'"
:src="images.receiveBtActive"
alt=""
width="35%"
@click="receiveAward(poolItem.id)"
/>
<img v-else :src="images.receiveBt" alt="" width="35%" />
</div>
</div>
</div>
</div>
</div>
<!-- 弹窗遮罩层 -->
<maskLayer :maskLayerShow="maskLayerShow" @click="closedPopup">
<!-- 帮助模块 -->
<div v-if="helpInfoShow" style="margin: 20% 10%; position: relative" @click.stop>
<img :src="images.helpInfo" alt="" width="100%" />
<div
style="position: absolute; width: 8%; aspect-ratio: 1/1; top: 3.8%; right: 7%"
@click="closedPopup"
></div>
</div>
<!-- 输入邀请码模块 -->
<div
v-if="enterCodeShow"
style="
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
"
@click="closedPopup"
>
<div
style="
width: 80%;
border-radius: 12px;
background: #fff;
padding: 12px;
display: flex;
flex-direction: column;
gap: 4px;
"
@click.stop
>
<div style="color: rgba(0, 0, 0, 0.8); font-weight: 800">Enter Invitation Code</div>
<div style="display: flex; justify-content: space-between; align-items: center; gap: 8px">
<!-- 邀请码 -->
<div style="flex: 1">
<input
v-model="invitationCode"
type="text"
style="
width: 100%;
height: 100%;
color: rgba(0, 0, 0, 0.4);
font-weight: 510;
border-radius: 8px;
padding: 4px 8px;
border: 1px solid rgba(0, 0, 0, 0.4);
outline: none;
background-color: transparent;
"
@keyup.enter="confirmInvitationCode"
/>
</div>
<!-- 确认按钮 -->
<img :src="images.confirm" alt="" width="25%" @click="confirm" />
</div>
<div style="color: rgba(0, 0, 0, 0.4); font-weight: 510; font-size: 0.7em">
*Only users who registered within 72 hours can fill in the invitation code. Once the
invitation code is flled in, itcannot be modifed.
</div>
</div>
</div>
</maskLayer>
<!-- 提示弹窗 -->
<div
v-show="tipShow"
style="position: fixed; top: 50vh; display: flex; justify-content: center; width: 100vw"
>
<div
style="padding: 12px; border-radius: 8px; background: rgba(0, 0, 0, 0.4); font-weight: 600"
>
Copied successfully
</div>
</div>
</div>
</template>
<script setup>
import { gotoPrivateChat } from '@/utils/appBridge.js'
import { computed, onMounted, onUnmounted, ref } from 'vue'
import GeneralHeader from '@/components/GeneralHeader.vue'
import maskLayer from '../../components/MaskLayer.vue'
import { showError, showWarning, showInfo, showSuccess } from '@/utils/toast.js'
import { useClipboard } from '@vueuse/core'
import {
getMyInviteCode, // 获取我的邀请码
bindInviteCode, // 绑定邀请码
getMyInviteIncome, // 获取收益统计
getMyInviteUsers, // 有效邀请用户列表
getInviteAwardPool, // 邀请用户奖励池
getInviteReceiveAward, // 邀请用户领取奖励
getMyInviter, // 获取我的邀请人信息
} from '@/api/invitation.js'
import { connectToApp } from '@/utils/appConnector.js'
// vite动态导入图片
const imageModules = import.meta.glob('@/assets/images/InvitationNewUser/*.{png,jpg,svg}', {
eager: true,
})
// 生成文件名映射对象(自动移除路径和扩展名)
const images = Object.fromEntries(
Object.entries(imageModules).map(([path, module]) => {
const fileName = path.split('/').pop().split('.')[0]
return [fileName, module.default]
})
)
const { copy, isSupported } = useClipboard()
const helpInfoShow = ref(false) //帮助模块
const enterCodeShow = ref(false) //交易弹窗
const tipShow = ref(false) //提示弹窗
const invitationCode = ref('') //邀请码
const myInviteInfo = ref({}) //我的邀请信息
const myInviter = ref({}) //我的邀请人信息
const myInviteIncome = ref({}) //邀请用户收益统计
const myInviteUsers = ref([]) //邀请用户列表
const inviteAwardPool = ref({})
const showModule = ref('list') //显示模块
const showBindingBt = computed(() => {
return !myInviter.value.myInfo?.expired && !myInviter.value.inviterInfo
})
// 展示遮罩层
const maskLayerShow = computed(() => {
return helpInfoShow.value || enterCodeShow.value
})
// 关闭弹窗
const closedPopup = () => {
helpInfoShow.value = false
enterCodeShow.value = false
}
// 复制到剪贴板(原生方法)
const copyCode = (text) => {
if (isSupported.value) {
copy(text)
} else {
// 降级方案
const textArea = document.createElement('textarea')
textArea.value = text
document.body.appendChild(textArea)
textArea.select()
document.execCommand('copy')
document.body.removeChild(textArea)
}
tipShow.value = true
setTimeout(() => {
tipShow.value = false
}, 2000)
}
// 展示奖品信息
const showAwardText = (award) => {
if (award.type == 'GOLD') return award.quantity
return award.quantity + 'Days'
}
// 更改邀请码
const confirmInvitationCode = () => {
if (!invitationCode.value.trim()) {
showWarning('Please enter a valid invitation code.')
return
}
}
// 获取我的邀请码
const apiGetMyInviteCode = async () => {
const resCode = await getMyInviteCode()
if (resCode.status && resCode.body) {
myInviteInfo.value = resCode.body
}
}
// 获取我的邀请人信息
const apiGetMyInviter = async () => {
const resInviter = await getMyInviter()
if (resInviter.status && resInviter.body) {
myInviter.value = resInviter.body || {}
}
}
// 绑定邀请码
const confirm = async () => {
if (!invitationCode.value.trim()) {
showWarning('Please enter a valid invitation code.')
return
}
let data = { inviteCode: invitationCode.value.trim(), inviteType: 'REGISTER' }
try {
const resBind = await bindInviteCode(data)
if (resBind.status) {
showSuccess('Invitation code bound successfully!')
} else {
showError('Invitation code binding failed.')
}
invitationCode.value = ''
enterCodeShow.value = false
} catch (error) {
showError(error.errorMsg)
}
}
// 获取收益统计
const apiGetMyInviteIncome = async () => {
const resIncome = await getMyInviteIncome()
if (resIncome.status && resIncome.body) {
myInviteIncome.value = resIncome.body
}
}
// 有效邀请用户列表
const apiGetMyInviteUsers = async () => {
const resUserList = await getMyInviteUsers()
if (resUserList.status && resUserList.body) {
myInviteUsers.value = resUserList.body
}
}
// 邀请用户奖励池
const apiGetInviteAwardPool = async () => {
const resAwardPool = await getInviteAwardPool()
if (resAwardPool.status && resAwardPool.body) {
inviteAwardPool.value = resAwardPool.body
}
}
// 邀请用户领取奖励
const receiveAward = async (awardId) => {
try {
await getInviteReceiveAward(awardId)
apiGetInviteAwardPool() // 刷新奖励池
} catch (error) {
apiGetInviteAwardPool() // 刷新奖励池
}
}
// 页面初始化数据
const initData = () => {
apiGetMyInviteCode() // 获取我的邀请码
apiGetMyInviter() // 获取我的邀请人信息
apiGetMyInviteIncome() // 获取收益统计
apiGetMyInviteUsers() // 有效邀请用户列表
apiGetInviteAwardPool() // 邀请用户奖励池
}
// 使用工具函数连接APP
const connectToAppHandler = async () => {
await connectToApp(() => {
// 连接成功回调
initData()
})
}
onMounted(() => {
connectToAppHandler()
})
</script>
<style lang="scss" scoped>
* {
color: white;
font-family: 'SF Pro Text';
}
.fullPage {
width: 100vw;
min-height: 100vh;
background-color: #5b4a8a;
background-image: url(../../assets/images/InvitationNewUser/bg.png);
background-size: 100% auto;
background-repeat: no-repeat;
position: relative;
}
@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>