浏览代码

feat: 新增 plugin-auth 登录弹窗插件,window新增 jyCoreSDK

zhangyuhan 1 年之前
父节点
当前提交
a5fa356041
共有 77 个文件被更改,包括 10332 次插入0 次删除
  1. 6 0
      plugins/login-auth/.env.development
  2. 6 0
      plugins/login-auth/.env.external
  3. 6 0
      plugins/login-auth/.env.internal
  4. 6 0
      plugins/login-auth/.env.production
  5. 97 0
      plugins/login-auth/README.md
  6. 83 0
      plugins/login-auth/example/index.html
  7. 83 0
      plugins/login-auth/index.html
  8. 58 0
      plugins/login-auth/package.json
  9. 51 0
      plugins/login-auth/src/App.vue
  10. 24 0
      plugins/login-auth/src/api/form.js
  11. 2 0
      plugins/login-auth/src/api/index.js
  12. 56 0
      plugins/login-auth/src/api/login.js
  13. 5 0
      plugins/login-auth/src/api/service.js
  14. 二进制
      plugins/login-auth/src/assets/icon/back.png
  15. 二进制
      plugins/login-auth/src/assets/icon/blue-back.png
  16. 二进制
      plugins/login-auth/src/assets/icon/close.png
  17. 二进制
      plugins/login-auth/src/assets/icon/icon-biyan.png
  18. 二进制
      plugins/login-auth/src/assets/icon/icon-company.png
  19. 二进制
      plugins/login-auth/src/assets/icon/icon-email.png
  20. 二进制
      plugins/login-auth/src/assets/icon/icon-guard.png
  21. 二进制
      plugins/login-auth/src/assets/icon/icon-pass.png
  22. 二进制
      plugins/login-auth/src/assets/icon/icon-phone.png
  23. 二进制
      plugins/login-auth/src/assets/icon/icon-see.png
  24. 二进制
      plugins/login-auth/src/assets/icon/select.png
  25. 二进制
      plugins/login-auth/src/assets/icon/success.png
  26. 二进制
      plugins/login-auth/src/assets/icon/test.png
  27. 二进制
      plugins/login-auth/src/assets/icon/tip-active.png
  28. 二进制
      plugins/login-auth/src/assets/icon/tip.png
  29. 二进制
      plugins/login-auth/src/assets/icon/wx.png
  30. 216 0
      plugins/login-auth/src/auto-imports.d.ts
  31. 20 0
      plugins/login-auth/src/components.d.ts
  32. 102 0
      plugins/login-auth/src/components/form/autoCompleteInput.vue
  33. 132 0
      plugins/login-auth/src/components/form/baseForm.vue
  34. 153 0
      plugins/login-auth/src/components/form/baseInput.vue
  35. 28 0
      plugins/login-auth/src/components/form/imgCaptchaInput.vue
  36. 6 0
      plugins/login-auth/src/components/form/passInput.vue
  37. 46 0
      plugins/login-auth/src/components/form/smsCaptchaInput.vue
  38. 43 0
      plugins/login-auth/src/components/toast/Toast.vue
  39. 57 0
      plugins/login-auth/src/components/toast/index.js
  40. 12 0
      plugins/login-auth/src/data/constant.ts
  41. 19 0
      plugins/login-auth/src/lib/core.ts
  42. 31 0
      plugins/login-auth/src/lib/main.ts
  43. 6 0
      plugins/login-auth/src/lib/module/bind-phone.ts
  44. 20 0
      plugins/login-auth/src/lib/module/common.ts
  45. 149 0
      plugins/login-auth/src/lib/module/index.ts
  46. 33 0
      plugins/login-auth/src/lib/module/poll.ts
  47. 247 0
      plugins/login-auth/src/lib/pluginLogin.ts
  48. 45 0
      plugins/login-auth/src/lib/pluginLoginAuth.ts
  49. 4 0
      plugins/login-auth/src/lib/pre-hook.ts
  50. 1 0
      plugins/login-auth/src/main.ts
  51. 30 0
      plugins/login-auth/src/module-model/autoLogin.ts
  52. 111 0
      plugins/login-auth/src/module-model/countDown.ts
  53. 15 0
      plugins/login-auth/src/module-model/dialog.ts
  54. 32 0
      plugins/login-auth/src/module-model/globalState.ts
  55. 2535 0
      plugins/login-auth/src/module-model/login-test.js
  56. 45 0
      plugins/login-auth/src/module-model/loginCookies.ts
  57. 28 0
      plugins/login-auth/src/module-model/loginLeftAd.ts
  58. 15 0
      plugins/login-auth/src/module-model/tab.ts
  59. 31 0
      plugins/login-auth/src/module-model/wxQrcode.ts
  60. 15 0
      plugins/login-auth/src/shims-tsx.d.ts
  61. 4 0
      plugins/login-auth/src/shims-vue.d.ts
  62. 13 0
      plugins/login-auth/src/style/icon.scss
  63. 1 0
      plugins/login-auth/src/style/index.scss
  64. 322 0
      plugins/login-auth/src/utils/Login.ts
  65. 57 0
      plugins/login-auth/src/utils/common.js
  66. 30 0
      plugins/login-auth/src/utils/directive.ts
  67. 43 0
      plugins/login-auth/src/utils/use.ts
  68. 403 0
      plugins/login-auth/src/views/Layout.vue
  69. 211 0
      plugins/login-auth/src/views/form/bindPhone.vue
  70. 436 0
      plugins/login-auth/src/views/form/login.vue
  71. 271 0
      plugins/login-auth/src/views/form/register.vue
  72. 160 0
      plugins/login-auth/src/views/form/setPass.vue
  73. 91 0
      plugins/login-auth/src/views/form/wx.vue
  74. 6 0
      plugins/login-auth/tailwind.config.js
  75. 32 0
      plugins/login-auth/tsconfig.json
  76. 139 0
      plugins/login-auth/vite.config.js
  77. 3403 0
      plugins/login-auth/yarn.lock

+ 6 - 0
plugins/login-auth/.env.development

@@ -0,0 +1,6 @@
+VITE_APP_BASE_API='/api'
+VITE_APP_IMAGE_BASE='https://web2-qmxtest.jydev.jianyu360.com'
+VITE_APP_QR_IMAGE_BASE='https://jybx3-webtest.jydev.jianyu360.com/front/share/'
+VITE_APP_APP_PROJECT_BASE='https://app2-jytest.jydev.jianyu360.com'
+VITE_APP_WX_PROJECT_BASE='https://jybx2-webtest.jydev.jianyu360.com'
+VITE_APP_GIT_BRANCH='v0.0.1'

+ 6 - 0
plugins/login-auth/.env.external

@@ -0,0 +1,6 @@
+VITE_APP_BASE_API=''
+VITE_APP_IMAGE_BASE=''
+VITE_APP_QR_IMAGE_BASE='/front/share/'
+VITE_APP_APP_PROJECT_BASE=''
+VITE_APP_WX_PROJECT_BASE=''
+VITE_APP_GIT_BRANCH='v1.1.53'

+ 6 - 0
plugins/login-auth/.env.internal

@@ -0,0 +1,6 @@
+VITE_APP_BASE_API=''
+VITE_APP_IMAGE_BASE=''
+VITE_APP_QR_IMAGE_BASE='/front/share/'
+VITE_APP_APP_PROJECT_BASE=''
+VITE_APP_WX_PROJECT_BASE=''
+VITE_APP_GIT_BRANCH='v1.1.53'

+ 6 - 0
plugins/login-auth/.env.production

@@ -0,0 +1,6 @@
+VITE_APP_BASE_API=''
+VITE_APP_IMAGE_BASE=''
+VITE_APP_QR_IMAGE_BASE='/front/share/'
+VITE_APP_APP_PROJECT_BASE=''
+VITE_APP_WX_PROJECT_BASE=''
+VITE_APP_GIT_BRANCH='v1.1.53'

+ 97 - 0
plugins/login-auth/README.md

@@ -0,0 +1,97 @@
+# SDK
+
+### Emitter
+
+### API
+
+#### API
+
+| API   | 参数                     | 说明       |
+| ----- | ------------------------ | ---------- |
+| $emit | (type, data, expands)    | 发布       |
+| $on   | (type, handler, expands) | 订阅       |
+| $once | (type, handler, expands) | 仅订阅单次 |
+| $off  | (type, handler, expands) | 取消订阅   |
+
+#### 参数
+
+| 参数               | 类型                           | 说明                                 |
+| ------------------ | ------------------------------ | ------------------------------------ |
+| type               | String                         | 事件标识                             |
+| data               | Any                            | 事件数据                             |
+| handler            | Function (data, expands, type) | 订阅回调函数                         |
+| expands            | Object                         | 扩展参数                             |
+| expands.cross      | Boolean                        | 是否发布跨标签页事件                 |
+| expands.fromCross  | Boolean                        | 是否来自跨标签页事件                 |
+| expands.replay     | Boolean                        | 是否发布可回放事件(仅回放最近一次) |
+| expands.fromReplay | Boolean                        | 是否来自可回放事件                   |
+
+#### 示例
+
+> 更多示例请参考 `test` 目录下的测试用例
+
+```javascript
+this.$on('init', () => {
+  // init
+})
+
+this.$emit('init')
+```
+
+#### 跨标签页通信
+
+> 跨标签页通信,需要在发布事件时设置 `cross` 参数为 `true`
+
+⚠️ 注意:会同时触发本页面的 $on() 监听及其他页面的 $on() 监听,如需不触发本页面的 $on() 监听,请在 $on 回调中单独判断 expands.`fromCross`
+
+```javascript
+this.$on('init', (data, expands) => {
+  // 是否来自跨标签页事件
+  if (expands?.fromCross) {
+  }
+})
+
+this.$emit('init', {
+  cross: true
+})
+```
+
+#### 可回放事件
+
+> 可回放事件,需要在发布事件时设置 `replay` 参数为 `true`
+
+```javascript
+this.$on('init', () => {
+  // init
+})
+
+this.$emit('init', { replay: true })
+```
+
+### 如何新增插件
+
+1. 在 `src/plugins` 目录下新增一个插件文件,文件名必须以 `plugin` 开头,如 `plugin-xxx.js`
+2. 在 `src/plugins/plugin-xxx/index.js` 引入插件文件,并导出插件对象,如:
+
+```js
+import plugin from './plugin'
+
+export default {
+  plugin
+}
+```
+
+### API
+
+| API      | 说明                      | 版本 |
+| -------- | ------------------------- | ---- |
+| $TabBus  | 同浏览器跨 Tab 标签页通信 | v1   |
+| $PageBus | 同页面通信                | v1   |
+| $Bus     | 整合上面两种通信方式      | v1   |
+| $Login   | 登录注册相关业务封装      | v1   |
+
+### 版本记录
+
+| 版本 | 日期    | 说明 |
+| ---- | ------- | ---- |
+| v1   | 2023-11 | 初版 |

+ 83 - 0
plugins/login-auth/example/index.html

@@ -0,0 +1,83 @@
+<!doctype html>
+<html lang="en">
+<head>
+  <meta charset="utf-8" />
+  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
+  <meta name="viewport" content="width=device-width,initial-scale=1.0" />
+  <link rel="icon" href="/favicon.ico" />
+  <title>Example</title>
+</head>
+<body class="dark:bg-gray-800">
+<noscript>
+  <strong
+  >We're sorry but this page doesn't work properly without JavaScript
+    enabled. Please enable it to continue.</strong
+  >
+</noscript>
+
+<main>
+  <header>
+    <div id='user-login' style='display:none'>
+      <img id='user-head' alt='user-head'>
+      <h6 id='user-name'></h6>
+    </div>
+    <div id='user-noLogin'>
+      <button onclick="commonLogin.open('login-code')">登录/注册</button>
+    </div>
+  </header>
+</main>
+
+<hr>
+
+<button onclick="commonLogin.open('login-wx')">微信登录</button>
+<button onclick="commonLogin.open('login-code')">登录/注册</button>
+<button onclick="commonLogin.open('login-pass')">密码登录</button>
+<button onclick="commonLogin.open('register')">注册</button>
+<button onclick="commonLogin.open('set-pass')">设置密码</button>
+<button onclick="commonLogin.open('bind-phone')">绑定手机号</button>
+<br />
+<button onclick="commonLogin.doSignOut()">退出登录</button>
+<div id="app"></div>
+<script src="../dist/jy-login.umd.js"></script>
+<script>
+
+  function toggleLoginDom (type, img, name) {
+    if (type) {
+      document.querySelector('#user-login').style.display = 'block'
+      document.querySelector('#user-noLogin').style.display = 'none'
+      document.querySelector('#user-head').src = img
+      document.querySelector('#user-name').innerText = name
+    } else {
+      document.querySelector('#user-login').style.display = 'none'
+      document.querySelector('#user-noLogin').style.display = 'block'
+    }
+  }
+
+  window.addEventListener('load', () => {
+    window.commonLogin = window.jyCoreSDK.$plugins['login'].getInstance()
+    window.commonLogin.init({
+      preloadLoginState: true,
+      pageNum: 10
+    })
+    console.log('commonLogin', window.commonLogin)
+
+    window.jyCoreSDK.$on('user-login-success', (data) => {
+      alert('登录成功')
+    })
+    window.jyCoreSDK.$on('user-sign-out', (data) => {
+      alert('退出登录成功')
+      location.reload()
+    })
+    window.jyCoreSDK.$on('user-info-update', (data) => {
+      console.log('更新用户信息', data)
+      const format = data.format || {}
+      if (format?.isLogin) {
+        toggleLoginDom(format?.isLogin, format.userInfo.userAvatar, format.userInfo.userName)
+      } else {
+        toggleLoginDom(false)
+      }
+    })
+  })
+</script>
+</body>
+</html>

+ 83 - 0
plugins/login-auth/index.html

@@ -0,0 +1,83 @@
+<!doctype html>
+<html lang="en">
+  <head>
+    <meta charset="utf-8" />
+    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
+    <meta name="viewport" content="width=device-width,initial-scale=1.0" />
+    <link rel="icon" href="/favicon.ico" />
+    <title>Example</title>
+  </head>
+  <body class="dark:bg-gray-800">
+    <noscript>
+      <strong
+        >We're sorry but this page doesn't work properly without JavaScript
+        enabled. Please enable it to continue.</strong
+      >
+    </noscript>
+
+    <main>
+      <header>
+        <div id='user-login' style='display:none'>
+          <img id='user-head' alt='user-head'>
+          <h6 id='user-name'></h6>
+        </div>
+        <div id='user-noLogin'>
+          <button onclick="commonLogin.open('login-code')">登录/注册</button>
+        </div>
+      </header>
+    </main>
+
+    <hr>
+
+    <button onclick="commonLogin.open('login-wx')">微信登录</button>
+    <button onclick="commonLogin.open('login-code')">登录/注册</button>
+    <button onclick="commonLogin.open('login-pass')">密码登录</button>
+    <button onclick="commonLogin.open('register')">注册</button>
+    <button onclick="commonLogin.open('set-pass')">设置密码</button>
+    <button onclick="commonLogin.open('bind-phone')">绑定手机号</button>
+    <br />
+    <button onclick="commonLogin.doSignOut()">退出登录</button>
+    <div id="app"></div>
+    <script type="module" src="/src/main.ts"></script>
+    <script>
+
+      function toggleLoginDom (type, img, name) {
+        if (type) {
+          document.querySelector('#user-login').style.display = 'block'
+          document.querySelector('#user-noLogin').style.display = 'none'
+          document.querySelector('#user-head').src = img
+          document.querySelector('#user-name').innerText = name
+        } else {
+          document.querySelector('#user-login').style.display = 'none'
+          document.querySelector('#user-noLogin').style.display = 'block'
+        }
+      }
+
+      window.addEventListener('load', () => {
+        window.commonLogin = window.jyCoreSDK.$plugins['login'].getInstance()
+        window.commonLogin.init({
+          preloadLoginState: true,
+          pageNum: 10
+        })
+        console.log('commonLogin', window.commonLogin)
+
+        window.jyCoreSDK.$on('user-login-success', (data) => {
+          alert('登录成功')
+        })
+        window.jyCoreSDK.$on('user-sign-out', (data) => {
+          alert('退出登录成功')
+          location.reload()
+        })
+        window.jyCoreSDK.$on('user-info-update', (data) => {
+          console.log('更新用户信息', data)
+          const format = data.format || {}
+          if (format?.isLogin) {
+            toggleLoginDom(format?.isLogin, format.userInfo.userAvatar, format.userInfo.userName)
+          } else {
+            toggleLoginDom(false)
+          }
+        })
+      })
+    </script>
+  </body>
+</html>

+ 58 - 0
plugins/login-auth/package.json

@@ -0,0 +1,58 @@
+{
+  "name": "@jy/plugin-login-auth",
+  "version": "1.0.0",
+  "files": [
+    "dist"
+  ],
+  "main": "./dist/plugin-login-auth.umd.js",
+  "module": "./dist/plugin-login-auth.mjs",
+  "exports": {
+    ".": {
+      "import": "./dist/plugin-login-auth.mjs",
+      "require": "./dist/plugin-login-auth.umd.js"
+    }
+  },
+  "private": true,
+  "scripts": {
+    "dev": "vite",
+    "build": "npm run build:external & npm run build:internal",
+    "build:external": "vite build --mode external",
+    "build:internal": "vite build --mode internal",
+    "lint": "eslint \"**/*.{vue,ts,js}\"",
+    "lint:fix": "eslint \"**/*.{vue,ts,js}\" --fix",
+    "test": "vitest",
+    "format": "prettier --write --cache ."
+  },
+  "dependencies": {
+    "@vueuse/core": "^9.13.0",
+    "@vueuse/integrations": "^9.13.0",
+    "axios": "^1.3.5",
+    "core-js": "^3.29.1",
+    "element-ui": "^2.15.13",
+    "lodash": "^4.17.21",
+    "postcss-prefix-selector": "^1.16.0",
+    "qs": "^6.11.2",
+    "vue": "^2.7.14",
+    "@jy/emiiter": "workspace:^"
+  },
+  "devDependencies": {
+    "@antfu/eslint-config": "^0.38.2",
+    "@iconify/json": "^2.2.42",
+    "@vitejs/plugin-basic-ssl": "^1.0.1",
+    "@vitejs/plugin-vue2": "^2.2.0",
+    "eslint": "^8.37.0",
+    "husky": "^8.0.3",
+    "sass": "^1.61.0",
+    "typescript": "^5.0.3",
+    "unplugin-auto-import": "^0.15.2",
+    "unplugin-icons": "^0.16.1",
+    "unplugin-vue-components": "^0.24.1",
+    "vite": "^4.2.1",
+    "vite-plugin-css-injected-by-js": "^3.1.0",
+    "vite-plugin-style-import": "^1.4.1",
+    "vite-plugin-windicss": "^1.8.10",
+    "vitest": "^0.34.6",
+    "vue-template-compiler": "^2.7.14",
+    "vue-template-es2015-compiler": "^1.9.1"
+  }
+}

+ 51 - 0
plugins/login-auth/src/App.vue

@@ -0,0 +1,51 @@
+<script setup lang="ts">
+import Layout from '@/views/Layout.vue'
+import { canShowDialog } from '@/module-model/dialog'
+import pluginLogin from '@/lib/pluginLogin'
+import { watch } from 'vue'
+
+function close() {
+  pluginLogin.close()
+}
+
+const className = 'body-is-show-login-auth'
+watch(canShowDialog, (t) => {
+  document.body.classList[t ? 'add' : 'remove'](className)
+})
+
+</script>
+
+<template>
+  <div class="plugin-login-auth-container" v-if="canShowDialog">
+    <div class="bg-mask" @click="close"></div>
+    <layout @close="close"></layout>
+  </div>
+</template>
+
+<style lang="scss">
+/* no-prefix */
+.body-is-show-login-auth {
+  overflow: hidden;
+}
+/* no-prefix */
+.plugin-login-auth-container {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  z-index: 667;
+}
+
+@import './style/index.scss';
+
+.bg-mask {
+  position: fixed;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  background-color: #000;
+  opacity: 0.5;
+}
+</style>

+ 24 - 0
plugins/login-auth/src/api/form.js

@@ -0,0 +1,24 @@
+import request from './service'
+import qs from 'qs'
+
+export function ajaxGetCompanyAssociation(data) {
+  return request({
+    url: '/jypay/user/company/association',
+    method: 'post',
+    data: qs.stringify(data)
+  })
+}
+export function ajaxSetBindPhone(data) {
+  return request({
+    url: '/jypay/user/phone/bind',
+    method: 'post',
+    data: qs.stringify(data)
+  })
+}
+export function ajaxGetADInfo(data) {
+  return request({
+    url: '/publicapply/free/getJyAdList',
+    method: 'post',
+    data
+  })
+}

+ 2 - 0
plugins/login-auth/src/api/index.js

@@ -0,0 +1,2 @@
+export * from './login'
+export * from './form'

+ 56 - 0
plugins/login-auth/src/api/login.js

@@ -0,0 +1,56 @@
+import request from './service'
+import qs from 'qs'
+
+export function ajaxSetLogin(data) {
+  return request({
+    url: '/phone/login',
+    method: 'post',
+    data: qs.stringify(data)
+  })
+}
+
+export function ajaxSetPass(data) {
+  return request({
+    url: '/publicapply/password/update',
+    method: 'post',
+    data
+  })
+}
+
+export function ajaxGetHasLogin(data) {
+  return request({
+    url: '/front/hasSign',
+    method: 'post',
+    data: qs.stringify(data)
+  })
+}
+
+export function ajaxGetLoginPolling(data) {
+  return request({
+    url: '/front/ajaxPolling',
+    method: 'post',
+    data
+  })
+}
+
+export function ajaxGetLoginNum(id, data) {
+  return request({
+    url: '/front/getLoginNum/' + id,
+    method: 'post',
+    data: qs.stringify(data)
+  })
+}
+
+export function ajaxSetKeepLogin(data) {
+  return request({
+    url: '/free/setKeepLogin',
+    method: 'post',
+    data: qs.stringify(data)
+  })
+}
+export function ajaxSetSignOut() {
+  return request({
+    url: '/front/signOut',
+    method: 'post'
+  })
+}

+ 5 - 0
plugins/login-auth/src/api/service.js

@@ -0,0 +1,5 @@
+import axios from 'axios'
+
+export default axios.create({
+  baseURL: import.meta.env.VITE_APP_BASE_API
+})

二进制
plugins/login-auth/src/assets/icon/back.png


二进制
plugins/login-auth/src/assets/icon/blue-back.png


二进制
plugins/login-auth/src/assets/icon/close.png


二进制
plugins/login-auth/src/assets/icon/icon-biyan.png


二进制
plugins/login-auth/src/assets/icon/icon-company.png


二进制
plugins/login-auth/src/assets/icon/icon-email.png


二进制
plugins/login-auth/src/assets/icon/icon-guard.png


二进制
plugins/login-auth/src/assets/icon/icon-pass.png


二进制
plugins/login-auth/src/assets/icon/icon-phone.png


二进制
plugins/login-auth/src/assets/icon/icon-see.png


二进制
plugins/login-auth/src/assets/icon/select.png


二进制
plugins/login-auth/src/assets/icon/success.png


二进制
plugins/login-auth/src/assets/icon/test.png


二进制
plugins/login-auth/src/assets/icon/tip-active.png


二进制
plugins/login-auth/src/assets/icon/tip.png


二进制
plugins/login-auth/src/assets/icon/wx.png


+ 216 - 0
plugins/login-auth/src/auto-imports.d.ts

@@ -0,0 +1,216 @@
+/* eslint-disable */
+/* prettier-ignore */
+// @ts-nocheck
+// Generated by unplugin-auto-import
+export {}
+declare global {
+  const asyncComputed: typeof import('@vueuse/core')['asyncComputed']
+  const autoResetRef: typeof import('@vueuse/core')['autoResetRef']
+  const computedAsync: typeof import('@vueuse/core')['computedAsync']
+  const computedEager: typeof import('@vueuse/core')['computedEager']
+  const computedInject: typeof import('@vueuse/core')['computedInject']
+  const computedWithControl: typeof import('@vueuse/core')['computedWithControl']
+  const controlledComputed: typeof import('@vueuse/core')['controlledComputed']
+  const controlledRef: typeof import('@vueuse/core')['controlledRef']
+  const createEventHook: typeof import('@vueuse/core')['createEventHook']
+  const createGlobalState: typeof import('@vueuse/core')['createGlobalState']
+  const createInjectionState: typeof import('@vueuse/core')['createInjectionState']
+  const createReactiveFn: typeof import('@vueuse/core')['createReactiveFn']
+  const createSharedComposable: typeof import('@vueuse/core')['createSharedComposable']
+  const createUnrefFn: typeof import('@vueuse/core')['createUnrefFn']
+  const debouncedRef: typeof import('@vueuse/core')['debouncedRef']
+  const debouncedWatch: typeof import('@vueuse/core')['debouncedWatch']
+  const eagerComputed: typeof import('@vueuse/core')['eagerComputed']
+  const extendRef: typeof import('@vueuse/core')['extendRef']
+  const ignorableWatch: typeof import('@vueuse/core')['ignorableWatch']
+  const isDefined: typeof import('@vueuse/core')['isDefined']
+  const makeDestructurable: typeof import('@vueuse/core')['makeDestructurable']
+  const onClickOutside: typeof import('@vueuse/core')['onClickOutside']
+  const onKeyStroke: typeof import('@vueuse/core')['onKeyStroke']
+  const onLongPress: typeof import('@vueuse/core')['onLongPress']
+  const onStartTyping: typeof import('@vueuse/core')['onStartTyping']
+  const pausableWatch: typeof import('@vueuse/core')['pausableWatch']
+  const reactify: typeof import('@vueuse/core')['reactify']
+  const reactifyObject: typeof import('@vueuse/core')['reactifyObject']
+  const reactiveComputed: typeof import('@vueuse/core')['reactiveComputed']
+  const reactiveOmit: typeof import('@vueuse/core')['reactiveOmit']
+  const reactivePick: typeof import('@vueuse/core')['reactivePick']
+  const refAutoReset: typeof import('@vueuse/core')['refAutoReset']
+  const refDebounced: typeof import('@vueuse/core')['refDebounced']
+  const refDefault: typeof import('@vueuse/core')['refDefault']
+  const refThrottled: typeof import('@vueuse/core')['refThrottled']
+  const refWithControl: typeof import('@vueuse/core')['refWithControl']
+  const resolveRef: typeof import('@vueuse/core')['resolveRef']
+  const resolveUnref: typeof import('@vueuse/core')['resolveUnref']
+  const syncRef: typeof import('@vueuse/core')['syncRef']
+  const syncRefs: typeof import('@vueuse/core')['syncRefs']
+  const templateRef: typeof import('@vueuse/core')['templateRef']
+  const throttledRef: typeof import('@vueuse/core')['throttledRef']
+  const throttledWatch: typeof import('@vueuse/core')['throttledWatch']
+  const toReactive: typeof import('@vueuse/core')['toReactive']
+  const tryOnBeforeMount: typeof import('@vueuse/core')['tryOnBeforeMount']
+  const tryOnBeforeUnmount: typeof import('@vueuse/core')['tryOnBeforeUnmount']
+  const tryOnMounted: typeof import('@vueuse/core')['tryOnMounted']
+  const tryOnScopeDispose: typeof import('@vueuse/core')['tryOnScopeDispose']
+  const tryOnUnmounted: typeof import('@vueuse/core')['tryOnUnmounted']
+  const unrefElement: typeof import('@vueuse/core')['unrefElement']
+  const until: typeof import('@vueuse/core')['until']
+  const useActiveElement: typeof import('@vueuse/core')['useActiveElement']
+  const useArrayEvery: typeof import('@vueuse/core')['useArrayEvery']
+  const useArrayFilter: typeof import('@vueuse/core')['useArrayFilter']
+  const useArrayFind: typeof import('@vueuse/core')['useArrayFind']
+  const useArrayFindIndex: typeof import('@vueuse/core')['useArrayFindIndex']
+  const useArrayFindLast: typeof import('@vueuse/core')['useArrayFindLast']
+  const useArrayJoin: typeof import('@vueuse/core')['useArrayJoin']
+  const useArrayMap: typeof import('@vueuse/core')['useArrayMap']
+  const useArrayReduce: typeof import('@vueuse/core')['useArrayReduce']
+  const useArraySome: typeof import('@vueuse/core')['useArraySome']
+  const useArrayUnique: typeof import('@vueuse/core')['useArrayUnique']
+  const useAsyncQueue: typeof import('@vueuse/core')['useAsyncQueue']
+  const useAsyncState: typeof import('@vueuse/core')['useAsyncState']
+  const useBase64: typeof import('@vueuse/core')['useBase64']
+  const useBattery: typeof import('@vueuse/core')['useBattery']
+  const useBluetooth: typeof import('@vueuse/core')['useBluetooth']
+  const useBreakpoints: typeof import('@vueuse/core')['useBreakpoints']
+  const useBroadcastChannel: typeof import('@vueuse/core')['useBroadcastChannel']
+  const useBrowserLocation: typeof import('@vueuse/core')['useBrowserLocation']
+  const useCached: typeof import('@vueuse/core')['useCached']
+  const useClipboard: typeof import('@vueuse/core')['useClipboard']
+  const useCloned: typeof import('@vueuse/core')['useCloned']
+  const useColorMode: typeof import('@vueuse/core')['useColorMode']
+  const useConfirmDialog: typeof import('@vueuse/core')['useConfirmDialog']
+  const useCounter: typeof import('@vueuse/core')['useCounter']
+  const useCssVar: typeof import('@vueuse/core')['useCssVar']
+  const useCurrentElement: typeof import('@vueuse/core')['useCurrentElement']
+  const useCycleList: typeof import('@vueuse/core')['useCycleList']
+  const useDark: typeof import('@vueuse/core')['useDark']
+  const useDateFormat: typeof import('@vueuse/core')['useDateFormat']
+  const useDebounce: typeof import('@vueuse/core')['useDebounce']
+  const useDebounceFn: typeof import('@vueuse/core')['useDebounceFn']
+  const useDebouncedRefHistory: typeof import('@vueuse/core')['useDebouncedRefHistory']
+  const useDeviceMotion: typeof import('@vueuse/core')['useDeviceMotion']
+  const useDeviceOrientation: typeof import('@vueuse/core')['useDeviceOrientation']
+  const useDevicePixelRatio: typeof import('@vueuse/core')['useDevicePixelRatio']
+  const useDevicesList: typeof import('@vueuse/core')['useDevicesList']
+  const useDisplayMedia: typeof import('@vueuse/core')['useDisplayMedia']
+  const useDocumentVisibility: typeof import('@vueuse/core')['useDocumentVisibility']
+  const useDraggable: typeof import('@vueuse/core')['useDraggable']
+  const useDropZone: typeof import('@vueuse/core')['useDropZone']
+  const useElementBounding: typeof import('@vueuse/core')['useElementBounding']
+  const useElementByPoint: typeof import('@vueuse/core')['useElementByPoint']
+  const useElementHover: typeof import('@vueuse/core')['useElementHover']
+  const useElementSize: typeof import('@vueuse/core')['useElementSize']
+  const useElementVisibility: typeof import('@vueuse/core')['useElementVisibility']
+  const useEventBus: typeof import('@vueuse/core')['useEventBus']
+  const useEventListener: typeof import('@vueuse/core')['useEventListener']
+  const useEventSource: typeof import('@vueuse/core')['useEventSource']
+  const useEyeDropper: typeof import('@vueuse/core')['useEyeDropper']
+  const useFavicon: typeof import('@vueuse/core')['useFavicon']
+  const useFetch: typeof import('@vueuse/core')['useFetch']
+  const useFileDialog: typeof import('@vueuse/core')['useFileDialog']
+  const useFileSystemAccess: typeof import('@vueuse/core')['useFileSystemAccess']
+  const useFocus: typeof import('@vueuse/core')['useFocus']
+  const useFocusWithin: typeof import('@vueuse/core')['useFocusWithin']
+  const useFps: typeof import('@vueuse/core')['useFps']
+  const useFullscreen: typeof import('@vueuse/core')['useFullscreen']
+  const useGamepad: typeof import('@vueuse/core')['useGamepad']
+  const useGeolocation: typeof import('@vueuse/core')['useGeolocation']
+  const useIdle: typeof import('@vueuse/core')['useIdle']
+  const useImage: typeof import('@vueuse/core')['useImage']
+  const useInfiniteScroll: typeof import('@vueuse/core')['useInfiniteScroll']
+  const useIntersectionObserver: typeof import('@vueuse/core')['useIntersectionObserver']
+  const useInterval: typeof import('@vueuse/core')['useInterval']
+  const useIntervalFn: typeof import('@vueuse/core')['useIntervalFn']
+  const useKeyModifier: typeof import('@vueuse/core')['useKeyModifier']
+  const useLastChanged: typeof import('@vueuse/core')['useLastChanged']
+  const useLocalStorage: typeof import('@vueuse/core')['useLocalStorage']
+  const useMagicKeys: typeof import('@vueuse/core')['useMagicKeys']
+  const useManualRefHistory: typeof import('@vueuse/core')['useManualRefHistory']
+  const useMediaControls: typeof import('@vueuse/core')['useMediaControls']
+  const useMediaQuery: typeof import('@vueuse/core')['useMediaQuery']
+  const useMemoize: typeof import('@vueuse/core')['useMemoize']
+  const useMemory: typeof import('@vueuse/core')['useMemory']
+  const useMounted: typeof import('@vueuse/core')['useMounted']
+  const useMouse: typeof import('@vueuse/core')['useMouse']
+  const useMouseInElement: typeof import('@vueuse/core')['useMouseInElement']
+  const useMousePressed: typeof import('@vueuse/core')['useMousePressed']
+  const useMutationObserver: typeof import('@vueuse/core')['useMutationObserver']
+  const useNavigatorLanguage: typeof import('@vueuse/core')['useNavigatorLanguage']
+  const useNetwork: typeof import('@vueuse/core')['useNetwork']
+  const useNow: typeof import('@vueuse/core')['useNow']
+  const useObjectUrl: typeof import('@vueuse/core')['useObjectUrl']
+  const useOffsetPagination: typeof import('@vueuse/core')['useOffsetPagination']
+  const useOnline: typeof import('@vueuse/core')['useOnline']
+  const usePageLeave: typeof import('@vueuse/core')['usePageLeave']
+  const useParallax: typeof import('@vueuse/core')['useParallax']
+  const usePermission: typeof import('@vueuse/core')['usePermission']
+  const usePointer: typeof import('@vueuse/core')['usePointer']
+  const usePointerLock: typeof import('@vueuse/core')['usePointerLock']
+  const usePointerSwipe: typeof import('@vueuse/core')['usePointerSwipe']
+  const usePreferredColorScheme: typeof import('@vueuse/core')['usePreferredColorScheme']
+  const usePreferredContrast: typeof import('@vueuse/core')['usePreferredContrast']
+  const usePreferredDark: typeof import('@vueuse/core')['usePreferredDark']
+  const usePreferredLanguages: typeof import('@vueuse/core')['usePreferredLanguages']
+  const usePreferredReducedMotion: typeof import('@vueuse/core')['usePreferredReducedMotion']
+  const usePrevious: typeof import('@vueuse/core')['usePrevious']
+  const useRafFn: typeof import('@vueuse/core')['useRafFn']
+  const useRefHistory: typeof import('@vueuse/core')['useRefHistory']
+  const useResizeObserver: typeof import('@vueuse/core')['useResizeObserver']
+  const useScreenOrientation: typeof import('@vueuse/core')['useScreenOrientation']
+  const useScreenSafeArea: typeof import('@vueuse/core')['useScreenSafeArea']
+  const useScriptTag: typeof import('@vueuse/core')['useScriptTag']
+  const useScroll: typeof import('@vueuse/core')['useScroll']
+  const useScrollLock: typeof import('@vueuse/core')['useScrollLock']
+  const useSessionStorage: typeof import('@vueuse/core')['useSessionStorage']
+  const useShare: typeof import('@vueuse/core')['useShare']
+  const useSorted: typeof import('@vueuse/core')['useSorted']
+  const useSpeechRecognition: typeof import('@vueuse/core')['useSpeechRecognition']
+  const useSpeechSynthesis: typeof import('@vueuse/core')['useSpeechSynthesis']
+  const useStepper: typeof import('@vueuse/core')['useStepper']
+  const useStorage: typeof import('@vueuse/core')['useStorage']
+  const useStorageAsync: typeof import('@vueuse/core')['useStorageAsync']
+  const useStyleTag: typeof import('@vueuse/core')['useStyleTag']
+  const useSupported: typeof import('@vueuse/core')['useSupported']
+  const useSwipe: typeof import('@vueuse/core')['useSwipe']
+  const useTemplateRefsList: typeof import('@vueuse/core')['useTemplateRefsList']
+  const useTextDirection: typeof import('@vueuse/core')['useTextDirection']
+  const useTextSelection: typeof import('@vueuse/core')['useTextSelection']
+  const useTextareaAutosize: typeof import('@vueuse/core')['useTextareaAutosize']
+  const useThrottle: typeof import('@vueuse/core')['useThrottle']
+  const useThrottleFn: typeof import('@vueuse/core')['useThrottleFn']
+  const useThrottledRefHistory: typeof import('@vueuse/core')['useThrottledRefHistory']
+  const useTimeAgo: typeof import('@vueuse/core')['useTimeAgo']
+  const useTimeout: typeof import('@vueuse/core')['useTimeout']
+  const useTimeoutFn: typeof import('@vueuse/core')['useTimeoutFn']
+  const useTimeoutPoll: typeof import('@vueuse/core')['useTimeoutPoll']
+  const useTimestamp: typeof import('@vueuse/core')['useTimestamp']
+  const useTitle: typeof import('@vueuse/core')['useTitle']
+  const useToNumber: typeof import('@vueuse/core')['useToNumber']
+  const useToString: typeof import('@vueuse/core')['useToString']
+  const useToggle: typeof import('@vueuse/core')['useToggle']
+  const useTransition: typeof import('@vueuse/core')['useTransition']
+  const useUrlSearchParams: typeof import('@vueuse/core')['useUrlSearchParams']
+  const useUserMedia: typeof import('@vueuse/core')['useUserMedia']
+  const useVModel: typeof import('@vueuse/core')['useVModel']
+  const useVModels: typeof import('@vueuse/core')['useVModels']
+  const useVibrate: typeof import('@vueuse/core')['useVibrate']
+  const useVirtualList: typeof import('@vueuse/core')['useVirtualList']
+  const useWakeLock: typeof import('@vueuse/core')['useWakeLock']
+  const useWebNotification: typeof import('@vueuse/core')['useWebNotification']
+  const useWebSocket: typeof import('@vueuse/core')['useWebSocket']
+  const useWebWorker: typeof import('@vueuse/core')['useWebWorker']
+  const useWebWorkerFn: typeof import('@vueuse/core')['useWebWorkerFn']
+  const useWindowFocus: typeof import('@vueuse/core')['useWindowFocus']
+  const useWindowScroll: typeof import('@vueuse/core')['useWindowScroll']
+  const useWindowSize: typeof import('@vueuse/core')['useWindowSize']
+  const watchArray: typeof import('@vueuse/core')['watchArray']
+  const watchAtMost: typeof import('@vueuse/core')['watchAtMost']
+  const watchDebounced: typeof import('@vueuse/core')['watchDebounced']
+  const watchIgnorable: typeof import('@vueuse/core')['watchIgnorable']
+  const watchOnce: typeof import('@vueuse/core')['watchOnce']
+  const watchPausable: typeof import('@vueuse/core')['watchPausable']
+  const watchThrottled: typeof import('@vueuse/core')['watchThrottled']
+  const watchTriggerable: typeof import('@vueuse/core')['watchTriggerable']
+  const watchWithFilter: typeof import('@vueuse/core')['watchWithFilter']
+  const whenever: typeof import('@vueuse/core')['whenever']
+}

+ 20 - 0
plugins/login-auth/src/components.d.ts

@@ -0,0 +1,20 @@
+/* eslint-disable */
+/* prettier-ignore */
+// @ts-nocheck
+// Generated by unplugin-vue-components
+// Read more: https://github.com/vuejs/core/pull/3399
+export {}
+
+declare module 'vue' {
+  export interface GlobalComponents {
+    AutoCompleteInput: typeof import('./components/form/autoCompleteInput.vue')['default']
+    BaseForm: typeof import('./components/form/baseForm.vue')['default']
+    BaseInput: typeof import('./components/form/baseInput.vue')['default']
+    ImgCaptchaInput: typeof import('./components/form/imgCaptchaInput.vue')['default']
+    PassInput: typeof import('./components/form/passInput.vue')['default']
+    RouterLink: typeof import('vue-router')['RouterLink']
+    RouterView: typeof import('vue-router')['RouterView']
+    SmsCaptchaInput: typeof import('./components/form/smsCaptchaInput.vue')['default']
+    Toast: typeof import('./components/toast/Toast.vue')['default']
+  }
+}

+ 102 - 0
plugins/login-auth/src/components/form/autoCompleteInput.vue

@@ -0,0 +1,102 @@
+<script setup>
+import { toRefs, ref, watch } from 'vue'
+import { ajaxGetCompanyAssociation } from '@/api'
+import { debounce } from 'lodash'
+
+const props = defineProps({
+  value: ''
+})
+
+const emit = defineEmits(['input'])
+
+const { value } = toRefs(props)
+
+const list = ref([])
+let tempValue = ''
+
+const getList = (value) => {
+  ajaxGetCompanyAssociation({
+    name: value
+  }).then(({ data }) => {
+    list.value = [value]
+    if (data.error_code === 0) {
+      const result = data.data || []
+      if (Array.isArray(result) && result.length) {
+        list.value = [value].concat(result.filter((v) => v !== value))
+      }
+    }
+  })
+}
+
+watch(
+  value,
+  debounce((val) => {
+    if (val.length < 2 || val === tempValue) {
+      list.value = []
+      return
+    }
+    getList(val)
+    tempValue = val
+  }, 150)
+)
+
+function doChangeItem(name) {
+  if (name === props.value) {
+    list.value = []
+    return
+  }
+  tempValue = name
+  emit('input', name)
+}
+</script>
+<template>
+  <div class="autocomplete-box" v-if="list.length">
+    <ul>
+      <li
+        v-for="(item, index) in list"
+        :key="index"
+        @click="doChangeItem(item)"
+      >
+        {{ item }}
+      </li>
+    </ul>
+  </div>
+</template>
+
+<style lang="scss">
+.autocomplete-box {
+  display: none;
+  background: #fff;
+  position: absolute;
+  left: 0;
+  top: 46px;
+  width: 100%;
+  max-height: 205px;
+  overflow: hidden;
+  overflow-y: auto;
+  z-index: 2;
+  box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.08);
+  border-radius: 8px;
+  &:hover {
+    display: block;
+  }
+  li {
+    width: 100%;
+    box-sizing: border-box;
+    color: #1d1d1d;
+    font-size: 14px;
+    line-height: 24px;
+    letter-spacing: 0px;
+    text-align: left;
+    padding: 10px 20px;
+    border-bottom: 1px solid rgba(0, 0, 0, 0.05);
+    cursor: pointer;
+    &:hover {
+      background: #f6f6f6;
+    }
+    &:last-child {
+      border-bottom: none;
+    }
+  }
+}
+</style>

+ 132 - 0
plugins/login-auth/src/components/form/baseForm.vue

@@ -0,0 +1,132 @@
+<script setup>
+import BaseInput from './baseInput.vue'
+import ImgCaptchaInput from './imgCaptchaInput.vue'
+import SmsCaptchaInput from './smsCaptchaInput.vue'
+import passInput from './passInput.vue'
+import autoCompleteInput from './autoCompleteInput.vue'
+import { watch, ref } from 'vue'
+import { assign } from 'lodash'
+
+const props = defineProps({
+  schema: {
+    required: true,
+    type: Array,
+    default: () => []
+  },
+  value: {
+    required: true,
+    type: Object,
+    default: () => ({})
+  }
+})
+
+const emit = defineEmits(['input', 'submit'])
+
+const baseChild = ref({})
+function showError(key, message) {
+  const inputComponent = baseChild.value[key]
+  if (inputComponent && inputComponent.showError) {
+    inputComponent.showError(message)
+  }
+}
+
+const imgCaptchaChild = ref(null)
+function doRefreshCaptcha() {
+  const imgCaptchaChildNode = imgCaptchaChild.value && imgCaptchaChild.value[0]
+  if (imgCaptchaChildNode.doRefreshCaptcha) {
+    imgCaptchaChildNode.doRefreshCaptcha()
+  }
+}
+
+defineExpose({
+  showError,
+  doRefreshCaptcha
+})
+
+const tranState = ref(assign({}, props.value))
+watch(tranState, (newValue) => {
+  emit('input', newValue)
+})
+
+watch(
+  () => props.value,
+  (newValue) => {
+    tranState.value = newValue
+  }
+)
+
+function doSubmit(key, validate) {
+  emit('submit', key, validate)
+}
+</script>
+<template>
+  <div>
+    <div v-for="item in schema">
+      <template v-if="item.type === 'base'">
+        <base-input
+          ref="baseChild"
+          @submit="doSubmit(item.key, $event)"
+          v-bind="item"
+          v-model="tranState[item.key].value"
+          :validate.sync="tranState[item.key].validate"
+        />
+      </template>
+      <template v-if="item.type === 'imgCaptcha'">
+        <base-input
+          ref="baseChild"
+          @submit="doSubmit(item.key, $event)"
+          v-bind="item"
+          v-model="tranState[item.key].value"
+          :validate.sync="tranState[item.key].validate"
+        >
+          <img-captcha-input ref="imgCaptchaChild" />
+        </base-input>
+      </template>
+      <template v-if="item.type === 'smsCaptcha'">
+        <base-input
+          ref="baseChild"
+          @submit="doSubmit(item.key, $event)"
+          v-bind="item"
+          v-model="tranState[item.key].value"
+          :validate.sync="tranState[item.key].validate"
+        >
+          <sms-captcha-input v-bind="item" />
+        </base-input>
+      </template>
+      <template v-if="item.type === 'pass'">
+        <base-input
+          ref="baseChild"
+          @submit="doSubmit(item.key, $event)"
+          v-bind="item"
+          v-model="tranState[item.key].value"
+          :validate.sync="tranState[item.key].validate"
+        >
+          <pass-input />
+        </base-input>
+      </template>
+      <template v-if="item.type === 'autocomplete'">
+        <base-input
+          class="input-autocomplete-container"
+          ref="baseChild"
+          @submit="doSubmit(item.key, $event)"
+          v-bind="item"
+          v-model="tranState[item.key].value"
+          :validate.sync="tranState[item.key].validate"
+        >
+          <auto-complete-input v-model="tranState[item.key].value" />
+        </base-input>
+      </template>
+    </div>
+  </div>
+</template>
+
+<style lang="scss">
+.input-autocomplete-container {
+  position: relative;
+  &.is-focus {
+    .autocomplete-box {
+      display: block;
+    }
+  }
+}
+</style>

+ 153 - 0
plugins/login-auth/src/components/form/baseInput.vue

@@ -0,0 +1,153 @@
+<script setup>
+import { computed, reactive } from 'vue'
+
+const props = defineProps({
+  value: {
+    type: [String, Number],
+    default: ''
+  },
+  icon: String,
+  validate: Boolean,
+  rule: {
+    type: [Function, RegExp]
+  },
+  message: '',
+  inputAttr: {
+    default: () => ({
+      placeholder: '',
+      type: 'text'
+    })
+  }
+})
+
+const emit = defineEmits(['input', 'update:validate', 'submit'])
+function doUpdateValidate(result) {
+  emit('update:validate', result)
+}
+
+/**
+ * 变量
+ */
+
+const inputValidate = reactive({
+  message: String(props.message),
+  state: {
+    'is-focus': false,
+    'is-error': false
+  }
+})
+
+const inputClassName = computed(() => {
+  let result = inputValidate.state
+  if (props.value === '') {
+    result['is-error'] = false
+  }
+
+  return Object.assign({}, inputValidate.state, result)
+})
+
+const inputErrorMessage = computed(() => {
+  if (props.value === '') {
+    return ''
+  }
+  return inputValidate.message
+})
+
+/**
+ * 输入校验
+ */
+
+function validate(value) {
+  let result = {
+    result: false,
+    message: ''
+  }
+  if (value === '') {
+    doUpdateValidate(result.result)
+    return result
+  }
+
+  if (typeof props.rule === 'function') {
+    result = props.rule(value)
+  } else if (props.rule instanceof RegExp) {
+    const regResult = props.rule.test(value)
+    result = {
+      result: regResult,
+      message: regResult ? '' : props.message
+    }
+  }
+  doUpdateValidate(result.result)
+  return result
+}
+
+function hideError() {
+  inputValidate.state['is-error'] = false
+  inputValidate.state['is-focus'] = true
+  inputValidate.message = ''
+}
+function showError(message) {
+  inputValidate.state['is-error'] = true
+  inputValidate.message = message
+  doUpdateValidate(false)
+}
+
+defineExpose({
+  showError
+})
+
+/**
+ * 输入框事件绑定
+ */
+
+function doInput(val) {
+  hideError()
+
+  const inputVal = val.trim()
+  emit('input', inputVal)
+
+  const maxLength = props.inputAttr.maxlength
+  const { result, message } = validate(inputVal)
+
+  if (maxLength && inputVal.length === Number(maxLength)) {
+    if (!result) {
+      showError(message)
+    }
+  }
+}
+function doBlur() {
+  const { result, message } = validate(props.value)
+  if (result) {
+    hideError()
+  } else {
+    showError(message)
+  }
+  inputValidate.state['is-focus'] = false
+}
+
+function doFocus() {
+  inputValidate.state['is-focus'] = true
+}
+
+function doEnter() {
+  emit('submit', props.validate)
+}
+</script>
+<template>
+  <div
+    class="login-auth--form-input"
+    :class="inputClassName"
+    :data-error="inputErrorMessage"
+  >
+    <i class="img-icon" :class="'icon-' + icon"></i>
+    <input
+      autocomplete="off"
+      v-bind="inputAttr"
+      :value="value"
+      @focus="doFocus"
+      @input="doInput($event.target.value)"
+      @blur="doBlur"
+      @keyup.enter="doEnter"
+    />
+    <slot></slot>
+  </div>
+</template>

+ 28 - 0
plugins/login-auth/src/components/form/imgCaptchaInput.vue

@@ -0,0 +1,28 @@
+<script setup>
+import { ref } from 'vue'
+
+/**
+ *  图片验证码刷新逻辑
+ */
+
+const baseImgCaptcha = 'https://www.jianyu360.cn/front/landpage/captcha'
+const imgCaptcha = ref(baseImgCaptcha)
+
+function doRefreshCaptcha() {
+  imgCaptcha.value = baseImgCaptcha + '?t=' + Date.now()
+}
+
+defineExpose({
+  doRefreshCaptcha
+})
+</script>
+<template>
+  <div class="verify-img-group">
+    <img
+      class="verify-img"
+      @click="doRefreshCaptcha"
+      :src="imgCaptcha"
+      alt="verify"
+    />
+  </div>
+</template>

+ 6 - 0
plugins/login-auth/src/components/form/passInput.vue

@@ -0,0 +1,6 @@
+<template>
+  <div class="pass-right-icon" v-toggle-input-type>
+    <i class="img-icon icon-icon-biyan"></i>
+    <i class="img-icon icon-icon-see"></i>
+  </div>
+</template>

+ 46 - 0
plugins/login-auth/src/components/form/smsCaptchaInput.vue

@@ -0,0 +1,46 @@
+<script setup>
+import { computed } from 'vue'
+import CountdownTimer from '@/module-model/countDown'
+
+const props = defineProps({
+  expands: {
+    default: () => ({})
+  },
+  actions: {
+    default: () => ({})
+  }
+})
+
+defineEmits(['input'])
+
+/**
+ * 倒计时逻辑
+ */
+
+const countDown = new CountdownTimer().getInstance()
+
+const canDoSetSms = computed(() => {
+  return !countDown.isCounting.value && props.expands.preCheckState.value
+})
+async function doGetSms() {
+  if (!canDoSetSms.value) {
+    return
+  }
+
+  let canNext = true
+
+  if (typeof props.actions.preSubmit === 'function') {
+    const result = await props.actions.preSubmit()
+    canNext = result
+  }
+  if (canNext) {
+    countDown.start()
+  }
+}
+</script>
+<template>
+  <div class="login-auth--form-after" :class="{ disable: !canDoSetSms }">
+    <span v-if="!countDown.isCounting.value" @click="doGetSms">获取验证码</span>
+    <span v-else>重新获取({{ countDown.countdown.value }}s)</span>
+  </div>
+</template>

+ 43 - 0
plugins/login-auth/src/components/toast/Toast.vue

@@ -0,0 +1,43 @@
+<template>
+  <div v-if="showWrap" class="wrap" :class="showContent ? 'fadein' : 'fadeout'">
+    {{ text }}
+  </div>
+</template>
+
+<style scoped>
+.wrap {
+  position: fixed;
+  left: 50%;
+  top: 50%;
+  background: rgba(0, 0, 0, 0.65);
+  padding: 16px 32px;
+  border-radius: 8px;
+  transform: translate(-50%, -50%);
+  color: #fff;
+  font-size: 16px;
+  z-index: 9999;
+}
+.fadein {
+  animation: animate_in 0.25s;
+}
+.fadeout {
+  animation: animate_out 0.25s;
+  opacity: 0;
+}
+@keyframes animate_in {
+  0% {
+    opacity: 0;
+  }
+  100% {
+    opacity: 1;
+  }
+}
+@keyframes animate_out {
+  0% {
+    opacity: 1;
+  }
+  100% {
+    opacity: 0;
+  }
+}
+</style>

+ 57 - 0
plugins/login-auth/src/components/toast/index.js

@@ -0,0 +1,57 @@
+import vue from 'vue'
+import toastComponent from './Toast.vue'
+const ToastConstructor = vue.extend(toastComponent)
+
+let ToastHistory = {}
+
+// 定义弹出组件的函数 接收2个参数, 要显示的文本 和 显示时间
+function showToast(text, duration = 2000) {
+  if (ToastHistory.el) ToastHistory.destory()
+
+  // 实例化一个 toast.vue
+  const toastDom = new ToastConstructor({
+    el: document.createElement('div'),
+    data() {
+      return {
+        text,
+        showWrap: true,
+        showContent: true
+      }
+    }
+  })
+  // 把 实例化的 toast.vue 添加到 body 里
+  try {
+    this.$root.$el.appendChild(toastDom.$el)
+  } catch (error) {
+    document.body.appendChild(toastDom.$el)
+  }
+  return new Promise((resolve) => {
+    // 提前 250ms 执行淡出动画(因为我们再css里面设置的隐藏动画持续是250ms)
+    const tFn1 = setTimeout(() => {
+      toastDom.showContent = false
+    }, duration - 250)
+    // 过了 duration 时间后隐藏整个组件
+    const tFn2 = setTimeout(() => {
+      toastDom.showWrap = false
+      resolve()
+    }, duration)
+
+    ToastHistory = {
+      el: toastDom.$el,
+      destory: () => {
+        clearTimeout(tFn1)
+        clearTimeout(tFn2)
+        toastDom.$el.remove()
+      }
+    }
+  })
+}
+
+// 注册为全局组件的函数
+const ToastPlugin = {
+  install(app) {
+    app.prototype.$toast = showToast
+  }
+}
+
+export default ToastPlugin

+ 12 - 0
plugins/login-auth/src/data/constant.ts

@@ -0,0 +1,12 @@
+const FormRules = {
+  // 账号登录
+  account: /^[a-zA-Z0-9\u4e00-\u9fa5@#&_-]/,
+  // 兼容虚拟号段【100】
+  phone: /^(1[3-9]\d{9}|1[0]\d{10})$/,
+  imgCode: /^\S{4}$/,
+  smsCode: /^\S{6}$/,
+  entName: /^\S{4,100}$/,
+  pass: /^\S{6,}$/,
+  email: /.*/
+}
+export { FormRules }

+ 19 - 0
plugins/login-auth/src/lib/core.ts

@@ -0,0 +1,19 @@
+import Emitter from '@jy/emiiter'
+
+function createCore ({ alias = 'jyCoreSDK'} = {}) {
+  if (!Object.prototype.hasOwnProperty.call(window, alias)) {
+    const devLog = localStorage.getItem('env') === 'development'
+    const core = Emitter({
+      logger: devLog,
+      cross: true,
+      customEvent: false,
+      replay: true,
+      name: 'core-sdk-emitter'
+    })
+    window[alias] = core
+  }
+  return window[alias]
+}
+
+const core = new createCore()
+export default core

+ 31 - 0
plugins/login-auth/src/lib/main.ts

@@ -0,0 +1,31 @@
+import './pre-hook'
+import Vue from 'vue'
+import App from '@/App.vue'
+import Toast from '@/components/toast/index.js'
+import 'virtual:windi.css'
+import '@/utils/directive'
+
+Vue.config.productionTip = false
+Vue.config.devtools = true
+
+Vue.use(Toast)
+
+// 注入 body
+const container = document.createElement('div')
+container.id = 'plugin-login-auth-container'
+document.body.appendChild(container)
+
+/* eslint-disable no-new */
+function initAppContainer () {
+  new Vue({
+    el: '#plugin-login-auth-container',
+    render: (h) => h(App)
+  })
+}
+
+initAppContainer()
+
+
+
+
+

+ 6 - 0
plugins/login-auth/src/lib/module/bind-phone.ts

@@ -0,0 +1,6 @@
+const bindPhone = {
+  format (obj, res) {
+    return obj
+  }
+}
+export default bindPhone

+ 20 - 0
plugins/login-auth/src/lib/module/common.ts

@@ -0,0 +1,20 @@
+import pluginLogin from '@/lib/pluginLogin'
+
+export function commonFormat (obj, res) {
+  if (res && res.status === 1 && res.userInfo) {
+    // 用户信息设置
+    if (res.userInfo.result === 'ok') {
+      obj.format.isLogin = true
+    }
+    obj.format.userInfo.userAvatar = import.meta.env.VITE_APP_IMAGE_BASE + res.userInfo.s_headimage
+    obj.format.userInfo.userName = res.userInfo.s_nickname
+    obj.format.userInfo.userPhone = res.userInfo.phone
+    obj.format.userInfo.openId = res.userInfo.openid
+  }
+  return obj
+}
+
+
+export function commonHandle (formatData) {
+  pluginLogin.emitUserLoginSuccess(formatData)
+}

+ 149 - 0
plugins/login-auth/src/lib/module/index.ts

@@ -0,0 +1,149 @@
+/**
+ * 统一业务成功后分发处理
+ *
+ * 历史业务逻辑梳理:
+ * 0. 是否需要设置密码(前置处理,不进入该分发,只更新用户信息)
+ * 1. 处理返回值,统一格式
+ * 2. 按顺序依次处理历史业务
+ *  2.0 更新用户头像等状态【已提髙到前置处理】
+ *  2.1 是否需要 set Cookies
+ *  2.2 是否需要重新登录
+ *  2.3 是否需要绑定手机号
+ *  2.4 TODO 是否需要新窗口打开<新用户兴趣偏好设置页面>
+ *  2.5 TODO 是否需要展示新用户引导 pc-guide
+ *  2.6 TODO 历史全局状态维护 【迁移SDK新方式】
+ *  2.7 TODO 消息提示获取
+ * 3. TODO 其他业务 原 processpage 函数
+ *  3.1 登录后返回指定URL
+ *  3.2 登录后特定页面操作
+ * 4. TODO 原全局 loginCallback 回调 【迁移SDK新方式】
+ */
+
+import loginCookie from '@/module-model/loginCookies'
+import { clearAllStorageOfReg } from '@/utils/common'
+import bindPhone from './bind-phone'
+import poll from './poll'
+import { useUrlSearchParams } from '@vueuse/core'
+import { commonFormat, commonHandle } from './common'
+
+const moduleMap = {
+  'login-pass': {
+    format: commonFormat,
+    dispatch: commonHandle
+  },
+  'login-code': {
+    format: commonFormat,
+    dispatch: commonHandle
+  },
+  'register': {
+    format: commonFormat,
+    dispatch: commonHandle
+  },
+  'set-pass': {},
+  'bind-phone': bindPhone,
+  'poll': poll
+}
+function getNowModule (type) {
+  let module = moduleMap[type]
+  return module
+}
+
+/**
+ * 检查是否存在 URL 参数 backTo
+ */
+
+function checkToPage (useResult) {
+  const params = useUrlSearchParams('history')
+  const backTo = params.backTo || ''
+  if (backTo) {
+    useResult().actions.needToPage = true
+    useResult().actions.expand.backToURL = backTo
+  }
+}
+
+/**
+ * 数据格式化
+ * @param type - 类型
+ * @param response
+ */
+function transformResponse (type, response) {
+  const result = {
+    actions: {
+      needClearCookie: false,
+      needSetCookie: false,
+      needReLogin: false,
+      needBindPhone: false,
+      needNewUserSetting: false,
+      needNewUserGuide: false,
+      needToPage: false,
+      expand: {}
+    },
+    format: {
+      isLogin: false,
+      userInfo: {
+        userAvatar: '',
+        userName: '',
+        userPhone: '',
+        openId: ''
+      },
+      userPower: {}
+    },
+    origin: response
+  }
+
+  // 公用业务检查
+  checkToPage(() => result)
+  // 特定业务检查
+  const module = getNowModule(type)
+  if (module && typeof module?.format === 'function') {
+    return module.format(result, response)
+  }
+  return result
+}
+
+/**
+ * 公共业务处理
+ * @param actions
+ * @param expand
+ */
+function commonAction ({ actions, expand }): void {
+  if (actions?.needClearCookie) {
+    // 清除历史 Cookies、Session
+    clearAllStorageOfReg(/-login-clear/)
+    loginCookie.clear()
+  }
+  if (actions?.needSetCookie) {
+    loginCookie.set(expand.cName, expand.cValue, expand.expires)
+  }
+  if (actions?.needReLogin) {
+    loginCookie.clear()
+    window.location.href = '/?nol=2'
+    return
+  }
+  if (actions?.needBindPhone) {
+    window.location.href = '/swordfish/frontPage/userMerge/sess/bind'
+    return
+  }
+  if (actions?.needToPage) {
+    if (expand?.backToURL) {
+      return location.replace(decodeURIComponent(expand.backToURL))
+    } else {
+      return location.replace('/')
+    }
+  }
+}
+
+function dispatchCallback (type: string, data): void {
+  const tranData = transformResponse(type, data)
+  commonAction(tranData)
+  const module = getNowModule(type)
+  if (module && typeof module?.dispatch === 'function') {
+    module.dispatch(tranData)
+  }
+  return tranData
+}
+
+export {
+  dispatchCallback,
+  transformResponse
+}

+ 33 - 0
plugins/login-auth/src/lib/module/poll.ts

@@ -0,0 +1,33 @@
+import { commonHandle } from './common'
+
+const poll = {
+  format (obj, res) {
+    if (res && res.result === 'ok') {
+      obj.format.isLogin = true
+      obj.format.userInfo.userAvatar = import.meta.env.VITE_APP_IMAGE_BASE + res.s_headimage
+      obj.format.userInfo.userName = res.s_nickname
+      obj.format.userInfo.openId = res.openid
+      obj.format.userInfo.userPhone = res.phone
+    }
+
+    // 业务判断设置
+    if (res) {
+      if (res?.resetpwd) {
+        obj.actions.needClearCookie = true
+        obj.actions.needReLogin = true
+      }
+      if (res?.cValue) {
+        obj.actions.needSetCookie = true
+        obj.actions.expand = Object.assign({
+          cValue: res.cValue,
+          cName: res.cName,
+          expire: res.expire
+        }, obj.actions.expand)
+      }
+    }
+
+    return obj
+  },
+  dispatch: commonHandle
+}
+export default poll

+ 247 - 0
plugins/login-auth/src/lib/pluginLogin.ts

@@ -0,0 +1,247 @@
+import { doChangeTabActive } from '@/module-model/tab'
+import { openDialog, closeDialog, canShowDialog } from '@/module-model/dialog'
+import loginCookie from '@/module-model/loginCookies'
+import { ScanCodeLoginDetection } from '@/utils/Login'
+import { doSetPageShareId } from '@/module-model/wxQrcode'
+import { getADInfo } from '@/module-model/loginLeftAd'
+import { clearAllStorageOfReg, trackReport } from '@/utils/common'
+import { ajaxSetSignOut } from '@/api'
+import LoginAuth from '@/lib/pluginLoginAuth'
+import core from '@/lib/core'
+import { dispatchCallback, transformResponse } from '@/lib/module'
+import { shareState, updateShareState } from '@/module-model/globalState'
+
+class PluginLogin {
+  hasInited: boolean
+  options: Record<string, any>
+  poll: any
+  emitter: any
+  constructor({ emitter }) {
+    this.hasInited = false
+    this.options = {}
+    this.emitter = emitter
+    this.poll = null
+    this.addListener()
+  }
+
+  addListener () {
+    // 登录成功后关闭轮询
+    this.emitter.$on('user-login-success', this.stop.bind(this))
+    // 更新全局用户状态
+    this.emitter.$on('user-info-update', this.setState.bind(this))
+  }
+
+  init(options) {
+    if (this.hasInited) {
+      console.warn('pluginLogin hasInited')
+      return
+    }
+    this.hasInited = true
+    this.options = Object.assign(
+      {
+        // 立即获取当前登录信息
+        preloadLoginState: true,
+        // 页面 num
+        pageNum: -1,
+        // 立即预加载弹窗左侧广告图片
+        preloadDialogImage: false,
+        // 自动打开弹窗
+        autoOpen: false,
+        type: 'login-code',
+        // 立即获取二维码并自动监听微信扫码登录
+        preloadWeChatImage: false
+      },
+      options
+    )
+
+    this.poll = null
+
+    if (this.options.preloadDialogImage) {
+      this.preload()
+    }
+
+    if (this.options.preloadLoginState) {
+      this.initPoll()
+      this.poll.preload()
+    }
+
+    if (this.options.preloadWeChatImage) {
+      this.start()
+    }
+
+    if (this.options.autoOpen) {
+      this.open(this.options.type)
+    }
+  }
+
+  /**
+   * 预加载
+   */
+  preload() {
+    // 预加载弹窗左侧广告
+    getADInfo()
+  }
+
+  /**
+   * 根据 type 打开弹窗并通知
+   * @param type - 类型
+   */
+  open(type = 'login-code') {
+    doChangeTabActive(type)
+    openDialog()
+    this.emit('open', type)
+  }
+
+  /**
+   * 关闭弹窗并通知
+   * @param type
+   */
+  close(type = '') {
+    closeDialog()
+    this.emit('close', type)
+  }
+
+  /**
+   * 尝试调用 options 配置的公共回调函数
+   * @param type - 函数名称
+   * @param data - 参数
+   */
+  emit(type, data = null) {
+    if (typeof this.options[type] === 'function') {
+      this.options[type](data)
+    } else {
+      console.warn('[plugin-login]: not find emit function:', type)
+    }
+  }
+
+  /**
+   * 初始化登录检查轮询器
+   */
+  initPoll() {
+    if (!this.poll) {
+      this.poll = new ScanCodeLoginDetection({
+        num: this.options.pageNum,
+        update: (type, data) => {
+          if (type === 'shareId') {
+            const { kopShareId, shareId } = data
+            doSetPageShareId(shareId, kopShareId)
+          }
+          if (type === 'login') {
+            this.emit('update', data)
+            this.handleUpdateInfo('poll', data)
+          }
+        },
+        success: (data) => {
+          this.emit('success', data)
+          this.handleUpdateInfo('poll', data)
+          this.handleSuccess('poll', data)
+        }
+      })
+    }
+  }
+
+  /**
+   * 开始轮询
+   */
+  start() {
+    this.initPoll()
+    this.poll.start()
+  }
+
+  /**
+   * 停止轮询
+   */
+  stop() {
+    this.poll?.stop()
+  }
+
+  /**
+   * 获取全局状态
+   */
+  getState() {
+    return shareState.value
+  }
+
+  setState ({ format }) {
+    if (format) {
+      updateShareState(format)
+    }
+  }
+
+  /**
+   * 退出登录
+   */
+  doSignOut() {
+    return ajaxSetSignOut().then(({ data }) => {
+      if (data === 'ok') {
+        clearAllStorageOfReg(/-login-clear/)
+        loginCookie.clear()
+        this.emitUserSignOut()
+      }
+    })
+  }
+
+  /**
+   * 处理信息相关更新
+   * @param type - 类型
+   * @param data
+   */
+  handleUpdateInfo (type, data) {
+    this.emitUserInfoUpdate(transformResponse(type, data))
+  }
+
+  /**
+   * 处理弹窗业务成功相关
+   * @param type - 类型
+   * @param data
+   */
+  handleSuccess (type, data) {
+    dispatchCallback(type, data)
+  }
+
+  /**
+   * 广播用户退出事件
+   */
+  emitUserSignOut () {
+    this.emitter.$emit('user-sign-out', {}, {
+      cross: true
+    })
+  }
+
+  /**
+   * 广播用户信息更新事件
+   * @param data - 用户信息
+   */
+  emitUserInfoUpdate (data) {
+    this.emitter.$emit('user-info-update', data, {
+      cross: true,
+      replay: true
+    })
+  }
+
+  /**
+   * 广播用户登录成功事件
+   * @param data
+   */
+  emitUserLoginSuccess (data) {
+    if (canShowDialog.value) {
+      this.close('user-login-success')
+    }
+    this.emitter.$emit('user-login-success', data, {
+      cross: true
+    })
+  }
+}
+
+const pluginLogin = new PluginLogin({
+  emitter: core
+})
+
+function addHook (hook) {
+  LoginAuth.register(hook, pluginLogin[hook].bind(pluginLogin))
+}
+
+// 注入 hooks
+['open', 'doSignOut', 'close', 'init', 'getState'].forEach(hook => addHook(hook))
+
+export default pluginLogin

+ 45 - 0
plugins/login-auth/src/lib/pluginLoginAuth.ts

@@ -0,0 +1,45 @@
+import { getScriptOptions } from '@/utils/common'
+
+const scriptOptions = getScriptOptions()
+
+class pluginLoginAuth {
+  name: string
+  options: any
+  hooks: Record<string, Function>
+  constructor (options = {}) {
+    this.name = 'login'
+    this.hooks = {}
+    this.options = Object.assign({
+      auto: false,
+      type: 'login-code'
+    }, scriptOptions, options)
+    if (this.options.auto) {
+      this.init()
+    }
+  }
+
+  init () {
+    // console.log('init', getScriptOptions())
+  }
+
+  use (context) {
+    context.$emit('register-plugin-login-auth', this, {
+      replay: true
+    })
+  }
+
+  getInstance () {
+    const hooks = this.hooks
+    return hooks
+  }
+  register (hook, fn) {
+    if (!this.hooks[hook]) {
+      this.hooks[hook] = fn
+    } else {
+      console.warn('not register hook:', hook)
+    }
+  }
+}
+
+const LoginAuth = new pluginLoginAuth()
+export default LoginAuth

+ 4 - 0
plugins/login-auth/src/lib/pre-hook.ts

@@ -0,0 +1,4 @@
+import core from './core'
+import LoginAuth from './pluginLoginAuth'
+
+core.use(LoginAuth)

+ 1 - 0
plugins/login-auth/src/main.ts

@@ -0,0 +1 @@
+import './lib/main'

+ 30 - 0
plugins/login-auth/src/module-model/autoLogin.ts

@@ -0,0 +1,30 @@
+import { Ref, ref } from 'vue'
+import { ajaxSetKeepLogin } from '@/api'
+import { pageInfo } from '@/module-model/globalState'
+
+/**
+ * 下次自动登录 选中状态
+ */
+const autoLoginState: Ref<boolean> = ref(false)
+
+/**
+ * 切换自动登录状态
+ * @param type
+ */
+function doSelectAutoLogin(type: boolean): void {
+  autoLoginState.value = type
+  doAjaxSet(type)
+}
+
+/**
+ * 请求上报
+ * @param type
+ */
+function doAjaxSet(type: boolean): void {
+  ajaxSetKeepLogin({
+    isAutoLogin: type,
+    loginER: pageInfo.shareId + '___' + pageInfo.kopShareId
+  })
+}
+
+export { autoLoginState, doSelectAutoLogin }

+ 111 - 0
plugins/login-auth/src/module-model/countDown.ts

@@ -0,0 +1,111 @@
+import { ref, Ref } from 'vue'
+
+interface CountdownTimerOptions {
+  delay?: number;
+  cacheKey?: string;
+}
+
+/**
+ * 倒计时
+ * - Ref countdown、isCounting
+ * - Fn start、stop
+ */
+class CountdownTimer {
+
+  delay: number;
+  cacheKey: string;
+  isCounting: Ref<boolean>;
+  countdown: Ref<number>;
+  countdownTimer: any;
+
+  constructor({ delay, cacheKey }: CountdownTimerOptions = {}) {
+    this.delay = delay || 59
+    this.cacheKey = cacheKey || 'sms-count-timer'
+    this.isCounting = ref(false)
+    this.countdown = ref(0)
+    this.countdownTimer = null
+
+    this.recoverCacheCountdown()
+  }
+
+  /**
+   * 对外提供调用
+   */
+  getInstance () {
+    return {
+      countdown: this.countdown,
+      isCounting: this.isCounting,
+      start: this.startCountdown.bind(this),
+      stop: this.stopTimer.bind(this)
+    }
+  }
+
+  /**
+   * 开始倒计时
+   */
+  startCountdown() {
+    if (!this.isCounting.value) {
+      if (this.cacheKey) {
+        localStorage.setItem(this.cacheKey, Date.now().toString())
+      }
+      this.countdown.value = this.delay
+      this.startTimer()
+    }
+  }
+
+  /**
+   * 恢复缓存倒计时
+   */
+  recoverCacheCountdown() {
+    if (this.cacheKey && localStorage.getItem(this.cacheKey)) {
+      const cacheDelay = this.calcCountdown(
+        parseInt(localStorage.getItem(this.cacheKey))
+      )
+      if (cacheDelay) {
+        this.countdown.value = cacheDelay
+        this.startTimer()
+      }
+    }
+  }
+
+  /**
+   * 计算倒计时,如果超过60秒则不再计算
+   * @param start - 需要与当前时间对比的开始时间,ms
+   */
+  calcCountdown(start) {
+    const startTime = parseInt(start) || Date.now()
+    const diffTime = Math.ceil((Date.now() - startTime) / 1000)
+
+    if (diffTime > 0 && diffTime <= this.delay) {
+      return this.delay - diffTime
+    }
+    return 0
+  }
+
+  /**
+   * 开始倒计时
+   */
+
+  startTimer() {
+    this.isCounting.value = true
+    this.countdownTimer = setInterval(() => {
+      this.countdown.value--
+      if (this.countdown.value <= 0) {
+        this.isCounting.value = false
+        clearInterval(this.countdownTimer)
+        if (this.cacheKey) {
+          localStorage.removeItem(this.cacheKey)
+        }
+      }
+    }, 1000)
+  }
+
+  /**
+   * 停止倒计时
+   */
+  stopTimer() {
+    clearInterval(this.countdownTimer)
+  }
+}
+
+export default CountdownTimer

+ 15 - 0
plugins/login-auth/src/module-model/dialog.ts

@@ -0,0 +1,15 @@
+import { ref, Ref } from 'vue'
+
+/**
+ * 弹窗状态管理
+ */
+const canShowDialog: Ref<boolean> = ref(false)
+
+function openDialog() {
+  canShowDialog.value = true
+}
+function closeDialog() {
+  canShowDialog.value = false
+}
+
+export { canShowDialog, openDialog, closeDialog }

+ 32 - 0
plugins/login-auth/src/module-model/globalState.ts

@@ -0,0 +1,32 @@
+import { computed, reactive, ref } from 'vue'
+import { tabActive } from '@/module-model/tab'
+import { canShowDialog } from '@/module-model/dialog'
+import { pageShareId, pageKopShareId } from '@/module-model/wxQrcode'
+const shareState = ref({
+  isLogin: false,
+  userInfo: {
+    openId: '',
+    userAvatar: '',
+    userName: '',
+    userPhone: ''
+  }
+})
+
+function updateShareState (state) {
+  shareState.value = state
+}
+
+const pageInfo = reactive({
+  pageNum: '',
+  shareId: pageShareId,
+  kopShareId: pageKopShareId
+})
+
+const dialogInfo = computed(() => {
+  return {
+    open: canShowDialog.value,
+    type: tabActive.value
+  }
+})
+
+export { shareState, updateShareState, pageInfo, dialogInfo }

+ 2535 - 0
plugins/login-auth/src/module-model/login-test.js

@@ -0,0 +1,2535 @@
+/**统一登录js文件**/
+var loginfg = '' //websocket请求标识
+var bIE9 = false
+if (
+  navigator.appName == 'Microsoft Internet Explorer' &&
+  navigator.appVersion.match(/[6789]./i)
+) {
+  bIE9 = true
+}
+var wsUrl =
+  'ws' +
+  (!bIE9 && 'https:' == document.location.protocol ? 's' : '') +
+  '://' +
+  window.location.host +
+  '/ws'
+var ws = null
+var openid = ''
+var jylgi = 0
+var loginflag = false //登录状态
+var mynum = '' //页面参数num
+var keysorpname = '' //项目名称
+var thurl = '' //url
+var semnum = '' //SEM
+var ldpnum = '' //落地页扫码后调整标识
+var ldmold = '' //落地页扫码后调整标识
+var pageshareid = ''
+var kopshareid = ''
+var oldshareid = ''
+var encryptId = null
+var qr_type = 's'
+var unseatflag = false //未登录情况下,用户点击超级搜索等开启按钮或者功能,根据此状态看是否弹出二维码
+var unseatzbqyflag = false //未登录情况下,用户点击中标企业等开启按钮或者功能,根据此状态看是否弹出二维码
+var sendMsgInterval = null
+var entjumpflag = false
+var isBindPage = false // 是否是绑定手机号页面功能
+//轮询查询
+var LoginPolling = {
+  isPostLoginPolling: true, //是否发起轮询请求
+  loginPollingInterval: null,
+  initInterval: null,
+  init: function () {
+    //防止重复调用
+    if (this.initInterval != null) {
+      return
+    }
+    //先发一个消息,保存session
+    this.postShareid()
+    this.initInterval = setInterval(this.postShareid, 3000)
+  },
+  postShareid: function () {
+    if (WSpolling.isPageHidden || pageshareid == '' || kopshareid == '') {
+      return
+    }
+    $.ajax({
+      type: 'POST',
+      url: '/front/ajaxPolling',
+      data: { reqType: 1, shareIds: pageshareid + '___' + kopshareid },
+      dataType: 'json',
+      timeout: 3000,
+      success: function (r) {
+        clearInterval(LoginPolling.initInterval)
+        LoginPolling.initInterval = null
+      }
+    })
+  },
+  start: function () {
+    //防止重复调用
+    if (this.loginPollingInterval != null) {
+      return
+    }
+    this.init()
+    //定时器,定时请求看是否扫码登录,返回用户信息,登录
+    this.loginPollingInterval = setInterval(function () {
+      //如果浏览器不支持webscoket,走ajax轮询方式
+      if (WSpolling.isPageHidden || !LoginPolling.isPostLoginPolling) {
+        return
+      }
+      $.ajax({
+        type: 'POST',
+        url: '/front/ajaxPolling',
+        data: { reqType: 2 },
+        dataType: 'json',
+        timeout: 3000,
+        success: function (r) {
+          if (!jQuery.isEmptyObject(r)) {
+            logic(r, mynum)
+          }
+        }
+      })
+    }, 5000)
+  },
+  stop: function () {
+    clearInterval(this.loginPollingInterval)
+    this.loginPollingInterval = null
+    this.isPostLoginPolling = false
+    this.initInterval = null
+  }
+}
+var webSocketHeartCheck = new WebSocketHeartCheck(LoginPolling)
+//创建websocket连接
+var createWebSocket = function () {
+  if ('WebSocket' in window) {
+    try {
+      ws = new WebSocket(wsUrl) //实例化websocket对象
+      initEventHandle()
+    } catch (e) {
+      reconnect()
+      //console.log(e)
+    }
+  } else {
+    LoginPolling.isPostLoginPolling = true
+  }
+}
+//
+var initEventHandle = function () {
+  ws.onmessage = function (e) {
+    //接收消息正常,就不再发ajax轮询
+    LoginPolling.isPostLoginPolling = false
+    if (e.data == '') {
+      return
+    } else if (e.data == 'HeartBeat') {
+      //心跳检测
+      //如果获取到消息,心跳检测重置
+      //拿到任何消息都说明当前连接是正常的
+      webSocketHeartCheck.reset().start(ws, loginflag)
+      return
+    }
+    //用户登录
+    logic($.parseJSON(e.data), mynum)
+  }
+  ws.onerror = function (e) {
+    //console.info("onerror");
+    reconnect()
+  }
+  ws.onclose = function (e) {
+    //console.info("onclose");
+    reconnect()
+  }
+  ws.onopen = function (e) {
+    SendMsg()
+    //心跳检测重置
+    webSocketHeartCheck.reset().start(ws, loginflag)
+  }
+}
+// 更新头像/昵称/手机号等信息
+function updateUserInfo(data) {
+  if (data.update) {
+    $.post('/jypay/user/getSimpleData', {}, function (result) {
+      if (result && result.userId) {
+        var userName = result.name
+          ? result.name === result.phone
+            ? ''
+            : result.name
+          : ''
+        updateUserInfo({
+          update: false,
+          name: userName,
+          phone: result.phone,
+          avatar: result.headImage || ''
+        })
+      }
+    })
+  }
+  $('#public-nav *[data-user-name]').text(data.name || '')
+  $('#public-nav *[data-user-phone]').text(data.phone || '')
+  $('#public-nav img[data-user-avatar]').attr(
+    'src',
+    data.avatar || '/common-module/public/image/auto.png'
+  )
+  $('#public-nav img[data-user-avatar]').on('error', function () {
+    if (
+      $(this).attr('src').indexOf('/common-module/public/image/auto.png') === -1
+    ) {
+      $(this).attr('src', '/common-module/public/image/auto.png')
+    }
+  })
+}
+// 切换登录/未登录展示元素
+function toggleLoginDom(type) {
+  if (type) {
+    $('#login .loginBtn').hide()
+    $('#public-nav .nav-avatar').show()
+    $('#public-nav .work-link').show()
+    $('#public-nav .fl').addClass('fix-work')
+    // 客服入口显示
+    $('#go-customer-4').show()
+  } else {
+    $('#public-nav .nav-avatar').hide()
+    $('#public-nav .work-link').hide()
+    $('#public-nav .fl').removeClass('fix-work')
+    $('#login .loginBtn').show()
+    // 客服入口隐藏
+    $('#go-customer-4').hide()
+  }
+}
+//
+function reconnect() {
+  if (webSocketHeartCheck.lockReconnect || loginflag) {
+    return
+  }
+  LoginPolling.isPostLoginPolling = true
+  webSocketHeartCheck.lockReconnect = true
+  LoginPolling.init()
+  //没连接上会一直重连,设置延迟避免请求过多
+  setTimeout(function () {
+    createWebSocket()
+    webSocketHeartCheck.lockReconnect = false
+  }, 2000)
+}
+//websocket查看用户是否登录
+var JYLogin = function (num) {
+  clearInterval(loginfg)
+  loginfg = setInterval(function () {
+    jylgi++
+    //console.log(jylgi+"-----")
+    if (jylgi > 120 * 60) {
+      getNewShareId(num, false)
+      jylgi = 0
+    }
+  }, 1000)
+}
+var SendMsg = function () {
+  if (pageshareid == '' || kopshareid == '') {
+    return
+  }
+  if (ws != null && ws.readyState == 1) {
+    //console.log("发送:"+pageshareid+"___"+kopshareid)
+    ws.send(pageshareid + '___' + kopshareid)
+  } else {
+    LoginPolling.isPostLoginPolling = true
+  }
+}
+//生成页面二维码,不同页面处理逻辑
+var getNewShareId = function (num, isFirst) {
+  mynum = num
+  pageType = 'T'
+  var rref = document.referrer
+  if (localStorage.getItem('oldshareid') != null) {
+    oldshareid = localStorage.getItem('oldshareid')
+  }
+  //console.log("num:"+num)
+  $.post(
+    '/front/getLoginNum/' + num,
+    { rref: rref, oid: oldshareid },
+    function (data) {
+      if ($('#bidLogin').attr('data-rec') == 'sjdc') {
+        window.location.href = '/front/dataExport/toSieve'
+        return
+      }
+      if (data && data.num) {
+        pageshareid = data.num
+        kopshareid = data.numot
+        mynum = num
+        if (!loginflag) {
+          if (isFirst) {
+            LoginPolling.start()
+            createWebSocket()
+          } else if (!isFirst) {
+            LoginPolling.init()
+            SendMsg()
+          }
+        }
+        localStorage.setItem('oldshareid', pageshareid)
+        //redisUserInfo(pageshareid,kopshareid);
+        $('.jyhead_qr img').attr('src', '/front/share/' + pageshareid)
+        $('#bottomimg').attr('src', '/front/share/' + pageshareid)
+        $('*[data-share-img]').attr('src', '/front/share/' + pageshareid)
+        $('#layerImg-login').attr('src', '/front/share/' + pageshareid)
+        $('#layerImg-zbsq').attr('src', '/front/share/' + pageshareid)
+        switch (num) {
+          case '10': //首页
+            //$("#layerImg").attr("src","/front/share/"+pageshareid);
+            //$("#sy-shareimg img").attr("src","/front/share/"+pageshareid);
+            $('.wxlinkdiv').attr('src', '/front/share/' + pageshareid)
+            break
+          case '11': //订阅页面
+            $('#vipCode').attr('src', '/front/share/' + kopshareid)
+            break
+          case '12': //搜索列表页
+            $('#layerImg').attr('src', '/front/share/' + pageshareid)
+            $('#wxCode').attr('src', '/front/share/' + pageshareid)
+            $('#keyImg').attr('src', '/front/share/' + kopshareid)
+            if (keysorpname != undefined && keysorpname != '') {
+              var ref = document.referrer
+              if (
+                (ref != '' && ref.indexOf('jianyu360.com') < 0) ||
+                ref.indexOf('qmx.top') < 0
+              ) {
+                $.post('/front/rediskw', { skw: keysorpname, num: kopshareid })
+              }
+            }
+            break
+          case '13':
+          case '130': //快照页
+            $('#layerImg').attr('src', '/front/share/' + pageshareid)
+            $('#wxCode').attr('src', '/front/share/' + kopshareid)
+            //生成二维码
+            if (keysorpname != undefined && keysorpname != '') {
+              $.post('/front/rediskw', { skw: keysorpname, num: kopshareid })
+            }
+            break
+          case '14': //标签页面
+            $('#bottomimg').attr('src', '/front/share/' + pageshareid)
+            $('*[data-share-img]').attr('src', '/front/share/' + pageshareid)
+            $('#layerImg').attr('src', '/front/share/' + pageshareid)
+            $('#keyImg').attr('src', '/front/share/' + pageshareid)
+            break
+          case '15': //博客列表和内容页面
+            break
+          case '16': //关于我们页面
+            break
+          case '18': //扫码关注企业18
+            $('#layerImg').attr('src', '/front/share/' + pageshareid)
+            var company = $.trim($("#zbSeatchT input[name='keywords']").val())
+            if (company != '' && company != null && company.length > 0) {
+              $('#keyImg').attr('src', '/front/share/' + kopshareid)
+              $.post('/front/rediskw', { skw: company, num: kopshareid })
+            } else {
+              $('#keyImg').attr('src', '/front/share/' + pageshareid)
+            }
+            break
+          case '19': //拟建项目
+            $('#layerImg').attr('src', '/front/share/' + pageshareid)
+            $('#wxCode').attr('src', '/front/share/' + pageshareid)
+            $('#keyImg').attr('src', '/front/share/' + kopshareid)
+            if (keysorpname != undefined && keysorpname != '') {
+              $.post('/front/rediskw', { skw: keysorpname, num: kopshareid })
+            }
+            break
+          case '17': //1808新落地页
+            $('.ewm1').attr('src', '/front/share/' + pageshareid)
+            $('.ewm2').attr('src', '/front/share/' + kopshareid)
+            $('#kwewm').attr('src', '/front/share/' + kopshareid)
+            $('.ecode_img img')
+              .attr('src', '/front/share/' + kopshareid)
+              .css('display', '')
+            break
+          case '23': //数据导出
+            break
+        }
+        JYLogin(num)
+      }
+    },
+    'json'
+  )
+}
+//
+var redisUserInfo = function (pid, kid) {
+  var rurl = window.location.href
+  var rref = document.referrer
+  if (localStorage.getItem('oldshareid') != null) {
+    oldshareid = localStorage.getItem('oldshareid')
+  }
+  $.post(
+    '/front/followinfo',
+    { pid: pid, kid: kid, rurl: rurl, rref: rref, oid: oldshareid },
+    function (data) {
+      if (data && data.result == 'ok') {
+        localStorage.setItem('oldshareid', pid)
+      }
+    }
+  )
+}
+function checkBigStatus() {
+  $.ajax({
+    type: 'post',
+    url: '/bigmember/use/isAdd',
+    success: function (res) {
+      if (res && res.data) {
+        window.memberStatus = res.data.memberStatus
+        window.memberPower = res.data.power
+        window.vipStatus = res.data.vipStatus // 是否是超级订阅用户
+        window.isFree = res.data.isFree // 是否是免费用户
+        window.freeFile = res.data.freeFile // 免费用户 是否体验过 0:未体验过 -1:体验过
+        window.viper = res.data.viper // 是否是超级订阅老用户 false:老用户 true: 新用户
+        window.entniche = res.data.entniche // 商机管理用户
+        window.fileNum = res.data.fileNum // 超级订阅用户可下载附件次数
+        window.isLogin = true // 用于其他页面判断是否已登录
+        window.isNewEntNiche = res.data.entIsNew
+        window.isEntService = res.data.isEntService
+        sessionStorage.setItem('bidPower', JSON.stringify(res.data.power))
+        if (res.data.memberStatus > 0) {
+          $('.myorderDiv.lastBox').show()
+        }
+        if (res.data.viper) {
+          $('.myorderDiv.ent-search').show()
+        }
+        if (
+          res.data.power.indexOf(4) == -1 &&
+          res.data.vipStatus > 0 &&
+          res.data.viper
+        ) {
+          $('.myorderDiv.entPortraitRecord').show()
+        }
+        if (
+          res.data.power.indexOf(5) == -1 &&
+          res.data.vipStatus > 0 &&
+          res.data.viper
+        ) {
+          $('.myorderDiv.buyerPortraitRecord').show()
+        }
+        if (
+          res.data.memberStatus <= 0 &&
+          res.data.vipStatus > 0 &&
+          res.data.viper
+        ) {
+          $('.myorderDiv.portraitRecord').show()
+        }
+        if (
+          res.data.memberStatus > 0 &&
+          res.data.vipStatus > 0 &&
+          res.data.viper &&
+          res.data.power.indexOf(3) === -1
+        ) {
+          $('.fileRecord').show()
+        }
+
+        if (
+          res.data.memberStatus <= 0 &&
+          res.data.vipStatus > 0 &&
+          res.data.viper
+        ) {
+          $('.fileRecord').show()
+        }
+
+        if ($.isArray(res.data.power)) {
+          // 大会员没有附加下载包权限用户且新版超级订阅用户
+          if (
+            res.data.memberStatus > 0 &&
+            res.data.vipStatus > 0 &&
+            res.data.viper &&
+            res.data.power.indexOf(3) === -1
+          ) {
+            $('.fileRecord').show()
+          }
+        }
+      }
+    },
+    complete: function () {
+      try {
+        getPowerComplete && getPowerComplete()
+      } catch (error) {}
+    }
+  })
+}
+// 查询商机管理PC权限
+function checkMenuForEnt() {
+  $.ajax({
+    type: 'get',
+    url: '/entbase/ent/mySelectent?t=' + new Date().getTime(),
+    success: function (er) {
+      $.ajax({
+        type: 'get',
+        url: '/front/entExportAuth/getAuth?t=' + new Date().getTime(),
+        success: function (r) {
+          $('.myorderDiv[data-ent-menu]').remove()
+          var tempHtml = ''
+          if (er.data != null && er.data.status == 1) {
+            tempHtml +=
+              '<div data-ent-menu class="myorderDiv" onclick="window.location.href=\'/orgpc/myent\'">' +
+              '<span>我的企业</span>' +
+              '</div>'
+          }
+          if (r.entnicheMenu == true) {
+            if (r.isNew == true) {
+              tempHtml +=
+                '<div data-ent-menu class="myorderDiv" id="entDiv">' +
+                '<span>商机管理</span>' +
+                '</div>'
+            } else {
+              tempHtml +=
+                '<div data-ent-menu id="entDiv" class="myorderDiv">' +
+                '<span>商机管理</span>' +
+                '</div>'
+            }
+          }
+          if (r.privatedata) {
+            tempHtml +=
+              '<div data-ent-menu class="myorderDiv" onclick="window.location.href=\'/swordfish/page_big_pc/free/custom_search\'">' +
+              '<span>画像分析系统</span>' +
+              '</div>'
+          }
+          $('.infoList .lastBox').before(tempHtml)
+          $('#entDiv').click(function () {
+            $.ajax({
+              type: 'POST',
+              url: '/entnicheNew/buy/whetherbuy',
+              success: function () {
+                if (r.entnicheMenu == true) {
+                  if (r.isNew == true) {
+                    window.location.href = '/entpc/newBus'
+                  } else {
+                    window.location.href = '/entpc/bus'
+                  }
+                }
+              }
+            })
+          })
+        }
+      })
+    }
+  })
+}
+var msgTimer = null
+function toReaded(ids, type, url) {
+  var _this = this
+  $.ajax({
+    type: 'POST',
+    url: '/jymessageCenter/markRead',
+    data: {
+      msgId: ids,
+      msgType: type
+    },
+    success: function () {
+      if (url) {
+        location.href = url
+      } else {
+        return
+      }
+    }
+  })
+}
+
+/**
+ * @date 2023/1/4 消息通知改为 webscoket 获取并调用浏览器消息通知
+ */
+// 查看是否有新消息
+function checkCounts() {
+  try {
+    // 非工作台模式下需要重建链接,工作台嵌入页面不需要额外初始化
+    if (!goTemplateData.inIframe) {
+      getMsgBuoyActive.listenNotification()
+    }
+  } catch (e) {}
+}
+
+//查询用户信息,响应页面登录信息
+var logic = function (data, num) {
+  if (data.result == 'ok') {
+    //判断是否需要设置cookie
+    if (data.cValue) {
+      afterLoginSetCookit(data.cName, data.cValue, data.expires)
+    }
+    // TODO login callback
+    try {
+      loginCallback()
+    } catch (e) {}
+    clearLoginStorage(/-login-clear/)
+    //$(".QRLogin").hide();
+    $('#bidLogin').modal('hide')
+    $('#bidcommunity').modal('hide')
+    clearInterval(loginfg)
+    loginflag = true
+    if (!data.phone && data.openid) {
+      window.location.href = '/swordfish/frontPage/userMerge/sess/bind'
+    }
+    processpage(data, num)
+    //登录成功,停止轮询
+    LoginPolling.stop()
+    //登录成功,停止心跳监测
+    webSocketHeartCheck.reset()
+    if (ws.readyState == 1) {
+      ws.send('close')
+      ws.close()
+    }
+    encryptId = data.encryptId
+    if (data.s_nickname.length > 11) {
+      data.s_nickname = data.s_nickname.substring(0, 11)
+      data.s_nickname = data.s_nickname + '...'
+    }
+    toggleLoginDom(true)
+    updateUserInfo({
+      update: true,
+      name: data.s_nickname || '',
+      phone: '',
+      avatar: data.s_headimage || ''
+    })
+    var skipInit = location.href.indexOf('/notin/page') !== -1
+    if (!skipInit && typeof window.GuideIntroDialog === 'function') {
+      window.guideIntroDialog = new GuideIntroDialog()
+    }
+    try {
+      checkBigStatus()
+      infoListCss()
+      message.init()
+      checkCounts()
+      if (typeof window.initIndexMsgList === 'function') {
+        initIndexMsgList()
+      }
+    } catch (e) {
+      console.warn(e)
+    }
+  }
+}
+
+//登录后处理页面逻辑
+var processpage = function (item, num) {
+  var backToUrl = getParam('backTo')
+  if (backToUrl) {
+    return location.replace(decodeURIComponent(backToUrl))
+  }
+  if (document.referrer === location.href) {
+    return location.replace('/')
+  }
+  var toHref = $('#bidLogin').attr('data-rec')
+  switch (toHref) {
+    case 'sjdc':
+      window.location.href = '/front/dataExport/toSieve'
+      return
+    case 'jydocs':
+      window.location.href = '/swordfish/docs'
+      return
+  }
+  // 未登录标签页注册后重定向首页
+  if (location.href.indexOf('/tags/') > -1) {
+    window.location.replace('/')
+  } else if (location.href.indexOf('/nologin/content') > -1) {
+    // 未登录三级页注册后刷新(后端重定向到登陆后的三级页)
+    window.location.reload()
+  }
+  clearInterval(loginfg)
+  switch (num) {
+    case '10': //10首页
+      var ful = $('#myModal').attr('aria-hidden')
+      if (ful == 'true') {
+        break
+      }
+      $('#myModal').modal('hide')
+      //			if(dataListId!=""){
+      //				setTimeout(function(){
+      //					window.open("/article/content/"+dataListId+".html");
+      //				},500)
+      //			}
+      break
+    case '11': //11订阅页面
+      //$("#myModal-01").click();
+      $('.modal').click()
+      break
+    case '12': //12搜索列表
+      var ful = $('#myModal').attr('aria-hidden')
+
+      if (ful == 'true') {
+        break
+      }
+
+      $('#myModal').modal('hide')
+      $('#labModal').modal('hide')
+      if (dataId != '') {
+        setTimeout(function () {
+          //$('a[dataId="'+ dataId +'"]').click();
+          var aHref = ''
+          if (searchvalue != '') {
+            aHref += '.html?kds=' + searchvalue
+          } else {
+            aHref += '.html'
+          }
+          window.open('/article/content/' + dataId + aHref)
+        }, 500)
+      }
+      break
+    case '13':
+    case '130': //13快照页
+      if (thurl != '' && thurl != 'D') {
+        window.location.href = thurl
+      } else if (thurl == '') {
+        window.location.href = '/'
+      }
+      break
+    case '14': //14标签页面
+      var ful = $('#myModal').attr('aria-hidden')
+      if (ful == 'true') {
+        break
+      }
+      $('#myModal').click()
+      if (dataId != '') {
+        setTimeout(function () {
+          window.open('/article/content/' + dataId + '.html')
+        }, 500)
+      }
+      break
+    case '15': //15剑鱼标讯博客页面
+      break
+    case '16': //关于我们页面16
+      break
+    case '18': //中标企业搜索
+      var ful = $('#myModal').attr('aria-hidden')
+      if (ful == 'true') {
+        break
+      }
+      $('#myModal').modal('hide')
+      $('#labModal').modal('hide')
+      if (dataId != '') {
+        setTimeout(function () {
+          //$('a[dataId="'+ dataId +'"]').click();
+          var aHref = ''
+          if (searchvalue != '') {
+            aHref += '.html?kds=' + searchvalue
+          } else {
+            aHref += '.html'
+          }
+          window.open('/article/content/' + dataId + aHref)
+        }, 500)
+      }
+      break
+      break
+    case '19': //拟建项目
+      var ful = $('#myModal').attr('aria-hidden')
+      if (ful == 'true') {
+        break
+      }
+      $('#myModal').modal('hide')
+      $('#labModal').modal('hide')
+      if (dataId != '') {
+        setTimeout(function () {
+          var aHref = ''
+          if (searchvalue != '') {
+            aHref += '.html?kds=' + searchvalue
+          } else {
+            aHref += '.html'
+          }
+          window.open('/article/content/' + dataId + aHref)
+        }, 500)
+      }
+      break
+    case '17': //落地页
+      $('#bidLogin').modal('hide')
+      $('.close').click()
+      if (ldpnum == '0') {
+        window.open('/jylab/supsearch/index.html', '_self')
+      } else if (ldpnum == '1') {
+        window.open('/front/subscribe.html', '_self')
+      } else if (ldpnum == '2') {
+        window.open('/jylab/supsearch/proposedProject.html', '_self')
+      } else if (ldpnum == '3') {
+        if (ldmold != '') {
+          window.open('/list/stype/' + ldmold + '.html', '_self')
+        } else {
+          window.open('/jylab/supsearch/index.html', '_self')
+        }
+      } else if (ldpnum == '4') {
+        if (ldmold != '') {
+          window.open('/list/area/' + ldmold + '.html', '_self')
+        } else {
+          window.open('/jylab/supsearch/index.html', '_self')
+        }
+      } else if (ldpnum == '5') {
+        if (ldmold) {
+          window.open('/article/content/' + ldmold + '.html')
+        } else {
+          window.open('/jylab/supsearch/index.html')
+        }
+      } else if (ldpnum == '6') {
+        window.open('/front/dataExport/toSieve')
+      }
+      break
+    case '24': //百度SEM-p 快照页推广-落地页
+      window.open(semHref, '_self')
+      break
+  }
+}
+
+/**
+ * 检查是否需要前往新用户兴趣设置
+ * @returns {boolean}
+ */
+function checkNeedGoNewUserSettingPage() {
+  // 同步请求判断是否新用户,需要跳转兴趣设置页面
+  var goPage
+  $.ajax({
+    type: 'post',
+    async: false,
+    url: '/salesLeads/appIsNewUerSales',
+    success: function (res) {
+      if (res && res.data) {
+        goPage = '/swordfish/frontPage/user/sess/set_favorite'
+      }
+    }
+  })
+  if (goPage) {
+    window.open(goPage)
+    return true
+  }
+  return false
+}
+
+function clearObjKeyForRegFn(obj, reg) {
+  if (obj) {
+    for (var k in obj) {
+      if (reg.test(k)) {
+        obj.removeItem(k)
+      }
+    }
+  }
+}
+
+function clearLoginStorage(reg) {
+  clearObjKeyForRegFn(sessionStorage, reg)
+  clearObjKeyForRegFn(localStorage, reg)
+}
+
+var removeLocalStorage = function () {
+  // 移除userId (大会员中标预测历史记录用到)
+  localStorage.removeItem('BIGMEMBER_PC')
+}
+
+//退出登录
+var signout = function () {
+  clearInterval(loginfg)
+  loginflag = false
+  unseatflag = false
+  unseatzbqyflag = false
+  toggleLoginDom(false)
+  loginBtnType()
+  $('.control-tabBtn>a:first>font').text('招标搜索')
+  $('.control-tabBtn>a:eq(2)').addClass('hidden')
+  $('.control-tabBtn>a:eq(3)').addClass('hidden')
+  $('.superSearch').show()
+  $.post('/front/signOut', function (data) {
+    if (data == 'ok') {
+      $('#noticed').hide()
+      clearLoginStorage(/-login-clear/)
+      afterSignoutClearCookit()
+      // window.location.href="/";
+      var pt = new RegExp(
+        '^/article/content/.+$|^/front/dataExport/.+$|^/front/common(Footer|Header)|^/front/course/codePay$|^/front/course/orderPay$|^/entpc/.+$|^/bid/pc/page/.+$'
+      )
+      if (pt.test(window.location.pathname)) {
+        window.location.href = '/'
+      } else {
+        window.location.reload()
+        /*LoginPolling.start();
+				createWebSocket();
+				getNewShareId(mynum,true);*/
+      }
+      window.localStorage.removeItem('bus-key-group-SCOPE')
+      window.localStorage.removeItem('noMesg')
+      clearInterval(msgTimer)
+      // 移除浏览器缓存
+      removeLocalStorage()
+    }
+  })
+}
+
+var afterSignoutClearCookit = function () {
+  try {
+    $.cookie('userid_secure', '', {
+      expires: -1,
+      path: '/',
+      domain: document.domain.replace(/[^.]+/, '')
+    })
+    $.cookie('klcn_value', '', {
+      expires: -1,
+      path: '/',
+      domain: document.domain.replace(/[^.]+/, '')
+    })
+  } catch (e) {
+    document.cookie = 'userid_secure=;expires=-1;path=/'
+    document.cookie = 'klcn_value=;expires=-1;path=/'
+  }
+}
+
+var afterLoginSetCookit = function (name, value, time) {
+  var expires = new Date(time)
+  try {
+    $.cookie(name, value, {
+      expires: expires.toGMTString(),
+      path: '/',
+      domain: document.domain.replace(/[^.]+/, '')
+    })
+  } catch (e) {
+    document.cookie =
+      name +
+      '=' +
+      value +
+      ';expires=' +
+      expires.toGMTString() +
+      ';path=/;domain=' +
+      document.domain.replace(/[^.]+/, '')
+  }
+}
+
+//查看用户是否已经登录
+var haslogin = function (num, kyorpn, url) {
+  mynum = num //页面logid
+  keysorpname = kyorpn //其他参数
+  thurl = url //列表也跳转快照页url
+  $.post('/front/hasSign', function (data, location) {
+    if (data) {
+      if (data.resetpwd) {
+        afterSignoutClearCookit()
+        window.location.href = '/?nol=2'
+        return
+      }
+
+      loginflag = true
+      // TODO login callback
+      try {
+        loginCallback()
+      } catch (e) {}
+
+      encryptId = data.encryptId
+      if (data.s_nickname != null && data.s_nickname.length > 11) {
+        data.s_nickname = data.s_nickname.substring(0, 11)
+        data.s_nickname = data.s_nickname + '...'
+      }
+      toggleLoginDom(true)
+      updateUserInfo({
+        update: true,
+        name: data.s_nickname || '',
+        phone: '',
+        avatar: data.s_headimage || ''
+      })
+      try {
+        checkBigStatus()
+        infoListCss()
+        message.init()
+        checkCounts()
+        if (typeof window.initIndexMsgList === 'function') {
+          initIndexMsgList()
+        }
+      } catch (e) {
+        console.error(e)
+      }
+    } else {
+      toggleLoginDom(false)
+      loginBtnType()
+      //pc限制登陆
+      var nosess = getParam('nol')
+      if (nosess && !loginflag) {
+        openLoginDig()
+      }
+      window.localStorage.setItem('noMesg', 0)
+    }
+    getNewShareId(num, true)
+  })
+}
+function loginBtnType() {
+  var href = window.location.pathname
+  var curTheme = $('#public-nav').attr('data-theme')
+  if (
+    href == '/' ||
+    href.indexOf('subscribe') > -1 ||
+    href.indexOf('advservices') > -1 ||
+    href.indexOf('solution') > -1 ||
+    href.indexOf('partner') > -1 ||
+    href.indexOf('aboutus') > -1 ||
+    href.indexOf('busicooperation') > -1 ||
+    href.indexOf('pcindex.html') > -1 ||
+    window.location.pathname === '/jyxspc/' ||
+    window.location.pathname === '/entpc/'
+  ) {
+    if (curTheme == 'dark') {
+      $('.loginBtn').attr(
+        'onmouseover',
+        "this.style.borderColor='#2cb7ca'; this.style.color='#2cb7ca';"
+      )
+      $('.loginBtn').attr(
+        'onmouseout',
+        "this.style.borderColor='#fff'; this.style.color='#fff';"
+      )
+    } else {
+      $('.loginBtn').css({
+        'border-color': '#e0e0e0',
+        color: 'rgb(37, 38, 39)'
+      })
+      $('.loginBtn').attr(
+        'onmouseover',
+        "this.style.borderColor='#2cb7ca'; this.style.color='#2cb7ca';"
+      )
+      $('.loginBtn').attr(
+        'onmouseout',
+        "this.style.borderColor='#e0e0e0'; this.style.color='#252627';"
+      )
+    }
+  } else if (href.indexOf('topics') > -1) {
+    $('.loginBtn').css({ border: 'none' })
+  } else {
+    $('.loginBtn').css({ 'border-color': '#e0e0e0', color: 'rgb(37, 38, 39)' })
+    $('.loginBtn').attr(
+      'onmouseover',
+      "this.style.borderColor='#2cb7ca'; this.style.color='#2cb7ca';"
+    )
+    $('.loginBtn').attr(
+      'onmouseout',
+      "this.style.borderColor='#e0e0e0'; this.style.color='#252627';"
+    )
+  }
+}
+///////////////////////////////
+
+// ajax部分匿名函数自执行,防止泄露全局变量
+$(function () {
+  function goBackOrigin(cb) {
+    var backOrigin = $.cookie('article')
+    if (backOrigin) {
+      location.replace(backOrigin)
+    } else {
+      typeof cb === 'function' ? cb() : window.close()
+    }
+  }
+  var Direct = {
+    verify: {},
+    forge: {},
+    loginInfo: {},
+    instance: {},
+    ajaxSms: function (e, type) {
+      var _this = this
+      switch (type) {
+        case 'verify': {
+          //手机号验证码登录 - 发送登录短信验证码
+          $.post(
+            '/phone/login',
+            {
+              reqType: 'sendIdentCode',
+              phone: $(
+                "#bidLogin .login-dig-input-box [name='verify_phone']"
+              ).val(),
+              // isAutoLogin: $('.sms-login .auto-login-checkbox').hasClass('checked'),
+              code: $(
+                "#bidLogin .login-dig-input-box [name='verify_code']"
+              ).val()
+            },
+            function (r) {
+              if (r.status == -1) {
+                _this.verify.phone.showError('手机号格式错误')
+              } else if (r.status == -2) {
+                //图形验证码错误
+                _this.verify.code.showError('图形验证码输入错误')
+                $('#bidLogin .verify-img').attr(
+                  'src',
+                  '/front/landpage/captcha?v=' + new Date().getTime()
+                )
+              } else if (r.status == -3) {
+                //图形验证码错误
+                _this.verify.phone.showError('手机号已被注册')
+                $('#bidLogin .verify-img').attr(
+                  'src',
+                  '/front/landpage/captcha?v=' + new Date().getTime()
+                )
+              } else {
+                sessionStorage.setItem(
+                  'login-verify-start-time',
+                  new Date().getTime()
+                )
+                startTimeDown(type)
+              }
+            }
+          )
+          break
+        }
+        case 'register': {
+          //手机号验证码登录(注册) - 发送登录短信验证码
+          $.post(
+            '/phone/login',
+            {
+              reqType: 'sendIdentCode',
+              register: 'true',
+              phone: $(
+                ".register-form-box .login-dig-input-box [name='register_phone']"
+              ).val(),
+              // isAutoLogin: $('.sms-login .auto-login-checkbox').hasClass('checked'),
+              code: $(
+                ".register-form-box .login-dig-input-box [name='register_code']"
+              ).val()
+            },
+            function (r) {
+              if (r.status == -1) {
+                _this.register.phone.showError('手机号格式错误')
+              } else if (r.status == -2) {
+                //图形验证码错误
+                _this.register.code.showError('图形验证码输入错误')
+                $('.register-form-box .verify-img').attr(
+                  'src',
+                  '/front/landpage/captcha?v=' + new Date().getTime()
+                )
+              } else if (r.status == -3) {
+                _this.register.phone.showError('手机号已被注册')
+                $('.register-form-box .verify-img').attr(
+                  'src',
+                  '/front/landpage/captcha?v=' + new Date().getTime()
+                )
+              } else {
+                sessionStorage.setItem(
+                  'login-verify-start-time',
+                  new Date().getTime()
+                )
+                startTimeDown(type)
+              }
+            }
+          )
+          break
+        }
+        case 'forge': {
+          $.post(
+            '/phone/forgetPwd',
+            {
+              reqType: 'sendIdentCode',
+              phone: $(
+                ".forgetpwd_page .login-dig-input-box [name='forge_phone']"
+              ).val(),
+              code: $(
+                ".forgetpwd_page .login-dig-input-box [name='forge_code']"
+              ).val()
+            },
+            function (r) {
+              if (r.status == 'phoneError') {
+                _this.forge.phone.showError('手机号格式错误')
+              } else if (r.status == 'codeError') {
+                _this.forge.code.showError('图形验证码输入错误')
+                $('.forgetpwd_page .verify-img').attr(
+                  'src',
+                  '/front/landpage/captcha?v=' + new Date().getTime()
+                )
+              } else if (r.status == 'phoneNotExists') {
+                _this.forge.phone.showError('手机号尚未注册')
+                $('.forgetpwd_page .verify-img').attr(
+                  'src',
+                  '/front/landpage/captcha?v=' + new Date().getTime()
+                )
+              } else if (r.status == 'y') {
+                sessionStorage.setItem(
+                  'login-verify-start-time',
+                  new Date().getTime()
+                )
+                startTimeDown(type)
+              }
+            }
+          )
+          break
+        }
+        case 'bind-phone': {
+          $.post(
+            '/jypay/user/phone/bind',
+            {
+              step: 1,
+              phone: $(
+                "#bidLogin .login-dig-input-box [name='verify_phone']"
+              ).val(),
+              code: $(
+                "#bidLogin .login-dig-input-box [name='verify_code']"
+              ).val()
+            },
+            function (r) {
+              if (r && r.error_code > -1) {
+                sessionStorage.setItem(
+                  'login-verify-start-time',
+                  new Date().getTime()
+                )
+                startTimeDown(type)
+              } else {
+                if (r.error_msg === '图形验证码错误') {
+                  if (_this.verify.code.value !== 'HIDE') {
+                    _this.verify.code.showError(
+                      r.error_msg || '发送错误,请稍后再试'
+                    )
+                  }
+                  getNewVerify()
+                } else if (r.error_msg === '手机号已被使用') {
+                  _this.verify.phone.showError('该手机号已被绑定,请更换手机号')
+                } else {
+                  _this.verify.sms.showError(
+                    r.error_msg || '发送错误,请稍后再试'
+                  )
+                }
+              }
+            }
+          )
+          break
+        }
+      }
+    },
+    // 忘记密码
+    ajaxStepOne: function (e, arr) {
+      $.post(
+        '/phone/forgetPwd',
+        { reqType: 'nextStep', identCode: arr[2].value },
+        function (r) {
+          e.setAttribute('data-loading', 'false')
+          if (r.status == 'identCodeError') {
+            arr[2].showError('短信验证码错误')
+          } else if (r.status == 'y') {
+            toggleStep(false)
+          }
+        }
+      )
+    },
+    ajaxStepTwo: function (e, arr) {
+      $.post(
+        '/phone/forgetPwd',
+        { reqType: 'save', password: arr[1].value },
+        function (r) {
+          e.setAttribute('data-loading', 'false')
+          if (r.status == 'passwordError') {
+            arr[0].showError('密码格式错误')
+          } else if (r.status == 'passwordRepeat') {
+            arr[0].showError('新密码不能与之前设置过的密码重复')
+          } else {
+            var toast = document.querySelector('.login-dig-success-toast')
+            toast.classList.add('is-show')
+            setTimeout(function () {
+              toast.classList.remove('is-show')
+              if (sessionStorage) {
+                sessionStorage.reLogin = 1
+              }
+              window.history.back()
+            }, 1500)
+          }
+        }
+      )
+    },
+    // 设置密码
+    ajaxSetPassword: function (e, arr) {
+      var payload = {
+        password: arr[0].value
+      }
+      $.ajax({
+        url: '/publicapply/password/update',
+        type: 'POST',
+        contentType: 'application/json',
+        data: JSON.stringify(payload),
+        success: function (r) {
+          e.setAttribute('data-loading', 'false')
+          if (r) {
+            // 密码保存成功,走登录成功步骤
+            logic(Direct.loginInfo.userInfo, mynum)
+          } else {
+            arr[1].showError('密码保存失败')
+          }
+        }
+      })
+    },
+    // 手机号+密码登录
+    ajaxLoginPass: function (e, arr) {
+      var payload = {
+        reqType: 'phoneLogin',
+        isAutoLogin: $('.password-login .auto-login-checkbox').hasClass(
+          'checked'
+        ),
+        phone: arr[0].value,
+        password: arr[1].value
+      }
+      $.post('/phone/login', payload, function (r) {
+        e.setAttribute('data-loading', 'false')
+        if (r.status == 1) {
+          logic(r.userInfo, mynum)
+        } else if (r.status == -1) {
+          arr[0].showError('该手机号未注册')
+        } else if (r.status == -2) {
+          arr[1].showError('密码输入错误')
+        }
+      })
+    },
+    ajaxLoginSms: function (e, arr) {
+      if ($('#bidLogin').attr('data-name') === 'bind-phone') {
+        $.post(
+          '/jypay/user/phone/bind',
+          {
+            step: 2,
+            phone: arr[0].value,
+            code: arr[2].value,
+            mode: isBindPage ? 'mergeBind' : ''
+          },
+          function (r) {
+            e.setAttribute('data-loading', 'false')
+            if (r && r.error_code > -1) {
+              if (r.data.state == 1) {
+                var backToUrl = getParam('backTo')
+                if (backToUrl) {
+                  return location.replace(decodeURIComponent(backToUrl))
+                }
+                if (isBindPage) {
+                  if (history.length === 1) {
+                    goBackOrigin()
+                  } else {
+                    if (document.referrer === location.href) {
+                      goBackOrigin(function () {
+                        location.href = '/'
+                      })
+                    } else {
+                      checkNeedGoNewUserSettingPage()
+                      history.back()
+                    }
+                  }
+                  return
+                }
+                if (r.data.needMerge) {
+                  location.href =
+                    '/swordfish/frontPage/userMerge/sess/merge?token=' +
+                    r.data.mergeToken
+                  return
+                } else {
+                  checkNeedGoNewUserSettingPage()
+                  $('#bidLogin').modal('hide')
+                  sessionStorage.setItem('bind-phone', arr[0].value.trim())
+                  typeof window.callBindPhoneSuccess === 'function' &&
+                    window.callBindPhoneSuccess(true)
+                }
+              } else if (r.data.state == 2) {
+                location.replace(
+                  '/swordfish/frontPage/userMerge/sess/merge?token=' +
+                    r.data.token
+                )
+              }
+            } else {
+              arr[2].showError(r.error_msg || '绑定错误,请稍后再试')
+            }
+          }
+        )
+      } else {
+        var source = getParam('source') //百度SEM
+        if (source != null) {
+          var pathname = window.location.pathname
+          if (pathname == '/front/structed/pc_index.html') {
+            //结构化数据
+            source += '_structed'
+          } else if (pathname == '/bid/pc/page/bidfile_landpage') {
+            //招标文件解读
+            source += '_bidfile'
+          } else if (pathname == '/big/page/index') {
+            //大会员
+            source += '_member'
+          }
+        } else {
+          source = ''
+        }
+        var payload = {
+          reqType: 'identCodeLogin',
+          identCode: arr[2].value,
+          isAutoLogin: $('.sms-login .auto-login-checkbox').hasClass('checked'),
+          source: source
+        }
+        // 短信验证码登录
+        $.post('/phone/login', payload, function (r) {
+          e.setAttribute('data-loading', 'false')
+          if (r.status == 1) {
+            if (r.userInfo.isNewUser) {
+              trackClick('注册行为-打开设置密码弹窗')
+              Direct.showSetPassModule(true)
+              Direct.loginInfo = r
+            } else {
+              logic(r.userInfo, mynum)
+            }
+          } else if (r.status == -1) {
+            arr[2].showError('短信验证码输入错误')
+          } else if (r.status == -4) {
+            arr[2].showError('系统错误,请重试')
+          }
+        })
+      }
+    },
+    // 新用户设置密码
+    showSetPassModule: function (type) {
+      var otherArr = [
+        '.login-dig-footer-box .wx-logo-box',
+        '.login-dig-footer-box .login-dig-text-split',
+        '.login-dig-tabbar-navbar',
+        '.login-dig-tabbar-content',
+        '.login-dig-tabbar-content.is-active',
+        '.pass-bottom',
+        '.login-dig-wx-qrcode-box',
+        '.login-dig-top-back-box',
+        '.code-bottom'
+      ]
+      var setPassArr = [
+        '.login-dig-tabbar-content.set-password',
+        '.login-dig-tabbar-navbar.set-pass-module',
+        '.set-pass-bottom'
+      ]
+      for (var i = 0; i < otherArr.length; i++) {
+        document.querySelector(otherArr[i]).style.display = type ? 'none' : ''
+      }
+      for (var i = 0; i < setPassArr.length; i++) {
+        document.querySelector(setPassArr[i]).style.display = type
+          ? 'block'
+          : 'none'
+      }
+    },
+    ajaxRegister: function (e, arr) {
+      var source = getParam('source') //百度SEM
+      if (source != null) {
+        var pathname = window.location.pathname
+        if (pathname == '/front/structed/pc_index.html') {
+          //结构化数据
+          source += '_structed'
+        } else if (pathname == '/bid/pc/page/bidfile_landpage') {
+          //招标文件解读
+          source += '_bidfile'
+        } else if (pathname == '/big/page/index') {
+          //大会员
+          source += '_member'
+        }
+      } else {
+        source = ''
+      }
+      var payload = {
+        reqType: 'identCodeLogin',
+        s_entname: arr[3].value,
+        identCode: arr[2].value,
+        source: source,
+        isAutoLogin: $('.sms-login .auto-login-checkbox').hasClass('checked'),
+        email: arr[4].value
+      }
+      // 短信验证码登录
+      $.post('/phone/login', payload, function (r) {
+        e.setAttribute('data-loading', 'false')
+        if (r.status == 1) {
+          logic(r.userInfo, mynum)
+          var toast = document.querySelector('.login-dig-success-toast')
+          toast.classList.add('is-show')
+          setTimeout(function () {
+            toast.classList.remove('is-show')
+            window.history.back()
+          }, 1500)
+        } else if (r.status == -1) {
+          arr[2].showError('短信验证码输入错误')
+        }
+      })
+    }
+  }
+  // @手机号绑定以及账号合并 2021/1/25
+  function toggleNeedVerifyInput(f, src) {
+    var verifyInput = $(
+      '.login-dig-tabbar-content.is-active .login-dig-input-box:eq(1)'
+    )
+    if ($('#bidLogin').attr('data-name') === 'bind-phone') {
+      if (f) {
+        if (verifyInput.find('input').val() === 'HIDE') {
+          verifyInput.find('input').val('')
+          Direct.verify.code.showError()
+        }
+        verifyInput.find('.verify-img').attr('src', src)
+        verifyInput.show()
+      } else {
+        verifyInput.find('input').val('HIDE')
+        Direct.verify.code.skip('HIDE')
+        verifyInput.hide()
+      }
+    }
+  }
+  var oldNeedStatus = false
+  window.getBindVerify = getNewVerify
+  function getNewVerify(cb) {
+    if (!oldNeedStatus) {
+      toggleNeedVerifyInput(false)
+    }
+    $.ajax({
+      url: '/jypay/user/phone/imgCaptcha?t=' + new Date().getTime(),
+      success: function (r) {
+        console.log(r)
+        if (r && r.data) {
+          oldNeedStatus = r.data.needVerify
+          if (r.data.needVerify) {
+            toggleNeedVerifyInput(
+              true,
+              'data:image/png;base64,' + r.data.imageData
+            )
+            typeof cb === 'function'
+              ? cb('data:image/png;base64,' + r.data.imageData)
+              : null
+          } else {
+            toggleNeedVerifyInput(false)
+          }
+        }
+      }
+    })
+  }
+  // 初始化弹窗
+  try {
+    initDirect()
+  } catch (e) {}
+  // 初始化忘记密码
+  initForgetDirect()
+  initRegisterDirect()
+  if (sessionStorage && sessionStorage.reLogin == 1) {
+    sessionStorage.removeItem('reLogin')
+    $(".login-dig-tabbar-navbar>[name='pass']").click()
+    openLoginDig()
+  }
+  $('#bidLogin').on('show.bs.modal', function () {
+    if ($('#bidLogin').attr('data-name') === 'bind-phone') {
+      getNewVerify()
+    } else {
+      var verify_path = '/front/landpage/captcha?v='
+      $('#bidLogin .verify-img').attr('src', verify_path + new Date().getTime())
+    }
+  })
+  $('#bidLogin').on('hidden.bs.modal', function () {
+    window.needToWork = false
+    $('.public-nav').css({ 'padding-right': '' })
+    if ($('#bidLogin').attr('data-rec')) {
+      $('#bidLogin').removeAttr('data-rec')
+    }
+    if (
+      Direct.loginInfo.userInfo &&
+      Direct.loginInfo.userInfo.result === 'ok'
+    ) {
+      location.reload()
+    }
+  })
+  function startTimeDown(type) {
+    var nowCount = 60
+    if (sessionStorage.getItem('login-verify-start-time')) {
+      var cCount = parseInt(
+        (new Date().getTime() -
+          sessionStorage.getItem('login-verify-start-time')) /
+          1000
+      )
+      if ((cCount >= 0) & (cCount <= 60)) {
+        nowCount -= cCount
+      } else {
+        sessionStorage.removeItem('login-verify-start-time')
+        return
+      }
+    } else {
+      return
+    }
+    var nowQ = 'span[data-name="verify_get_sms"]'
+    var otherQ = 'span[data-name="forge_get_sms"]'
+    if (type === 'forge') {
+      var tempQ = nowQ
+      nowQ = otherQ
+      otherQ = tempQ
+    }
+    if (type === 'register') {
+      nowQ = 'span[data-name="register_get_sms"]'
+      otherQ = 'span[data-name="verify_get_sms"]'
+    }
+    var Ele = document.querySelector(nowQ)
+    var otherEle = document.querySelector(otherQ)
+    var defalutIT = '重新获取(' + --nowCount + 's)'
+    if (Ele) Ele.innerText = defalutIT
+    if (otherEle) otherEle.innerText = defalutIT
+    var nowSS = window.setInterval(function () {
+      if (
+        nowCount === 1 ||
+        !sessionStorage.getItem('login-verify-start-time')
+      ) {
+        clearInterval(nowSS)
+        if (Ele) Ele.innerText = '获取验证码'
+        if (Ele) Ele.classList.remove('is-stop')
+        if (otherEle) otherEle.innerText = '获取验证码'
+        sessionStorage.removeItem('login-verify-start-time')
+        return
+      }
+      var iT = '重新获取(' + --nowCount + 's)'
+      if (Ele) Ele.classList.add('is-stop')
+      if (Ele) Ele.innerText = iT
+      if (otherEle) otherEle.classList.add('is-stop')
+      if (otherEle) otherEle.innerText = iT
+    }, 1000)
+  }
+  function getSMSCode(e) {
+    if (e.classList.contains('is-stop')) return
+    var verifyStartTime = new Date().getTime()
+    var oldTime =
+      sessionStorage.getItem('login-verify-start-time') ||
+      verifyStartTime - 70000
+    if (verifyStartTime - oldTime >= 60000) {
+      var nowQ =
+        e.getAttribute('data-name') === 'forge_get_sms' ? 'forge' : 'verify'
+      if ($('#bidLogin').attr('data-name') === 'bind-phone') {
+        nowQ = 'bind-phone'
+        // getNewVerify()
+      }
+      if (e.getAttribute('data-name') === 'verify_get_sms' && !isBindPage) {
+        nowQ = 'verify'
+        trackClick('注册行为-验证码登录/注册-获取验证码')
+      }
+      if (isBindPage) {
+        trackClick('绑定-发送验证码')
+      }
+      Direct.ajaxSms(e, nowQ)
+    }
+  }
+
+  // 表单规则
+  function ruleForPhone(data, type) {
+    var phoneReg = /^[1][3-9][0-9]{9}$/.test(data.value)
+    var createPhoneReg = /^[1][0][0][0-9]{8}$/.test(data.value)
+    var checkStatus = phoneReg || createPhoneReg
+    if (type === 'input') {
+      return data.value.length >= 11 ? checkStatus : true
+    }
+    if (type === 'blur') {
+      return data.value.length ? checkStatus : true
+    }
+    return checkStatus
+  }
+  function ruleForCode(data, type) {
+    var checkStatus = /^\S{4}$/.test(data.value)
+    if (type === 'blur') {
+      return data.value.length ? checkStatus : true
+    }
+    if (type === 'input') {
+      return data.value.length == 4 ? checkStatus : true
+    }
+    return checkStatus
+  }
+  function ruleForEnt(data, type) {
+    var checkStatus = /^\S{4,100}$/.test(data.value)
+    if (type === 'blur') {
+      return data.value.length ? checkStatus : true
+    }
+    if (type === 'input') {
+      return data.value.length < 4 ? checkStatus : true
+    }
+    return checkStatus
+  }
+  function ruleForSms(data, type) {
+    var checkStatus = /^\S{6}$/.test(data.value)
+    if (type === 'blur') {
+      return data.value.length ? checkStatus : true
+    }
+    if (type === 'input') {
+      return data.value.length == 6 ? checkStatus : true
+    }
+    return checkStatus
+  }
+  function ruleForPass(data, type) {
+    var checkStatus = /^\S{6,}$/.test(data.value)
+    if (type === 'blur') {
+      return data.value.length ? checkStatus : true
+    }
+    if (type === 'input') {
+      return data.value.length >= 6 ? checkStatus : true
+    }
+    return checkStatus
+  }
+  function createFormStauts(formOption) {
+    var nowEle = document.querySelector(formOption.el)
+    var errClass = 'is-error'
+    // 实时状态
+    var nowData = {
+      status: null,
+      next: formOption.next || false,
+      value: null,
+      el: nowEle,
+      skip: function (value) {
+        this.status = true
+        this.next = true
+        this.value = value
+        formOption.upStatus()
+      },
+      showError: function (error) {
+        this.status = false
+        this.next = false
+        formOption.upStatus()
+        if (error) {
+          this.el.parentNode.setAttribute('data-error', error)
+          this.el.parentNode.classList.add(errClass)
+        }
+      }
+    }
+    // 错误提示
+    if (formOption.errorTip && formOption.errorTip !== '') {
+      nowEle.parentNode.setAttribute('data-error', formOption.errorTip)
+    }
+    // 校验规则
+    if (typeof formOption.rule !== 'function') {
+      formOption.rule = function (data) {
+        return true
+      }
+    }
+    // 状态变动通知回调
+    if (typeof formOption.upStatus !== 'function') {
+      formOption.upStatus = function (data) {
+        return true
+      }
+    }
+    // 监听事件
+    var events = formOption.event
+    for (var i = 0; i < events.length; i++) {
+      if (nowEle)
+        nowEle.addEventListener(events[i], function (e) {
+          // input
+          var nowTarget = e.target
+          var errorTarget = nowTarget.parentNode
+          // 移除错误提示
+          errorTarget.classList.remove(errClass)
+          // 更新状态
+          nowData.value = nowTarget.value
+          nowData.status = formOption.rule(nowData, e.type)
+          nowData.next = formOption.rule(nowData, 'next')
+          formOption.upStatus()
+          // 更新错误提示
+          if (nowData.status) {
+            errorTarget.classList.remove(errClass)
+          } else {
+            errorTarget.classList.add(errClass)
+          }
+        })
+    }
+    /*formOption.event.forEach(function(v){
+			if (nowEle) nowEle.addEventListener(v,function (e) {
+                // input
+                var nowTarget = e.target
+                var errorTarget = nowTarget.parentNode
+                // 移除错误提示
+                errorTarget.classList.remove(errClass)
+                // 更新状态
+                nowData.value = nowTarget.value
+                nowData.status = formOption.rule(nowData, v)
+                nowData.next = formOption.rule(nowData, 'next')
+                formOption.upStatus()
+                // 更新错误提示
+                if (nowData.status) {
+                    errorTarget.classList.remove(errClass)
+                } else {
+                    errorTarget.classList.add(errClass)
+                }
+            })
+		});*/
+    return nowData
+  }
+  // 事件
+  function installInputEvent() {
+    // verify img event for click
+    var s1 = document.querySelectorAll('.login-dig-input-box .verify-img')
+    for (var i = 0; i < s1.length; i++) {
+      s1[i].addEventListener('click', function (e) {
+        var verify_path = '/front/landpage/captcha?v='
+        if ($('#bidLogin').attr('data-name') === 'bind-phone') {
+          getNewVerify(function (src) {
+            e.target.src = src
+          })
+        } else {
+          e.target.src = verify_path + new Date().getTime()
+        }
+      })
+    }
+    var s2 = document.querySelectorAll('.login-dig-input-box .l-get-sms')
+    for (var i = 0; i < s2.length; i++) {
+      s2[i].addEventListener('click', function (e) {
+        getSMSCode(e.target)
+      })
+    }
+    var s3 = document.querySelectorAll('.login-dig-input-box input')
+    for (var i = 0; i < s3.length; i++) {
+      s3[i].addEventListener('focus', function (e) {
+        var nowInput = e.target
+        nowInput.parentNode.classList.add('is-focus')
+      })
+      s3[i].addEventListener('blur', function (e) {
+        var nowInput = e.target
+        nowInput.parentNode.classList.remove('is-focus')
+      })
+    }
+  }
+  // E-公用
+
+  // 忘记密码
+  function toggleStep(type) {
+    var nowArr = [
+      '.forget-form-box[data-step="1"]',
+      '.forget-step-title[data-step="1"]'
+    ]
+    var otherArr = [
+      '.forget-form-box[data-step="2"]',
+      '.forget-step-title[data-step="2"]'
+    ]
+    for (var i = 0; i < otherArr.length; i++) {
+      if (document.querySelector(otherArr[i]))
+        document.querySelector(otherArr[i]).style.display = type ? 'none' : ''
+    }
+    for (var i = 0; i < nowArr.length; i++) {
+      if (document.querySelector(nowArr[i]))
+        document.querySelector(nowArr[i]).style.display = type ? '' : 'none'
+    }
+  }
+  // 弹窗登录
+  function installAddEventListener() {
+    // tabbar toggle event
+    document
+      .querySelector('.login-dig-tabbar-navbar')
+      .addEventListener('click', function (e) {
+        if (e.target.nodeName !== 'SPAN') return
+        if (e.target.classList.contains('is-active')) {
+          return
+        }
+        if (e.target.innerText === '密码登录') {
+          $('.code-bottom').hide()
+          $('.pass-bottom').show()
+          $('.line-box').addClass('pass-line-box')
+        } else {
+          $('.pass-bottom').hide()
+          $('.code-bottom').show()
+          $('.line-box').removeClass('pass-line-box')
+        }
+        var SelectName = e.target.getAttribute('name')
+        document
+          .querySelector('.login-dig-tabbar-navbar span.is-active')
+          .classList.toggle('is-active')
+        e.target.classList.toggle('is-active')
+        // content toggle
+        document
+          .querySelector('.login-dig-tabbar-content.is-active')
+          .classList.toggle('is-active')
+        document
+          .querySelector(
+            '.login-dig-tabbar-content[data-name="' + SelectName + '"]'
+          )
+          .classList.toggle('is-active')
+        if (SelectName === 'pass' && Direct.instance.password) {
+          $('.login-dig-footer-box p').addClass('passTip')
+          var myEvent = new Event('blur')
+          Direct.instance.password.arr[0].el.dispatchEvent(myEvent)
+          Direct.instance.password.arr[1].el.dispatchEvent(myEvent)
+        } else {
+          $('.login-dig-footer-box p').removeClass('passTip')
+        }
+      })
+    installInputEvent()
+  }
+  // 初始化
+  function isCheckInit(type) {
+    if (type === 'forge') {
+      return document.querySelector('button[name="forge_submit_phone"]')
+    } else {
+      return document.querySelector('button[name="register_submit_phone"]')
+    }
+  }
+  function initDirect() {
+    // 初始化事件
+    installAddEventListener()
+    // 初始化倒计时
+    startTimeDown()
+    // 验证码登录
+    var verifySubmit = {
+      el: 'button[name="verify_submit"]',
+      arr: [],
+      init: function (arr) {
+        this.arr = arr
+        this.check()
+        var submitEle = document.querySelector(this.el)
+        submitEle.addEventListener('click', this.submit)
+      },
+      submit: function (e) {
+        var e = e.target
+        if (e.getAttribute('data-loading') === 'true') return
+        e.setAttribute('data-loading', 'true')
+        if (isBindPage) {
+          trackClick('绑定-立即绑定')
+        } else {
+          trackClick('注册行为-登录/注册')
+        }
+        Direct.ajaxLoginSms(e, verifySubmit.arr)
+      },
+      check: function () {
+        var submitEle = document.querySelector(this.el)
+        var checkStauts = false
+        for (var i = 0; i < this.arr.length; i++) {
+          if (!this.arr[i].next) {
+            checkStauts = true
+          }
+        }
+        if (checkStauts) {
+          submitEle.setAttribute('disabled', checkStauts)
+        } else {
+          submitEle.removeAttribute('disabled')
+        }
+      }
+    }
+    var verifySendSms = {
+      el: '.login-dig-input-box span[data-name="verify_get_sms"]',
+      update: function (type) {
+        var Ele = document.querySelector(this.el)
+        if (type) {
+          Ele.classList.remove('is-stop')
+        } else {
+          if (isBindPage) {
+            Ele.classList.remove('is-stop')
+          } else {
+            Ele.classList.add('is-stop')
+          }
+        }
+      }
+    }
+    var verifyPhone = createFormStauts({
+      el: '.login-dig-input-box input[name="verify_phone"]',
+      rule: ruleForPhone,
+      event: ['input', 'blur'],
+      upStatus: function () {
+        verifySubmit.check()
+        verifySendSms.update(verifyCode.next && verifyPhone.next)
+      }
+    })
+    var verifyCode = createFormStauts({
+      el: '.login-dig-input-box input[name="verify_code"]',
+      rule: ruleForCode,
+      event: ['input', 'blur'],
+      upStatus: function () {
+        verifySubmit.check()
+        verifySendSms.update(verifyCode.next && verifyPhone.next)
+      }
+    })
+    var verifySms = createFormStauts({
+      el: '.login-dig-input-box input[name="verify_sms"]',
+      rule: ruleForSms,
+      event: ['input', 'blur'],
+      upStatus: function () {
+        verifySubmit.check()
+      }
+    })
+    verifySubmit.init([verifyPhone, verifyCode, verifySms])
+    verifySendSms.update(verifyCode.next && verifyPhone.next)
+
+    Direct.verify = {
+      phone: verifyPhone,
+      code: verifyCode,
+      sms: verifySms
+    }
+
+    // 密码登录
+    var passSubmit = {
+      el: 'button[name="pass_submit"]',
+      arr: [],
+      init: function (arr) {
+        this.arr = arr
+        this.check()
+        var submitEle = document.querySelector(this.el)
+        submitEle.addEventListener('click', this.submit)
+      },
+      submit: function (e) {
+        var e = e.target
+        if (e.getAttribute('data-loading') === 'true') return
+        e.setAttribute('data-loading', 'true')
+        Direct.ajaxLoginPass(e, passSubmit.arr)
+      },
+      check: function () {
+        var submitEle = document.querySelector(this.el)
+        var checkStauts = false
+        for (var i = 0; i < this.arr.length; i++) {
+          if (!this.arr[i].next) {
+            checkStauts = true
+          }
+        }
+        if (checkStauts) {
+          submitEle.setAttribute('disabled', checkStauts)
+        } else {
+          submitEle.removeAttribute('disabled')
+        }
+      }
+    }
+    var passPhone = createFormStauts({
+      el: '.login-dig-input-box input[name="pass_phone"]',
+      rule: ruleForPhone,
+      event: ['input', 'blur'],
+      upStatus: function () {
+        passSubmit.check()
+      }
+    })
+    var passPass = createFormStauts({
+      el: '.login-dig-input-box input[name="pass_pass"]',
+      rule: ruleForPass,
+      event: ['input', 'blur'],
+      upStatus: function () {
+        passSubmit.check()
+      }
+    })
+    passSubmit.init([passPhone, passPass])
+    Direct.instance.password = passSubmit
+
+    // 设置密码
+    var setPassSubmit = {
+      el: 'button[name="set_pass_submit"]',
+      init: function (arr) {
+        this.arr = arr
+        this.check()
+        var submitEle = document.querySelector(this.el)
+        submitEle.addEventListener('click', this.submit)
+      },
+      submit: function (e) {
+        var e = e.target
+        if (e.getAttribute('data-loading') === 'true') return
+        trackClick('注册行为-设置密码-确定')
+        Direct.ajaxSetPassword(e, setPassSubmit.arr)
+        // e.setAttribute('data-loading', 'true')
+        // Direct.ajaxLoginPass(e, passSubmit.arr)
+      },
+      check: function () {
+        var submitEle = document.querySelector(this.el)
+        var checkStauts = false
+        for (var i = 0; i < this.arr.length; i++) {
+          if (!this.arr[i].next) {
+            checkStauts = true
+          }
+        }
+        if (checkStauts) {
+          submitEle.setAttribute('disabled', checkStauts)
+        } else {
+          if (this.arr[0].value !== this.arr[1].value) {
+            this.arr[1].showError('两次密码输入不一致')
+          } else {
+            submitEle.removeAttribute('disabled')
+          }
+        }
+      }
+    }
+
+    // 暂不设置密码,走登录成功步骤
+    var setPassCancel = {
+      el: 'button[name="set_pass_cancel"]',
+      init: function () {
+        var submitEle = document.querySelector(this.el)
+        submitEle.addEventListener('click', this.submit)
+      },
+      submit: function (e) {
+        trackClick('注册行为-设置密码-暂不订阅')
+        logic(Direct.loginInfo.userInfo, mynum)
+      }
+    }
+
+    var setInitPass = createFormStauts({
+      el: '.login-dig-input-box input[name="init_pass"]',
+      rule: ruleForPass,
+      event: ['input', 'blur'],
+      upStatus: function () {
+        setPassSubmit.check()
+      }
+    })
+    var setCheckPass = createFormStauts({
+      el: '.login-dig-input-box input[name="check_pass"]',
+      rule: ruleForPass,
+      event: ['input', 'blur'],
+      upStatus: function () {
+        setPassSubmit.check()
+      }
+    })
+    setPassSubmit.init([setInitPass, setCheckPass])
+    setPassCancel.init()
+  }
+  function initForgetDirect() {
+    // 判断是否需要初始化
+    if (!isCheckInit('forge')) return
+    // 初始化显示
+    toggleStep(true)
+    // 初始化倒计时
+    startTimeDown('forge')
+    // 手机验证
+    var verifySubmit = {
+      el: 'button[name="forge_submit_phone"]',
+      arr: [],
+      init: function (arr) {
+        this.arr = arr
+        this.check()
+        var submitEle = document.querySelector(this.el)
+        if (!submitEle) return
+        submitEle.addEventListener('click', this.submit)
+      },
+      submit: function (e) {
+        var e = e.target
+        if (e.getAttribute('data-loading') === 'true') return
+        e.setAttribute('data-loading', 'true')
+        Direct.ajaxStepOne(e, verifySubmit.arr)
+      },
+      check: function () {
+        var submitEle = document.querySelector(this.el)
+        if (!submitEle) return
+        var checkStauts = false
+        for (var i = 0; i < this.arr.length; i++) {
+          if (!this.arr[i].next) {
+            checkStauts = true
+          }
+        }
+        if (checkStauts) {
+          submitEle.setAttribute('disabled', checkStauts)
+        } else {
+          submitEle.removeAttribute('disabled')
+        }
+      }
+    }
+    var verifySendSms = {
+      el: '.login-dig-input-box span[data-name="forge_get_sms"]',
+      update: function (type) {
+        var Ele = document.querySelector(this.el)
+        if (type) {
+          Ele.classList.remove('is-stop')
+        } else {
+          Ele.classList.add('is-stop')
+        }
+      }
+    }
+    var verifyPhone = createFormStauts({
+      el: '.login-dig-input-box input[name="forge_phone"]',
+      rule: ruleForPhone,
+      event: ['input', 'blur'],
+      upStatus: function () {
+        verifySubmit.check()
+        verifySendSms.update(verifyCode.next && verifyPhone.next)
+      }
+    })
+    var verifyCode = createFormStauts({
+      el: '.login-dig-input-box input[name="forge_code"]',
+      rule: ruleForCode,
+      event: ['input', 'blur'],
+      upStatus: function () {
+        verifySubmit.check()
+        verifySendSms.update(verifyCode.next && verifyPhone.next)
+      }
+    })
+    var verifySms = createFormStauts({
+      el: '.login-dig-input-box input[name="forge_sms"]',
+      rule: ruleForSms,
+      event: ['input', 'blur'],
+      upStatus: function () {
+        verifySubmit.check()
+      }
+    })
+    verifySubmit.init([verifyPhone, verifyCode, verifySms])
+    verifySendSms.update(verifyCode.next && verifyPhone.next)
+
+    // 密码重置
+    var passSubmit = {
+      el: 'button[name="forge_submit_pass"]',
+      arr: [],
+      init: function (arr) {
+        this.arr = arr
+        this.check()
+        var submitEle = document.querySelector(this.el)
+        submitEle.addEventListener('click', this.submit)
+      },
+      submit: function (e) {
+        var e = e.target
+        if (e.getAttribute('data-loading') === 'true') return
+        e.setAttribute('data-loading', 'true')
+        Direct.ajaxStepTwo(e, passSubmit.arr)
+      },
+      check: function () {
+        var submitEle = document.querySelector(this.el)
+        var checkStauts = false
+        for (var i = 0; i < this.arr.length; i++) {
+          if (!this.arr[i].next) {
+            checkStauts = true
+          }
+        }
+        if (checkStauts) {
+          submitEle.setAttribute('disabled', checkStauts)
+        } else {
+          if (this.arr[0].value !== this.arr[1].value) {
+            this.arr[1].showError('两次密码输入不一致')
+          } else {
+            submitEle.removeAttribute('disabled')
+          }
+        }
+      }
+    }
+    var passPhone = createFormStauts({
+      el: '.login-dig-input-box input[name="forge_pass_one"]',
+      rule: ruleForPass,
+      event: ['input', 'blur'],
+      upStatus: function () {
+        passSubmit.check()
+      }
+    })
+    var passPass = createFormStauts({
+      el: '.login-dig-input-box input[name="forge_pass_two"]',
+      rule: ruleForPass,
+      event: ['input', 'blur'],
+      upStatus: function () {
+        passSubmit.check()
+      }
+    })
+    passSubmit.init([passPhone, passPass])
+
+    Direct.forge = {
+      phone: verifyPhone,
+      code: verifyCode
+    }
+  }
+  function initRegisterDirect() {
+    // 判断是否需要初始化
+    if (!isCheckInit('register')) return
+    // 初始化倒计时
+    startTimeDown('register')
+    // 手机验证
+    var verifySubmit = {
+      el: 'button[name="register_submit_phone"]',
+      arr: [],
+      init: function (arr) {
+        this.arr = arr
+        this.check()
+        var submitEle = document.querySelector(this.el)
+        if (!submitEle) return
+        submitEle.addEventListener('click', this.submit)
+      },
+      submit: function (e) {
+        var e = e.target
+        if (e.getAttribute('data-loading') === 'true') return
+        e.setAttribute('data-loading', 'true')
+        trackClick('注册行为-立即注册')
+        Direct.ajaxRegister(e, verifySubmit.arr)
+      },
+      check: function () {
+        var submitEle = document.querySelector(this.el)
+        if (!submitEle) return
+        var checkStauts = false
+        for (var i = 0; i < this.arr.length; i++) {
+          if (!this.arr[i].next) {
+            checkStauts = true
+          }
+        }
+        if (checkStauts) {
+          submitEle.setAttribute('disabled', checkStauts)
+        } else {
+          submitEle.removeAttribute('disabled')
+        }
+      }
+    }
+    var verifySendSms = {
+      el: '.login-dig-input-box span[data-name="register_get_sms"]',
+      update: function (type) {
+        var Ele = document.querySelector(this.el)
+        if (type) {
+          Ele.classList.remove('is-stop')
+        } else {
+          Ele.classList.add('is-stop')
+        }
+      }
+    }
+    var verifyPhone = createFormStauts({
+      el: '.login-dig-input-box input[name="register_phone"]',
+      rule: ruleForPhone,
+      event: ['input', 'blur'],
+      upStatus: function () {
+        verifySubmit.check()
+        verifySendSms.update(
+          verifyCode.next && verifyPhone.next && verifyEnt.next
+        )
+      }
+    })
+    var verifyCode = createFormStauts({
+      el: '.login-dig-input-box input[name="register_code"]',
+      rule: ruleForCode,
+      event: ['input', 'blur'],
+      upStatus: function () {
+        verifySubmit.check()
+        verifySendSms.update(verifyCode.next && verifyPhone.next)
+      }
+    })
+    var verifySms = createFormStauts({
+      el: '.login-dig-input-box input[name="register_sms"]',
+      rule: ruleForSms,
+      event: ['input', 'blur'],
+      upStatus: function () {
+        verifySubmit.check()
+      }
+    })
+    var verifyEnt = createFormStauts({
+      el: '.login-dig-input-box input[name="verify_entname"]',
+      rule: ruleForEnt,
+      event: ['input', 'blur'],
+      upStatus: function () {
+        verifySubmit.check()
+        verifySendSms.update()
+      }
+    })
+    var verifyEmail = createFormStauts({
+      el: '.login-dig-input-box .register_email',
+      event: ['input', 'blur'],
+      next: true,
+      upStatus: function () {
+        verifySubmit.check()
+      }
+    })
+    verifySubmit.init([
+      verifyPhone,
+      verifyCode,
+      verifySms,
+      verifyEnt,
+      verifyEmail
+    ])
+    verifySendSms.update(verifyCode.next && verifyPhone.next && verifyEnt.next)
+
+    Direct.register = {
+      phone: verifyPhone,
+      code: verifyCode
+    }
+  }
+})
+// 注册埋点
+function trackClick(c_type) {
+  if (!c_type) return
+  try {
+    clab_tracker.track('c_register', {
+      c_platform: 'pc',
+      c_type: c_type,
+      date: new Date()
+    })
+  } catch (error) {
+    console.dir(error)
+  }
+}
+function openLoginDig(type, redirectUrl) {
+  $('#bidLogin .logo').show()
+  $('#bidLogin .bind-phone-head').hide()
+  $('.login-dig-tabbar-content.is-active .login-dig-input-box').show()
+  if ($('#bidLogin').attr('data-name') === 'bind-phone') {
+    $('#bidLogin').removeAttr('data-name')
+    $('.login-dig-submit-button').removeClass('bindphonebtn')
+    $('.login-dig-submit-button:disabled').css('background', '#E0E0E0')
+    $('.login-dig-submit-button:disabled').css('opacity', '0.5')
+    $('.login-dig-submit-button').css('margin-bottom', '0')
+    $("#bidLogin .login-dig-submit-button[name='verify_submit']").text(
+      '登录 / 注册'
+    )
+    $(".login-dig-tabbar-content[data-name='code'] .login-dig-input-box")
+      .removeClass('is-error')
+      .children('input')
+      .val('')
+  }
+  var href = window.location.href
+  var sourceStr = ''
+  if (href.indexOf('/front/structed/pc_index.html?source=baidusem') > -1) {
+    //结构化数据
+    sourceStr = '结构化数据-pc-baidusem'
+  } else if (
+    href.indexOf('/bid/pc/page/bidfile_landpage?source=baidusem') > -1
+  ) {
+    //招标文件解读
+    sourceStr = '招标文件解读-pc-baidusem'
+  }
+  if (sourceStr != '') {
+    try {
+      _hmt.push(['_trackEvent', sourceStr, 'click', '登录'])
+    } catch (e) {
+      console.log('未初始化百度统计', e)
+    }
+  }
+  $('#bidLogin').modal('show')
+  try {
+    var injectLogic = logic
+    logic = function (data, num) {
+      window.needToWork = Boolean(type)
+      if (data.result === 'ok') {
+        //判断是否需要设置cookie
+        if (data.cValue) {
+          afterLoginSetCookit(data.cName, data.cValue, data.expires)
+        }
+        // 判断是否绑定手机号
+        if (!data.phone && data.openid) {
+          window.location.href = '/swordfish/frontPage/userMerge/sess/bind'
+          return
+        }
+        // 检查是否需要新窗口打开<新用户兴趣偏好设置页面>
+        checkNeedGoNewUserSettingPage()
+        if (redirectUrl === 'reload') {
+          return location.reload()
+        }
+        // 需要登陆后重定向的页面
+        if (redirectUrl) {
+          location.href = redirectUrl
+          return
+        }
+        if (needToWork) {
+          location.href = '/page_workDesktop/'
+          return
+        }
+      }
+      injectLogic(data, num)
+    }
+  } catch (e) {}
+  // 埋点
+  trackClick('注册行为-登录或注册弹窗')
+}
+function openBindPhoneDig() {
+  openLoginDigForWx(false)
+  $('#bidLogin .logo').hide()
+  $('#bidLogin .bind-phone-head').show()
+  if ($('#bidLogin').attr('data-name') !== 'bind-phone') {
+    $('#bidLogin').attr('data-name', 'bind-phone')
+    // $('.login-dig-submit-button:disabled').css('background', '#2CB7CA')
+    // $('.login-dig-submit-button:disabled').css('opacity', '0.5')
+    $('.login-dig-submit-button').css('margin-bottom', '12px')
+    $('.login-dig-submit-button').addClass('bindphonebtn')
+    $("#bidLogin .login-dig-submit-button[name='verify_submit']").text(
+      '立即绑定'
+    )
+    $(".login-dig-tabbar-content[data-name='code'] .login-dig-input-box")
+      .removeClass('is-error')
+      .children('input')
+      .val('')
+  }
+  $('#bidLogin').modal('show')
+}
+// 密码切换显示/隐藏
+function switchPassShow(e, str) {
+  e.preventDefault()
+  const type = $(str).attr('type')
+  if (type === 'password') {
+    $(str).attr('type', 'text')
+  } else {
+    $(str).attr('type', 'password')
+  }
+}
+function closeLoginDig() {
+  $('#bidLogin').modal('hide')
+  window.location.reload()
+}
+function openLoginDigForWx(type) {
+  var otherArr = [
+    '.login-dig-footer-box .wx-logo-box',
+    '.login-dig-footer-box .login-dig-text-split',
+    '.login-dig-tabbar-navbar',
+    '.login-dig-tabbar-content',
+    '.login-dig-tabbar-content.is-active',
+    '.pass-bottom'
+  ]
+  var wxArr = [
+    '.login-dig-wx-qrcode-box',
+    '.login-dig-top-back-box',
+    '.code-bottom'
+  ]
+  for (var i = 0; i < otherArr.length; i++) {
+    document.querySelector(otherArr[i]).style.display = type ? 'none' : ''
+  }
+  for (var i = 0; i < wxArr.length; i++) {
+    document.querySelector(wxArr[i]).style.display = type ? '' : 'none'
+  }
+  $('.login-dig-footer-box p').removeClass('passTip')
+}
+
+function openLoginDigForReg(type) {
+  document.querySelector('.login-dig-tabbar-content').style.display = 'none'
+  document.querySelector('.login-dig-tabbar-content.is-active').style.display =
+    'none'
+  $('.login-dig-wx-qrcode-box').hide()
+  $('.login-dig-tabbar-navbar').hide()
+  $('.login-dig-reg').show()
+  $('.login-dig-footer-box').hide()
+  // 埋点
+  trackClick('注册行为-登录或注册弹窗')
+}
+
+function backLogin(type) {
+  var otherArr = [
+    '.login-dig-box .new_login > .logo',
+    '.login-dig-footer-box',
+    '.login-dig-footer-box .wx-logo-box',
+    '.login-dig-footer-box .login-dig-text-split',
+    '.login-dig-tabbar-navbar',
+    '.login-dig-tabbar-content',
+    '.login-dig-tabbar-content.is-active'
+  ]
+  for (var i = 0; i < otherArr.length; i++) {
+    document.querySelector(otherArr[i]).style.display = type ? 'none' : ''
+  }
+  $('.login-dig-reg').hide()
+}
+
+// 共三种登录。选择器要添加 sms-login / password-login / wx-qr-login 类名前缀限制
+var loginDialog = {
+  init: function () {
+    this.initEvnets()
+  },
+  initEvnets: function () {
+    this.bindAutoLoginCheckboxEvent()
+    this.enterLoginAction()
+  },
+  bindKeepLoginQr: function () {
+    var payload = {
+      isAutoLogin: $('.wx-qr-login .auto-login-checkbox').hasClass('checked'),
+      // pageshareid: pageshareid,
+      // kopshareid: kopshareid,
+      loginER: [pageshareid, kopshareid].join('___')
+    }
+    $.ajax({
+      url: '/free/setKeepLogin',
+      method: 'POST',
+      async: true,
+      data: payload
+    })
+  },
+  chcekBindKeep: function (dom) {
+    var $parent = $(dom).parents('.login-module-card')
+    var isWxQrLogin = $parent.hasClass('wx-qr-login')
+    if (isWxQrLogin) {
+      this.bindKeepLoginQr()
+    }
+  },
+  bindAutoLoginCheckboxEvent: function () {
+    var _this = this
+    $('.auto-login-container').on(
+      'click',
+      'label, .auto-login-checkbox',
+      function () {
+        // 手机号验证码自动登录、手机号密码自动登录、微信 下次自动登录 状态分离
+        // var $parent = $(this).parents('.auto-login-container')
+        // $parent.find('.auto-login-checkbox').toggleClass('checked')
+        // $parent.find('.auto-login-container').toggleClass('checked')
+        // _this.chcekBindKeep(this)
+
+        // 手机号验证码自动登录、手机号密码自动登录、微信 下次自动登录 状态同步
+        $('.auto-login-checkbox').toggleClass('checked')
+        $('.auto-login-container').toggleClass('checked')
+        _this.bindKeepLoginQr()
+      }
+    )
+    $('.auto-login-container')
+      .on('mouseover', '.icon-tip-container,.j-tooltip', function () {
+        var $parent = $(this).parents('.auto-login-container')
+        $parent.find('.icon-tip').addClass('highlight')
+        $parent.find('.j-tooltip').show()
+      })
+      .on('mouseleave', '.icon-tip-container,.j-tooltip', function () {
+        var $parent = $(this).parents('.auto-login-container')
+        $parent.find('.icon-tip').removeClass('highlight')
+        $parent.find('.j-tooltip').hide()
+      })
+  },
+  enterLoginAction: function () {
+    $('.sms-login .enter-action-login').on('keydown', function (e) {
+      if (e.keyCode === 13) {
+        // 触发点击事件
+        $('.sms-login .login-dig-submit-button[name=verify_submit]').trigger(
+          'click'
+        )
+      }
+    })
+    $('.password-login .enter-action-login').on('keydown', function (e) {
+      if (e.keyCode === 13) {
+        // 触发点击事件
+        $('.password-login .login-dig-submit-button[name=pass_submit]').trigger(
+          'click'
+        )
+      }
+    })
+  }
+}
+
+$(function () {
+  loginDialog.init()
+  $('#bidLogin').on('hide.bs.modal', function () {
+    backLogin(false)
+  })
+})

+ 45 - 0
plugins/login-auth/src/module-model/loginCookies.ts

@@ -0,0 +1,45 @@
+/**
+ * 登录相关 Cookies 操作
+ */
+class LoginCookies {
+  set(name, value, time) {
+    var expires = new Date(time)
+    try {
+      $.cookie(name, value, {
+        expires: expires.toGMTString(),
+        path: '/',
+        domain: document.domain.replace(/[^.]+/, '')
+      })
+    } catch (e) {
+      document.cookie =
+        name +
+        '=' +
+        value +
+        ';expires=' +
+        expires.toGMTString() +
+        ';path=/;domain=' +
+        document.domain.replace(/[^.]+/, '')
+    }
+  }
+  clear() {
+    try {
+      $.cookie('userid_secure', '', {
+        expires: -1,
+        path: '/',
+        domain: document.domain.replace(/[^.]+/, '')
+      })
+      $.cookie('klcn_value', '', {
+        expires: -1,
+        path: '/',
+        domain: document.domain.replace(/[^.]+/, '')
+      })
+    } catch (e) {
+      document.cookie = 'userid_secure=;expires=-1;path=/'
+      document.cookie = 'klcn_value=;expires=-1;path=/'
+    }
+  }
+}
+
+const loginCookie = new LoginCookies()
+
+export default loginCookie

+ 28 - 0
plugins/login-auth/src/module-model/loginLeftAd.ts

@@ -0,0 +1,28 @@
+import { useStorage } from '@vueuse/core'
+import { preloadImage } from '@/utils/common.js'
+import { ajaxGetADInfo } from '@/api'
+
+/**
+ * 弹窗左侧广告相关
+ */
+const adImg = useStorage('img--jy-pc-register-login', '')
+let init = false
+function getADInfo(preload = true) {
+  if (init) {
+    return
+  }
+  init = true
+  const adKey = 'jy-pc-register-login'
+  ajaxGetADInfo({
+    codes: [adKey]
+  }).then(({ data }) => {
+    if (data && data.data && data.data[adKey]) {
+      adImg.value = data.data[adKey][0].s_pic
+      if (preload) {
+        preloadImage(adImg.value)
+      }
+    }
+  })
+}
+
+export { getADInfo, adImg }

+ 15 - 0
plugins/login-auth/src/module-model/tab.ts

@@ -0,0 +1,15 @@
+import { computed, Ref, ref } from 'vue'
+
+/**
+ * 当前表单类型相关
+ */
+const tabActive: Ref<string> = ref('login-code')
+
+const tabActiveClassName = computed(() => {
+  return 'form-' + tabActive.value
+})
+function doChangeTabActive(active) {
+  tabActive.value = active
+}
+
+export { tabActive, tabActiveClassName, doChangeTabActive }

+ 31 - 0
plugins/login-auth/src/module-model/wxQrcode.ts

@@ -0,0 +1,31 @@
+import { computed, ref } from 'vue'
+
+/**
+ * 微信二维码相关
+ */
+
+const ImgBase = import.meta.env.VITE_APP_QR_IMAGE_BASE
+
+const pageShareId = ref('')
+const pageKopShareId = ref('')
+
+const pageWechatQrcodeImgSrc = computed(() => {
+  return ImgBase + pageShareId.value
+})
+
+const pageKopQrcodeImgSrc = computed(() => {
+  return ImgBase + pageKopShareId.value
+})
+
+function doSetPageShareId(shareId, kopShareId) {
+  pageKopShareId.value = kopShareId
+  pageShareId.value = shareId
+}
+
+export {
+  pageShareId,
+  pageKopShareId,
+  pageWechatQrcodeImgSrc,
+  pageKopQrcodeImgSrc,
+  doSetPageShareId
+}

+ 15 - 0
plugins/login-auth/src/shims-tsx.d.ts

@@ -0,0 +1,15 @@
+import type Vue from 'vue'
+
+declare global {
+  namespace JSX {
+    // tslint:disable no-empty-interface
+    interface Element extends VNode {}
+    // tslint:disable no-empty-interface
+    interface ElementClass extends Vue {}
+    type IntrinsicElements = Record<string, any>
+  }
+
+  interface ImportMeta {
+    env: Record<any, string>
+  }
+}

+ 4 - 0
plugins/login-auth/src/shims-vue.d.ts

@@ -0,0 +1,4 @@
+declare module '*.vue' {
+  import Vue from 'vue'
+  export default Vue
+}

+ 13 - 0
plugins/login-auth/src/style/icon.scss

@@ -0,0 +1,13 @@
+@mixin icon($name) {
+  .img-icon.icon-#{$name} {
+    background-image: url(@/assets/icon/#{$name}.png);
+    background-size: cover;
+    background-repeat: no-repeat;
+  }
+}
+
+.img-icon {
+  display: inline-block;
+  width: 18px;
+  height: 18px;
+}

+ 1 - 0
plugins/login-auth/src/style/index.scss

@@ -0,0 +1 @@
+@import './icon.scss';

+ 322 - 0
plugins/login-auth/src/utils/Login.ts

@@ -0,0 +1,322 @@
+/**
+ *
+ * 扫码登录历史逻辑梳理
+ *  1. 获取 session shareid
+ *  2. 创建链接,ws / ajax
+ *
+ * 接口:
+ *  1. /front/hasSign
+ *  2. /front/getLoginNum/ + num {rref: document.referrer, oid: oldshareid} oldshareid=localStorage.getItem("oldshareid");
+ *  3./front/ajaxPolling {reqType: 1,shareIds: pageshareid+"___"+kopshareid}
+ */
+import { useWebSocket } from '@vueuse/core'
+import { ajaxGetHasLogin, ajaxGetLoginPolling, ajaxGetLoginNum } from '@/api'
+
+
+/**
+ * 获取 WebSocket URL
+ * @param path - WebSocket 路径
+ * @returns {string} - WebSocket URL
+ */
+function getWebSocketUrl (path = '/ws') {
+  // 获取当前页面的协议
+  const protocol = window.location.protocol;
+
+  // 判断协议类型,决定使用的 WebSocket 协议
+  const socketProtocol = protocol === 'https:' ? 'wss://' : 'ws://';
+
+  // 获取当前页面的主机
+  const host = window.location.host;
+
+  // 构建 WebSocket URL
+  const websocketUrl = `${socketProtocol}${host}${path}`;
+
+  return websocketUrl;
+}
+
+
+
+/**
+ * 扫码登录
+ */
+class ScanCodeLoginDetection {
+  constructor(config) {
+    this.options = {}
+    this.setOptions(config)
+
+    this.requiredAjaxState = {
+      login: false,
+      shareId: false
+    }
+    if (this.options.login) {
+      this.requiredAjaxState.login = true
+    }
+
+    this.poll = null
+
+    this.init()
+  }
+
+  init() {
+    this.recoverShareId()
+  }
+
+  setOptions(config) {
+    this.options = Object.assign(
+      {
+        login: false,
+        // hasLogin 原有参数
+        num: -1,
+        pname: '',
+        purl: '',
+        // 二维码 原有参数
+        shareId: '',
+        kopShareId: ''
+      },
+      config
+    )
+  }
+
+  preload() {
+    return Promise.all([this.getLoginNum(), this.hasLogin()])
+  }
+
+  update(type, data) {
+    this.requiredAjaxState[type] = true
+    if (typeof this.options.update === 'function') {
+      this.options.update(type, data)
+    }
+  }
+
+  success(...args) {
+    if (typeof this.options.success === 'function') {
+      this.options.success(...args)
+    }
+  }
+
+  checkRequiredState() {
+    return this.requiredAjaxState.login && this.requiredAjaxState.shareId
+  }
+
+  async start() {
+    if (!this.requiredAjaxState.shareId) {
+      await this.getLoginNum()
+    }
+
+    if (!this.options.login) {
+      if (!this.poll) {
+        this.poll = this.createLoginStatusPoller()
+      }
+      this.poll.start()
+    }
+  }
+
+  stop() {
+    this.poll.stop()
+  }
+
+  createLoginStatusPoller() {
+    const shareIds = this.options.shareId + '___' + this.options.kopShareId
+    return new LoginStatusPoller({
+      api: async function (count) {
+        let params = {}
+
+        if (count === 0) {
+          params = {
+            reqType: 1,
+            shareIds: shareIds
+          }
+        } else {
+          params = {
+            reqType: 2
+          }
+        }
+
+        return ajaxGetLoginPolling(params)
+      },
+      ws: {
+        enable: true,
+        url: getWebSocketUrl(),
+        sendContent: shareIds,
+        options: {
+          heartbeat: {
+            message: 'HeartBeat',
+            interval: 5000,
+            pongTimeout: 1000
+          }
+        }
+      },
+      success: this.success.bind(this)
+    })
+  }
+
+  hasLogin() {
+    return ajaxGetHasLogin().then(({ data }) => {
+      if (!data) {
+        return
+      }
+
+      this.options.login = true
+      this.update('login', data)
+    })
+  }
+
+  async getLoginNum() {
+    const params = {
+      rref: document.referrer,
+      oid: this.options.shareId
+    }
+    return ajaxGetLoginNum(this.options.num, params).then(({ data }) => {
+      if (data?.num) {
+        this.options.shareId = data.num
+        this.options.kopShareId = data.numot
+        this.saveShareId()
+
+        this.update('shareId', {
+          shareId: this.options.shareId,
+          kopShareId: this.options.kopShareId
+        })
+      }
+    })
+  }
+
+  saveShareId() {
+    localStorage.setItem('oldshareid', this.options.shareId)
+  }
+
+  recoverShareId() {
+    const cacheShareId = localStorage.getItem('oldshareid')
+    if (cacheShareId) {
+      this.options.shareId = cacheShareId
+    }
+  }
+}
+
+/**
+ * 轮询
+ */
+class LoginStatusPoller {
+  constructor(config) {
+    const {
+      before = this.computeStep,
+      api,
+      ws,
+      success = () => {},
+      maxAttempts = 40
+    } = config
+
+    this.before = before
+    this.api = api
+    this.ws = ws
+    this.success = success
+
+    this.options = config
+
+    this.timer = null
+    this.websocket = null
+
+    this.pollingMaxAttempts = maxAttempts
+    this.pollingAttempts = 0
+  }
+
+  clearState() {
+    this.timer = null
+    this.websocket = null
+
+    this.pollingMaxAttempts = this.options.maxAttempts
+    this.pollingAttempts = 0
+  }
+
+  start() {
+    this.stop()
+    if (this.ws?.enable && this.supportsWebsockets()) {
+      this.createWebsocket()
+    } else {
+      this.poll()
+    }
+  }
+
+  stop() {
+    if (this.websocket) {
+      this.websocket.close()
+    }
+    if (this.timer) {
+      clearTimeout(this.timer)
+    }
+
+    this.clearState()
+  }
+
+  poll() {
+    if (this.pollingAttempts >= this.pollingMaxAttempts) {
+      return
+    }
+
+    const { step, state } = this.before(this.pollingAttempts)
+
+    if (state === false) {
+      return
+    }
+
+    clearTimeout(this.timer)
+
+    this.api(this.pollingAttempts)
+      .then(({ data }) => {
+        if (data) {
+          this.success(data)
+          this.stop()
+          return
+        }
+        this.pollingAttempts++ // 增加轮询次数
+        this.timer = setTimeout(() => {
+          this.poll()
+        }, step)
+      })
+      .catch((error) => {
+        console.error('Error:', error)
+      })
+  }
+
+  supportsWebsockets() {
+    return 'WebSocket' in window
+  }
+
+  createWebsocket() {
+    const options = Object.assign(
+      {
+        onMessage: (ws, event) => {
+          const data = JSON.parse(event.data)
+          if (data?.result === 'ok') {
+            this.success(data)
+          }
+          this.stop()
+        },
+        onError: (error) => {
+          // WebSocket出错时,使用备用ajax方案轮询
+          console.error('WebSocket error:', error)
+          this.poll()
+        }
+      },
+      this.ws.options
+    )
+    this.websocket = useWebSocket(this.ws.url, options)
+
+    this.websocket.send(this.ws.sendContent)
+  }
+
+  computeStep(count) {
+    let result = {
+      state: true,
+      step: 3000
+    }
+    const maxCount = 10
+    if (count <= maxCount) {
+      result.step = 3000
+    } else {
+      result.step = Math.min(20000, (count - maxCount) * 1000 + 3000)
+    }
+    return result
+  }
+}
+
+export { LoginStatusPoller, ScanCodeLoginDetection }

+ 57 - 0
plugins/login-auth/src/utils/common.js

@@ -0,0 +1,57 @@
+function preloadImage(url) {
+  const img = new Image()
+  img.src = url
+}
+
+function clearStorage(obj, reg) {
+  if (obj) {
+    for (var k in obj) {
+      if (reg.test(k)) {
+        obj.removeItem(k)
+      }
+    }
+  }
+}
+
+function clearAllStorageOfReg(reg) {
+  clearStorage(sessionStorage, new RegExp(reg))
+  clearStorage(localStorage, new RegExp(reg))
+}
+
+function trackReport(type, ...args) {
+  try {
+    if (type === 'baidu') {
+      _hmt.push(['_trackEvent', ...args])
+    } else {
+      clab_tracker.track(...args)
+    }
+  } catch (e) {
+    console.warn(e)
+  }
+}
+
+function getScriptOptions () {
+  // 获取配置参数
+  const options = {
+    auto: false,
+    type: 'login-code'
+  }
+
+  try {
+    const scriptTag = document.currentScript
+    const queryParams = new URLSearchParams(scriptTag.src.split('?')[1])
+    if (queryParams.get('auto')) {
+      const params = queryParams.get('auto')
+      options.auto = params === 'true'
+    }
+    if (queryParams.get('type')) {
+      options.type = queryParams.get('type')
+    }
+  } catch (e) {
+    console.warn(e)
+  }
+
+  return options
+}
+
+export { preloadImage, clearStorage, clearAllStorageOfReg, trackReport, getScriptOptions }

+ 30 - 0
plugins/login-auth/src/utils/directive.ts

@@ -0,0 +1,30 @@
+import Vue from 'vue'
+
+Vue.directive('toggle-input-type', {
+  inserted: function (el, binding) {
+    var toggleInputType = function () {
+      var sibling = el.previousElementSibling // 获取上一个兄弟节点
+      if (sibling && sibling.tagName === 'INPUT') {
+        if (sibling.type === 'password') {
+          sibling.type = 'text' // 切换为文本输入
+        } else if (sibling.type === 'text') {
+          sibling.type = 'password' // 切换为密码输入
+        }
+      }
+    }
+
+    el.addEventListener('click', toggleInputType)
+
+    // 解绑指令时移除事件监听器
+    el.$destroy = function () {
+      el.removeEventListener('click', toggleInputType)
+    }
+  },
+  unbind: function (el) {
+    // 在解绑指令时执行移除事件监听器的操作
+    if (el.$destroy) {
+      el.$destroy()
+      delete el.$destroy
+    }
+  }
+})

+ 43 - 0
plugins/login-auth/src/utils/use.ts

@@ -0,0 +1,43 @@
+import Vue from 'vue'
+import { useUrlSearchParams } from '@vueuse/core'
+
+/**
+ * Toast 弹窗
+ * @param text
+ * @param duration
+ */
+export function useToast (text, duration = 2000) {
+  const thisInstance = Vue.prototype
+  return thisInstance.$toast(text, duration)
+}
+
+/**
+ * 获取当前页面 URL source 参数
+ */
+export function useURLSource () {
+  const params = useUrlSearchParams('history')
+  return String(params.source) || ''
+}
+
+/**
+ * 特殊 source 处理
+ */
+export function useCustomSpecialSource () {
+  let source = useURLSource()
+  if (source) {
+    const pathname = window.location.pathname
+    //结构化数据
+    if (pathname == '/front/structed/pc_index.html') {
+      source += '_structed'
+    }
+    //招标文件解读
+    if (pathname == '/bid/pc/page/bidfile_landpage') {
+      source += '_bidfile'
+    }
+    //大会员
+    if (pathname == '/big/page/index') {
+      source += '_member'
+    }
+  }
+  return source
+}

+ 403 - 0
plugins/login-auth/src/views/Layout.vue

@@ -0,0 +1,403 @@
+<script setup lang="ts">
+import login from './form/login.vue'
+import register from './form/register.vue'
+import wx from './form/wx.vue'
+import setPass from './form/setPass.vue'
+import bindPhone from './form/bindPhone.vue'
+import { computed } from 'vue'
+import { tabActive, tabActiveClassName } from '@/module-model/tab'
+import { adImg, getADInfo } from '@/module-model/loginLeftAd'
+
+getADInfo()
+
+const formComponents = {
+  login,
+  register,
+  wx,
+  setPass,
+  bindPhone
+}
+
+const formComponentMaps = {
+  'login-code': 'login',
+  'login-pass': 'login',
+  register: 'register',
+  'login-wx': 'wx',
+  'set-pass': 'setPass',
+  'bind-phone': 'bindPhone'
+}
+
+const activeComponentName = computed(() => {
+  const active = formComponentMaps[tabActive.value]
+  return active
+})
+</script>
+<template>
+  <div class="login-auth-group flex flex-row" :class="tabActiveClassName">
+    <!--  左侧广告区域 -->
+    <div class="login-auth--left" v-if="adImg">
+      <img alt="登录注册" :src="adImg" />
+    </div>
+
+    <div class="login-auth--right">
+      <!--  公共Logo & Close  -->
+      <div class="login-auth--top">
+        <img
+          src="https://www.jianyu360.cn/images/swordfish/sf_01_new.png"
+          alt="剑鱼标讯"
+        />
+        <span class="img-icon--close" @click="$emit('close')"></span>
+      </div>
+      <!--  表单  -->
+      <component :is="formComponents[activeComponentName]"></component>
+    </div>
+  </div>
+</template>
+
+<style lang="scss">
+@import '@/style/icon.scss';
+@include icon('icon-phone');
+@include icon('icon-pass');
+@include icon('icon-guard');
+@include icon('icon-biyan');
+@include icon('icon-see');
+@include icon('icon-email');
+@include icon('icon-company');
+@include icon('wx');
+@include icon('tip');
+@include icon('tip-active');
+@include icon('blue-back');
+
+.login-auth {
+  &-group {
+    width: min-content;
+    max-width: 720px;
+    height: 584px;
+    background: #fff;
+    z-index: 667;
+    position: absolute;
+    top: 50%;
+    margin-top: -282px;
+    left: 50%;
+    transform: translate(-50%, 0);
+    box-sizing: border-box;
+    border-radius: 16px;
+    overflow: hidden;
+  }
+
+  &--left,
+  &--right {
+    width: 50%;
+    min-width: 360px;
+  }
+  &--top {
+    margin-top: 32px;
+    margin-left: 40px;
+    img {
+      width: 96px;
+      height: 25px;
+    }
+    .img-icon--close {
+      background: url(@/assets/icon/close.png);
+      background-size: 20px 20px;
+      position: absolute;
+      width: 20px;
+      height: 20px;
+      right: 16px;
+      top: 16px;
+      transition: all 0.2s;
+      cursor: pointer;
+      &:hover {
+        transform: scale(1.1);
+      }
+    }
+  }
+  &--form {
+    padding: 0 40px;
+    .verify-img-group {
+      position: absolute;
+      cursor: pointer;
+      height: 100%;
+      top: 0;
+      right: 1px;
+      display: flex;
+      flex-direction: row;
+      align-items: center;
+      color: #999999;
+    }
+    .verify-img {
+      width: 88px;
+      height: 40px;
+      border-radius: 130px;
+      background-color: #ffffff;
+    }
+    &-input {
+      margin-top: 12px;
+      display: flex;
+      flex-direction: row;
+      align-items: center;
+      width: 280px;
+      height: 44px;
+      color: #1d1d1d;
+      font-size: 14px;
+      background: #f3f6f7;
+      border-radius: 20px;
+      padding: 0 16px;
+      box-sizing: border-box;
+      border: 1px solid #f3f6f7;
+      position: relative;
+      &.is-focus {
+        border-color: #2cb7ca;
+      }
+      input {
+        width: 100%;
+        height: 90%;
+        margin-left: 8px;
+        color: inherit;
+        font-size: inherit;
+        border: none;
+        outline: none;
+        padding: 0px;
+        background: #f3f6f7;
+        &:-webkit-autofill {
+          -webkit-box-shadow: 0 0 0px 1000px #f3f6f7 inset !important;
+        }
+      }
+      &.is-error {
+        border-color: #ff3a20;
+        margin-bottom: 36px;
+        &::after {
+          content: attr(data-error);
+          position: absolute;
+          bottom: -24px;
+          left: 8px;
+          color: #ff3a20;
+          font-size: 14px;
+          line-height: 20px;
+        }
+      }
+    }
+    &-after {
+      position: absolute;
+      cursor: pointer;
+      height: 100%;
+      top: 0;
+      right: 16px;
+      display: flex;
+      flex-direction: row;
+      align-items: center;
+      color: #999999;
+      &.disable {
+        cursor: not-allowed;
+      }
+    }
+
+    .pass-right-icon {
+      cursor: pointer;
+      height: 18px;
+    }
+    .pass-right-icon .img-icon {
+      display: none;
+    }
+    input[type='password'] + .pass-right-icon {
+      .icon-icon-biyan {
+        display: inline-block;
+      }
+    }
+    input[type='text'] + .pass-right-icon {
+      .icon-icon-see {
+        display: inline-block;
+      }
+    }
+
+    .img-icon.icon-icon-pass{
+      width: 20px;
+    }
+  }
+  &--switch-tab {
+    &-group {
+      position: relative;
+      margin-top: 32px;
+      margin-bottom: 12px;
+      &.is-active-last::before {
+        width: 80px;
+        left: 132px;
+      }
+      &::before {
+        content: '';
+        position: absolute;
+        display: inline-block;
+        bottom: 0;
+        left: 0;
+        width: 118px;
+        height: 3px;
+        background: #2cb7ca;
+        transition: all 0.33s;
+      }
+    }
+    &-item {
+      color: #999;
+      font-size: 16px;
+      line-height: 24px;
+      cursor: pointer;
+      padding-bottom: 8px;
+      &.is-active {
+        color: #1d1d1d;
+      }
+      & + & {
+        margin-left: 24px;
+      }
+    }
+  }
+  &--submit-button {
+    margin-top: 12px;
+    cursor: pointer;
+    width: 280px;
+    height: 44px;
+    background: #2cb7ca;
+    border-radius: 63px;
+    font-size: 16px;
+    line-height: 24px;
+    color: #fff;
+    outline: none;
+    border: 1px solid #2cb7ca;
+    &:disabled {
+      border-color: #e0e0e0;
+      background: #e0e0e0;
+      cursor: not-allowed;
+    }
+  }
+  &--tip {
+    word-break: keep-all;
+    font-size: 12px;
+    text-align: center;
+    margin-top: 32px;
+    line-height: 20px;
+    color: #999999;
+    a {
+      color: inherit;
+      font-size: inherit;
+    }
+  }
+}
+.toggle-wx-login {
+  .wx-tip {
+    font-size: 12px;
+    line-height: 20px;
+    color: #999999;
+    margin-top: 16px;
+    &::after,
+    &::before {
+      content: '';
+      display: inline-block;
+      width: 30px;
+      height: 1px;
+      background: #999;
+      margin: 4px;
+    }
+  }
+  .wx-logo {
+    cursor: pointer;
+    width: 40px;
+    height: 40px;
+    margin: 0 auto;
+    margin-top: 8px;
+    background: rgba(44, 183, 202, 0.12);
+    border-radius: 96px;
+    .img-icon {
+      width: 24px;
+      height: 24px;
+    }
+  }
+}
+.auto-login-container {
+  margin-bottom: 0;
+  cursor: pointer;
+  font-size: 14px;
+  font-weight: 400;
+  line-height: 22px;
+  color: #999;
+  margin-top: 12px;
+  &.is-active {
+    color: #2cb7ca;
+    .auto-login-checkbox {
+      background: url('@/assets/icon/select.png') no-repeat 50%;
+      background-color: #2cb7ca;
+      background-size: 9px 8px;
+      border: 1px solid #2cb7ca !important;
+    }
+  }
+  .icon-tip-container {
+    position: relative;
+  }
+  .auto-login-checkbox {
+    margin-right: 4px;
+    display: inline-block;
+    width: 16px;
+    height: 16px;
+    border: 1px solid #c8d3de;
+    border-radius: 2px;
+    vertical-align: top;
+    cursor: pointer;
+  }
+  .icon-tip-action {
+    line-height: 16px;
+    margin-left: 4px;
+  }
+  .icon-tip-action .img-icon {
+    width: 16px;
+    height: 16px;
+  }
+  .icon-tip-active {
+    display: none;
+  }
+  .icon-tip-action:hover {
+    .icon-tip {
+      display: none;
+    }
+    .icon-tip-active {
+      display: inline-block;
+    }
+    & + .j-tooltip {
+      display: block;
+    }
+  }
+  .j-tooltip {
+    display: none;
+    position: absolute;
+    right: -93px;
+    bottom: -53px;
+    width: 203px;
+    padding: 6px 16px;
+    background: #e5f6f8;
+    font-size: 12px;
+    line-height: 18px;
+    color: #2cb7ca;
+    border-radius: 3px;
+    text-align: center;
+    filter: drop-shadow(0px 4px 8px rgba(0, 0, 0, 0.08));
+    &::before {
+      content: '';
+      position: absolute;
+      top: -10px;
+      left: 50%;
+      display: block;
+      width: 0;
+      height: 0;
+      border: 6px solid transparent;
+      border-bottom-color: #e5f6f8;
+      transform: translate(-50%, 0);
+    }
+  }
+  .forget-pass-link {
+    color: #2cb7ca;
+  }
+}
+.toggle-login-container {
+  cursor: pointer;
+  margin-top: 12px;
+  span {
+    margin-left: 8px;
+  }
+}
+</style>

+ 211 - 0
plugins/login-auth/src/views/form/bindPhone.vue

@@ -0,0 +1,211 @@
+<script setup lang="ts">
+import { computed, ref } from 'vue'
+import { autoLoginState, doSelectAutoLogin } from '@/module-model/autoLogin'
+import { some } from 'lodash'
+import { ajaxSetBindPhone } from '@/api'
+import { useToast } from '@/utils/use'
+import pluginLogin from '@/lib/pluginLogin'
+
+const FormRules = {
+  // 账号登录
+  account: /^[a-zA-Z0-9\u4e00-\u9fa5@#&_-]/,
+  // 兼容虚拟号段【100】
+  phone: /^(1[3-9]\d{9}|1[0]\d{10})$/,
+  imgCode: /^\S{4}$/,
+  smsCode: /^\S{6}$/,
+  entName: /^\S{4,100}$/,
+  pass: /^\S{6,}$/
+}
+
+/**
+ * 表单
+ */
+
+const loginCodeFormState = ref({
+  phone: {
+    value: '',
+    validate: false
+  },
+  smsCaptcha: {
+    value: '',
+    validate: false
+  }
+})
+
+const loginCodeFormNode = ref(null)
+
+const loginCodeForm = {
+  isLoading: ref(false),
+  canSubmit: computed(() => {
+    return (
+      !loginCodeForm.isLoading.value &&
+      !some(loginCodeFormState.value, (item) => item.validate === false)
+    )
+  }),
+  doSubmit() {
+    if (!loginCodeForm.canSubmit.value) {
+      return
+    }
+    loginCodeForm.isLoading.value = true
+    const params = {
+      step: 2,
+      phone: loginCodeFormState.value.phone.value,
+      code: loginCodeFormState.value.smsCaptcha.value,
+      mode: ''
+    }
+    ajaxSetBindPhone(params).then((r) => {
+      if (r?.error_code > -1) {
+        pluginLogin.handleSuccess('bind-phone', r)
+      } else {
+        loginCodeFormNode.value.showError(2, (r?.error_msg || '绑定错误,请稍后再试'))
+      }
+      loginCodeForm.isLoading.value = false
+    }).catch(() => {
+      useToast('绑定错误,请稍后再试')
+      loginCodeForm.isLoading.value = false
+    })
+  }
+}
+
+const loginCodeFormSchema = {
+  fields: [
+    {
+      key: 'phone',
+      type: 'base',
+      icon: 'icon-phone',
+      message: '手机号码输入错误',
+      rule: FormRules.phone,
+      inputAttr: {
+        name: 'verify_phone',
+        type: 'tel',
+        placeholder: '输入手机号码',
+        maxlength: 11
+      }
+    },
+    {
+      key: 'smsCaptcha',
+      type: 'smsCaptcha',
+      icon: 'icon-guard',
+      message: '短信验证码输入错误',
+      rule: FormRules.smsCode,
+      inputAttr: {
+        name: 'verify_sms',
+        type: 'text',
+        placeholder: '输入短信验证码',
+        maxlength: 6
+      },
+      expands: {
+        preCheckState: computed(() => {
+          const result = loginCodeFormState.value.phone.validate
+          return result
+        })
+      },
+      actions: {
+        preSubmit: async function () {
+          const params = {
+            step: 1,
+            phone: loginCodeFormState.value.phone.value,
+            code: loginCodeFormState.value.smsCaptcha.value
+          }
+          const result = await ajaxSetBindPhone(params).then((res) => {
+            if (res?.error_code > -1) {
+              return true
+            } else {
+              switch (res?.error_msg) {
+                case '图形验证码错误': {
+                  loginCodeFormNode.value.showError(1, '图形验证码输入错误')
+                  loginCodeFormNode.value.doRefreshCaptcha()
+                  break
+                }
+                case '手机号已被使用': {
+                  loginCodeFormNode.value.showError(0, '该手机号已被绑定,请更换手机号')
+                  break
+                }
+                default: {
+                  useToast(res?.error_msg || '发送错误,请稍后再试')
+                  break
+                }
+              }
+              return false
+            }
+          }).catch(() => {
+            useToast('发送错误,请稍后再试')
+          })
+          return result
+        }
+      }
+    }
+  ]
+}
+</script>
+<template>
+  <!--  表单  -->
+  <div class="login-auth--form">
+    <div class="bind-phone-tip">
+      <h3>绑定手机号</h3>
+      <span>为了给您提供更好的服务,请绑定手机号!</span>
+    </div>
+    <!-- 验证码登录 -->
+    <div class="login-auth--switch-tab-content">
+      <base-form
+        ref="loginCodeFormNode"
+        @submit="loginCodeForm.doSubmit"
+        :schema="loginCodeFormSchema.fields"
+        v-model="loginCodeFormState"
+      ></base-form>
+      <button
+        class="login-auth--submit-button"
+        name="verify_submit"
+        :disabled="!loginCodeForm.canSubmit.value"
+        @click="loginCodeForm.doSubmit"
+      >
+        立即绑定
+      </button>
+    </div>
+
+    <div
+      class="auto-login-container flex flex-row items-center justify-center"
+      :class="{ 'is-active': autoLoginState }"
+    >
+      <div class="flex flex-row items-center justify-center">
+        <div
+          class="flex flex-row items-center select-none"
+          @click="doSelectAutoLogin(!autoLoginState)"
+        >
+          <div class="auto-login-checkbox"></div>
+          <span>下次自动登录</span>
+        </div>
+        <div class="icon-tip-container">
+          <div class="icon-tip-action">
+            <i class="img-icon icon-tip"></i>
+            <i class="img-icon icon-tip-active"></i>
+          </div>
+          <div class="j-tooltip">
+            为了确保你的信息安全,不建议在公共设备上勾选此项。
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<style lang="scss">
+.bind-phone-tip {
+  padding: 12px 0 24px;
+  width: 100%;
+  text-align: center;
+  h3 {
+    color: #1d1d1d;
+    font-size: 16px;
+    line-height: 24px;
+    letter-spacing: 0px;
+  }
+  span {
+    margin-top: 6px;
+    color: #999999;
+    font-size: 12px;
+    line-height: 20px;
+    text-align: center;
+  }
+}
+</style>

+ 436 - 0
plugins/login-auth/src/views/form/login.vue

@@ -0,0 +1,436 @@
+<script setup lang="ts">
+import { some } from 'lodash'
+import { ajaxSetLogin } from '@/api'
+import { computed, ref } from 'vue'
+import { tabActive, doChangeTabActive } from '@/module-model/tab'
+import { autoLoginState, doSelectAutoLogin } from '@/module-model/autoLogin'
+import { FormRules } from '@/data/constant'
+import { trackReport } from '@/utils/common'
+import { useToast } from '@/utils/use'
+import pluginLogin from '@/lib/pluginLogin'
+
+// 埋点上报
+
+function track() {
+  const href = window.location.href
+  let sourceStr = ''
+  if (href.indexOf('/front/structed/pc_index.html?source=baidusem') > -1) {
+    sourceStr = '结构化数据-pc-baidusem'
+  } else if (
+    href.indexOf('/bid/pc/page/bidfile_landpage?source=baidusem') > -1
+  ) {
+    sourceStr = '招标文件解读-pc-baidusem'
+  }
+
+  if (sourceStr) {
+    trackReport('baidu', sourceStr, 'click', '登录')
+  }
+
+  trackReport('huiju', 'c_register', {
+    c_platform: 'pc',
+    c_type: '注册行为-登录或注册弹窗',
+    date: new Date()
+  })
+}
+
+track()
+
+// 表单 -- 验证码登录
+const loginCodeFormState = ref({
+  phone: {
+    value: '',
+    validate: false
+  },
+  imgCaptcha: {
+    value: '',
+    validate: false
+  },
+  smsCaptcha: {
+    value: '',
+    validate: false
+  }
+})
+
+const loginCodeFormNode = ref(null)
+
+const loginCodeForm = {
+  isLoading: ref(false),
+  canSubmit: computed(() => {
+    return (
+      !loginCodeForm.isLoading.value &&
+      !some(loginCodeFormState.value, (item) => item.validate === false)
+    )
+  }),
+  doSubmit() {
+    trackReport('huiju', 'c_register', {
+      c_platform: 'pc',
+      c_type: '注册行为-登录/注册',
+      date: new Date()
+    })
+
+    if (!loginCodeForm.canSubmit.value) {
+      return
+    }
+    loginCodeForm.isLoading.value = true
+    const urlParams = useUrlSearchParams()
+    const params = {
+      reqType: 'identCodeLogin',
+      identCode: loginCodeFormState.value.smsCaptcha.value,
+      isAutoLogin: autoLoginState.value,
+      source: urlParams.source
+    }
+    ajaxSetLogin(params).then(({ data }) => {
+      // 新用户 -> 设置密码
+      switch (data.status) {
+        case -1: {
+          loginCodeFormNode.value.showError(2, '短信验证码输入错误')
+          break
+        }
+        case -4: {
+          loginCodeFormNode.value.showError(2, '系统错误,请重试')
+          break
+        }
+        case 1: {
+          pluginLogin.handleUpdateInfo('login-code', data)
+          // 打开设置密码弹窗
+          if (data?.userInfo?.isNewUser) {
+            doChangeTabActive('set-pass')
+          } else {
+            pluginLogin.handleSuccess('login-code', data)
+          }
+          break
+        }
+      }
+      loginCodeForm.isLoading.value = false
+    }).catch(() => {
+      loginCodeForm.isLoading.value = false
+      useToast('出现错误,请稍后重试')
+    })
+  }
+}
+
+const loginCodeFormSchema = {
+  fields: [
+    {
+      key: 'phone',
+      type: 'base',
+      icon: 'icon-phone',
+      message: '手机号码输入错误',
+      rule: FormRules.phone,
+      inputAttr: {
+        name: 'verify_phone',
+        type: 'tel',
+        placeholder: '输入手机号码',
+        maxlength: 11
+      }
+    },
+    {
+      key: 'imgCaptcha',
+      type: 'imgCaptcha',
+      icon: 'icon-guard',
+      message: '图形验证码输入错误',
+      rule: FormRules.imgCode,
+      inputAttr: {
+        name: 'verify_code',
+        type: 'text',
+        placeholder: '输入图形验证码',
+        maxlength: 4
+      }
+    },
+    {
+      key: 'smsCaptcha',
+      type: 'smsCaptcha',
+      icon: 'icon-guard',
+      message: '短信验证码输入错误',
+      rule: FormRules.smsCode,
+      inputAttr: {
+        name: 'verify_sms',
+        type: 'text',
+        placeholder: '输入短信验证码',
+        maxlength: 6
+      },
+      expands: {
+        preCheckState: computed(() => {
+          const result =
+            loginCodeFormState.value.phone.validate &&
+            loginCodeFormState.value.imgCaptcha.validate
+          return result
+        })
+      },
+      actions: {
+        preSubmit: async function () {
+          trackReport('huiju', 'c_register', {
+            c_platform: 'pc',
+            c_type: '注册行为-验证码登录/注册-获取验证码',
+            date: new Date()
+          })
+
+          const params = {
+            reqType: 'sendIdentCode',
+            phone: loginCodeFormState.value.phone.value,
+            code: loginCodeFormState.value.imgCaptcha.value
+          }
+          const result = await ajaxSetLogin(params).then(({ data }) => {
+            const type = data.status
+            if (type < 0) {
+              const errorMaps = {
+                '-1': {
+                  key: 0,
+                  message: '手机号格式错误'
+                },
+                '-2': {
+                  key: 1,
+                  message: '图形验证码输入错误'
+                },
+                '-3': {
+                  key: 0,
+                  message: '手机号已被注册'
+                }
+              }
+              loginCodeFormNode.value.showError(
+                errorMaps[type].key,
+                errorMaps[type].message
+              )
+              if (type === -2 || type === -3) {
+                loginCodeFormNode.value.doRefreshCaptcha()
+              }
+              return false
+            }
+            return true
+          }).catch(() => {
+            useToast('出现错误,请稍后重试')
+          })
+          return result
+        }
+      }
+    }
+  ]
+}
+
+// 表单 - 密码登录
+const loginPassFormState = ref({
+  phone: {
+    value: '',
+    validate: false
+  },
+  pass: {
+    value: '',
+    validate: false
+  }
+})
+
+const loginPassFormNode = ref(null)
+
+const loginPassForm = {
+  isLoading: ref(false),
+  canSubmit: computed(() => {
+    return (
+      !loginPassForm.isLoading.value &&
+      !some(loginPassFormState.value, (item) => item.validate === false)
+    )
+  }),
+  doSubmit() {
+    trackReport('huiju', 'c_register', {
+      c_platform: 'pc',
+      c_type: '注册行为-验证码登录/注册-获取验证码',
+      date: new Date()
+    })
+
+    if (!loginPassForm.canSubmit.value) {
+      return
+    }
+    loginPassForm.isLoading.value = true
+    const params = {
+      reqType: 'phoneLogin',
+      phone: loginPassFormState.value.phone.value,
+      password: loginPassFormState.value.pass.value,
+      isAutoLogin: autoLoginState.value
+    }
+    ajaxSetLogin(params).then(({ data }) => {
+      // 新用户 -> 设置密码
+      switch (data.status) {
+        case -1: {
+          loginPassFormNode.value.showError(0, '手机号或账号名输入错误')
+          break
+        }
+        case -2: {
+          loginPassFormNode.value.showError(1, '密码输入错误')
+          break
+        }
+        case 1: {
+          pluginLogin.handleUpdateInfo('login-pass', data)
+          pluginLogin.handleSuccess('login-pass', data)
+          break
+        }
+      }
+      loginPassForm.isLoading.value = false
+    }).catch(() => {
+      loginPassForm.isLoading.value = false
+      useToast('出现错误,请稍后重试')
+    })
+  }
+}
+
+const loginPassFormSchema = {
+  fields: [
+    {
+      key: 'phone',
+      type: 'base',
+      icon: 'icon-phone',
+      message: '手机号码输入错误',
+      rule: FormRules.account,
+      inputAttr: {
+        name: 'pass_phone',
+        type: 'text',
+        placeholder: '请输入手机号或账号名',
+        maxlength: 30
+      }
+    },
+    {
+      key: 'pass',
+      type: 'pass',
+      icon: 'icon-pass',
+      message: '密码输入错误',
+      rule: FormRules.pass,
+      inputAttr: {
+        name: 'pass_pass',
+        type: 'password',
+        placeholder: '输入密码',
+        minlength: 6
+      }
+    }
+  ]
+}
+</script>
+<template>
+  <!--  表单  -->
+  <div class="login-auth--form">
+    <!-- 验证码登录 / 密码登录 -->
+    <template v-if="tabActive === 'login-code' || tabActive === 'login-pass'">
+      <!--  头部切换  -->
+      <div
+        class="login-auth--switch-tab-group flex flex-row"
+        :class="{ 'is-active-last': tabActive !== 'login-code' }"
+      >
+        <div
+          class="login-auth--switch-tab-item"
+          :class="{ 'is-active': tabActive === 'login-code' }"
+          @click="doChangeTabActive('login-code')"
+        >
+          验证码登录/注册
+        </div>
+        <div
+          class="login-auth--switch-tab-item"
+          :class="{ 'is-active': tabActive === 'login-pass' }"
+          @click="doChangeTabActive('login-pass')"
+        >
+          密码登录
+        </div>
+      </div>
+      <!-- 验证码登录 -->
+      <div
+        class="login-auth--switch-tab-content"
+        v-if="tabActive === 'login-code'"
+      >
+        <base-form
+          ref="loginCodeFormNode"
+          @submit="loginCodeForm.doSubmit"
+          :schema="loginCodeFormSchema.fields"
+          v-model="loginCodeFormState"
+        ></base-form>
+        <button
+          class="login-auth--submit-button"
+          name="verify_submit"
+          :disabled="!loginCodeForm.canSubmit.value"
+          @click="loginCodeForm.doSubmit"
+        >
+          登录/注册
+        </button>
+      </div>
+
+      <!-- 密码登录 -->
+      <div
+        class="login-auth--switch-tab-content"
+        v-if="tabActive === 'login-pass'"
+      >
+        <base-form
+          ref="loginPassFormNode"
+          @submit="loginPassForm.doSubmit"
+          :schema="loginPassFormSchema.fields"
+          v-model="loginPassFormState"
+        ></base-form>
+        <button
+          class="login-auth--submit-button"
+          name="verify_submit"
+          :disabled="!loginPassForm.canSubmit.value"
+          @click="loginPassForm.doSubmit"
+        >
+          登录
+        </button>
+      </div>
+
+      <div
+        class="auto-login-container flex flex-row items-center justify-center"
+        :class="{
+          'is-active': autoLoginState,
+          'justify-between': tabActive === 'login-pass'
+        }"
+      >
+        <div class="flex flex-row items-center justify-center">
+          <div
+            class="flex flex-row items-center select-none"
+            @click="doSelectAutoLogin(!autoLoginState)"
+          >
+            <div class="auto-login-checkbox"></div>
+            <span>下次自动登录</span>
+          </div>
+          <div class="icon-tip-container">
+            <div class="icon-tip-action">
+              <i class="img-icon icon-tip"></i>
+              <i class="img-icon icon-tip-active"></i>
+            </div>
+            <div class="j-tooltip">
+              为了确保你的信息安全,不建议在公共设备上勾选此项。
+            </div>
+          </div>
+        </div>
+
+        <div v-if="tabActive === 'login-pass'">
+          <a class="forget-pass-link" href="/phone/forgetPwd">忘记密码?</a>
+        </div>
+      </div>
+
+      <div class="toggle-wx-login flex flex-col items-center justify-center">
+        <div class="wx-tip">使用微信扫码登录</div>
+        <div
+          class="wx-logo flex items-center justify-center"
+          @click="doChangeTabActive('login-wx')"
+        >
+          <div class="img-icon icon-wx"></div>
+        </div>
+      </div>
+
+      <p class="login-auth--tip" v-if="tabActive === 'login-code'">
+        未注册用户验证后自动注册,登录/注册即代表同意
+        <span style="text-wrap: nowrap">
+          <a href="/front/staticPage/permission_rules.html"
+            >《剑鱼标讯用户使用许可协议》</a
+          >
+          <a href="/front/staticPage/privacy_rules.html"
+            >《剑鱼标讯隐私政策》</a
+          >
+        </span>
+      </p>
+
+      <p class="login-auth--tip" v-if="tabActive === 'login-pass'">
+        登录即代表同意
+        <a href="/front/staticPage/permission_rules.html"
+          >《剑鱼标讯用户使用许可协议》</a
+        >
+        <a href="/front/staticPage/privacy_rules.html">《剑鱼标讯隐私政策》</a>
+      </p>
+    </template>
+  </div>
+</template>
+
+<style lang="scss"></style>

+ 271 - 0
plugins/login-auth/src/views/form/register.vue

@@ -0,0 +1,271 @@
+<script setup lang="ts">
+import { computed, ref } from 'vue'
+import { doChangeTabActive } from '@/module-model/tab'
+import { some } from 'lodash'
+import { ajaxSetLogin } from '@/api'
+import { useCustomSpecialSource, useToast } from '@/utils/use'
+import pluginLogin from '@/lib/pluginLogin'
+
+const FormRules = {
+  // 账号登录
+  account: /^[a-zA-Z0-9\u4e00-\u9fa5@#&_-]/,
+  // 兼容虚拟号段【100】
+  phone: /^(1[3-9]\d{9}|1[0]\d{10})$/,
+  imgCode: /^\S{4}$/,
+  smsCode: /^\S{6}$/,
+  entName: /^\S{4,100}$/,
+  pass: /^\S{6,}$/,
+  email: /.*/
+}
+
+/**
+ * 表单
+ */
+
+const loginCodeFormState = ref({
+  phone: {
+    value: '',
+    validate: false
+  },
+  imgCaptcha: {
+    value: '',
+    validate: false
+  },
+  smsCaptcha: {
+    value: '',
+    validate: false
+  },
+  entName: {
+    value: '',
+    validate: false
+  },
+  email: {
+    value: '',
+    validate: true
+  }
+})
+
+const loginCodeFormNode = ref(null)
+
+const loginCodeForm = {
+  isLoading: ref(false),
+  canSubmit: computed(() => {
+    const tempState = Object.assign({}, loginCodeFormState.value)
+    tempState.email.validate = true
+    return (
+      !loginCodeForm.isLoading.value &&
+      !some(tempState, (item) => {
+        return item.validate === false
+      })
+    )
+  }),
+  doSubmit() {
+    if (!loginCodeForm.canSubmit.value) {
+      return
+    }
+    loginCodeForm.isLoading.value = true
+    const params = {
+      reqType: 'identCodeLogin',
+      s_entname: loginCodeFormState.value.entName.value,
+      identCode: loginCodeFormState.value.smsCaptcha.value,
+      isAutoLogin: false,
+      email: loginCodeFormState.value.email.value,
+      source: useCustomSpecialSource()
+    }
+    ajaxSetLogin(params).then(({ data }) => {
+      // 新用户 -> 设置密码
+      switch (data.status) {
+        case -1: {
+          loginCodeFormNode.value.showError(2, '短信验证码输入错误')
+          break
+        }
+        case -4: {
+          loginCodeFormNode.value.showError(2, '系统错误,请重试')
+          break
+        }
+        case 1: {
+          pluginLogin.handleUpdateInfo('register', data)
+          if (data.userInfo.isNewUser) {
+            doChangeTabActive('set-pass')
+          } else {
+            pluginLogin.handleSuccess('register', data)
+          }
+          loginCodeFormNode.value.showError(2, '短信验证码输入错误')
+          break
+        }
+      }
+      loginCodeForm.isLoading.value = false
+    }).catch(() => {
+      loginCodeForm.isLoading.value = false
+      useToast('出现错误,请稍后重试')
+    })
+  }
+}
+
+const loginCodeFormSchema = {
+  fields: [
+    {
+      key: 'phone',
+      type: 'base',
+      icon: 'icon-phone',
+      message: '手机号码输入错误',
+      rule: FormRules.phone,
+      inputAttr: {
+        name: 'verify_phone',
+        type: 'tel',
+        placeholder: '输入手机号码',
+        maxlength: 11
+      }
+    },
+    {
+      key: 'imgCaptcha',
+      type: 'imgCaptcha',
+      icon: 'icon-guard',
+      message: '图形验证码输入错误',
+      rule: FormRules.imgCode,
+      inputAttr: {
+        name: 'verify_code',
+        type: 'text',
+        placeholder: '输入图形验证码',
+        maxlength: 4
+      }
+    },
+    {
+      key: 'smsCaptcha',
+      type: 'smsCaptcha',
+      icon: 'icon-guard',
+      message: '短信验证码输入错误',
+      rule: FormRules.smsCode,
+      inputAttr: {
+        name: 'verify_sms',
+        type: 'text',
+        placeholder: '输入短信验证码',
+        maxlength: 6
+      },
+      expands: {
+        preCheckState: computed(() => {
+          const result =
+            loginCodeFormState.value.phone.validate &&
+            loginCodeFormState.value.imgCaptcha.validate
+          return result
+        })
+      },
+      actions: {
+        preSubmit: async function () {
+          const params = {
+            reqType: 'sendIdentCode',
+            phone: loginCodeFormState.value.phone.value,
+            code: loginCodeFormState.value.imgCaptcha.value
+          }
+          const result = await ajaxSetLogin(params).then(({ data }) => {
+            const type = data.status
+            if (type < 0) {
+              const errorMaps = {
+                '-1': {
+                  key: 0,
+                  message: '手机号格式错误'
+                },
+                '-2': {
+                  key: 1,
+                  message: '图形验证码输入错误'
+                },
+                '-3': {
+                  key: 0,
+                  message: '手机号已被注册'
+                }
+              }
+              loginCodeFormNode.value.showError(
+                errorMaps[type].key,
+                errorMaps[type].message
+              )
+              if (type === -2) {
+                loginCodeFormNode.value.doRefreshCaptcha()
+              }
+              return false
+            }
+            return true
+          }).catch(() => {
+            useToast('出现错误,请稍后重试')
+          })
+          return result
+        }
+      }
+    },
+    {
+      key: 'entName',
+      type: 'autocomplete',
+      icon: 'icon-company',
+      message: '公司名称最少4个字',
+      rule: FormRules.entName,
+      inputAttr: {
+        name: 'verify_entname',
+        type: 'text',
+        placeholder: '输入公司名称',
+        maxlength: 30
+      }
+    },
+    {
+      key: 'email',
+      type: 'base',
+      icon: 'icon-email',
+      message: '邮箱输入错误',
+      rule: FormRules.email,
+      inputAttr: {
+        name: 'register_email',
+        type: 'text',
+        placeholder: '输入电子邮箱'
+      }
+    }
+  ]
+}
+</script>
+<template>
+  <!--  表单  -->
+  <div class="login-auth--form">
+    <!-- 验证码登录 -->
+    <div class="login-auth--switch-tab-content">
+      <base-form
+        ref="loginCodeFormNode"
+        @submit="loginCodeForm.doSubmit"
+        :schema="loginCodeFormSchema.fields"
+        v-model="loginCodeFormState"
+      ></base-form>
+
+      <div class="register-show-space">
+        <img
+          src="https://cdn-ali2.jianyu360.cn/images/pc/register_email.png"
+          alt="注册活动"
+        />
+      </div>
+
+      <button
+        class="login-auth--submit-button"
+        name="verify_submit"
+        :disabled="!loginCodeForm.canSubmit.value"
+        @click="loginCodeForm.doSubmit"
+      >
+        立即注册
+      </button>
+
+      <div
+        class="toggle-login-container flex flex-row items-center justify-center"
+        @click="doChangeTabActive('login-code')"
+      >
+        <i class="img-icon icon-blue-back"></i>
+        <span>登录</span>
+      </div>
+    </div>
+  </div>
+</template>
+
+<style lang="scss">
+.register-show-space {
+  margin-top: 16px;
+  width: 292px;
+  height: 54px;
+  img {
+    width: 100%;
+    height: 100%;
+  }
+}
+</style>

+ 160 - 0
plugins/login-auth/src/views/form/setPass.vue

@@ -0,0 +1,160 @@
+<script setup lang="ts">
+import { computed, reactive, ref } from 'vue'
+import { some } from 'lodash'
+import { ajaxSetPass } from '@/api'
+import { FormRules } from '@/data/constant'
+import { useCustomSpecialSource, useToast } from '@/utils/use'
+import pluginLogin from '@/lib/pluginLogin'
+
+// 表单 $refs
+const formNode = ref(null)
+
+// 表单状态
+const formState = reactive({
+  password: {
+    value: '',
+    validate: false
+  },
+  password2: {
+    value: '',
+    validate: false
+  }
+})
+
+// 表单 Schema
+const formSchema = [
+  {
+    key: 'password',
+    type: 'pass',
+    icon: 'icon-pass',
+    message: '密码不少于6位',
+    rule: FormRules.pass,
+    inputAttr: {
+      name: 'init_pass',
+      type: 'password',
+      placeholder: '设置密码(最少6位)'
+    }
+  },
+  {
+    key: 'password2',
+    type: 'pass',
+    icon: 'icon-pass',
+    message: '两次密码输入不一致',
+    rule: function (val) {
+      const canNext = formState.password.value === val
+      return {
+        result: canNext,
+        message: '两次密码输入不一致'
+      }
+    },
+    inputAttr: {
+      name: 'check_pass',
+      type: 'password',
+      placeholder: '确认密码'
+    }
+  }
+]
+
+// 表单提交按钮事件
+
+const formSubmitLoading = ref(false)
+const canSubmit = computed(() => {
+  return (
+    !formSubmitLoading.value &&
+    !some(formState, (item) => {
+      return item.validate === false
+    })
+  )
+})
+
+// 提交表单
+
+function doSubmit(type) {
+  if (!type) {
+    pluginLogin.close()
+    return
+  }
+  if (!canSubmit.value) {
+    return
+  }
+  formSubmitLoading.value = true
+  const params = {
+    password: formState.password.value,
+    source: useCustomSpecialSource()
+  }
+  ajaxSetPass(params).then(({ data }) => {
+    if (data) {
+      pluginLogin.handleSuccess('set-pass', data)
+    } else {
+      formNode.value.showError(1, '密码保存失败')
+    }
+    formSubmitLoading.value = false
+  }).catch(() => {
+    formSubmitLoading.value = false
+    useToast('出现错误,请稍后重试')
+  })
+}
+</script>
+<template>
+  <!--  表单  -->
+  <div class="login-auth--form">
+    <!--  头部切换  -->
+    <div class="login-auth--switch-tab-group flex flex-row">
+      <div class="login-auth--switch-tab-item is-active">设置密码</div>
+    </div>
+    <!-- 设置密码 -->
+    <div class="login-auth--switch-tab-content">
+      <base-form
+        ref="loginCodeFormNode"
+        @submit="doSubmit"
+        :schema="formSchema"
+        v-model="formState"
+      >
+      </base-form>
+
+      <button
+        class="login-auth--submit-button"
+        name="verify_submit"
+        :disabled="!canSubmit"
+        @click="doSubmit"
+      >
+        确定
+      </button>
+      <button
+        class="login-auth--submit-button is-secondary"
+        name="verify_submit"
+        @click="doSubmit(false)"
+      >
+        暂不设置
+      </button>
+
+      <div class="set-pass-tip">
+        您可前往【设置-帐号与安全】设置或修改登录密码
+      </div>
+    </div>
+  </div>
+</template>
+
+<style lang="scss">
+.form-set-pass {
+  .login-auth--form {
+    .login-auth--switch-tab-group::before {
+      width: 64px;
+    }
+  }
+  .set-pass-tip {
+    margin-top: 12px;
+    color: #999;
+    text-align: center;
+    font-size: 12px;
+    font-style: normal;
+    font-weight: 400;
+    line-height: 18px;
+  }
+  .login-auth--submit-button.is-secondary {
+    background: #fff;
+    color: #1d1d1d;
+    border: 1px solid rgba(0, 0, 0, 0.05);
+  }
+}
+</style>

+ 91 - 0
plugins/login-auth/src/views/form/wx.vue

@@ -0,0 +1,91 @@
+<script setup lang="ts">
+import { tabActive, doChangeTabActive } from '@/module-model/tab'
+import { autoLoginState, doSelectAutoLogin } from '@/module-model/autoLogin'
+import { pageWechatQrcodeImgSrc, pageShareId } from '@/module-model/wxQrcode'
+import PluginLogin from '@/lib/pluginLogin'
+
+PluginLogin.start()
+</script>
+<template>
+  <!--  表单  -->
+  <div class="login-auth--form type-wx">
+    <div class="flex flex-col items-center justify-center">
+      <div class="wx-login--top-tip flex flex-row items-center justify-center">
+        <i class="img-icon icon-wx"></i>
+        <span>微信扫码登录,安全便捷</span>
+      </div>
+      <img
+        v-if="pageShareId"
+        class="wx-login--qrcode"
+        :src="pageWechatQrcodeImgSrc"
+        alt="微信扫码登录"
+      />
+    </div>
+
+    <div
+      class="auto-login-container flex flex-row items-center justify-center"
+      :class="{
+        'is-active': autoLoginState,
+        'justify-between': tabActive === 'login-pass'
+      }"
+    >
+      <div class="flex flex-row items-center justify-center">
+        <div
+          class="flex flex-row items-center select-none"
+          @click="doSelectAutoLogin(!autoLoginState)"
+        >
+          <div class="auto-login-checkbox"></div>
+          <span>下次自动登录</span>
+        </div>
+        <div class="icon-tip-container">
+          <div class="icon-tip-action">
+            <i class="img-icon icon-tip"></i>
+            <i class="img-icon icon-tip-active"></i>
+          </div>
+          <div class="j-tooltip">
+            为了确保你的信息安全,不建议在公共设备上勾选此项。
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <div
+      class="toggle-login-container flex flex-row items-center justify-center"
+      @click="doChangeTabActive('login-code')"
+    >
+      <i class="img-icon icon-blue-back"></i>
+      <span>验证码/密码登录</span>
+    </div>
+    <p class="login-auth--tip">
+      未注册用户验证后自动注册,登录/注册即代表同意
+      <span style="text-wrap: nowrap">
+        <a href="/front/staticPage/permission_rules.html"
+          >《剑鱼标讯用户使用许可协议》</a
+        >
+        <a href="/front/staticPage/privacy_rules.html">《剑鱼标讯隐私政策》</a>
+      </span>
+    </p>
+  </div>
+</template>
+
+<style lang="scss">
+.wx-login--top-tip {
+  margin-top: 48px;
+  padding: 4px 20px;
+  border-radius: 52px;
+  background: rgba(44, 183, 202, 0.08);
+  .icon-wx {
+    margin-right: 8px;
+  }
+}
+.wx-login--qrcode {
+  width: 240px;
+  height: 240px;
+  object-fit: contain;
+}
+.type-wx {
+  .auto-login-container {
+    margin-top: 0;
+  }
+}
+</style>

+ 6 - 0
plugins/login-auth/tailwind.config.js

@@ -0,0 +1,6 @@
+module.exports = {
+  darkMode: 'class', // or 'media'
+  theme: {},
+  variants: {},
+  plugins: []
+}

+ 32 - 0
plugins/login-auth/tsconfig.json

@@ -0,0 +1,32 @@
+{
+  "compilerOptions": {
+    "target": "esnext",
+    "module": "esnext",
+    "strict": true,
+    "jsx": "preserve",
+    "importHelpers": true,
+    "moduleResolution": "node",
+    "skipLibCheck": true,
+    "esModuleInterop": true,
+    "allowSyntheticDefaultImports": true,
+    "sourceMap": true,
+    "baseUrl": ".",
+    "types": ["@vueuse/core"],
+    "paths": {
+      "@/*": ["src/*"]
+    },
+    "lib": ["esnext", "dom", "dom.iterable", "scripthost"]
+  },
+  "include": [
+    "src/**/*.ts",
+    "src/**/*.tsx",
+    "src/**/*.vue",
+    "src/**/*.d.ts",
+    "tests/**/*.ts",
+    "tests/**/*.tsx"
+  ],
+  "exclude": ["node_modules"],
+  "vueCompilerOptions": {
+    "target": 2.7
+  }
+}

+ 139 - 0
plugins/login-auth/vite.config.js

@@ -0,0 +1,139 @@
+import path from 'node:path'
+import { defineConfig } from 'vite'
+import vue from '@vitejs/plugin-vue2'
+import WindiCSS from 'vite-plugin-windicss'
+import Components from 'unplugin-vue-components/vite'
+import Icons from 'unplugin-icons/vite'
+import IconsResolver from 'unplugin-icons/resolver'
+import AutoImport from 'unplugin-auto-import/vite'
+import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js'
+import prefixer from 'postcss-prefix-selector'
+import basicSsl from '@vitejs/plugin-basic-ssl'
+
+const buildMap = {
+  // 抽取vue等库
+  external: {
+    lib: {
+      entry: path.resolve(__dirname, 'src/lib/main.ts'),
+      name: 'JyLogin',
+      fileName: 'jy-login-mini'
+    },
+    rollupOptions: {
+      external: ['vue'],
+      output: {
+        globals: {
+          vue: 'Vue'
+        }
+      }
+    }
+  },
+  // 不抽取vue等库,全部打包到一起
+  internal: {
+    lib: {
+      entry: path.resolve(__dirname, 'src/lib/main.ts'),
+      name: 'JyLogin',
+      fileName: 'jy-login'
+    }
+  }
+}
+
+// 参数  { mode: 'external', command: 'build', ssrBuild: false }
+export default ({ mode, command }) => {
+  const buildDiff = buildMap[mode] || {}
+
+  return defineConfig({
+    resolve: {
+      alias: {
+        '@': `${path.resolve(__dirname, 'src')}`
+      }
+    },
+    build: {
+      target: 'chrome58',
+      cssTarget: 'chrome58',
+      minify: true,
+      emptyOutDir: false,
+      ...buildDiff
+    },
+    define: {
+      'process.env.NODE_ENV': '"production"'
+    },
+    css: {
+      postcss: {
+        plugins: [
+          prefixer({
+            prefix: '.plugin-login-auth-container',
+            transform(prefix, selector, prefixedSelector, filePath, rule) {
+              if (selector.match(/^(html|body)/))
+                return selector.replace(/^([^\s]*)/, `$1 ${prefix}`)
+
+              if (filePath.match(/node_modules/)) return selector
+
+              const annotation = rule.prev()
+              if (
+                annotation?.type === 'comment' &&
+                annotation.text.trim() === 'no-prefix'
+              )
+                return selector // Do not prefix style rules that are preceded by: /* no-prefix */
+
+              return prefixedSelector
+            }
+          })
+        ]
+      }
+    },
+    plugins: [
+      basicSsl(),
+      vue(),
+      WindiCSS(),
+      Components({
+        resolvers: [
+          IconsResolver({
+            componentPrefix: ''
+          })
+        ],
+        dts: 'src/components.d.ts'
+      }),
+      Icons(),
+      cssInjectedByJsPlugin(),
+      AutoImport({
+        imports: ['@vueuse/core'],
+        dts: 'src/auto-imports.d.ts'
+      })
+    ],
+
+    server: {
+      https: true,
+      host: true,
+      port: 3333,
+      proxy: {
+        '/aiChat': {
+          target: 'https://jybx3-webtest.jydev.jianyu360.com',
+          changeOrigin: true
+        },
+        '/jyapi': {
+          target: 'https://jybx3-webtest.jydev.jianyu360.com',
+          changeOrigin: true
+        },
+        '/api': {
+          target: 'https://jybx3-webtest.jydev.jianyu360.com',
+          changeOrigin: true,
+          rewrite: (path) => path.replace(/^\/api/, '')
+        },
+        '/front': {
+          target: 'https://jybx3-webtest.jydev.jianyu360.com',
+          changeOrigin: true
+        },
+        '/aiChat/ws': {
+          target: 'ws://jybx3-webtest.jydev.jianyu360.com',
+          changeOrigin: true,
+          ws: true
+        },
+        '/ws': {
+          target: 'wss://jybx3-webtest.jydev.jianyu360.com',
+          changeOrigin: true,
+          ws: true
+        }
+      }
+    }
+  })
+}

+ 3403 - 0
plugins/login-auth/yarn.lock

@@ -0,0 +1,3403 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@antfu/eslint-config-basic@0.38.2":
+  version "0.38.2"
+  resolved "https://registry.npmmirror.com/@antfu/eslint-config-basic/-/eslint-config-basic-0.38.2.tgz#e109ef21eb74c61916a69a488ef59a75baec3281"
+  integrity sha512-yyC7mlQ+p2Mu7TXOj0u/NojYXBjjAyJJDNbC1NM3e3KZdNZxi7mX31kb7FcdB3SMiaKIkKC3Yy3SAsajkYpVMg==
+  dependencies:
+    eslint-plugin-antfu "0.38.2"
+    eslint-plugin-eslint-comments "^3.2.0"
+    eslint-plugin-html "^7.1.0"
+    eslint-plugin-import "^2.27.5"
+    eslint-plugin-jsonc "^2.7.0"
+    eslint-plugin-markdown "^3.0.0"
+    eslint-plugin-n "^15.7.0"
+    eslint-plugin-no-only-tests "^3.1.0"
+    eslint-plugin-promise "^6.1.1"
+    eslint-plugin-unicorn "^46.0.0"
+    eslint-plugin-unused-imports "^2.0.0"
+    eslint-plugin-yml "^1.5.0"
+    jsonc-eslint-parser "^2.2.0"
+    yaml-eslint-parser "^1.2.0"
+
+"@antfu/eslint-config-ts@0.38.2":
+  version "0.38.2"
+  resolved "https://registry.npmmirror.com/@antfu/eslint-config-ts/-/eslint-config-ts-0.38.2.tgz#5c43420c3336f3d5f0fa4b92250890b1889a70f9"
+  integrity sha512-I4F8a9oJvTqd6/LLG4b6fhR1qNjEgVNdY8kuILxDV1vacwPpwQp00FfdN1LsjwBIvOQPtBh7KoG6HHep8D9YqQ==
+  dependencies:
+    "@antfu/eslint-config-basic" "0.38.2"
+    "@typescript-eslint/eslint-plugin" "^5.57.0"
+    "@typescript-eslint/parser" "^5.57.0"
+    eslint-plugin-jest "^27.2.1"
+
+"@antfu/eslint-config-vue@0.38.2":
+  version "0.38.2"
+  resolved "https://registry.npmmirror.com/@antfu/eslint-config-vue/-/eslint-config-vue-0.38.2.tgz#5bc65c59358d93defa2fb469dd0184babe769c40"
+  integrity sha512-YzLixISzgB1szc7++UwK45R5iKSMzo/f4DSWZOMNHWQb/qApjlaSDG5xBTRSPo57Yvm7pvrC8gQ10XfgFuCb6g==
+  dependencies:
+    "@antfu/eslint-config-basic" "0.38.2"
+    "@antfu/eslint-config-ts" "0.38.2"
+    eslint-plugin-vue "^9.10.0"
+    local-pkg "^0.4.3"
+
+"@antfu/eslint-config@^0.38.2":
+  version "0.38.2"
+  resolved "https://registry.npmmirror.com/@antfu/eslint-config/-/eslint-config-0.38.2.tgz#4c8509ad1664350dc794af45cf92fa33f5b0266e"
+  integrity sha512-JOWWCGSS3TSGVA9W6sN2WLD6bvCloENgbW1RpHoPfbZxqdK1phFrUt1wNQ43VHiBr9YGX/mmqCO+meIPzqBpiA==
+  dependencies:
+    "@antfu/eslint-config-vue" "0.38.2"
+    "@typescript-eslint/eslint-plugin" "^5.57.0"
+    "@typescript-eslint/parser" "^5.57.0"
+    eslint-plugin-eslint-comments "^3.2.0"
+    eslint-plugin-html "^7.1.0"
+    eslint-plugin-import "^2.27.5"
+    eslint-plugin-jsonc "^2.7.0"
+    eslint-plugin-n "^15.7.0"
+    eslint-plugin-promise "^6.1.1"
+    eslint-plugin-unicorn "^46.0.0"
+    eslint-plugin-vue "^9.10.0"
+    eslint-plugin-yml "^1.5.0"
+    jsonc-eslint-parser "^2.2.0"
+    yaml-eslint-parser "^1.2.0"
+
+"@antfu/install-pkg@^0.1.1":
+  version "0.1.1"
+  resolved "https://registry.npmmirror.com/@antfu/install-pkg/-/install-pkg-0.1.1.tgz#157bb04f0de8100b9e4c01734db1a6c77e98bbb5"
+  integrity sha512-LyB/8+bSfa0DFGC06zpCEfs89/XoWZwws5ygEa5D+Xsm3OfI+aXQ86VgVG7Acyef+rSZ5HE7J8rrxzrQeM3PjQ==
+  dependencies:
+    execa "^5.1.1"
+    find-up "^5.0.0"
+
+"@antfu/utils@^0.7.2":
+  version "0.7.2"
+  resolved "https://registry.npmmirror.com/@antfu/utils/-/utils-0.7.2.tgz#3bb6f37a6b188056fe9e2f363b6aa735ed65d7ca"
+  integrity sha512-vy9fM3pIxZmX07dL+VX1aZe7ynZ+YyB0jY+jE6r3hOK6GNY2t6W8rzpFC4tgpbXUYABkFQwgJq2XYXlxbXAI0g==
+
+"@babel/code-frame@^7.0.0":
+  version "7.16.7"
+  resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789"
+  integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==
+  dependencies:
+    "@babel/highlight" "^7.16.7"
+
+"@babel/helper-validator-identifier@^7.16.7":
+  version "7.16.7"
+  resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad"
+  integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==
+
+"@babel/helper-validator-identifier@^7.19.1":
+  version "7.19.1"
+  resolved "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2"
+  integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==
+
+"@babel/highlight@^7.16.7":
+  version "7.17.12"
+  resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.17.12.tgz#257de56ee5afbd20451ac0a75686b6b404257351"
+  integrity sha512-7yykMVF3hfZY2jsHZEEgLc+3x4o1O+fYyULu11GynEUQNwB6lua+IIQn1FiJxNucd5UlyJryrwsOh8PL9Sn8Qg==
+  dependencies:
+    "@babel/helper-validator-identifier" "^7.16.7"
+    chalk "^2.0.0"
+    js-tokens "^4.0.0"
+
+"@babel/parser@^7.18.4":
+  version "7.18.5"
+  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.5.tgz#337062363436a893a2d22faa60be5bb37091c83c"
+  integrity sha512-YZWVaglMiplo7v8f1oMQ5ZPQr0vn7HPeZXxXWsxXJRjGVrzUFn9OxFQl1sb5wzfootjA/yChhW84BV+383FSOw==
+
+"@esbuild/android-arm64@0.17.14":
+  version "0.17.14"
+  resolved "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.17.14.tgz#4624cea3c8941c91f9e9c1228f550d23f1cef037"
+  integrity sha512-eLOpPO1RvtsP71afiFTvS7tVFShJBCT0txiv/xjFBo5a7R7Gjw7X0IgIaFoLKhqXYAXhahoXm7qAmRXhY4guJg==
+
+"@esbuild/android-arm@0.17.14":
+  version "0.17.14"
+  resolved "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.17.14.tgz#74fae60fcab34c3f0e15cb56473a6091ba2b53a6"
+  integrity sha512-0CnlwnjDU8cks0yJLXfkaU/uoLyRf9VZJs4p1PskBr2AlAHeEsFEwJEo0of/Z3g+ilw5mpyDwThlxzNEIxOE4g==
+
+"@esbuild/android-x64@0.17.14":
+  version "0.17.14"
+  resolved "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.17.14.tgz#f002fbc08d5e939d8314bd23bcfb1e95d029491f"
+  integrity sha512-nrfQYWBfLGfSGLvRVlt6xi63B5IbfHm3tZCdu/82zuFPQ7zez4XjmRtF/wIRYbJQ/DsZrxJdEvYFE67avYXyng==
+
+"@esbuild/darwin-arm64@0.17.14":
+  version "0.17.14"
+  resolved "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.17.14.tgz#b8dcd79a1dd19564950b4ca51d62999011e2e168"
+  integrity sha512-eoSjEuDsU1ROwgBH/c+fZzuSyJUVXQTOIN9xuLs9dE/9HbV/A5IqdXHU1p2OfIMwBwOYJ9SFVGGldxeRCUJFyw==
+
+"@esbuild/darwin-x64@0.17.14":
+  version "0.17.14"
+  resolved "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.17.14.tgz#4b49f195d9473625efc3c773fc757018f2c0d979"
+  integrity sha512-zN0U8RWfrDttdFNkHqFYZtOH8hdi22z0pFm0aIJPsNC4QQZv7je8DWCX5iA4Zx6tRhS0CCc0XC2m7wKsbWEo5g==
+
+"@esbuild/freebsd-arm64@0.17.14":
+  version "0.17.14"
+  resolved "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.14.tgz#480923fd38f644c6342c55e916cc7c231a85eeb7"
+  integrity sha512-z0VcD4ibeZWVQCW1O7szaLxGsx54gcCnajEJMdYoYjLiq4g1jrP2lMq6pk71dbS5+7op/L2Aod+erw+EUr28/A==
+
+"@esbuild/freebsd-x64@0.17.14":
+  version "0.17.14"
+  resolved "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.17.14.tgz#a6b6b01954ad8562461cb8a5e40e8a860af69cbe"
+  integrity sha512-hd9mPcxfTgJlolrPlcXkQk9BMwNBvNBsVaUe5eNUqXut6weDQH8whcNaKNF2RO8NbpT6GY8rHOK2A9y++s+ehw==
+
+"@esbuild/linux-arm64@0.17.14":
+  version "0.17.14"
+  resolved "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.17.14.tgz#1fe2f39f78183b59f75a4ad9c48d079916d92418"
+  integrity sha512-FhAMNYOq3Iblcj9i+K0l1Fp/MHt+zBeRu/Qkf0LtrcFu3T45jcwB6A1iMsemQ42vR3GBhjNZJZTaCe3VFPbn9g==
+
+"@esbuild/linux-arm@0.17.14":
+  version "0.17.14"
+  resolved "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.17.14.tgz#18d594a49b64e4a3a05022c005cb384a58056a2a"
+  integrity sha512-BNTl+wSJ1omsH8s3TkQmIIIQHwvwJrU9u1ggb9XU2KTVM4TmthRIVyxSp2qxROJHhZuW/r8fht46/QE8hU8Qvg==
+
+"@esbuild/linux-ia32@0.17.14":
+  version "0.17.14"
+  resolved "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.17.14.tgz#f7f0182a9cfc0159e0922ed66c805c9c6ef1b654"
+  integrity sha512-91OK/lQ5y2v7AsmnFT+0EyxdPTNhov3y2CWMdizyMfxSxRqHazXdzgBKtlmkU2KYIc+9ZK3Vwp2KyXogEATYxQ==
+
+"@esbuild/linux-loong64@0.17.14":
+  version "0.17.14"
+  resolved "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.17.14.tgz#5f5305fdffe2d71dd9a97aa77d0c99c99409066f"
+  integrity sha512-vp15H+5NR6hubNgMluqqKza85HcGJgq7t6rMH7O3Y6ApiOWPkvW2AJfNojUQimfTp6OUrACUXfR4hmpcENXoMQ==
+
+"@esbuild/linux-mips64el@0.17.14":
+  version "0.17.14"
+  resolved "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.17.14.tgz#a602e85c51b2f71d2aedfe7f4143b2f92f97f3f5"
+  integrity sha512-90TOdFV7N+fgi6c2+GO9ochEkmm9kBAKnuD5e08GQMgMINOdOFHuYLPQ91RYVrnWwQ5683sJKuLi9l4SsbJ7Hg==
+
+"@esbuild/linux-ppc64@0.17.14":
+  version "0.17.14"
+  resolved "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.17.14.tgz#32d918d782105cbd9345dbfba14ee018b9c7afdf"
+  integrity sha512-NnBGeoqKkTugpBOBZZoktQQ1Yqb7aHKmHxsw43NddPB2YWLAlpb7THZIzsRsTr0Xw3nqiPxbA1H31ZMOG+VVPQ==
+
+"@esbuild/linux-riscv64@0.17.14":
+  version "0.17.14"
+  resolved "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.17.14.tgz#38612e7b6c037dff7022c33f49ca17f85c5dec58"
+  integrity sha512-0qdlKScLXA8MGVy21JUKvMzCYWovctuP8KKqhtE5A6IVPq4onxXhSuhwDd2g5sRCzNDlDjitc5sX31BzDoL5Fw==
+
+"@esbuild/linux-s390x@0.17.14":
+  version "0.17.14"
+  resolved "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.17.14.tgz#4397dff354f899e72fd035d72af59a700c465ccb"
+  integrity sha512-Hdm2Jo1yaaOro4v3+6/zJk6ygCqIZuSDJHdHaf8nVH/tfOuoEX5Riv03Ka15LmQBYJObUTNS1UdyoMk0WUn9Ww==
+
+"@esbuild/linux-x64@0.17.14":
+  version "0.17.14"
+  resolved "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.17.14.tgz#6c5cb99891b6c3e0c08369da3ef465e8038ad9c2"
+  integrity sha512-8KHF17OstlK4DuzeF/KmSgzrTWQrkWj5boluiiq7kvJCiQVzUrmSkaBvcLB2UgHpKENO2i6BthPkmUhNDaJsVw==
+
+"@esbuild/netbsd-x64@0.17.14":
+  version "0.17.14"
+  resolved "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.17.14.tgz#5fa5255a64e9bf3947c1b3bef5e458b50b211994"
+  integrity sha512-nVwpqvb3yyXztxIT2+VsxJhB5GCgzPdk1n0HHSnchRAcxqKO6ghXwHhJnr0j/B+5FSyEqSxF4q03rbA2fKXtUQ==
+
+"@esbuild/openbsd-x64@0.17.14":
+  version "0.17.14"
+  resolved "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.17.14.tgz#74d14c79dcb6faf446878cc64284aa4e02f5ca6f"
+  integrity sha512-1RZ7uQQ9zcy/GSAJL1xPdN7NDdOOtNEGiJalg/MOzeakZeTrgH/DoCkbq7TaPDiPhWqnDF+4bnydxRqQD7il6g==
+
+"@esbuild/sunos-x64@0.17.14":
+  version "0.17.14"
+  resolved "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.17.14.tgz#5c7d1c7203781d86c2a9b2ff77bd2f8036d24cfa"
+  integrity sha512-nqMjDsFwv7vp7msrwWRysnM38Sd44PKmW8EzV01YzDBTcTWUpczQg6mGao9VLicXSgW/iookNK6AxeogNVNDZA==
+
+"@esbuild/win32-arm64@0.17.14":
+  version "0.17.14"
+  resolved "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.17.14.tgz#dc36ed84f1390e73b6019ccf0566c80045e5ca3d"
+  integrity sha512-xrD0mccTKRBBIotrITV7WVQAwNJ5+1va6L0H9zN92v2yEdjfAN7864cUaZwJS7JPEs53bDTzKFbfqVlG2HhyKQ==
+
+"@esbuild/win32-ia32@0.17.14":
+  version "0.17.14"
+  resolved "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.17.14.tgz#0802a107afa9193c13e35de15a94fe347c588767"
+  integrity sha512-nXpkz9bbJrLLyUTYtRotSS3t5b+FOuljg8LgLdINWFs3FfqZMtbnBCZFUmBzQPyxqU87F8Av+3Nco/M3hEcu1w==
+
+"@esbuild/win32-x64@0.17.14":
+  version "0.17.14"
+  resolved "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.17.14.tgz#e81fb49de05fed91bf74251c9ca0343f4fc77d31"
+  integrity sha512-gPQmsi2DKTaEgG14hc3CHXHp62k8g6qr0Pas+I4lUxRMugGSATh/Bi8Dgusoz9IQ0IfdrvLpco6kujEIBoaogA==
+
+"@eslint-community/eslint-utils@^4.1.2", "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.3.0":
+  version "4.4.0"
+  resolved "https://registry.npmmirror.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59"
+  integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==
+  dependencies:
+    eslint-visitor-keys "^3.3.0"
+
+"@eslint-community/regexpp@^4.4.0":
+  version "4.5.0"
+  resolved "https://registry.npmmirror.com/@eslint-community/regexpp/-/regexpp-4.5.0.tgz#f6f729b02feee2c749f57e334b7a1b5f40a81724"
+  integrity sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ==
+
+"@eslint/eslintrc@^2.0.2":
+  version "2.0.2"
+  resolved "https://registry.npmmirror.com/@eslint/eslintrc/-/eslintrc-2.0.2.tgz#01575e38707add677cf73ca1589abba8da899a02"
+  integrity sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==
+  dependencies:
+    ajv "^6.12.4"
+    debug "^4.3.2"
+    espree "^9.5.1"
+    globals "^13.19.0"
+    ignore "^5.2.0"
+    import-fresh "^3.2.1"
+    js-yaml "^4.1.0"
+    minimatch "^3.1.2"
+    strip-json-comments "^3.1.1"
+
+"@eslint/js@8.37.0":
+  version "8.37.0"
+  resolved "https://registry.npmmirror.com/@eslint/js/-/js-8.37.0.tgz#cf1b5fa24217fe007f6487a26d765274925efa7d"
+  integrity sha512-x5vzdtOOGgFVDCUs81QRB2+liax8rFg3+7hqM+QhBG0/G3F1ZsoYl97UrqgHgQ9KKT7G6c4V+aTUCgu/n22v1A==
+
+"@humanwhocodes/config-array@^0.11.8":
+  version "0.11.8"
+  resolved "https://registry.npmmirror.com/@humanwhocodes/config-array/-/config-array-0.11.8.tgz#03595ac2075a4dc0f191cc2131de14fbd7d410b9"
+  integrity sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==
+  dependencies:
+    "@humanwhocodes/object-schema" "^1.2.1"
+    debug "^4.1.1"
+    minimatch "^3.0.5"
+
+"@humanwhocodes/module-importer@^1.0.1":
+  version "1.0.1"
+  resolved "https://registry.npmmirror.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c"
+  integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==
+
+"@humanwhocodes/object-schema@^1.2.1":
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45"
+  integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
+
+"@iconify/json@^2.2.42":
+  version "2.2.42"
+  resolved "https://registry.npmmirror.com/@iconify/json/-/json-2.2.42.tgz#e02abad9ab9120a45620abbc19bb4877442cf2d5"
+  integrity sha512-CLZHgcBIqNuy9lRwHjuvFb++OcqJFjJmr5Rg8MZ8Dc/hfcpU9L5IW4O3oB2UPQecXMKswZLoamfFajBAt03igw==
+  dependencies:
+    "@iconify/types" "*"
+    pathe "^1.0.0"
+
+"@iconify/types@*":
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/@iconify/types/-/types-1.1.0.tgz#dc15fc988b1b3fd558dd140a24ede7e0aac11280"
+  integrity sha512-Jh0llaK2LRXQoYsorIH8maClebsnzTcve+7U3rQUSnC11X4jtPnFuyatqFLvMxZ8MLG8dB4zfHsbPfuvxluONw==
+
+"@iconify/types@^2.0.0":
+  version "2.0.0"
+  resolved "https://registry.npmmirror.com/@iconify/types/-/types-2.0.0.tgz#ab0e9ea681d6c8a1214f30cd741fe3a20cc57f57"
+  integrity sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==
+
+"@iconify/utils@^2.1.5":
+  version "2.1.5"
+  resolved "https://registry.npmmirror.com/@iconify/utils/-/utils-2.1.5.tgz#75c17410aadec724d2ab7bd71e8710e448102438"
+  integrity sha512-6MvDI+I6QMvXn5rK9KQGdpEE4mmLTcuQdLZEiX5N+uZB+vc4Yw9K1OtnOgkl8mp4d9X0UrILREyZgF1NUwUt+Q==
+  dependencies:
+    "@antfu/install-pkg" "^0.1.1"
+    "@antfu/utils" "^0.7.2"
+    "@iconify/types" "^2.0.0"
+    debug "^4.3.4"
+    kolorist "^1.7.0"
+    local-pkg "^0.4.3"
+
+"@jridgewell/sourcemap-codec@^1.4.13":
+  version "1.4.14"
+  resolved "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
+  integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
+
+"@nodelib/fs.scandir@2.1.5":
+  version "2.1.5"
+  resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
+  integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==
+  dependencies:
+    "@nodelib/fs.stat" "2.0.5"
+    run-parallel "^1.1.9"
+
+"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b"
+  integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
+
+"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8":
+  version "1.2.8"
+  resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a"
+  integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
+  dependencies:
+    "@nodelib/fs.scandir" "2.1.5"
+    fastq "^1.6.0"
+
+"@rollup/pluginutils@^4.1.2":
+  version "4.2.1"
+  resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-4.2.1.tgz#e6c6c3aba0744edce3fb2074922d3776c0af2a6d"
+  integrity sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==
+  dependencies:
+    estree-walker "^2.0.1"
+    picomatch "^2.2.2"
+
+"@rollup/pluginutils@^5.0.2":
+  version "5.0.2"
+  resolved "https://registry.npmmirror.com/@rollup/pluginutils/-/pluginutils-5.0.2.tgz#012b8f53c71e4f6f9cb317e311df1404f56e7a33"
+  integrity sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==
+  dependencies:
+    "@types/estree" "^1.0.0"
+    estree-walker "^2.0.2"
+    picomatch "^2.3.1"
+
+"@types/estree@^1.0.0":
+  version "1.0.0"
+  resolved "https://registry.npmmirror.com/@types/estree/-/estree-1.0.0.tgz#5fb2e536c1ae9bf35366eed879e827fa59ca41c2"
+  integrity sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==
+
+"@types/json-schema@^7.0.9":
+  version "7.0.11"
+  resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3"
+  integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==
+
+"@types/json5@^0.0.29":
+  version "0.0.29"
+  resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
+  integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==
+
+"@types/mdast@^3.0.0":
+  version "3.0.10"
+  resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.10.tgz#4724244a82a4598884cbbe9bcfd73dff927ee8af"
+  integrity sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA==
+  dependencies:
+    "@types/unist" "*"
+
+"@types/normalize-package-data@^2.4.0":
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301"
+  integrity sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==
+
+"@types/semver@^7.3.12":
+  version "7.3.13"
+  resolved "https://registry.npmmirror.com/@types/semver/-/semver-7.3.13.tgz#da4bfd73f49bd541d28920ab0e2bf0ee80f71c91"
+  integrity sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==
+
+"@types/unist@*", "@types/unist@^2.0.2":
+  version "2.0.6"
+  resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d"
+  integrity sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==
+
+"@types/web-bluetooth@^0.0.16":
+  version "0.0.16"
+  resolved "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz#1d12873a8e49567371f2a75fe3e7f7edca6662d8"
+  integrity sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==
+
+"@typescript-eslint/eslint-plugin@^5.57.0":
+  version "5.57.0"
+  resolved "https://registry.npmmirror.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.57.0.tgz#52c8a7a4512f10e7249ca1e2e61f81c62c34365c"
+  integrity sha512-itag0qpN6q2UMM6Xgk6xoHa0D0/P+M17THnr4SVgqn9Rgam5k/He33MA7/D7QoJcdMxHFyX7U9imaBonAX/6qA==
+  dependencies:
+    "@eslint-community/regexpp" "^4.4.0"
+    "@typescript-eslint/scope-manager" "5.57.0"
+    "@typescript-eslint/type-utils" "5.57.0"
+    "@typescript-eslint/utils" "5.57.0"
+    debug "^4.3.4"
+    grapheme-splitter "^1.0.4"
+    ignore "^5.2.0"
+    natural-compare-lite "^1.4.0"
+    semver "^7.3.7"
+    tsutils "^3.21.0"
+
+"@typescript-eslint/parser@^5.57.0":
+  version "5.57.0"
+  resolved "https://registry.npmmirror.com/@typescript-eslint/parser/-/parser-5.57.0.tgz#f675bf2cd1a838949fd0de5683834417b757e4fa"
+  integrity sha512-orrduvpWYkgLCyAdNtR1QIWovcNZlEm6yL8nwH/eTxWLd8gsP+25pdLHYzL2QdkqrieaDwLpytHqycncv0woUQ==
+  dependencies:
+    "@typescript-eslint/scope-manager" "5.57.0"
+    "@typescript-eslint/types" "5.57.0"
+    "@typescript-eslint/typescript-estree" "5.57.0"
+    debug "^4.3.4"
+
+"@typescript-eslint/scope-manager@5.57.0":
+  version "5.57.0"
+  resolved "https://registry.npmmirror.com/@typescript-eslint/scope-manager/-/scope-manager-5.57.0.tgz#79ccd3fa7bde0758059172d44239e871e087ea36"
+  integrity sha512-NANBNOQvllPlizl9LatX8+MHi7bx7WGIWYjPHDmQe5Si/0YEYfxSljJpoTyTWFTgRy3X8gLYSE4xQ2U+aCozSw==
+  dependencies:
+    "@typescript-eslint/types" "5.57.0"
+    "@typescript-eslint/visitor-keys" "5.57.0"
+
+"@typescript-eslint/type-utils@5.57.0":
+  version "5.57.0"
+  resolved "https://registry.npmmirror.com/@typescript-eslint/type-utils/-/type-utils-5.57.0.tgz#98e7531c4e927855d45bd362de922a619b4319f2"
+  integrity sha512-kxXoq9zOTbvqzLbdNKy1yFrxLC6GDJFE2Yuo3KqSwTmDOFjUGeWSakgoXT864WcK5/NAJkkONCiKb1ddsqhLXQ==
+  dependencies:
+    "@typescript-eslint/typescript-estree" "5.57.0"
+    "@typescript-eslint/utils" "5.57.0"
+    debug "^4.3.4"
+    tsutils "^3.21.0"
+
+"@typescript-eslint/types@5.57.0":
+  version "5.57.0"
+  resolved "https://registry.npmmirror.com/@typescript-eslint/types/-/types-5.57.0.tgz#727bfa2b64c73a4376264379cf1f447998eaa132"
+  integrity sha512-mxsod+aZRSyLT+jiqHw1KK6xrANm19/+VFALVFP5qa/aiJnlP38qpyaTd0fEKhWvQk6YeNZ5LGwI1pDpBRBhtQ==
+
+"@typescript-eslint/typescript-estree@5.57.0":
+  version "5.57.0"
+  resolved "https://registry.npmmirror.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.57.0.tgz#ebcd0ee3e1d6230e888d88cddf654252d41e2e40"
+  integrity sha512-LTzQ23TV82KpO8HPnWuxM2V7ieXW8O142I7hQTxWIHDcCEIjtkat6H96PFkYBQqGFLW/G/eVVOB9Z8rcvdY/Vw==
+  dependencies:
+    "@typescript-eslint/types" "5.57.0"
+    "@typescript-eslint/visitor-keys" "5.57.0"
+    debug "^4.3.4"
+    globby "^11.1.0"
+    is-glob "^4.0.3"
+    semver "^7.3.7"
+    tsutils "^3.21.0"
+
+"@typescript-eslint/utils@5.57.0", "@typescript-eslint/utils@^5.10.0", "@typescript-eslint/utils@^5.57.0":
+  version "5.57.0"
+  resolved "https://registry.npmmirror.com/@typescript-eslint/utils/-/utils-5.57.0.tgz#eab8f6563a2ac31f60f3e7024b91bf75f43ecef6"
+  integrity sha512-ps/4WohXV7C+LTSgAL5CApxvxbMkl9B9AUZRtnEFonpIxZDIT7wC1xfvuJONMidrkB9scs4zhtRyIwHh4+18kw==
+  dependencies:
+    "@eslint-community/eslint-utils" "^4.2.0"
+    "@types/json-schema" "^7.0.9"
+    "@types/semver" "^7.3.12"
+    "@typescript-eslint/scope-manager" "5.57.0"
+    "@typescript-eslint/types" "5.57.0"
+    "@typescript-eslint/typescript-estree" "5.57.0"
+    eslint-scope "^5.1.1"
+    semver "^7.3.7"
+
+"@typescript-eslint/visitor-keys@5.57.0":
+  version "5.57.0"
+  resolved "https://registry.npmmirror.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.57.0.tgz#e2b2f4174aff1d15eef887ce3d019ecc2d7a8ac1"
+  integrity sha512-ery2g3k0hv5BLiKpPuwYt9KBkAp2ugT6VvyShXdLOkax895EC55sP0Tx5L0fZaQueiK3fBLvHVvEl3jFS5ia+g==
+  dependencies:
+    "@typescript-eslint/types" "5.57.0"
+    eslint-visitor-keys "^3.3.0"
+
+"@vitejs/plugin-vue2@^2.2.0":
+  version "2.2.0"
+  resolved "https://registry.npmmirror.com/@vitejs/plugin-vue2/-/plugin-vue2-2.2.0.tgz#7453207197d6ac2b7023cedc7133b142c604c356"
+  integrity sha512-1km7zEuZ/9QRPvzXSjikbTYGQPG86Mq1baktpC4sXqsXlb02HQKfi+fl8qVS703JM7cgm24Ga9j+RwKmvFn90A==
+
+"@vue/compiler-sfc@2.7.14":
+  version "2.7.14"
+  resolved "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-2.7.14.tgz#3446fd2fbb670d709277fc3ffa88efc5e10284fd"
+  integrity sha512-aNmNHyLPsw+sVvlQFQ2/8sjNuLtK54TC6cuKnVzAY93ks4ZBrvwQSnkkIh7bsbNhum5hJBS00wSDipQ937f5DA==
+  dependencies:
+    "@babel/parser" "^7.18.4"
+    postcss "^8.4.14"
+    source-map "^0.6.1"
+
+"@vueuse/core@9.13.0", "@vueuse/core@^9.13.0":
+  version "9.13.0"
+  resolved "https://registry.npmmirror.com/@vueuse/core/-/core-9.13.0.tgz#2f69e66d1905c1e4eebc249a01759cf88ea00cf4"
+  integrity sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==
+  dependencies:
+    "@types/web-bluetooth" "^0.0.16"
+    "@vueuse/metadata" "9.13.0"
+    "@vueuse/shared" "9.13.0"
+    vue-demi "*"
+
+"@vueuse/integrations@^9.13.0":
+  version "9.13.0"
+  resolved "https://registry.yarnpkg.com/@vueuse/integrations/-/integrations-9.13.0.tgz#a086459ab19b5bf98546d4f455c102dcf38a5cef"
+  integrity sha512-I1kX/tsfcvWWLZD7HZaP0LsSfchK13YxReLfharXhk72SFXp87doLbRaTfIF5w8m/gr/vPtcNyQPAXW7Ubpuww==
+  dependencies:
+    "@vueuse/core" "9.13.0"
+    "@vueuse/shared" "9.13.0"
+    vue-demi "*"
+
+"@vueuse/metadata@9.13.0":
+  version "9.13.0"
+  resolved "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-9.13.0.tgz#bc25a6cdad1b1a93c36ce30191124da6520539ff"
+  integrity sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==
+
+"@vueuse/shared@9.13.0":
+  version "9.13.0"
+  resolved "https://registry.npmmirror.com/@vueuse/shared/-/shared-9.13.0.tgz#089ff4cc4e2e7a4015e57a8f32e4b39d096353b9"
+  integrity sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==
+  dependencies:
+    vue-demi "*"
+
+"@windicss/config@1.8.10":
+  version "1.8.10"
+  resolved "https://registry.npmmirror.com/@windicss/config/-/config-1.8.10.tgz#717f070889db153fdfead4bc4401f4120f3de4ae"
+  integrity sha512-O9SsC110b1Ik3YYa4Ck/0TWuCo7YFfA9KDrwD5sAeqscT5COIGK1HszdCT3oh0MJFej2wNrvpfyW9h6yQaW6PA==
+  dependencies:
+    debug "^4.3.4"
+    jiti "^1.16.0"
+    windicss "^3.5.6"
+
+"@windicss/plugin-utils@1.8.10":
+  version "1.8.10"
+  resolved "https://registry.npmmirror.com/@windicss/plugin-utils/-/plugin-utils-1.8.10.tgz#241d5a93650be826c9cbd2614341885b044251c7"
+  integrity sha512-Phqk5OW1w+Mv+ry6t7BzAeDq3aMhbI94gR49j9vQCufFfDGCHndhhjtMK0sBv+NPJUsIAIh6qayb1iwBCXUGrw==
+  dependencies:
+    "@antfu/utils" "^0.7.2"
+    "@windicss/config" "1.8.10"
+    debug "^4.3.4"
+    fast-glob "^3.2.12"
+    magic-string "^0.27.0"
+    micromatch "^4.0.5"
+    windicss "^3.5.6"
+
+acorn-jsx@^5.3.2:
+  version "5.3.2"
+  resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
+  integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
+
+acorn@^8.5.0, acorn@^8.7.1:
+  version "8.7.1"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30"
+  integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==
+
+acorn@^8.8.0, acorn@^8.8.2:
+  version "8.8.2"
+  resolved "https://registry.npmmirror.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a"
+  integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==
+
+ajv@^6.10.0, ajv@^6.12.4:
+  version "6.12.6"
+  resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
+  integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
+  dependencies:
+    fast-deep-equal "^3.1.1"
+    fast-json-stable-stringify "^2.0.0"
+    json-schema-traverse "^0.4.1"
+    uri-js "^4.2.2"
+
+ansi-regex@^5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
+  integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
+
+ansi-styles@^3.2.1:
+  version "3.2.1"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
+  integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
+  dependencies:
+    color-convert "^1.9.0"
+
+ansi-styles@^4.1.0:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
+  integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
+  dependencies:
+    color-convert "^2.0.1"
+
+anymatch@~3.1.2:
+  version "3.1.2"
+  resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716"
+  integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==
+  dependencies:
+    normalize-path "^3.0.0"
+    picomatch "^2.0.4"
+
+argparse@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
+  integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
+
+array-buffer-byte-length@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.npmmirror.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz#fabe8bc193fea865f317fe7807085ee0dee5aead"
+  integrity sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==
+  dependencies:
+    call-bind "^1.0.2"
+    is-array-buffer "^3.0.1"
+
+array-includes@^3.1.6:
+  version "3.1.6"
+  resolved "https://registry.npmmirror.com/array-includes/-/array-includes-3.1.6.tgz#9e9e720e194f198266ba9e18c29e6a9b0e4b225f"
+  integrity sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==
+  dependencies:
+    call-bind "^1.0.2"
+    define-properties "^1.1.4"
+    es-abstract "^1.20.4"
+    get-intrinsic "^1.1.3"
+    is-string "^1.0.7"
+
+array-union@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
+  integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==
+
+array.prototype.flat@^1.3.1:
+  version "1.3.1"
+  resolved "https://registry.npmmirror.com/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz#ffc6576a7ca3efc2f46a143b9d1dda9b4b3cf5e2"
+  integrity sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==
+  dependencies:
+    call-bind "^1.0.2"
+    define-properties "^1.1.4"
+    es-abstract "^1.20.4"
+    es-shim-unscopables "^1.0.0"
+
+array.prototype.flatmap@^1.3.1:
+  version "1.3.1"
+  resolved "https://registry.npmmirror.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz#1aae7903c2100433cb8261cd4ed310aab5c4a183"
+  integrity sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==
+  dependencies:
+    call-bind "^1.0.2"
+    define-properties "^1.1.4"
+    es-abstract "^1.20.4"
+    es-shim-unscopables "^1.0.0"
+
+async-validator@~1.8.1:
+  version "1.8.5"
+  resolved "https://registry.yarnpkg.com/async-validator/-/async-validator-1.8.5.tgz#dc3e08ec1fd0dddb67e60842f02c0cd1cec6d7f0"
+  integrity sha512-tXBM+1m056MAX0E8TL2iCjg8WvSyXu0Zc8LNtYqrVeyoL3+esHRZ4SieE9fKQyyU09uONjnMEjrNBMqT0mbvmA==
+  dependencies:
+    babel-runtime "6.x"
+
+asynckit@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
+  integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
+
+available-typed-arrays@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.npmmirror.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7"
+  integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==
+
+axios@^1.3.5:
+  version "1.3.5"
+  resolved "https://registry.yarnpkg.com/axios/-/axios-1.3.5.tgz#e07209b39a0d11848e3e341fa087acd71dadc542"
+  integrity sha512-glL/PvG/E+xCWwV8S6nCHcrfg1exGx7vxyUIivIA1iL7BIh6bePylCfVHwp6k13ao7SATxB6imau2kqY+I67kw==
+  dependencies:
+    follow-redirects "^1.15.0"
+    form-data "^4.0.0"
+    proxy-from-env "^1.1.0"
+
+babel-helper-vue-jsx-merge-props@^2.0.0:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-2.0.3.tgz#22aebd3b33902328e513293a8e4992b384f9f1b6"
+  integrity sha512-gsLiKK7Qrb7zYJNgiXKpXblxbV5ffSwR0f5whkPAaBAR4fhi6bwRZxX9wBlIc5M/v8CCkXUbXZL4N/nSE97cqg==
+
+babel-runtime@6.x:
+  version "6.26.0"
+  resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
+  integrity sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==
+  dependencies:
+    core-js "^2.4.0"
+    regenerator-runtime "^0.11.0"
+
+balanced-match@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
+  integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
+
+binary-extensions@^2.0.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
+  integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
+
+boolbase@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
+  integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==
+
+brace-expansion@^1.1.7:
+  version "1.1.11"
+  resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
+  integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
+  dependencies:
+    balanced-match "^1.0.0"
+    concat-map "0.0.1"
+
+brace-expansion@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae"
+  integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==
+  dependencies:
+    balanced-match "^1.0.0"
+
+braces@^3.0.2, braces@~3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
+  integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
+  dependencies:
+    fill-range "^7.0.1"
+
+builtin-modules@^3.3.0:
+  version "3.3.0"
+  resolved "https://registry.npmmirror.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6"
+  integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==
+
+builtins@^5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/builtins/-/builtins-5.0.1.tgz#87f6db9ab0458be728564fa81d876d8d74552fa9"
+  integrity sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==
+  dependencies:
+    semver "^7.0.0"
+
+call-bind@^1.0.0, call-bind@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c"
+  integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==
+  dependencies:
+    function-bind "^1.1.1"
+    get-intrinsic "^1.0.2"
+
+callsites@^3.0.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
+  integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
+
+camel-case@^4.1.2:
+  version "4.1.2"
+  resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.2.tgz#9728072a954f805228225a6deea6b38461e1bd5a"
+  integrity sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==
+  dependencies:
+    pascal-case "^3.1.2"
+    tslib "^2.0.3"
+
+capital-case@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/capital-case/-/capital-case-1.0.4.tgz#9d130292353c9249f6b00fa5852bee38a717e669"
+  integrity sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==
+  dependencies:
+    no-case "^3.0.4"
+    tslib "^2.0.3"
+    upper-case-first "^2.0.2"
+
+chalk@^2.0.0:
+  version "2.4.2"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
+  integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
+  dependencies:
+    ansi-styles "^3.2.1"
+    escape-string-regexp "^1.0.5"
+    supports-color "^5.3.0"
+
+chalk@^4.0.0:
+  version "4.1.2"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
+  integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
+  dependencies:
+    ansi-styles "^4.1.0"
+    supports-color "^7.1.0"
+
+change-case@^4.1.2:
+  version "4.1.2"
+  resolved "https://registry.yarnpkg.com/change-case/-/change-case-4.1.2.tgz#fedfc5f136045e2398c0410ee441f95704641e12"
+  integrity sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A==
+  dependencies:
+    camel-case "^4.1.2"
+    capital-case "^1.0.4"
+    constant-case "^3.0.4"
+    dot-case "^3.0.4"
+    header-case "^2.0.4"
+    no-case "^3.0.4"
+    param-case "^3.0.4"
+    pascal-case "^3.1.2"
+    path-case "^3.0.4"
+    sentence-case "^3.0.4"
+    snake-case "^3.0.4"
+    tslib "^2.0.3"
+
+character-entities-legacy@^1.0.0:
+  version "1.1.4"
+  resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz#94bc1845dce70a5bb9d2ecc748725661293d8fc1"
+  integrity sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==
+
+character-entities@^1.0.0:
+  version "1.2.4"
+  resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-1.2.4.tgz#e12c3939b7eaf4e5b15e7ad4c5e28e1d48c5b16b"
+  integrity sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==
+
+character-reference-invalid@^1.0.0:
+  version "1.1.4"
+  resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz#083329cda0eae272ab3dbbf37e9a382c13af1560"
+  integrity sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==
+
+"chokidar@>=3.0.0 <4.0.0", chokidar@^3.5.3:
+  version "3.5.3"
+  resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
+  integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
+  dependencies:
+    anymatch "~3.1.2"
+    braces "~3.0.2"
+    glob-parent "~5.1.2"
+    is-binary-path "~2.1.0"
+    is-glob "~4.0.1"
+    normalize-path "~3.0.0"
+    readdirp "~3.6.0"
+  optionalDependencies:
+    fsevents "~2.3.2"
+
+ci-info@^3.6.1:
+  version "3.8.0"
+  resolved "https://registry.npmmirror.com/ci-info/-/ci-info-3.8.0.tgz#81408265a5380c929f0bc665d62256628ce9ef91"
+  integrity sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==
+
+clean-regexp@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/clean-regexp/-/clean-regexp-1.0.0.tgz#8df7c7aae51fd36874e8f8d05b9180bc11a3fed7"
+  integrity sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==
+  dependencies:
+    escape-string-regexp "^1.0.5"
+
+color-convert@^1.9.0:
+  version "1.9.3"
+  resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
+  integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
+  dependencies:
+    color-name "1.1.3"
+
+color-convert@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
+  integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
+  dependencies:
+    color-name "~1.1.4"
+
+color-name@1.1.3:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
+  integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
+
+color-name@~1.1.4:
+  version "1.1.4"
+  resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
+  integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
+
+combined-stream@^1.0.8:
+  version "1.0.8"
+  resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
+  integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
+  dependencies:
+    delayed-stream "~1.0.0"
+
+concat-map@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+  integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
+
+constant-case@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/constant-case/-/constant-case-3.0.4.tgz#3b84a9aeaf4cf31ec45e6bf5de91bdfb0589faf1"
+  integrity sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==
+  dependencies:
+    no-case "^3.0.4"
+    tslib "^2.0.3"
+    upper-case "^2.0.2"
+
+core-js@^2.4.0:
+  version "2.6.12"
+  resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec"
+  integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==
+
+core-js@^3.29.1:
+  version "3.29.1"
+  resolved "https://registry.npmmirror.com/core-js/-/core-js-3.29.1.tgz#40ff3b41588b091aaed19ca1aa5cb111803fa9a6"
+  integrity sha512-+jwgnhg6cQxKYIIjGtAHq2nwUOolo9eoFZ4sHfUH09BLXBgxnH4gA0zEd+t+BO2cNB8idaBtZFcFTRjQJRJmAw==
+
+cross-spawn@^7.0.2, cross-spawn@^7.0.3:
+  version "7.0.3"
+  resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
+  integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
+  dependencies:
+    path-key "^3.1.0"
+    shebang-command "^2.0.0"
+    which "^2.0.1"
+
+cssesc@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
+  integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
+
+csstype@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.0.tgz#4ddcac3718d787cf9df0d1b7d15033925c8f29f2"
+  integrity sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==
+
+de-indent@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d"
+  integrity sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==
+
+debug@^3.2.7:
+  version "3.2.7"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"
+  integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==
+  dependencies:
+    ms "^2.1.1"
+
+debug@^4.0.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4:
+  version "4.3.4"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
+  integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
+  dependencies:
+    ms "2.1.2"
+
+deep-is@^0.1.3:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831"
+  integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==
+
+deepmerge@^1.2.0:
+  version "1.5.2"
+  resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-1.5.2.tgz#10499d868844cdad4fee0842df8c7f6f0c95a753"
+  integrity sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ==
+
+define-properties@^1.1.3, define-properties@^1.1.4:
+  version "1.1.4"
+  resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.4.tgz#0b14d7bd7fbeb2f3572c3a7eda80ea5d57fb05b1"
+  integrity sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==
+  dependencies:
+    has-property-descriptors "^1.0.0"
+    object-keys "^1.1.1"
+
+delayed-stream@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
+  integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
+
+dir-glob@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
+  integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==
+  dependencies:
+    path-type "^4.0.0"
+
+doctrine@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d"
+  integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==
+  dependencies:
+    esutils "^2.0.2"
+
+doctrine@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961"
+  integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==
+  dependencies:
+    esutils "^2.0.2"
+
+dom-serializer@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.npmmirror.com/dom-serializer/-/dom-serializer-2.0.0.tgz#e41b802e1eedf9f6cae183ce5e622d789d7d8e53"
+  integrity sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==
+  dependencies:
+    domelementtype "^2.3.0"
+    domhandler "^5.0.2"
+    entities "^4.2.0"
+
+domelementtype@^2.3.0:
+  version "2.3.0"
+  resolved "https://registry.npmmirror.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d"
+  integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==
+
+domhandler@^5.0.1, domhandler@^5.0.2, domhandler@^5.0.3:
+  version "5.0.3"
+  resolved "https://registry.npmmirror.com/domhandler/-/domhandler-5.0.3.tgz#cc385f7f751f1d1fc650c21374804254538c7d31"
+  integrity sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==
+  dependencies:
+    domelementtype "^2.3.0"
+
+domutils@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.npmmirror.com/domutils/-/domutils-3.0.1.tgz#696b3875238338cb186b6c0612bd4901c89a4f1c"
+  integrity sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==
+  dependencies:
+    dom-serializer "^2.0.0"
+    domelementtype "^2.3.0"
+    domhandler "^5.0.1"
+
+dot-case@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751"
+  integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==
+  dependencies:
+    no-case "^3.0.4"
+    tslib "^2.0.3"
+
+element-ui@^2.15.13:
+  version "2.15.13"
+  resolved "https://registry.yarnpkg.com/element-ui/-/element-ui-2.15.13.tgz#380f019ee7d15b181105587b41fd5914c308a143"
+  integrity sha512-LJoatEYX6WV74FqXBss8Xfho9fh9rjDSzrDrTyREdGb1h1R3uRvmLh5jqp2JU137aj4/BgqA3K06RQpQBX33Bg==
+  dependencies:
+    async-validator "~1.8.1"
+    babel-helper-vue-jsx-merge-props "^2.0.0"
+    deepmerge "^1.2.0"
+    normalize-wheel "^1.0.1"
+    resize-observer-polyfill "^1.5.0"
+    throttle-debounce "^1.0.1"
+
+entities@^4.2.0, entities@^4.4.0:
+  version "4.4.0"
+  resolved "https://registry.npmmirror.com/entities/-/entities-4.4.0.tgz#97bdaba170339446495e653cfd2db78962900174"
+  integrity sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==
+
+error-ex@^1.3.1:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
+  integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
+  dependencies:
+    is-arrayish "^0.2.1"
+
+es-abstract@^1.19.0, es-abstract@^1.19.5:
+  version "1.20.1"
+  resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.20.1.tgz#027292cd6ef44bd12b1913b828116f54787d1814"
+  integrity sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==
+  dependencies:
+    call-bind "^1.0.2"
+    es-to-primitive "^1.2.1"
+    function-bind "^1.1.1"
+    function.prototype.name "^1.1.5"
+    get-intrinsic "^1.1.1"
+    get-symbol-description "^1.0.0"
+    has "^1.0.3"
+    has-property-descriptors "^1.0.0"
+    has-symbols "^1.0.3"
+    internal-slot "^1.0.3"
+    is-callable "^1.2.4"
+    is-negative-zero "^2.0.2"
+    is-regex "^1.1.4"
+    is-shared-array-buffer "^1.0.2"
+    is-string "^1.0.7"
+    is-weakref "^1.0.2"
+    object-inspect "^1.12.0"
+    object-keys "^1.1.1"
+    object.assign "^4.1.2"
+    regexp.prototype.flags "^1.4.3"
+    string.prototype.trimend "^1.0.5"
+    string.prototype.trimstart "^1.0.5"
+    unbox-primitive "^1.0.2"
+
+es-abstract@^1.20.4:
+  version "1.21.2"
+  resolved "https://registry.npmmirror.com/es-abstract/-/es-abstract-1.21.2.tgz#a56b9695322c8a185dc25975aa3b8ec31d0e7eff"
+  integrity sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==
+  dependencies:
+    array-buffer-byte-length "^1.0.0"
+    available-typed-arrays "^1.0.5"
+    call-bind "^1.0.2"
+    es-set-tostringtag "^2.0.1"
+    es-to-primitive "^1.2.1"
+    function.prototype.name "^1.1.5"
+    get-intrinsic "^1.2.0"
+    get-symbol-description "^1.0.0"
+    globalthis "^1.0.3"
+    gopd "^1.0.1"
+    has "^1.0.3"
+    has-property-descriptors "^1.0.0"
+    has-proto "^1.0.1"
+    has-symbols "^1.0.3"
+    internal-slot "^1.0.5"
+    is-array-buffer "^3.0.2"
+    is-callable "^1.2.7"
+    is-negative-zero "^2.0.2"
+    is-regex "^1.1.4"
+    is-shared-array-buffer "^1.0.2"
+    is-string "^1.0.7"
+    is-typed-array "^1.1.10"
+    is-weakref "^1.0.2"
+    object-inspect "^1.12.3"
+    object-keys "^1.1.1"
+    object.assign "^4.1.4"
+    regexp.prototype.flags "^1.4.3"
+    safe-regex-test "^1.0.0"
+    string.prototype.trim "^1.2.7"
+    string.prototype.trimend "^1.0.6"
+    string.prototype.trimstart "^1.0.6"
+    typed-array-length "^1.0.4"
+    unbox-primitive "^1.0.2"
+    which-typed-array "^1.1.9"
+
+es-module-lexer@^0.9.3:
+  version "0.9.3"
+  resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.9.3.tgz#6f13db00cc38417137daf74366f535c8eb438f19"
+  integrity sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==
+
+es-set-tostringtag@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.npmmirror.com/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz#338d502f6f674301d710b80c8592de8a15f09cd8"
+  integrity sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==
+  dependencies:
+    get-intrinsic "^1.1.3"
+    has "^1.0.3"
+    has-tostringtag "^1.0.0"
+
+es-shim-unscopables@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz#702e632193201e3edf8713635d083d378e510241"
+  integrity sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==
+  dependencies:
+    has "^1.0.3"
+
+es-to-primitive@^1.2.1:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a"
+  integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==
+  dependencies:
+    is-callable "^1.1.4"
+    is-date-object "^1.0.1"
+    is-symbol "^1.0.2"
+
+esbuild@^0.17.5:
+  version "0.17.14"
+  resolved "https://registry.npmmirror.com/esbuild/-/esbuild-0.17.14.tgz#d61a22de751a3133f3c6c7f9c1c3e231e91a3245"
+  integrity sha512-vOO5XhmVj/1XQR9NQ1UPq6qvMYL7QFJU57J5fKBKBKxp17uDt5PgxFDb4A2nEiXhr1qQs4x0F5+66hVVw4ruNw==
+  optionalDependencies:
+    "@esbuild/android-arm" "0.17.14"
+    "@esbuild/android-arm64" "0.17.14"
+    "@esbuild/android-x64" "0.17.14"
+    "@esbuild/darwin-arm64" "0.17.14"
+    "@esbuild/darwin-x64" "0.17.14"
+    "@esbuild/freebsd-arm64" "0.17.14"
+    "@esbuild/freebsd-x64" "0.17.14"
+    "@esbuild/linux-arm" "0.17.14"
+    "@esbuild/linux-arm64" "0.17.14"
+    "@esbuild/linux-ia32" "0.17.14"
+    "@esbuild/linux-loong64" "0.17.14"
+    "@esbuild/linux-mips64el" "0.17.14"
+    "@esbuild/linux-ppc64" "0.17.14"
+    "@esbuild/linux-riscv64" "0.17.14"
+    "@esbuild/linux-s390x" "0.17.14"
+    "@esbuild/linux-x64" "0.17.14"
+    "@esbuild/netbsd-x64" "0.17.14"
+    "@esbuild/openbsd-x64" "0.17.14"
+    "@esbuild/sunos-x64" "0.17.14"
+    "@esbuild/win32-arm64" "0.17.14"
+    "@esbuild/win32-ia32" "0.17.14"
+    "@esbuild/win32-x64" "0.17.14"
+
+escape-string-regexp@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
+  integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==
+
+escape-string-regexp@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
+  integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
+
+escape-string-regexp@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz#4683126b500b61762f2dbebace1806e8be31b1c8"
+  integrity sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==
+
+eslint-import-resolver-node@^0.3.7:
+  version "0.3.7"
+  resolved "https://registry.npmmirror.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz#83b375187d412324a1963d84fa664377a23eb4d7"
+  integrity sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==
+  dependencies:
+    debug "^3.2.7"
+    is-core-module "^2.11.0"
+    resolve "^1.22.1"
+
+eslint-module-utils@^2.7.4:
+  version "2.7.4"
+  resolved "https://registry.npmmirror.com/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz#4f3e41116aaf13a20792261e61d3a2e7e0583974"
+  integrity sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==
+  dependencies:
+    debug "^3.2.7"
+
+eslint-plugin-antfu@0.38.2:
+  version "0.38.2"
+  resolved "https://registry.npmmirror.com/eslint-plugin-antfu/-/eslint-plugin-antfu-0.38.2.tgz#c8153dcd7a4ea31650cd6a3284d0845cadcc1287"
+  integrity sha512-Fv4FxkkGsQ55Bw6u8GWhOuWTeiAxSWWH87rXzM0CSXYs4ql55tNuWvn+f9bWhPv1Q6eudr6DRuXuABCsrV0xlg==
+  dependencies:
+    "@typescript-eslint/utils" "^5.57.0"
+
+eslint-plugin-es@^4.1.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/eslint-plugin-es/-/eslint-plugin-es-4.1.0.tgz#f0822f0c18a535a97c3e714e89f88586a7641ec9"
+  integrity sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ==
+  dependencies:
+    eslint-utils "^2.0.0"
+    regexpp "^3.0.0"
+
+eslint-plugin-eslint-comments@^3.2.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-3.2.0.tgz#9e1cd7b4413526abb313933071d7aba05ca12ffa"
+  integrity sha512-0jkOl0hfojIHHmEHgmNdqv4fmh7300NdpA9FFpF7zaoLvB/QeXOGNLIo86oAveJFrfB1p05kC8hpEMHM8DwWVQ==
+  dependencies:
+    escape-string-regexp "^1.0.5"
+    ignore "^5.0.5"
+
+eslint-plugin-html@^7.1.0:
+  version "7.1.0"
+  resolved "https://registry.npmmirror.com/eslint-plugin-html/-/eslint-plugin-html-7.1.0.tgz#aec2a3772b40ccf51a5be4f972f07600539d3b3e"
+  integrity sha512-fNLRraV/e6j8e3XYOC9xgND4j+U7b1Rq+OygMlLcMg+wI/IpVbF+ubQa3R78EjKB9njT6TQOlcK5rFKBVVtdfg==
+  dependencies:
+    htmlparser2 "^8.0.1"
+
+eslint-plugin-import@^2.27.5:
+  version "2.27.5"
+  resolved "https://registry.npmmirror.com/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz#876a6d03f52608a3e5bb439c2550588e51dd6c65"
+  integrity sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==
+  dependencies:
+    array-includes "^3.1.6"
+    array.prototype.flat "^1.3.1"
+    array.prototype.flatmap "^1.3.1"
+    debug "^3.2.7"
+    doctrine "^2.1.0"
+    eslint-import-resolver-node "^0.3.7"
+    eslint-module-utils "^2.7.4"
+    has "^1.0.3"
+    is-core-module "^2.11.0"
+    is-glob "^4.0.3"
+    minimatch "^3.1.2"
+    object.values "^1.1.6"
+    resolve "^1.22.1"
+    semver "^6.3.0"
+    tsconfig-paths "^3.14.1"
+
+eslint-plugin-jest@^27.2.1:
+  version "27.2.1"
+  resolved "https://registry.npmmirror.com/eslint-plugin-jest/-/eslint-plugin-jest-27.2.1.tgz#b85b4adf41c682ea29f1f01c8b11ccc39b5c672c"
+  integrity sha512-l067Uxx7ZT8cO9NJuf+eJHvt6bqJyz2Z29wykyEdz/OtmcELQl2MQGQLX8J94O1cSJWAwUSEvCjwjA7KEK3Hmg==
+  dependencies:
+    "@typescript-eslint/utils" "^5.10.0"
+
+eslint-plugin-jsonc@^2.7.0:
+  version "2.7.0"
+  resolved "https://registry.npmmirror.com/eslint-plugin-jsonc/-/eslint-plugin-jsonc-2.7.0.tgz#ffce6c670f76aeb74765ac2f0fd97071d791d188"
+  integrity sha512-DZgC71h/hZ9t5k/OGAKOMdJCleg2neZLL7No+YYi2ZMroCN4X5huZdrLf1USbrc6UTHwYujd1EDwXHg1qJ6CYw==
+  dependencies:
+    "@eslint-community/eslint-utils" "^4.2.0"
+    jsonc-eslint-parser "^2.0.4"
+    natural-compare "^1.4.0"
+
+eslint-plugin-markdown@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.npmmirror.com/eslint-plugin-markdown/-/eslint-plugin-markdown-3.0.0.tgz#69a63ab3445076a3c2eb6fce6f5114785b19d318"
+  integrity sha512-hRs5RUJGbeHDLfS7ELanT0e29Ocyssf/7kBM+p7KluY5AwngGkDf8Oyu4658/NZSGTTq05FZeWbkxXtbVyHPwg==
+  dependencies:
+    mdast-util-from-markdown "^0.8.5"
+
+eslint-plugin-n@^15.7.0:
+  version "15.7.0"
+  resolved "https://registry.npmmirror.com/eslint-plugin-n/-/eslint-plugin-n-15.7.0.tgz#e29221d8f5174f84d18f2eb94765f2eeea033b90"
+  integrity sha512-jDex9s7D/Qial8AGVIHq4W7NswpUD5DPDL2RH8Lzd9EloWUuvUkHfv4FRLMipH5q2UtyurorBkPeNi1wVWNh3Q==
+  dependencies:
+    builtins "^5.0.1"
+    eslint-plugin-es "^4.1.0"
+    eslint-utils "^3.0.0"
+    ignore "^5.1.1"
+    is-core-module "^2.11.0"
+    minimatch "^3.1.2"
+    resolve "^1.22.1"
+    semver "^7.3.8"
+
+eslint-plugin-no-only-tests@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.npmmirror.com/eslint-plugin-no-only-tests/-/eslint-plugin-no-only-tests-3.1.0.tgz#f38e4935c6c6c4842bf158b64aaa20c366fe171b"
+  integrity sha512-Lf4YW/bL6Un1R6A76pRZyE1dl1vr31G/ev8UzIc/geCgFWyrKil8hVjYqWVKGB/UIGmb6Slzs9T0wNezdSVegw==
+
+eslint-plugin-promise@^6.1.1:
+  version "6.1.1"
+  resolved "https://registry.npmmirror.com/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz#269a3e2772f62875661220631bd4dafcb4083816"
+  integrity sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==
+
+eslint-plugin-unicorn@^46.0.0:
+  version "46.0.0"
+  resolved "https://registry.npmmirror.com/eslint-plugin-unicorn/-/eslint-plugin-unicorn-46.0.0.tgz#b5cdcc9465fd6e46ab7968b87dd4a43adc8d6031"
+  integrity sha512-j07WkC+PFZwk8J33LYp6JMoHa1lXc1u6R45pbSAipjpfpb7KIGr17VE2D685zCxR5VL4cjrl65kTJflziQWMDA==
+  dependencies:
+    "@babel/helper-validator-identifier" "^7.19.1"
+    "@eslint-community/eslint-utils" "^4.1.2"
+    ci-info "^3.6.1"
+    clean-regexp "^1.0.0"
+    esquery "^1.4.0"
+    indent-string "^4.0.0"
+    is-builtin-module "^3.2.0"
+    jsesc "^3.0.2"
+    lodash "^4.17.21"
+    pluralize "^8.0.0"
+    read-pkg-up "^7.0.1"
+    regexp-tree "^0.1.24"
+    regjsparser "^0.9.1"
+    safe-regex "^2.1.1"
+    semver "^7.3.8"
+    strip-indent "^3.0.0"
+
+eslint-plugin-unused-imports@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.npmmirror.com/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-2.0.0.tgz#d8db8c4d0cfa0637a8b51ce3fd7d1b6bc3f08520"
+  integrity sha512-3APeS/tQlTrFa167ThtP0Zm0vctjr4M44HMpeg1P4bK6wItarumq0Ma82xorMKdFsWpphQBlRPzw/pxiVELX1A==
+  dependencies:
+    eslint-rule-composer "^0.3.0"
+
+eslint-plugin-vue@^9.10.0:
+  version "9.10.0"
+  resolved "https://registry.npmmirror.com/eslint-plugin-vue/-/eslint-plugin-vue-9.10.0.tgz#bb6423166e6eab800344245b6eef6ce9480c78a7"
+  integrity sha512-2MgP31OBf8YilUvtakdVMc8xVbcMp7z7/iQj8LHVpXrSXHPXSJRUIGSPFI6b6pyCx/buKaFJ45ycqfHvQRiW2g==
+  dependencies:
+    "@eslint-community/eslint-utils" "^4.3.0"
+    natural-compare "^1.4.0"
+    nth-check "^2.0.1"
+    postcss-selector-parser "^6.0.9"
+    semver "^7.3.5"
+    vue-eslint-parser "^9.0.1"
+    xml-name-validator "^4.0.0"
+
+eslint-plugin-yml@^1.5.0:
+  version "1.5.0"
+  resolved "https://registry.npmmirror.com/eslint-plugin-yml/-/eslint-plugin-yml-1.5.0.tgz#e7eb4ae96701ec0f7f9689f9dc84a49f41833240"
+  integrity sha512-iygN054g+ZrnYmtOXMnT+sx9iDNXt89/m0+506cQHeG0+5jJN8hY5iOPQLd3yfd50AfK/mSasajBWruf1SoHpQ==
+  dependencies:
+    debug "^4.3.2"
+    lodash "^4.17.21"
+    natural-compare "^1.4.0"
+    yaml-eslint-parser "^1.1.0"
+
+eslint-rule-composer@^0.3.0:
+  version "0.3.0"
+  resolved "https://registry.npmmirror.com/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz#79320c927b0c5c0d3d3d2b76c8b4a488f25bbaf9"
+  integrity sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==
+
+eslint-scope@^5.1.1:
+  version "5.1.1"
+  resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
+  integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==
+  dependencies:
+    esrecurse "^4.3.0"
+    estraverse "^4.1.1"
+
+eslint-scope@^7.1.1:
+  version "7.1.1"
+  resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642"
+  integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==
+  dependencies:
+    esrecurse "^4.3.0"
+    estraverse "^5.2.0"
+
+eslint-utils@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27"
+  integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==
+  dependencies:
+    eslint-visitor-keys "^1.1.0"
+
+eslint-utils@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672"
+  integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==
+  dependencies:
+    eslint-visitor-keys "^2.0.0"
+
+eslint-visitor-keys@^1.1.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e"
+  integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==
+
+eslint-visitor-keys@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303"
+  integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==
+
+eslint-visitor-keys@^3.0.0, eslint-visitor-keys@^3.3.0:
+  version "3.3.0"
+  resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826"
+  integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==
+
+eslint-visitor-keys@^3.4.0:
+  version "3.4.0"
+  resolved "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz#c7f0f956124ce677047ddbc192a68f999454dedc"
+  integrity sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==
+
+eslint@^8.37.0:
+  version "8.37.0"
+  resolved "https://registry.npmmirror.com/eslint/-/eslint-8.37.0.tgz#1f660ef2ce49a0bfdec0b0d698e0b8b627287412"
+  integrity sha512-NU3Ps9nI05GUoVMxcZx1J8CNR6xOvUT4jAUMH5+z8lpp3aEdPVCImKw6PWG4PY+Vfkpr+jvMpxs/qoE7wq0sPw==
+  dependencies:
+    "@eslint-community/eslint-utils" "^4.2.0"
+    "@eslint-community/regexpp" "^4.4.0"
+    "@eslint/eslintrc" "^2.0.2"
+    "@eslint/js" "8.37.0"
+    "@humanwhocodes/config-array" "^0.11.8"
+    "@humanwhocodes/module-importer" "^1.0.1"
+    "@nodelib/fs.walk" "^1.2.8"
+    ajv "^6.10.0"
+    chalk "^4.0.0"
+    cross-spawn "^7.0.2"
+    debug "^4.3.2"
+    doctrine "^3.0.0"
+    escape-string-regexp "^4.0.0"
+    eslint-scope "^7.1.1"
+    eslint-visitor-keys "^3.4.0"
+    espree "^9.5.1"
+    esquery "^1.4.2"
+    esutils "^2.0.2"
+    fast-deep-equal "^3.1.3"
+    file-entry-cache "^6.0.1"
+    find-up "^5.0.0"
+    glob-parent "^6.0.2"
+    globals "^13.19.0"
+    grapheme-splitter "^1.0.4"
+    ignore "^5.2.0"
+    import-fresh "^3.0.0"
+    imurmurhash "^0.1.4"
+    is-glob "^4.0.0"
+    is-path-inside "^3.0.3"
+    js-sdsl "^4.1.4"
+    js-yaml "^4.1.0"
+    json-stable-stringify-without-jsonify "^1.0.1"
+    levn "^0.4.1"
+    lodash.merge "^4.6.2"
+    minimatch "^3.1.2"
+    natural-compare "^1.4.0"
+    optionator "^0.9.1"
+    strip-ansi "^6.0.1"
+    strip-json-comments "^3.1.0"
+    text-table "^0.2.0"
+
+espree@^9.0.0, espree@^9.3.1:
+  version "9.3.2"
+  resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.2.tgz#f58f77bd334731182801ced3380a8cc859091596"
+  integrity sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==
+  dependencies:
+    acorn "^8.7.1"
+    acorn-jsx "^5.3.2"
+    eslint-visitor-keys "^3.3.0"
+
+espree@^9.5.1:
+  version "9.5.1"
+  resolved "https://registry.npmmirror.com/espree/-/espree-9.5.1.tgz#4f26a4d5f18905bf4f2e0bd99002aab807e96dd4"
+  integrity sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==
+  dependencies:
+    acorn "^8.8.0"
+    acorn-jsx "^5.3.2"
+    eslint-visitor-keys "^3.4.0"
+
+esquery@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5"
+  integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==
+  dependencies:
+    estraverse "^5.1.0"
+
+esquery@^1.4.2:
+  version "1.5.0"
+  resolved "https://registry.npmmirror.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b"
+  integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==
+  dependencies:
+    estraverse "^5.1.0"
+
+esrecurse@^4.3.0:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921"
+  integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==
+  dependencies:
+    estraverse "^5.2.0"
+
+estraverse@^4.1.1:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
+  integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
+
+estraverse@^5.1.0, estraverse@^5.2.0:
+  version "5.3.0"
+  resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123"
+  integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
+
+estree-walker@^2.0.1, estree-walker@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac"
+  integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==
+
+esutils@^2.0.2:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
+  integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
+
+execa@^5.1.1:
+  version "5.1.1"
+  resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd"
+  integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==
+  dependencies:
+    cross-spawn "^7.0.3"
+    get-stream "^6.0.0"
+    human-signals "^2.1.0"
+    is-stream "^2.0.0"
+    merge-stream "^2.0.0"
+    npm-run-path "^4.0.1"
+    onetime "^5.1.2"
+    signal-exit "^3.0.3"
+    strip-final-newline "^2.0.0"
+
+fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
+  integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
+
+fast-glob@^3.2.12:
+  version "3.2.12"
+  resolved "https://registry.npmmirror.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80"
+  integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==
+  dependencies:
+    "@nodelib/fs.stat" "^2.0.2"
+    "@nodelib/fs.walk" "^1.2.3"
+    glob-parent "^5.1.2"
+    merge2 "^1.3.0"
+    micromatch "^4.0.4"
+
+fast-glob@^3.2.9:
+  version "3.2.11"
+  resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9"
+  integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==
+  dependencies:
+    "@nodelib/fs.stat" "^2.0.2"
+    "@nodelib/fs.walk" "^1.2.3"
+    glob-parent "^5.1.2"
+    merge2 "^1.3.0"
+    micromatch "^4.0.4"
+
+fast-json-stable-stringify@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
+  integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
+
+fast-levenshtein@^2.0.6:
+  version "2.0.6"
+  resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
+  integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==
+
+fastq@^1.6.0:
+  version "1.13.0"
+  resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c"
+  integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==
+  dependencies:
+    reusify "^1.0.4"
+
+file-entry-cache@^6.0.1:
+  version "6.0.1"
+  resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027"
+  integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==
+  dependencies:
+    flat-cache "^3.0.4"
+
+fill-range@^7.0.1:
+  version "7.0.1"
+  resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
+  integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
+  dependencies:
+    to-regex-range "^5.0.1"
+
+find-up@^4.1.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
+  integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==
+  dependencies:
+    locate-path "^5.0.0"
+    path-exists "^4.0.0"
+
+find-up@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc"
+  integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==
+  dependencies:
+    locate-path "^6.0.0"
+    path-exists "^4.0.0"
+
+flat-cache@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11"
+  integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==
+  dependencies:
+    flatted "^3.1.0"
+    rimraf "^3.0.2"
+
+flatted@^3.1.0:
+  version "3.2.5"
+  resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.5.tgz#76c8584f4fc843db64702a6bd04ab7a8bd666da3"
+  integrity sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==
+
+follow-redirects@^1.15.0:
+  version "1.15.2"
+  resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13"
+  integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==
+
+for-each@^0.3.3:
+  version "0.3.3"
+  resolved "https://registry.npmmirror.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e"
+  integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==
+  dependencies:
+    is-callable "^1.1.3"
+
+form-data@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
+  integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
+  dependencies:
+    asynckit "^0.4.0"
+    combined-stream "^1.0.8"
+    mime-types "^2.1.12"
+
+fs-extra@^10.0.0:
+  version "10.1.0"
+  resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf"
+  integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==
+  dependencies:
+    graceful-fs "^4.2.0"
+    jsonfile "^6.0.1"
+    universalify "^2.0.0"
+
+fs.realpath@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+  integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
+
+fsevents@~2.3.2:
+  version "2.3.2"
+  resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
+  integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
+
+function-bind@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
+  integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
+
+function.prototype.name@^1.1.5:
+  version "1.1.5"
+  resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621"
+  integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==
+  dependencies:
+    call-bind "^1.0.2"
+    define-properties "^1.1.3"
+    es-abstract "^1.19.0"
+    functions-have-names "^1.2.2"
+
+functions-have-names@^1.2.2:
+  version "1.2.3"
+  resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834"
+  integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==
+
+get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.2.tgz#336975123e05ad0b7ba41f152ee4aadbea6cf598"
+  integrity sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==
+  dependencies:
+    function-bind "^1.1.1"
+    has "^1.0.3"
+    has-symbols "^1.0.3"
+
+get-intrinsic@^1.1.3, get-intrinsic@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.2.0.tgz#7ad1dc0535f3a2904bba075772763e5051f6d05f"
+  integrity sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==
+  dependencies:
+    function-bind "^1.1.1"
+    has "^1.0.3"
+    has-symbols "^1.0.3"
+
+get-stream@^6.0.0:
+  version "6.0.1"
+  resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7"
+  integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==
+
+get-symbol-description@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6"
+  integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==
+  dependencies:
+    call-bind "^1.0.2"
+    get-intrinsic "^1.1.1"
+
+glob-parent@^5.1.2, glob-parent@~5.1.2:
+  version "5.1.2"
+  resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
+  integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
+  dependencies:
+    is-glob "^4.0.1"
+
+glob-parent@^6.0.2:
+  version "6.0.2"
+  resolved "https://registry.npmmirror.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3"
+  integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==
+  dependencies:
+    is-glob "^4.0.3"
+
+glob@^7.1.3:
+  version "7.2.3"
+  resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
+  integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
+  dependencies:
+    fs.realpath "^1.0.0"
+    inflight "^1.0.4"
+    inherits "2"
+    minimatch "^3.1.1"
+    once "^1.3.0"
+    path-is-absolute "^1.0.0"
+
+globals@^13.19.0:
+  version "13.20.0"
+  resolved "https://registry.npmmirror.com/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82"
+  integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==
+  dependencies:
+    type-fest "^0.20.2"
+
+globalthis@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.npmmirror.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf"
+  integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==
+  dependencies:
+    define-properties "^1.1.3"
+
+globby@^11.1.0:
+  version "11.1.0"
+  resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b"
+  integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==
+  dependencies:
+    array-union "^2.1.0"
+    dir-glob "^3.0.1"
+    fast-glob "^3.2.9"
+    ignore "^5.2.0"
+    merge2 "^1.4.1"
+    slash "^3.0.0"
+
+gopd@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.npmmirror.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c"
+  integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==
+  dependencies:
+    get-intrinsic "^1.1.3"
+
+graceful-fs@^4.1.6, graceful-fs@^4.2.0:
+  version "4.2.11"
+  resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
+  integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
+
+grapheme-splitter@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.npmmirror.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e"
+  integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==
+
+has-bigints@^1.0.1, has-bigints@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa"
+  integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==
+
+has-flag@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
+  integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==
+
+has-flag@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
+  integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
+
+has-property-descriptors@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861"
+  integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==
+  dependencies:
+    get-intrinsic "^1.1.1"
+
+has-proto@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.npmmirror.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0"
+  integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==
+
+has-symbols@^1.0.1, has-symbols@^1.0.2, has-symbols@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
+  integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
+
+has-tostringtag@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25"
+  integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==
+  dependencies:
+    has-symbols "^1.0.2"
+
+has@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
+  integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
+  dependencies:
+    function-bind "^1.1.1"
+
+he@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
+  integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
+
+header-case@^2.0.4:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/header-case/-/header-case-2.0.4.tgz#5a42e63b55177349cf405beb8d775acabb92c063"
+  integrity sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==
+  dependencies:
+    capital-case "^1.0.4"
+    tslib "^2.0.3"
+
+hosted-git-info@^2.1.4:
+  version "2.8.9"
+  resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9"
+  integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==
+
+htmlparser2@^8.0.1:
+  version "8.0.2"
+  resolved "https://registry.npmmirror.com/htmlparser2/-/htmlparser2-8.0.2.tgz#f002151705b383e62433b5cf466f5b716edaec21"
+  integrity sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==
+  dependencies:
+    domelementtype "^2.3.0"
+    domhandler "^5.0.3"
+    domutils "^3.0.1"
+    entities "^4.4.0"
+
+human-signals@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0"
+  integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==
+
+husky@^8.0.3:
+  version "8.0.3"
+  resolved "https://registry.npmmirror.com/husky/-/husky-8.0.3.tgz#4936d7212e46d1dea28fef29bb3a108872cd9184"
+  integrity sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==
+
+ignore@^5.0.5, ignore@^5.1.1, ignore@^5.2.0:
+  version "5.2.0"
+  resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a"
+  integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==
+
+immutable@^4.0.0:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.3.0.tgz#eb1738f14ffb39fd068b1dbe1296117484dd34be"
+  integrity sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg==
+
+import-fresh@^3.0.0, import-fresh@^3.2.1:
+  version "3.3.0"
+  resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
+  integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==
+  dependencies:
+    parent-module "^1.0.0"
+    resolve-from "^4.0.0"
+
+imurmurhash@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
+  integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==
+
+indent-string@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251"
+  integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==
+
+inflight@^1.0.4:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+  integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==
+  dependencies:
+    once "^1.3.0"
+    wrappy "1"
+
+inherits@2:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
+  integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
+
+internal-slot@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c"
+  integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==
+  dependencies:
+    get-intrinsic "^1.1.0"
+    has "^1.0.3"
+    side-channel "^1.0.4"
+
+internal-slot@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.npmmirror.com/internal-slot/-/internal-slot-1.0.5.tgz#f2a2ee21f668f8627a4667f309dc0f4fb6674986"
+  integrity sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==
+  dependencies:
+    get-intrinsic "^1.2.0"
+    has "^1.0.3"
+    side-channel "^1.0.4"
+
+is-alphabetical@^1.0.0:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-1.0.4.tgz#9e7d6b94916be22153745d184c298cbf986a686d"
+  integrity sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==
+
+is-alphanumerical@^1.0.0:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz#7eb9a2431f855f6b1ef1a78e326df515696c4dbf"
+  integrity sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==
+  dependencies:
+    is-alphabetical "^1.0.0"
+    is-decimal "^1.0.0"
+
+is-array-buffer@^3.0.1, is-array-buffer@^3.0.2:
+  version "3.0.2"
+  resolved "https://registry.npmmirror.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe"
+  integrity sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==
+  dependencies:
+    call-bind "^1.0.2"
+    get-intrinsic "^1.2.0"
+    is-typed-array "^1.1.10"
+
+is-arrayish@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
+  integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==
+
+is-bigint@^1.0.1:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3"
+  integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==
+  dependencies:
+    has-bigints "^1.0.1"
+
+is-binary-path@~2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
+  integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
+  dependencies:
+    binary-extensions "^2.0.0"
+
+is-boolean-object@^1.1.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719"
+  integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==
+  dependencies:
+    call-bind "^1.0.2"
+    has-tostringtag "^1.0.0"
+
+is-builtin-module@^3.2.0:
+  version "3.2.1"
+  resolved "https://registry.npmmirror.com/is-builtin-module/-/is-builtin-module-3.2.1.tgz#f03271717d8654cfcaf07ab0463faa3571581169"
+  integrity sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==
+  dependencies:
+    builtin-modules "^3.3.0"
+
+is-callable@^1.1.3, is-callable@^1.2.7:
+  version "1.2.7"
+  resolved "https://registry.npmmirror.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055"
+  integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==
+
+is-callable@^1.1.4, is-callable@^1.2.4:
+  version "1.2.4"
+  resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945"
+  integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==
+
+is-core-module@^2.11.0:
+  version "2.11.0"
+  resolved "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.11.0.tgz#ad4cb3e3863e814523c96f3f58d26cc570ff0144"
+  integrity sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==
+  dependencies:
+    has "^1.0.3"
+
+is-core-module@^2.9.0:
+  version "2.9.0"
+  resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.9.0.tgz#e1c34429cd51c6dd9e09e0799e396e27b19a9c69"
+  integrity sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==
+  dependencies:
+    has "^1.0.3"
+
+is-date-object@^1.0.1:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f"
+  integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==
+  dependencies:
+    has-tostringtag "^1.0.0"
+
+is-decimal@^1.0.0:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-1.0.4.tgz#65a3a5958a1c5b63a706e1b333d7cd9f630d3fa5"
+  integrity sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==
+
+is-extglob@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
+  integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
+
+is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1:
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
+  integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
+  dependencies:
+    is-extglob "^2.1.1"
+
+is-hexadecimal@^1.0.0:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7"
+  integrity sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==
+
+is-negative-zero@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150"
+  integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==
+
+is-number-object@^1.0.4:
+  version "1.0.7"
+  resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc"
+  integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==
+  dependencies:
+    has-tostringtag "^1.0.0"
+
+is-number@^7.0.0:
+  version "7.0.0"
+  resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
+  integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
+
+is-path-inside@^3.0.3:
+  version "3.0.3"
+  resolved "https://registry.npmmirror.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283"
+  integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
+
+is-regex@^1.1.4:
+  version "1.1.4"
+  resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958"
+  integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==
+  dependencies:
+    call-bind "^1.0.2"
+    has-tostringtag "^1.0.0"
+
+is-shared-array-buffer@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79"
+  integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==
+  dependencies:
+    call-bind "^1.0.2"
+
+is-stream@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077"
+  integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==
+
+is-string@^1.0.5, is-string@^1.0.7:
+  version "1.0.7"
+  resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd"
+  integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==
+  dependencies:
+    has-tostringtag "^1.0.0"
+
+is-symbol@^1.0.2, is-symbol@^1.0.3:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c"
+  integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==
+  dependencies:
+    has-symbols "^1.0.2"
+
+is-typed-array@^1.1.10, is-typed-array@^1.1.9:
+  version "1.1.10"
+  resolved "https://registry.npmmirror.com/is-typed-array/-/is-typed-array-1.1.10.tgz#36a5b5cb4189b575d1a3e4b08536bfb485801e3f"
+  integrity sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==
+  dependencies:
+    available-typed-arrays "^1.0.5"
+    call-bind "^1.0.2"
+    for-each "^0.3.3"
+    gopd "^1.0.1"
+    has-tostringtag "^1.0.0"
+
+is-weakref@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2"
+  integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==
+  dependencies:
+    call-bind "^1.0.2"
+
+isexe@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
+  integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
+
+jiti@^1.16.0:
+  version "1.18.2"
+  resolved "https://registry.npmmirror.com/jiti/-/jiti-1.18.2.tgz#80c3ef3d486ebf2450d9335122b32d121f2a83cd"
+  integrity sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==
+
+js-sdsl@^4.1.4:
+  version "4.4.0"
+  resolved "https://registry.npmmirror.com/js-sdsl/-/js-sdsl-4.4.0.tgz#8b437dbe642daa95760400b602378ed8ffea8430"
+  integrity sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==
+
+js-tokens@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
+  integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
+
+js-yaml@^4.1.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
+  integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
+  dependencies:
+    argparse "^2.0.1"
+
+jsesc@^3.0.2:
+  version "3.0.2"
+  resolved "https://registry.npmmirror.com/jsesc/-/jsesc-3.0.2.tgz#bb8b09a6597ba426425f2e4a07245c3d00b9343e"
+  integrity sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==
+
+jsesc@~0.5.0:
+  version "0.5.0"
+  resolved "https://registry.npmmirror.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d"
+  integrity sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==
+
+json-parse-even-better-errors@^2.3.0:
+  version "2.3.1"
+  resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
+  integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
+
+json-schema-traverse@^0.4.1:
+  version "0.4.1"
+  resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
+  integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
+
+json-stable-stringify-without-jsonify@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
+  integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==
+
+json5@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe"
+  integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==
+  dependencies:
+    minimist "^1.2.0"
+
+jsonc-eslint-parser@^2.0.4:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/jsonc-eslint-parser/-/jsonc-eslint-parser-2.1.0.tgz#4c126b530aa583d85308d0b3041ff81ce402bbb2"
+  integrity sha512-qCRJWlbP2v6HbmKW7R3lFbeiVWHo+oMJ0j+MizwvauqnCV/EvtAeEeuCgoc/ErtsuoKgYB8U4Ih8AxJbXoE6/g==
+  dependencies:
+    acorn "^8.5.0"
+    eslint-visitor-keys "^3.0.0"
+    espree "^9.0.0"
+    semver "^7.3.5"
+
+jsonc-eslint-parser@^2.2.0:
+  version "2.2.0"
+  resolved "https://registry.npmmirror.com/jsonc-eslint-parser/-/jsonc-eslint-parser-2.2.0.tgz#01ec9933dc3cc8302abb0c29884bf854c4f627e4"
+  integrity sha512-x5QjzBOORd+T2EjErIxJnkOEbLVEdD1ILEeBbIJt8Eq/zUn7P7M8qdnWiNVBK5f8oxnJpc6SBHOeeIEl/swPjg==
+  dependencies:
+    acorn "^8.5.0"
+    eslint-visitor-keys "^3.0.0"
+    espree "^9.0.0"
+    semver "^7.3.5"
+
+jsonc-parser@^3.2.0:
+  version "3.2.0"
+  resolved "https://registry.npmmirror.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76"
+  integrity sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==
+
+jsonfile@^6.0.1:
+  version "6.1.0"
+  resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
+  integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==
+  dependencies:
+    universalify "^2.0.0"
+  optionalDependencies:
+    graceful-fs "^4.1.6"
+
+kolorist@^1.6.0, kolorist@^1.7.0:
+  version "1.7.0"
+  resolved "https://registry.npmmirror.com/kolorist/-/kolorist-1.7.0.tgz#8e22bc470ea2d2743dbd461808f8b5246b19f5f4"
+  integrity sha512-ymToLHqL02udwVdbkowNpzjFd6UzozMtshPQKVi5k1EjKRqKqBrOnE9QbLEb0/pV76SAiIT13hdL8R6suc+f3g==
+
+levn@^0.4.1:
+  version "0.4.1"
+  resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade"
+  integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==
+  dependencies:
+    prelude-ls "^1.2.1"
+    type-check "~0.4.0"
+
+lines-and-columns@^1.1.6:
+  version "1.2.4"
+  resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
+  integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
+
+local-pkg@^0.4.3:
+  version "0.4.3"
+  resolved "https://registry.npmmirror.com/local-pkg/-/local-pkg-0.4.3.tgz#0ff361ab3ae7f1c19113d9bb97b98b905dbc4963"
+  integrity sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==
+
+locate-path@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0"
+  integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==
+  dependencies:
+    p-locate "^4.1.0"
+
+locate-path@^6.0.0:
+  version "6.0.0"
+  resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286"
+  integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==
+  dependencies:
+    p-locate "^5.0.0"
+
+lodash.merge@^4.6.2:
+  version "4.6.2"
+  resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
+  integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
+
+lodash@^4.17.21:
+  version "4.17.21"
+  resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
+  integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
+
+lower-case@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28"
+  integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==
+  dependencies:
+    tslib "^2.0.3"
+
+lru-cache@^6.0.0:
+  version "6.0.0"
+  resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
+  integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
+  dependencies:
+    yallist "^4.0.0"
+
+magic-string@^0.25.7:
+  version "0.25.9"
+  resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.9.tgz#de7f9faf91ef8a1c91d02c2e5314c8277dbcdd1c"
+  integrity sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==
+  dependencies:
+    sourcemap-codec "^1.4.8"
+
+magic-string@^0.27.0:
+  version "0.27.0"
+  resolved "https://registry.npmmirror.com/magic-string/-/magic-string-0.27.0.tgz#e4a3413b4bab6d98d2becffd48b4a257effdbbf3"
+  integrity sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==
+  dependencies:
+    "@jridgewell/sourcemap-codec" "^1.4.13"
+
+magic-string@^0.30.0:
+  version "0.30.0"
+  resolved "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.0.tgz#fd58a4748c5c4547338a424e90fa5dd17f4de529"
+  integrity sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==
+  dependencies:
+    "@jridgewell/sourcemap-codec" "^1.4.13"
+
+mdast-util-from-markdown@^0.8.5:
+  version "0.8.5"
+  resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-0.8.5.tgz#d1ef2ca42bc377ecb0463a987910dae89bd9a28c"
+  integrity sha512-2hkTXtYYnr+NubD/g6KGBS/0mFmBcifAsI0yIWRiRo0PjVs6SSOSOdtzbp6kSGnShDN6G5aWZpKQ2lWRy27mWQ==
+  dependencies:
+    "@types/mdast" "^3.0.0"
+    mdast-util-to-string "^2.0.0"
+    micromark "~2.11.0"
+    parse-entities "^2.0.0"
+    unist-util-stringify-position "^2.0.0"
+
+mdast-util-to-string@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz#b8cfe6a713e1091cb5b728fc48885a4767f8b97b"
+  integrity sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==
+
+merge-stream@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
+  integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
+
+merge2@^1.3.0, merge2@^1.4.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
+  integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
+
+micromark@~2.11.0:
+  version "2.11.4"
+  resolved "https://registry.yarnpkg.com/micromark/-/micromark-2.11.4.tgz#d13436138eea826383e822449c9a5c50ee44665a"
+  integrity sha512-+WoovN/ppKolQOFIAajxi7Lu9kInbPxFuTBVEavFcL8eAfVstoc5MocPmqBeAdBOJV00uaVjegzH4+MA0DN/uA==
+  dependencies:
+    debug "^4.0.0"
+    parse-entities "^2.0.0"
+
+micromatch@^4.0.4, micromatch@^4.0.5:
+  version "4.0.5"
+  resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
+  integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==
+  dependencies:
+    braces "^3.0.2"
+    picomatch "^2.3.1"
+
+mime-db@1.52.0:
+  version "1.52.0"
+  resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
+  integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
+
+mime-types@^2.1.12:
+  version "2.1.35"
+  resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
+  integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
+  dependencies:
+    mime-db "1.52.0"
+
+mimic-fn@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
+  integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
+
+min-indent@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869"
+  integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==
+
+minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
+  version "3.1.2"
+  resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
+  integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
+  dependencies:
+    brace-expansion "^1.1.7"
+
+minimatch@^7.4.2, minimatch@^7.4.3:
+  version "7.4.3"
+  resolved "https://registry.npmmirror.com/minimatch/-/minimatch-7.4.3.tgz#012cbf110a65134bb354ae9773b55256cdb045a2"
+  integrity sha512-5UB4yYusDtkRPbRiy1cqZ1IpGNcJCGlEMG17RKzPddpyiPKoCdwohbED8g4QXT0ewCt8LTkQXuljsUfQ3FKM4A==
+  dependencies:
+    brace-expansion "^2.0.1"
+
+minimist@^1.2.0, minimist@^1.2.6:
+  version "1.2.6"
+  resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
+  integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
+
+mlly@^1.1.1, mlly@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.npmmirror.com/mlly/-/mlly-1.2.0.tgz#f0f6c2fc8d2d12ea6907cd869066689b5031b613"
+  integrity sha512-+c7A3CV0KGdKcylsI6khWyts/CYrGTrRVo4R/I7u/cUsy0Conxa6LUhiEzVKIw14lc2L5aiO4+SeVe4TeGRKww==
+  dependencies:
+    acorn "^8.8.2"
+    pathe "^1.1.0"
+    pkg-types "^1.0.2"
+    ufo "^1.1.1"
+
+ms@2.1.2:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
+  integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
+
+ms@^2.1.1:
+  version "2.1.3"
+  resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
+  integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
+
+nanoid@^3.3.4:
+  version "3.3.4"
+  resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
+  integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==
+
+natural-compare-lite@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.npmmirror.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4"
+  integrity sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==
+
+natural-compare@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
+  integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==
+
+no-case@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d"
+  integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==
+  dependencies:
+    lower-case "^2.0.2"
+    tslib "^2.0.3"
+
+normalize-package-data@^2.5.0:
+  version "2.5.0"
+  resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
+  integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==
+  dependencies:
+    hosted-git-info "^2.1.4"
+    resolve "^1.10.0"
+    semver "2 || 3 || 4 || 5"
+    validate-npm-package-license "^3.0.1"
+
+normalize-path@^3.0.0, normalize-path@~3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
+  integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
+
+normalize-wheel@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/normalize-wheel/-/normalize-wheel-1.0.1.tgz#aec886affdb045070d856447df62ecf86146ec45"
+  integrity sha512-1OnlAPZ3zgrk8B91HyRj+eVv+kS5u+Z0SCsak6Xil/kmgEia50ga7zfkumayonZrImffAxPU/5WcyGhzetHNPA==
+
+npm-run-path@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea"
+  integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==
+  dependencies:
+    path-key "^3.0.0"
+
+nth-check@^2.0.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d"
+  integrity sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==
+  dependencies:
+    boolbase "^1.0.0"
+
+object-inspect@^1.12.0, object-inspect@^1.9.0:
+  version "1.12.2"
+  resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea"
+  integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==
+
+object-inspect@^1.12.3:
+  version "1.12.3"
+  resolved "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9"
+  integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==
+
+object-keys@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
+  integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
+
+object.assign@^4.1.2:
+  version "4.1.2"
+  resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940"
+  integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==
+  dependencies:
+    call-bind "^1.0.0"
+    define-properties "^1.1.3"
+    has-symbols "^1.0.1"
+    object-keys "^1.1.1"
+
+object.assign@^4.1.4:
+  version "4.1.4"
+  resolved "https://registry.npmmirror.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f"
+  integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==
+  dependencies:
+    call-bind "^1.0.2"
+    define-properties "^1.1.4"
+    has-symbols "^1.0.3"
+    object-keys "^1.1.1"
+
+object.values@^1.1.6:
+  version "1.1.6"
+  resolved "https://registry.npmmirror.com/object.values/-/object.values-1.1.6.tgz#4abbaa71eba47d63589d402856f908243eea9b1d"
+  integrity sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==
+  dependencies:
+    call-bind "^1.0.2"
+    define-properties "^1.1.4"
+    es-abstract "^1.20.4"
+
+once@^1.3.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+  integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
+  dependencies:
+    wrappy "1"
+
+onetime@^5.1.2:
+  version "5.1.2"
+  resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e"
+  integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==
+  dependencies:
+    mimic-fn "^2.1.0"
+
+optionator@^0.9.1:
+  version "0.9.1"
+  resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499"
+  integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==
+  dependencies:
+    deep-is "^0.1.3"
+    fast-levenshtein "^2.0.6"
+    levn "^0.4.1"
+    prelude-ls "^1.2.1"
+    type-check "^0.4.0"
+    word-wrap "^1.2.3"
+
+p-limit@^2.2.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
+  integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
+  dependencies:
+    p-try "^2.0.0"
+
+p-limit@^3.0.2:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b"
+  integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==
+  dependencies:
+    yocto-queue "^0.1.0"
+
+p-locate@^4.1.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07"
+  integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==
+  dependencies:
+    p-limit "^2.2.0"
+
+p-locate@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834"
+  integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==
+  dependencies:
+    p-limit "^3.0.2"
+
+p-try@^2.0.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
+  integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
+
+param-case@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5"
+  integrity sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==
+  dependencies:
+    dot-case "^3.0.4"
+    tslib "^2.0.3"
+
+parent-module@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
+  integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==
+  dependencies:
+    callsites "^3.0.0"
+
+parse-entities@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-2.0.0.tgz#53c6eb5b9314a1f4ec99fa0fdf7ce01ecda0cbe8"
+  integrity sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==
+  dependencies:
+    character-entities "^1.0.0"
+    character-entities-legacy "^1.0.0"
+    character-reference-invalid "^1.0.0"
+    is-alphanumerical "^1.0.0"
+    is-decimal "^1.0.0"
+    is-hexadecimal "^1.0.0"
+
+parse-json@^5.0.0:
+  version "5.2.0"
+  resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd"
+  integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==
+  dependencies:
+    "@babel/code-frame" "^7.0.0"
+    error-ex "^1.3.1"
+    json-parse-even-better-errors "^2.3.0"
+    lines-and-columns "^1.1.6"
+
+pascal-case@^3.1.2:
+  version "3.1.2"
+  resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.2.tgz#b48e0ef2b98e205e7c1dae747d0b1508237660eb"
+  integrity sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==
+  dependencies:
+    no-case "^3.0.4"
+    tslib "^2.0.3"
+
+path-case@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/path-case/-/path-case-3.0.4.tgz#9168645334eb942658375c56f80b4c0cb5f82c6f"
+  integrity sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg==
+  dependencies:
+    dot-case "^3.0.4"
+    tslib "^2.0.3"
+
+path-exists@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
+  integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==
+
+path-is-absolute@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
+  integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==
+
+path-key@^3.0.0, path-key@^3.1.0:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
+  integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
+
+path-parse@^1.0.7:
+  version "1.0.7"
+  resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
+  integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
+
+path-type@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
+  integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
+
+pathe@^1.0.0, pathe@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.npmmirror.com/pathe/-/pathe-1.1.0.tgz#e2e13f6c62b31a3289af4ba19886c230f295ec03"
+  integrity sha512-ODbEPR0KKHqECXW1GoxdDb+AZvULmXjVPy4rt+pGo2+TnjJTIPJQSVS6N63n8T2Ip+syHhbn52OewKicV0373w==
+
+picocolors@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
+  integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
+
+picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.3.1:
+  version "2.3.1"
+  resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
+  integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
+
+pkg-types@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.npmmirror.com/pkg-types/-/pkg-types-1.0.2.tgz#c233efc5210a781e160e0cafd60c0d0510a4b12e"
+  integrity sha512-hM58GKXOcj8WTqUXnsQyJYXdeAPbythQgEF3nTcEo+nkD49chjQ9IKm/QJy9xf6JakXptz86h7ecP2024rrLaQ==
+  dependencies:
+    jsonc-parser "^3.2.0"
+    mlly "^1.1.1"
+    pathe "^1.1.0"
+
+pluralize@^8.0.0:
+  version "8.0.0"
+  resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1"
+  integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==
+
+postcss-prefix-selector@^1.16.0:
+  version "1.16.0"
+  resolved "https://registry.yarnpkg.com/postcss-prefix-selector/-/postcss-prefix-selector-1.16.0.tgz#ad5b56f9a73a2c090ca7161049632c9d89bcb404"
+  integrity sha512-rdVMIi7Q4B0XbXqNUEI+Z4E+pueiu/CS5E6vRCQommzdQ/sgsS4dK42U7GX8oJR+TJOtT+Qv3GkNo6iijUMp3Q==
+
+postcss-selector-parser@^6.0.9:
+  version "6.0.10"
+  resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz#79b61e2c0d1bfc2602d549e11d0876256f8df88d"
+  integrity sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==
+  dependencies:
+    cssesc "^3.0.0"
+    util-deprecate "^1.0.2"
+
+postcss@^8.4.14:
+  version "8.4.14"
+  resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.14.tgz#ee9274d5622b4858c1007a74d76e42e56fd21caf"
+  integrity sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==
+  dependencies:
+    nanoid "^3.3.4"
+    picocolors "^1.0.0"
+    source-map-js "^1.0.2"
+
+postcss@^8.4.21:
+  version "8.4.21"
+  resolved "https://registry.npmmirror.com/postcss/-/postcss-8.4.21.tgz#c639b719a57efc3187b13a1d765675485f4134f4"
+  integrity sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==
+  dependencies:
+    nanoid "^3.3.4"
+    picocolors "^1.0.0"
+    source-map-js "^1.0.2"
+
+prelude-ls@^1.2.1:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
+  integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
+
+proxy-from-env@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
+  integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
+
+punycode@^2.1.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
+  integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
+
+queue-microtask@^1.2.2:
+  version "1.2.3"
+  resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
+  integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
+
+read-pkg-up@^7.0.1:
+  version "7.0.1"
+  resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507"
+  integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==
+  dependencies:
+    find-up "^4.1.0"
+    read-pkg "^5.2.0"
+    type-fest "^0.8.1"
+
+read-pkg@^5.2.0:
+  version "5.2.0"
+  resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc"
+  integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==
+  dependencies:
+    "@types/normalize-package-data" "^2.4.0"
+    normalize-package-data "^2.5.0"
+    parse-json "^5.0.0"
+    type-fest "^0.6.0"
+
+readdirp@~3.6.0:
+  version "3.6.0"
+  resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
+  integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==
+  dependencies:
+    picomatch "^2.2.1"
+
+regenerator-runtime@^0.11.0:
+  version "0.11.1"
+  resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
+  integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
+
+regexp-tree@^0.1.24, regexp-tree@~0.1.1:
+  version "0.1.24"
+  resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.24.tgz#3d6fa238450a4d66e5bc9c4c14bb720e2196829d"
+  integrity sha512-s2aEVuLhvnVJW6s/iPgEGK6R+/xngd2jNQ+xy4bXNDKxZKJH6jpPHY6kVeVv1IeLCHgswRj+Kl3ELaDjG6V1iw==
+
+regexp.prototype.flags@^1.4.3:
+  version "1.4.3"
+  resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac"
+  integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==
+  dependencies:
+    call-bind "^1.0.2"
+    define-properties "^1.1.3"
+    functions-have-names "^1.2.2"
+
+regexpp@^3.0.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2"
+  integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==
+
+regjsparser@^0.9.1:
+  version "0.9.1"
+  resolved "https://registry.npmmirror.com/regjsparser/-/regjsparser-0.9.1.tgz#272d05aa10c7c1f67095b1ff0addae8442fc5709"
+  integrity sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==
+  dependencies:
+    jsesc "~0.5.0"
+
+resize-observer-polyfill@^1.5.0:
+  version "1.5.1"
+  resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464"
+  integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==
+
+resolve-from@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
+  integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
+
+resolve@^1.10.0, resolve@^1.22.1:
+  version "1.22.1"
+  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
+  integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
+  dependencies:
+    is-core-module "^2.9.0"
+    path-parse "^1.0.7"
+    supports-preserve-symlinks-flag "^1.0.0"
+
+reusify@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
+  integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
+
+rimraf@^3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
+  integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
+  dependencies:
+    glob "^7.1.3"
+
+rollup@^3.18.0:
+  version "3.20.2"
+  resolved "https://registry.npmmirror.com/rollup/-/rollup-3.20.2.tgz#f798c600317f216de2e4ad9f4d9ab30a89b690ff"
+  integrity sha512-3zwkBQl7Ai7MFYQE0y1MeQ15+9jsi7XxfrqwTb/9EK8D9C9+//EBR4M+CuA1KODRaNbFez/lWxA5vhEGZp4MUg==
+  optionalDependencies:
+    fsevents "~2.3.2"
+
+run-parallel@^1.1.9:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
+  integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==
+  dependencies:
+    queue-microtask "^1.2.2"
+
+safe-regex-test@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.npmmirror.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz#793b874d524eb3640d1873aad03596db2d4f2295"
+  integrity sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==
+  dependencies:
+    call-bind "^1.0.2"
+    get-intrinsic "^1.1.3"
+    is-regex "^1.1.4"
+
+safe-regex@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-2.1.1.tgz#f7128f00d056e2fe5c11e81a1324dd974aadced2"
+  integrity sha512-rx+x8AMzKb5Q5lQ95Zoi6ZbJqwCLkqi3XuJXp5P3rT8OEc6sZCJG5AE5dU3lsgRr/F4Bs31jSlVN+j5KrsGu9A==
+  dependencies:
+    regexp-tree "~0.1.1"
+
+sass@^1.61.0:
+  version "1.61.0"
+  resolved "https://registry.yarnpkg.com/sass/-/sass-1.61.0.tgz#d1f6761bb833887b8fdab32a24e052c40531d02b"
+  integrity sha512-PDsN7BrVkNZK2+dj/dpKQAWZavbAQ87IXqVvw2+oEYI+GwlTWkvbQtL7F2cCNbMqJEYKPh1EcjSxsnqIb/kyaQ==
+  dependencies:
+    chokidar ">=3.0.0 <4.0.0"
+    immutable "^4.0.0"
+    source-map-js ">=0.6.2 <2.0.0"
+
+scule@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.npmmirror.com/scule/-/scule-1.0.0.tgz#895e6f4ba887e78d8b9b4111e23ae84fef82376d"
+  integrity sha512-4AsO/FrViE/iDNEPaAQlb77tf0csuq27EsVpy6ett584EcRTp6pTDLoGWVxCD77y5iU5FauOvhsI4o1APwPoSQ==
+
+"semver@2 || 3 || 4 || 5":
+  version "5.7.1"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
+  integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
+
+semver@^6.3.0:
+  version "6.3.0"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
+  integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
+
+semver@^7.0.0, semver@^7.3.5, semver@^7.3.6, semver@^7.3.7:
+  version "7.3.7"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f"
+  integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==
+  dependencies:
+    lru-cache "^6.0.0"
+
+semver@^7.3.8:
+  version "7.3.8"
+  resolved "https://registry.npmmirror.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798"
+  integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==
+  dependencies:
+    lru-cache "^6.0.0"
+
+sentence-case@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/sentence-case/-/sentence-case-3.0.4.tgz#3645a7b8c117c787fde8702056225bb62a45131f"
+  integrity sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==
+  dependencies:
+    no-case "^3.0.4"
+    tslib "^2.0.3"
+    upper-case-first "^2.0.2"
+
+shebang-command@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
+  integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
+  dependencies:
+    shebang-regex "^3.0.0"
+
+shebang-regex@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
+  integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
+
+side-channel@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf"
+  integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==
+  dependencies:
+    call-bind "^1.0.0"
+    get-intrinsic "^1.0.2"
+    object-inspect "^1.9.0"
+
+signal-exit@^3.0.3:
+  version "3.0.7"
+  resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
+  integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
+
+slash@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
+  integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
+
+snake-case@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-3.0.4.tgz#4f2bbd568e9935abdfd593f34c691dadb49c452c"
+  integrity sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==
+  dependencies:
+    dot-case "^3.0.4"
+    tslib "^2.0.3"
+
+"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
+  integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
+
+source-map@^0.6.1:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
+  integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
+
+sourcemap-codec@^1.4.8:
+  version "1.4.8"
+  resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4"
+  integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==
+
+spdx-correct@^3.0.0:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9"
+  integrity sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==
+  dependencies:
+    spdx-expression-parse "^3.0.0"
+    spdx-license-ids "^3.0.0"
+
+spdx-exceptions@^2.1.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d"
+  integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==
+
+spdx-expression-parse@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679"
+  integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==
+  dependencies:
+    spdx-exceptions "^2.1.0"
+    spdx-license-ids "^3.0.0"
+
+spdx-license-ids@^3.0.0:
+  version "3.0.11"
+  resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz#50c0d8c40a14ec1bf449bae69a0ea4685a9d9f95"
+  integrity sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==
+
+string.prototype.trim@^1.2.7:
+  version "1.2.7"
+  resolved "https://registry.npmmirror.com/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz#a68352740859f6893f14ce3ef1bb3037f7a90533"
+  integrity sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==
+  dependencies:
+    call-bind "^1.0.2"
+    define-properties "^1.1.4"
+    es-abstract "^1.20.4"
+
+string.prototype.trimend@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz#914a65baaab25fbdd4ee291ca7dde57e869cb8d0"
+  integrity sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==
+  dependencies:
+    call-bind "^1.0.2"
+    define-properties "^1.1.4"
+    es-abstract "^1.19.5"
+
+string.prototype.trimend@^1.0.6:
+  version "1.0.6"
+  resolved "https://registry.npmmirror.com/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz#c4a27fa026d979d79c04f17397f250a462944533"
+  integrity sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==
+  dependencies:
+    call-bind "^1.0.2"
+    define-properties "^1.1.4"
+    es-abstract "^1.20.4"
+
+string.prototype.trimstart@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz#5466d93ba58cfa2134839f81d7f42437e8c01fef"
+  integrity sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==
+  dependencies:
+    call-bind "^1.0.2"
+    define-properties "^1.1.4"
+    es-abstract "^1.19.5"
+
+string.prototype.trimstart@^1.0.6:
+  version "1.0.6"
+  resolved "https://registry.npmmirror.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz#e90ab66aa8e4007d92ef591bbf3cd422c56bdcf4"
+  integrity sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==
+  dependencies:
+    call-bind "^1.0.2"
+    define-properties "^1.1.4"
+    es-abstract "^1.20.4"
+
+strip-ansi@^6.0.1:
+  version "6.0.1"
+  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
+  integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
+  dependencies:
+    ansi-regex "^5.0.1"
+
+strip-bom@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
+  integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==
+
+strip-final-newline@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad"
+  integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==
+
+strip-indent@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001"
+  integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==
+  dependencies:
+    min-indent "^1.0.0"
+
+strip-json-comments@^3.1.0, strip-json-comments@^3.1.1:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
+  integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
+
+strip-literal@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.npmmirror.com/strip-literal/-/strip-literal-1.0.1.tgz#0115a332710c849b4e46497891fb8d585e404bd2"
+  integrity sha512-QZTsipNpa2Ppr6v1AmJHESqJ3Uz247MUS0OjrnnZjFAvEoWqxuyFuXn2xLgMtRnijJShAa1HL0gtJyUs7u7n3Q==
+  dependencies:
+    acorn "^8.8.2"
+
+supports-color@^5.3.0:
+  version "5.5.0"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
+  integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
+  dependencies:
+    has-flag "^3.0.0"
+
+supports-color@^7.1.0:
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
+  integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
+  dependencies:
+    has-flag "^4.0.0"
+
+supports-preserve-symlinks-flag@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
+  integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
+
+text-table@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
+  integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==
+
+throttle-debounce@^1.0.1:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/throttle-debounce/-/throttle-debounce-1.1.0.tgz#51853da37be68a155cb6e827b3514a3c422e89cd"
+  integrity sha512-XH8UiPCQcWNuk2LYePibW/4qL97+ZQ1AN3FNXwZRBNPPowo/NRU5fAlDCSNBJIYCKbioZfuYtMhG4quqoJhVzg==
+
+to-regex-range@^5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
+  integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
+  dependencies:
+    is-number "^7.0.0"
+
+tsconfig-paths@^3.14.1:
+  version "3.14.1"
+  resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a"
+  integrity sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==
+  dependencies:
+    "@types/json5" "^0.0.29"
+    json5 "^1.0.1"
+    minimist "^1.2.6"
+    strip-bom "^3.0.0"
+
+tslib@^1.8.1:
+  version "1.14.1"
+  resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
+  integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
+
+tslib@^2.0.3:
+  version "2.5.0"
+  resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf"
+  integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==
+
+tsutils@^3.21.0:
+  version "3.21.0"
+  resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623"
+  integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==
+  dependencies:
+    tslib "^1.8.1"
+
+type-check@^0.4.0, type-check@~0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
+  integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==
+  dependencies:
+    prelude-ls "^1.2.1"
+
+type-fest@^0.20.2:
+  version "0.20.2"
+  resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
+  integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
+
+type-fest@^0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b"
+  integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==
+
+type-fest@^0.8.1:
+  version "0.8.1"
+  resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
+  integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
+
+typed-array-length@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.npmmirror.com/typed-array-length/-/typed-array-length-1.0.4.tgz#89d83785e5c4098bec72e08b319651f0eac9c1bb"
+  integrity sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==
+  dependencies:
+    call-bind "^1.0.2"
+    for-each "^0.3.3"
+    is-typed-array "^1.1.9"
+
+typescript@^5.0.3:
+  version "5.0.3"
+  resolved "https://registry.npmmirror.com/typescript/-/typescript-5.0.3.tgz#fe976f0c826a88d0a382007681cbb2da44afdedf"
+  integrity sha512-xv8mOEDnigb/tN9PSMTwSEqAnUvkoXMQlicOb0IUVDBSQCgBSaAAROUZYy2IcUy5qU6XajK5jjjO7TMWqBTKZA==
+
+ufo@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.npmmirror.com/ufo/-/ufo-1.1.1.tgz#e70265e7152f3aba425bd013d150b2cdf4056d7c"
+  integrity sha512-MvlCc4GHrmZdAllBc0iUDowff36Q9Ndw/UzqmEKyrfSzokTd9ZCy1i+IIk5hrYKkjoYVQyNbrw7/F8XJ2rEwTg==
+
+unbox-primitive@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e"
+  integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==
+  dependencies:
+    call-bind "^1.0.2"
+    has-bigints "^1.0.2"
+    has-symbols "^1.0.3"
+    which-boxed-primitive "^1.0.2"
+
+unimport@^3.0.3:
+  version "3.0.4"
+  resolved "https://registry.npmmirror.com/unimport/-/unimport-3.0.4.tgz#b54d414b0f78673e76c9cbc2568b915c2d64b7c9"
+  integrity sha512-eoof/HLiNJcIkVpnqc7sJbzKSLx39J6xTaP7E4ElgVQKeq2t9fPTkvJKcA55IJTaRPkEkDq8kcc/IZPmrypnFg==
+  dependencies:
+    "@rollup/pluginutils" "^5.0.2"
+    escape-string-regexp "^5.0.0"
+    fast-glob "^3.2.12"
+    local-pkg "^0.4.3"
+    magic-string "^0.30.0"
+    mlly "^1.2.0"
+    pathe "^1.1.0"
+    pkg-types "^1.0.2"
+    scule "^1.0.0"
+    strip-literal "^1.0.1"
+    unplugin "^1.3.1"
+
+unist-util-stringify-position@^2.0.0:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz#cce3bfa1cdf85ba7375d1d5b17bdc4cada9bd9da"
+  integrity sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==
+  dependencies:
+    "@types/unist" "^2.0.2"
+
+universalify@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717"
+  integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==
+
+unplugin-auto-import@^0.15.2:
+  version "0.15.2"
+  resolved "https://registry.npmmirror.com/unplugin-auto-import/-/unplugin-auto-import-0.15.2.tgz#e0eaaa45a64192eaa0f03b993a4a773ddbf82f3b"
+  integrity sha512-Wivfu+xccgvEZG8QtZcIvt6napfX9wyOFqM//7FHOtev8+k+dp3ykiqsEl6TODgHmqTTBeQX4Ah1JvRgUNjlkg==
+  dependencies:
+    "@antfu/utils" "^0.7.2"
+    "@rollup/pluginutils" "^5.0.2"
+    local-pkg "^0.4.3"
+    magic-string "^0.30.0"
+    minimatch "^7.4.3"
+    unimport "^3.0.3"
+    unplugin "^1.3.1"
+
+unplugin-icons@^0.16.1:
+  version "0.16.1"
+  resolved "https://registry.npmmirror.com/unplugin-icons/-/unplugin-icons-0.16.1.tgz#e341185e17f4a7a9171b6dd932b5bf26a2f31fb9"
+  integrity sha512-qTunFUkpAyDnwzwV7YV1ZgCWRYfLuURcCurhhXOWMy2ipY88qx1pADvral2hJu4Xymh0X0t3Zcll3BIru2AVLQ==
+  dependencies:
+    "@antfu/install-pkg" "^0.1.1"
+    "@antfu/utils" "^0.7.2"
+    "@iconify/utils" "^2.1.5"
+    debug "^4.3.4"
+    kolorist "^1.7.0"
+    local-pkg "^0.4.3"
+    unplugin "^1.3.1"
+
+unplugin-vue-components@^0.24.1:
+  version "0.24.1"
+  resolved "https://registry.npmmirror.com/unplugin-vue-components/-/unplugin-vue-components-0.24.1.tgz#b5c3419c30a603dd795e3a0d63c4c12f4a5d8274"
+  integrity sha512-T3A8HkZoIE1Cja95xNqolwza0yD5IVlgZZ1PVAGvVCx8xthmjsv38xWRCtHtwl+rvZyL9uif42SRkDGw9aCfMA==
+  dependencies:
+    "@antfu/utils" "^0.7.2"
+    "@rollup/pluginutils" "^5.0.2"
+    chokidar "^3.5.3"
+    debug "^4.3.4"
+    fast-glob "^3.2.12"
+    local-pkg "^0.4.3"
+    magic-string "^0.30.0"
+    minimatch "^7.4.2"
+    resolve "^1.22.1"
+    unplugin "^1.1.0"
+
+unplugin@^1.1.0, unplugin@^1.3.1:
+  version "1.3.1"
+  resolved "https://registry.npmmirror.com/unplugin/-/unplugin-1.3.1.tgz#7af993ba8695d17d61b0845718380caf6af5109f"
+  integrity sha512-h4uUTIvFBQRxUKS2Wjys6ivoeofGhxzTe2sRWlooyjHXVttcVfV/JiavNd3d4+jty0SVV0dxGw9AkY9MwiaCEw==
+  dependencies:
+    acorn "^8.8.2"
+    chokidar "^3.5.3"
+    webpack-sources "^3.2.3"
+    webpack-virtual-modules "^0.5.0"
+
+upper-case-first@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/upper-case-first/-/upper-case-first-2.0.2.tgz#992c3273f882abd19d1e02894cc147117f844324"
+  integrity sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==
+  dependencies:
+    tslib "^2.0.3"
+
+upper-case@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-2.0.2.tgz#d89810823faab1df1549b7d97a76f8662bae6f7a"
+  integrity sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg==
+  dependencies:
+    tslib "^2.0.3"
+
+uri-js@^4.2.2:
+  version "4.4.1"
+  resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
+  integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
+  dependencies:
+    punycode "^2.1.0"
+
+util-deprecate@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
+  integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
+
+validate-npm-package-license@^3.0.1:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a"
+  integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==
+  dependencies:
+    spdx-correct "^3.0.0"
+    spdx-expression-parse "^3.0.0"
+
+vite-plugin-css-injected-by-js@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/vite-plugin-css-injected-by-js/-/vite-plugin-css-injected-by-js-3.1.0.tgz#d1160c975d40f256692e2465832e6ff18c22b3a3"
+  integrity sha512-qogCmpocZfcbSAYZQjS88ieIY0PzLUm7RkLFWFgAxkXdz3N6roZbSTNTxeIOj5IxFbZWACUPuVBBoo6qCuXDcw==
+
+vite-plugin-style-import@^1.4.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/vite-plugin-style-import/-/vite-plugin-style-import-1.4.1.tgz#47a66920cce5484640f2faacd73190aac0b91b94"
+  integrity sha512-lJCRvm7+So0hHdnSJiJPg9gD5mxtL6YY0jmhEph+k7ArpsyvqOh6han2kG5htbWWDZxHkUN9d1BuTFL//yCLLQ==
+  dependencies:
+    "@rollup/pluginutils" "^4.1.2"
+    change-case "^4.1.2"
+    debug "^4.3.3"
+    es-module-lexer "^0.9.3"
+    fs-extra "^10.0.0"
+    magic-string "^0.25.7"
+
+vite-plugin-windicss@^1.8.10:
+  version "1.8.10"
+  resolved "https://registry.npmmirror.com/vite-plugin-windicss/-/vite-plugin-windicss-1.8.10.tgz#a0e022c5d3def185fb2458a0ba41fc140421ddcb"
+  integrity sha512-scywsuzo46lcTBohspmF0WiwhWEte6p+OUVrX4yr7VMRvLHMHVfLtJReyD5pppjijG7YOwVsZn7XBWWZtF658Q==
+  dependencies:
+    "@windicss/plugin-utils" "1.8.10"
+    debug "^4.3.4"
+    kolorist "^1.6.0"
+    windicss "^3.5.6"
+
+vite@^4.2.1:
+  version "4.2.1"
+  resolved "https://registry.npmmirror.com/vite/-/vite-4.2.1.tgz#6c2eb337b0dfd80a9ded5922163b94949d7fc254"
+  integrity sha512-7MKhqdy0ISo4wnvwtqZkjke6XN4taqQ2TBaTccLIpOKv7Vp2h4Y+NpmWCnGDeSvvn45KxvWgGyb0MkHvY1vgbg==
+  dependencies:
+    esbuild "^0.17.5"
+    postcss "^8.4.21"
+    resolve "^1.22.1"
+    rollup "^3.18.0"
+  optionalDependencies:
+    fsevents "~2.3.2"
+
+vue-demi@*:
+  version "0.13.1"
+  resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.13.1.tgz#7604904c88be338418a10abbc94d5b8caa14cb8c"
+  integrity sha512-xmkJ56koG3ptpLnpgmIzk9/4nFf4CqduSJbUM0OdPoU87NwRuZ6x49OLhjSa/fC15fV+5CbEnrxU4oyE022svg==
+
+vue-eslint-parser@^9.0.1:
+  version "9.0.3"
+  resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-9.0.3.tgz#0c17a89e0932cc94fa6a79f0726697e13bfe3c96"
+  integrity sha512-yL+ZDb+9T0ELG4VIFo/2anAOz8SvBdlqEnQnvJ3M7Scq56DvtjY0VY88bByRZB0D4J0u8olBcfrXTVONXsh4og==
+  dependencies:
+    debug "^4.3.4"
+    eslint-scope "^7.1.1"
+    eslint-visitor-keys "^3.3.0"
+    espree "^9.3.1"
+    esquery "^1.4.0"
+    lodash "^4.17.21"
+    semver "^7.3.6"
+
+vue-router@^3.6.5:
+  version "3.6.5"
+  resolved "https://registry.npmmirror.com/vue-router/-/vue-router-3.6.5.tgz#95847d52b9a7e3f1361cb605c8e6441f202afad8"
+  integrity sha512-VYXZQLtjuvKxxcshuRAwjHnciqZVoXAjTjcqBTz4rKc8qih9g9pI3hbDjmqXaHdgL3v8pV6P8Z335XvHzESxLQ==
+
+vue-template-compiler@^2.7.14:
+  version "2.7.14"
+  resolved "https://registry.npmmirror.com/vue-template-compiler/-/vue-template-compiler-2.7.14.tgz#4545b7dfb88090744c1577ae5ac3f964e61634b1"
+  integrity sha512-zyA5Y3ArvVG0NacJDkkzJuPQDF8RFeRlzV2vLeSnhSpieO6LK2OVbdLPi5MPPs09Ii+gMO8nY4S3iKQxBxDmWQ==
+  dependencies:
+    de-indent "^1.0.2"
+    he "^1.2.0"
+
+vue-template-es2015-compiler@^1.9.1:
+  version "1.9.1"
+  resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz#1ee3bc9a16ecbf5118be334bb15f9c46f82f5825"
+  integrity sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==
+
+vue@^2.7.14:
+  version "2.7.14"
+  resolved "https://registry.npmmirror.com/vue/-/vue-2.7.14.tgz#3743dcd248fd3a34d421ae456b864a0246bafb17"
+  integrity sha512-b2qkFyOM0kwqWFuQmgd4o+uHGU7T+2z3T+WQp8UBjADfEv2n4FEMffzBmCKNP0IGzOEEfYjvtcC62xaSKeQDrQ==
+  dependencies:
+    "@vue/compiler-sfc" "2.7.14"
+    csstype "^3.1.0"
+
+webpack-sources@^3.2.3:
+  version "3.2.3"
+  resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde"
+  integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==
+
+webpack-virtual-modules@^0.5.0:
+  version "0.5.0"
+  resolved "https://registry.npmmirror.com/webpack-virtual-modules/-/webpack-virtual-modules-0.5.0.tgz#362f14738a56dae107937ab98ea7062e8bdd3b6c"
+  integrity sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw==
+
+which-boxed-primitive@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6"
+  integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==
+  dependencies:
+    is-bigint "^1.0.1"
+    is-boolean-object "^1.1.0"
+    is-number-object "^1.0.4"
+    is-string "^1.0.5"
+    is-symbol "^1.0.3"
+
+which-typed-array@^1.1.9:
+  version "1.1.9"
+  resolved "https://registry.npmmirror.com/which-typed-array/-/which-typed-array-1.1.9.tgz#307cf898025848cf995e795e8423c7f337efbde6"
+  integrity sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==
+  dependencies:
+    available-typed-arrays "^1.0.5"
+    call-bind "^1.0.2"
+    for-each "^0.3.3"
+    gopd "^1.0.1"
+    has-tostringtag "^1.0.0"
+    is-typed-array "^1.1.10"
+
+which@^2.0.1:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
+  integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
+  dependencies:
+    isexe "^2.0.0"
+
+windicss@^3.5.6:
+  version "3.5.6"
+  resolved "https://registry.yarnpkg.com/windicss/-/windicss-3.5.6.tgz#30a34da76894d952a96c9a1921f2e91e13932183"
+  integrity sha512-P1mzPEjgFMZLX0ZqfFht4fhV/FX8DTG7ERG1fBLiWvd34pTLVReS5CVsewKn9PApSgXnVfPWwvq+qUsRwpnwFA==
+
+word-wrap@^1.2.3:
+  version "1.2.3"
+  resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
+  integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==
+
+wrappy@1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+  integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
+
+xml-name-validator@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-4.0.0.tgz#79a006e2e63149a8600f15430f0a4725d1524835"
+  integrity sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==
+
+yallist@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
+  integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
+
+yaml-eslint-parser@^1.1.0, yaml-eslint-parser@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.npmmirror.com/yaml-eslint-parser/-/yaml-eslint-parser-1.2.0.tgz#b1a6ce4bd5111596f57a9213ec9c0dd1d0ac7e61"
+  integrity sha512-OmuvQd5lyIJWfFALc39K5fGqp0aWNc+EtyhVgcQIPZaUKMnTb7An3RMp+QJizJ/x0F4kpgTNe6BL/ctdvoIwIg==
+  dependencies:
+    eslint-visitor-keys "^3.0.0"
+    lodash "^4.17.21"
+    yaml "^2.0.0"
+
+yaml@^2.0.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.1.1.tgz#1e06fb4ca46e60d9da07e4f786ea370ed3c3cfec"
+  integrity sha512-o96x3OPo8GjWeSLF+wOAbrPfhFOGY0W00GNaxCDv+9hkcDJEnev1yh8S7pgHF0ik6zc8sQLuL8hjHjJULZp8bw==
+
+yocto-queue@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
+  integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==