|
@@ -19,7 +19,15 @@
|
|
|
<div class="limit" v-if="showDesc">Buy Limit: {{ state.data.userBuyCount || 0 }}/{{ state.data.perUserBuyLimit || 0 }}</div>
|
|
|
</div>
|
|
|
<div class="btn-area">
|
|
|
- <template v-for="item in state.data.salePlans.splice(0, 2).reverse()">
|
|
|
+ <!-- 兑换码 -->
|
|
|
+ <template v-if="(state.data.perUserBuyLimit - state.data.userBuyCount) >= 1 && (state.data.itemTotalCount - state.data.itemSoldCount) >= 1">
|
|
|
+ <div class="redeem" @click="showRedeemLayer">Redeem</div>
|
|
|
+ </template>
|
|
|
+ <template v-else>
|
|
|
+ <div class="redeem grey">Redeem</div>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-for="item in state.data.salePlans.slice(0, 2).reverse()">
|
|
|
<div class="buy1" @click="clickJump(item)" v-if="item.itemCount == 1 && (state.data.perUserBuyLimit - state.data.userBuyCount) >= 1
|
|
|
&& (state.data.itemTotalCount - state.data.itemSoldCount) >= 1">
|
|
|
<template v-if="(item.price.length + item.currencyInfo.tokenSymbol.length) > 30">
|
|
@@ -77,16 +85,42 @@
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
+
|
|
|
+ <!-- 兑换码弹出层 -->
|
|
|
+ <template v-if="showRedeem">
|
|
|
+ <div class="redeemLayer">
|
|
|
+ <div class="header">
|
|
|
+ <img :src="require('@/assets/svg/icon-close.svg')" @click="hideRedeemLayer" />
|
|
|
+ </div>
|
|
|
+ <div class="footer">
|
|
|
+ <div class="tips">Enter Redemption Code</div>
|
|
|
+ <div class="input"><input ref="refInput" type="text" v-model="redeemStr" /></div>
|
|
|
+ <div class="confirm">
|
|
|
+ <button class="btn" @click="redeemPost" v-if="redeemNext">Confirm</button>
|
|
|
+ <button class="btn grey" v-else>Confirm</button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="redeemMask" @click="hideRedeemLayer"></div>
|
|
|
+ </template>
|
|
|
</template>
|
|
|
<script setup>
|
|
|
import { useRouter } from 'vue-router'
|
|
|
-import { onMounted, reactive, inject, ref } from "vue";
|
|
|
-import { getNftMysteryBoxSaleInfo } from "@/http/nft";
|
|
|
+import { ElMessage } from 'element-plus'
|
|
|
+import { onMounted, reactive, inject, ref, nextTick, watchEffect } from "vue";
|
|
|
+import { getNftMysteryBoxSaleInfo, redeemNft } from "@/http/nft";
|
|
|
import BtnLoading from '../components/btn-loading.vue'
|
|
|
import { getQueryString } from "@/uilts/help";
|
|
|
+import { sendChromeTabMessage } from '@/uilts/chromeExtension.js';
|
|
|
let pay_info = inject('pay_info');
|
|
|
let router = useRouter()
|
|
|
let showDesc = ref(true)
|
|
|
+let showRedeem = ref(false)
|
|
|
+let redeemNext = ref(false)
|
|
|
+let redeemStr = ref('')
|
|
|
+let refInput = ref('')
|
|
|
+let groupId = ref('')
|
|
|
+let projectId = ref('')
|
|
|
let dialogStyle = reactive({
|
|
|
height: '800'
|
|
|
})
|
|
@@ -131,6 +165,85 @@ const setDialogStyle = () => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+const redeemPost = () => {
|
|
|
+ let params = {
|
|
|
+ redeemCode: redeemStr.value
|
|
|
+ }
|
|
|
+ if (projectId.value) {
|
|
|
+ params['nftProjectId'] = projectId.value
|
|
|
+ }
|
|
|
+ if (groupId.value) {
|
|
|
+ params['nftGroupId'] = groupId.value
|
|
|
+ }
|
|
|
+
|
|
|
+ // disabled btn
|
|
|
+ redeemNext.value = false
|
|
|
+
|
|
|
+ redeemNft({ params }).then(res => {
|
|
|
+ let { code, data } = res;
|
|
|
+ if (code == 0 && data) {
|
|
|
+ pay_info.buy_items = data
|
|
|
+ sendChromeTabMessage({ actionType: "FINISH_GROUP_BANNNER" }, () => { })
|
|
|
+ router.push({ path: '/open_box' });
|
|
|
+ } else {
|
|
|
+ let msg = ''
|
|
|
+ switch (res.code.toString()) {
|
|
|
+ case '5001':
|
|
|
+ msg = 'nft project not exist'
|
|
|
+ break;
|
|
|
+ case '5002':
|
|
|
+ msg = 'nft project not available'
|
|
|
+ break
|
|
|
+ case '5101':
|
|
|
+ msg = 'nft sale plan not exist'
|
|
|
+ break
|
|
|
+ case '5102':
|
|
|
+ msg = 'nft sold out'
|
|
|
+ break
|
|
|
+ case '5103':
|
|
|
+ msg = 'Purchase limit reached'
|
|
|
+ break
|
|
|
+ default:
|
|
|
+ msg = 'Invalid redemption code, please try again'
|
|
|
+ console.log(res.msg)
|
|
|
+ }
|
|
|
+ ElMessage({
|
|
|
+ message: msg,
|
|
|
+ type: 'warning'
|
|
|
+ })
|
|
|
+ redeemNext.value = true;
|
|
|
+ }
|
|
|
+ }).catch(() => {
|
|
|
+ ElMessage({
|
|
|
+ message: 'Invalid redemption code, please try again',
|
|
|
+ type: 'warning'
|
|
|
+ })
|
|
|
+ redeemNext.value = true;
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+const showRedeemLayer = () => {
|
|
|
+ showRedeem.value = true;
|
|
|
+ nextTick(() => {
|
|
|
+ refInput.value.focus()
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+const hideRedeemLayer = () => {
|
|
|
+ showRedeem.value = false;
|
|
|
+ redeemStr.value = '';
|
|
|
+}
|
|
|
+
|
|
|
+watchEffect(() => {
|
|
|
+ let len = 16
|
|
|
+ let str = redeemStr.value.replace(/[^a-zA-Z0-9]/g, '')
|
|
|
+ str = str.toUpperCase();
|
|
|
+ str = str.slice(0, len);
|
|
|
+ // set
|
|
|
+ redeemStr.value = str;
|
|
|
+ redeemNext.value = str !== '' && str.length === len;
|
|
|
+})
|
|
|
+
|
|
|
onMounted(() => {
|
|
|
setDialogStyle();
|
|
|
|
|
@@ -142,6 +255,11 @@ onMounted(() => {
|
|
|
if (!nft_project_Id) {
|
|
|
return
|
|
|
}
|
|
|
+
|
|
|
+ // 作用域外用
|
|
|
+ groupId.value = nft_group_Id
|
|
|
+ projectId.value = nft_project_Id
|
|
|
+
|
|
|
getNftMysteryBoxSaleInfo({
|
|
|
params: {
|
|
|
nftProjectId: nft_project_Id
|
|
@@ -151,6 +269,7 @@ onMounted(() => {
|
|
|
state.data = res.data
|
|
|
pay_info.home = res.data
|
|
|
let { perUserBuyLimit, itemTotalCount } = res.data;
|
|
|
+ // 不限购
|
|
|
if (perUserBuyLimit && itemTotalCount && perUserBuyLimit >= itemTotalCount) {
|
|
|
showDesc.value = false;
|
|
|
}
|
|
@@ -323,7 +442,110 @@ onMounted(() => {
|
|
|
background: #CDCDCD;
|
|
|
cursor: not-allowed;
|
|
|
}
|
|
|
+
|
|
|
+ .redeem {
|
|
|
+ border: 1px solid #1D9BF0;
|
|
|
+ background: rgba(29, 155, 240, 0.01);
|
|
|
+ border-radius: 100px;
|
|
|
+ color: #1D9BF0;
|
|
|
+ min-width: 110px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ font-weight: 700;
|
|
|
+ font-size: 16px;
|
|
|
+ cursor: pointer;
|
|
|
+ margin-right: 12px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ &.grey {
|
|
|
+ background: #CDCDCD;
|
|
|
+ cursor: not-allowed;
|
|
|
+ color: #fff;
|
|
|
+ border: unset;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+.redeemLayer {
|
|
|
+ position: absolute;
|
|
|
+ z-index: 25;
|
|
|
+ top: 50%;
|
|
|
+ left: 50%;
|
|
|
+ width: 630px;
|
|
|
+ height: 270px;
|
|
|
+ border-radius: 20px;
|
|
|
+ background: #FFFFFF;
|
|
|
+ transform: translate(-50%, -50%);
|
|
|
+ .header {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ height: 48px;
|
|
|
+ box-shadow: 0px 0.5px 0px #D1D9DD;
|
|
|
+ img {
|
|
|
+ width: 24px;
|
|
|
+ height: 24px;
|
|
|
+ margin-left: 14px;
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .footer {
|
|
|
+ padding: 20px;
|
|
|
+ .tips {
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 500;
|
|
|
+ line-height: 19px;
|
|
|
+ letter-spacing: 0.3px;
|
|
|
+ margin-bottom: 18px;
|
|
|
+ }
|
|
|
+ .input {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ height: 49px;
|
|
|
+ border-radius: 100px;
|
|
|
+ background: #FFFFFF;
|
|
|
+ border: 1px solid #DDDDDD;
|
|
|
+ input {
|
|
|
+ width: calc(100% - 40px);
|
|
|
+ border: 0;
|
|
|
+ outline: 0;
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 500;
|
|
|
+ line-height: 19px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .confirm {
|
|
|
+ margin-top: 45px;
|
|
|
+ text-align: right;
|
|
|
+ .btn {
|
|
|
+ border: 0;
|
|
|
+ width: 170px;
|
|
|
+ height: 51px;
|
|
|
+ cursor: pointer;
|
|
|
+ color: #FFFFFF;
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 700;
|
|
|
+ border-radius: 100px;
|
|
|
+ background: #1D9BF0;
|
|
|
+ &.grey {
|
|
|
+ background: #CDCDCD;
|
|
|
+ cursor: not-allowed;
|
|
|
+ color: #fff;
|
|
|
+ border: unset;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+.redeemMask {
|
|
|
+ position: absolute;
|
|
|
+ z-index: 24;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ background-color: rgba($color: #000000, $alpha: .7);
|
|
|
+}
|
|
|
</style>
|