Explorar o código

pending页面完成

skyfffire %!s(int64=3) %!d(string=hai) anos
pai
achega
d38ee1d6c0
Modificáronse 3 ficheiros con 378 adicións e 7 borrados
  1. 12 7
      src/App.vue
  2. 354 0
      src/components/Pending.vue
  3. 12 0
      src/plugins/model/EthMev.js

+ 12 - 7
src/App.vue

@@ -21,17 +21,17 @@
         v-model="tab"
         v-if="calcPwdMD5() === pwdMD5"
       >
+        <v-tab
+            key="pending"
+        >
+          Pending
+        </v-tab>
         <v-tab
           key="history"
         >
           History
         </v-tab>
 <!--        <v-tab-->
-<!--          key="new"-->
-<!--        >-->
-<!--          最新动态-->
-<!--        </v-tab>-->
-<!--        <v-tab-->
 <!--            key="my"-->
 <!--        >-->
 <!--          我的交易-->
@@ -89,6 +89,9 @@
         v-model="tab"
         v-else
       >
+        <v-tab-item key="pending">
+          <Pending></Pending>
+        </v-tab-item>
         <v-tab-item key="history">
           <History></History>
         </v-tab-item>
@@ -100,17 +103,19 @@
 <script>
 
 import History from "@/components/History";
