完成重构

This commit is contained in:
liangping 2021-07-28 19:20:30 +08:00
parent 1f064e33ad
commit e02cac6154
19 changed files with 37910 additions and 1791 deletions

35870
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -29,10 +29,13 @@
"bootstrap": "4.6.0",
"bootstrap-vue": "2.21.1",
"chart.js": "2.9.4",
"compare-versions": "^3.6.0",
"core-js": "3.8.1",
"dayjs": "^1.10.6",
"echarts": "4.8.0",
"jsonwebtoken": "8.5.1",
"leaflet": "1.6.0",
"node-fetch": "^2.6.1",
"portal-vue": "2.1.7",
"postcss-rtl": "1.7.3",
"prismjs": "1.19.0",
@ -41,6 +44,7 @@
"vee-validate": "3.4.5",
"vue": "2.x",
"vue-apexcharts": "1.6.0",
"vue-async-computed": "^3.9.0",
"vue-autosuggest": "2.2.0",
"vue-awesome-swiper": "4.1.1",
"vue-chartjs": "3.5.0",

View File

@ -55,7 +55,13 @@ export const isNavLinkActive = link => {
chainCompare = router.currentRoute.params.chain === link.route.params.chain
}
return matchedRoutes.some(route => (route.name === resolveRoutedName && chainCompare) || route.meta.navActiveLink === resolveRoutedName)
return matchedRoutes.some(route => {
const actived = (route.name === resolveRoutedName && chainCompare) || route.meta.navActiveLink === resolveRoutedName
if (actived) {
localStorage.setItem('selected_chain', link.route.params.chain)
}
return actived
})
}
/**

View File

@ -87,14 +87,18 @@ export default {
default: () => {},
},
},
data() {
return {
// result: {},
}
},
computed: {
selected_chain() {
const c = this.$route.params.chain
const has = Object.keys(store.state.chains.chains).findIndex(i => i === c)
if (has > -1) {
return store.state.chains.chains[c]
}
return store.state.chains.chains.cosmos
const selected = (has > -1) ? store.state.chains.chains[c] : store.state.chains.chains.cosmos
localStorage.setItem('selected_chain', selected)
return selected
},
},
}

25
src/libs/data/data.js Normal file
View File

@ -0,0 +1,25 @@
import dayjs from 'dayjs'
export function toDay(time) {
return dayjs(time).format('YYYY-MM-DD')
}
export function percent(num) {
return (num * 100).toFixed(2)
}
export function formatToken(token) {
// token.denom
// token.amount
let denom = token.denom.toUpperCase()
if (denom.charAt(0) === 'U') {
denom = denom.substring(1)
}
return `${(token.amount / 1000000).toFixed()} ${denom}`
}
export * from 'compare-versions'
export class Data {
}

5
src/libs/data/index.js Normal file
View File

@ -0,0 +1,5 @@
export { default as Proposal } from './proposal'
export { default as ProposalTally } from './proposal-tally'
export { default as StakingPool } from './staking-pool'
export default class Test {}

View File

@ -0,0 +1,16 @@
import { percent } from './data'
export default class ProposalTally {
constructor(element, total) {
this.yes = percent(Number(element.yes) / total)
this.no = percent(Number(element.no) / total)
this.veto = percent(Number(element.no_with_veto) / total)
this.abstain = percent(Number(element.abstain) / total)
this.turnout = percent((Number(element.yes) + Number(element.no) + Number(element.abstain) + Number(element.no_with_veto)) / total)
this.total = total
}
total() {
return this.total
}
}

View File

@ -0,0 +1,17 @@
import { percent } from './data'
export default class StakingPool {
constructor(element) {
this.element = element
this.bondedToken = Number(element.bonded_tokens)
this.notBondedToken = Number(element.not_bonded_tokens)
}
total() {
return this.bondedToken + this.notBondedToken
}
bondedRatio() {
return percent((this.bondedToken * 100) / this.total)
}
}

View File

@ -0,0 +1,77 @@
import dayjs from 'dayjs'
function toDay(time) {
return dayjs(time).format('YYYY-MM-DD')
}
function formatToken(token) {
// token.denom
// token.amount
let denom = token.denom.toUpperCase()
if (denom.charAt(0) === 'U') {
denom = denom.substring(1)
}
return `${(token.amount / 1000000).toFixed()} ${denom}`
}
const handler = class DefaultHandler {
commonProcess(res) {
this.raw = res
return res.result
}
processProposalTally(tally) {
console.log(tally)
const result = this.commonProcess(tally)
return result
}
processProposalList(proposals) {
console.log(proposals)
const ret = []
this.commonProcess(proposals[0]).forEach(element => {
const yes = Number(element.final_tally_result.yes)
const no = Number(element.final_tally_result.no)
const abstain = Number(element.final_tally_result.abstain)
const veto = Number(element.final_tally_result.no_with_veto)
// const j = voting.indexOf(element.id)
// if (proposals.length > 2 && j > -1) {
// const update = this.commonProcess(proposals[j + 2])
// yes = update.yes
// no = update.no
// abstain = update.abstain
// veto = update.no_with_veto
// }
// calculate total
const pool = this.commonProcess(proposals[1])
let total = yes + no + veto + abstain
if (total < Number(pool.bonded_tokens)) total = Number(pool.bonded_tokens)
ret.push({
id: element.id,
status: element.status,
type: element.content.type,
title: element.content.value.title,
description: element.content.value.description,
tally: {
yes: ((yes / total) * 100).toFixed(2),
no: ((no / total) * 100).toFixed(2),
abstain: ((abstain / total) * 100).toFixed(2),
veto: ((veto / total) * 100).toFixed(2),
turnout: (((yes + no + abstain + veto) / total) * 100).toFixed(2),
total,
},
submit_time: toDay(element.submit_time),
voting_end_time: toDay(element.voting_end_time),
voting_start_time: toDay(element.voting_start_time),
total_deposit: formatToken(element.total_deposit[0]),
})
})
console.log(ret)
return ret
}
}
export default handler

61
src/libs/fetch.js Normal file
View File

@ -0,0 +1,61 @@
import fetch from 'node-fetch'
import store from '@/store'
import DefaultHandler from '@/libs/default-handler'
import { Proposal, ProposalTally, StakingPool } from './data'
const requestVersion = async (c, url) => {
const response = await fetch(url)
const json = await response.json()
const sdk = json.application_version.build_deps.find(e => e.startsWith('github.com/cosmos/cosmos-sdk'))
const re = /(\d+(\.\d+)*)/i
const version = sdk.match(re)
console.log(`${c} sdk version:`, version[0])
store.commit('setup_sdk_version', { chain_name: c, version: version[0] })
return version[0]
}
function commonProcess(res) {
return res.result
}
const chainAPI = class ChainFetch {
constructor(route) {
const c = route.params.chain
const has = Object.keys(store.state.chains.chains).findIndex(i => i === c)
const selected = (has > -1) ? store.state.chains.chains[c] : store.state.chains.chains.cosmos
if (selected.sdk_version === undefined) {
const v = requestVersion(c, `${selected.api}/node_info`)
selected.sdk_version = v
}
this.config = selected
this.handler = new DefaultHandler()
}
async getStakingPool() {
return this.get('/staking/pool').then(data => new StakingPool(commonProcess(data)))
}
async getGovernanceTally(pid, total) {
return this.get(`/gov/proposals/${pid}/tally`).then(data => new ProposalTally(commonProcess(data), total))
}
async getGovernanceList() {
return Promise.all([this.get('/gov/proposals'), this.get('/staking/pool')]).then(data => {
const pool = new StakingPool(commonProcess(data[1]))
const ret = []
commonProcess(data[0]).forEach(e => {
const g = new Proposal(e, pool.bondedToken)
g.versionFixed(this.config.sdk_version)
ret.push(g)
})
return ret
})
}
async get(url) {
const response = await fetch(this.config.api + url)
return response.json()
}
}
export default chainAPI

View File

@ -1,4 +1,5 @@
import Vue from 'vue'
import AsyncComputed from 'vue-async-computed'
import { ToastPlugin, ModalPlugin } from 'bootstrap-vue'
import VueCompositionAPI from '@vue/composition-api'
import messages from '@/lang'
@ -11,12 +12,13 @@ import App from './App.vue'
// Global Components
import './global-components'
import '@/libs/axios'
import '@/libs/fetch'
// 3rd party plugins
import '@/libs/portal-vue'
import '@/libs/toastification'
Vue.use(AsyncComputed)
Vue.use(VueI18n)
const i18n = new VueI18n({

View File

@ -1,6 +1,6 @@
{
"chain_name": "akash",
"chain_id": "akashnet-1",
"api": "http://lcd.akash.forbole.com",
"api": "https://lcd-akash.keplr.app",
"logo": "https://look.ping.pub/static/chains/cosmoshub.svg"
}

View File

@ -1,5 +1,5 @@
{
"chain_name": "cosmos",
"api":"https://api.cosmos.network",
"api":"https://lcd-cosmoshub.keplr.app",
"logo": "https://look.ping.pub/static/chains/cosmoshub.svg"
}

View File

@ -1,26 +1,23 @@
const chains = {}
const configs = require.context('.', false, /\.json$/)
let selectedChain = {}
configs.keys().forEach(k => {
const c = configs(k)
if (c.chain_name === 'cosmos') {
selectedChain = c
}
chains[c.chain_name] = c
})
export default {
namespaced: true,
state: {
selectedChain,
chains,
},
getters: {
getchains: state => state.chains,
currentChain: state => chain => state.chains[chain],
},
mutations: {
setup_sdk_version(state, info) {
state.chains.chains[info.chain_name].sdk_version = info.version
},
},
actions: {},

View File

@ -0,0 +1,6 @@
{
"chain_name": "kava",
"chain_id": "kava-7",
"api": "https://kava4.data.kava.io",
"logo": "https://look.ping.pub/static/chains/cosmoshub.svg"
}

View File

@ -17,5 +17,6 @@ export default new Vuex.Store({
verticalMenu,
chains,
},
mutations: chains.mutations,
strict: process.env.DEV,
})

View File

@ -1,19 +1,43 @@
<template>
<section>
<b-row>
<!-- left align -->
<b-col
md="6"
<b-card
v-for="p in proposals"
:key="p.id"
>
<b-card>
<b-card-title class="mb-0">
<b-badge
v-if="p.status == 1"
pill
variant="light-info"
class="text-right"
>
Deposit
</b-badge>
<b-badge
v-if="p.status == 2"
pill
variant="light-primary"
class="text-right"
>
Voting
</b-badge>
<b-badge
v-if="p.status == 3"
pill
variant="light-success"
class="text-right"
>
Passed
</b-badge> #1. With supporting text below as a natural lead-in to additional content.With supporting text below as a natural lead-in to additional content
</b-badge>
<b-badge
v-if="p.status == 4"
pill
variant="light-danger"
class="text-right"
>
Rejected
</b-badge>
#{{ p.id }}. {{ p.title }}
</b-card-title>
<b-card-body md="12">
<div class="gov-wrapper">
@ -22,7 +46,7 @@
Start Date
</p>
<h6 class="mb-0">
2020-05-06
{{ p.voting_start_time }}
</h6>
</div>
<div class="gov">
@ -30,23 +54,23 @@
End Date
</p>
<h6 class="mb-0">
2020-05-06
{{ p.voting_end_time }}
</h6>
</div>
<div class="gov">
<!-- <div class="gov">
<p class="card-text mb-25">
Proposer
</p>
<h6 class="mb-0">
Ping.pub
</h6>
</div>
</div> -->
<div class="gov">
<p class="card-text mb-25">
Deposit
</p>
<h6 class="mb-0">
840.99
{{ p.total_deposit }}
</h6>
</div>
<div class="gov">
@ -54,62 +78,62 @@
Turnout
</p>
<h6 class="mb-0">
84.86%
{{ p.tally.turnout }}%
</h6>
</div>
</div>
</b-card-body>
<b-progress
:max="max"
:max="100"
height="2rem"
class="mb-2"
show-progress
>
<b-progress-bar
id="vote-yes"
:id="'vote-yes'+p.id"
variant="success"
:value="values[0]"
:value="p.tally.yes"
show-progress
/>
<b-progress-bar
id="vote-no"
:id="'vote-no'+p.id"
variant="warning"
:value="values[1]"
:value="p.tally.no"
show-progress
/>
<b-progress-bar
id="vote-veto"
:id="'vote-veto'+p.id"
variant="danger"
:value="values[2]"
:value="p.tally.veto"
show-progress
/>
<b-progress-bar
id="vote-abstain"
:id="'vote-abstain'+p.id"
variant="info"
:value="values[3]"
:value="p.tally.abstain"
show-progress
/>
</b-progress>
<b-tooltip
target="vote-yes"
:target="'vote-yes'+p.id"
>
{{ values[0] }} voted Yes
{{ p.tally.yes }}% voted Yes
</b-tooltip>
<b-tooltip
target="vote-no"
:target="'vote-no'+p.id"
>
{{ values[1] }} voted No
{{ p.tally.no }}% voted No
</b-tooltip>
<b-tooltip
target="vote-veto"
:target="'vote-veto'+p.id"
>
{{ values[2] }} voted Veta
{{ p.tally.veto }}% voted No With Veta
</b-tooltip>
<b-tooltip
target="vote-abstain"
:target="'vote-abstain'+p.id"
>
{{ values[3] }} voted Abstain
{{ p.tally.abstain }}% voted Abstain
</b-tooltip>
<b-card-footer>
<b-button
@ -126,88 +150,21 @@
</b-button>
</b-card-footer>
</b-card>
</b-col>
</b-row>
<b-row>
<b-col
md="12"
class="mb-1"
>
<b-card
title="# 1. Special title treatment"
class="mb-3"
>
<b-card-text>
# 1. With supporting text below as a natural lead-in to additional content.
</b-card-text>
<b-button
v-ripple.400="'rgba(113, 102, 240, 0.15)'"
variant="outline-primary"
>
Vote
</b-button>
</b-card>
</b-col>
<!-- center align -->
<b-col
md="6"
lg="4"
>
<b-card
title="Special title treatment"
class="text-center"
>
<b-card-text>
With supporting text below as a natural lead-in to additional content
</b-card-text>
<b-button
v-ripple.400="'rgba(113, 102, 240, 0.15)'"
variant="outline-primary"
>
Go somewhere
</b-button>
</b-card>
</b-col>
<!-- right align -->
<b-col
md="6"
lg="4"
>
<b-card
class="text-right"
title="Special title treatment"
>
<b-card-text>
With supporting text below as a natural lead-in to additional content.
</b-card-text>
<b-button
v-ripple.400="'rgba(113, 102, 240, 0.15)'"
variant="outline-primary"
>
Go somewhere
</b-button>
</b-card>
</b-col>
</b-row>
</section>
</template>
<script>
import {
BRow, BCol, BCard, BCardTitle, BCardText, BCardBody, BCardFooter, BButton, BProgressBar, BProgress, BBadge, BTooltip,
BCard, BCardTitle, BCardBody, BCardFooter, BButton, BProgressBar, BProgress, BBadge, BTooltip,
} from 'bootstrap-vue'
import Ripple from 'vue-ripple-directive'
import ChainAPI from '@/libs/fetch'
export default {
components: {
BCard,
BRow,
BCol,
BButton,
BCardFooter,
BCardText,
BProgressBar,
BProgress,
BBadge,
@ -221,13 +178,59 @@ export default {
data() {
return {
values: [15, 50, 10, 5],
max: 100,
max: 1,
}
},
computed: {
selected_c() {
console.log(localStorage.getItem('selected_chain'))
return localStorage.getItem('selected_chain')
},
// this.$http.get()
},
asyncComputed: {
proposals: {
get() {
const api = new ChainAPI(this.$route)
return api.getGovernanceList().then(res => {
const voting = res.filter(i => i.status === 2)
if (voting.length > 0) {
let i = 0
Promise.all(voting.reverse().map(p => api.getGovernanceTally(p.id, p.tally.total))).then(update => {
this.proposals.map(x => {
if (x.status === 2) {
const xh = x
xh.tally = update[i]
i += 1
return xh
}
return x
})
})
}
return res.reverse()
})
},
// default: 'loading...',
},
},
// watch: {
// proposals(val, newdata) {
// console.log('In watch', val, newdata)
// },
// },
}
</script>
<style scoped>
section {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.card {
flex-basis: 49%;
}
.gov-wrapper {
display: flex;
justify-content:center;

View File

@ -7,6 +7,8 @@
<script>
import { BCard, BCardText } from 'bootstrap-vue'
// import fetch from 'node-fetch'
import '@/libs/fetch'
export default {
components: {
@ -19,10 +21,18 @@ export default {
}
},
mounted() {
this.$http.get('/api/node_info', { crossdomain: true }).then(response => {
this.info = response.data
}).catch(e => {
console.log(e)
// this.$http.get('/api/node_info', { crossdomain: true }).then(response => {
// this.info = response.data
// }).catch(e => {
// console.log(e)
// })
this.fetchdata('http://lcd.akash.forbole.com/node_info', {
Headers: {
'Content-Type': 'text/html',
},
})
.then(response => {
console.log(response)
})
},
}

3173
yarn.lock

File diff suppressed because it is too large Load Diff