385 lines
9.3 KiB
Vue
385 lines
9.3 KiB
Vue
<template>
|
|
<section id="nft_section" data-anchor="nft">
|
|
<div class="info">
|
|
<div class="count-down">
|
|
<div class="time" v-if="presaleStatus === 2">{{timeStr}}</div>
|
|
<div class="title">{{presaleTitle}}</div>
|
|
</div>
|
|
<div class="text" v-html="hint">
|
|
</div>
|
|
</div>
|
|
<card-scroller :heros="heroDatas" :presale-status="presaleStatus" class="card-scroller"></card-scroller>
|
|
<div class="count-label">{{numberRest}}/{{numberTotal}}</div>
|
|
<div class="order-status" v-show="showOrderStatus">
|
|
<el-tooltip class="item" effect="light" content="Transaction in progress" placement="right">
|
|
<time-loader></time-loader>
|
|
</el-tooltip>
|
|
</div>
|
|
</section>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import { Component, Vue, Watch } from 'vue-property-decorator'
|
|
import CardScroller from '@/components/main/CardScroller.vue'
|
|
import { queryOrder, queryPresaleStatus, searchBox } from '@/api/Mall'
|
|
import { ISpineData } from '@/utils/SpineRender'
|
|
import { AppModule } from '@/store/modules/app'
|
|
import { secs2str } from '@/utils/time.util'
|
|
import { EventBus, PRESALE_BEGIN, PRESALE_ERROR, PRESALE_ORDER_GET, PRESALE_SUCCESS } from '@/utils/event-bus'
|
|
import { Loading } from 'element-ui'
|
|
import { ElLoadingComponent } from 'element-ui/types/loading'
|
|
import TimeLoader from '@/components/main/TimeLoader.vue'
|
|
import { UserModule } from '@/store/modules/user'
|
|
|
|
@Component({
|
|
name: 'NftSection',
|
|
components: {
|
|
TimeLoader,
|
|
CardScroller
|
|
|
|
}
|
|
})
|
|
export default class extends Vue {
|
|
heroDatas: ISpineData[] = []
|
|
hint = ''
|
|
presaleTitle = ''
|
|
presaleStatus = 0
|
|
numberTotal = 0
|
|
numberRest = 0
|
|
buyed = true
|
|
timeStr = ''
|
|
countdown = 0
|
|
timer: any = null
|
|
orderTimer: any = null
|
|
loadingInstance: ElLoadingComponent
|
|
showOrderStatus = false
|
|
historyOrderId: string | null = ''
|
|
|
|
created() {
|
|
this.fetchData()
|
|
this.subscribeToEvents()
|
|
}
|
|
|
|
mounted() {
|
|
this.checkOrderHistory()
|
|
}
|
|
|
|
unmounted() {
|
|
this.removeEvents()
|
|
}
|
|
|
|
@Watch('isLogin')
|
|
private accountChange() {
|
|
if (this.accountId) {
|
|
this.getPresaleInfo()
|
|
this.checkOrderHistory()
|
|
}
|
|
}
|
|
|
|
@Watch('countdown')
|
|
private countDownChange() {
|
|
this.timeStr = secs2str(this.countdown)
|
|
}
|
|
|
|
get accountId() {
|
|
return AppModule.accountId
|
|
}
|
|
|
|
get isLogin() {
|
|
return !!UserModule.token && !!AppModule.step
|
|
}
|
|
|
|
async fetchData() {
|
|
await this.queryPresaleList()
|
|
await this.getPresaleInfo()
|
|
}
|
|
|
|
checkOrderHistory() {
|
|
const historyOrderId = localStorage.getItem('tmp_presale_order_id')
|
|
if (historyOrderId && this.accountId) {
|
|
this.beginTraceOrderStatus(historyOrderId)
|
|
}
|
|
}
|
|
|
|
subscribeToEvents() {
|
|
EventBus.$on(PRESALE_BEGIN, this.onPresaleBegin.bind(this))
|
|
EventBus.$on(PRESALE_SUCCESS, this.onPresaleSuccess.bind(this))
|
|
EventBus.$on(PRESALE_ERROR, this.onPresaleError.bind(this))
|
|
EventBus.$on(PRESALE_ORDER_GET, this.onOrderIDGeted.bind(this))
|
|
}
|
|
|
|
removeEvents() {
|
|
EventBus.$off(PRESALE_BEGIN, this.onPresaleBegin.bind(this))
|
|
EventBus.$off(PRESALE_SUCCESS, this.onPresaleSuccess)
|
|
EventBus.$off(PRESALE_ERROR, this.onPresaleError)
|
|
EventBus.$off(PRESALE_ORDER_GET, this.onOrderIDGeted.bind(this))
|
|
}
|
|
|
|
onPresaleBegin() {
|
|
this.loadingInstance = Loading.service({})
|
|
console.log('presale begin')
|
|
}
|
|
|
|
onOrderIDGeted(orderId: string) {
|
|
console.log('order id:', orderId)
|
|
this.$alert('Transaction in progress', 'We will notify you after confirmation', { type: 'info', confirmButtonText: 'OK' })
|
|
this.beginTraceOrderStatus(orderId)
|
|
}
|
|
|
|
onPresaleError(res: any) {
|
|
console.log('presale error: ', res)
|
|
this.showOrderStatus = false
|
|
this.loadingInstance?.close()
|
|
this.$alert('Some error when process presale', 'Buy Failed', { type: 'error', confirmButtonText: 'OK' })
|
|
}
|
|
|
|
async onPresaleSuccess(res: any) {
|
|
console.log('presale success', res)
|
|
this.resetTmpOrderId()
|
|
this.showOrderStatus = false
|
|
this.$alert('Congratulations', 'Buy Success', { type: 'success', confirmButtonText: 'OK' })
|
|
await this.getPresaleInfo()
|
|
}
|
|
|
|
beginTraceOrderStatus(orderId: string) {
|
|
this.showOrderStatus = true
|
|
this.loadingInstance?.close()
|
|
this.orderTimer = setInterval(() => {
|
|
this.getOrderStatus(orderId)
|
|
}, 1000)
|
|
}
|
|
|
|
resetTmpOrderId() {
|
|
if (this.orderTimer !== null) {
|
|
clearInterval(this.orderTimer)
|
|
this.orderTimer = null
|
|
}
|
|
localStorage.removeItem('tmp_presale_order_id')
|
|
this.loadingInstance?.close()
|
|
}
|
|
|
|
async getOrderStatus(orderId: string) {
|
|
try {
|
|
const res: any = await queryOrder({ account: this.accountId, order_id: orderId })
|
|
if (res.state === 1) {
|
|
EventBus.$emit(PRESALE_SUCCESS, {})
|
|
} else if (res.state === 3) {
|
|
EventBus.$emit(PRESALE_ERROR, {})
|
|
this.resetTmpOrderId()
|
|
} else if (res.state === 0) {
|
|
EventBus.$emit(PRESALE_ERROR, {})
|
|
this.resetTmpOrderId()
|
|
}
|
|
} catch (err) {
|
|
console.log('query order status error', err)
|
|
}
|
|
}
|
|
|
|
beginCountdown() {
|
|
this.clearTimer()
|
|
this.timer = setInterval(() => {
|
|
if (this.countdown <= 0) {
|
|
this.clearTimer()
|
|
} else {
|
|
this.countdown--
|
|
}
|
|
}, 1000)
|
|
}
|
|
|
|
clearTimer() {
|
|
clearInterval(this.timer)
|
|
this.timer = null
|
|
}
|
|
|
|
async getPresaleInfo() {
|
|
const res: any = await queryPresaleStatus({ account: this.accountId })
|
|
if (res.presale_info) {
|
|
this.numberTotal = res.presale_info.total_num || 0
|
|
this.numberRest = this.numberTotal - (res.presale_info.sold_num || 0)
|
|
this.numberRest = this.numberRest < 0 ? 0 : this.numberRest
|
|
this.hint = res.presale_info.hint.replace(/\\n/g, '<br/>')
|
|
this.buyed = !!res.presale_info.buyed
|
|
this.presaleStatus = res.presale_info.state || 0
|
|
this.presaleTitle = res.presale_info.title
|
|
this.countdown = res.presale_info.countdown
|
|
if (this.presaleStatus === 1 && this.countdown > 0) {
|
|
this.beginCountdown()
|
|
}
|
|
AppModule.updatePresaleStat(this.presaleStatus)
|
|
|
|
const buySet: Set<string> = new Set()
|
|
if (res.presale_info.buyable_list) {
|
|
for (const sub of res.presale_info.buyable_list) {
|
|
buySet.add(sub.box_id)
|
|
}
|
|
}
|
|
AppModule.updateCanBuy(this.presaleStatus === 2 &&
|
|
this.numberRest > 0 && buySet.size > 0
|
|
)
|
|
|
|
for (const data of this.heroDatas) {
|
|
Vue.set(data, 'stopBuy', !buySet.has(data.id!))
|
|
}
|
|
}
|
|
}
|
|
|
|
async queryPresaleList() {
|
|
const reqData = {
|
|
account: '',
|
|
page: 0
|
|
}
|
|
const res: any = await searchBox(reqData)
|
|
this.heroDatas.length = 0
|
|
|
|
for (const data of res.rows) {
|
|
const heroData: any = {
|
|
name: data.name,
|
|
class: (data.job + '').toLowerCase(),
|
|
recordId: data.box_id,
|
|
id: data.box_id,
|
|
skelName: `n_${data.name.toLowerCase()}`,
|
|
directBuy: true,
|
|
stopBuy: false,
|
|
showBuy: true
|
|
}
|
|
if (data.currency_list && data.currency_list.length > 0) {
|
|
const priceData: any = data.currency_list[0]
|
|
heroData.discount = priceData.discount_rate
|
|
heroData.price = priceData.original_price
|
|
heroData.decimals = priceData.decimals || 8
|
|
heroData.priceDiscount = priceData.discount_price
|
|
heroData.currency = priceData.name
|
|
heroData.coinAddress = priceData.contract_address
|
|
}
|
|
this.heroDatas.push(heroData)
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
#nft_section {
|
|
background-image: url('../../assets/main/p3/bg_p3.png');
|
|
position: relative;
|
|
background-repeat: no-repeat;
|
|
background-size: cover;
|
|
}
|
|
.info {
|
|
position: absolute;
|
|
top: 100px;
|
|
left: 0;
|
|
right: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
color: white;
|
|
.count-down {
|
|
display: flex;
|
|
flex-direction: row;
|
|
color: #F9D41D;
|
|
font-family: 'title',serif;
|
|
height: 50px;
|
|
align-items: end;
|
|
.time {
|
|
font-size: 50px;
|
|
}
|
|
.title{
|
|
font-size: 30px;
|
|
margin-bottom: 7px;
|
|
margin-left: 20px;
|
|
}
|
|
}
|
|
.text{
|
|
font-family: "zitic",serif;
|
|
font-size: 20px;
|
|
margin-top: 20px;
|
|
white-space: pre-wrap;
|
|
}
|
|
}
|
|
.count-label {
|
|
font-family: 'title',serif;
|
|
font-size: 50px;
|
|
color: #21f730;
|
|
position: absolute;
|
|
left:0;
|
|
right: 0;
|
|
bottom: 76px;
|
|
margin: auto;
|
|
width: 200px;
|
|
text-align: center;
|
|
}
|
|
|
|
@media (max-width: 767px) {
|
|
.title img{
|
|
width: 281px;
|
|
top: 5vh;
|
|
}
|
|
.card-scroller {
|
|
height: 70vh;
|
|
font-size: 11px;
|
|
}
|
|
.title .text{
|
|
font-size: 14px;
|
|
}
|
|
}
|
|
@media (max-width: 415px) {
|
|
.card-scroller {
|
|
height: 70vh;
|
|
font-size: 10px;
|
|
bottom: 30px;
|
|
}
|
|
.count-label {
|
|
bottom: 10px;
|
|
}
|
|
.info {
|
|
top: 40px;
|
|
padding: 0 8px;
|
|
.text{
|
|
font-size: 15px;
|
|
}
|
|
.count-down{
|
|
.time {
|
|
font-size: 30px;
|
|
}
|
|
.title {
|
|
font-size: 20px;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@media (min-width: 321px) and (max-width: 375px) {
|
|
.info {
|
|
top: 40px;
|
|
padding: 0 8px;
|
|
.text{
|
|
font-size: 12px;
|
|
margin-top: 1px;
|
|
}
|
|
.count-down{
|
|
.time {
|
|
font-size: 30px;
|
|
}
|
|
.title {
|
|
font-size: 20px;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.order-status {
|
|
transform: scale(0.3);
|
|
width: 220px;
|
|
height: 220px;
|
|
border-radius: 110px;
|
|
background: white;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
transform-origin: top;
|
|
position: fixed;
|
|
left: 100px;
|
|
top: 100px;
|
|
}
|
|
|
|
</style>
|