1302 lines
40 KiB
Vue
1302 lines
40 KiB
Vue
<template>
|
|
<div class="detail">
|
|
<div class="bg-content">
|
|
<div class="detail-bg"></div>
|
|
<div v-if="detailData" class="detail-content">
|
|
<div class="content">
|
|
<div class="top-left">
|
|
<div class="top-left-img">
|
|
<ImgCard v-if="detailData.nft.token_id" :nftData="detailData.nft" />
|
|
<ImgCardTow v-else class="mint-hero" :nftData="detailData.nft" />
|
|
</div>
|
|
<div v-if="detailData.nft.type == 1 || detailData.nft.type == 12" class="btm-left">
|
|
<h2>Property</h2>
|
|
<div class="btm-detail">
|
|
<li>
|
|
<div>
|
|
<h5>Tier</h5>
|
|
<p>{{ nftAbilities['quality'] }}</p>
|
|
</div>
|
|
</li>
|
|
<li>
|
|
<div>
|
|
<h5>Active Days</h5>
|
|
<p>{{ nftAbilities['max_mining_days'] }}</p>
|
|
</div>
|
|
</li>
|
|
<li>
|
|
<div>
|
|
<h5>Wealth Value</h5>
|
|
<p>{{ parseInt(nftAbilities['wealth']) }}</p>
|
|
</div>
|
|
</li>
|
|
<li>
|
|
<div>
|
|
<h5>Luck Value</h5>
|
|
<p>{{ parseInt(nftAbilities['lucky']) }}</p>
|
|
</div>
|
|
</li>
|
|
<li>
|
|
<div>
|
|
<h5>HP</h5>
|
|
<p>{{ parseInt(nftAbilities['hp']) }}</p>
|
|
</div>
|
|
</li>
|
|
<li>
|
|
<div>
|
|
<h5>Attack</h5>
|
|
<p>{{ parseInt(nftAbilities['atk']) }}</p>
|
|
</div>
|
|
</li>
|
|
<li>
|
|
<div>
|
|
<h5>Defense</h5>
|
|
<p>{{ Number(nftAbilities['def']).toFixed(2) }}%</p>
|
|
</div>
|
|
</li>
|
|
<li>
|
|
<div>
|
|
<h5>Block Rate</h5>
|
|
<p>{{ Number(nftAbilities['block']).toFixed(2) }}%</p>
|
|
</div>
|
|
</li>
|
|
<li>
|
|
<div>
|
|
<h5>Crit Rate</h5>
|
|
<p>{{ Number(nftAbilities['crit']).toFixed(2) }}%</p>
|
|
</div>
|
|
</li>
|
|
<li v-if="nftAbilities['chip_slots']">
|
|
<div>
|
|
<h5>Chip Slots</h5>
|
|
<p>{{ nftAbilities['chip_slots'] }}</p>
|
|
</div>
|
|
</li>
|
|
<li v-if="nftAbilities['combat_ability_l']">
|
|
<div>
|
|
<h5 class="min-size">Combat Ability I</h5>
|
|
<p>{{ nftAbilities['combat_ability_l'] }}</p>
|
|
</div>
|
|
</li>
|
|
<li v-if="nftAbilities['combat_ability_2']">
|
|
<div>
|
|
<h5 class="min-size">Combat Ability II</h5>
|
|
<p>{{ nftAbilities['combat_ability_2'] }}</p>
|
|
</div>
|
|
</li>
|
|
</div>
|
|
</div>
|
|
<div
|
|
v-else-if="detailData.nft.item_id == 10017 || detailData.nft.item_id == 10018"
|
|
class="btm-left"
|
|
>
|
|
<h2>Property</h2>
|
|
<div class="gold-content">
|
|
<div class="left">
|
|
<h4>Gold Amount</h4>
|
|
<p>{{ detailData.nft.detail.gold_coins }}</p>
|
|
</div>
|
|
<div class="right">
|
|
<div class="right-img">
|
|
<img src="@/assets/img/marketplace/Icon_!.png" alt />
|
|
</div>
|
|
<div
|
|
class="right-tips"
|
|
>A Gold Card is equivalent to 100,000 Gold. Once redeemed, 100,000 Gold will be credited to your Counter Fire game account.</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="top-right">
|
|
<h2 v-if="detailData.nft.type == 13">Founder's Tag</h2>
|
|
<h2 v-else>{{ detailData.nft.name }}</h2>
|
|
<div class="top-right-owner">
|
|
<div>Owner:</div>
|
|
<div
|
|
class="address"
|
|
>{{ detailData.nft.owner_address ? detailData.nft.owner_address : myAddress }}</div>
|
|
</div>
|
|
<div class="top-right-price" v-if="detailData.event">
|
|
<li>
|
|
<div>Price</div>
|
|
<div class="time">
|
|
<img src="@/assets/img/marketplace/time.png" alt="img" />
|
|
<!-- <div>Time remaining: <StarTimer :endAt="detailData.event.data.end_at" /></div> -->
|
|
<div>(UTC)End Time: {{detailData.event.data.end_at}}</div>
|
|
</div>
|
|
</li>
|
|
<li>
|
|
<div class="price">
|
|
<span class="bold">{{ price }} </span>
|
|
<img :src="icon" alt="ICON" />
|
|
<span>( $ {{ usd }} )</span>
|
|
</div>
|
|
</li>
|
|
</div>
|
|
<div
|
|
class="back-time"
|
|
v-if="FOUNDER_ADDRESS.toLowerCase() == detailData.nft.owner_address.toLowerCase() || LOCKER_ADDRESS.toLowerCase() == detailData.nft.owner_address.toLowerCase()"
|
|
>
|
|
<div>
|
|
<img src="@/assets/img/marketplace/time.png" alt />
|
|
<span>
|
|
Time remaining :
|
|
{{ timeStaking(detailData.nft.last_lock_time)[0] }}d:
|
|
{{ timeStaking(detailData.nft.last_lock_time)[1] }}h:
|
|
{{ timeStaking(detailData.nft.last_lock_time)[2] }}m
|
|
</span>
|
|
</div>
|
|
<div>
|
|
<span
|
|
class="expected"
|
|
v-if="detailData.nft.type == 1 || detailData.nft.type == 12"
|
|
>+{{contribution(detailData.nft.detail.quality, detailData.nft.type)}}/d</span>
|
|
<span
|
|
class="expected"
|
|
v-if="detailData.nft.type == 13"
|
|
>+{{contribution(detailData.nft.quality, detailData.nft.type)}}/d</span>
|
|
<img src="@/assets/img/marketplace/totalContribution.png" alt />
|
|
</div>
|
|
</div>
|
|
<div class="top-right-btns">
|
|
<div
|
|
v-if="FOUNDER_ADDRESS.toLowerCase() == detailData.nft.owner_address.toLowerCase() || LOCKER_ADDRESS.toLowerCase() == detailData.nft.owner_address.toLowerCase()"
|
|
>
|
|
<div class="cancel" v-if="detailData.nft?.status == 1">
|
|
<span>Loading</span>
|
|
</div>
|
|
<div class="cancel" v-else>
|
|
<span @click="localWalletStore.token == '' ? cardLogin() : backStaking()">Withdraw</span>
|
|
</div>
|
|
</div>
|
|
<div
|
|
v-if="(detailData.nft.type == 1 && !detailData.nft.contract_address) && LOCKER_ADDRESS.toLowerCase() != detailData.nft.owner_address.toLowerCase()"
|
|
>
|
|
<div class="mint" @click="mintHero" v-if="detailData.nft.on_lock == '1'">Mint</div>
|
|
<div class="unLock" v-else>Mint</div>
|
|
</div>
|
|
<div
|
|
v-if="(detailData.nft.type == 1 && !detailData.nft.contract_address) && LOCKER_ADDRESS.toLowerCase() != detailData.nft.owner_address.toLowerCase()"
|
|
>
|
|
<div class="lock" v-if="detailData.nft.on_lock == '0'">
|
|
<img src="@/assets/img/marketplace/Icon_!.png" alt="">
|
|
<p>You need to lock in the game before Minting</p>
|
|
</div>
|
|
</div>
|
|
<!--
|
|
1、添加购物车
|
|
2、移除购物车
|
|
3、购买
|
|
4、
|
|
-->
|
|
|
|
<div v-if="myAddress != detailData.nft.owner_address">
|
|
<div
|
|
v-if="detailData.event != null"
|
|
class="buy"
|
|
@click="localWalletStore.token == '' ? cardLogin() : buyNow()"
|
|
>Buy Now</div>
|
|
<div
|
|
class="add"
|
|
v-if="detailData.event != null && detailData.in_shopcart == 0"
|
|
@click="localWalletStore.token == '' ? cardLogin() : addCart()"
|
|
>
|
|
<span>Add to cart</span>
|
|
<img src="@/assets/img/marketplace/Add_shopping_cart.png" alt />
|
|
</div>
|
|
<div
|
|
class="remove"
|
|
v-if="detailData.in_shopcart == 1"
|
|
@click="localWalletStore.token == '' ? cardLogin() : clearCart()"
|
|
>
|
|
<span>Remove from cart</span>
|
|
<img src="@/assets/img/marketplace/Move_out.png" alt />
|
|
</div>
|
|
</div>
|
|
<!--
|
|
1、上架
|
|
2、下架
|
|
3、使用
|
|
-->
|
|
<div v-if="myAddress == detailData.nft.owner_address && detailData.nft?.status != 1">
|
|
<div
|
|
class="sell"
|
|
@click="beginSell"
|
|
v-if="detailData.nft.on_sale == 0 && detailData.nft.type != 13"
|
|
>List</div>
|
|
<div class="cancel" @click="cancelSell" v-if="detailData.nft.on_sale == 1">Delist</div>
|
|
<div
|
|
class="redeem"
|
|
v-if="detailData.nft.on_sale == 0 && (detailData.nft.type == 1 || detailData.nft.type == 12)"
|
|
@click="lockToGame('convert')"
|
|
>
|
|
<span>Stake</span>
|
|
</div>
|
|
<div class="redeem" v-else-if="detailData.nft.type == 13">
|
|
<span v-if="detailData.nft?.status == 1" @click="lockToGame('founder')">Loading</span>
|
|
<span v-else @click="lockToGame('founder')">Stake</span>
|
|
</div>
|
|
<div
|
|
class="redeem"
|
|
@click="lockToGame('redeem')"
|
|
v-if="detailData.nft.on_sale == 0 && detailData.nft.type == 11"
|
|
>Redeem</div>
|
|
</div>
|
|
<!-- <div v-else-if="detailData.nft?.status == 1">
|
|
<div class="cancel">
|
|
<span>Loading</span>
|
|
</div>
|
|
</div>-->
|
|
</div>
|
|
<div class="info">
|
|
<h2>Info</h2>
|
|
<li>
|
|
<div>Contract address</div>
|
|
<div class="contract-address">
|
|
<div>{{ detailData.nft.contract_address}}</div>
|
|
<span v-if="detailData.nft.type != 13">
|
|
<a
|
|
:href="contractBlankUrl"
|
|
target="_blank"
|
|
>{{ sliceAddress(detailData.nft.contract_address) }}</a>
|
|
</span>
|
|
<span v-else>
|
|
<a
|
|
:href="founderBlankUrl"
|
|
target="_blank"
|
|
>{{ sliceAddress(detailData.nft.contract_address) }}</a>
|
|
</span>
|
|
</div>
|
|
</li>
|
|
<li>
|
|
<div>Token ID</div>
|
|
<div>
|
|
<a
|
|
:href="contractTokenUrl"
|
|
target="_blank"
|
|
>{{ detailData.nft.token_id ? detailData.nft.token_id : '-' }}</a>
|
|
</div>
|
|
</li>
|
|
<li>
|
|
<div>Blockchain</div>
|
|
<div>{{ detailData.nft.token_id ? 'lmmutascan' : '-' }}</div>
|
|
</li>
|
|
<li>
|
|
<div>Metadata</div>
|
|
<div v-if="detailData.nft.type != 13">
|
|
<a
|
|
:href="detailData.nft.meta_url"
|
|
target="_blank"
|
|
>{{ sliceAddress(detailData.nft.meta_url) }}</a>
|
|
</div>
|
|
<div v-else>
|
|
<a
|
|
:href="founderBlankUrl"
|
|
target="_blank"
|
|
>{{ sliceAddress(detailData.nft.meta_url) }}</a>
|
|
</div>
|
|
</li>
|
|
<li>
|
|
<div>Royalties</div>
|
|
<div>{{ detailData.nft.token_id ? '2%' : '-' }}</div>
|
|
</li>
|
|
<li v-if="detailData.nft.type == 13">
|
|
<div>Rarity</div>
|
|
<div v-if="detailData.nft.quality == 1">Common</div>
|
|
<div v-else-if="detailData.nft.quality == 2">Rare</div>
|
|
<div v-else-if="detailData.nft.quality == 3">Legendary</div>
|
|
</li>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<Footer />
|
|
<BuyDialog
|
|
:buyDialogVisible="buyDialogVisible"
|
|
:buyDataArr="buyDataArr"
|
|
@handleClose="BuyHandleClose"
|
|
/>
|
|
<SellDialog
|
|
v-if="detailData"
|
|
:sellDialogVisible="sellDialogVisible"
|
|
:floorPrice="floorPrice"
|
|
:sellDataArr="detailData.nft"
|
|
@handleClose="sellHandleClose"
|
|
/>
|
|
<LoadingDialog :loadingDialogVisible="loadingDialogVisible" />
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import {ref, toRefs, toRaw, onMounted, inject} from "vue";
|
|
const message = inject("$message");
|
|
import {useRouter, useRoute} from "vue-router";
|
|
import BuyDialog from "@/components/Dialogs/buyDialog.vue";
|
|
import ConfirmDialog from "@/components/Dialogs/confirmDialog.vue";
|
|
import LoadingDialog from "@/components/Dialogs/loadingDialog.vue";
|
|
import ImgCard from "@/components/common/imgCard.vue";
|
|
import ImgCardTow from "@/components/assets/imgs.vue";
|
|
import StarTimer from "@/components/common/starTimer.vue";
|
|
import SellDialog from "@/components/Dialogs/sellDialog.vue";
|
|
import Footer from "@/components/common/footer.vue";
|
|
import {nftDetail, apiGetPrice, apiTxHash} from "@/utils/marketplace";
|
|
import {priceCalculated} from "@/configs/priceCalculate.js";
|
|
import {BlockChain} from "@/components/chain/BlockChain";
|
|
import {walletStore} from "@/store/wallet";
|
|
import {useMarketplaceStore} from "@/store/marketplace";
|
|
import LazyLoadImg from "@/components/lazyloadimg";
|
|
import {formatPrice} from "@/components/chain/utils";
|
|
import {createModal} from "@/utils/model.util";
|
|
import {contribution, timeStaking} from "@/configs/priceCalculate";
|
|
const router = useRouter();
|
|
const route = useRoute();
|
|
const localWalletStore = walletStore();
|
|
const marketplaceList = useMarketplaceStore();
|
|
const props = defineProps({
|
|
address: String,
|
|
tokenid: String,
|
|
});
|
|
import placeholderImg from "@/assets/img/marketplace/GenesisHeroes_NFT.png";
|
|
const detailData = ref(null);
|
|
const assetsDetailData = ref(null);
|
|
const myAddress = localWalletStore.address;
|
|
const contractBlankUrl = ref();
|
|
const founderBlankUrl = ref();
|
|
const contractTokenUrl = ref();
|
|
const nftAbilities = ref();
|
|
const icon = ref("");
|
|
const usd = ref("");
|
|
const price = ref("");
|
|
const loadingDialogVisible = ref(false);
|
|
const LOCKER_ADDRESS = ref(import.meta.env.VUE_APP_LOCKER_ADDRESS);
|
|
const FOUNDER_ADDRESS = ref(import.meta.env.VUE_APP_FOUNDER_ADDRESS);
|
|
|
|
// 登录
|
|
const cardLogin = async () => {
|
|
await new BlockChain().connect();
|
|
};
|
|
|
|
// 购买
|
|
const buyDialogVisible = ref(false);
|
|
const buyDataArr = ref([]);
|
|
const buyNow = async () => {
|
|
detailData.value["icon"] = icon.value;
|
|
detailData.value["tokenAmount"] = price.value;
|
|
buyDataArr.value = [];
|
|
buyDataArr.value.push(detailData.value);
|
|
buyDialogVisible.value = true;
|
|
return;
|
|
const buyResult = await createModal(BuyDialog, {
|
|
buyDataArr: buyDataArr.value,
|
|
}).show();
|
|
console.log(buyResult.errcode);
|
|
if (buyResult.errcode == 0) {
|
|
message.success("buy success");
|
|
} else if (buyResult.errcode == 1) {
|
|
if (buyResult.err.message.indexOf() > -1) {
|
|
message.error("User rejected the request");
|
|
} else {
|
|
message.error("buy fail");
|
|
}
|
|
}
|
|
};
|
|
const BuyHandleClose = () => {
|
|
buyDialogVisible.value = false;
|
|
};
|
|
|
|
// 添加购物车
|
|
const addCart = async () => {
|
|
const data = {
|
|
net_id: import.meta.env.VUE_APP_NET_ID,
|
|
tokens: [
|
|
{
|
|
token_id: detailData.value.nft.token_id,
|
|
contract_address: detailData.value.nft.contract_address,
|
|
},
|
|
],
|
|
};
|
|
try {
|
|
const {errcode, errmsg} = await marketplaceList.addCartListState(data);
|
|
// console.log(errcode, errmsg)
|
|
if (errcode == 0) {
|
|
message.success("success! Add from cart");
|
|
marketplaceList.getCartList = await marketplaceList.getCartListState();
|
|
getDetail();
|
|
}
|
|
} catch (e) {
|
|
message.error("fail! Add from cart");
|
|
}
|
|
};
|
|
|
|
// 移除购物车
|
|
const clearCart = async () => {
|
|
// TODO:
|
|
const data = {
|
|
net_id: import.meta.env.VUE_APP_NET_ID,
|
|
tokens: [
|
|
{
|
|
token_id: detailData.value.nft.token_id,
|
|
contract_address: detailData.value.nft.contract_address,
|
|
},
|
|
],
|
|
};
|
|
try {
|
|
const {errcode, errmsg} = await marketplaceList.delCartListState(data);
|
|
if (errcode == 0) {
|
|
message.success("success! Remove from cart");
|
|
marketplaceList.getCartList = await marketplaceList.getCartListState();
|
|
getDetail();
|
|
}
|
|
} catch (e) {
|
|
// console.log(e)
|
|
}
|
|
};
|
|
|
|
// 下链使用
|
|
const lockToGame = async (type) => {
|
|
if (type == "founder") {
|
|
const confirmResult = await createModal(ConfirmDialog, {
|
|
title: "",
|
|
message: `Are you sure you want to stake?`,
|
|
}).show();
|
|
if (confirmResult.errcode == 0) {
|
|
loadingDialogVisible.value = true;
|
|
unlockMainConfirm();
|
|
}
|
|
} else if (type == "convert") {
|
|
const confirmResult = await createModal(ConfirmDialog, {
|
|
title: "",
|
|
message: "Are you sure you want to stake?",
|
|
}).show();
|
|
if (confirmResult.errcode == 0) {
|
|
loadingDialogVisible.value = true;
|
|
lockToGameConfirm();
|
|
}
|
|
} else if (type == "redeem") {
|
|
const confirmResult = await createModal(ConfirmDialog, {
|
|
title: "",
|
|
message: `Redeem ${detailData.value.nft.detail.gold_coins} Gold to your game account. Do you wish to proceed?`,
|
|
// message: 'Are you sure you want to stake?'
|
|
}).show();
|
|
if (confirmResult.errcode == 0) {
|
|
loadingDialogVisible.value = true;
|
|
lockToGameConfirm();
|
|
}
|
|
}
|
|
};
|
|
const lockToGameConfirm = async () => {
|
|
try {
|
|
const bc = new BlockChain();
|
|
let res = await bc.locker.lock(detailData.value.nft.contract_address, [detailData.value.nft.token_id]);
|
|
// message.success('lockToGame success')
|
|
detailData.value.nft["status"] = 1;
|
|
if (detailData.value.nft.type == 11) {
|
|
const confirmResult = await createModal(ConfirmDialog, {
|
|
title: "",
|
|
noBtnTitle: "",
|
|
message: "Redeem is complete. Please refresh the page in 3 to 4 minutes to view the updated status.",
|
|
}).show();
|
|
} else {
|
|
const confirmResult = await createModal(ConfirmDialog, {
|
|
title: "",
|
|
noBtnTitle: "",
|
|
message: "Staking is complete. Please refresh the page in 3 to 4 minutes to view the updated status.",
|
|
}).show();
|
|
}
|
|
loadingDialogVisible.value = false;
|
|
if (res) {
|
|
try {
|
|
const {confirmed} = await apiTxHash(detailData.value.nft.net_id, res);
|
|
let timer = setInterval(async () => {
|
|
// message.success('Unstake success.')
|
|
if (confirmed == 1) {
|
|
detailData.value.nft["status"] = "";
|
|
router.go(-1);
|
|
clearInterval(timer);
|
|
}
|
|
}, 2000);
|
|
} catch (e) {
|
|
console.log(e);
|
|
}
|
|
}
|
|
} catch (e) {
|
|
console.log(e.message);
|
|
if (e.message.indexOf("rejected") > -1) {
|
|
message.error("User rejected the request");
|
|
} else {
|
|
message.error("lockToGame fail.");
|
|
}
|
|
loadingDialogVisible.value = false;
|
|
}
|
|
};
|
|
const unlockMainConfirm = async () => {
|
|
try {
|
|
const bc = new BlockChain();
|
|
let res = await bc.locker.lockMain(detailData.value.nft.contract_address, [detailData.value.nft.token_id]);
|
|
detailData.value.nft["status"] = 1;
|
|
const confirmResult = await createModal(ConfirmDialog, {
|
|
title: "",
|
|
noBtnTitle: "",
|
|
message: "Staking is complete. Please refresh the page in 3 to 4 minutes to view the updated status.",
|
|
}).show();
|
|
loadingDialogVisible.value = false;
|
|
if (res) {
|
|
try {
|
|
const {confirmed} = await apiTxHash(detailData.value.nft.net_id, res);
|
|
let timer = setInterval(async () => {
|
|
// message.success('Unstake success.')
|
|
if (confirmed == 1) {
|
|
detailData.value.nft["status"] = "";
|
|
router.go(-1);
|
|
clearInterval(timer);
|
|
}
|
|
}, 2000);
|
|
} catch (e) {
|
|
console.log(e);
|
|
}
|
|
}
|
|
} catch (e) {
|
|
if (e.message.indexOf("rejected") > -1) {
|
|
message.error("User rejected the request");
|
|
} else {
|
|
message.error("lockToGame fail.");
|
|
}
|
|
loadingDialogVisible.value = false;
|
|
}
|
|
};
|
|
|
|
// 赎回
|
|
const backStaking = async () => {
|
|
if (marketplaceList.userGold < 0) {
|
|
const confirmResult = await createModal(ConfirmDialog, {
|
|
title: "",
|
|
message: "Unstake Failed - Negative in-game gold balance. Please adjust your balance to continue.",
|
|
}).show();
|
|
} else {
|
|
if (detailData.value.nft.type == 13) {
|
|
founderLock();
|
|
} else if (detailData.value.nft.type == 1 || detailData.value.nft.type == 12) {
|
|
heroLock();
|
|
}
|
|
}
|
|
};
|
|
|
|
const heroLock = async () => {
|
|
loadingDialogVisible.value = true;
|
|
try {
|
|
const bc = new BlockChain();
|
|
let res = await bc.locker.unlockOrMintGameNft(detailData.value.nft.contract_address, [
|
|
detailData.value.nft.token_id,
|
|
]);
|
|
detailData.value.nft["status"] = 1;
|
|
const confirmResult = await createModal(ConfirmDialog, {
|
|
title: "",
|
|
noBtnTitle: "",
|
|
message:
|
|
"Unstake success. It is expected to take 3-4 minutes. Please log in to the original wallet address to check later.",
|
|
}).show();
|
|
loadingDialogVisible.value = false;
|
|
if (res) {
|
|
try {
|
|
const {confirmed} = await apiTxHash(detailData.value.nft.net_id, res);
|
|
let timer = setInterval(async () => {
|
|
// message.success('Unstake success.')
|
|
if (confirmed) {
|
|
detailData.value.nft["status"] = "";
|
|
router.go(-1);
|
|
clearInterval(timer);
|
|
}
|
|
}, 2000);
|
|
} catch (e) {
|
|
console.log(e);
|
|
}
|
|
}
|
|
} catch (e) {
|
|
loadingDialogVisible.value = false;
|
|
if (e.message.indexOf("rejected") > -1) {
|
|
message.error("User rejected the request");
|
|
} else if (e.message.indexOf("select wallet") > -1) {
|
|
message.error("user cancel select wallet");
|
|
} else {
|
|
message.error("Unstake fail");
|
|
}
|
|
}
|
|
};
|
|
const founderLock = async () => {
|
|
loadingDialogVisible.value = true;
|
|
try {
|
|
const bc = new BlockChain();
|
|
let res = await bc.locker.unlockMain(detailData.value.nft.contract_address, [detailData.value.nft.token_id]);
|
|
detailData.value.nft["status"] = 1;
|
|
const confirmResult = await createModal(ConfirmDialog, {
|
|
title: "",
|
|
noBtnTitle: "",
|
|
message:
|
|
"Unstake success. It is expected to take 3-4 minutes. Please log in to the original wallet address to check later.",
|
|
}).show();
|
|
loadingDialogVisible.value = false;
|
|
if (res) {
|
|
try {
|
|
const {confirmed} = await apiTxHash(detailData.value.nft.net_id, res);
|
|
let timer = setInterval(async () => {
|
|
// message.success('Unstake success.')
|
|
if (confirmed) {
|
|
detailData.value.nft["status"] = "";
|
|
router.go(-1);
|
|
clearInterval(timer);
|
|
}
|
|
}, 2000);
|
|
} catch (e) {
|
|
console.log(e);
|
|
}
|
|
}
|
|
} catch (e) {
|
|
loadingDialogVisible.value = false;
|
|
if (e.message.indexOf("rejected") > -1) {
|
|
message.error("User rejected the request");
|
|
} else if (e.message.indexOf("select wallet") > -1) {
|
|
message.error("user cancel select wallet");
|
|
} else if (e.message.indexOf("eoa address changed") > -1) {
|
|
const confirmResult = await createModal(ConfirmDialog, {
|
|
title: "",
|
|
noBtnTitle: "",
|
|
message:
|
|
"It looks like there's an issue with your MetaMask or OKX wallet address. Please check your wallet address and try again.",
|
|
}).show();
|
|
} else {
|
|
message.error("Unstake fail");
|
|
}
|
|
}
|
|
};
|
|
|
|
// 售卖弹窗
|
|
const floorPrice = ref("0");
|
|
const sellDialogVisible = ref(false);
|
|
const beginSell = async () => {
|
|
if (detailData.value.event) return;
|
|
floorPrice.value = await getFloorPrice();
|
|
sellDialogVisible.value = true;
|
|
};
|
|
|
|
// 取消售卖
|
|
const cancelSell = async () => {
|
|
// console.log('cancelSell', detailData.value.event)
|
|
|
|
if (!detailData.value.event) return;
|
|
try {
|
|
let res = await new BlockChain().market.cancelOrder([detailData.value.event.data.id]);
|
|
if (res.result) {
|
|
let timer = setTimeout(() => {
|
|
getDetail();
|
|
message.success("Your item has been delisted.");
|
|
clearTimeout(timer);
|
|
}, 2000);
|
|
}
|
|
} catch (e) {
|
|
// try {
|
|
// let res = await new BlockChain().market.cancelOrdersOnChain([detailData.value.event.data.id])
|
|
// if(res.result) {
|
|
// let timer = setTimeout(() => {
|
|
// getDetail()
|
|
// clearTimeout(timer)
|
|
// }, 2000);
|
|
// }
|
|
// } catch (e2) {
|
|
// // console.log('cancelSell fail', e.message)
|
|
// }
|
|
if (e.message.indexOf("rejected") > -1) {
|
|
message.error("User rejected the request");
|
|
} else {
|
|
message.error("Your item has failed to be delisted.");
|
|
}
|
|
}
|
|
};
|
|
|
|
// 处理地址
|
|
const sliceAddress = (address) => {
|
|
if (!address) return "-";
|
|
if (address.length >= 10) {
|
|
return `${address.substring(0, 6)}......${address.slice(-4)}`;
|
|
}
|
|
return address;
|
|
};
|
|
|
|
// 获取地板价
|
|
const getFloorPrice = async () => {
|
|
const data = {
|
|
net_id: detailData.value.nft.net_id,
|
|
contract_address: detailData.value.nft.contract_address,
|
|
item_id: detailData.value.nft.item_id,
|
|
quality: detailData.value.nft.detail.quality,
|
|
};
|
|
let res = await apiGetPrice(data);
|
|
if (res.lowest_price_goods) {
|
|
floorPrice.value = res.lowest_price_goods.event.data.buy[0].amount;
|
|
} else {
|
|
floorPrice.value = "0";
|
|
}
|
|
return floorPrice.value;
|
|
};
|
|
|
|
// 关闭出售弹窗
|
|
const sellHandleClose = (val) => {
|
|
if (val) {
|
|
let timer = setTimeout(() => {
|
|
getDetail();
|
|
clearTimeout(timer);
|
|
}, 2000);
|
|
sellDialogVisible.value = false;
|
|
} else {
|
|
sellDialogVisible.value = false;
|
|
}
|
|
};
|
|
|
|
// mint上链
|
|
const mintHero = async () => {
|
|
console.log(toRaw(marketplaceList.activitySwitch).heroMint);
|
|
// return
|
|
if (toRaw(marketplaceList.activitySwitch).heroMint == 0) {
|
|
const confirmResult = await createModal(ConfirmDialog, {
|
|
title: "",
|
|
noBtnTitle: "",
|
|
message: "Mint Failed",
|
|
}).show();
|
|
} else {
|
|
if (marketplaceList.userGold < 0) {
|
|
const confirmResult = await createModal(ConfirmDialog, {
|
|
title: "",
|
|
noBtnTitle: "",
|
|
message: "Mint Failed - Negative in-game gold balance. Please adjust your balance to continue.",
|
|
}).show();
|
|
} else {
|
|
try {
|
|
const res = await new BlockChain().locker.mintNft([detailData.value.nft.uniid]);
|
|
message.success("Mint success.");
|
|
router.go(-1);
|
|
} catch (e) {
|
|
if (e.message.indexOf("rejected") > -1) {
|
|
message.error("User rejected the request");
|
|
} else if (e.message.indexOf("select wallet") > -1) {
|
|
message.error("user cancel select wallet");
|
|
} else {
|
|
message.error("Mint Failed.");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
const getDetail = async () => {
|
|
let {errcode, errmsg, data} = await nftDetail(props.address, props.tokenid);
|
|
// console.log(data)
|
|
contractBlankUrl.value = `${import.meta.env.VUE_APP_EXPLORER_URL}/address/${data.nft.contract_address}`;
|
|
|
|
contractTokenUrl.value = `${import.meta.env.VUE_APP_EXPLORER_URL}/token/${data.nft.contract_address}/instance/${
|
|
data.nft.token_id
|
|
}`;
|
|
if (errcode) {
|
|
// console.log(errmsg)
|
|
//TODO:: 提示错误信息
|
|
return;
|
|
}
|
|
const nftData = data.nft;
|
|
nftData.event = data.event;
|
|
nftAbilities.value = data.nft.detail;
|
|
detailData.value = data;
|
|
if (data.event?.data) {
|
|
const _data = formatPrice(data.event?.data);
|
|
icon.value = _data.icon;
|
|
usd.value = _data.usd;
|
|
price.value = _data.tokenAmount;
|
|
}
|
|
};
|
|
onMounted(() => {
|
|
if (location.pathname.length > 8) {
|
|
getDetail();
|
|
} else {
|
|
detailData.value = marketplaceList.detailData;
|
|
founderBlankUrl.value = `https://etherscan.io/token/0xec23679653337d4c6390d0eeba682246a6067777?a=${detailData.value.nft.token_id}`;
|
|
nftAbilities.value = marketplaceList.detailData.nft.detail;
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.detail {
|
|
width: 100%;
|
|
box-sizing: border-box;
|
|
background: #000;
|
|
.bg-content {
|
|
width: 100%;
|
|
height: 100%;
|
|
background: url("@/assets/img/marketplace/BG01.png") no-repeat;
|
|
background-size: 100% 100%;
|
|
}
|
|
.detail-bg {
|
|
width: 100%;
|
|
height: 84px;
|
|
}
|
|
.detail-content {
|
|
width: 100%;
|
|
height: 100%;
|
|
.content {
|
|
width: 1091px;
|
|
margin: 0 auto;
|
|
padding-top: 76px;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
color: #fff;
|
|
.top-left {
|
|
width: 321px;
|
|
.top-left-img {
|
|
height: 478px;
|
|
:deep(.card-img-common) {
|
|
.img-top {
|
|
width: 120px;
|
|
height: 35px;
|
|
top: 20px;
|
|
left: 20px;
|
|
font-size: 18px;
|
|
}
|
|
.img-btm {
|
|
bottom: 16px;
|
|
left: 20px;
|
|
> div {
|
|
width: 110px;
|
|
height: 40px;
|
|
font-size: 18px;
|
|
}
|
|
div:nth-child(2) {
|
|
margin-left: 15px;
|
|
}
|
|
}
|
|
}
|
|
:deep(.imgs) {
|
|
width: 100%;
|
|
height: 100%;
|
|
overflow: hidden;
|
|
.imgs-bg {
|
|
width: 100%;
|
|
height: 100%;
|
|
img {
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
// height: 450px;
|
|
}
|
|
.imgs-img {
|
|
width: 311px;
|
|
height: 413px;
|
|
}
|
|
.imgs-lock {
|
|
bottom: 220px;
|
|
left: 0px;
|
|
width: 311px;
|
|
height: 40px;
|
|
line-height: 40px;
|
|
}
|
|
.imgs-day {
|
|
bottom: 180px;
|
|
width: 90px;
|
|
height: 30px;
|
|
line-height: 30px;
|
|
font-size: 18px;
|
|
font-weight: 700;
|
|
}
|
|
.imgs-detail {
|
|
width: 311px;
|
|
height: 50px;
|
|
bottom: 65px;
|
|
div {
|
|
display: flex;
|
|
align-items: center;
|
|
img {
|
|
width: 40px;
|
|
height: 40px;
|
|
margin: 0 8px;
|
|
}
|
|
span {
|
|
font-family: "MEurostile";
|
|
font-weight: 700;
|
|
font-size: 32px;
|
|
color: #ffffff;
|
|
}
|
|
}
|
|
}
|
|
.imgs-quality {
|
|
bottom: 85px;
|
|
width: 80px;
|
|
height: 86px;
|
|
}
|
|
.imgs-name {
|
|
bottom: 15px;
|
|
font-size: 36px;
|
|
}
|
|
}
|
|
.mint-hero {
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
}
|
|
}
|
|
.top-right {
|
|
width: 712px;
|
|
padding-bottom: 80px;
|
|
h2 {
|
|
font-size: 42px;
|
|
font-family: "Poppins";
|
|
font-weight: bold;
|
|
}
|
|
.top-right-owner {
|
|
display: flex;
|
|
font-family: "Poppins";
|
|
font-weight: bold;
|
|
font-size: 30px;
|
|
.address {
|
|
margin-left: 20px;
|
|
}
|
|
}
|
|
.top-right-price {
|
|
width: 719px;
|
|
height: 133px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: space-between;
|
|
background: #2d2738;
|
|
border-radius: 20px;
|
|
margin-top: 10px;
|
|
color: #bb7fff;
|
|
padding: 15px 20px;
|
|
box-sizing: border-box;
|
|
li {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
> div {
|
|
display: flex;
|
|
font-size: 28px;
|
|
color: #9950fd;
|
|
}
|
|
.time {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: end;
|
|
font-size: 18px;
|
|
img {
|
|
width: 25px;
|
|
height: 28px;
|
|
margin-right: 5px;
|
|
}
|
|
div {
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
}
|
|
.price {
|
|
display: flex;
|
|
align-items: center;
|
|
span {
|
|
font-family: "Poppins";
|
|
font-weight: 400;
|
|
font-size: 24px;
|
|
color: #bb7fff;
|
|
}
|
|
.bold {
|
|
font-weight: bold;
|
|
font-size: 48px;
|
|
}
|
|
img {
|
|
width: 30px;
|
|
height: 30px;
|
|
margin-right: 20px;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.back-time {
|
|
// width: 340px;
|
|
height: 40px;
|
|
line-height: 40px;
|
|
border-radius: 20px;
|
|
font-family: "Poppins";
|
|
font-weight: 300;
|
|
font-size: 18px;
|
|
display: flex;
|
|
align-items: center;
|
|
div {
|
|
display: flex;
|
|
align-items: center;
|
|
background: #272130;
|
|
padding: 0 24px;
|
|
border-radius: 20px;
|
|
img {
|
|
width: 20px;
|
|
height: 25px;
|
|
margin-right: 6px;
|
|
// margin-left: 24px;
|
|
}
|
|
span {
|
|
display: inline-block;
|
|
height: 40px;
|
|
line-height: 40px;
|
|
color: #9a50ff;
|
|
}
|
|
|
|
&:nth-child(2) {
|
|
margin-left: 20px;
|
|
span {
|
|
font-family: "Poppins";
|
|
font-weight: 600;
|
|
font-size: 20px;
|
|
color: #f3f0ff;
|
|
}
|
|
.expected {
|
|
color: #00deff;
|
|
}
|
|
img {
|
|
width: 25px;
|
|
margin-left: 10px;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.top-right-btns {
|
|
div {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin: 10px 0;
|
|
> div {
|
|
width: 348px;
|
|
height: 57px;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
font-family: "Poppins";
|
|
font-weight: bold;
|
|
font-size: 28px;
|
|
color: #ffffff;
|
|
border-radius: 12px;
|
|
cursor: pointer;
|
|
}
|
|
.buy {
|
|
background: #6336d7;
|
|
}
|
|
.add {
|
|
background: #1778f1;
|
|
span {
|
|
height: 100%;
|
|
line-height: 57px;
|
|
border-radius: 12px;
|
|
text-align: center;
|
|
display: inline-block;
|
|
background: #1778f1;
|
|
}
|
|
img {
|
|
width: 43px;
|
|
height: 44px;
|
|
margin-left: 20px;
|
|
}
|
|
}
|
|
.remove {
|
|
background: #1778f1;
|
|
span {
|
|
height: 100%;
|
|
line-height: 57px;
|
|
border-radius: 12px;
|
|
text-align: center;
|
|
display: inline-block;
|
|
}
|
|
img {
|
|
width: 43px;
|
|
height: 44px;
|
|
}
|
|
}
|
|
.sell {
|
|
width: 348px;
|
|
background: #6336d7;
|
|
}
|
|
.cancel {
|
|
width: 348px;
|
|
background: #ff6271;
|
|
}
|
|
.redeem {
|
|
width: 348px;
|
|
background: #1778f1;
|
|
}
|
|
.mint {
|
|
background: #6336d7;
|
|
}
|
|
.lock {
|
|
height: 20px;
|
|
margin: 0;
|
|
img {
|
|
width: 20px;
|
|
height: 20px;
|
|
margin-right: 10px;
|
|
}
|
|
p {
|
|
font-size: 14px;
|
|
font-weight: 400;
|
|
}
|
|
}
|
|
.unLock {
|
|
background: #7f7f7f;
|
|
}
|
|
}
|
|
}
|
|
.info {
|
|
color: #b3b5da;
|
|
margin-top: 40px;
|
|
h2 {
|
|
font-family: "Poppins";
|
|
font-weight: bold;
|
|
font-size: 30px;
|
|
color: #fff;
|
|
border-bottom: 2px solid #3a3b57;
|
|
}
|
|
li {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
margin-top: 10px;
|
|
div {
|
|
width: 300px;
|
|
font-size: 22px;
|
|
text-align: left;
|
|
margin-top: 10px;
|
|
a {
|
|
color: #b3b5da;
|
|
cursor: pointer;
|
|
}
|
|
}
|
|
.contract-address {
|
|
position: relative;
|
|
cursor: pointer;
|
|
> div {
|
|
width: 560px;
|
|
height: 40px;
|
|
border-radius: 10px;
|
|
line-height: 40px;
|
|
border: 1px solid #7e7686;
|
|
position: absolute;
|
|
top: -50px;
|
|
left: -50%;
|
|
text-align: center;
|
|
background: #282131;
|
|
color: #fff;
|
|
display: none;
|
|
}
|
|
&:hover {
|
|
> div {
|
|
display: block;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.btm-left {
|
|
margin-top: 40px;
|
|
padding-bottom: 90px;
|
|
h2 {
|
|
font-size: 30px;
|
|
font-family: "Poppins";
|
|
font-weight: bold;
|
|
margin-bottom: 10px;
|
|
}
|
|
.btm-detail {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
clear: both;
|
|
justify-content: space-between;
|
|
width: 318px;
|
|
li {
|
|
width: 154px;
|
|
height: 84px;
|
|
background: #2d2738;
|
|
border-radius: 20px;
|
|
// margin-right: 9px;
|
|
margin-bottom: 10px;
|
|
div {
|
|
text-align: center;
|
|
font-size: 22px;
|
|
color: #b3b5da;
|
|
font-family: "Poppins";
|
|
h5 {
|
|
font-weight: bold;
|
|
}
|
|
.min-size {
|
|
font-size: 18px;
|
|
}
|
|
p {
|
|
font-weight: 400;
|
|
color: #fff;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.gold-content {
|
|
width: 455px;
|
|
height: 84px;
|
|
background: #2d2738;
|
|
border-radius: 20px;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
.left {
|
|
padding: 10px 19px;
|
|
font-family: "Poppins";
|
|
font-size: 22px;
|
|
h4 {
|
|
height: 18px;
|
|
font-weight: 400;
|
|
color: #b3b5da;
|
|
}
|
|
p {
|
|
height: 20px;
|
|
font-weight: bold;
|
|
color: #ffffff;
|
|
margin-top: 18px;
|
|
}
|
|
}
|
|
.right {
|
|
position: relative;
|
|
cursor: pointer;
|
|
margin-top: 9px;
|
|
margin-right: 10px;
|
|
.right-img {
|
|
width: 34px;
|
|
height: 33px;
|
|
img {
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
}
|
|
.right-tips {
|
|
display: none;
|
|
position: absolute;
|
|
top: 45px;
|
|
left: -20px;
|
|
width: 313px;
|
|
height: 82px;
|
|
padding: 20px;
|
|
box-sizing: border-box;
|
|
background: #1a1821;
|
|
box-shadow: 0px 15px 28px 3px rgba(22, 22, 22, 0.13);
|
|
border-radius: 10px;
|
|
border: 1px solid #b966ff;
|
|
}
|
|
&:hover {
|
|
.right-tips {
|
|
display: block;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
&:nth-child(2) {
|
|
padding-top: 20px;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</style> |