Table.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552
  1. <template>
  2. <div class="table-container">
  3. <v-card elevation="0">
  4. <!-- 表格上功能区 -->
  5. <v-card-title>
  6. <v-container id="dataTableHeader">
  7. <v-row>
  8. <v-col cols="4">
  9. {{ page.name }}
  10. </v-col>
  11. <v-col cols="8">
  12. <v-text-field hide-details single-line label="Local Search" append-icon="mdi-magnify"
  13. v-model="table.search"/>
  14. </v-col>
  15. </v-row>
  16. </v-container>
  17. </v-card-title>
  18. <!-- 顶部分页 -->
  19. <div class="mt-2">
  20. <v-row>
  21. <v-col cols="2"></v-col>
  22. <v-col cols="2">
  23. <v-text-field required type="number" label="page" v-model="tempPage" @change="inputPageNum"/>
  24. </v-col>
  25. <v-col cols="4">
  26. <v-pagination color="teal" :disabled="table.loading" :length="table.pageLength" v-model="table.pageNum"
  27. @input="generateTableDataAgain"></v-pagination>
  28. </v-col>
  29. </v-row>
  30. </div>
  31. <!-- 表格主体 -->
  32. <v-data-table calculate-widths multi-sort hide-default-footer
  33. class="history-table"
  34. @current-items="currentItems"
  35. @input="input"
  36. @item-selected="itemSelected"
  37. @item-expanded="itemExpanded"
  38. @page-count="pageCount"
  39. @pagination="pagination"
  40. @toggle-select-all="toggleSelectAll"
  41. @update:expanded="updateExpanded"
  42. @update:group-by="updateGroupBy"
  43. @update:group-desc="updateGroupEesc"
  44. @update:items-per-page="updateItemsPerPage"
  45. @update:multi-sort="updateMultiSort"
  46. @update:must-sort="updateMustSort"
  47. @update:options="updateOptions"
  48. @update:page="updatePage"
  49. @update:sort-by="updateSortBy"
  50. @update:sort-desc="updateSortDesc"
  51. @toggle="toggle"
  52. @dblclick:row="dblclickRow"
  53. :group-by="table.groupBy" :group-desc="table.groupDesc"
  54. :headers="table.headers" :items="table.data" :search="table.search" :loading="table.loading"
  55. :items-per-page="table.pageSize"
  56. :sort-by="table.sortBy" :sort-desc="table.sortDesc">
  57. <!-- 操作区 -->
  58. <template v-slot:item.option="{ item }">
  59. <div>
  60. <v-row>
  61. <v-col cols="5">
  62. <v-btn large icon elevation="0" color="primary" @click="editItem(item)">
  63. <v-icon>mdi-table-edit</v-icon>
  64. </v-btn>
  65. </v-col>
  66. </v-row>
  67. </div>
  68. </template>
  69. <!-- Block -->
  70. <template v-slot:item.block="{ item }">
  71. <div>
  72. {{ item.block }}
  73. </div>
  74. </template>
  75. <!-- Hash -->
  76. <template v-slot:item.hash="{ item }">
  77. <v-btn v-if="item.hash.indexOf('0x') !== -1" outlined text target="_blank"
  78. @click="httpKit.jumpToExplorer(item.hash, 'tx')">
  79. {{ hashKit.head5(item.hash) + '..' }}
  80. </v-btn>
  81. <v-chip v-else label target="_blank">
  82. {{ hashKit.head5(item.hash) + '..' }}
  83. </v-chip>
  84. </template>
  85. <!-- From -->
  86. <template v-slot:item.from="{ item }">
  87. <v-chip v-if="!item.fromName" label color="indigo lighten-3" @click="httpKit.jumpToExplorer(item.to)">
  88. {{ hashKit.headAndEnd2(item.from) }}
  89. </v-chip>
  90. <v-chip v-else label color="green lighten-3" target="_blank" @click="httpKit.jumpToExplorer(item.from)">
  91. {{ item.fromName }}
  92. </v-chip>
  93. </template>
  94. <!-- to -->
  95. <template v-slot:item.to="{ item }">
  96. <v-chip v-if="!item.toName" label color="indigo lighten-4" @click="httpKit.jumpToExplorer(item.to)">
  97. {{ hashKit.headAndEnd2(item.to) }}
  98. </v-chip>
  99. <v-chip v-else label color="indigo lighten-4" @click="httpKit.jumpToExplorer(item.to)">
  100. {{ item.toName }}
  101. </v-chip>
  102. </template>
  103. <template v-slot:item.type="{ item }">
  104. <div v-if="item.type !== undefined && item.type !== ''">
  105. {{ item.type }}
  106. </div>
  107. <div v-else>
  108. [type]
  109. </div>
  110. </template>
  111. <template v-slot:item.index="{ item }">
  112. <div v-if="item.index !== undefined">
  113. {{ item.index }}
  114. </div>
  115. <div v-else>
  116. [index]
  117. </div>
  118. </template>
  119. <template v-slot:item.status="{ item }">
  120. <div v-if="item.status !== undefined">
  121. {{ item.status }}
  122. </div>
  123. <div v-else>
  124. [status]
  125. </div>
  126. </template>
  127. <template v-slot:item.ping="{ item }">
  128. <div v-if="item.ping !== undefined">
  129. {{ item.ping }}
  130. </div>
  131. <div v-else>
  132. [ping]
  133. </div>
  134. </template>
  135. <template v-slot:item.isMev="{ item }">
  136. <BooleanViewer :value="item.isMev"></BooleanViewer>
  137. </template>
  138. <template v-slot:item.isBot="{ item }">
  139. <BooleanViewer :value="item.isBot"></BooleanViewer>
  140. </template>
  141. <template v-slot:item.maybeBot="{ item }">
  142. <BooleanViewer :value="item.maybeBot"></BooleanViewer>
  143. </template>
  144. <template v-slot:item.timestamp="{ item }">
  145. {{ formatTimeBySixBitTimestamp(item.timestamp) }}
  146. </template>
  147. <template v-slot:item.comment="{ item }">
  148. <div v-if="item.comment">
  149. <span class="memo-span">{{ item.comment }}</span>
  150. </div>
  151. <div v-else>
  152. [comment]
  153. </div>
  154. </template>
  155. <!--tradeInfo-->
  156. <template v-slot:item.transferList="{ item }">
  157. <div v-if="page.name === 'Pending Page'">
  158. <div class="tradeInfoBtn" @click="showTradeInfo(item)">
  159. <v-chip v-for="tokenAddress in item.tokenAddressList" :key='tokenAddress'
  160. :color="item.tokenMap[tokenAddress] ? hashKit.generateColorByHash(tokenAddress) : undefined"
  161. class="tokenChip">
  162. {{
  163. item.tokenMap[tokenAddress] ? item.tokenMap[tokenAddress] : '**' + hashKit.headAndEnd2(tokenAddress)
  164. }}
  165. </v-chip>
  166. </div>
  167. </div>
  168. <div v-else>
  169. <TradeInfo :item="item"></TradeInfo>
  170. </div>
  171. </template>
  172. </v-data-table>
  173. <!-- 底部分页 -->
  174. <div class="mt-2">
  175. <v-row>
  176. <v-col cols="2"></v-col>
  177. <v-col cols="2">
  178. <v-text-field type="number" required label="page" v-model="tempPage" @change="inputPageNum"/>
  179. </v-col>
  180. <v-col cols="4">
  181. <v-pagination :disabled="table.loading" :length="table.pageLength" v-model="table.pageNum"
  182. @input="generateTableDataAgain"></v-pagination>
  183. </v-col>
  184. </v-row>
  185. </div>
  186. </v-card>
  187. <!-- 展示transfer的详情 -->
  188. <v-dialog v-model="transferDetailsDialog.visible" max-width="800">
  189. <v-card elevation="0">
  190. <v-card-title>交易详情</v-card-title>
  191. <v-card-text>
  192. <TradeInfo :item="transferDetailsDialog.data"></TradeInfo>
  193. </v-card-text>
  194. <v-card-actions>
  195. <v-spacer></v-spacer>
  196. <v-btn text color="primary" @click="transferDetailsDialog.visible = false">我知道了</v-btn>
  197. </v-card-actions>
  198. </v-card>
  199. </v-dialog>
  200. <!-- 编辑框 -->
  201. <v-dialog v-model="editDialog.visible" max-width="1200">
  202. <v-card elevation="0">
  203. <v-card-title>编辑详情</v-card-title>
  204. <v-card-text>
  205. <v-row>
  206. <v-col cols="12">
  207. <v-text-field disabled label="hash" v-model="editDialog.item.hash"></v-text-field>
  208. </v-col>
  209. </v-row>
  210. <v-row>
  211. <v-col cols="12">
  212. <v-text-field label="comment" v-model="editDialog.item.comment"></v-text-field>
  213. </v-col>
  214. </v-row>
  215. <v-row>
  216. <v-col cols="6">
  217. <v-text-field disabled label="from" v-model="editDialog.item.from"></v-text-field>
  218. </v-col>
  219. <v-col cols="6">
  220. <v-text-field label="fromName" v-model="editDialog.item.fromName"></v-text-field>
  221. </v-col>
  222. </v-row>
  223. <v-row>
  224. <v-col cols="6">
  225. <v-text-field disabled label="to" v-model="editDialog.item.to"></v-text-field>
  226. </v-col>
  227. <v-col cols="6">
  228. <v-text-field label="toName" v-model="editDialog.item.toName"></v-text-field>
  229. </v-col>
  230. </v-row>
  231. </v-card-text>
  232. <v-card-actions>
  233. <v-spacer></v-spacer>
  234. <v-btn text color="primary" @click="updateAdapter">提交编辑</v-btn>
  235. </v-card-actions>
  236. </v-card>
  237. </v-dialog>
  238. </div>
  239. </template>
  240. <script>
  241. import TradeInfo from '@/components/viewer/history/table/TradeInfoDetails'
  242. import BooleanViewer from '@/components/viewer/history/table/BooleanViewer'
  243. import HashKit from '@/plugins/kit/HashKit'
  244. import HttpKit from '@/plugins/kit/HttpKit'
  245. import TimeKit from '@/plugins/kit/TimeKit'
  246. import AddressModel from "@/plugins/model/AddressModel";
  247. import jquery from 'jquery'
  248. export default {
  249. name: 'Table',
  250. components: {BooleanViewer, TradeInfo},
  251. props: ['query', 'page', 'table', 'tx'],
  252. inject: ['packQuery'],
  253. data: () => ({
  254. hashKit: HashKit,
  255. httpKit: HttpKit,
  256. timeKit: TimeKit,
  257. transferDetailsDialog: {
  258. data: [],
  259. visible: false
  260. },
  261. editDialog: {
  262. item: {},
  263. visible: false
  264. },
  265. tempPage: 1,
  266. addressModel: undefined,
  267. dblclickRowUrl: "https://tools.blocksec.com/tx/eth/",
  268. }),
  269. methods: {
  270. async deleteByHash(hash_code, item) {
  271. if (confirm('要删吗?\n' + hash_code)) {
  272. console.log(JSON.stringify(item))
  273. this.$msgkit.warning('还没有做,别急啊')
  274. // const rst = await EthMev.deleteByHash(hash_code)
  275. //
  276. // if (rst.data.state) {
  277. // this.$msgkit.success(rst.data.msg)
  278. //
  279. // await this.pullData()
  280. // } else {
  281. // this.$msgkit.error(rst.data.msg)
  282. // }
  283. }
  284. },
  285. async updateAdapter() {
  286. this.createAddressModel()
  287. const updateItem = this.editDialog.item
  288. const txBaseItem = {
  289. hash: updateItem.hash,
  290. comment: updateItem.comment
  291. }
  292. const fromAddrBaseItem = {
  293. hash: updateItem.from,
  294. name: updateItem.fromName
  295. }
  296. const toAddrBaseItem = {
  297. hash: updateItem.to,
  298. name: updateItem.toName
  299. }
  300. const rst1 = await this.tx.updateTxBaseModel(txBaseItem)
  301. const rst2 = await this.addressModel.updateAddressBaseModel(fromAddrBaseItem)
  302. const rst3 = await this.addressModel.updateAddressBaseModel(toAddrBaseItem)
  303. if (rst1.state && rst2.state && rst3.state) {
  304. this.$msgkit.success('更新成功')
  305. this.editDialog.visible = false
  306. } else {
  307. this.$msgkit.error(`rst1: ${rst1.msg}, rst2: ${rst2.msg}, rst3: ${rst3.msg}`)
  308. }
  309. },
  310. showTradeInfo(item) {
  311. this.transferDetailsDialog.data = item
  312. this.transferDetailsDialog.visible = true
  313. },
  314. async inputPageNum() {
  315. this.table.pageNum = parseInt(this.tempPage)
  316. await this.generateTableDataAgain()
  317. },
  318. async generateTableDataAgain() {
  319. this.tempPage = this.table.pageNum
  320. this.table.data = []
  321. await this.packQuery()
  322. },
  323. formatTimeBySixBitTimestamp(sixBitTimestamp) {
  324. let lastThreeBit = (sixBitTimestamp + '').slice(-3)
  325. return this.timeKit.getTime(sixBitTimestamp) + lastThreeBit
  326. },
  327. editItem(item) {
  328. this.editDialog.item = item
  329. this.editDialog.visible = true
  330. },
  331. createAddressModel() {
  332. if (!this.addressModel) this.addressModel = new AddressModel(this.tx.chainId, AddressModel.MODULES.unknown)
  333. },
  334. currentItems(val) {
  335. console.log("currentItems:", val)
  336. },
  337. input(val) {
  338. console.log("input:", val)
  339. },
  340. itemSelected(val) {
  341. console.log("itemSelected:", val)
  342. },
  343. pageCount(val) {
  344. console.log("pageCount:", val)
  345. },
  346. pagination(val) {
  347. console.log("pagination:", val)
  348. if (val.itemsLength === 0) {
  349. this.remButRegroupAll()
  350. }
  351. if (val.itemsLength > 0) {
  352. this.addButRegroup()
  353. }
  354. },
  355. toggleSelectAll(val) {
  356. console.log("toggleSelectAll:", val)
  357. },
  358. updateExpanded(val) {
  359. console.log("updateExpanded:", val)
  360. },
  361. updateGroupBy(val) {
  362. console.log("updateGroupBy:", val)
  363. },
  364. updateGroupEesc(val) {
  365. console.log("updateGroupEesc:", val)
  366. },
  367. updateItemsPerPage(val) {
  368. console.log("updateItemsPerPage:", val)
  369. },
  370. updateMultiSort(val) {
  371. console.log("updateMultiSort:", val)
  372. },
  373. updateMustSort(val) {
  374. console.log("updateMustSort:", val)
  375. },
  376. updateOptions(val) {
  377. console.log("updateOptions:", val)
  378. },
  379. updatePage(val) {
  380. console.log("updatePage:", val)
  381. },
  382. updateSortBy(val) {
  383. console.log("updateSortBy:", val)
  384. },
  385. updateSortDesc(val) {
  386. console.log("updateSortDesc:", val)
  387. },
  388. itemExpanded(item, val) {
  389. console.log("itemExpanded:", item, val)
  390. },
  391. toggle(val) {
  392. console.log("toggle:", val)
  393. },
  394. dblclickRow(event, value) {
  395. console.log("dblclickRow:", event, value)
  396. },
  397. //赋予按钮第二个点击事件
  398. addButClick(explorer) {
  399. jquery(".history-table div.v-data-table__wrapper table tbody").on("click", ".v-row-group__header td.text-start", function (dom) {
  400. console.log("当前访问:", this.tx, dom)
  401. //需要移除临时 并已经作废的标签
  402. var array_del = jquery("a.temporary_label")
  403. for (var d = 0; d < array_del.length; d++) {
  404. var a = array_del.eq(d)[0]
  405. var tr = jquery(jquery(a).parent().parent())[0]
  406. var className = tr.className
  407. if (className.indexOf("v-row-group__header") === -1) {
  408. jquery(a).remove()
  409. }
  410. }
  411. var array = jquery(".history-table div.v-data-table__wrapper table tbody .v-row-group__header td.text-start");
  412. for (var i = 0; i < array.length; i++) {
  413. //思路:根据 jq 拿到对应的td 然后循环遍历 动态添加元素标签
  414. var td = array.eq(i)[0]
  415. var innerText = td.innerText
  416. var but_x = jquery(td).children()[1]
  417. if (jquery(td).children().length > 2) {
  418. } else {
  419. //添加
  420. var href = explorer + "/block/" + innerText.split(": ")[1];
  421. var a = '<a class="temporary_label" href="' + href + '" target="_blank"> 跳转 </a>';
  422. jquery(but_x).before(a)
  423. }
  424. }
  425. })
  426. },
  427. //添加跳转标签
  428. addButRegroup(explorer) {
  429. var array = jquery(".history-table div.v-data-table__wrapper table tbody .v-row-group__header td.text-start");
  430. console.log(array)
  431. for (var i = 0; i < array.length; i++) {
  432. //思路:根据 jq 拿到对应的td 然后循环遍历 动态添加元素标签
  433. var td = array.eq(i)[0]
  434. var innerText = td.innerText
  435. var but_x = jquery(td).children()[1]
  436. if (jquery(td).children().length > 2) {
  437. } else {
  438. //添加
  439. var href = explorer + "/block/" + innerText.split(": ")[1];
  440. var a = '<a class="temporary_label" href="' + href + '" target="_blank"> 跳转 </a>';
  441. jquery(but_x).before(a)
  442. }
  443. }
  444. },
  445. //需要移除临时 并已经作废的标签
  446. remButRegroup() {
  447. var array_del = jquery("a.temporary_label")
  448. for (var d = 0; d < array_del.length; d++) {
  449. var a = array_del.eq(d)[0]
  450. var tr = jquery(jquery(a).parent().parent())[0]
  451. var className = tr.className
  452. if (className.indexOf("v-row-group__header") === -1) {
  453. jquery(a).remove()
  454. }
  455. }
  456. },
  457. remButRegroupAll() {
  458. var array_del = jquery("a.temporary_label")
  459. for (var d = 0; d < array_del.length; d++) {
  460. var a = array_del.eq(d)[0]
  461. jquery(a).remove()
  462. }
  463. },
  464. showIfHide(boo) {
  465. var array = jquery("a.temporary_label")
  466. if (array.length > 0) {
  467. var a = array[0]
  468. if (boo)
  469. jquery(a).hide()
  470. else
  471. jquery(a).show()
  472. }
  473. },
  474. },
  475. async mounted() {
  476. // let vm = new Vue({
  477. // el: "td.text-start",
  478. // click: () => {
  479. // console.log('点击')
  480. // }
  481. // });
  482. // $("td.text-start").on("click",this,function (){
  483. // console.log('点击')
  484. // });
  485. }
  486. }
  487. </script>
  488. <style scoped>
  489. .table-container {
  490. width: 100%;
  491. }
  492. #dataTableHeader {
  493. max-width: none;
  494. }
  495. .tokenChip {
  496. margin-top: 5px;
  497. margin-left: 5px;
  498. margin-bottom: 5px;
  499. }
  500. .tradeInfoBtn {
  501. padding: 15px !important;
  502. border: grey 2px solid;
  503. }
  504. .tradeInfoBtn:hover {
  505. background: beige;
  506. }
  507. .memo-span {
  508. width: 200px;
  509. display: block;
  510. padding: 10px;
  511. }
  512. </style>