bemarket/src/components/market/wallet/WalletPanel.vue
2022-04-01 08:18:37 +08:00

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>