648 lines
15 KiB
Vue
648 lines
15 KiB
Vue
<template>
|
|
<div class="wallet-container">
|
|
<div class="header">
|
|
<div class="label">Wallet</div>
|
|
</div>
|
|
<div class="horizontal-bar"></div>
|
|
<div class="code" v-if="logined">
|
|
<span class="uuid">{{showAccount}}</span>
|
|
<div v-clipboard:copy="account"
|
|
v-clipboard:success="onCopy"
|
|
v-clipboard:error="onCopyError">
|
|
<svg-icon
|
|
name="copy" class="icCopy"></svg-icon>
|
|
</div>
|
|
</div>
|
|
<div class="tab-bar-net">
|
|
<div class="tab-item"
|
|
v-for="n in nets"
|
|
@click='changeNet(n.id)'
|
|
:key="n.id"
|
|
:class="{'active': currentNet===n.id}"
|
|
>
|
|
<span>{{n.name}}</span>
|
|
</div>
|
|
</div>
|
|
<div class="wallet">
|
|
<total-balance :currencies="currencies"></total-balance>
|
|
<coin-card
|
|
v-for="d in coinList"
|
|
:coin-data="d"
|
|
:process = "showOrderStatus"
|
|
@coin-card-clicked = "onCardClicked"
|
|
:key="d.symbol"></coin-card>
|
|
</div>
|
|
<div class="header ingame"><span class="label">Ingame Currency</span>
|
|
</div>
|
|
<div class="horizontal-bar"></div>
|
|
<div class="wallet">
|
|
<placeholder-panel></placeholder-panel>
|
|
<coin-card
|
|
v-for="d in gameCoinList"
|
|
:coin-data="d"
|
|
:process = "showOrderStatus"
|
|
@coin-card-clicked = "onGameCardClicked"
|
|
:key="d.symbol"></coin-card>
|
|
</div>
|
|
<price-picker-modal></price-picker-modal>
|
|
<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>
|
|
</div>
|
|
</template>
|
|
<script lang="ts">
|
|
import { Component, Vue, Watch } from 'vue-property-decorator'
|
|
import TotalBalance, { ICurrentData } from '@/components/market/wallet/TotalBalance.vue'
|
|
import CoinCard, { ICoinData } from '@/components/market/wallet/CoinCard.vue'
|
|
import GameCoinCard from '@/components/market/wallet/GameCoinCard.vue'
|
|
import { AppModule } from '@/store/modules/app'
|
|
import PlaceholderPanel from '@/components/market/wallet/PlaceholderPanel.vue'
|
|
import ChainManager from '@/chain/ChainManager'
|
|
import { CONTRACT_ADDRESS, OFFICE_ACCOUNT } from '@/configs/config_chain'
|
|
import { formatPrice } from '@/utils/chain.util'
|
|
import { getUserInfo } from '@/api/User'
|
|
import PricePickerModal, { SHOW_AMOUNT_MODAL } from '@/components/market/PricePickerModal.vue'
|
|
import { EventBus } from '@/utils/event-bus'
|
|
import { queryRechargeResult, queryWithdrawalResult, withdrawal } from '@/api/Market'
|
|
import { ElLoadingComponent } from 'element-ui/types/loading'
|
|
import TimeLoader from '@/components/main/TimeLoader.vue'
|
|
|
|
const TMP_ORDER_ID = 'tmp_coin_order_id'
|
|
@Component({
|
|
name: 'WalletPanel',
|
|
components: {
|
|
TimeLoader,
|
|
PricePickerModal,
|
|
PlaceholderPanel,
|
|
GameCoinCard,
|
|
CoinCard,
|
|
TotalBalance
|
|
}
|
|
})
|
|
export default class WalletPanel extends Vue {
|
|
private currentNet: number = this.nets[0].id
|
|
chainManager = new ChainManager()
|
|
orderTimer: any = null
|
|
showOrderStatus = false
|
|
historyOrderId: string | null = ''
|
|
loadingInstance: ElLoadingComponent
|
|
|
|
get nets() {
|
|
return [...new ChainManager().availableChains.values()]
|
|
}
|
|
|
|
get logined() {
|
|
return this.chainManager.isLogined
|
|
}
|
|
|
|
@Watch('logined')
|
|
private accountChange() {
|
|
this.changeNet(this.nets[0].id)
|
|
if (this.account) {
|
|
this.updateCurrencies()
|
|
this.updateGameCoins()
|
|
this.checkOrderHistory()
|
|
}
|
|
}
|
|
|
|
private currencies: ICurrentData[] = []
|
|
|
|
private coinList: ICoinData[] = [
|
|
{
|
|
name: 'CEBG Coin',
|
|
type: 0,
|
|
id: 'cec',
|
|
symbol: 'cec',
|
|
amount: '-',
|
|
icon: require('@/assets/market/cec.png'),
|
|
price: '-',
|
|
btnName: 'Deposit',
|
|
btnDisable: true
|
|
},
|
|
{
|
|
name: 'CEBG Gem',
|
|
type: 0,
|
|
id: 'ceg',
|
|
symbol: 'ceg',
|
|
amount: '-',
|
|
icon: require('@/assets/market/ceg.png'),
|
|
price: '-',
|
|
btnName: 'Deposit',
|
|
btnDisable: true
|
|
}
|
|
]
|
|
|
|
private gameCoinList: ICoinData[] = [
|
|
{
|
|
name: 'CEBG Coin',
|
|
type: 1,
|
|
id: 'diamond',
|
|
symbol: 'gCEC',
|
|
amount: '-',
|
|
icon: require('@/assets/market/cec.png'),
|
|
price: '-',
|
|
btnName: 'Claim',
|
|
btnDisable: true
|
|
},
|
|
{
|
|
name: 'CEBG Gem',
|
|
type: 1,
|
|
id: 'gold',
|
|
symbol: 'gCEG',
|
|
amount: '-',
|
|
icon: require('@/assets/market/ceg.png'),
|
|
price: '-',
|
|
btnName: 'Claim',
|
|
btnDisable: true
|
|
}
|
|
]
|
|
|
|
created() {
|
|
for (const net of this.nets) {
|
|
this.currencies.push({
|
|
name: `W${net.symbol.toUpperCase()}`,
|
|
amount: '-',
|
|
price: '-',
|
|
chain: net.id
|
|
})
|
|
}
|
|
}
|
|
|
|
mounted() {
|
|
this.checkOrderHistory()
|
|
}
|
|
|
|
updateDefaultData(data: ICoinData) {
|
|
data.amount = '-'
|
|
data.price = '-'
|
|
data.btnDisable = true
|
|
return data
|
|
}
|
|
|
|
get showAccount() {
|
|
return AppModule.accountShow
|
|
}
|
|
|
|
get account() {
|
|
return AppModule.accountId
|
|
}
|
|
|
|
onCopy(e: any) {
|
|
this.$message({
|
|
message: 'You just copied accountId',
|
|
type: 'success',
|
|
duration: 5 * 1000
|
|
})
|
|
}
|
|
|
|
onCopyError(e: any) {
|
|
this.$message({
|
|
message: 'Failed to copy texts',
|
|
type: 'error',
|
|
duration: 5 * 1000
|
|
})
|
|
}
|
|
|
|
changeNet(net: number) {
|
|
this.currentNet = net
|
|
const chainData = CONTRACT_ADDRESS[net]
|
|
for (let i = 0, l = this.coinList.length; i < l; i++) {
|
|
const data = this.updateDefaultData(this.coinList[i])
|
|
data.chain = net
|
|
data.address = chainData[data.symbol]
|
|
this.$set(this.coinList, i, data)
|
|
}
|
|
this.updateBalanceSet()
|
|
}
|
|
|
|
async updateCurrencies() {
|
|
for (let i = 0, l = this.currencies.length; i < l; i++) {
|
|
const data = this.currencies[i]
|
|
const currentData = CONTRACT_ADDRESS[data.chain]
|
|
const eth = await this.chainManager.getBalance(currentData.eth, data.chain)
|
|
data.amount = eth
|
|
this.$set(this.currencies, i, data)
|
|
}
|
|
}
|
|
|
|
async updateBalanceSet() {
|
|
const currentData = CONTRACT_ADDRESS[this.currentNet]
|
|
if (currentData) {
|
|
const cec = await this.chainManager.getBalance(currentData.cec, this.currentNet)
|
|
const ceg = await this.chainManager.getBalance(currentData.ceg, this.currentNet)
|
|
console.log(formatPrice(cec, 18), formatPrice(ceg, 18))
|
|
const updateCoinData = (i: number, amount: number) => {
|
|
const cecData = this.coinList[i]
|
|
cecData.amount = formatPrice(amount, 18)
|
|
cecData.btnDisable = amount === 0
|
|
this.$set(this.coinList, i, cecData)
|
|
}
|
|
updateCoinData(0, cec)
|
|
updateCoinData(1, ceg)
|
|
}
|
|
}
|
|
|
|
async onCardClicked(data: ICoinData) {
|
|
console.log('on coin card clicked: ', data)
|
|
let value = 0
|
|
try {
|
|
value = await this.pickAmount({
|
|
min: 1,
|
|
max: data.amount,
|
|
title: 'Please input amount to deposit'
|
|
})
|
|
} catch (err) {
|
|
this.$message({
|
|
type: 'info',
|
|
message: 'User cancel'
|
|
})
|
|
}
|
|
if (!value) {
|
|
return
|
|
}
|
|
this.loadingInstance = this.$loading({})
|
|
try {
|
|
const res = await this.beginTransfer(data, value)
|
|
console.log(res)
|
|
const txHash = res.transactionHash
|
|
this.saveTmpOrderInfo(txHash, 0)
|
|
this.beginTraceOrderStatus(txHash, 0)
|
|
} catch (err) {
|
|
console.log(err)
|
|
this.$message({
|
|
type: 'info',
|
|
message: 'error transfer'
|
|
})
|
|
}
|
|
this.loadingInstance?.close()
|
|
}
|
|
|
|
async beginTransfer(data: ICoinData, amount: number) {
|
|
return this.chainManager.transferToAccount({
|
|
to: OFFICE_ACCOUNT,
|
|
amount: amount,
|
|
chainId: data.chain!,
|
|
address: data.address!
|
|
})
|
|
}
|
|
|
|
async onGameCardClicked(data: ICoinData) {
|
|
console.log('on game card clicked: ', data)
|
|
let value = 0
|
|
try {
|
|
value = await this.pickAmount({
|
|
min: 1,
|
|
max: data.amount,
|
|
title: 'Please input amount to claim'
|
|
})
|
|
} catch (err) {
|
|
this.$message({
|
|
type: 'info',
|
|
message: 'User cancel'
|
|
})
|
|
}
|
|
if (!value) {
|
|
return
|
|
}
|
|
const postData = {
|
|
account: AppModule.accountId,
|
|
type: data.id === 'gold' ? 1 : 2,
|
|
amount: value + '000000000000000000'
|
|
}
|
|
this.loadingInstance = this.$loading({})
|
|
try {
|
|
const res: any = await withdrawal(postData)
|
|
console.log('withdrawal result: ', res)
|
|
const seqId = res.seq_id
|
|
this.saveTmpOrderInfo(seqId, 1)
|
|
this.beginTraceOrderStatus(seqId, 1)
|
|
this.loadingInstance?.close()
|
|
} catch (err) {
|
|
this.loadingInstance?.close()
|
|
}
|
|
console.log('begin claim')
|
|
}
|
|
|
|
async updateGameCoins() {
|
|
const data = { account: AppModule.accountId }
|
|
const info: any = await getUserInfo(data)
|
|
for (let i = 0, l = this.gameCoinList.length; i < l; i++) {
|
|
const data = this.gameCoinList[i]
|
|
data.amount = info[data.id] || 0
|
|
data.btnDisable = data.amount === 0
|
|
this.$set(this.gameCoinList, i, data)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取用户选择的币的数量
|
|
* @param data
|
|
* @return {Promise<number>}
|
|
*/
|
|
pickAmount(data: any) {
|
|
return new Promise<number>((resolve, reject) => {
|
|
data.current = data.current || data.min
|
|
data.confirmFun = (val: number) => {
|
|
resolve && resolve(val)
|
|
}
|
|
data.cancelFun = () => {
|
|
// eslint-disable-next-line prefer-promise-reject-errors
|
|
reject && reject('cancel select')
|
|
}
|
|
EventBus.$emit(SHOW_AMOUNT_MODAL, data)
|
|
})
|
|
}
|
|
|
|
/**
|
|
* 查询token->game的订单
|
|
* @param {string} txhash
|
|
* @return {Promise<void>}
|
|
*/
|
|
async queryRechargeOrder(txhash: string) {
|
|
const data: any = {
|
|
account: AppModule.accountId,
|
|
txhash
|
|
}
|
|
try {
|
|
const res: any = await queryRechargeResult(data)
|
|
console.log('queryRechargeResult: ', res)
|
|
if (res.state === 1) {
|
|
this.resetTmpOrderId()
|
|
this.showOrderStatus = false
|
|
this.updateGameCoins()
|
|
this.updateBalanceSet()
|
|
this.$alert('Congratulations', 'Deposit Success', { type: 'success', confirmButtonText: 'OK' })
|
|
} else if (res.state === 3) {
|
|
this.resetTmpOrderId()
|
|
this.showOrderStatus = false
|
|
this.updateGameCoins()
|
|
this.updateBalanceSet()
|
|
this.$alert('Sorry', 'Deposit failed', { type: 'error', confirmButtonText: 'OK' })
|
|
}
|
|
} catch (err) {
|
|
console.log(err)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 查询token->game的订单
|
|
* @param {string} seqId
|
|
* @return {Promise<void>}
|
|
*/
|
|
async queryWithdrawOrder(seqId: string) {
|
|
const data: any = {
|
|
account: AppModule.accountId,
|
|
seq_id: seqId
|
|
}
|
|
try {
|
|
const res: any = await queryWithdrawalResult(data)
|
|
console.log('queryWithdrawalResult: ', res)
|
|
if (res.state === 1) {
|
|
this.resetTmpOrderId()
|
|
this.showOrderStatus = false
|
|
this.updateGameCoins()
|
|
this.updateBalanceSet()
|
|
this.$alert('Congratulations', 'Claim Success', { type: 'success', confirmButtonText: 'OK' })
|
|
} else if (res.state === 3) {
|
|
this.resetTmpOrderId()
|
|
this.showOrderStatus = false
|
|
this.updateGameCoins()
|
|
this.updateBalanceSet()
|
|
this.$alert('Sorry', 'Claim failed', { type: 'error', confirmButtonText: 'OK' })
|
|
}
|
|
} catch (err) {
|
|
console.log(err)
|
|
}
|
|
}
|
|
|
|
checkOrderHistory() {
|
|
const data = this.getTmpOrderInfo()
|
|
if (data && this.account) {
|
|
this.beginTraceOrderStatus(data.orderId, data.type)
|
|
}
|
|
}
|
|
|
|
resetTmpOrderId() {
|
|
if (this.orderTimer !== null) {
|
|
clearInterval(this.orderTimer)
|
|
this.orderTimer = null
|
|
}
|
|
this.removeTmpOrderInfo()
|
|
this.loadingInstance?.close()
|
|
}
|
|
|
|
saveTmpOrderInfo(orderId: string, type: number) {
|
|
const data = { orderId, type }
|
|
localStorage.setItem(TMP_ORDER_ID, JSON.stringify(data))
|
|
}
|
|
|
|
removeTmpOrderInfo() {
|
|
localStorage.removeItem(TMP_ORDER_ID)
|
|
}
|
|
|
|
getTmpOrderInfo() {
|
|
const dataStr = localStorage.getItem(TMP_ORDER_ID)
|
|
if (dataStr) {
|
|
try {
|
|
return JSON.parse(dataStr)
|
|
} catch (err) {
|
|
return null
|
|
}
|
|
}
|
|
return null
|
|
}
|
|
|
|
beginTraceOrderStatus(orderId: string, type: number) {
|
|
this.showOrderStatus = true
|
|
this.loadingInstance?.close()
|
|
this.orderTimer = setInterval(() => {
|
|
if (type === 0) {
|
|
this.queryRechargeOrder(orderId)
|
|
} else {
|
|
this.queryWithdrawOrder(orderId)
|
|
}
|
|
}, 1000)
|
|
}
|
|
}
|
|
</script>
|
|
<style lang="scss" scoped>
|
|
@import '../../../scss/breakpoints.scss';
|
|
|
|
.wallet-container {
|
|
box-sizing: border-box;
|
|
color: white;
|
|
width: 1440px;
|
|
.tab-bar-net {
|
|
display: flex;
|
|
flex-direction: row;
|
|
margin-bottom: 5px;
|
|
.tab-item{
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
flex: none;
|
|
cursor: pointer;
|
|
font-weight: bold;
|
|
font-size: 1em;
|
|
line-height: 1.5em;
|
|
padding: 0.5em 2.125em;
|
|
text-transform: uppercase;
|
|
border: 1px solid #413482;
|
|
height: 2em;
|
|
border-radius: 0.2em;
|
|
color: #bcadf2;
|
|
background: transparent;
|
|
//clip-path: polygon(10% 0, 100% 0, 90% 100%, 0% 100%);
|
|
&:not(:first-child) {
|
|
margin-left: 0.5em;
|
|
}
|
|
&.active {
|
|
color: #ffffff;
|
|
background: #413482;
|
|
}
|
|
}
|
|
}
|
|
.code {
|
|
display: flex;
|
|
align-self: flex-start;
|
|
cursor: pointer;
|
|
margin-bottom: 1.25em;
|
|
.uuid {
|
|
font-size: 1em;
|
|
line-height: 1.5;
|
|
|
|
&:active {
|
|
opacity: 0.6;
|
|
}
|
|
}
|
|
|
|
.copy {
|
|
margin-left: 0.5em;
|
|
}
|
|
}
|
|
.ingame {
|
|
margin-top: 3.625em;
|
|
}
|
|
|
|
.icCopy {
|
|
margin-left: 3.625em;
|
|
align-self: center;
|
|
&:active {
|
|
opacity: 0.6;
|
|
}
|
|
}
|
|
|
|
.header {
|
|
display: flex;
|
|
flex-direction: row;
|
|
align-items: center;
|
|
padding-bottom: 0.75em;
|
|
|
|
.label {
|
|
font-weight: bolder;
|
|
font-size: 1.375em;
|
|
line-height: 1.27;
|
|
color: #ffffff;
|
|
&.disable {
|
|
@include media('<tablet') {
|
|
color: #3c2885;
|
|
}
|
|
}
|
|
&.ingameCurrency {
|
|
margin-left: 2.1875em;
|
|
}
|
|
}
|
|
}
|
|
|
|
.horizontal-bar {
|
|
border: 0;
|
|
height: 1px;
|
|
background: #563cb8;
|
|
margin-bottom: 1.75em;
|
|
}
|
|
|
|
.wallet {
|
|
display: flex;
|
|
flex-direction: row;
|
|
justify-content: space-between;
|
|
}
|
|
}
|
|
.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('<wide') {
|
|
.wallet-container{
|
|
width: 1024px;
|
|
font-size: 13px;
|
|
}
|
|
}
|
|
// Mobile
|
|
@include media('<tablet') {
|
|
.wallet-container {
|
|
width: 100%;
|
|
.show {
|
|
display: flex !important;
|
|
}
|
|
.hide {
|
|
display: none !important;
|
|
}
|
|
.headerCoin {
|
|
margin-top: 28px;
|
|
}
|
|
.ingame {
|
|
margin-top: 28px;
|
|
}
|
|
.wallet {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
.coinCard {
|
|
width: 100%;
|
|
margin-bottom: 20px;
|
|
}
|
|
}
|
|
.walletIngame {
|
|
display: none;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Tablet
|
|
@include media('>=tablet', '<desktop') {
|
|
.wallet-container {
|
|
width: 100%;
|
|
.ingame {
|
|
margin-top: 38px;
|
|
}
|
|
.headerCoin {
|
|
margin-top: 28px;
|
|
}
|
|
.wallet {
|
|
display: flex;
|
|
flex-direction: row;
|
|
flex-wrap: wrap;
|
|
justify-content: space-between;
|
|
|
|
.coinCard {
|
|
width: 293px;
|
|
margin-bottom: 20px;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
</style>
|