add accounts

This commit is contained in:
liangping 2023-04-21 16:08:31 +08:00
parent fc8aab6ce0
commit 5f7339c04b
7 changed files with 134 additions and 27 deletions

View File

@ -0,0 +1,22 @@
<script lang="ts" setup>
import VueApexCharts from 'vue3-apexcharts'
import { useTheme } from 'vuetify'
import { getDonutChartConfig } from './apexChartConfig'
const props = defineProps(["series", "labels"])
const vuetifyTheme = useTheme()
const expenseRationChartConfig = computed(() => getDonutChartConfig(vuetifyTheme.current.value, props.labels))
</script>
<template>
<VueApexCharts
type="donut"
height="410"
:options="expenseRationChartConfig"
:series="series"
/>
</template>

View File

@ -1,7 +1,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import VueApexCharts from 'vue3-apexcharts' import VueApexCharts from 'vue3-apexcharts'
import { useTheme } from 'vuetify' import { useTheme } from 'vuetify'
import { getAreaChartSplineConfig, getMarketPriceChartConfig } from './apexCharConfig' import { getAreaChartSplineConfig, getMarketPriceChartConfig } from './apexChartConfig'
import { useIndexModule } from '@/modules/[chain]/indexStore'; import { useIndexModule } from '@/modules/[chain]/indexStore';
import { computed, ref } from '@vue/reactivity'; import { computed, ref } from '@vue/reactivity';

View File