+import Pending from "@/components/Pending";
 import md5 from 'md5-node'
 
 export default {
   name: 'App',
 
   components: {
-    History
+    History,
+    Pending
   },
 
   data: () => ({
-    tab: 'history',
+    tab: 'pending',
     pwdMD5: '7f5029bbd4daae18f3ae4cd910f0f4f0',
     pwd: ''
   }),

+ 354 - 0
src/components/Pending.vue

@@ -0,0 +1,354 @@
+<template>
+  <v-card
+      elevation="1"
+  >
+    <v-container>
+      <v-row>
+        <!-- block过滤 -->
+        <v-col
+            cols="18"
+            md="2"
+        >
+          <v-text-field
+              v-model="query.block"
+              label="BlockNumber"
+              required
+          ></v-text-field>
+        </v-col>
+
+        <!-- hash过滤 -->
+        <v-col
+            cols="18"
+            md="2"
+        >
+          <v-text-field
+              v-model="query.hash"
+              label="Hash"
+              required
+          ></v-text-field>
+        </v-col>
+
+        <!-- data过滤 -->
+        <v-col
+            cols="18"
+            md="6"
+        >
+          <v-text-field
+              v-model="query.dataVague"
+              label="Data"
+              required
+          ></v-text-field>
+        </v-col>
+
+        <v-col
+            cols="18"
+            md="1"
+        >
+          <v-btn outlined x-large tile color="primary" @click="generateHistoryData">
+            <v-icon>mdi-cloud-search-outline</v-icon>
+          </v-btn>
+        </v-col>
+      </v-row>
+    </v-container>
+
+    <v-card
+      elevation="0"
+    >
+      <v-card-title>
+        <v-container id="dataTableHeader">
+          <v-row>
+            <v-col cols="4">
+              Pending Data
+            </v-col>
+            <v-col cols="8">
+              <v-text-field
+                  v-model="search"
+                  append-icon="mdi-magnify"
+                  label="Local Search"
+                  single-line
+                  hide-details
+              ></v-text-field>
+            </v-col>
+          </v-row>
+
+          <v-row>
+            <v-col cols="12">
+                Block: {{ showBlock }}
+            </v-col>
+          </v-row>
+        </v-container>
+      </v-card-title>
+
+      <v-data-table
+        multi-sort
+        group-by="block"
+        calculate-widths
+        :headers="headers"
+        :items="tableData"
+        :search="search"
+        :items-per-page="200"
+        :loading="loading"
+        :sort-by="['block', 'gasPrice', 'pending']"
+        :sort-desc="[false, true, false]"
+      >
+        <template v-slot:item.option="{ item }">
+          <div @mouseenter="changeShowBlock(item, false)">
+            <v-row>
+              <!--            <v-col cols="5">-->
+              <!--              <v-btn icon elevation="0" color="blue" small>-->
+              <!--                <v-icon small>mdi-pencil-outline</v-icon>-->
+              <!--              </v-btn>-->
+              <!--            </v-col>-->
+              <v-col cols="5">
+                <v-btn icon elevation="0" color="red" large @click="deleteByHash(item.hash)">
+                  <v-icon large>mdi-delete-forever-outline</v-icon>
+                </v-btn>
+              </v-col>
+            </v-row>
+          </div>
+        </template>
+        <!-- Block -->
+        <template v-slot:item.block="{ item }">
+          <div @mouseenter="changeShowBlock(item, false)">
+            {{ item.block }}
+          </div>
+        </template>
+        <!-- Hash -->
+        <template v-slot:item.hash="{ item }">
+          <v-chip
+              label
+              :href="'https://www.oklink.com/en/ethw/tx/' + item.hash"
+              target="_blank"
+          >
+            {{ hashKit.head5(item.hash) + '..'  }}
+          </v-chip>
+        </template>
+        <!-- From -->
+        <template v-slot:item.from="{ item }">
+          <v-chip
+              label
+              color="green lighten-3" target="_blank"
+              @click="httpKit.jumpToEthw(item.from)"
+          >
+            {{ hashKit.headAndEnd2(item.from) }}
+          </v-chip>
+        </template>
+        <!-- to -->
+        <template v-slot:item.to="{ item }">
+          <v-chip label
+              color="indigo lighten-4"
+              @click="httpKit.jumpToEthw(item.to)"
+              v-if="!item.toName"
+          >
+            {{ hashKit.headAndEnd2(item.to) }}
+          </v-chip>
+          <v-chip
+              label
+              color="indigo lighten-4"
+              @click="httpKit.jumpToEthw(item.to)"
+              v-else
+          >
+            {{ item.toName }}
+          </v-chip>
+        </template>
+        <template v-slot:item.type="{ item }">
+          <div v-if="item.type !== undefined && item.type !== ''">
+            {{ item.type }}
+          </div>
+          <div v-else>
+            [type]
+          </div>
+        </template>
+        <template v-slot:item.index="{ item }">
+          <div v-if="item.index !== undefined">
+            {{ item.index }}
+          </div>
+          <div v-else>
+            [index]
+          </div>
+        </template>
+        <template v-slot:item.state="{ item }">
+          <div v-if="item.state !== undefined">
+            {{ item.state }}
+          </div>
+          <div v-else>
+            [state]
+          </div>
+        </template>
+        <template v-slot:item.mev="{ item }">
+          <div v-if="item.mev !== undefined">
+            {{ item.mev }}
+          </div>
+          <div v-else>
+            [mev]
+          </div>
+        </template>
+        <template v-slot:item.pending="{ item }">
+          <div v-if="item.pending !== undefined">
+            {{ item.pending }}
+          </div>
+          <div v-else>
+            [pending]
+          </div>
+        </template>
+        <!--tradeInfo-->
+        <template v-slot:item.tradeInfo="{ item }">
+          <TradeInfo :item="item"></TradeInfo>
+        </template>
+      </v-data-table>
+    </v-card>
+
+    <v-snackbar
+        v-model="blockSnackbar"
+        timeout="100000"
+        color="blue-grey"
+    >
+      block: {{ showBlock }}
+
+      <template v-slot:action="{ attrs }">
+        <v-btn
+            color="white"
+            text
+            v-bind="attrs"
+            @click="blockSnackbar = false"
+        >
+          Close
+        </v-btn>
+      </template>
+    </v-snackbar>
+  </v-card>
+</template>
+
+<script>
+  import NumKit from '@/plugins/kit/NumKit'
+  import HashKit from '@/plugins/kit/HashKit'
+  import HttpKit from '@/plugins/kit/HttpKit'
+  import EthMev from '@/plugins/model/EthMev'
+  import TradeInfo from '@/components/history/TradeInfo';
+
+  export default {
+    name: 'Pending',
+    components: { TradeInfo },
+    methods: {
+      // 获取数据
+      async generateHistoryData () {
+        this.tableData.length = 0
+
+        this.loading = true
+        const rst = await EthMev.getEthMevPendingData(this.query.block, this.query.hash, this.query.dataVague)
+        this.loading = false
+
+        if (!rst.data.state) {
+          this.$msgkit.error(rst.data.msg)
+
+          return
+        }
+
+        this.$msgkit.success(rst.data.msg)
+        this.tableData = rst.data.data
+
+        this.tableData.map(function (one) {
+          try {
+            let dataObj = one.dataObj
+
+            one.tradeInfo = dataObj.tradeInfo
+            one.from = dataObj.fromAdd
+            one.to = dataObj.toAdd
+            one.gasPrice = NumKit._N(parseInt(dataObj.gasPrice) / (10 ** 9), 2)
+            one.index = dataObj.index
+            one.type = dataObj.type
+            one.state = dataObj.status
+            one.pending = dataObj.pending
+          } catch (e) {
+            one.tradeInfo = []
+          }
+        })
+      },
+      async deleteByHash(hash_code) {
+        if (confirm('要删吗?\n' + hash_code)) {
+          const rst = await EthMev.deleteByHash(hash_code)
+
+          if (rst.data.state) {
+            this.$msgkit.success(rst.data.msg)
+
+            await this.pullData()
+          } else {
+            this.$msgkit.error(rst.data.msg)
+          }
+        }
+      },
+      logInfo (info) {
+        console.log(info)
+      },
+      changeShowBlock (item, openSnackbar) {
+        if (openSnackbar) this.blockSnackbar = true
+        this.showBlock = item.block
+      }
+    },
+
+    data: () => ({
+      hashKit: HashKit,
+      httpKit: HttpKit,
+      query: {
+        block: '',
+        hash: '',
+        dataVague: ''
+      },
+      blockSnackbar: false,
+      search: '',
+      showBlock: 0,
+      loading: false,
+      headers: [
+        { text: "Option", value: 'option' },
+        { text: 'Block', value: 'block' },
+        { text: 'Hash', value: 'hash' },
+        { text: 'From', value: 'from' },
+        { text: 'To', value: 'to' },
+        { text: 'GasPrice', value: 'gasPrice' },
+        { text: 'Type', value: 'type' },
+        { text: 'Index', value: 'index' },
+        { text: 'State', value: 'state' },
+        { text: 'Mev', value: 'mev' },
+        { text: 'Pending', value: 'pending' },
+        // { text: 'TradeInfo', value: 'tradeInfo'}
+      ],
+      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: []
+    }),
+
+    async mounted () {
+      await this.generateHistoryData()
+    }
+  }
+</script>
+
+<style>
+#dataTable {
+  height: 410px;
+}
+#dataTableHeader {
+  max-width: none;
+}
+.tradeLabel {
+  width: 250px;
+}
+thead.v-data-table-header {
+  position: fixed !important;
+  bottom: 0 !important;
+  z-index: 999;
+  background-color: rgba(255, 255, 255, 255);
+  width: 95%;
+  border-top: grey 1px solid;
+}
+div.tokenName {
+  text-align: left;
+  width: 100%;
+}
+div.tokenAmount {
+  text-align: right;
+  width: 100%;
+}
+span.v-chip__content {
+  width: 100%;
+}
+</style>

+ 12 - 0
src/plugins/model/EthMev.js

@@ -13,6 +13,18 @@ export default class EthMev {
     });
   }
 
+  static async getEthMevPendingData(block, hash, dataVague, page=1, size=200) {
+    let url = '/ethmev/findByHashOrBlockOrDataVaguePending'
+
+    return http.post(url, {
+      block: block,
+      hash: hash,
+      dataVague: dataVague,
+      limit1: (page - 1) * size,
+      limit2: size
+    });
+  }
+
   static async deleteByHash(hash) {
     let url = '/ethmev/deleteByHash'