diff --git a/src/App.vue b/src/App.vue index bab24dd..faaf7a8 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,12 +1,12 @@ @@ -100,6 +100,7 @@ a { width: 16px; height: 16px; } + label { width: 130px; margin-left: 10px; diff --git a/src/components/Nav.vue b/src/components/Nav.vue index 6c149b9..06369ee 100644 --- a/src/components/Nav.vue +++ b/src/components/Nav.vue @@ -9,12 +9,13 @@ + + diff --git a/src/components/index.ts b/src/components/index.ts index 8284f74..203d0af 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -4,6 +4,7 @@ import Footer from './Footer.vue' import Header from './Header.vue' import Nav from './Nav.vue' import Pagination from './Pagination.vue' +import TimeFormat from './TimeFormat.vue' export { Banner, @@ -11,5 +12,6 @@ export { Footer, Header, Nav, - Pagination + Pagination, + TimeFormat } diff --git a/src/hooks/useGetMaxHeight.ts b/src/hooks/useGetMaxHeight.ts new file mode 100644 index 0000000..5196d0c --- /dev/null +++ b/src/hooks/useGetMaxHeight.ts @@ -0,0 +1,39 @@ +import { block } from '@/api' +import vuex from '@/store' +import { ElMessage } from 'element-plus' +import { computed, onBeforeUnmount, onMounted, ref } from 'vue' + +export default function () { + const maxHeight = computed(() => vuex.getters.maxHeight) + + // eslint-disable-next-line no-undef + const interval = ref() + + onMounted(() => { + interval.value = setInterval(() => { + getLastHeader() + }, 5000) + }) + + const getLastHeader = () => { + block.getLastHeader().then(res => { + if (res.error) { + clearInterval(Number(interval.value)) + return ElMessage.error({ + message: res.error, + offset: 300 + }) + } else if (maxHeight.value !== res.result.height) { + vuex.dispatch('setMaxHeight', res.result.height).then() + } + }) + } + + onBeforeUnmount(() => { + clearInterval(Number(interval.value)) + }) + + return { + maxHeight + } +} diff --git a/src/router/routers/block.ts b/src/router/routers/block.ts index a2b05a6..51554d7 100644 --- a/src/router/routers/block.ts +++ b/src/router/routers/block.ts @@ -10,7 +10,7 @@ export default [ requiresAuth: false, showTabBar: true }, - component: () => import(/* webpackChunkName: "auth" */ '@/views/Block/index.vue') + component: () => import(/* webpackChunkName: "block" */ '@/views/Block/index.vue') }, { path: '/blocks/:hash', @@ -21,7 +21,7 @@ export default [ requiresAuth: false, showTabBar: true }, - component: () => import(/* webpackChunkName: "auth" */ '@/views/Block/detail.vue') + component: () => import(/* webpackChunkName: "block" */ '@/views/Block/detail.vue') }, { path: '/trades', @@ -32,7 +32,7 @@ export default [ requiresAuth: false, showTabBar: true }, - component: () => import(/* webpackChunkName: "auth" */ '@/views/Trade/index.vue') + component: () => import(/* webpackChunkName: "trade" */ '@/views/Trade/index.vue') }, { path: '/trades/:hash', @@ -43,7 +43,7 @@ export default [ requiresAuth: false, showTabBar: true }, - component: () => import(/* webpackChunkName: "auth" */ '@/views/Trade/detail.vue') + component: () => import(/* webpackChunkName: "trade" */ '@/views/Trade/detail.vue') }, { path: '/analytical', @@ -54,7 +54,7 @@ export default [ requiresAuth: false, showTabBar: true }, - component: () => import(/* webpackChunkName: "auth" */ '@/views/Other/analytical.vue') + component: () => import(/* webpackChunkName: "other" */ '@/views/Other/analytical.vue') }, { path: '/broadcast', @@ -65,7 +65,7 @@ export default [ requiresAuth: false, showTabBar: true }, - component: () => import(/* webpackChunkName: "auth" */ '@/views/Other/broadcast.vue') + component: () => import(/* webpackChunkName: "other" */ '@/views/Other/broadcast.vue') }, { path: '/address/:address', @@ -76,7 +76,40 @@ export default [ requiresAuth: false, showTabBar: true }, - component: () => import(/* webpackChunkName: "auth" */ '@/views/Address/index.vue') - } + component: () => import(/* webpackChunkName: "other" */ '@/views/Address/index.vue') + }, + { + path: '/nodes', + name: 'Nodes', + meta: { + title: '节点列表', + keepAlive: true, + requiresAuth: false, + showTabBar: true + }, + component: () => import(/* webpackChunkName: "other" */ '@/views/Nodes/index.vue') + }, + { + path: '/tokens', + name: 'Token', + meta: { + title: 'Token', + keepAlive: true, + requiresAuth: false, + showTabBar: true + }, + component: () => import(/* webpackChunkName: "other" */ '@/views/Token/index.vue') + }, + { + path: '/wallet', + name: 'Wallet', + meta: { + title: '我的钱包', + keepAlive: false, + requiresAuth: true, + showTabBar: true + }, + component: () => import(/* webpackChunkName: "wallet" */ '@/views/Wallet/index.vue') + }, ] as MyRouteRecordRaw[] diff --git a/src/types/block.d.ts b/src/types/block.d.ts index c29dfc4..fa5f65f 100644 --- a/src/types/block.d.ts +++ b/src/types/block.d.ts @@ -4,6 +4,41 @@ export declare type AssetType = { symbol: string } +export declare type AddrOverview = { + balance: number + reciver: number + txCount: number +} + +export declare type TokenAssetItem = { + symbol: string + account: { + addr: string + balance: string + currency: number + frozen: string + } +} + +export declare type NodeItem = { + addr: string + name: string + header: { + height: number + blockTime: number + version: number + difficulty: number + hash: string + parentHash: string + stateHash: string + txCount: number + txHash: string + } + mempoolSize: number + port: number + self: boolean +} + export declare type BlockOverview = { height: number hash: string @@ -13,3 +48,50 @@ export declare type BlockOverview = { blockTime: number stateHash: string } + +export declare type BlockItem = { + hash: string + height: number + txCount: number + blockTime: number + difficulty: number + parentHash: string + stateHash: string + txHash: string + version: number +} + +export declare type BlockDetail = { + actionName: string + amount: number + assets: [] + blockTime: number + fromAddr: string + fullHash: string + height: number + index: number + proofs: any + tx: { + hash: string + from: string + to: string + height: number + execer: string + expire: number + fee: number + feefmt: string + nonce: number + payload: any + rawPayload: string + signature: { + pubkey: string + signature: string + ty: number + } + } + receipt: { + logs: any + ty: number + tyName: string + } +} diff --git a/src/types/nav.ts b/src/types/nav.ts new file mode 100644 index 0000000..227c43a --- /dev/null +++ b/src/types/nav.ts @@ -0,0 +1,4 @@ +export declare type NavItem = { + title: string + route: string +} diff --git a/src/utils/filters.ts b/src/utils/filters.ts index 06a2ec0..26ca5b1 100644 --- a/src/utils/filters.ts +++ b/src/utils/filters.ts @@ -1,5 +1,5 @@ -import { AssetType } from '@/types/block' import store from '@/store' +import { AssetType } from '@/types/block' export const filterHash = (str: string, num?: number): string => { const length = num || 16 @@ -17,3 +17,14 @@ export const parseSymbol = (assets?: AssetType[]): string => { return store.getters.symbol } } + +export const timestampToTime = (timestamp: number) => { + const date = new Date(timestamp * 1000) + const Y = date.getFullYear() + '-' + const M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-' + const D = (date.getDate() < 10 ? '0' + date.getDate() : date.getDate()) + ' ' + const h = (date.getHours() < 10 ? '0' + date.getHours() : date.getHours()) + ':' + const m = (date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()) + ':' + const s = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds() + return Y + M + D + h + m + s +} diff --git a/src/views/Address/index.vue b/src/views/Address/index.vue index ed1ad8d..f7ab188 100644 --- a/src/views/Address/index.vue +++ b/src/views/Address/index.vue @@ -43,8 +43,16 @@
- - + + + {{ item.symbol }} + {{ (Number(item.account.balance) / 1e8).toFixed(2) }} +
@@ -113,7 +121,11 @@ {{ scope.row.tx.feefmt }} {{ parseSymbol(scope.row.assets) }} - + + + @@ -121,8 +133,9 @@ diff --git a/src/views/Other/broadcast.vue b/src/views/Other/broadcast.vue index b79d86d..6715827 100644 --- a/src/views/Other/broadcast.vue +++ b/src/views/Other/broadcast.vue @@ -8,9 +8,7 @@ 您可以在此页面输入签过名的源数据,十六进制格式文本,并将其广播到区块链网络。 -
- -
+ 广播数据 @@ -67,6 +65,7 @@ textarea { border-radius: 5px; border: 2px solid #ebeff1; font-size: 14px; + margin-bottom: 16px; &:focus { outline: none; diff --git a/src/views/Token/index.vue b/src/views/Token/index.vue new file mode 100644 index 0000000..5ee7a86 --- /dev/null +++ b/src/views/Token/index.vue @@ -0,0 +1,50 @@ + + + + + + + diff --git a/src/views/Trade/detail.vue b/src/views/Trade/detail.vue index 338ed4c..4b30f49 100644 --- a/src/views/Trade/detail.vue +++ b/src/views/Trade/detail.vue @@ -9,46 +9,191 @@ -
-
发送方{{ detail.tx.from }}
-
接收方{{ detail.tx.to }}
-
上链时间{{ detail.blockTime }}
-
资产{{ detail.amount }}
-
GAS费{{ detail.tx.feefmt }}
-
随机数{{ detail.tx.nonce }}
-
执行器{{ detail.tx.execer }}
-
函数{{ detail.actionName }}
-
类型{{ detail.index }}
-
- 输入数据 -
-{{ detail.receipt.logs }}
-        
+
+
+ 概况 +
+
+ +
+ + {{ detail.tx.from }} + +
+
+
+ +
+ + {{ detail.tx.to }} + +
+
+
+ +
+ + {{ detail.height }} + +
+
+
+ +
+ +
+
+
+ +
{{ detail.amount }} {{ parseSymbol(detail.assets) }}
+
+
+ +
{{ detail.tx.feefmt }} {{ parseSymbol(detail.assets) }} +
+
+
+ +
{{ detail.tx.nonce }}
+
+
+ +
{{ detail.tx.execer }}
+
+
+ +
{{ detail.actionName }}
+
+
+ +
{{ detail.index }}
+
+
+ +
+
+{{ detail.tx.payload }}
+          
+
+
+
+ +
+
+{{ detail.receipt }}
+          
+
-
- 输出数据 -
-{{ detail.receipt.logs }}
-      
diff --git a/src/views/Wallet/index.vue b/src/views/Wallet/index.vue new file mode 100644 index 0000000..604414e --- /dev/null +++ b/src/views/Wallet/index.vue @@ -0,0 +1,13 @@ + + + + +