@ -383,7 +383,7 @@ export const getRadialBarChartConfig = (themeColors: ThemeInstance['themes']['va
} }
} }
export const getDonutChartConfig = (themeColors: ThemeInstance['themes']['value']['colors']) => { export const getDonutChartConfig = (themeColors: ThemeInstance['themes']['value']['colors'], labels: string[]) => {
const donutColors = { const donutColors = {
series1: '#fdd835', series1: '#fdd835',
series2: '#00d4bd', series2: '#00d4bd',
@ -396,7 +396,7 @@ export const getDonutChartConfig = (themeColors: ThemeInstance['themes']['value'
return { return {
stroke: { width: 0 }, stroke: { width: 0 },
labels: ['Operational', 'Networking', 'Hiring', 'R&D'], labels,
colors: [donutColors.series1, donutColors.series5, donutColors.series3, donutColors.series2], colors: [donutColors.series1, donutColors.series5, donutColors.series3, donutColors.series2],
dataLabels: { dataLabels: {
enabled: true, enabled: true,
@ -425,10 +425,10 @@ export const getDonutChartConfig = (themeColors: ThemeInstance['themes']['value'
formatter: (val: string) => `${parseInt(val, 10)}`, formatter: (val: string) => `${parseInt(val, 10)}`,
}, },
total: { total: {
show: true, show: false,
fontSize: '1.5rem', fontSize: '1.5rem',
label: 'Operational', // label: 'Operational',
formatter: () => '31%', // formatter: () => '31%',
color: themePrimaryTextColor, color: themePrimaryTextColor,
}, },
}, },

View File

@ -64,7 +64,7 @@ export interface RequestRegistry {
staking_validators_address: Request<{validator: Validator}>; staking_validators_address: Request<{validator: Validator}>;
staking_validators_delegations: Request<PaginatedDelegations>; staking_validators_delegations: Request<PaginatedDelegations>;
staking_validators_delegations_delegator: Request<{delegation_response: Delegation}>; staking_validators_delegations_delegator: Request<{delegation_response: Delegation}>;
staking_validators_delegations_unbonding_delegations: Request<any>; staking_validators_delegations_unbonding_delegations: Request<PaginatedUnbonding>;
base_tendermint_abci_query: Request<any>; base_tendermint_abci_query: Request<any>;
base_tendermint_block_latest: Request<Block>; base_tendermint_block_latest: Request<Block>;

View File

@ -1,32 +1,52 @@
<script lang="ts" setup> <script lang="ts" setup>
import { useBlockchain, useFormatter } from '@/stores'; import { useBlockchain, useFormatter, useStakingStore } from '@/stores';
import DynamicComponent from '@/components/dynamic/DynamicComponent.vue'; import DynamicComponent from '@/components/dynamic/DynamicComponent.vue';
import DonutChart from '@/components/charts/DonutChart.vue'
import { computed, ref } from '@vue/reactivity'; import { computed, ref } from '@vue/reactivity';
import 'vue-json-pretty/lib/styles.css'; import 'vue-json-pretty/lib/styles.css';
import type { AuthAccount, Delegation, TxResponse, DelegatorRewards } from '@/types'; import type { AuthAccount, Delegation, TxResponse, DelegatorRewards, UnbondingResponses } from '@/types';
import type { Coin } from '@cosmjs/amino'; import type { Coin } from '@cosmjs/amino';
const props = defineProps(['address', 'chain']) const props = defineProps(['address', 'chain'])
const blockchain = useBlockchain() const blockchain = useBlockchain()
const stakingStore = useStakingStore()
const format = useFormatter() const format = useFormatter()
const account = ref({} as AuthAccount) const account = ref({} as AuthAccount)
const txs = ref({} as TxResponse[]) const txs = ref({} as TxResponse[])
const delegations = ref([] as Delegation[]) const delegations = ref([] as Delegation[])
const rewards = ref({} as DelegatorRewards) const rewards = ref({} as DelegatorRewards)
const balances = ref([] as Coin[]) const balances = ref([] as Coin[])
const totalAmount = computed(()=> { const unbonding = ref([] as UnbondingResponses[])
let total = 0; const unbondingTotal = ref(0)
const chart = {}
const totalAmountByCategory = computed(()=> {
let sumDel = 0;
delegations.value?.forEach(x => { delegations.value?.forEach(x => {
total += Number(x.balance.amount) sumDel += Number(x.balance.amount)
}) })
let sumRew = 0
rewards.value?.total?.forEach(x => { rewards.value?.total?.forEach(x => {
total += Number(x.amount) sumRew += Number(x.amount)
}) })
let sumBal = 0
balances.value?.forEach(x => { balances.value?.forEach(x => {
total += Number(x.amount) sumBal += Number(x.amount)
}) })
return total let sumUn = 0
unbonding.value?.forEach(x => {
x.entries?.forEach(y => {
sumUn += Number(y.balance)
})
})
return [sumBal, sumDel, sumRew, sumUn]
})
const labels = ['Balance', 'Delegation', 'Reward', 'Unbonding']
const totalAmount= computed(()=> {
return totalAmountByCategory.value.reduce((p, c)=> c + p, 0)
}) })
@ -46,6 +66,14 @@ function loadAccount(address: string) {
blockchain.rpc.getBankBalances(address).then(x => { blockchain.rpc.getBankBalances(address).then(x => {
balances.value = x.balances balances.value = x.balances
}) })
blockchain.rpc.getStakingDelegatorUnbonding(address).then(x => {
unbonding.value = x.unbonding_responses
x.unbonding_responses?.forEach(y => {
y.entries.forEach(z => {
unbondingTotal.value += Number(z.balance)
})
})
})
} }
loadAccount(props.address) loadAccount(props.address)
</script> </script>
@ -80,7 +108,7 @@ loadAccount(props.address)
<VCardItem> <VCardItem>
<VRow> <VRow>
<VCol cols="12" md="4"> <VCol cols="12" md="4">
xx <DonutChart :series="totalAmountByCategory" :labels="labels"/>
</VCol> </VCol>
<VCol cols="12" md="8"> <VCol cols="12" md="8">
<VList class="card-list"> <VList class="card-list">
@ -89,10 +117,10 @@ loadAccount(props.address)
<VAvatar <VAvatar
rounded rounded
variant="tonal" variant="tonal"
size="45" size="35"
color="success" color="info"
> >
<VIcon icon="mdi-card" /> <VIcon icon="mdi-account-cash" size="20"/>
</VAvatar> </VAvatar>
</template> </template>
<VListItemTitle class="text-sm font-weight-semibold"> <VListItemTitle class="text-sm font-weight-semibold">
@ -110,10 +138,10 @@ loadAccount(props.address)
<VAvatar <VAvatar
rounded rounded
variant="tonal" variant="tonal"
size="45" size="35"
color="info" color="warning"
> >
<VIcon icon="mdi-lock" /> <VIcon icon="mdi-user-clock" size="20" />
</VAvatar> </VAvatar>
</template> </template>
@ -132,10 +160,10 @@ loadAccount(props.address)
<VAvatar <VAvatar
rounded rounded
variant="tonal" variant="tonal"
size="45" size="35"
color="warning" color="success"
> >
<VIcon icon="mdi-up" /> <VIcon icon="mdi-account-arrow-up" size="20" />
</VAvatar> </VAvatar>
</template> </template>
@ -149,6 +177,29 @@ loadAccount(props.address)
<VChip color="primary">{{ format.calculatePercent(v.amount, totalAmount) }}</VChip> <VChip color="primary">{{ format.calculatePercent(v.amount, totalAmount) }}</VChip>
</template> </template>
</VListItem> </VListItem>
<VListItem>
<template #prepend>
<VAvatar
rounded
variant="tonal"
size="35"
color="error"
>
<VIcon icon="mdi-account-arrow-right" size="20" />
</VAvatar>
</template>
<VListItemTitle class="text-sm font-weight-semibold">
{{ format.formatToken({amount: String(unbondingTotal), denom: stakingStore.params.bond_denom}) }}
</VListItemTitle>
<VListItemSubtitle class="text-xs">
${{ 0 }}
</VListItemSubtitle>
<template #append>
<VChip color="primary">{{ format.calculatePercent(unbondingTotal, totalAmount) }}</VChip>
</template>
</VListItem>
</VList> </VList>
<VDivider class="my-2"></VDivider> <VDivider class="my-2"></VDivider>
{{ totalAmount }} {{ totalAmount }}
@ -177,6 +228,29 @@ loadAccount(props.address)
</VTable> </VTable>
</VCardItem> </VCardItem>
</VCard> </VCard>
<VCard class="my-5" v-if="unbonding && unbonding.length > 0">
<VCardItem>
<VCardTitle>Unbonding Delegations</VCardTitle>
<VTable>
<thead>
<tr><th>Creation Height</th><th>Initial Balance</th><th>Balance</th><th>Completion Time</th></tr>
</thead>
<tbody>
<div v-for="v in unbonding">
<tr>
<td>{{ format.validatorFromBech32(v.validator_address) }} </td>
</tr>
<tr v-for="entry in v.entries">
<td>{{ entry.creation_height }}</td>
<td>{{ format.formatToken({ amount: entry.initial_balance, denom: stakingStore.params.bond_denom }, true, "0,0.[00]") }}</td>
<td>{{ format.formatToken({ amount: entry.balance, denom: stakingStore.params.bond_denom }, true, "0,0.[00]") }}</td>
<td>{{ format.toDay(entry.completion_time, "to") }} </td>
</tr>
</div>
</tbody>
</VTable>
</VCardItem>
</VCard>
<VCard class="my-5"> <VCard class="my-5">
<VCardItem> <VCardItem>
<VCardTitle>Transactions</VCardTitle> <VCardTitle>Transactions</VCardTitle>

View File

@ -124,7 +124,7 @@ export const useFormatter = defineStore('formatter', {
const validator = this.staking.validators.find(x => x.operator_address === address) const validator = this.staking.validators.find(x => x.operator_address === address)
return validator?.description?.moniker return validator?.description?.moniker
}, },
calculatePercent(input?: string, total?: string|number ) { calculatePercent(input?: string|number, total?: string|number ) {
if(!input || !total) return '0' if(!input || !total) return '0'
const percent = Number(input)/Number(total) const percent = Number(input)/Number(total)
console.log(input, total, percent); console.log(input, total, percent);

View File

@ -29,6 +29,17 @@ export interface CommissionRate {
"update_time": string "update_time": string
} }
export interface UnbondingResponses {
delegator_address: string,
validator_address: string,
entries: {
creation_height: string,
completion_time: string,
initial_balance: string,
balance: string
}[]
}
export interface Delegation { export interface Delegation {
delegation: { delegation: {
delegator_address: string, delegator_address: string,
@ -70,7 +81,7 @@ export interface PaginatedRedelegations extends PaginatedResponse {
} }
export interface PaginatedUnbonding extends PaginatedResponse { export interface PaginatedUnbonding extends PaginatedResponse {
unbonding_responses: any[] unbonding_responses: UnbondingResponses[]
} }
export interface PaginatedValdiators extends PaginatedResponse { export interface PaginatedValdiators extends PaginatedResponse {