Browse Source

添加双向认证

lex 9 months ago
parent
commit
bcca0bb8ef

+ 2 - 1
components.d.ts

@@ -1,6 +1,6 @@
 // generated by unplugin-vue-components
 // We suggest you to commit this file into source control
-// Read more: https://github.com/vuejs/vue-next/pull/3399
+// Read more: https://github.com/vuejs/core/pull/3399
 import '@vue/runtime-core'
 
 declare module '@vue/runtime-core' {
@@ -9,6 +9,7 @@ declare module '@vue/runtime-core' {
     Pagination: typeof import('./src/components/pagination/index.vue')['default']
     RouterLink: typeof import('vue-router')['RouterLink']
     RouterView: typeof import('vue-router')['RouterView']
+    TheAuth: typeof import('./src/components/TheAuth/index.vue')['default']
   }
 }
 

+ 11 - 0
package-lock.json

@@ -24,6 +24,7 @@
         "cropperjs": "^1.5.12",
         "dayjs": "^1.10.7",
         "element-plus": "^2.2.5",
+        "eventemitter3": "^5.0.1",
         "html-to-image": "^1.9.0",
         "js-cookie": "^3.0.1",
         "loaders.css": "^0.1.2",
@@ -6176,6 +6177,11 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/eventemitter3": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmmirror.com/eventemitter3/-/eventemitter3-5.0.1.tgz",
+      "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA=="
+    },
     "node_modules/execa": {
       "version": "0.8.0",
       "resolved": "https://registry.npmmirror.com/execa/-/execa-0.8.0.tgz",
@@ -15475,6 +15481,11 @@
       "resolved": "https://registry.npmmirror.com/esutils/-/esutils-2.0.3.tgz",
       "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="
     },
