Ver Fonte

Merge branch 'main' into feature/v1.0.61

yuelujie há 11 meses atrás
pai
commit
6f548f351d

+ 6 - 1
apps/bigmember_pc/src/api/interceptors-anti.js

@@ -1,5 +1,10 @@
 import service from './service'
+import Vue from 'vue'
 import { registerAntiInterceptors } from '@jy/vue-anti'
+const loginButtonClick = () => {
+  Vue.prototype.$showLoginDialog(false, 'reload')
+}
+
+registerAntiInterceptors(service, { loginButtonClick })
 
-registerAntiInterceptors(service)
 export default service

+ 58 - 1
apps/jy-pc/src/views/proposed-detail/Detail.vue

@@ -1,6 +1,17 @@
 <template>
   <Layout v-loading="loading" class="demand-detail">
-    <div class="proposed-detail">
+    <div class="empty-content" v-if="emptyContent">
+      <empty>
+        <div class="empty-text-content">
+          <p>{{ emptyReasonText }}</p>
+          <div class="empty-content-actions">
+            <p class="empty-content-actions-text">5s后自动跳转到剑鱼官网首页</p>
+            <button class="empty-content-actions-button" @click="goToJyHome">前往剑鱼官网首页</button>
+          </div>
+        </div>
+      </empty>
+    </div>
+    <div class="proposed-detail" v-else>
       <div class="head">
         <div class="action-right-container" v-if="loginIn">
           <WorkspaceButtonGroup></WorkspaceButtonGroup>
@@ -107,6 +118,7 @@ import InformationSummary from './components/InformationSummary.vue'
 import projectDebriefing from './components/projectDebriefing.vue'
 import ProjectPerson from './components/ProjectPerson.vue'
 import Credentials from './components/Credentials.vue'
+import Empty from '@/components/empty/Empty.vue'
 import WorkspaceButtonGroup from '@/components/dialog/WorkspaceButtonGroup.vue'
 import { getLoginStatus } from '@/api/modules/front'
 import { getCommonAdList } from '@/api/modules/ad'
