浏览代码

Merge branch 'dev_1.1.0' of DeNet/de-net into master

v1.1.0 【NFT】
wenliming 2 年之前
父节点
当前提交
dd7bb61241
共有 78 个文件被更改,包括 5080 次插入1196 次删除
  1. 二进制
      src/assets/gif/box.gif
  2. 二进制
      src/assets/img/icon-arrow.png
  3. 二进制
      src/assets/img/icon-nft.png
  4. 二进制
      src/assets/img/icon-ntf-share.png
  5. 二进制
      src/assets/img/img-box1.png
  6. 二进制
      src/assets/img/img-box5.png
  7. 6 0
      src/assets/svg/icon-back-head-list.svg
  8. 1 1
      src/assets/svg/icon-currency-category-02.svg
  9. 1 0
      src/assets/svg/icon-default.svg
  10. 3 0
      src/assets/svg/icon-form-refresh-blue.svg
  11. 7 0
      src/assets/svg/icon-get-giveaways-s.svg
  12. 4 0
      src/assets/svg/icon-head-help.svg
  13. 6 0
      src/assets/svg/icon-home-list.svg
  14. 6 0
      src/assets/svg/icon-home-refresh.svg
  15. 6 0
      src/assets/svg/icon-loading-while.svg
  16. 3 0
      src/assets/svg/icon-nft-back-arrow.svg
  17. 8 0
      src/assets/svg/icon-send-giveaways-s.svg
  18. 1 0
      src/assets/svg/icon-tab-NFT-active.svg
  19. 1 0
      src/assets/svg/icon-tab-NFT.svg
  20. 3 0
      src/assets/svg/icon-tab-message-active.svg
  21. 3 0
      src/assets/svg/icon-tab-message.svg
  22. 3 0
      src/assets/svg/icon-tab-more-active.svg
  23. 3 0
      src/assets/svg/icon-tab-more.svg
  24. 3 0
      src/assets/svg/icon-tab-wallet-active.svg
  25. 3 0
      src/assets/svg/icon-tab-wallet.svg
  26. 1 1
      src/assets/svg/icon-telegram.svg
  27. 6 0
      src/assets/svg/icon-wallter-list-blind-box.svg
  28. 19 1
      src/entry/background.js
  29. 30 1
      src/entry/content.js
  30. 23 1
      src/entry/content_help.js
  31. 1 1
      src/http/configAPI.js
  32. 9 1
      src/http/discordApi.js
  33. 41 0
      src/http/nft.js
  34. 7 0
      src/http/pay.js
  35. 8 0
      src/http/publishApi.js
  36. 13 0
      src/iframe/buy-nft.js
  37. 6 0
      src/iframe/nft-card.js
  38. 24 0
      src/iframe/popup-page.js
  39. 9 1
      src/log-center/logEnum.js
  40. 18 1
      src/log-center/logger.js
  41. 98 3
      src/logic/background/twitter.js
  42. 58 20
      src/logic/content/ParseCard.js
  43. 329 24
      src/logic/content/twitter.js
  44. 5 2
      src/manifest.json
  45. 33 0
      src/router/buy-nft.js
  46. 45 5
      src/router/popup.js
  47. 29 1
      src/uilts/help.js
  48. 29 10
      src/view/components/currency-list.vue
  49. 88 44
      src/view/components/popup-transactions.vue
  50. 144 0
      src/view/components/preview-balance.vue
  51. 300 0
      src/view/iframe/buy-nft/buy/home.vue
  52. 142 0
      src/view/iframe/buy-nft/buy/open-box.vue
  53. 431 0
      src/view/iframe/buy-nft/buy/pay.vue
  54. 29 0
      src/view/iframe/buy-nft/components/btn-loading.vue
  55. 40 0
      src/view/iframe/buy-nft/index.vue
  56. 1 0
      src/view/iframe/home/home.vue
  57. 248 0
      src/view/iframe/nft/card.vue
  58. 30 0
      src/view/iframe/popup/index.vue
  59. 1 1
      src/view/iframe/publish/components/follow-input.vue
  60. 117 29
      src/view/iframe/publish/give-dialog.vue
  61. 59 5
      src/view/iframe/red-packet/red-packet.vue
  62. 34 4
      src/view/popup/components/head.vue
  63. 231 0
      src/view/popup/components/tabbar.vue
  64. 68 0
      src/view/popup/components/top-bar.vue
  65. 302 0
      src/view/popup/currency-detail.vue
  66. 8 0
      src/view/popup/index.vue
  67. 0 1028
      src/view/popup/popup.vue
  68. 163 0
      src/view/popup/tabbar-page/index.vue
  69. 667 0
      src/view/popup/tabbar-page/message/index.vue
  70. 115 0
      src/view/popup/tabbar-page/more/index.vue
  71. 424 0
      src/view/popup/tabbar-page/nft/detail.vue
  72. 138 0
      src/view/popup/tabbar-page/nft/index.vue
  73. 359 0
      src/view/popup/tabbar-page/wallter/popup.vue
  74. 5 4
      src/view/popup/top-up/home.vue
  75. 12 1
      src/view/popup/transactions.vue
  76. 5 4
      src/view/popup/withdraw/home.vue
  77. 6 1
      src/view/popup/withdraw/info.vue
  78. 1 1
      src/view/popup/withdraw/success.vue

二进制
src/assets/gif/box.gif


二进制
src/assets/img/icon-arrow.png


二进制
src/assets/img/icon-nft.png


二进制
src/assets/img/icon-ntf-share.png


二进制
src/assets/img/img-box1.png


二进制
src/assets/img/img-box5.png


文件差异内容过多而无法显示
+ 6 - 0
src/assets/svg/icon-back-head-list.svg


+ 1 - 1
src/assets/svg/icon-currency-category-02.svg

@@ -1,3 +1,3 @@
 <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
-<path d="M21 7L12 2L3 7V17L12 22L21 17V7ZM12 4.29L17.91 7.57L14.9 9.24C14.17 8.48 13.14 8 12 8C10.86 8 9.83 8.48 9.1 9.24L6.09 7.57L12 4.29ZM11 19.16L5 15.83V9.26L8.13 11C8.04 11.31 8 11.65 8 12C8 13.86 9.27 15.43 11 15.87V19.16ZM10 12C10 10.9 10.9 10 12 10C13.1 10 14 10.9 14 12C14 13.1 13.1 14 12 14C10.9 14 10 13.1 10 12ZM13 19.16V15.88C14.73 15.44 16 13.87 16 12.01C16 11.66 15.96 11.32 15.87 11L19 9.26V15.83L13 19.16Z" fill="#2CD2C8"/>
+<path d="M12.1243 5.01728L12.1 5.00382L12.0757 5.01728L6.75674 7.96928L6.67795 8.01301L6.75674 8.05672L9.46574 9.55972L9.4994 9.57839L9.52606 9.55064C10.1741 8.87593 11.0883 8.45 12.1 8.45C13.1117 8.45 14.0259 8.87593 14.6739 9.55064L14.7006 9.57839L14.7343 9.55972L17.4433 8.05672L17.5221 8.01301L17.4433 7.96928L12.1243 5.01728ZM11.1757 18.4877L11.25 18.5289V18.444V15.483V15.4441L11.2123 15.4345C9.67711 15.0441 8.55 13.6507 8.55 12C8.55 11.6886 8.5856 11.3875 8.66502 11.1139L8.67613 11.0757L8.64129 11.0563L5.82429 9.4903L5.75 9.449V9.534V15.447V15.4764L5.77574 15.4907L11.1757 18.4877ZM12.95 18.444V18.5289L13.0243 18.4877L18.4243 15.4907L18.45 15.4764V15.447V9.534V9.449L18.3757 9.4903L15.5587 11.0563L15.5242 11.0755L15.5349 11.1135C15.6144 11.3964 15.65 11.6977 15.65 12.009C15.65 13.6597 14.5229 15.0531 12.9877 15.4435L12.95 15.4531V15.492V18.444ZM12.1 3.0572L20.15 7.52942V16.4706L12.1 20.9428L4.05 16.4706V7.52942L12.1 3.0572ZM12.1 10.15C11.0824 10.15 10.25 10.9824 10.25 12C10.25 13.0176 11.0824 13.85 12.1 13.85C13.1176 13.85 13.95 13.0176 13.95 12C13.95 10.9824 13.1176 10.15 12.1 10.15Z" fill="#1D9BF0" stroke="#F7F7F7" stroke-width="0.1"/>
 </svg>

文件差异内容过多而无法显示
+ 1 - 0
src/assets/svg/icon-default.svg


+ 3 - 0
src/assets/svg/icon-form-refresh-blue.svg

@@ -0,0 +1,3 @@
+<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M4.21664 9.31085C4.21664 9.31085 6.4009 5.93844 9.85712 4.12882C13.3133 2.31927 17.5714 2.84021 20.364 4.59492C23.1566 6.34973 24.0968 7.83024 24.0968 7.83024L26.5022 6.45938C26.5022 6.45938 27 6.21266 27 6.78841V15.3978C27 15.3978 27 16.1655 26.4193 15.8912C25.9308 15.6607 20.648 12.655 18.9833 11.7067C18.0691 11.2988 18.8723 10.9673 18.8723 10.9673L21.1935 9.63986C21.1935 9.63986 19.8695 7.98074 17.9315 7.10206C15.8571 6.02069 13.9151 5.89246 11.5362 6.79105C9.985 7.37687 8.15868 8.87707 6.84323 11.093L4.21664 9.31085ZM25.7834 20.6891C25.7834 20.6891 23.5991 24.0616 20.1429 25.8711C16.6866 27.6807 12.4286 27.1599 9.63599 25.4051C6.84326 23.6503 5.90327 22.1697 5.90327 22.1697L3.4977 23.5405C3.4977 23.5405 3 23.7874 3 23.2115V14.6022C3 14.6022 3 13.8346 3.58058 14.1087C4.06912 14.3394 9.35204 17.345 11.0167 18.2933C11.9309 18.7013 11.1278 19.0326 11.1278 19.0326L8.80649 20.3601C8.80649 20.3601 10.1306 22.0192 12.0685 22.8979C14.1428 23.9792 16.0848 24.1075 18.4638 23.2089C20.0149 22.623 21.8412 21.123 23.1566 18.9069L25.7834 20.6891Z" fill="#1D9BF0"/>
+</svg>

文件差异内容过多而无法显示
+ 7 - 0
src/assets/svg/icon-get-giveaways-s.svg


+ 4 - 0
src/assets/svg/icon-head-help.svg

@@ -0,0 +1,4 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<circle opacity="0.4" cx="12" cy="12" r="12" fill="#4E4E4E"/>
+<path d="M12.4852 5.5C11.1784 5.5 10.1541 5.87086 9.41239 6.63024C8.67067 7.37196 8.2998 8.37859 8.2998 9.66777H10.1541C10.1541 8.89073 10.3131 8.29029 10.6309 7.86645C10.9841 7.3543 11.5669 7.10706 12.3616 7.10706C12.9974 7.10706 13.5095 7.28366 13.8627 7.63686C14.1983 7.99007 14.3749 8.46689 14.3749 9.08499C14.3749 9.54415 14.1983 9.96799 13.8804 10.3742L13.5802 10.7097C12.4852 11.681 11.8142 12.4051 11.5846 12.8996C11.3373 13.3587 11.2314 13.9238 11.2314 14.5773V14.8775H13.121V14.5773C13.121 14.1534 13.2093 13.7649 13.4036 13.4117C13.5625 13.0938 13.8097 12.7759 14.1453 12.4934C14.9753 11.7693 15.4698 11.3102 15.6287 11.1159C16.0702 10.5508 16.2998 9.82671 16.2998 8.96137C16.2998 7.90177 15.9466 7.05408 15.2402 6.43598C14.5338 5.80022 13.6155 5.5 12.4852 5.5ZM12.1674 16.096C11.8142 16.096 11.4963 16.202 11.249 16.4492C11.0018 16.6788 10.8782 16.979 10.8782 17.3499C10.8782 17.7031 11.0018 18.0033 11.249 18.2506C11.4963 18.4978 11.8142 18.6214 12.1674 18.6214C12.5206 18.6214 12.8384 18.4978 13.0857 18.2682C13.3329 18.021 13.4742 17.7208 13.4742 17.3499C13.4742 16.979 13.3506 16.6788 13.1033 16.4492C12.8561 16.202 12.5382 16.096 12.1674 16.096Z" fill="white"/>
+</svg>

文件差异内容过多而无法显示
+ 6 - 0
src/assets/svg/icon-home-list.svg


文件差异内容过多而无法显示
+ 6 - 0
src/assets/svg/icon-home-refresh.svg


+ 6 - 0
src/assets/svg/icon-loading-while.svg

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="margin: auto; background: rgb(255, 255, 255,0); display: block; shape-rendering: auto;" width="200px" height="200px" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid">
+<circle cx="50" cy="50" fill="none" stroke="#fff" stroke-width="12" r="35" stroke-dasharray="164.93361431346415 56.97787143782138">
+  <animateTransform attributeName="transform" type="rotate" repeatCount="indefinite" dur="1s" values="0 50 50;360 50 50" keyTimes="0;1"></animateTransform>
+</circle>
+<!-- [ldio] generated by https://loading.io/ --></svg>

+ 3 - 0
src/assets/svg/icon-nft-back-arrow.svg

@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M3.46967 11.4697C3.17678 11.7626 3.17678 12.2374 3.46967 12.5303L8.24264 17.3033C8.53553 17.5962 9.01041 17.5962 9.3033 17.3033C9.59619 17.0104 9.59619 16.5355 9.3033 16.2426L5.06066 12L9.3033 7.75736C9.59619 7.46447 9.59619 6.98959 9.3033 6.6967C9.01041 6.40381 8.53553 6.40381 8.24264 6.6967L3.46967 11.4697ZM20 11.25L4 11.25L4 12.75L20 12.75L20 11.25Z" fill="black"/>
+</svg>

文件差异内容过多而无法显示
+ 8 - 0
src/assets/svg/icon-send-giveaways-s.svg


文件差异内容过多而无法显示
+ 1 - 0
src/assets/svg/icon-tab-NFT-active.svg


文件差异内容过多而无法显示
+ 1 - 0
src/assets/svg/icon-tab-NFT.svg


+ 3 - 0
src/assets/svg/icon-tab-message-active.svg

@@ -0,0 +1,3 @@
+<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M15 24.8203C13.8506 24.8203 12.7405 24.6728 11.6932 24.3981C11.0133 24.2198 9.14472 24.8397 6.0875 26.2578C6.90527 23.6109 7.09915 22.0898 6.66917 21.6945C4.70537 19.8894 3.5 17.4468 3.5 14.7578C3.5 9.20044 8.64872 4.69531 15 4.69531C21.3513 4.69531 26.5 9.20044 26.5 14.7578C26.5 20.3152 21.3513 24.8203 15 24.8203ZM10.4288 16.0803C11.1432 16.0803 11.7225 15.5011 11.7225 14.7866C11.7225 14.0721 11.1432 13.4928 10.4288 13.4928C9.71426 13.4928 9.135 14.0721 9.135 14.7866C9.135 15.5011 9.71426 16.0803 10.4288 16.0803ZM15.0288 16.0803C15.7432 16.0803 16.3225 15.5011 16.3225 14.7866C16.3225 14.0721 15.7432 13.4928 15.0288 13.4928C14.3143 13.4928 13.735 14.0721 13.735 14.7866C13.735 15.5011 14.3143 16.0803 15.0288 16.0803ZM19.6287 16.0803C20.3432 16.0803 20.9225 15.5011 20.9225 14.7866C20.9225 14.0721 20.3432 13.4928 19.6287 13.4928C18.9143 13.4928 18.335 14.0721 18.335 14.7866C18.335 15.5011 18.9143 16.0803 19.6287 16.0803Z" fill="#1D9BF0"/>
+</svg>

+ 3 - 0
src/assets/svg/icon-tab-message.svg

@@ -0,0 +1,3 @@
+<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M15 24.8203C13.8506 24.8203 12.7405 24.6728 11.6932 24.3981C11.0133 24.2198 9.14472 24.8397 6.0875 26.2578C6.90527 23.6109 7.09915 22.0898 6.66917 21.6945C4.70537 19.8894 3.5 17.4468 3.5 14.7578C3.5 9.20044 8.64872 4.69531 15 4.69531C21.3513 4.69531 26.5 9.20044 26.5 14.7578C26.5 20.3152 21.3513 24.8203 15 24.8203ZM10.4288 16.0803C11.1432 16.0803 11.7225 15.5011 11.7225 14.7866C11.7225 14.0721 11.1432 13.4928 10.4288 13.4928C9.71426 13.4928 9.135 14.0721 9.135 14.7866C9.135 15.5011 9.71426 16.0803 10.4288 16.0803ZM15.0288 16.0803C15.7432 16.0803 16.3225 15.5011 16.3225 14.7866C16.3225 14.0721 15.7432 13.4928 15.0288 13.4928C14.3143 13.4928 13.735 14.0721 13.735 14.7866C13.735 15.5011 14.3143 16.0803 15.0288 16.0803ZM19.6287 16.0803C20.3432 16.0803 20.9225 15.5011 20.9225 14.7866C20.9225 14.0721 20.3432 13.4928 19.6287 13.4928C18.9143 13.4928 18.335 14.0721 18.335 14.7866C18.335 15.5011 18.9143 16.0803 19.6287 16.0803Z" fill="#C0C0C0"/>
+</svg>

+ 3 - 0
src/assets/svg/icon-tab-more-active.svg

@@ -0,0 +1,3 @@
+<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M14.465 12.034C14.465 13.3735 13.379 14.4595 12.0396 14.4595H7.43108C6.09162 14.4595 5.00559 13.3734 5.00559 12.034V7.4255C5.00559 6.08604 6.09162 5 7.43108 5H12.0395C13.379 5 14.465 6.08604 14.465 7.4255V12.034ZM25.0056 22.5744C25.0056 23.914 23.9196 25 22.58 25H17.9717C16.6322 25 15.5461 23.914 15.5461 22.5744V17.9661C15.5461 16.6266 16.6322 15.5405 17.9717 15.5405H22.58C23.9196 15.5405 25.0056 16.6266 25.0056 17.9661V22.5744ZM14.4595 22.5744C14.4595 23.914 13.3734 25 12.034 25H7.4255C6.08595 25 5 23.914 5 22.5744V17.9661C5 16.6266 6.08604 15.5405 7.4255 15.5405H12.0339C13.3734 15.5405 14.4594 16.6266 14.4594 17.9661V22.5744H14.4595ZM22.3336 7.10775C22.4817 7.10791 22.6237 7.16681 22.7284 7.27152C22.8331 7.37624 22.8921 7.51821 22.8923 7.66631V11.7932C22.8923 12.1011 22.6416 12.3517 22.3336 12.3517H18.2068C18.0588 12.3515 17.9168 12.2926 17.812 12.1879C17.7073 12.0832 17.6484 11.9412 17.6482 11.7932V7.66631C17.6482 7.35838 17.8988 7.10775 18.2068 7.10775H22.3336ZM22.5744 5H17.9661C16.6266 5 15.5405 6.08604 15.5405 7.42559V12.0339C15.5405 13.3734 16.6266 14.4595 17.9661 14.4595H22.5744C23.914 14.4595 25 13.3734 25 12.0339V7.42559C25 6.08604 23.914 5 22.5744 5Z" fill="#1D9BF0"/>
+</svg>

+ 3 - 0
src/assets/svg/icon-tab-more.svg

@@ -0,0 +1,3 @@
+<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M14.465 12.034C14.465 13.3735 13.379 14.4595 12.0396 14.4595H7.43108C6.09162 14.4595 5.00559 13.3734 5.00559 12.034V7.4255C5.00559 6.08604 6.09162 5 7.43108 5H12.0395C13.379 5 14.465 6.08604 14.465 7.4255V12.034ZM25.0056 22.5744C25.0056 23.914 23.9196 25 22.58 25H17.9717C16.6322 25 15.5461 23.914 15.5461 22.5744V17.9661C15.5461 16.6266 16.6322 15.5405 17.9717 15.5405H22.58C23.9196 15.5405 25.0056 16.6266 25.0056 17.9661V22.5744ZM14.4595 22.5744C14.4595 23.914 13.3734 25 12.034 25H7.4255C6.08595 25 5 23.914 5 22.5744V17.9661C5 16.6266 6.08604 15.5405 7.4255 15.5405H12.0339C13.3734 15.5405 14.4594 16.6266 14.4594 17.9661V22.5744H14.4595ZM22.3336 7.10775C22.4817 7.10791 22.6237 7.16681 22.7284 7.27152C22.8331 7.37624 22.8921 7.51821 22.8923 7.66631V11.7932C22.8923 12.1011 22.6416 12.3517 22.3336 12.3517H18.2068C18.0588 12.3515 17.9168 12.2926 17.812 12.1879C17.7073 12.0832 17.6484 11.9412 17.6482 11.7932V7.66631C17.6482 7.35838 17.8988 7.10775 18.2068 7.10775H22.3336ZM22.5744 5H17.9661C16.6266 5 15.5405 6.08604 15.5405 7.42559V12.0339C15.5405 13.3734 16.6266 14.4595 17.9661 14.4595H22.5744C23.914 14.4595 25 13.3734 25 12.0339V7.42559C25 6.08604 23.914 5 22.5744 5Z" fill="#C0C0C0"/>
+</svg>

+ 3 - 0
src/assets/svg/icon-tab-wallet-active.svg

@@ -0,0 +1,3 @@
+<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M6.9981 6H23.0044C24.6547 6 26 7.34533 26 8.9981V11.738H18.3117C16.4179 11.738 14.8684 13.2874 14.8684 15.1812V16.0617C14.8684 17.9555 16.4179 19.505 18.3117 19.505H26V22.2448C26 23.9 24.6547 25.2429 23.0019 25.2429H6.9981C5.34287 25.2429 4 23.8976 4 22.2448V8.9981C4 7.34287 5.34533 6 6.9981 6ZM16.0967 15.1806C16.0967 14.5928 16.3279 14.0394 16.7485 13.6188C17.1666 13.1983 17.7224 12.9671 18.3103 12.9671H25.9986V18.2746H18.3103C17.7224 18.2746 17.1691 18.0434 16.7485 17.6229C16.3279 17.2023 16.0967 16.6489 16.0967 16.0611V15.1806ZM20.1991 15.6208C20.1991 15.0773 19.7589 14.6371 19.2153 14.6371C18.6718 14.6371 18.2316 15.0773 18.2316 15.6208C18.2316 16.1644 18.6718 16.6046 19.2153 16.6046C19.7589 16.6046 20.1991 16.1644 20.1991 15.6208Z" fill="#1D9BF0"/>
+</svg>

+ 3 - 0
src/assets/svg/icon-tab-wallet.svg

@@ -0,0 +1,3 @@
+<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M6.9981 6H23.0044C24.6547 6 26 7.34533 26 8.9981V11.738H18.3117C16.4179 11.738 14.8684 13.2874 14.8684 15.1812V16.0617C14.8684 17.9555 16.4179 19.505 18.3117 19.505H26V22.2448C26 23.9 24.6547 25.2429 23.0019 25.2429H6.9981C5.34287 25.2429 4 23.8976 4 22.2448V8.9981C4 7.34287 5.34533 6 6.9981 6ZM16.0967 15.1806C16.0967 14.5928 16.3279 14.0394 16.7485 13.6188C17.1666 13.1983 17.7224 12.9671 18.3103 12.9671H25.9986V18.2746H18.3103C17.7224 18.2746 17.1691 18.0434 16.7485 17.6229C16.3279 17.2023 16.0967 16.6489 16.0967 16.0611V15.1806ZM20.1991 15.6208C20.1991 15.0773 19.7589 14.6371 19.2153 14.6371C18.6718 14.6371 18.2316 15.0773 18.2316 15.6208C18.2316 16.1644 18.6718 16.6046 19.2153 16.6046C19.7589 16.6046 20.1991 16.1644 20.1991 15.6208Z" fill="#C0C0C0"/>
+</svg>

+ 1 - 1
src/assets/svg/icon-telegram.svg

@@ -1,3 +1,3 @@
 <svg width="42" height="42" viewBox="0 0 42 42" fill="none" xmlns="http://www.w3.org/2000/svg">
-<path d="M32.2165 13.8207L28.5516 30.7927C28.2752 31.9905 27.5541 32.2887 26.5295 31.7244L20.9454 27.6837L18.251 30.2284C17.9528 30.5212 17.7034 30.7661 17.1288 30.7661L17.5299 25.1815L27.8794 15.9981C28.3294 15.6042 27.7818 15.3859 27.18 15.7799L14.3855 23.6909L8.87738 21.998C7.67925 21.6306 7.65757 20.8214 9.12677 20.2571L30.6714 12.1065C31.669 11.7392 32.5418 12.3248 32.2165 13.8207V13.8207Z" fill="#259EDA"/>
+<path d="M32.2165 13.8207L28.5516 30.7927C28.2752 31.9905 27.5541 32.2887 26.5295 31.7244L20.9454 27.6837L18.251 30.2284C17.9528 30.5212 17.7034 30.7661 17.1288 30.7661L17.5299 25.1815L27.8794 15.9981C28.3294 15.6042 27.7818 15.3859 27.18 15.7799L14.3855 23.6909L8.87738 21.998C7.67925 21.6306 7.65757 20.8214 9.12677 20.2571L30.6714 12.1065C31.669 11.7392 32.5418 12.3248 32.2165 13.8207Z" fill="#1D9BF0"/>
 </svg>

文件差异内容过多而无法显示
+ 6 - 0
src/assets/svg/icon-wallter-list-blind-box.svg


+ 19 - 1
src/entry/background.js

@@ -14,7 +14,11 @@ import {
     discordLoginCode,
     saveDiscordAuthWindowId,
     onDisconnectHandler,
-    getMessageInfo
+    getMessageInfo,
+    injectExtensionPopup,
+    setPopupConfig,
+    windwoLoadSetPopupPage,
+    setActionPopup
 } from "@/logic/background/twitter";
 
 import { PingPong } from "@/logic/background/help";
@@ -55,6 +59,14 @@ chrome.alarms.onAlarm.addListener(function (alarm) {
     }
 });
 
+chrome.action.onClicked.addListener(function(tab) { 
+    injectExtensionPopup(tab);
+});
+
+chrome.tabs.onActivated.addListener(function(activeInfo) {
+    setPopupConfig(activeInfo);
+})
+
 function onInstalledMethod() {
     onInstalledCreateTab()
     onInstalledMid()
@@ -114,6 +126,12 @@ function onMessageMethod(req, sender, sendResponse) {
             case 'CONTENT_PONG':
                 console.log('CONTENT_PONG')
                 break
+            case 'CONTENT_WINDOW_LOADED_SET_POPUP_PAGE': 
+                // windwoLoadSetPopupPage(req, sender);
+                break;
+            case 'CONTENT_SET_POPUP_CONFIG':
+                setActionPopup(req, sender);
+                break;
         }
     }
 }

+ 30 - 1
src/entry/content.js

