Browse Source

Merge branch 'feature/v1.0.36' into dev/1.0.36_zsy

zhangsiya 1 year ago
parent
commit
2c35e9b204

+ 19 - 0
apps/bigmember_pc/src/api/modules/user.js

@@ -149,3 +149,22 @@ export function readMark(data) {
     data
   })
 }
+
+// 获取用户最高权限身份
+export function getUserHighestPowerIdentity(data) {
+  data = qs.stringify(data)
+  return request({
+    url: '/publicapply/identity/newProduct',
+    method: 'post',
+    data
+  })
+}
+
+export function changeUserIdentity(data) {
+  data = qs.stringify(data)
+  return request({
+    url: '/publicapply/identity/switch',
+    method: 'post',
+    data
+  })
+}

+ 1 - 0
apps/bigmember_pc/src/components/ad/activity-dialog.vue

@@ -215,6 +215,7 @@ export default {
 
 <style scoped lang="scss">
 .activity-dialog {
+  z-index: 2045 !important;
   &.support-full {
     .activity-content-container {
       position: fixed;

+ 5 - 0
apps/bigmember_pc/src/components/collect-info/CollectInfo.vue

@@ -776,6 +776,11 @@ export default {
           break
         }
       }
+
+      // 免费用户市场分析报告,不展示agree模块
+      if (source.includes('pc_analysis_')) {
+        this.moduleShow.agree = false
+      }
     },
     // 特殊字段参数处理
     addMoreParams (source, params, type = true) {

+ 121 - 0
apps/bigmember_pc/src/components/dialog/CheckPowerAndSwitch.vue

@@ -0,0 +1,121 @@
+<template>
+  <CustomDialog
+    show-close
+    width="336px"
+    top="30vh"
+    class="check-power-and-switch-dialog"
+    title="身份切换提醒"
+    :visible.sync="visible"
+    @close="onClose"
+  >
+    <div class="content-text" v-html="messageText"></div>
+    <template #footer>
+      <button
+        class="action-button confirm"
+        @click="onClickConfirm"
+        v-loading="loading"
+      >
+        立即切换
+      </button>
+      <button class="action-button cancel" @click="onClickCancel">
+        暂不切换
+      </button>
+    </template>
+  </CustomDialog>
+</template>
+<script>
+import Dialog from './Dialog.vue'
+import { getUserHighestPowerIdentity, changeUserIdentity } from '@/api/modules/'
+
+export default {
+  name: 'CheckPowerAndSwitch',
+  components: {
+    [Dialog.name]: Dialog
+  },
+  data() {
+    return {
+      visible: false,
+      loading: false,
+      targetIdentity: {
+        currentIdentity: '',
+        entId: '',
+        entName: '',
+        productType: '',
+        token: ''
+      }
+    }
+  },
+  computed: {
+    messageText() {
+      const { entName, productType, currentIdentity } = this.targetIdentity
+      const arr = [
+        '当前访问身份为',
+        `<span class="highlight-text">“${currentIdentity || ''}”</span>`,
+        ',系统识别您在',
+        `<span class="highlight-text">“${entName || ''}”</span>身份下有`,
+        `<span class="highlight-text">“${productType || ''}”</span>权限`,
+        ',建议您切换到该身份下使用剑鱼标讯。'
+      ]
+      return arr.join('')
+    }
+  },
+  created() {
+    this.getUserHighestIdentity()
+  },
+  methods: {
+    onClose() {
+      this.getUserHighestIdentity(true)
+    },
+    onClickCancel() {
+      this.getUserHighestIdentity(true)
+      this.showDialog(false)
+    },
+    async onClickConfirm() {
+      this.switchNow()
+    },
+    showDialog(f = false) {
+      this.visible = f
+    },
+    async getUserHighestIdentity(clear) {
+      let payload = {
+        isClear: clear ? true : undefined
+      }
+      const { error_code: code, data } = await getUserHighestPowerIdentity(payload)
+      if (code === 0 && data) {
+        this.targetIdentity = data
+        if (data.token) {
+          this.showDialog(true)
+        }
+      }
+    },
+    async switchNow() {
+      const p = this.targetIdentity
+      if (!p.token) return
+      try {
+        this.loading = true
+        const { error_code: code, data } = await changeUserIdentity({
+          token: p.token
+        })
+        if (code === 0 && data === 1) {
+          location.reload()
+        } else {
+          this.$toast('身份切换失败')
+        }
+        this.loading = false
+      } catch (error) {
+        this.loading = false
+      }
+    }
+  }
+}
+</script>
+<style scoped lang="scss">
+.content-text {
+  text-align: center;
+}
+.action-button {
+  &.cancel {
+    color: #1d1d1d;
+  }
+}
+</style>

+ 10 - 0
apps/bigmember_pc/src/components/dialog/Dialog.vue

@@ -5,6 +5,7 @@
     v-bind="$props"
     :show-close="showClose"
     :visible="visible"
+    :before-close="beforeClose"
     @update:visible="update"
     v-component-change-mount="{ selector: comMount }"
     @open="$emit('open')"
@@ -42,6 +43,7 @@ export default {
   props: {
     visible: Boolean,
     showClose: Boolean,
+    beforeClose: Function,
     comMount: {
       type: String,
       default: ''
@@ -99,6 +101,14 @@ export default {
     font-size: 14px;
     line-height: 22px;
   }
+  .el-dialog__body,
+  .el-dialog__footer {
+    padding-left: 32px;
+    padding-right: 32px;
+  }
+  .el-dialog__footer {
+    padding-top: 6px;
+  }
   .dialog-footer {
     display: flex;
     align-items: center;

+ 2 - 0
apps/bigmember_pc/src/views/article-content/pages/Article.vue

@@ -24,6 +24,7 @@ import RecommendCustomersList from '@/views/article-content/components/Recommend
 import ContentSummary from '@/views/article-content/components/ContentSummary.vue'
 import RecommendEnt from '@/views/article-content/components/RecommendEnt.vue'
 import QuickMonitor from '@/composables/quick-monitor/component/QuickMonitor.vue'
+import CheckPowerAndSwitch from '@/components/dialog/CheckPowerAndSwitch'
 import {
   useContentStore,
   ContentExpandsModel,
@@ -415,6 +416,7 @@ function doClickFreeView() {
             @doOpenCollect="doOpenCollectDialog"
             @doOpenCustomer="doOpenCustomer"
           ></content-mask>
+          <CheckPowerAndSwitch />
 
           <div v-if="!canShowMask.show">
             <!--  顶部提示 -->

+ 3 - 0
apps/bigmember_pc/src/views/portrayal/EntPortrayal.vue

@@ -249,6 +249,7 @@
         </div>
       </div>
     </div>
+    <CheckPowerAndSwitch />
     <!-- 分享弹窗 -->
     <shareBox ref="shareBox"></shareBox>
   </Layout>
@@ -270,6 +271,7 @@ import WorkspaceButtonGroup from '@/components/dialog/WorkspaceButtonGroup.vue'
 import { mapState } from 'vuex'
 import { Dialog, Input, TabPane, Tabs } from 'element-ui'
 import { dateFormatter, getAssetsFile, moneyUnit } from '@/utils'
+import CheckPowerAndSwitch from '@/components/dialog/CheckPowerAndSwitch'
 import tdk from '@/utils/mixins/set-tdk.js'
 import {
   getEntWinnerSelect,
@@ -297,6 +299,7 @@ export default {
     Layout,
     BidInfoActive,
     WorkspaceButtonGroup,
+    CheckPowerAndSwitch,
     ContactList,
     MaskCard,
     Empty,

+ 3 - 0
apps/bigmember_pc/src/views/portrayal/EntSearchPortrayal.vue

@@ -371,6 +371,7 @@
       <!-- 留资弹窗 -->
       <CollectInfo ref="collectRef"></CollectInfo>
     </div>
+    <CheckPowerAndSwitch />
     <!-- 分享弹窗 -->
     <shareBox ref="shareBox"></shareBox>
     <!-- 右侧未登录模块 -->
@@ -401,6 +402,7 @@ import EntFollowStar from './components/EntFollowStar.vue'
 import shareBox from '@/components/shareBox/index.vue'
 import AsideNewscards from './components/AsideNewscards.vue'
 import WorkspaceButtonGroup from '@/components/dialog/WorkspaceButtonGroup.vue'
+import CheckPowerAndSwitch from '@/components/dialog/CheckPowerAndSwitch'
 import Empty from '@/components/common/Empty'
 import { mapState } from 'vuex'
 import { TabPane, Tabs } from 'element-ui'
@@ -442,6 +444,7 @@ export default {
     DynamicList,
     AsideNewscards,
     WorkspaceButtonGroup,
+    CheckPowerAndSwitch,
     shareBox,
     crmAction,
     Empty

+ 9 - 6
apps/bigmember_pc/src/views/portrayal/UnitPortrayal.vue

@@ -455,6 +455,7 @@
       </template>
       您可联系客服,申请升级产品套餐,监控更多业主
     </common-dialog>
+    <CheckPowerAndSwitch />
     <CollectInfo ref="collectRef"></CollectInfo>
     <!-- 分享弹窗 -->
     <shareBox ref="shareBox"></shareBox>
@@ -483,6 +484,7 @@ import vPopper from '@/components/common/Popper.vue'
 import shareBox from '@/components/shareBox/index.vue'
 import AsideNewscards from './components/AsideNewscards.vue'
 import WorkspaceButtonGroup from '@/components/dialog/WorkspaceButtonGroup.vue'
+import CheckPowerAndSwitch from '@/components/dialog/CheckPowerAndSwitch'
 import monitorCom from '@/components/common/Monitor.vue'
 import { Button, Dialog, Popover } from 'element-ui'
 import { getAssetsFile, openSelfLink } from '@/utils/'
@@ -520,6 +522,7 @@ export default {
     [Dialog.name]: Dialog,
     [Button.name]: Button,
     [Popover.name]: Popover,
+    CheckPowerAndSwitch,
     Empty,
     vPopper,
     shareBox,
@@ -2049,14 +2052,14 @@ export default {
       left: 50%;
       margin-top: 0;
       transform: translate(-50%, -50%);
-    }
 
-    .el-dialog {
-      border-radius: 8px;
-    }
+      &.el-dialog {
+        border-radius: 8px;
+      }
 
-    .el-dialog__header {
-      padding: 0;
+      .el-dialog__header {
+        padding: 0;
+      }
     }
   }
 

+ 3 - 0
apps/bigmember_pc/src/views/subscribe/SubPush.vue

@@ -442,6 +442,7 @@
           </button>
         </template>
       </CustomDialog>
+      <CheckPowerAndSwitch />
       <FollowOfficialAccountDialog
         :visible.sync="dialog.toFollowOfficialAccount"
       ></FollowOfficialAccountDialog>
@@ -497,6 +498,7 @@ import RadioGroup from '@/components/selector/RadioGroup.vue'
 // import CustomReport from '@/components/custom-report/customReport.vue'
 import FollowOfficialAccountDialog from '@/components/dialog/FollowOfficialAccountDialog.vue'
 import ConfigContent from '@/components/subscribe-manager/index'
+import CheckPowerAndSwitch from '@/components/dialog/CheckPowerAndSwitch'
 import SubscribeOverview from '@/components/subscribe-overview/index'
 import {
   getFreeUserPushInfo,
@@ -532,6 +534,7 @@ export default {
     PriceSelector,
     RadioGroup,
     DrawerCard,
+    CheckPowerAndSwitch,
     [CustomDialog.name]: CustomDialog,
     // CustomReport,
     FollowOfficialAccountDialog,

+ 3 - 0
apps/bigmember_pc/src/views/workspace/dashboard.vue

@@ -30,6 +30,7 @@
     </el-aside>
     <ActivityDialog ad="jy-pc-index-tap" />
     <GuideIntroDialog />
+    <CheckPowerAndSwitch />
   </el-container>
 </template>
 
@@ -39,6 +40,7 @@ import { chunk } from 'lodash'
 import { Container, Aside, Main } from 'element-ui'
 import MessageTips from './components/MessageTips.vue'
 import CommonUse from './components/CommonUse.vue'
+import CheckPowerAndSwitch from '@/components/dialog/CheckPowerAndSwitch'
 import SubscribeList from './components/SubscribeList.vue'
 // import MyCollections from './components/MyCollections.vue'
 // import ProjectFollow from './components/ProjectFollow.vue'
@@ -82,6 +84,7 @@ export default {
     BusinessToDo,
     NewsList,
     AnalysisReport,
+    CheckPowerAndSwitch,
     MyEquityList
   },
   computed: {

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

@@ -1,5 +1,5 @@
 import request from '@/api'
-// import qs from 'qs'
+import qs from 'qs'
 // 获取企业列表
 export function getEntList(data) {
   // data = qs.stringify(data)
@@ -28,3 +28,13 @@ export function ajaxGetUserInfo(data) {
     data
   })
 }
+
+// 获取用户最高权限身份
+export function getUserHighestPowerIdentity(data) {
+  data = qs.stringify(data)
+  return request({
+    url: '/publicapply/identity/newProduct',
+    method: 'post',
+    data
+  })
+}

+ 13 - 21
apps/mobile/src/components/search/bidding/filters.vue

@@ -253,6 +253,7 @@
               <KeywordsInputGroup
                 :readonly="noLoginOrFree"
                 v-model="cacheMoreFilters.buyerList"
+                :maxTagCount="15"
                 inputMaxlength="30"
                 placeholder="输入采购单位名称,找其招标项目"
                 class="buyer-filter"
@@ -275,6 +276,7 @@
               <KeywordsInputGroup
                 :readonly="noLoginOrFree"
                 v-model="cacheMoreFilters.winnerList"
+                :maxTagCount="15"
                 inputMaxlength="30"
                 placeholder="输入中标企业名称,找其中标项目"
                 class="winner-filter"
@@ -297,6 +299,7 @@
               <KeywordsInputGroup
                 :readonly="noLoginOrFree"
                 v-model="cacheMoreFilters.agencyList"
+                :maxTagCount="15"
                 inputMaxlength="30"
                 placeholder="输入代理机构名称,找其代理项目"
                 class="winner-filter"
@@ -762,28 +765,16 @@ export default {
           sameList.push(deepCompare(this.filters.winnerConcat, winnerConcat))
           sameList.push(deepCompare(this.filters.buyerConcat, buyerConcat))
           sameList.push(deepCompare(this.filters.notKey, notKey))
-          sameList.push(
-            deepCompare(this.filters.winnerConcat, winnerConcat)
-          )
-          sameList.push(
-            deepCompare(this.filters.buyerConcat, buyerConcat)
-          )
-          sameList.push(
-            deepCompare(this.filters.notKey, notKey)
-          )
+          sameList.push(deepCompare(this.filters.winnerConcat, winnerConcat))
+          sameList.push(deepCompare(this.filters.buyerConcat, buyerConcat))
+          sameList.push(deepCompare(this.filters.notKey, notKey))
 
           // 采购单位
-          sameList.push(
-            deepCompare(this.filters.buyerList, buyerList)
-          )
+          sameList.push(deepCompare(this.filters.buyerList, buyerList))
           // 中标单位
-          sameList.push(
-            deepCompare(this.filters.winnerList, winnerList)
-          )
+          sameList.push(deepCompare(this.filters.winnerList, winnerList))
           // 代理机构
-          sameList.push(
-            deepCompare(this.filters.agencyList, agencyList)
-          )
+          sameList.push(deepCompare(this.filters.agencyList, agencyList))
 
           // 附件
           sameList.push(this.filters.fileExists === fileExists)
@@ -949,6 +940,7 @@ export default {
             this.cacheMoreFilters.priceCheckbox = priceCheckbox
             filters.priceCheckbox = priceCheckbox
             priceSelector?.setState(price)
+            filters.price = JSON.parse(JSON.stringify(price))
           }
 
           // 时间
@@ -1066,7 +1058,7 @@ export default {
             const priceState = priceSelector?.getState()
             filters.price = priceState
           } else {
-            filters.price = defaultPrice
+            filters.price = JSON.parse(JSON.stringify(defaultPrice))
           }
           filters.priceCheckbox = priceCheckbox
 
@@ -1100,9 +1092,9 @@ export default {
       this.$emit('confirm', { type })
       this.$refs[`${type}Dropdown`]?.toggle(false)
     },
-    onChange(value) {
+    onChange(value = {}) {
       const filters = {}
-      Object.assign(filters, this.filters, value)
+      Object.assign(filters, JSON.parse(JSON.stringify(this.filters)), value)
       this.$emit('change', filters)
     },
     popupState(type, state = false) {

+ 7 - 32
apps/mobile/src/components/treasure-box/CommonUse.vue

@@ -82,35 +82,13 @@ export default {
     getCommonUseList() {
       const _this = this
       this.loading = true
-      workspaceCommonUse('list', { platform: this.$env.platform?.toUpperCase() }).then(res => {
-        const { data = [], error_code: code } = res
-        if (code === 0 && data) {
-          const maxNum = data.num || 8
-          _this.commonList = data.list || []
-          _this.commonList.forEach(temp => {
-            // 计算背景色
-            calcImgThemeColor(temp.icon).then(({ color }) => {
-              // rgba转hex
-              const hex = rgb2Hex(color)
-              const { rgba } = hexToRgba(hex, 0.08)
-              this.$set(temp, 'themeColor', rgba)
-            })
-            if (_this.isSettings) {
-              temp.canAdd = false
-            }
-          })
-          // 初始化常用组件
-          _this.$store.dispatch('treasureBox/setCommonFunction', _this.commonList)
-          _this.$store.dispatch('treasureBox/setCommonMaxNum', maxNum)
-        }
-      }).finally(() => {
-        this.loading = false
-      })
+      workspaceCommonUse('list', { platform: this.$env.platform?.toUpperCase() })
         .then((res) => {
           const { data = [], error_code: code } = res
           if (code === 0 && data) {
-            _this.commonList = data
-            _this.commonList.forEach((temp) => {
+            const maxNum = data.num || 8
+            _this.commonList = data.list || []
+            _this.commonList.forEach(temp => {
               // 计算背景色
               calcImgThemeColor(temp.icon).then(({ color }) => {
                 // rgba转hex
@@ -123,13 +101,10 @@ export default {
               }
             })
             // 初始化常用组件
-            _this.$store.dispatch(
-              'treasureBox/setCommonFunction',
-              _this.commonList
-            )
+            _this.$store.dispatch('treasureBox/setCommonFunction', _this.commonList)
+            _this.$store.dispatch('treasureBox/setCommonMaxNum', maxNum)
           }
-        })
-        .finally(() => {
+        }).finally(() => {
           this.loading = false
         })
     },

+ 3 - 0
apps/mobile/src/views/article/content.vue

@@ -122,6 +122,7 @@
       v-model="popup.thirdPartyVerify"
       :beforeLeavePage="beforeLeavePage"
     />
+    <CheckPowerAndSwitch />
     <appShareSheet
       v-model="shareShow"
       @share="calcAppShareInfo"
@@ -164,6 +165,7 @@ import AdSingle from '@/components/ad/Ad.vue'
 import FreeUserBiddingMask from '@/views/article/components/FreeUserBiddingMask.vue'
 import FreeUserAdvancedMask from '@/views/article/components/FreeUserAdvancedMask.vue'
 import ThirdPartyVerifyPopup from '@/views/article/components/ThirdPartyVerifyPopup.vue'
+import CheckPowerAndSwitch from '@/views/identity/components/CheckPowerAndSwitch'
 import { throttle } from 'lodash'
 import { mapState, mapMutations, mapActions, mapGetters } from 'vuex'
 import { getArticleShareInfo, getContentShareEncrypt } from '@/api/modules/article'
@@ -192,6 +194,7 @@ export default {
     FreeUserBiddingMask,
     FreeUserAdvancedMask,
     ThirdPartyVerifyPopup,
+    CheckPowerAndSwitch,
     NpsCard,
     TabActions,
     AdSingle

+ 106 - 0
apps/mobile/src/views/identity/components/CheckPowerAndSwitch.vue

@@ -0,0 +1,106 @@
+<template>
+  <div class="check-power-and-switch"></div>
+</template>
+<script>
+import { getUserHighestPowerIdentity } from '@/api/modules/ent'
+import { changeUserIdentity } from '@/api/modules/mine'
+
+export default {
+  name: 'CheckPowerAndSwitch',
+  data() {
+    return {
+      targetIdentity: {
+        currentIdentity: '',
+        entId: '',
+        entName: '',
+        productType: '',
+        token: ''
+      }
+    }
+  },
+  computed: {
+    messageText() {
+      const { entName, productType, currentIdentity } = this.targetIdentity
+      const arr = [
+        '当前访问身份为',
+        `<span class="highlight-text">“${currentIdentity || ''}”</span>`,
+        ',系统识别您在',
+        `<span class="highlight-text">“${entName || ''}”</span>身份下有`,
+        `<span class="highlight-text">“${productType || ''}”</span>权限`,
+        ',建议您切换到该身份下使用剑鱼标讯。'
+      ]
+      return arr.join('')
+    }
+  },
+  created() {
+    this.getUserHighestIdentity()
+  },
+  methods: {
+    showDialog(conf = {}) {
+      const defaultConf = {
+        title: '',
+        message: '',
+        className: 'j-confirm-dialog',
+        messageAlign: 'left',
+        showCancelButton: false,
+        confirmButtonText: '我知道了'
+      }
+      Object.assign(defaultConf, conf)
+      return this.$dialog.confirm(defaultConf)
+    },
+    async showSwitchPowerDialog() {
+      try {
+        await this.showDialog({
+          title: '身份切换提醒',
+          message: this.messageText,
+          messageAlign: 'left',
+          showCancelButton: true,
+          confirmButtonText: '立即切换',
+          cancelButtonText: '暂不切换',
+          beforeClose: this.beforeClose
+        })
+      } catch (error) {
+        this.getUserHighestIdentity(true)
+      }
+    },
+    async beforeClose(action, done) {
+      if (action === 'confirm') {
+        await this.switchNow()
+        done()
+      } else {
+        done()
+      }
+    },
+    async getUserHighestIdentity(clear) {
+      let payload = {
+        isClear: clear ? true : undefined
+      }
+      const { error_code: code, data } = await getUserHighestPowerIdentity(payload)
+      if (code === 0 && data) {
+        this.targetIdentity = data
+        if (data.token) {
+          this.showSwitchPowerDialog(this.targetIdentity)
+        }
+      }
+    },
+    async switchNow() {
+      const p = this.targetIdentity
+      if (!p.token) return
+      try {
+        this.loading = true
+        const { error_code: code, data } = await changeUserIdentity({
+          token: p.token
+        })
+        if (code === 0 && data === 1) {
+          location.reload()
+        } else {
+          this.$toast('身份切换失败')
+        }
+        this.loading = false
+      } catch (error) {
+        this.loading = false
+      }
+    }
+  }
+}
+</script>

+ 3 - 0
apps/mobile/src/views/search/middle/bidding/index.vue

@@ -45,12 +45,14 @@
         </div>
       </div>
     </div>
+    <CheckPowerAndSwitch />
   </div>
 </template>
 
 <script>
 import { HistoryList, AppIcon } from '@/ui'
 import HotKeyCard from '@/components/search/middle/HotKeyCard.vue'
+import CheckPowerAndSwitch from '@/views/identity/components/CheckPowerAndSwitch'
 import {
   getBiddingSearchHistory,
   getBiddingFilterList,
@@ -73,6 +75,7 @@ export default {
   components: {
     AppIcon,
     HotKeyCard,
+    CheckPowerAndSwitch,
     HistoryList
   },
   inject: {

+ 148 - 47
apps/mobile/src/views/search/result/bidding/index.vue

@@ -2,6 +2,7 @@
   <div class="j-container search-result-bidding top-radius">
     <div
       class="bidding-advanced-switch"
+      v-if="conf.searchGroupList.length"
       :class="{ 'loading-mask': listState.loading }"
     >
       <van-tabs
@@ -30,7 +31,7 @@
       <!-- 筛选器 -->
       <BiddingSearchFilters
         :bidColPower="pageState.bidColPower"
-        class="top-radius "
+        class="top-radius"
         :class="{ 'loading-mask': listState.loading }"
         ref="searchFilters"
         @noPower="onNoPower"
@@ -120,6 +121,25 @@
             </div>
           </div>
         </div>
+        <div
+          class="tip-toggle-search-mode-container"
+          v-show="toggleBlurModeTip.show"
+        >
+          <div>
+            如需查看更多相关信息,建议您将搜索模式切换为
+            <div class="tip-action highlight-text">
+              “模糊搜索”
+              <AppIcon
+                class="search-mode-label-icon"
+                name="help1"
+                @click="showSearchModeHelp"
+              >
+              </AppIcon>
+            </div>
+            按照当前条件共匹配到{{ toggleBlurModeTip.count }}条公告。
+          </div>
+          <button @click="doToggleSearchBlurMode">立即切换查看</button>
+        </div>
         <div class="list-wrapper" ref="listWrapper">
           <van-popup
             :style="popupHeight"
@@ -514,7 +534,7 @@ export default {
             id: '5',
             title: '招标结果',
             name: 'zbjg'
-          },
+          }
         ],
         tabListFree: [
           {
@@ -656,7 +676,11 @@ export default {
       },
       showBidStatus: false,
       popupHeight: 'height: 440px',
-      projectCellInfo: {}
+      projectCellInfo: {},
+      toggleSearchBlurData: {
+        show: false,
+        count: ''
+      }
     }
   },
   computed: {
@@ -835,6 +859,19 @@ export default {
      */
     inInjectBI() {
       return this.$route.name === 'search-bi-bidding'
+    },
+    // 切换模糊搜索
+    toggleBlurModeTip() {
+      const isBlurMode = this.filters.searchMode.indexOf('1') !== -1
+      let canShow = isBlurMode ? false : this.toggleSearchBlurData.show
+      if (this.listState.loading) {
+        canShow = false
+      }
+      const result = {
+        show: canShow,
+        count: this.toggleSearchBlurData.count
+      }
+      return result
     }
   },
   provide() {
@@ -925,20 +962,35 @@ export default {
     formatMoney,
     dateFormatter,
     replaceKeyword,
+    // 切换到模糊搜索
+    doToggleSearchBlurMode() {
+      this.switchSearchMode(1)
+      this.doSearch()
+    },
+    async showSearchModeHelp() {
+      return await this.$dialog.alert({
+        title: '搜索模式',
+        messageAlign: 'left',
+        className: 'j-confirm-dialog',
+        confirmButtonText: '我知道了',
+        message:
+          '<p>精准搜索: 搜索结果必须完全包含完整的关键词。如搜索"医疗设备" ,搜索结果一定完整包含“医疗设备”才能被搜索到,而“医疗的设备”或“设备医疗”的项目不会被搜索到。</p><br /><p>模糊搜索: 系统会先自动智能分词然后再进行搜索。如搜索"医疗设备" ,系统会自动分成“医疗”“设备”然后进行搜索,只要项目中出现“医疗”和“设备”都会被搜索到,前提是两个词必须一同出现在一则公告内,不分先后顺序。</p>'
+      })
+    },
     initBiHeaderTab() {
       // 山川应用下隐藏非招标结果的信息类型
       // 仅保留['全部', '招标结果', '招标信用信息']
-      this.searchGroupList = [
+      this.conf.searchGroupList = [
         {
           id: '0',
           title: '全部',
           name: ''
-        },
-        {
-          id: '5',
-          title: '招标结果',
-          name: 'zbjg'
-        },
+        }
+        // {
+        //   id: '5',
+        //   title: '招标结果',
+        //   name: 'zbjg'
+        // }
       ]
     },
     /**
@@ -1003,7 +1055,7 @@ export default {
       }
     },
     initDefaultFilterState() {
-      Object.assign(this.filters, this.defaultFilterState)
+      Object.assign(this.filters, JSON.parse(JSON.stringify(this.defaultFilterState)))
       this.$nextTick(() => {
         this.filters.keywords = this.topSearch.input
       })
@@ -1015,11 +1067,13 @@ export default {
     },
     getQueryString() {
       const { searchGroup } = this.$route.query
-      const searchGroupMap = this.conf.searchGroupList.map((s) => s.id)
-      if (searchGroup && searchGroupMap.includes(searchGroup)) {
-        this.pageState.searchGroup = searchGroup
-      } else {
-        this.pageState.searchGroup = this.conf.searchGroupList[0].id
+      if (this.conf.searchGroupList.length) {
+        const searchGroupMap = this.conf.searchGroupList.map((s) => s.id)
+        if (searchGroup && searchGroupMap.includes(searchGroup)) {
+          this.pageState.searchGroup = searchGroup
+        } else {
+          this.pageState.searchGroup = this.conf.searchGroupList[0].id
+        }
       }
     },
     calcInitFilters() {
@@ -1499,25 +1553,15 @@ export default {
             this.$toast('精准搜索无结果,已为您自动切换到模糊搜索')
           }
         }
-      } else {
-        // 搜索结果无数据,自动切换搜索模式到模糊搜索
-        /* 切换搜索模式逻辑 start */
-        if (params.pageNum === 1) {
-          if (params.searchMode === 0) {
-            this.switchSearchMode(1)
-            this.pageState.searchModeAutoChangedSearch = true
-            this.doSearch({ from: 'searchModeAutoChangedSearch' })
-          } else if (params.searchMode === 1) {
-            if (this.pageState.searchModeAutoChangedSearch) {
-              // 自动切换搜索模式搜索后还没查到数据,就改回精准搜索
-              this.switchSearchMode(0)
-              this.pageState.searchModeAutoChangedSearch = false
-            }
-          }
-        }
-        /* 切换搜索模式逻辑 end */
       }
 
+      this.checkToggleSearchMode({
+        pageNum: params.pageNum,
+        count: data.total || 0,
+        blurCount: data?.bCount || 0,
+        searchMode: params.searchMode
+      })
+
       if (params.pageNum === 1) {
         // 保存更多关键词到历史记录中
         this.saveAdditionalWordsToHistory()
@@ -1527,6 +1571,40 @@ export default {
         }
       }
     },
+    /**
+     * 检查是否需要切换模糊搜索、是否展示提示
+     * 1. 精准搜索无数据 (自动切换模糊搜索)
+     * 2. 精准搜索有数据,< 50,提示手动切换搜索模式
+     */
+    checkToggleSearchMode({
+      pageNum = 1,
+      searchMode = 0,
+      count = 0,
+      blurCount = 0
+    }) {
+      if (pageNum === 1) {
+        // 重置变量
+        this.toggleSearchBlurData.show = false
+        this.toggleSearchBlurData.count = ''
+
+        if (searchMode === 0) {
+          const canAutoToggleBlurMode = count < 1 && blurCount > count
+          const canShowToggleBlurModeTip =
+            count >= 1 && count < 50 && blurCount > count
+
+          if (canShowToggleBlurModeTip) {
+            this.toggleSearchBlurData.show = true
+            this.toggleSearchBlurData.count = blurCount
+          }
+
+          if (canAutoToggleBlurMode) {
+            this.switchSearchMode(1)
+            this.pageState.searchModeAutoChangedSearch = true
+            this.doSearch({ from: 'searchModeAutoChangedSearch' })
+          }
+        }
+      }
+    },
     // 切换搜索模式:精准搜索0/模糊搜索1
     switchSearchMode(m) {
       this.filters.searchMode = [m + '']
@@ -1610,7 +1688,8 @@ export default {
       }
       // 是否有附件
       item.isFile = item?.fileExists || false
-      item.leftTopBadgeText = item.site === '剑鱼信息发布平台' ? '业主委托项目' : ''
+      item.leftTopBadgeText =
+        item.site === '剑鱼信息发布平台' ? '业主委托项目' : ''
       // 拟建项目独有参数
       if (projectInfo) {
         Object.assign(item, projectInfo)
@@ -2176,7 +2255,7 @@ export default {
         done()
       }
     },
-    formatFilterItems (item) {
+    formatFilterItems(item) {
       item.scope = item.selectType
       item.infotype = item.subtype
       const formatted = FilterHistoryAjaxModel2ViewModel.formatAll(item)
@@ -2274,6 +2353,7 @@ export default {
           listState: this.listState,
           pageState: this.pageState,
           BIInfo: this.BIInfo,
+          toggleSearchBlurData: this.toggleSearchBlurData,
           recommendInfo: this.recommendInfo
         },
         { storage: sessionStorage }
@@ -2374,16 +2454,15 @@ export default {
       if (replace && Object.keys(replace).length) {
         Object.assign(params, replace)
       }
-      this.$storage.set(
-        BIDDING_SEARCH_LAST_FILTERS_CACHE_KEY,
-        params,
-        {
-          login: true
-        }
-      )
+      this.$storage.set(BIDDING_SEARCH_LAST_FILTERS_CACHE_KEY, params, {
+        login: true
+      })
     },
     restoreSearchGroupFromLocal() {
-      const params = this.$storage.get(BIDDING_SEARCH_GROUP_LAST_CACHE_KEY, false)
+      const params = this.$storage.get(
+        BIDDING_SEARCH_GROUP_LAST_CACHE_KEY,
+        false
+      )
       if (params) {
         this.pageState.searchGroup = params.searchGroup
       }
@@ -2392,10 +2471,7 @@ export default {
       const params = {
         searchGroup: this.pageState.searchGroup
       }
-      this.$storage.set(
-        BIDDING_SEARCH_GROUP_LAST_CACHE_KEY,
-        params
-      )
+      this.$storage.set(BIDDING_SEARCH_GROUP_LAST_CACHE_KEY, params)
     },
     beforeTabActiveChange(name) {
       if (name === 'detailedList') {
@@ -2528,6 +2604,31 @@ export default {
 }
 </style>
 <style lang="scss" scoped>
+.tip-toggle-search-mode-container {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  margin: 8px 16px;
+  margin-top: 0;
+  padding: 12px 16px;
+  background: linear-gradient(180deg, #e8ffff 0%, #ffffff 100%);
+  border: 0.5px solid #2abed1;
+  border-radius: 8px;
+  color: #5f5e64;
+  font-size: 13px;
+  line-height: 20px;
+  .tip-action {
+    display: inline-flex;
+    align-items: center;
+  }
+  button {
+    margin-top: 12px;
+    background: #2abed1;
+    padding: 5px 12px;
+    border-radius: 4px;
+    color: #f7f9fa;
+  }
+}
 .search-result-bidding {
   background: #f5f5f5;
   ::v-deep {

+ 3 - 0
apps/mobile/src/views/tabbar/Box.vue

@@ -39,6 +39,7 @@
         <all-use :all-need-badge="false" @openLink="openLink" />
       </div>
     </div>
+    <CheckPowerAndSwitch />
   </div>
 </template>
 <script>
@@ -48,6 +49,7 @@ import Swiper from '@/components/treasure-box/Swiper'
 import RecommendList from '@/components/treasure-box/Recommend'
 import CommonUse from '@/components/treasure-box/CommonUse'
 import AllUse from '@/components/treasure-box/AllUse'
+import CheckPowerAndSwitch from '@/views/identity/components/CheckPowerAndSwitch'
 import { openLinkOfOther, openAppOrWxPage } from '@/utils'
 import { LINKS, AdCode } from '@/data'
 import { mapGetters } from 'vuex'
@@ -65,6 +67,7 @@ export default {
     CommonUse,
     AllUse,
     RecommendList,
+    CheckPowerAndSwitch,
     [AppIcon.name]: AppIcon
   },
   data() {

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

@@ -67,6 +67,7 @@
       @close="closeNewUserPop"
       @load="toggleMessagePopShow(false)"
     />
+    <CheckPowerAndSwitch />
     <!-- 新注册用户底部悬浮广告位 -->
     <!-- <div class="new-user--pop-bottom" :class="{ 'has-wx': $envs.inWX }" v-if="isLogin && newUserPopConfig.showBottomPop && AD.newUserPopOfBottom.pic">
       <ad-single class="subscribe-top-box" :config="AD.newUserPopOfBottom"  :before-open="beforeOpenNewUserAD"  :show-tag="false" @close="closeNewUserPopOfBottom" @load="toggleMessagePopShow(false)"></ad-single>
@@ -90,6 +91,7 @@ import {
 } from '@/api/modules'
 import MessageCard from '@/components/message/message-card'
 import { adConfigFormatter } from '@/utils/format/modules/ad-formatter'
+import CheckPowerAndSwitch from '@/views/identity/components/CheckPowerAndSwitch'
 import {
   transferMethodsOfRefs,
   openLinkOfOther,
@@ -120,6 +122,7 @@ export default {
     MessageCard,
     Swipe,
     SwipeFloor,
+    CheckPowerAndSwitch,
     [Side.name]: Side,
     [Button.name]: Button,
     [Cell.name]: Cell,

+ 3 - 0
apps/mobile/src/views/tabbar/Layout.vue

@@ -19,6 +19,7 @@
         </div>
       </van-overlay>
       <router-view></router-view>
+      <!-- <CheckPowerAndSwitch /> -->
     </div>
     <!-- 此处必须用v-if,因为footerTabbar的mounted中清除了app的历史记录 -->
     <div class="j-footer" v-show="getFooterShow">
@@ -30,6 +31,7 @@
 <script>
 import { Overlay } from 'vant'
 import FooterTabbar from '@/components/footer-tabbar'
+// import CheckPowerAndSwitch from '@/views/identity/components/CheckPowerAndSwitch'
 import { callHideTab } from '@/utils'
 import { mapActions, mapGetters } from 'vuex'
 import { ajaxGetTipInfo } from '@/api/modules'
@@ -47,6 +49,7 @@ const beforeunload = function () {
 export default {
   name: 'TabbarLayout',
   components: {
+    // CheckPowerAndSwitch,
     [FooterTabbar.name]: FooterTabbar,
     [Overlay.name]: Overlay
   },

+ 3 - 0
apps/mobile/src/views/tabbar/Message.vue

@@ -79,6 +79,7 @@
         <p>暂无消息</p>
       </AppEmpty>
     </div>
+    <CheckPowerAndSwitch />
   </div>
 </template>
 
@@ -96,6 +97,7 @@ import { callChangeTab, checkNowInAppTabbarPage } from '@/utils/callFn/'
 import { appCallReloadTab } from '@/utils/callFn/appFn'
 import { MESSAGE } from '@/data'
 import { AppEmpty, AppIcon } from '@/ui'
+import CheckPowerAndSwitch from '@/views/identity/components/CheckPowerAndSwitch'
 import { openLinkOfOther, iosBackRefresh } from '@/utils'
 import { mapState, mapActions } from 'vuex'
 
@@ -104,6 +106,7 @@ export default {
   components: {
     [Badge.name]: Badge,
     [Icon.name]: Icon,
+    CheckPowerAndSwitch,
     AppEmpty,
     AppIcon
   },

+ 3 - 0
apps/mobile/src/views/tabbar/Mine.vue

@@ -8,6 +8,7 @@
       <!--菜单列表-->
       <mine-list />
     </div>
+    <CheckPowerAndSwitch />
   </div>
 </template>
 
@@ -18,6 +19,7 @@ import MineList from '@/components/mine/MineList'
 import store from '@/store'
 import { appCallBackTab } from '@/utils/callFn/appFn'
 import { envs } from '@/utils/prototype/modules/platform'
+import CheckPowerAndSwitch from '@/views/identity/components/CheckPowerAndSwitch'
 import { callHideRedSpotOnMenu } from '@/utils'
 
 export default {
@@ -25,6 +27,7 @@ export default {
   components: {
     MineHeader,
     SignIn,
+    CheckPowerAndSwitch,
     MineList
   },
   async beforeRouteEnter(to, from, next) {

+ 3 - 0
apps/mobile/src/views/tabbar/Subscribe.vue

@@ -474,6 +474,7 @@
       ref="popup_dataExport"
       @next="next_export"
     ></popupDataexport>
+    <CheckPowerAndSwitch />
   </div>
 </template>
 
@@ -500,6 +501,7 @@ import DataReportTip from '@/components/subscribe/DataReportTip'
 import RecommendCard from '@/components/recommend/'
 import Ad from '@/components/ad/Ad'
 import popupDataexport from '@/components/dataExport/popupDataexport.vue'
+import CheckPowerAndSwitch from '@/views/identity/components/CheckPowerAndSwitch'
 import { LINKS, vtMap, AdCode } from '@/data'
 import { wxShareMixin } from '@/utils/mixins/modules/wx-share'
 import { iosBackRefresh } from '@/utils/utils'
@@ -567,6 +569,7 @@ export default {
     [DropFilter.name]: DropFilter,
     [DatetimePicker.name]: DatetimePicker,
     [IndustrySidebar.name]: IndustrySidebar,
+    CheckPowerAndSwitch,
     RecommendCard,
     bidStatusNode,
     popupDataexport,