浏览代码

[add][ui和逻辑]

zhangwei 2 年之前
父节点
当前提交
fe6ba5862a

二进制
src/assets/gif/box.gif


二进制
src/assets/img/img-box1.png


二进制
src/assets/img/img-box5.png


文件差异内容过多而无法显示
+ 1 - 0
src/assets/svg/icon-default.svg


+ 11 - 0
src/http/nft.js

@@ -0,0 +1,11 @@
+
+
+import { service } from "./request";
+
+export function getNftProjectInfo(params) {
+    return service({
+        url: `/nft/project/getNftProjectInfo`,
+        method: 'post',
+        data: params
+    })
+}

+ 22 - 0
src/iframe/buy-nft.js

@@ -0,0 +1,22 @@
+import { createApp } from 'vue'
+import App from '@/view/iframe/buy-nft/index.vue'
+import ElementPlus from 'element-plus'
+import 'element-plus/dist/index.css'
+
+import "ant-design-vue/dist/antd.css"; // or 'ant-design-vue/dist/antd.less'
+import router from '@/router/buy-nft.js'
+import {Button,message,Tooltip} from "ant-design-vue";
+message.config({
+    top: `10px`,
+    duration: 3,
+    maxCount: 1,
+});
+
+const app = createApp(App);
+
+app.use(Button);
+app.use(Tooltip);
+app.use(message);
+app.use(router)
+app.use(ElementPlus);
+app.mount('#app');

+ 2 - 1
src/manifest.json

@@ -58,7 +58,8 @@
                 "/iframe/red-packet.html",
                 "/iframe/home.html",
                 "/iframe/publish-tips.html",
-                "/iframe/bind-tweet.html"
+                "/iframe/bind-tweet.html",
+                "/iframe/buy-nft.html"
             ],
             "matches": [
                 "<all_urls>"

+ 33 - 0
src/router/buy-nft.js

@@ -0,0 +1,33 @@
+import { createRouter, createWebHashHistory, createWebHistory } from "vue-router"
+import Home from '@/view/iframe/buy-nft/buy/home.vue'
+import Pay from '@/view/iframe/buy-nft/buy/pay.vue'
+import OpenBox from '@/view/iframe/buy-nft/buy/open-box.vue'
+
+let routes = [
+    {
+        path: '/',
+        name: 'Home',
+        component: Home,
+    },
+    {
+        path: "/pay",
+        name: 'Pay',
+        component: Pay
+    }, {
+        path: "/open_box",
+        name: 'OpenBox',
+        component: OpenBox
+    }
+]
+// 3. 创建路由实例
+const router = createRouter({
+
+    // 4. 采用hash 模式
+    history: createWebHashHistory('buy-nft.html'),
+    // 采用 history 模式
+    // history: createWebHistory('popup.html'),
+    routes, // short for `routes: routes`
+});
+
+export default router
+

+ 104 - 0
src/view/components/preview-balance.vue

@@ -0,0 +1,104 @@
+<template>
+    <div class="card-amount">
+        <img class="icon" src="@/assets/subject/icon-balance.png" />
+        <div class="con">
+            <div class="desc">Balance</div>
+            <div class="price">{{ currentCurrencyInfo.balance }} {{ currentCurrencyInfo.tokenSymbol }}</div>
+        </div>
+        <img class="refresh" :class="{ 'icon-refresh-rotate': false }" @click="updateCurrencyBanlce"
+            :src="require('@/assets/svg/icon-form-refresh.svg')" />
+    </div>
+</template>
+<script setup>
+import { ref } from "vue";
+import { syncChainTokenRechargeRecord } from "@/http/publishApi";
+/**
+ * 同步链上交易
+ */
+const asyncTokenRechRecord = (cb) => {
+    syncChainTokenRechargeRecord({
+        params: {
+            currencyCode: ''
+        }
+    }).then(res => {
+        if (res.code == 0) {
+            cb && cb(res.data)
+        }
+    })
+}
+// 刷新按钮旋转
+let refreshRotate = ref(false);
+
+// 当前选择的货币信息
+let currentCurrencyInfo = ref({
+    currencyCode: "",
+    currencyName: "",
+    balance: "",
+    currencyType: "",
+    iconPath: "",
+    minAmount: "",
+    tokenChain: "",
+    tokenSymbol: "",
+    usdEstimateBalance: ""
+});
+
+/**
+ * 更新货币余额
+ */
+const updateCurrencyBanlce = () => {
+    if (!refreshRotate.value) {
+        refreshRotate.value = true;
+        setTimeout(() => {
+            refreshRotate.value = false;
+        }, 1000)
+    }
+    asyncTokenRechRecord((res) => {
+        if (res.code == 0 && res.data && res.data.length) {
+            let currencyInfo = res.data[0];
+            if (currencyInfo.currencyCode == currentCurrencyInfo.value.currencyCode) {
+                currentCurrencyInfo.value.balance = currencyInfo.balance;
+            }
+        }
+    })
+}
+
+</script>
+
+<style lang="scss" scoped>
+.card-amount {
+    overflow: hidden;
+    display: flex;
+    height: 80px;
+    padding: 20px;
+    border-radius: 20px;
+    border: 1px solid #E6E6E6;
+
+    .icon {
+        width: 40px;
+        height: 40px;
+    }
+
+    .con {
+        flex: 1;
+        padding: 0 10px;
+
+        .desc {
+            color: rgba($color: #000000, $alpha: 0.5);
+            font-size: 12px;
+            margin-bottom: 4px;
+        }
+
+        .price {
+            font-size: 16px;
+            font-weight: bold;
+        }
+    }
+
+    .refresh {
+        cursor: pointer;
+        width: 50px;
+        height: 50px;
+        margin-top: -5px;
+    }
+}
+</style>

+ 166 - 0
src/view/iframe/buy-nft/buy/home.vue

@@ -0,0 +1,166 @@
+<template>
+    <div class="dialog">
+        <!-- home -->
+        <div class="area-title">
+            <img :src="require('@/assets/svg/icon-close.svg')" @click="clickClose" />
+            <div class="title">NFT Mystery box</div>
+        </div>
+        <!-- 内容 -->
+        <div class="area-content">
+            <img :src="require('@/assets/svg/icon-default.svg')" class="box" />
+        </div>
+
+        <!-- 底部 -->
+        <div class="footer">
+            <!-- 首页 -->
+            <div class="sold">SOLD: 107/10000 </div>
+            <div class="limit">Buy Limit: 0/5</div>
+            <!-- <btn-loading></btn-loading> -->
+            
+            <div class="buy5">
+                <div class="right">Buy 5</div>
+                <div class="left">
+                    <div class="off">20% OFF</div>
+                    <div class="usdt">40 USDT</div>
+                </div>
+            </div>
+            <!-- <btn-loading></btn-loading> -->
+            <div class="buy1" @click="clickJump">
+                <div class="right">Buy 1</div>
+                <div class="left">10 USDT</div>
+            </div>
+        </div>
+    </div>
+</template>
+<script setup>
+import router from "@/router/buy-nft.js";
+import { onMounted  } from "vue";
+import { getNftProjectInfo} from "@/http/nft";
+import BtnLoading from '../components/btn-loading.vue'
+
+
+const clickClose = () => {
+
+}
+const clickJump = () => {
+    router.push({ path: '/pay' });
+}
+onMounted(()=>{
+    
+})
+</script>
+
+<style lang="scss" scoped>
+.dialog {
+    background: #fff;
+    border-radius: 25px;
+    max-width: 90%;
+    min-width: 800px;
+    height: 90%;
+    z-index: 23;
+    display: flex;
+    flex-direction: column;
+
+
+    .area-title {
+        width: 100%;
+        height: 48px;
+        display: flex;
+        align-items: center;
+        border-bottom: 1px solid #D9D9D9;
+        font-weight: 500;
+        font-size: 16px;
+        letter-spacing: 0.3px;
+        color: #000000;
+
+        img {
+            width: 24p;
+            height: 24px;
+            margin-left: 14px;
+            margin-right: 12px;
+            cursor: pointer;
+        }
+
+    }
+
+    .area-content {
+        flex: 1;
+
+        img {
+            width: 100%;
+            height: 100%;
+        }
+    }
+
+    .footer {
+        border-top: 1px solid #D9D9D9;
+        height: 80px;
+        width: 100%;
+        display: flex;
+        align-items: center;
+        justify-content: flex-end;
+        position: relative;
+        .loading{
+            width: 24px;
+        }
+
+        .sold {
+            position: absolute;
+            left: 20px;
+        }
+
+        .limit {
+            color: #AF934E;
+            margin-right: 25px;
+        }
+
+        .buy5 {
+            border: 1px solid #1D9BF0;
+            background: rgba(29, 155, 240, 0.01);
+            border-radius: 100px;
+            color: #1D9BF0;
+            width: 217px;
+            height: 50px;
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            padding: 0 15px 0 20px;
+            font-weight: 700;
+            font-size: 18px;
+            cursor: pointer;
+            margin-right: 12px;
+
+            .off {
+                color: #AF934E;
+                font-weight: 700;
+                font-size: 14px;
+
+                letter-spacing: 0.3px;
+            }
+
+            .usdt {
+                color: #1D9BF0;
+                font-size: 14px;
+                font-weight: 700;
+
+            }
+        }
+
+        .buy1 {
+            cursor: pointer;
+            background: #1D9BF0;
+            color: #fff;
+            border-radius: 100px;
+            width: 217px;
+            height: 50px;
+            display: flex;
+            align-items: center;
+            font-size: 18px;
+            font-weight: 700;
+            justify-content: space-between;
+            padding: 0 15px 0 20px;
+            margin-right: 25px;
+        }
+    }
+}
+</style>

+ 135 - 0
src/view/iframe/buy-nft/buy/open-box.vue

@@ -0,0 +1,135 @@
+<template>
+    <!-- gif -->
+    <div class="box_content">
+        <img :src="require('@/assets/gif/box.gif')" class="box" v-show="state.box.show" />
+        <div class="nft" v-for="item in state.nft.data" v-show="item.show">
+            <div class="detail">
+                <img :src="require('@/assets/img/img-box5.png')" alt="" />
+            </div>
+            <p>Azuki #6346</p>
+        </div>
+    </div>
+</template>
+<script setup>
+import { reactive, onMounted } from 'vue'
+let state = reactive({
+    box: {
+        show: true
+    },
+    nft: {
+        data: [
+            {
+                show: false
+            },
+            {
+                show: false
+            }
+        ]
+    }
+})
+
+const setAllNoShow = () => {
+    state.nft.data.forEach((item) => {
+        item.show = false
+    })
+}
+
+const showNFTs = () => {
+    let len = state.nft.data.length
+    if (len == 0) {
+        return
+    }
+    let i = 0
+    setAllNoShow()
+    state.nft.data[i].show = true
+    i++
+    let timer = setInterval(() => {
+        if (len > i) {
+            setAllNoShow()
+            state.nft.data[i].show = true
+        } else {
+            clearInterval(timer)
+        }
+        i++
+    }, 2000)
+}
+
+onMounted(() => {
+    setTimeout(() => {
+        state.box.show = false
+        showNFTs()
+    }, 2000)
+
+})
+</script>
+<style lang="scss" scoped>
+.box_content {
+    position: fixed;
+    text-align: center;
+    display: flex;
+    justify-content: center;
+    z-index: 2;
+
+    .box {
+        width: 200px;
+        position: absolute;
+        top: 40%;
+        left: 50%;
+        margin-top: -100px;
+        margin-left: -100px;
+    }
+
+    .nft {
+        position: absolute;
+        top: 40%;
+        margin-top: -200px;
+        width: 400px;
+        height: 450px;
+        animation: myfirst 0.5s;
+
+        display: flex;
+        flex-direction: column;
+
+        .detail {
+            flex: 1;
+            text-align: center;
+
+            img {
+                width: 100%;
+                height: 100%;
+                border: 3px solid white;
+                border-radius: 10px;
+            }
+        }
+
+        p {
+            margin: 0;
+            padding: 0;
+            margin-top: 20px;
+            color: #FFFFFF;
+            font-size: 16px;
+            font-weight: 700;
+        }
+
+    }
+}
+
+@keyframes myfirst {
+    0% {
+        width: 300px;
+        height: 300px;
+    }
+
+    50% {
+        width: 450px;
+        height: 500px;
+        margin-top: -210px;
+    }
+
+    100% {
+        margin-top: -200px;
+        width: 400px;
+        height: 450px;
+    }
+}
+</style>

+ 280 - 0
src/view/iframe/buy-nft/buy/pay.vue

@@ -0,0 +1,280 @@
+<template>
+    <div class="dialog">
+        <!-- home -->
+        <div class="area-title">
+            <img :src="require('@/assets/svg/icon-back.svg')" @click="clickBack" />
+            <div class="title">Payment</div>
+        </div>
+        <!-- 内容 -->
+        <div class="area-content">
+            <div class="left">
+                <img :src="require('@/assets/img/img-box5.png')" alt="">
+                <div class="tip">
+                    <span>Mystery box*1</span>
+                    <span>
+                        <img src="" alt="">
+                        10
+                    </span>
+                </div>
+            </div>
+            <div class="right">
+                <div class="card-content">
+                    <div class="card-title">
+                        <img class="img" :src="require('@/assets/subject/top-01.svg')" />
+                        <div class="font">Deposit to Send Giveaway</div>
+                    </div>
+                    <top-up2 :asyncIng="false" :currentCurrencyInfo="{}" @topUpDone="topUpDone">
+                    </top-up2>
+
+                    <div class="card-title">
+                        <img class="img" :src="require('@/assets/subject/top-02.svg')" />
+                        <div class="font">Wait for the amount to arrive</div>
+                    </div>
+                    <preview-balance></preview-balance>
+                </div>
+            </div>
+        </div>
+
+        <!-- 底部 -->
+        <div class="footer">
+            <!-- <btn-loading></btn-loading> -->
+            <div class="pay" @click="clickPlay">Pay 10 USDT</div>
+        </div>
+    </div>
+</template>
+<script setup >
+import router from "@/router/buy-nft.js";
+import { ref } from 'vue'
+import topUp2 from "@/view/iframe/publish/components/top-up2.vue";
+import PreviewBalance from "@/view/components/preview-balance.vue";
+import BtnLoading from '../components/btn-loading.vue'
+let currentCurrencyInfo = ref({
+    currencyCode: "",
+    currencyName: "",
+    balance: "",
+    currencyType: "",
+    iconPath: "",
+    minAmount: "",
+    tokenChain: "",
+    tokenSymbol: "",
+    usdEstimateBalance: ""
+});
+
+const clickBack = () => {
+    router.back()
+}
+const clickPlay = () => {
+    router.push({ path: '/open_box' });
+}
+
+// 刷新按钮旋转
+let refreshRotate = ref(false);
+
+/**
+ * 同步链上交易
+ */
+const asyncTokenRechRecord = (cb) => {
+    syncChainTokenRechargeRecord({
+        params: {
+            currencyCode: currentCurrencyInfo.value.currencyCode
+        }
+    }).then(res => {
+        cb && cb(res)
+    })
+}
+
+
+
+</script>
+<style lang="scss" scoped>
+.dialog {
+    background: #fff;
+    border-radius: 25px;
+    max-width: 90%;
+    min-width: 800px;
+    height: 90%;
+    z-index: 23;
+    display: flex;
+    flex-direction: column;
+
+
+    .area-title {
+        width: 100%;
+        height: 48px;
+        display: flex;
+        align-items: center;
+        border-bottom: 1px solid #D9D9D9;
+        font-weight: 500;
+        font-size: 16px;
+        letter-spacing: 0.3px;
+        color: #000000;
+
+        img {
+            width: 24p;
+            height: 24px;
+            margin-left: 14px;
+            margin-right: 12px;
+            cursor: pointer;
+        }
+
+    }
+
+    .area-content {
+        display: flex;
+        overflow-y: auto;
+
+        .left {
+            width: 400px;
+            margin: 40px 56px 0 56px;
+
+            img {
+                max-width: 400px;
+                max-height: 400px;
+                width:100%;
+                height: auto;
+            }
+
+            .tip {
+                margin-top: 15px;
+                display: flex;
+                justify-content: space-between;
+
+                img {
+                    width: 14px;
+                    height: 14px;
+                }
+            }
+        }
+
+        .right {
+            margin: 30px 56px 0px 30px;
+
+            .card-content {
+                float: right;
+                width: 430px;
+
+                .card-title {
+                    height: 32px;
+
+                    .img {
+                        float: left;
+                        width: 20px;
+                        height: 20px;
+                        margin-right: 8px;
+                    }
+
+                    .font {
+                        float: left;
+                        font-size: 17px;
+                        font-weight: 500;
+
+                        span {
+                            color: #0091e9;
+                        }
+                    }
+                }
+
+
+
+                .card-list {
+                    padding: 20px;
+                    border-radius: 20px;
+                    border: 1px solid #E6E6E6;
+
+                    .item {
+                        display: flex;
+                        justify-content: space-between;
+                        align-items: center;
+                        height: 47px;
+                        font-size: 14px;
+                        font-weight: 500;
+                        box-shadow: inset 0px -1px 0px #EAEAEA;
+                    }
+                }
+            }
+        }
+    }
+
+    .pay {
+        width: 200px;
+        height: 50px;
+        font-weight: 700;
+        font-size: 18px;
+        margin-right: 30px;
+        color: #FFFFFF;
+        background: #1D9BF0;
+        border-radius: 10000px;
+        text-align: center;
+        line-height: 50px;
+        cursor: pointer;
+    }
+
+    .footer {
+        border-top: 1px solid #D9D9D9;
+        height: 80px;
+        width: 100%;
+        display: flex;
+        align-items: center;
+        justify-content: flex-end;
+        position: relative;
+
+        .sold {
+            position: absolute;
+            left: 20px;
+        }
+
+        .limit {
+            color: #AF934E;
+            margin-right: 25px;
+        }
+
+        .buy5 {
+            border: 1px solid #1D9BF0;
+            background: rgba(29, 155, 240, 0.01);
+            border-radius: 100px;
+            color: #1D9BF0;
+            width: 217px;
+            height: 50px;
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            padding: 0 15px 0 20px;
+            font-weight: 700;
+            font-size: 18px;
+            cursor: pointer;
+            margin-right: 12px;
+
+            .off {
+                color: #AF934E;
+                font-weight: 700;
+                font-size: 14px;
+
+                letter-spacing: 0.3px;
+            }
+
+            .usdt {
+                color: #1D9BF0;
+                font-size: 14px;
+                font-weight: 700;
+
+            }
+        }
+
+        .buy1 {
+            cursor: pointer;
+            background: #1D9BF0;
+            color: #fff;
+            border-radius: 100px;
+            width: 217px;
+            height: 50px;
+            display: flex;
+            align-items: center;
+            font-size: 18px;
+            font-weight: 700;
+            justify-content: space-between;
+            padding: 0 15px 0 20px;
+            margin-right: 25px;
+        }
+    }
+}
+</style>

+ 28 - 0
src/view/iframe/buy-nft/components/btn-loading.vue

@@ -0,0 +1,28 @@
+<template>
+    <div class="btn-loading">
+        <img :src="require('@/assets/svg/icon-loading.svg')" class="loading" />        
+    </div>
+</template>
+<script setup>
+import {  defineProps } from 'vue'
+const props = defineProps({
+    border_color: {
+        type: String,
+        default: 'blue',
+    },
+})
+</script>
+<style lang="scss" scoped>
+.btn-loading{
+    width: 100%;
+    height: 100%;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    cursor: auto;
+    img{
+        width:24px;
+        height: 24px;
+    }
+}
+</style>

+ 44 - 0
src/view/iframe/buy-nft/index.vue

@@ -0,0 +1,44 @@
+<template>
+    <div class="content">
+        <div class="background"></div>
+        <router-view></router-view>
+    </div>
+</template>
+<script setup>
+import { reactive } from 'vue'
+let state = reactive({
+    // 
+    show: 'dialog-home'
+})
+
+
+
+</script>
+<style lang="scss" >
+html,
+body,
+#app {
+    width: 100%;
+    height: 100%;
+    margin: 0;
+    padding: 0;
+
+}
+
+.content {
+    width: 100%;
+    height: 100%;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+
+    .background {
+        width: 100%;
+        height: 100%;
+        background: #000000;
+        opacity: 0.7;
+        position: fixed;
+        z-index: 1;
+    }
+}
+</style>

部分文件因为文件数量过多而无法显示