nieyuge 2 лет назад
Родитель
Сommit
734d5dd2a4
2 измененных файлов с 233 добавлено и 3 удалено
  1. 8 0
      src/http/nft.js
  2. 225 3
      src/view/iframe/buy-nft/buy/home.vue

+ 8 - 0
src/http/nft.js

@@ -79,4 +79,12 @@ export function transferRequest(params) {
         method: 'post',
         data: params
     })
+}
+
+export function redeemNft(params) {
+    return service({
+        url: `/nft/project/redeemNft`,
+        method: 'post',
+        data: params
+    })
 }

+ 225 - 3
src/view/iframe/buy-nft/buy/home.vue

@@ -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>