434 lines
10 KiB
Vue
434 lines
10 KiB
Vue
<template>
|
|
<div>
|
|
<top-menu class="desk-top" :current-tab="currentTab"></top-menu>
|
|
<section class="mynft">
|
|
<div class="container">
|
|
<div class="wrapper">
|
|
<nft-type-bar :select-idx="nftType" @nft-type-changed="onNftTypeClicked" class="left-bar"></nft-type-bar>
|
|
<sort-select
|
|
:filters="filters"
|
|
:selected-index="nftState"
|
|
@filter-change="filterChange"
|
|
></sort-select>
|
|
</div>
|
|
<nft-list :nft-datas="nftList" v-if="nftList.length > 0" @activate-clicked="onActivateClick"></nft-list>
|
|
<result-no
|
|
v-if="nftList.length === 0"
|
|
title="No Record."
|
|
desc=""
|
|
></result-no>
|
|
<pagination
|
|
v-if="totalPage>1"
|
|
:total="totalPage"
|
|
:current="currentPage"
|
|
@to-page="toPage"
|
|
class="page-comp"
|
|
></pagination>
|
|
</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>
|
|
<base-footer :auto-size="true">></base-footer>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import { Component, Vue, Watch } from 'vue-property-decorator'
|
|
import SearchPanel from '@/components/market/SearchPanel.vue'
|
|
import Pagination from '@/components/market/Pagination.vue'
|
|
import SearchResult from '@/components/market/SearchResult.vue'
|
|
import TopMenu from '@/components/market/TopMenu.vue'
|
|
import NftList from '@/components/market/NftList.vue'
|
|
import { getNftList } from '@/api/Mall'
|
|
import { AppModule } from '@/store/modules/app'
|
|
import BaseFooter from '@/components/layout/BaseFooter.vue'
|
|
import NftTypeBar from '@/components/market/NftTypeBar.vue'
|
|
import SortSelect from '@/components/market/SortSelect.vue'
|
|
import ResultNo from '@/components/market/ResultNo.vue'
|
|
import { INftData, parseNftData } from '@/types/Nft'
|
|
import TimeLoader from '@/components/main/TimeLoader.vue'
|
|
import { preActivateNFT, preOpenBox, queryActivateNFTState, queryBoxOpenState } from '@/api/Market'
|
|
import { createModal, ZModal } from '@/utils/modal.util'
|
|
import RewardModal from '@/components/core/RewardModal.vue'
|
|
import { ElLoadingComponent } from 'element-ui/types/loading'
|
|
import { UserModule } from '@/store/modules/user'
|
|
import ChainManager from '@/chain/ChainManager'
|
|
import { CONTRACT_ADDRESS } from '@/configs/config_chain'
|
|
|
|
const MYSTERY_BOX_CACHE = 'activate_nft_cache'
|
|
|
|
@Component({
|
|
components: {
|
|
TimeLoader,
|
|
ResultNo,
|
|
SortSelect,
|
|
NftTypeBar,
|
|
BaseFooter,
|
|
NftList,
|
|
SearchResult,
|
|
SearchPanel,
|
|
Pagination,
|
|
TopMenu
|
|
}
|
|
})
|
|
export default class MyNft extends Vue {
|
|
mobileFilterShow = false
|
|
currentTab = 'mynft'
|
|
nftList: INftData[] = []
|
|
nftType = 1
|
|
nftState = 0
|
|
showOrderStatus = false
|
|
private filters = ['All Items', 'Normal', 'Selling', 'Renting']
|
|
private totalPage = 1
|
|
private currentPage = 1
|
|
private dataCache: Map<any, INftData[]> = new Map()
|
|
|
|
private isProcess = false
|
|
private rewardModal: ZModal
|
|
orderTimer: any = null
|
|
loadingInstance: ElLoadingComponent
|
|
chainManager = new ChainManager()
|
|
|
|
get accountId() {
|
|
return AppModule.accountId
|
|
}
|
|
|
|
get isLogin() {
|
|
return !!UserModule.token && !!AppModule.step
|
|
}
|
|
|
|
get boxProxyAddress() {
|
|
return CONTRACT_ADDRESS[AppModule.chainId].nftProxy
|
|
}
|
|
|
|
onNftTypeClicked(typeId: number) {
|
|
console.log('nft type clicked: ', typeId)
|
|
if (this.nftType !== typeId) {
|
|
this.nftType = typeId
|
|
this.fetchDatas(1)
|
|
}
|
|
}
|
|
|
|
filterChange(id: number) {
|
|
console.log('filter change: ', id)
|
|
if (this.nftState !== id) {
|
|
this.nftState = id
|
|
this.fetchDatas(1)
|
|
}
|
|
}
|
|
|
|
@Watch('isLogin')
|
|
private accountChange() {
|
|
console.log('account change: ', AppModule.accountId)
|
|
if (this.accountId) {
|
|
this.fetchDatas(this.currentPage)
|
|
this.checkOrderHistory()
|
|
}
|
|
}
|
|
|
|
showFilter(val: boolean) {
|
|
this.mobileFilterShow = val
|
|
}
|
|
|
|
async fetchDatas(pageNo: number) {
|
|
if (!AppModule.accountId) {
|
|
return
|
|
}
|
|
const reqData: any = {
|
|
account: AppModule.accountId,
|
|
page: pageNo,
|
|
type: this.nftType
|
|
}
|
|
if (this.nftState > 0) {
|
|
reqData.state = this.nftState - 1
|
|
}
|
|
if (this.dataCache.has(reqData)) {
|
|
this.nftList = this.dataCache.get(reqData)!
|
|
} else {
|
|
this.nftList.length = 0
|
|
}
|
|
const res: any = await getNftList(reqData)
|
|
if (res.nfts) {
|
|
this.nftList.length = 0
|
|
for (const data of res.nfts) {
|
|
const nftData = parseNftData(data)
|
|
this.nftList.push(nftData)
|
|
}
|
|
this.dataCache.set(reqData, this.nftList)
|
|
}
|
|
if (res.page) {
|
|
const page = res.page
|
|
this.totalPage = page.total_pages || 1
|
|
this.currentPage = page.current_page || 1
|
|
}
|
|
console.log(res)
|
|
}
|
|
|
|
toPage(pageNo: number) {
|
|
console.log('to page: ', pageNo)
|
|
this.fetchDatas(pageNo)
|
|
}
|
|
|
|
showLoading() {
|
|
this.loadingInstance = this.$loading({ background: 'rgba(0, 0, 0, 0.8)' })
|
|
}
|
|
|
|
hideLoading() {
|
|
this.loadingInstance?.close()
|
|
}
|
|
|
|
async onActivateClick({ tokenId, type }: {tokenId: string, type: number}) {
|
|
console.log('onActivateClick: ', tokenId, type)
|
|
if (!this.isLogin) {
|
|
this.$message({
|
|
message: 'You should login first',
|
|
type: 'warning',
|
|
duration: 5 * 1000
|
|
})
|
|
return
|
|
}
|
|
if (this.isProcess) {
|
|
this.$message({
|
|
message: 'Box open in process',
|
|
type: 'warning',
|
|
duration: 5 * 1000
|
|
})
|
|
}
|
|
this.isProcess = true
|
|
const reqData = {
|
|
token_id: tokenId
|
|
}
|
|
this.showLoading()
|
|
let nonce, signature, nftNew
|
|
try {
|
|
const res: any = await preActivateNFT(reqData)
|
|
nonce = res.nonce
|
|
signature = res.signature
|
|
nftNew = res.new_token_id
|
|
} catch (err) {
|
|
console.log('pre activate err', err)
|
|
this.$message.error('activate nft with pre request error')
|
|
this.hideLoading()
|
|
this.isProcess = false
|
|
return false
|
|
}
|
|
try {
|
|
const result = await this.chainManager.activateOneNft(
|
|
this.boxProxyAddress, tokenId, nftNew, type, nonce, signature)
|
|
console.log('activate nft result: ', result)
|
|
const stateData = { token_id: tokenId, txhash: result.transactionHash }
|
|
localStorage.setItem(MYSTERY_BOX_CACHE, JSON.stringify(stateData))
|
|
this.hideLoading()
|
|
this.beginTraceOrderStatus(stateData)
|
|
} catch (err) {
|
|
console.log(err)
|
|
this.hideLoading()
|
|
this.isProcess = false
|
|
this.$message.error('activate nft with error: ' + err)
|
|
}
|
|
}
|
|
|
|
checkOrderHistory() {
|
|
const historyOrderId = localStorage.getItem(MYSTERY_BOX_CACHE)
|
|
if (historyOrderId && this.accountId) {
|
|
try {
|
|
const data = JSON.parse(historyOrderId)
|
|
this.beginTraceOrderStatus(data)
|
|
} catch (err) {
|
|
localStorage.removeItem(MYSTERY_BOX_CACHE)
|
|
}
|
|
}
|
|
}
|
|
|
|
beginTraceOrderStatus(cacheData: any) {
|
|
this.showOrderStatus = true
|
|
this.isProcess = true
|
|
this.loadingInstance?.close()
|
|
this.orderTimer = setInterval(() => {
|
|
this.getOrderStatus(cacheData)
|
|
}, 1000)
|
|
}
|
|
|
|
async getOrderStatus(data: any) {
|
|
console.log('getOrderStatus: ', data)
|
|
try {
|
|
const res: any = await queryActivateNFTState(data)
|
|
if (res.state === 1) {
|
|
// success
|
|
this.onOpenSuccess(res.nft)
|
|
}
|
|
} catch (err) {
|
|
console.log('query order status error', err)
|
|
}
|
|
}
|
|
|
|
resetTmpOrderId() {
|
|
if (this.orderTimer !== null) {
|
|
clearInterval(this.orderTimer)
|
|
this.orderTimer = null
|
|
}
|
|
this.isProcess = false
|
|
localStorage.removeItem(MYSTERY_BOX_CACHE)
|
|
this.loadingInstance?.close()
|
|
}
|
|
|
|
async onOpenSuccess(data: any) {
|
|
console.log('open success')
|
|
if (!this.isProcess) {
|
|
return
|
|
}
|
|
this.resetTmpOrderId()
|
|
this.showOrderStatus = false
|
|
const cardList: INftData[] = []
|
|
const nftData = parseNftData(data)
|
|
cardList.push(nftData)
|
|
this.showRewardModal({
|
|
title: 'NFT activate Success',
|
|
cardList
|
|
})
|
|
this.fetchDatas(this.currentPage)
|
|
// this.$alert('Congratulations', 'Open Success', { type: 'success', confirmButtonText: 'OK' })
|
|
}
|
|
|
|
showRewardModal(data: any) {
|
|
console.log('show reward modal with data: ', data)
|
|
this.rewardModal = createModal(RewardModal, data)
|
|
this.rewardModal.show()
|
|
}
|
|
}
|
|
</script>
|
|
<style lang="scss" scoped>
|
|
@import '../../scss/breakpoints.scss';
|
|
.mynft {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
.container {
|
|
display: flex;
|
|
flex-direction: column;
|
|
width: 1440px;
|
|
max-width: 100%;
|
|
box-sizing: border-box;
|
|
.wrapper{
|
|
display: flex;
|
|
flex-direction: row;
|
|
justify-content: space-between;
|
|
align-items: flex-end;
|
|
padding: 0 4%;
|
|
.left-bar{
|
|
width: 40%;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.mobile-top {
|
|
display: none;
|
|
}
|
|
.page-comp{
|
|
width: 100%;
|
|
}
|
|
.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;
|
|
}
|
|
@include media('<desktop') {
|
|
.container {
|
|
flex-direction: column;
|
|
.wrapper{
|
|
margin-top: 80px;
|
|
margin-bottom: -76px;
|
|
padding: 0;
|
|
.left-bar{
|
|
flex-grow: 1;
|
|
width: 50%!important;
|
|
padding: 0 15px;
|
|
}
|
|
}
|
|
}
|
|
.searchPanel {
|
|
width: 100%;
|
|
}
|
|
.filterTablet {
|
|
padding-top: 40px;
|
|
width: 100%;
|
|
-webkit-transition: all 0.3s;
|
|
transition: all 0.3s;
|
|
height: auto;
|
|
}
|
|
.filterTablet.collapsed {
|
|
padding-top: 0;
|
|
opacity: 0;
|
|
height: 0;
|
|
z-index: -1;
|
|
overflow: hidden;
|
|
}
|
|
.searchResult {
|
|
padding: 2.5em 4em;
|
|
}
|
|
.searchResult .wrapper .btnFilter {
|
|
display: -webkit-box;
|
|
display: -ms-flexbox;
|
|
display: flex;
|
|
text-transform: uppercase;
|
|
}
|
|
}
|
|
|
|
@media (min-width: 1024px) and (max-width: 1439px) {
|
|
.mynft {
|
|
font-size: 11px;
|
|
}
|
|
.mynft .container {
|
|
width: 1024px;
|
|
max-width: 100%;
|
|
}
|
|
}
|
|
|
|
@media (min-width: 768px) and (max-width: 1023px) {
|
|
.mynft {
|
|
font-size: 20px;
|
|
}
|
|
.container {
|
|
width: 768px;
|
|
}
|
|
}
|
|
|
|
@media (max-width: 767px) {
|
|
.mynft {
|
|
font-size: 11px;
|
|
}
|
|
}
|
|
|
|
@media (max-width: 767px) and (max-width: 320px) {
|
|
.mynft {
|
|
font-size: 9px;
|
|
}
|
|
}
|
|
|
|
@media (max-width: 767px) {
|
|
.container {
|
|
width: 375px;
|
|
}
|
|
.searchResult {
|
|
padding: 26px 20px;
|
|
}
|
|
|
|
.show{
|
|
display: flex!important;
|
|
}
|
|
}
|
|
</style>
|