Przeglądaj źródła

Merge branch 'main' into feature/v1.0.78

yuelujie 8 miesięcy temu
rodzic
commit
219399c243
41 zmienionych plików z 3967 dodań i 724 usunięć
  1. 8 0
      apps/bigmember_pc/src/api/modules/public.js
  2. 9 0
      apps/bigmember_pc/src/api/modules/subscribe.js
  3. 13 2
      apps/bigmember_pc/src/components/selector-cascader/AreaCityCountryCascader.vue
  4. 124 0
      apps/bigmember_pc/src/utils/format/search-bid-filter.js
  5. 352 0
      apps/bigmember_pc/src/views/search/bidding/components/extract-sub-dialog.vue
  6. 23 0
      apps/bigmember_pc/src/views/search/bidding/index.vue
  7. 33 2
      apps/bigmember_pc/src/views/search/bidding/model/base.js
  8. 112 0
      apps/bigmember_pc/src/views/search/bidding/model/modules/data-subscribe.js
  9. 6 6
      apps/bigmember_pc/src/views/search/sun/index.vue
  10. 230 188
      apps/bigmember_pc/src/views/search/sun/model/base.js
  11. 105 49
      apps/mobile/index.html
  12. 2 1
      apps/mobile/package.json
  13. 19 4
      apps/mobile/src/api/modules/pay.js
  14. 38 0
      apps/mobile/src/api/modules/public.js
  15. 11 1
      apps/mobile/src/api/modules/subscribe.js
  16. BIN
      apps/mobile/src/assets/image/course-page/1.jpg
  17. BIN
      apps/mobile/src/assets/image/course-page/2.jpg
  18. BIN
      apps/mobile/src/assets/image/course-page/3.jpg
  19. BIN
      apps/mobile/src/assets/image/course-page/4.jpg
  20. BIN
      apps/mobile/src/assets/image/course-page/video-1.mp4
  21. BIN
      apps/mobile/src/assets/image/course-page/video-2.mp4
  22. BIN
      apps/mobile/src/assets/image/course-page/video-3.mp4
  23. BIN
      apps/mobile/src/assets/image/icon/customer-bid.png
  24. 233 0
      apps/mobile/src/assets/style/modules/fast-login.scss
  25. 6 3
      apps/mobile/src/components/common/DropdownLayout.vue
  26. 60 0
      apps/mobile/src/components/customerBid/index.vue
  27. 335 0
      apps/mobile/src/components/one-click-binding/index.vue
  28. 702 60
      apps/mobile/src/components/search/bidding/oneKeySubscribeDialog.vue
  29. 0 3
      apps/mobile/src/components/search/sun/filters.vue
  30. 8 0
      apps/mobile/src/router/modules/course.js
  31. 31 15
      apps/mobile/src/store/modules/article.js
  32. 60 0
      apps/mobile/src/utils/callFn/appFn.js
  33. 18 11
      apps/mobile/src/utils/mixins/modules/app-wx-share.js
  34. 377 0
      apps/mobile/src/utils/mixins/modules/fast-bind.js
  35. 75 14
      apps/mobile/src/views/article/content.vue
  36. 71 0
      apps/mobile/src/views/coursePage/Index.vue
  37. 263 146
      apps/mobile/src/views/search/result/bidding/index.vue
  38. 40 23
      apps/mobile/src/views/search/result/sun/index.vue
  39. 91 45
      apps/mobile/src/views/tabbar/Home.vue
  40. 158 124
      apps/mobile/src/views/tabbar/Subscribe.vue
  41. 354 27
      pnpm-lock.yaml

+ 8 - 0
apps/bigmember_pc/src/api/modules/public.js

@@ -165,6 +165,14 @@ export function getZhiMaFilterData() {
   })
   })
 }
 }
 
 
+// 是否订阅(标讯搜索)
+export function getIsSubscribe() {
+  return request({
+    url: '/publicapply/subscribe/isSub',
+    method: 'post'
+  })
+}
+
 // 功能引导(阳光直采)
 // 功能引导(阳光直采)
 export function showFunctionGuide(data) {
 export function showFunctionGuide(data) {
   data = qs.stringify(data)
   data = qs.stringify(data)

+ 9 - 0
apps/bigmember_pc/src/api/modules/subscribe.js

@@ -260,3 +260,12 @@ export function getRecommenListData(data) {
     data: data
     data: data
   })
   })
 }
 }
+
+// 订阅设置修改(支持超级订阅、大会员、免费用户)
+export function updateSubscribe(vType, data) {
+  return request({
+    url: `/jyapi/jybx/subscribe/${vType}/update`,
+    method: 'post',
+    data: data
+  })
+}

+ 13 - 2
apps/bigmember_pc/src/components/selector-cascader/AreaCityCountryCascader.vue

@@ -233,9 +233,15 @@ export default {
   computed: {
   computed: {
     chooseText() {
     chooseText() {
       // select框内显示详细选择结果
       // select框内显示详细选择结果
+      const { allChecked } = this.getState()
       if (this.showSelected) {
       if (this.showSelected) {
         const tags = this.tags.map((v) => v.name)
         const tags = this.tags.map((v) => v.name)
-        const selectVal = tags.length ? tags.join('、') : '全国'
+        let selectVal = ''
+        if (tags.length > 0) {
+          selectVal = tags.join('、')
+        } else {
+          selectVal = allChecked ? '全国' : ''
+        }
         return !this.initMap
         return !this.initMap
           ? `<span class="default-text">${this.prefixText}</span>`
           ? `<span class="default-text">${this.prefixText}</span>`
           : `<span class="highlight-text">${selectVal}</span>`
           : `<span class="highlight-text">${selectVal}</span>`
@@ -561,7 +567,12 @@ export default {
       })
       })
       const regionMap = this.getCitiesToMap(formatData)
       const regionMap = this.getCitiesToMap(formatData)
       const { area, district } = this.formatProvinceAndCities(regionMap)
       const { area, district } = this.formatProvinceAndCities(regionMap)
-      const resultText = this.formatRegionToString(regionMap)
+      let resultText = ''
+      if (Object.keys(regionMap).length === 0 && !allCountryChecked) {
+        resultText = ''
+      } else {
+        resultText = this.formatRegionToString(regionMap)
+      }
       return {
       return {
         allChecked: allCountryChecked, // 全国是否选中
         allChecked: allCountryChecked, // 全国是否选中
         regionMap, // 选中的结果(省市县三级数据结构) => 应用场景:setState、数据转换
         regionMap, // 选中的结果(省市县三级数据结构) => 应用场景:setState、数据转换

+ 124 - 0
apps/bigmember_pc/src/utils/format/search-bid-filter.js

@@ -11,6 +11,34 @@ import {
   searchModeList,
   searchModeList,
   wordsModeList
   wordsModeList
 } from '@/assets/js/selector'
 } from '@/assets/js/selector'
+import { provinceListMapExp } from '@/assets/js/selector.js'
+import chinaMapJSON from '@/assets/js/china_area.js'
+
+
+function addSortNameToMap() {
+  let list = []
+  for (const key in provinceListMapExp) {
+    if (key === '#') {
+      continue
+    } else {
+      list = list.concat(provinceListMapExp[key])
+    }
+  }
+
+  chinaMapJSON.forEach((p) => {
+    const pName = p.name
+    for (let i = 0; i < list.length; i++) {
+      if (pName.includes(list[i])) {
+        p.shortName = list[i]
+        break
+      }
+    }
+    if (!p.shortName) {
+      p.shortName = ''
+    }
+  })
+}
+addSortNameToMap()
 
 
 /**
 /**
  * 保存筛选条件的接口,中的数据转前端标准数据
  * 保存筛选条件的接口,中的数据转前端标准数据
@@ -509,6 +537,102 @@ export class FilterHistoryAjaxModel2ViewModel {
       return '全部'
       return '全部'
     }
     }
   }
   }
+  /**
+   * 三级地区整理
+   * @param String area
+   * @param String city
+   * @param String district
+   *
+   * @returns Object
+   *
+   * 参数area示例:'北京,河南'
+   * 参数city示例:'福州市,邯郸市,石家庄市,秦皇岛市'
+   * 参数district示例:'郑州市_金水区,北京市_朝阳区'
+   */
+  static formatAreaCityToMap(area, city, district, regionMap) {
+    const result = {
+      area: undefined,
+      AreaCityText: undefined
+    }
+    if (regionMap && typeof regionMap === 'object') {
+      const text = this.getAreaCityText(regionMap)
+      result.area = regionMap
+      result.AreaCityText = text ? text.split(',') : []
+      return result
+    }
+    // 兼容老的数据整理
+    let text = ''
+    if (area && city) {
+      text = `${area},${city}`
+    }
+    else {
+      text = area || city
+    }
+    if (district) {
+      text += text ? `,${district}` : `${district}`
+    }
+    let reginArr = []
+    if (text) {
+      reginArr = text.split(',')
+    }
+    // 用area、city\district整理出前端组件通用格式的数据结构
+    const region = {}
+    reginArr.forEach((regItem) => {
+      chinaMapJSON.forEach((p) => {
+        const pName = p.shortName
+        if (pName.includes(regItem)) {
+          // 省级区域
+          region[regItem] = {}
+        }
+        else {
+          p.city.forEach((c) => {
+            const cName = c.name
+            // 市级区域 示例:{ 郑州市:[] }
+            if (cName.includes(regItem)) {
+              if (!region[pName]) {
+                region[pName] = {}
+              }
+              region[pName][regItem] = []
+            }
+            else {
+              // 区县 示例:郑州市:['金水区']
+              const districtArr = []
+              if (c.area) {
+                const district = regItem.includes('_')
+                  ? regItem.split('_')[1]
+                  : regItem
+                c.area.forEach((dis) => {
+                  if (dis.includes(district)) {
+                    districtArr.push(district)
+                  }
+                })
+              }
+              if (districtArr.length > 0) {
+                if (!region[pName]) {
+                  region[pName] = {}
+                }
+                const city = regItem.includes('_')
+                  ? regItem.split('_')[0]
+                  : regItem
+                if (!region[pName][city]) {
+                  region[pName][city] = []
+                }
+                region[pName][city] = region[pName][city].concat(districtArr)
+              }
+            }
+          })
+        }
+      })
+    })
+    if (Object.keys(region)) {
+      result.area = region
+    }
+    if (reginArr.length) {
+      result.AreaCityText = reginArr
+    }
+
+    return result
+  }
 }
 }
 
 
 /**
 /**

+ 352 - 0
apps/bigmember_pc/src/views/search/bidding/components/extract-sub-dialog.vue

@@ -0,0 +1,352 @@
+<script setup>
+import { computed, reactive, defineExpose, watch } from 'vue'
+// import CustomDialog from '@/components/dialog/Dialog.vue'
+import AreaCityCountryCascader from '@/components/selector-cascader/AreaCityCountryCascader'
+import { showToast } from '@/components/toast'
+
+const props = defineProps({
+  info: {
+    type: Object,
+    required: true,
+    default: () => ({
+      isSubscribe: false,
+      areaCount: 0,
+      keyCount: 0,
+      regionText: '',
+      regionMap: '',
+      keywords: []
+    })
+  },
+  isVip: {
+    type: Boolean,
+    default: false
+  },
+  isFree: {
+    type: Boolean,
+    default: false
+  }
+})
+
+const subscribe = reactive({
+  visible: props.info.isSubscribe,
+  regionText: props.info.regionText,
+  regionMap: props.info.regionMap,
+  area: '',
+  district: ''
+})
+const product = reactive({
+  input: '',
+  tags: props.info.keywords
+})
+const disabled = computed(() => {
+  return !(product.tags.length > 0 || subscribe.regionText)
+})
+
+const dialog = reactive({
+  freeLimit: false,
+  vipLimit: false
+})
+
+watch(() => props.info, (newVal) => {
+  const { isSubscribe, keywords, regionMap } = newVal
+  subscribe.visible = isSubscribe
+  subscribe.regionMap = regionMap || ''
+  product.tags = keywords
+}, {
+  deep: true
+})
+
+// 地区组件回调
+const onAreaCityCountryChange = (val) => {
+  const { resultText, regionMap, area, district } = val
+  console.log(val, regionMap, resultText)
+  subscribe.regionText = resultText
+  subscribe.regionMap = regionMap || ''
+  subscribe.area = area
+  subscribe.district = district
+}
+// 业务标签删除
+const handleClose = (tag) => {
+  product.tags.splice(product.tags.indexOf(tag), 1)
+}
+// 业务标签添加
+const addProduct = () => {
+  if (product.input) {
+    if (product.tags.length >= props.info.keyCount) {
+      return showToast('最多添加' + props.info.keyCount + '个')
+    }
+    if(product.tags.length && product.tags.includes(product.input)) {
+      return showToast('添加重复')
+    }
+    product.tags.push(product.input)
+  }
+  product.input = ''
+}
+// 弹框关闭
+const beforeCloseDialog = () => {
+  subscribe.visible = false
+}
+// 区域超出提示
+const onExceedChange = () => {
+  if (props.isVip) {
+    dialog.areaLimit = true
+  }
+  if (props.isFree) {
+    dialog.freeLimit = true
+  }
+}
+// 订阅提交
+const $emit = defineEmits(['bidding-subscribe'])
+const confirmHandle = () => {
+  const formatKeyword = product.tags.map(item => {
+    return {
+      appendkey: null,
+      key: item.split(/\s+/),
+      matchway: 1,
+      notkey: null,
+    }
+  })
+  const items = [{
+    a_key: formatKeyword
+  }]
+  const params = {
+    area: subscribe.area,
+    district: subscribe.district,
+    items: items
+  }
+  $emit('confirm', params)
+}
+
+defineExpose({
+  beforeCloseDialog
+})
+
+// 超级订阅去升级
+const goUpdateVip = () => {
+  window.open('/swordfish/page_big_pc/free/svip/buy?type=upgrade')
+}
+
+</script>
+
+<template>
+  <div class="extract-subscribe">
+    <el-dialog 
+      title="已帮您提取订阅信息,请确认"
+      customClass="extract-dialog"
+      width="380px"
+      :show-close="true"
+      :visible="subscribe.visible"
+      :close-on-click-modal="false"
+      :close-on-press-escape="false"
+      :before-close="beforeCloseDialog"
+    >
+      <div class="sub-container">
+        <div class="sub-item">
+          <p class="sub-item-label">您能接受哪些地区的业务?</p>
+          <AreaCityCountryCascader
+            class="area-city-country-cascader"
+            showSelected
+            showCount
+            :initMap="subscribe.regionMap"
+            :areaCount="info.areaCount"
+            @change="onAreaCityCountryChange"
+            @exceed="onExceedChange"
+          >
+            <div class="area-slot-header" slot="header"></div>
+          </AreaCityCountryCascader>
+        </div>
+        <div class="sub-item">
+          <p class="sub-item-label">您经营的产品或主营业务是?</p>
+          <div class="sub-item-tags">
+            <el-tag
+              type="info"
+              size="small"
+              :key="tag"
+              v-for="tag in product.tags"
+              closable
+              :disable-transitions="false"
+              @close="handleClose(tag)">
+              {{tag}}
+            </el-tag>
+          </div>
+          <div class="flex flex-items-center">
+            <el-input class="product-input" maxlength="200" v-model="product.input" placeholder="请输入内容" @keyup.enter.native="addProduct"></el-input>
+            <span class="add-btn" :class="{'highlight-text': product}" @click="addProduct">添加</span>
+          </div>
+        </div>
+        <div class="sub-set-tip">
+          前往<span class="highlight-text">订阅设置</span>,设置订阅信息推送渠道和推送时间
+        </div>
+      </div>
+      <div slot="footer">
+        <el-button type="primary" :disabled="disabled" class="action-button" @click="confirmHandle">完成订阅,立即免费查看信息</el-button>
+      </div>
+    </el-dialog>
+    <el-dialog
+      :visible.sync="dialog.vipLimit"
+      title="超出可选省份数量"
+      :show-close="false"
+      class="tip-dialog"
+      width="380px"
+      top="30vh"
+      center
+      v-component-change-mount="{ selector: '.extract-subscribe' }"
+    >
+      <div>
+        可选:<span class="highlight-text">{{ info.areaCount }}个省</span
+        >,如需增加省份数量,您可前往升级超级订阅。
+      </div>
+      <div slot="footer" class="dialog-footer">
+          <el-button type="primary" @click.stop="goUpdateVip">去升级</el-button>
+          <el-button @click="dialog.vipLimit = false">取 消</el-button>
+      </div>
+    </el-dialog>
+    <el-dialog
+      :visible.sync="dialog.freeLimit"
+      title="超出可选省份数量"
+      :show-close="false"
+      class="tip-dialog"
+      width="380px"
+      top="30vh"
+      center
+      v-component-change-mount="{ selector: '.extract-subscribe' }"
+    >
+      <div>您当前仅可订阅1个省,如需增加请前往app购买【省份订阅包】。
+      </div>
+      <div slot="footer" class="dialog-footer">
+        <el-button style="margin-right: 0;" type="primary" @click="dialog.freeLimit = false">我知道了</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+::v-deep {
+  .extract-dialog {
+    width: 380px !important;
+    padding: 32px;
+    border-radius: 8px !important;
+    .el-dialog__header{
+      padding-top: 0;
+    }
+    .el-dialog__body{
+      padding: 0;
+    }
+    .el-dialog__footer{
+      padding: 0;
+      text-align: center;
+    }
+    .sub-item-label{
+      font-size: 14px;
+      line-height: 22px;
+      color: #686868;
+    }
+    .sub-item-tags{
+      margin-top: 2px
+    }
+    .s-header{
+      margin: 0;
+      min-width: unset;
+    }
+    .area-city-country-cascader{
+      margin: 10px 0 12px;
+    }
+    .el-select{
+      width: 316px;
+    }
+    .product-input{
+      margin: 10px 0 12px;
+      .el-input__inner{
+        height: 30px;
+        line-height: 30px;
+      }
+    }
+    .add-btn{
+      padding-left: 12px;
+      flex-shrink: 0;
+      font-size: 14px;
+      line-height: 22px;
+      cursor: pointer;
+      color: #999999;
+      &.highlight-text{
+        color: $color_main;
+      }
+    }
+    .sub-set-tip{
+      padding: 20px 0 8px;
+    }
+    .action-button{
+      width: 316px;
+      height: 36px;
+      font-size: 16px;
+      padding: 0;
+    }
+    .el-tag{
+      margin-top: 8px
+    }
+    .el-tag--small{
+      padding: 0 6px 0 8px;
+      margin-right: 8px;
+      font-size: 14px;
+      &:hover{
+        color: $color_main;
+        background: #fff;
+        border-color: $color_main;
+        .el-icon-close{
+          color: $color_main;
+        }
+      }
+    }
+    .el-icon-close{
+      transform: scale(1);
+      top: 0;
+      right: 0;
+      &:hover{
+        background: unset;
+        color: $color_main;
+      }
+    }
+  }
+  .tip-dialog {
+    .el-button--primary,
+    .el-button--primary:hover,
+    .el-button--primary:focus {
+      width: 132px;
+      height: 36px;
+      margin-right: 52px;
+      text-align: center;
+      background: #2cb7ca;
+      border-radius: 6px;
+      font-style: 16px;
+      color: #fff;
+      border: 0;
+    }
+    .el-dialog {
+      border-radius: 8px;
+    }
+    .el-dialog__header {
+      padding: 32px 0 0;
+    }
+    .el-dialog__body {
+      padding: 20px 32px 32px;
+      color: #686868;
+      font-size: 14px;
+      line-height: 22px;
+      text-align: center;
+    }
+    .el-dialog__body i {
+      color: #2cb7ca;
+    }
+    .el-button {
+      width: 132px;
+      height: 36px;
+      padding: 0;
+      text-align: center;
+      font-size: 16px;
+    }
+    .el-dialog__footer {
+      padding: 0 0 32px;
+    }
+  }
+}
+</style>

+ 23 - 0
apps/bigmember_pc/src/views/search/bidding/index.vue

@@ -14,6 +14,7 @@ import powerPerson from '@/components/subscribe-manager/powerPerson.vue'
 import BidrenewalDialog from '@/views/BidrenewalDialog/index.vue'
 import BidrenewalDialog from '@/views/BidrenewalDialog/index.vue'
 import Empty from '@/components/common/Empty.vue'
 import Empty from '@/components/common/Empty.vue'
 import recommendCard from '@/views/search/bidding/components/recommend-card.vue'
 import recommendCard from '@/views/search/bidding/components/recommend-card.vue'
+// import ExtractSubDialog from '@/views/search/bidding/components/extract-sub-dialog.vue'
 // 导入业务模型
 // 导入业务模型
 import { useSearchBidModel, SearchBidModel } from './model/index'
 import { useSearchBidModel, SearchBidModel } from './model/index'
 import { getMsgDistributor } from '@/api/modules/'
 import { getMsgDistributor } from '@/api/modules/'
@@ -71,6 +72,8 @@ const {
   toggleBlurModeTip,
   toggleBlurModeTip,
   doToggleSearchBlurMode,
   doToggleSearchBlurMode,
   showFilter
   showFilter
+  // subscribeInfo,
+  // setSubscribeFun
 } = SearchBidModel
 } = SearchBidModel
 
 
 const {
 const {
@@ -94,6 +97,18 @@ const articleRef = ref({
   collect: !isInBI.value,
   collect: !isInBI.value,
   push: false
   push: false
 })
 })
+
+// 订阅提交(P643临时注掉,以后要上,勿删)
+// const extractSubRef = ref()
+// const onConfirmSubscribe = (params) => {
+//   setSubscribeFun(params, function() {
+//     try {
+//       extractSubRef.value.beforeCloseDialog()
+//     } catch (error) {
+//       console.log(error)
+//     }
+//   })
+// }
 </script>
 </script>
 
 
 <template>
 <template>
@@ -362,6 +377,14 @@ const articleRef = ref({
         frameborder="0"
         frameborder="0"
       ></iframe>
       ></iframe>
     </el-dialog>
     </el-dialog>
+    <!-- <extract-sub-dialog
+      ref="extractSubRef"
+      :info="subscribeInfo"
+      :isVip="isVip"
+      :isFree="isFree"
+      @confirm="onConfirmSubscribe"
+    >
+    </extract-sub-dialog> -->
   </div>
   </div>
 </template>
 </template>
 
 

+ 33 - 2
apps/bigmember_pc/src/views/search/bidding/model/base.js

@@ -41,6 +41,8 @@ import { beforeSearchModel } from './modules/before-search'
 import { recommendCardModel } from './modules/recommend-card'
 import { recommendCardModel } from './modules/recommend-card'
 // 搜索历史业务模型
 // 搜索历史业务模型
 import useSearchHistoryModel from '@jy/data-models/modules/quick-search-history/model'
 import useSearchHistoryModel from '@jy/data-models/modules/quick-search-history/model'
+// 订阅弹框业务
+// import { userSubscribeInfoModel } from './modules/data-subscribe'
 
 
 export default function () {
 export default function () {
   const that = getCurrentInstance().proxy
   const that = getCurrentInstance().proxy
@@ -127,6 +129,15 @@ export default function () {
 
 
   const { goback, keywords: urlKeywords, selectType: urlSelectType } = useRoute().query
   const { goback, keywords: urlKeywords, selectType: urlSelectType } = useRoute().query
 
 
+  // 订阅弹框相关变量(P643临时注掉,以后要上,勿删)
+  // 全局定时器
+  // const subTimer = ref(null)
+  // 停留秒数
+  // const subStopSeconds = ref(5000)
+  // 滚动屏数
+  // const screenCount = ref(1)
+  // const isStopShowModal = ref(false)
+
   // 缓存存储配置
   // 缓存存储配置
   const storageConfig = {
   const storageConfig = {
     listTab: {
     listTab: {
@@ -776,7 +787,14 @@ export default function () {
       if(inInjectBI) {
       if(inInjectBI) {
         getBidAddInfos()
         getBidAddInfos()
       }
       }
-
+      // P643临时注掉,以后要上,勿删
+      // if (inputKeywordsState.value.input && listState.pageNum === 1 && list.value) {
+      //   subTimer.value = setTimeout(() => {
+      //     openSubscribeModal(inputKeywordsState.value.input, () => {
+      //       isStopShowModal.value = true
+      //     })
+      //   }, subStopSeconds.value)
+      // }
     }
     }
     list.value = list.value.map(item => {
     list.value = list.value.map(item => {
       // 是否已读字段
       // 是否已读字段
@@ -1015,6 +1033,7 @@ export default function () {
     const scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop
     const scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop
     const watchFilter = document.querySelector('.searchTender').offsetTop - 25// 25为margin-top值
     const watchFilter = document.querySelector('.searchTender').offsetTop - 25// 25为margin-top值
     const watchTable = document.querySelector('.search-bidding-list-container').offsetTop - 15 // 15为margin-top值
     const watchTable = document.querySelector('.search-bidding-list-container').offsetTop - 15 // 15为margin-top值
+    const innerHeight = window.innerHeight || document.documentElement.innerHeight || document.body.innerHeight
     if (scrollTop >= watchFilter) {
     if (scrollTop >= watchFilter) {
       fixedTop.value = true
       fixedTop.value = true
       tableFixedTop.value = false
       tableFixedTop.value = false
@@ -1027,6 +1046,14 @@ export default function () {
     } else {
     } else {
       tableFixedTop.value = false
       tableFixedTop.value = false
     }
     }
+    // 计算当前滚动屏幕数(P643临时注掉,以后要上 勿删)
+    // screenCount.value = Math.ceil(scrollTop / innerHeight)
+    // if (screenCount.value > 2 && !isStopShowModal.value) {
+    //   clearTimeout(subTimer.value)
+    //   openSubscribeModal(inputKeywordsState.value.input, () => {
+    //     isStopShowModal.value = true
+    //   })
+    // }
   }
   }
 
 
   /*** 筛选条件头部、列表头部滚动end *****/
   /*** 筛选条件头部、列表头部滚动end *****/
@@ -1533,6 +1560,8 @@ export default function () {
     }
     }
   })
   })
 
 