@@ -116,6 +128,7 @@ export default {
   name: 'proposed-detail',
   components: {
     Layout,
+    Empty,
     InformationSummary,
     ProjectPerson,
     projectDebriefing,
@@ -124,6 +137,8 @@ export default {
   },
   data() {
     return {
+      emptyContent: false,
+      emptyReasonText: '该页面信息不存在',
       isVisible: false,
       loading: false,
       loginIn: false,
@@ -161,6 +176,14 @@ export default {
       }
       this.tab = index
     },
+    goToJyHome() {
+      window.top.location.href = '/'
+    },
+    startEmptyAutoGoHome() {
+      setTimeout(() => {
+        this.goToJyHome()
+      }, 5000)
+    },
     initdata() {
       this.pid = this.$route.query.pid
       details({ pid: this.pid }).then((res) => {
@@ -191,6 +214,13 @@ export default {
                 .setAttribute('content', '拟在建详情')
             }
           } catch (e) {}
+        } else {
+          const msg = res.error_msg || ''
+          if (msg.includes('不存在')) {
+            this.emptyReasonText = '由于相关部门要求,该信息已下架,敬请原谅'
+          }
+          this.emptyContent = true
+          this.startEmptyAutoGoHome()
         }
       })
     },
@@ -249,6 +279,31 @@ export default {
 .mt-8 {
   margin-top: 8px;
 }
+.empty-content {
+  width: 100%;
+  background-color: #fff;
+  p {
+    font-size: 16px;
+  }
+}
+.empty-text-content {
+  text-align: center;
+}
+.empty-content-actions {
+  margin-top: 6px;
+}
+.empty-content-actions-text {
+  margin-bottom: 6px;
+}
+.empty-content-actions-button {
+  width: 180px;
+  height: 40px;
+  font-size: 16px;
+  background-color: $main;
+  color: #fff;
+  border-radius: 4px;
+}
+
 .proposed-detail {
   padding-bottom: 20px;
   .head {
@@ -413,6 +468,8 @@ export default {
 }
 .demand-detail {
   width: 100%;
+  margin: 0 auto;
+  padding: 32px 0;
   ::v-deep {
     .content-main {
       display: flex;

+ 12 - 1
apps/mobile/src/api/interceptors-anti.js

@@ -1,5 +1,16 @@
 import service from './service'
 import { registerAntiInterceptors } from '@jy/vue-anti'
+import { openLinkOfOther } from '@/utils'
+import { LINKS } from '@/data'
+
+const loginButtonClick = () => {
+  openLinkOfOther(LINKS.APP登录页.app, {
+    query: {
+      to: 'back'
+    }
+  })
+}
+
+registerAntiInterceptors(service, { loginButtonClick })
 
-registerAntiInterceptors(service)
 export default service

BIN
apps/mobile/src/assets/image/public/logo-banner-full.png


BIN
apps/mobile/src/assets/image/public/logo-banner.png


+ 14 - 2
apps/mobile/src/components/footer-tabbar/index.vue

@@ -172,8 +172,20 @@ export default {
       const item = this.navs[navIndex]
       this.setActiveIcon(key)
       this.$emit('change', item)
-      callChangeTab(item.key, this.$router)
-      this.getCount()
+      if(!this.isLogin) {
+        if (item.key === 'subscribe') {
+          // TODO 跳转到订阅引导页
+          location.replace('/jyapp/freesubscribe/')
+        } else if (item.key === 'box') {
+          // TODO 跳转到工作台引导页
+          location.replace('/jyapp/workbench/')
+        } else {
+          callChangeTab(item.key, this.$router)
+        }
+      } else {
+        callChangeTab(item.key, this.$router)
+        this.getCount()
+      }
     }
   }
 }

+ 210 - 0
apps/mobile/src/components/no-login/NoLoginTabbar.vue

@@ -0,0 +1,210 @@
+<template>
+  <van-tabbar
+    :active-key="getNowActiveKey"
+    class="footer-box"
+    :fixed="false"
+    :safe-area-inset-bottom="true"
+    active-color="#2DA0FF"
+    inactive-color="#B7B7B7"
+    v-model="nowNavKey"
+    @change="onChange"
+  >
+    <van-tabbar-item
+      v-for="item in navs"
+      :name="item.key"
+      :key="item.key"
+    >
+      <div class="tabbar-image" slot="icon" slot-scope="props">
+        <AppIcon v-show="!props.active" :name="item.icon" />
+        <div
+          v-show="props.active"
+          class="lottie-an-tabbar"
+          ref="lottie"
+          :data-lottie-key="item.lottie"
+        />
+      </div>
+      <span
+        class="tabbar-title"
+        :class="{ active: props.active }"
+        slot-scope="props"
+        >{{ item.label }}</span
+      >
+    </van-tabbar-item>
+  </van-tabbar>
+</template>
+<script>
+// TODO 混合旧项目,暂时无法直接使用 route 模式,需手动跳转路由
+import lottie from 'lottie-web'
+import { Tabbar, TabbarItem } from 'vant'
+import { AppIcon } from '@/ui'
+import TabbarAnimationData from '@/assets/lottie/tabbar'
+import { mapGetters } from 'vuex'
+
+export default {
+  name: 'FooterTabbar',
+  components: {
+    [Tabbar.name]: Tabbar,
+    [TabbarItem.name]: TabbarItem,
+    [AppIcon.name]: AppIcon
+  },
+  props: {},
+  data: function () {
+    return {
+      isMounted: false,
+      nowNavKey: this.$route.meta?.tabbar || 'search',
+      navs: [
+        {
+          key: 'search',
+          label: '首页',
+          link: '/home',
+          icon: 'nav_un_home',
+          lottie: 'home'
+        },
+        {
+          key: 'subscribe',
+          label: '订阅',
+          link: '/subscribe',
+          icon: 'nav_un_book',
+          lottie: 'subscribe'
+        },
+        {
+          key: 'message',
+          label: '消息',
+          link: '/message',
+          icon: 'nav_un_message',
+          lottie: 'message'
+        },
+        {
+          key: 'box',
+          label: '工作台',
+          link: '/box',
+          icon: 'workSpace',
+          lottie: 'box'
+        },
+        {
+          key: 'me',
+          label: '我的',
+          link: '/me',
+          icon: 'nav_un_mine',
+          lottie: 'mine'
+        }
+      ]
+    }
+  },
+  computed: {
+    getTabbarKeys() {
+      return this.navs.map((v) => v.key)
+    },
+    getNowActiveKey() {
+      const nowKey = this.$route.meta?.tabbar
+      if (this.isMounted) {
+        this.refreshActiveIndex()
+      }
+      return nowKey
+    },
+    ...mapGetters('user', ['isLogin'])
+  },
+  mounted() {
+    this._LottieItems = this.navs.map((v, index) => {
+      return {
+        op: TabbarAnimationData[v.lottie].op,
+        lottie: lottie.loadAnimation({
+          animationData: Object.assign({}, TabbarAnimationData[v.lottie]),
+          loop: false,
+          autoplay: false,
+          renderer: 'svg',
+          container: this.$refs.lottie[index]
+        })
+      }
+    })
+    this.isMounted = true
+    this.setActiveIcon(this.nowNavKey)
+  },
+  methods: {
+    getIndex(key) {
+      return this.getTabbarKeys.indexOf(key)
+    },
+    refreshActiveIndex() {
+      this.nowNavKey = this.$route.meta?.tabbar
+      this.setActiveIcon(this.nowNavKey)
+    },
+    setActiveIcon(key) {
+      const index = this.getIndex(key)
+      if (index === -1) {
+        return
+      }
+      this._LottieItems[index].lottie.goToAndPlay(0, true)
+    },
+    onChange(key) {
+      const navIndex = this.getIndex(key)
+      if (navIndex === -1) {
+        return
+      }
+      // const item = this.navs[navIndex]
+      this.setActiveIcon(key)
+      if (key === 'subscribe') {
+        window.location.replace('/jyapp/freesubscribe/')
+      } else if (key === 'box') {
+        window.location.replace('/jyapp/workbench/')
+      } else if(key === 'message') {
+        window.location.href = '/jyapp/free/login?url=/jyapp/frontPage/messageCenter/sess/index'
+      } else if(key === 'me') {
+        window.location.href = '/jyapp/free/login?url=/jyapp/free/me'
+      } else if(key === 'search') {
+        window.location.replace('/')
+      }
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+$icon-size: 24px;
+$label-color: #171826;
+$label-color--active: #2abed1;
+
+.footer-box {
+  background: #fff;
+  box-shadow: inset 0px 0.5px 0px rgba(0, 0, 0, 0.04);
+  &::after {
+    border-color: transparent;
+  }
+}
+.van-tabbar-item__icon {
+  margin-bottom: 1px;
+}
+.van-tabbar-item {
+  padding-top: 5px;
+  justify-content: flex-start;
+  ::v-deep .van-info {
+    z-index: 1;
+  }
+}
+
+.tabbar-image {
+  position: relative;
+  width: $icon-size;
+  height: $icon-size;
+  .lottie-an-tabbar {
+    position: absolute;
+    top: 0;
+    left: 0;
+    z-index: 1;
+    width: inherit;
+    height: inherit;
+  }
+  i {
+    font-size: $icon-size;
+    color: $label-color;
+  }
+}
+.van-tabbar-item__text span.tabbar-title {
+  &.active {
+    color: $label-color--active;
+  }
+  color: $label-color;
+  font-size: 10px;
+  font-weight: 500;
+  line-height: 16px;
+  transition: color 0.2s;
+}
+</style>

+ 23 - 1
apps/mobile/src/components/search/Layout.vue

@@ -1,8 +1,17 @@
 <template>
   <div class="j-container layout-search">
+    <div
+      class="no-login-header"
+      :class="{
+        'app-no-login-header': $envs.inApp && !isLogin
+      }"
+      v-if="!isLogin"
+    >
+      <img class="img-logo" src="@/assets/image/public/logo-banner-full.png" alt="logo">
+    </div>
     <top-search
       :class="{
-        'app-header-top': $envs.inApp
+        'app-header-top': $envs.inApp && isLogin
       }"
       :value="value"
       :placeholder="placeholder"
@@ -21,6 +30,7 @@
 <script>
 import TopSearch from '@/components/search/TopSearch'
 import { debounce } from 'lodash'
+import { mapGetters } from 'vuex'
 
 export default {
   name: 'LayoutSearch',
@@ -50,6 +60,9 @@ export default {
       default: '多个关键词用空格隔开'
     }
   },
+  computed: {
+    ...mapGetters('user', ['isLogin'])
+  },
   methods: {
     onSubmit: debounce(
       function (type, data) {
@@ -93,6 +106,15 @@ export default {
   .app-header-top {
     padding-top: $app-header-padding-top;
   }
+  .no-login-header{
+    padding: 8px 0;
+    background: linear-gradient(#05B6CD, #4FCBDB);
+    text-align: center;
+  }
+  .app-no-login-header{
+    padding-top: $app-header-padding-top;
+    background: linear-gradient(#00AEE5, #05B6CD, #4FCBDB);;
+  }
 
   ::v-deep {
     .top-radius {

+ 216 - 0
apps/mobile/src/components/search/bidding/NoLoginBidList.vue

@@ -0,0 +1,216 @@
+<template>
+  <div class="new-list-module">
+    <div class="divider-container">
+      <span class="divider-title">招标信息</span>
+      <a class="divider-more" href="/">查看更多</a>
+    </div>
+    <van-loading v-if="loading" style="text-align: center" />
+    <div class="list">
+      <project-cell
+        class="right-bottom"
+        v-for="(item, index) in list"
+        :time-fmt="getTimeFmt"
+        :key="index"
+        :title="item.title"
+        :keys="item.keys"
+        card-type="detailed"
+        :detail="item.detail"
+        :line="false"
+        :tags="item.tags"
+        :time="item.time"
+        :isFile="false"
+        :leftTopBadgeText="item.leftTopBadgeText"
+        v-visited:content="item.id"
+        @click="onClick(item)"
+      >
+        <template slot="icon">
+          <div class="right-event" @click.stop="onKeep(item, index)">
+            <AppIcon
+              style="margin-right: 4px"
+              svg
+              size="20"
+              :name="item.isCollected ? 'shoucang' : 'shoucang_weishoucang'"
+            />
+            <span class="label-icon">收藏</span>
+          </div>
+        </template>
+      </project-cell>
+    </div>
+  </div>
+</template>
+
+<script>
+import { Button, Loading, Popup, Divider, Icon } from 'vant'
+import { AppEmpty, AppIcon, ProjectCell } from '@/ui'
+import { ajaxGetIndexList } from '@/api/modules'
+import {
+  formatMoney,
+  openAppOrWxPage,
+  openLinkOfOther
+} from '@/utils'
+import { LINKS } from '@/data'
+import qs from 'qs'
+import { mapState, mapGetters } from 'vuex'
+export default {
+  name: 'home-list',
+  components: {
+    [AppEmpty.name]: AppEmpty,
+    [AppIcon.name]: AppIcon,
+    [ProjectCell.name]: ProjectCell,
+    [Icon.name]: Icon,
+    [Popup.name]: Popup,
+    [Button.name]: Button,
+    [Loading.name]: Loading,
+    [Divider.name]: Divider
+  },
+  data() {
+    return {
+      loaded: false,
+      loading: false,
+      list: [],
+      projectCellInfo: {},
+      ajaxCount: 0
+    }
+  },
+  computed: {
+    getTimeFmt() {
+      return 'yyyy-MM-dd'
+    },
+    ...mapGetters('user', ['isLogin', 'isFree'])
+  },
+  created() {
+    this.loadList()
+  },
+  methods: {
+    onClick(item) {
+      const query = {}
+      if (item.keys) {
+        query.keywords = item.keys.join(' ')
+      }
+      openAppOrWxPage({
+        wx: LINKS.标讯详情页前缀.wx + item.id + '.html?' + qs.stringify(query),
+        app: LINKS.标讯详情页前缀.app + item.id + '.html?' + qs.stringify(query),
+        h5: LINKS.标讯详情页前缀.h5 + item.id + '.html?' + qs.stringify(query)
+      })
+    },
+    /**
+     * 获取最新标讯
+     */
+    loadList() {
+      this.loading = true
+      this.ajaxCount++
+      ajaxGetIndexList({
+        city: '',
+        isSearch: this.isLogin || this.isHasFreeKey ? 1 : 2,
+        noToast: true
+      })
+        .then((res) => {
+          const { data = {} } = res
+          if (Object.keys(data).length === 0 && this.ajaxCount < 2) {
+            // 如果第一次请求没有返回值(超时),再请求一次 最多请求两次
+            this.loadList()
+          }
+          const {
+            history: historyKeys = [],
+            list = []
+          } = data || {}
+
+
+          this.list = list.map((v) => {
+            const buyerClass =
+              v.buyerclass && v.buyerclass !== '其它' ? v.buyerclass : undefined
+            return {
+              id: v.id,
+              title: v.title,
+              keys: [].concat(v?.matchkeys || historyKeys),
+              isCollected: v?.isCol || false,
+              hasFile: v?.fileExists || false,
+              isCB: {
+                id: '',
+                value: 0
+              },
+              leftTopBadgeText:
+                v?.site === '剑鱼信息发布平台' ? '业主委托项目' : '',
+              tags: [
+                v?.area || '全国',
+                buyerClass,
+                v?.type || v?.subtype,
+                // 有中标金额取中标金额,没有取预算,预算没有置空
+                '登录即可免费查看'
+              ].filter((v) => v),
+              time: v?.publishTime ? v.publishTime * 1000 : '',
+              data: v
+            }
+          }).splice(0, 20)
+        })
+        .finally(() => {
+          this.loading = false
+          this.loaded = true
+        })
+        .catch(() => {
+          // 如果第一次请求失败,再请求一次 最多请求两次
+          if (this.ajaxCount < 2) {
+            this.loadList()
+          }
+        })
+    },
+    onKeep() {
+      if (!this.isLogin) {
+        return openLinkOfOther(LINKS.APP登录页.app, {
+          query: {
+            to: 'back'
+          }
+        })
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.new-list-module {
+  .list {
+    background: #f5f6f7;
+  }
+  .divider-container {
+    display: flex;
+    justify-content: space-between;
+    align-content: center;
+    padding: 15px 16px;
+    background: #fff;
+    .divider-title{
+      font-size: 16px;
+      line-height: 24px;
+    }
+    .divider-more{
+      font-size: 14px;
+      line-height: 20px;
+      color: $color_main;
+    }
+  }
+  ::v-deep{
+    .project-cell{
+      margin: 0 0 8px!important;
+      border-radius: 0!important;
+    }
+  }
+  .right-event {
+    margin-left: 24px;
+    .label-icon {
+      font-size: 14px;
+      color: #5f5e64;
+    }
+    &.cb_blue {
+      color: #2abed1;
+    }
+  }
+
+  .right-bottom {
+    margin: 8px;
+    border-radius: 12px;
+    &::after {
+      margin-left: 16px;
+    }
+  }
+}
+</style>

+ 15 - 0
apps/mobile/src/router/modules/search.js

@@ -12,6 +12,9 @@ const MiddleSearch = {
     {
       path: 'bidding',
       name: 'search-middle-bidding',
+      alias: [
+        '/jylab/supsearch/index.html'
+      ],
       component: () => import('@/views/search/middle/bidding/index.vue'),
       meta: {
         title: '招标采购搜索'
@@ -20,6 +23,9 @@ const MiddleSearch = {
     {
       path: 'company',
       name: 'search-middle-company',
+      alias: [
+        '/jylab/entSearch/index.html'
+      ],
       component: () => import('@/views/search/middle/company/index.vue'),
       meta: {
         title: '企业搜索'
@@ -28,6 +34,9 @@ const MiddleSearch = {
     {
       path: 'buyer',
       name: 'search-middle-buyer',
+      alias: [
+        '/jylab/purSearch/index.html'
+      ],
       component: () => import('@/views/search/middle/buyer/index.vue'),
       meta: {
         title: '采购单位搜索'
@@ -36,6 +45,9 @@ const MiddleSearch = {
     {
       path: 'supplier',
       name: 'search-middle-supplier',
+      alias: [
+        '/swordfish/page_big_pc/search/supply'
+      ],
       component: () => import('@/views/search/middle/supplier/index.vue'),
       meta: {
         title: '供应搜索'
@@ -44,6 +56,9 @@ const MiddleSearch = {
     {
       path: 'docs',
       name: 'search-middle-docs',
+      alias: [
+        '/swordfish/docs/search'
+      ],
       component: () => import('@/views/search/middle/docs/index.vue'),
       meta: {
         title: '文档搜索'

+ 22 - 5
apps/mobile/src/views/article/index.vue

@@ -34,27 +34,30 @@
                 v-if="contentInfo.publishEntName"
               >
                 <label>发布单位</label>
-                <div>{{ contentInfo.publishEntName }}</div>
+                <div v-if="isLogin">{{ contentInfo.publishEntName }}</div>
+                <div v-else class="login-see" @click="toLogin">登录即可免费查看</div>
               </div>
               <div class="content-item jy-hairline--bottom">
                 <label>发布人</label>
-                <div>
+                <div v-if="isLogin">
                   {{
                     contentInfo.infoDetailContact.name
                       ? contentInfo.infoDetailContact.name
                       : '-'
                   }}
                 </div>
+                <div v-else class="login-see" @click="toLogin">登录即可免费查看</div>
               </div>
               <div class="content-item jy-hairline--bottom">
                 <label>联系电话</label>
-                <div>
+                <div v-if="isLogin">
                   {{
                     contentInfo.infoDetailContact.phone
                       ? contentInfo.infoDetailContact.phone
                       : '-'
                   }}
                 </div>
+                <div v-else class="login-see" @click="toLogin">登录即可免费查看</div>
               </div>
               <div class="content-item jy-hairline--bottom">
                 <label>有效期至</label>
@@ -203,6 +206,7 @@ import {
 } from '@/utils'
 import { callPhone, downLoadFile, compareVersion } from '@/utils/callFn'
 import { emailRegExp, customerServiceTel } from '@/utils/constant/'
+import { openLinkOfOther } from '@/utils'
 import { LINKS } from '@/data'
 // api
 import { supplyInfoDetail } from '@/api/modules/jyinfo'
@@ -263,7 +267,8 @@ export default {
       'isSuper',
       'isMember',
       'bigMemberPower',
-      'isBusiness'
+      'isBusiness',
+      'isLogin'
     ]),
     // 免费用户免费体验次数
     freeFileNum() {
@@ -400,7 +405,7 @@ export default {
         data,
         error_code: code,
         error_msg: msg
-      } = await getEntInfo({ entId })
+      } = await getEntInfo({ entId, noToast: true })
       if (code === 0 && data) {
         // this.contentInfo.publishEntName = data.name
         // 信息中没有省市,从企业信息中获取
@@ -656,6 +661,15 @@ export default {
     },
     chargeFilePack() {
       this.$router.push('/common/order/create/filepack')
+    },
+    toLogin() {
+      if (!this.isLogin) {
+        return openLinkOfOther(LINKS.APP登录页.app, {
+          query: {
+            to: 'back'
+          }
+        })
+      }
     }
   }
 }
@@ -906,6 +920,9 @@ export default {
       margin-right: 12px;
       color: #5f5e64;
     }
+    .login-see {
+      color: $color_main;
+    }
   }
 }
 ::v-deep {

+ 1 - 1
apps/mobile/src/views/search/layout.vue

@@ -51,7 +51,7 @@ export default {
         console.log('is focus')
         vm.triggerFocus()
       }
-      const hasInput = to.params?.input || to.query?.input
+      const hasInput = to.params?.input || to.query?.input || to.query?.keywords
       if (hasInput || hasInput === '') {
         vm.$storage.set(CACHE_KEY, hasInput)
       }

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

@@ -42,8 +42,12 @@
             @delete="deleteList"
           ></history-list>
           <HotKeyCard class="content-module" @clickTag="clickHotKeyItem" />
+          <NoLoginBidList v-if="!isLogin"></NoLoginBidList>
         </div>
       </div>
+      <div class="j-footer" v-if="!isLogin">
+        <NoLoginTabbar></NoLoginTabbar>
+      </div>
     </div>
     <CheckUserDialog />
   </div>
@@ -53,7 +57,13 @@
 import { HistoryList, AppIcon } from '@/ui'
 import HotKeyCard from '@/components/search/middle/HotKeyCard.vue'
 import CheckUserDialog from '@/views/identity/components/CheckUserDialog'
-import { getBiddingFilterList } from '@/api/modules'
+import NoLoginBidList from '@/components/search/bidding/NoLoginBidList.vue'
+import NoLoginTabbar from '@/components/no-login/NoLoginTabbar.vue'
+import {
+  getBiddingSearchHistory,
+  getBiddingFilterList,
+  ajaxRemoveBiddingSearchHistory
+} from '@/api/modules'
 import {
   FilterHistoryAjaxModel2ViewModel,
   filterHistoryNotEmptyFormat
@@ -77,7 +87,9 @@ export default {
     AppIcon,
     HotKeyCard,
     CheckUserDialog,
-    HistoryList
+    HistoryList,
+    NoLoginBidList,
+    NoLoginTabbar
   },
   inject: {
     topSearch: {
@@ -437,7 +449,6 @@ export default {
         // }
         getHistoryQuery({ type: '1' }).then((res) => {
           if (res.success) {
-            console.log(res, 'resssss');
             this.biddingSearchHistory = res?.search || []
           }
         })

+ 10 - 8
apps/mobile/src/views/search/middle/layout.vue

@@ -123,14 +123,16 @@ export default {
       if (this.isLogin) {
         return true
       } else {
-        if (name === 'search-middle-supplier') {
-          this.toLogin({
-            query: {
-              to: 'back'
-            }
-          })
-        }
-        return name !== 'search-middle-supplier'
+        // P574移动端未登录seo调整 供应搜索未登录也能访问
+        // if (name === 'search-middle-supplier') {
+        //   this.toLogin({
+        //     query: {
+        //       to: 'back'
+        //     }
+        //   })
+        // }
+        // return name !== 'search-middle-supplier'
+        return true
       }
     },
     onSearch({ type, data }) {

+ 14 - 12
apps/mobile/src/views/search/middle/supplier/index.vue

@@ -37,21 +37,23 @@ export default {
       })
     },
     submit() {
-      // 历史记录新增
-      this.setHistory({
-        type: 'supplier',
-        item: {
-          label: this.topSearch.input
-        }
-      })
-      // 登录拦截
-      if (!this.isLogin) {
-        return openLinkOfOther(LINKS.APP登录页.app, {
-          query: {
-            url: '/jy_mobile/search/result/supplier'
+      if (this.isLogin) {
+        // 历史记录新增
+        this.setHistory({
+          type: 'supplier',
+          item: {
+            label: this.topSearch.input
           }
         })
       }
+      // 登录拦截
+      // if (!this.isLogin) {
+      //   return openLinkOfOther(LINKS.APP登录页.app, {
+      //     query: {
+      //       url: '/jy_mobile/search/result/supplier'
+      //     }
+      //   })
+      // }
       // 正常跳转
       this.$nextTick(() => {
         this.$router.push('/search/result/supplier')

+ 41 - 9
packages/vue-anti/src/components/VerifyPoints.vue

@@ -5,8 +5,13 @@
     </div>
     <div class="verify-points-panel">
       <div class="verify-points-panel-header">
-        <span>请在下图依次点击:</span>
-        <span>{{ textVerify }}</span>
+        <span class="verify-points-text">
+          <span>请在下图依次点击:</span>
+          <span>{{ textVerify }}</span>
+        </span>
+        <span class="verify-points-hd-actions">
+          <span class="verify-refresh verify-refresh-small" @click="onRefresh"></span>
+        </span>
       </div>
       <div class="verify-points-panel-main" @click="addPoint($event)" ref="pointsPanelMain">
         <img class="points-panel-img" :src="imgUrl || imgBase64AddPrefix(imgBase64)" alt="" ref="pointsPanelImg">
@@ -20,8 +25,12 @@
         ></span>
       </div>
       <div class="verify-points-panel-footer">
-        <span class="verify-refresh" @click="onRefresh"></span>
-        <button class="confirm-button verify-confirm" @click="onConfirm">确定</button>
+        <div class="verify-points-panel-footer-actions">
+          <button class="confirm-button verify-login" v-if="showLoginButton" @click="toLogin">登录</button>
+          <span class="verify-confirm-placeholder" v-else></span>
+          <button class="confirm-button verify-confirm" @click="onConfirm">确定</button>
+        </div>
+        <p class="verify-points-panel-footer-tips" v-if="showLoginButton">登录即可获得更多浏览权限</p>
       </div>
     </div>
   </div>
@@ -73,7 +82,12 @@ export default {
     pointsMaxCount: {
       type: Number,
       default: 3
-    }
+    },
+    loginButtonClick: Function,
+    showLoginButton: {
+      type: Boolean,
+      default: false
+    },
   },
   data () {
     return {
@@ -133,6 +147,9 @@ export default {
       this.onReset()
       this.$emit('refresh')
     },
+    toLogin() {
+      this.loginButtonClick && this.loginButtonClick()
+    },
     onConfirm () {
       if (this.points.length <= 0) return
       const imgWidth = this.$refs.pointsPanelImg.getBoundingClientRect().width
@@ -194,6 +211,9 @@ $black: #000;
     background-color: $white;
     border-radius: 4px;
     &-header {
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
       font-size: 16Px;
     }
     &-main {
@@ -202,17 +222,29 @@ $black: #000;
       min-height: 60Px;
     }
     &-footer {
-      display: flex;
-      align-items: center;
-      justify-content: space-between;
-      height: 28Px;
+      &-actions {
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        height: 28Px;
+      }
+      &-tips {
+        margin-top: 6Px;
+        font-size: 14Px;
+      }
     }
     .verify-refresh {
+      display: inline-block;
       width: 28Px;
       height: 28Px;
       background: transparent url(../assets/verify/verify-refresh.png) no-repeat;
       background-size: contain;
+      &.verify-refresh-small {
+        width: 24Px;
+        height: 24Px;
+      }
     }
+    .verify-login,
     .verify-confirm {
       padding: 0 12Px;
       font-size: 16Px;

+ 9 - 1
packages/vue-anti/src/components/VerifyPointsPopup.vue

@@ -10,10 +10,13 @@
       ref="verifyPoints"
       @refresh="onRefresh"
       @confirm="onConfirm"
+      :showLoginButton="showLoginButton"
+      :loginButtonClick="loginButtonClick"
       :imgBase64="imgBase64"
       :textVerify="textVerify" />
   </AntiPopup>
 </template>
+
 <script>
 import VerifyPoints from './VerifyPoints'
 import AntiPopup from './AntiPopup'
@@ -42,7 +45,12 @@ export default {
     textVerify: {
       type: String,
       default: ''
-    }
+    },
+    loginButtonClick: Function,
+    showLoginButton: {
+      type: Boolean,
+      default: false
+    },
   },
   model: {
     prop: 'value',

+ 12 - 1
packages/vue-anti/src/utils/register-anti-interceptors.js

@@ -61,7 +61,14 @@ function closeVerify () {
   }
 }
 
-export default function registerInterceptors (service) {
+let loginButtonClick = undefined
+
+export default function registerInterceptors (service, options = {}) {
+  if (options.loginButtonClick) {
+    // 保存回调到全局,防止丢失
+    loginButtonClick = options.loginButtonClick
+  }
+
   // 注册响应拦截器
   service.interceptors.response.use(async (response) => {
     const res = response.data
@@ -106,10 +113,14 @@ export default function registerInterceptors (service) {
 
     // 需要验证
     if (res.antiVerify === -1 && res.textVerify) {
+      const hasLogin = res.hasLogin
+      // console.log(hasLogin, loginButtonClick)
       // 等待验证码操作完成
       const iReceivedMsg = await new Promise((resolve) => {
         verify.verify({
           value: true,
+          hasLogin,
+          loginButtonClick,
           imgBase64: res.imgData,
           textVerify: res.textVerify,
           refresh () {

+ 8 - 1
packages/vue-anti/src/utils/verify-popup.js

@@ -25,6 +25,9 @@ export default class VerifyPoints {
 
   defaultConf = {
     noop: () => {},
+    loginButtonClickNoop: () => {
+      console.warn('登录事件未定义')
+    },
     getContainer: 'body'
   }
 
@@ -51,17 +54,21 @@ export default class VerifyPoints {
     }
 
     const vm = this.$vm
-    const { noop } = this.conf
+    const { noop, loginButtonClickNoop } = this.conf
     const {
       value = false,
+      hasLogin,
       imgBase64 = '',
       textVerify = '',
+      loginButtonClick = loginButtonClickNoop,
       refresh = noop,
       confirm = noop
     } = conf
 
     vm.imgBase64 = imgBase64
     vm.textVerify = textVerify
+    vm.showLoginButton = !hasLogin
+    vm.loginButtonClick = loginButtonClick || loginButtonClickNoop
 
     // 移除所有事件监听
     vm.$off('refresh')