+    "eventemitter3": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmmirror.com/eventemitter3/-/eventemitter3-5.0.1.tgz",
+      "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA=="
+    },
     "execa": {
       "version": "0.8.0",
       "resolved": "https://registry.npmmirror.com/execa/-/execa-0.8.0.tgz",

+ 1 - 0
package.json

@@ -36,6 +36,7 @@
     "cropperjs": "^1.5.12",
     "dayjs": "^1.10.7",
     "element-plus": "^2.2.5",
+    "eventemitter3": "^5.0.1",
     "html-to-image": "^1.9.0",
     "js-cookie": "^3.0.1",
     "loaders.css": "^0.1.2",

BIN
src/components/TheAuth/images/auth-title-bg.png


BIN
src/components/TheAuth/images/btn-done.png


BIN
src/components/TheAuth/images/btn-down.png


BIN
src/components/TheAuth/images/btn-up.png


BIN
src/components/TheAuth/images/downlowdCert.png


BIN
src/components/TheAuth/images/icon-close.png


BIN
src/components/TheAuth/images/mac/1.png


BIN
src/components/TheAuth/images/mac/2.png


BIN
src/components/TheAuth/images/mac/3.png


BIN
src/components/TheAuth/images/mac/4.png


BIN
src/components/TheAuth/images/mac/5.png


BIN
src/components/TheAuth/images/mac/6.png


BIN
src/components/TheAuth/images/window/1.png


BIN
src/components/TheAuth/images/window/2.png


BIN
src/components/TheAuth/images/window/3.png


BIN
src/components/TheAuth/images/window/4.png


BIN
src/components/TheAuth/images/window/5.png


BIN
src/components/TheAuth/images/window/6.png


BIN
src/components/TheAuth/images/window/7.png


BIN
src/components/TheAuth/images/window/8.png


+ 530 - 0
src/components/TheAuth/index.vue

@@ -0,0 +1,530 @@
+<template>
+  <div class="theAuth">
+    <div class="theTitle"></div>
+    <!-- {/* <i class={styles.iconClose} onClick={() => emit('close')}></i> */} -->
+    <div class="authContent">
+      <div class="steps">
+        <div class="scrollbarRef">
+          <div v-if="brower.ios">
+            <div v-if="step === 1">
+              <div class="step">
+                <div class="stepNum">01</div>
+                <div class="stepContent">
+                  <p class="txt">
+                    点击下方【下载证书】按钮,下载数据安全证书安装包
+                  </p>
+
+                  <div>
+                    <div class="downloadCert" @click="onDownload"></div>
+                  </div>
+                </div>
+              </div>
+
+              <div class="step">
+                <div class="stepNum">02</div>
+                <div class="stepContent">
+                  <p class="txt">
+                    双击<span>《安全证书.p12》</span>
+                    ,输入钥匙串密码 ,点击
+                    <span>【修改钥匙串】</span>
+                    <span style="color: #777"> (若无此步骤则忽略) </span>
+                  </p>
+                  <div class="imgs imgs2">
+                    <img src="./images/mac/1.png" class="m1" />
+                    <img src="./images/mac/6.png" class="m6" />
+                  </div>
+                </div>
+              </div>
+            </div>
+
+            <div class="step" v-if="step === 2">
+              <div class="stepNum">03</div>
+              <div class="stepContent">
+                <p class="txt">
+                  输入证书密码:
+                  <span class="red" style="text-decoration: underline">
+                    colexiu.com</span
+                  >
+                  ,点击
+                  <span>【好】</span>
+                </p>
+
+                <div class="imgs">
+                  <img src="./images/mac/2.png" class="m2" />
+                </div>
+              </div>
+            </div>
+
+            <div class="step" v-if="step === 3">
+              <div class="stepNum">04</div>
+              <div class="stepContent">
+                <p class="txt">
+                  <span class="red">重启浏览器</span>
+                  (在电脑屏幕左上方选择当前浏览器并点击
+                  <span>【退出】</span>),再重新打开酷乐秀官网
+                </p>
+                <div class="imgs">
+                  <img src="./images/mac/3.png" class="m3" />
+                </div>
+              </div>
+            </div>
+
+            <div class="step" v-if="step === 4">
+              <div class="stepNum">05</div>
+              <div class="stepContent">
+                <p class="txt">
+                  在【选择证书】弹窗中点击<span>【确定】</span>按钮
+                </p>
+                <div class="imgs">
+                  <img src="./images/mac/4.png" class="m4" />
+                </div>
+              </div>
+            </div>
+
+            <div v-if="step === 5">
+              <div class="step">
+                <div class="stepNum">06</div>
+                <div class="stepContent">
+                  <p class="txt">
+                    输入您的电脑密码,点击<span>【始终允许】</span>
+                    <span style="color: #777"> (若无此步骤则忽略) </span>
+                  </p>
+                  <div class="imgs">
+                    <img src="./images/mac/5.png" class="m5" />
+                  </div>
+                </div>
+              </div>
+              <div class="step">
+                <div class="stepNum">07</div>
+                <div class="stepContent">
+                  <p class="txt">证书安装完成,开始使用酷乐秀官网</p>
+                </div>
+              </div>
+            </div>
+          </div>
+
+          <div v-else>
+            <div v-if="step === 1">
+              <div class="step">
+                <div class="stepNum">01</div>
+                <div class="stepContent">
+                  <p class="txt">
+                    点击下方【下载证书】按钮,下载数据安全证书安装包
+                  </p>
+                  <div>
+                    <div class="downloadCert" @click="onDownload"></div>
+                  </div>
+                </div>
+              </div>
+              <div class="step">
+                <div class="stepNum">02</div>
+                <div class="stepContent">
+                  <p class="txt">
+                    双击<span>《安全证书.pfx》</span>,出现弹窗后点击
+                    <span>【下一步】</span>
+                  </p>
+                  <div class="imgs imgs2">
+                    <img src="./images/window/1.png" class="w1" />
+                    <img src="./images/window/2.png" class="w2" />
+                  </div>
+                </div>
+              </div>
+            </div>
+
+            <div class="step" v-if="step === 2">
+              <div class="stepNum">03</div>
+              <div class="stepContent">
+                <p class="txt">点击<span>【下一步】</span></p>
+                <div class="imgs">
+                  <img src="./images/window/3.png" class="w3" />
+                </div>
+              </div>
+            </div>
+
+            <div class="step" v-if="step === 3">
+              <div class="stepNum">04</div>
+              <div class="stepContent">
+                <p class="txt">点击<span>【下一步】</span></p>
+                <div class="imgs">
+                  <img src="./images/window/4.png" class="w4" />
+                </div>
+              </div>
+            </div>
+
+            <div class="step" v-if="step === 4">
+              <div class="stepNum">05</div>
+              <div class="stepContent">
+                <p class="txt">点击<span>【下一步】</span></p>
+                <div class="imgs">
+                  <img src="./images/window/8.png" class="w8" />
+                </div>
+              </div>
+            </div>
+
+            <div class="step" v-if="step === 5">
+              <div class="stepNum">06</div>
+              <div class="stepContent">
+                <p class="txt">点击<span>【完成】</span></p>
+                <div class="imgs">
+                  <img src="./images/window/5.png" class="w5" />
+                </div>
+              </div>
+            </div>
+
+            <div class="step" v-if="step === 6">
+              <div class="stepNum">07</div>
+              <div class="stepContent">
+                <p class="txt">点击<span>【确定】</span></p>
+                <div class="imgs">
+                  <img src="./images/window/6.png" class="w6" />
+                </div>
+              </div>
+            </div>
+
+            <div v-if="step === 7">
+              <div class="step">
+                <div class="stepNum">08</div>
+                <div class="stepContent">
+                  <p class="txt">
+                    <span class="red">重启浏览器</span>
+                    ,打开酷乐秀官网
+                  </p>
+                </div>
+              </div>
+
+              <div class="step">
+                <div class="stepNum">09</div>
+                <div class="stepContent">
+                  <p class="txt">
+                    在【选择证书】弹窗中点击<span>【确定】</span>
+                    按钮,证书安装完成,开始使用酷乐秀官网
+                  </p>
+                  <img src="./images/window/7.png" class="w7" />
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+
+      <div class="btnGroup">
+        <div
+          v-if="step > 1"
+          class="btn btnUp"
+          :style="{ cursor: step <= 1 ? 'not-allowed' : 'pointer' }"
+          @click="changeUpDown('up')"
+        ></div>
+        <div
+          :class="['btn', 'btnDown', step === maxStep && 'btnDone']"
+          @click="changeUpDown('down')"
+        ></div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script lang="ts">
+import { defineComponent, reactive, toRefs } from 'vue'
+
+import { browser } from '@/helpers/utils'
+export default defineComponent({
+  name: 'the-auth',
+  emits: ['close'],
+  setup(props, { emit }) {
+    const state = reactive({
+      brower: browser() || {},
+      step: 1,
+      maxStep: browser().ios ? 5 : 7
+    })
+    const changeUpDown = (type: string) => {
+      if (type === 'up') {
+        if (state.step <= 1) return
+        state.step -= 1
+      } else if (type === 'down') {
+        if (state.step >= state.maxStep) {
+          // state.$listeners.close()
+          emit('close')
+        } else {
+          state.step += 1
+        }
+      }
+      ;(document.querySelector('.scrollbarRef') as any).scrollTo(0, 0)
+    }
+    const onDownload = () => {
+      const isMac = (function () {
+        return /macintosh|mac os x/i.test(navigator.userAgent)
+      })()
+      if (isMac) {
+        window.open(
+          `https://oss.dayaedu.com/https-ssl/klx/安全证书.p12?v=${new Date().getTime()}`
+        )
+      } else {
+        window.open('https://oss.dayaedu.com/https-ssl/安全证书.pfx')
+      }
+    }
+
+    return {
+      ...toRefs(state),
+      changeUpDown,
+      onDownload
+    }
+  }
+})
+</script>
+
+<style lang="less" scoped>
+.theAuth {
+  // background-color: #fff;
+  width: 724px;
+  padding-top: 130px;
+  box-shadow: none;
+  position: relative;
+  // overflow: hidden;
+
+  .iconClose {
+    position: absolute;
+    right: 38px;
+    top: 118px;
+    width: 16px;
+    height: 16px;
+    background: url('./images/icon-close.png') no-repeat center;
+    background-size: contain;
+    cursor: pointer;
+  }
+}
+
+.theTitle {
+  position: absolute;
+  top: 0;
+  left: 0;
+  background: url('./images/auth-title-bg.png') top center no-repeat;
+  background-size: 100%;
+  width: 100%;
+  height: 142px;
+}
+
+.authContent {
+  // background: linear-gradient(180deg, #e1f8ff 0%, #bbe7fd 100%);
+  background: linear-gradient(180deg, #d3ede8 0%, #cff5fa 100%);
+  border-radius: 0 0 23px 23px;
+  padding-top: 8px;
+}
+
+.steps {
+  margin: 11px 27px 0;
+  padding-top: 12px;
+
+  background: linear-gradient(
+    180deg,
+    rgba(255, 255, 255, 0.7) 0%,
+    rgba(255, 255, 255, 0.7) 88%,
+    #c0e7eb 100%
+  );
+  border-radius: 18px;
+  border: 1px solid #ffffff;
+
+  .scrollbarRef {
+    margin: 0 0 25px;
+    padding: 14px 25px 25px;
+    min-height: calc(55vh - 28px);
+    max-height: calc(55vh - 28px);
+    overflow-x: hidden;
+    overflow-y: auto;
+
+    &::-webkit-scrollbar {
+      display: none;
+    }
+  }
+}
+
+.step {
+  display: flex;
+  align-items: flex-start;
+  padding-bottom: 35px;
+
+  .stepNum {
+    width: 33px;
+    height: 33px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    text-align: center;
+    background: #c1ece8;
+    border: 1px solid #ffffff;
+    font-size: 14px;
+    font-weight: 600;
+    color: #131415;
+    border-radius: 50%;
+    margin-right: 14px;
+    flex-shrink: 0;
+  }
+
+  .stepContent {
+    .txt {
+      font-size: 14px;
+      font-family: PingFangSC, PingFang SC;
+      font-weight: 600;
+      color: #000000;
+      line-height: 33px;
+
+      span {
+        color: #14928a;
+      }
+
+      .red {
+        color: #e80000;
+      }
+    }
+  }
+
+  .downloadCert {
+    margin-top: 14px;
+    width: 165px;
+    height: 39px;
+    background: url('./images/downlowdCert.png') no-repeat center;
+    background-size: contain;
+    border-radius: 50px;
+    cursor: pointer;
+  }
+
+  .imgs2 {
+    display: flex;
+    align-items: flex-start;
+    padding-top: 12px;
+
+    .m6,
+    .w2 {
+      margin-left: 38px;
+    }
+  }
+
+  img {
+    border-radius: 2px;
+  }
+
+  .w1 {
+    width: 90px;
+    height: 98px;
+  }
+
+  .w2 {
+    width: 250px;
+    height: 258px;
+  }
+
+  .w3,
+  .w4,
+  .w5,
+  .w8 {
+    margin-top: 12px;
+    width: 313px;
+    height: 322px;
+  }
+
+  .w6 {
+    margin-top: 12px;
+    width: 196px;
+    height: 207px;
+  }
+
+  .w7 {
+    margin-top: 8px;
+    width: 96%;
+  }
+
+  .m1 {
+    width: 73px;
+    height: 80px;
+  }
+
+  .m6 {
+    width: 263px;
+  }
+
+  .m3 {
+    margin-top: 8px;
+    width: 358px;
+  }
+
+  .m2,
+  .m4,
+  .m5 {
+    margin-top: 8px;
+    width: 100%;
+  }
+
+  .m2 {
+    width: 90%;
+  }
+
+  .moreImg {
+    display: flex;
+    align-items: center;
+    flex-wrap: wrap;
+
+    img {
+      width: 47%;
+      margin-bottom: 32px;
+
+      &:nth-child(2n + 2) {
+        margin-left: 6%;
+      }
+    }
+  }
+}
+
+.btnGroup {
+  padding: 25px 0;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+
+  // :global {
+  //   .n-button {
+  //     height: 37px !important;
+  //     width: 223px !important;
+  //     --n-border: none !important;
+  //     --n-border-hover: none !important;
+  //     --n-border-pressed: none !important;
+  //     --n-border-focus: none !important;
+  //     background: linear-gradient(305deg, #15BBFF 0%, #1784FF 100%);
+  //     border-radius: 22px;
+  //     font-size: 15Px;
+  //     font-family: AlimamaShuHeiTi, AlimamaShuHeiTi;
+  //     font-weight: bold;
+  //     color: #FFFFFF;
+  //     line-height: 22px;
+  //     letter-spacing: 1px;
+  //   }
+  // }
+  .btn {
+    width: 165px;
+    height: 39px;
+    cursor: pointer;
+    transition: opacity 0.2s ease;
+    &:hover {
+      opacity: 0.8;
+      transition: opacity 0.2s ease;
+    }
+
+    + .btn {
+      margin-left: 16px;
+    }
+  }
+
+  .btnUp {
+    background: url('./images/btn-up.png') no-repeat center center;
+    background-size: contain;
+  }
+
+  .btnDown {
+    background: url('./images/btn-down.png') no-repeat center center;
+    background-size: contain;
+  }
+
+  .btnDone {
+    background: url('./images/btn-done.png') no-repeat center center;
+    background-size: contain;
+  }
+}
+</style>

+ 7 - 2
src/helpers/request.ts

@@ -1,6 +1,6 @@
 import { extend } from 'umi-request'
 import cleanDeep from 'clean-deep'
-import { browser, getAuth, removeAuth } from '@/helpers/utils'
+import { browser, eventGlobal, getAuth, removeAuth } from '@/helpers/utils'
 import { postMessage } from './native-message'
 import { ElMessage } from 'element-plus'
 
@@ -66,7 +66,12 @@ request.interceptors.response.use(
   async res => {
     if (res.status > 299 || res.status < 200) {
       const msg = '服务器错误,状态码' + res.status
-      ElMessage.error(msg)
+      // 判断是否有资源需要证书,不提示错误信息
+      if (res.status === 511) {
+        eventGlobal.emit('auth-not-installed');
+      } else {
+        ElMessage.error(msg)
+      }
       throw new Error(msg)
     }
     const data = await res.clone().json()

+ 6 - 1
src/helpers/utils.ts

@@ -3,7 +3,12 @@ import numeral from 'numeral'
 import Cookies from 'js-cookie'
 import { state as helpState } from './helpState'
 import mitt from '@/helpers/mitt'
-import { platform } from 'os'
+// import { platform } from 'os'
+import EventEmitter from 'eventemitter3';
+
+export const eventGlobal = new EventEmitter();
+
+
 export const browser = () => {
   const u = navigator.userAgent
   //   app = navigator.appVersion;

+ 1 - 0
src/state.ts

@@ -9,6 +9,7 @@ export const state = reactive({
     data: {} as any
   },
   openLiveStatus: false,
+  authVisibleShow: false, // 授权搜索徐跑完图
   loginPopupStatus: false, // 登录弹窗状态
   loginPopupTimer: null as any // 登录弹窗定时器
 })

+ 32 - 9
src/style/index.css

@@ -4,14 +4,14 @@
 @tailwind utilities;
 
 :root {
-  --el-color-primary: #2DC7AA !important;
-  --el-color-primary-light-3: #2DC7AF !important;
-  --el-color-primary-light-5: #2FD8AC !important;
-  --el-color-primary-light-7: #2FD8AC !important;
+  --el-color-primary: #2dc7aa !important;
+  --el-color-primary-light-3: #2dc7af !important;
+  --el-color-primary-light-5: #2fd8ac !important;
+  --el-color-primary-light-7: #2fd8ac !important;
   --el-color-primary-light-8: #bbffef !important;
   --el-color-primary-light-9: #ecf9f6 !important;
   --el-color-primary-dark-2: #24ad93 !important;
-  --searchbgColor:'#f6f7f8' !important;
+  --searchbgColor: '#f6f7f8' !important;
   --el-border-radius-round: 999px !important;
   --el-border-radius-base: 10px !important;
 }
@@ -21,11 +21,11 @@ html {
 }
 
 body {
-  background: #F6F7F8;
+  background: #f6f7f8;
 }
 
-.user-shadow {  
-  box-shadow: 0px 2px 10px 0px rgba(0,0,0,0.1000);
+.user-shadow {
+  box-shadow: 0px 2px 10px 0px rgba(0, 0, 0, 0.1);
 }
 
 ::-webkit-scrollbar {
@@ -48,4 +48,27 @@ body {
 
 .el-input.is-disabled .el-input__inner {
   color: #606266 !important;
-}
+}
+
+.theAuthDialog {
+  background-color: transparent !important;
+  box-shadow: none !important;
+  border-radius: 0 !important;
+  margin: auto !important;
+  height: 100%;
+  display: flex;
+  align-items: center;
+}
+.theAuthDialog .el-dialog__header {
+  display: none !important;
+}
+
+.theAuthDialog .el-dialog__footer {
+  display: none !important;
+}
+
+.el-overlay .el-overlay-dialog .el-dialog.theAuthDialog .el-dialog__body {
+  padding: 0 !important;
+  max-height: 100% !important;
+  overflow: hidden;
+}

+ 5 - 1
src/views/App.module.less

@@ -6,20 +6,24 @@
       --el-dialog-border-radius: 10px !important;
       --el-dialog-bg-color: transparent !important;
     }
+
     .el-dialog__header,
     .el-dialog__body {
       padding: 0;
     }
   }
 }
+
 :global {
   .el-message-box {
     border-radius: 10px !important;
   }
 }
+
 :global {
   @import url('element-plus/dist/index.css');
 }
+
 :root {
   --theme-color: #2dc7aa;
-}
+}

+ 29 - 0
src/views/App.tsx

@@ -1,5 +1,6 @@
 import ColFooter from '@/components/col-footer'
 import ColHeader from '@/components/col-header'
+import TheAuth from '@/components/TheAuth/index.vue'
 import { ElConfigProvider, ElDialog } from 'element-plus'
 import { zhCn } from '@/helpers/zhCn'
 import { defineComponent } from 'vue'
@@ -14,6 +15,7 @@ import 'normalize.css'
 import 'element-plus/dist/index.css'
 import 'vue3-lottie/dist/style.css'
 import { useSubjectClearly } from '@/helpers/hooks'
+import { eventGlobal } from '@/helpers/utils'
 
 export default defineComponent({
   components: { silder },
@@ -31,6 +33,10 @@ export default defineComponent({
     // console.log('user end')
   },
   render() {
+    // 判断是否显示证书提示
+    eventGlobal.on('auth-not-installed', () => {
+      state.authVisibleShow = true
+    })
     return (
       <>
         {/* 263.5 footer, 70 header */}
@@ -65,6 +71,29 @@ export default defineComponent({
             )}
           </ElDialog>
         </div>
+        {/* <el-dialog
+      v-model="authVisibleShow"
+      width="724px"
+      :show-close="false"
+      :destroy-on-close="true"
+      :close-on-press-escape="false"
+      custom-class="theAuthDialog"
+      class="theAuthDialog"
+    >
+      <TheAuth @close="authVisibleShow = false" />
+    </el-dialog> */}
+        <ElDialog
+          modelValue={state.authVisibleShow}
+          onUpdate:modelValue={val => (state.authVisibleShow = val)}
+          showClose={false}
+          destroyOnClose={true}
+          closeOnPressEscape={false}
+          closeOnClickModal={false}
+          custom-class="theAuthDialog"
+          class="theAuthDialog"
+        >
+          <TheAuth onClose={() => (state.authVisibleShow = false)} />
+        </ElDialog>
       </>
     )
   }

+ 5 - 0
yarn.lock

@@ -3137,6 +3137,11 @@
   "resolved" "https://registry.npmmirror.com/esutils/-/esutils-2.0.3.tgz"
   "version" "2.0.3"
 
+"eventemitter3@^5.0.1":
+  "integrity" "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA=="
+  "resolved" "https://registry.npmmirror.com/eventemitter3/-/eventemitter3-5.0.1.tgz"
+  "version" "5.0.1"
+
 "execa@^0.8.0":
   "integrity" "sha512-zDWS+Rb1E8BlqqhALSt9kUhss8Qq4nN3iof3gsOdyINksElaPyNBtKUMTR62qhvgVWR0CqCX7sdnKe4MnUbFEA=="
   "resolved" "https://registry.npmmirror.com/execa/-/execa-0.8.0.tgz"