+  // 订阅弹框()
+  // const { subscribeInfo, setSubscribeFun, openSubscribeModal } = userSubscribeInfoModel()
 
 
   return {
   return {
     isLogin,
     isLogin,
@@ -1608,6 +1637,8 @@ export default function () {
     storageConfig,
     storageConfig,
     clearHistoryQuery,
     clearHistoryQuery,
     searchHistoryList,
     searchHistoryList,
-    showCurrentFilterText
+    showCurrentFilterText,
+    // subscribeInfo,
+    // setSubscribeFun
   }
   }
 }
 }

+ 112 - 0
apps/bigmember_pc/src/views/search/bidding/model/modules/data-subscribe.js

@@ -0,0 +1,112 @@
+import { reactive, computed, onMounted } from 'vue'
+import { getIsSubscribe, getBigMemberInfo, getSVIPBuyInfo, updateSubscribe } from '@/api/modules/'
+import { showToast } from '@/components/toast'
+import { useStore } from '@/store'
+
+// 个人版
+const isPersonal = computed(() => {
+  return useStore().getters['user/isPersonalVersion']
+})
+// 是否是免费用户
+const isFree = computed(() => {
+  return useStore().getters['user/isFree']
+})
+// 是否登录
+const isLogin = computed(() => {
+  return useStore().getters['user/loginFlag']
+})
+// 是否是超级订阅
+const isSVip = computed (() => {
+  return useStore().getters['user/svip']
+})
+// 是否是大会员
+const isBigMember = computed(() => {
+  return useStore().getters['user/bigmember']
+})
+
+export function userSubscribeInfoModel() {
+  // 订阅弹框信息
+  const subscribeInfo = reactive({
+    // 是否订阅
+    isSubscribe: false,
+    // 地区可订阅数量
+    areaCount: 0,
+    // 关键词可订阅数量
+    keyCount: 0,
+    // 地区map 用于组件回显('':不选, {}:全国)
+    regionMap: '',
+    area: '',
+    city: '',
+    district: '',
+    keywords: []
+  })
+
+  // 调用订阅弹框逻辑
+  const openSubscribeModal = async (keywords, callback) => {
+    // 个人版
+    if (isPersonal.value && isLogin.value) {
+      subscribeInfo.keywords = isFree ? keywords.split(/\s+/) : [keywords]
+      getIsSubscribeInfo()
+      if (isBigMember.value) {
+        // 大会员用户
+        getMemberSubInfo()
+      } else if (isSVip.value) {
+        // 超级订阅用户
+        getSVipSubInfo()
+      } else {
+        // 免费用户
+        subscribeInfo.areaCount = 1
+        subscribeInfo.keyCount = 10
+      }
+      callback && callback()
+    }
+  }
+
+  // 获取大会员订阅信息
+  const getMemberSubInfo = async () => {
+    const { data } = await getBigMemberInfo()
+    if (data) {
+      subscribeInfo.areaCount = -1
+      subscribeInfo.keyCount = data?.key_max_length
+    }
+  }
+  // 获取超级订阅订阅信息
+  const getSVipSubInfo = async () => {
+    const { data } = await getSVIPBuyInfo()
+    if (data) {
+      subscribeInfo.areaCount = data?.buyset?.areacount
+      subscribeInfo.keyCount = data?.key_max_length
+    }
+  }
+  // 获取订阅弹框信息
+  const getIsSubscribeInfo = async () => {
+    const { data } = await getIsSubscribe()
+    if (data) {
+      subscribeInfo.isSubscribe = data.isSubscribe
+      const { area } = data
+      subscribeInfo.regionMap = area ? area : ''
+    }
+  }
+  // 订阅设置
+  const setSubscribeFun = async (params, callback) => {
+    let vType = ''
+    if (isBigMember.value) {
+      vType = 'mType'
+    } else if (isSVip.value) {
+      vType = 'vType'
+    } else {
+      vType = 'fType'
+    }
+    const { error_code: code, error_msg: msg, data } = await updateSubscribe(vType, params)
+    if (code === 0 && data && data.status === 1) {
+      callback && callback()
+    } else {
+      showToast(msg)
+    }
+  }
+  return {
+    openSubscribeModal,
+    subscribeInfo,
+    setSubscribeFun
+  }
+}

+ 6 - 6
apps/bigmember_pc/src/views/search/sun/index.vue

