Forráskód Böngészése

Merge branch 'dev/v1.0.77_yf' of jianyu/web into feature/v1.0.77

yangfeng 9 hónapja
szülő
commit
8e28e88606

+ 2 - 1
apps/mobile/package.json

@@ -17,6 +17,7 @@
     "@jy/vue-anti": "workspace:^",
     "@sentry/vue": "^7.64.0",
     "@tinymce/tinymce-vue": "^3.2.8",
+    "aliyun_numberauthsdk_web": "^2.1.9",
     "dayjs": "^1.11.8",
     "html2canvas": "^1.4.1",
     "js-cookie": "^3.0.1",
@@ -36,10 +37,10 @@
   },
   "devDependencies": {
     "@jonny1994/postcss-px-to-viewport": "^1.1.0",
-    "@unocss/transformer-variant-group": "^0.58.5",
     "@nabla/vite-plugin-eslint": "^2.0.2",
     "@rushstack/eslint-patch": "^1.1.0",
     "@sentry/vite-plugin": "^2.21.1",
+    "@unocss/transformer-variant-group": "^0.58.5",
     "@vitejs/plugin-legacy": "^4.0.4",
     "@vitejs/plugin-vue2": "^2.2.0",
     "@vue/eslint-config-prettier": "^7.0.0",

+ 19 - 4
apps/mobile/src/api/modules/pay.js

@@ -1,5 +1,6 @@
-import request from '@/api'
 import qs from 'qs'
+import request from '@/api'
+
 export function screenList() {
   return request({
     url: '/subscribepay/dataExportPack/screenList',
@@ -208,7 +209,6 @@ export function getWxSdkSign(data) {
 /**
  * 获取商品详情信息(超级订阅、数据流量包)
  * @param data
- * @returns {AxiosPromise}
  */
 export function getCommodityDetail(data) {
   return request({
@@ -221,7 +221,6 @@ export function getCommodityDetail(data) {
 /**
  * 实时计算当前下单价格
  * @param data
- * @returns {AxiosPromise}
  */
 export function getOrderPrice(data) {
   return request({
@@ -234,7 +233,6 @@ export function getOrderPrice(data) {
 /**
  * 获取当前规格产品下的活动以及优惠信息
  * @param data
- * @returns {AxiosPromise}
  */
 export function getCommodityCouponInfo(data) {
   return request({
@@ -307,3 +305,20 @@ export function vipRenewReminder(data) {
     data: qs.stringify(data)
   })
 }
+
+// 获取图形验证码
+export function getPhoneCaptcha() {
+  return request({
+    url: `/jypay/user/phone/imgCaptcha?t=${Date.now()}`,
+    method: 'GET'
+  })
+}
+
+export function setPhoneBind(data, type) {
+  data = qs.stringify(data)
+  return request({
+    url: `/jypay/user/phone/${type}`,
+    method: 'POST',
+    data
+  })
+}

+ 20 - 0
apps/mobile/src/api/modules/public.js

@@ -334,6 +334,26 @@ export function getIsWhiteList() {
   })
 }
 
+// 一键登录/注册/绑定
+export function getPhoneByToken(data) {
+  data = qs.stringify(data)
+  return request({
+    url: '/publicapply/oneClick/getPhoneByToken',
+    method: 'POST',
+    data
+  })
+}
+
+// 一键登录 获取 H5 认证授权 Token
+export function getAuthToken(data) {
+  data = qs.stringify(data)
+  return request({
+    url: '/publicapply/oneClick/getAuthToken',
+    method: 'POST',
+    data
+  })
+}
+
 // 获取公众号置顶教程入口显示时间
 export function getConfiguration(data) {
   return request({

+ 23 - 19
apps/mobile/src/components/customerBid/index.vue

@@ -1,7 +1,11 @@
 <template>
-  <div class="customer-bid" :class="{ fadeOutRight: !scrollStatus }" :style="{ bottom: bottomPosition || '' }">
+  <div
+    class="customer-bid"
+    :class="{ fadeOutRight: !scrollStatus }"
+    :style="{ bottom: bottomPosition || '' }"
+  >
     <div class="content" @click="jumpCustomerPage">
-      <img src="@/assets/image/icon/customer-bid.png" alt="">
+      <img src="@/assets/image/icon/customer-bid.png" alt="" />
     </div>
   </div>
 </template>
@@ -33,24 +37,24 @@ export default {
 </script>
 
 <style lang="scss" scoped>
-  .customer-bid{
-    position: fixed;
+.customer-bid {
+  position: fixed;
+  width: 62px;
+  height: 62px;
+  bottom: 16%;
+  right: 2px;
+  z-index: 99;
+  &.fadeOutRight {
+    transform: translateX(98%);
+    opacity: 0.2;
+  }
+  .content {
+    height: 100%;
+    text-align: center;
+  }
+  img {
     width: 62px;
     height: 62px;
-    bottom: 16%;
-    right: 2px;
-    z-index: 99;
-    &.fadeOutRight {
-      transform: translateX(98%);
-      opacity: 0.2;
-    }
-    .content{
-      height:100%;
-      text-align: center;
-    }
-    img{
-      width: 62px;
-      height: 62px;
-    }
   }
+}
 </style>

+ 324 - 0
apps/mobile/src/components/one-click-binding/index.vue

@@ -0,0 +1,324 @@
+<template>
+  <div class="one-click-bind">
+    <div class="bind-header">
+      <span
+        >根据《中华人民共和国网络安全法》要求,<br />
+        为避免非正常使用标讯信息,需完成手机号绑定</span
+      >
+    </div>
+    <div class="bind-form">
+      <van-field
+        v-model.trim="info.phone"
+        label="手机号"
+        type="tel"
+        maxlength="11"
+        placeholder="请输入手机号码"
+        :error-message="errorMessage.phone"
+        @blur="checkPhoneRegPass"
+      ></van-field>
+      <van-field
+        v-show="picCode.show"
+        v-model.trim="info.picCode"
+        label=""
+        maxlength="6"
+        placeholder="图形验证码"
+        :error-message="errorMessage.picCode"
+      >
+        <template #button>
+          <div class="pic-code" @click="refreshCaptcha">
+            <img :src="imgBase64Complete" v-if="picCode.imgBase64" />
+            <van-loading size="24" v-else></van-loading>
+          </div>
+        </template>
+      </van-field>
+      <van-field
+        v-model.trim="info.code"
+        label="验证码"
+        maxlength="6"
+        placeholder="请输入验证码"
+        :error-message="errorMessage.code"
+      >
+        <template #button>
+          <van-button
+            class="send-code"
+            size="small"
+            :disabled="sendCodeButtonDisabled"
+            @click="sendVerifyCode"
+            >{{ sendCodeButtonText }}</van-button
+          >
+        </template>
+      </van-field>
+    </div>
+    <div class="bind-footer">
+      <div class="j-button-group">
+        <button
+          class="j-button-confirm"
+          @click="onSubmit"
+          :disabled="confirmButtonDisabled"
+        >
+          立即绑定
+        </button>
+      </div>
+      <div class="fast-login-container">
+        <button
+          class="fast-login-text fast-login-open-link highlight-text"
+          @click="getPhoneBind"
+        >
+          本机号码一键绑定
+        </button>
+      </div>
+      <div class="tip-text" v-if="showBottomTip">
+        根据《中华人民共和国网络安全法》第二十四条及相关法律规定,请您填写正确的手机号进行认证,获取更多网络服务。
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { Field, Button, Loading } from 'vant'
+import { getPhoneCaptcha, setPhoneBind } from '@/api/modules/'
+import fastLogin from '@/utils/mixins/modules/fast-bind'
+export default {
+  name: 'OneClickBinding',
+  props: {},
+  mixins: [fastLogin],
+  components: {
+    [Field.name]: Field,
+    [Button.name]: Button,
+    [Loading.name]: Loading
+  },
+  data() {
+    return {
+      info: {
+        phone: '',
+        picCode: '',
+        code: ''
+      },
+      errorMessage: {
+        phone: '',
+        picCode: '',
+        code: ''
+      },
+      sendCodeButton: {
+        timerId: 0,
+        timeStartDefault: 60,
+        defaultValue: '发送验证码',
+        count: 0
+      },
+      picCode: {
+        show: false,
+        imgBase64: '',
+        cacheShow: false,
+        cacheImgBase64: ''
+      },
+      conf: {
+        phoneReg: /^1[3-9]\d{9}$/
+      },
+      showBottomTip: false
+    }
+  },
+  computed: {
+    confirmButtonDisabled() {
+      let hasEmpty = false
+      if (this.picCode.show) {
+        hasEmpty = !this.info.phone || !this.info.code || !this.info.picCode
+      } else {
+        hasEmpty = !this.info.phone || !this.info.code
+      }
+      const pass = this.conf.phoneReg.test(this.info.phone)
+      return hasEmpty || !pass
+    },
+    sendCodeButtonText() {
+      const dText = this.sendCodeButton.defaultValue
+      return this.sendCodeButton.count <= 0
+        ? dText
+        : `重新发送(${this.sendCodeButton.count}s)`
+    },
+    sendCodeButtonDisabled() {
+      return this.sendCodeButton.count > 0
+    },
+    imgBase64Complete() {
+      return 'data:image/png;base64,' + this.picCode.imgBase64
+    }
+  },
+  methods: {
+    showToast(message) {
+      this.$toast({
+        duration: 1500,
+        forbidClick: true,
+        message: message
+      })
+    },
+    showLoading() {
+      return this.$toast.loading({
+        duration: 0,
+        forbidClick: true,
+        message: 'loading...'
+      })
+    },
+    async getImgCaptcha(needCache) {
+      if (this.picCode.cacheImgBase64) {
+        this.picCode.show = this.picCode.cacheShow
+        this.picCode.imgBase64 = this.picCode.cacheImgBase64
+        this.picCode.cacheImgBase64 = ''
+        return
+      }
+      const { error_code: code, error_msg: msg, data } = await getPhoneCaptcha()
+      if (code === 0 && data) {
+        // 是否缓存图片
+        if (needCache == 'cache') {
+          // 将下一张图片的状态缓存
+          this.picCode.cacheShow = data.needVerify
+          this.picCode.cacheImgBase64 = data.imageData
+        } else {
+          this.picCode.show = data.needVerify
+          this.picCode.imgBase64 = data.imageData
+        }
+      } else {
+        this.showToast(msg)
+      }
+    },
+    refreshCaptcha() {
+      this.picCode.imgBase64 = ''
+      this.getImgCaptcha()
+    },
+    checkPhoneRegPass() {
+      let pass = this.conf.phoneReg.test(this.info.phone)
+      if (this.info.phone) {
+        if (pass) {
+          this.errorMessage.phone = ''
+        } else {
+          this.errorMessage.phone = '手机号格式不正确'
+        }
+      } else {
+        this.errorMessage.phone = ''
+      }
+      return pass
+    },
+    startSendCodeTimer(t) {
+      this.sendCodeButton.count = t || this.sendCodeButton.timeStartDefault
+      this.sendCodeButton.timerId = setInterval(() => {
+        this.sendCodeButton.count--
+        if (this.sendCodeButton.count <= 0) {
+          // 倒计时结束
+          clearInterval(this.sendCodeButton.timerId)
+          // 倒计时结束,刷新验证码
+          if (this.picCode.cacheImgBase64) {
+            this.picCode.show = this.picCode.cacheShow
+            this.picCode.imgBase64 = this.picCode.cacheImgBase64
+            this.picCode.cacheImgBase64 = ''
+          } else {
+            this.refreshCaptcha()
+          }
+        }
+      }, 1000)
+    },
+    // 发送验证码
+    async sendVerifyCode() {
+      const pass = this.checkPhoneRegPass()
+      if (!pass) return
+      const loading = this.showLoading()
+      const params = {
+        phone: this.info.phone,
+        code: this.info.picCode,
+        step: 1
+      }
+      const {
+        error_code: code,
+        error_msg: msg,
+        data
+      } = await setPhoneBind(params, 'bind')
+      loading.clear()
+      if (code === 0 && data?.state === 1) {
+        this.startSendCodeTimer()
+        this.showToast('验证码发送成功')
+        this.getImgCaptcha('cache')
+      } else {
+        this.showToast(msg || '验证码发送失败')
+        this.refreshCaptcha()
+      }
+    },
+    bindPhoneSuccess(state) {
+      if (state === 1) {
+        let newQuery = JSON.parse(JSON.stringify(this.$route.query))
+        if (newQuery && newQuery.wxpush) {
+          delete newQuery.type
+        }
+        this.$router.replace({ query: newQuery })
+      }
+    },
+    async onSubmit() {
+      const pass = this.checkPhoneRegPass()
+      if (!pass) return
+      const loading = this.showLoading()
+      const params = {
+        phone: this.info.phone,
+        code: this.info.picCode,
+        step: 2
+      }
+      const {
+        error_code: code,
+        error_msg: msg,
+        data
+      } = await setPhoneBind(params, 'bind')
+      loading.clear()
+      if (code === 0 && data) {
+        this.bindPhoneSuccess(data.state)
+      } else {
+        this.$toast(msg)
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.one-click-bind {
+  margin: 12px;
+  border: 2px solid $color_main;
+  border-radius: 12px;
+  background: #fff;
+  .bind-header {
+    padding: 16px 8px 12px;
+    font-size: 14px;
+    line-height: 20px;
+    color: #171826;
+    text-align: center;
+  }
+  .bind-form {
+    padding: 0 8px;
+    .send-code {
+      height: unset;
+      color: $color_main;
+      font-size: 14px;
+      line-height: 20px;
+      border: none;
+    }
+    ::v-deep {
+      .van-cell {
+        align-items: center;
+        padding: 16px;
+      }
+      .van-field__label {
+        width: 75px;
+        margin-right: 8px;
+        font-size: 15px;
+        line-height: 22px;
+        color: #5f5e64;
+      }
+      .van-field__value {
+        font-size: 16px;
+      }
+    }
+  }
+  .fast-login-container {
+    text-align: center;
+  }
+  .fast-login-text {
+    padding-bottom: 20px;
+    font-size: 16px;
+    line-height: 26px;
+    background-color: transparent;
+  }
+}
+</style>

+ 60 - 0
apps/mobile/src/utils/callFn/appFn.js

@@ -283,3 +283,63 @@ export function appShare(
     console.warn('error: app call share', e)
   }
 }
+
+// 一键绑定、登录
+export function appGetPhoneBind() {
+  try {
+    JyObj.getPhoneBind()
+  }
+  catch (e) {
+    console.warn('error: app call getPhoneBind', e)
+  }
+}
+
+// 获取极光推送id
+export function appGetPushRid() {
+  try {
+    JyObj.getPushRid()
+  }
+  catch (e) {
+    console.warn('error: app call getPushRid', e)
+  }
+}
+
+// 获取推送id
+export function appGetOtherPushId() {
+  try {
+    JyObj.getOtherPushId()
+  }
+  catch (e) {
+    console.warn('error: app call getOtherPushId', e)
+  }
+}
+
+// 获取手机型号
+export function appGetPhoneType() {
+  try {
+    JyObj.getPhoneType()
+  }
+  catch (e) {
+    console.warn('error: app call getPhoneType', e)
+  }
+}
+
+// 渠道
+export function appGetChannel() {
+  try {
+    JyObj.getChannel()
+  }
+  catch (e) {
+    console.warn('error: app call getChannel', e)
+  }
+}
+
+// 设备id
+export function appGetDeviceId() {
+  try {
+    JyObj.getDeviceId()
+  }
+  catch (e) {
+    console.warn('error: app call getDeviceId', e)
+  }
+}

+ 396 - 0
apps/mobile/src/utils/mixins/modules/fast-bind.js

@@ -0,0 +1,396 @@
+import { PhoneNumberServer } from 'aliyun_numberauthsdk_web'
+import { envs } from '@/utils/prototype/modules/platform'
+import { getAuthToken, getPhoneByToken } from '@/api/modules/'
+import {
+  appGetChannel,
+  appGetDeviceId,
+  appGetOtherPushId,
+  appGetPhoneBind,
+  appGetPhoneType,
+  appGetPushRid
+} from '@/utils/callFn/appFn'
+
+const phoneNumberServer = new PhoneNumberServer()
+
+const fLogin = {
+  methods: {
+    getPrePayload() {
+      let payload = {}
+      const { query } = this.$route
+      try {
+        payload = {
+          rid: appGetPushRid(),
+          oid: appGetOtherPushId(),
+          phoneType: appGetPhoneType(),
+          channel: appGetChannel(),
+          deviceId: appGetDeviceId(),
+          disWord: query?.disWord || '',
+          activity: query?.activity || ''
+        }
+      }
+      catch (error) {
+        console.log(error)
+      }
+      return payload
+    },
+    async doPhoneFastLogin(tokenInfo) {
+      this.loading()
+      const payload = this.getPrePayload()
+      Object.assign(payload, tokenInfo)
+      const {
+        error_code: code,
+        error_msg: msg,
+        data
+      } = await getPhoneByToken(payload)
+      if (code === 0) {
+        this.doPhoneFastLoginSuccess(data)
+      }
+      else {
+        if (this.toast.enable) {
+          if (msg) {
+            this.$toast(msg)
+          }
+          else {
+            if (payload.actionType === 'B') {
+              this.$toast('绑定失败')
+            }
+            else {
+              this.$toast('登录失败')
+            }
+          }
+        }
+      }
+      this.loadingClear()
+      this.enableToast()
+    },
+    doPhoneFastLoginSuccess(data) {
+      if (data) {
+        // 绑定/登录成功回调
+        this.bindPhoneSuccess(data?.state)
+      }
+    }
+  }
+}
+const loadingMixin = {
+  methods: {
+    loading() {
+      return this.$toast.loading({
+        loadingType: 'spinner',
+        duration: 0,
+        forbidClick: true
+      })
+    },
+    loadingClear() {
+      return this.$toast.clear()
+    }
+  }
+}
+const toastMixin = {
+  data() {
+    return {
+      toast: {
+        enable: true // toast是否可用,默认可用
+      }
+    }
+  },
+  methods: {
+    enableToast() {
+      this.toast.enable = true
+    },
+    disabledToast() {
+      this.toast.enable = false
+    }
+  }
+}
+
+const fastLoginConfApp = {
+  mixins: [loadingMixin, toastMixin, fLogin],
+  data() {
+    return {
+      tokenInfo: {
+        accessToken: '',
+        outId: '',
+        requestId: '',
+        venderName: ''
+      }
+    }
+  },
+  created() {
+    window.getPhoneBindCallback = this.getPhoneBindCallback
+  },
+  methods: {
+    getPrePayload() {
+      return {
+        actionType: 'B'
+      }
+    },
+    doPhoneFastLoginSuccess(r) {
+      if (r && r.data) {
+        this.bindPhoneSuccess(r.data.state)
+      }
+    },
+    getPhoneBind() {
+      this.loading()
+      try {
+        appGetPhoneBind()
+      }
+      catch (e) {
+        console.log(e)
+        this.enableToast()
+        this.loadingClear()
+      }
+    },
+    getPhoneBindCallback(r) {
+      this.loadingClear()
+      if (!r)
+        return
+      const res = JSON.parse(r)
+      // 错误码需要注意:android取res.code,ios取resultCode
+      if (res && res.token) {
+        this.tokenInfo.accessToken = res.token
+        this.tokenInfo.outId = res.requestId
+        this.tokenInfo.requestId = res.requestId
+        this.tokenInfo.venderName = res.venderName
+        this.doFastBind()
+      }
+      else {
+        if (this.toast.enable && res.msg) {
+          // this.$toast(res.msg)
+          // 错误码需要注意:android取res.code,ios取resultCode
+          const androidError = res.code && res.code < 700000 && res.code > 600001
+          const iosError
+            = res.resultCode && res.resultCode < 700000 && res.resultCode > 600001
+          if (androidError || iosError) {
+            this.$toast('当前网络环境不支持一键绑定认证')
+          }
+        }
+      }
+      this.enableToast()
+    },
+    doFastBind() {
+      const tokenInfo = this.tokenInfo
+      this.doPhoneFastLogin(tokenInfo)
+    }
+  }
+}
+
+const fastLoginConfH5 = {
+  mixins: [loadingMixin, toastMixin, fLogin],
+  data() {
+    return {
+      authPageOption: {
+        // mount: 'h5-verify', // 指定挂载节点
+        navText: '一键登录', // 标题必须填,否则会报错(授权页css属性超过限制)
+        subtitle: '', // 副标题
+        isHideLogo: false, // logo显示隐藏
+        numberLabel: '请填写完整手机号,并授权剑鱼标讯认证使用',
+        logoImg: '/common-module/public/image/register_logo.png',
+        btnText: '一键登录/注册',
+        agreeSymbol: '、',
+        privacyOne: [
+          '《使用协议》',
+          '/jyapp/free/staticPage/permission_rules.html'
+        ],
+        privacyTwo: [
+          '《隐私政策》',
+          '/jyapp/free/staticPage/privacy_rules.html'
+        ],
+        showCustomView: true,
+        customView: {
+          element:
+            '<div class="btn_box other" onclick="clickEvent()"><button class="verify-button verify-cancel">其他手机号登录/注册</button></div>',
+          style: '.btn_box.other{width: 100%;}',
+          js: 'function clickEvent(){phoneNumberServer.closeLoginPage()}'
+        },
+        privacyBefore: '我已阅读并同意',
+        privacyEnd: '',
+        vendorPrivacyPrefix: '《',
+        vendorPrivacySuffix: '》',
+        privacyVenderIndex: 0,
+        isDialog: false, // 是否是弹窗样式
+        manualClose: true, // 是否手动关闭弹窗/授权页
+        isPrePageType: false,
+        isShowProtocolDesc: false
+      },
+      h5AuthInfo: {
+        jwtToken: '',
+        accessToken: ''
+      },
+      h5TokenInfo: {
+        outId: '',
+        requestId: '',
+        spToken: '',
+        vender: '' // CM/CU/CT CM:中国移动,CU:中国联通,CT:中国电信
+      },
+      prePayload: {}
+    }
+  },
+  created() {
+    this.prePayload = this.getPrePayload()
+    this.calcAuthPageOption()
+  },
+  methods: {
+    // 此方法有误差,在ios可能识别为unknown
+    checkLoginEnvAvailable() {
+      // 注: h5下为jssdk获取的wifi/cellular/unknown,app下为客户端sdk获取的'0'/'1'
+      const connection = phoneNumberServer.getConnection()
+      // 只要不是wifi就可以
+      console.log('当前网络:', connection)
+      return connection !== 'wifi'
+    },
+    unavailableEnvToast() {
+      const actionType = this.prePayload.actionType
+      if (actionType === 'B') {
+        this.$toast('当前网络环境不支持一键绑定认证')
+      }
+      else {
+        this.$toast('当前网络环境不支持一键登录认证')
+      }
+    },
+    async getPhoneBind() {
+      if (!this.checkLoginEnvAvailable()) {
+        if (this.toast.enable) {
+          this.unavailableEnvToast()
+        }
+        return this.enableToast()
+      }
+      this.loading()
+      const { error_msg: msg, data } = await getAuthToken()
+      if (data) {
+        this.h5AuthInfo = data
+        this.doCheckLogin()
+      }
+      else {
+        if (this.toast.enable && msg) {
+          this.$toast(msg)
+        }
+        else {
+          this.$toast('获取授权信息失败')
+        }
+        this.enableToast()
+      }
+    },
+    doCheckLogin() {
+      // 调用之前先去用户服务端获取accessToken和jwtToken
+      // var h5TokenInfo = {
+      //   jwtToken: "OhT****************dw",
+      //   accessToken: "qaxz*******************0qazx",
+      // };
+      const h5TokenInfo = this.h5AuthInfo
+      this.checkLogin(h5TokenInfo.jwtToken, h5TokenInfo.accessToken)
+    },
+    calcAuthPageOption() {
+      if (envs.inApp || envs.inH5) {
+        // do something
+      }
+      else {
+        this.authPageOption.privacyOne = [
+          '《使用协议》',
+          '/front/staticPage/permission_rules.html'
+        ]
+        this.authPageOption.privacyTwo = [
+          '《隐私政策》',
+          '/front/staticPage/privacy_rules.html'
+        ]
+        // this.authPageOption.btnText = '一键绑定手机号'
+      }
+    },
+    getToken() {
+      const _this = this
+      const authPageOption = this.authPageOption
+      phoneNumberServer.getLoginToken({
+        // 配置选项
+        authPageOption,
+        // 成功回调
+        success(res) {
+          console.log('取号成功', res)
+          // 一键登录: 可发请求到服务端调用 GetPhoneWithToken API, 获取用户手机号, 完成登录
+          // 拿到spToken去服务端发起Token验证
+          if (res.code === 600000) {
+            const h5TokenInfo = {
+              outId: res.requestId,
+              requestId: res.requestId,
+              spToken: res.spToken,
+              vender: res.vender
+            }
+            Object.assign(_this.h5TokenInfo, h5TokenInfo)
+            phoneNumberServer.closeLoginPage() // 手动关闭授权页时调用关闭页面
+            res.clearInput() // 清空输入框并将光标置于第一个输入框
+            res.focusOn(2) // 将光标置于第1-4个输入框
+            res.setMessage({
+              // 设置弹出Toast提示框(有默认样式)
+              showMessage: true, // 是否弹出Toast提示框
+              messageContent: '验证成功', // 弹出内容
+              messageStyle: {
+                // 自定义弹窗样式,写入css样式即可
+                color: '#fff',
+                borderRadius: '8px'
+              },
+              time: 2000 // 弹出时间/ms,默认3000毫秒
+            })
+            _this.verifyPhoneSuccess()
+          }
+        },
+        // 失败回调
+        error(res) {
+          // 提示用户关闭Wi-Fi或者尝试其他登录方案
+          // _this.showInputLogin()
+          console.log('取号失败', res)
+          if (_this.toast.enable) {
+            // _this.$toast(res.msg)
+            _this.unavailableEnvToast()
+          }
+          else {
+            _this.enableToast()
+            _this.loadingClear()
+          }
+        },
+        // 授权页状态监听函数
+        watch(status, data) {
+          // console.log('-----------------status', status, data);
+          // 当status为2时整个流程结束,比如如果按钮有loading状态此处置为false
+          console.log(status, data)
+        }
+      })
+    },
+    checkLogin(jwtToken, accessToken) {
+      const _this = this
+      phoneNumberServer.checkLoginAvailable({
+        accessToken,
+        jwtToken,
+        success(res) {
+          console.log('身份鉴权成功, 可唤起登录/绑定界面', res)
+          if (res.code === 600000) {
+            // 在此调用getLoginToken方法
+            _this.loadingClear()
+            _this.getToken()
+          }
+          _this.enableToast()
+        },
+        error(res) {
+          console.log('身份鉴权失败', res)
+          // 提示用户关闭Wi-Fi或者尝试其他登录方案
+          if (_this.toast.enable) {
+            if (_this.actionType === 'B') {
+              _this.$toast('身份鉴权失败,请使用其他方式绑定')
+            }
+            else {
+              _this.$toast('身份鉴权失败,请使用其他方式登录/注册')
+            }
+          }
+          else {
+            _this.loadingClear()
+          }
+          _this.enableToast()
+        }
+      })
+    },
+    verifyPhoneSuccess() {
+      const h5TokenInfo = this.h5TokenInfo
+      this.doPhoneFastLogin(h5TokenInfo)
+    }
+  }
+}
+
+const fastLogin = envs.inApp ? fastLoginConfApp : fastLoginConfH5
+export default fastLogin

+ 39 - 5
apps/mobile/src/views/article/content.vue

@@ -10,17 +10,34 @@
       <div v-else class="j-container page-container">
         <div
           class="j-main article-content-main"
-          :class="{ 'show-underline': otherModel.hasProject }"
+          :class="{
+            'show-underline': otherModel.hasProject,
+            'no-scroll': showBindPhone
+          }"
           @click="onScrollWrapperClick"
           ref="scrollWrapper"
           @scroll.passive="onScroll"
         >
-          <ContentHeader :beforeLeavePage="beforeLeavePage"></ContentHeader>
+          <ContentHeader
+            :class="{ 'z-index10': showBindPhone }"
+            :beforeLeavePage="beforeLeavePage"
+          ></ContentHeader>
           <ContentHeaderBannerTip
+            :class="{ 'z-index10': showBindPhone }"
             :id="pageState.id"
             :beforeLeavePage="beforeLeavePage"
             v-if="content.recommendedService"
           ></ContentHeaderBannerTip>
+          <OneClickBinding
+            v-if="showBindPhone"
+            :class="{ 'z-index10': showBindPhone }"
+          ></OneClickBinding>
+          <van-overlay
+            class-name="custom-overlay"
+            :show="showBindPhone"
+            :lock-scroll="false"
+          ></van-overlay>
+
           <van-tabs
             v-if="canRead"
             v-model="pageState.tabActive"
@@ -105,7 +122,6 @@
               />
             </van-tab>
           </van-tabs>
-
           <template v-if="!canRead">
             <FreeUserAdvancedMask
               v-if="content.isNiJian || content.isCaigouyixiang"
@@ -157,7 +173,7 @@
   </div>
 </template>
 <script>
-import { Tabs, Tab, Icon, Skeleton } from 'vant'
+import { Tabs, Tab, Icon, Skeleton, Overlay } from 'vant'
 import { mixinHeader } from '@/utils/mixins/header'
 import { appWxShareMixin } from '@/utils/mixins/modules/app-wx-share'
 import { isElementInScrollArea, checkAncestorClass } from '@jy/util'
@@ -180,6 +196,7 @@ import ThirdPartyVerifyPopup from '@/views/article/components/ThirdPartyVerifyPo
 import CheckUserDialog from '@/views/identity/components/CheckUserDialog'
 import CustomerCorner from '@/components/customer/index'
 import Error from '@/views/article/components/Error.vue'
+import OneClickBinding from '@/components/one-click-binding/index'
 import { throttle } from 'lodash'
 import { mapState, mapMutations, mapActions, mapGetters } from 'vuex'
 import {
@@ -198,6 +215,7 @@ export default {
     [Tab.name]: Tab,
     [Icon.name]: Icon,
     [Skeleton.name]: Skeleton,
+    [Overlay.name]: Overlay,
     ContentHeader,
     ContentHeaderBannerTip,
     ContentAbstract,
@@ -216,7 +234,8 @@ export default {
     TabActions,
     AdSingle,
     CustomerCorner,
-    Error
+    Error,
+    OneClickBinding
   },
   data() {
     return {
@@ -350,6 +369,11 @@ export default {
     },
     getContentAdID() {
       return (this.$envs.inWX ? 'jy' : 'jyapp') + '-wxcontent-bottom'
+    },
+    // 是否展示绑定手机号弹窗
+    showBindPhone() {
+      const { wxpush } = this.$route?.query
+      return wxpush === 'bind' && this.$envs.inWX
     }
   },
   async created() {
@@ -795,6 +819,16 @@ export default {
   margin: 8px 16px;
   margin-bottom: 32px;
 }
+.custom-overlay {
+  background: linear-gradient(#ededed66 80%, #f9f9f9 100%);
+}
+.z-index10 {
+  position: relative;
+  z-index: 10;
+}
+.no-scroll {
+  overflow: hidden;
+}
 </style>
 <style>
 .no-select {

+ 42 - 30
apps/mobile/src/views/coursePage/Index.vue

@@ -1,24 +1,36 @@
 <template>
   <div class="course-page">
     <div class="course-1">
-      <img src="@/assets/image/course-page/1.jpg" alt="">
+      <img src="@/assets/image/course-page/1.jpg" alt="" />
     </div>
     <div class="course-2 course-common">
-      <img src="@/assets/image/course-page/2.jpg" alt="">
+      <img src="@/assets/image/course-page/2.jpg" alt="" />
       <div class="course-video video-1">
-        <video preload="auto" controls src="@/assets/image/course-page/video-1.mp4" />
+        <video
+          preload="auto"
+          controls
+          src="@/assets/image/course-page/video-1.mp4"
+        />
       </div>
     </div>
     <div class="course-3 course-common">
-      <img src="@/assets/image/course-page/3.jpg" alt="">
+      <img src="@/assets/image/course-page/3.jpg" alt="" />
       <div class="course-video video-2">
-        <video preload="auto" controls src="@/assets/image/course-page/video-2.mp4" />
+        <video
+          preload="auto"
+          controls
+          src="@/assets/image/course-page/video-2.mp4"
+        />
       </div>
     </div>
     <div class="course-4 course-common">
-      <img src="@/assets/image/course-page/4.jpg" alt="">
+      <img src="@/assets/image/course-page/4.jpg" alt="" />
       <div class="course-video video-3">
-        <video preload="auto" controls src="@/assets/image/course-page/video-3.mp4" />
+        <video
+          preload="auto"
+          controls
+          src="@/assets/image/course-page/video-3.mp4"
+        />
       </div>
     </div>
   </div>
@@ -26,34 +38,34 @@
 
 <script>
 export default {
-  name: 'CoursePage',
+  name: 'CoursePage'
 }
 </script>
 
 <style lang="scss">
-  .course-page {
-    .course-common {
-      position: relative;
-      .course-video {
-        position: absolute;
-        top: 0;
-        left: 83px;
-        border-radius: 27px;
-        overflow: hidden;
-        &.video-1 {
-          top: 176px;
-        }
-        &.video-2 {
-          top: 192px;
-        }
-        &.video-3 {
-          top: 204px;
-        }
-        video {
-          width: 211px;
-          height: 456px;
-        }
+.course-page {
+  .course-common {
+    position: relative;
+    .course-video {
+      position: absolute;
+      top: 0;
+      left: 83px;
+      border-radius: 27px;
+      overflow: hidden;
+      &.video-1 {
+        top: 176px;
+      }
+      &.video-2 {
+        top: 192px;
+      }
+      &.video-3 {
+        top: 204px;
+      }
+      video {
+        width: 211px;
+        height: 456px;
       }
     }
   }
+}
 </style>

+ 5 - 3
apps/mobile/src/views/tabbar/Home.vue

@@ -276,7 +276,7 @@ export default {
     })
   },
   methods: {
-    checkShowToast () {
+    checkShowToast() {
       const needToast = this.$route.query.toast
       switch (needToast) {
         case 'l': {
@@ -292,7 +292,9 @@ export default {
           break
         }
         case 'c': {
-          this.$toast('您已是剑鱼标讯注册用户,不符合领取条件,如有疑问请咨询客服 400-108-6670')
+          this.$toast(
+            '您已是剑鱼标讯注册用户,不符合领取条件,如有疑问请咨询客服 400-108-6670'
+          )
           break
         }
         default: {
@@ -303,7 +305,7 @@ export default {
         }
       }
       if (needToast) {
-        const query = { ... this.$route.query }
+        const query = { ...this.$route.query }
         delete query.toast
         setTimeout(() => {
           this.$router.replace({

+ 354 - 27
pnpm-lock.yaml

@@ -308,6 +308,9 @@ importers:
       '@tinymce/tinymce-vue':
         specifier: ^3.2.8
         version: 3.2.8(vue@2.7.16)
+      aliyun_numberauthsdk_web:
+        specifier: ^2.1.9
+        version: 2.1.9
       dayjs:
         specifier: ^1.11.8
         version: 1.11.8
@@ -3584,18 +3587,15 @@ packages:
     resolution: {integrity: sha512-42UH54oPZHPdRHdw6BgoBD6cg/eVTmVrFcgeRDM3jbO7uxSoipVcmcIGFcA5jmOHO5apcyvBhkSKES3fQJnu7A==}
     dependencies:
       '@floating-ui/utils': 0.2.2
-    dev: true
 
   /@floating-ui/dom@1.6.4:
     resolution: {integrity: sha512-0G8R+zOvQsAG1pg2Q99P21jiqxqGBW1iRe/iXHsBRBxnpXKFI8QwbB4x5KmYLggNO5m34IQgOIu9SCRfR/WWiQ==}
     dependencies:
       '@floating-ui/core': 1.6.1
       '@floating-ui/utils': 0.2.2
-    dev: true
 
   /@floating-ui/utils@0.2.2:
     resolution: {integrity: sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw==}
-    dev: true
 
   /@floating-ui/vue@1.0.6(vue@3.3.11):
     resolution: {integrity: sha512-EdrOljjkpkkqZnrpqUcPoz9NvHxuTjUtSInh6GMv3+Mcy+giY2cE2pHh9rpacRcZ2eMSCxel9jWkWXTjLmY55w==}
@@ -3903,6 +3903,67 @@ packages:
     resolution: {integrity: sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ==}
     dev: true
 
+  /@rc-component/mini-decimal@1.1.0:
+    resolution: {integrity: sha512-jS4E7T9Li2GuYwI6PyiVXmxTiM6b07rlD9Ge8uGZSCz3WlzcG5ZK7g5bbuKNeZ9pgUuPK/5guV781ujdVpm4HQ==}
+    engines: {node: '>=8.x'}
+    dependencies:
+      '@babel/runtime': 7.22.6
+    dev: false
+
+  /@react-spring/animated@9.6.1(react@17.0.2):
+    resolution: {integrity: sha512-ls/rJBrAqiAYozjLo5EPPLLOb1LM0lNVQcXODTC1SMtS6DbuBCPaKco5svFUQFMP2dso3O+qcC4k9FsKc0KxMQ==}
+    peerDependencies:
+      react: ^16.8.0 || ^17.0.0 || ^18.0.0
+    dependencies:
+      '@react-spring/shared': 9.6.1(react@17.0.2)
+      '@react-spring/types': 9.6.1
+      react: 17.0.2
+    dev: false
+
+  /@react-spring/core@9.6.1(react@17.0.2):
+    resolution: {integrity: sha512-3HAAinAyCPessyQNNXe5W0OHzRfa8Yo5P748paPcmMowZ/4sMfaZ2ZB6e5x5khQI8NusOHj8nquoutd6FRY5WQ==}
+    peerDependencies:
+      react: ^16.8.0 || ^17.0.0 || ^18.0.0
+    dependencies:
+      '@react-spring/animated': 9.6.1(react@17.0.2)
+      '@react-spring/rafz': 9.6.1
+      '@react-spring/shared': 9.6.1(react@17.0.2)
+      '@react-spring/types': 9.6.1
+      react: 17.0.2
+    dev: false
+
+  /@react-spring/rafz@9.6.1:
+    resolution: {integrity: sha512-v6qbgNRpztJFFfSE3e2W1Uz+g8KnIBs6SmzCzcVVF61GdGfGOuBrbjIcp+nUz301awVmREKi4eMQb2Ab2gGgyQ==}
+    dev: false
+
+  /@react-spring/shared@9.6.1(react@17.0.2):
+    resolution: {integrity: sha512-PBFBXabxFEuF8enNLkVqMC9h5uLRBo6GQhRMQT/nRTnemVENimgRd+0ZT4yFnAQ0AxWNiJfX3qux+bW2LbG6Bw==}
+    peerDependencies:
+      react: ^16.8.0 || ^17.0.0 || ^18.0.0
+    dependencies:
+      '@react-spring/rafz': 9.6.1
+      '@react-spring/types': 9.6.1
+      react: 17.0.2
+    dev: false
+
+  /@react-spring/types@9.6.1:
+    resolution: {integrity: sha512-POu8Mk0hIU3lRXB3bGIGe4VHIwwDsQyoD1F394OK7STTiX9w4dG3cTLljjYswkQN+hDSHRrj4O36kuVa7KPU8Q==}
+    dev: false
+
+  /@react-spring/web@9.6.1(react-dom@17.0.2)(react@17.0.2):
+    resolution: {integrity: sha512-X2zR6q2Z+FjsWfGAmAXlQaoUHbPmfuCaXpuM6TcwXPpLE1ZD4A1eys/wpXboFQmDkjnrlTmKvpVna1MjWpZ5Hw==}
+    peerDependencies:
+      react: ^16.8.0 || ^17.0.0 || ^18.0.0
+      react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
+    dependencies:
+      '@react-spring/animated': 9.6.1(react@17.0.2)
+      '@react-spring/core': 9.6.1(react@17.0.2)
+      '@react-spring/shared': 9.6.1(react@17.0.2)
+      '@react-spring/types': 9.6.1
+      react: 17.0.2
+      react-dom: 17.0.2(react@17.0.2)
+    dev: false
+
   /@rollup/pluginutils@4.2.1:
     resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==}
     engines: {node: '>= 8.0.0'}
@@ -5138,6 +5199,19 @@ packages:
       - rollup
     dev: true
 
+  /@use-gesture/core@10.3.0:
+    resolution: {integrity: sha512-rh+6MND31zfHcy9VU3dOZCqGY511lvGcfyJenN4cWZe0u1BH6brBpBddLVXhF2r4BMqWbvxfsbL7D287thJU2A==}
+    dev: false
+
+  /@use-gesture/react@10.3.0(react@17.0.2):
+    resolution: {integrity: sha512-3zc+Ve99z4usVP6l9knYVbVnZgfqhKah7sIG+PS2w+vpig2v2OLct05vs+ZXMzwxdNCMka8B+8WlOo0z6Pn6DA==}
+    peerDependencies:
+      react: '>= 16.8.0'
+    dependencies:
+      '@use-gesture/core': 10.3.0
+      react: 17.0.2
+    dev: false
+
   /@vant/icons@1.8.0:
     resolution: {integrity: sha512-sKfEUo2/CkQFuERxvkuF6mGQZDKu3IQdj5rV9Fm0weJXtchDSSQ+zt8qPCNUEhh9Y8shy5PzxbvAfOOkCwlCXg==}
     dev: false
@@ -5593,7 +5667,7 @@ packages:
       '@vue/cli-service': ^3.0.0 || ^4.0.0 || ^5.0.0-0
       eslint: '>=7.5.0'
     dependencies:
-      '@vue/cli-service': 5.0.1(@babel/core@7.22.9)(@vue/compiler-sfc@3.4.21)(sass-loader@12.6.0)(vue-template-compiler@2.7.14)(vue@2.7.14)
+      '@vue/cli-service': 5.0.1(@babel/core@7.22.9)(@vue/compiler-sfc@3.4.21)(lodash@4.17.21)(sass-loader@12.0.0)(vue-template-compiler@2.6.14)(vue@2.7.16)
       '@vue/cli-shared-utils': 5.0.8
       eslint: 7.32.0
       eslint-webpack-plugin: 3.2.0(eslint@7.32.0)(webpack@5.88.2)
@@ -5613,7 +5687,7 @@ packages:
     peerDependencies:
       '@vue/cli-service': ^3.0.0 || ^4.0.0 || ^5.0.0-0
     dependencies:
-      '@vue/cli-service': 5.0.1(@babel/core@7.22.9)(@vue/compiler-sfc@3.4.21)(lodash@4.17.21)(sass-loader@12.0.0)(vue-template-compiler@2.6.14)(vue@2.7.14)
+      '@vue/cli-service': 5.0.1(@babel/core@7.22.9)(@vue/compiler-sfc@3.4.21)(lodash@4.17.21)(sass-loader@12.0.0)(vue-template-compiler@2.6.14)(vue@2.7.16)
       '@vue/cli-shared-utils': 5.0.8
     transitivePeerDependencies:
       - encoding
@@ -5624,7 +5698,7 @@ packages:
     peerDependencies:
       '@vue/cli-service': ^3.0.0 || ^4.0.0 || ^5.0.0-0
     dependencies:
-      '@vue/cli-service': 5.0.1(@babel/core@7.22.9)(@vue/compiler-sfc@3.4.21)(sass-loader@12.6.0)(vue-template-compiler@2.7.14)(vue@2.7.14)
+      '@vue/cli-service': 5.0.1(@babel/core@7.22.9)(@vue/compiler-sfc@3.4.21)(lodash@4.17.21)(sass-loader@12.0.0)(vue-template-compiler@2.6.14)(vue@2.7.16)
       '@vue/cli-shared-utils': 5.0.8
     transitivePeerDependencies:
       - encoding
@@ -5635,7 +5709,7 @@ packages:
     peerDependencies:
       '@vue/cli-service': ^3.0.0 || ^4.0.0 || ^5.0.0-0
     dependencies:
-      '@vue/cli-service': 5.0.1(@babel/core@7.22.9)(@vue/compiler-sfc@3.4.21)(lodash@4.17.21)(sass-loader@12.0.0)(vue-template-compiler@2.6.14)(vue@2.7.14)
+      '@vue/cli-service': 5.0.1(@babel/core@7.22.9)(@vue/compiler-sfc@3.4.21)(lodash@4.17.21)(sass-loader@12.0.0)(vue-template-compiler@2.6.14)(vue@2.7.16)
     dev: true
 
   /@vue/cli-plugin-vuex@5.0.8(@vue/cli-service@5.0.1):
@@ -5643,7 +5717,7 @@ packages:
     peerDependencies:
       '@vue/cli-service': ^3.0.0 || ^4.0.0 || ^5.0.0-0
     dependencies:
-      '@vue/cli-service': 5.0.1(@babel/core@7.22.9)(@vue/compiler-sfc@3.4.21)(sass-loader@12.6.0)(vue-template-compiler@2.7.14)(vue@2.7.14)
+      '@vue/cli-service': 5.0.1(@babel/core@7.22.9)(@vue/compiler-sfc@3.4.21)(lodash@4.17.21)(sass-loader@12.0.0)(vue-template-compiler@2.6.14)(vue@2.7.16)
     dev: true
 
   /@vue/cli-service@5.0.1(@babel/core@7.22.9)(@vue/compiler-sfc@3.4.21)(lodash@4.17.21)(sass-loader@12.0.0)(vue-template-compiler@2.6.14)(vue@2.7.14):
@@ -6857,6 +6931,24 @@ packages:
       - supports-color
     dev: true
 
+  /ahooks@3.8.1(react@17.0.2):
+    resolution: {integrity: sha512-JoP9+/RWO7MnI/uSKdvQ8WB10Y3oo1PjLv+4Sv4Vpm19Z86VUMdXh+RhWvMGxZZs06sq2p0xVtFk8Oh5ZObsoA==}
+    engines: {node: '>=8.0.0'}
+    peerDependencies:
+      react: ^16.8.0 || ^17.0.0 || ^18.0.0
+    dependencies:
+      '@babel/runtime': 7.22.6
+      dayjs: 1.11.8
+      intersection-observer: 0.12.2
+      js-cookie: 3.0.5
+      lodash: 4.17.21
+      react: 17.0.2
+      react-fast-compare: 3.2.2
+      resize-observer-polyfill: 1.5.1
+      screenfull: 5.2.0
+      tslib: 2.7.0
+    dev: false
+
   /ajv-formats@2.1.1(ajv@8.12.0):
     resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==}
     peerDependencies:
@@ -6921,6 +7013,22 @@ packages:
       '@algolia/transporter': 4.22.1
     dev: true
 
+  /aliyun_numberauthsdk_web@2.1.9:
+    resolution: {integrity: sha512-JHgX7y62B4G8VdmupwwmUZoP6WZvf1JpGpAtnWKw6UVpnL2vvbjx0av15FJur2i2q4BSxM6lMxFeu5U8xiFxkw==}
+    dependencies:
+      antd-mobile: 5.38.1(react-dom@17.0.2)(react@17.0.2)
+      axios: 0.19.2
+      crypto-js: 3.3.0
+      js-md5: 0.7.3
+      jsencrypt: 3.3.2
+      react: 17.0.2
+      react-dom: 17.0.2(react@17.0.2)
+      ua-parser-js: 0.7.39
+      uuid: 8.3.2
+    transitivePeerDependencies:
+      - supports-color
+    dev: false
+
   /ansi-colors@4.1.3:
     resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==}
     engines: {node: '>=6'}
@@ -6998,6 +7106,44 @@ packages:
     engines: {node: '>=12'}
     dev: true
 
+  /antd-mobile-icons@0.3.0:
+    resolution: {integrity: sha512-rqINQpJWZWrva9moCd1Ye695MZYWmqLPE+bY8d2xLRy7iSQwPsinCdZYjpUPp2zL/LnKYSyXxP2ut2A+DC+whQ==}
+    dev: false
+
+  /antd-mobile-v5-count@1.0.1:
+    resolution: {integrity: sha512-YGsiEDCPUDz3SzfXi6gLZn/HpeSMW+jgPc4qiYUr1fSopg3hkUie2TnooJdExgfiETHefH3Ggs58He0OVfegLA==}
+    dev: false
+
+  /antd-mobile@5.38.1(react-dom@17.0.2)(react@17.0.2):
+    resolution: {integrity: sha512-1szLVnmu6hz4iJfKFAsCImJkiLe8FV9IoFChXpnLRBz41wrSfjh7FwPuo0AfFfEuTmV2GYS6BNixiuGscHj+iQ==}
+    peerDependencies:
+      react: ^16.8.0 || ^17.0.0 || ^18.0.0
+      react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
+    dependencies:
+      '@floating-ui/dom': 1.6.4
+      '@rc-component/mini-decimal': 1.1.0
+      '@react-spring/web': 9.6.1(react-dom@17.0.2)(react@17.0.2)
+      '@use-gesture/react': 10.3.0(react@17.0.2)
+      ahooks: 3.8.1(react@17.0.2)
+      antd-mobile-icons: 0.3.0
+      antd-mobile-v5-count: 1.0.1
+      classnames: 2.5.1
+      dayjs: 1.11.8
+      deepmerge: 4.3.1
+      nano-memoize: 3.0.16
+      rc-field-form: 1.44.0(react-dom@17.0.2)(react@17.0.2)
+      rc-segmented: 2.4.1(react-dom@17.0.2)(react@17.0.2)
+      rc-util: 5.43.0(react-dom@17.0.2)(react@17.0.2)
+      react: 17.0.2
+      react-dom: 17.0.2(react@17.0.2)
+      react-fast-compare: 3.2.2
+      react-is: 18.2.0
+      runes2: 1.1.4
+      staged-components: 1.1.3(react@17.0.2)
+      tslib: 2.7.0
+      use-sync-external-store: 1.2.2(react@17.0.2)
+    dev: false
+
   /any-promise@1.3.0:
     resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}
     dev: true
@@ -7140,6 +7286,10 @@ packages:
       babel-runtime: 6.26.0
     dev: false
 
+  /async-validator@4.2.5:
+    resolution: {integrity: sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==}
+    dev: false
+
   /async@2.6.4:
     resolution: {integrity: sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==}
     dependencies:
@@ -7195,10 +7345,19 @@ packages:
     engines: {node: '>= 0.4'}
     dev: true
 
+  /axios@0.19.2:
+    resolution: {integrity: sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==}
+    deprecated: Critical security vulnerability fixed in v0.21.1. For more information, see https://github.com/axios/axios/pull/3410
+    dependencies:
+      follow-redirects: 1.5.10
+    transitivePeerDependencies:
+      - supports-color
+    dev: false
+
   /axios@0.27.2:
     resolution: {integrity: sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==}
     dependencies:
-      follow-redirects: 1.15.2(debug@4.3.4)
+      follow-redirects: 1.15.2
       form-data: 4.0.0
     transitivePeerDependencies:
       - debug
@@ -7206,7 +7365,7 @@ packages:
   /axios@1.4.0:
     resolution: {integrity: sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==}
     dependencies:
-      follow-redirects: 1.15.2(debug@4.3.4)
+      follow-redirects: 1.15.2
       form-data: 4.0.0
       proxy-from-env: 1.1.0
     transitivePeerDependencies:
@@ -7216,7 +7375,7 @@ packages:
   /axios@1.6.7:
     resolution: {integrity: sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==}
     dependencies:
-      follow-redirects: 1.15.5
+      follow-redirects: 1.15.5(debug@4.3.4)
       form-data: 4.0.0
       proxy-from-env: 1.1.0
     transitivePeerDependencies:
@@ -7721,6 +7880,10 @@ packages:
       validator: 13.12.0
     dev: true
 
+  /classnames@2.5.1:
+    resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==}
+    dev: false
+
   /clean-css@5.3.2:
     resolution: {integrity: sha512-JVJbM+f3d3Q704rF4bqQ5UUyTtuJ0JRKNbTKVEeujCCBoMdkEi+V+e8oktO9qGQNSvHrFTM6JZRXrUvGR1czww==}
     engines: {node: '>= 10.0'}
@@ -8237,6 +8400,10 @@ packages:
     resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==}
     dev: true
 
+  /crypto-js@3.3.0:
+    resolution: {integrity: sha512-DIT51nX0dCfKltpRiXV+/TVZq+Qq2NgF4644+K7Ttnla7zEzqc+kjJyiB96BHNyUTBxyjzRcZYpUdZa+QAqi6Q==}
+    dev: false
+
   /css-declaration-sorter@6.4.1(postcss@8.4.35):
     resolution: {integrity: sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g==}
     engines: {node: ^10 || ^12 || >=14}
@@ -8446,6 +8613,17 @@ packages:
       ms: 2.0.0
     dev: true
 
+  /debug@3.1.0:
+    resolution: {integrity: sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==}
+    peerDependencies:
+      supports-color: '*'
+    peerDependenciesMeta:
+      supports-color:
+        optional: true
+    dependencies:
+      ms: 2.0.0
+    dev: false
+
   /debug@3.2.7:
     resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
     peerDependencies:
@@ -8503,6 +8681,11 @@ packages:
     resolution: {integrity: sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ==}
     engines: {node: '>=0.10.0'}
 
+  /deepmerge@4.3.1:
+    resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
+    engines: {node: '>=0.10.0'}
+    dev: false
+
   /default-gateway@6.0.3:
     resolution: {integrity: sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==}
     engines: {node: '>= 10'}
@@ -9941,7 +10124,7 @@ packages:
       natural-compare: 1.4.0
       nth-check: 2.1.1
       postcss-selector-parser: 6.0.13
-      semver: 7.6.3
+      semver: 7.5.4
       vue-eslint-parser: 9.3.1(eslint@7.32.0)
       xml-name-validator: 4.0.0
     transitivePeerDependencies:
@@ -10699,7 +10882,7 @@ packages:
       tabbable: 6.2.0
     dev: true
 
-  /follow-redirects@1.15.2(debug@4.3.4):
+  /follow-redirects@1.15.2:
     resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==}
     engines: {node: '>=4.0'}
     peerDependencies:
@@ -10707,10 +10890,8 @@ packages:
     peerDependenciesMeta:
       debug:
         optional: true
-    dependencies:
-      debug: 4.3.4
 
-  /follow-redirects@1.15.5:
+  /follow-redirects@1.15.5(debug@4.3.4):
     resolution: {integrity: sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==}
     engines: {node: '>=4.0'}
     peerDependencies:
@@ -10718,6 +10899,17 @@ packages:
     peerDependenciesMeta:
       debug:
         optional: true
+    dependencies:
+      debug: 4.3.4
+
+  /follow-redirects@1.5.10:
+    resolution: {integrity: sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==}
+    engines: {node: '>=4.0'}
+    dependencies:
+      debug: 3.1.0
+    transitivePeerDependencies:
+      - supports-color
+    dev: false
 
   /for-each@0.3.3:
     resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
@@ -11221,7 +11413,7 @@ packages:
     engines: {node: '>=8.0.0'}
     dependencies:
       eventemitter3: 4.0.7
-      follow-redirects: 1.15.2(debug@4.3.4)
+      follow-redirects: 1.15.5(debug@4.3.4)
       requires-port: 1.0.0
     transitivePeerDependencies:
       - debug
@@ -11375,6 +11567,10 @@ packages:
     engines: {node: '>= 0.10'}
     dev: true
 
+  /intersection-observer@0.12.2:
+    resolution: {integrity: sha512-7m1vEcPCxXYI8HqnL8CKI6siDyD+eIWSwgB3DZA+ZTogxk9I4CDnj4wilt9x/+/QbHI4YG5YZNmC6458/e9Ktg==}
+    dev: false
+
   /inversify@6.0.1:
     resolution: {integrity: sha512-B3ex30927698TJENHR++8FfEaJGqoWOgI6ZY5Ht/nLUsFCwHn6akbwtnUAPCgUepAnTpe2qHxhDNjoKLyz6rgQ==}
     dev: true
@@ -11816,6 +12012,15 @@ packages:
     engines: {node: '>=12'}
     dev: false
 
+  /js-cookie@3.0.5:
+    resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==}
+    engines: {node: '>=14'}
+    dev: false
+
+  /js-md5@0.7.3:
+    resolution: {integrity: sha512-ZC41vPSTLKGwIRjqDh8DfXoCrdQIyBgspJVPXHBGu4nZlAEvG3nf+jO9avM9RmLiGakg7vz974ms99nEV0tmTQ==}
+    dev: false
+
   /js-message@1.0.7:
     resolution: {integrity: sha512-efJLHhLjIyKRewNS9EGZ4UpI8NguuL6fKkhRxVuMmrGV2xN/0APGdQYwLFky5w9naebSZ0OwAGp0G6/2Cg90rA==}
     engines: {node: '>=0.6.0'}
@@ -11831,7 +12036,6 @@ packages:
 
   /js-tokens@4.0.0:
     resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
-    dev: true
 
   /js-yaml@3.14.1:
     resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==}
@@ -11890,6 +12094,10 @@ packages:
       - utf-8-validate
     dev: true
 
+  /jsencrypt@3.3.2:
+    resolution: {integrity: sha512-arQR1R1ESGdAxY7ZheWr12wCaF2yF47v5qpB76TtV64H1pyGudk9Hvw8Y9tb/FiTIaaTRUyaSnm5T/Y53Ghm/A==}
+    dev: false
+
   /jsesc@0.5.0:
     resolution: {integrity: sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==}
     hasBin: true
@@ -12199,6 +12407,13 @@ packages:
     resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==}
     dev: true
 
+  /loose-envify@1.4.0:
+    resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
+    hasBin: true
+    dependencies:
+      js-tokens: 4.0.0
+    dev: false
+
   /lottie-web@5.12.0:
     resolution: {integrity: sha512-tt2oiv0EmXC8J/RF877dVCo93vZBBnww+SO6dldREgHD8EsP97jQ42JRryIRfY+6aVESQsHYNEAYgH25cBFy7A==}
     dev: false
@@ -12212,7 +12427,7 @@ packages:
   /lower-case@2.0.2:
     resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==}
     dependencies:
-      tslib: 2.6.0
+      tslib: 2.7.0
     dev: true
 
   /lru-cache@10.4.3:
@@ -12838,7 +13053,6 @@ packages:
 
   /ms@2.0.0:
     resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
-    dev: true
 
   /ms@2.1.2:
     resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
@@ -12879,6 +13093,10 @@ packages:
       thenify-all: 1.6.0
     dev: true
 
+  /nano-memoize@3.0.16:
+    resolution: {integrity: sha512-JyK96AKVGAwVeMj3MoMhaSXaUNqgMbCRSQB3trUV8tYZfWEzqUBKdK1qJpfuNXgKeHOx1jv/IEYTM659ly7zUA==}
+    dev: false
+
   /nanoid@3.3.7:
     resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==}
     engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
@@ -13026,7 +13244,6 @@ packages:
   /object-assign@4.1.1:
     resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
     engines: {node: '>=0.10.0'}
-    dev: true
 
   /object-inspect@1.12.3:
     resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==}
@@ -14051,9 +14268,84 @@ packages:
       unpipe: 1.0.0
     dev: true
 
+  /rc-field-form@1.44.0(react-dom@17.0.2)(react@17.0.2):
+    resolution: {integrity: sha512-el7w87fyDUsca63Y/s8qJcq9kNkf/J5h+iTdqG5WsSHLH0e6Usl7QuYSmSVzJMgtp40mOVZIY/W/QP9zwrp1FA==}
+    engines: {node: '>=8.x'}
+    peerDependencies:
+      react: '>=16.9.0'
+      react-dom: '>=16.9.0'
+    dependencies:
+      '@babel/runtime': 7.22.6
+      async-validator: 4.2.5
+      rc-util: 5.43.0(react-dom@17.0.2)(react@17.0.2)
+      react: 17.0.2
+      react-dom: 17.0.2(react@17.0.2)
+    dev: false
+
+  /rc-motion@2.9.3(react-dom@17.0.2)(react@17.0.2):
+    resolution: {integrity: sha512-rkW47ABVkic7WEB0EKJqzySpvDqwl60/tdkY7hWP7dYnh5pm0SzJpo54oW3TDUGXV5wfxXFmMkxrzRRbotQ0+w==}
+    peerDependencies:
+      react: '>=16.9.0'
+      react-dom: '>=16.9.0'
+    dependencies:
+      '@babel/runtime': 7.22.6
+      classnames: 2.5.1
+      rc-util: 5.43.0(react-dom@17.0.2)(react@17.0.2)
+      react: 17.0.2
+      react-dom: 17.0.2(react@17.0.2)
+    dev: false
+
+  /rc-segmented@2.4.1(react-dom@17.0.2)(react@17.0.2):
+    resolution: {integrity: sha512-KUi+JJFdKnumV9iXlm+BJ00O4NdVBp2TEexLCk6bK1x/RH83TvYKQMzIz/7m3UTRPD08RM/8VG/JNjWgWbd4cw==}
+    peerDependencies:
+      react: '>=16.0.0'
+      react-dom: '>=16.0.0'
+    dependencies:
+      '@babel/runtime': 7.22.6
+      classnames: 2.5.1
+      rc-motion: 2.9.3(react-dom@17.0.2)(react@17.0.2)
+      rc-util: 5.43.0(react-dom@17.0.2)(react@17.0.2)
+      react: 17.0.2
+      react-dom: 17.0.2(react@17.0.2)
+    dev: false
+
+  /rc-util@5.43.0(react-dom@17.0.2)(react@17.0.2):
+    resolution: {integrity: sha512-AzC7KKOXFqAdIBqdGWepL9Xn7cm3vnAmjlHqUnoQaTMZYhM4VlXGLkkHHxj/BZ7Td0+SOPKB4RGPboBVKT9htw==}
+    peerDependencies:
+      react: '>=16.9.0'
+      react-dom: '>=16.9.0'
+    dependencies:
+      '@babel/runtime': 7.22.6
+      react: 17.0.2
+      react-dom: 17.0.2(react@17.0.2)
+      react-is: 18.2.0
+    dev: false
+
+  /react-dom@17.0.2(react@17.0.2):
+    resolution: {integrity: sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==}
+    peerDependencies:
+      react: 17.0.2
+    dependencies:
+      loose-envify: 1.4.0
+      object-assign: 4.1.1
+      react: 17.0.2
+      scheduler: 0.20.2
+    dev: false
+
+  /react-fast-compare@3.2.2:
+    resolution: {integrity: sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==}
+    dev: false
+
   /react-is@18.2.0:
     resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==}
-    dev: true
+
+  /react@17.0.2:
+    resolution: {integrity: sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==}
+    engines: {node: '>=0.10.0'}
+    dependencies:
+      loose-envify: 1.4.0
+      object-assign: 4.1.1
+    dev: false
 
   /read-pkg-up@7.0.1:
     resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==}
@@ -14486,6 +14778,10 @@ packages:
     dependencies:
       queue-microtask: 1.2.3
 
+  /runes2@1.1.4:
+    resolution: {integrity: sha512-LNPnEDPOOU4ehF71m5JoQyzT2yxwD6ZreFJ7MxZUAoMKNMY1XrAo60H1CUoX5ncSm0rIuKlqn9JZNRrRkNou2g==}
+    dev: false
+
   /rxjs@7.8.1:
     resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==}
     dependencies:
@@ -14608,6 +14904,13 @@ packages:
       xmlchars: 2.2.0
     dev: true
 
+  /scheduler@0.20.2:
+    resolution: {integrity: sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==}
+    dependencies:
+      loose-envify: 1.4.0
+      object-assign: 4.1.1
+    dev: false
+
   /schema-utils@2.7.1:
     resolution: {integrity: sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==}
     engines: {node: '>= 8.9.0'}
@@ -14636,6 +14939,11 @@ packages:
       ajv-keywords: 5.1.0(ajv@8.12.0)
     dev: true
 
+  /screenfull@5.2.0:
+    resolution: {integrity: sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA==}
+    engines: {node: '>=0.10.0'}
+    dev: false
+
   /scslre@0.3.0:
     resolution: {integrity: sha512-3A6sD0WYP7+QrjbfNA2FN3FsOaGGFoekCVgTyypy53gPxhbkCIjtO6YWgdrfM+n/8sI8JeXZOIxsHjMTNxQ4nQ==}
     engines: {node: ^14.0.0 || >=16.0.0}
@@ -15045,6 +15353,14 @@ packages:
     resolution: {integrity: sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==}
     dev: true
 
+  /staged-components@1.1.3(react@17.0.2):
+    resolution: {integrity: sha512-9EIswzDqjwlEu+ymkV09TTlJfzSbKgEnNteUnZSTxkpMgr5Wx2CzzA9WcMFWBNCldqVPsHVnRGGrApduq2Se5A==}
+    peerDependencies:
+      react: ^16.8.0 || ^17.0.0 || ^18.0.0
+    dependencies:
+      react: 17.0.2
+    dev: false
+
   /statuses@1.5.0:
     resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==}
     engines: {node: '>= 0.6'}
@@ -15546,7 +15862,6 @@ packages:
 
   /tslib@2.7.0:
     resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==}
-    dev: true
 
   /tsutils@3.21.0(typescript@5.2.2):
     resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
@@ -15657,6 +15972,11 @@ packages:
     hasBin: true
     dev: true
 
+  /ua-parser-js@0.7.39:
+    resolution: {integrity: sha512-IZ6acm6RhQHNibSt7+c09hhvsKy9WUr4DVbeq9U8o71qxyYtJpQeDxQnMrVqnIFMLcQjHO0I9wgfO2vIahht4w==}
+    hasBin: true
+    dev: false
+
   /uc.micro@1.0.6:
     resolution: {integrity: sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==}
     dev: true
@@ -15990,13 +16310,13 @@ packages:
   /upper-case-first@2.0.2:
     resolution: {integrity: sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==}
     dependencies:
-      tslib: 2.6.0
+      tslib: 2.7.0
     dev: true
 
   /upper-case@2.0.2:
     resolution: {integrity: sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg==}
     dependencies:
-      tslib: 2.6.0
+      tslib: 2.7.0
     dev: true
 
   /uri-js@4.4.1:
@@ -16011,6 +16331,14 @@ packages:
       requires-port: 1.0.0
     dev: true
 
+  /use-sync-external-store@1.2.2(react@17.0.2):
+    resolution: {integrity: sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==}
+    peerDependencies:
+      react: ^16.8.0 || ^17.0.0 || ^18.0.0
+    dependencies:
+      react: 17.0.2
+    dev: false
+
   /util-deprecate@1.0.2:
     resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
     dev: true
@@ -16047,7 +16375,6 @@ packages:
   /uuid@8.3.2:
     resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==}
     hasBin: true
-    dev: true
 
   /v-charts@1.19.0(echarts@4.8.0)(vue@2.7.16)(zrender@4.3.2):
     resolution: {integrity: sha512-vm2HBUmxAsXK0ivwce9LytcpqrItDA5JSPLYVxZXtiuoyhcn80XX1/3dPJd/1GqG1OYv3jfBo1s9ra4q8GowqA==}
@@ -16205,7 +16532,7 @@ packages:
       '@types/eslint': 8.44.1
       eslint: 8.37.0
       rollup: 2.79.1
-      vite: 4.5.3(sass@1.71.1)(terser@5.19.2)
+      vite: 4.5.3(less@4.1.3)(sass@1.63.2)(terser@5.19.2)
     dev: true
 
   /vite-plugin-externals@0.6.2(vite@4.5.3):