|
|
@@ -0,0 +1,355 @@
|
|
|
+<template>
|
|
|
+ <v-card
|
|
|
+ elevation="1"
|
|
|
+ >
|
|
|
+ <v-container>
|
|
|
+ <v-row>
|
|
|
+ <!-- Start Time过滤 -->
|
|
|
+ <v-col
|
|
|
+ cols="18"
|
|
|
+ md="2"
|
|
|
+ >
|
|
|
+ <v-text-field
|
|
|
+ v-model="query.t1_str"
|
|
|
+ label="Start Time(YYYY/mm/DD HH:MM:SS)"
|
|
|
+ required
|
|
|
+ ></v-text-field>
|
|
|
+ </v-col>
|
|
|
+
|
|
|
+ <!-- End Time过滤 -->
|
|
|
+ <v-col
|
|
|
+ cols="18"
|
|
|
+ md="2"
|
|
|
+ >
|
|
|
+ <v-text-field
|
|
|
+ v-model="query.t2_str"
|
|
|
+ label="End Time(YYYY/mm/DD HH:MM:SS)"
|
|
|
+ required
|
|
|
+ ></v-text-field>
|
|
|
+ </v-col>
|
|
|
+
|
|
|
+ <!-- hash过滤 -->
|
|
|
+ <v-col
|
|
|
+ cols="18"
|
|
|
+ md="2"
|
|
|
+ >
|
|
|
+ <v-text-field
|
|
|
+ v-model="query.hs"
|
|
|
+ label="Hash"
|
|
|
+ required
|
|
|
+ ></v-text-field>
|
|
|
+ </v-col>
|
|
|
+
|
|
|
+ <!-- From -->
|
|
|
+ <v-col
|
|
|
+ cols="18"
|
|
|
+ md="2"
|
|
|
+ >
|
|
|
+ <v-text-field
|
|
|
+ v-model="query.fm"
|
|
|
+ label="From"
|
|
|
+ required
|
|
|
+ ></v-text-field>
|
|
|
+ </v-col>
|
|
|
+
|
|
|
+ <!-- To -->
|
|
|
+ <v-col
|
|
|
+ cols="18"
|
|
|
+ md="2"
|
|
|
+ >
|
|
|
+ <v-text-field
|
|
|
+ v-model="query.t"
|
|
|
+ label="To"
|
|
|
+ required
|
|
|
+ ></v-text-field>
|
|
|
+ </v-col>
|
|
|
+
|
|
|
+ <!-- State -->
|
|
|
+ <v-col
|
|
|
+ cols="18"
|
|
|
+ md="1"
|
|
|
+ >
|
|
|
+ <v-text-field
|
|
|
+ v-model="query.state"
|
|
|
+ label="State"
|
|
|
+ required
|
|
|
+ ></v-text-field>
|
|
|
+ </v-col>
|
|
|
+
|
|
|
+ <v-col
|
|
|
+ cols="18"
|
|
|
+ md="1"
|
|
|
+ >
|
|
|
+ <v-btn outlined tile color="primary" @click="searchData">
|
|
|
+ <v-icon left>mdi-cloud-search-outline</v-icon>
|
|
|
+ Search
|
|
|
+ </v-btn>
|
|
|
+ </v-col>
|
|
|
+ </v-row>
|
|
|
+ </v-container>
|
|
|
+
|
|
|
+ <v-card
|
|
|
+ elevation="0"
|
|
|
+ >
|
|
|
+ <v-card-title>
|
|
|
+ My Data
|
|
|
+ <v-spacer></v-spacer>
|
|
|
+ <v-text-field
|
|
|
+ v-model="search"
|
|
|
+ append-icon="mdi-magnify"
|
|
|
+ label="Search"
|
|
|
+ single-line
|
|
|
+ hide-details
|
|
|
+ ></v-text-field>
|
|
|
+ </v-card-title>
|
|
|
+
|
|
|
+ <v-data-table
|
|
|
+ dense
|
|
|
+ hide-default-footer
|
|
|
+ multi-sort
|
|
|
+ :headers="headers"
|
|
|
+ :items="tableData"
|
|
|
+ :search="search"
|
|
|
+ :items-per-page="10000"
|
|
|
+ :loading="loading"
|
|
|
+ :sort-by="['ts', 'block', 'nonce']"
|
|
|
+ :sort-desc="[true, true, true]"
|
|
|
+ >
|
|
|
+ <template v-slot:item.ts="{ item }">
|
|
|
+ {{ getTime(item.ts) }}
|
|
|
+ </template>
|
|
|
+ <!-- Type -->
|
|
|
+ <template v-slot:item.type="{ item }">
|
|
|
+ <v-chip small v-if="item.o.type.indexOf('err') !== -1" outlined label color="grey">
|
|
|
+ <v-icon small left>mdi-filter-remove</v-icon>
|
|
|
+ {{ item.o.type.split(':')[1] }}
|
|
|
+ </v-chip>
|
|
|
+ <v-chip small v-else-if="item.o.type.indexOf('WARN') !== -1" outlined label color="red lighten-2">
|
|
|
+ <v-icon small left>mdi-alert-circle-outline</v-icon>
|
|
|
+ {{ item.o.type.split(':')[1] }}
|
|
|
+ </v-chip>
|
|
|
+ <v-chip small v-else-if="item.o.type.indexOf('DS:') !== -1" outlined label color="cyan darken-3">
|
|
|
+ <v-icon small left>mdi-horse-human</v-icon>
|
|
|
+ {{ item.o.type.split(':')[1] }}
|
|
|
+ </v-chip>
|
|
|
+ <v-chip small v-else-if="item.o.type.indexOf('CASH') !== -1" outlined label color="black">
|
|
|
+ <v-icon small left>mdi-currency-usd</v-icon>
|
|
|
+ {{ item.o.type.split(':')[1] }}
|
|
|
+ </v-chip>
|
|
|
+ <v-chip small v-else-if="item.o.type.indexOf('ZIJI') !== -1" outlined label color="blue">
|
|
|
+ <v-icon small left>mdi-panda</v-icon>
|
|
|
+ {{ item.o.type.split(':')[1] }}
|
|
|
+ </v-chip>
|
|
|
+ </template>
|
|
|
+ <!-- Hash -->
|
|
|
+ <template v-slot:item.hs="{ item }">
|
|
|
+ <v-tooltip right>
|
|
|
+ <template v-slot:activator="{ on, attrs }">
|
|
|
+ <v-btn small :href="'https://etherscan.io/tx/' + item.hs" target="_blank" text v-on="on" v-bind="attrs">{{ getSimpleStr(item.hs) }}</v-btn>
|
|
|
+ </template>
|
|
|
+ <span>{{ item.hs }}</span>
|
|
|
+ </v-tooltip>
|
|
|
+ </template>
|
|
|
+ <!-- From -->
|
|
|
+<!-- <template v-slot:item.fm="{ item }">-->
|
|
|
+<!-- <v-tooltip right>-->
|
|
|
+<!-- <template v-slot:activator="{ on, attrs }">-->
|
|
|
+<!-- <v-btn :href="'https://etherscan.io/address/' + item.fm" target="_blank" text v-on="on" v-bind="attrs">{{ getSimpleStr(item.fm) }}</v-btn>-->
|
|
|
+<!-- </template>-->
|
|
|
+<!-- <span>{{ item.fm }}</span>-->
|
|
|
+<!-- </v-tooltip>-->
|
|
|
+<!-- </template>-->
|
|
|
+ <!-- Address -->
|
|
|
+ <template v-slot:item.symbolAddress="{ item }">
|
|
|
+ <v-tooltip right>
|
|
|
+ <template v-slot:activator="{ on, attrs }">
|
|
|
+ <v-btn small :href="'https://etherscan.io/address/' + item.symbolAddress" target="_blank" text v-on="on" v-bind="attrs">{{ getSimpleStr(item.symbolAddress) }}</v-btn>
|
|
|
+ </template>
|
|
|
+ <span>{{ item.symbolAddress }}</span>
|
|
|
+ </v-tooltip>
|
|
|
+ </template>
|
|
|
+ <!-- Gas -->
|
|
|
+ <template v-slot:item.o="{ item }">
|
|
|
+ {{ item.o.gas }}
|
|
|
+ </template>
|
|
|
+ <!-- 利润 -->
|
|
|
+ <template v-slot:item.profit="{ item }">
|
|
|
+ {{ item.o.profit }}
|
|
|
+ </template>
|
|
|
+ <!-- Block -->
|
|
|
+ <template v-slot:item.block="{ item }">
|
|
|
+ {{ item.o.blockNumber }}
|
|
|
+ </template>
|
|
|
+ <!-- Nonce -->
|
|
|
+ <template v-slot:item.nonce="{ item }">
|
|
|
+ {{ item.o.nonce }}
|
|
|
+ </template>
|
|
|
+ <!-- origin -->
|
|
|
+ <template v-slot:item.origin>
|
|
|
+ {{ '' }}
|
|
|
+ </template>
|
|
|
+ <!-- State -->
|
|
|
+ <template v-slot:item.state="{ item }">
|
|
|
+ <v-chip small v-if="item.state === 'ok'" outlined label color="teal"> ok </v-chip>
|
|
|
+ <v-chip small v-else-if="item.state === 'pending'" outlined label color="orange"> {{ item.state }} </v-chip>
|
|
|
+ <v-chip small v-else-if="item.state === 'fail'" outlined label color="red lighten-3"> {{ item.state }} </v-chip>
|
|
|
+ <v-chip small v-else-if="item.state === 'cancel'" outlined label color="blue-grey"> {{ item.state }} </v-chip>
|
|
|
+ </template>
|
|
|
+ <!-- Amount -->
|
|
|
+ <template v-slot:item.amount="{ item }">
|
|
|
+ <div v-if="!item.o.intoken">
|
|
|
+ <v-chip small outlined color="red accent-1">-{{ item.o.inamount }}(TOKEN)</v-chip>
|
|
|
+ >
|
|
|
+ <v-chip small outlined color="teal lighten-1" @click="jump(item.o.pairAddress)">+{{ item.o.outamount }}({{ item.o.outtoken }})</v-chip>
|
|
|
+ </div>
|
|
|
+ <div v-else-if="!item.o.outtoken">
|
|
|
+ <v-chip small outlined color="red accent-1">-{{ item.o.inamount }}({{ item.o.intoken }})</v-chip>
|
|
|
+ >
|
|
|
+ <v-chip small outlined color="teal lighten-1" @click="jump(item.o.pairAddress)">+{{ item.o.outamount }}(TOKEN)</v-chip>
|
|
|
+ </div>
|
|
|
+ <div v-else>
|
|
|
+ <v-chip small outlined color="red accent-1">-{{ item.o.inamount }}({{ item.o.intoken }})</v-chip>
|
|
|
+ >
|
|
|
+ <v-chip small outlined color="teal lighten-1" @click="jump(item.o.pairAddress)">+{{ item.o.outamount }}({{ item.o.outtoken }})</v-chip>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </v-data-table>
|
|
|
+ </v-card>
|
|
|
+ </v-card>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+ import axios from 'axios'
|
|
|
+
|
|
|
+ export default {
|
|
|
+ name: 'History',
|
|
|
+
|
|
|
+ methods: {
|
|
|
+ // 时间戳转换chart时间
|
|
|
+ getTime (timestamp) {
|
|
|
+ // 组织日期格式并返回
|
|
|
+ return this.dateFormat('YYYY-mm-dd HH:MM:SS:sss', new Date(timestamp * 1000))
|
|
|
+ },
|
|
|
+ dateFormat(fmt, date) {
|
|
|
+ let ret;
|
|
|
+ const opt = {
|
|
|
+ "Y+": date.getFullYear().toString(), // 年
|
|
|
+ "m+": (date.getMonth() + 1).toString(), // 月
|
|
|
+ "d+": date.getDate().toString(), // 日
|
|
|
+ "H+": date.getHours().toString(), // 时
|
|
|
+ "M+": date.getMinutes().toString(), // 分
|
|
|
+ "S+": date.getSeconds().toString(), // 秒
|
|
|
+ "s+": date.getMilliseconds().toString() // 毫秒
|
|
|
+ // 有其他格式化字符需求可以继续添加,必须转化成字符串
|
|
|
+ };
|
|
|
+ for (let k in opt) {
|
|
|
+ ret = new RegExp("(" + k + ")").exec(fmt);
|
|
|
+ if (ret) {
|
|
|
+ fmt = fmt.replace(ret[1], (ret[1].length === 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, "0")))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return fmt;
|
|
|
+ },
|
|
|
+ // 最后四位
|
|
|
+ getSimpleStr (str) {
|
|
|
+ if (str && str.indexOf('x') !== -1) {
|
|
|
+ return str.substr(0, 7) + '...' + str.substr(-4)
|
|
|
+ } else {
|
|
|
+ return ''
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async getRecord () {
|
|
|
+ let url = 'http://410eth.com/data/getRecordByMySelf'
|
|
|
+ if (process.env.NODE_ENV === 'development') {
|
|
|
+ url = '/api/data/getRecordByMySelf'
|
|
|
+ }
|
|
|
+ this.loading = true
|
|
|
+ if (this.searched) {
|
|
|
+ this.query.t1 = this.query.t1_str ? this.dateToTimestamp(this.query.t1_str) : ''
|
|
|
+ this.query.t2 = this.query.t2_str ? this.dateToTimestamp(this.query.t2_str) : ''
|
|
|
+ }
|
|
|
+ const data = await axios.get(url, { params: this.query })
|
|
|
+ this.tableData.length = 0
|
|
|
+
|
|
|
+ data.data.data.map(function (one) {
|
|
|
+ one.origin = one.o
|
|
|
+ one.o = JSON.parse(one.o.replaceAll("'", '"'))
|
|
|
+ one.blockNumber = one.o.blockNumber
|
|
|
+ one.gas = one.o.gas
|
|
|
+ one.nonce = one.o.nonce
|
|
|
+ one.profit = one.o.profit
|
|
|
+ one.symbolAddress = one.o.symbolAddress
|
|
|
+ })
|
|
|
+
|
|
|
+ this.tableData = data.data.data
|
|
|
+ this.loading = false
|
|
|
+ },
|
|
|
+ dateToTimestamp (str) {
|
|
|
+ let [a, b] = str.split(' ')
|
|
|
+ let [year, month, day] = a.split('/')
|
|
|
+ let [hour, minute, second] = b.split(':')
|
|
|
+
|
|
|
+ return new Date(year, month - 1, day, hour, minute, second).getTime() / 1000
|
|
|
+ },
|
|
|
+ jump (pairAddress) {
|
|
|
+ window.open('https://etherscan.io/address/' + pairAddress)
|
|
|
+ },
|
|
|
+ searchData () {
|
|
|
+ this.searched = true
|
|
|
+ this.getRecord()
|
|
|
+ clearInterval(this.intervalID)
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ data: () => ({
|
|
|
+ query: {
|
|
|
+ t1: '',
|
|
|
+ t1_str: '',
|
|
|
+ t2: '',
|
|
|
+ t2_str: '',
|
|
|
+ fm: '',
|
|
|
+ t: '',
|
|
|
+ state: '',
|
|
|
+ hs: ''
|
|
|
+ },
|
|
|
+ search: '',
|
|
|
+ loading: false,
|
|
|
+ headers: [
|
|
|
+ { text: 'Save Time', value: 'ts' },
|
|
|
+ // { text: 'Sender', value: 'fm' },
|
|
|
+ { text: '类型', value: 'type' },
|
|
|
+ { text: 'Symbol', value: 'symbolAddress' },
|
|
|
+ { text: '交易数量', value: 'amount' },
|
|
|
+ { text: '利润', value: 'profit' },
|
|
|
+ { text: 'Gas', value: 'gas' },
|
|
|
+ { text: '状态', value: 'state' },
|
|
|
+ { text: 'BlockNumber', value: 'blockNumber' },
|
|
|
+ { text: 'Nonce', value: 'nonce' },
|
|
|
+ { text: 'Hash', value: 'hs' },
|
|
|
+ { text: ' ', value: 'origin' }
|
|
|
+ ],
|
|
|
+ history: {"data":[{"t":"0x8a2a17e7adb6cbf6635380a35c04c01db473ed5ca919706f1c492d3aa1d9f1a9","fm":"0x6ff6f16a2459114fad74eed1604b402b97b02717","hs":"0x8a2a17e7adb6cbf6635380a35c04c01db473ed5ca919706f1c492d3aa1d9f1a9","state":"ok","ts":1602503469,"o":"{'type': 'NO TOKEN', 'intoken': 'WETH', 'outtoken': false, 'inamount': 0.314674952033383, 'outamount': 48953401866254456333, 'symbol': false, 'gas': 56.100000233, 'profit': 0, 'balance': 0, 'stocks': 0, 'decimals': 18, 'symbolAddress': '0x054f76beed60ab6dbeb23502178c52d6c5debe40', 'pairAddress': false, 'from': '0x6ff6f16a2459114fad74eed1604b402b97b02717', 'to': '0x8a2a17e7adb6cbf6635380a35c04c01db473ed5ca919706f1c492d3aa1d9f1a9', 'hs': '0x8a2a17e7adb6cbf6635380a35c04c01db473ed5ca919706f1c492d3aa1d9f1a9'}"}],"count":1,"state":"ok"},
|
|
|
+ tableData: [],
|
|
|
+ intervalID: 0,
|
|
|
+ searched: false
|
|
|
+ }),
|
|
|
+
|
|
|
+ mounted() {
|
|
|
+ this.query.t2_str = '2099/1/1 0:0:0'
|
|
|
+ this.query.t1_str = this.dateFormat('YYYY/mm/dd HH:MM:SS', new Date(new Date().getTime() - 10 * 60 * 1000))
|
|
|
+
|
|
|
+ const app = this
|
|
|
+
|
|
|
+ app.query.t1 = parseInt(((new Date().getTime()) / 1000 - 2 * 60) + '')
|
|
|
+ app.getRecord()
|
|
|
+
|
|
|
+ app.intervalID = setInterval(function () {
|
|
|
+ if (!app.loading) {
|
|
|
+ app.query.t1 = parseInt(((new Date().getTime()) / 1000) + '')
|
|
|
+ app.getRecord()
|
|
|
+ }
|
|
|
+ }, 10 * 1000)
|
|
|
+ }
|
|
|
+ }
|
|
|
+</script>
|
|
|
+cl
|