@@ -207,9 +207,9 @@ const leaveSource = () => {
         </template>
         </template>
         <template
         <template
           #list-after
           #list-after
-          v-if="listState.finished && activeItemStyleType !== 'T' && isLogin"
+          v-if="listState.finished && isLogin"
         >
         >
-          <div
+          <!-- <div
             class="p-16px text-right over-run-tips"
             class="p-16px text-right over-run-tips"
             v-if="isFree && listState.total >= 500"
             v-if="isFree && listState.total >= 500"
           >
           >
@@ -217,12 +217,12 @@ const leaveSource = () => {
             <span class="highlight-text" @click="onFreeTaste"
             <span class="highlight-text" @click="onFreeTaste"
               >点击免费查看更多信息</span
               >点击免费查看更多信息</span
             >
             >
-          </div>
+          </div> -->
           <div
           <div
             class="text-right over-run-tips"
             class="text-right over-run-tips"
-            v-if="isVip && listState.total >= 5000"
+            v-if="listState.total >= 500"
           >
           >
-            为您展示前5000条,可细化筛选条件查看更多信息
+            为您展示前500条,可细化筛选条件查看更多信息
           </div>
           </div>
         </template>
         </template>
         <template #pagination>
         <template #pagination>
@@ -592,7 +592,7 @@ const leaveSource = () => {
 }
 }
 .in-web {
 .in-web {
   .search-sun-page {
   .search-sun-page {
-    margin-top: 24px;
+    margin: 24px auto;
   }
   }
 }
 }
 .search-sun-page {
 .search-sun-page {

Plik diff jest za duży
+ 230 - 188
apps/bigmember_pc/src/views/search/sun/model/base.js


+ 105 - 49
apps/mobile/index.html

@@ -1,38 +1,82 @@
-<!DOCTYPE html>
+<!doctype html>
 <html lang="zh-CN">
 <html lang="zh-CN">
-
-<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, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no, viewport-fit=cover">
-  <meta name="browsermode" content="application">
-  <meta name="x5-orientation" content="portrait">
-  <meta name="screen-orientation" content="portrait">
-  <meta name="x5-page-mode" content="app">
-  <meta name="apple-mobile-web-app-capable" content="yes">
-  <meta name="apple-mobile-web-app-status-bar-style" content="black">
-  <meta name="format-detection" content="telephone=no">
-  <link rel="icon" href="/favicon.ico">
-  <link rel="preconnect" href="cdn-common.jianyu360.com">
-  <link rel="dns-prefetch" href="cdn-common.jianyu360.com">
-  <title>剑鱼标讯</title>
+  <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, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no, viewport-fit=cover"
+    />
+    <meta name="browsermode" content="application" />
+    <meta name="x5-orientation" content="portrait" />
+    <meta name="screen-orientation" content="portrait" />
+    <meta name="x5-page-mode" content="app" />
+    <meta name="apple-mobile-web-app-capable" content="yes" />
+    <meta name="apple-mobile-web-app-status-bar-style" content="black" />
+    <meta name="format-detection" content="telephone=no" />
+    <link rel="icon" href="/favicon.ico" />
+    <link rel="preconnect" href="cdn-common.jianyu360.com" />
+    <link rel="dns-prefetch" href="cdn-common.jianyu360.com" />
+    <title>剑鱼标讯</title>
+    <!-- <script src="//cdn.bootcdn.net/ajax/libs/vConsole/3.15.0/vconsole.min.js"></script>
+    <script>
+      new window.VConsole()
+    </script> -->
     <!-- 预加载,提升优先级  -->
     <!-- 预加载,提升优先级  -->
     <% if (!isDev) { %>
     <% if (!isDev) { %>
-    <link rel="preload" as="style" href="//cdn-common.jianyu360.com/cdn/assets/iconfont/mobile/24.2.28/iconfont.css">
-    <link rel="preload" as="script" href="//cdn-common.jianyu360.com/cdn/lib/vue/2.7.16/vue.min.js">
-    <link rel="preload" as="script" href="//cdn-common.jianyu360.com/cdn/lib/vue-router/3.6.5/vue-router.min.js">
-    <link rel="preload" as="script" href="//cdn-common.jianyu360.com/cdn/lib/vuex/3.6.2/vuex.min.js">
-    <link rel="preload" as="script" href="//cdn-common.jianyu360.com/cdn/lib/axios/1.6.7/axios.min.js">
+    <link
+      rel="preload"
+      as="style"
+      href="//cdn-common.jianyu360.com/cdn/assets/iconfont/mobile/24.2.28/iconfont.css"
+    />
+    <link
+      rel="preload"
+      as="script"
+      href="//cdn-common.jianyu360.com/cdn/lib/vue/2.7.16/vue.min.js"
+    />
+    <link
+      rel="preload"
+      as="script"
+      href="//cdn-common.jianyu360.com/cdn/lib/vue-router/3.6.5/vue-router.min.js"
+    />
+    <link
+      rel="preload"
+      as="script"
+      href="//cdn-common.jianyu360.com/cdn/lib/vuex/3.6.2/vuex.min.js"
+    />
+    <link
+      rel="preload"
+      as="script"
+      href="//cdn-common.jianyu360.com/cdn/lib/axios/1.6.7/axios.min.js"
+    />
 
 
-    <link rel="preload" as="script" href="//cdn-common.jianyu360.com/cdn/lib/vant/2.12.24/lib/vant.min.js">
-    <link rel="preload" as="script" href="//cdn-common.jianyu360.com/cdn/lib/lodash/4.17.21/lodash.min.js">
-    <link rel="preload" as="script" href="//cdn-common.jianyu360.com/cdn/lib/dayjs/1.11.4/dayjs.min.js">
-    <link rel="preload" as="script" href="//cdn-common.jianyu360.com/cdn/lib/js-cookie/2.2.1/js.cookie.min.js">
+    <link
+      rel="preload"
+      as="script"
+      href="//cdn-common.jianyu360.com/cdn/lib/vant/2.12.24/lib/vant.min.js"
+    />
+    <link
+      rel="preload"
+      as="script"
+      href="//cdn-common.jianyu360.com/cdn/lib/lodash/4.17.21/lodash.min.js"
+    />
+    <link
+      rel="preload"
+      as="script"
+      href="//cdn-common.jianyu360.com/cdn/lib/dayjs/1.11.4/dayjs.min.js"
+    />
+    <link
+      rel="preload"
+      as="script"
+      href="//cdn-common.jianyu360.com/cdn/lib/js-cookie/2.2.1/js.cookie.min.js"
+    />
     <% } %>
     <% } %>
 
 
     <!-- 按优先级加载  -->
     <!-- 按优先级加载  -->
-    <link rel="stylesheet" href="//cdn-common.jianyu360.com/cdn/assets/iconfont/mobile/24.7.16/iconfont.css">
+    <link
+      rel="stylesheet"
+      href="//cdn-common.jianyu360.com/cdn/assets/iconfont/mobile/24.7.16/iconfont.css"
+    />
 
 
     <% if (!isDev) { %>
     <% if (!isDev) { %>
 
 
@@ -52,30 +96,42 @@
     <% } %>
     <% } %>
     <script src="//res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
     <script src="//res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
 
 
-    <script defer src="//cdn-common.jianyu360.com/cdn/assets/iconfont/mobile/24.7.16/iconfont.js"></script>
-    <script defer src="//cdn-common.jianyu360.com/cdn/lib/echarts/4.8.0/echarts.min.js"></script>
-    <script defer src="//cdn-common.jianyu360.com/cdn/lib/v-charts/1.19.0/index.min.js"></script>
+    <script
+      defer
+      src="//cdn-common.jianyu360.com/cdn/assets/iconfont/mobile/24.7.16/iconfont.js"
+    ></script>
+    <script
+      defer
+      src="//cdn-common.jianyu360.com/cdn/lib/echarts/4.8.0/echarts.min.js"
+    ></script>
+    <script
+      defer
+      src="//cdn-common.jianyu360.com/cdn/lib/v-charts/1.19.0/index.min.js"
+    ></script>
 
 
-    <link  rel="stylesheet" href="//cdn-common.jianyu360.com/cdn/lib/v-charts/1.19.0/style.min.css">
-</head>
+    <link
+      rel="stylesheet"
+      href="//cdn-common.jianyu360.com/cdn/lib/v-charts/1.19.0/style.min.css"
+    />
+  </head>
 
 
-<body>
-  <noscript>
-    <strong>JavaScript enabled. Please enable it to continue.</strong>
-  </noscript>
-  <div id="app"></div>
-  <script type="module" src="/src/main.js"></script>
-  <!-- built files will be auto injected -->
-  <% if (!isDev) { %>
+  <body>
+    <noscript>
+      <strong>JavaScript enabled. Please enable it to continue.</strong>
+    </noscript>
+    <div id="app"></div>
+    <script type="module" src="/src/main.js"></script>
+    <!-- built files will be auto injected -->
+    <% if (!isDev) { %>
     <script src="/jyapp/js/common.js?v=<%= assets.version %>"></script>
     <script src="/jyapp/js/common.js?v=<%= assets.version %>"></script>
     <script src="/common-module/chart-module/js/chart-common.js?v=<%= assets.version %>"></script>
     <script src="/common-module/chart-module/js/chart-common.js?v=<%= assets.version %>"></script>
     <script src="/common-module/public/fotter.js?v=<%= assets.version %>"></script>
     <script src="/common-module/public/fotter.js?v=<%= assets.version %>"></script>
-  <% } %>
-
-  <% if (isDev) { %>
-   <!-- 开发环境需要加载的js -->
-    <script defer src="/common-module/chart-module/js/chart-common.js?v=<%= assets.version %>"></script>
-  <% } %>
-</body>
-
+    <% } %> <% if (isDev) { %>
+    <!-- 开发环境需要加载的js -->
+    <script
+      defer
+      src="/common-module/chart-module/js/chart-common.js?v=<%= assets.version %>"
+    ></script>
+    <% } %>
+  </body>
 </html>
 </html>

+ 2 - 1
apps/mobile/package.json

@@ -17,6 +17,7 @@
     "@jy/vue-anti": "workspace:^",
     "@jy/vue-anti": "workspace:^",
     "@sentry/vue": "^7.64.0",
     "@sentry/vue": "^7.64.0",
     "@tinymce/tinymce-vue": "^3.2.8",
     "@tinymce/tinymce-vue": "^3.2.8",
+    "aliyun_numberauthsdk_web": "^2.1.9",
     "dayjs": "^1.11.8",
     "dayjs": "^1.11.8",
     "html2canvas": "^1.4.1",
     "html2canvas": "^1.4.1",
     "js-cookie": "^3.0.1",
     "js-cookie": "^3.0.1",
@@ -36,10 +37,10 @@
   },
   },
   "devDependencies": {
   "devDependencies": {
     "@jonny1994/postcss-px-to-viewport": "^1.1.0",
     "@jonny1994/postcss-px-to-viewport": "^1.1.0",
-    "@unocss/transformer-variant-group": "^0.58.5",
     "@nabla/vite-plugin-eslint": "^2.0.2",
     "@nabla/vite-plugin-eslint": "^2.0.2",
     "@rushstack/eslint-patch": "^1.1.0",
     "@rushstack/eslint-patch": "^1.1.0",
     "@sentry/vite-plugin": "^2.21.1",
     "@sentry/vite-plugin": "^2.21.1",
+    "@unocss/transformer-variant-group": "^0.58.5",
     "@vitejs/plugin-legacy": "^4.0.4",
     "@vitejs/plugin-legacy": "^4.0.4",
     "@vitejs/plugin-vue2": "^2.2.0",
     "@vitejs/plugin-vue2": "^2.2.0",
     "@vue/eslint-config-prettier": "^7.0.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 qs from 'qs'
+import request from '@/api'
+
 export function screenList() {
 export function screenList() {
   return request({
   return request({
     url: '/subscribepay/dataExportPack/screenList',
     url: '/subscribepay/dataExportPack/screenList',
@@ -208,7 +209,6 @@ export function getWxSdkSign(data) {
 /**
 /**
  * 获取商品详情信息(超级订阅、数据流量包)
  * 获取商品详情信息(超级订阅、数据流量包)
  * @param data
  * @param data
- * @returns {AxiosPromise}
  */
  */
 export function getCommodityDetail(data) {
 export function getCommodityDetail(data) {
   return request({
   return request({
@@ -221,7 +221,6 @@ export function getCommodityDetail(data) {
 /**
 /**
  * 实时计算当前下单价格
  * 实时计算当前下单价格
  * @param data
  * @param data
- * @returns {AxiosPromise}
  */
  */
 export function getOrderPrice(data) {
 export function getOrderPrice(data) {
   return request({
   return request({
@@ -234,7 +233,6 @@ export function getOrderPrice(data) {
 /**
 /**
  * 获取当前规格产品下的活动以及优惠信息
  * 获取当前规格产品下的活动以及优惠信息
  * @param data
  * @param data
- * @returns {AxiosPromise}
  */
  */
 export function getCommodityCouponInfo(data) {
 export function getCommodityCouponInfo(data) {
   return request({
   return request({
@@ -307,3 +305,20 @@ export function vipRenewReminder(data) {
     data: qs.stringify(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
+  })
+}

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

@@ -333,3 +333,41 @@ export function getIsWhiteList() {
     method: 'get'
     method: 'get'
   })
   })
 }
 }
+
+// 一键登录/注册/绑定
+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({
+    url: '/publicapply/configuration/get',
+    method: 'post',
+    data
+  })
+}
+
+// 是否订阅查询
+export function getIsSub(data) {
+  return request({
+    url: '/publicapply/subscribe/isSub',
+    method: 'post',
+    data
+  })
+}

+ 11 - 1
apps/mobile/src/api/modules/subscribe.js

@@ -1,5 +1,5 @@
-import request from '@/api'
 import qs from 'qs'
 import qs from 'qs'
+import request from '@/api'
 import { envs } from '@/utils/prototype/modules/platform'
 import { envs } from '@/utils/prototype/modules/platform'
 
 
 // 获取用户订阅信息
 // 获取用户订阅信息
@@ -87,6 +87,16 @@ export function getPushListDataExportId(type = 'fType', data) {
   })
   })
 }
 }
 
 
+// 订阅设置更新接口
+
+export function getSubScribeUpdateApi(type = 'fType', data) {
+  return request({
+    url: `/jyapi/jybx/subscribe/${type}/update`,
+    method: 'post',
+    data
+  })
+}
+
 // 推送设置接口
 // 推送设置接口
 // 用户信息获取
 // 用户信息获取
 export function getUser(data) {
 export function getUser(data) {

BIN
apps/mobile/src/assets/image/course-page/1.jpg


BIN
apps/mobile/src/assets/image/course-page/2.jpg


BIN
apps/mobile/src/assets/image/course-page/3.jpg


BIN
apps/mobile/src/assets/image/course-page/4.jpg


BIN
apps/mobile/src/assets/image/course-page/video-1.mp4


BIN
apps/mobile/src/assets/image/course-page/video-2.mp4


BIN
apps/mobile/src/assets/image/course-page/video-3.mp4


BIN
apps/mobile/src/assets/image/icon/customer-bid.png


+ 233 - 0
apps/mobile/src/assets/style/modules/fast-login.scss

@@ -0,0 +1,233 @@
+.fast-login-container {
+  margin-top: 7px;
+  margin-bottom: 7px;
+  text-align: center;
+}
+.fast-login {
+  margin: 0 auto;
+  padding: 0 20px;
+}
+.fast-login-text {
+  font-size: 16px;
+  line-height: 26px;
+  background-color: transparent;
+}
+.fast-phone-container {
+  margin: 32px auto 40px;
+  text-align: center;
+}
+.fast-phone-number {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  color: #171826;
+  font-size: 24px;
+  line-height: 48px;
+}
+.fast-phone-text {
+  color: #5f5e64;
+  text-align: center;
+  font-size: 13px;
+  line-height: 20px;
+}
+.client-verify .phone-number-mask {
+  margin: 0 8px;
+}
+.h5-verify .van-password-input {
+  margin: 0 10px;
+}
+.h5-verify .phone-number-prefix,
+.h5-verify .phone-number-suffix {
+  letter-spacing: 5px;
+}
+.verify-button {
+  padding: 9px 0;
+  width: 100%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  text-align: center;
+  font-size: 18px;
+  line-height: 26px;
+  border-radius: 8px;
+  border: 1px solid transparent;
+}
+.verify-confirm {
+  color: #f7f9fa;
+  background-color: #2abed1;
+  border-color: #2abed1;
+}
+.verify-cancel {
+  color: #2abed1;
+  background-color: transparent;
+  border-color: #2abed1;
+}
+.verify-button-group .verify-button:not(:first-of-type) {
+  margin-top: 12px;
+}
+
+.van-password-input__security li {
+  flex: none;
+  width: 20px;
+  color: inherit;
+  font-size: inherit;
+  border-bottom: 1px solid #5f5e64;
+  background-color: transparent;
+}
+.van-password-input__security li:not(:last-of-type) {
+  margin-right: 10px;
+}
+.van-password-input__security li.van-password-input__item--focus {
+  border-bottom: 2px solid #2abed1;
+}
+
+/* 一键登录相关样式 */
+/* 此处可修改导航栏整体样式:字体大小,字体颜色,背景颜色等 */
+body .page-type-container {
+  position: fixed;
+  bottom: 0;
+  min-height: 100vh;
+  z-index: 99999;
+}
+body .page-type-container .nav-title {
+  color: #fff;
+}
+body
+  .page-type-container
+  .dialog-subtitle,
+  body
+  .dialog-type-container
+  .dialog-subtitle {
+  color: #5f5e64;
+  text-align: center;
+  font-size: 13px;
+  line-height: 20px;
+}
+/* 此处可修改logo容器的样式: 宽度 高度,圆角等 */
+body .page-type-container .logo {
+  margin-top: 0;
+  margin-bottom: 4vh;
+  width: 100%;
+}
+body .dialog-type-container .logo {
+  margin-top: 0;
+  margin-bottom: 4vw;
+  width: 86%;
+}
+.page-type-container .content {
+  min-height: unset;
+}
+/* 此处修改电话号码的样式: 颜色、字体大小等 */
+body .page-type-container .number-con-wrap {
+  flex-direction: column;
+}
+body .page-type-container .number-con-label {
+  color: #5f5e64;
+  text-align: center;
+  font-size: 13px;
+  line-height: 20px;
+}
+body .page-type-container .number-con,
+body .dialog-type-container .number-con {
+  color: #171826;
+  font-size: 24px;
+  line-height: 48px;
+}
+body .page-type-container .number-con {
+  margin: 4vw 0;
+}
+/* 此处修改电话号码掩码的样式:宽度、高度、字体颜、色间距等 */
+body .page-type-container .number-con input,
+body .dialog-type-container .number-con input {
+  padding: 0;
+  color: inherit;
+  font-size: inherit;
+  border-bottom: 1px solid #5f5e64;
+}
+body .page-type-container .number-con input:focus,
+body .dialog-type-container .number-con input:focus {
+  border-bottom: 2px solid #2abed1;
+}
+/* 此处修改协议勾选、选中时的颜色 */
+body
+  .page-type-container
+  .agreement
+  .checke-1
+  svg
+  g
+  body
+  .dialog-type-container
+  .agreement
+  .checke-1
+  svg
+  g {
+  fill: #2abed1;
+}
+/* 此处修改登录按钮的样式:颜色大小背景色等 */
+body .page-type-container .submit-btn,
+body .dialog-type-container .submit-btn {
+  margin: 10vw auto;
+  margin-bottom: 20vw;
+  padding: 9px 0;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  text-align: center;
+  font-size: 18px;
+  line-height: 26px;
+  border-radius: 8px;
+  border: 1px solid #2abed1;
+  background: #2abed1;
+}
+body .dialog-type-container .submit-btn {
+  margin: 8vw auto 4vw;
+}
+
+body .page-type-container .submit-disabled,
+body .dialog-type-container .submit-disabled {
+  background: #2abed1;
+}
+body .page-type-container .submit-btn.submit-disabled,
+body .dialog-type-container .submit-btn.submit-disabled {
+  opacity: 0.6;
+}
+/* 此处修改协议区域的样式: 字体颜色,大小等 */
+body .page-type-container .agreement {
+  margin: 2vh 6vw 0;
+}
+body .page-type-container .agreement .agree-content,
+body .dialog-type-container .agreement .agree-content {
+  width: 80vw;
+  margin: 0 auto;
+  color: #171826;
+}
+body .dialog-type-container .agreement .agree-content {
+  width: 74vw;
+}
+body .page-type-container .agreement .checke-0,
+body .page-type-container .agreement .checke-1,
+body .dialog-type-container .agreement .checke-0,
+body .dialog-type-container .agreement .checke-1 {
+  margin-right: 6px;
+}
+body .page-type-container .agreement .checke-1 svg g,
+body .dialog-type-container .agreement .checke-1 svg g {
+  fill: #2abed1;
+}
+body .page-type-container .agreement a,
+body .dialog-type-container .agreement a {
+  color: #2abed1;
+}
+body .page-type-container .custom-view-box {
+  margin: 0 auto;
+  margin-top: -27vw;
+}
+body .page-type-container .agreement .agree-content-tip {
+  top: -7.2vh;
+  left: -1.6vw;
+  background: rgba(0, 0, 0, 0.7);
+  color: #fff;
+}
+body .page-type-container .agreement .agree-content-tip::after {
+  content: unset;
+}

+ 6 - 3
apps/mobile/src/components/common/DropdownLayout.vue

@@ -1,12 +1,15 @@
 <template>
 <template>
   <div
   <div
-    class="j-container layout-card"
     ref="layoutCard"
     ref="layoutCard"
+    class="j-container layout-card"
     :style="{ 'max-height': maxHeight }"
     :style="{ 'max-height': maxHeight }"
   >
   >
+    <div class="j-header">
+      <slot name="header" />
+    </div>
     <div class="j-main">
     <div class="j-main">
-      <slot name="default"></slot>
-      <slot name="main"></slot>
+      <slot name="default" />
+      <slot name="main" />
     </div>
     </div>
     <div class="j-footer">
     <div class="j-footer">
       <slot name="footer">
       <slot name="footer">

+ 60 - 0
apps/mobile/src/components/customerBid/index.vue

@@ -0,0 +1,60 @@
+<template>
+  <div
+    class="customer-bid"
+    :class="{ fadeOutRight: !scrollStatus }"
+    :style="{ bottom: bottomPosition || '' }"
+  >
+    <div class="content" @click="jumpCustomerPage">
+      <img src="@/assets/image/icon/customer-bid.png" alt="" />
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  props: {
+    scrollStatus: {
+      type: Boolean,
+      default: false
+    },
+    bottomPosition: {
+      type: String,
+      default: ''
+    }
+  },
+  data() {
+    return {
+      show: false
+    }
+  },
+  created() {},
+  methods: {
+    jumpCustomerPage() {
+      this.$emit('jumpBidPage')
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.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;
+  }
+}
+</style>

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

@@ -0,0 +1,335 @@
+<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"
+            :class="{ active: info.phone }"
+            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 fastBind from '@/utils/mixins/modules/fast-bind'
+export default {
+  name: 'OneClickBinding',
+  mixins: [fastBind],
+  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) {
+      console.log(state, '组件内接收参数')
+      if (state === 1) {
+        let newQuery = JSON.parse(JSON.stringify(this.$route.query))
+        if (newQuery && newQuery.wxpush) {
+          delete newQuery.wxpush
+        }
+        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.code,
+        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">
+@import '@/assets/style/modules/fast-login.scss';
+</style>
+<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 {
+      padding: 0;
+      height: unset;
+      color: #c0c4cc;
+      font-size: 14px;
+      line-height: 20px;
+      border: none;
+      &.active {
+        color: $color_main;
+      }
+    }
+    ::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__control {
+        font-size: 16px;
+      }
+      .van-field__button {
+        display: flex;
+      }
+    }
+  }
+  .fast-login-container {
+    text-align: center;
+  }
+  .fast-login-text {
+    padding-bottom: 20px;
+    font-size: 16px;
+    line-height: 26px;
+    background-color: transparent;
+  }
+}
+</style>

+ 702 - 60
apps/mobile/src/components/search/bidding/oneKeySubscribeDialog.vue

@@ -1,41 +1,132 @@
 <template>
 <template>
   <van-dialog
   <van-dialog
     :value="value"
     :value="value"
-    title="订阅搜索词"
+    title="已帮您提取订阅信息,请确认"
     get-container="body"
     get-container="body"
-    className="j-confirm-dialog"
-    confirmButtonText="一键订阅"
-    cancelButtonText="暂不订阅"
+    class-name="j-confirm-dialog"
+    :show-confirm-button="false"
+    :class="{ 'disabled-confirm': disabledConfirm }"
     @cancel="onClose(false)"
     @cancel="onClose(false)"
     @close="onClose(false)"
     @close="onClose(false)"
-    :before-close="beforeClose"
-    :class="{ 'disabled-confirm': disabledConfirm }"
-    show-cancel-button
   >
   >
+    <template #title>
+      <div class="subscribe-title">
+        <span>已帮您提取订阅信息,请确认</span>
+        <van-icon name="clear" color="#C0C4CC" @click="onClose(false)" />
+      </div>
+    </template>
     <div class="content">
     <div class="content">
-      <div class="content-header">
-        <span>剑鱼标讯推荐您将搜索词</span>
-        <span class="highlight-text">“{{ keywords }}”</span>
-        <span>添加到您的订阅中,以保证及时接收项目信息。</span>
+      <div class="content-item">
+        <div class="content-header">
+          <span>您能接受哪些地区的业务?</span>
+          <!-- <span class="highlight-text">“{{ keywords }}”</span>
+          <span>添加到您的订阅中,以保证及时接收项目信息。</span> -->
+        </div>
+        <div class="content-body">
+          <van-field
+            readonly
+            :border="false"
+            clickable
+            name="picker"
+            :value="areaSelected"
+            placeholder="添加地区"
+            is-link
+            @click="setAreaType"
+          />
+        </div>
       </div>
       </div>
-      <div class="content-body" v-show="showSelectAreaField">
-        <van-field
-          readonly
-          :border="false"
-          clickable
-          name="picker"
-          :value="areaSelected"
-          placeholder="请选择订阅区域"
-          @click="areaPickerShow = true"
-          is-link
-        />
+      <div class="content-item" style="margin-top: 16px">
+        <div class="content-header">
+          <span>您经营的产品或主营业务是?</span>
+        </div>
+        <div class="keys-list">
+          <div v-for="(item, index) in keyList" :key="index" class="keys-item">
+            <div class="keys-text">
+              {{ item }}
+            </div>
+            <van-icon
+              name="cross"
+              size="12"
+              color="#C0C4CC"
+              @click="onDeleteKey(item)"
+            />
+          </div>
+        </div>
+        <div class="content-body product-field">
+          <van-field
+            v-model="productSelected"
+            :border="false"
+            name="picker"
+            placeholder="请输入您的经营产品或业务"
+          />
+          <van-button
+            class="j-add-product"
+            :disabled="productSelected.trim() === ''"
+            type="primary"
+            @click="onAddKey(productSelected)"
+          >
+            添加
+          </van-button>
+        </div>
       </div>
       </div>
-      <div class="content-footer">
-        <van-checkbox v-model="remindChecked" icon-size="18px"
-          >后续不再提醒</van-checkbox
-        >
+      <div class="subscribe-tip">
+        前往<span @click="toSubSetting">订阅设置</span>,设置订阅信息推送渠道和推送时间
       </div>
       </div>
     </div>
     </div>
+    <div class="j-button-group height40">
+      <van-button
+        class="j-button-confirm"
+        :disabled="disabledConfirm"
+        @click="subConfirmEvent"
+      >
+        完成订阅,立即免费查看信息
+      </van-button>
+    </div>
+    <van-popup
+      v-model="areaCascaderPickerShow"
+      class="area-cascader-picker"
+      round
+      position="bottom"
+      :safe-area-inset-bottom="true"
+      get-container="body"
+      :lazy-render="false"
+    >
+      <DropdownLayout max-height="auto" @cancel="onReset" @confirm="onConfirm">
+        <div slot="header" class="j-header-content">
+          <div class="title-row">
+            <span>区域选择</span>
+            <van-icon
+              name="clear"
+              color="#C0C4CC"
+              @click="areaCascaderPickerShow = false"
+            />
+          </div>
+          <div class="count-row">
+            <span>可选:</span>
+            <strong v-if="subInfo.productType === 'member'">全国</strong>
+            <strong v-else-if="subInfo.productType === 'vip' && areaInfo.buyAreaCount === -1">全国</strong>
+            <span v-else><strong>{{ areaInfo.buyAreaCount }}</strong>个省</span>,
+            <span>已选:</span>
+            <strong v-if="selectedCount === -1">全国</strong>
+            <span v-else><strong>{{ selectedCount }}</strong>个省</span>
+          </div>
+        </div>
+        <AreaCitySidebar
+          ref="areaSelector"
+          v-model="cacheMoreFilters.area"
+          class="area-city-sidebar"
+          :tag-text-only-selected-count="true"
+          :disabled-city-select="noLoginOrFree"
+          :use-province-city-split="true"
+          :before-change="onAreaBeforeChange"
+          @change="onAreaChanged"
+          @onDisabledCityClick="onNoPower"
+        />
+        <van-dialog v-model="showVipLimit" overlay-class="vip-limit-dialog-overlay" class="vip-limit-dialog" confirm-button-color="#2ABED1" confirm-button-text="去升级" title="超出可选省份数量" show-cancel-button @confirm="goUpgrade" @cancel="showVipLimit = false">
+          <div>可选:<span style="color: #2ABED1;">{{ areaInfo.buyAreaCount }}个省</span>,如需增加省份数量,您可前往升级超级订阅。</div>
+        </van-dialog>
+      </DropdownLayout>
+    </van-popup>
     <van-popup
     <van-popup
       v-model="areaPickerShow"
       v-model="areaPickerShow"
       round
       round
@@ -52,25 +143,33 @@
         <van-picker
         <van-picker
           ref="areaPicker"
           ref="areaPicker"
           class="highlight-active"
           class="highlight-active"
-          :columns="areaList"
-        ></van-picker>
+          :columns="proviceList"
+        />
         <div slot="footer">
         <div slot="footer">
           <div class="j-button-group height40">
           <div class="j-button-group height40">
             <button class="j-button-cancel" @click="areaPickerShow = false">
             <button class="j-button-cancel" @click="areaPickerShow = false">
               取消
               取消
             </button>
             </button>
-            <button class="j-button-confirm" @click="popupConfirm">确定</button>
+            <button class="j-button-confirm" @click="popupConfirm">
+              确定
+            </button>
           </div>
           </div>
         </div>
         </div>
       </PopupLayout>
       </PopupLayout>
     </van-popup>
     </van-popup>
   </van-dialog>
   </van-dialog>
 </template>
 </template>
+
 <script>
 <script>
-import { Dialog, Field, Checkbox, Popup, Picker } from 'vant'
+import { mapGetters } from 'vuex'
+import { Button, Checkbox, Dialog, Field, Icon, Picker, Popup } from 'vant'
 import PopupLayout from '@/components/common/PopupLayout'
 import PopupLayout from '@/components/common/PopupLayout'
-import { freeUserSubscribeSearch } from '@/api/modules'
+import { freeUserSubscribeSearch, getSVIPBuyInfo } from '@/api/modules'
+import DropdownLayout from '@/components/common/DropdownLayout'
 import { provinceListMapExp } from '@/data'
 import { provinceListMapExp } from '@/data'
+// 地区三级选择器
+import AreaCitySidebar from '@/components/selector/area-three-sidebar/index'
+
 export default {
 export default {
   name: 'SearchResultLayout',
   name: 'SearchResultLayout',
   components: {
   components: {
@@ -79,7 +178,15 @@ export default {
     [Field.name]: Field,
     [Field.name]: Field,
     [Popup.name]: Popup,
     [Popup.name]: Popup,
     [Picker.name]: Picker,
     [Picker.name]: Picker,
-    [Checkbox.name]: Checkbox
+    [Button.name]: Button,
+    [Icon.name]: Icon,
+    [Checkbox.name]: Checkbox,
+    DropdownLayout,
+    AreaCitySidebar
+  },
+  model: {
+    prop: 'value',
+    event: 'change'
   },
   },
   props: {
   props: {
     value: Boolean,
     value: Boolean,
@@ -93,68 +200,458 @@ export default {
     areaSet: {
     areaSet: {
       type: Boolean,
       type: Boolean,
       default: false
       default: false
+    },
+    subInfo: {
+      type: Object,
+      default: () => {
+        return {
+          area: '', // 省份
+          city: '', // 城市
+          district: '', // 区
+          frequentContinuous: 2, // 频数
+          isSubscribe: false, // 是否订阅
+          positionType: 0, // 身份:0个人1企业
+          productType: 'free',
+          screenNumb: 2 // 屏数
+        }
+      }
     }
     }
   },
   },
-  model: {
-    prop: 'value',
-    event: 'change'
-  },
   data() {
   data() {
     return {
     return {
       areaList: [],
       areaList: [],
+      proviceList: [],
       areaPickerShow: false,
       areaPickerShow: false,
-      remindChecked: false,
-      areaSelected: ''
+      areaCascaderPickerShow: false,
+      areaSelected: '',
+      productSelected: '',
+      keyList: [],
+      areaInfo: {
+        buyAreaCount: -1
+      },
+      cacheMoreFilters: {
+        area: {}
+      },
+      subUserInfo: {},
+      showVipLimit: false
     }
     }
   },
   },
   computed: {
   computed: {
+    ...mapGetters('user', ['isLogin', 'isFree', 'isWhiteList']),
     showSelectAreaField() {
     showSelectAreaField() {
       return this.areaSet
       return this.areaSet
     },
     },
     disabledConfirm() {
     disabledConfirm() {
-      if (this.showSelectAreaField) {
-        return !this.areaSelected
-      } else {
-        return false
+      return !(this.areaSelected && this.keyList.length)
+    },
+    noLoginOrFree() {
+      if (this.isLogin) {
+        return this.isFree
       }
       }
-    }
+      else {
+        return true
+      }
+    },
+    selectedCount() {
+      return Object.keys(this.cacheMoreFilters.area).length || -1
+    },
+  },
+  watch: {
+    value: {
+      handler(val) {
+        if (val) {
+          let $datas = sessionStorage.getItem('JY-MOBILE-bidding-subscribe')
+          if ($datas) {
+            $datas = JSON.parse($datas)
+            Object.assign(this.$data, $datas)
+          }
+          this.setKeyListFun(this.keywords)
+          if (this.subInfo.productType === 'free') {
+            let freeSelectArea = sessionStorage.getItem('freeSelectArea')
+            if (freeSelectArea) {
+              freeSelectArea = JSON.parse(freeSelectArea)
+              this.areaSelected = Object.keys(freeSelectArea)[0]
+              console.log('freeSelectArea', freeSelectArea, this.areaSelected)
+            }
+          }
+          else {
+            this.getVipUserInfo()
+          }
+          setTimeout(() => {
+            this.setStateArea()
+          }, 1000)
+        }
+      },
+      immediate: true
+    },
   },
   },
   created() {
   created() {
     this.initArea(provinceListMapExp)
     this.initArea(provinceListMapExp)
   },
   },
   methods: {
   methods: {
+    // 超级订阅升级
+    goUpgrade() {
+      this.$router.push('/order/create/svip?type=upgrade')
+    },
     initArea(map) {
     initArea(map) {
       let list = []
       let list = []
       for (const key in map) {
       for (const key in map) {
         if (key === '#') {
         if (key === '#') {
           continue
           continue
-        } else {
+        }
+        else {
           if (Array.isArray(map[key])) {
           if (Array.isArray(map[key])) {
             list = list.concat(map[key])
             list = list.concat(map[key])
           }
           }
         }
         }
       }
       }
-      this.areaList = list
+      this.proviceList = list
     },
     },
-    onClose(f = false) {
-      this.$emit('change', f)
+    // 获取付费用户订阅设置信息
+    async getVipUserInfo() {
+      const { productType } = this.subInfo
+      const { success, data } = await getSVIPBuyInfo()
+      if (success) {
+        this.subUserInfo = data
+        if (productType === 'vip') {
+          this.areaInfo.buyAreaCount = data?.buyset?.areacount || -1
+        }
+        else {
+          this.areaInfo.buyAreaCount = -1
+        }
+      }
     },
     },
     popupConfirm() {
     popupConfirm() {
       const { areaPicker } = this.$refs
       const { areaPicker } = this.$refs
       const value = areaPicker.getValues()
       const value = areaPicker.getValues()
+      const freeArea = {
+        [value[0]]: []
+      }
+      this.cacheMoreFilters.area = freeArea
+      console.log('value', value)
       this.areaSelected = value[0]
       this.areaSelected = value[0]
       this.areaPickerShow = false
       this.areaPickerShow = false
     },
     },
+    // 超出省份提示
+    onAreaBeforeChange(parent) {
+      console.log('parent', parent)
+      const { buyAreaCount } = this.areaInfo
+      // 全国(无限制)
+      if (buyAreaCount < 0) {
+        return true
+      }
+      else {
+        // 非全国(省份有限制)
+        if (parent.parentName && parent.parentName === '全国') {
+          this.showVipLimit = true
+          return false
+        }
+        else {
+          if (this.selectedCount >= buyAreaCount) {
+            // 已选择过的省份列表
+            const selectedProvinceList = []
+            const sourceFirstCount
+              = this.$refs.areaSelector.sourceFirstCount || []
+            for (const key in sourceFirstCount) {
+              selectedProvinceList.push(key)
+            }
+            // 已经选中过的可勾选掉
+            if (
+              parent.parentName
+              && selectedProvinceList.includes(parent.parentName)
+            ) {
+              return true
+            }
+            else {
+              this.showVipLimit = true
+              return false
+            }
+          }
+          else {
+            return true
+          }
+        }
+      }
+    },
+
+    // 回显访问信息地址
+    setStateArea() {
+      const { area, productType } = this.subInfo
+      if (productType === 'free') {
+        if (area && Object.keys(area).length) {
+          this.areaSelected = Object.keys(area)[0]
+          const freeArea = {
+            [this.areaSelected]: []
+          }
+          this.cacheMoreFilters.area = freeArea
+        }
+      }
+      else {
+        if (area && Object.keys(area).length) {
+          this.areaSelected = this.getLastLevelNames(area)
+          this.$refs.areaSelector.setState(area)
+          this.cacheMoreFilters.area = this.mergeAreaObjects(
+            this.cacheMoreFilters.area,
+            area
+          )
+        }
+      }
+    },
+    mergeAreaObjects(obj1, obj2) {
+      const mergedObj = { ...obj1 } // 复制第一个对象
+
+      // 遍历第二个对象的省份
+      for (const province in obj2) {
+        if (!mergedObj[province]) {
+          mergedObj[province] = {} // 如果第一个对象中没有这个省份,则创建一个空对象
+        }
+
+        // 遍历第二个对象的城市
+        for (const city in obj2[province]) {
+          if (!mergedObj[province][city]) {
+            mergedObj[province][city] = [] // 如果第一个对象中没有这个城市,则创建一个空数组
+          }
+        }
+      }
+
+      return mergedObj
+    },
+    transformAreaObject(areaObj) {
+      const provinceCities = {}
+      const cityDistricts = {}
+
+      // 遍历省份
+      for (const province in areaObj) {
+        // 存储省份和城市列表
+        provinceCities[province] = Object.keys(areaObj[province])
+
+        // 遍历城市
+        for (const city in areaObj[province]) {
+          // 如果城市有区域信息,则存储
+          if (
+            Array.isArray(areaObj[province][city])
+            && areaObj[province][city].length > 0
+          ) {
+            cityDistricts[city] = areaObj[province][city]
+          }
+        }
+      }
+
+      return { provinceCities, cityDistricts }
+    },
+    // 跳转到订阅设置
+    toSubSetting() {
+      const { inWX } = this.$envs
+      if (inWX) {
+        location.href = '/front/vipsubscribe/toSubVipSetPage#tipover'
+      }
+      else {
+        location.href = '/jyapp/vipsubscribe/toSubVipSetPage#tipover'
+      }
+    },
+    subConfirmEvent() {
+      const { productType } = this.subInfo
+
+      const items = this.formatKeywords(this.keyList)
+      let params = {}
+      if (productType !== 'free') {
+        const { provinceCities, cityDistricts } = this.transformAreaObject(
+          this.cacheMoreFilters.area
+        )
+        params = {
+          area: provinceCities,
+          district: cityDistricts,
+          items,
+          iSwitch: 1
+        }
+      }
+      else {
+        params = {
+          area: this.cacheMoreFilters.area,
+          items,
+          iSwitch: 1
+        }
+      }
+      this.$emit('confirm', params)
+    },
+    // 设置关键词格式
+    formatKeywords(arr) {
+      const aKeyItems = arr.map(item => ({
+        appendkey: [],
+        key: [item],
+        matchway: 1,
+        notkey: [],
+        updatetime: new Date().getTime() / 1000
+      }))
+
+      const result = [
+        {
+          a_key: aKeyItems,
+          s_item: '未分类',
+          updatetime: new Date().getTime() / 1000
+        }
+      ]
+
+      return result
+    },
+    setAreaType() {
+      // const { inWX } = this.$envs
+      // const link = inWX
+      //   ? '/areaPack/wx/page/set_area?sub=simple'
+      //   : '/jyapp/areaPack/page/set_area?sub=simple'
+      const { positionType, productType } = this.subInfo
+      if (positionType === 0) {
+        if (productType === 'free') {
+          // this.$emit('saveAreaDialog')
+          // sessionStorage.setItem('JY-MOBILE-bidding-subscribe', JSON.stringify(this.$data))
+          // location.href = link
+          this.areaPickerShow = true
+        }
+        else {
+          this.areaCascaderPickerShow = true
+          setTimeout(() => {
+            this.$refs.areaSelector.setState(this.cacheMoreFilters.area)
+          }, 1000)
+        }
+      }
+    },
+    onAddKey() {
+      if (!this.productSelected)
+        return
+      this.setKeyListFun(this.productSelected)
+    },
+    setKeyListFun(value) {
+      // 判断关键词是否已经添加过
+      if (this.keyList.includes(value)) {
+        this.$toast('关键词已添加过')
+        this.productSelected = ''
+        return
+      }
+      const { productType } = this.subInfo
+      if (productType === 'free') {
+        if (this.keyList.length >= 10) {
+          this.$toast('关键词数量不能超过10个')
+          this.productSelected = ''
+          return
+        }
+        if (value.includes(' ')) {
+          const newKeys = value.split(' ')
+          const remainingSlots = 10 - this.keyList.length
+          const keysToAdd = newKeys.slice(0, remainingSlots)
+
+          // 添加新关键词
+          this.keyList = [...this.keyList, ...keysToAdd]
+        }
+        else {
+          this.keyList.push(value)
+        }
+        this.productSelected = ''
+      }
+      else {
+        if (this.keyList.length > 300) {
+          this.$toast('关键词数量不能超过300个')
+          this.productSelected = ''
+          return
+        }
+        this.keyList.push(value)
+        this.productSelected = ''
+      }
+    },
+    onDeleteKey(item) {
+      const index = this.keyList.indexOf(item)
+      if (index > -1) {
+        this.keyList.splice(index, 1)
+      }
+    },
+    onAreaChanged(data) {
+      console.info(data, 'value', this.cacheMoreFilters.area)
+    },
+    getLastLevelNames(obj) {
+      const names = []
+
+      for (const province in obj) {
+        const provinceInfo = obj[province]
+        // 如果省下面直接是空对象,说明只有省
+        if (!Object.keys(provinceInfo).length) {
+          names.push(province)
+        }
+        else {
+          // 如果省下面有市
+          for (const city in provinceInfo) {
+            const cityInfo = provinceInfo[city]
+            // 如果市下面直接是空数组或空对象,说明只有市
+            if ((Array.isArray(cityInfo) && cityInfo.length === 0)) {
+              names.push(city)
+            }
+            else if (Array.isArray(cityInfo)) {
+              // 如果市下面有区
+              cityInfo.forEach((district) => {
+                if (typeof district === 'string') {
+                  names.push(district)
+                }
+              })
+            }
+          }
+        }
+      }
+
+      return names.join('、')
+    },
+
+    areaDataInit(data) {
+      let areaData = []
+      // 获取data的最后一级
+      const provinceArr = Object.keys(data)
+      if (provinceArr.length) {
+        provinceArr.forEach((item) => {
+          const cityArr = Object.keys(data[item])
+          if (cityArr.length) {
+            cityArr.forEach((city) => {
+              const districtArr = data[item][city]
+              if (districtArr.length) {
+                areaData = areaData.concat(districtArr)
+              }
+              else {
+                areaData.push(city)
+              }
+            })
+          }
+          else {
+            areaData.push(item)
+          }
+        })
+      }
+      console.log(areaData, 'areaData')
+
+      return areaData.join('、')
+    },
+    onNoPower() {
+      this.$emit('noPower')
+    },
+    onReset() {
+      this.cacheMoreFilters.area = {}
+      this.areaSelected = ''
+      this.areaCascaderPickerShow = false
+    },
+    onConfirm() {
+      this.areaSelected = this.areaDataInit(this.cacheMoreFilters.area)
+      this.areaCascaderPickerShow = false
+    },
+    onClose(f = false) {
+      this.$emit('change', f)
+    },
     async beforeClose(action, done) {
     async beforeClose(action, done) {
       if (action === 'confirm') {
       if (action === 'confirm') {
         if (this.disabledConfirm) {
         if (this.disabledConfirm) {
           return done(false)
           return done(false)
-        } else {
+        }
+        else {
           // 一键订阅
           // 一键订阅
           await this.oneKeySub(true)
           await this.oneKeySub(true)
           done()
           done()
         }
         }
-      } else {
+      }
+      else {
         // 暂不订阅
         // 暂不订阅
         await this.oneKeySub(false)
         await this.oneKeySub(false)
         done()
         done()
@@ -164,14 +661,16 @@ export default {
     async oneKeySub(type = false) {
     async oneKeySub(type = false) {
       const params = {}
       const params = {}
       if (type) {
       if (type) {
-        if (!this.keywords) return this.$toast('订阅关键词不能为空')
+        if (!this.keywords)
+          return this.$toast('订阅关键词不能为空')
         Object.assign(params, {
         Object.assign(params, {
           isNoSubscribe: 'Y', // 一键订阅
           isNoSubscribe: 'Y', // 一键订阅
           subsequentPrompt: this.remindChecked ? 'Y' : 'N',
           subsequentPrompt: this.remindChecked ? 'Y' : 'N',
           key: this.keywords.replace(/\s+/g, ''),
           key: this.keywords.replace(/\s+/g, ''),
           area: this.areaSelected
           area: this.areaSelected
         })
         })
-      } else {
+      }
+      else {
         Object.assign(params, {
         Object.assign(params, {
           isNoSubscribe: 'N', // 暂不订阅
           isNoSubscribe: 'N', // 暂不订阅
           subsequentPrompt: this.remindChecked ? 'Y' : 'N'
           subsequentPrompt: this.remindChecked ? 'Y' : 'N'
@@ -190,11 +689,13 @@ export default {
             this.onClose(false)
             this.onClose(false)
             this.$toast('订阅关键词成功')
             this.$toast('订阅关键词成功')
           }
           }
-        } else {
+        }
+        else {
           // 一键订阅失败
           // 一键订阅失败
           this.onClose(false)
           this.onClose(false)
         }
         }
-      } else {
+      }
+      else {
         if (msg) {
         if (msg) {
           this.$toast(msg)
           this.$toast(msg)
         }
         }
@@ -204,6 +705,7 @@ export default {
   }
   }
 }
 }
 </script>
 </script>
+
 <style lang="scss" scoped>
 <style lang="scss" scoped>
 .disabled-confirm {
 .disabled-confirm {
   ::v-deep {
   ::v-deep {
@@ -214,23 +716,108 @@ export default {
     }
     }
   }
   }
 }
 }
+.van-dialog.j-confirm-dialog {
+  max-width: 327px;
+  width: 327px;
+  border-radius: 12px;
+  ::v-deep {
+    .van-dialog__header {
+      padding: 24px 16px 14px;
+    }
+  }
+  .j-button-group {
+    padding: 12px 16px;
+    .j-button-confirm {
+      background: #2abed1;
+      color: #f7f9fa;
+      font-size: 16px;
+      font-weight: 400;
+      border: none;
+    }
+  }
+}
+.subscribe-title {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  & > span {
+    font-size: 18px;
+    font-weight: 400;
+  }
+}
 .content {
 .content {
-  padding: 8px 30px;
+  padding: 0 16px 8px;
+  border-bottom: 0.5px solid rgba(0, 0, 0, 0.05);
 }
 }
+.content-item {
+  .keys-list {
+    display: flex;
+    flex-wrap: wrap;
+    margin-top: 8px;
+    .keys-item {
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      margin-right: 8px;
+      margin-bottom: 8px;
+      padding: 4px 8px;
+      border-radius: 4px;
+      background: #f5f6f7;
+      .keys-text {
+        margin-right: 4px;
+        font-size: 11px;
+        color: #5f5e64;
+        line-height: 16px;
+      }
+    }
+  }
+}
+
 .content-header {
 .content-header {
-  font-size: 15px;
+  font-size: 14px;
   color: #5f5e64;
   color: #5f5e64;
-  line-height: 22px;
+  line-height: 20px;
   text-align: justify;
   text-align: justify;
 }
 }
 .content-body {
 .content-body {
-  margin-top: 16px;
-  font-size: 15px;
-  color: #5f5e64;
-  line-height: 22px;
+  margin-top: 8px;
+  font-size: 13px;
+  color: #171826;
+  line-height: 20px;
   text-align: justify;
   text-align: justify;
   border: 1px solid rgba(0, 0, 0, 0.1);
   border: 1px solid rgba(0, 0, 0, 0.1);
   border-radius: 4px;
   border-radius: 4px;
+  .van-cell {
+    padding: 4px 12px;
+    height: 32px;
+    ::v-deep {
+      .van-field__control::placeholder {
+        font-size: 13px;
+      }
+    }
+  }
+  &.product-field {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    border: none;
+    .van-cell {
+      flex: 1;
+      border: 1px solid rgba(0, 0, 0, 0.1);
+      border-radius: 4px;
+    }
+    .j-add-product {
+      margin-left: 8px;
+      padding: 0;
+      width: 50px;
+      height: 32px;
+      font-size: 13px;
+      line-height: 20px;
+      .van-button--disabled {
+        color: #87dfe9;
+      }
+    }
+  }
 }
 }
 .content-footer {
 .content-footer {
   margin: 24px 0 8px;
   margin: 24px 0 8px;
@@ -241,4 +828,59 @@ export default {
     }
     }
   }
   }
 }
 }
+.subscribe-tip {
+  margin-top: 24px;
+  font-size: 13px;
+  color: #686868;
+  & > span {
+    color: #2abed1;
+  }
+}
+.area-cascader-picker {
+  ::v-deep {
+    .j-header {
+      z-index: 0;
+    }
+  }
+  .j-header-content {
+    padding: 22px 16px 12px;
+    flex-direction: column;
+    align-items: flex-start;
+    color: #171826;
+    .title-row {
+      width: 100%;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      font-size: 20px;
+      line-height: 30px;
+      margin-bottom: 12px;
+    }
+    .count-row {
+      font-size: 14px;
+      strong {
+        color: #2abdd1;
+      }
+    }
+  }
+}
+.vip-limit-dialog {
+  ::v-deep {
+    .van-dialog__header {
+      font-size: 20px;
+      color: #171826;
+    }
+    .van-dialog__content {
+      padding: 16px;
+      color: #5F5E64;
+      line-height: 22px;
+      font-size: 15px;
+    }
+  }
+}
+::v-deep {
+  .vip-limit-dialog-overlay {
+    background: rgba(0, 0, 0, 0.2);
+  }
+}
 </style>
 </style>

+ 0 - 3
apps/mobile/src/components/search/sun/filters.vue

@@ -704,9 +704,6 @@ export default {
       console.log(error)
       console.log(error)
     }
     }
   },
   },
-  created() {
-    window.t = this
-  },
   methods: {
   methods: {
     getContainer() {
     getContainer() {
       return this.$root.$el.querySelector('.search-result-bidding')
       return this.$root.$el.querySelector('.search-result-bidding')

+ 8 - 0
apps/mobile/src/router/modules/course.js

@@ -0,0 +1,8 @@
+// 静态路由
+export default [
+  {
+    path: '/index',
+    name: 'index',
+    component: () => import('@/views/coursePage/Index.vue')
+  }
+]

+ 31 - 15
apps/mobile/src/store/modules/article.js

@@ -1,12 +1,12 @@
-import { appStorage } from '@/utils/storage'
 import { cloneDeep } from 'lodash'
 import { cloneDeep } from 'lodash'
 import useContentModel from '@jy/data-models/modules/article/model/content'
 import useContentModel from '@jy/data-models/modules/article/model/content'
 import useExpandModel from '@jy/data-models/modules/article/model/expand'
 import useExpandModel from '@jy/data-models/modules/article/model/expand'
+import { appStorage } from '@/utils/storage'
 
 
 import {
 import {
   getArticleAdvancedInfo,
   getArticleAdvancedInfo,
-  getArticlePreAgentInfo,
-  getArticleBaseInfo
+  getArticleBaseInfo,
+  getArticlePreAgentInfo
 } from '@/api/modules/article'
 } from '@/api/modules/article'
 
 
 const { model: mainModel, transformModel: contentTransform } = useContentModel()
 const { model: mainModel, transformModel: contentTransform } = useContentModel()
@@ -37,7 +37,8 @@ const defaultValueMap = {
     inBiddingPersonList: []
     inBiddingPersonList: []
   },
   },
   mainModel,
   mainModel,
-  expandModel
+  expandModel,
+  bindPhone: false
   // mainModel: {
   // mainModel: {
   //   content: {
   //   content: {
   //     id: '', // ABCY1xFfylYGSY7I2Bhc3ISCzAoIyFmYXh1KSgwNi8NaGpzZg1UCbM%3D
   //     id: '', // ABCY1xFfylYGSY7I2Bhc3ISCzAoIyFmYXh1KSgwNi8NaGpzZg1UCbM%3D
@@ -110,7 +111,8 @@ export default {
     resetState(state, resetKey) {
     resetState(state, resetKey) {
       if (resetKey) {
       if (resetKey) {
         state[resetKey] = cloneDeep(defaultValueMap[resetKey]) || {}
         state[resetKey] = cloneDeep(defaultValueMap[resetKey]) || {}
-      } else {
+      }
+      else {
         const keysArr = Object.keys(state)
         const keysArr = Object.keys(state)
         keysArr.forEach((key) => {
         keysArr.forEach((key) => {
           state[key] = cloneDeep(defaultValueMap[key]) || {}
           state[key] = cloneDeep(defaultValueMap[key]) || {}
@@ -149,6 +151,9 @@ export default {
     },
     },
     setOtherModelChild(state, { key, data }) {
     setOtherModelChild(state, { key, data }) {
       state.otherModel[key] = data
       state.otherModel[key] = data
+    },
+    setBaseInfoBindPhone(state, payload) {
+      state.bindPhone = payload
     }
     }
   },
   },
   actions: {
   actions: {
@@ -169,7 +174,8 @@ export default {
         let same = false
         let same = false
         try {
         try {
           same = thisId === storage.mainModel?.content?.id
           same = thisId === storage.mainModel?.content?.id
-        } catch (error) {
+        }
+        catch (error) {
           console.log(error)
           console.log(error)
           same = false
           same = false
         }
         }
@@ -191,7 +197,8 @@ export default {
         // 如果缓存存在
         // 如果缓存存在
         storage[id] = state
         storage[id] = state
         appStorage.set(CACHE_HISTORY_KEY, storage, storageConf)
         appStorage.set(CACHE_HISTORY_KEY, storage, storageConf)
-      } else {
+      }
+      else {
         // 无缓存
         // 无缓存
         const storageNew = {
         const storageNew = {
           [id]: state
           [id]: state
@@ -211,7 +218,8 @@ export default {
       }
       }
       if (storage) {
       if (storage) {
         return storage[id]
         return storage[id]
-      } else {
+      }
+      else {
         return null
         return null
       }
       }
     },
     },
@@ -243,10 +251,12 @@ export default {
         } = await getArticlePreAgentInfo()
         } = await getArticlePreAgentInfo()
         if (code === 0 && data) {
         if (code === 0 && data) {
           commit('setPreAgentInfo', data)
           commit('setPreAgentInfo', data)
-        } else {
+        }
+        else {
           console.log(msg)
           console.log(msg)
         }
         }
-      } catch (error) {
+      }
+      catch (error) {
         console.error(error)
         console.error(error)
       }
       }
     },
     },
@@ -262,18 +272,22 @@ export default {
           const r = contentTransform(data)
           const r = contentTransform(data)
           commit('setMainContentModel', r)
           commit('setMainContentModel', r)
           commit('setBaseInfoReqToken', data.token)
           commit('setBaseInfoReqToken', data.token)
-        } else {
+          commit('setBaseInfoBindPhone', data.bindPhone)
+        }
+        else {
           console.log(msg)
           console.log(msg)
         }
         }
         return { data, msg }
         return { data, msg }
-      } catch (error) {
+      }
+      catch (error) {
         console.error(error)
         console.error(error)
       }
       }
     },
     },
     async getAdvancedInfo({ commit, state }) {
     async getAdvancedInfo({ commit, state }) {
       const { reqInfo } = state
       const { reqInfo } = state
       const token = reqInfo.baseInfoReqToken
       const token = reqInfo.baseInfoReqToken
-      if (!token) return
+      if (!token)
+        return
       try {
       try {
         const {
         const {
           error_code: code,
           error_code: code,
@@ -283,10 +297,12 @@ export default {
         if (code === 0 && data) {
         if (code === 0 && data) {
           const r = expandTransform(data)
           const r = expandTransform(data)
           commit('setExpandModel', r)
           commit('setExpandModel', r)
-        } else {
+        }
+        else {
           console.log(msg)
           console.log(msg)
         }
         }
-      } catch (error) {
+      }
+      catch (error) {
         console.error(error)
         console.error(error)
       }
       }
     }
     }

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

@@ -283,3 +283,63 @@ export function appShare(
     console.warn('error: app call share', e)
     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)
+  }
+}

+ 18 - 11
apps/mobile/src/utils/mixins/modules/app-wx-share.js

@@ -28,7 +28,10 @@ export const appWxShareMixin = {
         wx: ''
         wx: ''
       },
       },
       shareEnableConf: {
       shareEnableConf: {
+        // 是否进入页面立即初始化分享流程
         shareActionImmediate: true,
         shareActionImmediate: true,
+        // 是否进入页面立即获取配置域名
+        getDomainImmediate: false,
         app: true, // 开启app分享
         app: true, // 开启app分享
         wx: true // 开启wx分享
         wx: true // 开启wx分享
       },
       },
@@ -46,6 +49,8 @@ export const appWxShareMixin = {
     console.log('app-wx-share')
     console.log('app-wx-share')
     if (this.shareEnableConf.shareActionImmediate) {
     if (this.shareEnableConf.shareActionImmediate) {
       this.initShareMixin()
       this.initShareMixin()
+    } else if (this.shareEnableConf.getDomainImmediate) {
+      this.getShareDomain()
     }
     }
   },
   },
   methods: {
   methods: {
@@ -55,7 +60,7 @@ export const appWxShareMixin = {
       } else {
       } else {
         if (this.shareEnableConf.app) {
         if (this.shareEnableConf.app) {
           if (this.shareConf.fetchDomain) {
           if (this.shareConf.fetchDomain) {
-            this.getShareDomain()
+            this.getShareDomain(true)
           } else {
           } else {
             this.refreshShareLink()
             this.refreshShareLink()
             this.registerWxShare()
             this.registerWxShare()
@@ -63,22 +68,24 @@ export const appWxShareMixin = {
         }
         }
       }
       }
     },
     },
-    refreshShareLink() {
+    refreshShareLink(origin) {
       if (!this.shareConf.pathname) return
       if (!this.shareConf.pathname) return
-      this.shareConf.link = this.shareConf.origin + this.shareConf.pathname
+      const originLink = origin || this.shareConf.origin
+      this.shareConf.link = originLink + this.shareConf.pathname
     },
     },
-    async getShareDomain() {
+    async getShareDomain(init = false) {
       const { data, error_code: code, error_msg: msg } = await getAppsDomain()
       const { data, error_code: code, error_msg: msg } = await getAppsDomain()
-      console.log(msg)
       if (code === 0 && data) {
       if (code === 0 && data) {
         // app往微信分享会用到(app分享到微信,需要分享微信的域名)
         // app往微信分享会用到(app分享到微信,需要分享微信的域名)
         Object.assign(this.domainConf, data)
         Object.assign(this.domainConf, data)
-        if (data.wx) {
-          this.shareConf.origin = data.wx
-          this.refreshShareLink()
-        }
-        if (this.isWeiXinBrowser) {
-          this.registerWxShare()
+        if (init) {
+          if (data.wx) {
+            this.shareConf.origin = data.wx
+            this.refreshShareLink()
+          }
+          if (this.isWeiXinBrowser) {
+            this.registerWxShare()
+          }
         }
         }
       }
       }
     },
     },

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

@@ -0,0 +1,377 @@
+import { PhoneNumberServer } from 'aliyun_numberauthsdk_web'
+import { envs } from '@/utils/prototype/modules/platform'
+import { getAuthToken, getPhoneByToken } from '@/api/modules/'
+import { appGetPhoneBind } from '@/utils/callFn/appFn'
+
+const phoneNumberServer = new PhoneNumberServer()
+
+const fLogin = {
+  methods: {
+    getPrePayload() {
+      return {
+        actionType: 'B'
+      }
+    },
+    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, 2000)
+          }
+          else {
+            if (payload.actionType === 'B') {
+              this.$toast('绑定失败', 2000)
+            }
+            else {
+              this.$toast('登录失败', 2000)
+            }
+          }
+        }
+      }
+      this.loadingClear()
+      this.enableToast()
+    },
+    doPhoneFastLoginSuccess(data) {
+      console.log(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 fastBindConfApp = {
+  mixins: [loadingMixin, toastMixin, fLogin],
+  data() {
+    return {
+      tokenInfo: {
+        accessToken: '',
+        outId: '',
+        requestId: '',
+        venderName: ''
+      }
+    }
+  },
+  created() {
+    window.getPhoneBindCallback = this.getPhoneBindCallback
+  },
+  methods: {
+    getPrePayload() {
+      return {
+        actionType: 'B'
+      }
+    },
+    doPhoneFastLoginSuccess(data) {
+      if (data) {
+        this.bindPhoneSuccess(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 fastBindConfH5 = {
+  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 fastBind = envs.inApp ? fastBindConfApp : fastBindConfH5
+export default fastBind

+ 75 - 14
apps/mobile/src/views/article/content.vue

@@ -10,17 +10,34 @@
       <div v-else class="j-container page-container">
       <div v-else class="j-container page-container">
         <div
         <div
           class="j-main article-content-main"
           class="j-main article-content-main"
-          :class="{ 'show-underline': otherModel.hasProject }"
+          :class="{
+            'show-underline': otherModel.hasProject,
+            'no-scroll': showBindPhone
+          }"
           @click="onScrollWrapperClick"
           @click="onScrollWrapperClick"
           ref="scrollWrapper"
           ref="scrollWrapper"
           @scroll.passive="onScroll"
           @scroll.passive="onScroll"
         >
         >
-          <ContentHeader :beforeLeavePage="beforeLeavePage"></ContentHeader>
+          <ContentHeader
+            :class="{ 'z-index10': showBindPhone }"
+            :beforeLeavePage="beforeLeavePage"
+          ></ContentHeader>
           <ContentHeaderBannerTip
           <ContentHeaderBannerTip
+            :class="{ 'z-index10': showBindPhone }"
             :id="pageState.id"
             :id="pageState.id"
             :beforeLeavePage="beforeLeavePage"
             :beforeLeavePage="beforeLeavePage"
             v-if="showContentHeaderBannerTip"
             v-if="showContentHeaderBannerTip"
           ></ContentHeaderBannerTip>
           ></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
           <van-tabs
             v-if="canReadConf.show"
             v-if="canReadConf.show"
             v-model="pageState.tabActive"
             v-model="pageState.tabActive"
@@ -36,7 +53,10 @@
                   class="content-abstract-module"
                   class="content-abstract-module"
                   :beforeLeavePage="beforeLeavePage"
                   :beforeLeavePage="beforeLeavePage"
                 />
                 />
-                <section class="content-abstract-other bg-white" v-if="!IsSunPublishContent">
+                <section
+                  class="content-abstract-other bg-white"
+                  v-if="!IsSunPublishContent"
+                >
                   <ContentAbstractEntList
                   <ContentAbstractEntList
                     v-if="!IsCustomTopNet"
                     v-if="!IsCustomTopNet"
                     class="content-abstract-ent-list-module"
                     class="content-abstract-ent-list-module"
@@ -124,7 +144,10 @@
           />
           />
         </div>
         </div>
         <div class="j-footer article-content-footer">
         <div class="j-footer article-content-footer">
-          <TabActions :beforeLeavePage="beforeLeavePage" v-if="showTabActions" />
+          <TabActions
+            :beforeLeavePage="beforeLeavePage"
+            v-if="showTabActions"
+          />
         </div>
         </div>
       </div>
       </div>
     </van-skeleton>
     </van-skeleton>
@@ -157,7 +180,7 @@
   </div>
   </div>
 </template>
 </template>
 <script>
 <script>
-import { Tabs, Tab, Icon, Skeleton } from 'vant'
+import { Tabs, Tab, Icon, Skeleton, Overlay } from 'vant'
 import { mixinHeader } from '@/utils/mixins/header'
 import { mixinHeader } from '@/utils/mixins/header'
 import { appWxShareMixin } from '@/utils/mixins/modules/app-wx-share'
 import { appWxShareMixin } from '@/utils/mixins/modules/app-wx-share'
 import { isElementInScrollArea, checkAncestorClass } from '@jy/util'
 import { isElementInScrollArea, checkAncestorClass } from '@jy/util'
@@ -180,6 +203,7 @@ import ThirdPartyVerifyPopup from '@/views/article/components/ThirdPartyVerifyPo
 import CheckUserDialog from '@/views/identity/components/CheckUserDialog'
 import CheckUserDialog from '@/views/identity/components/CheckUserDialog'
 import CustomerCorner from '@/components/customer/index'
 import CustomerCorner from '@/components/customer/index'
 import Error from '@/views/article/components/Error.vue'
 import Error from '@/views/article/components/Error.vue'
+import OneClickBinding from '@/components/one-click-binding/index'
 import { throttle } from 'lodash'
 import { throttle } from 'lodash'
 import { mapState, mapMutations, mapActions, mapGetters } from 'vuex'
 import { mapState, mapMutations, mapActions, mapGetters } from 'vuex'
 import {
 import {
@@ -198,6 +222,7 @@ export default {
     [Tab.name]: Tab,
     [Tab.name]: Tab,
     [Icon.name]: Icon,
     [Icon.name]: Icon,
     [Skeleton.name]: Skeleton,
     [Skeleton.name]: Skeleton,
+    [Overlay.name]: Overlay,
     ContentHeader,
     ContentHeader,
     ContentHeaderBannerTip,
     ContentHeaderBannerTip,
     ContentAbstract,
     ContentAbstract,
@@ -216,9 +241,11 @@ export default {
     TabActions,
     TabActions,
     AdSingle,
     AdSingle,
     CustomerCorner,
     CustomerCorner,
-    Error
+    Error,
+    OneClickBinding
   },
   },
   data() {
   data() {
+    const { inApp } = this.$envs
     return {
     return {
       pageLayoutConf: {
       pageLayoutConf: {
         actionRightStyle: {
         actionRightStyle: {
@@ -232,6 +259,7 @@ export default {
       },
       },
       shareEnableConf: {
       shareEnableConf: {
         shareActionImmediate: false,
         shareActionImmediate: false,
+        getDomainImmediate: inApp,
         app: true, // 开启app分享
         app: true, // 开启app分享
         wx: true // 开启wx分享
         wx: true // 开启wx分享
       },
       },
@@ -298,7 +326,8 @@ export default {
       summary: (state) => state.article.mainModel.summary,
       summary: (state) => state.article.mainModel.summary,
       mainModel: (state) => state.article.mainModel,
       mainModel: (state) => state.article.mainModel,
       expandModel: (state) => state.article.expandModel,
       expandModel: (state) => state.article.expandModel,
-      otherModel: (state) => state.article.otherModel
+      otherModel: (state) => state.article.otherModel,
+      bindPhone: (state) => state.article.bindPhone
     }),
     }),
     IsCustomTopNet() {
     IsCustomTopNet() {
       return this.content.IsCustomTopNet || false
       return this.content.IsCustomTopNet || false
@@ -329,12 +358,12 @@ export default {
       if (this.IsSunPublishContent) {
       if (this.IsSunPublishContent) {
         return {
         return {
           show: this.content.isCanRead, // 是否展示全部内容
           show: this.content.isCanRead, // 是否展示全部内容
-          showContentModule: this.hasPowerToReadSunPublishContent,
+          showContentModule: this.hasPowerToReadSunPublishContent
         }
         }
       } else {
       } else {
         return {
         return {
           show: this.content.isCanRead,
           show: this.content.isCanRead,
-          showContentModule: true,
+          showContentModule: true
         }
         }
       }
       }
     },
     },
@@ -354,12 +383,14 @@ export default {
       return this.mainModel.moduleShow
       return this.mainModel.moduleShow
     },
     },
     advancedModuleShow() {
     advancedModuleShow() {
-      const { tbService, customerRecommend, timeline, zbRecommend } = this.expandModel.moduleShow
+      const { tbService, customerRecommend, timeline, zbRecommend } =
+        this.expandModel.moduleShow
       return Object.assign({}, this.expandModel.moduleShow, {
       return Object.assign({}, this.expandModel.moduleShow, {
-        tbService: (this.IsCustomTopNet || this.IsSunPublishContent) ? false : tbService,
+        tbService:
+          this.IsCustomTopNet || this.IsSunPublishContent ? false : tbService,
         customerRecommend: this.IsSunPublishContent ? false : customerRecommend,
         customerRecommend: this.IsSunPublishContent ? false : customerRecommend,
         timeline: this.IsSunPublishContent ? false : timeline,
         timeline: this.IsSunPublishContent ? false : timeline,
-        zbRecommend: this.IsSunPublishContent ? false : zbRecommend,
+        zbRecommend: this.IsSunPublishContent ? false : zbRecommend
       })
       })
     },
     },
     // 客户推荐模块是否展示
     // 客户推荐模块是否展示
@@ -384,6 +415,18 @@ export default {
     getContentAdID() {
     getContentAdID() {
       const sun = this.IsSunPublishContent ? '-sun' : ''
       const sun = this.IsSunPublishContent ? '-sun' : ''
       return (this.$envs.inWX ? 'jy' : 'jyapp') + `${sun}-wxcontent-bottom`
       return (this.$envs.inWX ? 'jy' : 'jyapp') + `${sun}-wxcontent-bottom`
+    },
+    getContentAdID() {
+      return (this.$envs.inWX ? 'jy' : 'jyapp') + '-wxcontent-bottom'
+    },
+    // 是否展示绑定手机号弹窗
+    showBindPhone() {
+      const { wxpush } = this.$route?.query
+      return wxpush === 'bind' && this.$envs.inWX && !this.isBindPhone
+    },
+    // 从baseInfo获取是否绑定手机号(P607新增)
+    isBindPhone() {
+      return this.bindPhone
     }
     }
   },
   },
   async created() {
   async created() {
@@ -695,6 +738,8 @@ export default {
       contentList.push('向您推荐了剑鱼标讯')
       contentList.push('向您推荐了剑鱼标讯')
       const content = contentList.join('')
       const content = contentList.join('')
 
 
+      const shareToWx = shareType === 1 || shareType === 3
+
       let link = `/swordfish/about?source=app_infocontentshare&from=${
       let link = `/swordfish/about?source=app_infocontentshare&from=${
         this.shareInfoRes.userId || ''
         this.shareInfoRes.userId || ''
       }`
       }`
@@ -703,7 +748,9 @@ export default {
         .replace(/ /g, '')
         .replace(/ /g, '')
       if (shareType === 1) {
       if (shareType === 1) {
         // 分享给微信好友
         // 分享给微信好友
-        link = location.pathname.replace(import.meta.env.VITE_APP_BASE_URL, '')
+        link = location.pathname
+          .replace(import.meta.env.VITE_APP_BASE_URL, '')
+          .replace('/jyapp', '')
         if (location.search) {
         if (location.search) {
           link += `${location.search}&source=app_infocontentshare&from=${
           link += `${location.search}&source=app_infocontentshare&from=${
             this.shareInfoRes.userId || ''
             this.shareInfoRes.userId || ''
@@ -723,7 +770,11 @@ export default {
       this.shareConf.content = content
       this.shareConf.content = content
       this.shareConf.pathname = link
       this.shareConf.pathname = link
       // this.shareConf.link = link
       // this.shareConf.link = link
-      this.refreshShareLink()
+      if (this.$envs.inApp && shareToWx) {
+        this.refreshShareLink(this.domainConf.wx)
+      } else {
+        this.refreshShareLink()
+      }
     },
     },
     onScroll: throttle(function (e) {
     onScroll: throttle(function (e) {
       this.checkNpsView()
       this.checkNpsView()
@@ -833,6 +884,16 @@ export default {
   margin: 8px 16px;
   margin: 8px 16px;
   margin-bottom: 32px;
   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>
 <style>
 <style>
 .no-select {
 .no-select {

+ 71 - 0
apps/mobile/src/views/coursePage/Index.vue

@@ -0,0 +1,71 @@
+<template>
+  <div class="course-page">
+    <div class="course-1">
+      <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="" />
+      <div class="course-video video-1">
+        <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="" />
+      <div class="course-video video-2">
+        <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="" />
+      <div class="course-video video-3">
+        <video
+          preload="auto"
+          controls
+          src="@/assets/image/course-page/video-3.mp4"
+        />
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  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;
+      }
+    }
+  }
+}
+</style>

Plik diff jest za duży
+ 263 - 146
apps/mobile/src/views/search/result/bidding/index.vue


+ 40 - 23
apps/mobile/src/views/search/result/sun/index.vue

@@ -144,7 +144,9 @@
                   @click.stop="toToBuyerProfile(item.text)"
                   @click.stop="toToBuyerProfile(item.text)"
                   >{{ item.text }}</span
                   >{{ item.text }}</span
                 >
                 >
-                <span class="buyer-item link-clickable" v-else>{{ item.text }}</span>
+                <span class="buyer-item link-clickable" v-else>{{
+                  item.text
+                }}</span>
               </template>
               </template>
             </ProjectCell>
             </ProjectCell>
             <div
             <div
@@ -459,7 +461,7 @@ export default {
             name: 'detailedList',
             name: 'detailedList',
             cardType: 'detailed',
             cardType: 'detailed',
             needPower: true
             needPower: true
-          },
+          }
           // {
           // {
           //   title: '表格',
           //   title: '表格',
           //   name: 'table'
           //   name: 'table'
@@ -667,9 +669,9 @@ export default {
       }
       }
     },
     },
     getContentAdID() {
     getContentAdID() {
-      // const { inWX } = this.$envs
-      const { platform } = this.$env
-      return `${platform}-sunlightlist-search-middle`
+      const { inWX } = this.$envs
+      const prefix = inWX ? 'wx' : 'app'
+      return `${prefix}-sunlightlist-search-middle`
     },
     },
     savedFilterListCount() {
     savedFilterListCount() {
       return this.pageState.savedFilterList.length
       return this.pageState.savedFilterList.length
@@ -824,8 +826,8 @@ export default {
     // 历史筛选恢复会覆盖url参数
     // 历史筛选恢复会覆盖url参数
     this.restoreStateFromRouteParams()
     this.restoreStateFromRouteParams()
     this.calcInitFilters()
     this.calcInitFilters()
-    this.calcDropdownMenuMaxHeight()
     this.$nextTick(() => {
     this.$nextTick(() => {
+      this.calcDropdownMenuMaxHeight()
       const scrollWrap = this.$refs.listContainer
       const scrollWrap = this.$refs.listContainer
       scrollWrap.addEventListener('scroll', throttle(this.scrollWrapFn, 300))
       scrollWrap.addEventListener('scroll', throttle(this.scrollWrapFn, 300))
     })
     })
@@ -917,7 +919,9 @@ export default {
           filterDOM.getBoundingClientRect().top,
           filterDOM.getBoundingClientRect().top,
           filterDOM.clientHeight
           filterDOM.clientHeight
         )
         )
-        this.conf.maxHeight = `calc(100vh - ${domTop + h5Offset}px - ${noLoginTop}px)`
+        this.conf.maxHeight = `calc(100vh - ${
+          domTop + h5Offset
+        }px - ${noLoginTop}px)`
       }
       }
     },
     },
     initDefaultFilterState() {
     initDefaultFilterState() {
@@ -1150,12 +1154,24 @@ export default {
     },
     },
     async getList() {
     async getList() {
       const t = this.listState
       const t = this.listState
-      const { area: deliveryArea, city: deliveryCity, district:deliveryDistrict  } =
-        FilterHistoryViewModel2AjaxModel.formatAreaCity(this.filters.jfArea)
-      const { area: projectArea, city: projectCity, district:projectDistrict  } =
-        FilterHistoryViewModel2AjaxModel.formatAreaCity(this.filters.projectArea)
+      const {
+        area: deliveryArea,
+        city: deliveryCity,
+        district: deliveryDistrict
+      } = FilterHistoryViewModel2AjaxModel.formatAreaCity(this.filters.jfArea)
+      const {
+        area: projectArea,
+        city: projectCity,
+        district: projectDistrict
+      } = FilterHistoryViewModel2AjaxModel.formatAreaCity(
+        this.filters.projectArea
+      )
       const { moreKeywordsMode } = this.filters
       const { moreKeywordsMode } = this.filters
-      const { first: domainFirstType, second: domainSecondType, third: domainThirdType } = threeObjToSingle(this.filters.lingyu)
+      const {
+        first: domainFirstType,
+        second: domainSecondType,
+        third: domainThirdType
+      } = threeObjToSingle(this.filters.lingyu)
       // 整理wordsMode和additionalWords
       // 整理wordsMode和additionalWords
       let wordsMode
       let wordsMode
       let additionalWords
       let additionalWords
@@ -1232,7 +1248,7 @@ export default {
           data.isLimit === 1 ||
           data.isLimit === 1 ||
           data.isLimit === undefined ||
           data.isLimit === undefined ||
           data.isLimit === null
           data.isLimit === null
-          console.log(data)
+        console.log(data)
         if (code === 0 && data && isLimited) {
         if (code === 0 && data && isLimited) {
           // 判断是否为刷新
           // 判断是否为刷新
           if (t.refreshing) {
           if (t.refreshing) {
@@ -1421,7 +1437,7 @@ export default {
           ? item?.buyerClass
           ? item?.buyerClass
           : undefined
           : undefined
 
 
-          let signupEndTag = ''
+      let signupEndTag = ''
       if (item.signEndTime) {
       if (item.signEndTime) {
         const now = Date.now()
         const now = Date.now()
         const signupEnd = item.signEndTime * 1000 < now
         const signupEnd = item.signEndTime * 1000 < now
@@ -1467,7 +1483,9 @@ export default {
       if (item.buyerPerson === markText || item.buyerTel === markText) {
       if (item.buyerPerson === markText || item.buyerTel === markText) {
         buyerPersonTelText = markText
         buyerPersonTelText = markText
       } else {
       } else {
-        buyerPersonTelText = `${item.buyerPerson || ''} ${item.buyerTel || ''}`.trim()
+        buyerPersonTelText = `${item.buyerPerson || ''} ${
+          item.buyerTel || ''
+        }`.trim()
       }
       }
 
 
       // 详细列表数据
       // 详细列表数据
@@ -1500,13 +1518,13 @@ export default {
           splitter: ':',
           splitter: ':',
           text: item.deliveryLoc
           text: item.deliveryLoc
         }
         }
-      ].filter(r => !!r.text)
+      ].filter((r) => !!r.text)
     },
     },
     goToDetail(item) {
     goToDetail(item) {
       const { id, industry } = item
       const { id, industry } = item
       const query = {
       const query = {
-        from: 'sun',
-        keywords: this.pageState.splitKeys.join('+'),
+        fromlist: 'sun',
+        keywords: this.pageState.splitKeys.join('+')
       }
       }
       if (industry) {
       if (industry) {
         query.industry = industry
         query.industry = industry
@@ -1795,7 +1813,9 @@ export default {
     // 跳转采购单位画像
     // 跳转采购单位画像
     toToBuyerProfile(id) {
     toToBuyerProfile(id) {
       if (id === '点击查看') {
       if (id === '点击查看') {
-        return this.toLeaveInfoPage(`${this.$env.platform}_sunlightlist_viewdetails`)
+        return this.toLeaveInfoPage(
+          `${this.$env.platform}_sunlightlist_viewdetails`
+        )
       }
       }
       this.saveState()
       this.saveState()
       const { href } = this.$router.resolve({
       const { href } = this.$router.resolve({
@@ -2100,10 +2120,7 @@ export default {
       })
       })
     },
     },
     restoreSearchGroupFromLocal() {
     restoreSearchGroupFromLocal() {
-      const params = this.$storage.get(
-        SUN_SEARCH_GROUP_LAST_CACHE_KEY,
-        false
-      )
+      const params = this.$storage.get(SUN_SEARCH_GROUP_LAST_CACHE_KEY, false)
       if (params) {
       if (params) {
         this.pageState.searchGroup = params.searchGroup
         this.pageState.searchGroup = params.searchGroup
       }
       }

+ 91 - 45
apps/mobile/src/views/tabbar/Home.vue

@@ -1,19 +1,19 @@
 <template>
 <template>
   <div
   <div
+    ref="home-page"
     class="home"
     class="home"
+    :class="{ 'app-header-top': appHeaderTop }"
     @scroll="onScroll"
     @scroll="onScroll"
     @click.capture="doSave"
     @click.capture="doSave"
-    ref="home-page"
-    :class="{ 'app-header-top': appHeaderTop }"
   >
   >
     <!-- 头部广告位 -->
     <!-- 头部广告位 -->
-    <div class="header-exposure" v-if="isLogin"></div>
-    <h5 class="logo-title tabbar-header" v-if="isLogin">
+    <div v-if="isLogin" class="header-exposure" />
+    <h5 v-if="isLogin" class="logo-title tabbar-header">
       <div class="logo-img-container">
       <div class="logo-img-container">
         <img
         <img
           src="@/assets/image/public/logo-text-transparent-bg@2x.png"
           src="@/assets/image/public/logo-text-transparent-bg@2x.png"
           alt=""
           alt=""
-        />
+        >
       </div>
       </div>
     </h5>
     </h5>
     <!-- 搜索框 -->
     <!-- 搜索框 -->
@@ -35,30 +35,37 @@
     />
     />
     <div :class="{ 'home-content-container': isLogin }">
     <div :class="{ 'home-content-container': isLogin }">
       <!-- 金刚区广告位 -->
       <!-- 金刚区广告位 -->
-      <swipe-floor
+      <SwipeFloor
+        v-if="isLogin"
         class="swipe-floor"
         class="swipe-floor"
         :images="AD.floor"
         :images="AD.floor"
-        v-if="isLogin"
-      ></swipe-floor>
+      />
       <!-- 轮播广告位 -->
       <!-- 轮播广告位 -->
-      <swipe :images="AD.swipe" v-if="isLogin"></swipe>
+      <Swipe v-if="isLogin" :images="AD.swipe" />
       <!-- 内容区域 -->
       <!-- 内容区域 -->
       <!-- 消息 -->
       <!-- 消息 -->
-      <message-card></message-card>
+      <MessageCard />
       <!-- 最新标讯 -->
       <!-- 最新标讯 -->
-      <home-list
+      <HomeList
         ref="list"
         ref="list"
-        @bottomSetTip="bottomSetTip"
         :show-set-tip="showSetTip"
         :show-set-tip="showSetTip"
-      ></home-list>
+        @bottomSetTip="bottomSetTip"
+      />
     </div>
     </div>
     <!-- 侧边广告位 -->
     <!-- 侧边广告位 -->
     <!-- <ad-side :config="AD.side" :scroll-status="sideStatus" :bottom-position="hasBottomSetTip ? '22%' :'18%'"></ad-side> -->
     <!-- <ad-side :config="AD.side" :scroll-status="sideStatus" :bottom-position="hasBottomSetTip ? '22%' :'18%'"></ad-side> -->
-    <!--客服-->
-    <customer-corner
+    <!-- 客服 -->
+    <CustomerCorner
       :scroll-status="sideStatus"
       :scroll-status="sideStatus"
       :bottom-position="hasBottomSetTip ? '16%' : '12%'"
       :bottom-position="hasBottomSetTip ? '16%' : '12%'"
     />
     />
+    <!-- 招采 -->
+    <CustomerBid
+      v-show="isLogin && $envs.inWX && showTutorial"
+      bottom-position="19%"
+      :scroll-status="sideStatus"
+      @jumpBidPage="jumpBidPage"
+    />
     <!-- 弹窗广告位 -->
     <!-- 弹窗广告位 -->
     <AdPopScreen
     <AdPopScreen
       v-if="AD.full.pic"
       v-if="AD.full.pic"
@@ -85,8 +92,9 @@
     </div> -->
     </div> -->
   </div>
   </div>
 </template>
 </template>
+
 <script>
 <script>
-import { Button, Cell, Popup, Overlay, Image, Sticky } from 'vant'
+import { Button, Cell, Image, Overlay, Popup, Sticky } from 'vant'
 import { mapGetters } from 'vuex'
 import { mapGetters } from 'vuex'
 import { AppIcon } from '@/ui'
 import { AppIcon } from '@/ui'
 import AdPopScreen from '@/components/ad/pop-screen'
 import AdPopScreen from '@/components/ad/pop-screen'
@@ -98,20 +106,22 @@ import HotKeyList from '@/components/home/HotKeyList'
 import {
 import {
   ajaxGetAD,
   ajaxGetAD,
   ajaxGetNewUserAD,
   ajaxGetNewUserAD,
-  ajaxSetNewUserADRead
+  ajaxSetNewUserADRead,
+  getConfiguration
 } from '@/api/modules'
 } from '@/api/modules'
 import MessageCard from '@/components/message/message-card'
 import MessageCard from '@/components/message/message-card'
 import CustomerCorner from '@/components/customer/index'
 import CustomerCorner from '@/components/customer/index'
 import { adConfigFormatter } from '@/utils/format/modules/ad-formatter'
 import { adConfigFormatter } from '@/utils/format/modules/ad-formatter'
 import CheckUserDialog from '@/views/identity/components/CheckUserDialog'
 import CheckUserDialog from '@/views/identity/components/CheckUserDialog'
 import {
 import {
-  transferMethodsOfRefs,
-  openLinkOfOther,
   callHideTab,
   callHideTab,
-  checkHasGuideRecord
+  checkHasGuideRecord,
+  openLinkOfOther,
+  transferMethodsOfRefs
 } from '@/utils'
 } from '@/utils'
+import CustomerBid from '@/components/customerBid/index'
 import { appCallGetToken } from '@/utils/callFn/appFn'
 import { appCallGetToken } from '@/utils/callFn/appFn'
-import { LINKS, AdCode } from '@/data'
+import { AdCode, LINKS } from '@/data'
 import { checkAppUpdate } from '@/utils/callFn/checkUpdate'
 import { checkAppUpdate } from '@/utils/callFn/checkUpdate'
 import { mixinHeader } from '@/utils/mixins/header'
 import { mixinHeader } from '@/utils/mixins/header'
 import AdSingle from '@/components/ad/Ad'
 import AdSingle from '@/components/ad/Ad'
@@ -125,7 +135,6 @@ const ADUniqueID = AdCode.首页
 
 
 export default {
 export default {
   name: 'AppHome',
   name: 'AppHome',
-  mixins: [mixinHeader, setPageTdk],
   components: {
   components: {
     AdSingle,
     AdSingle,
     HotKeyList,
     HotKeyList,
@@ -136,6 +145,7 @@ export default {
     SwipeFloor,
     SwipeFloor,
     CheckUserDialog,
     CheckUserDialog,
     CustomerCorner,
     CustomerCorner,
+    CustomerBid,
     [Side.name]: Side,
     [Side.name]: Side,
     [Button.name]: Button,
     [Button.name]: Button,
     [Cell.name]: Cell,
     [Cell.name]: Cell,
@@ -145,6 +155,7 @@ export default {
     [AppIcon.name]: AppIcon,
     [AppIcon.name]: AppIcon,
     [Sticky.name]: Sticky
     [Sticky.name]: Sticky
   },
   },
+  mixins: [mixinHeader, setPageTdk],
   /**
   /**
    * 首页广告集
    * 首页广告集
    *  @typedef {object} AD 首页广告集
    *  @typedef {object} AD 首页广告集
@@ -199,7 +210,8 @@ export default {
       showBottomPop: false
       showBottomPop: false
     },
     },
     hasBottomSetTip: false,
     hasBottomSetTip: false,
-    showSetTip: false
+    showSetTip: false,
+    showTutorial: false
   }),
   }),
   computed: {
   computed: {
     ...mapGetters('user', ['isLogin']),
     ...mapGetters('user', ['isLogin']),
@@ -207,7 +219,8 @@ export default {
       const { inAppOrH5 } = this.$envs
       const { inAppOrH5 } = this.$envs
       if (this.isLogin) {
       if (this.isLogin) {
         return inAppOrH5
         return inAppOrH5
-      } else {
+      }
+      else {
         return false
         return false
       }
       }
     },
     },
@@ -235,6 +248,7 @@ export default {
   mounted() {
   mounted() {
     this.showNoLoginHeader()
     this.showNoLoginHeader()
     this.setPageTdk()
     this.setPageTdk()
+    this.getConfigurationApi()
   },
   },
   beforeRouteLeave(to, from, next) {
   beforeRouteLeave(to, from, next) {
     this.toggleMessagePopShow(false)
     this.toggleMessagePopShow(false)
@@ -276,7 +290,25 @@ export default {
     })
     })
   },
   },
   methods: {
   methods: {
-    checkShowToast () {
+    async getConfigurationApi() {
+      const { error_code: code, data } = await getConfiguration()
+      if (code === 0) {
+        const thisTime = Math.round(new Date() / 1000)
+        if (
+          thisTime >= data?.bulletFrameStart
+          && thisTime <= data?.bulletFrameEnd
+        ) {
+          this.showTutorial = true
+        }
+        else {
+          this.showTutorial = false
+        }
+      }
+    },
+    jumpBidPage() {
+      this.$router.push('/course/index')
+    },
+    checkShowToast() {
       const needToast = this.$route.query.toast
       const needToast = this.$route.query.toast
       switch (needToast) {
       switch (needToast) {
         case 'l': {
         case 'l': {
@@ -292,7 +324,9 @@ export default {
           break
           break
         }
         }
         case 'c': {
         case 'c': {
-          this.$toast('您已是剑鱼标讯注册用户,不符合领取条件,如有疑问请咨询客服 400-108-6670')
+          this.$toast(
+            '您已是剑鱼标讯注册用户,不符合领取条件,如有疑问请咨询客服 400-108-6670'
+          )
           break
           break
         }
         }
         default: {
         default: {
@@ -303,11 +337,11 @@ export default {
         }
         }
       }
       }
       if (needToast) {
       if (needToast) {
-        const query = { ... this.$route.query }
+        const query = { ...this.$route.query }
         delete query.toast
         delete query.toast
         setTimeout(() => {
         setTimeout(() => {
           this.$router.replace({
           this.$router.replace({
-            query: query
+            query
           })
           })
         }, 500)
         }, 500)
       }
       }
@@ -349,9 +383,11 @@ export default {
       }
       }
     },
     },
     checkCacheToSearch() {
     checkCacheToSearch() {
-      if (!this.isLogin) return false
+      if (!this.isLogin)
+        return false
       const { toSearch } = this.cacheState
       const { toSearch } = this.cacheState
-      if (!toSearch) return false
+      if (!toSearch)
+        return false
       this.cacheState.toSearch = false
       this.cacheState.toSearch = false
       this.toSearchFocus()
       this.toSearchFocus()
     },
     },
@@ -375,7 +411,7 @@ export default {
     },
     },
     doSaveToSearch() {
     doSaveToSearch() {
       this.$storage.set(
       this.$storage.set(
-        this._CACHE_KEY + 'cache',
+        `${this._CACHE_KEY}cache`,
         {
         {
           cacheState: this.cacheState
           cacheState: this.cacheState
         },
         },
@@ -385,10 +421,10 @@ export default {
       )
       )
     },
     },
     doRecoveryToSearch() {
     doRecoveryToSearch() {
-      const cache = this.$storage.get(this._CACHE_KEY + 'cache', false, {
+      const cache = this.$storage.get(`${this._CACHE_KEY}cache`, false, {
         storage: sessionStorage
         storage: sessionStorage
       })
       })
-      this.$storage.rm(this._CACHE_KEY + 'cache', {
+      this.$storage.rm(`${this._CACHE_KEY}cache`, {
         storage: sessionStorage
         storage: sessionStorage
       })
       })
       if (cache) {
       if (cache) {
@@ -413,7 +449,8 @@ export default {
           storage.data.newUserPopConfig.showBottomPop = false
           storage.data.newUserPopConfig.showBottomPop = false
           storage.data.AD.newUserPop = {}
           storage.data.AD.newUserPop = {}
           storage.data.AD.newUserPopOfBottom = {}
           storage.data.AD.newUserPopOfBottom = {}
-        } catch (e) {}
+        }
+        catch (e) {}
         Object.assign(this._data, storage.data)
         Object.assign(this._data, storage.data)
         this.$storage.rm(this._CACHE_KEY, {
         this.$storage.rm(this._CACHE_KEY, {
           login: true
           login: true
@@ -422,7 +459,8 @@ export default {
           this.$forceUpdate()
           this.$forceUpdate()
           this.$refs['home-page'].scrollTop = storage.top
           this.$refs['home-page'].scrollTop = storage.top
         })
         })
-      } else {
+      }
+      else {
         // 限制刷新频率
         // 限制刷新频率
         const nowTime = new Date().getTime()
         const nowTime = new Date().getTime()
         const maxUpdateTime = 5 * 1000
         const maxUpdateTime = 5 * 1000
@@ -492,7 +530,8 @@ export default {
      * @param codes
      * @param codes
      */
      */
     getAD() {
     getAD() {
-      if (!this.isLogin) return
+      if (!this.isLogin)
+        return
       // 获取消息悬浮信息
       // 获取消息悬浮信息
       this.toggleMessagePopShow(true)
       this.toggleMessagePopShow(true)
       // 获取新用户弹窗广告信息
       // 获取新用户弹窗广告信息
@@ -503,7 +542,7 @@ export default {
         // this.getPlatformAD.header,
         // this.getPlatformAD.header,
         this.getPlatformAD.swipe,
         this.getPlatformAD.swipe,
         this.getPlatformAD.floor
         this.getPlatformAD.floor
-      ].filter((v) => v)
+      ].filter(v => v)
       ajaxGetAD({
       ajaxGetAD({
         codes
         codes
       })
       })
@@ -522,18 +561,21 @@ export default {
 
 
             if (header.length) {
             if (header.length) {
               this.AD.header = header.map(adConfigFormatter)[0]
               this.AD.header = header.map(adConfigFormatter)[0]
-            } else {
+            }
+            else {
               this.AD.header = {}
               this.AD.header = {}
             }
             }
             if (full?.length) {
             if (full?.length) {
               this.AD.full = full.map(adConfigFormatter)[0]
               this.AD.full = full.map(adConfigFormatter)[0]
-            } else {
+            }
+            else {
               this.onInitNextDialog()
               this.onInitNextDialog()
               this.AD.full = {}
               this.AD.full = {}
             }
             }
             if (side.length) {
             if (side.length) {
               this.AD.side = side.map(adConfigFormatter)[0]
               this.AD.side = side.map(adConfigFormatter)[0]
-            } else {
+            }
+            else {
               this.AD.side = {}
               this.AD.side = {}
             }
             }
           }
           }
@@ -555,7 +597,8 @@ export default {
             this.toggleMessagePopShow(false)
             this.toggleMessagePopShow(false)
             this.AD.newUserPop = res.data.map(adConfigFormatter)[0]
             this.AD.newUserPop = res.data.map(adConfigFormatter)[0]
             this.AD.newUserPopOfBottom = res.data.map(adConfigFormatter)[1]
             this.AD.newUserPopOfBottom = res.data.map(adConfigFormatter)[1]
-          } else {
+          }
+          else {
             this.clearNewUserPopCache()
             this.clearNewUserPopCache()
           }
           }
         })
         })
@@ -592,7 +635,8 @@ export default {
       if (isClose) {
       if (isClose) {
         this.newUserPopConfig.showNextFullPop = true
         this.newUserPopConfig.showNextFullPop = true
         this.newUserPopConfig.showBottomPop = true
         this.newUserPopConfig.showBottomPop = true
-      } else {
+      }
+      else {
         this.clearNewUserPopCache()
         this.clearNewUserPopCache()
       }
       }
     },
     },
@@ -620,8 +664,8 @@ export default {
       if (type) {
       if (type) {
         // 判断是否展示有其他广告位
         // 判断是否展示有其他广告位
         if (
         if (
-          this.newUserPopConfig.showNextFullPop ||
-          this.newUserPopConfig.showBottomPop
+          this.newUserPopConfig.showNextFullPop
+          || this.newUserPopConfig.showBottomPop
         ) {
         ) {
           return
           return
         }
         }
@@ -644,7 +688,8 @@ export default {
     getNowMessagePopInfo() {
     getNowMessagePopInfo() {
       try {
       try {
         window.getMsgBuoyActive.getBuoyMsgAjax()
         window.getMsgBuoyActive.getBuoyMsgAjax()
-      } catch (e) {
+      }
+      catch (e) {
         console.warn(e)
         console.warn(e)
       }
       }
     },
     },
@@ -655,6 +700,7 @@ export default {
   }
   }
 }
 }
 </script>
 </script>
+
 <style lang="scss" scoped>
 <style lang="scss" scoped>
 .app-header-top {
 .app-header-top {
   padding-top: $app-header-padding-top;
   padding-top: $app-header-padding-top;

+ 158 - 124
apps/mobile/src/views/tabbar/Subscribe.vue

@@ -1,31 +1,33 @@
 <template>
 <template>
   <div class="j-container" @touchstart="appTabShow">
   <div class="j-container" @touchstart="appTabShow">
     <header class="subscribe-header-container">
     <header class="subscribe-header-container">
-      <div class="tabbar-header-top-placeholder" v-if="$envs.inApp"></div>
+      <div v-if="$envs.inApp" class="tabbar-header-top-placeholder" />
       <div class="subscribe-header tabbar-header">
       <div class="subscribe-header tabbar-header">
         <div class="subscribe-header-l">
         <div class="subscribe-header-l">
-          <h1 class="subscribe-header-title">{{ headerConf.titleText }}</h1>
+          <h1 class="subscribe-header-title">
+            {{ headerConf.titleText }}
+          </h1>
           <PowerSwitch
           <PowerSwitch
-            ref="powerSwitch"
             v-if="powerSwitchShow"
             v-if="powerSwitchShow"
-            :vSwitch="vSwitch"
-            :showTypes="vSwitchList"
-            :beforeLeave="beforeLeavePage"
+            ref="powerSwitch"
+            :v-switch="vSwitch"
+            :show-types="vSwitchList"
+            :before-leave="beforeLeavePage"
             @change="changeVSwitch"
             @change="changeVSwitch"
           />
           />
           <div
           <div
             v-else
             v-else
+            v-show="pageState.topBannerAd.textShow"
             ref="topAdText"
             ref="topAdText"
             class="top-ad-text"
             class="top-ad-text"
-            v-show="pageState.topBannerAd.textShow"
           >
           >
             立即使用 超级订阅
             立即使用 超级订阅
           </div>
           </div>
         </div>
         </div>
         <div class="subscribe-header-r">
         <div class="subscribe-header-r">
           <div
           <div
-            class="action-button subscribe-header-sub-title"
             v-if="showEntSubscribeButton"
             v-if="showEntSubscribeButton"
+            class="action-button subscribe-header-sub-title"
             @click="switchSubscribeType"
             @click="switchSubscribeType"
           >
           >
             {{ headerConf.subTitleText }}
             {{ headerConf.subTitleText }}
@@ -48,61 +50,61 @@
       </div>
       </div>
       <ad-single
       <ad-single
         v-if="topSuperVipAdShow"
         v-if="topSuperVipAdShow"
-        :show="pageState.topBannerAd.bannerShow"
         ref="topAd"
         ref="topAd"
+        :show="pageState.topBannerAd.bannerShow"
         :ad="topAdId"
         :ad="topAdId"
         cache
         cache
-        :showTag="false"
-        :showCloseIcon="false"
-        :beforeOpen="beforeLeavePage"
+        :show-tag="false"
+        :show-close-icon="false"
+        :before-open="beforeLeavePage"
+        class="ad-container subscribe-top-box"
         @loaded="onTopAdLoaded"
         @loaded="onTopAdLoaded"
         @close="onListAdClose()"
         @close="onListAdClose()"
-        class="ad-container subscribe-top-box"
       />
       />
       <DropFilter
       <DropFilter
-        v-model="filters"
         ref="dropFilter"
         ref="dropFilter"
+        v-model="filters"
         class="subscribe-drop-filter van-hairline--top"
         class="subscribe-drop-filter van-hairline--top"
         :default-state="defaultDropFilterState"
         :default-state="defaultDropFilterState"
         :options="dropFilterOptions"
         :options="dropFilterOptions"
-        :dropdownMenuOptions="dropdownMenuOptions"
+        :dropdown-menu-options="dropdownMenuOptions"
         @open="onFilterOpen"
         @open="onFilterOpen"
         @close="onFilterClose"
         @close="onFilterClose"
         @confirm="onFilterConfirm"
         @confirm="onFilterConfirm"
         @cancel="onFilterCancel"
         @cancel="onFilterCancel"
       >
       >
         <template v-if="isFree" #vipIcon>
         <template v-if="isFree" #vipIcon>
-          <span class="v-vip-icon"></span>
+          <span class="v-vip-icon" />
         </template>
         </template>
-        <template v-slot:more>
+        <template #more>
           <SubscribeMoreFilters
           <SubscribeMoreFilters
-            :disabledFilters="disabledFilters"
-            :isPersonal="isPersonalSubscribe"
             ref="moreFiltersRef"
             ref="moreFiltersRef"
+            :disabled-filters="disabledFilters"
+            :is-personal="isPersonalSubscribe"
             @onNoPower="onNoPower"
             @onNoPower="onNoPower"
           />
           />
         </template>
         </template>
       </DropFilter>
       </DropFilter>
-      <div class="tab-switch bg-white border-line-b" v-if="tabSwitchShow">
+      <div v-if="tabSwitchShow" class="tab-switch bg-white border-line-b">
         <van-tabs
         <van-tabs
-          class="tab-left"
           v-model="listTabActive"
           v-model="listTabActive"
+          class="tab-left"
           :ellipsis="false"
           :ellipsis="false"
           :before-change="beforeTabActiveChange"
           :before-change="beforeTabActiveChange"
           @change="onListTabChange"
           @change="onListTabChange"
         >
         >
           <van-tab
           <van-tab
             v-for="(tab, index) in conf.tabList"
             v-for="(tab, index) in conf.tabList"
+            :key="index"
             :name="tab.name"
             :name="tab.name"
             :title="tab.title"
             :title="tab.title"
-            :key="index"
-          ></van-tab>
+          />
         </van-tabs>
         </van-tabs>
         <div class="tab-right">
         <div class="tab-right">
           <div
           <div
+            v-if="listState.count > 0"
             class="data-export clickable"
             class="data-export clickable"
             @click="dataExport"
             @click="dataExport"
-            v-if="listState.count > 0"
           >
           >
             <AppIcon name="shujudaochu_xiao1" />
             <AppIcon name="shujudaochu_xiao1" />
             <span class="text">数据导出</span>
             <span class="text">数据导出</span>
@@ -112,8 +114,8 @@
       <div class="">
       <div class="">
         <!-- 超前项目推荐 & 定制化分析报告 -->
         <!-- 超前项目推荐 & 定制化分析报告 -->
         <RecommendCard
         <RecommendCard
-          :key="recommendInfo.key"
           v-if="recommendInfo.show"
           v-if="recommendInfo.show"
+          :key="recommendInfo.key"
           v-model="recommendInfo.showContent"
           v-model="recommendInfo.showContent"
           :chart-data="recommendInfo.chart"
           :chart-data="recommendInfo.chart"
           :brief-list="recommendInfo.brief"
           :brief-list="recommendInfo.brief"
@@ -125,24 +127,24 @@
       </div>
       </div>
     </header>
     </header>
     <main
     <main
-      class="j-main subscribe-list"
       ref="listContainer"
       ref="listContainer"
+      class="j-main subscribe-list"
       @scroll="scrollWrapFn"
       @scroll="scrollWrapFn"
     >
     >
       <van-list
       <van-list
         v-show="listTabActive === 'list' || listTabActive === 'detailedList'"
         v-show="listTabActive === 'list' || listTabActive === 'detailedList'"
+        ref="vanList"
         v-model="listState.loading"
         v-model="listState.loading"
         :finished="listState.finished"
         :finished="listState.finished"
         :offset="listState.offset"
         :offset="listState.offset"
         :finished-text="finishedText"
         :finished-text="finishedText"
         :immediate-check="false"
         :immediate-check="false"
-        @load="getList"
         class="more-list"
         class="more-list"
         :class="{ 'calc-height-1px': !hasMorePage }"
         :class="{ 'calc-height-1px': !hasMorePage }"
-        ref="vanList"
+        @load="getList"
       >
       >
         <div class="tab-search-info">
         <div class="tab-search-info">
-          <p class="search-total-count" v-if="listState.count > 0">
+          <p v-if="listState.count > 0" class="search-total-count">
             搜索到<span class="highlight-text">
             搜索到<span class="highlight-text">
               {{ calcListTotalText(listState.count) }} </span
               {{ calcListTotalText(listState.count) }} </span
             >条信息
             >条信息
@@ -150,38 +152,38 @@
         </div>
         </div>
         <div class="list-wrapper">
         <div class="list-wrapper">
           <van-popup
           <van-popup
+            v-model="showBidStatus"
             get-container="body"
             get-container="body"
             :style="popupHeight"
             :style="popupHeight"
-            v-model="showBidStatus"
             round
             round
             position="bottom"
             position="bottom"
           >
           >
-            <bid-status-node
+            <BidStatusNode
+              :project-cell-info="projectCellInfo"
               @cancel-update="cancelUpdate"
               @cancel-update="cancelUpdate"
               @save-success="saveSuccess"
               @save-success="saveSuccess"
-              :project-cell-info="projectCellInfo"
               @set-height="setHeight"
               @set-height="setHeight"
-            ></bid-status-node>
+            />
           </van-popup>
           </van-popup>
           <template v-for="(item, index) in subscribeList">
           <template v-for="(item, index) in subscribeList">
             <ProjectCell
             <ProjectCell
               v-if="!item.ad"
               v-if="!item.ad"
+              :key="item.id"
+              v-visited:subscribe="item._id"
               class="list-item"
               class="list-item"
               :class="item.className"
               :class="item.className"
-              :cardType="calcProjectCardType(item)"
-              :detailList="item.detailList"
-              @click="onClickCell(item)"
+              :card-type="calcProjectCardType(item)"
+              :detail-list="item.detailList"
               :title="item.title"
               :title="item.title"
               :time="item.dateTime"
               :time="item.dateTime"
               :detail="item.detail"
               :detail="item.detail"
               :filetext_search="item.filetext_search"
               :filetext_search="item.filetext_search"
-              :isFile="item.isFile"
+              :is-file="item.isFile"
               :keys="item.matchKeys"
               :keys="item.matchKeys"
-              :leftTopBadgeText="item.leftTopBadgeText"
+              :left-top-badge-text="item.leftTopBadgeText"
               :tags="item.tagList"
               :tags="item.tagList"
-              :pushSource="item.pushSource"
-              :key="item.id"
-              v-visited:subscribe="item._id"
+              :push-source="item.pushSource"
+              @click="onClickCell(item)"
             >
             >
               <template #buyerText="{ item }">
               <template #buyerText="{ item }">
                 <span
                 <span
@@ -192,15 +194,15 @@
               </template>
               </template>
               <template #winnerText="{ item }">
               <template #winnerText="{ item }">
                 <span
                 <span
+                  v-for="(winner, index) in item.children"
+                  :key="index"
                   class="winner-item highlight-text link-clickable j-splitter"
                   class="winner-item highlight-text link-clickable j-splitter"
                   data-j-splitter="、"
                   data-j-splitter="、"
-                  v-for="(winner, index) in item.children"
                   @click.stop="toToEntProfile(winner.id)"
                   @click.stop="toToEntProfile(winner.id)"
-                  :key="index"
                   >{{ winner.text }}</span
                   >{{ winner.text }}</span
                 >
                 >
               </template>
               </template>
-              <template slot="icon" v-if="item.isCB.id">
+              <template v-if="item.isCB.id" slot="icon">
                 <div
                 <div
                   class="right-event"
                   class="right-event"
                   :class="{ cb_blue: item.isCB.value }"
                   :class="{ cb_blue: item.isCB.value }"
@@ -229,43 +231,44 @@
                       'icon-star-fill': item.star,
                       'icon-star-fill': item.star,
                       'icon-star-streak': !item.star
                       'icon-star-streak': !item.star
                     }"
                     }"
-                  ></span>
+                  />
                   <span>&nbsp;{{ item.star ? '已收藏' : '收藏' }}</span>
                   <span>&nbsp;{{ item.star ? '已收藏' : '收藏' }}</span>
                 </div>
                 </div>
               </template>
               </template>
             </ProjectCell>
             </ProjectCell>
             <div
             <div
               v-else
               v-else
-              :key="[item.id, index].join('-')"
               v-show="item.show"
               v-show="item.show"
+              :key="[item.id, index].join('-')"
               class="middle-list-container"
               class="middle-list-container"
             >
             >
               <ad-single
               <ad-single
+                key="ad-item"
                 :class="item.className"
                 :class="item.className"
                 :ad="getContentAdID"
                 :ad="getContentAdID"
-                key="ad-item"
-                :showCloseIcon="true"
+                :show-close-icon="true"
                 cache
                 cache
-                :beforeOpen="beforeLeavePage"
+                :before-open="beforeLeavePage"
                 :vt="vSwitch"
                 :vt="vSwitch"
-                @close="onListAdClose(item)"
                 class="ad-container middle-list-ad"
                 class="ad-container middle-list-ad"
+                @close="onListAdClose(item)"
               />
               />
             </div>
             </div>
           </template>
           </template>
         </div>
         </div>
-        <div class="free-see-more" v-if="freeSeeMoreButtonShow">
+        <div v-if="freeSeeMoreButtonShow" class="free-see-more">
           <van-button
           <van-button
             class="free-see-more-button"
             class="free-see-more-button"
             size="large"
             size="large"
             plain
             plain
             @click="toLeaveInfoPage"
             @click="toLeaveInfoPage"
-            >查看更多</van-button
           >
           >
+            查看更多
+          </van-button>
         </div>
         </div>
         <AppEmpty
         <AppEmpty
-          state="sleep"
           v-show="listState.list.length === 0 && listState.finished"
           v-show="listState.list.length === 0 && listState.finished"
+          state="sleep"
         >
         >
           <!-- 有订阅管理权限的 -->
           <!-- 有订阅管理权限的 -->
           <div v-if="showSubscribeManageButton">
           <div v-if="showSubscribeManageButton">
@@ -303,8 +306,8 @@
           </template>
           </template>
         </AppEmpty>
         </AppEmpty>
       </van-list>
       </van-list>
-      <div class="table-container" v-show="listTabActive === 'table'">
-        <div class="scroll" v-show="listState.list.length">
+      <div v-show="listTabActive === 'table'" class="table-container">
+        <div v-show="listState.list.length" class="scroll">
           <table class="table">
           <table class="table">
             <tr class="table-header">
             <tr class="table-header">
               <td v-if="containsNiJian">项目代码</td>
               <td v-if="containsNiJian">项目代码</td>
@@ -322,10 +325,10 @@
             </tr>
             </tr>
             <tr
             <tr
               v-for="item in listState.list.slice(0, 20)"
               v-for="item in listState.list.slice(0, 20)"
-              class="table-content-tr"
+              :key="item.id"
               v-visited:subscribe="item._id"
               v-visited:subscribe="item._id"
+              class="table-content-tr"
               @click="onClickCell(item)"
               @click="onClickCell(item)"
-              :key="item.id"
             >
             >
               <!-- 项目代码 -->
               <!-- 项目代码 -->
               <td v-if="containsNiJian">
               <td v-if="containsNiJian">
@@ -339,7 +342,7 @@
                     pageState.splitKeys
                     pageState.splitKeys
                   )
                   )
                 "
                 "
-              ></td>
+              />
               <!-- 公告类型 -->
               <!-- 公告类型 -->
               <td v-if="!containsNiJian">
               <td v-if="!containsNiJian">
                 {{ item.subtype ? `${item.subtype}公告` : '-' }}
                 {{ item.subtype ? `${item.subtype}公告` : '-' }}
@@ -364,7 +367,9 @@
                 }}
                 }}
               </td>
               </td>
               <!-- 招标单位 -->
               <!-- 招标单位 -->
-              <td v-if="!containsNiJian">{{ item.buyer || '-' }}</td>
+              <td v-if="!containsNiJian">
+                {{ item.buyer || '-' }}
+              </td>
               <!-- 开标时间 -->
               <!-- 开标时间 -->
               <td v-if="!containsNiJian">
               <td v-if="!containsNiJian">
                 {{
                 {{
@@ -398,14 +403,14 @@
             </tr>
             </tr>
           </table>
           </table>
         </div>
         </div>
-        <div class="to-look-more" v-show="listState.list.length > 20">
-          <van-button plain size="small" type="primary" @click="dataExport"
-            >查看更多</van-button
-          >
+        <div v-show="listState.list.length > 20" class="to-look-more">
+          <van-button plain size="small" type="primary" @click="dataExport">
+            查看更多
+          </van-button>
         </div>
         </div>
         <AppEmpty
         <AppEmpty
-          state="sleep"
           v-show="listState.list.length === 0 && listState.finished"
           v-show="listState.list.length === 0 && listState.finished"
+          state="sleep"
         >
         >
           <!-- 有订阅管理权限的 -->
           <!-- 有订阅管理权限的 -->
           <div v-if="showSubscribeManageButton">
           <div v-if="showSubscribeManageButton">
@@ -446,60 +451,68 @@
     </main>
     </main>
     <footer class="j-footer">
     <footer class="j-footer">
       <NoticeBar
       <NoticeBar
-        rightText="了解详情"
+        v-if="pushMaxNoticeBarShow"
+        right-text="了解详情"
         @clickLeft="noticeBar.pushMaxShow = false"
         @clickLeft="noticeBar.pushMaxShow = false"
         @clickRight="toVipIntroducePage"
         @clickRight="toVipIntroducePage"
-        v-if="pushMaxNoticeBarShow"
-        >本次推送已达150条信息上限!开通超级订阅,支持每天最多推送2000条信息
+      >
+        本次推送已达150条信息上限!开通超级订阅,支持每天最多推送2000条信息
       </NoticeBar>
       </NoticeBar>
       <NoticeBar
       <NoticeBar
+        v-if="vipNoticeBarShow"
         theme="red"
         theme="red"
+        :right-text="noticeBar.vipRightText"
         @clickLeft="noticeBar.vipShow = false"
         @clickLeft="noticeBar.vipShow = false"
         @clickRight="toBuyVip"
         @clickRight="toBuyVip"
-        :rightText="noticeBar.vipRightText"
-        v-if="vipNoticeBarShow"
-        >{{ noticeBar.vipContentText }}
+      >
+        {{ noticeBar.vipContentText }}
       </NoticeBar>
       </NoticeBar>
       <NoticeBar
       <NoticeBar
+        v-if="keywordsSettingNoticeBarShow"
+        right-text="去设置"
         @clickLeft="noticeBar.settingKeywordsShow = false"
         @clickLeft="noticeBar.settingKeywordsShow = false"
         @clickRight="toKeysetPage"
         @clickRight="toKeysetPage"
-        rightText="去设置"
-        v-if="keywordsSettingNoticeBarShow"
-        >您未设置关键词,设置后接收信息更精准!
+      >
+        您未设置关键词,设置后接收信息更精准!
       </NoticeBar>
       </NoticeBar>
     </footer>
     </footer>
-    <!--    客服-->
-    <customer-corner
+    <!--    客服 -->
+    <CustomerCorner
       v-show="isLogin"
       v-show="isLogin"
       :scroll-status="scrollStatus"
       :scroll-status="scrollStatus"
       bottom-position="12%"
       bottom-position="12%"
     />
     />
+    <!-- 招采 -->
+    <CustomerBid
+      v-show="isLogin && $envs.inWX && showTutorial"
+      :scroll-status="scrollStatus"
+      bottom-position="19%"
+      @jumpBidPage="jumpBidPage"
+    />
     <DataReportTip
     <DataReportTip
       v-model="dataReport.tip"
       v-model="dataReport.tip"
-      :vSwitch="vSwitch"
-      :tipInfo="dataReport.tipInfo"
+      :v-switch="vSwitch"
+      :tip-info="dataReport.tipInfo"
     />
     />
-    <popupDataexport
-      ref="popup_dataExport"
-      @next="next_export"
-    ></popupDataexport>
+    <PopupDataexport ref="popup_dataExport" @next="next_export" />
     <CheckUserDialog />
     <CheckUserDialog />
   </div>
   </div>
 </template>
 </template>
 
 
 <script>
 <script>
-import { mapState, mapActions, mapGetters } from 'vuex'
-import { List, Badge, Button, Tabs, Tab, Tag, Popup } from 'vant'
+import { mapActions, mapGetters, mapState } from 'vuex'
+import { Badge, Button, List, Popup, Tab, Tabs, Tag } from 'vant'
 import dayjs from 'dayjs'
 import dayjs from 'dayjs'
 import qs from 'qs'
 import qs from 'qs'
+import { throttle } from 'lodash'
 import bidStatusNode from '@/components/bid-update/BidUpdate'
 import bidStatusNode from '@/components/bid-update/BidUpdate'
 import {
 import {
-  AppIcon,
   AppEmpty,
   AppEmpty,
-  ProjectCell,
-  DropFilter,
+  AppIcon,
   DatetimePicker,
   DatetimePicker,
-  NoticeBar
+  DropFilter,
+  NoticeBar,
+  ProjectCell
 } from '@/ui'
 } from '@/ui'
 // 三级地区筛选
 // 三级地区筛选
 import AreaThreeSidebar from '@/components/selector/area-three-sidebar/index'
 import AreaThreeSidebar from '@/components/selector/area-three-sidebar/index'
@@ -512,37 +525,38 @@ import Ad from '@/components/ad/Ad'
 import popupDataexport from '@/components/dataExport/popupDataexport.vue'
 import popupDataexport from '@/components/dataExport/popupDataexport.vue'
 import CheckUserDialog from '@/views/identity/components/CheckUserDialog'
 import CheckUserDialog from '@/views/identity/components/CheckUserDialog'
 import CustomerCorner from '@/components/customer/index'
 import CustomerCorner from '@/components/customer/index'
-import { LINKS, vtMap, AdCode } from '@/data'
+import CustomerBid from '@/components/customerBid/index'
+import { AdCode, LINKS, vtMap } from '@/data'
 import { wxShareMixin } from '@/utils/mixins/modules/wx-share'
 import { wxShareMixin } from '@/utils/mixins/modules/wx-share'
 import { iosBackRefresh } from '@/utils/utils'
 import { iosBackRefresh } from '@/utils/utils'
-import { throttle } from 'lodash'
 import {
 import {
-  callHideTab,
+  FilterHistoryViewModel2AjaxModel,
+  InfoTypeTransform,
   callHideRedSpotOnMenu,
   callHideRedSpotOnMenu,
+  callHideTab,
+  dateFormatter,
   formatMoney,
   formatMoney,
-  moneyUnit,
+  getRandomNumber,
+  getRandomString,
   iOSVersionLt14,
   iOSVersionLt14,
-  dateFormatter,
-  replaceKeyword,
+  moneyUnit,
   openAppOrWxPage,
   openAppOrWxPage,
   openLinkOfOther,
   openLinkOfOther,
-  getRandomString,
-  getRandomNumber,
-  FilterHistoryViewModel2AjaxModel,
-  InfoTypeTransform
+  replaceKeyword
 } from '@/utils'
 } from '@/utils'
 import {
 import {
-  selectEnt,
+  ajaxCanBiaoAction,
+  ajaxCanBiaoStatus,
+  checkDataReportTip,
+  checkHasReportData,
+  getConfiguration,
   getPushListDataExportId,
   getPushListDataExportId,
+  getSubscribePageAreaPackTip,
+  getUserSubscribeKeywords,
   getUserSubscribeList,
   getUserSubscribeList,
   getUserSubscribeSomeInfo,
   getUserSubscribeSomeInfo,
-  checkDataReportTip,
-  getSubscribePageAreaPackTip,
+  selectEnt,
   setSubscribePageAreaPackTipClose,
   setSubscribePageAreaPackTipClose,
-  checkHasReportData,
-  ajaxCanBiaoStatus,
-  ajaxCanBiaoAction,
-  getUserSubscribeKeywords,
   setUserSubscribeListVisited
   setUserSubscribeListVisited
 } from '@/api/modules'
 } from '@/api/modules'
 import { leadGetDate } from '@/api/modules/leadGeneration'
 import { leadGetDate } from '@/api/modules/leadGeneration'
@@ -559,7 +573,6 @@ const leaveSourceMap = {
 
 
 export default {
 export default {
   name: 'AppSubscribe',
   name: 'AppSubscribe',
-  mixins: [wxShareMixin],
   components: {
   components: {
     PowerSwitch,
     PowerSwitch,
     SubscribeMoreFilters,
     SubscribeMoreFilters,
@@ -581,10 +594,17 @@ export default {
     [IndustrySidebar.name]: IndustrySidebar,
     [IndustrySidebar.name]: IndustrySidebar,
     CheckUserDialog,
     CheckUserDialog,
     RecommendCard,
     RecommendCard,
-    bidStatusNode,
-    popupDataexport,
+    BidStatusNode: bidStatusNode,
+    PopupDataexport: popupDataexport,
     AreaThreeSidebar,
     AreaThreeSidebar,
-    CustomerCorner
+    CustomerCorner,
+    CustomerBid
+  },
+  mixins: [wxShareMixin],
+  provide() {
+    return {
+      getActiveSubscribeTypeState: this.getActiveSubscribeTypeState
+    }
   },
   },
   data() {
   data() {
     return {
     return {
@@ -823,12 +843,8 @@ export default {
       projectCellInfo: {},
       projectCellInfo: {},
       mergedKeywords: [],
       mergedKeywords: [],
       alreadyLeave: false, // 免费用户是否已经留资. true为已留资,false为未留资或者留资信息不全
       alreadyLeave: false, // 免费用户是否已经留资. true为已留资,false为未留资或者留资信息不全
-      scrollStatus: true
-    }
-  },
-  provide() {
-    return {
-      getActiveSubscribeTypeState: this.getActiveSubscribeTypeState
+      scrollStatus: true,
+      showTutorial: false
     }
     }
   },
   },
   computed: {
   computed: {
@@ -1125,7 +1141,7 @@ export default {
         // changed后会进行一次查询
         // changed后会进行一次查询
         // 默认查询
         // 默认查询
         // this.subscribeTypeActive = 'my'
         // this.subscribeTypeActive = 'my'
-        this.doSearch('firstInit') //初始化调用接口
+        this.doSearch('firstInit') // 初始化调用接口
       }
       }
       this.getMergedEntSubscribeKeywords()
       this.getMergedEntSubscribeKeywords()
     }
     }
@@ -1137,6 +1153,7 @@ export default {
     this.setDocumentTitle()
     this.setDocumentTitle()
     this.initScrollEvents()
     this.initScrollEvents()
     this.appTabShow()
     this.appTabShow()
+    this.getConfigurationApi()
     console.log(this.restfulApiUserTypeWitchVSwitch, 'mounted')
     console.log(this.restfulApiUserTypeWitchVSwitch, 'mounted')
   },
   },
   methods: {
   methods: {
@@ -1148,6 +1165,23 @@ export default {
       'userVipSwitchState',
       'userVipSwitchState',
       'getUserIdentityList'
       'getUserIdentityList'
     ]),
     ]),
+    jumpBidPage() {
+      this.$router.push('/course/index')
+    },
+    async getConfigurationApi() {
+      const { error_code: code, data } = await getConfiguration()
+      if (code === 0) {
+        const thisTime = Math.round(new Date() / 1000)
+        if (
+          thisTime >= data?.bulletFrameStart &&
+          thisTime <= data?.bulletFrameEnd
+        ) {
+          this.showTutorial = true
+        } else {
+          this.showTutorial = false
+        }
+      }
+    },
     // 检测是否需要处理ios兼容性问题
     // 检测是否需要处理ios兼容性问题
     // ios13以及以下需要处理兼容性问题
     // ios13以及以下需要处理兼容性问题
     checkIOSCompatible() {
     checkIOSCompatible() {
@@ -1538,7 +1572,7 @@ export default {
           }
           }
           case 'industry': {
           case 'industry': {
             const result = Object.keys(values).map((k) => {
             const result = Object.keys(values).map((k) => {
-              return values[k].map((v) => k + '_' + v).join(',')
+              return values[k].map((v) => `${k}_${v}`).join(',')
             })
             })
             params[key] = result.join(',')
             params[key] = result.join(',')
             break
             break
@@ -1685,7 +1719,7 @@ export default {
       await this.getList(type)
       await this.getList(type)
     },
     },
     // 下拉刷新,暂未用到
     // 下拉刷新,暂未用到
-    onRefresh: function () {
+    onRefresh() {
       // 重置数据
       // 重置数据
       this.listState.pageNum = 1
       this.listState.pageNum = 1
       // 解除加载完成状态
       // 解除加载完成状态
@@ -1910,7 +1944,7 @@ export default {
           ? item?.buyerClass
           ? item?.buyerClass
           : undefined
           : undefined
       // 有city时展示city,无展示area
       // 有city时展示city,无展示area
-      const region = city ? city : area
+      const region = city || area
       // 标签
       // 标签
       item.tagList = [
       item.tagList = [
         region || '',
         region || '',
@@ -1995,7 +2029,7 @@ export default {
         }
         }
       ]
       ]
     },
     },
-    dropdownMenuItemClick: function () {
+    dropdownMenuItemClick() {
       if (this.noLoginOrFree && this.isPersonalSubscribe) {
       if (this.noLoginOrFree && this.isPersonalSubscribe) {
         this.onNoPower()
         this.onNoPower()
       }
       }
@@ -2131,7 +2165,7 @@ export default {
     // 标讯收藏
     // 标讯收藏
     async doCollection(item, index) {
     async doCollection(item, index) {
       if (!this.isLogin) {
       if (!this.isLogin) {
-        this.pageState.cacheStar = index + ''
+        this.pageState.cacheStar = `${index}`
         this.saveState()
         this.saveState()
         return openLinkOfOther(LINKS.APP登录页.app, {
         return openLinkOfOther(LINKS.APP登录页.app, {
           query: {
           query: {
@@ -2144,7 +2178,7 @@ export default {
         stopLeaveInfo: !this.isFree || this.alreadyLeave, // 非免费用户或者已留资过的用户,不再重复留资
         stopLeaveInfo: !this.isFree || this.alreadyLeave, // 非免费用户或者已留资过的用户,不再重复留资
         id: item._id,
         id: item._id,
         beforeRedirect: () => {
         beforeRedirect: () => {
-          this.pageState.cacheStar = index + ''
+          this.pageState.cacheStar = `${index}`
           this.saveState()
           this.saveState()
         },
         },
         complete: ({ type, message }) => {
         complete: ({ type, message }) => {
@@ -2254,7 +2288,7 @@ export default {
               count += stateCounter[key]?._children_selectedCount || 0
               count += stateCounter[key]?._children_selectedCount || 0
             }
             }
             const countString = count || ''
             const countString = count || ''
-            areaTitle = '地区' + countString
+            areaTitle = `地区${countString}`
             this.searchState.areaDropdownMenuTitleText = areaTitle
             this.searchState.areaDropdownMenuTitleText = areaTitle
           } else {
           } else {
             const { areaDropdownMenuTitleText } = this.searchState
             const { areaDropdownMenuTitleText } = this.searchState
@@ -2268,7 +2302,7 @@ export default {
             .map((k) => this.filters.industry[k])
             .map((k) => this.filters.industry[k])
             .flat().length
             .flat().length
           const countString = count || ''
           const countString = count || ''
-          this.dropFilterOptions[2].menu.title = '行业' + countString
+          this.dropFilterOptions[2].menu.title = `行业${countString}`
           break
           break
         }
         }
         case 'more': {
         case 'more': {
@@ -2375,7 +2409,7 @@ export default {
       const { listContainer } = this.$refs
       const { listContainer } = this.$refs
       this.saveActiveTab()
       this.saveActiveTab()
       this.listState.scrollTop = listContainer
       this.listState.scrollTop = listContainer
-        ? parseInt(listContainer.scrollTop)
+        ? Number.parseInt(listContainer.scrollTop)
         : 0
         : 0
       this.$storage.set(
       this.$storage.set(
         this.$route.path,
         this.$route.path,

+ 354 - 27
pnpm-lock.yaml

@@ -308,6 +308,9 @@ importers:
       '@tinymce/tinymce-vue':
       '@tinymce/tinymce-vue':
         specifier: ^3.2.8
         specifier: ^3.2.8
         version: 3.2.8(vue@2.7.16)
         version: 3.2.8(vue@2.7.16)
+      aliyun_numberauthsdk_web:
+        specifier: ^2.1.9
+        version: 2.1.9
       dayjs:
       dayjs:
         specifier: ^1.11.8
         specifier: ^1.11.8
         version: 1.11.8
         version: 1.11.8
@@ -3584,18 +3587,15 @@ packages:
     resolution: {integrity: sha512-42UH54oPZHPdRHdw6BgoBD6cg/eVTmVrFcgeRDM3jbO7uxSoipVcmcIGFcA5jmOHO5apcyvBhkSKES3fQJnu7A==}
     resolution: {integrity: sha512-42UH54oPZHPdRHdw6BgoBD6cg/eVTmVrFcgeRDM3jbO7uxSoipVcmcIGFcA5jmOHO5apcyvBhkSKES3fQJnu7A==}
     dependencies:
     dependencies:
       '@floating-ui/utils': 0.2.2
       '@floating-ui/utils': 0.2.2
-    dev: true
 
 
   /@floating-ui/dom@1.6.4:
   /@floating-ui/dom@1.6.4:
     resolution: {integrity: sha512-0G8R+zOvQsAG1pg2Q99P21jiqxqGBW1iRe/iXHsBRBxnpXKFI8QwbB4x5KmYLggNO5m34IQgOIu9SCRfR/WWiQ==}
     resolution: {integrity: sha512-0G8R+zOvQsAG1pg2Q99P21jiqxqGBW1iRe/iXHsBRBxnpXKFI8QwbB4x5KmYLggNO5m34IQgOIu9SCRfR/WWiQ==}
     dependencies:
     dependencies:
       '@floating-ui/core': 1.6.1
       '@floating-ui/core': 1.6.1
       '@floating-ui/utils': 0.2.2
       '@floating-ui/utils': 0.2.2
-    dev: true
 
 
   /@floating-ui/utils@0.2.2:
   /@floating-ui/utils@0.2.2:
     resolution: {integrity: sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw==}
     resolution: {integrity: sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw==}
-    dev: true
 
 
   /@floating-ui/vue@1.0.6(vue@3.3.11):
   /@floating-ui/vue@1.0.6(vue@3.3.11):
     resolution: {integrity: sha512-EdrOljjkpkkqZnrpqUcPoz9NvHxuTjUtSInh6GMv3+Mcy+giY2cE2pHh9rpacRcZ2eMSCxel9jWkWXTjLmY55w==}
     resolution: {integrity: sha512-EdrOljjkpkkqZnrpqUcPoz9NvHxuTjUtSInh6GMv3+Mcy+giY2cE2pHh9rpacRcZ2eMSCxel9jWkWXTjLmY55w==}
@@ -3903,6 +3903,67 @@ packages:
     resolution: {integrity: sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ==}
     resolution: {integrity: sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ==}
     dev: true
     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:
   /@rollup/pluginutils@4.2.1:
     resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==}
     resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==}
     engines: {node: '>= 8.0.0'}
     engines: {node: '>= 8.0.0'}
@@ -5138,6 +5199,19 @@ packages:
       - rollup
       - rollup
     dev: true
     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:
   /@vant/icons@1.8.0:
     resolution: {integrity: sha512-sKfEUo2/CkQFuERxvkuF6mGQZDKu3IQdj5rV9Fm0weJXtchDSSQ+zt8qPCNUEhh9Y8shy5PzxbvAfOOkCwlCXg==}
     resolution: {integrity: sha512-sKfEUo2/CkQFuERxvkuF6mGQZDKu3IQdj5rV9Fm0weJXtchDSSQ+zt8qPCNUEhh9Y8shy5PzxbvAfOOkCwlCXg==}
     dev: false
     dev: false
@@ -5593,7 +5667,7 @@ packages:
       '@vue/cli-service': ^3.0.0 || ^4.0.0 || ^5.0.0-0
       '@vue/cli-service': ^3.0.0 || ^4.0.0 || ^5.0.0-0
       eslint: '>=7.5.0'
       eslint: '>=7.5.0'
     dependencies:
     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
       '@vue/cli-shared-utils': 5.0.8
       eslint: 7.32.0
       eslint: 7.32.0
       eslint-webpack-plugin: 3.2.0(eslint@7.32.0)(webpack@5.88.2)
       eslint-webpack-plugin: 3.2.0(eslint@7.32.0)(webpack@5.88.2)
@@ -5613,7 +5687,7 @@ packages:
     peerDependencies:
     peerDependencies:
       '@vue/cli-service': ^3.0.0 || ^4.0.0 || ^5.0.0-0
       '@vue/cli-service': ^3.0.0 || ^4.0.0 || ^5.0.0-0
     dependencies:
     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
       '@vue/cli-shared-utils': 5.0.8
     transitivePeerDependencies:
     transitivePeerDependencies:
       - encoding
       - encoding
@@ -5624,7 +5698,7 @@ packages:
     peerDependencies:
     peerDependencies:
       '@vue/cli-service': ^3.0.0 || ^4.0.0 || ^5.0.0-0
       '@vue/cli-service': ^3.0.0 || ^4.0.0 || ^5.0.0-0
     dependencies:
     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
       '@vue/cli-shared-utils': 5.0.8
     transitivePeerDependencies:
     transitivePeerDependencies:
       - encoding
       - encoding
@@ -5635,7 +5709,7 @@ packages:
     peerDependencies:
     peerDependencies:
       '@vue/cli-service': ^3.0.0 || ^4.0.0 || ^5.0.0-0
       '@vue/cli-service': ^3.0.0 || ^4.0.0 || ^5.0.0-0
     dependencies:
     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
     dev: true
 
 
   /@vue/cli-plugin-vuex@5.0.8(@vue/cli-service@5.0.1):
   /@vue/cli-plugin-vuex@5.0.8(@vue/cli-service@5.0.1):
@@ -5643,7 +5717,7 @@ packages:
     peerDependencies:
     peerDependencies:
       '@vue/cli-service': ^3.0.0 || ^4.0.0 || ^5.0.0-0
       '@vue/cli-service': ^3.0.0 || ^4.0.0 || ^5.0.0-0
     dependencies:
     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
     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):
   /@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
       - supports-color
     dev: true
     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):
   /ajv-formats@2.1.1(ajv@8.12.0):
     resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==}
     resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==}
     peerDependencies:
     peerDependencies:
@@ -6921,6 +7013,22 @@ packages:
       '@algolia/transporter': 4.22.1
       '@algolia/transporter': 4.22.1
     dev: true
     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:
   /ansi-colors@4.1.3:
     resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==}
     resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==}
     engines: {node: '>=6'}
     engines: {node: '>=6'}
@@ -6998,6 +7106,44 @@ packages:
     engines: {node: '>=12'}
     engines: {node: '>=12'}
     dev: true
     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:
   /any-promise@1.3.0:
     resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}
     resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}
     dev: true
     dev: true
@@ -7140,6 +7286,10 @@ packages:
       babel-runtime: 6.26.0
       babel-runtime: 6.26.0
     dev: false
     dev: false
 
 
+  /async-validator@4.2.5:
+    resolution: {integrity: sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==}
+    dev: false
+
   /async@2.6.4:
   /async@2.6.4:
     resolution: {integrity: sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==}
     resolution: {integrity: sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==}
     dependencies:
     dependencies:
@@ -7195,10 +7345,19 @@ packages:
     engines: {node: '>= 0.4'}
     engines: {node: '>= 0.4'}
     dev: true
     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:
   /axios@0.27.2:
     resolution: {integrity: sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==}
     resolution: {integrity: sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==}
     dependencies:
     dependencies:
-      follow-redirects: 1.15.2(debug@4.3.4)
+      follow-redirects: 1.15.2
       form-data: 4.0.0
       form-data: 4.0.0
     transitivePeerDependencies:
     transitivePeerDependencies:
       - debug
       - debug
@@ -7206,7 +7365,7 @@ packages:
   /axios@1.4.0:
   /axios@1.4.0:
     resolution: {integrity: sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==}
     resolution: {integrity: sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==}
     dependencies:
     dependencies:
-      follow-redirects: 1.15.2(debug@4.3.4)
+      follow-redirects: 1.15.2
       form-data: 4.0.0
       form-data: 4.0.0
       proxy-from-env: 1.1.0
       proxy-from-env: 1.1.0
     transitivePeerDependencies:
     transitivePeerDependencies:
@@ -7216,7 +7375,7 @@ packages:
   /axios@1.6.7:
   /axios@1.6.7:
     resolution: {integrity: sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==}
     resolution: {integrity: sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==}
     dependencies:
     dependencies:
-      follow-redirects: 1.15.5
+      follow-redirects: 1.15.5(debug@4.3.4)
       form-data: 4.0.0
       form-data: 4.0.0
       proxy-from-env: 1.1.0
       proxy-from-env: 1.1.0
     transitivePeerDependencies:
     transitivePeerDependencies:
@@ -7721,6 +7880,10 @@ packages:
       validator: 13.12.0
       validator: 13.12.0
     dev: true
     dev: true
 
 
+  /classnames@2.5.1:
+    resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==}
+    dev: false
+
   /clean-css@5.3.2:
   /clean-css@5.3.2:
     resolution: {integrity: sha512-JVJbM+f3d3Q704rF4bqQ5UUyTtuJ0JRKNbTKVEeujCCBoMdkEi+V+e8oktO9qGQNSvHrFTM6JZRXrUvGR1czww==}
     resolution: {integrity: sha512-JVJbM+f3d3Q704rF4bqQ5UUyTtuJ0JRKNbTKVEeujCCBoMdkEi+V+e8oktO9qGQNSvHrFTM6JZRXrUvGR1czww==}
     engines: {node: '>= 10.0'}
     engines: {node: '>= 10.0'}
@@ -8237,6 +8400,10 @@ packages:
     resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==}
     resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==}
     dev: true
     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):
   /css-declaration-sorter@6.4.1(postcss@8.4.35):
     resolution: {integrity: sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g==}
     resolution: {integrity: sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g==}
     engines: {node: ^10 || ^12 || >=14}
     engines: {node: ^10 || ^12 || >=14}
@@ -8446,6 +8613,17 @@ packages:
       ms: 2.0.0
       ms: 2.0.0
     dev: true
     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:
   /debug@3.2.7:
     resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
     resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
     peerDependencies:
     peerDependencies:
@@ -8503,6 +8681,11 @@ packages:
     resolution: {integrity: sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ==}
     resolution: {integrity: sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ==}
     engines: {node: '>=0.10.0'}
     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:
   /default-gateway@6.0.3:
     resolution: {integrity: sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==}
     resolution: {integrity: sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==}
     engines: {node: '>= 10'}
     engines: {node: '>= 10'}
@@ -9941,7 +10124,7 @@ packages:
       natural-compare: 1.4.0
       natural-compare: 1.4.0
       nth-check: 2.1.1
       nth-check: 2.1.1
       postcss-selector-parser: 6.0.13
       postcss-selector-parser: 6.0.13
-      semver: 7.6.3
+      semver: 7.5.4
       vue-eslint-parser: 9.3.1(eslint@7.32.0)
       vue-eslint-parser: 9.3.1(eslint@7.32.0)
       xml-name-validator: 4.0.0
       xml-name-validator: 4.0.0
     transitivePeerDependencies:
     transitivePeerDependencies:
@@ -10699,7 +10882,7 @@ packages:
       tabbable: 6.2.0
       tabbable: 6.2.0
     dev: true
     dev: true
 
 
-  /follow-redirects@1.15.2(debug@4.3.4):
+  /follow-redirects@1.15.2:
     resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==}
     resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==}
     engines: {node: '>=4.0'}
     engines: {node: '>=4.0'}
     peerDependencies:
     peerDependencies:
@@ -10707,10 +10890,8 @@ packages:
     peerDependenciesMeta:
     peerDependenciesMeta:
       debug:
       debug:
         optional: true
         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==}
     resolution: {integrity: sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==}
     engines: {node: '>=4.0'}
     engines: {node: '>=4.0'}
     peerDependencies:
     peerDependencies:
@@ -10718,6 +10899,17 @@ packages:
     peerDependenciesMeta:
     peerDependenciesMeta:
       debug:
       debug:
         optional: true
         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:
   /for-each@0.3.3:
     resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
     resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
@@ -11221,7 +11413,7 @@ packages:
     engines: {node: '>=8.0.0'}
     engines: {node: '>=8.0.0'}
     dependencies:
     dependencies:
       eventemitter3: 4.0.7
       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
       requires-port: 1.0.0
     transitivePeerDependencies:
     transitivePeerDependencies:
       - debug
       - debug
@@ -11375,6 +11567,10 @@ packages:
     engines: {node: '>= 0.10'}
     engines: {node: '>= 0.10'}
     dev: true
     dev: true
 
 
+  /intersection-observer@0.12.2:
+    resolution: {integrity: sha512-7m1vEcPCxXYI8HqnL8CKI6siDyD+eIWSwgB3DZA+ZTogxk9I4CDnj4wilt9x/+/QbHI4YG5YZNmC6458/e9Ktg==}
+    dev: false
+
   /inversify@6.0.1:
   /inversify@6.0.1:
     resolution: {integrity: sha512-B3ex30927698TJENHR++8FfEaJGqoWOgI6ZY5Ht/nLUsFCwHn6akbwtnUAPCgUepAnTpe2qHxhDNjoKLyz6rgQ==}
     resolution: {integrity: sha512-B3ex30927698TJENHR++8FfEaJGqoWOgI6ZY5Ht/nLUsFCwHn6akbwtnUAPCgUepAnTpe2qHxhDNjoKLyz6rgQ==}
     dev: true
     dev: true
@@ -11816,6 +12012,15 @@ packages:
     engines: {node: '>=12'}
     engines: {node: '>=12'}
     dev: false
     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:
   /js-message@1.0.7:
     resolution: {integrity: sha512-efJLHhLjIyKRewNS9EGZ4UpI8NguuL6fKkhRxVuMmrGV2xN/0APGdQYwLFky5w9naebSZ0OwAGp0G6/2Cg90rA==}
     resolution: {integrity: sha512-efJLHhLjIyKRewNS9EGZ4UpI8NguuL6fKkhRxVuMmrGV2xN/0APGdQYwLFky5w9naebSZ0OwAGp0G6/2Cg90rA==}
     engines: {node: '>=0.6.0'}
     engines: {node: '>=0.6.0'}
@@ -11831,7 +12036,6 @@ packages:
 
 
   /js-tokens@4.0.0:
   /js-tokens@4.0.0:
     resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
     resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
-    dev: true
 
 
   /js-yaml@3.14.1:
   /js-yaml@3.14.1:
     resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==}
     resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==}
@@ -11890,6 +12094,10 @@ packages:
       - utf-8-validate
       - utf-8-validate
     dev: true
     dev: true
 
 
+  /jsencrypt@3.3.2:
+    resolution: {integrity: sha512-arQR1R1ESGdAxY7ZheWr12wCaF2yF47v5qpB76TtV64H1pyGudk9Hvw8Y9tb/FiTIaaTRUyaSnm5T/Y53Ghm/A==}
+    dev: false
+
   /jsesc@0.5.0:
   /jsesc@0.5.0:
     resolution: {integrity: sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==}
     resolution: {integrity: sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==}
     hasBin: true
     hasBin: true
@@ -12199,6 +12407,13 @@ packages:
     resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==}
     resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==}
     dev: true
     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:
   /lottie-web@5.12.0:
     resolution: {integrity: sha512-tt2oiv0EmXC8J/RF877dVCo93vZBBnww+SO6dldREgHD8EsP97jQ42JRryIRfY+6aVESQsHYNEAYgH25cBFy7A==}
     resolution: {integrity: sha512-tt2oiv0EmXC8J/RF877dVCo93vZBBnww+SO6dldREgHD8EsP97jQ42JRryIRfY+6aVESQsHYNEAYgH25cBFy7A==}
     dev: false
     dev: false
@@ -12212,7 +12427,7 @@ packages:
   /lower-case@2.0.2:
   /lower-case@2.0.2:
     resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==}
     resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==}
     dependencies:
     dependencies:
-      tslib: 2.6.0
+      tslib: 2.7.0
     dev: true
     dev: true
 
 
   /lru-cache@10.4.3:
   /lru-cache@10.4.3:
@@ -12838,7 +13053,6 @@ packages:
 
 
   /ms@2.0.0:
   /ms@2.0.0:
     resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
     resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
-    dev: true
 
 
   /ms@2.1.2:
   /ms@2.1.2:
     resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
     resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
@@ -12879,6 +13093,10 @@ packages:
       thenify-all: 1.6.0
       thenify-all: 1.6.0
     dev: true
     dev: true
 
 
+  /nano-memoize@3.0.16:
+    resolution: {integrity: sha512-JyK96AKVGAwVeMj3MoMhaSXaUNqgMbCRSQB3trUV8tYZfWEzqUBKdK1qJpfuNXgKeHOx1jv/IEYTM659ly7zUA==}
+    dev: false
+
   /nanoid@3.3.7:
   /nanoid@3.3.7:
     resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==}
     resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==}
     engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
     engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
@@ -13026,7 +13244,6 @@ packages:
   /object-assign@4.1.1:
   /object-assign@4.1.1:
     resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
     resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
     engines: {node: '>=0.10.0'}
     engines: {node: '>=0.10.0'}
-    dev: true
 
 
   /object-inspect@1.12.3:
   /object-inspect@1.12.3:
     resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==}
     resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==}
@@ -14051,9 +14268,84 @@ packages:
       unpipe: 1.0.0
       unpipe: 1.0.0
     dev: true
     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:
   /react-is@18.2.0:
     resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==}
     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:
   /read-pkg-up@7.0.1:
     resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==}
     resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==}
@@ -14486,6 +14778,10 @@ packages:
     dependencies:
     dependencies:
       queue-microtask: 1.2.3
       queue-microtask: 1.2.3
 
 
+  /runes2@1.1.4:
+    resolution: {integrity: sha512-LNPnEDPOOU4ehF71m5JoQyzT2yxwD6ZreFJ7MxZUAoMKNMY1XrAo60H1CUoX5ncSm0rIuKlqn9JZNRrRkNou2g==}
+    dev: false
+
   /rxjs@7.8.1:
   /rxjs@7.8.1:
     resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==}
     resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==}
     dependencies:
     dependencies:
@@ -14608,6 +14904,13 @@ packages:
       xmlchars: 2.2.0
       xmlchars: 2.2.0
     dev: true
     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:
   /schema-utils@2.7.1:
     resolution: {integrity: sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==}
     resolution: {integrity: sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==}
     engines: {node: '>= 8.9.0'}
     engines: {node: '>= 8.9.0'}
@@ -14636,6 +14939,11 @@ packages:
       ajv-keywords: 5.1.0(ajv@8.12.0)
       ajv-keywords: 5.1.0(ajv@8.12.0)
     dev: true
     dev: true
 
 
+  /screenfull@5.2.0:
+    resolution: {integrity: sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA==}
+    engines: {node: '>=0.10.0'}
+    dev: false
+
   /scslre@0.3.0:
   /scslre@0.3.0:
     resolution: {integrity: sha512-3A6sD0WYP7+QrjbfNA2FN3FsOaGGFoekCVgTyypy53gPxhbkCIjtO6YWgdrfM+n/8sI8JeXZOIxsHjMTNxQ4nQ==}
     resolution: {integrity: sha512-3A6sD0WYP7+QrjbfNA2FN3FsOaGGFoekCVgTyypy53gPxhbkCIjtO6YWgdrfM+n/8sI8JeXZOIxsHjMTNxQ4nQ==}
     engines: {node: ^14.0.0 || >=16.0.0}
     engines: {node: ^14.0.0 || >=16.0.0}
@@ -15045,6 +15353,14 @@ packages:
     resolution: {integrity: sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==}
     resolution: {integrity: sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==}
     dev: true
     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:
   /statuses@1.5.0:
     resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==}
     resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==}
     engines: {node: '>= 0.6'}
     engines: {node: '>= 0.6'}
@@ -15546,7 +15862,6 @@ packages:
 
 
   /tslib@2.7.0:
   /tslib@2.7.0:
     resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==}
     resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==}
-    dev: true
 
 
   /tsutils@3.21.0(typescript@5.2.2):
   /tsutils@3.21.0(typescript@5.2.2):
     resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
     resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
@@ -15657,6 +15972,11 @@ packages:
     hasBin: true
     hasBin: true
     dev: true
     dev: true
 
 
+  /ua-parser-js@0.7.39:
+    resolution: {integrity: sha512-IZ6acm6RhQHNibSt7+c09hhvsKy9WUr4DVbeq9U8o71qxyYtJpQeDxQnMrVqnIFMLcQjHO0I9wgfO2vIahht4w==}
+    hasBin: true
+    dev: false
+
   /uc.micro@1.0.6:
   /uc.micro@1.0.6:
     resolution: {integrity: sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==}
     resolution: {integrity: sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==}
     dev: true
     dev: true
@@ -15990,13 +16310,13 @@ packages:
   /upper-case-first@2.0.2:
   /upper-case-first@2.0.2:
     resolution: {integrity: sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==}
     resolution: {integrity: sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==}
     dependencies:
     dependencies:
-      tslib: 2.6.0
+      tslib: 2.7.0
     dev: true
     dev: true
 
 
   /upper-case@2.0.2:
   /upper-case@2.0.2:
     resolution: {integrity: sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg==}
     resolution: {integrity: sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg==}
     dependencies:
     dependencies:
-      tslib: 2.6.0
+      tslib: 2.7.0
     dev: true
     dev: true
 
 
   /uri-js@4.4.1:
   /uri-js@4.4.1:
@@ -16011,6 +16331,14 @@ packages:
       requires-port: 1.0.0
       requires-port: 1.0.0
     dev: true
     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:
   /util-deprecate@1.0.2:
     resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
     resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
     dev: true
     dev: true
@@ -16047,7 +16375,6 @@ packages:
   /uuid@8.3.2:
   /uuid@8.3.2:
     resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==}
     resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==}
     hasBin: true
     hasBin: true
-    dev: true
 
 
   /v-charts@1.19.0(echarts@4.8.0)(vue@2.7.16)(zrender@4.3.2):
   /v-charts@1.19.0(echarts@4.8.0)(vue@2.7.16)(zrender@4.3.2):
     resolution: {integrity: sha512-vm2HBUmxAsXK0ivwce9LytcpqrItDA5JSPLYVxZXtiuoyhcn80XX1/3dPJd/1GqG1OYv3jfBo1s9ra4q8GowqA==}
     resolution: {integrity: sha512-vm2HBUmxAsXK0ivwce9LytcpqrItDA5JSPLYVxZXtiuoyhcn80XX1/3dPJd/1GqG1OYv3jfBo1s9ra4q8GowqA==}
@@ -16205,7 +16532,7 @@ packages:
       '@types/eslint': 8.44.1
       '@types/eslint': 8.44.1
       eslint: 8.37.0
       eslint: 8.37.0
       rollup: 2.79.1
       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
     dev: true
 
 
   /vite-plugin-externals@0.6.2(vite@4.5.3):
   /vite-plugin-externals@0.6.2(vite@4.5.3):

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików