nieyuge пре 2 година
родитељ
комит
db244ca94a

+ 181 - 5
package-lock.json

@@ -9,6 +9,52 @@
       "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.10.tgz",
       "integrity": "sha512-n2Q6i+fnJqzOaq2VkdXxy2TCPCWQZHiCo0XqmrCvDWcZQKRyZzYi4Z0yxlBuN0w+r2ZHmre+Q087DSrw3pbJDQ=="
     },
+    "@ctrl/tinycolor": {
+      "version": "3.4.1",
+      "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.4.1.tgz",
+      "integrity": "sha512-ej5oVy6lykXsvieQtqZxCOaLT+xD4+QNarq78cIYISHmZXshCvROLudpQN3lfL8G0NL7plMSSK+zlyvCaIJ4Iw=="
+    },
+    "@element-plus/icons-vue": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-2.0.6.tgz",
+      "integrity": "sha512-lPpG8hYkjL/Z97DH5Ei6w6o22Z4YdNglWCNYOPcB33JCF2A4wye6HFgSI7hEt9zdLyxlSpiqtgf9XcYU+m5mew=="
+    },
+    "@floating-ui/core": {
+      "version": "0.7.3",
+      "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-0.7.3.tgz",
+      "integrity": "sha512-buc8BXHmG9l82+OQXOFU3Kr2XQx9ys01U/Q9HMIrZ300iLc8HLMgh7dcCqgYzAzf4BkoQvDcXf5Y+CuEZ5JBYg=="
+    },
+    "@floating-ui/dom": {
+      "version": "0.5.4",
+      "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-0.5.4.tgz",
+      "integrity": "sha512-419BMceRLq0RrmTSDxn8hf9R3VCJv2K9PUfugh5JyEFmdjzDo+e8U5EdR8nzKq8Yj1htzLm3b6eQEEam3/rrtg==",
+      "requires": {
+        "@floating-ui/core": "^0.7.3"
+      }
+    },
+    "@popperjs/core": {
+      "version": "npm:@sxzz/popperjs-es@2.11.7",
+      "resolved": "https://registry.npmjs.org/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz",
+      "integrity": "sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ=="
+    },
+    "@types/lodash": {
+      "version": "4.14.182",
+      "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz",
+      "integrity": "sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q=="
+    },
+    "@types/lodash-es": {
+      "version": "4.17.6",
+      "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.6.tgz",
+      "integrity": "sha512-R+zTeVUKDdfoRxpAryaQNRKk3105Rrgx2CFRClIgRGaqDTdjsm8h6IYA8ir584W3ePzkZfst5xIgDwYrlh9HLg==",
+      "requires": {
+        "@types/lodash": "*"
+      }
+    },
+    "@types/web-bluetooth": {
+      "version": "0.0.14",
+      "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.14.tgz",
+      "integrity": "sha512-5d2RhCard1nQUC3aHcq/gHzWYO6K0WJmAbjO7mQJgCQKtZpgXxv1rOM6O/dBDhDYYVutk1sciOgNSe+5YyfM8A=="
+    },
     "@vitejs/plugin-vue": {
       "version": "2.3.3",
       "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-2.3.3.tgz",
@@ -160,6 +206,30 @@
       "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.33.tgz",
       "integrity": "sha512-UBc1Pg1T3yZ97vsA2ueER0F6GbJebLHYlEi4ou1H5YL4KWvMOOWwpYo9/QpWq93wxKG6Wo13IY74Hcn/f7c7Bg=="
     },
+    "@vueuse/core": {
+      "version": "8.9.2",
+      "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-8.9.2.tgz",
+      "integrity": "sha512-dE3/JgwqIHmmtmRBdZAnq87rZCSFbYVps2t3gWy9Jv/+Qp6sHSSKuPFtwguJVZ2OnaGnB/AMRmx4CuFRxFin3A==",
+      "requires": {
+        "@types/web-bluetooth": "^0.0.14",
+        "@vueuse/metadata": "8.9.2",
+        "@vueuse/shared": "8.9.2",
+        "vue-demi": "*"
+      }
+    },
+    "@vueuse/metadata": {
+      "version": "8.9.2",
+      "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-8.9.2.tgz",
+      "integrity": "sha512-g2s2BeyeEtJElmMFfFPnM+BTvnt0omniyvz8U18/zXDpQIMGozlNQgHoFeratyMfgVBhH/u2VKzmchChtDsgPQ=="
+    },
+    "@vueuse/shared": {
+      "version": "8.9.2",
+      "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-8.9.2.tgz",
+      "integrity": "sha512-s4Nk82oheL5z1GywyGnqjob0MzbAt88olMZa0vgt/p3gcMsT8Ff7+SqmNgEFC6AAs6xiuhOAZpnew9Zs3d90yQ==",
+      "requires": {
+        "vue-demi": "*"
+      }
+    },
     "accepts": {
       "version": "1.3.8",
       "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
@@ -181,6 +251,25 @@
       "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=",
       "dev": true
     },
+    "async-validator": {
+      "version": "4.2.5",
+      "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz",
+      "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg=="
+    },
+    "asynckit": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+      "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
+    },
+    "axios": {
+      "version": "0.27.2",
+      "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
+      "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
+      "requires": {
+        "follow-redirects": "^1.14.9",
+        "form-data": "^4.0.0"
+      }
+    },
     "body-parser": {
       "version": "1.20.0",
       "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz",
@@ -217,6 +306,14 @@
         "get-intrinsic": "^1.0.2"
       }
     },
+    "combined-stream": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+      "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+      "requires": {
+        "delayed-stream": "~1.0.0"
+      }
+    },
     "compressible": {
       "version": "2.0.18",
       "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz",
@@ -316,6 +413,11 @@
       "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.20.tgz",
       "integrity": "sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA=="
     },
+    "dayjs": {
+      "version": "1.11.3",
+      "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.3.tgz",
+      "integrity": "sha512-xxwlswWOlGhzgQ4TKzASQkUhqERI3egRNqgV4ScR8wlANA/A9tZ7miXa44vTTKEq5l7vWoL5G57bG3zA+Kow0A=="
+    },
     "debug": {
       "version": "2.6.9",
       "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
@@ -325,6 +427,11 @@
         "ms": "2.0.0"
       }
     },
+    "delayed-stream": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+      "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="
+    },
     "depd": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
@@ -343,6 +450,28 @@
       "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=",
       "dev": true
     },
+    "element-plus": {
+      "version": "2.2.9",
+      "resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.2.9.tgz",
+      "integrity": "sha512-jYbL0JkCdv95rkT6trZJjCAizLPySa0qcd2cgq+57SKQnCZAcNDDq4GbTuFRnNavdoeCJnuM3HIficTIUpsMOQ==",
+      "requires": {
+        "@ctrl/tinycolor": "^3.4.1",
+        "@element-plus/icons-vue": "^2.0.6",
+        "@floating-ui/dom": "^0.5.4",
+        "@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7",
+        "@types/lodash": "^4.14.182",
+        "@types/lodash-es": "^4.17.6",
+        "@vueuse/core": "^8.7.5",
+        "async-validator": "^4.2.5",
+        "dayjs": "^1.11.3",
+        "escape-html": "^1.0.3",
+        "lodash": "^4.17.21",
+        "lodash-es": "^4.17.21",
+        "lodash-unified": "^1.0.2",
+        "memoize-one": "^6.0.0",
+        "normalize-wheel-es": "^1.1.2"
+      }
+    },
     "encodeurl": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
@@ -530,8 +659,7 @@
     "escape-html": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
-      "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=",
-      "dev": true
+      "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
     },
     "estree-walker": {
       "version": "2.0.2",
@@ -598,6 +726,21 @@
         "unpipe": "~1.0.0"
       }
     },
+    "follow-redirects": {
+      "version": "1.15.1",
+      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz",
+      "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA=="
+    },
+    "form-data": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
+      "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
+      "requires": {
+        "asynckit": "^0.4.0",
+        "combined-stream": "^1.0.8",
+        "mime-types": "^2.1.12"
+      }
+    },
     "forwarded": {
       "version": "0.2.0",
       "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
@@ -718,6 +861,11 @@
       "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
       "dev": true
     },
+    "js-cookie": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.1.tgz",
+      "integrity": "sha512-+0rgsUXZu4ncpPxRL+lNEptWMOWl9etvPHc/koSRp6MPwpRYAhmk0dUG00J4bxVV3r9uUzfo24wW0knS07SKSw=="
+    },
     "klona": {
       "version": "2.0.5",
       "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.5.tgz",
@@ -751,6 +899,21 @@
         "klona": "^2.0.4"
       }
     },
+    "lodash": {
+      "version": "4.17.21",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+      "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
+    },
+    "lodash-es": {
+      "version": "4.17.21",
+      "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
+      "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
+    },
+    "lodash-unified": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/lodash-unified/-/lodash-unified-1.0.2.tgz",
+      "integrity": "sha512-OGbEy+1P+UT26CYi4opY4gebD8cWRDxAT6MAObIVQMiqYdxZr1g3QHWCToVsm31x2NkLS4K3+MC2qInaRMa39g=="
+    },
     "magic-string": {
       "version": "0.25.9",
       "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz",
@@ -776,6 +939,11 @@
       "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
       "dev": true
     },
+    "memoize-one": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz",
+      "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw=="
+    },
     "merge-descriptors": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
@@ -797,14 +965,12 @@
     "mime-db": {
       "version": "1.52.0",
       "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
-      "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
-      "dev": true
+      "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
     },
     "mime-types": {
       "version": "2.1.35",
       "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
       "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
-      "dev": true,
       "requires": {
         "mime-db": "1.52.0"
       }
@@ -857,6 +1023,11 @@
       "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
       "dev": true
     },
+    "normalize-wheel-es": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/normalize-wheel-es/-/normalize-wheel-es-1.1.2.tgz",
+      "integrity": "sha512-scX83plWJXYH1J4+BhAuIHadROzxX0UBF3+HuZNY2Ks8BciE7tSTQ+5JhTsvzjaO0/EJdm4JBGrfObKxFf3Png=="
+    },
     "object-inspect": {
       "version": "1.12.0",
       "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz",
@@ -1191,6 +1362,11 @@
         "@vue/shared": "3.2.33"
       }
     },
+    "vue-demi": {
+      "version": "0.13.4",
+      "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.4.tgz",
+      "integrity": "sha512-KP4lq9uSz0KZbaqCllRhnxMV3mYRsRWJfdsAhZyt5bV5O1RTpoeDptBRV9NOa/JgOpfaA9ane88VF7OjWNK/DA=="
+    },
     "vue-router": {
       "version": "4.0.15",
       "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.0.15.tgz",

+ 3 - 0
package.json

@@ -12,6 +12,9 @@
   },
   "dependencies": {
     "animate.css": "^4.1.1",
+    "axios": "^0.27.2",
+    "element-plus": "^2.2.9",
+    "js-cookie": "^3.0.1",
     "vue": "^3.2.25",
     "vue-router": "^4.0.15"
   },

+ 13 - 14
src/components/footer.vue

@@ -26,20 +26,19 @@
     </div>
 </template>
 
-<script>
-export default {
-    name: 'footerLayer',
-    methods: {
-        twitter () {
-            window.open(`https://twitter.com/denet2022`);
-        },
-        telegram () {
-            window.open(`https://t.me/denetpro`);
-        },
-        discord() {
-            window.open(`https://discord.gg/wZSz9p8ddG`);
-        }
-    }
+<script lang="ts" setup>
+import { postRequest } from '../static/http'
+
+const twitter = ()  => {
+    window.open(`https://twitter.com/denet2022`);
+}
+
+const telegram = () => {
+    window.open(`https://t.me/denetpro`);
+}
+
+const discord = () => {
+    window.open(`https://discord.gg/wZSz9p8ddG`);
 }
 </script>
 

+ 95 - 10
src/components/header.vue

@@ -1,20 +1,83 @@
 <template>
     <div class="header">
         <img class="logo" src="../static/img/logo.svg" alt="DeNet" />
-        <div class="down" @click="install">
-            <div class="text">Install</div>
+        <div class="operation">
+            <div class="login" @click="twitterAuth">
+                <img class="add" src="../static/img/header-add.svg" alt="">
+                <span>Create NFTs</span>
+            </div>
+            <div class="down" @click="install">
+                <div class="text">Install DeNet</div>
+            </div>
         </div>
     </div>
     <div class="header-place"></div>
 </template>
 
-<script>
-export default {
-    name: 'headerLayer',
-    methods: {
-        install () {
-            window.open(`https://chrome.google.com/webstore/detail/denet/inlfbeejfdgkknpiodhemfcokbdgofja`);
+<script lang="ts" setup>
+import Api from '../static/http/api'
+import { postRequest } from '../static/http'
+import { getMid, appVersionCode, getOauthUrl, createWindow } from '../static/utils'
+import { getStorage, removeStorage, setStorage, storageKey } from '../static/utils/storage'
+import { ref } from 'vue'
+import { useRouter } from 'vue-router'
+import { ElMessage } from 'element-plus'
+
+const timer = ref(0)
+
+const router = useRouter()
+
+const install =  () => {
+    window.open(`https://chrome.google.com/webstore/detail/denet/inlfbeejfdgkknpiodhemfcokbdgofja`);
+}
+
+const twitterAuth = () => {
+    postRequest(Api.twitterRequestToken, {
+        baseInfo: {
+            mid: getMid(),
+            appVersionCode,
+        },
+        params: {
+            oauthCallback: `https://denet.me/close`
         }
+    }).then(res => {
+        let { code, data, msg }  = res;
+        if ( code === 0 )  {
+            let url = getOauthUrl(data.authToken);
+            let win = createWindow(url);
+            timer.value = setInterval(() => {
+                if (win && win.closed) {
+                    clearInterval(timer.value);
+                    removeStorage(storageKey.verifier);
+                    twitterLogin(data);
+                }
+            }, 500)
+        } else {
+            ElMessage({ message: msg })
+        }
+    })
+}
+
+const twitterLogin = (data: { authToken: string, consumerKey: string }) => {
+    let verifier = getStorage(storageKey.verifier)
+    if (verifier) {
+        postRequest(Api.twitterLogin,  {
+            baseInfo: {
+                mid: getMid(),
+                appVersionCode,
+            },
+            params: {
+                consumerKey: data.consumerKey,
+                oauthToken: data.authToken,
+                oauthVerifier: verifier
+            }
+        }).then(res => {
+            let { code, data } = res;
+            if ( code === 0 ) {
+                setStorage(storageKey.userInfo, data);
+                router.push(`/nftList`)
+            }
+        })
     }
 }
 </script>
@@ -36,15 +99,37 @@ export default {
         height: 38px;
         margin-left: 26px;
     }
+    .operation {
+        display: flex;
+        flex-direction: row;
+    }
+    .login {
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        box-sizing: border-box;
+        height: 38px;
+        cursor: pointer;
+        padding: 0 18px;
+        font-size: 15px;
+        color: #1D9BF0;
+        margin-right: 19px;
+        border-radius: 20px;
+        border: solid 1px #1D9BF0;
+        .add {
+            width: 20px;
+            margin-right: 4px;
+        }
+    }
     .down {
         display: flex;
         align-items: center;
         justify-content: center;
-        width: 120px;
         height: 38px;
         cursor: pointer;
+        padding: 0 24px;
         margin-right: 26px;
-        border-radius: 100px;
+        border-radius: 20px;
         background: #1D9BF0;
         .text {
             color: #fff;

+ 3 - 0
src/main.ts

@@ -1,6 +1,8 @@
 import App from './App.vue'
 import { createSSRApp } from 'vue'
 import { createRouter } from './router'
+import ElementPlus from 'element-plus'
+import 'element-plus/dist/index.css'
 import 'animate.css';
 
 // SSR requires a fresh app instance per request, therefore we export a function
@@ -10,5 +12,6 @@ export function createApp() {
   const app = createSSRApp(App)
   const router = createRouter()
   app.use(router)
+  app.use(ElementPlus)
   return { app, router }
 }

+ 15 - 0
src/pages/close.vue

@@ -0,0 +1,15 @@
+<script lang="ts" setup>
+import { onMounted } from 'vue';
+import { setStorage, storageKey } from '../static/utils/storage'
+
+onMounted(() => {
+    let url = new URL(window.location.href);
+    let search = url.search;
+    let urlParams  = new URLSearchParams(search);
+    let verifier: any = urlParams.get('oauth_verifier');
+    // set
+    setStorage(storageKey.verifier, verifier)
+    // close
+    window.close()
+})
+</script>

+ 4 - 0
src/router.ts

@@ -13,6 +13,10 @@ export function createRouter() {
             name: 'home',
             path: '/',
             component: () => import('./pages/index.vue')
+        }, {
+            name: 'close',
+            path: '/close',
+            component: () => import('./pages/close.vue')
         }]
     })
 }

+ 4 - 0
src/static/http/api.ts

@@ -0,0 +1,4 @@
+export default {
+    'twitterLogin' : '/denet/user/twitterLogin',
+    'twitterRequestToken' : '/denet/user/twitterRequestToken',
+}

+ 48 - 0
src/static/http/index.ts

@@ -0,0 +1,48 @@
+// http封装库
+import { getEnvConfig } from '../utils';
+import axios from 'axios';
+
+// axios config
+const { host } = getEnvConfig();
+const instance = axios.create({
+    baseURL: host,
+    timeout: 240000,
+    headers: {
+        'content-type': 'application/json',
+        'Accept': 'application/json',
+    }
+});
+
+// 响应拦截器
+instance.interceptors.response.use((res) => {
+    return res.data;
+}, function (err) {
+    return Promise.reject(err);
+});
+
+export const postRequest = (url: string, params = {}, config = null) => {
+    const myConfig = {};
+    if (config) {
+        Object.assign(myConfig, config);
+    }
+    params = Object.assign({}, params);
+
+    return instance.post(url, params, myConfig).then(res => {
+        return res;
+    }).catch(err => {
+        return err;
+    });
+}
+
+export const getRequest = (url: string, params = {}, config = null) => {
+    const myConfig = Object.assign({}, { params: Object.assign({}, params) });
+    if (config) {
+        Object.assign(myConfig, config);
+    }
+
+    return instance.get(url, myConfig).then(res => {
+        return res;
+    }).catch(err => {
+        return err;
+    });
+}

+ 3 - 0
src/static/img/header-add.svg

@@ -0,0 +1,3 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M15.4857 9.28571H10.7143V4.51429C10.7143 4.12954 10.3847 3.8 10 3.8C9.61526 3.8 9.28571 4.12954 9.28571 4.51429V9.28571H4.51429C4.12954 9.28571 3.8 9.61526 3.8 10C3.8 10.3847 4.12954 10.7143 4.51429 10.7143H9.28571V15.4857C9.28571 15.8705 9.61526 16.2 10 16.2C10.3847 16.2 10.7143 15.8705 10.7143 15.4857V10.7143H15.4857C15.8705 10.7143 16.2 10.3847 16.2 10C16.2 9.61526 15.8705 9.28571 15.4857 9.28571Z" fill="#1D9BF0" stroke="#1D9BF0" stroke-width="0.4"/>
+</svg>

+ 75 - 0
src/static/utils/index.ts

@@ -0,0 +1,75 @@
+// @ts-ignore
+import Cookie from 'js-cookie';
+
+export const appVersionCode = 12;
+export const appType = 1;
+
+// 获取host
+export const getEnvConfig = () => {
+    let host
+
+    // @ts-ignore
+    switch(process.env.NODE_ENV) {
+        case `production`:
+            host = `https://api.denetme.net`
+            break;
+        case `pre`:
+            host = `https://preapi.denetme.net`
+            break;
+        default:
+            host = `https://testapi.denetme.net`
+            break;
+    }
+
+    return {
+        host
+    };
+}
+
+// 获取mid
+export const getMid = () => {
+    let _mid;
+    let _cookie_mid_arr = Cookie.get('mid') || []
+    if (_cookie_mid_arr.length > 0) {
+        _mid = JSON.parse(_cookie_mid_arr)[0].mid
+    } else {
+        _mid = guid()
+        Cookie.set('mid', JSON.stringify([{ mid: _mid }]), { expires: 1000 })
+    }
+    return _mid;
+}
+
+// 推特授权url
+export const getOauthUrl = (token: string) => {
+    return `https://api.twitter.com/oauth/authenticate?oauth_token=${token}`
+}
+
+// 创建窗口
+export const createWindow = (url: string, w: number = 400, h: number = 600) => {
+    var left = Math.round((window.screen.availWidth - w) / 2);
+    var top = Math.round((window.screen.availHeight - 100 - h) / 2);
+    var win = window.open(url, `newWin`, `width=${w}, height=${h}, top=${top}, left=${left}, toolbar=no, menubar=no, scrollbars=no, resizable=no, location=no, status=no`);
+    return win;
+}
+
+
+// 帮助函数
+const guid = () => {
+    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
+        var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
+        return v.toString(16);
+    });
+}
+
+// 获取cookie
+export const getCookie = (name: string) => {
+    if (name)  {
+        let getVal = Cookie.get(name)
+        return getVal
+    }
+}
+
+// 设置cookie
+export const setCookie = (name: string, val: any) => {
+    Cookie.set(name, JSON.stringify(val), { expires: 1000 })
+}

+ 19 - 0
src/static/utils/storage.ts

@@ -0,0 +1,19 @@
+// 获取storage
+export const getStorage = (name: string) => {
+    return localStorage.getItem(name)
+}
+
+// 设置storage
+export const setStorage = (name: string, val: any) => {
+    localStorage.setItem(name, val)
+}
+
+// 删除storage
+export const removeStorage = (name: string) => {
+    localStorage.removeItem(name)
+}
+
+export const storageKey = {
+    verifier: 'verifierKey',
+    userInfo: 'userInfoKey',
+}