@@ -8,6 +8,7 @@ import {
     showIframeHandler,
     hideIframeHandler,
     showTwitterPublishDialogHandler,
+    twitterPublishHandler,
     showPinTips,
     init,
     initExecuteScript,
@@ -18,7 +19,12 @@ import {
     getTweetAuthorByDom,
     facebookReplyTweet,
     doTaskTwitterAPI,
-    onTweetReplyClick
+    onTweetReplyClick,
+    showNFTSale,
+    showBuyNFT,
+    hideBuyNFT,
+    showPopupPage,
+    setPopupConfByPopupPage
 } from "@/logic/content/twitter.js";
 
 import {
@@ -32,6 +38,10 @@ chrome.storage.onChanged.addListener(changes => {
 window.onload = () => {
     init();
     initFacebookContent();
+    chrome.runtime.sendMessage({ 
+        actionType: "CONTENT_WINDOW_LOADED_SET_POPUP_PAGE", 
+        data: { } 
+    }, () => { });
 };
 
 window.onmessage = (res) => {
@@ -91,6 +101,25 @@ chrome.runtime.onMessage.addListener((req, sender, sendResponse) => {
         case 'IFRAME_TWITTER_API_DO_TASK':
             doTaskTwitterAPI(req)
             break
+        case 'IFRAME_NFT_SHOW_SALE':
+            showNFTSale()
+            break
+        case "IFRAME_TWITTER_PUBLISH":
+            twitterPublishHandler(req.publishRes);
+            break;
+        case 'IFRAME_TWITTER_SHOW_POPUP_PAGE':
+            let {from = ''} = req.data || {};
+            showPopupPage({path: '/NFT', from}); 
+            break
+        case "IFRAME_TWITTER_SHOW_BUY_NFT":
+            showBuyNFT(req.data)
+            break
+        case 'IFRAME_TWITTER_HIDE_BUY_NFT':
+            hideBuyNFT()
+            break
+        case 'BG_SET_POPUP_CONFIG':
+            setPopupConfByPopupPage();
+            break
     }
 })
 

+ 23 - 1
src/entry/content_help.js

@@ -1,3 +1,22 @@
+import {
+    appendPopupPage,
+    tiggerInjectPopupPage
+} from "@/logic/content/twitter.js";
+
+window.onload = () => {
+    appendPopupPage();
+    chrome.runtime.sendMessage({ 
+        actionType: "CONTENT_WINDOW_LOADED_SET_POPUP_PAGE", 
+        data: { } 
+    }, () => { });
+};
+
+chrome.runtime.sendMessage({ 
+    actionType: "CONTENT_SET_POPUP_CONFIG", 
+    data: {
+        popup: 'popup.html'
+    } 
+}, () => { });
 
 chrome.runtime.onMessage.addListener((req, sender, sendResponse) => {
     sendResponse('')
@@ -6,5 +25,8 @@ chrome.runtime.onMessage.addListener((req, sender, sendResponse) => {
             console.log('BACK_PING')
             chrome.runtime.sendMessage({ actionType: "CONTENT_PONG", data: '1' }, (res) => { console.log(res) })
             break
+        case 'BG_INJECT_EXTENSION_POPUP':
+            tiggerInjectPopupPage();
+            break
     }
-})
+})

+ 1 - 1
src/http/configAPI.js

@@ -1,4 +1,4 @@
-export const appVersionCode = 7
+export const appVersionCode = 10
 
 const api = {
 	production: 'https://api.denetme.net',

+ 9 - 1
src/http/discordApi.js

@@ -15,11 +15,19 @@ export function discordAuthUrl(params) {
  */
 export function getInviteGuildInfo(params) {
     return service({
-        url: `https://discord.com/api/invites/${params.inviteCode}`,
+        url: `https://discord.com/api/v9/invites/${params.inviteCode}?with_counts=true&with_expiration=true`,
         method: "get",
     });
 }
 
+export function getInviteGuildInfoByOpenApi(params) {
+    return service({
+        url: `https://discord.com/api/invites/${params.inviteCode}?with_counts=true&with_expiration=true`,
+        method: "get",
+    });
+}
+
+
 export function checkGuildJoined(params) {
     return service({
         url: `/openapi/discord/checkGuildJoined`,

+ 41 - 0
src/http/nft.js

@@ -0,0 +1,41 @@
+import { service } from "./request";
+
+export function getTwitterSaleNftProjectInfo(params) {
+    return service({
+        url: `/nft/project/getTwitterSaleNftProjectInfo`,
+        method: 'post',
+        data: params
+    })
+}
+
+export function nftListMine(params) {
+    return service({
+        url: `/nft/item/listMine`,
+        method: 'post',
+        data: params
+    })
+}
+
+export function getNFTDetail(params) {
+    return service({
+        url: `/nft/item/getDetail`,
+        method: 'post',
+        data: params
+    })
+}
+
+export function getNftMysteryBoxSaleInfo(params) {
+    return service({
+        url: `/nft/project/getNftMysteryBoxSaleInfo`,
+        method: 'post',
+        data: params
+    })
+}
+
+export function getNftProjectInfo(params) {
+    return service({
+        url: `/nft/project/getNftProjectInfo`,
+        method: 'post',
+        data: params
+    })
+}

+ 7 - 0
src/http/pay.js

@@ -33,5 +33,12 @@ export function getTokenRechargeAddress(params) {
     });
 }
 
+export function payNftMysteryBoxWithBalance(params) {
+    return service({
+        url: `/wallet/pay/payNftMysteryBoxWithBalance`,
+        method: "post",
+        data: params,
+    });
+}
 
 // ---- 提现 ----

+ 8 - 0
src/http/publishApi.js

@@ -75,6 +75,14 @@ export function searchCurrencyInfo(params) {
   })
 }
 
+export function getCurrencyInfoBySymbol(params) {
+  return service({
+    url: `/currency/v2/getCurrencyInfoBySymbol`,
+    method: 'post',
+    data: params
+  })
+}
+
 export function syncChainTokenRechargeRecord(params) {
   return service({
     url: `/wallet/recharge/syncChainTokenRechargeRecord`,

+ 13 - 0
src/iframe/buy-nft.js

@@ -0,0 +1,13 @@
+import { createApp } from 'vue'
+import App from '@/view/iframe/buy-nft/index.vue'
+import ElementPlus from 'element-plus'
+import 'element-plus/dist/index.css'
+
+import router from '@/router/buy-nft.js'
+
+const app = createApp(App);
+
+
+app.use(router)
+app.use(ElementPlus);
+app.mount('#app');

+ 6 - 0
src/iframe/nft-card.js

@@ -0,0 +1,6 @@
+import { createApp } from 'vue'
+import App from '@/view/iframe/nft/card.vue'
+
+const app = createApp(App);
+
+app.mount('#app');

+ 24 - 0
src/iframe/popup-page.js

@@ -0,0 +1,24 @@
+import { createApp } from 'vue'
+import App from '@/view/iframe/popup/index.vue'
+
+const app = createApp(App)
+
+// 引入路由对象实例
+import router from '@/router/popup.js'
+import "ant-design-vue/dist/antd.css"; // or 'ant-design-vue/dist/antd.less'
+import { Button, message, Tooltip } from "ant-design-vue";
+
+message.config({
+    top: `10px`,
+    duration: 3,
+    maxCount: 1,
+});
+app.use(Tooltip);
+app.use(Button);
+app.use(message);
+app.use(router)
+app.mount('#app')
+
+window.onload= () => {
+    document.title = 'DeNet'
+}

+ 9 - 1
src/log-center/logEnum.js

@@ -17,6 +17,14 @@ export const objectType = {
     loginButton: "login-button",
     withdrawButton: "withdraw-button",
     topupButton: "topup-button",
+
+    //discord 
+    getDiscordGuildNoData: 'get-discord-guild-no-data',
+    getDiscordGuildCatch: 'get-discord-guild-catch',
+    getDiscordGuildOpenApiNoData: 'get-discord-guild-openapi-no-data',
+    getDiscordGuildOpenApiCatch: 'get-discord-guild-openapi-catch',
+    saveDiscordGuildData: 'save-discord-guild-data',
+
     // 按钮点击
     open_button: 'open-button',
     // 关注全部
@@ -29,7 +37,7 @@ export const objectType = {
     // 点击检测任务
     get_giveaway: 'get-giveaway',
     // 成功领取到钱包
-    wallet_button: 'wallet-button'
+    wallet_button: 'wallet-button',
 }
 
 export const pageSource = {

+ 18 - 1
src/log-center/logger.js

@@ -1,4 +1,5 @@
 import {logApi} from '@/http/logApi'
+import { getBrowser } from '@/uilts/help.js';
 import { logType } from './logEnum.js';
 
 
@@ -7,7 +8,23 @@ import { logType } from './logEnum.js';
  * @extParams 最终上报到阿里云以json字符串存储的参数,如果extparams传入的不是obj会转换成obj
  */
 export function reportLog(eventData = {}, extParams = {}) {
-    paramsPretreatmentAndRequest(logType.denet, eventData, extParams)
+    if (chrome && chrome.tabs) {
+        chrome.tabs.getCurrent((tab) => {
+            let isMobile = navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i);
+            let { url = '' } = tab;
+            let platform = isMobile ? `mobile` : `pc`;
+            let browser = getBrowser();
+            let extData = {
+                url,
+                platform,
+                browser,
+                ...extParams,
+            }
+            paramsPretreatmentAndRequest(logType.denet, eventData, extData)
+        })
+    } else {
+        paramsPretreatmentAndRequest(logType.denet, eventData, extParams)
+    }
 }
 
 function paramsPretreatmentAndRequest(logType, eventData, extParams) {

+ 98 - 3
src/logic/background/twitter.js

@@ -87,6 +87,11 @@ export function twitterPinLoginCode(sender, code) {
         fetchTwitterLogin(authToken, consumerKey, code, receivedIds).then(res => {
             if (res.code == 0) {
                 setChromeStorage({ userInfo: JSON.stringify(res.data) })
+
+                sendActivetabMessage({
+                    actionType: 'BG_LOGIN_SET_USERINFO_CB'
+                });
+
                 // 获取全局消息数据
                 setMessageCount()
                 chrome.cookies.remove(LANDING_PAGE)
@@ -256,9 +261,24 @@ export function onInstalledCreateTab() {
             });
             removeChromeCookie(cookiesParams)
         } else {
-            chrome.tabs.create({
-                url: "https://twitter.com",
-            });
+            let nftParams = {
+                name: 'nft_info',
+                url: pageUrl
+            }
+            getChromeCookie(nftParams, (res) => {
+                let { twitterAccount, nftProjectId } = res;
+                if (res && twitterAccount && nftProjectId) {
+                    let url = `https://twitter.com/${twitterAccount}`
+                    chrome.tabs.create({
+                        url
+                    });
+                    removeChromeCookie(nftParams)
+                } else {
+                    chrome.tabs.create({
+                        url: "https://twitter.com",
+                    });
+                }
+            })
         }
     })
 }
@@ -345,4 +365,79 @@ export const onDisconnectHandler = (port) => {
             getMessageInfo();
         })
     }
+}
+
+export const injectExtensionPopup = (tab) => {
+    sendActivetabMessage({
+        actionType: 'BG_INJECT_EXTENSION_POPUP'
+    });
+}
+
+export const setPopupConfig = (activeInfo) => {
+    chrome.tabs.query({
+        active: true,
+        currentWindow: true
+    }, (tabs) => {
+        if(tabs.length) {
+            let {pendingUrl = '', url = ''} = tabs[0];
+            if(pendingUrl.startsWith('https://twitter.com') || url.startsWith('https://twitter.com')) {
+                sendActivetabMessage({
+                    actionType: 'BG_SET_POPUP_CONFIG'
+                });
+            } else {
+                chrome.action.setPopup({
+                    popup: 'popup.html',
+                },function() {
+                });
+            }
+
+            // if(pendingUrl.startsWith('chrome://') || url.startsWith('chrome://') || pendingUrl.startsWith('https://chrome.google.com') || url.startsWith('https://chrome.google.com')) {
+            //     chrome.action.setPopup({
+            //         popup: 'popup.html',
+            //     },function() {
+            //     });
+            // } else {
+            //     chrome.action.setPopup({
+            //         popup: '',
+            //     },function() {
+            //     });
+            // }
+        }
+    })
+}
+
+export const windwoLoadSetPopupPage = (data, sender) => {
+    let {url = ''} = sender.tab;
+    if(url.startsWith('chrome://')) {
+        chrome.action.setPopup({
+            popup: 'popup.html',
+        },function() {
+        });
+    } else {
+        chrome.action.setPopup({
+            popup: '',
+        },function() {
+        });
+    }
+}
+
+export const setActionPopup = (data) => {
+    let {popup} = data.data || {};
+    if(popup) {
+        chrome.action.getPopup(
+            {},
+            function(result){
+                if(!result) {
+                    chrome.action.setPopup({
+                        popup,
+                    },function() {
+                    });
+                }
+        });
+    } else {
+        chrome.action.setPopup({
+            popup: '',
+        },function() {
+        });
+    }
 }

+ 58 - 20
src/logic/content/ParseCard.js

@@ -41,12 +41,12 @@ class ParseCard {
             let item
             for (let i in arr_shadow) {
                 item = arr_shadow[i].childNodes
-                if(has_denet){
+                if (has_denet) {
                     break
                 }
                 if (item) {
                     for (let j in item) {
-                        if (item[j].innerText && item[j].innerText.includes('#DeNet')) {
+                        if (item[j].innerText && (item[j].innerText.includes('#DeNet') || item[j].innerText.includes('#DNFT'))) {
                             has_denet = true
                             break
                         }
@@ -64,8 +64,8 @@ class ParseCard {
             let arr_article = document.querySelectorAll('article') || []
             let _txt
             for (let i in arr_article) {
-                _txt = arr_article[i].innerText || ''                
-                if ((_txt.includes('#DeNet') || this.compatibleMask(arr_article[i])) && !this.isHasIframeByArticle(arr_article[i])) {
+                _txt = arr_article[i].innerText || ''
+                if ((_txt.includes('#DeNet') || _txt.includes('#DNFT') || this.compatibleMask(arr_article[i])) && !this.isHasIframeByArticle(arr_article[i])) {
                     de_net_card.push({
                         time: new Date().getTime(),
                         dom: arr_article[i]
@@ -104,7 +104,7 @@ class ParseCard {
         a_arr = Array.from(a_arr).reverse()
         for (let i in a_arr) {
             // 获取推特id
-            if (a_arr[i].href.indexOf('facebook.com') > 0 && a_arr[i].href.indexOf('denetme') > 0) {
+            if (a_arr[i].href.indexOf('facebook.com') > 0 && a_arr[i].href.indexOf('denetme') > 0 && a_arr[i].href.indexOf('nft') == -1) {
                 let faceUrl = new URL(a_arr[i].href);
                 let faceSearch = new URLSearchParams(faceUrl.search);
                 let faceJumpUrl = decodeURIComponent(faceSearch.get('u'));
@@ -124,7 +124,7 @@ class ParseCard {
                     }
                 }
             } else {
-                if (a_arr[i].href.indexOf('denetme.net') > 0) {
+                if (a_arr[i].href.indexOf('denetme.net') > 0 && a_arr[i].href.indexOf('nft') == -1) {
                     let urlArr = new URL(a_arr[i].href);
                     let searchArr = new URLSearchParams(urlArr.search);
                     let deUrlParams = searchArr.get('deUrlParams') || '{}';
@@ -230,18 +230,33 @@ class ParseCard {
 
     createIframe({ post_Id = '', tweet_Id = '', tweet_author = '' }, if_center = false) {
         let _iframe = document.createElement('iframe')
-        let tweet_str = '';
+        let _iframe_url = ''
+        let tweet_str = ''
         if (tweet_Id) {
-            tweet_str = `&tweetId=${tweet_Id}`;
+            tweet_str = `&tweetId=${tweet_Id}`
         }
         _iframe.id = post_Id
-        _iframe.src = chrome.runtime.getURL('/iframe/red-packet.html') + `?postId=${post_Id}${tweet_str}&tweet_author=${tweet_author}&window_origin=${window.location.origin}`;
+        _iframe_url =  chrome.runtime.getURL('/iframe/red-packet.html') + `?postId=${post_Id}${tweet_str}&tweet_author=${tweet_author}&window_origin=${window.location.origin}`;
+        // debugger mode
+        if(window.location.href.includes('denet_debugger')){
+            _iframe_url = _iframe_url + '&denet_debugger=1'
+        }
+        _iframe.src = _iframe_url
         _iframe.style.cssText = 'border:medium none; width:375px; min-height:500px;'
         if (if_center) {
             _iframe.style.cssText = 'border:medium none; width:375px; min-height:500px; display:block; margin:auto;'
         }
         return _iframe
     }
+    createNftIframe({ project_Id }) {
+        let project_arr = project_Id.split('/');
+        let projectId = project_arr[0]
+        let _iframe = document.createElement('iframe')
+        _iframe.id = project_Id
+        _iframe.src = chrome.runtime.getURL('/iframe/nft-card.html') + `?projectId=${projectId}&twitterAccount=${project_arr[1]}`;
+        _iframe.style.cssText = 'border:medium none; width:375px; min-height:300px;'
+        return _iframe
+    }
     isHasIframeByArticle(dom_card) {
         if (!dom_card || !dom_card.parentElement) {
             return
@@ -328,26 +343,49 @@ class ParseCard {
 
         dom.style = 'min-height:500px'
         if (dom) {
-            // let div = document.createElement('div')
-            // div.style.color = 'red'
-            // div.innerText = `
-            // tweet_Id:${tweet_Id} , 
-            // post_Id:${post_Id}
-            // 获取dom时间:${time}
-            // 短链接:${short_url}
-            // 渲染时长:${(new Date().getTime() - time) / 1000}s
-            // `
-            // dom.parentElement.appendChild(div)
+            // debugger mode
+            if (window.location.href.includes('denet_debugger')) {
+                let div = document.createElement('div')
+                div.style.color = 'red'
+                div.innerText = `
+                tweet_Id:${tweet_Id} , 
+                post_Id:${post_Id}
+                获取dom时间:${time}
+                短链接:${short_url}
+                渲染时长:${(new Date().getTime() - time) / 1000}s
+                `
+                dom.parentElement.appendChild(div)
+            }
             dom.appendChild(this.createIframe({ post_Id, tweet_Id }))
         }
+    }
+    replaceNftDomRedPacket({ dom_card, tweet_Id, post_Id, time, short_url }) {
+        if (!dom_card || !dom_card.parentElement) {
+            return
+        }
+        let dom = dom_card.querySelector('div[aria-labelledby]')
+        if (dom) {
+            for (let i = 0; i < dom.childNodes.length; i++) {
+                if (dom.children[i].tagName.toLowerCase() != 'iframe') {
+                    dom.children[i].style.display = 'none'
+                }
+            }
+        } else {
+            dom = dom_card.querySelector('div[lang][dir=auto]').parentElement
+        }
 
+        dom.style = 'min-height:300px'
+        if (dom) {
+            let project_Id = post_Id.replace('nft/', '');
+            dom.appendChild(this.createNftIframe({ project_Id }))
+        }
     }
     replaceFacebookPacket({ dom_card, tweet_Id, short_url, tweet_author }) {
         if (!dom_card || !dom_card.parentElement) {
             return
         }
         let dom = dom_card.querySelector('div[id^=jsc_c_]').parentElement
-            dom.style = 'min-height:500px'
+        dom.style = 'min-height:500px'
         if (dom) {
             for (let i = 0; i < dom.childNodes.length; i++) {
                 if (dom.children[i].tagName.toLowerCase() != 'iframe' && (i !== 0)) {

+ 329 - 24
src/logic/content/twitter.js

@@ -1,5 +1,5 @@
 import { getChromeStorage, setChromeStorage } from '@/uilts/chromeExtension.js'
-import { throttle, getQueryString, getCookie } from '@/uilts/help'
+import { throttle, getQueryString, getCookie, nextTick } from '@/uilts/help'
 import { discordAuthRedirectUri } from '@/http/configAPI'
 import { reportSrcPublishEvent } from '@/http/publishApi'
 import Report from "@/log-center/log"
@@ -95,7 +95,25 @@ export function showTwitterPublishDialogHandler(publishRes) {
     _publishTweetEvent(publishRes, bindTwitterArtMethod);
 }
 
+export function twitterPublishHandler(res) {
+    let bigBtn = document.querySelector('a[data-testid="SideNav_NewTweet_Button"]');
+    if (bigBtn) {
+        bigBtn.click();
+    } else {
+        let smallBtn = document.querySelector('a[href="/compose/tweet"]')
+        smallBtn && smallBtn.click();
+    }
+
+    nextTick(() => {
+        document.execCommand('selectAll');
+    }, 100).then(() => {
+        _setPublishContent(res.srcContent, 500);
+    })
+}
+
 export function showPinTips() {
+    hidePopupPage();
+    hideNoticeBindTweet();
     getChromeStorage('pinData', (res) => {
         if (!res || res.show) {
             let domPop = document.getElementById('de-pin-pop');
@@ -104,6 +122,13 @@ export function showPinTips() {
     })
 }
 
+export function hidePinTips() {
+    let pop = document.querySelector('#de-pin-pop');
+    if (pop) {
+        pop.style.display = 'none';
+    }
+}
+
 function addPinedPop() {
     let domPop = document.getElementById('de-pin-pop');
 
@@ -125,12 +150,7 @@ function addPinedPop() {
     popWrapper.appendChild(img);
     popWrapper.appendChild(contentDom);
 
-    let layersDom = document.getElementById('layers');
-    if (layersDom) {
-        layersDom.appendChild(popWrapper);
-    } else {
-        document.querySelector('body').appendChild(popWrapper);
-    }
+    document.querySelector('body').appendChild(popWrapper);
 
     let deCheck = document.querySelector('#de-check');
     let deRemind = document.querySelector('#de-remind');
@@ -237,7 +257,10 @@ function _addDeNetEditBtn(parent, dom, isClick = false) {
                 businessType: Report.businessType.buttonView,
                 objectType: Report.objectType.buttonSecond
             });
-            parent.parentNode.insertBefore(dom, parent.nextElementSibling);
+            let innerDeIcon = document.getElementById('de-btn1');
+            if (!innerDeIcon) {
+                parent.parentNode.insertBefore(dom, parent.nextElementSibling);
+            }
         } else {
             setTimeout(() => {
                 parent = _getScheduleDom(isClick);
@@ -330,13 +353,7 @@ function _addIframe() {
     dom.iframe = iframe;
     let iframeContent = document.getElementById('iframe-content');
     if (!iframeContent) {
-        let layersDom = document.getElementById('layers');
-        if (layersDom) {
-            layersDom.appendChild(iframe);
-        } else {
-            document.querySelector('body').appendChild(iframe);
-        }
-
+        document.querySelector('body').appendChild(iframe);
     }
 }
 
@@ -361,6 +378,8 @@ function addPublishTipsIframe(params = {}) {
 }
 
 export function noticeBindTweet(params) {
+    hidePinTips();
+    hidePopupPage();
     let iframe = document.createElement('iframe');
     iframe.id = 'de-notice-bind-tweet';
     iframe.src = chrome.runtime.getURL('/iframe/bind-tweet.html') + `?params=${JSON.stringify(params)}`;
@@ -417,7 +436,7 @@ function _deNetBtnClick() {
  * @private
  */
 let isSetContent = false;
-const _setPublishContent = throttle(function (content) {
+const _setPublishContent = throttle(function (content, time = 1000) {
     if (!isSetContent) {
         isSetContent = true;
         let inputEle = document.querySelector('div[contenteditable="true"]');
@@ -429,7 +448,7 @@ const _setPublishContent = throttle(function (content) {
             setTimeout(() => {
                 isSetContent = false;
             }, 2000)
-        }, 1000);
+        }, time);
     }
 }, 800);
 
@@ -674,7 +693,12 @@ function setIframeRedPacket(type = 'twitter') {
             // 过滤出可以请求的短链接
             parseCard.getCardParmas(card_json_data).then((res) => {
                 for (let i in res.has_post_Id_card_data) {
-                    parseCard.replaceDOMRedPacket(res.has_post_Id_card_data[i])
+                    let item = res.has_post_Id_card_data[i];
+                    if (item && item.post_Id && item.post_Id.indexOf('nft/') >= 0) {
+                        parseCard.replaceNftDomRedPacket(item)
+                    } else {
+                        parseCard.replaceDOMRedPacket(item)
+                    }
                 }
                 if (res.need_net_short_url.length > 0) {
                     // 请求短链接
@@ -708,13 +732,15 @@ export function initExecuteScript(changes) {
     }
 }
 
-const createIframe = ({ url, tweet_Id }, callback) => {
+const createNFTIframe = ({ url, id }, callback) => {
     let iframe = document.createElement('iframe')
-    iframe.id = `tweetId${tweet_Id}`
+    iframe.id = id
     iframe.src = url
+    iframe.style.cssText = 'border:medium none; width:100%; height:100%; z-index:100; position: fixed; top:0;left:0; display:none;';
     iframe.onload = () => {
-        callback()
+        callback && callback()
     }
+    document.body.appendChild(iframe);
 }
 
 
@@ -738,6 +764,7 @@ function initParseCard() {
                 checkHasDeBtn()
                 checkHasSliderDeBtn();
                 changeQueueNum(-1)
+                showNFTCard()
             }, 1000)
         } else if (inFacebook && inFacebookNode) {
             clearInterval(timer)
@@ -758,13 +785,22 @@ function initParseCard() {
 let inited = false
 // 初始化
 export function init() {
-    if(inited){
-        return 
+    if (inited) {
+        return
     }
     inited = true
     console.log('init')
 
     getDiscordAuthCode();
+    appendPopupPage();
+
+    chrome.runtime.sendMessage({ 
+        actionType: "CONTENT_SET_POPUP_CONFIG", 
+        data: {
+            popup: 'popup.html'
+        } 
+    }, () => { });
+
     let where = window.location.href.indexOf('twitter.com') < 0 && window.location.href.indexOf('facebook.com') < 0;
     if (where) {
         return
@@ -772,10 +808,13 @@ export function init() {
     twitterPinLogin();
     // 渲染dom
     initParseCard()
-
+    showNFTCard()
     renderDom();
     checkTwitterTaskState();
 
+    onBodyClick();
+    initBuyNFT();
+
     getChromeStorage("popupShowPublishDialog", (res) => {
         console.log("popupShowPublishDialog", res);
         if (res && res.show) {
@@ -840,6 +879,13 @@ export function replyHandle(params) {
         let tweetReply = document.querySelector('div[data-testid="tweetButtonInline"]');
         if (tweetReply) {
             tweetReply.addEventListener('click', function () {
+                // 详情页回复按钮点击
+                Report.reportLog({
+                    pageSource: Report.pageSource.mainPage,
+                    businessType: Report.businessType.buttonClick,
+                    objectType: Report.objectType.replyClickByDetailPage
+                });
+
                 let eleList = tweetReply.parentNode.parentNode.parentNode.parentNode.parentNode.querySelectorAll('span[data-text="true"]');
                 reportReplyResult(eleList, params, () => {
                     // iframe.contentWindow.postMessage({ actionType: 'CONTENT_RED_PACKET_REPLY_RASK_FINSH', data: {} }, '*');
@@ -889,6 +935,13 @@ function onReplyDialogOpen(params, iframe) {
 
         if (dialog && replyBtn) {
             replyBtn.addEventListener('click', function () {
+                // 推文页回复按钮点击
+                Report.reportLog({
+                    pageSource: Report.pageSource.mainPage,
+                    businessType: Report.businessType.buttonClick,
+                    objectType: Report.objectType.replyClickByTwitterList
+                });
+
                 let eleList = dialog.querySelector('div[contenteditable="true"]').querySelectorAll('span[data-text="true"]');
                 reportReplyResult(eleList, params, () => {
                     // 上報完成
@@ -901,6 +954,15 @@ function onReplyDialogOpen(params, iframe) {
 }
 
 const reportReplyResult = throttle(function (eleList, params, cb) {
+    //未过滤的回复文本
+    Report.reportLog({
+        pageSource: Report.pageSource.mainPage,
+        businessType: Report.businessType.buttonClick,
+        objectType: Report.objectType.replyInputTextGet
+    }, {
+        replyStr: eleList
+    });
+
     if (eleList && eleList.length) {
         let atList = [];
         for (let i = 0; i < eleList.length; i++) {
@@ -913,9 +975,27 @@ const reportReplyResult = throttle(function (eleList, params, cb) {
             }
         }
 
+        // 去重过滤文本
         atList = Array.from(new Set(atList));
 
+        Report.reportLog({
+            pageSource: Report.pageSource.mainPage,
+            businessType: Report.businessType.buttonClick,
+            objectType: Report.objectType.replyFilterTextGet
+        }, {
+            replyStr: atList
+        });
+
         if (atList.length >= 3) {
+            //真实上报
+            Report.reportLog({
+                pageSource: Report.pageSource.mainPage,
+                businessType: Report.businessType.buttonClick,
+                objectType: Report.objectType.replyReport
+            }, {
+                replyStr: atList
+            });
+
             fetchAddFinishEvent({
                 eventType: params.type,
                 luckdropId: params.taskLuckdropId
@@ -1166,4 +1246,229 @@ const TwitterLikeAPI = (tweet_Id) => {
     }).catch(() => {
         chrome.runtime.sendMessage({ actionType: "DO_TASK", do_type: 'api', tweet_Id, task_type: 'like', task_data: '', task_done: false }, () => { })
     })
+}
+
+export const hideBuyNFT = () => {
+    let iframe = document.querySelector('#nftProjectId')
+    iframe.style.display = 'none'
+    iframe.src = ''
+}
+
+export const showBuyNFT = ({ nft_project_Id }) => {
+    if (!nft_project_Id) {
+        return
+    }
+    let iframe = document.querySelector('#nftProjectId')
+    iframe.style.display = 'block'
+    iframe.src = chrome.runtime.getURL(`/iframe/buy-nft.html?nftProjectId=${nft_project_Id}`)
+}
+
+const initBuyNFT = () => {
+    let url = chrome.runtime.getURL(`/iframe/buy-nft.html`)
+    let id = `nftProjectId`
+    createNFTIframe({ url, id })
+}
+
+export const showNFTCard = () => {
+    let urlInfo = new URL(window.location.href)
+    let isTwitter = urlInfo.hostname === 'twitter.com'
+    let userElem = document.querySelector('div[data-testid="UserName"]');
+    let sideElem = document.querySelector('div[data-testid="sidebarColumn"]')
+    let tabIndex = sideElem && sideElem.querySelector('div[tabindex="0"]');
+    let isAppend = document.querySelector('div[id="de-nft-node"]');
+    let where = isTwitter && userElem && tabIndex;
+    if (where) {
+        let iframe = document.createElement('iframe');
+        iframe.src = chrome.runtime.getURL(`/iframe/nft-card.html`)
+        iframe.style.cssText = 'border:medium none; width:100%; height:290px;';
+        let nftElement = document.createElement('div');
+        nftElement.id = 'de-nft-node';
+        nftElement.innerHTML = `
+                ${iframe.outerHTML}
+                <style>
+                    #de-nft-node {height:290px; margin-bottom:17px; display:none;}
+                </style>
+            `;
+
+        if (tabIndex && tabIndex.firstChild && tabIndex.firstChild.childNodes && !isAppend) {
+            tabIndex.firstChild.insertBefore(nftElement, tabIndex.firstChild.childNodes[2]);
+        }
+    }
+}
+
+export const showNFTSale = () => {
+    document.querySelector('div[id="de-nft-node"]').style.display = 'block';
+}
+
+export const appendPopupPage = (params = {}) => {
+    let { path = '' } = params;
+
+    let iframe = document.createElement('iframe');
+        iframe.id = 'de-popup-page';
+        iframe.src = chrome.runtime.getURL('/iframe/popup-page.html') + `#${path}`;
+        iframe.style.cssText = `border: medium none; width: 375px;
+        height: 650px;position: fixed; right: 16px; top: 16px;background: #FFFFFF;border: 0.5px solid #919191;box-shadow: 0px 4px 20px rgba(0, 0, 0, 0.2);box-sizing: border-box;z-index: 90000;
+        animation-duration: 0.5s !important;
+        animation-timing-function: ease-in-out !important;
+        animation-fill-mode: forwards !important;
+        transition: all 1s ease 0s !important;right: -385px;transform: translateX(385px);`
+    let iframeContent = document.getElementById('de-popup-page');
+
+    let overlayDom = document.createElement('div');
+        overlayDom.id = 'de-popup-overlay';
+        overlayDom.style.cssText = `position: fixed;z-index: 88888;top: 0;
+        left: 0;width: 100%;height: 100%;opacity: 0;display: none`;
+
+    let overlay = document.getElementById('de-popup-overlay');
+    let body = document.querySelector('body');
+
+    if (!iframeContent && body) {
+        document.querySelector('body').appendChild(iframe);
+        if(!overlay) {
+            document.querySelector('body').appendChild(overlayDom);
+
+            overlayDom.addEventListener('click', function() {
+                hidePopupPage();
+            })
+        } else {
+            overlay.addEventListener('click', function() {
+                hidePopupPage();
+            })
+        }
+    }
+}
+
+let showPopupPageFrom = '';
+export const showPopupPage = (params = {}) => {
+    let { path = '', from } = params;
+    showPopupPageFrom = from;
+    hidePinTips();
+    hideNoticeBindTweet();
+
+    let iframe = document.getElementById('de-popup-page');
+    if (!iframe) {
+        appendPopupPage();
+        iframe = document.getElementById('de-popup-page');
+    }
+    if(iframe) {
+        if(path) {
+            iframe.src = chrome.runtime.getURL('/iframe/popup-page.html') + `#${path}`;
+        }
+        iframe.style.transform = 'translateX(-' + 395 + 'px)';
+    
+        chrome.runtime.sendMessage({ 
+            actionType: "CONTENT_POPUP_PAGE_SHOW", 
+            data: { } 
+        }, () => { });
+
+        chrome.runtime.sendMessage({ 
+            actionType: "CONTENT_SET_POPUP_CONFIG", 
+            data: {
+                popup: ''
+            } 
+        }, () => { });
+    
+        let overlay = document.getElementById('de-popup-overlay');
+        overlay.style.display = 'block';
+    
+        let htmlDom = document.querySelector('html');
+        if(htmlDom) {
+            htmlDom.style.overflowY = 'hidden';
+        }
+    }
+}
+
+export const hidePopupPage = () => {
+    let iframe = document.getElementById('de-popup-page');
+    if (iframe) {
+        iframe.style.transform = 'translateX(' + 385 + 'px)';
+
+        let overlay = document.getElementById('de-popup-overlay');
+        overlay.style.display = 'none';
+
+        let htmlDom = document.querySelector('html');
+        if(htmlDom) {
+            htmlDom.style.overflowY = 'auto';
+        }
+
+        chrome.runtime.sendMessage({ 
+            actionType: "CONTENT_SET_POPUP_CONFIG", 
+            data: {
+                popup: 'popup.html'
+            } 
+        }, () => { });
+
+        if(showPopupPageFrom == 'BUY_NFT_FINISH') {
+            chrome.runtime.sendMessage({ 
+                actionType: "CONTENT_GET_PINED", 
+                data: {} 
+            }, () => { });
+            showPopupPageFrom = '';
+        }
+    }
+}
+
+export const tiggerInjectPopupPage = () => {
+    let iframeContent = document.getElementById('de-popup-page');
+    if (iframeContent) {
+        hidePinTips();
+        hideNoticeBindTweet();
+        let {transform = ''} = iframeContent.style;
+        if(transform == 'translateX(385px)' || !transform) {
+            showPopupPage();
+        } else {
+            hidePopupPage();
+        }
+    } else {
+        appendPopupPage();
+        setTimeout(() => {
+            let iframe = document.getElementById('de-popup-page');
+            let {transform = ''} = iframe.style;
+            if(transform == 'translateX(385px)' || !transform) {
+                showPopupPage();
+            } else {
+                hidePopupPage();
+            }
+        }, 300)
+    }
+}
+
+const onBodyClick = () => {
+    if(window.location.href.indexOf('api.twitter.com') < 0) {
+        document.querySelector('body').addEventListener('click', function () {
+            console.log('click')
+            // hidePopupPage();
+        })
+    } 
+}
+
+
+export const setPopupConfByPopupPage = () => {
+    let iframe = document.getElementById('de-popup-page');
+    if (iframe) {
+        let {transform = ''} = iframe.style;
+
+        if(transform && transform == 'translateX(-395px)') {
+            chrome.runtime.sendMessage({ 
+                actionType: "CONTENT_SET_POPUP_CONFIG", 
+                data: {
+                    popup: ''
+                } 
+            }, () => { });
+        } else {
+            chrome.runtime.sendMessage({ 
+                actionType: "CONTENT_SET_POPUP_CONFIG", 
+                data: {
+                    popup: 'popup.html'
+                } 
+            }, () => { });
+        }
+    } else {
+        chrome.runtime.sendMessage({ 
+            actionType: "CONTENT_SET_POPUP_CONFIG", 
+            data: {
+                popup: 'popup.html'
+            } 
+        }, () => { });
+    }
 }

+ 5 - 2
src/manifest.json

@@ -2,7 +2,7 @@
     "manifest_version": 3,
     "name": "DeNet",
     "description": "Growing more twitter followers with Denet",
-    "version": "1.0.7",
+    "version": "1.1.0",
     "background": {
         "service_worker": "/js/background.js"
     },
@@ -66,7 +66,10 @@
                 "/iframe/red-packet.html",
                 "/iframe/home.html",
                 "/iframe/publish-tips.html",
-                "/iframe/bind-tweet.html"
+                "/iframe/bind-tweet.html",
+                "/iframe/nft-card.html",
+                "/iframe/buy-nft.html",
+                "/iframe/popup-page.html"
             ],
             "matches": [
                 "<all_urls>"

+ 33 - 0
src/router/buy-nft.js

@@ -0,0 +1,33 @@
+import { createRouter, createWebHashHistory, createWebHistory } from "vue-router"
+import Home from '@/view/iframe/buy-nft/buy/home.vue'
+import Pay from '@/view/iframe/buy-nft/buy/pay.vue'
+import OpenBox from '@/view/iframe/buy-nft/buy/open-box.vue'
+
+let routes = [
+    {
+        path: '/',
+        name: 'Home',
+        component: Home,
+    },
+    {
+        path: "/pay",
+        name: 'Pay',
+        component: Pay
+    }, {
+        path: "/open_box",
+        name: 'OpenBox',
+        component: OpenBox
+    }
+]
+// 3. 创建路由实例
+const router = createRouter({
+
+    // 4. 采用hash 模式
+    history: createWebHashHistory('buy-nft.html'),
+    // 采用 history 模式
+    // history: createWebHistory('popup.html'),
+    routes, // short for `routes: routes`
+});
+
+export default router
+

+ 45 - 5
src/router/popup.js

@@ -1,6 +1,13 @@
 /* eslint-disable */
 import { createRouter, createWebHashHistory, createWebHistory } from "vue-router"
-import Home from '@/view/popup/popup.vue'
+import Tabcontent from '@/view/popup/tabbar-page/index.vue'
+import Home from '@/view/popup/tabbar-page/wallter/popup.vue'
+import NFT  from '@/view/popup/tabbar-page/nft/index.vue'
+import Message from '@/view/popup/tabbar-page/message/index.vue'
+import More from '@/view/popup/tabbar-page/more/index.vue'
+
+import NFTDetail  from '@/view/popup/tabbar-page/nft/detail.vue'
+
 import Withdraw from '@/view/popup/withdraw/index.vue'
 import WithdrawInfo from '@/view/popup/withdraw/info.vue'
 import WithdrawConfirm from '@/view/popup/withdraw/confirm.vue'
@@ -14,12 +21,36 @@ import TopUp from '@/view/popup/top-up/index.vue'
 import TopUpInfo from '@/view/popup/top-up/info.vue'
 import TopUpHome from '@/view/popup/top-up/home.vue'
 
+import CurrencyDetail from '@/view/popup/currency-detail.vue'
+
 // 2. 定义路由配置
 const routes = [
     {
-        path: "/",
-        name: 'home',
-        component: Home
+        path: '/',
+        name: 'tabcontent',
+        component: Tabcontent,
+        children: [
+            {
+                path: "",
+                name: 'home',
+                component: Home
+            },
+            {
+                path: "NFT",
+                name: 'NFT',
+                component: NFT
+            },
+            {
+                path: "message",
+                name: 'message',
+                component: Message
+            },
+            {
+                path: "more",
+                name: 'more',
+                component: More
+            },
+        ]
     },
     {
         path: '/withdraw',
@@ -81,8 +112,17 @@ const routes = [
         path: '/transactions',
         name: 'Transactions',
         component: Transactions
+    },
+    {
+        path: '/NFTDetail',
+        name: 'NFTDetail',
+        component: NFTDetail
+    },
+    {
+        path: '/currencyDetail',
+        name: 'currencyDetail',
+        component: CurrencyDetail
     }
-
 ]
 
 

+ 29 - 1
src/uilts/help.js

@@ -100,4 +100,32 @@ export function getCookie(name){
       }
   }
   return "";
-}
+}
+
+export function nextTick(fn, time = 50) {
+    return new Promise((resolve, reject) => {
+        setTimeout(() => {
+            if (fn) fn();
+            resolve();
+        }, time)
+    })
+}
+
+export function getBrowser() {
+    let browser;
+    let UserAgent = navigator.userAgent.toLowerCase();
+    if (UserAgent.indexOf('chrome') > -1 && UserAgent.indexOf('safari') > -1) {
+        browser = `Chrome`
+    } else if (UserAgent.indexOf('firefox') > -1) {
+        browser = `Firefox`
+    } else if (UserAgent.indexOf('opera') > -1) {
+        browser = `Opera`
+    } else if (UserAgent.indexOf('safari') > -1 && UserAgent.indexOf('chrome') == -1) {
+        browser = `Safari`
+    } else if (UserAgent.indexOf('edge') > -1) {
+        browser = `Edge`
+    } else {
+        browser = `Other`
+    }
+    return browser;
+}

+ 29 - 10
src/view/components/currency-list.vue

@@ -2,14 +2,23 @@
 <template>
     <div class="currency-list-wrapper">
         <div class="search-input-wrapper">
-            <input class="input" v-model="keywords" @input="onInput" placeholder="Search name" />
+            <input class="input" 
+                :style="{width: !showRefresh ? '100%' : '88%'}"
+                v-model="keywords" 
+                placeholder="Search name"
+                @input="onInput" />
+
             <img :src="require('../../assets/svg/icon-form-refresh.svg')" 
+                v-if="showRefresh"
                 class="icon"
                 :class="{ 'icon-refresh-rotate': refreshRotate }"
                 @click="refresh">
-            <img :src="require('../../assets/svg/icon-clear-search.svg')" class="icon-clear"
-            v-if="keywords"
-            @click="clearIpt" >
+
+            <img :src="require('../../assets/svg/icon-clear-search.svg')" 
+                class="icon-clear"
+                v-if="keywords"
+                :style="{right: !showRefresh ? '6%' : '16%'}"
+                @click="clearIpt" >
         </div>
         <div class="list-wrapper" ref="listWrapperDom" @scroll="listScroll">
             <div class="page-list" ref="listContentDom" v-if="!showSearch">
@@ -22,7 +31,7 @@
                             {{ item.type == 1 ? 'Cash' : 'Crypto' }}
                         </div>
                         <div class="item-detail" v-for="(data, idx) in item.data" :key="idx"
-                            @click="selectCurrency(data.currencies)">
+                            @click="selectCurrency(data)">
                             <div class="left">
                                 <img class="icon-currency" :src="data.currencies[0].iconPath" />
                                 <div class="currency-info">
@@ -47,13 +56,13 @@
                     </template>
                 </div>
                 <div class="no-data" v-if="show_empty">
-                    {{page != 'top-up' ? 'Not found' : 'No balance'}}
+                    Not found
                 </div>
 
             </div>
             <!-- 显示搜索结果列表 -->
             <div class="search-list" v-else>
-                <div class="item-detail" v-for="(data, idx) in searchList" :key="idx" @click="selectCurrency(data.currencies)">
+                <div class="item-detail" v-for="(data, idx) in searchList" :key="idx" @click="selectCurrency(data)">
                     <div class="left">
                         <img class="icon-currency" :src="data.currencies[0].iconPath" />
                         <div class="currency-info">
@@ -75,7 +84,7 @@
                     </div>
                 </div>
                 <div class="no-data" v-if="!searchList.length">
-                    {{page != 'top-up' ? 'Not found' : 'No balance'}}
+                    Not found
                 </div>
             </div>
         </div>
@@ -96,6 +105,10 @@ const props = defineProps({
     filterEmptyBalance: {
         type: Boolean,
         default: false
+    },
+    showRefresh: {
+        type: Boolean,
+        default: true
     }
 })
 let keywords = ref('');
@@ -233,7 +246,7 @@ const listScroll = (e) => {
     let scrollTop = e.target.scrollTop || 0;
     if (
         listReqParams.loadMore === false &&
-        wrapperHeight + scrollTop >= listContentHeight
+        wrapperHeight + scrollTop >= (listContentHeight - 50)
     ) {
         listReqParams.loadMore = true;
         listReqParams.params.pageNum++;
@@ -276,6 +289,11 @@ defineExpose({
             border: none;
             outline: none;
             padding: 10px 80px 10px 22px;
+            color: #adadad;
+        }
+
+        input::placeholder {
+            color: #adadad;
         }
 
         .icon {
@@ -308,7 +326,6 @@ defineExpose({
                 padding: 0 10px;
                 box-sizing: border-box;
                 background: #f7f7f7;
-                font-weight: 500;
                 font-size: 14px;
                 color: #a2a2a2;
 
@@ -335,6 +352,7 @@ defineExpose({
                     width: 24px;
                     height: 24px;
                     margin-right: 12px;
+                    margin-top: 4px;
                 }
 
                 .currency-info {
@@ -342,6 +360,7 @@ defineExpose({
                         font-weight: 500;
                         font-size: 15px;
                         margin-bottom: 5px;
+                        word-break: break-all;
                     }
 
                     .desc {

+ 88 - 44
src/view/components/popup-transactions.vue

@@ -22,7 +22,7 @@
                         <template v-if="item.bizType == 1">
                             <img class="icon-avatar" :src="item.bizData.avatarUrl" />
                             <img class="icon-give" :src="
-                                require('@/assets/svg/icon-giveaways.svg')
+                                require('@/assets/svg/icon-get-giveaways-s.svg')
                             " />
                         </template>
                         <!-- 收入- 任务红包结余退款, -->
@@ -55,6 +55,12 @@
                                         require('@/assets/svg/icon-big-give.svg')
                             " />
                         </template>
+                        <!-- 支出-买盲盒 -->
+                        <template v-else-if="item.bizType == -3">
+                            <img style="margin-left:-4px" :src="
+                                        require('@/assets/svg/icon-wallter-list-blind-box.svg')
+                            " />
+                        </template>
                     </div>
                     <div class="info-wrapper">
                         <div class="left">
@@ -77,24 +83,29 @@
                                 <template v-else-if="item.bizType == -2">
                                     Giveaways
                                 </template>
+                                <template v-else-if="item.bizType == -3">
+                                    Mystery box*{{(item.bizData && item.bizData.nftItemCount || '')}}  Sold
+                                </template>
                             </div>
                             <div class="time">{{ moment(item.createTimestamp).format('MM-DD HH:mm:ss') }}</div>
                         </div>
                         <div class="right">
                             <div class="msg">
-                                <!-- 支出--提现 -->
                                 <template v-if="item.bizType == -1">
-                                    <!-- 提现状态(0:已申请,1:支付中,2:提现成功,3:提现失败) -->
+                                    <!-- 提现支出-状态(0:已申请,1:支付中,2:提现成功,3:提现失败) -->
                                     <template v-if="item.bizData.withdrawStatus == 0 || item.bizData.withdrawStatus == 1">
                                         <div>
-                                            <div class="balance">
+                                            <div class="balance"
+                                                :class="{'balance-direction': item.trxAmountCurrencyInfo.tokenSymbol.length + ('' + item.trxAmountValue).length > 12}">
                                                 <span class="amount">
                                                     <a-tooltip :title="'-'+item.trxAmountValue">
                                                         -{{ getBit(item.trxAmountValue) || 0 }}
                                                     </a-tooltip>
                                                 </span>
-                                                <span class="name">{{ item.trxAmountCurrencyInfo.tokenSymbol }}</span>
-                                                <img :src="item.trxAmountCurrencyInfo.iconPath" alt="">
+                                                <div class="trx-amount-currency-info">
+                                                    <span class="name">{{ item.trxAmountCurrencyInfo.tokenSymbol }}</span>
+                                                    <img :src="item.trxAmountCurrencyInfo.iconPath" alt="">
+                                                </div>
                                             </div>
                                             <div class="desc">
                                                 in progress
@@ -102,26 +113,32 @@
                                         </div>
                                     </template>
                                     <template v-else-if="item.bizData.withdrawStatus == 2">
-                                        <div class="balance">
+                                        <div class="balance"
+                                            :class="{'balance-direction': item.trxAmountCurrencyInfo.tokenSymbol.length + ('' + item.trxAmountValue).length > 12}">
                                             <span class="amount">
                                                 <a-tooltip :title="'-'+item.trxAmountValue">
                                                     -{{ getBit(item.trxAmountValue) || 0 }}
                                                 </a-tooltip>
                                             </span>
-                                            <span class="name">{{ item.trxAmountCurrencyInfo.tokenSymbol }}</span>
-                                            <img :src="item.trxAmountCurrencyInfo.iconPath" alt="">
+                                            <div class="trx-amount-currency-info">
+                                                <span class="name">{{ item.trxAmountCurrencyInfo.tokenSymbol }}</span>
+                                                <img :src="item.trxAmountCurrencyInfo.iconPath" alt="">
+                                            </div>
                                         </div>
                                     </template>
                                     <template v-else-if="item.bizData.withdrawStatus == 3">
                                         <div>
-                                            <div class="balance">
+                                            <div class="balance"
+                                                :class="{'balance-direction': item.trxAmountCurrencyInfo.tokenSymbol.length + ('' + item.trxAmountValue).length > 12}">
                                                 <span class="amount"> 
                                                     <a-tooltip :title="'-'+item.trxAmountValue">
                                                         -{{ getBit(item.trxAmountValue) || 0 }}
                                                     </a-tooltip>
                                                 </span>
-                                                <span class="name">{{ item.trxAmountCurrencyInfo.tokenSymbol }}</span>
-                                                <img :src="item.trxAmountCurrencyInfo.iconPath" alt="">
+                                                <div class="trx-amount-currency-info">
+                                                    <span class="name">{{ item.trxAmountCurrencyInfo.tokenSymbol }}</span>
+                                                    <img :src="item.trxAmountCurrencyInfo.iconPath" alt="">
+                                                </div>
                                             </div>
                                             <div class="desc">
                                                 Withdrawal failed
@@ -129,25 +146,44 @@
                                         </div>
                                     </template>
                                     <template v-else>
-                                        <span class="amount">
-                                            <a-tooltip :title="'-'+item.trxAmountValue">
-                                                -{{ getBit(item.trxAmountValue) || 0 }}
-                                            </a-tooltip>
-                                        </span>
-                                        <span class="name">{{ item.trxAmountCurrencyInfo.tokenSymbol }}</span>
-                                        <img :src="item.trxAmountCurrencyInfo.iconPath" alt="">
+                                        <div class="balance"
+                                            :class="{'balance-direction': item.trxAmountCurrencyInfo.tokenSymbol.length + ('' + item.trxAmountValue).length > 12}">
+                                            <span class="amount">
+                                                <a-tooltip :title="'-'+item.trxAmountValue">
+                                                    -{{ getBit(item.trxAmountValue) || 0 }}
+                                                </a-tooltip>
+                                            </span>
+                                            <div class="trx-amount-currency-info">
+                                                <span class="name">{{ item.trxAmountCurrencyInfo.tokenSymbol }}</span>
+                                                <img :src="item.trxAmountCurrencyInfo.iconPath" alt="">
+                                            </div>
+                                        </div>
                                     </template>
                                 </template>
-                                <!-- 收入 -->
+
                                 <template v-else>
-                                    <span class="amount">
-                                        <template v-if="item.bizType == -2">-</template>
-                                        <a-tooltip :title="item.bizType == -2 ? '-' + item.trxAmountValue : item.trxAmountValue">
-                                            {{ getBit(item.trxAmountValue) || 0 }}
-                                        </a-tooltip>
-                                    </span>
-                                    <span class="name">{{ item.trxAmountCurrencyInfo.tokenSymbol }}</span>
-                                    <img :src="item.trxAmountCurrencyInfo.iconPath" alt="">
+                                    <div class="balance"
+                                        :class="{'balance-direction': item.trxAmountCurrencyInfo.tokenSymbol.length + ('' + item.trxAmountValue).length > 12}">
+
+                                        <!--支出—— -2:零钱余额支付 、-3: NFT盲盒余额支付 -->
+                                        <span class="amount" v-if="item.bizType == -2 || item.bizType == -3">
+                                            -
+                                            <a-tooltip :title="'-' + item.trxAmountValue">
+                                                {{ getBit(item.trxAmountValue) || 0 }}
+                                            </a-tooltip>
+                                        </span>
+                                        <!-- 收入—— bizType:1、2、3、4 -->
+                                        <span class="amount" v-else>
+                                            <a-tooltip :title="item.trxAmountValue">
+                                                {{ getBit(item.trxAmountValue) || 0 }}
+                                            </a-tooltip>
+                                        </span>
+
+                                        <div class="trx-amount-currency-info">
+                                            <span class="name">{{ item.trxAmountCurrencyInfo.tokenSymbol }}</span>
+                                            <img :src="item.trxAmountCurrencyInfo.iconPath" alt="">
+                                        </div>
+                                    </div>
                                 </template>
                             </div>
                         </div>
@@ -160,7 +196,7 @@
 
 <script setup>
 /* eslint-disable */
-import { onMounted, ref, defineProps, defineEmits, onBeforeUnmount } from "vue";
+import { onMounted, ref, defineProps, defineEmits } from "vue";
 
 import redDot from "@/view/components/red-dot.vue";
 
@@ -178,7 +214,7 @@ let listContent = ref(null);
 let listReqParams = {
     params: {
         pageNum: 1,
-        pageSize: 10,
+        pageSize: 20,
     },
     loadMore: false,
 };
@@ -212,13 +248,6 @@ const getTransactionsList = () => {
 
 onMounted(() => {
     chrome.runtime.connect({ name: "popup_transactions" });
-    readAllMsgByType({
-        params: {
-            msgType: 1
-        }
-    }).then(res => {
-        setMessageCount();
-    });
     setTimeout(() => {
         isReadMsg.value = false;
         readAllMsgByType({
@@ -305,7 +334,6 @@ const listScroll = (e) => {
         .cell {
             display: flex;
             justify-content: space-between;
-            align-items: center;
             min-height: 66px;
             box-sizing: border-box;
             padding-left: 20px;
@@ -321,17 +349,19 @@ const listScroll = (e) => {
                 position: relative;
                 margin-right: 16px;
                 box-sizing: border-box;
+                margin-top: 11px;
 
                 .icon-avatar {
                     width: 34px;
                     height: 34px;
                     border-radius: 50%;
+                    margin-right: 4px;
                 }
 
                 .icon-give {
                     position: absolute;
-                    right: -4px;
-                    bottom: 2px;
+                    right: -2px;
+                    top: 19px;
                 }
             }
 
@@ -341,7 +371,6 @@ const listScroll = (e) => {
                 display: flex;
                 justify-content: space-between;
                 align-items: center;
-                border-bottom: 1px solid #ECECEC;
                 box-sizing: border-box;
                 padding: 10px 12px 10px 0;
 
@@ -351,7 +380,7 @@ const listScroll = (e) => {
                         font-size: 14px;
                         margin-bottom: 5px;
                         word-break: break-all;
-                        max-width: 120px;
+                        max-width: 140px;
                     }
 
                     .time {
@@ -373,6 +402,7 @@ const listScroll = (e) => {
 
                         .amount {
                             max-width: 110px;
+                            min-width: 20px;
                             display: inline-block;
                             word-break: break-all;
                             text-align: right;
@@ -380,7 +410,11 @@ const listScroll = (e) => {
 
                         .name {
                             margin-left: 3px;
-                            color: #E29A2E;
+                            color: #E86F00;
+                            max-width: 130px;
+                            line-height: 14px;
+                            font-size: 13px;
+                            word-break: break-all;
                         }
 
                         img {
@@ -391,9 +425,18 @@ const listScroll = (e) => {
 
                         .balance {
                             text-align: right;
-                            margin-bottom: 4px;
                             display: flex;
                             align-items: center;
+
+                            .trx-amount-currency-info {
+                                display: flex;
+                                align-items: center;
+                            }
+                        }
+
+                        .balance-direction {
+                            flex-direction: column;
+                            align-items: flex-end;
                         }
 
                         .desc {
@@ -401,6 +444,7 @@ const listScroll = (e) => {
                             font-weight: 400;
                             font-size: 12px;
                             color: #797979;
+                            margin-top: 4px;
                         }
                     }
 

+ 144 - 0
src/view/components/preview-balance.vue

@@ -0,0 +1,144 @@
+<template>
+    <div class="card-amount">
+        <img class="icon" src="@/assets/subject/icon-balance.png" />
+        <div class="con">
+            <div class="desc">Balance</div>
+            <div class="price">{{ currentCurrencyInfo.balance }} {{ props.tokenSymbol }}</div>
+        </div>
+        <img class="refresh" :class="{ 'icon-refresh-rotate': refreshRotate }" @click="updateCurrencyBanlce"
+            :src="require('@/assets/svg/icon-form-refresh-blue.svg')" />
+    </div>
+</template>
+<script setup>
+import { ref, onMounted, reactive, defineProps, defineEmits } from "vue";
+import { syncChainTokenRechargeRecord } from "@/http/publishApi";
+const emits = defineEmits(["updateData"]);
+const props = defineProps({
+    dialogVisible: {
+        type: Object,
+        default: {},
+    },
+    currencyCode: {
+        type: String,
+        default: ''
+    },
+    tokenSymbol: {
+        type: String,
+        default: ''
+    }
+});
+
+/**
+ * 同步链上交易
+ */
+const asyncTokenRechRecord = () => {
+    syncChainTokenRechargeRecord({
+        params: {
+            currencyCode: props.currencyCode
+        }
+    }).then(res => {
+        if (res.code == 0) {
+            let data = res.data || []
+            if (data.length > 0) {
+                let currencyInfo = data[0];
+                if (currencyInfo.currencyCode == props.currencyCode) {
+                    currentCurrencyInfo.balance = currencyInfo.balance;
+                    emits('updateData', currentCurrencyInfo)
+                }
+            } else {
+                currentCurrencyInfo.balance = 0
+                emits('updateData', currentCurrencyInfo)
+            }
+        }
+    })
+}
+// 刷新按钮旋转
+let refreshRotate = ref(false);
+
+// 当前选择的货币信息
+let currentCurrencyInfo = reactive({
+    currencyCode: "",
+    currencyName: "",
+    balance: "",
+    currencyType: "",
+    iconPath: "",
+    minAmount: "",
+    tokenChain: "",
+    tokenSymbol: "",
+    usdEstimateBalance: ""
+});
+
+/**
+ * 更新货币余额
+ */
+const updateCurrencyBanlce = () => {
+    if (!refreshRotate.value) {
+        refreshRotate.value = true;
+        setTimeout(() => {
+            refreshRotate.value = false;
+        }, 1000)
+    }
+    asyncTokenRechRecord()
+}
+
+
+onMounted(() => {
+    console.log(props.currencyCode)
+    if (!props.currencyCode) {
+        return
+    }
+    asyncTokenRechRecord()
+    setInterval(() => {
+        asyncTokenRechRecord()
+    }, 10000)
+})
+
+</script>
+
+<style lang="scss" scoped>
+.card-amount {
+    overflow: hidden;
+    display: flex;
+    align-items: center;
+    padding: 20px;
+    border-radius: 20px;
+    border: 1px solid #E6E6E6;
+
+    .icon {
+        width: 40px;
+        height: 40px;
+    }
+
+    .con {
+        flex: 1;
+        padding: 0 10px;
+
+        .desc {
+            color: rgba($color: #000000, $alpha: 0.5);
+            font-size: 12px;
+            margin-bottom: 4px;
+            line-height: 14px;
+        }
+
+        .price {
+            font-size: 16px;
+            font-weight: bold;
+            line-height: 19px;
+        }
+    }
+
+    .refresh {
+        cursor: pointer;
+        width: 30px;
+        height: 30px;
+        margin-top: -5px;
+    }
+
+
+}
+
+.icon-refresh-rotate {
+    transform: rotate(360deg);
+    transition-duration: 1s;
+}
+</style>

+ 300 - 0
src/view/iframe/buy-nft/buy/home.vue

@@ -0,0 +1,300 @@
+<template>
+    <div class="dialog">
+        <!-- home -->
+        <div class="area-title">
+            <img :src="require('@/assets/svg/icon-close.svg')" @click="clickClose" />
+            <div class="title">NFT Mystery box</div>
+        </div>
+        <!-- 内容 -->
+        <div class="area-content">
+            <img :src="state.data.mysteryBoxImagePath" class="box" v-show="state.data.mysteryBoxImagePath" />
+            <img :src="require('@/assets/svg/icon-default.svg')" class="box" v-show="!state.data.mysteryBoxImagePath" />
+        </div>
+
+        <!-- 底部 -->
+        <div class="footer" v-show="state.data.mysteryBoxImagePath">
+            <!-- 首页 -->
+            <div class="mark">
+                <div class="sold">SOLD: {{ state.data.itemSoldCount || 0 }}/{{ state.data.itemTotalCount || 0 }} </div>
+                <div class="limit">Buy Limit: {{ state.data.userBuyCount || 0 }}/{{ state.data.perUserBuyLimit || 0 }}
+                </div>
+            </div>
+            <div class="btn-area">
+                <template v-for="item in state.data.salePlans.splice(0, 2).reverse()">
+                    <div class="buy1" @click="clickJump(item)" v-if="item.itemCount == 1 && (state.data.perUserBuyLimit - state.data.userBuyCount) >= 1
+                    && (state.data.itemTotalCount - state.data.itemSoldCount) >= 1">
+                        <template v-if="(item.price.length + item.currencyInfo.tokenSymbol.length) > 30">
+                            <div class="left">Buy 1</div>
+                            <div class="right">
+                                <p>{{ item.price }}</p>
+                                <p>{{ item.currencyInfo.tokenSymbol }}</p>
+                            </div>
+                        </template>
+                        <template v-else>
+                            <div class="left">Buy 1</div>
+                            <div class="right">
+                                {{ item.price }}
+                                {{ item.currencyInfo.tokenSymbol }}
+                            </div>
+                        </template>
+                    </div>
+                    <div class="buy1 grey" v-if="item.itemCount == 1 && ((state.data.perUserBuyLimit - state.data.userBuyCount) <= 0
+                    || (state.data.itemTotalCount - state.data.itemSoldCount) <= 0)">
+                        <template v-if="(item.price.length + item.currencyInfo.tokenSymbol.length) > 30">
+                            <div class="left">Buy 1</div>
+                            <div class="right">
+                                <p>{{ item.price }}</p>
+                                <p>{{ item.currencyInfo.tokenSymbol }}</p>
+                            </div>
+                        </template>
+                        <template v-else>
+                            <div class="left">Buy 1</div>
+                            <div class="right">
+                                {{ item.price }}
+                                {{ item.currencyInfo.tokenSymbol }}
+                            </div>
+                        </template>
+                    </div>
+
+                    <div class="buy5" v-if="item.itemCount == 5 && (state.data.perUserBuyLimit - state.data.userBuyCount) >= 5 &&
+                    (state.data.itemTotalCount - state.data.itemSoldCount) >= 5" @click="clickJump(item)">
+                        <div class="left">Buy {{ item.itemCount }}</div>
+
+                        <div class="right" v-if="(item.price.length + item.currencyInfo.tokenSymbol.length) > 30">
+                            <div class="usdt">
+                                <p>{{ item.price }}</p>
+                                <p>{{ item.currencyInfo.tokenSymbol }}</p>
+                            </div>
+                            <div class="off">
+                                <p>{{ item.discount }}</p>
+                            </div>
+                        </div>
+                        <div class="right" v-else>
+                            <div class="usdt">{{ item.price }} {{ item.currencyInfo.tokenSymbol }}</div>
+                            <div class="off">{{ item.discount }}</div>
+                        </div>
+                    </div>
+                </template>
+            </div>
+        </div>
+    </div>
+</template>
+<script setup>
+import router from "@/router/buy-nft.js";
+import { onMounted, reactive, inject, } from "vue";
+import { getNftMysteryBoxSaleInfo } from "@/http/nft";
+import BtnLoading from '../components/btn-loading.vue'
+import { getQueryString } from "@/uilts/help";
+let pay_info = inject('pay_info');
+let state = reactive({
+    data: {
+        salePlans: [
+            {
+                currencyCode: 'BSC_TESTNET_BF_6X',
+                discount: '20$',
+                itemCount: 5,
+                price: 23,
+                salePlanId: '2'
+            },
+            {
+                currencyCode: 'BSC_TESTNET_BF_6X',
+                discount: '20$',
+                itemCount: 1,
+                price: 123,
+                salePlanId: '123'
+            }
+        ]
+    }
+})
+const clickClose = () => {
+    chrome.tabs.getCurrent((tab) => {
+        chrome.tabs.sendMessage(tab.id, {
+            actionType: "IFRAME_TWITTER_HIDE_BUY_NFT",
+        }, (res) => { });
+    })
+}
+const clickJump = (item) => {
+    pay_info.home.sale_plan = item
+    router.push({ path: '/pay' });
+}
+onMounted(() => {
+    let nft_project_Id = getQueryString('nftProjectId') || ''
+    if (!nft_project_Id) {
+        return
+    }
+    getNftMysteryBoxSaleInfo({
+        params: {
+            nftProjectId: nft_project_Id
+        }
+    }).then((res) => {
+        if (res.code == 0) {
+            state.data = res.data
+            pay_info.home = res.data
+        } else {
+
+        }
+    }).catch(() => {
+
+    })
+})
+</script>
+
+<style lang="scss" scoped>
+.dialog {
+    background: #fff;
+    border-radius: 25px;
+    max-width: 1000px;
+    min-width: 800px;
+    max-height: 90%;
+    min-height: 90%;
+    z-index: 23;
+    display: flex;
+    flex-direction: column;
+
+
+    .area-title {
+        width: 100%;
+        min-height: 48px;
+        display: flex;
+        align-items: center;
+        border-bottom: 1px solid #D9D9D9;
+        font-weight: 500;
+        font-size: 16px;
+        letter-spacing: 0.3px;
+        color: #000000;
+
+        img {
+            width: 24p;
+            height: 24px;
+            margin-left: 14px;
+            margin-right: 12px;
+            cursor: pointer;
+        }
+
+    }
+
+    .area-content {
+        flex: 1;
+        overflow-y: auto;
+
+        img {
+            width: 100%;
+            height: 100%;
+        }
+    }
+
+    .footer {
+        border-top: 1px solid #D9D9D9;
+        width: 100%;
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+
+        .loading {
+            width: 24px;
+        }
+
+        .mark {
+            margin-left: 20px;
+
+            .sold {}
+
+            .limit {
+                color: #AF934E;
+                margin-right: 25px;
+            }
+        }
+
+        .btn-area {
+            height: 100%;
+            display: flex;
+            padding: 15px 0;
+            min-height: 50px;
+
+            .buy5 {
+                border: 1px solid #1D9BF0;
+                background: rgba(29, 155, 240, 0.01);
+                border-radius: 100px;
+                color: #1D9BF0;
+                min-width: 217px;
+                display: flex;
+
+                justify-content: space-between;
+                align-items: center;
+                padding: 10px 15px 10px 20px;
+                font-weight: 700;
+                font-size: 14px;
+                cursor: pointer;
+                margin-right: 12px;
+
+                .left {
+                    margin-right: 20px;
+                }
+
+                .right {
+                    text-align: right;
+                    line-height: 17px;
+
+                    p {
+                        margin: 0;
+                        padding: 0;
+                        line-height: 17px;
+                    }
+                }
+
+
+                .off {
+                    color: #AF934E;
+                    font-weight: 700;
+                    font-size: 14px;
+
+                    letter-spacing: 0.3px;
+                }
+
+                .usdt {
+                    color: #1D9BF0;
+                    font-size: 14px;
+                    font-weight: 700;
+
+                }
+            }
+
+            .buy1 {
+                cursor: pointer;
+                background: #1D9BF0;
+                color: #fff;
+                border-radius: 100px;
+                min-width: 217px;
+                display: flex;
+                align-items: center;
+                font-size: 14px;
+                font-weight: 700;
+                justify-content: space-between;
+                padding: 0 15px 0 20px;
+                margin-right: 25px;
+
+                .left {
+                    margin-right: 20px;
+                }
+
+                .right {
+                    line-height: 17px;
+                    text-align: right;
+
+                    p {
+                        margin: 0;
+                        padding: 0;
+                        line-height: 17px;
+                    }
+                }
+
+            }
+
+            .grey {
+                background: #CDCDCD;
+                cursor: not-allowed;
+            }
+        }
+    }
+}
+</style>

+ 142 - 0
src/view/iframe/buy-nft/buy/open-box.vue

@@ -0,0 +1,142 @@
+<template>
+    <!-- gif -->
+    <div class="box_content">
+        <img :src="require('@/assets/gif/box.gif')" class="box" v-show="state.box.show" />
+        <div class="nft" v-for="item in state.nft.data" v-show="item.show">
+            <div class="detail">
+                <img :src="item.imagePath" alt="" />
+            </div>
+            <p>{{ item.nftItemName }}</p>
+        </div>
+    </div>
+</template>
+<script setup>
+import { reactive, onMounted, inject } from 'vue'
+import router from "@/router/buy-nft.js";
+let pay_info = inject('pay_info');
+let state = reactive({
+    box: {
+        show: true
+    },
+    nft: {
+        data: []
+    }
+})
+
+const setAllNoShow = () => {
+    state.nft.data.forEach((item) => {
+        item.show = false
+    })
+}
+
+const showNFTs = () => {
+    let len = state.nft.data.length
+    if (len == 0) {
+        return
+    }
+    let i = 0
+    setAllNoShow()
+    state.nft.data[i].show = true
+    i++
+    let timer = setInterval(() => {
+        if (len > i) {
+            setAllNoShow()
+            state.nft.data[i].show = true
+        } else {
+            clearInterval(timer)
+            chrome.tabs.getCurrent((tab) => {
+                chrome.tabs.sendMessage(tab.id, {
+                    actionType: "IFRAME_TWITTER_HIDE_BUY_NFT",
+                }, (res) => { });
+                chrome.tabs.sendMessage(tab.id, {
+                    actionType: "IFRAME_TWITTER_SHOW_POPUP_PAGE",
+                    data: {
+                        from: 'BUY_NFT_FINISH'
+                    }
+                }, (res) => { });
+                router.replace('/')
+            })
+        }
+        i++
+    }, 2000)
+}
+
+onMounted(() => {
+    state.nft.data = pay_info.buy_items || []
+    setTimeout(() => {
+        state.box.show = false
+        showNFTs()
+    }, 2000)
+})
+</script>
+<style lang="scss" scoped>
+.box_content {
+    position: fixed;
+    text-align: center;
+    display: flex;
+    justify-content: center;
+    z-index: 2;
+
+    .box {
+        width: 200px;
+        position: absolute;
+        top: 40%;
+        left: 50%;
+        margin-top: -100px;
+        margin-left: -100px;
+    }
+
+    .nft {
+        position: absolute;
+        top: 40%;
+        margin-top: -200px;
+        width: 400px;
+        height: 450px;
+        animation: myfirst 0.5s;
+
+        display: flex;
+        flex-direction: column;
+
+        .detail {
+            flex: 1;
+            text-align: center;
+
+            img {
+                width: 100%;
+                height: 100%;
+                border: 3px solid white;
+                border-radius: 10px;
+            }
+        }
+
+        p {
+            margin: 0;
+            padding: 0;
+            margin-top: 20px;
+            color: #FFFFFF;
+            font-size: 16px;
+            font-weight: 700;
+        }
+
+    }
+}
+
+@keyframes myfirst {
+    0% {
+        width: 300px;
+        height: 300px;
+    }
+
+    50% {
+        width: 450px;
+        height: 500px;
+        margin-top: -210px;
+    }
+
+    100% {
+        margin-top: -200px;
+        width: 400px;
+        height: 450px;
+    }
+}
+</style>

+ 431 - 0
src/view/iframe/buy-nft/buy/pay.vue

@@ -0,0 +1,431 @@
+<template>
+    <div class="dialog">
+        <!-- home -->
+        <div class="area-title">
+            <img :src="require('@/assets/svg/icon-back.svg')" @click="clickBack" />
+            <div class="title">Payment</div>
+        </div>
+        <!-- 内容 -->
+        <div class="area-content">
+            <div class="left">
+                <img :src="require('@/assets/img/img-box5.png')" v-show="pay_info.home.sale_plan.itemCount == 5"
+                    alt="" />
+                <img :src="require('@/assets/img/img-box1.png')" v-show="pay_info.home.sale_plan.itemCount == 1"
+                    alt="" />
+                <div class="tip">
+                    <span>Mystery box*{{ pay_info.home.sale_plan.itemCount }}</span>
+                    <div>
+                        <img :src="pay_info.home.sale_plan.currencyInfo.iconPath" alt="" />
+                        <span>{{ pay_info.home.sale_plan.price }}</span>
+                    </div>
+                </div>
+            </div>
+            <div class="right">
+                <div class="card-content">
+                    <template v-if="tempCurrentCurrencyInfo.currencyCode">
+                        <div class="card-title">
+                            <img class="img" :src="require('@/assets/subject/top-01.svg')" />
+                            <div class="font">Deposit to Send Giveaway</div>
+                        </div>
+                        <top-up2 v-if="tempCurrentCurrencyInfo.currencyCode" :asyncIng="asyncIng"
+                            :currentCurrencyInfo="tempCurrentCurrencyInfo" @topUpDone="topUpDone">
+                        </top-up2>
+
+                        <div class="card-title">
+                            <img class="img" :src="require('@/assets/subject/top-02.svg')" />
+                            <div class="font">Wait for the amount to arrive</div>
+                        </div>
+                        <preview-balance v-if="tempCurrentCurrencyInfo.currencyCode"
+                            :currencyCode="tempCurrentCurrencyInfo.currencyCode"
+                            :tokenSymbol="tempCurrentCurrencyInfo.tokenSymbol" @updateData="updateData">
+                        </preview-balance>
+                    </template>
+                </div>
+            </div>
+        </div>
+
+        <!-- 底部 -->
+        <div class="footer">
+            <div class="buy1" @click="clickPlay" v-if="state.is_btn_grey == false">
+                <btn-loading :color="'while'" v-if="state.loading.show"></btn-loading>
+                <template
+                    v-else-if="(pay_info.home.sale_plan.price.length + pay_info.home.sale_plan.currencyInfo.tokenSymbol.length) > 30">
+                    <div class="left">Pay</div>
+                    <div class="right">
+                        <p>{{ pay_info.home.sale_plan.price }}</p>
+                        <p>{{ pay_info.home.sale_plan.currencyInfo.tokenSymbol }}</p>
+                    </div>
+                </template>
+                <template v-else>
+                    <div class="left">Pay</div>
+                    <div class="right">
+                        {{ pay_info.home.sale_plan.price }}
+                        {{ pay_info.home.sale_plan.currencyInfo.tokenSymbol }}
+                    </div>
+                </template>
+            </div>
+            <div class="buy1 grey" v-else>
+                <template
+                    v-if="(pay_info.home.sale_plan.price.length + pay_info.home.sale_plan.currencyInfo.tokenSymbol.length) > 30">
+                    <div class="left">Pay</div>
+                    <div class="right">
+                        <p>{{ pay_info.home.sale_plan.price }}</p>
+                        <p>{{ pay_info.home.sale_plan.currencyInfo.tokenSymbol }}</p>
+                    </div>
+                </template>
+                <template v-else>
+                    <div class="left">Pay</div>
+                    <div class="right">
+                        {{ pay_info.home.sale_plan.price }}
+                        {{ pay_info.home.sale_plan.currencyInfo.tokenSymbol }}
+                    </div>
+                </template>
+            </div>
+        </div>
+    </div>
+</template>
+<script setup >
+import router from "@/router/buy-nft.js";
+import { ref, onMounted, inject, reactive } from 'vue'
+import topUp2 from "@/view/iframe/publish/components/top-up2.vue";
+import { getCurrencyInfoByCode } from "@/http/publishApi";
+import PreviewBalance from "@/view/components/preview-balance.vue";
+import BtnLoading from '../components/btn-loading.vue'
+import { payNftMysteryBoxWithBalance } from "@/http/pay";
+import { getChromeStorage } from "@/uilts/chromeExtension"
+import { ElMessage } from 'element-plus'
+let pay_info = inject('pay_info');
+let state = reactive({
+    loading: {
+        show: false
+    },
+    is_btn_grey: true
+})
+
+let currentCurrencyInfo = reactive({
+    currencyCode: "",
+    currencyName: "",
+    balance: "",
+});
+
+const updateData = (obj_data) => {
+    if (Number(obj_data.balance) >= Number(pay_info.home.sale_plan.price)) {
+        state.is_btn_grey = false
+    }
+}
+
+const clickBack = () => {
+    router.back()
+}
+const clickPlay = () => {
+    state.loading.show = true
+    payNftMysteryBoxWithBalance({
+        params: {
+            nftProjectId: pay_info.home.nftProjectId,
+            salePlanId: pay_info.home.sale_plan.salePlanId
+        }
+    }).then((res) => {
+        state.loading.show = false
+        if (res.code == 0) {
+            pay_info.buy_items = res.data.buyItems
+            router.push({ path: '/open_box' });
+        } else {
+            let msg = ''
+            switch (res.code.toString()) {
+                case '5001':
+                    msg = 'nft project not exist'
+                    break;
+                case '5002':
+                    msg = 'nft project not available'
+                    break
+                case '5101':
+                    msg = 'nft sale plan not exist'
+                    break
+                case '5102':
+                    msg = 'nft sold out'
+                    break
+                case '5103':
+                    msg = 'Purchase limit reached'
+                    break
+                default:
+                    console.log(res.msg)
+            }
+            ElMessage({
+                message: msg,
+                grouping: true,
+                type: 'warning',
+                offset: -16,
+                appendTo: document.body
+            })
+        }
+    }).catch(() => {
+        state.loading.show = false
+    })
+}
+// 余额是否同步中
+let asyncIng = ref(false);
+
+
+//临时货币信息
+let tempCurrentCurrencyInfo = ref({});
+
+
+const getLocalCurrencyInfoByCode = () => {
+    if (currentCurrencyInfo.currencyCode) {
+        getCurrencyInfo();
+    }
+}
+const getCurrencyInfo = async () => {
+    let { accessToken = '' } = await getChromeStorage('userInfo') || {};
+    if (accessToken) {
+        getCurrencyInfoByCode({
+            params: {
+                currencyCode: currentCurrencyInfo.currencyCode
+            }
+        }).then(res => {
+            if (res.code == 0 && res.data) {
+                currentCurrencyInfo = res.data;
+                tempCurrentCurrencyInfo.value = res.data;
+            }
+        });
+    }
+}
+
+onMounted(() => {
+    currentCurrencyInfo.currencyCode = pay_info.home.sale_plan.currencyCode
+    getLocalCurrencyInfoByCode()
+})
+
+
+</script>
+<style lang="scss" scoped>
+.dialog {
+    background: #fff;
+    border-radius: 25px;
+    max-width: 1000px;
+    min-width: 800px;
+    height: 90%;
+    z-index: 23;
+    display: flex;
+    flex-direction: column;
+
+
+    .area-title {
+        width: 100%;
+        height: 48px;
+        display: flex;
+        align-items: center;
+        border-bottom: 1px solid #D9D9D9;
+        font-weight: 500;
+        font-size: 16px;
+        letter-spacing: 0.3px;
+        color: #000000;
+
+        img {
+            width: 24p;
+            height: 24px;
+            margin-left: 14px;
+            margin-right: 12px;
+            cursor: pointer;
+        }
+
+    }
+
+    .area-content {
+        display: flex;
+        overflow-y: auto;
+        flex: 1;
+
+        .left {
+            width: 400px;
+            margin: 40px 56px 0 56px;
+
+            img {
+                max-width: 400px;
+                max-height: 400px;
+                width: 100%;
+                height: auto;
+            }
+
+            p {
+                margin: 0;
+                padding: 0;
+            }
+
+            .tip {
+                margin-top: 15px;
+                display: flex;
+                justify-content: space-between;
+                div{
+                    display: flex;
+                        align-items: center;
+                }
+
+                img {
+                    margin-right: 4px;
+                    width: 14px;
+                    height: 14px;
+                }
+            }
+        }
+
+        .right {
+            margin: 30px 56px 0px 30px;
+
+            .card-content {
+                float: right;
+                width: 430px;
+                padding-bottom: 22px;
+
+                .card-title {
+
+                    margin-bottom: 12px;
+                    display: flex;
+                    align-items: center;
+
+                    .img {
+                        width: 20px;
+                        height: 20px;
+                        margin-right: 8px;
+                    }
+
+                    .font {
+
+                        font-size: 17px;
+                        font-weight: 500;
+
+                        span {
+                            color: #0091e9;
+                        }
+                    }
+                }
+
+
+
+                .card-list {
+                    padding: 20px;
+                    border-radius: 20px;
+                    border: 1px solid #E6E6E6;
+
+                    .item {
+                        display: flex;
+                        justify-content: space-between;
+                        align-items: center;
+                        height: 47px;
+                        font-size: 14px;
+                        font-weight: 500;
+                        box-shadow: inset 0px -1px 0px #EAEAEA;
+                    }
+                }
+            }
+        }
+    }
+
+    .pay {
+        width: 200px;
+        height: 50px;
+        font-weight: 700;
+        font-size: 18px;
+        margin-right: 30px;
+        color: #FFFFFF;
+        background: #1D9BF0;
+        border-radius: 10000px;
+        text-align: center;
+        line-height: 50px;
+        cursor: pointer;
+
+        p {
+            margin: 0;
+            padding: 0;
+        }
+    }
+
+    .footer {
+        border-top: 1px solid #D9D9D9;
+        height: 80px;
+        width: 100%;
+        display: flex;
+        align-items: center;
+        justify-content: flex-end;
+        position: relative;
+
+        .sold {
+            position: absolute;
+            left: 20px;
+        }
+
+        .limit {
+            color: #AF934E;
+            margin-right: 25px;
+        }
+
+        .buy5 {
+            border: 1px solid #1D9BF0;
+            background: rgba(29, 155, 240, 0.01);
+            border-radius: 100px;
+            color: #1D9BF0;
+            width: 217px;
+            height: 50px;
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            padding: 0 15px 0 20px;
+            font-weight: 700;
+            font-size: 18px;
+            cursor: pointer;
+            margin-right: 12px;
+
+            .off {
+                color: #AF934E;
+                font-weight: 700;
+                font-size: 14px;
+
+                letter-spacing: 0.3px;
+            }
+
+            .usdt {
+                color: #1D9BF0;
+                font-size: 14px;
+                font-weight: 700;
+
+            }
+        }
+
+        .buy1 {
+            cursor: pointer;
+            background: #1D9BF0;
+            color: #fff;
+            border-radius: 100px;
+            min-width: 217px;
+            min-height: 50px;
+            display: flex;
+            align-items: center;
+            font-size: 14px;
+            font-weight: 700;
+            justify-content: space-between;
+            padding: 0 15px 0 20px;
+            margin-right: 25px;
+
+            .left {
+                margin-right: 20px;
+            }
+
+            .right {
+                text-align: right;
+
+                p {
+                    margin: 0;
+                    padding: 0;
+                    line-height: 17px;
+                }
+            }
+
+        }
+
+        .grey {
+            background: #CDCDCD;
+            cursor: not-allowed;
+        }
+    }
+}
+</style>

+ 29 - 0
src/view/iframe/buy-nft/components/btn-loading.vue

@@ -0,0 +1,29 @@
+<template>
+    <div class="btn-loading">
+        <img :src="require('@/assets/svg/icon-loading.svg')" class="loading" v-if="props.color == 'blue'"/>
+        <img :src="require('@/assets/svg/icon-loading-while.svg')" class="loading" v-else-if="props.color == 'while'"/>
+    </div>
+</template>
+<script setup>
+import {  defineProps } from 'vue'
+const props = defineProps({
+    color: {
+        type: String,
+        default: 'blue',
+    },
+})
+</script>
+<style lang="scss" scoped>
+.btn-loading{
+    width: 100%;
+    height: 100%;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    cursor: auto;
+    img{
+        width:24px;
+        height: 24px;
+    }
+}
+</style>

+ 40 - 0
src/view/iframe/buy-nft/index.vue

@@ -0,0 +1,40 @@
+<template>
+    <div class="content">
+        <router-view></router-view>
+    </div>
+</template>
+<script setup>
+import { reactive, provide } from 'vue'
+let pay_info = reactive({})
+provide('pay_info', pay_info)
+let state = reactive({
+    // 
+    show: 'dialog-home'
+})
+
+
+
+</script>
+<style lang="scss" >
+html,
+body,
+#app {
+    width: 100%;
+    height: 100%;
+    margin: 0;
+    padding: 0;
+}
+
+body {
+
+    background-color: rgba(0, 0, 0, 0.5);
+}
+
+.content {
+    width: 100%;
+    height: 100%;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+}
+</style>

+ 1 - 0
src/view/iframe/home/home.vue

@@ -39,6 +39,7 @@ onMounted(() => {
         box-shadow: 0px 4px 20px rgba(0, 0, 0, 0.2);
         border-radius: 15px;
         position: relative;
+        overflow-y: auto;
     }
 }
 /deep/ .page-wrapper {

+ 248 - 0
src/view/iframe/nft/card.vue

@@ -0,0 +1,248 @@
+<template>
+    <div class="nft" :class="{ border: isShare }">
+        <template v-if="!isLoading">
+            <div class="title">
+                <div class="tag">
+                    <img class="logo" :src="saleData.nftProjectAvatar" />
+                    <font class="text">{{saleData.nftProjectName}}</font>
+                    <img class="tagImg" :src=" require('@/assets/img/icon-nft.png') " />
+                </div>
+                <div class="share" v-if="!isShare" @click="share">
+                    <img :src=" require('@/assets/img/icon-ntf-share.png') " />
+                </div>
+            </div>
+            <div class="content">
+                <img :src="saleData.windowImagePath" />
+            </div>
+            <div class="buy" @click="buy">
+                <img class="guide" v-if="isShowGuide" :src=" require('@/assets/img/icon-arrow.png') " />
+                <button>Buy NFT</button>
+            </div>
+        </template>
+    </div>
+</template>
+
+<script setup>
+import { onBeforeMount, ref } from 'vue'
+import { getTwitterSaleNftProjectInfo, getNftProjectInfo } from '@/http/nft'
+import { pageUrl } from "@/http/configAPI.js"
+import { getChromeStorage, setChromeStorage } from '@/uilts/chromeExtension.js'
+const saleData = ref({});
+const isShare = ref(false);
+const isLoading = ref(true);
+const isShowGuide = ref(false);
+
+const getSaleInfo = () => {
+    chrome.tabs.getCurrent((tab) => {
+        let url = new URL(tab.url);
+        let pathname = url.pathname;
+        let pathArr, account;
+        if (pathname) {
+            pathname = decodeURIComponent(pathname);
+            pathname = pathname.slice(1);
+            pathArr = pathname.split('/');
+            account = pathArr[0];
+            getSaleProjectInfo(account);
+        }
+    })
+}
+
+const getSaleData = (projectId) => {
+    getNftProjectInfo({
+        params: {
+            nftProjectId: projectId
+        }
+    }).then(res => {
+        let { data } = res;
+        if (data !== null) {
+            // setData
+            saleData.value = data;
+            isLoading.value = false;
+        }
+    })
+}
+
+const getSaleProjectInfo = (account) => {
+    getTwitterSaleNftProjectInfo({
+        params: {
+            twitterAccount: account
+        }
+    }).then(res => {
+        let { data } = res;
+        if (data !== null) {
+            // setData
+            saleData.value = data;
+            isLoading.value = false;
+            // postMessage
+            chrome.tabs.getCurrent((tab) => {
+                chrome.tabs.sendMessage(tab.id, { actionType: "IFRAME_NFT_SHOW_SALE" });
+            })
+            getChromeStorage('nft_guide', (info) => {
+                if (!info) {
+                    isShowGuide.value = true
+                    setTimeout(() => {
+                        setChromeStorage({ nft_guide: Date.now() })
+                    }, 2000)
+                }
+            })
+        }
+    })
+}
+
+const share = () => {
+    chrome.tabs.getCurrent((tab) => {
+        let tagUrl = new URL(tab.url);
+        let tagPathName = tagUrl.pathname.slice(1);
+        let tagSearch = ``;
+        if (tagPathName) {
+            let tagArr = tagPathName.split('/');
+            tagSearch = `${btoa(tagArr[0])}`
+        }
+        let url = pageUrl + `/nft/${saleData.value.nftProjectId}/${tagSearch}`
+        let content = `#DNFT\r\r${url}`
+        chrome.tabs.getCurrent((tab) => {
+            chrome.tabs.sendMessage(tab.id, { actionType: "IFRAME_TWITTER_PUBLISH", publishRes: { srcContent: content }  });
+        });
+    });
+}
+
+const buy = () => {
+    getChromeStorage('userInfo', (_userInfo) => {
+        if (!_userInfo) {
+            chrome.runtime.sendMessage(
+                { actionType: "POPUP_LOGIN", data: "" },
+                (response) => {
+                    console.log("res", response);
+                }
+            )
+        } else {
+            chrome.tabs.getCurrent((tab) => {
+                chrome.tabs.sendMessage(tab.id, {
+                    actionType: "IFRAME_TWITTER_SHOW_BUY_NFT",
+                    data: {
+                        nft_project_Id: saleData.value.nftProjectId
+                    }
+                }, (res) => { });
+            })
+        }
+    })
+}
+
+onBeforeMount(() => {
+    let urlParams = new URL(window.location.href);
+    let searchParmas = new URLSearchParams(urlParams.search);
+    let projectId = searchParmas.get('projectId') || '';
+    if (projectId) {
+        isShare.value = true;
+        getSaleData(projectId)
+    } else {
+        getSaleInfo()
+    }
+})
+</script>
+
+<style lang='scss'>
+body {
+    margin: 0;
+    padding: 0;
+}
+
+.nft {
+    width: 100%;
+    height: 290px;
+    user-select:none;
+    border-radius:20px;
+    background:#F7F9F9;
+    &.border {
+        box-sizing: border-box;
+        border: solid 1px #DCDCDC;
+    }
+    .title {
+        height: 46px;
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+
+        .tag {
+            display: flex;
+            align-items: center;
+            padding-left: 15px;
+
+            .logo {
+                overflow: hidden;
+                width: 20px;
+                height: 20px;
+                border-radius: 50%;
+                background-color: #eee;
+            }
+
+            .text {
+                font-size: 18px;
+                font-weight: bold;
+                margin: 0 7px;
+            }
+
+            .tagImg {
+                width: 37px;
+                height: 22px;
+            }
+        }
+
+        .share {
+            cursor: pointer;
+            padding-right: 15px;
+
+            img {
+                width: 19px;
+                height: 18px;
+            }
+        }
+    }
+
+    .content {
+        height: 190px;
+
+        img {
+            width: 100%;
+            height: 100%;
+        }
+    }
+
+    .buy {
+        position: relative;
+        height: 54px;
+        display: flex;
+        justify-content: center;
+        .guide {
+            position: absolute;
+            top: 6px;
+            right: 30%;
+            width: 26px;
+            animation: fade 1s infinite;
+        }
+        button {
+            width: 100%;
+            height: 34px;
+            margin: 0 20px;
+            cursor: pointer;
+            color: #ffffff;
+            font-size: 15px;
+            font-weight: bold;
+            background: #000;
+            border: 0;
+            border-radius: 44px;
+        }
+    }
+}
+
+@keyframes fade {
+    0%, 100% {
+        opacity: .5;
+        transform: scale(1);
+    }
+    50% {
+        opacity: 1;
+        transform: scale(1.4);
+    }
+}
+</style>

+ 30 - 0
src/view/iframe/popup/index.vue

@@ -0,0 +1,30 @@
+<template>
+    <div class="popup_page_main">
+        <popup></popup>
+    </div>
+</template>
+
+
+<script setup>
+import { onMounted, ref } from "vue";
+import popup from '@/view/popup/index.vue'
+
+onMounted(() => {
+});
+
+</script>
+
+<style lang='scss'>
+#app {
+    height: 100%;
+}
+
+.popup_page_main {
+    height: 100%;
+    overflow: hidden;
+}
+
+.popup_content{
+    height: 650px !important;
+}
+</style>

+ 1 - 1
src/view/iframe/publish/components/follow-input.vue

@@ -310,7 +310,7 @@ const onUserMouseLeave = (params, index) => {
                 max-height: 430px;
                 position: absolute;
                 box-shadow: 0px 4px 20px 0px #0000004D;
-                overflow-y: scroll;
+                overflow-y: auto;
                 background-color: #fff; 
                 top: 30px;
                 left: -150px;

+ 117 - 29
src/view/iframe/publish/give-dialog.vue

@@ -388,7 +388,7 @@
                                                 class="refresh"
                                                 :class="{ 'icon-refresh-rotate': refreshRotate }"
                                                 @click="updateCurrencyBanlce"
-                                                :src=" require('@/assets/svg/icon-form-refresh.svg') "
+                                                :src=" require('@/assets/svg/icon-form-refresh-blue.svg') "
                                             />
                                         </div>
                                     </template>
@@ -446,7 +446,7 @@
 <script setup>
 import { ref, watch, reactive, defineProps, defineEmits, onMounted, nextTick, provide } from "vue";
 import { postPublish, verifyPaypalResult, syncChainTokenRechargeRecord, getCurrencyInfoByCode } from "@/http/publishApi";
-import { getInviteGuildInfo, saveInviteGuildInfo } from "@/http/discordApi";
+import { getInviteGuildInfo, getInviteGuildInfoByOpenApi, saveInviteGuildInfo } from "@/http/discordApi";
 import { payCalcFee, getPayConfig } from "@/http/pay";
 import { getFrontConfig } from "@/http/account";
 import {setChromeStorage, getChromeStorage} from "@/uilts/chromeExtension"
@@ -668,7 +668,7 @@ watch(
             // 更新余额
             clearInterval(timer.value);
             timer.value = setInterval(() => {
-                getCurrencyInfo();
+                getCurrencyInfo({loop: true});
             }, 10000)
         } else {
             clearInterval(timer.value);
@@ -744,6 +744,15 @@ const getPayAmount = async (amountValue) => {
 
 const saveDiscordGuildInfo = () => {
     let {guildId, inviteCode, inviteUrl} = discordInviteInfo.value;
+    //保存服务器信息 
+    Report.reportLog({
+        pageSource: Report.pageSource.publisherDialog,
+        businessType: Report.businessType.buttonClick,
+        objectType: Report.objectType.saveDiscordGuildData
+    }, {
+        reportData: discordInviteInfo.value
+    });
+
     if(guildId && inviteCode && inviteUrl) {
         saveInviteGuildInfo({
             params: {
@@ -776,13 +785,14 @@ const confirm = () => {
  * 货币列表-选中货币
  */
 const selectCurrency = (params) => {
-    tempCurrentCurrencyList.value = params;
+    let { currencies } = params;
+    tempCurrentCurrencyList.value = currencies;
     depositGuide.value = false;
-    if (params.length > 1) {
+    if (currencies.length > 1) {
         showCurrencyPop.value = false;
         showCurrencySelect.value = true;
     } else {
-        selectCurrencyAfter(params[0])
+        selectCurrencyAfter(currencies[0])
     }
 };
 
@@ -1402,27 +1412,72 @@ const getDiscordInviteInfo = ({inviteUrl, getDuildId}, cb) => {
     getInviteGuildInfo({
         inviteCode
     }).then(res => {
-        if(!res) {
-            res = {};
+        let resData = inviteGuildResHandler(res, {inviteCode, inviteUrl});
+        if(resData.data.guildId) {
+            cb && cb(resData);
+        } else {
+            //DISCORD 接口未获取到服务器信息 resdata
+            Report.reportLog({
+                pageSource: Report.pageSource.publisherDialog,
+                businessType: Report.businessType.buttonClick,
+                objectType: Report.objectType.getDiscordGuildNoData
+            }, {
+                resData: resData
+            });
+            getGuildInfoByOpenApi({inviteCode}, cb);
         }
-        let {name, icon, id} = res.guild || {};
+    }).catch((err) => {
+        //DISCORD 接口 catch 
+        Report.reportLog({
+            pageSource: Report.pageSource.publisherDialog,
+            businessType: Report.businessType.buttonClick,
+            objectType: Report.objectType.getDiscordGuildCatch
+        }, {
+            err: err
+        });
 
-        icon = icon && id ? `https://cdn.discordapp.com/icons/${id}/${icon}.png` : '';
-        let resData = {
-            inviteCode,
-            data: {
-                code: res.code,
-                guildId: id,
-                inviteUrl,
-                inviteCode,
-                expires: res.expires_at,
-                name,
-                icon,
-            }
+        let errMsg = err;
+        if(typeof errMsg == 'object') {
+            errMsg = JSON.stringify(err);
+        }
+        if(errMsg.indexOf('code 404') > -1) {
+            discordInviteInfo.value = {};
+            iptErrMsgTxt.value = discordIptErrTxt;
+        } else {
+            getGuildInfoByOpenApi({inviteCode}, cb);
+
+        }
+    });
+}
+
+const getGuildInfoByOpenApi = (params, cb) => {
+    let { inviteCode } = params;
+
+    getInviteGuildInfoByOpenApi({
+        inviteCode
+    }).then(res => {
+        let resData = inviteGuildResHandler(res, {inviteCode, inviteUrl});
+        if(resData.data.guildId) {
+            cb && cb(resData);
+        } else {
+            //OPENAPI 接口未获取到服务器信息 resdata
+            Report.reportLog({
+                pageSource: Report.pageSource.publisherDialog,
+                businessType: Report.businessType.buttonClick,
+                objectType: Report.objectType.getDiscordGuildOpenApiNoData
+            }, {
+                resData: resData
+            });
         }
-        discordInviteInfo.value = resData.data;
-        cb && cb(resData);
     }).catch((err) => {
+        // OPENAPI 接口 catch 限频
+        Report.reportLog({
+            pageSource: Report.pageSource.publisherDialog,
+            businessType: Report.businessType.buttonClick,
+            objectType: Report.objectType.getDiscordGuildOpenApiCatch
+        }, {
+            err: err
+        });
         if(iptErrMsgTxt.value && iptErrType == 'discord') {
             iptErrMsgTxt.value = '';
             iptErrType = '';
@@ -1430,6 +1485,35 @@ const getDiscordInviteInfo = ({inviteUrl, getDuildId}, cb) => {
     });
 }
 
+const inviteGuildResHandler = (res, params) => {
+    let {inviteCode, inviteUrl} = params;
+    if(!res) {
+        res = {};
+    }
+    let {name, icon, id} = res.guild || {};
+
+    icon = icon && id ? `https://cdn.discordapp.com/icons/${id}/${icon}.png` : '';
+    let resData = {
+        inviteCode,
+        data: {
+            code: res.code,
+            guildId: id,
+            inviteUrl,
+            inviteCode,
+            expires: res.expires_at,
+            name,
+            icon,
+        }
+    }
+    if(res.code == inviteCode) {
+         discordInviteInfo.value = resData.data;
+    } else {
+        discordInviteInfo.value = {};
+        iptErrMsgTxt.value = discordIptErrTxt;
+    }
+    return resData;
+};
+
 /**
  * 获取支付配置(paypalClientId)
  */
@@ -1471,7 +1555,8 @@ const getLocalCurrencyInfoByCode = () => {
     }
 }
 
-const getCurrencyInfo = async () => {
+const getCurrencyInfo = async (_params) => {
+    let { loop = false} = _params || {};
     let {accessToken = ''} = await getChromeStorage('userInfo') || {};
     if (accessToken) {
         getChromeStorage('selectCurrencyInfo', (res) => {
@@ -1484,7 +1569,9 @@ const getCurrencyInfo = async () => {
                     if(res.code == 0 && res.data) {
                         currentCurrencyInfo.value = res.data;
                         tempCurrentCurrencyInfo.value = res.data;
-                        onIptSetErrorTxt();
+                        if(!loop) {
+                            onIptSetErrorTxt();
+                        }
                     }
                 });
             }
@@ -1658,7 +1745,7 @@ onMounted(() => {
                 box-shadow: 0px 4px 30px rgba(0, 0, 0, 0.3);
                 background-color: #fff;
                 border-radius: 20px;
-                overflow-y: scroll;
+                overflow-y: auto;
             }
             
             .currency-pop-select {
@@ -1712,7 +1799,7 @@ onMounted(() => {
                 .form-wrapper {
                     padding: 0px 18px 18px 18px;
                     height: calc(100% - 80px);
-                    overflow-y: scroll;
+                    overflow-y: auto;
                     overflow-x: hidden;
                     box-sizing: border-box;
 
@@ -2138,6 +2225,7 @@ onMounted(() => {
         overflow: hidden;
         display: flex;
         height: 80px;
+        align-items: center;
         padding: 20px;
         border-radius: 20px;
         border: 1px solid #E6E6E6;
@@ -2160,8 +2248,8 @@ onMounted(() => {
         }
         .refresh {
             cursor: pointer;
-            width: 50px;
-            height: 50px;
+            width: 30px;
+            height: 30px;
             margin-top: -5px;
         }
     }

+ 59 - 5
src/view/iframe/red-packet/red-packet.vue

@@ -395,6 +395,7 @@ let facebookAppConfig = {
 
 let state = reactive({
   status: '',
+  userId: '',
   loading_show: false,
   loading_redbag: true,
   detail: {},
@@ -480,6 +481,10 @@ async function clickLikeBtn() {
     objectType: Report.objectType.like,
     pageSource: Report.pageSource.task_page,
     businessType: Report.businessType.buttonClick
+  }, {
+    postId: state.postId,
+    srcContentId: state.tweetId,
+    senderId: state.userId,
   });
 }
 function clickDone() {
@@ -489,6 +494,10 @@ function clickDone() {
     objectType: Report.objectType.wallet_button,
     pageSource: Report.pageSource.received_success_page,
     businessType: Report.businessType.buttonClick
+  }, {
+    postId: state.postId,
+    srcContentId: state.tweetId,
+    senderId: state.userId,
   });
 }
 function handleScroll(e) {
@@ -586,6 +595,10 @@ async function clickRetweetBtn() {
     objectType: Report.objectType.retweet,
     pageSource: Report.pageSource.task_page,
     businessType: Report.businessType.buttonClick
+  }, {
+    postId: state.postId,
+    srcContentId: state.tweetId,
+    senderId: state.userId,
   });
 }
 
@@ -817,7 +830,11 @@ async function clickFollowAll(item, is_all) {
   if (is_all) {
     _log_obj.objectType = Report.objectType.follow_button
   }
-  Report.reportLog(_log_obj);
+  Report.reportLog(_log_obj, {
+    postId: state.postId,
+    srcContentId: state.tweetId,
+    senderId: state.userId,
+  });
 }
 
 
@@ -853,6 +870,10 @@ const showCloseEndTimePageReport = () => {
   Report.reportLog({
     pageSource: Report.pageSource.expired_page,
     businessType: Report.businessType.pageView,
+  }, {
+    postId: state.postId,
+    srcContentId: state.tweetId,
+    senderId: state.userId,
   });
 }
 
@@ -862,6 +883,10 @@ const showSuccessPage = () => {
   Report.reportLog({
     pageSource: Report.pageSource.received_success_page,
     businessType: Report.businessType.pageView,
+  }, {
+    postId: state.postId,
+    srcContentId: state.tweetId,
+    senderId: state.userId,
   });
 }
 const showNotOpenPage = () => {
@@ -869,6 +894,10 @@ const showNotOpenPage = () => {
   Report.reportLog({
     pageSource: Report.pageSource.pending_page,
     businessType: Report.businessType.pageView
+  }, {
+    postId: state.postId,
+    srcContentId: state.tweetId,
+    senderId: state.userId,
   });
 }
 const showOpenedPage = () => {
@@ -881,6 +910,10 @@ const showOpenedPageReport = () => {
   Report.reportLog({
     pageSource: Report.pageSource.task_page,
     businessType: Report.businessType.pageView,
+  }, {
+    postId: state.postId,
+    srcContentId: state.tweetId,
+    senderId: state.userId,
   });
 }
 
@@ -894,6 +927,10 @@ const showRabbitPageReport = () => {
   Report.reportLog({
     pageSource: Report.pageSource.received_empty_rewards_page,
     businessType: Report.businessType.pageView,
+  }, {
+    postId: state.postId,
+    srcContentId: state.tweetId,
+    senderId: state.userId,
   });
 }
 
@@ -1035,6 +1072,7 @@ function init(initParams) {
       state.detail = JSON.parse(res.data.postBizData)
       state.detail.taskCondition = state.detail.taskCondition || []
       state.tweetId = state.srcContentId;
+      state.userId = res.data.srcUserId;
       state.tweet_author = state.detail.postUserInfo && state.detail.postUserInfo.nickName || '';
       // 不要删除这个console
       console.log('postBizData',state.detail)
@@ -1232,6 +1270,10 @@ function handleRedPacket() {
     pageSource: Report.pageSource.pending_page,
     businessType: Report.businessType.buttonClick,
     objectType: Report.objectType.open_button
+  }, {
+    postId: state.postId,
+    srcContentId: state.tweetId,
+    senderId: state.userId,
   });
 }
 
@@ -1297,7 +1339,10 @@ function handleFinishRedPacket() {
           businessType: Report.businessType.buttonClick,
           objectType: Report.objectType.get_giveaway
         }, {
-          get_giveaway_result: Report.extParams.success
+          get_giveaway_result: Report.extParams.success,
+          postId: state.postId,
+          srcContentId: state.tweetId,
+          senderId: state.userId,
         });
       } else {
         let _data = res.data.conditionResult
@@ -1373,7 +1418,10 @@ function handleFinishRedPacket() {
           businessType: Report.businessType.buttonClick,
           objectType: Report.objectType.get_giveaway
         }, {
-          get_giveaway_result: Report.extParams.failure
+          get_giveaway_result: Report.extParams.failure,
+          postId: state.postId,
+          srcContentId: state.tweetId,
+          senderId: state.userId,
         });
         if (discordAuthorizeRequired) {
           discordAuth('reAuth');
@@ -1386,7 +1434,10 @@ function handleFinishRedPacket() {
         businessType: Report.businessType.buttonClick,
         objectType: Report.objectType.get_giveaway
       }, {
-        get_giveaway_result: Report.extParams.failure
+        get_giveaway_result: Report.extParams.failure,
+        postId: state.postId,
+        srcContentId: state.tweetId,
+        senderId: state.userId,
       });
       handleErrorCode(res)
     }
@@ -1465,6 +1516,10 @@ function handleErrorCode(res) {
       Report.reportLog({
         pageSource: Report.pageSource.robot_detection_failed_page,
         businessType: Report.businessType.pageView,
+      }, {
+        postId: state.postId,
+        srcContentId: state.tweetId,
+        senderId: state.userId,
       });
       break
     // 无法校验用户Twitter信息
@@ -1565,7 +1620,6 @@ function onWindowMessage() {
 function onPageVisbile() {
   document.addEventListener('visibilitychange', function () {
     let isHidden = document.hidden;
-    console.log('joinDiscordActionState', joinDiscordActionState);
     if (!isHidden) {
       checkJoinDiscord();
     }

+ 34 - 4
src/view/popup/components/head.vue

@@ -12,9 +12,13 @@
         <template v-else>
             <img :src="require('@/assets/svg/icon-back.svg')" alt="" class="back" @click="clickBack">
             <div class="title">{{ props.title }}</div>
+            <img :src="require('@/assets/svg/icon-back-head-list.svg')"
+                v-if="show_list" 
+                class="list" 
+                @click="clickList" />
             <img :src="require('@/assets/svg/icon-refresh.svg')" alt="" class="refresh" v-if="show_refresh"
                 @click="clickRefresh" :class="{ transform_rotate: state.rotate }">
-            <img :src="require('@/assets/svg/icon-withdraw-help.svg')" alt="" class="help" v-if="props.show_help"
+            <img :src="require('@/assets/svg/icon-head-help.svg')" alt="" class="help" v-if="props.show_help"
                 @click="clickHelp">
             <img :src="require('@/assets/svg/icon-more-l.svg')" alt="" class="more" v-if="props.show_more"
                 @click="state.show_option = true">
@@ -43,7 +47,9 @@ let props = defineProps({
     show_more: Boolean,
     show_help: Boolean,
     back_url: String,
-    user_info: Object
+    user_info: Object,
+    show_list: Boolean,
+    transactionsRouterParams: Object,
 })
 
 let state = reactive({
@@ -74,13 +80,30 @@ function clickRefresh() {
 }
 
 function clickItem(path) {
-    router.push(path)
+    let params = props.transactionsRouterParams || {};
+    router.push({
+        path: path,
+        query: {
+            params: JSON.stringify(params)
+        }
+    })
 }
 
 function clickHelp() {
     window.open(`https://aboard-cattle-610.notion.site/How-to-withdraw-assets-from-DeNet-to-MetaMask-01c679bb9ff441429e31e8f7c1f67411`)
 }
 
+function clickList() {
+    let params = props.transactionsRouterParams || {};
+    console.log('transactionsRouterParams',params);
+    router.push({
+        path: '/transactions',
+        query: {
+            params: JSON.stringify(params)
+        }
+    })
+}
+
 </script>
 <style lang="scss" scoped>
 .border {
@@ -94,6 +117,7 @@ function clickHelp() {
     justify-content: space-between;
     align-items: center;
     padding: 0 12px;
+    overflow: hidden;
 
     &.home {
         height: 64px;
@@ -185,11 +209,16 @@ function clickHelp() {
         height: 24px;
     }
 
+    .list {
+        margin-right: 12px;
+    }
+
     .refresh {
-        margin-right: 20px;
+        
     }
 
     .help {
+        margin-left: 20px;
         margin-right: 12px;
     }
 
@@ -199,6 +228,7 @@ function clickHelp() {
         color: #000000;
         font-size: 16px;
         font-weight: 500;
+        word-break: break-all;
     }
 }
 </style>

+ 231 - 0
src/view/popup/components/tabbar.vue

@@ -0,0 +1,231 @@
+<template>
+    <div class="tab-bar-wrappeer">
+        <template
+            v-for="(item, index) in tabbarData"
+            :key="index">
+            <div class="tab-item" 
+                 v-if="item.path != '/NFT' || item.path == '/NFT' && showNFTTab"
+                 @click="tabbarHandler(item, index)">
+                    <red-dot class="red-dots"
+                        v-if="unReadCountTask > 0 && item.path == '/message' && currentTab.path != '/message'"
+                        ></red-dot>
+                    <img
+                        :src="
+                            index == currentTab.index
+                                ? item.iconActive
+                                : item.iconInActive
+                        "
+                    />
+                    <div
+                        class="text"
+                        :class="{ 'active-tab': index == currentTab.index }"
+                    >
+                        {{ item.name }}
+                    </div>
+            </div>
+        </template>
+    </div>
+</template>
+
+<script setup>
+import { ref, onMounted, defineProps, defineEmits, nextTick, watch, onBeforeUnmount } from "vue";
+
+import redDot from "@/view/components/red-dot.vue";
+import router from "@/router/popup.js";
+import { setBadgeInfo, hideBadge } from "@/logic/background/twitter";
+
+
+import { nftListMine } from "@/http/nft.js";
+import { getAllMessageInfo } from "@/http/messageApi"
+
+
+const props = defineProps({
+    userInfo: {
+        type: Object,
+        default: () => {
+            return {
+                accessToken: undefined,
+            };
+        }
+    },
+});
+
+watch(
+    () => props.userInfo,
+    (newVal) => {
+        getNFTListMine();
+        setMessageCount();
+    },
+    {
+        deep: true
+    }
+);
+
+
+let currentTab = ref({
+    index: 0,
+    path: '/'
+});
+
+let unReadCountTask = ref(0);
+let showNFTTab = ref(true);
+
+let tabbarData = ref([
+    {
+        name: "Wallet",
+        path: "/",
+        iconActive: require("@/assets/svg/icon-tab-wallet-active.svg"),
+        iconInActive: require("@/assets/svg/icon-tab-wallet.svg"),
+    },
+    {
+        name: "NFTs",
+        path: "/NFT",
+        iconActive: require("@/assets/svg/icon-tab-NFT-active.svg"),
+        iconInActive: require("@/assets/svg/icon-tab-NFT.svg"),
+    },
+    {
+        name: "Message",
+        path: "/message",
+        iconActive: require("@/assets/svg/icon-tab-message-active.svg"),
+        iconInActive: require("@/assets/svg/icon-tab-message.svg"),
+    },
+    {
+        name: "More",
+        path: "/more",
+        iconActive: require("@/assets/svg/icon-tab-more-active.svg"),
+        iconInActive: require("@/assets/svg/icon-tab-more.svg"),
+    },
+]);
+
+let NFTReqParams = {
+    params: {
+        pageNum: 1,
+        pageSize: 20,
+    },
+};
+
+const emits = defineEmits(["tabbarClick"]);
+
+const tabbarHandler = (params, index) => {
+    unReadCountTask.value = 0;
+    setMessageCount();
+    currentTab.value.index = index;
+    currentTab.value.path = params.path;
+    router.push(params.path);
+    emits("tabbarClick", params);
+};
+
+const setActiveTab = () => {
+    nextTick(() => {
+        let path = router.currentRoute.value.path;
+        let list = tabbarData.value;
+        for (let i = 0; i < list.length; i++) {
+            if (path == list[i].path) {
+                currentTab.value.index = i;
+                currentTab.value.path = path;
+                break;
+            }
+        }
+    })
+};
+
+const getNFTListMine = () => {
+    if(!props.userInfo.accessToken) return;
+    nftListMine({
+        params: NFTReqParams.params,
+    }).then((res) => {
+        if (res.data && res.data.length) {
+            showNFTTab.value = true;
+        } else {
+            showNFTTab.value = false;
+        }
+    });
+};
+
+
+const setMessageCount = () => {
+    if(!props.userInfo.accessToken) return;
+    getAllMessageInfo({params: {
+    }}).then(res => {
+        if(res.code == 0) {
+            let {unReadCountTotal = 0, unReadCountWalletDetail = 0, unReadCountTaskLuckdrop = 0} = res.data;
+            unReadCountTask.value = unReadCountTaskLuckdrop;
+            if(unReadCountTotal > 0) {
+                let text = unReadCountTotal > 99 ? '99+' : unReadCountTotal+'';
+                setBadgeInfo({data: {text}});
+            } else {
+                hideBadge();
+            }
+        }
+    });
+}
+
+
+const onMessage = () => {
+    chrome.runtime.onMessage.addListener(msgListener)
+}
+
+const msgListener = (req, sender, sendResponse) => {
+    sendResponse('');
+    switch (req.actionType) {
+        case 'CONTENT_POPUP_PAGE_SHOW':
+            init();
+            break;
+    }
+}
+
+const init = () => {
+    setActiveTab();
+    setMessageCount();
+}
+
+onMounted(() => {
+    onMessage();
+    init();
+});
+
+onBeforeUnmount(() => {
+    chrome.runtime.onMessage.removeListener(msgListener);
+})
+</script>
+
+<style scoped lang="scss">
+.tab-bar-wrappeer {
+    background: #ffffff;
+    box-shadow: inset 0px 1px 0px #ececec;
+    width: 100%;
+    height: 70px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+
+    position: absolute;
+    z-index: 1000;
+    bottom: 0px;
+
+    cursor: pointer;
+
+        .tab-item {
+            flex: 1;
+            text-align: center;
+            position: relative;
+
+            .text {
+                font-size: 12px;
+                color: #c0c0c0;
+            }
+
+            .active-tab {
+                color: #1d9bf0 !important;
+                font-weight: 500;
+            }
+
+            .red-dots {
+                position: absolute;
+                right: 32%;
+                top: 0px;
+            }
+        }
+    
+}
+</style>

+ 68 - 0
src/view/popup/components/top-bar.vue

@@ -0,0 +1,68 @@
+<template>
+    <div class="top-bar-wrapper" :style="{background: bgColor, boxShadow: boxShadow}">
+        <div class="left" @click="clickUserInfo">
+            <img :src="userInfo.avatarUrl" class="icon-avatar">
+            <span class="nick-name" :style="{color: color}">{{userInfo.nickName}}</span>
+        </div>
+        <!-- <div>
+            <img :src="require('@/assets/svg/icon-denet-logo.svg')" />
+        </div> -->
+    </div>
+</template>
+
+<script setup>
+import {defineProps} from 'vue';
+
+const props = defineProps({
+    userInfo: {
+        type: Object,
+        default: () => {
+            return {};
+        }
+    },
+    bgColor: {
+        type: String,
+        default: '#fff'
+    },
+    boxShadow: {
+        type: String,
+        default: 'none'
+    },
+    color: {
+        type: String,
+        default: '#fff'
+    }
+})
+
+function clickUserInfo() {
+    window.open(`https://twitter.com/${props.userInfo.nickName}`);
+}
+</script>
+
+<style scoped lang='scss'>
+.top-bar-wrapper {
+    width: 100%;
+    height: 48px;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    padding: 12px 16px;
+    box-sizing: border-box;
+
+    .left {
+        display: flex;
+        align-items: center;
+        cursor: pointer;
+        .icon-avatar {
+            width: 24px;
+            height: 24px;
+            margin-right: 8px;
+            border-radius: 50%;
+        }
+        .nick-name {
+            font-weight: 500;
+            font-size: 14px;
+        }
+    }
+}
+</style>

+ 302 - 0
src/view/popup/currency-detail.vue

@@ -0,0 +1,302 @@
+<template>
+  <div class="currency-detail-page">
+    <v-head :title="currencyInfo.tokenSymbol" 
+            :show_more="false"
+            :show_refresh="true"
+            :show_list="true"
+            :transactionsRouterParams="{
+              backUrl: 'back'
+            }"
+            @on-refresh="onRefresh" />
+    <div class="top">
+      <img
+        class="icon-currency"
+        :src="currencyInfo.iconPath"/>
+      <div class="amount">
+        <div class="balance"
+             :class="{'direction-column': (currencyInfo.totalBalance.length + currencyInfo.tokenSymbol.length) > 15}">
+          <a-tooltip :title="currencyInfo.totalBalance">
+              {{ getBit(currencyInfo.totalBalance) }}
+          </a-tooltip> 
+          <template v-if="currencyInfo.totalBalance.length + currencyInfo.tokenSymbol.length < 16">
+            &nbsp;&nbsp;
+          </template>
+          <span class="symbol">
+             {{currencyInfo.tokenSymbol}}
+          </span>
+        </div>
+        <div class="final">
+          <a-tooltip :title="'$'+currencyInfo.totalUsdEstimateBalance">
+              ${{ getBit(currencyInfo.totalUsdEstimateBalance) }}
+          </a-tooltip>
+        </div>
+      </div>
+    </div>
+    <div class="bottom">
+      <div class="btn deposit-btn"
+          v-if="currencyInfo.currencyCode != 'USD'"
+          @click="clickDeposit">Deposit</div>
+      <div class="btn withdrawal-btn" @click="clickWithdraw">Withdrawal</div>
+    </div>
+
+    <template v-if="showCurrencySelect">
+        <div class="selectDiv">
+            <currency-select 
+                ref="currencySelectDom"
+                :list="currenciesData"
+                @selectCurrency="selectCurrency">
+            </currency-select>
+        </div>
+        <div class="selectBg" @click="showCurrencySelect = false"></div>
+    </template>
+  </div>
+</template>
+
+<script setup>
+import { ref, onMounted, inject, reactive } from "vue";
+import router from "@/router/popup.js";
+import Report from "@/log-center/log";
+import { getStorage } from "@/uilts/help";
+
+import { getCurrencyInfoBySymbol } from "@/http/publishApi";
+
+import VHead from '@/view/popup/components/head.vue'
+import currencySelect from "@/view/components/currency-select.vue";
+import { getBit } from "@/uilts/help";
+
+let currenciesData = ref([]);
+let currencyInfo = ref({
+  totalBalance: '',
+  tokenSymbol: ''
+});
+let showCurrencySelect = ref(false);
+
+let currencyOpertionType = '';
+
+
+
+const selectCurrency = (params) => {
+    showCurrencySelect.value = false;
+    if(currencyOpertionType == 'WITHDRAW') {
+      withdrawHandle(params);
+    } else if(currencyOpertionType == 'DEPOSIT') {
+      depositHandle(params);
+    }
+}
+
+let withdraw_info = inject('withdraw_info')
+// 点击提现
+const clickWithdraw = () => {
+    Report.reportLog({
+        pageSource: Report.pageSource.denetHomePage,
+        businessType: Report.businessType.buttonClick,
+        objectType: Report.objectType.withdrawButton
+    });
+
+    if(currenciesData.value.length > 1) {
+      showCurrencySelect.value = true;
+      currencyOpertionType = "WITHDRAW";
+    } else if(currenciesData.value.length == 1){
+      withdrawHandle(currenciesData.value[0]);
+    }
+}
+
+const withdrawHandle = (_params) => {
+  withdraw_info.chainInfo = _params.chainInfo;
+  if (_params.currencyCode == 'USD') {
+      withdraw_info.currency_code = _params.currencyCode
+      router.push('/withdraw/paypal')
+  } else {
+      withdraw_info.source = 'home'
+      withdraw_info.balance = _params.balance
+      withdraw_info.token_symbol = _params.tokenSymbol || ''
+      withdraw_info.currency_name = _params.currencyName || ''
+      withdraw_info.token_chain = _params.tokenChain || 'BNB Chain'
+      withdraw_info.currency_code = _params.currencyCode
+      withdraw_info.icon_token = _params.iconPath || ''
+      withdraw_info.icon_net = require('@/assets/svg/icon-BNB.svg')
+      console.log(withdraw_info.chainInfo.iconPath)
+      router.push('/withdraw/info')
+  }
+}
+
+
+
+let top_up_info = inject('top_up_info');
+
+const clickDeposit = () => {
+    Report.reportLog({
+        pageSource: Report.pageSource.denetHomePage,
+        businessType: Report.businessType.buttonClick,
+        objectType: Report.objectType.topupButton
+    });
+
+    if(currenciesData.value.length > 1) {
+      showCurrencySelect.value = true;
+      currencyOpertionType = "DEPOSIT";
+    } else if(currenciesData.value.length == 1){
+      depositHandle(currenciesData.value[0]);
+    }
+}
+
+const depositHandle = (_params) => {
+  top_up_info.token = _params.currencyName || ''
+  top_up_info.token_chain = _params.tokenChain 
+  top_up_info.token_symbol = _params.tokenSymbol || ''
+  top_up_info.currency_code = _params.currencyCode
+  top_up_info.icon_token = _params.iconPath || ''
+  top_up_info.icon_net = require('@/assets/svg/icon-BNB.svg')
+  top_up_info.chainInfo = {
+    ..._params.chainInfo
+  };
+  
+  router.push('/top-up/info');
+};
+
+const onRefresh = () => {
+  getCurrencyInfoBySymbol({
+    params: {
+      symbol: currencyInfo.value.tokenSymbol
+    }
+  }).then(res => {
+    if(res.code == 0) {
+      if(res.data && res.data.currencyCategories && res.data.currencyCategories.length) {
+        let data = res.data.currencyCategories[0].data;
+        if(data.length) {
+          let {totalBalance = '', totalUsdEstimateBalance = ''} = data[0] || {};
+          currencyInfo.value.totalBalance = totalBalance;
+          currencyInfo.value.totalUsdEstimateBalance = totalUsdEstimateBalance;
+        }
+      }
+    }
+  })
+};
+
+onMounted(() => {
+    let {params = '{}'} = router.currentRoute.value.query;
+
+    let {currencies = [], totalBalance = 0, totalUsdEstimateBalance = 0} =  JSON.parse(params);
+
+    currenciesData.value = currencies;
+
+    if(currencies.length) {
+      currencyInfo.value = {
+        ...currencies[0],
+        totalBalance,
+        totalUsdEstimateBalance
+      };
+      console.log(currencyInfo.value )
+    }
+})
+</script>
+
+
+<style lang='scss' scoped>
+.currency-detail-page {
+  width: 100%;
+  height: 100%;
+  position: relative;
+
+  .top {
+    height: calc(100% - 212px);
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+
+    .icon-currency {
+      width: 100px;
+      margin-bottom: 30px;
+    }
+
+    .amount {
+      font-weight: 700;
+      font-size: 28px;
+      text-align: center;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      flex-direction: column;
+      width: 100%;
+      .balance {
+        padding: 0 18px;
+        box-sizing: border-box;
+        width: 100%;
+        word-break: break-word;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+
+        .symbol{
+          word-break: break-all;
+        }
+      }
+
+      .direction-column {
+        flex-direction: column;
+      }
+
+      .final {
+        margin-top: 9px;
+        font-weight: 500;
+        font-size: 22px;
+        color: #a2a2a2;
+        text-align: center;
+      }
+    }
+  }
+  .bottom {
+    height: 162px;
+    padding: 0 20px;
+    box-sizing: border-box;
+
+    .btn {
+      width: 100%;
+      height: 57px;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      font-weight: 500;
+      font-size: 17px;
+      border-radius: 100px;
+      cursor: pointer;
+    }
+
+    .deposit-btn {
+      margin-bottom: 18px;
+      background: #1d9bf0;
+      color: #fff;
+    }
+
+    .withdrawal-btn {
+      background: rgba(244, 244, 244, 0.01);
+      border: 1px solid #d7e8f4;
+      box-sizing: border-box;
+      color: #1d9bf0;
+    }
+  }
+
+
+  .selectDiv {
+      position: absolute;
+      z-index: 1000;
+      width: 100%;
+      max-height: 480px;
+      padding-bottom: 30px;
+      left: 0;
+      bottom: 0;
+      background-color: #fff;
+      border-radius: 20px 20px 0 0;
+      overflow-y: auto;
+  }
+  .selectBg {
+      position: absolute;
+      z-index: 999;
+      top: 0;
+      left: 0;
+      width: 100%;
+      height: 100%;
+      background: rgba($color: #000000, $alpha: 0.6);
+  }
+}
+</style>

+ 8 - 0
src/view/popup/index.vue

@@ -15,6 +15,14 @@ watch(withdraw_info, (newVal) => {
 
 provide('withdraw_info', withdraw_info)
 
+let top_up_info = reactive(getStorage("top_up_info") || {});
+
+watch(top_up_info, (newVal) => {
+  setStorage("top_up_info", newVal);
+});
+
+provide("top_up_info", top_up_info);
+
 let state = reactive({
   popup: true
 })

+ 0 - 1028
src/view/popup/popup.vue

@@ -1,1028 +0,0 @@
-<template>
-    <global-tip :type="'3'"></global-tip>
-    <div class="page-wrapper" ref="pageWrapperDom" @scroll="pageScroll">
-        <template v-if="isLogin && homeVisibility">
-            <v-head :show_more="true" :show_state="'home'" :user_info="userInfo"></v-head>
-            <div class="content">
-                <div class="balance">
-                    <div class="wallet">
-                        <img :src="require('@/assets/svg/icon-home-wallet.svg')" />
-                        <font>Balance Valuation</font>
-                    </div>
-                    <div class="bill" @click="showTransactions">
-                        <red-dot class="red-dot" v-if="unReadCountWallet > 0"></red-dot>
-                        <img :src="require('@/assets/svg/icon-home-bill.svg')" />
-                    </div>
-                </div>
-                <div class="amount">
-                    <a-tooltip :title="'$'+canWithdrawBalance">
-                        ${{ getBit(canWithdrawBalance) }}
-                    </a-tooltip>
-                </div>
-                <div class="area-btn">
-                    <div class="withdraw-btn" @click="clickWithdraw">Withdraw</div>
-                    <div class="top-up-btn" @click="clickTopUp">Deposit</div>
-                </div>
-            </div>
-
-            <div class="tab-bar">
-                <div class="tab-item" 
-                    :class="{ active: currentTabIndex == index }" 
-                    v-for="(item, index) in tabList"
-                    :key="index" 
-                    @click="clickTab(item, index)">
-                    <img :src="item.icon" class="icon" />
-                    {{ item.label }}
-                </div>
-            </div>
-            <div class="list-wrapper" ref="pageGiveListDom">
-                <div class="give-list" v-if="currentTabIndex == 0">
-                    <template v-if="giveList.length">
-                        <div class="cell" 
-                            :class="{'cell-center': item.type == 1}"
-                            v-for="(item, index) in giveList" 
-                            :key="index"
-                            @click="clickListItem(item, index)">
-
-                            <red-dot class="red-dots"
-                                v-if="item.unReadMsgCount > 0 && isReadMsg"></red-dot>
-
-                            <div class="img-wrapper">
-                                <!-- 收到红包 -->
-                                <template v-if="item.type == 1">
-                                    <img class="icon-avatar" :src="item.userInfo.avatarUrl" />
-                                    <img class="icon-give" :src="
-                                        require('@/assets/svg/icon-giveaways.svg')
-                                    " />
-                                </template>
-                                <!-- 发出去红包 -->
-                                <template v-else-if="2">
-                                    <img 
-                                        class="icon-big-give"
-                                        :src="
-                                        require('@/assets/svg/icon-list-big-give.svg')
-                                    " />
-                                </template>
-                            </div>
-                            <div class="info-wrapper"
-                                :class="{'info-center': item.type == 1}">
-                                <div class="left">
-                                    <div class="nickname">
-                                        {{
-                                                item.type == 1
-                                                    ? item.userInfo.nickName
-                                                    : "Giveaways"
-                                        }}
-                                    </div>
-                                    <div class="time">
-                                        {{
-                                                moment(item.timestamp).format(
-                                                    "MM-DD HH:mm:ss"
-                                                )
-                                        }}
-                                    </div>
-                                </div>
-                                <div class="right">
-                                    <div class="msg">
-                                        <div class="bold" 
-                                            :class="{'align-content': (item.type == 2 || (item.type == 1 && item.status == 1)) && 
-                                                                        item.amount.length + item.currencySymbol.length > 12 }">
-                                            <!-- 收到的 -->
-                                            <template v-if="item.type == 1">
-                                                <!-- 进行中-->
-                                                <template v-if="item.status == 0">
-                                                    in progress
-                                                </template>
-                                                <!-- 已完成 -->
-                                                <template v-else-if="item.status == 1">
-                                                    <span class="blance">
-                                                        <a-tooltip :title="item.amount">
-                                                            {{ getBit(item.amount) }}</a-tooltip>
-                                                    </span>
-                                                    <div class="coin-type-wrapper">
-                                                        <span class="coin-type">{{ item.currencySymbol || '' }}</span>
-                                                        <img :src="item.currencyIconPath" alt="">
-                                                    </div>
-                                                </template>
-                                                <!-- 已过期 -->
-                                                <template v-else-if="item.status == 2">
-                                                    Timeout
-                                                </template>
-                                            </template>
-                                            <!-- 发出去的 -->
-                                            <template v-else-if="item.type == 2">
-                                                <span class="blance">
-                                                    <a-tooltip :title="'-' + item.amount">
-                                                        -{{ getBit(item.amount) }}
-                                                    </a-tooltip>
-                                                </span>
-                                                <div class="coin-type-wrapper">
-                                                    <span class="coin-type">{{ item.currencySymbol || '' }}</span>
-                                                    <img :src="item.currencyIconPath" alt="">   
-                                                </div>
-                                            </template>
-                                        </div>
-                                        <!-- 发出的红包显示 -->
-                                        <div class="desc" v-if="item.type == 2">
-                                            <!-- 未发送-->
-                                            <template v-if="item.postTaskLuckdrop.reSendAvailable">
-                                                Unpublished
-                                            </template>
-                                            <!-- 进行中 -->
-                                            <template v-else-if="item.status == 1">
-                                                {{item.postTaskLuckdrop.receivedCount}}/{{item.postTaskLuckdrop.totalCount}}
-                                            </template>
-                                            <!-- 2:已结束; 3:提前终止-->
-                                            <template v-else-if="item.status == 2 || item.status == 3">
-                                                ({{item.status == 2 ? 'Time expired' : 'Termination'}})
-                                                {{
-                                                        item.postTaskLuckdrop
-                                                            .receivedCount
-                                                }}/{{
-                                                        item.postTaskLuckdrop
-                                                            .totalCount
-                                                }}
-                                            </template>
-                                            <!-- 红包提前终止/退款(进行中)显示-->
-                                            <template v-if="item.status == 4">
-                                                Terminating
-                                            </template>
-
-                                            <!-- 进行中或者未发送成功时显示 
-                                                v-if="item.status == 1 || item.postTaskLuckdrop.reSendAvailable"-->
-                                            <div  class="desc-bottom-bar">
-                                                <!-- 没有终止红包时显示 -->
-                                                <div v-if="item.postTaskLuckdrop.terminatedAvailable"
-                                                    class="btn"
-                                                    @click.stop="terminaHandler(item, index)">
-                                                    Termination
-                                                </div>
-                                                
-                                                <!-- 红包未发出显示 -->
-                                                <div class="btn send-btn"
-                                                    v-if="item.postTaskLuckdrop.reSendAvailable"       
-                                                    @click.stop="sendTwitter(item)">
-                                                    Send
-                                                </div>
-                                                <div v-else-if="item.srcContentId"
-                                                    class="btn detail-btn"
-                                                    @click.stop="clickListItem(item, index)">details</div>
-                                            </div>
-                                        </div>
-                                    </div>
-                                    <!-- 发红包—— 未发出、进行中 隐藏 -->
-                                    <img v-if="item.type != 2" 
-                                        class="icon" 
-                                        :src="require('@/assets/svg/icon-cell-arrow-right.svg')" />
-                                </div>
-                            </div>
-                        </div>
-                    </template>
-                    <template v-else>
-                        <img class="icon-empty" :src="require('@/assets/svg/icon-empty-list.svg')" />
-                    </template>
-                </div>
-                <div class="more-list" v-else>
-                    <div class="cell" 
-                    v-for="(item, index) in moreTabList" 
-                    :key="index"
-                    @click="moreItemHandle(item)">
-                        <img class="icon" :src="item.icon" />
-                        <div class="info-wrapper">
-                            <div class="left">
-                                {{ item.label }}
-                            </div>
-                            <div class="right">
-                                <img class="icon" :src="
-                                    require('@/assets/svg/icon-cell-arrow-right.svg')
-                                " />
-                            </div>
-                        </div>
-                    </div>
-                </div>
-            </div>
-        </template>
-        <!-- login -->
-        <popup-login v-if="!isLogin" @loginAction="loginAction" />
-        <template v-if="isLogin && !homeVisibility">
-            <!-- 交易列表 -->
-            <popup-transactions v-if="transactionsVisibility" @back="transactionsBack" />
-            <!-- 提现页 -->
-            <popup-withdraw :amountValue="canWithdrawBalance" :walletWithdrawConfig="walletWithdrawConfig"
-                v-if="withdrawVisibility" @back="withdrawBack" />
-        </template>
-        <modal :visible="modalVisible"   
-            title="Early termination of Giveaway?"
-            content="The remaining amount will be returned to your wallet within 1 day."
-            cancelText="Termination"
-            confirmText="Cancel"
-            @cancel="modalCancel"
-            @confirm="modalConfirm" />
-    </div>
-</template>
-
-<script setup>
-import { ref, onMounted, inject } from "vue";
-
-import popupLogin from "@/view/popup/components/login.vue";
-import popupTransactions from "@/view/components/popup-transactions";
-import popupWithdraw from "@/view/components/popup-withdraw.vue";
-import redDot from "@/view/components/red-dot.vue";
-import modal from "@/view/popup/components/modal.vue";
-
-import {
-    getChromeStorage,
-} from "@/uilts/chromeExtension";
-import { getBalance, getMineLuckdropRecords } from "@/http/account";
-import { readAllMsgByType, getAllMessageInfo } from "@/http/messageApi"
-import { terminatedLuckdrop } from "@/http/redPacket";
-import { setBadgeInfo, hideBadge } from "@/logic/background/twitter";
-import Report from "@/log-center/log";
-import router from "@/router/popup.js";
-import { getBit } from "@/uilts/help";
-import  GlobalTip  from '@/view/components/global-tip.vue'
-
-import VHead from '@/view/popup/components/head.vue';
-
-
-let withdraw_info = inject('withdraw_info')
-withdraw_info.paypal = {}
-
-var moment = require("moment");
-
-let pageWrapperDom = ref(null);
-let pageGiveListDom = ref(null);
-
-let isLogin = ref(false);
-let homeVisibility = ref(false);
-let transactionsVisibility = ref(false);
-let withdrawVisibility = ref(false);
-let modalVisible = ref(false);
-
-let terminaTask = {};
-
-let userInfo = ref({});
-let canWithdrawBalance = ref(0);
-withdraw_info.paypal.amount_value = canWithdrawBalance
-withdraw_info.balance = 0
-
-let isRequestWithdrawBalance = ref(false);
-
-let currentTabIndex = ref(0);
-let giveList = ref([]);
-
-// 钱包未读数
-let unReadCountWallet = ref(0);
-let isReadMsg = ref(true);
-
-let giveReqParams = {
-    params: {
-        pageNum: 1,
-        pageSize: 10,
-    },
-    loadMore: false,
-};
-
-
-let walletWithdrawConfig = ref({
-    withdrawUSDPaypalFee: 0,
-    withdrawUSDPreMinAmount: 100,
-    withdrawUSDSwitch: "",
-    withdrawUSDPaypalFeeDesc: ''
-});
-withdraw_info.paypal.wallet_withdraw_config = walletWithdrawConfig
-
-
-let moreTabList = ref([
-    {
-        icon: require("@/assets/svg/icon-website.svg"),
-        label: "Website",
-        href: 'https://denet.me'
-    },
-    {
-        icon: require("@/assets/svg/icon-twitter.svg"),
-        label: "Twitter",
-        href: 'https://twitter.com/denet2022'
-    },
-    {
-        icon: require("@/assets/svg/icon-discord.svg"),
-        label: "Discord",
-        href: 'https://discord.gg/wZSz9p8ddG'
-    }
-    // , {
-    //     icon: require("@/assets/svg/icon-telegram.svg"),
-    //     label: "Telegram",
-    //     href: 'https://t.me/denetpro'
-    // }
-]);
-
-let tabList = ref([
-    {
-        icon: require("@/assets/svg/icon-giveaways.svg"),
-        label: "Giveaways",
-    },
-    {
-        icon: require("@/assets/svg/icon-more.svg"),
-        label: "More",
-    },
-]);
-
-onMounted(() => {
-    checkLoginState(() => {
-        if (isLogin.value) {
-            getAccountBalance();
-            getLuckdropRecordsList();
-            chrome.runtime.connect({ name: "popup" });
-            Report.reportLog({
-                pageSource: Report.pageSource.denetHomePage,
-                businessType: Report.businessType.pageView,
-            },{
-                type: window.location.href.indexOf('home.html') > -1 ? 'web' : 'extensions'
-            });
-            setMessageCount();
-            setTimeout(() => {
-                isReadMsg.value = false;
-                readAllMsg({msgType: 1}, () => {
-                    setMessageCount();
-                });
-            }, 2000);
-        } else {
-            Report.reportLog({
-                pageSource: Report.pageSource.denetLogin,
-                businessType: Report.businessType.pageView,
-            });
-        }
-    });
-});
-
-const readAllMsg = ({msgType}, cb) => {
-    readAllMsgByType({
-        params: {
-            msgType
-        }
-    }).then(res => {
-        cb && cb();
-    })
-};
-
-const setMessageCount = () => {
-    getAllMessageInfo({params: {
-    }}).then(res => {
-        if(res.code == 0) {
-            let {unReadCountTotal = 0, unReadCountWalletDetail = 0, unReadCountTaskLuckdrop = 0} = res.data;
-            unReadCountWallet.value = unReadCountWalletDetail;
-            if(unReadCountTotal > 0) {
-                let text = unReadCountTotal > 99 ? '99+' : unReadCountTotal+'';
-                setBadgeInfo({data: {text}});
-            } else {
-                hideBadge();
-            }
-        }
-    });
-}
-
-const moreItemHandle = (params) => {
-    window.open(params.href);
-}
-
-
-/**
- * 获取账户余额
- */
-const getAccountBalance = () => {
-    isRequestWithdrawBalance.value = false;
-    getBalance({}).then((res) => {
-        isRequestWithdrawBalance.value = true;
-        if (res.code == 0) {
-            if (res.data) {
-                canWithdrawBalance.value = res.data.allAssetValuationUSD;
-                withdraw_info.balance = res.data.allAssetValuationUSD || 0
-            }
-        }
-    });
-};
-
-const getUserInfo = (cb) => {
-    getChromeStorage("userInfo", (res) => {
-        cb && cb(res);
-    });
-};
-
-/**
- * 检查登录状态
- */
-const checkLoginState = (cb) => {
-    getUserInfo((res) => {
-        if (res && res.accessToken) {
-            userInfo.value = res;
-            isLogin.value = true;
-            homeVisibility.value = true;
-        } else {
-            userInfo.value = {};
-            isLogin.value = false;
-        }
-        cb && cb();
-    });
-};
-
-const pageScroll = (e) => {
-    let wrapperHeight = pageWrapperDom.value.offsetHeight;
-    let pageGiveListHeight = pageGiveListDom.value.offsetHeight;
-    let scrollTop = e.target.scrollTop || 0;
-    if (currentTabIndex.value != 0) {
-        return;
-    }
-    if (
-        giveReqParams.loadMore === false &&
-        wrapperHeight + scrollTop >= pageGiveListHeight
-    ) {
-        giveReqParams.loadMore = true;
-        giveReqParams.params.pageNum++;
-        getLuckdropRecordsList();
-    }
-};
-
-/**
- * 获取红包列表
- */
-const getLuckdropRecordsList = () => {
-    getMineLuckdropRecords({
-        params: giveReqParams.params,
-    }).then((res) => {
-        if (res.data && res.data.length) {
-            if (giveReqParams.params.pageNum < 2) {
-                giveList.value = res.data;
-            } else {
-                let data = giveList.value;
-                data = data.concat(res.data);
-                giveList.value = data;
-            }
-            giveReqParams.loadMore = false;
-        }
-    });
-};
-
-const clickTab = (params, index) => {
-    currentTabIndex.value = index;
-    console.log(params, index);
-};
-
-/**
- * 点击列表跳转到推文
- */
-const clickListItem = (params) => {
-    if (!params.srcContentId) {
-        return;
-    }
-    let twitterUrl = "https://twitter.com/";
-    let nickName = "";
-    if (params.type == 1) {
-        nickName = params.userInfo.nickName;
-    } else if (params.type == 2) {
-        nickName = userInfo.value.nickName;
-    }
-    let url = twitterUrl + nickName + "/status/" + params.srcContentId;
-
-    chrome.tabs.create({
-        url,
-    });
-};
-
-/**
- * 交易列表返回
- */
-const transactionsBack = () => {
-    if (!homeVisibility.value) {
-        if (transactionsVisibility.value) {
-            transactionsVisibility.value = false;
-        }
-        homeVisibility.value = true;
-    }
-};
-
-/**
- * 提现返回
- */
-const withdrawBack = () => {
-    if (!homeVisibility.value) {
-        if (withdrawVisibility.value) {
-            withdrawVisibility.value = false;
-        }
-        homeVisibility.value = true;
-        getAccountBalance();
-        giveReqParams.params.pageNum = 1;
-        getLuckdropRecordsList();
-    }
-};
-
-
-const showTransactions = () => {
-//     // homeVisibility.value = false;
-//     // transactionsVisibility.value = true;
-
-    readAllMsg({msgType: 1});
-    router.push('/transactions')
-};
-
-// const clickWithdraw = () => {
-//     if (isRequestWithdrawBalance.value) {
-//         homeVisibility.value = false;
-//         withdrawVisibility.value = true;
-//     }
-// };
-
-const loginAction = () => {
-    Report.reportLog({
-        pageSource: Report.pageSource.denetLogin,
-        businessType: Report.businessType.buttonClick,
-        objectType: Report.objectType.loginButton
-    });
-    login();
-};
-
-const login = () => {
-    callEventPageMethod("POPUP_LOGIN", "", function (response) {
-        console.log("res", response);
-    });
-};
-
-/**
- * sendMessage
- */
-const callEventPageMethod = (actionType, data, callback) => {
-    chrome.runtime.sendMessage(
-        { 
-            actionType: actionType, 
-            data: data 
-        },
-        function (response) {
-            if (typeof callback === "function") callback(response);
-        }
-    );
-};
-
-/**
- * 点击发送,去发推
- */
-const sendTwitter = (params) => {
-    console.log(params)
-    callEventPageMethod(
-        "POPUP_PUBLISH_TWITTER_RED_PACK",
-        { 
-            srcContent: params.postTaskLuckdrop.srcContent, 
-            postId: params.postTaskLuckdrop.postId 
-        },
-        function (response) {
-            console.log("res", response);
-        }
-    );
-};
-// 点击提现
-const clickWithdraw = () => {
-    Report.reportLog({
-        pageSource: Report.pageSource.denetHomePage,
-        businessType: Report.businessType.buttonClick,
-        objectType: Report.objectType.withdrawButton
-    });
-    router.push('/withdraw/home');
-}
-const clickTopUp = () => {
-    Report.reportLog({
-        pageSource: Report.pageSource.denetHomePage,
-        businessType: Report.businessType.buttonClick,
-        objectType: Report.objectType.topupButton
-    });
-    router.push('/top-up/home');
-}
-
-const terminaHandler = (params, index) => {
-    terminaTask = params;
-    terminaTask.index = index;
-    modalVisible.value = true;
-}
-
-const modalCancel = () => {
-    //请求终止接口 id terminaTask.id 、 刷新当前列表、 关闭 
-    modalVisible.value = false;
-    let index = terminaTask.index;
-    terminatedLuckdrop({
-        params: {
-            luckdropId: terminaTask.id
-        }
-    }).then(res => {
-        if(res.code == 0) {
-            giveList.value[index]['status'] = res.data.status;
-            giveList.value[index]['postTaskLuckdrop']['reSendAvailable'] = false;
-            giveList.value[index]['postTaskLuckdrop']['terminatedAvailable'] = false;
-        }
-    });
-    terminaTask = {};
-}
-
-const modalConfirm = () => {
-    modalVisible.value = false;
-    terminaTask = {};
-}
-
-</script>
-
-<style lang="scss" scoped>
-html,
-body {
-    padding: 0 !important;
-    margin: 0 !important;
-}
-
-.page-wrapper {
-    width: 375px;
-    height: 600px;
-    box-sizing: border-box;
-    overflow-y: scroll;
-
-    .nav-bar {
-        padding: 14px;
-        box-sizing: border-box;
-        display: flex;
-        align-items: center;
-        justify-content: space-between;
-
-        .item {
-            display: flex;
-            align-items: center;
-            font-size: 13px;
-            cursor: pointer;
-
-            img {
-                width: 16px;
-                height: 16px;
-                margin-right: 4px;
-            }
-        }
-
-        .left {
-            font-weight: 500;
-        }
-
-        .right {
-            color: #b6b6b6;
-        }
-    }
-
-    .content {
-        padding: 20px;
-        background-color: #F0F8FE;
-
-        .icon-money {
-            width: 70px;
-            height: 70px;
-        }
-
-        .balance {
-            display: flex;
-            justify-content: space-between;
-            .wallet {
-                img {
-                    width: 24px;
-                    height: 24px;
-                    margin-right: 6px;
-                    vertical-align: middle;
-                }
-                font {
-                    color: #000;
-                    font-size: 14px;
-                    font-weight: bold;
-                }
-            }
-            .bill {
-                position: relative;
-                img {
-                    width: 24px;
-                    height: 24px;
-                    cursor: pointer;
-                }
-                .red-dot {
-                    position: absolute;
-                    right: 0px;
-                    top: -1px;
-                }
-            }
-        }
-
-        .amount {
-            margin-top: 20px;
-            margin-bottom: 20px;
-            font-weight: 700;
-            font-size: 36px;
-            line-height: 43px;
-        }
-
-        .area-btn {
-            display: flex;
-            justify-content: space-between;
-            font-weight: 600;
-            font-size: 15px;
-
-            .top-up-btn {
-                cursor: pointer;
-                border: 1px solid #1D9BF0;
-                color: #fff;
-                background: #1D9BF0;
-                border-radius: 100px;
-                width: 165px;
-                height: 38px;
-                text-align: center;
-                margin-left: 8px;
-                line-height: 36px;
-            }
-
-            .withdraw-btn {
-                background: rgba(56, 154, 255, 0.01);
-                border: 1px solid #1D9BF0;
-                box-sizing: border-box;
-                width: 165px;
-                font-size: 15px;
-                height: 38px;
-                text-align: center;
-                line-height: 36px;
-                border-radius: 100px;
-                color: #1D9BF0;
-                display: inline-block;
-                cursor: pointer;
-            }
-        }
-
-        .msg {
-            margin-top: 10px;
-            font-size: 13px;
-            color: #b6b6b6;
-        }
-    }
-
-    .tab-bar {
-        display: flex;
-        align-items: center;
-        position: sticky;
-        position: -webkit-sticky;
-        top: 0px;
-        z-index: 1000;
-        background-color: #fff;
-
-        .tab-item {
-            flex: 1;
-            display: flex;
-            align-items: center;
-            justify-content: center;
-            padding: 17px 0;
-            box-sizing: border-box;
-            border-bottom: 1px solid #ECECEC;
-            cursor: pointer;
-
-            .icon {
-                width: 16px;
-                height: 16px;
-                margin-right: 5px;
-                font-weight: 500;
-                font-size: 16px;
-            }
-        }
-
-        .active {
-            border-bottom: 2px solid #000;
-        }
-    }
-
-    .list-wrapper {
-        min-height: 202px;
-
-        .give-list {
-            min-height: 202px;
-            position: relative;
-
-            .cell {
-                display: flex;
-                justify-content: space-between;
-                min-height: 66px;
-                box-sizing: border-box;
-                padding-left: 14px;
-                position: relative;
-                cursor: pointer;
-
-                .red-dots {
-                    position: absolute; 
-                    right: 4px; 
-                    top: 4px;
-                }
-
-                .img-wrapper {
-                    position: relative;
-                    margin-right: 16px;
-                    box-sizing: border-box;
-
-                    .icon-avatar {
-                        width: 34px;
-                        height: 34px;
-                        border-radius: 50%;
-                    }
-
-                    .icon-give {
-                        position: absolute;
-                        right: -4px;
-                        bottom: 2px;
-                    }
-
-                    .icon-big-give {
-                        margin-top: 14px;
-                    }
-                }
-
-                .info-wrapper {
-                    flex: 1;
-                    height: 100%;
-                    display: flex;
-                    justify-content: space-between;
-                    border-bottom: 1px solid #ECECEC;
-                    box-sizing: border-box;
-                    padding: 10px 14px 10px 0;
-
-                    .left {
-                        .nickname {
-                            font-weight: 500;
-                            font-size: 14px;
-                            margin-bottom: 5px;
-                            max-width: 132px;
-                            word-break: break-all;
-                        }
-
-                        .time {
-                            font-size: 12px;
-                            color: #B0B0B0;
-                        }
-                    }
-
-                    .right {
-                        display: flex;
-                        align-items: center;
-                        cursor: pointer;
-
-                        .msg {
-                            .bold {
-                                font-weight: 500;
-                                font-size: 14px;
-                                text-align: right;
-                                display: flex;
-                                justify-content: flex-end;
-                                align-items: center;
-
-                                .blance {
-                                    margin-left: 3px;
-                                    display: inline-block;
-                                    max-width: 80px;
-                                    word-break: break-all;
-                                    line-height: 18px;
-                                    color: #E29A2E;
-                                }
-
-                                .coin-type-wrapper {
-                                    display: flex;
-                                    align-items: center;
-                                }
-
-                                .coin-type {
-                                    margin-left: 3px;
-                                }
-
-                                img {
-                                    margin-left: 4px;
-                                    width: 14px;
-                                    height: 14px;
-                                }
-                            }
-
-                            .align-content {
-                                flex-direction: column;
-                                align-items: flex-end;
-
-                                .blance {
-                                    max-width: 130px;
-                                }
-                            }
-
-                            .desc {
-                                font-size: 12px;
-                                color: #b6b6b6;
-                                margin-top: 5px;
-                                text-align: right;
-
-                                .desc-bottom-bar {
-                                    display: flex;
-                                    align-items: center;
-                                    justify-content: end;
-                                    margin-top: 10px;
-
-                                    .btn {
-                                        min-width: 80px;
-                                        height: 29px;
-                                        padding: 0 8px;
-                                        box-sizing: border-box;
-                                        font-weight: 400;
-                                        font-size: 14px;
-                                        cursor: pointer;
-                                        text-align: center;
-                                        border-radius: 100px;
-                                        color: #5E5E5E;
-                                        border: 1px solid #DFDFDF;
-                                        display: flex;
-                                        align-items: center;
-                                        justify-content: center;
-                                    }
-
-                                    .send-btn {
-                                        border: 1px solid #1D9BF0;
-                                        color: #1D9BF0;
-                                    }
-
-                                    .detail-btn, .send-btn {
-                                        margin-left: 8px;
-                                    }
-                                }
-                            }
-                        }
-
-                        .icon {
-                            width: 18px;
-                            height: 24px;
-                            margin-left: 4px;
-                            margin-right: -5px;
-                        }
-                    }
-                }
-                .info-center {
-                    align-items: center;
-                }
-            }
-            .cell-center {
-                align-items: center;
-            }
-
-            .icon-empty {
-                position: absolute;
-                left: 50%;
-                top: 50%;
-                transform: translate(-50%, -50%);
-            }
-        }
-
-        .more-list {
-            .cell {
-                cursor: pointer;
-                display: flex;
-                justify-content: space-between;
-                align-items: center;
-                height: 66px;
-                box-sizing: border-box;
-                padding-left: 20px;
-
-                .icon {
-                    width: 42px;
-                    height: 42px;
-                    border-radius: 50%;
-                }
-
-                .info-wrapper {
-                    flex: 1;
-                    height: 100%;
-                    display: flex;
-                    justify-content: space-between;
-                    align-items: center;
-                    border-bottom: 1px solid #ECECEC;
-                    box-sizing: border-box;
-                    padding-right: 16px;
-
-                    .left {
-                        font-weight: 500;
-                        font-size: 16px;
-                        .time {
-                            color: #B0B0B0;
-                        }
-                    }
-
-                    .right {
-                        display: flex;
-                        align-items: center;
-                        cursor: pointer;
-
-                        .icon {
-                            width: 18px;
-                            height: 24px;
-                        }
-                    }
-                }
-            }
-        }
-    }
-}
-
-.page-wrapper::-webkit-scrollbar {
-    display: none;
-}
-</style>

+ 163 - 0
src/view/popup/tabbar-page/index.vue

@@ -0,0 +1,163 @@
+<template>
+  <div class="tabbar-page-wrapper">
+    <global-tip :type="'3'"></global-tip>
+    <!-- login -->
+    <popup-login v-if="!loginStatus" @loginAction="loginAction" />
+    <template v-else>
+      <top-bar  :userInfo="userInfo" 
+                :bgColor="bgColor"
+                :color="color"
+                :boxShadow="boxShadow"></top-bar>
+      <div class="tabbar-content">
+        <router-view></router-view>
+      </div>
+      <tabbar :userInfo="userInfo"  
+              @tabbarClick = "onTabbarHandler"></tabbar>
+    </template>
+  </div>
+</template>
+
+<script setup>
+import { onMounted, onBeforeUnmount, ref, nextTick } from "vue";
+import { getChromeStorage } from "@/uilts/chromeExtension";
+import { setStorage, getStorage } from "@/uilts/help";
+import Report from "@/log-center/log";
+import router from "@/router/popup.js";
+
+import TopBar from "@/view/popup/components/top-bar.vue";
+import Tabbar from "@/view/popup/components/tabbar.vue";
+import  GlobalTip  from '@/view/components/global-tip.vue';
+import popupLogin from "@/view/popup/components/login.vue";
+
+let userInfo = ref({});
+let bgColor = ref('#1b92e2');
+let color =  ref('#fff');
+let boxShadow = ref('none');
+
+let loginStatus = ref('default'); 
+
+const getUserInfo = (cb) => {
+  getChromeStorage("userInfo", (res) => {
+    if (res && res.accessToken) {
+      userInfo.value = res;
+      loginStatus.value = res;
+    } else {
+      loginStatus.value = '';
+      userInfo.value = {};
+    }
+    cb && cb(res);
+  });
+};
+
+const onTabbarHandler = (params) => {
+  if(params.path == '/') {
+    bgColor.value = '#1b92e2';
+    boxShadow.value = 'none';
+    color.value = '#fff'
+  } else {
+    bgColor.value = '#fff';
+    color.value = '#000';
+
+    if(params.path != '/more') {
+      boxShadow.value = '0px 0.5px 0px 0px #D1D9DD';
+    } else {
+      boxShadow.value = 'none';
+    }
+  }
+}
+
+const loginAction = () => {
+    Report.reportLog({
+        pageSource: Report.pageSource.denetLogin,
+        businessType: Report.businessType.buttonClick,
+        objectType: Report.objectType.loginButton
+    });
+    login();
+};
+
+const login = () => {
+    callEventPageMethod("POPUP_LOGIN", "", function (response) {
+        console.log("res", response);
+    });
+}
+
+
+/**
+ * sendMessage
+ */
+const callEventPageMethod = (actionType, data, callback) => {
+    chrome.runtime.sendMessage(
+        { 
+            actionType: actionType, 
+            data: data 
+        },
+        function (response) {
+            if (typeof callback === "function") callback(response);
+        }
+    );
+};
+
+const onPageVisbile = () => {
+  document.addEventListener('visibilitychange', function () {
+    let isHidden = document.hidden;
+    if (!isHidden) {
+      if(!userInfo.value.accessToken) {
+        setTimeout(() => {
+          getUserInfo();
+        }, 500)
+      }
+    }
+  });
+}
+
+const onRuntimeMsg = () => {
+  chrome.runtime.onMessage.addListener(msgListener)
+}
+
+const msgListener = (req, sender, sendResponse) => {
+  sendResponse('');
+  switch (req.actionType) {
+    case 'BG_LOGIN_SET_USERINFO_CB':
+      if(!userInfo.value.accessToken) {
+        setTimeout(() => {
+          getUserInfo();
+        }, 800)
+      }
+      break;
+    case 'CONTENT_POPUP_PAGE_SHOW':
+        init();
+        break;
+  }
+}
+
+const init = () => {
+  nextTick(() => {
+    onTabbarHandler(router.currentRoute.value);
+  })
+  getUserInfo();
+}
+
+onMounted(() => {
+  onPageVisbile();
+  onRuntimeMsg();
+  init();
+});
+
+onBeforeUnmount(() => {
+  chrome.runtime.onMessage.removeListener(msgListener);
+})
+</script>
+
+
+<style lang='scss'>
+.tabbar-page-wrapper {
+  width: 100%;
+  height: 100%;
+  position: relative;
+
+  .tabbar-content {
+    width: 100%;
+    height: calc(100% - 120px);
+  }
+}
+</style>

+ 667 - 0
src/view/popup/tabbar-page/message/index.vue

@@ -0,0 +1,667 @@
+<template>
+  <div class="message-wrapper">
+    <!-- <div class="tab-bar">
+      <div
+        class="tab-item"
+        :class="{ active: currentTabIndex == index }"
+        v-for="(item, index) in tabList"
+        :key="index"
+        @click="clickTab(item, index)"
+      >
+        {{ item.label }}
+      </div>
+    </div> -->
+    <div class="tab-content" ref="pageWrapperDom" @scroll="pageScroll">
+      <div class="list-wrapper" ref="pageGiveListDom">
+        <div class="give-list" v-if="currentTabIndex == 0">
+          <template v-if="giveList.length">
+            <div
+              class="cell"
+              :class="{ 'cell-center': item.type == 1 }"
+              v-for="(item, index) in giveList"
+              :key="index"
+              @click="clickListItem(item, index)"
+            >
+              <red-dot
+                class="red-dots"
+                v-if="item.unReadMsgCount > 0 && isReadMsg"
+              ></red-dot>
+
+              <div class="img-wrapper">
+                <!-- 收到红包 -->
+                <template v-if="item.type == 1">
+                  <img class="icon-avatar" :src="item.userInfo.avatarUrl" />
+                  <img
+                    class="icon-give"
+                    :src="require('@/assets/svg/icon-get-giveaways-s.svg')"
+                  />
+                </template>
+                <!-- 发出去红包 -->
+                <template v-else-if="2">
+                  <img
+                    class="icon-big-give"
+                    :src="require('@/assets/svg/icon-send-giveaways-s.svg')"
+                  />
+                </template>
+              </div>
+              <div
+                class="info-wrapper"
+                :class="{ 'info-center': item.type == 1 }"
+              >
+                <div class="left">
+                  <div class="nickname">
+                    {{ item.type == 1 ? "Get Giveaway" : "Send Giveaway" }}
+                  </div>
+                  <div class="time">
+                    {{ moment(item.timestamp).format("MM-DD HH:mm:ss") }}
+                  </div>
+                </div>
+                <div class="right">
+                  <div class="msg">
+                    <div
+                      class="bold"
+                      :class="{
+                        'align-content':
+                          (item.type == 2 ||
+                            (item.type == 1 && item.status == 1)) &&
+                          item.amount.length + item.currencySymbol.length > 12,
+                      }"
+                    >
+                      <!-- 收到的 -->
+                      <template v-if="item.type == 1">
+                        <!-- 进行中-->
+                        <template v-if="item.status == 0">
+                          in progress
+                        </template>
+                        <!-- 已完成 -->
+                        <template v-else-if="item.status == 1">
+                          <span class="blance">
+                            <a-tooltip :title="item.amount">
+                              {{ getBit(item.amount) }}</a-tooltip
+                            >
+                          </span>
+                          <div class="coin-type-wrapper">
+                            <span class="coin-type">{{
+                              item.currencySymbol || ""
+                            }}</span>
+                            <img :src="item.currencyIconPath" alt="" />
+                          </div>
+                        </template>
+                        <!-- 已过期 -->
+                        <template v-else-if="item.status == 2">
+                          Timeout
+                        </template>
+                      </template>
+                      <!-- 发出去的 -->
+                      <template v-else-if="item.type == 2">
+                        <span class="blance">
+                          <a-tooltip :title="'-' + item.amount">
+                            -{{ getBit(item.amount) }}
+                          </a-tooltip>
+                        </span>
+                        <div class="coin-type-wrapper">
+                          <span class="coin-type">{{
+                            item.currencySymbol || ""
+                          }}</span>
+                          <img :src="item.currencyIconPath" alt="" />
+                        </div>
+                      </template>
+                    </div>
+                    <!-- 发出的红包显示 -->
+                    <div class="desc" v-if="item.type == 2">
+                      <!-- 未发送-->
+                      <template v-if="item.postTaskLuckdrop.reSendAvailable">
+                        Unpublished
+                      </template>
+                      <!-- 进行中 -->
+                      <template v-else-if="item.status == 1">
+                        {{ item.postTaskLuckdrop.receivedCount }}/{{
+                          item.postTaskLuckdrop.totalCount
+                        }}
+                      </template>
+                      <!-- 2:已结束; 3:提前终止-->
+                      <template
+                        v-else-if="item.status == 2 || item.status == 3"
+                      >
+                        ({{
+                          item.status == 2 ? "Time expired" : "Termination"
+                        }}) {{ item.postTaskLuckdrop.receivedCount }}/{{
+                          item.postTaskLuckdrop.totalCount
+                        }}
+                      </template>
+                      <!-- 红包提前终止/退款(进行中)显示-->
+                      <template v-if="item.status == 4"> Terminating </template>
+
+                      <!-- 进行中或者未发送成功时显示 
+                                                v-if="item.status == 1 || item.postTaskLuckdrop.reSendAvailable"-->
+                      <div class="desc-bottom-bar">
+                        <!-- 没有终止红包时显示 -->
+                        <div
+                          v-if="item.postTaskLuckdrop.terminatedAvailable"
+                          class="btn"
+                          @click.stop="terminaHandler(item, index)"
+                        >
+                          Termination
+                        </div>
+
+                        <!-- 红包未发出显示 -->
+                        <div
+                          class="btn send-btn"
+                          v-if="item.postTaskLuckdrop.reSendAvailable"
+                          @click.stop="sendTwitter(item)"
+                        >
+                          Send
+                        </div>
+                        <div
+                          v-else-if="item.srcContentId"
+                          class="btn detail-btn"
+                          @click.stop="clickListItem(item, index)"
+                        >
+                          details
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                  <!-- 发红包—— 未发出、进行中 隐藏 -->
+                  <img
+                    v-if="item.type != 2"
+                    class="icon"
+                    :src="require('@/assets/svg/icon-cell-arrow-right.svg')"
+                  />
+                </div>
+              </div>
+            </div>
+          </template>
+          <template v-else>
+            <img
+              class="icon-empty"
+              :src="require('@/assets/svg/icon-empty-list.svg')"
+            />
+          </template>
+        </div>
+      </div>
+    </div>
+    <modal
+      :visible="modalVisible"
+      title="Early termination of Giveaway?"
+      content="The remaining amount will be returned to your wallet within 1 day."
+      cancelText="Termination"
+      confirmText="Cancel"
+      @cancel="modalCancel"
+      @confirm="modalConfirm"
+    />
+  </div>
+</template>
+
+<script setup>
+import { ref, onMounted, inject, onBeforeUnmount } from "vue";
+
+import modal from "@/view/popup/components/modal.vue";
+import redDot from "@/view/components/red-dot.vue";
+
+import { getBit } from "@/uilts/help";
+import { getMineLuckdropRecords } from "@/http/account";
+import { terminatedLuckdrop } from "@/http/redPacket";
+import { readAllMsgByType, getAllMessageInfo } from "@/http/messageApi"
+import { setBadgeInfo, hideBadge } from "@/logic/background/twitter";
+import { getChromeStorage } from "@/uilts/chromeExtension";
+
+var moment = require("moment");
+
+let currentTabIndex = ref(0);
+let userInfo = ref({});
+
+let tabList = ref([
+  {
+    label: "ALL",
+  },
+  {
+    label: "Giveaway",
+  },
+  {
+    label: "NFT",
+  },
+]);
+
+let pageWrapperDom = ref(null);
+let pageGiveListDom = ref(null);
+
+let modalVisible = ref(false);
+let terminaTask = {};
+
+let giveList = ref([]);
+let giveReqParams = {
+  params: {
+    pageNum: 1,
+    pageSize: 20,
+  },
+  loadMore: false,
+};
+
+
+let isReadMsg = ref(true);
+
+const clickTab = (params, index) => {
+  currentTabIndex.value = index;
+};
+
+/**
+ * 获取红包列表
+ */
+const getLuckdropRecordsList = () => {
+  getMineLuckdropRecords({
+    params: giveReqParams.params,
+  }).then((res) => {
+    chrome.runtime.connect({ name: "popup" });
+    if (res.data && res.data.length) {
+      if (giveReqParams.params.pageNum < 2) {
+        giveList.value = res.data;
+      } else {
+        let data = giveList.value;
+        data = data.concat(res.data);
+        giveList.value = data;
+      }
+      giveReqParams.loadMore = false;
+    }
+  });
+};
+
+/**
+ * 点击列表跳转到推文
+ */
+const clickListItem = (params) => {
+  if (!params.srcContentId) {
+    return;
+  }
+  let twitterUrl = "https://twitter.com/";
+  let nickName = "";
+  if (params.type == 1) {
+    nickName = params.userInfo.nickName;
+  } else if (params.type == 2) {
+    nickName = userInfo.value.nickName;
+  }
+  let url = twitterUrl + nickName + "/status/" + params.srcContentId;
+
+  chrome.tabs.create({
+    url,
+  });
+};
+
+const pageScroll = (e) => {
+  let wrapperHeight = pageWrapperDom.value.offsetHeight;
+  let pageGiveListHeight = pageGiveListDom.value.offsetHeight;
+  let scrollTop = e.target.scrollTop || 0;
+  if (currentTabIndex.value != 0) {
+    return;
+  }
+  if (
+    giveReqParams.loadMore === false &&
+    wrapperHeight + scrollTop >= pageGiveListHeight - 60
+  ) {
+    giveReqParams.loadMore = true;
+    giveReqParams.params.pageNum++;
+    getLuckdropRecordsList();
+  }
+};
+
+/**
+ * 点击发送,去发推
+ */
+const sendTwitter = (params) => {
+  console.log(params);
+  callEventPageMethod(
+    "POPUP_PUBLISH_TWITTER_RED_PACK",
+    {
+      srcContent: params.postTaskLuckdrop.srcContent,
+      postId: params.postTaskLuckdrop.postId,
+    },
+    function (response) {
+      console.log("res", response);
+    }
+  );
+};
+
+/**
+ * sendMessage
+ */
+const callEventPageMethod = (actionType, data, callback) => {
+  chrome.runtime.sendMessage(
+    {
+      actionType: actionType,
+      data: data,
+    },
+    function (response) {
+      if (typeof callback === "function") callback(response);
+    }
+  );
+};
+
+const terminaHandler = (params, index) => {
+  terminaTask = params;
+  terminaTask.index = index;
+  modalVisible.value = true;
+};
+
+const modalCancel = () => {
+  //请求终止接口 id terminaTask.id 、 刷新当前列表、 关闭
+  modalVisible.value = false;
+  let index = terminaTask.index;
+  terminatedLuckdrop({
+    params: {
+      luckdropId: terminaTask.id,
+    },
+  }).then((res) => {
+    if (res.code == 0) {
+      giveList.value[index]["status"] = res.data.status;
+      giveList.value[index]["postTaskLuckdrop"]["reSendAvailable"] = false;
+      giveList.value[index]["postTaskLuckdrop"]["terminatedAvailable"] = false;
+    }
+  });
+  terminaTask = {};
+};
+
+const modalConfirm = () => {
+  modalVisible.value = false;
+  terminaTask = {};
+};
+
+const readAllMsg = ({msgType}, cb) => {
+    readAllMsgByType({
+        params: {
+            msgType
+        }
+    }).then(res => {
+        cb && cb();
+    })
+};
+
+const setMessageCount = () => {
+    getAllMessageInfo({params: {
+    }}).then(res => {
+        if(res.code == 0) {
+            let {unReadCountTotal = 0, unReadCountWalletDetail = 0, unReadCountTaskLuckdrop = 0} = res.data;
+            if(unReadCountTotal > 0) {
+                let text = unReadCountTotal > 99 ? '99+' : unReadCountTotal+'';
+                setBadgeInfo({data: {text}});
+            } else {
+                hideBadge();
+            }
+        }
+    });
+}
+
+
+const getUserInfo = (cb) => {
+  getChromeStorage("userInfo", (res) => {
+    if (res && res.accessToken) {
+      userInfo.value = res;
+    } else {
+      userInfo.value = {};
+    }
+    cb && cb(res);
+  });
+};
+
+const init = () => {
+  getUserInfo();
+  getLuckdropRecordsList();
+
+  setMessageCount();
+  setTimeout(() => {
+      isReadMsg.value = false;
+      readAllMsg({msgType: 1}, () => {
+          setMessageCount();
+      });
+  }, 2000);
+}
+
+const onMessage = () => {
+    chrome.runtime.onMessage.addListener(msgListener)
+}
+
+const msgListener = (req, sender, sendResponse) => {
+  sendResponse('');
+  switch (req.actionType) {
+      case 'CONTENT_POPUP_PAGE_SHOW':
+          init();
+          break;
+  }
+}
+
+onMounted(() => {
+  onMessage();
+  init();
+});
+
+onBeforeUnmount(() => {
+  chrome.runtime.onMessage.removeListener(msgListener);
+})
+</script>
+
+
+<style scoped lang="scss">
+.message-wrapper {
+  width: 100%;
+  height: 100%;
+  margin-top: 1px;
+  .tab-bar {
+    display: flex;
+    align-items: center;
+    background-color: #fff;
+    box-shadow: 0px 0.5px 0px #d1d9dd;
+
+    .tab-item {
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      padding: 14px 0px;
+      box-sizing: border-box;
+      border-bottom: 2px solid #fff;
+      margin: 0 12px;
+      font-size: 14px;
+      color: #949494;
+      cursor: pointer;
+    }
+
+    .active {
+      border-bottom: 2px solid #1d9bf0;
+      font-weight: 500;
+      color: #000;
+    }
+  }
+
+  .tab-content {
+    height: 100%;
+    overflow-y: auto;
+    .list-wrapper {
+      min-height: 202px;
+
+      .give-list {
+        min-height: 202px;
+        position: relative;
+
+        .cell {
+          display: flex;
+          justify-content: space-between;
+          min-height: 76px;
+          box-sizing: border-box;
+          padding-left: 14px;
+          position: relative;
+          cursor: pointer;
+
+          .red-dots {
+            position: absolute;
+            right: 4px;
+            top: 4px;
+          }
+
+          .img-wrapper {
+            position: relative;
+            margin-right: 16px;
+            box-sizing: border-box;
+
+            .icon-avatar {
+              width: 34px;
+              height: 34px;
+              border-radius: 50%;
+              margin-right: 8px;
+            }
+
+            .icon-give {
+              position: absolute;
+              right: 1px;
+              bottom: -1px;
+              width: 18px;
+              height: 18px;
+            }
+
+            .icon-big-give {
+              margin-top: 12px;
+            }
+          }
+
+          .info-wrapper {
+            flex: 1;
+            height: 100%;
+            display: flex;
+            justify-content: space-between;
+            box-sizing: border-box;
+            padding: 10px 14px 10px 0;
+
+            .left {
+              .nickname {
+                font-weight: 500;
+                font-size: 13px;
+                margin-bottom: 5px;
+                max-width: 132px;
+                word-break: break-all;
+              }
+
+              .time {
+                font-size: 12px;
+                color: #b0b0b0;
+              }
+            }
+
+            .right {
+              display: flex;
+              align-items: center;
+              cursor: pointer;
+
+              .msg {
+                display: flex;
+                align-items: end;
+                flex-direction: column;
+                .bold {
+                  font-weight: 500;
+                  font-size: 13px;
+                  text-align: right;
+                  display: flex;
+                  justify-content: flex-end;
+                  align-items: center;
+                  max-width: 140px;
+
+                  .blance {
+                    margin-left: 3px;
+                    display: inline-block;
+                    max-width: 80px;
+                    word-break: break-all;
+                    line-height: 18px;
+                    color: #e86f00;
+                  }
+
+                  .coin-type-wrapper {
+                    display: flex;
+                    align-items: center;
+                  }
+
+                  .coin-type {
+                    margin-left: 3px;
+                    word-break: break-all;
+                  }
+
+                  img {
+                    margin-left: 4px;
+                    width: 14px;
+                    height: 14px;
+                  }
+                }
+
+                .align-content {
+                  flex-direction: column;
+                  align-items: flex-end;
+
+                  .blance {
+                    max-width: 130px;
+                  }
+                }
+
+                .desc {
+                  font-size: 12px;
+                  color: #b6b6b6;
+                  margin-top: 5px;
+                  text-align: right;
+
+                  .desc-bottom-bar {
+                    display: flex;
+                    align-items: center;
+                    justify-content: end;
+                    margin-top: 10px;
+
+                    .btn {
+                      min-width: 80px;
+                      height: 29px;
+                      padding: 0 8px;
+                      box-sizing: border-box;
+                      font-weight: 400;
+                      font-size: 14px;
+                      cursor: pointer;
+                      text-align: center;
+                      border-radius: 100px;
+                      color: #5e5e5e;
+                      border: 1px solid #dfdfdf;
+                      display: flex;
+                      align-items: center;
+                      justify-content: center;
+                    }
+
+                    .send-btn {
+                      border: 1px solid #1d9bf0;
+                      color: #1d9bf0;
+                    }
+
+                    .detail-btn,
+                    .send-btn {
+                      margin-left: 8px;
+                    }
+                  }
+                }
+              }
+
+              .icon {
+                width: 18px;
+                height: 24px;
+                margin-left: 4px;
+                margin-right: -5px;
+              }
+            }
+          }
+          .info-center {
+            align-items: center;
+          }
+        }
+        .cell-center {
+          align-items: center;
+        }
+
+        .icon-empty {
+          position: absolute;
+          left: 50%;
+          top: 50%;
+          transform: translate(-50%, -50%);
+        }
+      }
+    }
+  }
+}
+</style>

+ 115 - 0
src/view/popup/tabbar-page/more/index.vue

@@ -0,0 +1,115 @@
+<template>
+  <div class="more-page">
+    <div class="more-list">
+      <div
+        class="cell"
+        v-for="(item, index) in moreTabList"
+        :key="index"
+        @click="moreItemHandle(item)"
+      >
+        <img class="icon" :src="item.icon" />
+        <div class="info-wrapper">
+          <div class="left">
+            {{ item.label }}
+          </div>
+          <div class="right">
+            <img
+              class="icon"
+              :src="require('@/assets/svg/icon-cell-arrow-right.svg')"
+            />
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { ref } from "vue";
+
+let moreTabList = ref([
+  {
+    icon: require("@/assets/svg/icon-website.svg"),
+    label: "Official Website",
+    href: "https://denet.me",
+  },
+  {
+    icon: require("@/assets/svg/icon-twitter.svg"),
+    label: "Twitter",
+    href: "https://twitter.com/denet2022",
+  },
+  {
+    icon: require("@/assets/svg/icon-discord.svg"),
+    label: "Discord",
+    href: "https://discord.gg/wZSz9p8ddG",
+  },
+  {
+      icon: require("@/assets/svg/icon-telegram.svg"),
+      label: "Telegram",
+      href: 'https://t.me/denetpro'
+  }
+]);
+
+const moreItemHandle = (params) => {
+  window.open(params.href);
+};
+</script>
+
+<style scoped lang="scss">
+.more-page {
+  background: #f6f6f6;
+  width: 100%;
+  height: 100%;
+  overflow: auto;
+  margin-top: 1px;
+
+  .more-list {
+    background: #fff;
+    margin-top: 10px;
+
+    .cell {
+      cursor: pointer;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      height: 56px;
+      box-sizing: border-box;
+      padding: 0 16px;
+
+      .icon {
+        width: 40px;
+        height: 40px;
+        border-radius: 50%;
+      }
+
+      .info-wrapper {
+        flex: 1;
+        height: 100%;
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        box-sizing: border-box;
+        margin-left: 13px;
+
+        .left {
+          font-size: 14px;
+          .time {
+            color: #b0b0b0;
+          }
+        }
+
+        .right {
+          display: flex;
+          align-items: center;
+          cursor: pointer;
+
+          .icon {
+            width: 18px;
+            height: 24px;
+          }
+        }
+      }
+    }
+  }
+}
+</style>

+ 424 - 0
src/view/popup/tabbar-page/nft/detail.vue

@@ -0,0 +1,424 @@
+<template>
+    <div class="nft-detail-wrapper">
+        <div class="back-bar">
+            <img
+                :src="require('@/assets/svg/icon-nft-back-arrow.svg')"
+                class="icon-arrow"
+                @click="back"
+            />
+            {{NFTInfo.nftItemName}}
+        </div>
+        <div class="content">
+            <div class="nft-img">
+                <img
+                    class="img"
+                    :src="NFTInfo.imagePath"
+                    @click="clickNFTImg"
+                />
+            </div>
+            <div class="desc item" v-if="nftMetaData.description">
+                <div class="title">Description</div>
+                <div class="desc-content" v-html="nftMetaData.description"></div>
+            </div>
+            <div class="prop item" v-if="nftMetaData.properties && nftMetaData.properties.length">
+                <div class="title">Properties</div>
+                <div class="prop-content">
+                    <div
+                        class="prop-item"
+                        v-for="(filedValueItem, filedValueIndex) in nftMetaData.properties"
+                        :key="filedValueIndex"
+                    >
+                        {{ filedValueItem.name }}
+                        <div class="prop-name">
+                            {{ filedValueItem.value }}
+                        </div>
+                        {{ filedValueItem.description }}
+                    </div>
+                </div>
+            </div>
+
+            <div class="about item" v-if="nftMetaData.about">
+                <div class="title">About</div>
+                <div class="about-content" v-html="nftMetaData.about"></div>
+            </div>
+            <div class="detail item"  v-if="nftDetailData.details">
+                    <div class="title">Details</div>
+                    <div class="detail-content">
+                        <div class="detail-item">
+                            <div class="left">Contract Address</div>
+                            <div class="right address"  
+                                @click="clickAddress">
+                                    <span>{{nftDetailData.details.contractAddress}}</span>
+                                    <span>{{nftDetailData.details.contractAddress}}</span>
+                            </div>
+                        </div>
+                        <div class="detail-item">
+                            <div class="left">Token ID</div>
+                            <div class="right token"
+                                @click="clickToken">
+                                {{nftDetailData.details.tokenId}}
+                            </div>
+                        </div>
+                        <div class="detail-item">
+                            <div class="left">Token Standard</div>
+                            <div class="right" >
+                                {{nftDetailData.details.tokenStandard}}
+                            </div>
+                        </div>
+                        <div class="detail-item">
+                            <div class="left">Blockchain</div>
+                            <div class="right" >
+                                {{nftDetailData.details.blockChain}}
+                            </div>
+                        </div>
+                        <div class="detail-item">
+                            <div class="left">Creator Fees</div>
+                            <div class="right" >
+                                {{nftDetailData.details.creatorFees}}
+                            </div>
+                        </div>
+                        <div class="detail-item">
+                            <div class="left">Transaction Royalties</div>
+                            <div class="right" >
+                                {{nftDetailData.details.transactionRoyalties}}
+                            </div>
+                        </div>
+                    </div>
+                </div>
+                <div class="date item"  v-if="nftDetailData.dateOfPossession">
+                    <div class="title">Date of possession</div>
+                    <div class="date-content">{{nftDetailData.dateOfPossession}}</div>
+                </div>
+
+                <div class="price item"  v-if="nftDetailData.purchasePrice">
+                    <div class="title">Purchase price</div>
+                    <div class="price-content">{{nftDetailData.purchasePrice}}</div>
+                </div>
+        </div>
+        <div class="bottom-bar">
+            <div class="default">NFT Sale function, coming soon</div>
+            <!-- <div class="sell">
+                    <div class="sell-btn">
+                        Sell
+                    </div>
+                </div> 
+                <div class="cancel-sale">
+                    <div class="left">
+                        233 USDT
+                        <div class="final">
+                            (Final 203.5 USDT)
+                        </div>
+                    </div>
+                    <div class="cancel-btn">
+                        Cancel sale
+                    </div>
+                </div> -->
+        </div>
+    </div>
+</template>
+
+<script setup>
+import { ref, onMounted } from "vue";
+import router from "@/router/popup.js";
+
+import {getNFTDetail} from "@/http/nft.js";
+
+let nftMetaData = ref({});
+let nftDetailData = ref({});
+
+let NFTInfo = ref({
+    imagePath: '',
+    nftItemName: ''
+});
+
+const back = () => {
+    router.back();
+};
+
+const clickAddress = () => {
+    let {contractAddressUrl = ''} = nftDetailData.value.details;
+    if(contractAddressUrl) {
+        window.open(contractAddressUrl);
+    }
+}
+
+const clickToken = () => {
+    let {tokenIdUrl = ''} = nftDetailData.value.details;
+    if(tokenIdUrl) {
+        window.open(tokenIdUrl);
+    }
+}
+
+const clickNFTImg = () => {
+    // window.open(NFTInfo.value.imagePath);
+};
+
+const getDetail = () => {
+    getNFTDetail({
+        params: {
+            nftItemId: NFTInfo.value.nftItemId
+        }
+    }).then(res => {
+        if(res.code == 0) {
+            console.log(res)
+            let { metadata = '{}'} = res.data || {};
+            nftDetailData.value = res.data;
+            nftMetaData.value = JSON.parse(metadata);
+        }
+    }).catch((err)=>{
+
+    })
+}
+
+onMounted(() => {
+    let {params = '{}'} = router.currentRoute.value.query;
+    NFTInfo.value = JSON.parse(params);
+    getDetail();
+})
+
+
+</script>
+
+<style scoped lang="scss">
+.nft-detail-wrapper {
+    width: 100%;
+    height: 100%;
+
+    .back-bar {
+        height: 48px;
+        background: #ffffff;
+        box-shadow: 0px 0.5px 0px #d1d9dd;
+        box-sizing: border-box;
+        padding: 14px;
+        font-weight: 500;
+        font-size: 16px;
+        display: flex;
+        align-items: center;
+
+        .icon-arrow {
+            width: 24px;
+            margin-right: 12px;
+            cursor: pointer;
+        }
+    }
+
+    .content {
+        width: 100%;
+        height: calc(100% - 120px);
+        padding: 0 16px;
+        box-sizing: border-box;
+        overflow-y: auto;
+
+        .nft-img {
+            margin-top: 23px;
+            margin-bottom: 20px;
+            text-align: center;
+            cursor: pointer;            
+
+            .img {
+                width: 280px;
+                border-radius: 26px;
+            }
+        }
+
+        .item {
+            border: 1px solid #e3e3e3;
+            border-radius: 10px;
+            padding: 14px;
+            box-sizing: border-box;
+            margin-bottom: 12px;
+
+            .title {
+                font-weight: 600;
+                font-size: 14px;
+            }
+        }
+
+        .desc {
+            margin-top: 10px;
+            .desc-content {
+                font-weight: 500;
+                font-size: 14px;
+                color: #929292;
+
+                span {
+                    color: #1d9bf0;
+                }
+            }
+        }
+
+        .prop {
+            .prop-content {
+                display: flex;
+                flex-wrap: wrap;
+                margin-top: 12px;
+
+                .prop-item {
+                    width: 48%;
+                    height: 88px;
+                    background: #f8f8f8;
+                    border-radius: 10px;
+                    display: flex;
+                    flex-direction: column;
+                    justify-content: center;
+                    padding: 8px;
+                    box-sizing: border-box;
+                    align-items: center;
+                    font-weight: 500;
+                    font-size: 12px;
+                    color: #929292;
+                    margin-bottom: 10px;
+
+                    .prop-name {
+                        font-weight: 700;
+                        font-size: 17px;
+                        margin-top: 6px;
+                        margin-bottom: 8px;
+                        color: #000;
+                    }
+                }
+                .prop-item:nth-child(odd) {
+                    margin-right: 8px;
+                }
+            }
+        }
+
+        .about-content {
+            margin-top: 22px;
+            .section {
+                font-weight: 400;
+                font-size: 14px;
+                margin-bottom: 20px;
+            }
+        }
+        .section {
+            font-weight: 400;
+            font-size: 14px;
+            margin-bottom: 10px;
+        }
+
+        .detail-content {
+            margin-top: 15px;
+
+            .detail-item {
+                display: flex;
+                align-items: center;
+                justify-content: space-between;
+                height: 24px;
+                font-weight: 400;
+                font-size: 14px;
+
+                .right {
+                    color: #929292;
+                }
+
+                .token {
+                    color: #1d9bf0 !important;
+                    cursor: pointer;
+                }
+
+                .address {
+                    width: 100px;
+                    white-space: nowrap;
+                    color: #1d9bf0 !important;
+                    cursor: pointer;
+
+                    > span {
+                        display: inline-block;
+                        overflow: hidden;
+                        text-overflow: ellipsis;
+                        width: 50%;
+                        + span {
+                            width: calc(50% + 10px);
+                            direction: rtl;
+                            margin-left: -11px;
+                        }
+                    }
+                }
+            }
+        }
+
+        .date-content,
+        .price-content {
+            margin-top: 10px;
+            font-weight: 500;
+            font-size: 14px;
+            color: #929292;
+        }
+    }
+
+    .bottom-bar {
+        background: #ffffff;
+        box-shadow: inset 0px 1px 0px #ececec;
+        height: 70px;
+        padding: 15px 16px;
+        box-sizing: border-box;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+
+        .default {
+            font-weight: 500;
+            font-size: 16px;
+            color: #a8a8a8;
+            text-align: center;
+        }
+
+        .sell {
+            width: 100%;
+            height: 100%;
+
+            .sell-btn {
+                width: 120px;
+                height: 40px;
+                box-sizing: border-box;
+                border: 1px solid #e9e9e9;
+                border-radius: 100px;
+                font-weight: 500;
+                font-size: 16px;
+                color: #1d9bf0;
+                display: flex;
+                align-items: center;
+                justify-content: center;
+                position: absolute;
+                right: 16px;
+                cursor: pointer;
+            }
+        }
+
+        .cancel-sale {
+            width: 100%;
+            height: 100%;
+            display: flex;
+            align-items: center;
+            justify-content: space-between;
+
+            .left {
+                font-weight: 500;
+                font-size: 15px;
+                .final {
+                    font-weight: 500;
+                    font-size: 12px;
+                    color: #929292;
+                    margin-top: 6px;
+                }
+            }
+
+            .cancel-btn {
+                width: 120px;
+                height: 40px;
+                box-sizing: border-box;
+                border: 1px solid #e9e9e9;
+                border-radius: 100px;
+                font-weight: 500;
+                font-size: 16px;
+                color: #ff0000;
+                display: flex;
+                align-items: center;
+                justify-content: center;
+                cursor: pointer;
+            }
+        }
+    }
+}
+</style>

+ 138 - 0
src/view/popup/tabbar-page/nft/index.vue

@@ -0,0 +1,138 @@
+<template>
+  <div class="nft-page-wrapper"
+    ref="pageWrapperDom"
+    @scroll="pageScroll" >
+    <div class="content" ref="pageListDom">
+      <div class="item" 
+          v-for="(item, index) in listData" 
+          :key="index" 
+          @click="clickNFT(item)">
+        <img :src="item.imagePath" class="img">
+        <div class="name">{{item.nftItemName}}</div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { ref, onMounted, onBeforeUnmount } from "vue";
+import router from "@/router/popup.js";
+
+import {nftListMine} from "@/http/nft.js";
+
+let listData = ref([]);
+
+let NFTReqParams = {
+  params: {
+    pageNum: 1,
+    pageSize: 30,
+  },
+  loadMore: false,
+};
+
+let pageWrapperDom = ref(null);
+let pageListDom = ref(null);
+
+const clickNFT = (params) => {
+  router.push({
+    path: '/NFTDetail',
+    query: {
+      params: JSON.stringify(params)
+    }
+  })
+}
+
+const getNFTListMine = () => {
+  nftListMine({
+    params: NFTReqParams.params,
+  }).then((res) => {
+    if (res.data && res.data.length) {
+      if (NFTReqParams.params.pageNum < 2) {
+        listData.value = res.data;
+      } else {
+        let data = listData.value;
+        data = data.concat(res.data);
+        listData.value = data;
+      }
+      NFTReqParams.loadMore = false;
+    }
+  });
+}
+
+
+
+const pageScroll = (e) => {
+  let wrapperHeight = pageWrapperDom.value.offsetHeight;
+  let pageListHeight = pageListDom.value.offsetHeight;
+  let scrollTop = e.target.scrollTop || 0;
+  if (
+    NFTReqParams.loadMore === false &&
+    wrapperHeight + scrollTop >= pageListHeight - 60
+  ) {
+    NFTReqParams.loadMore = true;
+    NFTReqParams.params.pageNum++;
+    getNFTListMine();
+  }
+};
+
+
+const onMessage = () => {
+    chrome.runtime.onMessage.addListener(msgListener);
+}
+
+const msgListener = (req, sender, sendResponse) => {
+    sendResponse('');
+    switch (req.actionType) {
+        case 'CONTENT_POPUP_PAGE_SHOW':
+            getNFTListMine();
+            break;
+    }
+}
+
+onMounted(() => {
+  onMessage();
+  getNFTListMine();
+})
+
+onBeforeUnmount(() => {
+    chrome.runtime.onMessage.removeListener(msgListener);
+})
+</script>
+
+
+<style scoped lang="scss">
+    .nft-page-wrapper {
+      width: 100%;
+      height: 100%;
+      overflow-y: auto;
+
+      .content {
+        width: 100%;
+        display: flex;
+        flex-wrap: wrap;
+        padding: 5px 2px 0 16px;
+        box-sizing: border-box;
+
+        .item {
+          width: 33%;
+          box-sizing: border-box;
+          padding-right: 14px;
+          margin-top: 15px;
+          cursor: pointer;
+
+          .img {
+            width: 100%;
+            border-radius: 5px;
+            height: 104px;
+            object-fit: cover;
+          }
+
+          .name {
+            font-weight: 400;
+            font-size: 12px;
+            margin-top: 6px;
+          }
+        }
+      }
+    }
+</style>

+ 359 - 0
src/view/popup/tabbar-page/wallter/popup.vue

@@ -0,0 +1,359 @@
+<template>
+    <div class="page-wrapper" ref="pageWrapperDom">
+        <div class="content">
+            <div class="balance">
+                <div class="wallet">
+                    <font>Balance Valuation</font>
+                </div>
+            </div>
+            <div class="amount-wrapper">
+                <div class="amount">
+                    <a-tooltip :title="'$'+canWithdrawBalance">
+                        ${{ getBit(canWithdrawBalance) }}
+                    </a-tooltip>
+                </div>
+
+                <div class="right">
+                    <div class="bill" @click="showTransactions">
+                        <red-dot class="red-dot" v-if="unReadCountWallet > 0"></red-dot>
+                        <img :src="require('@/assets/svg/icon-home-list.svg')" />
+                    </div>
+
+                    <img :src="require('@/assets/svg/icon-home-refresh.svg')" 
+                        class="icon"
+                        :class="{ transform_rotate: iconRotate }"
+                        @click="refreshList"  />
+                </div>
+            </div>
+        </div>
+
+        <currency-list 
+            v-if="userInfo.accessToken"
+            style="height: calc(100% - 103px);"
+            ref="currencyListDom"
+            :showRefresh="false"
+            :page="'top-up'"
+            @selectCurrency="selectCurrency"></currency-list>
+    </div>
+</template>
+
+<script setup>
+import { ref, onMounted, onBeforeUnmount, inject } from "vue";
+
+import redDot from "@/view/components/red-dot.vue";
+import CurrencyList from "@/view/components/currency-list.vue";
+
+import {
+    getChromeStorage,
+} from "@/uilts/chromeExtension";
+import { getBalance } from "@/http/account";
+import { getAllMessageInfo } from "@/http/messageApi"
+import { setBadgeInfo, hideBadge } from "@/logic/background/twitter";
+import Report from "@/log-center/log";
+import router from "@/router/popup.js";
+import { getBit } from "@/uilts/help";
+
+let withdraw_info = inject('withdraw_info')
+withdraw_info.paypal = {}
+
+var moment = require("moment");
+
+let userInfo = ref({});
+let canWithdrawBalance = ref(0);
+withdraw_info.paypal.amount_value = canWithdrawBalance
+withdraw_info.balance = 0
+
+let isRequestWithdrawBalance = ref(false);
+
+let currencyListDom = ref('');
+let iconRotate = ref(false)
+
+// 钱包未读数
+let unReadCountWallet = ref(0);
+
+let walletWithdrawConfig = ref({
+    withdrawUSDPaypalFee: 0,
+    withdrawUSDPreMinAmount: 100,
+    withdrawUSDSwitch: "",
+    withdrawUSDPaypalFeeDesc: ''
+});
+withdraw_info.paypal.wallet_withdraw_config = walletWithdrawConfig
+
+
+function selectCurrency(_params) {
+    router.push({ 
+        path: 'currencyDetail',
+        query: {
+            params: JSON.stringify(_params)
+        }
+    });
+}
+
+const init = () => {
+    checkLoginState((res) => {
+        if (res) {
+            getAccountBalance();
+            Report.reportLog({
+                pageSource: Report.pageSource.denetHomePage,
+                businessType: Report.businessType.pageView,
+            },{
+                type: window.location.href.indexOf('home.html') > -1 ? 'web' : 'extensions'
+            });
+            setMessageCount();
+        } else {
+            Report.reportLog({
+                pageSource: Report.pageSource.denetLogin,
+                businessType: Report.businessType.pageView,
+            });
+        }
+    });
+}
+
+const setMessageCount = () => {
+    getAllMessageInfo({params: {
+    }}).then(res => {
+        if(res.code == 0) {
+            let {unReadCountTotal = 0, unReadCountWalletDetail = 0, unReadCountTaskLuckdrop = 0} = res.data;
+            unReadCountWallet.value = unReadCountWalletDetail;
+            if(unReadCountTotal > 0) {
+                let text = unReadCountTotal > 99 ? '99+' : unReadCountTotal+'';
+                setBadgeInfo({data: {text}});
+            } else {
+                hideBadge();
+            }
+        }
+    });
+}
+
+
+/**
+ * 获取账户余额
+ */
+const getAccountBalance = () => {
+    isRequestWithdrawBalance.value = false;
+    getBalance({}).then((res) => {
+        isRequestWithdrawBalance.value = true;
+        if (res.code == 0) {
+            if (res.data) {
+                canWithdrawBalance.value = res.data.allAssetValuationUSD;
+                withdraw_info.balance = res.data.allAssetValuationUSD || 0
+            }
+        }
+    });
+};
+
+const getUserInfo = (cb) => {
+    getChromeStorage("userInfo", (res) => {
+        cb && cb(res);
+    });
+};
+
+/**
+ * 检查登录状态
+ */
+const checkLoginState = (cb) => {
+    getUserInfo((res) => {
+        if (res && res.accessToken) {
+            userInfo.value = res;
+        } else {
+            userInfo.value = {};
+        }
+        cb && cb(res);
+    });
+};
+
+const showTransactions = () => {
+    router.push('/transactions')
+};
+
+// 点击提现
+const clickWithdraw = () => {
+    Report.reportLog({
+        pageSource: Report.pageSource.denetHomePage,
+        businessType: Report.businessType.buttonClick,
+        objectType: Report.objectType.withdrawButton
+    });
+    router.push('/withdraw/home');
+}
+
+const clickTopUp = () => {
+    Report.reportLog({
+        pageSource: Report.pageSource.denetHomePage,
+        businessType: Report.businessType.buttonClick,
+        objectType: Report.objectType.topupButton
+    });
+    router.push('/top-up/home');
+}
+
+const refreshList = () => {
+    if (iconRotate.value) {
+        return
+    }
+    iconRotate.value = true
+    setTimeout(() => {
+        iconRotate.value = false
+    }, 1000)
+
+    getAccountBalance();
+    if(currencyListDom.value) {
+        currencyListDom.value.getCurrencyInfoList && currencyListDom.value.getCurrencyInfoList();
+    }
+}
+
+const onMessage = () => {
+    chrome.runtime.onMessage.addListener(msgListener)
+}
+
+const msgListener = (req, sender, sendResponse) => {
+    sendResponse('');
+    switch (req.actionType) {
+        case 'CONTENT_POPUP_PAGE_SHOW':
+            init();
+            if(currencyListDom.value) {
+                currencyListDom.value.getCurrencyInfoList && currencyListDom.value.getCurrencyInfoList();
+            }
+            break;
+    }
+}
+
+
+onMounted(() => {
+    onMessage();
+    init();
+});
+
+onBeforeUnmount(() => {
+    chrome.runtime.onMessage.removeListener(msgListener);
+})
+
+</script>
+
+<style lang="scss" scoped>
+html,
+body {
+    padding: 0 !important;
+    margin: 0 !important;
+}
+
+.page-wrapper {
+    width: 375px;
+    height: 100%;
+    box-sizing: border-box;
+    overflow-y: auto;
+
+    .nav-bar {
+        padding: 14px;
+        box-sizing: border-box;
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+
+        .item {
+            display: flex;
+            align-items: center;
+            font-size: 13px;
+            cursor: pointer;
+
+            img {
+                width: 16px;
+                height: 16px;
+                margin-right: 4px;
+            }
+        }
+
+        .left {
+            font-weight: 500;
+        }
+
+        .right {
+            color: #b6b6b6;
+        }
+    }
+
+    .content {
+        padding: 12px 16px 10px 16px;
+        background: #1D9BF0;
+        box-sizing: border-box;
+
+        .icon-money {
+            width: 70px;
+            height: 70px;
+        }
+
+        .balance {
+            display: flex;
+            justify-content: space-between;
+            .wallet {
+                font {
+                    font-size: 13px;
+                    color: #fff;
+                    opacity: 0.7;
+                }
+            }
+        }
+
+        .amount-wrapper {
+            margin-top: 2px;
+            font-weight: 700;
+            font-size: 36px;
+            color: #fff;
+            display: flex;
+            align-items: center;
+            justify-content: space-between;
+
+            .amount {
+                display: inline-block;
+            }
+
+            .right {
+                display: flex;
+                align-items: center;
+
+                .bill {
+                    height: 24px;
+                    width: 24px;
+                    position: relative;
+
+                    img {
+                        width: 24px;
+                        height: 24px;
+                        cursor: pointer;
+                        position: absolute;
+                        left: 0;
+                        top: 0;
+                    }
+
+                    .red-dot {
+                        position: absolute;
+                        right: 0px;
+                        top: -1px;
+                        z-index: 100;
+                    }
+                }
+
+                .icon {
+                    margin-left: 22px;
+                    cursor: pointer;
+                }
+                .transform_rotate {
+                    transform: rotate(360deg);
+                    transition-duration: 1s;
+                }
+            }
+        }
+
+        .msg {
+            margin-top: 10px;
+            font-size: 13px;
+            color: #b6b6b6;
+        }
+    }
+
+
+
+}
+
+.page-wrapper::-webkit-scrollbar {
+    display: none;
+}
+</style>

+ 5 - 4
src/view/popup/top-up/home.vue

@@ -30,11 +30,12 @@ let showCurrencySelect = ref(false)
 let tempCurrentCurrencyList = ref([])
 
 function selectCurrency(params) {
-    tempCurrentCurrencyList.value = params;
-    if (params.length > 1) {
+    let { currencies } = params;
+    tempCurrentCurrencyList.value = currencies;
+    if (currencies.length > 1) {
         showCurrencySelect.value = true;
     } else {
-        selectCurrencyAfter(params[0])
+        selectCurrencyAfter(currencies[0])
     }
 }
 function selectCurrencyAfter(_params) {
@@ -74,7 +75,7 @@ onMounted(() => {
     bottom: 0;
     background-color: #fff;
     border-radius: 20px 20px 0 0;
-    overflow-y: scroll;
+    overflow-y: auto;
 }
 .selectBg {
     position: absolute;

+ 12 - 1
src/view/popup/transactions.vue

@@ -1,7 +1,7 @@
 <template>
     <!-- 公共组件 -->
     <div class="info">
-        <v-head :title="'Transactions'" :show_more="false" :back_url="'/'" @onBack="clickBack" ></v-head>
+        <v-head :title="'Transactions'" :show_more="false" :back_url="back_url" @onBack="clickBack" ></v-head>
         <popup-transactions style="height: calc(100% - 48px);"></popup-transactions>
     </div>
 
@@ -10,8 +10,19 @@
 <script setup>
 import VHead from '@/view/popup/components/head.vue'
 import PopupTransactions from "@/view/components/popup-transactions";
+import {ref, onMounted} from 'vue';
+import router from "@/router/popup.js";
 
+let back_url = ref('/');
 
+onMounted(() => {
+    let {params = '{}'} = router.currentRoute.value.query;
+    let {backUrl = '/'} =  JSON.parse(params);
+    
+    if(backUrl == 'back') {
+        back_url.value = '';
+    }
+})
 </script>
 
 

+ 5 - 4
src/view/popup/withdraw/home.vue

@@ -30,11 +30,12 @@ let showCurrencySelect = ref(false)
 let tempCurrentCurrencyList = ref([])
 
 function selectCurrency(params) {
-    tempCurrentCurrencyList.value = params;
-    if (params.length > 1) {
+    let { currencies } = params;
+    tempCurrentCurrencyList.value = currencies;
+    if (currencies.length > 1) {
         showCurrencySelect.value = true;
     } else {
-        selectCurrencyAfter(params[0])
+        selectCurrencyAfter(currencies[0])
     }
 }
 
@@ -84,7 +85,7 @@ onMounted(() => {
     bottom: 0;
     background-color: #fff;
     border-radius: 20px 20px 0 0;
-    overflow-y: scroll;
+    overflow-y: auto;
 }
 .selectBg {
     position: absolute;

+ 6 - 1
src/view/popup/withdraw/info.vue

@@ -1,7 +1,12 @@
 <template>
   <!-- 公共组件 -->
   <div class="info">
-    <v-head :title="'Withdraw'" :show_more="true"></v-head>
+    <v-head :title="'Withdraw'" 
+            :show_more="true" 
+            :show_help="true"  
+            :transactionsRouterParams="{
+              backUrl: 'back'
+            }"></v-head>
     <!-- 内容 -->
     <div class="content">
       <div class="area-input-1">

+ 1 - 1
src/view/popup/withdraw/success.vue

@@ -17,7 +17,7 @@ let withdraw_info = inject('withdraw_info')
 
 let router = useRouter()
 const onDone = () => {
-    router.replace('/withdraw/home')
+    router.replace('/')
 }
 
 </script>

部分文件因为文件数量过多而无法显示