Commit 7800a6a0 authored by wenglk's avatar wenglk

添加交易区块筛选

parent 9d30fb01
import {
Table,
TableColumn,
Pagination,
Button,
Loading,
Select,
Option,
Message,
MessageBox
} from 'element-ui'
export default {
install(V: any) {
V.use(Button)
V.use(Pagination)
V.use(Select)
V.use(Option)
V.use(Table)
V.use(TableColumn)
V.use(Loading.directive)
V.prototype.$notify = Notification
V.prototype.$confirm = MessageBox.confirm
V.prototype.$message = Message
}
}
\ No newline at end of file
...@@ -70,6 +70,7 @@ export const lang = { ...@@ -70,6 +70,7 @@ export const lang = {
nextBlock: "Next Block", nextBlock: "Next Block",
no: "Nothing", no: "Nothing",
consensusAddress: "Consensus", consensusAddress: "Consensus",
txnsBlocks: "Block with more than {0} txns"
}, },
txDetail: { txDetail: {
detail: "Transaction details", detail: "Transaction details",
......
...@@ -70,6 +70,7 @@ export const lang = { ...@@ -70,6 +70,7 @@ export const lang = {
nextBlock: "下个区块", nextBlock: "下个区块",
no: "无", no: "无",
consensusAddress: "共识地址", consensusAddress: "共识地址",
txnsBlocks: '> {0}交易数量的区块'
}, },
txDetail: { txDetail: {
detail: "交易详情", detail: "交易详情",
......
...@@ -3,12 +3,16 @@ ...@@ -3,12 +3,16 @@
<div class="txNumBox text-center flex-shrink-0"> <div class="txNumBox text-center flex-shrink-0">
<div <div
class="text-footer-color text-base font-bold" class="text-footer-color text-base font-bold"
style="margin-top: 7px;" style="margin-top: 7px"
> >
{{ txCount }} {{ txCount }}
</div> </div>
<div class="text-xs font-bold text-footer-color-light"> <div class="text-xs font-bold text-footer-color-light">
{{ txCount === 1 ? $t('lang.block.txCount_single') : $t('lang.block.txCount') }} {{
txCount === 1
? $t("lang.block.txCount_single")
: $t("lang.block.txCount")
}}
</div> </div>
</div> </div>
<div class="msgBox flex-shrink-0 flex-grow mt-3.5 ml-2"> <div class="msgBox flex-shrink-0 flex-grow mt-3.5 ml-2">
...@@ -31,7 +35,7 @@ ...@@ -31,7 +35,7 @@
</div> </div>
<div> <div>
<span class="text-text-color text-xs"> <span class="text-text-color text-xs">
{{ $t('lang.block.packingAddress') }}: {{ $t("lang.block.packingAddress") }}:
</span> </span>
<span class="text-footer-color"> <span class="text-footer-color">
<router-link <router-link
...@@ -48,7 +52,7 @@ ...@@ -48,7 +52,7 @@
</div> </div>
<div> <div>
<span class="text-text-color text-xs"> <span class="text-text-color text-xs">
{{ $t('lang.block.blockReward') }} {{ $t("lang.block.blockReward") }}
</span> </span>
<span class="text-black text-xs"> <span class="text-black text-xs">
{{ height | filterBlockReward }} {{ height | filterBlockReward }}
...@@ -58,7 +62,7 @@ ...@@ -58,7 +62,7 @@
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from 'vue' import Vue from "vue";
export default Vue.extend({ export default Vue.extend({
props: { props: {
txCount: Number, txCount: Number,
...@@ -66,7 +70,7 @@ export default Vue.extend({ ...@@ -66,7 +70,7 @@ export default Vue.extend({
blockTime: Number, blockTime: Number,
packagingAddress: String, packagingAddress: String,
}, },
}) });
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.blockItem { .blockItem {
......
...@@ -8,7 +8,7 @@ import "./style.css"; ...@@ -8,7 +8,7 @@ import "./style.css";
import { Select } from "ant-design-vue"; import { Select } from "ant-design-vue";
import { i18n } from "./assets/lang/index"; import { i18n } from "./assets/lang/index";
import filters from "@/utils/filters"; import filters from "@/utils/filters";
import { Table, TableColumn, Pagination, Button, Loading } from "element-ui"; import ElementUI from './ElementConfig/index'
Object.entries(filters).forEach(([filterName, filterFunc]) => { Object.entries(filters).forEach(([filterName, filterFunc]) => {
Vue.filter(filterName, filterFunc); Vue.filter(filterName, filterFunc);
...@@ -27,11 +27,7 @@ Object.entries(filters).forEach(([filterName, filterFunc]) => { ...@@ -27,11 +27,7 @@ Object.entries(filters).forEach(([filterName, filterFunc]) => {
console.log('v.0.2.0'); console.log('v.0.2.0');
Vue.use(Select); Vue.use(Select);
Vue.use(Table); Vue.use(ElementUI);
Vue.use(TableColumn);
Vue.use(Pagination);
Vue.use(Button);
Vue.use(Loading.directive);
Vue.config.productionTip = false; Vue.config.productionTip = false;
......
import Vue from "vue"; import Vue from "vue";
import { message } from "ant-design-vue"; import { message } from "ant-design-vue";
import { getRpc } from "ycc-api/dist/cmjs/service/Rpc"; import { iBlockInBlockMixin } from "@/types/block";
import { iBlockInBlockMixin, iGetBlocksRetResultItem } from "@/types/block"; import { getBlocks, getBlocksCount } from "@/service/api";
import { yccApi } from "@/service/api";
import {
clearTimeoutFromTimerObj,
registerTimeoutToTimerObj,
} from "@/utils/common";
const Rpc = getRpc(yccApi);
const TimerObj = {} as any;
export default Vue.extend({ export default Vue.extend({
data() { data() {
return { return {
searchValue: "", searchValue: "",
maxHeight: 0,
startHeight: 0,
endHeight: 0,
Loading: false, Loading: false,
pages: { pages: {
currentPage: 1, currentPage: 1,
pageSize: 20, pageSize: 20,
total: 10, total: 10,
}, },
showTotal: 0,
range: 0,
Blocks: [] as iBlockInBlockMixin[], Blocks: [] as iBlockInBlockMixin[],
}; };
}, },
computed: {
selectOptions() {
return [
{
label: this.$t('lang.block.title'),
value: 0
},
{
label: this.$t('lang.block.txnsBlocks', [100]),
value: 100
},
{
label: this.$t('lang.block.txnsBlocks', [200]),
value: 200
},
{
label: this.$t('lang.block.txnsBlocks', [500]),
value: 500
},
{
label: this.$t('lang.block.txnsBlocks', [1000]),
value: 1000
},
{
label: this.$t('lang.block.txnsBlocks', [2000]),
value: 2000
},
{
label: this.$t('lang.block.txnsBlocks', [5000]),
value: 5000
}
]
}
},
mounted() { mounted() {
this.getLastBlock(); this.getBlocks();
this.getBlocksCount()
}, },
methods: { methods: {
getLastBlock() {
if (this.Loading) return;
this.Loading = true;
Rpc.getLastHeader().then((data) => {
if (data.error === null) {
if (data.result.height !== this.endHeight) {
this.maxHeight = data.result.height;
this.$store.commit("saveMaxHeight", this.maxHeight);
this.pages.total = this.maxHeight;
this.getBlocks(this.maxHeight);
return;
}
this.Loading = false;
} else {
this.Loading = false;
message.warning({
content: data.error as string,
});
}
});
},
pageChange(page: number) { pageChange(page: number) {
clearTimeoutFromTimerObj(TimerObj);
this.pages.currentPage = page; this.pages.currentPage = page;
const newHeight = this.getBlocks();
this.maxHeight - (this.pages.currentPage - 1) * this.pages.pageSize;
this.endHeight = 0;
this.Blocks = [];
this.getBlocks(newHeight);
}, },
sizeChange(size: number) { sizeChange(size: number) {
this.pages.pageSize = size; this.pages.pageSize = size;
this.pageChange(1); this.pageChange(1);
}, },
getBlocks(endHeight: number) { filterBlocks(range: number) {
this.pages.currentPage = 1
this.range = range
this.getBlocksCount()
this.getBlocks()
},
async getBlocksCount() {
const { result } = await getBlocksCount(this.range)
this.showTotal = result
this.pages.total = result > 100000 ? 100000 : result;
},
async getBlocks() {
this.Loading = true; this.Loading = true;
Rpc.getBlocks( try {
endHeight - this.pages.pageSize >= 0 const res = await getBlocks(this.pages.currentPage, this.pages.pageSize, this.range)
? endHeight - this.pages.pageSize if (res.result) {
: 0, this.Blocks = res.result
endHeight, this.Loading = false
true
).then((data) => {
if (data.error === null) {
const info = (data.result.items as iGetBlocksRetResultItem[])
.reverse()
.map((i) => ({
height: i.block.height,
blockTime: i.block.blockTime,
minerHash: i.block.txs[0].from,
txCount: i.block.txs.length,
}));
this.Blocks = [...info];
info.map((i) => {
Rpc.getBlockHash(i.height).then((ret) => {
const the = this.Blocks.find(
(block) => block.height === i.height
);
the && (the.hash = ret.result.hash);
this.Blocks = [...this.Blocks];
});
});
this.Loading = false;
} else {
this.Loading = false;
message.warning({
content: data.error,
});
} }
}); else throw (res.error)
}, } catch (e) {
}, this.Loading = false;
watch: { message.warning({
Loading(val) { content: e as string,
if (val === false && this.pages.currentPage === 1) { });
registerTimeoutToTimerObj(TimerObj, this.getLastBlock, 10 * 1e3);
} }
}, },
}, }
beforeDestroy() {
clearTimeoutFromTimerObj(TimerObj);
},
}); });
...@@ -113,6 +113,69 @@ export function getTxList(number: number, size: number) { ...@@ -113,6 +113,69 @@ export function getTxList(number: number, size: number) {
}); });
} }
/**
* 获取区块列表
*
* @export
* @param {number} number
* @param {number} size
* @param {number} gt
* @returns
*/
export function getBlocks(number: number, size: number, gt?: number) {
return axios(expandApi, {
method: "post",
params: {
id: 1,
method: "Block.BlockList",
params: [{
page: {
size,
number
},
range: [
{
gt,
key: "tx_count"
}
],
sort: [
{
key: "height",
ascending: false
}
]
}],
},
});
}
/**
* 获取区块总数
*
* @export
* @param {number} gt
* @returns
*/
export function getBlocksCount(gt: number) {
return axios(expandApi, {
method: "post",
params: {
id: 1,
method: "Block.Count",
params: [{
range: [
{
gt,
key: "tx_count"
}
]
}],
},
});
}
export function blockStatStatGets(startHeight: number, endHeight: number) { export function blockStatStatGets(startHeight: number, endHeight: number) {
return axios(expandApi, { return axios(expandApi, {
method: "post", method: "post",
......
...@@ -11,14 +11,32 @@ ...@@ -11,14 +11,32 @@
></m-page-container> ></m-page-container>
<div class="rounded-twoPx overflow-hidden shadow-shadow1 mt-3.5"> <div class="rounded-twoPx overflow-hidden shadow-shadow1 mt-3.5">
<m-title <m-title
:title="`${$t('lang.block.title')}(${maxHeight}${$t('lang.block.count')})`" :title="`${$t('lang.block.title')}(${showTotal}${$t(
'lang.block.count'
)})`"
></m-title> ></m-title>
<div class="search-container">
<el-select
v-model="range"
class="range-select"
size="small"
@change="filterBlocks"
>
<el-option
v-for="item in selectOptions"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</div>
<m-block-item <m-block-item
v-for="(item, i) in Blocks" v-for="(item, i) in Blocks"
:blockTime="item.blockTime" :blockTime="item.block_time"
:height="item.height" :height="item.height"
:packagingAddress="item.hash" :packagingAddress="item.from"
:txCount="item.txCount" :txCount="item.tx_count"
:key="i" :key="i"
></m-block-item> ></m-block-item>
</div> </div>
...@@ -34,20 +52,43 @@ ...@@ -34,20 +52,43 @@
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import MBlockItem from '@/components/mobile/m-blockItem.vue' import MBlockItem from "@/components/mobile/m-blockItem.vue";
import mChainSearch from '@/components/mobile/m-chainSearch.vue' import mChainSearch from "@/components/mobile/m-chainSearch.vue";
import MPageContainer from '@/components/mobile/m-pageContainer.vue' import MPageContainer from "@/components/mobile/m-pageContainer.vue";
import MTitle from '@/components/mobile/m-title.vue' import MTitle from "@/components/mobile/m-title.vue";
import VueTypedMixins from 'vue-typed-mixins' import VueTypedMixins from "vue-typed-mixins";
import blockMixin from '@/mixin/block' import blockMixin from "@/mixin/block";
export default VueTypedMixins(blockMixin).extend({ export default VueTypedMixins(blockMixin).extend({
components: { mChainSearch, MPageContainer, MTitle, MBlockItem }, components: { mChainSearch, MPageContainer, MTitle, MBlockItem },
}) });
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.rounded-twoPx {
position: relative;
}
.c-block { .c-block {
padding-top: 44px; padding-top: 44px;
border-radius: 2px; border-radius: 2px;
padding-bottom: 23px; padding-bottom: 23px;
} }
.c-title {
padding-top: 20px;
height: 130px;
align-items: flex-start;
}
.search-container {
padding: 0 25px;
display: flex;
justify-content: flex-end;
align-items: center;
position: absolute;
top: 50px;
z-index: 1;
height: 60px;
width: 100%;
background: #fafbfc;
}
.range-select {
width: 310px;
}
</style> </style>
<template> <template>
<div <div
class="the-block min-w-1200 md:w-bodySet mx-auto flow-root" class="the-block min-w-1200 md:w-bodySet mx-auto flow-root"
style="padding-bottom: 60px;" style="padding-bottom: 60px"
> >
<chain-search <chain-search
class="mt-7" class="mt-7"
...@@ -11,8 +11,8 @@ ...@@ -11,8 +11,8 @@
<div class="pc-block inner-box"> <div class="pc-block inner-box">
<div class="title flex items-center justify-between"> <div class="title flex items-center justify-between">
<span class="total-block"> <span class="total-block">
{{ $t('lang.block.title') }}{{ maxHeight | filterNum {{ $t("lang.block.title") }}{{ showTotal | filterNum
}}{{ $t('lang.block.count') }} }}{{ $t("lang.block.count") }}
</span> </span>
<page-container <page-container
@pageChange="pageChange" @pageChange="pageChange"
...@@ -23,85 +23,104 @@ ...@@ -23,85 +23,104 @@
></page-container> ></page-container>
</div> </div>
<!-- 表格部分 --> <!-- 表格部分 -->
<el-table <div class="table-container">
:data="Blocks" <div class="search-container">
stripe <el-select
style="width: 100%;" v-model="range"
class="data-table" class="range-select"
v-loading="Loading" size="small"
element-loading-text="Loading..." @change="filterBlocks"
element-loading-spinner="el-icon-loading" >
> <el-option
<template slot="empty"> v-for="item in selectOptions"
<div> :key="item.value"
<!-- <div :label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</div>
<el-table
:data="Blocks"
stripe
style="width: 100%"
class="data-table"
header-cell-class-name="header-style"
v-loading="Loading"
element-loading-text="Loading..."
element-loading-spinner="el-icon-loading"
>
<template slot="empty">
<div>
<!-- <div
v-if="Loading" v-if="Loading"
class="loading-line" class="loading-line"
v-loading="Loading" v-loading="Loading"
element-loading-text="Loading..." element-loading-text="Loading..."
element-loading-spinner="el-icon-loading" element-loading-spinner="el-icon-loading"
></div> --> ></div> -->
<span v-if="!Loading">{{ $t('lang.page.nodata') }}</span> <span v-if="!Loading">{{ $t("lang.page.nodata") }}</span>
</div>
</template>
<el-table-column width="40"></el-table-column>
<el-table-column :label="$t('lang.block.height')" width="180">
<template slot-scope="item">
<router-link
:to="`/blockDetail?height=${item.row.height}`"
class="light"
>
{{ item.row.height }}
</router-link>
</template>
</el-table-column>
<el-table-column prop="blockTime" :label="$t('lang.txDetail.time')">
<template slot-scope="item">
<!-- <count :time="item.row.blockTime" class="light2"></count> -->
<div class="text-darkBlue">
{{ item.row.blockTime | formatTime }}
</div>
</template>
</el-table-column>
<el-table-column prop="hash" :label="$t('lang.block.hash')">
<template slot-scope="item">
<router-link
:to="`/blockDetail?height=${item.row.height}`"
class="light"
>
{{ item.row.hash | filterHash(12) }}
</router-link>
</template>
</el-table-column>
<el-table-column :label="$t('lang.block.packingAddress')">
<template slot-scope="item">
<router-link
:to="`/blockDetail?height=${item.row.height}`"
class="light"
>
{{ item.row.minerHash | filterHash(12) }}
</router-link>
</template>
</el-table-column>
<el-table-column :label="$t('lang.block.blockReward')">
<template slot-scope="block">
<div class="light2">
{{ block.row.height | filterBlockReward }}
</div> </div>
</template> </template>
</el-table-column> <el-table-column width="40"></el-table-column>
<el-table-column <el-table-column :label="$t('lang.block.height')" width="180">
width="80" <template slot-scope="item">
prop="txCount" <router-link
align="right" :to="`/blockDetail?height=${item.row.height}`"
:label="$t('lang.block.txCount')" class="light"
> >
<template slot-scope="item"> {{ item.row.height }}
<div class="light">{{ item.row.txCount }}</div> </router-link>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column width="40"></el-table-column> <el-table-column prop="blockTime" :label="$t('lang.txDetail.time')">
</el-table> <template slot-scope="item">
<!-- <count :time="item.row.blockTime" class="light2"></count> -->
<div class="text-darkBlue">
{{ item.row.block_time | formatTime }}
</div>
</template>
</el-table-column>
<el-table-column prop="hash" :label="$t('lang.block.hash')">
<template slot-scope="item">
<router-link
:to="`/blockDetail?height=${item.row.height}`"
class="light"
>
{{ item.row.hash | filterHash(12) }}
</router-link>
</template>
</el-table-column>
<el-table-column :label="$t('lang.block.packingAddress')">
<template slot-scope="item">
<router-link
:to="`/blockDetail?height=${item.row.height}`"
class="light"
>
{{ item.row.from | filterHash(12) }}
</router-link>
</template>
</el-table-column>
<el-table-column :label="$t('lang.block.blockReward')">
<template slot-scope="block">
<div class="light2">
{{ block.row.height | filterBlockReward }}
</div>
</template>
</el-table-column>
<el-table-column
width="80"
prop="txCount"
align="right"
:label="$t('lang.block.txCount')"
>
<template slot-scope="item">
<div class="light">{{ item.row.tx_count }}</div>
</template>
</el-table-column>
<el-table-column width="40"></el-table-column>
</el-table>
</div>
<!-- 底部分页 --> <!-- 底部分页 -->
<div class="bottom-page flex justify-end"> <div class="bottom-page flex justify-end">
<page-container <page-container
...@@ -117,17 +136,35 @@ ...@@ -117,17 +136,35 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import VueTypedMixins from 'vue-typed-mixins' import VueTypedMixins from "vue-typed-mixins";
import ChainSearch from '@/components/pc/BlockChainBrowser/ChainSearch.vue' import ChainSearch from "@/components/pc/BlockChainBrowser/ChainSearch.vue";
import PageContainer from '@/components/pc/BlockChainBrowser/PageContainer.vue' import PageContainer from "@/components/pc/BlockChainBrowser/PageContainer.vue";
import Count from '@/components/pc/BlockChainBrowser/Count.vue' import Count from "@/components/pc/BlockChainBrowser/Count.vue";
import blockMixin from '@/mixin/block' import blockMixin from "@/mixin/block";
export default VueTypedMixins(blockMixin).extend({ export default VueTypedMixins(blockMixin).extend({
components: { ChainSearch, PageContainer, Count }, components: { ChainSearch, PageContainer, Count },
}) });
</script> </script>
<style scoped> <style scoped>
.table-container {
position: relative;
}
.search-container {
padding: 0 25px;
display: flex;
justify-content: flex-end;
align-items: center;
position: absolute;
top: 70px;
z-index: 1;
height: 80px;
width: 100%;
background: #fafbfc;
}
.range-select {
width: 310px;
}
.title { .title {
margin-top: 30px; margin-top: 30px;
} }
...@@ -179,3 +216,14 @@ export default VueTypedMixins(blockMixin).extend({ ...@@ -179,3 +216,14 @@ export default VueTypedMixins(blockMixin).extend({
color: #2545cb; color: #2545cb;
} }
</style> </style>
<style>
.header-style {
padding-top: 25px !important;
height: 150px;
vertical-align: baseline !important;
}
.range-select input {
border-radius: 20px;
}
</style>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment